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