[][kernel][common][eth][Fix issue with XGDM hang when reconnecting SFP+ Optical module]
[Description]
Fix issue with XGDM hang when reconnecting SFP+ Optical module.
This patch corrects the down/up sequence of the XGAMC link and adds a
delay between the USXGMII PCS link up and the XGMAC link up to avoid
runt packet issues.
Without this patch, the users may encounter a traffic stuck issue when
reconnecting the SFP+ optical module.
[Release-log]
N/A
Change-Id: I3981638e9be270ae8256cdc4070c319c6cc80e8b
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/8269169
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 bad8511..05bf2d7 100644
--- 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
@@ -444,7 +444,7 @@
/* Force Port1 XGMAC Link Up */
val = mtk_r32(eth, MTK_XGMAC_STS(MTK_GMAC1_ID));
- mtk_w32(eth, val | MTK_XGMAC_FORCE_LINK(MTK_GMAC1_ID),
+ mtk_w32(eth, val | MTK_XGMAC_FORCE_MODE(MTK_GMAC1_ID),
MTK_XGMAC_STS(MTK_GMAC1_ID));
/* Adjust GSW bridge IPG to 11*/
@@ -573,6 +573,28 @@
return NULL;
}
+static int mtk_mac_prepare(struct phylink_config *config, unsigned int mode,
+ phy_interface_t iface)
+{
+ struct mtk_mac *mac = container_of(config, struct mtk_mac,
+ phylink_config);
+ u32 val;
+
+ if (mac->type == MTK_XGDM_TYPE && mac->id != MTK_GMAC1_ID) {
+ val = mtk_r32(mac->hw, MTK_XMAC_MCR(mac->id));
+ val &= 0xfffffff0;
+ val |= XMAC_MCR_TRX_DISABLE;
+ mtk_w32(mac->hw, val, MTK_XMAC_MCR(mac->id));
+
+ val = mtk_r32(mac->hw, MTK_XGMAC_STS(mac->id));
+ val |= MTK_XGMAC_FORCE_MODE(mac->id);
+ val &= ~MTK_XGMAC_FORCE_LINK(mac->id);
+ mtk_w32(mac->hw, val, MTK_XGMAC_STS(mac->id));
+ }
+
+ return 0;
+}
+
static void mtk_mac_config(struct phylink_config *config, unsigned int mode,
const struct phylink_link_state *state)
{
@@ -997,7 +1019,7 @@
{
struct mtk_mac *mac = container_of(config, struct mtk_mac,
phylink_config);
- u32 mcr, mcr_cur, sts, force_link;
+ u32 mcr, mcr_cur, sts;
mac->speed = speed;
@@ -1043,27 +1065,17 @@
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) {
+ if (mode == MLO_AN_INBAND)
+ mdelay(1000);
+
/* 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;
- }
+ 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));
mcr = mtk_r32(mac->hw, MTK_XMAC_MCR(mac->id));
@@ -1221,6 +1233,7 @@
.validate = mtk_validate,
.mac_select_pcs = mtk_mac_select_pcs,
.mac_link_state = mtk_mac_pcs_get_state,
+ .mac_prepare = mtk_mac_prepare,
.mac_config = mtk_mac_config,
.mac_finish = mtk_mac_finish,
.mac_link_down = mtk_mac_link_down,
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 7811de7..566bb21 100644
--- 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
@@ -676,7 +676,8 @@
/* XMAC status registers */
#define MTK_XGMAC_STS(x) ((x == MTK_GMAC3_ID) ? 0x1001C : 0x1000C)
-#define MTK_XGMAC_FORCE_LINK(x) ((x == MTK_GMAC2_ID) ? BIT(31) : BIT(15))
+#define MTK_XGMAC_FORCE_MODE(x) ((x == MTK_GMAC2_ID) ? BIT(31) : BIT(15))
+#define MTK_XGMAC_FORCE_LINK(x) ((x == MTK_GMAC2_ID) ? BIT(27) : BIT(11))
#define MTK_USXGMII_PCS_LINK BIT(8)
#define MTK_XGMAC_RX_FC BIT(5)
#define MTK_XGMAC_TX_FC BIT(4)
@@ -1733,6 +1734,7 @@
struct regmap *regmap;
struct regmap *regmap_pextp;
struct delayed_work link_poll;
+ struct completion link_poll_completion;
phy_interface_t interface;
unsigned int mode;
u8 id;
diff --git a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_usxgmii.c b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_usxgmii.c
index 0cadc85..bcfe750 100644
--- a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_usxgmii.c
+++ b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_usxgmii.c
@@ -757,6 +757,8 @@
queue_delayed_work(system_power_efficient_wq, &mpcs->link_poll,
msecs_to_jiffies(1000));
}
+
+ complete(&mpcs->link_poll_completion);
}
static void mtk_usxgmii_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode,
@@ -771,8 +773,14 @@
mtk_usxgmii_pcs_config(pcs, mode,
interface, NULL, false);
+ reinit_completion(&mpcs->link_poll_completion);
+
queue_delayed_work(system_power_efficient_wq, &mpcs->link_poll,
msecs_to_jiffies(1000));
+
+ if (!wait_for_completion_timeout(&mpcs->link_poll_completion,
+ msecs_to_jiffies(3000)))
+ pr_warn("%s wait link poll complete timeout!\n", __func__);
}
static const struct phylink_pcs_ops mtk_usxgmii_pcs_ops = {
@@ -804,6 +812,7 @@
ss->pcs[i].pcs.poll = true;
ss->pcs[i].interface = PHY_INTERFACE_MODE_NA;
+ init_completion(&ss->pcs[i].link_poll_completion);
INIT_DELAYED_WORK(&ss->pcs[i].link_poll, mtk_usxgmii_link_poll);
of_node_put(np);