[Refactor and sync kernel from Openwrt]

[Description]
Refactor and sync kernel from OpenWRT

[Release-log]
N/A

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 9f86879..ba27b95 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
@@ -250,6 +250,14 @@
 		status = "disabled";
 	};
 
+	fan: pwm-fan {
+		compatible = "pwm-fan";
+		/* cooling level (0, 1, 2) : (0% duty, 50% duty, 100% duty) */
+		cooling-levels = <0 128 255>;
+		#cooling-cells = <2>;
+		status = "disabled";
+	};
+
 	uart0: serial@11002000 {
 		compatible = "mediatek,mt7986-uart",
 			     "mediatek,mt6577-uart";
@@ -304,6 +312,45 @@
 			polling-delay-passive = <1000>;
 			polling-delay = <1000>;
 			thermal-sensors = <&thermal 0>;
+			trips {
+				cpu_trip_hot: hot {
+					temperature = <60000>;
+					hysteresis = <2000>;
+					type = "hot";
+				};
+
+				cpu_trip_active: active {
+					temperature = <40000>;
+					hysteresis = <2000>;
+					type = "active";
+				};
+
+				cpu_trip_passive: passive {
+					temperature = <20000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+			};
+			cooling-maps {
+				cpu-hot {
+					/* hot: set fan to cooling level 2 */
+					cooling-device = <&fan 2 2>;
+					trip = <&cpu_trip_hot>;
+				};
+
+				cpu-active {
+					/* active: set fan to cooling level 1 */
+					cooling-device = <&fan 1 1>;
+					trip = <&cpu_trip_active>;
+				};
+
+				cpu-passive {
+					/* passive: set fan to cooling level 0 */
+					cooling-device = <&fan 0 0>;
+					trip = <&cpu_trip_passive>;
+				};
+			};
+
 		};
 	};
 
@@ -354,6 +401,10 @@
 			#address-cells = <0>;
 			#interrupt-cells = <1>;
 		};
+
+		slot0: pcie@0,0 {
+			reg = <0x0000 0 0 0 0>;
+		};
 	};
 
 	crypto: crypto@10320000 {
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 9f86879..ba27b95 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
@@ -250,6 +250,14 @@
 		status = "disabled";
 	};
 
+	fan: pwm-fan {
+		compatible = "pwm-fan";
+		/* cooling level (0, 1, 2) : (0% duty, 50% duty, 100% duty) */
+		cooling-levels = <0 128 255>;
+		#cooling-cells = <2>;
+		status = "disabled";
+	};
+
 	uart0: serial@11002000 {
 		compatible = "mediatek,mt7986-uart",
 			     "mediatek,mt6577-uart";
@@ -304,6 +312,45 @@
 			polling-delay-passive = <1000>;
 			polling-delay = <1000>;
 			thermal-sensors = <&thermal 0>;
+			trips {
+				cpu_trip_hot: hot {
+					temperature = <60000>;
+					hysteresis = <2000>;
+					type = "hot";
+				};
+
+				cpu_trip_active: active {
+					temperature = <40000>;
+					hysteresis = <2000>;
+					type = "active";
+				};
+
+				cpu_trip_passive: passive {
+					temperature = <20000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+			};
+			cooling-maps {
+				cpu-hot {
+					/* hot: set fan to cooling level 2 */
+					cooling-device = <&fan 2 2>;
+					trip = <&cpu_trip_hot>;
+				};
+
+				cpu-active {
+					/* active: set fan to cooling level 1 */
+					cooling-device = <&fan 1 1>;
+					trip = <&cpu_trip_active>;
+				};
+
+				cpu-passive {
+					/* passive: set fan to cooling level 0 */
+					cooling-device = <&fan 0 0>;
+					trip = <&cpu_trip_passive>;
+				};
+			};
+
 		};
 	};
 
@@ -354,6 +401,10 @@
 			#address-cells = <0>;
 			#interrupt-cells = <1>;
 		};
+
+		slot0: pcie@0,0 {
+			reg = <0x0000 0 0 0 0>;
+		};
 	};
 
 	crypto: crypto@10320000 {
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 ab411d9..7ba9a01 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
@@ -400,12 +400,12 @@
 
 static void mii_mgr_read_cl45(struct mtk_eth *eth, u16 port, u16 devad, u16 reg, u16 *data)
 {
-	mtk_cl45_ind_read(eth, port, devad, reg, data);
+	*data = _mtk_mdio_read(eth, port, mdiobus_c45_addr(devad, reg));
 }
 
 static void mii_mgr_write_cl45(struct mtk_eth *eth, u16 port, u16 devad, u16 reg, u16 data)
 {
-	mtk_cl45_ind_write(eth, port, devad, reg, data);
+	_mtk_mdio_write(eth, port, mdiobus_c45_addr(devad, reg), data);
 }
 
 int mtk_do_priv_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.h
index 43f4838..2113c1f 100755
--- 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
@@ -267,12 +267,10 @@
 }
 #endif
 
-extern u32 _mtk_mdio_read(struct mtk_eth *eth, u16 phy_addr, u16 phy_reg);
-extern u32 _mtk_mdio_write(struct mtk_eth *eth, u16 phy_addr,
-		    u16 phy_register, u16 write_data);
+extern u32 _mtk_mdio_read(struct mtk_eth *eth, int phy_addr, int phy_reg);
+extern u32 _mtk_mdio_write(struct mtk_eth *eth, int phy_addr,
+		    int phy_reg, u16 write_data);
 
-extern u32 mtk_cl45_ind_read(struct mtk_eth *eth, u16 port, u16 devad, u16 reg, u16 *data);
-extern u32 mtk_cl45_ind_write(struct mtk_eth *eth, u16 port, u16 devad, u16 reg, u16 data);
 extern atomic_t force;
 
 int debug_proc_init(struct mtk_eth *eth);
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 40d840e..3cd1e3b 100755
--- 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
@@ -103,18 +103,33 @@
 	return -1;
 }
 
-u32 _mtk_mdio_write(struct mtk_eth *eth, u16 phy_addr,
-			   u16 phy_register, u16 write_data)
+u32 _mtk_mdio_write(struct mtk_eth *eth, int phy_addr,
+			   int phy_reg, u16 write_data)
 {
 	if (mtk_mdio_busy_wait(eth))
 		return -1;
 
 	write_data &= 0xffff;
 
-	mtk_w32(eth, PHY_IAC_ACCESS | PHY_IAC_START | PHY_IAC_WRITE |
-		((phy_register & 0x1f) << PHY_IAC_REG_SHIFT) |
-		((phy_addr & 0x1f) << PHY_IAC_ADDR_SHIFT) | write_data,
-		MTK_PHY_IAC);
+	if (phy_reg & MII_ADDR_C45) {
+		mtk_w32(eth, PHY_IAC_ACCESS | PHY_IAC_START_C45 | PHY_IAC_ADDR_C45 |
+			((mdiobus_c45_devad(phy_reg) & 0x1f) << PHY_IAC_REG_SHIFT) |
+			((phy_addr & 0x1f) << PHY_IAC_ADDR_SHIFT) | mdiobus_c45_regad(phy_reg),
+			MTK_PHY_IAC);
+
+		if (mtk_mdio_busy_wait(eth))
+			return -1;
+
+		mtk_w32(eth, PHY_IAC_ACCESS | PHY_IAC_START_C45 | PHY_IAC_WRITE |
+			((mdiobus_c45_devad(phy_reg) & 0x1f) << PHY_IAC_REG_SHIFT) |
+			((phy_addr & 0x1f) << PHY_IAC_ADDR_SHIFT) | write_data,
+			MTK_PHY_IAC);
+	} else {
+		mtk_w32(eth, PHY_IAC_ACCESS | PHY_IAC_START | PHY_IAC_WRITE |
+			((phy_reg & 0x1f) << PHY_IAC_REG_SHIFT) |
+			((phy_addr & 0x1f) << PHY_IAC_ADDR_SHIFT) | write_data,
+			MTK_PHY_IAC);
+	}
 
 	if (mtk_mdio_busy_wait(eth))
 		return -1;
@@ -122,17 +137,32 @@
 	return 0;
 }
 
-u32 _mtk_mdio_read(struct mtk_eth *eth, u16 phy_addr, u16 phy_reg)
+u32 _mtk_mdio_read(struct mtk_eth *eth, int phy_addr, int phy_reg)
 {
 	u32 d;
 
 	if (mtk_mdio_busy_wait(eth))
 		return 0xffff;
 
+	if (phy_reg & MII_ADDR_C45) {
+		mtk_w32(eth, PHY_IAC_ACCESS | PHY_IAC_START_C45 | PHY_IAC_ADDR_C45 |
+			((mdiobus_c45_devad(phy_reg) & 0x1f) << PHY_IAC_REG_SHIFT) |
+			((phy_addr & 0x1f) << PHY_IAC_ADDR_SHIFT) | mdiobus_c45_regad(phy_reg),
+			MTK_PHY_IAC);
+
-	mtk_w32(eth, PHY_IAC_ACCESS | PHY_IAC_START | PHY_IAC_READ |
-		((phy_reg & 0x1f) << PHY_IAC_REG_SHIFT) |
-		((phy_addr & 0x1f) << PHY_IAC_ADDR_SHIFT),
-		MTK_PHY_IAC);
+		if (mtk_mdio_busy_wait(eth))
+			return 0xffff;
+
+		mtk_w32(eth, PHY_IAC_ACCESS | PHY_IAC_START_C45 | PHY_IAC_READ_C45 |
+			((mdiobus_c45_devad(phy_reg) & 0x1f) << PHY_IAC_REG_SHIFT) |
+			((phy_addr & 0x1f) << PHY_IAC_ADDR_SHIFT),
+			MTK_PHY_IAC);
+	} else {
+		mtk_w32(eth, PHY_IAC_ACCESS | PHY_IAC_START | PHY_IAC_READ |
+			((phy_reg & 0x1f) << PHY_IAC_REG_SHIFT) |
+			((phy_addr & 0x1f) << PHY_IAC_ADDR_SHIFT),
+			MTK_PHY_IAC);
+	}
 
 	if (mtk_mdio_busy_wait(eth))
 		return 0xffff;
@@ -157,34 +187,6 @@
 	return _mtk_mdio_read(eth, phy_addr, phy_reg);
 }
 
-u32 mtk_cl45_ind_read(struct mtk_eth *eth, u16 port, u16 devad, u16 reg, u16 *data)
-{
-        mutex_lock(&eth->mii_bus->mdio_lock);
-
-        _mtk_mdio_write(eth, port, MII_MMD_ACC_CTL_REG, devad);
-        _mtk_mdio_write(eth, port, MII_MMD_ADDR_DATA_REG, reg);
-        _mtk_mdio_write(eth, port, MII_MMD_ACC_CTL_REG, MMD_OP_MODE_DATA | devad);
-        *data = _mtk_mdio_read(eth, port, MII_MMD_ADDR_DATA_REG);
-
-        mutex_unlock(&eth->mii_bus->mdio_lock);
-
-        return 0;
-}
-
-u32 mtk_cl45_ind_write(struct mtk_eth *eth, u16 port, u16 devad, u16 reg, u16 data)
-{
-        mutex_lock(&eth->mii_bus->mdio_lock);
-
-        _mtk_mdio_write(eth, port, MII_MMD_ACC_CTL_REG, devad);
-        _mtk_mdio_write(eth, port, MII_MMD_ADDR_DATA_REG, reg);
-        _mtk_mdio_write(eth, port, MII_MMD_ACC_CTL_REG, MMD_OP_MODE_DATA | devad);
-        _mtk_mdio_write(eth, port, MII_MMD_ADDR_DATA_REG, data);
-
-        mutex_unlock(&eth->mii_bus->mdio_lock);
-
-        return 0;
-}
-
 static int mt7621_gmac0_rgmii_adjust(struct mtk_eth *eth,
 				     phy_interface_t interface)
 {
@@ -2580,7 +2582,7 @@
 				MTK_NDP_CO_PRO | MTK_MUTLI_CNT |
 				MTK_RESV_BUF | MTK_WCOMP_EN |
 				MTK_DMAD_WR_WDONE | MTK_CHK_DDONE_EN |
-				MTK_RX_2B_OFFSET, MTK_QDMA_GLO_CFG);
+				MTK_RX_2B_OFFSET | MTK_PKT_RX_WDONE, MTK_QDMA_GLO_CFG);
 		}
 		else
 			mtk_w32(eth,
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 367f7f1..b6380ff 100755
--- 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
@@ -365,6 +365,7 @@
 /* QDMA Global Configuration Register */
 #define MTK_QDMA_GLO_CFG	(QDMA_BASE + 0x204)
 #define MTK_RX_2B_OFFSET	BIT(31)
+#define MTK_PKT_RX_WDONE	BIT(27)
 #define MTK_RX_BT_32DWORDS	(3 << 11)
 #define MTK_NDP_CO_PRO		BIT(10)
 #define MTK_TX_WB_DDONE		BIT(6)
@@ -570,8 +571,11 @@
 #define MTK_PHY_IAC		0x10004
 #define PHY_IAC_ACCESS		BIT(31)
 #define PHY_IAC_READ		BIT(19)
+#define PHY_IAC_READ_C45	(3 << 18)
+#define PHY_IAC_ADDR_C45	(0 << 18)
 #define PHY_IAC_WRITE		BIT(18)
 #define PHY_IAC_START		BIT(16)
+#define PHY_IAC_START_C45	(0 << 16)
 #define PHY_IAC_ADDR_SHIFT	20
 #define PHY_IAC_REG_SHIFT	25
 #define PHY_IAC_TIMEOUT		HZ
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 ffceaa2..b4eef30 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7986.cfg
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7986.cfg
@@ -250,6 +250,7 @@
 CONFIG_HAS_IOPORT_MAP=y
 CONFIG_HOLES_IN_ZONE=y
 CONFIG_HOTPLUG_CPU=y
+CONFIG_HWMON=y
 # CONFIG_HW_NAT is not set
 CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_MTK=y
@@ -315,6 +316,7 @@
 CONFIG_MTD_NAND_MTK=y
 CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_SPI_NAND=y
+# CONFIG_MTD_SPI_NAND_W25N01KV is not set
 CONFIG_MTD_SPI_NOR=y
 CONFIG_MTD_SPLIT_FIRMWARE=y
 CONFIG_MTD_SPLIT_FIT_FW=y
@@ -448,6 +450,8 @@
 CONFIG_SCHED_MC=y
 CONFIG_SCSI=y
 # CONFIG_SECTION_MISMATCH_WARN_ONLY is not set
+# CONFIG_SENSORS_DRIVETEMP is not set
+CONFIG_SENSORS_PWM_FAN=y
 CONFIG_SERIAL_8250_FSL=y
 CONFIG_SERIAL_8250_MT6577=y
 CONFIG_SERIAL_8250_NR_UARTS=3
@@ -525,5 +529,3 @@
 CONFIG_ZLIB_DEFLATE=y
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZONE_DMA32=y
-CONFIG_NVMEM=y
-CONFIG_MTK_EFUSE=y
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0322-fix-dirty-race-between-do_tmpfile.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0322-fix-dirty-race-between-do_tmpfile.patch
new file mode 100644
index 0000000..94ce9bd
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0322-fix-dirty-race-between-do_tmpfile.patch
@@ -0,0 +1,100 @@
+diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
+--- a/fs/ubifs/dir.c
++++ b/fs/ubifs/dir.c
+@@ -356,6 +356,32 @@ out_budg:
+ 	return err;
+ }
+ 
++/**
++ * lock_2_inodes - a wrapper for locking two UBIFS inodes.
++ * @inode1: first inode
++ * @inode2: second inode
++ *
++ * We do not implement any tricks to guarantee strict lock ordering, because
++ * VFS has already done it for us on the @i_mutex. So this is just a simple
++ * wrapper function.
++ */
++static void lock_2_inodes(struct inode *inode1, struct inode *inode2)
++{
++	mutex_lock_nested(&ubifs_inode(inode1)->ui_mutex, WB_MUTEX_1);
++	mutex_lock_nested(&ubifs_inode(inode2)->ui_mutex, WB_MUTEX_2);
++}
++
++/**
++ * unlock_2_inodes - a wrapper for unlocking two UBIFS inodes.
++ * @inode1: first inode
++ * @inode2: second inode
++ */
++static void unlock_2_inodes(struct inode *inode1, struct inode *inode2)
++{
++	mutex_unlock(&ubifs_inode(inode2)->ui_mutex);
++	mutex_unlock(&ubifs_inode(inode1)->ui_mutex);
++}
++
+ static int do_tmpfile(struct inode *dir, struct dentry *dentry,
+ 		      umode_t mode, struct inode **whiteout)
+ {
+@@ -364,7 +390,7 @@ static int do_tmpfile(struct inode *dir, struct dentry *dentry,
+ 	struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1,
+ 					.dirtied_ino = 1};
+ 	struct ubifs_budget_req ino_req = { .dirtied_ino = 1 };
+-	struct ubifs_inode *ui, *dir_ui = ubifs_inode(dir);
++	struct ubifs_inode *ui;
+ 	int err, instantiated = 0;
+ 	struct fscrypt_name nm;
+ 
+@@ -426,18 +452,18 @@ static int do_tmpfile(struct inode *dir, struct dentry *dentry,
+ 	instantiated = 1;
+ 	mutex_unlock(&ui->ui_mutex);
+ 
+-	mutex_lock(&dir_ui->ui_mutex);
++	lock_2_inodes(dir, inode);
+ 	err = ubifs_jnl_update(c, dir, &nm, inode, 1, 0);
+ 	if (err)
+ 		goto out_cancel;
+-	mutex_unlock(&dir_ui->ui_mutex);
++	unlock_2_inodes(dir, inode);
+ 
+ 	ubifs_release_budget(c, &req);
+ 
+ 	return 0;
+ 
+ out_cancel:
+-	mutex_unlock(&dir_ui->ui_mutex);
++	unlock_2_inodes(dir, inode);
+ out_inode:
+ 	make_bad_inode(inode);
+ 	if (!instantiated)
+@@ -672,32 +698,6 @@ static int ubifs_dir_release(struct inode *dir, struct file *file)
+ 	return 0;
+ }
+ 
+-/**
+- * lock_2_inodes - a wrapper for locking two UBIFS inodes.
+- * @inode1: first inode
+- * @inode2: second inode
+- *
+- * We do not implement any tricks to guarantee strict lock ordering, because
+- * VFS has already done it for us on the @i_mutex. So this is just a simple
+- * wrapper function.
+- */
+-static void lock_2_inodes(struct inode *inode1, struct inode *inode2)
+-{
+-	mutex_lock_nested(&ubifs_inode(inode1)->ui_mutex, WB_MUTEX_1);
+-	mutex_lock_nested(&ubifs_inode(inode2)->ui_mutex, WB_MUTEX_2);
+-}
+-
+-/**
+- * unlock_2_inodes - a wrapper for unlocking two UBIFS inodes.
+- * @inode1: first inode
+- * @inode2: second inode
+- */
+-static void unlock_2_inodes(struct inode *inode1, struct inode *inode2)
+-{
+-	mutex_unlock(&ubifs_inode(inode2)->ui_mutex);
+-	mutex_unlock(&ubifs_inode(inode1)->ui_mutex);
+-}
+-
+ static int ubifs_link(struct dentry *old_dentry, struct inode *dir,
+ 		      struct dentry *dentry)
+ {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/7000-fix-race-inside-napi-enable.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/7000-fix-race-inside-napi-enable.patch
new file mode 100644
index 0000000..052f40c
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/7000-fix-race-inside-napi-enable.patch
@@ -0,0 +1,94 @@
+From git@z Thu Jan  1 00:00:00 1970
+Subject: [PATCH v2] napi: fix race inside napi_enable
+From: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
+Date: Sat, 18 Sep 2021 16:52:32 +0800
+Message-Id: <20210918085232.71436-1-xuanzhuo@linux.alibaba.com>
+To: netdev@vger.kernel.org, linyunsheng@huawei.com
+Cc: "David S. Miller" <davem@davemloft.net>, Jakub Kicinski <kuba@kernel.org>, Eric Dumazet <edumazet@google.com>, Daniel Borkmann <daniel@iogearbox.net>, Antoine Tenart <atenart@kernel.org>, Alexander Lobakin <alobakin@pm.me>, Wei Wang <weiwan@google.com>, Taehee Yoo <ap420073@gmail.com>,Björn Töpel <bjorn@kernel.org>, Arnd Bergmann <arnd@arndb.de>, Kumar Kartikeya Dwivedi <memxor@gmail.com>, Neil Horman <nhorman@redhat.com>, Dust Li <dust.li@linux.alibaba.com>
+List-Id: <netdev.vger.kernel.org>
+MIME-Version: 1.0
+Content-Type: text/plain; charset="utf-8"
+Content-Transfer-Encoding: 7bit
+
+The process will cause napi.state to contain NAPI_STATE_SCHED and
+not in the poll_list, which will cause napi_disable() to get stuck.
+
+The prefix "NAPI_STATE_" is removed in the figure below, and
+NAPI_STATE_HASHED is ignored in napi.state.
+
+                      CPU0       |                   CPU1       | napi.state
+===============================================================================
+napi_disable()                   |                              | SCHED | NPSVC
+napi_enable()                    |                              |
+{                                |                              |
+    smp_mb__before_atomic();     |                              |
+    clear_bit(SCHED, &n->state); |                              | NPSVC
+                                 | napi_schedule_prep()         | SCHED | NPSVC
+                                 | napi_poll()                  |
+                                 |   napi_complete_done()       |
+                                 |   {                          |
+                                 |      if (n->state & (NPSVC | | (1)
+                                 |               _BUSY_POLL)))  |
+                                 |           return false;      |
+                                 |     ................         |
+                                 |   }                          | SCHED | NPSVC
+                                 |                              |
+    clear_bit(NPSVC, &n->state); |                              | SCHED
+}                                |                              |
+                                 |                              |
+napi_schedule_prep()             |                              | SCHED | MISSED (2)
+
+(1) Here return direct. Because of NAPI_STATE_NPSVC exists.
+(2) NAPI_STATE_SCHED exists. So not add napi.poll_list to sd->poll_list
+
+Since NAPI_STATE_SCHED already exists and napi is not in the
+sd->poll_list queue, NAPI_STATE_SCHED cannot be cleared and will always
+exist.
+
+1. This will cause this queue to no longer receive packets.
+2. If you encounter napi_disable under the protection of rtnl_lock, it
+   will cause the entire rtnl_lock to be locked, affecting the overall
+   system.
+
+This patch uses cmpxchg to implement napi_enable(), which ensures that
+there will be no race due to the separation of clear two bits.
+
+Fixes: 2d8bff12699abc ("netpoll: Close race condition between poll_one_napi and napi_disable")
+Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
+Reviewed-by: Dust Li <dust.li@linux.alibaba.com>
+---
+ net/core/dev.c | 16 ++++++++++------
+ 1 file changed, 10 insertions(+), 6 deletions(-)
+
+diff --git a/net/core/dev.c b/net/core/dev.c
+index 74fd402d26dd..7ee9fecd3aff 100644
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -6923,12 +6923,16 @@ EXPORT_SYMBOL(napi_disable);
+  */
+ void napi_enable(struct napi_struct *n)
+ {
+-	BUG_ON(!test_bit(NAPI_STATE_SCHED, &n->state));
+-	smp_mb__before_atomic();
+-	clear_bit(NAPI_STATE_SCHED, &n->state);
+-	clear_bit(NAPI_STATE_NPSVC, &n->state);
+-	if (n->dev->threaded && n->thread)
+-		set_bit(NAPI_STATE_THREADED, &n->state);
++	unsigned long val, new;
++
++	do {
++		val = READ_ONCE(n->state);
++		BUG_ON(!test_bit(NAPI_STATE_SCHED, &val));
++
++		new = val & ~(NAPIF_STATE_SCHED | NAPIF_STATE_NPSVC);
++		if (n->dev->threaded && n->thread)
++			new |= NAPIF_STATE_THREADED;
++	} while (cmpxchg(&n->state, val, new) != val);
+ }
+ EXPORT_SYMBOL(napi_enable);
+ 
+
+-- 
+2.31.0
+
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/7001-net-make-napi-disable-symmetric-with-enable.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/7001-net-make-napi-disable-symmetric-with-enable.patch
new file mode 100644
index 0000000..ac84ffc
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/7001-net-make-napi-disable-symmetric-with-enable.patch
@@ -0,0 +1,64 @@
+From git@z Thu Jan  1 00:00:00 1970
+Subject: [PATCH v2] net: make napi_disable() symmetric with enable
+From: Jakub Kicinski <kuba@kernel.org>
+Date: Fri, 24 Sep 2021 13:24:53 -0700
+Message-Id: <20210924202453.1051687-1-kuba@kernel.org>
+To: davem@davemloft.net
+Cc: netdev@vger.kernel.org, eric.dumazet@gmail.com, weiwan@google.com, xuanzhuo@linux.alibaba.com, Jakub Kicinski <kuba@kernel.org>
+List-Id: <netdev.vger.kernel.org>
+MIME-Version: 1.0
+Content-Type: text/plain; charset="utf-8"
+Content-Transfer-Encoding: 7bit
+
+Commit 3765996e4f0b ("napi: fix race inside napi_enable") fixed
+an ordering bug in napi_enable() and made the napi_enable() diverge
+from napi_disable(). The state transitions done on disable are
+not symmetric to enable.
+
+There is no known bug in napi_disable() this is just refactoring.
+
+Eric suggests we can also replace msleep(1) with a more opportunistic
+usleep_range().
+
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ net/core/dev.c | 17 ++++++++++++-----
+ 1 file changed, 12 insertions(+), 5 deletions(-)
+
+diff --git a/net/core/dev.c b/net/core/dev.c
+index f24c3a9..f0a556a 100644
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -6386,18 +6386,25 @@ EXPORT_SYMBOL(netif_napi_add);
+ 
+ void napi_disable(struct napi_struct *n)
+ {
++	unsigned long val, new;
++
+ 	might_sleep();
+ 	set_bit(NAPI_STATE_DISABLE, &n->state);
+ 
+-	while (test_and_set_bit(NAPI_STATE_SCHED, &n->state))
+-		msleep(1);
+-	while (test_and_set_bit(NAPI_STATE_NPSVC, &n->state))
+-		msleep(1);
++	do {
++		val = READ_ONCE(n->state);
++		if (val & (NAPIF_STATE_SCHED | NAPIF_STATE_NPSVC)) {
++			usleep_range(20, 200);
++			continue;
++		}
++
++		new = val | NAPIF_STATE_SCHED | NAPIF_STATE_NPSVC;
++		new &= ~(NAPIF_STATE_THREADED);
++	} while (cmpxchg(&n->state, val, new) != val);
+ 
+ 	hrtimer_cancel(&n->timer);
+ 
+ 	clear_bit(NAPI_STATE_DISABLE, &n->state);
+-	clear_bit(NAPI_STATE_THREADED, &n->state);
+ }
+ EXPORT_SYMBOL(napi_disable);
+ 
+-- 
+2.31.1
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/7002-net-fix-premature-exit-from-napi-state-polling-in-napi-disable-v2.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/7002-net-fix-premature-exit-from-napi-state-polling-in-napi-disable-v2.patch
new file mode 100644
index 0000000..0daf233
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/7002-net-fix-premature-exit-from-napi-state-polling-in-napi-disable-v2.patch
@@ -0,0 +1,114 @@
+From git@z Thu Jan  1 00:00:00 1970
+Subject: [PATCH v2] net: fix premature exit from NAPI state polling in napi_disable()
+From: Alexander Lobakin <alexandr.lobakin@intel.com>
+Date: Wed, 10 Nov 2021 20:56:05 +0100
+Message-Id: <20211110195605.1304-1-alexandr.lobakin@intel.com>
+To: "David S. Miller" <davem@davemloft.net>, Jakub Kicinski <kuba@kernel.org>
+Cc: Alexander Lobakin <alexandr.lobakin@intel.com>, Jesse Brandeburg <jesse.brandeburg@intel.com>, Maciej Fijalkowski <maciej.fijalkowski@intel.com>, Michal Swiatkowski <michal.swiatkowski@intel.com>, Xuan Zhuo <xuanzhuo@linux.alibaba.com>, Antoine Tenart <atenart@kernel.org>, Eric Dumazet <edumazet@google.com>, Wei Wang <weiwan@google.com>,Björn Töpel <bjorn@kernel.org>, netdev@vger.kernel.org, linux-kernel@vger.kernel.org
+List-Id: <linux-kernel.vger.kernel.org>
+MIME-Version: 1.0
+Content-Type: text/plain; charset="utf-8"
+Content-Transfer-Encoding: 7bit
+
+Commit 719c57197010 ("net: make napi_disable() symmetric with
+enable") accidentally introduced a bug sometimes leading to a kernel
+BUG when bringing an iface up/down under heavy traffic load.
+
+Prior to this commit, napi_disable() was polling n->state until
+none of (NAPIF_STATE_SCHED | NAPIF_STATE_NPSVC) is set and then
+always flip them. Now there's a possibility to get away with the
+NAPIF_STATE_SCHE unset as 'continue' drops us to the cmpxchg()
+call with an unitialized variable, rather than straight to
+another round of the state check.
+
+Error path looks like:
+
+napi_disable():
+unsigned long val, new; /* new is uninitialized */
+
+do {
+	val = READ_ONCE(n->state); /* NAPIF_STATE_NPSVC and/or
+				      NAPIF_STATE_SCHED is set */
+	if (val & (NAPIF_STATE_SCHED | NAPIF_STATE_NPSVC)) { /* true */
+		usleep_range(20, 200);
+		continue; /* go straight to the condition check */
+	}
+	new = val | <...>
+} while (cmpxchg(&n->state, val, new) != val); /* state == val, cmpxchg()
+						  writes garbage */
+
+napi_enable():
+do {
+	val = READ_ONCE(n->state);
+	BUG_ON(!test_bit(NAPI_STATE_SCHED, &val)); /* 50/50 boom */
+<...>
+
+while the typical BUG splat is like:
+
+[  172.652461] ------------[ cut here ]------------
+[  172.652462] kernel BUG at net/core/dev.c:6937!
+[  172.656914] invalid opcode: 0000 [#1] PREEMPT SMP PTI
+[  172.661966] CPU: 36 PID: 2829 Comm: xdp_redirect_cp Tainted: G          I       5.15.0 #42
+[  172.670222] Hardware name: Intel Corporation S2600WFT/S2600WFT, BIOS SE5C620.86B.02.01.0014.082620210524 08/26/2021
+[  172.680646] RIP: 0010:napi_enable+0x5a/0xd0
+[  172.684832] Code: 07 49 81 cc 00 01 00 00 4c 89 e2 48 89 d8 80 e6 fb f0 48 0f b1 55 10 48 39 c3 74 10 48 8b 5d 10 f6 c7 04 75 3d f6 c3 01 75 b4 <0f> 0b 5b 5d 41 5c c3 65 ff 05 b8 e5 61 53 48 c7 c6 c0 f3 34 ad 48
+[  172.703578] RSP: 0018:ffffa3c9497477a8 EFLAGS: 00010246
+[  172.708803] RAX: ffffa3c96615a014 RBX: 0000000000000000 RCX: ffff8a4b575301a0
+< snip >
+[  172.782403] Call Trace:
+[  172.784857]  <TASK>
+[  172.786963]  ice_up_complete+0x6f/0x210 [ice]
+[  172.791349]  ice_xdp+0x136/0x320 [ice]
+[  172.795108]  ? ice_change_mtu+0x180/0x180 [ice]
+[  172.799648]  dev_xdp_install+0x61/0xe0
+[  172.803401]  dev_xdp_attach+0x1e0/0x550
+[  172.807240]  dev_change_xdp_fd+0x1e6/0x220
+[  172.811338]  do_setlink+0xee8/0x1010
+[  172.814917]  rtnl_setlink+0xe5/0x170
+[  172.818499]  ? bpf_lsm_binder_set_context_mgr+0x10/0x10
+[  172.823732]  ? security_capable+0x36/0x50
+< snip >
+
+Fix this by replacing 'do { } while (cmpxchg())' with an "infinite"
+for-loop with an explicit break.
+
+From v1 [0]:
+ - just use a for-loop to simplify both the fix and the existing
+   code (Eric).
+
+[0] https://lore.kernel.org/netdev/20211110191126.1214-1-alexandr.lobakin@intel.com
+
+Fixes: 719c57197010 ("net: make napi_disable() symmetric with enable")
+Suggested-by: Eric Dumazet <edumazet@google.com> # for-loop
+Signed-off-by: Alexander Lobakin <alexandr.lobakin@intel.com>
+Reviewed-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+---
+ net/core/dev.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/net/core/dev.c b/net/core/dev.c
+index c8f7c15..fe2c856 100644
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -6391,7 +6391,7 @@ void napi_disable(struct napi_struct *n)
+ 	might_sleep();
+ 	set_bit(NAPI_STATE_DISABLE, &n->state);
+ 
+-	do {
++	for ( ; ; ) {
+ 		val = READ_ONCE(n->state);
+ 		if (val & (NAPIF_STATE_SCHED | NAPIF_STATE_NPSVC)) {
+ 			usleep_range(20, 200);
+@@ -6400,7 +6400,10 @@ void napi_disable(struct napi_struct *n)
+ 
+ 		new = val | NAPIF_STATE_SCHED | NAPIF_STATE_NPSVC;
+ 		new &= ~(NAPIF_STATE_THREADED);
+-	} while (cmpxchg(&n->state, val, new) != val);
++
++		if (cmpxchg(&n->state, val, new) == val)
++			break;
++	}
+ 
+ 	hrtimer_cancel(&n->timer);
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/745-mdiobus-add-c45.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/745-mdiobus-add-c45.patch
new file mode 100644
index 0000000..93c00b8
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/745-mdiobus-add-c45.patch
@@ -0,0 +1,72 @@
+diff --git a/include/linux/mdio.h b/include/linux/mdio.h
+index 0f1f784de..006d1c1e9 100644
+--- a/include/linux/mdio.h
++++ b/include/linux/mdio.h
+@@ -7,8 +7,17 @@
+ #define __LINUX_MDIO_H__
+ 
+ #include <uapi/linux/mdio.h>
++#include <linux/bitfield.h>
+ #include <linux/mod_devicetable.h>
+ 
++/* Or MII_ADDR_C45 into regnum for read/write on mii_bus to enable the 21 bit
++ * IEEE 802.3ae clause 45 addressing mode used by 10GIGE phy chips.
++ */
++#define MII_ADDR_C45		(1<<30)
++#define MII_DEVADDR_C45_SHIFT	16
++#define MII_DEVADDR_C45_MASK	GENMASK(20, 16)
++#define MII_REGADDR_C45_MASK	GENMASK(15, 0)
++
+ struct gpio_desc;
+ struct mii_bus;
+ 
+@@ -325,6 +334,46 @@ int mdiobus_read_nested(struct mii_bus *bus, int addr, u32 regnum);
+ int mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val);
+ int mdiobus_write_nested(struct mii_bus *bus, int addr, u32 regnum, u16 val);
+ 
++static inline u32 mdiobus_c45_addr(int devad, u16 regnum)
++{
++	return MII_ADDR_C45 | devad << MII_DEVADDR_C45_SHIFT | regnum;
++}
++
++static inline u16 mdiobus_c45_regad(u32 regnum)
++{
++	return FIELD_GET(MII_REGADDR_C45_MASK, regnum);
++}
++
++static inline u16 mdiobus_c45_devad(u32 regnum)
++{
++	return FIELD_GET(MII_DEVADDR_C45_MASK, regnum);
++}
++
++static inline int __mdiobus_c45_read(struct mii_bus *bus, int prtad, int devad,
++				     u16 regnum)
++{
++	return __mdiobus_read(bus, prtad, mdiobus_c45_addr(devad, regnum));
++}
++
++static inline int __mdiobus_c45_write(struct mii_bus *bus, int prtad, int devad,
++				      u16 regnum, u16 val)
++{
++	return __mdiobus_write(bus, prtad, mdiobus_c45_addr(devad, regnum),
++			       val);
++}
++
++static inline int mdiobus_c45_read(struct mii_bus *bus, int prtad, int devad,
++				   u16 regnum)
++{
++	return mdiobus_read(bus, prtad, mdiobus_c45_addr(devad, regnum));
++}
++
++static inline int mdiobus_c45_write(struct mii_bus *bus, int prtad, int devad,
++				    u16 regnum, u16 val)
++{
++	return mdiobus_write(bus, prtad, mdiobus_c45_addr(devad, regnum), val);
++}
++
+ int mdiobus_register_device(struct mdio_device *mdiodev);
+ int mdiobus_unregister_device(struct mdio_device *mdiodev);
+ bool mdiobus_is_registered_device(struct mii_bus *bus, int addr);
+-- 
+2.18.0
+
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 c7955d2..15e464b 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
@@ -23,6 +23,7 @@
     file://0307-dts-mt7629-add-snand-support.patch \
     file://0308-dts-mt7622-add-snand-support.patch \
     file://0310-dts-add-wmac-support-for-mt7622-rfb1.patch \
+    file://0322-fix-dirty-race-between-do_tmpfile.patch \
     file://0400-sound-add-some-helpers-to-control-mtk_memif.patch \
     file://0401-sound-refine-hw-params-and-hw-prepare.patch \
     file://0402-sound-add-mt7986-driver.patch \
@@ -78,6 +79,9 @@
     file://414-mtd-spinand-fix-gigadevice-read-dummy.patch \
     file://415-mtd-spinand-fix-F50L1G41LB-ecc-check.patch \
     file://500-auxadc-add-auxadc-32k-clk.patch \
+    file://7000-fix-race-inside-napi-enable.patch \
+    file://7001-net-make-napi-disable-symmetric-with-enable.patch \
+    file://7002-net-fix-premature-exit-from-napi-state-polling-in-napi-disable-v2.patch \
     file://730-net-ethernet-mtk_eth_soc-add-mtk-dsa-tag-rx-offload.patch \
     file://738-mt7531-gsw-internal_phy_calibration.patch \
     file://739-mt7531-gsw-port5_external_phy_init.patch \
@@ -86,6 +90,7 @@
     file://742-net-dsa-add-MT7531-Gigabit-Ethernet-PHY-setting.patch \
     file://743-add-mediatek-ge-gphy-support.patch \
     file://744-en8801s-gphy-support.patch \
+    file://745-mdiobus-add-c45.patch \
     file://8000-PATCH-1-4-tphy-support-type-switch-by-pericfg.patch \
     file://8001-PATCH-2-4-dt-bindings-phy-Add-PHY_TYPE_DP-definition.patch \
     file://8002-PATCH-3-4-dt-bindings-phy-Add-PHY_TYPE_XPCS-definition.patch \