[][kernel][mt7987][eth][Add error handling for PSE error info to the FE misc ISR for the NETSYSv3.1]

[Description]
Add error handling for PSE error info to the FE misc ISR for the
NETSYSv3.1.

Without this patch, the ETH driver is unable to handle the interrupts
related to PSE error info.

[Release-log]
N/A


Change-Id: I29e9b244d462e707f2b3ebd6587dce5b0d5ec47a
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/9749162
diff --git a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_reset.c b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_reset.c
index 3cae2d1..e9998b9 100644
--- a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_reset.c
+++ b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_reset.c
@@ -219,10 +219,189 @@
 	return ret;
 }
 
+u32 mtk_gdm_dbg_out(struct mtk_eth *eth, u32 reg, u32 mask, u32 index)
+{
+	mtk_m32(eth, mask, index, reg);
+
+	return mtk_r32(eth, reg + 0x4);
+}
+
+void mtk_gdm_pl_end_page_error(struct mtk_eth *eth, int id)
+{
+	enum mtk_gdm_dbg_index {
+		FS_PL_END_MISMATCH_LGC_INFO_LSB = 20,
+		FS_PL_END_MISMATCH_LGC_INFO_MSB,
+		FS_PL_END_MISMATCH_EXT_INFO_31_0,
+		FS_PL_END_MISMATCH_EXT_INFO_63_32,
+		FS_PL_END_MISMATCH_EXT_INFO_95_64,
+		FS_PL_END_MISMATCH_EXT_INFO_127_96,
+		FS_PL_END_MISMATCH_EXT_INFO_159_128,
+		FS_PL_END_MISMATCH_EXT_INFO_161_160,
+		FS_PL_END_MISMATCH_LINK_LIST_INDEX,
+	};
+
+	if (id < 0 || id > 2)
+		return;
+
+	pr_info("====================================================");
+	pr_info("GDM%d FS_PL_END_MISMATCH_LGC_INFO_LSB      = %08x\n", id + 1,
+		mtk_gdm_dbg_out(eth, FE_GDM_DBG_CTRL(id), GDM_DBG_IDX_MASK,
+				FIELD_PREP(GDM_DBG_IDX_MASK,
+					   FS_PL_END_MISMATCH_LGC_INFO_LSB)));
+	pr_info("GDM%d FS_PL_END_MISMATCH_LGC_INFO_MSB      = %08x\n", id + 1,
+		mtk_gdm_dbg_out(eth, FE_GDM_DBG_CTRL(id), GDM_DBG_IDX_MASK,
+				FIELD_PREP(GDM_DBG_IDX_MASK,
+					   FS_PL_END_MISMATCH_LGC_INFO_MSB)));
+	pr_info("GDM%d FS_PL_END_MISMATCH_EXT_INFO[31:0]    = %08x\n", id + 1,
+		mtk_gdm_dbg_out(eth, FE_GDM_DBG_CTRL(id), GDM_DBG_IDX_MASK,
+				FIELD_PREP(GDM_DBG_IDX_MASK,
+					   FS_PL_END_MISMATCH_EXT_INFO_31_0)));
+	pr_info("GDM%d FS_PL_END_MISMATCH_EXT_INFO[63:32]   = %08x\n", id + 1,
+		mtk_gdm_dbg_out(eth, FE_GDM_DBG_CTRL(id), GDM_DBG_IDX_MASK,
+				FIELD_PREP(GDM_DBG_IDX_MASK,
+					   FS_PL_END_MISMATCH_EXT_INFO_63_32)));
+	pr_info("GDM%d FS_PL_END_MISMATCH_EXT_INFO[95:64]   = %08x\n", id + 1,
+		mtk_gdm_dbg_out(eth, FE_GDM_DBG_CTRL(id), GDM_DBG_IDX_MASK,
+				FIELD_PREP(GDM_DBG_IDX_MASK,
+					   FS_PL_END_MISMATCH_EXT_INFO_95_64)));
+	pr_info("GDM%d FS_PL_END_MISMATCH_EXT_INFO[127:96]  = %08x\n", id + 1,
+		mtk_gdm_dbg_out(eth, FE_GDM_DBG_CTRL(id), GDM_DBG_IDX_MASK,
+				FIELD_PREP(GDM_DBG_IDX_MASK,
+					   FS_PL_END_MISMATCH_EXT_INFO_127_96)));
+	pr_info("GDM%d FS_PL_END_MISMATCH_EXT_INFO[159:128] = %08x\n", id + 1,
+		mtk_gdm_dbg_out(eth, FE_GDM_DBG_CTRL(id), GDM_DBG_IDX_MASK,
+				FIELD_PREP(GDM_DBG_IDX_MASK,
+					   FS_PL_END_MISMATCH_EXT_INFO_159_128)));
+	pr_info("GDM%d FS_PL_END_MISMATCH_EXT_INFO[161:160] = %08x\n", id + 1,
+		mtk_gdm_dbg_out(eth, FE_GDM_DBG_CTRL(id), GDM_DBG_IDX_MASK,
+				FIELD_PREP(GDM_DBG_IDX_MASK,
+					   FS_PL_END_MISMATCH_EXT_INFO_161_160)));
+	pr_info("GDM%d FS_PL_END_MISMATCH_LINK_LIST_INDEX = %08x\n", id + 1,
+		mtk_gdm_dbg_out(eth, FE_GDM_DBG_CTRL(id), GDM_DBG_IDX_MASK,
+				FIELD_PREP(GDM_DBG_IDX_MASK,
+					   FS_PL_END_MISMATCH_LINK_LIST_INDEX)));
+	pr_info("====================================================");
+}
+
+void mtk_cdm_v2_pl_end_page_error(struct mtk_eth *eth, int id)
+{
+	enum mtk_gdm_dbg_index {
+		FS_PL_END_MISMATCH_LGC_INFO_LSB = 24,
+		FS_PL_END_MISMATCH_LGC_INFO_MSB,
+		FS_PL_END_MISMATCH_EXT_INFO_31_0,
+		FS_PL_END_MISMATCH_EXT_INFO_63_32,
+		FS_PL_END_MISMATCH_EXT_INFO_95_64,
+		FS_PL_END_MISMATCH_EXT_INFO_127_96,
+		FS_PL_END_MISMATCH_EXT_INFO_159_128,
+		FS_PL_END_MISMATCH_EXT_INFO_161_160,
+		FS_PL_END_MISMATCH_LINK_LIST_INDEX,
+	};
+
+	if (id < 0 || id > 2)
+		return;
+
+	pr_info("====================================================");
+	pr_info("CDM%d FS_PL_END_MISMATCH_LGC_INFO_LSB      = %08x\n", id + 1,
+		mtk_gdm_dbg_out(eth, FE_CDM_DBG_CTRL(id), CDM_DBG_IDX_MASK,
+				FIELD_PREP(CDM_DBG_IDX_MASK,
+					   FS_PL_END_MISMATCH_LGC_INFO_LSB)));
+	pr_info("CDM%d FS_PL_END_MISMATCH_LGC_INFO_MSB      = %08x\n", id + 1,
+		mtk_gdm_dbg_out(eth, FE_CDM_DBG_CTRL(id), CDM_DBG_IDX_MASK,
+				FIELD_PREP(CDM_DBG_IDX_MASK,
+					   FS_PL_END_MISMATCH_LGC_INFO_MSB)));
+	pr_info("CDM%d FS_PL_END_MISMATCH_EXT_INFO[31:0]    = %08x\n", id + 1,
+		mtk_gdm_dbg_out(eth, FE_CDM_DBG_CTRL(id), CDM_DBG_IDX_MASK,
+				FIELD_PREP(CDM_DBG_IDX_MASK,
+					   FS_PL_END_MISMATCH_EXT_INFO_31_0)));
+	pr_info("CDM%d FS_PL_END_MISMATCH_EXT_INFO[63:32]   = %08x\n", id + 1,
+		mtk_gdm_dbg_out(eth, FE_CDM_DBG_CTRL(id), CDM_DBG_IDX_MASK,
+				FIELD_PREP(CDM_DBG_IDX_MASK,
+					   FS_PL_END_MISMATCH_EXT_INFO_63_32)));
+	pr_info("CDM%d FS_PL_END_MISMATCH_EXT_INFO[95:64]   = %08x\n", id + 1,
+		mtk_gdm_dbg_out(eth, FE_CDM_DBG_CTRL(id), CDM_DBG_IDX_MASK,
+				FIELD_PREP(CDM_DBG_IDX_MASK,
+					   FS_PL_END_MISMATCH_EXT_INFO_95_64)));
+	pr_info("CDM%d FS_PL_END_MISMATCH_EXT_INFO[127:96]  = %08x\n", id + 1,
+		mtk_gdm_dbg_out(eth, FE_CDM_DBG_CTRL(id), CDM_DBG_IDX_MASK,
+				FIELD_PREP(CDM_DBG_IDX_MASK,
+					   FS_PL_END_MISMATCH_EXT_INFO_127_96)));
+	pr_info("CDM%d FS_PL_END_MISMATCH_EXT_INFO[159:128] = %08x\n", id + 1,
+		mtk_gdm_dbg_out(eth, FE_CDM_DBG_CTRL(id), CDM_DBG_IDX_MASK,
+				FIELD_PREP(CDM_DBG_IDX_MASK,
+					   FS_PL_END_MISMATCH_EXT_INFO_159_128)));
+	pr_info("CDM%d FS_PL_END_MISMATCH_EXT_INFO[161:160] = %08x\n", id + 1,
+		mtk_gdm_dbg_out(eth, FE_CDM_DBG_CTRL(id), CDM_DBG_IDX_MASK,
+				FIELD_PREP(CDM_DBG_IDX_MASK,
+					   FS_PL_END_MISMATCH_EXT_INFO_161_160)));
+	pr_info("CDM%d FS_PL_END_MISMATCH_LINK_LIST_INDEX = %08x\n", id + 1,
+		mtk_gdm_dbg_out(eth, FE_CDM_DBG_CTRL(id), CDM_DBG_IDX_MASK,
+				FIELD_PREP(CDM_DBG_IDX_MASK,
+					   FS_PL_END_MISMATCH_LINK_LIST_INDEX)));
+	pr_info("====================================================");
+}
+
+void mtk_cdm_v3_pl_end_page_error(struct mtk_eth *eth, int id)
+{
+	enum mtk_gdm_dbg_index {
+		FS_PL_END_MISMATCH_LGC_INFO_LSB = 27,
+		FS_PL_END_MISMATCH_LGC_INFO_MSB,
+		FS_PL_END_MISMATCH_EXT_INFO_31_0,
+		FS_PL_END_MISMATCH_EXT_INFO_63_32,
+		FS_PL_END_MISMATCH_EXT_INFO_95_64,
+		FS_PL_END_MISMATCH_EXT_INFO_127_96,
+		FS_PL_END_MISMATCH_EXT_INFO_159_128,
+		FS_PL_END_MISMATCH_EXT_INFO_161_160,
+		FS_PL_END_MISMATCH_LINK_LIST_INDEX,
+	};
+
+	if (id < 2 || id > 8)
+		return;
+
+	pr_info("====================================================");
+	pr_info("CDM%d FS_PL_END_MISMATCH_LGC_INFO_LSB      = %08x\n", id + 1,
+		mtk_gdm_dbg_out(eth, FE_CDM_DBG_CTRL(id), CDM_DBG_IDX_MASK,
+				FIELD_PREP(CDM_DBG_IDX_MASK,
+					   FS_PL_END_MISMATCH_LGC_INFO_LSB)));
+	pr_info("CDM%d FS_PL_END_MISMATCH_LGC_INFO_MSB      = %08x\n", id + 1,
+		mtk_gdm_dbg_out(eth, FE_CDM_DBG_CTRL(id), CDM_DBG_IDX_MASK,
+				FIELD_PREP(CDM_DBG_IDX_MASK,
+					   FS_PL_END_MISMATCH_LGC_INFO_MSB)));
+	pr_info("CDM%d FS_PL_END_MISMATCH_EXT_INFO[31:0]    = %08x\n", id + 1,
+		mtk_gdm_dbg_out(eth, FE_CDM_DBG_CTRL(id), CDM_DBG_IDX_MASK,
+				FIELD_PREP(CDM_DBG_IDX_MASK,
+					   FS_PL_END_MISMATCH_EXT_INFO_31_0)));
+	pr_info("CDM%d FS_PL_END_MISMATCH_EXT_INFO[63:32]   = %08x\n", id + 1,
+		mtk_gdm_dbg_out(eth, FE_CDM_DBG_CTRL(id), CDM_DBG_IDX_MASK,
+				FIELD_PREP(CDM_DBG_IDX_MASK,
+					   FS_PL_END_MISMATCH_EXT_INFO_63_32)));
+	pr_info("CDM%d FS_PL_END_MISMATCH_EXT_INFO[95:64]   = %08x\n", id + 1,
+		mtk_gdm_dbg_out(eth, FE_CDM_DBG_CTRL(id), CDM_DBG_IDX_MASK,
+				FIELD_PREP(CDM_DBG_IDX_MASK,
+					   FS_PL_END_MISMATCH_EXT_INFO_95_64)));
+	pr_info("CDM%d FS_PL_END_MISMATCH_EXT_INFO[127:96]  = %08x\n", id + 1,
+		mtk_gdm_dbg_out(eth, FE_CDM_DBG_CTRL(id), CDM_DBG_IDX_MASK,
+				FIELD_PREP(CDM_DBG_IDX_MASK,
+					   FS_PL_END_MISMATCH_EXT_INFO_127_96)));
+	pr_info("CDM%d FS_PL_END_MISMATCH_EXT_INFO[159:128] = %08x\n", id + 1,
+		mtk_gdm_dbg_out(eth, FE_CDM_DBG_CTRL(id), CDM_DBG_IDX_MASK,
+				FIELD_PREP(CDM_DBG_IDX_MASK,
+					   FS_PL_END_MISMATCH_EXT_INFO_159_128)));
+	pr_info("CDM%d FS_PL_END_MISMATCH_EXT_INFO[161:160] = %08x\n", id + 1,
+		mtk_gdm_dbg_out(eth, FE_CDM_DBG_CTRL(id), CDM_DBG_IDX_MASK,
+				FIELD_PREP(CDM_DBG_IDX_MASK,
+					   FS_PL_END_MISMATCH_EXT_INFO_161_160)));
+	pr_info("CDM%d FS_PL_END_MISMATCH_LINK_LIST_INDEX = %08x\n", id + 1,
+		mtk_gdm_dbg_out(eth, FE_CDM_DBG_CTRL(id), CDM_DBG_IDX_MASK,
+				FIELD_PREP(CDM_DBG_IDX_MASK,
+					   FS_PL_END_MISMATCH_LINK_LIST_INDEX)));
+	pr_info("====================================================");
+}
+
 irqreturn_t mtk_handle_fe_irq(int irq, void *_eth)
 {
 	struct mtk_eth *eth = _eth;
 	u32 status = 0, val = 0;
+	int i;
 
 	status = mtk_r32(eth, MTK_FE_INT_STATUS);
 	pr_info("[%s] Trigger FE Misc ISR: 0x%x\n", __func__, status);
@@ -241,6 +420,66 @@
 	}
 	mtk_w32(eth, 0xFFFFFFFF, MTK_FE_INT_STATUS);
 
+	if (eth->soc->caps == MT7987_CAPS) {
+		bool pl_end_error = false;
+
+		/* handle GDM/CDM l3len_over_run and pl_end_error */
+		status = mtk_r32(eth, MTK_FE_PINFO_INT_STATUS);
+		for (i = 0; i < 3; i++) {
+			if (status & MTK_GDM_L3LEN_OVER_RUN(i))
+				pr_warn("[%s] Detect GDM%d L3 length over run !",
+					__func__, i + 1);
+			if (status & MTK_GDM_PL_END_ERR(i)) {
+				pr_warn("[%s] Detect GDM%d packet end page error !",
+					__func__, i + 1);
+				mtk_gdm_pl_end_page_error(eth, i);
+				pl_end_error = true;
+			}
+		}
+		for (i = 0; i < 9; i++) {
+			if (status & MTK_CDM_L3LEN_OVER_RUN(i))
+				pr_warn("[%s] Detect CDM%d L3 length over run !",
+					__func__, i + 1);
+			if (status & MTK_CDM_PL_END_ERR(i)) {
+				pr_warn("[%s] Detect CDM%d packet end page error !",
+					__func__, i + 1);
+				if (i >= 2)
+					mtk_cdm_v3_pl_end_page_error(eth, i);
+				else
+					mtk_cdm_v2_pl_end_page_error(eth, i);
+				pl_end_error = true;
+			}
+		}
+		mtk_w32(eth, status, MTK_FE_PINFO_INT_STATUS);
+
+		/* handle GDM/CDM page_num_mismatch and runt_pkt_error */
+		status = mtk_r32(eth, FE_CGDM_INT3);
+		for (i = 0; i < 3; i++) {
+			if (status & FE_GDM_PAGE_MISMATCH(i))
+				pr_warn("[%s] Detect GDM%d page number mismatch !",
+					__func__, i + 1);
+		}
+		for (i = 0; i < 9; i++) {
+			if (status & FE_CDM_PAGE_MISMATCH(i))
+				pr_warn("[%s] Detect CDM%d page number mismatch !",
+					__func__, i + 1);
+			if (status & FE_CDM_RUNT_PACKET(i))
+				pr_warn("[%s] Detect CDM%d runt packet error !",
+					__func__, i + 1);
+		}
+		mtk_w32(eth, status, FE_CGDM_INT3);
+
+		if (pl_end_error) {
+			if (!test_bit(MTK_RESETTING, &eth->state)) {
+				/* disable GDM and GDM packet end page error interrupt */
+				mtk_w32(eth, 0x0000ffff, MTK_FE_PINFO_INT_ENABLE);
+				/* trigger an SER to let PSE go back to work normally */
+				atomic_inc(&force);
+				schedule_work(&eth->pending_work);
+			}
+		}
+	}
+
 	return IRQ_HANDLED;
 }
 
diff --git a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index 863288e..970ff66 100644
--- a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -4774,6 +4774,23 @@
 			/* GDM and CDM Threshold */
 			mtk_w32(eth, 0x08000707, MTK_CDMW0_THRES);
 			mtk_w32(eth, 0x00000077, MTK_CDMW1_THRES);
+		} else if (eth->soc->caps == MT7987_CAPS) {
+			/* enable PSE info error interrupt */
+			mtk_w32(eth, 0x00ffffff, MTK_FE_PINFO_INT_ENABLE);
+			/* enable CDMP l3_len_ov_drop */
+			mtk_m32(eth, MTK_CDMP_L3_LEN_OV_DROP,
+				MTK_CDMP_L3_LEN_OV_DROP, MTK_CDMP_IG_CTRL);
+			/* enable CDMQ l3_len_ov_drop */
+			mtk_m32(eth, MTK_CDMQ_L3_LEN_OV_DROP,
+				MTK_CDMQ_L3_LEN_OV_DROP, MTK_CDMQ_IG_CTRL);
+			/* enable CDMW0 l3_len_ov_drop */
+			mtk_m32(eth, MTK_CDMW0_L3_LEN_OV_DROP,
+				MTK_CDMW0_L3_LEN_OV_DROP, MTK_CDMW0_IG_CTRL);
+			/* disable GDM page_num_mismatch_det */
+			for (i = 0; i < 3; i++) {
+				mtk_m32(eth, GDM_PAGE_MISMATCH_DET, 0,
+					FE_GDM_DBG_CTRL(i));
+			}
 		}
 
 		if (MTK_HAS_CAPS(eth->soc->caps, MTK_ESW)) {
diff --git a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h
index 576246d..e0623a4 100644
--- a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -109,17 +109,31 @@
 /* Frame Engine Interrupt Grouping Register */
 #define MTK_FE_INT_GRP		0x20
 
+/* PSE Error Interrupt Status Register */
+#define MTK_FE_PINFO_INT_ENABLE	0x58
+#define MTK_FE_PINFO_INT_STATUS	0x5c
+#define MTK_CDM_PL_END_ERR(x)		BIT((x) + 15)
+#define MTK_GDM_PL_END_ERR(x)		BIT((x) + 12)
+#define MTK_CDM_L3LEN_OVER_RUN(x)	BIT((x) + 3)
+#define MTK_GDM_L3LEN_OVER_RUN(x)	BIT((x))
+
 /* Frame Engine LRO auto-learn table info */
 #define MTK_FE_ALT_CF8		0x300
 #define MTK_FE_ALT_SGL_CFC	0x304
 #define MTK_FE_ALT_SEQ_CFC	0x308
 
-/* CDMP Ingress Control Register */
+/* CDMW Ingress Control Register */
+#define MTK_CDMW0_IG_CTRL	0x1600
+#define MTK_CDMW0_L3_LEN_OV_DROP	BIT(1)
+
+/* CDMQ Ingress Control Register */
 #define MTK_CDMQ_IG_CTRL	0x1400
+#define MTK_CDMQ_L3_LEN_OV_DROP	BIT(2)
 #define MTK_CDMQ_STAG_EN	BIT(0)
 
 /* CDMP Ingress Control Register */
 #define MTK_CDMP_IG_CTRL	0x400
+#define MTK_CDMP_L3_LEN_OV_DROP	BIT(2)
 #define MTK_CDMP_STAG_EN	BIT(0)
 
 /* CDMP Exgress Control Register */
@@ -176,6 +190,19 @@
 /* PSE Output Queue Threshold Register*/
 #define PSE_OQ_TH(x)		(0x160 + ((x - 1) * 0x4))
 
+/* GDM and CDM Debug Control */
+#define FE_CDM_DBG_CTRL(x)	(0x38c + ((x) * 0x8))
+#define CDM_DBG_IDX_MASK	GENMASK(5, 0)
+
+#define FE_GDM_DBG_CTRL(x)	(0x3e0 + ((x) * 0x8))
+#define GDM_DBG_IDX_MASK	GENMASK(5, 1)
+#define GDM_PAGE_MISMATCH_DET	BIT(9)
+
+#define FE_CGDM_INT3		(0x3fc)
+#define FE_CDM_RUNT_PACKET(x)	BIT(22 - (x))
+#define FE_CDM_PAGE_MISMATCH(x)	BIT(11 - (x))
+#define FE_GDM_PAGE_MISMATCH(x)	BIT(2 - (x))
+
 /* GDM and CDM Threshold */
 #define MTK_GDM2_THRES		0x1530
 #define MTK_CDM2_THRES		0x1534