OSDN Git Service

Merge Official Source
authorZiMing Mo <msylgj@immortalwrt.org>
Wed, 11 May 2022 12:55:05 +0000 (20:55 +0800)
committerZiMing Mo <msylgj@immortalwrt.org>
Wed, 11 May 2022 12:55:23 +0000 (20:55 +0800)
Signed-off-by: ZiMing Mo <msylgj@immortalwrt.org>
70 files changed:
include/kernel-5.15
package/boot/uboot-envtools/files/ipq806x
package/boot/uboot-envtools/files/realtek
package/kernel/linux/modules/other.mk
package/kernel/linux/modules/usb.mk
package/network/config/firewall/Makefile
package/network/config/firewall/files/firewall.config
package/utils/nvram/Makefile
package/utils/nvram/files/nvram-bcm47xx.init [moved from package/utils/nvram/files/nvram.init with 97% similarity]
package/utils/nvram/files/nvram-bcm53xx.init [new file with mode: 0755]
target/linux/apm821xx/Makefile
target/linux/apm821xx/config-5.15 [new file with mode: 0644]
target/linux/apm821xx/patches-5.15/010-hwmon-tc654-add-thermal_cooling-device.patch [new file with mode: 0644]
target/linux/apm821xx/patches-5.15/201-add-amcc-apollo3g-support.patch [new file with mode: 0644]
target/linux/apm821xx/patches-5.15/300-fix-atheros-nics-on-apm82181.patch [new file with mode: 0644]
target/linux/apm821xx/patches-5.15/301-fix-memory-map-wndr4700.patch [new file with mode: 0644]
target/linux/apm821xx/patches-5.15/900-powerpc-bootwrapper-force-gzip-as-mkimage-s-compress.patch [new file with mode: 0644]
target/linux/armvirt/64/config-5.10
target/linux/armvirt/64/config-5.15
target/linux/ath79/patches-5.15/910-unaligned_access_hacks.patch
target/linux/bcm53xx/base-files/etc/init.d/clear_partialboot [deleted file]
target/linux/generic/backport-5.10/610-v5.15-58-netfilter-flowtable-avoid-possible-false-sharing.patch [new file with mode: 0644]
target/linux/generic/backport-5.10/890-v5.19-net-sfp-Add-tx-fault-workaround-for-Huawei-MA5671A-SFP-ON.patch [new file with mode: 0644]
target/linux/generic/backport-5.15/890-v5.19-net-sfp-Add-tx-fault-workaround-for-Huawei-MA5671A-SFP-ON.patch [new file with mode: 0644]
target/linux/generic/config-5.15
target/linux/generic/hack-5.10/650-netfilter-add-xt_FLOWOFFLOAD-target.patch
target/linux/generic/hack-5.15/650-netfilter-add-xt_FLOWOFFLOAD-target.patch
target/linux/generic/hack-5.15/780-usb-net-MeigLink_modem_support.patch
target/linux/generic/pending-5.10/704-00-netfilter-flowtable-fix-excessive-hw-offload-attempt.patch [new file with mode: 0644]
target/linux/generic/pending-5.10/704-01-netfilter-nft_flow_offload-skip-dst-neigh-lookup-for.patch [new file with mode: 0644]
target/linux/generic/pending-5.10/704-02-net-fix-dev_fill_forward_path-with-pppoe-bridge.patch [new file with mode: 0644]
target/linux/generic/pending-5.10/704-03-netfilter-nft_flow_offload-fix-offload-with-pppoe-vl.patch [new file with mode: 0644]
target/linux/generic/pending-5.10/705-net-dsa-tag_mtk-add-padding-for-tx-packets.patch [new file with mode: 0644]
target/linux/generic/pending-5.15/400-mtd-mtdsplit-support.patch
target/linux/generic/pending-5.15/495-mtd-core-add-get_mtd_device_by_node.patch
target/linux/generic/pending-5.15/630-packet_socket_type.patch
target/linux/generic/pending-5.15/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch
target/linux/generic/pending-5.15/704-00-netfilter-flowtable-fix-excessive-hw-offload-attempt.patch [new file with mode: 0644]
target/linux/generic/pending-5.15/704-01-netfilter-nft_flow_offload-skip-dst-neigh-lookup-for.patch [new file with mode: 0644]
target/linux/generic/pending-5.15/704-02-net-fix-dev_fill_forward_path-with-pppoe-bridge.patch [new file with mode: 0644]
target/linux/generic/pending-5.15/704-03-netfilter-nft_flow_offload-fix-offload-with-pppoe-vl.patch [new file with mode: 0644]
target/linux/generic/pending-5.15/705-net-dsa-tag_mtk-add-padding-for-tx-packets.patch [new file with mode: 0644]
target/linux/ipq40xx/files-5.15/drivers/net/mdio/ar40xx.c [deleted file]
target/linux/ipq40xx/files-5.15/drivers/net/mdio/ar40xx.h [deleted file]
target/linux/ipq40xx/files/drivers/net/mdio/ar40xx.c [moved from target/linux/ipq40xx/files-5.10/drivers/net/mdio/ar40xx.c with 100% similarity]
target/linux/ipq40xx/files/drivers/net/mdio/ar40xx.h [moved from target/linux/ipq40xx/files-5.10/drivers/net/mdio/ar40xx.h with 100% similarity]
target/linux/ipq40xx/patches-5.15/420-firmware-qcom-scm-disable-SDI.patch
target/linux/ipq806x/base-files/etc/board.d/02_network
target/linux/ipq806x/base-files/lib/upgrade/platform.sh
target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065-tr4400-v2.dts [new file with mode: 0644]
target/linux/ipq806x/image/generic.mk
target/linux/ipq806x/patches-5.10/0069-arm-boot-add-dts-files.patch
target/linux/ipq806x/patches-5.15/0069-arm-boot-add-dts-files.patch
target/linux/ipq806x/patches-5.15/099-1-mtd-nand-raw-qcom_nandc-add-boot_layout_mode-support.patch
target/linux/mediatek/patches-5.15/104-mt7622-add-snor-irq.patch
target/linux/mediatek/patches-5.15/120-06-v5.18-spi-spi-mem-Kill-the-spi_mem_dtr_supports_op-helper.patch
target/linux/mediatek/patches-5.15/120-10-v5.18-mtd-nand-fix-ecc-parameters-for-mt7622.patch [deleted file]
target/linux/mediatek/patches-5.15/192-arm64-dts-mt7622-specify-the-number-of-DMA-requests.patch
target/linux/mediatek/patches-5.15/600-arm64-dts-mediatek-Split-PCIe-node-for-MT2712-and-MT.patch
target/linux/mediatek/patches-5.15/602-arm64-dts-mediatek-add-mt7622-pcie-slot-node.patch
target/linux/mediatek/patches-5.15/710-pci-pcie-mediatek-add-support-for-coherent-DMA.patch
target/linux/ramips/dts/mt7621_cudy_x6.dts [new file with mode: 0644]
target/linux/ramips/dts/mt7628an_glinet_gl-mt300n-v2.dts
target/linux/ramips/image/mt7621.mk
target/linux/ramips/mt7621/base-files/etc/hotplug.d/ieee80211/10_fix_wifi_mac
target/linux/ramips/patches-5.15/200-add-ralink-eth.patch
target/linux/realtek/dts-5.10/rtl8382_zyxel_gs1900-16.dts [new file with mode: 0644]
target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c
target/linux/realtek/image/rtl838x.mk
target/linux/x86/modules.mk

index 1d8ca84..1575a9a 100644 (file)
@@ -1,2 +1,2 @@
-LINUX_VERSION-5.15 = .35
-LINUX_KERNEL_HASH-5.15.35 = 0a1a5ae2f30eb2b38215e59077f045aabd7f4e2857a881482f02ea48186105d8
+LINUX_VERSION-5.15 = .38
+LINUX_KERNEL_HASH-5.15.38 = 7e415d420990b88bfec038d56e920b9b28f99d54f31dbbd7aa82e66acca11052
index 7e1d71a..a8285d1 100644 (file)
@@ -30,6 +30,7 @@ ubootenv_mtdinfo () {
 }
 
 case "$board" in
+arris,tr4400-v2|\
 askey,rt4230w-rev6)
        ubootenv_add_uci_config "/dev/mtd9" "0x0" "0x40000" "0x20000"
        ;;
index c07175a..99a73a6 100644 (file)
@@ -15,6 +15,7 @@ zyxel,gs1900-8|\
 zyxel,gs1900-8hp-v1|\
 zyxel,gs1900-8hp-v2|\
 zyxel,gs1900-10hp|\
+zyxel,gs1900-16|\
 zyxel,gs1900-24-v1|\
 zyxel,gs1900-24hp-v1|\
 zyxel,gs1900-24hp-v2)
index c8fea03..802dd81 100644 (file)
@@ -1274,71 +1274,24 @@ endef
 $(eval $(call KernelPackage,tpm-i2c-infineon))
 
 
-define KernelPackage/w83627hf-wdt
+define KernelPackage/i6300esb-wdt
   SUBMENU:=$(OTHER_MENU)
-  TITLE:=Winbond 83627HF Watchdog Timer
-  KCONFIG:=CONFIG_W83627HF_WDT
-  FILES:=$(LINUX_DIR)/drivers/$(WATCHDOG_DIR)/w83627hf_wdt.ko
-  AUTOLOAD:=$(call AutoLoad,50,w83627hf-wdt,1)
+  TITLE:=Intel 6300ESB Timer/Watchdog
+  DEPENDS:=@PCI_SUPPORT @!SMALL_FLASH
+  KCONFIG:=CONFIG_I6300ESB_WDT \
+          CONFIG_WATCHDOG_CORE=y
+  FILES:=$(LINUX_DIR)/drivers/$(WATCHDOG_DIR)/i6300esb.ko
+  AUTOLOAD:=$(call AutoLoad,50,i6300esb,1)
 endef
 
-define KernelPackage/w83627hf-wdt/description
-  Kernel module for Winbond 83627HF Watchdog Timer
+define KernelPackage/i6300esb-wdt/description
+  Kernel module for the watchdog timer built into the Intel
+  6300ESB controller hub. Also used by QEMU/libvirt.
 endef
 
-$(eval $(call KernelPackage,w83627hf-wdt))
+$(eval $(call KernelPackage,i6300esb-wdt))
 
 
-define KernelPackage/itco-wdt
-  SUBMENU:=$(OTHER_MENU)
-  TITLE:=Intel iTCO Watchdog Timer
-  KCONFIG:=CONFIG_ITCO_WDT \
-           CONFIG_ITCO_VENDOR_SUPPORT=y
-  FILES:=$(LINUX_DIR)/drivers/$(WATCHDOG_DIR)/iTCO_wdt.ko \
-         $(LINUX_DIR)/drivers/$(WATCHDOG_DIR)/iTCO_vendor_support.ko
-  AUTOLOAD:=$(call AutoLoad,50,iTCO_vendor_support iTCO_wdt,1)
-endef
-
-define KernelPackage/itco-wdt/description
-  Kernel module for Intel iTCO Watchdog Timer
-endef
-
-$(eval $(call KernelPackage,itco-wdt))
-
-
-define KernelPackage/it87-wdt
-  SUBMENU:=$(OTHER_MENU)
-  TITLE:=ITE IT87 Watchdog Timer
-  KCONFIG:=CONFIG_IT87_WDT
-  FILES:=$(LINUX_DIR)/drivers/$(WATCHDOG_DIR)/it87_wdt.ko
-  AUTOLOAD:=$(call AutoLoad,50,it87-wdt,1)
-  MODPARAMS.it87-wdt:= \
-       nogameport=1 \
-       nocir=1
-endef
-
-define KernelPackage/it87-wdt/description
-  Kernel module for ITE IT87 Watchdog Timer
-endef
-
-$(eval $(call KernelPackage,it87-wdt))
-
-
-define KernelPackage/f71808e-wdt
-  SUBMENU:=$(OTHER_MENU)
-  TITLE:=Fintek F718xx/F818xx Watchdog Timer
-  DEPENDS:=@TARGET_x86
-  KCONFIG:=CONFIG_F71808E_WDT
-  FILES:=$(LINUX_DIR)/drivers/$(WATCHDOG_DIR)/f71808e_wdt.ko
-  AUTOLOAD:=$(call AutoProbe,f71808e-wdt,1)
-endef
-
-define KernelPackage/f71808e-wdt/description
-  Kernel module for the watchdog timer found on many Fintek Super-IO chips.
-endef
-
-$(eval $(call KernelPackage,f71808e-wdt))
-
 define KernelPackage/mhi-bus
   SUBMENU:=$(OTHER_MENU)
   TITLE:=MHI bus
index 97c957d..704c5b3 100644 (file)
@@ -1804,7 +1804,6 @@ $(eval $(call KernelPackage,usb-xhci-mtk))
 
 define KernelPackage/usb-xhci-pci-renesas
   TITLE:=Support for additional Renesas xHCI controller with firmware
-  DEPENDS:=@LINUX_5_10
   KCONFIG:=CONFIG_USB_XHCI_PCI_RENESAS
   HIDDEN:=1
   FILES:=$(LINUX_DIR)/drivers/usb/host/xhci-pci-renesas.ko
index 06770bd..4226981 100644 (file)
@@ -9,7 +9,7 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=firewall
-PKG_RELEASE:=2
+PKG_RELEASE:=3
 
 PKG_SOURCE_PROTO:=git
 PKG_SOURCE_URL=$(PROJECT_GIT)/project/firewall3.git
index 8d9462f..dcf76ee 100644 (file)
@@ -55,13 +55,11 @@ config rule
        option target           ACCEPT
 
 # Allow DHCPv6 replies
-# see https://dev.openwrt.org/ticket/10381
+# see https://github.com/openwrt/openwrt/issues/5066
 config rule
        option name             Allow-DHCPv6
        option src              wan
        option proto            udp
-       option src_ip           fc00::/6
-       option dest_ip          fc00::/6
        option dest_port        546
        option family           ipv6
        option target           ACCEPT
index 863b304..b957211 100644 (file)
@@ -8,7 +8,7 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=nvram
-PKG_RELEASE:=10
+PKG_RELEASE:=11
 
 PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
 
@@ -44,7 +44,11 @@ define Package/nvram/install
        $(INSTALL_BIN) $(PKG_BUILD_DIR)/nvram $(1)/usr/sbin/
 ifneq ($(CONFIG_TARGET_bcm47xx),)
        $(INSTALL_DIR) $(1)/etc/init.d
-       $(INSTALL_BIN) ./files/nvram.init $(1)/etc/init.d/nvram
+       $(INSTALL_BIN) ./files/nvram-bcm47xx.init $(1)/etc/init.d/nvram
+endif
+ifneq ($(CONFIG_TARGET_bcm53xx),)
+       $(INSTALL_DIR) $(1)/etc/init.d
+       $(INSTALL_BIN) ./files/nvram-bcm53xx.init $(1)/etc/init.d/nvram
 endif
 endef
 
similarity index 97%
rename from package/utils/nvram/files/nvram.init
rename to package/utils/nvram/files/nvram-bcm47xx.init
index 467ab28..4a2bcd1 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh /etc/rc.common
 # NVRAM setup
 #
-# This file handles the NVRAM quirks of various hardware.
+# This file handles the NVRAM quirks of various hardware of the bcm47xx target.
 
 START=02
 alias debug=${DEBUG:-:}
@@ -71,7 +71,7 @@ fixup_linksys() {
        esac
 }
 
-start() {
+boot() {
        # Don't do any fixups on the WGT634U
        [ "$(cat /proc/diag/model)" = "Netgear WGT634U" ] && return
 
diff --git a/package/utils/nvram/files/nvram-bcm53xx.init b/package/utils/nvram/files/nvram-bcm53xx.init
new file mode 100755 (executable)
index 0000000..0502cd2
--- /dev/null
@@ -0,0 +1,40 @@
+#!/bin/sh /etc/rc.common
+# NVRAM setup
+#
+# This file handles the NVRAM quirks of various hardware of the bcm53xx target.
+
+START=02
+
+clear_partialboots() {
+       # clear partialboots
+
+       case $(board_name) in
+               linksys,panamera)
+                       COMMIT=1
+                       nvram set partialboots=0
+                       ;;
+       esac
+}
+
+set_wireless_led_behaviour() {
+       # set Broadcom wireless LED behaviour for both radios
+       # 0:ledbh9 -> Behaviour of 2.4GHz LED
+       # 1:ledbh9 -> Behaviour of 5GHz LED
+       # 0x7 makes the wireless LEDs on, when radios are enabled, and blink when there's activity
+
+       case $(board_name) in
+               asus,rt-ac88u)
+                       COMMIT=1
+                       nvram set 0:ledbh9=0x7 set 1:ledbh9=0x7
+                       ;;
+       esac
+}
+
+boot() {
+       . /lib/functions.sh
+
+       clear_partialboots
+       set_wireless_led_behaviour
+
+       [ "$COMMIT" = "1" ] && nvram commit
+}
index 7d31ac8..f36274b 100644 (file)
@@ -10,6 +10,7 @@ FEATURES:=fpu dt gpio ramdisk squashfs usb
 SUBTARGETS:=nand sata
 
 KERNEL_PATCHVER:=5.10
+KERNEL_TESTING_PATCHVER:=5.15
 
 define Target/Description
        Build images for AppliedMicro APM821xx based boards.
diff --git a/target/linux/apm821xx/config-5.15 b/target/linux/apm821xx/config-5.15
new file mode 100644 (file)
index 0000000..c3f520c
--- /dev/null
@@ -0,0 +1,245 @@
+# CONFIG_40x is not set
+CONFIG_44x=y
+CONFIG_4xx=y
+CONFIG_4xx_SOC=y
+# CONFIG_ADVANCED_OPTIONS is not set
+CONFIG_APM821xx=y
+# CONFIG_APOLLO3G is not set
+# CONFIG_ARCHES is not set
+CONFIG_ARCH_32BIT_OFF_T=y
+CONFIG_ARCH_DMA_ADDR_T_64BIT=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_KEEP_MEMBLOCK=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
+CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y
+CONFIG_ARCH_MMAP_RND_BITS=11
+CONFIG_ARCH_MMAP_RND_BITS_MAX=17
+CONFIG_ARCH_MMAP_RND_BITS_MIN=11
+CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=17
+CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=11
+CONFIG_ARCH_STACKWALK=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_ARCH_WEAK_RELEASE_ACQUIRE=y
+CONFIG_AUDIT_ARCH=y
+# CONFIG_BAMBOO is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_BLK_MQ_PCI=y
+CONFIG_BLUESTONE=y
+CONFIG_BOOKE=y
+CONFIG_BOOKE_WDT=y
+# CONFIG_CANYONLANDS is not set
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_CMDLINE="rootfstype=squashfs noinitrd"
+CONFIG_CMDLINE_FROM_BOOTLOADER=y
+CONFIG_COMMON_CLK=y
+CONFIG_COMPAT_32BIT_TIME=y
+CONFIG_CPU_BIG_ENDIAN=y
+CONFIG_CRC16=y
+# CONFIG_CRC32_SARWATE is not set
+CONFIG_CRC32_SLICEBY8=y
+CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRYPTO_DEV_PPC4XX=y
+CONFIG_CRYPTO_HW=y
+CONFIG_CRYPTO_JITTERENTROPY=y
+CONFIG_CRYPTO_LIB_POLY1305_RSIZE=1
+CONFIG_CRYPTO_LZO=y
+# CONFIG_CRYPTO_MD5_PPC is not set
+CONFIG_CRYPTO_RNG=y
+CONFIG_CRYPTO_RNG2=y
+# CONFIG_CRYPTO_SHA1_PPC is not set
+CONFIG_DATA_SHIFT=12
+CONFIG_DMADEVICES=y
+CONFIG_DMA_DIRECT_REMAP=y
+CONFIG_DMA_ENGINE=y
+CONFIG_DMA_OF=y
+CONFIG_DMA_REMAP=y
+CONFIG_DTC=y
+CONFIG_DW_DMAC=y
+CONFIG_DW_DMAC_CORE=y
+CONFIG_EARLY_PRINTK=y
+# CONFIG_EBONY is not set
+CONFIG_EDAC_ATOMIC_SCRUB=y
+CONFIG_EDAC_SUPPORT=y
+# CONFIG_EIGER is not set
+CONFIG_EXTRA_TARGETS="uImage"
+CONFIG_FIXED_PHY=y
+CONFIG_FORCE_PCI=y
+# CONFIG_FSL_LBC is not set
+CONFIG_FWNODE_MDIO=y
+CONFIG_FW_LOADER_PAGED_BUF=y
+CONFIG_GENERIC_ALLOCATOR=y
+CONFIG_GENERIC_ATOMIC64=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_CPU=y
+CONFIG_GENERIC_CPU_AUTOPROBE=y
+CONFIG_GENERIC_EARLY_IOREMAP=y
+CONFIG_GENERIC_GETTIMEOFDAY=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_GENERIC_MSI_IRQ=y
+CONFIG_GENERIC_MSI_IRQ_DOMAIN=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_GENERIC_STRNCPY_FROM_USER=y
+CONFIG_GENERIC_STRNLEN_USER=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+# CONFIG_GEN_RTC is not set
+# CONFIG_GLACIER is not set
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_CDEV=y
+CONFIG_GPIO_GENERIC=y
+CONFIG_GPIO_GENERIC_PLATFORM=y
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_PPC4XX=y
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_IBM_IIC=y
+CONFIG_IBM_EMAC=y
+CONFIG_IBM_EMAC_EMAC4=y
+CONFIG_IBM_EMAC_POLL_WEIGHT=32
+CONFIG_IBM_EMAC_RGMII=y
+CONFIG_IBM_EMAC_RXB=128
+CONFIG_IBM_EMAC_RX_COPY_THRESHOLD=256
+CONFIG_IBM_EMAC_TAH=y
+CONFIG_IBM_EMAC_TXB=128
+# CONFIG_ICON is not set
+CONFIG_ILLEGAL_POINTER_VALUE=0
+CONFIG_IRQCHIP=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_DOMAIN_HIERARCHY=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_IRQ_WORK=y
+CONFIG_ISA_DMA_API=y
+# CONFIG_JFFS2_FS is not set
+# CONFIG_KATMAI is not set
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_LEDS_TRIGGER_MTD=y
+CONFIG_LEDS_TRIGGER_PATTERN=y
+CONFIG_LIBFDT=y
+CONFIG_LOCK_DEBUGGING_SUPPORT=y
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+# CONFIG_MATH_EMULATION is not set
+CONFIG_MDIO_BUS=y
+CONFIG_MDIO_DEVICE=y
+CONFIG_MDIO_DEVRES=y
+CONFIG_MEMFD_CREATE=y
+CONFIG_MIGRATION=y
+CONFIG_MMU_GATHER_PAGE_SIZE=y
+CONFIG_MODULES_USE_ELF_RELA=y
+CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+# CONFIG_MTD_CFI_GEOMETRY is not set
+# CONFIG_MTD_SPLIT_SQUASHFS_ROOT is not set
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NEED_PER_CPU_KM=y
+CONFIG_NEED_SG_DMA_LENGTH=y
+CONFIG_NET_SELFTESTS=y
+CONFIG_NOT_COHERENT_CACHE=y
+CONFIG_NO_HZ=y
+CONFIG_NO_HZ_COMMON=y
+CONFIG_NO_HZ_IDLE=y
+CONFIG_NR_CPUS=1
+CONFIG_NR_IRQS=512
+CONFIG_NVMEM=y
+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_SIGSUSPEND=y
+CONFIG_PACKING=y
+CONFIG_PAGE_OFFSET=0xc0000000
+CONFIG_PCI=y
+CONFIG_PCIEAER=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_PCI_DISABLE_COMMON_QUIRKS=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_MSI=y
+CONFIG_PCI_MSI_ARCH_FALLBACKS=y
+CONFIG_PCI_MSI_IRQ_DOMAIN=y
+CONFIG_PGTABLE_LEVELS=2
+CONFIG_PHYLIB=y
+CONFIG_PHYSICAL_START=0x00000000
+CONFIG_PHYS_64BIT=y
+CONFIG_PHYS_ADDR_T_64BIT=y
+# CONFIG_PMU_SYSFS is not set
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_PPC44x_SIMPLE=y
+CONFIG_PPC4xx_GPIO=y
+CONFIG_PPC4xx_MSI=y
+CONFIG_PPC4xx_PCI_EXPRESS=y
+# CONFIG_PPC64 is not set
+# CONFIG_PPC_47x is not set
+# CONFIG_PPC_85xx is not set
+# CONFIG_PPC_8xx is not set
+CONFIG_PPC_ADV_DEBUG_DACS=2
+CONFIG_PPC_ADV_DEBUG_DAC_RANGE=y
+CONFIG_PPC_ADV_DEBUG_DVCS=2
+CONFIG_PPC_ADV_DEBUG_IACS=4
+CONFIG_PPC_ADV_DEBUG_REGS=y
+# CONFIG_PPC_BOOK3S_32 is not set
+CONFIG_PPC_DCR=y
+CONFIG_PPC_DCR_NATIVE=y
+# CONFIG_PPC_EARLY_DEBUG is not set
+CONFIG_PPC_FPU=y
+CONFIG_PPC_FPU_REGS=y
+CONFIG_PPC_HAVE_KUEP=y
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_PPC_KUEP=y
+CONFIG_PPC_MMU_NOHASH=y
+CONFIG_PPC_MSI_BITMAP=y
+CONFIG_PPC_PAGE_SHIFT=12
+CONFIG_PPC_UDBG_16550=y
+CONFIG_PPC_WERROR=y
+CONFIG_PTE_64BIT=y
+CONFIG_PTP_1588_CLOCK_OPTIONAL=y
+# CONFIG_RAINIER is not set
+CONFIG_RAS=y
+CONFIG_RATIONAL=y
+CONFIG_REGULATOR=y
+CONFIG_RSEQ=y
+# CONFIG_SAM440EP is not set
+# CONFIG_SCOM_DEBUGFS is not set
+# CONFIG_SEQUOIA is not set
+CONFIG_SERIAL_8250_FSL=y
+CONFIG_SERIAL_MCTRL_GPIO=y
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_SGL_ALLOC=y
+CONFIG_SPARSE_IRQ=y
+CONFIG_SRCU=y
+CONFIG_SWPHY=y
+CONFIG_SYSCTL_EXCEPTION_TRACE=y
+# CONFIG_TAISHAN is not set
+CONFIG_TASK_SIZE=0xc0000000
+CONFIG_THREAD_INFO_IN_TASK=y
+CONFIG_THREAD_SHIFT=13
+CONFIG_TICK_CPU_ACCOUNTING=y
+CONFIG_TINY_SRCU=y
+CONFIG_USB_SUPPORT=y
+CONFIG_VDSO32=y
+# CONFIG_VIRTIO_MENU is not set
+# CONFIG_VIRT_CPU_ACCOUNTING_NATIVE is not set
+# CONFIG_WARP is not set
+CONFIG_WATCHDOG_CORE=y
+CONFIG_XZ_DEC_BCJ=y
+CONFIG_XZ_DEC_POWERPC=y
+# CONFIG_YOSEMITE is not set
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_ZLIB_INFLATE=y
diff --git a/target/linux/apm821xx/patches-5.15/010-hwmon-tc654-add-thermal_cooling-device.patch b/target/linux/apm821xx/patches-5.15/010-hwmon-tc654-add-thermal_cooling-device.patch
new file mode 100644 (file)
index 0000000..74f8e38
--- /dev/null
@@ -0,0 +1,166 @@
+From 4d49367c5303e3ebd17502a45b74de280f6be539 Mon Sep 17 00:00:00 2001
+From: Christian Lamparter <chunkeey@gmail.com>
+Date: Sun, 13 Feb 2022 01:47:33 +0100
+Subject: hwmon: (tc654) Add thermal_cooling device support
+
+Adds thermal_cooling device support to the tc654/tc655
+driver. This make it possible to integrate it into a
+device-tree supported thermal-zone node as a
+cooling device.
+
+I have been using this patch as part of the Netgear WNDR4700
+Centria NAS Router support within OpenWrt since 2016.
+
+Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
+Link: https://lore.kernel.org/r/20220213004733.2421193-1-chunkeey@gmail.com
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+---
+--- a/drivers/hwmon/tc654.c
++++ b/drivers/hwmon/tc654.c
+@@ -15,6 +15,7 @@
+ #include <linux/module.h>
+ #include <linux/mutex.h>
+ #include <linux/slab.h>
++#include <linux/thermal.h>
+ #include <linux/util_macros.h>
+ enum tc654_regs {
+@@ -379,28 +380,20 @@ static ssize_t pwm_show(struct device *d
+       return sprintf(buf, "%d\n", pwm);
+ }
+-static ssize_t pwm_store(struct device *dev, struct device_attribute *da,
+-                       const char *buf, size_t count)
++static int _set_pwm(struct tc654_data *data, unsigned long val)
+ {
+-      struct tc654_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
+-      unsigned long val;
+       int ret;
+-      if (kstrtoul(buf, 10, &val))
+-              return -EINVAL;
+-      if (val > 255)
+-              return -EINVAL;
+-
+       mutex_lock(&data->update_lock);
+-      if (val == 0)
++      if (val == 0) {
+               data->config |= TC654_REG_CONFIG_SDM;
+-      else
++              data->duty_cycle = 0;
++      } else {
+               data->config &= ~TC654_REG_CONFIG_SDM;
+-
+-      data->duty_cycle = find_closest(val, tc654_pwm_map,
+-                                      ARRAY_SIZE(tc654_pwm_map));
++              data->duty_cycle = val - 1;
++      }
+       ret = i2c_smbus_write_byte_data(client, TC654_REG_CONFIG, data->config);
+       if (ret < 0)
+@@ -411,6 +404,24 @@ static ssize_t pwm_store(struct device *
+ out:
+       mutex_unlock(&data->update_lock);
++      return ret;
++}
++
++static ssize_t pwm_store(struct device *dev, struct device_attribute *da,
++                       const char *buf, size_t count)
++{
++      struct tc654_data *data = dev_get_drvdata(dev);
++      unsigned long val;
++      int ret;
++
++      if (kstrtoul(buf, 10, &val))
++              return -EINVAL;
++      if (val > 255)
++              return -EINVAL;
++      if (val > 0)
++              val = find_closest(val, tc654_pwm_map, ARRAY_SIZE(tc654_pwm_map)) + 1;
++
++      ret = _set_pwm(data, val);
+       return ret < 0 ? ret : count;
+ }
+@@ -443,6 +454,58 @@ static struct attribute *tc654_attrs[] =
+ ATTRIBUTE_GROUPS(tc654);
+ /*
++ * thermal cooling device functions
++ *
++ * Account for the "ShutDown Mode (SDM)" state by offsetting
++ * the 16 PWM duty cycle states by 1.
++ *
++ * State  0 =   0% PWM | Shutdown - Fan(s) are off
++ * State  1 =  30% PWM | duty_cycle =  0
++ * State  2 = ~35% PWM | duty_cycle =  1
++ * [...]
++ * State 15 = ~95% PWM | duty_cycle = 14
++ * State 16 = 100% PWM | duty_cycle = 15
++ */
++#define TC654_MAX_COOLING_STATE       16
++
++static int tc654_get_max_state(struct thermal_cooling_device *cdev, unsigned long *state)
++{
++      *state = TC654_MAX_COOLING_STATE;
++      return 0;
++}
++
++static int tc654_get_cur_state(struct thermal_cooling_device *cdev, unsigned long *state)
++{
++      struct tc654_data *data = tc654_update_client(cdev->devdata);
++
++      if (IS_ERR(data))
++              return PTR_ERR(data);
++
++      if (data->config & TC654_REG_CONFIG_SDM)
++              *state = 0;     /* FAN is off */
++      else
++              *state = data->duty_cycle + 1;  /* offset PWM States by 1 */
++
++      return 0;
++}
++
++static int tc654_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state)
++{
++      struct tc654_data *data = tc654_update_client(cdev->devdata);
++
++      if (IS_ERR(data))
++              return PTR_ERR(data);
++
++      return _set_pwm(data, clamp_val(state, 0, TC654_MAX_COOLING_STATE));
++}
++
++static const struct thermal_cooling_device_ops tc654_fan_cool_ops = {
++      .get_max_state = tc654_get_max_state,
++      .get_cur_state = tc654_get_cur_state,
++      .set_cur_state = tc654_set_cur_state,
++};
++
++/*
+  * device probe and removal
+  */
+@@ -472,7 +535,18 @@ static int tc654_probe(struct i2c_client
+       hwmon_dev =
+           devm_hwmon_device_register_with_groups(dev, client->name, data,
+                                                  tc654_groups);
+-      return PTR_ERR_OR_ZERO(hwmon_dev);
++      if (IS_ERR(hwmon_dev))
++              return PTR_ERR(hwmon_dev);
++
++      if (IS_ENABLED(CONFIG_THERMAL)) {
++              struct thermal_cooling_device *cdev;
++
++              cdev = devm_thermal_of_cooling_device_register(dev, dev->of_node, client->name,
++                                                             hwmon_dev, &tc654_fan_cool_ops);
++              return PTR_ERR_OR_ZERO(cdev);
++      }
++
++      return 0;
+ }
+ static const struct i2c_device_id tc654_id[] = {
diff --git a/target/linux/apm821xx/patches-5.15/201-add-amcc-apollo3g-support.patch b/target/linux/apm821xx/patches-5.15/201-add-amcc-apollo3g-support.patch
new file mode 100644 (file)
index 0000000..e188954
--- /dev/null
@@ -0,0 +1,30 @@
+--- a/arch/powerpc/platforms/44x/Kconfig
++++ b/arch/powerpc/platforms/44x/Kconfig
+@@ -121,6 +121,17 @@ config CANYONLANDS
+       help
+         This option enables support for the AMCC PPC460EX evaluation board.
++config APOLLO3G
++      bool "Apollo3G"
++      depends on 44x
++      default n
++      select PPC44x_SIMPLE
++      select APM821xx
++      select IBM_EMAC_RGMII
++      select 460EX
++      help
++        This option enables support for the AMCC Apollo 3G board.
++
+ config GLACIER
+       bool "Glacier"
+       depends on 44x
+--- a/arch/powerpc/platforms/44x/ppc44x_simple.c
++++ b/arch/powerpc/platforms/44x/ppc44x_simple.c
+@@ -47,6 +47,7 @@ machine_device_initcall(ppc44x_simple, p
+  * board.c file for it rather than adding it to this list.
+  */
+ static char *board[] __initdata = {
++      "amcc,apollo3g",
+       "amcc,arches",
+       "amcc,bamboo",
+       "apm,bluestone",
diff --git a/target/linux/apm821xx/patches-5.15/300-fix-atheros-nics-on-apm82181.patch b/target/linux/apm821xx/patches-5.15/300-fix-atheros-nics-on-apm82181.patch
new file mode 100644 (file)
index 0000000..110726d
--- /dev/null
@@ -0,0 +1,51 @@
+--- a/arch/powerpc/platforms/4xx/pci.c
++++ b/arch/powerpc/platforms/4xx/pci.c
+@@ -1060,15 +1060,24 @@ static int __init apm821xx_pciex_init_po
+       u32 val;
+       /*
+-       * Do a software reset on PCIe ports.
+-       * This code is to fix the issue that pci drivers doesn't re-assign
+-       * bus number for PCIE devices after Uboot
+-       * scanned and configured all the buses (eg. PCIE NIC IntelPro/1000
+-       * PT quad port, SAS LSI 1064E)
++       * Only reset the PHY when no link is currently established.
++       * This is for the Atheros PCIe board which has problems to establish
++       * the link (again) after this PHY reset. All other currently tested
++       * PCIe boards don't show this problem.
+        */
+-
+-      mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x0);
+-      mdelay(10);
++      val = mfdcri(SDR0, port->sdr_base + PESDRn_LOOP);
++      if (!(val & 0x00001000)) {
++              /*
++               * Do a software reset on PCIe ports.
++               * This code is to fix the issue that pci drivers doesn't re-assign
++               * bus number for PCIE devices after Uboot
++               * scanned and configured all the buses (eg. PCIE NIC IntelPro/1000
++               * PT quad port, SAS LSI 1064E)
++               */
++
++              mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x0);
++              mdelay(10);
++      }
+       if (port->endpoint)
+               val = PTYPE_LEGACY_ENDPOINT << 20;
+@@ -1085,9 +1094,12 @@ static int __init apm821xx_pciex_init_po
+       mtdcri(SDR0, PESDR0_460EX_L0DRV, 0x00000130);
+       mtdcri(SDR0, PESDR0_460EX_L0CLK, 0x00000006);
+-      mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x10000000);
+-      mdelay(50);
+-      mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x30000000);
++      val = mfdcri(SDR0, port->sdr_base + PESDRn_LOOP);
++      if (!(val & 0x00001000)) {
++              mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x10000000);
++              mdelay(50);
++              mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x30000000);
++      }
+       mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET,
+               mfdcri(SDR0, port->sdr_base + PESDRn_RCSSET) |
diff --git a/target/linux/apm821xx/patches-5.15/301-fix-memory-map-wndr4700.patch b/target/linux/apm821xx/patches-5.15/301-fix-memory-map-wndr4700.patch
new file mode 100644 (file)
index 0000000..452d97e
--- /dev/null
@@ -0,0 +1,14 @@
+--- a/arch/powerpc/platforms/4xx/pci.c
++++ b/arch/powerpc/platforms/4xx/pci.c
+@@ -1902,9 +1902,9 @@ static void __init ppc4xx_configure_pcie
+                * if it works
+                */
+               out_le32(mbase + PECFG_PIM0LAL, 0x00000000);
+-              out_le32(mbase + PECFG_PIM0LAH, 0x00000000);
++              out_le32(mbase + PECFG_PIM0LAH, 0x00000008);
+               out_le32(mbase + PECFG_PIM1LAL, 0x00000000);
+-              out_le32(mbase + PECFG_PIM1LAH, 0x00000000);
++              out_le32(mbase + PECFG_PIM1LAH, 0x0000000c);
+               out_le32(mbase + PECFG_PIM01SAH, 0xffff0000);
+               out_le32(mbase + PECFG_PIM01SAL, 0x00000000);
diff --git a/target/linux/apm821xx/patches-5.15/900-powerpc-bootwrapper-force-gzip-as-mkimage-s-compress.patch b/target/linux/apm821xx/patches-5.15/900-powerpc-bootwrapper-force-gzip-as-mkimage-s-compress.patch
new file mode 100644 (file)
index 0000000..3a9f48d
--- /dev/null
@@ -0,0 +1,29 @@
+From c9395ad54e2cabb87d408becc37566f3d8248933 Mon Sep 17 00:00:00 2001
+From: Christian Lamparter <chunkeey@gmail.com>
+Date: Sun, 1 Dec 2019 02:08:23 +0100
+Subject: [PATCH] powerpc: bootwrapper: force gzip as mkimage's compression
+ method
+
+Due to CONFIG_KERNEL_XZ symbol, the bootwrapper code tries to
+instruct the mkimage to use the xz compression, which isn't
+supported. This patch forces the gzip compression, which is
+supported and doesn't matter because the generated uImage for
+the apm821xx target gets ignored as the OpenWrt toolchain will
+do separate U-Boot kernel images for each device individually.
+
+Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
+---
+ arch/powerpc/boot/Makefile | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/powerpc/boot/Makefile
++++ b/arch/powerpc/boot/Makefile
+@@ -257,7 +257,7 @@ compressor-$(CONFIG_KERNEL_LZO) := lzo
+ # args (to if_changed): 1 = (this rule), 2 = platform, 3 = dts 4=dtb 5=initrd
+ quiet_cmd_wrap        = WRAP    $@
+-      cmd_wrap        =$(CONFIG_SHELL) $(wrapper) -Z $(compressor-y) -c -o $@ -p $2 \
++      cmd_wrap        =$(CONFIG_SHELL) $(wrapper) -Z gzip -c -o $@ -p $2 \
+               $(CROSSWRAP) $(if $3, -s $3)$(if $4, -d $4)$(if $5, -i $5) \
+               vmlinux
index 1389a2a..8c29bdc 100644 (file)
@@ -36,6 +36,7 @@ CONFIG_ARM64_WORKAROUND_CLEAN_CACHE=y
 CONFIG_ARM64_WORKAROUND_REPEAT_TLBI=y
 CONFIG_ARM64_WORKAROUND_SPECULATIVE_AT=y
 CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND=y
+CONFIG_ARM_SBSA_WATCHDOG=y
 CONFIG_ATOMIC64_SELFTEST=y
 CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
@@ -147,4 +148,5 @@ CONFIG_VEXPRESS_CONFIG=y
 CONFIG_VIDEOMODE_HELPERS=y
 CONFIG_VIRTIO_DMA_SHARED_BUFFER=y
 CONFIG_VMAP_STACK=y
+CONFIG_WATCHDOG_CORE=y
 CONFIG_ZONE_DMA32=y
index 5818dca..c1047c8 100644 (file)
@@ -38,6 +38,7 @@ CONFIG_ARM64_WORKAROUND_CLEAN_CACHE=y
 CONFIG_ARM64_WORKAROUND_REPEAT_TLBI=y
 CONFIG_ARM64_WORKAROUND_SPECULATIVE_AT=y
 CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND=y
+CONFIG_ARM_SBSA_WATCHDOG=y
 CONFIG_ATOMIC64_SELFTEST=y
 CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
@@ -147,4 +148,5 @@ CONFIG_VEXPRESS_CONFIG=y
 CONFIG_VIDEOMODE_HELPERS=y
 CONFIG_VIRTIO_DMA_SHARED_BUFFER=y
 CONFIG_VMAP_STACK=y
+CONFIG_WATCHDOG_CORE=y
 CONFIG_ZONE_DMA32=y
index 46f5be3..436d6e0 100644 (file)
        list_for_each_entry(p, head, list) {
 --- a/net/ipv4/tcp_output.c
 +++ b/net/ipv4/tcp_output.c
-@@ -612,48 +612,53 @@ static void tcp_options_write(__be32 *pt
+@@ -613,48 +613,53 @@ static void tcp_options_write(__be32 *pt
        u16 options = opts->options;    /* mungable copy */
  
        if (unlikely(OPTION_MD5 & options)) {
        }
  
        if (unlikely(opts->num_sack_blocks)) {
-@@ -661,16 +666,17 @@ static void tcp_options_write(__be32 *pt
+@@ -662,16 +667,17 @@ static void tcp_options_write(__be32 *pt
                        tp->duplicate_sack : tp->selective_acks;
                int this_sack;
  
                }
  
                tp->rx_opt.dsack = 0;
-@@ -683,13 +689,14 @@ static void tcp_options_write(__be32 *pt
+@@ -684,13 +690,14 @@ static void tcp_options_write(__be32 *pt
  
                if (foc->exp) {
                        len = TCPOLEN_EXP_FASTOPEN_BASE + foc->len;
  EXPORT_SYMBOL(xfrm_parse_spi);
 --- a/net/ipv4/tcp_input.c
 +++ b/net/ipv4/tcp_input.c
-@@ -4129,14 +4129,16 @@ static bool tcp_parse_aligned_timestamp(
+@@ -4130,14 +4130,16 @@ static bool tcp_parse_aligned_timestamp(
  {
        const __be32 *ptr = (const __be32 *)(th + 1);
  
                *sum = csum_fold(csum_partial(diff, sizeof(diff),
 --- a/include/linux/etherdevice.h
 +++ b/include/linux/etherdevice.h
-@@ -512,7 +512,7 @@ static inline bool is_etherdev_addr(cons
+@@ -511,7 +511,7 @@ static inline bool is_etherdev_addr(cons
   * @b: Pointer to Ethernet header
   *
   * Compare two Ethernet headers, returns 0 if equal.
   * aligned OR the platform can handle unaligned access.  This is the
   * case for all packets coming into netif_receive_skb or similar
   * entry points.
-@@ -535,11 +535,12 @@ static inline unsigned long compare_ethe
+@@ -534,11 +534,12 @@ static inline unsigned long compare_ethe
        fold |= *(unsigned long *)(a + 6) ^ *(unsigned long *)(b + 6);
        return fold;
  #else
diff --git a/target/linux/bcm53xx/base-files/etc/init.d/clear_partialboot b/target/linux/bcm53xx/base-files/etc/init.d/clear_partialboot
deleted file mode 100755 (executable)
index b3eddf4..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/sh /etc/rc.common
-
-START=97
-boot() {
-       . /lib/functions.sh
-
-       case $(board_name) in
-               linksys,panamera)
-                       # clear partialboots
-                       nvram set partialboots=0 && nvram commit
-                       ;;
-       esac
-}
diff --git a/target/linux/generic/backport-5.10/610-v5.15-58-netfilter-flowtable-avoid-possible-false-sharing.patch b/target/linux/generic/backport-5.10/610-v5.15-58-netfilter-flowtable-avoid-possible-false-sharing.patch
new file mode 100644 (file)
index 0000000..69c06c5
--- /dev/null
@@ -0,0 +1,27 @@
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+Date: Sat, 17 Jul 2021 10:10:29 +0200
+Subject: [PATCH] netfilter: flowtable: avoid possible false sharing
+
+The flowtable follows the same timeout approach as conntrack, use the
+same idiom as in cc16921351d8 ("netfilter: conntrack: avoid same-timeout
+update") but also include the fix provided by e37542ba111f ("netfilter:
+conntrack: avoid possible false sharing").
+
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+---
+
+--- a/net/netfilter/nf_flow_table_core.c
++++ b/net/netfilter/nf_flow_table_core.c
+@@ -328,7 +328,11 @@ EXPORT_SYMBOL_GPL(flow_offload_add);
+ void flow_offload_refresh(struct nf_flowtable *flow_table,
+                         struct flow_offload *flow)
+ {
+-      flow->timeout = nf_flowtable_time_stamp + flow_offload_get_timeout(flow);
++      u32 timeout;
++
++      timeout = nf_flowtable_time_stamp + flow_offload_get_timeout(flow);
++      if (READ_ONCE(flow->timeout) != timeout)
++              WRITE_ONCE(flow->timeout, timeout);
+       if (likely(!nf_flowtable_hw_offload(flow_table)))
+               return;
diff --git a/target/linux/generic/backport-5.10/890-v5.19-net-sfp-Add-tx-fault-workaround-for-Huawei-MA5671A-SFP-ON.patch b/target/linux/generic/backport-5.10/890-v5.19-net-sfp-Add-tx-fault-workaround-for-Huawei-MA5671A-SFP-ON.patch
new file mode 100644 (file)
index 0000000..7a9de8e
--- /dev/null
@@ -0,0 +1,57 @@
+From f81d97cb646ab8b90fb181d66fccaf9589990de6 Mon Sep 17 00:00:00 2001
+From: Matthew Hagan <mnhagan88@gmail.com>
+Date: Sat, 30 Apr 2022 11:00:49 +0100
+Subject: [PATCH v2] net: sfp: Add tx-fault workaround for Huawei MA5671A SFP
+ ONT
+
+As noted elsewhere, various GPON SFP modules exhibit non-standard
+TX-fault behaviour. In the tested case, the Huawei MA5671A, when used
+in combination with a Marvell mv88e6085 switch, was found to
+persistently assert TX-fault, resulting in the module being disabled.
+
+This patch adds a quirk to ignore the SFP_F_TX_FAULT state, allowing the
+module to function.
+
+Change from v1: removal of erroneous return statment (Andrew Lunn)
+
+Signed-off-by: Matthew Hagan <mnhagan88@gmail.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+---
+ drivers/net/phy/sfp.c | 12 +++++++++++-
+ 1 file changed, 11 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -249,6 +249,7 @@ struct sfp {
+       struct sfp_eeprom_id id;
+       unsigned int module_power_mW;
+       unsigned int module_t_start_up;
++      bool tx_fault_ignore;
+ #if IS_ENABLED(CONFIG_HWMON)
+       struct sfp_diag diag;
+@@ -1893,6 +1894,12 @@ static int sfp_sm_mod_probe(struct sfp *
+       else
+               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;
++
+       return 0;
+ }
+@@ -2320,7 +2327,10 @@ static void sfp_check_state(struct sfp *
+       mutex_lock(&sfp->st_mutex);
+       state = sfp_get_state(sfp);
+       changed = state ^ sfp->state;
+-      changed &= SFP_F_PRESENT | SFP_F_LOS | SFP_F_TX_FAULT;
++      if (sfp->tx_fault_ignore)
++              changed &= SFP_F_PRESENT | SFP_F_LOS;
++      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/backport-5.15/890-v5.19-net-sfp-Add-tx-fault-workaround-for-Huawei-MA5671A-SFP-ON.patch b/target/linux/generic/backport-5.15/890-v5.19-net-sfp-Add-tx-fault-workaround-for-Huawei-MA5671A-SFP-ON.patch
new file mode 100644 (file)
index 0000000..bcada79
--- /dev/null
@@ -0,0 +1,57 @@
+From f81d97cb646ab8b90fb181d66fccaf9589990de6 Mon Sep 17 00:00:00 2001
+From: Matthew Hagan <mnhagan88@gmail.com>
+Date: Sat, 30 Apr 2022 11:00:49 +0100
+Subject: [PATCH v2] net: sfp: Add tx-fault workaround for Huawei MA5671A SFP
+ ONT
+
+As noted elsewhere, various GPON SFP modules exhibit non-standard
+TX-fault behaviour. In the tested case, the Huawei MA5671A, when used
+in combination with a Marvell mv88e6085 switch, was found to
+persistently assert TX-fault, resulting in the module being disabled.
+
+This patch adds a quirk to ignore the SFP_F_TX_FAULT state, allowing the
+module to function.
+
+Change from v1: removal of erroneous return statment (Andrew Lunn)
+
+Signed-off-by: Matthew Hagan <mnhagan88@gmail.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+---
+ drivers/net/phy/sfp.c | 12 +++++++++++-
+ 1 file changed, 11 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -250,6 +250,7 @@ struct sfp {
+       struct sfp_eeprom_id id;
+       unsigned int module_power_mW;
+       unsigned int module_t_start_up;
++      bool tx_fault_ignore;
+ #if IS_ENABLED(CONFIG_HWMON)
+       struct sfp_diag diag;
+@@ -1945,6 +1946,12 @@ static int sfp_sm_mod_probe(struct sfp *
+       else
+               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;
++
+       return 0;
+ }
+@@ -2397,7 +2404,10 @@ static void sfp_check_state(struct sfp *
+       mutex_lock(&sfp->st_mutex);
+       state = sfp_get_state(sfp);
+       changed = state ^ sfp->state;
+-      changed &= SFP_F_PRESENT | SFP_F_LOS | SFP_F_TX_FAULT;
++      if (sfp->tx_fault_ignore)
++              changed &= SFP_F_PRESENT | SFP_F_LOS;
++      else
++              changed &= SFP_F_PRESENT | SFP_F_LOS | SFP_F_TX_FAULT;
+       for (i = 0; i < GPIO_MAX; i++)
+               if (changed & BIT(i))
index 0aea476..13b8189 100644 (file)
@@ -4137,6 +4137,7 @@ CONFIG_NET_SCH_FQ_CODEL=y
 # 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
index 2333253..8435ae7 100644 (file)
@@ -98,7 +98,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
  obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o
 --- /dev/null
 +++ b/net/netfilter/xt_FLOWOFFLOAD.c
-@@ -0,0 +1,657 @@
+@@ -0,0 +1,712 @@
 +/*
 + * Copyright (C) 2018-2021 Felix Fietkau <nbd@nbd.name>
 + *
@@ -110,6 +110,9 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
 +#include <linux/init.h>
 +#include <linux/netfilter.h>
 +#include <linux/netfilter/xt_FLOWOFFLOAD.h>
++#include <linux/if_vlan.h>
++#include <linux/if_pppox.h>
++#include <linux/ppp_defs.h>
 +#include <net/ip.h>
 +#include <net/netfilter/nf_conntrack.h>
 +#include <net/netfilter/nf_conntrack_extend.h>
@@ -130,20 +133,62 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
 +      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 inline __be16 nf_flow_pppoe_proto(const struct sk_buff *skb)
++{
++      __be16 proto;
++
++      proto = *((__be16 *)(skb_mac_header(skb) + ETH_HLEN +
++                           sizeof(struct pppoe_hdr)));
++      switch (proto) {
++      case htons(PPP_IP):
++              return htons(ETH_P_IP);
++      case htons(PPP_IPV6):
++              return htons(ETH_P_IPV6);
++      }
++
++      return 0;
++}
++
 +static unsigned int
 +xt_flowoffload_net_hook(void *priv, struct sk_buff *skb,
 +                      const struct nf_hook_state *state)
 +{
-+      struct nf_flowtable *ft = priv;
-+
-+      if (!atomic_read(&ft->rhashtable.nelems))
-+              return NF_ACCEPT;
++      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):
@@ -323,7 +368,26 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
 +      return false;
 +}
 +
-+static bool flow_is_valid_ether_device(const struct net_device *dev)
++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))
@@ -332,174 +396,181 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
 +      return true;
 +}
 +
-+static void
-+xt_flowoffload_route_check_path(struct nf_flow_route *route,
-+                              const struct nf_conn *ct,
-+                              enum ip_conntrack_dir dir,
-+                              struct net_device **out_dev)
++static void nf_dev_path_info(const struct net_device_path_stack *stack,
++                           struct nf_forward_info *info,
++                           unsigned char *ha)
 +{
-+      const struct dst_entry *dst = route->tuple[dir].dst;
-+      const void *daddr = &ct->tuplehash[!dir].tuple.src.u3;
-+      struct net_device_path_stack stack;
-+      enum net_device_path_type prev_type;
-+      struct net_device *dev = dst->dev;
-+      struct neighbour *n;
-+      bool last = false;
-+      u8 nud_state;
++      const struct net_device_path *path;
 +      int i;
 +
-+      route->tuple[!dir].in.ifindex = dev->ifindex;
-+      route->tuple[dir].out.ifindex = dev->ifindex;
-+
-+      if (route->tuple[dir].xmit_type == FLOW_OFFLOAD_XMIT_XFRM)
-+              return;
-+
-+      if ((dev->flags & IFF_LOOPBACK) ||
-+          dev->type != ARPHRD_ETHER || dev->addr_len != ETH_ALEN ||
-+          !is_valid_ether_addr(dev->dev_addr))
-+              return;
-+
-+      n = dst_neigh_lookup(dst, daddr);
-+      if (!n)
-+              return;
-+
-+      read_lock_bh(&n->lock);
-+      nud_state = n->nud_state;
-+      memcpy(route->tuple[dir].out.h_dest, n->ha, ETH_ALEN);
-+      read_unlock_bh(&n->lock);
-+      neigh_release(n);
-+
-+      if (!(nud_state & NUD_VALID))
-+              return;
-+
-+      if (dev_fill_forward_path(dev, route->tuple[dir].out.h_dest, &stack) ||
-+          !stack.num_paths)
-+              return;
-+
-+      prev_type = DEV_PATH_ETHERNET;
-+      for (i = 0; i <= stack.num_paths; i++) {
-+              const struct net_device_path *path = &stack.path[i];
-+              int n_encaps = route->tuple[!dir].in.num_encaps;
-+
-+              dev = (struct net_device *)path->dev;
-+              if (flow_is_valid_ether_device(dev)) {
-+                      if (route->tuple[dir].xmit_type != FLOW_OFFLOAD_XMIT_DIRECT) {
-+                              memcpy(route->tuple[dir].out.h_source,
-+                                     dev->dev_addr, ETH_ALEN);
-+                              route->tuple[dir].out.ifindex = dev->ifindex;
-+                      }
-+                      route->tuple[dir].xmit_type = FLOW_OFFLOAD_XMIT_DIRECT;
-+              }
++      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_PPPOE:
++              case DEV_PATH_ETHERNET:
++              case DEV_PATH_DSA:
 +              case DEV_PATH_VLAN:
-+                      if (n_encaps >= NF_FLOW_TABLE_ENCAP_MAX ||
-+                          i == stack.num_paths) {
-+                              last = true;
++              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;
 +                      }
 +
-+                      route->tuple[!dir].in.num_encaps++;
-+                      route->tuple[!dir].in.encap[n_encaps].id = path->encap.id;
-+                      route->tuple[!dir].in.encap[n_encaps].proto = path->encap.proto;
++                      /* 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(route->tuple[dir].out.h_dest,
-+                                     path->encap.h_dest, ETH_ALEN);
++                              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:
-+                              if (n_encaps >= NF_FLOW_TABLE_ENCAP_MAX ||
-+                                  i == stack.num_paths) {
-+                                      last = true;
-+                                      break;
-+                              }
-+
-+                              route->tuple[!dir].in.num_encaps++;
-+                              route->tuple[!dir].in.encap[n_encaps].id =
-+                                      path->bridge.vlan_id;
-+                              route->tuple[!dir].in.encap[n_encaps].proto =
-+                                      path->bridge.vlan_proto;
++                              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:
-+                              route->tuple[!dir].in.num_encaps--;
-+                              break;
-+                      case DEV_PATH_BR_VLAN_UNTAG_HW:
-+                              route->tuple[!dir].in.ingress_vlans |= BIT(n_encaps - 1);
++                              info->num_encaps--;
 +                              break;
 +                      case DEV_PATH_BR_VLAN_KEEP:
 +                              break;
 +                      }
 +                      break;
 +              default:
-+                      last = true;
++                      info->indev = NULL;
 +                      break;
 +              }
-+
-+              if (last)
-+                      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_dev = dev;
-+      route->tuple[dir].out.hw_ifindex = dev->ifindex;
-+      route->tuple[!dir].in.ifindex = dev->ifindex;
++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_dir(struct nf_flow_route *route, const struct nf_conn *ct,
-+                       enum ip_conntrack_dir dir,
-+                       const struct xt_action_param *par, int ifindex)
++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 *dst = NULL;
++      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 = ifindex;
++              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 = ifindex;
++              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), &dst, &fl, false, xt_family(par));
-+      if (!dst)
++      nf_route(xt_net(par), &other_dst, &fl, false, xt_family(par));
++      if (!other_dst)
 +              return -ENOENT;
 +
-+      route->tuple[dir].dst = dst;
-+      if (dst_xfrm(dst))
-+              route->tuple[dir].xmit_type = FLOW_OFFLOAD_XMIT_XFRM;
-+      else
-+              route->tuple[dir].xmit_type = FLOW_OFFLOAD_XMIT_NEIGH;
-+
-+      return 0;
-+}
-+
-+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 **dev)
-+{
-+      int ret;
-+
-+      ret = xt_flowoffload_route_dir(route, ct, dir, par,
-+                                     dev[dir]->ifindex);
-+      if (ret)
-+              return ret;
++      nf_default_forward_path(route, this_dst, dir, devs);
++      nf_default_forward_path(route, other_dst, !dir, devs);
 +
-+      ret = xt_flowoffload_route_dir(route, ct, !dir, par,
-+                                     dev[!dir]->ifindex);
-+      if (ret)
-+              return ret;
-+
-+      xt_flowoffload_route_check_path(route, ct, dir, &dev[!dir]);
-+      xt_flowoffload_route_check_path(route, ct, !dir, &dev[dir]);
++      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;
 +}
@@ -542,7 +613,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
 +      }
 +
 +      if (nf_ct_ext_exist(ct, NF_CT_EXT_HELPER) ||
-+          ct->status & IPS_SEQ_ADJUST)
++          ct->status & (IPS_SEQ_ADJUST | IPS_NAT_CLASH))
 +              return XT_CONTINUE;
 +
 +      if (!nf_ct_is_confirmed(ct))
@@ -586,7 +657,6 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
 +      xt_flowoffload_check_device(table, devs[0]);
 +      xt_flowoffload_check_device(table, devs[1]);
 +
-+      dst_release(route.tuple[dir].dst);
 +      dst_release(route.tuple[!dir].dst);
 +
 +      return XT_CONTINUE;
@@ -594,7 +664,6 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
 +err_flow_add:
 +      flow_offload_free(flow);
 +err_flow_alloc:
-+      dst_release(route.tuple[dir].dst);
 +      dst_release(route.tuple[!dir].dst);
 +err_flow_route:
 +      clear_bit(IPS_OFFLOAD_BIT, &ct->status);
@@ -661,20 +730,6 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
 +      .notifier_call  = flow_offload_netdev_event,
 +};
 +
-+static unsigned int
-+nf_flow_offload_inet_hook(void *priv, struct sk_buff *skb,
-+                        const struct nf_hook_state *state)
-+{
-+      switch (skb->protocol) {
-+      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 nf_flow_rule_route_inet(struct net *net,
 +                                 const struct flow_offload *flow,
 +                                 enum flow_offload_tuple_dir dir,
@@ -704,7 +759,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
 +      .setup          = nf_flow_table_offload_setup,
 +      .action         = nf_flow_rule_route_inet,
 +      .free           = nf_flow_table_free,
-+      .hook           = nf_flow_offload_inet_hook,
++      .hook           = xt_flowoffload_net_hook,
 +      .owner          = THIS_MODULE,
 +};
 +
@@ -766,7 +821,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
  #include <net/netfilter/nf_flow_table.h>
  #include <net/netfilter/nf_conntrack.h>
  #include <net/netfilter/nf_conntrack_core.h>
-@@ -395,8 +394,7 @@ flow_offload_lookup(struct nf_flowtable
+@@ -401,8 +400,7 @@ flow_offload_lookup(struct nf_flowtable
  }
  EXPORT_SYMBOL_GPL(flow_offload_lookup);
  
@@ -776,7 +831,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
                      void (*iter)(struct flow_offload *flow, void *data),
                      void *data)
  {
-@@ -428,6 +426,7 @@ nf_flow_table_iterate(struct nf_flowtabl
+@@ -434,6 +432,7 @@ nf_flow_table_iterate(struct nf_flowtabl
  
        return err;
  }
index fa21ca1..0eca9f8 100644 (file)
@@ -98,7 +98,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
  obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o
 --- /dev/null
 +++ b/net/netfilter/xt_FLOWOFFLOAD.c
-@@ -0,0 +1,657 @@
+@@ -0,0 +1,694 @@
 +/*
 + * Copyright (C) 2018-2021 Felix Fietkau <nbd@nbd.name>
 + *
@@ -110,6 +110,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
 +#include <linux/init.h>
 +#include <linux/netfilter.h>
 +#include <linux/netfilter/xt_FLOWOFFLOAD.h>
++#include <linux/if_vlan.h>
 +#include <net/ip.h>
 +#include <net/netfilter/nf_conntrack.h>
 +#include <net/netfilter/nf_conntrack_extend.h>
@@ -130,6 +131,21 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
 +      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];
@@ -138,12 +154,23 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
 +xt_flowoffload_net_hook(void *priv, struct sk_buff *skb,
 +                      const struct nf_hook_state *state)
 +{
-+      struct nf_flowtable *ft = priv;
-+
-+      if (!atomic_read(&ft->rhashtable.nelems))
-+              return NF_ACCEPT;
++      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):
@@ -323,7 +350,26 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
 +      return false;
 +}
 +
-+static bool flow_is_valid_ether_device(const struct net_device *dev)
++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))
@@ -332,174 +378,181 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
 +      return true;
 +}
 +
-+static void
-+xt_flowoffload_route_check_path(struct nf_flow_route *route,
-+                              const struct nf_conn *ct,
-+                              enum ip_conntrack_dir dir,
-+                              struct net_device **out_dev)
++static void nf_dev_path_info(const struct net_device_path_stack *stack,
++                           struct nf_forward_info *info,
++                           unsigned char *ha)
 +{
-+      const struct dst_entry *dst = route->tuple[dir].dst;
-+      const void *daddr = &ct->tuplehash[!dir].tuple.src.u3;
-+      struct net_device_path_stack stack;
-+      enum net_device_path_type prev_type;
-+      struct net_device *dev = dst->dev;
-+      struct neighbour *n;
-+      bool last = false;
-+      u8 nud_state;
++      const struct net_device_path *path;
 +      int i;
 +
-+      route->tuple[!dir].in.ifindex = dev->ifindex;
-+      route->tuple[dir].out.ifindex = dev->ifindex;
-+
-+      if (route->tuple[dir].xmit_type == FLOW_OFFLOAD_XMIT_XFRM)
-+              return;
-+
-+      if ((dev->flags & IFF_LOOPBACK) ||
-+          dev->type != ARPHRD_ETHER || dev->addr_len != ETH_ALEN ||
-+          !is_valid_ether_addr(dev->dev_addr))
-+              return;
-+
-+      n = dst_neigh_lookup(dst, daddr);
-+      if (!n)
-+              return;
-+
-+      read_lock_bh(&n->lock);
-+      nud_state = n->nud_state;
-+      memcpy(route->tuple[dir].out.h_dest, n->ha, ETH_ALEN);
-+      read_unlock_bh(&n->lock);
-+      neigh_release(n);
-+
-+      if (!(nud_state & NUD_VALID))
-+              return;
-+
-+      if (dev_fill_forward_path(dev, route->tuple[dir].out.h_dest, &stack) ||
-+          !stack.num_paths)
-+              return;
-+
-+      prev_type = DEV_PATH_ETHERNET;
-+      for (i = 0; i <= stack.num_paths; i++) {
-+              const struct net_device_path *path = &stack.path[i];
-+              int n_encaps = route->tuple[!dir].in.num_encaps;
-+
-+              dev = (struct net_device *)path->dev;
-+              if (flow_is_valid_ether_device(dev)) {
-+                      if (route->tuple[dir].xmit_type != FLOW_OFFLOAD_XMIT_DIRECT) {
-+                              memcpy(route->tuple[dir].out.h_source,
-+                                     dev->dev_addr, ETH_ALEN);
-+                              route->tuple[dir].out.ifindex = dev->ifindex;
-+                      }
-+                      route->tuple[dir].xmit_type = FLOW_OFFLOAD_XMIT_DIRECT;
-+              }
++      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_PPPOE:
++              case DEV_PATH_ETHERNET:
++              case DEV_PATH_DSA:
 +              case DEV_PATH_VLAN:
-+                      if (n_encaps >= NF_FLOW_TABLE_ENCAP_MAX ||
-+                          i == stack.num_paths) {
-+                              last = true;
++              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;
 +                      }
 +
-+                      route->tuple[!dir].in.num_encaps++;
-+                      route->tuple[!dir].in.encap[n_encaps].id = path->encap.id;
-+                      route->tuple[!dir].in.encap[n_encaps].proto = path->encap.proto;
++                      /* 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(route->tuple[dir].out.h_dest,
-+                                     path->encap.h_dest, ETH_ALEN);
++                              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:
-+                              if (n_encaps >= NF_FLOW_TABLE_ENCAP_MAX ||
-+                                  i == stack.num_paths) {
-+                                      last = true;
-+                                      break;
-+                              }
-+
-+                              route->tuple[!dir].in.num_encaps++;
-+                              route->tuple[!dir].in.encap[n_encaps].id =
-+                                      path->bridge.vlan_id;
-+                              route->tuple[!dir].in.encap[n_encaps].proto =
-+                                      path->bridge.vlan_proto;
++                              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:
-+                              route->tuple[!dir].in.num_encaps--;
-+                              break;
-+                      case DEV_PATH_BR_VLAN_UNTAG_HW:
-+                              route->tuple[!dir].in.ingress_vlans |= BIT(n_encaps - 1);
++                              info->num_encaps--;
 +                              break;
 +                      case DEV_PATH_BR_VLAN_KEEP:
 +                              break;
 +                      }
 +                      break;
 +              default:
-+                      last = true;
++                      info->indev = NULL;
 +                      break;
 +              }
-+
-+              if (last)
-+                      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;
 +
-+      *out_dev = dev;
-+      route->tuple[dir].out.hw_ifindex = dev->ifindex;
-+      route->tuple[!dir].in.ifindex = dev->ifindex;
++      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_dir(struct nf_flow_route *route, const struct nf_conn *ct,
-+                       enum ip_conntrack_dir dir,
-+                       const struct xt_action_param *par, int ifindex)
++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 *dst = NULL;
++      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 = ifindex;
++              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 = ifindex;
++              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), &dst, &fl, false, xt_family(par));
-+      if (!dst)
++      nf_route(xt_net(par), &other_dst, &fl, false, xt_family(par));
++      if (!other_dst)
 +              return -ENOENT;
 +
-+      route->tuple[dir].dst = dst;
-+      if (dst_xfrm(dst))
-+              route->tuple[dir].xmit_type = FLOW_OFFLOAD_XMIT_XFRM;
-+      else
-+              route->tuple[dir].xmit_type = FLOW_OFFLOAD_XMIT_NEIGH;
-+
-+      return 0;
-+}
-+
-+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 **dev)
-+{
-+      int ret;
++      nf_default_forward_path(route, this_dst, dir, devs);
++      nf_default_forward_path(route, other_dst, !dir, devs);
 +
-+      ret = xt_flowoffload_route_dir(route, ct, dir, par,
-+                                     dev[dir]->ifindex);
-+      if (ret)
-+              return ret;
-+
-+      ret = xt_flowoffload_route_dir(route, ct, !dir, par,
-+                                     dev[!dir]->ifindex);
-+      if (ret)
-+              return ret;
-+
-+      xt_flowoffload_route_check_path(route, ct, dir, &dev[!dir]);
-+      xt_flowoffload_route_check_path(route, ct, !dir, &dev[dir]);
++      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;
 +}
@@ -542,7 +595,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
 +      }
 +
 +      if (nf_ct_ext_exist(ct, NF_CT_EXT_HELPER) ||
-+          ct->status & IPS_SEQ_ADJUST)
++          ct->status & (IPS_SEQ_ADJUST | IPS_NAT_CLASH))
 +              return XT_CONTINUE;
 +
 +      if (!nf_ct_is_confirmed(ct))
@@ -586,7 +639,6 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
 +      xt_flowoffload_check_device(table, devs[0]);
 +      xt_flowoffload_check_device(table, devs[1]);
 +
-+      dst_release(route.tuple[dir].dst);
 +      dst_release(route.tuple[!dir].dst);
 +
 +      return XT_CONTINUE;
@@ -594,7 +646,6 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
 +err_flow_add:
 +      flow_offload_free(flow);
 +err_flow_alloc:
-+      dst_release(route.tuple[dir].dst);
 +      dst_release(route.tuple[!dir].dst);
 +err_flow_route:
 +      clear_bit(IPS_OFFLOAD_BIT, &ct->status);
@@ -661,20 +712,6 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
 +      .notifier_call  = flow_offload_netdev_event,
 +};
 +
-+static unsigned int
-+nf_flow_offload_inet_hook(void *priv, struct sk_buff *skb,
-+                        const struct nf_hook_state *state)
-+{
-+      switch (skb->protocol) {
-+      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 nf_flow_rule_route_inet(struct net *net,
 +                                 const struct flow_offload *flow,
 +                                 enum flow_offload_tuple_dir dir,
@@ -704,7 +741,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
 +      .setup          = nf_flow_table_offload_setup,
 +      .action         = nf_flow_rule_route_inet,
 +      .free           = nf_flow_table_free,
-+      .hook           = nf_flow_offload_inet_hook,
++      .hook           = xt_flowoffload_net_hook,
 +      .owner          = THIS_MODULE,
 +};
 +
@@ -766,7 +803,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
  #include <net/netfilter/nf_flow_table.h>
  #include <net/netfilter/nf_conntrack.h>
  #include <net/netfilter/nf_conntrack_core.h>
-@@ -397,8 +396,7 @@ flow_offload_lookup(struct nf_flowtable
+@@ -399,8 +398,7 @@ flow_offload_lookup(struct nf_flowtable
  }
  EXPORT_SYMBOL_GPL(flow_offload_lookup);
  
@@ -776,7 +813,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
                      void (*iter)(struct flow_offload *flow, void *data),
                      void *data)
  {
-@@ -430,6 +428,7 @@ nf_flow_table_iterate(struct nf_flowtabl
+@@ -432,6 +430,7 @@ nf_flow_table_iterate(struct nf_flowtabl
  
        return err;
  }
index 85dc3db..8affabd 100644 (file)
@@ -19,7 +19,7 @@
  
  #define QUECTEL_VENDOR_ID                     0x2c7c
  /* These Quectel products use Quectel's vendor ID */
-@@ -1127,6 +1129,11 @@ static const struct usb_device_id option
+@@ -1129,6 +1131,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) },
diff --git a/target/linux/generic/pending-5.10/704-00-netfilter-flowtable-fix-excessive-hw-offload-attempt.patch b/target/linux/generic/pending-5.10/704-00-netfilter-flowtable-fix-excessive-hw-offload-attempt.patch
new file mode 100644 (file)
index 0000000..c15f090
--- /dev/null
@@ -0,0 +1,27 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Fri, 6 May 2022 12:37:23 +0200
+Subject: [PATCH] netfilter: flowtable: fix excessive hw offload attempts
+ after failure
+
+If a flow cannot be offloaded, the code currently repeatedly tries again as
+quickly as possible, which can significantly increase system load.
+Fix this by limiting flow timeout update and hardware offload retry to once
+per second.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/netfilter/nf_flow_table_core.c
++++ b/net/netfilter/nf_flow_table_core.c
+@@ -331,8 +331,10 @@ void flow_offload_refresh(struct nf_flow
+       u32 timeout;
+       timeout = nf_flowtable_time_stamp + flow_offload_get_timeout(flow);
+-      if (READ_ONCE(flow->timeout) != timeout)
++      if (timeout - READ_ONCE(flow->timeout) > HZ)
+               WRITE_ONCE(flow->timeout, timeout);
++      else
++              return;
+       if (likely(!nf_flowtable_hw_offload(flow_table)))
+               return;
diff --git a/target/linux/generic/pending-5.10/704-01-netfilter-nft_flow_offload-skip-dst-neigh-lookup-for.patch b/target/linux/generic/pending-5.10/704-01-netfilter-nft_flow_offload-skip-dst-neigh-lookup-for.patch
new file mode 100644 (file)
index 0000000..6683a53
--- /dev/null
@@ -0,0 +1,64 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Fri, 6 May 2022 12:43:58 +0200
+Subject: [PATCH] netfilter: nft_flow_offload: skip dst neigh lookup for
+ ppp devices
+
+The dst entry does not contain a valid hardware address, so skip the lookup
+in order to avoid running into errors here.
+The proper hardware address is filled in from nft_dev_path_info
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/netfilter/nft_flow_offload.c
++++ b/net/netfilter/nft_flow_offload.c
+@@ -36,6 +36,15 @@ static void nft_default_forward_path(str
+       route->tuple[dir].xmit_type     = nft_xmit_type(dst_cache);
+ }
++static bool nft_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 int nft_dev_fill_forward_path(const struct nf_flow_route *route,
+                                    const struct dst_entry *dst_cache,
+                                    const struct nf_conn *ct,
+@@ -47,6 +56,9 @@ static int nft_dev_fill_forward_path(con
+       struct neighbour *n;
+       u8 nud_state;
++      if (!nft_is_valid_ether_device(dev))
++              goto out;
++
+       n = dst_neigh_lookup(dst_cache, daddr);
+       if (!n)
+               return -1;
+@@ -60,6 +72,7 @@ static int nft_dev_fill_forward_path(con
+       if (!(nud_state & NUD_VALID))
+               return -1;
++out:
+       return dev_fill_forward_path(dev, ha, stack);
+ }
+@@ -78,15 +91,6 @@ struct nft_forward_info {
+       enum flow_offload_xmit_type xmit_type;
+ };
+-static bool nft_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 nft_dev_path_info(const struct net_device_path_stack *stack,
+                             struct nft_forward_info *info,
+                             unsigned char *ha, struct nf_flowtable *flowtable)
diff --git a/target/linux/generic/pending-5.10/704-02-net-fix-dev_fill_forward_path-with-pppoe-bridge.patch b/target/linux/generic/pending-5.10/704-02-net-fix-dev_fill_forward_path-with-pppoe-bridge.patch
new file mode 100644 (file)
index 0000000..04698f6
--- /dev/null
@@ -0,0 +1,66 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Fri, 6 May 2022 13:54:44 +0200
+Subject: [PATCH] net: fix dev_fill_forward_path with pppoe + bridge
+
+When calling dev_fill_forward_path on a pppoe device, the provided destination
+address is invalid. In order for the bridge fdb lookup to succeed, the pppoe
+code needs to update ctx->daddr to the correct value.
+Fix this by storing the address inside struct net_device_path_ctx
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
++++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+@@ -91,7 +91,6 @@ mtk_flow_get_wdma_info(struct net_device
+ {
+       struct net_device_path_ctx ctx = {
+               .dev = dev,
+-              .daddr = addr,
+       };
+       struct net_device_path path = {};
+@@ -101,6 +100,7 @@ mtk_flow_get_wdma_info(struct net_device
+       if (!dev->netdev_ops->ndo_fill_forward_path)
+               return -1;
++      memcpy(ctx.daddr, addr, sizeof(ctx.daddr));
+       if (dev->netdev_ops->ndo_fill_forward_path(&ctx, &path))
+               return -1;
+--- a/drivers/net/ppp/pppoe.c
++++ b/drivers/net/ppp/pppoe.c
+@@ -988,6 +988,7 @@ static int pppoe_fill_forward_path(struc
+       path->encap.proto = htons(ETH_P_PPP_SES);
+       path->encap.id = be16_to_cpu(po->num);
+       memcpy(path->encap.h_dest, po->pppoe_pa.remote, ETH_ALEN);
++      memcpy(ctx->daddr, po->pppoe_pa.remote, ETH_ALEN);
+       path->dev = ctx->dev;
+       ctx->dev = dev;
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -878,7 +878,7 @@ struct net_device_path_stack {
+ struct net_device_path_ctx {
+       const struct net_device *dev;
+-      const u8                *daddr;
++      u8                      daddr[ETH_ALEN];
+       int                     num_vlans;
+       struct {
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -863,11 +863,11 @@ int dev_fill_forward_path(const struct n
+       const struct net_device *last_dev;
+       struct net_device_path_ctx ctx = {
+               .dev    = dev,
+-              .daddr  = daddr,
+       };
+       struct net_device_path *path;
+       int ret = 0;
++      memcpy(ctx.daddr, daddr, sizeof(ctx.daddr));
+       stack->num_paths = 0;
+       while (ctx.dev && ctx.dev->netdev_ops->ndo_fill_forward_path) {
+               last_dev = ctx.dev;
diff --git a/target/linux/generic/pending-5.10/704-03-netfilter-nft_flow_offload-fix-offload-with-pppoe-vl.patch b/target/linux/generic/pending-5.10/704-03-netfilter-nft_flow_offload-fix-offload-with-pppoe-vl.patch
new file mode 100644 (file)
index 0000000..1e0dc99
--- /dev/null
@@ -0,0 +1,24 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Fri, 6 May 2022 15:15:06 +0200
+Subject: [PATCH] netfilter: nft_flow_offload: fix offload with pppoe +
+ vlan
+
+When running a combination of PPPoE on top of a VLAN, we need to set
+info->outdev to the PPPoE device, otherwise PPPoE encap is skipped
+during software offload.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/netfilter/nft_flow_offload.c
++++ b/net/netfilter/nft_flow_offload.c
+@@ -123,7 +123,8 @@ static void nft_dev_path_info(const stru
+                               info->indev = NULL;
+                               break;
+                       }
+-                      info->outdev = path->dev;
++                      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++;
diff --git a/target/linux/generic/pending-5.10/705-net-dsa-tag_mtk-add-padding-for-tx-packets.patch b/target/linux/generic/pending-5.10/705-net-dsa-tag_mtk-add-padding-for-tx-packets.patch
new file mode 100644 (file)
index 0000000..e27ac35
--- /dev/null
@@ -0,0 +1,29 @@
+From: Felix Fietkau <nbd@nbd.name>
+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 <nbd@nbd.name>
+---
+
+--- a/net/dsa/tag_mtk.c
++++ b/net/dsa/tag_mtk.c
+@@ -25,6 +25,14 @@ static struct sk_buff *mtk_tag_xmit(stru
+       u8 xmit_tpid;
+       u8 *mtk_tag;
++      /* 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).
++       */
++      if (__skb_put_padto(skb, ETH_ZLEN + MTK_HDR_LEN, false))
++              return NULL;
++
+       /* 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
index 18f26d9..1acb8d7 100644 (file)
  obj-$(CONFIG_MTD_BLOCK)               += mtdblock.o
 --- a/include/linux/mtd/mtd.h
 +++ b/include/linux/mtd/mtd.h
-@@ -615,6 +615,24 @@ static inline void mtd_align_erase_req(s
+@@ -613,6 +613,24 @@ static inline void mtd_align_erase_req(s
                req->len += mtd->erasesize - mod;
  }
  
  static inline uint32_t mtd_div_by_ws(uint64_t sz, struct mtd_info *mtd)
  {
        if (mtd->writesize_shift)
-@@ -687,6 +705,13 @@ extern void __put_mtd_device(struct mtd_
+@@ -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);
  
index 45fbcf7..a708a46 100644 (file)
@@ -64,7 +64,7 @@ Reviewed-by: Miquel Raynal <miquel.raynal@bootlin.com>
        mutex_lock(&mtd_table_mutex);
 --- a/include/linux/mtd/mtd.h
 +++ b/include/linux/mtd/mtd.h
-@@ -705,6 +705,8 @@ extern struct mtd_info *get_mtd_device(s
+@@ -703,6 +703,8 @@ extern struct mtd_info *get_mtd_device(s
  extern int __get_mtd_device(struct mtd_info *mtd);
  extern void __put_mtd_device(struct mtd_info *mtd);
  extern struct mtd_info *get_mtd_device_nm(const char *name);
index 70f07ba..c61935f 100644 (file)
@@ -87,7 +87,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
        if (!net_eq(dev_net(dev), sock_net(sk)))
                goto drop;
  
-@@ -3325,6 +3327,7 @@ static int packet_create(struct net *net
+@@ -3330,6 +3332,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 <nbd@nbd.name>
  
        if (sock->type == SOCK_PACKET)
                po->prot_hook.func = packet_rcv_spkt;
-@@ -3966,6 +3969,16 @@ packet_setsockopt(struct socket *sock, i
+@@ -3971,6 +3974,16 @@ packet_setsockopt(struct socket *sock, i
                po->xmit = val ? packet_direct_xmit : dev_queue_xmit;
                return 0;
        }
@@ -112,7 +112,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
        default:
                return -ENOPROTOOPT;
        }
-@@ -4022,6 +4035,13 @@ static int packet_getsockopt(struct sock
+@@ -4027,6 +4040,13 @@ static int packet_getsockopt(struct sock
        case PACKET_VNET_HDR:
                val = po->has_vnet_hdr;
                break;
index 3fb053a..3a00359 100644 (file)
@@ -157,7 +157,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
        case RTN_THROW:
        case RTN_UNREACHABLE:
        default:
-@@ -4559,6 +4578,17 @@ static int ip6_pkt_prohibit_out(struct n
+@@ -4560,6 +4579,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 <jogo@openwrt.org>
  /*
   *    Allocate a dst for local (unicast / anycast) address.
   */
-@@ -5039,7 +5069,8 @@ static int rtm_to_fib6_config(struct sk_
+@@ -5040,7 +5070,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 <jogo@openwrt.org>
                cfg->fc_flags |= RTF_REJECT;
  
        if (rtm->rtm_type == RTN_LOCAL)
-@@ -6292,6 +6323,8 @@ static int ip6_route_dev_notify(struct n
+@@ -6293,6 +6324,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 <jogo@openwrt.org>
                net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
                net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
  #endif
-@@ -6303,6 +6336,7 @@ static int ip6_route_dev_notify(struct n
+@@ -6304,6 +6337,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 <jogo@openwrt.org>
                in6_dev_put_clear(&net->ipv6.ip6_blk_hole_entry->rt6i_idev);
  #endif
        }
-@@ -6494,6 +6528,8 @@ static int __net_init ip6_route_net_init
+@@ -6495,6 +6529,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 <jogo@openwrt.org>
        net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
                                               sizeof(*net->ipv6.ip6_prohibit_entry),
                                               GFP_KERNEL);
-@@ -6504,11 +6540,21 @@ static int __net_init ip6_route_net_init
+@@ -6505,11 +6541,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 <jogo@openwrt.org>
        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);
-@@ -6535,6 +6581,8 @@ out:
+@@ -6536,6 +6582,8 @@ out:
        return ret;
  
  #ifdef CONFIG_IPV6_MULTIPLE_TABLES
@@ -243,7 +243,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
  out_ip6_prohibit_entry:
        kfree(net->ipv6.ip6_prohibit_entry);
  out_ip6_null_entry:
-@@ -6554,6 +6602,7 @@ static void __net_exit ip6_route_net_exi
+@@ -6555,6 +6603,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 <jogo@openwrt.org>
        kfree(net->ipv6.ip6_blk_hole_entry);
  #endif
        dst_entries_destroy(&net->ipv6.ip6_dst_ops);
-@@ -6631,6 +6680,9 @@ void __init ip6_route_init_special_entri
+@@ -6632,6 +6681,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-5.15/704-00-netfilter-flowtable-fix-excessive-hw-offload-attempt.patch b/target/linux/generic/pending-5.15/704-00-netfilter-flowtable-fix-excessive-hw-offload-attempt.patch
new file mode 100644 (file)
index 0000000..c03cb5a
--- /dev/null
@@ -0,0 +1,27 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Fri, 6 May 2022 12:37:23 +0200
+Subject: [PATCH] netfilter: flowtable: fix excessive hw offload attempts
+ after failure
+
+If a flow cannot be offloaded, the code currently repeatedly tries again as
+quickly as possible, which can significantly increase system load.
+Fix this by limiting flow timeout update and hardware offload retry to once
+per second.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/netfilter/nf_flow_table_core.c
++++ b/net/netfilter/nf_flow_table_core.c
+@@ -329,8 +329,10 @@ void flow_offload_refresh(struct nf_flow
+       u32 timeout;
+       timeout = nf_flowtable_time_stamp + flow_offload_get_timeout(flow);
+-      if (READ_ONCE(flow->timeout) != timeout)
++      if (timeout - READ_ONCE(flow->timeout) > HZ)
+               WRITE_ONCE(flow->timeout, timeout);
++      else
++              return;
+       if (likely(!nf_flowtable_hw_offload(flow_table)))
+               return;
diff --git a/target/linux/generic/pending-5.15/704-01-netfilter-nft_flow_offload-skip-dst-neigh-lookup-for.patch b/target/linux/generic/pending-5.15/704-01-netfilter-nft_flow_offload-skip-dst-neigh-lookup-for.patch
new file mode 100644 (file)
index 0000000..6683a53
--- /dev/null
@@ -0,0 +1,64 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Fri, 6 May 2022 12:43:58 +0200
+Subject: [PATCH] netfilter: nft_flow_offload: skip dst neigh lookup for
+ ppp devices
+
+The dst entry does not contain a valid hardware address, so skip the lookup
+in order to avoid running into errors here.
+The proper hardware address is filled in from nft_dev_path_info
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/netfilter/nft_flow_offload.c
++++ b/net/netfilter/nft_flow_offload.c
+@@ -36,6 +36,15 @@ static void nft_default_forward_path(str
+       route->tuple[dir].xmit_type     = nft_xmit_type(dst_cache);
+ }
++static bool nft_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 int nft_dev_fill_forward_path(const struct nf_flow_route *route,
+                                    const struct dst_entry *dst_cache,
+                                    const struct nf_conn *ct,
+@@ -47,6 +56,9 @@ static int nft_dev_fill_forward_path(con
+       struct neighbour *n;
+       u8 nud_state;
++      if (!nft_is_valid_ether_device(dev))
++              goto out;
++
+       n = dst_neigh_lookup(dst_cache, daddr);
+       if (!n)
+               return -1;
+@@ -60,6 +72,7 @@ static int nft_dev_fill_forward_path(con
+       if (!(nud_state & NUD_VALID))
+               return -1;
++out:
+       return dev_fill_forward_path(dev, ha, stack);
+ }
+@@ -78,15 +91,6 @@ struct nft_forward_info {
+       enum flow_offload_xmit_type xmit_type;
+ };
+-static bool nft_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 nft_dev_path_info(const struct net_device_path_stack *stack,
+                             struct nft_forward_info *info,
+                             unsigned char *ha, struct nf_flowtable *flowtable)
diff --git a/target/linux/generic/pending-5.15/704-02-net-fix-dev_fill_forward_path-with-pppoe-bridge.patch b/target/linux/generic/pending-5.15/704-02-net-fix-dev_fill_forward_path-with-pppoe-bridge.patch
new file mode 100644 (file)
index 0000000..984733a
--- /dev/null
@@ -0,0 +1,66 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Fri, 6 May 2022 13:54:44 +0200
+Subject: [PATCH] net: fix dev_fill_forward_path with pppoe + bridge
+
+When calling dev_fill_forward_path on a pppoe device, the provided destination
+address is invalid. In order for the bridge fdb lookup to succeed, the pppoe
+code needs to update ctx->daddr to the correct value.
+Fix this by storing the address inside struct net_device_path_ctx
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
++++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+@@ -90,7 +90,6 @@ mtk_flow_get_wdma_info(struct net_device
+ {
+       struct net_device_path_ctx ctx = {
+               .dev = dev,
+-              .daddr = addr,
+       };
+       struct net_device_path path = {};
+@@ -100,6 +99,7 @@ mtk_flow_get_wdma_info(struct net_device
+       if (!dev->netdev_ops->ndo_fill_forward_path)
+               return -1;
++      memcpy(ctx.daddr, addr, sizeof(ctx.daddr));
+       if (dev->netdev_ops->ndo_fill_forward_path(&ctx, &path))
+               return -1;
+--- a/drivers/net/ppp/pppoe.c
++++ b/drivers/net/ppp/pppoe.c
+@@ -988,6 +988,7 @@ static int pppoe_fill_forward_path(struc
+       path->encap.proto = htons(ETH_P_PPP_SES);
+       path->encap.id = be16_to_cpu(po->num);
+       memcpy(path->encap.h_dest, po->pppoe_pa.remote, ETH_ALEN);
++      memcpy(ctx->daddr, po->pppoe_pa.remote, ETH_ALEN);
+       path->dev = ctx->dev;
+       ctx->dev = dev;
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -894,7 +894,7 @@ struct net_device_path_stack {
+ struct net_device_path_ctx {
+       const struct net_device *dev;
+-      const u8                *daddr;
++      u8                      daddr[ETH_ALEN];
+       int                     num_vlans;
+       struct {
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -741,11 +741,11 @@ int dev_fill_forward_path(const struct n
+       const struct net_device *last_dev;
+       struct net_device_path_ctx ctx = {
+               .dev    = dev,
+-              .daddr  = daddr,
+       };
+       struct net_device_path *path;
+       int ret = 0;
++      memcpy(ctx.daddr, daddr, sizeof(ctx.daddr));
+       stack->num_paths = 0;
+       while (ctx.dev && ctx.dev->netdev_ops->ndo_fill_forward_path) {
+               last_dev = ctx.dev;
diff --git a/target/linux/generic/pending-5.15/704-03-netfilter-nft_flow_offload-fix-offload-with-pppoe-vl.patch b/target/linux/generic/pending-5.15/704-03-netfilter-nft_flow_offload-fix-offload-with-pppoe-vl.patch
new file mode 100644 (file)
index 0000000..1e0dc99
--- /dev/null
@@ -0,0 +1,24 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Fri, 6 May 2022 15:15:06 +0200
+Subject: [PATCH] netfilter: nft_flow_offload: fix offload with pppoe +
+ vlan
+
+When running a combination of PPPoE on top of a VLAN, we need to set
+info->outdev to the PPPoE device, otherwise PPPoE encap is skipped
+during software offload.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/netfilter/nft_flow_offload.c
++++ b/net/netfilter/nft_flow_offload.c
+@@ -123,7 +123,8 @@ static void nft_dev_path_info(const stru
+                               info->indev = NULL;
+                               break;
+                       }
+-                      info->outdev = path->dev;
++                      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++;
diff --git a/target/linux/generic/pending-5.15/705-net-dsa-tag_mtk-add-padding-for-tx-packets.patch b/target/linux/generic/pending-5.15/705-net-dsa-tag_mtk-add-padding-for-tx-packets.patch
new file mode 100644 (file)
index 0000000..e27ac35
--- /dev/null
@@ -0,0 +1,29 @@
+From: Felix Fietkau <nbd@nbd.name>
+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 <nbd@nbd.name>
+---
+
+--- a/net/dsa/tag_mtk.c
++++ b/net/dsa/tag_mtk.c
+@@ -25,6 +25,14 @@ static struct sk_buff *mtk_tag_xmit(stru
+       u8 xmit_tpid;
+       u8 *mtk_tag;
++      /* 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).
++       */
++      if (__skb_put_padto(skb, ETH_ZLEN + MTK_HDR_LEN, false))
++              return NULL;
++
+       /* 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/ipq40xx/files-5.15/drivers/net/mdio/ar40xx.c b/target/linux/ipq40xx/files-5.15/drivers/net/mdio/ar40xx.c
deleted file mode 100644 (file)
index f7ce42b..0000000
+++ /dev/null
@@ -1,1890 +0,0 @@
-/*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
- *
- * Permission to use, copy, modify, and/or distribute this software for
- * any purpose with or without fee is hereby granted, provided that the
- * above copyright notice and this permission notice appear in all copies.
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <linux/bitfield.h>
-#include <linux/module.h>
-#include <linux/list.h>
-#include <linux/bitops.h>
-#include <linux/switch.h>
-#include <linux/delay.h>
-#include <linux/phy.h>
-#include <linux/clk.h>
-#include <linux/reset.h>
-#include <linux/lockdep.h>
-#include <linux/workqueue.h>
-#include <linux/of_device.h>
-#include <linux/of_address.h>
-#include <linux/of_mdio.h>
-#include <linux/mdio.h>
-#include <linux/gpio.h>
-
-#include "ar40xx.h"
-
-static struct ar40xx_priv *ar40xx_priv;
-
-#define MIB_DESC(_s , _o, _n)  \
-       {                       \
-               .size = (_s),   \
-               .offset = (_o), \
-               .name = (_n),   \
-       }
-
-static const struct ar40xx_mib_desc ar40xx_mibs[] = {
-       MIB_DESC(1, AR40XX_STATS_RXBROAD, "RxBroad"),
-       MIB_DESC(1, AR40XX_STATS_RXPAUSE, "RxPause"),
-       MIB_DESC(1, AR40XX_STATS_RXMULTI, "RxMulti"),
-       MIB_DESC(1, AR40XX_STATS_RXFCSERR, "RxFcsErr"),
-       MIB_DESC(1, AR40XX_STATS_RXALIGNERR, "RxAlignErr"),
-       MIB_DESC(1, AR40XX_STATS_RXRUNT, "RxRunt"),
-       MIB_DESC(1, AR40XX_STATS_RXFRAGMENT, "RxFragment"),
-       MIB_DESC(1, AR40XX_STATS_RX64BYTE, "Rx64Byte"),
-       MIB_DESC(1, AR40XX_STATS_RX128BYTE, "Rx128Byte"),
-       MIB_DESC(1, AR40XX_STATS_RX256BYTE, "Rx256Byte"),
-       MIB_DESC(1, AR40XX_STATS_RX512BYTE, "Rx512Byte"),
-       MIB_DESC(1, AR40XX_STATS_RX1024BYTE, "Rx1024Byte"),
-       MIB_DESC(1, AR40XX_STATS_RX1518BYTE, "Rx1518Byte"),
-       MIB_DESC(1, AR40XX_STATS_RXMAXBYTE, "RxMaxByte"),
-       MIB_DESC(1, AR40XX_STATS_RXTOOLONG, "RxTooLong"),
-       MIB_DESC(2, AR40XX_STATS_RXGOODBYTE, "RxGoodByte"),
-       MIB_DESC(2, AR40XX_STATS_RXBADBYTE, "RxBadByte"),
-       MIB_DESC(1, AR40XX_STATS_RXOVERFLOW, "RxOverFlow"),
-       MIB_DESC(1, AR40XX_STATS_FILTERED, "Filtered"),
-       MIB_DESC(1, AR40XX_STATS_TXBROAD, "TxBroad"),
-       MIB_DESC(1, AR40XX_STATS_TXPAUSE, "TxPause"),
-       MIB_DESC(1, AR40XX_STATS_TXMULTI, "TxMulti"),
-       MIB_DESC(1, AR40XX_STATS_TXUNDERRUN, "TxUnderRun"),
-       MIB_DESC(1, AR40XX_STATS_TX64BYTE, "Tx64Byte"),
-       MIB_DESC(1, AR40XX_STATS_TX128BYTE, "Tx128Byte"),
-       MIB_DESC(1, AR40XX_STATS_TX256BYTE, "Tx256Byte"),
-       MIB_DESC(1, AR40XX_STATS_TX512BYTE, "Tx512Byte"),
-       MIB_DESC(1, AR40XX_STATS_TX1024BYTE, "Tx1024Byte"),
-       MIB_DESC(1, AR40XX_STATS_TX1518BYTE, "Tx1518Byte"),
-       MIB_DESC(1, AR40XX_STATS_TXMAXBYTE, "TxMaxByte"),
-       MIB_DESC(1, AR40XX_STATS_TXOVERSIZE, "TxOverSize"),
-       MIB_DESC(2, AR40XX_STATS_TXBYTE, "TxByte"),
-       MIB_DESC(1, AR40XX_STATS_TXCOLLISION, "TxCollision"),
-       MIB_DESC(1, AR40XX_STATS_TXABORTCOL, "TxAbortCol"),
-       MIB_DESC(1, AR40XX_STATS_TXMULTICOL, "TxMultiCol"),
-       MIB_DESC(1, AR40XX_STATS_TXSINGLECOL, "TxSingleCol"),
-       MIB_DESC(1, AR40XX_STATS_TXEXCDEFER, "TxExcDefer"),
-       MIB_DESC(1, AR40XX_STATS_TXDEFER, "TxDefer"),
-       MIB_DESC(1, AR40XX_STATS_TXLATECOL, "TxLateCol"),
-};
-
-static u32
-ar40xx_read(struct ar40xx_priv *priv, int reg)
-{
-       return readl(priv->hw_addr + reg);
-}
-
-static u32
-ar40xx_psgmii_read(struct ar40xx_priv *priv, int reg)
-{
-       return readl(priv->psgmii_hw_addr + reg);
-}
-
-static void
-ar40xx_write(struct ar40xx_priv *priv, int reg, u32 val)
-{
-       writel(val, priv->hw_addr + reg);
-}
-
-static u32
-ar40xx_rmw(struct ar40xx_priv *priv, int reg, u32 mask, u32 val)
-{
-       u32 ret;
-
-       ret = ar40xx_read(priv, reg);
-       ret &= ~mask;
-       ret |= val;
-       ar40xx_write(priv, reg, ret);
-       return ret;
-}
-
-static void
-ar40xx_psgmii_write(struct ar40xx_priv *priv, int reg, u32 val)
-{
-       writel(val, priv->psgmii_hw_addr + reg);
-}
-
-static void
-ar40xx_phy_dbg_write(struct ar40xx_priv *priv, int phy_addr,
-                    u16 dbg_addr, u16 dbg_data)
-{
-       struct mii_bus *bus = priv->mii_bus;
-
-       mutex_lock(&bus->mdio_lock);
-       bus->write(bus, phy_addr, AR40XX_MII_ATH_DBG_ADDR, dbg_addr);
-       bus->write(bus, phy_addr, AR40XX_MII_ATH_DBG_DATA, dbg_data);
-       mutex_unlock(&bus->mdio_lock);
-}
-
-static void
-ar40xx_phy_dbg_read(struct ar40xx_priv *priv, int phy_addr,
-                   u16 dbg_addr, u16 *dbg_data)
-{
-       struct mii_bus *bus = priv->mii_bus;
-
-       mutex_lock(&bus->mdio_lock);
-       bus->write(bus, phy_addr, AR40XX_MII_ATH_DBG_ADDR, dbg_addr);
-       *dbg_data = bus->read(bus, phy_addr, AR40XX_MII_ATH_DBG_DATA);
-       mutex_unlock(&bus->mdio_lock);
-}
-
-static void
-ar40xx_phy_mmd_write(struct ar40xx_priv *priv, u32 phy_id,
-                    u16 mmd_num, u16 reg_id, u16 reg_val)
-{
-       struct mii_bus *bus = priv->mii_bus;
-
-       mutex_lock(&bus->mdio_lock);
-       bus->write(bus, phy_id,
-                       AR40XX_MII_ATH_MMD_ADDR, mmd_num);
-       bus->write(bus, phy_id,
-                       AR40XX_MII_ATH_MMD_DATA, reg_id);
-       bus->write(bus, phy_id,
-                       AR40XX_MII_ATH_MMD_ADDR,
-                       0x4000 | mmd_num);
-       bus->write(bus, phy_id,
-               AR40XX_MII_ATH_MMD_DATA, reg_val);
-       mutex_unlock(&bus->mdio_lock);
-}
-
-static u16
-ar40xx_phy_mmd_read(struct ar40xx_priv *priv, u32 phy_id,
-                   u16 mmd_num, u16 reg_id)
-{
-       u16 value;
-       struct mii_bus *bus = priv->mii_bus;
-
-       mutex_lock(&bus->mdio_lock);
-       bus->write(bus, phy_id,
-                       AR40XX_MII_ATH_MMD_ADDR, mmd_num);
-       bus->write(bus, phy_id,
-                       AR40XX_MII_ATH_MMD_DATA, reg_id);
-       bus->write(bus, phy_id,
-                       AR40XX_MII_ATH_MMD_ADDR,
-                       0x4000 | mmd_num);
-       value = bus->read(bus, phy_id, AR40XX_MII_ATH_MMD_DATA);
-       mutex_unlock(&bus->mdio_lock);
-       return value;
-}
-
-/* Start of swconfig support */
-
-static void
-ar40xx_phy_poll_reset(struct ar40xx_priv *priv)
-{
-       u32 i, in_reset, retries = 500;
-       struct mii_bus *bus = priv->mii_bus;
-
-       /* Assume RESET was recently issued to some or all of the phys */
-       in_reset = GENMASK(AR40XX_NUM_PHYS - 1, 0);
-
-       while (retries--) {
-               /* 1ms should be plenty of time.
-                * 802.3 spec allows for a max wait time of 500ms
-                */
-               usleep_range(1000, 2000);
-
-               for (i = 0; i < AR40XX_NUM_PHYS; i++) {
-                       int val;
-
-                       /* skip devices which have completed reset */
-                       if (!(in_reset & BIT(i)))
-                               continue;
-
-                       val = mdiobus_read(bus, i, MII_BMCR);
-                       if (val < 0)
-                               continue;
-
-                       /* mark when phy is no longer in reset state */
-                       if (!(val & BMCR_RESET))
-                               in_reset &= ~BIT(i);
-               }
-
-               if (!in_reset)
-                       return;
-       }
-
-       dev_warn(&bus->dev, "Failed to reset all phys! (in_reset: 0x%x)\n",
-                in_reset);
-}
-
-static void
-ar40xx_phy_init(struct ar40xx_priv *priv)
-{
-       int i;
-       struct mii_bus *bus;
-       u16 val;
-
-       bus = priv->mii_bus;
-       for (i = 0; i < AR40XX_NUM_PORTS - 1; i++) {
-               ar40xx_phy_dbg_read(priv, i, AR40XX_PHY_DEBUG_0, &val);
-               val &= ~AR40XX_PHY_MANU_CTRL_EN;
-               ar40xx_phy_dbg_write(priv, i, AR40XX_PHY_DEBUG_0, val);
-               mdiobus_write(bus, i,
-                             MII_ADVERTISE, ADVERTISE_ALL |
-                             ADVERTISE_PAUSE_CAP |
-                             ADVERTISE_PAUSE_ASYM);
-               mdiobus_write(bus, i, MII_CTRL1000, ADVERTISE_1000FULL);
-               mdiobus_write(bus, i, MII_BMCR, BMCR_RESET | BMCR_ANENABLE);
-       }
-
-       ar40xx_phy_poll_reset(priv);
-}
-
-static void
-ar40xx_port_phy_linkdown(struct ar40xx_priv *priv)
-{
-       struct mii_bus *bus;
-       int i;
-       u16 val;
-
-       bus = priv->mii_bus;
-       for (i = 0; i < AR40XX_NUM_PORTS - 1; i++) {
-               mdiobus_write(bus, i, MII_CTRL1000, 0);
-               mdiobus_write(bus, i, MII_ADVERTISE, 0);
-               mdiobus_write(bus, i, MII_BMCR, BMCR_RESET | BMCR_ANENABLE);
-               ar40xx_phy_dbg_read(priv, i, AR40XX_PHY_DEBUG_0, &val);
-               val |= AR40XX_PHY_MANU_CTRL_EN;
-               ar40xx_phy_dbg_write(priv, i, AR40XX_PHY_DEBUG_0, val);
-               /* disable transmit */
-               ar40xx_phy_dbg_read(priv, i, AR40XX_PHY_DEBUG_2, &val);
-               val &= 0xf00f;
-               ar40xx_phy_dbg_write(priv, i, AR40XX_PHY_DEBUG_2, val);
-       }
-}
-
-static void
-ar40xx_set_mirror_regs(struct ar40xx_priv *priv)
-{
-       int port;
-
-       /* reset all mirror registers */
-       ar40xx_rmw(priv, AR40XX_REG_FWD_CTRL0,
-                  AR40XX_FWD_CTRL0_MIRROR_PORT,
-                  (0xF << AR40XX_FWD_CTRL0_MIRROR_PORT_S));
-       for (port = 0; port < AR40XX_NUM_PORTS; port++) {
-               ar40xx_rmw(priv, AR40XX_REG_PORT_LOOKUP(port),
-                          AR40XX_PORT_LOOKUP_ING_MIRROR_EN, 0);
-
-               ar40xx_rmw(priv, AR40XX_REG_PORT_HOL_CTRL1(port),
-                          AR40XX_PORT_HOL_CTRL1_EG_MIRROR_EN, 0);
-       }
-
-       /* now enable mirroring if necessary */
-       if (priv->source_port >= AR40XX_NUM_PORTS ||
-           priv->monitor_port >= AR40XX_NUM_PORTS ||
-           priv->source_port == priv->monitor_port) {
-               return;
-       }
-
-       ar40xx_rmw(priv, AR40XX_REG_FWD_CTRL0,
-                  AR40XX_FWD_CTRL0_MIRROR_PORT,
-                  (priv->monitor_port << AR40XX_FWD_CTRL0_MIRROR_PORT_S));
-
-       if (priv->mirror_rx)
-               ar40xx_rmw(priv, AR40XX_REG_PORT_LOOKUP(priv->source_port), 0,
-                          AR40XX_PORT_LOOKUP_ING_MIRROR_EN);
-
-       if (priv->mirror_tx)
-               ar40xx_rmw(priv, AR40XX_REG_PORT_HOL_CTRL1(priv->source_port),
-                          0, AR40XX_PORT_HOL_CTRL1_EG_MIRROR_EN);
-}
-
-static int
-ar40xx_sw_get_ports(struct switch_dev *dev, struct switch_val *val)
-{
-       struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
-       u8 ports = priv->vlan_table[val->port_vlan];
-       int i;
-
-       val->len = 0;
-       for (i = 0; i < dev->ports; i++) {
-               struct switch_port *p;
-
-               if (!(ports & BIT(i)))
-                       continue;
-
-               p = &val->value.ports[val->len++];
-               p->id = i;
-               if ((priv->vlan_tagged & BIT(i)) ||
-                   (priv->pvid[i] != val->port_vlan))
-                       p->flags = BIT(SWITCH_PORT_FLAG_TAGGED);
-               else
-                       p->flags = 0;
-       }
-       return 0;
-}
-
-static int
-ar40xx_sw_set_ports(struct switch_dev *dev, struct switch_val *val)
-{
-       struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
-       u8 *vt = &priv->vlan_table[val->port_vlan];
-       int i;
-
-       *vt = 0;
-       for (i = 0; i < val->len; i++) {
-               struct switch_port *p = &val->value.ports[i];
-
-               if (p->flags & BIT(SWITCH_PORT_FLAG_TAGGED)) {
-                       if (val->port_vlan == priv->pvid[p->id])
-                               priv->vlan_tagged |= BIT(p->id);
-               } else {
-                       priv->vlan_tagged &= ~BIT(p->id);
-                       priv->pvid[p->id] = val->port_vlan;
-               }
-
-               *vt |= BIT(p->id);
-       }
-       return 0;
-}
-
-static int
-ar40xx_reg_wait(struct ar40xx_priv *priv, u32 reg, u32 mask, u32 val,
-               unsigned timeout)
-{
-       int i;
-
-       for (i = 0; i < timeout; i++) {
-               u32 t;
-
-               t = ar40xx_read(priv, reg);
-               if ((t & mask) == val)
-                       return 0;
-
-               usleep_range(1000, 2000);
-       }
-
-       return -ETIMEDOUT;
-}
-
-static int
-ar40xx_mib_op(struct ar40xx_priv *priv, u32 op)
-{
-       int ret;
-
-       lockdep_assert_held(&priv->mib_lock);
-
-       /* Capture the hardware statistics for all ports */
-       ar40xx_rmw(priv, AR40XX_REG_MIB_FUNC,
-                  AR40XX_MIB_FUNC, (op << AR40XX_MIB_FUNC_S));
-
-       /* Wait for the capturing to complete. */
-       ret = ar40xx_reg_wait(priv, AR40XX_REG_MIB_FUNC,
-                             AR40XX_MIB_BUSY, 0, 10);
-
-       return ret;
-}
-
-static void
-ar40xx_mib_fetch_port_stat(struct ar40xx_priv *priv, int port, bool flush)
-{
-       unsigned int base;
-       u64 *mib_stats;
-       int i;
-       u32 num_mibs = ARRAY_SIZE(ar40xx_mibs);
-
-       WARN_ON(port >= priv->dev.ports);
-
-       lockdep_assert_held(&priv->mib_lock);
-
-       base = AR40XX_REG_PORT_STATS_START +
-              AR40XX_REG_PORT_STATS_LEN * port;
-
-       mib_stats = &priv->mib_stats[port * num_mibs];
-       if (flush) {
-               u32 len;
-
-               len = num_mibs * sizeof(*mib_stats);
-               memset(mib_stats, 0, len);
-               return;
-       }
-       for (i = 0; i < num_mibs; i++) {
-               const struct ar40xx_mib_desc *mib;
-               u64 t;
-
-               mib = &ar40xx_mibs[i];
-               t = ar40xx_read(priv, base + mib->offset);
-               if (mib->size == 2) {
-                       u64 hi;
-
-                       hi = ar40xx_read(priv, base + mib->offset + 4);
-                       t |= hi << 32;
-               }
-
-               mib_stats[i] += t;
-       }
-}
-
-static int
-ar40xx_mib_capture(struct ar40xx_priv *priv)
-{
-       return ar40xx_mib_op(priv, AR40XX_MIB_FUNC_CAPTURE);
-}
-
-static int
-ar40xx_mib_flush(struct ar40xx_priv *priv)
-{
-       return ar40xx_mib_op(priv, AR40XX_MIB_FUNC_FLUSH);
-}
-
-static int
-ar40xx_sw_set_reset_mibs(struct switch_dev *dev,
-                        const struct switch_attr *attr,
-                        struct switch_val *val)
-{
-       struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
-       unsigned int len;
-       int ret;
-       u32 num_mibs = ARRAY_SIZE(ar40xx_mibs);
-
-       mutex_lock(&priv->mib_lock);
-
-       len = priv->dev.ports * num_mibs * sizeof(*priv->mib_stats);
-       memset(priv->mib_stats, 0, len);
-       ret = ar40xx_mib_flush(priv);
-
-       mutex_unlock(&priv->mib_lock);
-       return ret;
-}
-
-static int
-ar40xx_sw_set_vlan(struct switch_dev *dev, const struct switch_attr *attr,
-                  struct switch_val *val)
-{
-       struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
-
-       priv->vlan = !!val->value.i;
-       return 0;
-}
-
-static int
-ar40xx_sw_get_vlan(struct switch_dev *dev, const struct switch_attr *attr,
-                  struct switch_val *val)
-{
-       struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
-
-       val->value.i = priv->vlan;
-       return 0;
-}
-
-static int
-ar40xx_sw_set_mirror_rx_enable(struct switch_dev *dev,
-                              const struct switch_attr *attr,
-                              struct switch_val *val)
-{
-       struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
-
-       mutex_lock(&priv->reg_mutex);
-       priv->mirror_rx = !!val->value.i;
-       ar40xx_set_mirror_regs(priv);
-       mutex_unlock(&priv->reg_mutex);
-
-       return 0;
-}
-
-static int
-ar40xx_sw_get_mirror_rx_enable(struct switch_dev *dev,
-                              const struct switch_attr *attr,
-                              struct switch_val *val)
-{
-       struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
-
-       mutex_lock(&priv->reg_mutex);
-       val->value.i = priv->mirror_rx;
-       mutex_unlock(&priv->reg_mutex);
-       return 0;
-}
-
-static int
-ar40xx_sw_set_mirror_tx_enable(struct switch_dev *dev,
-                              const struct switch_attr *attr,
-                              struct switch_val *val)
-{
-       struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
-
-       mutex_lock(&priv->reg_mutex);
-       priv->mirror_tx = !!val->value.i;
-       ar40xx_set_mirror_regs(priv);
-       mutex_unlock(&priv->reg_mutex);
-
-       return 0;
-}
-
-static int
-ar40xx_sw_get_mirror_tx_enable(struct switch_dev *dev,
-                              const struct switch_attr *attr,
-                              struct switch_val *val)
-{
-       struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
-
-       mutex_lock(&priv->reg_mutex);
-       val->value.i = priv->mirror_tx;
-       mutex_unlock(&priv->reg_mutex);
-       return 0;
-}
-
-static int
-ar40xx_sw_set_mirror_monitor_port(struct switch_dev *dev,
-                                 const struct switch_attr *attr,
-                                 struct switch_val *val)
-{
-       struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
-
-       mutex_lock(&priv->reg_mutex);
-       priv->monitor_port = val->value.i;
-       ar40xx_set_mirror_regs(priv);
-       mutex_unlock(&priv->reg_mutex);
-
-       return 0;
-}
-
-static int
-ar40xx_sw_get_mirror_monitor_port(struct switch_dev *dev,
-                                 const struct switch_attr *attr,
-                                 struct switch_val *val)
-{
-       struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
-
-       mutex_lock(&priv->reg_mutex);
-       val->value.i = priv->monitor_port;
-       mutex_unlock(&priv->reg_mutex);
-       return 0;
-}
-
-static int
-ar40xx_sw_set_mirror_source_port(struct switch_dev *dev,
-                                const struct switch_attr *attr,
-                                struct switch_val *val)
-{
-       struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
-
-       mutex_lock(&priv->reg_mutex);
-       priv->source_port = val->value.i;
-       ar40xx_set_mirror_regs(priv);
-       mutex_unlock(&priv->reg_mutex);
-
-       return 0;
-}
-
-static int
-ar40xx_sw_get_mirror_source_port(struct switch_dev *dev,
-                                const struct switch_attr *attr,
-                                struct switch_val *val)
-{
-       struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
-
-       mutex_lock(&priv->reg_mutex);
-       val->value.i = priv->source_port;
-       mutex_unlock(&priv->reg_mutex);
-       return 0;
-}
-
-static int
-ar40xx_sw_set_linkdown(struct switch_dev *dev,
-                      const struct switch_attr *attr,
-                      struct switch_val *val)
-{
-       struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
-
-       if (val->value.i == 1)
-               ar40xx_port_phy_linkdown(priv);
-       else
-               ar40xx_phy_init(priv);
-
-       return 0;
-}
-
-static int
-ar40xx_sw_set_port_reset_mib(struct switch_dev *dev,
-                            const struct switch_attr *attr,
-                            struct switch_val *val)
-{
-       struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
-       int port;
-       int ret;
-
-       port = val->port_vlan;
-       if (port >= dev->ports)
-               return -EINVAL;
-
-       mutex_lock(&priv->mib_lock);
-       ret = ar40xx_mib_capture(priv);
-       if (ret)
-               goto unlock;
-
-       ar40xx_mib_fetch_port_stat(priv, port, true);
-
-unlock:
-       mutex_unlock(&priv->mib_lock);
-       return ret;
-}
-
-static int
-ar40xx_sw_get_port_mib(struct switch_dev *dev,
-                      const struct switch_attr *attr,
-                      struct switch_val *val)
-{
-       struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
-       u64 *mib_stats;
-       int port;
-       int ret;
-       char *buf = priv->buf;
-       int i, len = 0;
-       u32 num_mibs = ARRAY_SIZE(ar40xx_mibs);
-
-       port = val->port_vlan;
-       if (port >= dev->ports)
-               return -EINVAL;
-
-       mutex_lock(&priv->mib_lock);
-       ret = ar40xx_mib_capture(priv);
-       if (ret)
-               goto unlock;
-
-       ar40xx_mib_fetch_port_stat(priv, port, false);
-
-       len += snprintf(buf + len, sizeof(priv->buf) - len,
-                       "Port %d MIB counters\n",
-                       port);
-
-       mib_stats = &priv->mib_stats[port * num_mibs];
-       for (i = 0; i < num_mibs; i++)
-               len += snprintf(buf + len, sizeof(priv->buf) - len,
-                               "%-12s: %llu\n",
-                               ar40xx_mibs[i].name,
-                               mib_stats[i]);
-
-       val->value.s = buf;
-       val->len = len;
-
-unlock:
-       mutex_unlock(&priv->mib_lock);
-       return ret;
-}
-
-static int
-ar40xx_sw_set_vid(struct switch_dev *dev, const struct switch_attr *attr,
-                 struct switch_val *val)
-{
-       struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
-
-       priv->vlan_id[val->port_vlan] = val->value.i;
-       return 0;
-}
-
-static int
-ar40xx_sw_get_vid(struct switch_dev *dev, const struct switch_attr *attr,
-                 struct switch_val *val)
-{
-       struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
-
-       val->value.i = priv->vlan_id[val->port_vlan];
-       return 0;
-}
-
-static int
-ar40xx_sw_get_pvid(struct switch_dev *dev, int port, int *vlan)
-{
-       struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
-       *vlan = priv->pvid[port];
-       return 0;
-}
-
-static int
-ar40xx_sw_set_pvid(struct switch_dev *dev, int port, int vlan)
-{
-       struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
-
-       /* make sure no invalid PVIDs get set */
-       if (vlan >= dev->vlans)
-               return -EINVAL;
-
-       priv->pvid[port] = vlan;
-       return 0;
-}
-
-static void
-ar40xx_read_port_link(struct ar40xx_priv *priv, int port,
-                     struct switch_port_link *link)
-{
-       u32 status;
-       u32 speed;
-
-       memset(link, 0, sizeof(*link));
-
-       status = ar40xx_read(priv, AR40XX_REG_PORT_STATUS(port));
-
-       link->aneg = !!(status & AR40XX_PORT_AUTO_LINK_EN);
-       if (link->aneg || (port != AR40XX_PORT_CPU))
-               link->link = !!(status & AR40XX_PORT_STATUS_LINK_UP);
-       else
-               link->link = true;
-
-       if (!link->link)
-               return;
-
-       link->duplex = !!(status & AR40XX_PORT_DUPLEX);
-       link->tx_flow = !!(status & AR40XX_PORT_STATUS_TXFLOW);
-       link->rx_flow = !!(status & AR40XX_PORT_STATUS_RXFLOW);
-
-       speed = (status & AR40XX_PORT_SPEED) >>
-                AR40XX_PORT_STATUS_SPEED_S;
-
-       switch (speed) {
-       case AR40XX_PORT_SPEED_10M:
-               link->speed = SWITCH_PORT_SPEED_10;
-               break;
-       case AR40XX_PORT_SPEED_100M:
-               link->speed = SWITCH_PORT_SPEED_100;
-               break;
-       case AR40XX_PORT_SPEED_1000M:
-               link->speed = SWITCH_PORT_SPEED_1000;
-               break;
-       default:
-               link->speed = SWITCH_PORT_SPEED_UNKNOWN;
-               break;
-       }
-}
-
-static int
-ar40xx_sw_get_port_link(struct switch_dev *dev, int port,
-                       struct switch_port_link *link)
-{
-       struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
-
-       ar40xx_read_port_link(priv, port, link);
-       return 0;
-}
-
-static const struct switch_attr ar40xx_sw_attr_globals[] = {
-       {
-               .type = SWITCH_TYPE_INT,
-               .name = "enable_vlan",
-               .description = "Enable VLAN mode",
-               .set = ar40xx_sw_set_vlan,
-               .get = ar40xx_sw_get_vlan,
-               .max = 1
-       },
-       {
-               .type = SWITCH_TYPE_NOVAL,
-               .name = "reset_mibs",
-               .description = "Reset all MIB counters",
-               .set = ar40xx_sw_set_reset_mibs,
-       },
-       {
-               .type = SWITCH_TYPE_INT,
-               .name = "enable_mirror_rx",
-               .description = "Enable mirroring of RX packets",
-               .set = ar40xx_sw_set_mirror_rx_enable,
-               .get = ar40xx_sw_get_mirror_rx_enable,
-               .max = 1
-       },
-       {
-               .type = SWITCH_TYPE_INT,
-               .name = "enable_mirror_tx",
-               .description = "Enable mirroring of TX packets",
-               .set = ar40xx_sw_set_mirror_tx_enable,
-               .get = ar40xx_sw_get_mirror_tx_enable,
-               .max = 1
-       },
-       {
-               .type = SWITCH_TYPE_INT,
-               .name = "mirror_monitor_port",
-               .description = "Mirror monitor port",
-               .set = ar40xx_sw_set_mirror_monitor_port,
-               .get = ar40xx_sw_get_mirror_monitor_port,
-               .max = AR40XX_NUM_PORTS - 1
-       },
-       {
-               .type = SWITCH_TYPE_INT,
-               .name = "mirror_source_port",
-               .description = "Mirror source port",
-               .set = ar40xx_sw_set_mirror_source_port,
-               .get = ar40xx_sw_get_mirror_source_port,
-               .max = AR40XX_NUM_PORTS - 1
-       },
-       {
-               .type = SWITCH_TYPE_INT,
-               .name = "linkdown",
-               .description = "Link down all the PHYs",
-               .set = ar40xx_sw_set_linkdown,
-               .max = 1
-       },
-};
-
-static const struct switch_attr ar40xx_sw_attr_port[] = {
-       {
-               .type = SWITCH_TYPE_NOVAL,
-               .name = "reset_mib",
-               .description = "Reset single port MIB counters",
-               .set = ar40xx_sw_set_port_reset_mib,
-       },
-       {
-               .type = SWITCH_TYPE_STRING,
-               .name = "mib",
-               .description = "Get port's MIB counters",
-               .set = NULL,
-               .get = ar40xx_sw_get_port_mib,
-       },
-};
-
-const struct switch_attr ar40xx_sw_attr_vlan[] = {
-       {
-               .type = SWITCH_TYPE_INT,
-               .name = "vid",
-               .description = "VLAN ID (0-4094)",
-               .set = ar40xx_sw_set_vid,
-               .get = ar40xx_sw_get_vid,
-               .max = 4094,
-       },
-};
-
-/* End of swconfig support */
-
-static int
-ar40xx_wait_bit(struct ar40xx_priv *priv, int reg, u32 mask, u32 val)
-{
-       int timeout = 20;
-       u32 t;
-
-       while (1) {
-               t = ar40xx_read(priv, reg);
-               if ((t & mask) == val)
-                       return 0;
-
-               if (timeout-- <= 0)
-                       break;
-
-               usleep_range(10, 20);
-       }
-
-       pr_err("ar40xx: timeout for reg %08x: %08x & %08x != %08x\n",
-              (unsigned int)reg, t, mask, val);
-       return -ETIMEDOUT;
-}
-
-static int
-ar40xx_atu_flush(struct ar40xx_priv *priv)
-{
-       int ret;
-
-       ret = ar40xx_wait_bit(priv, AR40XX_REG_ATU_FUNC,
-                             AR40XX_ATU_FUNC_BUSY, 0);
-       if (!ret)
-               ar40xx_write(priv, AR40XX_REG_ATU_FUNC,
-                            AR40XX_ATU_FUNC_OP_FLUSH |
-                            AR40XX_ATU_FUNC_BUSY);
-
-       return ret;
-}
-
-static void
-ar40xx_ess_reset(struct ar40xx_priv *priv)
-{
-       reset_control_assert(priv->ess_rst);
-       mdelay(10);
-       reset_control_deassert(priv->ess_rst);
-       /* Waiting for all inner tables init done.
-         * It cost 5~10ms.
-         */
-       mdelay(10);
-
-       pr_info("ESS reset ok!\n");
-}
-
-/* Start of psgmii self test */
-
-static void
-ar40xx_malibu_psgmii_ess_reset(struct ar40xx_priv *priv)
-{
-       u32 n;
-       struct mii_bus *bus = priv->mii_bus;
-       /* reset phy psgmii */
-       /* fix phy psgmii RX 20bit */
-       mdiobus_write(bus, 5, 0x0, 0x005b);
-       /* reset phy psgmii */
-       mdiobus_write(bus, 5, 0x0, 0x001b);
-       /* release reset phy psgmii */
-       mdiobus_write(bus, 5, 0x0, 0x005b);
-
-       for (n = 0; n < AR40XX_PSGMII_CALB_NUM; n++) {
-               u16 status;
-
-               status = ar40xx_phy_mmd_read(priv, 5, 1, 0x28);
-               if (status & BIT(0))
-                       break;
-               /* Polling interval to check PSGMII PLL in malibu is ready
-                 * the worst time is 8.67ms
-                 * for 25MHz reference clock
-                 * [512+(128+2048)*49]*80ns+100us
-                 */
-               mdelay(2);
-       }
-
-       /*check malibu psgmii calibration done end..*/
-
-       /*freeze phy psgmii RX CDR*/
-       mdiobus_write(bus, 5, 0x1a, 0x2230);
-
-       ar40xx_ess_reset(priv);
-
-       /*check psgmii calibration done start*/
-       for (n = 0; n < AR40XX_PSGMII_CALB_NUM; n++) {
-               u32 status;
-
-               status = ar40xx_psgmii_read(priv, 0xa0);
-               if (status & BIT(0))
-                       break;
-               /* Polling interval to check PSGMII PLL in ESS is ready */
-               mdelay(2);
-       }
-
-       /* check dakota psgmii calibration done end..*/
-
-       /* relesae phy psgmii RX CDR */
-       mdiobus_write(bus, 5, 0x1a, 0x3230);
-       /* release phy psgmii RX 20bit */
-       mdiobus_write(bus, 5, 0x0, 0x005f);
-}
-
-static void
-ar40xx_psgmii_single_phy_testing(struct ar40xx_priv *priv, int phy)
-{
-       int j;
-       u32 tx_ok, tx_error;
-       u32 rx_ok, rx_error;
-       u32 tx_ok_high16;
-       u32 rx_ok_high16;
-       u32 tx_all_ok, rx_all_ok;
-       struct mii_bus *bus = priv->mii_bus;
-
-       mdiobus_write(bus, phy, 0x0, 0x9000);
-       mdiobus_write(bus, phy, 0x0, 0x4140);
-
-       for (j = 0; j < AR40XX_PSGMII_CALB_NUM; j++) {
-               u16 status;
-
-               status = mdiobus_read(bus, phy, 0x11);
-               if (status & AR40XX_PHY_SPEC_STATUS_LINK)
-                       break;
-               /* the polling interval to check if the PHY link up or not
-                 * maxwait_timer: 750 ms +/-10 ms
-                 * minwait_timer : 1 us +/- 0.1us
-                 * time resides in minwait_timer ~ maxwait_timer
-                 * see IEEE 802.3 section 40.4.5.2
-                 */
-               mdelay(8);
-       }
-
-       /* enable check */
-       ar40xx_phy_mmd_write(priv, phy, 7, 0x8029, 0x0000);
-       ar40xx_phy_mmd_write(priv, phy, 7, 0x8029, 0x0003);
-
-       /* start traffic */
-       ar40xx_phy_mmd_write(priv, phy, 7, 0x8020, 0xa000);
-       /* wait for all traffic end
-         * 4096(pkt num)*1524(size)*8ns(125MHz)=49.9ms
-         */
-       mdelay(50);
-
-       /* check counter */
-       tx_ok = ar40xx_phy_mmd_read(priv, phy, 7, 0x802e);
-       tx_ok_high16 = ar40xx_phy_mmd_read(priv, phy, 7, 0x802d);
-       tx_error = ar40xx_phy_mmd_read(priv, phy, 7, 0x802f);
-       rx_ok = ar40xx_phy_mmd_read(priv, phy, 7, 0x802b);
-       rx_ok_high16 = ar40xx_phy_mmd_read(priv, phy, 7, 0x802a);
-       rx_error = ar40xx_phy_mmd_read(priv, phy, 7, 0x802c);
-       tx_all_ok = tx_ok + (tx_ok_high16 << 16);
-       rx_all_ok = rx_ok + (rx_ok_high16 << 16);
-       if (tx_all_ok == 0x1000 && tx_error == 0) {
-               /* success */
-               priv->phy_t_status &= (~BIT(phy));
-       } else {
-               pr_info("PHY %d single test PSGMII issue happen!\n", phy);
-               priv->phy_t_status |= BIT(phy);
-       }
-
-       mdiobus_write(bus, phy, 0x0, 0x1840);
-}
-
-static void
-ar40xx_psgmii_all_phy_testing(struct ar40xx_priv *priv)
-{
-       int phy, j;
-       struct mii_bus *bus = priv->mii_bus;
-
-       mdiobus_write(bus, 0x1f, 0x0, 0x9000);
-       mdiobus_write(bus, 0x1f, 0x0, 0x4140);
-
-       for (j = 0; j < AR40XX_PSGMII_CALB_NUM; j++) {
-               for (phy = 0; phy < AR40XX_NUM_PORTS - 1; phy++) {
-                       u16 status;
-
-                       status = mdiobus_read(bus, phy, 0x11);
-                       if (!(status & BIT(10)))
-                               break;
-               }
-
-               if (phy >= (AR40XX_NUM_PORTS - 1))
-                       break;
-               /* The polling interva to check if the PHY link up or not */
-               mdelay(8);
-       }
-       /* enable check */
-       ar40xx_phy_mmd_write(priv, 0x1f, 7, 0x8029, 0x0000);
-       ar40xx_phy_mmd_write(priv, 0x1f, 7, 0x8029, 0x0003);
-
-       /* start traffic */
-       ar40xx_phy_mmd_write(priv, 0x1f, 7, 0x8020, 0xa000);
-       /* wait for all traffic end
-         * 4096(pkt num)*1524(size)*8ns(125MHz)=49.9ms
-         */
-       mdelay(50);
-
-       for (phy = 0; phy < AR40XX_NUM_PORTS - 1; phy++) {
-               u32 tx_ok, tx_error;
-               u32 rx_ok, rx_error;
-               u32 tx_ok_high16;
-               u32 rx_ok_high16;
-               u32 tx_all_ok, rx_all_ok;
-
-               /* check counter */
-               tx_ok = ar40xx_phy_mmd_read(priv, phy, 7, 0x802e);
-               tx_ok_high16 = ar40xx_phy_mmd_read(priv, phy, 7, 0x802d);
-               tx_error = ar40xx_phy_mmd_read(priv, phy, 7, 0x802f);
-               rx_ok = ar40xx_phy_mmd_read(priv, phy, 7, 0x802b);
-               rx_ok_high16 = ar40xx_phy_mmd_read(priv, phy, 7, 0x802a);
-               rx_error = ar40xx_phy_mmd_read(priv, phy, 7, 0x802c);
-               tx_all_ok = tx_ok + (tx_ok_high16<<16);
-               rx_all_ok = rx_ok + (rx_ok_high16<<16);
-               if (tx_all_ok == 0x1000 && tx_error == 0) {
-                       /* success */
-                       priv->phy_t_status &= ~BIT(phy + 8);
-               } else {
-                       pr_info("PHY%d test see issue!\n", phy);
-                       priv->phy_t_status |= BIT(phy + 8);
-               }
-       }
-
-       pr_debug("PHY all test 0x%x \r\n", priv->phy_t_status);
-}
-
-void
-ar40xx_psgmii_self_test(struct ar40xx_priv *priv)
-{
-       u32 i, phy;
-       struct mii_bus *bus = priv->mii_bus;
-
-       ar40xx_malibu_psgmii_ess_reset(priv);
-
-       /* switch to access MII reg for copper */
-       mdiobus_write(bus, 4, 0x1f, 0x8500);
-       for (phy = 0; phy < AR40XX_NUM_PORTS - 1; phy++) {
-               /*enable phy mdio broadcast write*/
-               ar40xx_phy_mmd_write(priv, phy, 7, 0x8028, 0x801f);
-       }
-       /* force no link by power down */
-       mdiobus_write(bus, 0x1f, 0x0, 0x1840);
-       /*packet number*/
-       ar40xx_phy_mmd_write(priv, 0x1f, 7, 0x8021, 0x1000);
-       ar40xx_phy_mmd_write(priv, 0x1f, 7, 0x8062, 0x05e0);
-
-       /*fix mdi status */
-       mdiobus_write(bus, 0x1f, 0x10, 0x6800);
-       for (i = 0; i < AR40XX_PSGMII_CALB_NUM; i++) {
-               priv->phy_t_status = 0;
-
-               for (phy = 0; phy < AR40XX_NUM_PORTS - 1; phy++) {
-                       ar40xx_rmw(priv, AR40XX_REG_PORT_LOOKUP(phy + 1),
-                               AR40XX_PORT_LOOKUP_LOOPBACK,
-                               AR40XX_PORT_LOOKUP_LOOPBACK);
-               }
-
-               for (phy = 0; phy < AR40XX_NUM_PORTS - 1; phy++)
-                       ar40xx_psgmii_single_phy_testing(priv, phy);
-
-               ar40xx_psgmii_all_phy_testing(priv);
-
-               if (priv->phy_t_status)
-                       ar40xx_malibu_psgmii_ess_reset(priv);
-               else
-                       break;
-       }
-
-       if (i >= AR40XX_PSGMII_CALB_NUM)
-               pr_info("PSGMII cannot recover\n");
-       else
-               pr_debug("PSGMII recovered after %d times reset\n", i);
-
-       /* configuration recover */
-       /* packet number */
-       ar40xx_phy_mmd_write(priv, 0x1f, 7, 0x8021, 0x0);
-       /* disable check */
-       ar40xx_phy_mmd_write(priv, 0x1f, 7, 0x8029, 0x0);
-       /* disable traffic */
-       ar40xx_phy_mmd_write(priv, 0x1f, 7, 0x8020, 0x0);
-}
-
-void
-ar40xx_psgmii_self_test_clean(struct ar40xx_priv *priv)
-{
-       int phy;
-       struct mii_bus *bus = priv->mii_bus;
-
-       /* disable phy internal loopback */
-       mdiobus_write(bus, 0x1f, 0x10, 0x6860);
-       mdiobus_write(bus, 0x1f, 0x0, 0x9040);
-
-       for (phy = 0; phy < AR40XX_NUM_PORTS - 1; phy++) {
-               /* disable mac loop back */
-               ar40xx_rmw(priv, AR40XX_REG_PORT_LOOKUP(phy + 1),
-                               AR40XX_PORT_LOOKUP_LOOPBACK, 0);
-               /* disable phy mdio broadcast write */
-               ar40xx_phy_mmd_write(priv, phy, 7, 0x8028, 0x001f);
-       }
-
-       /* clear fdb entry */
-       ar40xx_atu_flush(priv);
-}
-
-/* End of psgmii self test */
-
-static void
-ar40xx_mac_mode_init(struct ar40xx_priv *priv, u32 mode)
-{
-       if (mode == PORT_WRAPPER_PSGMII) {
-               ar40xx_psgmii_write(priv, AR40XX_PSGMII_MODE_CONTROL, 0x2200);
-               ar40xx_psgmii_write(priv, AR40XX_PSGMIIPHY_TX_CONTROL, 0x8380);
-       }
-}
-
-static
-int ar40xx_cpuport_setup(struct ar40xx_priv *priv)
-{
-       u32 t;
-
-       t = AR40XX_PORT_STATUS_TXFLOW |
-            AR40XX_PORT_STATUS_RXFLOW |
-            AR40XX_PORT_TXHALF_FLOW |
-            AR40XX_PORT_DUPLEX |
-            AR40XX_PORT_SPEED_1000M;
-       ar40xx_write(priv, AR40XX_REG_PORT_STATUS(0), t);
-       usleep_range(10, 20);
-
-       t |= AR40XX_PORT_TX_EN |
-              AR40XX_PORT_RX_EN;
-       ar40xx_write(priv, AR40XX_REG_PORT_STATUS(0), t);
-
-       return 0;
-}
-
-static void
-ar40xx_init_port(struct ar40xx_priv *priv, int port)
-{
-       u32 t;
-
-       ar40xx_write(priv, AR40XX_REG_PORT_STATUS(port), 0);
-
-       ar40xx_write(priv, AR40XX_REG_PORT_HEADER(port), 0);
-
-       ar40xx_write(priv, AR40XX_REG_PORT_VLAN0(port), 0);
-
-       t = AR40XX_PORT_VLAN1_OUT_MODE_UNTOUCH << AR40XX_PORT_VLAN1_OUT_MODE_S;
-       ar40xx_write(priv, AR40XX_REG_PORT_VLAN1(port), t);
-
-       t = AR40XX_PORT_LOOKUP_LEARN;
-       t |= AR40XX_PORT_STATE_FORWARD << AR40XX_PORT_LOOKUP_STATE_S;
-       ar40xx_write(priv, AR40XX_REG_PORT_LOOKUP(port), t);
-}
-
-void
-ar40xx_init_globals(struct ar40xx_priv *priv)
-{
-       u32 t;
-
-       /* enable CPU port and disable mirror port */
-       t = AR40XX_FWD_CTRL0_CPU_PORT_EN |
-           AR40XX_FWD_CTRL0_MIRROR_PORT;
-       ar40xx_write(priv, AR40XX_REG_FWD_CTRL0, t);
-
-       /* forward multicast and broadcast frames to CPU */
-       t = (AR40XX_PORTS_ALL << AR40XX_FWD_CTRL1_UC_FLOOD_S) |
-           (AR40XX_PORTS_ALL << AR40XX_FWD_CTRL1_MC_FLOOD_S) |
-           (AR40XX_PORTS_ALL << AR40XX_FWD_CTRL1_BC_FLOOD_S);
-       ar40xx_write(priv, AR40XX_REG_FWD_CTRL1, t);
-
-       /* enable jumbo frames */
-       ar40xx_rmw(priv, AR40XX_REG_MAX_FRAME_SIZE,
-                  AR40XX_MAX_FRAME_SIZE_MTU, 9018 + 8 + 2);
-
-       /* Enable MIB counters */
-       ar40xx_rmw(priv, AR40XX_REG_MODULE_EN, 0,
-                  AR40XX_MODULE_EN_MIB);
-
-       /* Disable AZ */
-       ar40xx_write(priv, AR40XX_REG_EEE_CTRL, 0);
-
-       /* set flowctrl thershold for cpu port */
-       t = (AR40XX_PORT0_FC_THRESH_ON_DFLT << 16) |
-             AR40XX_PORT0_FC_THRESH_OFF_DFLT;
-       ar40xx_write(priv, AR40XX_REG_PORT_FLOWCTRL_THRESH(0), t);
-}
-
-static int
-ar40xx_hw_init(struct ar40xx_priv *priv)
-{
-       u32 i;
-
-       ar40xx_ess_reset(priv);
-
-       if (!priv->mii_bus)
-               return -1;
-
-       ar40xx_psgmii_self_test(priv);
-       ar40xx_psgmii_self_test_clean(priv);
-
-       ar40xx_mac_mode_init(priv, priv->mac_mode);
-
-       for (i = 0; i < priv->dev.ports; i++)
-               ar40xx_init_port(priv, i);
-
-       ar40xx_init_globals(priv);
-
-       return 0;
-}
-
-/* Start of qm error WAR */
-
-static
-int ar40xx_force_1g_full(struct ar40xx_priv *priv, u32 port_id)
-{
-       u32 reg;
-
-       if (port_id < 0 || port_id > 6)
-               return -1;
-
-       reg = AR40XX_REG_PORT_STATUS(port_id);
-       return ar40xx_rmw(priv, reg, AR40XX_PORT_SPEED,
-                       (AR40XX_PORT_SPEED_1000M | AR40XX_PORT_DUPLEX));
-}
-
-static
-int ar40xx_get_qm_status(struct ar40xx_priv *priv,
-                        u32 port_id, u32 *qm_buffer_err)
-{
-       u32 reg;
-       u32 qm_val;
-
-       if (port_id < 1 || port_id > 5) {
-               *qm_buffer_err = 0;
-               return -1;
-       }
-
-       if (port_id < 4) {
-               reg = AR40XX_REG_QM_PORT0_3_QNUM;
-               ar40xx_write(priv, AR40XX_REG_QM_DEBUG_ADDR, reg);
-               qm_val = ar40xx_read(priv, AR40XX_REG_QM_DEBUG_VALUE);
-               /* every 8 bits for each port */
-               *qm_buffer_err = (qm_val >> (port_id * 8)) & 0xFF;
-       } else {
-               reg = AR40XX_REG_QM_PORT4_6_QNUM;
-               ar40xx_write(priv, AR40XX_REG_QM_DEBUG_ADDR, reg);
-               qm_val = ar40xx_read(priv, AR40XX_REG_QM_DEBUG_VALUE);
-               /* every 8 bits for each port */
-               *qm_buffer_err = (qm_val >> ((port_id-4) * 8)) & 0xFF;
-       }
-
-       return 0;
-}
-
-static void
-ar40xx_sw_mac_polling_task(struct ar40xx_priv *priv)
-{
-       static int task_count;
-       u32 i;
-       u32 reg, value;
-       u32 link, speed, duplex;
-       u32 qm_buffer_err;
-       u16 port_phy_status[AR40XX_NUM_PORTS];
-       static u32 qm_err_cnt[AR40XX_NUM_PORTS] = {0, 0, 0, 0, 0, 0};
-       static u32 link_cnt[AR40XX_NUM_PORTS] = {0, 0, 0, 0, 0, 0};
-       struct mii_bus *bus = NULL;
-
-       if (!priv || !priv->mii_bus)
-               return;
-
-       bus = priv->mii_bus;
-
-       ++task_count;
-
-       for (i = 1; i < AR40XX_NUM_PORTS; ++i) {
-               port_phy_status[i] =
-                       mdiobus_read(bus, i-1, AR40XX_PHY_SPEC_STATUS);
-
-               speed = FIELD_GET(AR40XX_PHY_SPEC_STATUS_SPEED,
-                                 port_phy_status[i]);
-               link = FIELD_GET(AR40XX_PHY_SPEC_STATUS_LINK,
-                                port_phy_status[i]);
-               duplex = FIELD_GET(AR40XX_PHY_SPEC_STATUS_DUPLEX,
-                                  port_phy_status[i]);
-
-               if (link != priv->ar40xx_port_old_link[i]) {
-                       ++link_cnt[i];
-                       /* Up --> Down */
-                       if ((priv->ar40xx_port_old_link[i] ==
-                                       AR40XX_PORT_LINK_UP) &&
-                           (link == AR40XX_PORT_LINK_DOWN)) {
-                               /* LINK_EN disable(MAC force mode)*/
-                               reg = AR40XX_REG_PORT_STATUS(i);
-                               ar40xx_rmw(priv, reg,
-                                               AR40XX_PORT_AUTO_LINK_EN, 0);
-
-                               /* Check queue buffer */
-                               qm_err_cnt[i] = 0;
-                               ar40xx_get_qm_status(priv, i, &qm_buffer_err);
-                               if (qm_buffer_err) {
-                                       priv->ar40xx_port_qm_buf[i] =
-                                               AR40XX_QM_NOT_EMPTY;
-                               } else {
-                                       u16 phy_val = 0;
-
-                                       priv->ar40xx_port_qm_buf[i] =
-                                               AR40XX_QM_EMPTY;
-                                       ar40xx_force_1g_full(priv, i);
-                                       /* Ref:QCA8337 Datasheet,Clearing
-                                        * MENU_CTRL_EN prevents phy to
-                                        * stuck in 100BT mode when
-                                        * bringing up the link
-                                        */
-                                       ar40xx_phy_dbg_read(priv, i-1,
-                                                           AR40XX_PHY_DEBUG_0,
-                                                           &phy_val);
-                                       phy_val &= (~AR40XX_PHY_MANU_CTRL_EN);
-                                       ar40xx_phy_dbg_write(priv, i-1,
-                                                            AR40XX_PHY_DEBUG_0,
-                                                            phy_val);
-                               }
-                               priv->ar40xx_port_old_link[i] = link;
-                       } else if ((priv->ar40xx_port_old_link[i] ==
-                                               AR40XX_PORT_LINK_DOWN) &&
-                                       (link == AR40XX_PORT_LINK_UP)) {
-                               /* Down --> Up */
-                               if (priv->port_link_up[i] < 1) {
-                                       ++priv->port_link_up[i];
-                               } else {
-                                       /* Change port status */
-                                       reg = AR40XX_REG_PORT_STATUS(i);
-                                       value = ar40xx_read(priv, reg);
-                                       priv->port_link_up[i] = 0;
-
-                                       value &= ~(AR40XX_PORT_DUPLEX |
-                                                  AR40XX_PORT_SPEED);
-                                       value |= speed | (duplex ? BIT(6) : 0);
-                                       ar40xx_write(priv, reg, value);
-                                       /* clock switch need such time
-                                        * to avoid glitch
-                                        */
-                                       usleep_range(100, 200);
-
-                                       value |= AR40XX_PORT_AUTO_LINK_EN;
-                                       ar40xx_write(priv, reg, value);
-                                       /* HW need such time to make sure link
-                                        * stable before enable MAC
-                                        */
-                                       usleep_range(100, 200);
-
-                                       if (speed == AR40XX_PORT_SPEED_100M) {
-                                               u16 phy_val = 0;
-                                               /* Enable @100M, if down to 10M
-                                                * clock will change smoothly
-                                                */
-                                               ar40xx_phy_dbg_read(priv, i-1,
-                                                                   0,
-                                                                   &phy_val);
-                                               phy_val |=
-                                                       AR40XX_PHY_MANU_CTRL_EN;
-                                               ar40xx_phy_dbg_write(priv, i-1,
-                                                                    0,
-                                                                    phy_val);
-                                       }
-                                       priv->ar40xx_port_old_link[i] = link;
-                               }
-                       }
-               }
-
-               if (priv->ar40xx_port_qm_buf[i] == AR40XX_QM_NOT_EMPTY) {
-                       /* Check QM */
-                       ar40xx_get_qm_status(priv, i, &qm_buffer_err);
-                       if (qm_buffer_err) {
-                               ++qm_err_cnt[i];
-                       } else {
-                               priv->ar40xx_port_qm_buf[i] =
-                                               AR40XX_QM_EMPTY;
-                               qm_err_cnt[i] = 0;
-                               ar40xx_force_1g_full(priv, i);
-                       }
-               }
-       }
-}
-
-static void
-ar40xx_qm_err_check_work_task(struct work_struct *work)
-{
-       struct ar40xx_priv *priv = container_of(work, struct ar40xx_priv,
-                                       qm_dwork.work);
-
-       mutex_lock(&priv->qm_lock);
-
-       ar40xx_sw_mac_polling_task(priv);
-
-       mutex_unlock(&priv->qm_lock);
-
-       schedule_delayed_work(&priv->qm_dwork,
-                             msecs_to_jiffies(AR40XX_QM_WORK_DELAY));
-}
-
-static int
-ar40xx_qm_err_check_work_start(struct ar40xx_priv *priv)
-{
-       mutex_init(&priv->qm_lock);
-
-       INIT_DELAYED_WORK(&priv->qm_dwork, ar40xx_qm_err_check_work_task);
-
-       schedule_delayed_work(&priv->qm_dwork,
-                             msecs_to_jiffies(AR40XX_QM_WORK_DELAY));
-
-       return 0;
-}
-
-/* End of qm error WAR */
-
-static int
-ar40xx_vlan_init(struct ar40xx_priv *priv)
-{
-       int port;
-       unsigned long bmp;
-
-       /* By default Enable VLAN */
-       priv->vlan = 1;
-       priv->vlan_table[AR40XX_LAN_VLAN] = priv->cpu_bmp | priv->lan_bmp;
-       priv->vlan_table[AR40XX_WAN_VLAN] = priv->cpu_bmp | priv->wan_bmp;
-       priv->vlan_tagged = priv->cpu_bmp;
-       bmp = priv->lan_bmp;
-       for_each_set_bit(port, &bmp, AR40XX_NUM_PORTS)
-                       priv->pvid[port] = AR40XX_LAN_VLAN;
-
-       bmp = priv->wan_bmp;
-       for_each_set_bit(port, &bmp, AR40XX_NUM_PORTS)
-                       priv->pvid[port] = AR40XX_WAN_VLAN;
-
-       return 0;
-}
-
-static void
-ar40xx_mib_work_func(struct work_struct *work)
-{
-       struct ar40xx_priv *priv;
-       int err;
-
-       priv = container_of(work, struct ar40xx_priv, mib_work.work);
-
-       mutex_lock(&priv->mib_lock);
-
-       err = ar40xx_mib_capture(priv);
-       if (err)
-               goto next_port;
-
-       ar40xx_mib_fetch_port_stat(priv, priv->mib_next_port, false);
-
-next_port:
-       priv->mib_next_port++;
-       if (priv->mib_next_port >= priv->dev.ports)
-               priv->mib_next_port = 0;
-
-       mutex_unlock(&priv->mib_lock);
-
-       schedule_delayed_work(&priv->mib_work,
-                             msecs_to_jiffies(AR40XX_MIB_WORK_DELAY));
-}
-
-static void
-ar40xx_setup_port(struct ar40xx_priv *priv, int port, u32 members)
-{
-       u32 t;
-       u32 egress, ingress;
-       u32 pvid = priv->vlan_id[priv->pvid[port]];
-
-       if (priv->vlan) {
-               egress = AR40XX_PORT_VLAN1_OUT_MODE_UNMOD;
-
-               ingress = AR40XX_IN_SECURE;
-       } else {
-               egress = AR40XX_PORT_VLAN1_OUT_MODE_UNTOUCH;
-               ingress = AR40XX_IN_PORT_ONLY;
-       }
-
-       t = pvid << AR40XX_PORT_VLAN0_DEF_SVID_S;
-       t |= pvid << AR40XX_PORT_VLAN0_DEF_CVID_S;
-       ar40xx_write(priv, AR40XX_REG_PORT_VLAN0(port), t);
-
-       t = AR40XX_PORT_VLAN1_PORT_VLAN_PROP;
-       t |= egress << AR40XX_PORT_VLAN1_OUT_MODE_S;
-
-       ar40xx_write(priv, AR40XX_REG_PORT_VLAN1(port), t);
-
-       t = members;
-       t |= AR40XX_PORT_LOOKUP_LEARN;
-       t |= ingress << AR40XX_PORT_LOOKUP_IN_MODE_S;
-       t |= AR40XX_PORT_STATE_FORWARD << AR40XX_PORT_LOOKUP_STATE_S;
-       ar40xx_write(priv, AR40XX_REG_PORT_LOOKUP(port), t);
-}
-
-static void
-ar40xx_vtu_op(struct ar40xx_priv *priv, u32 op, u32 val)
-{
-       if (ar40xx_wait_bit(priv, AR40XX_REG_VTU_FUNC1,
-                           AR40XX_VTU_FUNC1_BUSY, 0))
-               return;
-
-       if ((op & AR40XX_VTU_FUNC1_OP) == AR40XX_VTU_FUNC1_OP_LOAD)
-               ar40xx_write(priv, AR40XX_REG_VTU_FUNC0, val);
-
-       op |= AR40XX_VTU_FUNC1_BUSY;
-       ar40xx_write(priv, AR40XX_REG_VTU_FUNC1, op);
-}
-
-static void
-ar40xx_vtu_load_vlan(struct ar40xx_priv *priv, u32 vid, u32 port_mask)
-{
-       u32 op;
-       u32 val;
-       int i;
-
-       op = AR40XX_VTU_FUNC1_OP_LOAD | (vid << AR40XX_VTU_FUNC1_VID_S);
-       val = AR40XX_VTU_FUNC0_VALID | AR40XX_VTU_FUNC0_IVL;
-       for (i = 0; i < AR40XX_NUM_PORTS; i++) {
-               u32 mode;
-
-               if ((port_mask & BIT(i)) == 0)
-                       mode = AR40XX_VTU_FUNC0_EG_MODE_NOT;
-               else if (priv->vlan == 0)
-                       mode = AR40XX_VTU_FUNC0_EG_MODE_KEEP;
-               else if ((priv->vlan_tagged & BIT(i)) ||
-                        (priv->vlan_id[priv->pvid[i]] != vid))
-                       mode = AR40XX_VTU_FUNC0_EG_MODE_TAG;
-               else
-                       mode = AR40XX_VTU_FUNC0_EG_MODE_UNTAG;
-
-               val |= mode << AR40XX_VTU_FUNC0_EG_MODE_S(i);
-       }
-       ar40xx_vtu_op(priv, op, val);
-}
-
-static void
-ar40xx_vtu_flush(struct ar40xx_priv *priv)
-{
-       ar40xx_vtu_op(priv, AR40XX_VTU_FUNC1_OP_FLUSH, 0);
-}
-
-static int
-ar40xx_sw_hw_apply(struct switch_dev *dev)
-{
-       struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
-       u8 portmask[AR40XX_NUM_PORTS];
-       int i, j;
-
-       mutex_lock(&priv->reg_mutex);
-       /* flush all vlan entries */
-       ar40xx_vtu_flush(priv);
-
-       memset(portmask, 0, sizeof(portmask));
-       if (priv->vlan) {
-               for (j = 0; j < AR40XX_MAX_VLANS; j++) {
-                       u8 vp = priv->vlan_table[j];
-
-                       if (!vp)
-                               continue;
-
-                       for (i = 0; i < dev->ports; i++) {
-                               u8 mask = BIT(i);
-
-                               if (vp & mask)
-                                       portmask[i] |= vp & ~mask;
-                       }
-
-                       ar40xx_vtu_load_vlan(priv, priv->vlan_id[j],
-                                            priv->vlan_table[j]);
-               }
-       } else {
-               /* 8021q vlan disabled */
-               for (i = 0; i < dev->ports; i++) {
-                       if (i == AR40XX_PORT_CPU)
-                               continue;
-
-                       portmask[i] = BIT(AR40XX_PORT_CPU);
-                       portmask[AR40XX_PORT_CPU] |= BIT(i);
-               }
-       }
-
-       /* update the port destination mask registers and tag settings */
-       for (i = 0; i < dev->ports; i++)
-               ar40xx_setup_port(priv, i, portmask[i]);
-
-       ar40xx_set_mirror_regs(priv);
-
-       mutex_unlock(&priv->reg_mutex);
-       return 0;
-}
-
-static int
-ar40xx_sw_reset_switch(struct switch_dev *dev)
-{
-       struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
-       int i, rv;
-
-       mutex_lock(&priv->reg_mutex);
-       memset(&priv->vlan, 0, sizeof(struct ar40xx_priv) -
-               offsetof(struct ar40xx_priv, vlan));
-
-       for (i = 0; i < AR40XX_MAX_VLANS; i++)
-               priv->vlan_id[i] = i;
-
-       ar40xx_vlan_init(priv);
-
-       priv->mirror_rx = false;
-       priv->mirror_tx = false;
-       priv->source_port = 0;
-       priv->monitor_port = 0;
-
-       mutex_unlock(&priv->reg_mutex);
-
-       rv = ar40xx_sw_hw_apply(dev);
-       return rv;
-}
-
-static int
-ar40xx_start(struct ar40xx_priv *priv)
-{
-       int ret;
-
-       ret = ar40xx_hw_init(priv);
-       if (ret)
-               return ret;
-
-       ret = ar40xx_sw_reset_switch(&priv->dev);
-       if (ret)
-               return ret;
-
-       /* at last, setup cpu port */
-       ret = ar40xx_cpuport_setup(priv);
-       if (ret)
-               return ret;
-
-       schedule_delayed_work(&priv->mib_work,
-                             msecs_to_jiffies(AR40XX_MIB_WORK_DELAY));
-
-       ar40xx_qm_err_check_work_start(priv);
-
-       return 0;
-}
-
-static const struct switch_dev_ops ar40xx_sw_ops = {
-       .attr_global = {
-               .attr = ar40xx_sw_attr_globals,
-               .n_attr = ARRAY_SIZE(ar40xx_sw_attr_globals),
-       },
-       .attr_port = {
-               .attr = ar40xx_sw_attr_port,
-               .n_attr = ARRAY_SIZE(ar40xx_sw_attr_port),
-       },
-       .attr_vlan = {
-               .attr = ar40xx_sw_attr_vlan,
-               .n_attr = ARRAY_SIZE(ar40xx_sw_attr_vlan),
-       },
-       .get_port_pvid = ar40xx_sw_get_pvid,
-       .set_port_pvid = ar40xx_sw_set_pvid,
-       .get_vlan_ports = ar40xx_sw_get_ports,
-       .set_vlan_ports = ar40xx_sw_set_ports,
-       .apply_config = ar40xx_sw_hw_apply,
-       .reset_switch = ar40xx_sw_reset_switch,
-       .get_port_link = ar40xx_sw_get_port_link,
-};
-
-/* Platform driver probe function */
-
-static int ar40xx_probe(struct platform_device *pdev)
-{
-       struct device_node *switch_node;
-       struct device_node *psgmii_node;
-       struct device_node *mdio_node;
-       const __be32 *mac_mode;
-       struct clk *ess_clk;
-       struct switch_dev *swdev;
-       struct ar40xx_priv *priv;
-       u32 len;
-       u32 num_mibs;
-       struct resource psgmii_base = {0};
-       struct resource switch_base = {0};
-       int ret;
-
-       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
-
-       platform_set_drvdata(pdev, priv);
-       ar40xx_priv = priv;
-
-       switch_node = of_node_get(pdev->dev.of_node);
-       if (of_address_to_resource(switch_node, 0, &switch_base) != 0)
-               return -EIO;
-
-       priv->hw_addr = devm_ioremap_resource(&pdev->dev, &switch_base);
-       if (IS_ERR(priv->hw_addr)) {
-               dev_err(&pdev->dev, "Failed to ioremap switch_base!\n");
-               return PTR_ERR(priv->hw_addr);
-       }
-
-       /*psgmii dts get*/
-       psgmii_node = of_find_node_by_name(NULL, "ess-psgmii");
-       if (!psgmii_node) {
-               dev_err(&pdev->dev, "Failed to find ess-psgmii node!\n");
-               return -EINVAL;
-       }
-
-       if (of_address_to_resource(psgmii_node, 0, &psgmii_base) != 0)
-               return -EIO;
-
-       priv->psgmii_hw_addr = devm_ioremap_resource(&pdev->dev, &psgmii_base);
-       if (IS_ERR(priv->psgmii_hw_addr)) {
-               dev_err(&pdev->dev, "psgmii ioremap fail!\n");
-               return PTR_ERR(priv->psgmii_hw_addr);
-       }
-
-       mac_mode = of_get_property(switch_node, "switch_mac_mode", &len);
-       if (!mac_mode) {
-               dev_err(&pdev->dev, "Failed to read switch_mac_mode\n");
-               return -EINVAL;
-       }
-       priv->mac_mode = be32_to_cpup(mac_mode);
-
-       ess_clk = of_clk_get_by_name(switch_node, "ess_clk");
-       if (ess_clk)
-               clk_prepare_enable(ess_clk);
-
-       priv->ess_rst = devm_reset_control_get(&pdev->dev, "ess_rst");
-       if (IS_ERR(priv->ess_rst)) {
-               dev_err(&pdev->dev, "Failed to get ess_rst control!\n");
-               return PTR_ERR(priv->ess_rst);
-       }
-
-       if (of_property_read_u32(switch_node, "switch_cpu_bmp",
-                                &priv->cpu_bmp) ||
-           of_property_read_u32(switch_node, "switch_lan_bmp",
-                                &priv->lan_bmp) ||
-           of_property_read_u32(switch_node, "switch_wan_bmp",
-                                &priv->wan_bmp)) {
-               dev_err(&pdev->dev, "Failed to read port properties\n");
-               return -EIO;
-       }
-
-       mutex_init(&priv->reg_mutex);
-       mutex_init(&priv->mib_lock);
-       INIT_DELAYED_WORK(&priv->mib_work, ar40xx_mib_work_func);
-
-       /* register switch */
-       swdev = &priv->dev;
-
-       mdio_node = of_find_compatible_node(NULL, NULL, "qcom,ipq4019-mdio");
-       if (!mdio_node) {
-               dev_err(&pdev->dev, "Probe failed - Cannot find mdio node by phandle!\n");
-               ret = -ENODEV;
-               goto err_missing_phy;
-       }
-
-       priv->mii_bus = of_mdio_find_bus(mdio_node);
-
-       if (priv->mii_bus == NULL) {
-               dev_err(&pdev->dev, "Probe failed - Missing PHYs!\n");
-               ret = -ENODEV;
-               goto err_missing_phy;
-       }
-
-       swdev->alias = dev_name(&priv->mii_bus->dev);
-
-       swdev->cpu_port = AR40XX_PORT_CPU;
-       swdev->name = "QCA AR40xx";
-       swdev->vlans = AR40XX_MAX_VLANS;
-       swdev->ports = AR40XX_NUM_PORTS;
-       swdev->ops = &ar40xx_sw_ops;
-       ret = register_switch(swdev, NULL);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "Switch registration failed!\n");
-               return ret;
-       }
-
-       num_mibs = ARRAY_SIZE(ar40xx_mibs);
-       len = priv->dev.ports * num_mibs *
-             sizeof(*priv->mib_stats);
-       priv->mib_stats = devm_kzalloc(&pdev->dev, len, GFP_KERNEL);
-       if (!priv->mib_stats) {
-               ret = -ENOMEM;
-               goto err_unregister_switch;
-       }
-
-       ar40xx_start(priv);
-
-       return 0;
-
-err_unregister_switch:
-       unregister_switch(&priv->dev);
-err_missing_phy:
-       platform_set_drvdata(pdev, NULL);
-       return ret;
-}
-
-static int ar40xx_remove(struct platform_device *pdev)
-{
-       struct ar40xx_priv *priv = platform_get_drvdata(pdev);
-
-       cancel_delayed_work_sync(&priv->qm_dwork);
-       cancel_delayed_work_sync(&priv->mib_work);
-
-       unregister_switch(&priv->dev);
-
-       return 0;
-}
-
-static const struct of_device_id ar40xx_of_mtable[] = {
-       {.compatible = "qcom,ess-switch" },
-       {}
-};
-
-struct platform_driver ar40xx_drv = {
-       .probe = ar40xx_probe,
-       .remove = ar40xx_remove,
-       .driver = {
-               .name    = "ar40xx",
-               .of_match_table = ar40xx_of_mtable,
-       },
-};
-
-module_platform_driver(ar40xx_drv);
-
-MODULE_DESCRIPTION("IPQ40XX ESS driver");
-MODULE_LICENSE("Dual BSD/GPL");
diff --git a/target/linux/ipq40xx/files-5.15/drivers/net/mdio/ar40xx.h b/target/linux/ipq40xx/files-5.15/drivers/net/mdio/ar40xx.h
deleted file mode 100644 (file)
index 7ba40cc..0000000
+++ /dev/null
@@ -1,342 +0,0 @@
-/*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
- *
- * Permission to use, copy, modify, and/or distribute this software for
- * any purpose with or without fee is hereby granted, provided that the
- * above copyright notice and this permission notice appear in all copies.
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
- #ifndef __AR40XX_H
-#define __AR40XX_H
-
-#define AR40XX_MAX_VLANS       128
-#define AR40XX_NUM_PORTS       6
-#define AR40XX_NUM_PHYS        5
-
-#define BITS(_s, _n)   (((1UL << (_n)) - 1) << _s)
-
-struct ar40xx_priv {
-       struct switch_dev dev;
-
-       u8  __iomem      *hw_addr;
-       u8  __iomem      *psgmii_hw_addr;
-       u32 mac_mode;
-       struct reset_control *ess_rst;
-       u32 cpu_bmp;
-       u32 lan_bmp;
-       u32 wan_bmp;
-
-       struct mii_bus *mii_bus;
-       struct phy_device *phy;
-
-       /* mutex for qm task */
-       struct mutex qm_lock;
-       struct delayed_work qm_dwork;
-       u32 port_link_up[AR40XX_NUM_PORTS];
-       u32 ar40xx_port_old_link[AR40XX_NUM_PORTS];
-       u32 ar40xx_port_qm_buf[AR40XX_NUM_PORTS];
-
-       u32 phy_t_status;
-
-       /* mutex for switch reg access */
-       struct mutex reg_mutex;
-
-       /* mutex for mib task */
-       struct mutex mib_lock;
-       struct delayed_work mib_work;
-       int mib_next_port;
-       u64 *mib_stats;
-
-       char buf[2048];
-
-       /* all fields below will be cleared on reset */
-       bool vlan;
-       u16 vlan_id[AR40XX_MAX_VLANS];
-       u8 vlan_table[AR40XX_MAX_VLANS];
-       u8 vlan_tagged;
-       u16 pvid[AR40XX_NUM_PORTS];
-
-       /* mirror */
-       bool mirror_rx;
-       bool mirror_tx;
-       int source_port;
-       int monitor_port;
-};
-
-#define AR40XX_PORT_LINK_UP 1
-#define AR40XX_PORT_LINK_DOWN 0
-#define AR40XX_QM_NOT_EMPTY  1
-#define AR40XX_QM_EMPTY  0
-
-#define AR40XX_LAN_VLAN        1
-#define AR40XX_WAN_VLAN        2
-
-enum ar40xx_port_wrapper_cfg {
-       PORT_WRAPPER_PSGMII = 0,
-};
-
-struct ar40xx_mib_desc {
-       u32 size;
-       u32 offset;
-       const char *name;
-};
-
-#define AR40XX_PORT_CPU        0
-
-#define AR40XX_PSGMII_MODE_CONTROL     0x1b4
-#define   AR40XX_PSGMII_ATHR_CSCO_MODE_25M     BIT(0)
-
-#define AR40XX_PSGMIIPHY_TX_CONTROL     0x288
-
-#define AR40XX_MII_ATH_MMD_ADDR                0x0d
-#define AR40XX_MII_ATH_MMD_DATA                0x0e
-#define AR40XX_MII_ATH_DBG_ADDR                0x1d
-#define AR40XX_MII_ATH_DBG_DATA                0x1e
-
-#define AR40XX_STATS_RXBROAD           0x00
-#define AR40XX_STATS_RXPAUSE           0x04
-#define AR40XX_STATS_RXMULTI           0x08
-#define AR40XX_STATS_RXFCSERR          0x0c
-#define AR40XX_STATS_RXALIGNERR                0x10
-#define AR40XX_STATS_RXRUNT            0x14
-#define AR40XX_STATS_RXFRAGMENT                0x18
-#define AR40XX_STATS_RX64BYTE          0x1c
-#define AR40XX_STATS_RX128BYTE         0x20
-#define AR40XX_STATS_RX256BYTE         0x24
-#define AR40XX_STATS_RX512BYTE         0x28
-#define AR40XX_STATS_RX1024BYTE                0x2c
-#define AR40XX_STATS_RX1518BYTE                0x30
-#define AR40XX_STATS_RXMAXBYTE         0x34
-#define AR40XX_STATS_RXTOOLONG         0x38
-#define AR40XX_STATS_RXGOODBYTE                0x3c
-#define AR40XX_STATS_RXBADBYTE         0x44
-#define AR40XX_STATS_RXOVERFLOW                0x4c
-#define AR40XX_STATS_FILTERED          0x50
-#define AR40XX_STATS_TXBROAD           0x54
-#define AR40XX_STATS_TXPAUSE           0x58
-#define AR40XX_STATS_TXMULTI           0x5c
-#define AR40XX_STATS_TXUNDERRUN                0x60
-#define AR40XX_STATS_TX64BYTE          0x64
-#define AR40XX_STATS_TX128BYTE         0x68
-#define AR40XX_STATS_TX256BYTE         0x6c
-#define AR40XX_STATS_TX512BYTE         0x70
-#define AR40XX_STATS_TX1024BYTE                0x74
-#define AR40XX_STATS_TX1518BYTE                0x78
-#define AR40XX_STATS_TXMAXBYTE         0x7c
-#define AR40XX_STATS_TXOVERSIZE                0x80
-#define AR40XX_STATS_TXBYTE            0x84
-#define AR40XX_STATS_TXCOLLISION       0x8c
-#define AR40XX_STATS_TXABORTCOL                0x90
-#define AR40XX_STATS_TXMULTICOL                0x94
-#define AR40XX_STATS_TXSINGLECOL       0x98
-#define AR40XX_STATS_TXEXCDEFER                0x9c
-#define AR40XX_STATS_TXDEFER           0xa0
-#define AR40XX_STATS_TXLATECOL         0xa4
-
-#define AR40XX_REG_MODULE_EN                   0x030
-#define   AR40XX_MODULE_EN_MIB                 BIT(0)
-
-#define AR40XX_REG_MIB_FUNC                    0x034
-#define   AR40XX_MIB_BUSY              BIT(17)
-#define   AR40XX_MIB_CPU_KEEP                  BIT(20)
-#define   AR40XX_MIB_FUNC              BITS(24, 3)
-#define   AR40XX_MIB_FUNC_S            24
-#define   AR40XX_MIB_FUNC_NO_OP                0x0
-#define   AR40XX_MIB_FUNC_FLUSH                0x1
-
-#define AR40XX_ESS_SERVICE_TAG         0x48
-#define AR40XX_ESS_SERVICE_TAG_STAG    BIT(17)
-
-#define AR40XX_REG_PORT_STATUS(_i)             (0x07c + (_i) * 4)
-#define   AR40XX_PORT_SPEED                    BITS(0, 2)
-#define   AR40XX_PORT_STATUS_SPEED_S   0
-#define   AR40XX_PORT_TX_EN                    BIT(2)
-#define   AR40XX_PORT_RX_EN                    BIT(3)
-#define   AR40XX_PORT_STATUS_TXFLOW    BIT(4)
-#define   AR40XX_PORT_STATUS_RXFLOW    BIT(5)
-#define   AR40XX_PORT_DUPLEX                   BIT(6)
-#define   AR40XX_PORT_TXHALF_FLOW              BIT(7)
-#define   AR40XX_PORT_STATUS_LINK_UP   BIT(8)
-#define   AR40XX_PORT_AUTO_LINK_EN             BIT(9)
-#define   AR40XX_PORT_STATUS_FLOW_CONTROL  BIT(12)
-
-#define AR40XX_REG_MAX_FRAME_SIZE              0x078
-#define   AR40XX_MAX_FRAME_SIZE_MTU            BITS(0, 14)
-
-#define AR40XX_REG_PORT_HEADER(_i)             (0x09c + (_i) * 4)
-
-#define AR40XX_REG_EEE_CTRL                    0x100
-#define   AR40XX_EEE_CTRL_DISABLE_PHY(_i)      BIT(4 + (_i) * 2)
-
-#define AR40XX_REG_PORT_VLAN0(_i)              (0x420 + (_i) * 0x8)
-#define   AR40XX_PORT_VLAN0_DEF_SVID           BITS(0, 12)
-#define   AR40XX_PORT_VLAN0_DEF_SVID_S         0
-#define   AR40XX_PORT_VLAN0_DEF_CVID           BITS(16, 12)
-#define   AR40XX_PORT_VLAN0_DEF_CVID_S         16
-
-#define AR40XX_REG_PORT_VLAN1(_i)              (0x424 + (_i) * 0x8)
-#define   AR40XX_PORT_VLAN1_CORE_PORT          BIT(9)
-#define   AR40XX_PORT_VLAN1_PORT_TLS_MODE      BIT(7)
-#define   AR40XX_PORT_VLAN1_PORT_VLAN_PROP     BIT(6)
-#define   AR40XX_PORT_VLAN1_OUT_MODE           BITS(12, 2)
-#define   AR40XX_PORT_VLAN1_OUT_MODE_S         12
-#define   AR40XX_PORT_VLAN1_OUT_MODE_UNMOD     0
-#define   AR40XX_PORT_VLAN1_OUT_MODE_UNTAG     1
-#define   AR40XX_PORT_VLAN1_OUT_MODE_TAG               2
-#define   AR40XX_PORT_VLAN1_OUT_MODE_UNTOUCH   3
-
-#define AR40XX_REG_VTU_FUNC0                   0x0610
-#define   AR40XX_VTU_FUNC0_EG_MODE             BITS(4, 14)
-#define   AR40XX_VTU_FUNC0_EG_MODE_S(_i)       (4 + (_i) * 2)
-#define   AR40XX_VTU_FUNC0_EG_MODE_KEEP                0
-#define   AR40XX_VTU_FUNC0_EG_MODE_UNTAG       1
-#define   AR40XX_VTU_FUNC0_EG_MODE_TAG         2
-#define   AR40XX_VTU_FUNC0_EG_MODE_NOT         3
-#define   AR40XX_VTU_FUNC0_IVL                 BIT(19)
-#define   AR40XX_VTU_FUNC0_VALID               BIT(20)
-
-#define AR40XX_REG_VTU_FUNC1                   0x0614
-#define   AR40XX_VTU_FUNC1_OP                  BITS(0, 3)
-#define   AR40XX_VTU_FUNC1_OP_NOOP             0
-#define   AR40XX_VTU_FUNC1_OP_FLUSH            1
-#define   AR40XX_VTU_FUNC1_OP_LOAD             2
-#define   AR40XX_VTU_FUNC1_OP_PURGE            3
-#define   AR40XX_VTU_FUNC1_OP_REMOVE_PORT      4
-#define   AR40XX_VTU_FUNC1_OP_GET_NEXT         5
-#define   AR40XX7_VTU_FUNC1_OP_GET_ONE         6
-#define   AR40XX_VTU_FUNC1_FULL                        BIT(4)
-#define   AR40XX_VTU_FUNC1_PORT                        BIT(8, 4)
-#define   AR40XX_VTU_FUNC1_PORT_S              8
-#define   AR40XX_VTU_FUNC1_VID                 BIT(16, 12)
-#define   AR40XX_VTU_FUNC1_VID_S               16
-#define   AR40XX_VTU_FUNC1_BUSY                        BIT(31)
-
-#define AR40XX_REG_FWD_CTRL0                   0x620
-#define   AR40XX_FWD_CTRL0_CPU_PORT_EN         BIT(10)
-#define   AR40XX_FWD_CTRL0_MIRROR_PORT         BITS(4, 4)
-#define   AR40XX_FWD_CTRL0_MIRROR_PORT_S       4
-
-#define AR40XX_REG_FWD_CTRL1                   0x624
-#define   AR40XX_FWD_CTRL1_UC_FLOOD            BITS(0, 7)
-#define   AR40XX_FWD_CTRL1_UC_FLOOD_S          0
-#define   AR40XX_FWD_CTRL1_MC_FLOOD            BITS(8, 7)
-#define   AR40XX_FWD_CTRL1_MC_FLOOD_S          8
-#define   AR40XX_FWD_CTRL1_BC_FLOOD            BITS(16, 7)
-#define   AR40XX_FWD_CTRL1_BC_FLOOD_S          16
-#define   AR40XX_FWD_CTRL1_IGMP                        BITS(24, 7)
-#define   AR40XX_FWD_CTRL1_IGMP_S              24
-
-#define AR40XX_REG_PORT_LOOKUP(_i)             (0x660 + (_i) * 0xc)
-#define   AR40XX_PORT_LOOKUP_MEMBER            BITS(0, 7)
-#define   AR40XX_PORT_LOOKUP_IN_MODE           BITS(8, 2)
-#define   AR40XX_PORT_LOOKUP_IN_MODE_S         8
-#define   AR40XX_PORT_LOOKUP_STATE             BITS(16, 3)
-#define   AR40XX_PORT_LOOKUP_STATE_S           16
-#define   AR40XX_PORT_LOOKUP_LEARN             BIT(20)
-#define   AR40XX_PORT_LOOKUP_LOOPBACK          BIT(21)
-#define   AR40XX_PORT_LOOKUP_ING_MIRROR_EN     BIT(25)
-
-#define AR40XX_REG_ATU_FUNC                    0x60c
-#define   AR40XX_ATU_FUNC_OP                   BITS(0, 4)
-#define   AR40XX_ATU_FUNC_OP_NOOP              0x0
-#define   AR40XX_ATU_FUNC_OP_FLUSH             0x1
-#define   AR40XX_ATU_FUNC_OP_LOAD              0x2
-#define   AR40XX_ATU_FUNC_OP_PURGE             0x3
-#define   AR40XX_ATU_FUNC_OP_FLUSH_LOCKED      0x4
-#define   AR40XX_ATU_FUNC_OP_FLUSH_UNICAST     0x5
-#define   AR40XX_ATU_FUNC_OP_GET_NEXT          0x6
-#define   AR40XX_ATU_FUNC_OP_SEARCH_MAC                0x7
-#define   AR40XX_ATU_FUNC_OP_CHANGE_TRUNK      0x8
-#define   AR40XX_ATU_FUNC_BUSY                 BIT(31)
-
-#define AR40XX_REG_QM_DEBUG_ADDR               0x820
-#define AR40XX_REG_QM_DEBUG_VALUE              0x824
-#define   AR40XX_REG_QM_PORT0_3_QNUM           0x1d
-#define   AR40XX_REG_QM_PORT4_6_QNUM           0x1e
-
-#define AR40XX_REG_PORT_HOL_CTRL1(_i)          (0x974 + (_i) * 0x8)
-#define   AR40XX_PORT_HOL_CTRL1_EG_MIRROR_EN   BIT(16)
-
-#define AR40XX_REG_PORT_FLOWCTRL_THRESH(_i)    (0x9b0 + (_i) * 0x4)
-#define   AR40XX_PORT0_FC_THRESH_ON_DFLT       0x60
-#define   AR40XX_PORT0_FC_THRESH_OFF_DFLT      0x90
-
-#define AR40XX_PHY_DEBUG_0   0
-#define AR40XX_PHY_MANU_CTRL_EN  BIT(12)
-
-#define AR40XX_PHY_DEBUG_2   2
-
-#define AR40XX_PHY_SPEC_STATUS 0x11
-#define   AR40XX_PHY_SPEC_STATUS_LINK          BIT(10)
-#define   AR40XX_PHY_SPEC_STATUS_DUPLEX                BIT(13)
-#define   AR40XX_PHY_SPEC_STATUS_SPEED         BITS(14, 2)
-
-/* port forwarding state */
-enum {
-       AR40XX_PORT_STATE_DISABLED = 0,
-       AR40XX_PORT_STATE_BLOCK = 1,
-       AR40XX_PORT_STATE_LISTEN = 2,
-       AR40XX_PORT_STATE_LEARN = 3,
-       AR40XX_PORT_STATE_FORWARD = 4
-};
-
-/* ingress 802.1q mode */
-enum {
-       AR40XX_IN_PORT_ONLY = 0,
-       AR40XX_IN_PORT_FALLBACK = 1,
-       AR40XX_IN_VLAN_ONLY = 2,
-       AR40XX_IN_SECURE = 3
-};
-
-/* egress 802.1q mode */
-enum {
-       AR40XX_OUT_KEEP = 0,
-       AR40XX_OUT_STRIP_VLAN = 1,
-       AR40XX_OUT_ADD_VLAN = 2
-};
-
-/* port speed */
-enum {
-       AR40XX_PORT_SPEED_10M = 0,
-       AR40XX_PORT_SPEED_100M = 1,
-       AR40XX_PORT_SPEED_1000M = 2,
-       AR40XX_PORT_SPEED_ERR = 3,
-};
-
-#define AR40XX_MIB_WORK_DELAY  2000 /* msecs */
-
-#define AR40XX_QM_WORK_DELAY    100
-
-#define   AR40XX_MIB_FUNC_CAPTURE      0x3
-
-#define AR40XX_REG_PORT_STATS_START    0x1000
-#define AR40XX_REG_PORT_STATS_LEN              0x100
-
-#define AR40XX_PORTS_ALL       0x3f
-
-#define AR40XX_PSGMII_ID       5
-#define AR40XX_PSGMII_CALB_NUM 100
-#define AR40XX_MALIBU_PSGMII_MODE_CTRL 0x6d
-#define AR40XX_MALIBU_PHY_PSGMII_MODE_CTRL_ADJUST_VAL  0x220c
-#define AR40XX_MALIBU_PHY_MMD7_DAC_CTRL        0x801a
-#define AR40XX_MALIBU_DAC_CTRL_MASK    0x380
-#define AR40XX_MALIBU_DAC_CTRL_VALUE   0x280
-#define AR40XX_MALIBU_PHY_RLP_CTRL       0x805a
-#define AR40XX_PSGMII_TX_DRIVER_1_CTRL 0xb
-#define AR40XX_MALIBU_PHY_PSGMII_REDUCE_SERDES_TX_AMP  0x8a
-#define AR40XX_MALIBU_PHY_LAST_ADDR    4
-
-static inline struct ar40xx_priv *
-swdev_to_ar40xx(struct switch_dev *swdev)
-{
-       return container_of(swdev, struct ar40xx_priv, dev);
-}
-
-#endif
index b2d7a40..a007410 100644 (file)
@@ -21,7 +21,7 @@
  static void qcom_scm_set_download_mode(bool enable)
  {
        bool avail;
-@@ -1320,6 +1334,13 @@ static int qcom_scm_probe(struct platfor
+@@ -1314,6 +1328,13 @@ static int qcom_scm_probe(struct platfor
        if (download_mode)
                qcom_scm_set_download_mode(true);
  
index 4cb691f..dc9c11e 100644 (file)
@@ -11,6 +11,11 @@ board_config_update
 board=$(board_name)
 
 case "$board" in
+arris,tr4400-v2)
+       ucidef_set_interfaces_lan_wan "eth1" "eth2"
+       ucidef_add_switch "switch0" \
+               "1:lan" "2:lan" "3:lan" "4:lan" "6u@eth1" "0u@eth0"
+       ;;
 askey,rt4230w-rev6 |\
 asrock,g10 |\
 nec,wg2600hp)
index 84ffcd8..f9e592f 100644 (file)
@@ -10,6 +10,7 @@ platform_check_image() {
 
 platform_do_upgrade() {
        case "$(board_name)" in
+       arris,tr4400-v2 |\
        askey,rt4230w-rev6 |\
        compex,wpq864|\
        netgear,d7800 |\
diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065-tr4400-v2.dts b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065-tr4400-v2.dts
new file mode 100644 (file)
index 0000000..871cc09
--- /dev/null
@@ -0,0 +1,425 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "qcom-ipq8065.dtsi"
+#include <dt-bindings/input/input.h>
+
+/ {
+       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 = <KEY_RESTART>;
+                       debounce-interval = <60>;
+                       wakeup-source;
+               };
+
+               wps {
+                       label = "wps";
+                       gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_WPS_BUTTON>;
+                       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 = <GSBI_PROT_SPI>;
+       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";
+
+       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>;
+
+                       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";
+};
+
+&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";
+               };
+       };
+};
index 819c73d..469f2c6 100644 (file)
@@ -65,6 +65,19 @@ define Device/ZyXELImage
                append-metadata
 endef
 
+define Device/arris_tr4400-v2
+       $(call Device/LegacyImage)
+       DEVICE_VENDOR := Arris
+       DEVICE_MODEL := TR4400
+       DEVICE_VARIANT := v2
+       SOC := qcom-ipq8065
+       BLOCKSIZE := 128k
+       PAGESIZE := 2048
+       DEVICE_PACKAGES := ath10k-firmware-qca9984-ct ath10k-firmware-qca99x0-ct
+       KERNEL_IN_UBI := 1
+endef
+TARGET_DEVICES += arris_tr4400-v2
+
 define Device/askey_rt4230w-rev6
        $(call Device/LegacyImage)
        DEVICE_VENDOR := Askey
index 275b960..a7eacf3 100644 (file)
@@ -10,7 +10,7 @@ Signed-off-by: John Crispin <john@phrozen.org>
 
 --- a/arch/arm/boot/dts/Makefile
 +++ b/arch/arm/boot/dts/Makefile
-@@ -908,8 +908,29 @@ dtb-$(CONFIG_ARCH_QCOM) += \
+@@ -908,8 +908,30 @@ dtb-$(CONFIG_ARCH_QCOM) += \
        qcom-ipq4019-ap.dk04.1-c3.dtb \
        qcom-ipq4019-ap.dk07.1-c1.dtb \
        qcom-ipq4019-ap.dk07.1-c2.dtb \
@@ -33,6 +33,7 @@ Signed-off-by: John Crispin <john@phrozen.org>
 +      qcom-ipq8065-nbg6817.dtb \
 +      qcom-ipq8065-r7800.dtb \
 +      qcom-ipq8065-rt4230w-rev6.dtb \
++      qcom-ipq8065-tr4400-v2.dtb \
 +      qcom-ipq8065-xr500.dtb \
 +      qcom-ipq8068-ecw5410.dtb \
 +      qcom-ipq8068-mr42.dtb \
index db12b32..05f39f6 100644 (file)
@@ -10,7 +10,7 @@ Signed-off-by: John Crispin <john@phrozen.org>
 
 --- a/arch/arm/boot/dts/Makefile
 +++ b/arch/arm/boot/dts/Makefile
-@@ -956,8 +956,29 @@ dtb-$(CONFIG_ARCH_QCOM) += \
+@@ -956,8 +956,30 @@ dtb-$(CONFIG_ARCH_QCOM) += \
        qcom-ipq4019-ap.dk04.1-c3.dtb \
        qcom-ipq4019-ap.dk07.1-c1.dtb \
        qcom-ipq4019-ap.dk07.1-c2.dtb \
@@ -32,8 +32,9 @@ Signed-off-by: John Crispin <john@phrozen.org>
 +      qcom-ipq8064-wxr-2533dhp.dtb \
 +      qcom-ipq8065-nbg6817.dtb \
 +      qcom-ipq8065-r7800.dtb \
-+      qcom-ipq8065-xr500.dtb \
 +      qcom-ipq8065-rt4230w-rev6.dtb \
++      qcom-ipq8065-tr4400-v2.dtb \
++      qcom-ipq8065-xr500.dtb \
 +      qcom-ipq8068-ecw5410.dtb \
 +      qcom-ipq8068-mr42.dtb \
 +      qcom-ipq8068-mr52.dtb \
index ec1d0e5..08c0672 100644 (file)
@@ -204,7 +204,7 @@ Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
        host->use_ecc = true;
        clear_bam_transaction(nandc);
  
-@@ -2899,6 +2958,7 @@ static int qcom_nand_host_init_and_regis
+@@ -2912,6 +2971,7 @@ static int qcom_nand_host_init_and_regis
        struct nand_chip *chip = &host->chip;
        struct mtd_info *mtd = nand_to_mtd(chip);
        struct device *dev = nandc->dev;
@@ -212,7 +212,7 @@ Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
        int ret;
  
        ret = of_property_read_u32(dn, "reg", &host->cs);
-@@ -2960,6 +3020,17 @@ static int qcom_nand_host_init_and_regis
+@@ -2962,6 +3022,17 @@ static int qcom_nand_host_init_and_regis
        if (ret)
                nand_cleanup(chip);
  
@@ -230,7 +230,7 @@ Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
        return ret;
  }
  
-@@ -3125,6 +3196,7 @@ static int qcom_nandc_remove(struct plat
+@@ -3127,6 +3198,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,
index 506db69..fa2cd96 100644 (file)
@@ -1,6 +1,6 @@
 --- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi
 +++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi
-@@ -577,6 +577,7 @@
+@@ -558,6 +558,7 @@
                compatible = "mediatek,mt7622-nor",
                             "mediatek,mt8173-nor";
                reg = <0 0x11014000 0 0xe0>;
index 0c9e723..c313a45 100644 (file)
@@ -25,9 +25,9 @@ Link: https://lore.kernel.org/linux-mtd/20220127091808.1043392-6-miquel.raynal@b
 
 --- a/drivers/spi/spi-cadence-quadspi.c
 +++ b/drivers/spi/spi-cadence-quadspi.c
-@@ -1230,10 +1230,7 @@ static bool cqspi_supports_mem_op(struct
-       if (!(all_true || all_false))
+@@ -1249,10 +1249,7 @@ static bool cqspi_supports_mem_op(struct
                return false;
+       }
  
 -      if (all_true)
 -              return spi_mem_dtr_supports_op(mem, op);
diff --git a/target/linux/mediatek/patches-5.15/120-10-v5.18-mtd-nand-fix-ecc-parameters-for-mt7622.patch b/target/linux/mediatek/patches-5.15/120-10-v5.18-mtd-nand-fix-ecc-parameters-for-mt7622.patch
deleted file mode 100644 (file)
index e1c9493..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-From 41825166744c6e5664281611f5e6d9a2e9333c2b Mon Sep 17 00:00:00 2001
-From: Chuanhong Guo <gch981213@gmail.com>
-Date: Sat, 2 Apr 2022 22:31:20 +0800
-Subject: [PATCH 10/15] mtd: nand: fix ecc parameters for mt7622
-
-According to the datasheet, mt7622 only has 5 ECC capabilities instead
-of 7, and the decoding error register is arranged  as follows:
-+------+---------+---------+---------+---------+
-| Bits |  19:15  |  14:10  |   9:5   |   4:0   |
-+------+---------+---------+---------+---------+
-| Name | ERRNUM3 | ERRNUM2 | ERRNUM1 | ERRNUM0 |
-+------+---------+---------+---------+---------+
-This means err_mask should be 0x1f instead of 0x3f and the number of
-bits shifted in mtk_ecc_get_stats should be 5 instead of 8.
-
-This commit introduces err_shift for the difference in this register
-and fix other existing parameters.
-
-Public MT7622 reference manual can be found on [0] and the info this
-commit is based on is from page 656 and page 660.
-
-[0]: https://wiki.banana-pi.org/Banana_Pi_BPI-R64#Documents
-
-Fixes: 98dea8d71931 ("mtd: nand: mtk: Support MT7622 NAND flash controller.")
-Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
-(cherry picked from commit 088b769abd1bd21753002b17b696ae1778b16e8c)
----
- drivers/mtd/nand/raw/mtk_ecc.c | 12 ++++++++----
- 1 file changed, 8 insertions(+), 4 deletions(-)
-
---- a/drivers/mtd/nand/raw/mtk_ecc.c
-+++ b/drivers/mtd/nand/raw/mtk_ecc.c
-@@ -43,6 +43,7 @@
- struct mtk_ecc_caps {
-       u32 err_mask;
-+      u32 err_shift;
-       const u8 *ecc_strength;
-       const u32 *ecc_regs;
-       u8 num_ecc_strength;
-@@ -76,7 +77,7 @@ static const u8 ecc_strength_mt2712[] =
- };
- static const u8 ecc_strength_mt7622[] = {
--      4, 6, 8, 10, 12, 14, 16
-+      4, 6, 8, 10, 12
- };
- enum mtk_ecc_regs {
-@@ -221,7 +222,7 @@ void mtk_ecc_get_stats(struct mtk_ecc *e
-       for (i = 0; i < sectors; i++) {
-               offset = (i >> 2) << 2;
-               err = readl(ecc->regs + ECC_DECENUM0 + offset);
--              err = err >> ((i % 4) * 8);
-+              err = err >> ((i % 4) * ecc->caps->err_shift);
-               err &= ecc->caps->err_mask;
-               if (err == ecc->caps->err_mask) {
-                       /* uncorrectable errors */
-@@ -449,6 +450,7 @@ EXPORT_SYMBOL(mtk_ecc_get_parity_bits);
- static const struct mtk_ecc_caps mtk_ecc_caps_mt2701 = {
-       .err_mask = 0x3f,
-+      .err_shift = 8,
-       .ecc_strength = ecc_strength_mt2701,
-       .ecc_regs = mt2701_ecc_regs,
-       .num_ecc_strength = 20,
-@@ -459,6 +461,7 @@ static const struct mtk_ecc_caps mtk_ecc
- static const struct mtk_ecc_caps mtk_ecc_caps_mt2712 = {
-       .err_mask = 0x7f,
-+      .err_shift = 8,
-       .ecc_strength = ecc_strength_mt2712,
-       .ecc_regs = mt2712_ecc_regs,
-       .num_ecc_strength = 23,
-@@ -468,10 +471,11 @@ static const struct mtk_ecc_caps mtk_ecc
- };
- static const struct mtk_ecc_caps mtk_ecc_caps_mt7622 = {
--      .err_mask = 0x3f,
-+      .err_mask = 0x1f,
-+      .err_shift = 5,
-       .ecc_strength = ecc_strength_mt7622,
-       .ecc_regs = mt7622_ecc_regs,
--      .num_ecc_strength = 7,
-+      .num_ecc_strength = 5,
-       .ecc_mode_shift = 4,
-       .parity_bits = 13,
-       .pg_irq_sel = 0,
index f8100b2..905d84d 100644 (file)
@@ -112,7 +112,7 @@ Signed-off-by: Rui Salvaterra <rsalvaterra@gmail.com>
 
 --- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi
 +++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi
-@@ -940,6 +940,7 @@
+@@ -941,6 +941,7 @@
                clock-names = "hsdma";
                power-domains = <&scpsys MT7622_POWER_DOMAIN_ETHSYS>;
                #dma-cells = <1>;
index 0c9b6d9..cdcb8ee 100644 (file)
@@ -194,7 +194,7 @@ Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
  &pio {
 --- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi
 +++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi
-@@ -807,75 +807,83 @@
+@@ -808,75 +808,83 @@
                #reset-cells = <1>;
        };
  
index 4ac5685..0ecceec 100644 (file)
@@ -1,6 +1,6 @@
 --- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi
 +++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi
-@@ -847,6 +847,12 @@
+@@ -848,6 +848,12 @@
                        #address-cells = <0>;
                        #interrupt-cells = <1>;
                };
@@ -13,7 +13,7 @@
        };
  
        pcie1: pcie@1a145000 {
-@@ -885,6 +891,12 @@
+@@ -886,6 +892,12 @@
                        #address-cells = <0>;
                        #interrupt-cells = <1>;
                };
index 8a57745..47de683 100644 (file)
@@ -10,7 +10,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
 
 --- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi
 +++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi
-@@ -835,6 +835,9 @@
+@@ -836,6 +836,9 @@
                bus-range = <0x00 0xff>;
                ranges = <0x82000000 0 0x20000000 0x0 0x20000000 0 0x8000000>;
                status = "disabled";
@@ -20,7 +20,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
  
                #interrupt-cells = <1>;
                interrupt-map-mask = <0 0 0 7>;
-@@ -879,6 +882,9 @@
+@@ -880,6 +883,9 @@
                bus-range = <0x00 0xff>;
                ranges = <0x82000000 0 0x28000000 0x0 0x28000000 0 0x8000000>;
                status = "disabled";
diff --git a/target/linux/ramips/dts/mt7621_cudy_x6.dts b/target/linux/ramips/dts/mt7621_cudy_x6.dts
new file mode 100644 (file)
index 0000000..ebb2149
--- /dev/null
@@ -0,0 +1,178 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+
+#include "mt7621.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+       compatible = "cudy,x6", "mediatek,mt7621-soc";
+       model = "CUDY X6";
+
+       aliases {
+               led-boot = &led_internet_blue;
+               led-failsafe = &led_internet_blue;
+               led-running = &led_internet_blue;
+               led-upgrade = &led_internet_blue;
+               label-mac-device = &gmac0;
+       };
+
+       chosen {
+               bootargs = "console=ttyS0,115200";
+       };
+
+       keys {
+               compatible = "gpio-keys";
+
+               reset {
+                       label = "reset";
+                       gpios = <&gpio 8 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_RESTART>;
+               };
+
+               wps {
+                       label = "wps";
+                       gpios = <&gpio 7 GPIO_ACTIVE_LOW>;
+                       linux,code = <KEY_WPS_BUTTON>;
+               };
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               led_internet_blue: internet_blue {
+                       label = "blue:internet";
+                       gpios = <&gpio 15 GPIO_ACTIVE_LOW>;
+               };
+
+               internet_red {
+                       label = "red:internet";
+                       gpios = <&gpio 16 GPIO_ACTIVE_LOW>;
+               };
+       };
+
+};
+
+&spi0 {
+       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 = "u-boot";
+                               reg = <0x0 0x30000>;
+                               read-only;
+                       };
+
+                       partition@30000 {
+                               label = "u-boot-env";
+                               reg = <0x30000 0x10000>;
+                               read-only;
+                       };
+
+                       factory: partition@40000 {
+                               label = "factory";
+                               reg = <0x40000 0x10000>;
+                               read-only;
+                       };
+
+                       partition@50000 {
+                               compatible = "denx,uimage";
+                               label = "firmware";
+                               reg = <0x50000 0x1f80000>;
+                       };
+
+                       partition@1fd0000 {
+                               label = "debug";
+                               reg = <0x1fd0000 0x10000>;
+                               read-only;
+                       };
+
+                       partition@1fe0000 {
+                               label = "backup";
+                               reg = <0x1fe0000 0x10000>;
+                               read-only;
+                       };
+
+                       bdinfo: partition@1ff0000 {
+                               label = "bdinfo";
+                               reg = <0x1ff0000 0x10000>;
+                               read-only;
+                       };
+               };
+       };
+};
+
+&pcie {
+       status = "okay";
+};
+
+&pcie1 {
+       wifi@0,0 {
+               compatible = "mediatek,mt76";
+               reg = <0x0000 0 0 0 0>;
+               mediatek,mtd-eeprom = <&factory 0x0000>;
+       };
+};
+
+&gmac0 {
+       nvmem-cells = <&macaddr_bdinfo_de00>;
+       nvmem-cell-names = "mac-address";
+};
+
+&switch0 {
+       ports {
+               port@0 {
+                       status = "okay";
+                       label = "lan1";
+               };
+
+               port@1 {
+                       status = "okay";
+                       label = "lan2";
+               };
+
+               port@2 {
+                       status = "okay";
+                       label = "lan3";
+               };
+
+               port@3 {
+                       status = "okay";
+                       label = "lan4";
+               };
+
+               port@4 {
+                       status = "okay";
+                       label = "wan";
+                       nvmem-cells = <&macaddr_bdinfo_de00>;
+                       nvmem-cell-names = "mac-address";
+                       mac-address-increment = <1>;
+               };
+       };
+};
+
+&state_default {
+       gpio {
+               groups = "uart3", "jtag";
+               function = "gpio";
+       };
+};
+
+&bdinfo {
+       compatible = "nvmem-cells";
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       macaddr_bdinfo_de00: macaddr@de00 {
+               reg = <0xde00 0x6>;
+       };
+};
index 48f0fbd..b002b61 100644 (file)
        };
 };
 
+&i2c {
+       status = "okay";
+};
+
 &uart1 {
        status = "okay";
 };
index 575bda8..c2ae7e6 100644 (file)
@@ -319,6 +319,16 @@ define Device/cudy_wr2100
 endef
 TARGET_DEVICES += cudy_wr2100
 
+define Device/cudy_x6
+  $(Device/dsa-migration)
+  IMAGE_SIZE := 32256k
+  DEVICE_VENDOR := Cudy
+  DEVICE_MODEL := X6
+  UIMAGE_NAME := R13
+  DEVICE_PACKAGES := kmod-mt7915e
+endef
+TARGET_DEVICES += cudy_x6
+
 define Device/dlink_dir-8xx-a1
   $(Device/dsa-migration)
   IMAGE_SIZE := 16000k
index 6128518..a35e9dc 100644 (file)
@@ -16,6 +16,10 @@ case "$board" in
                [ "$PHYNBR" = "0" ] && echo -n $hw_mac_addr_ra0 > /sys${DEVPATH}/macaddress
                [ "$PHYNBR" = "1" ] && echo -n $hw_mac_addr_rax0 > /sys${DEVPATH}/macaddress
                ;;
+       cudy,x6)
+               hw_mac_addr="$(mtd_get_mac_binary factory 0x4)"
+               macaddr_add $hw_mac_addr "$PHYNBR" > /sys${DEVPATH}/macaddress
+               ;;
        dlink,dir-853-a3)
                [ "$PHYNBR" = "0" ] && \
                        macaddr_setbit_la "$(mtd_get_mac_binary factory 0xe000)" \
index 4a0262e..63c864f 100644 (file)
@@ -1,8 +1,8 @@
 --- a/drivers/net/ethernet/Kconfig
 +++ b/drivers/net/ethernet/Kconfig
-@@ -162,6 +162,7 @@ source "drivers/net/ethernet/pasemi/Kcon
- source "drivers/net/ethernet/pensando/Kconfig"
+@@ -162,6 +162,7 @@ source "drivers/net/ethernet/pensando/Kc
  source "drivers/net/ethernet/qlogic/Kconfig"
+ source "drivers/net/ethernet/brocade/Kconfig"
  source "drivers/net/ethernet/qualcomm/Kconfig"
 +source "drivers/net/ethernet/ralink/Kconfig"
  source "drivers/net/ethernet/rdc/Kconfig"
diff --git a/target/linux/realtek/dts-5.10/rtl8382_zyxel_gs1900-16.dts b/target/linux/realtek/dts-5.10/rtl8382_zyxel_gs1900-16.dts
new file mode 100644 (file)
index 0000000..ac2eea7
--- /dev/null
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "rtl8380_zyxel_gs1900.dtsi"
+
+/ {
+       compatible = "zyxel,gs1900-16", "realtek,rtl838x-soc";
+       model = "ZyXEL GS1900-16";
+};
+
+&mdio {
+       EXTERNAL_PHY(16)
+       EXTERNAL_PHY(17)
+       EXTERNAL_PHY(18)
+       EXTERNAL_PHY(19)
+       EXTERNAL_PHY(20)
+       EXTERNAL_PHY(21)
+       EXTERNAL_PHY(22)
+       EXTERNAL_PHY(23)
+};
+
+&switch0 {
+       ports {
+               SWITCH_PORT(16, 9, qsgmii)
+               SWITCH_PORT(17, 10, qsgmii)
+               SWITCH_PORT(18, 11, qsgmii)
+               SWITCH_PORT(19, 12, qsgmii)
+               SWITCH_PORT(20, 13, qsgmii)
+               SWITCH_PORT(21, 14, qsgmii)
+               SWITCH_PORT(22, 15, qsgmii)
+               SWITCH_PORT(23, 16, qsgmii)
+       };
+};
+
+&gpio1 {
+       /delete-node/ poe_enable;
+};
index 4780632..2e3ab4a 100644 (file)
@@ -205,6 +205,15 @@ static int rtl83xx_setup(struct dsa_switch *ds)
 
        priv->r->l2_learning_setup();
 
+       /*
+        *  Make sure all frames sent to the switch's MAC are trapped to the CPU-port
+        *  0: FWD, 1: DROP, 2: TRAP2CPU
+        */
+       if (priv->family_id == RTL8380_FAMILY_ID)
+               sw_w32(0x2, RTL838X_SPCL_TRAP_SWITCH_MAC_CTRL);
+       else
+               sw_w32(0x2, RTL839X_SPCL_TRAP_SWITCH_MAC_CTRL);
+
        /* Enable MAC Polling PHY again */
        rtl83xx_enable_phy_polling(priv);
        pr_debug("Please wait until PHY is settled\n");
index 29e7ff2..e17dc8c 100644 (file)
@@ -111,6 +111,14 @@ define Device/zyxel_gs1900-10hp
 endef
 TARGET_DEVICES += zyxel_gs1900-10hp
 
+define Device/zyxel_gs1900-16
+  $(Device/zyxel_gs1900)
+  SOC := rtl8382
+  DEVICE_MODEL := GS1900-16
+  ZYXEL_VERS := AAHJ
+endef
+TARGET_DEVICES += zyxel_gs1900-16
+
 define Device/zyxel_gs1900-8
   $(Device/zyxel_gs1900)
   DEVICE_MODEL := GS1900-8
index fcf8dfc..28cb276 100644 (file)
@@ -35,6 +35,22 @@ endef
 $(eval $(call KernelPackage,amd-xgbe))
 
 
+define KernelPackage/f71808e-wdt
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=Fintek F718xx/F818xx Watchdog Timer
+  DEPENDS:=@TARGET_x86
+  KCONFIG:=CONFIG_F71808E_WDT
+  FILES:=$(LINUX_DIR)/drivers/watchdog/f71808e_wdt.ko
+  AUTOLOAD:=$(call AutoProbe,f71808e-wdt,1)
+endef
+
+define KernelPackage/f71808e-wdt/description
+  Kernel module for the watchdog timer found on many Fintek Super-IO chips.
+endef
+
+$(eval $(call KernelPackage,f71808e-wdt))
+
+
 define KernelPackage/sound-cs5535audio
   TITLE:=CS5535/CS5536 Audio Controller
   DEPENDS:=@TARGET_x86_geode +kmod-ac97
@@ -67,6 +83,60 @@ endef
 $(eval $(call KernelPackage,sp5100-tco))
 
 
+define KernelPackage/ib700-wdt
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=IB700 SBC Watchdog Timer
+  DEPENDS:=@TARGET_x86
+  KCONFIG:=CONFIG_IB700_WDT
+  FILES:=$(LINUX_DIR)/drivers/watchdog/ib700wdt.ko
+  AUTOLOAD:=$(call AutoLoad,50,ib700wdt,1)
+endef
+
+define KernelPackage/ib700-wdt/description
+  Kernel module for the hardware watchdog on the IB700 Single
+  Board Computer produced by TMC Technology (www.tmc-uk.com).
+  Also used by QEMU/libvirt.
+endef
+
+$(eval $(call KernelPackage,ib700-wdt))
+
+define KernelPackage/it87-wdt
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=ITE IT87 Watchdog Timer
+  DEPENDS:=@TARGET_x86
+  KCONFIG:=CONFIG_IT87_WDT
+  FILES:=$(LINUX_DIR)/drivers/watchdog/it87_wdt.ko
+  AUTOLOAD:=$(call AutoLoad,50,it87-wdt,1)
+  MODPARAMS.it87-wdt:= \
+       nogameport=1 \
+       nocir=1
+endef
+
+define KernelPackage/it87-wdt/description
+  Kernel module for ITE IT87 Watchdog Timer
+endef
+
+$(eval $(call KernelPackage,it87-wdt))
+
+
+define KernelPackage/itco-wdt
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=Intel iTCO Watchdog Timer
+  DEPENDS:=@TARGET_x86
+  KCONFIG:=CONFIG_ITCO_WDT \
+           CONFIG_ITCO_VENDOR_SUPPORT=y
+  FILES:=$(LINUX_DIR)/drivers/watchdog/iTCO_wdt.ko \
+         $(LINUX_DIR)/drivers/watchdog/iTCO_vendor_support.ko
+  AUTOLOAD:=$(call AutoLoad,50,iTCO_vendor_support iTCO_wdt,1)
+endef
+
+define KernelPackage/itco-wdt/description
+  Kernel module for Intel iTCO Watchdog Timer
+endef
+
+$(eval $(call KernelPackage,itco-wdt))
+
+
 define KernelPackage/pcengines-apuv2
   SUBMENU:=$(OTHER_MENU)
   TITLE:=PC Engines APUv2/3 front button and LEDs driver
@@ -88,7 +158,8 @@ define KernelPackage/meraki-mx100
   SUBMENU:=$(OTHER_MENU)
   TITLE:=Cisco Meraki MX100 Platform Driver
   DEPENDS:=@TARGET_x86 +kmod-tg3 +kmod-gpio-button-hotplug +kmod-leds-gpio \
-    +kmod-usb-ledtrig-usbport +nu801 +kmod-itco-wdt +kmod-leds-uleds
+    +kmod-usb-ledtrig-usbport +PACKAGE_kmod-meraki-mx100:nu801 +kmod-itco-wdt \
+    +kmod-leds-uleds
   KCONFIG:=CONFIG_MERAKI_MX100
   FILES:=$(LINUX_DIR)/drivers/platform/x86/meraki-mx100.ko
   AUTOLOAD:=$(call AutoLoad,60,meraki-mx100,1)
@@ -102,3 +173,18 @@ define KernelPackage/meraki-mx100/description
 endef
 
 $(eval $(call KernelPackage,meraki-mx100))
+
+define KernelPackage/w83627hf-wdt
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=Winbond 83627HF Watchdog Timer
+  DEPENDS:=@TARGET_x86
+  KCONFIG:=CONFIG_W83627HF_WDT
+  FILES:=$(LINUX_DIR)/drivers/watchdog/w83627hf_wdt.ko
+  AUTOLOAD:=$(call AutoLoad,50,w83627hf-wdt,1)
+endef
+
+define KernelPackage/w83627hf-wdt/description
+  Kernel module for Winbond 83627HF Watchdog Timer
+endef
+
+$(eval $(call KernelPackage,w83627hf-wdt))