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

[Description]
c642b937 [kernel][common][hnat][Fix BIND entry with DP=0 issue for Wifi Tx]
ed76ee89 [openwrt][mt7988][crypto][Fix neigh_output parameters for IPSec inline mode]
24d49512 [MAC80211][WED][Fix wdma rx hang on wed1 after SER]
8caa9f50 [openwrt][common][net][Bypass seq check of pptp data packets]
48ef0810 [kernel][common][eth][Fix rcu_sched detected stall issue during LRO stress test]
53587858 [kernel][common][eth][Correct ring buffer allocation for the LRO]
094dfc87 [openwrt][mt7988][crypto][Refactor tport setting for packets to EIP197]
60822c70 [kernel][common][hnat][Increase the field width of the SW_UDF]
8889384e [kernel][common][eth][Add Airoha AN8801SB 1G PHY driver v1.1.0]
5b3b005d [kernel][common][thermal][Remove unused cooling device node in dts]
d7a3043c [kernel][mt7988][eth][macsec: Add correct clock selection]
aa999785 [kernel][mt7988][hnat][Add ipv6, 3PPE, wmb function to PPE static mode]
53a4535d [[openwrt][kernel][common][eth][feature support] update eth error  reset detect condition]
9e8e84ea [kernel][common][pwm][Remove unused cell of pwm in dts]
1f80973b [kernel][common][pwm][Add pwm-gpio driver to Kconfig and Makefile]
1a579c58 [kernel][common][pwm][Add pwm-gpio as software pwm]
416ffc88 [openwrt][common][Fix build error in libkcapi]
de2c5d47 [kernel][common][Backport jitterrng to 2.2.0]
c1ac9fe9 [kernel][mt7988][eth][Update panic issue during SER test on the 4GB RFB]
317dcec1 [kernel][common][eth][Fix panic issue for the RX ring debug command]
3bb89973 [kernel][common][eth][Add a link down recovery handler for the SGMII]
c3853a9b [kernel][mt7988][eth][Add FE_CDM7_FSM and FE_GDM3_FSM to the dbg_regs command]
99977fc5 [kernel][common][Refactor network backport patch path]
a2610487 [MAC80211][hnat][Update multiple PPE allocation of the ETH for mt7988]
b1c06e45 [kernel][mt7988][eth][Fix panic issue during SER test on the 4GB RFB]
6dfdee52 [kernel][mt7988][hnat][Fix issue of HQoS not enable when used with NAT66]
d3e7752e [Add macsec HW offload backport from kernel 5.18]
9364c06f [kernel][common][eth][Fix Coverity scan warning]
15fa60ae [kernel][common][Revert jitterrng2.2.0 patch]
6df70da4 [MAC80211][hnat][Update IPv6 unbind issue for the routing mode]

[Release-log]

Change-Id: I834f8789e75ce9be3de0423aede5be7da8c84e82
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-emmc-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-emmc-rfb.dts
index 9c0c072..3c7c41a 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-emmc-rfb.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-emmc-rfb.dts
@@ -52,7 +52,7 @@
 };
 
 &fan {
-	pwms = <&pwm 1 50000 0>;
+	pwms = <&pwm 1 50000>;
 	status = "disabled";
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-gsw-spim-nand-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-gsw-spim-nand-rfb.dts
index af0c1c3..d1a53ae 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-gsw-spim-nand-rfb.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-gsw-spim-nand-rfb.dts
@@ -41,7 +41,7 @@
 };
 
 &fan {
-	pwms = <&pwm 1 50000 0>;
+	pwms = <&pwm 1 50000>;
 	status = "disabled";
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-sd-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-sd-rfb.dts
index de4569c..6b5d056 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-sd-rfb.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-sd-rfb.dts
@@ -43,7 +43,7 @@
 };
 
 &fan {
-	pwms = <&pwm 1 50000 0>;
+	pwms = <&pwm 1 50000>;
 	status = "disabled";
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-spim-nand-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-spim-nand-rfb.dts
index 28f576a..5baa16e 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-spim-nand-rfb.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-spim-nand-rfb.dts
@@ -34,7 +34,7 @@
 };
 
 &fan {
-	pwms = <&pwm 1 50000 0>;
+	pwms = <&pwm 1 50000>;
 	status = "disabled";
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-spim-nor-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-spim-nor-rfb.dts
index 7bd9be8..8cd84b5 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-spim-nor-rfb.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-spim-nor-rfb.dts
@@ -34,7 +34,7 @@
 };
 
 &fan {
-	pwms = <&pwm 1 50000 0>;
+	pwms = <&pwm 1 50000>;
 	status = "disabled";
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-emmc-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-emmc-rfb.dts
index fcde1dc..7f9734e 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-emmc-rfb.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-emmc-rfb.dts
@@ -65,7 +65,7 @@
 };
 
 &fan {
-	pwms = <&pwm 1 50000 0>;
+	pwms = <&pwm 1 50000>;
 	status = "disabled";
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-snfi-nand-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-snfi-nand-rfb.dts
index e56a291..eb41482 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-snfi-nand-rfb.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-snfi-nand-rfb.dts
@@ -47,7 +47,7 @@
 };
 
 &fan {
-	pwms = <&pwm 1 50000 0>;
+	pwms = <&pwm 1 50000>;
 	status = "disabled";
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-spim-nand-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-spim-nand-rfb.dts
index 59afe17..fe853e9 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-spim-nand-rfb.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-spim-nand-rfb.dts
@@ -47,7 +47,7 @@
 };
 
 &fan {
-	pwms = <&pwm 1 50000 0>;
+	pwms = <&pwm 1 50000>;
 	status = "disabled";
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-spim-nor-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-spim-nor-rfb.dts
index bf55f74..cf85743 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-spim-nor-rfb.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-spim-nor-rfb.dts
@@ -47,7 +47,7 @@
 };
 
 &fan {
-	pwms = <&pwm 1 50000 0>;
+	pwms = <&pwm 1 50000>;
 	status = "disabled";
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a.dtsi b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a.dtsi
index 1750c0a..888f8f5 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a.dtsi
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a.dtsi
@@ -336,12 +336,6 @@
 					hysteresis = <2000>;
 					type = "active";
 				};
-
-				cpu_trip_passive: passive {
-					temperature = <40000>;
-					hysteresis = <2000>;
-					type = "passive";
-				};
 			};
 
 			cooling-maps {
@@ -356,12 +350,6 @@
 					cooling-device = <&fan 1 1>;
 					trip = <&cpu_trip_active_low>;
 				};
-
-				cpu-passive {
-					/* passive: set fan to cooling level 0 */
-					cooling-device = <&fan 0 0>;
-					trip = <&cpu_trip_passive>;
-				};
 			};
 
 		};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-emmc-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-emmc-rfb.dts
index 9c0c072..3c7c41a 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-emmc-rfb.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-emmc-rfb.dts
@@ -52,7 +52,7 @@
 };
 
 &fan {
-	pwms = <&pwm 1 50000 0>;
+	pwms = <&pwm 1 50000>;
 	status = "disabled";
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-gsw-spim-nand-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-gsw-spim-nand-rfb.dts
index af0c1c3..d1a53ae 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-gsw-spim-nand-rfb.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-gsw-spim-nand-rfb.dts
@@ -41,7 +41,7 @@
 };
 
 &fan {
-	pwms = <&pwm 1 50000 0>;
+	pwms = <&pwm 1 50000>;
 	status = "disabled";
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-sd-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-sd-rfb.dts
index de4569c..6b5d056 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-sd-rfb.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-sd-rfb.dts
@@ -43,7 +43,7 @@
 };
 
 &fan {
-	pwms = <&pwm 1 50000 0>;
+	pwms = <&pwm 1 50000>;
 	status = "disabled";
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-spim-nand-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-spim-nand-rfb.dts
index 28f576a..5baa16e 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-spim-nand-rfb.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-spim-nand-rfb.dts
@@ -34,7 +34,7 @@
 };
 
 &fan {
-	pwms = <&pwm 1 50000 0>;
+	pwms = <&pwm 1 50000>;
 	status = "disabled";
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-spim-nor-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-spim-nor-rfb.dts
index 7bd9be8..8cd84b5 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-spim-nor-rfb.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-spim-nor-rfb.dts
@@ -34,7 +34,7 @@
 };
 
 &fan {
-	pwms = <&pwm 1 50000 0>;
+	pwms = <&pwm 1 50000>;
 	status = "disabled";
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-emmc-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-emmc-rfb.dts
index fcde1dc..7f9734e 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-emmc-rfb.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-emmc-rfb.dts
@@ -65,7 +65,7 @@
 };
 
 &fan {
-	pwms = <&pwm 1 50000 0>;
+	pwms = <&pwm 1 50000>;
 	status = "disabled";
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-snfi-nand-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-snfi-nand-rfb.dts
index e56a291..eb41482 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-snfi-nand-rfb.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-snfi-nand-rfb.dts
@@ -47,7 +47,7 @@
 };
 
 &fan {
-	pwms = <&pwm 1 50000 0>;
+	pwms = <&pwm 1 50000>;
 	status = "disabled";
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-spim-nand-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-spim-nand-rfb.dts
index 59afe17..fe853e9 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-spim-nand-rfb.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-spim-nand-rfb.dts
@@ -47,7 +47,7 @@
 };
 
 &fan {
-	pwms = <&pwm 1 50000 0>;
+	pwms = <&pwm 1 50000>;
 	status = "disabled";
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-spim-nor-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-spim-nor-rfb.dts
index bf55f74..cf85743 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-spim-nor-rfb.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-spim-nor-rfb.dts
@@ -47,7 +47,7 @@
 };
 
 &fan {
-	pwms = <&pwm 1 50000 0>;
+	pwms = <&pwm 1 50000>;
 	status = "disabled";
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a.dtsi b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
index 1750c0a..888f8f5 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
@@ -336,12 +336,6 @@
 					hysteresis = <2000>;
 					type = "active";
 				};
-
-				cpu_trip_passive: passive {
-					temperature = <40000>;
-					hysteresis = <2000>;
-					type = "passive";
-				};
 			};
 
 			cooling-maps {
@@ -356,12 +350,6 @@
 					cooling-device = <&fan 1 1>;
 					trip = <&cpu_trip_active_low>;
 				};
-
-				cpu-passive {
-					/* passive: set fan to cooling level 0 */
-					cooling-device = <&fan 0 0>;
-					trip = <&cpu_trip_passive>;
-				};
 			};
 
 		};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988-clkitg.dtsi b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988-clkitg.dtsi
index c676390..55cb53d 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988-clkitg.dtsi
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988-clkitg.dtsi
@@ -160,7 +160,7 @@
 			<&topckgen CK_TOP_PEXTP_SEL>,
 			<&topckgen CK_TOP_MCUSYS_BACKUP_625M_SEL>,
 			<&system_clk>,
-			<&topckgen CK_TOP_MACSEC_SEL>,
+			<&system_clk>,
 			<&system_clk>,
 			<&system_clk>,
 			<&system_clk>,
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 51a1c81..7e96640 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
@@ -161,12 +161,6 @@
 					hysteresis = <2000>;
 					type = "active";
 				};
-
-				cpu_trip_passive: passive {
-					temperature = <40000>;
-					hysteresis = <2000>;
-					type = "passive";
-				};
 			};
 
 			cooling-maps {
@@ -181,12 +175,6 @@
 					cooling-device = <&fan 1 1>;
 					trip = <&cpu_trip_active_low>;
 				};
-
-				cpu-passive {
-				/* passive: set fan to cooling level 0 */
-					cooling-device = <&fan 0 0>;
-					trip = <&cpu_trip_passive>;
-				};
 			};
 
 		};
@@ -875,7 +863,9 @@
 			 <&topckgen CK_TOP_NETSYS_PAO_2X_SEL>,
 			 <&topckgen CK_TOP_NETSYS_SYNC_250M_SEL>,
 			 <&topckgen CK_TOP_NETSYS_PPEFB_250M_SEL>,
-			 <&topckgen CK_TOP_NETSYS_WARP_SEL>;
+			 <&topckgen CK_TOP_NETSYS_WARP_SEL>,
+			 <&topckgen CK_TOP_MACSEC_SEL>,
+			 <&topckgen CK_TOP_NETSYS_TOPS_400M_SEL>;
 		clock-names = "xgp1", "xgp2", "xgp3", "fe", "gp2", "gp1",
 			      "gp3", "esw", "crypto", "sgmii_tx250m",
 			      "sgmii_rx250m", "sgmii2_tx250m", "sgmii2_rx250m",
@@ -890,19 +880,25 @@
 			      "top_netsys_500m_sel", "top_netsys_pao_2x_sel",
 			      "top_netsys_sync_250m_sel",
 			      "top_netsys_ppefb_250m_sel",
-			      "top_netsys_warp_sel";
+			      "top_netsys_warp_sel",
+			      "top_macsec_sel",
+			      "macsec_bus_clk";
 		assigned-clocks = <&topckgen CK_TOP_NETSYS_2X_SEL>,
 				  <&topckgen CK_TOP_NETSYS_GSW_SEL>,
 				  <&topckgen CK_TOP_USXGMII_SBUS_0_SEL>,
 				  <&topckgen CK_TOP_USXGMII_SBUS_1_SEL>,
 				  <&topckgen CK_TOP_SGM_0_SEL>,
-				  <&topckgen CK_TOP_SGM_1_SEL>;
+				  <&topckgen CK_TOP_SGM_1_SEL>,
+				  <&topckgen CK_TOP_MACSEC_SEL>,
+				  <&topckgen CK_TOP_NETSYS_TOPS_400M_SEL>;
 		assigned-clock-parents = <&topckgen CK_TOP_CB_NET2_800M>,
 					 <&topckgen CK_TOP_CB_NET1_D4>,
 					 <&topckgen CK_TOP_NET1_D8_D4>,
 					 <&topckgen CK_TOP_NET1_D8_D4>,
 					 <&topckgen CK_TOP_CB_SGM_325M>,
+					 <&topckgen CK_TOP_CB_SGM_325M>,
+					 <&topckgen CK_TOP_CB_SGM_325M>,
-					 <&topckgen CK_TOP_CB_SGM_325M>;
+					 <&topckgen CK_TOP_CB_NET2_D2>;
 		mediatek,ethsys = <&ethsys>;
 		mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>;
 		mediatek,usxgmiisys = <&usxgmiisys0>, <&usxgmiisys1>;
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 785bf71..5513d04 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
@@ -109,7 +109,7 @@
 };
 
 &fan {
-	pwms = <&pwm 0 50000 0>;
+	pwms = <&pwm 0 50000>;
 	status = "okay";
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-emmc.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-emmc.dts
index bf2abb6..d060c4a 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-emmc.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-emmc.dts
@@ -50,7 +50,7 @@
 };
 
 &fan {
-	pwms = <&pwm 0 50000 0>;
+	pwms = <&pwm 0 50000>;
 	status = "okay";
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-sd.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-sd.dts
index aa93f3c..5790dc9 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-sd.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-sd.dts
@@ -41,7 +41,7 @@
 };
 
 &fan {
-	pwms = <&pwm 0 50000 0>;
+	pwms = <&pwm 0 50000>;
 	status = "okay";
 };
 
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 c3e4f5c..a416519 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
@@ -92,7 +92,7 @@
 };
 
 &fan {
-	pwms = <&pwm 0 50000 0>;
+	pwms = <&pwm 0 50000>;
 	status = "okay";
 };
 
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 b8fb6aa..2029b57 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
@@ -75,7 +75,7 @@
 };
 
 &fan {
-	pwms = <&pwm 0 50000 0>;
+	pwms = <&pwm 0 50000>;
 	status = "okay";
 };
 
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 9dcd2b7..1d4e476 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
@@ -105,7 +105,7 @@
 };
 
 &fan {
-	pwms = <&pwm 0 50000 0>;
+	pwms = <&pwm 0 50000>;
 	status = "okay";
 };
 
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 7bd3e26..0d62ea5 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
@@ -105,7 +105,7 @@
 };
 
 &fan {
-	pwms = <&pwm 0 50000 0>;
+	pwms = <&pwm 0 50000>;
 	status = "okay";
 };
 
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 70a7554..578a489 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
@@ -32,7 +32,7 @@
 };
 
 &fan {
-	pwms = <&pwm 0 50000 0>;
+	pwms = <&pwm 0 50000>;
 	status = "okay";
 };
 
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 77eac13..eaf3d09 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
@@ -74,7 +74,7 @@
 };
 
 &fan {
-	pwms = <&pwm 0 50000 0>;
+	pwms = <&pwm 0 50000>;
 	status = "okay";
 };
 
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 abe0628..e81fff3 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
@@ -98,7 +98,7 @@
 };
 
 &fan {
-	pwms = <&pwm 0 50000 0>;
+	pwms = <&pwm 0 50000>;
 	status = "okay";
 };
 
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 13e25e1..318cc91 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
@@ -81,7 +81,7 @@
 };
 
 &fan {
-	pwms = <&pwm 0 50000 0>;
+	pwms = <&pwm 0 50000>;
 	status = "okay";
 };
 
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 3865bf8..4907ecd 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
@@ -91,7 +91,7 @@
 };
 
 &fan {
-	pwms = <&pwm 0 50000 0>;
+	pwms = <&pwm 0 50000>;
 	status = "okay";
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-emmc.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-emmc.dts
index 0aa4012..89d898a 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-emmc.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-emmc.dts
@@ -54,7 +54,7 @@
 };
 
 &fan {
-	pwms = <&pwm 0 50000 0>;
+	pwms = <&pwm 0 50000>;
 	status = "okay";
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-sd.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-sd.dts
index fea639f..56d1b60 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-sd.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-sd.dts
@@ -45,7 +45,7 @@
 };
 
 &fan {
-	pwms = <&pwm 0 50000 0>;
+	pwms = <&pwm 0 50000>;
 	status = "okay";
 };
 
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 00a3179..f88c0b9 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
@@ -86,7 +86,7 @@
 };
 
 &fan {
-	pwms = <&pwm 0 50000 0>;
+	pwms = <&pwm 0 50000>;
 	status = "okay";
 };
 
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 09b1772..aec7330 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
@@ -79,7 +79,7 @@
 };
 
 &fan {
-	pwms = <&pwm 0 50000 0>;
+	pwms = <&pwm 0 50000>;
 	status = "okay";
 };
 
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 a938ea8..a1a510f 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
@@ -109,7 +109,7 @@
 };
 
 &fan {
-	pwms = <&pwm 0 50000 0>;
+	pwms = <&pwm 0 50000>;
 	status = "okay";
 };
 
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 11d872e..4cab1ae 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
@@ -109,7 +109,7 @@
 };
 
 &fan {
-	pwms = <&pwm 0 50000 0>;
+	pwms = <&pwm 0 50000>;
 	status = "okay";
 };
 
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 5cb069e..e743718 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
@@ -36,7 +36,7 @@
 };
 
 &fan {
-	pwms = <&pwm 0 50000 0>;
+	pwms = <&pwm 0 50000>;
 	status = "okay";
 };
 
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 d844ddb..b832d59 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
@@ -109,7 +109,7 @@
 };
 
 &fan {
-	pwms = <&pwm 0 50000 0>;
+	pwms = <&pwm 0 50000>;
 	status = "okay";
 };
 
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 0e5064b..7bcf6c0 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
@@ -78,7 +78,7 @@
 };
 
 &fan {
-	pwms = <&pwm 0 50000 0>;
+	pwms = <&pwm 0 50000>;
 	status = "okay";
 };
 
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 9308de6..98e76f3 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
@@ -92,7 +92,7 @@
 };
 
 &fan {
-	pwms = <&pwm 0 50000 0>;
+	pwms = <&pwm 0 50000>;
 	status = "okay";
 };
 
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 e939bff..3fbdcb0 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
@@ -95,7 +95,7 @@
 };
 
 &fan {
-	pwms = <&pwm 0 50000 0>;
+	pwms = <&pwm 0 50000>;
 	status = "okay";
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.c
index e50e1ac..bfe2f0d 100755
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.c
@@ -925,12 +925,14 @@
 	struct mtk_rx_dma_v2 *rx_ring;
 	int i = 0, j = 0;
 
-	for (j = 0; j < MTK_RX_NAPI_NUM; j++) {
+	for (j = 0; j < MTK_MAX_RX_RING_NUM; j++) {
 		ring = &g_eth->rx_ring[j];
+		if (!ring->dma)
+			continue;
 
 		seq_printf(seq, "[Ring%d] next to read: %d\n", j,
 			   NEXT_DESP_IDX(ring->calc_idx, MTK_DMA_SIZE));
-		for (i = 0; i < MTK_DMA_SIZE; i++) {
+		for (i = 0; i < ring->dma_size; i++) {
 			rx_ring = ring->dma + i * eth->soc->txrx.rxd_size;
 
 			seq_printf(seq, "%d: %08x %08x %08x %08x", i,
@@ -1093,10 +1095,14 @@
 			   mtk_r32(eth, MTK_FE_CDM5_FSM));
 		seq_printf(seq, "| FE_CDM6_FSM	: %08x |\n",
 			   mtk_r32(eth, MTK_FE_CDM6_FSM));
+		seq_printf(seq, "| FE_CDM7_FSM	: %08x |\n",
+			   mtk_r32(eth, MTK_FE_CDM7_FSM));
 		seq_printf(seq, "| FE_GDM1_FSM	: %08x |\n",
 			   mtk_r32(eth, MTK_FE_GDM1_FSM));
 		seq_printf(seq, "| FE_GDM2_FSM	: %08x |\n",
 			   mtk_r32(eth, MTK_FE_GDM2_FSM));
+		seq_printf(seq, "| FE_GDM3_FSM	: %08x |\n",
+			   mtk_r32(eth, MTK_FE_GDM3_FSM));
 		seq_printf(seq, "| SGMII_EFUSE	: %08x |\n",
 			   mtk_dbg_r32(MTK_SGMII_EFUSE));
 		seq_printf(seq, "| SGMII0_RX_CNT : %08x |\n",
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
old mode 100755
new mode 100644
index 3e7c137..b97ddd7
--- 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
@@ -26,6 +26,7 @@
 #define MTK_FE_CDM4_FSM			0x298
 #define MTK_FE_CDM5_FSM			0x318
 #define MTK_FE_CDM6_FSM			0x328
+#define MTK_FE_CDM7_FSM			0x338
 #define MTK_FE_GDM1_FSM			0x228
 #define MTK_FE_GDM2_FSM			0x22C
 #define MTK_FE_GDM3_FSM			0x23C
@@ -38,6 +39,9 @@
 #define MTK_SGMII_EFUSE			0x11D008C8
 #define MTK_WED_RTQM_GLO_CFG		0x15010B00
 
+#define MTK_FE_GDM_FSM(x)		(((x) == 2) ? MTK_FE_GDM3_FSM :	\
+					 ((x) == 1) ? MTK_FE_GDM2_FSM : MTK_FE_GDM1_FSM)
+
 #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 1defeaf..8f947a3 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
@@ -225,15 +225,12 @@
 {
 	static u32 pre_dtx[MTK_WDMA_CNT];
 	static u32 err_cnt[MTK_WDMA_CNT];
-	u32 i = 0, cur_dtx = 0, tx_busy = 0, tx_rdy = 0, err_flag = 0;
-	u32 dbg_mon = 0;
+	u32 i, cur_dtx, tx_busy, err_flag = 0;
 
 	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;
-		dbg_mon = mtk_r32(eth, MTK_WDMA_TX_DBG_MON0(i));
-		tx_rdy = !(dbg_mon & MTK_CDM_TXFIFO_RDY);
-		if (cur_dtx == pre_dtx[i] && tx_busy && tx_rdy) {
+		if (cur_dtx == pre_dtx[i] && tx_busy) {
 			err_cnt[i]++;
 			if (err_cnt[i] >= 3) {
 				pr_info("WDMA %d Info\n", i);
@@ -513,6 +510,111 @@
 		return 0;
 }
 
+u32 mtk_monitor_gdm_rx(struct mtk_eth *eth)
+{
+	static u32 gmac_cnt[MTK_MAX_DEVS];
+	static u32 gdm_cnt[MTK_MAX_DEVS];
+	static u32 pre_fsm[MTK_MAX_DEVS];
+	static u32 pre_ipq[MTK_MAX_DEVS];
+	u32 mib_base = MTK_GDM1_TX_GBCNT;
+	u32 gmac_rxcnt[MTK_MAX_DEVS];
+	u32 is_gmac_rx[MTK_MAX_DEVS];
+	u32 cur_fsm, pse_ipq, err_flag = 0, i;
+
+	for (i = 0; i < MTK_MAX_DEVS; i++) {
+		is_gmac_rx[i] = (mtk_r32(eth, MTK_MAC_FSM(i)) & 0xFF0000) != 0x10000;
+		gmac_rxcnt[i] =
+			mtk_r32(eth, mib_base + MTK_GDM_RX_BASE + i * MTK_GDM_CNT_OFFSET);
+		if (is_gmac_rx[i] && (gmac_rxcnt[i] == 0))
+			gmac_cnt[i]++;
+		if (gmac_cnt[i] > 4) {
+			pr_info("GMAC%d Rx Info\n", i+1);
+			pr_info("err_cnt = %d", gmac_cnt[i]);
+			pr_info("GMAC_FSM = 0x%x\n",
+				mtk_r32(eth, MTK_MAC_FSM(i)));
+			err_flag = 1;
+		} else
+			gmac_cnt[i] = 0;
+	}
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
+		for (i = 0; i < MTK_MAX_DEVS; i++) {
+			if (i == 0) {
+				pse_ipq = (mtk_r32(eth, MTK_PSE_IQ_STA(0)) >> 16) & 0xFFF;
+				cur_fsm = mtk_r32(eth, MTK_FE_GDM1_FSM) & 0xFF;
+			} else if (i == 1) {
+				pse_ipq = mtk_r32(eth, MTK_PSE_IQ_STA(1)) & 0xFFF;
+				cur_fsm = mtk_r32(eth, MTK_FE_GDM2_FSM) & 0xFF;
+			} else {
+				pse_ipq = (mtk_r32(eth, MTK_PSE_IQ_STA(7)) >> 16) & 0xFFF;
+				cur_fsm = mtk_r32(eth, MTK_FE_GDM3_FSM) & 0xFF;
+			}
+
+			if (((cur_fsm == pre_fsm[i] && cur_fsm == 0x23) ||
+				(cur_fsm == pre_fsm[i] && cur_fsm == 0x24)) &&
+				(pse_ipq == pre_ipq[i] && pse_ipq != 0x00)) {
+				gdm_cnt[i]++;
+				if (gdm_cnt[i] >= 3) {
+					pr_info("GDM%d Rx Info\n", i + 1);
+					pr_info("err_cnt = %d", gdm_cnt[i]);
+					pr_info("GDM%d_FSM = %x\n", i + 1,
+						mtk_r32(eth, MTK_FE_GDM_FSM(i)));
+					pr_info("==============================\n");
+					err_flag = 1;
+				}
+			} else
+				gdm_cnt[i] = 0;
+
+			pre_fsm[i] = cur_fsm;
+			pre_ipq[i] = pse_ipq;
+		}
+	}
+
+	if (err_flag)
+		return MTK_FE_STOP_TRAFFIC;
+	else
+		return 0;
+}
+
+u32 mtk_monitor_gdm_tx(struct mtk_eth *eth)
+{
+	static u32 err_cnt[MTK_MAX_DEVS];
+	u32 mib_base = MTK_GDM1_TX_GBCNT;
+	u32 gmac_txcnt[MTK_MAX_DEVS];
+	u32 is_gmac_tx[MTK_MAX_DEVS];
+	u32 err_flag = 0, i, pse_opq;
+
+	for (i = 0; i < MTK_MAX_DEVS; i++) {
+		is_gmac_tx[i] =
+			(mtk_r32(eth, MTK_MAC_FSM(i)) & 0xFF000000) != 0x1000000;
+		gmac_txcnt[i] =
+			mtk_r32(eth, mib_base + MTK_GDM_TX_BASE + i * MTK_GDM_CNT_OFFSET);
+		if (i == 0)
+			pse_opq = (mtk_r32(eth, MTK_PSE_OQ_STA(0)) >> 16) & 0xFFF;
+		else if (i == 1)
+			pse_opq = mtk_r32(eth, MTK_PSE_OQ_STA(1)) & 0xFFF;
+		else
+			pse_opq = (mtk_r32(eth, MTK_PSE_OQ_STA(7)) >> 16) & 0xFFF;
+
+		if (is_gmac_tx[i] && (gmac_txcnt[i] == 0) && (pse_opq > 0))
+			err_cnt[i]++;
+		if (err_cnt[i] > 4) {
+			pr_info("GMAC%d Tx Info\n", i+1);
+			pr_info("err_cnt = %d", err_cnt[i]);
+			pr_info("GMAC_FSM = 0x%x\n",
+				mtk_r32(eth, MTK_MAC_FSM(i)));
+			err_flag = 1;
+		} else
+			err_cnt[i] = 0;
+
+	}
+
+	if (err_flag)
+		return MTK_FE_STOP_TRAFFIC;
+	else
+		return 0;
+}
+
 static const mtk_monitor_xdma_func mtk_reset_monitor_func[] = {
 	[0] = mtk_monitor_wdma_tx,
 	[1] = mtk_monitor_wdma_rx,
@@ -521,6 +623,8 @@
 	[4] = mtk_monitor_adma_rx,
 	[5] = mtk_monitor_tdma_tx,
 	[6] = mtk_monitor_tdma_rx,
+	[7] = mtk_monitor_gdm_tx,
+	[8] = mtk_monitor_gdm_rx,
 };
 
 void mtk_dma_monitor(struct timer_list *t)
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 a4117f4..ad5838c 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
@@ -43,8 +43,14 @@
 
 #if defined(CONFIG_MEDIATEK_NETSYS_V3)
 #define MTK_WDMA_CNT	(0x3)
+#define MTK_GDM_RX_BASE	(0x8)
+#define MTK_GDM_CNT_OFFSET	(0x80)
+#define MTK_GDM_TX_BASE	(0x48)
 #else
 #define MTK_WDMA_CNT	(0x2)
+#define MTK_GDM_RX_BASE	(0x8)
+#define MTK_GDM_CNT_OFFSET	(0x40)
+#define MTK_GDM_TX_BASE	(0x38)
 #endif
 
 enum mtk_reset_type {
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 010c992..6585c10 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
@@ -242,7 +242,7 @@
 	"top_eth_xgmii_sel", "top_eth_mii_sel", "top_netsys_sel",
 	"top_netsys_500m_sel", "top_netsys_pao_2x_sel",
 	"top_netsys_sync_250m_sel", "top_netsys_ppefb_250m_sel",
-	"top_netsys_warp_sel",
+	"top_netsys_warp_sel", "top_macsec_sel", "macsec_bus_clk",
 };
 
 void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg)
@@ -1564,6 +1564,17 @@
 	return true;
 }
 
+static void *mtk_max_lro_buf_alloc(gfp_t gfp_mask)
+{
+	unsigned int size = mtk_max_frag_size(MTK_MAX_LRO_RX_LENGTH);
+	unsigned long data;
+
+	data = __get_free_pages(gfp_mask | __GFP_COMP | __GFP_NOWARN,
+				get_order(size));
+
+	return (void *)data;
+}
+
 /* the qdma core needs scratch memory to be setup */
 static int mtk_init_fq_dma(struct mtk_eth *eth)
 {
@@ -2159,7 +2170,6 @@
 	struct mtk_rx_ring *ring = rx_napi->rx_ring;
 	int idx;
 	struct sk_buff *skb;
-	u64 addr64 = 0;
 	u8 *data, *new_data;
 	struct mtk_rx_dma_v2 *rxd, trxd;
 	int done = 0;
@@ -2170,7 +2180,8 @@
 	while (done < budget) {
 		unsigned int pktlen, *rxdcsum;
 		struct net_device *netdev = NULL;
-		dma_addr_t dma_addr = 0;
+		dma_addr_t dma_addr = DMA_MAPPING_ERROR;
+		u64 addr64 = 0;
 		int mac = 0;
 
 		idx = NEXT_DESP_IDX(ring->calc_idx, ring->dma_size);
@@ -2209,7 +2220,10 @@
 			goto release_desc;
 
 		/* alloc new buffer */
-		new_data = napi_alloc_frag(ring->frag_size);
+		if (ring->frag_size <= PAGE_SIZE)
+			new_data = napi_alloc_frag(ring->frag_size);
+		else
+			new_data = mtk_max_lro_buf_alloc(GFP_ATOMIC);
 		if (unlikely(!new_data)) {
 			netdev->stats.rx_dropped++;
 			goto release_desc;
@@ -2229,7 +2243,7 @@
 			  ((u64)(trxd.rxd2 & 0xf)) << 32 : 0;
 
 		dma_unmap_single(eth->dma_dev,
-				 (u64)(trxd.rxd1 | addr64),
+				 ((u64)(trxd.rxd1) | addr64),
 				 ring->buf_size, DMA_FROM_DEVICE);
 
 		/* receive data */
@@ -2313,8 +2327,12 @@
 		rxd->rxd1 = (unsigned int)dma_addr;
 
 release_desc:
-		addr64 = (MTK_HAS_CAPS(eth->soc->caps, MTK_8GB_ADDRESSING)) ?
-			  RX_DMA_SDP1(dma_addr) : 0;
+		if (MTK_HAS_CAPS(eth->soc->caps, MTK_8GB_ADDRESSING)) {
+			if (unlikely(dma_addr == DMA_MAPPING_ERROR))
+				addr64 = RX_DMA_GET_SDP1(rxd->rxd2);
+			else
+				addr64 = RX_DMA_SDP1(dma_addr);
+		}
 
 		if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628))
 			rxd->rxd2 = RX_DMA_LSO;
@@ -2692,7 +2710,10 @@
 		return -ENOMEM;
 
 	for (i = 0; i < rx_dma_size; i++) {
-		ring->data[i] = netdev_alloc_frag(ring->frag_size);
+		if (ring->frag_size <= PAGE_SIZE)
+			ring->data[i] = napi_alloc_frag(ring->frag_size);
+		else
+			ring->data[i] = mtk_max_lro_buf_alloc(GFP_ATOMIC);
 		if (!ring->data[i])
 			return -ENOMEM;
 	}
@@ -2800,7 +2821,7 @@
 				  ((u64)(rxd->rxd2 & 0xf)) << 32 : 0;
 
 			dma_unmap_single(eth->dma_dev,
-					 (u64)(rxd->rxd1 | addr64),
+					 ((u64)(rxd->rxd1) | addr64),
 					 ring->buf_size,
 					 DMA_FROM_DEVICE);
 			skb_free_frag(ring->data[i]);
@@ -3485,6 +3506,7 @@
 	struct mtk_rx_ring *ring = rx_napi->rx_ring;
 
 	if (unlikely(!(mtk_r32(eth, eth->soc->reg_map->pdma.irq_status) &
+		       mtk_r32(eth, eth->soc->reg_map->pdma.irq_mask) &
 		       MTK_RX_DONE_INT(ring->ring_no))))
 		return IRQ_NONE;
 
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 913302e..a48b363 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
@@ -618,6 +618,7 @@
 #define RX_DMA_GET_REV(_x)	(((_x) >> 10) & 0x1f)
 #define RX_DMA_VTAG		BIT(15)
 #define RX_DMA_SDP1(_x)		((((u64)(_x)) >> 32) & 0xf)
+#define RX_DMA_GET_SDP1(_x)	((_x) & 0xf)
 
 /* QDMA descriptor rxd3 */
 #define RX_DMA_VID(_x)		((_x) & VLAN_VID_MASK)
@@ -1145,6 +1146,8 @@
 	MTK_CLK_TOP_NETSYS_SYNC_250M_SEL,
 	MTK_CLK_TOP_NETSYS_PPEFB_250M_SEL,
 	MTK_CLK_TOP_NETSYS_WARP_SEL,
+	MTK_CLK_TOP_MACSEC_SEL,
+	MTK_CLK_TOP_NETSYS_TOPS_400M_SEL,
 	MTK_CLK_MAX
 };
 
@@ -1228,7 +1231,9 @@
 				 BIT(MTK_CLK_TOP_NETSYS_PAO_2X_SEL) | \
 				 BIT(MTK_CLK_TOP_NETSYS_SYNC_250M_SEL) | \
 				 BIT(MTK_CLK_TOP_NETSYS_PPEFB_250M_SEL) | \
-				 BIT(MTK_CLK_TOP_NETSYS_WARP_SEL))
+				 BIT(MTK_CLK_TOP_NETSYS_WARP_SEL) | \
+				 BIT(MTK_CLK_TOP_MACSEC_SEL) | \
+				 BIT(MTK_CLK_TOP_NETSYS_TOPS_400M_SEL))
 
 enum mtk_dev_state {
 	MTK_HW_INIT,
@@ -1702,7 +1707,9 @@
 	struct mtk_eth		*eth;
 	struct regmap		*regmap;
 	struct regmap		*regmap_pextp;
+	spinlock_t		regmap_lock;
 	phy_interface_t		interface;
+	__ETHTOOL_DECLARE_LINK_MODE_MASK(advertising);
 	u32			flags;
 	u32			ana_rgc3;
 	u8			id;
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 6d86f25..0ecdb25 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
@@ -384,11 +384,11 @@
 	u32 resv3_1 : 9;
 	u32 eg_keep_ecn : 1;
 	u32 eg_keep_dscp : 1;
-	u32 resv3_2:15;
+	u32 resv3_2:13;
 #else
-	u32 resv3:26;
+	u32 resv3:24;
 #endif
-	u32 act_dp : 6; /* UDF */
+	u32 act_dp : 8; /* UDF */
 	u16 vlan1;
 	u16 etype;
 	u32 dmac_hi;
@@ -446,11 +446,11 @@
 		u32 resv2_1 : 1;
 		u32 eg_keep_ecn : 1;
 		u32 eg_keep_cls : 1;
-		u32 resv2_2 : 15;
+		u32 resv2_2 : 13;
 #else
-		u32 resv2 : 18;
+		u32 resv2 : 16;
 #endif
-	u32 act_dp : 6; /* UDF */
+	u32 act_dp : 8; /* UDF */
 
 	union {
 		struct hnat_info_blk2 iblk2;
@@ -515,11 +515,11 @@
 		u32 resv2_1 : 1;
 		u32 eg_keep_ecn : 1;
 		u32 eg_keep_dscp : 1;
-		u32 resv2_2 : 15;
+		u32 resv2_2 : 13;
 #else
-	u32 resv2 : 18;
+	u32 resv2 : 16;
 #endif
-	u32 act_dp : 6; /* UDF */
+	u32 act_dp : 8; /* UDF */
 
 	union {
 		struct hnat_info_blk2 iblk2;
@@ -588,11 +588,11 @@
 	u32 resv4_1 : 9;
 	u32 eg_keep_ecn : 1;
 	u32 eg_keep_cls : 1;
-	u32 resv4_2 : 15;
+	u32 resv4_2 : 13;
 #else
-	u32 resv4 : 26;
+	u32 resv4 : 24;
 #endif
-	u32 act_dp : 6; /* UDF */
+	u32 act_dp : 8; /* UDF */
 
 	union {
 		struct hnat_info_blk2 iblk2;
@@ -652,11 +652,11 @@
 	u32 resv4_1 : 9;
 	u32 eg_keep_ecn : 1;
 	u32 eg_keep_cls : 1;
-	u32 resv4_2 : 15;
+	u32 resv4_2 : 13;
 #else
-	u32 resv4 : 26;
+	u32 resv4 : 24;
 #endif
-	u32 act_dp : 6; /* UDF */
+	u32 act_dp : 8; /* UDF */
 
 	union {
 		struct hnat_info_blk2 iblk2;
@@ -723,13 +723,13 @@
 	u32 eg_keep_tnl_qos : 1;
 	u32 resv1_2 : 4;
 	u32 per_flow_6rd_id : 1;
-	u32 resv2 : 9;
+	u32 resv2 : 7;
 #else
 	u32 resv1 : 13;
 	u32 per_flow_6rd_id : 1;
-	u32 resv2 : 9;
+	u32 resv2 : 7;
 #endif
-	u32 act_dp : 6; /* UDF */
+	u32 act_dp : 8; /* UDF */
 
 	union {
 		struct hnat_info_blk2 iblk2;
@@ -790,8 +790,8 @@
 	u32 eg_ipv6_dir : 1;
 	u32 eg_keep_ecn : 1;
 	u32 eg_keep_cls : 1;
-	u32 resv5 : 15;
-	u32 act_dp : 6; /* UDF */
+	u32 resv5 : 13;
+	u32 act_dp : 8; /* UDF */
 
 	union {
 		struct hnat_info_blk2 iblk2;
@@ -1220,8 +1220,8 @@
 #define NEXTHDR_IPIP 4
 #endif
 
-#define UDF_PINGPONG_IFIDX GENMASK(3, 0)
-#define UDF_HNAT_PRE_FILLED BIT(4)
+#define UDF_PINGPONG_IFIDX GENMASK(6, 0)
+#define UDF_HNAT_PRE_FILLED BIT(7)
 
 #define HQOS_FLAG(dev, skb, qid)			\
 	((IS_HQOS_UL_MODE && IS_WAN(dev)) ||		\
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 7efe182..34fc091 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
@@ -2971,73 +2971,168 @@
 	}
 
 	buf[len] = '\0';
-#if defined(CONFIG_MEDIATEK_NETSYS_V3)
-	if (sscanf(buf,
-		   "%5d %8x %8x %8x %hx %hx %8x %8x %8x %hx %hx %18s %18s %4x %4x %4x",
-		   &hash,
-		   &entry.ipv4_hnapt.info_blk1,
-		   &entry.ipv4_hnapt.sip,
-		   &entry.ipv4_hnapt.dip,
-		   &entry.ipv4_hnapt.sport,
-		   &entry.ipv4_hnapt.dport,
-		   &entry.ipv4_hnapt.info_blk2,
-		   &entry.ipv4_hnapt.new_sip,
-		   &entry.ipv4_hnapt.new_dip,
-		   &entry.ipv4_hnapt.new_sport,
-		   &entry.ipv4_hnapt.new_dport,
-		   dmac_str, smac_str, &tport_id, &tops_entry, &cdrt_id) != 16)
-		return -EFAULT;
 
-	if ((hash >= (int)hnat_priv->foe_etry_num) || (hash < -1) ||
-	    (TPORT_ID(tport_id) != tport_id) ||
-	    (TOPS_ENTRY(tops_entry) != tops_entry) ||
-	    (CDRT_ID(cdrt_id) != cdrt_id)) {
-		hnat_static_entry_help();
+	if (sscanf(buf, "%5d %8x", &hash, &entry.ipv4_hnapt.info_blk1) != 2) {
+		pr_info("Unknown input format!\n");
 		return -EFAULT;
 	}
 
+	if (entry.ipv4_hnapt.bfib1.pkt_type == IPV4_HNAPT) {
+#if defined(CONFIG_MEDIATEK_NETSYS_V3)
+		if (sscanf(buf,
+			"%5d %8x %8x %8x %hx %hx %8x %8x %8x %hx %hx %18s %18s %4x %4x %4x",
+			&hash,
+			&entry.ipv4_hnapt.info_blk1,
+			&entry.ipv4_hnapt.sip,
+			&entry.ipv4_hnapt.dip,
+			&entry.ipv4_hnapt.sport,
+			&entry.ipv4_hnapt.dport,
+			&entry.ipv4_hnapt.info_blk2,
+			&entry.ipv4_hnapt.new_sip,
+			&entry.ipv4_hnapt.new_dip,
+			&entry.ipv4_hnapt.new_sport,
+			&entry.ipv4_hnapt.new_dport,
+			dmac_str, smac_str, &tport_id, &tops_entry, &cdrt_id) != 16)
+			return -EFAULT;
+
+		if ((hash >= (int)hnat_priv->foe_etry_num) || (hash < -1) ||
+			(TPORT_ID(tport_id) != tport_id) ||
+			(TOPS_ENTRY(tops_entry) != tops_entry) ||
+			(CDRT_ID(cdrt_id) != cdrt_id)) {
+			hnat_static_entry_help();
+			return -EFAULT;
+		}
+
-	entry.ipv4_hnapt.tport_id = tport_id;
-	entry.ipv4_hnapt.tops_entry = tops_entry;
-	entry.ipv4_hnapt.cdrt_id = cdrt_id;
+		entry.ipv4_hnapt.tport_id = tport_id;
+		entry.ipv4_hnapt.tops_entry = tops_entry;
+		entry.ipv4_hnapt.cdrt_id = cdrt_id;
 #else
-	if (sscanf(buf,
-		   "%5d %8x %8x %8x %hx %hx %8x %8x %8x %hx %hx %18s %18s",
-		   &hash,
-		   &entry.ipv4_hnapt.info_blk1,
-		   &entry.ipv4_hnapt.sip,
-		   &entry.ipv4_hnapt.dip,
-		   &entry.ipv4_hnapt.sport,
-		   &entry.ipv4_hnapt.dport,
-		   &entry.ipv4_hnapt.info_blk2,
-		   &entry.ipv4_hnapt.new_sip,
-		   &entry.ipv4_hnapt.new_dip,
-		   &entry.ipv4_hnapt.new_sport,
-		   &entry.ipv4_hnapt.new_dport,
-		   dmac_str, smac_str) != 13)
-		return -EFAULT;
+		if (sscanf(buf,
+			"%5d %8x %8x %8x %hx %hx %8x %8x %8x %hx %hx %18s %18s",
+			&hash,
+			&entry.ipv4_hnapt.info_blk1,
+			&entry.ipv4_hnapt.sip,
+			&entry.ipv4_hnapt.dip,
+			&entry.ipv4_hnapt.sport,
+			&entry.ipv4_hnapt.dport,
+			&entry.ipv4_hnapt.info_blk2,
+			&entry.ipv4_hnapt.new_sip,
+			&entry.ipv4_hnapt.new_dip,
+			&entry.ipv4_hnapt.new_sport,
+			&entry.ipv4_hnapt.new_dport,
+			dmac_str, smac_str) != 13)
+			return -EFAULT;
 
-	if ((hash >= (int)hnat_priv->foe_etry_num) || (hash < -1)) {
-		hnat_static_entry_help();
+		if ((hash >= (int)hnat_priv->foe_etry_num) || (hash < -1)) {
+			hnat_static_entry_help();
+			return -EFAULT;
+		}
+#endif
+	} else if (entry.ipv4_hnapt.bfib1.pkt_type == IPV6_5T_ROUTE) {
+#if defined(CONFIG_MEDIATEK_NETSYS_V3)
+		if (sscanf(buf,
+			"%5d %8x %8x%8x%8x%8x %8x%8x%8x%8x %hx %hx %8x %18s %18s %4x %4x %4x",
+			&hash,
+			&entry.ipv6_5t_route.info_blk1,
+			&entry.ipv6_5t_route.ipv6_sip0,
+			&entry.ipv6_5t_route.ipv6_sip1,
+			&entry.ipv6_5t_route.ipv6_sip2,
+			&entry.ipv6_5t_route.ipv6_sip3,
+			&entry.ipv6_5t_route.ipv6_dip0,
+			&entry.ipv6_5t_route.ipv6_dip1,
+			&entry.ipv6_5t_route.ipv6_dip2,
+			&entry.ipv6_5t_route.ipv6_dip3,
+			&entry.ipv6_5t_route.sport,
+			&entry.ipv6_5t_route.dport,
+			&entry.ipv6_5t_route.info_blk2,
+			dmac_str, smac_str, &tport_id, &tops_entry, &cdrt_id) != 18)
+			return -EFAULT;
+
+		if ((hash >= (int)hnat_priv->foe_etry_num) || (hash < -1) ||
+			(TPORT_ID(tport_id) != tport_id) ||
+			(TOPS_ENTRY(tops_entry) != tops_entry) ||
+			(CDRT_ID(cdrt_id) != cdrt_id)) {
+			hnat_static_entry_help();
+			return -EFAULT;
+		}
+
+		entry.ipv6_5t_route.tport_id = tport_id;
+		entry.ipv6_5t_route.tops_entry = tops_entry;
+		entry.ipv6_5t_route.cdrt_id = cdrt_id;
+#else
+		if (sscanf(buf,
+			"%5d %8x %8x%8x%8x%8x %8x%8x%8x%8x %hx %hx %8x %18s %18s",
+			&hash,
+			&entry.ipv6_5t_route.info_blk1,
+			&entry.ipv6_5t_route.ipv6_sip0,
+			&entry.ipv6_5t_route.ipv6_sip1,
+			&entry.ipv6_5t_route.ipv6_sip2,
+			&entry.ipv6_5t_route.ipv6_sip3,
+			&entry.ipv6_5t_route.ipv6_dip0,
+			&entry.ipv6_5t_route.ipv6_dip1,
+			&entry.ipv6_5t_route.ipv6_dip2,
+			&entry.ipv6_5t_route.ipv6_dip3,
+			&entry.ipv6_5t_route.sport,
+			&entry.ipv6_5t_route.dport,
+			&entry.ipv6_5t_route.info_blk2,
+			dmac_str, smac_str) != 15)
+			return -EFAULT;
+
+		if ((hash >= (int)hnat_priv->foe_etry_num) || (hash < -1)) {
+			hnat_static_entry_help();
+			return -EFAULT;
+		}
+#endif
+	} else {
+		pr_info("Unknown packet type!\n");
 		return -EFAULT;
 	}
-#endif
+
 
 	hnat_parse_mac(smac_str, smac);
 	hnat_parse_mac(dmac_str, dmac);
-	entry.ipv4_hnapt.dmac_hi = swab32(*((u32 *)dmac));
-	entry.ipv4_hnapt.dmac_lo = swab16(*((u16 *)&dmac[4]));
-	entry.ipv4_hnapt.smac_hi = swab32(*((u32 *)smac));
-	entry.ipv4_hnapt.smac_lo = swab16(*((u16 *)&smac[4]));
+	if (entry.ipv4_hnapt.bfib1.pkt_type == IPV4_HNAPT) {
+		entry.ipv4_hnapt.dmac_hi = swab32(*((u32 *)dmac));
+		entry.ipv4_hnapt.dmac_lo = swab16(*((u16 *)&dmac[4]));
+		entry.ipv4_hnapt.smac_hi = swab32(*((u32 *)smac));
+		entry.ipv4_hnapt.smac_lo = swab16(*((u16 *)&smac[4]));
+	} else if (entry.ipv4_hnapt.bfib1.pkt_type == IPV6_5T_ROUTE) {
+		entry.ipv6_5t_route.dmac_hi = swab32(*((u32 *)dmac));
+		entry.ipv6_5t_route.dmac_lo = swab16(*((u16 *)&dmac[4]));
+		entry.ipv6_5t_route.smac_hi = swab32(*((u32 *)smac));
+		entry.ipv6_5t_route.smac_lo = swab16(*((u16 *)&smac[4]));
+	}
 
 	if (hash == -1)
 		hash = hnat_get_ppe_hash(&entry);
 
+#if defined(CONFIG_MEDIATEK_NETSYS_V3)
+	if (CFG_PPE_NUM == 3) {
+		switch (entry.ipv4_hnapt.bfib1.sp) {
+		case NR_GMAC1_PORT:
+			ppe_id = 0;
+			break;
+		case NR_GMAC2_PORT:
+			ppe_id = 1;
+			break;
+		case NR_GMAC3_PORT:
+			ppe_id = 2;
+			break;
+		default:
+			break;
+		}
+	}
+#endif
+
 	foe = &hnat_priv->foe_table_cpu[ppe_id][hash];
 	while ((foe->ipv4_hnapt.bfib1.state == BIND) && (coll < 4)) {
 		hash++;
 		coll++;
 		foe = &hnat_priv->foe_table_cpu[ppe_id][hash];
 	};
+
+	/* We must ensure all info has been updated before set to hw */
+	wmb();
 	memcpy(foe, &entry, sizeof(entry));
 
 	debug_level = 7;
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 75ae019..9fe85fb 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
@@ -1242,6 +1242,9 @@
 	entry.bfib1.pkt_type = foe->udib1.pkt_type; /* Get packte type state*/
 	entry.bfib1.state = foe->udib1.state;
 
+	if (unlikely(entry.bfib1.state != UNBIND))
+		return 0;
+
 #if defined(CONFIG_MEDIATEK_NETSYS_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
 	entry.bfib1.sp = foe->udib1.sp;
 #endif
@@ -1820,7 +1823,7 @@
 				entry.ipv6_5t_route.iblk2.fqos = 0;
 			else
 #if defined(CONFIG_MEDIATEK_NETSYS_V3)
-				switch (foe->bfib1.pkt_type) {
+				switch (entry.bfib1.pkt_type) {
 				case IPV4_MAP_E:
 				case IPV4_MAP_T:
 					entry.ipv4_mape.tport_id =
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 bdb6662..54ec897 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
@@ -73,6 +73,15 @@
 	return 0;
 }
 
+int mtk_sgmii_link_status(struct mtk_sgmii_pcs *mpcs)
+{
+	unsigned int val;
+
+	regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val);
+
+	return FIELD_GET(SGMII_LINK_STATYS, val);
+}
+
 void mtk_sgmii_reset(struct mtk_eth *eth, int id)
 {
 	u32 val = 0;
@@ -378,47 +387,6 @@
 	udelay(400);
 }
 
-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;
-
-	state->interface = mpcs->interface;
-
-	regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &bm);
-	if (bm & SGMII_AN_ENABLE) {
-		regmap_read(mpcs->regmap, SGMSYS_PCS_ADVERTISE, &adv);
-
-		phylink_mii_c22_pcs_decode_state(state,
-						 FIELD_GET(SGMII_BMSR, bm),
-						 FIELD_GET(SGMII_LPA, adv));
-	} else {
-		state->link = !!(bm & SGMII_LINK_STATYS);
-
-		regmap_read(mpcs->regmap, SGMSYS_SGMII_MODE, &sgm_mode);
-
-		switch (sgm_mode & SGMII_SPEED_MASK) {
-		case SGMII_SPEED_10:
-			state->speed = SPEED_10;
-			break;
-		case SGMII_SPEED_100:
-			state->speed = SPEED_100;
-			break;
-		case SGMII_SPEED_1000:
-			regmap_read(mpcs->regmap, mpcs->ana_rgc3, &rgc3);
-			rgc3 = FIELD_GET(RG_PHY_SPEED_3_125G, rgc3);
-			state->speed = rgc3 ? SPEED_2500 : SPEED_1000;
-			break;
-		}
-
-		if (sgm_mode & SGMII_DUPLEX_HALF)
-			state->duplex = DUPLEX_HALF;
-		else
-			state->duplex = DUPLEX_FULL;
-	}
-}
-
 static int mtk_sgmii_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
 				phy_interface_t interface,
 				const unsigned long *advertising,
@@ -435,6 +403,8 @@
 	if (advertise < 0)
 		return advertise;
 
+	spin_lock(&mpcs->regmap_lock);
+
 	/* Clearing IF_MODE_BIT0 switches the PCS to BASE-X mode, and
 	 * we assume that fixes it's speed at bitrate = line rate (in
 	 * other words, 1000Mbps or 2500Mbps).
@@ -461,8 +431,10 @@
 	if (mpcs->interface != interface ||
 	    mtk_sgmii_need_powerdown(mpcs, bmcr)) {
 		link_timer = phylink_get_link_timer_ns(interface);
-		if (link_timer < 0)
+		if (link_timer < 0) {
+			spin_unlock(&mpcs->regmap_lock);
 			return link_timer;
+		}
 
 		if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
 			mtk_sgmii_xfi_pll_enable(eth->sgmii);
@@ -497,6 +469,7 @@
 			     link_timer / 2 / 8);
 
 		mpcs->interface = interface;
+		linkmode_copy(mpcs->advertising, advertising);
 		mode_changed = true;
 	}
 
@@ -527,9 +500,62 @@
 		}
 	}
 
+	spin_unlock(&mpcs->regmap_lock);
+
 	return changed || mode_changed;
 }
 
+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;
+
+	regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &bm);
+	if (bm & SGMII_AN_ENABLE) {
+		regmap_read(mpcs->regmap, SGMSYS_PCS_ADVERTISE, &adv);
+
+		phylink_mii_c22_pcs_decode_state(state,
+						 FIELD_GET(SGMII_BMSR, bm),
+						 FIELD_GET(SGMII_LPA, adv));
+	} else {
+		state->link = !!(bm & SGMII_LINK_STATYS);
+
+		regmap_read(mpcs->regmap, SGMSYS_SGMII_MODE, &sgm_mode);
+
+		switch (sgm_mode & SGMII_SPEED_MASK) {
+		case SGMII_SPEED_10:
+			state->speed = SPEED_10;
+			break;
+		case SGMII_SPEED_100:
+			state->speed = SPEED_100;
+			break;
+		case SGMII_SPEED_1000:
+			regmap_read(mpcs->regmap, mpcs->ana_rgc3, &rgc3);
+			rgc3 = FIELD_GET(RG_PHY_SPEED_3_125G, rgc3);
+			state->speed = rgc3 ? SPEED_2500 : SPEED_1000;
+			break;
+		}
+
+		if (sgm_mode & SGMII_DUPLEX_HALF)
+			state->duplex = DUPLEX_HALF;
+		else
+			state->duplex = DUPLEX_FULL;
+	}
+
+	/* 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;
+		mtk_sgmii_pcs_config(pcs, MLO_AN_INBAND,
+				     state->interface, mpcs->advertising, false);
+	}
+}
+
 void mtk_sgmii_pcs_restart_an(struct phylink_pcs *pcs)
 {
 	struct mtk_sgmii_pcs *mpcs = pcs_to_mtk_sgmii_pcs(pcs);
@@ -549,7 +575,22 @@
 {
 	struct mtk_sgmii_pcs *mpcs = pcs_to_mtk_sgmii_pcs(pcs);
 	unsigned int sgm_mode, val;
+	unsigned long t_start = jiffies;
+
+	do {
+		msleep(1000);
+
+		if (mtk_sgmii_link_status(mpcs))
+			goto exit;
 
+		if (mode == MLO_AN_PHY)
+			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__);
+
+exit:
 	/* If autoneg is enabled, the force speed and duplex
 	 * are not useful, so don't go any further.
 	 */
@@ -607,6 +648,8 @@
 		ss->pcs[i].pcs.poll = true;
 		ss->pcs[i].interface = PHY_INTERFACE_MODE_NA;
 
+		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 cdb2a55..f114225 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
@@ -594,8 +594,10 @@
 		xfi_mode = FIELD_PREP(USXGMII_XFI_RX_MODE, USXGMII_XFI_RX_MODE_5G) |
 			   FIELD_PREP(USXGMII_XFI_TX_MODE, USXGMII_XFI_TX_MODE_5G);
 		adapt_mode = USXGMII_RATE_UPDATE_MODE;
-	} else
+	} else {
+		spin_unlock(&mpcs->regmap_lock);
 		return -EINVAL;
+	}
 
 	adapt_mode |= FIELD_PREP(USXGMII_RATE_ADAPT_MODE, USXGMII_RATE_ADAPT_MODE_X1);
 
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
new file mode 100644
index 0000000..2861c2e
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/an8801.c
@@ -0,0 +1,993 @@
+// SPDX-License-Identifier: GPL-2.0
+/* FILE NAME:  an8801.c
+ * PURPOSE:
+ *      Airoha phy driver for Linux
+ * NOTES:
+ *
+ */
+
+/* INCLUDE FILE DECLARATIONS
+ */
+
+#include <linux/of_device.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/phy.h>
+#include <linux/version.h>
+#include <linux/debugfs.h>
+
+#include "an8801.h"
+
+MODULE_DESCRIPTION("Airoha AN8801 PHY drivers");
+MODULE_AUTHOR("Airoha");
+MODULE_LICENSE("GPL");
+
+#define phydev_mdiobus(phy)        ((phy)->mdio.bus)
+#define phydev_mdiobus_lock(phy)   (phydev_mdiobus(phy)->mdio_lock)
+#define phydev_cfg(phy)            ((struct an8801_priv *)(phy)->priv)
+
+#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)
+
+#ifdef AN8801SB_DEBUGFS
+#define AN8801_DEBUGFS_POLARITY_HELP_STRING \
+	"\nUsage: echo [tx_polarity] [rx_polarity] > /sys/" \
+	"kernel/debug/mdio-bus\':[phy_addr]/polarity" \
+	"\npolarity: tx_normal, tx_reverse, rx_normal, rx_reverse" \
+	"\ntx_normal is tx polarity is normal." \
+	"\ntx_reverse is tx polarity need to be swapped." \
+	"\nrx_normal is rx polarity is normal." \
+	"\nrx_reverse is rx polarity need to be swapped." \
+	"\nFor example tx polarity need to be swapped. " \
+	"But rx polarity is normal." \
+	"\necho tx_reverse rx_normal > /sys/" \
+	"kernel/debug/mdio-bus\':[phy_addr]/polarity" \
+	"\n"
+#define AN8801_DEBUGFS_RX_ERROR_STRING \
+	"\nRx param is not correct." \
+	"\nrx_normal: rx polarity is normal." \
+	"rx_reverse: rx polarity is reverse.\n"
+#define AN8801_DEBUGFS_TX_ERROR_STRING \
+	"\nTx param is not correct." \
+	"\ntx_normal: tx polarity is normal." \
+	"tx_reverse: tx polarity is reverse.\n"
+#define AN8801_DEBUGFS_PBUS_HELP_STRING \
+	"\nUsage: echo w [pbus_addr] [pbus_reg] [value] > /sys/" \
+	"kernel/debug/mdio-bus\':[phy_addr]/pbus_reg_op" \
+	"\n       echo r [pbus_addr] [pbus_reg] > /sys/" \
+	"kernel/debug/mdio-bus\':[phy_addr]/pbus_reg_op" \
+	"\nRead example: PBUS addr 0x19, Register 0x19a4" \
+	"\necho r 19 19a4 > /sys/" \
+	"kernel/debug/mdio-bus\':[phy_addr]/pbus_reg_op" \
+	"\nWrite example: PBUS addr 0x19, Register 0xcf8 0x1a01503" \
+	"\necho w 19 cf8 1a01503> /sys/" \
+	"kernel/debug/mdio-bus\':[phy_addr]/pbus_reg_op" \
+	"\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,
+ *	GPIO3    <-> LED2,
+ */
+/* User-defined.B */
+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},
+	/* LED1 */
+	{LED_ENABLE, AIR_LED_GPIO2, AIR_ACTIVE_HIGH, AIR_LED1_ON, AIR_LED1_BLK},
+	/* LED2 */
+	{LED_ENABLE, AIR_LED_GPIO3, AIR_ACTIVE_HIGH, AIR_LED2_ON, AIR_LED2_BLK},
+};
+
+static const u16 led_blink_cfg_dlt = AIR_LED_BLK_DUR_64M;
+/* RGMII delay */
+static const u8 rxdelay_force = FALSE;
+static const u8 txdelay_force = FALSE;
+static const u16 rxdelay_step = AIR_RGMII_DELAY_NOSTEP;
+static const u8 rxdelay_align = FALSE;
+static const u16 txdelay_step = AIR_RGMII_DELAY_NOSTEP;
+/* User-defined.E */
+
+/************************************************************************
+ *                  F U N C T I O N S
+ ************************************************************************/
+static int __air_buckpbus_reg_write(struct phy_device *phydev, u32 addr,
+				    u32 data)
+{
+	int err = 0;
+
+	err = __phy_write(phydev, 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);
+
+	return err;
+}
+
+static u32 __air_buckpbus_reg_read(struct phy_device *phydev, u32 addr)
+{
+	int err = 0;
+	u32 data_h, data_l, data;
+
+	err = __phy_write(phydev, 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);
+	if (err)
+		return INVALID_DATA;
+
+	data = ((data_h & 0xffff) << 16) | (data_l & 0xffff);
+	return data;
+}
+
+static int air_buckpbus_reg_write(struct phy_device *phydev, u32 addr, u32 data)
+{
+	int err = 0;
+
+	mdiobus_lock(phydev);
+	err = __air_buckpbus_reg_write(phydev, addr, data);
+	mdiobus_unlock(phydev);
+
+	return err;
+}
+
+static u32 air_buckpbus_reg_read(struct phy_device *phydev, u32 addr)
+{
+	u32 data;
+
+	mdiobus_lock(phydev);
+	data = __air_buckpbus_reg_read(phydev, addr);
+	mdiobus_unlock(phydev);
+
+	return data;
+}
+
+static int __an8801_cl45_write(struct phy_device *phydev, int devad, u16 reg,
+				u16 val)
+{
+	u32 addr = (AN8801_EPHY_ADDR | AN8801_CL22 | (devad << 18) |
+				(reg << 2));
+
+	return __air_buckpbus_reg_write(phydev, addr, val);
+}
+
+static int __an8801_cl45_read(struct phy_device *phydev, int devad, u16 reg)
+{
+	u32 addr = (AN8801_EPHY_ADDR | AN8801_CL22 | (devad << 18) |
+				(reg << 2));
+
+	return __air_buckpbus_reg_read(phydev, addr);
+}
+
+static int an8801_cl45_write(struct phy_device *phydev, int devad, u16 reg,
+			      u16 val)
+{
+	int err = 0;
+
+	mdiobus_lock(phydev);
+	err = __an8801_cl45_write(phydev, devad, reg, val);
+	mdiobus_unlock(phydev);
+
+	return err;
+}
+
+static int an8801_cl45_read(struct phy_device *phydev, int devad, u16 reg,
+			     u16 *read_data)
+{
+	int data = 0;
+
+	mdiobus_lock(phydev);
+	data = __an8801_cl45_read(phydev, devad, reg);
+	mdiobus_unlock(phydev);
+
+	if (data == INVALID_DATA)
+		return -EINVAL;
+
+	*read_data = data;
+
+	return 0;
+}
+
+static int air_sw_reset(struct phy_device *phydev)
+{
+	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);
+	do {
+		mdelay(10);
+		reg_value = phy_read(phydev, MII_BMCR);
+		retry--;
+		if (retry == 0) {
+			phydev_err(phydev, "Reset fail !\n");
+			return -1;
+		}
+	} while (reg_value & BMCR_RESET);
+
+	return 0;
+}
+
+static int an8801_led_set_usr_def(struct phy_device *phydev, u8 entity,
+				   u16 polar, u16 on_evt, u16 blk_evt)
+{
+	int err;
+
+	if (polar == AIR_ACTIVE_HIGH)
+		on_evt |= LED_ON_POL;
+	else
+		on_evt &= ~LED_ON_POL;
+
+	on_evt |= LED_ON_EN;
+
+	err = an8801_cl45_write(phydev, 0x1f, LED_ON_CTRL(entity), on_evt);
+	if (err)
+		return -1;
+
+	return an8801_cl45_write(phydev, 0x1f, LED_BLK_CTRL(entity), blk_evt);
+}
+
+static int an8801_led_set_mode(struct phy_device *phydev, u8 mode)
+{
+	int err;
+	u16 data;
+
+	err = an8801_cl45_read(phydev, 0x1f, LED_BCR, &data);
+	if (err)
+		return -1;
+
+	switch (mode) {
+	case AIR_LED_MODE_DISABLE:
+		data &= ~LED_BCR_EXT_CTRL;
+		data &= ~LED_BCR_MODE_MASK;
+		data |= LED_BCR_MODE_DISABLE;
+		break;
+	case AIR_LED_MODE_USER_DEFINE:
+		data |= (LED_BCR_EXT_CTRL | LED_BCR_CLK_EN);
+		break;
+	}
+	return an8801_cl45_write(phydev, 0x1f, LED_BCR, data);
+}
+
+static int an8801_led_set_state(struct phy_device *phydev, u8 entity, u8 state)
+{
+	u16 data;
+	int err;
+
+	err = an8801_cl45_read(phydev, 0x1f, LED_ON_CTRL(entity), &data);
+	if (err)
+		return err;
+
+	if (state)
+		data |= LED_ON_EN;
+	else
+		data &= ~LED_ON_EN;
+
+	return an8801_cl45_write(phydev, 0x1f, LED_ON_CTRL(entity), data);
+}
+
+static int an8801_led_init(struct phy_device *phydev)
+{
+	struct an8801_priv *priv = phydev_cfg(phydev);
+	struct AIR_LED_CFG_T *led_cfg = priv->led_cfg;
+	int ret, led_id;
+	u32 data;
+	u16 led_blink_cfg = priv->led_blink_cfg;
+
+	ret = an8801_cl45_write(phydev, 0x1f, LED_BLK_DUR,
+				 LED_BLINK_DURATION(led_blink_cfg));
+	if (ret)
+		return ret;
+
+	ret = an8801_cl45_write(phydev, 0x1f, LED_ON_DUR,
+				 (LED_BLINK_DURATION(led_blink_cfg) >> 1));
+	if (ret)
+		return ret;
+
+	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);
+		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,
+				   "LED fail to set LED(%d) state, ret %d !\n",
+				   led_id, ret);
+			return ret;
+		}
+		if (led_cfg[led_id].en == LED_ENABLE) {
+			data = air_buckpbus_reg_read(phydev, 0x10000054);
+			data |= BIT(led_cfg[led_id].gpio);
+			ret |= air_buckpbus_reg_write(phydev, 0x10000054, data);
+
+			data = air_buckpbus_reg_read(phydev, 0x10000058);
+			data |= LED_GPIO_SEL(led_id, led_cfg[led_id].gpio);
+			ret |= air_buckpbus_reg_write(phydev, 0x10000058, data);
+
+			data = air_buckpbus_reg_read(phydev, 0x10000070);
+			data &= ~BIT(led_cfg[led_id].gpio);
+			ret |= air_buckpbus_reg_write(phydev, 0x10000070, data);
+
+			ret |= an8801_led_set_usr_def(phydev, led_id,
+				led_cfg[led_id].pol,
+				led_cfg[led_id].on_cfg,
+				led_cfg[led_id].blk_cfg);
+			if (ret != 0) {
+				phydev_err(phydev,
+					   "Fail to set LED(%d) usr def, ret %d !\n",
+					   led_id, ret);
+				return ret;
+			}
+		}
+	}
+	phydev_info(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 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.");
+			return -1;
+		}
+		if (val < AIR_RGMII_DELAY_NOSTEP ||
+		    val > AIR_RGMII_DELAY_STEP_7) {
+			phydev_err(phydev,
+				   "airoha,rxclk-delay value %u out of range.",
+				   val);
+			return -1;
+		}
+		priv->rxdelay_force = TRUE;
+		priv->rxdelay_step = val;
+		priv->rxdelay_align = of_property_read_bool(of_node,
+							    "airoha,rxclk-delay-align");
+	}
+
+	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,
+				   "airoha,txclk-delay value is invalid.");
+			return -1;
+		}
+		if (val < AIR_RGMII_DELAY_NOSTEP ||
+		    val > AIR_RGMII_DELAY_STEP_7) {
+			phydev_err(phydev,
+				   "airoha,txclk-delay value %u out of range.",
+				   val);
+			return -1;
+		}
+		priv->txdelay_force = TRUE;
+		priv->txdelay_step = val;
+	}
+
+	return 0;
+}
+#else
+static int an8801r_of_init(struct phy_device *phydev)
+{
+	return 0;
+}
+#endif /* CONFIG_OF */
+
+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");
+	}
+	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);
+	return 0;
+}
+
+static int an8801r_rgmii_txdelay(struct phy_device *phydev, u16 delay)
+{
+	u32 reg_val = delay & RGMII_DELAY_STEP_MASK;
+
+	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);
+	return 0;
+}
+
+static int an8801r_rgmii_delay_config(struct phy_device *phydev)
+{
+	struct an8801_priv *priv = phydev_cfg(phydev);
+
+	if (priv->rxdelay_force)
+		an8801r_rgmii_rxdelay(phydev, priv->rxdelay_step,
+				      priv->rxdelay_align);
+	if (priv->txdelay_force)
+		an8801r_rgmii_txdelay(phydev, priv->txdelay_step);
+	return 0;
+}
+
+static int an8801sb_config_init(struct phy_device *phydev)
+{
+	int ret;
+
+	/* 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);
+	if (ret != 0) {
+		phydev_err(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);
+		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);
+	return 0;
+}
+
+static int an8801r_config_init(struct phy_device *phydev)
+{
+	int ret;
+
+	ret = an8801r_of_init(phydev);
+	if (ret < 0)
+		return ret;
+
+	ret = air_sw_reset(phydev);
+	if (ret < 0)
+		return ret;
+
+	air_buckpbus_reg_write(phydev, 0x11F808D0, 0x180);
+
+	air_buckpbus_reg_write(phydev, 0x1021c004, 0x1);
+	air_buckpbus_reg_write(phydev, 0x10270004, 0x3f);
+	air_buckpbus_reg_write(phydev, 0x10270104, 0xff);
+	air_buckpbus_reg_write(phydev, 0x10270204, 0xff);
+
+	an8801r_rgmii_delay_config(phydev);
+
+	ret = an8801_led_init(phydev);
+	if (ret != 0) {
+		phydev_err(phydev, "LED initialize fail, ret %d !\n", ret);
+		return ret;
+	}
+	phydev_info(phydev, "AN8801R Initialize OK ! (%s)\n",
+		AN8801_DRIVER_VERSION);
+	return 0;
+}
+
+static int an8801_config_init(struct phy_device *phydev)
+{
+	if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
+		an8801sb_config_init(phydev);
+	} else if (phydev->interface == PHY_INTERFACE_MODE_RGMII) {
+		an8801r_config_init(phydev);
+	} else {
+		phydev_info(phydev, "AN8801 Phy-mode not support!!!\n");
+		return -1;
+	}
+	return 0;
+}
+
+#ifdef AN8801SB_DEBUGFS
+static const char * const tx_rx_string[32] = {
+		"Tx Normal, Rx Reverse",
+		"Tx Reverse, Rx Reverse",
+		"Tx Normal, Rx Normal",
+		"Tx Reverse, Rx Normal",
+};
+
+int an8801_set_polarity(struct phy_device *phydev, int tx_rx)
+{
+	int ret = 0;
+	unsigned long pbus_data = 0;
+
+	pr_notice("\n[Write] Polarity %s\n", tx_rx_string[tx_rx]);
+	pbus_data = (air_buckpbus_reg_read(phydev, 0x1022a0f8) &
+				(~(BIT(0) | BIT(1))));
+	pbus_data |= (BIT(4) | tx_rx);
+	ret = air_buckpbus_reg_write(phydev, 0x1022a0f8, pbus_data);
+	if (ret < 0)
+		return ret;
+	usleep_range(9800, 12000);
+	pbus_data &= ~BIT(4);
+	ret = air_buckpbus_reg_write(phydev, 0x1022a0f8, pbus_data);
+	if (ret < 0)
+		return ret;
+	pbus_data = air_buckpbus_reg_read(phydev, 0x1022a0f8);
+	tx_rx = pbus_data & (BIT(0) | BIT(1));
+	pr_notice("\n[Read] Polarity %s confirm....(%8lx)\n",
+		tx_rx_string[tx_rx], pbus_data);
+
+	return ret;
+}
+
+int air_polarity_help(void)
+{
+	pr_notice(AN8801_DEBUGFS_POLARITY_HELP_STRING);
+	return 0;
+}
+
+static ssize_t an8801_polarity_write(struct file *file, const char __user *ptr,
+					size_t len, loff_t *off)
+{
+	struct phy_device *phydev = file->private_data;
+	char buf[32], param1[32], param2[32];
+	int count = len, ret = 0, tx_rx = 0;
+
+	memset(buf, 0, 32);
+	memset(param1, 0, 32);
+	memset(param2, 0, 32);
+
+	if (count > sizeof(buf) - 1)
+		return -EINVAL;
+	if (copy_from_user(buf, ptr, len))
+		return -EFAULT;
+
+	ret = sscanf(buf, "%s %s", param1, param2);
+	if (ret < 0)
+		return ret;
+
+	if (!strncmp("help", param1, strlen("help"))) {
+		air_polarity_help();
+		return count;
+	}
+	if (!strncmp("tx_normal", param1, strlen("tx_normal"))) {
+		if (!strncmp("rx_normal", param2, strlen("rx_normal")))
+			tx_rx = AIR_POL_TX_NOR_RX_NOR;
+		else if (!strncmp("rx_reverse", param2, strlen("rx_reverse")))
+			tx_rx = AIR_POL_TX_NOR_RX_REV;
+		else {
+			pr_notice(AN8801_DEBUGFS_RX_ERROR_STRING);
+			return -EINVAL;
+		}
+	} else if (!strncmp("tx_reverse", param1, strlen("tx_reverse"))) {
+		if (!strncmp("rx_normal", param2, strlen("rx_normal")))
+			tx_rx = AIR_POL_TX_REV_RX_NOR;
+		else if (!strncmp("rx_reverse", param2, strlen("rx_reverse")))
+			tx_rx = AIR_POL_TX_REV_RX_REV;
+		else {
+			pr_notice(AN8801_DEBUGFS_RX_ERROR_STRING);
+			return -EINVAL;
+		}
+	} else {
+		pr_notice(AN8801_DEBUGFS_TX_ERROR_STRING);
+		return -EINVAL;
+	}
+	ret = an8801_set_polarity(phydev, tx_rx);
+	if (ret < 0)
+		return ret;
+	return count;
+}
+
+static int an8801_counter_show(struct seq_file *seq, void *v)
+{
+	struct phy_device *phydev = seq->private;
+	int ret = 0;
+	u32 pkt_cnt = 0;
+
+	seq_puts(seq, "==========AIR PHY COUNTER==========\n");
+	seq_puts(seq, "|\t<<FCM 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    :");
+	pkt_cnt = air_buckpbus_reg_read(phydev, 0x10270134);
+	seq_printf(seq, "%010u |\n", pkt_cnt);
+	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    :");
+	pkt_cnt = air_buckpbus_reg_read(phydev, 0x1027013C);
+	seq_printf(seq, "%010u |\n", pkt_cnt);
+	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  :");
+	pkt_cnt = air_buckpbus_reg_read(phydev, 0x10270124);
+	seq_printf(seq, "%010u |\n", pkt_cnt);
+	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      :");
+	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__);
+	else
+		seq_puts(seq, "\nClear Counter!!\n");
+
+	return ret;
+}
+
+static int an8801_counter_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, an8801_counter_show, inode->i_private);
+}
+
+static int an8801_debugfs_pbus_help(void)
+{
+	pr_notice(AN8801_DEBUGFS_PBUS_HELP_STRING);
+	return 0;
+}
+
+static ssize_t an8801_debugfs_pbus(struct file *file,
+		const char __user *buffer, size_t count,
+		loff_t *data)
+{
+	struct phy_device *phydev = file->private_data;
+	char buf[64];
+	int ret = 0;
+	unsigned int reg, addr;
+	unsigned long val;
+
+	memset(buf, 0, 64);
+
+	if (copy_from_user(buf, buffer, count))
+		return -EFAULT;
+
+	if (buf[0] == 'w') {
+		if (sscanf(buf, "w %x %x %lx", &addr, &reg, &val) == -1)
+			return -EFAULT;
+		if (addr > 0 && addr < 32) {
+			pr_notice("\nphy=0x%x, reg=0x%x, val=0x%lx\n",
+				addr, reg, val);
+
+			ret = air_buckpbus_reg_write(phydev, reg, val);
+			if (ret < 0)
+				return ret;
+			pr_notice("\nphy=%d, reg=0x%x, val=0x%lx confirm..\n",
+				addr, reg,
+				air_buckpbus_reg_read(phydev, reg));
+		} else {
+			pr_notice("addr is out of range(1~32)\n");
+		}
+	} else if (buf[0] == 'r') {
+		if (sscanf(buf, "r %x %x", &addr, &reg) == -1)
+			return -EFAULT;
+		if (addr > 0 && addr < 32) {
+			pr_notice("\nphy=0x%x, reg=0x%x, val=0x%lx\n",
+				addr, reg,
+				air_buckpbus_reg_read(phydev, reg));
+		} else {
+			pr_notice("addr is out of range(1~32)\n");
+		}
+	} else if (buf[0] == 'h') {
+		an8801_debugfs_pbus_help();
+	}
+
+	return count;
+}
+
+int an8801_info_show(struct seq_file *seq, void *v)
+{
+	struct phy_device *phydev = seq->private;
+	unsigned int tx_rx =
+		(air_buckpbus_reg_read(phydev, 0x1022a0f8) & 0x3);
+	unsigned long pbus_data = 0;
+
+	seq_puts(seq, "<<AIR AN8801 Driver Info>>\n");
+	pbus_data = air_buckpbus_reg_read(phydev, 0x1000009c);
+	seq_printf(seq, "| Product Version : E%ld\n", pbus_data & 0xf);
+	seq_printf(seq, "| Driver Version  : %s\n", AN8801_DRIVER_VERSION);
+	pbus_data = air_buckpbus_reg_read(phydev, 0x10220b04);
+	seq_printf(seq, "| Serdes Status   : Rx_Sync(%01ld), AN_Done(%01ld)\n",
+		GET_BIT(pbus_data, 4), GET_BIT(pbus_data, 0));
+	seq_printf(seq, "| Tx, Rx Polarity : %s(%02d)\n",
+		tx_rx_string[tx_rx], tx_rx);
+
+	seq_puts(seq, "\n");
+
+	return 0;
+}
+
+static int an8801_info_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, an8801_info_show, inode->i_private);
+}
+
+static const struct file_operations an8801_info_fops = {
+	.owner = THIS_MODULE,
+	.open = an8801_info_open,
+	.read = seq_read,
+	.llseek = noop_llseek,
+	.release = single_release,
+};
+
+static const struct file_operations an8801_counter_fops = {
+	.owner = THIS_MODULE,
+	.open = an8801_counter_open,
+	.read = seq_read,
+	.llseek = noop_llseek,
+	.release = single_release,
+};
+
+static const struct file_operations an8801_debugfs_pbus_fops = {
+	.owner = THIS_MODULE,
+	.open = simple_open,
+	.write = an8801_debugfs_pbus,
+	.llseek = noop_llseek,
+};
+
+static const struct file_operations an8801_polarity_fops = {
+	.owner = THIS_MODULE,
+	.open = simple_open,
+	.write = an8801_polarity_write,
+	.llseek = noop_llseek,
+};
+
+int an8801_debugfs_init(struct phy_device *phydev)
+{
+	int ret = 0;
+	struct an8801_priv *priv = phydev->priv;
+
+	phydev_info(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");
+		ret = -ENOMEM;
+	}
+	debugfs_create_file(DEBUGFS_DRIVER_INFO, 0444,
+					priv->debugfs_root, phydev,
+					&an8801_info_fops);
+	debugfs_create_file(DEBUGFS_COUNTER, 0644,
+					priv->debugfs_root, phydev,
+					&an8801_counter_fops);
+	debugfs_create_file(DEBUGFS_PBUS_OP, S_IFREG | 0200,
+					priv->debugfs_root, phydev,
+					&an8801_debugfs_pbus_fops);
+	debugfs_create_file(DEBUGFS_POLARITY, S_IFREG | 0200,
+					priv->debugfs_root, phydev,
+					&an8801_polarity_fops);
+	return ret;
+}
+
+static void air_debugfs_remove(struct phy_device *phydev)
+{
+	struct an8801_priv *priv = phydev->priv;
+
+	if (priv->debugfs_root != NULL) {
+		debugfs_remove_recursive(priv->debugfs_root);
+		priv->debugfs_root = NULL;
+	}
+}
+#endif /*AN8801SB_DEBUGFS*/
+
+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);
+
+	if (phy_id != AN8801_PHY_ID) {
+		phydev_err(phydev, "AN8801 can't be detected.\n");
+		return -1;
+	}
+
+	priv = devm_kzalloc(dev, sizeof(struct an8801_priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	for (led_id = AIR_LED0; led_id < MAX_LED_SIZE; led_id++)
+		priv->led_cfg[led_id] = led_cfg_dlt[led_id];
+
+	priv->led_blink_cfg  = led_blink_cfg_dlt;
+	priv->rxdelay_force  = rxdelay_force;
+	priv->txdelay_force  = txdelay_force;
+	priv->rxdelay_step   = rxdelay_step;
+	priv->rxdelay_align  = rxdelay_align;
+	priv->txdelay_step   = txdelay_step;
+
+	phydev->priv = priv;
+#ifdef AN8801SB_DEBUGFS
+	reg_value = air_buckpbus_reg_read(phydev, 0x10000094);
+	if (0 == (reg_value &
+		(AN8801_RG_PKG_SEL_LSB | AN8801_RG_PKG_SEL_MSB))) {
+		int ret = 0;
+
+		ret = an8801_debugfs_init(phydev);
+		if (ret < 0) {
+			air_debugfs_remove(phydev);
+			kfree(priv);
+			return ret;
+		}
+	} else {
+		phydev_info(phydev, "AN8801R not supprt debugfs\n");
+	}
+#endif
+	return 0;
+}
+
+static void an8801_phy_remove(struct phy_device *phydev)
+{
+	struct an8801_priv *priv = (struct an8801_priv *)phydev->priv;
+
+	if (priv) {
+#ifdef AN8801SB_DEBUGFS
+		air_debugfs_remove(phydev);
+#endif
+		kfree(priv);
+		phydev_info(phydev, "AN8801 remove OK!\n");
+	}
+}
+
+static int an8801sb_read_status(struct phy_device *phydev)
+{
+	int ret, prespeed = phydev->speed;
+	u32 reg_value = 0;
+	u32 an_retry = MAX_SGMII_AN_RETRY;
+
+	ret = genphy_read_status(phydev);
+	if (phydev->link == LINK_DOWN) {
+		prespeed = 0;
+		phydev->speed = 0;
+		ret |= an8801_cl45_write(
+			phydev, MMD_DEV_VSPEC2, PHY_PRE_SPEED_REG, prespeed);
+	}
+
+	if (prespeed != phydev->speed && phydev->link == LINK_UP) {
+		prespeed = phydev->speed;
+		ret |= an8801_cl45_write(
+			phydev, MMD_DEV_VSPEC2, PHY_PRE_SPEED_REG, prespeed);
+		phydev_info(phydev, "AN8801SB SPEED %d\n", prespeed);
+		air_buckpbus_reg_write(phydev, 0x10270108, 0x0a0a0404);
+		while (an_retry > 0) {
+			mdelay(1);       /* delay 1 ms */
+			reg_value = air_buckpbus_reg_read(
+				phydev, 0x10220b04);
+			if (reg_value & AN8801SB_SGMII_AN0_AN_DONE)
+				break;
+			an_retry--;
+		}
+		mdelay(10);        /* delay 10 ms */
+
+
+		if (phydev->autoneg == AUTONEG_DISABLE) {
+			phydev_info(phydev,
+				"AN8801SB force speed = %d\n", prespeed);
+			if (prespeed == SPEED_1000) {
+				air_buckpbus_reg_write(
+					phydev, 0x10220010, 0xd801);
+			} else if (prespeed == SPEED_100) {
+				air_buckpbus_reg_write(
+					phydev, 0x10220010, 0xd401);
+			} else {
+				air_buckpbus_reg_write(
+					phydev, 0x10220010, 0xd001);
+			}
+
+			reg_value = air_buckpbus_reg_read(
+				phydev, 0x10220000);
+			reg_value |= AN8801SB_SGMII_AN0_ANRESTART;
+			air_buckpbus_reg_write(
+				phydev, 0x10220000, reg_value);
+		}
+		reg_value = air_buckpbus_reg_read(phydev, 0x10220000);
+		reg_value |= AN8801SB_SGMII_AN0_RESET;
+		air_buckpbus_reg_write(phydev, 0x10220000, reg_value);
+	}
+	return ret;
+}
+
+static int an8801r_read_status(struct phy_device *phydev)
+{
+	int ret, prespeed = phydev->speed;
+	u32 data;
+
+	ret = genphy_read_status(phydev);
+	if (phydev->link == LINK_DOWN) {
+		prespeed = 0;
+		phydev->speed = 0;
+	}
+	if (prespeed != phydev->speed && phydev->link == LINK_UP) {
+		prespeed = phydev->speed;
+		phydev_dbg(phydev, "AN8801R SPEED %d\n", prespeed);
+		if (prespeed == SPEED_1000) {
+			data = air_buckpbus_reg_read(phydev, 0x10005054);
+			data |= BIT(0);
+			air_buckpbus_reg_write(phydev, 0x10005054, data);
+		} else {
+			data = air_buckpbus_reg_read(phydev, 0x10005054);
+			data &= ~BIT(0);
+			air_buckpbus_reg_write(phydev, 0x10005054, data);
+		}
+	}
+	return ret;
+}
+
+static int an8801_read_status(struct phy_device *phydev)
+{
+	if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
+		an8801sb_read_status(phydev);
+	} else if (phydev->interface == PHY_INTERFACE_MODE_RGMII) {
+		an8801r_read_status(phydev);
+	} else {
+		phydev_info(phydev, "AN8801 Phy-mode not support!\n");
+		return -1;
+	}
+	return 0;
+}
+
+static struct phy_driver airoha_driver[] = {
+	{
+		.phy_id         = AN8801_PHY_ID,
+		.name           = "Airoha AN8801",
+		.phy_id_mask    = 0x0ffffff0,
+		.features       = PHY_GBIT_FEATURES,
+		.config_init    = an8801_config_init,
+		.config_aneg    = genphy_config_aneg,
+		.probe          = an8801_phy_probe,
+		.remove         = an8801_phy_remove,
+		.read_status    = an8801_read_status,
+#if (KERNEL_VERSION(4, 5, 0) < LINUX_VERSION_CODE)
+		.read_mmd       = __an8801_cl45_read,
+		.write_mmd      = __an8801_cl45_write,
+#endif
+	}
+};
+
+module_phy_driver(airoha_driver);
+
+static struct mdio_device_id __maybe_unused airoha_tbl[] = {
+	{ AN8801_PHY_ID, 0x0ffffff0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(mdio, airoha_tbl);
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
new file mode 100644
index 0000000..e94c7c1
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/an8801.h
@@ -0,0 +1,214 @@
+// SPDX-License-Identifier: GPL-2.0
+/* FILE NAME:  an8801.h
+ * PURPOSE:
+ *      Define Airoha phy driver function
+ *
+ * NOTES:
+ *
+ */
+
+#ifndef __AN8801_H
+#define __AN8801_H
+
+/* NAMING DECLARATIONS
+ */
+#define AN8801_DRIVER_VERSION  "1.1.0"
+
+#define DEBUGFS_COUNTER         "counter"
+#define DEBUGFS_DRIVER_INFO     "driver_info"
+#define DEBUGFS_PBUS_OP         "pbus_op"
+#define DEBUGFS_POLARITY        "polarity"
+
+#define AN8801_MDIO_PHY_ID      0x1
+#define AN8801_PHY_ID1          0xc0ff
+#define AN8801_PHY_ID2          0x0421
+#define AN8801_PHY_ID      ((u32)((AN8801_PHY_ID1 << 16) | AN8801_PHY_ID2))
+
+#define TRUE                    1
+#define FALSE                   0
+#define LINK_UP                 1
+#define LINK_DOWN               0
+
+#define MAX_LED_SIZE            3
+
+#define MAX_RETRY               5
+
+#define AN8801_EPHY_ADDR            0x11000000
+#define AN8801_CL22                 0x00800000
+
+#define LED_ENABLE                  1
+#define LED_DISABLE                 0
+
+#define AN8801SB_DEBUGFS
+
+#ifndef BIT
+#define BIT(nr)                     (1 << (nr))
+#endif
+#ifndef GET_BIT
+#define GET_BIT(val, bit) ((val & BIT(bit)) >> bit)
+#endif
+
+#define LED_BCR                     (0x021)
+#define LED_BCR_EXT_CTRL            BIT(15)
+#define LED_BCR_EVT_ALL             BIT(4)
+#define LED_BCR_CLK_EN              BIT(3)
+#define LED_BCR_TIME_TEST           BIT(2)
+#define LED_BCR_MODE_MASK           (3)
+#define LED_BCR_MODE_DISABLE        (0)
+#define LED_BCR_MODE_2LED           (1)
+#define LED_BCR_MODE_3LED_1         (2)
+#define LED_BCR_MODE_3LED_2         (3)
+
+#define LED_ON_DUR                  (0x022)
+#define LED_ON_DUR_MASK             (0xffff)
+
+#define LED_BLK_DUR                 (0x023)
+#define LED_BLK_DUR_MASK            (0xffff)
+
+#define LED_ON_CTRL(i)              (0x024 + ((i) * 2))
+#define LED_ON_EN                   BIT(15)
+#define LED_ON_POL                  BIT(14)
+#define LED_ON_EVT_MASK             (0x7f)
+#define LED_ON_EVT_FORCE            BIT(6)
+#define LED_ON_EVT_HDX              BIT(5)
+#define LED_ON_EVT_FDX              BIT(4)
+#define LED_ON_EVT_LINK_DN          BIT(3)
+#define LED_ON_EVT_LINK_10M         BIT(2)
+#define LED_ON_EVT_LINK_100M        BIT(1)
+#define LED_ON_EVT_LINK_1000M       BIT(0)
+
+#define LED_BLK_CTRL(i)             (0x025 + ((i) * 2))
+#define LED_BLK_EVT_MASK            (0x3ff)
+#define LED_BLK_EVT_FORCE           BIT(9)
+#define LED_BLK_EVT_10M_RX          BIT(5)
+#define LED_BLK_EVT_10M_TX          BIT(4)
+#define LED_BLK_EVT_100M_RX         BIT(3)
+#define LED_BLK_EVT_100M_TX         BIT(2)
+#define LED_BLK_EVT_1000M_RX        BIT(1)
+#define LED_BLK_EVT_1000M_TX        BIT(0)
+
+#define UNIT_LED_BLINK_DURATION     1024
+
+/* Serdes auto negotation restart */
+#define AN8801SB_SGMII_AN0_ANRESTART    (0x0200)
+#define AN8801SB_SGMII_AN0_AN_DONE      (0x0001)
+#define AN8801SB_SGMII_AN0_RESET        (0x8000)
+
+
+#define PHY_PRE_SPEED_REG               (0x2b)
+
+#define MMD_DEV_VSPEC2          (0x1F)
+
+#define RGMII_DELAY_STEP_MASK       0x7
+#define RGMII_RXDELAY_ALIGN         BIT(4)
+#define RGMII_RXDELAY_FORCE_MODE    BIT(24)
+#define RGMII_TXDELAY_FORCE_MODE    BIT(24)
+#define AN8801_RG_PKG_SEL_LSB       BIT(4)
+#define AN8801_RG_PKG_SEL_MSB       BIT(5)
+
+/*
+For reference only
+*/
+/* User-defined.B */
+/* Link on(1G/100M/10M), no activity */
+#define AIR_LED0_ON \
+	(LED_ON_EVT_LINK_1000M | LED_ON_EVT_LINK_100M | LED_ON_EVT_LINK_10M)
+#define AIR_LED0_BLK     (0x0)
+/* No link on, activity(1G/100M/10M TX/RX) */
+#define AIR_LED1_ON      (0x0)
+#define AIR_LED1_BLK \
+	(LED_BLK_EVT_1000M_TX | LED_BLK_EVT_1000M_RX | \
+	LED_BLK_EVT_100M_TX | LED_BLK_EVT_100M_RX | \
+	LED_BLK_EVT_10M_TX | LED_BLK_EVT_10M_RX)
+/* Link on(100M/10M), activity(100M/10M TX/RX) */
+#define AIR_LED2_ON      (LED_ON_EVT_LINK_100M | LED_ON_EVT_LINK_10M)
+#define AIR_LED2_BLK \
+	(LED_BLK_EVT_100M_TX | LED_BLK_EVT_100M_RX | \
+	LED_BLK_EVT_10M_TX | LED_BLK_EVT_10M_RX)
+/* User-defined.E */
+
+/* Invalid data */
+#define INVALID_DATA            0xffffffff
+
+#define LED_BLINK_DURATION(f)       (UNIT_LED_BLINK_DURATION << (f))
+#define LED_GPIO_SEL(led, gpio)     ((led) << ((gpio) * 3))
+
+/* DATA TYPE DECLARATIONS
+ */
+enum AIR_LED_GPIO_PIN_T {
+	AIR_LED_GPIO1 = 1,
+	AIR_LED_GPIO2 = 2,
+	AIR_LED_GPIO3 = 3,
+	AIR_LED_GPIO5 = 5,
+	AIR_LED_GPIO8 = 8,
+	AIR_LED_GPIO9 = 9,
+};
+
+enum AIR_LED_T {
+	AIR_LED0 = 0,
+	AIR_LED1,
+	AIR_LED2,
+	AIR_LED3
+};
+
+enum AIR_LED_BLK_DUT_T {
+	AIR_LED_BLK_DUR_32M = 0,
+	AIR_LED_BLK_DUR_64M,
+	AIR_LED_BLK_DUR_128M,
+	AIR_LED_BLK_DUR_256M,
+	AIR_LED_BLK_DUR_512M,
+	AIR_LED_BLK_DUR_1024M,
+	AIR_LED_BLK_DUR_LAST
+};
+
+enum AIR_LED_POLARITY {
+	AIR_ACTIVE_LOW = 0,
+	AIR_ACTIVE_HIGH,
+};
+
+enum AIR_LED_MODE_T {
+	AIR_LED_MODE_DISABLE = 0,
+	AIR_LED_MODE_USER_DEFINE,
+	AIR_LED_MODE_LAST
+};
+
+enum AIR_RGMII_DELAY_STEP_T {
+	AIR_RGMII_DELAY_NOSTEP = 0,
+	AIR_RGMII_DELAY_STEP_1 = 1,
+	AIR_RGMII_DELAY_STEP_2 = 2,
+	AIR_RGMII_DELAY_STEP_3 = 3,
+	AIR_RGMII_DELAY_STEP_4 = 4,
+	AIR_RGMII_DELAY_STEP_5 = 5,
+	AIR_RGMII_DELAY_STEP_6 = 6,
+	AIR_RGMII_DELAY_STEP_7 = 7,
+};
+
+struct AIR_LED_CFG_T {
+	u16 en;
+	u16 gpio;
+	u16 pol;
+	u16 on_cfg;
+	u16 blk_cfg;
+};
+
+struct an8801_priv {
+	struct AIR_LED_CFG_T  led_cfg[MAX_LED_SIZE];
+	u32                   led_blink_cfg;
+	u8                    rxdelay_force;
+	u8                    txdelay_force;
+	u16                   rxdelay_step;
+	u8                    rxdelay_align;
+	u16                   txdelay_step;
+#ifdef AN8801SB_DEBUGFS
+	struct dentry        *debugfs_root;
+#endif
+};
+
+enum an8801_polarity {
+	AIR_POL_TX_NOR_RX_REV,
+	AIR_POL_TX_REV_RX_REV,
+	AIR_POL_TX_NOR_RX_NOR,
+	AIR_POL_TX_REV_RX_NOR,
+};
+
+#endif /* End of __AN8801_H */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/pwm/pwm-gpio.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/pwm/pwm-gpio.c
new file mode 100644
index 0000000..34b8e3c
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/pwm/pwm-gpio.c
@@ -0,0 +1,198 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (C) 2020 Axis Communications AB */
+
+#include <linux/gpio/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/hrtimer.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/pwm.h>
+#include <linux/err.h>
+#include <linux/of.h>
+
+struct pwm_gpio {
+	struct pwm_chip chip;
+	struct hrtimer hrtimer;
+	struct gpio_desc *gpio;
+	struct pwm_state state;
+	struct pwm_state nextstate;
+	spinlock_t lock;
+	bool changing;
+	bool running;
+	bool level;
+};
+
+static unsigned long pwm_gpio_toggle(struct pwm_gpio *gpwm, bool level)
+{
+	const struct pwm_state *state = &gpwm->state;
+	bool invert = state->polarity == PWM_POLARITY_INVERSED;
+
+	gpwm->level = level;
+	gpiod_set_value(gpwm->gpio, gpwm->level ^ invert);
+
+	if (!state->duty_cycle || state->duty_cycle == state->period) {
+		gpwm->running = false;
+		return 0;
+	}
+
+	gpwm->running = true;
+	return level ? state->duty_cycle : state->period - state->duty_cycle;
+}
+
+static enum hrtimer_restart pwm_gpio_timer(struct hrtimer *hrtimer)
+{
+	struct pwm_gpio *gpwm = container_of(hrtimer, struct pwm_gpio, hrtimer);
+	unsigned long nexttoggle;
+	unsigned long flags;
+	bool newlevel;
+
+	spin_lock_irqsave(&gpwm->lock, flags);
+
+	/* Apply new state at end of current period */
+	if (!gpwm->level && gpwm->changing) {
+		gpwm->changing = false;
+		gpwm->state = gpwm->nextstate;
+		newlevel = !!gpwm->state.duty_cycle;
+	} else {
+		newlevel = !gpwm->level;
+	}
+
+	nexttoggle = pwm_gpio_toggle(gpwm, newlevel);
+	if (nexttoggle)
+		hrtimer_forward(hrtimer, hrtimer_get_expires(hrtimer),
+				ns_to_ktime(nexttoggle));
+
+	spin_unlock_irqrestore(&gpwm->lock, flags);
+
+	return nexttoggle ? HRTIMER_RESTART : HRTIMER_NORESTART;
+}
+
+static int pwm_gpio_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+			  const struct pwm_state *state)
+{
+	struct pwm_gpio *gpwm = container_of(chip, struct pwm_gpio, chip);
+	unsigned long flags;
+
+	if (!state->enabled)
+		hrtimer_cancel(&gpwm->hrtimer);
+
+	spin_lock_irqsave(&gpwm->lock, flags);
+
+	if (!state->enabled) {
+		gpwm->state = *state;
+		gpwm->running = false;
+		gpwm->changing = false;
+
+		gpiod_set_value(gpwm->gpio, 0);
+	} else if (gpwm->running) {
+		gpwm->nextstate = *state;
+		gpwm->changing = true;
+	} else {
+		unsigned long nexttoggle;
+
+		gpwm->state = *state;
+		gpwm->changing = false;
+
+		nexttoggle = pwm_gpio_toggle(gpwm, !!state->duty_cycle);
+		if (nexttoggle)
+			hrtimer_start(&gpwm->hrtimer, nexttoggle,
+				      HRTIMER_MODE_REL);
+	}
+
+	spin_unlock_irqrestore(&gpwm->lock, flags);
+
+	return 0;
+}
+
+static void pwm_gpio_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
+			       struct pwm_state *state)
+{
+	struct pwm_gpio *gpwm = container_of(chip, struct pwm_gpio, chip);
+	unsigned long flags;
+
+	spin_lock_irqsave(&gpwm->lock, flags);
+
+	if (gpwm->changing)
+		*state = gpwm->nextstate;
+	else
+		*state = gpwm->state;
+
+	spin_unlock_irqrestore(&gpwm->lock, flags);
+}
+
+static const struct pwm_ops pwm_gpio_ops = {
+	.owner = THIS_MODULE,
+	.apply = pwm_gpio_apply,
+	.get_state = pwm_gpio_get_state,
+};
+
+static int pwm_gpio_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct pwm_gpio *gpwm;
+	int ret;
+
+	gpwm = devm_kzalloc(dev, sizeof(*gpwm), GFP_KERNEL);
+	if (!gpwm)
+		return -ENOMEM;
+
+	spin_lock_init(&gpwm->lock);
+
+	gpwm->gpio = devm_gpiod_get(dev, NULL, GPIOD_OUT_LOW);
+	if (IS_ERR(gpwm->gpio)) {
+		dev_err(dev, "could not get gpio\n");
+		return PTR_ERR(gpwm->gpio);
+	}
+
+	if (gpiod_cansleep(gpwm->gpio)) {
+		dev_err(dev, "sleeping GPIOs not supported\n");
+		return -EINVAL;
+	}
+
+	gpwm->chip.dev = dev;
+	gpwm->chip.ops = &pwm_gpio_ops;
+	gpwm->chip.base = pdev->id;
+	gpwm->chip.npwm = 1;
+
+	hrtimer_init(&gpwm->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	gpwm->hrtimer.function = pwm_gpio_timer;
+
+	ret = pwmchip_add(&gpwm->chip);
+	if (ret < 0) {
+		dev_err(dev, "could not add pwmchip\n");
+		return ret;
+	}
+
+	platform_set_drvdata(pdev, gpwm);
+
+	return 0;
+}
+
+static int pwm_gpio_remove(struct platform_device *pdev)
+{
+	struct pwm_gpio *gpwm = platform_get_drvdata(pdev);
+
+	pwm_disable(&gpwm->chip.pwms[0]);
+
+	return pwmchip_remove(&gpwm->chip);
+}
+
+static const struct of_device_id pwm_gpio_dt_ids[] = {
+	{ .compatible = "pwm-gpio" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, pwm_gpio_dt_ids);
+
+static struct platform_driver pwm_gpio_driver = {
+	.driver = {
+		.name = "pwm-gpio",
+		.of_match_table = pwm_gpio_dt_ids,
+	},
+	.probe = pwm_gpio_probe,
+	.remove = pwm_gpio_remove,
+};
+
+module_platform_driver(pwm_gpio_driver);
+
+MODULE_LICENSE("GPL v2");
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 a31bee9..1ba25be 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
@@ -45,8 +45,8 @@
  net/netfilter/nf_flow_table_core.c            |  462 ++++---
  net/netfilter/nf_flow_table_ip.c              |  447 +++---
  net/netfilter/nf_flow_table_offload.c         | 1199 +++++++++++++++++
- net/netfilter/xt_FLOWOFFLOAD.c                |  798 +++++++++++
- 41 files changed, 4993 insertions(+), 435 deletions(-)
+ net/netfilter/xt_FLOWOFFLOAD.c                |  800 +++++++++++
+ 41 files changed, 4995 insertions(+), 435 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
@@ -6089,7 +6089,7 @@
 index 0000000..2cab008
 --- /dev/null
 +++ b/net/netfilter/xt_FLOWOFFLOAD.c
-@@ -0,0 +1,798 @@
+@@ -0,0 +1,800 @@
 +/*
 + * Copyright (C) 2018-2021 Felix Fietkau <nbd@nbd.name>
 + *
@@ -6697,6 +6697,8 @@
 +
 +	if (skb->protocol == htons(ETH_P_IPV6))
 +		ct->inet6_mode = CT_INET_MODE_IPV6;
++	else
++		ct->inet6_mode = 0;
 +
 +	if (ct->status & IPS_NAT_MASK) {
 +		if (xt_flowoffload_route_nat(skb, ct, par, &route, dir, devs) < 0)
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 09502e9..16c04b5 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
@@ -152,13 +152,13 @@
  #if defined(CONFIG_NET_MEDIATEK_HNAT) || defined(CONFIG_NET_MEDIATEK_HNAT_MODULE)
  #include "mtk_hnat/nf_hnat_mtk.h"
 @@ -2191,6 +2193,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
- 		unsigned int pktlen, *rxdcsum;
  		struct net_device *netdev = NULL;
- 		dma_addr_t dma_addr = 0;
+ 		dma_addr_t dma_addr = DMA_MAPPING_ERROR;
+ 		u64 addr64 = 0;
 +		u32 hash, reason;
  		int mac = 0;
  
- 		if (eth->hwlro)
+ 		idx = NEXT_DESP_IDX(ring->calc_idx, ring->dma_size);
 @@ -2282,6 +2285,17 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
  			skb_checksum_none_assert(skb);
  		skb->protocol = eth_type_trans(skb, netdev);
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 407cea0..8d605e0 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,18 +1,18 @@
-From 9f734703a4a6870a34ea015ba27f01b986e80c4c Mon Sep 17 00:00:00 2001
+From 806bb7d1a0a44a92101c506564a41dc6c4b68fd0 Mon Sep 17 00:00:00 2001
 From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
-Date: Mon, 18 Sep 2023 10:59:56 +0800
+Date: Tue, 26 Dec 2023 16:31:34 +0800
 Subject: [PATCH 06/22] flow-offload-add-mkhnat-dual-ppe-new-v2
 
 ---
  arch/arm64/boot/dts/mediatek/mt7986a.dtsi     |  1 +
- drivers/net/ethernet/mediatek/mtk_eth_soc.c   | 67 ++++++++++++++-----
- drivers/net/ethernet/mediatek/mtk_eth_soc.h   | 14 +++-
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c   | 58 ++++++++++++++-----
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h   | 14 ++++-
  drivers/net/ethernet/mediatek/mtk_ppe.c       |  5 +-
- drivers/net/ethernet/mediatek/mtk_ppe.h       |  7 +-
- .../net/ethernet/mediatek/mtk_ppe_debugfs.c   | 27 ++++++--
- .../net/ethernet/mediatek/mtk_ppe_offload.c   | 48 ++++++++++---
+ drivers/net/ethernet/mediatek/mtk_ppe.h       |  7 ++-
+ .../net/ethernet/mediatek/mtk_ppe_debugfs.c   | 27 ++++++---
+ .../net/ethernet/mediatek/mtk_ppe_offload.c   | 48 +++++++++++----
  include/linux/netdevice.h                     |  4 ++
- 8 files changed, 131 insertions(+), 42 deletions(-)
+ 8 files changed, 124 insertions(+), 40 deletions(-)
  mode change 100644 => 100755 drivers/net/ethernet/mediatek/mtk_ppe_offload.c
 
 diff --git a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
@@ -31,37 +31,23 @@
 index bfda873..ee5e0c6 100644
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -2185,6 +2185,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;
-+	int i;
- 
- 	if (unlikely(!ring))
- 		goto rx_done;
-@@ -2297,14 +2298,20 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
+@@ -2276,14 +2276,16 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
  
  #if defined(CONFIG_MEDIATEK_NETSYS_RX_V2)
  		reason = FIELD_GET(MTK_RXD5_PPE_CPU_REASON_V2, trxd.rxd5);
 -		if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED)
 -			mtk_ppe_check_skb(eth->ppe, skb,
--					  trxd.rxd5 & MTK_RXD5_FOE_ENTRY_V2);
 +		if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED) {
-+			for (i = 0; i < eth->ppe_num; i++) {
-+				mtk_ppe_check_skb(eth->ppe[i], skb,
-+						  trxd.rxd5 & MTK_RXD5_FOE_ENTRY_V2);
-+			}
++			mtk_ppe_check_skb(eth->ppe[0], skb,
+ 					  trxd.rxd5 & MTK_RXD5_FOE_ENTRY_V2);
 +		}
  #else
  		reason = FIELD_GET(MTK_RXD4_PPE_CPU_REASON, trxd.rxd4);
 -		if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED)
 -			mtk_ppe_check_skb(eth->ppe, skb,
--					  trxd.rxd4 & MTK_RXD4_FOE_ENTRY);
 +		if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED) {
-+			for (i = 0; i < eth->ppe_num; i++) {
-+				mtk_ppe_check_skb(eth->ppe[i], skb,
-+						  trxd.rxd4 & MTK_RXD4_FOE_ENTRY);
-+			}
++			mtk_ppe_check_skb(eth->ppe[0], skb,
+ 					  trxd.rxd4 & MTK_RXD4_FOE_ENTRY);
 +		}
  #endif
  
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7986.cfg b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7986.cfg
index 20984c3..8626ee4 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7986.cfg
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7986.cfg
@@ -2,6 +2,7 @@
 CONFIG_AHCI_MTK=y
 CONFIG_AIROHA_EN8801SC_PHY=y
 # CONFIG_AIROHA_EN8811H_PHY is not set
+# CONFIG_AIROHA_AN8801_PHY is not set
 CONFIG_ARCH_CLOCKSOURCE_DATA=y
 CONFIG_ARCH_DMA_ADDR_T_64BIT=y
 CONFIG_ARCH_KEEP_MEMBLOCK=y
@@ -431,6 +432,7 @@
 CONFIG_PRINTK_TIME=y
 CONFIG_PWM=y
 CONFIG_PWM_MEDIATEK=y
+# CONFIG_PWM_GPIO is not set
 # CONFIG_PWM_MTK_DISP is not set
 CONFIG_PWM_SYSFS=y
 CONFIG_QUEUED_RWLOCKS=y
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 a36a0db..714ff5d 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7988.cfg
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7988.cfg
@@ -2,6 +2,7 @@
 CONFIG_AHCI_MTK=y
 # CONFIG_AIROHA_EN8801SC_PHY is not set
 # CONFIG_AIROHA_EN8811H_PHY is not set
+# CONFIG_AIROHA_AN8801_PHY is not set
 CONFIG_AQUANTIA_PHY=y
 CONFIG_AQUANTIA_PHY_FW_DOWNLOAD=y
 CONFIG_AQUANTIA_PHY_FW_DOWNLOAD_GANG=y
@@ -406,6 +407,7 @@
 # CONFIG_PSTORE_ZSTD_COMPRESS is not set
 CONFIG_PWM=y
 CONFIG_PWM_MEDIATEK=y
+# CONFIG_PWM_GPIO is not set
 # CONFIG_PWM_MTK_DISP is not set
 CONFIG_PWM_SYSFS=y
 CONFIG_QUEUED_RWLOCKS=y
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4102-mtk-crypto-offload-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4102-mtk-crypto-offload-support.patch
index 455ff04..e62c331 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4102-mtk-crypto-offload-support.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4102-mtk-crypto-offload-support.patch
@@ -1,25 +1,25 @@
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -1857,6 +1857,12 @@ static void mtk_tx_set_dma_desc_v3(struc
+@@ -1856,6 +1856,12 @@ static void mtk_tx_set_dma_desc_v3(struc
  
  	trace_printk("[%s] skb_shinfo(skb)->nr_frags=%x HNAT_SKB_CB2(skb)->magic=%x txd4=%x<-----\n",
  		     __func__, skb_shinfo(skb)->nr_frags, HNAT_SKB_CB2(skb)->magic, data);
 +
 +	/* forward to eip197 if this packet is going to encrypt */
-+	if (unlikely(skb_hnat_cdrt(skb) && is_magic_tag_valid(skb))) {
++	if (unlikely(skb->inner_protocol == IPPROTO_ESP && skb_hnat_cdrt(skb) && is_magic_tag_valid(skb))) {
 +		data &= ((~TX_DMA_TPORT_MASK) << TX_DMA_TPORT_SHIFT);
 +		data |= (EIP197_QDMA_TPORT & TX_DMA_TPORT_MASK) << TX_DMA_TPORT_SHIFT;
 +	}
  #endif
  	WRITE_ONCE(desc->txd4, data);
  
-@@ -1880,6 +1886,17 @@ static void mtk_tx_set_dma_desc_v3(struc
+@@ -1879,6 +1885,17 @@ static void mtk_tx_set_dma_desc_v3(struc
  
  	WRITE_ONCE(desc->txd7, 0);
  	WRITE_ONCE(desc->txd8, 0);
 +
 +#if defined(CONFIG_NET_MEDIATEK_HNAT) || defined(CONFIG_NET_MEDIATEK_HNAT_MODULE)
-+	if (unlikely(skb_hnat_cdrt(skb) && is_magic_tag_valid(skb))) {
++	if (unlikely(skb->inner_protocol == IPPROTO_ESP &&skb_hnat_cdrt(skb) && is_magic_tag_valid(skb))) {
 +		/* carry cdrt index for encryption */
 +		data = (skb_hnat_cdrt(skb) & TX_DMA_CDRT_MASK) << TX_DMA_CDRT_SHIFT;
 +		WRITE_ONCE(desc->txd8, data);
@@ -31,7 +31,7 @@
  }
  
  static void mtk_tx_set_dma_desc(struct sk_buff *skb, struct net_device *dev, void *txd,
-@@ -2307,6 +2324,7 @@ static int mtk_poll_rx(struct napi_struc
+@@ -2308,6 +2325,7 @@ static int mtk_poll_rx(struct napi_struc
  
  		skb_hnat_alg(skb) = 0;
  		skb_hnat_filled(skb) = 0;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1050-v6.4-backport-jitterrng-2.2.0.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1050-v6.4-backport-jitterrng-2.2.0.patch
index 3e85026..7161543 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1050-v6.4-backport-jitterrng-2.2.0.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1050-v6.4-backport-jitterrng-2.2.0.patch
@@ -141,12 +141,12 @@
 +			ret = -EAGAIN;
 +			break;
 +		}
-+		if (copy_to_user(buf+pos+total, out, ret)) {
++		if (copy_to_user(buf+pos+total, out, copy)) {
 +			ret = -EFAULT;
 +			break;
 +		}
-+		nbytes -= ret;
-+		total += ret;
++		nbytes -= copy;
++		total += copy;
 +	}
 +	kzfree(out);
 +
@@ -902,7 +902,7 @@
   * Entry function: Obtain entropy for the caller.
   *
   * This function invokes the entropy gathering logic as often to generate
-@@ -430,42 +521,64 @@ static void jent_fips_test(struct rand_data *ec)
+@@ -430,42 +521,62 @@ static void jent_fips_test(struct rand_data *ec)
   * This function truncates the last 64 bit entropy value output to the exact
   * size specified by the caller.
   *
@@ -928,7 +928,6 @@
  int jent_read_entropy(struct rand_data *ec, unsigned char *data,
  		      unsigned int len)
  {
-+	int ret = 0;
  	unsigned char *p = data;
  
  	if (!ec)
@@ -966,13 +965,11 @@
  			tocopy = len;
  		jent_memcpy(p, &ec->data, tocopy);
  
-+		ret = ret + tocopy;
  		len -= tocopy;
  		p += tocopy;
  	}
  
--	return 0;
-+	return ret;
+	return 0;
  }
  
  /***************************************************************************
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1600-mdiobus-add-c45.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1600-v5.18-mdiobus-add-c45.patch
similarity index 100%
rename from recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1600-mdiobus-add-c45.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1600-v5.18-mdiobus-add-c45.patch
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1703-mxl-gpy-phy-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1703-v5.18-mxl-gpy-phy-support.patch
similarity index 100%
rename from recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1703-mxl-gpy-phy-support.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1703-v5.18-mxl-gpy-phy-support.patch
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1704-net-phy-aquantia-add-AQR113C.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1704-v6.2-net-phy-aquantia-add-AQR113C.patch
similarity index 100%
rename from recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1704-net-phy-aquantia-add-AQR113C.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1704-v6.2-net-phy-aquantia-add-AQR113C.patch
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1708-net-phy-add-5GBASER.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1708-v6.2-net-phy-add-5GBASER.patch
similarity index 100%
rename from recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1708-net-phy-add-5GBASER.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1708-v6.2-net-phy-add-5GBASER.patch
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1709-net-phy-sfp-add-rollball-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1709-v6.2-net-phy-sfp-add-rollball-support.patch
similarity index 100%
rename from recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1709-net-phy-sfp-add-rollball-support.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1709-v6.2-net-phy-sfp-add-rollball-support.patch
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1710-net-phy-add-phylink-pcs-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1710-v6.2-net-phy-add-phylink-pcs-support.patch
similarity index 100%
rename from recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1710-net-phy-add-phylink-pcs-support.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1710-v6.2-net-phy-add-phylink-pcs-support.patch
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1711-net-phy-add-phylink-pcs-decode-helper.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1711-v6.2-net-phy-add-phylink-pcs-decode-helper.patch
similarity index 100%
rename from recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1711-net-phy-add-phylink-pcs-decode-helper.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1711-v6.2-net-phy-add-phylink-pcs-decode-helper.patch
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1712-net-phy-add-phylink-rate-matching-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1712-v6.2-net-phy-add-phylink-rate-matching-support.patch
similarity index 100%
rename from recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1712-net-phy-add-phylink-rate-matching-support.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1712-v6.2-net-phy-add-phylink-rate-matching-support.patch
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1750-v5.18-net-macsec-get-ready-to-backport-from-5-18.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1750-v5.18-net-macsec-get-ready-to-backport-from-5-18.patch
new file mode 100644
index 0000000..486e91c
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1750-v5.18-net-macsec-get-ready-to-backport-from-5-18.patch
@@ -0,0 +1,19 @@
+--- a/drivers/net/macsec.c
++++ b/drivers/net/macsec.c
+@@ -16,7 +16,6 @@
+ #include <net/genetlink.h>
+ #include <net/sock.h>
+ #include <net/gro_cells.h>
+-#include <linux/if_arp.h>
+ 
+ #include <uapi/linux/if_macsec.h>
+ 
+@@ -3240,8 +3239,6 @@ static int macsec_newlink(struct net *ne
+ 	real_dev = __dev_get_by_index(net, nla_get_u32(tb[IFLA_LINK]));
+ 	if (!real_dev)
+ 		return -ENODEV;
+-	if (real_dev->type != ARPHRD_ETHER)
+-		return -EINVAL;
+ 
+ 	dev->priv_flags |= IFF_MACSEC;
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1751-01-v5.18-net-macsec-move-some-definitions-in-a-dedicated-header.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1751-01-v5.18-net-macsec-move-some-definitions-in-a-dedicated-header.patch
new file mode 100644
index 0000000..204d821
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1751-01-v5.18-net-macsec-move-some-definitions-in-a-dedicated-header.patch
@@ -0,0 +1,406 @@
+From c0e4eadfb8daf2e9557c7450f9b237c08b404419 Mon Sep 17 00:00:00 2001
+From: Antoine Tenart <antoine.tenart@bootlin.com>
+Date: Mon, 13 Jan 2020 23:31:39 +0100
+Subject: net: macsec: move some definitions in a dedicated header
+
+This patch moves some structure, type and identifier definitions into a
+MACsec specific header. This patch does not modify how the MACsec code
+is running and only move things around. This is a preparation for the
+future MACsec hardware offloading support, which will re-use those
+definitions outside macsec.c.
+
+Signed-off-by: Antoine Tenart <antoine.tenart@bootlin.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/macsec.c | 164 +----------------------------------------------
+ include/net/macsec.h | 177 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 178 insertions(+), 163 deletions(-)
+ create mode 100644 include/net/macsec.h
+
+diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
+index afd8b2a082454..a336eee018f0b 100644
+--- a/drivers/net/macsec.c
++++ b/drivers/net/macsec.c
+@@ -16,11 +16,10 @@
+ #include <net/genetlink.h>
+ #include <net/sock.h>
+ #include <net/gro_cells.h>
++#include <net/macsec.h>
+ 
+ #include <uapi/linux/if_macsec.h>
+ 
+-typedef u64 __bitwise sci_t;
+-
+ #define MACSEC_SCI_LEN 8
+ 
+ /* SecTAG length = macsec_eth_header without the optional SCI */
+@@ -58,8 +57,6 @@ struct macsec_eth_header {
+ #define GCM_AES_IV_LEN 12
+ #define DEFAULT_ICV_LEN 16
+ 
+-#define MACSEC_NUM_AN 4 /* 2 bits for the association number */
+-
+ #define for_each_rxsc(secy, sc)				\
+ 	for (sc = rcu_dereference_bh(secy->rx_sc);	\
+ 	     sc;					\
+@@ -77,49 +74,6 @@ struct gcm_iv {
+ 	__be32 pn;
+ };
+ 
+-/**
+- * struct macsec_key - SA key
+- * @id: user-provided key identifier
+- * @tfm: crypto struct, key storage
+- */
+-struct macsec_key {
+-	u8 id[MACSEC_KEYID_LEN];
+-	struct crypto_aead *tfm;
+-};
+-
+-struct macsec_rx_sc_stats {
+-	__u64 InOctetsValidated;
+-	__u64 InOctetsDecrypted;
+-	__u64 InPktsUnchecked;
+-	__u64 InPktsDelayed;
+-	__u64 InPktsOK;
+-	__u64 InPktsInvalid;
+-	__u64 InPktsLate;
+-	__u64 InPktsNotValid;
+-	__u64 InPktsNotUsingSA;
+-	__u64 InPktsUnusedSA;
+-};
+-
+-struct macsec_rx_sa_stats {
+-	__u32 InPktsOK;
+-	__u32 InPktsInvalid;
+-	__u32 InPktsNotValid;
+-	__u32 InPktsNotUsingSA;
+-	__u32 InPktsUnusedSA;
+-};
+-
+-struct macsec_tx_sa_stats {
+-	__u32 OutPktsProtected;
+-	__u32 OutPktsEncrypted;
+-};
+-
+-struct macsec_tx_sc_stats {
+-	__u64 OutPktsProtected;
+-	__u64 OutPktsEncrypted;
+-	__u64 OutOctetsProtected;
+-	__u64 OutOctetsEncrypted;
+-};
+-
+ struct macsec_dev_stats {
+ 	__u64 OutPktsUntagged;
+ 	__u64 InPktsUntagged;
+@@ -131,124 +85,8 @@ struct macsec_dev_stats {
+ 	__u64 InPktsOverrun;
+ };
+ 
+-/**
+- * struct macsec_rx_sa - receive secure association
+- * @active:
+- * @next_pn: packet number expected for the next packet
+- * @lock: protects next_pn manipulations
+- * @key: key structure
+- * @stats: per-SA stats
+- */
+-struct macsec_rx_sa {
+-	struct macsec_key key;
+-	spinlock_t lock;
+-	u32 next_pn;
+-	refcount_t refcnt;
+-	bool active;
+-	struct macsec_rx_sa_stats __percpu *stats;
+-	struct macsec_rx_sc *sc;
+-	struct rcu_head rcu;
+-};
+-
+-struct pcpu_rx_sc_stats {
+-	struct macsec_rx_sc_stats stats;
+-	struct u64_stats_sync syncp;
+-};
+-
+-/**
+- * struct macsec_rx_sc - receive secure channel
+- * @sci: secure channel identifier for this SC
+- * @active: channel is active
+- * @sa: array of secure associations
+- * @stats: per-SC stats
+- */
+-struct macsec_rx_sc {
+-	struct macsec_rx_sc __rcu *next;
+-	sci_t sci;
+-	bool active;
+-	struct macsec_rx_sa __rcu *sa[MACSEC_NUM_AN];
+-	struct pcpu_rx_sc_stats __percpu *stats;
+-	refcount_t refcnt;
+-	struct rcu_head rcu_head;
+-};
+-
+-/**
+- * struct macsec_tx_sa - transmit secure association
+- * @active:
+- * @next_pn: packet number to use for the next packet
+- * @lock: protects next_pn manipulations
+- * @key: key structure
+- * @stats: per-SA stats
+- */
+-struct macsec_tx_sa {
+-	struct macsec_key key;
+-	spinlock_t lock;
+-	u32 next_pn;
+-	refcount_t refcnt;
+-	bool active;
+-	struct macsec_tx_sa_stats __percpu *stats;
+-	struct rcu_head rcu;
+-};
+-
+-struct pcpu_tx_sc_stats {
+-	struct macsec_tx_sc_stats stats;
+-	struct u64_stats_sync syncp;
+-};
+-
+-/**
+- * struct macsec_tx_sc - transmit secure channel
+- * @active:
+- * @encoding_sa: association number of the SA currently in use
+- * @encrypt: encrypt packets on transmit, or authenticate only
+- * @send_sci: always include the SCI in the SecTAG
+- * @end_station:
+- * @scb: single copy broadcast flag
+- * @sa: array of secure associations
+- * @stats: stats for this TXSC
+- */
+-struct macsec_tx_sc {
+-	bool active;
+-	u8 encoding_sa;
+-	bool encrypt;
+-	bool send_sci;
+-	bool end_station;
+-	bool scb;
+-	struct macsec_tx_sa __rcu *sa[MACSEC_NUM_AN];
+-	struct pcpu_tx_sc_stats __percpu *stats;
+-};
+-
+ #define MACSEC_VALIDATE_DEFAULT MACSEC_VALIDATE_STRICT
+ 
+-/**
+- * struct macsec_secy - MACsec Security Entity
+- * @netdev: netdevice for this SecY
+- * @n_rx_sc: number of receive secure channels configured on this SecY
+- * @sci: secure channel identifier used for tx
+- * @key_len: length of keys used by the cipher suite
+- * @icv_len: length of ICV used by the cipher suite
+- * @validate_frames: validation mode
+- * @operational: MAC_Operational flag
+- * @protect_frames: enable protection for this SecY
+- * @replay_protect: enable packet number checks on receive
+- * @replay_window: size of the replay window
+- * @tx_sc: transmit secure channel
+- * @rx_sc: linked list of receive secure channels
+- */
+-struct macsec_secy {
+-	struct net_device *netdev;
+-	unsigned int n_rx_sc;
+-	sci_t sci;
+-	u16 key_len;
+-	u16 icv_len;
+-	enum macsec_validation_type validate_frames;
+-	bool operational;
+-	bool protect_frames;
+-	bool replay_protect;
+-	u32 replay_window;
+-	struct macsec_tx_sc tx_sc;
+-	struct macsec_rx_sc __rcu *rx_sc;
+-};
+-
+ struct pcpu_secy_stats {
+ 	struct macsec_dev_stats stats;
+ 	struct u64_stats_sync syncp;
+diff --git a/include/net/macsec.h b/include/net/macsec.h
+new file mode 100644
+index 0000000000000..e7b41c1043f6f
+--- /dev/null
++++ b/include/net/macsec.h
+@@ -0,0 +1,177 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
++/*
++ * MACsec netdev header, used for h/w accelerated implementations.
++ *
++ * Copyright (c) 2015 Sabrina Dubroca <sd@queasysnail.net>
++ */
++#ifndef _NET_MACSEC_H_
++#define _NET_MACSEC_H_
++
++#include <linux/u64_stats_sync.h>
++#include <uapi/linux/if_link.h>
++#include <uapi/linux/if_macsec.h>
++
++typedef u64 __bitwise sci_t;
++
++#define MACSEC_NUM_AN 4 /* 2 bits for the association number */
++
++/**
++ * struct macsec_key - SA key
++ * @id: user-provided key identifier
++ * @tfm: crypto struct, key storage
++ */
++struct macsec_key {
++	u8 id[MACSEC_KEYID_LEN];
++	struct crypto_aead *tfm;
++};
++
++struct macsec_rx_sc_stats {
++	__u64 InOctetsValidated;
++	__u64 InOctetsDecrypted;
++	__u64 InPktsUnchecked;
++	__u64 InPktsDelayed;
++	__u64 InPktsOK;
++	__u64 InPktsInvalid;
++	__u64 InPktsLate;
++	__u64 InPktsNotValid;
++	__u64 InPktsNotUsingSA;
++	__u64 InPktsUnusedSA;
++};
++
++struct macsec_rx_sa_stats {
++	__u32 InPktsOK;
++	__u32 InPktsInvalid;
++	__u32 InPktsNotValid;
++	__u32 InPktsNotUsingSA;
++	__u32 InPktsUnusedSA;
++};
++
++struct macsec_tx_sa_stats {
++	__u32 OutPktsProtected;
++	__u32 OutPktsEncrypted;
++};
++
++struct macsec_tx_sc_stats {
++	__u64 OutPktsProtected;
++	__u64 OutPktsEncrypted;
++	__u64 OutOctetsProtected;
++	__u64 OutOctetsEncrypted;
++};
++
++/**
++ * struct macsec_rx_sa - receive secure association
++ * @active:
++ * @next_pn: packet number expected for the next packet
++ * @lock: protects next_pn manipulations
++ * @key: key structure
++ * @stats: per-SA stats
++ */
++struct macsec_rx_sa {
++	struct macsec_key key;
++	spinlock_t lock;
++	u32 next_pn;
++	refcount_t refcnt;
++	bool active;
++	struct macsec_rx_sa_stats __percpu *stats;
++	struct macsec_rx_sc *sc;
++	struct rcu_head rcu;
++};
++
++struct pcpu_rx_sc_stats {
++	struct macsec_rx_sc_stats stats;
++	struct u64_stats_sync syncp;
++};
++
++struct pcpu_tx_sc_stats {
++	struct macsec_tx_sc_stats stats;
++	struct u64_stats_sync syncp;
++};
++
++/**
++ * struct macsec_rx_sc - receive secure channel
++ * @sci: secure channel identifier for this SC
++ * @active: channel is active
++ * @sa: array of secure associations
++ * @stats: per-SC stats
++ */
++struct macsec_rx_sc {
++	struct macsec_rx_sc __rcu *next;
++	sci_t sci;
++	bool active;
++	struct macsec_rx_sa __rcu *sa[MACSEC_NUM_AN];
++	struct pcpu_rx_sc_stats __percpu *stats;
++	refcount_t refcnt;
++	struct rcu_head rcu_head;
++};
++
++/**
++ * struct macsec_tx_sa - transmit secure association
++ * @active:
++ * @next_pn: packet number to use for the next packet
++ * @lock: protects next_pn manipulations
++ * @key: key structure
++ * @stats: per-SA stats
++ */
++struct macsec_tx_sa {
++	struct macsec_key key;
++	spinlock_t lock;
++	u32 next_pn;
++	refcount_t refcnt;
++	bool active;
++	struct macsec_tx_sa_stats __percpu *stats;
++	struct rcu_head rcu;
++};
++
++/**
++ * struct macsec_tx_sc - transmit secure channel
++ * @active:
++ * @encoding_sa: association number of the SA currently in use
++ * @encrypt: encrypt packets on transmit, or authenticate only
++ * @send_sci: always include the SCI in the SecTAG
++ * @end_station:
++ * @scb: single copy broadcast flag
++ * @sa: array of secure associations
++ * @stats: stats for this TXSC
++ */
++struct macsec_tx_sc {
++	bool active;
++	u8 encoding_sa;
++	bool encrypt;
++	bool send_sci;
++	bool end_station;
++	bool scb;
++	struct macsec_tx_sa __rcu *sa[MACSEC_NUM_AN];
++	struct pcpu_tx_sc_stats __percpu *stats;
++};
++
++/**
++ * struct macsec_secy - MACsec Security Entity
++ * @netdev: netdevice for this SecY
++ * @n_rx_sc: number of receive secure channels configured on this SecY
++ * @sci: secure channel identifier used for tx
++ * @key_len: length of keys used by the cipher suite
++ * @icv_len: length of ICV used by the cipher suite
++ * @validate_frames: validation mode
++ * @operational: MAC_Operational flag
++ * @protect_frames: enable protection for this SecY
++ * @replay_protect: enable packet number checks on receive
++ * @replay_window: size of the replay window
++ * @tx_sc: transmit secure channel
++ * @rx_sc: linked list of receive secure channels
++ */
++struct macsec_secy {
++	struct net_device *netdev;
++	unsigned int n_rx_sc;
++	sci_t sci;
++	u16 key_len;
++	u16 icv_len;
++	enum macsec_validation_type validate_frames;
++	bool operational;
++	bool protect_frames;
++	bool replay_protect;
++	u32 replay_window;
++	struct macsec_tx_sc tx_sc;
++	struct macsec_rx_sc __rcu *rx_sc;
++};
++
++#endif /* _NET_MACSEC_H_ */
+-- 
+cgit 1.2.3-1.el7
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1752-02-v5.18-net-macsec-introduce-the-macsec_context-structure.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1752-02-v5.18-net-macsec-introduce-the-macsec_context-structure.patch
new file mode 100644
index 0000000..40c1149
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1752-02-v5.18-net-macsec-introduce-the-macsec_context-structure.patch
@@ -0,0 +1,103 @@
+From 76564261a7db80c5f5c624e0122a28787f266bdf Mon Sep 17 00:00:00 2001
+From: Antoine Tenart <antoine.tenart@bootlin.com>
+Date: Mon, 13 Jan 2020 23:31:40 +0100
+Subject: net: macsec: introduce the macsec_context structure
+
+This patch introduces the macsec_context structure. It will be used
+in the kernel to exchange information between the common MACsec
+implementation (macsec.c) and the MACsec hardware offloading
+implementations. This structure contains pointers to MACsec specific
+structures which contain the actual MACsec configuration, and to the
+underlying device (phydev for now).
+
+Signed-off-by: Antoine Tenart <antoine.tenart@bootlin.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ include/linux/phy.h                |  2 ++
+ include/net/macsec.h               | 21 +++++++++++++++++++++
+ include/uapi/linux/if_link.h       |  7 +++++++
+ tools/include/uapi/linux/if_link.h |  7 +++++++
+ 4 files changed, 37 insertions(+)
+
+diff --git a/include/linux/phy.h b/include/linux/phy.h
+index 3a70b756ac1aa..be079a7bb40aa 100644
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -332,6 +332,8 @@ struct phy_c45_device_ids {
+ 	u32 device_ids[8];
+ };
+ 
++struct macsec_context;
++
+ /* phy_device: An instance of a PHY
+  *
+  * drv: Pointer to the driver for this PHY instance
+diff --git a/include/net/macsec.h b/include/net/macsec.h
+index e7b41c1043f6f..0b98803f92ec1 100644
+--- a/include/net/macsec.h
++++ b/include/net/macsec.h
+@@ -174,4 +174,25 @@ struct macsec_secy {
+ 	struct macsec_rx_sc __rcu *rx_sc;
+ };
+ 
++/**
++ * struct macsec_context - MACsec context for hardware offloading
++ */
++struct macsec_context {
++	struct phy_device *phydev;
++	enum macsec_offload offload;
++
++	struct macsec_secy *secy;
++	struct macsec_rx_sc *rx_sc;
++	struct {
++		unsigned char assoc_num;
++		u8 key[MACSEC_KEYID_LEN];
++		union {
++			struct macsec_rx_sa *rx_sa;
++			struct macsec_tx_sa *tx_sa;
++		};
++	} sa;
++
++	u8 prepare:1;
++};
++
+ #endif /* _NET_MACSEC_H_ */
+diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
+index 1d69f637c5d6a..024af2d1d0af4 100644
+--- a/include/uapi/linux/if_link.h
++++ b/include/uapi/linux/if_link.h
+@@ -486,6 +486,13 @@ enum macsec_validation_type {
+ 	MACSEC_VALIDATE_MAX = __MACSEC_VALIDATE_END - 1,
+ };
+ 
++enum macsec_offload {
++	MACSEC_OFFLOAD_OFF = 0,
++	MACSEC_OFFLOAD_PHY = 1,
++	__MACSEC_OFFLOAD_END,
++	MACSEC_OFFLOAD_MAX = __MACSEC_OFFLOAD_END - 1,
++};
++
+ /* IPVLAN section */
+ enum {
+ 	IFLA_IPVLAN_UNSPEC,
+diff --git a/tools/include/uapi/linux/if_link.h b/tools/include/uapi/linux/if_link.h
+index 8aec8769d9442..42efdb84d1898 100644
+--- a/tools/include/uapi/linux/if_link.h
++++ b/tools/include/uapi/linux/if_link.h
+@@ -485,6 +485,13 @@ enum macsec_validation_type {
+ 	MACSEC_VALIDATE_MAX = __MACSEC_VALIDATE_END - 1,
+ };
+ 
++enum macsec_offload {
++	MACSEC_OFFLOAD_OFF = 0,
++	MACSEC_OFFLOAD_PHY = 1,
++	__MACSEC_OFFLOAD_END,
++	MACSEC_OFFLOAD_MAX = __MACSEC_OFFLOAD_END - 1,
++};
++
+ /* IPVLAN section */
+ enum {
+ 	IFLA_IPVLAN_UNSPEC,
+-- 
+cgit 1.2.3-1.el7
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1753-03-v5.18-net-macsec-introduce-MACsec-ops.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1753-03-v5.18-net-macsec-introduce-MACsec-ops.patch
new file mode 100644
index 0000000..1681b74
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1753-03-v5.18-net-macsec-introduce-MACsec-ops.patch
@@ -0,0 +1,50 @@
+From 0830e20b62ad156f7df5ff5b9c4cea280ebe8fef Mon Sep 17 00:00:00 2001
+From: Antoine Tenart <antoine.tenart@bootlin.com>
+Date: Mon, 13 Jan 2020 23:31:41 +0100
+Subject: net: macsec: introduce MACsec ops
+
+This patch introduces MACsec ops for drivers to support offloading
+MACsec operations.
+
+Signed-off-by: Antoine Tenart <antoine.tenart@bootlin.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ include/net/macsec.h | 24 ++++++++++++++++++++++++
+ 1 file changed, 24 insertions(+)
+
+diff --git a/include/net/macsec.h b/include/net/macsec.h
+index 0b98803f92ec1..16e7e5061178e 100644
+--- a/include/net/macsec.h
++++ b/include/net/macsec.h
+@@ -195,4 +195,28 @@ struct macsec_context {
+ 	u8 prepare:1;
+ };
+ 
++/**
++ * struct macsec_ops - MACsec offloading operations
++ */
++struct macsec_ops {
++	/* Device wide */
++	int (*mdo_dev_open)(struct macsec_context *ctx);
++	int (*mdo_dev_stop)(struct macsec_context *ctx);
++	/* SecY */
++	int (*mdo_add_secy)(struct macsec_context *ctx);
++	int (*mdo_upd_secy)(struct macsec_context *ctx);
++	int (*mdo_del_secy)(struct macsec_context *ctx);
++	/* Security channels */
++	int (*mdo_add_rxsc)(struct macsec_context *ctx);
++	int (*mdo_upd_rxsc)(struct macsec_context *ctx);
++	int (*mdo_del_rxsc)(struct macsec_context *ctx);
++	/* Security associations */
++	int (*mdo_add_rxsa)(struct macsec_context *ctx);
++	int (*mdo_upd_rxsa)(struct macsec_context *ctx);
++	int (*mdo_del_rxsa)(struct macsec_context *ctx);
++	int (*mdo_add_txsa)(struct macsec_context *ctx);
++	int (*mdo_upd_txsa)(struct macsec_context *ctx);
++	int (*mdo_del_txsa)(struct macsec_context *ctx);
++};
++
+ #endif /* _NET_MACSEC_H_ */
+-- 
+cgit 1.2.3-1.el7
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1754-04-v5.18-net-phy-add-MACsec-ops-in-phy_device.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1754-04-v5.18-net-phy-add-MACsec-ops-in-phy_device.patch
new file mode 100644
index 0000000..dff64b3
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1754-04-v5.18-net-phy-add-MACsec-ops-in-phy_device.patch
@@ -0,0 +1,50 @@
+From 2e18135845b359f26c37df38ba56565496517c10 Mon Sep 17 00:00:00 2001
+From: Antoine Tenart <antoine.tenart@bootlin.com>
+Date: Mon, 13 Jan 2020 23:31:42 +0100
+Subject: net: phy: add MACsec ops in phy_device
+
+This patch adds a reference to MACsec ops in the phy_device, to allow
+PHYs to support offloading MACsec operations. The phydev lock will be
+held while calling those helpers.
+
+Signed-off-by: Antoine Tenart <antoine.tenart@bootlin.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ include/linux/phy.h | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/include/linux/phy.h b/include/linux/phy.h
+index be079a7bb40aa..2929d0bc307fe 100644
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -333,6 +333,7 @@ struct phy_c45_device_ids {
+ };
+ 
+ struct macsec_context;
++struct macsec_ops;
+ 
+ /* phy_device: An instance of a PHY
+  *
+@@ -356,6 +357,7 @@ struct macsec_context;
+  * attached_dev: The attached enet driver's device instance ptr
+  * adjust_link: Callback for the enet controller to respond to
+  * changes in the link state.
++ * macsec_ops: MACsec offloading ops.
+  *
+  * speed, duplex, pause, supported, advertising, lp_advertising,
+  * and autoneg are used like in mii_if_info
+@@ -455,6 +457,11 @@ struct phy_device {
+ 
+ 	void (*phy_link_change)(struct phy_device *, bool up, bool do_carrier);
+ 	void (*adjust_link)(struct net_device *dev);
++
++#if IS_ENABLED(CONFIG_MACSEC)
++	/* MACsec management functions */
++	const struct macsec_ops *macsec_ops;
++#endif
+ };
+ #define to_phy_device(d) container_of(to_mdio_device(d), \
+ 				      struct phy_device, mdio)
+-- 
+cgit 1.2.3-1.el7
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1755-05-v5.18-net-macsec-hardware-offloading-infrastructure.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1755-05-v5.18-net-macsec-hardware-offloading-infrastructure.patch
new file mode 100644
index 0000000..1404301
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1755-05-v5.18-net-macsec-hardware-offloading-infrastructure.patch
@@ -0,0 +1,825 @@
+From 3cf3227a21d1fb020fe26128e60321bd2151e922 Mon Sep 17 00:00:00 2001
+From: Antoine Tenart <antoine.tenart@bootlin.com>
+Date: Mon, 13 Jan 2020 23:31:43 +0100
+Subject: net: macsec: hardware offloading infrastructure
+
+This patch introduces the MACsec hardware offloading infrastructure.
+
+The main idea here is to re-use the logic and data structures of the
+software MACsec implementation. This allows not to duplicate definitions
+and structure storing the same kind of information. It also allows to
+use a unified genlink interface for both MACsec implementations (so that
+the same userspace tool, `ip macsec`, is used with the same arguments).
+The MACsec offloading support cannot be disabled if an interface
+supports it at the moment.
+
+The MACsec configuration is passed to device drivers supporting it
+through macsec_ops which are called from the MACsec genl helpers. Those
+functions call the macsec ops of PHY and Ethernet drivers in two steps:
+a preparation one, and a commit one. The first step is allowed to fail
+and should be used to check if a provided configuration is compatible
+with the features provided by a MACsec engine, while the second step is
+not allowed to fail and should only be used to enable a given MACsec
+configuration. Two extra calls are made: when a virtual MACsec interface
+is created and when it is deleted, so that the hardware driver can stay
+in sync.
+
+The Rx and TX handlers are modified to take in account the special case
+were the MACsec transformation happens in the hardware, whether in a PHY
+or in a MAC, as the packets seen by the networking stack on both the
+physical and MACsec virtual interface are exactly the same. This leads
+to some limitations: the hardware and software implementations can't be
+used on the same physical interface, as the policies would be impossible
+to fulfill (such as strict validation of the frames). Also only a single
+virtual MACsec interface can be offloaded to a physical port supporting
+hardware offloading as it would be impossible to guess onto which
+interface a given packet should go (for ingress traffic).
+
+Another limitation as of now is that the counters and statistics are not
+reported back from the hardware to the software MACsec implementation.
+This isn't an issue when using offloaded MACsec transformations, but it
+should be added in the future so that the MACsec state can be reported
+to the user (which would also improve the debug).
+
+Signed-off-by: Antoine Tenart <antoine.tenart@bootlin.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/macsec.c | 453 +++++++++++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 441 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
+index a336eee018f0b..36b0416381bf1 100644
+--- a/drivers/net/macsec.c
++++ b/drivers/net/macsec.c
+@@ -11,12 +11,14 @@
+ #include <linux/module.h>
+ #include <crypto/aead.h>
+ #include <linux/etherdevice.h>
++#include <linux/netdevice.h>
+ #include <linux/rtnetlink.h>
+ #include <linux/refcount.h>
+ #include <net/genetlink.h>
+ #include <net/sock.h>
+ #include <net/gro_cells.h>
+ #include <net/macsec.h>
++#include <linux/phy.h>
+ 
+ #include <uapi/linux/if_macsec.h>
+ 
+@@ -98,6 +100,7 @@ struct pcpu_secy_stats {
+  * @real_dev: pointer to underlying netdevice
+  * @stats: MACsec device stats
+  * @secys: linked list of SecY's on the underlying device
++ * @offload: status of offloading on the MACsec device
+  */
+ struct macsec_dev {
+ 	struct macsec_secy secy;
+@@ -105,6 +108,7 @@ struct macsec_dev {
+ 	struct pcpu_secy_stats __percpu *stats;
+ 	struct list_head secys;
+ 	struct gro_cells gro_cells;
++	enum macsec_offload offload;
+ };
+ 
+ /**
+@@ -318,6 +322,56 @@ static void macsec_set_shortlen(struct macsec_eth_header *h, size_t data_len)
+ 		h->short_length = data_len;
+ }
+ 
++/* Checks if a MACsec interface is being offloaded to an hardware engine */
++static bool macsec_is_offloaded(struct macsec_dev *macsec)
++{
++	if (macsec->offload == MACSEC_OFFLOAD_PHY)
++		return true;
++
++	return false;
++}
++
++/* Checks if underlying layers implement MACsec offloading functions. */
++static bool macsec_check_offload(enum macsec_offload offload,
++				 struct macsec_dev *macsec)
++{
++	if (!macsec || !macsec->real_dev)
++		return false;
++
++	if (offload == MACSEC_OFFLOAD_PHY)
++		return macsec->real_dev->phydev &&
++		       macsec->real_dev->phydev->macsec_ops;
++
++	return false;
++}
++
++static const struct macsec_ops *__macsec_get_ops(enum macsec_offload offload,
++						 struct macsec_dev *macsec,
++						 struct macsec_context *ctx)
++{
++	if (ctx) {
++		memset(ctx, 0, sizeof(*ctx));
++		ctx->offload = offload;
++
++		if (offload == MACSEC_OFFLOAD_PHY)
++			ctx->phydev = macsec->real_dev->phydev;
++	}
++
++	return macsec->real_dev->phydev->macsec_ops;
++}
++
++/* Returns a pointer to the MACsec ops struct if any and updates the MACsec
++ * context device reference if provided.
++ */
++static const struct macsec_ops *macsec_get_ops(struct macsec_dev *macsec,
++					       struct macsec_context *ctx)
++{
++	if (!macsec_check_offload(macsec->offload, macsec))
++		return NULL;
++
++	return __macsec_get_ops(macsec->offload, macsec, ctx);
++}
++
+ /* validate MACsec packet according to IEEE 802.1AE-2006 9.12 */
+ static bool macsec_validate_skb(struct sk_buff *skb, u16 icv_len)
+ {
+@@ -867,8 +921,10 @@ static struct macsec_rx_sc *find_rx_sc_rtnl(struct macsec_secy *secy, sci_t sci)
+ 	return NULL;
+ }
+ 
+-static void handle_not_macsec(struct sk_buff *skb)
++static enum rx_handler_result handle_not_macsec(struct sk_buff *skb)
+ {
++	/* Deliver to the uncontrolled port by default */
++	enum rx_handler_result ret = RX_HANDLER_PASS;
+ 	struct macsec_rxh_data *rxd;
+ 	struct macsec_dev *macsec;
+ 
+@@ -883,7 +939,8 @@ static void handle_not_macsec(struct sk_buff *skb)
+ 		struct sk_buff *nskb;
+ 		struct pcpu_secy_stats *secy_stats = this_cpu_ptr(macsec->stats);
+ 
+-		if (macsec->secy.validate_frames == MACSEC_VALIDATE_STRICT) {
++		if (!macsec_is_offloaded(macsec) &&
++		    macsec->secy.validate_frames == MACSEC_VALIDATE_STRICT) {
+ 			u64_stats_update_begin(&secy_stats->syncp);
+ 			secy_stats->stats.InPktsNoTag++;
+ 			u64_stats_update_end(&secy_stats->syncp);
+@@ -902,9 +959,17 @@ static void handle_not_macsec(struct sk_buff *skb)
+ 			secy_stats->stats.InPktsUntagged++;
+ 			u64_stats_update_end(&secy_stats->syncp);
+ 		}
++
++		if (netif_running(macsec->secy.netdev) &&
++		    macsec_is_offloaded(macsec)) {
++			ret = RX_HANDLER_EXACT;
++			goto out;
++		}
+ 	}
+ 
++out:
+ 	rcu_read_unlock();
++	return ret;
+ }
+ 
+ static rx_handler_result_t macsec_handle_frame(struct sk_buff **pskb)
+@@ -929,12 +994,8 @@ static rx_handler_result_t macsec_handle_frame(struct sk_buff **pskb)
+ 		goto drop_direct;
+ 
+ 	hdr = macsec_ethhdr(skb);
+-	if (hdr->eth.h_proto != htons(ETH_P_MACSEC)) {
+-		handle_not_macsec(skb);
+-
+-		/* and deliver to the uncontrolled port */
+-		return RX_HANDLER_PASS;
+-	}
++	if (hdr->eth.h_proto != htons(ETH_P_MACSEC))
++		return handle_not_macsec(skb);
+ 
+ 	skb = skb_unshare(skb, GFP_ATOMIC);
+ 	*pskb = skb;
+@@ -1440,6 +1501,40 @@ static const struct nla_policy macsec_genl_sa_policy[NUM_MACSEC_SA_ATTR] = {
+ 				 .len = MACSEC_MAX_KEY_LEN, },
+ };
+ 
++/* Offloads an operation to a device driver */
++static int macsec_offload(int (* const func)(struct macsec_context *),
++			  struct macsec_context *ctx)
++{
++	int ret;
++
++	if (unlikely(!func))
++		return 0;
++
++	if (ctx->offload == MACSEC_OFFLOAD_PHY)
++		mutex_lock(&ctx->phydev->lock);
++
++	/* Phase I: prepare. The drive should fail here if there are going to be
++	 * issues in the commit phase.
++	 */
++	ctx->prepare = true;
++	ret = (*func)(ctx);
++	if (ret)
++		goto phy_unlock;
++
++	/* Phase II: commit. This step cannot fail. */
++	ctx->prepare = false;
++	ret = (*func)(ctx);
++	/* This should never happen: commit is not allowed to fail */
++	if (unlikely(ret))
++		WARN(1, "MACsec offloading commit failed (%d)\n", ret);
++
++phy_unlock:
++	if (ctx->offload == MACSEC_OFFLOAD_PHY)
++		mutex_unlock(&ctx->phydev->lock);
++
++	return ret;
++}
++
+ static int parse_sa_config(struct nlattr **attrs, struct nlattr **tb_sa)
+ {
+ 	if (!attrs[MACSEC_ATTR_SA_CONFIG])
+@@ -1555,13 +1650,40 @@ static int macsec_add_rxsa(struct sk_buff *skb, struct genl_info *info)
+ 	if (tb_sa[MACSEC_SA_ATTR_ACTIVE])
+ 		rx_sa->active = !!nla_get_u8(tb_sa[MACSEC_SA_ATTR_ACTIVE]);
+ 
+-	nla_memcpy(rx_sa->key.id, tb_sa[MACSEC_SA_ATTR_KEYID], MACSEC_KEYID_LEN);
+ 	rx_sa->sc = rx_sc;
++
++	/* If h/w offloading is available, propagate to the device */
++	if (macsec_is_offloaded(netdev_priv(dev))) {
++		const struct macsec_ops *ops;
++		struct macsec_context ctx;
++
++		ops = macsec_get_ops(netdev_priv(dev), &ctx);
++		if (!ops) {
++			err = -EOPNOTSUPP;
++			goto cleanup;
++		}
++
++		ctx.sa.assoc_num = assoc_num;
++		ctx.sa.rx_sa = rx_sa;
++		memcpy(ctx.sa.key, nla_data(tb_sa[MACSEC_SA_ATTR_KEY]),
++		       MACSEC_KEYID_LEN);
++
++		err = macsec_offload(ops->mdo_add_rxsa, &ctx);
++		if (err)
++			goto cleanup;
++	}
++
++	nla_memcpy(rx_sa->key.id, tb_sa[MACSEC_SA_ATTR_KEYID], MACSEC_KEYID_LEN);
+ 	rcu_assign_pointer(rx_sc->sa[assoc_num], rx_sa);
+ 
+ 	rtnl_unlock();
+ 
+ 	return 0;
++
++cleanup:
++	kfree(rx_sa);
++	rtnl_unlock();
++	return err;
+ }
+ 
+ static bool validate_add_rxsc(struct nlattr **attrs)
+@@ -1584,6 +1706,8 @@ static int macsec_add_rxsc(struct sk_buff *skb, struct genl_info *info)
+ 	struct nlattr **attrs = info->attrs;
+ 	struct macsec_rx_sc *rx_sc;
+ 	struct nlattr *tb_rxsc[MACSEC_RXSC_ATTR_MAX + 1];
++	bool was_active;
++	int ret;
+ 
+ 	if (!attrs[MACSEC_ATTR_IFINDEX])
+ 		return -EINVAL;
+@@ -1609,12 +1733,35 @@ static int macsec_add_rxsc(struct sk_buff *skb, struct genl_info *info)
+ 		return PTR_ERR(rx_sc);
+ 	}
+ 
++	was_active = rx_sc->active;
+ 	if (tb_rxsc[MACSEC_RXSC_ATTR_ACTIVE])
+ 		rx_sc->active = !!nla_get_u8(tb_rxsc[MACSEC_RXSC_ATTR_ACTIVE]);
+ 
++	if (macsec_is_offloaded(netdev_priv(dev))) {
++		const struct macsec_ops *ops;
++		struct macsec_context ctx;
++
++		ops = macsec_get_ops(netdev_priv(dev), &ctx);
++		if (!ops) {
++			ret = -EOPNOTSUPP;
++			goto cleanup;
++		}
++
++		ctx.rx_sc = rx_sc;
++
++		ret = macsec_offload(ops->mdo_add_rxsc, &ctx);
++		if (ret)
++			goto cleanup;
++	}
++
+ 	rtnl_unlock();
+ 
+ 	return 0;
++
++cleanup:
++	rx_sc->active = was_active;
++	rtnl_unlock();
++	return ret;
+ }
+ 
+ static bool validate_add_txsa(struct nlattr **attrs)
+@@ -1651,6 +1798,7 @@ static int macsec_add_txsa(struct sk_buff *skb, struct genl_info *info)
+ 	struct macsec_tx_sa *tx_sa;
+ 	unsigned char assoc_num;
+ 	struct nlattr *tb_sa[MACSEC_SA_ATTR_MAX + 1];
++	bool was_operational;
+ 	int err;
+ 
+ 	if (!attrs[MACSEC_ATTR_IFINDEX])
+@@ -1701,8 +1849,6 @@ static int macsec_add_txsa(struct sk_buff *skb, struct genl_info *info)
+ 		return err;
+ 	}
+ 
+-	nla_memcpy(tx_sa->key.id, tb_sa[MACSEC_SA_ATTR_KEYID], MACSEC_KEYID_LEN);
+-
+ 	spin_lock_bh(&tx_sa->lock);
+ 	tx_sa->next_pn = nla_get_u32(tb_sa[MACSEC_SA_ATTR_PN]);
+ 	spin_unlock_bh(&tx_sa->lock);
+@@ -1710,14 +1856,43 @@ static int macsec_add_txsa(struct sk_buff *skb, struct genl_info *info)
+ 	if (tb_sa[MACSEC_SA_ATTR_ACTIVE])
+ 		tx_sa->active = !!nla_get_u8(tb_sa[MACSEC_SA_ATTR_ACTIVE]);
+ 
++	was_operational = secy->operational;
+ 	if (assoc_num == tx_sc->encoding_sa && tx_sa->active)
+ 		secy->operational = true;
+ 
++	/* If h/w offloading is available, propagate to the device */
++	if (macsec_is_offloaded(netdev_priv(dev))) {
++		const struct macsec_ops *ops;
++		struct macsec_context ctx;
++
++		ops = macsec_get_ops(netdev_priv(dev), &ctx);
++		if (!ops) {
++			err = -EOPNOTSUPP;
++			goto cleanup;
++		}
++
++		ctx.sa.assoc_num = assoc_num;
++		ctx.sa.tx_sa = tx_sa;
++		memcpy(ctx.sa.key, nla_data(tb_sa[MACSEC_SA_ATTR_KEY]),
++		       MACSEC_KEYID_LEN);
++
++		err = macsec_offload(ops->mdo_add_txsa, &ctx);
++		if (err)
++			goto cleanup;
++	}
++
++	nla_memcpy(tx_sa->key.id, tb_sa[MACSEC_SA_ATTR_KEYID], MACSEC_KEYID_LEN);
+ 	rcu_assign_pointer(tx_sc->sa[assoc_num], tx_sa);
+ 
+ 	rtnl_unlock();
+ 
+ 	return 0;
++
++cleanup:
++	secy->operational = was_operational;
++	kfree(tx_sa);
++	rtnl_unlock();
++	return err;
+ }
+ 
+ static int macsec_del_rxsa(struct sk_buff *skb, struct genl_info *info)
+@@ -1730,6 +1905,7 @@ static int macsec_del_rxsa(struct sk_buff *skb, struct genl_info *info)
+ 	u8 assoc_num;
+ 	struct nlattr *tb_rxsc[MACSEC_RXSC_ATTR_MAX + 1];
+ 	struct nlattr *tb_sa[MACSEC_SA_ATTR_MAX + 1];
++	int ret;
+ 
+ 	if (!attrs[MACSEC_ATTR_IFINDEX])
+ 		return -EINVAL;
+@@ -1753,12 +1929,35 @@ static int macsec_del_rxsa(struct sk_buff *skb, struct genl_info *info)
+ 		return -EBUSY;
+ 	}
+ 
++	/* If h/w offloading is available, propagate to the device */
++	if (macsec_is_offloaded(netdev_priv(dev))) {
++		const struct macsec_ops *ops;
++		struct macsec_context ctx;
++
++		ops = macsec_get_ops(netdev_priv(dev), &ctx);
++		if (!ops) {
++			ret = -EOPNOTSUPP;
++			goto cleanup;
++		}
++
++		ctx.sa.assoc_num = assoc_num;
++		ctx.sa.rx_sa = rx_sa;
++
++		ret = macsec_offload(ops->mdo_del_rxsa, &ctx);
++		if (ret)
++			goto cleanup;
++	}
++
+ 	RCU_INIT_POINTER(rx_sc->sa[assoc_num], NULL);
+ 	clear_rx_sa(rx_sa);
+ 
+ 	rtnl_unlock();
+ 
+ 	return 0;
++
++cleanup:
++	rtnl_unlock();
++	return ret;
+ }
+ 
+ static int macsec_del_rxsc(struct sk_buff *skb, struct genl_info *info)
+@@ -1769,6 +1968,7 @@ static int macsec_del_rxsc(struct sk_buff *skb, struct genl_info *info)
+ 	struct macsec_rx_sc *rx_sc;
+ 	sci_t sci;
+ 	struct nlattr *tb_rxsc[MACSEC_RXSC_ATTR_MAX + 1];
++	int ret;
+ 
+ 	if (!attrs[MACSEC_ATTR_IFINDEX])
+ 		return -EINVAL;
+@@ -1795,10 +1995,31 @@ static int macsec_del_rxsc(struct sk_buff *skb, struct genl_info *info)
+ 		return -ENODEV;
+ 	}
+ 
++	/* If h/w offloading is available, propagate to the device */
++	if (macsec_is_offloaded(netdev_priv(dev))) {
++		const struct macsec_ops *ops;
++		struct macsec_context ctx;
++
++		ops = macsec_get_ops(netdev_priv(dev), &ctx);
++		if (!ops) {
++			ret = -EOPNOTSUPP;
++			goto cleanup;
++		}
++
++		ctx.rx_sc = rx_sc;
++		ret = macsec_offload(ops->mdo_del_rxsc, &ctx);
++		if (ret)
++			goto cleanup;
++	}
++
+ 	free_rx_sc(rx_sc);
+ 	rtnl_unlock();
+ 
+ 	return 0;
++
++cleanup:
++	rtnl_unlock();
++	return ret;
+ }
+ 
+ static int macsec_del_txsa(struct sk_buff *skb, struct genl_info *info)
+@@ -1810,6 +2031,7 @@ static int macsec_del_txsa(struct sk_buff *skb, struct genl_info *info)
+ 	struct macsec_tx_sa *tx_sa;
+ 	u8 assoc_num;
+ 	struct nlattr *tb_sa[MACSEC_SA_ATTR_MAX + 1];
++	int ret;
+ 
+ 	if (!attrs[MACSEC_ATTR_IFINDEX])
+ 		return -EINVAL;
+@@ -1830,12 +2052,35 @@ static int macsec_del_txsa(struct sk_buff *skb, struct genl_info *info)
+ 		return -EBUSY;
+ 	}
+ 
++	/* If h/w offloading is available, propagate to the device */
++	if (macsec_is_offloaded(netdev_priv(dev))) {
++		const struct macsec_ops *ops;
++		struct macsec_context ctx;
++
++		ops = macsec_get_ops(netdev_priv(dev), &ctx);
++		if (!ops) {
++			ret = -EOPNOTSUPP;
++			goto cleanup;
++		}
++
++		ctx.sa.assoc_num = assoc_num;
++		ctx.sa.tx_sa = tx_sa;
++
++		ret = macsec_offload(ops->mdo_del_txsa, &ctx);
++		if (ret)
++			goto cleanup;
++	}
++
+ 	RCU_INIT_POINTER(tx_sc->sa[assoc_num], NULL);
+ 	clear_tx_sa(tx_sa);
+ 
+ 	rtnl_unlock();
+ 
+ 	return 0;
++
++cleanup:
++	rtnl_unlock();
++	return ret;
+ }
+ 
+ static bool validate_upd_sa(struct nlattr **attrs)
+@@ -1868,6 +2113,9 @@ static int macsec_upd_txsa(struct sk_buff *skb, struct genl_info *info)
+ 	struct macsec_tx_sa *tx_sa;
+ 	u8 assoc_num;
+ 	struct nlattr *tb_sa[MACSEC_SA_ATTR_MAX + 1];
++	bool was_operational, was_active;
++	u32 prev_pn = 0;
++	int ret = 0;
+ 
+ 	if (!attrs[MACSEC_ATTR_IFINDEX])
+ 		return -EINVAL;
+@@ -1888,19 +2136,52 @@ static int macsec_upd_txsa(struct sk_buff *skb, struct genl_info *info)
+ 
+ 	if (tb_sa[MACSEC_SA_ATTR_PN]) {
+ 		spin_lock_bh(&tx_sa->lock);
++		prev_pn = tx_sa->next_pn;
+ 		tx_sa->next_pn = nla_get_u32(tb_sa[MACSEC_SA_ATTR_PN]);
+ 		spin_unlock_bh(&tx_sa->lock);
+ 	}
+ 
++	was_active = tx_sa->active;
+ 	if (tb_sa[MACSEC_SA_ATTR_ACTIVE])
+ 		tx_sa->active = nla_get_u8(tb_sa[MACSEC_SA_ATTR_ACTIVE]);
+ 
++	was_operational = secy->operational;
+ 	if (assoc_num == tx_sc->encoding_sa)
+ 		secy->operational = tx_sa->active;
+ 
++	/* If h/w offloading is available, propagate to the device */
++	if (macsec_is_offloaded(netdev_priv(dev))) {
++		const struct macsec_ops *ops;
++		struct macsec_context ctx;
++
++		ops = macsec_get_ops(netdev_priv(dev), &ctx);
++		if (!ops) {
++			ret = -EOPNOTSUPP;
++			goto cleanup;
++		}
++
++		ctx.sa.assoc_num = assoc_num;
++		ctx.sa.tx_sa = tx_sa;
++
++		ret = macsec_offload(ops->mdo_upd_txsa, &ctx);
++		if (ret)
++			goto cleanup;
++	}
++
+ 	rtnl_unlock();
+ 
+ 	return 0;
++
++cleanup:
++	if (tb_sa[MACSEC_SA_ATTR_PN]) {
++		spin_lock_bh(&tx_sa->lock);
++		tx_sa->next_pn = prev_pn;
++		spin_unlock_bh(&tx_sa->lock);
++	}
++	tx_sa->active = was_active;
++	secy->operational = was_operational;
++	rtnl_unlock();
++	return ret;
+ }
+ 
+ static int macsec_upd_rxsa(struct sk_buff *skb, struct genl_info *info)
+@@ -1913,6 +2194,9 @@ static int macsec_upd_rxsa(struct sk_buff *skb, struct genl_info *info)
+ 	u8 assoc_num;
+ 	struct nlattr *tb_rxsc[MACSEC_RXSC_ATTR_MAX + 1];
+ 	struct nlattr *tb_sa[MACSEC_SA_ATTR_MAX + 1];
++	bool was_active;
++	u32 prev_pn = 0;
++	int ret = 0;
+ 
+ 	if (!attrs[MACSEC_ATTR_IFINDEX])
+ 		return -EINVAL;
+@@ -1936,15 +2220,46 @@ static int macsec_upd_rxsa(struct sk_buff *skb, struct genl_info *info)
+ 
+ 	if (tb_sa[MACSEC_SA_ATTR_PN]) {
+ 		spin_lock_bh(&rx_sa->lock);
++		prev_pn = rx_sa->next_pn;
+ 		rx_sa->next_pn = nla_get_u32(tb_sa[MACSEC_SA_ATTR_PN]);
+ 		spin_unlock_bh(&rx_sa->lock);
+ 	}
+ 
++	was_active = rx_sa->active;
+ 	if (tb_sa[MACSEC_SA_ATTR_ACTIVE])
+ 		rx_sa->active = nla_get_u8(tb_sa[MACSEC_SA_ATTR_ACTIVE]);
+ 
++	/* If h/w offloading is available, propagate to the device */
++	if (macsec_is_offloaded(netdev_priv(dev))) {
++		const struct macsec_ops *ops;
++		struct macsec_context ctx;
++
++		ops = macsec_get_ops(netdev_priv(dev), &ctx);
++		if (!ops) {
++			ret = -EOPNOTSUPP;
++			goto cleanup;
++		}
++
++		ctx.sa.assoc_num = assoc_num;
++		ctx.sa.rx_sa = rx_sa;
++
++		ret = macsec_offload(ops->mdo_upd_rxsa, &ctx);
++		if (ret)
++			goto cleanup;
++	}
++
+ 	rtnl_unlock();
+ 	return 0;
++
++cleanup:
++	if (tb_sa[MACSEC_SA_ATTR_PN]) {
++		spin_lock_bh(&rx_sa->lock);
++		rx_sa->next_pn = prev_pn;
++		spin_unlock_bh(&rx_sa->lock);
++	}
++	rx_sa->active = was_active;
++	rtnl_unlock();
++	return ret;
+ }
+ 
+ static int macsec_upd_rxsc(struct sk_buff *skb, struct genl_info *info)
+@@ -1954,6 +2269,9 @@ static int macsec_upd_rxsc(struct sk_buff *skb, struct genl_info *info)
+ 	struct macsec_secy *secy;
+ 	struct macsec_rx_sc *rx_sc;
+ 	struct nlattr *tb_rxsc[MACSEC_RXSC_ATTR_MAX + 1];
++	unsigned int prev_n_rx_sc;
++	bool was_active;
++	int ret;
+ 
+ 	if (!attrs[MACSEC_ATTR_IFINDEX])
+ 		return -EINVAL;
+@@ -1971,6 +2289,8 @@ static int macsec_upd_rxsc(struct sk_buff *skb, struct genl_info *info)
+ 		return PTR_ERR(rx_sc);
+ 	}
+ 
++	was_active = rx_sc->active;
++	prev_n_rx_sc = secy->n_rx_sc;
+ 	if (tb_rxsc[MACSEC_RXSC_ATTR_ACTIVE]) {
+ 		bool new = !!nla_get_u8(tb_rxsc[MACSEC_RXSC_ATTR_ACTIVE]);
+ 
+@@ -1980,9 +2300,33 @@ static int macsec_upd_rxsc(struct sk_buff *skb, struct genl_info *info)
+ 		rx_sc->active = new;
+ 	}
+ 
++	/* If h/w offloading is available, propagate to the device */
++	if (macsec_is_offloaded(netdev_priv(dev))) {
++		const struct macsec_ops *ops;
++		struct macsec_context ctx;
++
++		ops = macsec_get_ops(netdev_priv(dev), &ctx);
++		if (!ops) {
++			ret = -EOPNOTSUPP;
++			goto cleanup;
++		}
++
++		ctx.rx_sc = rx_sc;
++
++		ret = macsec_offload(ops->mdo_upd_rxsc, &ctx);
++		if (ret)
++			goto cleanup;
++	}
++
+ 	rtnl_unlock();
+ 
+ 	return 0;
++
++cleanup:
++	secy->n_rx_sc = prev_n_rx_sc;
++	rx_sc->active = was_active;
++	rtnl_unlock();
++	return ret;
+ }
+ 
+ static int copy_tx_sa_stats(struct sk_buff *skb,
+@@ -2550,6 +2894,11 @@ static netdev_tx_t macsec_start_xmit(struct sk_buff *skb,
+ 	struct pcpu_secy_stats *secy_stats;
+ 	int ret, len;
+ 
++	if (macsec_is_offloaded(netdev_priv(dev))) {
++		skb->dev = macsec->real_dev;
++		return dev_queue_xmit(skb);
++	}
++
+ 	/* 10.5 */
+ 	if (!secy->protect_frames) {
+ 		secy_stats = this_cpu_ptr(macsec->stats);
+@@ -2663,6 +3012,22 @@ static int macsec_dev_open(struct net_device *dev)
+ 			goto clear_allmulti;
+ 	}
+ 
++	/* If h/w offloading is available, propagate to the device */
++	if (macsec_is_offloaded(macsec)) {
++		const struct macsec_ops *ops;
++		struct macsec_context ctx;
++
++		ops = macsec_get_ops(netdev_priv(dev), &ctx);
++		if (!ops) {
++			err = -EOPNOTSUPP;
++			goto clear_allmulti;
++		}
++
++		err = macsec_offload(ops->mdo_dev_open, &ctx);
++		if (err)
++			goto clear_allmulti;
++	}
++
+ 	if (netif_carrier_ok(real_dev))
+ 		netif_carrier_on(dev);
+ 
+@@ -2683,6 +3048,16 @@ static int macsec_dev_stop(struct net_device *dev)
+ 
+ 	netif_carrier_off(dev);
+ 
++	/* If h/w offloading is available, propagate to the device */
++	if (macsec_is_offloaded(macsec)) {
++		const struct macsec_ops *ops;
++		struct macsec_context ctx;
++
++		ops = macsec_get_ops(macsec, &ctx);
++		if (ops)
++			macsec_offload(ops->mdo_dev_stop, &ctx);
++	}
++
+ 	dev_mc_unsync(real_dev, dev);
+ 	dev_uc_unsync(real_dev, dev);
+ 
+@@ -2914,6 +3289,11 @@ static int macsec_changelink(struct net_device *dev, struct nlattr *tb[],
+ 			     struct nlattr *data[],
+ 			     struct netlink_ext_ack *extack)
+ {
++	struct macsec_dev *macsec = macsec_priv(dev);
++	struct macsec_tx_sa tx_sc;
++	struct macsec_secy secy;
++	int ret;
++
+ 	if (!data)
+ 		return 0;
+ 
+@@ -2923,7 +3303,41 @@ static int macsec_changelink(struct net_device *dev, struct nlattr *tb[],
+ 	    data[IFLA_MACSEC_PORT])
+ 		return -EINVAL;
+ 
+-	return macsec_changelink_common(dev, data);
++	/* Keep a copy of unmodified secy and tx_sc, in case the offload
++	 * propagation fails, to revert macsec_changelink_common.
++	 */
++	memcpy(&secy, &macsec->secy, sizeof(secy));
++	memcpy(&tx_sc, &macsec->secy.tx_sc, sizeof(tx_sc));
++
++	ret = macsec_changelink_common(dev, data);
++	if (ret)
++		return ret;
++
++	/* If h/w offloading is available, propagate to the device */
++	if (macsec_is_offloaded(macsec)) {
++		const struct macsec_ops *ops;
++		struct macsec_context ctx;
++		int ret;
++
++		ops = macsec_get_ops(netdev_priv(dev), &ctx);
++		if (!ops) {
++			ret = -EOPNOTSUPP;
++			goto cleanup;
++		}
++
++		ctx.secy = &macsec->secy;
++		ret = macsec_offload(ops->mdo_upd_secy, &ctx);
++		if (ret)
++			goto cleanup;
++	}
++
++	return 0;
++
++cleanup:
++	memcpy(&macsec->secy.tx_sc, &tx_sc, sizeof(tx_sc));
++	memcpy(&macsec->secy, &secy, sizeof(secy));
++
++	return ret;
+ }
+ 
+ static void macsec_del_dev(struct macsec_dev *macsec)
+@@ -2966,6 +3380,18 @@ static void macsec_dellink(struct net_device *dev, struct list_head *head)
+ 	struct net_device *real_dev = macsec->real_dev;
+ 	struct macsec_rxh_data *rxd = macsec_data_rtnl(real_dev);
+ 
++	/* If h/w offloading is available, propagate to the device */
++	if (macsec_is_offloaded(macsec)) {
++		const struct macsec_ops *ops;
++		struct macsec_context ctx;
++
++		ops = macsec_get_ops(netdev_priv(dev), &ctx);
++		if (ops) {
++			ctx.secy = &macsec->secy;
++			macsec_offload(ops->mdo_del_secy, &ctx);
++		}
++	}
++
+ 	macsec_common_dellink(dev, head);
+ 
+ 	if (list_empty(&rxd->secys)) {
+@@ -3077,6 +3503,9 @@ static int macsec_newlink(struct net *net, struct net_device *dev,
+ 
+ 	macsec->real_dev = real_dev;
+ 
++	/* MACsec offloading is off by default */
++	macsec->offload = MACSEC_OFFLOAD_OFF;
++
+ 	if (data && data[IFLA_MACSEC_ICV_LEN])
+ 		icv_len = nla_get_u8(data[IFLA_MACSEC_ICV_LEN]);
+ 	dev->mtu = real_dev->mtu - icv_len - macsec_extra_len(true);
+-- 
+cgit 1.2.3-1.el7
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1756-06-v5.18-net-macsec-add-nla-support-for-changing-the-offloading-selection.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1756-06-v5.18-net-macsec-add-nla-support-for-changing-the-offloading-selection.patch
new file mode 100644
index 0000000..849d2cd
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1756-06-v5.18-net-macsec-add-nla-support-for-changing-the-offloading-selection.patch
@@ -0,0 +1,253 @@
+From dcb780fb279514f268826f2e9f4df3bc75610703 Mon Sep 17 00:00:00 2001
+From: Antoine Tenart <antoine.tenart@bootlin.com>
+Date: Mon, 13 Jan 2020 23:31:44 +0100
+Subject: net: macsec: add nla support for changing the offloading selection
+
+MACsec offloading to underlying hardware devices is disabled by default
+(the software implementation is used). This patch adds support for
+changing this setting through the MACsec netlink interface. Many checks
+are done when enabling offloading on a given MACsec interface as there
+are limitations (it must be supported by the hardware, only a single
+interface can be offloaded on a given physical device at a time, rules
+can't be moved for now).
+
+Signed-off-by: Antoine Tenart <antoine.tenart@bootlin.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/macsec.c           | 145 ++++++++++++++++++++++++++++++++++++++++-
+ include/uapi/linux/if_macsec.h |  11 ++++
+ 2 files changed, 153 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
+index 36b0416381bf1..e515919e8687f 100644
+--- a/drivers/net/macsec.c
++++ b/drivers/net/macsec.c
+@@ -1484,6 +1484,7 @@ static const struct nla_policy macsec_genl_policy[NUM_MACSEC_ATTR] = {
+ 	[MACSEC_ATTR_IFINDEX] = { .type = NLA_U32 },
+ 	[MACSEC_ATTR_RXSC_CONFIG] = { .type = NLA_NESTED },
+ 	[MACSEC_ATTR_SA_CONFIG] = { .type = NLA_NESTED },
++	[MACSEC_ATTR_OFFLOAD] = { .type = NLA_NESTED },
+ };
+ 
+ static const struct nla_policy macsec_genl_rxsc_policy[NUM_MACSEC_RXSC_ATTR] = {
+@@ -1501,6 +1502,10 @@ static const struct nla_policy macsec_genl_sa_policy[NUM_MACSEC_SA_ATTR] = {
+ 				 .len = MACSEC_MAX_KEY_LEN, },
+ };
+ 
++static const struct nla_policy macsec_genl_offload_policy[NUM_MACSEC_OFFLOAD_ATTR] = {
++	[MACSEC_OFFLOAD_ATTR_TYPE] = { .type = NLA_U8 },
++};
++
+ /* Offloads an operation to a device driver */
+ static int macsec_offload(int (* const func)(struct macsec_context *),
+ 			  struct macsec_context *ctx)
+@@ -2329,6 +2334,126 @@ cleanup:
+ 	return ret;
+ }
+ 
++static bool macsec_is_configured(struct macsec_dev *macsec)
++{
++	struct macsec_secy *secy = &macsec->secy;
++	struct macsec_tx_sc *tx_sc = &secy->tx_sc;
++	int i;
++
++	if (secy->n_rx_sc > 0)
++		return true;
++
++	for (i = 0; i < MACSEC_NUM_AN; i++)
++		if (tx_sc->sa[i])
++			return true;
++
++	return false;
++}
++
++static int macsec_upd_offload(struct sk_buff *skb, struct genl_info *info)
++{
++	struct nlattr *tb_offload[MACSEC_OFFLOAD_ATTR_MAX + 1];
++	enum macsec_offload offload, prev_offload;
++	int (*func)(struct macsec_context *ctx);
++	struct nlattr **attrs = info->attrs;
++	struct net_device *dev, *loop_dev;
++	const struct macsec_ops *ops;
++	struct macsec_context ctx;
++	struct macsec_dev *macsec;
++	struct net *loop_net;
++	int ret;
++
++	if (!attrs[MACSEC_ATTR_IFINDEX])
++		return -EINVAL;
++
++	if (!attrs[MACSEC_ATTR_OFFLOAD])
++		return -EINVAL;
++
++	if (nla_parse_nested_deprecated(tb_offload, MACSEC_OFFLOAD_ATTR_MAX,
++					attrs[MACSEC_ATTR_OFFLOAD],
++					macsec_genl_offload_policy, NULL))
++		return -EINVAL;
++
++	dev = get_dev_from_nl(genl_info_net(info), attrs);
++	if (IS_ERR(dev))
++		return PTR_ERR(dev);
++	macsec = macsec_priv(dev);
++
++	offload = nla_get_u8(tb_offload[MACSEC_OFFLOAD_ATTR_TYPE]);
++	if (macsec->offload == offload)
++		return 0;
++
++	/* Check if the offloading mode is supported by the underlying layers */
++	if (offload != MACSEC_OFFLOAD_OFF &&
++	    !macsec_check_offload(offload, macsec))
++		return -EOPNOTSUPP;
++
++	if (offload == MACSEC_OFFLOAD_OFF)
++		goto skip_limitation;
++
++	/* Check the physical interface isn't offloading another interface
++	 * first.
++	 */
++	for_each_net(loop_net) {
++		for_each_netdev(loop_net, loop_dev) {
++			struct macsec_dev *priv;
++
++			if (!netif_is_macsec(loop_dev))
++				continue;
++
++			priv = macsec_priv(loop_dev);
++
++			if (priv->real_dev == macsec->real_dev &&
++			    priv->offload != MACSEC_OFFLOAD_OFF)
++				return -EBUSY;
++		}
++	}
++
++skip_limitation:
++	/* Check if the net device is busy. */
++	if (netif_running(dev))
++		return -EBUSY;
++
++	rtnl_lock();
++
++	prev_offload = macsec->offload;
++	macsec->offload = offload;
++
++	/* Check if the device already has rules configured: we do not support
++	 * rules migration.
++	 */
++	if (macsec_is_configured(macsec)) {
++		ret = -EBUSY;
++		goto rollback;
++	}
++
++	ops = __macsec_get_ops(offload == MACSEC_OFFLOAD_OFF ? prev_offload : offload,
++			       macsec, &ctx);
++	if (!ops) {
++		ret = -EOPNOTSUPP;
++		goto rollback;
++	}
++
++	if (prev_offload == MACSEC_OFFLOAD_OFF)
++		func = ops->mdo_add_secy;
++	else
++		func = ops->mdo_del_secy;
++
++	ctx.secy = &macsec->secy;
++	ret = macsec_offload(func, &ctx);
++	if (ret)
++		goto rollback;
++
++	rtnl_unlock();
++	return 0;
++
++rollback:
++	macsec->offload = prev_offload;
++
++	rtnl_unlock();
++	return ret;
++}
++
+ static int copy_tx_sa_stats(struct sk_buff *skb,
+ 			    struct macsec_tx_sa_stats __percpu *pstats)
+ {
+@@ -2590,12 +2715,13 @@ static noinline_for_stack int
+ dump_secy(struct macsec_secy *secy, struct net_device *dev,
+ 	  struct sk_buff *skb, struct netlink_callback *cb)
+ {
+-	struct macsec_rx_sc *rx_sc;
++	struct macsec_dev *macsec = netdev_priv(dev);
+ 	struct macsec_tx_sc *tx_sc = &secy->tx_sc;
+ 	struct nlattr *txsa_list, *rxsc_list;
+-	int i, j;
+-	void *hdr;
++	struct macsec_rx_sc *rx_sc;
+ 	struct nlattr *attr;
++	void *hdr;
++	int i, j;
+ 
+ 	hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
+ 			  &macsec_fam, NLM_F_MULTI, MACSEC_CMD_GET_TXSC);
+@@ -2607,6 +2733,13 @@ dump_secy(struct macsec_secy *secy, struct net_device *dev,
+ 	if (nla_put_u32(skb, MACSEC_ATTR_IFINDEX, dev->ifindex))
+ 		goto nla_put_failure;
+ 
++	attr = nla_nest_start_noflag(skb, MACSEC_ATTR_OFFLOAD);
++	if (!attr)
++		goto nla_put_failure;
++	if (nla_put_u8(skb, MACSEC_OFFLOAD_ATTR_TYPE, macsec->offload))
++		goto nla_put_failure;
++	nla_nest_end(skb, attr);
++
+ 	if (nla_put_secy(secy, skb))
+ 		goto nla_put_failure;
+ 
+@@ -2872,6 +3005,12 @@ static const struct genl_ops macsec_genl_ops[] = {
+ 		.doit = macsec_upd_rxsa,
+ 		.flags = GENL_ADMIN_PERM,
+ 	},
++	{
++		.cmd = MACSEC_CMD_UPD_OFFLOAD,
++		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
++		.doit = macsec_upd_offload,
++		.flags = GENL_ADMIN_PERM,
++	},
+ };
+ 
+ static struct genl_family macsec_fam __ro_after_init = {
+diff --git a/include/uapi/linux/if_macsec.h b/include/uapi/linux/if_macsec.h
+index 98e4d5d7c45ca..1d63c43c38cca 100644
+--- a/include/uapi/linux/if_macsec.h
++++ b/include/uapi/linux/if_macsec.h
+@@ -45,6 +45,7 @@ enum macsec_attrs {
+ 	MACSEC_ATTR_RXSC_LIST,   /* dump, nested, macsec_rxsc_attrs for each RXSC */
+ 	MACSEC_ATTR_TXSC_STATS,  /* dump, nested, macsec_txsc_stats_attr */
+ 	MACSEC_ATTR_SECY_STATS,  /* dump, nested, macsec_secy_stats_attr */
++	MACSEC_ATTR_OFFLOAD,     /* config, nested, macsec_offload_attrs */
+ 	__MACSEC_ATTR_END,
+ 	NUM_MACSEC_ATTR = __MACSEC_ATTR_END,
+ 	MACSEC_ATTR_MAX = __MACSEC_ATTR_END - 1,
+@@ -97,6 +98,15 @@ enum macsec_sa_attrs {
+ 	MACSEC_SA_ATTR_MAX = __MACSEC_SA_ATTR_END - 1,
+ };
+ 
++enum macsec_offload_attrs {
++	MACSEC_OFFLOAD_ATTR_UNSPEC,
++	MACSEC_OFFLOAD_ATTR_TYPE, /* config/dump, u8 0..2 */
++	MACSEC_OFFLOAD_ATTR_PAD,
++	__MACSEC_OFFLOAD_ATTR_END,
++	NUM_MACSEC_OFFLOAD_ATTR = __MACSEC_OFFLOAD_ATTR_END,
++	MACSEC_OFFLOAD_ATTR_MAX = __MACSEC_OFFLOAD_ATTR_END - 1,
++};
++
+ enum macsec_nl_commands {
+ 	MACSEC_CMD_GET_TXSC,
+ 	MACSEC_CMD_ADD_RXSC,
+@@ -108,6 +118,7 @@ enum macsec_nl_commands {
+ 	MACSEC_CMD_ADD_RXSA,
+ 	MACSEC_CMD_DEL_RXSA,
+ 	MACSEC_CMD_UPD_RXSA,
++	MACSEC_CMD_UPD_OFFLOAD,
+ };
+ 
+ /* u64 per-RXSC stats */
+-- 
+cgit 1.2.3-1.el7
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1757-07-v5.18-net-phy-mscc-macsec-initialization.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1757-07-v5.18-net-phy-mscc-macsec-initialization.patch
new file mode 100644
index 0000000..869e7b6
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1757-07-v5.18-net-phy-mscc-macsec-initialization.patch
@@ -0,0 +1,953 @@
+From 1bbe0ecc2a1a008bcfeb7fd2d8f95c8e9a1867c6 Mon Sep 17 00:00:00 2001
+From: Antoine Tenart <antoine.tenart@bootlin.com>
+Date: Mon, 13 Jan 2020 23:31:45 +0100
+Subject: net: phy: mscc: macsec initialization
+
+This patch adds support for initializing the MACsec engine found within
+some Microsemi PHYs. The engine is initialized in a passthrough mode and
+does not modify any incoming or outgoing packet. But thanks to this it
+now can be configured to perform MACsec transformations on packets,
+which will be supported by a future patch.
+
+The MACsec read and write functions are wrapped into two versions: one
+called during the init phase, and the other one later on. This is
+because the init functions in the Microsemi PHY driver are called while
+the MDIO bus lock is taken.
+
+Signed-off-by: Antoine Tenart <antoine.tenart@bootlin.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/phy/mscc.c           | 382 +++++++++++++++++++++++++++++++++++++++
+ drivers/net/phy/mscc_fc_buffer.h |  64 +++++++
+ drivers/net/phy/mscc_mac.h       | 159 ++++++++++++++++
+ drivers/net/phy/mscc_macsec.h    | 260 ++++++++++++++++++++++++++
+ 4 files changed, 865 insertions(+)
+ create mode 100644 drivers/net/phy/mscc_fc_buffer.h
+ create mode 100644 drivers/net/phy/mscc_mac.h
+ create mode 100644 drivers/net/phy/mscc_macsec.h
+
+diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c
+index 50214c081164f..8579a59a1336a 100644
+--- a/drivers/net/phy/mscc.c
++++ b/drivers/net/phy/mscc.c
+@@ -18,6 +18,10 @@
+ #include <linux/netdevice.h>
+ #include <dt-bindings/net/mscc-phy-vsc8531.h>
+ 
++#include "mscc_macsec.h"
++#include "mscc_mac.h"
++#include "mscc_fc_buffer.h"
++
+ enum rgmii_rx_clock_delay {
+ 	RGMII_RX_CLK_DELAY_0_2_NS = 0,
+ 	RGMII_RX_CLK_DELAY_0_8_NS = 1,
+@@ -121,6 +125,26 @@ enum rgmii_rx_clock_delay {
+ #define PHY_S6G_PLL_FSM_CTRL_DATA_POS	  8
+ #define PHY_S6G_PLL_FSM_ENA_POS		  7
+ 
++#define MSCC_EXT_PAGE_MACSEC_17		  17
++#define MSCC_EXT_PAGE_MACSEC_18		  18
++
++#define MSCC_EXT_PAGE_MACSEC_19		  19
++#define MSCC_PHY_MACSEC_19_REG_ADDR(x)	  (x)
++#define MSCC_PHY_MACSEC_19_TARGET(x)	  ((x) << 12)
++#define MSCC_PHY_MACSEC_19_READ		  BIT(14)
++#define MSCC_PHY_MACSEC_19_CMD		  BIT(15)
++
++#define MSCC_EXT_PAGE_MACSEC_20		  20
++#define MSCC_PHY_MACSEC_20_TARGET(x)	  (x)
++enum macsec_bank {
++	FC_BUFFER   = 0x04,
++	HOST_MAC    = 0x05,
++	LINE_MAC    = 0x06,
++	IP_1588     = 0x0e,
++	MACSEC_INGR = 0x38,
++	MACSEC_EGR  = 0x3c,
++};
++
+ #define MSCC_EXT_PAGE_ACCESS		  31
+ #define MSCC_PHY_PAGE_STANDARD		  0x0000 /* Standard registers */
+ #define MSCC_PHY_PAGE_EXTENDED		  0x0001 /* Extended registers */
+@@ -128,6 +152,7 @@ enum rgmii_rx_clock_delay {
+ #define MSCC_PHY_PAGE_EXTENDED_3	  0x0003 /* Extended reg - page 3 */
+ #define MSCC_PHY_PAGE_EXTENDED_4	  0x0004 /* Extended reg - page 4 */
+ #define MSCC_PHY_PAGE_CSR_CNTL		  MSCC_PHY_PAGE_EXTENDED_4
++#define MSCC_PHY_PAGE_MACSEC		  MSCC_PHY_PAGE_EXTENDED_4
+ /* Extended reg - GPIO; this is a bank of registers that are shared for all PHYs
+  * in the same package.
+  */
+@@ -1584,6 +1609,350 @@ out:
+ 	return ret;
+ }
+ 
++#if IS_ENABLED(CONFIG_MACSEC)
++static u32 vsc8584_macsec_phy_read(struct phy_device *phydev,
++				   enum macsec_bank bank, u32 reg)
++{
++	u32 val, val_l = 0, val_h = 0;
++	unsigned long deadline;
++	int rc;
++
++	rc = phy_select_page(phydev, MSCC_PHY_PAGE_MACSEC);
++	if (rc < 0)
++		goto failed;
++
++	__phy_write(phydev, MSCC_EXT_PAGE_MACSEC_20,
++		    MSCC_PHY_MACSEC_20_TARGET(bank >> 2));
++
++	if (bank >> 2 == 0x1)
++		/* non-MACsec access */
++		bank &= 0x3;
++	else
++		bank = 0;
++
++	__phy_write(phydev, MSCC_EXT_PAGE_MACSEC_19,
++		    MSCC_PHY_MACSEC_19_CMD | MSCC_PHY_MACSEC_19_READ |
++		    MSCC_PHY_MACSEC_19_REG_ADDR(reg) |
++		    MSCC_PHY_MACSEC_19_TARGET(bank));
++
++	deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS);
++	do {
++		val = __phy_read(phydev, MSCC_EXT_PAGE_MACSEC_19);
++	} while (time_before(jiffies, deadline) && !(val & MSCC_PHY_MACSEC_19_CMD));
++
++	val_l = __phy_read(phydev, MSCC_EXT_PAGE_MACSEC_17);
++	val_h = __phy_read(phydev, MSCC_EXT_PAGE_MACSEC_18);
++
++failed:
++	phy_restore_page(phydev, rc, rc);
++
++	return (val_h << 16) | val_l;
++}
++
++static void vsc8584_macsec_phy_write(struct phy_device *phydev,
++				     enum macsec_bank bank, u32 reg, u32 val)
++{
++	unsigned long deadline;
++	int rc;
++
++	rc = phy_select_page(phydev, MSCC_PHY_PAGE_MACSEC);
++	if (rc < 0)
++		goto failed;
++
++	__phy_write(phydev, MSCC_EXT_PAGE_MACSEC_20,
++		    MSCC_PHY_MACSEC_20_TARGET(bank >> 2));
++
++	if ((bank >> 2 == 0x1) || (bank >> 2 == 0x3))
++		bank &= 0x3;
++	else
++		/* MACsec access */
++		bank = 0;
++
++	__phy_write(phydev, MSCC_EXT_PAGE_MACSEC_17, (u16)val);
++	__phy_write(phydev, MSCC_EXT_PAGE_MACSEC_18, (u16)(val >> 16));
++
++	__phy_write(phydev, MSCC_EXT_PAGE_MACSEC_19,
++		    MSCC_PHY_MACSEC_19_CMD | MSCC_PHY_MACSEC_19_REG_ADDR(reg) |
++		    MSCC_PHY_MACSEC_19_TARGET(bank));
++
++	deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS);
++	do {
++		val = __phy_read(phydev, MSCC_EXT_PAGE_MACSEC_19);
++	} while (time_before(jiffies, deadline) && !(val & MSCC_PHY_MACSEC_19_CMD));
++
++failed:
++	phy_restore_page(phydev, rc, rc);
++}
++
++static void vsc8584_macsec_classification(struct phy_device *phydev,
++					  enum macsec_bank bank)
++{
++	/* enable VLAN tag parsing */
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_CP_TAG,
++				 MSCC_MS_SAM_CP_TAG_PARSE_STAG |
++				 MSCC_MS_SAM_CP_TAG_PARSE_QTAG |
++				 MSCC_MS_SAM_CP_TAG_PARSE_QINQ);
++}
++
++static void vsc8584_macsec_flow_default_action(struct phy_device *phydev,
++					       enum macsec_bank bank,
++					       bool block)
++{
++	u32 port = (bank == MACSEC_INGR) ?
++		    MSCC_MS_PORT_UNCONTROLLED : MSCC_MS_PORT_COMMON;
++	u32 action = MSCC_MS_FLOW_BYPASS;
++
++	if (block)
++		action = MSCC_MS_FLOW_DROP;
++
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_NM_FLOW_NCP,
++				 /* MACsec untagged */
++				 MSCC_MS_SAM_NM_FLOW_NCP_UNTAGGED_FLOW_TYPE(action) |
++				 MSCC_MS_SAM_NM_FLOW_NCP_UNTAGGED_DROP_ACTION(MSCC_MS_ACTION_DROP) |
++				 MSCC_MS_SAM_NM_FLOW_NCP_UNTAGGED_DEST_PORT(port) |
++				 /* MACsec tagged */
++				 MSCC_MS_SAM_NM_FLOW_NCP_TAGGED_FLOW_TYPE(action) |
++				 MSCC_MS_SAM_NM_FLOW_NCP_TAGGED_DROP_ACTION(MSCC_MS_ACTION_DROP) |
++				 MSCC_MS_SAM_NM_FLOW_NCP_TAGGED_DEST_PORT(port) |
++				 /* Bad tag */
++				 MSCC_MS_SAM_NM_FLOW_NCP_BADTAG_FLOW_TYPE(action) |
++				 MSCC_MS_SAM_NM_FLOW_NCP_BADTAG_DROP_ACTION(MSCC_MS_ACTION_DROP) |
++				 MSCC_MS_SAM_NM_FLOW_NCP_BADTAG_DEST_PORT(port) |
++				 /* Kay tag */
++				 MSCC_MS_SAM_NM_FLOW_NCP_KAY_FLOW_TYPE(action) |
++				 MSCC_MS_SAM_NM_FLOW_NCP_KAY_DROP_ACTION(MSCC_MS_ACTION_DROP) |
++				 MSCC_MS_SAM_NM_FLOW_NCP_KAY_DEST_PORT(port));
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_NM_FLOW_CP,
++				 /* MACsec untagged */
++				 MSCC_MS_SAM_NM_FLOW_NCP_UNTAGGED_FLOW_TYPE(action) |
++				 MSCC_MS_SAM_NM_FLOW_CP_UNTAGGED_DROP_ACTION(MSCC_MS_ACTION_DROP) |
++				 MSCC_MS_SAM_NM_FLOW_CP_UNTAGGED_DEST_PORT(port) |
++				 /* MACsec tagged */
++				 MSCC_MS_SAM_NM_FLOW_NCP_TAGGED_FLOW_TYPE(action) |
++				 MSCC_MS_SAM_NM_FLOW_CP_TAGGED_DROP_ACTION(MSCC_MS_ACTION_DROP) |
++				 MSCC_MS_SAM_NM_FLOW_CP_TAGGED_DEST_PORT(port) |
++				 /* Bad tag */
++				 MSCC_MS_SAM_NM_FLOW_NCP_BADTAG_FLOW_TYPE(action) |
++				 MSCC_MS_SAM_NM_FLOW_CP_BADTAG_DROP_ACTION(MSCC_MS_ACTION_DROP) |
++				 MSCC_MS_SAM_NM_FLOW_CP_BADTAG_DEST_PORT(port) |
++				 /* Kay tag */
++				 MSCC_MS_SAM_NM_FLOW_NCP_KAY_FLOW_TYPE(action) |
++				 MSCC_MS_SAM_NM_FLOW_CP_KAY_DROP_ACTION(MSCC_MS_ACTION_DROP) |
++				 MSCC_MS_SAM_NM_FLOW_CP_KAY_DEST_PORT(port));
++}
++
++static void vsc8584_macsec_integrity_checks(struct phy_device *phydev,
++					    enum macsec_bank bank)
++{
++	u32 val;
++
++	if (bank != MACSEC_INGR)
++		return;
++
++	/* Set default rules to pass unmatched frames */
++	val = vsc8584_macsec_phy_read(phydev, bank,
++				      MSCC_MS_PARAMS2_IG_CC_CONTROL);
++	val |= MSCC_MS_PARAMS2_IG_CC_CONTROL_NON_MATCH_CTRL_ACT |
++	       MSCC_MS_PARAMS2_IG_CC_CONTROL_NON_MATCH_ACT;
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_PARAMS2_IG_CC_CONTROL,
++				 val);
++
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_PARAMS2_IG_CP_TAG,
++				 MSCC_MS_PARAMS2_IG_CP_TAG_PARSE_STAG |
++				 MSCC_MS_PARAMS2_IG_CP_TAG_PARSE_QTAG |
++				 MSCC_MS_PARAMS2_IG_CP_TAG_PARSE_QINQ);
++}
++
++static void vsc8584_macsec_block_init(struct phy_device *phydev,
++				      enum macsec_bank bank)
++{
++	u32 val;
++	int i;
++
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_ENA_CFG,
++				 MSCC_MS_ENA_CFG_SW_RST |
++				 MSCC_MS_ENA_CFG_MACSEC_BYPASS_ENA);
++
++	/* Set the MACsec block out of s/w reset and enable clocks */
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_ENA_CFG,
++				 MSCC_MS_ENA_CFG_CLK_ENA);
++
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_STATUS_CONTEXT_CTRL,
++				 bank == MACSEC_INGR ? 0xe5880214 : 0xe5880218);
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_MISC_CONTROL,
++				 MSCC_MS_MISC_CONTROL_MC_LATENCY_FIX(bank == MACSEC_INGR ? 57 : 40) |
++				 MSCC_MS_MISC_CONTROL_XFORM_REC_SIZE(bank == MACSEC_INGR ? 1 : 2));
++
++	/* Clear the counters */
++	val = vsc8584_macsec_phy_read(phydev, bank, MSCC_MS_COUNT_CONTROL);
++	val |= MSCC_MS_COUNT_CONTROL_AUTO_CNTR_RESET;
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_COUNT_CONTROL, val);
++
++	/* Enable octet increment mode */
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_PP_CTRL,
++				 MSCC_MS_PP_CTRL_MACSEC_OCTET_INCR_MODE);
++
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_BLOCK_CTX_UPDATE, 0x3);
++
++	val = vsc8584_macsec_phy_read(phydev, bank, MSCC_MS_COUNT_CONTROL);
++	val |= MSCC_MS_COUNT_CONTROL_RESET_ALL;
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_COUNT_CONTROL, val);
++
++	/* Set the MTU */
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_NON_VLAN_MTU_CHECK,
++				 MSCC_MS_NON_VLAN_MTU_CHECK_NV_MTU_COMPARE(32761) |
++				 MSCC_MS_NON_VLAN_MTU_CHECK_NV_MTU_COMP_DROP);
++
++	for (i = 0; i < 8; i++)
++		vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_VLAN_MTU_CHECK(i),
++					 MSCC_MS_VLAN_MTU_CHECK_MTU_COMPARE(32761) |
++					 MSCC_MS_VLAN_MTU_CHECK_MTU_COMP_DROP);
++
++	if (bank == MACSEC_EGR) {
++		val = vsc8584_macsec_phy_read(phydev, bank, MSCC_MS_INTR_CTRL_STATUS);
++		val &= ~MSCC_MS_INTR_CTRL_STATUS_INTR_ENABLE_M;
++		vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_INTR_CTRL_STATUS, val);
++
++		vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_FC_CFG,
++					 MSCC_MS_FC_CFG_FCBUF_ENA |
++					 MSCC_MS_FC_CFG_LOW_THRESH(0x1) |
++					 MSCC_MS_FC_CFG_HIGH_THRESH(0x4) |
++					 MSCC_MS_FC_CFG_LOW_BYTES_VAL(0x4) |
++					 MSCC_MS_FC_CFG_HIGH_BYTES_VAL(0x6));
++	}
++
++	vsc8584_macsec_classification(phydev, bank);
++	vsc8584_macsec_flow_default_action(phydev, bank, false);
++	vsc8584_macsec_integrity_checks(phydev, bank);
++
++	/* Enable the MACsec block */
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_ENA_CFG,
++				 MSCC_MS_ENA_CFG_CLK_ENA |
++				 MSCC_MS_ENA_CFG_MACSEC_ENA |
++				 MSCC_MS_ENA_CFG_MACSEC_SPEED_MODE(0x5));
++}
++
++static void vsc8584_macsec_mac_init(struct phy_device *phydev,
++				    enum macsec_bank bank)
++{
++	u32 val;
++	int i;
++
++	/* Clear host & line stats */
++	for (i = 0; i < 36; i++)
++		vsc8584_macsec_phy_write(phydev, bank, 0x1c + i, 0);
++
++	val = vsc8584_macsec_phy_read(phydev, bank,
++				      MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL);
++	val &= ~MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_PAUSE_MODE_M;
++	val |= MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_PAUSE_MODE(2) |
++	       MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_PAUSE_VALUE(0xffff);
++	vsc8584_macsec_phy_write(phydev, bank,
++				 MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL, val);
++
++	val = vsc8584_macsec_phy_read(phydev, bank,
++				      MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_2);
++	val |= 0xffff;
++	vsc8584_macsec_phy_write(phydev, bank,
++				 MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_2, val);
++
++	val = vsc8584_macsec_phy_read(phydev, bank,
++				      MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL);
++	if (bank == HOST_MAC)
++		val |= MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_PAUSE_TIMER_ENA |
++		       MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_PAUSE_FRAME_DROP_ENA;
++	else
++		val |= MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_PAUSE_REACT_ENA |
++		       MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_PAUSE_FRAME_DROP_ENA |
++		       MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_PAUSE_MODE |
++		       MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_EARLY_PAUSE_DETECT_ENA;
++	vsc8584_macsec_phy_write(phydev, bank,
++				 MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL, val);
++
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MAC_CFG_PKTINF_CFG,
++				 MSCC_MAC_CFG_PKTINF_CFG_STRIP_FCS_ENA |
++				 MSCC_MAC_CFG_PKTINF_CFG_INSERT_FCS_ENA |
++				 MSCC_MAC_CFG_PKTINF_CFG_LPI_RELAY_ENA |
++				 MSCC_MAC_CFG_PKTINF_CFG_STRIP_PREAMBLE_ENA |
++				 MSCC_MAC_CFG_PKTINF_CFG_INSERT_PREAMBLE_ENA |
++				 (bank == HOST_MAC ?
++				  MSCC_MAC_CFG_PKTINF_CFG_ENABLE_TX_PADDING : 0));
++
++	val = vsc8584_macsec_phy_read(phydev, bank, MSCC_MAC_CFG_MODE_CFG);
++	val &= ~MSCC_MAC_CFG_MODE_CFG_DISABLE_DIC;
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MAC_CFG_MODE_CFG, val);
++
++	val = vsc8584_macsec_phy_read(phydev, bank, MSCC_MAC_CFG_MAXLEN_CFG);
++	val &= ~MSCC_MAC_CFG_MAXLEN_CFG_MAX_LEN_M;
++	val |= MSCC_MAC_CFG_MAXLEN_CFG_MAX_LEN(10240);
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MAC_CFG_MAXLEN_CFG, val);
++
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MAC_CFG_ADV_CHK_CFG,
++				 MSCC_MAC_CFG_ADV_CHK_CFG_SFD_CHK_ENA |
++				 MSCC_MAC_CFG_ADV_CHK_CFG_PRM_CHK_ENA |
++				 MSCC_MAC_CFG_ADV_CHK_CFG_OOR_ERR_ENA |
++				 MSCC_MAC_CFG_ADV_CHK_CFG_INR_ERR_ENA);
++
++	val = vsc8584_macsec_phy_read(phydev, bank, MSCC_MAC_CFG_LFS_CFG);
++	val &= ~MSCC_MAC_CFG_LFS_CFG_LFS_MODE_ENA;
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MAC_CFG_LFS_CFG, val);
++
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MAC_CFG_ENA_CFG,
++				 MSCC_MAC_CFG_ENA_CFG_RX_CLK_ENA |
++				 MSCC_MAC_CFG_ENA_CFG_TX_CLK_ENA |
++				 MSCC_MAC_CFG_ENA_CFG_RX_ENA |
++				 MSCC_MAC_CFG_ENA_CFG_TX_ENA);
++}
++
++/* Must be called with mdio_lock taken */
++static int vsc8584_macsec_init(struct phy_device *phydev)
++{
++	u32 val;
++
++	vsc8584_macsec_block_init(phydev, MACSEC_INGR);
++	vsc8584_macsec_block_init(phydev, MACSEC_EGR);
++	vsc8584_macsec_mac_init(phydev, HOST_MAC);
++	vsc8584_macsec_mac_init(phydev, LINE_MAC);
++
++	vsc8584_macsec_phy_write(phydev, FC_BUFFER,
++				 MSCC_FCBUF_FC_READ_THRESH_CFG,
++				 MSCC_FCBUF_FC_READ_THRESH_CFG_TX_THRESH(4) |
++				 MSCC_FCBUF_FC_READ_THRESH_CFG_RX_THRESH(5));
++
++	val = vsc8584_macsec_phy_read(phydev, FC_BUFFER, MSCC_FCBUF_MODE_CFG);
++	val |= MSCC_FCBUF_MODE_CFG_PAUSE_GEN_ENA |
++	       MSCC_FCBUF_MODE_CFG_RX_PPM_RATE_ADAPT_ENA |
++	       MSCC_FCBUF_MODE_CFG_TX_PPM_RATE_ADAPT_ENA;
++	vsc8584_macsec_phy_write(phydev, FC_BUFFER, MSCC_FCBUF_MODE_CFG, val);
++
++	vsc8584_macsec_phy_write(phydev, FC_BUFFER, MSCC_FCBUF_PPM_RATE_ADAPT_THRESH_CFG,
++				 MSCC_FCBUF_PPM_RATE_ADAPT_THRESH_CFG_TX_THRESH(8) |
++				 MSCC_FCBUF_PPM_RATE_ADAPT_THRESH_CFG_TX_OFFSET(9));
++
++	val = vsc8584_macsec_phy_read(phydev, FC_BUFFER,
++				      MSCC_FCBUF_TX_DATA_QUEUE_CFG);
++	val &= ~(MSCC_FCBUF_TX_DATA_QUEUE_CFG_START_M |
++		 MSCC_FCBUF_TX_DATA_QUEUE_CFG_END_M);
++	val |= MSCC_FCBUF_TX_DATA_QUEUE_CFG_START(0) |
++		MSCC_FCBUF_TX_DATA_QUEUE_CFG_END(5119);
++	vsc8584_macsec_phy_write(phydev, FC_BUFFER,
++				 MSCC_FCBUF_TX_DATA_QUEUE_CFG, val);
++
++	val = vsc8584_macsec_phy_read(phydev, FC_BUFFER, MSCC_FCBUF_ENA_CFG);
++	val |= MSCC_FCBUF_ENA_CFG_TX_ENA | MSCC_FCBUF_ENA_CFG_RX_ENA;
++	vsc8584_macsec_phy_write(phydev, FC_BUFFER, MSCC_FCBUF_ENA_CFG, val);
++
++	val = vsc8584_macsec_phy_read(phydev, IP_1588,
++				      MSCC_PROC_0_IP_1588_TOP_CFG_STAT_MODE_CTL);
++	val &= ~MSCC_PROC_0_IP_1588_TOP_CFG_STAT_MODE_CTL_PROTOCOL_MODE_M;
++	val |= MSCC_PROC_0_IP_1588_TOP_CFG_STAT_MODE_CTL_PROTOCOL_MODE(4);
++	vsc8584_macsec_phy_write(phydev, IP_1588,
++				 MSCC_PROC_0_IP_1588_TOP_CFG_STAT_MODE_CTL, val);
++
++	return 0;
++}
++#endif /* CONFIG_MACSEC */
++
+ /* Check if one PHY has already done the init of the parts common to all PHYs
+  * in the Quad PHY package.
+  */
+@@ -1733,6 +2102,19 @@ static int vsc8584_config_init(struct phy_device *phydev)
+ 
+ 	mutex_unlock(&phydev->mdio.bus->mdio_lock);
+ 
++#if IS_ENABLED(CONFIG_MACSEC)
++	/* MACsec */
++	switch (phydev->phy_id & phydev->drv->phy_id_mask) {
++	case PHY_ID_VSC856X:
++	case PHY_ID_VSC8575:
++	case PHY_ID_VSC8582:
++	case PHY_ID_VSC8584:
++		ret = vsc8584_macsec_init(phydev);
++		if (ret)
++			goto err;
++	}
++#endif
++
+ 	phy_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
+ 
+ 	val = phy_read(phydev, MSCC_PHY_EXT_PHY_CNTL_1);
+diff --git a/drivers/net/phy/mscc_fc_buffer.h b/drivers/net/phy/mscc_fc_buffer.h
+new file mode 100644
+index 0000000000000..7e9c0e8778952
+--- /dev/null
++++ b/drivers/net/phy/mscc_fc_buffer.h
+@@ -0,0 +1,64 @@
++/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
++/*
++ * Microsemi Ocelot Switch driver
++ *
++ * Copyright (C) 2019 Microsemi Corporation
++ */
++
++#ifndef _MSCC_OCELOT_FC_BUFFER_H_
++#define _MSCC_OCELOT_FC_BUFFER_H_
++
++#define MSCC_FCBUF_ENA_CFG					0x00
++#define MSCC_FCBUF_MODE_CFG					0x01
++#define MSCC_FCBUF_PPM_RATE_ADAPT_THRESH_CFG			0x02
++#define MSCC_FCBUF_TX_CTRL_QUEUE_CFG				0x03
++#define MSCC_FCBUF_TX_DATA_QUEUE_CFG				0x04
++#define MSCC_FCBUF_RX_DATA_QUEUE_CFG				0x05
++#define MSCC_FCBUF_TX_BUFF_XON_XOFF_THRESH_CFG			0x06
++#define MSCC_FCBUF_FC_READ_THRESH_CFG				0x07
++#define MSCC_FCBUF_TX_FRM_GAP_COMP				0x08
++
++#define MSCC_FCBUF_ENA_CFG_TX_ENA				BIT(0)
++#define MSCC_FCBUF_ENA_CFG_RX_ENA				BIT(4)
++
++#define MSCC_FCBUF_MODE_CFG_DROP_BEHAVIOUR			BIT(4)
++#define MSCC_FCBUF_MODE_CFG_PAUSE_REACT_ENA			BIT(8)
++#define MSCC_FCBUF_MODE_CFG_RX_PPM_RATE_ADAPT_ENA		BIT(12)
++#define MSCC_FCBUF_MODE_CFG_TX_PPM_RATE_ADAPT_ENA		BIT(16)
++#define MSCC_FCBUF_MODE_CFG_TX_CTRL_QUEUE_ENA			BIT(20)
++#define MSCC_FCBUF_MODE_CFG_PAUSE_GEN_ENA			BIT(24)
++#define MSCC_FCBUF_MODE_CFG_INCLUDE_PAUSE_RCVD_IN_PAUSE_GEN	BIT(28)
++
++#define MSCC_FCBUF_PPM_RATE_ADAPT_THRESH_CFG_TX_THRESH(x)	(x)
++#define MSCC_FCBUF_PPM_RATE_ADAPT_THRESH_CFG_TX_THRESH_M	GENMASK(15, 0)
++#define MSCC_FCBUF_PPM_RATE_ADAPT_THRESH_CFG_TX_OFFSET(x)	((x) << 16)
++#define MSCC_FCBUF_PPM_RATE_ADAPT_THRESH_CFG_TX_OFFSET_M	GENMASK(19, 16)
++#define MSCC_FCBUF_PPM_RATE_ADAPT_THRESH_CFG_RX_THRESH(x)	((x) << 20)
++#define MSCC_FCBUF_PPM_RATE_ADAPT_THRESH_CFG_RX_THRESH_M	GENMASK(31, 20)
++
++#define MSCC_FCBUF_TX_CTRL_QUEUE_CFG_START(x)			(x)
++#define MSCC_FCBUF_TX_CTRL_QUEUE_CFG_START_M			GENMASK(15, 0)
++#define MSCC_FCBUF_TX_CTRL_QUEUE_CFG_END(x)			((x) << 16)
++#define MSCC_FCBUF_TX_CTRL_QUEUE_CFG_END_M			GENMASK(31, 16)
++
++#define MSCC_FCBUF_TX_DATA_QUEUE_CFG_START(x)			(x)
++#define MSCC_FCBUF_TX_DATA_QUEUE_CFG_START_M			GENMASK(15, 0)
++#define MSCC_FCBUF_TX_DATA_QUEUE_CFG_END(x)			((x) << 16)
++#define MSCC_FCBUF_TX_DATA_QUEUE_CFG_END_M			GENMASK(31, 16)
++
++#define MSCC_FCBUF_RX_DATA_QUEUE_CFG_START(x)			(x)
++#define MSCC_FCBUF_RX_DATA_QUEUE_CFG_START_M			GENMASK(15, 0)
++#define MSCC_FCBUF_RX_DATA_QUEUE_CFG_END(x)			((x) << 16)
++#define MSCC_FCBUF_RX_DATA_QUEUE_CFG_END_M			GENMASK(31, 16)
++
++#define MSCC_FCBUF_TX_BUFF_XON_XOFF_THRESH_CFG_XOFF_THRESH(x)	(x)
++#define MSCC_FCBUF_TX_BUFF_XON_XOFF_THRESH_CFG_XOFF_THRESH_M	GENMASK(15, 0)
++#define MSCC_FCBUF_TX_BUFF_XON_XOFF_THRESH_CFG_XON_THRESH(x)	((x) << 16)
++#define MSCC_FCBUF_TX_BUFF_XON_XOFF_THRESH_CFG_XON_THRESH_M	GENMASK(31, 16)
++
++#define MSCC_FCBUF_FC_READ_THRESH_CFG_TX_THRESH(x)		(x)
++#define MSCC_FCBUF_FC_READ_THRESH_CFG_TX_THRESH_M		GENMASK(15, 0)
++#define MSCC_FCBUF_FC_READ_THRESH_CFG_RX_THRESH(x)		((x) << 16)
++#define MSCC_FCBUF_FC_READ_THRESH_CFG_RX_THRESH_M		GENMASK(31, 16)
++
++#endif
+diff --git a/drivers/net/phy/mscc_mac.h b/drivers/net/phy/mscc_mac.h
+new file mode 100644
+index 0000000000000..9420ee5175a61
+--- /dev/null
++++ b/drivers/net/phy/mscc_mac.h
+@@ -0,0 +1,159 @@
++/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
++/*
++ * Microsemi Ocelot Switch driver
++ *
++ * Copyright (c) 2017 Microsemi Corporation
++ */
++
++#ifndef _MSCC_OCELOT_LINE_MAC_H_
++#define _MSCC_OCELOT_LINE_MAC_H_
++
++#define MSCC_MAC_CFG_ENA_CFG					0x00
++#define MSCC_MAC_CFG_MODE_CFG					0x01
++#define MSCC_MAC_CFG_MAXLEN_CFG					0x02
++#define MSCC_MAC_CFG_NUM_TAGS_CFG				0x03
++#define MSCC_MAC_CFG_TAGS_CFG					0x04
++#define MSCC_MAC_CFG_ADV_CHK_CFG				0x07
++#define MSCC_MAC_CFG_LFS_CFG					0x08
++#define MSCC_MAC_CFG_LB_CFG					0x09
++#define MSCC_MAC_CFG_PKTINF_CFG					0x0a
++#define MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL			0x0b
++#define MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_2			0x0c
++#define MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL			0x0d
++#define MSCC_MAC_PAUSE_CFG_STATE				0x0e
++#define MSCC_MAC_PAUSE_CFG_MAC_ADDRESS_LSB			0x0f
++#define MSCC_MAC_PAUSE_CFG_MAC_ADDRESS_MSB			0x10
++#define MSCC_MAC_STATUS_RX_LANE_STICKY_0			0x11
++#define MSCC_MAC_STATUS_RX_LANE_STICKY_1			0x12
++#define MSCC_MAC_STATUS_TX_MONITOR_STICKY			0x13
++#define MSCC_MAC_STATUS_TX_MONITOR_STICKY_MASK			0x14
++#define MSCC_MAC_STATUS_STICKY					0x15
++#define MSCC_MAC_STATUS_STICKY_MASK				0x16
++#define MSCC_MAC_STATS_32BIT_RX_HIH_CKSM_ERR_CNT		0x17
++#define MSCC_MAC_STATS_32BIT_RX_XGMII_PROT_ERR_CNT		0x18
++#define MSCC_MAC_STATS_32BIT_RX_SYMBOL_ERR_CNT			0x19
++#define MSCC_MAC_STATS_32BIT_RX_PAUSE_CNT			0x1a
++#define MSCC_MAC_STATS_32BIT_RX_UNSUP_OPCODE_CNT		0x1b
++#define MSCC_MAC_STATS_32BIT_RX_UC_CNT				0x1c
++#define MSCC_MAC_STATS_32BIT_RX_MC_CNT				0x1d
++#define MSCC_MAC_STATS_32BIT_RX_BC_CNT				0x1e
++#define MSCC_MAC_STATS_32BIT_RX_CRC_ERR_CNT			0x1f
++#define MSCC_MAC_STATS_32BIT_RX_UNDERSIZE_CNT			0x20
++#define MSCC_MAC_STATS_32BIT_RX_FRAGMENTS_CNT			0x21
++#define MSCC_MAC_STATS_32BIT_RX_IN_RANGE_LEN_ERR_CNT		0x22
++#define MSCC_MAC_STATS_32BIT_RX_OUT_OF_RANGE_LEN_ERR_CNT	0x23
++#define MSCC_MAC_STATS_32BIT_RX_OVERSIZE_CNT			0x24
++#define MSCC_MAC_STATS_32BIT_RX_JABBERS_CNT			0x25
++#define MSCC_MAC_STATS_32BIT_RX_SIZE64_CNT			0x26
++#define MSCC_MAC_STATS_32BIT_RX_SIZE65TO127_CNT			0x27
++#define MSCC_MAC_STATS_32BIT_RX_SIZE128TO255_CNT		0x28
++#define MSCC_MAC_STATS_32BIT_RX_SIZE256TO511_CNT		0x29
++#define MSCC_MAC_STATS_32BIT_RX_SIZE512TO1023_CNT		0x2a
++#define MSCC_MAC_STATS_32BIT_RX_SIZE1024TO1518_CNT		0x2b
++#define MSCC_MAC_STATS_32BIT_RX_SIZE1519TOMAX_CNT		0x2c
++#define MSCC_MAC_STATS_32BIT_RX_IPG_SHRINK_CNT			0x2d
++#define MSCC_MAC_STATS_32BIT_TX_PAUSE_CNT			0x2e
++#define MSCC_MAC_STATS_32BIT_TX_UC_CNT				0x2f
++#define MSCC_MAC_STATS_32BIT_TX_MC_CNT				0x30
++#define MSCC_MAC_STATS_32BIT_TX_BC_CNT				0x31
++#define MSCC_MAC_STATS_32BIT_TX_SIZE64_CNT			0x32
++#define MSCC_MAC_STATS_32BIT_TX_SIZE65TO127_CNT			0x33
++#define MSCC_MAC_STATS_32BIT_TX_SIZE128TO255_CNT		0x34
++#define MSCC_MAC_STATS_32BIT_TX_SIZE256TO511_CNT		0x35
++#define MSCC_MAC_STATS_32BIT_TX_SIZE512TO1023_CNT		0x36
++#define MSCC_MAC_STATS_32BIT_TX_SIZE1024TO1518_CNT		0x37
++#define MSCC_MAC_STATS_32BIT_TX_SIZE1519TOMAX_CNT		0x38
++#define MSCC_MAC_STATS_40BIT_RX_BAD_BYTES_CNT			0x39
++#define MSCC_MAC_STATS_40BIT_RX_BAD_BYTES_MSB_CNT		0x3a
++#define MSCC_MAC_STATS_40BIT_RX_OK_BYTES_CNT			0x3b
++#define MSCC_MAC_STATS_40BIT_RX_OK_BYTES_MSB_CNT		0x3c
++#define MSCC_MAC_STATS_40BIT_RX_IN_BYTES_CNT			0x3d
++#define MSCC_MAC_STATS_40BIT_RX_IN_BYTES_MSB_CNT		0x3e
++#define MSCC_MAC_STATS_40BIT_TX_OK_BYTES_CNT			0x3f
++#define MSCC_MAC_STATS_40BIT_TX_OK_BYTES_MSB_CNT		0x40
++#define MSCC_MAC_STATS_40BIT_TX_OUT_BYTES_CNT			0x41
++#define MSCC_MAC_STATS_40BIT_TX_OUT_BYTES_MSB_CNT		0x42
++
++#define MSCC_MAC_CFG_ENA_CFG_RX_CLK_ENA				BIT(0)
++#define MSCC_MAC_CFG_ENA_CFG_TX_CLK_ENA				BIT(4)
++#define MSCC_MAC_CFG_ENA_CFG_RX_SW_RST				BIT(8)
++#define MSCC_MAC_CFG_ENA_CFG_TX_SW_RST				BIT(12)
++#define MSCC_MAC_CFG_ENA_CFG_RX_ENA				BIT(16)
++#define MSCC_MAC_CFG_ENA_CFG_TX_ENA				BIT(20)
++
++#define MSCC_MAC_CFG_MODE_CFG_FORCE_CW_UPDATE_INTERVAL(x)	((x) << 20)
++#define MSCC_MAC_CFG_MODE_CFG_FORCE_CW_UPDATE_INTERVAL_M	GENMASK(29, 20)
++#define MSCC_MAC_CFG_MODE_CFG_FORCE_CW_UPDATE			BIT(16)
++#define MSCC_MAC_CFG_MODE_CFG_TUNNEL_PAUSE_FRAMES		BIT(14)
++#define MSCC_MAC_CFG_MODE_CFG_MAC_PREAMBLE_CFG(x)		((x) << 10)
++#define MSCC_MAC_CFG_MODE_CFG_MAC_PREAMBLE_CFG_M		GENMASK(12, 10)
++#define MSCC_MAC_CFG_MODE_CFG_MAC_IPG_CFG			BIT(6)
++#define MSCC_MAC_CFG_MODE_CFG_XGMII_GEN_MODE_ENA		BIT(4)
++#define MSCC_MAC_CFG_MODE_CFG_HIH_CRC_CHECK			BIT(2)
++#define MSCC_MAC_CFG_MODE_CFG_UNDERSIZED_FRAME_DROP_DIS		BIT(1)
++#define MSCC_MAC_CFG_MODE_CFG_DISABLE_DIC			BIT(0)
++
++#define MSCC_MAC_CFG_MAXLEN_CFG_MAX_LEN_TAG_CHK			BIT(16)
++#define MSCC_MAC_CFG_MAXLEN_CFG_MAX_LEN(x)			(x)
++#define MSCC_MAC_CFG_MAXLEN_CFG_MAX_LEN_M			GENMASK(15, 0)
++
++#define MSCC_MAC_CFG_TAGS_CFG_RSZ				0x4
++#define MSCC_MAC_CFG_TAGS_CFG_TAG_ID(x)				((x) << 16)
++#define MSCC_MAC_CFG_TAGS_CFG_TAG_ID_M				GENMASK(31, 16)
++#define MSCC_MAC_CFG_TAGS_CFG_TAG_ENA				BIT(4)
++
++#define MSCC_MAC_CFG_ADV_CHK_CFG_EXT_EOP_CHK_ENA		BIT(24)
++#define MSCC_MAC_CFG_ADV_CHK_CFG_EXT_SOP_CHK_ENA		BIT(20)
++#define MSCC_MAC_CFG_ADV_CHK_CFG_SFD_CHK_ENA			BIT(16)
++#define MSCC_MAC_CFG_ADV_CHK_CFG_PRM_SHK_CHK_DIS		BIT(12)
++#define MSCC_MAC_CFG_ADV_CHK_CFG_PRM_CHK_ENA			BIT(8)
++#define MSCC_MAC_CFG_ADV_CHK_CFG_OOR_ERR_ENA			BIT(4)
++#define MSCC_MAC_CFG_ADV_CHK_CFG_INR_ERR_ENA			BIT(0)
++
++#define MSCC_MAC_CFG_LFS_CFG_LFS_INH_TX				BIT(8)
++#define MSCC_MAC_CFG_LFS_CFG_LFS_DIS_TX				BIT(4)
++#define MSCC_MAC_CFG_LFS_CFG_LFS_UNIDIR_ENA			BIT(3)
++#define MSCC_MAC_CFG_LFS_CFG_USE_LEADING_EDGE_DETECT		BIT(2)
++#define MSCC_MAC_CFG_LFS_CFG_SPURIOUS_Q_DIS			BIT(1)
++#define MSCC_MAC_CFG_LFS_CFG_LFS_MODE_ENA			BIT(0)
++
++#define MSCC_MAC_CFG_LB_CFG_XGMII_HOST_LB_ENA			BIT(4)
++#define MSCC_MAC_CFG_LB_CFG_XGMII_PHY_LB_ENA			BIT(0)
++
++#define MSCC_MAC_CFG_PKTINF_CFG_STRIP_FCS_ENA			BIT(0)
++#define MSCC_MAC_CFG_PKTINF_CFG_INSERT_FCS_ENA			BIT(4)
++#define MSCC_MAC_CFG_PKTINF_CFG_STRIP_PREAMBLE_ENA		BIT(8)
++#define MSCC_MAC_CFG_PKTINF_CFG_INSERT_PREAMBLE_ENA		BIT(12)
++#define MSCC_MAC_CFG_PKTINF_CFG_LPI_RELAY_ENA			BIT(16)
++#define MSCC_MAC_CFG_PKTINF_CFG_LF_RELAY_ENA			BIT(20)
++#define MSCC_MAC_CFG_PKTINF_CFG_RF_RELAY_ENA			BIT(24)
++#define MSCC_MAC_CFG_PKTINF_CFG_ENABLE_TX_PADDING		BIT(25)
++#define MSCC_MAC_CFG_PKTINF_CFG_ENABLE_RX_PADDING		BIT(26)
++#define MSCC_MAC_CFG_PKTINF_CFG_ENABLE_4BYTE_PREAMBLE		BIT(27)
++#define MSCC_MAC_CFG_PKTINF_CFG_MACSEC_BYPASS_NUM_PTP_STALL_CLKS(x)	((x) << 28)
++#define MSCC_MAC_CFG_PKTINF_CFG_MACSEC_BYPASS_NUM_PTP_STALL_CLKS_M	GENMASK(30, 28)
++
++#define MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_PAUSE_VALUE(x)		((x) << 16)
++#define MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_PAUSE_VALUE_M		GENMASK(31, 16)
++#define MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_WAIT_FOR_LPI_LOW	BIT(12)
++#define MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_USE_PAUSE_STALL_ENA	BIT(8)
++#define MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_PAUSE_REPL_MODE	BIT(4)
++#define MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_PAUSE_FRC_FRAME	BIT(2)
++#define MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_PAUSE_MODE(x)		(x)
++#define MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_PAUSE_MODE_M		GENMASK(1, 0)
++
++#define MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_EARLY_PAUSE_DETECT_ENA	BIT(16)
++#define MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_PRE_CRC_MODE		BIT(20)
++#define MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_PAUSE_TIMER_ENA	BIT(12)
++#define MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_PAUSE_REACT_ENA	BIT(8)
++#define MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_PAUSE_FRAME_DROP_ENA	BIT(4)
++#define MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_PAUSE_MODE		BIT(0)
++
++#define MSCC_MAC_PAUSE_CFG_STATE_PAUSE_STATE			BIT(0)
++#define MSCC_MAC_PAUSE_CFG_STATE_MAC_TX_PAUSE_GEN		BIT(4)
++
++#define MSCC_PROC_0_IP_1588_TOP_CFG_STAT_MODE_CTL			0x2
++#define MSCC_PROC_0_IP_1588_TOP_CFG_STAT_MODE_CTL_PROTOCOL_MODE(x)	(x)
++#define MSCC_PROC_0_IP_1588_TOP_CFG_STAT_MODE_CTL_PROTOCOL_MODE_M	GENMASK(2, 0)
++
++#endif /* _MSCC_OCELOT_LINE_MAC_H_ */
+diff --git a/drivers/net/phy/mscc_macsec.h b/drivers/net/phy/mscc_macsec.h
+new file mode 100644
+index 0000000000000..0d108da28dad2
+--- /dev/null
++++ b/drivers/net/phy/mscc_macsec.h
+@@ -0,0 +1,260 @@
++/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
++/*
++ * Microsemi Ocelot Switch driver
++ *
++ * Copyright (c) 2018 Microsemi Corporation
++ */
++
++#ifndef _MSCC_OCELOT_MACSEC_H_
++#define _MSCC_OCELOT_MACSEC_H_
++
++#define CONTROL_TYPE_EGRESS		0x6
++#define CONTROL_TYPE_INGRESS		0xf
++#define CONTROL_IV0			BIT(5)
++#define CONTROL_IV1			BIT(6)
++#define CONTROL_IV2			BIT(7)
++#define CONTROL_UPDATE_SEQ		BIT(13)
++#define CONTROL_IV_IN_SEQ		BIT(14)
++#define CONTROL_ENCRYPT_AUTH		BIT(15)
++#define CONTROL_KEY_IN_CTX		BIT(16)
++#define CONTROL_CRYPTO_ALG(x)		((x) << 17)
++#define     CTRYPTO_ALG_AES_CTR_128	0x5
++#define     CTRYPTO_ALG_AES_CTR_192	0x6
++#define     CTRYPTO_ALG_AES_CTR_256	0x7
++#define CONTROL_DIGEST_TYPE(x)		((x) << 21)
++#define CONTROL_AUTH_ALG(x)		((x) << 23)
++#define     AUTH_ALG_AES_GHAS		0x4
++#define CONTROL_AN(x)			((x) << 26)
++#define CONTROL_SEQ_TYPE(x)		((x) << 28)
++#define CONTROL_SEQ_MASK		BIT(30)
++#define CONTROL_CONTEXT_ID		BIT(31)
++
++enum mscc_macsec_destination_ports {
++	MSCC_MS_PORT_COMMON		= 0,
++	MSCC_MS_PORT_RSVD		= 1,
++	MSCC_MS_PORT_CONTROLLED		= 2,
++	MSCC_MS_PORT_UNCONTROLLED	= 3,
++};
++
++enum mscc_macsec_drop_actions {
++	MSCC_MS_ACTION_BYPASS_CRC	= 0,
++	MSCC_MS_ACTION_BYPASS_BAD	= 1,
++	MSCC_MS_ACTION_DROP		= 2,
++	MSCC_MS_ACTION_BYPASS		= 3,
++};
++
++enum mscc_macsec_flow_types {
++	MSCC_MS_FLOW_BYPASS		= 0,
++	MSCC_MS_FLOW_DROP		= 1,
++	MSCC_MS_FLOW_INGRESS		= 2,
++	MSCC_MS_FLOW_EGRESS		= 3,
++};
++
++enum mscc_macsec_validate_levels {
++	MSCC_MS_VALIDATE_DISABLED	= 0,
++	MSCC_MS_VALIDATE_CHECK		= 1,
++	MSCC_MS_VALIDATE_STRICT		= 2,
++};
++
++#define MSCC_MS_XFORM_REC(x, y)		(((x) << 5) + (y))
++#define MSCC_MS_ENA_CFG			0x800
++#define MSCC_MS_FC_CFG			0x804
++#define MSCC_MS_SAM_MISC_MATCH(x)	(0x1004 + ((x) << 4))
++#define MSCC_MS_SAM_MATCH_SCI_LO(x)	(0x1005 + ((x) << 4))
++#define MSCC_MS_SAM_MATCH_SCI_HI(x)	(0x1006 + ((x) << 4))
++#define MSCC_MS_SAM_MASK(x)		(0x1007 + ((x) << 4))
++#define MSCC_MS_SAM_ENTRY_SET1		0x1808
++#define MSCC_MS_SAM_ENTRY_CLEAR1	0x180c
++#define MSCC_MS_SAM_FLOW_CTRL(x)	(0x1c00 + (x))
++#define MSCC_MS_SAM_CP_TAG		0x1e40
++#define MSCC_MS_SAM_NM_FLOW_NCP		0x1e51
++#define MSCC_MS_SAM_NM_FLOW_CP		0x1e52
++#define MSCC_MS_MISC_CONTROL		0x1e5f
++#define MSCC_MS_COUNT_CONTROL		0x3204
++#define MSCC_MS_PARAMS2_IG_CC_CONTROL	0x3a10
++#define MSCC_MS_PARAMS2_IG_CP_TAG	0x3a14
++#define MSCC_MS_VLAN_MTU_CHECK(x)	(0x3c40 + (x))
++#define MSCC_MS_NON_VLAN_MTU_CHECK	0x3c48
++#define MSCC_MS_PP_CTRL			0x3c4b
++#define MSCC_MS_STATUS_CONTEXT_CTRL	0x3d02
++#define MSCC_MS_INTR_CTRL_STATUS	0x3d04
++#define MSCC_MS_BLOCK_CTX_UPDATE	0x3d0c
++
++/* MACSEC_ENA_CFG */
++#define MSCC_MS_ENA_CFG_CLK_ENA				BIT(0)
++#define MSCC_MS_ENA_CFG_SW_RST				BIT(1)
++#define MSCC_MS_ENA_CFG_MACSEC_BYPASS_ENA		BIT(8)
++#define MSCC_MS_ENA_CFG_MACSEC_ENA			BIT(9)
++#define MSCC_MS_ENA_CFG_MACSEC_SPEED_MODE(x)		((x) << 10)
++#define MSCC_MS_ENA_CFG_MACSEC_SPEED_MODE_M		GENMASK(12, 10)
++
++/* MACSEC_FC_CFG */
++#define MSCC_MS_FC_CFG_FCBUF_ENA			BIT(0)
++#define MSCC_MS_FC_CFG_USE_PKT_EXPANSION_INDICATION	BIT(1)
++#define MSCC_MS_FC_CFG_LOW_THRESH(x)			((x) << 4)
++#define MSCC_MS_FC_CFG_LOW_THRESH_M			GENMASK(7, 4)
++#define MSCC_MS_FC_CFG_HIGH_THRESH(x)			((x) << 8)
++#define MSCC_MS_FC_CFG_HIGH_THRESH_M			GENMASK(11, 8)
++#define MSCC_MS_FC_CFG_LOW_BYTES_VAL(x)			((x) << 12)
++#define MSCC_MS_FC_CFG_LOW_BYTES_VAL_M			GENMASK(14, 12)
++#define MSCC_MS_FC_CFG_HIGH_BYTES_VAL(x)		((x) << 16)
++#define MSCC_MS_FC_CFG_HIGH_BYTES_VAL_M			GENMASK(18, 16)
++
++/* MSCC_MS_SAM_MAC_SA_MATCH_HI */
++#define MSCC_MS_SAM_MAC_SA_MATCH_HI_ETYPE(x)		((x) << 16)
++#define MSCC_MS_SAM_MAC_SA_MATCH_HI_ETYPE_M		GENMASK(31, 16)
++
++/* MACSEC_SAM_MISC_MATCH */
++#define MSCC_MS_SAM_MISC_MATCH_VLAN_VALID		BIT(0)
++#define MSCC_MS_SAM_MISC_MATCH_QINQ_FOUND		BIT(1)
++#define MSCC_MS_SAM_MISC_MATCH_STAG_VALID		BIT(2)
++#define MSCC_MS_SAM_MISC_MATCH_QTAG_VALID		BIT(3)
++#define MSCC_MS_SAM_MISC_MATCH_VLAN_UP(x)		((x) << 4)
++#define MSCC_MS_SAM_MISC_MATCH_VLAN_UP_M		GENMASK(6, 4)
++#define MSCC_MS_SAM_MISC_MATCH_CONTROL_PACKET		BIT(7)
++#define MSCC_MS_SAM_MISC_MATCH_UNTAGGED			BIT(8)
++#define MSCC_MS_SAM_MISC_MATCH_TAGGED			BIT(9)
++#define MSCC_MS_SAM_MISC_MATCH_BAD_TAG			BIT(10)
++#define MSCC_MS_SAM_MISC_MATCH_KAY_TAG			BIT(11)
++#define MSCC_MS_SAM_MISC_MATCH_SOURCE_PORT(x)		((x) << 12)
++#define MSCC_MS_SAM_MISC_MATCH_SOURCE_PORT_M		GENMASK(13, 12)
++#define MSCC_MS_SAM_MISC_MATCH_PRIORITY(x)		((x) << 16)
++#define MSCC_MS_SAM_MISC_MATCH_PRIORITY_M		GENMASK(19, 16)
++#define MSCC_MS_SAM_MISC_MATCH_AN(x)			((x) << 24)
++#define MSCC_MS_SAM_MISC_MATCH_TCI(x)			((x) << 26)
++
++/* MACSEC_SAM_MASK */
++#define MSCC_MS_SAM_MASK_MAC_SA_MASK(x)			(x)
++#define MSCC_MS_SAM_MASK_MAC_SA_MASK_M			GENMASK(5, 0)
++#define MSCC_MS_SAM_MASK_MAC_DA_MASK(x)			((x) << 6)
++#define MSCC_MS_SAM_MASK_MAC_DA_MASK_M			GENMASK(11, 6)
++#define MSCC_MS_SAM_MASK_MAC_ETYPE_MASK			BIT(12)
++#define MSCC_MS_SAM_MASK_VLAN_VLD_MASK			BIT(13)
++#define MSCC_MS_SAM_MASK_QINQ_FOUND_MASK		BIT(14)
++#define MSCC_MS_SAM_MASK_STAG_VLD_MASK			BIT(15)
++#define MSCC_MS_SAM_MASK_QTAG_VLD_MASK			BIT(16)
++#define MSCC_MS_SAM_MASK_VLAN_UP_MASK			BIT(17)
++#define MSCC_MS_SAM_MASK_VLAN_ID_MASK			BIT(18)
++#define MSCC_MS_SAM_MASK_SOURCE_PORT_MASK		BIT(19)
++#define MSCC_MS_SAM_MASK_CTL_PACKET_MASK		BIT(20)
++#define MSCC_MS_SAM_MASK_VLAN_UP_INNER_MASK		BIT(21)
++#define MSCC_MS_SAM_MASK_VLAN_ID_INNER_MASK		BIT(22)
++#define MSCC_MS_SAM_MASK_SCI_MASK			BIT(23)
++#define MSCC_MS_SAM_MASK_AN_MASK(x)			((x) << 24)
++#define MSCC_MS_SAM_MASK_TCI_MASK(x)			((x) << 26)
++
++/* MACSEC_SAM_FLOW_CTRL_EGR */
++#define MSCC_MS_SAM_FLOW_CTRL_FLOW_TYPE(x)		(x)
++#define MSCC_MS_SAM_FLOW_CTRL_FLOW_TYPE_M		GENMASK(1, 0)
++#define MSCC_MS_SAM_FLOW_CTRL_DEST_PORT(x)		((x) << 2)
++#define MSCC_MS_SAM_FLOW_CTRL_DEST_PORT_M		GENMASK(3, 2)
++#define MSCC_MS_SAM_FLOW_CTRL_RESV_4			BIT(4)
++#define MSCC_MS_SAM_FLOW_CTRL_FLOW_CRYPT_AUTH		BIT(5)
++#define MSCC_MS_SAM_FLOW_CTRL_DROP_ACTION(x)		((x) << 6)
++#define MSCC_MS_SAM_FLOW_CTRL_DROP_ACTION_M		GENMASK(7, 6)
++#define MSCC_MS_SAM_FLOW_CTRL_RESV_15_TO_8(x)		((x) << 8)
++#define MSCC_MS_SAM_FLOW_CTRL_RESV_15_TO_8_M		GENMASK(15, 8)
++#define MSCC_MS_SAM_FLOW_CTRL_PROTECT_FRAME		BIT(16)
++#define MSCC_MS_SAM_FLOW_CTRL_REPLAY_PROTECT		BIT(16)
++#define MSCC_MS_SAM_FLOW_CTRL_SA_IN_USE			BIT(17)
++#define MSCC_MS_SAM_FLOW_CTRL_INCLUDE_SCI		BIT(18)
++#define MSCC_MS_SAM_FLOW_CTRL_USE_ES			BIT(19)
++#define MSCC_MS_SAM_FLOW_CTRL_USE_SCB			BIT(20)
++#define MSCC_MS_SAM_FLOW_CTRL_VALIDATE_FRAMES(x)	((x) << 19)
++#define MSCC_MS_SAM_FLOW_CTRL_TAG_BYPASS_SIZE(x)	((x) << 21)
++#define MSCC_MS_SAM_FLOW_CTRL_TAG_BYPASS_SIZE_M		GENMASK(22, 21)
++#define MSCC_MS_SAM_FLOW_CTRL_RESV_23			BIT(23)
++#define MSCC_MS_SAM_FLOW_CTRL_CONFIDENTIALITY_OFFSET(x)	((x) << 24)
++#define MSCC_MS_SAM_FLOW_CTRL_CONFIDENTIALITY_OFFSET_M	GENMASK(30, 24)
++#define MSCC_MS_SAM_FLOW_CTRL_CONF_PROTECT		BIT(31)
++
++/* MACSEC_SAM_CP_TAG */
++#define MSCC_MS_SAM_CP_TAG_MAP_TBL(x)			(x)
++#define MSCC_MS_SAM_CP_TAG_MAP_TBL_M			GENMASK(23, 0)
++#define MSCC_MS_SAM_CP_TAG_DEF_UP(x)			((x) << 24)
++#define MSCC_MS_SAM_CP_TAG_DEF_UP_M			GENMASK(26, 24)
++#define MSCC_MS_SAM_CP_TAG_STAG_UP_EN			BIT(27)
++#define MSCC_MS_SAM_CP_TAG_QTAG_UP_EN			BIT(28)
++#define MSCC_MS_SAM_CP_TAG_PARSE_QINQ			BIT(29)
++#define MSCC_MS_SAM_CP_TAG_PARSE_STAG			BIT(30)
++#define MSCC_MS_SAM_CP_TAG_PARSE_QTAG			BIT(31)
++
++/* MACSEC_SAM_NM_FLOW_NCP */
++#define MSCC_MS_SAM_NM_FLOW_NCP_UNTAGGED_FLOW_TYPE(x)	(x)
++#define MSCC_MS_SAM_NM_FLOW_NCP_UNTAGGED_DEST_PORT(x)	((x) << 2)
++#define MSCC_MS_SAM_NM_FLOW_NCP_UNTAGGED_DROP_ACTION(x)	((x) << 6)
++#define MSCC_MS_SAM_NM_FLOW_NCP_TAGGED_FLOW_TYPE(x)	((x) << 8)
++#define MSCC_MS_SAM_NM_FLOW_NCP_TAGGED_DEST_PORT(x)	((x) << 10)
++#define MSCC_MS_SAM_NM_FLOW_NCP_TAGGED_DROP_ACTION(x)	((x) << 14)
++#define MSCC_MS_SAM_NM_FLOW_NCP_BADTAG_FLOW_TYPE(x)	((x) << 16)
++#define MSCC_MS_SAM_NM_FLOW_NCP_BADTAG_DEST_PORT(x)	((x) << 18)
++#define MSCC_MS_SAM_NM_FLOW_NCP_BADTAG_DROP_ACTION(x)	((x) << 22)
++#define MSCC_MS_SAM_NM_FLOW_NCP_KAY_FLOW_TYPE(x)	((x) << 24)
++#define MSCC_MS_SAM_NM_FLOW_NCP_KAY_DEST_PORT(x)	((x) << 26)
++#define MSCC_MS_SAM_NM_FLOW_NCP_KAY_DROP_ACTION(x)	((x) << 30)
++
++/* MACSEC_SAM_NM_FLOW_CP */
++#define MSCC_MS_SAM_NM_FLOW_CP_UNTAGGED_FLOW_TYPE(x)	(x)
++#define MSCC_MS_SAM_NM_FLOW_CP_UNTAGGED_DEST_PORT(x)	((x) << 2)
++#define MSCC_MS_SAM_NM_FLOW_CP_UNTAGGED_DROP_ACTION(x)	((x) << 6)
++#define MSCC_MS_SAM_NM_FLOW_CP_TAGGED_FLOW_TYPE(x)	((x) << 8)
++#define MSCC_MS_SAM_NM_FLOW_CP_TAGGED_DEST_PORT(x)	((x) << 10)
++#define MSCC_MS_SAM_NM_FLOW_CP_TAGGED_DROP_ACTION(x)	((x) << 14)
++#define MSCC_MS_SAM_NM_FLOW_CP_BADTAG_FLOW_TYPE(x)	((x) << 16)
++#define MSCC_MS_SAM_NM_FLOW_CP_BADTAG_DEST_PORT(x)	((x) << 18)
++#define MSCC_MS_SAM_NM_FLOW_CP_BADTAG_DROP_ACTION(x)	((x) << 22)
++#define MSCC_MS_SAM_NM_FLOW_CP_KAY_FLOW_TYPE(x)		((x) << 24)
++#define MSCC_MS_SAM_NM_FLOW_CP_KAY_DEST_PORT(x)		((x) << 26)
++#define MSCC_MS_SAM_NM_FLOW_CP_KAY_DROP_ACTION(x)	((x) << 30)
++
++/* MACSEC_MISC_CONTROL */
++#define MSCC_MS_MISC_CONTROL_MC_LATENCY_FIX(x)		(x)
++#define MSCC_MS_MISC_CONTROL_MC_LATENCY_FIX_M		GENMASK(5, 0)
++#define MSCC_MS_MISC_CONTROL_STATIC_BYPASS		BIT(8)
++#define MSCC_MS_MISC_CONTROL_NM_MACSEC_EN		BIT(9)
++#define MSCC_MS_MISC_CONTROL_VALIDATE_FRAMES(x)		((x) << 10)
++#define MSCC_MS_MISC_CONTROL_VALIDATE_FRAMES_M		GENMASK(11, 10)
++#define MSCC_MS_MISC_CONTROL_XFORM_REC_SIZE(x)		((x) << 24)
++#define MSCC_MS_MISC_CONTROL_XFORM_REC_SIZE_M		GENMASK(25, 24)
++
++/* MACSEC_COUNT_CONTROL */
++#define MSCC_MS_COUNT_CONTROL_RESET_ALL			BIT(0)
++#define MSCC_MS_COUNT_CONTROL_DEBUG_ACCESS		BIT(1)
++#define MSCC_MS_COUNT_CONTROL_SATURATE_CNTRS		BIT(2)
++#define MSCC_MS_COUNT_CONTROL_AUTO_CNTR_RESET		BIT(3)
++
++/* MACSEC_PARAMS2_IG_CC_CONTROL */
++#define MSCC_MS_PARAMS2_IG_CC_CONTROL_NON_MATCH_CTRL_ACT	BIT(14)
++#define MSCC_MS_PARAMS2_IG_CC_CONTROL_NON_MATCH_ACT	BIT(15)
++
++/* MACSEC_PARAMS2_IG_CP_TAG */
++#define MSCC_MS_PARAMS2_IG_CP_TAG_MAP_TBL(x)		(x)
++#define MSCC_MS_PARAMS2_IG_CP_TAG_MAP_TBL_M		GENMASK(23, 0)
++#define MSCC_MS_PARAMS2_IG_CP_TAG_DEF_UP(x)		((x) << 24)
++#define MSCC_MS_PARAMS2_IG_CP_TAG_DEF_UP_M		GENMASK(26, 24)
++#define MSCC_MS_PARAMS2_IG_CP_TAG_STAG_UP_EN		BIT(27)
++#define MSCC_MS_PARAMS2_IG_CP_TAG_QTAG_UP_EN		BIT(28)
++#define MSCC_MS_PARAMS2_IG_CP_TAG_PARSE_QINQ		BIT(29)
++#define MSCC_MS_PARAMS2_IG_CP_TAG_PARSE_STAG		BIT(30)
++#define MSCC_MS_PARAMS2_IG_CP_TAG_PARSE_QTAG		BIT(31)
++
++/* MACSEC_VLAN_MTU_CHECK */
++#define MSCC_MS_VLAN_MTU_CHECK_MTU_COMPARE(x)		(x)
++#define MSCC_MS_VLAN_MTU_CHECK_MTU_COMPARE_M		GENMASK(14, 0)
++#define MSCC_MS_VLAN_MTU_CHECK_MTU_COMP_DROP		BIT(15)
++
++/* MACSEC_NON_VLAN_MTU_CHECK */
++#define MSCC_MS_NON_VLAN_MTU_CHECK_NV_MTU_COMPARE(x)	(x)
++#define MSCC_MS_NON_VLAN_MTU_CHECK_NV_MTU_COMPARE_M	GENMASK(14, 0)
++#define MSCC_MS_NON_VLAN_MTU_CHECK_NV_MTU_COMP_DROP	BIT(15)
++
++/* MACSEC_PP_CTRL */
++#define MSCC_MS_PP_CTRL_MACSEC_OCTET_INCR_MODE		BIT(0)
++
++/* MACSEC_INTR_CTRL_STATUS */
++#define MSCC_MS_INTR_CTRL_STATUS_INTR_CLR_STATUS(x)	(x)
++#define MSCC_MS_INTR_CTRL_STATUS_INTR_CLR_STATUS_M	GENMASK(15, 0)
++#define MSCC_MS_INTR_CTRL_STATUS_INTR_ENABLE(x)		((x) << 16)
++#define MSCC_MS_INTR_CTRL_STATUS_INTR_ENABLE_M		GENMASK(31, 16)
++
++#endif
+-- 
+cgit 1.2.3-1.el7
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1758-08-v5.18-net-phy-mscc-macsec-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1758-08-v5.18-net-phy-mscc-macsec-support.patch
new file mode 100644
index 0000000..9c7ea17
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1758-08-v5.18-net-phy-mscc-macsec-support.patch
@@ -0,0 +1,786 @@
+From 28c5107aa904ef9db6b023039d20b6b4c4181675 Mon Sep 17 00:00:00 2001
+From: Antoine Tenart <antoine.tenart@bootlin.com>
+Date: Mon, 13 Jan 2020 23:31:46 +0100
+Subject: net: phy: mscc: macsec support
+
+This patch adds MACsec offloading support to some Microsemi PHYs, to
+configure flows and transformations so that matched packets can be
+processed by the MACsec engine, either at egress, or at ingress.
+
+Signed-off-by: Antoine Tenart <antoine.tenart@bootlin.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/phy/Kconfig       |   3 +
+ drivers/net/phy/mscc.c        | 691 ++++++++++++++++++++++++++++++++++++++++++
+ drivers/net/phy/mscc_macsec.h |   4 +
+ 3 files changed, 698 insertions(+)
+
+diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
+index 2e016271e1268..ac82ff959b7c0 100644
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -437,6 +437,9 @@ config MICROCHIP_T1_PHY
+ 
+ config MICROSEMI_PHY
+ 	tristate "Microsemi PHYs"
++	depends on MACSEC || MACSEC=n
++	select CRYPTO_AES
++	select CRYPTO_ECB
+ 	---help---
+ 	  Currently supports VSC8514, VSC8530, VSC8531, VSC8540 and VSC8541 PHYs
+ 
+diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c
+index 8579a59a1336a..ccf17818570f9 100644
+--- a/drivers/net/phy/mscc.c
++++ b/drivers/net/phy/mscc.c
+@@ -18,6 +18,13 @@
+ #include <linux/netdevice.h>
+ #include <dt-bindings/net/mscc-phy-vsc8531.h>
+ 
++#include <linux/scatterlist.h>
++#include <crypto/skcipher.h>
++
++#if IS_ENABLED(CONFIG_MACSEC)
++#include <net/macsec.h>
++#endif
++
+ #include "mscc_macsec.h"
+ #include "mscc_mac.h"
+ #include "mscc_fc_buffer.h"
+@@ -436,6 +443,44 @@ static const struct vsc85xx_hw_stat vsc8584_hw_stats[] = {
+ 	},
+ };
+ 
++#if IS_ENABLED(CONFIG_MACSEC)
++struct macsec_flow {
++	struct list_head list;
++	enum mscc_macsec_destination_ports port;
++	enum macsec_bank bank;
++	u32 index;
++	int assoc_num;
++	bool has_transformation;
++
++	/* Highest takes precedence [0..15] */
++	u8 priority;
++
++	u8 key[MACSEC_KEYID_LEN];
++
++	union {
++		struct macsec_rx_sa *rx_sa;
++		struct macsec_tx_sa *tx_sa;
++	};
++
++	/* Matching */
++	struct {
++		u8 sci:1;
++		u8 tagged:1;
++		u8 untagged:1;
++		u8 etype:1;
++	} match;
++
++	u16 etype;
++
++	/* Action */
++	struct {
++		u8 bypass:1;
++		u8 drop:1;
++	} action;
++
++};
++#endif
++
+ struct vsc8531_private {
+ 	int rate_magic;
+ 	u16 supp_led_modes;
+@@ -449,6 +494,19 @@ struct vsc8531_private {
+ 	 * package.
+ 	 */
+ 	unsigned int base_addr;
++
++#if IS_ENABLED(CONFIG_MACSEC)
++	/* MACsec fields:
++	 * - One SecY per device (enforced at the s/w implementation level)
++	 * - macsec_flows: list of h/w flows
++	 * - ingr_flows: bitmap of ingress flows
++	 * - egr_flows: bitmap of egress flows
++	 */
++	struct macsec_secy *secy;
++	struct list_head macsec_flows;
++	unsigned long ingr_flows;
++	unsigned long egr_flows;
++#endif
+ };
+ 
+ #ifdef CONFIG_OF_MDIO
+@@ -1951,6 +2009,634 @@ static int vsc8584_macsec_init(struct phy_device *phydev)
+ 
+ 	return 0;
+ }
++
++static void vsc8584_macsec_flow(struct phy_device *phydev,
++				struct macsec_flow *flow)
++{
++	struct vsc8531_private *priv = phydev->priv;
++	enum macsec_bank bank = flow->bank;
++	u32 val, match = 0, mask = 0, action = 0, idx = flow->index;
++
++	if (flow->match.tagged)
++		match |= MSCC_MS_SAM_MISC_MATCH_TAGGED;
++	if (flow->match.untagged)
++		match |= MSCC_MS_SAM_MISC_MATCH_UNTAGGED;
++
++	if (bank == MACSEC_INGR && flow->assoc_num >= 0) {
++		match |= MSCC_MS_SAM_MISC_MATCH_AN(flow->assoc_num);
++		mask |= MSCC_MS_SAM_MASK_AN_MASK(0x3);
++	}
++
++	if (bank == MACSEC_INGR && flow->match.sci && flow->rx_sa->sc->sci) {
++		match |= MSCC_MS_SAM_MISC_MATCH_TCI(BIT(3));
++		mask |= MSCC_MS_SAM_MASK_TCI_MASK(BIT(3)) |
++			MSCC_MS_SAM_MASK_SCI_MASK;
++
++		vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_MATCH_SCI_LO(idx),
++					 lower_32_bits(flow->rx_sa->sc->sci));
++		vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_MATCH_SCI_HI(idx),
++					 upper_32_bits(flow->rx_sa->sc->sci));
++	}
++
++	if (flow->match.etype) {
++		mask |= MSCC_MS_SAM_MASK_MAC_ETYPE_MASK;
++
++		vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_MAC_SA_MATCH_HI(idx),
++					 MSCC_MS_SAM_MAC_SA_MATCH_HI_ETYPE(htons(flow->etype)));
++	}
++
++	match |= MSCC_MS_SAM_MISC_MATCH_PRIORITY(flow->priority);
++
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_MISC_MATCH(idx), match);
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_MASK(idx), mask);
++
++	/* Action for matching packets */
++	if (flow->action.drop)
++		action = MSCC_MS_FLOW_DROP;
++	else if (flow->action.bypass || flow->port == MSCC_MS_PORT_UNCONTROLLED)
++		action = MSCC_MS_FLOW_BYPASS;
++	else
++		action = (bank == MACSEC_INGR) ?
++			 MSCC_MS_FLOW_INGRESS : MSCC_MS_FLOW_EGRESS;
++
++	val = MSCC_MS_SAM_FLOW_CTRL_FLOW_TYPE(action) |
++	      MSCC_MS_SAM_FLOW_CTRL_DROP_ACTION(MSCC_MS_ACTION_DROP) |
++	      MSCC_MS_SAM_FLOW_CTRL_DEST_PORT(flow->port);
++
++	if (action == MSCC_MS_FLOW_BYPASS)
++		goto write_ctrl;
++
++	if (bank == MACSEC_INGR) {
++		if (priv->secy->replay_protect)
++			val |= MSCC_MS_SAM_FLOW_CTRL_REPLAY_PROTECT;
++		if (priv->secy->validate_frames == MACSEC_VALIDATE_STRICT)
++			val |= MSCC_MS_SAM_FLOW_CTRL_VALIDATE_FRAMES(MSCC_MS_VALIDATE_STRICT);
++		else if (priv->secy->validate_frames == MACSEC_VALIDATE_CHECK)
++			val |= MSCC_MS_SAM_FLOW_CTRL_VALIDATE_FRAMES(MSCC_MS_VALIDATE_CHECK);
++	} else if (bank == MACSEC_EGR) {
++		if (priv->secy->protect_frames)
++			val |= MSCC_MS_SAM_FLOW_CTRL_PROTECT_FRAME;
++		if (priv->secy->tx_sc.encrypt)
++			val |= MSCC_MS_SAM_FLOW_CTRL_CONF_PROTECT;
++		if (priv->secy->tx_sc.send_sci)
++			val |= MSCC_MS_SAM_FLOW_CTRL_INCLUDE_SCI;
++	}
++
++write_ctrl:
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_FLOW_CTRL(idx), val);
++}
++
++static struct macsec_flow *vsc8584_macsec_find_flow(struct macsec_context *ctx,
++						    enum macsec_bank bank)
++{
++	struct vsc8531_private *priv = ctx->phydev->priv;
++	struct macsec_flow *pos, *tmp;
++
++	list_for_each_entry_safe(pos, tmp, &priv->macsec_flows, list)
++		if (pos->assoc_num == ctx->sa.assoc_num && pos->bank == bank)
++			return pos;
++
++	return ERR_PTR(-ENOENT);
++}
++
++static void vsc8584_macsec_flow_enable(struct phy_device *phydev,
++				       struct macsec_flow *flow)
++{
++	enum macsec_bank bank = flow->bank;
++	u32 val, idx = flow->index;
++
++	if ((flow->bank == MACSEC_INGR && flow->rx_sa && !flow->rx_sa->active) ||
++	    (flow->bank == MACSEC_EGR && flow->tx_sa && !flow->tx_sa->active))
++		return;
++
++	/* Enable */
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_ENTRY_SET1, BIT(idx));
++
++	/* Set in-use */
++	val = vsc8584_macsec_phy_read(phydev, bank, MSCC_MS_SAM_FLOW_CTRL(idx));
++	val |= MSCC_MS_SAM_FLOW_CTRL_SA_IN_USE;
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_FLOW_CTRL(idx), val);
++}
++
++static void vsc8584_macsec_flow_disable(struct phy_device *phydev,
++					struct macsec_flow *flow)
++{
++	enum macsec_bank bank = flow->bank;
++	u32 val, idx = flow->index;
++
++	/* Disable */
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_ENTRY_CLEAR1, BIT(idx));
++
++	/* Clear in-use */
++	val = vsc8584_macsec_phy_read(phydev, bank, MSCC_MS_SAM_FLOW_CTRL(idx));
++	val &= ~MSCC_MS_SAM_FLOW_CTRL_SA_IN_USE;
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_FLOW_CTRL(idx), val);
++}
++
++static u32 vsc8584_macsec_flow_context_id(struct macsec_flow *flow)
++{
++	if (flow->bank == MACSEC_INGR)
++		return flow->index + MSCC_MS_MAX_FLOWS;
++
++	return flow->index;
++}
++
++/* Derive the AES key to get a key for the hash autentication */
++static int vsc8584_macsec_derive_key(const u8 key[MACSEC_KEYID_LEN],
++				     u16 key_len, u8 hkey[16])
++{
++	struct crypto_skcipher *tfm = crypto_alloc_skcipher("ecb(aes)", 0, 0);
++	struct skcipher_request *req = NULL;
++	struct scatterlist src, dst;
++	DECLARE_CRYPTO_WAIT(wait);
++	u32 input[4] = {0};
++	int ret;
++
++	if (IS_ERR(tfm))
++		return PTR_ERR(tfm);
++
++	req = skcipher_request_alloc(tfm, GFP_KERNEL);
++	if (!req) {
++		ret = -ENOMEM;
++		goto out;
++	}
++
++	skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
++				      CRYPTO_TFM_REQ_MAY_SLEEP, crypto_req_done,
++				      &wait);
++	ret = crypto_skcipher_setkey(tfm, key, key_len);
++	if (ret < 0)
++		goto out;
++
++	sg_init_one(&src, input, 16);
++	sg_init_one(&dst, hkey, 16);
++	skcipher_request_set_crypt(req, &src, &dst, 16, NULL);
++
++	ret = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
++
++out:
++	skcipher_request_free(req);
++	crypto_free_skcipher(tfm);
++	return ret;
++}
++
++static int vsc8584_macsec_transformation(struct phy_device *phydev,
++					 struct macsec_flow *flow)
++{
++	struct vsc8531_private *priv = phydev->priv;
++	enum macsec_bank bank = flow->bank;
++	int i, ret, index = flow->index;
++	u32 rec = 0, control = 0;
++	u8 hkey[16];
++	sci_t sci;
++
++	ret = vsc8584_macsec_derive_key(flow->key, priv->secy->key_len, hkey);
++	if (ret)
++		return ret;
++
++	switch (priv->secy->key_len) {
++	case 16:
++		control |= CONTROL_CRYPTO_ALG(CTRYPTO_ALG_AES_CTR_128);
++		break;
++	case 32:
++		control |= CONTROL_CRYPTO_ALG(CTRYPTO_ALG_AES_CTR_256);
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	control |= (bank == MACSEC_EGR) ?
++		   (CONTROL_TYPE_EGRESS | CONTROL_AN(priv->secy->tx_sc.encoding_sa)) :
++		   (CONTROL_TYPE_INGRESS | CONTROL_SEQ_MASK);
++
++	control |= CONTROL_UPDATE_SEQ | CONTROL_ENCRYPT_AUTH | CONTROL_KEY_IN_CTX |
++		   CONTROL_IV0 | CONTROL_IV1 | CONTROL_IV_IN_SEQ |
++		   CONTROL_DIGEST_TYPE(0x2) | CONTROL_SEQ_TYPE(0x1) |
++		   CONTROL_AUTH_ALG(AUTH_ALG_AES_GHAS) | CONTROL_CONTEXT_ID;
++
++	/* Set the control word */
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_XFORM_REC(index, rec++),
++				 control);
++
++	/* Set the context ID. Must be unique. */
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_XFORM_REC(index, rec++),
++				 vsc8584_macsec_flow_context_id(flow));
++
++	/* Set the encryption/decryption key */
++	for (i = 0; i < priv->secy->key_len / sizeof(u32); i++)
++		vsc8584_macsec_phy_write(phydev, bank,
++					 MSCC_MS_XFORM_REC(index, rec++),
++					 ((u32 *)flow->key)[i]);
++
++	/* Set the authentication key */
++	for (i = 0; i < 4; i++)
++		vsc8584_macsec_phy_write(phydev, bank,
++					 MSCC_MS_XFORM_REC(index, rec++),
++					 ((u32 *)hkey)[i]);
++
++	/* Initial sequence number */
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_XFORM_REC(index, rec++),
++				 bank == MACSEC_INGR ?
++				 flow->rx_sa->next_pn : flow->tx_sa->next_pn);
++
++	if (bank == MACSEC_INGR)
++		/* Set the mask (replay window size) */
++		vsc8584_macsec_phy_write(phydev, bank,
++					 MSCC_MS_XFORM_REC(index, rec++),
++					 priv->secy->replay_window);
++
++	/* Set the input vectors */
++	sci = bank == MACSEC_INGR ? flow->rx_sa->sc->sci : priv->secy->sci;
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_XFORM_REC(index, rec++),
++				 lower_32_bits(sci));
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_XFORM_REC(index, rec++),
++				 upper_32_bits(sci));
++
++	while (rec < 20)
++		vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_XFORM_REC(index, rec++),
++					 0);
++
++	flow->has_transformation = true;
++	return 0;
++}
++
++static struct macsec_flow *vsc8584_macsec_alloc_flow(struct vsc8531_private *priv,
++						     enum macsec_bank bank)
++{
++	unsigned long *bitmap = bank == MACSEC_INGR ?
++				&priv->ingr_flows : &priv->egr_flows;
++	struct macsec_flow *flow;
++	int index;
++
++	index = find_first_zero_bit(bitmap, MSCC_MS_MAX_FLOWS);
++
++	if (index == MSCC_MS_MAX_FLOWS)
++		return ERR_PTR(-ENOMEM);
++
++	flow = kzalloc(sizeof(*flow), GFP_KERNEL);
++	if (!flow)
++		return ERR_PTR(-ENOMEM);
++
++	set_bit(index, bitmap);
++	flow->index = index;
++	flow->bank = bank;
++	flow->priority = 8;
++	flow->assoc_num = -1;
++
++	list_add_tail(&flow->list, &priv->macsec_flows);
++	return flow;
++}
++
++static void vsc8584_macsec_free_flow(struct vsc8531_private *priv,
++				     struct macsec_flow *flow)
++{
++	unsigned long *bitmap = flow->bank == MACSEC_INGR ?
++				&priv->ingr_flows : &priv->egr_flows;
++
++	list_del(&flow->list);
++	clear_bit(flow->index, bitmap);
++	kfree(flow);
++}
++
++static int vsc8584_macsec_add_flow(struct phy_device *phydev,
++				   struct macsec_flow *flow, bool update)
++{
++	int ret;
++
++	flow->port = MSCC_MS_PORT_CONTROLLED;
++	vsc8584_macsec_flow(phydev, flow);
++
++	if (update)
++		return 0;
++
++	ret = vsc8584_macsec_transformation(phydev, flow);
++	if (ret) {
++		vsc8584_macsec_free_flow(phydev->priv, flow);
++		return ret;
++	}
++
++	return 0;
++}
++
++static int vsc8584_macsec_default_flows(struct phy_device *phydev)
++{
++	struct macsec_flow *flow;
++
++	/* Add a rule to let the MKA traffic go through, ingress */
++	flow = vsc8584_macsec_alloc_flow(phydev->priv, MACSEC_INGR);
++	if (IS_ERR(flow))
++		return PTR_ERR(flow);
++
++	flow->priority = 15;
++	flow->port = MSCC_MS_PORT_UNCONTROLLED;
++	flow->match.tagged = 1;
++	flow->match.untagged = 1;
++	flow->match.etype = 1;
++	flow->etype = ETH_P_PAE;
++	flow->action.bypass = 1;
++
++	vsc8584_macsec_flow(phydev, flow);
++	vsc8584_macsec_flow_enable(phydev, flow);
++
++	/* Add a rule to let the MKA traffic go through, egress */
++	flow = vsc8584_macsec_alloc_flow(phydev->priv, MACSEC_EGR);
++	if (IS_ERR(flow))
++		return PTR_ERR(flow);
++
++	flow->priority = 15;
++	flow->port = MSCC_MS_PORT_COMMON;
++	flow->match.untagged = 1;
++	flow->match.etype = 1;
++	flow->etype = ETH_P_PAE;
++	flow->action.bypass = 1;
++
++	vsc8584_macsec_flow(phydev, flow);
++	vsc8584_macsec_flow_enable(phydev, flow);
++
++	return 0;
++}
++
++static void vsc8584_macsec_del_flow(struct phy_device *phydev,
++				    struct macsec_flow *flow)
++{
++	vsc8584_macsec_flow_disable(phydev, flow);
++	vsc8584_macsec_free_flow(phydev->priv, flow);
++}
++
++static int __vsc8584_macsec_add_rxsa(struct macsec_context *ctx,
++				     struct macsec_flow *flow, bool update)
++{
++	struct phy_device *phydev = ctx->phydev;
++	struct vsc8531_private *priv = phydev->priv;
++
++	if (!flow) {
++		flow = vsc8584_macsec_alloc_flow(priv, MACSEC_INGR);
++		if (IS_ERR(flow))
++			return PTR_ERR(flow);
++
++		memcpy(flow->key, ctx->sa.key, priv->secy->key_len);
++	}
++
++	flow->assoc_num = ctx->sa.assoc_num;
++	flow->rx_sa = ctx->sa.rx_sa;
++
++	/* Always match tagged packets on ingress */
++	flow->match.tagged = 1;
++	flow->match.sci = 1;
++
++	if (priv->secy->validate_frames != MACSEC_VALIDATE_DISABLED)
++		flow->match.untagged = 1;
++
++	return vsc8584_macsec_add_flow(phydev, flow, update);
++}
++
++static int __vsc8584_macsec_add_txsa(struct macsec_context *ctx,
++				     struct macsec_flow *flow, bool update)
++{
++	struct phy_device *phydev = ctx->phydev;
++	struct vsc8531_private *priv = phydev->priv;
++
++	if (!flow) {
++		flow = vsc8584_macsec_alloc_flow(priv, MACSEC_EGR);
++		if (IS_ERR(flow))
++			return PTR_ERR(flow);
++
++		memcpy(flow->key, ctx->sa.key, priv->secy->key_len);
++	}
++
++	flow->assoc_num = ctx->sa.assoc_num;
++	flow->tx_sa = ctx->sa.tx_sa;
++
++	/* Always match untagged packets on egress */
++	flow->match.untagged = 1;
++
++	return vsc8584_macsec_add_flow(phydev, flow, update);
++}
++
++static int vsc8584_macsec_dev_open(struct macsec_context *ctx)
++{
++	struct vsc8531_private *priv = ctx->phydev->priv;
++	struct macsec_flow *flow, *tmp;
++
++	/* No operation to perform before the commit step */
++	if (ctx->prepare)
++		return 0;
++
++	list_for_each_entry_safe(flow, tmp, &priv->macsec_flows, list)
++		vsc8584_macsec_flow_enable(ctx->phydev, flow);
++
++	return 0;
++}
++
++static int vsc8584_macsec_dev_stop(struct macsec_context *ctx)
++{
++	struct vsc8531_private *priv = ctx->phydev->priv;
++	struct macsec_flow *flow, *tmp;
++
++	/* No operation to perform before the commit step */
++	if (ctx->prepare)
++		return 0;
++
++	list_for_each_entry_safe(flow, tmp, &priv->macsec_flows, list)
++		vsc8584_macsec_flow_disable(ctx->phydev, flow);
++
++	return 0;
++}
++
++static int vsc8584_macsec_add_secy(struct macsec_context *ctx)
++{
++	struct vsc8531_private *priv = ctx->phydev->priv;
++	struct macsec_secy *secy = ctx->secy;
++
++	if (ctx->prepare) {
++		if (priv->secy)
++			return -EEXIST;
++
++		return 0;
++	}
++
++	priv->secy = secy;
++
++	vsc8584_macsec_flow_default_action(ctx->phydev, MACSEC_EGR,
++					   secy->validate_frames != MACSEC_VALIDATE_DISABLED);
++	vsc8584_macsec_flow_default_action(ctx->phydev, MACSEC_INGR,
++					   secy->validate_frames != MACSEC_VALIDATE_DISABLED);
++
++	return vsc8584_macsec_default_flows(ctx->phydev);
++}
++
++static int vsc8584_macsec_del_secy(struct macsec_context *ctx)
++{
++	struct vsc8531_private *priv = ctx->phydev->priv;
++	struct macsec_flow *flow, *tmp;
++
++	/* No operation to perform before the commit step */
++	if (ctx->prepare)
++		return 0;
++
++	list_for_each_entry_safe(flow, tmp, &priv->macsec_flows, list)
++		vsc8584_macsec_del_flow(ctx->phydev, flow);
++
++	vsc8584_macsec_flow_default_action(ctx->phydev, MACSEC_EGR, false);
++	vsc8584_macsec_flow_default_action(ctx->phydev, MACSEC_INGR, false);
++
++	priv->secy = NULL;
++	return 0;
++}
++
++static int vsc8584_macsec_upd_secy(struct macsec_context *ctx)
++{
++	/* No operation to perform before the commit step */
++	if (ctx->prepare)
++		return 0;
++
++	vsc8584_macsec_del_secy(ctx);
++	return vsc8584_macsec_add_secy(ctx);
++}
++
++static int vsc8584_macsec_add_rxsc(struct macsec_context *ctx)
++{
++	/* Nothing to do */
++	return 0;
++}
++
++static int vsc8584_macsec_upd_rxsc(struct macsec_context *ctx)
++{
++	return -EOPNOTSUPP;
++}
++
++static int vsc8584_macsec_del_rxsc(struct macsec_context *ctx)
++{
++	struct vsc8531_private *priv = ctx->phydev->priv;
++	struct macsec_flow *flow, *tmp;
++
++	/* No operation to perform before the commit step */
++	if (ctx->prepare)
++		return 0;
++
++	list_for_each_entry_safe(flow, tmp, &priv->macsec_flows, list) {
++		if (flow->bank == MACSEC_INGR && flow->rx_sa &&
++		    flow->rx_sa->sc->sci == ctx->rx_sc->sci)
++			vsc8584_macsec_del_flow(ctx->phydev, flow);
++	}
++
++	return 0;
++}
++
++static int vsc8584_macsec_add_rxsa(struct macsec_context *ctx)
++{
++	struct macsec_flow *flow = NULL;
++
++	if (ctx->prepare)
++		return __vsc8584_macsec_add_rxsa(ctx, flow, false);
++
++	flow = vsc8584_macsec_find_flow(ctx, MACSEC_INGR);
++	if (IS_ERR(flow))
++		return PTR_ERR(flow);
++
++	vsc8584_macsec_flow_enable(ctx->phydev, flow);
++	return 0;
++}
++
++static int vsc8584_macsec_upd_rxsa(struct macsec_context *ctx)
++{
++	struct macsec_flow *flow;
++
++	flow = vsc8584_macsec_find_flow(ctx, MACSEC_INGR);
++	if (IS_ERR(flow))
++		return PTR_ERR(flow);
++
++	if (ctx->prepare) {
++		/* Make sure the flow is disabled before updating it */
++		vsc8584_macsec_flow_disable(ctx->phydev, flow);
++
++		return __vsc8584_macsec_add_rxsa(ctx, flow, true);
++	}
++
++	vsc8584_macsec_flow_enable(ctx->phydev, flow);
++	return 0;
++}
++
++static int vsc8584_macsec_del_rxsa(struct macsec_context *ctx)
++{
++	struct macsec_flow *flow;
++
++	flow = vsc8584_macsec_find_flow(ctx, MACSEC_INGR);
++
++	if (IS_ERR(flow))
++		return PTR_ERR(flow);
++	if (ctx->prepare)
++		return 0;
++
++	vsc8584_macsec_del_flow(ctx->phydev, flow);
++	return 0;
++}
++
++static int vsc8584_macsec_add_txsa(struct macsec_context *ctx)
++{
++	struct macsec_flow *flow = NULL;
++
++	if (ctx->prepare)
++		return __vsc8584_macsec_add_txsa(ctx, flow, false);
++
++	flow = vsc8584_macsec_find_flow(ctx, MACSEC_EGR);
++	if (IS_ERR(flow))
++		return PTR_ERR(flow);
++
++	vsc8584_macsec_flow_enable(ctx->phydev, flow);
++	return 0;
++}
++
++static int vsc8584_macsec_upd_txsa(struct macsec_context *ctx)
++{
++	struct macsec_flow *flow;
++
++	flow = vsc8584_macsec_find_flow(ctx, MACSEC_EGR);
++	if (IS_ERR(flow))
++		return PTR_ERR(flow);
++
++	if (ctx->prepare) {
++		/* Make sure the flow is disabled before updating it */
++		vsc8584_macsec_flow_disable(ctx->phydev, flow);
++
++		return __vsc8584_macsec_add_txsa(ctx, flow, true);
++	}
++
++	vsc8584_macsec_flow_enable(ctx->phydev, flow);
++	return 0;
++}
++
++static int vsc8584_macsec_del_txsa(struct macsec_context *ctx)
++{
++	struct macsec_flow *flow;
++
++	flow = vsc8584_macsec_find_flow(ctx, MACSEC_EGR);
++
++	if (IS_ERR(flow))
++		return PTR_ERR(flow);
++	if (ctx->prepare)
++		return 0;
++
++	vsc8584_macsec_del_flow(ctx->phydev, flow);
++	return 0;
++}
++
++static struct macsec_ops vsc8584_macsec_ops = {
++	.mdo_dev_open = vsc8584_macsec_dev_open,
++	.mdo_dev_stop = vsc8584_macsec_dev_stop,
++	.mdo_add_secy = vsc8584_macsec_add_secy,
++	.mdo_upd_secy = vsc8584_macsec_upd_secy,
++	.mdo_del_secy = vsc8584_macsec_del_secy,
++	.mdo_add_rxsc = vsc8584_macsec_add_rxsc,
++	.mdo_upd_rxsc = vsc8584_macsec_upd_rxsc,
++	.mdo_del_rxsc = vsc8584_macsec_del_rxsc,
++	.mdo_add_rxsa = vsc8584_macsec_add_rxsa,
++	.mdo_upd_rxsa = vsc8584_macsec_upd_rxsa,
++	.mdo_del_rxsa = vsc8584_macsec_del_rxsa,
++	.mdo_add_txsa = vsc8584_macsec_add_txsa,
++	.mdo_upd_txsa = vsc8584_macsec_upd_txsa,
++	.mdo_del_txsa = vsc8584_macsec_del_txsa,
++};
+ #endif /* CONFIG_MACSEC */
+ 
+ /* Check if one PHY has already done the init of the parts common to all PHYs
+@@ -2109,6 +2795,11 @@ static int vsc8584_config_init(struct phy_device *phydev)
+ 	case PHY_ID_VSC8575:
+ 	case PHY_ID_VSC8582:
+ 	case PHY_ID_VSC8584:
++		INIT_LIST_HEAD(&vsc8531->macsec_flows);
++		vsc8531->secy = NULL;
++
++		phydev->macsec_ops = &vsc8584_macsec_ops;
++
+ 		ret = vsc8584_macsec_init(phydev);
+ 		if (ret)
+ 			goto err;
+diff --git a/drivers/net/phy/mscc_macsec.h b/drivers/net/phy/mscc_macsec.h
+index 0d108da28dad2..9b5d0af91d204 100644
+--- a/drivers/net/phy/mscc_macsec.h
++++ b/drivers/net/phy/mscc_macsec.h
+@@ -8,6 +8,8 @@
+ #ifndef _MSCC_OCELOT_MACSEC_H_
+ #define _MSCC_OCELOT_MACSEC_H_
+ 
++#define MSCC_MS_MAX_FLOWS		16
++
+ #define CONTROL_TYPE_EGRESS		0x6
+ #define CONTROL_TYPE_INGRESS		0xf
+ #define CONTROL_IV0			BIT(5)
+@@ -59,6 +61,8 @@ enum mscc_macsec_validate_levels {
+ #define MSCC_MS_XFORM_REC(x, y)		(((x) << 5) + (y))
+ #define MSCC_MS_ENA_CFG			0x800
+ #define MSCC_MS_FC_CFG			0x804
++#define MSCC_MS_SAM_MAC_SA_MATCH_LO(x)	(0x1000 + ((x) << 4))
++#define MSCC_MS_SAM_MAC_SA_MATCH_HI(x)	(0x1001 + ((x) << 4))
+ #define MSCC_MS_SAM_MISC_MATCH(x)	(0x1004 + ((x) << 4))
+ #define MSCC_MS_SAM_MATCH_SCI_LO(x)	(0x1005 + ((x) << 4))
+ #define MSCC_MS_SAM_MATCH_SCI_HI(x)	(0x1006 + ((x) << 4))
+-- 
+cgit 1.2.3-1.el7
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1759-09-v5.18-net-macsec-PN-wrap-callback.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1759-09-v5.18-net-macsec-PN-wrap-callback.patch
new file mode 100644
index 0000000..75d7839
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1759-09-v5.18-net-macsec-PN-wrap-callback.patch
@@ -0,0 +1,72 @@
+From 5c937de78b39e47ce9924fc4b863c5b727edc328 Mon Sep 17 00:00:00 2001
+From: Antoine Tenart <antoine.tenart@bootlin.com>
+Date: Mon, 13 Jan 2020 23:31:47 +0100
+Subject: net: macsec: PN wrap callback
+
+Allow to call macsec_pn_wrapped from hardware drivers to notify when a
+PN rolls over. Some drivers might used an interrupt to implement this.
+
+Signed-off-by: Antoine Tenart <antoine.tenart@bootlin.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/macsec.c | 25 +++++++++++++++++++------
+ include/net/macsec.h |  2 ++
+ 2 files changed, 21 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
+index e515919e8687f..45bfd99f17fa9 100644
+--- a/drivers/net/macsec.c
++++ b/drivers/net/macsec.c
+@@ -424,6 +424,23 @@ static struct macsec_eth_header *macsec_ethhdr(struct sk_buff *skb)
+ 	return (struct macsec_eth_header *)skb_mac_header(skb);
+ }
+ 
++static void __macsec_pn_wrapped(struct macsec_secy *secy,
++				struct macsec_tx_sa *tx_sa)
++{
++	pr_debug("PN wrapped, transitioning to !oper\n");
++	tx_sa->active = false;
++	if (secy->protect_frames)
++		secy->operational = false;
++}
++
++void macsec_pn_wrapped(struct macsec_secy *secy, struct macsec_tx_sa *tx_sa)
++{
++	spin_lock_bh(&tx_sa->lock);
++	__macsec_pn_wrapped(secy, tx_sa);
++	spin_unlock_bh(&tx_sa->lock);
++}
++EXPORT_SYMBOL_GPL(macsec_pn_wrapped);
++
+ static u32 tx_sa_update_pn(struct macsec_tx_sa *tx_sa, struct macsec_secy *secy)
+ {
+ 	u32 pn;
+@@ -432,12 +449,8 @@ static u32 tx_sa_update_pn(struct macsec_tx_sa *tx_sa, struct macsec_secy *secy)
+ 	pn = tx_sa->next_pn;
+ 
+ 	tx_sa->next_pn++;
+-	if (tx_sa->next_pn == 0) {
+-		pr_debug("PN wrapped, transitioning to !oper\n");
+-		tx_sa->active = false;
+-		if (secy->protect_frames)
+-			secy->operational = false;
+-	}
++	if (tx_sa->next_pn == 0)
++		__macsec_pn_wrapped(secy, tx_sa);
+ 	spin_unlock_bh(&tx_sa->lock);
+ 
+ 	return pn;
+diff --git a/include/net/macsec.h b/include/net/macsec.h
+index 16e7e5061178e..92e43db8b5667 100644
+--- a/include/net/macsec.h
++++ b/include/net/macsec.h
+@@ -219,4 +219,6 @@ struct macsec_ops {
+ 	int (*mdo_del_txsa)(struct macsec_context *ctx);
+ };
+ 
++void macsec_pn_wrapped(struct macsec_secy *secy, struct macsec_tx_sa *tx_sa);
++
+ #endif /* _NET_MACSEC_H_ */
+-- 
+cgit 1.2.3-1.el7
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1760-10-v5.18-net-phy-mscc-PN-rollover-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1760-10-v5.18-net-phy-mscc-PN-rollover-support.patch
new file mode 100644
index 0000000..2c9bef6
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1760-10-v5.18-net-phy-mscc-PN-rollover-support.patch
@@ -0,0 +1,129 @@
+From 781449a4ae3b381950ee9aec4d8a54e35f66ab9b Mon Sep 17 00:00:00 2001
+From: Antoine Tenart <antoine.tenart@bootlin.com>
+Date: Mon, 13 Jan 2020 23:31:48 +0100
+Subject: net: phy: mscc: PN rollover support
+
+This patch adds support for handling MACsec PN rollover in the mscc PHY
+driver. When a flow rolls over, an interrupt is fired. This patch adds
+the logic to check all flows and identify the one rolling over in the
+handle_interrupt PHY helper, then disables the flow and report the event
+to the MACsec core.
+
+Signed-off-by: Antoine Tenart <antoine.tenart@bootlin.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/phy/mscc.c        | 60 ++++++++++++++++++++++++++++++++++++++++++-
+ drivers/net/phy/mscc_macsec.h |  2 ++
+ 2 files changed, 61 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/phy/mscc.c
++++ b/drivers/net/phy/mscc.c
+@@ -80,7 +80,7 @@ enum rgmii_rx_clock_delay {
+ #define MSCC_PHY_EXT_PHY_CNTL_2		  24
+ 
+ #define MII_VSC85XX_INT_MASK		  25
+-#define MII_VSC85XX_INT_MASK_MASK	  0xa000
++#define MII_VSC85XX_INT_MASK_MASK	  0xa020
+ #define MII_VSC85XX_INT_MASK_WOL	  0x0040
+ #define MII_VSC85XX_INT_STATUS		  26
+ 
+@@ -207,6 +207,9 @@ enum macsec_bank {
+ #define SECURE_ON_ENABLE		  0x8000
+ #define SECURE_ON_PASSWD_LEN_4		  0x4000
+ 
++#define MSCC_PHY_EXTENDED_INT		  28
++#define MSCC_PHY_EXTENDED_INT_MS_EGR	  BIT(9)
++
+ /* Extended Page 3 Registers */
+ #define MSCC_PHY_SERDES_TX_VALID_CNT	  21
+ #define MSCC_PHY_SERDES_TX_CRC_ERR_CNT	  22
+@@ -2805,6 +2808,43 @@ err:
+ 	return ret;
+ }
+ 
++static int vsc8584_handle_interrupt(struct phy_device *phydev)
++{
++#if IS_ENABLED(CONFIG_MACSEC)
++	struct vsc8531_private *priv = phydev->priv;
++	struct macsec_flow *flow, *tmp;
++	u32 cause, rec;
++
++	/* Check MACsec PN rollover */
++	cause = vsc8584_macsec_phy_read(phydev, MACSEC_EGR,
++					MSCC_MS_INTR_CTRL_STATUS);
++	cause &= MSCC_MS_INTR_CTRL_STATUS_INTR_CLR_STATUS_M;
++	if (!(cause & MACSEC_INTR_CTRL_STATUS_ROLLOVER))
++		goto skip_rollover;
++
++	rec = 6 + priv->secy->key_len / sizeof(u32);
++	list_for_each_entry_safe(flow, tmp, &priv->macsec_flows, list) {
++		u32 val;
++
++		if (flow->bank != MACSEC_EGR || !flow->has_transformation)
++			continue;
++
++		val = vsc8584_macsec_phy_read(phydev, MACSEC_EGR,
++					      MSCC_MS_XFORM_REC(flow->index, rec));
++		if (val == 0xffffffff) {
++			vsc8584_macsec_flow_disable(phydev, flow);
++			macsec_pn_wrapped(priv->secy, flow->tx_sa);
++			break;
++		}
++	}
++
++skip_rollover:
++#endif
++
++	phy_mac_interrupt(phydev);
++	return 0;
++}
++
+ static int vsc85xx_config_init(struct phy_device *phydev)
+ {
+ 	int rc, i, phy_id;
+@@ -3248,6 +3288,20 @@ static int vsc85xx_config_intr(struct ph
+ 	int rc;
+ 
+ 	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
++#if IS_ENABLED(CONFIG_MACSEC)
++		phy_write(phydev, MSCC_EXT_PAGE_ACCESS,
++			  MSCC_PHY_PAGE_EXTENDED_2);
++		phy_write(phydev, MSCC_PHY_EXTENDED_INT,
++			  MSCC_PHY_EXTENDED_INT_MS_EGR);
++		phy_write(phydev, MSCC_EXT_PAGE_ACCESS,
++			  MSCC_PHY_PAGE_STANDARD);
++
++		vsc8584_macsec_phy_write(phydev, MACSEC_EGR,
++					 MSCC_MS_AIC_CTRL, 0xf);
++		vsc8584_macsec_phy_write(phydev, MACSEC_EGR,
++			MSCC_MS_INTR_CTRL_STATUS,
++			MSCC_MS_INTR_CTRL_STATUS_INTR_ENABLE(MACSEC_INTR_CTRL_STATUS_ROLLOVER));
++#endif
+ 		rc = phy_write(phydev, MII_VSC85XX_INT_MASK,
+ 			       MII_VSC85XX_INT_MASK_MASK);
+ 	} else {
+@@ -3553,6 +3607,7 @@ static struct phy_driver vsc85xx_driver[
+ 	.config_aneg    = &vsc85xx_config_aneg,
+ 	.aneg_done	= &genphy_aneg_done,
+ 	.read_status	= &vsc85xx_read_status,
++	.handle_interrupt = &vsc8584_handle_interrupt,
+ 	.ack_interrupt  = &vsc85xx_ack_interrupt,
+ 	.config_intr    = &vsc85xx_config_intr,
+ 	.did_interrupt  = &vsc8584_did_interrupt,
+--- a/drivers/net/phy/mscc_macsec.h
++++ b/drivers/net/phy/mscc_macsec.h
+@@ -83,6 +83,7 @@ enum mscc_macsec_validate_levels {
+ #define MSCC_MS_STATUS_CONTEXT_CTRL	0x3d02
+ #define MSCC_MS_INTR_CTRL_STATUS	0x3d04
+ #define MSCC_MS_BLOCK_CTX_UPDATE	0x3d0c
++#define MSCC_MS_AIC_CTRL		0x3e02
+ 
+ /* MACSEC_ENA_CFG */
+ #define MSCC_MS_ENA_CFG_CLK_ENA				BIT(0)
+@@ -260,5 +261,6 @@ enum mscc_macsec_validate_levels {
+ #define MSCC_MS_INTR_CTRL_STATUS_INTR_CLR_STATUS_M	GENMASK(15, 0)
+ #define MSCC_MS_INTR_CTRL_STATUS_INTR_ENABLE(x)		((x) << 16)
+ #define MSCC_MS_INTR_CTRL_STATUS_INTR_ENABLE_M		GENMASK(31, 16)
++#define MACSEC_INTR_CTRL_STATUS_ROLLOVER		BIT(5)
+ 
+ #endif
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1761-v5.18-net-macsec-invoke-mdo_upd_secy-callback-when-mac-address-changed.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1761-v5.18-net-macsec-invoke-mdo_upd_secy-callback-when-mac-address-changed.patch
new file mode 100644
index 0000000..ab7986b
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1761-v5.18-net-macsec-invoke-mdo_upd_secy-callback-when-mac-address-changed.patch
@@ -0,0 +1,44 @@
+From 09f4136c5d6b4c5144a965bd086009863d58ff08 Mon Sep 17 00:00:00 2001
+From: Dmitry Bogdanov <dbogdanov@marvell.com>
+Date: Tue, 10 Mar 2020 18:22:25 +0300
+Subject: net: macsec: invoke mdo_upd_secy callback when mac address changed
+
+Notify the offload engine about MAC address change to reconfigure it
+accordingly.
+
+Fixes: 3cf3227a21d1 ("net: macsec: hardware offloading infrastructure")
+Signed-off-by: Dmitry Bogdanov <dbogdanov@marvell.com>
+Signed-off-by: Mark Starovoytov <mstarovoitov@marvell.com>
+Signed-off-by: Igor Russkikh <irusskikh@marvell.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/macsec.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
+index 66c6392251bc3..6ec6fc191a6e4 100644
+--- a/drivers/net/macsec.c
++++ b/drivers/net/macsec.c
+@@ -3274,6 +3274,19 @@ static int macsec_set_mac_address(struct net_device *dev, void *p)
+ out:
+ 	ether_addr_copy(dev->dev_addr, addr->sa_data);
+ 	macsec->secy.sci = dev_to_sci(dev, MACSEC_PORT_ES);
++
++	/* If h/w offloading is available, propagate to the device */
++	if (macsec_is_offloaded(macsec)) {
++		const struct macsec_ops *ops;
++		struct macsec_context ctx;
++
++		ops = macsec_get_ops(macsec, &ctx);
++		if (ops) {
++			ctx.secy = &macsec->secy;
++			macsec_offload(ops->mdo_upd_secy, &ctx);
++		}
++	}
++
+ 	return 0;
+ }
+ 
+-- 
+cgit 1.2.3-1.el7
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1762-v5.18-net-macsec-Support-XPN-frame-handling-IEEE-802.1AEbw.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1762-v5.18-net-macsec-Support-XPN-frame-handling-IEEE-802.1AEbw.patch
new file mode 100644
index 0000000..357977e
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1762-v5.18-net-macsec-Support-XPN-frame-handling-IEEE-802.1AEbw.patch
@@ -0,0 +1,479 @@
+From a21ecf0e033807b976967286e6c392f48ee2049f Mon Sep 17 00:00:00 2001
+From: Era Mayflower <mayflowerera@gmail.com>
+Date: Mon, 9 Mar 2020 19:47:01 +0000
+Subject: macsec: Support XPN frame handling - IEEE 802.1AEbw
+
+Support extended packet number cipher suites (802.1AEbw) frames handling.
+This does not include the needed netlink patches.
+
+    * Added xpn boolean field to `struct macsec_secy`.
+    * Added ssci field to `struct_macsec_tx_sa` (802.1AE figure 10-5).
+    * Added ssci field to `struct_macsec_rx_sa` (802.1AE figure 10-5).
+    * Added salt field to `struct macsec_key` (802.1AE 10.7 NOTE 1).
+    * Created pn_t type for easy access to lower and upper halves.
+    * Created salt_t type for easy access to the "ssci" and "pn" parts.
+    * Created `macsec_fill_iv_xpn` function to create IV in XPN mode.
+    * Support in PN recovery and preliminary replay check in XPN mode.
+
+In addition, according to IEEE 802.1AEbw figure 10-5, the PN of incoming
+frame can be 0 when XPN cipher suite is used, so fixed the function
+`macsec_validate_skb` to fail on PN=0 only if XPN is off.
+
+Signed-off-by: Era Mayflower <mayflowerera@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/macsec.c | 130 +++++++++++++++++++++++++++++++++++++--------------
+ include/net/macsec.h |  45 ++++++++++++++++--
+ 2 files changed, 136 insertions(+), 39 deletions(-)
+
+diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
+index 6ec6fc191a6e4..6c71e250cccb0 100644
+--- a/drivers/net/macsec.c
++++ b/drivers/net/macsec.c
+@@ -19,6 +19,7 @@
+ #include <net/gro_cells.h>
+ #include <net/macsec.h>
+ #include <linux/phy.h>
++#include <linux/byteorder/generic.h>
+ 
+ #include <uapi/linux/if_macsec.h>
+ 
+@@ -68,6 +69,16 @@ struct macsec_eth_header {
+ 	     sc;					\
+ 	     sc = rtnl_dereference(sc->next))
+ 
++#define pn_same_half(pn1, pn2) (!(((pn1) >> 31) ^ ((pn2) >> 31)))
++
++struct gcm_iv_xpn {
++	union {
++		u8 short_secure_channel_id[4];
++		ssci_t ssci;
++	};
++	__be64 pn;
++} __packed;
++
+ struct gcm_iv {
+ 	union {
+ 		u8 secure_channel_id[8];
+@@ -372,8 +383,8 @@ static const struct macsec_ops *macsec_get_ops(struct macsec_dev *macsec,
+ 	return __macsec_get_ops(macsec->offload, macsec, ctx);
+ }
+ 
+-/* validate MACsec packet according to IEEE 802.1AE-2006 9.12 */
+-static bool macsec_validate_skb(struct sk_buff *skb, u16 icv_len)
++/* validate MACsec packet according to IEEE 802.1AE-2018 9.12 */
++static bool macsec_validate_skb(struct sk_buff *skb, u16 icv_len, bool xpn)
+ {
+ 	struct macsec_eth_header *h = (struct macsec_eth_header *)skb->data;
+ 	int len = skb->len - 2 * ETH_ALEN;
+@@ -398,8 +409,8 @@ static bool macsec_validate_skb(struct sk_buff *skb, u16 icv_len)
+ 	if (h->unused)
+ 		return false;
+ 
+-	/* rx.pn != 0 (figure 10-5) */
+-	if (!h->packet_number)
++	/* rx.pn != 0 if not XPN (figure 10-5 with 802.11AEbw-2013 amendment) */
++	if (!h->packet_number && !xpn)
+ 		return false;
+ 
+ 	/* length check, f) g) h) i) */
+@@ -411,6 +422,15 @@ static bool macsec_validate_skb(struct sk_buff *skb, u16 icv_len)
+ #define MACSEC_NEEDED_HEADROOM (macsec_extra_len(true))
+ #define MACSEC_NEEDED_TAILROOM MACSEC_STD_ICV_LEN
+ 
++static void macsec_fill_iv_xpn(unsigned char *iv, ssci_t ssci, u64 pn,
++			       salt_t salt)
++{
++	struct gcm_iv_xpn *gcm_iv = (struct gcm_iv_xpn *)iv;
++
++	gcm_iv->ssci = ssci ^ salt.ssci;
++	gcm_iv->pn = cpu_to_be64(pn) ^ salt.pn;
++}
++
+ static void macsec_fill_iv(unsigned char *iv, sci_t sci, u32 pn)
+ {
+ 	struct gcm_iv *gcm_iv = (struct gcm_iv *)iv;
+@@ -446,14 +466,19 @@ void macsec_pn_wrapped(struct macsec_secy *secy, struct macsec_tx_sa *tx_sa)
+ }
+ EXPORT_SYMBOL_GPL(macsec_pn_wrapped);
+ 
+-static u32 tx_sa_update_pn(struct macsec_tx_sa *tx_sa, struct macsec_secy *secy)
++static pn_t tx_sa_update_pn(struct macsec_tx_sa *tx_sa,
++			    struct macsec_secy *secy)
+ {
+-	u32 pn;
++	pn_t pn;
+ 
+ 	spin_lock_bh(&tx_sa->lock);
+-	pn = tx_sa->next_pn;
+ 
+-	tx_sa->next_pn++;
++	pn = tx_sa->next_pn_halves;
++	if (secy->xpn)
++		tx_sa->next_pn++;
++	else
++		tx_sa->next_pn_halves.lower++;
++
+ 	if (tx_sa->next_pn == 0)
+ 		__macsec_pn_wrapped(secy, tx_sa);
+ 	spin_unlock_bh(&tx_sa->lock);
+@@ -568,7 +593,7 @@ static struct sk_buff *macsec_encrypt(struct sk_buff *skb,
+ 	struct macsec_tx_sa *tx_sa;
+ 	struct macsec_dev *macsec = macsec_priv(dev);
+ 	bool sci_present;
+-	u32 pn;
++	pn_t pn;
+ 
+ 	secy = &macsec->secy;
+ 	tx_sc = &secy->tx_sc;
+@@ -610,12 +635,12 @@ static struct sk_buff *macsec_encrypt(struct sk_buff *skb,
+ 	memmove(hh, eth, 2 * ETH_ALEN);
+ 
+ 	pn = tx_sa_update_pn(tx_sa, secy);
+-	if (pn == 0) {
++	if (pn.full64 == 0) {
+ 		macsec_txsa_put(tx_sa);
+ 		kfree_skb(skb);
+ 		return ERR_PTR(-ENOLINK);
+ 	}
+-	macsec_fill_sectag(hh, secy, pn, sci_present);
++	macsec_fill_sectag(hh, secy, pn.lower, sci_present);
+ 	macsec_set_shortlen(hh, unprotected_len - 2 * ETH_ALEN);
+ 
+ 	skb_put(skb, secy->icv_len);
+@@ -646,7 +671,10 @@ static struct sk_buff *macsec_encrypt(struct sk_buff *skb,
+ 		return ERR_PTR(-ENOMEM);
+ 	}
+ 
+-	macsec_fill_iv(iv, secy->sci, pn);
++	if (secy->xpn)
++		macsec_fill_iv_xpn(iv, tx_sa->ssci, pn.full64, tx_sa->key.salt);
++	else
++		macsec_fill_iv(iv, secy->sci, pn.lower);
+ 
+ 	sg_init_table(sg, ret);
+ 	ret = skb_to_sgvec(skb, sg, 0, skb->len);
+@@ -698,13 +726,14 @@ static bool macsec_post_decrypt(struct sk_buff *skb, struct macsec_secy *secy, u
+ 	u32 lowest_pn = 0;
+ 
+ 	spin_lock(&rx_sa->lock);
+-	if (rx_sa->next_pn >= secy->replay_window)
+-		lowest_pn = rx_sa->next_pn - secy->replay_window;
++	if (rx_sa->next_pn_halves.lower >= secy->replay_window)
++		lowest_pn = rx_sa->next_pn_halves.lower - secy->replay_window;
+ 
+ 	/* Now perform replay protection check again
+ 	 * (see IEEE 802.1AE-2006 figure 10-5)
+ 	 */
+-	if (secy->replay_protect && pn < lowest_pn) {
++	if (secy->replay_protect && pn < lowest_pn &&
++	    (!secy->xpn || pn_same_half(pn, lowest_pn))) {
+ 		spin_unlock(&rx_sa->lock);
+ 		u64_stats_update_begin(&rxsc_stats->syncp);
+ 		rxsc_stats->stats.InPktsLate++;
+@@ -753,8 +782,15 @@ static bool macsec_post_decrypt(struct sk_buff *skb, struct macsec_secy *secy, u
+ 		}
+ 		u64_stats_update_end(&rxsc_stats->syncp);
+ 
+-		if (pn >= rx_sa->next_pn)
+-			rx_sa->next_pn = pn + 1;
++		// Instead of "pn >=" - to support pn overflow in xpn
++		if (pn + 1 > rx_sa->next_pn_halves.lower) {
++			rx_sa->next_pn_halves.lower = pn + 1;
++		} else if (secy->xpn &&
++			   !pn_same_half(pn, rx_sa->next_pn_halves.lower)) {
++			rx_sa->next_pn_halves.upper++;
++			rx_sa->next_pn_halves.lower = pn + 1;
++		}
++
+ 		spin_unlock(&rx_sa->lock);
+ 	}
+ 
+@@ -841,6 +877,7 @@ static struct sk_buff *macsec_decrypt(struct sk_buff *skb,
+ 	unsigned char *iv;
+ 	struct aead_request *req;
+ 	struct macsec_eth_header *hdr;
++	u32 hdr_pn;
+ 	u16 icv_len = secy->icv_len;
+ 
+ 	macsec_skb_cb(skb)->valid = false;
+@@ -860,7 +897,21 @@ static struct sk_buff *macsec_decrypt(struct sk_buff *skb,
+ 	}
+ 
+ 	hdr = (struct macsec_eth_header *)skb->data;
+-	macsec_fill_iv(iv, sci, ntohl(hdr->packet_number));
++	hdr_pn = ntohl(hdr->packet_number);
++
++	if (secy->xpn) {
++		pn_t recovered_pn = rx_sa->next_pn_halves;
++
++		recovered_pn.lower = hdr_pn;
++		if (hdr_pn < rx_sa->next_pn_halves.lower &&
++		    !pn_same_half(hdr_pn, rx_sa->next_pn_halves.lower))
++			recovered_pn.upper++;
++
++		macsec_fill_iv_xpn(iv, rx_sa->ssci, recovered_pn.full64,
++				   rx_sa->key.salt);
++	} else {
++		macsec_fill_iv(iv, sci, hdr_pn);
++	}
+ 
+ 	sg_init_table(sg, ret);
+ 	ret = skb_to_sgvec(skb, sg, 0, skb->len);
+@@ -1001,7 +1052,7 @@ static rx_handler_result_t macsec_handle_frame(struct sk_buff **pskb)
+ 	struct macsec_rxh_data *rxd;
+ 	struct macsec_dev *macsec;
+ 	sci_t sci;
+-	u32 pn;
++	u32 hdr_pn;
+ 	bool cbit;
+ 	struct pcpu_rx_sc_stats *rxsc_stats;
+ 	struct pcpu_secy_stats *secy_stats;
+@@ -1072,7 +1123,7 @@ static rx_handler_result_t macsec_handle_frame(struct sk_buff **pskb)
+ 	secy_stats = this_cpu_ptr(macsec->stats);
+ 	rxsc_stats = this_cpu_ptr(rx_sc->stats);
+ 
+-	if (!macsec_validate_skb(skb, secy->icv_len)) {
++	if (!macsec_validate_skb(skb, secy->icv_len, secy->xpn)) {
+ 		u64_stats_update_begin(&secy_stats->syncp);
+ 		secy_stats->stats.InPktsBadTag++;
+ 		u64_stats_update_end(&secy_stats->syncp);
+@@ -1104,13 +1155,16 @@ static rx_handler_result_t macsec_handle_frame(struct sk_buff **pskb)
+ 	}
+ 
+ 	/* First, PN check to avoid decrypting obviously wrong packets */
+-	pn = ntohl(hdr->packet_number);
++	hdr_pn = ntohl(hdr->packet_number);
+ 	if (secy->replay_protect) {
+ 		bool late;
+ 
+ 		spin_lock(&rx_sa->lock);
+-		late = rx_sa->next_pn >= secy->replay_window &&
+-		       pn < (rx_sa->next_pn - secy->replay_window);
++		late = rx_sa->next_pn_halves.lower >= secy->replay_window &&
++		       hdr_pn < (rx_sa->next_pn_halves.lower - secy->replay_window);
++
++		if (secy->xpn)
++			late = late && pn_same_half(rx_sa->next_pn_halves.lower, hdr_pn);
+ 		spin_unlock(&rx_sa->lock);
+ 
+ 		if (late) {
+@@ -1139,7 +1193,7 @@ static rx_handler_result_t macsec_handle_frame(struct sk_buff **pskb)
+ 		return RX_HANDLER_CONSUMED;
+ 	}
+ 
+-	if (!macsec_post_decrypt(skb, secy, pn))
++	if (!macsec_post_decrypt(skb, secy, hdr_pn))
+ 		goto drop;
+ 
+ deliver:
+@@ -1666,7 +1720,7 @@ static int macsec_add_rxsa(struct sk_buff *skb, struct genl_info *info)
+ 
+ 	if (tb_sa[MACSEC_SA_ATTR_PN]) {
+ 		spin_lock_bh(&rx_sa->lock);
+-		rx_sa->next_pn = nla_get_u32(tb_sa[MACSEC_SA_ATTR_PN]);
++		rx_sa->next_pn_halves.lower = nla_get_u32(tb_sa[MACSEC_SA_ATTR_PN]);
+ 		spin_unlock_bh(&rx_sa->lock);
+ 	}
+ 
+@@ -1873,7 +1927,7 @@ static int macsec_add_txsa(struct sk_buff *skb, struct genl_info *info)
+ 	}
+ 
+ 	spin_lock_bh(&tx_sa->lock);
+-	tx_sa->next_pn = nla_get_u32(tb_sa[MACSEC_SA_ATTR_PN]);
++	tx_sa->next_pn_halves.lower = nla_get_u32(tb_sa[MACSEC_SA_ATTR_PN]);
+ 	spin_unlock_bh(&tx_sa->lock);
+ 
+ 	if (tb_sa[MACSEC_SA_ATTR_ACTIVE])
+@@ -2137,9 +2191,11 @@ static int macsec_upd_txsa(struct sk_buff *skb, struct genl_info *info)
+ 	u8 assoc_num;
+ 	struct nlattr *tb_sa[MACSEC_SA_ATTR_MAX + 1];
+ 	bool was_operational, was_active;
+-	u32 prev_pn = 0;
++	pn_t prev_pn;
+ 	int ret = 0;
+ 
++	prev_pn.full64 = 0;
++
+ 	if (!attrs[MACSEC_ATTR_IFINDEX])
+ 		return -EINVAL;
+ 
+@@ -2159,8 +2215,8 @@ static int macsec_upd_txsa(struct sk_buff *skb, struct genl_info *info)
+ 
+ 	if (tb_sa[MACSEC_SA_ATTR_PN]) {
+ 		spin_lock_bh(&tx_sa->lock);
+-		prev_pn = tx_sa->next_pn;
+-		tx_sa->next_pn = nla_get_u32(tb_sa[MACSEC_SA_ATTR_PN]);
++		prev_pn = tx_sa->next_pn_halves;
++		tx_sa->next_pn_halves.lower = nla_get_u32(tb_sa[MACSEC_SA_ATTR_PN]);
+ 		spin_unlock_bh(&tx_sa->lock);
+ 	}
+ 
+@@ -2198,7 +2254,7 @@ static int macsec_upd_txsa(struct sk_buff *skb, struct genl_info *info)
+ cleanup:
+ 	if (tb_sa[MACSEC_SA_ATTR_PN]) {
+ 		spin_lock_bh(&tx_sa->lock);
+-		tx_sa->next_pn = prev_pn;
++		tx_sa->next_pn_halves = prev_pn;
+ 		spin_unlock_bh(&tx_sa->lock);
+ 	}
+ 	tx_sa->active = was_active;
+@@ -2218,9 +2274,11 @@ static int macsec_upd_rxsa(struct sk_buff *skb, struct genl_info *info)
+ 	struct nlattr *tb_rxsc[MACSEC_RXSC_ATTR_MAX + 1];
+ 	struct nlattr *tb_sa[MACSEC_SA_ATTR_MAX + 1];
+ 	bool was_active;
+-	u32 prev_pn = 0;
++	pn_t prev_pn;
+ 	int ret = 0;
+ 
++	prev_pn.full64 = 0;
++
+ 	if (!attrs[MACSEC_ATTR_IFINDEX])
+ 		return -EINVAL;
+ 
+@@ -2243,8 +2301,8 @@ static int macsec_upd_rxsa(struct sk_buff *skb, struct genl_info *info)
+ 
+ 	if (tb_sa[MACSEC_SA_ATTR_PN]) {
+ 		spin_lock_bh(&rx_sa->lock);
+-		prev_pn = rx_sa->next_pn;
+-		rx_sa->next_pn = nla_get_u32(tb_sa[MACSEC_SA_ATTR_PN]);
++		prev_pn = rx_sa->next_pn_halves;
++		rx_sa->next_pn_halves.lower = nla_get_u32(tb_sa[MACSEC_SA_ATTR_PN]);
+ 		spin_unlock_bh(&rx_sa->lock);
+ 	}
+ 
+@@ -2277,7 +2335,7 @@ static int macsec_upd_rxsa(struct sk_buff *skb, struct genl_info *info)
+ cleanup:
+ 	if (tb_sa[MACSEC_SA_ATTR_PN]) {
+ 		spin_lock_bh(&rx_sa->lock);
+-		rx_sa->next_pn = prev_pn;
++		rx_sa->next_pn_halves = prev_pn;
+ 		spin_unlock_bh(&rx_sa->lock);
+ 	}
+ 	rx_sa->active = was_active;
+@@ -2796,7 +2854,7 @@ dump_secy(struct macsec_secy *secy, struct net_device *dev,
+ 		}
+ 
+ 		if (nla_put_u8(skb, MACSEC_SA_ATTR_AN, i) ||
+-		    nla_put_u32(skb, MACSEC_SA_ATTR_PN, tx_sa->next_pn) ||
++		    nla_put_u32(skb, MACSEC_SA_ATTR_PN, tx_sa->next_pn_halves.lower) ||
+ 		    nla_put(skb, MACSEC_SA_ATTR_KEYID, MACSEC_KEYID_LEN, tx_sa->key.id) ||
+ 		    nla_put_u8(skb, MACSEC_SA_ATTR_ACTIVE, tx_sa->active)) {
+ 			nla_nest_cancel(skb, txsa_nest);
+@@ -2900,7 +2958,7 @@ dump_secy(struct macsec_secy *secy, struct net_device *dev,
+ 			nla_nest_end(skb, attr);
+ 
+ 			if (nla_put_u8(skb, MACSEC_SA_ATTR_AN, i) ||
+-			    nla_put_u32(skb, MACSEC_SA_ATTR_PN, rx_sa->next_pn) ||
++			    nla_put_u32(skb, MACSEC_SA_ATTR_PN, rx_sa->next_pn_halves.lower) ||
+ 			    nla_put(skb, MACSEC_SA_ATTR_KEYID, MACSEC_KEYID_LEN, rx_sa->key.id) ||
+ 			    nla_put_u8(skb, MACSEC_SA_ATTR_ACTIVE, rx_sa->active)) {
+ 				nla_nest_cancel(skb, rxsa_nest);
+diff --git a/include/net/macsec.h b/include/net/macsec.h
+index 92e43db8b5667..43cd54e178770 100644
+--- a/include/net/macsec.h
++++ b/include/net/macsec.h
+@@ -11,18 +11,45 @@
+ #include <uapi/linux/if_link.h>
+ #include <uapi/linux/if_macsec.h>
+ 
++#define MACSEC_SALT_LEN 12
++#define MACSEC_NUM_AN 4 /* 2 bits for the association number */
++
+ typedef u64 __bitwise sci_t;
++typedef u32 __bitwise ssci_t;
+ 
+-#define MACSEC_NUM_AN 4 /* 2 bits for the association number */
++typedef union salt {
++	struct {
++		u32 ssci;
++		u64 pn;
++	} __packed;
++	u8 bytes[MACSEC_SALT_LEN];
++} __packed salt_t;
++
++typedef union pn {
++	struct {
++#if defined(__LITTLE_ENDIAN_BITFIELD)
++		u32 lower;
++		u32 upper;
++#elif defined(__BIG_ENDIAN_BITFIELD)
++		u32 upper;
++		u32 lower;
++#else
++#error	"Please fix <asm/byteorder.h>"
++#endif
++	};
++	u64 full64;
++} pn_t;
+ 
+ /**
+  * struct macsec_key - SA key
+  * @id: user-provided key identifier
+  * @tfm: crypto struct, key storage
++ * @salt: salt used to generate IV in XPN cipher suites
+  */
+ struct macsec_key {
+ 	u8 id[MACSEC_KEYID_LEN];
+ 	struct crypto_aead *tfm;
++	salt_t salt;
+ };
+ 
+ struct macsec_rx_sc_stats {
+@@ -64,12 +91,17 @@ struct macsec_tx_sc_stats {
+  * @next_pn: packet number expected for the next packet
+  * @lock: protects next_pn manipulations
+  * @key: key structure
++ * @ssci: short secure channel identifier
+  * @stats: per-SA stats
+  */
+ struct macsec_rx_sa {
+ 	struct macsec_key key;
++	ssci_t ssci;
+ 	spinlock_t lock;
+-	u32 next_pn;
++	union {
++		pn_t next_pn_halves;
++		u64 next_pn;
++	};
+ 	refcount_t refcnt;
+ 	bool active;
+ 	struct macsec_rx_sa_stats __percpu *stats;
+@@ -110,12 +142,17 @@ struct macsec_rx_sc {
+  * @next_pn: packet number to use for the next packet
+  * @lock: protects next_pn manipulations
+  * @key: key structure
++ * @ssci: short secure channel identifier
+  * @stats: per-SA stats
+  */
+ struct macsec_tx_sa {
+ 	struct macsec_key key;
++	ssci_t ssci;
+ 	spinlock_t lock;
+-	u32 next_pn;
++	union {
++		pn_t next_pn_halves;
++		u64 next_pn;
++	};
+ 	refcount_t refcnt;
+ 	bool active;
+ 	struct macsec_tx_sa_stats __percpu *stats;
+@@ -152,6 +189,7 @@ struct macsec_tx_sc {
+  * @key_len: length of keys used by the cipher suite
+  * @icv_len: length of ICV used by the cipher suite
+  * @validate_frames: validation mode
++ * @xpn: enable XPN for this SecY
+  * @operational: MAC_Operational flag
+  * @protect_frames: enable protection for this SecY
+  * @replay_protect: enable packet number checks on receive
+@@ -166,6 +204,7 @@ struct macsec_secy {
+ 	u16 key_len;
+ 	u16 icv_len;
+ 	enum macsec_validation_type validate_frames;
++	bool xpn;
+ 	bool operational;
+ 	bool protect_frames;
+ 	bool replay_protect;
+-- 
+cgit 1.2.3-1.el7
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1763-v5.18-net-macsec-Netlink-support-of-XPN-cipher-suites-IEEE802.1AEbw.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1763-v5.18-net-macsec-Netlink-support-of-XPN-cipher-suites-IEEE802.1AEbw.patch
new file mode 100644
index 0000000..2d00be3
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1763-v5.18-net-macsec-Netlink-support-of-XPN-cipher-suites-IEEE802.1AEbw.patch
@@ -0,0 +1,452 @@
+From 48ef50fa866aae087f63c7de8a47e76537f88691 Mon Sep 17 00:00:00 2001
+From: Era Mayflower <mayflowerera@gmail.com>
+Date: Mon, 9 Mar 2020 19:47:02 +0000
+Subject: macsec: Netlink support of XPN cipher suites (IEEE 802.1AEbw)
+
+Netlink support of extended packet number cipher suites,
+allows adding and updating XPN macsec interfaces.
+
+Added support in:
+    * Creating interfaces with GCM-AES-XPN-128 and GCM-AES-XPN-256 suites.
+    * Setting and getting 64bit packet numbers with of SAs.
+    * Setting (only on SA creation) and getting ssci of SAs.
+    * Setting salt when installing a SAK.
+
+Added 2 cipher suite identifiers according to 802.1AE-2018 table 14-1:
+    * MACSEC_CIPHER_ID_GCM_AES_XPN_128
+    * MACSEC_CIPHER_ID_GCM_AES_XPN_256
+
+In addition, added 2 new netlink attribute types:
+    * MACSEC_SA_ATTR_SSCI
+    * MACSEC_SA_ATTR_SALT
+
+Depends on: macsec: Support XPN frame handling - IEEE 802.1AEbw.
+
+Signed-off-by: Era Mayflower <mayflowerera@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/macsec.c           | 161 +++++++++++++++++++++++++++++++++++++----
+ include/net/macsec.h           |   3 +
+ include/uapi/linux/if_macsec.h |   8 +-
+ 3 files changed, 157 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
+index 6c71e250cccb0..49b138e7aeac3 100644
+--- a/drivers/net/macsec.c
++++ b/drivers/net/macsec.c
+@@ -240,11 +240,13 @@ static struct macsec_cb *macsec_skb_cb(struct sk_buff *skb)
+ #define MACSEC_PORT_ES (htons(0x0001))
+ #define MACSEC_PORT_SCB (0x0000)
+ #define MACSEC_UNDEF_SCI ((__force sci_t)0xffffffffffffffffULL)
++#define MACSEC_UNDEF_SSCI ((__force ssci_t)0xffffffff)
+ 
+ #define MACSEC_GCM_AES_128_SAK_LEN 16
+ #define MACSEC_GCM_AES_256_SAK_LEN 32
+ 
+ #define DEFAULT_SAK_LEN MACSEC_GCM_AES_128_SAK_LEN
++#define DEFAULT_XPN false
+ #define DEFAULT_SEND_SCI true
+ #define DEFAULT_ENCRYPT false
+ #define DEFAULT_ENCODING_SA 0
+@@ -1311,6 +1313,7 @@ static int init_rx_sa(struct macsec_rx_sa *rx_sa, char *sak, int key_len,
+ 		return PTR_ERR(rx_sa->key.tfm);
+ 	}
+ 
++	rx_sa->ssci = MACSEC_UNDEF_SSCI;
+ 	rx_sa->active = false;
+ 	rx_sa->next_pn = 1;
+ 	refcount_set(&rx_sa->refcnt, 1);
+@@ -1409,6 +1412,7 @@ static int init_tx_sa(struct macsec_tx_sa *tx_sa, char *sak, int key_len,
+ 		return PTR_ERR(tx_sa->key.tfm);
+ 	}
+ 
++	tx_sa->ssci = MACSEC_UNDEF_SSCI;
+ 	tx_sa->active = false;
+ 	refcount_set(&tx_sa->refcnt, 1);
+ 	spin_lock_init(&tx_sa->lock);
+@@ -1452,6 +1456,16 @@ static int nla_put_sci(struct sk_buff *skb, int attrtype, sci_t value,
+ 	return nla_put_u64_64bit(skb, attrtype, (__force u64)value, padattr);
+ }
+ 
++static ssci_t nla_get_ssci(const struct nlattr *nla)
++{
++	return (__force ssci_t)nla_get_u32(nla);
++}
++
++static int nla_put_ssci(struct sk_buff *skb, int attrtype, ssci_t value)
++{
++	return nla_put_u32(skb, attrtype, (__force u64)value);
++}
++
+ static struct macsec_tx_sa *get_txsa_from_nl(struct net *net,
+ 					     struct nlattr **attrs,
+ 					     struct nlattr **tb_sa,
+@@ -1567,11 +1581,14 @@ static const struct nla_policy macsec_genl_rxsc_policy[NUM_MACSEC_RXSC_ATTR] = {
+ static const struct nla_policy macsec_genl_sa_policy[NUM_MACSEC_SA_ATTR] = {
+ 	[MACSEC_SA_ATTR_AN] = { .type = NLA_U8 },
+ 	[MACSEC_SA_ATTR_ACTIVE] = { .type = NLA_U8 },
+-	[MACSEC_SA_ATTR_PN] = { .type = NLA_U32 },
++	[MACSEC_SA_ATTR_PN] = { .type = NLA_MIN_LEN, .len = 4 },
+ 	[MACSEC_SA_ATTR_KEYID] = { .type = NLA_BINARY,
+ 				   .len = MACSEC_KEYID_LEN, },
+ 	[MACSEC_SA_ATTR_KEY] = { .type = NLA_BINARY,
+ 				 .len = MACSEC_MAX_KEY_LEN, },
++	[MACSEC_SA_ATTR_SSCI] = { .type = NLA_U32 },
++	[MACSEC_SA_ATTR_SALT] = { .type = NLA_BINARY,
++				  .len = MACSEC_SALT_LEN, },
+ };
+ 
+ static const struct nla_policy macsec_genl_offload_policy[NUM_MACSEC_OFFLOAD_ATTR] = {
+@@ -1644,7 +1661,8 @@ static bool validate_add_rxsa(struct nlattr **attrs)
+ 	if (nla_get_u8(attrs[MACSEC_SA_ATTR_AN]) >= MACSEC_NUM_AN)
+ 		return false;
+ 
+-	if (attrs[MACSEC_SA_ATTR_PN] && nla_get_u32(attrs[MACSEC_SA_ATTR_PN]) == 0)
++	if (attrs[MACSEC_SA_ATTR_PN] &&
++	    *(u64 *)nla_data(attrs[MACSEC_SA_ATTR_PN]) == 0)
+ 		return false;
+ 
+ 	if (attrs[MACSEC_SA_ATTR_ACTIVE]) {
+@@ -1666,6 +1684,7 @@ static int macsec_add_rxsa(struct sk_buff *skb, struct genl_info *info)
+ 	struct macsec_rx_sc *rx_sc;
+ 	struct macsec_rx_sa *rx_sa;
+ 	unsigned char assoc_num;
++	int pn_len;
+ 	struct nlattr *tb_rxsc[MACSEC_RXSC_ATTR_MAX + 1];
+ 	struct nlattr *tb_sa[MACSEC_SA_ATTR_MAX + 1];
+ 	int err;
+@@ -1698,6 +1717,29 @@ static int macsec_add_rxsa(struct sk_buff *skb, struct genl_info *info)
+ 		return -EINVAL;
+ 	}
+ 
++	pn_len = secy->xpn ? MACSEC_XPN_PN_LEN : MACSEC_DEFAULT_PN_LEN;
++	if (nla_len(tb_sa[MACSEC_SA_ATTR_PN]) != pn_len) {
++		pr_notice("macsec: nl: add_rxsa: bad pn length: %d != %d\n",
++			  nla_len(tb_sa[MACSEC_SA_ATTR_PN]), pn_len);
++		rtnl_unlock();
++		return -EINVAL;
++	}
++
++	if (secy->xpn) {
++		if (!tb_sa[MACSEC_SA_ATTR_SSCI] || !tb_sa[MACSEC_SA_ATTR_SALT]) {
++			rtnl_unlock();
++			return -EINVAL;
++		}
++
++		if (nla_len(tb_sa[MACSEC_SA_ATTR_SALT]) != MACSEC_SALT_LEN) {
++			pr_notice("macsec: nl: add_rxsa: bad salt length: %d != %d\n",
++				  nla_len(tb_sa[MACSEC_SA_ATTR_SALT]),
++				  MACSEC_SA_ATTR_SALT);
++			rtnl_unlock();
++			return -EINVAL;
++		}
++	}
++
+ 	rx_sa = rtnl_dereference(rx_sc->sa[assoc_num]);
+ 	if (rx_sa) {
+ 		rtnl_unlock();
+@@ -1720,7 +1762,7 @@ static int macsec_add_rxsa(struct sk_buff *skb, struct genl_info *info)
+ 
+ 	if (tb_sa[MACSEC_SA_ATTR_PN]) {
+ 		spin_lock_bh(&rx_sa->lock);
+-		rx_sa->next_pn_halves.lower = nla_get_u32(tb_sa[MACSEC_SA_ATTR_PN]);
++		rx_sa->next_pn = nla_get_u64(tb_sa[MACSEC_SA_ATTR_PN]);
+ 		spin_unlock_bh(&rx_sa->lock);
+ 	}
+ 
+@@ -1750,6 +1792,12 @@ static int macsec_add_rxsa(struct sk_buff *skb, struct genl_info *info)
+ 			goto cleanup;
+ 	}
+ 
++	if (secy->xpn) {
++		rx_sa->ssci = nla_get_ssci(tb_sa[MACSEC_SA_ATTR_SSCI]);
++		nla_memcpy(rx_sa->key.salt.bytes, tb_sa[MACSEC_SA_ATTR_SALT],
++			   MACSEC_SALT_LEN);
++	}
++
+ 	nla_memcpy(rx_sa->key.id, tb_sa[MACSEC_SA_ATTR_KEYID], MACSEC_KEYID_LEN);
+ 	rcu_assign_pointer(rx_sc->sa[assoc_num], rx_sa);
+ 
+@@ -1874,6 +1922,7 @@ static int macsec_add_txsa(struct sk_buff *skb, struct genl_info *info)
+ 	struct macsec_tx_sc *tx_sc;
+ 	struct macsec_tx_sa *tx_sa;
+ 	unsigned char assoc_num;
++	int pn_len;
+ 	struct nlattr *tb_sa[MACSEC_SA_ATTR_MAX + 1];
+ 	bool was_operational;
+ 	int err;
+@@ -1906,6 +1955,29 @@ static int macsec_add_txsa(struct sk_buff *skb, struct genl_info *info)
+ 		return -EINVAL;
+ 	}
+ 
++	pn_len = secy->xpn ? MACSEC_XPN_PN_LEN : MACSEC_DEFAULT_PN_LEN;
++	if (nla_len(tb_sa[MACSEC_SA_ATTR_PN]) != pn_len) {
++		pr_notice("macsec: nl: add_txsa: bad pn length: %d != %d\n",
++			  nla_len(tb_sa[MACSEC_SA_ATTR_PN]), pn_len);
++		rtnl_unlock();
++		return -EINVAL;
++	}
++
++	if (secy->xpn) {
++		if (!tb_sa[MACSEC_SA_ATTR_SSCI] || !tb_sa[MACSEC_SA_ATTR_SALT]) {
++			rtnl_unlock();
++			return -EINVAL;
++		}
++
++		if (nla_len(tb_sa[MACSEC_SA_ATTR_SALT]) != MACSEC_SALT_LEN) {
++			pr_notice("macsec: nl: add_txsa: bad salt length: %d != %d\n",
++				  nla_len(tb_sa[MACSEC_SA_ATTR_SALT]),
++				  MACSEC_SA_ATTR_SALT);
++			rtnl_unlock();
++			return -EINVAL;
++		}
++	}
++
+ 	tx_sa = rtnl_dereference(tx_sc->sa[assoc_num]);
+ 	if (tx_sa) {
+ 		rtnl_unlock();
+@@ -1927,7 +1999,7 @@ static int macsec_add_txsa(struct sk_buff *skb, struct genl_info *info)
+ 	}
+ 
+ 	spin_lock_bh(&tx_sa->lock);
+-	tx_sa->next_pn_halves.lower = nla_get_u32(tb_sa[MACSEC_SA_ATTR_PN]);
++	tx_sa->next_pn = nla_get_u64(tb_sa[MACSEC_SA_ATTR_PN]);
+ 	spin_unlock_bh(&tx_sa->lock);
+ 
+ 	if (tb_sa[MACSEC_SA_ATTR_ACTIVE])
+@@ -1958,6 +2030,12 @@ static int macsec_add_txsa(struct sk_buff *skb, struct genl_info *info)
+ 			goto cleanup;
+ 	}
+ 
++	if (secy->xpn) {
++		tx_sa->ssci = nla_get_ssci(tb_sa[MACSEC_SA_ATTR_SSCI]);
++		nla_memcpy(tx_sa->key.salt.bytes, tb_sa[MACSEC_SA_ATTR_SALT],
++			   MACSEC_SALT_LEN);
++	}
++
+ 	nla_memcpy(tx_sa->key.id, tb_sa[MACSEC_SA_ATTR_KEYID], MACSEC_KEYID_LEN);
+ 	rcu_assign_pointer(tx_sc->sa[assoc_num], tx_sa);
+ 
+@@ -2164,7 +2242,9 @@ static bool validate_upd_sa(struct nlattr **attrs)
+ {
+ 	if (!attrs[MACSEC_SA_ATTR_AN] ||
+ 	    attrs[MACSEC_SA_ATTR_KEY] ||
+-	    attrs[MACSEC_SA_ATTR_KEYID])
++	    attrs[MACSEC_SA_ATTR_KEYID] ||
++	    attrs[MACSEC_SA_ATTR_SSCI] ||
++	    attrs[MACSEC_SA_ATTR_SALT])
+ 		return false;
+ 
+ 	if (nla_get_u8(attrs[MACSEC_SA_ATTR_AN]) >= MACSEC_NUM_AN)
+@@ -2214,9 +2294,19 @@ static int macsec_upd_txsa(struct sk_buff *skb, struct genl_info *info)
+ 	}
+ 
+ 	if (tb_sa[MACSEC_SA_ATTR_PN]) {
++		int pn_len;
++
++		pn_len = secy->xpn ? MACSEC_XPN_PN_LEN : MACSEC_DEFAULT_PN_LEN;
++		if (nla_len(tb_sa[MACSEC_SA_ATTR_PN]) != pn_len) {
++			pr_notice("macsec: nl: upd_txsa: bad pn length: %d != %d\n",
++				  nla_len(tb_sa[MACSEC_SA_ATTR_PN]), pn_len);
++			rtnl_unlock();
++			return -EINVAL;
++		}
++
+ 		spin_lock_bh(&tx_sa->lock);
+ 		prev_pn = tx_sa->next_pn_halves;
+-		tx_sa->next_pn_halves.lower = nla_get_u32(tb_sa[MACSEC_SA_ATTR_PN]);
++		tx_sa->next_pn = nla_get_u64(tb_sa[MACSEC_SA_ATTR_PN]);
+ 		spin_unlock_bh(&tx_sa->lock);
+ 	}
+ 
+@@ -2300,9 +2390,19 @@ static int macsec_upd_rxsa(struct sk_buff *skb, struct genl_info *info)
+ 	}
+ 
+ 	if (tb_sa[MACSEC_SA_ATTR_PN]) {
++		int pn_len;
++
++		pn_len = secy->xpn ? MACSEC_XPN_PN_LEN : MACSEC_DEFAULT_PN_LEN;
++		if (nla_len(tb_sa[MACSEC_SA_ATTR_PN]) != pn_len) {
++			pr_notice("macsec: nl: upd_rxsa: bad pn length: %d != %d\n",
++				  nla_len(tb_sa[MACSEC_SA_ATTR_PN]), pn_len);
++			rtnl_unlock();
++			return -EINVAL;
++		}
++
+ 		spin_lock_bh(&rx_sa->lock);
+ 		prev_pn = rx_sa->next_pn_halves;
+-		rx_sa->next_pn_halves.lower = nla_get_u32(tb_sa[MACSEC_SA_ATTR_PN]);
++		rx_sa->next_pn = nla_get_u64(tb_sa[MACSEC_SA_ATTR_PN]);
+ 		spin_unlock_bh(&rx_sa->lock);
+ 	}
+ 
+@@ -2749,10 +2849,10 @@ static int nla_put_secy(struct macsec_secy *secy, struct sk_buff *skb)
+ 
+ 	switch (secy->key_len) {
+ 	case MACSEC_GCM_AES_128_SAK_LEN:
+-		csid = MACSEC_DEFAULT_CIPHER_ID;
++		csid = secy->xpn ? MACSEC_CIPHER_ID_GCM_AES_XPN_128 : MACSEC_DEFAULT_CIPHER_ID;
+ 		break;
+ 	case MACSEC_GCM_AES_256_SAK_LEN:
+-		csid = MACSEC_CIPHER_ID_GCM_AES_256;
++		csid = secy->xpn ? MACSEC_CIPHER_ID_GCM_AES_XPN_256 : MACSEC_CIPHER_ID_GCM_AES_256;
+ 		break;
+ 	default:
+ 		goto cancel;
+@@ -2843,6 +2943,8 @@ dump_secy(struct macsec_secy *secy, struct net_device *dev,
+ 	for (i = 0, j = 1; i < MACSEC_NUM_AN; i++) {
+ 		struct macsec_tx_sa *tx_sa = rtnl_dereference(tx_sc->sa[i]);
+ 		struct nlattr *txsa_nest;
++		u64 pn;
++		int pn_len;
+ 
+ 		if (!tx_sa)
+ 			continue;
+@@ -2853,9 +2955,18 @@ dump_secy(struct macsec_secy *secy, struct net_device *dev,
+ 			goto nla_put_failure;
+ 		}
+ 
++		if (secy->xpn) {
++			pn = tx_sa->next_pn;
++			pn_len = MACSEC_XPN_PN_LEN;
++		} else {
++			pn = tx_sa->next_pn_halves.lower;
++			pn_len = MACSEC_DEFAULT_PN_LEN;
++		}
++
+ 		if (nla_put_u8(skb, MACSEC_SA_ATTR_AN, i) ||
+-		    nla_put_u32(skb, MACSEC_SA_ATTR_PN, tx_sa->next_pn_halves.lower) ||
++		    nla_put(skb, MACSEC_SA_ATTR_PN, pn_len, &pn) ||
+ 		    nla_put(skb, MACSEC_SA_ATTR_KEYID, MACSEC_KEYID_LEN, tx_sa->key.id) ||
++		    (secy->xpn && nla_put_ssci(skb, MACSEC_SA_ATTR_SSCI, tx_sa->ssci)) ||
+ 		    nla_put_u8(skb, MACSEC_SA_ATTR_ACTIVE, tx_sa->active)) {
+ 			nla_nest_cancel(skb, txsa_nest);
+ 			nla_nest_cancel(skb, txsa_list);
+@@ -2928,6 +3039,8 @@ dump_secy(struct macsec_secy *secy, struct net_device *dev,
+ 		for (i = 0, k = 1; i < MACSEC_NUM_AN; i++) {
+ 			struct macsec_rx_sa *rx_sa = rtnl_dereference(rx_sc->sa[i]);
+ 			struct nlattr *rxsa_nest;
++			u64 pn;
++			int pn_len;
+ 
+ 			if (!rx_sa)
+ 				continue;
+@@ -2957,9 +3070,18 @@ dump_secy(struct macsec_secy *secy, struct net_device *dev,
+ 			}
+ 			nla_nest_end(skb, attr);
+ 
++			if (secy->xpn) {
++				pn = rx_sa->next_pn;
++				pn_len = MACSEC_XPN_PN_LEN;
++			} else {
++				pn = rx_sa->next_pn_halves.lower;
++				pn_len = MACSEC_DEFAULT_PN_LEN;
++			}
++
+ 			if (nla_put_u8(skb, MACSEC_SA_ATTR_AN, i) ||
+-			    nla_put_u32(skb, MACSEC_SA_ATTR_PN, rx_sa->next_pn_halves.lower) ||
++			    nla_put(skb, MACSEC_SA_ATTR_PN, pn_len, &pn) ||
+ 			    nla_put(skb, MACSEC_SA_ATTR_KEYID, MACSEC_KEYID_LEN, rx_sa->key.id) ||
++			    (secy->xpn && nla_put_ssci(skb, MACSEC_SA_ATTR_SSCI, rx_sa->ssci)) ||
+ 			    nla_put_u8(skb, MACSEC_SA_ATTR_ACTIVE, rx_sa->active)) {
+ 				nla_nest_cancel(skb, rxsa_nest);
+ 				nla_nest_cancel(skb, rxsc_nest);
+@@ -3503,9 +3625,19 @@ static int macsec_changelink_common(struct net_device *dev,
+ 		case MACSEC_CIPHER_ID_GCM_AES_128:
+ 		case MACSEC_DEFAULT_CIPHER_ID:
+ 			secy->key_len = MACSEC_GCM_AES_128_SAK_LEN;
++			secy->xpn = false;
+ 			break;
+ 		case MACSEC_CIPHER_ID_GCM_AES_256:
+ 			secy->key_len = MACSEC_GCM_AES_256_SAK_LEN;
++			secy->xpn = false;
++			break;
++		case MACSEC_CIPHER_ID_GCM_AES_XPN_128:
++			secy->key_len = MACSEC_GCM_AES_128_SAK_LEN;
++			secy->xpn = true;
++			break;
++		case MACSEC_CIPHER_ID_GCM_AES_XPN_256:
++			secy->key_len = MACSEC_GCM_AES_256_SAK_LEN;
++			secy->xpn = true;
+ 			break;
+ 		default:
+ 			return -EINVAL;
+@@ -3695,6 +3827,7 @@ static int macsec_add_dev(struct net_device *dev, sci_t sci, u8 icv_len)
+ 	secy->validate_frames = MACSEC_VALIDATE_DEFAULT;
+ 	secy->protect_frames = true;
+ 	secy->replay_protect = false;
++	secy->xpn = DEFAULT_XPN;
+ 
+ 	secy->sci = sci;
+ 	secy->tx_sc.active = true;
+@@ -3824,6 +3957,8 @@ static int macsec_validate_attr(struct nlattr *tb[], struct nlattr *data[],
+ 	switch (csid) {
+ 	case MACSEC_CIPHER_ID_GCM_AES_128:
+ 	case MACSEC_CIPHER_ID_GCM_AES_256:
++	case MACSEC_CIPHER_ID_GCM_AES_XPN_128:
++	case MACSEC_CIPHER_ID_GCM_AES_XPN_256:
+ 	case MACSEC_DEFAULT_CIPHER_ID:
+ 		if (icv_len < MACSEC_MIN_ICV_LEN ||
+ 		    icv_len > MACSEC_STD_ICV_LEN)
+@@ -3897,10 +4032,10 @@ static int macsec_fill_info(struct sk_buff *skb,
+ 
+ 	switch (secy->key_len) {
+ 	case MACSEC_GCM_AES_128_SAK_LEN:
+-		csid = MACSEC_DEFAULT_CIPHER_ID;
++		csid = secy->xpn ? MACSEC_CIPHER_ID_GCM_AES_XPN_128 : MACSEC_DEFAULT_CIPHER_ID;
+ 		break;
+ 	case MACSEC_GCM_AES_256_SAK_LEN:
+-		csid = MACSEC_CIPHER_ID_GCM_AES_256;
++		csid = secy->xpn ? MACSEC_CIPHER_ID_GCM_AES_XPN_256 : MACSEC_CIPHER_ID_GCM_AES_256;
+ 		break;
+ 	default:
+ 		goto nla_put_failure;
+diff --git a/include/net/macsec.h b/include/net/macsec.h
+index 43cd54e178770..2e4780dbf5c6a 100644
+--- a/include/net/macsec.h
++++ b/include/net/macsec.h
+@@ -11,6 +11,9 @@
+ #include <uapi/linux/if_link.h>
+ #include <uapi/linux/if_macsec.h>
+ 
++#define MACSEC_DEFAULT_PN_LEN 4
++#define MACSEC_XPN_PN_LEN 8
++
+ #define MACSEC_SALT_LEN 12
+ #define MACSEC_NUM_AN 4 /* 2 bits for the association number */
+ 
+diff --git a/include/uapi/linux/if_macsec.h b/include/uapi/linux/if_macsec.h
+index 1d63c43c38cca..3af2aa069a367 100644
+--- a/include/uapi/linux/if_macsec.h
++++ b/include/uapi/linux/if_macsec.h
+@@ -22,9 +22,11 @@
+ 
+ #define MACSEC_KEYID_LEN 16
+ 
+-/* cipher IDs as per IEEE802.1AEbn-2011 */
++/* cipher IDs as per IEEE802.1AE-2018 (Table 14-1) */
+ #define MACSEC_CIPHER_ID_GCM_AES_128 0x0080C20001000001ULL
+ #define MACSEC_CIPHER_ID_GCM_AES_256 0x0080C20001000002ULL
++#define MACSEC_CIPHER_ID_GCM_AES_XPN_128 0x0080C20001000003ULL
++#define MACSEC_CIPHER_ID_GCM_AES_XPN_256 0x0080C20001000004ULL
+ 
+ /* deprecated cipher ID for GCM-AES-128 */
+ #define MACSEC_DEFAULT_CIPHER_ID     0x0080020001000001ULL
+@@ -88,11 +90,13 @@ enum macsec_sa_attrs {
+ 	MACSEC_SA_ATTR_UNSPEC,
+ 	MACSEC_SA_ATTR_AN,     /* config/dump, u8 0..3 */
+ 	MACSEC_SA_ATTR_ACTIVE, /* config/dump, u8 0..1 */
+-	MACSEC_SA_ATTR_PN,     /* config/dump, u32 */
++	MACSEC_SA_ATTR_PN,     /* config/dump, u32/u64 (u64 if XPN) */
+ 	MACSEC_SA_ATTR_KEY,    /* config, data */
+ 	MACSEC_SA_ATTR_KEYID,  /* config/dump, 128-bit */
+ 	MACSEC_SA_ATTR_STATS,  /* dump, nested, macsec_sa_stats_attr */
+ 	MACSEC_SA_ATTR_PAD,
++	MACSEC_SA_ATTR_SSCI,   /* config/dump, u32 - XPN only */
++	MACSEC_SA_ATTR_SALT,   /* config, 96-bit - XPN only */
+ 	__MACSEC_SA_ATTR_END,
+ 	NUM_MACSEC_SA_ATTR = __MACSEC_SA_ATTR_END,
+ 	MACSEC_SA_ATTR_MAX = __MACSEC_SA_ATTR_END - 1,
+-- 
+cgit 1.2.3-1.el7
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1764-v5.18-net-macsec-restrict-to-ethernet-devices.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1764-v5.18-net-macsec-restrict-to-ethernet-devices.patch
new file mode 100644
index 0000000..bae5efa
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1764-v5.18-net-macsec-restrict-to-ethernet-devices.patch
@@ -0,0 +1,41 @@
+From b06d072ccc4b1acd0147b17914b7ad1caa1818bb Mon Sep 17 00:00:00 2001
+From: Willem de Bruijn <willemb@google.com>
+Date: Sun, 22 Mar 2020 13:51:13 -0400
+Subject: macsec: restrict to ethernet devices
+
+Only attach macsec to ethernet devices.
+
+Syzbot was able to trigger a KMSAN warning in macsec_handle_frame
+by attaching to a phonet device.
+
+Macvlan has a similar check in macvlan_port_create.
+
+v1->v2
+  - fix commit message typo
+
+Reported-by: syzbot <syzkaller@googlegroups.com>
+Signed-off-by: Willem de Bruijn <willemb@google.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/macsec.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/net/macsec.c
++++ b/drivers/net/macsec.c
+@@ -20,6 +20,7 @@
+ #include <net/macsec.h>
+ #include <linux/phy.h>
+ #include <linux/byteorder/generic.h>
++#include <linux/if_arp.h>
+ 
+ #include <uapi/linux/if_macsec.h>
+ 
+@@ -3859,6 +3860,8 @@ static int macsec_newlink(struct net *ne
+ 	real_dev = __dev_get_by_index(net, nla_get_u32(tb[IFLA_LINK]));
+ 	if (!real_dev)
+ 		return -ENODEV;
++	if (real_dev->type != ARPHRD_ETHER)
++		return -EINVAL;
+ 
+ 	dev->priv_flags |= IFF_MACSEC;
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1765-01-v5.18-net-introduce-the-MACSEC-netdev-feature.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1765-01-v5.18-net-introduce-the-MACSEC-netdev-feature.patch
new file mode 100644
index 0000000..fa99dfb
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1765-01-v5.18-net-introduce-the-MACSEC-netdev-feature.patch
@@ -0,0 +1,39 @@
+From 5908220b2b3d6918f88cd645a39e1dcb84d1c5d9 Mon Sep 17 00:00:00 2001
+From: Antoine Tenart <antoine.tenart@bootlin.com>
+Date: Wed, 25 Mar 2020 15:52:30 +0300
+Subject: net: introduce the MACSEC netdev feature
+
+This patch introduce a new netdev feature, which will be used by drivers
+to state they can perform MACsec transformations in hardware.
+
+The patchset was gathered by Mark, macsec functinality itself
+was implemented by Dmitry, Mark and Pavel Belous.
+
+Signed-off-by: Antoine Tenart <antoine.tenart@bootlin.com>
+Signed-off-by: Mark Starovoytov <mstarovoitov@marvell.com>
+Signed-off-by: Igor Russkikh <irusskikh@marvell.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ include/linux/netdev_features.h | 3 +++
+ net/ethtool/common.c            | 1 +
+ 2 files changed, 4 insertions(+)
+
+--- a/include/linux/netdev_features.h
++++ b/include/linux/netdev_features.h
+@@ -81,6 +81,8 @@ enum {
+ 	NETIF_F_GRO_HW_BIT,		/* Hardware Generic receive offload */
+ 	NETIF_F_HW_TLS_RECORD_BIT,	/* Offload TLS record */
+ 
++	NETIF_F_HW_MACSEC_BIT,		/* Offload MACsec operations */
++
+ 	/*
+ 	 * Add your fresh new feature above and remember to update
+ 	 * netdev_features_strings[] in net/ethtool/common.c and maybe
+@@ -150,6 +152,7 @@ enum {
+ #define NETIF_F_GSO_UDP_L4	__NETIF_F(GSO_UDP_L4)
+ #define NETIF_F_HW_TLS_TX	__NETIF_F(HW_TLS_TX)
+ #define NETIF_F_HW_TLS_RX	__NETIF_F(HW_TLS_RX)
++#define NETIF_F_HW_MACSEC	__NETIF_F(HW_MACSEC)
+ 
+ /* Finds the next feature with the highest number of the range of start till 0.
+  */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1766-02-v5.18-net-add-a-reference-to-MACsec-ops-in-net_device.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1766-02-v5.18-net-add-a-reference-to-MACsec-ops-in-net_device.patch
new file mode 100644
index 0000000..c3372fd
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1766-02-v5.18-net-add-a-reference-to-MACsec-ops-in-net_device.patch
@@ -0,0 +1,49 @@
+From 30e9bb8472f4454d0544020574bb03d96ffa0e52 Mon Sep 17 00:00:00 2001
+From: Antoine Tenart <antoine.tenart@bootlin.com>
+Date: Wed, 25 Mar 2020 15:52:31 +0300
+Subject: net: add a reference to MACsec ops in net_device
+
+This patch adds a reference to MACsec ops to the net_device structure,
+allowing net device drivers to implement offloading operations for
+MACsec.
+
+Signed-off-by: Antoine Tenart <antoine.tenart@bootlin.com>
+Signed-off-by: Mark Starovoytov <mstarovoitov@marvell.com>
+Signed-off-by: Igor Russkikh <irusskikh@marvell.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ include/linux/netdevice.h | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -53,6 +53,8 @@ struct netpoll_info;
+ struct device;
+ struct phy_device;
+ struct dsa_port;
++struct macsec_context;
++struct macsec_ops;
+ 
+ struct sfp_bus;
+ /* 802.11 specific */
+@@ -1805,6 +1807,8 @@ enum netdev_ml_priv_type {
+  *
+  *	@threaded:	napi threaded mode is enabled
+  *
++ *	@macsec_ops:    MACsec offloading ops
++ *
+  *	FIXME: cleanup struct net_device such that network protocol info
+  *	moves out.
+  */
+@@ -2109,6 +2113,11 @@ struct net_device {
+ 	bool			proto_down;
+ 	unsigned		wol_enabled:1;
+ 	unsigned		threaded:1;
++
++#if IS_ENABLED(CONFIG_MACSEC)
++	/* MACsec management functions */
++	const struct macsec_ops *macsec_ops;
++#endif
+ };
+ #define to_net_dev(d) container_of(d, struct net_device, dev)
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1767-03-v5.18-net-macsec-allow-to-reference-a-netdev-from-a-MACsec-context.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1767-03-v5.18-net-macsec-allow-to-reference-a-netdev-from-a-MACsec-context.patch
new file mode 100644
index 0000000..b3ef8df
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1767-03-v5.18-net-macsec-allow-to-reference-a-netdev-from-a-MACsec-context.patch
@@ -0,0 +1,35 @@
+From 8fa9137180b2fd8482b671f7e0bd8cf7538cbf59 Mon Sep 17 00:00:00 2001
+From: Antoine Tenart <antoine.tenart@bootlin.com>
+Date: Wed, 25 Mar 2020 15:52:32 +0300
+Subject: net: macsec: allow to reference a netdev from a MACsec context
+
+This patch allows to reference a net_device from a MACsec context. This
+is needed to allow implementing MACsec operations in net device drivers.
+
+Signed-off-by: Antoine Tenart <antoine.tenart@bootlin.com>
+Signed-off-by: Mark Starovoytov <mstarovoitov@marvell.com>
+Signed-off-by: Igor Russkikh <irusskikh@marvell.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ include/net/macsec.h | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/include/net/macsec.h b/include/net/macsec.h
+index 2e4780dbf5c6a..71de2c863df70 100644
+--- a/include/net/macsec.h
++++ b/include/net/macsec.h
+@@ -220,7 +220,10 @@ struct macsec_secy {
+  * struct macsec_context - MACsec context for hardware offloading
+  */
+ struct macsec_context {
+-	struct phy_device *phydev;
++	union {
++		struct net_device *netdev;
++		struct phy_device *phydev;
++	};
+ 	enum macsec_offload offload;
+ 
+ 	struct macsec_secy *secy;
+-- 
+cgit 1.2.3-1.el7
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1768-04-v5.18-net-macsec-add-support-for-offloading-to-the-MAC.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1768-04-v5.18-net-macsec-add-support-for-offloading-to-the-MAC.patch
new file mode 100644
index 0000000..6b5dd5d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1768-04-v5.18-net-macsec-add-support-for-offloading-to-the-MAC.patch
@@ -0,0 +1,77 @@
+From 21114b7feec29e4425a3ac48a037569c016a46c8 Mon Sep 17 00:00:00 2001
+From: Antoine Tenart <antoine.tenart@bootlin.com>
+Date: Wed, 25 Mar 2020 15:52:33 +0300
+Subject: net: macsec: add support for offloading to the MAC
+
+This patch adds a new MACsec offloading option, MACSEC_OFFLOAD_MAC,
+allowing a user to select a MAC as a provider for MACsec offloading
+operations.
+
+Signed-off-by: Antoine Tenart <antoine.tenart@bootlin.com>
+Signed-off-by: Mark Starovoytov <mstarovoitov@marvell.com>
+Signed-off-by: Igor Russkikh <irusskikh@marvell.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/macsec.c               | 13 +++++++++++--
+ include/uapi/linux/if_link.h       |  1 +
+ tools/include/uapi/linux/if_link.h |  1 +
+ 3 files changed, 13 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/macsec.c
++++ b/drivers/net/macsec.c
+@@ -339,7 +339,8 @@ static void macsec_set_shortlen(struct m
+ /* Checks if a MACsec interface is being offloaded to an hardware engine */
+ static bool macsec_is_offloaded(struct macsec_dev *macsec)
+ {
+-	if (macsec->offload == MACSEC_OFFLOAD_PHY)
++	if (macsec->offload == MACSEC_OFFLOAD_MAC ||
++	    macsec->offload == MACSEC_OFFLOAD_PHY)
+ 		return true;
+ 
+ 	return false;
+@@ -355,6 +356,9 @@ static bool macsec_check_offload(enum ma
+ 	if (offload == MACSEC_OFFLOAD_PHY)
+ 		return macsec->real_dev->phydev &&
+ 		       macsec->real_dev->phydev->macsec_ops;
++	else if (offload == MACSEC_OFFLOAD_MAC)
++		return macsec->real_dev->features & NETIF_F_HW_MACSEC &&
++		       macsec->real_dev->macsec_ops;
+ 
+ 	return false;
+ }
+@@ -369,9 +373,14 @@ static const struct macsec_ops *__macsec
+ 
+ 		if (offload == MACSEC_OFFLOAD_PHY)
+ 			ctx->phydev = macsec->real_dev->phydev;
++		else if (offload == MACSEC_OFFLOAD_MAC)
++			ctx->netdev = macsec->real_dev;
+ 	}
+ 
+-	return macsec->real_dev->phydev->macsec_ops;
++	if (offload == MACSEC_OFFLOAD_PHY)
++		return macsec->real_dev->phydev->macsec_ops;
++	else
++		return macsec->real_dev->macsec_ops;
+ }
+ 
+ /* Returns a pointer to the MACsec ops struct if any and updates the MACsec
+--- a/include/uapi/linux/if_link.h
++++ b/include/uapi/linux/if_link.h
+@@ -486,6 +486,7 @@ enum macsec_validation_type {
+ enum macsec_offload {
+ 	MACSEC_OFFLOAD_OFF = 0,
+ 	MACSEC_OFFLOAD_PHY = 1,
++	MACSEC_OFFLOAD_MAC = 2,
+ 	__MACSEC_OFFLOAD_END,
+ 	MACSEC_OFFLOAD_MAX = __MACSEC_OFFLOAD_END - 1,
+ };
+--- a/tools/include/uapi/linux/if_link.h
++++ b/tools/include/uapi/linux/if_link.h
+@@ -486,6 +486,7 @@ enum macsec_validation_type {
+ enum macsec_offload {
+ 	MACSEC_OFFLOAD_OFF = 0,
+ 	MACSEC_OFFLOAD_PHY = 1,
++	MACSEC_OFFLOAD_MAC = 2,
+ 	__MACSEC_OFFLOAD_END,
+ 	MACSEC_OFFLOAD_MAX = __MACSEC_OFFLOAD_END - 1,
+ };
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1769-05-v5.18-net-macsec-init-secy-pointer-in-macsec_context.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1769-05-v5.18-net-macsec-init-secy-pointer-in-macsec_context.patch
new file mode 100644
index 0000000..017e415
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1769-05-v5.18-net-macsec-init-secy-pointer-in-macsec_context.patch
@@ -0,0 +1,131 @@
+From 182879f89b858fede98136ea3ad45fe9c7178387 Mon Sep 17 00:00:00 2001
+From: Dmitry Bogdanov <dbogdanov@marvell.com>
+Date: Wed, 25 Mar 2020 15:52:34 +0300
+Subject: net: macsec: init secy pointer in macsec_context
+
+This patch adds secy pointer initialization in the macsec_context.
+It will be used by MAC drivers in offloading operations.
+
+Signed-off-by: Dmitry Bogdanov <dbogdanov@marvell.com>
+Signed-off-by: Mark Starovoytov <mstarovoitov@marvell.com>
+Signed-off-by: Igor Russkikh <irusskikh@marvell.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/macsec.c | 16 +++++++++++++++-
+ 1 file changed, 15 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
+index d29c072e19af6..093e81d605ec7 100644
+--- a/drivers/net/macsec.c
++++ b/drivers/net/macsec.c
+@@ -1794,6 +1794,7 @@ static int macsec_add_rxsa(struct sk_buff *skb, struct genl_info *info)
+ 
+ 		ctx.sa.assoc_num = assoc_num;
+ 		ctx.sa.rx_sa = rx_sa;
++		ctx.secy = secy;
+ 		memcpy(ctx.sa.key, nla_data(tb_sa[MACSEC_SA_ATTR_KEY]),
+ 		       MACSEC_KEYID_LEN);
+ 
+@@ -1841,6 +1842,7 @@ static int macsec_add_rxsc(struct sk_buff *skb, struct genl_info *info)
+ 	struct nlattr **attrs = info->attrs;
+ 	struct macsec_rx_sc *rx_sc;
+ 	struct nlattr *tb_rxsc[MACSEC_RXSC_ATTR_MAX + 1];
++	struct macsec_secy *secy;
+ 	bool was_active;
+ 	int ret;
+ 
+@@ -1860,6 +1862,7 @@ static int macsec_add_rxsc(struct sk_buff *skb, struct genl_info *info)
+ 		return PTR_ERR(dev);
+ 	}
+ 
++	secy = &macsec_priv(dev)->secy;
+ 	sci = nla_get_sci(tb_rxsc[MACSEC_RXSC_ATTR_SCI]);
+ 
+ 	rx_sc = create_rx_sc(dev, sci);
+@@ -1883,6 +1886,7 @@ static int macsec_add_rxsc(struct sk_buff *skb, struct genl_info *info)
+ 		}
+ 
+ 		ctx.rx_sc = rx_sc;
++		ctx.secy = secy;
+ 
+ 		ret = macsec_offload(ops->mdo_add_rxsc, &ctx);
+ 		if (ret)
+@@ -2032,6 +2036,7 @@ static int macsec_add_txsa(struct sk_buff *skb, struct genl_info *info)
+ 
+ 		ctx.sa.assoc_num = assoc_num;
+ 		ctx.sa.tx_sa = tx_sa;
++		ctx.secy = secy;
+ 		memcpy(ctx.sa.key, nla_data(tb_sa[MACSEC_SA_ATTR_KEY]),
+ 		       MACSEC_KEYID_LEN);
+ 
+@@ -2107,6 +2112,7 @@ static int macsec_del_rxsa(struct sk_buff *skb, struct genl_info *info)
+ 
+ 		ctx.sa.assoc_num = assoc_num;
+ 		ctx.sa.rx_sa = rx_sa;
++		ctx.secy = secy;
+ 
+ 		ret = macsec_offload(ops->mdo_del_rxsa, &ctx);
+ 		if (ret)
+@@ -2172,6 +2178,7 @@ static int macsec_del_rxsc(struct sk_buff *skb, struct genl_info *info)
+ 		}
+ 
+ 		ctx.rx_sc = rx_sc;
++		ctx.secy = secy;
+ 		ret = macsec_offload(ops->mdo_del_rxsc, &ctx);
+ 		if (ret)
+ 			goto cleanup;
+@@ -2230,6 +2237,7 @@ static int macsec_del_txsa(struct sk_buff *skb, struct genl_info *info)
+ 
+ 		ctx.sa.assoc_num = assoc_num;
+ 		ctx.sa.tx_sa = tx_sa;
++		ctx.secy = secy;
+ 
+ 		ret = macsec_offload(ops->mdo_del_txsa, &ctx);
+ 		if (ret)
+@@ -2341,6 +2349,7 @@ static int macsec_upd_txsa(struct sk_buff *skb, struct genl_info *info)
+ 
+ 		ctx.sa.assoc_num = assoc_num;
+ 		ctx.sa.tx_sa = tx_sa;
++		ctx.secy = secy;
+ 
+ 		ret = macsec_offload(ops->mdo_upd_txsa, &ctx);
+ 		if (ret)
+@@ -2433,6 +2442,7 @@ static int macsec_upd_rxsa(struct sk_buff *skb, struct genl_info *info)
+ 
+ 		ctx.sa.assoc_num = assoc_num;
+ 		ctx.sa.rx_sa = rx_sa;
++		ctx.secy = secy;
+ 
+ 		ret = macsec_offload(ops->mdo_upd_rxsa, &ctx);
+ 		if (ret)
+@@ -2503,6 +2513,7 @@ static int macsec_upd_rxsc(struct sk_buff *skb, struct genl_info *info)
+ 		}
+ 
+ 		ctx.rx_sc = rx_sc;
++		ctx.secy = secy;
+ 
+ 		ret = macsec_offload(ops->mdo_upd_rxsc, &ctx);
+ 		if (ret)
+@@ -3370,6 +3381,7 @@ static int macsec_dev_open(struct net_device *dev)
+ 			goto clear_allmulti;
+ 		}
+ 
++		ctx.secy = &macsec->secy;
+ 		err = macsec_offload(ops->mdo_dev_open, &ctx);
+ 		if (err)
+ 			goto clear_allmulti;
+@@ -3401,8 +3413,10 @@ static int macsec_dev_stop(struct net_device *dev)
+ 		struct macsec_context ctx;
+ 
+ 		ops = macsec_get_ops(macsec, &ctx);
+-		if (ops)
++		if (ops) {
++			ctx.secy = &macsec->secy;
+ 			macsec_offload(ops->mdo_dev_stop, &ctx);
++		}
+ 	}
+ 
+ 	dev_mc_unsync(real_dev, dev);
+-- 
+cgit 1.2.3-1.el7
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1770-06-v5.18-net-macsec-allow-multiple-macsec-devices-with-offload.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1770-06-v5.18-net-macsec-allow-multiple-macsec-devices-with-offload.patch
new file mode 100644
index 0000000..4ef5870
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1770-06-v5.18-net-macsec-allow-multiple-macsec-devices-with-offload.patch
@@ -0,0 +1,65 @@
+From a249f8050624f92f844605274de3367e2c8ac706 Mon Sep 17 00:00:00 2001
+From: Dmitry Bogdanov <dbogdanov@marvell.com>
+Date: Wed, 25 Mar 2020 15:52:35 +0300
+Subject: net: macsec: allow multiple macsec devices with offload
+
+Offload engine can setup several SecY. Each macsec interface shall have
+its own mac address. It will filter a traffic by dest mac address.
+
+Signed-off-by: Dmitry Bogdanov <dbogdanov@marvell.com>
+Signed-off-by: Mark Starovoytov <mstarovoitov@marvell.com>
+Signed-off-by: Igor Russkikh <irusskikh@marvell.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/macsec.c | 25 +------------------------
+ 1 file changed, 1 insertion(+), 24 deletions(-)
+
+diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
+index 093e81d605ec7..146a7881a20ac 100644
+--- a/drivers/net/macsec.c
++++ b/drivers/net/macsec.c
+@@ -2553,11 +2553,10 @@ static int macsec_upd_offload(struct sk_buff *skb, struct genl_info *info)
+ 	enum macsec_offload offload, prev_offload;
+ 	int (*func)(struct macsec_context *ctx);
+ 	struct nlattr **attrs = info->attrs;
+-	struct net_device *dev, *loop_dev;
++	struct net_device *dev;
+ 	const struct macsec_ops *ops;
+ 	struct macsec_context ctx;
+ 	struct macsec_dev *macsec;
+-	struct net *loop_net;
+ 	int ret;
+ 
+ 	if (!attrs[MACSEC_ATTR_IFINDEX])
+@@ -2585,28 +2584,6 @@ static int macsec_upd_offload(struct sk_buff *skb, struct genl_info *info)
+ 	    !macsec_check_offload(offload, macsec))
+ 		return -EOPNOTSUPP;
+ 
+-	if (offload == MACSEC_OFFLOAD_OFF)
+-		goto skip_limitation;
+-
+-	/* Check the physical interface isn't offloading another interface
+-	 * first.
+-	 */
+-	for_each_net(loop_net) {
+-		for_each_netdev(loop_net, loop_dev) {
+-			struct macsec_dev *priv;
+-
+-			if (!netif_is_macsec(loop_dev))
+-				continue;
+-
+-			priv = macsec_priv(loop_dev);
+-
+-			if (priv->real_dev == macsec->real_dev &&
+-			    priv->offload != MACSEC_OFFLOAD_OFF)
+-				return -EBUSY;
+-		}
+-	}
+-
+-skip_limitation:
+ 	/* Check if the net device is busy. */
+ 	if (netif_running(dev))
+ 		return -EBUSY;
+-- 
+cgit 1.2.3-1.el7
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1771-07-v5.18-net-macsec-support-multicast-broadcast-when-offloading.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1771-07-v5.18-net-macsec-support-multicast-broadcast-when-offloading.patch
new file mode 100644
index 0000000..2f17478
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1771-07-v5.18-net-macsec-support-multicast-broadcast-when-offloading.patch
@@ -0,0 +1,105 @@
+From f428011b90ec0de7429886f753b7c3293392761c Mon Sep 17 00:00:00 2001
+From: Mark Starovoytov <mstarovoitov@marvell.com>
+Date: Wed, 25 Mar 2020 15:52:36 +0300
+Subject: net: macsec: support multicast/broadcast when offloading
+
+The idea is simple. If the frame is an exact match for the controlled port
+(based on DA comparison), then we simply divert this skb to matching port.
+
+Multicast/broadcast messages are delivered to all ports.
+
+Signed-off-by: Mark Starovoytov <mstarovoitov@marvell.com>
+Signed-off-by: Igor Russkikh <irusskikh@marvell.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/macsec.c | 51 ++++++++++++++++++++++++++++++++++++++-------------
+ 1 file changed, 38 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
+index 146a7881a20ac..c7ad7c6f1d1ec 100644
+--- a/drivers/net/macsec.c
++++ b/drivers/net/macsec.c
+@@ -1006,22 +1006,53 @@ static enum rx_handler_result handle_not_macsec(struct sk_buff *skb)
+ {
+ 	/* Deliver to the uncontrolled port by default */
+ 	enum rx_handler_result ret = RX_HANDLER_PASS;
++	struct ethhdr *hdr = eth_hdr(skb);
+ 	struct macsec_rxh_data *rxd;
+ 	struct macsec_dev *macsec;
+ 
+ 	rcu_read_lock();
+ 	rxd = macsec_data_rcu(skb->dev);
+ 
+-	/* 10.6 If the management control validateFrames is not
+-	 * Strict, frames without a SecTAG are received, counted, and
+-	 * delivered to the Controlled Port
+-	 */
+ 	list_for_each_entry_rcu(macsec, &rxd->secys, secys) {
+ 		struct sk_buff *nskb;
+ 		struct pcpu_secy_stats *secy_stats = this_cpu_ptr(macsec->stats);
++		struct net_device *ndev = macsec->secy.netdev;
+ 
+-		if (!macsec_is_offloaded(macsec) &&
+-		    macsec->secy.validate_frames == MACSEC_VALIDATE_STRICT) {
++		/* If h/w offloading is enabled, HW decodes frames and strips
++		 * the SecTAG, so we have to deduce which port to deliver to.
++		 */
++		if (macsec_is_offloaded(macsec) && netif_running(ndev)) {
++			if (ether_addr_equal_64bits(hdr->h_dest,
++						    ndev->dev_addr)) {
++				/* exact match, divert skb to this port */
++				skb->dev = ndev;
++				skb->pkt_type = PACKET_HOST;
++				ret = RX_HANDLER_ANOTHER;
++				goto out;
++			} else if (is_multicast_ether_addr_64bits(
++					   hdr->h_dest)) {
++				/* multicast frame, deliver on this port too */
++				nskb = skb_clone(skb, GFP_ATOMIC);
++				if (!nskb)
++					break;
++
++				nskb->dev = ndev;
++				if (ether_addr_equal_64bits(hdr->h_dest,
++							    ndev->broadcast))
++					nskb->pkt_type = PACKET_BROADCAST;
++				else
++					nskb->pkt_type = PACKET_MULTICAST;
++
++				netif_rx(nskb);
++			}
++			continue;
++		}
++
++		/* 10.6 If the management control validateFrames is not
++		 * Strict, frames without a SecTAG are received, counted, and
++		 * delivered to the Controlled Port
++		 */
++		if (macsec->secy.validate_frames == MACSEC_VALIDATE_STRICT) {
+ 			u64_stats_update_begin(&secy_stats->syncp);
+ 			secy_stats->stats.InPktsNoTag++;
+ 			u64_stats_update_end(&secy_stats->syncp);
+@@ -1033,19 +1064,13 @@ static enum rx_handler_result handle_not_macsec(struct sk_buff *skb)
+ 		if (!nskb)
+ 			break;
+ 
+-		nskb->dev = macsec->secy.netdev;
++		nskb->dev = ndev;
+ 
+ 		if (netif_rx(nskb) == NET_RX_SUCCESS) {
+ 			u64_stats_update_begin(&secy_stats->syncp);
+ 			secy_stats->stats.InPktsUntagged++;
+ 			u64_stats_update_end(&secy_stats->syncp);
+ 		}
+-
+-		if (netif_running(macsec->secy.netdev) &&
+-		    macsec_is_offloaded(macsec)) {
+-			ret = RX_HANDLER_EXACT;
+-			goto out;
+-		}
+ 	}
+ 
+ out:
+-- 
+cgit 1.2.3-1.el7
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1772-08-v5.18-net-macsec-add-support-for-getting-offloaded-stats.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1772-08-v5.18-net-macsec-add-support-for-getting-offloaded-stats.patch
new file mode 100644
index 0000000..5848eeb
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1772-08-v5.18-net-macsec-add-support-for-getting-offloaded-stats.patch
@@ -0,0 +1,580 @@
+From b62c3624500a7e1cc081e75973299c1f7901a438 Mon Sep 17 00:00:00 2001
+From: Dmitry Bogdanov <dbogdanov@marvell.com>
+Date: Wed, 25 Mar 2020 15:52:37 +0300
+Subject: net: macsec: add support for getting offloaded stats
+
+When HW offloading is enabled, offloaded stats should be used, because
+s/w stats are wrong and out of sync with the HW in this case.
+
+Signed-off-by: Dmitry Bogdanov <dbogdanov@marvell.com>
+Signed-off-by: Mark Starovoytov <mstarovoitov@marvell.com>
+Signed-off-by: Igor Russkikh <irusskikh@marvell.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/macsec.c | 321 ++++++++++++++++++++++++++++++++++-----------------
+ include/net/macsec.h |  24 ++++
+ 2 files changed, 237 insertions(+), 108 deletions(-)
+
+diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
+index c7ad7c6f1d1ec..b00a078d13ffe 100644
+--- a/drivers/net/macsec.c
++++ b/drivers/net/macsec.c
+@@ -88,17 +88,6 @@ struct gcm_iv {
+ 	__be32 pn;
+ };
+ 
+-struct macsec_dev_stats {
+-	__u64 OutPktsUntagged;
+-	__u64 InPktsUntagged;
+-	__u64 OutPktsTooLong;
+-	__u64 InPktsNoTag;
+-	__u64 InPktsBadTag;
+-	__u64 InPktsUnknownSCI;
+-	__u64 InPktsNoSCI;
+-	__u64 InPktsOverrun;
+-};
+-
+ #define MACSEC_VALIDATE_DEFAULT MACSEC_VALIDATE_STRICT
+ 
+ struct pcpu_secy_stats {
+@@ -2653,207 +2642,309 @@ rollback:
+ 	return ret;
+ }
+ 
+-static int copy_tx_sa_stats(struct sk_buff *skb,
+-			    struct macsec_tx_sa_stats __percpu *pstats)
++static void get_tx_sa_stats(struct net_device *dev, int an,
++			    struct macsec_tx_sa *tx_sa,
++			    struct macsec_tx_sa_stats *sum)
+ {
+-	struct macsec_tx_sa_stats sum = {0, };
++	struct macsec_dev *macsec = macsec_priv(dev);
+ 	int cpu;
+ 
++	/* If h/w offloading is available, propagate to the device */
++	if (macsec_is_offloaded(macsec)) {
++		const struct macsec_ops *ops;
++		struct macsec_context ctx;
++
++		ops = macsec_get_ops(macsec, &ctx);
++		if (ops) {
++			ctx.sa.assoc_num = an;
++			ctx.sa.tx_sa = tx_sa;
++			ctx.stats.tx_sa_stats = sum;
++			ctx.secy = &macsec_priv(dev)->secy;
++			macsec_offload(ops->mdo_get_tx_sa_stats, &ctx);
++		}
++		return;
++	}
++
+ 	for_each_possible_cpu(cpu) {
+-		const struct macsec_tx_sa_stats *stats = per_cpu_ptr(pstats, cpu);
++		const struct macsec_tx_sa_stats *stats =
++			per_cpu_ptr(tx_sa->stats, cpu);
+ 
+-		sum.OutPktsProtected += stats->OutPktsProtected;
+-		sum.OutPktsEncrypted += stats->OutPktsEncrypted;
++		sum->OutPktsProtected += stats->OutPktsProtected;
++		sum->OutPktsEncrypted += stats->OutPktsEncrypted;
+ 	}
++}
+ 
+-	if (nla_put_u32(skb, MACSEC_SA_STATS_ATTR_OUT_PKTS_PROTECTED, sum.OutPktsProtected) ||
+-	    nla_put_u32(skb, MACSEC_SA_STATS_ATTR_OUT_PKTS_ENCRYPTED, sum.OutPktsEncrypted))
++static int copy_tx_sa_stats(struct sk_buff *skb, struct macsec_tx_sa_stats *sum)
++{
++	if (nla_put_u32(skb, MACSEC_SA_STATS_ATTR_OUT_PKTS_PROTECTED,
++			sum->OutPktsProtected) ||
++	    nla_put_u32(skb, MACSEC_SA_STATS_ATTR_OUT_PKTS_ENCRYPTED,
++			sum->OutPktsEncrypted))
+ 		return -EMSGSIZE;
+ 
+ 	return 0;
+ }
+ 
+-static noinline_for_stack int
+-copy_rx_sa_stats(struct sk_buff *skb,
+-		 struct macsec_rx_sa_stats __percpu *pstats)
++static void get_rx_sa_stats(struct net_device *dev,
++			    struct macsec_rx_sc *rx_sc, int an,
++			    struct macsec_rx_sa *rx_sa,
++			    struct macsec_rx_sa_stats *sum)
+ {
+-	struct macsec_rx_sa_stats sum = {0, };
++	struct macsec_dev *macsec = macsec_priv(dev);
+ 	int cpu;
+ 
++	/* If h/w offloading is available, propagate to the device */
++	if (macsec_is_offloaded(macsec)) {
++		const struct macsec_ops *ops;
++		struct macsec_context ctx;
++
++		ops = macsec_get_ops(macsec, &ctx);
++		if (ops) {
++			ctx.sa.assoc_num = an;
++			ctx.sa.rx_sa = rx_sa;
++			ctx.stats.rx_sa_stats = sum;
++			ctx.secy = &macsec_priv(dev)->secy;
++			ctx.rx_sc = rx_sc;
++			macsec_offload(ops->mdo_get_rx_sa_stats, &ctx);
++		}
++		return;
++	}
++
+ 	for_each_possible_cpu(cpu) {
+-		const struct macsec_rx_sa_stats *stats = per_cpu_ptr(pstats, cpu);
++		const struct macsec_rx_sa_stats *stats =
++			per_cpu_ptr(rx_sa->stats, cpu);
+ 
+-		sum.InPktsOK         += stats->InPktsOK;
+-		sum.InPktsInvalid    += stats->InPktsInvalid;
+-		sum.InPktsNotValid   += stats->InPktsNotValid;
+-		sum.InPktsNotUsingSA += stats->InPktsNotUsingSA;
+-		sum.InPktsUnusedSA   += stats->InPktsUnusedSA;
++		sum->InPktsOK         += stats->InPktsOK;
++		sum->InPktsInvalid    += stats->InPktsInvalid;
++		sum->InPktsNotValid   += stats->InPktsNotValid;
++		sum->InPktsNotUsingSA += stats->InPktsNotUsingSA;
++		sum->InPktsUnusedSA   += stats->InPktsUnusedSA;
+ 	}
++}
+ 
+-	if (nla_put_u32(skb, MACSEC_SA_STATS_ATTR_IN_PKTS_OK, sum.InPktsOK) ||
+-	    nla_put_u32(skb, MACSEC_SA_STATS_ATTR_IN_PKTS_INVALID, sum.InPktsInvalid) ||
+-	    nla_put_u32(skb, MACSEC_SA_STATS_ATTR_IN_PKTS_NOT_VALID, sum.InPktsNotValid) ||
+-	    nla_put_u32(skb, MACSEC_SA_STATS_ATTR_IN_PKTS_NOT_USING_SA, sum.InPktsNotUsingSA) ||
+-	    nla_put_u32(skb, MACSEC_SA_STATS_ATTR_IN_PKTS_UNUSED_SA, sum.InPktsUnusedSA))
++static int copy_rx_sa_stats(struct sk_buff *skb,
++			    struct macsec_rx_sa_stats *sum)
++{
++	if (nla_put_u32(skb, MACSEC_SA_STATS_ATTR_IN_PKTS_OK, sum->InPktsOK) ||
++	    nla_put_u32(skb, MACSEC_SA_STATS_ATTR_IN_PKTS_INVALID,
++			sum->InPktsInvalid) ||
++	    nla_put_u32(skb, MACSEC_SA_STATS_ATTR_IN_PKTS_NOT_VALID,
++			sum->InPktsNotValid) ||
++	    nla_put_u32(skb, MACSEC_SA_STATS_ATTR_IN_PKTS_NOT_USING_SA,
++			sum->InPktsNotUsingSA) ||
++	    nla_put_u32(skb, MACSEC_SA_STATS_ATTR_IN_PKTS_UNUSED_SA,
++			sum->InPktsUnusedSA))
+ 		return -EMSGSIZE;
+ 
+ 	return 0;
+ }
+ 
+-static noinline_for_stack int
+-copy_rx_sc_stats(struct sk_buff *skb, struct pcpu_rx_sc_stats __percpu *pstats)
++static void get_rx_sc_stats(struct net_device *dev,
++			    struct macsec_rx_sc *rx_sc,
++			    struct macsec_rx_sc_stats *sum)
+ {
+-	struct macsec_rx_sc_stats sum = {0, };
++	struct macsec_dev *macsec = macsec_priv(dev);
+ 	int cpu;
+ 
++	/* If h/w offloading is available, propagate to the device */
++	if (macsec_is_offloaded(macsec)) {
++		const struct macsec_ops *ops;
++		struct macsec_context ctx;
++
++		ops = macsec_get_ops(macsec, &ctx);
++		if (ops) {
++			ctx.stats.rx_sc_stats = sum;
++			ctx.secy = &macsec_priv(dev)->secy;
++			ctx.rx_sc = rx_sc;
++			macsec_offload(ops->mdo_get_rx_sc_stats, &ctx);
++		}
++		return;
++	}
++
+ 	for_each_possible_cpu(cpu) {
+ 		const struct pcpu_rx_sc_stats *stats;
+ 		struct macsec_rx_sc_stats tmp;
+ 		unsigned int start;
+ 
+-		stats = per_cpu_ptr(pstats, cpu);
++		stats = per_cpu_ptr(rx_sc->stats, cpu);
+ 		do {
+ 			start = u64_stats_fetch_begin_irq(&stats->syncp);
+ 			memcpy(&tmp, &stats->stats, sizeof(tmp));
+ 		} while (u64_stats_fetch_retry_irq(&stats->syncp, start));
+ 
+-		sum.InOctetsValidated += tmp.InOctetsValidated;
+-		sum.InOctetsDecrypted += tmp.InOctetsDecrypted;
+-		sum.InPktsUnchecked   += tmp.InPktsUnchecked;
+-		sum.InPktsDelayed     += tmp.InPktsDelayed;
+-		sum.InPktsOK          += tmp.InPktsOK;
+-		sum.InPktsInvalid     += tmp.InPktsInvalid;
+-		sum.InPktsLate        += tmp.InPktsLate;
+-		sum.InPktsNotValid    += tmp.InPktsNotValid;
+-		sum.InPktsNotUsingSA  += tmp.InPktsNotUsingSA;
+-		sum.InPktsUnusedSA    += tmp.InPktsUnusedSA;
++		sum->InOctetsValidated += tmp.InOctetsValidated;
++		sum->InOctetsDecrypted += tmp.InOctetsDecrypted;
++		sum->InPktsUnchecked   += tmp.InPktsUnchecked;
++		sum->InPktsDelayed     += tmp.InPktsDelayed;
++		sum->InPktsOK          += tmp.InPktsOK;
++		sum->InPktsInvalid     += tmp.InPktsInvalid;
++		sum->InPktsLate        += tmp.InPktsLate;
++		sum->InPktsNotValid    += tmp.InPktsNotValid;
++		sum->InPktsNotUsingSA  += tmp.InPktsNotUsingSA;
++		sum->InPktsUnusedSA    += tmp.InPktsUnusedSA;
+ 	}
++}
+ 
++static int copy_rx_sc_stats(struct sk_buff *skb, struct macsec_rx_sc_stats *sum)
++{
+ 	if (nla_put_u64_64bit(skb, MACSEC_RXSC_STATS_ATTR_IN_OCTETS_VALIDATED,
+-			      sum.InOctetsValidated,
++			      sum->InOctetsValidated,
+ 			      MACSEC_RXSC_STATS_ATTR_PAD) ||
+ 	    nla_put_u64_64bit(skb, MACSEC_RXSC_STATS_ATTR_IN_OCTETS_DECRYPTED,
+-			      sum.InOctetsDecrypted,
++			      sum->InOctetsDecrypted,
+ 			      MACSEC_RXSC_STATS_ATTR_PAD) ||
+ 	    nla_put_u64_64bit(skb, MACSEC_RXSC_STATS_ATTR_IN_PKTS_UNCHECKED,
+-			      sum.InPktsUnchecked,
++			      sum->InPktsUnchecked,
+ 			      MACSEC_RXSC_STATS_ATTR_PAD) ||
+ 	    nla_put_u64_64bit(skb, MACSEC_RXSC_STATS_ATTR_IN_PKTS_DELAYED,
+-			      sum.InPktsDelayed,
++			      sum->InPktsDelayed,
+ 			      MACSEC_RXSC_STATS_ATTR_PAD) ||
+ 	    nla_put_u64_64bit(skb, MACSEC_RXSC_STATS_ATTR_IN_PKTS_OK,
+-			      sum.InPktsOK,
++			      sum->InPktsOK,
+ 			      MACSEC_RXSC_STATS_ATTR_PAD) ||
+ 	    nla_put_u64_64bit(skb, MACSEC_RXSC_STATS_ATTR_IN_PKTS_INVALID,
+-			      sum.InPktsInvalid,
++			      sum->InPktsInvalid,
+ 			      MACSEC_RXSC_STATS_ATTR_PAD) ||
+ 	    nla_put_u64_64bit(skb, MACSEC_RXSC_STATS_ATTR_IN_PKTS_LATE,
+-			      sum.InPktsLate,
++			      sum->InPktsLate,
+ 			      MACSEC_RXSC_STATS_ATTR_PAD) ||
+ 	    nla_put_u64_64bit(skb, MACSEC_RXSC_STATS_ATTR_IN_PKTS_NOT_VALID,
+-			      sum.InPktsNotValid,
++			      sum->InPktsNotValid,
+ 			      MACSEC_RXSC_STATS_ATTR_PAD) ||
+ 	    nla_put_u64_64bit(skb, MACSEC_RXSC_STATS_ATTR_IN_PKTS_NOT_USING_SA,
+-			      sum.InPktsNotUsingSA,
++			      sum->InPktsNotUsingSA,
+ 			      MACSEC_RXSC_STATS_ATTR_PAD) ||
+ 	    nla_put_u64_64bit(skb, MACSEC_RXSC_STATS_ATTR_IN_PKTS_UNUSED_SA,
+-			      sum.InPktsUnusedSA,
++			      sum->InPktsUnusedSA,
+ 			      MACSEC_RXSC_STATS_ATTR_PAD))
+ 		return -EMSGSIZE;
+ 
+ 	return 0;
+ }
+ 
+-static noinline_for_stack int
+-copy_tx_sc_stats(struct sk_buff *skb, struct pcpu_tx_sc_stats __percpu *pstats)
++static void get_tx_sc_stats(struct net_device *dev,
++			    struct macsec_tx_sc_stats *sum)
+ {
+-	struct macsec_tx_sc_stats sum = {0, };
++	struct macsec_dev *macsec = macsec_priv(dev);
+ 	int cpu;
+ 
++	/* If h/w offloading is available, propagate to the device */
++	if (macsec_is_offloaded(macsec)) {
++		const struct macsec_ops *ops;
++		struct macsec_context ctx;
++
++		ops = macsec_get_ops(macsec, &ctx);
++		if (ops) {
++			ctx.stats.tx_sc_stats = sum;
++			ctx.secy = &macsec_priv(dev)->secy;
++			macsec_offload(ops->mdo_get_tx_sc_stats, &ctx);
++		}
++		return;
++	}
++
+ 	for_each_possible_cpu(cpu) {
+ 		const struct pcpu_tx_sc_stats *stats;
+ 		struct macsec_tx_sc_stats tmp;
+ 		unsigned int start;
+ 
+-		stats = per_cpu_ptr(pstats, cpu);
++		stats = per_cpu_ptr(macsec_priv(dev)->secy.tx_sc.stats, cpu);
+ 		do {
+ 			start = u64_stats_fetch_begin_irq(&stats->syncp);
+ 			memcpy(&tmp, &stats->stats, sizeof(tmp));
+ 		} while (u64_stats_fetch_retry_irq(&stats->syncp, start));
+ 
+-		sum.OutPktsProtected   += tmp.OutPktsProtected;
+-		sum.OutPktsEncrypted   += tmp.OutPktsEncrypted;
+-		sum.OutOctetsProtected += tmp.OutOctetsProtected;
+-		sum.OutOctetsEncrypted += tmp.OutOctetsEncrypted;
++		sum->OutPktsProtected   += tmp.OutPktsProtected;
++		sum->OutPktsEncrypted   += tmp.OutPktsEncrypted;
++		sum->OutOctetsProtected += tmp.OutOctetsProtected;
++		sum->OutOctetsEncrypted += tmp.OutOctetsEncrypted;
+ 	}
++}
+ 
++static int copy_tx_sc_stats(struct sk_buff *skb, struct macsec_tx_sc_stats *sum)
++{
+ 	if (nla_put_u64_64bit(skb, MACSEC_TXSC_STATS_ATTR_OUT_PKTS_PROTECTED,
+-			      sum.OutPktsProtected,
++			      sum->OutPktsProtected,
+ 			      MACSEC_TXSC_STATS_ATTR_PAD) ||
+ 	    nla_put_u64_64bit(skb, MACSEC_TXSC_STATS_ATTR_OUT_PKTS_ENCRYPTED,
+-			      sum.OutPktsEncrypted,
++			      sum->OutPktsEncrypted,
+ 			      MACSEC_TXSC_STATS_ATTR_PAD) ||
+ 	    nla_put_u64_64bit(skb, MACSEC_TXSC_STATS_ATTR_OUT_OCTETS_PROTECTED,
+-			      sum.OutOctetsProtected,
++			      sum->OutOctetsProtected,
+ 			      MACSEC_TXSC_STATS_ATTR_PAD) ||
+ 	    nla_put_u64_64bit(skb, MACSEC_TXSC_STATS_ATTR_OUT_OCTETS_ENCRYPTED,
+-			      sum.OutOctetsEncrypted,
++			      sum->OutOctetsEncrypted,
+ 			      MACSEC_TXSC_STATS_ATTR_PAD))
+ 		return -EMSGSIZE;
+ 
+ 	return 0;
+ }
+ 
+-static noinline_for_stack int
+-copy_secy_stats(struct sk_buff *skb, struct pcpu_secy_stats __percpu *pstats)
++static void get_secy_stats(struct net_device *dev, struct macsec_dev_stats *sum)
+ {
+-	struct macsec_dev_stats sum = {0, };
++	struct macsec_dev *macsec = macsec_priv(dev);
+ 	int cpu;
+ 
++	/* If h/w offloading is available, propagate to the device */
++	if (macsec_is_offloaded(macsec)) {
++		const struct macsec_ops *ops;
++		struct macsec_context ctx;
++
++		ops = macsec_get_ops(macsec, &ctx);
++		if (ops) {
++			ctx.stats.dev_stats = sum;
++			ctx.secy = &macsec_priv(dev)->secy;
++			macsec_offload(ops->mdo_get_dev_stats, &ctx);
++		}
++		return;
++	}
++
+ 	for_each_possible_cpu(cpu) {
+ 		const struct pcpu_secy_stats *stats;
+ 		struct macsec_dev_stats tmp;
+ 		unsigned int start;
+ 
+-		stats = per_cpu_ptr(pstats, cpu);
++		stats = per_cpu_ptr(macsec_priv(dev)->stats, cpu);
+ 		do {
+ 			start = u64_stats_fetch_begin_irq(&stats->syncp);
+ 			memcpy(&tmp, &stats->stats, sizeof(tmp));
+ 		} while (u64_stats_fetch_retry_irq(&stats->syncp, start));
+ 
+-		sum.OutPktsUntagged  += tmp.OutPktsUntagged;
+-		sum.InPktsUntagged   += tmp.InPktsUntagged;
+-		sum.OutPktsTooLong   += tmp.OutPktsTooLong;
+-		sum.InPktsNoTag      += tmp.InPktsNoTag;
+-		sum.InPktsBadTag     += tmp.InPktsBadTag;
+-		sum.InPktsUnknownSCI += tmp.InPktsUnknownSCI;
+-		sum.InPktsNoSCI      += tmp.InPktsNoSCI;
+-		sum.InPktsOverrun    += tmp.InPktsOverrun;
++		sum->OutPktsUntagged  += tmp.OutPktsUntagged;
++		sum->InPktsUntagged   += tmp.InPktsUntagged;
++		sum->OutPktsTooLong   += tmp.OutPktsTooLong;
++		sum->InPktsNoTag      += tmp.InPktsNoTag;
++		sum->InPktsBadTag     += tmp.InPktsBadTag;
++		sum->InPktsUnknownSCI += tmp.InPktsUnknownSCI;
++		sum->InPktsNoSCI      += tmp.InPktsNoSCI;
++		sum->InPktsOverrun    += tmp.InPktsOverrun;
+ 	}
++}
+ 
++static int copy_secy_stats(struct sk_buff *skb, struct macsec_dev_stats *sum)
++{
+ 	if (nla_put_u64_64bit(skb, MACSEC_SECY_STATS_ATTR_OUT_PKTS_UNTAGGED,
+-			      sum.OutPktsUntagged,
++			      sum->OutPktsUntagged,
+ 			      MACSEC_SECY_STATS_ATTR_PAD) ||
+ 	    nla_put_u64_64bit(skb, MACSEC_SECY_STATS_ATTR_IN_PKTS_UNTAGGED,
+-			      sum.InPktsUntagged,
++			      sum->InPktsUntagged,
+ 			      MACSEC_SECY_STATS_ATTR_PAD) ||
+ 	    nla_put_u64_64bit(skb, MACSEC_SECY_STATS_ATTR_OUT_PKTS_TOO_LONG,
+-			      sum.OutPktsTooLong,
++			      sum->OutPktsTooLong,
+ 			      MACSEC_SECY_STATS_ATTR_PAD) ||
+ 	    nla_put_u64_64bit(skb, MACSEC_SECY_STATS_ATTR_IN_PKTS_NO_TAG,
+-			      sum.InPktsNoTag,
++			      sum->InPktsNoTag,
+ 			      MACSEC_SECY_STATS_ATTR_PAD) ||
+ 	    nla_put_u64_64bit(skb, MACSEC_SECY_STATS_ATTR_IN_PKTS_BAD_TAG,
+-			      sum.InPktsBadTag,
++			      sum->InPktsBadTag,
+ 			      MACSEC_SECY_STATS_ATTR_PAD) ||
+ 	    nla_put_u64_64bit(skb, MACSEC_SECY_STATS_ATTR_IN_PKTS_UNKNOWN_SCI,
+-			      sum.InPktsUnknownSCI,
++			      sum->InPktsUnknownSCI,
+ 			      MACSEC_SECY_STATS_ATTR_PAD) ||
+ 	    nla_put_u64_64bit(skb, MACSEC_SECY_STATS_ATTR_IN_PKTS_NO_SCI,
+-			      sum.InPktsNoSCI,
++			      sum->InPktsNoSCI,
+ 			      MACSEC_SECY_STATS_ATTR_PAD) ||
+ 	    nla_put_u64_64bit(skb, MACSEC_SECY_STATS_ATTR_IN_PKTS_OVERRUN,
+-			      sum.InPktsOverrun,
++			      sum->InPktsOverrun,
+ 			      MACSEC_SECY_STATS_ATTR_PAD))
+ 		return -EMSGSIZE;
+ 
+@@ -2914,7 +3005,12 @@ static noinline_for_stack int
+ dump_secy(struct macsec_secy *secy, struct net_device *dev,
+ 	  struct sk_buff *skb, struct netlink_callback *cb)
+ {
++	struct macsec_tx_sc_stats tx_sc_stats = {0, };
++	struct macsec_tx_sa_stats tx_sa_stats = {0, };
++	struct macsec_rx_sc_stats rx_sc_stats = {0, };
++	struct macsec_rx_sa_stats rx_sa_stats = {0, };
+ 	struct macsec_dev *macsec = netdev_priv(dev);
++	struct macsec_dev_stats dev_stats = {0, };
+ 	struct macsec_tx_sc *tx_sc = &secy->tx_sc;
+ 	struct nlattr *txsa_list, *rxsc_list;
+ 	struct macsec_rx_sc *rx_sc;
+@@ -2945,7 +3041,9 @@ dump_secy(struct macsec_secy *secy, struct net_device *dev,
+ 	attr = nla_nest_start_noflag(skb, MACSEC_ATTR_TXSC_STATS);
+ 	if (!attr)
+ 		goto nla_put_failure;
+-	if (copy_tx_sc_stats(skb, tx_sc->stats)) {
++
++	get_tx_sc_stats(dev, &tx_sc_stats);
++	if (copy_tx_sc_stats(skb, &tx_sc_stats)) {
+ 		nla_nest_cancel(skb, attr);
+ 		goto nla_put_failure;
+ 	}
+@@ -2954,7 +3052,8 @@ dump_secy(struct macsec_secy *secy, struct net_device *dev,
+ 	attr = nla_nest_start_noflag(skb, MACSEC_ATTR_SECY_STATS);
+ 	if (!attr)
+ 		goto nla_put_failure;
+-	if (copy_secy_stats(skb, macsec_priv(dev)->stats)) {
++	get_secy_stats(dev, &dev_stats);
++	if (copy_secy_stats(skb, &dev_stats)) {
+ 		nla_nest_cancel(skb, attr);
+ 		goto nla_put_failure;
+ 	}
+@@ -2978,6 +3077,22 @@ dump_secy(struct macsec_secy *secy, struct net_device *dev,
+ 			goto nla_put_failure;
+ 		}
+ 
++		attr = nla_nest_start_noflag(skb, MACSEC_SA_ATTR_STATS);
++		if (!attr) {
++			nla_nest_cancel(skb, txsa_nest);
++			nla_nest_cancel(skb, txsa_list);
++			goto nla_put_failure;
++		}
++		memset(&tx_sa_stats, 0, sizeof(tx_sa_stats));
++		get_tx_sa_stats(dev, i, tx_sa, &tx_sa_stats);
++		if (copy_tx_sa_stats(skb, &tx_sa_stats)) {
++			nla_nest_cancel(skb, attr);
++			nla_nest_cancel(skb, txsa_nest);
++			nla_nest_cancel(skb, txsa_list);
++			goto nla_put_failure;
++		}
++		nla_nest_end(skb, attr);
++
+ 		if (secy->xpn) {
+ 			pn = tx_sa->next_pn;
+ 			pn_len = MACSEC_XPN_PN_LEN;
+@@ -2996,20 +3111,6 @@ dump_secy(struct macsec_secy *secy, struct net_device *dev,
+ 			goto nla_put_failure;
+ 		}
+ 
+-		attr = nla_nest_start_noflag(skb, MACSEC_SA_ATTR_STATS);
+-		if (!attr) {
+-			nla_nest_cancel(skb, txsa_nest);
+-			nla_nest_cancel(skb, txsa_list);
+-			goto nla_put_failure;
+-		}
+-		if (copy_tx_sa_stats(skb, tx_sa->stats)) {
+-			nla_nest_cancel(skb, attr);
+-			nla_nest_cancel(skb, txsa_nest);
+-			nla_nest_cancel(skb, txsa_list);
+-			goto nla_put_failure;
+-		}
+-		nla_nest_end(skb, attr);
+-
+ 		nla_nest_end(skb, txsa_nest);
+ 	}
+ 	nla_nest_end(skb, txsa_list);
+@@ -3043,7 +3144,9 @@ dump_secy(struct macsec_secy *secy, struct net_device *dev,
+ 			nla_nest_cancel(skb, rxsc_list);
+ 			goto nla_put_failure;
+ 		}
+-		if (copy_rx_sc_stats(skb, rx_sc->stats)) {
++		memset(&rx_sc_stats, 0, sizeof(rx_sc_stats));
++		get_rx_sc_stats(dev, rx_sc, &rx_sc_stats);
++		if (copy_rx_sc_stats(skb, &rx_sc_stats)) {
+ 			nla_nest_cancel(skb, attr);
+ 			nla_nest_cancel(skb, rxsc_nest);
+ 			nla_nest_cancel(skb, rxsc_list);
+@@ -3084,7 +3187,9 @@ dump_secy(struct macsec_secy *secy, struct net_device *dev,
+ 				nla_nest_cancel(skb, rxsc_list);
+ 				goto nla_put_failure;
+ 			}
+-			if (copy_rx_sa_stats(skb, rx_sa->stats)) {
++			memset(&rx_sa_stats, 0, sizeof(rx_sa_stats));
++			get_rx_sa_stats(dev, rx_sc, i, rx_sa, &rx_sa_stats);
++			if (copy_rx_sa_stats(skb, &rx_sa_stats)) {
+ 				nla_nest_cancel(skb, attr);
+ 				nla_nest_cancel(skb, rxsa_list);
+ 				nla_nest_cancel(skb, rxsc_nest);
+diff --git a/include/net/macsec.h b/include/net/macsec.h
+index 71de2c863df70..52874cdfe2260 100644
+--- a/include/net/macsec.h
++++ b/include/net/macsec.h
+@@ -88,6 +88,17 @@ struct macsec_tx_sc_stats {
+ 	__u64 OutOctetsEncrypted;
+ };
+ 
++struct macsec_dev_stats {
++	__u64 OutPktsUntagged;
++	__u64 InPktsUntagged;
++	__u64 OutPktsTooLong;
++	__u64 InPktsNoTag;
++	__u64 InPktsBadTag;
++	__u64 InPktsUnknownSCI;
++	__u64 InPktsNoSCI;
++	__u64 InPktsOverrun;
++};
++
+ /**
+  * struct macsec_rx_sa - receive secure association
+  * @active:
+@@ -236,6 +247,13 @@ struct macsec_context {
+ 			struct macsec_tx_sa *tx_sa;
+ 		};
+ 	} sa;
++	union {
++		struct macsec_tx_sc_stats *tx_sc_stats;
++		struct macsec_tx_sa_stats *tx_sa_stats;
++		struct macsec_rx_sc_stats *rx_sc_stats;
++		struct macsec_rx_sa_stats *rx_sa_stats;
++		struct macsec_dev_stats  *dev_stats;
++	} stats;
+ 
+ 	u8 prepare:1;
+ };
+@@ -262,6 +280,12 @@ struct macsec_ops {
+ 	int (*mdo_add_txsa)(struct macsec_context *ctx);
+ 	int (*mdo_upd_txsa)(struct macsec_context *ctx);
+ 	int (*mdo_del_txsa)(struct macsec_context *ctx);
++	/* Statistics */
++	int (*mdo_get_dev_stats)(struct macsec_context *ctx);
++	int (*mdo_get_tx_sc_stats)(struct macsec_context *ctx);
++	int (*mdo_get_tx_sa_stats)(struct macsec_context *ctx);
++	int (*mdo_get_rx_sc_stats)(struct macsec_context *ctx);
++	int (*mdo_get_rx_sa_stats)(struct macsec_context *ctx);
+ };
+ 
+ void macsec_pn_wrapped(struct macsec_secy *secy, struct macsec_tx_sa *tx_sa);
+-- 
+cgit 1.2.3-1.el7
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1773-09-v5.18-net-macsec-report-real_dev-features-when-HW-offloading-is-enabled.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1773-09-v5.18-net-macsec-report-real_dev-features-when-HW-offloading-is-enabled.patch
new file mode 100644
index 0000000..b91bb9b
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1773-09-v5.18-net-macsec-report-real_dev-features-when-HW-offloading-is-enabled.patch
@@ -0,0 +1,94 @@
+From c850240b6c4132574a00f2da439277ab94265b66 Mon Sep 17 00:00:00 2001
+From: Mark Starovoytov <mstarovoitov@marvell.com>
+Date: Wed, 25 Mar 2020 15:52:38 +0300
+Subject: net: macsec: report real_dev features when HW offloading is enabled
+
+This patch makes real_dev_feature propagation by MACSec offloaded device.
+
+Issue description:
+real_dev features are disabled upon macsec creation.
+
+Root cause:
+Features limitation (specific to SW MACSec limitation) is being applied
+to HW offloaded case as well.
+This causes 'set_features' request on the real_dev with reduced feature
+set due to chain propagation.
+
+Proposed solution:
+Report real_dev features when HW offloading is enabled.
+NB! MACSec offloaded device does not propagate VLAN offload features at
+the moment. This can potentially be added later on as a separate patch.
+
+Note: this patch requires HW offloading to be enabled by default in order
+to function properly.
+
+Signed-off-by: Mark Starovoytov <mstarovoitov@marvell.com>
+Signed-off-by: Igor Russkikh <irusskikh@marvell.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/macsec.c | 26 ++++++++++++++++++++++----
+ 1 file changed, 22 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
+index b00a078d13ffe..2dad91cba459c 100644
+--- a/drivers/net/macsec.c
++++ b/drivers/net/macsec.c
+@@ -2633,6 +2633,10 @@ static int macsec_upd_offload(struct sk_buff *skb, struct genl_info *info)
+ 		goto rollback;
+ 
+ 	rtnl_unlock();
++	/* Force features update, since they are different for SW MACSec and
++	 * HW offloading cases.
++	 */
++	netdev_update_features(dev);
+ 	return 0;
+ 
+ rollback:
+@@ -3399,9 +3403,16 @@ static netdev_tx_t macsec_start_xmit(struct sk_buff *skb,
+ 	return ret;
+ }
+ 
+-#define MACSEC_FEATURES \
++#define SW_MACSEC_FEATURES \
+ 	(NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST)
+ 
++/* If h/w offloading is enabled, use real device features save for
++ *   VLAN_FEATURES - they require additional ops
++ *   HW_MACSEC - no reason to report it
++ */
++#define REAL_DEV_FEATURES(dev) \
++	((dev)->features & ~(NETIF_F_VLAN_FEATURES | NETIF_F_HW_MACSEC))
++
+ static int macsec_dev_init(struct net_device *dev)
+ {
+ 	struct macsec_dev *macsec = macsec_priv(dev);
+@@ -3418,8 +3429,12 @@ static int macsec_dev_init(struct net_device *dev)
+ 		return err;
+ 	}
+ 
+-	dev->features = real_dev->features & MACSEC_FEATURES;
+-	dev->features |= NETIF_F_LLTX | NETIF_F_GSO_SOFTWARE;
++	if (macsec_is_offloaded(macsec)) {
++		dev->features = REAL_DEV_FEATURES(real_dev);
++	} else {
++		dev->features = real_dev->features & SW_MACSEC_FEATURES;
++		dev->features |= NETIF_F_LLTX | NETIF_F_GSO_SOFTWARE;
++	}
+ 
+ 	dev->needed_headroom = real_dev->needed_headroom +
+ 			       MACSEC_NEEDED_HEADROOM;
+@@ -3448,7 +3463,10 @@ static netdev_features_t macsec_fix_features(struct net_device *dev,
+ 	struct macsec_dev *macsec = macsec_priv(dev);
+ 	struct net_device *real_dev = macsec->real_dev;
+ 
+-	features &= (real_dev->features & MACSEC_FEATURES) |
++	if (macsec_is_offloaded(macsec))
++		return REAL_DEV_FEATURES(real_dev);
++
++	features &= (real_dev->features & SW_MACSEC_FEATURES) |
+ 		    NETIF_F_GSO_SOFTWARE | NETIF_F_SOFT_FEATURES;
+ 	features |= NETIF_F_LLTX;
+ 
+-- 
+cgit 1.2.3-1.el7
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1774-v5.18-net-macsec-add-support-for-specifying-offload-upon-link-creation.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1774-v5.18-net-macsec-add-support-for-specifying-offload-upon-link-creation.patch
new file mode 100644
index 0000000..8cac11c
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1774-v5.18-net-macsec-add-support-for-specifying-offload-upon-link-creation.patch
@@ -0,0 +1,102 @@
+From 791bb3fcafcedd11f9066da9fee9342ecb6904d0 Mon Sep 17 00:00:00 2001
+From: Mark Starovoytov <mstarovoitov@marvell.com>
+Date: Wed, 25 Mar 2020 16:01:34 +0300
+Subject: net: macsec: add support for specifying offload upon link creation
+
+This patch adds new netlink attribute to allow a user to (optionally)
+specify the desired offload mode immediately upon MACSec link creation.
+
+Separate iproute patch will be required to support this from user space.
+
+Signed-off-by: Mark Starovoytov <mstarovoitov@marvell.com>
+Signed-off-by: Igor Russkikh <irusskikh@marvell.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/macsec.c               | 31 +++++++++++++++++++++++++++++--
+ include/uapi/linux/if_link.h       |  1 +
+ tools/include/uapi/linux/if_link.h |  1 +
+ 3 files changed, 31 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
+index 2dad91cba459c..da82d7f16a09d 100644
+--- a/drivers/net/macsec.c
++++ b/drivers/net/macsec.c
+@@ -1469,6 +1469,11 @@ static struct net_device *get_dev_from_nl(struct net *net,
+ 	return dev;
+ }
+ 
++static enum macsec_offload nla_get_offload(const struct nlattr *nla)
++{
++	return (__force enum macsec_offload)nla_get_u8(nla);
++}
++
+ static sci_t nla_get_sci(const struct nlattr *nla)
+ {
+ 	return (__force sci_t)nla_get_u64(nla);
+@@ -4012,8 +4017,16 @@ static int macsec_newlink(struct net *net, struct net_device *dev,
+ 
+ 	macsec->real_dev = real_dev;
+ 
+-	/* MACsec offloading is off by default */
+-	macsec->offload = MACSEC_OFFLOAD_OFF;
++	if (data && data[IFLA_MACSEC_OFFLOAD])
++		macsec->offload = nla_get_offload(data[IFLA_MACSEC_OFFLOAD]);
++	else
++		/* MACsec offloading is off by default */
++		macsec->offload = MACSEC_OFFLOAD_OFF;
++
++	/* Check if the offloading mode is supported by the underlying layers */
++	if (macsec->offload != MACSEC_OFFLOAD_OFF &&
++	    !macsec_check_offload(macsec->offload, macsec))
++		return -EOPNOTSUPP;
+ 
+ 	if (data && data[IFLA_MACSEC_ICV_LEN])
+ 		icv_len = nla_get_u8(data[IFLA_MACSEC_ICV_LEN]);
+@@ -4056,6 +4069,20 @@ static int macsec_newlink(struct net *net, struct net_device *dev,
+ 			goto del_dev;
+ 	}
+ 
++	/* If h/w offloading is available, propagate to the device */
++	if (macsec_is_offloaded(macsec)) {
++		const struct macsec_ops *ops;
++		struct macsec_context ctx;
++
++		ops = macsec_get_ops(macsec, &ctx);
++		if (ops) {
++			ctx.secy = &macsec->secy;
++			err = macsec_offload(ops->mdo_add_secy, &ctx);
++			if (err)
++				goto del_dev;
++		}
++	}
++
+ 	err = register_macsec_dev(real_dev, dev);
+ 	if (err < 0)
+ 		goto del_dev;
+diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
+index d6ccd0105c050..e204c3e4dce10 100644
+--- a/include/uapi/linux/if_link.h
++++ b/include/uapi/linux/if_link.h
+@@ -463,6 +463,7 @@ enum {
+ 	IFLA_MACSEC_REPLAY_PROTECT,
+ 	IFLA_MACSEC_VALIDATION,
+ 	IFLA_MACSEC_PAD,
++	IFLA_MACSEC_OFFLOAD,
+ 	__IFLA_MACSEC_MAX,
+ };
+ 
+diff --git a/tools/include/uapi/linux/if_link.h b/tools/include/uapi/linux/if_link.h
+index 771371d5b9960..24cf6fe075f74 100644
+--- a/tools/include/uapi/linux/if_link.h
++++ b/tools/include/uapi/linux/if_link.h
+@@ -463,6 +463,7 @@ enum {
+ 	IFLA_MACSEC_REPLAY_PROTECT,
+ 	IFLA_MACSEC_VALIDATION,
+ 	IFLA_MACSEC_PAD,
++	IFLA_MACSEC_OFFLOAD,
+ 	__IFLA_MACSEC_MAX,
+ };
+ 
+-- 
+cgit 1.2.3-1.el7
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1775-v5.18-net-macsec-fix-NULL-dereference-in-macsec_upd_offload.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1775-v5.18-net-macsec-fix-NULL-dereference-in-macsec_upd_offload.patch
new file mode 100644
index 0000000..b885c0f
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1775-v5.18-net-macsec-fix-NULL-dereference-in-macsec_upd_offload.patch
@@ -0,0 +1,35 @@
+From aa81700cf2326e288c9ca1fe7b544039617f1fc2 Mon Sep 17 00:00:00 2001
+From: Davide Caratti <dcaratti@redhat.com>
+Date: Mon, 6 Apr 2020 11:38:29 +0200
+Subject: macsec: fix NULL dereference in macsec_upd_offload()
+
+macsec_upd_offload() gets the value of MACSEC_OFFLOAD_ATTR_TYPE
+without checking its presence in the request message, and this causes
+a NULL dereference. Fix it rejecting any configuration that does not
+include this attribute.
+
+Reported-and-tested-by: syzbot+7022ab7c383875c17eff@syzkaller.appspotmail.com
+Fixes: dcb780fb2795 ("net: macsec: add nla support for changing the offloading selection")
+Signed-off-by: Davide Caratti <dcaratti@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/macsec.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
+index da82d7f16a09d..0d580d81d910f 100644
+--- a/drivers/net/macsec.c
++++ b/drivers/net/macsec.c
+@@ -2594,6 +2594,9 @@ static int macsec_upd_offload(struct sk_buff *skb, struct genl_info *info)
+ 		return PTR_ERR(dev);
+ 	macsec = macsec_priv(dev);
+ 
++	if (!tb_offload[MACSEC_OFFLOAD_ATTR_TYPE])
++		return -EINVAL;
++
+ 	offload = nla_get_u8(tb_offload[MACSEC_OFFLOAD_ATTR_TYPE]);
+ 	if (macsec->offload == offload)
+ 		return 0;
+-- 
+cgit 1.2.3-1.el7
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1776-v5.18-net-macsec-fix-using-wrong-structure-in-macsec_changelink.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1776-v5.18-net-macsec-fix-using-wrong-structure-in-macsec_changelink.patch
new file mode 100644
index 0000000..8d10c56
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1776-v5.18-net-macsec-fix-using-wrong-structure-in-macsec_changelink.patch
@@ -0,0 +1,73 @@
+From 022e9d6090599c0593c78e87dc9ba98a290e6bc4 Mon Sep 17 00:00:00 2001
+From: Taehee Yoo <ap420073@gmail.com>
+Date: Thu, 9 Apr 2020 14:08:08 +0000
+Subject: net: macsec: fix using wrong structure in macsec_changelink()
+
+In the macsec_changelink(), "struct macsec_tx_sa tx_sc" is used to
+store "macsec_secy.tx_sc".
+But, the struct type of tx_sc is macsec_tx_sc, not macsec_tx_sa.
+So, the macsec_tx_sc should be used instead.
+
+Test commands:
+    ip link add dummy0 type dummy
+    ip link add macsec0 link dummy0 type macsec
+    ip link set macsec0 type macsec encrypt off
+
+Splat looks like:
+[61119.963483][ T9335] ==================================================================
+[61119.964709][ T9335] BUG: KASAN: slab-out-of-bounds in macsec_changelink.part.34+0xb6/0x200 [macsec]
+[61119.965787][ T9335] Read of size 160 at addr ffff888020d69c68 by task ip/9335
+[61119.966699][ T9335]
+[61119.966979][ T9335] CPU: 0 PID: 9335 Comm: ip Not tainted 5.6.0+ #503
+[61119.967791][ T9335] Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006
+[61119.968914][ T9335] Call Trace:
+[61119.969324][ T9335]  dump_stack+0x96/0xdb
+[61119.969809][ T9335]  ? macsec_changelink.part.34+0xb6/0x200 [macsec]
+[61119.970554][ T9335]  print_address_description.constprop.5+0x1be/0x360
+[61119.971294][ T9335]  ? macsec_changelink.part.34+0xb6/0x200 [macsec]
+[61119.971973][ T9335]  ? macsec_changelink.part.34+0xb6/0x200 [macsec]
+[61119.972703][ T9335]  __kasan_report+0x12a/0x170
+[61119.973323][ T9335]  ? macsec_changelink.part.34+0xb6/0x200 [macsec]
+[61119.973942][ T9335]  kasan_report+0xe/0x20
+[61119.974397][ T9335]  check_memory_region+0x149/0x1a0
+[61119.974866][ T9335]  memcpy+0x1f/0x50
+[61119.975209][ T9335]  macsec_changelink.part.34+0xb6/0x200 [macsec]
+[61119.975825][ T9335]  ? macsec_get_stats64+0x3e0/0x3e0 [macsec]
+[61119.976451][ T9335]  ? kernel_text_address+0x111/0x120
+[61119.976990][ T9335]  ? pskb_expand_head+0x25f/0xe10
+[61119.977503][ T9335]  ? stack_trace_save+0x82/0xb0
+[61119.977986][ T9335]  ? memset+0x1f/0x40
+[61119.978397][ T9335]  ? __nla_validate_parse+0x98/0x1ab0
+[61119.978936][ T9335]  ? macsec_alloc_tfm+0x90/0x90 [macsec]
+[61119.979511][ T9335]  ? __kasan_slab_free+0x111/0x150
+[61119.980021][ T9335]  ? kfree+0xce/0x2f0
+[61119.980700][ T9335]  ? netlink_trim+0x196/0x1f0
+[61119.981420][ T9335]  ? nla_memcpy+0x90/0x90
+[61119.982036][ T9335]  ? register_lock_class+0x19e0/0x19e0
+[61119.982776][ T9335]  ? memcpy+0x34/0x50
+[61119.983327][ T9335]  __rtnl_newlink+0x922/0x1270
+[ ... ]
+
+Fixes: 3cf3227a21d1 ("net: macsec: hardware offloading infrastructure")
+Signed-off-by: Taehee Yoo <ap420073@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/macsec.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
+index 0d580d81d910f..a183250ff66ad 100644
+--- a/drivers/net/macsec.c
++++ b/drivers/net/macsec.c
+@@ -3809,7 +3809,7 @@ static int macsec_changelink(struct net_device *dev, struct nlattr *tb[],
+ 			     struct netlink_ext_ack *extack)
+ {
+ 	struct macsec_dev *macsec = macsec_priv(dev);
+-	struct macsec_tx_sa tx_sc;
++	struct macsec_tx_sc tx_sc;
+ 	struct macsec_secy secy;
+ 	int ret;
+ 
+-- 
+cgit 1.2.3-1.el7
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1777-v5.18-net-partially-revert-dynamic-lockdep-key-changes.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1777-v5.18-net-partially-revert-dynamic-lockdep-key-changes.patch
new file mode 100644
index 0000000..df1d001
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1777-v5.18-net-partially-revert-dynamic-lockdep-key-changes.patch
@@ -0,0 +1,753 @@
+From 1a33e10e4a95cb109ff1145098175df3113313ef Mon Sep 17 00:00:00 2001
+From: Cong Wang <xiyou.wangcong@gmail.com>
+Date: Sat, 2 May 2020 22:22:19 -0700
+Subject: net: partially revert dynamic lockdep key changes
+
+This patch reverts the folowing commits:
+
+commit 064ff66e2bef84f1153087612032b5b9eab005bd
+"bonding: add missing netdev_update_lockdep_key()"
+
+commit 53d374979ef147ab51f5d632dfe20b14aebeccd0
+"net: avoid updating qdisc_xmit_lock_key in netdev_update_lockdep_key()"
+
+commit 1f26c0d3d24125992ab0026b0dab16c08df947c7
+"net: fix kernel-doc warning in <linux/netdevice.h>"
+
+commit ab92d68fc22f9afab480153bd82a20f6e2533769
+"net: core: add generic lockdep keys"
+
+but keeps the addr_list_lock_key because we still lock
+addr_list_lock nestedly on stack devices, unlikely xmit_lock
+this is safe because we don't take addr_list_lock on any fast
+path.
+
+Reported-and-tested-by: syzbot+aaa6fa4949cc5d9b7b25@syzkaller.appspotmail.com
+Cc: Dmitry Vyukov <dvyukov@google.com>
+Cc: Taehee Yoo <ap420073@gmail.com>
+Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
+Acked-by: Taehee Yoo <ap420073@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/bonding/bond_main.c                   |  1 +
+ drivers/net/ethernet/netronome/nfp/nfp_net_repr.c | 16 ++++
+ drivers/net/hamradio/bpqether.c                   | 20 +++++
+ drivers/net/hyperv/netvsc_drv.c                   |  2 +
+ drivers/net/ipvlan/ipvlan_main.c                  |  2 +
+ drivers/net/macsec.c                              |  2 +
+ drivers/net/macvlan.c                             |  2 +
+ drivers/net/ppp/ppp_generic.c                     |  2 +
+ drivers/net/team/team.c                           |  1 +
+ drivers/net/vrf.c                                 |  1 +
+ drivers/net/wireless/intersil/hostap/hostap_hw.c  | 22 ++++++
+ include/linux/netdevice.h                         | 27 +++++--
+ net/8021q/vlan_dev.c                              | 21 ++++++
+ net/batman-adv/soft-interface.c                   | 30 ++++++++
+ net/bluetooth/6lowpan.c                           |  8 ++
+ net/core/dev.c                                    | 90 ++++++++++++++++++-----
+ net/dsa/slave.c                                   | 12 +++
+ net/ieee802154/6lowpan/core.c                     |  8 ++
+ net/l2tp/l2tp_eth.c                               |  1 +
+ net/netrom/af_netrom.c                            | 21 ++++++
+ net/rose/af_rose.c                                | 21 ++++++
+ net/sched/sch_generic.c                           | 17 +++--
+ 22 files changed, 294 insertions(+), 33 deletions(-)
+
+diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
+index 2e70e43c5df5c..d01871321d220 100644
+--- a/drivers/net/bonding/bond_main.c
++++ b/drivers/net/bonding/bond_main.c
+@@ -4898,6 +4898,7 @@ static int bond_init(struct net_device *bond_dev)
+ 	spin_lock_init(&bond->stats_lock);
+ 	lockdep_register_key(&bond->stats_lock_key);
+ 	lockdep_set_class(&bond->stats_lock, &bond->stats_lock_key);
++	netdev_lockdep_set_classes(bond_dev);
+ 
+ 	list_add_tail(&bond->bond_list, &bn->dev_list);
+ 
+diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c
+index 79d72c88bbef2..b3cabc274121b 100644
+--- a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c
++++ b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c
+@@ -299,6 +299,20 @@ static void nfp_repr_clean(struct nfp_repr *repr)
+ 	nfp_port_free(repr->port);
+ }
+ 
++static struct lock_class_key nfp_repr_netdev_xmit_lock_key;
++
++static void nfp_repr_set_lockdep_class_one(struct net_device *dev,
++					   struct netdev_queue *txq,
++					   void *_unused)
++{
++	lockdep_set_class(&txq->_xmit_lock, &nfp_repr_netdev_xmit_lock_key);
++}
++
++static void nfp_repr_set_lockdep_class(struct net_device *dev)
++{
++	netdev_for_each_tx_queue(dev, nfp_repr_set_lockdep_class_one, NULL);
++}
++
+ int nfp_repr_init(struct nfp_app *app, struct net_device *netdev,
+ 		  u32 cmsg_port_id, struct nfp_port *port,
+ 		  struct net_device *pf_netdev)
+@@ -308,6 +322,8 @@ int nfp_repr_init(struct nfp_app *app, struct net_device *netdev,
+ 	u32 repr_cap = nn->tlv_caps.repr_cap;
+ 	int err;
+ 
++	nfp_repr_set_lockdep_class(netdev);
++
+ 	repr->port = port;
+ 	repr->dst = metadata_dst_alloc(0, METADATA_HW_PORT_MUX, GFP_KERNEL);
+ 	if (!repr->dst)
+diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c
+index fbea6f232819e..206688154fdfa 100644
+--- a/drivers/net/hamradio/bpqether.c
++++ b/drivers/net/hamradio/bpqether.c
+@@ -107,6 +107,25 @@ struct bpqdev {
+ 
+ static LIST_HEAD(bpq_devices);
+ 
++/*
++ * bpqether network devices are paired with ethernet devices below them, so
++ * form a special "super class" of normal ethernet devices; split their locks
++ * off into a separate class since they always nest.
++ */
++static struct lock_class_key bpq_netdev_xmit_lock_key;
++
++static void bpq_set_lockdep_class_one(struct net_device *dev,
++				      struct netdev_queue *txq,
++				      void *_unused)
++{
++	lockdep_set_class(&txq->_xmit_lock, &bpq_netdev_xmit_lock_key);
++}
++
++static void bpq_set_lockdep_class(struct net_device *dev)
++{
++	netdev_for_each_tx_queue(dev, bpq_set_lockdep_class_one, NULL);
++}
++
+ /* ------------------------------------------------------------------------ */
+ 
+ 
+@@ -477,6 +496,7 @@ static int bpq_new_device(struct net_device *edev)
+ 	err = register_netdevice(ndev);
+ 	if (err)
+ 		goto error;
++	bpq_set_lockdep_class(ndev);
+ 
+ 	/* List protected by RTNL */
+ 	list_add_rcu(&bpq->bpq_list, &bpq_devices);
+diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
+index d8e86bdbfba1e..c0b647a4c8934 100644
+--- a/drivers/net/hyperv/netvsc_drv.c
++++ b/drivers/net/hyperv/netvsc_drv.c
+@@ -2456,6 +2456,8 @@ static int netvsc_probe(struct hv_device *dev,
+ 		NETIF_F_HW_VLAN_CTAG_RX;
+ 	net->vlan_features = net->features;
+ 
++	netdev_lockdep_set_classes(net);
++
+ 	/* MTU range: 68 - 1500 or 65521 */
+ 	net->min_mtu = NETVSC_MTU_MIN;
+ 	if (nvdev->nvsp_version >= NVSP_PROTOCOL_VERSION_2)
+diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c
+index f195f278a83aa..15e87c097b0b3 100644
+--- a/drivers/net/ipvlan/ipvlan_main.c
++++ b/drivers/net/ipvlan/ipvlan_main.c
+@@ -131,6 +131,8 @@ static int ipvlan_init(struct net_device *dev)
+ 	dev->gso_max_segs = phy_dev->gso_max_segs;
+ 	dev->hard_header_len = phy_dev->hard_header_len;
+ 
++	netdev_lockdep_set_classes(dev);
++
+ 	ipvlan->pcpu_stats = netdev_alloc_pcpu_stats(struct ipvl_pcpu_stats);
+ 	if (!ipvlan->pcpu_stats)
+ 		return -ENOMEM;
+diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
+index 758baf7cb8a16..ea3f25cc79efa 100644
+--- a/drivers/net/macsec.c
++++ b/drivers/net/macsec.c
+@@ -4047,6 +4047,8 @@ static int macsec_newlink(struct net *net, struct net_device *dev,
+ 	if (err < 0)
+ 		return err;
+ 
++	netdev_lockdep_set_classes(dev);
++
+ 	err = netdev_upper_dev_link(real_dev, dev, extack);
+ 	if (err < 0)
+ 		goto unregister;
+diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
+index d45600e0a38cd..34eb073cdd744 100644
+--- a/drivers/net/macvlan.c
++++ b/drivers/net/macvlan.c
+@@ -890,6 +890,8 @@ static int macvlan_init(struct net_device *dev)
+ 	dev->gso_max_segs	= lowerdev->gso_max_segs;
+ 	dev->hard_header_len	= lowerdev->hard_header_len;
+ 
++	netdev_lockdep_set_classes(dev);
++
+ 	vlan->pcpu_stats = netdev_alloc_pcpu_stats(struct vlan_pcpu_stats);
+ 	if (!vlan->pcpu_stats)
+ 		return -ENOMEM;
+diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
+index 22cc2cb9d878f..7d005896a0f93 100644
+--- a/drivers/net/ppp/ppp_generic.c
++++ b/drivers/net/ppp/ppp_generic.c
+@@ -1410,6 +1410,8 @@ static int ppp_dev_init(struct net_device *dev)
+ {
+ 	struct ppp *ppp;
+ 
++	netdev_lockdep_set_classes(dev);
++
+ 	ppp = netdev_priv(dev);
+ 	/* Let the netdevice take a reference on the ppp file. This ensures
+ 	 * that ppp_destroy_interface() won't run before the device gets
+diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
+index 04845a4017f93..8c1e02752ff61 100644
+--- a/drivers/net/team/team.c
++++ b/drivers/net/team/team.c
+@@ -1647,6 +1647,7 @@ static int team_init(struct net_device *dev)
+ 
+ 	lockdep_register_key(&team->team_lock_key);
+ 	__mutex_init(&team->lock, "team->team_lock_key", &team->team_lock_key);
++	netdev_lockdep_set_classes(dev);
+ 
+ 	return 0;
+ 
+diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c
+index 56f8aab46f89b..43928a1c2f2a4 100644
+--- a/drivers/net/vrf.c
++++ b/drivers/net/vrf.c
+@@ -867,6 +867,7 @@ static int vrf_dev_init(struct net_device *dev)
+ 
+ 	/* similarly, oper state is irrelevant; set to up to avoid confusion */
+ 	dev->operstate = IF_OPER_UP;
++	netdev_lockdep_set_classes(dev);
+ 	return 0;
+ 
+ out_rth:
+diff --git a/drivers/net/wireless/intersil/hostap/hostap_hw.c b/drivers/net/wireless/intersil/hostap/hostap_hw.c
+index 58212c532c900..aadf3dec5bf32 100644
+--- a/drivers/net/wireless/intersil/hostap/hostap_hw.c
++++ b/drivers/net/wireless/intersil/hostap/hostap_hw.c
+@@ -3041,6 +3041,27 @@ static void prism2_clear_set_tim_queue(local_info_t *local)
+ 	}
+ }
+ 
++
++/*
++ * HostAP uses two layers of net devices, where the inner
++ * layer gets called all the time from the outer layer.
++ * This is a natural nesting, which needs a split lock type.
++ */
++static struct lock_class_key hostap_netdev_xmit_lock_key;
++
++static void prism2_set_lockdep_class_one(struct net_device *dev,
++					 struct netdev_queue *txq,
++					 void *_unused)
++{
++	lockdep_set_class(&txq->_xmit_lock,
++			  &hostap_netdev_xmit_lock_key);
++}
++
++static void prism2_set_lockdep_class(struct net_device *dev)
++{
++	netdev_for_each_tx_queue(dev, prism2_set_lockdep_class_one, NULL);
++}
++
+ static struct net_device *
+ prism2_init_local_data(struct prism2_helper_functions *funcs, int card_idx,
+ 		       struct device *sdev)
+@@ -3199,6 +3220,7 @@ while (0)
+ 	if (ret >= 0)
+ 		ret = register_netdevice(dev);
+ 
++	prism2_set_lockdep_class(dev);
+ 	rtnl_unlock();
+ 	if (ret < 0) {
+ 		printk(KERN_WARNING "%s: register netdevice failed!\n",
+diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
+index 5a8d40f1ffe2a..7725efd6e48a1 100644
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -1805,13 +1805,11 @@ enum netdev_priv_flags {
+  *	@phydev:	Physical device may attach itself
+  *			for hardware timestamping
+  *	@sfp_bus:	attached &struct sfp_bus structure.
+- *	@qdisc_tx_busylock_key: lockdep class annotating Qdisc->busylock
+- *				spinlock
+- *	@qdisc_running_key:	lockdep class annotating Qdisc->running seqcount
+- *	@qdisc_xmit_lock_key:	lockdep class annotating
+- *				netdev_queue->_xmit_lock spinlock
++ *
+  *	@addr_list_lock_key:	lockdep class annotating
+  *				net_device->addr_list_lock spinlock
++ *	@qdisc_tx_busylock: lockdep class annotating Qdisc->busylock spinlock
++ *	@qdisc_running_key: lockdep class annotating Qdisc->running seqcount
+  *
+  *	@proto_down:	protocol port state information can be sent to the
+  *			switch driver and used to set the phys state of the
+@@ -2112,10 +2110,9 @@ struct net_device {
+ #endif
+ 	struct phy_device	*phydev;
+ 	struct sfp_bus		*sfp_bus;
+-	struct lock_class_key	qdisc_tx_busylock_key;
+-	struct lock_class_key	qdisc_running_key;
+-	struct lock_class_key	qdisc_xmit_lock_key;
+ 	struct lock_class_key	addr_list_lock_key;
++	struct lock_class_key	*qdisc_tx_busylock;
++	struct lock_class_key	*qdisc_running_key;
+ 	bool			proto_down;
+ 	unsigned		wol_enabled:1;
+ 
+@@ -2200,6 +2197,20 @@ static inline void netdev_for_each_tx_queue(struct net_device *dev,
+ 		f(dev, &dev->_tx[i], arg);
+ }
+ 
++#define netdev_lockdep_set_classes(dev)				\
++{								\
++	static struct lock_class_key qdisc_tx_busylock_key;	\
++	static struct lock_class_key qdisc_running_key;		\
++	static struct lock_class_key qdisc_xmit_lock_key;	\
++	unsigned int i;						\
++								\
++	(dev)->qdisc_tx_busylock = &qdisc_tx_busylock_key;	\
++	(dev)->qdisc_running_key = &qdisc_running_key;		\
++	for (i = 0; i < (dev)->num_tx_queues; i++)		\
++		lockdep_set_class(&(dev)->_tx[i]._xmit_lock,	\
++				  &qdisc_xmit_lock_key);	\
++}
++
+ u16 netdev_pick_tx(struct net_device *dev, struct sk_buff *skb,
+ 		     struct net_device *sb_dev);
+ struct netdev_queue *netdev_core_pick_tx(struct net_device *dev,
+diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
+index 990b9fde28c65..319220b2341dd 100644
+--- a/net/8021q/vlan_dev.c
++++ b/net/8021q/vlan_dev.c
+@@ -489,6 +489,25 @@ static void vlan_dev_set_rx_mode(struct net_device *vlan_dev)
+ 	dev_uc_sync(vlan_dev_priv(vlan_dev)->real_dev, vlan_dev);
+ }
+ 
++/*
++ * vlan network devices have devices nesting below it, and are a special
++ * "super class" of normal network devices; split their locks off into a
++ * separate class since they always nest.
++ */
++static struct lock_class_key vlan_netdev_xmit_lock_key;
++
++static void vlan_dev_set_lockdep_one(struct net_device *dev,
++				     struct netdev_queue *txq,
++				     void *unused)
++{
++	lockdep_set_class(&txq->_xmit_lock, &vlan_netdev_xmit_lock_key);
++}
++
++static void vlan_dev_set_lockdep_class(struct net_device *dev)
++{
++	netdev_for_each_tx_queue(dev, vlan_dev_set_lockdep_one, NULL);
++}
++
+ static const struct header_ops vlan_header_ops = {
+ 	.create	 = vlan_dev_hard_header,
+ 	.parse	 = eth_header_parse,
+@@ -579,6 +598,8 @@ static int vlan_dev_init(struct net_device *dev)
+ 
+ 	SET_NETDEV_DEVTYPE(dev, &vlan_type);
+ 
++	vlan_dev_set_lockdep_class(dev);
++
+ 	vlan->vlan_pcpu_stats = netdev_alloc_pcpu_stats(struct vlan_pcpu_stats);
+ 	if (!vlan->vlan_pcpu_stats)
+ 		return -ENOMEM;
+diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c
+index 5f05a728f347a..822af540b8540 100644
+--- a/net/batman-adv/soft-interface.c
++++ b/net/batman-adv/soft-interface.c
+@@ -739,6 +739,34 @@ static int batadv_interface_kill_vid(struct net_device *dev, __be16 proto,
+ 	return 0;
+ }
+ 
++/* batman-adv network devices have devices nesting below it and are a special
++ * "super class" of normal network devices; split their locks off into a
++ * separate class since they always nest.
++ */
++static struct lock_class_key batadv_netdev_xmit_lock_key;
++
++/**
++ * batadv_set_lockdep_class_one() - Set lockdep class for a single tx queue
++ * @dev: device which owns the tx queue
++ * @txq: tx queue to modify
++ * @_unused: always NULL
++ */
++static void batadv_set_lockdep_class_one(struct net_device *dev,
++					 struct netdev_queue *txq,
++					 void *_unused)
++{
++	lockdep_set_class(&txq->_xmit_lock, &batadv_netdev_xmit_lock_key);
++}
++
++/**
++ * batadv_set_lockdep_class() - Set txq and addr_list lockdep class
++ * @dev: network device to modify
++ */
++static void batadv_set_lockdep_class(struct net_device *dev)
++{
++	netdev_for_each_tx_queue(dev, batadv_set_lockdep_class_one, NULL);
++}
++
+ /**
+  * batadv_softif_init_late() - late stage initialization of soft interface
+  * @dev: registered network device to modify
+@@ -752,6 +780,8 @@ static int batadv_softif_init_late(struct net_device *dev)
+ 	int ret;
+ 	size_t cnt_len = sizeof(u64) * BATADV_CNT_NUM;
+ 
++	batadv_set_lockdep_class(dev);
++
+ 	bat_priv = netdev_priv(dev);
+ 	bat_priv->soft_iface = dev;
+ 
+diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
+index 4febc82a7c761..bb55d92691b06 100644
+--- a/net/bluetooth/6lowpan.c
++++ b/net/bluetooth/6lowpan.c
+@@ -571,7 +571,15 @@ static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev)
+ 	return err < 0 ? NET_XMIT_DROP : err;
+ }
+ 
++static int bt_dev_init(struct net_device *dev)
++{
++	netdev_lockdep_set_classes(dev);
++
++	return 0;
++}
++
+ static const struct net_device_ops netdev_ops = {
++	.ndo_init		= bt_dev_init,
+ 	.ndo_start_xmit		= bt_xmit,
+ };
+ 
+diff --git a/net/core/dev.c b/net/core/dev.c
+index afff16849c261..f8d83922a6afb 100644
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -398,6 +398,74 @@ static RAW_NOTIFIER_HEAD(netdev_chain);
+ DEFINE_PER_CPU_ALIGNED(struct softnet_data, softnet_data);
+ EXPORT_PER_CPU_SYMBOL(softnet_data);
+ 
++#ifdef CONFIG_LOCKDEP
++/*
++ * register_netdevice() inits txq->_xmit_lock and sets lockdep class
++ * according to dev->type
++ */
++static const unsigned short netdev_lock_type[] = {
++	 ARPHRD_NETROM, ARPHRD_ETHER, ARPHRD_EETHER, ARPHRD_AX25,
++	 ARPHRD_PRONET, ARPHRD_CHAOS, ARPHRD_IEEE802, ARPHRD_ARCNET,
++	 ARPHRD_APPLETLK, ARPHRD_DLCI, ARPHRD_ATM, ARPHRD_METRICOM,
++	 ARPHRD_IEEE1394, ARPHRD_EUI64, ARPHRD_INFINIBAND, ARPHRD_SLIP,
++	 ARPHRD_CSLIP, ARPHRD_SLIP6, ARPHRD_CSLIP6, ARPHRD_RSRVD,
++	 ARPHRD_ADAPT, ARPHRD_ROSE, ARPHRD_X25, ARPHRD_HWX25,
++	 ARPHRD_PPP, ARPHRD_CISCO, ARPHRD_LAPB, ARPHRD_DDCMP,
++	 ARPHRD_RAWHDLC, ARPHRD_TUNNEL, ARPHRD_TUNNEL6, ARPHRD_FRAD,
++	 ARPHRD_SKIP, ARPHRD_LOOPBACK, ARPHRD_LOCALTLK, ARPHRD_FDDI,
++	 ARPHRD_BIF, ARPHRD_SIT, ARPHRD_IPDDP, ARPHRD_IPGRE,
++	 ARPHRD_PIMREG, ARPHRD_HIPPI, ARPHRD_ASH, ARPHRD_ECONET,
++	 ARPHRD_IRDA, ARPHRD_FCPP, ARPHRD_FCAL, ARPHRD_FCPL,
++	 ARPHRD_FCFABRIC, ARPHRD_IEEE80211, ARPHRD_IEEE80211_PRISM,
++	 ARPHRD_IEEE80211_RADIOTAP, ARPHRD_PHONET, ARPHRD_PHONET_PIPE,
++	 ARPHRD_IEEE802154, ARPHRD_VOID, ARPHRD_NONE};
++
++static const char *const netdev_lock_name[] = {
++	"_xmit_NETROM", "_xmit_ETHER", "_xmit_EETHER", "_xmit_AX25",
++	"_xmit_PRONET", "_xmit_CHAOS", "_xmit_IEEE802", "_xmit_ARCNET",
++	"_xmit_APPLETLK", "_xmit_DLCI", "_xmit_ATM", "_xmit_METRICOM",
++	"_xmit_IEEE1394", "_xmit_EUI64", "_xmit_INFINIBAND", "_xmit_SLIP",
++	"_xmit_CSLIP", "_xmit_SLIP6", "_xmit_CSLIP6", "_xmit_RSRVD",
++	"_xmit_ADAPT", "_xmit_ROSE", "_xmit_X25", "_xmit_HWX25",
++	"_xmit_PPP", "_xmit_CISCO", "_xmit_LAPB", "_xmit_DDCMP",
++	"_xmit_RAWHDLC", "_xmit_TUNNEL", "_xmit_TUNNEL6", "_xmit_FRAD",
++	"_xmit_SKIP", "_xmit_LOOPBACK", "_xmit_LOCALTLK", "_xmit_FDDI",
++	"_xmit_BIF", "_xmit_SIT", "_xmit_IPDDP", "_xmit_IPGRE",
++	"_xmit_PIMREG", "_xmit_HIPPI", "_xmit_ASH", "_xmit_ECONET",
++	"_xmit_IRDA", "_xmit_FCPP", "_xmit_FCAL", "_xmit_FCPL",
++	"_xmit_FCFABRIC", "_xmit_IEEE80211", "_xmit_IEEE80211_PRISM",
++	"_xmit_IEEE80211_RADIOTAP", "_xmit_PHONET", "_xmit_PHONET_PIPE",
++	"_xmit_IEEE802154", "_xmit_VOID", "_xmit_NONE"};
++
++static struct lock_class_key netdev_xmit_lock_key[ARRAY_SIZE(netdev_lock_type)];
++
++static inline unsigned short netdev_lock_pos(unsigned short dev_type)
++{
++	int i;
++
++	for (i = 0; i < ARRAY_SIZE(netdev_lock_type); i++)
++		if (netdev_lock_type[i] == dev_type)
++			return i;
++	/* the last key is used by default */
++	return ARRAY_SIZE(netdev_lock_type) - 1;
++}
++
++static inline void netdev_set_xmit_lockdep_class(spinlock_t *lock,
++						 unsigned short dev_type)
++{
++	int i;
++
++	i = netdev_lock_pos(dev_type);
++	lockdep_set_class_and_name(lock, &netdev_xmit_lock_key[i],
++				   netdev_lock_name[i]);
++}
++#else
++static inline void netdev_set_xmit_lockdep_class(spinlock_t *lock,
++						 unsigned short dev_type)
++{
++}
++#endif
++
+ /*******************************************************************************
+  *
+  *		Protocol management and registration routines
+@@ -9208,7 +9276,7 @@ static void netdev_init_one_queue(struct net_device *dev,
+ {
+ 	/* Initialize queue lock */
+ 	spin_lock_init(&queue->_xmit_lock);
+-	lockdep_set_class(&queue->_xmit_lock, &dev->qdisc_xmit_lock_key);
++	netdev_set_xmit_lockdep_class(&queue->_xmit_lock, dev->type);
+ 	queue->xmit_lock_owner = -1;
+ 	netdev_queue_numa_node_write(queue, NUMA_NO_NODE);
+ 	queue->dev = dev;
+@@ -9255,22 +9323,6 @@ void netif_tx_stop_all_queues(struct net_device *dev)
+ }
+ EXPORT_SYMBOL(netif_tx_stop_all_queues);
+ 
+-static void netdev_register_lockdep_key(struct net_device *dev)
+-{
+-	lockdep_register_key(&dev->qdisc_tx_busylock_key);
+-	lockdep_register_key(&dev->qdisc_running_key);
+-	lockdep_register_key(&dev->qdisc_xmit_lock_key);
+-	lockdep_register_key(&dev->addr_list_lock_key);
+-}
+-
+-static void netdev_unregister_lockdep_key(struct net_device *dev)
+-{
+-	lockdep_unregister_key(&dev->qdisc_tx_busylock_key);
+-	lockdep_unregister_key(&dev->qdisc_running_key);
+-	lockdep_unregister_key(&dev->qdisc_xmit_lock_key);
+-	lockdep_unregister_key(&dev->addr_list_lock_key);
+-}
+-
+ void netdev_update_lockdep_key(struct net_device *dev)
+ {
+ 	lockdep_unregister_key(&dev->addr_list_lock_key);
+@@ -9837,7 +9889,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
+ 
+ 	dev_net_set(dev, &init_net);
+ 
+-	netdev_register_lockdep_key(dev);
++	lockdep_register_key(&dev->addr_list_lock_key);
+ 
+ 	dev->gso_max_size = GSO_MAX_SIZE;
+ 	dev->gso_max_segs = GSO_MAX_SEGS;
+@@ -9926,7 +9978,7 @@ void free_netdev(struct net_device *dev)
+ 	free_percpu(dev->xdp_bulkq);
+ 	dev->xdp_bulkq = NULL;
+ 
+-	netdev_unregister_lockdep_key(dev);
++	lockdep_unregister_key(&dev->addr_list_lock_key);
+ 
+ 	/*  Compatibility with error handling in drivers */
+ 	if (dev->reg_state == NETREG_UNINITIALIZED) {
+diff --git a/net/dsa/slave.c b/net/dsa/slave.c
+index ba8bf90dc0cc1..fa26340437519 100644
+--- a/net/dsa/slave.c
++++ b/net/dsa/slave.c
+@@ -1671,6 +1671,15 @@ static int dsa_slave_phy_setup(struct net_device *slave_dev)
+ 	return ret;
+ }
+ 
++static struct lock_class_key dsa_slave_netdev_xmit_lock_key;
++static void dsa_slave_set_lockdep_class_one(struct net_device *dev,
++					    struct netdev_queue *txq,
++					    void *_unused)
++{
++	lockdep_set_class(&txq->_xmit_lock,
++			  &dsa_slave_netdev_xmit_lock_key);
++}
++
+ int dsa_slave_suspend(struct net_device *slave_dev)
+ {
+ 	struct dsa_port *dp = dsa_slave_to_port(slave_dev);
+@@ -1754,6 +1763,9 @@ int dsa_slave_create(struct dsa_port *port)
+ 		slave_dev->max_mtu = ETH_MAX_MTU;
+ 	SET_NETDEV_DEVTYPE(slave_dev, &dsa_type);
+ 
++	netdev_for_each_tx_queue(slave_dev, dsa_slave_set_lockdep_class_one,
++				 NULL);
++
+ 	SET_NETDEV_DEV(slave_dev, port->ds->dev);
+ 	slave_dev->dev.of_node = port->dn;
+ 	slave_dev->vlan_features = master->vlan_features;
+diff --git a/net/ieee802154/6lowpan/core.c b/net/ieee802154/6lowpan/core.c
+index c0b107cdd7153..3297e7fa99458 100644
+--- a/net/ieee802154/6lowpan/core.c
++++ b/net/ieee802154/6lowpan/core.c
+@@ -58,6 +58,13 @@ static const struct header_ops lowpan_header_ops = {
+ 	.create	= lowpan_header_create,
+ };
+ 
++static int lowpan_dev_init(struct net_device *ldev)
++{
++	netdev_lockdep_set_classes(ldev);
++
++	return 0;
++}
++
+ static int lowpan_open(struct net_device *dev)
+ {
+ 	if (!open_count)
+@@ -89,6 +96,7 @@ static int lowpan_get_iflink(const struct net_device *dev)
+ }
+ 
+ static const struct net_device_ops lowpan_netdev_ops = {
++	.ndo_init		= lowpan_dev_init,
+ 	.ndo_start_xmit		= lowpan_xmit,
+ 	.ndo_open		= lowpan_open,
+ 	.ndo_stop		= lowpan_stop,
+diff --git a/net/l2tp/l2tp_eth.c b/net/l2tp/l2tp_eth.c
+index d3b520b9b2c9d..fd5ac2788e45c 100644
+--- a/net/l2tp/l2tp_eth.c
++++ b/net/l2tp/l2tp_eth.c
+@@ -56,6 +56,7 @@ static int l2tp_eth_dev_init(struct net_device *dev)
+ {
+ 	eth_hw_addr_random(dev);
+ 	eth_broadcast_addr(dev->broadcast);
++	netdev_lockdep_set_classes(dev);
+ 
+ 	return 0;
+ }
+diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
+index 7b1a74f74aad5..eccc7d366e17f 100644
+--- a/net/netrom/af_netrom.c
++++ b/net/netrom/af_netrom.c
+@@ -63,6 +63,26 @@ static DEFINE_SPINLOCK(nr_list_lock);
+ 
+ static const struct proto_ops nr_proto_ops;
+ 
++/*
++ * NETROM network devices are virtual network devices encapsulating NETROM
++ * frames into AX.25 which will be sent through an AX.25 device, so form a
++ * special "super class" of normal net devices; split their locks off into a
++ * separate class since they always nest.
++ */
++static struct lock_class_key nr_netdev_xmit_lock_key;
++
++static void nr_set_lockdep_one(struct net_device *dev,
++			       struct netdev_queue *txq,
++			       void *_unused)
++{
++	lockdep_set_class(&txq->_xmit_lock, &nr_netdev_xmit_lock_key);
++}
++
++static void nr_set_lockdep_key(struct net_device *dev)
++{
++	netdev_for_each_tx_queue(dev, nr_set_lockdep_one, NULL);
++}
++
+ /*
+  *	Socket removal during an interrupt is now safe.
+  */
+@@ -1394,6 +1414,7 @@ static int __init nr_proto_init(void)
+ 			free_netdev(dev);
+ 			goto fail;
+ 		}
++		nr_set_lockdep_key(dev);
+ 		dev_nr[i] = dev;
+ 	}
+ 
+diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
+index 1e8eeb044b07d..e7a872207b464 100644
+--- a/net/rose/af_rose.c
++++ b/net/rose/af_rose.c
+@@ -64,6 +64,26 @@ static const struct proto_ops rose_proto_ops;
+ 
+ ax25_address rose_callsign;
+ 
++/*
++ * ROSE network devices are virtual network devices encapsulating ROSE
++ * frames into AX.25 which will be sent through an AX.25 device, so form a
++ * special "super class" of normal net devices; split their locks off into a
++ * separate class since they always nest.
++ */
++static struct lock_class_key rose_netdev_xmit_lock_key;
++
++static void rose_set_lockdep_one(struct net_device *dev,
++				 struct netdev_queue *txq,
++				 void *_unused)
++{
++	lockdep_set_class(&txq->_xmit_lock, &rose_netdev_xmit_lock_key);
++}
++
++static void rose_set_lockdep_key(struct net_device *dev)
++{
++	netdev_for_each_tx_queue(dev, rose_set_lockdep_one, NULL);
++}
++
+ /*
+  *	Convert a ROSE address into text.
+  */
+@@ -1511,6 +1531,7 @@ static int __init rose_proto_init(void)
+ 			free_netdev(dev);
+ 			goto fail;
+ 		}
++		rose_set_lockdep_key(dev);
+ 		dev_rose[i] = dev;
+ 	}
+ 
+diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
+index ad24fa1a51e63..ebc55d8842473 100644
+--- a/net/sched/sch_generic.c
++++ b/net/sched/sch_generic.c
+@@ -794,6 +794,9 @@ struct Qdisc_ops pfifo_fast_ops __read_mostly = {
+ };
+ EXPORT_SYMBOL(pfifo_fast_ops);
+ 
++static struct lock_class_key qdisc_tx_busylock;
++static struct lock_class_key qdisc_running_key;
++
+ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
+ 			  const struct Qdisc_ops *ops,
+ 			  struct netlink_ext_ack *extack)
+@@ -846,9 +849,17 @@ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
+ 	}
+ 
+ 	spin_lock_init(&sch->busylock);
++	lockdep_set_class(&sch->busylock,
++			  dev->qdisc_tx_busylock ?: &qdisc_tx_busylock);
++
+ 	/* seqlock has the same scope of busylock, for NOLOCK qdisc */
+ 	spin_lock_init(&sch->seqlock);
++	lockdep_set_class(&sch->busylock,
++			  dev->qdisc_tx_busylock ?: &qdisc_tx_busylock);
++
+ 	seqcount_init(&sch->running);
++	lockdep_set_class(&sch->running,
++			  dev->qdisc_running_key ?: &qdisc_running_key);
+ 
+ 	sch->ops = ops;
+ 	sch->flags = ops->static_flags;
+@@ -859,12 +870,6 @@ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
+ 	dev_hold(dev);
+ 	refcount_set(&sch->refcnt, 1);
+ 
+-	if (sch != &noop_qdisc) {
+-		lockdep_set_class(&sch->busylock, &dev->qdisc_tx_busylock_key);
+-		lockdep_set_class(&sch->seqlock, &dev->qdisc_tx_busylock_key);
+-		lockdep_set_class(&sch->running, &dev->qdisc_running_key);
+-	}
+-
+ 	return sch;
+ errout1:
+ 	kfree(p);
+-- 
+cgit 1.2.3-1.el7
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1778-v5.18-net-macsec-fix-rtnl-locking-issue.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1778-v5.18-net-macsec-fix-rtnl-locking-issue.patch
new file mode 100644
index 0000000..1ffaa86
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1778-v5.18-net-macsec-fix-rtnl-locking-issue.patch
@@ -0,0 +1,38 @@
+From 29ca3cdfe13b2792b8624e6f769777e8cb387f9c Mon Sep 17 00:00:00 2001
+From: Antoine Tenart <antoine.tenart@bootlin.com>
+Date: Wed, 6 May 2020 15:58:30 +0200
+Subject: net: macsec: fix rtnl locking issue
+
+netdev_update_features() must be called with the rtnl lock taken. Not
+doing so triggers a warning, as ASSERT_RTNL() is used in
+__netdev_update_features(), the first function called by
+netdev_update_features(). Fix this.
+
+Fixes: c850240b6c41 ("net: macsec: report real_dev features when HW offloading is enabled")
+Signed-off-by: Antoine Tenart <antoine.tenart@bootlin.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/macsec.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
+index d4034025c87c1..d0d31cb991803 100644
+--- a/drivers/net/macsec.c
++++ b/drivers/net/macsec.c
+@@ -2641,11 +2641,12 @@ static int macsec_upd_offload(struct sk_buff *skb, struct genl_info *info)
+ 	if (ret)
+ 		goto rollback;
+ 
+-	rtnl_unlock();
+ 	/* Force features update, since they are different for SW MACSec and
+ 	 * HW offloading cases.
+ 	 */
+ 	netdev_update_features(dev);
++
++	rtnl_unlock();
+ 	return 0;
+ 
+ rollback:
+-- 
+cgit 1.2.3-1.el7
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1779-v5.18-net-change-addr_list_lock-back-to-static-key.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1779-v5.18-net-change-addr_list_lock-back-to-static-key.patch
new file mode 100644
index 0000000..7ab7e00
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1779-v5.18-net-change-addr_list_lock-back-to-static-key.patch
@@ -0,0 +1,550 @@
+From 845e0ebb4408d4473cf60d21224a897037e9a77a Mon Sep 17 00:00:00 2001
+From: Cong Wang <xiyou.wangcong@gmail.com>
+Date: Mon, 8 Jun 2020 14:53:01 -0700
+Subject: net: change addr_list_lock back to static key
+
+The dynamic key update for addr_list_lock still causes troubles,
+for example the following race condition still exists:
+
+CPU 0:				CPU 1:
+(RCU read lock)			(RTNL lock)
+dev_mc_seq_show()		netdev_update_lockdep_key()
+				  -> lockdep_unregister_key()
+ -> netif_addr_lock_bh()
+
+because lockdep doesn't provide an API to update it atomically.
+Therefore, we have to move it back to static keys and use subclass
+for nest locking like before.
+
+In commit 1a33e10e4a95 ("net: partially revert dynamic lockdep key
+changes"), I already reverted most parts of commit ab92d68fc22f
+("net: core: add generic lockdep keys").
+
+This patch reverts the rest and also part of commit f3b0a18bb6cb
+("net: remove unnecessary variables and callback"). After this
+patch, addr_list_lock changes back to using static keys and
+subclasses to satisfy lockdep. Thanks to dev->lower_level, we do
+not have to change back to ->ndo_get_lock_subclass().
+
+And hopefully this reduces some syzbot lockdep noises too.
+
+Reported-by: syzbot+f3a0e80c34b3fc28ac5e@syzkaller.appspotmail.com
+Cc: Taehee Yoo <ap420073@gmail.com>
+Cc: Dmitry Vyukov <dvyukov@google.com>
+Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/bonding/bond_main.c                  |  2 --
+ drivers/net/bonding/bond_options.c               |  2 --
+ drivers/net/hamradio/bpqether.c                  |  2 ++
+ drivers/net/macsec.c                             |  5 ++++
+ drivers/net/macvlan.c                            | 13 ++++++++--
+ drivers/net/vxlan.c                              |  4 +---
+ drivers/net/wireless/intersil/hostap/hostap_hw.c |  3 +++
+ include/linux/netdevice.h                        | 12 ++++++----
+ net/8021q/vlan_dev.c                             |  8 +++++--
+ net/batman-adv/soft-interface.c                  |  2 ++
+ net/bridge/br_device.c                           |  8 +++++++
+ net/core/dev.c                                   | 30 +++++++++++++-----------
+ net/core/dev_addr_lists.c                        | 12 +++++-----
+ net/core/rtnetlink.c                             |  1 -
+ net/dsa/master.c                                 |  4 ++++
+ net/netrom/af_netrom.c                           |  2 ++
+ net/rose/af_rose.c                               |  2 ++
+ 17 files changed, 76 insertions(+), 36 deletions(-)
+
+diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
+index a25c65d4af716..004919aea5fbf 100644
+--- a/drivers/net/bonding/bond_main.c
++++ b/drivers/net/bonding/bond_main.c
+@@ -3687,8 +3687,6 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd
+ 	case BOND_RELEASE_OLD:
+ 	case SIOCBONDRELEASE:
+ 		res = bond_release(bond_dev, slave_dev);
+-		if (!res)
+-			netdev_update_lockdep_key(slave_dev);
+ 		break;
+ 	case BOND_SETHWADDR_OLD:
+ 	case SIOCBONDSETHWADDR:
+diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c
+index 215c109232893..ddb3916d3506b 100644
+--- a/drivers/net/bonding/bond_options.c
++++ b/drivers/net/bonding/bond_options.c
+@@ -1398,8 +1398,6 @@ static int bond_option_slaves_set(struct bonding *bond,
+ 	case '-':
+ 		slave_dbg(bond->dev, dev, "Releasing interface\n");
+ 		ret = bond_release(bond->dev, dev);
+-		if (!ret)
+-			netdev_update_lockdep_key(dev);
+ 		break;
+ 
+ 	default:
+diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c
+index 60dcaf2a04a91..1ad6085994b1c 100644
+--- a/drivers/net/hamradio/bpqether.c
++++ b/drivers/net/hamradio/bpqether.c
+@@ -113,6 +113,7 @@ static LIST_HEAD(bpq_devices);
+  * off into a separate class since they always nest.
+  */
+ static struct lock_class_key bpq_netdev_xmit_lock_key;
++static struct lock_class_key bpq_netdev_addr_lock_key;
+ 
+ static void bpq_set_lockdep_class_one(struct net_device *dev,
+ 				      struct netdev_queue *txq,
+@@ -123,6 +124,7 @@ static void bpq_set_lockdep_class_one(struct net_device *dev,
+ 
+ static void bpq_set_lockdep_class(struct net_device *dev)
+ {
++	lockdep_set_class(&dev->addr_list_lock, &bpq_netdev_addr_lock_key);
+ 	netdev_for_each_tx_queue(dev, bpq_set_lockdep_class_one, NULL);
+ }
+ 
+diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
+index 20b53e255f68a..e56547bfdac9a 100644
+--- a/drivers/net/macsec.c
++++ b/drivers/net/macsec.c
+@@ -3999,6 +3999,8 @@ static int macsec_add_dev(struct net_device *dev, sci_t sci, u8 icv_len)
+ 	return 0;
+ }
+ 
++static struct lock_class_key macsec_netdev_addr_lock_key;
++
+ static int macsec_newlink(struct net *net, struct net_device *dev,
+ 			  struct nlattr *tb[], struct nlattr *data[],
+ 			  struct netlink_ext_ack *extack)
+@@ -4050,6 +4052,9 @@ static int macsec_newlink(struct net *net, struct net_device *dev,
+ 		return err;
+ 
+ 	netdev_lockdep_set_classes(dev);
++	lockdep_set_class_and_subclass(&dev->addr_list_lock,
++				       &macsec_netdev_addr_lock_key,
++				       dev->lower_level);
+ 
+ 	err = netdev_upper_dev_link(real_dev, dev, extack);
+ 	if (err < 0)
+diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
+index 563aed5b3d9fe..6a6cc9f753075 100644
+--- a/drivers/net/macvlan.c
++++ b/drivers/net/macvlan.c
+@@ -860,6 +860,8 @@ static int macvlan_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+  * "super class" of normal network devices; split their locks off into a
+  * separate class since they always nest.
+  */
++static struct lock_class_key macvlan_netdev_addr_lock_key;
++
+ #define ALWAYS_ON_OFFLOADS \
+ 	(NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_GSO_SOFTWARE | \
+ 	 NETIF_F_GSO_ROBUST | NETIF_F_GSO_ENCAP_ALL)
+@@ -875,6 +877,14 @@ static int macvlan_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+ #define MACVLAN_STATE_MASK \
+ 	((1<<__LINK_STATE_NOCARRIER) | (1<<__LINK_STATE_DORMANT))
+ 
++static void macvlan_set_lockdep_class(struct net_device *dev)
++{
++	netdev_lockdep_set_classes(dev);
++	lockdep_set_class_and_subclass(&dev->addr_list_lock,
++				       &macvlan_netdev_addr_lock_key,
++				       dev->lower_level);
++}
++
+ static int macvlan_init(struct net_device *dev)
+ {
+ 	struct macvlan_dev *vlan = netdev_priv(dev);
+@@ -892,8 +902,7 @@ static int macvlan_init(struct net_device *dev)
+ 	dev->gso_max_size	= lowerdev->gso_max_size;
+ 	dev->gso_max_segs	= lowerdev->gso_max_segs;
+ 	dev->hard_header_len	= lowerdev->hard_header_len;
+-
+-	netdev_lockdep_set_classes(dev);
++	macvlan_set_lockdep_class(dev);
+ 
+ 	vlan->pcpu_stats = netdev_alloc_pcpu_stats(struct vlan_pcpu_stats);
+ 	if (!vlan->pcpu_stats)
+diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
+index 5bb448ae6c9c4..47424b2da6437 100644
+--- a/drivers/net/vxlan.c
++++ b/drivers/net/vxlan.c
+@@ -4245,10 +4245,8 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[],
+ 		mod_timer(&vxlan->age_timer, jiffies);
+ 
+ 	netdev_adjacent_change_commit(dst->remote_dev, lowerdev, dev);
+-	if (lowerdev && lowerdev != dst->remote_dev) {
++	if (lowerdev && lowerdev != dst->remote_dev)
+ 		dst->remote_dev = lowerdev;
+-		netdev_update_lockdep_key(lowerdev);
+-	}
+ 	vxlan_config_apply(dev, &conf, lowerdev, vxlan->net, true);
+ 	return 0;
+ }
+diff --git a/drivers/net/wireless/intersil/hostap/hostap_hw.c b/drivers/net/wireless/intersil/hostap/hostap_hw.c
+index aadf3dec5bf32..2ab34cf74ecc3 100644
+--- a/drivers/net/wireless/intersil/hostap/hostap_hw.c
++++ b/drivers/net/wireless/intersil/hostap/hostap_hw.c
+@@ -3048,6 +3048,7 @@ static void prism2_clear_set_tim_queue(local_info_t *local)
+  * This is a natural nesting, which needs a split lock type.
+  */
+ static struct lock_class_key hostap_netdev_xmit_lock_key;
++static struct lock_class_key hostap_netdev_addr_lock_key;
+ 
+ static void prism2_set_lockdep_class_one(struct net_device *dev,
+ 					 struct netdev_queue *txq,
+@@ -3059,6 +3060,8 @@ static void prism2_set_lockdep_class_one(struct net_device *dev,
+ 
+ static void prism2_set_lockdep_class(struct net_device *dev)
+ {
++	lockdep_set_class(&dev->addr_list_lock,
++			  &hostap_netdev_addr_lock_key);
+ 	netdev_for_each_tx_queue(dev, prism2_set_lockdep_class_one, NULL);
+ }
+ 
+diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
+index 1a96e9c4ec36f..e2825e27ef89d 100644
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -1821,8 +1821,6 @@ enum netdev_priv_flags {
+  *			for hardware timestamping
+  *	@sfp_bus:	attached &struct sfp_bus structure.
+  *
+- *	@addr_list_lock_key:	lockdep class annotating
+- *				net_device->addr_list_lock spinlock
+  *	@qdisc_tx_busylock: lockdep class annotating Qdisc->busylock spinlock
+  *	@qdisc_running_key: lockdep class annotating Qdisc->running seqcount
+  *
+@@ -2125,7 +2123,6 @@ struct net_device {
+ #endif
+ 	struct phy_device	*phydev;
+ 	struct sfp_bus		*sfp_bus;
+-	struct lock_class_key	addr_list_lock_key;
+ 	struct lock_class_key	*qdisc_tx_busylock;
+ 	struct lock_class_key	*qdisc_running_key;
+ 	bool			proto_down;
+@@ -2217,10 +2214,13 @@ static inline void netdev_for_each_tx_queue(struct net_device *dev,
+ 	static struct lock_class_key qdisc_tx_busylock_key;	\
+ 	static struct lock_class_key qdisc_running_key;		\
+ 	static struct lock_class_key qdisc_xmit_lock_key;	\
++	static struct lock_class_key dev_addr_list_lock_key;	\
+ 	unsigned int i;						\
+ 								\
+ 	(dev)->qdisc_tx_busylock = &qdisc_tx_busylock_key;	\
+ 	(dev)->qdisc_running_key = &qdisc_running_key;		\
++	lockdep_set_class(&(dev)->addr_list_lock,		\
++			  &dev_addr_list_lock_key);		\
+ 	for (i = 0; i < (dev)->num_tx_queues; i++)		\
+ 		lockdep_set_class(&(dev)->_tx[i]._xmit_lock,	\
+ 				  &qdisc_xmit_lock_key);	\
+@@ -3253,7 +3253,6 @@ static inline void netif_stop_queue(struct net_device *dev)
+ }
+ 
+ void netif_tx_stop_all_queues(struct net_device *dev);
+-void netdev_update_lockdep_key(struct net_device *dev);
+ 
+ static inline bool netif_tx_queue_stopped(const struct netdev_queue *dev_queue)
+ {
+@@ -4239,6 +4238,11 @@ static inline void netif_addr_lock(struct net_device *dev)
+ 	spin_lock(&dev->addr_list_lock);
+ }
+ 
++static inline void netif_addr_lock_nested(struct net_device *dev)
++{
++	spin_lock_nested(&dev->addr_list_lock, dev->lower_level);
++}
++
+ static inline void netif_addr_lock_bh(struct net_device *dev)
+ {
+ 	spin_lock_bh(&dev->addr_list_lock);
+diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
+index f00bb57f0f600..c8d6a07e23c57 100644
+--- a/net/8021q/vlan_dev.c
++++ b/net/8021q/vlan_dev.c
+@@ -494,6 +494,7 @@ static void vlan_dev_set_rx_mode(struct net_device *vlan_dev)
+  * separate class since they always nest.
+  */
+ static struct lock_class_key vlan_netdev_xmit_lock_key;
++static struct lock_class_key vlan_netdev_addr_lock_key;
+ 
+ static void vlan_dev_set_lockdep_one(struct net_device *dev,
+ 				     struct netdev_queue *txq,
+@@ -502,8 +503,11 @@ static void vlan_dev_set_lockdep_one(struct net_device *dev,
+ 	lockdep_set_class(&txq->_xmit_lock, &vlan_netdev_xmit_lock_key);
+ }
+ 
+-static void vlan_dev_set_lockdep_class(struct net_device *dev)
++static void vlan_dev_set_lockdep_class(struct net_device *dev, int subclass)
+ {
++	lockdep_set_class_and_subclass(&dev->addr_list_lock,
++				       &vlan_netdev_addr_lock_key,
++				       subclass);
+ 	netdev_for_each_tx_queue(dev, vlan_dev_set_lockdep_one, NULL);
+ }
+ 
+@@ -597,7 +601,7 @@ static int vlan_dev_init(struct net_device *dev)
+ 
+ 	SET_NETDEV_DEVTYPE(dev, &vlan_type);
+ 
+-	vlan_dev_set_lockdep_class(dev);
++	vlan_dev_set_lockdep_class(dev, dev->lower_level);
+ 
+ 	vlan->vlan_pcpu_stats = netdev_alloc_pcpu_stats(struct vlan_pcpu_stats);
+ 	if (!vlan->vlan_pcpu_stats)
+diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c
+index 0ddd80130ea36..f1f1c86f34193 100644
+--- a/net/batman-adv/soft-interface.c
++++ b/net/batman-adv/soft-interface.c
+@@ -745,6 +745,7 @@ static int batadv_interface_kill_vid(struct net_device *dev, __be16 proto,
+  * separate class since they always nest.
+  */
+ static struct lock_class_key batadv_netdev_xmit_lock_key;
++static struct lock_class_key batadv_netdev_addr_lock_key;
+ 
+ /**
+  * batadv_set_lockdep_class_one() - Set lockdep class for a single tx queue
+@@ -765,6 +766,7 @@ static void batadv_set_lockdep_class_one(struct net_device *dev,
+  */
+ static void batadv_set_lockdep_class(struct net_device *dev)
+ {
++	lockdep_set_class(&dev->addr_list_lock, &batadv_netdev_addr_lock_key);
+ 	netdev_for_each_tx_queue(dev, batadv_set_lockdep_class_one, NULL);
+ }
+ 
+diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
+index 8ec1362588af1..8c7b78f8bc230 100644
+--- a/net/bridge/br_device.c
++++ b/net/bridge/br_device.c
+@@ -105,6 +105,13 @@ out:
+ 	return NETDEV_TX_OK;
+ }
+ 
++static struct lock_class_key bridge_netdev_addr_lock_key;
++
++static void br_set_lockdep_class(struct net_device *dev)
++{
++	lockdep_set_class(&dev->addr_list_lock, &bridge_netdev_addr_lock_key);
++}
++
+ static int br_dev_init(struct net_device *dev)
+ {
+ 	struct net_bridge *br = netdev_priv(dev);
+@@ -143,6 +150,7 @@ static int br_dev_init(struct net_device *dev)
+ 		br_fdb_hash_fini(br);
+ 	}
+ 
++	br_set_lockdep_class(dev);
+ 	return err;
+ }
+ 
+diff --git a/net/core/dev.c b/net/core/dev.c
+index 061496a1f640f..6bc2388141f6f 100644
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -439,6 +439,7 @@ static const char *const netdev_lock_name[] = {
+ 	"_xmit_IEEE802154", "_xmit_VOID", "_xmit_NONE"};
+ 
+ static struct lock_class_key netdev_xmit_lock_key[ARRAY_SIZE(netdev_lock_type)];
++static struct lock_class_key netdev_addr_lock_key[ARRAY_SIZE(netdev_lock_type)];
+ 
+ static inline unsigned short netdev_lock_pos(unsigned short dev_type)
+ {
+@@ -460,11 +461,25 @@ static inline void netdev_set_xmit_lockdep_class(spinlock_t *lock,
+ 	lockdep_set_class_and_name(lock, &netdev_xmit_lock_key[i],
+ 				   netdev_lock_name[i]);
+ }
++
++static inline void netdev_set_addr_lockdep_class(struct net_device *dev)
++{
++	int i;
++
++	i = netdev_lock_pos(dev->type);
++	lockdep_set_class_and_name(&dev->addr_list_lock,
++				   &netdev_addr_lock_key[i],
++				   netdev_lock_name[i]);
++}
+ #else
+ static inline void netdev_set_xmit_lockdep_class(spinlock_t *lock,
+ 						 unsigned short dev_type)
+ {
+ }
++
++static inline void netdev_set_addr_lockdep_class(struct net_device *dev)
++{
++}
+ #endif
+ 
+ /*******************************************************************************
+@@ -9373,15 +9388,6 @@ void netif_tx_stop_all_queues(struct net_device *dev)
+ }
+ EXPORT_SYMBOL(netif_tx_stop_all_queues);
+ 
+-void netdev_update_lockdep_key(struct net_device *dev)
+-{
+-	lockdep_unregister_key(&dev->addr_list_lock_key);
+-	lockdep_register_key(&dev->addr_list_lock_key);
+-
+-	lockdep_set_class(&dev->addr_list_lock, &dev->addr_list_lock_key);
+-}
+-EXPORT_SYMBOL(netdev_update_lockdep_key);
+-
+ /**
+  *	register_netdevice	- register a network device
+  *	@dev: device to register
+@@ -9420,7 +9426,7 @@ int register_netdevice(struct net_device *dev)
+ 		return ret;
+ 
+ 	spin_lock_init(&dev->addr_list_lock);
+-	lockdep_set_class(&dev->addr_list_lock, &dev->addr_list_lock_key);
++	netdev_set_addr_lockdep_class(dev);
+ 
+ 	ret = dev_get_valid_name(net, dev, dev->name);
+ 	if (ret < 0)
+@@ -9939,8 +9945,6 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
+ 
+ 	dev_net_set(dev, &init_net);
+ 
+-	lockdep_register_key(&dev->addr_list_lock_key);
+-
+ 	dev->gso_max_size = GSO_MAX_SIZE;
+ 	dev->gso_max_segs = GSO_MAX_SEGS;
+ 	dev->upper_level = 1;
+@@ -10028,8 +10032,6 @@ void free_netdev(struct net_device *dev)
+ 	free_percpu(dev->xdp_bulkq);
+ 	dev->xdp_bulkq = NULL;
+ 
+-	lockdep_unregister_key(&dev->addr_list_lock_key);
+-
+ 	/*  Compatibility with error handling in drivers */
+ 	if (dev->reg_state == NETREG_UNINITIALIZED) {
+ 		netdev_freemem(dev);
+diff --git a/net/core/dev_addr_lists.c b/net/core/dev_addr_lists.c
+index 2f949b5a1eb9c..6393ba930097b 100644
+--- a/net/core/dev_addr_lists.c
++++ b/net/core/dev_addr_lists.c
+@@ -637,7 +637,7 @@ int dev_uc_sync(struct net_device *to, struct net_device *from)
+ 	if (to->addr_len != from->addr_len)
+ 		return -EINVAL;
+ 
+-	netif_addr_lock(to);
++	netif_addr_lock_nested(to);
+ 	err = __hw_addr_sync(&to->uc, &from->uc, to->addr_len);
+ 	if (!err)
+ 		__dev_set_rx_mode(to);
+@@ -667,7 +667,7 @@ int dev_uc_sync_multiple(struct net_device *to, struct net_device *from)
+ 	if (to->addr_len != from->addr_len)
+ 		return -EINVAL;
+ 
+-	netif_addr_lock(to);
++	netif_addr_lock_nested(to);
+ 	err = __hw_addr_sync_multiple(&to->uc, &from->uc, to->addr_len);
+ 	if (!err)
+ 		__dev_set_rx_mode(to);
+@@ -691,7 +691,7 @@ void dev_uc_unsync(struct net_device *to, struct net_device *from)
+ 		return;
+ 
+ 	netif_addr_lock_bh(from);
+-	netif_addr_lock(to);
++	netif_addr_lock_nested(to);
+ 	__hw_addr_unsync(&to->uc, &from->uc, to->addr_len);
+ 	__dev_set_rx_mode(to);
+ 	netif_addr_unlock(to);
+@@ -858,7 +858,7 @@ int dev_mc_sync(struct net_device *to, struct net_device *from)
+ 	if (to->addr_len != from->addr_len)
+ 		return -EINVAL;
+ 
+-	netif_addr_lock(to);
++	netif_addr_lock_nested(to);
+ 	err = __hw_addr_sync(&to->mc, &from->mc, to->addr_len);
+ 	if (!err)
+ 		__dev_set_rx_mode(to);
+@@ -888,7 +888,7 @@ int dev_mc_sync_multiple(struct net_device *to, struct net_device *from)
+ 	if (to->addr_len != from->addr_len)
+ 		return -EINVAL;
+ 
+-	netif_addr_lock(to);
++	netif_addr_lock_nested(to);
+ 	err = __hw_addr_sync_multiple(&to->mc, &from->mc, to->addr_len);
+ 	if (!err)
+ 		__dev_set_rx_mode(to);
+@@ -912,7 +912,7 @@ void dev_mc_unsync(struct net_device *to, struct net_device *from)
+ 		return;
+ 
+ 	netif_addr_lock_bh(from);
+-	netif_addr_lock(to);
++	netif_addr_lock_nested(to);
+ 	__hw_addr_unsync(&to->mc, &from->mc, to->addr_len);
+ 	__dev_set_rx_mode(to);
+ 	netif_addr_unlock(to);
+diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
+index 2269199c58910..9aedc15736adf 100644
+--- a/net/core/rtnetlink.c
++++ b/net/core/rtnetlink.c
+@@ -2462,7 +2462,6 @@ static int do_set_master(struct net_device *dev, int ifindex,
+ 			err = ops->ndo_del_slave(upper_dev, dev);
+ 			if (err)
+ 				return err;
+-			netdev_update_lockdep_key(dev);
+ 		} else {
+ 			return -EOPNOTSUPP;
+ 		}
+diff --git a/net/dsa/master.c b/net/dsa/master.c
+index a621367c6e8c2..480a61460c239 100644
+--- a/net/dsa/master.c
++++ b/net/dsa/master.c
+@@ -327,6 +327,8 @@ static void dsa_master_reset_mtu(struct net_device *dev)
+ 	rtnl_unlock();
+ }
+ 
++static struct lock_class_key dsa_master_addr_list_lock_key;
++
+ int dsa_master_setup(struct net_device *dev, struct dsa_port *cpu_dp)
+ {
+ 	int ret;
+@@ -345,6 +347,8 @@ int dsa_master_setup(struct net_device *dev, struct dsa_port *cpu_dp)
+ 	wmb();
+ 
+ 	dev->dsa_ptr = cpu_dp;
++	lockdep_set_class(&dev->addr_list_lock,
++			  &dsa_master_addr_list_lock_key);
+ 	ret = dsa_master_ethtool_setup(dev);
+ 	if (ret)
+ 		return ret;
+diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
+index eccc7d366e17f..f90ef6934b8f4 100644
+--- a/net/netrom/af_netrom.c
++++ b/net/netrom/af_netrom.c
+@@ -70,6 +70,7 @@ static const struct proto_ops nr_proto_ops;
+  * separate class since they always nest.
+  */
+ static struct lock_class_key nr_netdev_xmit_lock_key;
++static struct lock_class_key nr_netdev_addr_lock_key;
+ 
+ static void nr_set_lockdep_one(struct net_device *dev,
+ 			       struct netdev_queue *txq,
+@@ -80,6 +81,7 @@ static void nr_set_lockdep_one(struct net_device *dev,
+ 
+ static void nr_set_lockdep_key(struct net_device *dev)
+ {
++	lockdep_set_class(&dev->addr_list_lock, &nr_netdev_addr_lock_key);
+ 	netdev_for_each_tx_queue(dev, nr_set_lockdep_one, NULL);
+ }
+ 
+diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
+index e7a872207b464..ce85656ac9c15 100644
+--- a/net/rose/af_rose.c
++++ b/net/rose/af_rose.c
+@@ -71,6 +71,7 @@ ax25_address rose_callsign;
+  * separate class since they always nest.
+  */
+ static struct lock_class_key rose_netdev_xmit_lock_key;
++static struct lock_class_key rose_netdev_addr_lock_key;
+ 
+ static void rose_set_lockdep_one(struct net_device *dev,
+ 				 struct netdev_queue *txq,
+@@ -81,6 +82,7 @@ static void rose_set_lockdep_one(struct net_device *dev,
+ 
+ static void rose_set_lockdep_key(struct net_device *dev)
+ {
++	lockdep_set_class(&dev->addr_list_lock, &rose_netdev_addr_lock_key);
+ 	netdev_for_each_tx_queue(dev, rose_set_lockdep_one, NULL);
+ }
+ 
+-- 
+cgit 1.2.3-1.el7
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1780-v5.18-net-get-rid-of-lockdep_set_class_and_subclass.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1780-v5.18-net-get-rid-of-lockdep_set_class_and_subclass.patch
new file mode 100644
index 0000000..db820ea
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1780-v5.18-net-get-rid-of-lockdep_set_class_and_subclass.patch
@@ -0,0 +1,88 @@
+From be74294ffa24f5fbc0d6643842e3e095447e17a2 Mon Sep 17 00:00:00 2001
+From: Cong Wang <xiyou.wangcong@gmail.com>
+Date: Fri, 26 Jun 2020 11:24:22 -0700
+Subject: net: get rid of lockdep_set_class_and_subclass()
+
+lockdep_set_class_and_subclass() is meant to reduce
+the _nested() annotations by assigning a default subclass.
+For addr_list_lock, we have to compute the subclass at
+run-time as the netdevice topology changes after creation.
+
+So, we should just get rid of these
+lockdep_set_class_and_subclass() and stick with our _nested()
+annotations.
+
+Fixes: 845e0ebb4408 ("net: change addr_list_lock back to static key")
+Suggested-by: Taehee Yoo <ap420073@gmail.com>
+Cc: Dmitry Vyukov <dvyukov@google.com>
+Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/macsec.c  | 5 ++---
+ drivers/net/macvlan.c | 5 ++---
+ net/8021q/vlan_dev.c  | 9 ++++-----
+ 3 files changed, 8 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
+index e56547bfdac9a..9159846b8b938 100644
+--- a/drivers/net/macsec.c
++++ b/drivers/net/macsec.c
+@@ -4052,9 +4052,8 @@ static int macsec_newlink(struct net *net, struct net_device *dev,
+ 		return err;
+ 
+ 	netdev_lockdep_set_classes(dev);
+-	lockdep_set_class_and_subclass(&dev->addr_list_lock,
+-				       &macsec_netdev_addr_lock_key,
+-				       dev->lower_level);
++	lockdep_set_class(&dev->addr_list_lock,
++			  &macsec_netdev_addr_lock_key);
+ 
+ 	err = netdev_upper_dev_link(real_dev, dev, extack);
+ 	if (err < 0)
+diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
+index 6a6cc9f753075..4942f6112e51f 100644
+--- a/drivers/net/macvlan.c
++++ b/drivers/net/macvlan.c
+@@ -880,9 +880,8 @@ static struct lock_class_key macvlan_netdev_addr_lock_key;
+ static void macvlan_set_lockdep_class(struct net_device *dev)
+ {
+ 	netdev_lockdep_set_classes(dev);
+-	lockdep_set_class_and_subclass(&dev->addr_list_lock,
+-				       &macvlan_netdev_addr_lock_key,
+-				       dev->lower_level);
++	lockdep_set_class(&dev->addr_list_lock,
++			  &macvlan_netdev_addr_lock_key);
+ }
+ 
+ static int macvlan_init(struct net_device *dev)
+diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
+index c8d6a07e23c57..3dd7c972677be 100644
+--- a/net/8021q/vlan_dev.c
++++ b/net/8021q/vlan_dev.c
+@@ -503,11 +503,10 @@ static void vlan_dev_set_lockdep_one(struct net_device *dev,
+ 	lockdep_set_class(&txq->_xmit_lock, &vlan_netdev_xmit_lock_key);
+ }
+ 
+-static void vlan_dev_set_lockdep_class(struct net_device *dev, int subclass)
++static void vlan_dev_set_lockdep_class(struct net_device *dev)
+ {
+-	lockdep_set_class_and_subclass(&dev->addr_list_lock,
+-				       &vlan_netdev_addr_lock_key,
+-				       subclass);
++	lockdep_set_class(&dev->addr_list_lock,
++			  &vlan_netdev_addr_lock_key);
+ 	netdev_for_each_tx_queue(dev, vlan_dev_set_lockdep_one, NULL);
+ }
+ 
+@@ -601,7 +600,7 @@ static int vlan_dev_init(struct net_device *dev)
+ 
+ 	SET_NETDEV_DEVTYPE(dev, &vlan_type);
+ 
+-	vlan_dev_set_lockdep_class(dev, dev->lower_level);
++	vlan_dev_set_lockdep_class(dev);
+ 
+ 	vlan->vlan_pcpu_stats = netdev_alloc_pcpu_stats(struct vlan_pcpu_stats);
+ 	if (!vlan->vlan_pcpu_stats)
+-- 
+cgit 1.2.3-1.el7
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1781-v5.18-netlink-consistently-use-NLA_POLICY_MIN_LEN.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1781-v5.18-netlink-consistently-use-NLA_POLICY_MIN_LEN.patch
new file mode 100644
index 0000000..27e4e8e
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1781-v5.18-netlink-consistently-use-NLA_POLICY_MIN_LEN.patch
@@ -0,0 +1,50 @@
+From bc0435855041d7fff0b83dd992fc4be34aa11afb Mon Sep 17 00:00:00 2001
+From: Johannes Berg <johannes.berg@intel.com>
+Date: Tue, 18 Aug 2020 10:17:32 +0200
+Subject: netlink: consistently use NLA_POLICY_MIN_LEN()
+
+Change places that open-code NLA_POLICY_MIN_LEN() to
+use the macro instead, giving us flexibility in how we
+handle the details of the macro.
+
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/macsec.c            | 2 +-
+ drivers/net/wireguard/netlink.c | 4 ++--
+ net/wireless/nl80211.c          | 6 +++---
+ 3 files changed, 6 insertions(+), 6 deletions(-)
+
+--- a/drivers/net/macsec.c
++++ b/drivers/net/macsec.c
+@@ -1608,7 +1608,7 @@ static const struct nla_policy macsec_ge
+ static const struct nla_policy macsec_genl_sa_policy[NUM_MACSEC_SA_ATTR] = {
+ 	[MACSEC_SA_ATTR_AN] = { .type = NLA_U8 },
+ 	[MACSEC_SA_ATTR_ACTIVE] = { .type = NLA_U8 },
+-	[MACSEC_SA_ATTR_PN] = { .type = NLA_MIN_LEN, .len = 4 },
++	[MACSEC_SA_ATTR_PN] = NLA_POLICY_MIN_LEN(4),
+ 	[MACSEC_SA_ATTR_KEYID] = { .type = NLA_BINARY,
+ 				   .len = MACSEC_KEYID_LEN, },
+ 	[MACSEC_SA_ATTR_KEY] = { .type = NLA_BINARY,
+--- a/net/wireless/nl80211.c
++++ b/net/wireless/nl80211.c
+@@ -676,7 +676,7 @@ nl80211_wowlan_tcp_policy[NUM_NL80211_WO
+ 	},
+ 	[NL80211_WOWLAN_TCP_SRC_PORT] = { .type = NLA_U16 },
+ 	[NL80211_WOWLAN_TCP_DST_PORT] = { .type = NLA_U16 },
+-	[NL80211_WOWLAN_TCP_DATA_PAYLOAD] = { .type = NLA_MIN_LEN, .len = 1 },
++	[NL80211_WOWLAN_TCP_DATA_PAYLOAD] = NLA_POLICY_MIN_LEN(1),
+ 	[NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ] = {
+ 		.len = sizeof(struct nl80211_wowlan_tcp_data_seq)
+ 	},
+@@ -684,8 +684,8 @@ nl80211_wowlan_tcp_policy[NUM_NL80211_WO
+ 		.len = sizeof(struct nl80211_wowlan_tcp_data_token)
+ 	},
+ 	[NL80211_WOWLAN_TCP_DATA_INTERVAL] = { .type = NLA_U32 },
+-	[NL80211_WOWLAN_TCP_WAKE_PAYLOAD] = { .type = NLA_MIN_LEN, .len = 1 },
+-	[NL80211_WOWLAN_TCP_WAKE_MASK] = { .type = NLA_MIN_LEN, .len = 1 },
++	[NL80211_WOWLAN_TCP_WAKE_PAYLOAD] = NLA_POLICY_MIN_LEN(1),
++	[NL80211_WOWLAN_TCP_WAKE_MASK] = NLA_POLICY_MIN_LEN(1),
+ };
+ #endif /* CONFIG_PM */
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1782-v5.18-net-macsec-Add-missing-documentation-for-gro_cells.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1782-v5.18-net-macsec-Add-missing-documentation-for-gro_cells.patch
new file mode 100644
index 0000000..7d781e7
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1782-v5.18-net-macsec-Add-missing-documentation-for-gro_cells.patch
@@ -0,0 +1,31 @@
+From ecdc5689d93eab429f7a48ae058b7c516a4a3c95 Mon Sep 17 00:00:00 2001
+From: Lee Jones <lee.jones@linaro.org>
+Date: Mon, 2 Nov 2020 11:45:07 +0000
+Subject: net: macsec: Add missing documentation for 'gro_cells'
+
+Fixes the following W=1 kernel build warning(s):
+
+ drivers/net/macsec.c:113: warning: Function parameter or member 'gro_cells' not described in 'macsec_dev'
+
+Signed-off-by: Lee Jones <lee.jones@linaro.org>
+Link: https://lore.kernel.org/r/20201102114512.1062724-26-lee.jones@linaro.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/macsec.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
+index 11ca5fa902a16..92425e1fd70c0 100644
+--- a/drivers/net/macsec.c
++++ b/drivers/net/macsec.c
+@@ -101,6 +101,7 @@ struct pcpu_secy_stats {
+  * @real_dev: pointer to underlying netdevice
+  * @stats: MACsec device stats
+  * @secys: linked list of SecY's on the underlying device
++ * @gro_cells: pointer to the Generic Receive Offload cell
+  * @offload: status of offloading on the MACsec device
+  */
+ struct macsec_dev {
+-- 
+cgit 1.2.3-1.el7
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1783-v5.18-net-macsec-fix-the-length-used-to-copy-the-key-for-offloading.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1783-v5.18-net-macsec-fix-the-length-used-to-copy-the-key-for-offloading.patch
new file mode 100644
index 0000000..ed68254
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1783-v5.18-net-macsec-fix-the-length-used-to-copy-the-key-for-offloading.patch
@@ -0,0 +1,60 @@
+From 1f7fe5121127e037b86592ba42ce36515ea0e3f7 Mon Sep 17 00:00:00 2001
+From: Antoine Tenart <atenart@kernel.org>
+Date: Thu, 24 Jun 2021 11:38:28 +0200
+Subject: net: macsec: fix the length used to copy the key for offloading
+
+The key length used when offloading macsec to Ethernet or PHY drivers
+was set to MACSEC_KEYID_LEN (16), which is an issue as:
+- This was never meant to be the key length.
+- The key length can be > 16.
+
+Fix this by using MACSEC_MAX_KEY_LEN to store the key (the max length
+accepted in uAPI) and secy->key_len to copy it.
+
+Fixes: 3cf3227a21d1 ("net: macsec: hardware offloading infrastructure")
+Reported-by: Lior Nahmanson <liorna@nvidia.com>
+Signed-off-by: Antoine Tenart <atenart@kernel.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/macsec.c | 4 ++--
+ include/net/macsec.h | 2 +-
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
+index 92425e1fd70c0..93dc48b9b4f24 100644
+--- a/drivers/net/macsec.c
++++ b/drivers/net/macsec.c
+@@ -1819,7 +1819,7 @@ static int macsec_add_rxsa(struct sk_buff *skb, struct genl_info *info)
+ 		ctx.sa.rx_sa = rx_sa;
+ 		ctx.secy = secy;
+ 		memcpy(ctx.sa.key, nla_data(tb_sa[MACSEC_SA_ATTR_KEY]),
+-		       MACSEC_KEYID_LEN);
++		       secy->key_len);
+ 
+ 		err = macsec_offload(ops->mdo_add_rxsa, &ctx);
+ 		if (err)
+@@ -2061,7 +2061,7 @@ static int macsec_add_txsa(struct sk_buff *skb, struct genl_info *info)
+ 		ctx.sa.tx_sa = tx_sa;
+ 		ctx.secy = secy;
+ 		memcpy(ctx.sa.key, nla_data(tb_sa[MACSEC_SA_ATTR_KEY]),
+-		       MACSEC_KEYID_LEN);
++		       secy->key_len);
+ 
+ 		err = macsec_offload(ops->mdo_add_txsa, &ctx);
+ 		if (err)
+diff --git a/include/net/macsec.h b/include/net/macsec.h
+index 52874cdfe2260..d6fa6b97f6efa 100644
+--- a/include/net/macsec.h
++++ b/include/net/macsec.h
+@@ -241,7 +241,7 @@ struct macsec_context {
+ 	struct macsec_rx_sc *rx_sc;
+ 	struct {
+ 		unsigned char assoc_num;
+-		u8 key[MACSEC_KEYID_LEN];
++		u8 key[MACSEC_MAX_KEY_LEN];
+ 		union {
+ 			struct macsec_rx_sa *rx_sa;
+ 			struct macsec_tx_sa *tx_sa;
+-- 
+cgit 1.2.3-1.el7
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1784-v5.18-net-drivers-get-ready-for-const-netdev-dev_addr.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1784-v5.18-net-drivers-get-ready-for-const-netdev-dev_addr.patch
new file mode 100644
index 0000000..ad3bd2f
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1784-v5.18-net-drivers-get-ready-for-const-netdev-dev_addr.patch
@@ -0,0 +1,73 @@
+From 8bc7823ed3bd5b87765e1b3d6f72c69624680921 Mon Sep 17 00:00:00 2001
+From: Jakub Kicinski <kuba@kernel.org>
+Date: Fri, 22 Oct 2021 16:21:02 -0700
+Subject: net: drivers: get ready for const netdev->dev_addr
+
+Commit 406f42fa0d3c ("net-next: When a bond have a massive amount
+of VLANs...") introduced a rbtree for faster Ethernet address look
+up. To maintain netdev->dev_addr in this tree we need to make all
+the writes to it go through appropriate helpers. We will make
+netdev->dev_addr a const.
+
+Make sure local references to netdev->dev_addr are constant.
+
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/macsec.c              | 2 +-
+ drivers/net/macvlan.c             | 3 ++-
+ drivers/net/vmxnet3/vmxnet3_drv.c | 4 ++--
+ 3 files changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
+index 18b6dba9394e8..16aa3a478e9e8 100644
+--- a/drivers/net/macsec.c
++++ b/drivers/net/macsec.c
+@@ -250,7 +250,7 @@ static bool send_sci(const struct macsec_secy *secy)
+ 		(secy->n_rx_sc > 1 && !tx_sc->end_station && !tx_sc->scb);
+ }
+ 
+-static sci_t make_sci(u8 *addr, __be16 port)
++static sci_t make_sci(const u8 *addr, __be16 port)
+ {
+ 	sci_t sci;
+ 
+diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
+index 6189acb33973c..d2f830ec2969c 100644
+--- a/drivers/net/macvlan.c
++++ b/drivers/net/macvlan.c
+@@ -698,7 +698,8 @@ hash_del:
+ 	return 0;
+ }
+ 
+-static int macvlan_sync_address(struct net_device *dev, unsigned char *addr)
++static int macvlan_sync_address(struct net_device *dev,
++				const unsigned char *addr)
+ {
+ 	struct macvlan_dev *vlan = netdev_priv(dev);
+ 	struct net_device *lowerdev = vlan->lowerdev;
+diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
+index 7a205ddf0060a..3e1b7746cce44 100644
+--- a/drivers/net/vmxnet3/vmxnet3_drv.c
++++ b/drivers/net/vmxnet3/vmxnet3_drv.c
+@@ -46,7 +46,7 @@ MODULE_DEVICE_TABLE(pci, vmxnet3_pciid_table);
+ static int enable_mq = 1;
+ 
+ static void
+-vmxnet3_write_mac_addr(struct vmxnet3_adapter *adapter, u8 *mac);
++vmxnet3_write_mac_addr(struct vmxnet3_adapter *adapter, const u8 *mac);
+ 
+ /*
+  *    Enable/Disable the given intr
+@@ -2806,7 +2806,7 @@ vmxnet3_quiesce_dev(struct vmxnet3_adapter *adapter)
+ 
+ 
+ static void
+-vmxnet3_write_mac_addr(struct vmxnet3_adapter *adapter, u8 *mac)
++vmxnet3_write_mac_addr(struct vmxnet3_adapter *adapter, const u8 *mac)
+ {
+ 	u32 tmp;
+ 
+-- 
+cgit 1.2.3-1.el7
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1785-v5.18-net-macsec-Fix-offload-support-for-NETDEV_UNREGISTER-event.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1785-v5.18-net-macsec-Fix-offload-support-for-NETDEV_UNREGISTER-event.patch
new file mode 100644
index 0000000..b3e5930
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1785-v5.18-net-macsec-Fix-offload-support-for-NETDEV_UNREGISTER-event.patch
@@ -0,0 +1,70 @@
+From 9cef24c8b76c1f6effe499d2f131807c90f7ce9a Mon Sep 17 00:00:00 2001
+From: Lior Nahmanson <liorna@nvidia.com>
+Date: Sun, 30 Jan 2022 13:29:01 +0200
+Subject: net: macsec: Fix offload support for NETDEV_UNREGISTER event
+
+Current macsec netdev notify handler handles NETDEV_UNREGISTER event by
+releasing relevant SW resources only, this causes resources leak in case
+of macsec HW offload, as the underlay driver was not notified to clean
+it's macsec offload resources.
+
+Fix by calling the underlay driver to clean it's relevant resources
+by moving offload handling from macsec_dellink() to macsec_common_dellink()
+when handling NETDEV_UNREGISTER event.
+
+Fixes: 3cf3227a21d1 ("net: macsec: hardware offloading infrastructure")
+Signed-off-by: Lior Nahmanson <liorna@nvidia.com>
+Reviewed-by: Raed Salem <raeds@nvidia.com>
+Signed-off-by: Raed Salem <raeds@nvidia.com>
+Reviewed-by: Antoine Tenart <atenart@kernel.org>
+Link: https://lore.kernel.org/r/1643542141-28956-1-git-send-email-raeds@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/macsec.c | 24 ++++++++++++------------
+ 1 file changed, 12 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
+index 16aa3a478e9e8..33ff33c05aabc 100644
+--- a/drivers/net/macsec.c
++++ b/drivers/net/macsec.c
+@@ -3870,6 +3870,18 @@ static void macsec_common_dellink(struct net_device *dev, struct list_head *head
+ 	struct macsec_dev *macsec = macsec_priv(dev);
+ 	struct net_device *real_dev = macsec->real_dev;
+ 
++	/* If h/w offloading is available, propagate to the device */
++	if (macsec_is_offloaded(macsec)) {
++		const struct macsec_ops *ops;
++		struct macsec_context ctx;
++
++		ops = macsec_get_ops(netdev_priv(dev), &ctx);
++		if (ops) {
++			ctx.secy = &macsec->secy;
++			macsec_offload(ops->mdo_del_secy, &ctx);
++		}
++	}
++
+ 	unregister_netdevice_queue(dev, head);
+ 	list_del_rcu(&macsec->secys);
+ 	macsec_del_dev(macsec);
+@@ -3884,18 +3896,6 @@ static void macsec_dellink(struct net_device *dev, struct list_head *head)
+ 	struct net_device *real_dev = macsec->real_dev;
+ 	struct macsec_rxh_data *rxd = macsec_data_rtnl(real_dev);
+ 
+-	/* If h/w offloading is available, propagate to the device */
+-	if (macsec_is_offloaded(macsec)) {
+-		const struct macsec_ops *ops;
+-		struct macsec_context ctx;
+-
+-		ops = macsec_get_ops(netdev_priv(dev), &ctx);
+-		if (ops) {
+-			ctx.secy = &macsec->secy;
+-			macsec_offload(ops->mdo_del_secy, &ctx);
+-		}
+-	}
+-
+ 	macsec_common_dellink(dev, head);
+ 
+ 	if (list_empty(&rxd->secys)) {
+-- 
+cgit 1.2.3-1.el7
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1786-v5.18-net-macsec-Verify-that-send_sci-is-on-when-setting-Tx-sci-explicitly.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1786-v5.18-net-macsec-Verify-that-send_sci-is-on-when-setting-Tx-sci-explicitly.patch
new file mode 100644
index 0000000..bc78ff3
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1786-v5.18-net-macsec-Verify-that-send_sci-is-on-when-setting-Tx-sci-explicitly.patch
@@ -0,0 +1,43 @@
+From d0cfa548dbde354de986911d3913897b5448faad Mon Sep 17 00:00:00 2001
+From: Lior Nahmanson <liorna@nvidia.com>
+Date: Sun, 30 Jan 2022 13:37:52 +0200
+Subject: net: macsec: Verify that send_sci is on when setting Tx sci
+ explicitly
+
+When setting Tx sci explicit, the Rx side is expected to use this
+sci and not recalculate it from the packet.However, in case of Tx sci
+is explicit and send_sci is off, the receiver is wrongly recalculate
+the sci from the source MAC address which most likely be different
+than the explicit sci.
+
+Fix by preventing such configuration when macsec newlink is established
+and return EINVAL error code on such cases.
+
+Fixes: c09440f7dcb3 ("macsec: introduce IEEE 802.1AE driver")
+Signed-off-by: Lior Nahmanson <liorna@nvidia.com>
+Reviewed-by: Raed Salem <raeds@nvidia.com>
+Signed-off-by: Raed Salem <raeds@nvidia.com>
+Link: https://lore.kernel.org/r/1643542672-29403-1-git-send-email-raeds@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/macsec.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/drivers/net/macsec.c
++++ b/drivers/net/macsec.c
+@@ -4047,6 +4047,15 @@ static int macsec_newlink(struct net *ne
+ 	    !macsec_check_offload(macsec->offload, macsec))
+ 		return -EOPNOTSUPP;
+ 
++	/* send_sci must be set to true when transmit sci explicitly is set */
++	if ((data && data[IFLA_MACSEC_SCI]) &&
++	    (data && data[IFLA_MACSEC_INC_SCI])) {
++		u8 send_sci = !!nla_get_u8(data[IFLA_MACSEC_INC_SCI]);
++
++		if (!send_sci)
++			return -EINVAL;
++	}
++
+ 	if (data && data[IFLA_MACSEC_ICV_LEN])
+ 		icv_len = nla_get_u8(data[IFLA_MACSEC_ICV_LEN]);
+ 	mtu = real_dev->mtu - icv_len - macsec_extra_len(true);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2134-add-pwm-gpio-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2134-add-pwm-gpio-support.patch
new file mode 100644
index 0000000..01426f1
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2134-add-pwm-gpio-support.patch
@@ -0,0 +1,46 @@
+From 102d3751ff3a46edf91c96490a9c7bd2d32e788a Mon Sep 17 00:00:00 2001
+From: Maso Huang <maso.huang@mediatek.com>
+Date: Fri, 29 Dec 2023 16:26:16 +0800
+Subject: [PATCH] add pwm-gpio support
+
+---
+ drivers/pwm/Kconfig  | 10 ++++++++++
+ drivers/pwm/Makefile |  1 +
+ 2 files changed, 11 insertions(+)
+
+diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
+index e3a2518..9b2200c 100644
+--- a/drivers/pwm/Kconfig
++++ b/drivers/pwm/Kconfig
+@@ -171,6 +171,16 @@ config PWM_FSL_FTM
+ 	  To compile this driver as a module, choose M here: the module
+ 	  will be called pwm-fsl-ftm.
+ 
++config PWM_GPIO
++	tristate "GPIO PWM support"
++	depends on OF && GPIOLIB
++	help
++	  Generic PWM framework driver for a software PWM toggling a GPIO pin
++	  from kernel high-resolution timers.
++
++	  To compile this driver as a module, choose M here: the module
++	  will be called pwm-gpio.
++
+ config PWM_HIBVT
+ 	tristate "HiSilicon BVT PWM support"
+ 	depends on ARCH_HISI || COMPILE_TEST
+diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
+index 26326ad..034c1d0 100644
+--- a/drivers/pwm/Makefile
++++ b/drivers/pwm/Makefile
+@@ -15,6 +15,7 @@ obj-$(CONFIG_PWM_CRC)		+= pwm-crc.o
+ obj-$(CONFIG_PWM_CROS_EC)	+= pwm-cros-ec.o
+ obj-$(CONFIG_PWM_EP93XX)	+= pwm-ep93xx.o
+ obj-$(CONFIG_PWM_FSL_FTM)	+= pwm-fsl-ftm.o
++obj-$(CONFIG_PWM_GPIO)		+= pwm-gpio.o
+ obj-$(CONFIG_PWM_HIBVT)		+= pwm-hibvt.o
+ obj-$(CONFIG_PWM_IMG)		+= pwm-img.o
+ obj-$(CONFIG_PWM_IMX1)		+= pwm-imx1.o
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1701-add-default-setting-to-dsa-unused-port.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2731-add-default-setting-to-dsa-unused-port.patch
similarity index 100%
rename from recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1701-add-default-setting-to-dsa-unused-port.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2731-add-default-setting-to-dsa-unused-port.patch
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1702-net-dsa-add-MT7531-Gigabit-Ethernet-PHY-setting.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2732-net-dsa-add-MT7531-Gigabit-Ethernet-PHY-setting.patch
similarity index 100%
rename from recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1702-net-dsa-add-MT7531-Gigabit-Ethernet-PHY-setting.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2732-net-dsa-add-MT7531-Gigabit-Ethernet-PHY-setting.patch
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1705-add-netlink-support-for-dsa.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2733-add-netlink-support-for-dsa.patch
similarity index 100%
rename from recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1705-add-netlink-support-for-dsa.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2733-add-netlink-support-for-dsa.patch
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1706-net-dsa-support-mt7988.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2734-net-dsa-support-mt7988.patch
similarity index 100%
rename from recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1706-net-dsa-support-mt7988.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2734-net-dsa-support-mt7988.patch
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1707-add-mdio-bus-for-gphy-calibration.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2735-add-mdio-bus-for-gphy-calibration.patch
similarity index 100%
rename from recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1707-add-mdio-bus-for-gphy-calibration.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2735-add-mdio-bus-for-gphy-calibration.patch
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2720-net-dsa-phy-coverity-scan.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2736-net-dsa-phy-coverity-scan.patch
similarity index 100%
rename from recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2720-net-dsa-phy-coverity-scan.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2736-net-dsa-phy-coverity-scan.patch
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2721-net-mt753x-phy-coverity-scan.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2737-net-mt753x-phy-coverity-scan.patch
similarity index 100%
rename from recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2721-net-mt753x-phy-coverity-scan.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2737-net-mt753x-phy-coverity-scan.patch
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2738-an8801sb-gphy-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2738-an8801sb-gphy-support.patch
new file mode 100644
index 0000000..1a7fbf1
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2738-an8801sb-gphy-support.patch
@@ -0,0 +1,41 @@
+From 535fdc6dfce7def996a5188819ffc96231c36f98 Mon Sep 17 00:00:00 2001
+From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
+Date: Tue, 2 Jan 2024 18:13:43 +0800
+Subject: [PATCH] [networking][999-2738-an8801sb-gphy-support.patch]
+
+---
+ drivers/net/phy/Kconfig  |   5 +
+ drivers/net/phy/Makefile |   1 +
+ 2 files changed, 6 insertions(+)
+
+diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
+index ccd3f3f..5dbfb17 100644
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -345,6 +345,11 @@ config SFP
+ 	depends on HWMON || HWMON=n
+ 	select MDIO_I2C
+ 
++config AIROHA_AN8801_PHY
++	tristate "Drivers for Airoha AN8801 Gigabit PHYs"
++	---help---
++	  Currently supports the Airoha AN8801 PHY.
++
+ config AIROHA_EN8801SC_PHY
+ 	tristate "Drivers for Airoha EN8801S Gigabit PHYs for MediaTek SoC."
+ 	---help---
+diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
+index 1e8d67b..d39e54b 100644
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -74,6 +74,7 @@ endif
+ ifdef CONFIG_AQUANTIA_PHY_MIB
+ aquantia-objs			+= aquantia_mib.o
+ endif
++obj-$(CONFIG_AIROHA_AN8801_PHY)	+= an8801.o
+ obj-$(CONFIG_AIROHA_EN8801SC_PHY)	+= en8801sc.o
+ air_en8811h-y := air_en8811h_main.o air_en8811h_api.o
+ obj-$(CONFIG_AIROHA_EN8811H_PHY)	+= air_en8811h.o
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2738-net-pptp-bypass-seq-check.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2738-net-pptp-bypass-seq-check.patch
new file mode 100644
index 0000000..625bbda
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2738-net-pptp-bypass-seq-check.patch
@@ -0,0 +1,28 @@
+--- a/drivers/net/ppp/pptp.c
++++ b/drivers/net/ppp/pptp.c
+@@ -308,6 +308,15 @@ static int pptp_rcv_core(struct sock *sk
+ 				(PPP_PROTOCOL(payload) == PPP_LCP) &&
+ 				((payload[4] == PPP_LCP_ECHOREQ) || (payload[4] == PPP_LCP_ECHOREP)))
+ 			goto allow_packet;
++
++		/*
++		 * Updating seq_recv and checking seq of data packets causes
++		 * severe packet drop in multi-core scenario. It is bypassed
++		 * here as a workaround solution.
++		 */
++		if ((payload[0] == PPP_ALLSTATIONS) && (payload[1] == PPP_UI) &&
++				!PPP_PROTOCOL_CTRL(payload))
++			goto allow_packet;
+ 	} else {
+ 		opt->seq_recv = seq;
+ allow_packet:
+--- a/include/uapi/linux/ppp_defs.h
++++ b/include/uapi/linux/ppp_defs.h
+@@ -23,6 +23,7 @@
+ #define PPP_ADDRESS(p)	(((__u8 *)(p))[0])
+ #define PPP_CONTROL(p)	(((__u8 *)(p))[1])
+ #define PPP_PROTOCOL(p)	((((__u8 *)(p))[2] << 8) + ((__u8 *)(p))[3])
++#define PPP_PROTOCOL_CTRL(p)	(PPP_PROTOCOL(p) & 0xF000)
+ 
+ /*
+  * Significant octet values.
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 e927bc3..dcc13b9 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
@@ -35,23 +35,55 @@
     file://1010-pcie-mediatek-fix-clearing-interrupt-status.patch \
     file://1020-spi-nor-w25q512jv.patch \
     file://1021-ubnt-ledbar-driver.patch \
-    file://999-1050-v6.4-backport-jitterrng-2.2.0.patch \
+    file://999-1050-v6.4-backport-jitterrng-2.2.0.patch;apply=no \
     file://999-1051-v5.10-backport-libkcapi.patch \
-    file://999-1600-mdiobus-add-c45.patch \
-    file://999-1701-add-default-setting-to-dsa-unused-port.patch \
-    file://999-1702-net-dsa-add-MT7531-Gigabit-Ethernet-PHY-setting.patch \
-    file://999-1703-mxl-gpy-phy-support.patch \
-    file://999-1704-net-phy-aquantia-add-AQR113C.patch \
-    file://999-1705-add-netlink-support-for-dsa.patch \
-    file://999-1706-net-dsa-support-mt7988.patch \
-    file://999-1707-add-mdio-bus-for-gphy-calibration.patch \
-    file://999-1708-net-phy-add-5GBASER.patch \
-    file://999-1709-net-phy-sfp-add-rollball-support.patch \
-    file://999-1710-net-phy-add-phylink-pcs-support.patch;apply=no \
-    file://999-1711-net-phy-add-phylink-pcs-decode-helper.patch \
-    file://999-1712-net-phy-add-phylink-rate-matching-support.patch;apply=no \
+    file://999-1600-v5.18-mdiobus-add-c45.patch \
+    file://999-1703-v5.18-mxl-gpy-phy-support.patch \
+    file://999-1704-v6.2-net-phy-aquantia-add-AQR113C.patch \
+    file://999-1708-v6.2-net-phy-add-5GBASER.patch \
+    file://999-1709-v6.2-net-phy-sfp-add-rollball-support.patch \
+    file://999-1710-v6.2-net-phy-add-phylink-pcs-support.patch;apply=no \
+    file://999-1711-v6.2-net-phy-add-phylink-pcs-decode-helper.patch \
+    file://999-1712-v6.2-net-phy-add-phylink-rate-matching-support.patch;apply=no \
     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-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 \
+    file://999-1753-03-v5.18-net-macsec-introduce-MACsec-ops.patch \
+    file://999-1754-04-v5.18-net-phy-add-MACsec-ops-in-phy_device.patch \
+    file://999-1755-05-v5.18-net-macsec-hardware-offloading-infrastructure.patch \
+    file://999-1756-06-v5.18-net-macsec-add-nla-support-for-changing-the-offloading-selection.patch \
+    file://999-1757-07-v5.18-net-phy-mscc-macsec-initialization.patch \
+    file://999-1758-08-v5.18-net-phy-mscc-macsec-support.patch \
+    file://999-1759-09-v5.18-net-macsec-PN-wrap-callback.patch \
+    file://999-1760-10-v5.18-net-phy-mscc-PN-rollover-support.patch \
+    file://999-1761-v5.18-net-macsec-invoke-mdo_upd_secy-callback-when-mac-address-changed.patch \
+    file://999-1762-v5.18-net-macsec-Support-XPN-frame-handling-IEEE-802.1AEbw.patch \
+    file://999-1763-v5.18-net-macsec-Netlink-support-of-XPN-cipher-suites-IEEE802.1AEbw.patch \
+    file://999-1764-v5.18-net-macsec-restrict-to-ethernet-devices.patch \
+    file://999-1765-01-v5.18-net-introduce-the-MACSEC-netdev-feature.patch \
+    file://999-1766-02-v5.18-net-add-a-reference-to-MACsec-ops-in-net_device.patch \
+    file://999-1767-03-v5.18-net-macsec-allow-to-reference-a-netdev-from-a-MACsec-context.patch \
+    file://999-1768-04-v5.18-net-macsec-add-support-for-offloading-to-the-MAC.patch \
+    file://999-1769-05-v5.18-net-macsec-init-secy-pointer-in-macsec_context.patch \
+    file://999-1770-06-v5.18-net-macsec-allow-multiple-macsec-devices-with-offload.patch \
+    file://999-1771-07-v5.18-net-macsec-support-multicast-broadcast-when-offloading.patch \
+    file://999-1772-08-v5.18-net-macsec-add-support-for-getting-offloaded-stats.patch \
+    file://999-1773-09-v5.18-net-macsec-report-real_dev-features-when-HW-offloading-is-enabled.patch \
+    file://999-1774-v5.18-net-macsec-add-support-for-specifying-offload-upon-link-creation.patch \
+    file://999-1775-v5.18-net-macsec-fix-NULL-dereference-in-macsec_upd_offload.patch \
+    file://999-1776-v5.18-net-macsec-fix-using-wrong-structure-in-macsec_changelink.patch \
+    file://999-1777-v5.18-net-partially-revert-dynamic-lockdep-key-changes.patch \
+    file://999-1778-v5.18-net-macsec-fix-rtnl-locking-issue.patch \
+    file://999-1779-v5.18-net-change-addr_list_lock-back-to-static-key.patch \
+    file://999-1780-v5.18-net-get-rid-of-lockdep_set_class_and_subclass.patch \
+    file://999-1781-v5.18-netlink-consistently-use-NLA_POLICY_MIN_LEN.patch \
+    file://999-1782-v5.18-net-macsec-Add-missing-documentation-for-gro_cells.patch \
+    file://999-1783-v5.18-net-macsec-fix-the-length-used-to-copy-the-key-for-offloading.patch \
+    file://999-1784-v5.18-net-drivers-get-ready-for-const-netdev-dev_addr.patch \
+    file://999-1785-v5.18-net-macsec-Fix-offload-support-for-NETDEV_UNREGISTER-event.patch \
+    file://999-1786-v5.18-net-macsec-Verify-that-send_sci-is-on-when-setting-Tx-sci-explicitly.patch \
     file://999-1800-v6.7-MT7986-ASoC-platform-driver.patch \
     file://999-1801-v6.1-iio-adc-add-rtq6056-support.patch \
     file://999-1802-v6.4-backport-pinctrl-pinconf-setting-combo.patch \
@@ -81,6 +113,7 @@
     file://999-2131-pwm-add-mt7981-support.patch \
     file://999-2132-add-pwm-feature-in-mt7988-project.patch \
     file://999-2133-pwm-mediatek-add-longer-period-support.patch \
+    file://999-2134-add-pwm-gpio-support.patch \
     file://999-2140-mtk-thermal-add-lvts-support.patch \
     file://999-2150-sound-add-some-helpers-to-control-mtk_memif.patch \
     file://999-2151-sound-refine-hw-params-and-hw-prepare.patch \
@@ -149,8 +182,6 @@
     file://999-2716-en8801sc-gphy-support.patch \
     file://999-2717-add-mediatek-2p5ge-phy-support.patch \
     file://999-2719-net-phy-aquantia-add-firmware-download.patch \
-    file://999-2720-net-dsa-phy-coverity-scan.patch \
-    file://999-2721-net-mt753x-phy-coverity-scan.patch;apply=no \
     file://999-2722-dt-bindings-phy-Add-PHY_TYPE_DP-definition.patch \
     file://999-2723-dt-bindings-phy-Add-PHY_TYPE_XPCS-definition.patch \
     file://999-2724-dt-bindings-phy-Add-DT-bindings-for-Xilinx-ZynqMP-PS.patch \
@@ -159,6 +190,15 @@
     file://999-2728-net-phy-aquantia-add-mib-read.patch \
     file://999-2729-net-phy-remove-reporting-line-rate-to-mac.patch;apply=no \
     file://999-2730-net-phy-sfp-change-shared-mod-def0.patch \
+    file://999-2731-add-default-setting-to-dsa-unused-port.patch \
+    file://999-2732-net-dsa-add-MT7531-Gigabit-Ethernet-PHY-setting.patch \
+    file://999-2733-add-netlink-support-for-dsa.patch \
+    file://999-2734-net-dsa-support-mt7988.patch \
+    file://999-2735-add-mdio-bus-for-gphy-calibration.patch \
+    file://999-2736-net-dsa-phy-coverity-scan.patch \
+    file://999-2737-net-mt753x-phy-coverity-scan.patch;apply=no \
+    file://999-2738-an8801sb-gphy-support.patch \
+    file://999-2738-net-pptp-bypass-seq-check.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/mediatek/wed3/999-3019-mtk-wed-add-wed3-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3019-mtk-wed-add-wed3-support.patch
index 7b27db3..b90693d 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3019-mtk-wed-add-wed3-support.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3019-mtk-wed-add-wed3-support.patch
@@ -1,7 +1,7 @@
-From 7d891b389a58e3f8c99782339df7c0b023440558 Mon Sep 17 00:00:00 2001
+From 542064ad977706558be071e0f7d706f5aa37f390 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 1/5] mtk:wed:add wed3 support
 
 ---
  arch/arm64/boot/dts/mediatek/mt7988.dtsi      |  152 ++-
@@ -24,10 +24,10 @@
  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 bcfa581..c866d85 100644
+index 7e96640..3368240 100644
 --- a/arch/arm64/boot/dts/mediatek/mt7988.dtsi
 +++ b/arch/arm64/boot/dts/mediatek/mt7988.dtsi
-@@ -205,44 +205,49 @@
+@@ -193,44 +193,49 @@
  		status = "disabled";
  	};
  
@@ -112,7 +112,7 @@
  	};
  
  	wdma: wdma@15104800 {
-@@ -252,15 +257,25 @@
+@@ -240,15 +245,25 @@
  		      <0 0x15105000 0 0x400>;
  	};
  
@@ -146,7 +146,7 @@
  	};
  
  	wocpu0_ilm: wocpu0_ilm@151E0000 {
-@@ -268,31 +283,53 @@
+@@ -256,31 +271,53 @@
  		reg = <0 0x151E0000 0 0x8000>;
  	};
  
@@ -214,8 +214,8 @@
  	};
  
  	reserved-memory {
-@@ -906,6 +943,7 @@
- 					 <&topckgen CK_TOP_CB_SGM_325M>;
+@@ -901,6 +938,7 @@
+ 					 <&topckgen CK_TOP_CB_NET2_D2>;
  		mediatek,ethsys = <&ethsys>;
  		mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>;
 +		mediatek,wed = <&wed0>, <&wed1>, <&wed2>;
@@ -223,7 +223,7 @@
  		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 70a7554..bed27b4 100644
+index 578a489..596f0ca 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
 @@ -369,9 +369,23 @@
@@ -253,10 +253,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 e8e3a69..5dd481b 100644
+index e743718..f430118 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
-@@ -379,9 +379,23 @@
+@@ -381,9 +381,23 @@
  	status = "okay";
  };
  
@@ -283,10 +283,10 @@
 +};
 \ No newline at end of file
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 86ab1f1..ec5e5ec 100644
+index c75ce25..ec78adf 100644
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -5218,7 +5218,8 @@ static int mtk_probe(struct platform_device *pdev)
+@@ -5216,7 +5216,8 @@ static int mtk_probe(struct platform_device *pdev)
  							  "mediatek,wed", i);
  		static const u32 wdma_regs[] = {
  			MTK_WDMA0_BASE,
@@ -297,7 +297,7 @@
  		void __iomem *wdma;
  		u32 wdma_phy;
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-index 3ab8ab5..f10fed1 100644
+index 1074f46..a788d43 100644
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
 @@ -623,9 +623,12 @@
@@ -440,7 +440,7 @@
  }
  
 diff --git a/drivers/net/ethernet/mediatek/mtk_wed.c b/drivers/net/ethernet/mediatek/mtk_wed.c
-index 3e760f7..7b2e199 100644
+index 48c35ae..561fc6c 100644
 --- a/drivers/net/ethernet/mediatek/mtk_wed.c
 +++ b/drivers/net/ethernet/mediatek/mtk_wed.c
 @@ -28,7 +28,7 @@ struct wo_cmd_ring {
@@ -3509,10 +3509,10 @@
 +#define MTK_WED_PCIE_BASE2			0x11290000
  #endif
 diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
-index 0967dc2..3211f34 100644
+index b2abebe..204051d 100644
 --- a/include/linux/netdevice.h
 +++ b/include/linux/netdevice.h
-@@ -875,6 +875,13 @@ struct net_device_path {
+@@ -880,6 +880,13 @@ struct net_device_path {
  			u8 queue;
  			u16 wcid;
  			u8 bss;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3020-mtk-wed-add-wed3-ser-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3020-mtk-wed-add-wed3-ser-support.patch
index ea0daa2..328a4bc 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3020-mtk-wed-add-wed3-ser-support.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3020-mtk-wed-add-wed3-ser-support.patch
@@ -1,19 +1,19 @@
-From a77480d9f1e1f2de7d27365a9668daf98184b0e2 Mon Sep 17 00:00:00 2001
+From f0b9f017b170690be346d3e08371fdadca0d59d3 Mon Sep 17 00:00:00 2001
 From: mtk27745 <rex.lu@mediatek.com>
 Date: Mon, 18 Sep 2023 13:22:44 +0800
-Subject: [PATCH 21/22] mtk wed add wed3 ser support
+Subject: [PATCH] mtk wed add wed3 ser support
 
 ---
- drivers/net/ethernet/mediatek/mtk_wed.c      | 236 +++++++++++++++++--
+ drivers/net/ethernet/mediatek/mtk_wed.c      | 260 +++++++++++++++++--
  drivers/net/ethernet/mediatek/mtk_wed_regs.h |  73 +++++-
  include/linux/soc/mediatek/mtk_wed.h         |   6 +-
- 3 files changed, 291 insertions(+), 24 deletions(-)
+ 3 files changed, 310 insertions(+), 29 deletions(-)
 
 diff --git a/drivers/net/ethernet/mediatek/mtk_wed.c b/drivers/net/ethernet/mediatek/mtk_wed.c
-index 9047cb0..0d101d5 100644
+index 561fc6c..f20a4ae 100644
 --- a/drivers/net/ethernet/mediatek/mtk_wed.c
 +++ b/drivers/net/ethernet/mediatek/mtk_wed.c
-@@ -99,11 +99,65 @@ mtk_wdma_rx_reset(struct mtk_wed_device *dev)
+@@ -99,16 +99,70 @@ mtk_wdma_rx_reset(struct mtk_wed_device *dev)
  	u32 status;
  	u32 mask = MTK_WDMA_GLO_CFG_RX_DMA_BUSY;
  	int busy, i;
@@ -80,7 +80,14 @@
  	wdma_w32(dev, MTK_WDMA_RESET_IDX, MTK_WDMA_RESET_IDX_RX);
  	wdma_w32(dev, MTK_WDMA_RESET_IDX, 0);
  
-@@ -121,13 +175,62 @@ mtk_wdma_tx_reset(struct mtk_wed_device *dev)
+-	for (i = 0; i < ARRAY_SIZE(dev->rx_wdma); i++)
+-		if (!dev->rx_wdma[i].desc) {
++	for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++)
++		if (!dev->tx_wdma[i].desc) {
+ 			wdma_w32(dev, MTK_WDMA_RING_RX(i) +
+ 				 MTK_WED_RING_OFS_CPU_IDX, 0);
+ 	}
+@@ -121,16 +175,65 @@ mtk_wdma_tx_reset(struct mtk_wed_device *dev)
  {
  	u32 status;
  	u32 mask = MTK_WDMA_GLO_CFG_TX_DMA_BUSY;
@@ -143,8 +150,12 @@
 +	}
  	wdma_w32(dev, MTK_WDMA_RESET_IDX, MTK_WDMA_RESET_IDX_TX);
  	wdma_w32(dev, MTK_WDMA_RESET_IDX, 0);
- 	for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++)
-@@ -903,7 +1006,7 @@ mtk_wed_dma_enable(struct mtk_wed_device *dev)
+-	for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++)
++	for (i = 0; i < ARRAY_SIZE(dev->rx_wdma); i++)
+ 		wdma_w32(dev, MTK_WDMA_RING_TX(i) +
+ 			 MTK_WED_RING_OFS_CPU_IDX, 0);
+ }
+@@ -913,7 +1016,7 @@ mtk_wed_dma_enable(struct mtk_wed_device *dev)
  				MTK_WED_WPDMA_GLO_CFG_RX_DRV_UNS_VER_FORCE_4);
  
  			wdma_set(dev, MTK_WDMA_PREF_RX_CFG, MTK_WDMA_PREF_RX_CFG_PREF_EN);
@@ -153,7 +164,7 @@
  			if (mtk_wed_get_rx_capa(dev)) {
  				wed_set(dev, MTK_WED_WPDMA_RX_D_PREF_CFG,
  					MTK_WED_WPDMA_RX_D_PREF_EN |
-@@ -1466,13 +1569,30 @@ mtk_wed_rx_reset(struct mtk_wed_device *dev)
+@@ -1476,13 +1579,30 @@ mtk_wed_rx_reset(struct mtk_wed_device *dev)
  	mtk_wed_mcu_send_msg(wo, MODULE_ID_WO, MTK_WED_WO_CMD_CHANGE_STATE,
  			     &state, sizeof(state), true);
  
@@ -184,7 +195,7 @@
  		wed_w32(dev, MTK_WED_WPDMA_RX_D_RST_IDX,
  			MTK_WED_WPDMA_RX_D_RST_CRX_IDX |
  			MTK_WED_WPDMA_RX_D_RST_DRV_IDX);
-@@ -1500,6 +1620,24 @@ mtk_wed_rx_reset(struct mtk_wed_device *dev)
+@@ -1510,6 +1630,24 @@ mtk_wed_rx_reset(struct mtk_wed_device *dev)
  		wed_w32(dev, MTK_WED_RROQM_RST_IDX, 0);
  	}
  
@@ -209,7 +220,7 @@
  	/* reset route qm */
  	wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_RX_ROUTE_QM_EN);
  	busy = mtk_wed_poll_busy(dev, MTK_WED_CTRL,
-@@ -1507,8 +1645,13 @@ mtk_wed_rx_reset(struct mtk_wed_device *dev)
+@@ -1517,8 +1655,13 @@ mtk_wed_rx_reset(struct mtk_wed_device *dev)
  	if (busy) {
  		mtk_wed_reset(dev, MTK_WED_RESET_RX_ROUTE_QM);
  	} else {
@@ -225,7 +236,7 @@
  	}
  
  	/* reset tx wdma */
-@@ -1516,8 +1659,13 @@ mtk_wed_rx_reset(struct mtk_wed_device *dev)
+@@ -1526,8 +1669,13 @@ mtk_wed_rx_reset(struct mtk_wed_device *dev)
  
  	/* reset tx wdma drv */
  	wed_clr(dev, MTK_WED_WDMA_GLO_CFG, MTK_WED_WDMA_GLO_CFG_TX_DRV_EN);
@@ -241,7 +252,7 @@
  	mtk_wed_reset(dev, MTK_WED_RESET_WDMA_TX_DRV);
  
  	/* reset wed rx dma */
-@@ -1535,9 +1683,17 @@ mtk_wed_rx_reset(struct mtk_wed_device *dev)
+@@ -1545,9 +1693,17 @@ mtk_wed_rx_reset(struct mtk_wed_device *dev)
  	/* reset rx bm */
  	wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_RX_BM_EN);
  	mtk_wed_poll_busy(dev, MTK_WED_CTRL,
@@ -260,7 +271,7 @@
  	/* wo change to enable state */
  	state = WO_STATE_ENABLE;
  	mtk_wed_mcu_send_msg(wo, MODULE_ID_WO, MTK_WED_WO_CMD_CHANGE_STATE,
-@@ -1554,6 +1710,9 @@ mtk_wed_rx_reset(struct mtk_wed_device *dev)
+@@ -1564,6 +1720,9 @@ mtk_wed_rx_reset(struct mtk_wed_device *dev)
  	}
  
  	mtk_wed_free_rx_buffer(dev);
@@ -270,7 +281,7 @@
  }
  
  
-@@ -1587,18 +1746,40 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
+@@ -1597,18 +1756,54 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
  
  	/* 2. Reset WDMA Rx DMA/Driver_Engine */
  	busy = !!mtk_wdma_rx_reset(dev);
@@ -303,6 +314,20 @@
 +					  MTK_WED_WDMA_RX_PREF_BUSY);
 +			wed_clr(dev, MTK_WED_WDMA_RX_PREF_CFG, MTK_WED_WDMA_RX_PREF_DDONE2_EN);
 +
++			/* reset prefetch index */
++			wed_set(dev, MTK_WED_WDMA_RX_PREF_CFG,
++				MTK_WED_WDMA_RX_PREF_RX0_SIDX_CLR |
++				MTK_WED_WDMA_RX_PREF_RX1_SIDX_CLR);
++
++			wed_clr(dev, MTK_WED_WDMA_RX_PREF_CFG,
++				MTK_WED_WDMA_RX_PREF_RX0_SIDX_CLR |
++				MTK_WED_WDMA_RX_PREF_RX1_SIDX_CLR);
++
++			/* reset prefetch FIFO */
++			wed_w32(dev, MTK_WED_WDMA_RX_PREF_FIFO_CFG,
++				MTK_WED_WDMA_RX_PREF_FIFO_RX0_CLR |
++				MTK_WED_WDMA_RX_PREF_FIFO_RX1_CLR);
++			wed_w32(dev, MTK_WED_WDMA_RX_PREF_FIFO_CFG, 0);
 +			/*2. Reset dma index*/
 +			wed_w32(dev, MTK_WED_WDMA_RESET_IDX,
 +				MTK_WED_WDMA_RESET_IDX_RX_ALL);
@@ -314,7 +339,7 @@
  		wed_w32(dev, MTK_WED_WDMA_RESET_IDX, 0);
  
  		wed_set(dev, MTK_WED_WDMA_GLO_CFG,
-@@ -1613,9 +1794,15 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
+@@ -1623,9 +1818,15 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
  		MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
  
  	for (i = 0; i < 100; i++) {
@@ -333,7 +358,7 @@
  	}
  	mtk_wed_reset(dev, MTK_WED_RESET_TX_FREE_AGENT);
  
-@@ -1624,18 +1811,20 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
+@@ -1634,18 +1835,20 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
  
  	/* 4. Reset WED WPDMA Tx Driver Engine */
  	busy = mtk_wed_poll_busy(dev, MTK_WED_WPDMA_GLO_CFG,
@@ -356,31 +381,37 @@
  	} else {
  		wed_w32(dev, MTK_WED_WPDMA_RESET_IDX,
  			MTK_WED_WPDMA_RESET_IDX_TX |
-@@ -1648,7 +1837,13 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
+@@ -1658,11 +1861,17 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
  		}
  	}
  
 -	if (dev->ver > MTK_WED_V1) {
+-		dev->init_done = false;
+-		mtk_wed_rx_reset(dev);
++	dev->init_done = false;
++
 +	if (dev->hw->version == 3) {
 +		/*reset wed pao*/
 +		wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_TX_PAO_EN);
 +		mtk_wed_reset(dev, MTK_WED_RESET_TX_PAO);
-+	}
-+
-+	if (mtk_wed_get_rx_capa(dev)) {
- 		dev->init_done = false;
- 		mtk_wed_rx_reset(dev);
  	}
-@@ -1863,7 +2058,7 @@ mtk_wed_ppe_check(struct mtk_wed_device *dev, struct sk_buff *skb,
+ 
++	if (mtk_wed_get_rx_capa(dev))
++		mtk_wed_rx_reset(dev);
++
  }
  
+ static int
+@@ -1875,7 +2084,7 @@ mtk_wed_ppe_check(struct mtk_wed_device *dev, struct sk_buff *skb,
+ }
+ 
  static void
 -mtk_wed_start_hwrro(struct mtk_wed_device *dev, u32 irq_mask)
 +mtk_wed_start_hwrro(struct mtk_wed_device *dev, u32 irq_mask, bool reset)
  {
  	int idx, ret;
  
-@@ -1873,6 +2068,11 @@ mtk_wed_start_hwrro(struct mtk_wed_device *dev, u32 irq_mask)
+@@ -1885,6 +2094,11 @@ mtk_wed_start_hwrro(struct mtk_wed_device *dev, u32 irq_mask)
  	if (!mtk_wed_get_rx_capa(dev) || !dev->wlan.hwrro)
  		return;
  
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3022-mediatek-ethernet-add-multiple-ppe-allocation.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3022-mediatek-ethernet-add-multiple-ppe-allocation.patch
index 9ac533a..cd6c8ca 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3022-mediatek-ethernet-add-multiple-ppe-allocation.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3022-mediatek-ethernet-add-multiple-ppe-allocation.patch
@@ -1,20 +1,20 @@
-From 9c849a6e5a246489c5c91565d4c89a32958cad29 Mon Sep 17 00:00:00 2001
+From f80b9b330efd9d675c7c548c5af459792037ca99 Mon Sep 17 00:00:00 2001
 From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
-Date: Thu, 16 Nov 2023 11:21:53 +0800
-Subject: [PATCH] 999-3022-mediatek-ethernet-add-multiple-ppe-allocation
+Date: Tue, 26 Dec 2023 16:46:16 +0800
+Subject: [PATCH] 999-3022-mediatek-ethernet-add-multiple-ppe-allocatiion.patch
 
 ---
- arch/arm64/boot/dts/mediatek/mt7988.dtsi        |  1 +
- drivers/net/ethernet/mediatek/mtk_eth_soc.c     | 10 +++++++++-
- drivers/net/ethernet/mediatek/mtk_eth_soc.h     |  2 ++
- drivers/net/ethernet/mediatek/mtk_ppe_offload.c | 10 ++++++++++
- 4 files changed, 22 insertions(+), 1 deletion(-)
+ arch/arm64/boot/dts/mediatek/mt7988.dtsi      |  1 +
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c   | 19 +++++++++++++++++--
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h   |  3 +++
+ .../net/ethernet/mediatek/mtk_ppe_offload.c   | 10 ++++++++++
+ 4 files changed, 31 insertions(+), 2 deletions(-)
 
 diff --git a/arch/arm64/boot/dts/mediatek/mt7988.dtsi b/arch/arm64/boot/dts/mediatek/mt7988.dtsi
-index 8d83f6b..d378a65 100644
+index 44a2f1b..cf50542 100644
 --- a/arch/arm64/boot/dts/mediatek/mt7988.dtsi
 +++ b/arch/arm64/boot/dts/mediatek/mt7988.dtsi
-@@ -950,6 +950,7 @@
+@@ -949,6 +949,7 @@
  		mediatek,infracfg = <&topmisc>;
  		mediatek,toprgu = <&watchdog>;
  		mediatek,hwver = <&hwver>;
@@ -23,26 +23,49 @@
  		#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 de2eac4..55d05fd 100644
+index 4cdfead..9009960 100644
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -3669,7 +3669,14 @@ static int mtk_open(struct net_device *dev)
+@@ -2170,6 +2170,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;
++	int i;
+ 
+ 	if (unlikely(!ring))
+ 		goto rx_done;
+@@ -2277,7 +2278,8 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
+ #if defined(CONFIG_MEDIATEK_NETSYS_RX_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
+ 		reason = FIELD_GET(MTK_RXD5_PPE_CPU_REASON_V2, trxd.rxd5);
+ 		if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED) {
+-			mtk_ppe_check_skb(eth->ppe[0], skb,
++			i = eth->mac[mac]->ppe_idx;
++			mtk_ppe_check_skb(eth->ppe[i], skb,
+ 					  trxd.rxd5 & MTK_RXD5_FOE_ENTRY_V2);
+ 		}
+ #else
+@@ -3781,7 +3783,19 @@ static int mtk_open(struct net_device *dev)
  			     SGMSYS_QPHY_PWR_STATE_CTRL, 0);
  
  	if (eth->soc->offload_version) {
 -			gdm_config = MTK_GDMA_TO_PPE0;
 +#if defined(CONFIG_MEDIATEK_NETSYS_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
-+			if (eth->ppe_num >= 3 && mac->id == 2)
++			if (eth->ppe_num >= 3 && mac->id == 2) {
++				mac->ppe_idx = 2;
 +				gdm_config = MTK_GDMA_TO_PPE2;
-+			else if (eth->ppe_num >=2 && mac->id == 1)
++			} else if (eth->ppe_num >= 2 && mac->id == 1) {
++				mac->ppe_idx = 1;
 +				gdm_config = MTK_GDMA_TO_PPE1;
-+			else
++			} else
 +#endif
++			{
++				mac->ppe_idx = 0;
 +				gdm_config = MTK_GDMA_TO_PPE0;
++			}
  
  			for (i = 0; i < eth->ppe_num; i++)
  				mtk_ppe_start(eth->ppe[i]);
-@@ -4635,6 +4642,7 @@ static const struct net_device_ops mtk_netdev_ops = {
+@@ -4748,6 +4762,7 @@ static const struct net_device_ops mtk_netdev_ops = {
  	.ndo_poll_controller	= mtk_poll_controller,
  #endif
  	.ndo_setup_tc		= mtk_eth_setup_tc,
@@ -51,10 +74,18 @@
  
  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 50024a2..e0dfc9d 100644
+index 12ffb3c..1bf335c 100644
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -2041,6 +2041,8 @@ int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type,
+@@ -1945,6 +1945,7 @@ struct mtk_mac {
+ 	phy_interface_t			interface;
+ 	unsigned int			mode;
+ 	unsigned int			type;
++	unsigned int			ppe_idx;
+ 	int				speed;
+ 	struct device_node		*of_node;
+ 	struct phylink			*phylink;
+@@ -2045,6 +2046,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);
@@ -64,10 +95,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 eab9e9d..e5ff575 100644
+index 339359e..8f721ba 100644
 --- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
 +++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
-@@ -694,6 +694,16 @@ int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type,
+@@ -693,6 +693,16 @@ int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type,
  	}
  }
  
@@ -76,7 +107,7 @@
 +{
 +	struct mtk_mac *mac = netdev_priv(ctx->dev);
 +
-+	path->mtk_wdma.wdma_idx = mac->id;
++	path->mtk_wdma.wdma_idx = mac->ppe_idx;
 +
 +	return 0;
 +}
diff --git a/recipes-kernel/linux/linux-mediatek_5.4.bb b/recipes-kernel/linux/linux-mediatek_5.4.bb
index dde2f00..18f0553 100644
--- a/recipes-kernel/linux/linux-mediatek_5.4.bb
+++ b/recipes-kernel/linux/linux-mediatek_5.4.bb
@@ -96,11 +96,12 @@
             patch -p1 < ${WORKDIR}/001-rdkb-eth-mtk-change-ifname-for.patch
             patch -p1 < ${WORKDIR}/003-rdkb-mtd-kernel-ubi-relayout.patch
             patch -p1 < ${WORKDIR}/0600-net-phylink-propagate-resolved-link-config-via-mac_l.patch
+            patch -p1 < ${WORKDIR}/999-1050-v6.4-backport-jitterrng-2.2.0.patch
             patch -p1 < ${WORKDIR}/999-2713-mt7531-gsw-internal_phy_calibration.patch
             patch -p1 < ${WORKDIR}/999-2714-mt7531-gsw-port5_external_phy_init.patch
-            patch -p1 < ${WORKDIR}/999-2721-net-mt753x-phy-coverity-scan.patch
-            patch -p1 < ${WORKDIR}/999-1710-net-phy-add-phylink-pcs-support.patch
-            patch -p1 < ${WORKDIR}/999-1712-net-phy-add-phylink-rate-matching-support.patch
+            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-2702-v5.9-net-phy-add-support-for-a-common-probe-between-shared-PHYs.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