Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

igb: Add BCM54616 initialization code for I354 mgmt on Netberg Aurora 420 #76

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
283 changes: 283 additions & 0 deletions patch/0012-igb-setup-Broadcom-54616-PHY-when-no-EEPROM-present.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,283 @@
From 0bd96ca66657b5e05eca6758613be614bee63a77 Mon Sep 17 00:00:00 2001
From: Sergey Popovich <[email protected]>
Date: Tue, 25 Dec 2018 06:54:08 +0000
Subject: igb: Setup Broadcom 54616 PHY when no EEPROM present

While commit eeb0149660a2 ("igb: support BCM54616 PHY") adds basic
support for Broadcom 54616 PHY it does not handle case when EEPROM
is missing.

In that case we need initialize PHY manually by isolating it from
MII interface and providing methods to force speed and duplex.

Behaviour was observed on Netberg Aurora 420 switch management port
that uses igb MAC and Broadcom PHY.

Fixes: commit eeb0149660a2 ("igb: support BCM54616 PHY")
Cc: Jeff Kirsher <[email protected]>
Cc: John W Linville <[email protected]>
Signed-off-by: Sergey Popovich <[email protected]>
---
e1000_82575.c | 12 +++--
e1000_defines.h | 1 +
e1000_phy.c | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
e1000_phy.h | 4 ++
4 files changed, 158 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c
index d9aaa13..19a464d 100644
--- a/drivers/net/ethernet/intel/igb/e1000_82575.c
+++ b/drivers/net/ethernet/intel/igb/e1000_82575.c
@@ -342,6 +342,8 @@ static s32 igb_init_phy_params_82575(struct e1000_hw *hw)
break;
case BCM54616_E_PHY_ID:
phy->type = e1000_phy_bcm54616;
+ phy->ops.get_phy_info = igb_get_phy_info_bcm54xx;
+ phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_bcm54xx;
break;
default:
ret_val = -E1000_ERR_PHY;
@@ -1285,9 +1287,12 @@ static s32 igb_get_cfg_done_82575(struct e1000_hw *hw)
hw_dbg("MNG configuration cycle has not completed.\n");

/* If EEPROM is not marked present, init the PHY manually */
- if (((rd32(E1000_EECD) & E1000_EECD_PRES) == 0) &&
- (hw->phy.type == e1000_phy_igp_3))
- igb_phy_init_script_igp3(hw);
+ if ((rd32(E1000_EECD) & E1000_EECD_PRES) == 0) {
+ if (hw->phy.type == e1000_phy_igp_3)
+ igb_phy_init_script_igp3(hw);
+ else if (hw->phy.type == e1000_phy_bcm54616)
+ igb_phy_init_script_bcm54xx(hw);
+ }

return 0;
}
@@ -1663,6 +1668,7 @@ static s32 igb_setup_copper_link_82575(struct e1000_hw *hw)
ret_val = igb_copper_link_setup_82580(hw);
break;
case e1000_phy_bcm54616:
+ ret_val = igb_copper_link_setup_bcm54xx(hw);
break;
default:
ret_val = -E1000_ERR_PHY;
diff --git a/drivers/net/ethernet/intel/igb/e1000_defines.h b/drivers/net/ethernet/intel/igb/e1000_defines.h
index ce95b7e..2a14819 100644
--- a/drivers/net/ethernet/intel/igb/e1000_defines.h
+++ b/drivers/net/ethernet/intel/igb/e1000_defines.h
@@ -632,6 +632,7 @@
/* PHY Control Register */
#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */
#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */
+#define MII_CR_ISOLATE 0x0400 /* Isolate PHY from MII */
#define MII_CR_POWER_DOWN 0x0800 /* Power down */
#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */
#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */
diff --git a/drivers/net/ethernet/intel/igb/e1000_phy.c b/drivers/net/ethernet/intel/igb/e1000_phy.c
index 2788a54..4c9090a 100644
--- a/drivers/net/ethernet/intel/igb/e1000_phy.c
+++ b/drivers/net/ethernet/intel/igb/e1000_phy.c
@@ -23,6 +23,7 @@

#include <linux/if_ether.h>
#include <linux/delay.h>
+#include <linux/brcmphy.h>

#include "e1000_mac.h"
#include "e1000_phy.h"
@@ -467,6 +468,34 @@ out:
}

/**
+ * igb_copper_link_setup_bcm54xx - Setup BCM54xx PHY for copper link
+ * @hw: pointer to the HW structure
+ *
+ * Sets up copper link.
+ **/
+s32 igb_copper_link_setup_bcm54xx(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val = 0;
+ u16 phy_data;
+
+ if (phy->reset_disable)
+ return 0;
+
+ ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data);
+ if (ret_val)
+ goto out;
+
+ phy_data &= ~(MII_CR_ISOLATE);
+
+ ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data);
+ if (ret_val)
+ goto out;
+out:
+ return ret_val;
+}
+
+/**
* igb_copper_link_setup_82580 - Setup 82580 PHY for copper link
* @hw: pointer to the HW structure
*
@@ -1676,6 +1705,55 @@ s32 igb_phy_has_link(struct e1000_hw *hw, u32 iterations,
}

/**
+ * igb_phy_force_speed_duplex_bcm54xx - Force speed/duplex for BCM54xx PHY
+ * @hw: pointer to the HW structure
+ *
+ * Calls the PHY setup function to force speed and duplex. Waits
+ * for link and returns successful if link up is successful, else
+ * -E1000_ERR_PHY (-2).
+ **/
+s32 igb_phy_force_speed_duplex_bcm54xx(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 phy_data;
+ bool link;
+
+ ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data);
+ if (ret_val)
+ goto out;
+
+ igb_phy_force_speed_duplex_setup(hw, &phy_data);
+
+ phy_data &= ~(MII_CR_POWER_DOWN | MII_CR_ISOLATE);
+
+ ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data);
+ if (ret_val)
+ goto out;
+
+ udelay(1);
+
+ if (phy->autoneg_wait_to_complete) {
+ hw_dbg("Waiting for forced speed/duplex link on BCM phy.\n");
+
+ ret_val = igb_phy_has_link(hw, PHY_FORCE_LIMIT, 100000, &link);
+ if (ret_val)
+ goto out;
+
+ if (!link)
+ hw_dbg("Link taking longer than expected.\n");
+
+ /* Try once more */
+ ret_val = igb_phy_has_link(hw, PHY_FORCE_LIMIT, 100000, &link);
+ if (ret_val)
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
* igb_get_cable_length_m88 - Determine cable length for m88 PHY
* @hw: pointer to the HW structure
*
@@ -2058,6 +2136,39 @@ out:
}

/**
+ * igb_get_phy_info_bcm54xx - Retrieve PHY information
+ * @hw: pointer to the HW structure
+ *
+ * Valid for only copper links. Read the PHY status register (sticky read)
+ * to verify that link is up.
+ **/
+s32 igb_get_phy_info_bcm54xx(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ bool link;
+
+ if (phy->media_type != e1000_media_type_copper) {
+ hw_dbg("Phy info is only valid for copper media\n");
+ ret_val = -E1000_ERR_CONFIG;
+ goto out;
+ }
+
+ ret_val = igb_phy_has_link(hw, 1, 0, &link);
+ if (ret_val)
+ goto out;
+
+ if (!link) {
+ hw_dbg("Phy info is only valid if link is up\n");
+ ret_val = -E1000_ERR_CONFIG;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
* igb_phy_sw_reset - PHY software reset
* @hw: pointer to the HW structure
*
@@ -2215,6 +2326,39 @@ s32 igb_phy_init_script_igp3(struct e1000_hw *hw)
}

/**
+ * igb_phy_init_script_bcm54xx - Initialize BCM54xx PHY
+ * @hw: pointer to the HW structure
+ *
+ * Initialize Broadcom 54xx to work correctly.
+ **/
+s32 igb_phy_init_script_bcm54xx(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ u16 data = 0;
+ s32 ret_val = 0;
+
+ ret_val = phy->ops.read_reg(hw, MII_BCM54XX_ECR, &data);
+ if (ret_val)
+ goto out;
+
+ /* Mask interrupts globally. */
+ data |= MII_BCM54XX_ECR_IM;
+ ret_val = phy->ops.write_reg(hw, MII_BCM54XX_ECR, data);
+ if (ret_val)
+ goto out;
+
+ /* Unmask events we are interested in. */
+ data = ~(MII_BCM54XX_INT_DUPLEX |
+ MII_BCM54XX_INT_SPEED |
+ MII_BCM54XX_INT_LINK);
+ ret_val = phy->ops.write_reg(hw, MII_BCM54XX_IMR, data);
+ if (ret_val)
+ goto out;
+out:
+ return ret_val;
+}
+
+/**
* igb_initialize_M88E1512_phy - Initialize M88E1512 PHY
* @hw: pointer to the HW structure
*
diff --git a/drivers/net/ethernet/intel/igb/e1000_phy.h b/drivers/net/ethernet/intel/igb/e1000_phy.h
index 9b622b3..dd55a10 100644
--- a/drivers/net/ethernet/intel/igb/e1000_phy.h
+++ b/drivers/net/ethernet/intel/igb/e1000_phy.h
@@ -61,6 +61,7 @@ s32 igb_phy_has_link(struct e1000_hw *hw, u32 iterations,
void igb_power_up_phy_copper(struct e1000_hw *hw);
void igb_power_down_phy_copper(struct e1000_hw *hw);
s32 igb_phy_init_script_igp3(struct e1000_hw *hw);
+s32 igb_phy_init_script_bcm54xx(struct e1000_hw *hw);
s32 igb_initialize_M88E1512_phy(struct e1000_hw *hw);
s32 igb_initialize_M88E1543_phy(struct e1000_hw *hw);
s32 igb_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data);
@@ -75,6 +76,9 @@ s32 igb_get_cable_length_82580(struct e1000_hw *hw);
s32 igb_read_phy_reg_82580(struct e1000_hw *hw, u32 offset, u16 *data);
s32 igb_write_phy_reg_82580(struct e1000_hw *hw, u32 offset, u16 data);
s32 igb_check_polarity_m88(struct e1000_hw *hw);
+s32 igb_copper_link_setup_bcm54xx(struct e1000_hw *hw);
+s32 igb_phy_force_speed_duplex_bcm54xx(struct e1000_hw *hw);
+s32 igb_get_phy_info_bcm54xx(struct e1000_hw *hw);

/* IGP01E1000 Specific Registers */
#define IGP01E1000_PHY_PORT_CONFIG 0x10 /* Port Config */
--
2.11.0

3 changes: 2 additions & 1 deletion patch/series
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
0009-platform-mellonox-introduce-mlxreg-io-driver-and-add.patch
0010-config-mellanox-configuration.patch
0011-support-Broadcom-54616-Phy-for-Intel-igb-driver.patch
0012-platform-mellanox-mlxreg-hotplug-driver-add-check-fo.patch
0012-igb-setup-Broadcom-54616-PHY-when-no-EEPROM-present.patch
0013-platform-mellanox-mlxreg-hotplug-driver-add-check-fo.patch
driver-arista-net-tg3-dma-mask-4g-sb800.patch
driver-arista-net-tg3-disallow-broadcom-default-mac.patch
driver-arista-net-tg3-access-regs-indirectly.patch
Expand Down