[rdkb][common][bsp][Refactor and sync kernel from openwrt]

[Description]
30651f4f [kernel][common][eth][Refactor polling idle condition of the GDM/MAC FSM]
83ecb7ca [MAC80211][hnat][Correct maximum rate limit for the PPPQ]
f0e27f7c [HIGH][kernel][common][eth][Update Airoha AN8801SB 1G PHY driver from v1.1.0 to v1.1.3]
d024fef4 [kernel][mt7988][eth][Fix ADMAv2 Tx hang and low throughput issues]
40086c25 [HIGH][kernel][common][eth][Refactor the link down recovery handler for out-of-band devices used with USXGMII/SGMII]
506042e0 [kernel][common][eth][Add phylink pcs_enable and pcs_disable methods]
1219ad6b [HIGH][kernel][mt7988][eth][Fix software padding processing in Ethernet Tx path]
a7c93592 [kernel][common][hnat][Fix Issue of nf_conntrack statistics missing after read all_entry]
7d04444b [openwrt][mt7988][hnat][Change header guard in hnat.h]
01555ca6 [HIGH][kernel][common][eth][Fix HQoS is not functioning properly following the SER issue]
a4163a16 [kernel][mt7988][lvts][Add multiple thermal zones support]
34d82c33 [kernel][common][eth][Add individual polarity control to the SGMII]
6831cde2 [openwrt][mt7988][hnat][Add header guard in hnat.h]
701fc2e7 [[kernel][mt7988][eth][add SER path from wifi to eth]]
48284e92 [openwrt][mt7988][tops][refactor tops-tool and add logger suuport]
69ddea16 [kernel][common][eth][Refactor polling idle condition of the GDM/MAC FSM]
05f3c827 [openwrt][mt7988][app][Add utility for configuring Mxl series ethernet switchs]
19d8db9f [kernel][mt7988][eth][Add support for the permanent MAC address of the ethtool]
11095c23 [CRITICAL][kernel][common][eth][Add automatic firmware selection for Aquantia PHY]

[Release-log]

Change-Id: I4417986b3a2c0dd1d8e62846abc345464bbaffbc
diff --git a/recipes-bsp/marvell-eth-firmware/files/AQR-G4_v5.7.0-AQR_EVB_Generic_X3410_StdCfg_MDISwap_USX_ID46316_VER2140.cld b/recipes-bsp/marvell-eth-firmware/files/AQR-G4_v5.7.0-AQR_EVB_Generic_X3410_StdCfg_MDISwap_USX_ID46316_VER2148.cld
similarity index 99%
rename from recipes-bsp/marvell-eth-firmware/files/AQR-G4_v5.7.0-AQR_EVB_Generic_X3410_StdCfg_MDISwap_USX_ID46316_VER2140.cld
rename to recipes-bsp/marvell-eth-firmware/files/AQR-G4_v5.7.0-AQR_EVB_Generic_X3410_StdCfg_MDISwap_USX_ID46316_VER2148.cld
index 1baac15..c856456 100644
--- a/recipes-bsp/marvell-eth-firmware/files/AQR-G4_v5.7.0-AQR_EVB_Generic_X3410_StdCfg_MDISwap_USX_ID46316_VER2140.cld
+++ b/recipes-bsp/marvell-eth-firmware/files/AQR-G4_v5.7.0-AQR_EVB_Generic_X3410_StdCfg_MDISwap_USX_ID46316_VER2148.cld
Binary files differ
diff --git a/recipes-bsp/marvell-eth-firmware/marvell-eth-firmware.bb b/recipes-bsp/marvell-eth-firmware/marvell-eth-firmware.bb
index 68919fe..b1ad94d 100644
--- a/recipes-bsp/marvell-eth-firmware/marvell-eth-firmware.bb
+++ b/recipes-bsp/marvell-eth-firmware/marvell-eth-firmware.bb
@@ -6,7 +6,7 @@
 SRC_URI = " \
     file://Rhe-05.06-Candidate7-AQR_Mediatek_23B_StartOff_ID45623_VER36657.cld \
     file://Rhe-05.06-Candidate9-AQR_Mediatek_23B_P5_ID45824_LCLVER1.cld\
-    file://AQR-G4_v5.7.0-AQR_EVB_Generic_X3410_StdCfg_MDISwap_USX_ID46316_VER2140.cld \
+    file://AQR-G4_v5.7.0-AQR_EVB_Generic_X3410_StdCfg_MDISwap_USX_ID46316_VER2148.cld \
 "
 
 S = "${WORKDIR}"
@@ -17,7 +17,7 @@
     install -d ${D}/${base_libdir}/firmware/
     install -m 644 ${WORKDIR}/Rhe-05.06-Candidate9-AQR_Mediatek_23B_P5_ID45824_LCLVER1.cld ${D}${base_libdir}/firmware/
     install -m 644 ${WORKDIR}/Rhe-05.06-Candidate7-AQR_Mediatek_23B_StartOff_ID45623_VER36657.cld ${D}${base_libdir}/firmware/
-    install -m 644 ${WORKDIR}/AQR-G4_v5.7.0-AQR_EVB_Generic_X3410_StdCfg_MDISwap_USX_ID46316_VER2140.cld  ${D}${base_libdir}/firmware/
+    install -m 644 ${WORKDIR}/AQR-G4_v5.7.0-AQR_EVB_Generic_X3410_StdCfg_MDISwap_USX_ID46316_VER2148.cld  ${D}${base_libdir}/firmware/
 }
 
 FILES_${PN} += "${base_libdir}/firmware/"
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988.dtsi b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988.dtsi
index 9abe45f..f38b2b7 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988.dtsi
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988.dtsi
@@ -133,7 +133,7 @@
 	};
 
 	thermal-zones {
-		cpu_thermal: cpu-thermal {
+		thermal_zone0: soc_thermal {
 			polling-delay-passive = <1000>;
 			polling-delay = <1000>;
 			thermal-sensors = <&lvts 0>;
@@ -178,6 +178,54 @@
 			};
 
 		};
+
+		thermal_zone1: mcusys_thermal0 {
+			polling-delay-passive = <1000>;
+			polling-delay = <1000>;
+			thermal-sensors = <&lvts 1>;
+		};
+
+		thermal_zone2: mcusys_thermal1 {
+			polling-delay-passive = <1000>;
+			polling-delay = <1000>;
+			thermal-sensors = <&lvts 2>;
+		};
+
+		thermal_zone3: eth2p5g_thermal0 {
+			polling-delay-passive = <1000>;
+			polling-delay = <1000>;
+			thermal-sensors = <&lvts 3>;
+		};
+
+		thermal_zone4: eth2p5g_thermal1 {
+			polling-delay-passive = <1000>;
+			polling-delay = <1000>;
+			thermal-sensors = <&lvts 4>;
+		};
+
+		thermal_zone5: tops_thermal0 {
+			polling-delay-passive = <1000>;
+			polling-delay = <1000>;
+			thermal-sensors = <&lvts 5>;
+		};
+
+		thermal_zone6: tops_thermal1 {
+			polling-delay-passive = <1000>;
+			polling-delay = <1000>;
+			thermal-sensors = <&lvts 6>;
+		};
+
+		thermal_zone7: ethsys_thermal0 {
+			polling-delay-passive = <1000>;
+			polling-delay = <1000>;
+			thermal-sensors = <&lvts 7>;
+		};
+
+		thermal_zone8: ethsys_thermal1 {
+			polling-delay-passive = <1000>;
+			polling-delay = <1000>;
+			thermal-sensors = <&lvts 8>;
+		};
 	};
 
 	mmc0: mmc@11230000 {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-88d-10g-spim-nand.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-88d-10g-spim-nand.dts
index 8ebcbaf..c558535 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-88d-10g-spim-nand.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-88d-10g-spim-nand.dts
@@ -416,6 +416,7 @@
 	gmac0: mac@0 {
 		compatible = "mediatek,eth-mac";
 		reg = <0>;
+		mtd-mac-address = <&factory 0xFFFF4>;
 		mac-type = "xgdm";
 		phy-mode = "10gbase-kr";
 
@@ -429,6 +430,7 @@
 	gmac1: mac@1 {
 		compatible = "mediatek,eth-mac";
 		reg = <1>;
+		mtd-mac-address = <&factory 0xFFFFA>;
 		mac-type = "xgdm";
 		phy-mode = "usxgmii";
 		phy-handle = <&phy0>;
@@ -437,6 +439,7 @@
 	gmac2: mac@2 {
 		compatible = "mediatek,eth-mac";
 		reg = <2>;
+		mtd-mac-address = <&factory 0xFFFEE>;
 		mac-type = "xgdm";
 		phy-mode = "usxgmii";
 		phy-handle = <&phy1>;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-sfp-spim-nand.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-sfp-spim-nand.dts
index 54e2cf0..8fbe9c5 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-sfp-spim-nand.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-sfp-spim-nand.dts
@@ -352,6 +352,7 @@
 	gmac0: mac@0 {
 		compatible = "mediatek,eth-mac";
 		reg = <0>;
+		mtd-mac-address = <&factory 0xFFFF4>;
 		mac-type = "xgdm";
 		phy-mode = "10gbase-kr";
 
@@ -365,6 +366,7 @@
 	gmac1: mac@1 {
 		compatible = "mediatek,eth-mac";
 		reg = <1>;
+		mtd-mac-address = <&factory 0xFFFFA>;
 		mac-type = "xgdm";
 		phy-mode = "10gbase-kr";
 		managed = "in-band-status";
@@ -374,6 +376,7 @@
 	gmac2: mac@2 {
 		compatible = "mediatek,eth-mac";
 		reg = <2>;
+		mtd-mac-address = <&factory 0xFFFEE>;
 		mac-type = "xgdm";
 		phy-mode = "10gbase-kr";
 		managed = "in-band-status";
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-snfi-nand.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-snfi-nand.dts
index 7881834..cde918b 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-snfi-nand.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-snfi-nand.dts
@@ -287,6 +287,7 @@
 	gmac0: mac@0 {
 		compatible = "mediatek,eth-mac";
 		reg = <0>;
+		mtd-mac-address = <&factory 0xFFFF4>;
 		mac-type = "xgdm";
 		phy-mode = "10gbase-kr";
 
@@ -300,6 +301,7 @@
 	gmac1: mac@1 {
 		compatible = "mediatek,eth-mac";
 		reg = <1>;
+		mtd-mac-address = <&factory 0xFFFFA>;
 		mac-type = "xgdm";
 		phy-mode = "usxgmii";
 		phy-handle = <&phy0>;
@@ -308,6 +310,7 @@
 	gmac2: mac@2 {
 		compatible = "mediatek,eth-mac";
 		reg = <2>;
+		mtd-mac-address = <&factory 0xFFFEE>;
 		mac-type = "xgdm";
 		phy-mode = "usxgmii";
 		phy-handle = <&phy1>;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nand-CASAN.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nand-CASAN.dts
index 2404a40..834eb41 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nand-CASAN.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nand-CASAN.dts
@@ -411,6 +411,7 @@
 	gmac0: mac@0 {
 		compatible = "mediatek,eth-mac";
 		reg = <0>;
+		mtd-mac-address = <&factory 0xFFFF4>;
 		mac-type = "xgdm";
 		phy-mode = "10gbase-kr";
 
@@ -424,6 +425,7 @@
 	gmac1: mac@1 {
 		compatible = "mediatek,eth-mac";
 		reg = <1>;
+		mtd-mac-address = <&factory 0xFFFFA>;
 		mac-type = "xgdm";
 		phy-mode = "usxgmii";
 		phy-handle = <&phy0>;
@@ -432,6 +434,7 @@
 	gmac2: mac@2 {
 		compatible = "mediatek,eth-mac";
 		reg = <2>;
+		mtd-mac-address = <&factory 0xFFFEE>;
 		mac-type = "xgdm";
 		phy-mode = "usxgmii";
 		phy-handle = <&phy1>;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nand.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nand.dts
index 2624584..224583a 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nand.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nand.dts
@@ -411,6 +411,7 @@
 	gmac0: mac@0 {
 		compatible = "mediatek,eth-mac";
 		reg = <0>;
+		mtd-mac-address = <&factory 0xFFFF4>;
 		mac-type = "xgdm";
 		phy-mode = "10gbase-kr";
 
@@ -424,6 +425,7 @@
 	gmac1: mac@1 {
 		compatible = "mediatek,eth-mac";
 		reg = <1>;
+		mtd-mac-address = <&factory 0xFFFFA>;
 		mac-type = "xgdm";
 		phy-mode = "usxgmii";
 		phy-handle = <&phy0>;
@@ -432,6 +434,7 @@
 	gmac2: mac@2 {
 		compatible = "mediatek,eth-mac";
 		reg = <2>;
+		mtd-mac-address = <&factory 0xFFFEE>;
 		mac-type = "xgdm";
 		phy-mode = "usxgmii";
 		phy-handle = <&phy1>;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nor.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nor.dts
index 2fa9f5d..24c7799 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nor.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nor.dts
@@ -279,6 +279,7 @@
 	gmac0: mac@0 {
 		compatible = "mediatek,eth-mac";
 		reg = <0>;
+		mtd-mac-address = <&factory 0xFFFF4>;
 		mac-type = "xgdm";
 		phy-mode = "10gbase-kr";
 
@@ -292,6 +293,7 @@
 	gmac1: mac@1 {
 		compatible = "mediatek,eth-mac";
 		reg = <1>;
+		mtd-mac-address = <&factory 0xFFFFA>;
 		mac-type = "xgdm";
 		phy-mode = "usxgmii";
 		phy-handle = <&phy0>;
@@ -300,6 +302,7 @@
 	gmac2: mac@2 {
 		compatible = "mediatek,eth-mac";
 		reg = <2>;
+		mtd-mac-address = <&factory 0xFFFEE>;
 		mac-type = "xgdm";
 		phy-mode = "usxgmii";
 		phy-handle = <&phy1>;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-e2p5g-spim-nand.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-e2p5g-spim-nand.dts
index dc27135..4562413 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-e2p5g-spim-nand.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-e2p5g-spim-nand.dts
@@ -321,6 +321,7 @@
 	gmac0: mac@0 {
 		compatible = "mediatek,eth-mac";
 		reg = <0>;
+		mtd-mac-address = <&factory 0xFFFF4>;
 		mac-type = "xgdm";
 		phy-mode = "10gbase-kr";
 
@@ -334,6 +335,7 @@
 	gmac1: mac@1 {
 		compatible = "mediatek,eth-mac";
 		reg = <1>;
+		mtd-mac-address = <&factory 0xFFFFA>;
 		mac-type = "gdm";
 		phy-mode = "2500base-x";
 		phy-handle = <&phy13>;
@@ -342,6 +344,7 @@
 	gmac2: mac@2 {
 		compatible = "mediatek,eth-mac";
 		reg = <2>;
+		mtd-mac-address = <&factory 0xFFFEE>;
 		mac-type = "gdm";
 		phy-mode = "2500base-x";
 		phy-handle = <&phy5>;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-i2p5g-spim-nand.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-i2p5g-spim-nand.dts
index e88bc4f..2803b7b 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-i2p5g-spim-nand.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-i2p5g-spim-nand.dts
@@ -284,6 +284,7 @@
 	gmac0: mac@0 {
 		compatible = "mediatek,eth-mac";
 		reg = <0>;
+		mtd-mac-address = <&factory 0xFFFF4>;
 		mac-type = "xgdm";
 		phy-mode = "10gbase-kr";
 
@@ -297,6 +298,7 @@
 	gmac1: mac@1 {
 		compatible = "mediatek,eth-mac";
 		reg = <1>;
+		mtd-mac-address = <&factory 0xFFFFA>;
 		mac-type = "xgdm";
 		phy-mode = "xgmii";
 		phy-handle = <&phy0>;
@@ -305,6 +307,7 @@
 	gmac2: mac@2 {
 		compatible = "mediatek,eth-mac";
 		reg = <2>;
+		mtd-mac-address = <&factory 0xFFFEE>;
 		mac-type = "xgdm";
 		phy-mode = "usxgmii";
 		phy-handle = <&phy1>;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-gsw-10g-sfp-spim-nand.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-gsw-10g-sfp-spim-nand.dts
index d6da110..a922d57 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-gsw-10g-sfp-spim-nand.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-gsw-10g-sfp-spim-nand.dts
@@ -336,6 +336,7 @@
 	gmac0: mac@0 {
 		compatible = "mediatek,eth-mac";
 		reg = <0>;
+		mtd-mac-address = <&factory 0xFFFF4>;
 		mac-type = "xgdm";
 		phy-mode = "10gbase-kr";
 
@@ -349,6 +350,7 @@
 	gmac1: mac@1 {
 		compatible = "mediatek,eth-mac";
 		reg = <1>;
+		mtd-mac-address = <&factory 0xFFFFA>;
 		mac-type = "xgdm";
 		phy-mode = "10gbase-kr";
 		managed = "in-band-status";
@@ -358,6 +360,7 @@
 	gmac2: mac@2 {
 		compatible = "mediatek,eth-mac";
 		reg = <2>;
+		mtd-mac-address = <&factory 0xFFFEE>;
 		mac-type = "xgdm";
 		phy-mode = "10gbase-kr";
 		managed = "in-band-status";
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-gsw-10g-spim-nand-4pcie.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-gsw-10g-spim-nand-4pcie.dts
index daac5d7..4ee16fd 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-gsw-10g-spim-nand-4pcie.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-gsw-10g-spim-nand-4pcie.dts
@@ -324,6 +324,7 @@
 	gmac0: mac@0 {
 		compatible = "mediatek,eth-mac";
 		reg = <0>;
+		mtd-mac-address = <&factory 0xFFFF4>;
 		mac-type = "xgdm";
 		phy-mode = "10gbase-kr";
 
@@ -337,6 +338,7 @@
 	gmac1: mac@1 {
 		compatible = "mediatek,eth-mac";
 		reg = <1>;
+		mtd-mac-address = <&factory 0xFFFFA>;
 		mac-type = "xgdm";
 		phy-mode = "usxgmii";
 		phy-handle = <&phy0>;
@@ -345,6 +347,7 @@
 	gmac2: mac@2 {
 		compatible = "mediatek,eth-mac";
 		reg = <2>;
+		mtd-mac-address = <&factory 0xFFFEE>;
 		mac-type = "xgdm";
 		phy-mode = "usxgmii";
 		phy-handle = <&phy1>;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-gsw-10g-spim-nand.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-gsw-10g-spim-nand.dts
index 5ea962f..b084812 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-gsw-10g-spim-nand.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-gsw-10g-spim-nand.dts
@@ -356,6 +356,7 @@
 	gmac0: mac@0 {
 		compatible = "mediatek,eth-mac";
 		reg = <0>;
+		mtd-mac-address = <&factory 0xFFFF4>;
 		mac-type = "xgdm";
 		phy-mode = "10gbase-kr";
 
@@ -369,6 +370,7 @@
 	gmac1: mac@1 {
 		compatible = "mediatek,eth-mac";
 		reg = <1>;
+		mtd-mac-address = <&factory 0xFFFFA>;
 		mac-type = "xgdm";
 		phy-mode = "usxgmii";
 		phy-handle = <&phy0>;
@@ -377,6 +379,7 @@
 	gmac2: mac@2 {
 		compatible = "mediatek,eth-mac";
 		reg = <2>;
+		mtd-mac-address = <&factory 0xFFFEE>;
 		mac-type = "xgdm";
 		phy-mode = "usxgmii";
 		phy-handle = <&phy1>;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-sfp-spim-nand.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-sfp-spim-nand.dts
index a6f3257..356ff3a 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-sfp-spim-nand.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-sfp-spim-nand.dts
@@ -335,6 +335,7 @@
 	gmac0: mac@0 {
 		compatible = "mediatek,eth-mac";
 		reg = <0>;
+		mtd-mac-address = <&factory 0xFFFF4>;
 		mac-type = "xgdm";
 		phy-mode = "10gbase-kr";
 
@@ -348,6 +349,7 @@
 	gmac1: mac@1 {
 		compatible = "mediatek,eth-mac";
 		reg = <1>;
+		mtd-mac-address = <&factory 0xFFFFA>;
 		mac-type = "xgdm";
 		phy-mode = "xgmii";
 		phy-handle = <&phy0>;
@@ -356,6 +358,7 @@
 	gmac2: mac@2 {
 		compatible = "mediatek,eth-mac";
 		reg = <2>;
+		mtd-mac-address = <&factory 0xFFFEE>;
 		mac-type = "xgdm";
 		phy-mode = "10gbase-kr";
 		managed = "in-band-status";
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-snfi-nand.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-snfi-nand.dts
index f3cee2b..bd4326f 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-snfi-nand.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-snfi-nand.dts
@@ -298,6 +298,7 @@
 	gmac0: mac@0 {
 		compatible = "mediatek,eth-mac";
 		reg = <0>;
+		mtd-mac-address = <&factory 0xFFFF4>;
 		mac-type = "xgdm";
 		phy-mode = "10gbase-kr";
 
@@ -311,6 +312,7 @@
 	gmac1: mac@1 {
 		compatible = "mediatek,eth-mac";
 		reg = <1>;
+		mtd-mac-address = <&factory 0xFFFFA>;
 		mac-type = "xgdm";
 		phy-mode = "xgmii";
 		phy-handle = <&phy0>;
@@ -319,6 +321,7 @@
 	gmac2: mac@2 {
 		compatible = "mediatek,eth-mac";
 		reg = <2>;
+		mtd-mac-address = <&factory 0xFFFEE>;
 		mac-type = "xgdm";
 		phy-mode = "usxgmii";
 		phy-handle = <&phy1>;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nand-CASAN.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nand-CASAN.dts
index e4b03bf..42efe94 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nand-CASAN.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nand-CASAN.dts
@@ -392,6 +392,7 @@
 	gmac0: mac@0 {
 		compatible = "mediatek,eth-mac";
 		reg = <0>;
+		mtd-mac-address = <&factory 0xFFFF4>;
 		mac-type = "xgdm";
 		phy-mode = "10gbase-kr";
 
@@ -405,6 +406,7 @@
 	gmac1: mac@1 {
 		compatible = "mediatek,eth-mac";
 		reg = <1>;
+		mtd-mac-address = <&factory 0xFFFFA>;
 		mac-type = "xgdm";
 		phy-mode = "xgmii";
 		phy-handle = <&phy0>;
@@ -413,6 +415,7 @@
 	gmac2: mac@2 {
 		compatible = "mediatek,eth-mac";
 		reg = <2>;
+		mtd-mac-address = <&factory 0xFFFEE>;
 		mac-type = "xgdm";
 		phy-mode = "usxgmii";
 		phy-handle = <&phy1>;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nand.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nand.dts
index d4f96c8..3e2c564 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nand.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nand.dts
@@ -392,6 +392,7 @@
 	gmac0: mac@0 {
 		compatible = "mediatek,eth-mac";
 		reg = <0>;
+		mtd-mac-address = <&factory 0xFFFF4>;
 		mac-type = "xgdm";
 		phy-mode = "10gbase-kr";
 
@@ -405,6 +406,7 @@
 	gmac1: mac@1 {
 		compatible = "mediatek,eth-mac";
 		reg = <1>;
+		mtd-mac-address = <&factory 0xFFFFA>;
 		mac-type = "xgdm";
 		phy-mode = "xgmii";
 		phy-handle = <&phy0>;
@@ -413,6 +415,7 @@
 	gmac2: mac@2 {
 		compatible = "mediatek,eth-mac";
 		reg = <2>;
+		mtd-mac-address = <&factory 0xFFFEE>;
 		mac-type = "xgdm";
 		phy-mode = "usxgmii";
 		phy-handle = <&phy1>;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nor.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nor.dts
index be66a65..f72c5d3 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nor.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nor.dts
@@ -290,6 +290,7 @@
 	gmac0: mac@0 {
 		compatible = "mediatek,eth-mac";
 		reg = <0>;
+		mtd-mac-address = <&factory 0xFFFF4>;
 		mac-type = "xgdm";
 		phy-mode = "10gbase-kr";
 
@@ -303,6 +304,7 @@
 	gmac1: mac@1 {
 		compatible = "mediatek,eth-mac";
 		reg = <1>;
+		mtd-mac-address = <&factory 0xFFFFA>;
 		mac-type = "xgdm";
 		phy-mode = "xgmii";
 		phy-handle = <&phy0>;
@@ -311,6 +313,7 @@
 	gmac2: mac@2 {
 		compatible = "mediatek,eth-mac";
 		reg = <2>;
+		mtd-mac-address = <&factory 0xFFFEE>;
 		mac-type = "xgdm";
 		phy-mode = "usxgmii";
 		phy-handle = <&phy1>;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-wan-spim-nand.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-wan-spim-nand.dts
index a3bde2e..7a3d9a6 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-wan-spim-nand.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-wan-spim-nand.dts
@@ -392,6 +392,7 @@
 	gmac0: mac@0 {
 		compatible = "mediatek,eth-mac";
 		reg = <0>;
+		mtd-mac-address = <&factory 0xFFFF4>;
 		mac-type = "xgdm";
 		phy-mode = "10gbase-kr";
 
@@ -405,6 +406,7 @@
 	gmac1: mac@1 {
 		compatible = "mediatek,eth-mac";
 		reg = <1>;
+		mtd-mac-address = <&factory 0xFFFFA>;
 		mac-type = "xgdm";
 		phy-mode = "xgmii";
 		phy-handle = <&phy0>;
@@ -413,6 +415,7 @@
 	gmac2: mac@2 {
 		compatible = "mediatek,eth-mac";
 		reg = <2>;
+		mtd-mac-address = <&factory 0xFFFEE>;
 		mac-type = "xgdm";
 		phy-mode = "usxgmii";
 		phy-handle = <&phy1>;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-e2p5g-spim-nand.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-e2p5g-spim-nand.dts
index 7fdec3f..78847ef 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-e2p5g-spim-nand.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-e2p5g-spim-nand.dts
@@ -310,6 +310,7 @@
 	gmac0: mac@0 {
 		compatible = "mediatek,eth-mac";
 		reg = <0>;
+		mtd-mac-address = <&factory 0xFFFF4>;
 		mac-type = "xgdm";
 		phy-mode = "10gbase-kr";
 
@@ -323,6 +324,7 @@
 	gmac1: mac@1 {
 		compatible = "mediatek,eth-mac";
 		reg = <1>;
+		mtd-mac-address = <&factory 0xFFFFA>;
 		mac-type = "xgdm";
 		phy-mode = "xgmii";
 		phy-handle = <&phy0>;
@@ -331,6 +333,7 @@
 	gmac2: mac@2 {
 		compatible = "mediatek,eth-mac";
 		reg = <2>;
+		mtd-mac-address = <&factory 0xFFFEE>;
 		mac-type = "gdm";
 		phy-mode = "2500base-x";
 		phy-handle = <&phy5>;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-gsw-10g-sfp-spim-nand.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-gsw-10g-sfp-spim-nand.dts
index 2ed715c..18bbfcc 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-gsw-10g-sfp-spim-nand.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-gsw-10g-sfp-spim-nand.dts
@@ -324,6 +324,7 @@
 	gmac0: mac@0 {
 		compatible = "mediatek,eth-mac";
 		reg = <0>;
+		mtd-mac-address = <&factory 0xFFFF4>;
 		mac-type = "xgdm";
 		phy-mode = "10gbase-kr";
 
@@ -337,6 +338,7 @@
 	gmac1: mac@1 {
 		compatible = "mediatek,eth-mac";
 		reg = <1>;
+		mtd-mac-address = <&factory 0xFFFFA>;
 		mac-type = "xgdm";
 		phy-mode = "xgmii";
 		phy-handle = <&phy0>;
@@ -345,6 +347,7 @@
 	gmac2: mac@2 {
 		compatible = "mediatek,eth-mac";
 		reg = <2>;
+		mtd-mac-address = <&factory 0xFFFEE>;
 		mac-type = "xgdm";
 		phy-mode = "10gbase-kr";
 		managed = "in-band-status";
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-gsw-10g-spim-nand.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-gsw-10g-spim-nand.dts
index ac3da71..1f5ea1f 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-gsw-10g-spim-nand.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-gsw-10g-spim-nand.dts
@@ -354,6 +354,7 @@
 	gmac0: mac@0 {
 		compatible = "mediatek,eth-mac";
 		reg = <0>;
+		mtd-mac-address = <&factory 0xFFFF4>;
 		mac-type = "xgdm";
 		phy-mode = "10gbase-kr";
 
@@ -367,6 +368,7 @@
 	gmac1: mac@1 {
 		compatible = "mediatek,eth-mac";
 		reg = <1>;
+		mtd-mac-address = <&factory 0xFFFFA>;
 		mac-type = "xgdm";
 		phy-mode = "xgmii";
 		phy-handle = <&phy0>;
@@ -375,6 +377,7 @@
 	gmac2: mac@2 {
 		compatible = "mediatek,eth-mac";
 		reg = <2>;
+		mtd-mac-address = <&factory 0xFFFEE>;
 		mac-type = "xgdm";
 		phy-mode = "usxgmii";
 		phy-handle = <&phy1>;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.h
index 9b0469c..b02324c 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.h
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.h
@@ -60,6 +60,14 @@
 #define MTK_FE_GDM_FSM(x)		(((x) == 2) ? MTK_FE_GDM3_FSM :	\
 					 ((x) == 1) ? MTK_FE_GDM2_FSM : MTK_FE_GDM1_FSM)
 
+#define MTK_FE_CDM_FSM(x)		(((x) == 0) ? MTK_FE_CDM3_FSM :	\
+					 ((x) == 1) ? MTK_FE_CDM4_FSM : MTK_FE_CDM5_FSM)
+
+#define MTK_FE_WDMA_OQ(x)		\
+	(((x) == 0) ? (mtk_r32(eth, MTK_PSE_OQ_STA(4)) & 0x00000FFF) :	\
+	(((x) == 1) ? (mtk_r32(eth, MTK_PSE_OQ_STA(4)) & 0x0FFF0000) :	\
+	(mtk_r32(eth, MTK_PSE_OQ_STA(6)) & 0x0FFF0000)))
+
 #if defined(CONFIG_MEDIATEK_NETSYS_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
 #define MTK_PSE_IQ_STA(x)		(0x180 + (x) * 0x4)
 #define MTK_PSE_OQ_STA(x)		(0x1A0 + (x) * 0x4)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_reset.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_reset.c
index 5a219e1..396cdc0 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_reset.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_reset.c
@@ -22,6 +22,13 @@
 	[MTK_EVENT_RFIFO_UF]	= "RFIFO UF",
 };
 
+struct mtk_qdma_cfg {
+	u32 qtx_cfg[MTK_QDMA_TX_NUM];
+	u32 qtx_sch[MTK_QDMA_TX_NUM];
+	u32 tx_sch[2];
+};
+
+static struct mtk_qdma_cfg mtk_qdma_cfg_backup;
 static int mtk_wifi_num = 0;
 static int mtk_rest_cnt = 0;
 u32 mtk_reset_flag = MTK_FE_START_RESET;
@@ -246,19 +253,52 @@
 	}
 }
 
+void mtk_check_pse_oq_sta(struct mtk_eth *eth, u32 port, u32 *pre_opq, u32 *err_opq)
+{
+	u32 mask = port % 2 ? 0x0FFF0000 : 0x00000FFF;
+	u32 id = port / 2;
+	u32 cur_opq;
+
+	cur_opq = (mtk_r32(eth, MTK_PSE_OQ_STA(id)) & mask);
+	if ((cur_opq != 0) && (cur_opq == *pre_opq))
+		*err_opq++;
+	else
+		*err_opq = 0;
+
+	*pre_opq = cur_opq;
+}
+
 u32 mtk_monitor_wdma_tx(struct mtk_eth *eth)
 {
 	static u32 pre_dtx[MTK_WDMA_CNT];
 	static u32 err_cnt[MTK_WDMA_CNT];
-	u32 i, cur_dtx, tx_busy, err_flag = 0;
+	static u32 err_opq1, err_opq2, err_opq8;
+	static u32 err_opq9, err_opq13, err_opq15;
+	u32 opq1, opq2, opq8, opq9, opq13, opq15;
+	u32 cur_dtx, tx_busy, fsm_ts;
+	u32 i, err_opq = 0, err_flag = 0;
+
+	mtk_check_pse_oq_sta(eth, 1, &opq1, &err_opq1);
+	mtk_check_pse_oq_sta(eth, 2, &opq2, &err_opq2);
+	mtk_check_pse_oq_sta(eth, 8, &opq8, &err_opq8);
+	mtk_check_pse_oq_sta(eth, 9, &opq9, &err_opq9);
+	mtk_check_pse_oq_sta(eth, 13, &opq13, &err_opq13);
+	mtk_check_pse_oq_sta(eth, 15, &opq15, &err_opq15);
+
+	if ((err_opq1 >= 3) || (err_opq2 >= 3) || (err_opq8 >= 3) ||
+	    (err_opq9 >= 3) || (err_opq13 >= 3) || (err_opq15 >= 3))
+		err_opq = 1;
 
 	for (i = 0; i < MTK_WDMA_CNT; i++) {
 		cur_dtx = mtk_r32(eth, MTK_WDMA_DTX_PTR(i));
 		tx_busy = mtk_r32(eth, MTK_WDMA_GLO_CFG(i)) & MTK_TX_DMA_BUSY;
-		if (cur_dtx == pre_dtx[i] && tx_busy) {
+		fsm_ts = mtk_r32(eth, MTK_FE_CDM_FSM(i)) &
+			(MTK_CDM_TS_FSM_MASK | MTK_CDM_TS_PARSER_FSM_MASK);
+		/*dtx unchange && tx busy && cdm-ts-fsm && ouput*/
+		if (cur_dtx == pre_dtx[i] && tx_busy && fsm_ts && err_opq) {
 			err_cnt[i]++;
 			if (err_cnt[i] >= 3) {
-				pr_info("WDMA %d Info\n", i);
+				pr_info("WDMA %d Tx Info\n", i);
 				pr_info("err_cnt = %d", err_cnt[i]);
 				pr_info("prev_dtx = 0x%x	| cur_dtx = 0x%x\n",
 					pre_dtx[i], cur_dtx);
@@ -270,6 +310,16 @@
 					mtk_r32(eth, MTK_WDMA_GLO_CFG(i)));
 				pr_info("WDMA_TX_DBG_MON0 = 0x%x\n",
 					mtk_r32(eth, MTK_WDMA_TX_DBG_MON0(i)));
+				pr_info("WDMA_CDM_FSM = 0x%x\n",
+					mtk_r32(eth, MTK_FE_CDM_FSM(i)));
+				pr_info("PSE_OQ_STA0 = 0x%x\n",
+					mtk_r32(eth, MTK_PSE_OQ_STA(0)));
+				pr_info("PSE_OQ_STA1 = 0x%x\n",
+					mtk_r32(eth, MTK_PSE_OQ_STA(1)));
+				pr_info("PSE_OQ_STA4 = 0x%x\n",
+					mtk_r32(eth, MTK_PSE_OQ_STA(4)));
+				pr_info("PSE_OQ_STA7 = 0x%x\n",
+					mtk_r32(eth, MTK_PSE_OQ_STA(7)));
 				pr_info("==============================\n");
 				err_flag = 1;
 			}
@@ -289,24 +339,21 @@
 	static u32 pre_drx[MTK_WDMA_CNT];
 	static u32 pre_opq[MTK_WDMA_CNT];
 	static u32 err_cnt[MTK_WDMA_CNT];
-	u32 i = 0, cur_drx = 0, rx_busy = 0, err_flag = 0;
-	u32 cur_opq = 0;
+	u32 cur_crx = 0, cur_drx = 0, cur_opq = 0, fsm_fs;
+	u32 i, err_flag = 0;
 
 	for (i = 0; i < MTK_WDMA_CNT; i++) {
+		cur_crx = mtk_r32(eth, MTK_WDMA_CRX_PTR(i));
 		cur_drx = mtk_r32(eth, MTK_WDMA_DRX_PTR(i));
-		rx_busy = mtk_r32(eth, MTK_WDMA_GLO_CFG(i)) & MTK_RX_DMA_BUSY;
-		if (i == 0)
-			cur_opq = (mtk_r32(eth, MTK_PSE_OQ_STA(5)) & 0x1FF);
-		else if (i == 1)
-			cur_opq = (mtk_r32(eth, MTK_PSE_OQ_STA(5)) & 0x1FF0000);
-		else
-			cur_opq = (mtk_r32(eth, MTK_PSE_OQ_STA(7)) & 0x1FF0000);
-
-		if (cur_drx == pre_drx[i] && rx_busy && cur_opq != 0 &&
-			cur_opq == pre_opq[i]) {
+		cur_opq = MTK_FE_WDMA_OQ(i);
+		fsm_fs = mtk_r32(eth, MTK_FE_CDM_FSM(i)) &
+			(MTK_CDM_FS_FSM_MASK | MTK_CDM_FS_PARSER_FSM_MASK);
+		/*drx unchange && ring not full && output && fsm_fs*/
+		if (cur_drx == pre_drx[i] && (cur_crx != cur_drx) &&
+		    (cur_opq != 0 && cur_opq == pre_opq[i]) && fsm_fs) {
 			err_cnt[i]++;
 			if (err_cnt[i] >= 3) {
-				pr_info("WDMA %d Info\n", i);
+				pr_info("WDMA %d Rx Info\n", i);
 				pr_info("err_cnt = %d", err_cnt[i]);
 				pr_info("prev_drx = 0x%x	| cur_drx = 0x%x\n",
 					pre_drx[i], cur_drx);
@@ -316,6 +363,8 @@
 					mtk_r32(eth, MTK_WDMA_DRX_PTR(i)));
 				pr_info("WDMA_GLO_CFG = 0x%x\n",
 					mtk_r32(eth, MTK_WDMA_GLO_CFG(i)));
+				pr_info("PSE_OQ_STA = 0x%x\n", MTK_FE_WDMA_OQ(i));
+				pr_info("PSE_CDM_FSM = 0x%x\n", mtk_r32(eth, MTK_FE_CDM_FSM(i)));
 				pr_info("==============================\n");
 				err_flag = 1;
 			}
@@ -418,16 +467,17 @@
 
 u32 mtk_monitor_adma_rx(struct mtk_eth *eth)
 {
-	static u32 err_cnt_arx, pre_drx;
-	u32 err_flag = 0, cur_drx = 0;
+	static u32 err_cnt_arx, pre_drx, pre_opq;
+	u32 err_flag = 0;
 
-	u32 opq0 = (mtk_r32(eth, MTK_PSE_OQ_STA(0)) & 0x1FF) != 0;
-	u32 cdm1_fsm = (mtk_r32(eth, MTK_FE_CDM1_FSM) & 0xFFFF0000) != 0;
-	u32 cur_stat = ((mtk_r32(eth, MTK_ADMA_RX_DBG0) & 0x1F) == 0);
-	u32 fifo_rdy = ((mtk_r32(eth, MTK_ADMA_RX_DBG0) & 0x40) == 0);
-	cur_drx = mtk_r32(eth, MTK_ADMA_DRX_PTR);
+	u32 opq0 = (mtk_r32(eth, MTK_PSE_OQ_STA(0)) & 0xFFF);
+	u32 fsm_fs = (mtk_r32(eth, MTK_FE_CDM1_FSM) & 0x0F0F0000) != 0;
+	u32 cur_crx = mtk_r32(eth, MTK_ADMA_CRX_PTR);
+	u32 cur_drx = mtk_r32(eth, MTK_ADMA_DRX_PTR);
 
-	if (opq0 && cdm1_fsm && cur_stat && fifo_rdy && (cur_drx == pre_drx)) {
+	/*drx don't move && ring not full && output queue && fs_fsm*/
+	if ((cur_drx == pre_drx) && (cur_crx != cur_drx) &&
+	    (opq0 != 0 && opq0 == pre_opq) && fsm_fs) {
 		err_cnt_arx++;
 		if (err_cnt_arx >= 3) {
 			pr_info("ADMA Rx Info\n");
@@ -440,6 +490,8 @@
 				mtk_r32(eth, MTK_ADMA_RX_DBG0));
 			pr_info("MTK_ADMA_RX_DBG1 = 0x%x\n",
 				mtk_r32(eth, MTK_ADMA_RX_DBG1));
+			pr_info("MTK_ADMA_CRX_PTR = 0x%x\n",
+				mtk_r32(eth, MTK_ADMA_CRX_PTR));
 			pr_info("MTK_ADMA_DRX_PTR = 0x%x\n",
 				mtk_r32(eth, MTK_ADMA_DRX_PTR));
 			pr_info("==============================\n");
@@ -449,6 +501,7 @@
 		err_cnt_arx = 0;
 
 	pre_drx = cur_drx;
+	pre_opq = opq0;
 	if (err_flag)
 		return MTK_FE_STOP_TRAFFIC;
 	else
@@ -673,6 +726,58 @@
 	mod_timer(&eth->mtk_dma_monitor_timer, jiffies + 1 * HZ);
 }
 
+void mtk_save_qdma_cfg(struct mtk_eth *eth)
+{
+	int i;
+
+	for (i = 0; i < MTK_QDMA_TX_NUM; i++) {
+		mtk_m32(eth, MTK_QTX_CFG_PAGE, (i / MTK_QTX_PER_PAGE),
+			MTK_QDMA_PAGE);
+
+		mtk_qdma_cfg_backup.qtx_cfg[i] =
+			mtk_r32(eth, MTK_QTX_CFG(i % MTK_QTX_PER_PAGE));
+		mtk_qdma_cfg_backup.qtx_sch[i] =
+			mtk_r32(eth, MTK_QTX_SCH(i % MTK_QTX_PER_PAGE));
+	}
+	mtk_m32(eth, MTK_QTX_CFG_PAGE, 0, MTK_QDMA_PAGE);
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2) ||
+	    MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
+		mtk_qdma_cfg_backup.tx_sch[0] =
+			mtk_r32(eth, MTK_QDMA_TX_4SCH_BASE(0));
+		mtk_qdma_cfg_backup.tx_sch[1] =
+			mtk_r32(eth, MTK_QDMA_TX_4SCH_BASE(2));
+	} else
+		mtk_qdma_cfg_backup.tx_sch[0] =
+			mtk_r32(eth, MTK_QDMA_TX_2SCH_BASE);
+}
+
+void mtk_restore_qdma_cfg(struct mtk_eth *eth)
+{
+	int i;
+
+	for (i = 0; i < MTK_QDMA_TX_NUM; i++) {
+		mtk_m32(eth, MTK_QTX_CFG_PAGE, (i / MTK_QTX_PER_PAGE),
+			MTK_QDMA_PAGE);
+
+		mtk_w32(eth, mtk_qdma_cfg_backup.qtx_cfg[i],
+			MTK_QTX_CFG(i % MTK_QTX_PER_PAGE));
+		mtk_w32(eth, mtk_qdma_cfg_backup.qtx_sch[i],
+			MTK_QTX_SCH(i % MTK_QTX_PER_PAGE));
+	}
+	mtk_m32(eth, MTK_QTX_CFG_PAGE, 0, MTK_QDMA_PAGE);
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2) ||
+	    MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
+		mtk_w32(eth, mtk_qdma_cfg_backup.tx_sch[0],
+			MTK_QDMA_TX_4SCH_BASE(0));
+		mtk_w32(eth, mtk_qdma_cfg_backup.tx_sch[1],
+			MTK_QDMA_TX_4SCH_BASE(2));
+	} else
+		mtk_w32(eth, mtk_qdma_cfg_backup.tx_sch[0],
+			MTK_QDMA_TX_2SCH_BASE);
+}
+
 void mtk_prepare_reset_fe(struct mtk_eth *eth)
 {
 	u32 i = 0, val = 0, mcr = 0;
@@ -760,9 +865,10 @@
 	}
 }
 
-static int mtk_eth_netdevice_event(struct notifier_block *unused,
-				   unsigned long event, void *ptr)
+int mtk_eth_netdevice_event(struct notifier_block *n, unsigned long event, void *ptr)
 {
+	struct mtk_eth *eth = container_of(n, struct mtk_eth, netdevice_notifier);
+
 	switch (event) {
 	case MTK_WIFI_RESET_DONE:
 	case MTK_FE_STOP_TRAFFIC_DONE:
@@ -788,13 +894,16 @@
 		complete(&wait_ser_done);
 		mtk_rest_cnt = mtk_wifi_num;
 		break;
+	case MTK_FE_START_RESET_INIT:
+		pr_info("%s rcv fe start reset init event:%lx\n", __func__, event);
+		if ((atomic_read(&reset_lock) == 0) &&
+		    (atomic_read(&force) == 1)) {
+			mtk_reset_flag = MTK_FE_START_RESET;
+			schedule_work(&eth->pending_work);
+		}
 	default:
 		break;
 	}
 
 	return NOTIFY_DONE;
 }
-
-struct notifier_block mtk_eth_netdevice_nb __read_mostly = {
-	.notifier_call = mtk_eth_netdevice_event,
-};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_reset.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_reset.h
index ad5838c..dd8206a 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_reset.h
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_reset.h
@@ -19,6 +19,7 @@
 #define MTK_FE_STOP_TRAFFIC_DONE	(0x2006)
 #define MTK_FE_START_TRAFFIC	(0x2007)
 #define MTK_FE_STOP_TRAFFIC_DONE_FAIL	(0x2008)
+#define MTK_FE_START_RESET_INIT	(0x2009)
 
 /*FE GDM Counter */
 #define MTK_GDM_RX_FC	(0x24)
@@ -71,7 +72,7 @@
 	MTK_EVENT_RFIFO_UF	= 19,
 };
 
-extern struct notifier_block mtk_eth_netdevice_nb __read_mostly;
+int mtk_eth_netdevice_event(struct notifier_block *n, unsigned long event, void *ptr);
 extern struct completion wait_ser_done;
 extern char* mtk_reset_event_name[32];
 extern atomic_t reset_lock;
@@ -86,6 +87,8 @@
 void mtk_reset_event_update(struct mtk_eth *eth, u32 id);
 void mtk_dump_netsys_info(void *_eth);
 void mtk_dma_monitor(struct timer_list *t);
+void mtk_save_qdma_cfg(struct mtk_eth *eth);
+void mtk_restore_qdma_cfg(struct mtk_eth *eth);
 void mtk_prepare_reset_fe(struct mtk_eth *eth);
 void mtk_prepare_reset_ppe(struct mtk_eth *eth, u32 ppe_id);
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index 7ff8baf..42a2521 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -10,6 +10,7 @@
 #include <linux/of_mdio.h>
 #include <linux/of_net.h>
 #include <linux/of_address.h>
+#include <linux/mtd/mtd.h>
 #include <linux/mfd/syscon.h>
 #include <linux/regmap.h>
 #include <linux/clk.h>
@@ -912,68 +913,39 @@
 	return 1;
 }
 
-static int mtk_gdm_fsm_get(struct mtk_mac *mac, u32 gdm)
-{
-	u32 fsm = mtk_r32(mac->hw, gdm);
-	u32 ret = 0, val = 0;
-
-	switch (mac->type) {
-	case MTK_GDM_TYPE:
-		ret = fsm == 0;
-		break;
-	case MTK_XGDM_TYPE:
-		ret = fsm == 0x10000000;
-		break;
-	default:
-		break;
-	}
-
-	if ((mac->type == MTK_XGDM_TYPE) && (mac->id != MTK_GMAC1_ID)) {
-		val = mtk_r32(mac->hw, MTK_MAC_FSM(mac->id));
-		if ((val == 0x02010100) || (val == 0x01010100)) {
-			ret = (mac->interface == PHY_INTERFACE_MODE_XGMII) ?
-				((fsm & 0x0fffffff) == 0) : ((fsm & 0x00ffffff) == 0);
-		} else
-			ret = 0;
-	}
-
-	return ret;
-}
-
 static void mtk_gdm_fsm_poll(struct mtk_mac *mac)
 {
-	u32 gdm = 0, i = 0;
-
-	switch (mac->id) {
-	case MTK_GMAC1_ID:
-		gdm = MTK_FE_GDM1_FSM;
-		break;
-	case MTK_GMAC2_ID:
-		gdm = MTK_FE_GDM2_FSM;
-		break;
-	case MTK_GMAC3_ID:
-		gdm = MTK_FE_GDM3_FSM;
-		break;
-	default:
-		pr_info("%s mac id invalid", __func__);
-		break;
-	}
+	u32 gdm_fsm, mac_fsm, gdm_idle, mac_idle;
+	u32 i = 0;
 
 	while (i < 3) {
-		if (mtk_gdm_fsm_get(mac, gdm))
+		gdm_fsm = mtk_r32(mac->hw, MTK_FE_GDM_FSM(mac->id));
+		mac_fsm = mtk_r32(mac->hw, MTK_MAC_FSM(mac->id));
+
+		if (mac->type == MTK_XGDM_TYPE) {
+			gdm_idle = ((gdm_fsm & 0x00ffffff) == 0);
+			mac_idle = 1;
+		} else {
+			gdm_idle = ((gdm_fsm & 0xffffffff) == 0);
+			mac_idle = (mac_fsm == 0x01010000 || mac_fsm == 0x01010100);
+		}
+
+		if (gdm_idle && mac_idle)
 			break;
+
 		msleep(500);
 		i++;
 	}
 
 	if (i == 3)
-		pr_info("%s fsm invalid", __func__);
+		pr_info("%s poll fsm idle timeout(gdm=%08x, mac=%08x)\n",
+			__func__, gdm_fsm, mac_fsm);
 }
 
 static void mtk_pse_port_link_set(struct mtk_mac *mac, bool up,
 				  phy_interface_t interface)
 {
-	u32 fe_glo_cfg, val = 0;
+	u32 fe_glo_cfg, val = 0, port = 0;
 
 	if (!up && interface == PHY_INTERFACE_MODE_XGMII) {
 		void __iomem *base;
@@ -992,25 +964,29 @@
 		}
 	}
 
-	fe_glo_cfg = mtk_r32(mac->hw, MTK_FE_GLO_CFG(mac->id));
 	switch (mac->id) {
 	case MTK_GMAC1_ID:
 		val = MTK_FE_LINK_DOWN_P1;
+		port = PSE_GDM1_PORT;
 		break;
 	case MTK_GMAC2_ID:
 		val = MTK_FE_LINK_DOWN_P2;
+		port = PSE_GDM2_PORT;
 		break;
 	case MTK_GMAC3_ID:
 		val = MTK_FE_LINK_DOWN_P15;
+		port = PSE_GDM3_PORT;
 		break;
 	}
 
+	fe_glo_cfg = mtk_r32(mac->hw, MTK_FE_GLO_CFG(port));
+
 	if (!up)
 		fe_glo_cfg |= val;
 	else
 		fe_glo_cfg &= ~val;
 
-	mtk_w32(mac->hw, fe_glo_cfg, MTK_FE_GLO_CFG(mac->id));
+	mtk_w32(mac->hw, fe_glo_cfg, MTK_FE_GLO_CFG(port));
 	mtk_gdm_fsm_poll(mac);
 }
 
@@ -2101,10 +2077,11 @@
 	int queue = skb_get_queue_mapping(skb);
 	int k = 0;
 
-	if (skb->len < 32) {
+	if (skb->len <= 40) {
 		if (skb_put_padto(skb, MTK_MIN_TX_LENGTH))
 			return -ENOMEM;
 
+		txd_info.last = !skb_is_nonlinear(skb);
 		txd_info.size = skb_headlen(skb);
 	}
 
@@ -2159,7 +2136,7 @@
 			}
 
 			memset(&txd_info, 0, sizeof(struct mtk_tx_dma_desc_info));
-			txd_info.size = min(frag_size, MTK_TX_DMA_BUF_LEN);
+			txd_info.size = min(frag_size, eth->soc->txrx.dma_max_len);
 			txd_info.qid = queue;
 			txd_info.last = i == skb_shinfo(skb)->nr_frags - 1 &&
 					!(frag_size - txd_info.size);
@@ -3891,9 +3868,19 @@
 			MTK_RX_BT_32DWORDS | MTK_MULTI_EN,
 			reg_map->pdma.glo_cfg);
 	} else {
-		mtk_w32(eth, MTK_TX_WB_DDONE | MTK_TX_DMA_EN | MTK_RX_DMA_EN |
-			MTK_MULTI_EN | MTK_PDMA_SIZE_8DWORDS,
-			reg_map->pdma.glo_cfg);
+		if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
+			mtk_w32(eth, MTK_TX_DMA_EN | MTK_RX_DMA_EN |
+				MTK_PDMA_SIZE_8DWORDS | MTK_TX_WB_DDONE |
+				MTK_CHK_DDONE | MTK_MULTI_EN_V2 |
+				MTK_PDMA_MUTLI_CNT | MTK_PDMA_RESV_BUF |
+				MTK_DEC_WCOMP | MTK_CSR_CLKGATE_BYP,
+				reg_map->pdma.glo_cfg);
+		} else {
+			mtk_w32(eth, MTK_TX_WB_DDONE | MTK_TX_DMA_EN |
+				MTK_RX_DMA_EN | MTK_MULTI_EN |
+				MTK_PDMA_SIZE_8DWORDS,
+				reg_map->pdma.glo_cfg);
+		}
 	}
 
 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_RX_V2) && eth->hwlro) {
@@ -4492,8 +4479,10 @@
 	const char *mac_addr;
 
 	mac_addr = of_get_mac_address(mac->of_node);
-	if (!IS_ERR(mac_addr))
+	if (!IS_ERR(mac_addr)) {
 		ether_addr_copy(dev->dev_addr, mac_addr);
+		ether_addr_copy(dev->perm_addr, mac_addr);
+	}
 
 	/* If the mac address is invalid, use random mac address  */
 	if (!is_valid_ether_addr(dev->dev_addr)) {
@@ -4590,6 +4579,10 @@
 
 	mtk_phy_config(eth, 0);
 
+	/* Store QDMA configurations to prepare for reset */
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA))
+		mtk_save_qdma_cfg(eth);
+
 	/* Adjust PPE configurations to prepare for reset */
 	mtk_prepare_reset_ppe(eth, 0);
 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSTCTRL_PPE1))
@@ -4679,6 +4672,10 @@
 		break;
 	}
 
+	/* Restore QDMA configurations */
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA))
+		mtk_restore_qdma_cfg(eth);
+
 	atomic_dec(&reset_lock);
 
 	timer_setup(&eth->mtk_dma_monitor_timer, mtk_dma_monitor, 0);
@@ -5250,6 +5247,40 @@
 	return 0;
 }
 
+static int mtk_of_mtd_mac_address_is_available(struct device_node *np)
+{
+#ifdef CONFIG_MTD
+	struct device_node *mtd_np = NULL;
+	int size;
+	struct mtd_info *mtd;
+	const char *part;
+	const __be32 *list;
+	phandle phandle;
+
+	list = of_get_property(np, "mtd-mac-address", &size);
+	if (!list || (size != (2 * sizeof(*list))))
+		return 0;
+
+	phandle = be32_to_cpup(list++);
+	if (phandle)
+		mtd_np = of_find_node_by_phandle(phandle);
+
+	if (!mtd_np)
+		return 0;
+
+	part = of_get_property(mtd_np, "label", NULL);
+	if (!part)
+		part = mtd_np->name;
+
+	mtd = get_mtd_device_nm(part);
+	if (IS_ERR(mtd))
+		return -ENODEV;
+
+	return 1;
+#endif
+	return 0;
+}
+
 static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
 {
 	const __be32 *_id = of_get_property(np, "reg", NULL);
@@ -5278,6 +5309,9 @@
 		return -EINVAL;
 	}
 
+	if (mtk_of_mtd_mac_address_is_available(np) < 0)
+		return -EPROBE_DEFER;
+
 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA))
 		txqs = MTK_QDMA_TX_NUM;
 
@@ -5777,7 +5811,8 @@
 
 	platform_set_drvdata(pdev, eth);
 
-	register_netdevice_notifier(&mtk_eth_netdevice_nb);
+	eth->netdevice_notifier.notifier_call = mtk_eth_netdevice_event;
+	register_netdevice_notifier(&eth->netdevice_notifier);
 #if defined(CONFIG_MEDIATEK_NETSYS_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
 	timer_setup(&eth->mtk_dma_monitor_timer, mtk_dma_monitor, 0);
 	eth->mtk_dma_monitor_timer.expires = jiffies;
@@ -5823,7 +5858,7 @@
 
 	mtk_cleanup(eth);
 	mtk_mdio_cleanup(eth);
-	unregister_netdevice_notifier(&mtk_eth_netdevice_nb);
+	unregister_netdevice_notifier(&eth->netdevice_notifier);
 	del_timer_sync(&eth->mtk_dma_monitor_timer);
 
 	return 0;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h
index d2452be..9fae48f 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -71,7 +71,7 @@
 #define MTK_RSS_MAX_INDIRECTION_TABLE	128
 
 /* Frame Engine Global Configuration */
-#define MTK_FE_GLO_CFG(x)		((x == MTK_GMAC3_ID) ? 0x24 : 0x00)
+#define MTK_FE_GLO_CFG(port)	((port < 8) ? 0x0 : 0x24)
 #define MTK_FE_LINK_DOWN_P1	BIT(9)
 #define MTK_FE_LINK_DOWN_P2	BIT(10)
 #define MTK_FE_LINK_DOWN_P3	BIT(11)
@@ -295,11 +295,19 @@
 
 /* PDMA Global Configuration Register */
 #define MTK_PDMA_GLO_CFG	(PDMA_BASE + 0x204)
-#define MTK_RX_DMA_LRO_EN	BIT(8)
+#define MTK_CSR_CLKGATE_BYP	BIT(30)
 #define MTK_MULTI_EN		BIT(10)
+#define MTK_RX_DMA_LRO_EN	BIT(8)
 #define MTK_PDMA_SIZE_8DWORDS	(1 << 4)
 
-/* PDMA Global Configuration Register */
+/* PDMA V2 Global Configuration Register */
+#define MTK_DEC_WCOMP		BIT(28)
+#define MTK_PDMA_RESV_BUF	(0x40 << 16)
+#define MTK_PDMA_MUTLI_CNT	(0xf << 12)
+#define MTK_MULTI_EN_V2		BIT(11)
+#define MTK_CHK_DDONE		BIT(10)
+
+/* PDMA RX DMA Configuration Register */
 #define MTK_PDMA_RX_CFG		(PDMA_BASE + 0x210)
 #define MTK_PDMA_LRO_SDL	(0x3000)
 #define MTK_RX_CFG_SDL_OFFSET	(16)
@@ -312,6 +320,7 @@
 #define MTK_PST_DTX_IDX_CFG(x)	(MTK_PST_DTX_IDX0 << (x))
 
 /*PDMA HW RX Index Register*/
+#define MTK_ADMA_CRX_PTR	(PDMA_BASE + 0x108)
 #define MTK_ADMA_DRX_PTR	(PDMA_BASE + 0x10C)
 
 /* PDMA Delay Interrupt Register */
@@ -485,6 +494,9 @@
 #define FC_THRES_DROP_EN	(7 << 16)
 #define FC_THRES_MIN		0x4444
 
+/* QDMA TX Scheduler Rate Control Register */
+#define MTK_QDMA_TX_2SCH_BASE	(QDMA_BASE + 0x214)
+
 /* QDMA Interrupt Status Register */
 #define MTK_QDMA_INT_STATUS	(QDMA_BASE + 0x218)
 #if defined(CONFIG_MEDIATEK_NETSYS_RX_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
@@ -555,6 +567,9 @@
 /* QDMA FQ Free Page Buffer Length Register */
 #define MTK_QDMA_FQ_BLEN	(QDMA_BASE +0x32c)
 
+/* QDMA TX Scheduler Rate Control Register */
+#define MTK_QDMA_TX_4SCH_BASE(x)	(QDMA_BASE + 0x398 + (((x) >> 1) * 0x4))
+
 /* WDMA Registers */
 #define MTK_WDMA_CTX_PTR(x)	(WDMA_BASE(x) + 0x8)
 #define MTK_WDMA_DTX_PTR(x)	(WDMA_BASE(x) + 0xC)
@@ -563,7 +578,10 @@
 #define MTK_WDMA_RX_DBG_MON1(x)	(WDMA_BASE(x) + 0x3c4)
 #define MTK_WDMA_CRX_PTR(x)	(WDMA_BASE(x) + 0x108)
 #define MTK_WDMA_DRX_PTR(x)	(WDMA_BASE(x) + 0x10C)
-#define MTK_CDM_TXFIFO_RDY	BIT(7)
+#define MTK_CDM_FS_PARSER_FSM_MASK	GENMASK(27, 24)
+#define MTK_CDM_FS_FSM_MASK		GENMASK(19, 16)
+#define MTK_CDM_TS_PARSER_FSM_MASK	GENMASK(12, 8)
+#define MTK_CDM_TS_FSM_MASK		GENMASK(3, 0)
 
 /*TDMA Register*/
 #define MTK_TDMA_GLO_CFG	(0x6204)
@@ -959,7 +977,8 @@
 /* Register to QPHY wrapper control */
 #define SGMSYS_QPHY_WRAP_CTRL	0xec
 #define SGMII_PN_SWAP_MASK	GENMASK(1, 0)
-#define SGMII_PN_SWAP_TX_RX	(BIT(0) | BIT(1))
+#define SGMII_PN_SWAP_RX	BIT(1)
+#define SGMII_PN_SWAP_TX	BIT(0)
 
 /* USXGMII subsystem config registers */
 /* Register to control speed */
@@ -1745,7 +1764,7 @@
 #define MTK_SGMII_PHYSPEED_2500        BIT(1)
 #define MTK_SGMII_PHYSPEED_5000	       BIT(2)
 #define MTK_SGMII_PHYSPEED_10000       BIT(3)
-#define MTK_SGMII_PN_SWAP	       BIT(16)
+
 #define MTK_HAS_FLAGS(flags, _x)       (((flags) & (_x)) == (_x))
 
 /* struct mtk_sgmii_pcs - This structure holds each sgmii regmap and associated
@@ -1765,9 +1784,13 @@
 	spinlock_t		regmap_lock;
 	phy_interface_t		interface;
 	__ETHTOOL_DECLARE_LINK_MODE_MASK(advertising);
+	unsigned long		link_poll_inband;
+	unsigned int		mode;
 	u32			flags;
 	u32			ana_rgc3;
+	u32			polarity;
 	u8			id;
+	struct timer_list	link_poll_outband;
 	struct phylink_pcs	pcs;
 };
 
@@ -1797,8 +1820,10 @@
 	struct regmap		*regmap_pextp;
 	spinlock_t		regmap_lock;
 	phy_interface_t		interface;
+	unsigned long		link_poll_inband;
 	unsigned int		mode;
 	u8			id;
+	struct timer_list	link_poll_outband;
 	struct phylink_pcs	pcs;
 };
 
@@ -1920,6 +1945,7 @@
 	u32				rx_dma_l4_valid;
 	int				ip_align;
 	spinlock_t			syscfg0_lock;
+	struct notifier_block		netdevice_notifier;
 	struct timer_list		mtk_dma_monitor_timer;
 };
 
@@ -1999,7 +2025,6 @@
 struct phylink_pcs *mtk_usxgmii_select_pcs(struct mtk_usxgmii *ss, int id);
 int mtk_usxgmii_init(struct mtk_eth *eth, struct device_node *r);
 int mtk_toprgu_init(struct mtk_eth *eth, struct device_node *r);
-void mtk_usxgmii_link_poll(struct work_struct *work);
 
 void mtk_eth_set_dma_device(struct mtk_eth *eth, struct device *dma_dev);
 u32 mtk_rss_indr_table(struct mtk_rss_params *rss_params, int index);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat.c
index 1b769ed..4a7e14f 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat.c
@@ -49,6 +49,9 @@
 void (*ppe_dev_unregister_hook)(struct net_device *dev) = NULL;
 EXPORT_SYMBOL(ppe_dev_unregister_hook);
 
+int (*hnat_set_wdma_pse_port_state)(int wdma_idx, int up) = NULL;
+EXPORT_SYMBOL(hnat_set_wdma_pse_port_state);
+
 static void hnat_sma_build_entry(struct timer_list *t)
 {
 	int i;
@@ -161,6 +164,20 @@
 	return -EINVAL;
 }
 
+static int mtk_set_wdma_pse_port_state(int wdma_idx, int up)
+{
+	u32 port = 0, link_dwn = 0;
+
+	port = mtk_get_wdma_rx_port(wdma_idx);
+	if (port < 0)
+		return -EINVAL;
+
+	link_dwn = 0x1 << (port - NR_WDMA0_PORT);
+	cr_set_field(hnat_priv->fe_base + MTK_FE_GLO_CFG(port), link_dwn, !up);
+
+	return 0;
+}
+
 void set_gmac_ppe_fwd(int id, int enable)
 {
 	void __iomem *reg;
@@ -644,6 +661,7 @@
 		ra_sw_nat_clear_bind_entries = foe_clear_all_bind_entries;
 		hnat_get_wdma_tx_port = mtk_get_wdma_tx_port;
 		hnat_get_wdma_rx_port = mtk_get_wdma_rx_port;
+		hnat_set_wdma_pse_port_state = mtk_set_wdma_pse_port_state;
 	}
 
 	if (hnat_register_nf_hooks())
@@ -665,6 +683,7 @@
 	ra_sw_nat_clear_bind_entries = NULL;
 	hnat_get_wdma_tx_port = NULL;
 	hnat_get_wdma_rx_port = NULL;
+	hnat_set_wdma_pse_port_state = NULL;
 	hnat_unregister_nf_hooks();
 
 	for (i = 0; i < CFG_PPE_NUM; i++) {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h
index 97e16d9..6af93af 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h
@@ -10,9 +10,8 @@
  *   Copyright (C) 2014-2016 Sean Wang <sean.wang@mediatek.com>
  *   Copyright (C) 2016-2017 John Crispin <blogic@openwrt.org>
  */
-
-#ifndef _MTK_NF_HNAT_H_
-#define _MTK_NF_HNAT_H_
+#ifndef NF_HNAT_H
+#define NF_HNAT_H
 
 #include <linux/debugfs.h>
 #include <linux/string.h>
@@ -889,6 +888,7 @@
 struct hnat_accounting {
 	u64 bytes;
 	u64 packets;
+	u64 nfct; /* For retrieving nf_conn info */
 };
 
 enum mtk_hnat_version {
@@ -1333,4 +1333,5 @@
 {
 	return (readl(hnat_priv->fe_base + 0x0010)) & 0xffff;
 }
-#endif /* _MTK_NF_HNAT_H_ */
+
+#endif /* NF_HNAT_H */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c
index 31271d8..d111cb3 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c
@@ -18,6 +18,8 @@
 #include <linux/iopoll.h>
 #include <linux/inet.h>
 #include <net/ipv6.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_acct.h>
 
 #include "hnat.h"
 #include "nf_hnat_mtk.h"
@@ -976,6 +978,30 @@
 
 }
 
+static int hnat_nfct_counter_update(struct mtk_hnat *h, u32 ppe_id,
+				    u32 index, u64 bytes, u64 packets)
+{
+	struct nf_conn *ct;
+	struct nf_conn_acct *acct;
+	struct nf_conn_counter *counter;
+	enum ip_conntrack_info ctinfo;
+	u64 nfct;
+
+	nfct = h->acct[ppe_id][index].nfct;
+	ctinfo = nfct & NFCT_INFOMASK;
+	ct = (struct nf_conn *)(nfct & NFCT_PTRMASK);
+	if (ct) {
+		acct = nf_conn_acct_find(ct);
+		if (acct) {
+			counter = acct->counter;
+			atomic64_add(bytes, &counter[CTINFO2DIR(ctinfo)].bytes);
+			atomic64_add(packets, &counter[CTINFO2DIR(ctinfo)].packets);
+		}
+	}
+
+	return 0;
+}
+
 struct hnat_accounting *hnat_get_count(struct mtk_hnat *h, u32 ppe_id,
 				       u32 index, struct hnat_accounting *diff)
 
@@ -1002,6 +1028,8 @@
 		diff->packets = packets;
 	}
 
+	hnat_nfct_counter_update(h, ppe_id, index, bytes, packets);
+
 	return &h->acct[ppe_id][index];
 }
 EXPORT_SYMBOL(hnat_get_count);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
index c5e26e8..b86a7dd 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
@@ -1893,9 +1893,11 @@
 	/*reset statistic for this entry*/
 	if (hnat_priv->data->per_flow_accounting &&
 	    skb_hnat_entry(skb) < hnat_priv->foe_etry_num &&
-	    skb_hnat_ppe(skb) < CFG_PPE_NUM)
+	    skb_hnat_ppe(skb) < CFG_PPE_NUM) {
 		memset(&hnat_priv->acct[skb_hnat_ppe(skb)][skb_hnat_entry(skb)],
-		       0, sizeof(struct mib_entry));
+		       0, sizeof(struct hnat_accounting));
+		hnat_priv->acct[skb_hnat_ppe(skb)][skb_hnat_entry(skb)].nfct = skb_get_nfct(skb);
+	}
 
 	return 0;
 }
@@ -2365,28 +2367,6 @@
 	}
 }
 
-static void mtk_hnat_nf_update(struct sk_buff *skb)
-{
-	struct nf_conn *ct;
-	struct nf_conn_acct *acct;
-	struct nf_conn_counter *counter;
-	enum ip_conntrack_info ctinfo;
-	struct hnat_accounting diff;
-
-	ct = nf_ct_get(skb, &ctinfo);
-	if (ct) {
-		if (!hnat_get_count(hnat_priv, skb_hnat_ppe(skb), skb_hnat_entry(skb), &diff))
-			return;
-
-		acct = nf_conn_acct_find(ct);
-		if (acct) {
-			counter = acct->counter;
-			atomic64_add(diff.packets, &counter[CTINFO2DIR(ctinfo)].packets);
-			atomic64_add(diff.bytes, &counter[CTINFO2DIR(ctinfo)].bytes);
-		}
-	}
-}
-
 int mtk_464xlat_fill_mac(struct foe_entry *entry, struct sk_buff *skb,
 			 const struct net_device *out, bool l2w)
 {
@@ -2731,7 +2711,7 @@
 	case HIT_BIND_KEEPALIVE_DUP_OLD_HDR:
 		/* update hnat count to nf_conntrack by keepalive */
 		if (hnat_priv->data->per_flow_accounting && hnat_priv->nf_stat_en)
-			mtk_hnat_nf_update(skb);
+			hnat_get_count(hnat_priv, skb_hnat_ppe(skb), skb_hnat_entry(skb), NULL);
 
 		if (fn && !mtk_hnat_accel_type(skb))
 			break;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_sgmii.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_sgmii.c
index 710b1b8..745ce8b 100755
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_sgmii.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_sgmii.c
@@ -153,22 +153,6 @@
 	mdelay(1);
 }
 
-int mtk_sgmii_need_powerdown(struct mtk_sgmii_pcs *mpcs, unsigned int bmcr)
-{
-	u32 val;
-
-	/* need to power down sgmii if link down */
-	regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val);
-	if (!(val & SGMII_LINK_STATYS))
-		return true;
-
-	/* need to power down sgmii if autoneg change */
-	if ((val & SGMII_AN_ENABLE) != bmcr)
-		return true;
-
-	return false;
-}
-
 void mtk_sgmii_setup_phya_gen1(struct mtk_sgmii_pcs *mpcs)
 {
 	if (!mpcs->regmap_pextp)
@@ -432,50 +416,48 @@
 			speed = SGMII_SPEED_1000;
 	}
 
-	if (mpcs->interface != interface ||
-	    mtk_sgmii_need_powerdown(mpcs, bmcr)) {
-		link_timer = phylink_get_link_timer_ns(interface);
-		if (link_timer < 0) {
-			spin_unlock(&mpcs->regmap_lock);
-			return link_timer;
-		}
+	if (mpcs->interface != interface) {
+		mpcs->interface = interface;
+		mpcs->mode = mode;
+		linkmode_copy(mpcs->advertising, advertising);
+		mode_changed = true;
+	}
 
-		if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
-			mtk_sgmii_xfi_pll_enable(eth->sgmii);
-			mtk_sgmii_reset(eth, mpcs->id);
-		}
+	link_timer = phylink_get_link_timer_ns(interface);
+	if (link_timer < 0) {
+		spin_unlock(&mpcs->regmap_lock);
+		return link_timer;
+	}
 
-		/* PHYA power down */
-		regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL,
-				   SGMII_PHYA_PWD, SGMII_PHYA_PWD);
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
+		mtk_sgmii_xfi_pll_enable(eth->sgmii);
+		mtk_sgmii_reset(eth, mpcs->id);
+	}
 
-		/* Reset SGMII PCS state */
-		regmap_update_bits(mpcs->regmap, SGMII_RESERVED_0,
-				   SGMII_SW_RESET, SGMII_SW_RESET);
+	/* PHYA power down */
+	regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL,
+			   SGMII_PHYA_PWD, SGMII_PHYA_PWD);
 
-		/* Configure the interface polarity */
-		if (MTK_HAS_FLAGS(mpcs->flags, MTK_SGMII_PN_SWAP))
-			regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_WRAP_CTRL,
-					   SGMII_PN_SWAP_MASK,
-					   SGMII_PN_SWAP_TX_RX);
+	/* Reset SGMII PCS state */
+	regmap_update_bits(mpcs->regmap, SGMII_RESERVED_0,
+			   SGMII_SW_RESET, SGMII_SW_RESET);
 
-		if (interface == PHY_INTERFACE_MODE_2500BASEX)
-			rgc3 = RG_PHY_SPEED_3_125G;
-		else
-			rgc3 = 0;
+	/* Configure the interface polarity */
+	regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_WRAP_CTRL,
+			   SGMII_PN_SWAP_MASK, mpcs->polarity);
 
-		/* Configure the underlying interface speed */
-		regmap_update_bits(mpcs->regmap, mpcs->ana_rgc3,
-				   RG_PHY_SPEED_3_125G, rgc3);
+	if (interface == PHY_INTERFACE_MODE_2500BASEX)
+		rgc3 = RG_PHY_SPEED_3_125G;
+	else
+		rgc3 = 0;
 
-		/* Setup the link timer */
-		regmap_write(mpcs->regmap, SGMSYS_PCS_LINK_TIMER,
-			     link_timer / 2 / 8);
+	/* Configure the underlying interface speed */
+	regmap_update_bits(mpcs->regmap, mpcs->ana_rgc3,
+			   RG_PHY_SPEED_3_125G, rgc3);
 
-		mpcs->interface = interface;
-		linkmode_copy(mpcs->advertising, advertising);
-		mode_changed = true;
-	}
+	/* Setup the link timer */
+	regmap_write(mpcs->regmap, SGMSYS_PCS_LINK_TIMER,
+		     link_timer / 2 / 8);
 
 	/* Update the advertisement, noting whether it has changed */
 	regmap_update_bits_check(mpcs->regmap, SGMSYS_PCS_ADVERTISE,
@@ -492,16 +474,14 @@
 			   SGMII_AN_ENABLE, bmcr);
 
 	/* Release PHYA power down state */
-	usleep_range(50, 100);
+	udelay(100);
 	regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, 0);
 
-	if (mode_changed) {
-		if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
-			if (interface == PHY_INTERFACE_MODE_2500BASEX)
-				mtk_sgmii_setup_phya_gen2(mpcs);
-			else
-				mtk_sgmii_setup_phya_gen1(mpcs);
-		}
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
+		if (interface == PHY_INTERFACE_MODE_2500BASEX)
+			mtk_sgmii_setup_phya_gen2(mpcs);
+		else
+			mtk_sgmii_setup_phya_gen1(mpcs);
 	}
 
 	spin_unlock(&mpcs->regmap_lock);
@@ -509,12 +489,45 @@
 	return changed || mode_changed;
 }
 
+static void mtk_sgmii_pcs_link_poll(struct timer_list *t)
+{
+	struct mtk_sgmii_pcs *mpcs = from_timer(mpcs, t, link_poll_outband);
+
+	if (mpcs->interface == PHY_INTERFACE_MODE_NA)
+		goto exit;
+
+	if (!mtk_sgmii_link_status(mpcs))
+		mtk_sgmii_pcs_config(&mpcs->pcs, mpcs->mode, mpcs->interface,
+				     mpcs->advertising, false);
+
+exit:
+	if (mpcs->mode != MLO_AN_INBAND)
+		mod_timer(&mpcs->link_poll_outband, jiffies + HZ);
+}
+
+static int mtk_sgmii_pcs_enable(struct phylink_pcs *pcs)
+{
+	struct mtk_sgmii_pcs *mpcs = pcs_to_mtk_sgmii_pcs(pcs);
+
+	mod_timer(&mpcs->link_poll_outband, jiffies + HZ);
+
+	return 0;
+}
+
+static void mtk_sgmii_pcs_disable(struct phylink_pcs *pcs)
+{
+	struct mtk_sgmii_pcs *mpcs = pcs_to_mtk_sgmii_pcs(pcs);
+
+	del_timer_sync(&mpcs->link_poll_outband);
+
+	mpcs->interface = PHY_INTERFACE_MODE_NA;
+}
+
 static void mtk_sgmii_pcs_get_state(struct phylink_pcs *pcs,
 				    struct phylink_link_state *state)
 {
 	struct mtk_sgmii_pcs *mpcs = pcs_to_mtk_sgmii_pcs(pcs);
 	unsigned int bm, adv, rgc3, sgm_mode;
-	static unsigned long t_start;
 
 	state->interface = mpcs->interface;
 
@@ -553,8 +566,8 @@
 	/* Reconfiguring SGMII every second to ensure that PCS can
 	 * link up with the Link Partner when a module is inserted.
 	 */
-	if (state->link == 0 && time_after(jiffies, t_start + HZ)) {
-		t_start = jiffies;
+	if (state->link == 0 && time_after(jiffies, mpcs->link_poll_inband + HZ)) {
+		mpcs->link_poll_inband = jiffies;
 		mtk_sgmii_pcs_config(pcs, MLO_AN_INBAND,
 				     state->interface, mpcs->advertising, false);
 	}
@@ -582,17 +595,15 @@
 	unsigned long t_start = jiffies;
 
 	do {
-		msleep(1000);
+		msleep(100);
 
 		if (mtk_sgmii_link_status(mpcs))
 			goto exit;
 
-		if (mode != MLO_AN_INBAND)
-			mtk_sgmii_pcs_config(&mpcs->pcs, mode,
-					     interface, mpcs->advertising, false);
 	} while (time_before(jiffies, t_start + msecs_to_jiffies(3000)));
 
 	pr_warn("%s wait link up timeout!\n", __func__);
+	return;
 
 exit:
 	/* If autoneg is enabled, the force speed and duplex
@@ -620,6 +631,8 @@
 
 static const struct phylink_pcs_ops mtk_sgmii_pcs_ops = {
 	.pcs_config = mtk_sgmii_pcs_config,
+	.pcs_enable = mtk_sgmii_pcs_enable,
+	.pcs_disable = mtk_sgmii_pcs_disable,
 	.pcs_get_state = mtk_sgmii_pcs_get_state,
 	.pcs_an_restart = mtk_sgmii_pcs_restart_an,
 	.pcs_link_up = mtk_sgmii_pcs_link_up,
@@ -644,14 +657,20 @@
 		if (IS_ERR(ss->pcs[i].regmap))
 			return PTR_ERR(ss->pcs[i].regmap);
 
-		ss->pcs[i].flags &= ~(MTK_SGMII_PN_SWAP);
+		ss->pcs[i].polarity = 0;
 		if (of_property_read_bool(np, "pn_swap"))
-			ss->pcs[i].flags |= MTK_SGMII_PN_SWAP;
+			ss->pcs[i].polarity |= SGMII_PN_SWAP_TX | SGMII_PN_SWAP_RX;
+		else if (of_property_read_bool(np, "pn_swap_tx"))
+			ss->pcs[i].polarity |= SGMII_PN_SWAP_TX;
+		else if (of_property_read_bool(np, "pn_swap_rx"))
+			ss->pcs[i].polarity |= SGMII_PN_SWAP_RX;
 
 		ss->pcs[i].pcs.ops = &mtk_sgmii_pcs_ops;
 		ss->pcs[i].pcs.poll = true;
 		ss->pcs[i].interface = PHY_INTERFACE_MODE_NA;
 
+		timer_setup(&ss->pcs[i].link_poll_outband, mtk_sgmii_pcs_link_poll, 0);
+
 		spin_lock_init(&ss->pcs[i].regmap_lock);
 
 		of_node_put(np);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_usxgmii.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_usxgmii.c
index 40eb309..4e5db68 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_usxgmii.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_usxgmii.c
@@ -671,13 +671,46 @@
 	return mode_changed;
 }
 
+static void mtk_usxgmii_pcs_link_poll(struct timer_list *t)
+{
+	struct mtk_usxgmii_pcs *mpcs = from_timer(mpcs, t, link_poll_outband);
+
+	if (mpcs->interface == PHY_INTERFACE_MODE_NA)
+		goto exit;
+
+	if (!mtk_usxgmii_link_status(mpcs))
+		mtk_usxgmii_pcs_config(&mpcs->pcs, mpcs->mode,
+				       mpcs->interface, NULL, false);
+
+exit:
+	if (mpcs->mode != MLO_AN_INBAND)
+		mod_timer(&mpcs->link_poll_outband, jiffies + HZ);
+}
+
+static int mtk_usxgmii_pcs_enable(struct phylink_pcs *pcs)
+{
+	struct mtk_usxgmii_pcs *mpcs = pcs_to_mtk_usxgmii_pcs(pcs);
+
+	mod_timer(&mpcs->link_poll_outband, jiffies + HZ);
+
+	return 0;
+}
+
+static void mtk_usxgmii_pcs_disable(struct phylink_pcs *pcs)
+{
+	struct mtk_usxgmii_pcs *mpcs = pcs_to_mtk_usxgmii_pcs(pcs);
+
+	del_timer_sync(&mpcs->link_poll_outband);
+
+	mpcs->interface = PHY_INTERFACE_MODE_NA;
+}
+
 static void mtk_usxgmii_pcs_get_state(struct phylink_pcs *pcs,
 				    struct phylink_link_state *state)
 {
 	struct mtk_usxgmii_pcs *mpcs = pcs_to_mtk_usxgmii_pcs(pcs);
 	struct mtk_eth *eth = mpcs->eth;
 	struct mtk_mac *mac = eth->mac[mtk_xgmii2mac_id(eth, mpcs->id)];
-	static unsigned long t_start;
 	u32 val = 0;
 
 	regmap_read(mpcs->regmap, RG_PCS_AN_CTRL0, &val);
@@ -743,8 +776,8 @@
 	/* Reconfiguring USXGMII every second to ensure that PCS can
 	 * link up with the Link Partner when a module is inserted.
 	 */
-	if (state->link == 0 && time_after(jiffies, t_start + HZ)) {
-		t_start = jiffies;
+	if (state->link == 0 && time_after(jiffies, mpcs->link_poll_inband + HZ)) {
+		mpcs->link_poll_inband = jiffies;
 		mtk_usxgmii_pcs_config(pcs, MLO_AN_INBAND,
 				       state->interface, NULL, false);
 	}
@@ -769,7 +802,6 @@
 {
 	struct mtk_usxgmii_pcs *mpcs = pcs_to_mtk_usxgmii_pcs(pcs);
 	unsigned long t_start = jiffies;
-	unsigned int mpcs_mode;
 
 	/* Reconfiguring USXGMII to ensure the quality of the RX signal
 	 * after the line side link up.
@@ -778,18 +810,11 @@
 			       interface, NULL, false);
 
 	do {
-		msleep(1000);
+		msleep(100);
 
 		if (mtk_usxgmii_link_status(mpcs))
 			return;
 
-		spin_lock(&mpcs->regmap_lock);
-		mpcs_mode = mpcs->mode;
-		spin_unlock(&mpcs->regmap_lock);
-
-		if (mpcs_mode != MLO_AN_INBAND)
-			mtk_usxgmii_pcs_config(&mpcs->pcs, mode,
-						interface, NULL, false);
 	} while (time_before(jiffies, t_start + msecs_to_jiffies(3000)));
 
 	pr_warn("%s wait link up timeout!\n", __func__);
@@ -797,6 +822,8 @@
 
 static const struct phylink_pcs_ops mtk_usxgmii_pcs_ops = {
 	.pcs_config = mtk_usxgmii_pcs_config,
+	.pcs_enable = mtk_usxgmii_pcs_enable,
+	.pcs_disable = mtk_usxgmii_pcs_disable,
 	.pcs_get_state = mtk_usxgmii_pcs_get_state,
 	.pcs_an_restart = mtk_usxgmii_pcs_restart_an,
 	.pcs_link_up = mtk_usxgmii_pcs_link_up,
@@ -824,6 +851,8 @@
 		ss->pcs[i].pcs.poll = true;
 		ss->pcs[i].interface = PHY_INTERFACE_MODE_NA;
 
+		timer_setup(&ss->pcs[i].link_poll_outband, mtk_usxgmii_pcs_link_poll, 0);
+
 		spin_lock_init(&ss->pcs[i].regmap_lock);
 
 		of_node_put(np);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/an8801.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/an8801.c
index 2861c2e..9b8f0e5 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/an8801.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/an8801.c
@@ -1,12 +1,12 @@
-// SPDX-License-Identifier: GPL-2.0
-/* FILE NAME:  an8801.c
- * PURPOSE:
- *      Airoha phy driver for Linux
- * NOTES:
+/*SPDX-License-Identifier: GPL-2.0*/
+/*FILE NAME:  an8801.c
+ *PURPOSE:
+ *Airoha phy driver for Linux
+ *NOTES:
  *
  */
 
-/* INCLUDE FILE DECLARATIONS
+/*INCLUDE FILE DECLARATIONS
  */
 
 #include <linux/of_device.h>
@@ -24,14 +24,22 @@
 MODULE_AUTHOR("Airoha");
 MODULE_LICENSE("GPL");
 
-#define phydev_mdiobus(phy)        ((phy)->mdio.bus)
-#define phydev_mdiobus_lock(phy)   (phydev_mdiobus(phy)->mdio_lock)
+#if (KERNEL_VERSION(4, 5, 0) > LINUX_VERSION_CODE)
+#define phydev_mdiobus(_dev) (_dev->bus)
+#define phydev_phy_addr(_dev) (_dev->addr)
+#define phydev_dev(_dev) (&_dev->dev)
+#else
+#define phydev_mdiobus(_dev) (_dev->mdio.bus)
+#define phydev_phy_addr(_dev) (_dev->mdio.addr)
+#define phydev_dev(_dev) (&_dev->mdio.dev)
+#endif
 #define phydev_cfg(phy)            ((struct an8801_priv *)(phy)->priv)
-
+#define phydev_mdiobus_lock(phy)   (phydev_mdiobus(phy)->mdio_lock)
 #define mdiobus_lock(phy)          (mutex_lock(&phydev_mdiobus_lock(phy)))
 #define mdiobus_unlock(phy)        (mutex_unlock(&phydev_mdiobus_lock(phy)))
 
 #define MAX_SGMII_AN_RETRY              (100)
+#define MCS_LINK_STATUS_MASK            (BIT(2))
 
 #ifdef AN8801SB_DEBUGFS
 #define AN8801_DEBUGFS_POLARITY_HELP_STRING \
@@ -69,12 +77,6 @@
 	"\n"
 #endif
 
-#if (KERNEL_VERSION(4, 5, 0) > LINUX_VERSION_CODE)
-#define phydev_dev(_dev) (&_dev->dev)
-#else
-#define phydev_dev(_dev) (&_dev->mdio.dev)
-#endif
-
 /* For reference only
  *	GPIO1    <-> LED0,
  *	GPIO2    <-> LED1,
@@ -84,11 +86,11 @@
 static const struct AIR_LED_CFG_T led_cfg_dlt[MAX_LED_SIZE] = {
 //   LED Enable,          GPIO,    LED Polarity,      LED ON,    LED Blink
 	/* LED0 */
-	{LED_ENABLE, AIR_LED_GPIO1, AIR_ACTIVE_LOW,  AIR_LED0_ON, AIR_LED0_BLK},
+	{LED_ENABLE, AIR_LED_GPIO5, AIR_ACTIVE_LOW,  AIR_LED0_ON, AIR_LED0_BLK},
 	/* LED1 */
-	{LED_ENABLE, AIR_LED_GPIO2, AIR_ACTIVE_HIGH, AIR_LED1_ON, AIR_LED1_BLK},
+	{LED_ENABLE, AIR_LED_GPIO8, AIR_ACTIVE_LOW,  AIR_LED1_ON, AIR_LED1_BLK},
 	/* LED2 */
-	{LED_ENABLE, AIR_LED_GPIO3, AIR_ACTIVE_HIGH, AIR_LED2_ON, AIR_LED2_BLK},
+	{LED_ENABLE, AIR_LED_GPIO9, AIR_ACTIVE_LOW,  AIR_LED2_ON, AIR_LED2_BLK},
 };
 
 static const u16 led_blink_cfg_dlt = AIR_LED_BLK_DUR_64M;
@@ -107,17 +109,19 @@
 				    u32 data)
 {
 	int err = 0;
+	int phy_addr = phydev_phy_addr(phydev);
+	struct mii_bus *mbus = phydev_mdiobus(phydev);
 
-	err = __phy_write(phydev, 0x1F, 4);
+	err = mbus->write(mbus, phy_addr, 0x1F, 4);
 	if (err)
 		return err;
 
-	err |= __phy_write(phydev, 0x10, 0);
-	err |= __phy_write(phydev, 0x11, (u16)(addr >> 16));
-	err |= __phy_write(phydev, 0x12, (u16)(addr & 0xffff));
-	err |= __phy_write(phydev, 0x13, (u16)(data >> 16));
-	err |= __phy_write(phydev, 0x14, (u16)(data & 0xffff));
-	err |= __phy_write(phydev, 0x1F, 0);
+	err |= mbus->write(mbus, phy_addr, 0x10, 0);
+	err |= mbus->write(mbus, phy_addr, 0x11, (u16)(addr >> 16));
+	err |= mbus->write(mbus, phy_addr, 0x12, (u16)(addr & 0xffff));
+	err |= mbus->write(mbus, phy_addr, 0x13, (u16)(data >> 16));
+	err |= mbus->write(mbus, phy_addr, 0x14, (u16)(data & 0xffff));
+	err |= mbus->write(mbus, phy_addr, 0x1F, 0);
 
 	return err;
 }
@@ -126,17 +130,19 @@
 {
 	int err = 0;
 	u32 data_h, data_l, data;
+	int phy_addr = phydev_phy_addr(phydev);
+	struct mii_bus *mbus = phydev_mdiobus(phydev);
 
-	err = __phy_write(phydev, 0x1F, 4);
+	err = mbus->write(mbus, phy_addr, 0x1F, 4);
 	if (err)
 		return err;
 
-	err |= __phy_write(phydev, 0x10, 0);
-	err |= __phy_write(phydev, 0x15, (u16)(addr >> 16));
-	err |= __phy_write(phydev, 0x16, (u16)(addr & 0xffff));
-	data_h = __phy_read(phydev, 0x17);
-	data_l = __phy_read(phydev, 0x18);
-	err |= __phy_write(phydev, 0x1F, 0);
+	err |= mbus->write(mbus, phy_addr, 0x10, 0);
+	err |= mbus->write(mbus, phy_addr, 0x15, (u16)(addr >> 16));
+	err |= mbus->write(mbus, phy_addr, 0x16, (u16)(addr & 0xffff));
+	data_h = mbus->read(mbus, phy_addr, 0x17);
+	data_l = mbus->read(mbus, phy_addr, 0x18);
+	err |= mbus->write(mbus, phy_addr, 0x1F, 0);
 	if (err)
 		return INVALID_DATA;
 
@@ -217,7 +223,6 @@
 	u32 reg_value;
 	u8 retry = MAX_RETRY;
 
-	/* Software Reset PHY */
 	reg_value = phy_read(phydev, MII_BMCR);
 	reg_value |= BMCR_RESET;
 	phy_write(phydev, MII_BMCR, reg_value);
@@ -226,7 +231,7 @@
 		reg_value = phy_read(phydev, MII_BMCR);
 		retry--;
 		if (retry == 0) {
-			phydev_err(phydev, "Reset fail !\n");
+			dev_err(phydev_dev(phydev), "Reset fail !\n");
 			return -1;
 		}
 	} while (reg_value & BMCR_RESET);
@@ -312,14 +317,15 @@
 
 	ret = an8801_led_set_mode(phydev, AIR_LED_MODE_USER_DEFINE);
 	if (ret != 0) {
-		phydev_err(phydev, "LED fail to set mode, ret %d !\n", ret);
+		dev_err(phydev_dev(phydev),
+				"LED fail to set mode, ret %d !\n", ret);
 		return ret;
 	}
 
 	for (led_id = AIR_LED0; led_id < MAX_LED_SIZE; led_id++) {
 		ret = an8801_led_set_state(phydev, led_id, led_cfg[led_id].en);
 		if (ret != 0) {
-			phydev_err(phydev,
+			dev_err(phydev_dev(phydev),
 				   "LED fail to set LED(%d) state, ret %d !\n",
 				   led_id, ret);
 			return ret;
@@ -342,34 +348,33 @@
 				led_cfg[led_id].on_cfg,
 				led_cfg[led_id].blk_cfg);
 			if (ret != 0) {
-				phydev_err(phydev,
+				dev_err(phydev_dev(phydev),
 					   "Fail to set LED(%d) usr def, ret %d !\n",
 					   led_id, ret);
 				return ret;
 			}
 		}
 	}
-	phydev_info(phydev, "LED initialize OK !\n");
+	dev_info(phydev_dev(phydev), "LED initialize OK !\n");
 	return 0;
 }
 
 #ifdef CONFIG_OF
 static int an8801r_of_init(struct phy_device *phydev)
 {
-	struct device *dev = &phydev->mdio.dev;
-	struct device_node *of_node = dev->of_node;
+	struct device_node *of_node = phydev_dev(phydev)->of_node;
 	struct an8801_priv *priv = phydev_cfg(phydev);
 	u32 val = 0;
 
 	if (of_find_property(of_node, "airoha,rxclk-delay", NULL)) {
 		if (of_property_read_u32(of_node, "airoha,rxclk-delay",
 					 &val) != 0) {
-			phydev_err(phydev, "airoha,rxclk-delay value is invalid.");
+			dev_err(phydev_dev(phydev), "airoha,rxclk-delay value is invalid.");
 			return -1;
 		}
 		if (val < AIR_RGMII_DELAY_NOSTEP ||
 		    val > AIR_RGMII_DELAY_STEP_7) {
-			phydev_err(phydev,
+			dev_err(phydev_dev(phydev),
 				   "airoha,rxclk-delay value %u out of range.",
 				   val);
 			return -1;
@@ -383,13 +388,13 @@
 	if (of_find_property(of_node, "airoha,txclk-delay", NULL)) {
 		if (of_property_read_u32(of_node, "airoha,txclk-delay",
 					 &val) != 0) {
-			phydev_err(phydev,
+			dev_err(phydev_dev(phydev),
 				   "airoha,txclk-delay value is invalid.");
 			return -1;
 		}
 		if (val < AIR_RGMII_DELAY_NOSTEP ||
 		    val > AIR_RGMII_DELAY_STEP_7) {
-			phydev_err(phydev,
+			dev_err(phydev_dev(phydev),
 				   "airoha,txclk-delay value %u out of range.",
 				   val);
 			return -1;
@@ -397,6 +402,31 @@
 		priv->txdelay_force = TRUE;
 		priv->txdelay_step = val;
 	}
+	return 0;
+}
+
+static int an8801sb_of_init(struct phy_device *phydev)
+{
+	struct device_node *of_node = phydev_dev(phydev)->of_node;
+	struct an8801_priv *priv = phydev_cfg(phydev);
+	u32 val = 0;
+
+	priv->pol = AIR_POL_TX_NOR_RX_NOR;
+	if (of_find_property(of_node, "airoha,polarity", NULL)) {
+		if (of_property_read_u32(of_node, "airoha,polarity",
+					 &val) != 0) {
+			dev_err(phydev_dev(phydev), "airoha,polarity value is invalid.");
+			return -1;
+		}
+		if (val < AIR_POL_TX_NOR_RX_REV ||
+		    val > AIR_POL_TX_REV_RX_NOR) {
+			dev_err(phydev_dev(phydev),
+				   "airoha,polarity value %u out of range.",
+				   val);
+			return -1;
+		}
+		priv->pol = val;
+	}
 
 	return 0;
 }
@@ -405,21 +435,26 @@
 {
 	return 0;
 }
-#endif /* CONFIG_OF */
+static int an8801sb_of_init(struct phy_device *phydev)
+{
+	return 0;
+}
+#endif
+
 
 static int an8801r_rgmii_rxdelay(struct phy_device *phydev, u16 delay, u8 align)
 {
 	u32 reg_val = delay & RGMII_DELAY_STEP_MASK;
 
-	/* align */
 	if (align) {
 		reg_val |= RGMII_RXDELAY_ALIGN;
-		phydev_info(phydev, "Rxdelay align\n");
+		dev_info(phydev_dev(phydev), "Rxdelay align\n");
 	}
 	reg_val |= RGMII_RXDELAY_FORCE_MODE;
 	air_buckpbus_reg_write(phydev, 0x1021C02C, reg_val);
 	reg_val = air_buckpbus_reg_read(phydev, 0x1021C02C);
-	phydev_info(phydev, "Force rxdelay = %d(0x%x)\n", delay, reg_val);
+	dev_info(phydev_dev(phydev),
+		"Force rxdelay = %d(0x%x)\n", delay, reg_val);
 	return 0;
 }
 
@@ -430,7 +465,8 @@
 	reg_val |= RGMII_TXDELAY_FORCE_MODE;
 	air_buckpbus_reg_write(phydev, 0x1021C024, reg_val);
 	reg_val = air_buckpbus_reg_read(phydev, 0x1021C024);
-	phydev_info(phydev, "Force txdelay = %d(0x%x)\n", delay, reg_val);
+	dev_info(phydev_dev(phydev),
+		"Force txdelay = %d(0x%x)\n", delay, reg_val);
 	return 0;
 }
 
@@ -449,27 +485,64 @@
 static int an8801sb_config_init(struct phy_device *phydev)
 {
 	int ret;
+	struct an8801_priv *priv = phydev_cfg(phydev);
+	u32 pbus_value = 0;
+	u32 reg_value = 0;
+
+	reg_value = phy_read(phydev, MII_BMSR);
+	if ((reg_value & MCS_LINK_STATUS_MASK) != 0) {
+		ret = air_buckpbus_reg_write(phydev, 0x10220010, 0x1801);
+		if (ret < 0)
+			return ret;
+		reg_value = air_buckpbus_reg_read(phydev, 0x10220010);
+		dev_dbg(phydev_dev(phydev),
+			"air_buckpbus_reg_read(0x10220010,0x%x).\n", reg_value);
+
+		ret = air_buckpbus_reg_write(phydev, 0x10220000, 0x9140);
+		if (ret < 0)
+			return ret;
+		reg_value = air_buckpbus_reg_read(phydev, 0x10220000);
+		dev_dbg(phydev_dev(phydev),
+			"air_buckpbus_reg_read(0x10220000,0x%x).\n", reg_value);
+		mdelay(80);
+	}
+
+	ret = an8801sb_of_init(phydev);
+	if (ret < 0)
+		return ret;
+#ifdef CONFIG_OF
+	pbus_value = air_buckpbus_reg_read(phydev, 0x1022a0f8);
+	pbus_value &= ~0x3;
+	pbus_value |= priv->pol;
+	ret = air_buckpbus_reg_write(phydev, 0x1022a0f8, pbus_value);
+	if (ret < 0)
+		return ret;
+#endif
+	pbus_value = air_buckpbus_reg_read(phydev, 0x1022a0f8);
+	dev_info(phydev_dev(phydev),
+		"Tx, Rx Polarity : %08x\n", pbus_value);
 
-	/* disable LPM */
 	ret = an8801_cl45_write(phydev, MMD_DEV_VSPEC2, 0x600, 0x1e);
 	ret |= an8801_cl45_write(phydev, MMD_DEV_VSPEC2, 0x601, 0x02);
-	/*default disable EEE*/
-	ret |= an8801_cl45_write(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0x0);
+
+	ret |= an8801_cl45_write(phydev, 7, 60, 0x0);
 	if (ret != 0) {
-		phydev_err(phydev, "AN8801SB initialize fail, ret %d !\n", ret);
+		dev_err(phydev_dev(phydev),
+			"AN8801SB initialize fail, ret %d !\n", ret);
 		return ret;
 	}
 
 	ret = an8801_led_init(phydev);
 	if (ret != 0) {
-		phydev_err(phydev, "LED initialize fail, ret %d !\n", ret);
+		dev_err(phydev_dev(phydev),
+			"LED initialize fail, ret %d !\n", ret);
 		return ret;
 	}
 	air_buckpbus_reg_write(phydev, 0x10270100, 0x0f);
-	air_buckpbus_reg_write(phydev, 0x10270104, 0x3f);
 	air_buckpbus_reg_write(phydev, 0x10270108, 0x10100303);
-	phydev_info(phydev, "AN8801SB Initialize OK ! (%s)\n",
-		AN8801_DRIVER_VERSION);
+
+	dev_info(phydev_dev(phydev),
+		"AN8801SB Initialize OK ! (%s)\n", AN8801_DRIVER_VERSION);
 	return 0;
 }
 
@@ -496,10 +569,11 @@
 
 	ret = an8801_led_init(phydev);
 	if (ret != 0) {
-		phydev_err(phydev, "LED initialize fail, ret %d !\n", ret);
+		dev_err(phydev_dev(phydev),
+			"LED initialize fail, ret %d !\n", ret);
 		return ret;
 	}
-	phydev_info(phydev, "AN8801R Initialize OK ! (%s)\n",
+	dev_info(phydev_dev(phydev), "AN8801R Initialize OK ! (%s)\n",
 		AN8801_DRIVER_VERSION);
 	return 0;
 }
@@ -511,7 +585,7 @@
 	} else if (phydev->interface == PHY_INTERFACE_MODE_RGMII) {
 		an8801r_config_init(phydev);
 	} else {
-		phydev_info(phydev, "AN8801 Phy-mode not support!!!\n");
+		dev_info(phydev_dev(phydev), "AN8801 Phy-mode not support!!!\n");
 		return -1;
 	}
 	return 0;
@@ -613,39 +687,100 @@
 	struct phy_device *phydev = seq->private;
 	int ret = 0;
 	u32 pkt_cnt = 0;
+	struct mii_bus *mbus = phydev_mdiobus(phydev);
 
 	seq_puts(seq, "==========AIR PHY COUNTER==========\n");
-	seq_puts(seq, "|\t<<FCM COUNTER>>\n");
-	seq_puts(seq, "| Rx from Line side_S    :");
+	seq_puts(seq, "|\t<<SERDES COUNTER>>\n");
+	air_buckpbus_reg_write(phydev, 0x10226124, 0xaa);
+	air_buckpbus_reg_write(phydev, 0x10226124, 0x0);
+	seq_puts(seq, "| PHY Rx DV CNT           :");
+	pkt_cnt = air_buckpbus_reg_read(phydev, 0x1022614c);
+	seq_printf(seq, "%010u |\n", pkt_cnt);
+	seq_puts(seq, "| PHY Tx EN CNT           :");
+	pkt_cnt = air_buckpbus_reg_read(phydev, 0x10226148);
+	seq_printf(seq, "%010u |\n", pkt_cnt);
+	seq_puts(seq, "|  Tx ER CNT              :");
+	pkt_cnt = air_buckpbus_reg_read(phydev, 0x10226150);
+	seq_printf(seq, "%010u |\n", pkt_cnt);
+	seq_puts(seq, "| MAC Rx DV CNT           :");
+	pkt_cnt = air_buckpbus_reg_read(phydev, 0x10226138);
+	seq_printf(seq, "%010u |\n", pkt_cnt);
+	seq_puts(seq, "| MAC Tx EN CNT           :");
+	pkt_cnt = air_buckpbus_reg_read(phydev, 0x1022612C);
+	seq_printf(seq, "%010u |\n", pkt_cnt);
+	seq_puts(seq, "| Tx ER CNT               :");
+	pkt_cnt = air_buckpbus_reg_read(phydev, 0x10226130);
+	seq_printf(seq, "%010u |\n", pkt_cnt);
+	ret = air_buckpbus_reg_write(phydev, 0x10226124, 0x55);
+	ret |= air_buckpbus_reg_write(phydev, 0x10226124, 0x0);
+	if (ret < 0)
+		seq_puts(seq, "| Clear Serdes Counter fail\n");
+	else
+		seq_puts(seq, "| Clear Serdes Counter!!\n");
+
+	seq_puts(seq, "|\t<<EFIFO COUNTER>>\n");
+	seq_puts(seq, "| Rx from Line side_S     :");
 	pkt_cnt = air_buckpbus_reg_read(phydev, 0x10270130);
 	seq_printf(seq, "%010u |\n", pkt_cnt);
-	seq_puts(seq, "| Rx from Line side_E    :");
+	seq_puts(seq, "| Rx from Line side_E     :");
 	pkt_cnt = air_buckpbus_reg_read(phydev, 0x10270134);
 	seq_printf(seq, "%010u |\n", pkt_cnt);
-	seq_puts(seq, "| Tx to System side_S    :");
+	seq_puts(seq, "| Tx to System side_S     :");
 	pkt_cnt = air_buckpbus_reg_read(phydev, 0x10270138);
 	seq_printf(seq, "%010u |\n", pkt_cnt);
-	seq_puts(seq, "| Tx to System side_E    :");
+	seq_puts(seq, "| Tx to System side_E     :");
 	pkt_cnt = air_buckpbus_reg_read(phydev, 0x1027013C);
 	seq_printf(seq, "%010u |\n", pkt_cnt);
-	seq_puts(seq, "| Rx from System side_S  :");
+	seq_puts(seq, "| Rx from System side_S   :");
 	pkt_cnt = air_buckpbus_reg_read(phydev, 0x10270120);
 	seq_printf(seq, "%010u |\n", pkt_cnt);
-	seq_puts(seq, "| Rx from System side_E  :");
+	seq_puts(seq, "| Rx from System side_E   :");
 	pkt_cnt = air_buckpbus_reg_read(phydev, 0x10270124);
 	seq_printf(seq, "%010u |\n", pkt_cnt);
-	seq_puts(seq, "| Tx to Line side_S      :");
+	seq_puts(seq, "| Tx to Line side_S       :");
 	pkt_cnt = air_buckpbus_reg_read(phydev, 0x10270128);
 	seq_printf(seq, "%010u |\n", pkt_cnt);
-	seq_puts(seq, "| Tx to Line side_E      :");
+	seq_puts(seq, "| Tx to Line side_E       :");
 	pkt_cnt = air_buckpbus_reg_read(phydev, 0x1027012C);
 	seq_printf(seq, "%010u |\n", pkt_cnt);
 
 	ret = air_buckpbus_reg_write(phydev, 0x1027011C, 0x3);
 	if (ret < 0)
-		seq_printf(seq, "\nClear Counter fail\n", __func__);
+		seq_puts(seq, "| Clear EFIFO Counter fail\n");
 	else
-		seq_puts(seq, "\nClear Counter!!\n");
+		seq_puts(seq, "| Clear EFIFO Counter!!\n");
+
+	seq_puts(seq, "|\t<<LS Counter>>\n");
+	ret = phy_write(phydev, 0x1f, 1);
+	if (ret < 0)
+		return ret;
+	seq_puts(seq, "| Rx from Line side       :");
+	pkt_cnt = phy_read(phydev, 0x12) & 0x7fff;
+	seq_printf(seq, "%010u |\n", pkt_cnt);
+	seq_puts(seq, "| Rx Error from Line side :");
+	pkt_cnt = phy_read(phydev, 0x17) & 0xff;
+	seq_printf(seq, "%010u |\n", pkt_cnt);
+
+	ret = phy_write(phydev, 0x1f, 0);
+	if (ret < 0)
+		return ret;
+	ret = phy_write(phydev, 0x1f, 0x52B5);
+	if (ret < 0)
+		return ret;
+	ret = phy_write(phydev, 0x10, 0xBF92);
+	if (ret < 0)
+		return ret;
+
+	seq_puts(seq, "| Tx to Line side         :");
+	pkt_cnt = (phy_read(phydev, 0x11) & 0x7ffe) >> 1;
+	seq_printf(seq, "%010u |\n", pkt_cnt);
+	seq_puts(seq, "| Tx Error to Line side   :");
+	pkt_cnt = phy_read(phydev, 0x12);
+	pkt_cnt &= 0x7f;
+	seq_printf(seq, "%010u |\n\n", pkt_cnt);
+	ret = phy_write(phydev, 0x1f, 0);
+	if (ret < 0)
+		return ret;
 
 	return ret;
 }
@@ -771,11 +906,11 @@
 	int ret = 0;
 	struct an8801_priv *priv = phydev->priv;
 
-	phydev_info(phydev, "Debugfs init start\n");
+	dev_info(phydev_dev(phydev), "Debugfs init start\n");
 	priv->debugfs_root =
 		debugfs_create_dir(dev_name(phydev_dev(phydev)), NULL);
 	if (!priv->debugfs_root) {
-		phydev_err(phydev, "Debugfs init err\n");
+		dev_err(phydev_dev(phydev), "Debugfs init err\n");
 		ret = -ENOMEM;
 	}
 	debugfs_create_file(DEBUGFS_DRIVER_INFO, 0444,
@@ -807,21 +942,23 @@
 static int an8801_phy_probe(struct phy_device *phydev)
 {
 	u32 reg_value, phy_id, led_id;
-	struct device *dev = &phydev->mdio.dev;
 	struct an8801_priv *priv = NULL;
 
 	reg_value = phy_read(phydev, 2);
 	phy_id = reg_value << 16;
 	reg_value = phy_read(phydev, 3);
 	phy_id |= reg_value;
-	phydev_info(phydev, "PHY-ID = %x\n", phy_id);
+	dev_info(phydev_dev(phydev), "PHY-ID = %x\n", phy_id);
 
 	if (phy_id != AN8801_PHY_ID) {
-		phydev_err(phydev, "AN8801 can't be detected.\n");
+		dev_err(phydev_dev(phydev),
+			"AN8801 can't be detected.\n");
 		return -1;
 	}
 
-	priv = devm_kzalloc(dev, sizeof(struct an8801_priv), GFP_KERNEL);
+	priv = devm_kzalloc(phydev_dev(phydev)
+						, sizeof(struct an8801_priv)
+						, GFP_KERNEL);
 	if (!priv)
 		return -ENOMEM;
 
@@ -849,7 +986,7 @@
 			return ret;
 		}
 	} else {
-		phydev_info(phydev, "AN8801R not supprt debugfs\n");
+		dev_info(phydev_dev(phydev), "AN8801R not supprt debugfs\n");
 	}
 #endif
 	return 0;
@@ -864,7 +1001,7 @@
 		air_debugfs_remove(phydev);
 #endif
 		kfree(priv);
-		phydev_info(phydev, "AN8801 remove OK!\n");
+		dev_info(phydev_dev(phydev), "AN8801 remove OK!\n");
 	}
 }
 
@@ -886,7 +1023,7 @@
 		prespeed = phydev->speed;
 		ret |= an8801_cl45_write(
 			phydev, MMD_DEV_VSPEC2, PHY_PRE_SPEED_REG, prespeed);
-		phydev_info(phydev, "AN8801SB SPEED %d\n", prespeed);
+		dev_info(phydev_dev(phydev), "AN8801SB SPEED %d\n", prespeed);
 		air_buckpbus_reg_write(phydev, 0x10270108, 0x0a0a0404);
 		while (an_retry > 0) {
 			mdelay(1);       /* delay 1 ms */
@@ -900,7 +1037,7 @@
 
 
 		if (phydev->autoneg == AUTONEG_DISABLE) {
-			phydev_info(phydev,
+			dev_info(phydev_dev(phydev),
 				"AN8801SB force speed = %d\n", prespeed);
 			if (prespeed == SPEED_1000) {
 				air_buckpbus_reg_write(
@@ -938,7 +1075,7 @@
 	}
 	if (prespeed != phydev->speed && phydev->link == LINK_UP) {
 		prespeed = phydev->speed;
-		phydev_dbg(phydev, "AN8801R SPEED %d\n", prespeed);
+		dev_dbg(phydev_dev(phydev), "AN8801R SPEED %d\n", prespeed);
 		if (prespeed == SPEED_1000) {
 			data = air_buckpbus_reg_read(phydev, 0x10005054);
 			data |= BIT(0);
@@ -959,7 +1096,7 @@
 	} else if (phydev->interface == PHY_INTERFACE_MODE_RGMII) {
 		an8801r_read_status(phydev);
 	} else {
-		phydev_info(phydev, "AN8801 Phy-mode not support!\n");
+		dev_info(phydev_dev(phydev), "AN8801 Phy-mode not support!\n");
 		return -1;
 	}
 	return 0;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/an8801.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/an8801.h
index e94c7c1..9d1d2fa 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/an8801.h
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/an8801.h
@@ -1,9 +1,9 @@
-// SPDX-License-Identifier: GPL-2.0
-/* FILE NAME:  an8801.h
- * PURPOSE:
- *      Define Airoha phy driver function
+/*SPDX-License-Identifier: GPL-2.0*/
+/*FILE NAME:  an8801.h
+ *PURPOSE:
+ *Define Airoha phy driver function
  *
- * NOTES:
+ *NOTES:
  *
  */
 
@@ -12,7 +12,7 @@
 
 /* NAMING DECLARATIONS
  */
-#define AN8801_DRIVER_VERSION  "1.1.0"
+#define AN8801_DRIVER_VERSION  "1.1.3"
 
 #define DEBUGFS_COUNTER         "counter"
 #define DEBUGFS_DRIVER_INFO     "driver_info"
@@ -202,6 +202,7 @@
 #ifdef AN8801SB_DEBUGFS
 	struct dentry        *debugfs_root;
 #endif
+	int                   pol;
 };
 
 enum an8801_polarity {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3001-mt7622-backport-nf-hw-offload-framework-and-upstream.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3001-mt7622-backport-nf-hw-offload-framework-and-upstream.patch
index 4a9bfae..d2bde5e 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3001-mt7622-backport-nf-hw-offload-framework-and-upstream.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3001-mt7622-backport-nf-hw-offload-framework-and-upstream.patch
@@ -1,6 +1,6 @@
-From 35623475d9eb8522756b0b4833c95a31a0ceb10b Mon Sep 17 00:00:00 2001
-From: Bo Jiao <Bo.Jiao@mediatek.com>
-Date: Mon, 18 Sep 2023 10:52:27 +0800
+From fdcf6ba6449ebc18a908a7c66164ee6a7f463ae0 Mon Sep 17 00:00:00 2001
+From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
+Date: Tue, 28 May 2024 16:51:32 +0800
 Subject: [PATCH 01/24] mt7622 backport nf hw offload framework and upstream
  hnat plus xt-FLOWOFFLOAD update v2
 
@@ -22,6 +22,7 @@
  .../net/netfilter/ipv6/nf_conntrack_ipv6.h    |    3 -
  include/net/netfilter/nf_conntrack.h          |   14 +
  include/net/netfilter/nf_conntrack_acct.h     |   11 +
+ include/net/netfilter/nf_conntrack_l4proto.h  |    7 +
  include/net/netfilter/nf_flow_table.h         |  268 +++-
  include/net/netns/conntrack.h                 |    6 +
  .../linux/netfilter/nf_conntrack_common.h     |    9 +-
@@ -39,14 +40,14 @@
  net/netfilter/Kconfig                         |   14 +-
  net/netfilter/Makefile                        |    4 +-
  net/netfilter/nf_conntrack_core.c             |   20 +-
- net/netfilter/nf_conntrack_proto_tcp.c        |    4 +
+ net/netfilter/nf_conntrack_proto_tcp.c        |   10 +-
  net/netfilter/nf_conntrack_proto_udp.c        |    4 +
  net/netfilter/nf_conntrack_standalone.c       |   34 +-
- net/netfilter/nf_flow_table_core.c            |  462 ++++---
+ net/netfilter/nf_flow_table_core.c            |  470 ++++---
  net/netfilter/nf_flow_table_ip.c              |  447 +++---
  net/netfilter/nf_flow_table_offload.c         | 1199 +++++++++++++++++
- net/netfilter/xt_FLOWOFFLOAD.c                |  800 +++++++++++
- 41 files changed, 4999 insertions(+), 435 deletions(-)
+ net/netfilter/xt_FLOWOFFLOAD.c                |  780 +++++++++++
+ 42 files changed, 4983 insertions(+), 452 deletions(-)
  mode change 100644 => 100755 drivers/net/ethernet/mediatek/Makefile
  mode change 100644 => 100755 drivers/net/ethernet/mediatek/mtk_eth_soc.c
  mode change 100644 => 100755 drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -76,10 +77,10 @@
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 old mode 100644
 new mode 100755
-index 37fd338..20b2943
+index cf5a7d6..d7959db
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -4001,6 +4001,7 @@ static int mtk_open(struct net_device *dev)
+@@ -4011,6 +4011,7 @@ static int mtk_open(struct net_device *dev)
  	u32 id = mtk_mac2xgmii_id(eth, mac->id);
  	int err, i;
  	struct device_node *phy_node;
@@ -87,7 +88,7 @@
  
  	err = phylink_of_phy_connect(mac->phylink, mac->of_node, 0);
  	if (err) {
-@@ -4085,7 +4086,10 @@ static int mtk_open(struct net_device *dev)
+@@ -4095,7 +4096,10 @@ static int mtk_open(struct net_device *dev)
  		regmap_write(eth->sgmii->pcs[id].regmap,
  			     SGMSYS_QPHY_PWR_STATE_CTRL, 0);
  
@@ -99,7 +100,7 @@
  
  	return 0;
  }
-@@ -4172,6 +4176,9 @@ static int mtk_stop(struct net_device *dev)
+@@ -4182,6 +4186,9 @@ static int mtk_stop(struct net_device *dev)
  
  	mtk_dma_free(eth);
  
@@ -109,7 +110,7 @@
  	return 0;
  }
  
-@@ -5081,6 +5088,7 @@ static const struct net_device_ops mtk_netdev_ops = {
+@@ -5102,6 +5109,7 @@ static const struct net_device_ops mtk_netdev_ops = {
  #ifdef CONFIG_NET_POLL_CONTROLLER
  	.ndo_poll_controller	= mtk_poll_controller,
  #endif
@@ -117,7 +118,7 @@
  };
  
  static void mux_poll(struct work_struct *work)
-@@ -5711,6 +5719,17 @@ static int mtk_probe(struct platform_device *pdev)
+@@ -5771,6 +5779,17 @@ static int mtk_probe(struct platform_device *pdev)
  			goto err_free_dev;
  	}
  
@@ -135,7 +136,7 @@
  	for (i = 0; i < MTK_MAX_DEVS; i++) {
  		if (!eth->netdev[i])
  			continue;
-@@ -5811,6 +5830,7 @@ static const struct mtk_soc_data mt2701_data = {
+@@ -5872,6 +5891,7 @@ static const struct mtk_soc_data mt2701_data = {
  	.required_clks = MT7623_CLKS_BITMAP,
  	.required_pctl = true,
  	.has_sram = false,
@@ -143,7 +144,7 @@
  	.rss_num = 0,
  	.txrx = {
  		.txd_size = sizeof(struct mtk_tx_dma),
-@@ -5828,6 +5848,7 @@ static const struct mtk_soc_data mt7621_data = {
+@@ -5892,6 +5912,7 @@ static const struct mtk_soc_data mt7621_data = {
  	.required_clks = MT7621_CLKS_BITMAP,
  	.required_pctl = false,
  	.has_sram = false,
@@ -151,7 +152,7 @@
  	.rss_num = 0,
  	.txrx = {
  		.txd_size = sizeof(struct mtk_tx_dma),
-@@ -5846,6 +5867,7 @@ static const struct mtk_soc_data mt7622_data = {
+@@ -5913,6 +5934,7 @@ static const struct mtk_soc_data mt7622_data = {
  	.required_clks = MT7622_CLKS_BITMAP,
  	.required_pctl = false,
  	.has_sram = false,
@@ -159,7 +160,7 @@
  	.rss_num = 0,
  	.txrx = {
  		.txd_size = sizeof(struct mtk_tx_dma),
-@@ -5863,6 +5885,7 @@ static const struct mtk_soc_data mt7623_data = {
+@@ -5933,6 +5955,7 @@ static const struct mtk_soc_data mt7623_data = {
  	.required_clks = MT7623_CLKS_BITMAP,
  	.required_pctl = true,
  	.has_sram = false,
@@ -170,7 +171,7 @@
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
 old mode 100644
 new mode 100755
-index 26a99d1..4d3a63c
+index 9fae48f..54b2c7c
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
 @@ -15,6 +15,8 @@
@@ -182,7 +183,7 @@
  
  #define MTK_QDMA_PAGE_SIZE	2048
  #define	MTK_MAX_RX_LENGTH	1536
-@@ -47,7 +49,8 @@
+@@ -46,7 +48,8 @@
  				 NETIF_F_HW_VLAN_CTAG_TX | \
  				 NETIF_F_SG | NETIF_F_TSO | \
  				 NETIF_F_TSO6 | \
@@ -192,7 +193,7 @@
  #define MTK_SET_FEATURES	(NETIF_F_LRO | \
  				 NETIF_F_HW_VLAN_CTAG_RX)
  #define MTK_HW_FEATURES_MT7628	(NETIF_F_SG | NETIF_F_RXCSUM)
-@@ -134,6 +137,7 @@
+@@ -133,6 +136,7 @@
  #define MTK_GDMA_UCS_EN		BIT(20)
  #define MTK_GDMA_STRP_CRC	BIT(16)
  #define MTK_GDMA_TO_PDMA	0x0
@@ -200,7 +201,7 @@
  #define MTK_GDMA_DROP_ALL	0x7777
  
  /* GDM Egress Control Register */
-@@ -661,6 +665,12 @@
+@@ -686,6 +690,12 @@
  #define RX_DMA_TCI(_x)		((_x) & (VLAN_PRIO_MASK | VLAN_VID_MASK))
  #define RX_DMA_VPID(_x)		(((_x) >> 16) & 0xffff)
  
@@ -213,7 +214,7 @@
  /* QDMA descriptor rxd4 */
  #define RX_DMA_L4_VALID		BIT(24)
  #define RX_DMA_L4_VALID_PDMA	BIT(30)		/* when PDMA is used */
-@@ -1712,6 +1722,7 @@ struct mtk_soc_data {
+@@ -1737,6 +1747,7 @@ struct mtk_soc_data {
  	u64		caps;
  	u64		required_clks;
  	bool		required_pctl;
@@ -221,9 +222,9 @@
  	netdev_features_t hw_features;
  	bool		has_sram;
  	struct {
-@@ -1912,6 +1923,9 @@ struct mtk_eth {
- 	int				ip_align;
+@@ -1947,6 +1958,9 @@ struct mtk_eth {
  	spinlock_t			syscfg0_lock;
+ 	struct notifier_block		netdevice_notifier;
  	struct timer_list		mtk_dma_monitor_timer;
 +
 +	struct mtk_ppe			ppe;
@@ -231,9 +232,9 @@
  };
  
  /* struct mtk_mac -	the structure that holds the info about the MACs of the
-@@ -1993,6 +2007,9 @@ int mtk_toprgu_init(struct mtk_eth *eth, struct device_node *r);
- int mtk_dump_usxgmii(struct regmap *pmap, char *name, u32 offset, u32 range);
- void mtk_usxgmii_link_poll(struct work_struct *work);
+@@ -2026,6 +2040,9 @@ struct phylink_pcs *mtk_usxgmii_select_pcs(struct mtk_usxgmii *ss, int id);
+ int mtk_usxgmii_init(struct mtk_eth *eth, struct device_node *r);
+ int mtk_toprgu_init(struct mtk_eth *eth, struct device_node *r);
  
 +int mtk_eth_offload_init(struct mtk_eth *eth);
 +int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type,
@@ -2043,7 +2044,7 @@
  
  static int pppoe_recvmsg(struct socket *sock, struct msghdr *m,
 diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
-index 1c1ab37..44842a2 100644
+index ac36fe9..2d1aa35 100644
 --- a/include/linux/netdevice.h
 +++ b/include/linux/netdevice.h
 @@ -843,6 +843,59 @@ typedef u16 (*select_queue_fallback_t)(struct net_device *dev,
@@ -2210,7 +2211,7 @@
 -
  #endif /* _NF_CONNTRACK_IPV6_H*/
 diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
-index 90690e3..38a8d3f 100644
+index 90690e3..ce0bc3e 100644
 --- a/include/net/netfilter/nf_conntrack.h
 +++ b/include/net/netfilter/nf_conntrack.h
 @@ -105,6 +105,8 @@ struct nf_conn {
@@ -2222,7 +2223,7 @@
  };
  
  static inline struct nf_conn *
-@@ -279,6 +281,18 @@ static inline bool nf_ct_should_gc(const struct nf_conn *ct)
+@@ -279,6 +279,18 @@ static inline bool nf_ct_should_gc(const struct nf_conn *ct)
  	       !nf_ct_is_dying(ct);
  }
  
@@ -2263,6 +2264,24 @@
  void nf_conntrack_acct_pernet_init(struct net *net);
  
  int nf_conntrack_acct_init(void);
+diff --git a/include/net/netfilter/nf_conntrack_l4proto.h b/include/net/netfilter/nf_conntrack_l4proto.h
+index 4cad1f0..886ac6b 100644
+--- a/include/net/netfilter/nf_conntrack_l4proto.h
++++ b/include/net/netfilter/nf_conntrack_l4proto.h
+@@ -203,6 +203,13 @@ static inline struct nf_icmp_net *nf_icmpv6_pernet(struct net *net)
+ }
+ #endif
+ 
++/* Caller must check nf_ct_protonum(ct) is IPPROTO_TCP before calling. */
++static bool nf_conntrack_tcp_established(const struct nf_conn *ct)
++{
++	return ct->proto.tcp.state == TCP_CONNTRACK_ESTABLISHED &&
++	       test_bit(IPS_ASSURED_BIT, &ct->status);
++}
++
+ #ifdef CONFIG_NF_CT_PROTO_DCCP
+ static inline struct nf_dccp_net *nf_dccp_pernet(struct net *net)
+ {
 diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h
 index 68d7fc9..7374cb2 100644
 --- a/include/net/netfilter/nf_flow_table.h
@@ -2724,10 +2743,10 @@
  
  static void vlan_dev_free(struct net_device *dev)
 diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
-index ab201d5..deec45b 100644
+index 44bdb01..03934dd 100644
 --- a/net/bridge/br_device.c
 +++ b/net/bridge/br_device.c
-@@ -385,6 +385,54 @@ static int br_del_slave(struct net_device *dev, struct net_device *slave_dev)
+@@ -387,6 +387,54 @@ static int br_del_slave(struct net_device *dev, struct net_device *slave_dev)
  	return br_del_if(br, slave_dev);
  }
  
@@ -2782,7 +2801,7 @@
  static const struct ethtool_ops br_ethtool_ops = {
  	.get_drvinfo    = br_getinfo,
  	.get_link	= ethtool_op_get_link,
-@@ -418,6 +466,7 @@ static const struct net_device_ops br_netdev_ops = {
+@@ -420,6 +468,7 @@ static const struct net_device_ops br_netdev_ops = {
  	.ndo_bridge_setlink	 = br_setlink,
  	.ndo_bridge_dellink	 = br_dellink,
  	.ndo_features_check	 = passthru_features_check,
@@ -2895,7 +2914,7 @@
  		     struct bridge_vlan_info *p_vinfo)
  {
 diff --git a/net/core/dev.c b/net/core/dev.c
-index ef7362b..5bade26 100644
+index 9da89f2..e9dd11e 100644
 --- a/net/core/dev.c
 +++ b/net/core/dev.c
 @@ -722,6 +722,52 @@ int dev_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
@@ -3042,10 +3061,10 @@
  	tristate "Netfilter IPv4 packet duplication to alternate destination"
  	depends on !NF_CONNTRACK || NF_CONNTRACK
 diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
-index 816275b..671f767 100644
+index c67d634..ef836d6 100644
 --- a/net/ipv6/ip6_output.c
 +++ b/net/ipv6/ip6_output.c
-@@ -607,7 +607,7 @@ int ip6_forward(struct sk_buff *skb)
+@@ -613,7 +613,7 @@ int ip6_forward(struct sk_buff *skb)
  		}
  	}
  
@@ -3076,7 +3095,7 @@
  	tristate "Netfilter IPv6 packet duplication to alternate destination"
  	depends on !NF_CONNTRACK || NF_CONNTRACK
 diff --git a/net/ipv6/route.c b/net/ipv6/route.c
-index 43d185c..82a752c 100644
+index d99d12a..29d6fd2 100644
 --- a/net/ipv6/route.c
 +++ b/net/ipv6/route.c
 @@ -83,7 +83,7 @@ enum rt6_nud_state {
@@ -3250,10 +3269,23 @@
  	return nf_ct_delete(ct, 0, 0);
  }
 diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
-index e219b6f..5cdc627 100644
+index e219b6f..65e406f 100644
 --- a/net/netfilter/nf_conntrack_proto_tcp.c
 +++ b/net/netfilter/nf_conntrack_proto_tcp.c
-@@ -1463,6 +1463,10 @@ void nf_conntrack_tcp_init_net(struct net *net)
+@@ -840,12 +840,6 @@ static noinline bool tcp_new(struct nf_conn *ct, const struct sk_buff *skb,
+ 	return true;
+ }
+ 
+-static bool nf_conntrack_tcp_established(const struct nf_conn *ct)
+-{
+-	return ct->proto.tcp.state == TCP_CONNTRACK_ESTABLISHED &&
+-	       test_bit(IPS_ASSURED_BIT, &ct->status);
+-}
+-
+ static void nf_ct_tcp_state_reset(struct ip_ct_tcp_state *state)
+ {
+ 	state->td_end		= 0;
+@@ -1463,6 +1457,10 @@ void nf_conntrack_tcp_init_net(struct net *net)
  	tn->tcp_loose = nf_ct_tcp_loose;
  	tn->tcp_be_liberal = nf_ct_tcp_be_liberal;
  	tn->tcp_max_retrans = nf_ct_tcp_max_retrans;
@@ -3365,7 +3397,7 @@
  	nf_conntrack_standalone_init_tcp_sysctl(net, table);
  	nf_conntrack_standalone_init_sctp_sysctl(net, table);
 diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c
-index f212cec..c3054af 100644
+index f212cec..a342d92 100644
 --- a/net/netfilter/nf_flow_table_core.c
 +++ b/net/netfilter/nf_flow_table_core.c
 @@ -7,43 +7,21 @@
@@ -3486,7 +3518,7 @@
  err_ct_refcnt:
  	nf_ct_put(ct);
  
-@@ -115,40 +73,135 @@ flow_offload_alloc(struct nf_conn *ct, struct nf_flow_route *route)
+@@ -115,65 +73,158 @@ flow_offload_alloc(struct nf_conn *ct, struct nf_flow_route *route)
  }
  EXPORT_SYMBOL_GPL(flow_offload_alloc);
  
@@ -3560,24 +3592,39 @@
 +
 +	return 0;
 +}
-+
+ 
+-static inline __s32 nf_flow_timeout_delta(unsigned int timeout)
 +static void nft_flow_dst_release(struct flow_offload *flow,
 +				 enum flow_offload_tuple_dir dir)
-+{
+ {
+-	return (__s32)(timeout - (u32)jiffies);
 +	if (flow->tuplehash[dir].tuple.xmit_type == FLOW_OFFLOAD_XMIT_NEIGH ||
 +	    flow->tuplehash[dir].tuple.xmit_type == FLOW_OFFLOAD_XMIT_XFRM)
 +		dst_release(flow->tuplehash[dir].tuple.dst_cache);
-+}
-+
+ }
+ 
+-static void flow_offload_fixup_ct_timeout(struct nf_conn *ct)
 +int flow_offload_route_init(struct flow_offload *flow,
 +			    const struct nf_flow_route *route)
-+{
+ {
+-	const struct nf_conntrack_l4proto *l4proto;
+-	int l4num = nf_ct_protonum(ct);
+-	unsigned int timeout;
 +	int err;
-+
+ 
+-	l4proto = nf_ct_l4proto_find(l4num);
+-	if (!l4proto)
+-		return;
 +	err = flow_offload_fill_route(flow, route, FLOW_OFFLOAD_DIR_ORIGINAL);
 +	if (err < 0)
 +		return err;
-+
+ 
+-	if (l4num == IPPROTO_TCP)
+-		timeout = NF_FLOWTABLE_TCP_PICKUP_TIMEOUT;
+-	else if (l4num == IPPROTO_UDP)
+-		timeout = NF_FLOWTABLE_UDP_PICKUP_TIMEOUT;
+-	else
+-		return;
 +	err = flow_offload_fill_route(flow, route, FLOW_OFFLOAD_DIR_REPLY);
 +	if (err < 0)
 +		goto err_route_reply;
@@ -3588,64 +3635,56 @@
 +
 +err_route_reply:
 +	nft_flow_dst_release(flow, FLOW_OFFLOAD_DIR_ORIGINAL);
-+
+ 
+-	if (nf_flow_timeout_delta(ct->timeout) > (__s32)timeout)
+-		ct->timeout = nfct_time_stamp + timeout;
 +	return err;
-+}
+ }
 +EXPORT_SYMBOL_GPL(flow_offload_route_init);
  
--static inline __s32 nf_flow_timeout_delta(unsigned int timeout)
+-static void flow_offload_fixup_ct_state(struct nf_conn *ct)
 +static void flow_offload_fixup_tcp(struct ip_ct_tcp *tcp)
  {
--	return (__s32)(timeout - (u32)jiffies);
-+	tcp->state = TCP_CONNTRACK_ESTABLISHED;
+-	if (nf_ct_protonum(ct) == IPPROTO_TCP)
+-		flow_offload_fixup_tcp(&ct->proto.tcp);
 +	tcp->seen[0].td_maxwin = 0;
 +	tcp->seen[1].td_maxwin = 0;
  }
  
- static void flow_offload_fixup_ct_timeout(struct nf_conn *ct)
+ static void flow_offload_fixup_ct(struct nf_conn *ct)
  {
--	const struct nf_conntrack_l4proto *l4proto;
+-	flow_offload_fixup_ct_state(ct);
+-	flow_offload_fixup_ct_timeout(ct);
 +	struct net *net = nf_ct_net(ct);
- 	int l4num = nf_ct_protonum(ct);
--	unsigned int timeout;
++	int l4num = nf_ct_protonum(ct);
 +	s32 timeout;
- 
--	l4proto = nf_ct_l4proto_find(l4num);
--	if (!l4proto)
--		return;
++
 +	if (l4num == IPPROTO_TCP) {
 +		struct nf_tcp_net *tn = nf_tcp_pernet(net);
- 
--	if (l4num == IPPROTO_TCP)
--		timeout = NF_FLOWTABLE_TCP_PICKUP_TIMEOUT;
--	else if (l4num == IPPROTO_UDP)
--		timeout = NF_FLOWTABLE_UDP_PICKUP_TIMEOUT;
--	else
-+		timeout = tn->timeouts[TCP_CONNTRACK_ESTABLISHED];
++
++		flow_offload_fixup_tcp(&ct->proto.tcp);
++
++		timeout = tn->timeouts[ct->proto.tcp.state];
 +		timeout -= tn->offload_timeout;
 +	} else if (l4num == IPPROTO_UDP) {
 +		struct nf_udp_net *tn = nf_udp_pernet(net);
++		enum udp_conntrack state =
++			test_bit(IPS_SEEN_REPLY_BIT, &ct->status) ?
++			UDP_CT_REPLIED : UDP_CT_UNREPLIED;
 +
-+		timeout = tn->timeouts[UDP_CT_REPLIED];
++		timeout = tn->timeouts[state];
 +		timeout -= tn->offload_timeout;
 +	} else {
- 		return;
++		return;
 +	}
 +
 +	if (timeout < 0)
 +		timeout = 0;
- 
--	if (nf_flow_timeout_delta(ct->timeout) > (__s32)timeout)
--		ct->timeout = nfct_time_stamp + timeout;
++
 +	if (nf_flow_timeout_delta(READ_ONCE(ct->timeout)) > (__s32)timeout)
 +		WRITE_ONCE(ct->timeout, nfct_time_stamp + timeout);
  }
  
- static void flow_offload_fixup_ct_state(struct nf_conn *ct)
-@@ -163,17 +216,23 @@ static void flow_offload_fixup_ct(struct nf_conn *ct)
- 	flow_offload_fixup_ct_timeout(ct);
- }
- 
 -void flow_offload_free(struct flow_offload *flow)
 +static void flow_offload_route_release(struct flow_offload *flow)
  {
@@ -3675,7 +3714,7 @@
  }
  EXPORT_SYMBOL_GPL(flow_offload_free);
  
-@@ -181,14 +240,14 @@ static u32 flow_offload_hash(const void *data, u32 len, u32 seed)
+@@ -181,14 +232,14 @@ static u32 flow_offload_hash(const void *data, u32 len, u32 seed)
  {
  	const struct flow_offload_tuple *tuple = data;
  
@@ -3692,7 +3731,7 @@
  }
  
  static int flow_offload_hash_cmp(struct rhashtable_compare_arg *arg,
-@@ -197,7 +256,7 @@ static int flow_offload_hash_cmp(struct rhashtable_compare_arg *arg,
+@@ -197,7 +248,7 @@ static int flow_offload_hash_cmp(struct rhashtable_compare_arg *arg,
  	const struct flow_offload_tuple *tuple = arg->key;
  	const struct flow_offload_tuple_rhash *x = ptr;
  
@@ -3701,7 +3740,7 @@
  		return 1;
  
  	return 0;
-@@ -211,30 +270,30 @@ static const struct rhashtable_params nf_flow_offload_rhash_params = {
+@@ -211,30 +262,30 @@ static const struct rhashtable_params nf_flow_offload_rhash_params = {
  	.automatic_shrinking	= true,
  };
  
@@ -3719,21 +3758,21 @@
 +	unsigned long timeout = NF_FLOW_TIMEOUT;
 +	struct net *net = nf_ct_net(flow->ct);
 +	int l4num = nf_ct_protonum(flow->ct);
- 
--	entry = container_of(flow, struct flow_offload_entry, flow);
--	ct = entry->ct;
++
 +	if (l4num == IPPROTO_TCP) {
 +		struct nf_tcp_net *tn = nf_tcp_pernet(net);
  
--	if (nf_ct_expires(ct) < DAY / 2)
--		ct->timeout = nfct_time_stamp + DAY;
+-	entry = container_of(flow, struct flow_offload_entry, flow);
+-	ct = entry->ct;
 +		timeout = tn->offload_timeout;
 +	} else if (l4num == IPPROTO_UDP) {
 +		struct nf_udp_net *tn = nf_udp_pernet(net);
 +
 +		timeout = tn->offload_timeout;
 +	}
-+
+ 
+-	if (nf_ct_expires(ct) < DAY / 2)
+-		ct->timeout = nfct_time_stamp + DAY;
 +	return timeout;
  }
  
@@ -3747,7 +3786,7 @@
  
  	err = rhashtable_insert_fast(&flow_table->rhashtable,
  				     &flow->tuplehash[0].node,
-@@ -252,10 +311,35 @@ int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow)
+@@ -252,10 +303,35 @@ int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow)
  		return err;
  	}
  
@@ -3783,7 +3822,7 @@
  static inline bool nf_flow_has_expired(const struct flow_offload *flow)
  {
  	return nf_flow_timeout_delta(flow->timeout) <= 0;
-@@ -264,8 +348,6 @@ static inline bool nf_flow_has_expired(const struct flow_offload *flow)
+@@ -264,8 +340,6 @@ static inline bool nf_flow_has_expired(const struct flow_offload *flow)
  static void flow_offload_del(struct nf_flowtable *flow_table,
  			     struct flow_offload *flow)
  {
@@ -3792,25 +3831,21 @@
  	rhashtable_remove_fast(&flow_table->rhashtable,
  			       &flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].node,
  			       nf_flow_offload_rhash_params);
-@@ -273,28 +355,21 @@ static void flow_offload_del(struct nf_flowtable *flow_table,
+@@ -273,28 +347,15 @@ static void flow_offload_del(struct nf_flowtable *flow_table,
  			       &flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].node,
  			       nf_flow_offload_rhash_params);
  
 -	e = container_of(flow, struct flow_offload_entry, flow);
 -	clear_bit(IPS_OFFLOAD_BIT, &e->ct->status);
-+	clear_bit(IPS_OFFLOAD_BIT, &flow->ct->status);
- 
- 	if (nf_flow_has_expired(flow))
+-
+-	if (nf_flow_has_expired(flow))
 -		flow_offload_fixup_ct(e->ct);
 -	else if (flow->flags & FLOW_OFFLOAD_TEARDOWN)
 -		flow_offload_fixup_ct_timeout(e->ct);
 -
 -	if (!(flow->flags & FLOW_OFFLOAD_TEARDOWN))
 -		flow_offload_fixup_ct_state(e->ct);
-+		flow_offload_fixup_ct(flow->ct);
-+	else
-+		flow_offload_fixup_ct_timeout(flow->ct);
- 
+-
  	flow_offload_free(flow);
  }
  
@@ -3819,15 +3854,16 @@
 -	struct flow_offload_entry *e;
 -
 -	flow->flags |= FLOW_OFFLOAD_TEARDOWN;
++	clear_bit(IPS_OFFLOAD_BIT, &flow->ct->status);
 +	set_bit(NF_FLOW_TEARDOWN, &flow->flags);
  
 -	e = container_of(flow, struct flow_offload_entry, flow);
 -	flow_offload_fixup_ct_state(e->ct);
-+	flow_offload_fixup_ct_state(flow->ct);
++	flow_offload_fixup_ct(flow->ct);
  }
  EXPORT_SYMBOL_GPL(flow_offload_teardown);
  
-@@ -304,7 +379,6 @@ flow_offload_lookup(struct nf_flowtable *flow_table,
+@@ -304,7 +365,6 @@ flow_offload_lookup(struct nf_flowtable *flow_table,
  {
  	struct flow_offload_tuple_rhash *tuplehash;
  	struct flow_offload *flow;
@@ -3835,7 +3871,7 @@
  	int dir;
  
  	tuplehash = rhashtable_lookup(&flow_table->rhashtable, tuple,
-@@ -314,19 +388,17 @@ flow_offload_lookup(struct nf_flowtable *flow_table,
+@@ -314,19 +374,17 @@ flow_offload_lookup(struct nf_flowtable *flow_table,
  
  	dir = tuplehash->tuple.dir;
  	flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]);
@@ -3858,7 +3894,7 @@
  		      void (*iter)(struct flow_offload *flow, void *data),
  		      void *data)
  {
-@@ -339,7 +411,6 @@ nf_flow_table_iterate(struct nf_flowtable *flow_table,
+@@ -339,7 +397,6 @@ nf_flow_table_iterate(struct nf_flowtable *flow_table,
  	rhashtable_walk_start(&hti);
  
  	while ((tuplehash = rhashtable_walk_next(&hti))) {
@@ -3866,7 +3902,7 @@
  		if (IS_ERR(tuplehash)) {
  			if (PTR_ERR(tuplehash) != -EAGAIN) {
  				err = PTR_ERR(tuplehash);
-@@ -359,23 +430,52 @@ nf_flow_table_iterate(struct nf_flowtable *flow_table,
+@@ -359,23 +416,52 @@ nf_flow_table_iterate(struct nf_flowtable *flow_table,
  
  	return err;
  }
@@ -3910,7 +3946,7 @@
 +	if (nf_flow_has_expired(flow) ||
 +	    nf_ct_is_dying(flow->ct) ||
 +	    nf_flow_has_stale_dst(flow))
-+		set_bit(NF_FLOW_TEARDOWN, &flow->flags);
++		flow_offload_teardown(flow);
 +
 +	if (test_bit(NF_FLOW_TEARDOWN, &flow->flags)) {
 +		if (test_bit(NF_FLOW_HW, &flow->flags)) {
@@ -3930,7 +3966,7 @@
  }
  
  static void nf_flow_offload_work_gc(struct work_struct *work)
-@@ -387,30 +487,20 @@ static void nf_flow_offload_work_gc(struct work_struct *work)
+@@ -387,30 +473,20 @@ static void nf_flow_offload_work_gc(struct work_struct *work)
  	queue_delayed_work(system_power_efficient_wq, &flow_table->gc_work, HZ);
  }
  
@@ -3965,7 +4001,7 @@
  	udph = (void *)(skb_network_header(skb) + thoff);
  	if (udph->check || skb->ip_summed == CHECKSUM_PARTIAL) {
  		inet_proto_csum_replace2(&udph->check, skb, port,
-@@ -418,38 +508,28 @@ static int nf_flow_nat_port_udp(struct sk_buff *skb, unsigned int thoff,
+@@ -418,38 +494,28 @@ static int nf_flow_nat_port_udp(struct sk_buff *skb, unsigned int thoff,
  		if (!udph->check)
  			udph->check = CSUM_MANGLED_0;
  	}
@@ -4011,7 +4047,7 @@
  	hdr = (void *)(skb_network_header(skb) + thoff);
  
  	switch (dir) {
-@@ -463,25 +543,19 @@ int nf_flow_snat_port(const struct flow_offload *flow,
+@@ -463,25 +529,19 @@ int nf_flow_snat_port(const struct flow_offload *flow,
  		new_port = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.src_port;
  		hdr->dest = new_port;
  		break;
@@ -4041,7 +4077,7 @@
  	hdr = (void *)(skb_network_header(skb) + thoff);
  
  	switch (dir) {
-@@ -495,11 +569,9 @@ int nf_flow_dnat_port(const struct flow_offload *flow,
+@@ -495,11 +555,9 @@ int nf_flow_dnat_port(const struct flow_offload *flow,
  		new_port = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.dst_port;
  		hdr->source = new_port;
  		break;
@@ -4054,7 +4090,7 @@
  }
  EXPORT_SYMBOL_GPL(nf_flow_dnat_port);
  
-@@ -507,7 +579,9 @@ int nf_flow_table_init(struct nf_flowtable *flowtable)
+@@ -507,7 +565,9 @@ int nf_flow_table_init(struct nf_flowtable *flowtable)
  {
  	int err;
  
@@ -4065,7 +4101,7 @@
  
  	err = rhashtable_init(&flowtable->rhashtable,
  			      &nf_flow_offload_rhash_params);
-@@ -528,25 +602,24 @@ EXPORT_SYMBOL_GPL(nf_flow_table_init);
+@@ -528,25 +588,24 @@ EXPORT_SYMBOL_GPL(nf_flow_table_init);
  static void nf_flow_table_do_cleanup(struct flow_offload *flow, void *data)
  {
  	struct net_device *dev = data;
@@ -4097,7 +4133,7 @@
  }
  
  void nf_flow_table_cleanup(struct net_device *dev)
-@@ -555,7 +628,7 @@ void nf_flow_table_cleanup(struct net_device *dev)
+@@ -555,7 +614,7 @@ void nf_flow_table_cleanup(struct net_device *dev)
  
  	mutex_lock(&flowtable_lock);
  	list_for_each_entry(flowtable, &flowtables, list)
@@ -4106,7 +4142,7 @@
  	mutex_unlock(&flowtable_lock);
  }
  EXPORT_SYMBOL_GPL(nf_flow_table_cleanup);
-@@ -565,9 +638,14 @@ void nf_flow_table_free(struct nf_flowtable *flow_table)
+@@ -565,9 +624,14 @@ void nf_flow_table_free(struct nf_flowtable *flow_table)
  	mutex_lock(&flowtable_lock);
  	list_del(&flow_table->list);
  	mutex_unlock(&flowtable_lock);
@@ -4121,7 +4157,7 @@
  	rhashtable_destroy(&flow_table->rhashtable);
  }
  EXPORT_SYMBOL_GPL(nf_flow_table_free);
-@@ -591,12 +669,23 @@ static struct notifier_block flow_offload_netdev_notifier = {
+@@ -591,12 +655,23 @@ static struct notifier_block flow_offload_netdev_notifier = {
  
  static int __init nf_flow_table_module_init(void)
  {
@@ -4146,7 +4182,7 @@
  }
  
  module_init(nf_flow_table_module_init);
-@@ -604,3 +693,4 @@ module_exit(nf_flow_table_module_exit);
+@@ -604,3 +679,4 @@ module_exit(nf_flow_table_module_exit);
  
  MODULE_LICENSE("GPL");
  MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
@@ -6086,10 +6122,10 @@
 +}
 diff --git a/net/netfilter/xt_FLOWOFFLOAD.c b/net/netfilter/xt_FLOWOFFLOAD.c
 new file mode 100644
-index 0000000..e4c7db9
+index 0000000..9120c60
 --- /dev/null
 +++ b/net/netfilter/xt_FLOWOFFLOAD.c
-@@ -0,0 +1,800 @@
+@@ -0,0 +1,780 @@
 +/*
 + * Copyright (C) 2018-2021 Felix Fietkau <nbd@nbd.name>
 + *
@@ -6104,6 +6140,7 @@
 +#include <linux/if_vlan.h>
 +#include <net/ip.h>
 +#include <net/netfilter/nf_conntrack.h>
++#include <net/netfilter/nf_conntrack_core.h>
 +#include <net/netfilter/nf_conntrack_extend.h>
 +#include <net/netfilter/nf_conntrack_helper.h>
 +#include <net/netfilter/nf_flow_table.h>
@@ -6457,53 +6494,34 @@
 +	if (!nf_is_valid_ether_device(dev))
 +		goto out;
 +
-+	if (ct->status & IPS_NAT_MASK || ct->inet6_mode == CT_INET_MODE_IPV6) {
-+		n = dst_neigh_lookup(dst_cache, daddr);
-+		if (!n)
-+			return -1;
++	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);
++	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;
-+	}
++	if (!(nud_state & NUD_VALID))
++		return -1;
 +
 +out:
 +	return dev_fill_forward_path(dev, ha, stack);
 +}
 +
-+static int nf_dev_forward_path(struct sk_buff *skb,
-+				struct nf_flow_route *route,
++static int 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 ethhdr *eth;
-+	enum ip_conntrack_dir skb_dir;
 +	struct net_device_path_stack stack;
 +	struct nf_forward_info info = {};
 +	unsigned char ha[ETH_ALEN];
 +	int i;
 +
-+	if (!(ct->status & IPS_NAT_MASK) && skb_mac_header_was_set(skb) &&
-+	    ct->inet6_mode != CT_INET_MODE_IPV6) {
-+		eth = eth_hdr(skb);
-+		skb_dir = CTINFO2DIR(skb_get_nfct(skb) & NFCT_INFOMASK);
-+
-+		if (skb_dir != dir) {
-+			memcpy(ha, eth->h_source, ETH_ALEN);
-+			memcpy(info.h_source, eth->h_dest, ETH_ALEN);
-+		} else {
-+			memcpy(ha, eth->h_dest, ETH_ALEN);
-+			memcpy(info.h_source, eth->h_source, ETH_ALEN);
-+		}
-+	}
-+
 +	if (nf_dev_fill_forward_path(route, dst, ct, dir, ha, &stack) >= 0)
 +		nf_dev_path_info(&stack, &info, ha);
 +
@@ -6593,9 +6611,9 @@
 +
 +	if (route->tuple[dir].xmit_type	== FLOW_OFFLOAD_XMIT_NEIGH &&
 +	    route->tuple[!dir].xmit_type == FLOW_OFFLOAD_XMIT_NEIGH) {
-+		if (nf_dev_forward_path(skb, route, ct, dir, devs))
++		if (nf_dev_forward_path(route, ct, dir, devs))
 +			return -1;
-+		if (nf_dev_forward_path(skb, route, ct, !dir, devs))
++		if (nf_dev_forward_path(route, ct, !dir, devs))
 +			return -1;
 +	}
 +
@@ -6624,8 +6642,8 @@
 +
 +	if (route->tuple[dir].xmit_type	== FLOW_OFFLOAD_XMIT_NEIGH &&
 +	    route->tuple[!dir].xmit_type == FLOW_OFFLOAD_XMIT_NEIGH) {
-+		if (nf_dev_forward_path(skb, route, ct, dir, devs) ||
-+		    nf_dev_forward_path(skb, route, ct, !dir, devs)) {
++		if (nf_dev_forward_path(route, ct, dir, devs) ||
++		    nf_dev_forward_path(route, ct, !dir, devs)) {
 +			ret = -1;
 +			goto err_route_dir2;
 +		}
@@ -6663,12 +6681,10 @@
 +
 +	switch (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum) {
 +	case IPPROTO_TCP:
-+		if (ct->proto.tcp.state != TCP_CONNTRACK_ESTABLISHED)
-+			return XT_CONTINUE;
-+
 +		tcph = skb_header_pointer(skb, par->thoff,
 +					  sizeof(_tcph), &_tcph);
-+		if (unlikely(!tcph || tcph->fin || tcph->rst))
++		if (unlikely(!tcph || tcph->fin || tcph->rst ||
++			     !nf_conntrack_tcp_established(ct)))
 +			return XT_CONTINUE;
 +		break;
 +	case IPPROTO_UDP:
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3003-add-wed.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3003-add-wed.patch
index a60b6ce..050bf10 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3003-add-wed.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3003-add-wed.patch
@@ -1,13 +1,13 @@
-From b895d23fa63dd712191b6d223fe6c41682c7d375 Mon Sep 17 00:00:00 2001
+From d61de8847d9d566958b15f1f64e2fde6fa7502eb Mon Sep 17 00:00:00 2001
 From: Sujuan Chen <sujuan.chen@mediatek.com>
 Date: Mon, 18 Sep 2023 10:56:21 +0800
-Subject: [PATCH 03/24] add wed
+Subject: [PATCH 04/26] add wed
 
 ---
  arch/arm64/boot/dts/mediatek/mt7622.dtsi      |  32 +-
  drivers/net/ethernet/mediatek/Kconfig         |   4 +
  drivers/net/ethernet/mediatek/Makefile        |   5 +
- drivers/net/ethernet/mediatek/mtk_eth_soc.c   |  39 +-
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c   |  56 +-
  drivers/net/ethernet/mediatek/mtk_eth_soc.h   |   5 +-
  drivers/net/ethernet/mediatek/mtk_ppe.c       | 378 +++++++-
  drivers/net/ethernet/mediatek/mtk_ppe.h       |  89 +-
@@ -15,13 +15,13 @@
  .../net/ethernet/mediatek/mtk_ppe_offload.c   | 167 +++-
  drivers/net/ethernet/mediatek/mtk_wed.c       | 881 ++++++++++++++++++
  drivers/net/ethernet/mediatek/mtk_wed.h       | 135 +++
- .../net/ethernet/mediatek/mtk_wed_debugfs.c   | 175 ++++
+ .../net/ethernet/mediatek/mtk_wed_debugfs.c   | 173 ++++
  drivers/net/ethernet/mediatek/mtk_wed_ops.c   |   8 +
  drivers/net/ethernet/mediatek/mtk_wed_regs.h  | 251 +++++
  include/linux/netdevice.h                     |   7 +
  include/linux/soc/mediatek/mtk_wed.h          | 131 +++
  net/core/dev.c                                |   4 +
- 17 files changed, 2212 insertions(+), 103 deletions(-)
+ 17 files changed, 2222 insertions(+), 108 deletions(-)
  mode change 100755 => 100644 drivers/net/ethernet/mediatek/Kconfig
  mode change 100755 => 100644 drivers/net/ethernet/mediatek/Makefile
  mode change 100755 => 100644 drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -134,10 +134,10 @@
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 old mode 100755
 new mode 100644
-index 20b2943..8d15399
+index 19af710..6cbf84f
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -21,11 +21,13 @@
+@@ -22,11 +22,13 @@
  #include <linux/pinctrl/devinfo.h>
  #include <linux/phylink.h>
  #include <linux/gpio/consumer.h>
@@ -151,7 +151,7 @@
  
  #if defined(CONFIG_NET_MEDIATEK_HNAT) || defined(CONFIG_NET_MEDIATEK_HNAT_MODULE)
  #include "mtk_hnat/nf_hnat_mtk.h"
-@@ -2356,6 +2358,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
+@@ -2355,6 +2357,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
  		struct net_device *netdev = NULL;
  		dma_addr_t dma_addr = DMA_MAPPING_ERROR;
  		u64 addr64 = 0;
@@ -159,7 +159,7 @@
  		int mac = 0;
  
  		idx = NEXT_DESP_IDX(ring->calc_idx, ring->dma_size);
-@@ -2444,6 +2447,17 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
+@@ -2443,6 +2446,17 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
  			skb_checksum_none_assert(skb);
  		skb->protocol = eth_type_trans(skb, netdev);
  
@@ -177,7 +177,7 @@
  		if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) {
  			if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_RX_V2)) {
  				if (trxd.rxd3 & RX_DMA_VTAG_V2)
-@@ -4177,7 +4191,7 @@ static int mtk_stop(struct net_device *dev)
+@@ -4187,7 +4201,7 @@ static int mtk_stop(struct net_device *dev)
  	mtk_dma_free(eth);
  
  	if (eth->soc->offload_version)
@@ -186,7 +186,7 @@
  
  	return 0;
  }
-@@ -5560,6 +5574,22 @@ static int mtk_probe(struct platform_device *pdev)
+@@ -5620,6 +5634,22 @@ static int mtk_probe(struct platform_device *pdev)
  		}
  	}
  
@@ -209,7 +209,45 @@
  	if (MTK_HAS_CAPS(eth->soc->caps, MTK_PDMA_INT)) {
  		for (i = 0; i < MTK_PDMA_IRQ_NUM; i++)
  			eth->irq_pdma[i] = platform_get_irq(pdev, i);
-@@ -5720,10 +5750,11 @@ static int mtk_probe(struct platform_device *pdev)
+@@ -5636,7 +5666,8 @@ static int mtk_probe(struct platform_device *pdev)
+ 
+ 		if (eth->irq_fe[i] < 0) {
+ 			dev_err(&pdev->dev, "no IRQ%d resource found\n", i);
+-			return -ENXIO;
++			err = -ENXIO;
++			goto err_wed_exit;
+ 		}
+ 	}
+ 
+@@ -5644,12 +5675,15 @@ static int mtk_probe(struct platform_device *pdev)
+ 		eth->clks[i] = devm_clk_get(eth->dev,
+ 					    mtk_clks_source_name[i]);
+ 		if (IS_ERR(eth->clks[i])) {
+-			if (PTR_ERR(eth->clks[i]) == -EPROBE_DEFER)
+-				return -EPROBE_DEFER;
++			if (PTR_ERR(eth->clks[i]) == -EPROBE_DEFER) {
++				err = -EPROBE_DEFER;
++				goto err_wed_exit;
++			}
+ 			if (eth->soc->required_clks & BIT(i)) {
+ 				dev_err(&pdev->dev, "clock %s not found\n",
+ 					mtk_clks_source_name[i]);
+-				return -EINVAL;
++				err = -EINVAL;
++				goto err_wed_exit;
+ 			}
+ 			eth->clks[i] = NULL;
+ 		}
+@@ -5660,7 +5694,7 @@ static int mtk_probe(struct platform_device *pdev)
+ 
+ 	err = mtk_hw_init(eth, MTK_TYPE_COLD_RESET);
+ 	if (err)
+-		return err;
++		goto err_wed_exit;
+ 
+ 	eth->hwlro = MTK_HAS_CAPS(eth->soc->caps, MTK_HWLRO);
+ 
+@@ -5780,10 +5814,11 @@ static int mtk_probe(struct platform_device *pdev)
  	}
  
  	if (eth->soc->offload_version) {
@@ -224,13 +262,30 @@
  
  		err = mtk_eth_offload_init(eth);
  		if (err)
+@@ -5847,6 +5882,8 @@ static int mtk_probe(struct platform_device *pdev)
+ 	mtk_free_dev(eth);
+ err_deinit_hw:
+ 	mtk_hw_deinit(eth);
++err_wed_exit:
++	mtk_wed_exit();
+ 
+ 	return err;
+ }
+@@ -5866,6 +5903,7 @@ static int mtk_remove(struct platform_device *pdev)
+ 		phylink_disconnect_phy(mac->phylink);
+ 	}
+ 
++	mtk_wed_exit();
+ 	mtk_hw_deinit(eth);
+ 
+ 	netif_napi_del(&eth->tx_napi);
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
 old mode 100755
 new mode 100644
-index 4d3a63c..00cfe3b
+index 54b2c7c..5ede64c
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -615,6 +615,9 @@
+@@ -640,6 +640,9 @@
  #define RX_DMA_SPORT_MASK       0x7
  #define RX_DMA_SPORT_MASK_V2    0xf
  
@@ -240,8 +295,8 @@
  /* QDMA descriptor txd4 */
  #define TX_DMA_CHKSUM		(0x7 << 29)
  #define TX_DMA_TSO		BIT(28)
-@@ -1924,7 +1927,7 @@ struct mtk_eth {
- 	spinlock_t			syscfg0_lock;
+@@ -1959,7 +1962,7 @@ struct mtk_eth {
+ 	struct notifier_block		netdevice_notifier;
  	struct timer_list		mtk_dma_monitor_timer;
  
 -	struct mtk_ppe			ppe;
@@ -1262,7 +1317,7 @@
  	return rhashtable_init(&eth->flow_table, &mtk_flow_ht_params);
 diff --git a/drivers/net/ethernet/mediatek/mtk_wed.c b/drivers/net/ethernet/mediatek/mtk_wed.c
 new file mode 100644
-index 0000000..affa704
+index 0000000..9982c88
 --- /dev/null
 +++ b/drivers/net/ethernet/mediatek/mtk_wed.c
 @@ -0,0 +1,881 @@
@@ -2142,7 +2197,7 @@
 +			continue;
 +
 +		hw_list[i] = NULL;
-+		debugfs_remove(hw->debugfs_dir);
++		debugfs_remove_recursive(hw->debugfs_dir);
 +		put_device(hw->dev);
 +		kfree(hw);
 +	}
@@ -2290,10 +2345,10 @@
 +#endif
 diff --git a/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c b/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c
 new file mode 100644
-index 0000000..a81d3fd
+index 0000000..8ad7252
 --- /dev/null
 +++ b/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c
-@@ -0,0 +1,175 @@
+@@ -0,0 +1,173 @@
 +// SPDX-License-Identifier: GPL-2.0-only
 +/* Copyright (C) 2021 Felix Fietkau <nbd@nbd.name> */
 +
@@ -2461,8 +2516,6 @@
 +
 +	snprintf(hw->dirname, sizeof(hw->dirname), "wed%d", hw->index);
 +	dir = debugfs_create_dir(hw->dirname, NULL);
-+	if (!dir)
-+		return;
 +
 +	hw->debugfs_dir = dir;
 +	debugfs_create_u32("regidx", 0600, dir, &hw->debugfs_reg);
@@ -2741,7 +2794,7 @@
 +
 +#endif
 diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
-index 44842a2..5305384 100644
+index 2d1aa35..85d582c 100644
 --- a/include/linux/netdevice.h
 +++ b/include/linux/netdevice.h
 @@ -849,6 +849,7 @@ enum net_device_path_type {
@@ -2903,7 +2956,7 @@
 +
 +#endif
 diff --git a/net/core/dev.c b/net/core/dev.c
-index 5bade26..0775e8d 100644
+index e9dd11e..64d3e41 100644
 --- a/net/core/dev.c
 +++ b/net/core/dev.c
 @@ -758,6 +758,10 @@ int dev_fill_forward_path(const struct net_device *dev, const u8 *daddr,
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3005-flow-offload-add-mkhnat-dual-ppe-new-v2.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3005-flow-offload-add-mkhnat-dual-ppe-new-v2.patch
index 5ff363b..f581048 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3005-flow-offload-add-mkhnat-dual-ppe-new-v2.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3005-flow-offload-add-mkhnat-dual-ppe-new-v2.patch
@@ -1,7 +1,7 @@
-From 01556d88ad11f0d096d2816b2a69999994e1740f Mon Sep 17 00:00:00 2001
+From 226c1fcb4c878a4275e7727a7b62596ddc4fc2c8 Mon Sep 17 00:00:00 2001
 From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
 Date: Mon, 18 Mar 2024 16:26:28 +0800
-Subject: [PATCH 05/24] flow-offload-add-mkhnat-dual-ppe-new-v2
+Subject: [PATCH 06/26] flow-offload-add-mkhnat-dual-ppe-new-v2
 
 ---
  arch/arm64/boot/dts/mediatek/mt7986a.dtsi     |  1 +
@@ -28,10 +28,10 @@
                  #address-cells = <1>;
                  #size-cells = <0>;
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 2fb67e0..7eeddb3 100644
+index a621a14..e284538 100644
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -2464,7 +2464,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
+@@ -2459,7 +2459,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
  #endif
  
  		if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED)
@@ -40,7 +40,7 @@
  
  		if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) {
  			if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_RX_V2)) {
-@@ -4112,8 +4112,12 @@ static int mtk_open(struct net_device *dev)
+@@ -4114,8 +4114,12 @@ static int mtk_open(struct net_device *dev)
  		regmap_write(eth->sgmii->pcs[id].regmap,
  			     SGMSYS_QPHY_PWR_STATE_CTRL, 0);
  
@@ -55,7 +55,7 @@
  
  	mtk_gdm_config(eth, mac->id, gdm_config);
  
-@@ -4202,8 +4206,10 @@ static int mtk_stop(struct net_device *dev)
+@@ -4204,8 +4208,10 @@ static int mtk_stop(struct net_device *dev)
  
  	mtk_dma_free(eth);
  
@@ -68,7 +68,7 @@
  
  	return 0;
  }
-@@ -5762,15 +5768,35 @@ static int mtk_probe(struct platform_device *pdev)
+@@ -5818,15 +5824,35 @@ static int mtk_probe(struct platform_device *pdev)
  	}
  
  	if (eth->soc->offload_version) {
@@ -112,10 +112,10 @@
  
  	for (i = 0; i < MTK_MAX_DEVS; i++) {
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-index 910baaf..3995608 100644
+index ba2e17a..4cf8fca 100644
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -137,7 +137,12 @@
+@@ -136,7 +136,12 @@
  #define MTK_GDMA_UCS_EN		BIT(20)
  #define MTK_GDMA_STRP_CRC	BIT(16)
  #define MTK_GDMA_TO_PDMA	0x0
@@ -129,8 +129,8 @@
  #define MTK_GDMA_DROP_ALL	0x7777
  
  /* GDM Egress Control Register */
-@@ -1936,7 +1941,8 @@ struct mtk_eth {
- 	spinlock_t			syscfg0_lock;
+@@ -1967,7 +1972,8 @@ struct mtk_eth {
+ 	struct notifier_block		netdevice_notifier;
  	struct timer_list		mtk_dma_monitor_timer;
  
 -	struct mtk_ppe			*ppe;
@@ -139,9 +139,9 @@
  	struct rhashtable		flow_table;
  };
  
-@@ -2019,9 +2025,11 @@ int mtk_toprgu_init(struct mtk_eth *eth, struct device_node *r);
- int mtk_dump_usxgmii(struct regmap *pmap, char *name, u32 offset, u32 range);
- void mtk_usxgmii_link_poll(struct work_struct *work);
+@@ -2048,9 +2054,11 @@ struct phylink_pcs *mtk_usxgmii_select_pcs(struct mtk_usxgmii *ss, int id);
+ int mtk_usxgmii_init(struct mtk_eth *eth, struct device_node *r);
+ int mtk_toprgu_init(struct mtk_eth *eth, struct device_node *r);
  
 -int mtk_eth_offload_init(struct mtk_eth *eth);
 +int mtk_eth_offload_init(struct mtk_eth *eth, int id);
@@ -437,7 +437,7 @@
  
  	return rhashtable_init(&eth->flow_table, &mtk_flow_ht_params);
 diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
-index 5305384..b2abebe 100644
+index 85d582c..0a7eb9a 100644
 --- a/include/linux/netdevice.h
 +++ b/include/linux/netdevice.h
 @@ -1316,6 +1316,8 @@ struct tlsdev_ops;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3006-add-wed-tx-support-for-netsys2.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3006-add-wed-tx-support-for-netsys2.patch
index 5197d21..c44fd0f 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3006-add-wed-tx-support-for-netsys2.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3006-add-wed-tx-support-for-netsys2.patch
@@ -1,7 +1,7 @@
-From 56e9bf306919ffb33d45951541d908cd7d21c081 Mon Sep 17 00:00:00 2001
+From ff7b25716f5a51c15c8f66d9358588a0f29632b8 Mon Sep 17 00:00:00 2001
 From: Bo Jiao <Bo.Jiao@mediatek.com>
 Date: Mon, 18 Sep 2023 11:01:55 +0800
-Subject: [PATCH 06/24] add-wed-tx-support-for-netsys2
+Subject: [PATCH 07/26] add-wed-tx-support-for-netsys2
 
 ---
  arch/arm64/boot/dts/mediatek/mt7981.dtsi      |   1 +
@@ -105,10 +105,10 @@
  	};
  
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 07209f0..268c9e7 100644
+index e284538..a1dcb0a 100644
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -5476,6 +5476,7 @@ static int mtk_probe(struct platform_device *pdev)
+@@ -5525,6 +5525,7 @@ static int mtk_probe(struct platform_device *pdev)
  {
  	struct device_node *mac_np, *mux_np;
  	struct mtk_eth *eth;
@@ -116,7 +116,7 @@
  	int err, i;
  
  	eth = devm_kzalloc(&pdev->dev, sizeof(*eth), GFP_KERNEL);
-@@ -5498,13 +5499,12 @@ static int mtk_probe(struct platform_device *pdev)
+@@ -5549,13 +5550,12 @@ static int mtk_probe(struct platform_device *pdev)
  		eth->sram_base = (void __force *)eth->base + MTK_ETH_SRAM_OFFSET;
  	}
  
@@ -135,7 +135,7 @@
  
  	mtk_get_hwver(eth);
  
-@@ -5593,20 +5593,25 @@ static int mtk_probe(struct platform_device *pdev)
+@@ -5644,20 +5644,25 @@ static int mtk_probe(struct platform_device *pdev)
  		}
  	}
  
@@ -174,10 +174,10 @@
  
  	if (MTK_HAS_CAPS(eth->soc->caps, MTK_PDMA_INT)) {
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-index a00583f..9099dea 100644
+index 4cf8fca..14a2390 100644
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -620,9 +620,6 @@
+@@ -645,9 +645,6 @@
  #define RX_DMA_SPORT_MASK       0x7
  #define RX_DMA_SPORT_MASK_V2    0xf
  
@@ -188,7 +188,7 @@
  #define TX_DMA_CHKSUM		(0x7 << 29)
  #define TX_DMA_TSO		BIT(28)
 diff --git a/drivers/net/ethernet/mediatek/mtk_wed.c b/drivers/net/ethernet/mediatek/mtk_wed.c
-index affa704..02e06a8 100644
+index 9982c88..c40c82a 100644
 --- a/drivers/net/ethernet/mediatek/mtk_wed.c
 +++ b/drivers/net/ethernet/mediatek/mtk_wed.c
 @@ -18,15 +18,6 @@
@@ -1001,7 +1001,7 @@
  void mtk_wed_exit(void)
 @@ -876,6 +1138,7 @@ void mtk_wed_exit(void)
  		hw_list[i] = NULL;
- 		debugfs_remove(hw->debugfs_dir);
+ 		debugfs_remove_recursive(hw->debugfs_dir);
  		put_device(hw->dev);
 +		of_node_put(hw->node);
  		kfree(hw);
@@ -1065,7 +1065,7 @@
  }
  static inline void
 diff --git a/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c b/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c
-index a81d3fd..f420f18 100644
+index 8ad7252..20cca20 100644
 --- a/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c
 +++ b/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c
 @@ -116,6 +116,9 @@ wed_txinfo_show(struct seq_file *s, void *data)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3012-flow-offload-add-mtkhnat-qdma-qos.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3012-flow-offload-add-mtkhnat-qdma-qos.patch
index ba80883..7792485 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3012-flow-offload-add-mtkhnat-qdma-qos.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3012-flow-offload-add-mtkhnat-qdma-qos.patch
@@ -1,19 +1,19 @@
-From 51573e91708521bdc47a9d6f771f2cbde11e5ed7 Mon Sep 17 00:00:00 2001
+From 1892dfe5c26f58f5831a34485ea00241d8e6ae1a Mon Sep 17 00:00:00 2001
 From: "chak-kei.lam" <chak-kei.lam@mediatek.com>
 Date: Tue, 9 Apr 2024 15:05:24 +0800
-Subject: [PATCH 12/24] flow-offload-add-mtkhnat-qdma-qos
+Subject: [PATCH 13/26] flow-offload-add-mtkhnat-qdma-qos
 
 ---
  drivers/net/ethernet/mediatek/Makefile        |   2 +-
  drivers/net/ethernet/mediatek/mtk_eth_soc.c   |  10 +
- drivers/net/ethernet/mediatek/mtk_eth_soc.h   |  50 ++
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h   |  44 ++
  drivers/net/ethernet/mediatek/mtk_ppe.c       |  48 +-
  drivers/net/ethernet/mediatek/mtk_ppe.h       |   4 +
  .../net/ethernet/mediatek/mtk_ppe_offload.c   |  28 +-
  .../net/ethernet/mediatek/mtk_qdma_debugfs.c  | 448 ++++++++++++++++++
  include/net/flow_offload.h                    |   1 +
  net/netfilter/nf_flow_table_offload.c         |   4 +-
- 9 files changed, 590 insertions(+), 5 deletions(-)
+ 9 files changed, 584 insertions(+), 5 deletions(-)
  create mode 100644 drivers/net/ethernet/mediatek/mtk_qdma_debugfs.c
 
 diff --git a/drivers/net/ethernet/mediatek/Makefile b/drivers/net/ethernet/mediatek/Makefile
@@ -30,10 +30,10 @@
  ifdef CONFIG_DEBUG_FS
  mtk_eth-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed_debugfs.o
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 60672c6..8e3a276 100644
+index 63d1cc3..b6293c2 100644
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -5838,6 +5838,8 @@ static int mtk_probe(struct platform_device *pdev)
+@@ -5868,6 +5868,8 @@ static int mtk_probe(struct platform_device *pdev)
  		}
  
  		mtk_ppe_debugfs_init(eth);
@@ -42,7 +42,7 @@
  	}
  
  	for (i = 0; i < MTK_MAX_DEVS; i++) {
-@@ -5953,6 +5955,7 @@ static const struct mtk_soc_data mt2701_data = {
+@@ -5987,6 +5989,7 @@ static const struct mtk_soc_data mt2701_data = {
  		.rx_dma_l4_valid = RX_DMA_L4_VALID,
  		.dma_max_len = MTK_TX_DMA_BUF_LEN,
  		.dma_len_offset = MTK_TX_DMA_BUF_SHIFT,
@@ -50,7 +50,7 @@
  	},
  };
  
-@@ -5976,6 +5979,7 @@ static const struct mtk_soc_data mt7621_data = {
+@@ -6010,6 +6013,7 @@ static const struct mtk_soc_data mt7621_data = {
  		.rxd_size = sizeof(struct mtk_rx_dma),
  		.dma_max_len = MTK_TX_DMA_BUF_LEN,
  		.dma_len_offset = MTK_TX_DMA_BUF_SHIFT,
@@ -58,7 +58,7 @@
  	},
  };
  
-@@ -6000,6 +6004,7 @@ static const struct mtk_soc_data mt7622_data = {
+@@ -6034,6 +6038,7 @@ static const struct mtk_soc_data mt7622_data = {
  		.rx_dma_l4_valid = RX_DMA_L4_VALID,
  		.dma_max_len = MTK_TX_DMA_BUF_LEN,
  		.dma_len_offset = MTK_TX_DMA_BUF_SHIFT,
@@ -66,7 +66,7 @@
  	},
  };
  
-@@ -6023,6 +6028,7 @@ static const struct mtk_soc_data mt7623_data = {
+@@ -6057,6 +6062,7 @@ static const struct mtk_soc_data mt7623_data = {
  		.rx_dma_l4_valid = RX_DMA_L4_VALID,
  		.dma_max_len = MTK_TX_DMA_BUF_LEN,
  		.dma_len_offset = MTK_TX_DMA_BUF_SHIFT,
@@ -74,7 +74,7 @@
  	},
  };
  
-@@ -6069,6 +6075,7 @@ static const struct mtk_soc_data mt7986_data = {
+@@ -6103,6 +6109,7 @@ static const struct mtk_soc_data mt7986_data = {
  		.rx_dma_l4_valid = RX_DMA_L4_VALID_V2,
  		.dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
  		.dma_len_offset = MTK_TX_DMA_BUF_SHIFT_V2,
@@ -82,7 +82,7 @@
  	},
  };
  
-@@ -6093,6 +6100,7 @@ static const struct mtk_soc_data mt7981_data = {
+@@ -6127,6 +6134,7 @@ static const struct mtk_soc_data mt7981_data = {
  		.rx_dma_l4_valid = RX_DMA_L4_VALID_V2,
  		.dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
  		.dma_len_offset = MTK_TX_DMA_BUF_SHIFT_V2,
@@ -90,7 +90,7 @@
  	},
  };
  
-@@ -6117,6 +6125,7 @@ static const struct mtk_soc_data mt7988_data = {
+@@ -6148,6 +6156,7 @@ static const struct mtk_soc_data mt7988_data = {
  		.rx_dma_l4_valid = RX_DMA_L4_VALID_V2,
  		.dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
  		.dma_len_offset = MTK_TX_DMA_BUF_SHIFT_V2,
@@ -98,7 +98,7 @@
  	},
  };
  
-@@ -6138,6 +6147,7 @@ static const struct mtk_soc_data rt5350_data = {
+@@ -6169,6 +6178,7 @@ static const struct mtk_soc_data rt5350_data = {
  		.rx_dma_l4_valid = RX_DMA_L4_VALID_PDMA,
  		.dma_max_len = MTK_TX_DMA_BUF_LEN,
  		.dma_len_offset = MTK_TX_DMA_BUF_SHIFT,
@@ -107,20 +107,10 @@
  };
  
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-index 52e4b85..7b3230e 100644
+index 351e66c..2ddadf3 100644
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -495,6 +495,9 @@
- #define FC_THRES_DROP_EN	(7 << 16)
- #define FC_THRES_MIN		0x4444
- 
-+/* QDMA TX Scheduler Rate Control Register */
-+#define MTK_QDMA_TX_2SCH_BASE	(QDMA_BASE + 0x214)
-+
- /* QDMA Interrupt Status Register */
- #define MTK_QDMA_INT_STATUS	(QDMA_BASE + 0x218)
- #if defined(CONFIG_MEDIATEK_NETSYS_RX_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
-@@ -538,6 +541,11 @@
+@@ -549,6 +549,11 @@
  /* QDMA Interrupt Mask Register */
  #define MTK_QDMA_HRED2		(QDMA_BASE + 0x244)
  
@@ -132,22 +122,19 @@
  /* QDMA TX Forward CPU Pointer Register */
  #define MTK_QTX_CTX_PTR		(QDMA_BASE +0x300)
  
-@@ -565,6 +573,14 @@
- /* QDMA FQ Free Page Buffer Length Register */
- #define MTK_QDMA_FQ_BLEN	(QDMA_BASE +0x32c)
+@@ -578,6 +583,11 @@
  
-+/* QDMA TX Scheduler Rate Control Register */
-+#define MTK_QDMA_TX_4SCH_BASE(x)	(QDMA_BASE + 0x398 + (((x) >> 1) * 0x4))
+ /* QDMA TX Scheduler Rate Control Register */
+ #define MTK_QDMA_TX_4SCH_BASE(x)	(QDMA_BASE + 0x398 + (((x) >> 1) * 0x4))
 +#define MTK_QDMA_TX_SCH_MASK		GENMASK(15, 0)
 +#define MTK_QDMA_TX_SCH_MAX_WFQ		BIT(15)
 +#define MTK_QDMA_TX_SCH_RATE_EN		BIT(11)
 +#define MTK_QDMA_TX_SCH_RATE_MAN	GENMASK(10, 4)
 +#define MTK_QDMA_TX_SCH_RATE_EXP	GENMASK(3, 0)
-+
+ 
  /* WDMA Registers */
  #define MTK_WDMA_CTX_PTR(x)	(WDMA_BASE(x) + 0x8)
- #define MTK_WDMA_DTX_PTR(x)	(WDMA_BASE(x) + 0xC)
-@@ -1753,6 +1769,7 @@ struct mtk_soc_data {
+@@ -1771,6 +1781,7 @@ struct mtk_soc_data {
  		u32	rx_dma_l4_valid;
  		u32	dma_max_len;
  		u32	dma_len_offset;
@@ -155,15 +142,15 @@
  	} txrx;
  };
  
-@@ -1946,6 +1963,7 @@ struct mtk_eth {
- 	spinlock_t			syscfg0_lock;
+@@ -1971,6 +1982,7 @@ struct mtk_eth {
+ 	struct notifier_block		netdevice_notifier;
  	struct timer_list		mtk_dma_monitor_timer;
  
 +	u8				qos_toggle;
  	u8				ppe_num;
  	struct mtk_ppe			*ppe[MTK_MAX_PPE_NUM];
  	struct rhashtable		flow_table;
-@@ -2004,6 +2022,36 @@ extern const struct of_device_id of_mtk_match[];
+@@ -2029,6 +2041,36 @@ extern const struct of_device_id of_mtk_match[];
  extern u32 mtk_hwlro_stats_ebl;
  extern u32 dbg_show_level;
  
@@ -200,7 +187,7 @@
  /* read the hardware status register */
  void mtk_stats_update_mac(struct mtk_mac *mac);
  
-@@ -2037,4 +2085,6 @@ void mtk_eth_set_dma_device(struct mtk_eth *eth, struct device *dma_dev);
+@@ -2060,4 +2102,6 @@ void mtk_eth_set_dma_device(struct mtk_eth *eth, struct device *dma_dev);
  u32 mtk_rss_indr_table(struct mtk_rss_params *rss_params, int index);
  
  int mtk_ppe_debugfs_init(struct mtk_eth *eth);
@@ -208,10 +195,10 @@
 +int mtk_qdma_debugfs_init(struct mtk_eth *eth);
  #endif /* MTK_ETH_H */
 diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c
-index 7b92fff..f5dbfe9 100755
+index 94e03b2..8388f65 100755
 --- a/drivers/net/ethernet/mediatek/mtk_ppe.c
 +++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
-@@ -139,7 +139,7 @@ static void mtk_ppe_cache_enable(struct mtk_ppe *ppe, bool enable)
+@@ -128,7 +128,7 @@ static void mtk_ppe_cache_enable(struct mtk_ppe *ppe, bool enable)
  		enable * MTK_PPE_CACHE_CTL_EN);
  }
  
@@ -220,7 +207,7 @@
  {
  	u32 hv1, hv2, hv3;
  	u32 hash;
-@@ -431,12 +431,58 @@ int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq,
+@@ -420,12 +420,58 @@ int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq,
  	return 0;
  }
  
@@ -280,10 +267,10 @@
  mtk_flow_entry_match(struct mtk_flow_entry *entry, struct mtk_foe_entry *data)
  {
 diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.h b/drivers/net/ethernet/mediatek/mtk_ppe.h
-index bc48bd9..5529d64 100644
+index 86288b0..5ab864f 100644
 --- a/drivers/net/ethernet/mediatek/mtk_ppe.h
 +++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
-@@ -429,9 +429,13 @@ int mtk_foe_entry_set_vlan(struct mtk_foe_entry *entry, int vid);
+@@ -403,9 +403,13 @@ int mtk_foe_entry_set_vlan(struct mtk_foe_entry *entry, int vid);
  int mtk_foe_entry_set_pppoe(struct mtk_foe_entry *entry, int sid);
  int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq,
  			   int bss, int wcid);
@@ -298,7 +285,7 @@
  
  #endif
 diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
-index f9cd2f9..f0c63da 100755
+index b80f72d..3bc50a4 100755
 --- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
 +++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
 @@ -9,6 +9,8 @@
@@ -329,7 +316,7 @@
  	if (dev == eth->netdev[0])
  		pse_port = PSE_GDM1_PORT;
  	else if (dev == eth->netdev[1])
-@@ -219,6 +224,23 @@ mtk_flow_set_output_device(struct mtk_eth *eth, struct mtk_foe_entry *foe,
+@@ -217,6 +222,23 @@ mtk_flow_set_output_device(struct mtk_eth *eth, struct mtk_foe_entry *foe,
  		return -EOPNOTSUPP;
  
  out:
@@ -353,7 +340,7 @@
  	mtk_foe_entry_set_pse_port(foe, pse_port);
  
  	return 0;
-@@ -449,7 +471,9 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
+@@ -447,7 +469,9 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
  	if (data.pppoe.num == 1)
  		mtk_foe_entry_set_pppoe(&foe, data.pppoe.sid);
  
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3015-ethernet-update-ppe-from-netsys2-to-netsys3.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3015-ethernet-update-ppe-from-netsys2-to-netsys3.patch
index b6c0d41..04ef1f6 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3015-ethernet-update-ppe-from-netsys2-to-netsys3.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3015-ethernet-update-ppe-from-netsys2-to-netsys3.patch
@@ -1,4 +1,4 @@
-From aaac91720ca1fd7679896286eac2b014e7150fca Mon Sep 17 00:00:00 2001
+From 2914bec639e2749bbd6d021639b8c3d8c0a2490e Mon Sep 17 00:00:00 2001
 From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
 Date: Mon, 18 Mar 2024 16:35:07 +0800
 Subject: [PATCH 15/24] ethernet-update-ppe-from-netsys2-to-netsys3
@@ -13,10 +13,10 @@
  6 files changed, 82 insertions(+), 19 deletions(-)
 
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 952bf51..f477ff3 100644
+index 1be1d43..04968da 100644
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -2447,7 +2447,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
+@@ -2441,7 +2441,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
  			skb_checksum_none_assert(skb);
  		skb->protocol = eth_type_trans(skb, netdev);
  
@@ -24,8 +24,8 @@
 +#if defined(CONFIG_MEDIATEK_NETSYS_RX_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
  		hash = trxd.rxd5 & MTK_RXD5_FOE_ENTRY_V2;
  		reason = FIELD_GET(MTK_RXD5_PPE_CPU_REASON_V2, trxd.rxd5);
- 		if (hash != MTK_RXD5_FOE_ENTRY_V2) {
-@@ -5798,7 +5798,8 @@ static int mtk_probe(struct platform_device *pdev)
+ 		if (hash != MTK_RXD5_FOE_ENTRY_V2)
+@@ -5829,7 +5829,8 @@ static int mtk_probe(struct platform_device *pdev)
  
  		for (i = 0; i < eth->ppe_num; i++) {
  			eth->ppe[i] = mtk_ppe_init(eth,
@@ -35,7 +35,7 @@
  						   2, eth->soc->hash_way, i,
  						   eth->soc->has_accounting);
  			if (!eth->ppe[i]) {
-@@ -6065,6 +6066,9 @@ static const struct mtk_soc_data mt7988_data = {
+@@ -6120,6 +6121,9 @@ static const struct mtk_soc_data mt7988_data = {
  	.required_clks = MT7988_CLKS_BITMAP,
  	.required_pctl = false,
  	.has_sram = true,
@@ -46,10 +46,10 @@
  	.txrx = {
  		.txd_size = sizeof(struct mtk_tx_dma_v2),
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-index 58547af..9c46ac1 100644
+index 6ad3468..e882436 100644
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -137,9 +137,10 @@
+@@ -136,9 +136,10 @@
  #define MTK_GDMA_UCS_EN		BIT(20)
  #define MTK_GDMA_STRP_CRC	BIT(16)
  #define MTK_GDMA_TO_PDMA	0x0
@@ -61,7 +61,7 @@
  #else
  #define MTK_GDMA_TO_PPE0	0x4444
  #endif
-@@ -2018,14 +2019,14 @@ extern u32 dbg_show_level;
+@@ -2023,14 +2024,14 @@ extern u32 dbg_show_level;
  
  static inline void mtk_set_ib1_sp(struct mtk_eth *eth, struct mtk_foe_entry *foe, u32 val)
  {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3019-mtk-wed-add-wed3-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3019-mtk-wed-add-wed3-support.patch
index 3a5aa25..b4c96a0 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3019-mtk-wed-add-wed3-support.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3019-mtk-wed-add-wed3-support.patch
@@ -1,7 +1,7 @@
-From b6e8f376899070b8109c3413b15e572f8f03dc06 Mon Sep 17 00:00:00 2001
+From 3334403e4b8341c928c9897806a3641131f5c467 Mon Sep 17 00:00:00 2001
 From: Sujuan Chen <sujuan.chen@mediatek.com>
 Date: Mon, 18 Sep 2023 13:21:15 +0800
-Subject: [PATCH] mtk:wed:add wed3 support
+Subject: [PATCH 19/24] mtk:wed:add wed3 support
 
 ---
  arch/arm64/boot/dts/mediatek/mt7988.dtsi      |  152 +-
@@ -22,7 +22,7 @@
  mode change 100755 => 100644 drivers/net/ethernet/mediatek/mtk_ppe.c
 
 diff --git a/arch/arm64/boot/dts/mediatek/mt7988.dtsi b/arch/arm64/boot/dts/mediatek/mt7988.dtsi
-index 7e96640..3368240 100644
+index 9abe45f..7faf6af 100644
 --- a/arch/arm64/boot/dts/mediatek/mt7988.dtsi
 +++ b/arch/arm64/boot/dts/mediatek/mt7988.dtsi
 @@ -193,44 +193,49 @@
@@ -212,8 +212,8 @@
  	};
  
  	reserved-memory {
-@@ -901,6 +938,7 @@
- 					 <&topckgen CK_TOP_CB_NET2_D2>;
+@@ -899,6 +936,7 @@
+ 					 <&topckgen CK_TOP_CB_SGM_325M>;
  		mediatek,ethsys = <&ethsys>;
  		mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>;
 +		mediatek,wed = <&wed0>, <&wed1>, <&wed2>;
@@ -221,10 +221,10 @@
  		mediatek,xfi_pextp = <&xfi_pextp0>, <&xfi_pextp1>;
  		mediatek,xfi_pll = <&xfi_pll>;
 diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nor.dts b/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nor.dts
-index a22af29..9169188 100644
+index 24c7799..c283c5e 100644
 --- a/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nor.dts
 +++ b/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nor.dts
-@@ -372,9 +372,23 @@
+@@ -434,9 +434,23 @@
  	status = "okay";
  };
  
@@ -251,10 +251,10 @@
 +};
 \ No newline at end of file
 diff --git a/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nor.dts b/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nor.dts
-index effcfd8..30e4846 100644
+index f72c5d3..6503700 100644
 --- a/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nor.dts
 +++ b/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nor.dts
-@@ -382,9 +382,23 @@
+@@ -444,9 +444,23 @@
  	status = "okay";
  };
  
@@ -3662,7 +3662,7 @@
 +#define MTK_WED_PCIE_BASE2			0x11290000
  #endif
 diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
-index b2abebe..a9e455d 100644
+index 0a7eb9a..33e5f5f 100644
 --- a/include/linux/netdevice.h
 +++ b/include/linux/netdevice.h
 @@ -880,6 +880,13 @@ struct net_device_path {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3022-mediatek-ethernet-add-multiple-ppe-allocati.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3022-mediatek-ethernet-add-multiple-ppe-allocati.patch
index c96eaa8..0e8e9a0 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3022-mediatek-ethernet-add-multiple-ppe-allocati.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3022-mediatek-ethernet-add-multiple-ppe-allocati.patch
@@ -1,4 +1,4 @@
-From e917fdd9042787edd43e4070c3480baf0dfb8d33 Mon Sep 17 00:00:00 2001
+From d40796af640489047848feeb83886962a25ce024 Mon Sep 17 00:00:00 2001
 From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
 Date: Mon, 18 Mar 2024 16:57:13 +0800
 Subject: [PATCH 22/24] 
@@ -12,10 +12,10 @@
  4 files changed, 33 insertions(+), 3 deletions(-)
 
 diff --git a/arch/arm64/boot/dts/mediatek/mt7988.dtsi b/arch/arm64/boot/dts/mediatek/mt7988.dtsi
-index 4a1a446..57b27f8 100644
+index 7faf6af..a8cb3d8 100644
 --- a/arch/arm64/boot/dts/mediatek/mt7988.dtsi
 +++ b/arch/arm64/boot/dts/mediatek/mt7988.dtsi
-@@ -942,6 +942,7 @@
+@@ -943,6 +943,7 @@
  		mediatek,infracfg = <&topmisc>;
  		mediatek,toprgu = <&watchdog>;
  		mediatek,hwver = <&hwver>;
@@ -24,10 +24,10 @@
  		#address-cells = <1>;
  		#size-cells = <0>;
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 291afdc..c0f4ade 100644
+index 04968da..6db2e52 100644
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -2349,6 +2349,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
+@@ -2343,6 +2343,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
  	u8 *data, *new_data;
  	struct mtk_rx_dma_v2 *rxd, trxd;
  	int done = 0;
@@ -35,8 +35,8 @@
  
  	if (unlikely(!ring))
  		goto rx_done;
-@@ -2463,8 +2464,10 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
- 		}
+@@ -2453,8 +2454,10 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
+ 			skb_set_hash(skb, jhash_1word(hash, 0), PKT_HASH_TYPE_L4);
  #endif
  
 -		if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED)
@@ -48,7 +48,7 @@
  
  		if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) {
  			if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_RX_V2)) {
-@@ -4113,7 +4116,19 @@ static int mtk_open(struct net_device *dev)
+@@ -4100,7 +4103,19 @@ static int mtk_open(struct net_device *dev)
  			     SGMSYS_QPHY_PWR_STATE_CTRL, 0);
  
  	if (eth->soc->offload_version) {
@@ -69,7 +69,7 @@
  
  			for (i = 0; i < eth->ppe_num; i++)
  				mtk_ppe_start(eth->ppe[i]);
-@@ -5129,6 +5144,7 @@ static const struct net_device_ops mtk_netdev_ops = {
+@@ -5119,6 +5134,7 @@ static const struct net_device_ops mtk_netdev_ops = {
  	.ndo_poll_controller	= mtk_poll_controller,
  #endif
  	.ndo_setup_tc		= mtk_eth_setup_tc,
@@ -78,10 +78,10 @@
  
  static void mux_poll(struct work_struct *work)
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-index 8454361..d958aec 100644
+index 1514b83..fc5bb30 100644
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -1978,6 +1978,7 @@ struct mtk_mac {
+@@ -1982,6 +1982,7 @@ struct mtk_mac {
  	phy_interface_t			interface;
  	unsigned int			mode;
  	unsigned int			type;
@@ -89,7 +89,7 @@
  	int				speed;
  	struct device_node		*of_node;
  	struct phylink			*phylink;
-@@ -2079,6 +2080,8 @@ int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type,
+@@ -2082,6 +2083,8 @@ int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type,
  		     void *type_data);
  int mtk_eth_setup_tc_block(struct net_device *dev, struct flow_block_offload *f,
  			   struct mtk_eth *eth);
@@ -99,10 +99,10 @@
  u32 mtk_rss_indr_table(struct mtk_rss_params *rss_params, int index);
  
 diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
-index 402f1e3..3bfbec8 100644
+index 2d432f2..7f432be 100644
 --- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
 +++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
-@@ -828,6 +828,16 @@ int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type,
+@@ -694,6 +694,16 @@ int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type,
  	}
  }
  
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3099-flow-offload-binding-when-there-is-no-ARP.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3099-flow-offload-binding-when-there-is-no-ARP.patch
new file mode 100644
index 0000000..f342f5c
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3099-flow-offload-binding-when-there-is-no-ARP.patch
@@ -0,0 +1,104 @@
+From 65df61bf369b84c9fbd2145242d09e8a854773e0 Mon Sep 17 00:00:00 2001
+From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
+Date: Tue, 28 May 2024 14:44:58 +0800
+Subject: [PATCH] flow offload binding when there is no ARP
+
+---
+ net/netfilter/xt_FLOWOFFLOAD.c       | 49 ++++++++++++++++++++--------
+ 1 files changed, 34 insertions(+), 15 deletions(-)
+
+diff --git a/net/netfilter/xt_FLOWOFFLOAD.c b/net/netfilter/xt_FLOWOFFLOAD.c
+index 99fc6a1..fa10d02 100644
+--- a/net/netfilter/xt_FLOWOFFLOAD.c
++++ b/net/netfilter/xt_FLOWOFFLOAD.c
+@@ -395,34 +395,53 @@ static int nf_dev_fill_forward_path(const struct nf_flow_route *route,
+ 	if (!nf_is_valid_ether_device(dev))
+ 		goto out;
+ 
+-	n = dst_neigh_lookup(dst_cache, daddr);
+-	if (!n)
+-		return -1;
++	if (ct->status & IPS_NAT_MASK || ct->inet6_mode == CT_INET_MODE_IPV6) {
++		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);
++		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;
++		if (!(nud_state & NUD_VALID))
++			return -1;
++	}
+ 
+ out:
+ 	return dev_fill_forward_path(dev, ha, stack);
+ }
+ 
+-static int nf_dev_forward_path(struct nf_flow_route *route,
++static int nf_dev_forward_path(struct sk_buff *skb,
++				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 ethhdr *eth;
++	enum ip_conntrack_dir skb_dir;
+ 	struct net_device_path_stack stack;
+ 	struct nf_forward_info info = {};
+ 	unsigned char ha[ETH_ALEN];
+ 	int i;
+ 
++	if (!(ct->status & IPS_NAT_MASK) && skb_mac_header_was_set(skb) &&
++	    ct->inet6_mode != CT_INET_MODE_IPV6) {
++		eth = eth_hdr(skb);
++		skb_dir = CTINFO2DIR(skb_get_nfct(skb) & NFCT_INFOMASK);
++
++		if (skb_dir != dir) {
++			memcpy(ha, eth->h_source, ETH_ALEN);
++			memcpy(info.h_source, eth->h_dest, ETH_ALEN);
++		} else {
++			memcpy(ha, eth->h_dest, ETH_ALEN);
++			memcpy(info.h_source, eth->h_source, ETH_ALEN);
++		}
++	}
++
+ 	if (nf_dev_fill_forward_path(route, dst, ct, dir, ha, &stack) >= 0)
+ 		nf_dev_path_info(&stack, &info, ha);
+ 
+@@ -512,9 +531,9 @@ xt_flowoffload_route_nat(struct sk_buff *skb, const struct nf_conn *ct,
+ 
+ 	if (route->tuple[dir].xmit_type	== FLOW_OFFLOAD_XMIT_NEIGH &&
+ 	    route->tuple[!dir].xmit_type == FLOW_OFFLOAD_XMIT_NEIGH) {
+-		if (nf_dev_forward_path(route, ct, dir, devs))
++		if (nf_dev_forward_path(skb, route, ct, dir, devs))
+ 			return -1;
+-		if (nf_dev_forward_path(route, ct, !dir, devs))
++		if (nf_dev_forward_path(skb, route, ct, !dir, devs))
+ 			return -1;
+ 	}
+ 
+@@ -543,8 +562,8 @@ xt_flowoffload_route_bridge(struct sk_buff *skb, const struct nf_conn *ct,
+ 
+ 	if (route->tuple[dir].xmit_type	== FLOW_OFFLOAD_XMIT_NEIGH &&
+ 	    route->tuple[!dir].xmit_type == FLOW_OFFLOAD_XMIT_NEIGH) {
+-		if (nf_dev_forward_path(route, ct, dir, devs) ||
+-		    nf_dev_forward_path(route, ct, !dir, devs)) {
++		if (nf_dev_forward_path(skb, route, ct, dir, devs) ||
++		    nf_dev_forward_path(skb, route, ct, !dir, devs)) {
+ 			ret = -1;
+ 			goto err_route_dir2;
+ 		}
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7988.cfg b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7988.cfg
index 1976c16..747c9d2 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7988.cfg
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7988.cfg
@@ -8,7 +8,9 @@
 CONFIG_AQUANTIA_PHY_FW_DOWNLOAD=y
 CONFIG_AQUANTIA_PHY_FW_DOWNLOAD_GANG=y
 # CONFIG_AQUANTIA_PHY_FW_DOWNLOAD_SINGLE is not set
-CONFIG_AQUANTIA_PHY_FW_FILE="AQR-G4_v5.7.0-AQR_EVB_Generic_X3410_StdCfg_MDISwap_USX_ID46316_VER2140.cld"
+CONFIG_AQUANTIA_PHY_FW_FILE="Rhe-05.06-Candidate7-AQR_Mediatek_23B_StartOff_ID45623_VER36657.cld"
+CONFIG_AQUANTIA_PHY_FW_FILE_AQR113C="Rhe-05.06-Candidate9-AQR_Mediatek_23B_P5_ID45824_LCLVER1.cld"
+CONFIG_AQUANTIA_PHY_FW_FILE_CUX3410="AQR-G4_v5.7.0-AQR_EVB_Generic_X3410_StdCfg_MDISwap_USX_ID46316_VER2148.cld"
 CONFIG_AQUANTIA_PHY_MIB=y
 CONFIG_ARCH_CLOCKSOURCE_DATA=y
 CONFIG_ARCH_DMA_ADDR_T_64BIT=y
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1716-v6.6-net-phy-add-phylink-pcs_enable-and-pcs_disable.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1716-v6.6-net-phy-add-phylink-pcs_enable-and-pcs_disable.patch
new file mode 100644
index 0000000..29306fd
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1716-v6.6-net-phy-add-phylink-pcs_enable-and-pcs_disable.patch
@@ -0,0 +1,109 @@
+From d3fd7b4ccaf867811a777cf7aecaaa9f32d94331 Mon Sep 17 00:00:00 2001
+From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
+Date: Mon, 13 May 2024 17:05:16 +0800
+Subject: [PATCH] 999-1716-v6.6-net-phy-add-phylink-pcs_enable-and-pcs_disable
+
+---
+ drivers/net/phy/phylink.c | 26 +++++++++++++++++++++++++-
+ include/linux/phylink.h   |  2 ++
+ 2 files changed, 27 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
+index 9b9bb17..1d79f59 100644
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -32,6 +32,10 @@
+ enum {
+ 	PHYLINK_DISABLE_STOPPED,
+ 	PHYLINK_DISABLE_LINK,
++
++	PCS_STATE_DOWN = 0,
++	PCS_STATE_STARTING,
++	PCS_STATE_STARTED,
+ };
+ 
+ /**
+@@ -69,6 +73,7 @@ struct phylink {
+ 	struct mutex state_mutex;
+ 	struct phylink_link_state phy_state;
+ 	struct work_struct resolve;
++	unsigned int pcs_state;
+ 
+ 	bool mac_link_dropped;
+ 	bool using_mac_select_pcs;
+@@ -520,11 +525,20 @@ static void phylink_major_config(struct phylink *pl, bool restart,
+ 	/* If we have a new PCS, switch to the new PCS after preparing the MAC
+ 	 * for the change.
+ 	 */
+-	if (pcs_changed)
++	if (pcs_changed) {
++		if (pl->pcs && pl->pcs->ops->pcs_disable)
++			pcs->ops->pcs_disable(pl->pcs);
++
+ 		pl->pcs = pcs;
++	}
+ 
+ 	phylink_mac_config(pl, state);
+ 
++	if (pl->pcs_state == PCS_STATE_STARTING || pcs_changed) {
++		if (pl->pcs && pl->pcs->ops->pcs_enable)
++			err = pcs->ops->pcs_enable(pl->pcs);
++	}
++
+ 	if (pl->pcs) {
+ 		err = pl->pcs->ops->pcs_config(pl->pcs, pl->cur_link_an_mode,
+ 					       state->interface,
+@@ -1022,6 +1036,7 @@ struct phylink *phylink_create(struct phylink_config *config,
+ 	pl->link_config.speed = SPEED_UNKNOWN;
+ 	pl->link_config.duplex = DUPLEX_UNKNOWN;
+ 	pl->link_config.an_enabled = true;
++	pl->pcs_state = PCS_STATE_DOWN;
+ 	pl->mac_ops = mac_ops;
+ 	__set_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state);
+ 	timer_setup(&pl->link_poll, phylink_fixed_poll, 0);
+@@ -1370,6 +1385,8 @@ void phylink_start(struct phylink *pl)
+ 	if (pl->netdev)
+ 		netif_carrier_off(pl->netdev);
+ 
++	pl->pcs_state = PCS_STATE_STARTING;
++
+ 	/* Apply the link configuration to the MAC when starting. This allows
+ 	 * a fixed-link to start with the correct parameters, and also
+ 	 * ensures that we set the appropriate advertisement for Serdes links.
+@@ -1381,6 +1398,8 @@ void phylink_start(struct phylink *pl)
+ 	phylink_resolve_flow(pl, &pl->link_config);
+ 	phylink_mac_initial_config(pl, true);
+ 
++	pl->pcs_state = PCS_STATE_STARTED;
++
+ 	clear_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state);
+ 	phylink_run_resolve(pl);
+ 
+@@ -1442,6 +1461,11 @@ void phylink_stop(struct phylink *pl)
+ 	}
+ 
+ 	phylink_run_resolve_and_disable(pl, PHYLINK_DISABLE_STOPPED);
++
++	pl->pcs_state = PCS_STATE_DOWN;
++
++	if (pl->pcs && pl->pcs->ops->pcs_disable)
++		pl->pcs->ops->pcs_disable(pl->pcs);
+ }
+ EXPORT_SYMBOL_GPL(phylink_stop);
+ 
+diff --git a/include/linux/phylink.h b/include/linux/phylink.h
+index e1c022f..fae9794 100644
+--- a/include/linux/phylink.h
++++ b/include/linux/phylink.h
+@@ -349,6 +349,8 @@ struct phylink_pcs {
+ struct phylink_pcs_ops {
+ 	int (*pcs_validate)(struct phylink_pcs *pcs, unsigned long *supported,
+ 			    const struct phylink_link_state *state);
++	int (*pcs_enable)(struct phylink_pcs *pcs);
++	void (*pcs_disable)(struct phylink_pcs *pcs);
+ 	void (*pcs_get_state)(struct phylink_pcs *pcs,
+ 			      struct phylink_link_state *state);
+ 	int (*pcs_config)(struct phylink_pcs *pcs, unsigned int mode,
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2741-net-phy-aquantia-add-automatic-firmware-selection.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2741-net-phy-aquantia-add-automatic-firmware-selection.patch
new file mode 100644
index 0000000..f4969c8
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2741-net-phy-aquantia-add-automatic-firmware-selection.patch
@@ -0,0 +1,178 @@
+diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
+index 3c2ea9f..e5a8b70 100644
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -412,11 +412,25 @@ choice
+ endchoice
+ 
+ config AQUANTIA_PHY_FW_FILE
+-	string "FW File"
++	string "Default PHY FW File"
+ 	depends on AQUANTIA_PHY
+ 	default "Rhe-05.06-Candidate7-AQR_Mediatek_23B_StartOff_ID45623_VER36657.cld"
+ 	---help---
+-	  Currently supports the Aquantia AQR113c
++	  This is the default FW.
++
++config AQUANTIA_PHY_FW_FILE_AQR113C
++	string "AQR113C PHY FW File"
++	depends on AQUANTIA_PHY
++	default "Rhe-05.06-Candidate7-AQR_Mediatek_23B_StartOff_ID45623_VER36657.cld"
++	---help---
++	  This FW is for AQR113C
++
++config AQUANTIA_PHY_FW_FILE_CUX3410
++	string "CUX3410 PHY FW File"
++	depends on AQUANTIA_PHY
++	default "AQR-G4_v5.7.0-AQR_EVB_Generic_X3410_StdCfg_MDISwap_USX_ID46316_VER2148.cld"
++	---help---
++	  This FW is for CUX3410
+ 
+ config AQUANTIA_PHY_MIB
+ 	tristate "MIB Read Enable"
+diff --git a/drivers/net/phy/aquantia.h b/drivers/net/phy/aquantia.h
+index 03d6744..d7e6786 100644
+--- a/drivers/net/phy/aquantia.h
++++ b/drivers/net/phy/aquantia.h
+@@ -9,6 +9,16 @@
+ #include <linux/device.h>
+ #include <linux/phy.h>
+ 
++#define PHY_ID_AQ1202	0x03a1b445
++#define PHY_ID_AQ2104	0x03a1b460
++#define PHY_ID_AQR105	0x03a1b4a2
++#define PHY_ID_AQR106	0x03a1b4d0
++#define PHY_ID_AQR107	0x03a1b4e0
++#define PHY_ID_AQCS109	0x03a1b5c2
++#define PHY_ID_AQR405	0x03a1b4b0
++#define PHY_ID_AQR113C	0x31c31c12
++#define PHY_ID_CUX3410	0x31c31dd3
++
+ #define MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT		4
+ 
+ #define PMAPMD_RSVD_VEND_PROV				0xe400
+diff --git a/drivers/net/phy/aquantia_firmware.c b/drivers/net/phy/aquantia_firmware.c
+index f37bee1..55a9a29 100644
+--- a/drivers/net/phy/aquantia_firmware.c
++++ b/drivers/net/phy/aquantia_firmware.c
+@@ -19,6 +19,8 @@
+ #endif
+ 
+ #define AQR_FIRMWARE					CONFIG_AQUANTIA_PHY_FW_FILE
++#define AQR113C_FIRMWARE				CONFIG_AQUANTIA_PHY_FW_FILE_AQR113C
++#define CUX3410_FIRMWARE				CONFIG_AQUANTIA_PHY_FW_FILE_CUX3410
+ 
+ /* Vendor specific 1, MDIO_MMD_VEND1 */
+ #define VEND1_STD_CONTROL1				0x0000
+@@ -923,6 +925,18 @@ int aqr_firmware_heartbeat_thread(void *data)
+ 	return ret;
+ }
+ 
++static char* aqr_firmware_name_get(u32 phy_id)
++{
++	switch (phy_id) {
++		case PHY_ID_AQR113C:
++			return AQR113C_FIRMWARE;
++		case PHY_ID_CUX3410:
++			return CUX3410_FIRMWARE;
++		default:
++			return AQR_FIRMWARE;
++	}
++}
++
+ static void aqr_firmware_download_cb(const struct firmware *fw, void *context)
+ {
+ 	struct phy_device **phydevs = context;
+@@ -931,6 +945,8 @@ static void aqr_firmware_download_cb(const struct firmware *fw, void *context)
+ 	struct aqr107_priv *priv = phydevs[0]->priv;
+ 	int result[MAX_GANGLOAD_DEVICES];
+ 	int i, num_phydevs = 0, ret = 0;
++	u32 phy_id = phydevs[0]->drv->phy_id;
++	char *firmware_name = aqr_firmware_name_get(phy_id);
+ 
+ 	if (!fw)
+ 		return;
+@@ -957,7 +973,7 @@ retry:
+ 
+ 			dev = &phydevs[i]->mdio.dev;
+ 			dev_err(dev, "failed to download firmware %s, ret: %d\n",
+-				AQR_FIRMWARE, ret);
++				firmware_name, ret);
+ 			goto retry;
+ 		}
+ 	}
+@@ -1005,6 +1021,8 @@ static int aqr_firmware_download_single(struct phy_device *phydev, bool force_re
+ 	struct device *dev = &phydev->mdio.dev;
+ 	const struct firmware *fw;
+ 	int ret = 0;
++	u32 phy_id = phydev->drv->phy_id;
++	char *firmware_name = aqr_firmware_name_get(phy_id);
+ 
+ 	if (priv->fw_initialized == true && force_reload == false)
+ 		return 0;
+@@ -1016,10 +1034,10 @@ static int aqr_firmware_download_single(struct phy_device *phydev, bool force_re
+ 	priv->fw_dl_mode = FW_DL_SINGLE;
+ 	priv->heartbeat = -1;
+ 
+-	ret = request_firmware(&fw, AQR_FIRMWARE, dev);
++	ret = request_firmware(&fw, firmware_name, dev);
+ 	if (ret) {
+ 		dev_err(dev, "failed to request firmware %s, ret: %d\n",
+-			AQR_FIRMWARE, ret);
++			firmware_name, ret);
+ 	}
+ 
+ 	aqr_firmware_download_cb(fw, priv->phydevs);
+@@ -1032,6 +1050,8 @@ static int aqr_firmware_gandload_thread(void *data)
+ 	struct phy_device **phydevs = data;
+ 	struct device *dev = &phydevs[0]->mdio.dev;
+ 	int ret = 0;
++	u32 phy_id = phydevs[0]->drv->phy_id;
++	char *firmware_name = aqr_firmware_name_get(phy_id);
+ 
+ 	for (;;) {
+ 		if (kthread_should_stop())
+@@ -1040,11 +1060,11 @@ static int aqr_firmware_gandload_thread(void *data)
+ 		/* either maximum gangload phy devices or timeout is reached */
+ 		if (gangload == MAX_GANGLOAD_DEVICES ||
+ 		    time_after(jiffies, gangload_timeout)) {
+-			ret = request_firmware_nowait(THIS_MODULE, true, AQR_FIRMWARE, dev,
++			ret = request_firmware_nowait(THIS_MODULE, true, firmware_name, dev,
+ 						      GFP_KERNEL, phydevs, aqr_firmware_download_cb);
+ 			if (ret) {
+ 				dev_err(dev, "failed to request firmware %s, ret: %d\n",
+-					AQR_FIRMWARE, ret);
++					firmware_name, ret);
+ 			}
+ 			break;
+ 		}
+diff --git a/drivers/net/phy/aquantia_main.c b/drivers/net/phy/aquantia_main.c
+index f445ef9..208fc7d 100644
+--- a/drivers/net/phy/aquantia_main.c
++++ b/drivers/net/phy/aquantia_main.c
+@@ -17,16 +17,6 @@
+ 
+ #include "aquantia.h"
+ 
+-#define PHY_ID_AQ1202	0x03a1b445
+-#define PHY_ID_AQ2104	0x03a1b460
+-#define PHY_ID_AQR105	0x03a1b4a2
+-#define PHY_ID_AQR106	0x03a1b4d0
+-#define PHY_ID_AQR107	0x03a1b4e0
+-#define PHY_ID_AQCS109	0x03a1b5c2
+-#define PHY_ID_AQR405	0x03a1b4b0
+-#define PHY_ID_AQR113C	0x31c31c12
+-#define PHY_ID_CUX3410	0x31c31dd3
+-
+ #define MDIO_PHYXS_VEND_IF_STATUS		0xe812
+ #define MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK	GENMASK(7, 3)
+ #define MDIO_PHYXS_VEND_IF_STATUS_TYPE_KR	0
+@@ -489,7 +479,7 @@ void aqr107_chip_info(struct phy_device *phydev)
+ 	build_id = FIELD_GET(VEND1_GLOBAL_RSVD_STAT1_FW_BUILD_ID, val);
+ 	prov_id = FIELD_GET(VEND1_GLOBAL_RSVD_STAT1_PROV_ID, val);
+ 
+-	phydev_dbg(phydev, "FW %u.%u, Build %u, Provisioning %u\n",
++	phydev_info(phydev, "FW %u.%u, Build %u, Provisioning %u\n",
+ 		   fw_major, fw_minor, build_id, prov_id);
+ }
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/patches-5.4.inc b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/patches-5.4.inc
index 4571e0e..8bf5b8b 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/patches-5.4.inc
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/patches-5.4.inc
@@ -55,6 +55,7 @@
     file://999-1713-v5.15-net-dsa-add-dsa_port_from_netdev.patch \
     file://999-1714-v5.15-net-dsa-add-netdev_upper_dev_link.patch \
     file://999-1715-v6.2-net-dsa-add-set-queue-mapping.patch \
+    file://999-1716-v6.6-net-phy-add-phylink-pcs_enable-and-pcs_disable.patch;apply=no \
     file://999-1750-v5.18-net-macsec-get-ready-to-backport-from-5-18.patch \
     file://999-1751-01-v5.18-net-macsec-move-some-definitions-in-a-dedicated-header.patch \
     file://999-1752-02-v5.18-net-macsec-introduce-the-macsec_context-structure.patch \
@@ -218,6 +219,7 @@
     file://999-2739-net-phy-aquantia-add-CUX3410.patch \
     file://999-2739-net_dsa_add_tag_arht.patch \
     file://999-2740-crypto-add-eip197-aes-ctr-support.patch \
+    file://999-2741-net-phy-aquantia-add-automatic-firmware-selection.patch \
     file://999-2800-misc-add-mtk-platform.patch \
     file://999-2850-fips-140-3-compliance.patch \
     file://999-2900-dts-mt7622-enable-new-mtk-snand-for-ubi.patch \
diff --git a/recipes-kernel/linux/linux-mediatek_5.4.bb b/recipes-kernel/linux/linux-mediatek_5.4.bb
index 746a7dc..b3a4f9b 100644
--- a/recipes-kernel/linux/linux-mediatek_5.4.bb
+++ b/recipes-kernel/linux/linux-mediatek_5.4.bb
@@ -103,6 +103,7 @@
             patch -p1 < ${WORKDIR}/999-2737-net-mt753x-phy-coverity-scan.patch
             patch -p1 < ${WORKDIR}/999-1710-v6.2-net-phy-add-phylink-pcs-support.patch
             patch -p1 < ${WORKDIR}/999-1712-v6.2-net-phy-add-phylink-rate-matching-support.patch
+            patch -p1 < ${WORKDIR}/999-1716-v6.6-net-phy-add-phylink-pcs_enable-and-pcs_disable.patch
             patch -p1 < ${WORKDIR}/999-2725-iwconfig-wireless-rate-fix.patch
             patch -p1 < ${WORKDIR}/999-2729-net-phy-remove-reporting-line-rate-to-mac.patch
             patch -p1 < ${WORKDIR}/999-2739-drivers_net_ethernet_mediatek_hnat.patch