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