blob: bb42104b23778421e60b0e989847606ea0eb2ce2 [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/**********************************************************/
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000171
172#define CL45_WR_OVER_CL22(_bp, _phy, _bank, _addr, _val) \
173 bnx2x_cl45_write(_bp, _phy, \
Yaniv Rosner7aa07112010-09-07 11:41:01 +0000174 (_phy)->def_md_devad, \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700175 (_bank + (_addr & 0xf)), \
176 _val)
177
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000178#define CL45_RD_OVER_CL22(_bp, _phy, _bank, _addr, _val) \
179 bnx2x_cl45_read(_bp, _phy, \
Yaniv Rosner7aa07112010-09-07 11:41:01 +0000180 (_phy)->def_md_devad, \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700181 (_bank + (_addr & 0xf)), \
182 _val)
183
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000184static void bnx2x_set_serdes_access(struct bnx2x *bp, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700185{
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000186 u32 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +0000187
Eilon Greensteinc1b73992009-02-12 08:37:07 +0000188 /* Set Clause 22 */
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000189 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + port*0x10, 1);
Eilon Greensteinc1b73992009-02-12 08:37:07 +0000190 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 */
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000195 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + port*0x10, 0);
Eilon Greensteinc1b73992009-02-12 08:37:07 +0000196}
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000197
Eilon Greensteinc1b73992009-02-12 08:37:07 +0000198static void bnx2x_set_phy_mdio(struct link_params *params, u8 phy_flags)
199{
200 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +0000201
Eilon Greensteinc1b73992009-02-12 08:37:07 +0000202 if (phy_flags & PHY_XGXS_FLAG) {
203 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_ST +
204 params->port*0x18, 0);
205 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + params->port*0x18,
206 DEFAULT_PHY_DEV_ADDR);
207 } else {
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000208 bnx2x_set_serdes_access(bp, params->port);
Eilon Greensteinc1b73992009-02-12 08:37:07 +0000209
210 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_DEVAD +
211 params->port*0x10,
212 DEFAULT_PHY_DEV_ADDR);
213 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700214}
215
216static u32 bnx2x_bits_en(struct bnx2x *bp, u32 reg, u32 bits)
217{
218 u32 val = REG_RD(bp, reg);
219
220 val |= bits;
221 REG_WR(bp, reg, val);
222 return val;
223}
224
225static u32 bnx2x_bits_dis(struct bnx2x *bp, u32 reg, u32 bits)
226{
227 u32 val = REG_RD(bp, reg);
228
229 val &= ~bits;
230 REG_WR(bp, reg, val);
231 return val;
232}
233
234static void bnx2x_emac_init(struct link_params *params,
235 struct link_vars *vars)
236{
237 /* reset and unreset the emac core */
238 struct bnx2x *bp = params->bp;
239 u8 port = params->port;
240 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
241 u32 val;
242 u16 timeout;
243
244 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
245 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
246 udelay(5);
247 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
248 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
249
250 /* init emac - use read-modify-write */
251 /* self clear reset */
252 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700253 EMAC_WR(bp, EMAC_REG_EMAC_MODE, (val | EMAC_MODE_RESET));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700254
255 timeout = 200;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700256 do {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700257 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
258 DP(NETIF_MSG_LINK, "EMAC reset reg is %u\n", val);
259 if (!timeout) {
260 DP(NETIF_MSG_LINK, "EMAC timeout!\n");
261 return;
262 }
263 timeout--;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700264 } while (val & EMAC_MODE_RESET);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700265
266 /* Set mac address */
267 val = ((params->mac_addr[0] << 8) |
268 params->mac_addr[1]);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700269 EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700270
271 val = ((params->mac_addr[2] << 24) |
272 (params->mac_addr[3] << 16) |
273 (params->mac_addr[4] << 8) |
274 params->mac_addr[5]);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700275 EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH + 4, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700276}
277
278static u8 bnx2x_emac_enable(struct link_params *params,
279 struct link_vars *vars, u8 lb)
280{
281 struct bnx2x *bp = params->bp;
282 u8 port = params->port;
283 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
284 u32 val;
285
286 DP(NETIF_MSG_LINK, "enabling EMAC\n");
287
288 /* enable emac and not bmac */
289 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 1);
290
291 /* for paladium */
292 if (CHIP_REV_IS_EMUL(bp)) {
293 /* Use lane 1 (of lanes 0-3) */
294 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1);
295 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
296 port*4, 1);
297 }
298 /* for fpga */
299 else
300
301 if (CHIP_REV_IS_FPGA(bp)) {
302 /* Use lane 1 (of lanes 0-3) */
303 DP(NETIF_MSG_LINK, "bnx2x_emac_enable: Setting FPGA\n");
304
305 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1);
306 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4,
307 0);
308 } else
309 /* ASIC */
310 if (vars->phy_flags & PHY_XGXS_FLAG) {
311 u32 ser_lane = ((params->lane_config &
312 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
313 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
314
315 DP(NETIF_MSG_LINK, "XGXS\n");
316 /* select the master lanes (out of 0-3) */
317 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 +
318 port*4, ser_lane);
319 /* select XGXS */
320 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
321 port*4, 1);
322
323 } else { /* SerDes */
324 DP(NETIF_MSG_LINK, "SerDes\n");
325 /* select SerDes */
326 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
327 port*4, 0);
328 }
329
Eilon Greenstein811a2f22009-02-12 08:37:04 +0000330 bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
331 EMAC_RX_MODE_RESET);
332 bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
333 EMAC_TX_MODE_RESET);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700334
335 if (CHIP_REV_IS_SLOW(bp)) {
336 /* config GMII mode */
337 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700338 EMAC_WR(bp, EMAC_REG_EMAC_MODE,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700339 (val | EMAC_MODE_PORT_GMII));
340 } else { /* ASIC */
341 /* pause enable/disable */
342 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
343 EMAC_RX_MODE_FLOW_EN);
David S. Millerc0700f92008-12-16 23:53:20 -0800344 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700345 bnx2x_bits_en(bp, emac_base +
346 EMAC_REG_EMAC_RX_MODE,
347 EMAC_RX_MODE_FLOW_EN);
348
349 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700350 (EMAC_TX_MODE_EXT_PAUSE_EN |
351 EMAC_TX_MODE_FLOW_EN));
David S. Millerc0700f92008-12-16 23:53:20 -0800352 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700353 bnx2x_bits_en(bp, emac_base +
354 EMAC_REG_EMAC_TX_MODE,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700355 (EMAC_TX_MODE_EXT_PAUSE_EN |
356 EMAC_TX_MODE_FLOW_EN));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700357 }
358
359 /* KEEP_VLAN_TAG, promiscuous */
360 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_RX_MODE);
361 val |= EMAC_RX_MODE_KEEP_VLAN_TAG | EMAC_RX_MODE_PROMISCUOUS;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700362 EMAC_WR(bp, EMAC_REG_EMAC_RX_MODE, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700363
364 /* Set Loopback */
365 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
366 if (lb)
367 val |= 0x810;
368 else
369 val &= ~0x810;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700370 EMAC_WR(bp, EMAC_REG_EMAC_MODE, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700371
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +0000372 /* enable emac */
373 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 1);
374
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700375 /* enable emac for jumbo packets */
Eilon Greenstein3196a882008-08-13 15:58:49 -0700376 EMAC_WR(bp, EMAC_REG_EMAC_RX_MTU_SIZE,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700377 (EMAC_RX_MTU_SIZE_JUMBO_ENA |
378 (ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD)));
379
380 /* strip CRC */
381 REG_WR(bp, NIG_REG_NIG_INGRESS_EMAC0_NO_CRC + port*4, 0x1);
382
383 /* disable the NIG in/out to the bmac */
384 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x0);
385 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, 0x0);
386 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x0);
387
388 /* enable the NIG in/out to the emac */
389 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x1);
390 val = 0;
David S. Millerc0700f92008-12-16 23:53:20 -0800391 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700392 val = 1;
393
394 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, val);
395 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x1);
396
397 if (CHIP_REV_IS_EMUL(bp)) {
398 /* take the BigMac out of reset */
399 REG_WR(bp,
400 GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
401 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
402
403 /* enable access for bmac registers */
404 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
Eilon Greenstein6f654972009-08-12 08:23:51 +0000405 } else
406 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700407
408 vars->mac_type = MAC_TYPE_EMAC;
409 return 0;
410}
411
412
413
414static u8 bnx2x_bmac_enable(struct link_params *params, struct link_vars *vars,
415 u8 is_lb)
416{
417 struct bnx2x *bp = params->bp;
418 u8 port = params->port;
419 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
420 NIG_REG_INGRESS_BMAC0_MEM;
421 u32 wb_data[2];
422 u32 val;
423
424 DP(NETIF_MSG_LINK, "Enabling BigMAC\n");
425 /* reset and unreset the BigMac */
426 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
427 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
428 msleep(1);
429
430 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
431 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
432
433 /* enable access for bmac registers */
434 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
435
436 /* XGXS control */
437 wb_data[0] = 0x3c;
438 wb_data[1] = 0;
439 REG_WR_DMAE(bp, bmac_addr +
440 BIGMAC_REGISTER_BMAC_XGXS_CONTROL,
441 wb_data, 2);
442
443 /* tx MAC SA */
444 wb_data[0] = ((params->mac_addr[2] << 24) |
445 (params->mac_addr[3] << 16) |
446 (params->mac_addr[4] << 8) |
447 params->mac_addr[5]);
448 wb_data[1] = ((params->mac_addr[0] << 8) |
449 params->mac_addr[1]);
450 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_SOURCE_ADDR,
451 wb_data, 2);
452
453 /* tx control */
454 val = 0xc0;
David S. Millerc0700f92008-12-16 23:53:20 -0800455 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700456 val |= 0x800000;
457 wb_data[0] = val;
458 wb_data[1] = 0;
459 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_CONTROL,
460 wb_data, 2);
461
462 /* mac control */
463 val = 0x3;
464 if (is_lb) {
465 val |= 0x4;
466 DP(NETIF_MSG_LINK, "enable bmac loopback\n");
467 }
468 wb_data[0] = val;
469 wb_data[1] = 0;
470 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
471 wb_data, 2);
472
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700473 /* set rx mtu */
474 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
475 wb_data[1] = 0;
476 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_MAX_SIZE,
477 wb_data, 2);
478
479 /* rx control set to don't strip crc */
480 val = 0x14;
David S. Millerc0700f92008-12-16 23:53:20 -0800481 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700482 val |= 0x20;
483 wb_data[0] = val;
484 wb_data[1] = 0;
485 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_CONTROL,
486 wb_data, 2);
487
488 /* set tx mtu */
489 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
490 wb_data[1] = 0;
491 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_MAX_SIZE,
492 wb_data, 2);
493
494 /* set cnt max size */
495 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
496 wb_data[1] = 0;
497 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_CNT_MAX_SIZE,
498 wb_data, 2);
499
500 /* configure safc */
501 wb_data[0] = 0x1000200;
502 wb_data[1] = 0;
503 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_LLFC_MSG_FLDS,
504 wb_data, 2);
505 /* fix for emulation */
506 if (CHIP_REV_IS_EMUL(bp)) {
507 wb_data[0] = 0xf000;
508 wb_data[1] = 0;
509 REG_WR_DMAE(bp,
510 bmac_addr + BIGMAC_REGISTER_TX_PAUSE_THRESHOLD,
511 wb_data, 2);
512 }
513
514 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0x1);
515 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 0x0);
516 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 0x0);
517 val = 0;
David S. Millerc0700f92008-12-16 23:53:20 -0800518 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700519 val = 1;
520 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, val);
521 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x0);
522 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x0);
523 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, 0x0);
524 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x1);
525 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x1);
526
527 vars->mac_type = MAC_TYPE_BMAC;
528 return 0;
529}
530
531static void bnx2x_phy_deassert(struct link_params *params, u8 phy_flags)
532{
533 struct bnx2x *bp = params->bp;
534 u32 val;
535
536 if (phy_flags & PHY_XGXS_FLAG) {
537 DP(NETIF_MSG_LINK, "bnx2x_phy_deassert:XGXS\n");
538 val = XGXS_RESET_BITS;
539
540 } else { /* SerDes */
541 DP(NETIF_MSG_LINK, "bnx2x_phy_deassert:SerDes\n");
542 val = SERDES_RESET_BITS;
543 }
544
545 val = val << (params->port*16);
546
547 /* reset and unreset the SerDes/XGXS */
548 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
549 val);
550 udelay(500);
551 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET,
552 val);
Eilon Greensteinc1b73992009-02-12 08:37:07 +0000553 bnx2x_set_phy_mdio(params, phy_flags);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700554}
555
556void bnx2x_link_status_update(struct link_params *params,
557 struct link_vars *vars)
558{
559 struct bnx2x *bp = params->bp;
560 u8 link_10g;
561 u8 port = params->port;
562
563 if (params->switch_cfg == SWITCH_CFG_1G)
564 vars->phy_flags = PHY_SERDES_FLAG;
565 else
566 vars->phy_flags = PHY_XGXS_FLAG;
567 vars->link_status = REG_RD(bp, params->shmem_base +
568 offsetof(struct shmem_region,
569 port_mb[port].link_status));
570
571 vars->link_up = (vars->link_status & LINK_STATUS_LINK_UP);
572
573 if (vars->link_up) {
574 DP(NETIF_MSG_LINK, "phy link up\n");
575
576 vars->phy_link_up = 1;
577 vars->duplex = DUPLEX_FULL;
578 switch (vars->link_status &
579 LINK_STATUS_SPEED_AND_DUPLEX_MASK) {
580 case LINK_10THD:
581 vars->duplex = DUPLEX_HALF;
582 /* fall thru */
583 case LINK_10TFD:
584 vars->line_speed = SPEED_10;
585 break;
586
587 case LINK_100TXHD:
588 vars->duplex = DUPLEX_HALF;
589 /* fall thru */
590 case LINK_100T4:
591 case LINK_100TXFD:
592 vars->line_speed = SPEED_100;
593 break;
594
595 case LINK_1000THD:
596 vars->duplex = DUPLEX_HALF;
597 /* fall thru */
598 case LINK_1000TFD:
599 vars->line_speed = SPEED_1000;
600 break;
601
602 case LINK_2500THD:
603 vars->duplex = DUPLEX_HALF;
604 /* fall thru */
605 case LINK_2500TFD:
606 vars->line_speed = SPEED_2500;
607 break;
608
609 case LINK_10GTFD:
610 vars->line_speed = SPEED_10000;
611 break;
612
613 case LINK_12GTFD:
614 vars->line_speed = SPEED_12000;
615 break;
616
617 case LINK_12_5GTFD:
618 vars->line_speed = SPEED_12500;
619 break;
620
621 case LINK_13GTFD:
622 vars->line_speed = SPEED_13000;
623 break;
624
625 case LINK_15GTFD:
626 vars->line_speed = SPEED_15000;
627 break;
628
629 case LINK_16GTFD:
630 vars->line_speed = SPEED_16000;
631 break;
632
633 default:
634 break;
635 }
636
Yaniv Rosner7aa07112010-09-07 11:41:01 +0000637 vars->flow_ctrl = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700638 if (vars->link_status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED)
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
Yaniv Rosner7aa07112010-09-07 11:41:01 +0000644 if (!vars->flow_ctrl)
645 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
646
647 if (vars->line_speed &&
648 ((vars->line_speed == SPEED_10) ||
649 (vars->line_speed == SPEED_100))) {
650 vars->phy_flags |= PHY_SGMII_FLAG;
651 } else {
652 vars->phy_flags &= ~PHY_SGMII_FLAG;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700653 }
654
655 /* anything 10 and over uses the bmac */
656 link_10g = ((vars->line_speed == SPEED_10000) ||
657 (vars->line_speed == SPEED_12000) ||
658 (vars->line_speed == SPEED_12500) ||
659 (vars->line_speed == SPEED_13000) ||
660 (vars->line_speed == SPEED_15000) ||
661 (vars->line_speed == SPEED_16000));
662 if (link_10g)
663 vars->mac_type = MAC_TYPE_BMAC;
664 else
665 vars->mac_type = MAC_TYPE_EMAC;
666
667 } else { /* link down */
668 DP(NETIF_MSG_LINK, "phy link down\n");
669
670 vars->phy_link_up = 0;
671
672 vars->line_speed = 0;
673 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -0800674 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700675
676 /* indicate no mac active */
677 vars->mac_type = MAC_TYPE_NONE;
678 }
679
680 DP(NETIF_MSG_LINK, "link_status 0x%x phy_link_up %x\n",
681 vars->link_status, vars->phy_link_up);
682 DP(NETIF_MSG_LINK, "line_speed %x duplex %x flow_ctrl 0x%x\n",
683 vars->line_speed, vars->duplex, vars->flow_ctrl);
684}
685
686static void bnx2x_update_mng(struct link_params *params, u32 link_status)
687{
688 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +0000689
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700690 REG_WR(bp, params->shmem_base +
691 offsetof(struct shmem_region,
692 port_mb[params->port].link_status),
693 link_status);
694}
695
696static void bnx2x_bmac_rx_disable(struct bnx2x *bp, u8 port)
697{
698 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
699 NIG_REG_INGRESS_BMAC0_MEM;
700 u32 wb_data[2];
Eilon Greenstein3196a882008-08-13 15:58:49 -0700701 u32 nig_bmac_enable = REG_RD(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700702
703 /* Only if the bmac is out of reset */
704 if (REG_RD(bp, MISC_REG_RESET_REG_2) &
705 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port) &&
706 nig_bmac_enable) {
707
708 /* Clear Rx Enable bit in BMAC_CONTROL register */
709 REG_RD_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
710 wb_data, 2);
711 wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
712 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
713 wb_data, 2);
714
715 msleep(1);
716 }
717}
718
719static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl,
720 u32 line_speed)
721{
722 struct bnx2x *bp = params->bp;
723 u8 port = params->port;
724 u32 init_crd, crd;
725 u32 count = 1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700726
727 /* disable port */
728 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x1);
729
730 /* wait for init credit */
731 init_crd = REG_RD(bp, PBF_REG_P0_INIT_CRD + port*4);
732 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
733 DP(NETIF_MSG_LINK, "init_crd 0x%x crd 0x%x\n", init_crd, crd);
734
735 while ((init_crd != crd) && count) {
736 msleep(5);
737
738 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
739 count--;
740 }
741 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
742 if (init_crd != crd) {
743 DP(NETIF_MSG_LINK, "BUG! init_crd 0x%x != crd 0x%x\n",
744 init_crd, crd);
745 return -EINVAL;
746 }
747
David S. Millerc0700f92008-12-16 23:53:20 -0800748 if (flow_ctrl & BNX2X_FLOW_CTRL_RX ||
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700749 line_speed == SPEED_10 ||
750 line_speed == SPEED_100 ||
751 line_speed == SPEED_1000 ||
752 line_speed == SPEED_2500) {
753 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700754 /* update threshold */
755 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, 0);
756 /* update init credit */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700757 init_crd = 778; /* (800-18-4) */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700758
759 } else {
760 u32 thresh = (ETH_MAX_JUMBO_PACKET_SIZE +
761 ETH_OVREHEAD)/16;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700762 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700763 /* update threshold */
764 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, thresh);
765 /* update init credit */
766 switch (line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700767 case SPEED_10000:
768 init_crd = thresh + 553 - 22;
769 break;
770
771 case SPEED_12000:
772 init_crd = thresh + 664 - 22;
773 break;
774
775 case SPEED_13000:
776 init_crd = thresh + 742 - 22;
777 break;
778
779 case SPEED_16000:
780 init_crd = thresh + 778 - 22;
781 break;
782 default:
783 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
784 line_speed);
785 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700786 }
787 }
788 REG_WR(bp, PBF_REG_P0_INIT_CRD + port*4, init_crd);
789 DP(NETIF_MSG_LINK, "PBF updated to speed %d credit %d\n",
790 line_speed, init_crd);
791
792 /* probe the credit changes */
793 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x1);
794 msleep(5);
795 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x0);
796
797 /* enable port */
798 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x0);
799 return 0;
800}
801
Eilon Greenstein589abe32009-02-12 08:36:55 +0000802static u32 bnx2x_get_emac_base(struct bnx2x *bp, u32 ext_phy_type, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700803{
804 u32 emac_base;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +0000805
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700806 switch (ext_phy_type) {
807 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
Eilon Greenstein589abe32009-02-12 08:36:55 +0000808 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
Eilon Greenstein4d295db2009-07-21 05:47:47 +0000809 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
Eilon Greenstein589abe32009-02-12 08:36:55 +0000810 /* All MDC/MDIO is directed through single EMAC */
811 if (REG_RD(bp, NIG_REG_PORT_SWAP))
812 emac_base = GRCBASE_EMAC0;
813 else
814 emac_base = GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700815 break;
816 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Eilon Greenstein6378c022008-08-13 15:59:25 -0700817 emac_base = (port) ? GRCBASE_EMAC0 : GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700818 break;
819 default:
Eilon Greenstein6378c022008-08-13 15:59:25 -0700820 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700821 break;
822 }
823 return emac_base;
824
825}
826
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000827u8 bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy,
828 u8 devad, u16 reg, u16 val)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700829{
830 u32 tmp, saved_mode;
831 u8 i, rc = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700832
833 /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
834 * (a value of 49==0x31) and make sure that the AUTO poll is off
835 */
Eilon Greenstein589abe32009-02-12 08:36:55 +0000836
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000837 saved_mode = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700838 tmp = saved_mode & ~(EMAC_MDIO_MODE_AUTO_POLL |
839 EMAC_MDIO_MODE_CLOCK_CNT);
840 tmp |= (EMAC_MDIO_MODE_CLAUSE_45 |
841 (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000842 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, tmp);
843 REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700844 udelay(40);
845
846 /* address */
847
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000848 tmp = ((phy->addr << 21) | (devad << 16) | reg |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700849 EMAC_MDIO_COMM_COMMAND_ADDRESS |
850 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000851 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700852
853 for (i = 0; i < 50; i++) {
854 udelay(10);
855
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000856 tmp = REG_RD(bp, phy->mdio_ctrl +
857 EMAC_REG_EMAC_MDIO_COMM);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700858 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
859 udelay(5);
860 break;
861 }
862 }
863 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
864 DP(NETIF_MSG_LINK, "write phy register failed\n");
865 rc = -EFAULT;
866 } else {
867 /* data */
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000868 tmp = ((phy->addr << 21) | (devad << 16) | val |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700869 EMAC_MDIO_COMM_COMMAND_WRITE_45 |
870 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000871 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700872
873 for (i = 0; i < 50; i++) {
874 udelay(10);
875
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000876 tmp = REG_RD(bp, phy->mdio_ctrl +
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700877 EMAC_REG_EMAC_MDIO_COMM);
878 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
879 udelay(5);
880 break;
881 }
882 }
883 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
884 DP(NETIF_MSG_LINK, "write phy register failed\n");
885 rc = -EFAULT;
886 }
887 }
888
889 /* Restore the saved mode */
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000890 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700891
892 return rc;
893}
894
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000895u8 bnx2x_cl45_read(struct bnx2x *bp, struct bnx2x_phy *phy,
896 u8 devad, u16 reg, u16 *ret_val)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700897{
898 u32 val, saved_mode;
899 u16 i;
900 u8 rc = 0;
901
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700902 /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
903 * (a value of 49==0x31) and make sure that the AUTO poll is off
904 */
Eilon Greenstein589abe32009-02-12 08:36:55 +0000905
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000906 saved_mode = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
907 val = saved_mode & ~((EMAC_MDIO_MODE_AUTO_POLL |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700908 EMAC_MDIO_MODE_CLOCK_CNT));
909 val |= (EMAC_MDIO_MODE_CLAUSE_45 |
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +0000910 (49L << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000911 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, val);
912 REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700913 udelay(40);
914
915 /* address */
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000916 val = ((phy->addr << 21) | (devad << 16) | reg |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700917 EMAC_MDIO_COMM_COMMAND_ADDRESS |
918 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000919 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700920
921 for (i = 0; i < 50; i++) {
922 udelay(10);
923
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000924 val = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700925 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
926 udelay(5);
927 break;
928 }
929 }
930 if (val & EMAC_MDIO_COMM_START_BUSY) {
931 DP(NETIF_MSG_LINK, "read phy register failed\n");
932
933 *ret_val = 0;
934 rc = -EFAULT;
935
936 } else {
937 /* data */
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000938 val = ((phy->addr << 21) | (devad << 16) |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700939 EMAC_MDIO_COMM_COMMAND_READ_45 |
940 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000941 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700942
943 for (i = 0; i < 50; i++) {
944 udelay(10);
945
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000946 val = REG_RD(bp, phy->mdio_ctrl +
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700947 EMAC_REG_EMAC_MDIO_COMM);
948 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
949 *ret_val = (u16)(val & EMAC_MDIO_COMM_DATA);
950 break;
951 }
952 }
953 if (val & EMAC_MDIO_COMM_START_BUSY) {
954 DP(NETIF_MSG_LINK, "read phy register failed\n");
955
956 *ret_val = 0;
957 rc = -EFAULT;
958 }
959 }
960
961 /* Restore the saved mode */
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000962 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700963
964 return rc;
965}
966
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000967u8 bnx2x_phy_read(struct link_params *params, u8 phy_addr,
968 u8 devad, u16 reg, u16 *ret_val)
969{
970 u8 phy_index;
971 /**
972 * Probe for the phy according to the given phy_addr, and execute
973 * the read request on it
974 */
975 for (phy_index = 0; phy_index < params->num_phys; phy_index++) {
976 if (params->phy[phy_index].addr == phy_addr) {
977 return bnx2x_cl45_read(params->bp,
978 &params->phy[phy_index], devad,
979 reg, ret_val);
980 }
981 }
982 return -EINVAL;
983}
984
985u8 bnx2x_phy_write(struct link_params *params, u8 phy_addr,
986 u8 devad, u16 reg, u16 val)
987{
988 u8 phy_index;
989 /**
990 * Probe for the phy according to the given phy_addr, and execute
991 * the write request on it
992 */
993 for (phy_index = 0; phy_index < params->num_phys; phy_index++) {
994 if (params->phy[phy_index].addr == phy_addr) {
995 return bnx2x_cl45_write(params->bp,
996 &params->phy[phy_index], devad,
997 reg, val);
998 }
999 }
1000 return -EINVAL;
1001}
1002
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001003static void bnx2x_set_aer_mmd(struct link_params *params,
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001004 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001005{
1006 struct bnx2x *bp = params->bp;
1007 u32 ser_lane;
1008 u16 offset;
1009
1010 ser_lane = ((params->lane_config &
1011 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
1012 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
1013
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001014 offset = (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ?
1015 (phy->addr + ser_lane) : 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001016
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001017 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001018 MDIO_REG_BANK_AER_BLOCK,
1019 MDIO_AER_BLOCK_AER_REG, 0x3800 + offset);
1020}
1021
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001022static void bnx2x_set_master_ln(struct link_params *params,
1023 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001024{
1025 struct bnx2x *bp = params->bp;
1026 u16 new_master_ln, ser_lane;
1027 ser_lane = ((params->lane_config &
1028 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
1029 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
1030
1031 /* set the master_ln for AN */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001032 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001033 MDIO_REG_BANK_XGXS_BLOCK2,
1034 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
1035 &new_master_ln);
1036
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001037 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001038 MDIO_REG_BANK_XGXS_BLOCK2 ,
1039 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
1040 (new_master_ln | ser_lane));
1041}
1042
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001043static u8 bnx2x_reset_unicore(struct link_params *params,
1044 struct bnx2x_phy *phy,
1045 u8 set_serdes)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001046{
1047 struct bnx2x *bp = params->bp;
1048 u16 mii_control;
1049 u16 i;
1050
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001051 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001052 MDIO_REG_BANK_COMBO_IEEE0,
1053 MDIO_COMBO_IEEE0_MII_CONTROL, &mii_control);
1054
1055 /* reset the unicore */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001056 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001057 MDIO_REG_BANK_COMBO_IEEE0,
1058 MDIO_COMBO_IEEE0_MII_CONTROL,
1059 (mii_control |
1060 MDIO_COMBO_IEEO_MII_CONTROL_RESET));
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001061 if (set_serdes)
1062 bnx2x_set_serdes_access(bp, params->port);
Eilon Greensteinc1b73992009-02-12 08:37:07 +00001063
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001064 /* wait for the reset to self clear */
1065 for (i = 0; i < MDIO_ACCESS_TIMEOUT; i++) {
1066 udelay(5);
1067
1068 /* the reset erased the previous bank value */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001069 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001070 MDIO_REG_BANK_COMBO_IEEE0,
1071 MDIO_COMBO_IEEE0_MII_CONTROL,
1072 &mii_control);
1073
1074 if (!(mii_control & MDIO_COMBO_IEEO_MII_CONTROL_RESET)) {
1075 udelay(5);
1076 return 0;
1077 }
1078 }
1079
1080 DP(NETIF_MSG_LINK, "BUG! XGXS is still in reset!\n");
1081 return -EINVAL;
1082
1083}
1084
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001085static void bnx2x_set_swap_lanes(struct link_params *params,
1086 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001087{
1088 struct bnx2x *bp = params->bp;
1089 /* Each two bits represents a lane number:
1090 No swap is 0123 => 0x1b no need to enable the swap */
1091 u16 ser_lane, rx_lane_swap, tx_lane_swap;
1092
1093 ser_lane = ((params->lane_config &
1094 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
1095 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
1096 rx_lane_swap = ((params->lane_config &
1097 PORT_HW_CFG_LANE_SWAP_CFG_RX_MASK) >>
1098 PORT_HW_CFG_LANE_SWAP_CFG_RX_SHIFT);
1099 tx_lane_swap = ((params->lane_config &
1100 PORT_HW_CFG_LANE_SWAP_CFG_TX_MASK) >>
1101 PORT_HW_CFG_LANE_SWAP_CFG_TX_SHIFT);
1102
1103 if (rx_lane_swap != 0x1b) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001104 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001105 MDIO_REG_BANK_XGXS_BLOCK2,
1106 MDIO_XGXS_BLOCK2_RX_LN_SWAP,
1107 (rx_lane_swap |
1108 MDIO_XGXS_BLOCK2_RX_LN_SWAP_ENABLE |
1109 MDIO_XGXS_BLOCK2_RX_LN_SWAP_FORCE_ENABLE));
1110 } else {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001111 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001112 MDIO_REG_BANK_XGXS_BLOCK2,
1113 MDIO_XGXS_BLOCK2_RX_LN_SWAP, 0);
1114 }
1115
1116 if (tx_lane_swap != 0x1b) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001117 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001118 MDIO_REG_BANK_XGXS_BLOCK2,
1119 MDIO_XGXS_BLOCK2_TX_LN_SWAP,
1120 (tx_lane_swap |
1121 MDIO_XGXS_BLOCK2_TX_LN_SWAP_ENABLE));
1122 } else {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001123 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001124 MDIO_REG_BANK_XGXS_BLOCK2,
1125 MDIO_XGXS_BLOCK2_TX_LN_SWAP, 0);
1126 }
1127}
1128
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001129static void bnx2x_set_parallel_detection(struct bnx2x_phy *phy,
1130 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001131{
1132 struct bnx2x *bp = params->bp;
1133 u16 control2;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001134 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001135 MDIO_REG_BANK_SERDES_DIGITAL,
1136 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
1137 &control2);
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001138 if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
Yaniv Rosner18afb0a2009-11-05 19:18:04 +02001139 control2 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
1140 else
1141 control2 &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001142 DP(NETIF_MSG_LINK, "phy->speed_cap_mask = 0x%x, control2 = 0x%x\n",
1143 phy->speed_cap_mask, control2);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001144 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001145 MDIO_REG_BANK_SERDES_DIGITAL,
1146 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
1147 control2);
1148
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001149 if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
Yaniv Rosner18afb0a2009-11-05 19:18:04 +02001150 (params->speed_cap_mask &
1151 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001152 DP(NETIF_MSG_LINK, "XGXS\n");
1153
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001154 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001155 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1156 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK,
1157 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT);
1158
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001159 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001160 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1161 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
1162 &control2);
1163
1164
1165 control2 |=
1166 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN;
1167
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001168 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001169 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1170 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
1171 control2);
1172
1173 /* Disable parallel detection of HiG */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001174 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001175 MDIO_REG_BANK_XGXS_BLOCK2,
1176 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G,
1177 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_CX4_XGXS |
1178 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_HIGIG_XGXS);
1179 }
1180}
1181
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001182static void bnx2x_set_autoneg(struct bnx2x_phy *phy,
1183 struct link_params *params,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001184 struct link_vars *vars,
1185 u8 enable_cl73)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001186{
1187 struct bnx2x *bp = params->bp;
1188 u16 reg_val;
1189
1190 /* CL37 Autoneg */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001191 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001192 MDIO_REG_BANK_COMBO_IEEE0,
1193 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
1194
1195 /* CL37 Autoneg Enabled */
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_COMBO_IEEO_MII_CONTROL_AN_EN;
1198 else /* CL37 Autoneg Disabled */
1199 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1200 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN);
1201
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001202 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001203 MDIO_REG_BANK_COMBO_IEEE0,
1204 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
1205
1206 /* Enable/Disable Autodetection */
1207
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001208 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001209 MDIO_REG_BANK_SERDES_DIGITAL,
1210 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, &reg_val);
Eilon Greenstein239d6862009-08-12 08:23:04 +00001211 reg_val &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN |
1212 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT);
1213 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001214 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001215 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
1216 else
1217 reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
1218
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001219 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001220 MDIO_REG_BANK_SERDES_DIGITAL,
1221 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, reg_val);
1222
1223 /* Enable TetonII and BAM autoneg */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001224 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001225 MDIO_REG_BANK_BAM_NEXT_PAGE,
1226 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
1227 &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001228 if (vars->line_speed == SPEED_AUTO_NEG) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001229 /* Enable BAM aneg Mode and TetonII aneg Mode */
1230 reg_val |= (MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
1231 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
1232 } else {
1233 /* TetonII and BAM Autoneg Disabled */
1234 reg_val &= ~(MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
1235 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
1236 }
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001237 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001238 MDIO_REG_BANK_BAM_NEXT_PAGE,
1239 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
1240 reg_val);
1241
Eilon Greenstein239d6862009-08-12 08:23:04 +00001242 if (enable_cl73) {
1243 /* Enable Cl73 FSM status bits */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001244 CL45_WR_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001245 MDIO_REG_BANK_CL73_USERB0,
1246 MDIO_CL73_USERB0_CL73_UCTRL,
Yaniv Rosner7846e472009-11-05 19:18:07 +02001247 0xe);
Eilon Greenstein239d6862009-08-12 08:23:04 +00001248
1249 /* Enable BAM Station Manager*/
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001250 CL45_WR_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001251 MDIO_REG_BANK_CL73_USERB0,
1252 MDIO_CL73_USERB0_CL73_BAM_CTRL1,
1253 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN |
1254 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_STATION_MNGR_EN |
1255 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN);
1256
Yaniv Rosner7846e472009-11-05 19:18:07 +02001257 /* Advertise CL73 link speeds */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001258 CL45_RD_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001259 MDIO_REG_BANK_CL73_IEEEB1,
1260 MDIO_CL73_IEEEB1_AN_ADV2,
1261 &reg_val);
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001262 if (phy->speed_cap_mask &
Yaniv Rosner7846e472009-11-05 19:18:07 +02001263 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
1264 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001265 if (phy->speed_cap_mask &
Yaniv Rosner7846e472009-11-05 19:18:07 +02001266 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
1267 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX;
Eilon Greenstein239d6862009-08-12 08:23:04 +00001268
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001269 CL45_WR_OVER_CL22(bp, phy,
Julia Lawallcc817352010-08-05 10:26:38 +00001270 MDIO_REG_BANK_CL73_IEEEB1,
1271 MDIO_CL73_IEEEB1_AN_ADV2,
1272 reg_val);
Eilon Greenstein239d6862009-08-12 08:23:04 +00001273
Eilon Greenstein239d6862009-08-12 08:23:04 +00001274 /* CL73 Autoneg Enabled */
1275 reg_val = MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN;
1276
1277 } else /* CL73 Autoneg Disabled */
1278 reg_val = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001279
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001280 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001281 MDIO_REG_BANK_CL73_IEEEB0,
1282 MDIO_CL73_IEEEB0_CL73_AN_CONTROL, reg_val);
1283}
1284
1285/* program SerDes, forced speed */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001286static void bnx2x_program_serdes(struct bnx2x_phy *phy,
1287 struct link_params *params,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001288 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001289{
1290 struct bnx2x *bp = params->bp;
1291 u16 reg_val;
1292
Eilon Greenstein57937202009-08-12 08:23:53 +00001293 /* program duplex, disable autoneg and sgmii*/
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001294 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001295 MDIO_REG_BANK_COMBO_IEEE0,
1296 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
1297 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX |
Eilon Greenstein57937202009-08-12 08:23:53 +00001298 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1299 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK);
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001300 if (phy->req_duplex == DUPLEX_FULL)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001301 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001302 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001303 MDIO_REG_BANK_COMBO_IEEE0,
1304 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
1305
1306 /* program speed
1307 - needed only if the speed is greater than 1G (2.5G or 10G) */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001308 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001309 MDIO_REG_BANK_SERDES_DIGITAL,
1310 MDIO_SERDES_DIGITAL_MISC1, &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001311 /* clearing the speed value before setting the right speed */
1312 DP(NETIF_MSG_LINK, "MDIO_REG_BANK_SERDES_DIGITAL = 0x%x\n", reg_val);
1313
1314 reg_val &= ~(MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_MASK |
1315 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
1316
1317 if (!((vars->line_speed == SPEED_1000) ||
1318 (vars->line_speed == SPEED_100) ||
1319 (vars->line_speed == SPEED_10))) {
1320
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001321 reg_val |= (MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_156_25M |
1322 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001323 if (vars->line_speed == SPEED_10000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001324 reg_val |=
1325 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_10G_CX4;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001326 if (vars->line_speed == SPEED_13000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001327 reg_val |=
1328 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_13G;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001329 }
1330
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001331 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001332 MDIO_REG_BANK_SERDES_DIGITAL,
1333 MDIO_SERDES_DIGITAL_MISC1, reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001334
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001335}
1336
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001337static void bnx2x_set_brcm_cl37_advertisment(struct bnx2x_phy *phy,
1338 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001339{
1340 struct bnx2x *bp = params->bp;
1341 u16 val = 0;
1342
1343 /* configure the 48 bits for BAM AN */
1344
1345 /* set extended capabilities */
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001346 if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001347 val |= MDIO_OVER_1G_UP1_2_5G;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001348 if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001349 val |= MDIO_OVER_1G_UP1_10G;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001350 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001351 MDIO_REG_BANK_OVER_1G,
1352 MDIO_OVER_1G_UP1, val);
1353
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001354 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001355 MDIO_REG_BANK_OVER_1G,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001356 MDIO_OVER_1G_UP3, 0x400);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001357}
1358
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001359static void bnx2x_calc_ieee_aneg_adv(struct bnx2x_phy *phy,
1360 struct link_params *params, u16 *ieee_fc)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001361{
Yaniv Rosnerd5cb9e92009-11-05 19:18:10 +02001362 struct bnx2x *bp = params->bp;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001363 *ieee_fc = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001364 /* resolve pause mode and advertisement
1365 * Please refer to Table 28B-3 of the 802.3ab-1999 spec */
1366
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001367 switch (phy->req_flow_ctrl) {
David S. Millerc0700f92008-12-16 23:53:20 -08001368 case BNX2X_FLOW_CTRL_AUTO:
1369 if (params->req_fc_auto_adv == BNX2X_FLOW_CTRL_BOTH) {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001370 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001371 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
1372 } else {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001373 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001374 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
1375 }
1376 break;
David S. Millerc0700f92008-12-16 23:53:20 -08001377 case BNX2X_FLOW_CTRL_TX:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001378 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001379 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
1380 break;
1381
David S. Millerc0700f92008-12-16 23:53:20 -08001382 case BNX2X_FLOW_CTRL_RX:
1383 case BNX2X_FLOW_CTRL_BOTH:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001384 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001385 break;
1386
David S. Millerc0700f92008-12-16 23:53:20 -08001387 case BNX2X_FLOW_CTRL_NONE:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001388 default:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001389 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001390 break;
1391 }
Yaniv Rosnerd5cb9e92009-11-05 19:18:10 +02001392 DP(NETIF_MSG_LINK, "ieee_fc = 0x%x\n", *ieee_fc);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001393}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001394
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001395static void bnx2x_set_ieee_aneg_advertisment(struct bnx2x_phy *phy,
1396 struct link_params *params,
Eilon Greenstein1ef70b92009-08-12 08:23:59 +00001397 u16 ieee_fc)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001398{
1399 struct bnx2x *bp = params->bp;
Yaniv Rosner7846e472009-11-05 19:18:07 +02001400 u16 val;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001401 /* for AN, we are always publishing full duplex */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001402
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001403 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001404 MDIO_REG_BANK_COMBO_IEEE0,
Eilon Greenstein1ef70b92009-08-12 08:23:59 +00001405 MDIO_COMBO_IEEE0_AUTO_NEG_ADV, ieee_fc);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001406 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner7846e472009-11-05 19:18:07 +02001407 MDIO_REG_BANK_CL73_IEEEB1,
1408 MDIO_CL73_IEEEB1_AN_ADV1, &val);
1409 val &= ~MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_BOTH;
1410 val |= ((ieee_fc<<3) & MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001411 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosner7846e472009-11-05 19:18:07 +02001412 MDIO_REG_BANK_CL73_IEEEB1,
1413 MDIO_CL73_IEEEB1_AN_ADV1, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001414}
1415
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001416static void bnx2x_restart_autoneg(struct bnx2x_phy *phy,
1417 struct link_params *params,
1418 u8 enable_cl73)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001419{
1420 struct bnx2x *bp = params->bp;
Eilon Greenstein3a36f2e2009-02-12 08:37:09 +00001421 u16 mii_control;
Eilon Greenstein239d6862009-08-12 08:23:04 +00001422
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001423 DP(NETIF_MSG_LINK, "bnx2x_restart_autoneg\n");
Eilon Greenstein3a36f2e2009-02-12 08:37:09 +00001424 /* Enable and restart BAM/CL37 aneg */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001425
Eilon Greenstein239d6862009-08-12 08:23:04 +00001426 if (enable_cl73) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001427 CL45_RD_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001428 MDIO_REG_BANK_CL73_IEEEB0,
1429 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1430 &mii_control);
1431
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001432 CL45_WR_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001433 MDIO_REG_BANK_CL73_IEEEB0,
1434 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1435 (mii_control |
1436 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN |
1437 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN));
1438 } else {
1439
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001440 CL45_RD_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001441 MDIO_REG_BANK_COMBO_IEEE0,
1442 MDIO_COMBO_IEEE0_MII_CONTROL,
1443 &mii_control);
1444 DP(NETIF_MSG_LINK,
1445 "bnx2x_restart_autoneg mii_control before = 0x%x\n",
1446 mii_control);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001447 CL45_WR_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001448 MDIO_REG_BANK_COMBO_IEEE0,
1449 MDIO_COMBO_IEEE0_MII_CONTROL,
1450 (mii_control |
1451 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1452 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN));
1453 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001454}
1455
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001456static void bnx2x_initialize_sgmii_process(struct bnx2x_phy *phy,
1457 struct link_params *params,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001458 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001459{
1460 struct bnx2x *bp = params->bp;
1461 u16 control1;
1462
1463 /* in SGMII mode, the unicore is always slave */
1464
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001465 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001466 MDIO_REG_BANK_SERDES_DIGITAL,
1467 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
1468 &control1);
1469 control1 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT;
1470 /* set sgmii mode (and not fiber) */
1471 control1 &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE |
1472 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET |
1473 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_MSTR_MODE);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001474 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001475 MDIO_REG_BANK_SERDES_DIGITAL,
1476 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
1477 control1);
1478
1479 /* if forced speed */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001480 if (!(vars->line_speed == SPEED_AUTO_NEG)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001481 /* set speed, disable autoneg */
1482 u16 mii_control;
1483
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001484 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001485 MDIO_REG_BANK_COMBO_IEEE0,
1486 MDIO_COMBO_IEEE0_MII_CONTROL,
1487 &mii_control);
1488 mii_control &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1489 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK|
1490 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX);
1491
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001492 switch (vars->line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001493 case SPEED_100:
1494 mii_control |=
1495 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_100;
1496 break;
1497 case SPEED_1000:
1498 mii_control |=
1499 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_1000;
1500 break;
1501 case SPEED_10:
1502 /* there is nothing to set for 10M */
1503 break;
1504 default:
1505 /* invalid speed for SGMII */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001506 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
1507 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001508 break;
1509 }
1510
1511 /* setting the full duplex */
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001512 if (phy->req_duplex == DUPLEX_FULL)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001513 mii_control |=
1514 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001515 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001516 MDIO_REG_BANK_COMBO_IEEE0,
1517 MDIO_COMBO_IEEE0_MII_CONTROL,
1518 mii_control);
1519
1520 } else { /* AN mode */
1521 /* enable and restart AN */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001522 bnx2x_restart_autoneg(phy, 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 }
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001552 if (pause_result & (1<<0))
1553 vars->link_status |= LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE;
1554 if (pause_result & (1<<1))
1555 vars->link_status |= LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE;
1556
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001557}
1558
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001559static u8 bnx2x_ext_phy_resolve_fc(struct bnx2x_phy *phy,
1560 struct link_params *params,
1561 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001562{
1563 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00001564 u16 ld_pause; /* local */
1565 u16 lp_pause; /* link partner */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001566 u16 pause_result;
1567 u8 ret = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001568 /* read twice */
1569
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001570 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001571
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001572 if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO)
1573 vars->flow_ctrl = phy->req_flow_ctrl;
1574 else if (phy->req_line_speed != SPEED_AUTO_NEG)
1575 vars->flow_ctrl = params->req_fc_auto_adv;
1576 else if (vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001577 ret = 1;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001578 bnx2x_cl45_read(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001579 MDIO_AN_DEVAD,
1580 MDIO_AN_REG_ADV_PAUSE, &ld_pause);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001581 bnx2x_cl45_read(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001582 MDIO_AN_DEVAD,
1583 MDIO_AN_REG_LP_AUTO_NEG, &lp_pause);
1584 pause_result = (ld_pause &
1585 MDIO_AN_REG_ADV_PAUSE_MASK) >> 8;
1586 pause_result |= (lp_pause &
1587 MDIO_AN_REG_ADV_PAUSE_MASK) >> 10;
Frans Pop2381a552010-03-24 07:57:36 +00001588 DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x\n",
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001589 pause_result);
1590 bnx2x_pause_resolve(vars, pause_result);
1591 }
1592 return ret;
1593}
1594
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001595static u8 bnx2x_direct_parallel_detect_used(struct bnx2x_phy *phy,
1596 struct link_params *params)
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02001597{
1598 struct bnx2x *bp = params->bp;
1599 u16 pd_10g, status2_1000x;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001600 if (phy->req_line_speed != SPEED_AUTO_NEG)
1601 return 0;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001602 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02001603 MDIO_REG_BANK_SERDES_DIGITAL,
1604 MDIO_SERDES_DIGITAL_A_1000X_STATUS2,
1605 &status2_1000x);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001606 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02001607 MDIO_REG_BANK_SERDES_DIGITAL,
1608 MDIO_SERDES_DIGITAL_A_1000X_STATUS2,
1609 &status2_1000x);
1610 if (status2_1000x & MDIO_SERDES_DIGITAL_A_1000X_STATUS2_AN_DISABLED) {
1611 DP(NETIF_MSG_LINK, "1G parallel detect link on port %d\n",
1612 params->port);
1613 return 1;
1614 }
1615
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001616 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02001617 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1618 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_STATUS,
1619 &pd_10g);
1620
1621 if (pd_10g & MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_STATUS_PD_LINK) {
1622 DP(NETIF_MSG_LINK, "10G parallel detect link on port %d\n",
1623 params->port);
1624 return 1;
1625 }
1626 return 0;
1627}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001628
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001629static void bnx2x_flow_ctrl_resolve(struct bnx2x_phy *phy,
1630 struct link_params *params,
1631 struct link_vars *vars,
1632 u32 gp_status)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001633{
1634 struct bnx2x *bp = params->bp;
Eilon Greenstein3196a882008-08-13 15:58:49 -07001635 u16 ld_pause; /* local driver */
1636 u16 lp_pause; /* link partner */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001637 u16 pause_result;
1638
David S. Millerc0700f92008-12-16 23:53:20 -08001639 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001640
1641 /* resolve from gp_status in case of AN complete and not sgmii */
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001642 if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO)
1643 vars->flow_ctrl = phy->req_flow_ctrl;
1644 else if (phy->req_line_speed != SPEED_AUTO_NEG)
1645 vars->flow_ctrl = params->req_fc_auto_adv;
1646 else if ((gp_status & MDIO_AN_CL73_OR_37_COMPLETE) &&
1647 (!(vars->phy_flags & PHY_SGMII_FLAG))) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001648 if (bnx2x_direct_parallel_detect_used(phy, params)) {
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02001649 vars->flow_ctrl = params->req_fc_auto_adv;
1650 return;
1651 }
Yaniv Rosner7846e472009-11-05 19:18:07 +02001652 if ((gp_status &
1653 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
1654 MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) ==
1655 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
1656 MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) {
1657
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001658 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner7846e472009-11-05 19:18:07 +02001659 MDIO_REG_BANK_CL73_IEEEB1,
1660 MDIO_CL73_IEEEB1_AN_ADV1,
1661 &ld_pause);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001662 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner7846e472009-11-05 19:18:07 +02001663 MDIO_REG_BANK_CL73_IEEEB1,
1664 MDIO_CL73_IEEEB1_AN_LP_ADV1,
1665 &lp_pause);
1666 pause_result = (ld_pause &
1667 MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK)
1668 >> 8;
1669 pause_result |= (lp_pause &
1670 MDIO_CL73_IEEEB1_AN_LP_ADV1_PAUSE_MASK)
1671 >> 10;
1672 DP(NETIF_MSG_LINK, "pause_result CL73 0x%x\n",
1673 pause_result);
1674 } else {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001675 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner7846e472009-11-05 19:18:07 +02001676 MDIO_REG_BANK_COMBO_IEEE0,
1677 MDIO_COMBO_IEEE0_AUTO_NEG_ADV,
1678 &ld_pause);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001679 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner7846e472009-11-05 19:18:07 +02001680 MDIO_REG_BANK_COMBO_IEEE0,
1681 MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1,
1682 &lp_pause);
1683 pause_result = (ld_pause &
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001684 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>5;
Yaniv Rosner7846e472009-11-05 19:18:07 +02001685 pause_result |= (lp_pause &
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001686 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7;
Yaniv Rosner7846e472009-11-05 19:18:07 +02001687 DP(NETIF_MSG_LINK, "pause_result CL37 0x%x\n",
1688 pause_result);
1689 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001690 bnx2x_pause_resolve(vars, pause_result);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001691 }
1692 DP(NETIF_MSG_LINK, "flow_ctrl 0x%x\n", vars->flow_ctrl);
1693}
1694
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001695static void bnx2x_check_fallback_to_cl37(struct bnx2x_phy *phy,
1696 struct link_params *params)
Eilon Greenstein239d6862009-08-12 08:23:04 +00001697{
1698 struct bnx2x *bp = params->bp;
1699 u16 rx_status, ustat_val, cl37_fsm_recieved;
1700 DP(NETIF_MSG_LINK, "bnx2x_check_fallback_to_cl37\n");
1701 /* Step 1: Make sure signal is detected */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001702 CL45_RD_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001703 MDIO_REG_BANK_RX0,
1704 MDIO_RX0_RX_STATUS,
1705 &rx_status);
1706 if ((rx_status & MDIO_RX0_RX_STATUS_SIGDET) !=
1707 (MDIO_RX0_RX_STATUS_SIGDET)) {
1708 DP(NETIF_MSG_LINK, "Signal is not detected. Restoring CL73."
1709 "rx_status(0x80b0) = 0x%x\n", rx_status);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001710 CL45_WR_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001711 MDIO_REG_BANK_CL73_IEEEB0,
1712 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1713 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN);
1714 return;
1715 }
1716 /* Step 2: Check CL73 state machine */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001717 CL45_RD_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001718 MDIO_REG_BANK_CL73_USERB0,
1719 MDIO_CL73_USERB0_CL73_USTAT1,
1720 &ustat_val);
1721 if ((ustat_val &
1722 (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK |
1723 MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) !=
1724 (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK |
1725 MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) {
1726 DP(NETIF_MSG_LINK, "CL73 state-machine is not stable. "
1727 "ustat_val(0x8371) = 0x%x\n", ustat_val);
1728 return;
1729 }
1730 /* Step 3: Check CL37 Message Pages received to indicate LP
1731 supports only CL37 */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001732 CL45_RD_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001733 MDIO_REG_BANK_REMOTE_PHY,
1734 MDIO_REMOTE_PHY_MISC_RX_STATUS,
1735 &cl37_fsm_recieved);
1736 if ((cl37_fsm_recieved &
1737 (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG |
1738 MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) !=
1739 (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG |
1740 MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) {
1741 DP(NETIF_MSG_LINK, "No CL37 FSM were received. "
1742 "misc_rx_status(0x8330) = 0x%x\n",
1743 cl37_fsm_recieved);
1744 return;
1745 }
1746 /* The combined cl37/cl73 fsm state information indicating that we are
1747 connected to a device which does not support cl73, but does support
1748 cl37 BAM. In this case we disable cl73 and restart cl37 auto-neg */
1749 /* Disable CL73 */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001750 CL45_WR_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001751 MDIO_REG_BANK_CL73_IEEEB0,
1752 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1753 0);
1754 /* Restart CL37 autoneg */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001755 bnx2x_restart_autoneg(phy, params, 0);
Eilon Greenstein239d6862009-08-12 08:23:04 +00001756 DP(NETIF_MSG_LINK, "Disabling CL73, and restarting CL37 autoneg\n");
1757}
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001758
1759static void bnx2x_xgxs_an_resolve(struct bnx2x_phy *phy,
1760 struct link_params *params,
1761 struct link_vars *vars,
1762 u32 gp_status)
1763{
1764 if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE)
1765 vars->link_status |=
1766 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
1767
1768 if (bnx2x_direct_parallel_detect_used(phy, params))
1769 vars->link_status |=
1770 LINK_STATUS_PARALLEL_DETECTION_USED;
1771}
1772
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00001773static u8 bnx2x_link_settings_status(struct bnx2x_phy *phy,
1774 struct link_params *params,
1775 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001776{
1777 struct bnx2x *bp = params->bp;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00001778 u16 new_line_speed , gp_status;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001779 u8 rc = 0;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001780 u32 ext_phy_type;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00001781 /* Read gp_status */
1782 CL45_RD_OVER_CL22(bp, phy,
1783 MDIO_REG_BANK_GP_STATUS,
1784 MDIO_GP_STATUS_TOP_AN_STATUS1,
1785 &gp_status);
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001786 if (phy->req_line_speed == SPEED_AUTO_NEG)
1787 vars->link_status |= LINK_STATUS_AUTO_NEGOTIATE_ENABLED;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001788 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) {
1789 DP(NETIF_MSG_LINK, "phy link up gp_status=0x%x\n",
1790 gp_status);
1791
1792 vars->phy_link_up = 1;
1793 vars->link_status |= LINK_STATUS_LINK_UP;
1794
1795 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_DUPLEX_STATUS)
1796 vars->duplex = DUPLEX_FULL;
1797 else
1798 vars->duplex = DUPLEX_HALF;
1799
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001800 if (SINGLE_MEDIA_DIRECT(params)) {
1801 bnx2x_flow_ctrl_resolve(phy, params, vars, gp_status);
1802 if (phy->req_line_speed == SPEED_AUTO_NEG)
1803 bnx2x_xgxs_an_resolve(phy, params, vars,
1804 gp_status);
1805 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001806
1807 switch (gp_status & GP_STATUS_SPEED_MASK) {
1808 case GP_STATUS_10M:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001809 new_line_speed = SPEED_10;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001810 if (vars->duplex == DUPLEX_FULL)
1811 vars->link_status |= LINK_10TFD;
1812 else
1813 vars->link_status |= LINK_10THD;
1814 break;
1815
1816 case GP_STATUS_100M:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001817 new_line_speed = SPEED_100;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001818 if (vars->duplex == DUPLEX_FULL)
1819 vars->link_status |= LINK_100TXFD;
1820 else
1821 vars->link_status |= LINK_100TXHD;
1822 break;
1823
1824 case GP_STATUS_1G:
1825 case GP_STATUS_1G_KX:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001826 new_line_speed = SPEED_1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001827 if (vars->duplex == DUPLEX_FULL)
1828 vars->link_status |= LINK_1000TFD;
1829 else
1830 vars->link_status |= LINK_1000THD;
1831 break;
1832
1833 case GP_STATUS_2_5G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001834 new_line_speed = SPEED_2500;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001835 if (vars->duplex == DUPLEX_FULL)
1836 vars->link_status |= LINK_2500TFD;
1837 else
1838 vars->link_status |= LINK_2500THD;
1839 break;
1840
1841 case GP_STATUS_5G:
1842 case GP_STATUS_6G:
1843 DP(NETIF_MSG_LINK,
1844 "link speed unsupported gp_status 0x%x\n",
1845 gp_status);
1846 return -EINVAL;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00001847
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001848 case GP_STATUS_10G_KX4:
1849 case GP_STATUS_10G_HIG:
1850 case GP_STATUS_10G_CX4:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001851 new_line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001852 vars->link_status |= LINK_10GTFD;
1853 break;
1854
1855 case GP_STATUS_12G_HIG:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001856 new_line_speed = SPEED_12000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001857 vars->link_status |= LINK_12GTFD;
1858 break;
1859
1860 case GP_STATUS_12_5G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001861 new_line_speed = SPEED_12500;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001862 vars->link_status |= LINK_12_5GTFD;
1863 break;
1864
1865 case GP_STATUS_13G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001866 new_line_speed = SPEED_13000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001867 vars->link_status |= LINK_13GTFD;
1868 break;
1869
1870 case GP_STATUS_15G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001871 new_line_speed = SPEED_15000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001872 vars->link_status |= LINK_15GTFD;
1873 break;
1874
1875 case GP_STATUS_16G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001876 new_line_speed = SPEED_16000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001877 vars->link_status |= LINK_16GTFD;
1878 break;
1879
1880 default:
1881 DP(NETIF_MSG_LINK,
1882 "link speed unsupported gp_status 0x%x\n",
1883 gp_status);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00001884 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001885 }
1886
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001887 vars->line_speed = new_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001888 vars->link_status |= LINK_STATUS_SERDES_LINK;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001889 ext_phy_type = params->phy[EXT_PHY1].type;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07001890 if ((params->req_line_speed == SPEED_AUTO_NEG) &&
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001891 ((ext_phy_type ==
Yaniv Rosner57963ed2008-08-13 15:55:28 -07001892 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ||
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001893 (ext_phy_type ==
Eilon Greenstein589abe32009-02-12 08:36:55 +00001894 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) ||
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001895 (ext_phy_type ==
Yaniv Rosnerb5bbf002009-11-05 19:18:21 +02001896 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706) ||
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001897 (ext_phy_type ==
Eilon Greenstein2f904462009-08-12 08:22:16 +00001898 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001899 vars->autoneg = AUTO_NEG_ENABLED;
1900
1901 if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) {
1902 vars->autoneg |= AUTO_NEG_COMPLETE;
1903 vars->link_status |=
1904 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
1905 }
1906
1907 vars->autoneg |= AUTO_NEG_PARALLEL_DETECTION_USED;
1908 vars->link_status |=
1909 LINK_STATUS_PARALLEL_DETECTION_USED;
1910
1911 }
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001912
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001913 } else { /* link_down */
1914 DP(NETIF_MSG_LINK, "phy link down\n");
1915
1916 vars->phy_link_up = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07001917
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001918 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08001919 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001920 vars->autoneg = AUTO_NEG_DISABLED;
1921 vars->mac_type = MAC_TYPE_NONE;
Eilon Greenstein239d6862009-08-12 08:23:04 +00001922
1923 if ((params->req_line_speed == SPEED_AUTO_NEG) &&
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001924 (SINGLE_MEDIA_DIRECT(params))) {
Eilon Greenstein239d6862009-08-12 08:23:04 +00001925 /* Check signal is detected */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001926 bnx2x_check_fallback_to_cl37(&params->phy[INT_PHY],
1927 params);
Eilon Greenstein239d6862009-08-12 08:23:04 +00001928 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001929 }
1930
Frans Pop2381a552010-03-24 07:57:36 +00001931 DP(NETIF_MSG_LINK, "gp_status 0x%x phy_link_up %x line_speed %x\n",
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001932 gp_status, vars->phy_link_up, vars->line_speed);
1933 DP(NETIF_MSG_LINK, "duplex %x flow_ctrl 0x%x"
1934 " autoneg 0x%x\n",
1935 vars->duplex,
1936 vars->flow_ctrl, vars->autoneg);
1937 DP(NETIF_MSG_LINK, "link_status 0x%x\n", vars->link_status);
1938
1939 return rc;
1940}
1941
Eilon Greensteined8680a2009-02-12 08:37:12 +00001942static void bnx2x_set_gmii_tx_driver(struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001943{
1944 struct bnx2x *bp = params->bp;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001945 struct bnx2x_phy *phy = &params->phy[INT_PHY];
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001946 u16 lp_up2;
1947 u16 tx_driver;
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00001948 u16 bank;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001949
1950 /* read precomp */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001951 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001952 MDIO_REG_BANK_OVER_1G,
1953 MDIO_OVER_1G_LP_UP2, &lp_up2);
1954
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001955 /* bits [10:7] at lp_up2, positioned at [15:12] */
1956 lp_up2 = (((lp_up2 & MDIO_OVER_1G_LP_UP2_PREEMPHASIS_MASK) >>
1957 MDIO_OVER_1G_LP_UP2_PREEMPHASIS_SHIFT) <<
1958 MDIO_TX0_TX_DRIVER_PREEMPHASIS_SHIFT);
1959
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00001960 if (lp_up2 == 0)
1961 return;
1962
1963 for (bank = MDIO_REG_BANK_TX0; bank <= MDIO_REG_BANK_TX3;
1964 bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0)) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001965 CL45_RD_OVER_CL22(bp, phy,
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00001966 bank,
1967 MDIO_TX0_TX_DRIVER, &tx_driver);
1968
1969 /* replace tx_driver bits [15:12] */
1970 if (lp_up2 !=
1971 (tx_driver & MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK)) {
1972 tx_driver &= ~MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK;
1973 tx_driver |= lp_up2;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001974 CL45_WR_OVER_CL22(bp, phy,
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00001975 bank,
1976 MDIO_TX0_TX_DRIVER, tx_driver);
1977 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001978 }
1979}
1980
1981static u8 bnx2x_emac_program(struct link_params *params,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00001982 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001983{
1984 struct bnx2x *bp = params->bp;
1985 u8 port = params->port;
1986 u16 mode = 0;
1987
1988 DP(NETIF_MSG_LINK, "setting link speed & duplex\n");
1989 bnx2x_bits_dis(bp, GRCBASE_EMAC0 + port*0x400 +
1990 EMAC_REG_EMAC_MODE,
1991 (EMAC_MODE_25G_MODE |
1992 EMAC_MODE_PORT_MII_10M |
1993 EMAC_MODE_HALF_DUPLEX));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00001994 switch (vars->line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001995 case SPEED_10:
1996 mode |= EMAC_MODE_PORT_MII_10M;
1997 break;
1998
1999 case SPEED_100:
2000 mode |= EMAC_MODE_PORT_MII;
2001 break;
2002
2003 case SPEED_1000:
2004 mode |= EMAC_MODE_PORT_GMII;
2005 break;
2006
2007 case SPEED_2500:
2008 mode |= (EMAC_MODE_25G_MODE | EMAC_MODE_PORT_GMII);
2009 break;
2010
2011 default:
2012 /* 10G not valid for EMAC */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002013 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
2014 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002015 return -EINVAL;
2016 }
2017
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002018 if (vars->duplex == DUPLEX_HALF)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002019 mode |= EMAC_MODE_HALF_DUPLEX;
2020 bnx2x_bits_en(bp,
2021 GRCBASE_EMAC0 + port*0x400 + EMAC_REG_EMAC_MODE,
2022 mode);
2023
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002024 bnx2x_set_led(params, LED_MODE_OPER, vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002025 return 0;
2026}
2027
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002028static u8 bnx2x_init_serdes(struct bnx2x_phy *phy,
2029 struct link_params *params,
2030 struct link_vars *vars)
2031{
2032 u8 rc;
2033 vars->phy_flags |= PHY_SGMII_FLAG;
2034 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
2035 bnx2x_set_aer_mmd(params, phy);
2036 rc = bnx2x_reset_unicore(params, phy, 1);
2037 /* reset the SerDes and wait for reset bit return low */
2038 if (rc != 0)
2039 return rc;
2040 bnx2x_set_aer_mmd(params, phy);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002041
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002042 return rc;
2043}
2044
2045static u8 bnx2x_init_xgxs(struct bnx2x_phy *phy,
2046 struct link_params *params,
2047 struct link_vars *vars)
2048{
2049 u8 rc;
2050 vars->phy_flags = PHY_XGXS_FLAG;
2051 if ((phy->req_line_speed &&
2052 ((phy->req_line_speed == SPEED_100) ||
2053 (phy->req_line_speed == SPEED_10))) ||
2054 (!phy->req_line_speed &&
2055 (phy->speed_cap_mask >=
2056 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL) &&
2057 (phy->speed_cap_mask <
2058 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
2059 ))
2060 vars->phy_flags |= PHY_SGMII_FLAG;
2061 else
2062 vars->phy_flags &= ~PHY_SGMII_FLAG;
2063
2064 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
2065 bnx2x_set_aer_mmd(params, phy);
2066 bnx2x_set_master_ln(params, phy);
2067
2068 rc = bnx2x_reset_unicore(params, phy, 0);
2069 /* reset the SerDes and wait for reset bit return low */
2070 if (rc != 0)
2071 return rc;
2072
2073 bnx2x_set_aer_mmd(params, phy);
2074
2075 /* setting the masterLn_def again after the reset */
2076 bnx2x_set_master_ln(params, phy);
2077 bnx2x_set_swap_lanes(params, phy);
2078
2079 return rc;
2080}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002081/*****************************************************************************/
Eilon Greenstein17de50b2008-08-13 15:56:59 -07002082/* External Phy section */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002083/*****************************************************************************/
Eilon Greensteinf57a6022009-08-12 08:23:11 +00002084void bnx2x_ext_phy_hw_reset(struct bnx2x *bp, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002085{
2086 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07002087 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002088 msleep(1);
2089 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002090 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002091}
2092
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002093static void bnx2x_save_spirom_version(struct bnx2x *bp, u8 port,
2094 u32 shmem_base, u32 spirom_ver)
2095{
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002096 DP(NETIF_MSG_LINK, "FW version 0x%x:0x%x for port %d\n",
2097 (u16)(spirom_ver>>16), (u16)spirom_ver, port);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002098 REG_WR(bp, shmem_base +
2099 offsetof(struct shmem_region,
2100 port_mb[port].ext_phy_fw_version),
2101 spirom_ver);
2102}
2103
2104static void bnx2x_save_bcm_spirom_ver(struct bnx2x *bp, u8 port,
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002105 struct bnx2x_phy *phy,
2106 u32 shmem_base)
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002107{
2108 u16 fw_ver1, fw_ver2;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002109
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002110 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002111 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002112 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002113 MDIO_PMA_REG_ROM_VER2, &fw_ver2);
2114 bnx2x_save_spirom_version(bp, port, shmem_base,
2115 (u32)(fw_ver1<<16 | fw_ver2));
2116}
2117
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002118static void bnx2x_save_8481_spirom_version(struct bnx2x_phy *phy,
2119 struct link_params *params,
2120 u32 shmem_base)
Eilon Greensteinb1607af2009-08-12 08:22:54 +00002121{
2122 u16 val, fw_ver1, fw_ver2, cnt;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002123 struct bnx2x *bp = params->bp;
2124
2125 /* For the 32 bits registers in 848xx, access via MDIO2ARM interface.*/
Eilon Greensteinb1607af2009-08-12 08:22:54 +00002126 /* (1) set register 0xc200_0014(SPI_BRIDGE_CTRL_2) to 0x03000000 */
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002127 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0014);
2128 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200);
2129 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81B, 0x0000);
2130 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81C, 0x0300);
2131 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x0009);
Eilon Greensteinb1607af2009-08-12 08:22:54 +00002132
2133 for (cnt = 0; cnt < 100; cnt++) {
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002134 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val);
Eilon Greensteinb1607af2009-08-12 08:22:54 +00002135 if (val & 1)
2136 break;
2137 udelay(5);
2138 }
2139 if (cnt == 100) {
2140 DP(NETIF_MSG_LINK, "Unable to read 8481 phy fw version(1)\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002141 bnx2x_save_spirom_version(bp, params->port,
Eilon Greensteinb1607af2009-08-12 08:22:54 +00002142 shmem_base, 0);
2143 return;
2144 }
2145
2146
2147 /* 2) read register 0xc200_0000 (SPI_FW_STATUS) */
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002148 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0000);
2149 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200);
2150 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x000A);
Eilon Greensteinb1607af2009-08-12 08:22:54 +00002151 for (cnt = 0; cnt < 100; cnt++) {
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002152 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val);
Eilon Greensteinb1607af2009-08-12 08:22:54 +00002153 if (val & 1)
2154 break;
2155 udelay(5);
2156 }
2157 if (cnt == 100) {
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002158 DP(NETIF_MSG_LINK, "Unable to read 848xx phy fw version(2)\n");
2159 bnx2x_save_spirom_version(bp, params->port, 0,
2160 phy->ver_addr);
Eilon Greensteinb1607af2009-08-12 08:22:54 +00002161 return;
2162 }
2163
2164 /* lower 16 bits of the register SPI_FW_STATUS */
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002165 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81B, &fw_ver1);
Eilon Greensteinb1607af2009-08-12 08:22:54 +00002166 /* upper 16 bits of register SPI_FW_STATUS */
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002167 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81C, &fw_ver2);
Eilon Greensteinb1607af2009-08-12 08:22:54 +00002168
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002169 bnx2x_save_spirom_version(bp, params->port, (fw_ver2<<16) | fw_ver1,
2170 phy->ver_addr);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002171}
2172
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002173static u8 bnx2x_8073_is_snr_needed(struct bnx2x *bp, struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002174{
2175 /* This is only required for 8073A1, version 102 only */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002176 u16 val;
2177
2178 /* Read 8073 HW revision*/
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002179 bnx2x_cl45_read(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002180 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00002181 MDIO_PMA_REG_8073_CHIP_REV, &val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002182
2183 if (val != 1) {
2184 /* No need to workaround in 8073 A1 */
2185 return 0;
2186 }
2187
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002188 bnx2x_cl45_read(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002189 MDIO_PMA_DEVAD,
2190 MDIO_PMA_REG_ROM_VER2, &val);
2191
2192 /* SNR should be applied only for version 0x102 */
2193 if (val != 0x102)
2194 return 0;
2195
2196 return 1;
2197}
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002198static u8 bnx2x_8073_xaui_wa(struct bnx2x *bp, struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002199{
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002200 u16 val, cnt, cnt1 ;
2201
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002202 bnx2x_cl45_read(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002203 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00002204 MDIO_PMA_REG_8073_CHIP_REV, &val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002205
2206 if (val > 0) {
2207 /* No need to workaround in 8073 A1 */
2208 return 0;
2209 }
2210 /* XAUI workaround in 8073 A0: */
2211
2212 /* After loading the boot ROM and restarting Autoneg,
2213 poll Dev1, Reg $C820: */
2214
2215 for (cnt = 0; cnt < 1000; cnt++) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002216 bnx2x_cl45_read(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002217 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00002218 MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
2219 &val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002220 /* If bit [14] = 0 or bit [13] = 0, continue on with
2221 system initialization (XAUI work-around not required,
2222 as these bits indicate 2.5G or 1G link up). */
2223 if (!(val & (1<<14)) || !(val & (1<<13))) {
2224 DP(NETIF_MSG_LINK, "XAUI work-around not required\n");
2225 return 0;
2226 } else if (!(val & (1<<15))) {
2227 DP(NETIF_MSG_LINK, "clc bit 15 went off\n");
2228 /* If bit 15 is 0, then poll Dev1, Reg $C841 until
2229 it's MSB (bit 15) goes to 1 (indicating that the
2230 XAUI workaround has completed),
2231 then continue on with system initialization.*/
2232 for (cnt1 = 0; cnt1 < 1000; cnt1++) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002233 bnx2x_cl45_read(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002234 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00002235 MDIO_PMA_REG_8073_XAUI_WA, &val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002236 if (val & (1<<15)) {
2237 DP(NETIF_MSG_LINK,
2238 "XAUI workaround has completed\n");
2239 return 0;
2240 }
2241 msleep(3);
2242 }
2243 break;
2244 }
2245 msleep(3);
2246 }
2247 DP(NETIF_MSG_LINK, "Warning: XAUI work-around timeout !!!\n");
2248 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002249}
2250
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002251static void bnx2x_8073_8727_external_rom_boot(struct bnx2x *bp,
2252 struct bnx2x_phy *phy,
2253 u8 port, u32 shmem_base)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002254{
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002255 /* Boot port from external ROM */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002256 /* EDC grst */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002257 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002258 MDIO_PMA_DEVAD,
2259 MDIO_PMA_REG_GEN_CTRL,
2260 0x0001);
2261
2262 /* ucode reboot and rst */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002263 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002264 MDIO_PMA_DEVAD,
2265 MDIO_PMA_REG_GEN_CTRL,
2266 0x008c);
2267
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002268 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002269 MDIO_PMA_DEVAD,
2270 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
2271
2272 /* Reset internal microprocessor */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002273 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002274 MDIO_PMA_DEVAD,
2275 MDIO_PMA_REG_GEN_CTRL,
2276 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
2277
2278 /* Release srst bit */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002279 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002280 MDIO_PMA_DEVAD,
2281 MDIO_PMA_REG_GEN_CTRL,
2282 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2283
Yaniv Rosner8ca60a62010-09-01 09:51:17 +00002284 /* wait for 120ms for code download via SPI port */
2285 msleep(120);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002286
2287 /* Clear ser_boot_ctl bit */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002288 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002289 MDIO_PMA_DEVAD,
2290 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002291 bnx2x_save_bcm_spirom_ver(bp, port, phy, shmem_base);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002292}
2293
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002294static void bnx2x_8726_external_rom_boot(struct bnx2x_phy *phy,
2295 struct link_params *params)
Eilon Greenstein589abe32009-02-12 08:36:55 +00002296{
2297 struct bnx2x *bp = params->bp;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002298 /* Need to wait 100ms after reset */
2299 msleep(100);
2300
Eilon Greenstein589abe32009-02-12 08:36:55 +00002301 /* Micro controller re-boot */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002302 bnx2x_cl45_write(bp, phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002303 MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, 0x018B);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002304
2305 /* Set soft reset */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002306 bnx2x_cl45_write(bp, phy,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002307 MDIO_PMA_DEVAD,
2308 MDIO_PMA_REG_GEN_CTRL,
2309 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
2310
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002311 bnx2x_cl45_write(bp, phy,
Eilon Greensteincc1cb002009-03-02 08:00:03 +00002312 MDIO_PMA_DEVAD,
Yaniv Rosner93f72882009-11-05 19:18:26 +02002313 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
Eilon Greensteincc1cb002009-03-02 08:00:03 +00002314
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002315 bnx2x_cl45_write(bp, phy,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002316 MDIO_PMA_DEVAD,
2317 MDIO_PMA_REG_GEN_CTRL,
2318 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2319
Eilon Greensteincc1cb002009-03-02 08:00:03 +00002320 /* wait for 150ms for microcode load */
2321 msleep(150);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002322
2323 /* Disable serial boot control, tristates pins SS_N, SCK, MOSI, MISO */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002324 bnx2x_cl45_write(bp, phy,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002325 MDIO_PMA_DEVAD,
2326 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
2327
2328 msleep(200);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002329 bnx2x_save_bcm_spirom_ver(bp, params->port,
2330 phy,
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002331 params->shmem_base);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002332}
2333
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002334static void bnx2x_sfp_set_transmitter(struct bnx2x *bp,
2335 struct bnx2x_phy *phy,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002336 u8 port,
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002337 u8 tx_en)
Eilon Greenstein589abe32009-02-12 08:36:55 +00002338{
2339 u16 val;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002340
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002341 DP(NETIF_MSG_LINK, "Setting transmitter tx_en=%x for port %x\n",
2342 tx_en, port);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002343 /* Disable/Enable transmitter ( TX laser of the SFP+ module.)*/
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002344 bnx2x_cl45_read(bp, phy,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002345 MDIO_PMA_DEVAD,
2346 MDIO_PMA_REG_PHY_IDENTIFIER,
2347 &val);
2348
2349 if (tx_en)
2350 val &= ~(1<<15);
2351 else
2352 val |= (1<<15);
2353
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002354 bnx2x_cl45_write(bp, phy,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002355 MDIO_PMA_DEVAD,
2356 MDIO_PMA_REG_PHY_IDENTIFIER,
2357 val);
2358}
2359
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002360static u8 bnx2x_8726_read_sfp_module_eeprom(struct bnx2x_phy *phy,
2361 struct link_params *params,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002362 u16 addr, u8 byte_cnt, u8 *o_buf)
2363{
Eilon Greenstein589abe32009-02-12 08:36:55 +00002364 struct bnx2x *bp = params->bp;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002365 u16 val = 0;
2366 u16 i;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002367 if (byte_cnt > 16) {
2368 DP(NETIF_MSG_LINK, "Reading from eeprom is"
2369 " is limited to 0xf\n");
2370 return -EINVAL;
2371 }
2372 /* Set the read command byte count */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002373 bnx2x_cl45_write(bp, phy,
2374 MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002375 (byte_cnt | 0xa000));
2376
2377 /* Set the read command address */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002378 bnx2x_cl45_write(bp, phy,
2379 MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002380 addr);
2381
2382 /* Activate read command */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002383 bnx2x_cl45_write(bp, phy,
2384 MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002385 0x2c0f);
2386
2387 /* Wait up to 500us for command complete status */
2388 for (i = 0; i < 100; i++) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002389 bnx2x_cl45_read(bp, phy,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002390 MDIO_PMA_DEVAD,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002391 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
2392 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
2393 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
Eilon Greenstein589abe32009-02-12 08:36:55 +00002394 break;
2395 udelay(5);
2396 }
2397
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002398 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
2399 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
Eilon Greenstein589abe32009-02-12 08:36:55 +00002400 DP(NETIF_MSG_LINK,
2401 "Got bad status 0x%x when reading from SFP+ EEPROM\n",
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002402 (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
Eilon Greenstein589abe32009-02-12 08:36:55 +00002403 return -EINVAL;
2404 }
2405
2406 /* Read the buffer */
2407 for (i = 0; i < byte_cnt; i++) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002408 bnx2x_cl45_read(bp, phy,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002409 MDIO_PMA_DEVAD,
2410 MDIO_PMA_REG_8726_TWO_WIRE_DATA_BUF + i, &val);
2411 o_buf[i] = (u8)(val & MDIO_PMA_REG_8726_TWO_WIRE_DATA_MASK);
2412 }
2413
2414 for (i = 0; i < 100; i++) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002415 bnx2x_cl45_read(bp, phy,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002416 MDIO_PMA_DEVAD,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002417 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
2418 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
2419 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002420 return 0;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002421 msleep(1);
2422 }
2423 return -EINVAL;
2424}
2425
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002426static u8 bnx2x_8727_read_sfp_module_eeprom(struct bnx2x_phy *phy,
2427 struct link_params *params,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002428 u16 addr, u8 byte_cnt, u8 *o_buf)
Eilon Greenstein589abe32009-02-12 08:36:55 +00002429{
2430 struct bnx2x *bp = params->bp;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002431 u16 val, i;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002432
2433 if (byte_cnt > 16) {
2434 DP(NETIF_MSG_LINK, "Reading from eeprom is"
2435 " is limited to 0xf\n");
2436 return -EINVAL;
2437 }
2438
2439 /* Need to read from 1.8000 to clear it */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002440 bnx2x_cl45_read(bp, phy,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002441 MDIO_PMA_DEVAD,
2442 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
2443 &val);
2444
2445 /* Set the read command byte count */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002446 bnx2x_cl45_write(bp, phy,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002447 MDIO_PMA_DEVAD,
2448 MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
2449 ((byte_cnt < 2) ? 2 : byte_cnt));
2450
2451 /* Set the read command address */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002452 bnx2x_cl45_write(bp, phy,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002453 MDIO_PMA_DEVAD,
2454 MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
2455 addr);
2456 /* Set the destination address */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002457 bnx2x_cl45_write(bp, phy,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002458 MDIO_PMA_DEVAD,
2459 0x8004,
2460 MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF);
2461
2462 /* Activate read command */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002463 bnx2x_cl45_write(bp, phy,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002464 MDIO_PMA_DEVAD,
2465 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
2466 0x8002);
2467 /* Wait appropriate time for two-wire command to finish before
2468 polling the status register */
2469 msleep(1);
2470
2471 /* Wait up to 500us for command complete status */
2472 for (i = 0; i < 100; i++) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002473 bnx2x_cl45_read(bp, phy,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002474 MDIO_PMA_DEVAD,
2475 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
2476 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
2477 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
2478 break;
2479 udelay(5);
2480 }
2481
2482 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
2483 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
2484 DP(NETIF_MSG_LINK,
2485 "Got bad status 0x%x when reading from SFP+ EEPROM\n",
2486 (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
2487 return -EINVAL;
2488 }
2489
2490 /* Read the buffer */
2491 for (i = 0; i < byte_cnt; i++) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002492 bnx2x_cl45_read(bp, phy,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002493 MDIO_PMA_DEVAD,
2494 MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF + i, &val);
2495 o_buf[i] = (u8)(val & MDIO_PMA_REG_8727_TWO_WIRE_DATA_MASK);
2496 }
2497
2498 for (i = 0; i < 100; i++) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002499 bnx2x_cl45_read(bp, phy,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002500 MDIO_PMA_DEVAD,
2501 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
2502 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
2503 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
2504 return 0;;
2505 msleep(1);
2506 }
2507
2508 return -EINVAL;
2509}
2510
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002511u8 bnx2x_read_sfp_module_eeprom(struct bnx2x_phy *phy,
2512 struct link_params *params, u16 addr,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002513 u8 byte_cnt, u8 *o_buf)
2514{
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002515 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
2516 return bnx2x_8726_read_sfp_module_eeprom(phy, params, addr,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002517 byte_cnt, o_buf);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002518 else if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
2519 return bnx2x_8727_read_sfp_module_eeprom(phy, params, addr,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002520 byte_cnt, o_buf);
2521 return -EINVAL;
2522}
2523
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002524static u8 bnx2x_get_edc_mode(struct bnx2x_phy *phy,
2525 struct link_params *params,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002526 u16 *edc_mode)
2527{
2528 struct bnx2x *bp = params->bp;
2529 u8 val, check_limiting_mode = 0;
2530 *edc_mode = EDC_MODE_LIMITING;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002531
2532 /* First check for copper cable */
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002533 if (bnx2x_read_sfp_module_eeprom(phy,
2534 params,
2535 SFP_EEPROM_CON_TYPE_ADDR,
2536 1,
2537 &val) != 0) {
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002538 DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM\n");
Eilon Greenstein589abe32009-02-12 08:36:55 +00002539 return -EINVAL;
2540 }
2541
2542 switch (val) {
2543 case SFP_EEPROM_CON_TYPE_VAL_COPPER:
2544 {
2545 u8 copper_module_type;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002546
Eilon Greenstein589abe32009-02-12 08:36:55 +00002547 /* Check if its active cable( includes SFP+ module)
2548 of passive cable*/
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002549 if (bnx2x_read_sfp_module_eeprom(phy,
2550 params,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002551 SFP_EEPROM_FC_TX_TECH_ADDR,
2552 1,
2553 &copper_module_type) !=
2554 0) {
2555 DP(NETIF_MSG_LINK,
2556 "Failed to read copper-cable-type"
2557 " from SFP+ EEPROM\n");
2558 return -EINVAL;
2559 }
2560
2561 if (copper_module_type &
2562 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE) {
2563 DP(NETIF_MSG_LINK, "Active Copper cable detected\n");
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002564 check_limiting_mode = 1;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002565 } else if (copper_module_type &
2566 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE) {
2567 DP(NETIF_MSG_LINK, "Passive Copper"
2568 " cable detected\n");
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002569 *edc_mode =
2570 EDC_MODE_PASSIVE_DAC;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002571 } else {
2572 DP(NETIF_MSG_LINK, "Unknown copper-cable-"
2573 "type 0x%x !!!\n", copper_module_type);
2574 return -EINVAL;
2575 }
2576 break;
2577 }
2578 case SFP_EEPROM_CON_TYPE_VAL_LC:
2579 DP(NETIF_MSG_LINK, "Optic module detected\n");
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002580 check_limiting_mode = 1;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002581 break;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002582 default:
2583 DP(NETIF_MSG_LINK, "Unable to determine module type 0x%x !!!\n",
2584 val);
2585 return -EINVAL;
2586 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002587
2588 if (check_limiting_mode) {
2589 u8 options[SFP_EEPROM_OPTIONS_SIZE];
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002590 if (bnx2x_read_sfp_module_eeprom(phy,
2591 params,
2592 SFP_EEPROM_OPTIONS_ADDR,
2593 SFP_EEPROM_OPTIONS_SIZE,
2594 options) != 0) {
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002595 DP(NETIF_MSG_LINK, "Failed to read Option"
2596 " field from module EEPROM\n");
2597 return -EINVAL;
2598 }
2599 if ((options[0] & SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK))
2600 *edc_mode = EDC_MODE_LINEAR;
2601 else
2602 *edc_mode = EDC_MODE_LIMITING;
2603 }
2604 DP(NETIF_MSG_LINK, "EDC mode is set to 0x%x\n", *edc_mode);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002605 return 0;
2606}
Eilon Greenstein589abe32009-02-12 08:36:55 +00002607/* This function read the relevant field from the module ( SFP+ ),
2608 and verify it is compliant with this board */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002609static u8 bnx2x_verify_sfp_module(struct bnx2x_phy *phy,
2610 struct link_params *params)
Eilon Greenstein589abe32009-02-12 08:36:55 +00002611{
2612 struct bnx2x *bp = params->bp;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002613 u32 val;
2614 u32 fw_resp;
2615 char vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE+1];
2616 char vendor_pn[SFP_EEPROM_PART_NO_SIZE+1];
Eilon Greenstein589abe32009-02-12 08:36:55 +00002617
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002618 val = REG_RD(bp, params->shmem_base +
2619 offsetof(struct shmem_region, dev_info.
2620 port_feature_config[params->port].config));
2621 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
2622 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_NO_ENFORCEMENT) {
Eilon Greenstein589abe32009-02-12 08:36:55 +00002623 DP(NETIF_MSG_LINK, "NOT enforcing module verification\n");
2624 return 0;
2625 }
2626
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002627 /* Ask the FW to validate the module */
2628 if (!(params->feature_config_flags &
2629 FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY)) {
2630 DP(NETIF_MSG_LINK, "FW does not support OPT MDL "
2631 "verification\n");
2632 return -EINVAL;
2633 }
2634
2635 fw_resp = bnx2x_fw_command(bp, DRV_MSG_CODE_VRFY_OPT_MDL);
2636 if (fw_resp == FW_MSG_CODE_VRFY_OPT_MDL_SUCCESS) {
2637 DP(NETIF_MSG_LINK, "Approved module\n");
Eilon Greenstein589abe32009-02-12 08:36:55 +00002638 return 0;
2639 }
2640
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002641 /* format the warning message */
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002642 if (bnx2x_read_sfp_module_eeprom(phy,
2643 params,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002644 SFP_EEPROM_VENDOR_NAME_ADDR,
2645 SFP_EEPROM_VENDOR_NAME_SIZE,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002646 (u8 *)vendor_name))
2647 vendor_name[0] = '\0';
2648 else
2649 vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE] = '\0';
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002650 if (bnx2x_read_sfp_module_eeprom(phy,
2651 params,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002652 SFP_EEPROM_PART_NO_ADDR,
2653 SFP_EEPROM_PART_NO_SIZE,
2654 (u8 *)vendor_pn))
2655 vendor_pn[0] = '\0';
2656 else
2657 vendor_pn[SFP_EEPROM_PART_NO_SIZE] = '\0';
Eilon Greenstein589abe32009-02-12 08:36:55 +00002658
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002659 netdev_info(bp->dev, "Warning: Unqualified SFP+ module detected,"
2660 " Port %d from %s part number %s\n",
Joe Perches7995c642010-02-17 15:01:52 +00002661 params->port, vendor_name, vendor_pn);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002662 return -EINVAL;
2663}
2664
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002665static u8 bnx2x_8726_set_limiting_mode(struct bnx2x *bp,
2666 struct bnx2x_phy *phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002667 u16 edc_mode)
Eilon Greenstein589abe32009-02-12 08:36:55 +00002668{
Eilon Greensteincc1cb002009-03-02 08:00:03 +00002669 u16 cur_limiting_mode;
Eilon Greensteincc1cb002009-03-02 08:00:03 +00002670
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002671 bnx2x_cl45_read(bp, phy,
Eilon Greensteincc1cb002009-03-02 08:00:03 +00002672 MDIO_PMA_DEVAD,
2673 MDIO_PMA_REG_ROM_VER2,
2674 &cur_limiting_mode);
2675 DP(NETIF_MSG_LINK, "Current Limiting mode is 0x%x\n",
2676 cur_limiting_mode);
2677
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002678 if (edc_mode == EDC_MODE_LIMITING) {
Eilon Greenstein589abe32009-02-12 08:36:55 +00002679 DP(NETIF_MSG_LINK,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002680 "Setting LIMITING MODE\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002681 bnx2x_cl45_write(bp, phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002682 MDIO_PMA_DEVAD,
2683 MDIO_PMA_REG_ROM_VER2,
2684 EDC_MODE_LIMITING);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002685 } else { /* LRM mode ( default )*/
Eilon Greensteincc1cb002009-03-02 08:00:03 +00002686
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002687 DP(NETIF_MSG_LINK, "Setting LRM MODE\n");
Eilon Greenstein589abe32009-02-12 08:36:55 +00002688
Eilon Greenstein589abe32009-02-12 08:36:55 +00002689 /* Changing to LRM mode takes quite few seconds.
2690 So do it only if current mode is limiting
2691 ( default is LRM )*/
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002692 if (cur_limiting_mode != EDC_MODE_LIMITING)
Eilon Greenstein589abe32009-02-12 08:36:55 +00002693 return 0;
2694
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002695 bnx2x_cl45_write(bp, phy,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002696 MDIO_PMA_DEVAD,
2697 MDIO_PMA_REG_LRM_MODE,
2698 0);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002699 bnx2x_cl45_write(bp, phy,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002700 MDIO_PMA_DEVAD,
2701 MDIO_PMA_REG_ROM_VER2,
2702 0x128);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002703 bnx2x_cl45_write(bp, phy,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002704 MDIO_PMA_DEVAD,
2705 MDIO_PMA_REG_MISC_CTRL0,
2706 0x4008);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002707 bnx2x_cl45_write(bp, phy,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002708 MDIO_PMA_DEVAD,
2709 MDIO_PMA_REG_LRM_MODE,
2710 0xaaaa);
2711 }
2712 return 0;
2713}
2714
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002715static u8 bnx2x_8727_set_limiting_mode(struct bnx2x *bp,
2716 struct bnx2x_phy *phy,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002717 u16 edc_mode)
2718{
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002719 u16 phy_identifier;
2720 u16 rom_ver2_val;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002721 bnx2x_cl45_read(bp, phy,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002722 MDIO_PMA_DEVAD,
2723 MDIO_PMA_REG_PHY_IDENTIFIER,
2724 &phy_identifier);
2725
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002726 bnx2x_cl45_write(bp, phy,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002727 MDIO_PMA_DEVAD,
2728 MDIO_PMA_REG_PHY_IDENTIFIER,
2729 (phy_identifier & ~(1<<9)));
2730
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002731 bnx2x_cl45_read(bp, phy,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002732 MDIO_PMA_DEVAD,
2733 MDIO_PMA_REG_ROM_VER2,
2734 &rom_ver2_val);
2735 /* Keep the MSB 8-bits, and set the LSB 8-bits with the edc_mode */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002736 bnx2x_cl45_write(bp, phy,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002737 MDIO_PMA_DEVAD,
2738 MDIO_PMA_REG_ROM_VER2,
2739 (rom_ver2_val & 0xff00) | (edc_mode & 0x00ff));
2740
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002741 bnx2x_cl45_write(bp, phy,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002742 MDIO_PMA_DEVAD,
2743 MDIO_PMA_REG_PHY_IDENTIFIER,
2744 (phy_identifier | (1<<9)));
2745
2746 return 0;
2747}
2748
2749
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002750static u8 bnx2x_wait_for_sfp_module_initialized(struct bnx2x_phy *phy,
2751 struct link_params *params)
2752
Eilon Greenstein589abe32009-02-12 08:36:55 +00002753{
2754 u8 val;
2755 struct bnx2x *bp = params->bp;
2756 u16 timeout;
2757 /* Initialization time after hot-plug may take up to 300ms for some
2758 phys type ( e.g. JDSU ) */
2759 for (timeout = 0; timeout < 60; timeout++) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002760 if (bnx2x_read_sfp_module_eeprom(phy, params, 1, 1, &val)
Eilon Greenstein589abe32009-02-12 08:36:55 +00002761 == 0) {
2762 DP(NETIF_MSG_LINK, "SFP+ module initialization "
2763 "took %d ms\n", timeout * 5);
2764 return 0;
2765 }
2766 msleep(5);
2767 }
2768 return -EINVAL;
2769}
2770
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002771static void bnx2x_8727_power_module(struct bnx2x *bp,
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002772 struct bnx2x_phy *phy,
2773 u8 is_power_up) {
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002774 /* Make sure GPIOs are not using for LED mode */
2775 u16 val;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002776 /*
2777 * In the GPIO register, bit 4 is use to detemine if the GPIOs are
2778 * operating as INPUT or as OUTPUT. Bit 1 is for input, and 0 for
2779 * output
2780 * Bits 0-1 determine the gpios value for OUTPUT in case bit 4 val is 0
2781 * Bits 8-9 determine the gpios value for INPUT in case bit 4 val is 1
2782 * where the 1st bit is the over-current(only input), and 2nd bit is
2783 * for power( only output )
2784 */
2785
2786 /*
2787 * In case of NOC feature is disabled and power is up, set GPIO control
2788 * as input to enable listening of over-current indication
2789 */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002790 if (phy->flags & FLAGS_NOC)
2791 return;
2792 if (!(phy->flags &
2793 FLAGS_NOC) && is_power_up)
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002794 val = (1<<4);
2795 else
2796 /*
2797 * Set GPIO control to OUTPUT, and set the power bit
2798 * to according to the is_power_up
2799 */
2800 val = ((!(is_power_up)) << 1);
2801
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002802 bnx2x_cl45_write(bp, phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002803 MDIO_PMA_DEVAD,
2804 MDIO_PMA_REG_8727_GPIO_CTRL,
2805 val);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002806}
2807
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002808static u8 bnx2x_sfp_module_detection(struct bnx2x_phy *phy,
2809 struct link_params *params)
Eilon Greenstein589abe32009-02-12 08:36:55 +00002810{
2811 struct bnx2x *bp = params->bp;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002812 u16 edc_mode;
2813 u8 rc = 0;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002814
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002815 u32 val = REG_RD(bp, params->shmem_base +
2816 offsetof(struct shmem_region, dev_info.
2817 port_feature_config[params->port].config));
Eilon Greenstein589abe32009-02-12 08:36:55 +00002818
2819 DP(NETIF_MSG_LINK, "SFP+ module plugged in/out detected on port %d\n",
2820 params->port);
2821
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002822 if (bnx2x_get_edc_mode(phy, params, &edc_mode) != 0) {
Eilon Greenstein589abe32009-02-12 08:36:55 +00002823 DP(NETIF_MSG_LINK, "Failed to get valid module type\n");
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002824 return -EINVAL;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002825 } else if (bnx2x_verify_sfp_module(phy, params) !=
Eilon Greenstein589abe32009-02-12 08:36:55 +00002826 0) {
2827 /* check SFP+ module compatibility */
2828 DP(NETIF_MSG_LINK, "Module verification failed!!\n");
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002829 rc = -EINVAL;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002830 /* Turn on fault module-detected led */
2831 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
2832 MISC_REGISTERS_GPIO_HIGH,
2833 params->port);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002834 if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) &&
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002835 ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
2836 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_POWER_DOWN)) {
2837 /* Shutdown SFP+ module */
2838 DP(NETIF_MSG_LINK, "Shutdown SFP+ module!!\n");
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002839 bnx2x_8727_power_module(bp, phy, 0);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002840 return rc;
2841 }
2842 } else {
2843 /* Turn off fault module-detected led */
2844 DP(NETIF_MSG_LINK, "Turn off fault module-detected led\n");
2845 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
2846 MISC_REGISTERS_GPIO_LOW,
2847 params->port);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002848 }
2849
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002850 /* power up the SFP module */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002851 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002852 bnx2x_8727_power_module(bp, phy, 1);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002853
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002854 /* Check and set limiting mode / LRM mode on 8726.
2855 On 8727 it is done automatically */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002856 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
2857 bnx2x_8726_set_limiting_mode(bp, phy, edc_mode);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002858 else
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002859 bnx2x_8727_set_limiting_mode(bp, phy, edc_mode);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002860 /*
2861 * Enable transmit for this module if the module is approved, or
2862 * if unapproved modules should also enable the Tx laser
2863 */
2864 if (rc == 0 ||
2865 (val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) !=
2866 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002867 bnx2x_sfp_set_transmitter(bp, phy, params->port, 1);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002868 else
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002869 bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002870
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002871 return rc;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002872}
2873
2874void bnx2x_handle_module_detect_int(struct link_params *params)
2875{
2876 struct bnx2x *bp = params->bp;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002877 struct bnx2x_phy *phy = &params->phy[EXT_PHY1];
Eilon Greenstein589abe32009-02-12 08:36:55 +00002878 u32 gpio_val;
2879 u8 port = params->port;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002880
Eilon Greenstein589abe32009-02-12 08:36:55 +00002881 /* Set valid module led off */
2882 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
2883 MISC_REGISTERS_GPIO_HIGH,
2884 params->port);
2885
2886 /* Get current gpio val refelecting module plugged in / out*/
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002887 gpio_val = bnx2x_get_gpio(bp, MISC_REGISTERS_GPIO_3, port);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002888
2889 /* Call the handling function in case module is detected */
2890 if (gpio_val == 0) {
2891
2892 bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002893 MISC_REGISTERS_GPIO_INT_OUTPUT_CLR,
2894 port);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002895
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002896 if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0)
2897 bnx2x_sfp_module_detection(phy, params);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002898 else
2899 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
2900 } else {
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002901 u32 val = REG_RD(bp, params->shmem_base +
2902 offsetof(struct shmem_region, dev_info.
2903 port_feature_config[params->port].
2904 config));
2905
Eilon Greenstein589abe32009-02-12 08:36:55 +00002906 bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002907 MISC_REGISTERS_GPIO_INT_OUTPUT_SET,
2908 port);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002909 /* Module was plugged out. */
2910 /* Disable transmit for this module */
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002911 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
2912 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002913 bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002914 }
2915}
2916
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002917static void bnx2x_807x_force_10G(struct bnx2x *bp, struct bnx2x_phy *phy)
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002918{
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002919 /* Force KR or KX */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002920 bnx2x_cl45_write(bp, phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002921 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x2040);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002922 bnx2x_cl45_write(bp, phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002923 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0x000b);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002924 bnx2x_cl45_write(bp, phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002925 MDIO_PMA_DEVAD, MDIO_PMA_REG_BCM_CTRL, 0x0000);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002926 bnx2x_cl45_write(bp, phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002927 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x0000);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002928}
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002929
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002930static void bnx2x_8073_set_xaui_low_power_mode(struct bnx2x *bp,
2931 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002932{
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002933 u16 val;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002934 bnx2x_cl45_read(bp, phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002935 MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_CHIP_REV, &val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002936
2937 if (val == 0) {
2938 /* Mustn't set low power mode in 8073 A0 */
2939 return;
2940 }
2941
2942 /* Disable PLL sequencer (use read-modify-write to clear bit 13) */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002943 bnx2x_cl45_read(bp, phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002944 MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, &val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002945 val &= ~(1<<13);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002946 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002947 MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
2948
2949 /* PLL controls */
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002950 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805E, 0x1077);
2951 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805D, 0x0000);
2952 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805C, 0x030B);
2953 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805B, 0x1240);
2954 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805A, 0x2490);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002955
2956 /* Tx Controls */
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002957 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80A7, 0x0C74);
2958 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80A6, 0x9041);
2959 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80A5, 0x4640);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002960
2961 /* Rx Controls */
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002962 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80FE, 0x01C4);
2963 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80FD, 0x9249);
2964 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80FC, 0x2015);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002965
2966 /* Enable PLL sequencer (use read-modify-write to set bit 13) */
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002967 bnx2x_cl45_read(bp, phy, MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, &val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002968 val |= (1<<13);
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002969 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002970}
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002971
2972static void bnx2x_8073_set_pause_cl37(struct link_params *params,
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002973 struct bnx2x_phy *phy,
2974 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002975{
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002976 u16 cl37_val;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002977 struct bnx2x *bp = params->bp;
2978 bnx2x_cl45_read(bp, phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002979 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, &cl37_val);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002980
2981 cl37_val &= ~MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
2982 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002983 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002984 if ((vars->ieee_fc &
2985 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) ==
2986 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) {
2987 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC;
2988 }
2989 if ((vars->ieee_fc &
2990 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
2991 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
2992 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
2993 }
2994 if ((vars->ieee_fc &
2995 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
2996 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
2997 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
2998 }
2999 DP(NETIF_MSG_LINK,
3000 "Ext phy AN advertize cl37 0x%x\n", cl37_val);
3001
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003002 bnx2x_cl45_write(bp, phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003003 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, cl37_val);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003004 msleep(500);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003005}
3006
3007static void bnx2x_ext_phy_set_pause(struct link_params *params,
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003008 struct bnx2x_phy *phy,
3009 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003010{
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003011 u16 val;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003012 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003013 /* read modify write pause advertizing */
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003014 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV_PAUSE, &val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003015
3016 val &= ~MDIO_AN_REG_ADV_PAUSE_BOTH;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003017
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003018 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
Yaniv Rosner7aa07112010-09-07 11:41:01 +00003019 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003020 if ((vars->ieee_fc &
3021 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003022 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
3023 val |= MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC;
3024 }
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003025 if ((vars->ieee_fc &
3026 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003027 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003028 val |= MDIO_AN_REG_ADV_PAUSE_PAUSE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003029 }
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003030 DP(NETIF_MSG_LINK, "Ext phy AN advertize 0x%x\n", val);
3031 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV_PAUSE, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003032}
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003033
3034static void bnx2x_set_preemphasis(struct bnx2x_phy *phy,
3035 struct link_params *params)
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00003036{
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003037
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00003038 u16 bank, i = 0;
3039 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003040
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00003041 for (bank = MDIO_REG_BANK_RX0, i = 0; bank <= MDIO_REG_BANK_RX3;
3042 bank += (MDIO_REG_BANK_RX1-MDIO_REG_BANK_RX0), i++) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003043 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003044 bank,
3045 MDIO_RX0_RX_EQ_BOOST,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003046 phy->rx_preemphasis[i]);
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00003047 }
3048
3049 for (bank = MDIO_REG_BANK_TX0, i = 0; bank <= MDIO_REG_BANK_TX3;
3050 bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0), i++) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003051 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003052 bank,
3053 MDIO_TX0_TX_DRIVER,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003054 phy->tx_preemphasis[i]);
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00003055 }
3056}
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003057
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003058static void bnx2x_8481_set_led(struct bnx2x *bp,
3059 struct bnx2x_phy *phy)
Eilon Greenstein2f904462009-08-12 08:22:16 +00003060{
Yaniv Rosnera1e4be32010-09-01 09:51:33 +00003061 u16 val;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003062
3063 /* PHYC_CTL_LED_CTL */
3064 bnx2x_cl45_read(bp, phy,
Yaniv Rosnera1e4be32010-09-01 09:51:33 +00003065 MDIO_PMA_DEVAD,
3066 MDIO_PMA_REG_8481_LINK_SIGNAL, &val);
3067 val &= 0xFE00;
3068 val |= 0x0092;
Eilon Greenstein2f904462009-08-12 08:22:16 +00003069
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003070 bnx2x_cl45_write(bp, phy,
Yaniv Rosnera1e4be32010-09-01 09:51:33 +00003071 MDIO_PMA_DEVAD,
3072 MDIO_PMA_REG_8481_LINK_SIGNAL, val);
Eilon Greenstein2f904462009-08-12 08:22:16 +00003073
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003074 bnx2x_cl45_write(bp, phy,
Yaniv Rosnera1e4be32010-09-01 09:51:33 +00003075 MDIO_PMA_DEVAD,
3076 MDIO_PMA_REG_8481_LED1_MASK,
3077 0x80);
3078
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003079 bnx2x_cl45_write(bp, phy,
Yaniv Rosnera1e4be32010-09-01 09:51:33 +00003080 MDIO_PMA_DEVAD,
3081 MDIO_PMA_REG_8481_LED2_MASK,
3082 0x18);
3083
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003084 bnx2x_cl45_write(bp, phy,
Yaniv Rosnera1e4be32010-09-01 09:51:33 +00003085 MDIO_PMA_DEVAD,
3086 MDIO_PMA_REG_8481_LED3_MASK,
3087 0x0040);
3088
Eilon Greenstein2f904462009-08-12 08:22:16 +00003089 /* 'Interrupt Mask' */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003090 bnx2x_cl45_write(bp, phy,
Yaniv Rosnera1e4be32010-09-01 09:51:33 +00003091 MDIO_AN_DEVAD,
3092 0xFFFB, 0xFFFD);
Eilon Greenstein2f904462009-08-12 08:22:16 +00003093}
Eilon Greenstein2f904462009-08-12 08:22:16 +00003094
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003095static void bnx2x_init_internal_phy(struct bnx2x_phy *phy,
3096 struct link_params *params,
3097 struct link_vars *vars)
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003098{
3099 struct bnx2x *bp = params->bp;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003100 u8 enable_cl73 = (SINGLE_MEDIA_DIRECT(params) ||
3101 (params->loopback_mode == LOOPBACK_XGXS_10));
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003102 if (!(vars->phy_flags & PHY_SGMII_FLAG)) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003103 if (SINGLE_MEDIA_DIRECT(params) &&
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00003104 (params->feature_config_flags &
3105 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED))
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003106 bnx2x_set_preemphasis(phy, params);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003107
3108 /* forced speed requested? */
Yaniv Rosner7846e472009-11-05 19:18:07 +02003109 if (vars->line_speed != SPEED_AUTO_NEG ||
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003110 (SINGLE_MEDIA_DIRECT(params) &&
Yaniv Rosner7846e472009-11-05 19:18:07 +02003111 params->loopback_mode == LOOPBACK_EXT)) {
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003112 DP(NETIF_MSG_LINK, "not SGMII, no AN\n");
3113
3114 /* disable autoneg */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003115 bnx2x_set_autoneg(phy, params, vars, 0);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003116
3117 /* program speed and duplex */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003118 bnx2x_program_serdes(phy, params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003119
3120 } else { /* AN_mode */
3121 DP(NETIF_MSG_LINK, "not SGMII, AN\n");
3122
3123 /* AN enabled */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003124 bnx2x_set_brcm_cl37_advertisment(phy, params);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003125
3126 /* program duplex & pause advertisement (for aneg) */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003127 bnx2x_set_ieee_aneg_advertisment(phy, params,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003128 vars->ieee_fc);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003129
3130 /* enable autoneg */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003131 bnx2x_set_autoneg(phy, params, vars, enable_cl73);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003132
3133 /* enable and restart AN */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003134 bnx2x_restart_autoneg(phy, params, enable_cl73);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003135 }
3136
3137 } else { /* SGMII mode */
3138 DP(NETIF_MSG_LINK, "SGMII\n");
3139
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003140 bnx2x_initialize_sgmii_process(phy, params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003141 }
3142}
3143
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003144static u16 bnx2x_wait_reset_complete(struct bnx2x *bp,
3145 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003146{
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003147 u16 cnt, ctrl;
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003148 /* Wait for soft reset to get cleared upto 1 sec */
3149 for (cnt = 0; cnt < 1000; cnt++) {
3150 bnx2x_cl45_read(bp, phy,
3151 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, &ctrl);
3152 if (!(ctrl & (1<<15)))
3153 break;
3154 msleep(1);
3155 }
3156 DP(NETIF_MSG_LINK, "control reg 0x%x (after %d ms)\n", ctrl, cnt);
3157 return cnt;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003158}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003159
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003160static u8 bnx2x_8705_config_init(struct bnx2x_phy *phy,
3161 struct link_params *params,
3162 struct link_vars *vars)
3163{
3164 struct bnx2x *bp = params->bp;
3165 DP(NETIF_MSG_LINK, "init 8705\n");
3166 /* Restore normal power mode*/
3167 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
3168 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
3169 /* HW reset */
3170 bnx2x_ext_phy_hw_reset(bp, params->port);
3171 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0xa040);
3172 bnx2x_wait_reset_complete(bp, phy);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003173
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003174 bnx2x_cl45_write(bp, phy,
3175 MDIO_PMA_DEVAD, MDIO_PMA_REG_MISC_CTRL, 0x8288);
3176 bnx2x_cl45_write(bp, phy,
3177 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, 0x7fbf);
3178 bnx2x_cl45_write(bp, phy,
3179 MDIO_PMA_DEVAD, MDIO_PMA_REG_CMU_PLL_BYPASS, 0x0100);
3180 bnx2x_cl45_write(bp, phy,
3181 MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_CNTL, 0x1);
3182 /* BCM8705 doesn't have microcode, hence the 0 */
3183 bnx2x_save_spirom_version(bp, params->port, params->shmem_base, 0);
3184 return 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003185}
3186
3187static u8 bnx2x_8706_config_init(struct bnx2x_phy *phy,
3188 struct link_params *params,
3189 struct link_vars *vars)
3190{
3191 u16 cnt, val;
3192 struct bnx2x *bp = params->bp;
3193 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
3194 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
3195 /* HW reset */
3196 bnx2x_ext_phy_hw_reset(bp, params->port);
3197 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0xa040);
3198
3199 bnx2x_wait_reset_complete(bp, phy);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003200
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003201 /* Wait until fw is loaded */
3202 for (cnt = 0; cnt < 100; cnt++) {
3203 bnx2x_cl45_read(bp, phy,
3204 MDIO_PMA_DEVAD, MDIO_PMA_REG_ROM_VER1, &val);
3205 if (val)
3206 break;
3207 msleep(10);
3208 }
3209 DP(NETIF_MSG_LINK, "XGXS 8706 is initialized after %d ms\n", cnt);
3210 if ((params->feature_config_flags &
3211 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
3212 u8 i;
3213 u16 reg;
3214 for (i = 0; i < 4; i++) {
3215 reg = MDIO_XS_8706_REG_BANK_RX0 +
3216 i*(MDIO_XS_8706_REG_BANK_RX1 -
3217 MDIO_XS_8706_REG_BANK_RX0);
3218 bnx2x_cl45_read(bp, phy, MDIO_XS_DEVAD, reg, &val);
3219 /* Clear first 3 bits of the control */
3220 val &= ~0x7;
3221 /* Set control bits according to configuration */
3222 val |= (phy->rx_preemphasis[i] & 0x7);
3223 DP(NETIF_MSG_LINK, "Setting RX Equalizer to BCM8706"
3224 " reg 0x%x <-- val 0x%x\n", reg, val);
3225 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, reg, val);
3226 }
3227 }
3228 /* Force speed */
3229 if (phy->req_line_speed == SPEED_10000) {
3230 DP(NETIF_MSG_LINK, "XGXS 8706 force 10Gbps\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003231
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003232 bnx2x_cl45_write(bp, phy,
3233 MDIO_PMA_DEVAD,
3234 MDIO_PMA_REG_DIGITAL_CTRL, 0x400);
3235 bnx2x_cl45_write(bp, phy,
3236 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 1);
3237 } else {
3238 /* Force 1Gbps using autoneg with 1G advertisment */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003239
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003240 /* Allow CL37 through CL73 */
3241 DP(NETIF_MSG_LINK, "XGXS 8706 AutoNeg\n");
3242 bnx2x_cl45_write(bp, phy,
3243 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_CL73, 0x040c);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003244
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003245 /* Enable Full-Duplex advertisment on CL37 */
3246 bnx2x_cl45_write(bp, phy,
3247 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LP, 0x0020);
3248 /* Enable CL37 AN */
3249 bnx2x_cl45_write(bp, phy,
3250 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
3251 /* 1G support */
3252 bnx2x_cl45_write(bp, phy,
3253 MDIO_AN_DEVAD, MDIO_AN_REG_ADV, (1<<5));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003254
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003255 /* Enable clause 73 AN */
3256 bnx2x_cl45_write(bp, phy,
3257 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
3258 bnx2x_cl45_write(bp, phy,
3259 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
3260 0x0400);
3261 bnx2x_cl45_write(bp, phy,
3262 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL,
3263 0x0004);
3264 }
3265 bnx2x_save_bcm_spirom_ver(bp, params->port, phy, params->shmem_base);
3266 return 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003267}
3268
3269static u8 bnx2x_8726_config_init(struct bnx2x_phy *phy,
3270 struct link_params *params,
3271 struct link_vars *vars)
3272{
3273 struct bnx2x *bp = params->bp;
3274 DP(NETIF_MSG_LINK, "Initializing BCM8726\n");
3275 /* Restore normal power mode*/
3276 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
3277 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
3278
3279 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
3280 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
3281
3282 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
3283 bnx2x_wait_reset_complete(bp, phy);
3284
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003285 bnx2x_8726_external_rom_boot(phy, params);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003286
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003287 /* Need to call module detected on initialization since
3288 the module detection triggered by actual module
3289 insertion might occur before driver is loaded, and when
3290 driver is loaded, it reset all registers, including the
3291 transmitter */
3292 bnx2x_sfp_module_detection(phy, params);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003293
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003294 if (phy->req_line_speed == SPEED_1000) {
3295 DP(NETIF_MSG_LINK, "Setting 1G force\n");
3296 bnx2x_cl45_write(bp, phy,
3297 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x40);
3298 bnx2x_cl45_write(bp, phy,
3299 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0xD);
3300 bnx2x_cl45_write(bp, phy,
3301 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x5);
3302 bnx2x_cl45_write(bp, phy,
3303 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
3304 0x400);
3305 } else if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
3306 (phy->speed_cap_mask &
3307 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G) &&
3308 ((phy->speed_cap_mask &
3309 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) !=
3310 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
3311 DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
3312 /* Set Flow control */
3313 bnx2x_ext_phy_set_pause(params, phy, vars);
3314 bnx2x_cl45_write(bp, phy,
3315 MDIO_AN_DEVAD, MDIO_AN_REG_ADV, 0x20);
3316 bnx2x_cl45_write(bp, phy,
3317 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_CL73, 0x040c);
3318 bnx2x_cl45_write(bp, phy,
3319 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, 0x0020);
3320 bnx2x_cl45_write(bp, phy,
3321 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
3322 bnx2x_cl45_write(bp, phy,
3323 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
3324 /* Enable RX-ALARM control to receive
3325 interrupt for 1G speed change */
3326 bnx2x_cl45_write(bp, phy,
3327 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x4);
3328 bnx2x_cl45_write(bp, phy,
3329 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
3330 0x400);
Eilon Greenstein589abe32009-02-12 08:36:55 +00003331
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003332 } else { /* Default 10G. Set only LASI control */
3333 bnx2x_cl45_write(bp, phy,
3334 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 1);
3335 }
Eilon Greenstein589abe32009-02-12 08:36:55 +00003336
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003337 /* Set TX PreEmphasis if needed */
3338 if ((params->feature_config_flags &
3339 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
3340 DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x,"
3341 "TX_CTRL2 0x%x\n",
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003342 phy->tx_preemphasis[0],
3343 phy->tx_preemphasis[1]);
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003344 bnx2x_cl45_write(bp, phy,
3345 MDIO_PMA_DEVAD,
3346 MDIO_PMA_REG_8726_TX_CTRL1,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003347 phy->tx_preemphasis[0]);
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00003348
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003349 bnx2x_cl45_write(bp, phy,
3350 MDIO_PMA_DEVAD,
3351 MDIO_PMA_REG_8726_TX_CTRL2,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003352 phy->tx_preemphasis[1]);
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003353 }
3354 return 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003355
3356}
3357
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003358static u8 bnx2x_8073_config_init(struct bnx2x_phy *phy,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003359 struct link_params *params,
3360 struct link_vars *vars)
3361{
3362 struct bnx2x *bp = params->bp;
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003363 u16 val = 0, tmp1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003364 u8 gpio_port;
3365 DP(NETIF_MSG_LINK, "Init 8073\n");
3366
3367 gpio_port = params->port;
3368 /* Restore normal power mode*/
3369 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
3370 MISC_REGISTERS_GPIO_OUTPUT_HIGH, gpio_port);
3371
3372 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
3373 MISC_REGISTERS_GPIO_OUTPUT_HIGH, gpio_port);
3374
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003375 /* enable LASI */
3376 bnx2x_cl45_write(bp, phy,
3377 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL, (1<<2));
3378 bnx2x_cl45_write(bp, phy,
3379 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x0004);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003380
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003381 bnx2x_8073_set_pause_cl37(params, phy, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003382
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003383 bnx2x_8073_set_xaui_low_power_mode(bp, phy);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003384
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003385 bnx2x_cl45_read(bp, phy,
3386 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &tmp1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003387
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003388 bnx2x_cl45_read(bp, phy,
3389 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &tmp1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003390
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003391 DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1): 0x%x\n", tmp1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003392
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003393 /* Enable CL37 BAM */
3394 bnx2x_cl45_read(bp, phy,
3395 MDIO_AN_DEVAD,
3396 MDIO_AN_REG_8073_BAM, &val);
3397 bnx2x_cl45_write(bp, phy,
3398 MDIO_AN_DEVAD,
3399 MDIO_AN_REG_8073_BAM, val | 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003400
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003401 if (params->loopback_mode == LOOPBACK_EXT) {
3402 bnx2x_807x_force_10G(bp, phy);
3403 DP(NETIF_MSG_LINK, "Forced speed 10G on 807X\n");
3404 return 0;
3405 } else {
3406 bnx2x_cl45_write(bp, phy,
3407 MDIO_PMA_DEVAD, MDIO_PMA_REG_BCM_CTRL, 0x0002);
3408 }
3409 if (phy->req_line_speed != SPEED_AUTO_NEG) {
3410 if (phy->req_line_speed == SPEED_10000) {
3411 val = (1<<7);
3412 } else if (phy->req_line_speed == SPEED_2500) {
3413 val = (1<<5);
3414 /* Note that 2.5G works only
3415 when used with 1G advertisment */
3416 } else
3417 val = (1<<5);
3418 } else {
3419 val = 0;
3420 if (phy->speed_cap_mask &
3421 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
3422 val |= (1<<7);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003423
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003424 /* Note that 2.5G works only when
3425 used with 1G advertisment */
3426 if (phy->speed_cap_mask &
3427 (PORT_HW_CFG_SPEED_CAPABILITY_D0_1G |
3428 PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G))
3429 val |= (1<<5);
3430 DP(NETIF_MSG_LINK, "807x autoneg val = 0x%x\n", val);
3431 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003432
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003433 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV, val);
3434 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_8073_2_5G, &tmp1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003435
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003436 if (((phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G) &&
3437 (phy->req_line_speed == SPEED_AUTO_NEG)) ||
3438 (phy->req_line_speed == SPEED_2500)) {
3439 u16 phy_ver;
3440 /* Allow 2.5G for A1 and above */
3441 bnx2x_cl45_read(bp, phy,
3442 MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_CHIP_REV,
3443 &phy_ver);
3444 DP(NETIF_MSG_LINK, "Add 2.5G\n");
3445 if (phy_ver > 0)
3446 tmp1 |= 1;
3447 else
3448 tmp1 &= 0xfffe;
3449 } else {
3450 DP(NETIF_MSG_LINK, "Disable 2.5G\n");
3451 tmp1 &= 0xfffe;
3452 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003453
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003454 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_8073_2_5G, tmp1);
3455 /* Add support for CL37 (passive mode) II */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003456
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003457 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, &tmp1);
3458 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD,
3459 (tmp1 | ((phy->req_duplex == DUPLEX_FULL) ?
3460 0x20 : 0x40)));
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003461
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003462 /* Add support for CL37 (passive mode) III */
3463 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003464
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003465 /* The SNR will improve about 2db by changing
3466 BW and FEE main tap. Rest commands are executed
3467 after link is up*/
3468 if (bnx2x_8073_is_snr_needed(bp, phy))
3469 bnx2x_cl45_write(bp, phy,
3470 MDIO_PMA_DEVAD, MDIO_PMA_REG_EDC_FFE_MAIN,
3471 0xFB0C);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003472
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003473 /* Enable FEC (Forware Error Correction) Request in the AN */
3474 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV2, &tmp1);
3475 tmp1 |= (1<<15);
3476 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV2, tmp1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003477
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003478 bnx2x_ext_phy_set_pause(params, phy, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003479
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003480 /* Restart autoneg */
3481 msleep(500);
3482 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
3483 DP(NETIF_MSG_LINK, "807x Autoneg Restart: Advertise 1G=%x, 10G=%x\n",
3484 ((val & (1<<5)) > 0), ((val & (1<<7)) > 0));
3485 return 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003486}
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003487
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003488static u8 bnx2x_8727_config_init(struct bnx2x_phy *phy,
3489 struct link_params *params,
3490 struct link_vars *vars)
3491{
3492 u16 tmp1, val, mod_abs;
3493 u16 rx_alarm_ctrl_val;
3494 u16 lasi_ctrl_val;
3495 struct bnx2x *bp = params->bp;
3496 /* Enable PMD link, MOD_ABS_FLT, and 1G link alarm */
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003497
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003498 bnx2x_wait_reset_complete(bp, phy);
3499 rx_alarm_ctrl_val = (1<<2) | (1<<5) ;
3500 lasi_ctrl_val = 0x0004;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003501
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003502 DP(NETIF_MSG_LINK, "Initializing BCM8727\n");
3503 /* enable LASI */
3504 bnx2x_cl45_write(bp, phy,
3505 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
3506 rx_alarm_ctrl_val);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003507
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003508 bnx2x_cl45_write(bp, phy,
3509 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, lasi_ctrl_val);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003510
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003511 /* Initially configure MOD_ABS to interrupt when
3512 module is presence( bit 8) */
3513 bnx2x_cl45_read(bp, phy,
3514 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
3515 /* Set EDC off by setting OPTXLOS signal input to low
3516 (bit 9).
3517 When the EDC is off it locks onto a reference clock and
3518 avoids becoming 'lost'.*/
3519 mod_abs &= ~((1<<8) | (1<<9));
3520 bnx2x_cl45_write(bp, phy,
3521 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003522
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003523
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003524 /* Make MOD_ABS give interrupt on change */
3525 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL,
3526 &val);
3527 val |= (1<<12);
3528 bnx2x_cl45_write(bp, phy,
3529 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL, val);
3530 /* Set 8727 GPIOs to input to allow reading from the
3531 8727 GPIO0 status which reflect SFP+ module
3532 over-current */
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003533
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003534 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL,
3535 &val);
3536 val &= 0xff8f; /* Reset bits 4-6 */
3537 bnx2x_cl45_write(bp, phy,
3538 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL, val);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003539
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003540 bnx2x_8727_power_module(bp, phy, 1);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003541
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003542 bnx2x_cl45_read(bp, phy,
3543 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &tmp1);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003544
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003545 bnx2x_cl45_read(bp, phy,
3546 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &tmp1);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003547
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003548 /* Set option 1G speed */
3549 if (phy->req_line_speed == SPEED_1000) {
3550 DP(NETIF_MSG_LINK, "Setting 1G force\n");
3551 bnx2x_cl45_write(bp, phy,
3552 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x40);
3553 bnx2x_cl45_write(bp, phy,
3554 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0xD);
3555 bnx2x_cl45_read(bp, phy,
3556 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, &tmp1);
3557 DP(NETIF_MSG_LINK, "1.7 = 0x%x\n", tmp1);
3558 } else if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
3559 ((phy->speed_cap_mask &
3560 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) &&
3561 ((phy->speed_cap_mask &
3562 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) !=
3563 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003564
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003565 DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
3566 bnx2x_cl45_write(bp, phy,
3567 MDIO_AN_DEVAD, MDIO_AN_REG_8727_MISC_CTRL, 0);
3568 bnx2x_cl45_write(bp, phy,
3569 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1300);
3570 } else {
3571 /**
3572 * Since the 8727 has only single reset pin, need to set the 10G
3573 * registers although it is default
3574 */
3575 bnx2x_cl45_write(bp, phy,
3576 MDIO_AN_DEVAD, MDIO_AN_REG_8727_MISC_CTRL,
3577 0x0020);
3578 bnx2x_cl45_write(bp, phy,
3579 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x0100);
3580 bnx2x_cl45_write(bp, phy,
3581 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x2040);
3582 bnx2x_cl45_write(bp, phy,
3583 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2,
3584 0x0008);
3585 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003586
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003587
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003588 /* Set 2-wire transfer rate of SFP+ module EEPROM
3589 * to 100Khz since some DACs(direct attached cables) do
3590 * not work at 400Khz.
3591 */
3592 bnx2x_cl45_write(bp, phy,
3593 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR,
3594 0xa001);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003595
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003596 /* Set TX PreEmphasis if needed */
3597 if ((params->feature_config_flags &
3598 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
3599 DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x, TX_CTRL2 0x%x\n",
3600 phy->tx_preemphasis[0],
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003601 phy->tx_preemphasis[1]);
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003602 bnx2x_cl45_write(bp, phy,
3603 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TX_CTRL1,
3604 phy->tx_preemphasis[0]);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003605
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003606 bnx2x_cl45_write(bp, phy,
3607 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TX_CTRL2,
3608 phy->tx_preemphasis[1]);
3609 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003610
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003611 return 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003612}
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003613
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003614static u8 bnx2x_7101_config_init(struct bnx2x_phy *phy,
3615 struct link_params *params,
3616 struct link_vars *vars)
3617{
3618 u16 fw_ver1, fw_ver2, val;
3619 struct bnx2x *bp = params->bp;
3620 DP(NETIF_MSG_LINK, "Setting the SFX7101 LASI indication\n");
3621
3622 /* Restore normal power mode*/
3623 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
3624 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
3625 /* HW reset */
3626 bnx2x_ext_phy_hw_reset(bp, params->port);
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003627 bnx2x_wait_reset_complete(bp, phy);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003628
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003629 bnx2x_cl45_write(bp, phy,
3630 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x1);
3631 DP(NETIF_MSG_LINK, "Setting the SFX7101 LED to blink on traffic\n");
3632 bnx2x_cl45_write(bp, phy,
3633 MDIO_PMA_DEVAD, MDIO_PMA_REG_7107_LED_CNTL, (1<<3));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003634
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003635 bnx2x_ext_phy_set_pause(params, phy, vars);
3636 /* Restart autoneg */
3637 bnx2x_cl45_read(bp, phy,
3638 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, &val);
3639 val |= 0x200;
3640 bnx2x_cl45_write(bp, phy,
3641 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, val);
Eilon Greenstein28577182009-02-12 08:37:00 +00003642
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003643 /* Save spirom version */
3644 bnx2x_cl45_read(bp, phy,
3645 MDIO_PMA_DEVAD, MDIO_PMA_REG_7101_VER1, &fw_ver1);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003646
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003647 bnx2x_cl45_read(bp, phy,
3648 MDIO_PMA_DEVAD, MDIO_PMA_REG_7101_VER2, &fw_ver2);
3649 bnx2x_save_spirom_version(bp, params->port,
3650 (u32)(fw_ver1<<16 | fw_ver2), phy->ver_addr);
3651 return 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003652}
3653
3654static u8 bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy,
3655 struct link_params *params,
3656 struct link_vars *vars)
3657{
3658 struct bnx2x *bp = params->bp;
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003659 u16 autoneg_val, an_1000_val, an_10_100_val;
3660 bnx2x_wait_reset_complete(bp, phy);
3661 bnx2x_bits_en(bp, NIG_REG_LATCH_BC_0 + params->port*4,
3662 1 << NIG_LATCH_BC_ENABLE_MI_INT);
Yaniv Rosnera1e4be32010-09-01 09:51:33 +00003663
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003664 bnx2x_cl45_write(bp, phy,
3665 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x0000);
3666 bnx2x_8481_set_led(bp, phy);
3667 /* set 1000 speed advertisement */
3668 bnx2x_cl45_read(bp, phy,
3669 MDIO_AN_DEVAD, MDIO_AN_REG_8481_1000T_CTRL,
3670 &an_1000_val);
Eilon Greenstein28577182009-02-12 08:37:00 +00003671
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003672 bnx2x_ext_phy_set_pause(params, phy, vars);
3673 bnx2x_cl45_read(bp, phy,
3674 MDIO_AN_DEVAD,
3675 MDIO_AN_REG_8481_LEGACY_AN_ADV,
3676 &an_10_100_val);
3677 bnx2x_cl45_read(bp, phy,
3678 MDIO_AN_DEVAD, MDIO_AN_REG_8481_LEGACY_MII_CTRL,
3679 &autoneg_val);
3680 /* Disable forced speed */
3681 autoneg_val &= ~((1<<6) | (1<<8) | (1<<9) | (1<<12) | (1<<13));
3682 an_10_100_val &= ~((1<<5) | (1<<6) | (1<<7) | (1<<8));
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02003683
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003684 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
3685 (phy->speed_cap_mask &
3686 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) ||
3687 (phy->req_line_speed == SPEED_1000)) {
3688 an_1000_val |= (1<<8);
3689 autoneg_val |= (1<<9 | 1<<12);
3690 if (phy->req_duplex == DUPLEX_FULL)
3691 an_1000_val |= (1<<9);
3692 DP(NETIF_MSG_LINK, "Advertising 1G\n");
3693 } else
3694 an_1000_val &= ~((1<<8) | (1<<9));
Eilon Greenstein28577182009-02-12 08:37:00 +00003695
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003696 bnx2x_cl45_write(bp, phy,
3697 MDIO_AN_DEVAD, MDIO_AN_REG_8481_1000T_CTRL,
3698 an_1000_val);
Eilon Greenstein2f904462009-08-12 08:22:16 +00003699
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003700 /* set 10 speed advertisement */
3701 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
3702 (phy->speed_cap_mask &
3703 (PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL |
3704 PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF)))) {
3705 an_10_100_val |= (1<<7);
3706 /* Enable autoneg and restart autoneg for legacy speeds */
3707 autoneg_val |= (1<<9 | 1<<12);
Yaniv Rosner46d15cc2009-11-05 19:18:30 +02003708
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003709 if (phy->req_duplex == DUPLEX_FULL)
3710 an_10_100_val |= (1<<8);
3711 DP(NETIF_MSG_LINK, "Advertising 100M\n");
3712 }
3713 /* set 10 speed advertisement */
3714 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
3715 (phy->speed_cap_mask &
3716 (PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL |
3717 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF)))) {
3718 an_10_100_val |= (1<<5);
3719 autoneg_val |= (1<<9 | 1<<12);
3720 if (phy->req_duplex == DUPLEX_FULL)
3721 an_10_100_val |= (1<<6);
3722 DP(NETIF_MSG_LINK, "Advertising 10M\n");
3723 }
Eilon Greenstein2f904462009-08-12 08:22:16 +00003724
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003725 /* Only 10/100 are allowed to work in FORCE mode */
3726 if (phy->req_line_speed == SPEED_100) {
3727 autoneg_val |= (1<<13);
3728 /* Enabled AUTO-MDIX when autoneg is disabled */
3729 bnx2x_cl45_write(bp, phy,
3730 MDIO_AN_DEVAD, MDIO_AN_REG_8481_AUX_CTRL,
3731 (1<<15 | 1<<9 | 7<<0));
3732 DP(NETIF_MSG_LINK, "Setting 100M force\n");
3733 }
3734 if (phy->req_line_speed == SPEED_10) {
3735 /* Enabled AUTO-MDIX when autoneg is disabled */
3736 bnx2x_cl45_write(bp, phy,
3737 MDIO_AN_DEVAD, MDIO_AN_REG_8481_AUX_CTRL,
3738 (1<<15 | 1<<9 | 7<<0));
3739 DP(NETIF_MSG_LINK, "Setting 10M force\n");
3740 }
Eilon Greenstein2f904462009-08-12 08:22:16 +00003741
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003742 bnx2x_cl45_write(bp, phy,
3743 MDIO_AN_DEVAD, MDIO_AN_REG_8481_LEGACY_AN_ADV,
3744 an_10_100_val);
Yaniv Rosnerac4d9442010-09-01 09:51:25 +00003745
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003746 if (phy->req_duplex == DUPLEX_FULL)
3747 autoneg_val |= (1<<8);
Yaniv Rosnerac4d9442010-09-01 09:51:25 +00003748
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003749 bnx2x_cl45_write(bp, phy,
3750 MDIO_AN_DEVAD,
3751 MDIO_AN_REG_8481_LEGACY_MII_CTRL, autoneg_val);
Yaniv Rosnerac4d9442010-09-01 09:51:25 +00003752
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003753 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
3754 (phy->speed_cap_mask &
3755 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) ||
3756 (phy->req_line_speed == SPEED_10000)) {
3757 DP(NETIF_MSG_LINK, "Advertising 10G\n");
3758 /* Restart autoneg for 10G*/
Yaniv Rosnerac4d9442010-09-01 09:51:25 +00003759
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003760 bnx2x_cl45_write(bp, phy,
3761 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL,
3762 0x3200);
3763 } else if (phy->req_line_speed != SPEED_10 &&
3764 phy->req_line_speed != SPEED_100) {
3765 bnx2x_cl45_write(bp, phy,
3766 MDIO_AN_DEVAD,
3767 MDIO_AN_REG_8481_10GBASE_T_AN_CTRL,
3768 1);
3769 }
3770 /* Save spirom version */
3771 bnx2x_save_8481_spirom_version(phy, params, params->shmem_base);
Yaniv Rosnerac4d9442010-09-01 09:51:25 +00003772
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003773 return 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003774}
3775
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003776static u8 bnx2x_848x3_config_init(struct bnx2x_phy *phy,
3777 struct link_params *params,
3778 struct link_vars *vars)
3779{
3780 struct bnx2x *bp = params->bp;
3781 u16 temp;
3782 msleep(1);
3783 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
3784 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
3785 params->port);
3786 msleep(200); /* 100 is not enough */
3787
3788 /**
3789 * BCM84823 requires that XGXS links up first @ 10G for normal
3790 * behavior
3791 */
3792 temp = vars->line_speed;
3793 vars->line_speed = SPEED_10000;
3794 bnx2x_set_autoneg(phy, params, vars, 0);
3795 bnx2x_program_serdes(phy, params, vars);
3796 vars->line_speed = temp;
3797 return bnx2x_848xx_cmn_config_init(phy, params, vars);
3798}
3799
3800static u8 bnx2x_8481_config_init(struct bnx2x_phy *phy,
3801 struct link_params *params,
3802 struct link_vars *vars)
3803{
3804 struct bnx2x *bp = params->bp;
3805 /* Restore normal power mode*/
3806 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
3807 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
3808
3809 /* HW reset */
3810 bnx2x_ext_phy_hw_reset(bp, params->port);
3811
3812 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
3813 return bnx2x_848xx_cmn_config_init(phy, params, vars);
3814}
Yaniv Rosner7aa07112010-09-07 11:41:01 +00003815
3816
3817static void bnx2x_ext_phy_10G_an_resolve(struct bnx2x *bp,
3818 struct bnx2x_phy *phy,
3819 struct link_vars *vars)
3820{
3821 u16 val;
3822 bnx2x_cl45_read(bp, phy,
3823 MDIO_AN_DEVAD,
3824 MDIO_AN_REG_STATUS, &val);
3825 bnx2x_cl45_read(bp, phy,
3826 MDIO_AN_DEVAD,
3827 MDIO_AN_REG_STATUS, &val);
3828 if (val & (1<<5))
3829 vars->link_status |= LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
3830 if ((val & (1<<0)) == 0)
3831 vars->link_status |= LINK_STATUS_PARALLEL_DETECTION_USED;
3832}
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003833static void bnx2x_8727_handle_mod_abs(struct bnx2x_phy *phy,
3834 struct link_params *params)
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003835{
3836 struct bnx2x *bp = params->bp;
3837 u16 mod_abs, rx_alarm_status;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003838 u32 val = REG_RD(bp, params->shmem_base +
3839 offsetof(struct shmem_region, dev_info.
3840 port_feature_config[params->port].
3841 config));
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003842 bnx2x_cl45_read(bp, phy,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003843 MDIO_PMA_DEVAD,
3844 MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
3845 if (mod_abs & (1<<8)) {
3846
3847 /* Module is absent */
3848 DP(NETIF_MSG_LINK, "MOD_ABS indication "
3849 "show module is absent\n");
3850
3851 /* 1. Set mod_abs to detect next module
3852 presence event
3853 2. Set EDC off by setting OPTXLOS signal input to low
3854 (bit 9).
3855 When the EDC is off it locks onto a reference clock and
3856 avoids becoming 'lost'.*/
3857 mod_abs &= ~((1<<8)|(1<<9));
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003858 bnx2x_cl45_write(bp, phy,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003859 MDIO_PMA_DEVAD,
3860 MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
3861
3862 /* Clear RX alarm since it stays up as long as
3863 the mod_abs wasn't changed */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003864 bnx2x_cl45_read(bp, phy,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003865 MDIO_PMA_DEVAD,
3866 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
3867
3868 } else {
3869 /* Module is present */
3870 DP(NETIF_MSG_LINK, "MOD_ABS indication "
3871 "show module is present\n");
3872 /* First thing, disable transmitter,
3873 and if the module is ok, the
3874 module_detection will enable it*/
3875
3876 /* 1. Set mod_abs to detect next module
3877 absent event ( bit 8)
3878 2. Restore the default polarity of the OPRXLOS signal and
3879 this signal will then correctly indicate the presence or
3880 absence of the Rx signal. (bit 9) */
3881 mod_abs |= ((1<<8)|(1<<9));
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003882 bnx2x_cl45_write(bp, phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003883 MDIO_PMA_DEVAD,
3884 MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003885
3886 /* Clear RX alarm since it stays up as long as
3887 the mod_abs wasn't changed. This is need to be done
3888 before calling the module detection, otherwise it will clear
3889 the link update alarm */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003890 bnx2x_cl45_read(bp, phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003891 MDIO_PMA_DEVAD,
3892 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003893
3894
3895 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
3896 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003897 bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003898
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003899 if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0)
3900 bnx2x_sfp_module_detection(phy, params);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003901 else
3902 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
3903 }
3904
3905 DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n",
3906 rx_alarm_status);
3907 /* No need to check link status in case of
3908 module plugged in/out */
3909}
3910
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003911static u8 bnx2x_8705_read_status(struct bnx2x_phy *phy,
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003912 struct link_params *params,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003913 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003914{
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003915 u8 link_up = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003916 u16 val1, rx_sd;
3917 struct bnx2x *bp = params->bp;
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003918 DP(NETIF_MSG_LINK, "read status 8705\n");
3919 bnx2x_cl45_read(bp, phy,
3920 MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_STATUS, &val1);
3921 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003922
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003923 bnx2x_cl45_read(bp, phy,
3924 MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_STATUS, &val1);
3925 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003926
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003927 bnx2x_cl45_read(bp, phy,
3928 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD, &rx_sd);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003929
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003930 bnx2x_cl45_read(bp, phy,
3931 MDIO_PMA_DEVAD, 0xc809, &val1);
3932 bnx2x_cl45_read(bp, phy,
3933 MDIO_PMA_DEVAD, 0xc809, &val1);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003934
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003935 DP(NETIF_MSG_LINK, "8705 1.c809 val=0x%x\n", val1);
3936 link_up = ((rx_sd & 0x1) && (val1 & (1<<9)) && ((val1 & (1<<8)) == 0));
3937 if (link_up) {
3938 vars->line_speed = SPEED_10000;
3939 bnx2x_ext_phy_resolve_fc(phy, params, vars);
3940 }
3941 return link_up;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003942}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003943
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003944static u8 bnx2x_8706_8726_read_status(struct bnx2x_phy *phy,
3945 struct link_params *params,
3946 struct link_vars *vars)
3947{
3948 u8 link_up = 0;
3949 u16 val1, val2, rx_sd, pcs_status;
3950 struct bnx2x *bp = params->bp;
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003951 DP(NETIF_MSG_LINK, "XGXS 8706/8726\n");
3952 /* Clear RX Alarm*/
3953 bnx2x_cl45_read(bp, phy,
3954 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &val2);
3955 /* clear LASI indication*/
3956 bnx2x_cl45_read(bp, phy,
3957 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
3958 bnx2x_cl45_read(bp, phy,
3959 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val2);
3960 DP(NETIF_MSG_LINK, "8706/8726 LASI status 0x%x--> 0x%x\n", val1, val2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003961
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003962 bnx2x_cl45_read(bp, phy,
3963 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD, &rx_sd);
3964 bnx2x_cl45_read(bp, phy,
3965 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &pcs_status);
3966 bnx2x_cl45_read(bp, phy,
3967 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &val2);
3968 bnx2x_cl45_read(bp, phy,
3969 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &val2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003970
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003971 DP(NETIF_MSG_LINK, "8706/8726 rx_sd 0x%x pcs_status 0x%x 1Gbps"
3972 " link_status 0x%x\n", rx_sd, pcs_status, val2);
3973 /* link is up if both bit 0 of pmd_rx_sd and
3974 * bit 0 of pcs_status are set, or if the autoneg bit
3975 * 1 is set
3976 */
3977 link_up = ((rx_sd & pcs_status & 0x1) || (val2 & (1<<1)));
3978 if (link_up) {
3979 if (val2 & (1<<1))
3980 vars->line_speed = SPEED_1000;
3981 else
3982 vars->line_speed = SPEED_10000;
3983 bnx2x_ext_phy_resolve_fc(phy, params, vars);
3984 }
3985 return link_up;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003986}
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003987
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003988static u8 bnx2x_8706_read_status(struct bnx2x_phy *phy,
3989 struct link_params *params,
3990 struct link_vars *vars)
3991{
3992 return bnx2x_8706_8726_read_status(phy, params, vars);
3993}
3994
3995static u8 bnx2x_8726_read_status(struct bnx2x_phy *phy,
3996 struct link_params *params,
3997 struct link_vars *vars)
3998{
3999 struct bnx2x *bp = params->bp;
4000 u16 val1;
4001 u8 link_up = bnx2x_8706_8726_read_status(phy, params, vars);
4002 if (link_up) {
4003 bnx2x_cl45_read(bp, phy,
4004 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER,
4005 &val1);
4006 if (val1 & (1<<15)) {
4007 DP(NETIF_MSG_LINK, "Tx is disabled\n");
4008 link_up = 0;
4009 vars->line_speed = 0;
4010 }
4011 }
4012 return link_up;
4013}
4014static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy,
4015 struct link_params *params,
4016 struct link_vars *vars)
4017
4018{
4019 struct bnx2x *bp = params->bp;
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004020 u8 link_up = 0;
4021 u16 link_status = 0;
4022 u16 rx_alarm_status, val1;
4023 /* Check the LASI */
4024 bnx2x_cl45_read(bp, phy,
4025 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM,
4026 &rx_alarm_status);
4027 vars->line_speed = 0;
4028 DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n", rx_alarm_status);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004029
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004030 bnx2x_cl45_read(bp, phy,
4031 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004032
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004033 DP(NETIF_MSG_LINK, "8727 LASI status 0x%x\n", val1);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004034
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004035 /* Clear MSG-OUT */
4036 bnx2x_cl45_read(bp, phy,
4037 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &val1);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004038
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004039 /**
4040 * If a module is present and there is need to check
4041 * for over current
4042 */
4043 if (!(phy->flags & FLAGS_NOC) && !(rx_alarm_status & (1<<5))) {
4044 /* Check over-current using 8727 GPIO0 input*/
4045 bnx2x_cl45_read(bp, phy,
4046 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_GPIO_CTRL,
4047 &val1);
4048
4049 if ((val1 & (1<<8)) == 0) {
4050 DP(NETIF_MSG_LINK, "8727 Power fault has been detected"
4051 " on port %d\n", params->port);
4052 netdev_err(bp->dev, "Error: Power fault on Port %d has"
4053 " been detected and the power to "
4054 "that SFP+ module has been removed"
4055 " to prevent failure of the card."
4056 " Please remove the SFP+ module and"
4057 " restart the system to clear this"
4058 " error.\n",
4059 params->port);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004060
4061 /*
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004062 * Disable all RX_ALARMs except for
4063 * mod_abs
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004064 */
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004065 bnx2x_cl45_write(bp, phy,
4066 MDIO_PMA_DEVAD,
4067 MDIO_PMA_REG_RX_ALARM_CTRL, (1<<5));
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004068
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004069 bnx2x_cl45_read(bp, phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004070 MDIO_PMA_DEVAD,
4071 MDIO_PMA_REG_PHY_IDENTIFIER, &val1);
4072 /* Wait for module_absent_event */
4073 val1 |= (1<<8);
4074 bnx2x_cl45_write(bp, phy,
4075 MDIO_PMA_DEVAD,
4076 MDIO_PMA_REG_PHY_IDENTIFIER, val1);
4077 /* Clear RX alarm */
4078 bnx2x_cl45_read(bp, phy,
4079 MDIO_PMA_DEVAD,
4080 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
4081 return 0;
4082 }
4083 } /* Over current check */
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004084
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004085 /* When module absent bit is set, check module */
4086 if (rx_alarm_status & (1<<5)) {
4087 bnx2x_8727_handle_mod_abs(phy, params);
4088 /* Enable all mod_abs and link detection bits */
4089 bnx2x_cl45_write(bp, phy,
4090 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
4091 ((1<<5) | (1<<2)));
4092 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004093
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004094 /* If transmitter is disabled, ignore false link up indication */
4095 bnx2x_cl45_read(bp, phy,
4096 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, &val1);
4097 if (val1 & (1<<15)) {
4098 DP(NETIF_MSG_LINK, "Tx is disabled\n");
4099 return 0;
4100 }
4101
4102 bnx2x_cl45_read(bp, phy,
4103 MDIO_PMA_DEVAD,
4104 MDIO_PMA_REG_8073_SPEED_LINK_STATUS, &link_status);
4105
4106 /* Bits 0..2 --> speed detected,
4107 bits 13..15--> link is down */
4108 if ((link_status & (1<<2)) && (!(link_status & (1<<15)))) {
4109 link_up = 1;
4110 vars->line_speed = SPEED_10000;
4111 } else if ((link_status & (1<<0)) && (!(link_status & (1<<13)))) {
4112 link_up = 1;
4113 vars->line_speed = SPEED_1000;
4114 DP(NETIF_MSG_LINK, "port %x: External link up in 1G\n",
4115 params->port);
4116 } else {
4117 link_up = 0;
4118 DP(NETIF_MSG_LINK, "port %x: External link is down\n",
4119 params->port);
4120 }
4121 if (link_up)
4122 bnx2x_ext_phy_resolve_fc(phy, params, vars);
4123 return link_up;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004124}
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004125
Yaniv Rosner7aa07112010-09-07 11:41:01 +00004126static void bnx2x_8073_resolve_fc(struct bnx2x_phy *phy,
4127 struct link_params *params,
4128 struct link_vars *vars)
4129{
4130 struct bnx2x *bp = params->bp;
4131 if (phy->req_line_speed == SPEED_10 ||
4132 phy->req_line_speed == SPEED_100) {
4133 vars->flow_ctrl = phy->req_flow_ctrl;
4134 return;
4135 }
4136
4137 if (bnx2x_ext_phy_resolve_fc(phy, params, vars) &&
4138 (vars->flow_ctrl == BNX2X_FLOW_CTRL_NONE)) {
4139 u16 pause_result;
4140 u16 ld_pause; /* local */
4141 u16 lp_pause; /* link partner */
4142 bnx2x_cl45_read(bp, phy,
4143 MDIO_AN_DEVAD,
4144 MDIO_AN_REG_CL37_FC_LD, &ld_pause);
4145
4146 bnx2x_cl45_read(bp, phy,
4147 MDIO_AN_DEVAD,
4148 MDIO_AN_REG_CL37_FC_LP, &lp_pause);
4149 pause_result = (ld_pause &
4150 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 5;
4151 pause_result |= (lp_pause &
4152 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 7;
4153
4154 bnx2x_pause_resolve(vars, pause_result);
4155 DP(NETIF_MSG_LINK, "Ext PHY CL37 pause result 0x%x\n",
4156 pause_result);
4157 }
4158}
4159
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004160static u8 bnx2x_8073_read_status(struct bnx2x_phy *phy,
4161 struct link_params *params,
4162 struct link_vars *vars)
4163{
4164 struct bnx2x *bp = params->bp;
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004165 u8 link_up = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004166 u16 val1, val2;
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004167 u16 link_status = 0;
4168 u16 an1000_status = 0;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00004169
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004170 bnx2x_cl45_read(bp, phy,
4171 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004172
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004173 DP(NETIF_MSG_LINK, "8703 LASI status 0x%x\n", val1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004174
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004175 /* clear the interrupt LASI status register */
4176 bnx2x_cl45_read(bp, phy,
4177 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val2);
4178 bnx2x_cl45_read(bp, phy,
4179 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val1);
4180 DP(NETIF_MSG_LINK, "807x PCS status 0x%x->0x%x\n", val2, val1);
4181 /* Clear MSG-OUT */
4182 bnx2x_cl45_read(bp, phy,
4183 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &val1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004184
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004185 /* Check the LASI */
4186 bnx2x_cl45_read(bp, phy,
4187 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &val2);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004188
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004189 DP(NETIF_MSG_LINK, "KR 0x9003 0x%x\n", val2);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004190
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004191 /* Check the link status */
4192 bnx2x_cl45_read(bp, phy,
4193 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val2);
4194 DP(NETIF_MSG_LINK, "KR PCS status 0x%x\n", val2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004195
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004196 bnx2x_cl45_read(bp, phy,
4197 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
4198 bnx2x_cl45_read(bp, phy,
4199 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
4200 link_up = ((val1 & 4) == 4);
4201 DP(NETIF_MSG_LINK, "PMA_REG_STATUS=0x%x\n", val1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004202
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004203 if (link_up &&
4204 ((phy->req_line_speed != SPEED_10000))) {
4205 if (bnx2x_8073_xaui_wa(bp, phy) != 0)
4206 return 0;
4207 }
4208 bnx2x_cl45_read(bp, phy,
4209 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &an1000_status);
4210 bnx2x_cl45_read(bp, phy,
4211 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &an1000_status);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004212
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004213 /* Check the link status on 1.1.2 */
4214 bnx2x_cl45_read(bp, phy,
4215 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
4216 bnx2x_cl45_read(bp, phy,
4217 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
4218 DP(NETIF_MSG_LINK, "KR PMA status 0x%x->0x%x,"
4219 "an_link_status=0x%x\n", val2, val1, an1000_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004220
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004221 link_up = (((val1 & 4) == 4) || (an1000_status & (1<<1)));
4222 if (link_up && bnx2x_8073_is_snr_needed(bp, phy)) {
4223 /* The SNR will improve about 2dbby
4224 changing the BW and FEE main tap.*/
4225 /* The 1st write to change FFE main
4226 tap is set before restart AN */
4227 /* Change PLL Bandwidth in EDC
4228 register */
4229 bnx2x_cl45_write(bp, phy,
4230 MDIO_PMA_DEVAD, MDIO_PMA_REG_PLL_BANDWIDTH,
4231 0x26BC);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004232
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004233 /* Change CDR Bandwidth in EDC register */
4234 bnx2x_cl45_write(bp, phy,
4235 MDIO_PMA_DEVAD, MDIO_PMA_REG_CDR_BANDWIDTH,
4236 0x0333);
4237 }
4238 bnx2x_cl45_read(bp, phy,
4239 MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
4240 &link_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004241
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004242 /* Bits 0..2 --> speed detected, bits 13..15--> link is down */
4243 if ((link_status & (1<<2)) && (!(link_status & (1<<15)))) {
4244 link_up = 1;
4245 vars->line_speed = SPEED_10000;
4246 DP(NETIF_MSG_LINK, "port %x: External link up in 10G\n",
4247 params->port);
4248 } else if ((link_status & (1<<1)) && (!(link_status & (1<<14)))) {
4249 link_up = 1;
4250 vars->line_speed = SPEED_2500;
4251 DP(NETIF_MSG_LINK, "port %x: External link up in 2.5G\n",
4252 params->port);
4253 } else if ((link_status & (1<<0)) && (!(link_status & (1<<13)))) {
4254 link_up = 1;
4255 vars->line_speed = SPEED_1000;
4256 DP(NETIF_MSG_LINK, "port %x: External link up in 1G\n",
4257 params->port);
4258 } else {
4259 link_up = 0;
4260 DP(NETIF_MSG_LINK, "port %x: External link is down\n",
4261 params->port);
4262 }
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004263
Yaniv Rosner7aa07112010-09-07 11:41:01 +00004264 if (link_up) {
4265 bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
4266 bnx2x_8073_resolve_fc(phy, params, vars);
4267 }
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004268 return link_up;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004269}
4270
4271static u8 bnx2x_7101_read_status(struct bnx2x_phy *phy,
4272 struct link_params *params,
4273 struct link_vars *vars)
4274{
4275 struct bnx2x *bp = params->bp;
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004276 u8 link_up;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004277 u16 val1, val2;
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004278 bnx2x_cl45_read(bp, phy,
4279 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val2);
4280 bnx2x_cl45_read(bp, phy,
4281 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
4282 DP(NETIF_MSG_LINK, "10G-base-T LASI status 0x%x->0x%x\n",
4283 val2, val1);
4284 bnx2x_cl45_read(bp, phy,
4285 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
4286 bnx2x_cl45_read(bp, phy,
4287 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
4288 DP(NETIF_MSG_LINK, "10G-base-T PMA status 0x%x->0x%x\n",
4289 val2, val1);
4290 link_up = ((val1 & 4) == 4);
4291 /* if link is up
4292 * print the AN outcome of the SFX7101 PHY
4293 */
4294 if (link_up) {
4295 bnx2x_cl45_read(bp, phy,
4296 MDIO_AN_DEVAD, MDIO_AN_REG_MASTER_STATUS,
4297 &val2);
4298 vars->line_speed = SPEED_10000;
4299 DP(NETIF_MSG_LINK, "SFX7101 AN status 0x%x->Master=%x\n",
4300 val2, (val2 & (1<<14)));
Yaniv Rosner7aa07112010-09-07 11:41:01 +00004301 bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
4302 bnx2x_ext_phy_resolve_fc(phy, params, vars);
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004303 }
4304 return link_up;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004305}
4306
4307static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy,
4308 struct link_params *params,
4309 struct link_vars *vars)
4310{
4311 struct bnx2x *bp = params->bp;
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004312 u16 val, val1, val2;
4313 u8 link_up = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004314
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004315 /* Check 10G-BaseT link status */
4316 /* Check PMD signal ok */
4317 bnx2x_cl45_read(bp, phy,
4318 MDIO_AN_DEVAD, 0xFFFA, &val1);
4319 bnx2x_cl45_read(bp, phy,
4320 MDIO_PMA_DEVAD, MDIO_PMA_REG_8481_PMD_SIGNAL,
4321 &val2);
4322 DP(NETIF_MSG_LINK, "BCM848xx: PMD_SIGNAL 1.a811 = 0x%x\n", val2);
4323
4324 /* Check link 10G */
4325 if (val2 & (1<<11)) {
4326 vars->line_speed = SPEED_10000;
4327 link_up = 1;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00004328 bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004329 } else { /* Check Legacy speed link */
4330 u16 legacy_status, legacy_speed;
4331
4332 /* Enable expansion register 0x42 (Operation mode status) */
4333 bnx2x_cl45_write(bp, phy,
4334 MDIO_AN_DEVAD,
4335 MDIO_AN_REG_8481_EXPANSION_REG_ACCESS, 0xf42);
4336
4337 /* Get legacy speed operation status */
4338 bnx2x_cl45_read(bp, phy,
4339 MDIO_AN_DEVAD,
4340 MDIO_AN_REG_8481_EXPANSION_REG_RD_RW,
4341 &legacy_status);
4342
4343 DP(NETIF_MSG_LINK, "Legacy speed status"
4344 " = 0x%x\n", legacy_status);
4345 link_up = ((legacy_status & (1<<11)) == (1<<11));
4346 if (link_up) {
4347 legacy_speed = (legacy_status & (3<<9));
4348 if (legacy_speed == (0<<9))
4349 vars->line_speed = SPEED_10;
4350 else if (legacy_speed == (1<<9))
4351 vars->line_speed = SPEED_100;
4352 else if (legacy_speed == (2<<9))
4353 vars->line_speed = SPEED_1000;
4354 else /* Should not happen */
4355 vars->line_speed = 0;
4356
4357 if (legacy_status & (1<<8))
4358 vars->duplex = DUPLEX_FULL;
4359 else
4360 vars->duplex = DUPLEX_HALF;
4361
4362 DP(NETIF_MSG_LINK, "Link is up in %dMbps,"
4363 " is_duplex_full= %d\n", vars->line_speed,
4364 (vars->duplex == DUPLEX_FULL));
4365
4366 /* Check legacy speed AN resolution */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004367 bnx2x_cl45_read(bp, phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004368 MDIO_AN_DEVAD,
4369 MDIO_AN_REG_8481_LEGACY_MII_STATUS,
4370 &val);
4371 if (val & (1<<5))
4372 vars->link_status |=
4373 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004374 bnx2x_cl45_read(bp, phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004375 MDIO_AN_DEVAD,
4376 MDIO_AN_REG_8481_LEGACY_AN_EXPANSION,
4377 &val);
4378 if ((val & (1<<0)) == 0)
4379 vars->link_status |=
4380 LINK_STATUS_PARALLEL_DETECTION_USED;
4381 }
4382 }
Yaniv Rosner7aa07112010-09-07 11:41:01 +00004383 if (link_up) {
4384 DP(NETIF_MSG_LINK, "BCM84823: link speed is %d\n",
4385 vars->line_speed);
4386 bnx2x_ext_phy_resolve_fc(phy, params, vars);
4387 }
4388
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004389 return link_up;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004390}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004391static void bnx2x_link_int_enable(struct link_params *params)
4392{
4393 u8 port = params->port;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004394 u32 mask;
4395 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00004396
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004397 /* setting the status to report on link up
4398 for either XGXS or SerDes */
4399
4400 if (params->switch_cfg == SWITCH_CFG_10G) {
4401 mask = (NIG_MASK_XGXS0_LINK10G |
4402 NIG_MASK_XGXS0_LINK_STATUS);
4403 DP(NETIF_MSG_LINK, "enabled XGXS interrupt\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004404 if (!(SINGLE_MEDIA_DIRECT(params)) &&
4405 params->phy[INT_PHY].type !=
4406 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004407 mask |= NIG_MASK_MI_INT;
4408 DP(NETIF_MSG_LINK, "enabled external phy int\n");
4409 }
4410
4411 } else { /* SerDes */
4412 mask = NIG_MASK_SERDES0_LINK_STATUS;
4413 DP(NETIF_MSG_LINK, "enabled SerDes interrupt\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004414 if (!(SINGLE_MEDIA_DIRECT(params)) &&
4415 params->phy[INT_PHY].type !=
4416 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_NOT_CONN) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004417 mask |= NIG_MASK_MI_INT;
4418 DP(NETIF_MSG_LINK, "enabled external phy int\n");
4419 }
4420 }
4421 bnx2x_bits_en(bp,
4422 NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
4423 mask);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00004424
4425 DP(NETIF_MSG_LINK, "port %x, is_xgxs %x, int_status 0x%x\n", port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004426 (params->switch_cfg == SWITCH_CFG_10G),
4427 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004428 DP(NETIF_MSG_LINK, " int_mask 0x%x, MI_INT %x, SERDES_LINK %x\n",
4429 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
4430 REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
4431 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS+port*0x3c));
4432 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
4433 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
4434 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
4435}
4436
Eilon Greenstein2f904462009-08-12 08:22:16 +00004437static void bnx2x_8481_rearm_latch_signal(struct bnx2x *bp, u8 port,
4438 u8 is_mi_int)
4439{
4440 u32 latch_status = 0, is_mi_int_status;
4441 /* Disable the MI INT ( external phy int )
4442 * by writing 1 to the status register. Link down indication
4443 * is high-active-signal, so in this case we need to write the
4444 * status to clear the XOR
4445 */
4446 /* Read Latched signals */
4447 latch_status = REG_RD(bp,
4448 NIG_REG_LATCH_STATUS_0 + port*8);
4449 is_mi_int_status = REG_RD(bp,
4450 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4);
4451 DP(NETIF_MSG_LINK, "original_signal = 0x%x, nig_status = 0x%x,"
4452 "latch_status = 0x%x\n",
4453 is_mi_int, is_mi_int_status, latch_status);
4454 /* Handle only those with latched-signal=up.*/
4455 if (latch_status & 1) {
4456 /* For all latched-signal=up,Write original_signal to status */
4457 if (is_mi_int)
4458 bnx2x_bits_en(bp,
4459 NIG_REG_STATUS_INTERRUPT_PORT0
4460 + port*4,
4461 NIG_STATUS_EMAC0_MI_INT);
4462 else
4463 bnx2x_bits_dis(bp,
4464 NIG_REG_STATUS_INTERRUPT_PORT0
4465 + port*4,
4466 NIG_STATUS_EMAC0_MI_INT);
4467 /* For all latched-signal=up : Re-Arm Latch signals */
4468 REG_WR(bp, NIG_REG_LATCH_STATUS_0 + port*8,
4469 (latch_status & 0xfffe) | (latch_status & 1));
4470 }
4471}
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004472
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004473/*
4474 * link management
4475 */
4476static void bnx2x_link_int_ack(struct link_params *params,
Eilon Greenstein2f904462009-08-12 08:22:16 +00004477 struct link_vars *vars, u8 is_10g,
4478 u8 is_mi_int)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004479{
4480 struct bnx2x *bp = params->bp;
4481 u8 port = params->port;
4482
4483 /* first reset all status
4484 * we assume only one line will be change at a time */
4485 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
4486 (NIG_STATUS_XGXS0_LINK10G |
4487 NIG_STATUS_XGXS0_LINK_STATUS |
4488 NIG_STATUS_SERDES0_LINK_STATUS));
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004489 if ((params->phy[EXT_PHY1].type
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02004490 == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481) ||
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004491 (params->phy[EXT_PHY1].type
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02004492 == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823)) {
Eilon Greenstein2f904462009-08-12 08:22:16 +00004493 bnx2x_8481_rearm_latch_signal(bp, port, is_mi_int);
4494 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004495 if (vars->phy_link_up) {
4496 if (is_10g) {
4497 /* Disable the 10G link interrupt
4498 * by writing 1 to the status register
4499 */
4500 DP(NETIF_MSG_LINK, "10G XGXS phy link up\n");
4501 bnx2x_bits_en(bp,
4502 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
4503 NIG_STATUS_XGXS0_LINK10G);
4504
4505 } else if (params->switch_cfg == SWITCH_CFG_10G) {
4506 /* Disable the link interrupt
4507 * by writing 1 to the relevant lane
4508 * in the status register
4509 */
4510 u32 ser_lane = ((params->lane_config &
4511 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
4512 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
4513
Eilon Greenstein2f904462009-08-12 08:22:16 +00004514 DP(NETIF_MSG_LINK, "%d speed XGXS phy link up\n",
4515 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004516 bnx2x_bits_en(bp,
4517 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
4518 ((1 << ser_lane) <<
4519 NIG_STATUS_XGXS0_LINK_STATUS_SIZE));
4520
4521 } else { /* SerDes */
4522 DP(NETIF_MSG_LINK, "SerDes phy link up\n");
4523 /* Disable the link interrupt
4524 * by writing 1 to the status register
4525 */
4526 bnx2x_bits_en(bp,
4527 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
4528 NIG_STATUS_SERDES0_LINK_STATUS);
4529 }
4530
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004531 }
4532}
4533
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004534static u8 bnx2x_7101_format_ver(u32 spirom_ver, u8 *str, u16 *len)
4535{
4536 if (*len < 5)
4537 return -EINVAL;
4538 str[0] = (spirom_ver & 0xFF);
4539 str[1] = (spirom_ver & 0xFF00) >> 8;
4540 str[2] = (spirom_ver & 0xFF0000) >> 16;
4541 str[3] = (spirom_ver & 0xFF000000) >> 24;
4542 str[4] = '\0';
4543 *len -= 5;
4544 return 0;
4545}
4546
4547static u8 bnx2x_format_ver(u32 num, u8 *str, u16 *len)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004548{
4549 u8 *str_ptr = str;
4550 u32 mask = 0xf0000000;
4551 u8 shift = 8*4;
4552 u8 digit;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004553 if (*len < 10) {
Frederik Schwarzer025dfda2008-10-16 19:02:37 +02004554 /* Need more than 10chars for this format */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004555 *str_ptr = '\0';
4556 return -EINVAL;
4557 }
4558 while (shift > 0) {
4559
4560 shift -= 4;
4561 digit = ((num & mask) >> shift);
4562 if (digit < 0xa)
4563 *str_ptr = digit + '0';
4564 else
4565 *str_ptr = digit - 0xa + 'a';
4566 str_ptr++;
4567 mask = mask >> 4;
4568 if (shift == 4*4) {
4569 *str_ptr = ':';
4570 str_ptr++;
4571 }
4572 }
4573 *str_ptr = '\0';
4574 return 0;
4575}
4576
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004577static u8 bnx2x_848xx_format_ver(u32 raw_ver, u8 *str, u16 *len)
4578{
4579 u8 status = 0;
4580 u32 spirom_ver;
4581 spirom_ver = ((raw_ver & 0xF80) >> 7) << 16 | (raw_ver & 0x7F);
4582 status = bnx2x_format_ver(spirom_ver, str, len);
4583 return status;
4584}
4585
4586static u8 bnx2x_null_format_ver(u32 spirom_ver, u8 *str, u16 *len)
4587{
4588 str[0] = '\0';
4589 (*len)--;
4590 return 0;
4591}
4592
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004593u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
4594 u8 *version, u16 len)
4595{
Julia Lawall0376d5b2009-07-19 05:26:35 +00004596 struct bnx2x *bp;
Eilon Greensteina35da8d2009-02-12 08:37:02 +00004597 u32 spirom_ver = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004598 u8 status = 0;
4599 u8 *ver_p = version;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004600 if (version == NULL || params == NULL)
4601 return -EINVAL;
Julia Lawall0376d5b2009-07-19 05:26:35 +00004602 bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004603
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004604 /* Extract first external phy*/
4605 version[0] = '\0';
4606 spirom_ver = REG_RD(bp, params->phy[EXT_PHY1].ver_addr);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00004607
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004608 if (params->phy[EXT_PHY1].format_fw_ver)
4609 status |= params->phy[EXT_PHY1].format_fw_ver(spirom_ver,
4610 ver_p,
4611 &len);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004612 return status;
4613}
4614
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004615static void bnx2x_set_xgxs_loopback(struct bnx2x_phy *phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004616 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004617{
4618 u8 port = params->port;
4619 struct bnx2x *bp = params->bp;
4620
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004621 if (phy->req_line_speed != SPEED_1000) {
Eilon Greenstein6378c022008-08-13 15:59:25 -07004622 u32 md_devad;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004623
4624 DP(NETIF_MSG_LINK, "XGXS 10G loopback enable\n");
4625
4626 /* change the uni_phy_addr in the nig */
4627 md_devad = REG_RD(bp, (NIG_REG_XGXS0_CTRL_MD_DEVAD +
4628 port*0x18));
4629
4630 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, 0x5);
4631
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004632 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004633 5,
4634 (MDIO_REG_BANK_AER_BLOCK +
4635 (MDIO_AER_BLOCK_AER_REG & 0xf)),
4636 0x2800);
4637
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004638 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004639 5,
4640 (MDIO_REG_BANK_CL73_IEEEB0 +
4641 (MDIO_CL73_IEEEB0_CL73_AN_CONTROL & 0xf)),
4642 0x6041);
Eilon Greenstein38582762009-01-14 06:44:16 +00004643 msleep(200);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004644 /* set aer mmd back */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004645 bnx2x_set_aer_mmd(params, phy);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004646
4647 /* and md_devad */
4648 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
4649 md_devad);
4650
4651 } else {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004652 u16 mii_ctrl;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004653 DP(NETIF_MSG_LINK, "XGXS 1G loopback enable\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004654 bnx2x_cl45_read(bp, phy, 5,
4655 (MDIO_REG_BANK_COMBO_IEEE0 +
4656 (MDIO_COMBO_IEEE0_MII_CONTROL & 0xf)),
4657 &mii_ctrl);
4658 bnx2x_cl45_write(bp, phy, 5,
4659 (MDIO_REG_BANK_COMBO_IEEE0 +
4660 (MDIO_COMBO_IEEE0_MII_CONTROL & 0xf)),
4661 mii_ctrl |
4662 MDIO_COMBO_IEEO_MII_CONTROL_LOOPBACK);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004663 }
4664}
4665
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004666static void bnx2x_8726_config_loopback(struct bnx2x_phy *phy,
4667 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004668{
4669 struct bnx2x *bp = params->bp;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004670 DP(NETIF_MSG_LINK, "PMA/PMD ext_phy_loopback: 8726\n");
4671 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x0001);
4672}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004673
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004674static void bnx2x_7101_config_loopback(struct bnx2x_phy *phy,
4675 struct link_params *params)
4676{
4677 struct bnx2x *bp = params->bp;
4678 /* SFX7101_XGXS_TEST1 */
4679 bnx2x_cl45_write(bp, phy,
4680 MDIO_XS_DEVAD, MDIO_XS_SFX7101_XGXS_TEST1, 0x100);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004681}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004682/*
4683 *------------------------------------------------------------------------
4684 * bnx2x_override_led_value -
4685 *
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004686 * Override the led value of the requested led
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004687 *
4688 *------------------------------------------------------------------------
4689 */
4690u8 bnx2x_override_led_value(struct bnx2x *bp, u8 port,
4691 u32 led_idx, u32 value)
4692{
4693 u32 reg_val;
4694
4695 /* If port 0 then use EMAC0, else use EMAC1*/
4696 u32 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
4697
4698 DP(NETIF_MSG_LINK,
4699 "bnx2x_override_led_value() port %x led_idx %d value %d\n",
4700 port, led_idx, value);
4701
4702 switch (led_idx) {
4703 case 0: /* 10MB led */
4704 /* Read the current value of the LED register in
4705 the EMAC block */
4706 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
4707 /* Set the OVERRIDE bit to 1 */
4708 reg_val |= EMAC_LED_OVERRIDE;
4709 /* If value is 1, set the 10M_OVERRIDE bit,
4710 otherwise reset it.*/
4711 reg_val = (value == 1) ? (reg_val | EMAC_LED_10MB_OVERRIDE) :
4712 (reg_val & ~EMAC_LED_10MB_OVERRIDE);
4713 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
4714 break;
4715 case 1: /*100MB led */
4716 /*Read the current value of the LED register in
4717 the EMAC block */
4718 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
4719 /* Set the OVERRIDE bit to 1 */
4720 reg_val |= EMAC_LED_OVERRIDE;
4721 /* If value is 1, set the 100M_OVERRIDE bit,
4722 otherwise reset it.*/
4723 reg_val = (value == 1) ? (reg_val | EMAC_LED_100MB_OVERRIDE) :
4724 (reg_val & ~EMAC_LED_100MB_OVERRIDE);
4725 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
4726 break;
4727 case 2: /* 1000MB led */
4728 /* Read the current value of the LED register in the
4729 EMAC block */
4730 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
4731 /* Set the OVERRIDE bit to 1 */
4732 reg_val |= EMAC_LED_OVERRIDE;
4733 /* If value is 1, set the 1000M_OVERRIDE bit, otherwise
4734 reset it. */
4735 reg_val = (value == 1) ? (reg_val | EMAC_LED_1000MB_OVERRIDE) :
4736 (reg_val & ~EMAC_LED_1000MB_OVERRIDE);
4737 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
4738 break;
4739 case 3: /* 2500MB led */
4740 /* Read the current value of the LED register in the
4741 EMAC block*/
4742 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
4743 /* Set the OVERRIDE bit to 1 */
4744 reg_val |= EMAC_LED_OVERRIDE;
4745 /* If value is 1, set the 2500M_OVERRIDE bit, otherwise
4746 reset it.*/
4747 reg_val = (value == 1) ? (reg_val | EMAC_LED_2500MB_OVERRIDE) :
4748 (reg_val & ~EMAC_LED_2500MB_OVERRIDE);
4749 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
4750 break;
4751 case 4: /*10G led */
4752 if (port == 0) {
4753 REG_WR(bp, NIG_REG_LED_10G_P0,
4754 value);
4755 } else {
4756 REG_WR(bp, NIG_REG_LED_10G_P1,
4757 value);
4758 }
4759 break;
4760 case 5: /* TRAFFIC led */
4761 /* Find if the traffic control is via BMAC or EMAC */
4762 if (port == 0)
4763 reg_val = REG_RD(bp, NIG_REG_NIG_EMAC0_EN);
4764 else
4765 reg_val = REG_RD(bp, NIG_REG_NIG_EMAC1_EN);
4766
4767 /* Override the traffic led in the EMAC:*/
4768 if (reg_val == 1) {
4769 /* Read the current value of the LED register in
4770 the EMAC block */
4771 reg_val = REG_RD(bp, emac_base +
4772 EMAC_REG_EMAC_LED);
4773 /* Set the TRAFFIC_OVERRIDE bit to 1 */
4774 reg_val |= EMAC_LED_OVERRIDE;
4775 /* If value is 1, set the TRAFFIC bit, otherwise
4776 reset it.*/
4777 reg_val = (value == 1) ? (reg_val | EMAC_LED_TRAFFIC) :
4778 (reg_val & ~EMAC_LED_TRAFFIC);
4779 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
4780 } else { /* Override the traffic led in the BMAC: */
4781 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
4782 + port*4, 1);
4783 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 + port*4,
4784 value);
4785 }
4786 break;
4787 default:
4788 DP(NETIF_MSG_LINK,
4789 "bnx2x_override_led_value() unknown led index %d "
4790 "(should be 0-5)\n", led_idx);
4791 return -EINVAL;
4792 }
4793
4794 return 0;
4795}
4796
4797
Yaniv Rosner7846e472009-11-05 19:18:07 +02004798u8 bnx2x_set_led(struct link_params *params, u8 mode, u32 speed)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004799{
Yaniv Rosner7846e472009-11-05 19:18:07 +02004800 u8 port = params->port;
4801 u16 hw_led_mode = params->hw_led_mode;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004802 u8 rc = 0;
Eilon Greenstein345b5d52008-08-13 15:58:12 -07004803 u32 tmp;
4804 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Yaniv Rosner7846e472009-11-05 19:18:07 +02004805 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004806 DP(NETIF_MSG_LINK, "bnx2x_set_led: port %x, mode %d\n", port, mode);
4807 DP(NETIF_MSG_LINK, "speed 0x%x, hw_led_mode 0x%x\n",
4808 speed, hw_led_mode);
4809 switch (mode) {
4810 case LED_MODE_OFF:
4811 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 0);
4812 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
4813 SHARED_HW_CFG_LED_MAC1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07004814
4815 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07004816 EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp | EMAC_LED_OVERRIDE));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004817 break;
4818
4819 case LED_MODE_OPER:
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004820 if (SINGLE_MEDIA_DIRECT(params)) {
Yaniv Rosner7846e472009-11-05 19:18:07 +02004821 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0);
4822 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1);
4823 } else {
4824 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
4825 hw_led_mode);
4826 }
4827
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004828 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 +
4829 port*4, 0);
4830 /* Set blinking rate to ~15.9Hz */
4831 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4,
4832 LED_BLINK_RATE_VAL);
4833 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 +
4834 port*4, 1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07004835 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07004836 EMAC_WR(bp, EMAC_REG_EMAC_LED,
Eilon Greenstein345b5d52008-08-13 15:58:12 -07004837 (tmp & (~EMAC_LED_OVERRIDE)));
4838
Yaniv Rosner7846e472009-11-05 19:18:07 +02004839 if (CHIP_IS_E1(bp) &&
Eilon Greenstein34f80b02008-06-23 20:33:01 -07004840 ((speed == SPEED_2500) ||
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004841 (speed == SPEED_1000) ||
4842 (speed == SPEED_100) ||
4843 (speed == SPEED_10))) {
4844 /* On Everest 1 Ax chip versions for speeds less than
4845 10G LED scheme is different */
4846 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
4847 + port*4, 1);
4848 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 +
4849 port*4, 0);
4850 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_TRAFFIC_P0 +
4851 port*4, 1);
4852 }
4853 break;
4854
4855 default:
4856 rc = -EINVAL;
4857 DP(NETIF_MSG_LINK, "bnx2x_set_led: Invalid led mode %d\n",
4858 mode);
4859 break;
4860 }
4861 return rc;
4862
4863}
4864
4865u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars)
4866{
4867 struct bnx2x *bp = params->bp;
4868 u16 gp_status = 0;
4869
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004870 CL45_RD_OVER_CL22(bp, &params->phy[INT_PHY],
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004871 MDIO_REG_BANK_GP_STATUS,
4872 MDIO_GP_STATUS_TOP_AN_STATUS1,
4873 &gp_status);
4874 /* link is up only if both local phy and external phy are up */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004875 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) {
4876 u8 ext_phy_link_up = 1;
4877 struct link_vars temp_vars;
4878 if (params->phy[EXT_PHY1].read_status)
4879 ext_phy_link_up &=
4880 params->phy[EXT_PHY1].read_status(
4881 &params->phy[EXT_PHY1],
4882 params, &temp_vars);
4883 if (ext_phy_link_up)
4884 return 0;
4885 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004886
4887 return -ESRCH;
4888}
4889
4890static u8 bnx2x_link_initialize(struct link_params *params,
4891 struct link_vars *vars)
4892{
4893 struct bnx2x *bp = params->bp;
4894 u8 port = params->port;
4895 u8 rc = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004896 u8 phy_index, non_ext_phy;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004897 struct bnx2x_phy *ext_phy = &params->phy[EXT_PHY1];
4898 struct bnx2x_phy *int_phy = &params->phy[INT_PHY];
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004899 /* Activate the external PHY */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004900
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004901 bnx2x_set_aer_mmd(params, int_phy);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004902
4903 if (vars->phy_flags & PHY_XGXS_FLAG)
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004904 bnx2x_set_master_ln(params, int_phy);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004905
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004906 rc = bnx2x_reset_unicore(params, int_phy,
4907 int_phy->type ==
4908 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004909 /* reset the SerDes and wait for reset bit return low */
4910 if (rc != 0)
4911 return rc;
4912
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004913 bnx2x_set_aer_mmd(params, int_phy);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004914
4915 /* setting the masterLn_def again after the reset */
4916 if (vars->phy_flags & PHY_XGXS_FLAG) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004917 bnx2x_set_master_ln(params, int_phy);
4918 bnx2x_set_swap_lanes(params, int_phy);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004919 }
4920
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004921 if (vars->phy_flags & PHY_XGXS_FLAG) {
Eilon Greenstein44722d12009-01-14 06:44:21 +00004922 if ((params->req_line_speed &&
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004923 ((params->req_line_speed == SPEED_100) ||
Eilon Greenstein44722d12009-01-14 06:44:21 +00004924 (params->req_line_speed == SPEED_10))) ||
4925 (!params->req_line_speed &&
4926 (params->speed_cap_mask >=
4927 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL) &&
4928 (params->speed_cap_mask <
4929 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
4930 )) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004931 vars->phy_flags |= PHY_SGMII_FLAG;
4932 } else {
4933 vars->phy_flags &= ~PHY_SGMII_FLAG;
4934 }
4935 }
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004936 /* In case of external phy existance, the line speed would be the
4937 line speed linked up by the external phy. In case it is direct only,
4938 then the line_speed during initialization will be equal to the
4939 req_line_speed*/
4940 vars->line_speed = params->req_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004941
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004942 bnx2x_calc_ieee_aneg_adv(int_phy, params, &vars->ieee_fc);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004943
4944 /* init ext phy and enable link state int */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004945 non_ext_phy = ((ext_phy->type ==
4946 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ||
Eilon Greenstein8660d8c2009-03-02 08:01:02 +00004947 (params->loopback_mode == LOOPBACK_XGXS_10));
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004948
4949 if (non_ext_phy ||
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004950 (ext_phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) ||
4951 (ext_phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706) ||
4952 (ext_phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) ||
Eilon Greenstein8660d8c2009-03-02 08:01:02 +00004953 (params->loopback_mode == LOOPBACK_EXT_PHY)) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004954 if (vars->line_speed == SPEED_AUTO_NEG)
4955 bnx2x_set_parallel_detection(int_phy, params);
4956 bnx2x_init_internal_phy(int_phy, params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004957 }
4958
4959 if (!non_ext_phy)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004960 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
4961 phy_index++) {
4962 params->phy[phy_index].config_init(
4963 &params->phy[phy_index],
4964 params, vars);
4965 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004966
4967 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004968 (NIG_STATUS_XGXS0_LINK10G |
4969 NIG_STATUS_XGXS0_LINK_STATUS |
4970 NIG_STATUS_SERDES0_LINK_STATUS));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004971
4972 return rc;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004973}
4974
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004975static void set_phy_vars(struct link_params *params)
4976{
4977 struct bnx2x *bp = params->bp;
4978 u8 actual_phy_idx, phy_index;
4979
4980 for (phy_index = INT_PHY; phy_index < params->num_phys;
4981 phy_index++) {
4982
4983 actual_phy_idx = phy_index;
4984 params->phy[actual_phy_idx].req_flow_ctrl =
4985 params->req_flow_ctrl;
4986
4987 params->phy[actual_phy_idx].req_line_speed =
4988 params->req_line_speed;
4989
4990 params->phy[actual_phy_idx].speed_cap_mask =
4991 params->speed_cap_mask;
4992
4993 params->phy[actual_phy_idx].req_duplex =
4994 params->req_duplex;
4995
4996 DP(NETIF_MSG_LINK, "req_flow_ctrl %x, req_line_speed %x,"
4997 " speed_cap_mask %x\n",
4998 params->phy[actual_phy_idx].req_flow_ctrl,
4999 params->phy[actual_phy_idx].req_line_speed,
5000 params->phy[actual_phy_idx].speed_cap_mask);
5001 }
5002}
5003
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005004u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
5005{
5006 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005007 u32 val;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005008
5009 DP(NETIF_MSG_LINK, "Phy Initialization started\n");
5010 DP(NETIF_MSG_LINK, "req_speed %d, req_flowctrl %d\n",
5011 params->req_line_speed, params->req_flow_ctrl);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005012 vars->link_status = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005013 vars->phy_link_up = 0;
5014 vars->link_up = 0;
5015 vars->line_speed = 0;
5016 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08005017 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005018 vars->mac_type = MAC_TYPE_NONE;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005019 vars->phy_flags = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005020
5021 /* disable attentions */
5022 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4,
5023 (NIG_MASK_XGXS0_LINK_STATUS |
5024 NIG_MASK_XGXS0_LINK10G |
5025 NIG_MASK_SERDES0_LINK_STATUS |
5026 NIG_MASK_MI_INT));
5027
5028 bnx2x_emac_init(params, vars);
5029
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005030 if (params->num_phys == 0) {
5031 DP(NETIF_MSG_LINK, "No phy found for initialization !!\n");
5032 return -EINVAL;
5033 }
5034 set_phy_vars(params);
5035
5036 DP(NETIF_MSG_LINK, "Num of phys on board: %d\n", params->num_phys);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005037 if (CHIP_REV_IS_FPGA(bp)) {
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005038
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005039 vars->link_up = 1;
5040 vars->line_speed = SPEED_10000;
5041 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08005042 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005043 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
Eilon Greenstein34f80b02008-06-23 20:33:01 -07005044 /* enable on E1.5 FPGA */
5045 if (CHIP_IS_E1H(bp)) {
5046 vars->flow_ctrl |=
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005047 (BNX2X_FLOW_CTRL_TX |
5048 BNX2X_FLOW_CTRL_RX);
Eilon Greenstein34f80b02008-06-23 20:33:01 -07005049 vars->link_status |=
5050 (LINK_STATUS_TX_FLOW_CONTROL_ENABLED |
5051 LINK_STATUS_RX_FLOW_CONTROL_ENABLED);
5052 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005053
5054 bnx2x_emac_enable(params, vars, 0);
5055 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
5056 /* disable drain */
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005057 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005058
5059 /* update shared memory */
5060 bnx2x_update_mng(params, vars->link_status);
5061
5062 return 0;
5063
5064 } else
5065 if (CHIP_REV_IS_EMUL(bp)) {
5066
5067 vars->link_up = 1;
5068 vars->line_speed = SPEED_10000;
5069 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08005070 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005071 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
5072
5073 bnx2x_bmac_enable(params, vars, 0);
5074
5075 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
5076 /* Disable drain */
5077 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
5078 + params->port*4, 0);
5079
5080 /* update shared memory */
5081 bnx2x_update_mng(params, vars->link_status);
5082
5083 return 0;
5084
5085 } else
5086 if (params->loopback_mode == LOOPBACK_BMAC) {
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005087
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005088 vars->link_up = 1;
5089 vars->line_speed = SPEED_10000;
5090 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08005091 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005092 vars->mac_type = MAC_TYPE_BMAC;
5093
5094 vars->phy_flags = PHY_XGXS_FLAG;
5095
5096 bnx2x_phy_deassert(params, vars->phy_flags);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005097
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005098 /* set bmac loopback */
5099 bnx2x_bmac_enable(params, vars, 1);
5100
5101 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
5102 params->port*4, 0);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005103
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005104 } else if (params->loopback_mode == LOOPBACK_EMAC) {
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005105
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005106 vars->link_up = 1;
5107 vars->line_speed = SPEED_1000;
5108 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08005109 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005110 vars->mac_type = MAC_TYPE_EMAC;
5111
5112 vars->phy_flags = PHY_XGXS_FLAG;
5113
5114 bnx2x_phy_deassert(params, vars->phy_flags);
5115 /* set bmac loopback */
5116 bnx2x_emac_enable(params, vars, 1);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005117 bnx2x_emac_program(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005118 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
5119 params->port*4, 0);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005120
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005121 } else if ((params->loopback_mode == LOOPBACK_XGXS_10) ||
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005122 (params->loopback_mode == LOOPBACK_EXT_PHY)) {
5123
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005124 vars->link_up = 1;
5125 vars->line_speed = SPEED_10000;
5126 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08005127 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005128
5129 vars->phy_flags = PHY_XGXS_FLAG;
5130
5131 val = REG_RD(bp,
5132 NIG_REG_XGXS0_CTRL_PHY_ADDR+
5133 params->port*0x18);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005134
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005135 bnx2x_phy_deassert(params, vars->phy_flags);
5136 bnx2x_link_initialize(params, vars);
5137
5138 vars->mac_type = MAC_TYPE_BMAC;
5139
5140 bnx2x_bmac_enable(params, vars, 0);
5141
5142 if (params->loopback_mode == LOOPBACK_XGXS_10) {
5143 /* set 10G XGXS loopback */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005144 params->phy[INT_PHY].config_loopback(
5145 &params->phy[INT_PHY],
5146 params);
5147
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005148 } else {
5149 /* set external phy loopback */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005150 u8 phy_index;
5151 for (phy_index = EXT_PHY1;
5152 phy_index < params->num_phys; phy_index++) {
5153 if (params->phy[phy_index].config_loopback)
5154 params->phy[phy_index].config_loopback(
5155 &params->phy[phy_index],
Yaniv Rosner62b29a52010-09-07 11:40:58 +00005156 params);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005157 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005158 }
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005159
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005160 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
5161 params->port*4, 0);
Eilon Greensteinba71d312009-07-21 05:47:49 +00005162
Yaniv Rosner7846e472009-11-05 19:18:07 +02005163 bnx2x_set_led(params, LED_MODE_OPER, vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005164 } else
5165 /* No loopback */
5166 {
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005167 if (params->switch_cfg == SWITCH_CFG_10G)
5168 vars->phy_flags = PHY_XGXS_FLAG;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005169 bnx2x_phy_deassert(params, vars->phy_flags);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005170 bnx2x_link_initialize(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005171 msleep(30);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005172 bnx2x_link_int_enable(params);
5173 }
5174 return 0;
5175}
5176
Eilon Greenstein589abe32009-02-12 08:36:55 +00005177
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005178static void bnx2x_8726_link_reset(struct bnx2x_phy *phy,
5179 struct link_params *params)
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005180{
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005181 struct bnx2x *bp = params->bp;
5182 DP(NETIF_MSG_LINK, "bnx2x_8726_link_reset port %d\n", params->port);
Eilon Greenstein589abe32009-02-12 08:36:55 +00005183 /* Set serial boot control for external load */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005184 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005185 MDIO_PMA_DEVAD,
5186 MDIO_PMA_REG_GEN_CTRL, 0x0001);
5187}
5188
5189static void bnx2x_8727_link_reset(struct bnx2x_phy *phy,
5190 struct link_params *params)
5191{
5192 struct bnx2x *bp = params->bp;
5193 /* Disable Transmitter */
5194 bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
5195}
5196static void bnx2x_8073_link_reset(struct bnx2x_phy *phy,
5197 struct link_params *params)
5198{
5199 struct bnx2x *bp = params->bp;
5200 u8 gpio_port;
5201 gpio_port = params->port;
5202 DP(NETIF_MSG_LINK, "Setting 8073 port %d into low power mode\n",
5203 gpio_port);
5204 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
5205 MISC_REGISTERS_GPIO_OUTPUT_LOW,
5206 gpio_port);
5207}
5208static void bnx2x_8481_link_reset(struct bnx2x_phy *phy,
5209 struct link_params *params)
5210{
5211 bnx2x_cl45_write(params->bp, phy,
5212 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x0000);
5213 bnx2x_cl45_write(params->bp, phy,
5214 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1);
5215}
5216
5217static void bnx2x_848x3_link_reset(struct bnx2x_phy *phy,
5218 struct link_params *params)
5219{
5220 struct bnx2x *bp = params->bp;
5221 u8 port = params->port;
5222 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
5223 MISC_REGISTERS_GPIO_OUTPUT_LOW,
5224 port);
5225}
5226
5227static void bnx2x_common_ext_link_reset(struct bnx2x_phy *phy,
5228 struct link_params *params)
5229{
5230 struct bnx2x *bp = params->bp;
5231 u8 gpio_port;
5232 /* HW reset */
5233 gpio_port = params->port;
5234 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
5235 MISC_REGISTERS_GPIO_OUTPUT_LOW,
5236 gpio_port);
5237 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
5238 MISC_REGISTERS_GPIO_OUTPUT_LOW,
5239 gpio_port);
5240 DP(NETIF_MSG_LINK, "reset external PHY\n");
5241}
5242
5243static void bnx2x_int_link_reset(struct bnx2x_phy *phy,
5244 struct link_params *params)
5245{
5246 /* reset the SerDes/XGXS */
5247 REG_WR(params->bp, GRCBASE_MISC +
5248 MISC_REGISTERS_RESET_REG_3_CLEAR,
5249 (0x1ff << (params->port*16)));
Eilon Greenstein589abe32009-02-12 08:36:55 +00005250}
5251
5252u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
5253 u8 reset_ext_phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005254{
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005255 struct bnx2x *bp = params->bp;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005256
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005257 u8 phy_index, port = params->port;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005258
Yaniv Rosnerd5cb9e92009-11-05 19:18:10 +02005259 DP(NETIF_MSG_LINK, "Resetting the link of port %d\n", port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005260 /* disable attentions */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005261 vars->link_status = 0;
5262 bnx2x_update_mng(params, vars->link_status);
5263 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
5264 (NIG_MASK_XGXS0_LINK_STATUS |
5265 NIG_MASK_XGXS0_LINK10G |
5266 NIG_MASK_SERDES0_LINK_STATUS |
5267 NIG_MASK_MI_INT));
5268
5269 /* activate nig drain */
5270 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
5271
5272 /* disable nig egress interface */
5273 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
5274 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
5275
5276 /* Stop BigMac rx */
5277 bnx2x_bmac_rx_disable(bp, port);
5278
5279 /* disable emac */
5280 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
5281
5282 msleep(10);
5283 /* The PHY reset is controled by GPIO 1
5284 * Hold it as vars low
5285 */
5286 /* clear link led */
Yaniv Rosner7846e472009-11-05 19:18:07 +02005287 bnx2x_set_led(params, LED_MODE_OFF, 0);
Eilon Greenstein589abe32009-02-12 08:36:55 +00005288 if (reset_ext_phy) {
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005289 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
5290 phy_index++) {
5291 if (params->phy[phy_index].link_reset)
5292 params->phy[phy_index].link_reset(
5293 &params->phy[phy_index],
5294 params);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005295 }
5296 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005297
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005298 if (params->phy[INT_PHY].link_reset)
5299 params->phy[INT_PHY].link_reset(
5300 &params->phy[INT_PHY], params);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005301 /* reset BigMac */
5302 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
5303 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
5304
5305 /* disable nig ingress interface */
5306 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0);
5307 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0);
5308 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
5309 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
5310 vars->link_up = 0;
5311 return 0;
5312}
5313
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005314
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005315static u8 bnx2x_update_link_down(struct link_params *params,
5316 struct link_vars *vars)
5317{
5318 struct bnx2x *bp = params->bp;
5319 u8 port = params->port;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005320
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005321 DP(NETIF_MSG_LINK, "Port %x: Link is down\n", port);
Yaniv Rosner7846e472009-11-05 19:18:07 +02005322 bnx2x_set_led(params, LED_MODE_OFF, 0);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005323
5324 /* indicate no mac active */
5325 vars->mac_type = MAC_TYPE_NONE;
5326
5327 /* update shared memory */
5328 vars->link_status = 0;
5329 vars->line_speed = 0;
5330 bnx2x_update_mng(params, vars->link_status);
5331
5332 /* activate nig drain */
5333 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
5334
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00005335 /* disable emac */
5336 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
5337
5338 msleep(10);
5339
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005340 /* reset BigMac */
5341 bnx2x_bmac_rx_disable(bp, params->port);
5342 REG_WR(bp, GRCBASE_MISC +
5343 MISC_REGISTERS_RESET_REG_2_CLEAR,
5344 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
5345 return 0;
5346}
5347
5348static u8 bnx2x_update_link_up(struct link_params *params,
5349 struct link_vars *vars,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005350 u8 link_10g)
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005351{
5352 struct bnx2x *bp = params->bp;
5353 u8 port = params->port;
5354 u8 rc = 0;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005355
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005356 vars->link_status |= LINK_STATUS_LINK_UP;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00005357 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
5358 vars->link_status |=
5359 LINK_STATUS_TX_FLOW_CONTROL_ENABLED;
5360
5361 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
5362 vars->link_status |=
5363 LINK_STATUS_RX_FLOW_CONTROL_ENABLED;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005364 if (link_10g) {
5365 bnx2x_bmac_enable(params, vars, 0);
Yaniv Rosner7846e472009-11-05 19:18:07 +02005366 bnx2x_set_led(params, LED_MODE_OPER, SPEED_10000);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005367 } else {
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005368 rc = bnx2x_emac_program(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005369
Yaniv Rosner0c786f02009-11-05 19:18:32 +02005370 bnx2x_emac_enable(params, vars, 0);
5371
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005372 /* AN complete? */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005373 if ((vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE)
5374 && (!(vars->phy_flags & PHY_SGMII_FLAG)) &&
5375 SINGLE_MEDIA_DIRECT(params))
5376 bnx2x_set_gmii_tx_driver(params);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005377 }
5378
5379 /* PBF - link up */
5380 rc |= bnx2x_pbf_update(params, vars->flow_ctrl,
5381 vars->line_speed);
5382
5383 /* disable drain */
5384 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 0);
5385
5386 /* update shared memory */
5387 bnx2x_update_mng(params, vars->link_status);
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00005388 msleep(20);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005389 return rc;
5390}
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005391/**
5392 * The bnx2x_link_update function should be called upon link
5393 * interrupt.
5394 * Link is considered up as follows:
5395 * - DIRECT_SINGLE_MEDIA - Only XGXS link (internal link) needs
5396 * to be up
5397 * - SINGLE_MEDIA - The link between the 577xx and the external
5398 * phy (XGXS) need to up as well as the external link of the
5399 * phy (PHY_EXT1)
5400 * - DUAL_MEDIA - The link between the 577xx and the first
5401 * external phy needs to be up, and at least one of the 2
5402 * external phy link must be up.
Yaniv Rosner62b29a52010-09-07 11:40:58 +00005403 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005404u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars)
5405{
5406 struct bnx2x *bp = params->bp;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005407 struct link_vars phy_vars[MAX_PHYS];
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005408 u8 port = params->port;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005409 u8 link_10g, phy_index;
5410 u8 ext_phy_link_up = 0, cur_link_up, rc = 0;
Eilon Greenstein2f904462009-08-12 08:22:16 +00005411 u8 is_mi_int = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005412 u16 ext_phy_line_speed = 0, prev_line_speed = vars->line_speed;
5413 u8 active_external_phy = INT_PHY;
5414 vars->link_status = 0;
5415 for (phy_index = INT_PHY; phy_index < params->num_phys;
5416 phy_index++) {
5417 phy_vars[phy_index].flow_ctrl = 0;
5418 phy_vars[phy_index].link_status = 0;
5419 phy_vars[phy_index].line_speed = 0;
5420 phy_vars[phy_index].duplex = DUPLEX_FULL;
5421 phy_vars[phy_index].phy_link_up = 0;
5422 phy_vars[phy_index].link_up = 0;
5423 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005424
5425 DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n",
Eilon Greenstein2f904462009-08-12 08:22:16 +00005426 port, (vars->phy_flags & PHY_XGXS_FLAG),
5427 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005428
Eilon Greenstein2f904462009-08-12 08:22:16 +00005429 is_mi_int = (u8)(REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT +
5430 port*0x18) > 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005431 DP(NETIF_MSG_LINK, "int_mask 0x%x MI_INT %x, SERDES_LINK %x\n",
Eilon Greenstein2f904462009-08-12 08:22:16 +00005432 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
5433 is_mi_int,
5434 REG_RD(bp,
5435 NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005436
5437 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
5438 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
5439 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
5440
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00005441 /* disable emac */
5442 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
5443
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005444 /**
5445 * Step 1:
5446 * Check external link change only for external phys, and apply
5447 * priority selection between them in case the link on both phys
5448 * is up. Note that the instead of the common vars, a temporary
5449 * vars argument is used since each phy may have different link/
5450 * speed/duplex result
5451 */
5452 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
5453 phy_index++) {
5454 struct bnx2x_phy *phy = &params->phy[phy_index];
5455 if (!phy->read_status)
5456 continue;
5457 /* Read link status and params of this ext phy */
5458 cur_link_up = phy->read_status(phy, params,
5459 &phy_vars[phy_index]);
5460 if (cur_link_up) {
5461 DP(NETIF_MSG_LINK, "phy in index %d link is up\n",
5462 phy_index);
5463 } else {
5464 DP(NETIF_MSG_LINK, "phy in index %d link is down\n",
5465 phy_index);
5466 continue;
5467 }
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005468
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005469 if (!ext_phy_link_up) {
5470 ext_phy_link_up = 1;
5471 active_external_phy = phy_index;
5472 }
5473 }
5474 prev_line_speed = vars->line_speed;
5475 /**
5476 * Step 2:
5477 * Read the status of the internal phy. In case of
5478 * DIRECT_SINGLE_MEDIA board, this link is the external link,
5479 * otherwise this is the link between the 577xx and the first
5480 * external phy
5481 */
5482 if (params->phy[INT_PHY].read_status)
5483 params->phy[INT_PHY].read_status(
5484 &params->phy[INT_PHY],
5485 params, vars);
5486 /**
5487 * The INT_PHY flow control reside in the vars. This include the
5488 * case where the speed or flow control are not set to AUTO.
5489 * Otherwise, the active external phy flow control result is set
5490 * to the vars. The ext_phy_line_speed is needed to check if the
5491 * speed is different between the internal phy and external phy.
5492 * This case may be result of intermediate link speed change.
5493 */
5494 if (active_external_phy > INT_PHY) {
5495 vars->flow_ctrl = phy_vars[active_external_phy].flow_ctrl;
5496 /**
5497 * Link speed is taken from the XGXS. AN and FC result from
5498 * the external phy.
5499 */
5500 vars->link_status |= phy_vars[active_external_phy].link_status;
5501 ext_phy_line_speed = phy_vars[active_external_phy].line_speed;
5502 vars->duplex = phy_vars[active_external_phy].duplex;
5503 if (params->phy[active_external_phy].supported &
5504 SUPPORTED_FIBRE)
5505 vars->link_status |= LINK_STATUS_SERDES_LINK;
5506 DP(NETIF_MSG_LINK, "Active external phy selected: %x\n",
5507 active_external_phy);
5508 }
5509 DP(NETIF_MSG_LINK, "vars->flow_ctrl = 0x%x, vars->link_status = 0x%x,"
5510 " ext_phy_line_speed = %d\n", vars->flow_ctrl,
5511 vars->link_status, ext_phy_line_speed);
5512 /**
5513 * Upon link speed change set the NIG into drain mode. Comes to
5514 * deals with possible FIFO glitch due to clk change when speed
5515 * is decreased without link down indicator
5516 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005517
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005518 if (vars->phy_link_up) {
5519 if (!(SINGLE_MEDIA_DIRECT(params)) && ext_phy_link_up &&
5520 (ext_phy_line_speed != vars->line_speed)) {
5521 DP(NETIF_MSG_LINK, "Internal link speed %d is"
5522 " different than the external"
5523 " link speed %d\n", vars->line_speed,
5524 ext_phy_line_speed);
5525 vars->phy_link_up = 0;
5526 } else if (prev_line_speed != vars->line_speed) {
5527 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
5528 + params->port*4, 0);
5529 msleep(1);
5530 }
5531 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005532
5533 /* anything 10 and over uses the bmac */
5534 link_10g = ((vars->line_speed == SPEED_10000) ||
5535 (vars->line_speed == SPEED_12000) ||
5536 (vars->line_speed == SPEED_12500) ||
5537 (vars->line_speed == SPEED_13000) ||
5538 (vars->line_speed == SPEED_15000) ||
5539 (vars->line_speed == SPEED_16000));
5540
Eilon Greenstein2f904462009-08-12 08:22:16 +00005541 bnx2x_link_int_ack(params, vars, link_10g, is_mi_int);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005542
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005543 /**
5544 * In case external phy link is up, and internal link is down
5545 * (not initialized yet probably after link initialization, it
5546 * needs to be initialized.
5547 * Note that after link down-up as result of cable plug, the xgxs
5548 * link would probably become up again without the need
5549 * initialize it
5550 */
5551 if (!(SINGLE_MEDIA_DIRECT(params))) {
5552 DP(NETIF_MSG_LINK, "ext_phy_link_up = %d, int_link_up = %d,"
5553 " init_preceding = %d\n", ext_phy_link_up,
5554 vars->phy_link_up,
5555 params->phy[EXT_PHY1].flags &
5556 FLAGS_INIT_XGXS_FIRST);
5557 if (!(params->phy[EXT_PHY1].flags &
5558 FLAGS_INIT_XGXS_FIRST)
5559 && ext_phy_link_up && !vars->phy_link_up) {
5560 vars->line_speed = ext_phy_line_speed;
5561 if (vars->line_speed < SPEED_1000)
5562 vars->phy_flags |= PHY_SGMII_FLAG;
5563 else
5564 vars->phy_flags &= ~PHY_SGMII_FLAG;
5565 bnx2x_init_internal_phy(&params->phy[INT_PHY],
5566 params,
5567 vars);
5568 }
5569 }
5570 /**
5571 * Link is up only if both local phy and external phy (in case of
5572 * non-direct board) are up
5573 */
5574 vars->link_up = (vars->phy_link_up &&
5575 (ext_phy_link_up ||
5576 SINGLE_MEDIA_DIRECT(params)));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005577
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005578 if (vars->link_up)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005579 rc = bnx2x_update_link_up(params, vars, link_10g);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005580 else
5581 rc = bnx2x_update_link_down(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005582
5583 return rc;
5584}
5585
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005586static void bnx2x_8481_hw_reset(struct bnx2x_phy *phy,
5587 struct link_params *params)
5588{
5589 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
5590 MISC_REGISTERS_GPIO_OUTPUT_LOW, 0);
5591 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
5592 MISC_REGISTERS_GPIO_OUTPUT_LOW, 1);
5593}
5594
5595static void bnx2x_8727_hw_reset(struct bnx2x_phy *phy,
5596 struct link_params *params) {
5597 u32 swap_val, swap_override;
5598 u8 port;
5599 /**
5600 * The PHY reset is controlled by GPIO 1. Fake the port number
5601 * to cancel the swap done in set_gpio()
5602 */
5603 struct bnx2x *bp = params->bp;
5604 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
5605 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
5606 port = (swap_val && swap_override) ^ 1;
5607 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
5608 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
5609}
5610
5611static void bnx2x_7101_hw_reset(struct bnx2x_phy *phy,
5612 struct link_params *params) {
5613 /* Low power mode is controlled by GPIO 2 */
5614 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_2,
5615 MISC_REGISTERS_GPIO_OUTPUT_LOW, params->port);
5616 /* The PHY reset is controlled by GPIO 1 */
5617 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
5618 MISC_REGISTERS_GPIO_OUTPUT_LOW, params->port);
5619}
5620/******************************************************************/
5621/* STATIC PHY DECLARATION */
5622/******************************************************************/
5623
5624static struct bnx2x_phy phy_null = {
5625 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN,
5626 .addr = 0,
5627 .flags = FLAGS_INIT_XGXS_FIRST,
5628 .def_md_devad = 0,
5629 .reserved = 0,
5630 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5631 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5632 .mdio_ctrl = 0,
5633 .supported = 0,
5634 .media_type = ETH_PHY_NOT_PRESENT,
5635 .ver_addr = 0,
5636 .req_flow_ctrl = 0,
5637 .req_line_speed = 0,
5638 .speed_cap_mask = 0,
5639 .req_duplex = 0,
5640 .rsrv = 0,
5641 .config_init = (config_init_t)NULL,
5642 .read_status = (read_status_t)NULL,
5643 .link_reset = (link_reset_t)NULL,
5644 .config_loopback = (config_loopback_t)NULL,
5645 .format_fw_ver = (format_fw_ver_t)NULL,
5646 .hw_reset = (hw_reset_t)NULL,
5647 .set_link_led = (set_link_led_t)NULL
5648};
5649
5650static struct bnx2x_phy phy_serdes = {
5651 .type = PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT,
5652 .addr = 0xff,
5653 .flags = 0,
5654 .def_md_devad = 0,
5655 .reserved = 0,
5656 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5657 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5658 .mdio_ctrl = 0,
5659 .supported = (SUPPORTED_10baseT_Half |
5660 SUPPORTED_10baseT_Full |
5661 SUPPORTED_100baseT_Half |
5662 SUPPORTED_100baseT_Full |
5663 SUPPORTED_1000baseT_Full |
5664 SUPPORTED_2500baseX_Full |
5665 SUPPORTED_TP |
5666 SUPPORTED_Autoneg |
5667 SUPPORTED_Pause |
5668 SUPPORTED_Asym_Pause),
5669 .media_type = ETH_PHY_UNSPECIFIED,
5670 .ver_addr = 0,
5671 .req_flow_ctrl = 0,
5672 .req_line_speed = 0,
5673 .speed_cap_mask = 0,
5674 .req_duplex = 0,
5675 .rsrv = 0,
5676 .config_init = (config_init_t)bnx2x_init_serdes,
5677 .read_status = (read_status_t)bnx2x_link_settings_status,
5678 .link_reset = (link_reset_t)bnx2x_int_link_reset,
5679 .config_loopback = (config_loopback_t)NULL,
5680 .format_fw_ver = (format_fw_ver_t)NULL,
5681 .hw_reset = (hw_reset_t)NULL,
5682 .set_link_led = (set_link_led_t)NULL
5683};
5684
5685static struct bnx2x_phy phy_xgxs = {
5686 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT,
5687 .addr = 0xff,
5688 .flags = 0,
5689 .def_md_devad = 0,
5690 .reserved = 0,
5691 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5692 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5693 .mdio_ctrl = 0,
5694 .supported = (SUPPORTED_10baseT_Half |
5695 SUPPORTED_10baseT_Full |
5696 SUPPORTED_100baseT_Half |
5697 SUPPORTED_100baseT_Full |
5698 SUPPORTED_1000baseT_Full |
5699 SUPPORTED_2500baseX_Full |
5700 SUPPORTED_10000baseT_Full |
5701 SUPPORTED_FIBRE |
5702 SUPPORTED_Autoneg |
5703 SUPPORTED_Pause |
5704 SUPPORTED_Asym_Pause),
5705 .media_type = ETH_PHY_UNSPECIFIED,
5706 .ver_addr = 0,
5707 .req_flow_ctrl = 0,
5708 .req_line_speed = 0,
5709 .speed_cap_mask = 0,
5710 .req_duplex = 0,
5711 .rsrv = 0,
5712 .config_init = (config_init_t)bnx2x_init_xgxs,
5713 .read_status = (read_status_t)bnx2x_link_settings_status,
5714 .link_reset = (link_reset_t)bnx2x_int_link_reset,
5715 .config_loopback = (config_loopback_t)bnx2x_set_xgxs_loopback,
5716 .format_fw_ver = (format_fw_ver_t)NULL,
5717 .hw_reset = (hw_reset_t)NULL,
5718 .set_link_led = (set_link_led_t)NULL
5719};
5720
5721static struct bnx2x_phy phy_7101 = {
5722 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5723 .addr = 0xff,
5724 .flags = FLAGS_FAN_FAILURE_DET_REQ,
5725 .def_md_devad = 0,
5726 .reserved = 0,
5727 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5728 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5729 .mdio_ctrl = 0,
5730 .supported = (SUPPORTED_10000baseT_Full |
5731 SUPPORTED_TP |
5732 SUPPORTED_Autoneg |
5733 SUPPORTED_Pause |
5734 SUPPORTED_Asym_Pause),
5735 .media_type = ETH_PHY_BASE_T,
5736 .ver_addr = 0,
5737 .req_flow_ctrl = 0,
5738 .req_line_speed = 0,
5739 .speed_cap_mask = 0,
5740 .req_duplex = 0,
5741 .rsrv = 0,
5742 .config_init = (config_init_t)bnx2x_7101_config_init,
5743 .read_status = (read_status_t)bnx2x_7101_read_status,
5744 .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
5745 .config_loopback = (config_loopback_t)bnx2x_7101_config_loopback,
5746 .format_fw_ver = (format_fw_ver_t)bnx2x_7101_format_ver,
5747 .hw_reset = (hw_reset_t)bnx2x_7101_hw_reset,
5748 .set_link_led = (set_link_led_t)NULL
5749};
5750static struct bnx2x_phy phy_8073 = {
5751 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5752 .addr = 0xff,
5753 .flags = FLAGS_HW_LOCK_REQUIRED,
5754 .def_md_devad = 0,
5755 .reserved = 0,
5756 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5757 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5758 .mdio_ctrl = 0,
5759 .supported = (SUPPORTED_10000baseT_Full |
5760 SUPPORTED_2500baseX_Full |
5761 SUPPORTED_1000baseT_Full |
5762 SUPPORTED_FIBRE |
5763 SUPPORTED_Autoneg |
5764 SUPPORTED_Pause |
5765 SUPPORTED_Asym_Pause),
5766 .media_type = ETH_PHY_UNSPECIFIED,
5767 .ver_addr = 0,
5768 .req_flow_ctrl = 0,
5769 .req_line_speed = 0,
5770 .speed_cap_mask = 0,
5771 .req_duplex = 0,
5772 .rsrv = 0,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00005773 .config_init = (config_init_t)bnx2x_8073_config_init,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005774 .read_status = (read_status_t)bnx2x_8073_read_status,
5775 .link_reset = (link_reset_t)bnx2x_8073_link_reset,
5776 .config_loopback = (config_loopback_t)NULL,
5777 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
5778 .hw_reset = (hw_reset_t)NULL,
5779 .set_link_led = (set_link_led_t)NULL
5780};
5781static struct bnx2x_phy phy_8705 = {
5782 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705,
5783 .addr = 0xff,
5784 .flags = FLAGS_INIT_XGXS_FIRST,
5785 .def_md_devad = 0,
5786 .reserved = 0,
5787 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5788 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5789 .mdio_ctrl = 0,
5790 .supported = (SUPPORTED_10000baseT_Full |
5791 SUPPORTED_FIBRE |
5792 SUPPORTED_Pause |
5793 SUPPORTED_Asym_Pause),
5794 .media_type = ETH_PHY_XFP_FIBER,
5795 .ver_addr = 0,
5796 .req_flow_ctrl = 0,
5797 .req_line_speed = 0,
5798 .speed_cap_mask = 0,
5799 .req_duplex = 0,
5800 .rsrv = 0,
5801 .config_init = (config_init_t)bnx2x_8705_config_init,
5802 .read_status = (read_status_t)bnx2x_8705_read_status,
5803 .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
5804 .config_loopback = (config_loopback_t)NULL,
5805 .format_fw_ver = (format_fw_ver_t)bnx2x_null_format_ver,
5806 .hw_reset = (hw_reset_t)NULL,
5807 .set_link_led = (set_link_led_t)NULL
5808};
5809static struct bnx2x_phy phy_8706 = {
5810 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706,
5811 .addr = 0xff,
5812 .flags = FLAGS_INIT_XGXS_FIRST,
5813 .def_md_devad = 0,
5814 .reserved = 0,
5815 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5816 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5817 .mdio_ctrl = 0,
5818 .supported = (SUPPORTED_10000baseT_Full |
5819 SUPPORTED_1000baseT_Full |
5820 SUPPORTED_FIBRE |
5821 SUPPORTED_Pause |
5822 SUPPORTED_Asym_Pause),
5823 .media_type = ETH_PHY_SFP_FIBER,
5824 .ver_addr = 0,
5825 .req_flow_ctrl = 0,
5826 .req_line_speed = 0,
5827 .speed_cap_mask = 0,
5828 .req_duplex = 0,
5829 .rsrv = 0,
5830 .config_init = (config_init_t)bnx2x_8706_config_init,
5831 .read_status = (read_status_t)bnx2x_8706_read_status,
5832 .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
5833 .config_loopback = (config_loopback_t)NULL,
5834 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
5835 .hw_reset = (hw_reset_t)NULL,
5836 .set_link_led = (set_link_led_t)NULL
5837};
5838
5839static struct bnx2x_phy phy_8726 = {
5840 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
5841 .addr = 0xff,
5842 .flags = (FLAGS_HW_LOCK_REQUIRED |
5843 FLAGS_INIT_XGXS_FIRST),
5844 .def_md_devad = 0,
5845 .reserved = 0,
5846 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5847 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5848 .mdio_ctrl = 0,
5849 .supported = (SUPPORTED_10000baseT_Full |
5850 SUPPORTED_1000baseT_Full |
5851 SUPPORTED_Autoneg |
5852 SUPPORTED_FIBRE |
5853 SUPPORTED_Pause |
5854 SUPPORTED_Asym_Pause),
5855 .media_type = ETH_PHY_SFP_FIBER,
5856 .ver_addr = 0,
5857 .req_flow_ctrl = 0,
5858 .req_line_speed = 0,
5859 .speed_cap_mask = 0,
5860 .req_duplex = 0,
5861 .rsrv = 0,
5862 .config_init = (config_init_t)bnx2x_8726_config_init,
5863 .read_status = (read_status_t)bnx2x_8726_read_status,
5864 .link_reset = (link_reset_t)bnx2x_8726_link_reset,
5865 .config_loopback = (config_loopback_t)bnx2x_8726_config_loopback,
5866 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
5867 .hw_reset = (hw_reset_t)NULL,
5868 .set_link_led = (set_link_led_t)NULL
5869};
5870
5871static struct bnx2x_phy phy_8727 = {
5872 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
5873 .addr = 0xff,
5874 .flags = FLAGS_FAN_FAILURE_DET_REQ,
5875 .def_md_devad = 0,
5876 .reserved = 0,
5877 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5878 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5879 .mdio_ctrl = 0,
5880 .supported = (SUPPORTED_10000baseT_Full |
5881 SUPPORTED_1000baseT_Full |
5882 SUPPORTED_Autoneg |
5883 SUPPORTED_FIBRE |
5884 SUPPORTED_Pause |
5885 SUPPORTED_Asym_Pause),
5886 .media_type = ETH_PHY_SFP_FIBER,
5887 .ver_addr = 0,
5888 .req_flow_ctrl = 0,
5889 .req_line_speed = 0,
5890 .speed_cap_mask = 0,
5891 .req_duplex = 0,
5892 .rsrv = 0,
5893 .config_init = (config_init_t)bnx2x_8727_config_init,
5894 .read_status = (read_status_t)bnx2x_8727_read_status,
5895 .link_reset = (link_reset_t)bnx2x_8727_link_reset,
5896 .config_loopback = (config_loopback_t)NULL,
5897 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
5898 .hw_reset = (hw_reset_t)bnx2x_8727_hw_reset,
5899 .set_link_led = (set_link_led_t)NULL
5900};
5901static struct bnx2x_phy phy_8481 = {
5902 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
5903 .addr = 0xff,
5904 .flags = FLAGS_FAN_FAILURE_DET_REQ,
5905 .def_md_devad = 0,
5906 .reserved = 0,
5907 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5908 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5909 .mdio_ctrl = 0,
5910 .supported = (SUPPORTED_10baseT_Half |
5911 SUPPORTED_10baseT_Full |
5912 SUPPORTED_100baseT_Half |
5913 SUPPORTED_100baseT_Full |
5914 SUPPORTED_1000baseT_Full |
5915 SUPPORTED_10000baseT_Full |
5916 SUPPORTED_TP |
5917 SUPPORTED_Autoneg |
5918 SUPPORTED_Pause |
5919 SUPPORTED_Asym_Pause),
5920 .media_type = ETH_PHY_BASE_T,
5921 .ver_addr = 0,
5922 .req_flow_ctrl = 0,
5923 .req_line_speed = 0,
5924 .speed_cap_mask = 0,
5925 .req_duplex = 0,
5926 .rsrv = 0,
5927 .config_init = (config_init_t)bnx2x_8481_config_init,
5928 .read_status = (read_status_t)bnx2x_848xx_read_status,
5929 .link_reset = (link_reset_t)bnx2x_8481_link_reset,
5930 .config_loopback = (config_loopback_t)NULL,
5931 .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver,
5932 .hw_reset = (hw_reset_t)bnx2x_8481_hw_reset,
5933 .set_link_led = (set_link_led_t)NULL
5934};
5935
5936static struct bnx2x_phy phy_84823 = {
5937 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823,
5938 .addr = 0xff,
5939 .flags = FLAGS_FAN_FAILURE_DET_REQ,
5940 .def_md_devad = 0,
5941 .reserved = 0,
5942 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5943 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5944 .mdio_ctrl = 0,
5945 .supported = (SUPPORTED_10baseT_Half |
5946 SUPPORTED_10baseT_Full |
5947 SUPPORTED_100baseT_Half |
5948 SUPPORTED_100baseT_Full |
5949 SUPPORTED_1000baseT_Full |
5950 SUPPORTED_10000baseT_Full |
5951 SUPPORTED_TP |
5952 SUPPORTED_Autoneg |
5953 SUPPORTED_Pause |
5954 SUPPORTED_Asym_Pause),
5955 .media_type = ETH_PHY_BASE_T,
5956 .ver_addr = 0,
5957 .req_flow_ctrl = 0,
5958 .req_line_speed = 0,
5959 .speed_cap_mask = 0,
5960 .req_duplex = 0,
5961 .rsrv = 0,
5962 .config_init = (config_init_t)bnx2x_848x3_config_init,
5963 .read_status = (read_status_t)bnx2x_848xx_read_status,
5964 .link_reset = (link_reset_t)bnx2x_848x3_link_reset,
5965 .config_loopback = (config_loopback_t)NULL,
5966 .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver,
5967 .hw_reset = (hw_reset_t)NULL,
5968 .set_link_led = (set_link_led_t)NULL
5969};
5970
5971/*****************************************************************/
5972/* */
5973/* Populate the phy according. Main function: bnx2x_populate_phy */
5974/* */
5975/*****************************************************************/
5976
5977static void bnx2x_populate_preemphasis(struct bnx2x *bp, u32 shmem_base,
5978 struct bnx2x_phy *phy, u8 port,
5979 u8 phy_index)
5980{
5981 /* Get the 4 lanes xgxs config rx and tx */
5982 u32 rx = 0, tx = 0, i;
5983 for (i = 0; i < 2; i++) {
5984 /**
5985 * INT_PHY and EXT_PHY1 share the same value location in the
5986 * shmem. When num_phys is greater than 1, than this value
5987 * applies only to EXT_PHY1
5988 */
5989
5990 rx = REG_RD(bp, shmem_base +
5991 offsetof(struct shmem_region,
5992 dev_info.port_hw_config[port].xgxs_config_rx[i<<1]));
5993
5994 tx = REG_RD(bp, shmem_base +
5995 offsetof(struct shmem_region,
5996 dev_info.port_hw_config[port].xgxs_config_tx[i<<1]));
5997
5998 phy->rx_preemphasis[i << 1] = ((rx>>16) & 0xffff);
5999 phy->rx_preemphasis[(i << 1) + 1] = (rx & 0xffff);
6000
6001 phy->tx_preemphasis[i << 1] = ((tx>>16) & 0xffff);
6002 phy->tx_preemphasis[(i << 1) + 1] = (tx & 0xffff);
6003 }
6004}
6005
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006006static u32 bnx2x_get_ext_phy_config(struct bnx2x *bp, u32 shmem_base,
6007 u8 phy_index, u8 port)
6008{
6009 u32 ext_phy_config = 0;
6010 switch (phy_index) {
6011 case EXT_PHY1:
6012 ext_phy_config = REG_RD(bp, shmem_base +
6013 offsetof(struct shmem_region,
6014 dev_info.port_hw_config[port].external_phy_config));
6015 break;
6016 default:
6017 DP(NETIF_MSG_LINK, "Invalid phy_index %d\n", phy_index);
6018 return -EINVAL;
6019 }
6020
6021 return ext_phy_config;
6022}
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006023static u8 bnx2x_populate_int_phy(struct bnx2x *bp, u32 shmem_base, u8 port,
6024 struct bnx2x_phy *phy)
6025{
6026 u32 phy_addr;
6027 u32 chip_id;
6028 u32 switch_cfg = (REG_RD(bp, shmem_base +
6029 offsetof(struct shmem_region,
6030 dev_info.port_feature_config[port].link_config)) &
6031 PORT_FEATURE_CONNECTED_SWITCH_MASK);
6032 chip_id = REG_RD(bp, MISC_REG_CHIP_NUM) << 16;
6033 switch (switch_cfg) {
6034 case SWITCH_CFG_1G:
6035 phy_addr = REG_RD(bp,
6036 NIG_REG_SERDES0_CTRL_PHY_ADDR +
6037 port * 0x10);
6038 *phy = phy_serdes;
6039 break;
6040 case SWITCH_CFG_10G:
6041 phy_addr = REG_RD(bp,
6042 NIG_REG_XGXS0_CTRL_PHY_ADDR +
6043 port * 0x18);
6044 *phy = phy_xgxs;
6045 break;
6046 default:
6047 DP(NETIF_MSG_LINK, "Invalid switch_cfg\n");
6048 return -EINVAL;
6049 }
6050 phy->addr = (u8)phy_addr;
6051 phy->mdio_ctrl = bnx2x_get_emac_base(bp,
6052 phy->type,
6053 port);
6054 phy->def_md_devad = DEFAULT_PHY_DEV_ADDR;
6055
6056 DP(NETIF_MSG_LINK, "Internal phy port=%d, addr=0x%x, mdio_ctl=0x%x\n",
6057 port, phy->addr, phy->mdio_ctrl);
6058
6059 bnx2x_populate_preemphasis(bp, shmem_base, phy, port, INT_PHY);
6060 return 0;
6061}
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006062
6063static u8 bnx2x_populate_ext_phy(struct bnx2x *bp,
6064 u8 phy_index,
6065 u32 shmem_base,
6066 u8 port,
6067 struct bnx2x_phy *phy)
6068{
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006069 u32 ext_phy_config, phy_type;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006070
6071 ext_phy_config = bnx2x_get_ext_phy_config(bp, shmem_base,
6072 phy_index, port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006073 phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
6074 /* Select the phy type */
6075 switch (phy_type) {
6076 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
6077 *phy = phy_8073;
6078 break;
6079 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
6080 *phy = phy_8705;
6081 break;
6082 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
6083 *phy = phy_8706;
6084 break;
6085 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
6086 *phy = phy_8726;
6087 break;
6088 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
6089 /* BCM8727_NOC => BCM8727 no over current */
6090 *phy = phy_8727;
6091 phy->flags |= FLAGS_NOC;
6092 break;
6093 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
6094 *phy = phy_8727;
6095 break;
6096 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
6097 *phy = phy_8481;
6098 break;
6099 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
6100 *phy = phy_84823;
6101 break;
6102 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
6103 *phy = phy_7101;
6104 break;
6105 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
6106 *phy = phy_null;
6107 return -EINVAL;
6108 default:
6109 *phy = phy_null;
6110 return 0;
6111 }
6112
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006113 phy->addr = XGXS_EXT_PHY_ADDR(ext_phy_config);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006114 bnx2x_populate_preemphasis(bp, shmem_base, phy, port, phy_index);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006115 phy->mdio_ctrl = bnx2x_get_emac_base(bp, phy->type, port);
Yaniv Rosner62b29a52010-09-07 11:40:58 +00006116
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006117 return 0;
6118}
6119
6120static u8 bnx2x_populate_phy(struct bnx2x *bp, u8 phy_index, u32 shmem_base,
6121 u8 port, struct bnx2x_phy *phy)
6122{
6123 u8 status = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006124 phy->type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN;
6125 if (phy_index == INT_PHY)
6126 return bnx2x_populate_int_phy(bp, shmem_base, port, phy);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006127 status = bnx2x_populate_ext_phy(bp, phy_index, shmem_base,
6128 port, phy);
6129 return status;
6130}
6131
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006132static void bnx2x_phy_def_cfg(struct link_params *params,
6133 struct bnx2x_phy *phy,
6134 u8 actual_phy_idx)
6135{
6136 struct bnx2x *bp = params->bp;
6137 u32 link_config;
6138 /* Populate the default phy configuration for MF mode */
6139 link_config = REG_RD(bp, params->shmem_base +
6140 offsetof(struct shmem_region, dev_info.
6141 port_feature_config[params->port].link_config));
6142 phy->speed_cap_mask = REG_RD(bp, params->shmem_base +
6143 offsetof(struct shmem_region, dev_info.
6144 port_hw_config[params->port].speed_capability_mask));
6145
6146 phy->req_duplex = DUPLEX_FULL;
6147 switch (link_config & PORT_FEATURE_LINK_SPEED_MASK) {
6148 case PORT_FEATURE_LINK_SPEED_10M_HALF:
6149 phy->req_duplex = DUPLEX_HALF;
6150 case PORT_FEATURE_LINK_SPEED_10M_FULL:
6151 phy->req_line_speed = SPEED_10;
6152 break;
6153 case PORT_FEATURE_LINK_SPEED_100M_HALF:
6154 phy->req_duplex = DUPLEX_HALF;
6155 case PORT_FEATURE_LINK_SPEED_100M_FULL:
6156 phy->req_line_speed = SPEED_100;
6157 break;
6158 case PORT_FEATURE_LINK_SPEED_1G:
6159 phy->req_line_speed = SPEED_1000;
6160 break;
6161 case PORT_FEATURE_LINK_SPEED_2_5G:
6162 phy->req_line_speed = SPEED_2500;
6163 break;
6164 case PORT_FEATURE_LINK_SPEED_10G_CX4:
6165 phy->req_line_speed = SPEED_10000;
6166 break;
6167 default:
6168 phy->req_line_speed = SPEED_AUTO_NEG;
6169 break;
6170 }
6171
6172 switch (link_config & PORT_FEATURE_FLOW_CONTROL_MASK) {
6173 case PORT_FEATURE_FLOW_CONTROL_AUTO:
6174 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_AUTO;
6175 break;
6176 case PORT_FEATURE_FLOW_CONTROL_TX:
6177 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_TX;
6178 break;
6179 case PORT_FEATURE_FLOW_CONTROL_RX:
6180 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_RX;
6181 break;
6182 case PORT_FEATURE_FLOW_CONTROL_BOTH:
6183 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_BOTH;
6184 break;
6185 default:
6186 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_NONE;
6187 break;
6188 }
6189}
6190
6191u8 bnx2x_phy_probe(struct link_params *params)
6192{
6193 u8 phy_index, actual_phy_idx, link_cfg_idx;
6194
6195 struct bnx2x *bp = params->bp;
6196 struct bnx2x_phy *phy;
6197 params->num_phys = 0;
6198 DP(NETIF_MSG_LINK, "Begin phy probe\n");
6199
6200 for (phy_index = INT_PHY; phy_index < MAX_PHYS;
6201 phy_index++) {
6202 link_cfg_idx = LINK_CONFIG_IDX(phy_index);
6203 actual_phy_idx = phy_index;
6204
6205 phy = &params->phy[actual_phy_idx];
6206 if (bnx2x_populate_phy(bp, phy_index, params->shmem_base,
6207 params->port,
6208 phy) != 0) {
6209 params->num_phys = 0;
6210 DP(NETIF_MSG_LINK, "phy probe failed in phy index %d\n",
6211 phy_index);
6212 for (phy_index = INT_PHY;
6213 phy_index < MAX_PHYS;
6214 phy_index++)
6215 *phy = phy_null;
6216 return -EINVAL;
6217 }
6218 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)
6219 break;
6220
6221 bnx2x_phy_def_cfg(params, phy, actual_phy_idx);
6222 params->num_phys++;
6223 }
6224
6225 DP(NETIF_MSG_LINK, "End phy probe. #phys found %x\n", params->num_phys);
6226 return 0;
6227}
6228
6229u32 bnx2x_supported_attr(struct link_params *params, u8 phy_idx)
6230{
6231 if (phy_idx < params->num_phys)
6232 return params->phy[phy_idx].supported;
6233 return 0;
6234}
6235
6236
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006237static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base)
6238{
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006239 struct bnx2x_phy phy[PORT_MAX];
6240 struct bnx2x_phy *phy_blk[PORT_MAX];
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006241 u16 val;
6242 s8 port;
6243
6244 /* PART1 - Reset both phys */
6245 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
6246 /* Extract the ext phy address for the port */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006247 if (bnx2x_populate_phy(bp, EXT_PHY1, shmem_base,
6248 port, &phy[port]) !=
6249 0) {
6250 DP(NETIF_MSG_LINK, "populate_phy failed\n");
6251 return -EINVAL;
6252 }
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006253 /* disable attentions */
6254 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
6255 (NIG_MASK_XGXS0_LINK_STATUS |
6256 NIG_MASK_XGXS0_LINK10G |
6257 NIG_MASK_SERDES0_LINK_STATUS |
6258 NIG_MASK_MI_INT));
6259
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006260 /* Need to take the phy out of low power mode in order
6261 to write to access its registers */
6262 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
6263 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
6264
6265 /* Reset the phy */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006266 bnx2x_cl45_write(bp, &phy[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006267 MDIO_PMA_DEVAD,
6268 MDIO_PMA_REG_CTRL,
6269 1<<15);
6270 }
6271
6272 /* Add delay of 150ms after reset */
6273 msleep(150);
6274
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006275 if (phy[PORT_0].addr & 0x1) {
6276 phy_blk[PORT_0] = &(phy[PORT_1]);
6277 phy_blk[PORT_1] = &(phy[PORT_0]);
6278 } else {
6279 phy_blk[PORT_0] = &(phy[PORT_0]);
6280 phy_blk[PORT_1] = &(phy[PORT_1]);
6281 }
6282
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006283 /* PART2 - Download firmware to both phys */
6284 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
6285 u16 fw_ver1;
6286
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006287 bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port],
6288 port, shmem_base);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006289
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006290 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006291 MDIO_PMA_DEVAD,
6292 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
Eilon Greenstein16b311c2009-01-14 06:44:24 +00006293 if (fw_ver1 == 0 || fw_ver1 == 0x4321) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006294 DP(NETIF_MSG_LINK,
Eilon Greenstein16b311c2009-01-14 06:44:24 +00006295 "bnx2x_8073_common_init_phy port %x:"
6296 "Download failed. fw version = 0x%x\n",
6297 port, fw_ver1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006298 return -EINVAL;
6299 }
6300
6301 /* Only set bit 10 = 1 (Tx power down) */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006302 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006303 MDIO_PMA_DEVAD,
6304 MDIO_PMA_REG_TX_POWER_DOWN, &val);
6305
6306 /* Phase1 of TX_POWER_DOWN reset */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006307 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006308 MDIO_PMA_DEVAD,
6309 MDIO_PMA_REG_TX_POWER_DOWN,
6310 (val | 1<<10));
6311 }
6312
6313 /* Toggle Transmitter: Power down and then up with 600ms
6314 delay between */
6315 msleep(600);
6316
6317 /* PART3 - complete TX_POWER_DOWN process, and set GPIO2 back to low */
6318 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Eilon Greensteinf5372252009-02-12 08:38:30 +00006319 /* Phase2 of POWER_DOWN_RESET */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006320 /* Release bit 10 (Release Tx power down) */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006321 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006322 MDIO_PMA_DEVAD,
6323 MDIO_PMA_REG_TX_POWER_DOWN, &val);
6324
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006325 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006326 MDIO_PMA_DEVAD,
6327 MDIO_PMA_REG_TX_POWER_DOWN, (val & (~(1<<10))));
6328 msleep(15);
6329
6330 /* Read modify write the SPI-ROM version select register */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006331 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006332 MDIO_PMA_DEVAD,
6333 MDIO_PMA_REG_EDC_FFE_MAIN, &val);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006334 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006335 MDIO_PMA_DEVAD,
6336 MDIO_PMA_REG_EDC_FFE_MAIN, (val | (1<<12)));
6337
6338 /* set GPIO2 back to LOW */
6339 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
6340 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
6341 }
6342 return 0;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006343}
6344
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006345static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base)
6346{
Eilon Greensteinbc7f0a02009-08-12 08:23:01 +00006347 s8 port, first_port, i;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006348 u32 swap_val, swap_override;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006349 struct bnx2x_phy phy[PORT_MAX];
6350 struct bnx2x_phy *phy_blk[PORT_MAX];
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006351 DP(NETIF_MSG_LINK, "Executing BCM8727 common init\n");
6352 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
6353 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
6354
Eilon Greensteinf57a6022009-08-12 08:23:11 +00006355 bnx2x_ext_phy_hw_reset(bp, 1 ^ (swap_val && swap_override));
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006356 msleep(5);
6357
Eilon Greensteinbc7f0a02009-08-12 08:23:01 +00006358 if (swap_val && swap_override)
6359 first_port = PORT_0;
6360 else
6361 first_port = PORT_1;
6362
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006363 /* PART1 - Reset both phys */
Eilon Greensteinbc7f0a02009-08-12 08:23:01 +00006364 for (i = 0, port = first_port; i < PORT_MAX; i++, port = !port) {
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006365 /* Extract the ext phy address for the port */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006366 if (bnx2x_populate_phy(bp, EXT_PHY1, shmem_base,
6367 port, &phy[port]) !=
6368 0) {
6369 DP(NETIF_MSG_LINK, "populate phy failed\n");
6370 return -EINVAL;
6371 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006372 /* disable attentions */
6373 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
6374 (NIG_MASK_XGXS0_LINK_STATUS |
6375 NIG_MASK_XGXS0_LINK10G |
6376 NIG_MASK_SERDES0_LINK_STATUS |
6377 NIG_MASK_MI_INT));
6378
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006379
6380 /* Reset the phy */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006381 bnx2x_cl45_write(bp, &phy[port],
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006382 MDIO_PMA_DEVAD,
6383 MDIO_PMA_REG_CTRL,
6384 1<<15);
6385 }
6386
6387 /* Add delay of 150ms after reset */
6388 msleep(150);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006389 if (phy[PORT_0].addr & 0x1) {
6390 phy_blk[PORT_0] = &(phy[PORT_1]);
6391 phy_blk[PORT_1] = &(phy[PORT_0]);
6392 } else {
6393 phy_blk[PORT_0] = &(phy[PORT_0]);
6394 phy_blk[PORT_1] = &(phy[PORT_1]);
6395 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006396 /* PART2 - Download firmware to both phys */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006397 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006398 u16 fw_ver1;
6399
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006400 bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port],
6401 port, shmem_base);
6402 bnx2x_cl45_read(bp, phy_blk[port],
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006403 MDIO_PMA_DEVAD,
6404 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
6405 if (fw_ver1 == 0 || fw_ver1 == 0x4321) {
6406 DP(NETIF_MSG_LINK,
Eilon Greensteinbc7f0a02009-08-12 08:23:01 +00006407 "bnx2x_8727_common_init_phy port %x:"
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006408 "Download failed. fw version = 0x%x\n",
6409 port, fw_ver1);
6410 return -EINVAL;
6411 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006412 }
6413
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006414 return 0;
6415}
6416
Eilon Greenstein589abe32009-02-12 08:36:55 +00006417static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp, u32 shmem_base)
6418{
Eilon Greenstein589abe32009-02-12 08:36:55 +00006419 u32 val;
6420 s8 port;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006421 struct bnx2x_phy phy;
Eilon Greenstein589abe32009-02-12 08:36:55 +00006422 /* Use port1 because of the static port-swap */
6423 /* Enable the module detection interrupt */
6424 val = REG_RD(bp, MISC_REG_GPIO_EVENT_EN);
6425 val |= ((1<<MISC_REGISTERS_GPIO_3)|
6426 (1<<(MISC_REGISTERS_GPIO_3 + MISC_REGISTERS_GPIO_PORT_SHIFT)));
6427 REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val);
6428
Eilon Greensteinf57a6022009-08-12 08:23:11 +00006429 bnx2x_ext_phy_hw_reset(bp, 1);
Eilon Greenstein589abe32009-02-12 08:36:55 +00006430 msleep(5);
6431 for (port = 0; port < PORT_MAX; port++) {
6432 /* Extract the ext phy address for the port */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006433 if (bnx2x_populate_phy(bp, EXT_PHY1, shmem_base,
6434 port, &phy) !=
6435 0) {
6436 DP(NETIF_MSG_LINK, "populate phy failed\n");
6437 return -EINVAL;
6438 }
Eilon Greenstein589abe32009-02-12 08:36:55 +00006439
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006440 /* Reset phy*/
6441 bnx2x_cl45_write(bp, &phy,
6442 MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, 0x0001);
Eilon Greenstein589abe32009-02-12 08:36:55 +00006443
Eilon Greenstein589abe32009-02-12 08:36:55 +00006444
6445 /* Set fault module detected LED on */
6446 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
6447 MISC_REGISTERS_GPIO_HIGH,
6448 port);
6449 }
6450
6451 return 0;
6452}
6453
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006454u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base)
6455{
6456 u8 rc = 0;
6457 u32 ext_phy_type;
6458
Eilon Greensteinf5372252009-02-12 08:38:30 +00006459 DP(NETIF_MSG_LINK, "Begin common phy init\n");
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006460
6461 /* Read the ext_phy_type for arbitrary port(0) */
6462 ext_phy_type = XGXS_EXT_PHY_TYPE(
6463 REG_RD(bp, shmem_base +
6464 offsetof(struct shmem_region,
6465 dev_info.port_hw_config[0].external_phy_config)));
6466
6467 switch (ext_phy_type) {
6468 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
6469 {
6470 rc = bnx2x_8073_common_init_phy(bp, shmem_base);
6471 break;
6472 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006473
6474 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
6475 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
6476 rc = bnx2x_8727_common_init_phy(bp, shmem_base);
6477 break;
6478
Eilon Greenstein589abe32009-02-12 08:36:55 +00006479 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
6480 /* GPIO1 affects both ports, so there's need to pull
6481 it for single port alone */
6482 rc = bnx2x_8726_common_init_phy(bp, shmem_base);
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02006483 break;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006484 default:
6485 DP(NETIF_MSG_LINK,
6486 "bnx2x_common_init_phy: ext_phy 0x%x not required\n",
6487 ext_phy_type);
6488 break;
6489 }
6490
6491 return rc;
6492}
6493
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006494void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006495{
6496 u16 val, cnt;
6497
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006498 bnx2x_cl45_read(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006499 MDIO_PMA_DEVAD,
6500 MDIO_PMA_REG_7101_RESET, &val);
6501
6502 for (cnt = 0; cnt < 10; cnt++) {
6503 msleep(50);
6504 /* Writes a self-clearing reset */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006505 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006506 MDIO_PMA_DEVAD,
6507 MDIO_PMA_REG_7101_RESET,
6508 (val | (1<<15)));
6509 /* Wait for clear */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006510 bnx2x_cl45_read(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006511 MDIO_PMA_DEVAD,
6512 MDIO_PMA_REG_7101_RESET, &val);
6513
6514 if ((val & (1<<15)) == 0)
6515 break;
6516 }
6517}