@@ -37,6 +37,7 @@ enum hbg_nic_state {
HBG_NIC_STATE_RESETTING,
HBG_NIC_STATE_RESET_FAIL,
HBG_NIC_STATE_NEED_RESET, /* trigger a reset in scheduled task */
+ HBG_NIC_STATE_NP_LINK_FAIL,
};
enum hbg_reset_type {
@@ -82,7 +83,7 @@ enum hbg_hw_event_type {
HBG_HW_EVENT_NONE = 0,
HBG_HW_EVENT_INIT, /* driver is loading */
HBG_HW_EVENT_RESET,
-
+ HBG_HW_EVENT_CORE_RESET,
HBG_HW_EVENT_SERDES_LOOPBACK_ENABLE = 4,
HBG_HW_EVENT_SERDES_LOOPBACK_DISABLE = 5,
};
@@ -257,6 +258,7 @@ struct hbg_stats {
u64 tx_dma_err_cnt;
u64 self_test_rx_pkt_cnt;
+ u64 np_link_fail_cnt;
};
typedef void (*self_test_pkt_recv)(struct net_device *ndev,
@@ -117,6 +117,8 @@ static int hbg_dbg_nic_state(struct seq_file *s, void *unused)
reset_type_str[priv->reset_type]);
seq_printf(s, "need reset state: %s\n",
state_str_true_false(priv, HBG_NIC_STATE_NEED_RESET));
+ seq_printf(s, "np_link fail state: %s\n",
+ state_str_true_false(priv, HBG_NIC_STATE_NP_LINK_FAIL));
return 0;
}
@@ -46,6 +46,16 @@ int hbg_rebuild(struct hbg_priv *priv)
return 0;
}
+int hbg_reset_phy(struct hbg_priv *priv)
+{
+ struct phy_device *phydev = priv->mac.phydev;
+
+ if (phydev->drv->soft_reset)
+ return phydev->drv->soft_reset(phydev);
+
+ return genphy_soft_reset(phydev);
+}
+
static int hbg_reset_prepare(struct hbg_priv *priv, enum hbg_reset_type type)
{
int ret;
@@ -61,12 +71,22 @@ static int hbg_reset_prepare(struct hbg_priv *priv, enum hbg_reset_type type)
priv->reset_type = type;
set_bit(HBG_NIC_STATE_RESETTING, &priv->state);
clear_bit(HBG_NIC_STATE_RESET_FAIL, &priv->state);
- ret = hbg_hw_event_notify(priv, HBG_HW_EVENT_RESET);
+
+ ret = hbg_reset_phy(priv);
if (ret) {
- set_bit(HBG_NIC_STATE_RESET_FAIL, &priv->state);
- clear_bit(HBG_NIC_STATE_RESETTING, &priv->state);
+ dev_err(&priv->pdev->dev, "failed to reset phy\n");
+ goto reset_fail;
}
+ ret = hbg_hw_event_notify(priv, HBG_HW_EVENT_RESET);
+ if (ret)
+ goto reset_fail;
+
+ return 0;
+
+reset_fail:
+ set_bit(HBG_NIC_STATE_RESET_FAIL, &priv->state);
+ clear_bit(HBG_NIC_STATE_RESETTING, &priv->state);
return ret;
}
@@ -17,6 +17,7 @@
*/
#define HBG_ENDIAN_CTRL_LE_DATA_BE 0x0
#define HBG_PCU_FRAME_LEN_PLUS 4
+#define HBG_LINK_FAIL_RETRY_TIMES 5
static bool hbg_hw_spec_is_valid(struct hbg_priv *priv)
{
@@ -217,12 +218,38 @@ void hbg_hw_fill_buffer(struct hbg_priv *priv, u32 buffer_dma_addr)
hbg_reg_write(priv, HBG_REG_RX_CFF_ADDR_ADDR, buffer_dma_addr);
}
-void hbg_hw_adjust_link(struct hbg_priv *priv, u32 speed, u32 duplex)
+int hbg_hw_adjust_link(struct hbg_priv *priv, u32 speed, u32 duplex)
{
+ struct hbg_stats *stats = &priv->stats;
+ int ret;
+
+ clear_bit(HBG_NIC_STATE_NP_LINK_FAIL, &priv->state);
+ hbg_hw_mac_enable(priv, HBG_STATUS_DISABLE);
+
hbg_reg_write_field(priv, HBG_REG_PORT_MODE_ADDR,
HBG_REG_PORT_MODE_M, speed);
hbg_reg_write_field(priv, HBG_REG_DUPLEX_TYPE_ADDR,
HBG_REG_DUPLEX_B, duplex);
+
+ ret = hbg_hw_event_notify(priv, HBG_HW_EVENT_CORE_RESET);
+ if (ret)
+ return ret;
+
+ hbg_hw_mac_enable(priv, HBG_STATUS_ENABLE);
+
+ if (!hbg_reg_read_field(priv, HBG_REG_AN_NEG_STATE_ADDR,
+ HBG_REG_AN_NEG_STATE_NP_LINK_OK_B)) {
+ set_bit(HBG_NIC_STATE_NP_LINK_FAIL, &priv->state);
+
+ stats->np_link_fail_cnt++;
+ if (!(stats->np_link_fail_cnt % HBG_LINK_FAIL_RETRY_TIMES))
+ return -EFAULT;
+
+ return -ENOLINK;
+ }
+
+ stats->np_link_fail_cnt = 0;
+ return 0;
}
/* only support uc filter */
@@ -44,7 +44,7 @@ static inline void hbg_reg_write64(struct hbg_priv *priv, u32 addr, u64 value)
int hbg_hw_event_notify(struct hbg_priv *priv,
enum hbg_hw_event_type event_type);
int hbg_hw_init(struct hbg_priv *priv);
-void hbg_hw_adjust_link(struct hbg_priv *priv, u32 speed, u32 duplex);
+int hbg_hw_adjust_link(struct hbg_priv *priv, u32 speed, u32 duplex);
u32 hbg_hw_get_irq_status(struct hbg_priv *priv);
void hbg_hw_irq_clear(struct hbg_priv *priv, u32 mask);
bool hbg_hw_irq_is_enabled(struct hbg_priv *priv, u32 mask);
@@ -3,6 +3,7 @@
#include <linux/phy.h>
#include "hbg_common.h"
+#include "hbg_err.h"
#include "hbg_hw.h"
#include "hbg_mdio.h"
#include "hbg_reg.h"
@@ -132,6 +133,7 @@ static void hbg_phy_adjust_link(struct net_device *netdev)
struct hbg_priv *priv = netdev_priv(netdev);
struct phy_device *phydev = netdev->phydev;
u32 speed;
+ int ret;
if (phydev->link != priv->mac.link_status) {
if (phydev->link) {
@@ -152,7 +154,16 @@ static void hbg_phy_adjust_link(struct net_device *netdev)
priv->mac.speed = speed;
priv->mac.duplex = phydev->duplex;
priv->mac.autoneg = phydev->autoneg;
- hbg_hw_adjust_link(priv, speed, phydev->duplex);
+ ret = hbg_hw_adjust_link(priv, speed, phydev->duplex);
+ if (ret == -ENOLINK) {
+ dev_err(&priv->pdev->dev,
+ "failed to link between MAC and PHY\n");
+ hbg_reset_phy(priv);
+ } else if (ret == -EFAULT) {
+ dev_err(&priv->pdev->dev,
+ "failed to fix the MAC link status\n");
+ }
+
hbg_flowctrl_cfg(priv);
}
@@ -54,6 +54,7 @@
#define HBG_REG_PAUSE_ENABLE_RX_B BIT(0)
#define HBG_REG_PAUSE_ENABLE_TX_B BIT(1)
#define HBG_REG_AN_NEG_STATE_ADDR (HBG_REG_SGMII_BASE + 0x0058)
+#define HBG_REG_AN_NEG_STATE_NP_LINK_OK_B BIT(15)
#define HBG_REG_TRANSMIT_CTRL_ADDR (HBG_REG_SGMII_BASE + 0x0060)
#define HBG_REG_TRANSMIT_CTRL_PAD_EN_B BIT(7)
#define HBG_REG_TRANSMIT_CTRL_CRC_ADD_B BIT(6)
If the rate changed frequently, the PHY link ok, but the MAC link maybe fails. As a result, the network port is unavailable. According to the documents of the chip, core_reset needs to do to fix the fault. In hw_adjus_link(), the core_reset is added to try to ensure that MAC link status is normal. In addition, MAC link failure detection is added. If the MAC link fails after core_reset, the PHY will reset and re-link up to five times. Signed-off-by: Jijie Shao <shaojijie@huawei.com> --- .../ethernet/hisilicon/hibmcge/hbg_common.h | 4 ++- .../ethernet/hisilicon/hibmcge/hbg_debugfs.c | 2 ++ .../net/ethernet/hisilicon/hibmcge/hbg_err.c | 26 +++++++++++++++-- .../net/ethernet/hisilicon/hibmcge/hbg_hw.c | 29 ++++++++++++++++++- .../net/ethernet/hisilicon/hibmcge/hbg_hw.h | 2 +- .../net/ethernet/hisilicon/hibmcge/hbg_mdio.c | 13 ++++++++- .../net/ethernet/hisilicon/hibmcge/hbg_reg.h | 1 + 7 files changed, 70 insertions(+), 7 deletions(-)