[][kernel][common][eth][Add heartbeat check for Aquantia firwmare download]

[Description]
Add heartbeat check for Aquantia firwmare download.

AQR113C will reset whole chip including firmware when detect EMC,
then cause uP's heartbeat stopped.
Therefore, we have to re-download firmware to handle this error case.

If without this patch, AQR113C will not working anymore after detect EMC.

[Release-log]
N/A


Change-Id: Ib83a9ac354c12ab5a303b49696826b74460fe740
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/7060741
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 a132dfe..f568322 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,64 @@
+@@ -9,8 +9,65 @@
  #include <linux/device.h>
  #include <linux/phy.h>
  
@@ -121,6 +121,7 @@
 +	u64 sgmii_stats[AQR107_SGMII_STAT_SZ];
 +#ifdef CONFIG_AQUANTIA_PHY_FW_DOWNLOAD
 +	struct phy_device *phydevs[1];
++	struct task_struct *heartbeat;
 +	bool fw_initialized;
 +	int fw_dl_mode;
 +#endif
@@ -147,7 +148,7 @@
 index 0000000..7aeec86
 --- /dev/null
 +++ b/drivers/net/phy/aquantia_firmware.c
-@@ -0,0 +1,1032 @@
+@@ -0,0 +1,1095 @@
 +// SPDX-License-Identifier: GPL-2.0
 +/* FW download driver for Aquantia PHY
 + */
@@ -216,6 +217,8 @@
 +#define VEND1_RSVD_PROV2_DAISYCHAIN_HOPCOUNT		GENMASK(5, 0)
 +#define VEND1_RSVD_PROV2_DAISYCHAIN_HOPCOUNT_OVERRIDE	BIT(6)
 +
++#define VEND1_GLOBAL_RSVD_STAT2				0xc886
++
 +/*! The byte address, in processor memory, of the start of the IRAM segment. */
 +#define AQ_IRAM_BASE_ADDRESS				0x40000000
 +
@@ -294,6 +297,8 @@
 +static int gangload = 0;
 +static DEFINE_SPINLOCK(gangload_lock);
 +
++static int aqr_firmware_download_single(struct phy_device *phydev);
++
 +void AQ_API_EnableMDIO_BootLoadMode
 +(
 +	/*! The target PHY port.*/
@@ -1023,6 +1028,52 @@
 +					      NULL, NULL, 0);
 +}
 +
++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);
++
++	ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_RSVD_STAT2);
++	if (ret < 0)
++		return ret;
++
++	cur = ret;
++
++	if (prev == cur)
++		return 1;
++
++	return 0;
++}
++
++static int aqr_firmware_heartbeat_thread(void *data)
++{
++	struct phy_device *phydev = data;
++	struct aqr107_priv *priv = phydev->priv;
++	int ret = 0;
++
++	for (;;) {
++		if (kthread_should_stop())
++			break;
++
++		if (aqr_firmware_check_heartbeat(phydev) == 1) {
++			priv->fw_initialized = false;
++			aqr_firmware_download_single(phydev);
++		}
++
++		set_current_state(TASK_INTERRUPTIBLE);
++		schedule_timeout(HZ);
++	}
++
++	return ret;
++}
++
 +static void aqr_firmware_download_cb(const struct firmware *fw, void *context)
 +{
 +	struct phy_device **phydevs = context;
@@ -1073,6 +1124,19 @@
 +				phydevs[i]->state = PHY_UP;
 +				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)) {
++					dev_err(dev,
++						"%s Failed to create thread for aqr_firmware_heartbeat_thread\n",
++						__func__);
++				}
++				wake_up_process(priv->heartbeat);
++			}
 +		}
 +	}
 +
@@ -1081,7 +1145,7 @@
 +	spin_unlock(&gangload_lock);
 +}
 +
-+int aqr_firmware_download_single(struct phy_device *phydev)
++static int aqr_firmware_download_single(struct phy_device *phydev)
 +{
 +	struct aqr107_priv *priv = phydev->priv;
 +	struct device *dev = &phydev->mdio.dev;
@@ -1184,6 +1248,14 @@
 index ac8dd8e..421cdd3 100644
 --- a/drivers/net/phy/aquantia_main.c
 +++ b/drivers/net/phy/aquantia_main.c
+@@ -8,6 +8,7 @@
+  */
+
+ #include <linux/kernel.h>
++#include <linux/kthread.h>
+ #include <linux/module.h>
+ #include <linux/delay.h>
+ #include <linux/bitfield.h>
 @@ -73,18 +73,6 @@
  #define MDIO_AN_RX_VEND_STAT3			0xe832
  #define MDIO_AN_RX_VEND_STAT3_AFR		BIT(0)
@@ -1268,3 +1340,27 @@
  	/* ensure that a latched downshift event is cleared */
  	aqr107_read_downshift_event(phydev);
  
+@@ -605,6 +609,15 @@ static int aqr107_resume(struct phy_device *phydev)
+ 				  MDIO_CTRL1_LPOWER);
+ }
+
++static void aqr107_remove(struct phy_device *phydev)
++{
++#ifdef CONFIG_AQUANTIA_PHY_FW_DOWNLOAD
++	struct aqr107_priv *priv = phydev->priv;
++
++	kthread_stop(priv->heartbeat);
++#endif
++}
++
+ static int aqr107_probe(struct phy_device *phydev)
+ {
+ 	phydev->priv = devm_kzalloc(&phydev->mdio.dev,
+@@ -711,6 +737,7 @@ static struct phy_driver aqr_driver[] = {
+ 	.get_strings    = aqr107_get_strings,
+ 	.get_stats      = aqr107_get_stats,
+ 	.link_change_notify = aqr107_link_change_notify,
++	.remove         = aqr107_remove,
+ },
+ };
+