blob: 7a8df7a2f4da7a724e331aca995b6f89ffd29225 [file] [log] [blame]
Eilon Greensteind05c26c2009-01-17 23:26:13 -08001/* Copyright 2008-2009 Broadcom Corporation
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002 *
3 * Unless you and Broadcom execute a separate written software license
4 * agreement governing use of this software, this software is licensed to you
5 * under the terms of the GNU General Public License version 2, available
6 * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL").
7 *
8 * Notwithstanding the above, under no circumstances may you combine this
9 * software in any way with any other Broadcom software provided under a
10 * license other than the GPL, without Broadcom's express prior written
11 * consent.
12 *
13 * Written by Yaniv Rosner
14 *
15 */
16
Joe Perches7995c642010-02-17 15:01:52 +000017#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
18
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070019#include <linux/kernel.h>
20#include <linux/errno.h>
21#include <linux/pci.h>
22#include <linux/netdevice.h>
23#include <linux/delay.h>
24#include <linux/ethtool.h>
25#include <linux/mutex.h>
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070026
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070027#include "bnx2x.h"
28
29/********************************************************/
Eilon Greenstein3196a882008-08-13 15:58:49 -070030#define ETH_HLEN 14
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070031#define ETH_OVREHEAD (ETH_HLEN + 8)/* 8 for CRC + VLAN*/
32#define ETH_MIN_PACKET_SIZE 60
33#define ETH_MAX_PACKET_SIZE 1500
34#define ETH_MAX_JUMBO_PACKET_SIZE 9600
35#define MDIO_ACCESS_TIMEOUT 1000
36#define BMAC_CONTROL_RX_ENABLE 2
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070037
38/***********************************************************/
Eilon Greenstein3196a882008-08-13 15:58:49 -070039/* Shortcut definitions */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070040/***********************************************************/
41
Eilon Greenstein2f904462009-08-12 08:22:16 +000042#define NIG_LATCH_BC_ENABLE_MI_INT 0
43
44#define NIG_STATUS_EMAC0_MI_INT \
45 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_EMAC0_MISC_MI_INT
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070046#define NIG_STATUS_XGXS0_LINK10G \
47 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK10G
48#define NIG_STATUS_XGXS0_LINK_STATUS \
49 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS
50#define NIG_STATUS_XGXS0_LINK_STATUS_SIZE \
51 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS_SIZE
52#define NIG_STATUS_SERDES0_LINK_STATUS \
53 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_SERDES0_LINK_STATUS
54#define NIG_MASK_MI_INT \
55 NIG_MASK_INTERRUPT_PORT0_REG_MASK_EMAC0_MISC_MI_INT
56#define NIG_MASK_XGXS0_LINK10G \
57 NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK10G
58#define NIG_MASK_XGXS0_LINK_STATUS \
59 NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK_STATUS
60#define NIG_MASK_SERDES0_LINK_STATUS \
61 NIG_MASK_INTERRUPT_PORT0_REG_MASK_SERDES0_LINK_STATUS
62
63#define MDIO_AN_CL73_OR_37_COMPLETE \
64 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE | \
65 MDIO_GP_STATUS_TOP_AN_STATUS1_CL37_AUTONEG_COMPLETE)
66
67#define XGXS_RESET_BITS \
68 (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_RSTB_HW | \
69 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_IDDQ | \
70 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN | \
71 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN_SD | \
72 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_TXD_FIFO_RSTB)
73
74#define SERDES_RESET_BITS \
75 (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_RSTB_HW | \
76 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_IDDQ | \
77 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN | \
78 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN_SD)
79
80#define AUTONEG_CL37 SHARED_HW_CFG_AN_ENABLE_CL37
81#define AUTONEG_CL73 SHARED_HW_CFG_AN_ENABLE_CL73
Eilon Greenstein3196a882008-08-13 15:58:49 -070082#define AUTONEG_BAM SHARED_HW_CFG_AN_ENABLE_BAM
83#define AUTONEG_PARALLEL \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070084 SHARED_HW_CFG_AN_ENABLE_PARALLEL_DETECTION
Eilon Greenstein3196a882008-08-13 15:58:49 -070085#define AUTONEG_SGMII_FIBER_AUTODET \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070086 SHARED_HW_CFG_AN_EN_SGMII_FIBER_AUTO_DETECT
Eilon Greenstein3196a882008-08-13 15:58:49 -070087#define AUTONEG_REMOTE_PHY SHARED_HW_CFG_AN_ENABLE_REMOTE_PHY
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070088
89#define GP_STATUS_PAUSE_RSOLUTION_TXSIDE \
90 MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_TXSIDE
91#define GP_STATUS_PAUSE_RSOLUTION_RXSIDE \
92 MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_RXSIDE
93#define GP_STATUS_SPEED_MASK \
94 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_MASK
95#define GP_STATUS_10M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10M
96#define GP_STATUS_100M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_100M
97#define GP_STATUS_1G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G
98#define GP_STATUS_2_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_2_5G
99#define GP_STATUS_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_5G
100#define GP_STATUS_6G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_6G
101#define GP_STATUS_10G_HIG \
102 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_HIG
103#define GP_STATUS_10G_CX4 \
104 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_CX4
105#define GP_STATUS_12G_HIG \
106 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12G_HIG
107#define GP_STATUS_12_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12_5G
108#define GP_STATUS_13G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_13G
109#define GP_STATUS_15G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_15G
110#define GP_STATUS_16G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_16G
111#define GP_STATUS_1G_KX MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G_KX
112#define GP_STATUS_10G_KX4 \
113 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_KX4
114
115#define LINK_10THD LINK_STATUS_SPEED_AND_DUPLEX_10THD
116#define LINK_10TFD LINK_STATUS_SPEED_AND_DUPLEX_10TFD
117#define LINK_100TXHD LINK_STATUS_SPEED_AND_DUPLEX_100TXHD
118#define LINK_100T4 LINK_STATUS_SPEED_AND_DUPLEX_100T4
119#define LINK_100TXFD LINK_STATUS_SPEED_AND_DUPLEX_100TXFD
120#define LINK_1000THD LINK_STATUS_SPEED_AND_DUPLEX_1000THD
121#define LINK_1000TFD LINK_STATUS_SPEED_AND_DUPLEX_1000TFD
122#define LINK_1000XFD LINK_STATUS_SPEED_AND_DUPLEX_1000XFD
123#define LINK_2500THD LINK_STATUS_SPEED_AND_DUPLEX_2500THD
124#define LINK_2500TFD LINK_STATUS_SPEED_AND_DUPLEX_2500TFD
125#define LINK_2500XFD LINK_STATUS_SPEED_AND_DUPLEX_2500XFD
126#define LINK_10GTFD LINK_STATUS_SPEED_AND_DUPLEX_10GTFD
127#define LINK_10GXFD LINK_STATUS_SPEED_AND_DUPLEX_10GXFD
128#define LINK_12GTFD LINK_STATUS_SPEED_AND_DUPLEX_12GTFD
129#define LINK_12GXFD LINK_STATUS_SPEED_AND_DUPLEX_12GXFD
130#define LINK_12_5GTFD LINK_STATUS_SPEED_AND_DUPLEX_12_5GTFD
131#define LINK_12_5GXFD LINK_STATUS_SPEED_AND_DUPLEX_12_5GXFD
132#define LINK_13GTFD LINK_STATUS_SPEED_AND_DUPLEX_13GTFD
133#define LINK_13GXFD LINK_STATUS_SPEED_AND_DUPLEX_13GXFD
134#define LINK_15GTFD LINK_STATUS_SPEED_AND_DUPLEX_15GTFD
135#define LINK_15GXFD LINK_STATUS_SPEED_AND_DUPLEX_15GXFD
136#define LINK_16GTFD LINK_STATUS_SPEED_AND_DUPLEX_16GTFD
137#define LINK_16GXFD LINK_STATUS_SPEED_AND_DUPLEX_16GXFD
138
139#define PHY_XGXS_FLAG 0x1
140#define PHY_SGMII_FLAG 0x2
141#define PHY_SERDES_FLAG 0x4
142
Eilon Greenstein589abe32009-02-12 08:36:55 +0000143/* */
144#define SFP_EEPROM_CON_TYPE_ADDR 0x2
145 #define SFP_EEPROM_CON_TYPE_VAL_LC 0x7
146 #define SFP_EEPROM_CON_TYPE_VAL_COPPER 0x21
147
Eilon Greenstein4d295db2009-07-21 05:47:47 +0000148
149#define SFP_EEPROM_COMP_CODE_ADDR 0x3
150 #define SFP_EEPROM_COMP_CODE_SR_MASK (1<<4)
151 #define SFP_EEPROM_COMP_CODE_LR_MASK (1<<5)
152 #define SFP_EEPROM_COMP_CODE_LRM_MASK (1<<6)
153
Eilon Greenstein589abe32009-02-12 08:36:55 +0000154#define SFP_EEPROM_FC_TX_TECH_ADDR 0x8
155 #define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE 0x4
156 #define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE 0x8
Eilon Greenstein4d295db2009-07-21 05:47:47 +0000157
Eilon Greenstein589abe32009-02-12 08:36:55 +0000158#define SFP_EEPROM_OPTIONS_ADDR 0x40
159 #define SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK 0x1
160#define SFP_EEPROM_OPTIONS_SIZE 2
161
Eilon Greenstein4d295db2009-07-21 05:47:47 +0000162#define EDC_MODE_LINEAR 0x0022
163#define EDC_MODE_LIMITING 0x0044
164#define EDC_MODE_PASSIVE_DAC 0x0055
Eilon Greenstein589abe32009-02-12 08:36:55 +0000165
Eilon Greenstein4d295db2009-07-21 05:47:47 +0000166
167
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700168/**********************************************************/
169/* INTERFACE */
170/**********************************************************/
171#define CL45_WR_OVER_CL22(_bp, _port, _phy_addr, _bank, _addr, _val) \
172 bnx2x_cl45_write(_bp, _port, 0, _phy_addr, \
173 DEFAULT_PHY_DEV_ADDR, \
174 (_bank + (_addr & 0xf)), \
175 _val)
176
177#define CL45_RD_OVER_CL22(_bp, _port, _phy_addr, _bank, _addr, _val) \
178 bnx2x_cl45_read(_bp, _port, 0, _phy_addr, \
179 DEFAULT_PHY_DEV_ADDR, \
180 (_bank + (_addr & 0xf)), \
181 _val)
182
Eilon Greensteinc1b73992009-02-12 08:37:07 +0000183static void bnx2x_set_serdes_access(struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700184{
185 struct bnx2x *bp = params->bp;
Eilon Greensteinc1b73992009-02-12 08:37:07 +0000186 u32 emac_base = (params->port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +0000187
Eilon Greensteinc1b73992009-02-12 08:37:07 +0000188 /* Set Clause 22 */
189 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + params->port*0x10, 1);
190 REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245f8000);
191 udelay(500);
192 REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245d000f);
193 udelay(500);
194 /* Set Clause 45 */
195 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + params->port*0x10, 0);
196}
197static void bnx2x_set_phy_mdio(struct link_params *params, u8 phy_flags)
198{
199 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +0000200
Eilon Greensteinc1b73992009-02-12 08:37:07 +0000201 if (phy_flags & PHY_XGXS_FLAG) {
202 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_ST +
203 params->port*0x18, 0);
204 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + params->port*0x18,
205 DEFAULT_PHY_DEV_ADDR);
206 } else {
207 bnx2x_set_serdes_access(params);
208
209 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_DEVAD +
210 params->port*0x10,
211 DEFAULT_PHY_DEV_ADDR);
212 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700213}
214
215static u32 bnx2x_bits_en(struct bnx2x *bp, u32 reg, u32 bits)
216{
217 u32 val = REG_RD(bp, reg);
218
219 val |= bits;
220 REG_WR(bp, reg, val);
221 return val;
222}
223
224static u32 bnx2x_bits_dis(struct bnx2x *bp, u32 reg, u32 bits)
225{
226 u32 val = REG_RD(bp, reg);
227
228 val &= ~bits;
229 REG_WR(bp, reg, val);
230 return val;
231}
232
233static void bnx2x_emac_init(struct link_params *params,
234 struct link_vars *vars)
235{
236 /* reset and unreset the emac core */
237 struct bnx2x *bp = params->bp;
238 u8 port = params->port;
239 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
240 u32 val;
241 u16 timeout;
242
243 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
244 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
245 udelay(5);
246 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
247 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
248
249 /* init emac - use read-modify-write */
250 /* self clear reset */
251 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700252 EMAC_WR(bp, EMAC_REG_EMAC_MODE, (val | EMAC_MODE_RESET));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700253
254 timeout = 200;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700255 do {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700256 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
257 DP(NETIF_MSG_LINK, "EMAC reset reg is %u\n", val);
258 if (!timeout) {
259 DP(NETIF_MSG_LINK, "EMAC timeout!\n");
260 return;
261 }
262 timeout--;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700263 } while (val & EMAC_MODE_RESET);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700264
265 /* Set mac address */
266 val = ((params->mac_addr[0] << 8) |
267 params->mac_addr[1]);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700268 EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700269
270 val = ((params->mac_addr[2] << 24) |
271 (params->mac_addr[3] << 16) |
272 (params->mac_addr[4] << 8) |
273 params->mac_addr[5]);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700274 EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH + 4, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700275}
276
277static u8 bnx2x_emac_enable(struct link_params *params,
278 struct link_vars *vars, u8 lb)
279{
280 struct bnx2x *bp = params->bp;
281 u8 port = params->port;
282 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
283 u32 val;
284
285 DP(NETIF_MSG_LINK, "enabling EMAC\n");
286
287 /* enable emac and not bmac */
288 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 1);
289
290 /* for paladium */
291 if (CHIP_REV_IS_EMUL(bp)) {
292 /* Use lane 1 (of lanes 0-3) */
293 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1);
294 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
295 port*4, 1);
296 }
297 /* for fpga */
298 else
299
300 if (CHIP_REV_IS_FPGA(bp)) {
301 /* Use lane 1 (of lanes 0-3) */
302 DP(NETIF_MSG_LINK, "bnx2x_emac_enable: Setting FPGA\n");
303
304 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1);
305 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4,
306 0);
307 } else
308 /* ASIC */
309 if (vars->phy_flags & PHY_XGXS_FLAG) {
310 u32 ser_lane = ((params->lane_config &
311 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
312 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
313
314 DP(NETIF_MSG_LINK, "XGXS\n");
315 /* select the master lanes (out of 0-3) */
316 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 +
317 port*4, ser_lane);
318 /* select XGXS */
319 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
320 port*4, 1);
321
322 } else { /* SerDes */
323 DP(NETIF_MSG_LINK, "SerDes\n");
324 /* select SerDes */
325 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
326 port*4, 0);
327 }
328
Eilon Greenstein811a2f22009-02-12 08:37:04 +0000329 bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
330 EMAC_RX_MODE_RESET);
331 bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
332 EMAC_TX_MODE_RESET);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700333
334 if (CHIP_REV_IS_SLOW(bp)) {
335 /* config GMII mode */
336 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700337 EMAC_WR(bp, EMAC_REG_EMAC_MODE,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700338 (val | EMAC_MODE_PORT_GMII));
339 } else { /* ASIC */
340 /* pause enable/disable */
341 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
342 EMAC_RX_MODE_FLOW_EN);
David S. Millerc0700f92008-12-16 23:53:20 -0800343 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700344 bnx2x_bits_en(bp, emac_base +
345 EMAC_REG_EMAC_RX_MODE,
346 EMAC_RX_MODE_FLOW_EN);
347
348 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700349 (EMAC_TX_MODE_EXT_PAUSE_EN |
350 EMAC_TX_MODE_FLOW_EN));
David S. Millerc0700f92008-12-16 23:53:20 -0800351 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700352 bnx2x_bits_en(bp, emac_base +
353 EMAC_REG_EMAC_TX_MODE,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700354 (EMAC_TX_MODE_EXT_PAUSE_EN |
355 EMAC_TX_MODE_FLOW_EN));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700356 }
357
358 /* KEEP_VLAN_TAG, promiscuous */
359 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_RX_MODE);
360 val |= EMAC_RX_MODE_KEEP_VLAN_TAG | EMAC_RX_MODE_PROMISCUOUS;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700361 EMAC_WR(bp, EMAC_REG_EMAC_RX_MODE, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700362
363 /* Set Loopback */
364 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
365 if (lb)
366 val |= 0x810;
367 else
368 val &= ~0x810;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700369 EMAC_WR(bp, EMAC_REG_EMAC_MODE, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700370
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +0000371 /* enable emac */
372 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 1);
373
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700374 /* enable emac for jumbo packets */
Eilon Greenstein3196a882008-08-13 15:58:49 -0700375 EMAC_WR(bp, EMAC_REG_EMAC_RX_MTU_SIZE,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700376 (EMAC_RX_MTU_SIZE_JUMBO_ENA |
377 (ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD)));
378
379 /* strip CRC */
380 REG_WR(bp, NIG_REG_NIG_INGRESS_EMAC0_NO_CRC + port*4, 0x1);
381
382 /* disable the NIG in/out to the bmac */
383 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x0);
384 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, 0x0);
385 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x0);
386
387 /* enable the NIG in/out to the emac */
388 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x1);
389 val = 0;
David S. Millerc0700f92008-12-16 23:53:20 -0800390 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700391 val = 1;
392
393 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, val);
394 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x1);
395
396 if (CHIP_REV_IS_EMUL(bp)) {
397 /* take the BigMac out of reset */
398 REG_WR(bp,
399 GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
400 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
401
402 /* enable access for bmac registers */
403 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
Eilon Greenstein6f654972009-08-12 08:23:51 +0000404 } else
405 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700406
407 vars->mac_type = MAC_TYPE_EMAC;
408 return 0;
409}
410
411
412
413static u8 bnx2x_bmac_enable(struct link_params *params, struct link_vars *vars,
414 u8 is_lb)
415{
416 struct bnx2x *bp = params->bp;
417 u8 port = params->port;
418 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
419 NIG_REG_INGRESS_BMAC0_MEM;
420 u32 wb_data[2];
421 u32 val;
422
423 DP(NETIF_MSG_LINK, "Enabling BigMAC\n");
424 /* reset and unreset the BigMac */
425 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
426 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
427 msleep(1);
428
429 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
430 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
431
432 /* enable access for bmac registers */
433 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
434
435 /* XGXS control */
436 wb_data[0] = 0x3c;
437 wb_data[1] = 0;
438 REG_WR_DMAE(bp, bmac_addr +
439 BIGMAC_REGISTER_BMAC_XGXS_CONTROL,
440 wb_data, 2);
441
442 /* tx MAC SA */
443 wb_data[0] = ((params->mac_addr[2] << 24) |
444 (params->mac_addr[3] << 16) |
445 (params->mac_addr[4] << 8) |
446 params->mac_addr[5]);
447 wb_data[1] = ((params->mac_addr[0] << 8) |
448 params->mac_addr[1]);
449 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_SOURCE_ADDR,
450 wb_data, 2);
451
452 /* tx control */
453 val = 0xc0;
David S. Millerc0700f92008-12-16 23:53:20 -0800454 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700455 val |= 0x800000;
456 wb_data[0] = val;
457 wb_data[1] = 0;
458 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_CONTROL,
459 wb_data, 2);
460
461 /* mac control */
462 val = 0x3;
463 if (is_lb) {
464 val |= 0x4;
465 DP(NETIF_MSG_LINK, "enable bmac loopback\n");
466 }
467 wb_data[0] = val;
468 wb_data[1] = 0;
469 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
470 wb_data, 2);
471
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700472 /* set rx mtu */
473 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
474 wb_data[1] = 0;
475 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_MAX_SIZE,
476 wb_data, 2);
477
478 /* rx control set to don't strip crc */
479 val = 0x14;
David S. Millerc0700f92008-12-16 23:53:20 -0800480 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700481 val |= 0x20;
482 wb_data[0] = val;
483 wb_data[1] = 0;
484 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_CONTROL,
485 wb_data, 2);
486
487 /* set tx mtu */
488 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
489 wb_data[1] = 0;
490 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_MAX_SIZE,
491 wb_data, 2);
492
493 /* set cnt max size */
494 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
495 wb_data[1] = 0;
496 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_CNT_MAX_SIZE,
497 wb_data, 2);
498
499 /* configure safc */
500 wb_data[0] = 0x1000200;
501 wb_data[1] = 0;
502 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_LLFC_MSG_FLDS,
503 wb_data, 2);
504 /* fix for emulation */
505 if (CHIP_REV_IS_EMUL(bp)) {
506 wb_data[0] = 0xf000;
507 wb_data[1] = 0;
508 REG_WR_DMAE(bp,
509 bmac_addr + BIGMAC_REGISTER_TX_PAUSE_THRESHOLD,
510 wb_data, 2);
511 }
512
513 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0x1);
514 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 0x0);
515 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 0x0);
516 val = 0;
David S. Millerc0700f92008-12-16 23:53:20 -0800517 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700518 val = 1;
519 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, val);
520 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x0);
521 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x0);
522 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, 0x0);
523 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x1);
524 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x1);
525
526 vars->mac_type = MAC_TYPE_BMAC;
527 return 0;
528}
529
530static void bnx2x_phy_deassert(struct link_params *params, u8 phy_flags)
531{
532 struct bnx2x *bp = params->bp;
533 u32 val;
534
535 if (phy_flags & PHY_XGXS_FLAG) {
536 DP(NETIF_MSG_LINK, "bnx2x_phy_deassert:XGXS\n");
537 val = XGXS_RESET_BITS;
538
539 } else { /* SerDes */
540 DP(NETIF_MSG_LINK, "bnx2x_phy_deassert:SerDes\n");
541 val = SERDES_RESET_BITS;
542 }
543
544 val = val << (params->port*16);
545
546 /* reset and unreset the SerDes/XGXS */
547 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
548 val);
549 udelay(500);
550 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET,
551 val);
Eilon Greensteinc1b73992009-02-12 08:37:07 +0000552 bnx2x_set_phy_mdio(params, phy_flags);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700553}
554
555void bnx2x_link_status_update(struct link_params *params,
556 struct link_vars *vars)
557{
558 struct bnx2x *bp = params->bp;
559 u8 link_10g;
560 u8 port = params->port;
561
562 if (params->switch_cfg == SWITCH_CFG_1G)
563 vars->phy_flags = PHY_SERDES_FLAG;
564 else
565 vars->phy_flags = PHY_XGXS_FLAG;
566 vars->link_status = REG_RD(bp, params->shmem_base +
567 offsetof(struct shmem_region,
568 port_mb[port].link_status));
569
570 vars->link_up = (vars->link_status & LINK_STATUS_LINK_UP);
571
572 if (vars->link_up) {
573 DP(NETIF_MSG_LINK, "phy link up\n");
574
575 vars->phy_link_up = 1;
576 vars->duplex = DUPLEX_FULL;
577 switch (vars->link_status &
578 LINK_STATUS_SPEED_AND_DUPLEX_MASK) {
579 case LINK_10THD:
580 vars->duplex = DUPLEX_HALF;
581 /* fall thru */
582 case LINK_10TFD:
583 vars->line_speed = SPEED_10;
584 break;
585
586 case LINK_100TXHD:
587 vars->duplex = DUPLEX_HALF;
588 /* fall thru */
589 case LINK_100T4:
590 case LINK_100TXFD:
591 vars->line_speed = SPEED_100;
592 break;
593
594 case LINK_1000THD:
595 vars->duplex = DUPLEX_HALF;
596 /* fall thru */
597 case LINK_1000TFD:
598 vars->line_speed = SPEED_1000;
599 break;
600
601 case LINK_2500THD:
602 vars->duplex = DUPLEX_HALF;
603 /* fall thru */
604 case LINK_2500TFD:
605 vars->line_speed = SPEED_2500;
606 break;
607
608 case LINK_10GTFD:
609 vars->line_speed = SPEED_10000;
610 break;
611
612 case LINK_12GTFD:
613 vars->line_speed = SPEED_12000;
614 break;
615
616 case LINK_12_5GTFD:
617 vars->line_speed = SPEED_12500;
618 break;
619
620 case LINK_13GTFD:
621 vars->line_speed = SPEED_13000;
622 break;
623
624 case LINK_15GTFD:
625 vars->line_speed = SPEED_15000;
626 break;
627
628 case LINK_16GTFD:
629 vars->line_speed = SPEED_16000;
630 break;
631
632 default:
633 break;
634 }
635
636 if (vars->link_status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED)
David S. Millerc0700f92008-12-16 23:53:20 -0800637 vars->flow_ctrl |= BNX2X_FLOW_CTRL_TX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700638 else
David S. Millerc0700f92008-12-16 23:53:20 -0800639 vars->flow_ctrl &= ~BNX2X_FLOW_CTRL_TX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700640
641 if (vars->link_status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED)
David S. Millerc0700f92008-12-16 23:53:20 -0800642 vars->flow_ctrl |= BNX2X_FLOW_CTRL_RX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700643 else
David S. Millerc0700f92008-12-16 23:53:20 -0800644 vars->flow_ctrl &= ~BNX2X_FLOW_CTRL_RX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700645
646 if (vars->phy_flags & PHY_XGXS_FLAG) {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700647 if (vars->line_speed &&
648 ((vars->line_speed == SPEED_10) ||
649 (vars->line_speed == SPEED_100))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700650 vars->phy_flags |= PHY_SGMII_FLAG;
651 } else {
652 vars->phy_flags &= ~PHY_SGMII_FLAG;
653 }
654 }
655
656 /* anything 10 and over uses the bmac */
657 link_10g = ((vars->line_speed == SPEED_10000) ||
658 (vars->line_speed == SPEED_12000) ||
659 (vars->line_speed == SPEED_12500) ||
660 (vars->line_speed == SPEED_13000) ||
661 (vars->line_speed == SPEED_15000) ||
662 (vars->line_speed == SPEED_16000));
663 if (link_10g)
664 vars->mac_type = MAC_TYPE_BMAC;
665 else
666 vars->mac_type = MAC_TYPE_EMAC;
667
668 } else { /* link down */
669 DP(NETIF_MSG_LINK, "phy link down\n");
670
671 vars->phy_link_up = 0;
672
673 vars->line_speed = 0;
674 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -0800675 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700676
677 /* indicate no mac active */
678 vars->mac_type = MAC_TYPE_NONE;
679 }
680
681 DP(NETIF_MSG_LINK, "link_status 0x%x phy_link_up %x\n",
682 vars->link_status, vars->phy_link_up);
683 DP(NETIF_MSG_LINK, "line_speed %x duplex %x flow_ctrl 0x%x\n",
684 vars->line_speed, vars->duplex, vars->flow_ctrl);
685}
686
687static void bnx2x_update_mng(struct link_params *params, u32 link_status)
688{
689 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +0000690
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700691 REG_WR(bp, params->shmem_base +
692 offsetof(struct shmem_region,
693 port_mb[params->port].link_status),
694 link_status);
695}
696
697static void bnx2x_bmac_rx_disable(struct bnx2x *bp, u8 port)
698{
699 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
700 NIG_REG_INGRESS_BMAC0_MEM;
701 u32 wb_data[2];
Eilon Greenstein3196a882008-08-13 15:58:49 -0700702 u32 nig_bmac_enable = REG_RD(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700703
704 /* Only if the bmac is out of reset */
705 if (REG_RD(bp, MISC_REG_RESET_REG_2) &
706 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port) &&
707 nig_bmac_enable) {
708
709 /* Clear Rx Enable bit in BMAC_CONTROL register */
710 REG_RD_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
711 wb_data, 2);
712 wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
713 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
714 wb_data, 2);
715
716 msleep(1);
717 }
718}
719
720static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl,
721 u32 line_speed)
722{
723 struct bnx2x *bp = params->bp;
724 u8 port = params->port;
725 u32 init_crd, crd;
726 u32 count = 1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700727
728 /* disable port */
729 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x1);
730
731 /* wait for init credit */
732 init_crd = REG_RD(bp, PBF_REG_P0_INIT_CRD + port*4);
733 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
734 DP(NETIF_MSG_LINK, "init_crd 0x%x crd 0x%x\n", init_crd, crd);
735
736 while ((init_crd != crd) && count) {
737 msleep(5);
738
739 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
740 count--;
741 }
742 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
743 if (init_crd != crd) {
744 DP(NETIF_MSG_LINK, "BUG! init_crd 0x%x != crd 0x%x\n",
745 init_crd, crd);
746 return -EINVAL;
747 }
748
David S. Millerc0700f92008-12-16 23:53:20 -0800749 if (flow_ctrl & BNX2X_FLOW_CTRL_RX ||
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700750 line_speed == SPEED_10 ||
751 line_speed == SPEED_100 ||
752 line_speed == SPEED_1000 ||
753 line_speed == SPEED_2500) {
754 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700755 /* update threshold */
756 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, 0);
757 /* update init credit */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700758 init_crd = 778; /* (800-18-4) */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700759
760 } else {
761 u32 thresh = (ETH_MAX_JUMBO_PACKET_SIZE +
762 ETH_OVREHEAD)/16;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700763 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700764 /* update threshold */
765 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, thresh);
766 /* update init credit */
767 switch (line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700768 case SPEED_10000:
769 init_crd = thresh + 553 - 22;
770 break;
771
772 case SPEED_12000:
773 init_crd = thresh + 664 - 22;
774 break;
775
776 case SPEED_13000:
777 init_crd = thresh + 742 - 22;
778 break;
779
780 case SPEED_16000:
781 init_crd = thresh + 778 - 22;
782 break;
783 default:
784 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
785 line_speed);
786 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700787 }
788 }
789 REG_WR(bp, PBF_REG_P0_INIT_CRD + port*4, init_crd);
790 DP(NETIF_MSG_LINK, "PBF updated to speed %d credit %d\n",
791 line_speed, init_crd);
792
793 /* probe the credit changes */
794 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x1);
795 msleep(5);
796 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x0);
797
798 /* enable port */
799 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x0);
800 return 0;
801}
802
Eilon Greenstein589abe32009-02-12 08:36:55 +0000803static u32 bnx2x_get_emac_base(struct bnx2x *bp, u32 ext_phy_type, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700804{
805 u32 emac_base;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +0000806
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700807 switch (ext_phy_type) {
808 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
Eilon Greenstein589abe32009-02-12 08:36:55 +0000809 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
Eilon Greenstein4d295db2009-07-21 05:47:47 +0000810 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
Eilon Greenstein589abe32009-02-12 08:36:55 +0000811 /* All MDC/MDIO is directed through single EMAC */
812 if (REG_RD(bp, NIG_REG_PORT_SWAP))
813 emac_base = GRCBASE_EMAC0;
814 else
815 emac_base = GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700816 break;
817 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Eilon Greenstein6378c022008-08-13 15:59:25 -0700818 emac_base = (port) ? GRCBASE_EMAC0 : GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700819 break;
820 default:
Eilon Greenstein6378c022008-08-13 15:59:25 -0700821 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700822 break;
823 }
824 return emac_base;
825
826}
827
828u8 bnx2x_cl45_write(struct bnx2x *bp, u8 port, u32 ext_phy_type,
829 u8 phy_addr, u8 devad, u16 reg, u16 val)
830{
831 u32 tmp, saved_mode;
832 u8 i, rc = 0;
Eilon Greenstein589abe32009-02-12 08:36:55 +0000833 u32 mdio_ctrl = bnx2x_get_emac_base(bp, ext_phy_type, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700834
835 /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
836 * (a value of 49==0x31) and make sure that the AUTO poll is off
837 */
Eilon Greenstein589abe32009-02-12 08:36:55 +0000838
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700839 saved_mode = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
840 tmp = saved_mode & ~(EMAC_MDIO_MODE_AUTO_POLL |
841 EMAC_MDIO_MODE_CLOCK_CNT);
842 tmp |= (EMAC_MDIO_MODE_CLAUSE_45 |
843 (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
844 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, tmp);
845 REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
846 udelay(40);
847
848 /* address */
849
850 tmp = ((phy_addr << 21) | (devad << 16) | reg |
851 EMAC_MDIO_COMM_COMMAND_ADDRESS |
852 EMAC_MDIO_COMM_START_BUSY);
853 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
854
855 for (i = 0; i < 50; i++) {
856 udelay(10);
857
858 tmp = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
859 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
860 udelay(5);
861 break;
862 }
863 }
864 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
865 DP(NETIF_MSG_LINK, "write phy register failed\n");
866 rc = -EFAULT;
867 } else {
868 /* data */
869 tmp = ((phy_addr << 21) | (devad << 16) | val |
870 EMAC_MDIO_COMM_COMMAND_WRITE_45 |
871 EMAC_MDIO_COMM_START_BUSY);
872 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
873
874 for (i = 0; i < 50; i++) {
875 udelay(10);
876
877 tmp = REG_RD(bp, mdio_ctrl +
878 EMAC_REG_EMAC_MDIO_COMM);
879 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
880 udelay(5);
881 break;
882 }
883 }
884 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
885 DP(NETIF_MSG_LINK, "write phy register failed\n");
886 rc = -EFAULT;
887 }
888 }
889
890 /* Restore the saved mode */
891 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
892
893 return rc;
894}
895
896u8 bnx2x_cl45_read(struct bnx2x *bp, u8 port, u32 ext_phy_type,
897 u8 phy_addr, u8 devad, u16 reg, u16 *ret_val)
898{
899 u32 val, saved_mode;
900 u16 i;
901 u8 rc = 0;
902
Eilon Greenstein589abe32009-02-12 08:36:55 +0000903 u32 mdio_ctrl = bnx2x_get_emac_base(bp, ext_phy_type, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700904 /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
905 * (a value of 49==0x31) and make sure that the AUTO poll is off
906 */
Eilon Greenstein589abe32009-02-12 08:36:55 +0000907
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700908 saved_mode = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
909 val = saved_mode & ((EMAC_MDIO_MODE_AUTO_POLL |
910 EMAC_MDIO_MODE_CLOCK_CNT));
911 val |= (EMAC_MDIO_MODE_CLAUSE_45 |
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +0000912 (49L << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700913 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, val);
914 REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
915 udelay(40);
916
917 /* address */
918 val = ((phy_addr << 21) | (devad << 16) | reg |
919 EMAC_MDIO_COMM_COMMAND_ADDRESS |
920 EMAC_MDIO_COMM_START_BUSY);
921 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
922
923 for (i = 0; i < 50; i++) {
924 udelay(10);
925
926 val = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
927 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
928 udelay(5);
929 break;
930 }
931 }
932 if (val & EMAC_MDIO_COMM_START_BUSY) {
933 DP(NETIF_MSG_LINK, "read phy register failed\n");
934
935 *ret_val = 0;
936 rc = -EFAULT;
937
938 } else {
939 /* data */
940 val = ((phy_addr << 21) | (devad << 16) |
941 EMAC_MDIO_COMM_COMMAND_READ_45 |
942 EMAC_MDIO_COMM_START_BUSY);
943 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
944
945 for (i = 0; i < 50; i++) {
946 udelay(10);
947
948 val = REG_RD(bp, mdio_ctrl +
949 EMAC_REG_EMAC_MDIO_COMM);
950 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
951 *ret_val = (u16)(val & EMAC_MDIO_COMM_DATA);
952 break;
953 }
954 }
955 if (val & EMAC_MDIO_COMM_START_BUSY) {
956 DP(NETIF_MSG_LINK, "read phy register failed\n");
957
958 *ret_val = 0;
959 rc = -EFAULT;
960 }
961 }
962
963 /* Restore the saved mode */
964 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
965
966 return rc;
967}
968
969static void bnx2x_set_aer_mmd(struct link_params *params,
970 struct link_vars *vars)
971{
972 struct bnx2x *bp = params->bp;
973 u32 ser_lane;
974 u16 offset;
975
976 ser_lane = ((params->lane_config &
977 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
978 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
979
980 offset = (vars->phy_flags & PHY_XGXS_FLAG) ?
981 (params->phy_addr + ser_lane) : 0;
982
983 CL45_WR_OVER_CL22(bp, params->port,
984 params->phy_addr,
985 MDIO_REG_BANK_AER_BLOCK,
986 MDIO_AER_BLOCK_AER_REG, 0x3800 + offset);
987}
988
989static void bnx2x_set_master_ln(struct link_params *params)
990{
991 struct bnx2x *bp = params->bp;
992 u16 new_master_ln, ser_lane;
993 ser_lane = ((params->lane_config &
994 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
995 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
996
997 /* set the master_ln for AN */
998 CL45_RD_OVER_CL22(bp, params->port,
999 params->phy_addr,
1000 MDIO_REG_BANK_XGXS_BLOCK2,
1001 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
1002 &new_master_ln);
1003
1004 CL45_WR_OVER_CL22(bp, params->port,
1005 params->phy_addr,
1006 MDIO_REG_BANK_XGXS_BLOCK2 ,
1007 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
1008 (new_master_ln | ser_lane));
1009}
1010
1011static u8 bnx2x_reset_unicore(struct link_params *params)
1012{
1013 struct bnx2x *bp = params->bp;
1014 u16 mii_control;
1015 u16 i;
1016
1017 CL45_RD_OVER_CL22(bp, params->port,
1018 params->phy_addr,
1019 MDIO_REG_BANK_COMBO_IEEE0,
1020 MDIO_COMBO_IEEE0_MII_CONTROL, &mii_control);
1021
1022 /* reset the unicore */
1023 CL45_WR_OVER_CL22(bp, params->port,
1024 params->phy_addr,
1025 MDIO_REG_BANK_COMBO_IEEE0,
1026 MDIO_COMBO_IEEE0_MII_CONTROL,
1027 (mii_control |
1028 MDIO_COMBO_IEEO_MII_CONTROL_RESET));
Eilon Greenstein6f654972009-08-12 08:23:51 +00001029 if (params->switch_cfg == SWITCH_CFG_1G)
1030 bnx2x_set_serdes_access(params);
Eilon Greensteinc1b73992009-02-12 08:37:07 +00001031
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001032 /* wait for the reset to self clear */
1033 for (i = 0; i < MDIO_ACCESS_TIMEOUT; i++) {
1034 udelay(5);
1035
1036 /* the reset erased the previous bank value */
1037 CL45_RD_OVER_CL22(bp, params->port,
1038 params->phy_addr,
1039 MDIO_REG_BANK_COMBO_IEEE0,
1040 MDIO_COMBO_IEEE0_MII_CONTROL,
1041 &mii_control);
1042
1043 if (!(mii_control & MDIO_COMBO_IEEO_MII_CONTROL_RESET)) {
1044 udelay(5);
1045 return 0;
1046 }
1047 }
1048
1049 DP(NETIF_MSG_LINK, "BUG! XGXS is still in reset!\n");
1050 return -EINVAL;
1051
1052}
1053
1054static void bnx2x_set_swap_lanes(struct link_params *params)
1055{
1056 struct bnx2x *bp = params->bp;
1057 /* Each two bits represents a lane number:
1058 No swap is 0123 => 0x1b no need to enable the swap */
1059 u16 ser_lane, rx_lane_swap, tx_lane_swap;
1060
1061 ser_lane = ((params->lane_config &
1062 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
1063 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
1064 rx_lane_swap = ((params->lane_config &
1065 PORT_HW_CFG_LANE_SWAP_CFG_RX_MASK) >>
1066 PORT_HW_CFG_LANE_SWAP_CFG_RX_SHIFT);
1067 tx_lane_swap = ((params->lane_config &
1068 PORT_HW_CFG_LANE_SWAP_CFG_TX_MASK) >>
1069 PORT_HW_CFG_LANE_SWAP_CFG_TX_SHIFT);
1070
1071 if (rx_lane_swap != 0x1b) {
1072 CL45_WR_OVER_CL22(bp, params->port,
1073 params->phy_addr,
1074 MDIO_REG_BANK_XGXS_BLOCK2,
1075 MDIO_XGXS_BLOCK2_RX_LN_SWAP,
1076 (rx_lane_swap |
1077 MDIO_XGXS_BLOCK2_RX_LN_SWAP_ENABLE |
1078 MDIO_XGXS_BLOCK2_RX_LN_SWAP_FORCE_ENABLE));
1079 } else {
1080 CL45_WR_OVER_CL22(bp, params->port,
1081 params->phy_addr,
1082 MDIO_REG_BANK_XGXS_BLOCK2,
1083 MDIO_XGXS_BLOCK2_RX_LN_SWAP, 0);
1084 }
1085
1086 if (tx_lane_swap != 0x1b) {
1087 CL45_WR_OVER_CL22(bp, params->port,
1088 params->phy_addr,
1089 MDIO_REG_BANK_XGXS_BLOCK2,
1090 MDIO_XGXS_BLOCK2_TX_LN_SWAP,
1091 (tx_lane_swap |
1092 MDIO_XGXS_BLOCK2_TX_LN_SWAP_ENABLE));
1093 } else {
1094 CL45_WR_OVER_CL22(bp, params->port,
1095 params->phy_addr,
1096 MDIO_REG_BANK_XGXS_BLOCK2,
1097 MDIO_XGXS_BLOCK2_TX_LN_SWAP, 0);
1098 }
1099}
1100
1101static void bnx2x_set_parallel_detection(struct link_params *params,
Eilon Greenstein3196a882008-08-13 15:58:49 -07001102 u8 phy_flags)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001103{
1104 struct bnx2x *bp = params->bp;
1105 u16 control2;
1106
1107 CL45_RD_OVER_CL22(bp, params->port,
1108 params->phy_addr,
1109 MDIO_REG_BANK_SERDES_DIGITAL,
1110 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
1111 &control2);
Yaniv Rosner18afb0a2009-11-05 19:18:04 +02001112 if (params->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
1113 control2 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
1114 else
1115 control2 &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
1116 DP(NETIF_MSG_LINK, "params->speed_cap_mask = 0x%x, control2 = 0x%x\n",
1117 params->speed_cap_mask, control2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001118 CL45_WR_OVER_CL22(bp, params->port,
1119 params->phy_addr,
1120 MDIO_REG_BANK_SERDES_DIGITAL,
1121 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
1122 control2);
1123
Yaniv Rosner18afb0a2009-11-05 19:18:04 +02001124 if ((phy_flags & PHY_XGXS_FLAG) &&
1125 (params->speed_cap_mask &
1126 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001127 DP(NETIF_MSG_LINK, "XGXS\n");
1128
1129 CL45_WR_OVER_CL22(bp, params->port,
1130 params->phy_addr,
1131 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1132 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK,
1133 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT);
1134
1135 CL45_RD_OVER_CL22(bp, params->port,
1136 params->phy_addr,
1137 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1138 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
1139 &control2);
1140
1141
1142 control2 |=
1143 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN;
1144
1145 CL45_WR_OVER_CL22(bp, params->port,
1146 params->phy_addr,
1147 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1148 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
1149 control2);
1150
1151 /* Disable parallel detection of HiG */
1152 CL45_WR_OVER_CL22(bp, params->port,
1153 params->phy_addr,
1154 MDIO_REG_BANK_XGXS_BLOCK2,
1155 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G,
1156 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_CX4_XGXS |
1157 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_HIGIG_XGXS);
1158 }
1159}
1160
1161static void bnx2x_set_autoneg(struct link_params *params,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001162 struct link_vars *vars,
1163 u8 enable_cl73)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001164{
1165 struct bnx2x *bp = params->bp;
1166 u16 reg_val;
1167
1168 /* CL37 Autoneg */
1169
1170 CL45_RD_OVER_CL22(bp, params->port,
1171 params->phy_addr,
1172 MDIO_REG_BANK_COMBO_IEEE0,
1173 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
1174
1175 /* CL37 Autoneg Enabled */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001176 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001177 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_AN_EN;
1178 else /* CL37 Autoneg Disabled */
1179 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1180 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN);
1181
1182 CL45_WR_OVER_CL22(bp, params->port,
1183 params->phy_addr,
1184 MDIO_REG_BANK_COMBO_IEEE0,
1185 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
1186
1187 /* Enable/Disable Autodetection */
1188
1189 CL45_RD_OVER_CL22(bp, params->port,
1190 params->phy_addr,
1191 MDIO_REG_BANK_SERDES_DIGITAL,
1192 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, &reg_val);
Eilon Greenstein239d6862009-08-12 08:23:04 +00001193 reg_val &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN |
1194 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT);
1195 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001196 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001197 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
1198 else
1199 reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
1200
1201 CL45_WR_OVER_CL22(bp, params->port,
1202 params->phy_addr,
1203 MDIO_REG_BANK_SERDES_DIGITAL,
1204 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, reg_val);
1205
1206 /* Enable TetonII and BAM autoneg */
1207 CL45_RD_OVER_CL22(bp, params->port,
1208 params->phy_addr,
1209 MDIO_REG_BANK_BAM_NEXT_PAGE,
1210 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
1211 &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001212 if (vars->line_speed == SPEED_AUTO_NEG) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001213 /* Enable BAM aneg Mode and TetonII aneg Mode */
1214 reg_val |= (MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
1215 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
1216 } else {
1217 /* TetonII and BAM Autoneg Disabled */
1218 reg_val &= ~(MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
1219 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
1220 }
1221 CL45_WR_OVER_CL22(bp, params->port,
1222 params->phy_addr,
1223 MDIO_REG_BANK_BAM_NEXT_PAGE,
1224 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
1225 reg_val);
1226
Eilon Greenstein239d6862009-08-12 08:23:04 +00001227 if (enable_cl73) {
1228 /* Enable Cl73 FSM status bits */
1229 CL45_WR_OVER_CL22(bp, params->port,
1230 params->phy_addr,
1231 MDIO_REG_BANK_CL73_USERB0,
1232 MDIO_CL73_USERB0_CL73_UCTRL,
Yaniv Rosner7846e472009-11-05 19:18:07 +02001233 0xe);
Eilon Greenstein239d6862009-08-12 08:23:04 +00001234
1235 /* Enable BAM Station Manager*/
1236 CL45_WR_OVER_CL22(bp, params->port,
1237 params->phy_addr,
1238 MDIO_REG_BANK_CL73_USERB0,
1239 MDIO_CL73_USERB0_CL73_BAM_CTRL1,
1240 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN |
1241 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_STATION_MNGR_EN |
1242 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN);
1243
Yaniv Rosner7846e472009-11-05 19:18:07 +02001244 /* Advertise CL73 link speeds */
Eilon Greenstein239d6862009-08-12 08:23:04 +00001245 CL45_RD_OVER_CL22(bp, params->port,
1246 params->phy_addr,
1247 MDIO_REG_BANK_CL73_IEEEB1,
1248 MDIO_CL73_IEEEB1_AN_ADV2,
1249 &reg_val);
Yaniv Rosner7846e472009-11-05 19:18:07 +02001250 if (params->speed_cap_mask &
1251 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
1252 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4;
1253 if (params->speed_cap_mask &
1254 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
1255 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX;
Eilon Greenstein239d6862009-08-12 08:23:04 +00001256
Julia Lawallcc817352010-08-05 10:26:38 +00001257 CL45_WR_OVER_CL22(bp, params->port,
1258 params->phy_addr,
1259 MDIO_REG_BANK_CL73_IEEEB1,
1260 MDIO_CL73_IEEEB1_AN_ADV2,
1261 reg_val);
Eilon Greenstein239d6862009-08-12 08:23:04 +00001262
Eilon Greenstein239d6862009-08-12 08:23:04 +00001263 /* CL73 Autoneg Enabled */
1264 reg_val = MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN;
1265
1266 } else /* CL73 Autoneg Disabled */
1267 reg_val = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001268
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001269 CL45_WR_OVER_CL22(bp, params->port,
1270 params->phy_addr,
1271 MDIO_REG_BANK_CL73_IEEEB0,
1272 MDIO_CL73_IEEEB0_CL73_AN_CONTROL, reg_val);
1273}
1274
1275/* program SerDes, forced speed */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001276static void bnx2x_program_serdes(struct link_params *params,
1277 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001278{
1279 struct bnx2x *bp = params->bp;
1280 u16 reg_val;
1281
Eilon Greenstein57937202009-08-12 08:23:53 +00001282 /* program duplex, disable autoneg and sgmii*/
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001283 CL45_RD_OVER_CL22(bp, params->port,
1284 params->phy_addr,
1285 MDIO_REG_BANK_COMBO_IEEE0,
1286 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
1287 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX |
Eilon Greenstein57937202009-08-12 08:23:53 +00001288 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1289 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001290 if (params->req_duplex == DUPLEX_FULL)
1291 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
1292 CL45_WR_OVER_CL22(bp, params->port,
1293 params->phy_addr,
1294 MDIO_REG_BANK_COMBO_IEEE0,
1295 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
1296
1297 /* program speed
1298 - needed only if the speed is greater than 1G (2.5G or 10G) */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001299 CL45_RD_OVER_CL22(bp, params->port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001300 params->phy_addr,
1301 MDIO_REG_BANK_SERDES_DIGITAL,
1302 MDIO_SERDES_DIGITAL_MISC1, &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001303 /* clearing the speed value before setting the right speed */
1304 DP(NETIF_MSG_LINK, "MDIO_REG_BANK_SERDES_DIGITAL = 0x%x\n", reg_val);
1305
1306 reg_val &= ~(MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_MASK |
1307 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
1308
1309 if (!((vars->line_speed == SPEED_1000) ||
1310 (vars->line_speed == SPEED_100) ||
1311 (vars->line_speed == SPEED_10))) {
1312
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001313 reg_val |= (MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_156_25M |
1314 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001315 if (vars->line_speed == SPEED_10000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001316 reg_val |=
1317 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_10G_CX4;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001318 if (vars->line_speed == SPEED_13000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001319 reg_val |=
1320 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_13G;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001321 }
1322
1323 CL45_WR_OVER_CL22(bp, params->port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001324 params->phy_addr,
1325 MDIO_REG_BANK_SERDES_DIGITAL,
1326 MDIO_SERDES_DIGITAL_MISC1, reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001327
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001328}
1329
1330static void bnx2x_set_brcm_cl37_advertisment(struct link_params *params)
1331{
1332 struct bnx2x *bp = params->bp;
1333 u16 val = 0;
1334
1335 /* configure the 48 bits for BAM AN */
1336
1337 /* set extended capabilities */
1338 if (params->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G)
1339 val |= MDIO_OVER_1G_UP1_2_5G;
1340 if (params->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
1341 val |= MDIO_OVER_1G_UP1_10G;
1342 CL45_WR_OVER_CL22(bp, params->port,
1343 params->phy_addr,
1344 MDIO_REG_BANK_OVER_1G,
1345 MDIO_OVER_1G_UP1, val);
1346
1347 CL45_WR_OVER_CL22(bp, params->port,
1348 params->phy_addr,
1349 MDIO_REG_BANK_OVER_1G,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001350 MDIO_OVER_1G_UP3, 0x400);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001351}
1352
Eilon Greenstein1ef70b92009-08-12 08:23:59 +00001353static void bnx2x_calc_ieee_aneg_adv(struct link_params *params, u16 *ieee_fc)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001354{
Yaniv Rosnerd5cb9e92009-11-05 19:18:10 +02001355 struct bnx2x *bp = params->bp;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001356 *ieee_fc = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001357 /* resolve pause mode and advertisement
1358 * Please refer to Table 28B-3 of the 802.3ab-1999 spec */
1359
1360 switch (params->req_flow_ctrl) {
David S. Millerc0700f92008-12-16 23:53:20 -08001361 case BNX2X_FLOW_CTRL_AUTO:
1362 if (params->req_fc_auto_adv == BNX2X_FLOW_CTRL_BOTH) {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001363 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001364 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
1365 } else {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001366 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001367 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
1368 }
1369 break;
David S. Millerc0700f92008-12-16 23:53:20 -08001370 case BNX2X_FLOW_CTRL_TX:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001371 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001372 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
1373 break;
1374
David S. Millerc0700f92008-12-16 23:53:20 -08001375 case BNX2X_FLOW_CTRL_RX:
1376 case BNX2X_FLOW_CTRL_BOTH:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001377 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001378 break;
1379
David S. Millerc0700f92008-12-16 23:53:20 -08001380 case BNX2X_FLOW_CTRL_NONE:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001381 default:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001382 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001383 break;
1384 }
Yaniv Rosnerd5cb9e92009-11-05 19:18:10 +02001385 DP(NETIF_MSG_LINK, "ieee_fc = 0x%x\n", *ieee_fc);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001386}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001387
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001388static void bnx2x_set_ieee_aneg_advertisment(struct link_params *params,
Eilon Greenstein1ef70b92009-08-12 08:23:59 +00001389 u16 ieee_fc)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001390{
1391 struct bnx2x *bp = params->bp;
Yaniv Rosner7846e472009-11-05 19:18:07 +02001392 u16 val;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001393 /* for AN, we are always publishing full duplex */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001394
1395 CL45_WR_OVER_CL22(bp, params->port,
1396 params->phy_addr,
1397 MDIO_REG_BANK_COMBO_IEEE0,
Eilon Greenstein1ef70b92009-08-12 08:23:59 +00001398 MDIO_COMBO_IEEE0_AUTO_NEG_ADV, ieee_fc);
Yaniv Rosner7846e472009-11-05 19:18:07 +02001399 CL45_RD_OVER_CL22(bp, params->port,
1400 params->phy_addr,
1401 MDIO_REG_BANK_CL73_IEEEB1,
1402 MDIO_CL73_IEEEB1_AN_ADV1, &val);
1403 val &= ~MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_BOTH;
1404 val |= ((ieee_fc<<3) & MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK);
1405 CL45_WR_OVER_CL22(bp, params->port,
1406 params->phy_addr,
1407 MDIO_REG_BANK_CL73_IEEEB1,
1408 MDIO_CL73_IEEEB1_AN_ADV1, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001409}
1410
Eilon Greenstein239d6862009-08-12 08:23:04 +00001411static void bnx2x_restart_autoneg(struct link_params *params, u8 enable_cl73)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001412{
1413 struct bnx2x *bp = params->bp;
Eilon Greenstein3a36f2e2009-02-12 08:37:09 +00001414 u16 mii_control;
Eilon Greenstein239d6862009-08-12 08:23:04 +00001415
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001416 DP(NETIF_MSG_LINK, "bnx2x_restart_autoneg\n");
Eilon Greenstein3a36f2e2009-02-12 08:37:09 +00001417 /* Enable and restart BAM/CL37 aneg */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001418
Eilon Greenstein239d6862009-08-12 08:23:04 +00001419 if (enable_cl73) {
1420 CL45_RD_OVER_CL22(bp, params->port,
1421 params->phy_addr,
1422 MDIO_REG_BANK_CL73_IEEEB0,
1423 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1424 &mii_control);
1425
1426 CL45_WR_OVER_CL22(bp, params->port,
1427 params->phy_addr,
1428 MDIO_REG_BANK_CL73_IEEEB0,
1429 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1430 (mii_control |
1431 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN |
1432 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN));
1433 } else {
1434
1435 CL45_RD_OVER_CL22(bp, params->port,
1436 params->phy_addr,
1437 MDIO_REG_BANK_COMBO_IEEE0,
1438 MDIO_COMBO_IEEE0_MII_CONTROL,
1439 &mii_control);
1440 DP(NETIF_MSG_LINK,
1441 "bnx2x_restart_autoneg mii_control before = 0x%x\n",
1442 mii_control);
1443 CL45_WR_OVER_CL22(bp, params->port,
1444 params->phy_addr,
1445 MDIO_REG_BANK_COMBO_IEEE0,
1446 MDIO_COMBO_IEEE0_MII_CONTROL,
1447 (mii_control |
1448 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1449 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN));
1450 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001451}
1452
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001453static void bnx2x_initialize_sgmii_process(struct link_params *params,
1454 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001455{
1456 struct bnx2x *bp = params->bp;
1457 u16 control1;
1458
1459 /* in SGMII mode, the unicore is always slave */
1460
1461 CL45_RD_OVER_CL22(bp, params->port,
1462 params->phy_addr,
1463 MDIO_REG_BANK_SERDES_DIGITAL,
1464 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
1465 &control1);
1466 control1 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT;
1467 /* set sgmii mode (and not fiber) */
1468 control1 &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE |
1469 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET |
1470 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_MSTR_MODE);
1471 CL45_WR_OVER_CL22(bp, params->port,
1472 params->phy_addr,
1473 MDIO_REG_BANK_SERDES_DIGITAL,
1474 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
1475 control1);
1476
1477 /* if forced speed */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001478 if (!(vars->line_speed == SPEED_AUTO_NEG)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001479 /* set speed, disable autoneg */
1480 u16 mii_control;
1481
1482 CL45_RD_OVER_CL22(bp, params->port,
1483 params->phy_addr,
1484 MDIO_REG_BANK_COMBO_IEEE0,
1485 MDIO_COMBO_IEEE0_MII_CONTROL,
1486 &mii_control);
1487 mii_control &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1488 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK|
1489 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX);
1490
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001491 switch (vars->line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001492 case SPEED_100:
1493 mii_control |=
1494 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_100;
1495 break;
1496 case SPEED_1000:
1497 mii_control |=
1498 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_1000;
1499 break;
1500 case SPEED_10:
1501 /* there is nothing to set for 10M */
1502 break;
1503 default:
1504 /* invalid speed for SGMII */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001505 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
1506 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001507 break;
1508 }
1509
1510 /* setting the full duplex */
1511 if (params->req_duplex == DUPLEX_FULL)
1512 mii_control |=
1513 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
1514 CL45_WR_OVER_CL22(bp, params->port,
1515 params->phy_addr,
1516 MDIO_REG_BANK_COMBO_IEEE0,
1517 MDIO_COMBO_IEEE0_MII_CONTROL,
1518 mii_control);
1519
1520 } else { /* AN mode */
1521 /* enable and restart AN */
Eilon Greenstein239d6862009-08-12 08:23:04 +00001522 bnx2x_restart_autoneg(params, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001523 }
1524}
1525
1526
1527/*
1528 * link management
1529 */
1530
1531static void bnx2x_pause_resolve(struct link_vars *vars, u32 pause_result)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001532{ /* LD LP */
1533 switch (pause_result) { /* ASYM P ASYM P */
1534 case 0xb: /* 1 0 1 1 */
David S. Millerc0700f92008-12-16 23:53:20 -08001535 vars->flow_ctrl = BNX2X_FLOW_CTRL_TX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001536 break;
1537
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001538 case 0xe: /* 1 1 1 0 */
David S. Millerc0700f92008-12-16 23:53:20 -08001539 vars->flow_ctrl = BNX2X_FLOW_CTRL_RX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001540 break;
1541
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001542 case 0x5: /* 0 1 0 1 */
1543 case 0x7: /* 0 1 1 1 */
1544 case 0xd: /* 1 1 0 1 */
1545 case 0xf: /* 1 1 1 1 */
David S. Millerc0700f92008-12-16 23:53:20 -08001546 vars->flow_ctrl = BNX2X_FLOW_CTRL_BOTH;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001547 break;
1548
1549 default:
1550 break;
1551 }
1552}
1553
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00001554static u8 bnx2x_ext_phy_resolve_fc(struct link_params *params,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001555 struct link_vars *vars)
1556{
1557 struct bnx2x *bp = params->bp;
1558 u8 ext_phy_addr;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00001559 u16 ld_pause; /* local */
1560 u16 lp_pause; /* link partner */
1561 u16 an_complete; /* AN complete */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001562 u16 pause_result;
1563 u8 ret = 0;
1564 u32 ext_phy_type;
1565 u8 port = params->port;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00001566 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001567 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
1568 /* read twice */
1569
1570 bnx2x_cl45_read(bp, port,
1571 ext_phy_type,
1572 ext_phy_addr,
1573 MDIO_AN_DEVAD,
1574 MDIO_AN_REG_STATUS, &an_complete);
1575 bnx2x_cl45_read(bp, port,
1576 ext_phy_type,
1577 ext_phy_addr,
1578 MDIO_AN_DEVAD,
1579 MDIO_AN_REG_STATUS, &an_complete);
1580
1581 if (an_complete & MDIO_AN_REG_STATUS_AN_COMPLETE) {
1582 ret = 1;
1583 bnx2x_cl45_read(bp, port,
1584 ext_phy_type,
1585 ext_phy_addr,
1586 MDIO_AN_DEVAD,
1587 MDIO_AN_REG_ADV_PAUSE, &ld_pause);
1588 bnx2x_cl45_read(bp, port,
1589 ext_phy_type,
1590 ext_phy_addr,
1591 MDIO_AN_DEVAD,
1592 MDIO_AN_REG_LP_AUTO_NEG, &lp_pause);
1593 pause_result = (ld_pause &
1594 MDIO_AN_REG_ADV_PAUSE_MASK) >> 8;
1595 pause_result |= (lp_pause &
1596 MDIO_AN_REG_ADV_PAUSE_MASK) >> 10;
Frans Pop2381a552010-03-24 07:57:36 +00001597 DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x\n",
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001598 pause_result);
1599 bnx2x_pause_resolve(vars, pause_result);
David S. Millerc0700f92008-12-16 23:53:20 -08001600 if (vars->flow_ctrl == BNX2X_FLOW_CTRL_NONE &&
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001601 ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
1602 bnx2x_cl45_read(bp, port,
1603 ext_phy_type,
1604 ext_phy_addr,
1605 MDIO_AN_DEVAD,
1606 MDIO_AN_REG_CL37_FC_LD, &ld_pause);
1607
1608 bnx2x_cl45_read(bp, port,
1609 ext_phy_type,
1610 ext_phy_addr,
1611 MDIO_AN_DEVAD,
1612 MDIO_AN_REG_CL37_FC_LP, &lp_pause);
1613 pause_result = (ld_pause &
1614 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 5;
1615 pause_result |= (lp_pause &
1616 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 7;
1617
1618 bnx2x_pause_resolve(vars, pause_result);
Frans Pop2381a552010-03-24 07:57:36 +00001619 DP(NETIF_MSG_LINK, "Ext PHY CL37 pause result 0x%x\n",
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001620 pause_result);
1621 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001622 }
1623 return ret;
1624}
1625
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02001626static u8 bnx2x_direct_parallel_detect_used(struct link_params *params)
1627{
1628 struct bnx2x *bp = params->bp;
1629 u16 pd_10g, status2_1000x;
1630 CL45_RD_OVER_CL22(bp, params->port,
1631 params->phy_addr,
1632 MDIO_REG_BANK_SERDES_DIGITAL,
1633 MDIO_SERDES_DIGITAL_A_1000X_STATUS2,
1634 &status2_1000x);
1635 CL45_RD_OVER_CL22(bp, params->port,
1636 params->phy_addr,
1637 MDIO_REG_BANK_SERDES_DIGITAL,
1638 MDIO_SERDES_DIGITAL_A_1000X_STATUS2,
1639 &status2_1000x);
1640 if (status2_1000x & MDIO_SERDES_DIGITAL_A_1000X_STATUS2_AN_DISABLED) {
1641 DP(NETIF_MSG_LINK, "1G parallel detect link on port %d\n",
1642 params->port);
1643 return 1;
1644 }
1645
1646 CL45_RD_OVER_CL22(bp, params->port,
1647 params->phy_addr,
1648 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1649 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_STATUS,
1650 &pd_10g);
1651
1652 if (pd_10g & MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_STATUS_PD_LINK) {
1653 DP(NETIF_MSG_LINK, "10G parallel detect link on port %d\n",
1654 params->port);
1655 return 1;
1656 }
1657 return 0;
1658}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001659
1660static void bnx2x_flow_ctrl_resolve(struct link_params *params,
1661 struct link_vars *vars,
1662 u32 gp_status)
1663{
1664 struct bnx2x *bp = params->bp;
Eilon Greenstein3196a882008-08-13 15:58:49 -07001665 u16 ld_pause; /* local driver */
1666 u16 lp_pause; /* link partner */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001667 u16 pause_result;
1668
David S. Millerc0700f92008-12-16 23:53:20 -08001669 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001670
1671 /* resolve from gp_status in case of AN complete and not sgmii */
David S. Millerc0700f92008-12-16 23:53:20 -08001672 if ((params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) &&
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001673 (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) &&
1674 (!(vars->phy_flags & PHY_SGMII_FLAG)) &&
1675 (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
1676 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT)) {
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02001677 if (bnx2x_direct_parallel_detect_used(params)) {
1678 vars->flow_ctrl = params->req_fc_auto_adv;
1679 return;
1680 }
Yaniv Rosner7846e472009-11-05 19:18:07 +02001681 if ((gp_status &
1682 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
1683 MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) ==
1684 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
1685 MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) {
1686
1687 CL45_RD_OVER_CL22(bp, params->port,
1688 params->phy_addr,
1689 MDIO_REG_BANK_CL73_IEEEB1,
1690 MDIO_CL73_IEEEB1_AN_ADV1,
1691 &ld_pause);
1692 CL45_RD_OVER_CL22(bp, params->port,
1693 params->phy_addr,
1694 MDIO_REG_BANK_CL73_IEEEB1,
1695 MDIO_CL73_IEEEB1_AN_LP_ADV1,
1696 &lp_pause);
1697 pause_result = (ld_pause &
1698 MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK)
1699 >> 8;
1700 pause_result |= (lp_pause &
1701 MDIO_CL73_IEEEB1_AN_LP_ADV1_PAUSE_MASK)
1702 >> 10;
1703 DP(NETIF_MSG_LINK, "pause_result CL73 0x%x\n",
1704 pause_result);
1705 } else {
1706
1707 CL45_RD_OVER_CL22(bp, params->port,
1708 params->phy_addr,
1709 MDIO_REG_BANK_COMBO_IEEE0,
1710 MDIO_COMBO_IEEE0_AUTO_NEG_ADV,
1711 &ld_pause);
1712 CL45_RD_OVER_CL22(bp, params->port,
1713 params->phy_addr,
1714 MDIO_REG_BANK_COMBO_IEEE0,
1715 MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1,
1716 &lp_pause);
1717 pause_result = (ld_pause &
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001718 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>5;
Yaniv Rosner7846e472009-11-05 19:18:07 +02001719 pause_result |= (lp_pause &
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001720 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7;
Yaniv Rosner7846e472009-11-05 19:18:07 +02001721 DP(NETIF_MSG_LINK, "pause_result CL37 0x%x\n",
1722 pause_result);
1723 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001724 bnx2x_pause_resolve(vars, pause_result);
David S. Millerc0700f92008-12-16 23:53:20 -08001725 } else if ((params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) &&
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00001726 (bnx2x_ext_phy_resolve_fc(params, vars))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001727 return;
1728 } else {
David S. Millerc0700f92008-12-16 23:53:20 -08001729 if (params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001730 vars->flow_ctrl = params->req_fc_auto_adv;
1731 else
1732 vars->flow_ctrl = params->req_flow_ctrl;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001733 }
1734 DP(NETIF_MSG_LINK, "flow_ctrl 0x%x\n", vars->flow_ctrl);
1735}
1736
Eilon Greenstein239d6862009-08-12 08:23:04 +00001737static void bnx2x_check_fallback_to_cl37(struct link_params *params)
1738{
1739 struct bnx2x *bp = params->bp;
1740 u16 rx_status, ustat_val, cl37_fsm_recieved;
1741 DP(NETIF_MSG_LINK, "bnx2x_check_fallback_to_cl37\n");
1742 /* Step 1: Make sure signal is detected */
1743 CL45_RD_OVER_CL22(bp, params->port,
1744 params->phy_addr,
1745 MDIO_REG_BANK_RX0,
1746 MDIO_RX0_RX_STATUS,
1747 &rx_status);
1748 if ((rx_status & MDIO_RX0_RX_STATUS_SIGDET) !=
1749 (MDIO_RX0_RX_STATUS_SIGDET)) {
1750 DP(NETIF_MSG_LINK, "Signal is not detected. Restoring CL73."
1751 "rx_status(0x80b0) = 0x%x\n", rx_status);
1752 CL45_WR_OVER_CL22(bp, params->port,
1753 params->phy_addr,
1754 MDIO_REG_BANK_CL73_IEEEB0,
1755 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1756 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN);
1757 return;
1758 }
1759 /* Step 2: Check CL73 state machine */
1760 CL45_RD_OVER_CL22(bp, params->port,
1761 params->phy_addr,
1762 MDIO_REG_BANK_CL73_USERB0,
1763 MDIO_CL73_USERB0_CL73_USTAT1,
1764 &ustat_val);
1765 if ((ustat_val &
1766 (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK |
1767 MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) !=
1768 (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK |
1769 MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) {
1770 DP(NETIF_MSG_LINK, "CL73 state-machine is not stable. "
1771 "ustat_val(0x8371) = 0x%x\n", ustat_val);
1772 return;
1773 }
1774 /* Step 3: Check CL37 Message Pages received to indicate LP
1775 supports only CL37 */
1776 CL45_RD_OVER_CL22(bp, params->port,
1777 params->phy_addr,
1778 MDIO_REG_BANK_REMOTE_PHY,
1779 MDIO_REMOTE_PHY_MISC_RX_STATUS,
1780 &cl37_fsm_recieved);
1781 if ((cl37_fsm_recieved &
1782 (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG |
1783 MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) !=
1784 (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG |
1785 MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) {
1786 DP(NETIF_MSG_LINK, "No CL37 FSM were received. "
1787 "misc_rx_status(0x8330) = 0x%x\n",
1788 cl37_fsm_recieved);
1789 return;
1790 }
1791 /* The combined cl37/cl73 fsm state information indicating that we are
1792 connected to a device which does not support cl73, but does support
1793 cl37 BAM. In this case we disable cl73 and restart cl37 auto-neg */
1794 /* Disable CL73 */
1795 CL45_WR_OVER_CL22(bp, params->port,
1796 params->phy_addr,
1797 MDIO_REG_BANK_CL73_IEEEB0,
1798 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1799 0);
1800 /* Restart CL37 autoneg */
1801 bnx2x_restart_autoneg(params, 0);
1802 DP(NETIF_MSG_LINK, "Disabling CL73, and restarting CL37 autoneg\n");
1803}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001804static u8 bnx2x_link_settings_status(struct link_params *params,
Eilon Greenstein2f904462009-08-12 08:22:16 +00001805 struct link_vars *vars,
1806 u32 gp_status,
1807 u8 ext_phy_link_up)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001808{
1809 struct bnx2x *bp = params->bp;
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001810 u16 new_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001811 u8 rc = 0;
1812 vars->link_status = 0;
1813
1814 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) {
1815 DP(NETIF_MSG_LINK, "phy link up gp_status=0x%x\n",
1816 gp_status);
1817
1818 vars->phy_link_up = 1;
1819 vars->link_status |= LINK_STATUS_LINK_UP;
1820
1821 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_DUPLEX_STATUS)
1822 vars->duplex = DUPLEX_FULL;
1823 else
1824 vars->duplex = DUPLEX_HALF;
1825
1826 bnx2x_flow_ctrl_resolve(params, vars, gp_status);
1827
1828 switch (gp_status & GP_STATUS_SPEED_MASK) {
1829 case GP_STATUS_10M:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001830 new_line_speed = SPEED_10;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001831 if (vars->duplex == DUPLEX_FULL)
1832 vars->link_status |= LINK_10TFD;
1833 else
1834 vars->link_status |= LINK_10THD;
1835 break;
1836
1837 case GP_STATUS_100M:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001838 new_line_speed = SPEED_100;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001839 if (vars->duplex == DUPLEX_FULL)
1840 vars->link_status |= LINK_100TXFD;
1841 else
1842 vars->link_status |= LINK_100TXHD;
1843 break;
1844
1845 case GP_STATUS_1G:
1846 case GP_STATUS_1G_KX:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001847 new_line_speed = SPEED_1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001848 if (vars->duplex == DUPLEX_FULL)
1849 vars->link_status |= LINK_1000TFD;
1850 else
1851 vars->link_status |= LINK_1000THD;
1852 break;
1853
1854 case GP_STATUS_2_5G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001855 new_line_speed = SPEED_2500;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001856 if (vars->duplex == DUPLEX_FULL)
1857 vars->link_status |= LINK_2500TFD;
1858 else
1859 vars->link_status |= LINK_2500THD;
1860 break;
1861
1862 case GP_STATUS_5G:
1863 case GP_STATUS_6G:
1864 DP(NETIF_MSG_LINK,
1865 "link speed unsupported gp_status 0x%x\n",
1866 gp_status);
1867 return -EINVAL;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00001868
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001869 case GP_STATUS_10G_KX4:
1870 case GP_STATUS_10G_HIG:
1871 case GP_STATUS_10G_CX4:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001872 new_line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001873 vars->link_status |= LINK_10GTFD;
1874 break;
1875
1876 case GP_STATUS_12G_HIG:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001877 new_line_speed = SPEED_12000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001878 vars->link_status |= LINK_12GTFD;
1879 break;
1880
1881 case GP_STATUS_12_5G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001882 new_line_speed = SPEED_12500;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001883 vars->link_status |= LINK_12_5GTFD;
1884 break;
1885
1886 case GP_STATUS_13G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001887 new_line_speed = SPEED_13000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001888 vars->link_status |= LINK_13GTFD;
1889 break;
1890
1891 case GP_STATUS_15G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001892 new_line_speed = SPEED_15000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001893 vars->link_status |= LINK_15GTFD;
1894 break;
1895
1896 case GP_STATUS_16G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001897 new_line_speed = SPEED_16000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001898 vars->link_status |= LINK_16GTFD;
1899 break;
1900
1901 default:
1902 DP(NETIF_MSG_LINK,
1903 "link speed unsupported gp_status 0x%x\n",
1904 gp_status);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00001905 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001906 }
1907
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001908 /* Upon link speed change set the NIG into drain mode.
1909 Comes to deals with possible FIFO glitch due to clk change
1910 when speed is decreased without link down indicator */
1911 if (new_line_speed != vars->line_speed) {
Eilon Greenstein2f904462009-08-12 08:22:16 +00001912 if (XGXS_EXT_PHY_TYPE(params->ext_phy_config) !=
1913 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT &&
1914 ext_phy_link_up) {
1915 DP(NETIF_MSG_LINK, "Internal link speed %d is"
1916 " different than the external"
1917 " link speed %d\n", new_line_speed,
1918 vars->line_speed);
1919 vars->phy_link_up = 0;
1920 return 0;
1921 }
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001922 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
1923 + params->port*4, 0);
1924 msleep(1);
1925 }
1926 vars->line_speed = new_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001927 vars->link_status |= LINK_STATUS_SERDES_LINK;
1928
Yaniv Rosner57963ed2008-08-13 15:55:28 -07001929 if ((params->req_line_speed == SPEED_AUTO_NEG) &&
1930 ((XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
1931 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ||
1932 (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
Eilon Greenstein589abe32009-02-12 08:36:55 +00001933 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) ||
1934 (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
Yaniv Rosnerb5bbf002009-11-05 19:18:21 +02001935 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706) ||
1936 (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
Eilon Greenstein2f904462009-08-12 08:22:16 +00001937 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001938 vars->autoneg = AUTO_NEG_ENABLED;
1939
1940 if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) {
1941 vars->autoneg |= AUTO_NEG_COMPLETE;
1942 vars->link_status |=
1943 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
1944 }
1945
1946 vars->autoneg |= AUTO_NEG_PARALLEL_DETECTION_USED;
1947 vars->link_status |=
1948 LINK_STATUS_PARALLEL_DETECTION_USED;
1949
1950 }
David S. Millerc0700f92008-12-16 23:53:20 -08001951 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001952 vars->link_status |=
1953 LINK_STATUS_TX_FLOW_CONTROL_ENABLED;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001954
David S. Millerc0700f92008-12-16 23:53:20 -08001955 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001956 vars->link_status |=
1957 LINK_STATUS_RX_FLOW_CONTROL_ENABLED;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001958
1959 } else { /* link_down */
1960 DP(NETIF_MSG_LINK, "phy link down\n");
1961
1962 vars->phy_link_up = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07001963
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001964 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08001965 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001966 vars->autoneg = AUTO_NEG_DISABLED;
1967 vars->mac_type = MAC_TYPE_NONE;
Eilon Greenstein239d6862009-08-12 08:23:04 +00001968
1969 if ((params->req_line_speed == SPEED_AUTO_NEG) &&
1970 ((XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
1971 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT))) {
1972 /* Check signal is detected */
1973 bnx2x_check_fallback_to_cl37(params);
1974 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001975 }
1976
Frans Pop2381a552010-03-24 07:57:36 +00001977 DP(NETIF_MSG_LINK, "gp_status 0x%x phy_link_up %x line_speed %x\n",
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001978 gp_status, vars->phy_link_up, vars->line_speed);
1979 DP(NETIF_MSG_LINK, "duplex %x flow_ctrl 0x%x"
1980 " autoneg 0x%x\n",
1981 vars->duplex,
1982 vars->flow_ctrl, vars->autoneg);
1983 DP(NETIF_MSG_LINK, "link_status 0x%x\n", vars->link_status);
1984
1985 return rc;
1986}
1987
Eilon Greensteined8680a2009-02-12 08:37:12 +00001988static void bnx2x_set_gmii_tx_driver(struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001989{
1990 struct bnx2x *bp = params->bp;
1991 u16 lp_up2;
1992 u16 tx_driver;
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00001993 u16 bank;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001994
1995 /* read precomp */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001996 CL45_RD_OVER_CL22(bp, params->port,
1997 params->phy_addr,
1998 MDIO_REG_BANK_OVER_1G,
1999 MDIO_OVER_1G_LP_UP2, &lp_up2);
2000
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002001 /* bits [10:7] at lp_up2, positioned at [15:12] */
2002 lp_up2 = (((lp_up2 & MDIO_OVER_1G_LP_UP2_PREEMPHASIS_MASK) >>
2003 MDIO_OVER_1G_LP_UP2_PREEMPHASIS_SHIFT) <<
2004 MDIO_TX0_TX_DRIVER_PREEMPHASIS_SHIFT);
2005
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00002006 if (lp_up2 == 0)
2007 return;
2008
2009 for (bank = MDIO_REG_BANK_TX0; bank <= MDIO_REG_BANK_TX3;
2010 bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0)) {
2011 CL45_RD_OVER_CL22(bp, params->port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002012 params->phy_addr,
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00002013 bank,
2014 MDIO_TX0_TX_DRIVER, &tx_driver);
2015
2016 /* replace tx_driver bits [15:12] */
2017 if (lp_up2 !=
2018 (tx_driver & MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK)) {
2019 tx_driver &= ~MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK;
2020 tx_driver |= lp_up2;
2021 CL45_WR_OVER_CL22(bp, params->port,
2022 params->phy_addr,
2023 bank,
2024 MDIO_TX0_TX_DRIVER, tx_driver);
2025 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002026 }
2027}
2028
2029static u8 bnx2x_emac_program(struct link_params *params,
2030 u32 line_speed, u32 duplex)
2031{
2032 struct bnx2x *bp = params->bp;
2033 u8 port = params->port;
2034 u16 mode = 0;
2035
2036 DP(NETIF_MSG_LINK, "setting link speed & duplex\n");
2037 bnx2x_bits_dis(bp, GRCBASE_EMAC0 + port*0x400 +
2038 EMAC_REG_EMAC_MODE,
2039 (EMAC_MODE_25G_MODE |
2040 EMAC_MODE_PORT_MII_10M |
2041 EMAC_MODE_HALF_DUPLEX));
2042 switch (line_speed) {
2043 case SPEED_10:
2044 mode |= EMAC_MODE_PORT_MII_10M;
2045 break;
2046
2047 case SPEED_100:
2048 mode |= EMAC_MODE_PORT_MII;
2049 break;
2050
2051 case SPEED_1000:
2052 mode |= EMAC_MODE_PORT_GMII;
2053 break;
2054
2055 case SPEED_2500:
2056 mode |= (EMAC_MODE_25G_MODE | EMAC_MODE_PORT_GMII);
2057 break;
2058
2059 default:
2060 /* 10G not valid for EMAC */
2061 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n", line_speed);
2062 return -EINVAL;
2063 }
2064
2065 if (duplex == DUPLEX_HALF)
2066 mode |= EMAC_MODE_HALF_DUPLEX;
2067 bnx2x_bits_en(bp,
2068 GRCBASE_EMAC0 + port*0x400 + EMAC_REG_EMAC_MODE,
2069 mode);
2070
Yaniv Rosner7846e472009-11-05 19:18:07 +02002071 bnx2x_set_led(params, LED_MODE_OPER, line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002072 return 0;
2073}
2074
2075/*****************************************************************************/
Eilon Greenstein17de50b2008-08-13 15:56:59 -07002076/* External Phy section */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002077/*****************************************************************************/
Eilon Greensteinf57a6022009-08-12 08:23:11 +00002078void bnx2x_ext_phy_hw_reset(struct bnx2x *bp, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002079{
2080 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07002081 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002082 msleep(1);
2083 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07002084 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002085}
2086
2087static void bnx2x_ext_phy_reset(struct link_params *params,
2088 struct link_vars *vars)
2089{
2090 struct bnx2x *bp = params->bp;
2091 u32 ext_phy_type;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00002092 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
2093
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002094 DP(NETIF_MSG_LINK, "Port %x: bnx2x_ext_phy_reset\n", params->port);
2095 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2096 /* The PHY reset is controled by GPIO 1
2097 * Give it 1ms of reset pulse
2098 */
2099 if (vars->phy_flags & PHY_XGXS_FLAG) {
2100
2101 switch (ext_phy_type) {
2102 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
2103 DP(NETIF_MSG_LINK, "XGXS Direct\n");
2104 break;
2105
2106 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
2107 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
2108 DP(NETIF_MSG_LINK, "XGXS 8705/8706\n");
2109
2110 /* Restore normal power mode*/
2111 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07002112 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
2113 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002114
2115 /* HW reset */
Eilon Greensteinf57a6022009-08-12 08:23:11 +00002116 bnx2x_ext_phy_hw_reset(bp, params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002117
2118 bnx2x_cl45_write(bp, params->port,
2119 ext_phy_type,
2120 ext_phy_addr,
2121 MDIO_PMA_DEVAD,
2122 MDIO_PMA_REG_CTRL, 0xa040);
2123 break;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002124
2125 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
2126 break;
2127
Eilon Greenstein589abe32009-02-12 08:36:55 +00002128 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
2129
2130 /* Restore normal power mode*/
2131 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
2132 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
2133 params->port);
2134
2135 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
2136 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
2137 params->port);
2138
2139 bnx2x_cl45_write(bp, params->port,
2140 ext_phy_type,
2141 ext_phy_addr,
2142 MDIO_PMA_DEVAD,
2143 MDIO_PMA_REG_CTRL,
2144 1<<15);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002145 break;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002146
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002147 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002148 DP(NETIF_MSG_LINK, "XGXS 8072\n");
2149
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002150 /* Unset Low Power Mode and SW reset */
2151 /* Restore normal power mode*/
2152 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07002153 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
2154 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002155
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002156 bnx2x_cl45_write(bp, params->port,
2157 ext_phy_type,
2158 ext_phy_addr,
2159 MDIO_PMA_DEVAD,
2160 MDIO_PMA_REG_CTRL,
2161 1<<15);
2162 break;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002163
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002164 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002165 DP(NETIF_MSG_LINK, "XGXS 8073\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002166
2167 /* Restore normal power mode*/
2168 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07002169 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
2170 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002171
2172 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07002173 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
2174 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002175 break;
2176
2177 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
2178 DP(NETIF_MSG_LINK, "XGXS SFX7101\n");
2179
2180 /* Restore normal power mode*/
2181 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07002182 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
2183 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002184
2185 /* HW reset */
Eilon Greensteinf57a6022009-08-12 08:23:11 +00002186 bnx2x_ext_phy_hw_reset(bp, params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002187 break;
2188
Eilon Greenstein28577182009-02-12 08:37:00 +00002189 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
Eilon Greenstein28577182009-02-12 08:37:00 +00002190 /* Restore normal power mode*/
2191 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
2192 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
2193 params->port);
2194
2195 /* HW reset */
Eilon Greensteinf57a6022009-08-12 08:23:11 +00002196 bnx2x_ext_phy_hw_reset(bp, params->port);
Eilon Greenstein28577182009-02-12 08:37:00 +00002197
2198 bnx2x_cl45_write(bp, params->port,
2199 ext_phy_type,
2200 ext_phy_addr,
2201 MDIO_PMA_DEVAD,
2202 MDIO_PMA_REG_CTRL,
2203 1<<15);
2204 break;
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02002205 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
2206 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002207 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
2208 DP(NETIF_MSG_LINK, "XGXS PHY Failure detected\n");
2209 break;
2210
2211 default:
2212 DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
2213 params->ext_phy_config);
2214 break;
2215 }
2216
2217 } else { /* SerDes */
2218 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
2219 switch (ext_phy_type) {
2220 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
2221 DP(NETIF_MSG_LINK, "SerDes Direct\n");
2222 break;
2223
2224 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
2225 DP(NETIF_MSG_LINK, "SerDes 5482\n");
Eilon Greensteinf57a6022009-08-12 08:23:11 +00002226 bnx2x_ext_phy_hw_reset(bp, params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002227 break;
2228
2229 default:
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002230 DP(NETIF_MSG_LINK, "BAD SerDes ext_phy_config 0x%x\n",
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002231 params->ext_phy_config);
2232 break;
2233 }
2234 }
2235}
2236
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002237static void bnx2x_save_spirom_version(struct bnx2x *bp, u8 port,
2238 u32 shmem_base, u32 spirom_ver)
2239{
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002240 DP(NETIF_MSG_LINK, "FW version 0x%x:0x%x for port %d\n",
2241 (u16)(spirom_ver>>16), (u16)spirom_ver, port);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002242 REG_WR(bp, shmem_base +
2243 offsetof(struct shmem_region,
2244 port_mb[port].ext_phy_fw_version),
2245 spirom_ver);
2246}
2247
2248static void bnx2x_save_bcm_spirom_ver(struct bnx2x *bp, u8 port,
2249 u32 ext_phy_type, u8 ext_phy_addr,
2250 u32 shmem_base)
2251{
2252 u16 fw_ver1, fw_ver2;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002253
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002254 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD,
2255 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
2256 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD,
2257 MDIO_PMA_REG_ROM_VER2, &fw_ver2);
2258 bnx2x_save_spirom_version(bp, port, shmem_base,
2259 (u32)(fw_ver1<<16 | fw_ver2));
2260}
2261
Eilon Greensteinb1607af2009-08-12 08:22:54 +00002262
2263static void bnx2x_save_8481_spirom_version(struct bnx2x *bp, u8 port,
2264 u8 ext_phy_addr, u32 shmem_base)
2265{
2266 u16 val, fw_ver1, fw_ver2, cnt;
2267 /* For the 32 bits registers in 8481, access via MDIO2ARM interface.*/
2268 /* (1) set register 0xc200_0014(SPI_BRIDGE_CTRL_2) to 0x03000000 */
2269 bnx2x_cl45_write(bp, port,
2270 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2271 ext_phy_addr, MDIO_PMA_DEVAD,
2272 0xA819, 0x0014);
2273 bnx2x_cl45_write(bp, port,
2274 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2275 ext_phy_addr,
2276 MDIO_PMA_DEVAD,
2277 0xA81A,
2278 0xc200);
2279 bnx2x_cl45_write(bp, port,
2280 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2281 ext_phy_addr,
2282 MDIO_PMA_DEVAD,
2283 0xA81B,
2284 0x0000);
2285 bnx2x_cl45_write(bp, port,
2286 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2287 ext_phy_addr,
2288 MDIO_PMA_DEVAD,
2289 0xA81C,
2290 0x0300);
2291 bnx2x_cl45_write(bp, port,
2292 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2293 ext_phy_addr,
2294 MDIO_PMA_DEVAD,
2295 0xA817,
2296 0x0009);
2297
2298 for (cnt = 0; cnt < 100; cnt++) {
2299 bnx2x_cl45_read(bp, port,
2300 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2301 ext_phy_addr,
2302 MDIO_PMA_DEVAD,
2303 0xA818,
2304 &val);
2305 if (val & 1)
2306 break;
2307 udelay(5);
2308 }
2309 if (cnt == 100) {
2310 DP(NETIF_MSG_LINK, "Unable to read 8481 phy fw version(1)\n");
2311 bnx2x_save_spirom_version(bp, port,
2312 shmem_base, 0);
2313 return;
2314 }
2315
2316
2317 /* 2) read register 0xc200_0000 (SPI_FW_STATUS) */
2318 bnx2x_cl45_write(bp, port,
2319 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2320 ext_phy_addr, MDIO_PMA_DEVAD,
2321 0xA819, 0x0000);
2322 bnx2x_cl45_write(bp, port,
2323 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2324 ext_phy_addr, MDIO_PMA_DEVAD,
2325 0xA81A, 0xc200);
2326 bnx2x_cl45_write(bp, port,
2327 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2328 ext_phy_addr, MDIO_PMA_DEVAD,
2329 0xA817, 0x000A);
2330 for (cnt = 0; cnt < 100; cnt++) {
2331 bnx2x_cl45_read(bp, port,
2332 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2333 ext_phy_addr,
2334 MDIO_PMA_DEVAD,
2335 0xA818,
2336 &val);
2337 if (val & 1)
2338 break;
2339 udelay(5);
2340 }
2341 if (cnt == 100) {
2342 DP(NETIF_MSG_LINK, "Unable to read 8481 phy fw version(2)\n");
2343 bnx2x_save_spirom_version(bp, port,
2344 shmem_base, 0);
2345 return;
2346 }
2347
2348 /* lower 16 bits of the register SPI_FW_STATUS */
2349 bnx2x_cl45_read(bp, port,
2350 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2351 ext_phy_addr,
2352 MDIO_PMA_DEVAD,
2353 0xA81B,
2354 &fw_ver1);
2355 /* upper 16 bits of register SPI_FW_STATUS */
2356 bnx2x_cl45_read(bp, port,
2357 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2358 ext_phy_addr,
2359 MDIO_PMA_DEVAD,
2360 0xA81C,
2361 &fw_ver2);
2362
2363 bnx2x_save_spirom_version(bp, port,
2364 shmem_base, (fw_ver2<<16) | fw_ver1);
2365}
2366
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002367static void bnx2x_bcm8072_external_rom_boot(struct link_params *params)
2368{
2369 struct bnx2x *bp = params->bp;
2370 u8 port = params->port;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00002371 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002372 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002373
2374 /* Need to wait 200ms after reset */
2375 msleep(200);
2376 /* Boot port from external ROM
2377 * Set ser_boot_ctl bit in the MISC_CTRL1 register
2378 */
2379 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2380 MDIO_PMA_DEVAD,
2381 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
2382
2383 /* Reset internal microprocessor */
2384 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2385 MDIO_PMA_DEVAD,
2386 MDIO_PMA_REG_GEN_CTRL,
2387 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2388 /* set micro reset = 0 */
2389 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2390 MDIO_PMA_DEVAD,
2391 MDIO_PMA_REG_GEN_CTRL,
2392 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
2393 /* Reset internal microprocessor */
2394 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2395 MDIO_PMA_DEVAD,
2396 MDIO_PMA_REG_GEN_CTRL,
2397 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2398 /* wait for 100ms for code download via SPI port */
2399 msleep(100);
2400
2401 /* Clear ser_boot_ctl bit */
2402 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2403 MDIO_PMA_DEVAD,
2404 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
2405 /* Wait 100ms */
2406 msleep(100);
2407
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002408 bnx2x_save_bcm_spirom_ver(bp, port,
2409 ext_phy_type,
2410 ext_phy_addr,
2411 params->shmem_base);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002412}
2413
2414static u8 bnx2x_8073_is_snr_needed(struct link_params *params)
2415{
2416 /* This is only required for 8073A1, version 102 only */
2417
2418 struct bnx2x *bp = params->bp;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00002419 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002420 u16 val;
2421
2422 /* Read 8073 HW revision*/
2423 bnx2x_cl45_read(bp, params->port,
2424 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2425 ext_phy_addr,
2426 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00002427 MDIO_PMA_REG_8073_CHIP_REV, &val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002428
2429 if (val != 1) {
2430 /* No need to workaround in 8073 A1 */
2431 return 0;
2432 }
2433
2434 bnx2x_cl45_read(bp, params->port,
2435 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2436 ext_phy_addr,
2437 MDIO_PMA_DEVAD,
2438 MDIO_PMA_REG_ROM_VER2, &val);
2439
2440 /* SNR should be applied only for version 0x102 */
2441 if (val != 0x102)
2442 return 0;
2443
2444 return 1;
2445}
2446
2447static u8 bnx2x_bcm8073_xaui_wa(struct link_params *params)
2448{
2449 struct bnx2x *bp = params->bp;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00002450 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002451 u16 val, cnt, cnt1 ;
2452
2453 bnx2x_cl45_read(bp, params->port,
2454 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2455 ext_phy_addr,
2456 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00002457 MDIO_PMA_REG_8073_CHIP_REV, &val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002458
2459 if (val > 0) {
2460 /* No need to workaround in 8073 A1 */
2461 return 0;
2462 }
2463 /* XAUI workaround in 8073 A0: */
2464
2465 /* After loading the boot ROM and restarting Autoneg,
2466 poll Dev1, Reg $C820: */
2467
2468 for (cnt = 0; cnt < 1000; cnt++) {
2469 bnx2x_cl45_read(bp, params->port,
2470 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2471 ext_phy_addr,
2472 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00002473 MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
2474 &val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002475 /* If bit [14] = 0 or bit [13] = 0, continue on with
2476 system initialization (XAUI work-around not required,
2477 as these bits indicate 2.5G or 1G link up). */
2478 if (!(val & (1<<14)) || !(val & (1<<13))) {
2479 DP(NETIF_MSG_LINK, "XAUI work-around not required\n");
2480 return 0;
2481 } else if (!(val & (1<<15))) {
2482 DP(NETIF_MSG_LINK, "clc bit 15 went off\n");
2483 /* If bit 15 is 0, then poll Dev1, Reg $C841 until
2484 it's MSB (bit 15) goes to 1 (indicating that the
2485 XAUI workaround has completed),
2486 then continue on with system initialization.*/
2487 for (cnt1 = 0; cnt1 < 1000; cnt1++) {
2488 bnx2x_cl45_read(bp, params->port,
2489 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2490 ext_phy_addr,
2491 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00002492 MDIO_PMA_REG_8073_XAUI_WA, &val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002493 if (val & (1<<15)) {
2494 DP(NETIF_MSG_LINK,
2495 "XAUI workaround has completed\n");
2496 return 0;
2497 }
2498 msleep(3);
2499 }
2500 break;
2501 }
2502 msleep(3);
2503 }
2504 DP(NETIF_MSG_LINK, "Warning: XAUI work-around timeout !!!\n");
2505 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002506}
2507
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002508static void bnx2x_bcm8073_bcm8727_external_rom_boot(struct bnx2x *bp, u8 port,
2509 u8 ext_phy_addr,
2510 u32 ext_phy_type,
2511 u32 shmem_base)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002512{
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002513 /* Boot port from external ROM */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002514 /* EDC grst */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002515 bnx2x_cl45_write(bp, port,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002516 ext_phy_type,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002517 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002518 MDIO_PMA_DEVAD,
2519 MDIO_PMA_REG_GEN_CTRL,
2520 0x0001);
2521
2522 /* ucode reboot and rst */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002523 bnx2x_cl45_write(bp, port,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002524 ext_phy_type,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002525 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002526 MDIO_PMA_DEVAD,
2527 MDIO_PMA_REG_GEN_CTRL,
2528 0x008c);
2529
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002530 bnx2x_cl45_write(bp, port,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002531 ext_phy_type,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002532 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002533 MDIO_PMA_DEVAD,
2534 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
2535
2536 /* Reset internal microprocessor */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002537 bnx2x_cl45_write(bp, port,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002538 ext_phy_type,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002539 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002540 MDIO_PMA_DEVAD,
2541 MDIO_PMA_REG_GEN_CTRL,
2542 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
2543
2544 /* Release srst bit */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002545 bnx2x_cl45_write(bp, port,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002546 ext_phy_type,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002547 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002548 MDIO_PMA_DEVAD,
2549 MDIO_PMA_REG_GEN_CTRL,
2550 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2551
Yaniv Rosner8ca60a62010-09-01 09:51:17 +00002552 /* wait for 120ms for code download via SPI port */
2553 msleep(120);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002554
2555 /* Clear ser_boot_ctl bit */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002556 bnx2x_cl45_write(bp, port,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002557 ext_phy_type,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002558 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002559 MDIO_PMA_DEVAD,
2560 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
2561
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002562 bnx2x_save_bcm_spirom_ver(bp, port,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002563 ext_phy_type,
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002564 ext_phy_addr,
2565 shmem_base);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002566}
2567
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002568static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port,
2569 u8 ext_phy_addr,
2570 u32 shmem_base)
2571{
2572 bnx2x_bcm8073_bcm8727_external_rom_boot(bp, port, ext_phy_addr,
2573 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2574 shmem_base);
2575}
2576
2577static void bnx2x_bcm8727_external_rom_boot(struct bnx2x *bp, u8 port,
2578 u8 ext_phy_addr,
2579 u32 shmem_base)
2580{
2581 bnx2x_bcm8073_bcm8727_external_rom_boot(bp, port, ext_phy_addr,
2582 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
2583 shmem_base);
2584
2585}
2586
Eilon Greenstein589abe32009-02-12 08:36:55 +00002587static void bnx2x_bcm8726_external_rom_boot(struct link_params *params)
2588{
2589 struct bnx2x *bp = params->bp;
2590 u8 port = params->port;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00002591 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002592 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2593
2594 /* Need to wait 100ms after reset */
2595 msleep(100);
2596
Eilon Greenstein589abe32009-02-12 08:36:55 +00002597 /* Micro controller re-boot */
2598 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2599 MDIO_PMA_DEVAD,
2600 MDIO_PMA_REG_GEN_CTRL,
Yaniv Rosner93f72882009-11-05 19:18:26 +02002601 0x018B);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002602
2603 /* Set soft reset */
2604 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2605 MDIO_PMA_DEVAD,
2606 MDIO_PMA_REG_GEN_CTRL,
2607 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
2608
Eilon Greensteincc1cb002009-03-02 08:00:03 +00002609 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2610 MDIO_PMA_DEVAD,
Yaniv Rosner93f72882009-11-05 19:18:26 +02002611 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
Eilon Greensteincc1cb002009-03-02 08:00:03 +00002612
Eilon Greenstein589abe32009-02-12 08:36:55 +00002613 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2614 MDIO_PMA_DEVAD,
2615 MDIO_PMA_REG_GEN_CTRL,
2616 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2617
Eilon Greensteincc1cb002009-03-02 08:00:03 +00002618 /* wait for 150ms for microcode load */
2619 msleep(150);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002620
2621 /* Disable serial boot control, tristates pins SS_N, SCK, MOSI, MISO */
2622 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2623 MDIO_PMA_DEVAD,
2624 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
2625
2626 msleep(200);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002627 bnx2x_save_bcm_spirom_ver(bp, port,
2628 ext_phy_type,
2629 ext_phy_addr,
2630 params->shmem_base);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002631}
2632
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002633static void bnx2x_sfp_set_transmitter(struct bnx2x *bp, u8 port,
2634 u32 ext_phy_type, u8 ext_phy_addr,
2635 u8 tx_en)
Eilon Greenstein589abe32009-02-12 08:36:55 +00002636{
2637 u16 val;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002638
Eilon Greenstein589abe32009-02-12 08:36:55 +00002639 DP(NETIF_MSG_LINK, "Setting transmitter tx_en=%x for port %x\n",
2640 tx_en, port);
2641 /* Disable/Enable transmitter ( TX laser of the SFP+ module.)*/
2642 bnx2x_cl45_read(bp, port,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002643 ext_phy_type,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002644 ext_phy_addr,
2645 MDIO_PMA_DEVAD,
2646 MDIO_PMA_REG_PHY_IDENTIFIER,
2647 &val);
2648
2649 if (tx_en)
2650 val &= ~(1<<15);
2651 else
2652 val |= (1<<15);
2653
2654 bnx2x_cl45_write(bp, port,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002655 ext_phy_type,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002656 ext_phy_addr,
2657 MDIO_PMA_DEVAD,
2658 MDIO_PMA_REG_PHY_IDENTIFIER,
2659 val);
2660}
2661
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002662static u8 bnx2x_8726_read_sfp_module_eeprom(struct link_params *params,
2663 u16 addr, u8 byte_cnt, u8 *o_buf)
2664{
Eilon Greenstein589abe32009-02-12 08:36:55 +00002665 struct bnx2x *bp = params->bp;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002666 u16 val = 0;
2667 u16 i;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002668 u8 port = params->port;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00002669 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002670 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002671
Eilon Greenstein589abe32009-02-12 08:36:55 +00002672 if (byte_cnt > 16) {
2673 DP(NETIF_MSG_LINK, "Reading from eeprom is"
2674 " is limited to 0xf\n");
2675 return -EINVAL;
2676 }
2677 /* Set the read command byte count */
2678 bnx2x_cl45_write(bp, port,
2679 ext_phy_type,
2680 ext_phy_addr,
2681 MDIO_PMA_DEVAD,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002682 MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002683 (byte_cnt | 0xa000));
2684
2685 /* Set the read command address */
2686 bnx2x_cl45_write(bp, port,
2687 ext_phy_type,
2688 ext_phy_addr,
2689 MDIO_PMA_DEVAD,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002690 MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002691 addr);
2692
2693 /* Activate read command */
2694 bnx2x_cl45_write(bp, port,
2695 ext_phy_type,
2696 ext_phy_addr,
2697 MDIO_PMA_DEVAD,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002698 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002699 0x2c0f);
2700
2701 /* Wait up to 500us for command complete status */
2702 for (i = 0; i < 100; i++) {
2703 bnx2x_cl45_read(bp, port,
2704 ext_phy_type,
2705 ext_phy_addr,
2706 MDIO_PMA_DEVAD,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002707 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
2708 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
2709 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
Eilon Greenstein589abe32009-02-12 08:36:55 +00002710 break;
2711 udelay(5);
2712 }
2713
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002714 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
2715 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
Eilon Greenstein589abe32009-02-12 08:36:55 +00002716 DP(NETIF_MSG_LINK,
2717 "Got bad status 0x%x when reading from SFP+ EEPROM\n",
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002718 (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
Eilon Greenstein589abe32009-02-12 08:36:55 +00002719 return -EINVAL;
2720 }
2721
2722 /* Read the buffer */
2723 for (i = 0; i < byte_cnt; i++) {
2724 bnx2x_cl45_read(bp, port,
2725 ext_phy_type,
2726 ext_phy_addr,
2727 MDIO_PMA_DEVAD,
2728 MDIO_PMA_REG_8726_TWO_WIRE_DATA_BUF + i, &val);
2729 o_buf[i] = (u8)(val & MDIO_PMA_REG_8726_TWO_WIRE_DATA_MASK);
2730 }
2731
2732 for (i = 0; i < 100; i++) {
2733 bnx2x_cl45_read(bp, port,
2734 ext_phy_type,
2735 ext_phy_addr,
2736 MDIO_PMA_DEVAD,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002737 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
2738 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
2739 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
Eilon Greenstein589abe32009-02-12 08:36:55 +00002740 return 0;;
2741 msleep(1);
2742 }
2743 return -EINVAL;
2744}
2745
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002746static u8 bnx2x_8727_read_sfp_module_eeprom(struct link_params *params,
2747 u16 addr, u8 byte_cnt, u8 *o_buf)
Eilon Greenstein589abe32009-02-12 08:36:55 +00002748{
2749 struct bnx2x *bp = params->bp;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002750 u16 val, i;
2751 u8 port = params->port;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00002752 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002753 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2754
2755 if (byte_cnt > 16) {
2756 DP(NETIF_MSG_LINK, "Reading from eeprom is"
2757 " is limited to 0xf\n");
2758 return -EINVAL;
2759 }
2760
2761 /* Need to read from 1.8000 to clear it */
2762 bnx2x_cl45_read(bp, port,
2763 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
2764 ext_phy_addr,
2765 MDIO_PMA_DEVAD,
2766 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
2767 &val);
2768
2769 /* Set the read command byte count */
2770 bnx2x_cl45_write(bp, port,
2771 ext_phy_type,
2772 ext_phy_addr,
2773 MDIO_PMA_DEVAD,
2774 MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
2775 ((byte_cnt < 2) ? 2 : byte_cnt));
2776
2777 /* Set the read command address */
2778 bnx2x_cl45_write(bp, port,
2779 ext_phy_type,
2780 ext_phy_addr,
2781 MDIO_PMA_DEVAD,
2782 MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
2783 addr);
2784 /* Set the destination address */
2785 bnx2x_cl45_write(bp, port,
2786 ext_phy_type,
2787 ext_phy_addr,
2788 MDIO_PMA_DEVAD,
2789 0x8004,
2790 MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF);
2791
2792 /* Activate read command */
2793 bnx2x_cl45_write(bp, port,
2794 ext_phy_type,
2795 ext_phy_addr,
2796 MDIO_PMA_DEVAD,
2797 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
2798 0x8002);
2799 /* Wait appropriate time for two-wire command to finish before
2800 polling the status register */
2801 msleep(1);
2802
2803 /* Wait up to 500us for command complete status */
2804 for (i = 0; i < 100; i++) {
2805 bnx2x_cl45_read(bp, port,
2806 ext_phy_type,
2807 ext_phy_addr,
2808 MDIO_PMA_DEVAD,
2809 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
2810 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
2811 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
2812 break;
2813 udelay(5);
2814 }
2815
2816 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
2817 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
2818 DP(NETIF_MSG_LINK,
2819 "Got bad status 0x%x when reading from SFP+ EEPROM\n",
2820 (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
2821 return -EINVAL;
2822 }
2823
2824 /* Read the buffer */
2825 for (i = 0; i < byte_cnt; i++) {
2826 bnx2x_cl45_read(bp, port,
2827 ext_phy_type,
2828 ext_phy_addr,
2829 MDIO_PMA_DEVAD,
2830 MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF + i, &val);
2831 o_buf[i] = (u8)(val & MDIO_PMA_REG_8727_TWO_WIRE_DATA_MASK);
2832 }
2833
2834 for (i = 0; i < 100; i++) {
2835 bnx2x_cl45_read(bp, port,
2836 ext_phy_type,
2837 ext_phy_addr,
2838 MDIO_PMA_DEVAD,
2839 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
2840 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
2841 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
2842 return 0;;
2843 msleep(1);
2844 }
2845
2846 return -EINVAL;
2847}
2848
2849u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
2850 u8 byte_cnt, u8 *o_buf)
2851{
2852 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2853
2854 if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
2855 return bnx2x_8726_read_sfp_module_eeprom(params, addr,
2856 byte_cnt, o_buf);
2857 else if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
2858 return bnx2x_8727_read_sfp_module_eeprom(params, addr,
2859 byte_cnt, o_buf);
2860 return -EINVAL;
2861}
2862
2863static u8 bnx2x_get_edc_mode(struct link_params *params,
2864 u16 *edc_mode)
2865{
2866 struct bnx2x *bp = params->bp;
2867 u8 val, check_limiting_mode = 0;
2868 *edc_mode = EDC_MODE_LIMITING;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002869
2870 /* First check for copper cable */
2871 if (bnx2x_read_sfp_module_eeprom(params,
2872 SFP_EEPROM_CON_TYPE_ADDR,
2873 1,
2874 &val) != 0) {
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002875 DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM\n");
Eilon Greenstein589abe32009-02-12 08:36:55 +00002876 return -EINVAL;
2877 }
2878
2879 switch (val) {
2880 case SFP_EEPROM_CON_TYPE_VAL_COPPER:
2881 {
2882 u8 copper_module_type;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002883
Eilon Greenstein589abe32009-02-12 08:36:55 +00002884 /* Check if its active cable( includes SFP+ module)
2885 of passive cable*/
2886 if (bnx2x_read_sfp_module_eeprom(params,
2887 SFP_EEPROM_FC_TX_TECH_ADDR,
2888 1,
2889 &copper_module_type) !=
2890 0) {
2891 DP(NETIF_MSG_LINK,
2892 "Failed to read copper-cable-type"
2893 " from SFP+ EEPROM\n");
2894 return -EINVAL;
2895 }
2896
2897 if (copper_module_type &
2898 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE) {
2899 DP(NETIF_MSG_LINK, "Active Copper cable detected\n");
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002900 check_limiting_mode = 1;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002901 } else if (copper_module_type &
2902 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE) {
2903 DP(NETIF_MSG_LINK, "Passive Copper"
2904 " cable detected\n");
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002905 *edc_mode =
2906 EDC_MODE_PASSIVE_DAC;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002907 } else {
2908 DP(NETIF_MSG_LINK, "Unknown copper-cable-"
2909 "type 0x%x !!!\n", copper_module_type);
2910 return -EINVAL;
2911 }
2912 break;
2913 }
2914 case SFP_EEPROM_CON_TYPE_VAL_LC:
2915 DP(NETIF_MSG_LINK, "Optic module detected\n");
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002916 check_limiting_mode = 1;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002917 break;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002918 default:
2919 DP(NETIF_MSG_LINK, "Unable to determine module type 0x%x !!!\n",
2920 val);
2921 return -EINVAL;
2922 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002923
2924 if (check_limiting_mode) {
2925 u8 options[SFP_EEPROM_OPTIONS_SIZE];
2926 if (bnx2x_read_sfp_module_eeprom(params,
2927 SFP_EEPROM_OPTIONS_ADDR,
2928 SFP_EEPROM_OPTIONS_SIZE,
2929 options) != 0) {
2930 DP(NETIF_MSG_LINK, "Failed to read Option"
2931 " field from module EEPROM\n");
2932 return -EINVAL;
2933 }
2934 if ((options[0] & SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK))
2935 *edc_mode = EDC_MODE_LINEAR;
2936 else
2937 *edc_mode = EDC_MODE_LIMITING;
2938 }
2939 DP(NETIF_MSG_LINK, "EDC mode is set to 0x%x\n", *edc_mode);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002940 return 0;
2941}
2942
Eilon Greenstein589abe32009-02-12 08:36:55 +00002943/* This function read the relevant field from the module ( SFP+ ),
2944 and verify it is compliant with this board */
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002945static u8 bnx2x_verify_sfp_module(struct link_params *params)
Eilon Greenstein589abe32009-02-12 08:36:55 +00002946{
2947 struct bnx2x *bp = params->bp;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002948 u32 val;
2949 u32 fw_resp;
2950 char vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE+1];
2951 char vendor_pn[SFP_EEPROM_PART_NO_SIZE+1];
Eilon Greenstein589abe32009-02-12 08:36:55 +00002952
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002953 val = REG_RD(bp, params->shmem_base +
2954 offsetof(struct shmem_region, dev_info.
2955 port_feature_config[params->port].config));
2956 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
2957 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_NO_ENFORCEMENT) {
Eilon Greenstein589abe32009-02-12 08:36:55 +00002958 DP(NETIF_MSG_LINK, "NOT enforcing module verification\n");
2959 return 0;
2960 }
2961
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002962 /* Ask the FW to validate the module */
2963 if (!(params->feature_config_flags &
2964 FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY)) {
2965 DP(NETIF_MSG_LINK, "FW does not support OPT MDL "
2966 "verification\n");
2967 return -EINVAL;
2968 }
2969
2970 fw_resp = bnx2x_fw_command(bp, DRV_MSG_CODE_VRFY_OPT_MDL);
2971 if (fw_resp == FW_MSG_CODE_VRFY_OPT_MDL_SUCCESS) {
2972 DP(NETIF_MSG_LINK, "Approved module\n");
Eilon Greenstein589abe32009-02-12 08:36:55 +00002973 return 0;
2974 }
2975
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002976 /* format the warning message */
Eilon Greenstein589abe32009-02-12 08:36:55 +00002977 if (bnx2x_read_sfp_module_eeprom(params,
2978 SFP_EEPROM_VENDOR_NAME_ADDR,
2979 SFP_EEPROM_VENDOR_NAME_SIZE,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002980 (u8 *)vendor_name))
2981 vendor_name[0] = '\0';
2982 else
2983 vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE] = '\0';
2984 if (bnx2x_read_sfp_module_eeprom(params,
2985 SFP_EEPROM_PART_NO_ADDR,
2986 SFP_EEPROM_PART_NO_SIZE,
2987 (u8 *)vendor_pn))
2988 vendor_pn[0] = '\0';
2989 else
2990 vendor_pn[SFP_EEPROM_PART_NO_SIZE] = '\0';
Eilon Greenstein589abe32009-02-12 08:36:55 +00002991
Joe Perches7995c642010-02-17 15:01:52 +00002992 netdev_info(bp->dev, "Warning: Unqualified SFP+ module detected, Port %d from %s part number %s\n",
2993 params->port, vendor_name, vendor_pn);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002994 return -EINVAL;
2995}
2996
Eilon Greenstein589abe32009-02-12 08:36:55 +00002997static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002998 u16 edc_mode)
Eilon Greenstein589abe32009-02-12 08:36:55 +00002999{
3000 struct bnx2x *bp = params->bp;
3001 u8 port = params->port;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00003002 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Eilon Greensteincc1cb002009-03-02 08:00:03 +00003003 u16 cur_limiting_mode;
Eilon Greensteincc1cb002009-03-02 08:00:03 +00003004
3005 bnx2x_cl45_read(bp, port,
3006 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
3007 ext_phy_addr,
3008 MDIO_PMA_DEVAD,
3009 MDIO_PMA_REG_ROM_VER2,
3010 &cur_limiting_mode);
3011 DP(NETIF_MSG_LINK, "Current Limiting mode is 0x%x\n",
3012 cur_limiting_mode);
3013
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003014 if (edc_mode == EDC_MODE_LIMITING) {
Eilon Greenstein589abe32009-02-12 08:36:55 +00003015 DP(NETIF_MSG_LINK,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003016 "Setting LIMITING MODE\n");
Eilon Greenstein589abe32009-02-12 08:36:55 +00003017 bnx2x_cl45_write(bp, port,
3018 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
3019 ext_phy_addr,
3020 MDIO_PMA_DEVAD,
3021 MDIO_PMA_REG_ROM_VER2,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003022 EDC_MODE_LIMITING);
Eilon Greenstein589abe32009-02-12 08:36:55 +00003023 } else { /* LRM mode ( default )*/
Eilon Greensteincc1cb002009-03-02 08:00:03 +00003024
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003025 DP(NETIF_MSG_LINK, "Setting LRM MODE\n");
Eilon Greenstein589abe32009-02-12 08:36:55 +00003026
Eilon Greenstein589abe32009-02-12 08:36:55 +00003027 /* Changing to LRM mode takes quite few seconds.
3028 So do it only if current mode is limiting
3029 ( default is LRM )*/
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003030 if (cur_limiting_mode != EDC_MODE_LIMITING)
Eilon Greenstein589abe32009-02-12 08:36:55 +00003031 return 0;
3032
3033 bnx2x_cl45_write(bp, port,
3034 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
3035 ext_phy_addr,
3036 MDIO_PMA_DEVAD,
3037 MDIO_PMA_REG_LRM_MODE,
3038 0);
3039 bnx2x_cl45_write(bp, port,
3040 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
3041 ext_phy_addr,
3042 MDIO_PMA_DEVAD,
3043 MDIO_PMA_REG_ROM_VER2,
3044 0x128);
3045 bnx2x_cl45_write(bp, port,
3046 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
3047 ext_phy_addr,
3048 MDIO_PMA_DEVAD,
3049 MDIO_PMA_REG_MISC_CTRL0,
3050 0x4008);
3051 bnx2x_cl45_write(bp, port,
3052 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
3053 ext_phy_addr,
3054 MDIO_PMA_DEVAD,
3055 MDIO_PMA_REG_LRM_MODE,
3056 0xaaaa);
3057 }
3058 return 0;
3059}
3060
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003061static u8 bnx2x_bcm8727_set_limiting_mode(struct link_params *params,
3062 u16 edc_mode)
3063{
3064 struct bnx2x *bp = params->bp;
3065 u8 port = params->port;
3066 u16 phy_identifier;
3067 u16 rom_ver2_val;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00003068 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003069
3070 bnx2x_cl45_read(bp, port,
3071 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
3072 ext_phy_addr,
3073 MDIO_PMA_DEVAD,
3074 MDIO_PMA_REG_PHY_IDENTIFIER,
3075 &phy_identifier);
3076
3077 bnx2x_cl45_write(bp, port,
3078 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
3079 ext_phy_addr,
3080 MDIO_PMA_DEVAD,
3081 MDIO_PMA_REG_PHY_IDENTIFIER,
3082 (phy_identifier & ~(1<<9)));
3083
3084 bnx2x_cl45_read(bp, port,
3085 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
3086 ext_phy_addr,
3087 MDIO_PMA_DEVAD,
3088 MDIO_PMA_REG_ROM_VER2,
3089 &rom_ver2_val);
3090 /* Keep the MSB 8-bits, and set the LSB 8-bits with the edc_mode */
3091 bnx2x_cl45_write(bp, port,
3092 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
3093 ext_phy_addr,
3094 MDIO_PMA_DEVAD,
3095 MDIO_PMA_REG_ROM_VER2,
3096 (rom_ver2_val & 0xff00) | (edc_mode & 0x00ff));
3097
3098 bnx2x_cl45_write(bp, port,
3099 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
3100 ext_phy_addr,
3101 MDIO_PMA_DEVAD,
3102 MDIO_PMA_REG_PHY_IDENTIFIER,
3103 (phy_identifier | (1<<9)));
3104
3105 return 0;
3106}
3107
3108
Eilon Greenstein589abe32009-02-12 08:36:55 +00003109static u8 bnx2x_wait_for_sfp_module_initialized(struct link_params *params)
3110{
3111 u8 val;
3112 struct bnx2x *bp = params->bp;
3113 u16 timeout;
3114 /* Initialization time after hot-plug may take up to 300ms for some
3115 phys type ( e.g. JDSU ) */
3116 for (timeout = 0; timeout < 60; timeout++) {
3117 if (bnx2x_read_sfp_module_eeprom(params, 1, 1, &val)
3118 == 0) {
3119 DP(NETIF_MSG_LINK, "SFP+ module initialization "
3120 "took %d ms\n", timeout * 5);
3121 return 0;
3122 }
3123 msleep(5);
3124 }
3125 return -EINVAL;
3126}
3127
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003128static void bnx2x_8727_power_module(struct bnx2x *bp,
3129 struct link_params *params,
3130 u8 ext_phy_addr, u8 is_power_up) {
3131 /* Make sure GPIOs are not using for LED mode */
3132 u16 val;
3133 u8 port = params->port;
3134 /*
3135 * In the GPIO register, bit 4 is use to detemine if the GPIOs are
3136 * operating as INPUT or as OUTPUT. Bit 1 is for input, and 0 for
3137 * output
3138 * Bits 0-1 determine the gpios value for OUTPUT in case bit 4 val is 0
3139 * Bits 8-9 determine the gpios value for INPUT in case bit 4 val is 1
3140 * where the 1st bit is the over-current(only input), and 2nd bit is
3141 * for power( only output )
3142 */
3143
3144 /*
3145 * In case of NOC feature is disabled and power is up, set GPIO control
3146 * as input to enable listening of over-current indication
3147 */
3148
3149 if (!(params->feature_config_flags &
3150 FEATURE_CONFIG_BCM8727_NOC) && is_power_up)
3151 val = (1<<4);
3152 else
3153 /*
3154 * Set GPIO control to OUTPUT, and set the power bit
3155 * to according to the is_power_up
3156 */
3157 val = ((!(is_power_up)) << 1);
3158
3159 bnx2x_cl45_write(bp, port,
3160 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
3161 ext_phy_addr,
3162 MDIO_PMA_DEVAD,
3163 MDIO_PMA_REG_8727_GPIO_CTRL,
3164 val);
3165}
3166
Eilon Greenstein589abe32009-02-12 08:36:55 +00003167static u8 bnx2x_sfp_module_detection(struct link_params *params)
3168{
3169 struct bnx2x *bp = params->bp;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003170 u16 edc_mode;
3171 u8 rc = 0;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00003172 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Eilon Greenstein589abe32009-02-12 08:36:55 +00003173 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003174 u32 val = REG_RD(bp, params->shmem_base +
3175 offsetof(struct shmem_region, dev_info.
3176 port_feature_config[params->port].config));
Eilon Greenstein589abe32009-02-12 08:36:55 +00003177
3178 DP(NETIF_MSG_LINK, "SFP+ module plugged in/out detected on port %d\n",
3179 params->port);
3180
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003181 if (bnx2x_get_edc_mode(params, &edc_mode) != 0) {
Eilon Greenstein589abe32009-02-12 08:36:55 +00003182 DP(NETIF_MSG_LINK, "Failed to get valid module type\n");
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003183 return -EINVAL;
3184 } else if (bnx2x_verify_sfp_module(params) !=
Eilon Greenstein589abe32009-02-12 08:36:55 +00003185 0) {
3186 /* check SFP+ module compatibility */
3187 DP(NETIF_MSG_LINK, "Module verification failed!!\n");
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003188 rc = -EINVAL;
Eilon Greenstein589abe32009-02-12 08:36:55 +00003189 /* Turn on fault module-detected led */
3190 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
3191 MISC_REGISTERS_GPIO_HIGH,
3192 params->port);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003193 if ((ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) &&
3194 ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
3195 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_POWER_DOWN)) {
3196 /* Shutdown SFP+ module */
3197 DP(NETIF_MSG_LINK, "Shutdown SFP+ module!!\n");
3198 bnx2x_8727_power_module(bp, params,
3199 ext_phy_addr, 0);
3200 return rc;
3201 }
3202 } else {
3203 /* Turn off fault module-detected led */
3204 DP(NETIF_MSG_LINK, "Turn off fault module-detected led\n");
3205 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
3206 MISC_REGISTERS_GPIO_LOW,
3207 params->port);
Eilon Greenstein589abe32009-02-12 08:36:55 +00003208 }
3209
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003210 /* power up the SFP module */
3211 if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
3212 bnx2x_8727_power_module(bp, params, ext_phy_addr, 1);
Eilon Greenstein589abe32009-02-12 08:36:55 +00003213
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003214 /* Check and set limiting mode / LRM mode on 8726.
3215 On 8727 it is done automatically */
3216 if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
3217 bnx2x_bcm8726_set_limiting_mode(params, edc_mode);
3218 else
3219 bnx2x_bcm8727_set_limiting_mode(params, edc_mode);
3220 /*
3221 * Enable transmit for this module if the module is approved, or
3222 * if unapproved modules should also enable the Tx laser
3223 */
3224 if (rc == 0 ||
3225 (val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) !=
3226 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
3227 bnx2x_sfp_set_transmitter(bp, params->port,
3228 ext_phy_type, ext_phy_addr, 1);
3229 else
3230 bnx2x_sfp_set_transmitter(bp, params->port,
3231 ext_phy_type, ext_phy_addr, 0);
Eilon Greenstein589abe32009-02-12 08:36:55 +00003232
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003233 return rc;
Eilon Greenstein589abe32009-02-12 08:36:55 +00003234}
3235
3236void bnx2x_handle_module_detect_int(struct link_params *params)
3237{
3238 struct bnx2x *bp = params->bp;
3239 u32 gpio_val;
3240 u8 port = params->port;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00003241
Eilon Greenstein589abe32009-02-12 08:36:55 +00003242 /* Set valid module led off */
3243 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
3244 MISC_REGISTERS_GPIO_HIGH,
3245 params->port);
3246
3247 /* Get current gpio val refelecting module plugged in / out*/
3248 gpio_val = bnx2x_get_gpio(bp, MISC_REGISTERS_GPIO_3, port);
3249
3250 /* Call the handling function in case module is detected */
3251 if (gpio_val == 0) {
3252
3253 bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
3254 MISC_REGISTERS_GPIO_INT_OUTPUT_CLR,
3255 port);
3256
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003257 if (bnx2x_wait_for_sfp_module_initialized(params) ==
3258 0)
Eilon Greenstein589abe32009-02-12 08:36:55 +00003259 bnx2x_sfp_module_detection(params);
3260 else
3261 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
3262 } else {
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00003263 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
3264
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003265 u32 ext_phy_type =
3266 XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3267 u32 val = REG_RD(bp, params->shmem_base +
3268 offsetof(struct shmem_region, dev_info.
3269 port_feature_config[params->port].
3270 config));
3271
Eilon Greenstein589abe32009-02-12 08:36:55 +00003272 bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
3273 MISC_REGISTERS_GPIO_INT_OUTPUT_SET,
3274 port);
3275 /* Module was plugged out. */
3276 /* Disable transmit for this module */
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003277 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
3278 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
3279 bnx2x_sfp_set_transmitter(bp, params->port,
3280 ext_phy_type, ext_phy_addr, 0);
Eilon Greenstein589abe32009-02-12 08:36:55 +00003281 }
3282}
3283
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003284static void bnx2x_bcm807x_force_10G(struct link_params *params)
3285{
3286 struct bnx2x *bp = params->bp;
3287 u8 port = params->port;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00003288 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003289 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3290
3291 /* Force KR or KX */
3292 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3293 MDIO_PMA_DEVAD,
3294 MDIO_PMA_REG_CTRL,
3295 0x2040);
3296 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3297 MDIO_PMA_DEVAD,
3298 MDIO_PMA_REG_10G_CTRL2,
3299 0x000b);
3300 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3301 MDIO_PMA_DEVAD,
3302 MDIO_PMA_REG_BCM_CTRL,
3303 0x0000);
3304 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3305 MDIO_AN_DEVAD,
3306 MDIO_AN_REG_CTRL,
3307 0x0000);
3308}
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00003309
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003310static void bnx2x_bcm8073_set_xaui_low_power_mode(struct link_params *params)
3311{
3312 struct bnx2x *bp = params->bp;
3313 u8 port = params->port;
3314 u16 val;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00003315 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003316 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3317
3318 bnx2x_cl45_read(bp, params->port,
3319 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
3320 ext_phy_addr,
3321 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00003322 MDIO_PMA_REG_8073_CHIP_REV, &val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003323
3324 if (val == 0) {
3325 /* Mustn't set low power mode in 8073 A0 */
3326 return;
3327 }
3328
3329 /* Disable PLL sequencer (use read-modify-write to clear bit 13) */
3330 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
3331 MDIO_XS_DEVAD,
3332 MDIO_XS_PLL_SEQUENCER, &val);
3333 val &= ~(1<<13);
3334 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3335 MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
3336
3337 /* PLL controls */
3338 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3339 MDIO_XS_DEVAD, 0x805E, 0x1077);
3340 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3341 MDIO_XS_DEVAD, 0x805D, 0x0000);
3342 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3343 MDIO_XS_DEVAD, 0x805C, 0x030B);
3344 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3345 MDIO_XS_DEVAD, 0x805B, 0x1240);
3346 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3347 MDIO_XS_DEVAD, 0x805A, 0x2490);
3348
3349 /* Tx Controls */
3350 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3351 MDIO_XS_DEVAD, 0x80A7, 0x0C74);
3352 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3353 MDIO_XS_DEVAD, 0x80A6, 0x9041);
3354 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3355 MDIO_XS_DEVAD, 0x80A5, 0x4640);
3356
3357 /* Rx Controls */
3358 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3359 MDIO_XS_DEVAD, 0x80FE, 0x01C4);
3360 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3361 MDIO_XS_DEVAD, 0x80FD, 0x9249);
3362 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3363 MDIO_XS_DEVAD, 0x80FC, 0x2015);
3364
3365 /* Enable PLL sequencer (use read-modify-write to set bit 13) */
3366 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
3367 MDIO_XS_DEVAD,
3368 MDIO_XS_PLL_SEQUENCER, &val);
3369 val |= (1<<13);
3370 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3371 MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
3372}
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003373
3374static void bnx2x_8073_set_pause_cl37(struct link_params *params,
3375 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003376{
3377 struct bnx2x *bp = params->bp;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003378 u16 cl37_val;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00003379 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003380 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3381
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003382 bnx2x_cl45_read(bp, params->port,
3383 ext_phy_type,
3384 ext_phy_addr,
3385 MDIO_AN_DEVAD,
3386 MDIO_AN_REG_CL37_FC_LD, &cl37_val);
3387
3388 cl37_val &= ~MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
3389 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
3390
3391 if ((vars->ieee_fc &
3392 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) ==
3393 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) {
3394 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC;
3395 }
3396 if ((vars->ieee_fc &
3397 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
3398 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
3399 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
3400 }
3401 if ((vars->ieee_fc &
3402 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
3403 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
3404 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
3405 }
3406 DP(NETIF_MSG_LINK,
3407 "Ext phy AN advertize cl37 0x%x\n", cl37_val);
3408
3409 bnx2x_cl45_write(bp, params->port,
3410 ext_phy_type,
3411 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003412 MDIO_AN_DEVAD,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003413 MDIO_AN_REG_CL37_FC_LD, cl37_val);
3414 msleep(500);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003415}
3416
3417static void bnx2x_ext_phy_set_pause(struct link_params *params,
3418 struct link_vars *vars)
3419{
3420 struct bnx2x *bp = params->bp;
3421 u16 val;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00003422 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003423 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3424
3425 /* read modify write pause advertizing */
3426 bnx2x_cl45_read(bp, params->port,
3427 ext_phy_type,
3428 ext_phy_addr,
3429 MDIO_AN_DEVAD,
3430 MDIO_AN_REG_ADV_PAUSE, &val);
3431
3432 val &= ~MDIO_AN_REG_ADV_PAUSE_BOTH;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003433
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003434 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
3435
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003436 if ((vars->ieee_fc &
3437 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003438 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
3439 val |= MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC;
3440 }
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003441 if ((vars->ieee_fc &
3442 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003443 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
3444 val |=
3445 MDIO_AN_REG_ADV_PAUSE_PAUSE;
3446 }
3447 DP(NETIF_MSG_LINK,
3448 "Ext phy AN advertize 0x%x\n", val);
3449 bnx2x_cl45_write(bp, params->port,
3450 ext_phy_type,
3451 ext_phy_addr,
3452 MDIO_AN_DEVAD,
3453 MDIO_AN_REG_ADV_PAUSE, val);
3454}
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00003455static void bnx2x_set_preemphasis(struct link_params *params)
3456{
3457 u16 bank, i = 0;
3458 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003459
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00003460 for (bank = MDIO_REG_BANK_RX0, i = 0; bank <= MDIO_REG_BANK_RX3;
3461 bank += (MDIO_REG_BANK_RX1-MDIO_REG_BANK_RX0), i++) {
3462 CL45_WR_OVER_CL22(bp, params->port,
3463 params->phy_addr,
3464 bank,
3465 MDIO_RX0_RX_EQ_BOOST,
3466 params->xgxs_config_rx[i]);
3467 }
3468
3469 for (bank = MDIO_REG_BANK_TX0, i = 0; bank <= MDIO_REG_BANK_TX3;
3470 bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0), i++) {
3471 CL45_WR_OVER_CL22(bp, params->port,
3472 params->phy_addr,
3473 bank,
3474 MDIO_TX0_TX_DRIVER,
3475 params->xgxs_config_tx[i]);
3476 }
3477}
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003478
Eilon Greenstein2f904462009-08-12 08:22:16 +00003479
3480static void bnx2x_8481_set_led4(struct link_params *params,
3481 u32 ext_phy_type, u8 ext_phy_addr)
3482{
3483 struct bnx2x *bp = params->bp;
3484
3485 /* PHYC_CTL_LED_CTL */
3486 bnx2x_cl45_write(bp, params->port,
3487 ext_phy_type,
3488 ext_phy_addr,
3489 MDIO_PMA_DEVAD,
3490 MDIO_PMA_REG_8481_LINK_SIGNAL, 0xa482);
3491
3492 /* Unmask LED4 for 10G link */
3493 bnx2x_cl45_write(bp, params->port,
3494 ext_phy_type,
3495 ext_phy_addr,
3496 MDIO_PMA_DEVAD,
3497 MDIO_PMA_REG_8481_SIGNAL_MASK, (1<<6));
3498 /* 'Interrupt Mask' */
3499 bnx2x_cl45_write(bp, params->port,
3500 ext_phy_type,
3501 ext_phy_addr,
3502 MDIO_AN_DEVAD,
3503 0xFFFB, 0xFFFD);
3504}
3505static void bnx2x_8481_set_legacy_led_mode(struct link_params *params,
3506 u32 ext_phy_type, u8 ext_phy_addr)
3507{
3508 struct bnx2x *bp = params->bp;
3509
3510 /* LED1 (10G Link): Disable LED1 when 10/100/1000 link */
3511 /* LED2 (1G/100/10 Link): Enable LED2 when 10/100/1000 link) */
3512 bnx2x_cl45_write(bp, params->port,
3513 ext_phy_type,
3514 ext_phy_addr,
3515 MDIO_AN_DEVAD,
3516 MDIO_AN_REG_8481_LEGACY_SHADOW,
3517 (1<<15) | (0xd << 10) | (0xc<<4) | 0xe);
3518}
3519
3520static void bnx2x_8481_set_10G_led_mode(struct link_params *params,
3521 u32 ext_phy_type, u8 ext_phy_addr)
3522{
3523 struct bnx2x *bp = params->bp;
3524 u16 val1;
3525
3526 /* LED1 (10G Link) */
3527 /* Enable continuse based on source 7(10G-link) */
3528 bnx2x_cl45_read(bp, params->port,
3529 ext_phy_type,
3530 ext_phy_addr,
3531 MDIO_PMA_DEVAD,
3532 MDIO_PMA_REG_8481_LINK_SIGNAL,
3533 &val1);
3534 /* Set bit 2 to 0, and bits [1:0] to 10 */
Yaniv Rosner46d15cc2009-11-05 19:18:30 +02003535 val1 &= ~((1<<0) | (1<<2) | (1<<7)); /* Clear bits 0,2,7*/
3536 val1 |= ((1<<1) | (1<<6)); /* Set bit 1, 6 */
Eilon Greenstein2f904462009-08-12 08:22:16 +00003537
3538 bnx2x_cl45_write(bp, params->port,
3539 ext_phy_type,
3540 ext_phy_addr,
3541 MDIO_PMA_DEVAD,
3542 MDIO_PMA_REG_8481_LINK_SIGNAL,
3543 val1);
3544
3545 /* Unmask LED1 for 10G link */
3546 bnx2x_cl45_read(bp, params->port,
3547 ext_phy_type,
3548 ext_phy_addr,
3549 MDIO_PMA_DEVAD,
3550 MDIO_PMA_REG_8481_LED1_MASK,
3551 &val1);
3552 /* Set bit 2 to 0, and bits [1:0] to 10 */
3553 val1 |= (1<<7);
3554 bnx2x_cl45_write(bp, params->port,
3555 ext_phy_type,
3556 ext_phy_addr,
3557 MDIO_PMA_DEVAD,
3558 MDIO_PMA_REG_8481_LED1_MASK,
3559 val1);
3560
3561 /* LED2 (1G/100/10G Link) */
3562 /* Mask LED2 for 10G link */
3563 bnx2x_cl45_write(bp, params->port,
3564 ext_phy_type,
3565 ext_phy_addr,
3566 MDIO_PMA_DEVAD,
3567 MDIO_PMA_REG_8481_LED2_MASK,
3568 0);
3569
Yaniv Rosner46d15cc2009-11-05 19:18:30 +02003570 /* Unmask LED3 for 10G link */
Eilon Greenstein2f904462009-08-12 08:22:16 +00003571 bnx2x_cl45_write(bp, params->port,
3572 ext_phy_type,
3573 ext_phy_addr,
3574 MDIO_PMA_DEVAD,
Eilon Greenstein2f904462009-08-12 08:22:16 +00003575 MDIO_PMA_REG_8481_LED3_MASK,
Yaniv Rosner46d15cc2009-11-05 19:18:30 +02003576 0x6);
Eilon Greenstein2f904462009-08-12 08:22:16 +00003577 bnx2x_cl45_write(bp, params->port,
3578 ext_phy_type,
3579 ext_phy_addr,
3580 MDIO_PMA_DEVAD,
Yaniv Rosner46d15cc2009-11-05 19:18:30 +02003581 MDIO_PMA_REG_8481_LED3_BLINK,
3582 0);
Eilon Greenstein2f904462009-08-12 08:22:16 +00003583}
3584
3585
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003586static void bnx2x_init_internal_phy(struct link_params *params,
Eilon Greenstein239d6862009-08-12 08:23:04 +00003587 struct link_vars *vars,
3588 u8 enable_cl73)
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003589{
3590 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00003591
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003592 if (!(vars->phy_flags & PHY_SGMII_FLAG)) {
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00003593 if ((XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
3594 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
3595 (params->feature_config_flags &
3596 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED))
3597 bnx2x_set_preemphasis(params);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003598
3599 /* forced speed requested? */
Yaniv Rosner7846e472009-11-05 19:18:07 +02003600 if (vars->line_speed != SPEED_AUTO_NEG ||
3601 ((XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
3602 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
3603 params->loopback_mode == LOOPBACK_EXT)) {
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003604 DP(NETIF_MSG_LINK, "not SGMII, no AN\n");
3605
3606 /* disable autoneg */
Eilon Greenstein239d6862009-08-12 08:23:04 +00003607 bnx2x_set_autoneg(params, vars, 0);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003608
3609 /* program speed and duplex */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003610 bnx2x_program_serdes(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003611
3612 } else { /* AN_mode */
3613 DP(NETIF_MSG_LINK, "not SGMII, AN\n");
3614
3615 /* AN enabled */
3616 bnx2x_set_brcm_cl37_advertisment(params);
3617
3618 /* program duplex & pause advertisement (for aneg) */
3619 bnx2x_set_ieee_aneg_advertisment(params,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003620 vars->ieee_fc);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003621
3622 /* enable autoneg */
Eilon Greenstein239d6862009-08-12 08:23:04 +00003623 bnx2x_set_autoneg(params, vars, enable_cl73);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003624
3625 /* enable and restart AN */
Eilon Greenstein239d6862009-08-12 08:23:04 +00003626 bnx2x_restart_autoneg(params, enable_cl73);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003627 }
3628
3629 } else { /* SGMII mode */
3630 DP(NETIF_MSG_LINK, "SGMII\n");
3631
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003632 bnx2x_initialize_sgmii_process(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003633 }
3634}
3635
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003636static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
3637{
3638 struct bnx2x *bp = params->bp;
3639 u32 ext_phy_type;
3640 u8 ext_phy_addr;
3641 u16 cnt;
3642 u16 ctrl = 0;
3643 u16 val = 0;
3644 u8 rc = 0;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00003645
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003646 if (vars->phy_flags & PHY_XGXS_FLAG) {
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00003647 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003648
3649 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3650 /* Make sure that the soft reset is off (expect for the 8072:
3651 * due to the lock, it will be done inside the specific
3652 * handling)
3653 */
3654 if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
3655 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
3656 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN) &&
3657 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) &&
3658 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073)) {
3659 /* Wait for soft reset to get cleared upto 1 sec */
3660 for (cnt = 0; cnt < 1000; cnt++) {
3661 bnx2x_cl45_read(bp, params->port,
3662 ext_phy_type,
3663 ext_phy_addr,
3664 MDIO_PMA_DEVAD,
3665 MDIO_PMA_REG_CTRL, &ctrl);
3666 if (!(ctrl & (1<<15)))
3667 break;
3668 msleep(1);
3669 }
3670 DP(NETIF_MSG_LINK, "control reg 0x%x (after %d ms)\n",
3671 ctrl, cnt);
3672 }
3673
3674 switch (ext_phy_type) {
3675 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003676 break;
3677
3678 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
3679 DP(NETIF_MSG_LINK, "XGXS 8705\n");
3680
3681 bnx2x_cl45_write(bp, params->port,
3682 ext_phy_type,
3683 ext_phy_addr,
3684 MDIO_PMA_DEVAD,
3685 MDIO_PMA_REG_MISC_CTRL,
3686 0x8288);
3687 bnx2x_cl45_write(bp, params->port,
3688 ext_phy_type,
3689 ext_phy_addr,
3690 MDIO_PMA_DEVAD,
3691 MDIO_PMA_REG_PHY_IDENTIFIER,
3692 0x7fbf);
3693 bnx2x_cl45_write(bp, params->port,
3694 ext_phy_type,
3695 ext_phy_addr,
3696 MDIO_PMA_DEVAD,
3697 MDIO_PMA_REG_CMU_PLL_BYPASS,
3698 0x0100);
3699 bnx2x_cl45_write(bp, params->port,
3700 ext_phy_type,
3701 ext_phy_addr,
3702 MDIO_WIS_DEVAD,
3703 MDIO_WIS_REG_LASI_CNTL, 0x1);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003704
Eilon Greenstein3b313b62009-03-02 08:00:10 +00003705 /* BCM8705 doesn't have microcode, hence the 0 */
3706 bnx2x_save_spirom_version(bp, params->port,
3707 params->shmem_base, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003708 break;
3709
3710 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003711 /* Wait until fw is loaded */
3712 for (cnt = 0; cnt < 100; cnt++) {
3713 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3714 ext_phy_addr, MDIO_PMA_DEVAD,
3715 MDIO_PMA_REG_ROM_VER1, &val);
3716 if (val)
3717 break;
3718 msleep(10);
3719 }
3720 DP(NETIF_MSG_LINK, "XGXS 8706 is initialized "
3721 "after %d ms\n", cnt);
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00003722 if ((params->feature_config_flags &
3723 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
3724 u8 i;
3725 u16 reg;
3726 for (i = 0; i < 4; i++) {
3727 reg = MDIO_XS_8706_REG_BANK_RX0 +
3728 i*(MDIO_XS_8706_REG_BANK_RX1 -
3729 MDIO_XS_8706_REG_BANK_RX0);
3730 bnx2x_cl45_read(bp, params->port,
3731 ext_phy_type,
3732 ext_phy_addr,
3733 MDIO_XS_DEVAD,
3734 reg, &val);
3735 /* Clear first 3 bits of the control */
3736 val &= ~0x7;
3737 /* Set control bits according to
3738 configuation */
3739 val |= (params->xgxs_config_rx[i] &
3740 0x7);
3741 DP(NETIF_MSG_LINK, "Setting RX"
3742 "Equalizer to BCM8706 reg 0x%x"
3743 " <-- val 0x%x\n", reg, val);
3744 bnx2x_cl45_write(bp, params->port,
3745 ext_phy_type,
3746 ext_phy_addr,
3747 MDIO_XS_DEVAD,
3748 reg, val);
3749 }
3750 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003751 /* Force speed */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003752 if (params->req_line_speed == SPEED_10000) {
3753 DP(NETIF_MSG_LINK, "XGXS 8706 force 10Gbps\n");
3754
3755 bnx2x_cl45_write(bp, params->port,
3756 ext_phy_type,
3757 ext_phy_addr,
3758 MDIO_PMA_DEVAD,
3759 MDIO_PMA_REG_DIGITAL_CTRL,
3760 0x400);
Yaniv Rosnerb5bbf002009-11-05 19:18:21 +02003761 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3762 ext_phy_addr, MDIO_PMA_DEVAD,
3763 MDIO_PMA_REG_LASI_CTRL, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003764 } else {
3765 /* Force 1Gbps using autoneg with 1G
3766 advertisment */
3767
3768 /* Allow CL37 through CL73 */
3769 DP(NETIF_MSG_LINK, "XGXS 8706 AutoNeg\n");
3770 bnx2x_cl45_write(bp, params->port,
3771 ext_phy_type,
3772 ext_phy_addr,
3773 MDIO_AN_DEVAD,
3774 MDIO_AN_REG_CL37_CL73,
3775 0x040c);
3776
3777 /* Enable Full-Duplex advertisment on CL37 */
3778 bnx2x_cl45_write(bp, params->port,
3779 ext_phy_type,
3780 ext_phy_addr,
3781 MDIO_AN_DEVAD,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003782 MDIO_AN_REG_CL37_FC_LP,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003783 0x0020);
3784 /* Enable CL37 AN */
3785 bnx2x_cl45_write(bp, params->port,
3786 ext_phy_type,
3787 ext_phy_addr,
3788 MDIO_AN_DEVAD,
3789 MDIO_AN_REG_CL37_AN,
3790 0x1000);
3791 /* 1G support */
3792 bnx2x_cl45_write(bp, params->port,
3793 ext_phy_type,
3794 ext_phy_addr,
3795 MDIO_AN_DEVAD,
3796 MDIO_AN_REG_ADV, (1<<5));
3797
3798 /* Enable clause 73 AN */
3799 bnx2x_cl45_write(bp, params->port,
3800 ext_phy_type,
3801 ext_phy_addr,
3802 MDIO_AN_DEVAD,
3803 MDIO_AN_REG_CTRL,
3804 0x1200);
Yaniv Rosnerb5bbf002009-11-05 19:18:21 +02003805 bnx2x_cl45_write(bp, params->port,
3806 ext_phy_type,
3807 ext_phy_addr,
3808 MDIO_PMA_DEVAD,
3809 MDIO_PMA_REG_RX_ALARM_CTRL,
3810 0x0400);
3811 bnx2x_cl45_write(bp, params->port,
3812 ext_phy_type,
3813 ext_phy_addr,
3814 MDIO_PMA_DEVAD,
3815 MDIO_PMA_REG_LASI_CTRL, 0x0004);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003816
3817 }
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003818 bnx2x_save_bcm_spirom_ver(bp, params->port,
3819 ext_phy_type,
3820 ext_phy_addr,
3821 params->shmem_base);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003822 break;
Eilon Greenstein589abe32009-02-12 08:36:55 +00003823 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
3824 DP(NETIF_MSG_LINK, "Initializing BCM8726\n");
3825 bnx2x_bcm8726_external_rom_boot(params);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003826
Eilon Greenstein589abe32009-02-12 08:36:55 +00003827 /* Need to call module detected on initialization since
3828 the module detection triggered by actual module
3829 insertion might occur before driver is loaded, and when
3830 driver is loaded, it reset all registers, including the
3831 transmitter */
3832 bnx2x_sfp_module_detection(params);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003833
3834 /* Set Flow control */
3835 bnx2x_ext_phy_set_pause(params, vars);
Eilon Greenstein589abe32009-02-12 08:36:55 +00003836 if (params->req_line_speed == SPEED_1000) {
3837 DP(NETIF_MSG_LINK, "Setting 1G force\n");
3838 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3839 ext_phy_addr, MDIO_PMA_DEVAD,
3840 MDIO_PMA_REG_CTRL, 0x40);
3841 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3842 ext_phy_addr, MDIO_PMA_DEVAD,
3843 MDIO_PMA_REG_10G_CTRL2, 0xD);
3844 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3845 ext_phy_addr, MDIO_PMA_DEVAD,
3846 MDIO_PMA_REG_LASI_CTRL, 0x5);
3847 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3848 ext_phy_addr, MDIO_PMA_DEVAD,
3849 MDIO_PMA_REG_RX_ALARM_CTRL,
3850 0x400);
3851 } else if ((params->req_line_speed ==
3852 SPEED_AUTO_NEG) &&
3853 ((params->speed_cap_mask &
3854 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G))) {
Frans Pop2381a552010-03-24 07:57:36 +00003855 DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
Eilon Greenstein589abe32009-02-12 08:36:55 +00003856 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3857 ext_phy_addr, MDIO_AN_DEVAD,
3858 MDIO_AN_REG_ADV, 0x20);
3859 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3860 ext_phy_addr, MDIO_AN_DEVAD,
3861 MDIO_AN_REG_CL37_CL73, 0x040c);
3862 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3863 ext_phy_addr, MDIO_AN_DEVAD,
3864 MDIO_AN_REG_CL37_FC_LD, 0x0020);
3865 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3866 ext_phy_addr, MDIO_AN_DEVAD,
3867 MDIO_AN_REG_CL37_AN, 0x1000);
3868 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3869 ext_phy_addr, MDIO_AN_DEVAD,
3870 MDIO_AN_REG_CTRL, 0x1200);
3871
3872 /* Enable RX-ALARM control to receive
3873 interrupt for 1G speed change */
3874 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3875 ext_phy_addr, MDIO_PMA_DEVAD,
3876 MDIO_PMA_REG_LASI_CTRL, 0x4);
3877 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3878 ext_phy_addr, MDIO_PMA_DEVAD,
3879 MDIO_PMA_REG_RX_ALARM_CTRL,
3880 0x400);
3881
3882 } else { /* Default 10G. Set only LASI control */
3883 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3884 ext_phy_addr, MDIO_PMA_DEVAD,
3885 MDIO_PMA_REG_LASI_CTRL, 1);
3886 }
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00003887
3888 /* Set TX PreEmphasis if needed */
3889 if ((params->feature_config_flags &
3890 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
3891 DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x,"
3892 "TX_CTRL2 0x%x\n",
3893 params->xgxs_config_tx[0],
3894 params->xgxs_config_tx[1]);
3895 bnx2x_cl45_write(bp, params->port,
3896 ext_phy_type,
3897 ext_phy_addr,
3898 MDIO_PMA_DEVAD,
3899 MDIO_PMA_REG_8726_TX_CTRL1,
3900 params->xgxs_config_tx[0]);
3901
3902 bnx2x_cl45_write(bp, params->port,
3903 ext_phy_type,
3904 ext_phy_addr,
3905 MDIO_PMA_DEVAD,
3906 MDIO_PMA_REG_8726_TX_CTRL2,
3907 params->xgxs_config_tx[1]);
3908 }
Eilon Greenstein589abe32009-02-12 08:36:55 +00003909 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003910 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
3911 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
3912 {
3913 u16 tmp1;
3914 u16 rx_alarm_ctrl_val;
3915 u16 lasi_ctrl_val;
3916 if (ext_phy_type ==
3917 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) {
3918 rx_alarm_ctrl_val = 0x400;
3919 lasi_ctrl_val = 0x0004;
3920 } else {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003921 rx_alarm_ctrl_val = (1<<2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003922 lasi_ctrl_val = 0x0004;
3923 }
3924
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003925 /* enable LASI */
3926 bnx2x_cl45_write(bp, params->port,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003927 ext_phy_type,
3928 ext_phy_addr,
3929 MDIO_PMA_DEVAD,
3930 MDIO_PMA_REG_RX_ALARM_CTRL,
3931 rx_alarm_ctrl_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003932
3933 bnx2x_cl45_write(bp, params->port,
3934 ext_phy_type,
3935 ext_phy_addr,
3936 MDIO_PMA_DEVAD,
3937 MDIO_PMA_REG_LASI_CTRL,
3938 lasi_ctrl_val);
3939
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003940 bnx2x_8073_set_pause_cl37(params, vars);
3941
3942 if (ext_phy_type ==
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00003943 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072)
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003944 bnx2x_bcm8072_external_rom_boot(params);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00003945 else
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003946 /* In case of 8073 with long xaui lines,
3947 don't set the 8073 xaui low power*/
3948 bnx2x_bcm8073_set_xaui_low_power_mode(params);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003949
3950 bnx2x_cl45_read(bp, params->port,
3951 ext_phy_type,
3952 ext_phy_addr,
3953 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00003954 MDIO_PMA_REG_M8051_MSGOUT_REG,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003955 &tmp1);
3956
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003957 bnx2x_cl45_read(bp, params->port,
3958 ext_phy_type,
3959 ext_phy_addr,
3960 MDIO_PMA_DEVAD,
3961 MDIO_PMA_REG_RX_ALARM, &tmp1);
3962
3963 DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1):"
3964 "0x%x\n", tmp1);
3965
3966 /* If this is forced speed, set to KR or KX
3967 * (all other are not supported)
3968 */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003969 if (params->loopback_mode == LOOPBACK_EXT) {
3970 bnx2x_bcm807x_force_10G(params);
3971 DP(NETIF_MSG_LINK,
3972 "Forced speed 10G on 807X\n");
3973 break;
3974 } else {
3975 bnx2x_cl45_write(bp, params->port,
3976 ext_phy_type, ext_phy_addr,
3977 MDIO_PMA_DEVAD,
3978 MDIO_PMA_REG_BCM_CTRL,
3979 0x0002);
3980 }
3981 if (params->req_line_speed != SPEED_AUTO_NEG) {
3982 if (params->req_line_speed == SPEED_10000) {
3983 val = (1<<7);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003984 } else if (params->req_line_speed ==
3985 SPEED_2500) {
3986 val = (1<<5);
3987 /* Note that 2.5G works only
3988 when used with 1G advertisment */
3989 } else
3990 val = (1<<5);
3991 } else {
3992
3993 val = 0;
3994 if (params->speed_cap_mask &
3995 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
3996 val |= (1<<7);
3997
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003998 /* Note that 2.5G works only when
3999 used with 1G advertisment */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004000 if (params->speed_cap_mask &
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004001 (PORT_HW_CFG_SPEED_CAPABILITY_D0_1G |
4002 PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G))
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004003 val |= (1<<5);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004004 DP(NETIF_MSG_LINK,
4005 "807x autoneg val = 0x%x\n", val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004006 }
4007
4008 bnx2x_cl45_write(bp, params->port,
4009 ext_phy_type,
4010 ext_phy_addr,
4011 MDIO_AN_DEVAD,
4012 MDIO_AN_REG_ADV, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004013 if (ext_phy_type ==
4014 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004015 bnx2x_cl45_read(bp, params->port,
4016 ext_phy_type,
4017 ext_phy_addr,
4018 MDIO_AN_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00004019 MDIO_AN_REG_8073_2_5G, &tmp1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004020
4021 if (((params->speed_cap_mask &
4022 PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G) &&
4023 (params->req_line_speed ==
4024 SPEED_AUTO_NEG)) ||
4025 (params->req_line_speed ==
4026 SPEED_2500)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004027 u16 phy_ver;
4028 /* Allow 2.5G for A1 and above */
4029 bnx2x_cl45_read(bp, params->port,
4030 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
4031 ext_phy_addr,
4032 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00004033 MDIO_PMA_REG_8073_CHIP_REV, &phy_ver);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004034 DP(NETIF_MSG_LINK, "Add 2.5G\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004035 if (phy_ver > 0)
4036 tmp1 |= 1;
4037 else
4038 tmp1 &= 0xfffe;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004039 } else {
4040 DP(NETIF_MSG_LINK, "Disable 2.5G\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004041 tmp1 &= 0xfffe;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004042 }
4043
4044 bnx2x_cl45_write(bp, params->port,
4045 ext_phy_type,
4046 ext_phy_addr,
4047 MDIO_AN_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00004048 MDIO_AN_REG_8073_2_5G, tmp1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004049 }
4050
4051 /* Add support for CL37 (passive mode) II */
4052
4053 bnx2x_cl45_read(bp, params->port,
4054 ext_phy_type,
4055 ext_phy_addr,
4056 MDIO_AN_DEVAD,
4057 MDIO_AN_REG_CL37_FC_LD,
4058 &tmp1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004059
4060 bnx2x_cl45_write(bp, params->port,
4061 ext_phy_type,
4062 ext_phy_addr,
4063 MDIO_AN_DEVAD,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004064 MDIO_AN_REG_CL37_FC_LD, (tmp1 |
4065 ((params->req_duplex == DUPLEX_FULL) ?
4066 0x20 : 0x40)));
4067
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004068 /* Add support for CL37 (passive mode) III */
4069 bnx2x_cl45_write(bp, params->port,
4070 ext_phy_type,
4071 ext_phy_addr,
4072 MDIO_AN_DEVAD,
4073 MDIO_AN_REG_CL37_AN, 0x1000);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004074
4075 if (ext_phy_type ==
4076 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004077 /* The SNR will improve about 2db by changing
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004078 BW and FEE main tap. Rest commands are executed
4079 after link is up*/
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004080 /*Change FFE main cursor to 5 in EDC register*/
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004081 if (bnx2x_8073_is_snr_needed(params))
4082 bnx2x_cl45_write(bp, params->port,
4083 ext_phy_type,
4084 ext_phy_addr,
4085 MDIO_PMA_DEVAD,
4086 MDIO_PMA_REG_EDC_FFE_MAIN,
4087 0xFB0C);
4088
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004089 /* Enable FEC (Forware Error Correction)
4090 Request in the AN */
4091 bnx2x_cl45_read(bp, params->port,
4092 ext_phy_type,
4093 ext_phy_addr,
4094 MDIO_AN_DEVAD,
4095 MDIO_AN_REG_ADV2, &tmp1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004096
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004097 tmp1 |= (1<<15);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004098
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004099 bnx2x_cl45_write(bp, params->port,
4100 ext_phy_type,
4101 ext_phy_addr,
4102 MDIO_AN_DEVAD,
4103 MDIO_AN_REG_ADV2, tmp1);
4104
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004105 }
4106
4107 bnx2x_ext_phy_set_pause(params, vars);
4108
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004109 /* Restart autoneg */
4110 msleep(500);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004111 bnx2x_cl45_write(bp, params->port,
4112 ext_phy_type,
4113 ext_phy_addr,
4114 MDIO_AN_DEVAD,
4115 MDIO_AN_REG_CTRL, 0x1200);
4116 DP(NETIF_MSG_LINK, "807x Autoneg Restart: "
4117 "Advertise 1G=%x, 10G=%x\n",
4118 ((val & (1<<5)) > 0),
4119 ((val & (1<<7)) > 0));
4120 break;
4121 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004122
4123 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
4124 {
4125 u16 tmp1;
4126 u16 rx_alarm_ctrl_val;
4127 u16 lasi_ctrl_val;
4128
4129 /* Enable PMD link, MOD_ABS_FLT, and 1G link alarm */
4130
4131 u16 mod_abs;
4132 rx_alarm_ctrl_val = (1<<2) | (1<<5) ;
4133 lasi_ctrl_val = 0x0004;
4134
4135 DP(NETIF_MSG_LINK, "Initializing BCM8727\n");
4136 /* enable LASI */
4137 bnx2x_cl45_write(bp, params->port,
4138 ext_phy_type,
4139 ext_phy_addr,
4140 MDIO_PMA_DEVAD,
4141 MDIO_PMA_REG_RX_ALARM_CTRL,
4142 rx_alarm_ctrl_val);
4143
4144 bnx2x_cl45_write(bp, params->port,
4145 ext_phy_type,
4146 ext_phy_addr,
4147 MDIO_PMA_DEVAD,
4148 MDIO_PMA_REG_LASI_CTRL,
4149 lasi_ctrl_val);
4150
4151 /* Initially configure MOD_ABS to interrupt when
4152 module is presence( bit 8) */
4153 bnx2x_cl45_read(bp, params->port,
4154 ext_phy_type,
4155 ext_phy_addr,
4156 MDIO_PMA_DEVAD,
4157 MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
4158 /* Set EDC off by setting OPTXLOS signal input to low
4159 (bit 9).
4160 When the EDC is off it locks onto a reference clock and
4161 avoids becoming 'lost'.*/
4162 mod_abs &= ~((1<<8) | (1<<9));
4163 bnx2x_cl45_write(bp, params->port,
4164 ext_phy_type,
4165 ext_phy_addr,
4166 MDIO_PMA_DEVAD,
4167 MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
4168
4169 /* Make MOD_ABS give interrupt on change */
4170 bnx2x_cl45_read(bp, params->port,
4171 ext_phy_type,
4172 ext_phy_addr,
4173 MDIO_PMA_DEVAD,
4174 MDIO_PMA_REG_8727_PCS_OPT_CTRL,
4175 &val);
4176 val |= (1<<12);
4177 bnx2x_cl45_write(bp, params->port,
4178 ext_phy_type,
4179 ext_phy_addr,
4180 MDIO_PMA_DEVAD,
4181 MDIO_PMA_REG_8727_PCS_OPT_CTRL,
4182 val);
4183
4184 /* Set 8727 GPIOs to input to allow reading from the
4185 8727 GPIO0 status which reflect SFP+ module
4186 over-current */
4187
4188 bnx2x_cl45_read(bp, params->port,
4189 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
4190 ext_phy_addr,
4191 MDIO_PMA_DEVAD,
4192 MDIO_PMA_REG_8727_PCS_OPT_CTRL,
4193 &val);
4194 val &= 0xff8f; /* Reset bits 4-6 */
4195 bnx2x_cl45_write(bp, params->port,
4196 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
4197 ext_phy_addr,
4198 MDIO_PMA_DEVAD,
4199 MDIO_PMA_REG_8727_PCS_OPT_CTRL,
4200 val);
4201
4202 bnx2x_8727_power_module(bp, params, ext_phy_addr, 1);
4203 bnx2x_bcm8073_set_xaui_low_power_mode(params);
4204
4205 bnx2x_cl45_read(bp, params->port,
4206 ext_phy_type,
4207 ext_phy_addr,
4208 MDIO_PMA_DEVAD,
4209 MDIO_PMA_REG_M8051_MSGOUT_REG,
4210 &tmp1);
4211
4212 bnx2x_cl45_read(bp, params->port,
4213 ext_phy_type,
4214 ext_phy_addr,
4215 MDIO_PMA_DEVAD,
4216 MDIO_PMA_REG_RX_ALARM, &tmp1);
4217
4218 /* Set option 1G speed */
4219 if (params->req_line_speed == SPEED_1000) {
4220
4221 DP(NETIF_MSG_LINK, "Setting 1G force\n");
4222 bnx2x_cl45_write(bp, params->port,
4223 ext_phy_type,
4224 ext_phy_addr,
4225 MDIO_PMA_DEVAD,
4226 MDIO_PMA_REG_CTRL, 0x40);
4227 bnx2x_cl45_write(bp, params->port,
4228 ext_phy_type,
4229 ext_phy_addr,
4230 MDIO_PMA_DEVAD,
4231 MDIO_PMA_REG_10G_CTRL2, 0xD);
4232 bnx2x_cl45_read(bp, params->port,
4233 ext_phy_type,
4234 ext_phy_addr,
4235 MDIO_PMA_DEVAD,
4236 MDIO_PMA_REG_10G_CTRL2, &tmp1);
Frans Pop2381a552010-03-24 07:57:36 +00004237 DP(NETIF_MSG_LINK, "1.7 = 0x%x\n", tmp1);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004238
4239 } else if ((params->req_line_speed ==
4240 SPEED_AUTO_NEG) &&
4241 ((params->speed_cap_mask &
Yaniv Rosnereb80ce72010-09-01 09:51:20 +00004242 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) &&
4243 ((params->speed_cap_mask &
4244 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) !=
4245 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
Frans Pop2381a552010-03-24 07:57:36 +00004246 DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004247 bnx2x_cl45_write(bp, params->port, ext_phy_type,
4248 ext_phy_addr, MDIO_AN_DEVAD,
4249 MDIO_PMA_REG_8727_MISC_CTRL, 0);
4250 bnx2x_cl45_write(bp, params->port, ext_phy_type,
4251 ext_phy_addr, MDIO_AN_DEVAD,
4252 MDIO_AN_REG_CL37_AN, 0x1300);
4253 } else {
4254 /* Since the 8727 has only single reset pin,
4255 need to set the 10G registers although it is
4256 default */
4257 bnx2x_cl45_write(bp, params->port, ext_phy_type,
Yaniv Rosnereb80ce72010-09-01 09:51:20 +00004258 ext_phy_addr, MDIO_AN_DEVAD,
4259 MDIO_AN_REG_8727_MISC_CTRL,
4260 0x0020);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004261 bnx2x_cl45_write(bp, params->port, ext_phy_type,
Yaniv Rosnereb80ce72010-09-01 09:51:20 +00004262 ext_phy_addr, MDIO_AN_DEVAD,
4263 MDIO_AN_REG_CL37_AN, 0x0100);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004264 bnx2x_cl45_write(bp, params->port, ext_phy_type,
Yaniv Rosnereb80ce72010-09-01 09:51:20 +00004265 ext_phy_addr, MDIO_PMA_DEVAD,
4266 MDIO_PMA_REG_CTRL, 0x2040);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004267 bnx2x_cl45_write(bp, params->port, ext_phy_type,
Yaniv Rosnereb80ce72010-09-01 09:51:20 +00004268 ext_phy_addr, MDIO_PMA_DEVAD,
4269 MDIO_PMA_REG_10G_CTRL2, 0x0008);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004270 }
4271
Yaniv Rosner1ab6c162010-06-14 23:25:19 -07004272 /* Set 2-wire transfer rate of SFP+ module EEPROM
4273 * to 100Khz since some DACs(direct attached cables) do
4274 * not work at 400Khz.
4275 */
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004276 bnx2x_cl45_write(bp, params->port,
4277 ext_phy_type,
4278 ext_phy_addr,
4279 MDIO_PMA_DEVAD,
4280 MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR,
Yaniv Rosner1ab6c162010-06-14 23:25:19 -07004281 0xa001);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004282
4283 /* Set TX PreEmphasis if needed */
4284 if ((params->feature_config_flags &
4285 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
4286 DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x,"
4287 "TX_CTRL2 0x%x\n",
4288 params->xgxs_config_tx[0],
4289 params->xgxs_config_tx[1]);
4290 bnx2x_cl45_write(bp, params->port,
4291 ext_phy_type,
4292 ext_phy_addr,
4293 MDIO_PMA_DEVAD,
4294 MDIO_PMA_REG_8727_TX_CTRL1,
4295 params->xgxs_config_tx[0]);
4296
4297 bnx2x_cl45_write(bp, params->port,
4298 ext_phy_type,
4299 ext_phy_addr,
4300 MDIO_PMA_DEVAD,
4301 MDIO_PMA_REG_8727_TX_CTRL2,
4302 params->xgxs_config_tx[1]);
4303 }
4304
4305 break;
4306 }
4307
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004308 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
Eilon Greensteina35da8d2009-02-12 08:37:02 +00004309 {
4310 u16 fw_ver1, fw_ver2;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004311 DP(NETIF_MSG_LINK,
4312 "Setting the SFX7101 LASI indication\n");
4313
4314 bnx2x_cl45_write(bp, params->port,
4315 ext_phy_type,
4316 ext_phy_addr,
4317 MDIO_PMA_DEVAD,
4318 MDIO_PMA_REG_LASI_CTRL, 0x1);
4319 DP(NETIF_MSG_LINK,
4320 "Setting the SFX7101 LED to blink on traffic\n");
4321 bnx2x_cl45_write(bp, params->port,
4322 ext_phy_type,
4323 ext_phy_addr,
4324 MDIO_PMA_DEVAD,
4325 MDIO_PMA_REG_7107_LED_CNTL, (1<<3));
4326
4327 bnx2x_ext_phy_set_pause(params, vars);
4328 /* Restart autoneg */
4329 bnx2x_cl45_read(bp, params->port,
4330 ext_phy_type,
4331 ext_phy_addr,
4332 MDIO_AN_DEVAD,
4333 MDIO_AN_REG_CTRL, &val);
4334 val |= 0x200;
4335 bnx2x_cl45_write(bp, params->port,
4336 ext_phy_type,
4337 ext_phy_addr,
4338 MDIO_AN_DEVAD,
4339 MDIO_AN_REG_CTRL, val);
Eilon Greenstein28577182009-02-12 08:37:00 +00004340
Eilon Greensteina35da8d2009-02-12 08:37:02 +00004341 /* Save spirom version */
4342 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4343 ext_phy_addr, MDIO_PMA_DEVAD,
4344 MDIO_PMA_REG_7101_VER1, &fw_ver1);
4345
4346 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4347 ext_phy_addr, MDIO_PMA_DEVAD,
4348 MDIO_PMA_REG_7101_VER2, &fw_ver2);
4349
4350 bnx2x_save_spirom_version(params->bp, params->port,
4351 params->shmem_base,
4352 (u32)(fw_ver1<<16 | fw_ver2));
Eilon Greenstein28577182009-02-12 08:37:00 +00004353 break;
Eilon Greensteina35da8d2009-02-12 08:37:02 +00004354 }
Eilon Greenstein28577182009-02-12 08:37:00 +00004355 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02004356 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
Yaniv Rosnerac4d9442010-09-01 09:51:25 +00004357 {
Eilon Greenstein2f904462009-08-12 08:22:16 +00004358 /* This phy uses the NIG latch mechanism since link
4359 indication arrives through its LED4 and not via
4360 its LASI signal, so we get steady signal
4361 instead of clear on read */
Yaniv Rosnerac4d9442010-09-01 09:51:25 +00004362 u16 autoneg_val, an_1000_val, an_10_100_val;
Eilon Greenstein2f904462009-08-12 08:22:16 +00004363 bnx2x_bits_en(bp, NIG_REG_LATCH_BC_0 + params->port*4,
Yaniv Rosnerac4d9442010-09-01 09:51:25 +00004364 1 << NIG_LATCH_BC_ENABLE_MI_INT);
Eilon Greenstein28577182009-02-12 08:37:00 +00004365
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02004366 bnx2x_cl45_write(bp, params->port,
Yaniv Rosnerac4d9442010-09-01 09:51:25 +00004367 ext_phy_type,
4368 ext_phy_addr,
4369 MDIO_PMA_DEVAD,
4370 MDIO_PMA_REG_CTRL, 0x0000);
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02004371
Eilon Greenstein2f904462009-08-12 08:22:16 +00004372 bnx2x_8481_set_led4(params, ext_phy_type, ext_phy_addr);
Eilon Greenstein28577182009-02-12 08:37:00 +00004373
Yaniv Rosnerac4d9442010-09-01 09:51:25 +00004374 bnx2x_cl45_read(bp, params->port,
4375 ext_phy_type,
4376 ext_phy_addr,
4377 MDIO_AN_DEVAD,
4378 MDIO_AN_REG_8481_1000T_CTRL,
4379 &an_1000_val);
4380 bnx2x_ext_phy_set_pause(params, vars);
4381 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4382 ext_phy_addr, MDIO_AN_DEVAD,
4383 MDIO_AN_REG_8481_LEGACY_AN_ADV,
4384 &an_10_100_val);
4385 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4386 ext_phy_addr, MDIO_AN_DEVAD,
4387 MDIO_AN_REG_8481_LEGACY_MII_CTRL,
4388 &autoneg_val);
4389 /* Disable forced speed */
4390 autoneg_val &= ~((1<<6) | (1<<8) | (1<<9) | (1<<12) |
4391 (1<<13));
4392 an_10_100_val &= ~((1<<5) | (1<<6) | (1<<7) | (1<<8));
Eilon Greenstein2f904462009-08-12 08:22:16 +00004393
Yaniv Rosnerac4d9442010-09-01 09:51:25 +00004394 if (((params->req_line_speed == SPEED_AUTO_NEG) &&
4395 (params->speed_cap_mask &
4396 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) ||
4397 (params->req_line_speed == SPEED_1000)) {
4398 an_1000_val |= (1<<8);
4399 autoneg_val |= (1<<9 | 1<<12);
Eilon Greenstein2f904462009-08-12 08:22:16 +00004400 if (params->req_duplex == DUPLEX_FULL)
Yaniv Rosnerac4d9442010-09-01 09:51:25 +00004401 an_1000_val |= (1<<9);
4402 DP(NETIF_MSG_LINK, "Advertising 1G\n");
4403 } else
4404 an_1000_val &= ~((1<<8) | (1<<9));
Yaniv Rosner46d15cc2009-11-05 19:18:30 +02004405
Eilon Greenstein28577182009-02-12 08:37:00 +00004406 bnx2x_cl45_write(bp, params->port,
Yaniv Rosnerac4d9442010-09-01 09:51:25 +00004407 ext_phy_type,
4408 ext_phy_addr,
4409 MDIO_AN_DEVAD,
4410 MDIO_AN_REG_8481_1000T_CTRL,
4411 an_1000_val);
Eilon Greenstein2f904462009-08-12 08:22:16 +00004412
Yaniv Rosnerac4d9442010-09-01 09:51:25 +00004413 /* set 10 speed advertisement */
4414 if (((params->req_line_speed == SPEED_AUTO_NEG) &&
4415 (params->speed_cap_mask &
4416 (PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL |
4417 PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF)))) {
4418 an_10_100_val |= (1<<7);
4419 /*
4420 * Enable autoneg and restart autoneg for
4421 * legacy speeds
4422 */
4423 autoneg_val |= (1<<9 | 1<<12);
Eilon Greenstein2f904462009-08-12 08:22:16 +00004424
Yaniv Rosnerac4d9442010-09-01 09:51:25 +00004425 if (params->req_duplex == DUPLEX_FULL)
4426 an_10_100_val |= (1<<8);
4427 DP(NETIF_MSG_LINK, "Advertising 100M\n");
Eilon Greenstein2f904462009-08-12 08:22:16 +00004428 }
Yaniv Rosnerac4d9442010-09-01 09:51:25 +00004429 /* set 10 speed advertisement */
4430 if (((params->req_line_speed == SPEED_AUTO_NEG) &&
4431 (params->speed_cap_mask &
4432 (PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL |
4433 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF)))) {
4434 an_10_100_val |= (1<<5);
4435 autoneg_val |= (1<<9 | 1<<12);
4436 if (params->req_duplex == DUPLEX_FULL)
4437 an_10_100_val |= (1<<6);
4438 DP(NETIF_MSG_LINK, "Advertising 10M\n");
4439 }
4440
4441 /* Only 10/100 are allowed to work in FORCE mode */
4442 if (params->req_line_speed == SPEED_100) {
4443 autoneg_val |= (1<<13);
4444 /* Enabled AUTO-MDIX when autoneg is disabled */
4445 bnx2x_cl45_write(bp, params->port,
4446 ext_phy_type,
4447 ext_phy_addr,
4448 MDIO_AN_DEVAD,
4449 MDIO_AN_REG_8481_AUX_CTRL,
4450 (1<<15 | 1<<9 | 7<<0));
4451 DP(NETIF_MSG_LINK, "Setting 100M force\n");
4452 }
4453 if (params->req_line_speed == SPEED_10) {
4454 /* Enabled AUTO-MDIX when autoneg is disabled */
4455 bnx2x_cl45_write(bp, params->port,
4456 ext_phy_type,
4457 ext_phy_addr,
4458 MDIO_AN_DEVAD,
4459 MDIO_AN_REG_8481_AUX_CTRL,
4460 (1<<15 | 1<<9 | 7<<0));
4461 DP(NETIF_MSG_LINK, "Setting 10M force\n");
4462 }
4463
4464 bnx2x_cl45_write(bp, params->port,
4465 ext_phy_type,
4466 ext_phy_addr,
4467 MDIO_AN_DEVAD,
4468 MDIO_AN_REG_8481_LEGACY_AN_ADV,
4469 an_10_100_val);
4470
4471 if (params->req_duplex == DUPLEX_FULL)
4472 autoneg_val |= (1<<8);
4473
4474 bnx2x_cl45_write(bp, params->port,
4475 ext_phy_type,
4476 ext_phy_addr,
4477 MDIO_AN_DEVAD,
4478 MDIO_AN_REG_8481_LEGACY_MII_CTRL,
4479 autoneg_val);
4480
4481 if (((params->req_line_speed == SPEED_AUTO_NEG) &&
4482 (params->speed_cap_mask &
4483 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) ||
4484 (params->req_line_speed == SPEED_10000)) {
4485 DP(NETIF_MSG_LINK, "Advertising 10G\n");
4486 /* Restart autoneg for 10G*/
4487
4488 bnx2x_cl45_write(bp, params->port,
4489 ext_phy_type,
4490 ext_phy_addr,
4491 MDIO_AN_DEVAD,
4492 MDIO_AN_REG_CTRL,
4493 0x3200);
4494
4495 } else if (params->req_line_speed != SPEED_10 &&
4496 params->req_line_speed != SPEED_100)
4497 bnx2x_cl45_write(bp, params->port,
4498 ext_phy_type,
4499 ext_phy_addr,
4500 MDIO_AN_DEVAD,
4501 MDIO_AN_REG_8481_10GBASE_T_AN_CTRL,
4502 1);
Eilon Greenstein28577182009-02-12 08:37:00 +00004503
Eilon Greensteinb1607af2009-08-12 08:22:54 +00004504 /* Save spirom version */
4505 bnx2x_save_8481_spirom_version(bp, params->port,
4506 ext_phy_addr,
4507 params->shmem_base);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004508 break;
Yaniv Rosnerac4d9442010-09-01 09:51:25 +00004509 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004510 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
4511 DP(NETIF_MSG_LINK,
4512 "XGXS PHY Failure detected 0x%x\n",
4513 params->ext_phy_config);
4514 rc = -EINVAL;
4515 break;
4516 default:
4517 DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
4518 params->ext_phy_config);
4519 rc = -EINVAL;
4520 break;
4521 }
4522
4523 } else { /* SerDes */
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004524
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004525 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
4526 switch (ext_phy_type) {
4527 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
4528 DP(NETIF_MSG_LINK, "SerDes Direct\n");
4529 break;
4530
4531 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
4532 DP(NETIF_MSG_LINK, "SerDes 5482\n");
4533 break;
4534
4535 default:
4536 DP(NETIF_MSG_LINK, "BAD SerDes ext_phy_config 0x%x\n",
4537 params->ext_phy_config);
4538 break;
4539 }
4540 }
4541 return rc;
4542}
4543
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004544static void bnx2x_8727_handle_mod_abs(struct link_params *params)
4545{
4546 struct bnx2x *bp = params->bp;
4547 u16 mod_abs, rx_alarm_status;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00004548 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004549 u32 val = REG_RD(bp, params->shmem_base +
4550 offsetof(struct shmem_region, dev_info.
4551 port_feature_config[params->port].
4552 config));
4553 bnx2x_cl45_read(bp, params->port,
4554 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
4555 ext_phy_addr,
4556 MDIO_PMA_DEVAD,
4557 MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
4558 if (mod_abs & (1<<8)) {
4559
4560 /* Module is absent */
4561 DP(NETIF_MSG_LINK, "MOD_ABS indication "
4562 "show module is absent\n");
4563
4564 /* 1. Set mod_abs to detect next module
4565 presence event
4566 2. Set EDC off by setting OPTXLOS signal input to low
4567 (bit 9).
4568 When the EDC is off it locks onto a reference clock and
4569 avoids becoming 'lost'.*/
4570 mod_abs &= ~((1<<8)|(1<<9));
4571 bnx2x_cl45_write(bp, params->port,
4572 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
4573 ext_phy_addr,
4574 MDIO_PMA_DEVAD,
4575 MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
4576
4577 /* Clear RX alarm since it stays up as long as
4578 the mod_abs wasn't changed */
4579 bnx2x_cl45_read(bp, params->port,
4580 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
4581 ext_phy_addr,
4582 MDIO_PMA_DEVAD,
4583 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
4584
4585 } else {
4586 /* Module is present */
4587 DP(NETIF_MSG_LINK, "MOD_ABS indication "
4588 "show module is present\n");
4589 /* First thing, disable transmitter,
4590 and if the module is ok, the
4591 module_detection will enable it*/
4592
4593 /* 1. Set mod_abs to detect next module
4594 absent event ( bit 8)
4595 2. Restore the default polarity of the OPRXLOS signal and
4596 this signal will then correctly indicate the presence or
4597 absence of the Rx signal. (bit 9) */
4598 mod_abs |= ((1<<8)|(1<<9));
4599 bnx2x_cl45_write(bp, params->port,
4600 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
4601 ext_phy_addr,
4602 MDIO_PMA_DEVAD,
4603 MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
4604
4605 /* Clear RX alarm since it stays up as long as
4606 the mod_abs wasn't changed. This is need to be done
4607 before calling the module detection, otherwise it will clear
4608 the link update alarm */
4609 bnx2x_cl45_read(bp, params->port,
4610 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
4611 ext_phy_addr,
4612 MDIO_PMA_DEVAD,
4613 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
4614
4615
4616 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
4617 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
4618 bnx2x_sfp_set_transmitter(bp, params->port,
4619 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
4620 ext_phy_addr, 0);
4621
4622 if (bnx2x_wait_for_sfp_module_initialized(params)
4623 == 0)
4624 bnx2x_sfp_module_detection(params);
4625 else
4626 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
4627 }
4628
4629 DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n",
4630 rx_alarm_status);
4631 /* No need to check link status in case of
4632 module plugged in/out */
4633}
4634
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004635
4636static u8 bnx2x_ext_phy_is_link_up(struct link_params *params,
Eilon Greenstein2f904462009-08-12 08:22:16 +00004637 struct link_vars *vars,
4638 u8 is_mi_int)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004639{
4640 struct bnx2x *bp = params->bp;
4641 u32 ext_phy_type;
4642 u8 ext_phy_addr;
4643 u16 val1 = 0, val2;
4644 u16 rx_sd, pcs_status;
4645 u8 ext_phy_link_up = 0;
4646 u8 port = params->port;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00004647
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004648 if (vars->phy_flags & PHY_XGXS_FLAG) {
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00004649 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004650 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
4651 switch (ext_phy_type) {
4652 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
4653 DP(NETIF_MSG_LINK, "XGXS Direct\n");
4654 ext_phy_link_up = 1;
4655 break;
4656
4657 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
4658 DP(NETIF_MSG_LINK, "XGXS 8705\n");
4659 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4660 ext_phy_addr,
4661 MDIO_WIS_DEVAD,
4662 MDIO_WIS_REG_LASI_STATUS, &val1);
4663 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
4664
4665 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4666 ext_phy_addr,
4667 MDIO_WIS_DEVAD,
4668 MDIO_WIS_REG_LASI_STATUS, &val1);
4669 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
4670
4671 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4672 ext_phy_addr,
4673 MDIO_PMA_DEVAD,
4674 MDIO_PMA_REG_RX_SD, &rx_sd);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004675
4676 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4677 ext_phy_addr,
4678 1,
4679 0xc809, &val1);
4680 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4681 ext_phy_addr,
4682 1,
4683 0xc809, &val1);
4684
4685 DP(NETIF_MSG_LINK, "8705 1.c809 val=0x%x\n", val1);
Joe Perches8e95a202009-12-03 07:58:21 +00004686 ext_phy_link_up = ((rx_sd & 0x1) && (val1 & (1<<9)) &&
4687 ((val1 & (1<<8)) == 0));
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07004688 if (ext_phy_link_up)
4689 vars->line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004690 break;
4691
4692 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
Eilon Greenstein589abe32009-02-12 08:36:55 +00004693 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
4694 DP(NETIF_MSG_LINK, "XGXS 8706/8726\n");
4695 /* Clear RX Alarm*/
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004696 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4697 ext_phy_addr,
Eilon Greenstein589abe32009-02-12 08:36:55 +00004698 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM,
4699 &val2);
4700 /* clear LASI indication*/
4701 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4702 ext_phy_addr,
4703 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS,
4704 &val1);
4705 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4706 ext_phy_addr,
4707 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS,
4708 &val2);
4709 DP(NETIF_MSG_LINK, "8706/8726 LASI status 0x%x-->"
4710 "0x%x\n", val1, val2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004711
4712 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4713 ext_phy_addr,
Eilon Greenstein589abe32009-02-12 08:36:55 +00004714 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD,
4715 &rx_sd);
4716 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4717 ext_phy_addr,
4718 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS,
4719 &pcs_status);
4720 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4721 ext_phy_addr,
4722 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS,
4723 &val2);
4724 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4725 ext_phy_addr,
4726 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS,
4727 &val2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004728
Eilon Greenstein589abe32009-02-12 08:36:55 +00004729 DP(NETIF_MSG_LINK, "8706/8726 rx_sd 0x%x"
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004730 " pcs_status 0x%x 1Gbps link_status 0x%x\n",
4731 rx_sd, pcs_status, val2);
4732 /* link is up if both bit 0 of pmd_rx_sd and
4733 * bit 0 of pcs_status are set, or if the autoneg bit
4734 1 is set
4735 */
4736 ext_phy_link_up = ((rx_sd & pcs_status & 0x1) ||
4737 (val2 & (1<<1)));
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004738 if (ext_phy_link_up) {
Eilon Greenstein589abe32009-02-12 08:36:55 +00004739 if (ext_phy_type ==
4740 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) {
4741 /* If transmitter is disabled,
4742 ignore false link up indication */
4743 bnx2x_cl45_read(bp, params->port,
4744 ext_phy_type,
4745 ext_phy_addr,
4746 MDIO_PMA_DEVAD,
4747 MDIO_PMA_REG_PHY_IDENTIFIER,
4748 &val1);
4749 if (val1 & (1<<15)) {
4750 DP(NETIF_MSG_LINK, "Tx is "
4751 "disabled\n");
4752 ext_phy_link_up = 0;
4753 break;
4754 }
4755 }
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004756 if (val2 & (1<<1))
4757 vars->line_speed = SPEED_1000;
4758 else
4759 vars->line_speed = SPEED_10000;
4760 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004761 break;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004762
4763 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
4764 {
4765 u16 link_status = 0;
4766 u16 rx_alarm_status;
4767 /* Check the LASI */
4768 bnx2x_cl45_read(bp, params->port,
4769 ext_phy_type,
4770 ext_phy_addr,
4771 MDIO_PMA_DEVAD,
4772 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
4773
4774 DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n",
4775 rx_alarm_status);
4776
4777 bnx2x_cl45_read(bp, params->port,
4778 ext_phy_type,
4779 ext_phy_addr,
4780 MDIO_PMA_DEVAD,
4781 MDIO_PMA_REG_LASI_STATUS, &val1);
4782
4783 DP(NETIF_MSG_LINK,
4784 "8727 LASI status 0x%x\n",
4785 val1);
4786
4787 /* Clear MSG-OUT */
4788 bnx2x_cl45_read(bp, params->port,
4789 ext_phy_type,
4790 ext_phy_addr,
4791 MDIO_PMA_DEVAD,
4792 MDIO_PMA_REG_M8051_MSGOUT_REG,
4793 &val1);
4794
4795 /*
4796 * If a module is present and there is need to check
4797 * for over current
4798 */
4799 if (!(params->feature_config_flags &
4800 FEATURE_CONFIG_BCM8727_NOC) &&
4801 !(rx_alarm_status & (1<<5))) {
4802 /* Check over-current using 8727 GPIO0 input*/
4803 bnx2x_cl45_read(bp, params->port,
4804 ext_phy_type,
4805 ext_phy_addr,
4806 MDIO_PMA_DEVAD,
4807 MDIO_PMA_REG_8727_GPIO_CTRL,
4808 &val1);
4809
4810 if ((val1 & (1<<8)) == 0) {
4811 DP(NETIF_MSG_LINK, "8727 Power fault"
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00004812 " has been detected on "
4813 "port %d\n",
4814 params->port);
Joe Perches7995c642010-02-17 15:01:52 +00004815 netdev_err(bp->dev, "Error: Power fault on Port %d has been detected and the power to that SFP+ module has been removed to prevent failure of the card. Please remove the SFP+ module and restart the system to clear this error.\n",
4816 params->port);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004817 /*
4818 * Disable all RX_ALARMs except for
4819 * mod_abs
4820 */
4821 bnx2x_cl45_write(bp, params->port,
4822 ext_phy_type,
4823 ext_phy_addr,
4824 MDIO_PMA_DEVAD,
4825 MDIO_PMA_REG_RX_ALARM_CTRL,
4826 (1<<5));
4827
4828 bnx2x_cl45_read(bp, params->port,
4829 ext_phy_type,
4830 ext_phy_addr,
4831 MDIO_PMA_DEVAD,
4832 MDIO_PMA_REG_PHY_IDENTIFIER,
4833 &val1);
4834 /* Wait for module_absent_event */
4835 val1 |= (1<<8);
4836 bnx2x_cl45_write(bp, params->port,
4837 ext_phy_type,
4838 ext_phy_addr,
4839 MDIO_PMA_DEVAD,
4840 MDIO_PMA_REG_PHY_IDENTIFIER,
4841 val1);
4842 /* Clear RX alarm */
4843 bnx2x_cl45_read(bp, params->port,
4844 ext_phy_type,
4845 ext_phy_addr,
4846 MDIO_PMA_DEVAD,
4847 MDIO_PMA_REG_RX_ALARM,
4848 &rx_alarm_status);
4849 break;
4850 }
4851 } /* Over current check */
4852
4853 /* When module absent bit is set, check module */
4854 if (rx_alarm_status & (1<<5)) {
4855 bnx2x_8727_handle_mod_abs(params);
4856 /* Enable all mod_abs and link detection bits */
4857 bnx2x_cl45_write(bp, params->port,
4858 ext_phy_type,
4859 ext_phy_addr,
4860 MDIO_PMA_DEVAD,
4861 MDIO_PMA_REG_RX_ALARM_CTRL,
4862 ((1<<5) | (1<<2)));
4863 }
4864
4865 /* If transmitter is disabled,
4866 ignore false link up indication */
4867 bnx2x_cl45_read(bp, params->port,
4868 ext_phy_type,
4869 ext_phy_addr,
4870 MDIO_PMA_DEVAD,
4871 MDIO_PMA_REG_PHY_IDENTIFIER,
4872 &val1);
4873 if (val1 & (1<<15)) {
4874 DP(NETIF_MSG_LINK, "Tx is disabled\n");
4875 ext_phy_link_up = 0;
4876 break;
4877 }
4878
4879 bnx2x_cl45_read(bp, params->port,
4880 ext_phy_type,
4881 ext_phy_addr,
4882 MDIO_PMA_DEVAD,
4883 MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
4884 &link_status);
4885
4886 /* Bits 0..2 --> speed detected,
4887 bits 13..15--> link is down */
4888 if ((link_status & (1<<2)) &&
4889 (!(link_status & (1<<15)))) {
4890 ext_phy_link_up = 1;
4891 vars->line_speed = SPEED_10000;
4892 } else if ((link_status & (1<<0)) &&
4893 (!(link_status & (1<<13)))) {
4894 ext_phy_link_up = 1;
4895 vars->line_speed = SPEED_1000;
4896 DP(NETIF_MSG_LINK,
4897 "port %x: External link"
4898 " up in 1G\n", params->port);
4899 } else {
4900 ext_phy_link_up = 0;
4901 DP(NETIF_MSG_LINK,
4902 "port %x: External link"
4903 " is down\n", params->port);
4904 }
4905 break;
4906 }
4907
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004908 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
4909 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
4910 {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004911 u16 link_status = 0;
4912 u16 an1000_status = 0;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00004913
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004914 if (ext_phy_type ==
4915 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) {
4916 bnx2x_cl45_read(bp, params->port,
4917 ext_phy_type,
4918 ext_phy_addr,
4919 MDIO_PCS_DEVAD,
4920 MDIO_PCS_REG_LASI_STATUS, &val1);
4921 bnx2x_cl45_read(bp, params->port,
4922 ext_phy_type,
4923 ext_phy_addr,
4924 MDIO_PCS_DEVAD,
4925 MDIO_PCS_REG_LASI_STATUS, &val2);
4926 DP(NETIF_MSG_LINK,
4927 "870x LASI status 0x%x->0x%x\n",
4928 val1, val2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004929 } else {
4930 /* In 8073, port1 is directed through emac0 and
4931 * port0 is directed through emac1
4932 */
4933 bnx2x_cl45_read(bp, params->port,
4934 ext_phy_type,
4935 ext_phy_addr,
4936 MDIO_PMA_DEVAD,
4937 MDIO_PMA_REG_LASI_STATUS, &val1);
4938
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004939 DP(NETIF_MSG_LINK,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004940 "8703 LASI status 0x%x\n",
4941 val1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004942 }
4943
4944 /* clear the interrupt LASI status register */
4945 bnx2x_cl45_read(bp, params->port,
4946 ext_phy_type,
4947 ext_phy_addr,
4948 MDIO_PCS_DEVAD,
4949 MDIO_PCS_REG_STATUS, &val2);
4950 bnx2x_cl45_read(bp, params->port,
4951 ext_phy_type,
4952 ext_phy_addr,
4953 MDIO_PCS_DEVAD,
4954 MDIO_PCS_REG_STATUS, &val1);
4955 DP(NETIF_MSG_LINK, "807x PCS status 0x%x->0x%x\n",
4956 val2, val1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004957 /* Clear MSG-OUT */
4958 bnx2x_cl45_read(bp, params->port,
4959 ext_phy_type,
4960 ext_phy_addr,
4961 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00004962 MDIO_PMA_REG_M8051_MSGOUT_REG,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004963 &val1);
4964
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004965 /* Check the LASI */
4966 bnx2x_cl45_read(bp, params->port,
4967 ext_phy_type,
4968 ext_phy_addr,
4969 MDIO_PMA_DEVAD,
4970 MDIO_PMA_REG_RX_ALARM, &val2);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004971
4972 DP(NETIF_MSG_LINK, "KR 0x9003 0x%x\n", val2);
4973
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004974 /* Check the link status */
4975 bnx2x_cl45_read(bp, params->port,
4976 ext_phy_type,
4977 ext_phy_addr,
4978 MDIO_PCS_DEVAD,
4979 MDIO_PCS_REG_STATUS, &val2);
4980 DP(NETIF_MSG_LINK, "KR PCS status 0x%x\n", val2);
4981
4982 bnx2x_cl45_read(bp, params->port,
4983 ext_phy_type,
4984 ext_phy_addr,
4985 MDIO_PMA_DEVAD,
4986 MDIO_PMA_REG_STATUS, &val2);
4987 bnx2x_cl45_read(bp, params->port,
4988 ext_phy_type,
4989 ext_phy_addr,
4990 MDIO_PMA_DEVAD,
4991 MDIO_PMA_REG_STATUS, &val1);
4992 ext_phy_link_up = ((val1 & 4) == 4);
4993 DP(NETIF_MSG_LINK, "PMA_REG_STATUS=0x%x\n", val1);
4994 if (ext_phy_type ==
4995 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004996
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004997 if (ext_phy_link_up &&
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004998 ((params->req_line_speed !=
4999 SPEED_10000))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005000 if (bnx2x_bcm8073_xaui_wa(params)
5001 != 0) {
5002 ext_phy_link_up = 0;
5003 break;
5004 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005005 }
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005006 bnx2x_cl45_read(bp, params->port,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00005007 ext_phy_type,
5008 ext_phy_addr,
5009 MDIO_AN_DEVAD,
5010 MDIO_AN_REG_LINK_STATUS,
5011 &an1000_status);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005012 bnx2x_cl45_read(bp, params->port,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00005013 ext_phy_type,
5014 ext_phy_addr,
5015 MDIO_AN_DEVAD,
5016 MDIO_AN_REG_LINK_STATUS,
5017 &an1000_status);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005018
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005019 /* Check the link status on 1.1.2 */
5020 bnx2x_cl45_read(bp, params->port,
5021 ext_phy_type,
5022 ext_phy_addr,
5023 MDIO_PMA_DEVAD,
5024 MDIO_PMA_REG_STATUS, &val2);
5025 bnx2x_cl45_read(bp, params->port,
5026 ext_phy_type,
5027 ext_phy_addr,
5028 MDIO_PMA_DEVAD,
5029 MDIO_PMA_REG_STATUS, &val1);
5030 DP(NETIF_MSG_LINK, "KR PMA status 0x%x->0x%x,"
5031 "an_link_status=0x%x\n",
5032 val2, val1, an1000_status);
5033
Eilon Greenstein356e2382009-02-12 08:38:32 +00005034 ext_phy_link_up = (((val1 & 4) == 4) ||
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005035 (an1000_status & (1<<1)));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005036 if (ext_phy_link_up &&
5037 bnx2x_8073_is_snr_needed(params)) {
5038 /* The SNR will improve about 2dbby
5039 changing the BW and FEE main tap.*/
5040
5041 /* The 1st write to change FFE main
5042 tap is set before restart AN */
5043 /* Change PLL Bandwidth in EDC
5044 register */
5045 bnx2x_cl45_write(bp, port, ext_phy_type,
5046 ext_phy_addr,
5047 MDIO_PMA_DEVAD,
5048 MDIO_PMA_REG_PLL_BANDWIDTH,
5049 0x26BC);
5050
5051 /* Change CDR Bandwidth in EDC
5052 register */
5053 bnx2x_cl45_write(bp, port, ext_phy_type,
5054 ext_phy_addr,
5055 MDIO_PMA_DEVAD,
5056 MDIO_PMA_REG_CDR_BANDWIDTH,
5057 0x0333);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005058 }
5059 bnx2x_cl45_read(bp, params->port,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00005060 ext_phy_type,
5061 ext_phy_addr,
5062 MDIO_PMA_DEVAD,
5063 MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
5064 &link_status);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005065
5066 /* Bits 0..2 --> speed detected,
5067 bits 13..15--> link is down */
5068 if ((link_status & (1<<2)) &&
5069 (!(link_status & (1<<15)))) {
5070 ext_phy_link_up = 1;
5071 vars->line_speed = SPEED_10000;
5072 DP(NETIF_MSG_LINK,
5073 "port %x: External link"
5074 " up in 10G\n", params->port);
5075 } else if ((link_status & (1<<1)) &&
5076 (!(link_status & (1<<14)))) {
5077 ext_phy_link_up = 1;
5078 vars->line_speed = SPEED_2500;
5079 DP(NETIF_MSG_LINK,
5080 "port %x: External link"
5081 " up in 2.5G\n", params->port);
5082 } else if ((link_status & (1<<0)) &&
5083 (!(link_status & (1<<13)))) {
5084 ext_phy_link_up = 1;
5085 vars->line_speed = SPEED_1000;
5086 DP(NETIF_MSG_LINK,
5087 "port %x: External link"
5088 " up in 1G\n", params->port);
5089 } else {
5090 ext_phy_link_up = 0;
5091 DP(NETIF_MSG_LINK,
5092 "port %x: External link"
5093 " is down\n", params->port);
5094 }
5095 } else {
5096 /* See if 1G link is up for the 8072 */
5097 bnx2x_cl45_read(bp, params->port,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00005098 ext_phy_type,
5099 ext_phy_addr,
5100 MDIO_AN_DEVAD,
5101 MDIO_AN_REG_LINK_STATUS,
5102 &an1000_status);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005103 bnx2x_cl45_read(bp, params->port,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00005104 ext_phy_type,
5105 ext_phy_addr,
5106 MDIO_AN_DEVAD,
5107 MDIO_AN_REG_LINK_STATUS,
5108 &an1000_status);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005109 if (an1000_status & (1<<1)) {
5110 ext_phy_link_up = 1;
5111 vars->line_speed = SPEED_1000;
5112 DP(NETIF_MSG_LINK,
5113 "port %x: External link"
5114 " up in 1G\n", params->port);
5115 } else if (ext_phy_link_up) {
5116 ext_phy_link_up = 1;
5117 vars->line_speed = SPEED_10000;
5118 DP(NETIF_MSG_LINK,
5119 "port %x: External link"
5120 " up in 10G\n", params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005121 }
5122 }
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005123
5124
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005125 break;
5126 }
5127 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
5128 bnx2x_cl45_read(bp, params->port, ext_phy_type,
5129 ext_phy_addr,
5130 MDIO_PMA_DEVAD,
5131 MDIO_PMA_REG_LASI_STATUS, &val2);
5132 bnx2x_cl45_read(bp, params->port, ext_phy_type,
5133 ext_phy_addr,
5134 MDIO_PMA_DEVAD,
5135 MDIO_PMA_REG_LASI_STATUS, &val1);
5136 DP(NETIF_MSG_LINK,
5137 "10G-base-T LASI status 0x%x->0x%x\n",
5138 val2, val1);
5139 bnx2x_cl45_read(bp, params->port, ext_phy_type,
5140 ext_phy_addr,
5141 MDIO_PMA_DEVAD,
5142 MDIO_PMA_REG_STATUS, &val2);
5143 bnx2x_cl45_read(bp, params->port, ext_phy_type,
5144 ext_phy_addr,
5145 MDIO_PMA_DEVAD,
5146 MDIO_PMA_REG_STATUS, &val1);
5147 DP(NETIF_MSG_LINK,
5148 "10G-base-T PMA status 0x%x->0x%x\n",
5149 val2, val1);
5150 ext_phy_link_up = ((val1 & 4) == 4);
5151 /* if link is up
5152 * print the AN outcome of the SFX7101 PHY
5153 */
5154 if (ext_phy_link_up) {
5155 bnx2x_cl45_read(bp, params->port,
5156 ext_phy_type,
5157 ext_phy_addr,
5158 MDIO_AN_DEVAD,
5159 MDIO_AN_REG_MASTER_STATUS,
5160 &val2);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005161 vars->line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005162 DP(NETIF_MSG_LINK,
5163 "SFX7101 AN status 0x%x->Master=%x\n",
5164 val2,
5165 (val2 & (1<<14)));
5166 }
5167 break;
Eilon Greenstein28577182009-02-12 08:37:00 +00005168 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02005169 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
Eilon Greenstein2f904462009-08-12 08:22:16 +00005170 /* Check 10G-BaseT link status */
5171 /* Check PMD signal ok */
5172 bnx2x_cl45_read(bp, params->port, ext_phy_type,
5173 ext_phy_addr,
5174 MDIO_AN_DEVAD,
5175 0xFFFA,
5176 &val1);
5177 bnx2x_cl45_read(bp, params->port, ext_phy_type,
Eilon Greenstein28577182009-02-12 08:37:00 +00005178 ext_phy_addr,
5179 MDIO_PMA_DEVAD,
Eilon Greenstein2f904462009-08-12 08:22:16 +00005180 MDIO_PMA_REG_8481_PMD_SIGNAL,
5181 &val2);
5182 DP(NETIF_MSG_LINK, "PMD_SIGNAL 1.a811 = 0x%x\n", val2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005183
Eilon Greenstein2f904462009-08-12 08:22:16 +00005184 /* Check link 10G */
5185 if (val2 & (1<<11)) {
Eilon Greenstein28577182009-02-12 08:37:00 +00005186 vars->line_speed = SPEED_10000;
5187 ext_phy_link_up = 1;
Eilon Greenstein2f904462009-08-12 08:22:16 +00005188 bnx2x_8481_set_10G_led_mode(params,
5189 ext_phy_type,
5190 ext_phy_addr);
5191 } else { /* Check Legacy speed link */
5192 u16 legacy_status, legacy_speed;
Eilon Greenstein28577182009-02-12 08:37:00 +00005193
Eilon Greenstein2f904462009-08-12 08:22:16 +00005194 /* Enable expansion register 0x42
5195 (Operation mode status) */
5196 bnx2x_cl45_write(bp, params->port,
5197 ext_phy_type,
5198 ext_phy_addr,
5199 MDIO_AN_DEVAD,
5200 MDIO_AN_REG_8481_EXPANSION_REG_ACCESS,
5201 0xf42);
Eilon Greenstein28577182009-02-12 08:37:00 +00005202
Eilon Greenstein2f904462009-08-12 08:22:16 +00005203 /* Get legacy speed operation status */
5204 bnx2x_cl45_read(bp, params->port,
5205 ext_phy_type,
5206 ext_phy_addr,
5207 MDIO_AN_DEVAD,
5208 MDIO_AN_REG_8481_EXPANSION_REG_RD_RW,
5209 &legacy_status);
5210
5211 DP(NETIF_MSG_LINK, "Legacy speed status"
5212 " = 0x%x\n", legacy_status);
5213 ext_phy_link_up = ((legacy_status & (1<<11))
5214 == (1<<11));
5215 if (ext_phy_link_up) {
5216 legacy_speed = (legacy_status & (3<<9));
5217 if (legacy_speed == (0<<9))
5218 vars->line_speed = SPEED_10;
5219 else if (legacy_speed == (1<<9))
5220 vars->line_speed =
5221 SPEED_100;
5222 else if (legacy_speed == (2<<9))
5223 vars->line_speed =
5224 SPEED_1000;
5225 else /* Should not happen */
5226 vars->line_speed = 0;
5227
5228 if (legacy_status & (1<<8))
5229 vars->duplex = DUPLEX_FULL;
5230 else
5231 vars->duplex = DUPLEX_HALF;
5232
5233 DP(NETIF_MSG_LINK, "Link is up "
5234 "in %dMbps, is_duplex_full"
5235 "= %d\n",
5236 vars->line_speed,
5237 (vars->duplex == DUPLEX_FULL));
5238 bnx2x_8481_set_legacy_led_mode(params,
5239 ext_phy_type,
5240 ext_phy_addr);
Eilon Greenstein28577182009-02-12 08:37:00 +00005241 }
5242 }
Eilon Greenstein28577182009-02-12 08:37:00 +00005243 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005244 default:
5245 DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
5246 params->ext_phy_config);
5247 ext_phy_link_up = 0;
5248 break;
5249 }
Eilon Greenstein57937202009-08-12 08:23:53 +00005250 /* Set SGMII mode for external phy */
5251 if (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) {
5252 if (vars->line_speed < SPEED_1000)
5253 vars->phy_flags |= PHY_SGMII_FLAG;
5254 else
5255 vars->phy_flags &= ~PHY_SGMII_FLAG;
5256 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005257
5258 } else { /* SerDes */
5259 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
5260 switch (ext_phy_type) {
5261 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
5262 DP(NETIF_MSG_LINK, "SerDes Direct\n");
5263 ext_phy_link_up = 1;
5264 break;
5265
5266 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
5267 DP(NETIF_MSG_LINK, "SerDes 5482\n");
5268 ext_phy_link_up = 1;
5269 break;
5270
5271 default:
5272 DP(NETIF_MSG_LINK,
5273 "BAD SerDes ext_phy_config 0x%x\n",
5274 params->ext_phy_config);
5275 ext_phy_link_up = 0;
5276 break;
5277 }
5278 }
5279
5280 return ext_phy_link_up;
5281}
5282
5283static void bnx2x_link_int_enable(struct link_params *params)
5284{
5285 u8 port = params->port;
5286 u32 ext_phy_type;
5287 u32 mask;
5288 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005289
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005290 /* setting the status to report on link up
5291 for either XGXS or SerDes */
5292
5293 if (params->switch_cfg == SWITCH_CFG_10G) {
5294 mask = (NIG_MASK_XGXS0_LINK10G |
5295 NIG_MASK_XGXS0_LINK_STATUS);
5296 DP(NETIF_MSG_LINK, "enabled XGXS interrupt\n");
5297 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
5298 if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
5299 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
5300 (ext_phy_type !=
5301 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)) {
5302 mask |= NIG_MASK_MI_INT;
5303 DP(NETIF_MSG_LINK, "enabled external phy int\n");
5304 }
5305
5306 } else { /* SerDes */
5307 mask = NIG_MASK_SERDES0_LINK_STATUS;
5308 DP(NETIF_MSG_LINK, "enabled SerDes interrupt\n");
5309 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
5310 if ((ext_phy_type !=
5311 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT) &&
5312 (ext_phy_type !=
5313 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_NOT_CONN)) {
5314 mask |= NIG_MASK_MI_INT;
5315 DP(NETIF_MSG_LINK, "enabled external phy int\n");
5316 }
5317 }
5318 bnx2x_bits_en(bp,
5319 NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
5320 mask);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005321
5322 DP(NETIF_MSG_LINK, "port %x, is_xgxs %x, int_status 0x%x\n", port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005323 (params->switch_cfg == SWITCH_CFG_10G),
5324 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005325 DP(NETIF_MSG_LINK, " int_mask 0x%x, MI_INT %x, SERDES_LINK %x\n",
5326 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
5327 REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
5328 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS+port*0x3c));
5329 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
5330 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
5331 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
5332}
5333
Eilon Greenstein2f904462009-08-12 08:22:16 +00005334static void bnx2x_8481_rearm_latch_signal(struct bnx2x *bp, u8 port,
5335 u8 is_mi_int)
5336{
5337 u32 latch_status = 0, is_mi_int_status;
5338 /* Disable the MI INT ( external phy int )
5339 * by writing 1 to the status register. Link down indication
5340 * is high-active-signal, so in this case we need to write the
5341 * status to clear the XOR
5342 */
5343 /* Read Latched signals */
5344 latch_status = REG_RD(bp,
5345 NIG_REG_LATCH_STATUS_0 + port*8);
5346 is_mi_int_status = REG_RD(bp,
5347 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4);
5348 DP(NETIF_MSG_LINK, "original_signal = 0x%x, nig_status = 0x%x,"
5349 "latch_status = 0x%x\n",
5350 is_mi_int, is_mi_int_status, latch_status);
5351 /* Handle only those with latched-signal=up.*/
5352 if (latch_status & 1) {
5353 /* For all latched-signal=up,Write original_signal to status */
5354 if (is_mi_int)
5355 bnx2x_bits_en(bp,
5356 NIG_REG_STATUS_INTERRUPT_PORT0
5357 + port*4,
5358 NIG_STATUS_EMAC0_MI_INT);
5359 else
5360 bnx2x_bits_dis(bp,
5361 NIG_REG_STATUS_INTERRUPT_PORT0
5362 + port*4,
5363 NIG_STATUS_EMAC0_MI_INT);
5364 /* For all latched-signal=up : Re-Arm Latch signals */
5365 REG_WR(bp, NIG_REG_LATCH_STATUS_0 + port*8,
5366 (latch_status & 0xfffe) | (latch_status & 1));
5367 }
5368}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005369/*
5370 * link management
5371 */
5372static void bnx2x_link_int_ack(struct link_params *params,
Eilon Greenstein2f904462009-08-12 08:22:16 +00005373 struct link_vars *vars, u8 is_10g,
5374 u8 is_mi_int)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005375{
5376 struct bnx2x *bp = params->bp;
5377 u8 port = params->port;
5378
5379 /* first reset all status
5380 * we assume only one line will be change at a time */
5381 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
5382 (NIG_STATUS_XGXS0_LINK10G |
5383 NIG_STATUS_XGXS0_LINK_STATUS |
5384 NIG_STATUS_SERDES0_LINK_STATUS));
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02005385 if ((XGXS_EXT_PHY_TYPE(params->ext_phy_config)
5386 == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481) ||
5387 (XGXS_EXT_PHY_TYPE(params->ext_phy_config)
5388 == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823)) {
Eilon Greenstein2f904462009-08-12 08:22:16 +00005389 bnx2x_8481_rearm_latch_signal(bp, port, is_mi_int);
5390 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005391 if (vars->phy_link_up) {
5392 if (is_10g) {
5393 /* Disable the 10G link interrupt
5394 * by writing 1 to the status register
5395 */
5396 DP(NETIF_MSG_LINK, "10G XGXS phy link up\n");
5397 bnx2x_bits_en(bp,
5398 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
5399 NIG_STATUS_XGXS0_LINK10G);
5400
5401 } else if (params->switch_cfg == SWITCH_CFG_10G) {
5402 /* Disable the link interrupt
5403 * by writing 1 to the relevant lane
5404 * in the status register
5405 */
5406 u32 ser_lane = ((params->lane_config &
5407 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
5408 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
5409
Eilon Greenstein2f904462009-08-12 08:22:16 +00005410 DP(NETIF_MSG_LINK, "%d speed XGXS phy link up\n",
5411 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005412 bnx2x_bits_en(bp,
5413 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
5414 ((1 << ser_lane) <<
5415 NIG_STATUS_XGXS0_LINK_STATUS_SIZE));
5416
5417 } else { /* SerDes */
5418 DP(NETIF_MSG_LINK, "SerDes phy link up\n");
5419 /* Disable the link interrupt
5420 * by writing 1 to the status register
5421 */
5422 bnx2x_bits_en(bp,
5423 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
5424 NIG_STATUS_SERDES0_LINK_STATUS);
5425 }
5426
5427 } else { /* link_down */
5428 }
5429}
5430
5431static u8 bnx2x_format_ver(u32 num, u8 *str, u16 len)
5432{
5433 u8 *str_ptr = str;
5434 u32 mask = 0xf0000000;
5435 u8 shift = 8*4;
5436 u8 digit;
5437 if (len < 10) {
Frederik Schwarzer025dfda2008-10-16 19:02:37 +02005438 /* Need more than 10chars for this format */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005439 *str_ptr = '\0';
5440 return -EINVAL;
5441 }
5442 while (shift > 0) {
5443
5444 shift -= 4;
5445 digit = ((num & mask) >> shift);
5446 if (digit < 0xa)
5447 *str_ptr = digit + '0';
5448 else
5449 *str_ptr = digit - 0xa + 'a';
5450 str_ptr++;
5451 mask = mask >> 4;
5452 if (shift == 4*4) {
5453 *str_ptr = ':';
5454 str_ptr++;
5455 }
5456 }
5457 *str_ptr = '\0';
5458 return 0;
5459}
5460
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005461u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
5462 u8 *version, u16 len)
5463{
Julia Lawall0376d5b2009-07-19 05:26:35 +00005464 struct bnx2x *bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005465 u32 ext_phy_type = 0;
Eilon Greensteina35da8d2009-02-12 08:37:02 +00005466 u32 spirom_ver = 0;
Eilon Greenstein97b41da2009-08-12 08:22:59 +00005467 u8 status;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005468
5469 if (version == NULL || params == NULL)
5470 return -EINVAL;
Julia Lawall0376d5b2009-07-19 05:26:35 +00005471 bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005472
Eilon Greensteina35da8d2009-02-12 08:37:02 +00005473 spirom_ver = REG_RD(bp, params->shmem_base +
5474 offsetof(struct shmem_region,
5475 port_mb[params->port].ext_phy_fw_version));
5476
Eilon Greenstein97b41da2009-08-12 08:22:59 +00005477 status = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005478 /* reset the returned value to zero */
5479 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005480 switch (ext_phy_type) {
5481 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
5482
5483 if (len < 5)
5484 return -EINVAL;
5485
Eilon Greensteina35da8d2009-02-12 08:37:02 +00005486 version[0] = (spirom_ver & 0xFF);
5487 version[1] = (spirom_ver & 0xFF00) >> 8;
5488 version[2] = (spirom_ver & 0xFF0000) >> 16;
5489 version[3] = (spirom_ver & 0xFF000000) >> 24;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005490 version[4] = '\0';
5491
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005492 break;
5493 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
5494 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Eilon Greenstein4d295db2009-07-21 05:47:47 +00005495 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005496 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
Eilon Greenstein589abe32009-02-12 08:36:55 +00005497 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
Eilon Greensteinb1607af2009-08-12 08:22:54 +00005498 status = bnx2x_format_ver(spirom_ver, version, len);
5499 break;
Eilon Greenstein9223dea2009-03-02 08:00:15 +00005500 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02005501 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
Eilon Greensteinb1607af2009-08-12 08:22:54 +00005502 spirom_ver = ((spirom_ver & 0xF80) >> 7) << 16 |
5503 (spirom_ver & 0x7F);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00005504 status = bnx2x_format_ver(spirom_ver, version, len);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005505 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005506 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
Eilon Greenstein97b41da2009-08-12 08:22:59 +00005507 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
5508 version[0] = '\0';
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005509 break;
5510
5511 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
5512 DP(NETIF_MSG_LINK, "bnx2x_get_ext_phy_fw_version:"
5513 " type is FAILURE!\n");
5514 status = -EINVAL;
5515 break;
5516
5517 default:
5518 break;
5519 }
5520 return status;
5521}
5522
5523static void bnx2x_set_xgxs_loopback(struct link_params *params,
5524 struct link_vars *vars,
5525 u8 is_10g)
5526{
5527 u8 port = params->port;
5528 struct bnx2x *bp = params->bp;
5529
5530 if (is_10g) {
Eilon Greenstein6378c022008-08-13 15:59:25 -07005531 u32 md_devad;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005532
5533 DP(NETIF_MSG_LINK, "XGXS 10G loopback enable\n");
5534
5535 /* change the uni_phy_addr in the nig */
5536 md_devad = REG_RD(bp, (NIG_REG_XGXS0_CTRL_MD_DEVAD +
5537 port*0x18));
5538
5539 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, 0x5);
5540
5541 bnx2x_cl45_write(bp, port, 0,
5542 params->phy_addr,
5543 5,
5544 (MDIO_REG_BANK_AER_BLOCK +
5545 (MDIO_AER_BLOCK_AER_REG & 0xf)),
5546 0x2800);
5547
5548 bnx2x_cl45_write(bp, port, 0,
5549 params->phy_addr,
5550 5,
5551 (MDIO_REG_BANK_CL73_IEEEB0 +
5552 (MDIO_CL73_IEEEB0_CL73_AN_CONTROL & 0xf)),
5553 0x6041);
Eilon Greenstein38582762009-01-14 06:44:16 +00005554 msleep(200);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005555 /* set aer mmd back */
5556 bnx2x_set_aer_mmd(params, vars);
5557
5558 /* and md_devad */
5559 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
5560 md_devad);
5561
5562 } else {
5563 u16 mii_control;
5564
5565 DP(NETIF_MSG_LINK, "XGXS 1G loopback enable\n");
5566
5567 CL45_RD_OVER_CL22(bp, port,
5568 params->phy_addr,
5569 MDIO_REG_BANK_COMBO_IEEE0,
5570 MDIO_COMBO_IEEE0_MII_CONTROL,
5571 &mii_control);
5572
5573 CL45_WR_OVER_CL22(bp, port,
5574 params->phy_addr,
5575 MDIO_REG_BANK_COMBO_IEEE0,
5576 MDIO_COMBO_IEEE0_MII_CONTROL,
5577 (mii_control |
5578 MDIO_COMBO_IEEO_MII_CONTROL_LOOPBACK));
5579 }
5580}
5581
5582
5583static void bnx2x_ext_phy_loopback(struct link_params *params)
5584{
5585 struct bnx2x *bp = params->bp;
5586 u8 ext_phy_addr;
5587 u32 ext_phy_type;
5588
5589 if (params->switch_cfg == SWITCH_CFG_10G) {
5590 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00005591 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005592 /* CL37 Autoneg Enabled */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005593 switch (ext_phy_type) {
5594 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
5595 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN:
5596 DP(NETIF_MSG_LINK,
5597 "ext_phy_loopback: We should not get here\n");
5598 break;
5599 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
5600 DP(NETIF_MSG_LINK, "ext_phy_loopback: 8705\n");
5601 break;
5602 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
5603 DP(NETIF_MSG_LINK, "ext_phy_loopback: 8706\n");
5604 break;
Eilon Greenstein589abe32009-02-12 08:36:55 +00005605 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
5606 DP(NETIF_MSG_LINK, "PMA/PMD ext_phy_loopback: 8726\n");
5607 bnx2x_cl45_write(bp, params->port, ext_phy_type,
5608 ext_phy_addr,
5609 MDIO_PMA_DEVAD,
5610 MDIO_PMA_REG_CTRL,
5611 0x0001);
5612 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005613 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
5614 /* SFX7101_XGXS_TEST1 */
5615 bnx2x_cl45_write(bp, params->port, ext_phy_type,
5616 ext_phy_addr,
5617 MDIO_XS_DEVAD,
5618 MDIO_XS_SFX7101_XGXS_TEST1,
5619 0x100);
5620 DP(NETIF_MSG_LINK,
5621 "ext_phy_loopback: set ext phy loopback\n");
5622 break;
5623 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
5624
5625 break;
5626 } /* switch external PHY type */
5627 } else {
5628 /* serdes */
5629 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
5630 ext_phy_addr = (params->ext_phy_config &
5631 PORT_HW_CFG_SERDES_EXT_PHY_ADDR_MASK)
5632 >> PORT_HW_CFG_SERDES_EXT_PHY_ADDR_SHIFT;
5633 }
5634}
5635
5636
5637/*
5638 *------------------------------------------------------------------------
5639 * bnx2x_override_led_value -
5640 *
5641 * Override the led value of the requsted led
5642 *
5643 *------------------------------------------------------------------------
5644 */
5645u8 bnx2x_override_led_value(struct bnx2x *bp, u8 port,
5646 u32 led_idx, u32 value)
5647{
5648 u32 reg_val;
5649
5650 /* If port 0 then use EMAC0, else use EMAC1*/
5651 u32 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
5652
5653 DP(NETIF_MSG_LINK,
5654 "bnx2x_override_led_value() port %x led_idx %d value %d\n",
5655 port, led_idx, value);
5656
5657 switch (led_idx) {
5658 case 0: /* 10MB led */
5659 /* Read the current value of the LED register in
5660 the EMAC block */
5661 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
5662 /* Set the OVERRIDE bit to 1 */
5663 reg_val |= EMAC_LED_OVERRIDE;
5664 /* If value is 1, set the 10M_OVERRIDE bit,
5665 otherwise reset it.*/
5666 reg_val = (value == 1) ? (reg_val | EMAC_LED_10MB_OVERRIDE) :
5667 (reg_val & ~EMAC_LED_10MB_OVERRIDE);
5668 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
5669 break;
5670 case 1: /*100MB led */
5671 /*Read the current value of the LED register in
5672 the EMAC block */
5673 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
5674 /* Set the OVERRIDE bit to 1 */
5675 reg_val |= EMAC_LED_OVERRIDE;
5676 /* If value is 1, set the 100M_OVERRIDE bit,
5677 otherwise reset it.*/
5678 reg_val = (value == 1) ? (reg_val | EMAC_LED_100MB_OVERRIDE) :
5679 (reg_val & ~EMAC_LED_100MB_OVERRIDE);
5680 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
5681 break;
5682 case 2: /* 1000MB led */
5683 /* Read the current value of the LED register in the
5684 EMAC block */
5685 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
5686 /* Set the OVERRIDE bit to 1 */
5687 reg_val |= EMAC_LED_OVERRIDE;
5688 /* If value is 1, set the 1000M_OVERRIDE bit, otherwise
5689 reset it. */
5690 reg_val = (value == 1) ? (reg_val | EMAC_LED_1000MB_OVERRIDE) :
5691 (reg_val & ~EMAC_LED_1000MB_OVERRIDE);
5692 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
5693 break;
5694 case 3: /* 2500MB led */
5695 /* Read the current value of the LED register in the
5696 EMAC block*/
5697 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
5698 /* Set the OVERRIDE bit to 1 */
5699 reg_val |= EMAC_LED_OVERRIDE;
5700 /* If value is 1, set the 2500M_OVERRIDE bit, otherwise
5701 reset it.*/
5702 reg_val = (value == 1) ? (reg_val | EMAC_LED_2500MB_OVERRIDE) :
5703 (reg_val & ~EMAC_LED_2500MB_OVERRIDE);
5704 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
5705 break;
5706 case 4: /*10G led */
5707 if (port == 0) {
5708 REG_WR(bp, NIG_REG_LED_10G_P0,
5709 value);
5710 } else {
5711 REG_WR(bp, NIG_REG_LED_10G_P1,
5712 value);
5713 }
5714 break;
5715 case 5: /* TRAFFIC led */
5716 /* Find if the traffic control is via BMAC or EMAC */
5717 if (port == 0)
5718 reg_val = REG_RD(bp, NIG_REG_NIG_EMAC0_EN);
5719 else
5720 reg_val = REG_RD(bp, NIG_REG_NIG_EMAC1_EN);
5721
5722 /* Override the traffic led in the EMAC:*/
5723 if (reg_val == 1) {
5724 /* Read the current value of the LED register in
5725 the EMAC block */
5726 reg_val = REG_RD(bp, emac_base +
5727 EMAC_REG_EMAC_LED);
5728 /* Set the TRAFFIC_OVERRIDE bit to 1 */
5729 reg_val |= EMAC_LED_OVERRIDE;
5730 /* If value is 1, set the TRAFFIC bit, otherwise
5731 reset it.*/
5732 reg_val = (value == 1) ? (reg_val | EMAC_LED_TRAFFIC) :
5733 (reg_val & ~EMAC_LED_TRAFFIC);
5734 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
5735 } else { /* Override the traffic led in the BMAC: */
5736 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
5737 + port*4, 1);
5738 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 + port*4,
5739 value);
5740 }
5741 break;
5742 default:
5743 DP(NETIF_MSG_LINK,
5744 "bnx2x_override_led_value() unknown led index %d "
5745 "(should be 0-5)\n", led_idx);
5746 return -EINVAL;
5747 }
5748
5749 return 0;
5750}
5751
5752
Yaniv Rosner7846e472009-11-05 19:18:07 +02005753u8 bnx2x_set_led(struct link_params *params, u8 mode, u32 speed)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005754{
Yaniv Rosner7846e472009-11-05 19:18:07 +02005755 u8 port = params->port;
5756 u16 hw_led_mode = params->hw_led_mode;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005757 u8 rc = 0;
Eilon Greenstein345b5d52008-08-13 15:58:12 -07005758 u32 tmp;
5759 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Yaniv Rosner7846e472009-11-05 19:18:07 +02005760 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
5761 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005762 DP(NETIF_MSG_LINK, "bnx2x_set_led: port %x, mode %d\n", port, mode);
5763 DP(NETIF_MSG_LINK, "speed 0x%x, hw_led_mode 0x%x\n",
5764 speed, hw_led_mode);
5765 switch (mode) {
5766 case LED_MODE_OFF:
5767 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 0);
5768 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
5769 SHARED_HW_CFG_LED_MAC1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07005770
5771 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07005772 EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp | EMAC_LED_OVERRIDE));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005773 break;
5774
5775 case LED_MODE_OPER:
Yaniv Rosner7846e472009-11-05 19:18:07 +02005776 if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) {
5777 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0);
5778 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1);
5779 } else {
5780 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
5781 hw_led_mode);
5782 }
5783
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005784 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 +
5785 port*4, 0);
5786 /* Set blinking rate to ~15.9Hz */
5787 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4,
5788 LED_BLINK_RATE_VAL);
5789 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 +
5790 port*4, 1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07005791 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07005792 EMAC_WR(bp, EMAC_REG_EMAC_LED,
Eilon Greenstein345b5d52008-08-13 15:58:12 -07005793 (tmp & (~EMAC_LED_OVERRIDE)));
5794
Yaniv Rosner7846e472009-11-05 19:18:07 +02005795 if (CHIP_IS_E1(bp) &&
Eilon Greenstein34f80b02008-06-23 20:33:01 -07005796 ((speed == SPEED_2500) ||
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005797 (speed == SPEED_1000) ||
5798 (speed == SPEED_100) ||
5799 (speed == SPEED_10))) {
5800 /* On Everest 1 Ax chip versions for speeds less than
5801 10G LED scheme is different */
5802 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
5803 + port*4, 1);
5804 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 +
5805 port*4, 0);
5806 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_TRAFFIC_P0 +
5807 port*4, 1);
5808 }
5809 break;
5810
5811 default:
5812 rc = -EINVAL;
5813 DP(NETIF_MSG_LINK, "bnx2x_set_led: Invalid led mode %d\n",
5814 mode);
5815 break;
5816 }
5817 return rc;
5818
5819}
5820
5821u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars)
5822{
5823 struct bnx2x *bp = params->bp;
5824 u16 gp_status = 0;
5825
5826 CL45_RD_OVER_CL22(bp, params->port,
5827 params->phy_addr,
5828 MDIO_REG_BANK_GP_STATUS,
5829 MDIO_GP_STATUS_TOP_AN_STATUS1,
5830 &gp_status);
5831 /* link is up only if both local phy and external phy are up */
5832 if ((gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) &&
Eilon Greenstein2f904462009-08-12 08:22:16 +00005833 bnx2x_ext_phy_is_link_up(params, vars, 1))
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005834 return 0;
5835
5836 return -ESRCH;
5837}
5838
5839static u8 bnx2x_link_initialize(struct link_params *params,
5840 struct link_vars *vars)
5841{
5842 struct bnx2x *bp = params->bp;
5843 u8 port = params->port;
5844 u8 rc = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005845 u8 non_ext_phy;
5846 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005847
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005848 /* Activate the external PHY */
5849 bnx2x_ext_phy_reset(params, vars);
5850
5851 bnx2x_set_aer_mmd(params, vars);
5852
5853 if (vars->phy_flags & PHY_XGXS_FLAG)
5854 bnx2x_set_master_ln(params);
5855
5856 rc = bnx2x_reset_unicore(params);
5857 /* reset the SerDes and wait for reset bit return low */
5858 if (rc != 0)
5859 return rc;
5860
5861 bnx2x_set_aer_mmd(params, vars);
5862
5863 /* setting the masterLn_def again after the reset */
5864 if (vars->phy_flags & PHY_XGXS_FLAG) {
5865 bnx2x_set_master_ln(params);
5866 bnx2x_set_swap_lanes(params);
5867 }
5868
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005869 if (vars->phy_flags & PHY_XGXS_FLAG) {
Eilon Greenstein44722d12009-01-14 06:44:21 +00005870 if ((params->req_line_speed &&
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005871 ((params->req_line_speed == SPEED_100) ||
Eilon Greenstein44722d12009-01-14 06:44:21 +00005872 (params->req_line_speed == SPEED_10))) ||
5873 (!params->req_line_speed &&
5874 (params->speed_cap_mask >=
5875 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL) &&
5876 (params->speed_cap_mask <
5877 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
5878 )) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005879 vars->phy_flags |= PHY_SGMII_FLAG;
5880 } else {
5881 vars->phy_flags &= ~PHY_SGMII_FLAG;
5882 }
5883 }
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005884 /* In case of external phy existance, the line speed would be the
5885 line speed linked up by the external phy. In case it is direct only,
5886 then the line_speed during initialization will be equal to the
5887 req_line_speed*/
5888 vars->line_speed = params->req_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005889
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07005890 bnx2x_calc_ieee_aneg_adv(params, &vars->ieee_fc);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005891
5892 /* init ext phy and enable link state int */
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005893 non_ext_phy = ((ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ||
Eilon Greenstein8660d8c2009-03-02 08:01:02 +00005894 (params->loopback_mode == LOOPBACK_XGXS_10));
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005895
5896 if (non_ext_phy ||
Eilon Greenstein589abe32009-02-12 08:36:55 +00005897 (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) ||
Yaniv Rosnerb5bbf002009-11-05 19:18:21 +02005898 (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706) ||
Eilon Greenstein28577182009-02-12 08:37:00 +00005899 (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) ||
Eilon Greenstein8660d8c2009-03-02 08:01:02 +00005900 (params->loopback_mode == LOOPBACK_EXT_PHY)) {
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005901 if (params->req_line_speed == SPEED_AUTO_NEG)
5902 bnx2x_set_parallel_detection(params, vars->phy_flags);
Eilon Greenstein239d6862009-08-12 08:23:04 +00005903 bnx2x_init_internal_phy(params, vars, non_ext_phy);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005904 }
5905
5906 if (!non_ext_phy)
5907 rc |= bnx2x_ext_phy_init(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005908
5909 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005910 (NIG_STATUS_XGXS0_LINK10G |
5911 NIG_STATUS_XGXS0_LINK_STATUS |
5912 NIG_STATUS_SERDES0_LINK_STATUS));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005913
5914 return rc;
5915
5916}
5917
5918
5919u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
5920{
5921 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005922 u32 val;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005923
5924 DP(NETIF_MSG_LINK, "Phy Initialization started\n");
5925 DP(NETIF_MSG_LINK, "req_speed %d, req_flowctrl %d\n",
5926 params->req_line_speed, params->req_flow_ctrl);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005927 vars->link_status = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005928 vars->phy_link_up = 0;
5929 vars->link_up = 0;
5930 vars->line_speed = 0;
5931 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08005932 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005933 vars->mac_type = MAC_TYPE_NONE;
5934
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005935 if (params->switch_cfg == SWITCH_CFG_1G)
5936 vars->phy_flags = PHY_SERDES_FLAG;
5937 else
5938 vars->phy_flags = PHY_XGXS_FLAG;
5939
5940 /* disable attentions */
5941 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4,
5942 (NIG_MASK_XGXS0_LINK_STATUS |
5943 NIG_MASK_XGXS0_LINK10G |
5944 NIG_MASK_SERDES0_LINK_STATUS |
5945 NIG_MASK_MI_INT));
5946
5947 bnx2x_emac_init(params, vars);
5948
5949 if (CHIP_REV_IS_FPGA(bp)) {
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005950
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005951 vars->link_up = 1;
5952 vars->line_speed = SPEED_10000;
5953 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08005954 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005955 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
Eilon Greenstein34f80b02008-06-23 20:33:01 -07005956 /* enable on E1.5 FPGA */
5957 if (CHIP_IS_E1H(bp)) {
5958 vars->flow_ctrl |=
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005959 (BNX2X_FLOW_CTRL_TX |
5960 BNX2X_FLOW_CTRL_RX);
Eilon Greenstein34f80b02008-06-23 20:33:01 -07005961 vars->link_status |=
5962 (LINK_STATUS_TX_FLOW_CONTROL_ENABLED |
5963 LINK_STATUS_RX_FLOW_CONTROL_ENABLED);
5964 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005965
5966 bnx2x_emac_enable(params, vars, 0);
5967 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
5968 /* disable drain */
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005969 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005970
5971 /* update shared memory */
5972 bnx2x_update_mng(params, vars->link_status);
5973
5974 return 0;
5975
5976 } else
5977 if (CHIP_REV_IS_EMUL(bp)) {
5978
5979 vars->link_up = 1;
5980 vars->line_speed = SPEED_10000;
5981 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08005982 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005983 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
5984
5985 bnx2x_bmac_enable(params, vars, 0);
5986
5987 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
5988 /* Disable drain */
5989 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
5990 + params->port*4, 0);
5991
5992 /* update shared memory */
5993 bnx2x_update_mng(params, vars->link_status);
5994
5995 return 0;
5996
5997 } else
5998 if (params->loopback_mode == LOOPBACK_BMAC) {
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005999
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006000 vars->link_up = 1;
6001 vars->line_speed = SPEED_10000;
6002 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08006003 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006004 vars->mac_type = MAC_TYPE_BMAC;
6005
6006 vars->phy_flags = PHY_XGXS_FLAG;
6007
6008 bnx2x_phy_deassert(params, vars->phy_flags);
6009 /* set bmac loopback */
6010 bnx2x_bmac_enable(params, vars, 1);
6011
6012 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
6013 params->port*4, 0);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00006014
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006015 } else if (params->loopback_mode == LOOPBACK_EMAC) {
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00006016
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006017 vars->link_up = 1;
6018 vars->line_speed = SPEED_1000;
6019 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08006020 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006021 vars->mac_type = MAC_TYPE_EMAC;
6022
6023 vars->phy_flags = PHY_XGXS_FLAG;
6024
6025 bnx2x_phy_deassert(params, vars->phy_flags);
6026 /* set bmac loopback */
6027 bnx2x_emac_enable(params, vars, 1);
6028 bnx2x_emac_program(params, vars->line_speed,
6029 vars->duplex);
6030 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
6031 params->port*4, 0);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00006032
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006033 } else if ((params->loopback_mode == LOOPBACK_XGXS_10) ||
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00006034 (params->loopback_mode == LOOPBACK_EXT_PHY)) {
6035
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006036 vars->link_up = 1;
6037 vars->line_speed = SPEED_10000;
6038 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08006039 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006040
6041 vars->phy_flags = PHY_XGXS_FLAG;
6042
6043 val = REG_RD(bp,
6044 NIG_REG_XGXS0_CTRL_PHY_ADDR+
6045 params->port*0x18);
6046 params->phy_addr = (u8)val;
6047
6048 bnx2x_phy_deassert(params, vars->phy_flags);
6049 bnx2x_link_initialize(params, vars);
6050
6051 vars->mac_type = MAC_TYPE_BMAC;
6052
6053 bnx2x_bmac_enable(params, vars, 0);
6054
6055 if (params->loopback_mode == LOOPBACK_XGXS_10) {
6056 /* set 10G XGXS loopback */
6057 bnx2x_set_xgxs_loopback(params, vars, 1);
6058 } else {
6059 /* set external phy loopback */
6060 bnx2x_ext_phy_loopback(params);
6061 }
6062 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
6063 params->port*4, 0);
Eilon Greensteinba71d312009-07-21 05:47:49 +00006064
Yaniv Rosner7846e472009-11-05 19:18:07 +02006065 bnx2x_set_led(params, LED_MODE_OPER, vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006066 } else
6067 /* No loopback */
6068 {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006069 bnx2x_phy_deassert(params, vars->phy_flags);
6070 switch (params->switch_cfg) {
6071 case SWITCH_CFG_1G:
6072 vars->phy_flags |= PHY_SERDES_FLAG;
6073 if ((params->ext_phy_config &
6074 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_MASK) ==
6075 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482) {
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00006076 vars->phy_flags |= PHY_SGMII_FLAG;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006077 }
6078
6079 val = REG_RD(bp,
6080 NIG_REG_SERDES0_CTRL_PHY_ADDR+
6081 params->port*0x10);
6082
6083 params->phy_addr = (u8)val;
6084
6085 break;
6086 case SWITCH_CFG_10G:
6087 vars->phy_flags |= PHY_XGXS_FLAG;
6088 val = REG_RD(bp,
6089 NIG_REG_XGXS0_CTRL_PHY_ADDR+
6090 params->port*0x18);
6091 params->phy_addr = (u8)val;
6092
6093 break;
6094 default:
6095 DP(NETIF_MSG_LINK, "Invalid switch_cfg\n");
6096 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006097 }
Eilon Greensteinf5372252009-02-12 08:38:30 +00006098 DP(NETIF_MSG_LINK, "Phy address = 0x%x\n", params->phy_addr);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006099
6100 bnx2x_link_initialize(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006101 msleep(30);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006102 bnx2x_link_int_enable(params);
6103 }
6104 return 0;
6105}
6106
Eilon Greenstein589abe32009-02-12 08:36:55 +00006107static void bnx2x_8726_reset_phy(struct bnx2x *bp, u8 port, u8 ext_phy_addr)
6108{
6109 DP(NETIF_MSG_LINK, "bnx2x_8726_reset_phy port %d\n", port);
6110
6111 /* Set serial boot control for external load */
6112 bnx2x_cl45_write(bp, port,
6113 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726, ext_phy_addr,
6114 MDIO_PMA_DEVAD,
6115 MDIO_PMA_REG_GEN_CTRL, 0x0001);
Eilon Greenstein589abe32009-02-12 08:36:55 +00006116}
6117
6118u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
6119 u8 reset_ext_phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006120{
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006121 struct bnx2x *bp = params->bp;
6122 u32 ext_phy_config = params->ext_phy_config;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006123 u8 port = params->port;
6124 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006125 u32 val = REG_RD(bp, params->shmem_base +
6126 offsetof(struct shmem_region, dev_info.
6127 port_feature_config[params->port].
6128 config));
Yaniv Rosnerd5cb9e92009-11-05 19:18:10 +02006129 DP(NETIF_MSG_LINK, "Resetting the link of port %d\n", port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006130 /* disable attentions */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006131 vars->link_status = 0;
6132 bnx2x_update_mng(params, vars->link_status);
6133 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
6134 (NIG_MASK_XGXS0_LINK_STATUS |
6135 NIG_MASK_XGXS0_LINK10G |
6136 NIG_MASK_SERDES0_LINK_STATUS |
6137 NIG_MASK_MI_INT));
6138
6139 /* activate nig drain */
6140 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
6141
6142 /* disable nig egress interface */
6143 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
6144 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
6145
6146 /* Stop BigMac rx */
6147 bnx2x_bmac_rx_disable(bp, port);
6148
6149 /* disable emac */
6150 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
6151
6152 msleep(10);
6153 /* The PHY reset is controled by GPIO 1
6154 * Hold it as vars low
6155 */
6156 /* clear link led */
Yaniv Rosner7846e472009-11-05 19:18:07 +02006157 bnx2x_set_led(params, LED_MODE_OFF, 0);
Eilon Greenstein589abe32009-02-12 08:36:55 +00006158 if (reset_ext_phy) {
6159 switch (ext_phy_type) {
6160 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
6161 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
6162 break;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006163
6164 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
6165 {
6166
6167 /* Disable Transmitter */
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00006168 u8 ext_phy_addr =
6169 XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006170 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
6171 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
6172 bnx2x_sfp_set_transmitter(bp, port,
6173 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
6174 ext_phy_addr, 0);
6175 break;
6176 }
Eilon Greenstein589abe32009-02-12 08:36:55 +00006177 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
6178 DP(NETIF_MSG_LINK, "Setting 8073 port %d into "
6179 "low power mode\n",
6180 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006181 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07006182 MISC_REGISTERS_GPIO_OUTPUT_LOW,
6183 port);
Eilon Greenstein589abe32009-02-12 08:36:55 +00006184 break;
6185 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
6186 {
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00006187 u8 ext_phy_addr =
6188 XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Eilon Greenstein589abe32009-02-12 08:36:55 +00006189 /* Set soft reset */
6190 bnx2x_8726_reset_phy(bp, params->port, ext_phy_addr);
6191 break;
6192 }
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02006193 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
6194 {
6195 u8 ext_phy_addr =
6196 XGXS_EXT_PHY_ADDR(params->ext_phy_config);
6197 bnx2x_cl45_write(bp, port,
6198 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
6199 ext_phy_addr,
6200 MDIO_AN_DEVAD,
6201 MDIO_AN_REG_CTRL, 0x0000);
6202 bnx2x_cl45_write(bp, port,
6203 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
6204 ext_phy_addr,
6205 MDIO_PMA_DEVAD,
6206 MDIO_PMA_REG_CTRL, 1);
6207 break;
6208 }
Eilon Greenstein589abe32009-02-12 08:36:55 +00006209 default:
6210 /* HW reset */
6211 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
6212 MISC_REGISTERS_GPIO_OUTPUT_LOW,
6213 port);
6214 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
6215 MISC_REGISTERS_GPIO_OUTPUT_LOW,
6216 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006217 DP(NETIF_MSG_LINK, "reset external PHY\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006218 }
6219 }
6220 /* reset the SerDes/XGXS */
6221 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
6222 (0x1ff << (port*16)));
6223
6224 /* reset BigMac */
6225 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
6226 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
6227
6228 /* disable nig ingress interface */
6229 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0);
6230 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0);
6231 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
6232 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
6233 vars->link_up = 0;
6234 return 0;
6235}
6236
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006237static u8 bnx2x_update_link_down(struct link_params *params,
6238 struct link_vars *vars)
6239{
6240 struct bnx2x *bp = params->bp;
6241 u8 port = params->port;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00006242
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006243 DP(NETIF_MSG_LINK, "Port %x: Link is down\n", port);
Yaniv Rosner7846e472009-11-05 19:18:07 +02006244 bnx2x_set_led(params, LED_MODE_OFF, 0);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006245
6246 /* indicate no mac active */
6247 vars->mac_type = MAC_TYPE_NONE;
6248
6249 /* update shared memory */
6250 vars->link_status = 0;
6251 vars->line_speed = 0;
6252 bnx2x_update_mng(params, vars->link_status);
6253
6254 /* activate nig drain */
6255 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
6256
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00006257 /* disable emac */
6258 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
6259
6260 msleep(10);
6261
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006262 /* reset BigMac */
6263 bnx2x_bmac_rx_disable(bp, params->port);
6264 REG_WR(bp, GRCBASE_MISC +
6265 MISC_REGISTERS_RESET_REG_2_CLEAR,
6266 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
6267 return 0;
6268}
6269
6270static u8 bnx2x_update_link_up(struct link_params *params,
6271 struct link_vars *vars,
6272 u8 link_10g, u32 gp_status)
6273{
6274 struct bnx2x *bp = params->bp;
6275 u8 port = params->port;
6276 u8 rc = 0;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00006277
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006278 vars->link_status |= LINK_STATUS_LINK_UP;
6279 if (link_10g) {
6280 bnx2x_bmac_enable(params, vars, 0);
Yaniv Rosner7846e472009-11-05 19:18:07 +02006281 bnx2x_set_led(params, LED_MODE_OPER, SPEED_10000);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006282 } else {
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006283 rc = bnx2x_emac_program(params, vars->line_speed,
6284 vars->duplex);
6285
Yaniv Rosner0c786f02009-11-05 19:18:32 +02006286 bnx2x_emac_enable(params, vars, 0);
6287
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006288 /* AN complete? */
6289 if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) {
6290 if (!(vars->phy_flags &
6291 PHY_SGMII_FLAG))
Eilon Greensteined8680a2009-02-12 08:37:12 +00006292 bnx2x_set_gmii_tx_driver(params);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006293 }
6294 }
6295
6296 /* PBF - link up */
6297 rc |= bnx2x_pbf_update(params, vars->flow_ctrl,
6298 vars->line_speed);
6299
6300 /* disable drain */
6301 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 0);
6302
6303 /* update shared memory */
6304 bnx2x_update_mng(params, vars->link_status);
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00006305 msleep(20);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006306 return rc;
6307}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006308/* This function should called upon link interrupt */
6309/* In case vars->link_up, driver needs to
6310 1. Update the pbf
6311 2. Disable drain
6312 3. Update the shared memory
6313 4. Indicate link up
6314 5. Set LEDs
6315 Otherwise,
6316 1. Update shared memory
6317 2. Reset BigMac
6318 3. Report link down
6319 4. Unset LEDs
6320*/
6321u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars)
6322{
6323 struct bnx2x *bp = params->bp;
6324 u8 port = params->port;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006325 u16 gp_status;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006326 u8 link_10g;
6327 u8 ext_phy_link_up, rc = 0;
6328 u32 ext_phy_type;
Eilon Greenstein2f904462009-08-12 08:22:16 +00006329 u8 is_mi_int = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006330
6331 DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n",
Eilon Greenstein2f904462009-08-12 08:22:16 +00006332 port, (vars->phy_flags & PHY_XGXS_FLAG),
6333 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006334
Eilon Greenstein2f904462009-08-12 08:22:16 +00006335 is_mi_int = (u8)(REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT +
6336 port*0x18) > 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006337 DP(NETIF_MSG_LINK, "int_mask 0x%x MI_INT %x, SERDES_LINK %x\n",
Eilon Greenstein2f904462009-08-12 08:22:16 +00006338 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
6339 is_mi_int,
6340 REG_RD(bp,
6341 NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006342
6343 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
6344 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
6345 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
6346
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00006347 /* disable emac */
6348 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
6349
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006350 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006351
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006352 /* Check external link change only for non-direct */
Eilon Greenstein2f904462009-08-12 08:22:16 +00006353 ext_phy_link_up = bnx2x_ext_phy_is_link_up(params, vars, is_mi_int);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006354
6355 /* Read gp_status */
6356 CL45_RD_OVER_CL22(bp, port, params->phy_addr,
6357 MDIO_REG_BANK_GP_STATUS,
6358 MDIO_GP_STATUS_TOP_AN_STATUS1,
6359 &gp_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006360
Eilon Greenstein2f904462009-08-12 08:22:16 +00006361 rc = bnx2x_link_settings_status(params, vars, gp_status,
6362 ext_phy_link_up);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006363 if (rc != 0)
6364 return rc;
6365
6366 /* anything 10 and over uses the bmac */
6367 link_10g = ((vars->line_speed == SPEED_10000) ||
6368 (vars->line_speed == SPEED_12000) ||
6369 (vars->line_speed == SPEED_12500) ||
6370 (vars->line_speed == SPEED_13000) ||
6371 (vars->line_speed == SPEED_15000) ||
6372 (vars->line_speed == SPEED_16000));
6373
Eilon Greenstein2f904462009-08-12 08:22:16 +00006374 bnx2x_link_int_ack(params, vars, link_10g, is_mi_int);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006375
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006376 /* In case external phy link is up, and internal link is down
6377 ( not initialized yet probably after link initialization, it needs
6378 to be initialized.
6379 Note that after link down-up as result of cable plug,
6380 the xgxs link would probably become up again without the need to
6381 initialize it*/
6382
6383 if ((ext_phy_type != PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT) &&
6384 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) &&
Yaniv Rosnerb5bbf002009-11-05 19:18:21 +02006385 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706) &&
Eilon Greenstein589abe32009-02-12 08:36:55 +00006386 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) &&
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006387 (ext_phy_link_up && !vars->phy_link_up))
Eilon Greenstein239d6862009-08-12 08:23:04 +00006388 bnx2x_init_internal_phy(params, vars, 0);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006389
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006390 /* link is up only if both local phy and external phy are up */
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006391 vars->link_up = (ext_phy_link_up && vars->phy_link_up);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006392
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006393 if (vars->link_up)
6394 rc = bnx2x_update_link_up(params, vars, link_10g, gp_status);
6395 else
6396 rc = bnx2x_update_link_down(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006397
6398 return rc;
6399}
6400
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006401static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base)
6402{
6403 u8 ext_phy_addr[PORT_MAX];
6404 u16 val;
6405 s8 port;
6406
6407 /* PART1 - Reset both phys */
6408 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
6409 /* Extract the ext phy address for the port */
6410 u32 ext_phy_config = REG_RD(bp, shmem_base +
6411 offsetof(struct shmem_region,
6412 dev_info.port_hw_config[port].external_phy_config));
6413
6414 /* disable attentions */
6415 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
6416 (NIG_MASK_XGXS0_LINK_STATUS |
6417 NIG_MASK_XGXS0_LINK10G |
6418 NIG_MASK_SERDES0_LINK_STATUS |
6419 NIG_MASK_MI_INT));
6420
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00006421 ext_phy_addr[port] = XGXS_EXT_PHY_ADDR(ext_phy_config);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006422
6423 /* Need to take the phy out of low power mode in order
6424 to write to access its registers */
6425 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
6426 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
6427
6428 /* Reset the phy */
6429 bnx2x_cl45_write(bp, port,
6430 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
6431 ext_phy_addr[port],
6432 MDIO_PMA_DEVAD,
6433 MDIO_PMA_REG_CTRL,
6434 1<<15);
6435 }
6436
6437 /* Add delay of 150ms after reset */
6438 msleep(150);
6439
6440 /* PART2 - Download firmware to both phys */
6441 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
6442 u16 fw_ver1;
6443
6444 bnx2x_bcm8073_external_rom_boot(bp, port,
Eilon Greensteina35da8d2009-02-12 08:37:02 +00006445 ext_phy_addr[port], shmem_base);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006446
6447 bnx2x_cl45_read(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
6448 ext_phy_addr[port],
6449 MDIO_PMA_DEVAD,
6450 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
Eilon Greenstein16b311c2009-01-14 06:44:24 +00006451 if (fw_ver1 == 0 || fw_ver1 == 0x4321) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006452 DP(NETIF_MSG_LINK,
Eilon Greenstein16b311c2009-01-14 06:44:24 +00006453 "bnx2x_8073_common_init_phy port %x:"
6454 "Download failed. fw version = 0x%x\n",
6455 port, fw_ver1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006456 return -EINVAL;
6457 }
6458
6459 /* Only set bit 10 = 1 (Tx power down) */
6460 bnx2x_cl45_read(bp, port,
6461 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
6462 ext_phy_addr[port],
6463 MDIO_PMA_DEVAD,
6464 MDIO_PMA_REG_TX_POWER_DOWN, &val);
6465
6466 /* Phase1 of TX_POWER_DOWN reset */
6467 bnx2x_cl45_write(bp, port,
6468 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
6469 ext_phy_addr[port],
6470 MDIO_PMA_DEVAD,
6471 MDIO_PMA_REG_TX_POWER_DOWN,
6472 (val | 1<<10));
6473 }
6474
6475 /* Toggle Transmitter: Power down and then up with 600ms
6476 delay between */
6477 msleep(600);
6478
6479 /* PART3 - complete TX_POWER_DOWN process, and set GPIO2 back to low */
6480 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Eilon Greensteinf5372252009-02-12 08:38:30 +00006481 /* Phase2 of POWER_DOWN_RESET */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006482 /* Release bit 10 (Release Tx power down) */
6483 bnx2x_cl45_read(bp, port,
6484 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
6485 ext_phy_addr[port],
6486 MDIO_PMA_DEVAD,
6487 MDIO_PMA_REG_TX_POWER_DOWN, &val);
6488
6489 bnx2x_cl45_write(bp, port,
6490 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
6491 ext_phy_addr[port],
6492 MDIO_PMA_DEVAD,
6493 MDIO_PMA_REG_TX_POWER_DOWN, (val & (~(1<<10))));
6494 msleep(15);
6495
6496 /* Read modify write the SPI-ROM version select register */
6497 bnx2x_cl45_read(bp, port,
6498 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
6499 ext_phy_addr[port],
6500 MDIO_PMA_DEVAD,
6501 MDIO_PMA_REG_EDC_FFE_MAIN, &val);
6502 bnx2x_cl45_write(bp, port,
6503 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
6504 ext_phy_addr[port],
6505 MDIO_PMA_DEVAD,
6506 MDIO_PMA_REG_EDC_FFE_MAIN, (val | (1<<12)));
6507
6508 /* set GPIO2 back to LOW */
6509 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
6510 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
6511 }
6512 return 0;
6513
6514}
6515
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006516static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base)
6517{
6518 u8 ext_phy_addr[PORT_MAX];
Eilon Greensteinbc7f0a02009-08-12 08:23:01 +00006519 s8 port, first_port, i;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006520 u32 swap_val, swap_override;
6521 DP(NETIF_MSG_LINK, "Executing BCM8727 common init\n");
6522 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
6523 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
6524
Eilon Greensteinf57a6022009-08-12 08:23:11 +00006525 bnx2x_ext_phy_hw_reset(bp, 1 ^ (swap_val && swap_override));
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006526 msleep(5);
6527
Eilon Greensteinbc7f0a02009-08-12 08:23:01 +00006528 if (swap_val && swap_override)
6529 first_port = PORT_0;
6530 else
6531 first_port = PORT_1;
6532
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006533 /* PART1 - Reset both phys */
Eilon Greensteinbc7f0a02009-08-12 08:23:01 +00006534 for (i = 0, port = first_port; i < PORT_MAX; i++, port = !port) {
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006535 /* Extract the ext phy address for the port */
6536 u32 ext_phy_config = REG_RD(bp, shmem_base +
6537 offsetof(struct shmem_region,
6538 dev_info.port_hw_config[port].external_phy_config));
6539
6540 /* disable attentions */
6541 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
6542 (NIG_MASK_XGXS0_LINK_STATUS |
6543 NIG_MASK_XGXS0_LINK10G |
6544 NIG_MASK_SERDES0_LINK_STATUS |
6545 NIG_MASK_MI_INT));
6546
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00006547 ext_phy_addr[port] = XGXS_EXT_PHY_ADDR(ext_phy_config);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006548
6549 /* Reset the phy */
6550 bnx2x_cl45_write(bp, port,
6551 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
6552 ext_phy_addr[port],
6553 MDIO_PMA_DEVAD,
6554 MDIO_PMA_REG_CTRL,
6555 1<<15);
6556 }
6557
6558 /* Add delay of 150ms after reset */
6559 msleep(150);
6560
6561 /* PART2 - Download firmware to both phys */
Eilon Greensteinbc7f0a02009-08-12 08:23:01 +00006562 for (i = 0, port = first_port; i < PORT_MAX; i++, port = !port) {
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006563 u16 fw_ver1;
6564
6565 bnx2x_bcm8727_external_rom_boot(bp, port,
6566 ext_phy_addr[port], shmem_base);
6567
6568 bnx2x_cl45_read(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
6569 ext_phy_addr[port],
6570 MDIO_PMA_DEVAD,
6571 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
6572 if (fw_ver1 == 0 || fw_ver1 == 0x4321) {
6573 DP(NETIF_MSG_LINK,
Eilon Greensteinbc7f0a02009-08-12 08:23:01 +00006574 "bnx2x_8727_common_init_phy port %x:"
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006575 "Download failed. fw version = 0x%x\n",
6576 port, fw_ver1);
6577 return -EINVAL;
6578 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006579 }
6580
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006581 return 0;
6582}
6583
Eilon Greenstein589abe32009-02-12 08:36:55 +00006584
6585static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp, u32 shmem_base)
6586{
6587 u8 ext_phy_addr;
6588 u32 val;
6589 s8 port;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00006590
Eilon Greenstein589abe32009-02-12 08:36:55 +00006591 /* Use port1 because of the static port-swap */
6592 /* Enable the module detection interrupt */
6593 val = REG_RD(bp, MISC_REG_GPIO_EVENT_EN);
6594 val |= ((1<<MISC_REGISTERS_GPIO_3)|
6595 (1<<(MISC_REGISTERS_GPIO_3 + MISC_REGISTERS_GPIO_PORT_SHIFT)));
6596 REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val);
6597
Eilon Greensteinf57a6022009-08-12 08:23:11 +00006598 bnx2x_ext_phy_hw_reset(bp, 1);
Eilon Greenstein589abe32009-02-12 08:36:55 +00006599 msleep(5);
6600 for (port = 0; port < PORT_MAX; port++) {
6601 /* Extract the ext phy address for the port */
6602 u32 ext_phy_config = REG_RD(bp, shmem_base +
6603 offsetof(struct shmem_region,
6604 dev_info.port_hw_config[port].external_phy_config));
6605
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00006606 ext_phy_addr = XGXS_EXT_PHY_ADDR(ext_phy_config);
Eilon Greenstein589abe32009-02-12 08:36:55 +00006607 DP(NETIF_MSG_LINK, "8726_common_init : ext_phy_addr = 0x%x\n",
6608 ext_phy_addr);
6609
6610 bnx2x_8726_reset_phy(bp, port, ext_phy_addr);
6611
6612 /* Set fault module detected LED on */
6613 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
6614 MISC_REGISTERS_GPIO_HIGH,
6615 port);
6616 }
6617
6618 return 0;
6619}
6620
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02006621
6622static u8 bnx2x_84823_common_init_phy(struct bnx2x *bp, u32 shmem_base)
6623{
6624 /* HW reset */
6625 bnx2x_ext_phy_hw_reset(bp, 1);
6626 return 0;
6627}
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006628u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base)
6629{
6630 u8 rc = 0;
6631 u32 ext_phy_type;
6632
Eilon Greensteinf5372252009-02-12 08:38:30 +00006633 DP(NETIF_MSG_LINK, "Begin common phy init\n");
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006634
6635 /* Read the ext_phy_type for arbitrary port(0) */
6636 ext_phy_type = XGXS_EXT_PHY_TYPE(
6637 REG_RD(bp, shmem_base +
6638 offsetof(struct shmem_region,
6639 dev_info.port_hw_config[0].external_phy_config)));
6640
6641 switch (ext_phy_type) {
6642 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
6643 {
6644 rc = bnx2x_8073_common_init_phy(bp, shmem_base);
6645 break;
6646 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006647
6648 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
6649 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
6650 rc = bnx2x_8727_common_init_phy(bp, shmem_base);
6651 break;
6652
Eilon Greenstein589abe32009-02-12 08:36:55 +00006653 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
6654 /* GPIO1 affects both ports, so there's need to pull
6655 it for single port alone */
6656 rc = bnx2x_8726_common_init_phy(bp, shmem_base);
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02006657 break;
6658 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
6659 rc = bnx2x_84823_common_init_phy(bp, shmem_base);
Eilon Greenstein589abe32009-02-12 08:36:55 +00006660 break;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006661 default:
6662 DP(NETIF_MSG_LINK,
6663 "bnx2x_common_init_phy: ext_phy 0x%x not required\n",
6664 ext_phy_type);
6665 break;
6666 }
6667
6668 return rc;
6669}
6670
Eilon Greensteinf57a6022009-08-12 08:23:11 +00006671void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, u8 port, u8 phy_addr)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006672{
6673 u16 val, cnt;
6674
6675 bnx2x_cl45_read(bp, port,
6676 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
6677 phy_addr,
6678 MDIO_PMA_DEVAD,
6679 MDIO_PMA_REG_7101_RESET, &val);
6680
6681 for (cnt = 0; cnt < 10; cnt++) {
6682 msleep(50);
6683 /* Writes a self-clearing reset */
6684 bnx2x_cl45_write(bp, port,
6685 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
6686 phy_addr,
6687 MDIO_PMA_DEVAD,
6688 MDIO_PMA_REG_7101_RESET,
6689 (val | (1<<15)));
6690 /* Wait for clear */
6691 bnx2x_cl45_read(bp, port,
6692 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
6693 phy_addr,
6694 MDIO_PMA_DEVAD,
6695 MDIO_PMA_REG_7101_RESET, &val);
6696
6697 if ((val & (1<<15)) == 0)
6698 break;
6699 }
6700}