[][kernel][common][eth][Refactor heartbeat check for Aquantia firwmare download]
[Description]
Refactor heartbeat check for Aquantia firwmare download.
- Simplify heartbeat check function.
- Remove unnecessary gangload_lock.
- Add PHY power down check in the aqr_firmware_download_cb().
If without this patch, kernel might encounter self-detected stall issue
during SER burnin test.
[Release-log]
N/A
Change-Id: I5c6f24133c9ada6b1dffb8e1d74281db5944fbb3
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/7281418
diff --git a/target/linux/mediatek/patches-5.4/751-net-phy-aquantia-add-firmware-download.patch b/target/linux/mediatek/patches-5.4/751-net-phy-aquantia-add-firmware-download.patch
index 2fe3132..7a9f229 100644
--- a/target/linux/mediatek/patches-5.4/751-net-phy-aquantia-add-firmware-download.patch
+++ b/target/linux/mediatek/patches-5.4/751-net-phy-aquantia-add-firmware-download.patch
@@ -77,7 +77,7 @@
index 5a16caa..912bbe6 100644
--- a/drivers/net/phy/aquantia.h
+++ b/drivers/net/phy/aquantia.h
-@@ -9,8 +9,65 @@
+@@ -9,8 +9,66 @@
#include <linux/device.h>
#include <linux/phy.h>
@@ -121,9 +121,10 @@
+ u64 sgmii_stats[AQR107_SGMII_STAT_SZ];
+#ifdef CONFIG_AQUANTIA_PHY_FW_DOWNLOAD
+ struct phy_device *phydevs[1];
-+ struct task_struct *heartbeat;
++ struct task_struct *heartbeat_thread;
+ bool fw_initialized;
+ int fw_dl_mode;
++ u16 heartbeat;
+#endif
+};
+
@@ -295,7 +296,6 @@
+struct task_struct *gangload_kthread = NULL;
+struct phy_device *gangload_phydevs[MAX_GANGLOAD_DEVICES];
+static int gangload = 0;
-+static DEFINE_SPINLOCK(gangload_lock);
+
+static int aqr_firmware_download_single(struct phy_device *phydev);
+
@@ -1030,40 +1030,37 @@
+
+static int aqr_firmware_check_heartbeat(struct phy_device *phydev)
+{
-+ int prev, cur, ret;
-+
-+ ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_RSVD_STAT2);
-+ if (ret < 0)
-+ return ret;
-+
-+ prev = ret;
-+
-+ msleep(1500);
++ struct aqr107_priv *priv = phydev->priv;
++ int stopped = 0, ret;
+
+ ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_RSVD_STAT2);
+ if (ret < 0)
+ return ret;
+
-+ cur = ret;
++ if (priv->heartbeat == ret)
++ stopped = 1;
+
-+ if (prev == cur)
-+ return 1;
++ priv->heartbeat = ret;
+
-+ return 0;
++ return stopped;
+}
+
+static int aqr_firmware_heartbeat_thread(void *data)
+{
+ struct phy_device *phydev = data;
+ struct aqr107_priv *priv = phydev->priv;
++ struct device *dev;
+ int ret = 0;
+
++ dev = &phydev->mdio.dev;
++
+ for (;;) {
+ if (kthread_should_stop())
+ break;
+
+ if (phydev->state != PHY_HALTED &&
+ aqr_firmware_check_heartbeat(phydev) == 1) {
++ dev_err(dev, "Detect heartbeat stopped, start to realod firmware...\n");
+ priv->fw_initialized = false;
+ aqr_firmware_download_single(phydev);
+ }
@@ -1087,12 +1084,16 @@
+ if (!fw)
+ return;
+
-+ spin_lock(&gangload_lock);
-+
+ num_phydevs = priv->fw_dl_mode == FW_DL_GNAGLOAD ?
+ MAX_GANGLOAD_DEVICES : 1;
+
+retry:
++ if (gandload_phydev->state == PHY_HALTED) {
++ dev = &phydevs[0]->mdio.dev;
++ dev_info(dev, "Detect PHY power down, stop to reload firmware...\n");
++ goto out;
++ }
++
+ memset(result, 0, sizeof(result));
+
+ ret = AQ_API_WriteBootLoadImage(phydevs, num_phydevs, gandload_phydev,
@@ -1126,24 +1127,22 @@
+ phy_queue_state_machine(phydevs[i], 0);
+ }
+
-+ /* create a thread for monitor heartbeats status */
-+ if (!priv->heartbeat) {
-+ priv->heartbeat = kthread_create(aqr_firmware_heartbeat_thread,
-+ phydevs[i],
-+ "aqr_firmware_heartbeat_thread");
-+ if (IS_ERR(priv->heartbeat)) {
++ /* create a thread for monitor heartbeat status */
++ if (!priv->heartbeat_thread) {
++ priv->heartbeat_thread = kthread_create(aqr_firmware_heartbeat_thread,
++ phydevs[i],
++ "aqr_firmware_heartbeat_thread");
++ if (IS_ERR(priv->heartbeat_thread)) {
+ dev_err(dev,
+ "%s Failed to create thread for aqr_firmware_heartbeat_thread\n",
+ __func__);
+ }
-+ wake_up_process(priv->heartbeat);
++ wake_up_process(priv->heartbeat_thread);
+ }
+ }
+ }
-+
++out:
+ release_firmware(fw);
-+
-+ spin_unlock(&gangload_lock);
+}
+
+static int aqr_firmware_download_single(struct phy_device *phydev)
@@ -1158,6 +1157,7 @@
+
+ priv->fw_dl_mode = FW_DL_SINGLE;
+ priv->phydevs[0] = phydev;
++ priv->heartbeat = -1;
+
+ ret = request_firmware(&fw, AQR_FIRMWARE, dev);
+ if (ret) {
@@ -1229,6 +1229,7 @@
+ }
+
+ priv->fw_dl_mode = FW_DL_GNAGLOAD;
++ priv->heartbeat = -1;
+ gangload_phydevs[gangload] = phydev;
+ gangload++;
+
@@ -1350,7 +1351,7 @@
+#ifdef CONFIG_AQUANTIA_PHY_FW_DOWNLOAD
+ struct aqr107_priv *priv = phydev->priv;
+
-+ kthread_stop(priv->heartbeat);
++ kthread_stop(priv->heartbeat_thread);
+#endif
+}
+