Skip to content

Commit d58dd75

Browse files
[igb]: Support forcing speed and get info for Broadcom 54616 PHY
We have support for Broadcom 54616 backported from Linux Kernel upstream in commit 3639697 ("[igb]: support broadcom 54616 phy for Intel igb driver (#3)"). However that support doesn't account for the case when no EEPROM present and we need to initialize PHY manually. Signed-off-by: Sergey Popovich <[email protected]>
1 parent 34b5061 commit d58dd75

File tree

2 files changed

+284
-0
lines changed

2 files changed

+284
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,283 @@
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+

patch/series

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
0009-platform-mellonox-introduce-mlxreg-io-driver-and-add.patch
1111
0010-config-mellanox-configuration.patch
1212
0011-support-Broadcom-54616-Phy-for-Intel-igb-driver.patch
13+
0012-igb-setup-Broadcom-54616-PHY-when-no-EEPROM-present.patch
1314
0013-platform-mellanox-mlxreg-hotplug-driver-add-check-fo.patch
1415
driver-arista-net-tg3-dma-mask-4g-sb800.patch
1516
driver-arista-net-tg3-disallow-broadcom-default-mac.patch

0 commit comments

Comments
 (0)