[][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
 +}
 +