[][kernel][common][eth][Update firmware download feature for the Aquantia PHY driver]

[Description]
Refactor firmware download feature for the Aquantia PHY driver.
  - Align "Retry Attempts before Downshift" setting with bypass
    firmware loading method.
  - Change create/destroy condition for the heartbeat check thread.
  - Fix Pasue/Asym Pause loss issue when recovering firmware by the
    hearbeat check thread.
  - Add a check condition for the firmware loading, the driver will
    bypass firmware loading if RFB attached a 10G PHY Flash.

If without this patch, the setting of the 10G PHY may differ from the
bypass firmware loading method.

[Release-log]
N/A


Change-Id: I245da3b0e5b7299b42473c20cc6f0899cfff5bd3
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/7508809
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 28248f4..f6e0f95 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
@@ -74,13 +74,15 @@
  obj-$(CONFIG_AIROHA_EN8801SC_PHY)	+= en8801sc.o
  obj-$(CONFIG_AQUANTIA_PHY)	+= aquantia.o
 diff --git a/drivers/net/phy/aquantia.h b/drivers/net/phy/aquantia.h
-index 5a16caa..912bbe6 100644
+index 5a16caa..ab1c241 100644
 --- a/drivers/net/phy/aquantia.h
 +++ b/drivers/net/phy/aquantia.h
-@@ -9,8 +9,66 @@
+@@ -9,8 +9,72 @@
  #include <linux/device.h>
  #include <linux/phy.h>
  
++#define MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT		4
++
 +#define PMAPMD_RSVD_VEND_PROV				0xe400
 +#define PMAPMD_RSVD_VEND_PROV_MDI_CONF			BIT(0)
 +
@@ -122,12 +124,15 @@
 +#ifdef CONFIG_AQUANTIA_PHY_FW_DOWNLOAD
 +	struct phy_device *phydevs[1];
 +	struct task_struct *heartbeat_thread;
++	spinlock_t lock;
 +	bool fw_initialized;
 +	int fw_dl_mode;
 +	u16 heartbeat;
 +#endif
 +};
 +
++int aqr107_set_downshift(struct phy_device *phydev, u8 cnt);
++void aqr107_chip_info(struct phy_device *phydev);
 +int aqr107_config_mdi(struct phy_device *phydev);
 +
  #if IS_REACHABLE(CONFIG_HWMON)
@@ -142,14 +147,15 @@
 +	FW_DL_GNAGLOAD,
 +};
 +
++int aqr_firmware_heartbeat_thread(void *data);
 +int aqr_firmware_download(struct phy_device *phydev);
 +#endif
 diff --git a/drivers/net/phy/aquantia_firmware.c b/drivers/net/phy/aquantia_firmware.c
 new file mode 100644
-index 0000000..7aeec86
+index 0000000..622557c
 --- /dev/null
 +++ b/drivers/net/phy/aquantia_firmware.c
-@@ -0,0 +1,1096 @@
+@@ -0,0 +1,1092 @@
 +// SPDX-License-Identifier: GPL-2.0
 +/* FW download driver for Aquantia PHY
 + */
@@ -1037,15 +1043,17 @@
 +	if (ret < 0)
 +		return ret;
 +
++	/* heartbeat stopped if the current heartbeat is equal to the previous */
 +	if (priv->heartbeat == ret)
 +		stopped = 1;
 +
++	/* update heartbeat to the private data */
 +	priv->heartbeat = ret;
 +
 +	return stopped;
 +}
 +
-+static int aqr_firmware_heartbeat_thread(void *data)
++int aqr_firmware_heartbeat_thread(void *data)
 +{
 +	struct phy_device *phydev = data;
 +	struct aqr107_priv *priv = phydev->priv;
@@ -1058,10 +1066,11 @@
 +		if (kthread_should_stop())
 +			break;
 +
-+		if (phydev->state != PHY_HALTED &&
++		if (priv->fw_initialized == true &&
 +		    aqr_firmware_check_heartbeat(phydev) == 1) {
 +			dev_err(dev, "Detect heartbeat stopped, start to realod firmware...\n");
 +			priv->fw_initialized = false;
++			priv->fw_dl_mode = FW_DL_SINGLE;
 +			aqr_firmware_download_single(phydev);
 +		}
 +
@@ -1076,7 +1085,7 @@
 +{
 +	struct phy_device **phydevs = context;
 +	struct phy_device *gandload_phydev = phydevs[0];
-+	struct device *dev;
++	struct device *dev = &phydevs[0]->mdio.dev;
 +	struct aqr107_priv *priv = phydevs[0]->priv;
 +	int result[MAX_GANGLOAD_DEVICES];
 +	int i, num_phydevs = 0, ret = 0;
@@ -1089,7 +1098,6 @@
 +
 +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;
 +	}
@@ -1115,30 +1123,23 @@
 +
 +	for (i = 0; i < num_phydevs; i++) {
 +		if (result[i] == 0) {
++			dev = &phydevs[i]->mdio.dev;
 +			priv = phydevs[i]->priv;
 +			priv->fw_initialized = true;
 +
++			aqr107_chip_info(phydevs[i]);
++
 +#ifdef CONFIG_AQUANTIA_PHY_MDI_SWAP
 +			aqr107_config_mdi(phydevs[i]);
 +#endif
 +
-+			if (priv->fw_dl_mode == FW_DL_GNAGLOAD) {
++			aqr107_set_downshift(phydevs[i],
++					     MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT);
++
++			if (phy_is_started(phydevs[i])) {
 +				phydevs[i]->state = PHY_UP;
 +				phy_queue_state_machine(phydevs[i], 0);
 +			}
-+
-+			/* 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_thread);
-+			}
 +		}
 +	}
 +out:
@@ -1155,13 +1156,14 @@
 +	if (priv->fw_initialized == true)
 +		return 0;
 +
++	spin_lock_init(&priv->lock);
 +	priv->fw_dl_mode = FW_DL_SINGLE;
 +	priv->phydevs[0] = phydev;
 +	priv->heartbeat = -1;
 +
 +	ret = request_firmware(&fw, AQR_FIRMWARE, dev);
 +	if (ret) {
-+		dev_err(dev, "failed to load firmware %s, ret: %d\n",
++		dev_err(dev, "failed to request firmware %s, ret: %d\n",
 +			AQR_FIRMWARE, ret);
 +	}
 +
@@ -1185,7 +1187,7 @@
 +			ret = request_firmware_nowait(THIS_MODULE, true, AQR_FIRMWARE, dev,
 +						      GFP_KERNEL, phydevs, aqr_firmware_download_cb);
 +			if (ret) {
-+				dev_err(dev, "failed to load firmware %s, ret: %d\n",
++				dev_err(dev, "failed to request firmware %s, ret: %d\n",
 +					AQR_FIRMWARE, ret);
 +			}
 +			break;
@@ -1214,8 +1216,7 @@
 +						  "aqr_firmware_gandload_thread");
 +		if (IS_ERR(gangload_kthread)) {
 +			dev_err(dev,
-+				"%s Failed to create thread for aqr_firmware_gandload_thread\n",
-+				__func__);
++				"failed to create aqr_firmware_gandload_thread\n");
 +			return PTR_ERR(gangload_kthread);
 +		}
 +		wake_up_process(gangload_kthread);
@@ -1223,11 +1224,12 @@
 +
 +	for (i = 0; i < gangload; i++) {
 +		if (gangload_phydevs[i] == phydev) {
-+			dev_err(dev, "Detect duplicate gangload phydev\n");
++			dev_warn(dev, "Detect duplicate gangload phydev\n");
 +			return -EINVAL;
 +		}
 +	}
 +
++	spin_lock_init(&priv->lock);
 +	priv->fw_dl_mode = FW_DL_GNAGLOAD;
 +	priv->heartbeat = -1;
 +	gangload_phydevs[gangload] = phydev;
@@ -1247,17 +1249,25 @@
 +	return ret;
 +}
 diff --git a/drivers/net/phy/aquantia_main.c b/drivers/net/phy/aquantia_main.c
-index ac8dd8e..421cdd3 100644
+index a8c828b..d98757f 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>
+@@ -39,7 +40,6 @@
+ #define MDIO_AN_VEND_PROV_2500BASET_FULL	BIT(10)
+ #define MDIO_AN_VEND_PROV_DOWNSHIFT_EN		BIT(4)
+ #define MDIO_AN_VEND_PROV_DOWNSHIFT_MASK	GENMASK(3, 0)
+-#define MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT	4
+ 
+ #define MDIO_AN_TX_VEND_STATUS1			0xc800
+ #define MDIO_AN_TX_VEND_STATUS1_RATE_MASK	GENMASK(3, 1)
 @@ -73,18 +73,6 @@
  #define MDIO_AN_RX_VEND_STAT3			0xe832
  #define MDIO_AN_RX_VEND_STAT3_AFR		BIT(0)
@@ -1309,7 +1319,25 @@
  static int aqr107_get_sset_count(struct phy_device *phydev)
  {
  	return AQR107_SGMII_STAT_SZ;
-@@ -498,6 +461,17 @@ static void aqr107_chip_info(struct phy_device *phydev)
+@@ -422,7 +361,7 @@ static int aqr107_get_downshift(struct phy_device *phydev, u8 *data)
+ 	return 0;
+ }
+ 
+-static int aqr107_set_downshift(struct phy_device *phydev, u8 cnt)
++int aqr107_set_downshift(struct phy_device *phydev, u8 cnt)
+ {
+ 	int val = 0;
+ 
+@@ -482,7 +421,7 @@ static int aqr107_wait_reset_complete(struct phy_device *phydev)
+ 	return val ? 0 : -ETIMEDOUT;
+ }
+ 
+-static void aqr107_chip_info(struct phy_device *phydev)
++void aqr107_chip_info(struct phy_device *phydev)
+ {
+ 	u8 fw_major, fw_minor, build_id, prov_id;
+ 	int val;
+@@ -505,6 +444,17 @@ static void aqr107_chip_info(struct phy_device *phydev)
  		   fw_major, fw_minor, build_id, prov_id);
  }
  
@@ -1327,42 +1355,58 @@
  static int aqr107_config_init(struct phy_device *phydev)
  {
  	int ret;
-@@ -517,6 +491,14 @@ static int aqr107_config_init(struct phy_device *phydev)
+@@ -520,6 +470,14 @@ static int aqr107_config_init(struct phy_device *phydev)
+ 	ret = aqr107_wait_reset_complete(phydev);
  	if (!ret)
  		aqr107_chip_info(phydev);
- 
-+#if !defined(CONFIG_AQUANTIA_PHY_FW_DOWNLOAD) && defined(CONFIG_AQUANTIA_PHY_MDI_SWAP)
-+	aqr107_config_mdi(phydev);
-+#endif
-+
 +#ifdef CONFIG_AQUANTIA_PHY_FW_DOWNLOAD
-+	aqr_firmware_download(phydev);
++	else
++		return aqr_firmware_download(phydev);
 +#endif
 +
++#ifdef CONFIG_AQUANTIA_PHY_MDI_SWAP
++	aqr107_config_mdi(phydev);
++#endif
+ 
  	return aqr107_set_downshift(phydev, MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT);
  }
+@@ -604,12 +556,39 @@ static void aqr107_link_change_notify(struct phy_device *phydev)
  
-@@ -605,6 +609,15 @@ static int aqr107_resume(struct phy_device *phydev)
- 				  MDIO_CTRL1_LPOWER);
- }
-
-+static void aqr107_remove(struct phy_device *phydev)
-+{
+ static int aqr107_suspend(struct phy_device *phydev)
+ {
 +#ifdef CONFIG_AQUANTIA_PHY_FW_DOWNLOAD
 +	struct aqr107_priv *priv = phydev->priv;
 +
-+	kthread_stop(priv->heartbeat_thread);
++	spin_lock(&priv->lock);
++	if (priv->heartbeat_thread) {
++		kthread_stop(priv->heartbeat_thread);
++		priv->heartbeat_thread = NULL;
++		priv->heartbeat = -1;
++	}
++	spin_unlock(&priv->lock);
 +#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,
- },
- };
+ 	return phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MDIO_CTRL1,
+ 				MDIO_CTRL1_LPOWER);
+ }
  
+ static int aqr107_resume(struct phy_device *phydev)
+ {
++#ifdef CONFIG_AQUANTIA_PHY_FW_DOWNLOAD
++	struct aqr107_priv *priv = phydev->priv;
++
++	spin_lock(&priv->lock);
++	if (!priv->heartbeat_thread) {
++		priv->heartbeat_thread = kthread_create(aqr_firmware_heartbeat_thread,
++							phydev,
++							"aqr_firmware_heartbeat_thread");
++		if (IS_ERR(priv->heartbeat_thread)) {
++			phydev_err(phydev,
++				   "Failed to create aqr_firmware_heartbeat_thread\n");
++		}
++		wake_up_process(priv->heartbeat_thread);
++	}
++	spin_unlock(&priv->lock);
++#endif
+ 	return phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MDIO_CTRL1,
+ 				  MDIO_CTRL1_LPOWER);
+ }