[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(ð->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(ð->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(ð->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(ð->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 \