blob: 72ac8dcf6e20e9d599c6073e6a802b14844f19aa [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/*****************************************************************************/
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00002082/* 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;
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00003274 u32 val;
3275 u32 swap_val, swap_override, aeu_gpio_mask, offset;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003276 DP(NETIF_MSG_LINK, "Initializing BCM8726\n");
3277 /* Restore normal power mode*/
3278 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
3279 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
3280
3281 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
3282 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
3283
3284 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
3285 bnx2x_wait_reset_complete(bp, phy);
3286
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003287 bnx2x_8726_external_rom_boot(phy, params);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003288
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003289 /* Need to call module detected on initialization since
3290 the module detection triggered by actual module
3291 insertion might occur before driver is loaded, and when
3292 driver is loaded, it reset all registers, including the
3293 transmitter */
3294 bnx2x_sfp_module_detection(phy, params);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003295
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003296 if (phy->req_line_speed == SPEED_1000) {
3297 DP(NETIF_MSG_LINK, "Setting 1G force\n");
3298 bnx2x_cl45_write(bp, phy,
3299 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x40);
3300 bnx2x_cl45_write(bp, phy,
3301 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0xD);
3302 bnx2x_cl45_write(bp, phy,
3303 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x5);
3304 bnx2x_cl45_write(bp, phy,
3305 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
3306 0x400);
3307 } else if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
3308 (phy->speed_cap_mask &
3309 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G) &&
3310 ((phy->speed_cap_mask &
3311 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) !=
3312 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
3313 DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
3314 /* Set Flow control */
3315 bnx2x_ext_phy_set_pause(params, phy, vars);
3316 bnx2x_cl45_write(bp, phy,
3317 MDIO_AN_DEVAD, MDIO_AN_REG_ADV, 0x20);
3318 bnx2x_cl45_write(bp, phy,
3319 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_CL73, 0x040c);
3320 bnx2x_cl45_write(bp, phy,
3321 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, 0x0020);
3322 bnx2x_cl45_write(bp, phy,
3323 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
3324 bnx2x_cl45_write(bp, phy,
3325 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
3326 /* Enable RX-ALARM control to receive
3327 interrupt for 1G speed change */
3328 bnx2x_cl45_write(bp, phy,
3329 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x4);
3330 bnx2x_cl45_write(bp, phy,
3331 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
3332 0x400);
Eilon Greenstein589abe32009-02-12 08:36:55 +00003333
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003334 } else { /* Default 10G. Set only LASI control */
3335 bnx2x_cl45_write(bp, phy,
3336 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 1);
3337 }
Eilon Greenstein589abe32009-02-12 08:36:55 +00003338
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003339 /* Set TX PreEmphasis if needed */
3340 if ((params->feature_config_flags &
3341 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
3342 DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x,"
3343 "TX_CTRL2 0x%x\n",
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003344 phy->tx_preemphasis[0],
3345 phy->tx_preemphasis[1]);
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003346 bnx2x_cl45_write(bp, phy,
3347 MDIO_PMA_DEVAD,
3348 MDIO_PMA_REG_8726_TX_CTRL1,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003349 phy->tx_preemphasis[0]);
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00003350
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003351 bnx2x_cl45_write(bp, phy,
3352 MDIO_PMA_DEVAD,
3353 MDIO_PMA_REG_8726_TX_CTRL2,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003354 phy->tx_preemphasis[1]);
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003355 }
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00003356
3357 /* Set GPIO3 to trigger SFP+ module insertion/removal */
3358 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
3359 MISC_REGISTERS_GPIO_INPUT_HI_Z, params->port);
3360
3361 /* The GPIO should be swapped if the swap register is set and active */
3362 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
3363 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
3364
3365 /* Select function upon port-swap configuration */
3366 if (params->port == 0) {
3367 offset = MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0;
3368 aeu_gpio_mask = (swap_val && swap_override) ?
3369 AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_1 :
3370 AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0;
3371 } else {
3372 offset = MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0;
3373 aeu_gpio_mask = (swap_val && swap_override) ?
3374 AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0 :
3375 AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_1;
3376 }
3377 val = REG_RD(bp, offset);
3378 /* add GPIO3 to group */
3379 val |= aeu_gpio_mask;
3380 REG_WR(bp, offset, val);
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003381 return 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003382
3383}
3384
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003385static u8 bnx2x_8073_config_init(struct bnx2x_phy *phy,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003386 struct link_params *params,
3387 struct link_vars *vars)
3388{
3389 struct bnx2x *bp = params->bp;
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003390 u16 val = 0, tmp1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003391 u8 gpio_port;
3392 DP(NETIF_MSG_LINK, "Init 8073\n");
3393
3394 gpio_port = params->port;
3395 /* Restore normal power mode*/
3396 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
3397 MISC_REGISTERS_GPIO_OUTPUT_HIGH, gpio_port);
3398
3399 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
3400 MISC_REGISTERS_GPIO_OUTPUT_HIGH, gpio_port);
3401
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003402 /* enable LASI */
3403 bnx2x_cl45_write(bp, phy,
3404 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL, (1<<2));
3405 bnx2x_cl45_write(bp, phy,
3406 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x0004);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003407
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003408 bnx2x_8073_set_pause_cl37(params, phy, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003409
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003410 bnx2x_8073_set_xaui_low_power_mode(bp, phy);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003411
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003412 bnx2x_cl45_read(bp, phy,
3413 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &tmp1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003414
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003415 bnx2x_cl45_read(bp, phy,
3416 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &tmp1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003417
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003418 DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1): 0x%x\n", tmp1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003419
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003420 /* Enable CL37 BAM */
3421 bnx2x_cl45_read(bp, phy,
3422 MDIO_AN_DEVAD,
3423 MDIO_AN_REG_8073_BAM, &val);
3424 bnx2x_cl45_write(bp, phy,
3425 MDIO_AN_DEVAD,
3426 MDIO_AN_REG_8073_BAM, val | 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003427
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003428 if (params->loopback_mode == LOOPBACK_EXT) {
3429 bnx2x_807x_force_10G(bp, phy);
3430 DP(NETIF_MSG_LINK, "Forced speed 10G on 807X\n");
3431 return 0;
3432 } else {
3433 bnx2x_cl45_write(bp, phy,
3434 MDIO_PMA_DEVAD, MDIO_PMA_REG_BCM_CTRL, 0x0002);
3435 }
3436 if (phy->req_line_speed != SPEED_AUTO_NEG) {
3437 if (phy->req_line_speed == SPEED_10000) {
3438 val = (1<<7);
3439 } else if (phy->req_line_speed == SPEED_2500) {
3440 val = (1<<5);
3441 /* Note that 2.5G works only
3442 when used with 1G advertisment */
3443 } else
3444 val = (1<<5);
3445 } else {
3446 val = 0;
3447 if (phy->speed_cap_mask &
3448 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
3449 val |= (1<<7);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003450
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003451 /* Note that 2.5G works only when
3452 used with 1G advertisment */
3453 if (phy->speed_cap_mask &
3454 (PORT_HW_CFG_SPEED_CAPABILITY_D0_1G |
3455 PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G))
3456 val |= (1<<5);
3457 DP(NETIF_MSG_LINK, "807x autoneg val = 0x%x\n", val);
3458 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003459
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003460 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV, val);
3461 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_8073_2_5G, &tmp1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003462
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003463 if (((phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G) &&
3464 (phy->req_line_speed == SPEED_AUTO_NEG)) ||
3465 (phy->req_line_speed == SPEED_2500)) {
3466 u16 phy_ver;
3467 /* Allow 2.5G for A1 and above */
3468 bnx2x_cl45_read(bp, phy,
3469 MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_CHIP_REV,
3470 &phy_ver);
3471 DP(NETIF_MSG_LINK, "Add 2.5G\n");
3472 if (phy_ver > 0)
3473 tmp1 |= 1;
3474 else
3475 tmp1 &= 0xfffe;
3476 } else {
3477 DP(NETIF_MSG_LINK, "Disable 2.5G\n");
3478 tmp1 &= 0xfffe;
3479 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003480
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003481 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_8073_2_5G, tmp1);
3482 /* Add support for CL37 (passive mode) II */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003483
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003484 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, &tmp1);
3485 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD,
3486 (tmp1 | ((phy->req_duplex == DUPLEX_FULL) ?
3487 0x20 : 0x40)));
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003488
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003489 /* Add support for CL37 (passive mode) III */
3490 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003491
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003492 /* The SNR will improve about 2db by changing
3493 BW and FEE main tap. Rest commands are executed
3494 after link is up*/
3495 if (bnx2x_8073_is_snr_needed(bp, phy))
3496 bnx2x_cl45_write(bp, phy,
3497 MDIO_PMA_DEVAD, MDIO_PMA_REG_EDC_FFE_MAIN,
3498 0xFB0C);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003499
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003500 /* Enable FEC (Forware Error Correction) Request in the AN */
3501 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV2, &tmp1);
3502 tmp1 |= (1<<15);
3503 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV2, tmp1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003504
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003505 bnx2x_ext_phy_set_pause(params, phy, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003506
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003507 /* Restart autoneg */
3508 msleep(500);
3509 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
3510 DP(NETIF_MSG_LINK, "807x Autoneg Restart: Advertise 1G=%x, 10G=%x\n",
3511 ((val & (1<<5)) > 0), ((val & (1<<7)) > 0));
3512 return 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003513}
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003514
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003515static u8 bnx2x_8727_config_init(struct bnx2x_phy *phy,
3516 struct link_params *params,
3517 struct link_vars *vars)
3518{
3519 u16 tmp1, val, mod_abs;
3520 u16 rx_alarm_ctrl_val;
3521 u16 lasi_ctrl_val;
3522 struct bnx2x *bp = params->bp;
3523 /* Enable PMD link, MOD_ABS_FLT, and 1G link alarm */
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003524
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003525 bnx2x_wait_reset_complete(bp, phy);
3526 rx_alarm_ctrl_val = (1<<2) | (1<<5) ;
3527 lasi_ctrl_val = 0x0004;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003528
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003529 DP(NETIF_MSG_LINK, "Initializing BCM8727\n");
3530 /* enable LASI */
3531 bnx2x_cl45_write(bp, phy,
3532 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
3533 rx_alarm_ctrl_val);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003534
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003535 bnx2x_cl45_write(bp, phy,
3536 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, lasi_ctrl_val);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003537
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003538 /* Initially configure MOD_ABS to interrupt when
3539 module is presence( bit 8) */
3540 bnx2x_cl45_read(bp, phy,
3541 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
3542 /* Set EDC off by setting OPTXLOS signal input to low
3543 (bit 9).
3544 When the EDC is off it locks onto a reference clock and
3545 avoids becoming 'lost'.*/
3546 mod_abs &= ~((1<<8) | (1<<9));
3547 bnx2x_cl45_write(bp, phy,
3548 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003549
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003550
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003551 /* Make MOD_ABS give interrupt on change */
3552 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL,
3553 &val);
3554 val |= (1<<12);
3555 bnx2x_cl45_write(bp, phy,
3556 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL, val);
3557 /* Set 8727 GPIOs to input to allow reading from the
3558 8727 GPIO0 status which reflect SFP+ module
3559 over-current */
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003560
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003561 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL,
3562 &val);
3563 val &= 0xff8f; /* Reset bits 4-6 */
3564 bnx2x_cl45_write(bp, phy,
3565 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL, val);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003566
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003567 bnx2x_8727_power_module(bp, phy, 1);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003568
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003569 bnx2x_cl45_read(bp, phy,
3570 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &tmp1);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003571
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003572 bnx2x_cl45_read(bp, phy,
3573 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &tmp1);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003574
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003575 /* Set option 1G speed */
3576 if (phy->req_line_speed == SPEED_1000) {
3577 DP(NETIF_MSG_LINK, "Setting 1G force\n");
3578 bnx2x_cl45_write(bp, phy,
3579 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x40);
3580 bnx2x_cl45_write(bp, phy,
3581 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0xD);
3582 bnx2x_cl45_read(bp, phy,
3583 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, &tmp1);
3584 DP(NETIF_MSG_LINK, "1.7 = 0x%x\n", tmp1);
3585 } else if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
3586 ((phy->speed_cap_mask &
3587 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) &&
3588 ((phy->speed_cap_mask &
3589 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) !=
3590 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003591
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003592 DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
3593 bnx2x_cl45_write(bp, phy,
3594 MDIO_AN_DEVAD, MDIO_AN_REG_8727_MISC_CTRL, 0);
3595 bnx2x_cl45_write(bp, phy,
3596 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1300);
3597 } else {
3598 /**
3599 * Since the 8727 has only single reset pin, need to set the 10G
3600 * registers although it is default
3601 */
3602 bnx2x_cl45_write(bp, phy,
3603 MDIO_AN_DEVAD, MDIO_AN_REG_8727_MISC_CTRL,
3604 0x0020);
3605 bnx2x_cl45_write(bp, phy,
3606 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x0100);
3607 bnx2x_cl45_write(bp, phy,
3608 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x2040);
3609 bnx2x_cl45_write(bp, phy,
3610 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2,
3611 0x0008);
3612 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003613
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003614
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003615 /* Set 2-wire transfer rate of SFP+ module EEPROM
3616 * to 100Khz since some DACs(direct attached cables) do
3617 * not work at 400Khz.
3618 */
3619 bnx2x_cl45_write(bp, phy,
3620 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR,
3621 0xa001);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003622
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003623 /* Set TX PreEmphasis if needed */
3624 if ((params->feature_config_flags &
3625 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
3626 DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x, TX_CTRL2 0x%x\n",
3627 phy->tx_preemphasis[0],
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003628 phy->tx_preemphasis[1]);
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003629 bnx2x_cl45_write(bp, phy,
3630 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TX_CTRL1,
3631 phy->tx_preemphasis[0]);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003632
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003633 bnx2x_cl45_write(bp, phy,
3634 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TX_CTRL2,
3635 phy->tx_preemphasis[1]);
3636 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003637
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003638 return 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003639}
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003640
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003641static u8 bnx2x_7101_config_init(struct bnx2x_phy *phy,
3642 struct link_params *params,
3643 struct link_vars *vars)
3644{
3645 u16 fw_ver1, fw_ver2, val;
3646 struct bnx2x *bp = params->bp;
3647 DP(NETIF_MSG_LINK, "Setting the SFX7101 LASI indication\n");
3648
3649 /* Restore normal power mode*/
3650 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
3651 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
3652 /* HW reset */
3653 bnx2x_ext_phy_hw_reset(bp, params->port);
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003654 bnx2x_wait_reset_complete(bp, phy);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003655
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003656 bnx2x_cl45_write(bp, phy,
3657 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x1);
3658 DP(NETIF_MSG_LINK, "Setting the SFX7101 LED to blink on traffic\n");
3659 bnx2x_cl45_write(bp, phy,
3660 MDIO_PMA_DEVAD, MDIO_PMA_REG_7107_LED_CNTL, (1<<3));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003661
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003662 bnx2x_ext_phy_set_pause(params, phy, vars);
3663 /* Restart autoneg */
3664 bnx2x_cl45_read(bp, phy,
3665 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, &val);
3666 val |= 0x200;
3667 bnx2x_cl45_write(bp, phy,
3668 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, val);
Eilon Greenstein28577182009-02-12 08:37:00 +00003669
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003670 /* Save spirom version */
3671 bnx2x_cl45_read(bp, phy,
3672 MDIO_PMA_DEVAD, MDIO_PMA_REG_7101_VER1, &fw_ver1);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003673
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003674 bnx2x_cl45_read(bp, phy,
3675 MDIO_PMA_DEVAD, MDIO_PMA_REG_7101_VER2, &fw_ver2);
3676 bnx2x_save_spirom_version(bp, params->port,
3677 (u32)(fw_ver1<<16 | fw_ver2), phy->ver_addr);
3678 return 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003679}
3680
3681static u8 bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy,
3682 struct link_params *params,
3683 struct link_vars *vars)
3684{
3685 struct bnx2x *bp = params->bp;
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003686 u16 autoneg_val, an_1000_val, an_10_100_val;
3687 bnx2x_wait_reset_complete(bp, phy);
3688 bnx2x_bits_en(bp, NIG_REG_LATCH_BC_0 + params->port*4,
3689 1 << NIG_LATCH_BC_ENABLE_MI_INT);
Yaniv Rosnera1e4be32010-09-01 09:51:33 +00003690
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003691 bnx2x_cl45_write(bp, phy,
3692 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x0000);
3693 bnx2x_8481_set_led(bp, phy);
3694 /* set 1000 speed advertisement */
3695 bnx2x_cl45_read(bp, phy,
3696 MDIO_AN_DEVAD, MDIO_AN_REG_8481_1000T_CTRL,
3697 &an_1000_val);
Eilon Greenstein28577182009-02-12 08:37:00 +00003698
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003699 bnx2x_ext_phy_set_pause(params, phy, vars);
3700 bnx2x_cl45_read(bp, phy,
3701 MDIO_AN_DEVAD,
3702 MDIO_AN_REG_8481_LEGACY_AN_ADV,
3703 &an_10_100_val);
3704 bnx2x_cl45_read(bp, phy,
3705 MDIO_AN_DEVAD, MDIO_AN_REG_8481_LEGACY_MII_CTRL,
3706 &autoneg_val);
3707 /* Disable forced speed */
3708 autoneg_val &= ~((1<<6) | (1<<8) | (1<<9) | (1<<12) | (1<<13));
3709 an_10_100_val &= ~((1<<5) | (1<<6) | (1<<7) | (1<<8));
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02003710
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003711 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
3712 (phy->speed_cap_mask &
3713 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) ||
3714 (phy->req_line_speed == SPEED_1000)) {
3715 an_1000_val |= (1<<8);
3716 autoneg_val |= (1<<9 | 1<<12);
3717 if (phy->req_duplex == DUPLEX_FULL)
3718 an_1000_val |= (1<<9);
3719 DP(NETIF_MSG_LINK, "Advertising 1G\n");
3720 } else
3721 an_1000_val &= ~((1<<8) | (1<<9));
Eilon Greenstein28577182009-02-12 08:37:00 +00003722
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003723 bnx2x_cl45_write(bp, phy,
3724 MDIO_AN_DEVAD, MDIO_AN_REG_8481_1000T_CTRL,
3725 an_1000_val);
Eilon Greenstein2f904462009-08-12 08:22:16 +00003726
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003727 /* set 10 speed advertisement */
3728 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
3729 (phy->speed_cap_mask &
3730 (PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL |
3731 PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF)))) {
3732 an_10_100_val |= (1<<7);
3733 /* Enable autoneg and restart autoneg for legacy speeds */
3734 autoneg_val |= (1<<9 | 1<<12);
Yaniv Rosner46d15cc2009-11-05 19:18:30 +02003735
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003736 if (phy->req_duplex == DUPLEX_FULL)
3737 an_10_100_val |= (1<<8);
3738 DP(NETIF_MSG_LINK, "Advertising 100M\n");
3739 }
3740 /* set 10 speed advertisement */
3741 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
3742 (phy->speed_cap_mask &
3743 (PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL |
3744 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF)))) {
3745 an_10_100_val |= (1<<5);
3746 autoneg_val |= (1<<9 | 1<<12);
3747 if (phy->req_duplex == DUPLEX_FULL)
3748 an_10_100_val |= (1<<6);
3749 DP(NETIF_MSG_LINK, "Advertising 10M\n");
3750 }
Eilon Greenstein2f904462009-08-12 08:22:16 +00003751
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003752 /* Only 10/100 are allowed to work in FORCE mode */
3753 if (phy->req_line_speed == SPEED_100) {
3754 autoneg_val |= (1<<13);
3755 /* Enabled AUTO-MDIX when autoneg is disabled */
3756 bnx2x_cl45_write(bp, phy,
3757 MDIO_AN_DEVAD, MDIO_AN_REG_8481_AUX_CTRL,
3758 (1<<15 | 1<<9 | 7<<0));
3759 DP(NETIF_MSG_LINK, "Setting 100M force\n");
3760 }
3761 if (phy->req_line_speed == SPEED_10) {
3762 /* Enabled AUTO-MDIX when autoneg is disabled */
3763 bnx2x_cl45_write(bp, phy,
3764 MDIO_AN_DEVAD, MDIO_AN_REG_8481_AUX_CTRL,
3765 (1<<15 | 1<<9 | 7<<0));
3766 DP(NETIF_MSG_LINK, "Setting 10M force\n");
3767 }
Eilon Greenstein2f904462009-08-12 08:22:16 +00003768
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003769 bnx2x_cl45_write(bp, phy,
3770 MDIO_AN_DEVAD, MDIO_AN_REG_8481_LEGACY_AN_ADV,
3771 an_10_100_val);
Yaniv Rosnerac4d9442010-09-01 09:51:25 +00003772
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003773 if (phy->req_duplex == DUPLEX_FULL)
3774 autoneg_val |= (1<<8);
Yaniv Rosnerac4d9442010-09-01 09:51:25 +00003775
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003776 bnx2x_cl45_write(bp, phy,
3777 MDIO_AN_DEVAD,
3778 MDIO_AN_REG_8481_LEGACY_MII_CTRL, autoneg_val);
Yaniv Rosnerac4d9442010-09-01 09:51:25 +00003779
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003780 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
3781 (phy->speed_cap_mask &
3782 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) ||
3783 (phy->req_line_speed == SPEED_10000)) {
3784 DP(NETIF_MSG_LINK, "Advertising 10G\n");
3785 /* Restart autoneg for 10G*/
Yaniv Rosnerac4d9442010-09-01 09:51:25 +00003786
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003787 bnx2x_cl45_write(bp, phy,
3788 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL,
3789 0x3200);
3790 } else if (phy->req_line_speed != SPEED_10 &&
3791 phy->req_line_speed != SPEED_100) {
3792 bnx2x_cl45_write(bp, phy,
3793 MDIO_AN_DEVAD,
3794 MDIO_AN_REG_8481_10GBASE_T_AN_CTRL,
3795 1);
3796 }
3797 /* Save spirom version */
3798 bnx2x_save_8481_spirom_version(phy, params, params->shmem_base);
Yaniv Rosnerac4d9442010-09-01 09:51:25 +00003799
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003800 return 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003801}
3802
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003803static u8 bnx2x_848x3_config_init(struct bnx2x_phy *phy,
3804 struct link_params *params,
3805 struct link_vars *vars)
3806{
3807 struct bnx2x *bp = params->bp;
3808 u16 temp;
3809 msleep(1);
3810 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
3811 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
3812 params->port);
3813 msleep(200); /* 100 is not enough */
3814
3815 /**
3816 * BCM84823 requires that XGXS links up first @ 10G for normal
3817 * behavior
3818 */
3819 temp = vars->line_speed;
3820 vars->line_speed = SPEED_10000;
3821 bnx2x_set_autoneg(phy, params, vars, 0);
3822 bnx2x_program_serdes(phy, params, vars);
3823 vars->line_speed = temp;
3824 return bnx2x_848xx_cmn_config_init(phy, params, vars);
3825}
3826
3827static u8 bnx2x_8481_config_init(struct bnx2x_phy *phy,
3828 struct link_params *params,
3829 struct link_vars *vars)
3830{
3831 struct bnx2x *bp = params->bp;
3832 /* Restore normal power mode*/
3833 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
3834 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
3835
3836 /* HW reset */
3837 bnx2x_ext_phy_hw_reset(bp, params->port);
3838
3839 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
3840 return bnx2x_848xx_cmn_config_init(phy, params, vars);
3841}
Yaniv Rosner7aa07112010-09-07 11:41:01 +00003842
3843
3844static void bnx2x_ext_phy_10G_an_resolve(struct bnx2x *bp,
3845 struct bnx2x_phy *phy,
3846 struct link_vars *vars)
3847{
3848 u16 val;
3849 bnx2x_cl45_read(bp, phy,
3850 MDIO_AN_DEVAD,
3851 MDIO_AN_REG_STATUS, &val);
3852 bnx2x_cl45_read(bp, phy,
3853 MDIO_AN_DEVAD,
3854 MDIO_AN_REG_STATUS, &val);
3855 if (val & (1<<5))
3856 vars->link_status |= LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
3857 if ((val & (1<<0)) == 0)
3858 vars->link_status |= LINK_STATUS_PARALLEL_DETECTION_USED;
3859}
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003860static void bnx2x_8727_handle_mod_abs(struct bnx2x_phy *phy,
3861 struct link_params *params)
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003862{
3863 struct bnx2x *bp = params->bp;
3864 u16 mod_abs, rx_alarm_status;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003865 u32 val = REG_RD(bp, params->shmem_base +
3866 offsetof(struct shmem_region, dev_info.
3867 port_feature_config[params->port].
3868 config));
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003869 bnx2x_cl45_read(bp, phy,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003870 MDIO_PMA_DEVAD,
3871 MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
3872 if (mod_abs & (1<<8)) {
3873
3874 /* Module is absent */
3875 DP(NETIF_MSG_LINK, "MOD_ABS indication "
3876 "show module is absent\n");
3877
3878 /* 1. Set mod_abs to detect next module
3879 presence event
3880 2. Set EDC off by setting OPTXLOS signal input to low
3881 (bit 9).
3882 When the EDC is off it locks onto a reference clock and
3883 avoids becoming 'lost'.*/
3884 mod_abs &= ~((1<<8)|(1<<9));
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003885 bnx2x_cl45_write(bp, phy,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003886 MDIO_PMA_DEVAD,
3887 MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
3888
3889 /* Clear RX alarm since it stays up as long as
3890 the mod_abs wasn't changed */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003891 bnx2x_cl45_read(bp, phy,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003892 MDIO_PMA_DEVAD,
3893 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
3894
3895 } else {
3896 /* Module is present */
3897 DP(NETIF_MSG_LINK, "MOD_ABS indication "
3898 "show module is present\n");
3899 /* First thing, disable transmitter,
3900 and if the module is ok, the
3901 module_detection will enable it*/
3902
3903 /* 1. Set mod_abs to detect next module
3904 absent event ( bit 8)
3905 2. Restore the default polarity of the OPRXLOS signal and
3906 this signal will then correctly indicate the presence or
3907 absence of the Rx signal. (bit 9) */
3908 mod_abs |= ((1<<8)|(1<<9));
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003909 bnx2x_cl45_write(bp, phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003910 MDIO_PMA_DEVAD,
3911 MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003912
3913 /* Clear RX alarm since it stays up as long as
3914 the mod_abs wasn't changed. This is need to be done
3915 before calling the module detection, otherwise it will clear
3916 the link update alarm */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003917 bnx2x_cl45_read(bp, phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003918 MDIO_PMA_DEVAD,
3919 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003920
3921
3922 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
3923 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003924 bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003925
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003926 if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0)
3927 bnx2x_sfp_module_detection(phy, params);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003928 else
3929 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
3930 }
3931
3932 DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n",
3933 rx_alarm_status);
3934 /* No need to check link status in case of
3935 module plugged in/out */
3936}
3937
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003938static u8 bnx2x_8705_read_status(struct bnx2x_phy *phy,
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003939 struct link_params *params,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003940 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003941{
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003942 u8 link_up = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003943 u16 val1, rx_sd;
3944 struct bnx2x *bp = params->bp;
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003945 DP(NETIF_MSG_LINK, "read status 8705\n");
3946 bnx2x_cl45_read(bp, phy,
3947 MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_STATUS, &val1);
3948 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003949
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003950 bnx2x_cl45_read(bp, phy,
3951 MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_STATUS, &val1);
3952 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003953
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003954 bnx2x_cl45_read(bp, phy,
3955 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD, &rx_sd);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003956
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003957 bnx2x_cl45_read(bp, phy,
3958 MDIO_PMA_DEVAD, 0xc809, &val1);
3959 bnx2x_cl45_read(bp, phy,
3960 MDIO_PMA_DEVAD, 0xc809, &val1);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003961
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003962 DP(NETIF_MSG_LINK, "8705 1.c809 val=0x%x\n", val1);
3963 link_up = ((rx_sd & 0x1) && (val1 & (1<<9)) && ((val1 & (1<<8)) == 0));
3964 if (link_up) {
3965 vars->line_speed = SPEED_10000;
3966 bnx2x_ext_phy_resolve_fc(phy, params, vars);
3967 }
3968 return link_up;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003969}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003970
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003971static u8 bnx2x_8706_8726_read_status(struct bnx2x_phy *phy,
3972 struct link_params *params,
3973 struct link_vars *vars)
3974{
3975 u8 link_up = 0;
3976 u16 val1, val2, rx_sd, pcs_status;
3977 struct bnx2x *bp = params->bp;
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003978 DP(NETIF_MSG_LINK, "XGXS 8706/8726\n");
3979 /* Clear RX Alarm*/
3980 bnx2x_cl45_read(bp, phy,
3981 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &val2);
3982 /* clear LASI indication*/
3983 bnx2x_cl45_read(bp, phy,
3984 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
3985 bnx2x_cl45_read(bp, phy,
3986 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val2);
3987 DP(NETIF_MSG_LINK, "8706/8726 LASI status 0x%x--> 0x%x\n", val1, val2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003988
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003989 bnx2x_cl45_read(bp, phy,
3990 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD, &rx_sd);
3991 bnx2x_cl45_read(bp, phy,
3992 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &pcs_status);
3993 bnx2x_cl45_read(bp, phy,
3994 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &val2);
3995 bnx2x_cl45_read(bp, phy,
3996 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &val2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003997
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003998 DP(NETIF_MSG_LINK, "8706/8726 rx_sd 0x%x pcs_status 0x%x 1Gbps"
3999 " link_status 0x%x\n", rx_sd, pcs_status, val2);
4000 /* link is up if both bit 0 of pmd_rx_sd and
4001 * bit 0 of pcs_status are set, or if the autoneg bit
4002 * 1 is set
4003 */
4004 link_up = ((rx_sd & pcs_status & 0x1) || (val2 & (1<<1)));
4005 if (link_up) {
4006 if (val2 & (1<<1))
4007 vars->line_speed = SPEED_1000;
4008 else
4009 vars->line_speed = SPEED_10000;
4010 bnx2x_ext_phy_resolve_fc(phy, params, vars);
4011 }
4012 return link_up;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004013}
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004014
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004015static u8 bnx2x_8706_read_status(struct bnx2x_phy *phy,
4016 struct link_params *params,
4017 struct link_vars *vars)
4018{
4019 return bnx2x_8706_8726_read_status(phy, params, vars);
4020}
4021
4022static u8 bnx2x_8726_read_status(struct bnx2x_phy *phy,
4023 struct link_params *params,
4024 struct link_vars *vars)
4025{
4026 struct bnx2x *bp = params->bp;
4027 u16 val1;
4028 u8 link_up = bnx2x_8706_8726_read_status(phy, params, vars);
4029 if (link_up) {
4030 bnx2x_cl45_read(bp, phy,
4031 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER,
4032 &val1);
4033 if (val1 & (1<<15)) {
4034 DP(NETIF_MSG_LINK, "Tx is disabled\n");
4035 link_up = 0;
4036 vars->line_speed = 0;
4037 }
4038 }
4039 return link_up;
4040}
4041static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy,
4042 struct link_params *params,
4043 struct link_vars *vars)
4044
4045{
4046 struct bnx2x *bp = params->bp;
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004047 u8 link_up = 0;
4048 u16 link_status = 0;
4049 u16 rx_alarm_status, val1;
4050 /* Check the LASI */
4051 bnx2x_cl45_read(bp, phy,
4052 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM,
4053 &rx_alarm_status);
4054 vars->line_speed = 0;
4055 DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n", rx_alarm_status);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004056
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004057 bnx2x_cl45_read(bp, phy,
4058 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004059
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004060 DP(NETIF_MSG_LINK, "8727 LASI status 0x%x\n", val1);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004061
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004062 /* Clear MSG-OUT */
4063 bnx2x_cl45_read(bp, phy,
4064 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &val1);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004065
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004066 /**
4067 * If a module is present and there is need to check
4068 * for over current
4069 */
4070 if (!(phy->flags & FLAGS_NOC) && !(rx_alarm_status & (1<<5))) {
4071 /* Check over-current using 8727 GPIO0 input*/
4072 bnx2x_cl45_read(bp, phy,
4073 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_GPIO_CTRL,
4074 &val1);
4075
4076 if ((val1 & (1<<8)) == 0) {
4077 DP(NETIF_MSG_LINK, "8727 Power fault has been detected"
4078 " on port %d\n", params->port);
4079 netdev_err(bp->dev, "Error: Power fault on Port %d has"
4080 " been detected and the power to "
4081 "that SFP+ module has been removed"
4082 " to prevent failure of the card."
4083 " Please remove the SFP+ module and"
4084 " restart the system to clear this"
4085 " error.\n",
4086 params->port);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004087
4088 /*
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004089 * Disable all RX_ALARMs except for
4090 * mod_abs
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004091 */
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004092 bnx2x_cl45_write(bp, phy,
4093 MDIO_PMA_DEVAD,
4094 MDIO_PMA_REG_RX_ALARM_CTRL, (1<<5));
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004095
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004096 bnx2x_cl45_read(bp, phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004097 MDIO_PMA_DEVAD,
4098 MDIO_PMA_REG_PHY_IDENTIFIER, &val1);
4099 /* Wait for module_absent_event */
4100 val1 |= (1<<8);
4101 bnx2x_cl45_write(bp, phy,
4102 MDIO_PMA_DEVAD,
4103 MDIO_PMA_REG_PHY_IDENTIFIER, val1);
4104 /* Clear RX alarm */
4105 bnx2x_cl45_read(bp, phy,
4106 MDIO_PMA_DEVAD,
4107 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
4108 return 0;
4109 }
4110 } /* Over current check */
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004111
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004112 /* When module absent bit is set, check module */
4113 if (rx_alarm_status & (1<<5)) {
4114 bnx2x_8727_handle_mod_abs(phy, params);
4115 /* Enable all mod_abs and link detection bits */
4116 bnx2x_cl45_write(bp, phy,
4117 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
4118 ((1<<5) | (1<<2)));
4119 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004120
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004121 /* If transmitter is disabled, ignore false link up indication */
4122 bnx2x_cl45_read(bp, phy,
4123 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, &val1);
4124 if (val1 & (1<<15)) {
4125 DP(NETIF_MSG_LINK, "Tx is disabled\n");
4126 return 0;
4127 }
4128
4129 bnx2x_cl45_read(bp, phy,
4130 MDIO_PMA_DEVAD,
4131 MDIO_PMA_REG_8073_SPEED_LINK_STATUS, &link_status);
4132
4133 /* Bits 0..2 --> speed detected,
4134 bits 13..15--> link is down */
4135 if ((link_status & (1<<2)) && (!(link_status & (1<<15)))) {
4136 link_up = 1;
4137 vars->line_speed = SPEED_10000;
4138 } else if ((link_status & (1<<0)) && (!(link_status & (1<<13)))) {
4139 link_up = 1;
4140 vars->line_speed = SPEED_1000;
4141 DP(NETIF_MSG_LINK, "port %x: External link up in 1G\n",
4142 params->port);
4143 } else {
4144 link_up = 0;
4145 DP(NETIF_MSG_LINK, "port %x: External link is down\n",
4146 params->port);
4147 }
4148 if (link_up)
4149 bnx2x_ext_phy_resolve_fc(phy, params, vars);
4150 return link_up;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004151}
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004152
Yaniv Rosner7aa07112010-09-07 11:41:01 +00004153static void bnx2x_8073_resolve_fc(struct bnx2x_phy *phy,
4154 struct link_params *params,
4155 struct link_vars *vars)
4156{
4157 struct bnx2x *bp = params->bp;
4158 if (phy->req_line_speed == SPEED_10 ||
4159 phy->req_line_speed == SPEED_100) {
4160 vars->flow_ctrl = phy->req_flow_ctrl;
4161 return;
4162 }
4163
4164 if (bnx2x_ext_phy_resolve_fc(phy, params, vars) &&
4165 (vars->flow_ctrl == BNX2X_FLOW_CTRL_NONE)) {
4166 u16 pause_result;
4167 u16 ld_pause; /* local */
4168 u16 lp_pause; /* link partner */
4169 bnx2x_cl45_read(bp, phy,
4170 MDIO_AN_DEVAD,
4171 MDIO_AN_REG_CL37_FC_LD, &ld_pause);
4172
4173 bnx2x_cl45_read(bp, phy,
4174 MDIO_AN_DEVAD,
4175 MDIO_AN_REG_CL37_FC_LP, &lp_pause);
4176 pause_result = (ld_pause &
4177 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 5;
4178 pause_result |= (lp_pause &
4179 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 7;
4180
4181 bnx2x_pause_resolve(vars, pause_result);
4182 DP(NETIF_MSG_LINK, "Ext PHY CL37 pause result 0x%x\n",
4183 pause_result);
4184 }
4185}
4186
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004187static u8 bnx2x_8073_read_status(struct bnx2x_phy *phy,
4188 struct link_params *params,
4189 struct link_vars *vars)
4190{
4191 struct bnx2x *bp = params->bp;
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004192 u8 link_up = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004193 u16 val1, val2;
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004194 u16 link_status = 0;
4195 u16 an1000_status = 0;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00004196
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004197 bnx2x_cl45_read(bp, phy,
4198 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004199
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004200 DP(NETIF_MSG_LINK, "8703 LASI status 0x%x\n", val1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004201
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004202 /* clear the interrupt LASI status register */
4203 bnx2x_cl45_read(bp, phy,
4204 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val2);
4205 bnx2x_cl45_read(bp, phy,
4206 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val1);
4207 DP(NETIF_MSG_LINK, "807x PCS status 0x%x->0x%x\n", val2, val1);
4208 /* Clear MSG-OUT */
4209 bnx2x_cl45_read(bp, phy,
4210 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &val1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004211
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004212 /* Check the LASI */
4213 bnx2x_cl45_read(bp, phy,
4214 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &val2);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004215
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004216 DP(NETIF_MSG_LINK, "KR 0x9003 0x%x\n", val2);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004217
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004218 /* Check the link status */
4219 bnx2x_cl45_read(bp, phy,
4220 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val2);
4221 DP(NETIF_MSG_LINK, "KR PCS status 0x%x\n", val2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004222
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004223 bnx2x_cl45_read(bp, phy,
4224 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
4225 bnx2x_cl45_read(bp, phy,
4226 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
4227 link_up = ((val1 & 4) == 4);
4228 DP(NETIF_MSG_LINK, "PMA_REG_STATUS=0x%x\n", val1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004229
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004230 if (link_up &&
4231 ((phy->req_line_speed != SPEED_10000))) {
4232 if (bnx2x_8073_xaui_wa(bp, phy) != 0)
4233 return 0;
4234 }
4235 bnx2x_cl45_read(bp, phy,
4236 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &an1000_status);
4237 bnx2x_cl45_read(bp, phy,
4238 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &an1000_status);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004239
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004240 /* Check the link status on 1.1.2 */
4241 bnx2x_cl45_read(bp, phy,
4242 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
4243 bnx2x_cl45_read(bp, phy,
4244 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
4245 DP(NETIF_MSG_LINK, "KR PMA status 0x%x->0x%x,"
4246 "an_link_status=0x%x\n", val2, val1, an1000_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004247
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004248 link_up = (((val1 & 4) == 4) || (an1000_status & (1<<1)));
4249 if (link_up && bnx2x_8073_is_snr_needed(bp, phy)) {
4250 /* The SNR will improve about 2dbby
4251 changing the BW and FEE main tap.*/
4252 /* The 1st write to change FFE main
4253 tap is set before restart AN */
4254 /* Change PLL Bandwidth in EDC
4255 register */
4256 bnx2x_cl45_write(bp, phy,
4257 MDIO_PMA_DEVAD, MDIO_PMA_REG_PLL_BANDWIDTH,
4258 0x26BC);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004259
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004260 /* Change CDR Bandwidth in EDC register */
4261 bnx2x_cl45_write(bp, phy,
4262 MDIO_PMA_DEVAD, MDIO_PMA_REG_CDR_BANDWIDTH,
4263 0x0333);
4264 }
4265 bnx2x_cl45_read(bp, phy,
4266 MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
4267 &link_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004268
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004269 /* Bits 0..2 --> speed detected, bits 13..15--> link is down */
4270 if ((link_status & (1<<2)) && (!(link_status & (1<<15)))) {
4271 link_up = 1;
4272 vars->line_speed = SPEED_10000;
4273 DP(NETIF_MSG_LINK, "port %x: External link up in 10G\n",
4274 params->port);
4275 } else if ((link_status & (1<<1)) && (!(link_status & (1<<14)))) {
4276 link_up = 1;
4277 vars->line_speed = SPEED_2500;
4278 DP(NETIF_MSG_LINK, "port %x: External link up in 2.5G\n",
4279 params->port);
4280 } else if ((link_status & (1<<0)) && (!(link_status & (1<<13)))) {
4281 link_up = 1;
4282 vars->line_speed = SPEED_1000;
4283 DP(NETIF_MSG_LINK, "port %x: External link up in 1G\n",
4284 params->port);
4285 } else {
4286 link_up = 0;
4287 DP(NETIF_MSG_LINK, "port %x: External link is down\n",
4288 params->port);
4289 }
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004290
Yaniv Rosner7aa07112010-09-07 11:41:01 +00004291 if (link_up) {
4292 bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
4293 bnx2x_8073_resolve_fc(phy, params, vars);
4294 }
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004295 return link_up;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004296}
4297
4298static u8 bnx2x_7101_read_status(struct bnx2x_phy *phy,
4299 struct link_params *params,
4300 struct link_vars *vars)
4301{
4302 struct bnx2x *bp = params->bp;
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004303 u8 link_up;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004304 u16 val1, val2;
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004305 bnx2x_cl45_read(bp, phy,
4306 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val2);
4307 bnx2x_cl45_read(bp, phy,
4308 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
4309 DP(NETIF_MSG_LINK, "10G-base-T LASI status 0x%x->0x%x\n",
4310 val2, val1);
4311 bnx2x_cl45_read(bp, phy,
4312 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
4313 bnx2x_cl45_read(bp, phy,
4314 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
4315 DP(NETIF_MSG_LINK, "10G-base-T PMA status 0x%x->0x%x\n",
4316 val2, val1);
4317 link_up = ((val1 & 4) == 4);
4318 /* if link is up
4319 * print the AN outcome of the SFX7101 PHY
4320 */
4321 if (link_up) {
4322 bnx2x_cl45_read(bp, phy,
4323 MDIO_AN_DEVAD, MDIO_AN_REG_MASTER_STATUS,
4324 &val2);
4325 vars->line_speed = SPEED_10000;
4326 DP(NETIF_MSG_LINK, "SFX7101 AN status 0x%x->Master=%x\n",
4327 val2, (val2 & (1<<14)));
Yaniv Rosner7aa07112010-09-07 11:41:01 +00004328 bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
4329 bnx2x_ext_phy_resolve_fc(phy, params, vars);
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004330 }
4331 return link_up;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004332}
4333
4334static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy,
4335 struct link_params *params,
4336 struct link_vars *vars)
4337{
4338 struct bnx2x *bp = params->bp;
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004339 u16 val, val1, val2;
4340 u8 link_up = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004341
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004342 /* Check 10G-BaseT link status */
4343 /* Check PMD signal ok */
4344 bnx2x_cl45_read(bp, phy,
4345 MDIO_AN_DEVAD, 0xFFFA, &val1);
4346 bnx2x_cl45_read(bp, phy,
4347 MDIO_PMA_DEVAD, MDIO_PMA_REG_8481_PMD_SIGNAL,
4348 &val2);
4349 DP(NETIF_MSG_LINK, "BCM848xx: PMD_SIGNAL 1.a811 = 0x%x\n", val2);
4350
4351 /* Check link 10G */
4352 if (val2 & (1<<11)) {
4353 vars->line_speed = SPEED_10000;
4354 link_up = 1;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00004355 bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004356 } else { /* Check Legacy speed link */
4357 u16 legacy_status, legacy_speed;
4358
4359 /* Enable expansion register 0x42 (Operation mode status) */
4360 bnx2x_cl45_write(bp, phy,
4361 MDIO_AN_DEVAD,
4362 MDIO_AN_REG_8481_EXPANSION_REG_ACCESS, 0xf42);
4363
4364 /* Get legacy speed operation status */
4365 bnx2x_cl45_read(bp, phy,
4366 MDIO_AN_DEVAD,
4367 MDIO_AN_REG_8481_EXPANSION_REG_RD_RW,
4368 &legacy_status);
4369
4370 DP(NETIF_MSG_LINK, "Legacy speed status"
4371 " = 0x%x\n", legacy_status);
4372 link_up = ((legacy_status & (1<<11)) == (1<<11));
4373 if (link_up) {
4374 legacy_speed = (legacy_status & (3<<9));
4375 if (legacy_speed == (0<<9))
4376 vars->line_speed = SPEED_10;
4377 else if (legacy_speed == (1<<9))
4378 vars->line_speed = SPEED_100;
4379 else if (legacy_speed == (2<<9))
4380 vars->line_speed = SPEED_1000;
4381 else /* Should not happen */
4382 vars->line_speed = 0;
4383
4384 if (legacy_status & (1<<8))
4385 vars->duplex = DUPLEX_FULL;
4386 else
4387 vars->duplex = DUPLEX_HALF;
4388
4389 DP(NETIF_MSG_LINK, "Link is up in %dMbps,"
4390 " is_duplex_full= %d\n", vars->line_speed,
4391 (vars->duplex == DUPLEX_FULL));
4392
4393 /* Check legacy speed AN resolution */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004394 bnx2x_cl45_read(bp, phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004395 MDIO_AN_DEVAD,
4396 MDIO_AN_REG_8481_LEGACY_MII_STATUS,
4397 &val);
4398 if (val & (1<<5))
4399 vars->link_status |=
4400 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004401 bnx2x_cl45_read(bp, phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004402 MDIO_AN_DEVAD,
4403 MDIO_AN_REG_8481_LEGACY_AN_EXPANSION,
4404 &val);
4405 if ((val & (1<<0)) == 0)
4406 vars->link_status |=
4407 LINK_STATUS_PARALLEL_DETECTION_USED;
4408 }
4409 }
Yaniv Rosner7aa07112010-09-07 11:41:01 +00004410 if (link_up) {
4411 DP(NETIF_MSG_LINK, "BCM84823: link speed is %d\n",
4412 vars->line_speed);
4413 bnx2x_ext_phy_resolve_fc(phy, params, vars);
4414 }
4415
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004416 return link_up;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004417}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004418static void bnx2x_link_int_enable(struct link_params *params)
4419{
4420 u8 port = params->port;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004421 u32 mask;
4422 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00004423
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004424 /* setting the status to report on link up
4425 for either XGXS or SerDes */
4426
4427 if (params->switch_cfg == SWITCH_CFG_10G) {
4428 mask = (NIG_MASK_XGXS0_LINK10G |
4429 NIG_MASK_XGXS0_LINK_STATUS);
4430 DP(NETIF_MSG_LINK, "enabled XGXS interrupt\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004431 if (!(SINGLE_MEDIA_DIRECT(params)) &&
4432 params->phy[INT_PHY].type !=
4433 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004434 mask |= NIG_MASK_MI_INT;
4435 DP(NETIF_MSG_LINK, "enabled external phy int\n");
4436 }
4437
4438 } else { /* SerDes */
4439 mask = NIG_MASK_SERDES0_LINK_STATUS;
4440 DP(NETIF_MSG_LINK, "enabled SerDes interrupt\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004441 if (!(SINGLE_MEDIA_DIRECT(params)) &&
4442 params->phy[INT_PHY].type !=
4443 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_NOT_CONN) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004444 mask |= NIG_MASK_MI_INT;
4445 DP(NETIF_MSG_LINK, "enabled external phy int\n");
4446 }
4447 }
4448 bnx2x_bits_en(bp,
4449 NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
4450 mask);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00004451
4452 DP(NETIF_MSG_LINK, "port %x, is_xgxs %x, int_status 0x%x\n", port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004453 (params->switch_cfg == SWITCH_CFG_10G),
4454 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004455 DP(NETIF_MSG_LINK, " int_mask 0x%x, MI_INT %x, SERDES_LINK %x\n",
4456 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
4457 REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
4458 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS+port*0x3c));
4459 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
4460 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
4461 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
4462}
4463
Eilon Greenstein2f904462009-08-12 08:22:16 +00004464static void bnx2x_8481_rearm_latch_signal(struct bnx2x *bp, u8 port,
4465 u8 is_mi_int)
4466{
4467 u32 latch_status = 0, is_mi_int_status;
4468 /* Disable the MI INT ( external phy int )
4469 * by writing 1 to the status register. Link down indication
4470 * is high-active-signal, so in this case we need to write the
4471 * status to clear the XOR
4472 */
4473 /* Read Latched signals */
4474 latch_status = REG_RD(bp,
4475 NIG_REG_LATCH_STATUS_0 + port*8);
4476 is_mi_int_status = REG_RD(bp,
4477 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4);
4478 DP(NETIF_MSG_LINK, "original_signal = 0x%x, nig_status = 0x%x,"
4479 "latch_status = 0x%x\n",
4480 is_mi_int, is_mi_int_status, latch_status);
4481 /* Handle only those with latched-signal=up.*/
4482 if (latch_status & 1) {
4483 /* For all latched-signal=up,Write original_signal to status */
4484 if (is_mi_int)
4485 bnx2x_bits_en(bp,
4486 NIG_REG_STATUS_INTERRUPT_PORT0
4487 + port*4,
4488 NIG_STATUS_EMAC0_MI_INT);
4489 else
4490 bnx2x_bits_dis(bp,
4491 NIG_REG_STATUS_INTERRUPT_PORT0
4492 + port*4,
4493 NIG_STATUS_EMAC0_MI_INT);
4494 /* For all latched-signal=up : Re-Arm Latch signals */
4495 REG_WR(bp, NIG_REG_LATCH_STATUS_0 + port*8,
4496 (latch_status & 0xfffe) | (latch_status & 1));
4497 }
4498}
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004499
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004500/*
4501 * link management
4502 */
4503static void bnx2x_link_int_ack(struct link_params *params,
Eilon Greenstein2f904462009-08-12 08:22:16 +00004504 struct link_vars *vars, u8 is_10g,
4505 u8 is_mi_int)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004506{
4507 struct bnx2x *bp = params->bp;
4508 u8 port = params->port;
4509
4510 /* first reset all status
4511 * we assume only one line will be change at a time */
4512 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
4513 (NIG_STATUS_XGXS0_LINK10G |
4514 NIG_STATUS_XGXS0_LINK_STATUS |
4515 NIG_STATUS_SERDES0_LINK_STATUS));
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004516 if ((params->phy[EXT_PHY1].type
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02004517 == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481) ||
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004518 (params->phy[EXT_PHY1].type
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02004519 == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823)) {
Eilon Greenstein2f904462009-08-12 08:22:16 +00004520 bnx2x_8481_rearm_latch_signal(bp, port, is_mi_int);
4521 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004522 if (vars->phy_link_up) {
4523 if (is_10g) {
4524 /* Disable the 10G link interrupt
4525 * by writing 1 to the status register
4526 */
4527 DP(NETIF_MSG_LINK, "10G XGXS phy link up\n");
4528 bnx2x_bits_en(bp,
4529 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
4530 NIG_STATUS_XGXS0_LINK10G);
4531
4532 } else if (params->switch_cfg == SWITCH_CFG_10G) {
4533 /* Disable the link interrupt
4534 * by writing 1 to the relevant lane
4535 * in the status register
4536 */
4537 u32 ser_lane = ((params->lane_config &
4538 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
4539 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
4540
Eilon Greenstein2f904462009-08-12 08:22:16 +00004541 DP(NETIF_MSG_LINK, "%d speed XGXS phy link up\n",
4542 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004543 bnx2x_bits_en(bp,
4544 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
4545 ((1 << ser_lane) <<
4546 NIG_STATUS_XGXS0_LINK_STATUS_SIZE));
4547
4548 } else { /* SerDes */
4549 DP(NETIF_MSG_LINK, "SerDes phy link up\n");
4550 /* Disable the link interrupt
4551 * by writing 1 to the status register
4552 */
4553 bnx2x_bits_en(bp,
4554 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
4555 NIG_STATUS_SERDES0_LINK_STATUS);
4556 }
4557
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004558 }
4559}
4560
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004561static u8 bnx2x_7101_format_ver(u32 spirom_ver, u8 *str, u16 *len)
4562{
4563 if (*len < 5)
4564 return -EINVAL;
4565 str[0] = (spirom_ver & 0xFF);
4566 str[1] = (spirom_ver & 0xFF00) >> 8;
4567 str[2] = (spirom_ver & 0xFF0000) >> 16;
4568 str[3] = (spirom_ver & 0xFF000000) >> 24;
4569 str[4] = '\0';
4570 *len -= 5;
4571 return 0;
4572}
4573
4574static u8 bnx2x_format_ver(u32 num, u8 *str, u16 *len)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004575{
4576 u8 *str_ptr = str;
4577 u32 mask = 0xf0000000;
4578 u8 shift = 8*4;
4579 u8 digit;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004580 if (*len < 10) {
Frederik Schwarzer025dfda2008-10-16 19:02:37 +02004581 /* Need more than 10chars for this format */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004582 *str_ptr = '\0';
4583 return -EINVAL;
4584 }
4585 while (shift > 0) {
4586
4587 shift -= 4;
4588 digit = ((num & mask) >> shift);
4589 if (digit < 0xa)
4590 *str_ptr = digit + '0';
4591 else
4592 *str_ptr = digit - 0xa + 'a';
4593 str_ptr++;
4594 mask = mask >> 4;
4595 if (shift == 4*4) {
4596 *str_ptr = ':';
4597 str_ptr++;
4598 }
4599 }
4600 *str_ptr = '\0';
4601 return 0;
4602}
4603
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004604static u8 bnx2x_848xx_format_ver(u32 raw_ver, u8 *str, u16 *len)
4605{
4606 u8 status = 0;
4607 u32 spirom_ver;
4608 spirom_ver = ((raw_ver & 0xF80) >> 7) << 16 | (raw_ver & 0x7F);
4609 status = bnx2x_format_ver(spirom_ver, str, len);
4610 return status;
4611}
4612
4613static u8 bnx2x_null_format_ver(u32 spirom_ver, u8 *str, u16 *len)
4614{
4615 str[0] = '\0';
4616 (*len)--;
4617 return 0;
4618}
4619
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004620u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
4621 u8 *version, u16 len)
4622{
Julia Lawall0376d5b2009-07-19 05:26:35 +00004623 struct bnx2x *bp;
Eilon Greensteina35da8d2009-02-12 08:37:02 +00004624 u32 spirom_ver = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004625 u8 status = 0;
4626 u8 *ver_p = version;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004627 if (version == NULL || params == NULL)
4628 return -EINVAL;
Julia Lawall0376d5b2009-07-19 05:26:35 +00004629 bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004630
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004631 /* Extract first external phy*/
4632 version[0] = '\0';
4633 spirom_ver = REG_RD(bp, params->phy[EXT_PHY1].ver_addr);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00004634
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004635 if (params->phy[EXT_PHY1].format_fw_ver)
4636 status |= params->phy[EXT_PHY1].format_fw_ver(spirom_ver,
4637 ver_p,
4638 &len);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004639 return status;
4640}
4641
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004642static void bnx2x_set_xgxs_loopback(struct bnx2x_phy *phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004643 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004644{
4645 u8 port = params->port;
4646 struct bnx2x *bp = params->bp;
4647
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004648 if (phy->req_line_speed != SPEED_1000) {
Eilon Greenstein6378c022008-08-13 15:59:25 -07004649 u32 md_devad;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004650
4651 DP(NETIF_MSG_LINK, "XGXS 10G loopback enable\n");
4652
4653 /* change the uni_phy_addr in the nig */
4654 md_devad = REG_RD(bp, (NIG_REG_XGXS0_CTRL_MD_DEVAD +
4655 port*0x18));
4656
4657 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, 0x5);
4658
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004659 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004660 5,
4661 (MDIO_REG_BANK_AER_BLOCK +
4662 (MDIO_AER_BLOCK_AER_REG & 0xf)),
4663 0x2800);
4664
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004665 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004666 5,
4667 (MDIO_REG_BANK_CL73_IEEEB0 +
4668 (MDIO_CL73_IEEEB0_CL73_AN_CONTROL & 0xf)),
4669 0x6041);
Eilon Greenstein38582762009-01-14 06:44:16 +00004670 msleep(200);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004671 /* set aer mmd back */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004672 bnx2x_set_aer_mmd(params, phy);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004673
4674 /* and md_devad */
4675 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
4676 md_devad);
4677
4678 } else {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004679 u16 mii_ctrl;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004680 DP(NETIF_MSG_LINK, "XGXS 1G loopback enable\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004681 bnx2x_cl45_read(bp, phy, 5,
4682 (MDIO_REG_BANK_COMBO_IEEE0 +
4683 (MDIO_COMBO_IEEE0_MII_CONTROL & 0xf)),
4684 &mii_ctrl);
4685 bnx2x_cl45_write(bp, phy, 5,
4686 (MDIO_REG_BANK_COMBO_IEEE0 +
4687 (MDIO_COMBO_IEEE0_MII_CONTROL & 0xf)),
4688 mii_ctrl |
4689 MDIO_COMBO_IEEO_MII_CONTROL_LOOPBACK);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004690 }
4691}
4692
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004693static void bnx2x_8726_config_loopback(struct bnx2x_phy *phy,
4694 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004695{
4696 struct bnx2x *bp = params->bp;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004697 DP(NETIF_MSG_LINK, "PMA/PMD ext_phy_loopback: 8726\n");
4698 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x0001);
4699}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004700
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004701static void bnx2x_7101_config_loopback(struct bnx2x_phy *phy,
4702 struct link_params *params)
4703{
4704 struct bnx2x *bp = params->bp;
4705 /* SFX7101_XGXS_TEST1 */
4706 bnx2x_cl45_write(bp, phy,
4707 MDIO_XS_DEVAD, MDIO_XS_SFX7101_XGXS_TEST1, 0x100);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004708}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004709/*
4710 *------------------------------------------------------------------------
4711 * bnx2x_override_led_value -
4712 *
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004713 * Override the led value of the requested led
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004714 *
4715 *------------------------------------------------------------------------
4716 */
4717u8 bnx2x_override_led_value(struct bnx2x *bp, u8 port,
4718 u32 led_idx, u32 value)
4719{
4720 u32 reg_val;
4721
4722 /* If port 0 then use EMAC0, else use EMAC1*/
4723 u32 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
4724
4725 DP(NETIF_MSG_LINK,
4726 "bnx2x_override_led_value() port %x led_idx %d value %d\n",
4727 port, led_idx, value);
4728
4729 switch (led_idx) {
4730 case 0: /* 10MB led */
4731 /* Read the current value of the LED register in
4732 the EMAC block */
4733 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
4734 /* Set the OVERRIDE bit to 1 */
4735 reg_val |= EMAC_LED_OVERRIDE;
4736 /* If value is 1, set the 10M_OVERRIDE bit,
4737 otherwise reset it.*/
4738 reg_val = (value == 1) ? (reg_val | EMAC_LED_10MB_OVERRIDE) :
4739 (reg_val & ~EMAC_LED_10MB_OVERRIDE);
4740 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
4741 break;
4742 case 1: /*100MB led */
4743 /*Read the current value of the LED register in
4744 the EMAC block */
4745 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
4746 /* Set the OVERRIDE bit to 1 */
4747 reg_val |= EMAC_LED_OVERRIDE;
4748 /* If value is 1, set the 100M_OVERRIDE bit,
4749 otherwise reset it.*/
4750 reg_val = (value == 1) ? (reg_val | EMAC_LED_100MB_OVERRIDE) :
4751 (reg_val & ~EMAC_LED_100MB_OVERRIDE);
4752 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
4753 break;
4754 case 2: /* 1000MB led */
4755 /* Read the current value of the LED register in the
4756 EMAC block */
4757 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
4758 /* Set the OVERRIDE bit to 1 */
4759 reg_val |= EMAC_LED_OVERRIDE;
4760 /* If value is 1, set the 1000M_OVERRIDE bit, otherwise
4761 reset it. */
4762 reg_val = (value == 1) ? (reg_val | EMAC_LED_1000MB_OVERRIDE) :
4763 (reg_val & ~EMAC_LED_1000MB_OVERRIDE);
4764 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
4765 break;
4766 case 3: /* 2500MB led */
4767 /* Read the current value of the LED register in the
4768 EMAC block*/
4769 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
4770 /* Set the OVERRIDE bit to 1 */
4771 reg_val |= EMAC_LED_OVERRIDE;
4772 /* If value is 1, set the 2500M_OVERRIDE bit, otherwise
4773 reset it.*/
4774 reg_val = (value == 1) ? (reg_val | EMAC_LED_2500MB_OVERRIDE) :
4775 (reg_val & ~EMAC_LED_2500MB_OVERRIDE);
4776 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
4777 break;
4778 case 4: /*10G led */
4779 if (port == 0) {
4780 REG_WR(bp, NIG_REG_LED_10G_P0,
4781 value);
4782 } else {
4783 REG_WR(bp, NIG_REG_LED_10G_P1,
4784 value);
4785 }
4786 break;
4787 case 5: /* TRAFFIC led */
4788 /* Find if the traffic control is via BMAC or EMAC */
4789 if (port == 0)
4790 reg_val = REG_RD(bp, NIG_REG_NIG_EMAC0_EN);
4791 else
4792 reg_val = REG_RD(bp, NIG_REG_NIG_EMAC1_EN);
4793
4794 /* Override the traffic led in the EMAC:*/
4795 if (reg_val == 1) {
4796 /* Read the current value of the LED register in
4797 the EMAC block */
4798 reg_val = REG_RD(bp, emac_base +
4799 EMAC_REG_EMAC_LED);
4800 /* Set the TRAFFIC_OVERRIDE bit to 1 */
4801 reg_val |= EMAC_LED_OVERRIDE;
4802 /* If value is 1, set the TRAFFIC bit, otherwise
4803 reset it.*/
4804 reg_val = (value == 1) ? (reg_val | EMAC_LED_TRAFFIC) :
4805 (reg_val & ~EMAC_LED_TRAFFIC);
4806 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
4807 } else { /* Override the traffic led in the BMAC: */
4808 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
4809 + port*4, 1);
4810 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 + port*4,
4811 value);
4812 }
4813 break;
4814 default:
4815 DP(NETIF_MSG_LINK,
4816 "bnx2x_override_led_value() unknown led index %d "
4817 "(should be 0-5)\n", led_idx);
4818 return -EINVAL;
4819 }
4820
4821 return 0;
4822}
4823
4824
Yaniv Rosner7846e472009-11-05 19:18:07 +02004825u8 bnx2x_set_led(struct link_params *params, u8 mode, u32 speed)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004826{
Yaniv Rosner7846e472009-11-05 19:18:07 +02004827 u8 port = params->port;
4828 u16 hw_led_mode = params->hw_led_mode;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004829 u8 rc = 0;
Eilon Greenstein345b5d52008-08-13 15:58:12 -07004830 u32 tmp;
4831 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Yaniv Rosner7846e472009-11-05 19:18:07 +02004832 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004833 DP(NETIF_MSG_LINK, "bnx2x_set_led: port %x, mode %d\n", port, mode);
4834 DP(NETIF_MSG_LINK, "speed 0x%x, hw_led_mode 0x%x\n",
4835 speed, hw_led_mode);
4836 switch (mode) {
4837 case LED_MODE_OFF:
4838 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 0);
4839 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
4840 SHARED_HW_CFG_LED_MAC1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07004841
4842 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07004843 EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp | EMAC_LED_OVERRIDE));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004844 break;
4845
4846 case LED_MODE_OPER:
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004847 if (SINGLE_MEDIA_DIRECT(params)) {
Yaniv Rosner7846e472009-11-05 19:18:07 +02004848 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0);
4849 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1);
4850 } else {
4851 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
4852 hw_led_mode);
4853 }
4854
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004855 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 +
4856 port*4, 0);
4857 /* Set blinking rate to ~15.9Hz */
4858 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4,
4859 LED_BLINK_RATE_VAL);
4860 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 +
4861 port*4, 1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07004862 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07004863 EMAC_WR(bp, EMAC_REG_EMAC_LED,
Eilon Greenstein345b5d52008-08-13 15:58:12 -07004864 (tmp & (~EMAC_LED_OVERRIDE)));
4865
Yaniv Rosner7846e472009-11-05 19:18:07 +02004866 if (CHIP_IS_E1(bp) &&
Eilon Greenstein34f80b02008-06-23 20:33:01 -07004867 ((speed == SPEED_2500) ||
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004868 (speed == SPEED_1000) ||
4869 (speed == SPEED_100) ||
4870 (speed == SPEED_10))) {
4871 /* On Everest 1 Ax chip versions for speeds less than
4872 10G LED scheme is different */
4873 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
4874 + port*4, 1);
4875 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 +
4876 port*4, 0);
4877 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_TRAFFIC_P0 +
4878 port*4, 1);
4879 }
4880 break;
4881
4882 default:
4883 rc = -EINVAL;
4884 DP(NETIF_MSG_LINK, "bnx2x_set_led: Invalid led mode %d\n",
4885 mode);
4886 break;
4887 }
4888 return rc;
4889
4890}
4891
4892u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars)
4893{
4894 struct bnx2x *bp = params->bp;
4895 u16 gp_status = 0;
4896
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004897 CL45_RD_OVER_CL22(bp, &params->phy[INT_PHY],
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004898 MDIO_REG_BANK_GP_STATUS,
4899 MDIO_GP_STATUS_TOP_AN_STATUS1,
4900 &gp_status);
4901 /* link is up only if both local phy and external phy are up */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004902 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) {
4903 u8 ext_phy_link_up = 1;
4904 struct link_vars temp_vars;
4905 if (params->phy[EXT_PHY1].read_status)
4906 ext_phy_link_up &=
4907 params->phy[EXT_PHY1].read_status(
4908 &params->phy[EXT_PHY1],
4909 params, &temp_vars);
4910 if (ext_phy_link_up)
4911 return 0;
4912 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004913
4914 return -ESRCH;
4915}
4916
4917static u8 bnx2x_link_initialize(struct link_params *params,
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00004918 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004919{
4920 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004921 u8 rc = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004922 u8 phy_index, non_ext_phy;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004923 struct bnx2x_phy *ext_phy = &params->phy[EXT_PHY1];
4924 struct bnx2x_phy *int_phy = &params->phy[INT_PHY];
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004925 /* Activate the external PHY */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004926
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004927 bnx2x_set_aer_mmd(params, int_phy);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004928
4929 if (vars->phy_flags & PHY_XGXS_FLAG)
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004930 bnx2x_set_master_ln(params, int_phy);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004931
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004932 rc = bnx2x_reset_unicore(params, int_phy,
4933 int_phy->type ==
4934 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004935 /* reset the SerDes and wait for reset bit return low */
4936 if (rc != 0)
4937 return rc;
4938
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004939 bnx2x_set_aer_mmd(params, int_phy);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004940
4941 /* setting the masterLn_def again after the reset */
4942 if (vars->phy_flags & PHY_XGXS_FLAG) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004943 bnx2x_set_master_ln(params, int_phy);
4944 bnx2x_set_swap_lanes(params, int_phy);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004945 }
4946
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004947 if (vars->phy_flags & PHY_XGXS_FLAG) {
Eilon Greenstein44722d12009-01-14 06:44:21 +00004948 if ((params->req_line_speed &&
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004949 ((params->req_line_speed == SPEED_100) ||
Eilon Greenstein44722d12009-01-14 06:44:21 +00004950 (params->req_line_speed == SPEED_10))) ||
4951 (!params->req_line_speed &&
4952 (params->speed_cap_mask >=
4953 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL) &&
4954 (params->speed_cap_mask <
4955 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
4956 )) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004957 vars->phy_flags |= PHY_SGMII_FLAG;
4958 } else {
4959 vars->phy_flags &= ~PHY_SGMII_FLAG;
4960 }
4961 }
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004962 /* In case of external phy existance, the line speed would be the
4963 line speed linked up by the external phy. In case it is direct only,
4964 then the line_speed during initialization will be equal to the
4965 req_line_speed*/
4966 vars->line_speed = params->req_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004967
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004968 bnx2x_calc_ieee_aneg_adv(int_phy, params, &vars->ieee_fc);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004969
4970 /* init ext phy and enable link state int */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004971 non_ext_phy = ((ext_phy->type ==
4972 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ||
Eilon Greenstein8660d8c2009-03-02 08:01:02 +00004973 (params->loopback_mode == LOOPBACK_XGXS_10));
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004974
4975 if (non_ext_phy ||
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004976 (ext_phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) ||
4977 (ext_phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706) ||
4978 (ext_phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) ||
Eilon Greenstein8660d8c2009-03-02 08:01:02 +00004979 (params->loopback_mode == LOOPBACK_EXT_PHY)) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004980 if (vars->line_speed == SPEED_AUTO_NEG)
4981 bnx2x_set_parallel_detection(int_phy, params);
4982 bnx2x_init_internal_phy(int_phy, params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004983 }
4984
4985 if (!non_ext_phy)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004986 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
4987 phy_index++) {
4988 params->phy[phy_index].config_init(
4989 &params->phy[phy_index],
4990 params, vars);
4991 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004992
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00004993 /* Reset the interrupt indication after phy was initialized */
4994 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 +
4995 params->port*4,
4996 (NIG_STATUS_XGXS0_LINK10G |
4997 NIG_STATUS_XGXS0_LINK_STATUS |
4998 NIG_STATUS_SERDES0_LINK_STATUS |
4999 NIG_MASK_MI_INT));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005000
5001 return rc;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005002}
5003
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005004static void set_phy_vars(struct link_params *params)
5005{
5006 struct bnx2x *bp = params->bp;
5007 u8 actual_phy_idx, phy_index;
5008
5009 for (phy_index = INT_PHY; phy_index < params->num_phys;
5010 phy_index++) {
5011
5012 actual_phy_idx = phy_index;
5013 params->phy[actual_phy_idx].req_flow_ctrl =
5014 params->req_flow_ctrl;
5015
5016 params->phy[actual_phy_idx].req_line_speed =
5017 params->req_line_speed;
5018
5019 params->phy[actual_phy_idx].speed_cap_mask =
5020 params->speed_cap_mask;
5021
5022 params->phy[actual_phy_idx].req_duplex =
5023 params->req_duplex;
5024
5025 DP(NETIF_MSG_LINK, "req_flow_ctrl %x, req_line_speed %x,"
5026 " speed_cap_mask %x\n",
5027 params->phy[actual_phy_idx].req_flow_ctrl,
5028 params->phy[actual_phy_idx].req_line_speed,
5029 params->phy[actual_phy_idx].speed_cap_mask);
5030 }
5031}
5032
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005033u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
5034{
5035 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005036 u32 val;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005037
5038 DP(NETIF_MSG_LINK, "Phy Initialization started\n");
5039 DP(NETIF_MSG_LINK, "req_speed %d, req_flowctrl %d\n",
5040 params->req_line_speed, params->req_flow_ctrl);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005041 vars->link_status = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005042 vars->phy_link_up = 0;
5043 vars->link_up = 0;
5044 vars->line_speed = 0;
5045 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08005046 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005047 vars->mac_type = MAC_TYPE_NONE;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005048 vars->phy_flags = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005049
5050 /* disable attentions */
5051 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4,
5052 (NIG_MASK_XGXS0_LINK_STATUS |
5053 NIG_MASK_XGXS0_LINK10G |
5054 NIG_MASK_SERDES0_LINK_STATUS |
5055 NIG_MASK_MI_INT));
5056
5057 bnx2x_emac_init(params, vars);
5058
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005059 if (params->num_phys == 0) {
5060 DP(NETIF_MSG_LINK, "No phy found for initialization !!\n");
5061 return -EINVAL;
5062 }
5063 set_phy_vars(params);
5064
5065 DP(NETIF_MSG_LINK, "Num of phys on board: %d\n", params->num_phys);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005066 if (CHIP_REV_IS_FPGA(bp)) {
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005067
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005068 vars->link_up = 1;
5069 vars->line_speed = SPEED_10000;
5070 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08005071 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005072 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
Eilon Greenstein34f80b02008-06-23 20:33:01 -07005073 /* enable on E1.5 FPGA */
5074 if (CHIP_IS_E1H(bp)) {
5075 vars->flow_ctrl |=
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005076 (BNX2X_FLOW_CTRL_TX |
5077 BNX2X_FLOW_CTRL_RX);
Eilon Greenstein34f80b02008-06-23 20:33:01 -07005078 vars->link_status |=
5079 (LINK_STATUS_TX_FLOW_CONTROL_ENABLED |
5080 LINK_STATUS_RX_FLOW_CONTROL_ENABLED);
5081 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005082
5083 bnx2x_emac_enable(params, vars, 0);
5084 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
5085 /* disable drain */
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005086 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005087
5088 /* update shared memory */
5089 bnx2x_update_mng(params, vars->link_status);
5090
5091 return 0;
5092
5093 } else
5094 if (CHIP_REV_IS_EMUL(bp)) {
5095
5096 vars->link_up = 1;
5097 vars->line_speed = SPEED_10000;
5098 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08005099 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005100 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
5101
5102 bnx2x_bmac_enable(params, vars, 0);
5103
5104 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
5105 /* Disable drain */
5106 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
5107 + params->port*4, 0);
5108
5109 /* update shared memory */
5110 bnx2x_update_mng(params, vars->link_status);
5111
5112 return 0;
5113
5114 } else
5115 if (params->loopback_mode == LOOPBACK_BMAC) {
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005116
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005117 vars->link_up = 1;
5118 vars->line_speed = SPEED_10000;
5119 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08005120 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005121 vars->mac_type = MAC_TYPE_BMAC;
5122
5123 vars->phy_flags = PHY_XGXS_FLAG;
5124
5125 bnx2x_phy_deassert(params, vars->phy_flags);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005126
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005127 /* set bmac loopback */
5128 bnx2x_bmac_enable(params, vars, 1);
5129
5130 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
5131 params->port*4, 0);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005132
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005133 } else if (params->loopback_mode == LOOPBACK_EMAC) {
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005134
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005135 vars->link_up = 1;
5136 vars->line_speed = SPEED_1000;
5137 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08005138 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005139 vars->mac_type = MAC_TYPE_EMAC;
5140
5141 vars->phy_flags = PHY_XGXS_FLAG;
5142
5143 bnx2x_phy_deassert(params, vars->phy_flags);
5144 /* set bmac loopback */
5145 bnx2x_emac_enable(params, vars, 1);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005146 bnx2x_emac_program(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005147 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
5148 params->port*4, 0);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005149
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005150 } else if ((params->loopback_mode == LOOPBACK_XGXS_10) ||
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005151 (params->loopback_mode == LOOPBACK_EXT_PHY)) {
5152
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005153 vars->link_up = 1;
5154 vars->line_speed = SPEED_10000;
5155 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08005156 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005157
5158 vars->phy_flags = PHY_XGXS_FLAG;
5159
5160 val = REG_RD(bp,
5161 NIG_REG_XGXS0_CTRL_PHY_ADDR+
5162 params->port*0x18);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005163
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005164 bnx2x_phy_deassert(params, vars->phy_flags);
5165 bnx2x_link_initialize(params, vars);
5166
5167 vars->mac_type = MAC_TYPE_BMAC;
5168
5169 bnx2x_bmac_enable(params, vars, 0);
5170
5171 if (params->loopback_mode == LOOPBACK_XGXS_10) {
5172 /* set 10G XGXS loopback */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005173 params->phy[INT_PHY].config_loopback(
5174 &params->phy[INT_PHY],
5175 params);
5176
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005177 } else {
5178 /* set external phy loopback */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005179 u8 phy_index;
5180 for (phy_index = EXT_PHY1;
5181 phy_index < params->num_phys; phy_index++) {
5182 if (params->phy[phy_index].config_loopback)
5183 params->phy[phy_index].config_loopback(
5184 &params->phy[phy_index],
Yaniv Rosner62b29a52010-09-07 11:40:58 +00005185 params);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005186 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005187 }
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005188
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005189 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
5190 params->port*4, 0);
Eilon Greensteinba71d312009-07-21 05:47:49 +00005191
Yaniv Rosner7846e472009-11-05 19:18:07 +02005192 bnx2x_set_led(params, LED_MODE_OPER, vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005193 } else
5194 /* No loopback */
5195 {
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005196 if (params->switch_cfg == SWITCH_CFG_10G)
5197 vars->phy_flags = PHY_XGXS_FLAG;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005198 bnx2x_phy_deassert(params, vars->phy_flags);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005199 bnx2x_link_initialize(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005200 msleep(30);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005201 bnx2x_link_int_enable(params);
5202 }
5203 return 0;
5204}
5205
Eilon Greenstein589abe32009-02-12 08:36:55 +00005206
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005207static void bnx2x_8726_link_reset(struct bnx2x_phy *phy,
5208 struct link_params *params)
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005209{
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005210 struct bnx2x *bp = params->bp;
5211 DP(NETIF_MSG_LINK, "bnx2x_8726_link_reset port %d\n", params->port);
Eilon Greenstein589abe32009-02-12 08:36:55 +00005212 /* Set serial boot control for external load */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005213 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005214 MDIO_PMA_DEVAD,
5215 MDIO_PMA_REG_GEN_CTRL, 0x0001);
5216}
5217
5218static void bnx2x_8727_link_reset(struct bnx2x_phy *phy,
5219 struct link_params *params)
5220{
5221 struct bnx2x *bp = params->bp;
5222 /* Disable Transmitter */
5223 bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
5224}
5225static void bnx2x_8073_link_reset(struct bnx2x_phy *phy,
5226 struct link_params *params)
5227{
5228 struct bnx2x *bp = params->bp;
5229 u8 gpio_port;
5230 gpio_port = params->port;
5231 DP(NETIF_MSG_LINK, "Setting 8073 port %d into low power mode\n",
5232 gpio_port);
5233 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
5234 MISC_REGISTERS_GPIO_OUTPUT_LOW,
5235 gpio_port);
5236}
5237static void bnx2x_8481_link_reset(struct bnx2x_phy *phy,
5238 struct link_params *params)
5239{
5240 bnx2x_cl45_write(params->bp, phy,
5241 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x0000);
5242 bnx2x_cl45_write(params->bp, phy,
5243 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1);
5244}
5245
5246static void bnx2x_848x3_link_reset(struct bnx2x_phy *phy,
5247 struct link_params *params)
5248{
5249 struct bnx2x *bp = params->bp;
5250 u8 port = params->port;
5251 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
5252 MISC_REGISTERS_GPIO_OUTPUT_LOW,
5253 port);
5254}
5255
5256static void bnx2x_common_ext_link_reset(struct bnx2x_phy *phy,
5257 struct link_params *params)
5258{
5259 struct bnx2x *bp = params->bp;
5260 u8 gpio_port;
5261 /* HW reset */
5262 gpio_port = params->port;
5263 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
5264 MISC_REGISTERS_GPIO_OUTPUT_LOW,
5265 gpio_port);
5266 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
5267 MISC_REGISTERS_GPIO_OUTPUT_LOW,
5268 gpio_port);
5269 DP(NETIF_MSG_LINK, "reset external PHY\n");
5270}
5271
5272static void bnx2x_int_link_reset(struct bnx2x_phy *phy,
5273 struct link_params *params)
5274{
5275 /* reset the SerDes/XGXS */
5276 REG_WR(params->bp, GRCBASE_MISC +
5277 MISC_REGISTERS_RESET_REG_3_CLEAR,
5278 (0x1ff << (params->port*16)));
Eilon Greenstein589abe32009-02-12 08:36:55 +00005279}
5280
5281u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
5282 u8 reset_ext_phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005283{
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005284 struct bnx2x *bp = params->bp;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005285
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005286 u8 phy_index, port = params->port;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005287
Yaniv Rosnerd5cb9e92009-11-05 19:18:10 +02005288 DP(NETIF_MSG_LINK, "Resetting the link of port %d\n", port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005289 /* disable attentions */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005290 vars->link_status = 0;
5291 bnx2x_update_mng(params, vars->link_status);
5292 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
5293 (NIG_MASK_XGXS0_LINK_STATUS |
5294 NIG_MASK_XGXS0_LINK10G |
5295 NIG_MASK_SERDES0_LINK_STATUS |
5296 NIG_MASK_MI_INT));
5297
5298 /* activate nig drain */
5299 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
5300
5301 /* disable nig egress interface */
5302 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
5303 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
5304
5305 /* Stop BigMac rx */
5306 bnx2x_bmac_rx_disable(bp, port);
5307
5308 /* disable emac */
5309 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
5310
5311 msleep(10);
5312 /* The PHY reset is controled by GPIO 1
5313 * Hold it as vars low
5314 */
5315 /* clear link led */
Yaniv Rosner7846e472009-11-05 19:18:07 +02005316 bnx2x_set_led(params, LED_MODE_OFF, 0);
Eilon Greenstein589abe32009-02-12 08:36:55 +00005317 if (reset_ext_phy) {
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005318 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
5319 phy_index++) {
5320 if (params->phy[phy_index].link_reset)
5321 params->phy[phy_index].link_reset(
5322 &params->phy[phy_index],
5323 params);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005324 }
5325 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005326
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005327 if (params->phy[INT_PHY].link_reset)
5328 params->phy[INT_PHY].link_reset(
5329 &params->phy[INT_PHY], params);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005330 /* reset BigMac */
5331 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
5332 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
5333
5334 /* disable nig ingress interface */
5335 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0);
5336 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0);
5337 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
5338 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
5339 vars->link_up = 0;
5340 return 0;
5341}
5342
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005343
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005344static u8 bnx2x_update_link_down(struct link_params *params,
5345 struct link_vars *vars)
5346{
5347 struct bnx2x *bp = params->bp;
5348 u8 port = params->port;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005349
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005350 DP(NETIF_MSG_LINK, "Port %x: Link is down\n", port);
Yaniv Rosner7846e472009-11-05 19:18:07 +02005351 bnx2x_set_led(params, LED_MODE_OFF, 0);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005352
5353 /* indicate no mac active */
5354 vars->mac_type = MAC_TYPE_NONE;
5355
5356 /* update shared memory */
5357 vars->link_status = 0;
5358 vars->line_speed = 0;
5359 bnx2x_update_mng(params, vars->link_status);
5360
5361 /* activate nig drain */
5362 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
5363
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00005364 /* disable emac */
5365 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
5366
5367 msleep(10);
5368
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005369 /* reset BigMac */
5370 bnx2x_bmac_rx_disable(bp, params->port);
5371 REG_WR(bp, GRCBASE_MISC +
5372 MISC_REGISTERS_RESET_REG_2_CLEAR,
5373 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
5374 return 0;
5375}
5376
5377static u8 bnx2x_update_link_up(struct link_params *params,
5378 struct link_vars *vars,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005379 u8 link_10g)
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005380{
5381 struct bnx2x *bp = params->bp;
5382 u8 port = params->port;
5383 u8 rc = 0;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005384
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005385 vars->link_status |= LINK_STATUS_LINK_UP;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00005386 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
5387 vars->link_status |=
5388 LINK_STATUS_TX_FLOW_CONTROL_ENABLED;
5389
5390 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
5391 vars->link_status |=
5392 LINK_STATUS_RX_FLOW_CONTROL_ENABLED;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005393 if (link_10g) {
5394 bnx2x_bmac_enable(params, vars, 0);
Yaniv Rosner7846e472009-11-05 19:18:07 +02005395 bnx2x_set_led(params, LED_MODE_OPER, SPEED_10000);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005396 } else {
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005397 rc = bnx2x_emac_program(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005398
Yaniv Rosner0c786f02009-11-05 19:18:32 +02005399 bnx2x_emac_enable(params, vars, 0);
5400
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005401 /* AN complete? */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005402 if ((vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE)
5403 && (!(vars->phy_flags & PHY_SGMII_FLAG)) &&
5404 SINGLE_MEDIA_DIRECT(params))
5405 bnx2x_set_gmii_tx_driver(params);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005406 }
5407
5408 /* PBF - link up */
5409 rc |= bnx2x_pbf_update(params, vars->flow_ctrl,
5410 vars->line_speed);
5411
5412 /* disable drain */
5413 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 0);
5414
5415 /* update shared memory */
5416 bnx2x_update_mng(params, vars->link_status);
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00005417 msleep(20);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005418 return rc;
5419}
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005420/**
5421 * The bnx2x_link_update function should be called upon link
5422 * interrupt.
5423 * Link is considered up as follows:
5424 * - DIRECT_SINGLE_MEDIA - Only XGXS link (internal link) needs
5425 * to be up
5426 * - SINGLE_MEDIA - The link between the 577xx and the external
5427 * phy (XGXS) need to up as well as the external link of the
5428 * phy (PHY_EXT1)
5429 * - DUAL_MEDIA - The link between the 577xx and the first
5430 * external phy needs to be up, and at least one of the 2
5431 * external phy link must be up.
Yaniv Rosner62b29a52010-09-07 11:40:58 +00005432 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005433u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars)
5434{
5435 struct bnx2x *bp = params->bp;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005436 struct link_vars phy_vars[MAX_PHYS];
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005437 u8 port = params->port;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005438 u8 link_10g, phy_index;
5439 u8 ext_phy_link_up = 0, cur_link_up, rc = 0;
Eilon Greenstein2f904462009-08-12 08:22:16 +00005440 u8 is_mi_int = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005441 u16 ext_phy_line_speed = 0, prev_line_speed = vars->line_speed;
5442 u8 active_external_phy = INT_PHY;
5443 vars->link_status = 0;
5444 for (phy_index = INT_PHY; phy_index < params->num_phys;
5445 phy_index++) {
5446 phy_vars[phy_index].flow_ctrl = 0;
5447 phy_vars[phy_index].link_status = 0;
5448 phy_vars[phy_index].line_speed = 0;
5449 phy_vars[phy_index].duplex = DUPLEX_FULL;
5450 phy_vars[phy_index].phy_link_up = 0;
5451 phy_vars[phy_index].link_up = 0;
5452 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005453
5454 DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n",
Eilon Greenstein2f904462009-08-12 08:22:16 +00005455 port, (vars->phy_flags & PHY_XGXS_FLAG),
5456 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005457
Eilon Greenstein2f904462009-08-12 08:22:16 +00005458 is_mi_int = (u8)(REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT +
5459 port*0x18) > 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005460 DP(NETIF_MSG_LINK, "int_mask 0x%x MI_INT %x, SERDES_LINK %x\n",
Eilon Greenstein2f904462009-08-12 08:22:16 +00005461 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
5462 is_mi_int,
5463 REG_RD(bp,
5464 NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005465
5466 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
5467 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
5468 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
5469
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00005470 /* disable emac */
5471 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
5472
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005473 /**
5474 * Step 1:
5475 * Check external link change only for external phys, and apply
5476 * priority selection between them in case the link on both phys
5477 * is up. Note that the instead of the common vars, a temporary
5478 * vars argument is used since each phy may have different link/
5479 * speed/duplex result
5480 */
5481 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
5482 phy_index++) {
5483 struct bnx2x_phy *phy = &params->phy[phy_index];
5484 if (!phy->read_status)
5485 continue;
5486 /* Read link status and params of this ext phy */
5487 cur_link_up = phy->read_status(phy, params,
5488 &phy_vars[phy_index]);
5489 if (cur_link_up) {
5490 DP(NETIF_MSG_LINK, "phy in index %d link is up\n",
5491 phy_index);
5492 } else {
5493 DP(NETIF_MSG_LINK, "phy in index %d link is down\n",
5494 phy_index);
5495 continue;
5496 }
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005497
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005498 if (!ext_phy_link_up) {
5499 ext_phy_link_up = 1;
5500 active_external_phy = phy_index;
5501 }
5502 }
5503 prev_line_speed = vars->line_speed;
5504 /**
5505 * Step 2:
5506 * Read the status of the internal phy. In case of
5507 * DIRECT_SINGLE_MEDIA board, this link is the external link,
5508 * otherwise this is the link between the 577xx and the first
5509 * external phy
5510 */
5511 if (params->phy[INT_PHY].read_status)
5512 params->phy[INT_PHY].read_status(
5513 &params->phy[INT_PHY],
5514 params, vars);
5515 /**
5516 * The INT_PHY flow control reside in the vars. This include the
5517 * case where the speed or flow control are not set to AUTO.
5518 * Otherwise, the active external phy flow control result is set
5519 * to the vars. The ext_phy_line_speed is needed to check if the
5520 * speed is different between the internal phy and external phy.
5521 * This case may be result of intermediate link speed change.
5522 */
5523 if (active_external_phy > INT_PHY) {
5524 vars->flow_ctrl = phy_vars[active_external_phy].flow_ctrl;
5525 /**
5526 * Link speed is taken from the XGXS. AN and FC result from
5527 * the external phy.
5528 */
5529 vars->link_status |= phy_vars[active_external_phy].link_status;
5530 ext_phy_line_speed = phy_vars[active_external_phy].line_speed;
5531 vars->duplex = phy_vars[active_external_phy].duplex;
5532 if (params->phy[active_external_phy].supported &
5533 SUPPORTED_FIBRE)
5534 vars->link_status |= LINK_STATUS_SERDES_LINK;
5535 DP(NETIF_MSG_LINK, "Active external phy selected: %x\n",
5536 active_external_phy);
5537 }
5538 DP(NETIF_MSG_LINK, "vars->flow_ctrl = 0x%x, vars->link_status = 0x%x,"
5539 " ext_phy_line_speed = %d\n", vars->flow_ctrl,
5540 vars->link_status, ext_phy_line_speed);
5541 /**
5542 * Upon link speed change set the NIG into drain mode. Comes to
5543 * deals with possible FIFO glitch due to clk change when speed
5544 * is decreased without link down indicator
5545 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005546
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005547 if (vars->phy_link_up) {
5548 if (!(SINGLE_MEDIA_DIRECT(params)) && ext_phy_link_up &&
5549 (ext_phy_line_speed != vars->line_speed)) {
5550 DP(NETIF_MSG_LINK, "Internal link speed %d is"
5551 " different than the external"
5552 " link speed %d\n", vars->line_speed,
5553 ext_phy_line_speed);
5554 vars->phy_link_up = 0;
5555 } else if (prev_line_speed != vars->line_speed) {
5556 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
5557 + params->port*4, 0);
5558 msleep(1);
5559 }
5560 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005561
5562 /* anything 10 and over uses the bmac */
5563 link_10g = ((vars->line_speed == SPEED_10000) ||
5564 (vars->line_speed == SPEED_12000) ||
5565 (vars->line_speed == SPEED_12500) ||
5566 (vars->line_speed == SPEED_13000) ||
5567 (vars->line_speed == SPEED_15000) ||
5568 (vars->line_speed == SPEED_16000));
5569
Eilon Greenstein2f904462009-08-12 08:22:16 +00005570 bnx2x_link_int_ack(params, vars, link_10g, is_mi_int);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005571
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005572 /**
5573 * In case external phy link is up, and internal link is down
5574 * (not initialized yet probably after link initialization, it
5575 * needs to be initialized.
5576 * Note that after link down-up as result of cable plug, the xgxs
5577 * link would probably become up again without the need
5578 * initialize it
5579 */
5580 if (!(SINGLE_MEDIA_DIRECT(params))) {
5581 DP(NETIF_MSG_LINK, "ext_phy_link_up = %d, int_link_up = %d,"
5582 " init_preceding = %d\n", ext_phy_link_up,
5583 vars->phy_link_up,
5584 params->phy[EXT_PHY1].flags &
5585 FLAGS_INIT_XGXS_FIRST);
5586 if (!(params->phy[EXT_PHY1].flags &
5587 FLAGS_INIT_XGXS_FIRST)
5588 && ext_phy_link_up && !vars->phy_link_up) {
5589 vars->line_speed = ext_phy_line_speed;
5590 if (vars->line_speed < SPEED_1000)
5591 vars->phy_flags |= PHY_SGMII_FLAG;
5592 else
5593 vars->phy_flags &= ~PHY_SGMII_FLAG;
5594 bnx2x_init_internal_phy(&params->phy[INT_PHY],
5595 params,
5596 vars);
5597 }
5598 }
5599 /**
5600 * Link is up only if both local phy and external phy (in case of
5601 * non-direct board) are up
5602 */
5603 vars->link_up = (vars->phy_link_up &&
5604 (ext_phy_link_up ||
5605 SINGLE_MEDIA_DIRECT(params)));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005606
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005607 if (vars->link_up)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005608 rc = bnx2x_update_link_up(params, vars, link_10g);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005609 else
5610 rc = bnx2x_update_link_down(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005611
5612 return rc;
5613}
5614
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005615static void bnx2x_8481_hw_reset(struct bnx2x_phy *phy,
5616 struct link_params *params)
5617{
5618 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
5619 MISC_REGISTERS_GPIO_OUTPUT_LOW, 0);
5620 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
5621 MISC_REGISTERS_GPIO_OUTPUT_LOW, 1);
5622}
5623
5624static void bnx2x_8727_hw_reset(struct bnx2x_phy *phy,
5625 struct link_params *params) {
5626 u32 swap_val, swap_override;
5627 u8 port;
5628 /**
5629 * The PHY reset is controlled by GPIO 1. Fake the port number
5630 * to cancel the swap done in set_gpio()
5631 */
5632 struct bnx2x *bp = params->bp;
5633 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
5634 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
5635 port = (swap_val && swap_override) ^ 1;
5636 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
5637 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
5638}
5639
5640static void bnx2x_7101_hw_reset(struct bnx2x_phy *phy,
5641 struct link_params *params) {
5642 /* Low power mode is controlled by GPIO 2 */
5643 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_2,
5644 MISC_REGISTERS_GPIO_OUTPUT_LOW, params->port);
5645 /* The PHY reset is controlled by GPIO 1 */
5646 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
5647 MISC_REGISTERS_GPIO_OUTPUT_LOW, params->port);
5648}
5649/******************************************************************/
5650/* STATIC PHY DECLARATION */
5651/******************************************************************/
5652
5653static struct bnx2x_phy phy_null = {
5654 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN,
5655 .addr = 0,
5656 .flags = FLAGS_INIT_XGXS_FIRST,
5657 .def_md_devad = 0,
5658 .reserved = 0,
5659 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5660 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5661 .mdio_ctrl = 0,
5662 .supported = 0,
5663 .media_type = ETH_PHY_NOT_PRESENT,
5664 .ver_addr = 0,
5665 .req_flow_ctrl = 0,
5666 .req_line_speed = 0,
5667 .speed_cap_mask = 0,
5668 .req_duplex = 0,
5669 .rsrv = 0,
5670 .config_init = (config_init_t)NULL,
5671 .read_status = (read_status_t)NULL,
5672 .link_reset = (link_reset_t)NULL,
5673 .config_loopback = (config_loopback_t)NULL,
5674 .format_fw_ver = (format_fw_ver_t)NULL,
5675 .hw_reset = (hw_reset_t)NULL,
5676 .set_link_led = (set_link_led_t)NULL
5677};
5678
5679static struct bnx2x_phy phy_serdes = {
5680 .type = PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT,
5681 .addr = 0xff,
5682 .flags = 0,
5683 .def_md_devad = 0,
5684 .reserved = 0,
5685 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5686 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5687 .mdio_ctrl = 0,
5688 .supported = (SUPPORTED_10baseT_Half |
5689 SUPPORTED_10baseT_Full |
5690 SUPPORTED_100baseT_Half |
5691 SUPPORTED_100baseT_Full |
5692 SUPPORTED_1000baseT_Full |
5693 SUPPORTED_2500baseX_Full |
5694 SUPPORTED_TP |
5695 SUPPORTED_Autoneg |
5696 SUPPORTED_Pause |
5697 SUPPORTED_Asym_Pause),
5698 .media_type = ETH_PHY_UNSPECIFIED,
5699 .ver_addr = 0,
5700 .req_flow_ctrl = 0,
5701 .req_line_speed = 0,
5702 .speed_cap_mask = 0,
5703 .req_duplex = 0,
5704 .rsrv = 0,
5705 .config_init = (config_init_t)bnx2x_init_serdes,
5706 .read_status = (read_status_t)bnx2x_link_settings_status,
5707 .link_reset = (link_reset_t)bnx2x_int_link_reset,
5708 .config_loopback = (config_loopback_t)NULL,
5709 .format_fw_ver = (format_fw_ver_t)NULL,
5710 .hw_reset = (hw_reset_t)NULL,
5711 .set_link_led = (set_link_led_t)NULL
5712};
5713
5714static struct bnx2x_phy phy_xgxs = {
5715 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT,
5716 .addr = 0xff,
5717 .flags = 0,
5718 .def_md_devad = 0,
5719 .reserved = 0,
5720 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5721 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5722 .mdio_ctrl = 0,
5723 .supported = (SUPPORTED_10baseT_Half |
5724 SUPPORTED_10baseT_Full |
5725 SUPPORTED_100baseT_Half |
5726 SUPPORTED_100baseT_Full |
5727 SUPPORTED_1000baseT_Full |
5728 SUPPORTED_2500baseX_Full |
5729 SUPPORTED_10000baseT_Full |
5730 SUPPORTED_FIBRE |
5731 SUPPORTED_Autoneg |
5732 SUPPORTED_Pause |
5733 SUPPORTED_Asym_Pause),
5734 .media_type = ETH_PHY_UNSPECIFIED,
5735 .ver_addr = 0,
5736 .req_flow_ctrl = 0,
5737 .req_line_speed = 0,
5738 .speed_cap_mask = 0,
5739 .req_duplex = 0,
5740 .rsrv = 0,
5741 .config_init = (config_init_t)bnx2x_init_xgxs,
5742 .read_status = (read_status_t)bnx2x_link_settings_status,
5743 .link_reset = (link_reset_t)bnx2x_int_link_reset,
5744 .config_loopback = (config_loopback_t)bnx2x_set_xgxs_loopback,
5745 .format_fw_ver = (format_fw_ver_t)NULL,
5746 .hw_reset = (hw_reset_t)NULL,
5747 .set_link_led = (set_link_led_t)NULL
5748};
5749
5750static struct bnx2x_phy phy_7101 = {
5751 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5752 .addr = 0xff,
5753 .flags = FLAGS_FAN_FAILURE_DET_REQ,
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_TP |
5761 SUPPORTED_Autoneg |
5762 SUPPORTED_Pause |
5763 SUPPORTED_Asym_Pause),
5764 .media_type = ETH_PHY_BASE_T,
5765 .ver_addr = 0,
5766 .req_flow_ctrl = 0,
5767 .req_line_speed = 0,
5768 .speed_cap_mask = 0,
5769 .req_duplex = 0,
5770 .rsrv = 0,
5771 .config_init = (config_init_t)bnx2x_7101_config_init,
5772 .read_status = (read_status_t)bnx2x_7101_read_status,
5773 .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
5774 .config_loopback = (config_loopback_t)bnx2x_7101_config_loopback,
5775 .format_fw_ver = (format_fw_ver_t)bnx2x_7101_format_ver,
5776 .hw_reset = (hw_reset_t)bnx2x_7101_hw_reset,
5777 .set_link_led = (set_link_led_t)NULL
5778};
5779static struct bnx2x_phy phy_8073 = {
5780 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5781 .addr = 0xff,
5782 .flags = FLAGS_HW_LOCK_REQUIRED,
5783 .def_md_devad = 0,
5784 .reserved = 0,
5785 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5786 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5787 .mdio_ctrl = 0,
5788 .supported = (SUPPORTED_10000baseT_Full |
5789 SUPPORTED_2500baseX_Full |
5790 SUPPORTED_1000baseT_Full |
5791 SUPPORTED_FIBRE |
5792 SUPPORTED_Autoneg |
5793 SUPPORTED_Pause |
5794 SUPPORTED_Asym_Pause),
5795 .media_type = ETH_PHY_UNSPECIFIED,
5796 .ver_addr = 0,
5797 .req_flow_ctrl = 0,
5798 .req_line_speed = 0,
5799 .speed_cap_mask = 0,
5800 .req_duplex = 0,
5801 .rsrv = 0,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00005802 .config_init = (config_init_t)bnx2x_8073_config_init,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005803 .read_status = (read_status_t)bnx2x_8073_read_status,
5804 .link_reset = (link_reset_t)bnx2x_8073_link_reset,
5805 .config_loopback = (config_loopback_t)NULL,
5806 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
5807 .hw_reset = (hw_reset_t)NULL,
5808 .set_link_led = (set_link_led_t)NULL
5809};
5810static struct bnx2x_phy phy_8705 = {
5811 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705,
5812 .addr = 0xff,
5813 .flags = FLAGS_INIT_XGXS_FIRST,
5814 .def_md_devad = 0,
5815 .reserved = 0,
5816 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5817 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5818 .mdio_ctrl = 0,
5819 .supported = (SUPPORTED_10000baseT_Full |
5820 SUPPORTED_FIBRE |
5821 SUPPORTED_Pause |
5822 SUPPORTED_Asym_Pause),
5823 .media_type = ETH_PHY_XFP_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_8705_config_init,
5831 .read_status = (read_status_t)bnx2x_8705_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_null_format_ver,
5835 .hw_reset = (hw_reset_t)NULL,
5836 .set_link_led = (set_link_led_t)NULL
5837};
5838static struct bnx2x_phy phy_8706 = {
5839 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706,
5840 .addr = 0xff,
5841 .flags = FLAGS_INIT_XGXS_FIRST,
5842 .def_md_devad = 0,
5843 .reserved = 0,
5844 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5845 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5846 .mdio_ctrl = 0,
5847 .supported = (SUPPORTED_10000baseT_Full |
5848 SUPPORTED_1000baseT_Full |
5849 SUPPORTED_FIBRE |
5850 SUPPORTED_Pause |
5851 SUPPORTED_Asym_Pause),
5852 .media_type = ETH_PHY_SFP_FIBER,
5853 .ver_addr = 0,
5854 .req_flow_ctrl = 0,
5855 .req_line_speed = 0,
5856 .speed_cap_mask = 0,
5857 .req_duplex = 0,
5858 .rsrv = 0,
5859 .config_init = (config_init_t)bnx2x_8706_config_init,
5860 .read_status = (read_status_t)bnx2x_8706_read_status,
5861 .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
5862 .config_loopback = (config_loopback_t)NULL,
5863 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
5864 .hw_reset = (hw_reset_t)NULL,
5865 .set_link_led = (set_link_led_t)NULL
5866};
5867
5868static struct bnx2x_phy phy_8726 = {
5869 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
5870 .addr = 0xff,
5871 .flags = (FLAGS_HW_LOCK_REQUIRED |
5872 FLAGS_INIT_XGXS_FIRST),
5873 .def_md_devad = 0,
5874 .reserved = 0,
5875 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5876 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5877 .mdio_ctrl = 0,
5878 .supported = (SUPPORTED_10000baseT_Full |
5879 SUPPORTED_1000baseT_Full |
5880 SUPPORTED_Autoneg |
5881 SUPPORTED_FIBRE |
5882 SUPPORTED_Pause |
5883 SUPPORTED_Asym_Pause),
5884 .media_type = ETH_PHY_SFP_FIBER,
5885 .ver_addr = 0,
5886 .req_flow_ctrl = 0,
5887 .req_line_speed = 0,
5888 .speed_cap_mask = 0,
5889 .req_duplex = 0,
5890 .rsrv = 0,
5891 .config_init = (config_init_t)bnx2x_8726_config_init,
5892 .read_status = (read_status_t)bnx2x_8726_read_status,
5893 .link_reset = (link_reset_t)bnx2x_8726_link_reset,
5894 .config_loopback = (config_loopback_t)bnx2x_8726_config_loopback,
5895 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
5896 .hw_reset = (hw_reset_t)NULL,
5897 .set_link_led = (set_link_led_t)NULL
5898};
5899
5900static struct bnx2x_phy phy_8727 = {
5901 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
5902 .addr = 0xff,
5903 .flags = FLAGS_FAN_FAILURE_DET_REQ,
5904 .def_md_devad = 0,
5905 .reserved = 0,
5906 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5907 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5908 .mdio_ctrl = 0,
5909 .supported = (SUPPORTED_10000baseT_Full |
5910 SUPPORTED_1000baseT_Full |
5911 SUPPORTED_Autoneg |
5912 SUPPORTED_FIBRE |
5913 SUPPORTED_Pause |
5914 SUPPORTED_Asym_Pause),
5915 .media_type = ETH_PHY_SFP_FIBER,
5916 .ver_addr = 0,
5917 .req_flow_ctrl = 0,
5918 .req_line_speed = 0,
5919 .speed_cap_mask = 0,
5920 .req_duplex = 0,
5921 .rsrv = 0,
5922 .config_init = (config_init_t)bnx2x_8727_config_init,
5923 .read_status = (read_status_t)bnx2x_8727_read_status,
5924 .link_reset = (link_reset_t)bnx2x_8727_link_reset,
5925 .config_loopback = (config_loopback_t)NULL,
5926 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
5927 .hw_reset = (hw_reset_t)bnx2x_8727_hw_reset,
5928 .set_link_led = (set_link_led_t)NULL
5929};
5930static struct bnx2x_phy phy_8481 = {
5931 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
5932 .addr = 0xff,
5933 .flags = FLAGS_FAN_FAILURE_DET_REQ,
5934 .def_md_devad = 0,
5935 .reserved = 0,
5936 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5937 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5938 .mdio_ctrl = 0,
5939 .supported = (SUPPORTED_10baseT_Half |
5940 SUPPORTED_10baseT_Full |
5941 SUPPORTED_100baseT_Half |
5942 SUPPORTED_100baseT_Full |
5943 SUPPORTED_1000baseT_Full |
5944 SUPPORTED_10000baseT_Full |
5945 SUPPORTED_TP |
5946 SUPPORTED_Autoneg |
5947 SUPPORTED_Pause |
5948 SUPPORTED_Asym_Pause),
5949 .media_type = ETH_PHY_BASE_T,
5950 .ver_addr = 0,
5951 .req_flow_ctrl = 0,
5952 .req_line_speed = 0,
5953 .speed_cap_mask = 0,
5954 .req_duplex = 0,
5955 .rsrv = 0,
5956 .config_init = (config_init_t)bnx2x_8481_config_init,
5957 .read_status = (read_status_t)bnx2x_848xx_read_status,
5958 .link_reset = (link_reset_t)bnx2x_8481_link_reset,
5959 .config_loopback = (config_loopback_t)NULL,
5960 .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver,
5961 .hw_reset = (hw_reset_t)bnx2x_8481_hw_reset,
5962 .set_link_led = (set_link_led_t)NULL
5963};
5964
5965static struct bnx2x_phy phy_84823 = {
5966 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823,
5967 .addr = 0xff,
5968 .flags = FLAGS_FAN_FAILURE_DET_REQ,
5969 .def_md_devad = 0,
5970 .reserved = 0,
5971 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5972 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5973 .mdio_ctrl = 0,
5974 .supported = (SUPPORTED_10baseT_Half |
5975 SUPPORTED_10baseT_Full |
5976 SUPPORTED_100baseT_Half |
5977 SUPPORTED_100baseT_Full |
5978 SUPPORTED_1000baseT_Full |
5979 SUPPORTED_10000baseT_Full |
5980 SUPPORTED_TP |
5981 SUPPORTED_Autoneg |
5982 SUPPORTED_Pause |
5983 SUPPORTED_Asym_Pause),
5984 .media_type = ETH_PHY_BASE_T,
5985 .ver_addr = 0,
5986 .req_flow_ctrl = 0,
5987 .req_line_speed = 0,
5988 .speed_cap_mask = 0,
5989 .req_duplex = 0,
5990 .rsrv = 0,
5991 .config_init = (config_init_t)bnx2x_848x3_config_init,
5992 .read_status = (read_status_t)bnx2x_848xx_read_status,
5993 .link_reset = (link_reset_t)bnx2x_848x3_link_reset,
5994 .config_loopback = (config_loopback_t)NULL,
5995 .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver,
5996 .hw_reset = (hw_reset_t)NULL,
5997 .set_link_led = (set_link_led_t)NULL
5998};
5999
6000/*****************************************************************/
6001/* */
6002/* Populate the phy according. Main function: bnx2x_populate_phy */
6003/* */
6004/*****************************************************************/
6005
6006static void bnx2x_populate_preemphasis(struct bnx2x *bp, u32 shmem_base,
6007 struct bnx2x_phy *phy, u8 port,
6008 u8 phy_index)
6009{
6010 /* Get the 4 lanes xgxs config rx and tx */
6011 u32 rx = 0, tx = 0, i;
6012 for (i = 0; i < 2; i++) {
6013 /**
6014 * INT_PHY and EXT_PHY1 share the same value location in the
6015 * shmem. When num_phys is greater than 1, than this value
6016 * applies only to EXT_PHY1
6017 */
6018
6019 rx = REG_RD(bp, shmem_base +
6020 offsetof(struct shmem_region,
6021 dev_info.port_hw_config[port].xgxs_config_rx[i<<1]));
6022
6023 tx = REG_RD(bp, shmem_base +
6024 offsetof(struct shmem_region,
6025 dev_info.port_hw_config[port].xgxs_config_tx[i<<1]));
6026
6027 phy->rx_preemphasis[i << 1] = ((rx>>16) & 0xffff);
6028 phy->rx_preemphasis[(i << 1) + 1] = (rx & 0xffff);
6029
6030 phy->tx_preemphasis[i << 1] = ((tx>>16) & 0xffff);
6031 phy->tx_preemphasis[(i << 1) + 1] = (tx & 0xffff);
6032 }
6033}
6034
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006035static u32 bnx2x_get_ext_phy_config(struct bnx2x *bp, u32 shmem_base,
6036 u8 phy_index, u8 port)
6037{
6038 u32 ext_phy_config = 0;
6039 switch (phy_index) {
6040 case EXT_PHY1:
6041 ext_phy_config = REG_RD(bp, shmem_base +
6042 offsetof(struct shmem_region,
6043 dev_info.port_hw_config[port].external_phy_config));
6044 break;
6045 default:
6046 DP(NETIF_MSG_LINK, "Invalid phy_index %d\n", phy_index);
6047 return -EINVAL;
6048 }
6049
6050 return ext_phy_config;
6051}
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006052static u8 bnx2x_populate_int_phy(struct bnx2x *bp, u32 shmem_base, u8 port,
6053 struct bnx2x_phy *phy)
6054{
6055 u32 phy_addr;
6056 u32 chip_id;
6057 u32 switch_cfg = (REG_RD(bp, shmem_base +
6058 offsetof(struct shmem_region,
6059 dev_info.port_feature_config[port].link_config)) &
6060 PORT_FEATURE_CONNECTED_SWITCH_MASK);
6061 chip_id = REG_RD(bp, MISC_REG_CHIP_NUM) << 16;
6062 switch (switch_cfg) {
6063 case SWITCH_CFG_1G:
6064 phy_addr = REG_RD(bp,
6065 NIG_REG_SERDES0_CTRL_PHY_ADDR +
6066 port * 0x10);
6067 *phy = phy_serdes;
6068 break;
6069 case SWITCH_CFG_10G:
6070 phy_addr = REG_RD(bp,
6071 NIG_REG_XGXS0_CTRL_PHY_ADDR +
6072 port * 0x18);
6073 *phy = phy_xgxs;
6074 break;
6075 default:
6076 DP(NETIF_MSG_LINK, "Invalid switch_cfg\n");
6077 return -EINVAL;
6078 }
6079 phy->addr = (u8)phy_addr;
6080 phy->mdio_ctrl = bnx2x_get_emac_base(bp,
6081 phy->type,
6082 port);
6083 phy->def_md_devad = DEFAULT_PHY_DEV_ADDR;
6084
6085 DP(NETIF_MSG_LINK, "Internal phy port=%d, addr=0x%x, mdio_ctl=0x%x\n",
6086 port, phy->addr, phy->mdio_ctrl);
6087
6088 bnx2x_populate_preemphasis(bp, shmem_base, phy, port, INT_PHY);
6089 return 0;
6090}
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006091
6092static u8 bnx2x_populate_ext_phy(struct bnx2x *bp,
6093 u8 phy_index,
6094 u32 shmem_base,
6095 u8 port,
6096 struct bnx2x_phy *phy)
6097{
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006098 u32 ext_phy_config, phy_type;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006099
6100 ext_phy_config = bnx2x_get_ext_phy_config(bp, shmem_base,
6101 phy_index, port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006102 phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
6103 /* Select the phy type */
6104 switch (phy_type) {
6105 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
6106 *phy = phy_8073;
6107 break;
6108 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
6109 *phy = phy_8705;
6110 break;
6111 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
6112 *phy = phy_8706;
6113 break;
6114 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
6115 *phy = phy_8726;
6116 break;
6117 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
6118 /* BCM8727_NOC => BCM8727 no over current */
6119 *phy = phy_8727;
6120 phy->flags |= FLAGS_NOC;
6121 break;
6122 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
6123 *phy = phy_8727;
6124 break;
6125 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
6126 *phy = phy_8481;
6127 break;
6128 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
6129 *phy = phy_84823;
6130 break;
6131 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
6132 *phy = phy_7101;
6133 break;
6134 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
6135 *phy = phy_null;
6136 return -EINVAL;
6137 default:
6138 *phy = phy_null;
6139 return 0;
6140 }
6141
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006142 phy->addr = XGXS_EXT_PHY_ADDR(ext_phy_config);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006143 bnx2x_populate_preemphasis(bp, shmem_base, phy, port, phy_index);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006144 phy->mdio_ctrl = bnx2x_get_emac_base(bp, phy->type, port);
Yaniv Rosner62b29a52010-09-07 11:40:58 +00006145
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006146 return 0;
6147}
6148
6149static u8 bnx2x_populate_phy(struct bnx2x *bp, u8 phy_index, u32 shmem_base,
6150 u8 port, struct bnx2x_phy *phy)
6151{
6152 u8 status = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006153 phy->type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN;
6154 if (phy_index == INT_PHY)
6155 return bnx2x_populate_int_phy(bp, shmem_base, port, phy);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006156 status = bnx2x_populate_ext_phy(bp, phy_index, shmem_base,
6157 port, phy);
6158 return status;
6159}
6160
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006161static void bnx2x_phy_def_cfg(struct link_params *params,
6162 struct bnx2x_phy *phy,
6163 u8 actual_phy_idx)
6164{
6165 struct bnx2x *bp = params->bp;
6166 u32 link_config;
6167 /* Populate the default phy configuration for MF mode */
6168 link_config = REG_RD(bp, params->shmem_base +
6169 offsetof(struct shmem_region, dev_info.
6170 port_feature_config[params->port].link_config));
6171 phy->speed_cap_mask = REG_RD(bp, params->shmem_base +
6172 offsetof(struct shmem_region, dev_info.
6173 port_hw_config[params->port].speed_capability_mask));
6174
6175 phy->req_duplex = DUPLEX_FULL;
6176 switch (link_config & PORT_FEATURE_LINK_SPEED_MASK) {
6177 case PORT_FEATURE_LINK_SPEED_10M_HALF:
6178 phy->req_duplex = DUPLEX_HALF;
6179 case PORT_FEATURE_LINK_SPEED_10M_FULL:
6180 phy->req_line_speed = SPEED_10;
6181 break;
6182 case PORT_FEATURE_LINK_SPEED_100M_HALF:
6183 phy->req_duplex = DUPLEX_HALF;
6184 case PORT_FEATURE_LINK_SPEED_100M_FULL:
6185 phy->req_line_speed = SPEED_100;
6186 break;
6187 case PORT_FEATURE_LINK_SPEED_1G:
6188 phy->req_line_speed = SPEED_1000;
6189 break;
6190 case PORT_FEATURE_LINK_SPEED_2_5G:
6191 phy->req_line_speed = SPEED_2500;
6192 break;
6193 case PORT_FEATURE_LINK_SPEED_10G_CX4:
6194 phy->req_line_speed = SPEED_10000;
6195 break;
6196 default:
6197 phy->req_line_speed = SPEED_AUTO_NEG;
6198 break;
6199 }
6200
6201 switch (link_config & PORT_FEATURE_FLOW_CONTROL_MASK) {
6202 case PORT_FEATURE_FLOW_CONTROL_AUTO:
6203 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_AUTO;
6204 break;
6205 case PORT_FEATURE_FLOW_CONTROL_TX:
6206 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_TX;
6207 break;
6208 case PORT_FEATURE_FLOW_CONTROL_RX:
6209 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_RX;
6210 break;
6211 case PORT_FEATURE_FLOW_CONTROL_BOTH:
6212 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_BOTH;
6213 break;
6214 default:
6215 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_NONE;
6216 break;
6217 }
6218}
6219
6220u8 bnx2x_phy_probe(struct link_params *params)
6221{
6222 u8 phy_index, actual_phy_idx, link_cfg_idx;
6223
6224 struct bnx2x *bp = params->bp;
6225 struct bnx2x_phy *phy;
6226 params->num_phys = 0;
6227 DP(NETIF_MSG_LINK, "Begin phy probe\n");
6228
6229 for (phy_index = INT_PHY; phy_index < MAX_PHYS;
6230 phy_index++) {
6231 link_cfg_idx = LINK_CONFIG_IDX(phy_index);
6232 actual_phy_idx = phy_index;
6233
6234 phy = &params->phy[actual_phy_idx];
6235 if (bnx2x_populate_phy(bp, phy_index, params->shmem_base,
6236 params->port,
6237 phy) != 0) {
6238 params->num_phys = 0;
6239 DP(NETIF_MSG_LINK, "phy probe failed in phy index %d\n",
6240 phy_index);
6241 for (phy_index = INT_PHY;
6242 phy_index < MAX_PHYS;
6243 phy_index++)
6244 *phy = phy_null;
6245 return -EINVAL;
6246 }
6247 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)
6248 break;
6249
6250 bnx2x_phy_def_cfg(params, phy, actual_phy_idx);
6251 params->num_phys++;
6252 }
6253
6254 DP(NETIF_MSG_LINK, "End phy probe. #phys found %x\n", params->num_phys);
6255 return 0;
6256}
6257
6258u32 bnx2x_supported_attr(struct link_params *params, u8 phy_idx)
6259{
6260 if (phy_idx < params->num_phys)
6261 return params->phy[phy_idx].supported;
6262 return 0;
6263}
6264
6265
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006266static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base)
6267{
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006268 struct bnx2x_phy phy[PORT_MAX];
6269 struct bnx2x_phy *phy_blk[PORT_MAX];
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006270 u16 val;
6271 s8 port;
6272
6273 /* PART1 - Reset both phys */
6274 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
6275 /* Extract the ext phy address for the port */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006276 if (bnx2x_populate_phy(bp, EXT_PHY1, shmem_base,
6277 port, &phy[port]) !=
6278 0) {
6279 DP(NETIF_MSG_LINK, "populate_phy failed\n");
6280 return -EINVAL;
6281 }
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006282 /* disable attentions */
6283 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
6284 (NIG_MASK_XGXS0_LINK_STATUS |
6285 NIG_MASK_XGXS0_LINK10G |
6286 NIG_MASK_SERDES0_LINK_STATUS |
6287 NIG_MASK_MI_INT));
6288
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006289 /* Need to take the phy out of low power mode in order
6290 to write to access its registers */
6291 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
6292 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
6293
6294 /* Reset the phy */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006295 bnx2x_cl45_write(bp, &phy[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006296 MDIO_PMA_DEVAD,
6297 MDIO_PMA_REG_CTRL,
6298 1<<15);
6299 }
6300
6301 /* Add delay of 150ms after reset */
6302 msleep(150);
6303
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006304 if (phy[PORT_0].addr & 0x1) {
6305 phy_blk[PORT_0] = &(phy[PORT_1]);
6306 phy_blk[PORT_1] = &(phy[PORT_0]);
6307 } else {
6308 phy_blk[PORT_0] = &(phy[PORT_0]);
6309 phy_blk[PORT_1] = &(phy[PORT_1]);
6310 }
6311
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006312 /* PART2 - Download firmware to both phys */
6313 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
6314 u16 fw_ver1;
6315
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006316 bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port],
6317 port, shmem_base);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006318
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006319 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006320 MDIO_PMA_DEVAD,
6321 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
Eilon Greenstein16b311c2009-01-14 06:44:24 +00006322 if (fw_ver1 == 0 || fw_ver1 == 0x4321) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006323 DP(NETIF_MSG_LINK,
Eilon Greenstein16b311c2009-01-14 06:44:24 +00006324 "bnx2x_8073_common_init_phy port %x:"
6325 "Download failed. fw version = 0x%x\n",
6326 port, fw_ver1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006327 return -EINVAL;
6328 }
6329
6330 /* Only set bit 10 = 1 (Tx power down) */
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_TX_POWER_DOWN, &val);
6334
6335 /* Phase1 of TX_POWER_DOWN reset */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006336 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006337 MDIO_PMA_DEVAD,
6338 MDIO_PMA_REG_TX_POWER_DOWN,
6339 (val | 1<<10));
6340 }
6341
6342 /* Toggle Transmitter: Power down and then up with 600ms
6343 delay between */
6344 msleep(600);
6345
6346 /* PART3 - complete TX_POWER_DOWN process, and set GPIO2 back to low */
6347 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Eilon Greensteinf5372252009-02-12 08:38:30 +00006348 /* Phase2 of POWER_DOWN_RESET */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006349 /* Release bit 10 (Release Tx power down) */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006350 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006351 MDIO_PMA_DEVAD,
6352 MDIO_PMA_REG_TX_POWER_DOWN, &val);
6353
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006354 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006355 MDIO_PMA_DEVAD,
6356 MDIO_PMA_REG_TX_POWER_DOWN, (val & (~(1<<10))));
6357 msleep(15);
6358
6359 /* Read modify write the SPI-ROM version select register */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006360 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006361 MDIO_PMA_DEVAD,
6362 MDIO_PMA_REG_EDC_FFE_MAIN, &val);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006363 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006364 MDIO_PMA_DEVAD,
6365 MDIO_PMA_REG_EDC_FFE_MAIN, (val | (1<<12)));
6366
6367 /* set GPIO2 back to LOW */
6368 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
6369 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
6370 }
6371 return 0;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006372}
6373
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006374static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base)
6375{
Eilon Greensteinbc7f0a02009-08-12 08:23:01 +00006376 s8 port, first_port, i;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006377 u32 swap_val, swap_override;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006378 struct bnx2x_phy phy[PORT_MAX];
6379 struct bnx2x_phy *phy_blk[PORT_MAX];
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006380 DP(NETIF_MSG_LINK, "Executing BCM8727 common init\n");
6381 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
6382 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
6383
Eilon Greensteinf57a6022009-08-12 08:23:11 +00006384 bnx2x_ext_phy_hw_reset(bp, 1 ^ (swap_val && swap_override));
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006385 msleep(5);
6386
Eilon Greensteinbc7f0a02009-08-12 08:23:01 +00006387 if (swap_val && swap_override)
6388 first_port = PORT_0;
6389 else
6390 first_port = PORT_1;
6391
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006392 /* PART1 - Reset both phys */
Eilon Greensteinbc7f0a02009-08-12 08:23:01 +00006393 for (i = 0, port = first_port; i < PORT_MAX; i++, port = !port) {
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006394 /* Extract the ext phy address for the port */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006395 if (bnx2x_populate_phy(bp, EXT_PHY1, shmem_base,
6396 port, &phy[port]) !=
6397 0) {
6398 DP(NETIF_MSG_LINK, "populate phy failed\n");
6399 return -EINVAL;
6400 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006401 /* disable attentions */
6402 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
6403 (NIG_MASK_XGXS0_LINK_STATUS |
6404 NIG_MASK_XGXS0_LINK10G |
6405 NIG_MASK_SERDES0_LINK_STATUS |
6406 NIG_MASK_MI_INT));
6407
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006408
6409 /* Reset the phy */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006410 bnx2x_cl45_write(bp, &phy[port],
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006411 MDIO_PMA_DEVAD,
6412 MDIO_PMA_REG_CTRL,
6413 1<<15);
6414 }
6415
6416 /* Add delay of 150ms after reset */
6417 msleep(150);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006418 if (phy[PORT_0].addr & 0x1) {
6419 phy_blk[PORT_0] = &(phy[PORT_1]);
6420 phy_blk[PORT_1] = &(phy[PORT_0]);
6421 } else {
6422 phy_blk[PORT_0] = &(phy[PORT_0]);
6423 phy_blk[PORT_1] = &(phy[PORT_1]);
6424 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006425 /* PART2 - Download firmware to both phys */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006426 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006427 u16 fw_ver1;
6428
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006429 bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port],
6430 port, shmem_base);
6431 bnx2x_cl45_read(bp, phy_blk[port],
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006432 MDIO_PMA_DEVAD,
6433 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
6434 if (fw_ver1 == 0 || fw_ver1 == 0x4321) {
6435 DP(NETIF_MSG_LINK,
Eilon Greensteinbc7f0a02009-08-12 08:23:01 +00006436 "bnx2x_8727_common_init_phy port %x:"
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006437 "Download failed. fw version = 0x%x\n",
6438 port, fw_ver1);
6439 return -EINVAL;
6440 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006441 }
6442
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006443 return 0;
6444}
6445
Eilon Greenstein589abe32009-02-12 08:36:55 +00006446static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp, u32 shmem_base)
6447{
Eilon Greenstein589abe32009-02-12 08:36:55 +00006448 u32 val;
6449 s8 port;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006450 struct bnx2x_phy phy;
Eilon Greenstein589abe32009-02-12 08:36:55 +00006451 /* Use port1 because of the static port-swap */
6452 /* Enable the module detection interrupt */
6453 val = REG_RD(bp, MISC_REG_GPIO_EVENT_EN);
6454 val |= ((1<<MISC_REGISTERS_GPIO_3)|
6455 (1<<(MISC_REGISTERS_GPIO_3 + MISC_REGISTERS_GPIO_PORT_SHIFT)));
6456 REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val);
6457
Eilon Greensteinf57a6022009-08-12 08:23:11 +00006458 bnx2x_ext_phy_hw_reset(bp, 1);
Eilon Greenstein589abe32009-02-12 08:36:55 +00006459 msleep(5);
6460 for (port = 0; port < PORT_MAX; port++) {
6461 /* Extract the ext phy address for the port */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006462 if (bnx2x_populate_phy(bp, EXT_PHY1, shmem_base,
6463 port, &phy) !=
6464 0) {
6465 DP(NETIF_MSG_LINK, "populate phy failed\n");
6466 return -EINVAL;
6467 }
Eilon Greenstein589abe32009-02-12 08:36:55 +00006468
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006469 /* Reset phy*/
6470 bnx2x_cl45_write(bp, &phy,
6471 MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, 0x0001);
Eilon Greenstein589abe32009-02-12 08:36:55 +00006472
Eilon Greenstein589abe32009-02-12 08:36:55 +00006473
6474 /* Set fault module detected LED on */
6475 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
6476 MISC_REGISTERS_GPIO_HIGH,
6477 port);
6478 }
6479
6480 return 0;
6481}
6482
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006483u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base)
6484{
6485 u8 rc = 0;
6486 u32 ext_phy_type;
6487
Eilon Greensteinf5372252009-02-12 08:38:30 +00006488 DP(NETIF_MSG_LINK, "Begin common phy init\n");
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006489
6490 /* Read the ext_phy_type for arbitrary port(0) */
6491 ext_phy_type = XGXS_EXT_PHY_TYPE(
6492 REG_RD(bp, shmem_base +
6493 offsetof(struct shmem_region,
6494 dev_info.port_hw_config[0].external_phy_config)));
6495
6496 switch (ext_phy_type) {
6497 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
6498 {
6499 rc = bnx2x_8073_common_init_phy(bp, shmem_base);
6500 break;
6501 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006502
6503 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
6504 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
6505 rc = bnx2x_8727_common_init_phy(bp, shmem_base);
6506 break;
6507
Eilon Greenstein589abe32009-02-12 08:36:55 +00006508 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
6509 /* GPIO1 affects both ports, so there's need to pull
6510 it for single port alone */
6511 rc = bnx2x_8726_common_init_phy(bp, shmem_base);
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02006512 break;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006513 default:
6514 DP(NETIF_MSG_LINK,
6515 "bnx2x_common_init_phy: ext_phy 0x%x not required\n",
6516 ext_phy_type);
6517 break;
6518 }
6519
6520 return rc;
6521}
6522
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006523void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006524{
6525 u16 val, cnt;
6526
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006527 bnx2x_cl45_read(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006528 MDIO_PMA_DEVAD,
6529 MDIO_PMA_REG_7101_RESET, &val);
6530
6531 for (cnt = 0; cnt < 10; cnt++) {
6532 msleep(50);
6533 /* Writes a self-clearing reset */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006534 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006535 MDIO_PMA_DEVAD,
6536 MDIO_PMA_REG_7101_RESET,
6537 (val | (1<<15)));
6538 /* Wait for clear */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006539 bnx2x_cl45_read(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006540 MDIO_PMA_DEVAD,
6541 MDIO_PMA_REG_7101_RESET, &val);
6542
6543 if ((val & (1<<15)) == 0)
6544 break;
6545 }
6546}
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00006547
6548u8 bnx2x_hw_lock_required(struct bnx2x *bp, u32 shmem_base)
6549{
6550 u8 phy_index;
6551 struct bnx2x_phy phy;
6552 for (phy_index = INT_PHY; phy_index < MAX_PHYS;
6553 phy_index++) {
6554 if (bnx2x_populate_phy(bp, phy_index, shmem_base,
6555 0, &phy) != 0) {
6556 DP(NETIF_MSG_LINK, "populate phy failed\n");
6557 return 0;
6558 }
6559
6560 if (phy.flags & FLAGS_HW_LOCK_REQUIRED)
6561 return 1;
6562 }
6563 return 0;
6564}
6565
6566u8 bnx2x_fan_failure_det_req(struct bnx2x *bp,
6567 u32 shmem_base,
6568 u8 port)
6569{
6570 u8 phy_index, fan_failure_det_req = 0;
6571 struct bnx2x_phy phy;
6572 for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
6573 phy_index++) {
6574 if (bnx2x_populate_phy(bp, phy_index, shmem_base,
6575 port, &phy)
6576 != 0) {
6577 DP(NETIF_MSG_LINK, "populate phy failed\n");
6578 return 0;
6579 }
6580 fan_failure_det_req |= (phy.flags &
6581 FLAGS_FAN_FAILURE_DET_REQ);
6582 }
6583 return fan_failure_det_req;
6584}
6585
6586void bnx2x_hw_reset_phy(struct link_params *params)
6587{
6588 u8 phy_index;
6589 for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
6590 phy_index++) {
6591 if (params->phy[phy_index].hw_reset) {
6592 params->phy[phy_index].hw_reset(
6593 &params->phy[phy_index],
6594 params);
6595 params->phy[phy_index] = phy_null;
6596 }
6597 }
6598}