[rdk-b][common][bsp][Refactor and sync kernel from Openwrt]
[Description]
Refactor and sync kernel from Openwrt to v5.4.219
[Release-log]
N/A
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/120-Fix-alloc_node_mem_map-with-ARCH_PFN_OFFSET-calcu.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/120-Fix-alloc_node_mem_map-with-ARCH_PFN_OFFSET-calcu.patch
index 09e8267..680ea7e 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/120-Fix-alloc_node_mem_map-with-ARCH_PFN_OFFSET-calcu.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/120-Fix-alloc_node_mem_map-with-ARCH_PFN_OFFSET-calcu.patch
@@ -71,7 +71,7 @@
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
-@@ -6886,7 +6886,7 @@ static void __ref alloc_node_mem_map(str
+@@ -6931,7 +6931,7 @@ static void __ref alloc_node_mem_map(str
mem_map = NODE_DATA(0)->node_mem_map;
#if defined(CONFIG_HAVE_MEMBLOCK_NODE_MAP) || defined(CONFIG_FLATMEM)
if (page_to_pfn(mem_map) != pgdat->node_start_pfn)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/834-ledtrig-libata.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/834-ledtrig-libata.patch
index 1c6eb8c..4bb74ed 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/834-ledtrig-libata.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/834-ledtrig-libata.patch
@@ -65,7 +65,7 @@
/**
* ata_build_rw_tf - Build ATA taskfile for given read/write request
* @tf: Target ATA taskfile
-@@ -5155,6 +5168,9 @@ struct ata_queued_cmd *ata_qc_new_init(s
+@@ -5159,6 +5172,9 @@ struct ata_queued_cmd *ata_qc_new_init(s
if (tag < 0)
return NULL;
}
@@ -75,7 +75,7 @@
qc = __ata_qc_from_tag(ap, tag);
qc->tag = qc->hw_tag = tag;
-@@ -6091,6 +6107,9 @@ struct ata_port *ata_port_alloc(struct a
+@@ -6095,6 +6111,9 @@ struct ata_port *ata_port_alloc(struct a
ap->stats.unhandled_irq = 1;
ap->stats.idle_irq = 1;
#endif
@@ -85,7 +85,7 @@
ata_sff_port_init(ap);
return ap;
-@@ -6126,6 +6145,12 @@ static void ata_host_release(struct kref
+@@ -6130,6 +6149,12 @@ static void ata_host_release(struct kref
kfree(ap->pmp_link);
kfree(ap->slave_link);
@@ -98,7 +98,7 @@
kfree(ap);
host->ports[i] = NULL;
}
-@@ -6589,7 +6614,23 @@ int ata_host_register(struct ata_host *h
+@@ -6593,7 +6618,23 @@ int ata_host_register(struct ata_host *h
host->ports[i]->print_id = atomic_inc_return(&ata_print_id);
host->ports[i]->local_port_no = i + 1;
}
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 16b872e..a4d3f2f 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
@@ -358,19 +358,23 @@
<&topckgen CK_TOP_NPU_TOPS_SEL>,
<&topckgen CK_TOP_CK_NPU_SEL_CM_TOPS_SEL>;
clock-names = "bus", "sram", "xdma", "offload", "mgmt";
+ power-domains = <&topmisc MT7988_POWER_DOMAIN_TOPS0>,
+ <&topmisc MT7988_POWER_DOMAIN_TOPS1>;
+
interrupt-parent = <&gic>;
interrupts = <GIC_SPI 199 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 280 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "tdma-tx-pause", "mbox";
- topmisc = <&topmisc>;
+
fe_mem = <ð>;
- topckgen = <&topckgen>;
};
+
hpdma1: hpdma@09106000 {
compatible = "mediatek,hpdma-top";
reg = <0 0x09106000 0 0x1000>;
reg-names = "base";
};
+
hpdma2: hpdma@09606000 {
compatible = "mediatek,hpdma-sub";
reg = <0 0x09606000 0 0x1000>;
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 c6f76bf..5ad8645 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
@@ -656,6 +656,26 @@
pr_info("+-----------------------------------------------+\n");
}
+void dump_each_port(struct seq_file *seq, struct mtk_eth *eth, u32 base)
+{
+ u32 pkt_cnt = 0;
+ int i = 0;
+
+ for (i = 0; i < 7; i++) {
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
+ if ((base == 0x402C) && (i == 6))
+ base = 0x408C;
+ else if ((base == 0x408C) && (i == 6))
+ base = 0x402C;
+ else
+ ;
+ }
+ pkt_cnt = mt7530_mdio_r32(eth, (base) + (i * 0x100));
+ seq_printf(seq, "%8u ", pkt_cnt);
+ }
+ seq_puts(seq, "\n");
+}
+
int esw_cnt_read(struct seq_file *seq, void *v)
{
unsigned int pkt_cnt = 0;
@@ -669,56 +689,47 @@
mt798x_iomap();
-#define DUMP_EACH_PORT(base) \
- do { \
- for (i = 0; i < 7; i++) { \
- pkt_cnt = mt7530_mdio_r32(eth, (base) + (i * 0x100));\
- seq_printf(seq, "%8u ", pkt_cnt); \
- } \
- seq_puts(seq, "\n"); \
- } while (0)
-
seq_printf(seq, "===================== %8s %8s %8s %8s %8s %8s %8s\n",
"Port0", "Port1", "Port2", "Port3", "Port4", "Port5",
"Port6");
seq_puts(seq, "Tx Drop Packet :");
- DUMP_EACH_PORT(0x4000);
+ dump_each_port(seq, eth, 0x4000);
seq_puts(seq, "Tx CRC Error :");
- DUMP_EACH_PORT(0x4004);
+ dump_each_port(seq, eth, 0x4004);
seq_puts(seq, "Tx Unicast Packet :");
- DUMP_EACH_PORT(0x4008);
+ dump_each_port(seq, eth, 0x4008);
seq_puts(seq, "Tx Multicast Packet :");
- DUMP_EACH_PORT(0x400C);
+ dump_each_port(seq, eth, 0x400C);
seq_puts(seq, "Tx Broadcast Packet :");
- DUMP_EACH_PORT(0x4010);
+ dump_each_port(seq, eth, 0x4010);
seq_puts(seq, "Tx Collision Event :");
- DUMP_EACH_PORT(0x4014);
+ dump_each_port(seq, eth, 0x4014);
seq_puts(seq, "Tx Pause Packet :");
- DUMP_EACH_PORT(0x402C);
+ dump_each_port(seq, eth, 0x402C);
seq_puts(seq, "Rx Drop Packet :");
- DUMP_EACH_PORT(0x4060);
+ dump_each_port(seq, eth, 0x4060);
seq_puts(seq, "Rx Filtering Packet :");
- DUMP_EACH_PORT(0x4064);
+ dump_each_port(seq, eth, 0x4064);
seq_puts(seq, "Rx Unicast Packet :");
- DUMP_EACH_PORT(0x4068);
+ dump_each_port(seq, eth, 0x4068);
seq_puts(seq, "Rx Multicast Packet :");
- DUMP_EACH_PORT(0x406C);
+ dump_each_port(seq, eth, 0x406C);
seq_puts(seq, "Rx Broadcast Packet :");
- DUMP_EACH_PORT(0x4070);
+ dump_each_port(seq, eth, 0x4070);
seq_puts(seq, "Rx Alignment Error :");
- DUMP_EACH_PORT(0x4074);
+ dump_each_port(seq, eth, 0x4074);
seq_puts(seq, "Rx CRC Error :");
- DUMP_EACH_PORT(0x4078);
+ dump_each_port(seq, eth, 0x4078);
seq_puts(seq, "Rx Undersize Error :");
- DUMP_EACH_PORT(0x407C);
+ dump_each_port(seq, eth, 0x407C);
seq_puts(seq, "Rx Fragment Error :");
- DUMP_EACH_PORT(0x4080);
+ dump_each_port(seq, eth, 0x4080);
seq_puts(seq, "Rx Oversize Error :");
- DUMP_EACH_PORT(0x4084);
+ dump_each_port(seq, eth, 0x4084);
seq_puts(seq, "Rx Jabber Error :");
- DUMP_EACH_PORT(0x4088);
+ dump_each_port(seq, eth, 0x4088);
seq_puts(seq, "Rx Pause Packet :");
- DUMP_EACH_PORT(0x408C);
+ dump_each_port(seq, eth, 0x408C);
mt7530_mdio_w32(eth, 0x4fe0, 0xf0);
mt7530_mdio_w32(eth, 0x4fe0, 0x800000f0);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mediatek-ge.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mediatek-ge.c
index 0eefd36..50729d6 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mediatek-ge.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mediatek-ge.c
@@ -538,7 +538,7 @@
switch(phydev->drv->phy_id) {
case 0x03a29481:
{
- int tmp[16] = { 1, 1, 1, 1 };
+ int tmp[16] = { -1, -1, -1, -1 };
memcpy(bias, (const void *)tmp, sizeof(bias));
break;
}
@@ -894,6 +894,13 @@
/* Disable TX power saving */
phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG7,
MTK_PHY_DA_AD_BUF_BIAS_LP_MASK, 0x3 << 8);
+
+ /* Slave mode finetune, Kp=3/Kf=2 */
+ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+ __phy_write(phydev, 0x12, 0x0);
+ __phy_write(phydev, 0x11, 0x750);
+ __phy_write(phydev, 0x10, 0x9686);
+ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
}
static int mt798x_phy_calibration(struct phy_device *phydev)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0007-cpufreq-mtk-vbining-add-mt7988-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0007-cpufreq-mtk-vbining-add-mt7988-support.patch
index 8e99118..aa31f22 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0007-cpufreq-mtk-vbining-add-mt7988-support.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0007-cpufreq-mtk-vbining-add-mt7988-support.patch
@@ -15,10 +15,10 @@
struct cpufreq_frequency_table *freq_table;
int ret;
+ int target_vproc;
-+ u32 reg_val;
++ u8 reg_val;
+ struct nvmem_cell *cell;
+ size_t len;
-+ u32 *buf;
++ u8 *buf;
info = mtk_cpu_dvfs_info_lookup(policy->cpu);
if (!info) {
@@ -28,7 +28,7 @@
+ cell = nvmem_cell_get(info->cpu_dev, "calibration-data");
+ if (!IS_ERR(cell)) {
-+ buf = (u32 *)nvmem_cell_read(cell, &len);
++ buf = (u8 *)nvmem_cell_read(cell, &len);
+ nvmem_cell_put(cell);
+ if (!IS_ERR(buf)) {
+ reg_val = buf[0] & 0x1f;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/750-add-mdio-bus-for-gphy-calibration.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/750-add-mdio-bus-for-gphy-calibration.patch
new file mode 100755
index 0000000..e3efa34
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/750-add-mdio-bus-for-gphy-calibration.patch
@@ -0,0 +1,133 @@
+Index: linux-5.4.215/drivers/net/dsa/mt7530.c
+===================================================================
+--- linux-5.4.215.orig/drivers/net/dsa/mt7530.c
++++ linux-5.4.215/drivers/net/dsa/mt7530.c
+@@ -847,6 +847,117 @@ mt7531_ind_phy_write(struct dsa_switch *
+ return ret;
+ }
+
++static int mt753x_mdio_read(struct mii_bus *bus, int addr, int regnum)
++{
++ struct mt7530_priv *priv = bus->priv;
++ struct mt7530_dummy_poll p;
++ int ret;
++ u32 val;
++
++ INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
++
++ mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
++
++ ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
++ !(val & MT7531_PHY_ACS_ST), 20, 100000);
++ if (ret < 0) {
++ dev_err(priv->dev, "poll timeout\n");
++ goto out;
++ }
++
++ val = MT7531_MDIO_CL22_READ | MT7531_MDIO_PHY_ADDR(addr) |
++ MT7531_MDIO_REG_ADDR(regnum);
++
++ mt7530_mii_write(priv, MT7531_PHY_IAC, val | MT7531_PHY_ACS_ST);
++
++ ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
++ !(val & MT7531_PHY_ACS_ST), 20, 100000);
++ if (ret < 0) {
++ dev_err(priv->dev, "poll timeout\n");
++ goto out;
++ }
++
++ ret = val & MT7531_MDIO_RW_DATA_MASK;
++out:
++ mutex_unlock(&priv->bus->mdio_lock);
++
++ return ret;
++}
++
++static int mt753x_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val)
++{
++ struct mt7530_priv *priv = bus->priv;
++ struct mt7530_dummy_poll p;
++ int ret;
++ u32 reg;
++
++ INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
++
++ mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
++
++ ret = readx_poll_timeout(_mt7530_unlocked_read, &p, reg,
++ !(reg & MT7531_PHY_ACS_ST), 20, 100000);
++ if (ret < 0) {
++ dev_err(priv->dev, "poll timeout\n");
++ goto out;
++ }
++
++ reg = MT7531_MDIO_CL22_WRITE | MT7531_MDIO_PHY_ADDR(addr) |
++ MT7531_MDIO_REG_ADDR(regnum) | val;
++
++ mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
++
++ ret = readx_poll_timeout(_mt7530_unlocked_read, &p, reg,
++ !(reg & MT7531_PHY_ACS_ST), 20, 100000);
++ if (ret < 0) {
++ dev_err(priv->dev, "poll timeout\n");
++ goto out;
++ }
++
++out:
++ mutex_unlock(&priv->bus->mdio_lock);
++
++ return ret;
++}
++
++static int mt753x_setup_mdio(struct dsa_switch *ds)
++{
++ struct mt7530_priv *priv = ds->priv;
++ struct device_node *mdio_np;
++ int ret;
++
++ mdio_np = of_get_compatible_child(priv->dev->of_node, "mediatek,dsa-slave-mdio");
++ if (!mdio_np) {
++ dev_err(priv->dev, "no MDIO bus node\n");
++ return -ENODEV;
++ }
++
++ priv->ds->slave_mii_bus = devm_mdiobus_alloc(priv->dev);
++ if (!priv->ds->slave_mii_bus) {
++ ret = -ENOMEM;
++ goto err_put_node;
++ }
++ priv->ds->slave_mii_bus->name = "mediatek,dsa-slave-mdio";
++ priv->ds->slave_mii_bus->priv = priv;
++ priv->ds->slave_mii_bus->parent = priv->dev;
++ priv->ds->slave_mii_bus->phy_mask = ~priv->ds->phys_mii_mask;
++ priv->ds->slave_mii_bus->read = mt753x_mdio_read;
++ priv->ds->slave_mii_bus->write = mt753x_mdio_write;
++ snprintf(priv->ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "dsa-%d.%d",
++ priv->ds->dst->index, priv->ds->index);
++ priv->ds->slave_mii_bus->dev.of_node = mdio_np;
++
++ ret = of_mdiobus_register(priv->ds->slave_mii_bus, mdio_np);
++ if (ret)
++ dev_err(priv->dev, "unable to register MDIO bus %s\n",
++ priv->ds->slave_mii_bus->id);
++
++err_put_node:
++ of_node_put(mdio_np);
++
++ return ret;
++}
++
+ static void
+ mt7530_get_strings(struct dsa_switch *ds, int port, u32 stringset,
+ uint8_t *data)
+@@ -2694,6 +2805,10 @@ mt7988_setup(struct dsa_switch *ds)
+ if (ret < 0)
+ return ret;
+
++ ret = mt753x_setup_mdio(ds);
++ if (ret < 0)
++ dev_err(priv->dev, "mt753x_setup_mdio failed\n");
++
+ return 0;
+ }
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/750-add-mdio-bus-for-phy-node.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/750-add-mdio-bus-for-phy-node.patch
deleted file mode 100644
index 5a130b1..0000000
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/750-add-mdio-bus-for-phy-node.patch
+++ /dev/null
@@ -1,165 +0,0 @@
-Index: linux-5.4.203/drivers/net/dsa/mt7530.c
-===================================================================
---- linux-5.4.203.orig/drivers/net/dsa/mt7530.c
-+++ linux-5.4.203/drivers/net/dsa/mt7530.c
-@@ -847,6 +847,132 @@ mt7531_ind_phy_write(struct dsa_switch *
- return ret;
- }
-
-+static int mt753x_mdio_read(struct mii_bus *bus, int addr, int regnum)
-+{
-+ struct mt7530_priv *priv = bus->priv;
-+ struct mt7530_dummy_poll p;
-+ int ret;
-+ u32 val;
-+
-+ INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
-+
-+ mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
-+
-+ ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
-+ !(val & MT7531_PHY_ACS_ST), 20, 100000);
-+ if (ret < 0) {
-+ dev_err(priv->dev, "poll timeout\n");
-+ goto out;
-+ }
-+
-+ val = MT7531_MDIO_CL22_READ | MT7531_MDIO_PHY_ADDR(addr) |
-+ MT7531_MDIO_REG_ADDR(regnum);
-+
-+ mt7530_mii_write(priv, MT7531_PHY_IAC, val | MT7531_PHY_ACS_ST);
-+
-+ ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
-+ !(val & MT7531_PHY_ACS_ST), 20, 100000);
-+ if (ret < 0) {
-+ dev_err(priv->dev, "poll timeout\n");
-+ goto out;
-+ }
-+
-+ ret = val & MT7531_MDIO_RW_DATA_MASK;
-+out:
-+ mutex_unlock(&priv->bus->mdio_lock);
-+
-+ return ret;
-+}
-+
-+static int mt753x_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val)
-+{
-+ struct mt7530_priv *priv = bus->priv;
-+ struct mt7530_dummy_poll p;
-+ int ret;
-+ u32 reg;
-+
-+ INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
-+
-+ mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
-+
-+ ret = readx_poll_timeout(_mt7530_unlocked_read, &p, reg,
-+ !(reg & MT7531_PHY_ACS_ST), 20, 100000);
-+ if (ret < 0) {
-+ dev_err(priv->dev, "poll timeout\n");
-+ goto out;
-+ }
-+
-+ reg = MT7531_MDIO_CL22_WRITE | MT7531_MDIO_PHY_ADDR(addr) |
-+ MT7531_MDIO_REG_ADDR(regnum) | val;
-+
-+ mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
-+
-+ ret = readx_poll_timeout(_mt7530_unlocked_read, &p, reg,
-+ !(reg & MT7531_PHY_ACS_ST), 20, 100000);
-+ if (ret < 0) {
-+ dev_err(priv->dev, "poll timeout\n");
-+ goto out;
-+ }
-+
-+out:
-+ mutex_unlock(&priv->bus->mdio_lock);
-+
-+ return ret;
-+}
-+
-+static int mt753x_mdio_init(struct mt7530_priv *priv)
-+{
-+ struct device_node *dn;
-+ struct device_node *mii_np;
-+ int ret;
-+
-+ dn = priv->dev->of_node;
-+
-+ mii_np = of_get_child_by_name(dn, "mdio-bus");
-+ if (!mii_np) {
-+ ret = -ENODEV;
-+ goto err_put_node;
-+ }
-+
-+ if (!of_device_is_available(mii_np)) {
-+ ret = -ENODEV;
-+ goto err_put_node;
-+ }
-+
-+ priv->gbus = devm_mdiobus_alloc(priv->dev);
-+ if (!priv->gbus) {
-+ ret = -ENOMEM;
-+ goto err_put_node;
-+ }
-+ priv->gbus->name = "mt753x_mdio";
-+ priv->gbus->read = mt753x_mdio_read;
-+ priv->gbus->write = mt753x_mdio_write;
-+ priv->gbus->priv = priv;
-+ priv->gbus->parent = priv->dev;
-+
-+ if(snprintf(priv->gbus->id, MII_BUS_ID_SIZE, "%s@%s", mii_np->name, dn->name) < 0) {
-+ ret = -ENOMEM;
-+ goto err_put_node;
-+ }
-+
-+ ret = of_mdiobus_register(priv->gbus, mii_np);
-+ if (ret)
-+ priv->gbus = NULL;
-+
-+err_put_node:
-+ of_node_put(mii_np);
-+
-+ return ret;
-+}
-+
-+static void mt753x_mdio_exit(struct mt7530_priv *priv)
-+{
-+ if (!priv->gbus)
-+ return;
-+
-+ mdiobus_unregister(priv->gbus);
-+}
-+
- static void
- mt7530_get_strings(struct dsa_switch *ds, int port, u32 stringset,
- uint8_t *data)
-@@ -2892,6 +3018,7 @@ mt7530_probe(struct mdio_device *mdiodev
- return ret;
- }
- mt7530_nl_init(&priv);
-+ mt753x_mdio_init(priv);
-
- return 0;
- }
-@@ -2919,6 +3046,7 @@ mt7530_remove(struct mdio_device *mdiode
- iounmap(priv->base);
-
- mt7530_nl_exit();
-+ mt753x_mdio_exit(priv);
- }
-
- static struct mdio_driver mt7530_mdio_driver = {
-Index: linux-5.4.203/drivers/net/dsa/mt7530.h
-===================================================================
---- linux-5.4.203.orig/drivers/net/dsa/mt7530.h
-+++ linux-5.4.203/drivers/net/dsa/mt7530.h
-@@ -730,6 +730,7 @@ struct mt7530_priv {
- struct device *dev;
- struct dsa_switch *ds;
- struct mii_bus *bus;
-+ struct mii_bus *gbus;
- struct reset_control *rstc;
- struct regulator *core_pwr;
- struct regulator *io_pwr;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/8011-ovs-add-multicast-to-unicast-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/8011-ovs-add-multicast-to-unicast-support.patch
new file mode 100755
index 0000000..d0764d2
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/8011-ovs-add-multicast-to-unicast-support.patch
@@ -0,0 +1,366 @@
+diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
+index 9e8a5c4..16f5187 100644
+--- a/net/openvswitch/actions.c
++++ b/net/openvswitch/actions.c
+@@ -919,6 +919,10 @@ static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port,
+ struct sw_flow_key *key)
+ {
+ struct vport *vport = ovs_vport_rcu(dp, out_port);
++ struct multicast_data_base *mdb;
++ struct multicast_table *table;
++ struct multicast_table_entry *entry;
++ struct sk_buff *skb_cpy;
+
+ if (likely(vport)) {
+ u16 mru = OVS_CB(skb)->mru;
+@@ -933,7 +937,28 @@ static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port,
+
+ if (likely(!mru ||
+ (skb->len <= mru + vport->dev->hard_header_len))) {
+- ovs_vport_send(vport, skb, ovs_key_mac_proto(key));
++ if (is_ipv4_multicast(skb) && !is_igmp(skb)) {
++ mdb = vport->mdb;
++ spin_lock(&mdb->tbl_lock);
++ list_for_each_entry(table, &mdb->list_head, mdb_node) {
++ if (table->group_addr.u.ip4 == key->ipv4.addr.dst) {
++ list_for_each_entry(entry, &table->entry_list, entry_node) {
++ skb_cpy = skb_copy(skb, GFP_ATOMIC);
++ if (!skb_cpy) {
++ kfree_skb(skb);
++ pr_err("%s(): error\n", __func__);
++ spin_unlock(&mdb->tbl_lock);
++ return;
++ }
++ memcpy(skb_cpy->data, entry->eth_addr, ETH_ALEN);
++ ovs_vport_send(vport, skb_cpy, ovs_key_mac_proto(key));
++ }
++ }
++ }
++ spin_unlock(&mdb->tbl_lock);
++ kfree_skb(skb);
++ } else
++ ovs_vport_send(vport, skb, ovs_key_mac_proto(key));
+ } else if (mru <= vport->dev->mtu) {
+ struct net *net = read_pnet(&dp->net);
+
+diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
+index 4f097bd..e6be550 100644
+--- a/net/openvswitch/datapath.c
++++ b/net/openvswitch/datapath.c
+@@ -11,6 +11,7 @@
+ #include <linux/if_vlan.h>
+ #include <linux/in.h>
+ #include <linux/ip.h>
++#include <linux/igmp.h>
+ #include <linux/jhash.h>
+ #include <linux/delay.h>
+ #include <linux/time.h>
+@@ -530,6 +531,166 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
+ return err;
+ }
+
++static int ovs_ip4_multicast_add_group(__be32 _group_addr,
++ const u8 *entry_addr,
++ struct vport *input_vport)
++{
++ struct multicast_data_base *mdb;
++ struct multicast_table *table;
++ struct multicast_table_entry *entry;
++
++ if (ipv4_is_local_multicast(_group_addr))
++ return 0;
++
++ mdb = input_vport->mdb;
++ spin_lock(&mdb->tbl_lock);
++ list_for_each_entry(table, &mdb->list_head, mdb_node) {
++ if (table->group_addr.u.ip4 == _group_addr) {
++ list_for_each_entry(entry, &table->entry_list, entry_node) {
++ if (!memcmp(entry->eth_addr, entry_addr, ETH_ALEN)) {
++ spin_unlock(&mdb->tbl_lock);
++ return 0;
++ }
++ }
++ entry = kzalloc(sizeof(struct multicast_table_entry), GFP_ATOMIC);
++ if (!entry) {
++ spin_unlock(&mdb->tbl_lock);
++ return -ENOMEM;
++ }
++
++ memcpy(entry->eth_addr, entry_addr, ETH_ALEN);
++ list_add(&entry->entry_node, &table->entry_list);
++ spin_unlock(&mdb->tbl_lock);
++ return 0;
++ }
++ }
++
++ table = kzalloc(sizeof(struct multicast_table), GFP_ATOMIC);
++ if (!table) {
++ spin_unlock(&mdb->tbl_lock);
++ return -ENOMEM;
++ }
++
++ INIT_LIST_HEAD(&table->entry_list);
++ entry = kzalloc(sizeof(struct multicast_table_entry), GFP_ATOMIC);
++ if (!entry) {
++ kfree(table);
++ spin_unlock(&mdb->tbl_lock);
++ return -ENOMEM;
++ }
++
++ memcpy(entry->eth_addr, entry_addr, ETH_ALEN);
++ list_add(&entry->entry_node, &table->entry_list);
++
++ table->group_addr.u.ip4 = _group_addr;
++ list_add(&table->mdb_node, &mdb->list_head);
++
++ spin_unlock(&mdb->tbl_lock);
++ return 0;
++}
++
++static int ovs_ip4_multicast_leave_group(__be32 _group_addr,
++ const u8 *entry_addr,
++ struct vport *input_vport)
++{
++ struct multicast_data_base *mdb;
++ struct multicast_table *table, *table_tmp;
++ struct multicast_table_entry *entry, *entry_tmp;
++
++ if (ipv4_is_local_multicast(_group_addr))
++ return 0;
++
++ mdb = input_vport->mdb;
++ spin_lock(&mdb->tbl_lock);
++ list_for_each_entry_safe(table, table_tmp, &mdb->list_head, mdb_node) {
++ if (table->group_addr.u.ip4 == _group_addr) {
++ list_for_each_entry_safe(entry, entry_tmp, &table->entry_list, entry_node) {
++ if (!memcmp(entry->eth_addr, entry_addr, ETH_ALEN)) {
++ list_del(&entry->entry_node);
++ kfree(entry);
++
++ if (list_empty(&table->entry_list)) {
++ list_del(&table->mdb_node);
++ kfree(table);
++ }
++ spin_unlock(&mdb->tbl_lock);
++ return 0;
++ }
++ }
++ }
++ }
++ spin_unlock(&mdb->tbl_lock);
++ return 0;
++}
++
++static int ovs_multicast_ipv4_rcv(struct sk_buff *skb, struct vport *input_vport)
++{
++ struct ethhdr *eth_hdr;
++ const u8 *dl_src;
++ __be32 group_addr;
++ struct iphdr *ip_header;
++ struct igmphdr *igmp_hdr;
++ int i;
++ struct igmpv3_report *igmpv3_hdr;
++ u16 group_num;
++ struct igmpv3_grec *grec;
++ u8 group_type;
++ u8 aux_data_len;
++ u16 num_of_source;
++ int err;
++
++ err = ip_mc_check_igmp(skb);
++ if (err < 0)
++ return 0;
++
++ eth_hdr = skb_eth_hdr(skb);
++ dl_src = eth_hdr->h_source;
++ ip_header = (struct iphdr *)(skb->data + 14);
++ igmp_hdr = (struct igmphdr *)((u8 *)ip_header + ip_header->ihl * 4);
++
++ switch (igmp_hdr->type) {
++ case IGMP_HOST_MEMBERSHIP_REPORT:
++ case IGMPV2_HOST_MEMBERSHIP_REPORT:
++ group_addr = igmp_hdr->group;
++ ovs_ip4_multicast_add_group(group_addr, dl_src, input_vport);
++ break;
++ case IGMP_HOST_LEAVE_MESSAGE:
++ group_addr = igmp_hdr->group;
++ ovs_ip4_multicast_leave_group(group_addr, dl_src, input_vport);
++ break;
++ case IGMPV3_HOST_MEMBERSHIP_REPORT:
++ igmpv3_hdr = (struct igmpv3_report *)igmp_hdr;
++ group_num = ntohs(igmpv3_hdr->ngrec);
++ grec = igmpv3_hdr->grec;
++ //group_num = ntohs(*(u16 *)(igmp_hdr + 6));
++ //group = igmp_hdr + 8;
++ for (i = 0; i < group_num; i++) {
++ group_type = grec->grec_type;
++ aux_data_len = grec->grec_auxwords;
++ num_of_source = ntohs(grec->grec_nsrcs);
++ group_addr = grec->grec_mca;
++
++ if (group_type == IGMPV3_MODE_IS_EXCLUDE ||
++ group_type == IGMPV3_CHANGE_TO_EXCLUDE ||
++ group_type == IGMPV3_ALLOW_NEW_SOURCES)
++ ovs_ip4_multicast_add_group(group_addr, dl_src, input_vport);
++
++ if (group_type == IGMPV3_MODE_IS_INCLUDE ||
++ group_type == IGMPV3_CHANGE_TO_INCLUDE ||
++ group_type == IGMPV3_BLOCK_OLD_SOURCES)
++ if (num_of_source == 0)
++ ovs_ip4_multicast_leave_group(group_addr, dl_src, input_vport);
++
++ grec += (8 + (num_of_source * 4) + aux_data_len);
++ }
++ break;
++ default:
++ pr_warning("%s(): error pkt\n", __func__);
++ break;
++ }
++ return 0;
++}
++
+ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
+ {
+ struct ovs_header *ovs_header = info->userhdr;
+@@ -604,6 +765,9 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
+ OVS_CB(packet)->input_vport = input_vport;
+ sf_acts = rcu_dereference(flow->sf_acts);
+
++ if (is_igmp(packet))
++ ovs_multicast_ipv4_rcv(packet, input_vport);
++
+ local_bh_disable();
+ err = ovs_execute_actions(dp, packet, sf_acts, &flow->key);
+ local_bh_enable();
+@@ -2183,6 +2347,9 @@ static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
+ struct datapath *dp;
+ struct vport *vport;
+ unsigned int new_headroom;
++ struct multicast_data_base *mdb;
++ struct multicast_table *table, *table_tmp;
++ struct multicast_table_entry *entry, *entry_tmp;
+ int err;
+
+ reply = ovs_vport_cmd_alloc_info();
+@@ -2210,6 +2377,22 @@ static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
+ if (netdev_get_fwd_headroom(vport->dev) == dp->max_headroom)
+ update_headroom = true;
+
++ mdb = vport->mdb;
++ spin_lock(&mdb->tbl_lock);
++ list_for_each_entry_safe(table, table_tmp, &mdb->list_head, mdb_node) {
++ list_for_each_entry_safe(entry, entry_tmp, &table->entry_list, entry_node) {
++ list_del(&entry->entry_node);
++ kfree(entry);
++
++ if (list_empty(&table->entry_list)) {
++ list_del(&table->mdb_node);
++ kfree(table);
++ }
++ }
++ }
++ spin_unlock(&mdb->tbl_lock);
++ kfree(mdb);
++
+ netdev_reset_rx_headroom(vport->dev);
+ ovs_dp_detach_port(vport);
+
+diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h
+index 81e85dd..520532e 100644
+--- a/net/openvswitch/datapath.h
++++ b/net/openvswitch/datapath.h
+@@ -215,6 +215,31 @@ static inline struct datapath *get_dp(struct net *net, int dp_ifindex)
+ return dp;
+ }
+
++#define IGMP_PROTOCOL_OFFSET 23
++/* support ipv4 for now */
++static inline bool is_ipv4_multicast(struct sk_buff *skb)
++{
++ struct ethhdr *eth_hdr = skb_eth_hdr(skb);
++
++ return eth_hdr->h_dest[0] == 0x01 && skb->protocol == htons(ETH_P_IP);
++}
++
++static inline bool is_igmp(struct sk_buff *skb)
++{
++ struct ethhdr *eth_hdr;
++
++ if (!skb)
++ return 0;
++
++ eth_hdr = skb_eth_hdr(skb);
++
++ if (eth_hdr->h_dest[0] == 0x01 &&
++ skb->protocol == htons(ETH_P_IP))
++ return (*(skb->data + IGMP_PROTOCOL_OFFSET) == IPPROTO_IGMP);
++ else
++ return 0;
++}
++
+ extern struct notifier_block ovs_dp_device_notifier;
+ extern struct genl_family dp_vport_genl_family;
+
+diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c
+index 19af0ef..77bc923 100644
+--- a/net/openvswitch/vport.c
++++ b/net/openvswitch/vport.c
+@@ -141,6 +141,14 @@ struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *ops,
+ return ERR_PTR(-EINVAL);
+ }
+
++ vport->mdb = kzalloc(sizeof(struct multicast_data_base), GFP_KERNEL);
++ if (!vport->mdb) {
++ kfree(vport);
++ return ERR_PTR(-ENOMEM);
++ }
++ INIT_LIST_HEAD(&vport->mdb->list_head);
++ spin_lock_init(&vport->mdb->tbl_lock);
++
+ return vport;
+ }
+ EXPORT_SYMBOL_GPL(ovs_vport_alloc);
+diff --git a/net/openvswitch/vport.h b/net/openvswitch/vport.h
+index 1eb7495..eb69d6c 100644
+--- a/net/openvswitch/vport.h
++++ b/net/openvswitch/vport.h
+@@ -55,6 +55,30 @@ struct vport_portids {
+ u32 ids[];
+ };
+
++struct ip_addr {
++ union {
++ __be32 ip4;
++ struct in6_addr ip6;
++ } u;
++};
++
++struct multicast_table_entry {
++ struct list_head entry_node;
++ u8 eth_addr[ETH_ALEN];
++};
++
++struct multicast_table {
++ struct list_head mdb_node;
++ struct list_head entry_list;
++ struct ip_addr group_addr;
++};
++
++struct multicast_data_base {
++ struct list_head list_head;
++ spinlock_t tbl_lock;
++};
++
++
+ /**
+ * struct vport - one port within a datapath
+ * @dev: Pointer to net_device.
+@@ -79,6 +103,8 @@ struct vport {
+
+ struct list_head detach_list;
+ struct rcu_head rcu;
++
++ struct multicast_data_base *mdb;
+ };
+
+ /**
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 4c9012a..d63d381 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
@@ -108,7 +108,7 @@
file://747-net-phy-aquantia-add-AQR113C.patch \
file://748-add-netlink-support-for-dsa.patch \
file://749-net-dsa-support-mt7988.patch \
- file://750-add-mdio-bus-for-phy-node.patch \
+ file://750-add-mdio-bus-for-gphy-calibration.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 \
@@ -120,6 +120,7 @@
file://8008-phy-phy-mtk-tphy-add-auto-load-valid-check-mechanism.patch \
file://8010-ovs-support-flow-offload.patch \
file://8010-phy-phy-mtk-xsphy-support-type-switch-by-pericfg.patch \
+ file://8011-ovs-add-multicast-to-unicast-support.patch \
file://9000-PATCH-1-1-xHCI-change-compliance-mode-de-emphasis-default-as-g.patch \
file://9001-PATCH-1-2-xHCI-MT7986-USB-2.0-USBIF-compliance-toolkit.patch \
file://9002-PATCH-1-1-usb-add-embedded-Host-feature-support.patch \
diff --git a/recipes-kernel/linux/linux-mediatek_5.4.bb b/recipes-kernel/linux/linux-mediatek_5.4.bb
index 06ca553..aecbc7d 100644
--- a/recipes-kernel/linux/linux-mediatek_5.4.bb
+++ b/recipes-kernel/linux/linux-mediatek_5.4.bb
@@ -7,8 +7,8 @@
KBRANCH ?= "linux-5.4.y"
-LINUX_VERSION ?= "5.4.215"
-SRCREV_machine ?= "6215647d9699cb8f1bf7333ec849242c4a9cf9a6"
+LINUX_VERSION ?= "5.4.219"
+SRCREV_machine ?= "fd92cfed8bc6668d314acd1e6da708a80826f768"
KMETA = "kernel-meta"
SRCREV_meta ?= "feeb59687bc0f054af837a5061f8d413ec7c93e9"