[][kernel][mt7988][eth][Change XGAMC force-link control flow and add XGMAC reset flow]
[Description]
Change XGAMC force-link control flow and add XGMAC reset flow.
After PHY link-down or link-up event,
it will cause noise interference to XGMAC.
These noises will cause XFI counter error.
If the noise is like start-of-frame signal,
it will make XGMAC enter the wrong finite-state.
XGMAC will start to wait for the end-of-frame
but the data buffer is filled with other noises.
When the first packet is receive,
only the end-of-frame signal is preserved,
so the data of the first packet will be lost.
Therefore, we will reset XGMAC after PHY link-up event
and clear all XFI counter values after the reset.
Changing XGMAC force-link flow is to
protect XGDM from being affected when XGMAC resets.
Without this patch, the first packet will be randomly lost after link-up
and the wrong XFI count values will appear.
[Release-log]
N/A
Change-Id: I669d4d6a25fae718966840233bcff9915d25919e
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/7784606
diff --git a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index 0c94e93..353b656 100755
--- a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -586,7 +586,7 @@
phylink_config);
struct mtk_eth *eth = mac->hw;
u32 sid, i;
- int val = 0, ge_mode, force_link, err = 0;
+ int val = 0, ge_mode, err = 0;
unsigned int mac_type = mac->type;
/* MT76x8 has no hardware settings between for the MAC */
@@ -747,43 +747,14 @@
mtk_w32(mac->hw, MAC_MCR_FORCE_LINK_DOWN, MTK_MAC_MCR(mac->id));
if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
- switch (mac->id) {
- case MTK_GMAC1_ID:
+ if (mac->id == MTK_GMAC1_ID)
mtk_setup_bridge_switch(eth);
- break;
- case MTK_GMAC2_ID:
- force_link = (mac->interface ==
- PHY_INTERFACE_MODE_XGMII) ?
- MTK_XGMAC_FORCE_LINK(mac->id) : 0;
- val = mtk_r32(eth, MTK_XGMAC_STS(mac->id));
- mtk_w32(eth, val | force_link,
- MTK_XGMAC_STS(mac->id));
- break;
- case MTK_GMAC3_ID:
- val = mtk_r32(eth, MTK_XGMAC_STS(mac->id));
- mtk_w32(eth,
- val | MTK_XGMAC_FORCE_LINK(mac->id),
- MTK_XGMAC_STS(mac->id));
- break;
- }
}
} else if (mac->type == MTK_GDM_TYPE) {
val = mtk_r32(eth, MTK_GDMA_EG_CTRL(mac->id));
mtk_w32(eth, val & ~MTK_GDMA_XGDM_SEL,
MTK_GDMA_EG_CTRL(mac->id));
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
- switch (mac->id) {
- case MTK_GMAC2_ID:
- case MTK_GMAC3_ID:
- val = mtk_r32(eth, MTK_XGMAC_STS(mac->id));
- mtk_w32(eth,
- val & ~MTK_XGMAC_FORCE_LINK(mac->id),
- MTK_XGMAC_STS(mac->id));
- break;
- }
- }
-
/* FIXME: In current hardware design, we have to reset FE
* when swtiching XGDM to GDM. Therefore, here trigger an SER
* to let GDM go back to the initial state.
@@ -915,7 +886,7 @@
{
struct mtk_mac *mac = container_of(config, struct mtk_mac,
phylink_config);
- u32 mcr;
+ u32 mcr, sts;
if (mac->type == MTK_GDM_TYPE) {
mcr = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id));
@@ -927,6 +898,10 @@
mcr &= 0xfffffff0;
mcr |= XMAC_MCR_TRX_DISABLE;
mtk_w32(mac->hw, mcr, MTK_XMAC_MCR(mac->id));
+
+ 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));
}
}
@@ -936,7 +911,7 @@
{
struct mtk_mac *mac = container_of(config, struct mtk_mac,
phylink_config);
- u32 mcr, mcr_cur;
+ u32 mcr, mcr_cur, sts, force_link;
mac->speed = speed;
@@ -981,6 +956,28 @@
if (mode == MLO_AN_PHY && phy)
mtk_setup_eee(mac, phy_init_eee(phy, false) >= 0);
} else if (mac->type == MTK_XGDM_TYPE && mac->id != MTK_GMAC1_ID) {
+ /* Eliminate the interference(before link-up) caused by PHY noise */
+ mtk_m32(mac->hw, XMAC_LOGIC_RST, 0x0, MTK_XMAC_LOGIC_RST(mac->id));
+ mdelay(20);
+ mtk_m32(mac->hw, XMAC_GLB_CNTCLR, 0x1, MTK_XMAC_CNT_CTRL(mac->id));
+
+ switch (mac->id) {
+ case MTK_GMAC2_ID:
+ force_link = (mac->interface ==
+ PHY_INTERFACE_MODE_XGMII) ?
+ MTK_XGMAC_FORCE_LINK(mac->id) : 0;
+ sts = mtk_r32(mac->hw, MTK_XGMAC_STS(mac->id));
+ mtk_w32(mac->hw, sts | force_link,
+ MTK_XGMAC_STS(mac->id));
+ break;
+ case MTK_GMAC3_ID:
+ sts = mtk_r32(mac->hw, MTK_XGMAC_STS(mac->id));
+ mtk_w32(mac->hw,
+ sts | MTK_XGMAC_FORCE_LINK(mac->id),
+ MTK_XGMAC_STS(mac->id));
+ break;
+ }
+
mcr = mtk_r32(mac->hw, MTK_XMAC_MCR(mac->id));
mcr &= ~(XMAC_MCR_FORCE_TX_FC | XMAC_MCR_FORCE_RX_FC);
diff --git a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h
index fd328e5..57bf7b1 100755
--- a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -699,11 +699,20 @@
#define MAC_MCR_FORCE_LINK_DOWN (MAC_MCR_FORCE_MODE)
/* XFI Mac control registers */
-#define MTK_XMAC_MCR(x) (0x12000 + ((x - 1) * 0x1000))
+#define MTK_XMAC_BASE(x) (0x12000 + ((x - 1) * 0x1000))
+#define MTK_XMAC_MCR(x) (MTK_XMAC_BASE(x))
#define XMAC_MCR_TRX_DISABLE 0xf
#define XMAC_MCR_FORCE_TX_FC BIT(5)
#define XMAC_MCR_FORCE_RX_FC BIT(4)
+/* XFI Mac logic reset registers */
+#define MTK_XMAC_LOGIC_RST(x) (MTK_XMAC_BASE(x) + 0x10)
+#define XMAC_LOGIC_RST BIT(0)
+
+/* XFI Mac count global control */
+#define MTK_XMAC_CNT_CTRL(x) (MTK_XMAC_BASE(x) + 0x100)
+#define XMAC_GLB_CNTCLR BIT(0)
+
/* Mac EEE control registers */
#define MTK_MAC_EEE(x) (0x10104 + (x * 0x100))
#define MAC_EEE_WAKEUP_TIME_1000 GENMASK(31, 24)