[rdkb][common][bsp][Refactor and sync kernel from openwrt]
[Description]
11f0341c [kernel][pinctrl][Backport spinlock for mtk_rmw]
eb40a7b4 [openwrt][mt7988][tops][Fix TCP not binding over L2TP/IPSec]
90df6779 [kernel][common][eth][Add a Ethernet passive Mux support]
979b8fbc [openwrt][mt7988][crypto][Add default enable upstream lookaside driver]
ced9d91c [openwrt][mt7988][tops][fix configuration typo]
648ba5b4 [MAC80211][hnat][Fix LAN/WAN software path low t-Put issue]
3190b596 [MAC80211][mt7986][hnat][Add hw configuration for PPE]
f807e962 [openwrt][mt7988][tops][update tops-tool default behavior]
83f9d770 [openwrt][mt7988][tops][split release and develop package]
f60f869c [openwrt][mt7988][crypto][prevent hnat bind UDP flow]
cadd001c [openwrt][mt7988][tops][prevent hnat bind UDP flow]
3174c47a [kernel][mt7988][eth][Add a link down recovery handler for the USXGMII]
405dbcd5 [openwrt][mt7988][tops: init skb_hnat_is_decrypt(skb)]
e8133606 [kernel][common][eth][Update Airoha EN8811H 2.5G PHY driver to v1.2.2]
6a9ef281 [openwrt][mt7988][tops: update firmware to support L2TP over IPsec]
f4508a0d [kernel][common][eth][Update gangload timeout mechanism for the Aquantia PHY driver]
5c8145fc [[openwrt][mt7988][config][GDM/GMAC FSM poll update]]
a4724176 [Kernel][hnat][Fix tport_id, tops_entry and cdrt_id in entry_detail]
f9ec3668 [kernel][common][eth][Update RX ring debug command]
f17a714b [openwrt][mt7988][tops][support L2TP/IPSec]
198a6450 [openwrt][mt7988][pce][support get CDRT index API]
6ac1fd75 [openwrt][mt7988][tops][tnl-offload: support with crypto-eip]
eccf181f [kernel][common][app][Fix coverity issue for the switch utility]
9a41e836 [kernel][misc][IPv4/IPv6 multicast]
6d5ef6d9 [openwrt][mt7988][tops][add cpu utilization fetching]
adbb1c6b [openwrt][mt7988][crypto-eip: update CLS API usage]
2c2bad81 [openwrt][mt7988][tops][separate CLS_ENTRY and TOPS_ENTRY dependency]
1c33e019 [openwrt][mt7988][pce][separate CLS entry definition from TOPS_ENTRY]
0c10c4bd [kernel][mt7988][emmc][platform.sh: Align upgrade script with mt7986's]
1dfa59c4 [MAC80211][hnat][Update 2.5G LAN/WAN low t-Put issue for the PPPQ]
4df6d59c [[openwrt][mt7986/81/88][config][lro ring id operate error]]
b7adb872 [openwrt][mt7988][eth][Fix coverity issue for Ethernet driver]
e172205a [openwrt][mt7988][crypto][EIP197 Alpha Release]
e6740a1e [openwrt][mt7988][arm64: dts: mt7988: add device tree node for eip197 inline mode]
3ec85b5c [openwrt][mt7988][crypto][EIP197 DDK Porting]
1af86bb6 [openwrt][mt7988][tops][fix coverity issue]
969c5b8b [MAC80211][wed][fix wed init fail issue]
97e18807 [MAC80211][hnat][Fix 2.5G LAN/WAN low t-Put issue for the PPPQ]
dce0053c [[openwrt][mt7986/81][config][allocate qdma dmad in dram instead of sram]]
5b358add [MAC80211][wed][repatch because apply patch error]
6d263a9d [openwrt][mt7988][tops][Fix conflict: empty line]
f46ad9a7 [Kernel][hnat][Fix ipv4 in ipv6 packets can't be bind in MAPE scene]
6e24e5fc [kernel][common][eth][Remove phylink set line rate to maximum]
1e4cffaf [openwrt][mt7988][tops][Add rate limit on QDMA queue]
c7f321d3 [MAC80211][wed][Change WARN_RATELIMIT to pr_err for wed ext interrupt]
[Release-log]
Change-Id: I0e6dcb33e6d94e5ea0e3887a0c14a54aa554e8a3
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 92b32c5..561450e 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
@@ -587,7 +587,8 @@
};
crypto: crypto@15600000 {
- compatible = "inside-secure,safexcel-eip197b";
+ compatible = "inside-secure,safexcel-eip197b",
+ "security-ip-197-srv";
reg = <0 0x15600000 0 0x180000>;
interrupts = <GIC_SPI 214 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 215 IRQ_TYPE_LEVEL_HIGH>,
@@ -595,6 +596,7 @@
<GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "ring0", "ring1", "ring2", "ring3";
status = "okay";
+ eth = <ð>;
};
afe: audio-controller@11210000 {
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 a1db345..e50e1ac 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
@@ -921,26 +921,30 @@
int rx_ring_read(struct seq_file *seq, void *v)
{
struct mtk_eth *eth = g_eth;
- struct mtk_rx_ring *ring = &g_eth->rx_ring[0];
+ struct mtk_rx_ring *ring;
struct mtk_rx_dma_v2 *rx_ring;
- int i = 0;
+ int i = 0, j = 0;
- seq_printf(seq, "next to read: %d\n",
- NEXT_DESP_IDX(ring->calc_idx, MTK_DMA_SIZE));
- for (i = 0; i < MTK_DMA_SIZE; i++) {
- rx_ring = ring->dma + i * eth->soc->txrx.rxd_size;
+ for (j = 0; j < MTK_RX_NAPI_NUM; j++) {
+ ring = &g_eth->rx_ring[j];
- seq_printf(seq, "%d: %08x %08x %08x %08x", i,
- rx_ring->rxd1, rx_ring->rxd2,
- rx_ring->rxd3, rx_ring->rxd4);
+ seq_printf(seq, "[Ring%d] next to read: %d\n", j,
+ NEXT_DESP_IDX(ring->calc_idx, MTK_DMA_SIZE));
+ for (i = 0; i < MTK_DMA_SIZE; i++) {
+ rx_ring = ring->dma + i * eth->soc->txrx.rxd_size;
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_RX_V2)) {
- seq_printf(seq, " %08x %08x %08x %08x",
- rx_ring->rxd5, rx_ring->rxd6,
- rx_ring->rxd7, rx_ring->rxd8);
- }
+ seq_printf(seq, "%d: %08x %08x %08x %08x", i,
+ rx_ring->rxd1, rx_ring->rxd2,
+ rx_ring->rxd3, rx_ring->rxd4);
- seq_printf(seq, "\n");
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_RX_V2)) {
+ seq_printf(seq, " %08x %08x %08x %08x",
+ rx_ring->rxd5, rx_ring->rxd6,
+ rx_ring->rxd7, rx_ring->rxd8);
+ }
+
+ seq_puts(seq, "\n");
+ }
}
return 0;
@@ -1782,7 +1786,7 @@
((reg_op1 >> MTK_LRO_RING_AGE_TIME_L_OFFSET) & 0x3ff);
seq_printf(seq,
"Ring[%d]: MAX_AGG_CNT=%d, AGG_TIME=%d, AGE_TIME=%d, Threshold=%d\n",
- (MTK_HAS_CAPS(g_eth->soc->caps, MTK_NETSYS_RX_V2)) ?
+ !(MTK_HAS_CAPS(g_eth->soc->caps, MTK_NETSYS_RX_V2)) ?
i : i+3,
agg_cnt, agg_time, age_time, reg_op4);
}
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 29630a8..b0cfc66 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -878,18 +878,26 @@
static int mtk_gdm_fsm_get(struct mtk_mac *mac, u32 gdm)
{
u32 fsm = mtk_r32(mac->hw, gdm);
- u32 ret = 0;
+ u32 ret = 0, val = 0;
- if (mac->type == MTK_GDM_TYPE)
+ switch (mac->type) {
+ case MTK_GDM_TYPE:
ret = fsm == 0;
- else if (mac->type == MTK_XGDM_TYPE) {
- if (mac->id == MTK_GMAC1_ID) {
- if (((fsm & 0x7ffffff) == 0) &&
- (mtk_r32(mac->hw, MTK_MAC_FSM(mac->id)) == 0x1010000))
- ret = 1;
+ break;
+ case MTK_XGDM_TYPE:
+ ret = fsm == 0x10000000;
+ break;
+ default:
+ break;
+ }
+
+ if ((mac->type == MTK_XGDM_TYPE) && (mac->id != MTK_GMAC1_ID)) {
+ val = mtk_r32(mac->hw, MTK_MAC_FSM(mac->id));
+ if ((val == 0x02010100) || (val == 0x01010100)) {
+ ret = (mac->interface == PHY_INTERFACE_MODE_XGMII) ?
+ ((fsm & 0x0fffffff) == 0) : ((fsm & 0x00ffffff) == 0);
} else
- ret = ((mac->interface == PHY_INTERFACE_MODE_XGMII) ?
- ((fsm & 0xfffffff) == 0) : ((fsm & 0x0ffffff) == 0));
+ ret = 0;
}
return ret;
@@ -913,7 +921,7 @@
pr_info("%s mac id invalid", __func__);
break;
}
- msleep(500);
+
while (i < 3) {
if (mtk_gdm_fsm_get(mac, gdm))
break;
@@ -927,7 +935,7 @@
static void mtk_pse_port_link_set(struct mtk_mac *mac, bool up)
{
- u32 fe_glo_cfg, val;
+ u32 fe_glo_cfg, val = 0;
fe_glo_cfg = mtk_r32(mac->hw, MTK_FE_GLO_CFG(mac->id));
switch (mac->id) {
@@ -956,6 +964,8 @@
{
struct mtk_mac *mac = container_of(config, struct mtk_mac,
phylink_config);
+ struct mtk_eth *eth = mac->hw;
+ unsigned int id;
u32 mcr, sts;
mtk_pse_port_link_set(mac, false);
@@ -964,8 +974,9 @@
mcr &= ~(MAC_MCR_TX_EN | MAC_MCR_RX_EN | MAC_MCR_FORCE_LINK);
mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id));
} else if (mac->type == MTK_XGDM_TYPE && mac->id != MTK_GMAC1_ID) {
- mcr = mtk_r32(mac->hw, MTK_XMAC_MCR(mac->id));
+ struct mtk_usxgmii_pcs *mpcs;
+ mcr = mtk_r32(mac->hw, MTK_XMAC_MCR(mac->id));
mcr &= 0xfffffff0;
mcr |= XMAC_MCR_TRX_DISABLE;
mtk_w32(mac->hw, mcr, MTK_XMAC_MCR(mac->id));
@@ -973,6 +984,10 @@
sts = mtk_r32(mac->hw, MTK_XGMAC_STS(mac->id));
sts &= ~MTK_XGMAC_FORCE_LINK(mac->id);
mtk_w32(mac->hw, sts, MTK_XGMAC_STS(mac->id));
+
+ id = mtk_mac2xgmii_id(eth, mac->id);
+ mpcs = ð->usxgmii->pcs[id];
+ cancel_delayed_work_sync(&mpcs->link_poll);
}
}
@@ -3345,7 +3360,7 @@
if (eth->hwlro) {
mtk_hwlro_rx_uninit(eth);
- i = (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V1)) ? 1 : 4;
+ i = (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_RX_V2)) ? 4 : 1;
for (; i < MTK_MAX_RX_RING_NUM; i++)
mtk_rx_clean(eth, ð->rx_ring[i], 0);
}
@@ -4560,6 +4575,151 @@
#endif
};
+static void mux_poll(struct work_struct *work)
+{
+ struct mtk_mux *mux = container_of(work, struct mtk_mux, poll.work);
+ struct mtk_mac *mac = mux->mac;
+ struct mtk_eth *eth = mac->hw;
+ struct net_device *dev = eth->netdev[mac->id];
+ unsigned int channel;
+
+ if (IS_ERR(mux->gpio[0]) || IS_ERR(mux->gpio[1]))
+ goto exit;
+
+ channel = gpiod_get_value_cansleep(mux->gpio[0]);
+ if (mux->channel == channel || !netif_running(dev))
+ goto exit;
+
+ rtnl_lock();
+
+ mtk_stop(dev);
+
+ if (channel == 0 || channel == 1) {
+ mac->of_node = mux->data[channel]->of_node;
+ mac->phylink = mux->data[channel]->phylink;
+ };
+
+ dev_info(eth->dev, "ethernet mux: switch to channel%d\n", channel);
+
+ gpiod_set_value_cansleep(mux->gpio[1], channel);
+
+ mtk_open(dev);
+
+ rtnl_unlock();
+
+ mux->channel = channel;
+
+exit:
+ mod_delayed_work(system_wq, &mux->poll, msecs_to_jiffies(100));
+}
+
+static int mtk_add_mux_channel(struct mtk_mux *mux, struct device_node *np)
+{
+ const __be32 *_id = of_get_property(np, "reg", NULL);
+ struct mtk_mac *mac = mux->mac;
+ struct mtk_eth *eth = mac->hw;
+ struct mtk_mux_data *data;
+ struct phylink *phylink;
+ int phy_mode, id;
+
+ if (!_id) {
+ dev_err(eth->dev, "missing mux channel id\n");
+ return -EINVAL;
+ }
+
+ id = be32_to_cpup(_id);
+ if (id < 0 || id > 1) {
+ dev_err(eth->dev, "%d is not a valid mux channel id\n", id);
+ return -EINVAL;
+ }
+
+ data = kmalloc(sizeof(*data), GFP_KERNEL);
+ if (unlikely(!data)) {
+ dev_err(eth->dev, "failed to create mux data structure\n");
+ return -ENOMEM;
+ }
+
+ mux->data[id] = data;
+
+ /* phylink create */
+ phy_mode = of_get_phy_mode(np);
+ if (phy_mode < 0) {
+ dev_err(eth->dev, "incorrect phy-mode\n");
+ return -EINVAL;
+ }
+
+ phylink = phylink_create(&mux->mac->phylink_config,
+ of_fwnode_handle(np),
+ phy_mode, &mtk_phylink_ops);
+ if (IS_ERR(phylink)) {
+ dev_err(eth->dev, "failed to create phylink structure\n");
+ return PTR_ERR(phylink);
+ }
+
+ data->of_node = np;
+ data->phylink = phylink;
+
+ return 0;
+}
+
+static int mtk_add_mux(struct mtk_eth *eth, struct device_node *np)
+{
+ const __be32 *_id = of_get_property(np, "reg", NULL);
+ struct device_node *child;
+ struct mtk_mux *mux;
+ unsigned int id;
+ int err;
+
+ if (!_id) {
+ dev_err(eth->dev, "missing attach mac id\n");
+ return -EINVAL;
+ }
+
+ id = be32_to_cpup(_id);
+ if (id < 0 || id >= MTK_MAX_DEVS) {
+ dev_err(eth->dev, "%d is not a valid attach mac id\n", id);
+ return -EINVAL;
+ }
+
+ mux = kmalloc(sizeof(struct mtk_mux), GFP_KERNEL);
+ if (unlikely(!mux)) {
+ dev_err(eth->dev, "failed to create mux structure\n");
+ return -ENOMEM;
+ }
+
+ eth->mux[id] = mux;
+
+ mux->mac = eth->mac[id];
+ mux->channel = 0;
+
+ mux->gpio[0] = fwnode_get_named_gpiod(of_fwnode_handle(np),
+ "mod-def0-gpios", 0,
+ GPIOD_IN, "?");
+ if (IS_ERR(mux->gpio[0]))
+ dev_err(eth->dev, "failed to requset gpio for mod-def0-gpios\n");
+
+ mux->gpio[1] = fwnode_get_named_gpiod(of_fwnode_handle(np),
+ "chan-sel-gpios", 0,
+ GPIOD_OUT_LOW, "?");
+ if (IS_ERR(mux->gpio[1]))
+ dev_err(eth->dev, "failed to requset gpio for chan-sel-gpios\n");
+
+ for_each_child_of_node(np, child) {
+ err = mtk_add_mux_channel(mux, child);
+ if (err) {
+ dev_err(eth->dev, "failed to add mtk_mux\n");
+ of_node_put(child);
+ return -ECHILD;
+ }
+ of_node_put(child);
+ }
+
+ INIT_DELAYED_WORK(&mux->poll, mux_poll);
+ mod_delayed_work(system_wq, &mux->poll, msecs_to_jiffies(3000));
+
+ return 0;
+}
+
static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
{
const __be32 *_id = of_get_property(np, "reg", NULL);
@@ -4757,7 +4917,7 @@
static int mtk_probe(struct platform_device *pdev)
{
- struct device_node *mac_np;
+ struct device_node *mac_np, *mux_np;
struct mtk_eth *eth;
int err, i;
@@ -4928,6 +5088,26 @@
}
}
+ mux_np = of_get_child_by_name(eth->dev->of_node, "mux-bus");
+ if (mux_np) {
+ struct device_node *child;
+
+ for_each_available_child_of_node(mux_np, child) {
+ if (!of_device_is_compatible(child,
+ "mediatek,eth-mux"))
+ continue;
+
+ if (!of_device_is_available(child))
+ continue;
+
+ err = mtk_add_mux(eth, child);
+ if (err)
+ dev_err(&pdev->dev, "failed to add mux\n");
+
+ of_node_put(mux_np);
+ };
+ }
+
err = mtk_napi_init(eth);
if (err)
goto err_free_dev;
@@ -5158,7 +5338,7 @@
.hw_features = MTK_HW_FEATURES,
.required_clks = MT7986_CLKS_BITMAP,
.required_pctl = false,
- .has_sram = true,
+ .has_sram = false,
.rss_num = 0,
.txrx = {
.txd_size = sizeof(struct mtk_tx_dma_v2),
@@ -5176,7 +5356,7 @@
.hw_features = MTK_HW_FEATURES,
.required_clks = MT7981_CLKS_BITMAP,
.required_pctl = false,
- .has_sram = true,
+ .has_sram = false,
.rss_num = 0,
.txrx = {
.txd_size = sizeof(struct mtk_tx_dma_v2),
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
old mode 100755
new mode 100644
index f87635c..88df3b2
--- 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
@@ -945,6 +945,11 @@
#define USXGMII_LPA_LINK BIT(15)
#define USXGMII_LPA_LATCH BIT(31)
+/* Register to read PCS Link status */
+#define RG_PCS_RX_STATUS0 0x904
+#define RG_PCS_RX_STATUS_UPDATE BIT(16)
+#define RG_PCS_RX_LINK_STATUS BIT(2)
+
/* Register to control USXGMII XFI PLL digital */
#define XFI_PLL_DIG_GLB8 0x08
#define RG_XFI_PLL_EN BIT(31)
@@ -1035,6 +1040,7 @@
struct mtk_eth;
struct mtk_mac;
+struct mtk_mux;
/* struct mtk_hw_stats - the structure that holds the traffic statistics.
* @stats_lock: make sure that stats operations are atomic
@@ -1715,7 +1721,9 @@
struct mtk_eth *eth;
struct regmap *regmap;
struct regmap *regmap_pextp;
+ struct delayed_work link_poll;
phy_interface_t interface;
+ unsigned int mode;
u8 id;
struct phylink_pcs pcs;
};
@@ -1801,6 +1809,7 @@
struct net_device dummy_dev;
struct net_device *netdev[MTK_MAX_DEVS];
struct mtk_mac *mac[MTK_MAX_DEVS];
+ struct mtk_mux *mux[MTK_MAX_DEVS];
int irq_fe[MTK_FE_IRQ_NUM];
int irq_pdma[MTK_PDMA_IRQ_NUM];
u8 hwver;
@@ -1865,6 +1874,25 @@
u32 tx_lpi_timer;
};
+/* struct mtk_mux_data - the structure that holds the private data about the
+ * Passive MUXs of the SoC
+ */
+struct mtk_mux_data {
+ struct device_node *of_node;
+ struct phylink *phylink;
+};
+
+/* struct mtk_mux - the structure that holds the info about the Passive MUXs of the
+ * SoC
+ */
+struct mtk_mux {
+ struct delayed_work poll;
+ struct gpio_desc *gpio[2];
+ struct mtk_mux_data *data[2];
+ struct mtk_mac *mac;
+ unsigned int channel;
+};
+
/* the struct describing the SoC. these are declared in the soc_xyz.c files */
extern struct mtk_eth *g_eth;
extern const struct of_device_id of_mtk_match[];
@@ -1895,6 +1923,7 @@
int mtk_usxgmii_init(struct mtk_eth *eth, struct device_node *r);
int mtk_toprgu_init(struct mtk_eth *eth, struct device_node *r);
int mtk_dump_usxgmii(struct regmap *pmap, char *name, u32 offset, u32 range);
+void mtk_usxgmii_link_poll(struct work_struct *work);
void mtk_eth_set_dma_device(struct mtk_eth *eth, struct device *dma_dev);
u32 mtk_rss_indr_table(struct mtk_rss_params *rss_params, int index);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c
index 96d446e..f648386 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c
@@ -371,7 +371,11 @@
pr_info("==========<PPE_ID=%d, Flow Table Entry=%d (%p)>===============\n",
ppe_id, index, entry);
if (debug_level >= 2) {
- print_cnt = 20;
+ if (hnat_priv->data->version == MTK_HNAT_V3)
+ print_cnt = 28;
+ else
+ print_cnt = 20;
+
for (i = 0; i < print_cnt; i++)
pr_info("%02d: %08X\n", i, *(p + i));
}
@@ -619,10 +623,23 @@
"TCP" : entry->ipv6_5t_route.bfib1.udp == 1 ?
"UDP" : "Unknown");
#if defined(CONFIG_MEDIATEK_NETSYS_V3)
- pr_info("tport_id = %d, tops_entry = %d, cdrt_id = %d\n",
- entry->ipv6_5t_route.tport_id,
- entry->ipv6_5t_route.tops_entry,
- entry->ipv6_5t_route.cdrt_id);
+ if (IS_IPV6_HNAT(entry) || IS_IPV6_HNAPT(entry)) {
+ pr_info("tport_id = %d, tops_entry = %d, cdrt_id = %d\n",
+ entry->ipv6_hnapt.tport_id,
+ entry->ipv6_hnapt.tops_entry,
+ entry->ipv6_hnapt.cdrt_id);
+
+ } else if (IS_IPV4_MAPE(entry) || IS_IPV4_MAPT(entry)) {
+ pr_info("tport_id = %d, tops_entry = %d, cdrt_id = %d\n",
+ entry->ipv4_mape.tport_id,
+ entry->ipv4_mape.tops_entry,
+ entry->ipv4_mape.cdrt_id);
+ } else {
+ pr_info("tport_id = %d, tops_entry = %d, cdrt_id = %d\n",
+ entry->ipv6_5t_route.tport_id,
+ entry->ipv6_5t_route.tops_entry,
+ entry->ipv6_5t_route.cdrt_id);
+ }
#endif
pr_info("=========================================\n\n");
}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
index 31c03ca..d34ac9d 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
@@ -1246,6 +1246,10 @@
switch (ntohs(eth->h_proto)) {
case ETH_P_IP:
iph = ip_hdr(skb);
+ /* Do not bind if pkt is fragmented */
+ if (ip_is_fragment(iph))
+ return 0;
+
switch (iph->protocol) {
case IPPROTO_UDP:
udp = 1;
@@ -2521,10 +2525,6 @@
if (unlikely(!skb_hnat_is_hashed(skb)))
return 0;
- /* Do not bind if pkt is fragmented */
- if (ip_is_fragment(ip_hdr(skb)))
- return 0;
-
if (out->netdev_ops->ndo_flow_offload_check) {
out->netdev_ops->ndo_flow_offload_check(&hw_path);
out = (IS_GMAC1_MODE) ? hw_path.virt_dev : hw_path.dev;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_usxgmii.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_usxgmii.c
index a181fc2..0cadc85 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_usxgmii.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_usxgmii.c
@@ -468,6 +468,25 @@
udelay(400);
}
+int mtk_usxgmii_link_status(struct mtk_usxgmii_pcs *mpcs)
+{
+ unsigned int val;
+
+ /* Refresh USXGMII link status by toggling RG_PCS_RX_STATUS_UPDATE */
+ regmap_read(mpcs->regmap, RG_PCS_RX_STATUS0, &val);
+ val |= RG_PCS_RX_STATUS_UPDATE;
+ regmap_write(mpcs->regmap, RG_PCS_RX_STATUS0, val);
+
+ regmap_read(mpcs->regmap, RG_PCS_RX_STATUS0, &val);
+ val &= ~RG_PCS_RX_STATUS_UPDATE;
+ regmap_write(mpcs->regmap, RG_PCS_RX_STATUS0, val);
+
+ /* Read USXGMII link status */
+ regmap_read(mpcs->regmap, RG_PCS_RX_STATUS0, &val);
+
+ return FIELD_GET(RG_PCS_RX_LINK_STATUS, val);
+}
+
void mtk_usxgmii_reset(struct mtk_eth *eth, int id)
{
u32 val = 0;
@@ -580,6 +599,7 @@
if (mpcs->interface != interface) {
mpcs->interface = interface;
+ mpcs->mode = mode;
mode_changed = true;
}
@@ -725,15 +745,34 @@
regmap_write(mpcs->regmap, RG_PCS_AN_CTRL0, val);
}
+void mtk_usxgmii_link_poll(struct work_struct *work)
+{
+ struct delayed_work *dwork = to_delayed_work(work);
+ struct mtk_usxgmii_pcs *mpcs = container_of(dwork, struct mtk_usxgmii_pcs, link_poll);
+
+ if (!mtk_usxgmii_link_status(mpcs)) {
+ mtk_usxgmii_pcs_config(&mpcs->pcs, mpcs->mode,
+ mpcs->interface, NULL, false);
+
+ queue_delayed_work(system_power_efficient_wq, &mpcs->link_poll,
+ msecs_to_jiffies(1000));
+ }
+}
+
static void mtk_usxgmii_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode,
phy_interface_t interface,
int speed, int duplex)
{
+ struct mtk_usxgmii_pcs *mpcs = pcs_to_mtk_usxgmii_pcs(pcs);
+
/* Reconfiguring USXGMII to ensure the quality of the RX signal
* after the line side link up.
*/
mtk_usxgmii_pcs_config(pcs, mode,
interface, NULL, false);
+
+ queue_delayed_work(system_power_efficient_wq, &mpcs->link_poll,
+ msecs_to_jiffies(1000));
}
static const struct phylink_pcs_ops mtk_usxgmii_pcs_ops = {
@@ -765,6 +804,8 @@
ss->pcs[i].pcs.poll = true;
ss->pcs[i].interface = PHY_INTERFACE_MODE_NA;
+ INIT_DELAYED_WORK(&ss->pcs[i].link_poll, mtk_usxgmii_link_poll);
+
of_node_put(np);
}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/air_en8811h.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/air_en8811h.h
new file mode 100644
index 0000000..6a0afaf
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/air_en8811h.h
@@ -0,0 +1,144 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*************************************************
+ * FILE NAME: air_en8811h.h
+ * PURPOSE:
+ * EN8811H PHY Driver for Linux
+ * NOTES:
+ *
+ * Copyright (C) 2023 Airoha Technology Corp.
+ *************************************************/
+#ifndef __EN8811H_H
+#define __EN8811H_H
+
+#define EN8811H_MD32_DM "EthMD32.dm.bin"
+#define EN8811H_MD32_DSP "EthMD32.DSP.bin"
+
+#define EN8811H_PHY_ID1 0x03a2
+#define EN8811H_PHY_ID2 0xa411
+#define EN8811H_PHY_ID ((EN8811H_PHY_ID1 << 16) | EN8811H_PHY_ID2)
+#define EN8811H_PHY_READY 0x02
+#define MAX_RETRY 25
+
+#define EN8811H_TX_POL_NORMAL 0x1
+#define EN8811H_TX_POL_REVERSE 0x0
+
+#define EN8811H_RX_POL_NORMAL (0x0 << 1)
+#define EN8811H_RX_POL_REVERSE (0x1 << 1)
+
+
+/***************************************************************
+ * The following led_cfg example is for reference only.
+ * LED0 Link 2500/Blink 2500 TxRx (GPIO5) <-> BASE_T_LED0,
+ * LED1 Link 1000/Blink 1000 TxRx (GPIO4) <-> BASE_T_LED1,
+ * LED2 Link 100 /Blink 100 TxRx (GPIO3) <-> BASE_T_LED2,
+ ***************************************************************/
+/* User-defined.B */
+#define AIR_LED0_ON (LED_ON_EVT_LINK_2500M)
+#define AIR_LED0_BLK (LED_BLK_EVT_2500M_TX_ACT | LED_BLK_EVT_2500M_RX_ACT)
+#define AIR_LED1_ON (LED_ON_EVT_LINK_1000M)
+#define AIR_LED1_BLK (LED_BLK_EVT_1000M_TX_ACT | LED_BLK_EVT_1000M_RX_ACT)
+#define AIR_LED2_ON (LED_ON_EVT_LINK_100M)
+#define AIR_LED2_BLK (LED_BLK_EVT_100M_TX_ACT | LED_BLK_EVT_100M_RX_ACT)
+/* User-defined.E */
+
+/* CL45 MDIO control */
+#define MII_MMD_ACC_CTL_REG 0x0d
+#define MII_MMD_ADDR_DATA_REG 0x0e
+#define MMD_OP_MODE_DATA BIT(14)
+
+#define EN8811H_DRIVER_VERSION "v1.2.2"
+
+#define LED_ON_CTRL(i) (0x024 + ((i)*2))
+#define LED_ON_EN (1 << 15)
+#define LED_ON_POL (1 << 14)
+#define LED_ON_EVT_MASK (0x1ff)
+/* LED ON Event Option.B */
+#define LED_ON_EVT_LINK_2500M (1 << 8)
+#define LED_ON_EVT_FORCE (1 << 6)
+#define LED_ON_EVT_LINK_DOWN (1 << 3)
+#define LED_ON_EVT_LINK_100M (1 << 1)
+#define LED_ON_EVT_LINK_1000M (1 << 0)
+/* LED ON Event Option.E */
+
+#define LED_BLK_CTRL(i) (0x025 + ((i)*2))
+#define LED_BLK_EVT_MASK (0xfff)
+/* LED Blinking Event Option.B*/
+#define LED_BLK_EVT_2500M_RX_ACT (1 << 11)
+#define LED_BLK_EVT_2500M_TX_ACT (1 << 10)
+#define LED_BLK_EVT_FORCE (1 << 9)
+#define LED_BLK_EVT_100M_RX_ACT (1 << 3)
+#define LED_BLK_EVT_100M_TX_ACT (1 << 2)
+#define LED_BLK_EVT_1000M_RX_ACT (1 << 1)
+#define LED_BLK_EVT_1000M_TX_ACT (1 << 0)
+/* LED Blinking Event Option.E*/
+#define EN8811H_LED_COUNT 3
+
+#define LED_BCR (0x021)
+#define LED_BCR_EXT_CTRL (1 << 15)
+#define LED_BCR_CLK_EN (1 << 3)
+#define LED_BCR_TIME_TEST (1 << 2)
+#define LED_BCR_MODE_MASK (3)
+#define LED_BCR_MODE_DISABLE (0)
+
+#define LED_ON_DUR (0x022)
+#define LED_ON_DUR_MASK (0xffff)
+
+#define LED_BLK_DUR (0x023)
+#define LED_BLK_DUR_MASK (0xffff)
+
+#define UNIT_LED_BLINK_DURATION 1024
+
+#define GET_BIT(val, bit) ((val & BIT(bit)) >> bit)
+
+#define INVALID_DATA 0xffff
+#define PBUS_INVALID_DATA 0xffffffff
+
+struct en8811h_priv {
+ struct dentry *debugfs_root;
+ unsigned int dm_crc32;
+ unsigned int dsp_crc32;
+ char buf[512];
+};
+
+struct air_base_t_led_cfg {
+ u16 en;
+ u16 gpio;
+ u16 pol;
+ u16 on_cfg;
+ u16 blk_cfg;
+};
+enum air_led_gpio {
+ AIR_LED2_GPIO3 = 3,
+ AIR_LED1_GPIO4,
+ AIR_LED0_GPIO5,
+ AIR_LED_LAST
+};
+
+enum air_base_t_led {
+ AIR_BASE_T_LED0,
+ AIR_BASE_T_LED1,
+ AIR_BASE_T_LED2,
+ AIR_BASE_T_LED3
+};
+
+enum air_led_blk_dur {
+ AIR_LED_BLK_DUR_32M,
+ AIR_LED_BLK_DUR_64M,
+ AIR_LED_BLK_DUR_128M,
+ AIR_LED_BLK_DUR_256M,
+ AIR_LED_BLK_DUR_512M,
+ AIR_LED_BLK_DUR_1024M,
+ AIR_LED_BLK_DUR_LAST
+};
+
+enum air_led_polarity {
+ AIR_ACTIVE_LOW,
+ AIR_ACTIVE_HIGH,
+};
+enum air_led_mode {
+ AIR_LED_MODE_DISABLE,
+ AIR_LED_MODE_USER_DEFINE,
+ AIR_LED_MODE_LAST
+};
+
+#endif /* End of __EN8811H_H */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/air_en8811h_api.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/air_en8811h_api.c
new file mode 100644
index 0000000..731a37d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/air_en8811h_api.c
@@ -0,0 +1,1227 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*************************************************
+ * FILE NAME: air_en8811h_api.c
+ * PURPOSE:
+ * EN8811H PHY Driver for Linux
+ * NOTES:
+ *
+ * Copyright (C) 2023 Airoha Technology Corp.
+ *************************************************/
+
+/* INCLUDE FILE DECLARATIONS
+*/
+#include <linux/uaccess.h>
+#include <linux/trace_seq.h>
+#include <linux/seq_file.h>
+#include <linux/u64_stats_sync.h>
+#include <linux/dma-mapping.h>
+#include <linux/netdevice.h>
+#include <linux/ctype.h>
+#include <linux/of_mdio.h>
+#include <linux/of_address.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+#include <linux/debugfs.h>
+
+#include "air_en8811h.h"
+#include "air_en8811h_api.h"
+
+/*
+struct air_phy_debug {
+ struct dentry *root;
+};
+struct air_phy_debug air_debug;
+*/
+
+static const char * const tx_rx_string[32] = {
+ "Tx Reverse, Rx Normal",
+ "Tx Normal, Rx Normal",
+ "Tx Reverse, Rx Reverse",
+ "Tx Normal, Rx Reverse",
+};
+
+/* Airoha MII read function */
+static int __air_mii_cl22_read(struct mii_bus *ebus,
+ int addr, unsigned int phy_register)
+{
+ int read_data;
+#if (KERNEL_VERSION(4, 16, 0) < LINUX_VERSION_CODE)
+ read_data = __mdiobus_read(ebus, addr, phy_register);
+#else
+ read_data = ebus->read(ebus, addr, phy_register);
+#endif
+ return read_data;
+}
+/* Airoha MII write function */
+static int __air_mii_cl22_write(struct mii_bus *ebus, int addr,
+ unsigned int phy_register, unsigned int write_data)
+{
+ int ret = 0;
+#if (KERNEL_VERSION(4, 16, 0) < LINUX_VERSION_CODE)
+ ret = __mdiobus_write(ebus, addr, phy_register, write_data);
+#else
+ ret = ebus->write(ebus, addr, phy_register, write_data);
+#endif
+ return ret;
+}
+
+/* Airoha MII read function */
+int air_mii_cl22_read(struct mii_bus *ebus, int addr, unsigned int phy_register)
+{
+ int read_data;
+
+ mutex_lock(&ebus->mdio_lock);
+ read_data = __air_mii_cl22_read(ebus, addr, phy_register);
+ mutex_unlock(&ebus->mdio_lock);
+ return read_data;
+}
+/* Airoha MII write function */
+int air_mii_cl22_write(struct mii_bus *ebus, int addr,
+ unsigned int phy_register, unsigned int write_data)
+{
+ int ret = 0;
+
+ mutex_lock(&ebus->mdio_lock);
+ ret = __air_mii_cl22_write(ebus, addr, phy_register, write_data);
+ mutex_unlock(&ebus->mdio_lock);
+ return ret;
+}
+
+static int __air_mii_cl45_read(struct phy_device *phydev, int devad, u16 reg)
+{
+ int ret = 0;
+ int data;
+ struct device *dev = phydev_dev(phydev);
+ struct mii_bus *mbus = phydev_mdio_bus(phydev);
+ int addr = phydev_addr(phydev);
+
+ ret |= __air_mii_cl22_write(mbus, addr, MII_MMD_ACC_CTL_REG, devad);
+ ret |= __air_mii_cl22_write(mbus, addr, MII_MMD_ADDR_DATA_REG, reg);
+ ret |= __air_mii_cl22_write(mbus, addr,
+ MII_MMD_ACC_CTL_REG, MMD_OP_MODE_DATA | devad);
+ if (ret) {
+ dev_err(dev, "__air_mii_cl22_write, ret: %d\n", ret);
+ return INVALID_DATA;
+ }
+ data = __air_mii_cl22_read(mbus, addr, MII_MMD_ADDR_DATA_REG);
+ return data;
+}
+
+static int __air_mii_cl45_write(struct phy_device *phydev,
+ int devad, u16 reg, u16 write_data)
+{
+ int ret = 0;
+ struct device *dev = phydev_dev(phydev);
+ struct mii_bus *mbus = phydev_mdio_bus(phydev);
+ int addr = phydev_addr(phydev);
+
+ ret |= __air_mii_cl22_write(mbus, addr, MII_MMD_ACC_CTL_REG, devad);
+ ret |= __air_mii_cl22_write(mbus, addr, MII_MMD_ADDR_DATA_REG, reg);
+ ret |= __air_mii_cl22_write(mbus, addr,
+ MII_MMD_ACC_CTL_REG, MMD_OP_MODE_DATA | devad);
+ ret |= __air_mii_cl22_write(mbus, addr,
+ MII_MMD_ADDR_DATA_REG, write_data);
+ if (ret) {
+ dev_err(dev, "__air_mii_cl22_write, ret: %d\n", ret);
+ return ret;
+ }
+ return 0;
+}
+
+int air_mii_cl45_read(struct phy_device *phydev, int devad, u16 reg)
+{
+ int data;
+ struct device *dev = phydev_dev(phydev);
+ struct mii_bus *mbus = phydev_mdio_bus(phydev);
+
+ mutex_lock(&mbus->mdio_lock);
+ data = __air_mii_cl45_read(phydev, devad, reg);
+ mutex_unlock(&mbus->mdio_lock);
+ if (data == INVALID_DATA) {
+ dev_err(dev, "__airoha_cl45_read fail\n");
+ return INVALID_DATA;
+ }
+ return data;
+}
+
+int air_mii_cl45_write(struct phy_device *phydev,
+ int devad, u16 reg, u16 write_data)
+{
+ int ret = 0;
+ struct device *dev = phydev_dev(phydev);
+ struct mii_bus *mbus = phydev_mdio_bus(phydev);
+
+ mutex_lock(&mbus->mdio_lock);
+ ret |= __air_mii_cl45_write(phydev, devad, reg, write_data);
+ mutex_unlock(&mbus->mdio_lock);
+ if (ret) {
+ dev_err(dev, "__airoha_cl45_write, ret: %d\n", ret);
+ return ret;
+ }
+ return ret;
+}
+
+/* EN8811H PBUS read function */
+static unsigned int __air_pbus_reg_read(struct phy_device *phydev,
+ unsigned int pbus_address)
+{
+ struct mii_bus *mbus = phydev_mdio_bus(phydev);
+ int addr = phydev_addr(phydev);
+ struct device *dev = phydev_dev(phydev);
+ unsigned int pbus_data_low, pbus_data_high;
+ unsigned int pbus_data;
+ int ret = 0;
+
+ ret |= __air_mii_cl22_write(mbus, (addr + 8),
+ 0x1F, (pbus_address >> 6));
+ pbus_data_low = __air_mii_cl22_read(mbus, (addr + 8),
+ ((pbus_address >> 2) & 0xf));
+ pbus_data_high = __air_mii_cl22_read(mbus, (addr + 8), 0x10);
+ pbus_data = (pbus_data_high << 16) + pbus_data_low;
+ if (ret) {
+ dev_err(dev, "%s: ret: %d\n", __func__, ret);
+ return ret;
+ }
+ return pbus_data;
+}
+
+unsigned int air_pbus_reg_read(struct phy_device *phydev,
+ unsigned int pbus_address)
+{
+ struct mii_bus *mbus = phydev_mdio_bus(phydev);
+ struct device *dev = phydev_dev(phydev);
+ int ret = 0;
+ unsigned int data;
+
+ mutex_lock(&mbus->mdio_lock);
+ data = __air_pbus_reg_read(phydev, pbus_address);
+ mutex_unlock(&mbus->mdio_lock);
+ if (ret) {
+ dev_err(dev, "%s: ret: %d\n", __func__, ret);
+ return ret;
+ }
+ return data;
+}
+
+/* EN8811H PBUS write function */
+static int __air_pbus_reg_write(struct phy_device *phydev,
+ unsigned int pbus_address, unsigned long pbus_data)
+{
+ struct mii_bus *mbus = phydev_mdio_bus(phydev);
+ int addr = phydev_addr(phydev);
+ struct device *dev = phydev_dev(phydev);
+ int ret = 0;
+
+ ret |= __air_mii_cl22_write(mbus, (addr + 8),
+ 0x1F, (pbus_address >> 6));
+ ret |= __air_mii_cl22_write(mbus, (addr + 8),
+ ((pbus_address >> 2) & 0xf), (pbus_data & 0xFFFF));
+ ret |= __air_mii_cl22_write(mbus, (addr + 8),
+ 0x10, (pbus_data >> 16));
+ if (ret) {
+ dev_err(dev, "%s: ret: %d\n", __func__, ret);
+ return ret;
+ }
+ return 0;
+}
+
+int air_pbus_reg_write(struct phy_device *phydev,
+ unsigned int pbus_address, unsigned int pbus_data)
+{
+ struct mii_bus *mbus = phydev_mdio_bus(phydev);
+ struct device *dev = phydev_dev(phydev);
+ int ret = 0;
+
+ mutex_lock(&mbus->mdio_lock);
+ ret |= __air_pbus_reg_write(phydev, pbus_address, pbus_data);
+ mutex_unlock(&mbus->mdio_lock);
+ if (ret) {
+ dev_err(dev, "%s: ret: %d\n", __func__, ret);
+ return ret;
+ }
+ return 0;
+}
+/* EN8811H BUCK write function */
+static int __air_buckpbus_reg_write(struct phy_device *phydev,
+ unsigned int pbus_address, unsigned int pbus_data)
+{
+ int ret = 0;
+ struct device *dev = phydev_dev(phydev);
+ struct mii_bus *mbus = phydev_mdio_bus(phydev);
+ int addr = phydev_addr(phydev);
+
+ /* page 4 */
+ ret |= __air_mii_cl22_write(mbus, addr, 0x1F, 4);
+ ret |= __air_mii_cl22_write(mbus, addr, 0x10, 0);
+ ret |= __air_mii_cl22_write(mbus, addr,
+ 0x11, ((pbus_address >> 16) & 0xffff));
+ ret |= __air_mii_cl22_write(mbus, addr,
+ 0x12, (pbus_address & 0xffff));
+ ret |= __air_mii_cl22_write(mbus, addr,
+ 0x13, ((pbus_data >> 16) & 0xffff));
+ ret |= __air_mii_cl22_write(mbus, addr, 0x14, (pbus_data & 0xffff));
+ ret |= __air_mii_cl22_write(mbus, addr, 0x1F, 0);
+ if (ret < 0) {
+ dev_err(dev, "__air_mii_cl22_write, ret: %d\n", ret);
+ return ret;
+ }
+ return 0;
+}
+
+/* EN8811H BUCK read function */
+static unsigned int __air_buckpbus_reg_read(struct phy_device *phydev,
+ unsigned int pbus_address)
+{
+ unsigned int pbus_data = 0, pbus_data_low, pbus_data_high;
+ int ret = 0;
+ struct device *dev = phydev_dev(phydev);
+ struct mii_bus *mbus = phydev_mdio_bus(phydev);
+ int addr = phydev_addr(phydev);
+
+ /* page 4 */
+ ret |= __air_mii_cl22_write(mbus, addr, 0x1F, 4);
+ ret |= __air_mii_cl22_write(mbus, addr, 0x10, 0);
+ ret |= __air_mii_cl22_write(mbus, addr,
+ 0x15, ((pbus_address >> 16) & 0xffff));
+ ret |= __air_mii_cl22_write(mbus, addr,
+ 0x16, (pbus_address & 0xffff));
+ if (ret) {
+ dev_err(dev, "__air_mii_cl22_write, ret: %d\n", ret);
+ return PBUS_INVALID_DATA;
+ }
+
+ pbus_data_high = __air_mii_cl22_read(mbus, addr, 0x17);
+ pbus_data_low = __air_mii_cl22_read(mbus, addr, 0x18);
+ pbus_data = (pbus_data_high << 16) + pbus_data_low;
+ ret |= __air_mii_cl22_write(mbus, addr, 0x1F, 0);
+ if (ret) {
+ dev_err(dev, "__air_mii_cl22_write, ret: %d\n", ret);
+ return ret;
+ }
+ return pbus_data;
+}
+
+unsigned int air_buckpbus_reg_read(struct phy_device *phydev,
+ unsigned int pbus_address)
+{
+ unsigned int data;
+ struct device *dev = phydev_dev(phydev);
+ struct mii_bus *mbus = phydev_mdio_bus(phydev);
+
+ mutex_lock(&mbus->mdio_lock);
+ data = __air_buckpbus_reg_read(phydev, pbus_address);
+ mutex_unlock(&mbus->mdio_lock);
+ if (data == INVALID_DATA) {
+ dev_err(dev, "__air_buckpbus_reg_read fail\n");
+ return INVALID_DATA;
+ }
+ return data;
+}
+
+int air_buckpbus_reg_write(struct phy_device *phydev,
+ unsigned int pbus_address, unsigned int pbus_data)
+{
+ int ret = 0;
+ struct device *dev = phydev_dev(phydev);
+ struct mii_bus *mbus = phydev_mdio_bus(phydev);
+
+ mutex_lock(&mbus->mdio_lock);
+ ret |= __air_buckpbus_reg_write(phydev, pbus_address, pbus_data);
+ mutex_unlock(&mbus->mdio_lock);
+ if (ret) {
+ dev_err(dev, "__air_buckpbus_reg_write, ret: %d\n", ret);
+ return ret;
+ }
+ return ret;
+}
+
+static int air_resolve_an_speed(struct phy_device *phydev)
+{
+ int lpagb = 0, advgb = 0, common_adv_gb = 0;
+ int lpa = 0, adv = 0, common_adv = 0;
+ struct device *dev = phydev_dev(phydev);
+ struct mii_bus *mbus = phydev_mdio_bus(phydev);
+ int addr = phydev_addr(phydev);
+
+ dev_dbg(dev, "AN mode!\n");
+ dev_dbg(dev, "SPEED 1000/100!\n");
+ lpagb = air_mii_cl22_read(mbus,
+ addr, MII_STAT1000);
+ if (lpagb < 0)
+ return lpagb;
+ advgb = air_mii_cl22_read(mbus,
+ addr, MII_CTRL1000);
+ if (adv < 0)
+ return adv;
+ common_adv_gb = (lpagb & (advgb << 2));
+
+ lpa = air_mii_cl22_read(mbus, addr, MII_LPA);
+ if (lpa < 0)
+ return lpa;
+ adv = air_mii_cl22_read(mbus,
+ addr, MII_ADVERTISE);
+ if (adv < 0)
+ return adv;
+ phydev->pause = GET_BIT(adv, 10);
+ phydev->asym_pause = GET_BIT(adv, 11);
+ common_adv = (lpa & adv);
+
+ phydev->speed = SPEED_UNKNOWN;
+ phydev->duplex = DUPLEX_HALF;
+ if (common_adv_gb & (LPA_1000FULL | LPA_1000HALF)) {
+ phydev->speed = SPEED_1000;
+ if (common_adv_gb & LPA_1000FULL)
+ phydev->duplex = DUPLEX_FULL;
+ } else if (common_adv & (LPA_100FULL | LPA_100HALF)) {
+ phydev->speed = SPEED_100;
+ if (common_adv & LPA_100FULL)
+ phydev->duplex = DUPLEX_FULL;
+ } else {
+ if (common_adv & LPA_10FULL)
+ phydev->duplex = DUPLEX_FULL;
+ }
+ return 0;
+}
+
+int air_get_autonego(struct phy_device *phydev, int *an)
+{
+ int reg;
+ struct mii_bus *mbus = phydev_mdio_bus(phydev);
+ int addr = phydev_addr(phydev);
+
+ reg = air_mii_cl22_read(mbus, addr, MII_BMCR);
+ if (reg < 0)
+ return -EINVAL;
+ if (reg & BMCR_ANENABLE)
+ *an = AUTONEG_ENABLE;
+ else
+ *an = AUTONEG_DISABLE;
+ return 0;
+}
+
+static int air_read_status(struct phy_device *phydev)
+{
+ int ret = 0, reg = 0, an = AUTONEG_DISABLE, bmcr = 0;
+ u32 pbus_value = 0;
+ struct device *dev = phydev_dev(phydev);
+ struct mii_bus *mbus = phydev_mdio_bus(phydev);
+ int addr = phydev_addr(phydev);
+
+ phydev->speed = SPEED_UNKNOWN;
+ phydev->duplex = DUPLEX_UNKNOWN;
+ phydev->pause = 0;
+ phydev->asym_pause = 0;
+ phydev->link = 0;
+ phydev->autoneg = AUTONEG_DISABLE;
+ reg = air_mii_cl22_read(mbus, addr, MII_BMSR);
+ if (reg < 0) {
+ dev_err(dev, "MII_BMSR reg %d!\n", reg);
+ return reg;
+ }
+ reg = air_mii_cl22_read(mbus, addr, MII_BMSR);
+ if (reg < 0) {
+ dev_err(dev, "MII_BMSR reg %d!\n", reg);
+ return reg;
+ }
+ if (reg & BMSR_LSTATUS) {
+ phydev->link = 1;
+ ret = air_get_autonego(phydev, &an);
+ if (ret < 0)
+ return ret;
+ phydev->autoneg = an;
+ pbus_value = air_buckpbus_reg_read(phydev, 0x109D4);
+ if (0x10 & pbus_value) {
+ phydev->speed = SPEED_2500;
+ phydev->duplex = DUPLEX_FULL;
+ } else {
+ ret = air_get_autonego(phydev, &an);
+ if (phydev->autoneg == AUTONEG_ENABLE) {
+ ret = air_resolve_an_speed(phydev);
+ if (ret < 0)
+ return ret;
+ } else {
+ dev_dbg(dev, "Force mode!\n");
+ bmcr = air_mii_cl22_read(mbus, addr, MII_BMCR);
+
+ if (bmcr < 0)
+ return bmcr;
+
+ if (bmcr & BMCR_FULLDPLX)
+ phydev->duplex = DUPLEX_FULL;
+ else
+ phydev->duplex = DUPLEX_HALF;
+
+ if (bmcr & BMCR_SPEED1000)
+ phydev->speed = SPEED_1000;
+ else if (bmcr & BMCR_SPEED100)
+ phydev->speed = SPEED_100;
+ else
+ phydev->speed = SPEED_UNKNOWN;
+ }
+ }
+ }
+
+ return ret;
+}
+#ifdef CONFIG_AIROHA_EN8811H_PHY_DEBUGFS
+static void air_polarity_help(void)
+{
+ pr_notice("\nUsage:\n"
+ "[debugfs] = /sys/kernel/debug/mdio-bus\':[phy_addr]\n"
+ "echo [tx polarity] [rx polarity] > /[debugfs]/polarity\n"
+ "option: tx_normal, tx_reverse, rx_normal, rx_revers\n");
+}
+
+static int air_set_polarity(struct phy_device *phydev, int tx_rx)
+{
+ int ret = 0;
+ unsigned int pbus_data = 0;
+
+ pr_debug("\nPolarit %s\n", tx_rx_string[tx_rx]);
+ pbus_data = air_buckpbus_reg_read(phydev, 0xca0f8) & ~(BIT(0) | BIT(1));
+ pbus_data |= tx_rx;
+ ret = air_buckpbus_reg_write(phydev, 0xca0f8, pbus_data);
+ if (ret < 0)
+ pr_notice("\n%s:air_buckpbus_reg_write fail\n", __func__);
+ pbus_data = air_buckpbus_reg_read(phydev, 0xca0f8);
+ pr_notice("\nPolarity %s confirm....(%02lx)\n",
+ tx_rx_string[tx_rx], pbus_data & (BIT(0) | BIT(1)));
+
+ return ret;
+}
+
+static int air_set_mode(struct phy_device *phydev, int dbg_mode)
+{
+ int ret = 0, val = 0;
+ unsigned int pbus_data = 0;
+ struct mii_bus *mbus = phydev_mdio_bus(phydev);
+ int addr = phydev_addr(phydev);
+
+ switch (dbg_mode) {
+ case AIR_PORT_MODE_FORCE_100:
+ pr_notice("\nForce 100M\n");
+ val = air_mii_cl22_read(mbus, addr, MII_ADVERTISE) | BIT(8);
+ ret = air_mii_cl22_write(mbus, addr, MII_ADVERTISE, val);
+ if (unlikely(ret < 0))
+ break;
+ val = air_mii_cl22_read(mbus, addr, MII_CTRL1000) & ~BIT(9);
+ ret = air_mii_cl22_write(mbus, addr, MII_CTRL1000, val);
+ if (unlikely(ret < 0))
+ break;
+ val = air_mii_cl45_read(phydev, 0x7, 0x20) & ~BIT(7);
+ ret = air_mii_cl45_write(phydev, 0x7, 0x20, val);
+ if (unlikely(ret < 0))
+ break;
+ val = air_mii_cl22_read(mbus, addr, MII_BMCR) | BIT(9);
+ ret = air_mii_cl22_write(mbus, addr, MII_BMCR, val);
+ if (unlikely(ret < 0))
+ break;
+ break;
+ case AIR_PORT_MODE_FORCE_1000:
+ pr_notice("\nForce 1000M\n");
+ val = air_mii_cl22_read(mbus, addr, MII_ADVERTISE) & ~BIT(8);
+ ret = air_mii_cl22_write(mbus, addr, MII_ADVERTISE, val);
+ if (unlikely(ret < 0))
+ break;
+ val = air_mii_cl22_read(mbus, addr, MII_CTRL1000) | BIT(9);
+ ret = air_mii_cl22_write(mbus, addr, MII_CTRL1000, val);
+ if (unlikely(ret < 0))
+ break;
+ val = air_mii_cl45_read(phydev, 0x7, 0x20) & ~BIT(7);
+ ret = air_mii_cl45_write(phydev, 0x7, 0x20, val);
+ if (unlikely(ret < 0))
+ break;
+ val = air_mii_cl22_read(mbus, addr, MII_BMCR) | BIT(9);
+ ret = air_mii_cl22_write(mbus, addr, MII_BMCR, val);
+ if (unlikely(ret < 0))
+ break;
+ break;
+ case AIR_PORT_MODE_FORCE_2500:
+ pr_notice("\nForce 2500M\n");
+ val = air_mii_cl22_read(mbus, addr, MII_ADVERTISE) & ~BIT(8);
+ ret = air_mii_cl22_write(mbus, addr, MII_ADVERTISE, val);
+ if (unlikely(ret < 0))
+ break;
+ val = air_mii_cl22_read(mbus, addr, MII_CTRL1000) & ~BIT(9);
+ ret = air_mii_cl22_write(mbus, addr, MII_CTRL1000, val);
+ if (unlikely(ret < 0))
+ break;
+ val = air_mii_cl45_read(phydev, 0x7, 0x20) | BIT(7);
+ ret = air_mii_cl45_write(phydev, 0x7, 0x20, val);
+ if (unlikely(ret < 0))
+ break;
+ val = air_mii_cl22_read(mbus, addr, MII_BMCR) | BIT(9);
+ ret = air_mii_cl22_write(mbus, addr, MII_BMCR, val);
+ if (unlikely(ret < 0))
+ break;
+ break;
+ case AIR_PORT_MODE_AUTONEGO:
+ pr_notice("\nAutonego mode\n");
+ val = air_mii_cl22_read(mbus, addr, MII_ADVERTISE) | BIT(8);
+ ret = air_mii_cl22_write(mbus, addr, MII_ADVERTISE, val);
+ if (unlikely(ret < 0))
+ break;
+ val = air_mii_cl22_read(mbus, addr, MII_CTRL1000) | BIT(9);
+ ret = air_mii_cl22_write(mbus, addr, MII_CTRL1000, val);
+ if (unlikely(ret < 0))
+ break;
+ val = air_mii_cl45_read(phydev, 0x7, 0x20) | BIT(7);
+ ret = air_mii_cl45_write(phydev, 0x7, 0x20, val);
+ if (unlikely(ret < 0))
+ break;
+ val = air_mii_cl22_read(mbus, addr, MII_BMCR) | BIT(9);
+ ret = air_mii_cl22_write(mbus, addr, MII_BMCR, val);
+ if (unlikely(ret < 0))
+ break;
+ break;
+ case AIR_PORT_MODE_POWER_DOWN:
+ pr_notice("\nPower Down\n");
+ val = air_mii_cl22_read(mbus, addr, MII_BMCR) | BIT(11);
+ ret = air_mii_cl22_write(mbus, addr, MII_BMCR, val);
+ if (unlikely(ret < 0))
+ break;
+ break;
+ case AIR_PORT_MODE_POWER_UP:
+ pr_notice("\nPower Up\n");
+ val = air_mii_cl22_read(mbus, addr, MII_BMCR) & ~BIT(11);
+ ret = air_mii_cl22_write(mbus, addr, MII_BMCR, val);
+ if (unlikely(ret < 0))
+ break;
+ break;
+ case AIR_PORT_MODE_FC_DIS:
+ pr_notice("\nFlow Control Disabled\n");
+ pbus_data = air_buckpbus_reg_read(phydev, 0xe0008);
+ pbus_data &= ~(BIT(6) | BIT(7));
+ ret = air_buckpbus_reg_write(phydev, 0xe0008, pbus_data);
+ if (unlikely(ret < 0))
+ break;
+ pbus_data = air_buckpbus_reg_read(phydev, 0xe000c);
+ pbus_data &= ~(BIT(0) | BIT(1));
+ ret = air_buckpbus_reg_write(phydev, 0xe000c, pbus_data);
+ if (unlikely(ret < 0))
+ break;
+ break;
+ case AIR_PORT_MODE_FC_EN:
+ pr_notice("\nFlow Control Enabled\n");
+ pbus_data = air_buckpbus_reg_read(phydev, 0xe0008);
+ pbus_data |= (BIT(6) | BIT(7));
+ ret = air_buckpbus_reg_write(phydev, 0xe0008, pbus_data);
+ if (unlikely(ret < 0))
+ break;
+ pbus_data = air_buckpbus_reg_read(phydev, 0xe000c);
+ pbus_data |= (BIT(0) | BIT(1));
+ ret = air_buckpbus_reg_write(phydev, 0xe000c, pbus_data);
+ if (unlikely(ret < 0))
+ break;
+ break;
+ default:
+ pr_notice("\nWrong Port mode\n");
+ break;
+ }
+ return ret;
+}
+
+static int airphy_info_show(struct seq_file *seq, void *v)
+{
+ struct phy_device *phydev = seq->private;
+ struct en8811h_priv *priv = phydev->priv;
+ unsigned int val = 0;
+
+ seq_puts(seq, "<<AIR EN8811H Driver info>>\n");
+ seq_printf(seq, "| Driver Version : %s\n",
+ EN8811H_DRIVER_VERSION);
+ val = air_buckpbus_reg_read(phydev, 0xcf914);
+ seq_printf(seq, "| Boot mode : %s\n",
+ ((val & BIT(24)) >> 24) ? "Flash" : "Download Code");
+ seq_printf(seq, "| EthMD32.dm.bin CRC32: %08x\n",
+ priv->dm_crc32);
+ seq_printf(seq, "| EthMD32.DSP.bin CRC32: %08x\n",
+ priv->dsp_crc32);
+ val = air_buckpbus_reg_read(phydev, 0x3b3c);
+ seq_printf(seq, "| MD32 FW Version : %08x\n", val);
+ val = air_mii_cl45_read(phydev, 0x1e, 0x8009);
+ seq_printf(seq, "| MD32 FW Status : %08x\n",
+ air_mii_cl45_read(phydev, 0x1e, 0x8009));
+ val = (air_buckpbus_reg_read(phydev, 0xca0f8) & 0x3);
+ seq_printf(seq, "| Tx, Rx Polarity : %s(%02d)\n",
+ tx_rx_string[val], val);
+
+ seq_puts(seq, "\n");
+
+ return 0;
+}
+
+static int airphy_info_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, airphy_info_show, inode->i_private);
+}
+
+static int airphy_fcm_counter_show(struct phy_device *phydev,
+ struct seq_file *seq)
+{
+ int ret = 0;
+ u32 pkt_cnt = 0;
+
+ seq_puts(seq, "|\t<<FCM Counter>>\n");
+ seq_puts(seq, "| Rx from Line side_S :");
+ pkt_cnt = air_buckpbus_reg_read(phydev, 0xe0090);
+ seq_printf(seq, "%010u |\n", pkt_cnt);
+ seq_puts(seq, "| Rx from Line side_T :");
+ pkt_cnt = air_buckpbus_reg_read(phydev, 0xe0094);
+ seq_printf(seq, "%010u |\n", pkt_cnt);
+ seq_puts(seq, "| Tx to System side_S :");
+ pkt_cnt = air_buckpbus_reg_read(phydev, 0xe009c);
+ seq_printf(seq, "%010u |\n", pkt_cnt);
+ seq_puts(seq, "| Tx to System side_T :");
+ pkt_cnt = air_buckpbus_reg_read(phydev, 0xe00A0);
+ seq_printf(seq, "%010u |\n", pkt_cnt);
+ seq_puts(seq, "| Rx from System side_S :");
+ pkt_cnt = air_buckpbus_reg_read(phydev, 0xe0078);
+ seq_printf(seq, "%010u |\n", pkt_cnt);
+ seq_puts(seq, "| Rx from System side_T :");
+ pkt_cnt = air_buckpbus_reg_read(phydev, 0xe007C);
+ seq_printf(seq, "%010u |\n", pkt_cnt);
+ seq_puts(seq, "| Tx to Line side_S :");
+ pkt_cnt = air_buckpbus_reg_read(phydev, 0xe0084);
+ seq_printf(seq, "%010u |\n", pkt_cnt);
+ seq_puts(seq, "| Tx to Line side_T :");
+ pkt_cnt = air_buckpbus_reg_read(phydev, 0xe0088);
+ seq_printf(seq, "%010u |\n", pkt_cnt);
+ ret = air_buckpbus_reg_write(phydev, 0xe0074, 0xf);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+static int airphy_ss_counter_show(struct phy_device *phydev,
+ struct seq_file *seq)
+{
+ int ret = 0;
+ u32 pkt_cnt = 0;
+
+ seq_puts(seq, "|\t<<SS Counter>>\n");
+ ret = air_buckpbus_reg_write(phydev, 0xC602C, 0x3);
+ if (ret < 0)
+ return ret;
+ seq_puts(seq, "| TX Start :");
+ pkt_cnt = air_buckpbus_reg_read(phydev, 0xC60B0);
+ seq_printf(seq, "%010u |\n", pkt_cnt);
+ seq_puts(seq, "| TX Terminal :");
+ pkt_cnt = air_buckpbus_reg_read(phydev, 0xC60B4);
+ seq_printf(seq, "%010u |\n", pkt_cnt);
+ seq_puts(seq, "| RX Start :");
+ pkt_cnt = air_buckpbus_reg_read(phydev, 0xC60BC);
+ seq_printf(seq, "%010u |\n", pkt_cnt);
+ seq_puts(seq, "| RX Terminal :");
+ pkt_cnt = air_buckpbus_reg_read(phydev, 0xC60C0);
+ seq_printf(seq, "%010u |\n\n", pkt_cnt);
+ ret = air_buckpbus_reg_write(phydev, 0xC602C, 0x4);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+static int airphy_counter_show(struct seq_file *seq, void *v)
+{
+ struct phy_device *phydev = seq->private;
+ struct mii_bus *mbus = phydev_mdio_bus(phydev);
+ int ret = 0, addr = phydev_addr(phydev);
+ u32 pkt_cnt = 0;
+
+ ret = air_read_status(phydev);
+ if (ret < 0)
+ return ret;
+ seq_puts(seq, "==========AIR PHY COUNTER==========\n");
+ ret = airphy_fcm_counter_show(phydev, seq);
+ if (ret < 0)
+ return ret;
+ if (phydev->link && phydev->speed == SPEED_2500) {
+ seq_puts(seq, "|\t<<LS Counter>>\n");
+ ret = air_buckpbus_reg_write(phydev, 0x30718, 0x10);
+ if (ret < 0)
+ return ret;
+ ret = air_buckpbus_reg_write(phydev, 0x30718, 0x0);
+ if (ret < 0)
+ return ret;
+ seq_puts(seq, "|\tBefore EF\n");
+ seq_puts(seq, "| TX to Line side_S :");
+ pkt_cnt = air_buckpbus_reg_read(phydev, 0x3071c);
+ seq_printf(seq, "%010u |\n", pkt_cnt);
+ seq_puts(seq, "| TX to Line side_T :");
+ pkt_cnt = air_buckpbus_reg_read(phydev, 0x30720);
+ seq_printf(seq, "%010u |\n", pkt_cnt);
+ seq_puts(seq, "| RX from Line side_S :");
+ pkt_cnt = air_buckpbus_reg_read(phydev, 0x3072c);
+ seq_printf(seq, "%010u |\n", pkt_cnt);
+ seq_puts(seq, "| RX from Line side_T :");
+ pkt_cnt = air_buckpbus_reg_read(phydev, 0x30730);
+ seq_printf(seq, "%010u |\n", pkt_cnt);
+ seq_puts(seq, "| TX_ENC :");
+ pkt_cnt = air_buckpbus_reg_read(phydev, 0x30724);
+ seq_printf(seq, "%010u |\n", pkt_cnt);
+ seq_puts(seq, "| RX_DEC :");
+ pkt_cnt = air_buckpbus_reg_read(phydev, 0x30728);
+ seq_printf(seq, "%010u |\n", pkt_cnt);
+ seq_puts(seq, "|\tAfter EF\n");
+ seq_puts(seq, "| TX to Line side_S :");
+ pkt_cnt = air_buckpbus_reg_read(phydev, 0x30734);
+ seq_printf(seq, "%010u |\n", pkt_cnt);
+ seq_puts(seq, "| TX to Line side_T :");
+ pkt_cnt = air_buckpbus_reg_read(phydev, 0x30738);
+ seq_printf(seq, "%010u |\n", pkt_cnt);
+ seq_puts(seq, "| RX from Line side_S :");
+ pkt_cnt = air_buckpbus_reg_read(phydev, 0x30764);
+ seq_printf(seq, "%010u |\n", pkt_cnt);
+ seq_puts(seq, "| RX from Line side_T :");
+ pkt_cnt = air_buckpbus_reg_read(phydev, 0x30768);
+ seq_printf(seq, "%010u |\n", pkt_cnt);
+ ret = air_buckpbus_reg_write(phydev, 0x30718, 0x13);
+ if (ret < 0)
+ return ret;
+ ret = air_buckpbus_reg_write(phydev, 0x30718, 0x3);
+ if (ret < 0)
+ return ret;
+ ret = air_buckpbus_reg_write(phydev, 0x30718, 0x10);
+ if (ret < 0)
+ return ret;
+ ret = air_buckpbus_reg_write(phydev, 0x30718, 0x0);
+ if (ret < 0)
+ return ret;
+ seq_puts(seq, "|\t<<MAC Counter>>\n");
+ seq_puts(seq, "| TX Error from System side:");
+ pkt_cnt = air_buckpbus_reg_read(phydev, 0x131000);
+ seq_printf(seq, "%010u |\n", pkt_cnt);
+ seq_puts(seq, "| RX Error to System side :");
+ pkt_cnt = air_buckpbus_reg_read(phydev, 0x132000);
+ seq_printf(seq, "%010u |\n", pkt_cnt);
+ seq_puts(seq, "| TX from System side :");
+ pkt_cnt = air_buckpbus_reg_read(phydev, 0x131004);
+ seq_printf(seq, "%010u |\n", pkt_cnt);
+ seq_puts(seq, "| RX to System Side :");
+ pkt_cnt = air_buckpbus_reg_read(phydev, 0x132004);
+ seq_printf(seq, "%010u |\n", pkt_cnt);
+ }
+ if (phydev->link && ((phydev->speed != SPEED_2500))) {
+ seq_puts(seq, "|\t<<LS Counter>>\n");
+ ret = air_mii_cl22_write(mbus, addr, 0x1f, 1);
+ if (ret < 0)
+ return ret;
+ seq_puts(seq, "| RX from Line side :");
+ pkt_cnt = air_mii_cl22_read(mbus, addr, 0x12) & 0x7fff;
+ seq_printf(seq, "%010u |\n", pkt_cnt);
+ seq_puts(seq, "| RX Error from Line side :");
+ pkt_cnt = air_mii_cl22_read(mbus, addr, 0x17) & 0xff;
+ seq_printf(seq, "%010u |\n", pkt_cnt);
+ ret = air_mii_cl22_write(mbus, addr, 0x1f, 0);
+ if (ret < 0)
+ return ret;
+ ret = air_mii_cl22_write(mbus, addr, 0x1f, 0x52B5);
+ if (ret < 0)
+ return ret;
+ ret = air_mii_cl22_write(mbus, addr, 0x10, 0xBF92);
+ if (ret < 0)
+ return ret;
+ seq_puts(seq, "| TX to Line side :");
+ pkt_cnt = (air_mii_cl22_read(mbus, addr, 0x11) & 0x7ffe) >> 1;
+ seq_printf(seq, "%010u |\n", pkt_cnt);
+ seq_puts(seq, "| TX Error to Line side :");
+ pkt_cnt = air_mii_cl22_read(mbus, addr, 0x12);
+ pkt_cnt &= 0x7f;
+ seq_printf(seq, "%010u |\n", pkt_cnt);
+ ret = air_mii_cl22_write(mbus, addr, 0x1f, 0);
+ if (ret < 0)
+ return ret;
+ }
+ if (phydev->link) {
+ ret = airphy_ss_counter_show(phydev, seq);
+ if (ret < 0)
+ return ret;
+ }
+ return ret;
+}
+
+static int airphy_counter_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, airphy_counter_show, inode->i_private);
+}
+
+static ssize_t airphy_polarity_write(struct file *file, const char __user *ptr,
+ size_t len, loff_t *off)
+{
+ struct phy_device *phydev = file->private_data;
+ char buf[32], param1[32], param2[32];
+ int count = len, ret = 0, tx_rx = 0;
+
+ memset(buf, 0, 32);
+ memset(param1, 0, 32);
+ memset(param2, 0, 32);
+
+ if (count > sizeof(buf) - 1)
+ return -EINVAL;
+ if (copy_from_user(buf, ptr, len))
+ return -EFAULT;
+ if (sscanf(buf, "%s %s", param1, param2) == -1)
+ return -EFAULT;
+
+ if (!strncmp("tx_normal", param1, strlen("tx_normal"))) {
+ if (!strncmp("rx_normal", param2, strlen("rx_normal")))
+ tx_rx = AIR_POL_TX_NOR_RX_NOR;
+ else if (!strncmp("rx_reverse", param2, strlen("rx_reverse")))
+ tx_rx = AIR_POL_TX_NOR_RX_REV;
+ else {
+ pr_notice("\nRx param is not correct.\n");
+ return -EINVAL;
+ }
+ } else if (!strncmp("tx_reverse", param1, strlen("tx_reverse"))) {
+ if (!strncmp("rx_normal", param2, strlen("rx_normal")))
+ tx_rx = AIR_POL_TX_REV_RX_NOR;
+ else if (!strncmp("rx_reverse", param2, strlen("rx_reverse")))
+ tx_rx = AIR_POL_TX_REV_RX_REV;
+ else {
+ pr_notice("\nRx param is not correct.\n");
+ return -EINVAL;
+ }
+ } else {
+ air_polarity_help();
+ return count;
+ }
+ pr_notice("\nSet Polarity %s\n", tx_rx_string[tx_rx]);
+ ret = air_set_polarity(phydev, tx_rx);
+ if (ret < 0)
+ return ret;
+ return count;
+}
+static void airphy_port_mode_help(void)
+{
+ pr_notice("\nUsage:\n"
+ "[debugfs] = /sys/kernel/debug/mdio-bus\':[phy_addr]\n"
+ "echo [mode] [para] > /[debugfs]/port_mode\n"
+ "echo re-an > /[debugfs]/port_mode\n"
+ "echo auto > /[debugfs]/port_mode\n"
+ "echo 2500 > /[debugfs]/port_mode\n"
+ "echo 1000 > /[debugfs]/port_mode\n"
+ "echo 100 > /[debugfs]/port_mode\n"
+ "echo power up/down > /[debugfs]/port_mode\n");
+}
+
+static ssize_t airphy_port_mode(struct file *file, const char __user *ptr,
+ size_t len, loff_t *off)
+{
+ struct phy_device *phydev = file->private_data;
+ char buf[32], cmd[32], param[32];
+ int count = len, ret = 0;
+ int num = 0, val = 0;
+
+ memset(buf, 0, 32);
+ memset(cmd, 0, 32);
+ memset(param, 0, 32);
+
+ if (count > sizeof(buf) - 1)
+ return -EINVAL;
+ if (copy_from_user(buf, ptr, len))
+ return -EFAULT;
+
+ num = sscanf(buf, "%s %s", cmd, param);
+ if (num < 1 || num > 3)
+ return -EFAULT;
+
+ if (!strncmp("auto", cmd, strlen("auto")))
+ ret = air_set_mode(phydev, AIR_PORT_MODE_AUTONEGO);
+ else if (!strncmp("2500", cmd, strlen("2500")))
+ ret = air_set_mode(phydev, AIR_PORT_MODE_FORCE_2500);
+ else if (!strncmp("1000", cmd, strlen("1000")))
+ ret = air_set_mode(phydev, AIR_PORT_MODE_FORCE_1000);
+ else if (!strncmp("100", cmd, strlen("100")))
+ ret = air_set_mode(phydev, AIR_PORT_MODE_FORCE_100);
+ else if (!strncmp("re-an", cmd, strlen("re-an"))) {
+ val = phy_read(phydev, MII_BMCR) | BIT(9);
+ ret = phy_write(phydev, MII_BMCR, val);
+ } else if (!strncmp("power", cmd, strlen("power"))) {
+ if (!strncmp("down", param, strlen("down")))
+ ret = air_set_mode(phydev, AIR_PORT_MODE_POWER_DOWN);
+ else if (!strncmp("up", param, strlen("up")))
+ ret = air_set_mode(phydev, AIR_PORT_MODE_POWER_UP);
+ } else if (!strncmp("int_sw_release", cmd, strlen("int_sw_release"))) {
+ ret = air_pbus_reg_write(phydev, 0xcf928, 0x0);
+ pr_notice("\ninternal sw reset released\n");
+ } else if (!strncmp("help", cmd, strlen("help"))) {
+ airphy_port_mode_help();
+ }
+
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static void airphy_debugfs_buckpbus_help(void)
+{
+ pr_notice("\nUsage:\n"
+ "[debugfs] = /sys/kernel/debug/mdio-bus\':[phy_addr]\n"
+ "Read:\n"
+ "echo r [buckpbus_register] > /[debugfs]/buckpbus_op\n"
+ "Write:\n"
+ "echo w [buckpbus_register] [value] > /[debugfs]/buckpbus_op\n");
+}
+
+
+static ssize_t airphy_debugfs_buckpbus(struct file *file,
+ const char __user *buffer, size_t count,
+ loff_t *data)
+{
+ struct phy_device *phydev = file->private_data;
+ char buf[64];
+ int ret = 0;
+ unsigned int reg, val;
+
+ memset(buf, 0, 64);
+ if (count > sizeof(buf) - 1)
+ return -EINVAL;
+ if (copy_from_user(buf, buffer, count))
+ return -EFAULT;
+
+ if (buf[0] == 'w') {
+ if (sscanf(buf, "w %x %x", ®, &val) == -1)
+ return -EFAULT;
+
+ pr_notice("\nphy=%d, reg=0x%x, val=0x%x\n",
+ phydev_addr(phydev), reg, val);
+ ret = air_buckpbus_reg_write(phydev, reg, val);
+ if (ret < 0) {
+ pr_notice("\nbuckpbus_reg_write fail\n");
+ return -EIO;
+ }
+ val = air_buckpbus_reg_read(phydev, reg);
+ pr_notice("\nphy=%d, reg=0x%x, val=0x%x confirm..\n",
+ phydev_addr(phydev), reg, val);
+ } else if (buf[0] == 'r') {
+ if (sscanf(buf, "r %x", ®) == -1)
+ return -EFAULT;
+
+ val = air_buckpbus_reg_read(phydev, reg);
+ pr_notice("\nphy=%d, reg=0x%x, val=0x%x\n",
+ phydev_addr(phydev), reg, val);
+ } else
+ airphy_debugfs_buckpbus_help();
+
+ return count;
+}
+
+static ssize_t airphy_debugfs_pbus(struct file *file,
+ const char __user *buffer, size_t count,
+ loff_t *data)
+{
+ struct phy_device *phydev = file->private_data;
+ char buf[64];
+ int ret = 0;
+ unsigned int reg, val;
+
+ memset(buf, 0, 64);
+ if (copy_from_user(buf, buffer, count))
+ return -EFAULT;
+
+ if (buf[0] == 'w') {
+ if (sscanf(buf, "w %x %x", ®, &val) == -1)
+ return -EFAULT;
+
+ pr_notice("\nphy=%d, reg=0x%x, val=0x%x\n",
+ phydev_addr(phydev), reg, val);
+ ret = air_pbus_reg_write(phydev, reg, val);
+ if (ret < 0) {
+ pr_notice("\npbus_reg_write fail\n");
+ return -EIO;
+ }
+ val = air_pbus_reg_read(phydev, reg);
+ pr_notice("\nphy=%d, reg=0x%x, val=0x%x confirm..\n",
+ phydev_addr(phydev), reg, val);
+ } else if (buf[0] == 'r') {
+ if (sscanf(buf, "r %x", ®) == -1)
+ return -EFAULT;
+
+ val = air_pbus_reg_read(phydev, reg);
+ pr_notice("\nphy=%d, reg=0x%x, val=0x%x\n",
+ phydev_addr(phydev), reg, val);
+ } else
+ airphy_debugfs_buckpbus_help();
+
+ return count;
+}
+
+static int airphy_link_status(struct seq_file *seq, void *v)
+{
+ int ret = 0;
+ struct phy_device *phydev = seq->private;
+
+ ret = air_read_status(phydev);
+ if (ret < 0)
+ return ret;
+
+ seq_printf(seq, "%s Information:\n", dev_name(phydev_dev(phydev)));
+ seq_printf(seq, "\tPHYAD: %02d\n", phydev_addr(phydev));
+ seq_printf(seq, "\tLink Status: %s\n", phydev->link ? "UP" : "DOWN");
+ if (phydev->link) {
+ seq_printf(seq, "\tAuto-Nego: %s\n",
+ phydev->autoneg ? "on" : "off");
+ seq_puts(seq, "\tSpeed: ");
+ if (phydev->speed == SPEED_UNKNOWN)
+ seq_printf(seq, "Unknown! (%i)\n", phydev->speed);
+ else
+ seq_printf(seq, "%uMb/s\n", phydev->speed);
+
+ seq_printf(seq, "\tDuplex: %s\n",
+ phydev->duplex ? "Full" : "Half");
+ seq_puts(seq, "\n");
+ }
+
+ return ret;
+}
+
+static int airphy_link_status_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, airphy_link_status, inode->i_private);
+}
+
+static int dbg_regs_show(struct seq_file *seq, void *v)
+{
+ struct phy_device *phydev = seq->private;
+ struct mii_bus *mbus = phydev_mdio_bus(phydev);
+ int addr = phydev_addr(phydev);
+
+ seq_puts(seq, "\t<<DEBUG REG DUMP>>\n");
+ seq_printf(seq, "| RG_MII_BMSR : 0x%08x |\n",
+ air_mii_cl22_read(mbus, addr, MII_BMSR));
+ seq_printf(seq, "| RG_MII_REF_CLK : 0x%08x |\n",
+ air_mii_cl22_read(mbus, addr, 0x1d));
+ seq_printf(seq, "| RG_SYS_LINK_MODE : 0x%08x |\n",
+ air_buckpbus_reg_read(phydev, 0xe0004));
+ seq_printf(seq, "| RG_FCM_CTRL : 0x%08x |\n",
+ air_buckpbus_reg_read(phydev, 0xe000C));
+ seq_printf(seq, "| RG_SS_PAUSE_TIME : 0x%08x |\n",
+ air_buckpbus_reg_read(phydev, 0xe0020));
+ seq_printf(seq, "| RG_MIN_IPG_NUM : 0x%08x |\n",
+ air_buckpbus_reg_read(phydev, 0xe002C));
+ seq_printf(seq, "| RG_CTROL_0 : 0x%08x |\n",
+ air_buckpbus_reg_read(phydev, 0xc0000));
+ seq_printf(seq, "| RG_LINK_STATUS : 0x%08x |\n",
+ air_buckpbus_reg_read(phydev, 0xc0b04));
+ seq_printf(seq, "| RG_LINK_PARTNER_AN : 0x%08x |\n",
+ air_buckpbus_reg_read(phydev, 0xc0014));
+ seq_printf(seq, "| RG_FN_PWR_CTRL_STATUS : 0x%08x |\n",
+ air_buckpbus_reg_read(phydev, 0x1020c));
+ seq_printf(seq, "| RG_WHILE_LOOP_COUNT : 0x%08x |\n",
+ air_buckpbus_reg_read(phydev, 0x3A48));
+
+ return 0;
+}
+
+static int airphy_dbg_regs_show_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, dbg_regs_show, inode->i_private);
+}
+
+static const struct file_operations airphy_info_fops = {
+ .owner = THIS_MODULE,
+ .open = airphy_info_open,
+ .read = seq_read,
+ .llseek = noop_llseek,
+};
+
+static const struct file_operations airphy_counter_fops = {
+ .owner = THIS_MODULE,
+ .open = airphy_counter_open,
+ .read = seq_read,
+ .llseek = noop_llseek,
+};
+
+static const struct file_operations airphy_debugfs_buckpbus_fops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .write = airphy_debugfs_buckpbus,
+ .llseek = noop_llseek,
+};
+
+static const struct file_operations airphy_debugfs_pbus_fops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .write = airphy_debugfs_pbus,
+ .llseek = noop_llseek,
+};
+
+static const struct file_operations airphy_port_mode_fops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .write = airphy_port_mode,
+ .llseek = noop_llseek,
+};
+
+static const struct file_operations airphy_polarity_fops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .write = airphy_polarity_write,
+ .llseek = noop_llseek,
+};
+
+static const struct file_operations airphy_link_status_fops = {
+ .owner = THIS_MODULE,
+ .open = airphy_link_status_open,
+ .read = seq_read,
+ .llseek = noop_llseek,
+};
+
+static const struct file_operations airphy_dbg_reg_show_fops = {
+ .owner = THIS_MODULE,
+ .open = airphy_dbg_regs_show_open,
+ .read = seq_read,
+ .llseek = noop_llseek,
+};
+
+int airphy_debugfs_init(struct phy_device *phydev)
+{
+ int ret = 0;
+ struct en8811h_priv *priv = phydev->priv;
+ struct dentry *dir = priv->debugfs_root;
+
+ dev_dbg(phydev_dev(phydev), "%s: start\n", __func__);
+ dir = debugfs_create_dir(dev_name(phydev_dev(phydev)), NULL);
+ if (!dir) {
+ dev_err(phydev_dev(phydev), "%s:err at %d\n",
+ __func__, __LINE__);
+ ret = -ENOMEM;
+ }
+ debugfs_create_file(DEBUGFS_DRIVER_INFO, S_IFREG | 0444,
+ dir, phydev,
+ &airphy_info_fops);
+ debugfs_create_file(DEBUGFS_COUNTER, S_IFREG | 0444,
+ dir, phydev,
+ &airphy_counter_fops);
+ debugfs_create_file(DEBUGFS_BUCKPBUS_OP, S_IFREG | 0200,
+ dir, phydev,
+ &airphy_debugfs_buckpbus_fops);
+ debugfs_create_file(DEBUGFS_PBUS_OP, S_IFREG | 0200,
+ dir, phydev,
+ &airphy_debugfs_pbus_fops);
+ debugfs_create_file(DEBUGFS_PORT_MODE, S_IFREG | 0200,
+ dir, phydev,
+ &airphy_port_mode_fops);
+ debugfs_create_file(DEBUGFS_POLARITY, S_IFREG | 0200,
+ dir, phydev,
+ &airphy_polarity_fops);
+ debugfs_create_file(DEBUGFS_LINK_STATUS, S_IFREG | 0444,
+ dir, phydev,
+ &airphy_link_status_fops);
+ debugfs_create_file(DEBUGFS_DBG_REG_SHOW, S_IFREG | 0444,
+ dir, phydev,
+ &airphy_dbg_reg_show_fops);
+
+ priv->debugfs_root = dir;
+ return ret;
+}
+
+void air_debugfs_remove(struct phy_device *phydev)
+{
+ struct en8811h_priv *priv = phydev->priv;
+
+ debugfs_remove_recursive(priv->debugfs_root);
+ priv->debugfs_root = NULL;
+}
+#endif /*CONFIG_AIROHA_EN8811H_PHY_DEBUGFS*/
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/air_en8811h_api.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/air_en8811h_api.h
new file mode 100644
index 0000000..a1d97ce
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/air_en8811h_api.h
@@ -0,0 +1,87 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*************************************************
+ * FILE NAME: air_en8811h_api.h
+ * PURPOSE:
+ * EN8811H PHY Driver for Linux
+ * NOTES:
+ *
+ * Copyright (C) 2023 Airoha Technology Corp.
+ *************************************************/
+#ifndef __EN8811H_API_H
+#define __EN8811H_API_H
+#include <linux/version.h>
+
+#if (KERNEL_VERSION(4, 5, 0) > LINUX_VERSION_CODE)
+#define phydev_mdio_bus(_dev) (_dev->bus)
+#define phydev_addr(_dev) (_dev->addr)
+#define phydev_dev(_dev) (&_dev->dev)
+#else
+#define phydev_mdio_bus(_dev) (_dev->mdio.bus)
+#define phydev_addr(_dev) (_dev->mdio.addr)
+#define phydev_dev(_dev) (&_dev->mdio.dev)
+#endif
+
+#define BUFFER_LENGTH 512
+
+#define DEBUGFS_COUNTER "counter"
+#define DEBUGFS_DRIVER_INFO "drvinfo"
+#define DEBUGFS_PORT_MODE "port_mode"
+#define DEBUGFS_BUCKPBUS_OP "buckpbus_op"
+#define DEBUGFS_PBUS_OP "pbus_op"
+#define DEBUGFS_POLARITY "polarity"
+#define DEBUGFS_LINK_STATUS "link_status"
+#define DEBUGFS_DBG_REG_SHOW "dbg_regs_show"
+
+enum air_port_mode {
+ AIR_PORT_MODE_FORCE_100,
+ AIR_PORT_MODE_FORCE_1000,
+ AIR_PORT_MODE_FORCE_2500,
+ AIR_PORT_MODE_AUTONEGO,
+ AIR_PORT_MODE_POWER_DOWN,
+ AIR_PORT_MODE_POWER_UP,
+ AIR_PORT_MODE_FC_UNSUPPORT,
+ AIR_PORT_MODE_FC_SUPPORT,
+ AIR_PORT_MODE_FC_DIS,
+ AIR_PORT_MODE_FC_EN,
+ AIR_PORT_MODE_LAST = 0xFF,
+};
+
+enum air_polarity {
+ AIR_POL_TX_REV_RX_NOR,
+ AIR_POL_TX_NOR_RX_NOR,
+ AIR_POL_TX_REV_RX_REV,
+ AIR_POL_TX_NOR_RX_REV,
+ AIR_POL_TX_NOR_RX_LAST = 0xff,
+};
+
+/* Link mode bit indices */
+enum air_link_mode_bit {
+ AIR_LINK_MODE_10baseT_Half_BIT = 0,
+ AIR_LINK_MODE_10baseT_Full_BIT = 1,
+ AIR_LINK_MODE_100baseT_Half_BIT = 2,
+ AIR_LINK_MODE_100baseT_Full_BIT = 3,
+ AIR_LINK_MODE_1000baseT_Full_BIT = 4,
+ AIR_LINK_MODE_2500baseT_Full_BIT = 5,
+};
+
+#ifndef unlikely
+# define unlikely(x) (x)
+#endif
+int air_pbus_reg_write(struct phy_device *phydev,
+ unsigned int pbus_address, unsigned int pbus_data);
+int air_mii_cl22_write(struct mii_bus *ebus, int addr,
+ unsigned int phy_register, unsigned int write_data);
+int air_mii_cl22_read(struct mii_bus *ebus,
+ int addr, unsigned int phy_register);
+int air_mii_cl45_read(struct phy_device *phydev, int devad, u16 reg);
+int air_mii_cl45_write(struct phy_device *phydev,
+ int devad, u16 reg, u16 write_data);
+unsigned int air_buckpbus_reg_read(struct phy_device *phydev,
+ unsigned int pbus_address);
+int air_buckpbus_reg_write(struct phy_device *phydev,
+ unsigned int pbus_address, unsigned int pbus_data);
+#ifdef CONFIG_AIROHA_EN8811H_PHY_DEBUGFS
+int airphy_debugfs_init(struct phy_device *phydev);
+void air_debugfs_remove(struct phy_device *phydev);
+#endif /*CONFIG_AIROHA_EN8811H_PHY_DEBUGFS*/
+#endif /* End of __EN8811H_API_H */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/air_en8811h_main.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/air_en8811h_main.c
new file mode 100644
index 0000000..353e226
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/air_en8811h_main.c
@@ -0,0 +1,480 @@
+// SPDX-License-Identifier: GPL-2.0
+/*************************************************
+ * FILE NAME: air_en8811h_main.c
+ * PURPOSE:
+ * EN8811H PHY Driver for Linux
+ * NOTES:
+ *
+ * Copyright (C) 2023 Airoha Technology Corp.
+ *************************************************/
+
+/* INCLUDE FILE DECLARATIONS
+*/
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+#include <linux/delay.h>
+#include <linux/ethtool.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/crc32.h>
+#include <linux/debugfs.h>
+#include "air_en8811h_api.h"
+#include "air_en8811h.h"
+
+MODULE_DESCRIPTION("Airoha EN8811H PHY Drivers");
+MODULE_AUTHOR("Airoha");
+MODULE_LICENSE("GPL");
+
+/**************************
+ * GPIO5 <-> BASE_T_LED0,
+ * GPIO4 <-> BASE_T_LED1,
+ * GPIO3 <-> BASE_T_LED2,
+ **************************/
+/* User-defined.B */
+#define AIR_LED_SUPPORT
+#ifdef AIR_LED_SUPPORT
+static const struct air_base_t_led_cfg led_cfg[3] = {
+/********************************************************************
+ *Enable, GPIO, LED Polarity, LED ON, LED Blink
+*********************************************************************/
+ {1, AIR_LED0_GPIO5, AIR_ACTIVE_HIGH, AIR_LED0_ON, AIR_LED0_BLK},
+ {1, AIR_LED1_GPIO4, AIR_ACTIVE_HIGH, AIR_LED1_ON, AIR_LED1_BLK},
+ {1, AIR_LED2_GPIO3, AIR_ACTIVE_HIGH, AIR_LED2_ON, AIR_LED2_BLK},
+};
+static const u16 led_dur = UNIT_LED_BLINK_DURATION << AIR_LED_BLK_DUR_64M;
+#endif
+/* User-defined.E */
+
+/***********************************************************
+ * F U N C T I O N S
+ ***********************************************************/
+
+
+static int MDIOWriteBuf(struct phy_device *phydev,
+ unsigned long address, const struct firmware *fw)
+{
+ unsigned int write_data, offset;
+ int ret = 0;
+ struct device *dev = phydev_dev(phydev);
+ struct mii_bus *mbus = phydev_mdio_bus(phydev);
+ int addr = phydev_addr(phydev);
+ /* page 4 */
+ ret = air_mii_cl22_write(mbus, addr, 0x1F, 4);
+ if (ret < 0) {
+ dev_err(dev, "air_mii_cl22_write, ret: %d\n", ret);
+ return ret;
+ }
+ /* address increment*/
+ ret = air_mii_cl22_write(mbus, addr, 0x10, 0x8000);
+ if (ret < 0) {
+ dev_err(dev, "air_mii_cl22_write, ret: %d\n", ret);
+ return ret;
+ }
+ ret = air_mii_cl22_write(mbus, addr, 0x11,
+ (u32)((address >> 16) & 0xffff));
+ if (ret < 0) {
+ dev_err(dev, "air_mii_cl22_write, ret: %d\n", ret);
+ return ret;
+ }
+ ret = air_mii_cl22_write(mbus, addr, 0x12, (u32)(address & 0xffff));
+ if (ret < 0) {
+ dev_err(dev, "air_mii_cl22_write, ret: %d\n", ret);
+ return ret;
+ }
+
+ for (offset = 0; offset < fw->size; offset += 4) {
+ write_data = (fw->data[offset + 3] << 8) | fw->data[offset + 2];
+ ret = air_mii_cl22_write(mbus, addr, 0x13, write_data);
+ if (ret < 0) {
+ dev_err(dev, "air_mii_cl22_write, ret: %d\n", ret);
+ return ret;
+ }
+ write_data = (fw->data[offset + 1] << 8) | fw->data[offset];
+ ret = air_mii_cl22_write(mbus, addr, 0x14, write_data);
+ if (ret < 0) {
+ dev_err(dev, "air_mii_cl22_write, ret: %d\n", ret);
+ return ret;
+ }
+ }
+ ret = air_mii_cl22_write(mbus, addr, 0x1F, 0);
+ if (ret < 0) {
+ dev_err(dev, "air_mii_cl22_write, ret: %d\n", ret);
+ return ret;
+ }
+ return 0;
+}
+
+static int en8811h_load_firmware(struct phy_device *phydev)
+{
+ struct device *dev = phydev_dev(phydev);
+ const struct firmware *fw;
+ const char *firmware;
+ int ret = 0;
+ u32 pbus_value = 0;
+#ifdef CONFIG_AIROHA_EN8811H_PHY_DEBUGFS
+ struct en8811h_priv *priv = phydev->priv;
+#endif
+ ret = air_buckpbus_reg_write(phydev, 0x0f0018, 0x0);
+ if (ret < 0)
+ return ret;
+ pbus_value = air_buckpbus_reg_read(phydev, 0x800000);
+ pbus_value |= BIT(11);
+ ret = air_buckpbus_reg_write(phydev, 0x800000, pbus_value);
+ if (ret < 0)
+ return ret;
+ firmware = EN8811H_MD32_DM;
+ ret = request_firmware_direct(&fw, firmware, dev);
+ if (ret < 0) {
+ dev_err(dev,
+ "failed to load firmware %s, ret: %d\n", firmware, ret);
+ return ret;
+ }
+#ifdef CONFIG_AIROHA_EN8811H_PHY_DEBUGFS
+ priv->dm_crc32 = ~crc32(~0, fw->data, fw->size);
+#endif
+ dev_info(dev, "%s: crc32=0x%x\n",
+ firmware, ~crc32(~0, fw->data, fw->size));
+ /* Download DM */
+ ret = MDIOWriteBuf(phydev, 0x00000000, fw);
+ release_firmware(fw);
+ if (ret < 0) {
+ dev_err(dev,
+ "MDIOWriteBuf 0x00000000 fail, ret: %d\n", ret);
+ return ret;
+ }
+
+ firmware = EN8811H_MD32_DSP;
+ ret = request_firmware_direct(&fw, firmware, dev);
+ if (ret < 0) {
+ dev_info(dev,
+ "failed to load firmware %s, ret: %d\n", firmware, ret);
+ return ret;
+ }
+#ifdef CONFIG_AIROHA_EN8811H_PHY_DEBUGFS
+ priv->dsp_crc32 = ~crc32(~0, fw->data, fw->size);
+#endif
+ dev_info(dev, "%s: crc32=0x%x\n",
+ firmware, ~crc32(~0, fw->data, fw->size));
+ /* Download PM */
+ ret = MDIOWriteBuf(phydev, 0x00100000, fw);
+ release_firmware(fw);
+ if (ret < 0) {
+ dev_err(dev,
+ "MDIOWriteBuf 0x00100000 fail , ret: %d\n", ret);
+ return ret;
+ }
+ pbus_value = air_buckpbus_reg_read(phydev, 0x800000);
+ pbus_value &= ~BIT(11);
+ ret = air_buckpbus_reg_write(phydev, 0x800000, pbus_value);
+ if (ret < 0)
+ return ret;
+ ret = air_buckpbus_reg_write(phydev, 0x0f0018, 0x01);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+#ifdef AIR_LED_SUPPORT
+static int airoha_led_set_usr_def(struct phy_device *phydev, u8 entity,
+ int polar, u16 on_evt, u16 blk_evt)
+{
+ int ret = 0;
+
+ if (polar == AIR_ACTIVE_HIGH)
+ on_evt |= LED_ON_POL;
+ else
+ on_evt &= ~LED_ON_POL;
+
+ ret = air_mii_cl45_write(phydev, 0x1f,
+ LED_ON_CTRL(entity), on_evt | LED_ON_EN);
+ if (ret < 0)
+ return ret;
+ ret = air_mii_cl45_write(phydev, 0x1f, LED_BLK_CTRL(entity), blk_evt);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+static int airoha_led_set_mode(struct phy_device *phydev, u8 mode)
+{
+ u16 cl45_data;
+ int err = 0;
+ struct device *dev = phydev_dev(phydev);
+
+ cl45_data = air_mii_cl45_read(phydev, 0x1f, LED_BCR);
+ switch (mode) {
+ case AIR_LED_MODE_DISABLE:
+ cl45_data &= ~LED_BCR_EXT_CTRL;
+ cl45_data &= ~LED_BCR_MODE_MASK;
+ cl45_data |= LED_BCR_MODE_DISABLE;
+ break;
+ case AIR_LED_MODE_USER_DEFINE:
+ cl45_data |= LED_BCR_EXT_CTRL;
+ cl45_data |= LED_BCR_CLK_EN;
+ break;
+ default:
+ dev_err(dev, "LED mode%d is not supported!\n", mode);
+ return -EINVAL;
+ }
+ err = air_mii_cl45_write(phydev, 0x1f, LED_BCR, cl45_data);
+ if (err < 0)
+ return err;
+ return 0;
+}
+
+static int airoha_led_set_state(struct phy_device *phydev, u8 entity, u8 state)
+{
+ u16 cl45_data = 0;
+ int err;
+
+ cl45_data = air_mii_cl45_read(phydev, 0x1f, LED_ON_CTRL(entity));
+ if (state == 1)
+ cl45_data |= LED_ON_EN;
+ else
+ cl45_data &= ~LED_ON_EN;
+
+ err = air_mii_cl45_write(phydev, 0x1f, LED_ON_CTRL(entity), cl45_data);
+ if (err < 0)
+ return err;
+ return 0;
+}
+
+static int en8811h_led_init(struct phy_device *phydev)
+{
+
+ unsigned long led_gpio = 0, reg_value = 0;
+ u16 cl45_data = led_dur;
+ int ret = 0, id;
+ struct device *dev = phydev_dev(phydev);
+
+ ret = air_mii_cl45_write(phydev, 0x1f, LED_BLK_DUR, cl45_data);
+ if (ret < 0)
+ return ret;
+ cl45_data >>= 1;
+ ret = air_mii_cl45_write(phydev, 0x1f, LED_ON_DUR, cl45_data);
+ if (ret < 0)
+ return ret;
+ ret = airoha_led_set_mode(phydev, AIR_LED_MODE_USER_DEFINE);
+ if (ret != 0) {
+ dev_err(dev, "led_set_mode fail(ret:%d)!\n", ret);
+ return ret;
+ }
+ for (id = 0; id < EN8811H_LED_COUNT; id++) {
+ /* LED0 <-> GPIO5, LED1 <-> GPIO4, LED0 <-> GPIO3 */
+ if (led_cfg[id].gpio != (id + (AIR_LED0_GPIO5 - (2 * id)))) {
+ dev_err(dev, "LED%d uses incorrect GPIO%d !\n",
+ id, led_cfg[id].gpio);
+ return -EINVAL;
+ }
+ ret = airoha_led_set_state(phydev, id, led_cfg[id].en);
+ if (ret != 0) {
+ dev_err(dev, "led_set_state fail(ret:%d)!\n", ret);
+ return ret;
+ }
+ if (led_cfg[id].en == 1) {
+ led_gpio |= BIT(led_cfg[id].gpio);
+ ret = airoha_led_set_usr_def(phydev, id,
+ led_cfg[id].pol, led_cfg[id].on_cfg,
+ led_cfg[id].blk_cfg);
+ if (ret != 0) {
+ dev_err(dev, "led_set_usr_def fail!\n");
+ return ret;
+ }
+ }
+ }
+ reg_value = air_buckpbus_reg_read(phydev, 0xcf8b8) | led_gpio;
+ ret = air_buckpbus_reg_write(phydev, 0xcf8b8, reg_value);
+ if (ret < 0)
+ return ret;
+ dev_info(dev, "LED initialize OK !\n");
+ return 0;
+}
+#endif /* AIR_LED_SUPPORT */
+#if (KERNEL_VERSION(4, 5, 0) < LINUX_VERSION_CODE)
+static int en8811h_get_features(struct phy_device *phydev)
+{
+ int ret;
+ struct device *dev = phydev_dev(phydev);
+
+ dev_dbg(dev, "%s()\n", __func__);
+ ret = air_pbus_reg_write(phydev, 0xcf928, 0x0);
+ if (ret < 0)
+ return ret;
+ ret = genphy_read_abilities(phydev);
+ if (ret)
+ return ret;
+ /* EN8811H supports 100M/1G/2.5G speed. */
+ linkmode_clear_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
+ phydev->supported);
+ linkmode_clear_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
+ phydev->supported);
+ linkmode_clear_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
+ phydev->supported);
+ linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
+ phydev->supported);
+ linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
+ phydev->supported);
+ linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
+ phydev->supported);
+ return 0;
+}
+#endif
+
+static int en8811h_probe(struct phy_device *phydev)
+{
+ int ret = 0;
+ int reg_value, pid1 = 0, pid2 = 0;
+ u32 retry, pbus_value = 0;
+ struct device *dev = phydev_dev(phydev);
+ struct mii_bus *mbus = phydev_mdio_bus(phydev);
+ int addr = phydev_addr(phydev);
+
+#ifdef CONFIG_AIROHA_EN8811H_PHY_DEBUGFS
+ struct en8811h_priv *priv;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+ phydev->priv = priv;
+#endif /*CONFIG_AIROHA_EN8811H_PHY_DEBUGFS*/
+ ret = air_pbus_reg_write(phydev, 0xcf928, 0x0);
+ if (ret < 0)
+ return ret;
+ pid1 = air_mii_cl22_read(mbus, addr, MII_PHYSID1);
+ if (pid1 < 0)
+ return pid1;
+ pid2 = air_mii_cl22_read(mbus, addr, MII_PHYSID2);
+ if (pid2 < 0)
+ return pid2;
+ dev_info(dev, "PHY = %x - %x\n", pid1, pid2);
+ if ((pid1 != EN8811H_PHY_ID1) || (pid2 != EN8811H_PHY_ID2)) {
+ dev_err(dev, "EN8811H dose not exist !\n");
+ return -ENODEV;
+ }
+ pbus_value = air_buckpbus_reg_read(phydev, 0xcf914);
+ dev_info(dev, "Bootmode: %s\n",
+ (GET_BIT(pbus_value, 24) ? "Flash" : "Download Code"));
+
+ ret = en8811h_load_firmware(phydev);
+ if (ret < 0) {
+ dev_err(dev, "EN8811H load firmware fail.\n");
+ return ret;
+ }
+#ifdef CONFIG_AIROHA_EN8811H_PHY_DEBUGFS
+ ret = airphy_debugfs_init(phydev);
+ if (ret < 0) {
+ dev_err(dev, "air_debug_procfs_init fail. (ret=%d)\n", ret);
+ air_debugfs_remove(phydev);
+ kfree(priv);
+ return ret;
+ }
+#endif /* CONFIG_AIROHA_EN8811H_PHY_DEBUGFS */
+ retry = MAX_RETRY;
+ do {
+ mdelay(300);
+ reg_value = air_mii_cl45_read(phydev, 0x1e, 0x8009);
+ if (reg_value == EN8811H_PHY_READY) {
+ dev_info(dev, "EN8811H PHY ready!\n");
+ break;
+ }
+ retry--;
+ } while (retry);
+ if (retry == 0) {
+ dev_err(dev, "MD32 FW is not ready.(Status 0x%x)\n", reg_value);
+ pbus_value = air_buckpbus_reg_read(phydev, 0x3b3c);
+ dev_err(dev,
+ "Check MD32 FW Version(0x3b3c) : %08x\n", pbus_value);
+ dev_err(dev,
+ "EN8811H initialize fail!\n");
+ return 0;
+ }
+ /* Mode selection*/
+ dev_info(dev, "EN8811H Mode 1 !\n");
+ ret = air_mii_cl45_write(phydev, 0x1e, 0x800c, 0x0);
+ if (ret < 0)
+ return ret;
+ ret = air_mii_cl45_write(phydev, 0x1e, 0x800d, 0x0);
+ if (ret < 0)
+ return ret;
+ ret = air_mii_cl45_write(phydev, 0x1e, 0x800e, 0x1101);
+ if (ret < 0)
+ return ret;
+ ret = air_mii_cl45_write(phydev, 0x1e, 0x800f, 0x0002);
+ if (ret < 0)
+ return ret;
+ /* Serdes polarity */
+ pbus_value = air_buckpbus_reg_read(phydev, 0xca0f8);
+ pbus_value &= ~0x3;
+ pbus_value |= (EN8811H_RX_POL_NORMAL | EN8811H_TX_POL_NORMAL);
+ ret = air_buckpbus_reg_write(phydev, 0xca0f8, pbus_value);
+ if (ret < 0)
+ return ret;
+ pbus_value = air_buckpbus_reg_read(phydev, 0xca0f8);
+ dev_info(dev, "Tx, Rx Polarity : %08x\n", pbus_value);
+ pbus_value = air_buckpbus_reg_read(phydev, 0x3b3c);
+ dev_info(dev, "MD32 FW Version : %08x\n", pbus_value);
+#if defined(AIR_LED_SUPPORT)
+ ret = en8811h_led_init(phydev);
+ if (ret < 0) {
+ dev_err(dev, "en8811h_led_init fail. (ret=%d)\n", ret);
+ return ret;
+ }
+#endif
+ dev_info(dev, "EN8811H initialize OK! (%s)\n", EN8811H_DRIVER_VERSION);
+ return 0;
+}
+void en8811h_remove(struct phy_device *phydev)
+{
+#ifdef CONFIG_AIROHA_EN8811H_PHY_DEBUGFS
+ struct en8811h_priv *priv = phydev->priv;
+ struct device *dev = phydev_dev(phydev);
+
+ dev_dbg(dev, "%s: start\n", __func__);
+ if (priv) {
+ dev_info(dev, "%s: air_debugfs_remove\n", __func__);
+ air_debugfs_remove(phydev);
+ kfree(priv);
+ }
+#endif /*CONFIG_AIROHA_EN8811H_PHY_DEBUGFS*/
+}
+
+static struct phy_driver en8811h_driver[] = {
+{
+ .phy_id = EN8811H_PHY_ID,
+ .name = "Airoha EN8811H",
+ .phy_id_mask = 0x0ffffff0,
+ .probe = en8811h_probe,
+ .remove = en8811h_remove,
+#if (KERNEL_VERSION(4, 5, 0) < LINUX_VERSION_CODE)
+ .get_features = en8811h_get_features,
+ .read_mmd = air_mii_cl45_read,
+ .write_mmd = air_mii_cl45_write,
+#endif
+} };
+
+int __init en8811h_phy_driver_register(void)
+{
+ int ret;
+#if (KERNEL_VERSION(4, 5, 0) > LINUX_VERSION_CODE)
+ ret = phy_driver_register(en8811h_driver);
+#else
+ ret = phy_driver_register(en8811h_driver, THIS_MODULE);
+#endif
+ if (!ret)
+ return 0;
+
+ phy_driver_unregister(en8811h_driver);
+ return ret;
+}
+
+void __exit en8811h_phy_driver_unregister(void)
+{
+ phy_driver_unregister(en8811h_driver);
+}
+
+module_init(en8811h_phy_driver_register);
+module_exit(en8811h_phy_driver_unregister);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3000-mtketh-add-threaded-napi-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3000-mtketh-add-threaded-napi-support.patch
deleted file mode 100755
index 99e3ecd..0000000
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3000-mtketh-add-threaded-napi-support.patch
+++ /dev/null
@@ -1,14 +0,0 @@
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index b6bdb978..9de1b0b6 100755
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -3696,6 +3696,9 @@ static int mtk_probe(struct platform_device *pdev)
- * for NAPI to work
- */
- init_dummy_netdev(ð->dummy_dev);
-+ eth->dummy_dev.threaded = 1;
-+ strcpy(eth->dummy_dev.name, "mtk_eth");
-+
- netif_napi_add(ð->dummy_dev, ð->tx_napi, mtk_napi_tx,
- MTK_NAPI_WEIGHT);
- netif_napi_add(ð->dummy_dev, ð->rx_napi[0].napi, mtk_napi_rx,
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3001-mtketh-add-qdma-sw-solution-for-mac80211-sdk.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3001-mtketh-add-qdma-sw-solution-for-mac80211-sdk.patch
deleted file mode 100755
index 2089f78..0000000
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3001-mtketh-add-qdma-sw-solution-for-mac80211-sdk.patch
+++ /dev/null
@@ -1,24 +0,0 @@
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 28cda15..d34a3a0 100755
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -24,6 +24,7 @@
- #include "mtk_eth_soc.h"
- #include "mtk_eth_dbg.h"
- #include "mtk_eth_reset.h"
-+#include "mtk_hnat/hnat.h"
-
- #if defined(CONFIG_NET_MEDIATEK_HNAT) || defined(CONFIG_NET_MEDIATEK_HNAT_MODULE)
- #include "mtk_hnat/nf_hnat_mtk.h"
-@@ -3722,6 +3722,10 @@ static int mtk_probe(struct platform_device *pdev)
- timer_setup(ð->mtk_dma_monitor_timer, mtk_dma_monitor, 0);
- eth->mtk_dma_monitor_timer.expires = jiffies;
- add_timer(ð->mtk_dma_monitor_timer);
--#endif
-+
-+ mtk_w32(eth, 0x00000404, MTK_QTX_CFG(MTK_QDMA_GMAC2_QID));
-+ mtk_w32(eth, 0x40000000, MTK_QTX_SCH(MTK_QDMA_GMAC2_QID));
-+ mtk_w32(eth, 0x80008000, QDMA_TX_4SCH_BASE(0));
-+#endif
-
- return 0;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3003-mt7622-backport-nf-hw-offload-framework-and-ups.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3003-mt7622-backport-nf-hw-offload-framework-and-ups.patch
index b52782f..9ccf9ce 100755
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3003-mt7622-backport-nf-hw-offload-framework-and-ups.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3003-mt7622-backport-nf-hw-offload-framework-and-ups.patch
@@ -237,7 +237,7 @@
index 000000000..66298e223
--- /dev/null
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
-@@ -0,0 +1,509 @@
+@@ -0,0 +1,510 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (C) 2020 Felix Fietkau <nbd@nbd.name> */
+
@@ -714,6 +714,7 @@
+ val = MTK_PPE_GLO_CFG_EN |
+ MTK_PPE_GLO_CFG_IP4_L4_CS_DROP |
+ MTK_PPE_GLO_CFG_IP4_CS_DROP |
++ MTK_PPE_GLO_CFG_MCAST_TB_EN |
+ MTK_PPE_GLO_CFG_FLOW_DROP_UPDATE;
+ ppe_w32(ppe, MTK_PPE_GLO_CFG, val);
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3005-add-wed.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3005-add-wed.patch
index 201a629..fe2dc53 100755
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3005-add-wed.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3005-add-wed.patch
@@ -138,7 +138,7 @@
index 819d8a0be..2121335a1
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -20,12 +21,14 @@
+@@ -20,11 +21,13 @@
#include <linux/pinctrl/devinfo.h>
#include <linux/phylink.h>
#include <linux/gpio/consumer.h>
@@ -148,7 +148,6 @@
#include "mtk_eth_soc.h"
#include "mtk_eth_dbg.h"
#include "mtk_eth_reset.h"
- #include "mtk_hnat/hnat.h"
+#include "mtk_wed.h"
#if defined(CONFIG_NET_MEDIATEK_HNAT) || defined(CONFIG_NET_MEDIATEK_HNAT_MODULE)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3006-ethernet-update-ppe-from-mt7622-to-mt7986.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3006-ethernet-update-ppe-from-mt7622-to-mt7986.patch
index c0efd12..dcfd527 100755
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3006-ethernet-update-ppe-from-mt7622-to-mt7986.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3006-ethernet-update-ppe-from-mt7622-to-mt7986.patch
@@ -49,7 +49,7 @@
@@ -3926,13 +3937,14 @@ static const struct mtk_soc_data mt7986_data = {
.required_clks = MT7986_CLKS_BITMAP,
.required_pctl = false,
- .has_sram = true,
+ .has_sram = false,
+ .offload_version = 2,
.rss_num = 0,
.txrx = {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3007-flow-offload-add-mkhnat-dual-ppe-new-v2.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3007-flow-offload-add-mkhnat-dual-ppe-new-v2.patch
index ee370b6..9957670 100755
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3007-flow-offload-add-mkhnat-dual-ppe-new-v2.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3007-flow-offload-add-mkhnat-dual-ppe-new-v2.patch
@@ -1,25 +1,25 @@
-From a59cb5c770a694cb34ab179ec59e91ba5c39908b Mon Sep 17 00:00:00 2001
-From: Bo Jiao <Bo.Jiao@mediatek.com>
-Date: Mon, 27 Jun 2022 14:48:35 +0800
-Subject: [PATCH 6/8] 9995-flow-offload-add-mkhnat-dual-ppe-new-v2
+From 8341e1b35ca14f303f828f96f5e63719f80be88e Mon Sep 17 00:00:00 2001
+From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
+Date: Wed, 23 Aug 2023 11:36:05 +0800
+Subject: [PATCH] 999-3007-flow-offload-add-mkhnat-dual-ppe-new-v2
---
arch/arm64/boot/dts/mediatek/mt7986a.dtsi | 1 +
drivers/net/ethernet/mediatek/mtk_eth_soc.c | 67 ++++++++++++++-----
- drivers/net/ethernet/mediatek/mtk_eth_soc.h | 10 ++-
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h | 14 +++-
drivers/net/ethernet/mediatek/mtk_ppe.c | 5 +-
drivers/net/ethernet/mediatek/mtk_ppe.h | 7 +-
.../net/ethernet/mediatek/mtk_ppe_debugfs.c | 27 ++++++--
- .../net/ethernet/mediatek/mtk_ppe_offload.c | 45 ++++++++++---
+ .../net/ethernet/mediatek/mtk_ppe_offload.c | 48 ++++++++++---
include/linux/netdevice.h | 4 ++
- 8 files changed, 125 insertions(+), 41 deletions(-)
+ 8 files changed, 131 insertions(+), 42 deletions(-)
mode change 100644 => 100755 drivers/net/ethernet/mediatek/mtk_ppe_offload.c
diff --git a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
-index 7f78de6b9..381136c21 100644
+index e5d4e12..0c54e12 100644
--- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
-@@ -479,6 +479,7 @@
+@@ -496,6 +496,7 @@
mediatek,ethsys = <ðsys>;
mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>;
mediatek,wed = <&wed0>, <&wed1>;
@@ -28,10 +28,10 @@
#address-cells = <1>;
#size-cells = <0>;
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 01fc1e5c0..3f67bebfe 100644
+index f019c56..81b68d6 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -1732,6 +1732,7 @@ static int mtk_poll_rx(struct napi_struc
+@@ -2097,6 +2097,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
u8 *data, *new_data;
struct mtk_rx_dma_v2 *rxd, trxd;
int done = 0;
@@ -39,7 +39,7 @@
if (unlikely(!ring))
goto rx_done;
-@@ -1843,14 +1844,20 @@ static int mtk_poll_rx(struct napi_struc
+@@ -2209,14 +2210,20 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
#if defined(CONFIG_MEDIATEK_NETSYS_RX_V2)
reason = FIELD_GET(MTK_RXD5_PPE_CPU_REASON_V2, trxd.rxd5);
@@ -66,9 +66,9 @@
#endif
if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) {
-@@ -3184,8 +3191,12 @@ static int mtk_open(struct net_device *d
- if (!phy_node && eth->xgmii->regmap_sgmii[mac->id])
- regmap_write(eth->xgmii->regmap_sgmii[mac->id], SGMSYS_QPHY_PWR_STATE_CTRL, 0);
+@@ -3588,8 +3595,12 @@ static int mtk_open(struct net_device *dev)
+ regmap_write(eth->sgmii->pcs[id].regmap,
+ SGMSYS_QPHY_PWR_STATE_CTRL, 0);
- if (eth->soc->offload_version && mtk_ppe_start(ð->ppe) == 0)
- gdm_config = MTK_GDMA_TO_PPE;
@@ -81,7 +81,7 @@
mtk_gdm_config(eth, mac->id, gdm_config);
-@@ -3268,8 +3279,10 @@ static int mtk_stop(struct net_device *d
+@@ -3671,8 +3682,10 @@ static int mtk_stop(struct net_device *dev)
mtk_dma_free(eth);
@@ -94,7 +94,7 @@
return 0;
}
-@@ -4408,15 +4421,35 @@ static int mtk_probe(struct platform_dev
+@@ -4958,15 +4971,35 @@ static int mtk_probe(struct platform_device *pdev)
}
if (eth->soc->offload_version) {
@@ -138,10 +138,10 @@
for (i = 0; i < MTK_MAX_DEVS; i++) {
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-index fce1a7172..b4de7c0c6 100644
+index 8675c86..fad3e73 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -118,7 +118,12 @@
+@@ -130,7 +130,12 @@
#define MTK_GDMA_UCS_EN BIT(20)
#define MTK_GDMA_STRP_CRC BIT(16)
#define MTK_GDMA_TO_PDMA 0x0
@@ -155,7 +155,7 @@
#define MTK_GDMA_DROP_ALL 0x7777
/* GDM Egress Control Register */
-@@ -1612,7 +1617,8 @@ struct mtk_eth {
+@@ -1856,7 +1861,8 @@ struct mtk_eth {
spinlock_t syscfg0_lock;
struct timer_list mtk_dma_monitor_timer;
@@ -165,8 +165,8 @@
struct rhashtable flow_table;
};
-@@ -1668,9 +1674,11 @@ int mtk_gmac_usxgmii_path_setup(struct m
- void mtk_usxgmii_reset(struct mtk_xgmii *ss, int mac_id);
+@@ -1918,9 +1924,11 @@ int mtk_usxgmii_init(struct mtk_eth *eth, struct device_node *r);
+ int mtk_toprgu_init(struct mtk_eth *eth, struct device_node *r);
int mtk_dump_usxgmii(struct regmap *pmap, char *name, u32 offset, u32 range);
-int mtk_eth_offload_init(struct mtk_eth *eth);
@@ -179,10 +179,10 @@
+int mtk_ppe_debugfs_init(struct mtk_eth *eth);
#endif /* MTK_ETH_H */
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c
-index d46e91178..3d6ff30ba 100755
+index 7506670..0ff1fef 100755
--- a/drivers/net/ethernet/mediatek/mtk_ppe.c
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
-@@ -677,7 +677,7 @@ int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
+@@ -696,7 +696,7 @@ int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
}
struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base,
@@ -191,7 +191,7 @@
{
struct device *dev = eth->dev;
struct mtk_foe_entry *foe;
-@@ -696,6 +696,7 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base,
+@@ -715,6 +715,7 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base,
ppe->eth = eth;
ppe->dev = dev;
ppe->version = version;
@@ -199,7 +199,7 @@
foe = dmam_alloc_coherent(ppe->dev, MTK_PPE_ENTRIES * sizeof(*foe),
&ppe->foe_phys, GFP_KERNEL);
-@@ -704,8 +705,6 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base,
+@@ -723,8 +724,6 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base,
ppe->foe_table = foe;
@@ -209,11 +209,10 @@
}
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.h b/drivers/net/ethernet/mediatek/mtk_ppe.h
-index a76f4b0ac..21cc55145 100644
+index 7012351..86bbac8 100644
--- a/drivers/net/ethernet/mediatek/mtk_ppe.h
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
-@@ -8,10 +8,12 @@
- #include <linux/bitfield.h>
+@@ -9,8 +9,10 @@
#include <linux/rhashtable.h>
#if defined(CONFIG_MEDIATEK_NETSYS_V2)
@@ -224,8 +223,7 @@
#define MTK_ETH_PPE_BASE 0xc00
#endif
- #define MTK_PPE_ENTRIES_SHIFT 3
-@@ -253,6 +255,7 @@ struct mtk_flow_entry {
+@@ -299,6 +301,7 @@ struct mtk_flow_entry {
};
};
u8 type;
@@ -233,7 +231,7 @@
s8 wed_index;
u16 hash;
union {
-@@ -272,6 +275,7 @@ struct mtk_ppe {
+@@ -318,6 +321,7 @@ struct mtk_ppe {
struct device *dev;
void __iomem *base;
int version;
@@ -241,7 +239,7 @@
struct mtk_foe_entry *foe_table;
dma_addr_t foe_phys;
-@@ -284,7 +288,7 @@ struct mtk_ppe {
+@@ -330,7 +334,7 @@ struct mtk_ppe {
void *acct_table;
};
@@ -250,7 +248,7 @@
int mtk_ppe_start(struct mtk_ppe *ppe);
int mtk_ppe_stop(struct mtk_ppe *ppe);
-@@ -335,6 +339,5 @@ int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq,
+@@ -381,6 +385,5 @@ int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq,
int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
@@ -258,7 +256,7 @@
#endif
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c b/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c
-index a591ab1fd..f4ebe5944 100644
+index a591ab1..f4ebe59 100644
--- a/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c
@@ -73,9 +73,8 @@ mtk_print_addr_info(struct seq_file *m, struct mtk_flow_addr_info *ai)
@@ -332,10 +330,10 @@
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
old mode 100644
new mode 100755
-index 5a4201447..2f7d76d3b
+index 77594f3..18f6333
--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
-@@ -226,8 +226,10 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
+@@ -229,9 +229,12 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
struct flow_action_entry *act;
struct mtk_flow_data data = {};
struct mtk_foe_entry foe;
@@ -345,9 +343,11 @@
+ struct net_device_path_ctx ctx = {};
+ struct net_device_path path = {};
int offload_type = 0;
++ int ppe_index = 0;
int wed_index = -1;
u16 addr_type = 0;
-@@ -242,6 +244,10 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
+ u8 l4proto = 0;
+@@ -245,6 +248,10 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
struct flow_match_meta match;
flow_rule_match_meta(rule, &match);
@@ -358,45 +358,49 @@
} else {
return -EOPNOTSUPP;
}
-@@ -435,11 +441,27 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
- if (!entry)
- return -ENOMEM;
+@@ -347,6 +354,20 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
+ if (err)
+ return err;
-+ i = 0;
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+ if (idev && idev->netdev_ops->ndo_fill_receive_path) {
+ ctx.dev = idev;
+ idev->netdev_ops->ndo_fill_receive_path(&ctx, &path);
-+ i = path.mtk_wdma.wdma_idx;
-+ if (i >= eth->ppe_num) {
++ ppe_index = path.mtk_wdma.wdma_idx;
++ if (ppe_index >= eth->ppe_num) {
+ if (printk_ratelimit())
-+ pr_info("[%s] PPE%d doesn't exist, please check mtketh-ppe-num in dts !\n", __func__, i);
++ pr_info("[%s] PPE%d doesn't exist, please check mtketh-ppe-num in dts !\n", __func__, ppe_index);
+
+ return -EINVAL;
+ }
+ }
+#endif
+
+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
+ struct flow_match_ports ports;
+
+@@ -440,9 +461,10 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
+
entry->cookie = f->cookie;
memcpy(&entry->data, &foe, sizeof(entry->data));
-+ entry->ppe_index = i;
++ entry->ppe_index = ppe_index;
entry->wed_index = wed_index;
- if (mtk_foe_entry_commit(eth->ppe, entry) < 0)
-+ if (mtk_foe_entry_commit(eth->ppe[i], entry) < 0)
++ if (mtk_foe_entry_commit(eth->ppe[ppe_index], entry) < 0)
goto free;
err = rhashtable_insert_fast(ð->flow_table, &entry->node,
-@@ -450,7 +470,7 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
+@@ -453,7 +475,7 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
return 0;
clear:
- mtk_foe_entry_clear(eth->ppe, entry);
-+ mtk_foe_entry_clear(eth->ppe[i], entry);
++ mtk_foe_entry_clear(eth->ppe[ppe_index], entry);
free:
kfree(entry);
if (wed_index >= 0)
-@@ -462,13 +482,15 @@ static int
+@@ -465,13 +487,15 @@ static int
mtk_flow_offload_destroy(struct mtk_eth *eth, struct flow_cls_offload *f)
{
struct mtk_flow_entry *entry;
@@ -413,7 +417,7 @@
rhashtable_remove_fast(ð->flow_table, &entry->node,
mtk_flow_ht_params);
if (entry->wed_index >= 0)
-@@ -483,13 +505,15 @@ mtk_flow_offload_stats(struct mtk_eth *eth, struct flow_cls_offload *f)
+@@ -486,13 +510,15 @@ mtk_flow_offload_stats(struct mtk_eth *eth, struct flow_cls_offload *f)
{
struct mtk_flow_entry *entry;
u32 idle;
@@ -430,7 +434,7 @@
f->stats.lastused = jiffies - idle * HZ;
return 0;
-@@ -540,10 +564,12 @@ mtk_eth_setup_tc_block(struct net_device *dev, struct flow_block_offload *f)
+@@ -543,10 +569,12 @@ mtk_eth_setup_tc_block(struct net_device *dev, struct flow_block_offload *f)
static LIST_HEAD(block_cb_list);
struct flow_block_cb *block_cb;
flow_setup_cb_t *cb;
@@ -446,7 +450,7 @@
if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
return -EOPNOTSUPP;
-@@ -591,9 +618,9 @@ int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type,
+@@ -603,9 +631,9 @@ int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type,
}
}
@@ -459,10 +463,10 @@
return rhashtable_init(ð->flow_table, &mtk_flow_ht_params);
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
-index 35998b1a7..0ada2461b 100644
+index 59a3e96..0967dc2 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
-@@ -1302,6 +1302,8 @@ struct tlsdev_ops;
+@@ -1311,6 +1311,8 @@ struct tlsdev_ops;
* rtnl_lock is not held.
* int (*ndo_fill_forward_path)(struct net_device_path_ctx *ctx, struct net_device_path *path);
* Get the forwarding path to reach the real device from the HW destination address
@@ -471,7 +475,7 @@
*/
struct net_device_ops {
int (*ndo_init)(struct net_device *dev);
-@@ -1501,6 +1503,8 @@ struct net_device_ops {
+@@ -1510,6 +1512,8 @@ struct net_device_ops {
struct devlink_port * (*ndo_get_devlink_port)(struct net_device *dev);
int (*ndo_fill_forward_path)(struct net_device_path_ctx *ctx,
struct net_device_path *path);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3008-add-wed-tx-support-for-mt7986.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3008-add-wed-tx-support-for-mt7986.patch
old mode 100755
new mode 100644
index 7734ce2..f6fcae3
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3008-add-wed-tx-support-for-mt7986.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3008-add-wed-tx-support-for-mt7986.patch
@@ -6,12 +6,12 @@
---
arch/arm64/boot/dts/mediatek/mt7986a.dtsi | 2 +
arch/arm64/boot/dts/mediatek/mt7986b.dtsi | 2 +
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 8 +-
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 17 +-
drivers/net/ethernet/mediatek/mtk_eth_soc.h | 5 +
- drivers/net/ethernet/mediatek/mtk_wed.c | 502 +++++++++++++-----
+ drivers/net/ethernet/mediatek/mtk_wed.c | 496 +++++++++++++-----
drivers/net/ethernet/mediatek/mtk_wed.h | 18 +-
.../net/ethernet/mediatek/mtk_wed_debugfs.c | 3 +
- drivers/net/ethernet/mediatek/mtk_wed_regs.h | 127 ++++-
+ drivers/net/ethernet/mediatek/mtk_wed_regs.h | 130 ++++-
include/linux/soc/mediatek/mtk_wed.h | 29 +-
9 files changed, 546 insertions(+), 150 deletions(-)
@@ -59,7 +59,7 @@
index 3f67bebfe..ac021e2ed 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -3579,6 +3579,7 @@ static int mtk_probe(struct platform_device *pdev)
+@@ -4807,6 +4807,7 @@ static int mtk_probe(struct platform_device *pdev)
{
struct device_node *mac_np;
struct mtk_eth *eth;
@@ -67,15 +67,26 @@
int err, i;
eth = devm_kzalloc(&pdev->dev, sizeof(*eth), GFP_KERNEL);
-@@ -3594,7 +3595,6 @@ static int mtk_probe(struct platform_device *pdev)
- return PTR_ERR(eth->base);
+@@ -4827,13 +4828,12 @@ static int mtk_probe(struct platform_device *pdev)
+ return PTR_ERR(eth->sram_base);
+ }
- if(eth->soc->has_sram) {
+- if(eth->soc->has_sram) {
- struct resource *res;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (unlikely(!res))
- return -EINVAL;
-@@ -3682,12 +3682,16 @@ static int mtk_probe(struct platform_device *pdev)
+- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+- if (unlikely(!res))
+- return -EINVAL;
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (unlikely(!res))
++ return -EINVAL;
++
++ if(eth->soc->has_sram)
+ eth->phy_scratch_ring = res->start + MTK_ETH_SRAM_OFFSET;
+- }
+
+ mtk_get_hwver(eth);
+
+@@ -4929,12 +4929,15 @@ static int mtk_probe(struct platform_device *pdev)
MTK_WDMA1_BASE
};
void __iomem *wdma;
@@ -86,8 +97,7 @@
wdma = eth->base + wdma_regs[i];
- mtk_wed_add_hw(np, eth, wdma, i);
-+ if (res)
-+ wdma_phy = res->start + wdma_regs[i];
++ wdma_phy = res->start + wdma_regs[i];
+
+ mtk_wed_add_hw(np, eth, wdma, wdma_phy, i);
}
@@ -832,20 +842,7 @@
}
return 0;
-@@ -706,10 +935,8 @@ mtk_wed_irq_get(struct mtk_wed_device *dev, u32 mask)
- val = wed_r32(dev, MTK_WED_EXT_INT_STATUS);
- wed_w32(dev, MTK_WED_EXT_INT_STATUS, val);
- val &= MTK_WED_EXT_INT_STATUS_ERROR_MASK;
-- if (!dev->hw->num_flows)
-- val &= ~MTK_WED_EXT_INT_STATUS_TKID_WO_PYLD;
-- if (val && net_ratelimit())
-- pr_err("mtk_wed%d: error status=%08x\n", dev->hw->index, val);
-+ WARN_RATELIMIT(val, "mtk_wed%d: error status=%08x\n",
-+ dev->hw->index, val);
-
- val = wed_r32(dev, MTK_WED_INT_STATUS);
- val &= mask;
-@@ -780,7 +1007,8 @@ out:
+@@ -780,7 +1009,8 @@ out:
}
void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
@@ -855,7 +852,7 @@
{
static const struct mtk_wed_ops wed_ops = {
.attach = mtk_wed_attach,
-@@ -830,21 +1058,27 @@ void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
+@@ -830,21 +1060,27 @@ void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
hw->eth = eth;
hw->dev = &pdev->dev;
hw->wdma = wdma;
@@ -992,7 +989,7 @@
#define MTK_WED_RESET 0x008
#define MTK_WED_RESET_TX_BM BIT(0)
#define MTK_WED_RESET_TX_FREE_AGENT BIT(4)
-@@ -41,6 +51,7 @@ struct mtk_wdma_desc {
+@@ -41,6 +55,7 @@ struct mtk_wdma_desc {
#define MTK_WED_CTRL_RESERVE_EN BIT(12)
#define MTK_WED_CTRL_RESERVE_BUSY BIT(13)
#define MTK_WED_CTRL_FINAL_DIDX_READ BIT(24)
@@ -1000,7 +997,7 @@
#define MTK_WED_CTRL_MIB_READ_CLEAR BIT(28)
#define MTK_WED_EXT_INT_STATUS 0x020
-@@ -49,6 +60,10 @@ struct mtk_wdma_desc {
+@@ -49,6 +64,10 @@ struct mtk_wdma_desc {
#define MTK_WED_EXT_INT_STATUS_TKID_TITO_INVALID BIT(4)
#define MTK_WED_EXT_INT_STATUS_TX_FBUF_LO_TH BIT(8)
#define MTK_WED_EXT_INT_STATUS_TX_FBUF_HI_TH BIT(9)
@@ -1011,7 +1008,7 @@
#define MTK_WED_EXT_INT_STATUS_RX_FBUF_LO_TH BIT(12)
#define MTK_WED_EXT_INT_STATUS_RX_FBUF_HI_TH BIT(13)
#define MTK_WED_EXT_INT_STATUS_RX_DRV_R_RESP_ERR BIT(16)
-@@ -57,16 +71,23 @@ struct mtk_wdma_desc {
+@@ -57,16 +76,23 @@ struct mtk_wdma_desc {
#define MTK_WED_EXT_INT_STATUS_RX_DRV_INIT_WDMA_EN BIT(19)
#define MTK_WED_EXT_INT_STATUS_RX_DRV_BM_DMAD_COHERENT BIT(20)
#define MTK_WED_EXT_INT_STATUS_TX_DRV_R_RESP_ERR BIT(21)
@@ -1038,7 +1035,7 @@
#define MTK_WED_EXT_INT_MASK 0x028
-@@ -80,10 +103,6 @@ struct mtk_wdma_desc {
+@@ -80,10 +106,6 @@ struct mtk_wdma_desc {
#define MTK_WED_TX_BM_BASE 0x084
@@ -1049,7 +1046,7 @@
#define MTK_WED_TX_BM_BUF_LEN 0x08c
#define MTK_WED_TX_BM_INTF 0x09c
-@@ -93,9 +112,38 @@ struct mtk_wdma_desc {
+@@ -93,9 +115,38 @@ struct mtk_wdma_desc {
#define MTK_WED_TX_BM_INTF_TKID_READ BIT(29)
#define MTK_WED_TX_BM_DYN_THR 0x0a0
@@ -1088,7 +1085,7 @@
#define MTK_WED_INT_STATUS 0x200
#define MTK_WED_INT_MASK 0x204
-@@ -125,6 +173,7 @@ struct mtk_wdma_desc {
+@@ -125,6 +176,7 @@ struct mtk_wdma_desc {
#define MTK_WED_RESET_IDX_RX GENMASK(17, 16)
#define MTK_WED_TX_MIB(_n) (0x2a0 + (_n) * 4)
@@ -1096,7 +1093,7 @@
#define MTK_WED_RING_TX(_n) (0x300 + (_n) * 0x10)
-@@ -139,6 +188,19 @@ struct mtk_wdma_desc {
+@@ -139,6 +191,19 @@ struct mtk_wdma_desc {
#define MTK_WED_WPDMA_GLO_CFG_TX_DRV_BUSY BIT(1)
#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_EN BIT(2)
#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_BUSY BIT(3)
@@ -1116,7 +1113,7 @@
#define MTK_WED_WPDMA_GLO_CFG_RX_BT_SIZE GENMASK(5, 4)
#define MTK_WED_WPDMA_GLO_CFG_TX_WB_DDONE BIT(6)
#define MTK_WED_WPDMA_GLO_CFG_BIG_ENDIAN BIT(7)
-@@ -152,24 +214,54 @@ struct mtk_wdma_desc {
+@@ -152,24 +217,54 @@ struct mtk_wdma_desc {
#define MTK_WED_WPDMA_GLO_CFG_FIRST_TOKEN_ONLY BIT(26)
#define MTK_WED_WPDMA_GLO_CFG_OMIT_RX_INFO BIT(27)
#define MTK_WED_WPDMA_GLO_CFG_OMIT_TX_INFO BIT(28)
@@ -1172,7 +1169,7 @@
#define MTK_WED_WPDMA_TX_MIB(_n) (0x5a0 + (_n) * 4)
#define MTK_WED_WPDMA_TX_COHERENT_MIB(_n) (0x5d0 + (_n) * 4)
-@@ -203,14 +295,22 @@ struct mtk_wdma_desc {
+@@ -203,14 +298,22 @@ struct mtk_wdma_desc {
#define MTK_WED_WDMA_RESET_IDX_RX GENMASK(17, 16)
#define MTK_WED_WDMA_RESET_IDX_DRV GENMASK(25, 24)
@@ -1196,7 +1193,7 @@
#define MTK_WED_WDMA_RX_MIB(_n) (0xae0 + (_n) * 4)
#define MTK_WED_WDMA_RX_RECYCLE_MIB(_n) (0xae8 + (_n) * 4)
-@@ -221,14 +321,21 @@ struct mtk_wdma_desc {
+@@ -221,14 +324,21 @@ struct mtk_wdma_desc {
#define MTK_WED_RING_OFS_CPU_IDX 0x08
#define MTK_WED_RING_OFS_DMA_IDX 0x0c
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3012-ethernet-update-ppe-backward-compatible-two-way-hash.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3012-ethernet-update-ppe-backward-compatible-two-way-hash.patch
index cfe29e7..554a0ee 100755
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3012-ethernet-update-ppe-backward-compatible-two-way-hash.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3012-ethernet-update-ppe-backward-compatible-two-way-hash.patch
@@ -47,7 +47,7 @@
@@ -4635,6 +4640,7 @@ static const struct mtk_soc_data mt7986_
.required_clks = MT7986_CLKS_BITMAP,
.required_pctl = false,
- .has_sram = true,
+ .has_sram = false,
+ .hash_way = 4,
.offload_version = 2,
.rss_num = 0,
@@ -55,7 +55,7 @@
@@ -4651,6 +4657,8 @@ static const struct mtk_soc_data mt7981_
.required_clks = MT7981_CLKS_BITMAP,
.required_pctl = false,
- .has_sram = true,
+ .has_sram = false,
+ .hash_way = 4,
+ .offload_version = 2,
.rss_num = 0,
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3013-flow-offload-add-mtkhnat-flow-accounting.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3013-flow-offload-add-mtkhnat-flow-accounting.patch
index ed90d2c..b29a907 100755
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3013-flow-offload-add-mtkhnat-flow-accounting.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3013-flow-offload-add-mtkhnat-flow-accounting.patch
@@ -55,7 +55,7 @@
@@ -4138,6 +4144,7 @@ static const struct mtk_soc_data mt7986_data = {
.required_clks = MT7986_CLKS_BITMAP,
.required_pctl = false,
- .has_sram = true,
+ .has_sram = false,
+ .has_accounting = true,
.hash_way = 4,
.offload_version = 2,
@@ -63,7 +63,7 @@
@@ -4155,6 +4162,7 @@ static const struct mtk_soc_data mt7981_data = {
.required_clks = MT7981_CLKS_BITMAP,
.required_pctl = false,
- .has_sram = true,
+ .has_sram = false,
+ .has_accounting = true,
.hash_way = 4,
.offload_version = 2,
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3014-flow-offload-add-mtkhnat-qdma-qos.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3014-flow-offload-add-mtkhnat-qdma-qos.patch
index fd9a5d4..74a937e 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3014-flow-offload-add-mtkhnat-qdma-qos.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3014-flow-offload-add-mtkhnat-qdma-qos.patch
@@ -1,5 +1,23 @@
+From e2277f2ea6c9657b727b082f7baa967ef94861dc Mon Sep 17 00:00:00 2001
+From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
+Date: Sat, 26 Aug 2023 00:38:09 +0800
+Subject: [PATCH] 999-3014-flow-offload-add-mtkhnat-qdma-qos
+
+---
+ drivers/net/ethernet/mediatek/Makefile | 2 +-
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 10 +
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h | 63 ++-
+ drivers/net/ethernet/mediatek/mtk_ppe.c | 48 +-
+ drivers/net/ethernet/mediatek/mtk_ppe.h | 4 +
+ .../net/ethernet/mediatek/mtk_ppe_offload.c | 28 +-
+ .../net/ethernet/mediatek/mtk_qdma_debugfs.c | 439 ++++++++++++++++++
+ include/net/flow_offload.h | 1 +
+ net/netfilter/nf_flow_table_offload.c | 4 +-
+ 9 files changed, 593 insertions(+), 6 deletions(-)
+ create mode 100644 drivers/net/ethernet/mediatek/mtk_qdma_debugfs.c
+
diff --git a/drivers/net/ethernet/mediatek/Makefile b/drivers/net/ethernet/mediatek/Makefile
-index 0c724a5..93cd55f 100644
+index fdbb90f..c7d2296 100644
--- a/drivers/net/ethernet/mediatek/Makefile
+++ b/drivers/net/ethernet/mediatek/Makefile
@@ -5,7 +5,7 @@
@@ -12,10 +30,10 @@
ifdef CONFIG_DEBUG_FS
mtk_eth-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed_debugfs.o
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index ca76047..809c735 100644
+index 9102144..a370547 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -4787,6 +4787,8 @@ static int mtk_probe(struct platform_device *pdev)
+@@ -5085,6 +5085,8 @@ static int mtk_probe(struct platform_device *pdev)
}
mtk_ppe_debugfs_init(eth);
@@ -24,7 +42,7 @@
}
for (i = 0; i < MTK_MAX_DEVS; i++) {
-@@ -4901,6 +4903,7 @@ static const struct mtk_soc_data mt2701_data = {
+@@ -5197,6 +5199,7 @@ static const struct mtk_soc_data mt2701_data = {
.rx_dma_l4_valid = RX_DMA_L4_VALID,
.dma_max_len = MTK_TX_DMA_BUF_LEN,
.dma_len_offset = MTK_TX_DMA_BUF_SHIFT,
@@ -32,7 +50,7 @@
},
};
-@@ -4920,6 +4923,7 @@ static const struct mtk_soc_data mt7621_data = {
+@@ -5217,6 +5220,7 @@ static const struct mtk_soc_data mt7621_data = {
.rxd_size = sizeof(struct mtk_rx_dma),
.dma_max_len = MTK_TX_DMA_BUF_LEN,
.dma_len_offset = MTK_TX_DMA_BUF_SHIFT,
@@ -40,7 +58,7 @@
},
};
-@@ -4940,6 +4944,7 @@ static const struct mtk_soc_data mt7622_data = {
+@@ -5238,6 +5242,7 @@ static const struct mtk_soc_data mt7622_data = {
.rx_dma_l4_valid = RX_DMA_L4_VALID,
.dma_max_len = MTK_TX_DMA_BUF_LEN,
.dma_len_offset = MTK_TX_DMA_BUF_SHIFT,
@@ -48,7 +66,7 @@
},
};
-@@ -4959,6 +4964,7 @@ static const struct mtk_soc_data mt7623_data = {
+@@ -5258,6 +5263,7 @@ static const struct mtk_soc_data mt7623_data = {
.rx_dma_l4_valid = RX_DMA_L4_VALID,
.dma_max_len = MTK_TX_DMA_BUF_LEN,
.dma_len_offset = MTK_TX_DMA_BUF_SHIFT,
@@ -56,7 +74,7 @@
},
};
-@@ -4997,6 +5003,7 @@ static const struct mtk_soc_data mt7986_data = {
+@@ -5298,6 +5304,7 @@ static const struct mtk_soc_data mt7986_data = {
.rx_dma_l4_valid = RX_DMA_L4_VALID_V2,
.dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
.dma_len_offset = MTK_TX_DMA_BUF_SHIFT_V2,
@@ -64,7 +82,7 @@
},
};
-@@ -5017,6 +5024,7 @@ static const struct mtk_soc_data mt7981_data = {
+@@ -5319,6 +5326,7 @@ static const struct mtk_soc_data mt7981_data = {
.rx_dma_l4_valid = RX_DMA_L4_VALID_V2,
.dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
.dma_len_offset = MTK_TX_DMA_BUF_SHIFT_V2,
@@ -72,7 +90,7 @@
},
};
-@@ -5034,6 +5042,7 @@ static const struct mtk_soc_data mt7988_data = {
+@@ -5337,6 +5345,7 @@ static const struct mtk_soc_data mt7988_data = {
.rx_dma_l4_valid = RX_DMA_L4_VALID_V2,
.dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
.dma_len_offset = MTK_TX_DMA_BUF_SHIFT_V2,
@@ -80,7 +98,7 @@
},
};
-@@ -5051,6 +5060,7 @@ static const struct mtk_soc_data rt5350_data = {
+@@ -5355,6 +5364,7 @@ static const struct mtk_soc_data rt5350_data = {
.rx_dma_l4_valid = RX_DMA_L4_VALID_PDMA,
.dma_max_len = MTK_TX_DMA_BUF_LEN,
.dma_len_offset = MTK_TX_DMA_BUF_SHIFT,
@@ -89,10 +107,10 @@
};
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-index c6afff5..bd73c27 100644
+index db139a1..a7892e2 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -385,10 +385,21 @@
+@@ -398,10 +398,21 @@
/* QDMA TX Queue Configuration Registers */
#define MTK_QTX_CFG(x) (QDMA_BASE + (x * 0x10))
@@ -114,7 +132,7 @@
/* QDMA RX Base Pointer Register */
#define MTK_QRX_BASE_PTR0 (QDMA_BASE + 0x100)
-@@ -406,7 +417,9 @@
+@@ -419,7 +430,9 @@
#define MTK_QRX_DRX_IDX0 (QDMA_BASE + 0x10c)
/* QDMA Page Configuration Register */
@@ -125,7 +143,7 @@
/* QDMA Global Configuration Register */
#define MTK_QDMA_GLO_CFG (QDMA_BASE + 0x204)
-@@ -443,6 +456,9 @@
+@@ -456,6 +469,9 @@
#define FC_THRES_DROP_EN (7 << 16)
#define FC_THRES_MIN 0x4444
@@ -134,8 +152,8 @@
+
/* QDMA Interrupt Status Register */
#define MTK_QDMA_INT_STATUS (QDMA_BASE + 0x218)
- #if defined(CONFIG_MEDIATEK_NETSYS_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
-@@ -478,6 +494,11 @@
+ #if defined(CONFIG_MEDIATEK_NETSYS_RX_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
+@@ -492,6 +508,11 @@
/* QDMA Interrupt Mask Register */
#define MTK_QDMA_HRED2 (QDMA_BASE + 0x244)
@@ -147,7 +165,7 @@
/* QDMA TX Forward CPU Pointer Register */
#define MTK_QTX_CTX_PTR (QDMA_BASE +0x300)
-@@ -505,6 +526,14 @@
+@@ -519,6 +540,14 @@
/* QDMA FQ Free Page Buffer Length Register */
#define MTK_QDMA_FQ_BLEN (QDMA_BASE +0x32c)
@@ -162,7 +180,7 @@
/* WDMA Registers */
#define MTK_WDMA_CTX_PTR(x) (WDMA_BASE(x) + 0x8)
#define MTK_WDMA_DTX_PTR(x) (WDMA_BASE(x) + 0xC)
-@@ -1596,6 +1625,7 @@ struct mtk_soc_data {
+@@ -1682,6 +1711,7 @@ struct mtk_soc_data {
u32 rx_dma_l4_valid;
u32 dma_max_len;
u32 dma_len_offset;
@@ -170,7 +188,7 @@
} txrx;
};
-@@ -1736,6 +1766,7 @@ struct mtk_eth {
+@@ -1868,6 +1898,7 @@ struct mtk_eth {
spinlock_t syscfg0_lock;
struct timer_list mtk_dma_monitor_timer;
@@ -178,18 +196,62 @@
u8 ppe_num;
struct mtk_ppe *ppe[MTK_MAX_PPE_NUM];
struct rhashtable flow_table;
-@@ -1815,4 +1846,6 @@ int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type,
- void mtk_eth_set_dma_device(struct mtk_eth *eth, struct device *dma_dev);
+@@ -1906,6 +1937,34 @@ extern const struct of_device_id of_mtk_match[];
+ extern u32 mtk_hwlro_stats_ebl;
+ extern u32 dbg_show_level;
+
++static inline void mtk_set_ib1_sp(struct mtk_eth *eth, struct mtk_foe_entry *foe, u32 val)
++{
++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
++ foe->ib1 |= FIELD_PREP(MTK_FOE_IB1_UNBIND_SRC_PORT, val);
++}
++
++static inline u32 mtk_get_ib1_sp(struct mtk_eth *eth, struct mtk_foe_entry *foe)
++{
++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
++ return FIELD_GET(MTK_FOE_IB1_UNBIND_SRC_PORT, foe->ib1);
++
++ return 0;
++}
++
++static inline int
++mtk_ppe_check_pppq_path(struct mtk_eth *eth, struct mtk_foe_entry *foe, int dsa_port)
++{
++ u32 sp = mtk_get_ib1_sp(eth, foe);
++
++ if ((dsa_port >= 0 && dsa_port <= 4) ||
++ (dsa_port == 5 && (sp == PSE_WDMA0_PORT ||
++ sp == PSE_WDMA1_PORT ||
++ sp == PSE_WDMA2_PORT)))
++ return 1;
++
++ return 0;
++}
++
+ /* read the hardware status register */
+ void mtk_stats_update_mac(struct mtk_mac *mac);
+
+@@ -1938,4 +1997,6 @@ void mtk_eth_set_dma_device(struct mtk_eth *eth, struct device *dma_dev);
+ u32 mtk_rss_indr_table(struct mtk_rss_params *rss_params, int index);
int mtk_ppe_debugfs_init(struct mtk_eth *eth);
+
+int mtk_qdma_debugfs_init(struct mtk_eth *eth);
#endif /* MTK_ETH_H */
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c
-index a49275f..1767823 100755
+index 107f5a1..0d4ae28 100755
--- a/drivers/net/ethernet/mediatek/mtk_ppe.c
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
-@@ -406,6 +406,16 @@ int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq,
+@@ -128,7 +128,7 @@ static void mtk_ppe_cache_enable(struct mtk_ppe *ppe, bool enable)
+ enable * MTK_PPE_CACHE_CTL_EN);
+ }
+
+-static u32 mtk_ppe_hash_entry(struct mtk_ppe *ppe, struct mtk_foe_entry *e)
++u32 mtk_ppe_hash_entry(struct mtk_ppe *ppe, struct mtk_foe_entry *e)
+ {
+ u32 hv1, hv2, hv3;
+ u32 hash;
+@@ -420,12 +420,58 @@ int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq,
return 0;
}
@@ -206,20 +268,68 @@
static inline bool mtk_foe_entry_usable(struct mtk_foe_entry *entry)
{
return !(entry->ib1 & MTK_FOE_IB1_STATIC) &&
+ FIELD_GET(MTK_FOE_IB1_STATE, entry->ib1) != MTK_FOE_STATE_BIND;
+ }
+
++bool mtk_foe_entry_match(struct mtk_foe_entry *entry, struct mtk_foe_entry *data)
++{
++ int type, len;
++
++ if ((data->ib1 ^ entry->ib1) & MTK_FOE_IB1_UDP)
++ return false;
++
++ type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1);
++ if (type > MTK_PPE_PKT_TYPE_IPV4_DSLITE)
++ len = offsetof(struct mtk_foe_entry, ipv6._rsv);
++ else
++ len = offsetof(struct mtk_foe_entry, ipv4.ib2);
++
++ return !memcmp(&entry->data, &data->data, len - 4);
++}
++
++int mtk_foe_entry_set_sp(struct mtk_ppe *ppe, struct mtk_foe_entry *entry)
++{
++ struct mtk_foe_entry *hwe;
++ u32 hash, sp = 0;
++ int i;
++
++ hash = mtk_ppe_hash_entry(ppe, entry);
++ for (i = 0; i < ppe->way; i++) {
++ hwe = &ppe->foe_table[hash + i];
++ if (mtk_foe_entry_match(hwe, entry)) {
++ sp = mtk_get_ib1_sp(ppe->eth, hwe);
++ break;
++ }
++ }
++
++ mtk_set_ib1_sp(ppe->eth, entry, sp);
++
++ return 0;
++}
++
+ static bool
+ mtk_flow_entry_match(struct mtk_flow_entry *entry, struct mtk_foe_entry *data)
+ {
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.h b/drivers/net/ethernet/mediatek/mtk_ppe.h
-index 8076e5d..c46c4d9 100644
+index 86288b0..5ab864f 100644
--- a/drivers/net/ethernet/mediatek/mtk_ppe.h
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
-@@ -356,6 +356,7 @@ int mtk_foe_entry_set_vlan(struct mtk_foe_entry *entry, int vid);
+@@ -403,9 +403,13 @@ int mtk_foe_entry_set_vlan(struct mtk_foe_entry *entry, int vid);
int mtk_foe_entry_set_pppoe(struct mtk_foe_entry *entry, int sid);
int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq,
int bss, int wcid);
+int mtk_foe_entry_set_qid(struct mtk_foe_entry *entry, int qid);
++bool mtk_foe_entry_match(struct mtk_foe_entry *entry, struct mtk_foe_entry *data);
++int mtk_foe_entry_set_sp(struct mtk_ppe *ppe, struct mtk_foe_entry *entry);
int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
+ struct mtk_foe_accounting *mtk_foe_entry_get_mib(struct mtk_ppe *ppe, u32 index, struct mtk_foe_accounting *diff);
++u32 mtk_ppe_hash_entry(struct mtk_ppe *ppe, struct mtk_foe_entry *e);
+
+ #endif
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
-index f258539..3b17819 100755
+index b80f72d..3bc50a4 100755
--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
@@ -9,6 +9,8 @@
@@ -244,7 +354,7 @@
if (dsa_port >= 0)
mtk_foe_entry_set_dsa(foe, dsa_port);
-+ if (eth->qos_toggle == 2 && dsa_port >= 0)
++ if (eth->qos_toggle == 2 && mtk_ppe_check_pppq_path(eth, foe, dsa_port))
+ mtk_foe_entry_set_qid(foe, dsa_port & MTK_QDMA_TX_MASK);
+
if (dev == eth->netdev[0])
@@ -274,60 +384,23 @@
mtk_foe_entry_set_pse_port(foe, pse_port);
return 0;
-@@ -432,7 +455,7 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
+@@ -447,7 +469,9 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
if (data.pppoe.num == 1)
mtk_foe_entry_set_pppoe(&foe, data.pppoe.sid);
- err = mtk_flow_set_output_device(eth, &foe, odev, data.eth.h_dest,
++ mtk_foe_entry_set_sp(eth->ppe[ppe_index], &foe);
++
+ err = mtk_flow_set_output_device(eth, &foe, odev, f->flow->ct, data.eth.h_dest,
&wed_index);
if (err)
return err;
-diff --git a/include/net/flow_offload.h b/include/net/flow_offload.h
-index 59b8736..7261b6d 100644
---- a/include/net/flow_offload.h
-+++ b/include/net/flow_offload.h
-@@ -365,6 +378,7 @@ struct flow_cls_offload {
- struct flow_cls_common_offload common;
- enum flow_cls_command command;
- unsigned long cookie;
-+ struct flow_offload *flow;
- struct flow_rule *rule;
- struct flow_stats stats;
- u32 classid;
-diff --git a/net/netfilter/nf_flow_table_offload.c b/net/netfilter/nf_flow_table_offload.c
-index d94c6fb..886ced5 100644
---- a/net/netfilter/nf_flow_table_offload.c
-+++ b/net/netfilter/nf_flow_table_offload.c
-@@ -810,11 +810,13 @@ static int nf_flow_offload_alloc(const struct flow_offload_work *offload,
- }
-
- static void nf_flow_offload_init(struct flow_cls_offload *cls_flow,
-+ struct flow_offload *flow,
- __be16 proto, int priority,
- enum flow_cls_command cmd,
- const struct flow_offload_tuple *tuple,
- struct netlink_ext_ack *extack)
- {
-+ cls_flow->flow = flow;
- cls_flow->common.protocol = proto;
- cls_flow->common.prio = priority;
- cls_flow->common.extack = extack;
-@@ -836,7 +838,7 @@ static int nf_flow_offload_tuple(struct nf_flowtable *flowtable,
- __be16 proto = ETH_P_ALL;
- int err, i = 0;
-
-- nf_flow_offload_init(&cls_flow, proto, priority, cmd,
-+ nf_flow_offload_init(&cls_flow, flow, proto, priority, cmd,
- &flow->tuplehash[dir].tuple, &extack);
- if (cmd == FLOW_CLS_REPLACE)
- cls_flow.rule = flow_rule->rule;
diff --git a/drivers/net/ethernet/mediatek/mtk_qdma_debugfs.c b/drivers/net/ethernet/mediatek/mtk_qdma_debugfs.c
new file mode 100644
-index 0000000..198b924
+index 0000000..3a7c585
--- /dev/null
+++ b/drivers/net/ethernet/mediatek/mtk_qdma_debugfs.c
-@@ -0,0 +1,435 @@
+@@ -0,0 +1,439 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (c) 2022 MediaTek Inc.
@@ -435,8 +508,12 @@
+{
+ struct mtk_eth *eth = m->private;
+
-+ seq_printf(m, "value=%d, HQoS is %s now!\n",
-+ eth->qos_toggle, (eth->qos_toggle) ? "enabled" : "disabled");
++ if (eth->qos_toggle == 0)
++ pr_info("HQoS is disabled now!\n");
++ else if (eth->qos_toggle == 1)
++ pr_info("HQoS is enabled now!\n");
++ else if (eth->qos_toggle == 2)
++ pr_info("Per-port-per-queue mode is enabled!\n");
+
+ return 0;
+}
@@ -763,3 +840,45 @@
+
+ return 0;
+}
+diff --git a/include/net/flow_offload.h b/include/net/flow_offload.h
+index 59b8736..c4eb45c 100644
+--- a/include/net/flow_offload.h
++++ b/include/net/flow_offload.h
+@@ -365,6 +365,7 @@ struct flow_cls_offload {
+ struct flow_cls_common_offload common;
+ enum flow_cls_command command;
+ unsigned long cookie;
++ struct flow_offload *flow;
+ struct flow_rule *rule;
+ struct flow_stats stats;
+ u32 classid;
+diff --git a/net/netfilter/nf_flow_table_offload.c b/net/netfilter/nf_flow_table_offload.c
+index 50f2f2e..ba34572 100644
+--- a/net/netfilter/nf_flow_table_offload.c
++++ b/net/netfilter/nf_flow_table_offload.c
+@@ -810,11 +810,13 @@ static int nf_flow_offload_alloc(const struct flow_offload_work *offload,
+ }
+
+ static void nf_flow_offload_init(struct flow_cls_offload *cls_flow,
++ struct flow_offload *flow,
+ __be16 proto, int priority,
+ enum flow_cls_command cmd,
+ const struct flow_offload_tuple *tuple,
+ struct netlink_ext_ack *extack)
+ {
++ cls_flow->flow = flow;
+ cls_flow->common.protocol = proto;
+ cls_flow->common.prio = priority;
+ cls_flow->common.extack = extack;
+@@ -836,7 +838,7 @@ static int nf_flow_offload_tuple(struct nf_flowtable *flowtable,
+ __be16 proto = ETH_P_ALL;
+ int err, i = 0;
+
+- nf_flow_offload_init(&cls_flow, proto, priority, cmd,
++ nf_flow_offload_init(&cls_flow, flow, proto, priority, cmd,
+ &flow->tuplehash[dir].tuple, &extack);
+ if (cmd == FLOW_CLS_REPLACE)
+ cls_flow.rule = flow_rule->rule;
+--
+2.18.0
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3017-ethernet-update-ppe-from-mt7986-to-mt7988.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3017-ethernet-update-ppe-from-mt7986-to-mt7988.patch
index d9af44d..872a279 100755
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3017-ethernet-update-ppe-from-mt7986-to-mt7988.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3017-ethernet-update-ppe-from-mt7986-to-mt7988.patch
@@ -1,8 +1,21 @@
+From 06c3b8d434290affb720808a38315a78e94c9923 Mon Sep 17 00:00:00 2001
+From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
+Date: Sat, 26 Aug 2023 00:45:40 +0800
+Subject: [PATCH] 999-3017-ethernet-update-ppe-from-mt7986-to-mt7988
+
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 14 ++++---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h | 9 +++--
+ drivers/net/ethernet/mediatek/mtk_ppe.c | 18 ++++++---
+ drivers/net/ethernet/mediatek/mtk_ppe.h | 38 ++++++++++++++++---
+ .../net/ethernet/mediatek/mtk_ppe_offload.c | 6 ++-
+ 5 files changed, 64 insertions(+), 21 deletions(-)
+
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 4075ec2..524c5d9 100644
+index a370547..239c25d 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -1796,17 +1796,17 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
+@@ -2272,17 +2272,17 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
skb_checksum_none_assert(skb);
skb->protocol = eth_type_trans(skb, netdev);
@@ -24,7 +37,7 @@
reason = FIELD_GET(MTK_RXD5_PPE_CPU_REASON_V2, trxd.rxd5);
if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED) {
for (i = 0; i < eth->ppe_num; i++) {
-@@ -4448,7 +4448,8 @@ static int mtk_probe(struct platform_device *pdev)
+@@ -5071,7 +5071,8 @@ static int mtk_probe(struct platform_device *pdev)
for (i = 0; i < eth->ppe_num; i++) {
eth->ppe[i] = mtk_ppe_init(eth,
@@ -34,28 +47,21 @@
2, eth->soc->hash_way, i,
eth->soc->has_accounting);
if (!eth->ppe[i]) {
-@@ -4626,13 +4626,16 @@ static const struct mtk_soc_data mt7988_data = {
+@@ -5338,6 +5339,9 @@ static const struct mtk_soc_data mt7988_data = {
.required_clks = MT7988_CLKS_BITMAP,
.required_pctl = false,
.has_sram = true,
+ .has_accounting = true,
+ .hash_way = 4,
+ .offload_version = 2,
- .rss_num = 4,
+ .rss_num = 4,
.txrx = {
.txd_size = sizeof(struct mtk_tx_dma_v2),
- .rxd_size = sizeof(struct mtk_rx_dma_v2),
- .rx_dma_l4_valid = RX_DMA_L4_VALID_V2,
- .dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
- .dma_len_offset = MTK_TX_DMA_BUF_SHIFT_V2,
- .qdma_tx_sch = 4,
- },
- };
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-index 5b39d87..94bd423 100644
+index a7892e2..cd19c8d 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -118,7 +118,8 @@
+@@ -130,9 +130,10 @@
#define MTK_GDMA_UCS_EN BIT(20)
#define MTK_GDMA_STRP_CRC BIT(16)
#define MTK_GDMA_TO_PDMA 0x0
@@ -65,8 +71,28 @@
#define MTK_GDMA_TO_PPE1 0x4444
+#define MTK_GMAC_TO_PPE2 0xcccc
#else
+ #define MTK_GDMA_TO_PPE0 0x4444
+ #endif
+@@ -1939,13 +1940,15 @@ extern u32 dbg_show_level;
+
+ static inline void mtk_set_ib1_sp(struct mtk_eth *eth, struct mtk_foe_entry *foe, u32 val)
+ {
+- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2) ||
++ MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3))
+ foe->ib1 |= FIELD_PREP(MTK_FOE_IB1_UNBIND_SRC_PORT, val);
+ }
+
+ static inline u32 mtk_get_ib1_sp(struct mtk_eth *eth, struct mtk_foe_entry *foe)
+ {
+- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2) ||
++ MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3))
+ return FIELD_GET(MTK_FOE_IB1_UNBIND_SRC_PORT, foe->ib1);
+
+ return 0;
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c
-index 98f61fe..bd504d4 100755
+index 0d4ae28..308d5a1 100755
--- a/drivers/net/ethernet/mediatek/mtk_ppe.c
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
@@ -211,7 +211,7 @@ int mtk_foe_entry_prepare(struct mtk_foe_entry *entry, int type, int l4proto,
@@ -104,7 +130,7 @@
return 0;
}
-@@ -867,13 +867,16 @@ int mtk_ppe_start(struct mtk_ppe *ppe)
+@@ -922,13 +927,16 @@ int mtk_ppe_start(struct mtk_ppe *ppe)
mtk_ppe_init_foe_table(ppe);
ppe_w32(ppe, MTK_PPE_TB_BASE, ppe->foe_phys);
@@ -123,7 +149,7 @@
MTK_PPE_TB_CFG_INFO_SEL |
#endif
FIELD_PREP(MTK_PPE_TB_CFG_SEARCH_MISS,
-@@ -937,7 +940,7 @@ int mtk_ppe_start(struct mtk_ppe *ppe)
+@@ -992,7 +1000,7 @@ int mtk_ppe_start(struct mtk_ppe *ppe)
ppe_w32(ppe, MTK_PPE_DEFAULT_CPU_PORT, 0);
@@ -133,7 +159,7 @@
ppe_w32(ppe, MTK_PPE_SBW_CTRL, 0x7f);
#endif
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.h b/drivers/net/ethernet/mediatek/mtk_ppe.h
-index 703b2bd..03b4dfb 100644
+index 5ab864f..5529d64 100644
--- a/drivers/net/ethernet/mediatek/mtk_ppe.h
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
@@ -8,7 +8,10 @@
@@ -148,7 +174,7 @@
#define MTK_MAX_PPE_NUM 2
#define MTK_ETH_PPE_BASE 0x2000
#else
-@@ -22,7 +22,7 @@
+@@ -22,7 +25,7 @@
#define MTK_PPE_WAIT_TIMEOUT_US 1000000
#define MTK_FOE_IB1_UNBIND_TIMESTAMP GENMASK(7, 0)
@@ -157,7 +183,7 @@
#define MTK_FOE_IB1_UNBIND_SRC_PORT GENMASK(11, 8)
#define MTK_FOE_IB1_UNBIND_PACKETS GENMASK(19, 12)
#define MTK_FOE_IB1_UNBIND_PREBIND BIT(22)
-@@ -70,7 +70,7 @@ enum {
+@@ -70,7 +73,7 @@ enum {
MTK_PPE_PKT_TYPE_IPV6_6RD = 7,
};
@@ -166,7 +192,7 @@
#define MTK_FOE_IB2_QID GENMASK(6, 0)
#define MTK_FOE_IB2_PORT_MG BIT(7)
#define MTK_FOE_IB2_PSE_QOS BIT(8)
-@@ -98,7 +98,18 @@ enum {
+@@ -98,7 +101,18 @@ enum {
#define MTK_FOE_IB2_DSCP GENMASK(31, 24)
@@ -186,7 +212,7 @@
#define MTK_FOE_WINFO_BSS GENMASK(5, 0)
#define MTK_FOE_WINFO_WCID GENMASK(15, 6)
#else
-@@ -128,7 +139,17 @@ struct mtk_foe_mac_info {
+@@ -128,7 +142,17 @@ struct mtk_foe_mac_info {
u16 pppoe_id;
u16 src_mac_lo;
@@ -205,7 +231,7 @@
u16 minfo;
u16 winfo;
#endif
-@@ -249,7 +265,9 @@ struct mtk_foe_entry {
+@@ -249,7 +273,9 @@ struct mtk_foe_entry {
struct mtk_foe_ipv4_dslite dslite;
struct mtk_foe_ipv6 ipv6;
struct mtk_foe_ipv6_6rd ipv6_6rd;
@@ -217,7 +243,7 @@
#else
u32 data[19];
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
-index a5bf090..0e41ff2 100755
+index 3bc50a4..f0c63da 100755
--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
@@ -195,7 +195,7 @@ mtk_flow_set_output_device(struct mtk_eth *eth, struct mtk_foe_entry *foe,
@@ -229,7 +255,7 @@
if (info.wdma_idx == 0)
pse_port = PSE_WDMA0_PORT;
else if (info.wdma_idx == 1)
-@@ -220,6 +220,8 @@ mtk_flow_set_output_device(struct mtk_eth *eth, struct mtk_foe_entry *foe,
+@@ -218,6 +218,8 @@ mtk_flow_set_output_device(struct mtk_eth *eth, struct mtk_foe_entry *foe,
pse_port = PSE_GDM1_PORT;
else if (dev == eth->netdev[1])
pse_port = PSE_GDM2_PORT;
@@ -238,12 +264,15 @@
else
return -EOPNOTSUPP;
-@@ -452,7 +452,7 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
- return -ENOMEM;
+@@ -376,7 +378,7 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
+ if (err)
+ return err;
- i = 0;
-#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+#if defined(CONFIG_MEDIATEK_NETSYS_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
if (idev && idev->netdev_ops->ndo_fill_receive_path) {
ctx.dev = idev;
idev->netdev_ops->ndo_fill_receive_path(&ctx, &path);
+--
+2.18.0
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3019-flow-offload-add-mtkhnat-dscp.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3019-flow-offload-add-mtkhnat-dscp.patch
index fe278a7..a43261a 100755
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3019-flow-offload-add-mtkhnat-dscp.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3019-flow-offload-add-mtkhnat-dscp.patch
@@ -1,5 +1,19 @@
+From 72dd3b798e3a08122e9a769d6f0197b0f357478e Mon Sep 17 00:00:00 2001
+From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
+Date: Wed, 23 Aug 2023 14:03:52 +0800
+Subject: [PATCH] 999-3019-flow-offload-add-mtkhnat-dscp
+
+---
+ drivers/net/ethernet/mediatek/mtk_ppe.c | 11 +++++++
+ drivers/net/ethernet/mediatek/mtk_ppe.h | 1 +
+ .../net/ethernet/mediatek/mtk_ppe_offload.c | 12 +++++++
+ include/net/netfilter/nf_flow_table.h | 2 ++
+ net/netfilter/nf_flow_table_offload.c | 7 +++-
+ net/netfilter/xt_FLOWOFFLOAD.c | 32 +++++++++++++++++++
+ 6 files changed, 64 insertions(+), 1 deletion(-)
+
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c
-index c2416b1..bc13a9b 100755
+index 4c17a4e..2860e99 100755
--- a/drivers/net/ethernet/mediatek/mtk_ppe.c
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
@@ -435,6 +435,17 @@ int mtk_foe_entry_set_qid(struct mtk_foe_entry *entry, int qid)
@@ -21,7 +35,7 @@
{
return !(entry->ib1 & MTK_FOE_IB1_STATIC) &&
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.h b/drivers/net/ethernet/mediatek/mtk_ppe.h
-index e7ecbf7..df10040 100644
+index 4abed85..57251d3 100644
--- a/drivers/net/ethernet/mediatek/mtk_ppe.h
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
@@ -430,6 +430,7 @@ int mtk_foe_entry_set_pppoe(struct mtk_foe_entry *entry, int sid);
@@ -29,14 +43,14 @@
int bss, int wcid);
int mtk_foe_entry_set_qid(struct mtk_foe_entry *entry, int qid);
+int mtk_foe_entry_set_dscp(struct mtk_foe_entry *entry, int dscp);
+ bool mtk_foe_entry_match(struct mtk_foe_entry *entry, struct mtk_foe_entry *data);
int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
- int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
-index 23d2048..9bc0857 100644
+index 989b412..f89875d 100644
--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
-@@ -246,6 +246,7 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
+@@ -262,6 +262,7 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
int wed_index = -1;
u16 addr_type = 0;
u8 l4proto = 0;
@@ -44,7 +58,7 @@
int err = 0;
int i;
-@@ -282,6 +283,15 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
+@@ -298,6 +299,15 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
return -EOPNOTSUPP;
}
@@ -60,17 +74,17 @@
switch (addr_type) {
case 0:
offload_type = MTK_PPE_PKT_TYPE_BRIDGE;
-@@ -441,6 +451,8 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
+@@ -471,6 +481,8 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
if (data.pppoe.num == 1)
mtk_foe_entry_set_pppoe(&foe, data.pppoe.sid);
+ mtk_foe_entry_set_dscp(&foe, dscp);
+
+ mtk_foe_entry_set_sp(eth->ppe[ppe_index], &foe);
+
err = mtk_flow_set_output_device(eth, &foe, odev, f->flow->ct, data.eth.h_dest,
- &wed_index);
- if (err)
diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h
-index 55359dd..1a23c03 100644
+index feac793..97a277d 100644
--- a/include/net/netfilter/nf_flow_table.h
+++ b/include/net/netfilter/nf_flow_table.h
@@ -36,6 +36,7 @@ struct nf_flow_key {
@@ -90,7 +104,7 @@
struct flow_offload_tuple_rhash {
diff --git a/net/netfilter/nf_flow_table_offload.c b/net/netfilter/nf_flow_table_offload.c
-index 61cc518..c1a5f64 100644
+index ba34572..b8b2fa6 100644
--- a/net/netfilter/nf_flow_table_offload.c
+++ b/net/netfilter/nf_flow_table_offload.c
@@ -104,6 +104,7 @@ static int nf_flow_rule_match(struct nf_flow_match *match,
@@ -118,7 +132,7 @@
}
diff --git a/net/netfilter/xt_FLOWOFFLOAD.c b/net/netfilter/xt_FLOWOFFLOAD.c
-index 2d5c3cc..b231dd7 100644
+index 1defb15..d4aecab 100644
--- a/net/netfilter/xt_FLOWOFFLOAD.c
+++ b/net/netfilter/xt_FLOWOFFLOAD.c
@@ -49,6 +49,35 @@ static DEFINE_SPINLOCK(hooks_lock);
@@ -157,7 +171,7 @@
static unsigned int
xt_flowoffload_net_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
-@@ -599,6 +628,9 @@ flowoffload_tg(struct sk_buff *skb, const struct xt_action_param *par)
+@@ -617,6 +646,9 @@ flowoffload_tg(struct sk_buff *skb, const struct xt_action_param *par)
if (flow_offload_route_init(flow, &route) < 0)
goto err_flow_add;
@@ -167,3 +181,6 @@
if (tcph) {
ct->proto.tcp.seen[0].flags |= IP_CT_TCP_FLAG_BE_LIBERAL;
ct->proto.tcp.seen[1].flags |= IP_CT_TCP_FLAG_BE_LIBERAL;
+--
+2.18.0
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-1022-backport-linux-6.2-xfrm-packet-mode.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-1022-backport-linux-6.2-xfrm-packet-mode.patch
new file mode 100644
index 0000000..9eb9347
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-1022-backport-linux-6.2-xfrm-packet-mode.patch
@@ -0,0 +1,980 @@
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -919,6 +919,10 @@ struct xfrmdev_ops {
+ bool (*xdo_dev_offload_ok) (struct sk_buff *skb,
+ struct xfrm_state *x);
+ void (*xdo_dev_state_advance_esn) (struct xfrm_state *x);
++ void (*xdo_dev_state_update_curlft) (struct xfrm_state *x);
++ int (*xdo_dev_policy_add) (struct xfrm_policy *x);
++ void (*xdo_dev_policy_delete) (struct xfrm_policy *x);
++ void (*xdo_dev_policy_free) (struct xfrm_policy *x);
+ };
+ #endif
+
+--- a/include/net/xfrm.h
++++ b/include/net/xfrm.h
+@@ -125,11 +125,25 @@ struct xfrm_state_walk {
+ struct xfrm_address_filter *filter;
+ };
+
++enum {
++ XFRM_DEV_OFFLOAD_IN = 1,
++ XFRM_DEV_OFFLOAD_OUT,
++ XFRM_DEV_OFFLOAD_FWD,
++};
++
++enum {
++ XFRM_DEV_OFFLOAD_UNSPECIFIED,
++ XFRM_DEV_OFFLOAD_CRYPTO,
++ XFRM_DEV_OFFLOAD_PACKET,
++};
++
+ struct xfrm_state_offload {
+ struct net_device *dev;
+ unsigned long offload_handle;
+ unsigned int num_exthdrs;
+ u8 flags;
++ u8 dir : 2;
++ u8 type : 2;
+ };
+
+ struct xfrm_mode {
+@@ -527,6 +541,8 @@ struct xfrm_policy {
+ struct xfrm_tmpl xfrm_vec[XFRM_MAX_DEPTH];
+ struct hlist_node bydst_inexact_list;
+ struct rcu_head rcu;
++
++ struct xfrm_state_offload xdo;
+ };
+
+ static inline struct net *xp_net(const struct xfrm_policy *xp)
+@@ -1084,6 +1100,29 @@ xfrm_state_addr_cmp(const struct xfrm_tm
+ }
+
+ #ifdef CONFIG_XFRM
++static inline struct xfrm_state *xfrm_input_state(struct sk_buff *skb)
++{
++ struct sec_path *sp = skb_sec_path(skb);
++
++ return sp->xvec[sp->len - 1];
++}
++#endif
++
++static inline struct xfrm_offload *xfrm_offload(struct sk_buff *skb)
++{
++#ifdef CONFIG_XFRM
++ struct sec_path *sp = skb_sec_path(skb);
++
++ if (!sp || !sp->olen || sp->len != sp->olen)
++ return NULL;
++
++ return &sp->ovec[sp->olen - 1];
++#else
++ return NULL;
++#endif
++}
++
++#ifdef CONFIG_XFRM
+ int __xfrm_policy_check(struct sock *, int dir, struct sk_buff *skb,
+ unsigned short family);
+
+@@ -1093,10 +1132,19 @@ static inline int __xfrm_policy_check2(s
+ {
+ struct net *net = dev_net(skb->dev);
+ int ndir = dir | (reverse ? XFRM_POLICY_MASK + 1 : 0);
++ struct xfrm_offload *xo = xfrm_offload(skb);
++ struct xfrm_state *x;
+
+ if (sk && sk->sk_policy[XFRM_POLICY_IN])
+ return __xfrm_policy_check(sk, ndir, skb, family);
+
++ if (xo) {
++ x = xfrm_input_state(skb);
++ if (x->xso.type == XFRM_DEV_OFFLOAD_PACKET)
++ return (xo->flags & CRYPTO_DONE) &&
++ (xo->status & CRYPTO_SUCCESS);
++ }
++
+ return (!net->xfrm.policy_count[dir] && !secpath_exists(skb)) ||
+ (skb_dst(skb) && (skb_dst(skb)->flags & DST_NOPOLICY)) ||
+ __xfrm_policy_check(sk, ndir, skb, family);
+@@ -1490,6 +1538,23 @@ struct xfrm_state *xfrm_stateonly_find(s
+ struct xfrm_state *xfrm_state_lookup_byspi(struct net *net, __be32 spi,
+ unsigned short family);
+ int xfrm_state_check_expire(struct xfrm_state *x);
++#ifdef CONFIG_XFRM_OFFLOAD
++static inline void xfrm_dev_state_update_curlft(struct xfrm_state *x)
++{
++ struct xfrm_state_offload *xdo = &x->xso;
++ struct net_device *dev = xdo->dev;
++
++ if (x->xso.type != XFRM_DEV_OFFLOAD_PACKET)
++ return;
++
++ if (dev && dev->xfrmdev_ops &&
++ dev->xfrmdev_ops->xdo_dev_state_update_curlft)
++ dev->xfrmdev_ops->xdo_dev_state_update_curlft(x);
++
++}
++#else
++static inline void xfrm_dev_state_update_curlft(struct xfrm_state *x) {}
++#endif
+ void xfrm_state_insert(struct xfrm_state *x);
+ int xfrm_state_add(struct xfrm_state *x);
+ int xfrm_state_update(struct xfrm_state *x);
+@@ -1539,6 +1604,8 @@ struct xfrm_state *xfrm_find_acq_byseq(s
+ int xfrm_state_delete(struct xfrm_state *x);
+ int xfrm_state_flush(struct net *net, u8 proto, bool task_valid, bool sync);
+ int xfrm_dev_state_flush(struct net *net, struct net_device *dev, bool task_valid);
++int xfrm_dev_policy_flush(struct net *net, struct net_device *dev,
++ bool task_valid);
+ void xfrm_sad_getinfo(struct net *net, struct xfrmk_sadinfo *si);
+ void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si);
+ u32 xfrm_replay_seqhi(struct xfrm_state *x, __be32 net_seq);
+@@ -1820,29 +1887,6 @@ static inline void xfrm_states_delete(st
+ }
+ #endif
+
+-#ifdef CONFIG_XFRM
+-static inline struct xfrm_state *xfrm_input_state(struct sk_buff *skb)
+-{
+- struct sec_path *sp = skb_sec_path(skb);
+-
+- return sp->xvec[sp->len - 1];
+-}
+-#endif
+-
+-static inline struct xfrm_offload *xfrm_offload(struct sk_buff *skb)
+-{
+-#ifdef CONFIG_XFRM
+- struct sec_path *sp = skb_sec_path(skb);
+-
+- if (!sp || !sp->olen || sp->len != sp->olen)
+- return NULL;
+-
+- return &sp->ovec[sp->olen - 1];
+-#else
+- return NULL;
+-#endif
+-}
+-
+ void __init xfrm_dev_init(void);
+
+ #ifdef CONFIG_XFRM_OFFLOAD
+@@ -1851,6 +1895,9 @@ void xfrm_dev_backlog(struct softnet_dat
+ struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t features, bool *again);
+ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
+ struct xfrm_user_offload *xuo);
++int xfrm_dev_policy_add(struct net *net, struct xfrm_policy *xp,
++ struct xfrm_user_offload *xuo, u8 dir,
++ struct netlink_ext_ack *extack);
+ bool xfrm_dev_offload_ok(struct sk_buff *skb, struct xfrm_state *x);
+
+ static inline void xfrm_dev_state_advance_esn(struct xfrm_state *x)
+@@ -1899,6 +1946,27 @@ static inline void xfrm_dev_state_free(s
+ dev_put(dev);
+ }
+ }
++
++static inline void xfrm_dev_policy_delete(struct xfrm_policy *x)
++{
++ struct xfrm_state_offload *xdo = &x->xdo;
++ struct net_device *dev = xdo->dev;
++
++ if (dev && dev->xfrmdev_ops && dev->xfrmdev_ops->xdo_dev_policy_delete)
++ dev->xfrmdev_ops->xdo_dev_policy_delete(x);
++}
++
++static inline void xfrm_dev_policy_free(struct xfrm_policy *x)
++{
++ struct xfrm_state_offload *xdo = &x->xdo;
++ struct net_device *dev = xdo->dev;
++
++ if (dev && dev->xfrmdev_ops) {
++ if (dev->xfrmdev_ops->xdo_dev_policy_free)
++ dev->xfrmdev_ops->xdo_dev_policy_free(x);
++ xdo->dev = NULL;
++ }
++}
+ #else
+ static inline void xfrm_dev_resume(struct sk_buff *skb)
+ {
+@@ -1931,6 +1999,21 @@ static inline bool xfrm_dev_offload_ok(s
+ return false;
+ }
+
++static inline int xfrm_dev_policy_add(struct net *net, struct xfrm_policy *xp,
++ struct xfrm_user_offload *xuo, u8 dir,
++ struct netlink_ext_ack *extack)
++{
++ return 0;
++}
++
++static inline void xfrm_dev_policy_delete(struct xfrm_policy *x)
++{
++}
++
++static inline void xfrm_dev_policy_free(struct xfrm_policy *x)
++{
++}
++
+ static inline void xfrm_dev_state_advance_esn(struct xfrm_state *x)
+ {
+ }
+--- a/include/uapi/linux/xfrm.h
++++ b/include/uapi/linux/xfrm.h
+@@ -512,6 +512,12 @@ struct xfrm_user_offload {
+ */
+ #define XFRM_OFFLOAD_IPV6 1
+ #define XFRM_OFFLOAD_INBOUND 2
++/* Two bits above are relevant for state path only, while
++ * offload is used for both policy and state flows.
++ *
++ * In policy offload mode, they are free and can be safely reused.
++ */
++#define XFRM_OFFLOAD_PACKET 4
+
+ #ifndef __KERNEL__
+ /* backwards compatibility for userspace */
+--- a/net/xfrm/xfrm_device.c
++++ b/net/xfrm/xfrm_device.c
+@@ -80,6 +80,7 @@ struct sk_buff *validate_xmit_xfrm(struc
+ struct softnet_data *sd;
+ netdev_features_t esp_features = features;
+ struct xfrm_offload *xo = xfrm_offload(skb);
++ struct net_device *dev = skb->dev;
+ struct sec_path *sp;
+
+ if (!xo || (xo->flags & XFRM_XMIT))
+@@ -93,6 +94,17 @@ struct sk_buff *validate_xmit_xfrm(struc
+ if (xo->flags & XFRM_GRO || x->xso.flags & XFRM_OFFLOAD_INBOUND)
+ return skb;
+
++ /* The packet was sent to HW IPsec packet offload engine,
++ * but to wrong device. Drop the packet, so it won't skip
++ * XFRM stack.
++ */
++ if (x->xso.type == XFRM_DEV_OFFLOAD_PACKET && x->xso.dev != dev) {
++ kfree_skb(skb);
++ //dev_core_stats_tx_dropped_inc(dev);
++ atomic_long_inc(&dev->tx_dropped);
++ return NULL;
++ }
++
+ local_irq_save(flags);
+ sd = this_cpu_ptr(&softnet_data);
+ err = !skb_queue_empty(&sd->xfrm_backlog);
+@@ -198,6 +210,7 @@ int xfrm_dev_state_add(struct net *net,
+ struct xfrm_state_offload *xso = &x->xso;
+ xfrm_address_t *saddr;
+ xfrm_address_t *daddr;
++ bool is_packet_offload;
+
+ if (!x->type_offload)
+ return -EINVAL;
+@@ -206,9 +219,11 @@ int xfrm_dev_state_add(struct net *net,
+ if (x->encap || x->tfcpad)
+ return -EINVAL;
+
+- if (xuo->flags & ~(XFRM_OFFLOAD_IPV6 | XFRM_OFFLOAD_INBOUND))
++ if (xuo->flags &
++ ~(XFRM_OFFLOAD_IPV6 | XFRM_OFFLOAD_INBOUND | XFRM_OFFLOAD_PACKET))
+ return -EINVAL;
+
++ is_packet_offload = xuo->flags & XFRM_OFFLOAD_PACKET;
+ dev = dev_get_by_index(net, xuo->ifindex);
+ if (!dev) {
+ if (!(xuo->flags & XFRM_OFFLOAD_INBOUND)) {
+@@ -223,7 +238,7 @@ int xfrm_dev_state_add(struct net *net,
+ x->props.family,
+ xfrm_smark_get(0, x));
+ if (IS_ERR(dst))
+- return 0;
++ return (is_packet_offload) ? -EINVAL : 0;
+
+ dev = dst->dev;
+
+@@ -234,7 +249,7 @@ int xfrm_dev_state_add(struct net *net,
+ if (!dev->xfrmdev_ops || !dev->xfrmdev_ops->xdo_dev_state_add) {
+ xso->dev = NULL;
+ dev_put(dev);
+- return 0;
++ return (is_packet_offload) ? -EINVAL : 0;
+ }
+
+ if (x->props.flags & XFRM_STATE_ESN &&
+@@ -249,14 +264,28 @@ int xfrm_dev_state_add(struct net *net,
+ /* Don't forward bit that is not implemented */
+ xso->flags = xuo->flags & ~XFRM_OFFLOAD_IPV6;
+
++ if (is_packet_offload)
++ xso->type = XFRM_DEV_OFFLOAD_PACKET;
++ else
++ xso->type = XFRM_DEV_OFFLOAD_CRYPTO;
++
+ err = dev->xfrmdev_ops->xdo_dev_state_add(x);
+ if (err) {
+ xso->num_exthdrs = 0;
+ xso->flags = 0;
+ xso->dev = NULL;
+ dev_put(dev);
++ xso->type = XFRM_DEV_OFFLOAD_UNSPECIFIED;
+
+- if (err != -EOPNOTSUPP)
++ /* User explicitly requested packet offload mode and configured
++ * policy in addition to the XFRM state. So be civil to users,
++ * and return an error instead of taking fallback path.
++ *
++ * This WARN_ON() can be seen as a documentation for driver
++ * authors to do not return -EOPNOTSUPP in packet offload mode.
++ */
++ WARN_ON(err == -EOPNOTSUPP && is_packet_offload);
++ if (err != -EOPNOTSUPP || is_packet_offload)
+ return err;
+ }
+
+@@ -264,6 +293,65 @@ int xfrm_dev_state_add(struct net *net,
+ }
+ EXPORT_SYMBOL_GPL(xfrm_dev_state_add);
+
++int xfrm_dev_policy_add(struct net *net, struct xfrm_policy *xp,
++ struct xfrm_user_offload *xuo, u8 dir,
++ struct netlink_ext_ack *extack)
++{
++ struct xfrm_state_offload *xdo = &xp->xdo;
++ struct net_device *dev;
++ int err;
++
++ if (!xuo->flags || xuo->flags & ~XFRM_OFFLOAD_PACKET) {
++ /* We support only packet offload mode and it means
++ * that user must set XFRM_OFFLOAD_PACKET bit.
++ */
++ NL_SET_ERR_MSG(extack, "Unrecognized flags in offload request");
++ return -EINVAL;
++ }
++
++ dev = dev_get_by_index(net, xuo->ifindex);
++ if (!dev)
++ return -EINVAL;
++
++ if (!dev->xfrmdev_ops || !dev->xfrmdev_ops->xdo_dev_policy_add) {
++ xdo->dev = NULL;
++ dev_put(dev);
++ NL_SET_ERR_MSG(extack, "Policy offload is not supported");
++ return -EINVAL;
++ }
++
++ xdo->dev = dev;
++ xdo->type = XFRM_DEV_OFFLOAD_PACKET;
++ switch (dir) {
++ case XFRM_POLICY_IN:
++ xdo->dir = XFRM_DEV_OFFLOAD_IN;
++ break;
++ case XFRM_POLICY_OUT:
++ xdo->dir = XFRM_DEV_OFFLOAD_OUT;
++ break;
++ case XFRM_POLICY_FWD:
++ xdo->dir = XFRM_DEV_OFFLOAD_FWD;
++ break;
++ default:
++ xdo->dev = NULL;
++ dev_put(dev);
++ NL_SET_ERR_MSG(extack, "Unrecognized oflload direction");
++ return -EINVAL;
++ }
++
++ err = dev->xfrmdev_ops->xdo_dev_policy_add(xp);
++ if (err) {
++ xdo->dev = NULL;
++ xdo->type = XFRM_DEV_OFFLOAD_UNSPECIFIED;
++ xdo->dir = 0;
++ NL_SET_ERR_MSG(extack, "Device failed to offload this policy");
++ return err;
++ }
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(xfrm_dev_policy_add);
++
+ bool xfrm_dev_offload_ok(struct sk_buff *skb, struct xfrm_state *x)
+ {
+ int mtu;
+@@ -274,8 +362,9 @@ bool xfrm_dev_offload_ok(struct sk_buff
+ if (!x->type_offload || x->encap)
+ return false;
+
+- if ((!dev || (dev == xfrm_dst_path(dst)->dev)) &&
+- (!xdst->child->xfrm)) {
++ if (x->xso.type == XFRM_DEV_OFFLOAD_PACKET ||
++ ((!dev || (dev == xfrm_dst_path(dst)->dev)) &&
++ !xdst->child->xfrm)) {
+ mtu = xfrm_state_mtu(x, xdst->child_mtu_cached);
+ if (skb->len <= mtu)
+ goto ok;
+@@ -376,8 +465,10 @@ static int xfrm_dev_feat_change(struct n
+
+ static int xfrm_dev_down(struct net_device *dev)
+ {
+- if (dev->features & NETIF_F_HW_ESP)
++ if (dev->features & NETIF_F_HW_ESP) {
+ xfrm_dev_state_flush(dev_net(dev), dev, true);
++ xfrm_dev_policy_flush(dev_net(dev), dev, true);
++ }
+
+ return NOTIFY_DONE;
+ }
+--- a/net/xfrm/xfrm_output.c
++++ b/net/xfrm/xfrm_output.c
+@@ -410,7 +410,7 @@ static int xfrm_output_one(struct sk_buf
+ struct xfrm_state *x = dst->xfrm;
+ struct net *net = xs_net(x);
+
+- if (err <= 0)
++ if (err <= 0 || x->xso.type == XFRM_DEV_OFFLOAD_PACKET)
+ goto resume;
+
+ do {
+@@ -568,6 +568,16 @@ int xfrm_output(struct sock *sk, struct
+ struct xfrm_state *x = skb_dst(skb)->xfrm;
+ int err;
+
++ if (x->xso.type == XFRM_DEV_OFFLOAD_PACKET) {
++ if (!xfrm_dev_offload_ok(skb, x)) {
++ XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR);
++ kfree_skb(skb);
++ return -EHOSTUNREACH;
++ }
++
++ return xfrm_output_resume(skb, 0);
++ }
++
+ secpath_reset(skb);
+
+ if (xfrm_dev_offload_ok(skb, x)) {
+--- a/net/xfrm/xfrm_policy.c
++++ b/net/xfrm/xfrm_policy.c
+@@ -423,6 +423,7 @@ void xfrm_policy_destroy(struct xfrm_pol
+ if (del_timer(&policy->timer) || del_timer(&policy->polq.hold_timer))
+ BUG();
+
++ xfrm_dev_policy_free(policy);
+ call_rcu(&policy->rcu, xfrm_policy_destroy_rcu);
+ }
+ EXPORT_SYMBOL(xfrm_policy_destroy);
+@@ -533,7 +534,7 @@ redo:
+ __get_hash_thresh(net, pol->family, dir, &dbits, &sbits);
+ h = __addr_hash(&pol->selector.daddr, &pol->selector.saddr,
+ pol->family, nhashmask, dbits, sbits);
+- if (!entry0) {
++ if (!entry0 || pol->xdo.type == XFRM_DEV_OFFLOAD_PACKET) {
+ hlist_del_rcu(&pol->bydst);
+ hlist_add_head_rcu(&pol->bydst, ndsttable + h);
+ h0 = h;
+@@ -864,7 +865,7 @@ static void xfrm_policy_inexact_list_rei
+ break;
+ }
+
+- if (newpos)
++ if (newpos && policy->xdo.type != XFRM_DEV_OFFLOAD_PACKET)
+ hlist_add_behind_rcu(&policy->bydst, newpos);
+ else
+ hlist_add_head_rcu(&policy->bydst, &n->hhead);
+@@ -1345,7 +1346,7 @@ static void xfrm_hash_rebuild(struct wor
+ else
+ break;
+ }
+- if (newpos)
++ if (newpos && policy->xdo.type != XFRM_DEV_OFFLOAD_PACKET)
+ hlist_add_behind_rcu(&policy->bydst, newpos);
+ else
+ hlist_add_head_rcu(&policy->bydst, chain);
+@@ -1522,7 +1523,7 @@ static void xfrm_policy_insert_inexact_l
+ break;
+ }
+
+- if (newpos)
++ if (newpos && policy->xdo.type != XFRM_DEV_OFFLOAD_PACKET)
+ hlist_add_behind_rcu(&policy->bydst_inexact_list, newpos);
+ else
+ hlist_add_head_rcu(&policy->bydst_inexact_list, chain);
+@@ -1559,9 +1560,12 @@ static struct xfrm_policy *xfrm_policy_i
+ break;
+ }
+
+- if (newpos)
++ if (newpos && policy->xdo.type != XFRM_DEV_OFFLOAD_PACKET)
+ hlist_add_behind_rcu(&policy->bydst, &newpos->bydst);
+ else
++ /* Packet offload policies enter to the head
++ * to speed-up lookups.
++ */
+ hlist_add_head_rcu(&policy->bydst, chain);
+
+ return delpol;
+@@ -1767,12 +1771,41 @@ xfrm_policy_flush_secctx_check(struct ne
+ }
+ return err;
+ }
++
++static inline int xfrm_dev_policy_flush_secctx_check(struct net *net,
++ struct net_device *dev,
++ bool task_valid)
++{
++ struct xfrm_policy *pol;
++ int err = 0;
++
++ list_for_each_entry(pol, &net->xfrm.policy_all, walk.all) {
++ if (pol->walk.dead ||
++ xfrm_policy_id2dir(pol->index) >= XFRM_POLICY_MAX ||
++ pol->xdo.dev != dev)
++ continue;
++
++ err = security_xfrm_policy_delete(pol->security);
++ if (err) {
++ xfrm_audit_policy_delete(pol, 0, task_valid);
++ return err;
++ }
++ }
++ return err;
++}
+ #else
+ static inline int
+ xfrm_policy_flush_secctx_check(struct net *net, u8 type, bool task_valid)
+ {
+ return 0;
+ }
++
++static inline int xfrm_dev_policy_flush_secctx_check(struct net *net,
++ struct net_device *dev,
++ bool task_valid)
++{
++ return 0;
++}
+ #endif
+
+ int xfrm_policy_flush(struct net *net, u8 type, bool task_valid)
+@@ -1812,6 +1845,44 @@ out:
+ }
+ EXPORT_SYMBOL(xfrm_policy_flush);
+
++int xfrm_dev_policy_flush(struct net *net, struct net_device *dev,
++ bool task_valid)
++{
++ int dir, err = 0, cnt = 0;
++ struct xfrm_policy *pol;
++
++ spin_lock_bh(&net->xfrm.xfrm_policy_lock);
++
++ err = xfrm_dev_policy_flush_secctx_check(net, dev, task_valid);
++ if (err)
++ goto out;
++
++again:
++ list_for_each_entry(pol, &net->xfrm.policy_all, walk.all) {
++ dir = xfrm_policy_id2dir(pol->index);
++ if (pol->walk.dead ||
++ dir >= XFRM_POLICY_MAX ||
++ pol->xdo.dev != dev)
++ continue;
++
++ __xfrm_policy_unlink(pol, dir);
++ spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
++ cnt++;
++ xfrm_audit_policy_delete(pol, 1, task_valid);
++ xfrm_policy_kill(pol);
++ spin_lock_bh(&net->xfrm.xfrm_policy_lock);
++ goto again;
++ }
++ if (cnt)
++ __xfrm_policy_inexact_flush(net);
++ else
++ err = -ESRCH;
++out:
++ spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
++ return err;
++}
++EXPORT_SYMBOL(xfrm_dev_policy_flush);
++
+ int xfrm_policy_walk(struct net *net, struct xfrm_policy_walk *walk,
+ int (*func)(struct xfrm_policy *, int, int, void*),
+ void *data)
+@@ -2113,6 +2184,9 @@ static struct xfrm_policy *xfrm_policy_l
+ break;
+ }
+ }
++ if (ret && ret->xdo.type == XFRM_DEV_OFFLOAD_PACKET)
++ goto skip_inexact;
++
+ bin = xfrm_policy_inexact_lookup_rcu(net, type, family, dir, if_id);
+ if (!bin || !xfrm_policy_find_inexact_candidates(&cand, bin, saddr,
+ daddr))
+@@ -2246,6 +2320,7 @@ int xfrm_policy_delete(struct xfrm_polic
+ pol = __xfrm_policy_unlink(pol, dir);
+ spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
+ if (pol) {
++ xfrm_dev_policy_delete(pol);
+ xfrm_policy_kill(pol);
+ return 0;
+ }
+--- a/net/xfrm/xfrm_state.c
++++ b/net/xfrm/xfrm_state.c
+@@ -78,6 +78,25 @@ xfrm_spi_hash(struct net *net, const xfr
+ return __xfrm_spi_hash(daddr, spi, proto, family, net->xfrm.state_hmask);
+ }
+
++#define XFRM_STATE_INSERT(by, _n, _h, _type) \
++ { \
++ struct xfrm_state *_x = NULL; \
++ \
++ if (_type != XFRM_DEV_OFFLOAD_PACKET) { \
++ hlist_for_each_entry_rcu(_x, _h, by) { \
++ if (_x->xso.type == XFRM_DEV_OFFLOAD_PACKET) \
++ continue; \
++ break; \
++ } \
++ } \
++ \
++ if (!_x || _x->xso.type == XFRM_DEV_OFFLOAD_PACKET) \
++ /* SAD is empty or consist from HW SAs only */ \
++ hlist_add_head_rcu(_n, _h); \
++ else \
++ hlist_add_before_rcu(_n, &_x->by); \
++ }
++
+ static void xfrm_hash_transfer(struct hlist_head *list,
+ struct hlist_head *ndsttable,
+ struct hlist_head *nsrctable,
+@@ -93,18 +112,20 @@ static void xfrm_hash_transfer(struct hl
+ h = __xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
+ x->props.reqid, x->props.family,
+ nhashmask);
+- hlist_add_head_rcu(&x->bydst, ndsttable + h);
++ XFRM_STATE_INSERT(bydst, &x->bydst, ndsttable + h, x->xso.type);
+
+ h = __xfrm_src_hash(&x->id.daddr, &x->props.saddr,
+ x->props.family,
+ nhashmask);
+- hlist_add_head_rcu(&x->bysrc, nsrctable + h);
++ XFRM_STATE_INSERT(bysrc, &x->bysrc, nsrctable + h, x->xso.type);
+
+ if (x->id.spi) {
+ h = __xfrm_spi_hash(&x->id.daddr, x->id.spi,
+ x->id.proto, x->props.family,
+ nhashmask);
+ hlist_add_head_rcu(&x->byspi, nspitable + h);
++ XFRM_STATE_INSERT(byspi, &x->byspi, nspitable + h,
++ x->xso.type);
+ }
+ }
+ }
+@@ -527,6 +548,8 @@ static enum hrtimer_restart xfrm_timer_h
+ int err = 0;
+
+ spin_lock(&x->lock);
++ xfrm_dev_state_update_curlft(x);
++
+ if (x->km.state == XFRM_STATE_DEAD)
+ goto out;
+ if (x->km.state == XFRM_STATE_EXPIRED)
+@@ -923,6 +946,49 @@ xfrm_init_tempstate(struct xfrm_state *x
+ x->props.family = tmpl->encap_family;
+ }
+
++static struct xfrm_state *__xfrm_state_lookup_all(struct net *net, u32 mark,
++ const xfrm_address_t *daddr,
++ __be32 spi, u8 proto,
++ unsigned short family,
++ struct xfrm_state_offload *xdo)
++{
++ unsigned int h = xfrm_spi_hash(net, daddr, spi, proto, family);
++ struct xfrm_state *x;
++
++ hlist_for_each_entry_rcu(x, net->xfrm.state_byspi + h, byspi) {
++#ifdef CONFIG_XFRM_OFFLOAD
++ if (xdo->type == XFRM_DEV_OFFLOAD_PACKET) {
++ if (x->xso.type != XFRM_DEV_OFFLOAD_PACKET)
++ /* HW states are in the head of list, there is
++ * no need to iterate further.
++ */
++ break;
++
++ /* Packet offload: both policy and SA should
++ * have same device.
++ */
++ if (xdo->dev != x->xso.dev)
++ continue;
++ } else if (x->xso.type == XFRM_DEV_OFFLOAD_PACKET)
++ /* Skip HW policy for SW lookups */
++ continue;
++#endif
++ if (x->props.family != family ||
++ x->id.spi != spi ||
++ x->id.proto != proto ||
++ !xfrm_addr_equal(&x->id.daddr, daddr, family))
++ continue;
++
++ if ((mark & x->mark.m) != x->mark.v)
++ continue;
++ if (!xfrm_state_hold_rcu(x))
++ continue;
++ return x;
++ }
++
++ return NULL;
++}
++
+ static struct xfrm_state *__xfrm_state_lookup(struct net *net, u32 mark,
+ const xfrm_address_t *daddr,
+ __be32 spi, u8 proto,
+@@ -1062,6 +1128,23 @@ xfrm_state_find(const xfrm_address_t *da
+ rcu_read_lock();
+ h = xfrm_dst_hash(net, daddr, saddr, tmpl->reqid, encap_family);
+ hlist_for_each_entry_rcu(x, net->xfrm.state_bydst + h, bydst) {
++#ifdef CONFIG_XFRM_OFFLOAD
++ if (pol->xdo.type == XFRM_DEV_OFFLOAD_PACKET) {
++ if (x->xso.type != XFRM_DEV_OFFLOAD_PACKET)
++ /* HW states are in the head of list, there is
++ * no need to iterate further.
++ */
++ break;
++
++ /* Packet offload: both policy and SA should
++ * have same device.
++ */
++ if (pol->xdo.dev != x->xso.dev)
++ continue;
++ } else if (x->xso.type == XFRM_DEV_OFFLOAD_PACKET)
++ /* Skip HW policy for SW lookups */
++ continue;
++#endif
+ if (x->props.family == encap_family &&
+ x->props.reqid == tmpl->reqid &&
+ (mark & x->mark.m) == x->mark.v &&
+@@ -1079,6 +1162,23 @@ xfrm_state_find(const xfrm_address_t *da
+
+ h_wildcard = xfrm_dst_hash(net, daddr, &saddr_wildcard, tmpl->reqid, encap_family);
+ hlist_for_each_entry_rcu(x, net->xfrm.state_bydst + h_wildcard, bydst) {
++#ifdef CONFIG_XFRM_OFFLOAD
++ if (pol->xdo.type == XFRM_DEV_OFFLOAD_PACKET) {
++ if (x->xso.type != XFRM_DEV_OFFLOAD_PACKET)
++ /* HW states are in the head of list, there is
++ * no need to iterate further.
++ */
++ break;
++
++ /* Packet offload: both policy and SA should
++ * have same device.
++ */
++ if (pol->xdo.dev != x->xso.dev)
++ continue;
++ } else if (x->xso.type == XFRM_DEV_OFFLOAD_PACKET)
++ /* Skip HW policy for SW lookups */
++ continue;
++#endif
+ if (x->props.family == encap_family &&
+ x->props.reqid == tmpl->reqid &&
+ (mark & x->mark.m) == x->mark.v &&
+@@ -1096,8 +1196,10 @@ found:
+ x = best;
+ if (!x && !error && !acquire_in_progress) {
+ if (tmpl->id.spi &&
+- (x0 = __xfrm_state_lookup(net, mark, daddr, tmpl->id.spi,
+- tmpl->id.proto, encap_family)) != NULL) {
++ (x0 = __xfrm_state_lookup_all(net, mark, daddr,
++ tmpl->id.spi, tmpl->id.proto,
++ encap_family,
++ &pol->xdo)) != NULL) {
+ to_put = x0;
+ error = -EEXIST;
+ goto out;
+@@ -1131,17 +1233,42 @@ found:
+ x = NULL;
+ goto out;
+ }
+-
++#ifdef CONFIG_XFRM_OFFLOAD
++ if (pol->xdo.type == XFRM_DEV_OFFLOAD_PACKET) {
++ struct xfrm_state_offload *xdo = &pol->xdo;
++ struct xfrm_state_offload *xso = &x->xso;
++
++ xso->type = XFRM_DEV_OFFLOAD_PACKET;
++ xso->dir = xdo->dir;
++ xso->dev = xdo->dev;
++ error = xso->dev->xfrmdev_ops->xdo_dev_state_add(x);
++ if (error) {
++ xso->dir = 0;
++ xso->dev = NULL;
++ xso->type = XFRM_DEV_OFFLOAD_UNSPECIFIED;
++ x->km.state = XFRM_STATE_DEAD;
++ to_put = x;
++ x = NULL;
++ goto out;
++ }
++ }
++#endif
+ if (km_query(x, tmpl, pol) == 0) {
+ spin_lock_bh(&net->xfrm.xfrm_state_lock);
+ x->km.state = XFRM_STATE_ACQ;
+ list_add(&x->km.all, &net->xfrm.state_all);
+- hlist_add_head_rcu(&x->bydst, net->xfrm.state_bydst + h);
++ XFRM_STATE_INSERT(bydst, &x->bydst,
++ net->xfrm.state_bydst + h,
++ x->xso.type);
+ h = xfrm_src_hash(net, daddr, saddr, encap_family);
+- hlist_add_head_rcu(&x->bysrc, net->xfrm.state_bysrc + h);
++ XFRM_STATE_INSERT(bysrc, &x->bysrc,
++ net->xfrm.state_bysrc + h,
++ x->xso.type);
+ if (x->id.spi) {
+ h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, encap_family);
+- hlist_add_head_rcu(&x->byspi, net->xfrm.state_byspi + h);
++ XFRM_STATE_INSERT(byspi, &x->byspi,
++ net->xfrm.state_byspi + h,
++ x->xso.type);
+ }
+ x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires;
+ hrtimer_start(&x->mtimer,
+@@ -1151,6 +1278,16 @@ found:
+ xfrm_hash_grow_check(net, x->bydst.next != NULL);
+ spin_unlock_bh(&net->xfrm.xfrm_state_lock);
+ } else {
++#ifdef CONFIG_XFRM_OFFLOAD
++ struct xfrm_state_offload *xso = &x->xso;
++
++ if (xso->type == XFRM_DEV_OFFLOAD_PACKET) {
++ xso->dev->xfrmdev_ops->xdo_dev_state_delete(x);
++ xso->dir = 0;
++ xso->dev = NULL;
++ xso->type = XFRM_DEV_OFFLOAD_UNSPECIFIED;
++ }
++#endif
+ x->km.state = XFRM_STATE_DEAD;
+ to_put = x;
+ x = NULL;
+@@ -1246,16 +1383,19 @@ static void __xfrm_state_insert(struct x
+
+ h = xfrm_dst_hash(net, &x->id.daddr, &x->props.saddr,
+ x->props.reqid, x->props.family);
+- hlist_add_head_rcu(&x->bydst, net->xfrm.state_bydst + h);
++ XFRM_STATE_INSERT(bydst, &x->bydst, net->xfrm.state_bydst + h,
++ x->xso.type);
+
+ h = xfrm_src_hash(net, &x->id.daddr, &x->props.saddr, x->props.family);
+- hlist_add_head_rcu(&x->bysrc, net->xfrm.state_bysrc + h);
++ XFRM_STATE_INSERT(bysrc, &x->bysrc, net->xfrm.state_bysrc + h,
++ x->xso.type);
+
+ if (x->id.spi) {
+ h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto,
+ x->props.family);
+
+- hlist_add_head_rcu(&x->byspi, net->xfrm.state_byspi + h);
++ XFRM_STATE_INSERT(byspi, &x->byspi, net->xfrm.state_byspi + h,
++ x->xso.type);
+ }
+
+ hrtimer_start(&x->mtimer, ktime_set(1, 0), HRTIMER_MODE_REL_SOFT);
+@@ -1369,9 +1509,11 @@ static struct xfrm_state *__find_acq_cor
+ ktime_set(net->xfrm.sysctl_acq_expires, 0),
+ HRTIMER_MODE_REL_SOFT);
+ list_add(&x->km.all, &net->xfrm.state_all);
+- hlist_add_head_rcu(&x->bydst, net->xfrm.state_bydst + h);
++ XFRM_STATE_INSERT(bydst, &x->bydst, net->xfrm.state_bydst + h,
++ x->xso.type);
+ h = xfrm_src_hash(net, daddr, saddr, family);
+- hlist_add_head_rcu(&x->bysrc, net->xfrm.state_bysrc + h);
++ XFRM_STATE_INSERT(bysrc, &x->bysrc, net->xfrm.state_bysrc + h,
++ x->xso.type);
+
+ net->xfrm.state_num++;
+
+@@ -1742,6 +1884,8 @@ EXPORT_SYMBOL(xfrm_state_update);
+
+ int xfrm_state_check_expire(struct xfrm_state *x)
+ {
++ xfrm_dev_state_update_curlft(x);
++
+ if (!x->curlft.use_time)
+ x->curlft.use_time = ktime_get_real_seconds();
+
+@@ -2043,7 +2187,8 @@ int xfrm_alloc_spi(struct xfrm_state *x,
+ spin_lock_bh(&net->xfrm.xfrm_state_lock);
+ x->id.spi = newspi;
+ h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, x->props.family);
+- hlist_add_head_rcu(&x->byspi, net->xfrm.state_byspi + h);
++ XFRM_STATE_INSERT(byspi, &x->byspi, net->xfrm.state_byspi + h,
++ x->xso.type);
+ spin_unlock_bh(&net->xfrm.xfrm_state_lock);
+
+ err = 0;
+--- a/net/xfrm/xfrm_user.c
++++ b/net/xfrm/xfrm_user.c
+@@ -844,6 +844,8 @@ static int copy_user_offload(struct xfrm
+ memset(xuo, 0, sizeof(*xuo));
+ xuo->ifindex = xso->dev->ifindex;
+ xuo->flags = xso->flags;
++ if (xso->type == XFRM_DEV_OFFLOAD_PACKET)
++ xuo->flags |= XFRM_OFFLOAD_PACKET;
+
+ return 0;
+ }
+@@ -1634,6 +1636,15 @@ static struct xfrm_policy *xfrm_policy_c
+ if (attrs[XFRMA_IF_ID])
+ xp->if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
+
++ /* configure the hardware if offload is requested */
++ if (attrs[XFRMA_OFFLOAD_DEV]) {
++ err = xfrm_dev_policy_add(net, xp,
++ nla_data(attrs[XFRMA_OFFLOAD_DEV]),
++ p->dir, 0);
++ if (err)
++ goto error;
++ }
++
+ return xp;
+ error:
+ *errp = err;
+@@ -1672,6 +1683,7 @@ static int xfrm_add_policy(struct sk_buf
+ xfrm_audit_policy_add(xp, err ? 0 : 1, true);
+
+ if (err) {
++ xfrm_dev_policy_delete(xp);
+ security_xfrm_policy_free(xp->security);
+ kfree(xp);
+ return err;
+@@ -1783,6 +1795,8 @@ static int dump_one_policy(struct xfrm_p
+ err = xfrm_mark_put(skb, &xp->mark);
+ if (!err)
+ err = xfrm_if_id_put(skb, xp->if_id);
++ if (!err && xp->xdo.dev)
++ err = copy_user_offload(&xp->xdo, skb);
+ if (err) {
+ nlmsg_cancel(skb, nlh);
+ return err;
+@@ -2958,6 +2972,8 @@ static int build_acquire(struct sk_buff
+ err = xfrm_mark_put(skb, &xp->mark);
+ if (!err)
+ err = xfrm_if_id_put(skb, xp->if_id);
++ if (!err && xp->xdo.dev)
++ err = copy_user_offload(&xp->xdo, skb);
+ if (err) {
+ nlmsg_cancel(skb, nlh);
+ return err;
+@@ -3076,6 +3092,8 @@ static int build_polexpire(struct sk_buf
+ err = xfrm_mark_put(skb, &xp->mark);
+ if (!err)
+ err = xfrm_if_id_put(skb, xp->if_id);
++ if (!err && xp->xdo.dev)
++ err = copy_user_offload(&xp->xdo, skb);
+ if (err) {
+ nlmsg_cancel(skb, nlh);
+ return err;
+@@ -3159,6 +3177,8 @@ static int xfrm_notify_policy(struct xfr
+ err = xfrm_mark_put(skb, &xp->mark);
+ if (!err)
+ err = xfrm_if_id_put(skb, xp->if_id);
++ if (!err && xp->xdo.dev)
++ err = copy_user_offload(&xp->xdo, skb);
+ if (err)
+ goto out_free_skb;
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-2728-xfrm-extend-packet-mode-to-support-esp-tunnel-mode.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-2728-xfrm-extend-packet-mode-to-support-esp-tunnel-mode.patch
new file mode 100644
index 0000000..ba9bc98
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-2728-xfrm-extend-packet-mode-to-support-esp-tunnel-mode.patch
@@ -0,0 +1,28 @@
+--- a/net/xfrm/xfrm_output.c
++++ b/net/xfrm/xfrm_output.c
+@@ -410,7 +410,7 @@ static int xfrm_output_one(struct sk_buf
+ struct xfrm_state *x = dst->xfrm;
+ struct net *net = xs_net(x);
+
+- if (err <= 0 || x->xso.type == XFRM_DEV_OFFLOAD_PACKET)
++ if (err <= 0)
+ goto resume;
+
+ do {
+@@ -568,16 +568,6 @@ int xfrm_output(struct sock *sk, struct
+ struct xfrm_state *x = skb_dst(skb)->xfrm;
+ int err;
+
+- if (x->xso.type == XFRM_DEV_OFFLOAD_PACKET) {
+- if (!xfrm_dev_offload_ok(skb, x)) {
+- XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR);
+- kfree_skb(skb);
+- return -EHOSTUNREACH;
+- }
+-
+- return xfrm_output_resume(skb, 0);
+- }
+-
+ secpath_reset(skb);
+
+ if (xfrm_dev_offload_ok(skb, x)) {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4100-mtk-tops-tunnel-offload-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4100-mtk-tunnel-offload-support.patch
similarity index 81%
rename from recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4100-mtk-tops-tunnel-offload-support.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4100-mtk-tunnel-offload-support.patch
index a4a6d95..57a1dde 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4100-mtk-tops-tunnel-offload-support.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4100-mtk-tunnel-offload-support.patch
@@ -10,7 +10,7 @@
void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg)
{
__raw_writel(val, eth->base + reg);
-@@ -2089,6 +2092,7 @@ static int mtk_poll_rx(struct napi_struc
+@@ -2171,6 +2174,7 @@ static int mtk_poll_rx(struct napi_struc
u64 addr64 = 0;
u8 *data, *new_data;
struct mtk_rx_dma_v2 *rxd, trxd;
@@ -18,7 +18,7 @@
int done = 0;
if (unlikely(!ring))
-@@ -2132,11 +2136,20 @@ static int mtk_poll_rx(struct napi_struc
+@@ -2214,11 +2218,20 @@ static int mtk_poll_rx(struct napi_struc
0 : RX_DMA_GET_SPORT(trxd.rxd4) - 1;
}
@@ -43,7 +43,7 @@
if (unlikely(test_bit(MTK_RESETTING, ð->state)))
goto release_desc;
-@@ -2221,6 +2234,8 @@ static int mtk_poll_rx(struct napi_struc
+@@ -2303,6 +2316,8 @@ static int mtk_poll_rx(struct napi_struc
skb_hnat_alg(skb) = 0;
skb_hnat_filled(skb) = 0;
skb_hnat_magic_tag(skb) = HNAT_MAGIC_TAG;
@@ -94,16 +94,16 @@
{
--- a/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h
+++ b/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h
-@@ -1085,6 +1085,8 @@ enum FoeIpAct {
- #define NR_WDMA0_PORT 8
+@@ -1087,6 +1087,8 @@ enum FoeIpAct {
#define NR_WDMA1_PORT 9
+ #define NR_WDMA2_PORT 13
#define NR_GMAC3_PORT 15
+#define NR_TDMA_TPORT 4
+#define NR_TDMA_QDMA_TPORT 5
#define LAN_DEV_NAME hnat_priv->lan
#define LAN2_DEV_NAME hnat_priv->lan2
#define IS_WAN(dev) \
-@@ -1208,6 +1210,8 @@ static inline bool hnat_dsa_is_enable(st
+@@ -1210,6 +1212,8 @@ static inline bool hnat_dsa_is_enable(st
}
#endif
@@ -112,7 +112,7 @@
void hnat_deinit_debugfs(struct mtk_hnat *h);
int hnat_init_debugfs(struct mtk_hnat *h);
int hnat_register_nf_hooks(void);
-@@ -1224,6 +1228,9 @@ extern int qos_ul_toggle;
+@@ -1226,6 +1230,9 @@ extern int qos_ul_toggle;
extern int hook_toggle;
extern int mape_toggle;
extern int qos_toggle;
@@ -192,7 +192,7 @@
rcu_read_unlock_bh();
return 0;
-@@ -1202,6 +1233,37 @@ static struct ethhdr *get_ipv6_ipip_ethh
+@@ -1202,6 +1233,81 @@ static struct ethhdr *get_ipv6_ipip_ethh
return eth;
}
@@ -205,10 +205,53 @@
+ memcpy(entry,
+ &hnat_priv->foe_table_cpu[skb_hnat_ppe(skb)][skb_hnat_entry(skb)],
+ sizeof(*entry));
++
++#if defined(CONFIG_MEDIATEK_NETSYS_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
++ entry->bfib1.mc = 0;
++#endif /* defined(CONFIG_MEDIATEK_NETSYS_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3) */
++ entry->bfib1.ka = 0;
++ entry->bfib1.vlan_layer = 0;
++ entry->bfib1.psn = 0;
++ entry->bfib1.vpm = 0;
++ entry->bfib1.ps = 0;
++}
++
++static inline void hnat_qos_tnl(u32 id, const struct net_device *dev)
++{
++ u32 cfg;
++ u32 max_man = 0;
++ u32 max_exp = 0;
++ const struct mtk_mac *mac;
++
++ if (!dev)
++ return;
++ mac = netdev_priv(dev);
++
++ switch (mac->speed) {
++ case SPEED_100:
++ case SPEED_1000:
++ case SPEED_2500:
++ case SPEED_5000:
++ case SPEED_10000:
++ max_man = mac->speed / SPEED_100;
++ max_exp = 5;
++ break;
++ default:
++ return;
++ }
++
++ cfg = QTX_SCH_MIN_RATE_EN | QTX_SCH_MAX_RATE_EN;
++ cfg |= (1 << QTX_SCH_MIN_RATE_MAN_OFFSET) |
++ (4 << QTX_SCH_MIN_RATE_EXP_OFFSET) |
++ (max_man << QTX_SCH_MAX_RATE_MAN_OFFSET) |
++ (max_exp << QTX_SCH_MAX_RATE_EXP_OFFSET) |
++ (4 << QTX_SCH_MAX_RATE_WGHT_OFFSET);
++ writel(cfg, hnat_priv->fe_base + QTX_SCH(id % NUM_OF_Q_PER_PAGE));
+}
+
+static inline void hnat_fill_offload_engine_entry(struct sk_buff *skb,
-+ struct foe_entry *entry)
++ struct foe_entry *entry,
++ const struct net_device *dev)
+{
+#if defined(CONFIG_MEDIATEK_NETSYS_V3)
+ if (skb_hnat_tops(skb) && skb_hnat_is_encap(skb)) {
@@ -224,13 +267,14 @@
+ }
+
+ entry->ipv4_hnapt.iblk2.qid = 12; /* offload engine use QID 12 */
++ hnat_qos_tnl(12, dev); /* set rate limit to line rate */
+#endif /* defined(CONFIG_MEDIATEK_NETSYS_V3) */
+}
+
static unsigned int skb_to_hnat_info(struct sk_buff *skb,
const struct net_device *dev,
struct foe_entry *foe,
-@@ -1237,6 +1299,11 @@ static unsigned int skb_to_hnat_info(str
+@@ -1238,6 +1344,11 @@ static unsigned int skb_to_hnat_info(str
if (whnat && is_hnat_pre_filled(foe))
return 0;
@@ -242,15 +286,7 @@
entry.bfib1.pkt_type = foe->udib1.pkt_type; /* Get packte type state*/
entry.bfib1.state = foe->udib1.state;
-@@ -1247,6 +1314,7 @@ static unsigned int skb_to_hnat_info(str
- switch (ntohs(eth->h_proto)) {
- case ETH_P_IP:
- iph = ip_hdr(skb);
-+
- switch (iph->protocol) {
- case IPPROTO_UDP:
- udp = 1;
-@@ -1628,6 +1696,10 @@ static unsigned int skb_to_hnat_info(str
+@@ -1633,6 +1744,10 @@ static unsigned int skb_to_hnat_info(str
/* Fill Layer2 Info.*/
entry = ppe_fill_L2_info(eth, entry, hw_path);
@@ -261,12 +297,12 @@
/* Fill Info Blk*/
entry = ppe_fill_info_blk(eth, entry, hw_path);
-@@ -1806,7 +1878,20 @@ static unsigned int skb_to_hnat_info(str
+@@ -1833,7 +1948,20 @@ static unsigned int skb_to_hnat_info(str
entry.ipv6_5t_route.act_dp |= UDF_HNAT_PRE_FILLED;
}
+#if defined(CONFIG_MEDIATEK_NETSYS_V3)
-+ hnat_fill_offload_engine_entry(skb, &entry);
++ hnat_fill_offload_engine_entry(skb, &entry, dev);
+#endif
+
+hnat_entry_skip_bind:
@@ -282,7 +318,7 @@
memcpy(foe, &entry, sizeof(entry));
/*reset statistic for this entry*/
if (hnat_priv->data->per_flow_accounting &&
-@@ -1859,6 +1944,7 @@ int mtk_sw_nat_hook_tx(struct sk_buff *s
+@@ -1886,6 +2014,7 @@ int mtk_sw_nat_hook_tx(struct sk_buff *s
return NF_ACCEPT;
eth = eth_hdr(skb);
@@ -290,7 +326,7 @@
memcpy(&bfib1_tx, &entry->bfib1, sizeof(entry->bfib1));
/*not bind multicast if PPE mcast not enable*/
-@@ -1878,6 +1964,12 @@ int mtk_sw_nat_hook_tx(struct sk_buff *s
+@@ -1905,6 +2034,12 @@ int mtk_sw_nat_hook_tx(struct sk_buff *s
switch ((int)bfib1_tx.pkt_type) {
case IPV4_HNAPT:
case IPV4_HNAT:
@@ -303,18 +339,18 @@
entry->ipv4_hnapt.smac_hi = swab32(*((u32 *)eth->h_source));
entry->ipv4_hnapt.smac_lo = swab16(*((u16 *)ð->h_source[4]));
break;
-@@ -2037,6 +2129,10 @@ int mtk_sw_nat_hook_tx(struct sk_buff *s
+@@ -2066,6 +2201,10 @@ int mtk_sw_nat_hook_tx(struct sk_buff *s
entry->ipv6_5t_route.iblk2.dp = gmac_no;
}
+#if defined(CONFIG_MEDIATEK_NETSYS_V3)
-+ hnat_fill_offload_engine_entry(skb, entry);
++ hnat_fill_offload_engine_entry(skb, entry, NULL);
+#endif
+
bfib1_tx.ttl = 1;
bfib1_tx.state = BIND;
wmb();
-@@ -2058,6 +2154,7 @@ int mtk_sw_nat_hook_rx(struct sk_buff *s
+@@ -2087,6 +2226,7 @@ int mtk_sw_nat_hook_rx(struct sk_buff *s
}
skb_hnat_alg(skb) = 0;
@@ -322,7 +358,7 @@
skb_hnat_magic_tag(skb) = HNAT_MAGIC_TAG;
if (skb_hnat_iface(skb) == FOE_MAGIC_WED0)
-@@ -2504,6 +2601,7 @@ static unsigned int mtk_hnat_nf_post_rou
+@@ -2535,6 +2675,7 @@ static unsigned int mtk_hnat_nf_post_rou
struct flow_offload_hw_path hw_path = { .dev = (struct net_device*)out,
.virt_dev = (struct net_device*)out };
const struct net_device *arp_dev = out;
@@ -330,14 +366,25 @@
if (xlat_toggle && !mtk_464xlat_post_process(skb, out))
return 0;
-@@ -2524,10 +2622,18 @@ static unsigned int mtk_hnat_nf_post_rou
+@@ -2551,10 +2692,29 @@ static unsigned int mtk_hnat_nf_post_rou
if (out->netdev_ops->ndo_flow_offload_check) {
out->netdev_ops->ndo_flow_offload_check(&hw_path);
+
out = (IS_GMAC1_MODE) ? hw_path.virt_dev : hw_path.dev;
-+ if (hw_path.flags & FLOW_OFFLOAD_PATH_TNL && mtk_tnl_encap_offload)
-+ skb_hnat_set_tops(skb, hw_path.tnl_type + 1);
++ if (hw_path.flags & FLOW_OFFLOAD_PATH_TNL && mtk_tnl_encap_offload) {
++ if (ntohs(skb->protocol) == ETH_P_IP
++ && ip_hdr(skb)->protocol == IPPROTO_TCP) {
++ skb_hnat_set_tops(skb, hw_path.tnl_type + 1);
++ } else {
++ /*
++ * we are not support protocols other than IPv4 TCP
++ * for tunnel protocol offload yet
++ */
++ skb_hnat_alg(skb) = 1;
++ return 0;
++ }
++ }
}
if (!IS_LAN_GRP(out) && !IS_WAN(out) && !IS_EXT(out))
@@ -349,7 +396,7 @@
return 0;
trace_printk("[%s] case hit, %x-->%s, reason=%x\n", __func__,
-@@ -2547,9 +2653,18 @@ static unsigned int mtk_hnat_nf_post_rou
+@@ -2574,9 +2734,18 @@ static unsigned int mtk_hnat_nf_post_rou
if (fn && !mtk_hnat_accel_type(skb))
break;
@@ -369,7 +416,7 @@
skb_to_hnat_info(skb, out, entry, &hw_path);
break;
case HIT_BIND_KEEPALIVE_DUP_OLD_HDR:
-@@ -2820,7 +2935,7 @@ mtk_hnat_ipv4_nf_local_out(void *priv, s
+@@ -2847,7 +3016,7 @@ mtk_hnat_ipv4_nf_local_out(void *priv, s
if (iph->protocol == IPPROTO_IPV6) {
entry->udib1.pkt_type = IPV6_6RD;
hnat_set_head_frags(state, skb, 0, hnat_set_alg);
@@ -438,7 +485,7 @@
u8 eth_dest[ETH_ALEN];
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -1868,6 +1868,9 @@ extern const struct of_device_id of_mtk_
+@@ -1874,6 +1874,9 @@ extern const struct of_device_id of_mtk_
extern u32 mtk_hwlro_stats_ebl;
extern u32 dbg_show_level;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4101-mtk-tops-network-service-error-recover-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4101-mtk-tunnel-network-service-error-recover-support.patch
similarity index 96%
rename from recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4101-mtk-tops-network-service-error-recover-support.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4101-mtk-tunnel-network-service-error-recover-support.patch
index fbb46ac..9f9e26a 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4101-mtk-tops-network-service-error-recover-support.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4101-mtk-tunnel-network-service-error-recover-support.patch
@@ -38,7 +38,7 @@
#define MTK_ETHTOOL_STAT(x) { #x, \
offsetof(struct mtk_hw_stats, x) / sizeof(u64) }
-@@ -4057,6 +4058,8 @@ static void mtk_pending_work(struct work
+@@ -4141,6 +4142,8 @@ static void mtk_pending_work(struct work
}
pr_warn("wait for MTK_FE_START_RESET\n");
}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4102-mtk-crypto-offload-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4102-mtk-crypto-offload-support.patch
new file mode 100644
index 0000000..75880ed
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4102-mtk-crypto-offload-support.patch
@@ -0,0 +1,183 @@
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -2316,6 +2316,7 @@ static int mtk_poll_rx(struct napi_struc
+
+ skb_hnat_alg(skb) = 0;
+ skb_hnat_filled(skb) = 0;
++ skb_hnat_set_cdrt(skb, 0);
+ skb_hnat_magic_tag(skb) = HNAT_MAGIC_TAG;
+ skb_hnat_set_tops(skb, 0);
+ skb_hnat_set_is_decap(skb, 0);
+--- a/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
++++ b/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
+@@ -1076,6 +1076,9 @@ static unsigned int hnat_ipv4_get_nextho
+ return 0;
+ }
+
++ if (!skb_hnat_cdrt(skb) && dst && dst_xfrm(dst))
++ return 0;
++
+ rcu_read_lock_bh();
+ nexthop = (__force u32)rt_nexthop(rt, ip_hdr(skb)->daddr);
+ neigh = __ipv4_neigh_lookup_noref(dev, nexthop);
+@@ -1097,7 +1100,7 @@ static unsigned int hnat_ipv4_get_nextho
+ * outer header, we must update its outer mac header pointer
+ * before filling outer mac or it may screw up inner mac
+ */
+- if (skb_hnat_tops(skb) && skb_hnat_is_encap(skb)) {
++ if ((skb_hnat_tops(skb) && skb_hnat_is_encap(skb)) || skb_hnat_cdrt(skb)) {
+ skb_push(skb, sizeof(struct ethhdr));
+ skb_reset_mac_header(skb);
+ }
+@@ -1105,7 +1108,7 @@ static unsigned int hnat_ipv4_get_nextho
+ memcpy(eth_hdr(skb)->h_dest, neigh->ha, ETH_ALEN);
+ memcpy(eth_hdr(skb)->h_source, out->dev_addr, ETH_ALEN);
+
+- if (skb_hnat_tops(skb) && skb_hnat_is_encap(skb))
++ if ((skb_hnat_tops(skb) && skb_hnat_is_encap(skb)) || skb_hnat_cdrt(skb))
+ skb_pull(skb, sizeof(struct ethhdr));
+
+ rcu_read_unlock_bh();
+@@ -1299,6 +1302,9 @@ static inline void hnat_fill_offload_eng
+ */
+ entry->ipv4_hnapt.tport_id = NR_TDMA_QDMA_TPORT;
+ entry->ipv4_hnapt.tops_entry = skb_hnat_tops(skb);
++ } else if (skb_hnat_cdrt(skb)) {
++ entry->ipv4_hnapt.tport_id = NR_EIP197_QDMA_TPORT;
++ entry->ipv4_hnapt.cdrt_id = skb_hnat_cdrt(skb);
+ } else {
+ return;
+ }
+@@ -1344,7 +1350,8 @@ static unsigned int skb_to_hnat_info(str
+ if (whnat && is_hnat_pre_filled(foe))
+ return 0;
+
+- if (skb_hnat_tops(skb) && !(hw_path->flags & FLOW_OFFLOAD_PATH_TNL)) {
++ if ((skb_hnat_tops(skb) && !(hw_path->flags & FLOW_OFFLOAD_PATH_TNL))
++ || (skb_hnat_cdrt(skb) && skb_dst(skb) && !dst_xfrm(skb_dst(skb)))) {
+ hnat_get_filled_unbind_entry(skb, &entry);
+ goto hnat_entry_bind;
+ }
+@@ -1744,7 +1751,8 @@ static unsigned int skb_to_hnat_info(str
+ /* Fill Layer2 Info.*/
+ entry = ppe_fill_L2_info(eth, entry, hw_path);
+
+- if (skb_hnat_tops(skb) && hw_path->flags & FLOW_OFFLOAD_PATH_TNL)
++ if ((skb_hnat_tops(skb) && hw_path->flags & FLOW_OFFLOAD_PATH_TNL)
++ || (!skb_hnat_cdrt(skb) && skb_dst(skb) && dst_xfrm(skb_dst(skb))))
+ goto hnat_entry_skip_bind;
+
+ hnat_entry_bind:
+@@ -1950,6 +1958,8 @@ hnat_entry_bind:
+
+ #if defined(CONFIG_MEDIATEK_NETSYS_V3)
+ hnat_fill_offload_engine_entry(skb, &entry, dev);
++ if (skb_hnat_cdrt(skb))
++ entry = ppe_fill_L2_info(eth, entry, hw_path);
+ #endif
+
+ hnat_entry_skip_bind:
+@@ -2227,6 +2237,7 @@ int mtk_sw_nat_hook_rx(struct sk_buff *s
+
+ skb_hnat_alg(skb) = 0;
+ skb_hnat_set_tops(skb, 0);
++ skb_hnat_set_cdrt(skb, 0);
+ skb_hnat_magic_tag(skb) = HNAT_MAGIC_TAG;
+
+ if (skb_hnat_iface(skb) == FOE_MAGIC_WED0)
+@@ -2313,7 +2324,8 @@ static unsigned int mtk_hnat_accel_type(
+ * is from local_out which is also filtered in sanity check.
+ */
+ dst = skb_dst(skb);
+- if (dst && dst_xfrm(dst))
++ if (dst && dst_xfrm(dst)
++ && (!mtk_crypto_offloadable || !mtk_crypto_offloadable(skb)))
+ return 0;
+
+ ct = nf_ct_get(skb, &ctinfo);
+@@ -2709,6 +2721,14 @@ static unsigned int mtk_hnat_nf_post_rou
+ }
+ }
+
++ /* we are not support protocols other than IPv4 TCP for crypto offload yet */
++ if (skb_hnat_is_decrypt(skb)
++ && (ntohs(skb->protocol) != ETH_P_IP
++ || ip_hdr(skb)->protocol != IPPROTO_TCP)) {
++ skb_hnat_alg(skb) = 1;
++ return 0;
++ }
++
+ if (!IS_LAN_GRP(out) && !IS_WAN(out) && !IS_EXT(out))
+ is_virt_dev = true;
+
+@@ -3016,7 +3036,10 @@ mtk_hnat_ipv4_nf_local_out(void *priv, s
+ if (iph->protocol == IPPROTO_IPV6) {
+ entry->udib1.pkt_type = IPV6_6RD;
+ hnat_set_head_frags(state, skb, 0, hnat_set_alg);
+- } else if (!skb_hnat_tops(skb)) {
++ } else if (is_magic_tag_valid(skb)
++ && (skb_hnat_cdrt(skb) || skb_hnat_tops(skb))) {
++ hnat_set_head_frags(state, skb, 0, hnat_set_alg);
++ } else {
+ hnat_set_head_frags(state, skb, 1, hnat_set_alg);
+ }
+
+--- a/drivers/net/ethernet/mediatek/mtk_hnat/nf_hnat_mtk.h
++++ b/drivers/net/ethernet/mediatek/mtk_hnat/nf_hnat_mtk.h
+@@ -46,7 +46,8 @@ struct hnat_desc {
+ u32 amsdu : 1;
+ u32 tops : 6;
+ u32 is_decap : 1;
+- u32 resv3 : 12;
++ u32 cdrt : 8;
++ u32 resv3 : 4;
+ u32 magic_tag_protect : 16;
+ } __packed;
+ #elif defined(CONFIG_MEDIATEK_NETSYS_RX_V2)
+@@ -99,12 +100,16 @@ struct hnat_desc {
+ #define skb_hnat_is_encap(skb) (!skb_hnat_is_decap(skb))
+ #define skb_hnat_set_tops(skb, tops) ((skb_hnat_tops(skb)) = (tops))
+ #define skb_hnat_set_is_decap(skb, is_decap) ((skb_hnat_is_decap(skb)) = (is_decap))
++#define skb_hnat_cdrt(skb) (((struct hnat_desc *)((skb)->head))->cdrt)
++#define skb_hnat_set_cdrt(skb, cdrt) ((skb_hnat_cdrt(skb)) = (cdrt))
+ #else /* !defined(CONFIG_MEDIATEK_NETSYS_V3) */
+ #define skb_hnat_tops(skb) (0)
+ #define skb_hnat_is_decap(skb) (0)
+ #define skb_hnat_is_encap(skb) (0)
+ #define skb_hnat_set_tops(skb, tops)
+ #define skb_hnat_set_is_decap(skb, is_decap)
++#define skb_hnat_cdrt(skb) (0)
++#define skb_hnat_set_cdrt(skb, cdrt)
+ #endif /* defined(CONFIG_MEDIATEK_NETSYS_V3) */
+ #define skb_hnat_magic(skb) (((struct hnat_desc *)(skb->head))->magic)
+ #define skb_hnat_reason(skb) (((struct hnat_desc *)(skb->head))->crsn)
+--- a/drivers/net/ethernet/mediatek/mtk_hnat/hnat.c
++++ b/drivers/net/ethernet/mediatek/mtk_hnat/hnat.c
+@@ -49,6 +49,8 @@ int (*mtk_tnl_decap_offload)(struct sk_b
+ EXPORT_SYMBOL(mtk_tnl_decap_offload);
+ bool (*mtk_tnl_decap_offloadable)(struct sk_buff *skb) = NULL;
+ EXPORT_SYMBOL(mtk_tnl_decap_offloadable);
++bool (*mtk_crypto_offloadable)(struct sk_buff *skb) = NULL;
++EXPORT_SYMBOL(mtk_crypto_offloadable);
+
+ static void hnat_sma_build_entry(struct timer_list *t)
+ {
+--- a/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h
++++ b/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h
+@@ -1087,6 +1087,8 @@ enum FoeIpAct {
+ #define NR_WDMA1_PORT 9
+ #define NR_WDMA2_PORT 13
+ #define NR_GMAC3_PORT 15
++#define NR_EIP197_TPORT 2
++#define NR_EIP197_QDMA_TPORT 3
+ #define NR_TDMA_TPORT 4
+ #define NR_TDMA_QDMA_TPORT 5
+ #define LAN_DEV_NAME hnat_priv->lan
+@@ -1233,6 +1235,7 @@ extern int qos_toggle;
+ extern int (*mtk_tnl_encap_offload)(struct sk_buff *skb);
+ extern int (*mtk_tnl_decap_offload)(struct sk_buff *skb);
+ extern bool (*mtk_tnl_decap_offloadable)(struct sk_buff *skb);
++extern bool (*mtk_crypto_offloadable)(struct sk_buff *skb);
+
+ int ext_if_add(struct extdev_entry *ext_entry);
+ int ext_if_del(struct extdev_entry *ext_entry);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4103-mtk-tunnel-crypto-offload-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4103-mtk-tunnel-crypto-offload-support.patch
new file mode 100644
index 0000000..b2cc240
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4103-mtk-tunnel-crypto-offload-support.patch
@@ -0,0 +1,211 @@
+--- a/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h
++++ b/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h
+@@ -1091,6 +1091,8 @@ enum FoeIpAct {
+ #define NR_EIP197_QDMA_TPORT 3
+ #define NR_TDMA_TPORT 4
+ #define NR_TDMA_QDMA_TPORT 5
++#define NR_TDMA_EIP197_TPORT 8
++#define NR_TDMA_EIP197_QDMA_TPORT 9
+ #define LAN_DEV_NAME hnat_priv->lan
+ #define LAN2_DEV_NAME hnat_priv->lan2
+ #define IS_WAN(dev) \
+--- a/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
++++ b/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
+@@ -1099,7 +1099,8 @@ static unsigned int hnat_ipv4_get_nextho
+ * outer header, we must update its outer mac header pointer
+ * before filling outer mac or it may screw up inner mac
+ */
+- if ((skb_hnat_tops(skb) && skb_hnat_is_encap(skb)) || skb_hnat_cdrt(skb)) {
++ if ((skb_hnat_tops(skb) && skb_hnat_is_encap(skb))
++ || (skb_hnat_cdrt(skb) && skb_hnat_is_encrypt(skb))) {
+ skb_push(skb, sizeof(struct ethhdr));
+ skb_reset_mac_header(skb);
+ }
+@@ -1107,7 +1108,8 @@ static unsigned int hnat_ipv4_get_nextho
+ memcpy(eth_hdr(skb)->h_dest, neigh->ha, ETH_ALEN);
+ memcpy(eth_hdr(skb)->h_source, out->dev_addr, ETH_ALEN);
+
+- if ((skb_hnat_tops(skb) && skb_hnat_is_encap(skb)) || skb_hnat_cdrt(skb))
++ if ((skb_hnat_tops(skb) && skb_hnat_is_encap(skb))
++ || (skb_hnat_cdrt(skb) && skb_hnat_is_encrypt(skb)))
+ skb_pull(skb, sizeof(struct ethhdr));
+
+ rcu_read_unlock_bh();
+@@ -1255,6 +1257,38 @@ static inline void hnat_get_filled_unbin
+ entry->bfib1.ps = 0;
+ }
+
++/*
++ * check offload engine data is prepared
++ * return 0 for packets not related to offload engine
++ * return positive value for offload engine prepared data done
++ * return negative value for data is still constructing
++ */
++static inline int hnat_offload_engine_done(struct sk_buff *skb,
++ struct flow_offload_hw_path *hw_path)
++{
++ struct dst_entry *dst = skb_dst(skb);
++
++ if ((skb_hnat_tops(skb) && !(hw_path->flags & FLOW_OFFLOAD_PATH_TNL))) {
++ /* tunnel encap'ed */
++ if (dst && dst_xfrm(dst))
++ /*
++ * skb not ready to bind since it is still needs
++ * to be encrypted
++ */
++ return -1;
++
++ /* nothing need to be done further for this skb */
++ return 1;
++ }
++
++ if (skb_hnat_cdrt(skb) && skb_hnat_is_encrypt(skb) && dst && !dst_xfrm(dst))
++ /* crypto encrypted done */
++ return 1;
++
++ /* no need for tunnel encapsulation or crypto encryption */
++ return 0;
++}
++
+ static inline void hnat_qos_tnl(u32 id, const struct net_device *dev)
+ {
+ u32 cfg;
+@@ -1299,9 +1333,15 @@ static inline void hnat_fill_offload_eng
+ * we fill in hnat tport and tops_entry for tunnel encapsulation
+ * offloading
+ */
+- entry->ipv4_hnapt.tport_id = NR_TDMA_QDMA_TPORT;
++ if (skb_hnat_cdrt(skb) && skb_hnat_is_encrypt(skb)) {
++ entry->ipv4_hnapt.tport_id = NR_TDMA_EIP197_QDMA_TPORT;
++ entry->ipv4_hnapt.cdrt_id = skb_hnat_cdrt(skb);
++ } else {
++ entry->ipv4_hnapt.tport_id = NR_TDMA_QDMA_TPORT;
++ }
+ entry->ipv4_hnapt.tops_entry = skb_hnat_tops(skb);
+- } else if (skb_hnat_cdrt(skb)) {
++
++ } else if (skb_hnat_cdrt(skb) && skb_hnat_is_encrypt(skb)) {
+ entry->ipv4_hnapt.tport_id = NR_EIP197_QDMA_TPORT;
+ entry->ipv4_hnapt.cdrt_id = skb_hnat_cdrt(skb);
+ } else {
+@@ -1333,6 +1373,7 @@ static unsigned int skb_to_hnat_info(str
+ u32 port_id = 0;
+ u32 payload_len = 0;
+ int mape = 0;
++ int ret;
+
+ ct = nf_ct_get(skb, &ctinfo);
+
+@@ -1349,10 +1390,12 @@ static unsigned int skb_to_hnat_info(str
+ if (whnat && is_hnat_pre_filled(foe))
+ return 0;
+
+- if ((skb_hnat_tops(skb) && !(hw_path->flags & FLOW_OFFLOAD_PATH_TNL))
+- || (skb_hnat_cdrt(skb) && skb_dst(skb) && !dst_xfrm(skb_dst(skb)))) {
++ ret = hnat_offload_engine_done(skb, hw_path);
++ if (ret == 1) {
+ hnat_get_filled_unbind_entry(skb, &entry);
+ goto hnat_entry_bind;
++ } else if (ret == -1) {
++ return 0;
+ }
+
+ entry.bfib1.pkt_type = foe->udib1.pkt_type; /* Get packte type state*/
+@@ -1751,7 +1794,8 @@ static unsigned int skb_to_hnat_info(str
+ entry = ppe_fill_L2_info(eth, entry, hw_path);
+
+ if ((skb_hnat_tops(skb) && hw_path->flags & FLOW_OFFLOAD_PATH_TNL)
+- || (!skb_hnat_cdrt(skb) && skb_dst(skb) && dst_xfrm(skb_dst(skb))))
++ || (!skb_hnat_cdrt(skb) && skb_hnat_is_encrypt(skb)
++ && skb_dst(skb) && dst_xfrm(skb_dst(skb))))
+ goto hnat_entry_skip_bind;
+
+ hnat_entry_bind:
+@@ -1957,7 +2001,7 @@ hnat_entry_bind:
+
+ #if defined(CONFIG_MEDIATEK_NETSYS_V3)
+ hnat_fill_offload_engine_entry(skb, &entry, dev);
+- if (skb_hnat_cdrt(skb))
++ if (skb_hnat_cdrt(skb) && skb_hnat_is_encrypt(skb))
+ entry = ppe_fill_L2_info(eth, entry, hw_path);
+ #endif
+
+@@ -2237,6 +2281,7 @@ int mtk_sw_nat_hook_rx(struct sk_buff *s
+ skb_hnat_alg(skb) = 0;
+ skb_hnat_set_tops(skb, 0);
+ skb_hnat_set_cdrt(skb, 0);
++ skb_hnat_set_is_decrypt(skb, 0);
+ skb_hnat_magic_tag(skb) = HNAT_MAGIC_TAG;
+
+ if (skb_hnat_iface(skb) == FOE_MAGIC_WED0)
+@@ -3037,7 +3082,8 @@ mtk_hnat_ipv4_nf_local_out(void *priv, s
+ entry->udib1.pkt_type = IPV6_6RD;
+ hnat_set_head_frags(state, skb, 0, hnat_set_alg);
+ } else if (is_magic_tag_valid(skb)
+- && (skb_hnat_cdrt(skb) || skb_hnat_tops(skb))) {
++ && ((skb_hnat_cdrt(skb) && skb_hnat_is_encrypt(skb))
++ || skb_hnat_tops(skb))) {
+ hnat_set_head_frags(state, skb, 0, hnat_set_alg);
+ } else {
+ hnat_set_head_frags(state, skb, 1, hnat_set_alg);
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -2324,10 +2324,11 @@ static int mtk_poll_rx(struct napi_struc
+
+ skb_hnat_alg(skb) = 0;
+ skb_hnat_filled(skb) = 0;
+- skb_hnat_set_cdrt(skb, 0);
++ skb_hnat_set_cdrt(skb, RX_DMA_GET_CDRT(trxd.rxd7));
+ skb_hnat_magic_tag(skb) = HNAT_MAGIC_TAG;
+ skb_hnat_set_tops(skb, 0);
+ skb_hnat_set_is_decap(skb, 0);
++ skb_hnat_set_is_decrypt(skb, (skb_hnat_cdrt(skb) ? 1 : 0));
+
+ if (skb_hnat_reason(skb) == HIT_BIND_FORCE_TO_CPU) {
+ trace_printk("[%s] reason=0x%x(force to CPU) from WAN to Ext\n",
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -640,6 +640,9 @@
+ #define RX_DMA_GET_AGG_CNT_V2(_x) (((_x) >> 16) & 0xff)
+ #define RX_DMA_GET_TOPS_CRSN(_x) (((_x) >> 24) & 0xff)
+
++/* PDMA V2 descriptor rxd7 */
++#define RX_DMA_GET_CDRT(_x) (((_x) >> 8) & 0xff)
++
+ /* PHY Polling and SMI Master Control registers */
+ #define MTK_PPSC 0x10000
+ #define PPSC_MDC_CFG GENMASK(29, 24)
+--- a/drivers/net/ethernet/mediatek/mtk_hnat/nf_hnat_mtk.h
++++ b/drivers/net/ethernet/mediatek/mtk_hnat/nf_hnat_mtk.h
+@@ -47,7 +47,8 @@ struct hnat_desc {
+ u32 tops : 6;
+ u32 is_decap : 1;
+ u32 cdrt : 8;
+- u32 resv3 : 4;
++ u32 is_decrypt : 1;
++ u32 resv3 : 3;
+ u32 magic_tag_protect : 16;
+ } __packed;
+ #elif defined(CONFIG_MEDIATEK_NETSYS_RX_V2)
+@@ -101,7 +102,10 @@ struct hnat_desc {
+ #define skb_hnat_set_tops(skb, tops) ((skb_hnat_tops(skb)) = (tops))
+ #define skb_hnat_set_is_decap(skb, is_decap) ((skb_hnat_is_decap(skb)) = (is_decap))
+ #define skb_hnat_cdrt(skb) (((struct hnat_desc *)((skb)->head))->cdrt)
++#define skb_hnat_is_decrypt(skb) (((struct hnat_desc *)((skb)->head))->is_decrypt)
++#define skb_hnat_is_encrypt(skb) (!skb_hnat_is_decrypt(skb))
+ #define skb_hnat_set_cdrt(skb, cdrt) ((skb_hnat_cdrt(skb)) = (cdrt))
++#define skb_hnat_set_is_decrypt(skb, is_dec) ((skb_hnat_is_decrypt(skb)) = is_dec)
+ #else /* !defined(CONFIG_MEDIATEK_NETSYS_V3) */
+ #define skb_hnat_tops(skb) (0)
+ #define skb_hnat_is_decap(skb) (0)
+@@ -109,7 +113,10 @@ struct hnat_desc {
+ #define skb_hnat_set_tops(skb, tops)
+ #define skb_hnat_set_is_decap(skb, is_decap)
+ #define skb_hnat_cdrt(skb) (0)
++#define skb_hnat_is_decrypt(skb) (0)
++#define skb_hnat_is_encrypt(skb) (0)
+ #define skb_hnat_set_cdrt(skb, cdrt)
++#define skb_hnat_set_is_decrypt(skb, is_dec)
+ #endif /* defined(CONFIG_MEDIATEK_NETSYS_V3) */
+ #define skb_hnat_magic(skb) (((struct hnat_desc *)(skb->head))->magic)
+ #define skb_hnat_reason(skb) (((struct hnat_desc *)(skb->head))->crsn)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4500-mtk-tops-gre-offload-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4500-mtk-gre-offload-support.patch
similarity index 100%
rename from recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4500-mtk-tops-gre-offload-support.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4500-mtk-gre-offload-support.patch
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4500-mtk-tops-l2tp-offload-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4500-mtk-l2tp-offload-support.patch
similarity index 100%
rename from recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4500-mtk-tops-l2tp-offload-support.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4500-mtk-l2tp-offload-support.patch
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1033-backport-pinctrl-spinlock.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1033-backport-pinctrl-spinlock.patch
new file mode 100644
index 0000000..875bd7b
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1033-backport-pinctrl-spinlock.patch
@@ -0,0 +1,29 @@
+--- a/drivers/pinctrl/mediatek/pinctrl-moore.c
++++ b/drivers/pinctrl/mediatek/pinctrl-moore.c
+@@ -662,6 +662,7 @@ int mtk_moore_pinctrl_probe(struct platf
+ }
+
+ hw->nbase = hw->soc->nbase_names;
++ spin_lock_init(&hw->lock);
+
+ /* Copy from internal struct mtk_pin_desc to register to the core */
+ pins = devm_kmalloc_array(&pdev->dev, hw->soc->npins, sizeof(*pins),
+--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
++++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
+@@ -55,11 +55,16 @@ static u32 mtk_r32(struct mtk_pinctrl *p
+ void mtk_rmw(struct mtk_pinctrl *pctl, u8 i, u32 reg, u32 mask, u32 set)
+ {
+ u32 val;
++ unsigned long flags;
++
++ spin_lock_irqsave(&pctl->lock, flags);
+
+ val = mtk_r32(pctl, i, reg);
+ val &= ~mask;
+ val |= set;
+ mtk_w32(pctl, i, reg, val);
++
++ spin_unlock_irqrestore(&pctl->lock, flags);
+ }
+
+ static int mtk_hw_pin_field_lookup(struct mtk_pinctrl *hw,
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2704-en8811h-2p5gphy-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2704-en8811h-2p5gphy-support.patch
index 5e3c619..366414c 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2704-en8811h-2p5gphy-support.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2704-en8811h-2p5gphy-support.patch
@@ -5,19 +5,15 @@
[backport-networking-drivers][999-1703-en8811h-2p5gphy-support.patch]
---
- drivers/net/phy/Kconfig | 5 +
- drivers/net/phy/Makefile | 1 +
- drivers/net/phy/air_en8811h.c | 702 ++++++++++++++++++++++++++++++++++
- drivers/net/phy/air_en8811h.h | 151 ++++++++
- 4 files changed, 859 insertions(+)
- create mode 100644 drivers/net/phy/air_en8811h.c
- create mode 100644 drivers/net/phy/air_en8811h.h
+ drivers/net/phy/Kconfig | 11 +
+ drivers/net/phy/Makefile | 2 +
+ 2 files changed, 13 insertions(+)
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 170dd00cd..5eeccfee2 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
-@@ -345,6 +345,11 @@ config SFP
+@@ -345,6 +345,17 @@ config SFP
depends on HWMON || HWMON=n
select MDIO_I2C
@@ -26,6 +22,12 @@
+ ---help---
+ Currently supports the Airoha EN8811H PHY.
+
++config AIROHA_EN8811H_PHY_DEBUGFS
++ bool "EN8811H debugfs support"
++ depends on AIROHA_EN8811H_PHY
++ ---help---
++ Enable creation of debugfs files for the EN8811H drivers.
++
config ADIN_PHY
tristate "Analog Devices Industrial Ethernet PHYs"
help
@@ -33,879 +35,15 @@
index 2368c1d19..8ea612a85 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
-@@ -67,6 +67,7 @@ aquantia-objs += aquantia_main.o
+@@ -67,6 +67,8 @@ aquantia-objs += aquantia_main.o
ifdef CONFIG_HWMON
aquantia-objs += aquantia_hwmon.o
endif
++air_en8811h-y := air_en8811h_main.o air_en8811h_api.o
+obj-$(CONFIG_AIROHA_EN8811H_PHY) += air_en8811h.o
obj-$(CONFIG_AQUANTIA_PHY) += aquantia.o
obj-$(CONFIG_AX88796B_PHY) += ax88796b.o
obj-$(CONFIG_AT803X_PHY) += at803x.o
-diff --git a/drivers/net/phy/air_en8811h.c b/drivers/net/phy/air_en8811h.c
-new file mode 100644
-index 000000000..cf564fc04
---- /dev/null
-+++ b/drivers/net/phy/air_en8811h.c
-@@ -0,0 +1,702 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+
-+/* FILE NAME: air_en8811h.c
-+ * PURPOSE:
-+ * EN8811H phy driver for Linux
-+ * NOTES:
-+ *
-+ */
-+
-+/* INCLUDE FILE DECLARATIONS
-+ */
-+#include <linux/kernel.h>
-+#include <linux/errno.h>
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/mii.h>
-+#include <linux/phy.h>
-+#include <linux/delay.h>
-+#include <linux/ethtool.h>
-+#include <linux/delay.h>
-+#include <linux/version.h>
-+#include <linux/firmware.h>
-+#include <linux/crc32.h>
-+
-+#include "air_en8811h.h"
-+
-+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0))
-+#define phydev_mdio_bus(_dev) (_dev->bus)
-+#define phydev_addr(_dev) (_dev->addr)
-+#define phydev_dev(_dev) (&_dev->dev)
-+#else
-+#define phydev_mdio_bus(_dev) (_dev->mdio.bus)
-+#define phydev_addr(_dev) (_dev->mdio.addr)
-+#define phydev_dev(_dev) (&_dev->mdio.dev)
-+#endif
-+
-+MODULE_DESCRIPTION("Airoha EN8811H PHY drivers");
-+MODULE_AUTHOR("Airoha");
-+MODULE_LICENSE("GPL");
-+
-+/*
-+GPIO5 <-> BASE_T_LED0,
-+GPIO4 <-> BASE_T_LED1,
-+GPIO3 <-> BASE_T_LED2,
-+*/
-+/* User-defined.B */
-+#define AIR_LED_SUPPORT
-+#ifdef AIR_LED_SUPPORT
-+static const AIR_BASE_T_LED_CFG_T led_cfg[3] =
-+{
-+ /*
-+ * LED Enable, GPIO, LED Polarity, LED ON, LED Blink
-+ */
-+ {LED_ENABLE, AIR_LED0_GPIO5, AIR_ACTIVE_HIGH, BASE_T_LED0_ON_CFG, BASE_T_LED0_BLK_CFG}, /* BASE-T LED0 */
-+ {LED_ENABLE, AIR_LED1_GPIO4, AIR_ACTIVE_HIGH, BASE_T_LED1_ON_CFG, BASE_T_LED1_BLK_CFG}, /* BASE-T LED1 */
-+ {LED_ENABLE, AIR_LED2_GPIO3, AIR_ACTIVE_HIGH, BASE_T_LED2_ON_CFG, BASE_T_LED2_BLK_CFG}, /* BASE-T LED2 */
-+};
-+static const u16 led_dur = UNIT_LED_BLINK_DURATION << AIR_LED_BLK_DUR_64M;
-+#endif
-+/* User-defined.E */
-+
-+/************************************************************************
-+* F U N C T I O N S
-+************************************************************************/
-+#if 0
-+/* Airoha MII read function */
-+static int air_mii_cl22_read(struct mii_bus *ebus, unsigned int phy_addr,unsigned int phy_register)
-+{
-+ int read_data;
-+ read_data = mdiobus_read(ebus, phy_addr, phy_register);
-+ return read_data;
-+}
-+#endif
-+/* Airoha MII write function */
-+static int air_mii_cl22_write(struct mii_bus *ebus, unsigned int phy_addr, unsigned int phy_register,unsigned int write_data)
-+{
-+ int ret = 0;
-+ ret = mdiobus_write(ebus, phy_addr, phy_register, write_data);
-+ return ret;
-+}
-+
-+static int air_mii_cl45_read(struct phy_device *phydev, int devad, u16 reg)
-+{
-+ int ret = 0;
-+ int data;
-+ struct device *dev = phydev_dev(phydev);
-+ ret = phy_write(phydev, MII_MMD_ACC_CTL_REG, devad);
-+ if (ret < 0) {
-+ dev_err(dev, "phy_write, ret: %d\n", ret);
-+ return INVALID_DATA;
-+ }
-+ ret = phy_write(phydev, MII_MMD_ADDR_DATA_REG, reg);
-+ if (ret < 0) {
-+ dev_err(dev, "phy_write, ret: %d\n", ret);
-+ return INVALID_DATA;
-+ }
-+ ret = phy_write(phydev, MII_MMD_ACC_CTL_REG, MMD_OP_MODE_DATA | devad);
-+ if (ret < 0) {
-+ dev_err(dev, "phy_write, ret: %d\n", ret);
-+ return INVALID_DATA;
-+ }
-+ data = phy_read(phydev, MII_MMD_ADDR_DATA_REG);
-+ return data;
-+}
-+
-+static int air_mii_cl45_write(struct phy_device *phydev, int devad, u16 reg, u16 write_data)
-+{
-+ int ret = 0;
-+ struct device *dev = phydev_dev(phydev);
-+ ret = phy_write(phydev, MII_MMD_ACC_CTL_REG, devad);
-+ if (ret < 0) {
-+ dev_err(dev, "phy_write, ret: %d\n", ret);
-+ return ret;
-+ }
-+ ret = phy_write(phydev, MII_MMD_ADDR_DATA_REG, reg);
-+ if (ret < 0) {
-+ dev_err(dev, "phy_write, ret: %d\n", ret);
-+ return ret;
-+ }
-+ ret = phy_write(phydev, MII_MMD_ACC_CTL_REG, MMD_OP_MODE_DATA | devad);
-+ if (ret < 0) {
-+ dev_err(dev, "phy_write, ret: %d\n", ret);
-+ return ret;
-+ }
-+ ret = phy_write(phydev, MII_MMD_ADDR_DATA_REG, write_data);
-+ if (ret < 0) {
-+ dev_err(dev, "phy_write, ret: %d\n", ret);
-+ return ret;
-+ }
-+ return 0;
-+}
-+/* Use default PBUS_PHY_ID */
-+/* EN8811H PBUS write function */
-+static int air_pbus_reg_write(struct phy_device *phydev, unsigned long pbus_address, unsigned long pbus_data)
-+{
-+ struct mii_bus *mbus = phydev_mdio_bus(phydev);
-+ int addr = phydev_addr(phydev);
-+ int ret = 0;
-+ ret = air_mii_cl22_write(mbus, (addr + 8), 0x1F, (unsigned int)(pbus_address >> 6));
-+ AIR_RTN_ERR(ret);
-+ ret = air_mii_cl22_write(mbus, (addr + 8), (unsigned int)((pbus_address >> 2) & 0xf), (unsigned int)(pbus_data & 0xFFFF));
-+ AIR_RTN_ERR(ret);
-+ ret = air_mii_cl22_write(mbus, (addr + 8), 0x10, (unsigned int)(pbus_data >> 16));
-+ AIR_RTN_ERR(ret);
-+ return 0;
-+}
-+
-+/* EN8811H BUCK write function */
-+static int air_buckpbus_reg_write(struct phy_device *phydev, unsigned long pbus_address, unsigned int pbus_data)
-+{
-+ int ret = 0;
-+ struct device *dev = phydev_dev(phydev);
-+ ret = phy_write(phydev, 0x1F, (unsigned int)4); /* page 4 */
-+ if (ret < 0) {
-+ dev_err(dev, "phy_write, ret: %d\n", ret);
-+ return ret;
-+ }
-+ ret = phy_write(phydev, 0x10, (unsigned int)0);
-+ if (ret < 0) {
-+ dev_err(dev, "phy_write, ret: %d\n", ret);
-+ return ret;
-+ }
-+ ret = phy_write(phydev, 0x11, (unsigned int)((pbus_address >> 16) & 0xffff));
-+ if (ret < 0) {
-+ dev_err(dev, "phy_write, ret: %d\n", ret);
-+ return ret;
-+ }
-+ ret = phy_write(phydev, 0x12, (unsigned int)(pbus_address & 0xffff));
-+ if (ret < 0) {
-+ dev_err(dev, "phy_write, ret: %d\n", ret);
-+ return ret;
-+ }
-+ ret = phy_write(phydev, 0x13, (unsigned int)((pbus_data >> 16) & 0xffff));
-+ if (ret < 0) {
-+ dev_err(dev, "phy_write, ret: %d\n", ret);
-+ return ret;
-+ }
-+ ret = phy_write(phydev, 0x14, (unsigned int)(pbus_data & 0xffff));
-+ if (ret < 0) {
-+ dev_err(dev, "phy_write, ret: %d\n", ret);
-+ return ret;
-+ }
-+ ret = phy_write(phydev, 0x1F, 0);
-+ if (ret < 0) {
-+ dev_err(dev, "phy_write, ret: %d\n", ret);
-+ return ret;
-+ }
-+ return 0;
-+}
-+
-+/* EN8811H BUCK read function */
-+static unsigned int air_buckpbus_reg_read(struct phy_device *phydev, unsigned long pbus_address)
-+{
-+ unsigned int pbus_data = 0, pbus_data_low, pbus_data_high;
-+ int ret = 0;
-+ struct device *dev = phydev_dev(phydev);
-+ ret = phy_write(phydev, 0x1F, (unsigned int)4); /* page 4 */
-+ if (ret < 0) {
-+ dev_err(dev, "phy_write, ret: %d\n", ret);
-+ return PBUS_INVALID_DATA;
-+ }
-+ ret = phy_write(phydev, 0x10, (unsigned int)0);
-+ if (ret < 0) {
-+ dev_err(dev, "phy_write, ret: %d\n", ret);
-+ return PBUS_INVALID_DATA;
-+ }
-+ ret = phy_write(phydev, 0x15, (unsigned int)((pbus_address >> 16) & 0xffff));
-+ if (ret < 0) {
-+ dev_err(dev, "phy_write, ret: %d\n", ret);
-+ return PBUS_INVALID_DATA;
-+ }
-+ ret = phy_write(phydev, 0x16, (unsigned int)(pbus_address & 0xffff));
-+ if (ret < 0) {
-+ dev_err(dev, "phy_write, ret: %d\n", ret);
-+ return PBUS_INVALID_DATA;
-+ }
-+
-+ pbus_data_high = phy_read(phydev, 0x17);
-+ pbus_data_low = phy_read(phydev, 0x18);
-+ pbus_data = (pbus_data_high << 16) + pbus_data_low;
-+ ret = phy_write(phydev, 0x1F, 0);
-+ if (ret < 0) {
-+ dev_err(dev, "phy_write, ret: %d\n", ret);
-+ return ret;
-+ }
-+ return pbus_data;
-+}
-+
-+static int MDIOWriteBuf(struct phy_device *phydev, unsigned long address, const struct firmware *fw)
-+{
-+ unsigned int write_data, offset ;
-+ int ret = 0;
-+ struct device *dev = phydev_dev(phydev);
-+ ret = phy_write(phydev, 0x1F, (unsigned int)4); /* page 4 */
-+ if (ret < 0) {
-+ dev_err(dev, "phy_write, ret: %d\n", ret);
-+ return ret;
-+ }
-+ ret = phy_write(phydev, 0x10, (unsigned int)0x8000); /* address increment*/
-+ if (ret < 0) {
-+ dev_err(dev, "phy_write, ret: %d\n", ret);
-+ return ret;
-+ }
-+ ret = phy_write(phydev, 0x11, (unsigned int)((address >> 16) & 0xffff));
-+ if (ret < 0) {
-+ dev_err(dev, "phy_write, ret: %d\n", ret);
-+ return ret;
-+ }
-+ ret = phy_write(phydev, 0x12, (unsigned int)(address & 0xffff));
-+ if (ret < 0) {
-+ dev_err(dev, "phy_write, ret: %d\n", ret);
-+ return ret;
-+ }
-+
-+ for (offset = 0; offset < fw->size; offset += 4)
-+ {
-+ write_data = (fw->data[offset + 3] << 8) | fw->data[offset + 2];
-+ ret = phy_write(phydev, 0x13, write_data);
-+ if (ret < 0) {
-+ dev_err(dev, "phy_write, ret: %d\n", ret);
-+ return ret;
-+ }
-+ write_data = (fw->data[offset + 1] << 8) | fw->data[offset];
-+ ret = phy_write(phydev, 0x14, write_data);
-+ if (ret < 0) {
-+ dev_err(dev, "phy_write, ret: %d\n", ret);
-+ return ret;
-+ }
-+ }
-+ ret = phy_write(phydev, 0x1F, (unsigned int)0);
-+ if (ret < 0) {
-+ dev_err(dev, "phy_write, ret: %d\n", ret);
-+ return ret;
-+ }
-+ return 0;
-+}
-+
-+static int en8811h_load_firmware(struct phy_device *phydev)
-+{
-+ struct device *dev = phydev_dev(phydev);
-+ const struct firmware *fw;
-+ const char *firmware;
-+ int ret = 0;
-+ unsigned int crc32;
-+ u32 pbus_value = 0;
-+
-+ ret = air_buckpbus_reg_write(phydev, 0x0f0018, 0x0);
-+ AIR_RTN_ERR(ret);
-+ pbus_value = air_buckpbus_reg_read(phydev, 0x800000);
-+ pbus_value |= BIT(11);
-+ ret = air_buckpbus_reg_write(phydev, 0x800000, pbus_value);
-+ AIR_RTN_ERR(ret);
-+ firmware = EN8811H_MD32_DM;
-+ ret = request_firmware_direct(&fw, firmware, dev);
-+ if (ret < 0) {
-+ dev_info(dev, "failed to load firmware %s, ret: %d\n", firmware, ret);
-+ return ret;
-+ }
-+ crc32 = ~crc32(~0, fw->data, fw->size);
-+ dev_info(dev, "%s: crc32=0x%x\n", firmware, crc32);
-+ /* Download DM */
-+ ret = MDIOWriteBuf(phydev, 0x00000000, fw);
-+ if (ret < 0) {
-+ dev_info(dev, "MDIOWriteBuf 0x00000000 fail, ret: %d\n", ret);
-+ return ret;
-+ }
-+ release_firmware(fw);
-+
-+ firmware = EN8811H_MD32_DSP;
-+ ret = request_firmware_direct(&fw, firmware, dev);
-+ if (ret < 0) {
-+ dev_info(dev, "failed to load firmware %s, ret: %d\n", firmware, ret);
-+ return ret;
-+ }
-+ crc32 = ~crc32(~0, fw->data, fw->size);
-+ dev_info(dev, "%s: crc32=0x%x\n", firmware, crc32);
-+ /* Download PM */
-+ ret = MDIOWriteBuf(phydev, 0x00100000, fw);
-+ if (ret < 0) {
-+ dev_info(dev, "MDIOWriteBuf 0x00100000 fail , ret: %d\n", ret);
-+ return ret;
-+ }
-+ release_firmware(fw);
-+
-+ pbus_value = air_buckpbus_reg_read(phydev, 0x800000);
-+ pbus_value &= ~BIT(11);
-+ ret = air_buckpbus_reg_write(phydev, 0x800000, pbus_value);
-+ AIR_RTN_ERR(ret);
-+ ret = air_buckpbus_reg_write(phydev, 0x0f0018, 0x01);
-+ AIR_RTN_ERR(ret);
-+ return 0;
-+}
-+
-+#ifdef AIR_LED_SUPPORT
-+static int airoha_led_set_usr_def(struct phy_device *phydev, u8 entity, int polar,
-+ u16 on_evt, u16 blk_evt)
-+{
-+ int ret = 0;
-+ if (AIR_ACTIVE_HIGH == polar) {
-+ on_evt |= LED_ON_POL;
-+ } else {
-+ on_evt &= ~LED_ON_POL ;
-+ }
-+ ret = air_mii_cl45_write(phydev, 0x1f, LED_ON_CTRL(entity), on_evt | LED_ON_EN);
-+ AIR_RTN_ERR(ret);
-+ ret = air_mii_cl45_write(phydev, 0x1f, LED_BLK_CTRL(entity), blk_evt);
-+ AIR_RTN_ERR(ret);
-+ return 0;
-+}
-+
-+static int airoha_led_set_mode(struct phy_device *phydev, u8 mode)
-+{
-+ u16 cl45_data;
-+ int err = 0;
-+ struct device *dev = phydev_dev(phydev);
-+ cl45_data = air_mii_cl45_read(phydev, 0x1f, LED_BCR);
-+ switch (mode) {
-+ case AIR_LED_MODE_DISABLE:
-+ cl45_data &= ~LED_BCR_EXT_CTRL;
-+ cl45_data &= ~LED_BCR_MODE_MASK;
-+ cl45_data |= LED_BCR_MODE_DISABLE;
-+ break;
-+ case AIR_LED_MODE_USER_DEFINE:
-+ cl45_data |= LED_BCR_EXT_CTRL;
-+ cl45_data |= LED_BCR_CLK_EN;
-+ break;
-+ default:
-+ dev_err(dev, "LED mode%d is not supported!\n", mode);
-+ return -EINVAL;
-+ }
-+ err = air_mii_cl45_write(phydev, 0x1f, LED_BCR, cl45_data);
-+ AIR_RTN_ERR(err);
-+ return 0;
-+}
-+
-+static int airoha_led_set_state(struct phy_device *phydev, u8 entity, u8 state)
-+{
-+ u16 cl45_data = 0;
-+ int err;
-+
-+ cl45_data = air_mii_cl45_read(phydev, 0x1f, LED_ON_CTRL(entity));
-+ if (LED_ENABLE == state) {
-+ cl45_data |= LED_ON_EN;
-+ } else {
-+ cl45_data &= ~LED_ON_EN;
-+ }
-+
-+ err = air_mii_cl45_write(phydev, 0x1f, LED_ON_CTRL(entity), cl45_data);
-+ AIR_RTN_ERR(err);
-+ return 0;
-+}
-+
-+static int en8811h_led_init(struct phy_device *phydev)
-+{
-+
-+ unsigned long led_gpio = 0, reg_value = 0;
-+ u16 cl45_data = led_dur;
-+ int ret = 0, led_id;
-+ struct device *dev = phydev_dev(phydev);
-+ ret = air_mii_cl45_write(phydev, 0x1f, LED_BLK_DUR, cl45_data);
-+ AIR_RTN_ERR(ret);
-+ cl45_data >>= 1;
-+ ret = air_mii_cl45_write(phydev, 0x1f, LED_ON_DUR, cl45_data);
-+ AIR_RTN_ERR(ret);
-+ ret = airoha_led_set_mode(phydev, AIR_LED_MODE_USER_DEFINE);
-+ if (ret != 0) {
-+ dev_err(dev, "LED fail to set mode, ret %d !\n", ret);
-+ return ret;
-+ }
-+ for(led_id = 0; led_id < EN8811H_LED_COUNT; led_id++)
-+ {
-+ /* LED0 <-> GPIO5, LED1 <-> GPIO4, LED0 <-> GPIO3 */
-+ if (led_cfg[led_id].gpio != (led_id + (AIR_LED0_GPIO5 - (2 * led_id))))
-+ {
-+ dev_err(dev, "LED%d uses incorrect GPIO%d !\n", led_id, led_cfg[led_id].gpio);
-+ return -EINVAL;
-+ }
-+ ret = airoha_led_set_state(phydev, led_id, led_cfg[led_id].en);
-+ if (ret != 0)
-+ {
-+ dev_err(dev, "LED fail to set state, ret %d !\n", ret);
-+ return ret;
-+ }
-+ if (LED_ENABLE == led_cfg[led_id].en)
-+ {
-+ led_gpio |= BIT(led_cfg[led_id].gpio);
-+ ret = airoha_led_set_usr_def(phydev, led_id, led_cfg[led_id].pol, led_cfg[led_id].on_cfg, led_cfg[led_id].blk_cfg);
-+ if (ret != 0)
-+ {
-+ dev_err(dev, "LED fail to set default, ret %d !\n", ret);
-+ return ret;
-+ }
-+ }
-+ }
-+ reg_value = air_buckpbus_reg_read(phydev, 0xcf8b8) | led_gpio;
-+ ret = air_buckpbus_reg_write(phydev, 0xcf8b8, reg_value);
-+ AIR_RTN_ERR(ret);
-+
-+ dev_info(dev, "LED initialize OK !\n");
-+ return 0;
-+}
-+#endif /* AIR_LED_SUPPORT */
-+#if (LINUX_VERSION_CODE > KERNEL_VERSION(4, 5, 0))
-+static int en8811h_get_features(struct phy_device *phydev)
-+{
-+ int ret;
-+ struct device *dev = phydev_dev(phydev);
-+ dev_info(dev, "%s()\n", __func__);
-+ ret = air_pbus_reg_write(phydev, 0xcf928 , 0x0);
-+ AIR_RTN_ERR(ret);
-+ ret = genphy_read_abilities(phydev);
-+ if (ret)
-+ return ret;
-+
-+ /* EN8811H supports 100M/1G/2.5G speed. */
-+ linkmode_clear_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
-+ phydev->supported);
-+ linkmode_clear_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
-+ phydev->supported);
-+ linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
-+ phydev->supported);
-+ linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
-+ phydev->supported);
-+ linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
-+ phydev->supported);
-+ linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
-+ phydev->supported);
-+ return 0;
-+}
-+#endif
-+static int en8811h_phy_probe(struct phy_device *phydev)
-+{
-+ int ret = 0;
-+ int reg_value, pid1 = 0, pid2 = 0;
-+ u32 pbus_value = 0, retry;
-+ struct device *dev = phydev_dev(phydev);
-+ ret = air_pbus_reg_write(phydev, 0xcf928 , 0x0);
-+ AIR_RTN_ERR(ret);
-+ pid1 = phy_read(phydev, MII_PHYSID1);
-+ if (pid1 < 0)
-+ return pid1;
-+ pid2 = phy_read(phydev, MII_PHYSID2);
-+ if (pid2 < 0)
-+ return pid2;
-+ dev_info(dev, "PHY = %x - %x\n", pid1, pid2);
-+ if ((EN8811H_PHY_ID1 != pid1) || (EN8811H_PHY_ID2 != pid2))
-+ {
-+ dev_err(dev, "EN8811H dose not exist !\n");
-+ return -ENODEV;
-+ }
-+ ret = en8811h_load_firmware(phydev);
-+ if (ret)
-+ {
-+ dev_err(dev,"EN8811H load firmware fail.\n");
-+ return ret;
-+ }
-+ retry = MAX_RETRY;
-+ do {
-+ mdelay(300);
-+ reg_value = air_mii_cl45_read(phydev, 0x1e, 0x8009);
-+ if (EN8811H_PHY_READY == reg_value)
-+ {
-+ dev_info(dev, "EN8811H PHY ready!\n");
-+ break;
-+ }
-+ retry--;
-+ } while (retry);
-+ if (0 == retry)
-+ {
-+ dev_err(dev, "EN8811H initialize fail ! reg: 0x%x\n", reg_value);
-+ return -EIO;
-+ }
-+ /* Mode selection*/
-+ dev_info(dev, "EN8811H Mode 1 !\n");
-+ ret = air_mii_cl45_write(phydev, 0x1e, 0x800c, 0x0);
-+ AIR_RTN_ERR(ret);
-+ ret = air_mii_cl45_write(phydev, 0x1e, 0x800d, 0x0);
-+ AIR_RTN_ERR(ret);
-+ ret = air_mii_cl45_write(phydev, 0x1e, 0x800e, 0x1101);
-+ AIR_RTN_ERR(ret);
-+ ret = air_mii_cl45_write(phydev, 0x1e, 0x800f, 0x0002);
-+ AIR_RTN_ERR(ret);
-+
-+ /* Serdes polarity */
-+ pbus_value = air_buckpbus_reg_read(phydev, 0xca0f8);
-+ pbus_value = (pbus_value & 0xfffffffc) | EN8811H_RX_POLARITY_NORMAL | EN8811H_TX_POLARITY_NORMAL;
-+ ret = air_buckpbus_reg_write(phydev, 0xca0f8, pbus_value);
-+ AIR_RTN_ERR(ret);
-+ pbus_value = air_buckpbus_reg_read(phydev, 0xca0f8);
-+ dev_info(dev, "0xca0f8= 0x%x\n", pbus_value);
-+ pbus_value = air_buckpbus_reg_read(phydev, 0x3b3c);
-+ dev_info(dev, "Version(0x3b3c)= %x\n", pbus_value);
-+#if defined(AIR_LED_SUPPORT)
-+ ret = en8811h_led_init(phydev);
-+ if (ret < 0)
-+ {
-+ dev_err(dev, "en8811h_led_init fail. (ret=%d)\n", ret);
-+ return ret;
-+ }
-+#endif
-+ dev_info(dev, "EN8811H initialize OK ! (%s)\n", EN8811H_FW_VERSION);
-+ return 0;
-+}
-+
-+static int en8811h_get_autonego(struct phy_device *phydev, int *an)
-+{
-+ int reg;
-+ reg = phy_read(phydev, MII_BMCR);
-+ if (reg < 0)
-+ return -EINVAL;
-+ if (reg & BMCR_ANENABLE)
-+ *an = AUTONEG_ENABLE;
-+ else
-+ *an = AUTONEG_DISABLE;
-+ return 0;
-+}
-+
-+static int en8811h_read_status(struct phy_device *phydev)
-+{
-+ int ret = 0, lpagb = 0, lpa = 0, common_adv_gb = 0, common_adv = 0, advgb = 0, adv = 0, reg = 0, an = AUTONEG_DISABLE, bmcr = 0;
-+ int old_link = phydev->link;
-+ u32 pbus_value = 0;
-+ struct device *dev = phydev_dev(phydev);
-+ ret = genphy_update_link(phydev);
-+ if (ret)
-+ {
-+ dev_err(dev, "ret %d!\n", ret);
-+ return ret;
-+ }
-+
-+ if (old_link && phydev->link)
-+ return 0;
-+
-+ phydev->speed = SPEED_UNKNOWN;
-+ phydev->duplex = DUPLEX_UNKNOWN;
-+ phydev->pause = 0;
-+ phydev->asym_pause = 0;
-+
-+ reg = phy_read(phydev, MII_BMSR);
-+ if (reg < 0)
-+ {
-+ dev_err(dev, "MII_BMSR reg %d!\n", reg);
-+ return reg;
-+ }
-+ reg = phy_read(phydev, MII_BMSR);
-+ if (reg < 0)
-+ {
-+ dev_err(dev, "MII_BMSR reg %d!\n", reg);
-+ return reg;
-+ }
-+ if(reg & BMSR_LSTATUS)
-+ {
-+ pbus_value = air_buckpbus_reg_read(phydev, 0x109D4);
-+ if (0x10 & pbus_value) {
-+ phydev->speed = SPEED_2500;
-+ phydev->duplex = DUPLEX_FULL;
-+ }
-+ else
-+ {
-+ ret = en8811h_get_autonego(phydev, &an);
-+ if ((AUTONEG_ENABLE == an) && (0 == ret))
-+ {
-+ dev_dbg(dev, "AN mode!\n");
-+ dev_dbg(dev, "SPEED 1000/100!\n");
-+ lpagb = phy_read(phydev, MII_STAT1000);
-+ if (lpagb < 0 )
-+ return lpagb;
-+ advgb = phy_read(phydev, MII_CTRL1000);
-+ if (adv < 0 )
-+ return adv;
-+ common_adv_gb = (lpagb & (advgb << 2));
-+
-+ lpa = phy_read(phydev, MII_LPA);
-+ if (lpa < 0 )
-+ return lpa;
-+ adv = phy_read(phydev, MII_ADVERTISE);
-+ if (adv < 0 )
-+ return adv;
-+ common_adv = (lpa & adv);
-+
-+ phydev->speed = SPEED_10;
-+ phydev->duplex = DUPLEX_HALF;
-+ if (common_adv_gb & (LPA_1000FULL | LPA_1000HALF))
-+ {
-+ phydev->speed = SPEED_1000;
-+ if (common_adv_gb & LPA_1000FULL)
-+
-+ phydev->duplex = DUPLEX_FULL;
-+ }
-+ else if (common_adv & (LPA_100FULL | LPA_100HALF))
-+ {
-+ phydev->speed = SPEED_100;
-+ if (common_adv & LPA_100FULL)
-+ phydev->duplex = DUPLEX_FULL;
-+ }
-+ else
-+ {
-+ if (common_adv & LPA_10FULL)
-+ phydev->duplex = DUPLEX_FULL;
-+ }
-+ }
-+ else
-+ {
-+ dev_dbg(dev, "Force mode!\n");
-+ bmcr = phy_read(phydev, MII_BMCR);
-+
-+ if (bmcr < 0)
-+ return bmcr;
-+
-+ if (bmcr & BMCR_FULLDPLX)
-+ phydev->duplex = DUPLEX_FULL;
-+ else
-+ phydev->duplex = DUPLEX_HALF;
-+
-+ if (bmcr & BMCR_SPEED1000)
-+ phydev->speed = SPEED_1000;
-+ else if (bmcr & BMCR_SPEED100)
-+ phydev->speed = SPEED_100;
-+ else
-+ phydev->speed = SPEED_UNKNOWN;
-+ }
-+ }
-+ }
-+
-+ return ret;
-+}
-+static struct phy_driver en8811h_driver[] = {
-+{
-+ .phy_id = EN8811H_PHY_ID,
-+ .name = "Airoha EN8811H",
-+ .phy_id_mask = 0x0ffffff0,
-+ .probe = en8811h_phy_probe,
-+ .read_status = en8811h_read_status,
-+#if (LINUX_VERSION_CODE > KERNEL_VERSION(4, 5, 0))
-+ .get_features = en8811h_get_features,
-+ .read_mmd = air_mii_cl45_read,
-+ .write_mmd = air_mii_cl45_write,
-+#endif
-+} };
-+
-+int __init en8811h_phy_driver_register(void)
-+{
-+ int ret;
-+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0))
-+ ret = phy_driver_register(en8811h_driver);
-+#else
-+ ret = phy_driver_register(en8811h_driver, THIS_MODULE);
-+#endif
-+ if (!ret)
-+ return 0;
-+
-+ phy_driver_unregister(en8811h_driver);
-+ return ret;
-+}
-+
-+void __exit en8811h_phy_driver_unregister(void)
-+{
-+ phy_driver_unregister(en8811h_driver);
-+}
-+
-+module_init(en8811h_phy_driver_register);
-+module_exit(en8811h_phy_driver_unregister);
-diff --git a/drivers/net/phy/air_en8811h.h b/drivers/net/phy/air_en8811h.h
-new file mode 100644
-index 000000000..1c9162795
---- /dev/null
-+++ b/drivers/net/phy/air_en8811h.h
-@@ -0,0 +1,151 @@
-+#ifndef __EN8811H_H
-+#define __EN8811H_H
-+
-+#define EN8811H_MD32_DM "EthMD32.dm.bin"
-+#define EN8811H_MD32_DSP "EthMD32.DSP.bin"
-+
-+#define EN8811H_PHY_ID1 0x03a2
-+#define EN8811H_PHY_ID2 0xa411
-+#define EN8811H_PHY_ID ((EN8811H_PHY_ID1 << 16) | EN8811H_PHY_ID2)
-+#define EN8811H_PHY_READY 0x02
-+#define MAX_RETRY 5
-+
-+#define EN8811H_TX_POLARITY_NORMAL 0x1
-+#define EN8811H_TX_POLARITY_REVERSE 0x0
-+
-+#define EN8811H_RX_POLARITY_REVERSE (0x1 << 1)
-+#define EN8811H_RX_POLARITY_NORMAL (0x0 << 1)
-+
-+
-+/*
-+The following led_cfg example is for reference only.
-+LED0 Link 2500/Blink 2500 TxRx (GPIO5) <-> BASE_T_LED0,
-+LED1 Link 1000/Blink 1000 TxRx (GPIO4) <-> BASE_T_LED1,
-+LED2 Link 100 /Blink 100 TxRx (GPIO3) <-> BASE_T_LED2,
-+*/
-+/* User-defined.B */
-+#define BASE_T_LED0_ON_CFG (LED_ON_EVT_LINK_2500M)
-+#define BASE_T_LED0_BLK_CFG (LED_BLK_EVT_2500M_TX_ACT | LED_BLK_EVT_2500M_RX_ACT)
-+#define BASE_T_LED1_ON_CFG (LED_ON_EVT_LINK_1000M)
-+#define BASE_T_LED1_BLK_CFG (LED_BLK_EVT_1000M_TX_ACT | LED_BLK_EVT_1000M_RX_ACT)
-+#define BASE_T_LED2_ON_CFG (LED_ON_EVT_LINK_100M)
-+#define BASE_T_LED2_BLK_CFG (LED_BLK_EVT_100M_TX_ACT | LED_BLK_EVT_100M_RX_ACT)
-+/* User-defined.E */
-+
-+/* CL45 MDIO control */
-+#define MII_MMD_ACC_CTL_REG 0x0d
-+#define MII_MMD_ADDR_DATA_REG 0x0e
-+#define MMD_OP_MODE_DATA BIT(14)
-+
-+#define EN8811H_FW_VERSION "1.1.3"
-+
-+#define LED_ON_CTRL(i) (0x024 + ((i)*2))
-+#define LED_ON_EN (1 << 15)
-+#define LED_ON_POL (1 << 14)
-+#define LED_ON_EVT_MASK (0x1ff)
-+/* LED ON Event Option.B */
-+#define LED_ON_EVT_LINK_2500M (1 << 8)
-+#define LED_ON_EVT_FORCE (1 << 6)
-+#define LED_ON_EVT_LINK_DOWN (1 << 3)
-+#define LED_ON_EVT_LINK_100M (1 << 1)
-+#define LED_ON_EVT_LINK_1000M (1 << 0)
-+/* LED ON Event Option.E */
-+
-+#define LED_BLK_CTRL(i) (0x025 + ((i)*2))
-+#define LED_BLK_EVT_MASK (0xfff)
-+/* LED Blinking Event Option.B*/
-+#define LED_BLK_EVT_2500M_RX_ACT (1 << 11)
-+#define LED_BLK_EVT_2500M_TX_ACT (1 << 10)
-+#define LED_BLK_EVT_FORCE (1 << 9)
-+#define LED_BLK_EVT_100M_RX_ACT (1 << 3)
-+#define LED_BLK_EVT_100M_TX_ACT (1 << 2)
-+#define LED_BLK_EVT_1000M_RX_ACT (1 << 1)
-+#define LED_BLK_EVT_1000M_TX_ACT (1 << 0)
-+/* LED Blinking Event Option.E*/
-+#define LED_ENABLE 1
-+#define LED_DISABLE 0
-+
-+#define EN8811H_LED_COUNT 3
-+
-+#define LED_BCR (0x021)
-+#define LED_BCR_EXT_CTRL (1 << 15)
-+#define LED_BCR_CLK_EN (1 << 3)
-+#define LED_BCR_TIME_TEST (1 << 2)
-+#define LED_BCR_MODE_MASK (3)
-+#define LED_BCR_MODE_DISABLE (0)
-+
-+#define LED_ON_DUR (0x022)
-+#define LED_ON_DUR_MASK (0xffff)
-+
-+#define LED_BLK_DUR (0x023)
-+#define LED_BLK_DUR_MASK (0xffff)
-+
-+#define UNIT_LED_BLINK_DURATION 1024
-+
-+#define AIR_RTN_ON_ERR(cond, err) \
-+ do { if ((cond)) return (err); } while(0)
-+
-+#define AIR_RTN_ERR(err) AIR_RTN_ON_ERR(err < 0, err)
-+
-+#define LED_SET_EVT(reg, cod, result, bit) do \
-+ { \
-+ if(reg & cod) { \
-+ result |= bit; \
-+ } \
-+ } while(0)
-+
-+#define LED_SET_GPIO_SEL(gpio, led, val) do \
-+ { \
-+ val |= (led << (8 * (gpio % 4))); \
-+ } while(0)
-+
-+#define INVALID_DATA 0xffff
-+#define PBUS_INVALID_DATA 0xffffffff
-+
-+typedef struct AIR_BASE_T_LED_CFG_S
-+{
-+ u16 en;
-+ u16 gpio;
-+ u16 pol;
-+ u16 on_cfg;
-+ u16 blk_cfg;
-+}AIR_BASE_T_LED_CFG_T;
-+typedef enum
-+{
-+ AIR_LED2_GPIO3 = 3,
-+ AIR_LED1_GPIO4,
-+ AIR_LED0_GPIO5,
-+ AIR_LED_LAST
-+} AIR_LED_GPIO;
-+
-+typedef enum {
-+ AIR_BASE_T_LED0,
-+ AIR_BASE_T_LED1,
-+ AIR_BASE_T_LED2,
-+ AIR_BASE_T_LED3
-+}AIR_BASE_T_LED;
-+
-+typedef enum
-+{
-+ AIR_LED_BLK_DUR_32M,
-+ AIR_LED_BLK_DUR_64M,
-+ AIR_LED_BLK_DUR_128M,
-+ AIR_LED_BLK_DUR_256M,
-+ AIR_LED_BLK_DUR_512M,
-+ AIR_LED_BLK_DUR_1024M,
-+ AIR_LED_BLK_DUR_LAST
-+} AIR_LED_BLK_DUT_T;
-+
-+typedef enum
-+{
-+ AIR_ACTIVE_LOW,
-+ AIR_ACTIVE_HIGH,
-+} AIR_LED_POLARITY;
-+typedef enum
-+{
-+ AIR_LED_MODE_DISABLE,
-+ AIR_LED_MODE_USER_DEFINE,
-+ AIR_LED_MODE_LAST
-+} AIR_LED_MODE_T;
-+
-+#endif /* End of __EN8811H_MD32_H */
--
2.34.1
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2716-en8801sc-gphy-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2716-en8801sc-gphy-support.patch
index 47168b9..27ba8be 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2716-en8801sc-gphy-support.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2716-en8801sc-gphy-support.patch
@@ -33,6 +33,7 @@
aquantia-objs += aquantia_hwmon.o
endif
+obj-$(CONFIG_AIROHA_EN8801SC_PHY) += en8801sc.o
+ air_en8811h-y := air_en8811h_main.o air_en8811h_api.o
obj-$(CONFIG_AIROHA_EN8811H_PHY) += air_en8811h.o
obj-$(CONFIG_AQUANTIA_PHY) += aquantia.o
obj-$(CONFIG_AX88796B_PHY) += ax88796b.o
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2719-net-phy-aquantia-add-firmware-download.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2719-net-phy-aquantia-add-firmware-download.patch
index 170b841..407896c 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2719-net-phy-aquantia-add-firmware-download.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2719-net-phy-aquantia-add-firmware-download.patch
@@ -140,7 +140,7 @@
#endif
+
+#ifdef CONFIG_AQUANTIA_PHY_FW_DOWNLOAD
-+enum {
++enum aqr_fw_dl_mode {
+ FW_DL_SINGLE = 0,
+ FW_DL_GNAGLOAD,
+};
@@ -153,7 +153,7 @@
index 000000000..d2828aad4
--- /dev/null
+++ b/drivers/net/phy/aquantia_firmware.c
-@@ -0,0 +1,1100 @@
+@@ -0,0 +1,1109 @@
+// SPDX-License-Identifier: GPL-2.0
+/* FW download driver for Aquantia PHY
+ */
@@ -301,8 +301,9 @@
+struct phy_device *gangload_phydevs[MAX_GANGLOAD_DEVICES];
+static unsigned long gangload_timeout = 0;
+static int gangload = 0;
++static DEFINE_SPINLOCK(gangload_lock);
+
-+static int aqr_firmware_download_single(struct phy_device *phydev);
++static int aqr_firmware_download_single(struct phy_device *phydev, bool force_reload);
+
+void AQ_API_EnableMDIO_BootLoadMode
+(
@@ -1068,9 +1069,7 @@
+ if (priv->fw_initialized == true &&
+ aqr_firmware_check_heartbeat(phydev) == 1) {
+ dev_err(dev, "Detect heartbeat stopped, start to realod firmware...\n");
-+ priv->fw_initialized = false;
-+ priv->fw_dl_mode = FW_DL_SINGLE;
-+ aqr_firmware_download_single(phydev);
++ aqr_firmware_download_single(phydev, true);
+ }
+
+ set_current_state(TASK_INTERRUPTIBLE);
@@ -1092,12 +1091,14 @@
+ if (!fw)
+ return;
+
++ spin_lock(&gangload_lock);
++
+ num_phydevs = priv->fw_dl_mode == FW_DL_GNAGLOAD ?
+ gangload : 1;
+
+retry:
-+ if (gandload_phydev->state == PHY_HALTED) {
-+ dev_info(dev, "Detect PHY power down, stop to reload firmware...\n");
++ if (gandload_phydev->state == PHY_HALTED && priv->fw_initialized == true) {
++ dev_info(dev, "Detect PHY power down, stop to download firmware...\n");
+ goto out;
+ }
+
@@ -1139,23 +1140,28 @@
+ }
+ }
+ }
++
+out:
+ release_firmware(fw);
++
++ spin_unlock(&gangload_lock);
+}
+
-+static int aqr_firmware_download_single(struct phy_device *phydev)
++static int aqr_firmware_download_single(struct phy_device *phydev, bool force_reload)
+{
+ struct aqr107_priv *priv = phydev->priv;
+ struct device *dev = &phydev->mdio.dev;
+ const struct firmware *fw;
+ int ret = 0;
+
-+ if (priv->fw_initialized == true)
++ if (priv->fw_initialized == true && force_reload == false)
+ return 0;
+
-+ spin_lock_init(&priv->lock);
++ if (priv->phydevs[0] != phydev) {
++ priv->phydevs[0] = phydev;
++ spin_lock_init(&priv->lock);
++ }
+ priv->fw_dl_mode = FW_DL_SINGLE;
-+ priv->phydevs[0] = phydev;
+ priv->heartbeat = -1;
+
+ ret = request_firmware(&fw, AQR_FIRMWARE, dev);
@@ -1224,18 +1230,21 @@
+ wake_up_process(gangload_kthread);
+ }
+
-+ /* fall back to single mode if timeout is reached */
-+ if (time_after(jiffies, gangload_timeout))
-+ return aqr_firmware_download_single(phydev);
-+
+ for (i = 0; i < gangload; i++) {
+ if (gangload_phydevs[i] == phydev) {
+ dev_warn(dev, "Detect duplicate gangload phydev\n");
-+ return -EINVAL;
++ return 0;
+ }
+ }
+
-+ spin_lock_init(&priv->lock);
++ /* fall back to single mode if timeout is reached */
++ if (time_after(jiffies, gangload_timeout))
++ return aqr_firmware_download_single(phydev, false);
++
++ if (priv->phydevs[0] != phydev) {
++ priv->phydevs[0] = phydev;
++ spin_lock_init(&priv->lock);
++ }
+ priv->fw_dl_mode = FW_DL_GNAGLOAD;
+ priv->heartbeat = -1;
+ gangload_phydevs[gangload] = phydev;
@@ -1248,7 +1257,7 @@
+{
+ int ret = 0;
+#ifdef CONFIG_AQUANTIA_PHY_FW_DOWNLOAD_SINGLE
-+ ret = aqr_firmware_download_single(phydev);
++ ret = aqr_firmware_download_single(phydev, false);
+#elif CONFIG_AQUANTIA_PHY_FW_DOWNLOAD_GANG
+ ret = aqr_firmware_download_gang(phydev);
+#endif
@@ -1383,20 +1392,21 @@
return aqr107_set_downshift(phydev, MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT);
}
-@@ -574,12 +559,41 @@ static void aqr107_link_change_notify(struct phy_device *phydev)
+@@ -574,12 +559,43 @@ static void aqr107_link_change_notify(struct phy_device *phydev)
static int aqr107_suspend(struct phy_device *phydev)
{
+#ifdef CONFIG_AQUANTIA_PHY_FW_DOWNLOAD
+ struct aqr107_priv *priv = phydev->priv;
+
-+ spin_lock(&priv->lock);
-+ if (priv->heartbeat_thread) {
-+ kthread_stop(priv->heartbeat_thread);
-+ priv->heartbeat_thread = NULL;
-+ priv->heartbeat = -1;
++ if (spin_trylock(&priv->lock)) {
++ if (priv->heartbeat_thread) {
++ kthread_stop(priv->heartbeat_thread);
++ priv->heartbeat_thread = NULL;
++ priv->heartbeat = -1;
++ }
++ spin_unlock(&priv->lock);
+ }
-+ spin_unlock(&priv->lock);
+#endif
return phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MDIO_CTRL1,
MDIO_CTRL1_LPOWER);
@@ -1407,20 +1417,21 @@
+#ifdef CONFIG_AQUANTIA_PHY_FW_DOWNLOAD
+ struct aqr107_priv *priv = phydev->priv;
+
-+ spin_lock(&priv->lock);
-+ if (!priv->heartbeat_thread) {
-+ priv->heartbeat_thread = kthread_create(aqr_firmware_heartbeat_thread,
-+ phydev,
-+ "aqr_firmware_heartbeat_thread");
-+ if (IS_ERR(priv->heartbeat_thread)) {
-+ phydev_err(phydev,
-+ "Failed to create aqr_firmware_heartbeat_thread(%ld)\n",
-+ PTR_ERR(priv->heartbeat_thread));
-+ priv->heartbeat_thread = NULL;
-+ } else
-+ wake_up_process(priv->heartbeat_thread);
++ if (spin_trylock(&priv->lock)) {
++ if (!priv->heartbeat_thread) {
++ priv->heartbeat_thread = kthread_create(aqr_firmware_heartbeat_thread,
++ phydev,
++ "aqr_firmware_heartbeat_thread");
++ if (IS_ERR(priv->heartbeat_thread)) {
++ phydev_err(phydev,
++ "Failed to create aqr_firmware_heartbeat_thread(%ld)\n",
++ PTR_ERR(priv->heartbeat_thread));
++ priv->heartbeat_thread = NULL;
++ } else
++ wake_up_process(priv->heartbeat_thread);
++ }
++ spin_unlock(&priv->lock);
+ }
-+ spin_unlock(&priv->lock);
+#endif
return phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MDIO_CTRL1,
MDIO_CTRL1_LPOWER);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2729-net-phy-remove-reporting-line-rate-to-mac.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2729-net-phy-remove-reporting-line-rate-to-mac.patch
new file mode 100644
index 0000000..4f62103
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2729-net-phy-remove-reporting-line-rate-to-mac.patch
@@ -0,0 +1,14 @@
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -686,7 +686,10 @@ static void phylink_link_up(struct phyli
+ * the link_state) to the interface speed, and will send
+ * pause frames to the MAC to limit its transmission speed.
+ */
+- speed = phylink_interface_max_speed(link_state.interface);
++ /* For tunnel HW offload, we need to get true link rate to
++ * set QDMA rate limit as link rate.
++ */
++ // speed = phylink_interface_max_speed(link_state.interface);
+ duplex = DUPLEX_FULL;
+ rx_pause = true;
+ break;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2730-net-phy-sfp-change-shared-mod-def0.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2730-net-phy-sfp-change-shared-mod-def0.patch
new file mode 100644
index 0000000..479f58b
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2730-net-phy-sfp-change-shared-mod-def0.patch
@@ -0,0 +1,43 @@
+From c576ce67488bc8b0285933f315cb183c9171f199 Mon Sep 17 00:00:00 2001
+From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
+Date: Thu, 7 Sep 2023 12:01:57 +0800
+Subject: [PATCH] 999-2730-net-phy-sfp-change-shared-mod-def0
+
+---
+ drivers/net/phy/sfp.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c
+index 0c335b1..d49a825 100644
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -152,7 +152,7 @@ static const char *gpio_of_names[] = {
+ };
+
+ static const enum gpiod_flags gpio_flags[] = {
+- GPIOD_IN,
++ GPIOD_IN | GPIOD_FLAGS_BIT_NONEXCLUSIVE,
+ GPIOD_IN,
+ GPIOD_IN,
+ GPIOD_ASIS,
+@@ -512,7 +512,7 @@ static unsigned int sfp_gpio_get_state(struct sfp *sfp)
+ unsigned int i, state, v;
+
+ for (i = state = 0; i < GPIO_MAX; i++) {
+- if (gpio_flags[i] != GPIOD_IN || !sfp->gpio[i])
++ if (((gpio_flags[i] & GPIOD_IN) != GPIOD_IN) || !sfp->gpio[i])
+ continue;
+
+ v = gpiod_get_value_cansleep(sfp->gpio[i]);
+@@ -2757,7 +2757,7 @@ static int sfp_probe(struct platform_device *pdev)
+ }
+
+ for (i = 0; i < GPIO_MAX; i++) {
+- if (gpio_flags[i] != GPIOD_IN || !sfp->gpio[i])
++ if (((gpio_flags[i] & GPIOD_IN) != GPIOD_IN) || !sfp->gpio[i])
+ continue;
+
+ sfp->gpio_irq[i] = gpiod_to_irq(sfp->gpio[i]);
+--
+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 8f19163..e4bde13 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
@@ -36,6 +36,7 @@
file://1020-spi-nor-w25q512jv.patch \
file://1021-ubnt-ledbar-driver.patch \
file://999-1000-backport-pinctrl-pinconf-setting-combo.patch \
+ file://999-1033-backport-pinctrl-spinlock.patch \
file://999-1600-mdiobus-add-c45.patch \
file://999-1700-macsec-revert-async-support.patch \
file://999-1701-add-default-setting-to-dsa-unused-port.patch \
@@ -147,6 +148,8 @@
file://999-2725-iwconfig-wireless-rate-fix.patch;apply=no \
file://999-2727-net-phy-sfp-add-debug-info.patch.patch \
file://999-2728-net-phy-aquantia-add-mib-read.patch \
+ file://999-2729-net-phy-remove-reporting-line-rate-to-mac.patch;apply=no \
+ file://999-2730-net-phy-sfp-change-shared-mod-def0.patch \
file://999-2800-misc-add-mtk-platform.patch \
file://999-2900-dts-mt7622-enable-new-mtk-snand-for-ubi.patch \
file://999-2901-dts-mt7622-remove-cooling-device.patch \
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3021-mtk-wed-add-wed3-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3021-mtk-wed-add-wed3-support.patch
index 69df648..cda6afa 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3021-mtk-wed-add-wed3-support.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3021-mtk-wed-add-wed3-support.patch
@@ -1,9 +1,8 @@
-From 400f8349a31ffc48538aa7df64a88111de9a738b Mon Sep 17 00:00:00 2001
-From: Sujuan Chen <sujuan.chen@mediatek.com>
-Date: Thu, 13 Apr 2023 15:51:08 +0800
+From e8b3ef23ae83316d6b1d7d544708cc2a076ba571 Mon Sep 17 00:00:00 2001
+From: mtk27745 <rex.lu@mediatek.com>
+Date: Mon, 11 Sep 2023 11:25:07 +0800
Subject: [PATCH] mtk:wed:add wed3 support
-Signed-off-by: sujuan.chen <sujuan.chen@mediatek.com>
---
arch/arm64/boot/dts/mediatek/mt7988.dtsi | 152 ++-
.../dts/mediatek/mt7988a-dsa-10g-spim-nor.dts | 16 +-
@@ -13,7 +12,7 @@
drivers/net/ethernet/mediatek/mtk_ppe.c | 17 +-
drivers/net/ethernet/mediatek/mtk_ppe.h | 2 +-
.../net/ethernet/mediatek/mtk_ppe_offload.c | 13 +-
- drivers/net/ethernet/mediatek/mtk_wed.c | 1148 +++++++++++++----
+ drivers/net/ethernet/mediatek/mtk_wed.c | 1155 +++++++++++++----
drivers/net/ethernet/mediatek/mtk_wed.h | 25 +-
.../net/ethernet/mediatek/mtk_wed_debugfs.c | 584 ++++++++-
drivers/net/ethernet/mediatek/mtk_wed_mcu.c | 13 +-
@@ -21,14 +20,14 @@
drivers/net/ethernet/mediatek/mtk_wed_regs.h | 338 ++++-
include/linux/netdevice.h | 7 +
include/linux/soc/mediatek/mtk_wed.h | 81 +-
- 16 files changed, 1446 insertions(+), 333 deletions(-)
+ 16 files changed, 2045 insertions(+), 387 deletions(-)
mode change 100755 => 100644 drivers/net/ethernet/mediatek/mtk_ppe.c
diff --git a/arch/arm64/boot/dts/mediatek/mt7988.dtsi b/arch/arm64/boot/dts/mediatek/mt7988.dtsi
-index 364deef..f9a0120 100644
+index 561450e9ba48..8995ea30d4f7 100644
--- a/arch/arm64/boot/dts/mediatek/mt7988.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt7988.dtsi
-@@ -191,44 +191,49 @@
+@@ -205,44 +205,49 @@
status = "disabled";
};
@@ -113,7 +112,7 @@
};
wdma: wdma@15104800 {
-@@ -238,15 +243,25 @@
+@@ -252,15 +257,25 @@
<0 0x15105000 0 0x400>;
};
@@ -147,7 +146,7 @@
};
wocpu0_ilm: wocpu0_ilm@151E0000 {
-@@ -254,31 +269,53 @@
+@@ -268,31 +283,53 @@
reg = <0 0x151E0000 0 0x8000>;
};
@@ -215,7 +214,7 @@
};
reserved-memory {
-@@ -827,6 +864,7 @@
+@@ -902,6 +939,7 @@
<&topckgen CK_TOP_CB_SGM_325M>;
mediatek,ethsys = <ðsys>;
mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>;
@@ -224,10 +223,10 @@
mediatek,xfi_pextp = <&xfi_pextp0>, <&xfi_pextp1>;
mediatek,xfi_pll = <&xfi_pll>;
diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nor.dts b/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nor.dts
-index 7db5164..0a6db8b 100644
+index 70a7554473f6..bed27b4b3488 100644
--- a/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nor.dts
+++ b/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nor.dts
-@@ -341,9 +341,23 @@
+@@ -369,9 +369,23 @@
status = "okay";
};
@@ -254,10 +253,10 @@
+};
\ No newline at end of file
diff --git a/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nor.dts b/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nor.dts
-index 67c6508..c407b33 100644
+index e8e3a69290c8..5dd481b72ea8 100644
--- a/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nor.dts
+++ b/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nor.dts
-@@ -325,9 +325,23 @@
+@@ -379,9 +379,23 @@
status = "okay";
};
@@ -284,10 +283,10 @@
+};
\ No newline at end of file
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 388982c..d59c29f 100644
+index 6fabc5758fb6..655928cc7462 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -4865,7 +4865,8 @@ static int mtk_probe(struct platform_device *pdev)
+@@ -5094,7 +5094,8 @@ static int mtk_probe(struct platform_device *pdev)
"mediatek,wed", i);
static const u32 wdma_regs[] = {
MTK_WDMA0_BASE,
@@ -298,10 +297,10 @@
void __iomem *wdma;
u32 wdma_phy;
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-index a9feaed..70e8377 100644
+index 80f4c4b32a30..06f2b5d98b81 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -605,9 +605,12 @@
+@@ -611,9 +611,12 @@
#define RX_DMA_SPORT_MASK 0x7
#define RX_DMA_SPORT_MASK_V2 0xf
@@ -318,7 +317,7 @@
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c
old mode 100755
new mode 100644
-index bc13a9b..3910163
+index 384e811d6946..eda23c2afbbf
--- a/drivers/net/ethernet/mediatek/mtk_ppe.c
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
@@ -9,6 +9,7 @@
@@ -367,7 +366,7 @@
}
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.h b/drivers/net/ethernet/mediatek/mtk_ppe.h
-index df10040..9e7d5aa 100644
+index 2a8b6ef225a2..66c7f10170d2 100644
--- a/drivers/net/ethernet/mediatek/mtk_ppe.h
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
@@ -428,7 +428,7 @@ int mtk_foe_entry_set_dsa(struct mtk_foe_entry *entry, int port);
@@ -378,9 +377,9 @@
+ int bss, int wcid, bool amsdu_en);
int mtk_foe_entry_set_qid(struct mtk_foe_entry *entry, int qid);
int mtk_foe_entry_set_dscp(struct mtk_foe_entry *entry, int dscp);
- int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
+ bool mtk_foe_entry_match(struct mtk_foe_entry *entry, struct mtk_foe_entry *data);
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
-index 9bc0857..86fc9a1 100644
+index 95174b795cf0..eab9e9de7193 100644
--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
@@ -112,6 +112,7 @@ mtk_flow_get_wdma_info(struct net_device *dev, const u8 *addr, struct mtk_wdma_i
@@ -408,7 +407,7 @@
else
return -EOPNOTSUPP;
#endif
-@@ -458,8 +461,8 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
+@@ -490,8 +493,8 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
if (err)
return err;
@@ -419,8 +418,8 @@
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
if (!entry)
-@@ -499,8 +502,8 @@ clear:
- mtk_foe_entry_clear(eth->ppe[i], entry);
+@@ -516,8 +519,8 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
+ mtk_foe_entry_clear(eth->ppe[ppe_index], entry);
free:
kfree(entry);
- if (wed_index >= 0)
@@ -431,7 +430,7 @@
}
diff --git a/drivers/net/ethernet/mediatek/mtk_wed.c b/drivers/net/ethernet/mediatek/mtk_wed.c
-index 37a86c3..e3809db 100644
+index 3e760f7c5f3d..6ac4aa8d4e3c 100644
--- a/drivers/net/ethernet/mediatek/mtk_wed.c
+++ b/drivers/net/ethernet/mediatek/mtk_wed.c
@@ -28,7 +28,7 @@ struct wo_cmd_ring {
@@ -1018,10 +1017,10 @@
-#define MTK_WFMDA_RX_DMA_EN BIT(2)
+ if (!mtk_wed_get_rx_capa(dev))
+ return 0;
-
++
+ wed_set(dev, MTK_WED_RRO_PG_BM_RX_DMAM,
+ FIELD_PREP(MTK_WED_RRO_PG_BM_RX_SDL0, 128));
-+
+
+ wed_w32(dev, MTK_WED_RRO_PG_BM_BASE,
+ dev->rx_page_buf_ring.desc_phys);
+
@@ -1323,12 +1322,12 @@
- value = wed_r32(dev, MTK_WED_PCIE_CFG_BASE);
- wed_w32(dev, MTK_WED_PCIE_CFG_INTM, PCIE_BASE_ADDR0 | 0x180);
- wed_w32(dev, MTK_WED_PCIE_CFG_BASE, PCIE_BASE_ADDR0 | 0x184);
--
-- value = wed_r32(dev, MTK_WED_PCIE_CFG_INTM);
-- value = wed_r32(dev, MTK_WED_PCIE_CFG_BASE);
+ MTK_WED_PCIE_INT_CTRL_MSK_IRQ_FILTER |
+ FIELD_PREP(MTK_WED_PCIE_INT_CTRL_SRC_SEL, dev->hw->index));
+- value = wed_r32(dev, MTK_WED_PCIE_CFG_INTM);
+- value = wed_r32(dev, MTK_WED_PCIE_CFG_BASE);
+-
- wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER, BIT(24));
- wed_r32(dev, MTK_WED_PCIE_INT_TRIGGER);
-
@@ -2088,16 +2087,24 @@
static u32
mtk_wed_irq_get(struct mtk_wed_device *dev, u32 mask)
{
-@@ -1660,6 +2335,8 @@ mtk_wed_irq_get(struct mtk_wed_device *dev, u32 mask)
+@@ -1659,9 +2334,13 @@ mtk_wed_irq_get(struct mtk_wed_device *dev, u32 mask)
+
val = wed_r32(dev, MTK_WED_EXT_INT_STATUS);
wed_w32(dev, MTK_WED_EXT_INT_STATUS, val);
- val &= MTK_WED_EXT_INT_STATUS_ERROR_MASK;
-+ if (dev->hw->version == 3)
+- val &= MTK_WED_EXT_INT_STATUS_ERROR_MASK;
+- if (!dev->hw->num_flows)
+- val &= ~MTK_WED_EXT_INT_STATUS_TKID_WO_PYLD;
++ if (dev->hw->version == 3) {
+ val &= MTK_WED_EXT_INT_STATUS_RX_DRV_COHERENT;
- WARN_RATELIMIT(val, "mtk_wed%d: error status=%08x\n",
- dev->hw->index, val);
++ } else {
++ val &= MTK_WED_EXT_INT_STATUS_ERROR_MASK;
++ if (!dev->hw->num_flows)
++ val &= ~MTK_WED_EXT_INT_STATUS_TKID_WO_PYLD;
++ }
+ if (val && net_ratelimit())
+ pr_err("mtk_wed%d: error status=%08x\n", dev->hw->index, val);
-@@ -1752,6 +2429,9 @@ void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
+@@ -1754,6 +2433,9 @@ void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
.tx_ring_setup = mtk_wed_tx_ring_setup,
.txfree_ring_setup = mtk_wed_txfree_ring_setup,
.rx_ring_setup = mtk_wed_rx_ring_setup,
@@ -2107,7 +2114,7 @@
.msg_update = mtk_wed_send_msg,
.start = mtk_wed_start,
.stop = mtk_wed_stop,
-@@ -1763,6 +2443,7 @@ void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
+@@ -1765,6 +2447,7 @@ void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
.detach = mtk_wed_detach,
.setup_tc = mtk_wed_eth_setup_tc,
.ppe_check = mtk_wed_ppe_check,
@@ -2115,7 +2122,7 @@
};
struct device_node *eth_np = eth->dev->of_node;
struct platform_device *pdev;
-@@ -1802,9 +2483,10 @@ void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
+@@ -1804,9 +2487,10 @@ void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
hw->wdma_phy = wdma_phy;
hw->index = index;
hw->irq = irq;
@@ -2128,7 +2135,7 @@
hw->mirror = syscon_regmap_lookup_by_phandle(eth_np,
"mediatek,pcie-mirror");
hw->hifsys = syscon_regmap_lookup_by_phandle(eth_np,
-@@ -1819,7 +2501,6 @@ void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
+@@ -1821,7 +2505,6 @@ void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
regmap_write(hw->mirror, 0, 0);
regmap_write(hw->mirror, 4, 0);
}
@@ -2137,7 +2144,7 @@
mtk_wed_hw_add_debugfs(hw);
diff --git a/drivers/net/ethernet/mediatek/mtk_wed.h b/drivers/net/ethernet/mediatek/mtk_wed.h
-index 490873c..fcf7bd0 100644
+index 490873cc58ac..fcf7bd0a6f66 100644
--- a/drivers/net/ethernet/mediatek/mtk_wed.h
+++ b/drivers/net/ethernet/mediatek/mtk_wed.h
@@ -10,10 +10,13 @@
@@ -2204,7 +2211,7 @@
#ifdef CONFIG_NET_MEDIATEK_SOC_WED
diff --git a/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c b/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c
-index 4a9e684..51e3d7c 100644
+index 4a9e684edbdb..51e3d7c94d86 100644
--- a/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c
+++ b/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c
@@ -11,9 +11,11 @@ struct reg_dump {
@@ -2901,7 +2908,7 @@
}
}
diff --git a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
-index 96e30a3..055594d 100644
+index 96e30a320ed7..055594de1c98 100644
--- a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
+++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
@@ -242,7 +242,7 @@ mtk_wed_load_firmware(struct mtk_wed_wo *wo)
@@ -2939,7 +2946,7 @@
wo_w32(wo, WOX_MCU_CFG_LS_WF_MCU_CFG_WM_WA_ADDR, val);
diff --git a/drivers/net/ethernet/mediatek/mtk_wed_mcu.h b/drivers/net/ethernet/mediatek/mtk_wed_mcu.h
-index 19e1199..c07bdb6 100644
+index 19e1199783f4..c07bdb6ca153 100644
--- a/drivers/net/ethernet/mediatek/mtk_wed_mcu.h
+++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.h
@@ -16,8 +16,9 @@
@@ -2955,7 +2962,7 @@
#define WOCPU_EMI_DEV_NODE "mediatek,wocpu_emi"
#define WOCPU_ILM_DEV_NODE "mediatek,wocpu_ilm"
diff --git a/drivers/net/ethernet/mediatek/mtk_wed_regs.h b/drivers/net/ethernet/mediatek/mtk_wed_regs.h
-index 403a36b..4e619ff 100644
+index 403a36bb9d5e..25be547b98fa 100644
--- a/drivers/net/ethernet/mediatek/mtk_wed_regs.h
+++ b/drivers/net/ethernet/mediatek/mtk_wed_regs.h
@@ -20,6 +20,9 @@
@@ -3458,10 +3465,10 @@
+#define MTK_WED_PCIE_BASE2 0x11290000
#endif
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
-index 58b5ce6..5e51790 100644
+index 0967dc24060f..3211f344847e 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
-@@ -873,6 +873,13 @@ struct net_device_path {
+@@ -875,6 +875,13 @@ struct net_device_path {
u8 queue;
u16 wcid;
u8 bss;
@@ -3476,7 +3483,7 @@
};
};
diff --git a/include/linux/soc/mediatek/mtk_wed.h b/include/linux/soc/mediatek/mtk_wed.h
-index 27cf284..60336e0 100644
+index 27cf284b4af3..2b389e8a813c 100644
--- a/include/linux/soc/mediatek/mtk_wed.h
+++ b/include/linux/soc/mediatek/mtk_wed.h
@@ -5,11 +5,14 @@