diff --git a/patch/0012-igb-setup-Broadcom-54616-PHY-when-no-EEPROM-present.patch b/patch/0012-igb-setup-Broadcom-54616-PHY-when-no-EEPROM-present.patch new file mode 100644 index 000000000..c6691d0b3 --- /dev/null +++ b/patch/0012-igb-setup-Broadcom-54616-PHY-when-no-EEPROM-present.patch @@ -0,0 +1,283 @@ +From 0bd96ca66657b5e05eca6758613be614bee63a77 Mon Sep 17 00:00:00 2001 +From: Sergey Popovich +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 +Cc: John W Linville +Signed-off-by: Sergey Popovich +--- + 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 + #include ++#include + + #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 + diff --git a/patch/series b/patch/series index a36016595..470295b6b 100644 --- a/patch/series +++ b/patch/series @@ -10,6 +10,7 @@ 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-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