Commit ea0fbd05 authored by Gatis Peisenieks's avatar Gatis Peisenieks Committed by David S. Miller

atl1c: improve link detection reliability on Mikrotik 10/25G NIC

Mikrotik 10/25G NIC emulates the MDIO accesses, but the emulation is
not 100% reliable - the MDIO ops occasionally can timeout.

This adds a reliable way of detecting link on Mikrotik 10/25G NIC.
Signed-off-by: default avatarGatis Peisenieks <gatis@mikrotik.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b0390009
...@@ -636,6 +636,23 @@ int atl1c_phy_init(struct atl1c_hw *hw) ...@@ -636,6 +636,23 @@ int atl1c_phy_init(struct atl1c_hw *hw)
return 0; return 0;
} }
bool atl1c_get_link_status(struct atl1c_hw *hw)
{
u16 phy_data;
if (hw->nic_type == athr_mt) {
u32 spd;
AT_READ_REG(hw, REG_MT_SPEED, &spd);
return !!spd;
}
/* MII_BMSR must be read twice */
atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
return !!(phy_data & BMSR_LSTATUS);
}
/* /*
* Detects the current speed and duplex settings of the hardware. * Detects the current speed and duplex settings of the hardware.
* *
...@@ -695,15 +712,12 @@ int atl1c_phy_to_ps_link(struct atl1c_hw *hw) ...@@ -695,15 +712,12 @@ int atl1c_phy_to_ps_link(struct atl1c_hw *hw)
int ret = 0; int ret = 0;
u16 autoneg_advertised = ADVERTISED_10baseT_Half; u16 autoneg_advertised = ADVERTISED_10baseT_Half;
u16 save_autoneg_advertised; u16 save_autoneg_advertised;
u16 phy_data;
u16 mii_lpa_data; u16 mii_lpa_data;
u16 speed = SPEED_0; u16 speed = SPEED_0;
u16 duplex = FULL_DUPLEX; u16 duplex = FULL_DUPLEX;
int i; int i;
atl1c_read_phy_reg(hw, MII_BMSR, &phy_data); if (atl1c_get_link_status(hw)) {
atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
if (phy_data & BMSR_LSTATUS) {
atl1c_read_phy_reg(hw, MII_LPA, &mii_lpa_data); atl1c_read_phy_reg(hw, MII_LPA, &mii_lpa_data);
if (mii_lpa_data & LPA_10FULL) if (mii_lpa_data & LPA_10FULL)
autoneg_advertised = ADVERTISED_10baseT_Full; autoneg_advertised = ADVERTISED_10baseT_Full;
...@@ -726,9 +740,7 @@ int atl1c_phy_to_ps_link(struct atl1c_hw *hw) ...@@ -726,9 +740,7 @@ int atl1c_phy_to_ps_link(struct atl1c_hw *hw)
if (mii_lpa_data) { if (mii_lpa_data) {
for (i = 0; i < AT_SUSPEND_LINK_TIMEOUT; i++) { for (i = 0; i < AT_SUSPEND_LINK_TIMEOUT; i++) {
mdelay(100); mdelay(100);
atl1c_read_phy_reg(hw, MII_BMSR, &phy_data); if (atl1c_get_link_status(hw)) {
atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
if (phy_data & BMSR_LSTATUS) {
if (atl1c_get_speed_and_duplex(hw, &speed, if (atl1c_get_speed_and_duplex(hw, &speed,
&duplex) != 0) &duplex) != 0)
dev_dbg(&pdev->dev, dev_dbg(&pdev->dev,
......
...@@ -26,6 +26,7 @@ void atl1c_phy_disable(struct atl1c_hw *hw); ...@@ -26,6 +26,7 @@ void atl1c_phy_disable(struct atl1c_hw *hw);
void atl1c_hw_set_mac_addr(struct atl1c_hw *hw, u8 *mac_addr); void atl1c_hw_set_mac_addr(struct atl1c_hw *hw, u8 *mac_addr);
int atl1c_phy_reset(struct atl1c_hw *hw); int atl1c_phy_reset(struct atl1c_hw *hw);
int atl1c_read_mac_addr(struct atl1c_hw *hw); int atl1c_read_mac_addr(struct atl1c_hw *hw);
bool atl1c_get_link_status(struct atl1c_hw *hw);
int atl1c_get_speed_and_duplex(struct atl1c_hw *hw, u16 *speed, u16 *duplex); int atl1c_get_speed_and_duplex(struct atl1c_hw *hw, u16 *speed, u16 *duplex);
u32 atl1c_hash_mc_addr(struct atl1c_hw *hw, u8 *mc_addr); u32 atl1c_hash_mc_addr(struct atl1c_hw *hw, u8 *mc_addr);
void atl1c_hash_set(struct atl1c_hw *hw, u32 hash_value); void atl1c_hash_set(struct atl1c_hw *hw, u32 hash_value);
......
...@@ -232,15 +232,14 @@ static void atl1c_check_link_status(struct atl1c_adapter *adapter) ...@@ -232,15 +232,14 @@ static void atl1c_check_link_status(struct atl1c_adapter *adapter)
struct pci_dev *pdev = adapter->pdev; struct pci_dev *pdev = adapter->pdev;
int err; int err;
unsigned long flags; unsigned long flags;
u16 speed, duplex, phy_data; u16 speed, duplex;
bool link;
spin_lock_irqsave(&adapter->mdio_lock, flags); spin_lock_irqsave(&adapter->mdio_lock, flags);
/* MII_BMSR must read twise */ link = atl1c_get_link_status(hw);
atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
spin_unlock_irqrestore(&adapter->mdio_lock, flags); spin_unlock_irqrestore(&adapter->mdio_lock, flags);
if ((phy_data & BMSR_LSTATUS) == 0) { if (!link) {
/* link down */ /* link down */
netif_carrier_off(netdev); netif_carrier_off(netdev);
hw->hibernate = true; hw->hibernate = true;
...@@ -284,16 +283,13 @@ static void atl1c_link_chg_event(struct atl1c_adapter *adapter) ...@@ -284,16 +283,13 @@ static void atl1c_link_chg_event(struct atl1c_adapter *adapter)
{ {
struct net_device *netdev = adapter->netdev; struct net_device *netdev = adapter->netdev;
struct pci_dev *pdev = adapter->pdev; struct pci_dev *pdev = adapter->pdev;
u16 phy_data; bool link;
u16 link_up;
spin_lock(&adapter->mdio_lock); spin_lock(&adapter->mdio_lock);
atl1c_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data); link = atl1c_get_link_status(&adapter->hw);
atl1c_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data);
spin_unlock(&adapter->mdio_lock); spin_unlock(&adapter->mdio_lock);
link_up = phy_data & BMSR_LSTATUS;
/* notify upper layer link down ASAP */ /* notify upper layer link down ASAP */
if (!link_up) { if (!link) {
if (netif_carrier_ok(netdev)) { if (netif_carrier_ok(netdev)) {
/* old link state: Up */ /* old link state: Up */
netif_carrier_off(netdev); netif_carrier_off(netdev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment