|
| 1 | +From 0bd96ca66657b5e05eca6758613be614bee63a77 Mon Sep 17 00:00:00 2001 |
| 2 | +From: Sergey Popovich < [email protected]> |
| 3 | +Date: Tue, 25 Dec 2018 06:54:08 +0000 |
| 4 | +Subject: igb: Setup Broadcom 54616 PHY when no EEPROM present |
| 5 | + |
| 6 | +While commit eeb0149660a2 ("igb: support BCM54616 PHY") adds basic |
| 7 | +support for Broadcom 54616 PHY it does not handle case when EEPROM |
| 8 | +is missing. |
| 9 | + |
| 10 | +In that case we need initialize PHY manually by isolating it from |
| 11 | +MII interface and providing methods to force speed and duplex. |
| 12 | + |
| 13 | +Behaviour was observed on Netberg Aurora 420 switch management port |
| 14 | +that uses igb MAC and Broadcom PHY. |
| 15 | + |
| 16 | +Fixes: commit eeb0149660a2 ("igb: support BCM54616 PHY") |
| 17 | +Cc: Jeff Kirsher < [email protected]> |
| 18 | +Cc: John W Linville < [email protected]> |
| 19 | +Signed-off-by: Sergey Popovich < [email protected]> |
| 20 | +--- |
| 21 | + e1000_82575.c | 12 +++-- |
| 22 | + e1000_defines.h | 1 + |
| 23 | + e1000_phy.c | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| 24 | + e1000_phy.h | 4 ++ |
| 25 | + 4 files changed, 158 insertions(+), 3 deletions(-) |
| 26 | + |
| 27 | +diff --git a/e1000_82575.c b/e1000_82575.c |
| 28 | +index d9aaa13..19a464d 100644 |
| 29 | +--- a/e1000_82575.c |
| 30 | ++++ b/e1000_82575.c |
| 31 | +@@ -342,6 +342,8 @@ static s32 igb_init_phy_params_82575(struct e1000_hw *hw) |
| 32 | + break; |
| 33 | + case BCM54616_E_PHY_ID: |
| 34 | + phy->type = e1000_phy_bcm54616; |
| 35 | ++ phy->ops.get_phy_info = igb_get_phy_info_bcm54xx; |
| 36 | ++ phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_bcm54xx; |
| 37 | + break; |
| 38 | + default: |
| 39 | + ret_val = -E1000_ERR_PHY; |
| 40 | +@@ -1285,9 +1287,12 @@ static s32 igb_get_cfg_done_82575(struct e1000_hw *hw) |
| 41 | + hw_dbg("MNG configuration cycle has not completed.\n"); |
| 42 | + |
| 43 | + /* If EEPROM is not marked present, init the PHY manually */ |
| 44 | +- if (((rd32(E1000_EECD) & E1000_EECD_PRES) == 0) && |
| 45 | +- (hw->phy.type == e1000_phy_igp_3)) |
| 46 | +- igb_phy_init_script_igp3(hw); |
| 47 | ++ if ((rd32(E1000_EECD) & E1000_EECD_PRES) == 0) { |
| 48 | ++ if (hw->phy.type == e1000_phy_igp_3) |
| 49 | ++ igb_phy_init_script_igp3(hw); |
| 50 | ++ else if (hw->phy.type == e1000_phy_bcm54616) |
| 51 | ++ igb_phy_init_script_bcm54xx(hw); |
| 52 | ++ } |
| 53 | + |
| 54 | + return 0; |
| 55 | + } |
| 56 | +@@ -1663,6 +1668,7 @@ static s32 igb_setup_copper_link_82575(struct e1000_hw *hw) |
| 57 | + ret_val = igb_copper_link_setup_82580(hw); |
| 58 | + break; |
| 59 | + case e1000_phy_bcm54616: |
| 60 | ++ ret_val = igb_copper_link_setup_bcm54xx(hw); |
| 61 | + break; |
| 62 | + default: |
| 63 | + ret_val = -E1000_ERR_PHY; |
| 64 | +diff --git a/e1000_defines.h b/e1000_defines.h |
| 65 | +index ce95b7e..2a14819 100644 |
| 66 | +--- a/e1000_defines.h |
| 67 | ++++ b/e1000_defines.h |
| 68 | +@@ -632,6 +632,7 @@ |
| 69 | + /* PHY Control Register */ |
| 70 | + #define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */ |
| 71 | + #define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */ |
| 72 | ++#define MII_CR_ISOLATE 0x0400 /* Isolate PHY from MII */ |
| 73 | + #define MII_CR_POWER_DOWN 0x0800 /* Power down */ |
| 74 | + #define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */ |
| 75 | + #define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */ |
| 76 | +diff --git a/e1000_phy.c b/e1000_phy.c |
| 77 | +index 2788a54..4c9090a 100644 |
| 78 | +--- a/e1000_phy.c |
| 79 | ++++ b/e1000_phy.c |
| 80 | +@@ -23,6 +23,7 @@ |
| 81 | + |
| 82 | + #include <linux/if_ether.h> |
| 83 | + #include <linux/delay.h> |
| 84 | ++#include <linux/brcmphy.h> |
| 85 | + |
| 86 | + #include "e1000_mac.h" |
| 87 | + #include "e1000_phy.h" |
| 88 | +@@ -467,6 +468,34 @@ out: |
| 89 | + } |
| 90 | + |
| 91 | + /** |
| 92 | ++ * igb_copper_link_setup_bcm54xx - Setup BCM54xx PHY for copper link |
| 93 | ++ * @hw: pointer to the HW structure |
| 94 | ++ * |
| 95 | ++ * Sets up copper link. |
| 96 | ++ **/ |
| 97 | ++s32 igb_copper_link_setup_bcm54xx(struct e1000_hw *hw) |
| 98 | ++{ |
| 99 | ++ struct e1000_phy_info *phy = &hw->phy; |
| 100 | ++ s32 ret_val = 0; |
| 101 | ++ u16 phy_data; |
| 102 | ++ |
| 103 | ++ if (phy->reset_disable) |
| 104 | ++ return 0; |
| 105 | ++ |
| 106 | ++ ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data); |
| 107 | ++ if (ret_val) |
| 108 | ++ goto out; |
| 109 | ++ |
| 110 | ++ phy_data &= ~(MII_CR_ISOLATE); |
| 111 | ++ |
| 112 | ++ ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data); |
| 113 | ++ if (ret_val) |
| 114 | ++ goto out; |
| 115 | ++out: |
| 116 | ++ return ret_val; |
| 117 | ++} |
| 118 | ++ |
| 119 | ++/** |
| 120 | + * igb_copper_link_setup_82580 - Setup 82580 PHY for copper link |
| 121 | + * @hw: pointer to the HW structure |
| 122 | + * |
| 123 | +@@ -1676,6 +1705,55 @@ s32 igb_phy_has_link(struct e1000_hw *hw, u32 iterations, |
| 124 | + } |
| 125 | + |
| 126 | + /** |
| 127 | ++ * igb_phy_force_speed_duplex_bcm54xx - Force speed/duplex for BCM54xx PHY |
| 128 | ++ * @hw: pointer to the HW structure |
| 129 | ++ * |
| 130 | ++ * Calls the PHY setup function to force speed and duplex. Waits |
| 131 | ++ * for link and returns successful if link up is successful, else |
| 132 | ++ * -E1000_ERR_PHY (-2). |
| 133 | ++ **/ |
| 134 | ++s32 igb_phy_force_speed_duplex_bcm54xx(struct e1000_hw *hw) |
| 135 | ++{ |
| 136 | ++ struct e1000_phy_info *phy = &hw->phy; |
| 137 | ++ s32 ret_val; |
| 138 | ++ u16 phy_data; |
| 139 | ++ bool link; |
| 140 | ++ |
| 141 | ++ ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data); |
| 142 | ++ if (ret_val) |
| 143 | ++ goto out; |
| 144 | ++ |
| 145 | ++ igb_phy_force_speed_duplex_setup(hw, &phy_data); |
| 146 | ++ |
| 147 | ++ phy_data &= ~(MII_CR_POWER_DOWN | MII_CR_ISOLATE); |
| 148 | ++ |
| 149 | ++ ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data); |
| 150 | ++ if (ret_val) |
| 151 | ++ goto out; |
| 152 | ++ |
| 153 | ++ udelay(1); |
| 154 | ++ |
| 155 | ++ if (phy->autoneg_wait_to_complete) { |
| 156 | ++ hw_dbg("Waiting for forced speed/duplex link on BCM phy.\n"); |
| 157 | ++ |
| 158 | ++ ret_val = igb_phy_has_link(hw, PHY_FORCE_LIMIT, 100000, &link); |
| 159 | ++ if (ret_val) |
| 160 | ++ goto out; |
| 161 | ++ |
| 162 | ++ if (!link) |
| 163 | ++ hw_dbg("Link taking longer than expected.\n"); |
| 164 | ++ |
| 165 | ++ /* Try once more */ |
| 166 | ++ ret_val = igb_phy_has_link(hw, PHY_FORCE_LIMIT, 100000, &link); |
| 167 | ++ if (ret_val) |
| 168 | ++ goto out; |
| 169 | ++ } |
| 170 | ++ |
| 171 | ++out: |
| 172 | ++ return ret_val; |
| 173 | ++} |
| 174 | ++ |
| 175 | ++/** |
| 176 | + * igb_get_cable_length_m88 - Determine cable length for m88 PHY |
| 177 | + * @hw: pointer to the HW structure |
| 178 | + * |
| 179 | +@@ -2058,6 +2136,39 @@ out: |
| 180 | + } |
| 181 | + |
| 182 | + /** |
| 183 | ++ * igb_get_phy_info_bcm54xx - Retrieve PHY information |
| 184 | ++ * @hw: pointer to the HW structure |
| 185 | ++ * |
| 186 | ++ * Valid for only copper links. Read the PHY status register (sticky read) |
| 187 | ++ * to verify that link is up. |
| 188 | ++ **/ |
| 189 | ++s32 igb_get_phy_info_bcm54xx(struct e1000_hw *hw) |
| 190 | ++{ |
| 191 | ++ struct e1000_phy_info *phy = &hw->phy; |
| 192 | ++ s32 ret_val; |
| 193 | ++ bool link; |
| 194 | ++ |
| 195 | ++ if (phy->media_type != e1000_media_type_copper) { |
| 196 | ++ hw_dbg("Phy info is only valid for copper media\n"); |
| 197 | ++ ret_val = -E1000_ERR_CONFIG; |
| 198 | ++ goto out; |
| 199 | ++ } |
| 200 | ++ |
| 201 | ++ ret_val = igb_phy_has_link(hw, 1, 0, &link); |
| 202 | ++ if (ret_val) |
| 203 | ++ goto out; |
| 204 | ++ |
| 205 | ++ if (!link) { |
| 206 | ++ hw_dbg("Phy info is only valid if link is up\n"); |
| 207 | ++ ret_val = -E1000_ERR_CONFIG; |
| 208 | ++ goto out; |
| 209 | ++ } |
| 210 | ++ |
| 211 | ++out: |
| 212 | ++ return ret_val; |
| 213 | ++} |
| 214 | ++ |
| 215 | ++/** |
| 216 | + * igb_phy_sw_reset - PHY software reset |
| 217 | + * @hw: pointer to the HW structure |
| 218 | + * |
| 219 | +@@ -2215,6 +2326,39 @@ s32 igb_phy_init_script_igp3(struct e1000_hw *hw) |
| 220 | + } |
| 221 | + |
| 222 | + /** |
| 223 | ++ * igb_phy_init_script_bcm54xx - Initialize BCM54xx PHY |
| 224 | ++ * @hw: pointer to the HW structure |
| 225 | ++ * |
| 226 | ++ * Initialize Broadcom 54xx to work correctly. |
| 227 | ++ **/ |
| 228 | ++s32 igb_phy_init_script_bcm54xx(struct e1000_hw *hw) |
| 229 | ++{ |
| 230 | ++ struct e1000_phy_info *phy = &hw->phy; |
| 231 | ++ u16 data = 0; |
| 232 | ++ s32 ret_val = 0; |
| 233 | ++ |
| 234 | ++ ret_val = phy->ops.read_reg(hw, MII_BCM54XX_ECR, &data); |
| 235 | ++ if (ret_val) |
| 236 | ++ goto out; |
| 237 | ++ |
| 238 | ++ /* Mask interrupts globally. */ |
| 239 | ++ data |= MII_BCM54XX_ECR_IM; |
| 240 | ++ ret_val = phy->ops.write_reg(hw, MII_BCM54XX_ECR, data); |
| 241 | ++ if (ret_val) |
| 242 | ++ goto out; |
| 243 | ++ |
| 244 | ++ /* Unmask events we are interested in. */ |
| 245 | ++ data = ~(MII_BCM54XX_INT_DUPLEX | |
| 246 | ++ MII_BCM54XX_INT_SPEED | |
| 247 | ++ MII_BCM54XX_INT_LINK); |
| 248 | ++ ret_val = phy->ops.write_reg(hw, MII_BCM54XX_IMR, data); |
| 249 | ++ if (ret_val) |
| 250 | ++ goto out; |
| 251 | ++out: |
| 252 | ++ return ret_val; |
| 253 | ++} |
| 254 | ++ |
| 255 | ++/** |
| 256 | + * igb_initialize_M88E1512_phy - Initialize M88E1512 PHY |
| 257 | + * @hw: pointer to the HW structure |
| 258 | + * |
| 259 | +diff --git a/e1000_phy.h b/e1000_phy.h |
| 260 | +index 9b622b3..dd55a10 100644 |
| 261 | +--- a/e1000_phy.h |
| 262 | ++++ b/e1000_phy.h |
| 263 | +@@ -61,6 +61,7 @@ s32 igb_phy_has_link(struct e1000_hw *hw, u32 iterations, |
| 264 | + void igb_power_up_phy_copper(struct e1000_hw *hw); |
| 265 | + void igb_power_down_phy_copper(struct e1000_hw *hw); |
| 266 | + s32 igb_phy_init_script_igp3(struct e1000_hw *hw); |
| 267 | ++s32 igb_phy_init_script_bcm54xx(struct e1000_hw *hw); |
| 268 | + s32 igb_initialize_M88E1512_phy(struct e1000_hw *hw); |
| 269 | + s32 igb_initialize_M88E1543_phy(struct e1000_hw *hw); |
| 270 | + s32 igb_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data); |
| 271 | +@@ -75,6 +76,9 @@ s32 igb_get_cable_length_82580(struct e1000_hw *hw); |
| 272 | + s32 igb_read_phy_reg_82580(struct e1000_hw *hw, u32 offset, u16 *data); |
| 273 | + s32 igb_write_phy_reg_82580(struct e1000_hw *hw, u32 offset, u16 data); |
| 274 | + s32 igb_check_polarity_m88(struct e1000_hw *hw); |
| 275 | ++s32 igb_copper_link_setup_bcm54xx(struct e1000_hw *hw); |
| 276 | ++s32 igb_phy_force_speed_duplex_bcm54xx(struct e1000_hw *hw); |
| 277 | ++s32 igb_get_phy_info_bcm54xx(struct e1000_hw *hw); |
| 278 | + |
| 279 | + /* IGP01E1000 Specific Registers */ |
| 280 | + #define IGP01E1000_PHY_PORT_CONFIG 0x10 /* Port Config */ |
| 281 | +-- |
| 282 | +2.11.0 |
| 283 | + |
0 commit comments