blob: c2f1e3c24c0bd7b4db31171524ce89d979ddeecd [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 Rosnerea4e0402008-06-23 20:27:26 -0700174 DEFAULT_PHY_DEV_ADDR, \
175 (_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 Rosnerea4e0402008-06-23 20:27:26 -0700180 DEFAULT_PHY_DEV_ADDR, \
181 (_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
637 if (vars->link_status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED)
David S. Millerc0700f92008-12-16 23:53:20 -0800638 vars->flow_ctrl |= BNX2X_FLOW_CTRL_TX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700639 else
David S. Millerc0700f92008-12-16 23:53:20 -0800640 vars->flow_ctrl &= ~BNX2X_FLOW_CTRL_TX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700641
642 if (vars->link_status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED)
David S. Millerc0700f92008-12-16 23:53:20 -0800643 vars->flow_ctrl |= BNX2X_FLOW_CTRL_RX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700644 else
David S. Millerc0700f92008-12-16 23:53:20 -0800645 vars->flow_ctrl &= ~BNX2X_FLOW_CTRL_RX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700646
647 if (vars->phy_flags & PHY_XGXS_FLAG) {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700648 if (vars->line_speed &&
649 ((vars->line_speed == SPEED_10) ||
650 (vars->line_speed == SPEED_100))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700651 vars->phy_flags |= PHY_SGMII_FLAG;
652 } else {
653 vars->phy_flags &= ~PHY_SGMII_FLAG;
654 }
655 }
656
657 /* anything 10 and over uses the bmac */
658 link_10g = ((vars->line_speed == SPEED_10000) ||
659 (vars->line_speed == SPEED_12000) ||
660 (vars->line_speed == SPEED_12500) ||
661 (vars->line_speed == SPEED_13000) ||
662 (vars->line_speed == SPEED_15000) ||
663 (vars->line_speed == SPEED_16000));
664 if (link_10g)
665 vars->mac_type = MAC_TYPE_BMAC;
666 else
667 vars->mac_type = MAC_TYPE_EMAC;
668
669 } else { /* link down */
670 DP(NETIF_MSG_LINK, "phy link down\n");
671
672 vars->phy_link_up = 0;
673
674 vars->line_speed = 0;
675 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -0800676 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700677
678 /* indicate no mac active */
679 vars->mac_type = MAC_TYPE_NONE;
680 }
681
682 DP(NETIF_MSG_LINK, "link_status 0x%x phy_link_up %x\n",
683 vars->link_status, vars->phy_link_up);
684 DP(NETIF_MSG_LINK, "line_speed %x duplex %x flow_ctrl 0x%x\n",
685 vars->line_speed, vars->duplex, vars->flow_ctrl);
686}
687
688static void bnx2x_update_mng(struct link_params *params, u32 link_status)
689{
690 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +0000691
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700692 REG_WR(bp, params->shmem_base +
693 offsetof(struct shmem_region,
694 port_mb[params->port].link_status),
695 link_status);
696}
697
698static void bnx2x_bmac_rx_disable(struct bnx2x *bp, u8 port)
699{
700 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
701 NIG_REG_INGRESS_BMAC0_MEM;
702 u32 wb_data[2];
Eilon Greenstein3196a882008-08-13 15:58:49 -0700703 u32 nig_bmac_enable = REG_RD(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700704
705 /* Only if the bmac is out of reset */
706 if (REG_RD(bp, MISC_REG_RESET_REG_2) &
707 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port) &&
708 nig_bmac_enable) {
709
710 /* Clear Rx Enable bit in BMAC_CONTROL register */
711 REG_RD_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
712 wb_data, 2);
713 wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
714 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
715 wb_data, 2);
716
717 msleep(1);
718 }
719}
720
721static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl,
722 u32 line_speed)
723{
724 struct bnx2x *bp = params->bp;
725 u8 port = params->port;
726 u32 init_crd, crd;
727 u32 count = 1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700728
729 /* disable port */
730 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x1);
731
732 /* wait for init credit */
733 init_crd = REG_RD(bp, PBF_REG_P0_INIT_CRD + port*4);
734 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
735 DP(NETIF_MSG_LINK, "init_crd 0x%x crd 0x%x\n", init_crd, crd);
736
737 while ((init_crd != crd) && count) {
738 msleep(5);
739
740 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
741 count--;
742 }
743 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
744 if (init_crd != crd) {
745 DP(NETIF_MSG_LINK, "BUG! init_crd 0x%x != crd 0x%x\n",
746 init_crd, crd);
747 return -EINVAL;
748 }
749
David S. Millerc0700f92008-12-16 23:53:20 -0800750 if (flow_ctrl & BNX2X_FLOW_CTRL_RX ||
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700751 line_speed == SPEED_10 ||
752 line_speed == SPEED_100 ||
753 line_speed == SPEED_1000 ||
754 line_speed == SPEED_2500) {
755 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700756 /* update threshold */
757 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, 0);
758 /* update init credit */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700759 init_crd = 778; /* (800-18-4) */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700760
761 } else {
762 u32 thresh = (ETH_MAX_JUMBO_PACKET_SIZE +
763 ETH_OVREHEAD)/16;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700764 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700765 /* update threshold */
766 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, thresh);
767 /* update init credit */
768 switch (line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700769 case SPEED_10000:
770 init_crd = thresh + 553 - 22;
771 break;
772
773 case SPEED_12000:
774 init_crd = thresh + 664 - 22;
775 break;
776
777 case SPEED_13000:
778 init_crd = thresh + 742 - 22;
779 break;
780
781 case SPEED_16000:
782 init_crd = thresh + 778 - 22;
783 break;
784 default:
785 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
786 line_speed);
787 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700788 }
789 }
790 REG_WR(bp, PBF_REG_P0_INIT_CRD + port*4, init_crd);
791 DP(NETIF_MSG_LINK, "PBF updated to speed %d credit %d\n",
792 line_speed, init_crd);
793
794 /* probe the credit changes */
795 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x1);
796 msleep(5);
797 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x0);
798
799 /* enable port */
800 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x0);
801 return 0;
802}
803
Eilon Greenstein589abe32009-02-12 08:36:55 +0000804static u32 bnx2x_get_emac_base(struct bnx2x *bp, u32 ext_phy_type, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700805{
806 u32 emac_base;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +0000807
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700808 switch (ext_phy_type) {
809 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
Eilon Greenstein589abe32009-02-12 08:36:55 +0000810 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
Eilon Greenstein4d295db2009-07-21 05:47:47 +0000811 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
Eilon Greenstein589abe32009-02-12 08:36:55 +0000812 /* All MDC/MDIO is directed through single EMAC */
813 if (REG_RD(bp, NIG_REG_PORT_SWAP))
814 emac_base = GRCBASE_EMAC0;
815 else
816 emac_base = GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700817 break;
818 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Eilon Greenstein6378c022008-08-13 15:59:25 -0700819 emac_base = (port) ? GRCBASE_EMAC0 : GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700820 break;
821 default:
Eilon Greenstein6378c022008-08-13 15:59:25 -0700822 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700823 break;
824 }
825 return emac_base;
826
827}
828
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000829u8 bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy,
830 u8 devad, u16 reg, u16 val)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700831{
832 u32 tmp, saved_mode;
833 u8 i, rc = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700834
835 /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
836 * (a value of 49==0x31) and make sure that the AUTO poll is off
837 */
Eilon Greenstein589abe32009-02-12 08:36:55 +0000838
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000839 saved_mode = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700840 tmp = saved_mode & ~(EMAC_MDIO_MODE_AUTO_POLL |
841 EMAC_MDIO_MODE_CLOCK_CNT);
842 tmp |= (EMAC_MDIO_MODE_CLAUSE_45 |
843 (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000844 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, tmp);
845 REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700846 udelay(40);
847
848 /* address */
849
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000850 tmp = ((phy->addr << 21) | (devad << 16) | reg |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700851 EMAC_MDIO_COMM_COMMAND_ADDRESS |
852 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000853 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700854
855 for (i = 0; i < 50; i++) {
856 udelay(10);
857
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000858 tmp = REG_RD(bp, phy->mdio_ctrl +
859 EMAC_REG_EMAC_MDIO_COMM);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700860 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
861 udelay(5);
862 break;
863 }
864 }
865 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
866 DP(NETIF_MSG_LINK, "write phy register failed\n");
867 rc = -EFAULT;
868 } else {
869 /* data */
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000870 tmp = ((phy->addr << 21) | (devad << 16) | val |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700871 EMAC_MDIO_COMM_COMMAND_WRITE_45 |
872 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000873 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700874
875 for (i = 0; i < 50; i++) {
876 udelay(10);
877
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000878 tmp = REG_RD(bp, phy->mdio_ctrl +
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700879 EMAC_REG_EMAC_MDIO_COMM);
880 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
881 udelay(5);
882 break;
883 }
884 }
885 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
886 DP(NETIF_MSG_LINK, "write phy register failed\n");
887 rc = -EFAULT;
888 }
889 }
890
891 /* Restore the saved mode */
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000892 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700893
894 return rc;
895}
896
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000897u8 bnx2x_cl45_read(struct bnx2x *bp, struct bnx2x_phy *phy,
898 u8 devad, u16 reg, u16 *ret_val)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700899{
900 u32 val, saved_mode;
901 u16 i;
902 u8 rc = 0;
903
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700904 /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
905 * (a value of 49==0x31) and make sure that the AUTO poll is off
906 */
Eilon Greenstein589abe32009-02-12 08:36:55 +0000907
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000908 saved_mode = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
909 val = saved_mode & ~((EMAC_MDIO_MODE_AUTO_POLL |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700910 EMAC_MDIO_MODE_CLOCK_CNT));
911 val |= (EMAC_MDIO_MODE_CLAUSE_45 |
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +0000912 (49L << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000913 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, val);
914 REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700915 udelay(40);
916
917 /* address */
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000918 val = ((phy->addr << 21) | (devad << 16) | reg |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700919 EMAC_MDIO_COMM_COMMAND_ADDRESS |
920 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000921 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700922
923 for (i = 0; i < 50; i++) {
924 udelay(10);
925
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000926 val = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700927 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
928 udelay(5);
929 break;
930 }
931 }
932 if (val & EMAC_MDIO_COMM_START_BUSY) {
933 DP(NETIF_MSG_LINK, "read phy register failed\n");
934
935 *ret_val = 0;
936 rc = -EFAULT;
937
938 } else {
939 /* data */
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000940 val = ((phy->addr << 21) | (devad << 16) |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700941 EMAC_MDIO_COMM_COMMAND_READ_45 |
942 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000943 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700944
945 for (i = 0; i < 50; i++) {
946 udelay(10);
947
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000948 val = REG_RD(bp, phy->mdio_ctrl +
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700949 EMAC_REG_EMAC_MDIO_COMM);
950 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
951 *ret_val = (u16)(val & EMAC_MDIO_COMM_DATA);
952 break;
953 }
954 }
955 if (val & EMAC_MDIO_COMM_START_BUSY) {
956 DP(NETIF_MSG_LINK, "read phy register failed\n");
957
958 *ret_val = 0;
959 rc = -EFAULT;
960 }
961 }
962
963 /* Restore the saved mode */
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000964 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700965
966 return rc;
967}
968
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000969u8 bnx2x_phy_read(struct link_params *params, u8 phy_addr,
970 u8 devad, u16 reg, u16 *ret_val)
971{
972 u8 phy_index;
973 /**
974 * Probe for the phy according to the given phy_addr, and execute
975 * the read request on it
976 */
977 for (phy_index = 0; phy_index < params->num_phys; phy_index++) {
978 if (params->phy[phy_index].addr == phy_addr) {
979 return bnx2x_cl45_read(params->bp,
980 &params->phy[phy_index], devad,
981 reg, ret_val);
982 }
983 }
984 return -EINVAL;
985}
986
987u8 bnx2x_phy_write(struct link_params *params, u8 phy_addr,
988 u8 devad, u16 reg, u16 val)
989{
990 u8 phy_index;
991 /**
992 * Probe for the phy according to the given phy_addr, and execute
993 * the write request on it
994 */
995 for (phy_index = 0; phy_index < params->num_phys; phy_index++) {
996 if (params->phy[phy_index].addr == phy_addr) {
997 return bnx2x_cl45_write(params->bp,
998 &params->phy[phy_index], devad,
999 reg, val);
1000 }
1001 }
1002 return -EINVAL;
1003}
1004
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001005static void bnx2x_set_aer_mmd(struct link_params *params,
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001006 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001007{
1008 struct bnx2x *bp = params->bp;
1009 u32 ser_lane;
1010 u16 offset;
1011
1012 ser_lane = ((params->lane_config &
1013 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
1014 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
1015
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001016 offset = (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ?
1017 (phy->addr + ser_lane) : 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001018
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001019 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001020 MDIO_REG_BANK_AER_BLOCK,
1021 MDIO_AER_BLOCK_AER_REG, 0x3800 + offset);
1022}
1023
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001024static void bnx2x_set_master_ln(struct link_params *params,
1025 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001026{
1027 struct bnx2x *bp = params->bp;
1028 u16 new_master_ln, ser_lane;
1029 ser_lane = ((params->lane_config &
1030 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
1031 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
1032
1033 /* set the master_ln for AN */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001034 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001035 MDIO_REG_BANK_XGXS_BLOCK2,
1036 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
1037 &new_master_ln);
1038
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001039 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001040 MDIO_REG_BANK_XGXS_BLOCK2 ,
1041 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
1042 (new_master_ln | ser_lane));
1043}
1044
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001045static u8 bnx2x_reset_unicore(struct link_params *params,
1046 struct bnx2x_phy *phy,
1047 u8 set_serdes)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001048{
1049 struct bnx2x *bp = params->bp;
1050 u16 mii_control;
1051 u16 i;
1052
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001053 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001054 MDIO_REG_BANK_COMBO_IEEE0,
1055 MDIO_COMBO_IEEE0_MII_CONTROL, &mii_control);
1056
1057 /* reset the unicore */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001058 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001059 MDIO_REG_BANK_COMBO_IEEE0,
1060 MDIO_COMBO_IEEE0_MII_CONTROL,
1061 (mii_control |
1062 MDIO_COMBO_IEEO_MII_CONTROL_RESET));
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001063 if (set_serdes)
1064 bnx2x_set_serdes_access(bp, params->port);
Eilon Greensteinc1b73992009-02-12 08:37:07 +00001065
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001066 /* wait for the reset to self clear */
1067 for (i = 0; i < MDIO_ACCESS_TIMEOUT; i++) {
1068 udelay(5);
1069
1070 /* the reset erased the previous bank value */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001071 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001072 MDIO_REG_BANK_COMBO_IEEE0,
1073 MDIO_COMBO_IEEE0_MII_CONTROL,
1074 &mii_control);
1075
1076 if (!(mii_control & MDIO_COMBO_IEEO_MII_CONTROL_RESET)) {
1077 udelay(5);
1078 return 0;
1079 }
1080 }
1081
1082 DP(NETIF_MSG_LINK, "BUG! XGXS is still in reset!\n");
1083 return -EINVAL;
1084
1085}
1086
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001087static void bnx2x_set_swap_lanes(struct link_params *params,
1088 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001089{
1090 struct bnx2x *bp = params->bp;
1091 /* Each two bits represents a lane number:
1092 No swap is 0123 => 0x1b no need to enable the swap */
1093 u16 ser_lane, rx_lane_swap, tx_lane_swap;
1094
1095 ser_lane = ((params->lane_config &
1096 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
1097 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
1098 rx_lane_swap = ((params->lane_config &
1099 PORT_HW_CFG_LANE_SWAP_CFG_RX_MASK) >>
1100 PORT_HW_CFG_LANE_SWAP_CFG_RX_SHIFT);
1101 tx_lane_swap = ((params->lane_config &
1102 PORT_HW_CFG_LANE_SWAP_CFG_TX_MASK) >>
1103 PORT_HW_CFG_LANE_SWAP_CFG_TX_SHIFT);
1104
1105 if (rx_lane_swap != 0x1b) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001106 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001107 MDIO_REG_BANK_XGXS_BLOCK2,
1108 MDIO_XGXS_BLOCK2_RX_LN_SWAP,
1109 (rx_lane_swap |
1110 MDIO_XGXS_BLOCK2_RX_LN_SWAP_ENABLE |
1111 MDIO_XGXS_BLOCK2_RX_LN_SWAP_FORCE_ENABLE));
1112 } else {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001113 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001114 MDIO_REG_BANK_XGXS_BLOCK2,
1115 MDIO_XGXS_BLOCK2_RX_LN_SWAP, 0);
1116 }
1117
1118 if (tx_lane_swap != 0x1b) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001119 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001120 MDIO_REG_BANK_XGXS_BLOCK2,
1121 MDIO_XGXS_BLOCK2_TX_LN_SWAP,
1122 (tx_lane_swap |
1123 MDIO_XGXS_BLOCK2_TX_LN_SWAP_ENABLE));
1124 } else {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001125 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001126 MDIO_REG_BANK_XGXS_BLOCK2,
1127 MDIO_XGXS_BLOCK2_TX_LN_SWAP, 0);
1128 }
1129}
1130
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001131static void bnx2x_set_parallel_detection(struct bnx2x_phy *phy,
1132 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001133{
1134 struct bnx2x *bp = params->bp;
1135 u16 control2;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001136 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001137 MDIO_REG_BANK_SERDES_DIGITAL,
1138 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
1139 &control2);
Yaniv Rosner18afb0a2009-11-05 19:18:04 +02001140 if (params->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
1141 control2 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
1142 else
1143 control2 &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
1144 DP(NETIF_MSG_LINK, "params->speed_cap_mask = 0x%x, control2 = 0x%x\n",
1145 params->speed_cap_mask, control2);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001146 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001147 MDIO_REG_BANK_SERDES_DIGITAL,
1148 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
1149 control2);
1150
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001151 if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
Yaniv Rosner18afb0a2009-11-05 19:18:04 +02001152 (params->speed_cap_mask &
1153 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001154 DP(NETIF_MSG_LINK, "XGXS\n");
1155
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001156 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001157 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1158 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK,
1159 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT);
1160
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001161 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001162 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1163 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
1164 &control2);
1165
1166
1167 control2 |=
1168 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN;
1169
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001170 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001171 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1172 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
1173 control2);
1174
1175 /* Disable parallel detection of HiG */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001176 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001177 MDIO_REG_BANK_XGXS_BLOCK2,
1178 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G,
1179 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_CX4_XGXS |
1180 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_HIGIG_XGXS);
1181 }
1182}
1183
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001184static void bnx2x_set_autoneg(struct bnx2x_phy *phy,
1185 struct link_params *params,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001186 struct link_vars *vars,
1187 u8 enable_cl73)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001188{
1189 struct bnx2x *bp = params->bp;
1190 u16 reg_val;
1191
1192 /* CL37 Autoneg */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001193 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001194 MDIO_REG_BANK_COMBO_IEEE0,
1195 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
1196
1197 /* CL37 Autoneg Enabled */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001198 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001199 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_AN_EN;
1200 else /* CL37 Autoneg Disabled */
1201 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1202 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN);
1203
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001204 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001205 MDIO_REG_BANK_COMBO_IEEE0,
1206 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
1207
1208 /* Enable/Disable Autodetection */
1209
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001210 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001211 MDIO_REG_BANK_SERDES_DIGITAL,
1212 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, &reg_val);
Eilon Greenstein239d6862009-08-12 08:23:04 +00001213 reg_val &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN |
1214 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT);
1215 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001216 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001217 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
1218 else
1219 reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
1220
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001221 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001222 MDIO_REG_BANK_SERDES_DIGITAL,
1223 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, reg_val);
1224
1225 /* Enable TetonII and BAM autoneg */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001226 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001227 MDIO_REG_BANK_BAM_NEXT_PAGE,
1228 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
1229 &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001230 if (vars->line_speed == SPEED_AUTO_NEG) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001231 /* Enable BAM aneg Mode and TetonII aneg Mode */
1232 reg_val |= (MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
1233 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
1234 } else {
1235 /* TetonII and BAM Autoneg Disabled */
1236 reg_val &= ~(MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
1237 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
1238 }
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001239 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001240 MDIO_REG_BANK_BAM_NEXT_PAGE,
1241 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
1242 reg_val);
1243
Eilon Greenstein239d6862009-08-12 08:23:04 +00001244 if (enable_cl73) {
1245 /* Enable Cl73 FSM status bits */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001246 CL45_WR_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001247 MDIO_REG_BANK_CL73_USERB0,
1248 MDIO_CL73_USERB0_CL73_UCTRL,
Yaniv Rosner7846e472009-11-05 19:18:07 +02001249 0xe);
Eilon Greenstein239d6862009-08-12 08:23:04 +00001250
1251 /* Enable BAM Station Manager*/
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001252 CL45_WR_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001253 MDIO_REG_BANK_CL73_USERB0,
1254 MDIO_CL73_USERB0_CL73_BAM_CTRL1,
1255 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN |
1256 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_STATION_MNGR_EN |
1257 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN);
1258
Yaniv Rosner7846e472009-11-05 19:18:07 +02001259 /* Advertise CL73 link speeds */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001260 CL45_RD_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001261 MDIO_REG_BANK_CL73_IEEEB1,
1262 MDIO_CL73_IEEEB1_AN_ADV2,
1263 &reg_val);
Yaniv Rosner7846e472009-11-05 19:18:07 +02001264 if (params->speed_cap_mask &
1265 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
1266 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4;
1267 if (params->speed_cap_mask &
1268 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
1269 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX;
Eilon Greenstein239d6862009-08-12 08:23:04 +00001270
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001271 CL45_WR_OVER_CL22(bp, phy,
Julia Lawallcc817352010-08-05 10:26:38 +00001272 MDIO_REG_BANK_CL73_IEEEB1,
1273 MDIO_CL73_IEEEB1_AN_ADV2,
1274 reg_val);
Eilon Greenstein239d6862009-08-12 08:23:04 +00001275
Eilon Greenstein239d6862009-08-12 08:23:04 +00001276 /* CL73 Autoneg Enabled */
1277 reg_val = MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN;
1278
1279 } else /* CL73 Autoneg Disabled */
1280 reg_val = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001281
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001282 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001283 MDIO_REG_BANK_CL73_IEEEB0,
1284 MDIO_CL73_IEEEB0_CL73_AN_CONTROL, reg_val);
1285}
1286
1287/* program SerDes, forced speed */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001288static void bnx2x_program_serdes(struct bnx2x_phy *phy,
1289 struct link_params *params,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001290 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001291{
1292 struct bnx2x *bp = params->bp;
1293 u16 reg_val;
1294
Eilon Greenstein57937202009-08-12 08:23:53 +00001295 /* program duplex, disable autoneg and sgmii*/
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001296 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001297 MDIO_REG_BANK_COMBO_IEEE0,
1298 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
1299 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX |
Eilon Greenstein57937202009-08-12 08:23:53 +00001300 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1301 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001302 if (params->req_duplex == DUPLEX_FULL)
1303 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001304 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001305 MDIO_REG_BANK_COMBO_IEEE0,
1306 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
1307
1308 /* program speed
1309 - needed only if the speed is greater than 1G (2.5G or 10G) */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001310 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001311 MDIO_REG_BANK_SERDES_DIGITAL,
1312 MDIO_SERDES_DIGITAL_MISC1, &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001313 /* clearing the speed value before setting the right speed */
1314 DP(NETIF_MSG_LINK, "MDIO_REG_BANK_SERDES_DIGITAL = 0x%x\n", reg_val);
1315
1316 reg_val &= ~(MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_MASK |
1317 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
1318
1319 if (!((vars->line_speed == SPEED_1000) ||
1320 (vars->line_speed == SPEED_100) ||
1321 (vars->line_speed == SPEED_10))) {
1322
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001323 reg_val |= (MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_156_25M |
1324 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001325 if (vars->line_speed == SPEED_10000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001326 reg_val |=
1327 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_10G_CX4;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001328 if (vars->line_speed == SPEED_13000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001329 reg_val |=
1330 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_13G;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001331 }
1332
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001333 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001334 MDIO_REG_BANK_SERDES_DIGITAL,
1335 MDIO_SERDES_DIGITAL_MISC1, reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001336
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001337}
1338
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001339static void bnx2x_set_brcm_cl37_advertisment(struct bnx2x_phy *phy,
1340 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001341{
1342 struct bnx2x *bp = params->bp;
1343 u16 val = 0;
1344
1345 /* configure the 48 bits for BAM AN */
1346
1347 /* set extended capabilities */
1348 if (params->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G)
1349 val |= MDIO_OVER_1G_UP1_2_5G;
1350 if (params->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
1351 val |= MDIO_OVER_1G_UP1_10G;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001352 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001353 MDIO_REG_BANK_OVER_1G,
1354 MDIO_OVER_1G_UP1, val);
1355
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001356 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001357 MDIO_REG_BANK_OVER_1G,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001358 MDIO_OVER_1G_UP3, 0x400);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001359}
1360
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001361static void bnx2x_calc_ieee_aneg_adv(struct bnx2x_phy *phy,
1362 struct link_params *params, u16 *ieee_fc)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001363{
Yaniv Rosnerd5cb9e92009-11-05 19:18:10 +02001364 struct bnx2x *bp = params->bp;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001365 *ieee_fc = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001366 /* resolve pause mode and advertisement
1367 * Please refer to Table 28B-3 of the 802.3ab-1999 spec */
1368
1369 switch (params->req_flow_ctrl) {
David S. Millerc0700f92008-12-16 23:53:20 -08001370 case BNX2X_FLOW_CTRL_AUTO:
1371 if (params->req_fc_auto_adv == BNX2X_FLOW_CTRL_BOTH) {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001372 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001373 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
1374 } else {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001375 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001376 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
1377 }
1378 break;
David S. Millerc0700f92008-12-16 23:53:20 -08001379 case BNX2X_FLOW_CTRL_TX:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001380 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001381 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
1382 break;
1383
David S. Millerc0700f92008-12-16 23:53:20 -08001384 case BNX2X_FLOW_CTRL_RX:
1385 case BNX2X_FLOW_CTRL_BOTH:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001386 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001387 break;
1388
David S. Millerc0700f92008-12-16 23:53:20 -08001389 case BNX2X_FLOW_CTRL_NONE:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001390 default:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001391 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001392 break;
1393 }
Yaniv Rosnerd5cb9e92009-11-05 19:18:10 +02001394 DP(NETIF_MSG_LINK, "ieee_fc = 0x%x\n", *ieee_fc);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001395}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001396
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001397static void bnx2x_set_ieee_aneg_advertisment(struct bnx2x_phy *phy,
1398 struct link_params *params,
Eilon Greenstein1ef70b92009-08-12 08:23:59 +00001399 u16 ieee_fc)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001400{
1401 struct bnx2x *bp = params->bp;
Yaniv Rosner7846e472009-11-05 19:18:07 +02001402 u16 val;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001403 /* for AN, we are always publishing full duplex */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001404
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001405 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001406 MDIO_REG_BANK_COMBO_IEEE0,
Eilon Greenstein1ef70b92009-08-12 08:23:59 +00001407 MDIO_COMBO_IEEE0_AUTO_NEG_ADV, ieee_fc);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001408 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner7846e472009-11-05 19:18:07 +02001409 MDIO_REG_BANK_CL73_IEEEB1,
1410 MDIO_CL73_IEEEB1_AN_ADV1, &val);
1411 val &= ~MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_BOTH;
1412 val |= ((ieee_fc<<3) & MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001413 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosner7846e472009-11-05 19:18:07 +02001414 MDIO_REG_BANK_CL73_IEEEB1,
1415 MDIO_CL73_IEEEB1_AN_ADV1, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001416}
1417
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001418static void bnx2x_restart_autoneg(struct bnx2x_phy *phy,
1419 struct link_params *params,
1420 u8 enable_cl73)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001421{
1422 struct bnx2x *bp = params->bp;
Eilon Greenstein3a36f2e2009-02-12 08:37:09 +00001423 u16 mii_control;
Eilon Greenstein239d6862009-08-12 08:23:04 +00001424
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001425 DP(NETIF_MSG_LINK, "bnx2x_restart_autoneg\n");
Eilon Greenstein3a36f2e2009-02-12 08:37:09 +00001426 /* Enable and restart BAM/CL37 aneg */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001427
Eilon Greenstein239d6862009-08-12 08:23:04 +00001428 if (enable_cl73) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001429 CL45_RD_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001430 MDIO_REG_BANK_CL73_IEEEB0,
1431 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1432 &mii_control);
1433
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001434 CL45_WR_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001435 MDIO_REG_BANK_CL73_IEEEB0,
1436 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1437 (mii_control |
1438 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN |
1439 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN));
1440 } else {
1441
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001442 CL45_RD_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001443 MDIO_REG_BANK_COMBO_IEEE0,
1444 MDIO_COMBO_IEEE0_MII_CONTROL,
1445 &mii_control);
1446 DP(NETIF_MSG_LINK,
1447 "bnx2x_restart_autoneg mii_control before = 0x%x\n",
1448 mii_control);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001449 CL45_WR_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001450 MDIO_REG_BANK_COMBO_IEEE0,
1451 MDIO_COMBO_IEEE0_MII_CONTROL,
1452 (mii_control |
1453 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1454 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN));
1455 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001456}
1457
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001458static void bnx2x_initialize_sgmii_process(struct bnx2x_phy *phy,
1459 struct link_params *params,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001460 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001461{
1462 struct bnx2x *bp = params->bp;
1463 u16 control1;
1464
1465 /* in SGMII mode, the unicore is always slave */
1466
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001467 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001468 MDIO_REG_BANK_SERDES_DIGITAL,
1469 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
1470 &control1);
1471 control1 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT;
1472 /* set sgmii mode (and not fiber) */
1473 control1 &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE |
1474 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET |
1475 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_MSTR_MODE);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001476 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001477 MDIO_REG_BANK_SERDES_DIGITAL,
1478 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
1479 control1);
1480
1481 /* if forced speed */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001482 if (!(vars->line_speed == SPEED_AUTO_NEG)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001483 /* set speed, disable autoneg */
1484 u16 mii_control;
1485
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001486 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001487 MDIO_REG_BANK_COMBO_IEEE0,
1488 MDIO_COMBO_IEEE0_MII_CONTROL,
1489 &mii_control);
1490 mii_control &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1491 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK|
1492 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX);
1493
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001494 switch (vars->line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001495 case SPEED_100:
1496 mii_control |=
1497 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_100;
1498 break;
1499 case SPEED_1000:
1500 mii_control |=
1501 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_1000;
1502 break;
1503 case SPEED_10:
1504 /* there is nothing to set for 10M */
1505 break;
1506 default:
1507 /* invalid speed for SGMII */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001508 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
1509 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001510 break;
1511 }
1512
1513 /* setting the full duplex */
1514 if (params->req_duplex == DUPLEX_FULL)
1515 mii_control |=
1516 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001517 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001518 MDIO_REG_BANK_COMBO_IEEE0,
1519 MDIO_COMBO_IEEE0_MII_CONTROL,
1520 mii_control);
1521
1522 } else { /* AN mode */
1523 /* enable and restart AN */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001524 bnx2x_restart_autoneg(phy, params, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001525 }
1526}
1527
1528
1529/*
1530 * link management
1531 */
1532
1533static void bnx2x_pause_resolve(struct link_vars *vars, u32 pause_result)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001534{ /* LD LP */
1535 switch (pause_result) { /* ASYM P ASYM P */
1536 case 0xb: /* 1 0 1 1 */
David S. Millerc0700f92008-12-16 23:53:20 -08001537 vars->flow_ctrl = BNX2X_FLOW_CTRL_TX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001538 break;
1539
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001540 case 0xe: /* 1 1 1 0 */
David S. Millerc0700f92008-12-16 23:53:20 -08001541 vars->flow_ctrl = BNX2X_FLOW_CTRL_RX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001542 break;
1543
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001544 case 0x5: /* 0 1 0 1 */
1545 case 0x7: /* 0 1 1 1 */
1546 case 0xd: /* 1 1 0 1 */
1547 case 0xf: /* 1 1 1 1 */
David S. Millerc0700f92008-12-16 23:53:20 -08001548 vars->flow_ctrl = BNX2X_FLOW_CTRL_BOTH;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001549 break;
1550
1551 default:
1552 break;
1553 }
1554}
1555
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001556static u8 bnx2x_ext_phy_resolve_fc(struct bnx2x_phy *phy,
1557 struct link_params *params,
1558 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001559{
1560 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00001561 u16 ld_pause; /* local */
1562 u16 lp_pause; /* link partner */
1563 u16 an_complete; /* AN complete */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001564 u16 pause_result;
1565 u8 ret = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001566 /* read twice */
1567
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001568 bnx2x_cl45_read(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001569 MDIO_AN_DEVAD,
1570 MDIO_AN_REG_STATUS, &an_complete);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001571 bnx2x_cl45_read(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001572 MDIO_AN_DEVAD,
1573 MDIO_AN_REG_STATUS, &an_complete);
1574
1575 if (an_complete & MDIO_AN_REG_STATUS_AN_COMPLETE) {
1576 ret = 1;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001577 bnx2x_cl45_read(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001578 MDIO_AN_DEVAD,
1579 MDIO_AN_REG_ADV_PAUSE, &ld_pause);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001580 bnx2x_cl45_read(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001581 MDIO_AN_DEVAD,
1582 MDIO_AN_REG_LP_AUTO_NEG, &lp_pause);
1583 pause_result = (ld_pause &
1584 MDIO_AN_REG_ADV_PAUSE_MASK) >> 8;
1585 pause_result |= (lp_pause &
1586 MDIO_AN_REG_ADV_PAUSE_MASK) >> 10;
Frans Pop2381a552010-03-24 07:57:36 +00001587 DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x\n",
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001588 pause_result);
1589 bnx2x_pause_resolve(vars, pause_result);
David S. Millerc0700f92008-12-16 23:53:20 -08001590 if (vars->flow_ctrl == BNX2X_FLOW_CTRL_NONE &&
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001591 phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
1592 bnx2x_cl45_read(bp, phy,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001593 MDIO_AN_DEVAD,
1594 MDIO_AN_REG_CL37_FC_LD, &ld_pause);
1595
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001596 bnx2x_cl45_read(bp, phy,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001597 MDIO_AN_DEVAD,
1598 MDIO_AN_REG_CL37_FC_LP, &lp_pause);
1599 pause_result = (ld_pause &
1600 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 5;
1601 pause_result |= (lp_pause &
1602 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 7;
1603
1604 bnx2x_pause_resolve(vars, pause_result);
Frans Pop2381a552010-03-24 07:57:36 +00001605 DP(NETIF_MSG_LINK, "Ext PHY CL37 pause result 0x%x\n",
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001606 pause_result);
1607 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001608 }
1609 return ret;
1610}
1611
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001612static u8 bnx2x_direct_parallel_detect_used(struct bnx2x_phy *phy,
1613 struct link_params *params)
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02001614{
1615 struct bnx2x *bp = params->bp;
1616 u16 pd_10g, status2_1000x;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001617 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02001618 MDIO_REG_BANK_SERDES_DIGITAL,
1619 MDIO_SERDES_DIGITAL_A_1000X_STATUS2,
1620 &status2_1000x);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001621 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02001622 MDIO_REG_BANK_SERDES_DIGITAL,
1623 MDIO_SERDES_DIGITAL_A_1000X_STATUS2,
1624 &status2_1000x);
1625 if (status2_1000x & MDIO_SERDES_DIGITAL_A_1000X_STATUS2_AN_DISABLED) {
1626 DP(NETIF_MSG_LINK, "1G parallel detect link on port %d\n",
1627 params->port);
1628 return 1;
1629 }
1630
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001631 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02001632 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1633 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_STATUS,
1634 &pd_10g);
1635
1636 if (pd_10g & MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_STATUS_PD_LINK) {
1637 DP(NETIF_MSG_LINK, "10G parallel detect link on port %d\n",
1638 params->port);
1639 return 1;
1640 }
1641 return 0;
1642}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001643
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001644static void bnx2x_flow_ctrl_resolve(struct bnx2x_phy *phy,
1645 struct link_params *params,
1646 struct link_vars *vars,
1647 u32 gp_status)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001648{
1649 struct bnx2x *bp = params->bp;
Eilon Greenstein3196a882008-08-13 15:58:49 -07001650 u16 ld_pause; /* local driver */
1651 u16 lp_pause; /* link partner */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001652 u16 pause_result;
1653
David S. Millerc0700f92008-12-16 23:53:20 -08001654 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001655
1656 /* resolve from gp_status in case of AN complete and not sgmii */
David S. Millerc0700f92008-12-16 23:53:20 -08001657 if ((params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) &&
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001658 (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) &&
1659 (!(vars->phy_flags & PHY_SGMII_FLAG)) &&
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001660 (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT)) {
1661 if (bnx2x_direct_parallel_detect_used(phy, params)) {
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02001662 vars->flow_ctrl = params->req_fc_auto_adv;
1663 return;
1664 }
Yaniv Rosner7846e472009-11-05 19:18:07 +02001665 if ((gp_status &
1666 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
1667 MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) ==
1668 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
1669 MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) {
1670
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001671 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner7846e472009-11-05 19:18:07 +02001672 MDIO_REG_BANK_CL73_IEEEB1,
1673 MDIO_CL73_IEEEB1_AN_ADV1,
1674 &ld_pause);
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_CL73_IEEEB1,
1677 MDIO_CL73_IEEEB1_AN_LP_ADV1,
1678 &lp_pause);
1679 pause_result = (ld_pause &
1680 MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK)
1681 >> 8;
1682 pause_result |= (lp_pause &
1683 MDIO_CL73_IEEEB1_AN_LP_ADV1_PAUSE_MASK)
1684 >> 10;
1685 DP(NETIF_MSG_LINK, "pause_result CL73 0x%x\n",
1686 pause_result);
1687 } else {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001688 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner7846e472009-11-05 19:18:07 +02001689 MDIO_REG_BANK_COMBO_IEEE0,
1690 MDIO_COMBO_IEEE0_AUTO_NEG_ADV,
1691 &ld_pause);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001692 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner7846e472009-11-05 19:18:07 +02001693 MDIO_REG_BANK_COMBO_IEEE0,
1694 MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1,
1695 &lp_pause);
1696 pause_result = (ld_pause &
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001697 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>5;
Yaniv Rosner7846e472009-11-05 19:18:07 +02001698 pause_result |= (lp_pause &
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001699 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7;
Yaniv Rosner7846e472009-11-05 19:18:07 +02001700 DP(NETIF_MSG_LINK, "pause_result CL37 0x%x\n",
1701 pause_result);
1702 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001703 bnx2x_pause_resolve(vars, pause_result);
David S. Millerc0700f92008-12-16 23:53:20 -08001704 } else if ((params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) &&
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001705 (bnx2x_ext_phy_resolve_fc(phy, params, vars))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001706 return;
1707 } else {
David S. Millerc0700f92008-12-16 23:53:20 -08001708 if (params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001709 vars->flow_ctrl = params->req_fc_auto_adv;
1710 else
1711 vars->flow_ctrl = params->req_flow_ctrl;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001712 }
1713 DP(NETIF_MSG_LINK, "flow_ctrl 0x%x\n", vars->flow_ctrl);
1714}
1715
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001716static void bnx2x_check_fallback_to_cl37(struct bnx2x_phy *phy,
1717 struct link_params *params)
Eilon Greenstein239d6862009-08-12 08:23:04 +00001718{
1719 struct bnx2x *bp = params->bp;
1720 u16 rx_status, ustat_val, cl37_fsm_recieved;
1721 DP(NETIF_MSG_LINK, "bnx2x_check_fallback_to_cl37\n");
1722 /* Step 1: Make sure signal is detected */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001723 CL45_RD_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001724 MDIO_REG_BANK_RX0,
1725 MDIO_RX0_RX_STATUS,
1726 &rx_status);
1727 if ((rx_status & MDIO_RX0_RX_STATUS_SIGDET) !=
1728 (MDIO_RX0_RX_STATUS_SIGDET)) {
1729 DP(NETIF_MSG_LINK, "Signal is not detected. Restoring CL73."
1730 "rx_status(0x80b0) = 0x%x\n", rx_status);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001731 CL45_WR_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001732 MDIO_REG_BANK_CL73_IEEEB0,
1733 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1734 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN);
1735 return;
1736 }
1737 /* Step 2: Check CL73 state machine */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001738 CL45_RD_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001739 MDIO_REG_BANK_CL73_USERB0,
1740 MDIO_CL73_USERB0_CL73_USTAT1,
1741 &ustat_val);
1742 if ((ustat_val &
1743 (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK |
1744 MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) !=
1745 (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK |
1746 MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) {
1747 DP(NETIF_MSG_LINK, "CL73 state-machine is not stable. "
1748 "ustat_val(0x8371) = 0x%x\n", ustat_val);
1749 return;
1750 }
1751 /* Step 3: Check CL37 Message Pages received to indicate LP
1752 supports only CL37 */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001753 CL45_RD_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001754 MDIO_REG_BANK_REMOTE_PHY,
1755 MDIO_REMOTE_PHY_MISC_RX_STATUS,
1756 &cl37_fsm_recieved);
1757 if ((cl37_fsm_recieved &
1758 (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG |
1759 MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) !=
1760 (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG |
1761 MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) {
1762 DP(NETIF_MSG_LINK, "No CL37 FSM were received. "
1763 "misc_rx_status(0x8330) = 0x%x\n",
1764 cl37_fsm_recieved);
1765 return;
1766 }
1767 /* The combined cl37/cl73 fsm state information indicating that we are
1768 connected to a device which does not support cl73, but does support
1769 cl37 BAM. In this case we disable cl73 and restart cl37 auto-neg */
1770 /* Disable CL73 */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001771 CL45_WR_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001772 MDIO_REG_BANK_CL73_IEEEB0,
1773 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1774 0);
1775 /* Restart CL37 autoneg */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001776 bnx2x_restart_autoneg(phy, params, 0);
Eilon Greenstein239d6862009-08-12 08:23:04 +00001777 DP(NETIF_MSG_LINK, "Disabling CL73, and restarting CL37 autoneg\n");
1778}
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00001779static u8 bnx2x_link_settings_status(struct bnx2x_phy *phy,
1780 struct link_params *params,
1781 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001782{
1783 struct bnx2x *bp = params->bp;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00001784 u16 new_line_speed , gp_status;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001785 u8 rc = 0;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001786 u32 ext_phy_type;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00001787 /* Read gp_status */
1788 CL45_RD_OVER_CL22(bp, phy,
1789 MDIO_REG_BANK_GP_STATUS,
1790 MDIO_GP_STATUS_TOP_AN_STATUS1,
1791 &gp_status);
1792
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001793 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) {
1794 DP(NETIF_MSG_LINK, "phy link up gp_status=0x%x\n",
1795 gp_status);
1796
1797 vars->phy_link_up = 1;
1798 vars->link_status |= LINK_STATUS_LINK_UP;
1799
1800 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_DUPLEX_STATUS)
1801 vars->duplex = DUPLEX_FULL;
1802 else
1803 vars->duplex = DUPLEX_HALF;
1804
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001805 bnx2x_flow_ctrl_resolve(&params->phy[INT_PHY],
1806 params, vars, gp_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001807
1808 switch (gp_status & GP_STATUS_SPEED_MASK) {
1809 case GP_STATUS_10M:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001810 new_line_speed = SPEED_10;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001811 if (vars->duplex == DUPLEX_FULL)
1812 vars->link_status |= LINK_10TFD;
1813 else
1814 vars->link_status |= LINK_10THD;
1815 break;
1816
1817 case GP_STATUS_100M:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001818 new_line_speed = SPEED_100;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001819 if (vars->duplex == DUPLEX_FULL)
1820 vars->link_status |= LINK_100TXFD;
1821 else
1822 vars->link_status |= LINK_100TXHD;
1823 break;
1824
1825 case GP_STATUS_1G:
1826 case GP_STATUS_1G_KX:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001827 new_line_speed = SPEED_1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001828 if (vars->duplex == DUPLEX_FULL)
1829 vars->link_status |= LINK_1000TFD;
1830 else
1831 vars->link_status |= LINK_1000THD;
1832 break;
1833
1834 case GP_STATUS_2_5G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001835 new_line_speed = SPEED_2500;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001836 if (vars->duplex == DUPLEX_FULL)
1837 vars->link_status |= LINK_2500TFD;
1838 else
1839 vars->link_status |= LINK_2500THD;
1840 break;
1841
1842 case GP_STATUS_5G:
1843 case GP_STATUS_6G:
1844 DP(NETIF_MSG_LINK,
1845 "link speed unsupported gp_status 0x%x\n",
1846 gp_status);
1847 return -EINVAL;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00001848
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001849 case GP_STATUS_10G_KX4:
1850 case GP_STATUS_10G_HIG:
1851 case GP_STATUS_10G_CX4:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001852 new_line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001853 vars->link_status |= LINK_10GTFD;
1854 break;
1855
1856 case GP_STATUS_12G_HIG:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001857 new_line_speed = SPEED_12000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001858 vars->link_status |= LINK_12GTFD;
1859 break;
1860
1861 case GP_STATUS_12_5G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001862 new_line_speed = SPEED_12500;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001863 vars->link_status |= LINK_12_5GTFD;
1864 break;
1865
1866 case GP_STATUS_13G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001867 new_line_speed = SPEED_13000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001868 vars->link_status |= LINK_13GTFD;
1869 break;
1870
1871 case GP_STATUS_15G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001872 new_line_speed = SPEED_15000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001873 vars->link_status |= LINK_15GTFD;
1874 break;
1875
1876 case GP_STATUS_16G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001877 new_line_speed = SPEED_16000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001878 vars->link_status |= LINK_16GTFD;
1879 break;
1880
1881 default:
1882 DP(NETIF_MSG_LINK,
1883 "link speed unsupported gp_status 0x%x\n",
1884 gp_status);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00001885 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001886 }
1887
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001888 vars->line_speed = new_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001889 vars->link_status |= LINK_STATUS_SERDES_LINK;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001890 ext_phy_type = params->phy[EXT_PHY1].type;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07001891 if ((params->req_line_speed == SPEED_AUTO_NEG) &&
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001892 ((ext_phy_type ==
Yaniv Rosner57963ed2008-08-13 15:55:28 -07001893 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ||
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001894 (ext_phy_type ==
Eilon Greenstein589abe32009-02-12 08:36:55 +00001895 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) ||
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001896 (ext_phy_type ==
Yaniv Rosnerb5bbf002009-11-05 19:18:21 +02001897 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706) ||
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001898 (ext_phy_type ==
Eilon Greenstein2f904462009-08-12 08:22:16 +00001899 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001900 vars->autoneg = AUTO_NEG_ENABLED;
1901
1902 if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) {
1903 vars->autoneg |= AUTO_NEG_COMPLETE;
1904 vars->link_status |=
1905 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
1906 }
1907
1908 vars->autoneg |= AUTO_NEG_PARALLEL_DETECTION_USED;
1909 vars->link_status |=
1910 LINK_STATUS_PARALLEL_DETECTION_USED;
1911
1912 }
David S. Millerc0700f92008-12-16 23:53:20 -08001913 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001914 vars->link_status |=
1915 LINK_STATUS_TX_FLOW_CONTROL_ENABLED;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001916
David S. Millerc0700f92008-12-16 23:53:20 -08001917 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001918 vars->link_status |=
1919 LINK_STATUS_RX_FLOW_CONTROL_ENABLED;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001920
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001921
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001922 } else { /* link_down */
1923 DP(NETIF_MSG_LINK, "phy link down\n");
1924
1925 vars->phy_link_up = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07001926
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001927 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08001928 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001929 vars->autoneg = AUTO_NEG_DISABLED;
1930 vars->mac_type = MAC_TYPE_NONE;
Eilon Greenstein239d6862009-08-12 08:23:04 +00001931
1932 if ((params->req_line_speed == SPEED_AUTO_NEG) &&
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001933 (SINGLE_MEDIA_DIRECT(params))) {
Eilon Greenstein239d6862009-08-12 08:23:04 +00001934 /* Check signal is detected */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001935 bnx2x_check_fallback_to_cl37(&params->phy[INT_PHY],
1936 params);
Eilon Greenstein239d6862009-08-12 08:23:04 +00001937 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001938 }
1939
Frans Pop2381a552010-03-24 07:57:36 +00001940 DP(NETIF_MSG_LINK, "gp_status 0x%x phy_link_up %x line_speed %x\n",
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001941 gp_status, vars->phy_link_up, vars->line_speed);
1942 DP(NETIF_MSG_LINK, "duplex %x flow_ctrl 0x%x"
1943 " autoneg 0x%x\n",
1944 vars->duplex,
1945 vars->flow_ctrl, vars->autoneg);
1946 DP(NETIF_MSG_LINK, "link_status 0x%x\n", vars->link_status);
1947
1948 return rc;
1949}
1950
Eilon Greensteined8680a2009-02-12 08:37:12 +00001951static void bnx2x_set_gmii_tx_driver(struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001952{
1953 struct bnx2x *bp = params->bp;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001954 struct bnx2x_phy *phy = &params->phy[INT_PHY];
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001955 u16 lp_up2;
1956 u16 tx_driver;
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00001957 u16 bank;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001958
1959 /* read precomp */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001960 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001961 MDIO_REG_BANK_OVER_1G,
1962 MDIO_OVER_1G_LP_UP2, &lp_up2);
1963
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001964 /* bits [10:7] at lp_up2, positioned at [15:12] */
1965 lp_up2 = (((lp_up2 & MDIO_OVER_1G_LP_UP2_PREEMPHASIS_MASK) >>
1966 MDIO_OVER_1G_LP_UP2_PREEMPHASIS_SHIFT) <<
1967 MDIO_TX0_TX_DRIVER_PREEMPHASIS_SHIFT);
1968
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00001969 if (lp_up2 == 0)
1970 return;
1971
1972 for (bank = MDIO_REG_BANK_TX0; bank <= MDIO_REG_BANK_TX3;
1973 bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0)) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001974 CL45_RD_OVER_CL22(bp, phy,
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00001975 bank,
1976 MDIO_TX0_TX_DRIVER, &tx_driver);
1977
1978 /* replace tx_driver bits [15:12] */
1979 if (lp_up2 !=
1980 (tx_driver & MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK)) {
1981 tx_driver &= ~MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK;
1982 tx_driver |= lp_up2;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001983 CL45_WR_OVER_CL22(bp, phy,
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00001984 bank,
1985 MDIO_TX0_TX_DRIVER, tx_driver);
1986 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001987 }
1988}
1989
1990static u8 bnx2x_emac_program(struct link_params *params,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00001991 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001992{
1993 struct bnx2x *bp = params->bp;
1994 u8 port = params->port;
1995 u16 mode = 0;
1996
1997 DP(NETIF_MSG_LINK, "setting link speed & duplex\n");
1998 bnx2x_bits_dis(bp, GRCBASE_EMAC0 + port*0x400 +
1999 EMAC_REG_EMAC_MODE,
2000 (EMAC_MODE_25G_MODE |
2001 EMAC_MODE_PORT_MII_10M |
2002 EMAC_MODE_HALF_DUPLEX));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002003 switch (vars->line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002004 case SPEED_10:
2005 mode |= EMAC_MODE_PORT_MII_10M;
2006 break;
2007
2008 case SPEED_100:
2009 mode |= EMAC_MODE_PORT_MII;
2010 break;
2011
2012 case SPEED_1000:
2013 mode |= EMAC_MODE_PORT_GMII;
2014 break;
2015
2016 case SPEED_2500:
2017 mode |= (EMAC_MODE_25G_MODE | EMAC_MODE_PORT_GMII);
2018 break;
2019
2020 default:
2021 /* 10G not valid for EMAC */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002022 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
2023 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002024 return -EINVAL;
2025 }
2026
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002027 if (vars->duplex == DUPLEX_HALF)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002028 mode |= EMAC_MODE_HALF_DUPLEX;
2029 bnx2x_bits_en(bp,
2030 GRCBASE_EMAC0 + port*0x400 + EMAC_REG_EMAC_MODE,
2031 mode);
2032
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002033 bnx2x_set_led(params, LED_MODE_OPER, vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002034 return 0;
2035}
2036
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002037static u8 bnx2x_init_serdes(struct bnx2x_phy *phy,
2038 struct link_params *params,
2039 struct link_vars *vars)
2040{
2041 u8 rc;
2042 vars->phy_flags |= PHY_SGMII_FLAG;
2043 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
2044 bnx2x_set_aer_mmd(params, phy);
2045 rc = bnx2x_reset_unicore(params, phy, 1);
2046 /* reset the SerDes and wait for reset bit return low */
2047 if (rc != 0)
2048 return rc;
2049 bnx2x_set_aer_mmd(params, phy);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002050
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002051 return rc;
2052}
2053
2054static u8 bnx2x_init_xgxs(struct bnx2x_phy *phy,
2055 struct link_params *params,
2056 struct link_vars *vars)
2057{
2058 u8 rc;
2059 vars->phy_flags = PHY_XGXS_FLAG;
2060 if ((phy->req_line_speed &&
2061 ((phy->req_line_speed == SPEED_100) ||
2062 (phy->req_line_speed == SPEED_10))) ||
2063 (!phy->req_line_speed &&
2064 (phy->speed_cap_mask >=
2065 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL) &&
2066 (phy->speed_cap_mask <
2067 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
2068 ))
2069 vars->phy_flags |= PHY_SGMII_FLAG;
2070 else
2071 vars->phy_flags &= ~PHY_SGMII_FLAG;
2072
2073 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
2074 bnx2x_set_aer_mmd(params, phy);
2075 bnx2x_set_master_ln(params, phy);
2076
2077 rc = bnx2x_reset_unicore(params, phy, 0);
2078 /* reset the SerDes and wait for reset bit return low */
2079 if (rc != 0)
2080 return rc;
2081
2082 bnx2x_set_aer_mmd(params, phy);
2083
2084 /* setting the masterLn_def again after the reset */
2085 bnx2x_set_master_ln(params, phy);
2086 bnx2x_set_swap_lanes(params, phy);
2087
2088 return rc;
2089}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002090/*****************************************************************************/
Eilon Greenstein17de50b2008-08-13 15:56:59 -07002091/* External Phy section */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002092/*****************************************************************************/
Eilon Greensteinf57a6022009-08-12 08:23:11 +00002093void bnx2x_ext_phy_hw_reset(struct bnx2x *bp, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002094{
2095 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07002096 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002097 msleep(1);
2098 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002099 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002100}
2101
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002102static void bnx2x_save_spirom_version(struct bnx2x *bp, u8 port,
2103 u32 shmem_base, u32 spirom_ver)
2104{
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002105 DP(NETIF_MSG_LINK, "FW version 0x%x:0x%x for port %d\n",
2106 (u16)(spirom_ver>>16), (u16)spirom_ver, port);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002107 REG_WR(bp, shmem_base +
2108 offsetof(struct shmem_region,
2109 port_mb[port].ext_phy_fw_version),
2110 spirom_ver);
2111}
2112
2113static void bnx2x_save_bcm_spirom_ver(struct bnx2x *bp, u8 port,
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002114 struct bnx2x_phy *phy,
2115 u32 shmem_base)
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002116{
2117 u16 fw_ver1, fw_ver2;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002118
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002119 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002120 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002121 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002122 MDIO_PMA_REG_ROM_VER2, &fw_ver2);
2123 bnx2x_save_spirom_version(bp, port, shmem_base,
2124 (u32)(fw_ver1<<16 | fw_ver2));
2125}
2126
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002127static void bnx2x_save_8481_spirom_version(struct bnx2x_phy *phy,
2128 struct link_params *params,
2129 u32 shmem_base)
Eilon Greensteinb1607af2009-08-12 08:22:54 +00002130{
2131 u16 val, fw_ver1, fw_ver2, cnt;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002132 struct bnx2x *bp = params->bp;
2133
2134 /* For the 32 bits registers in 848xx, access via MDIO2ARM interface.*/
Eilon Greensteinb1607af2009-08-12 08:22:54 +00002135 /* (1) set register 0xc200_0014(SPI_BRIDGE_CTRL_2) to 0x03000000 */
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002136 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0014);
2137 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200);
2138 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81B, 0x0000);
2139 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81C, 0x0300);
2140 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x0009);
Eilon Greensteinb1607af2009-08-12 08:22:54 +00002141
2142 for (cnt = 0; cnt < 100; cnt++) {
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002143 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val);
Eilon Greensteinb1607af2009-08-12 08:22:54 +00002144 if (val & 1)
2145 break;
2146 udelay(5);
2147 }
2148 if (cnt == 100) {
2149 DP(NETIF_MSG_LINK, "Unable to read 8481 phy fw version(1)\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002150 bnx2x_save_spirom_version(bp, params->port,
Eilon Greensteinb1607af2009-08-12 08:22:54 +00002151 shmem_base, 0);
2152 return;
2153 }
2154
2155
2156 /* 2) read register 0xc200_0000 (SPI_FW_STATUS) */
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002157 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0000);
2158 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200);
2159 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x000A);
Eilon Greensteinb1607af2009-08-12 08:22:54 +00002160 for (cnt = 0; cnt < 100; cnt++) {
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002161 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val);
Eilon Greensteinb1607af2009-08-12 08:22:54 +00002162 if (val & 1)
2163 break;
2164 udelay(5);
2165 }
2166 if (cnt == 100) {
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002167 DP(NETIF_MSG_LINK, "Unable to read 848xx phy fw version(2)\n");
2168 bnx2x_save_spirom_version(bp, params->port, 0,
2169 phy->ver_addr);
Eilon Greensteinb1607af2009-08-12 08:22:54 +00002170 return;
2171 }
2172
2173 /* lower 16 bits of the register SPI_FW_STATUS */
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002174 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81B, &fw_ver1);
Eilon Greensteinb1607af2009-08-12 08:22:54 +00002175 /* upper 16 bits of register SPI_FW_STATUS */
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002176 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81C, &fw_ver2);
Eilon Greensteinb1607af2009-08-12 08:22:54 +00002177
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002178 bnx2x_save_spirom_version(bp, params->port, (fw_ver2<<16) | fw_ver1,
2179 phy->ver_addr);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002180}
2181
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002182static u8 bnx2x_8073_is_snr_needed(struct bnx2x *bp, struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002183{
2184 /* This is only required for 8073A1, version 102 only */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002185 u16 val;
2186
2187 /* Read 8073 HW revision*/
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002188 bnx2x_cl45_read(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002189 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00002190 MDIO_PMA_REG_8073_CHIP_REV, &val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002191
2192 if (val != 1) {
2193 /* No need to workaround in 8073 A1 */
2194 return 0;
2195 }
2196
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002197 bnx2x_cl45_read(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002198 MDIO_PMA_DEVAD,
2199 MDIO_PMA_REG_ROM_VER2, &val);
2200
2201 /* SNR should be applied only for version 0x102 */
2202 if (val != 0x102)
2203 return 0;
2204
2205 return 1;
2206}
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002207static u8 bnx2x_8073_xaui_wa(struct bnx2x *bp, struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002208{
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002209 u16 val, cnt, cnt1 ;
2210
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002211 bnx2x_cl45_read(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002212 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00002213 MDIO_PMA_REG_8073_CHIP_REV, &val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002214
2215 if (val > 0) {
2216 /* No need to workaround in 8073 A1 */
2217 return 0;
2218 }
2219 /* XAUI workaround in 8073 A0: */
2220
2221 /* After loading the boot ROM and restarting Autoneg,
2222 poll Dev1, Reg $C820: */
2223
2224 for (cnt = 0; cnt < 1000; cnt++) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002225 bnx2x_cl45_read(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002226 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00002227 MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
2228 &val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002229 /* If bit [14] = 0 or bit [13] = 0, continue on with
2230 system initialization (XAUI work-around not required,
2231 as these bits indicate 2.5G or 1G link up). */
2232 if (!(val & (1<<14)) || !(val & (1<<13))) {
2233 DP(NETIF_MSG_LINK, "XAUI work-around not required\n");
2234 return 0;
2235 } else if (!(val & (1<<15))) {
2236 DP(NETIF_MSG_LINK, "clc bit 15 went off\n");
2237 /* If bit 15 is 0, then poll Dev1, Reg $C841 until
2238 it's MSB (bit 15) goes to 1 (indicating that the
2239 XAUI workaround has completed),
2240 then continue on with system initialization.*/
2241 for (cnt1 = 0; cnt1 < 1000; cnt1++) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002242 bnx2x_cl45_read(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002243 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00002244 MDIO_PMA_REG_8073_XAUI_WA, &val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002245 if (val & (1<<15)) {
2246 DP(NETIF_MSG_LINK,
2247 "XAUI workaround has completed\n");
2248 return 0;
2249 }
2250 msleep(3);
2251 }
2252 break;
2253 }
2254 msleep(3);
2255 }
2256 DP(NETIF_MSG_LINK, "Warning: XAUI work-around timeout !!!\n");
2257 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002258}
2259
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002260static void bnx2x_8073_8727_external_rom_boot(struct bnx2x *bp,
2261 struct bnx2x_phy *phy,
2262 u8 port, u32 shmem_base)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002263{
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002264 /* Boot port from external ROM */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002265 /* EDC grst */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002266 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002267 MDIO_PMA_DEVAD,
2268 MDIO_PMA_REG_GEN_CTRL,
2269 0x0001);
2270
2271 /* ucode reboot and rst */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002272 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002273 MDIO_PMA_DEVAD,
2274 MDIO_PMA_REG_GEN_CTRL,
2275 0x008c);
2276
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002277 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002278 MDIO_PMA_DEVAD,
2279 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
2280
2281 /* Reset internal microprocessor */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002282 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002283 MDIO_PMA_DEVAD,
2284 MDIO_PMA_REG_GEN_CTRL,
2285 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
2286
2287 /* Release srst 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_GEN_CTRL,
2291 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2292
Yaniv Rosner8ca60a62010-09-01 09:51:17 +00002293 /* wait for 120ms for code download via SPI port */
2294 msleep(120);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002295
2296 /* Clear ser_boot_ctl bit */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002297 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002298 MDIO_PMA_DEVAD,
2299 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002300 bnx2x_save_bcm_spirom_ver(bp, port, phy, shmem_base);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002301}
2302
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002303static void bnx2x_8726_external_rom_boot(struct bnx2x_phy *phy,
2304 struct link_params *params)
Eilon Greenstein589abe32009-02-12 08:36:55 +00002305{
2306 struct bnx2x *bp = params->bp;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002307 /* Need to wait 100ms after reset */
2308 msleep(100);
2309
Eilon Greenstein589abe32009-02-12 08:36:55 +00002310 /* Micro controller re-boot */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002311 bnx2x_cl45_write(bp, phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002312 MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, 0x018B);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002313
2314 /* Set soft reset */
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_MICRO_RESET);
2319
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002320 bnx2x_cl45_write(bp, phy,
Eilon Greensteincc1cb002009-03-02 08:00:03 +00002321 MDIO_PMA_DEVAD,
Yaniv Rosner93f72882009-11-05 19:18:26 +02002322 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
Eilon Greensteincc1cb002009-03-02 08:00:03 +00002323
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_GEN_CTRL,
2327 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2328
Eilon Greensteincc1cb002009-03-02 08:00:03 +00002329 /* wait for 150ms for microcode load */
2330 msleep(150);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002331
2332 /* Disable serial boot control, tristates pins SS_N, SCK, MOSI, MISO */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002333 bnx2x_cl45_write(bp, phy,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002334 MDIO_PMA_DEVAD,
2335 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
2336
2337 msleep(200);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002338 bnx2x_save_bcm_spirom_ver(bp, params->port,
2339 phy,
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002340 params->shmem_base);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002341}
2342
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002343static void bnx2x_sfp_set_transmitter(struct bnx2x *bp,
2344 struct bnx2x_phy *phy,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002345 u8 port,
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002346 u8 tx_en)
Eilon Greenstein589abe32009-02-12 08:36:55 +00002347{
2348 u16 val;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002349
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002350 DP(NETIF_MSG_LINK, "Setting transmitter tx_en=%x for port %x\n",
2351 tx_en, port);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002352 /* Disable/Enable transmitter ( TX laser of the SFP+ module.)*/
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002353 bnx2x_cl45_read(bp, phy,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002354 MDIO_PMA_DEVAD,
2355 MDIO_PMA_REG_PHY_IDENTIFIER,
2356 &val);
2357
2358 if (tx_en)
2359 val &= ~(1<<15);
2360 else
2361 val |= (1<<15);
2362
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002363 bnx2x_cl45_write(bp, phy,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002364 MDIO_PMA_DEVAD,
2365 MDIO_PMA_REG_PHY_IDENTIFIER,
2366 val);
2367}
2368
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002369static u8 bnx2x_8726_read_sfp_module_eeprom(struct bnx2x_phy *phy,
2370 struct link_params *params,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002371 u16 addr, u8 byte_cnt, u8 *o_buf)
2372{
Eilon Greenstein589abe32009-02-12 08:36:55 +00002373 struct bnx2x *bp = params->bp;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002374 u16 val = 0;
2375 u16 i;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002376 if (byte_cnt > 16) {
2377 DP(NETIF_MSG_LINK, "Reading from eeprom is"
2378 " is limited to 0xf\n");
2379 return -EINVAL;
2380 }
2381 /* Set the read command byte count */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002382 bnx2x_cl45_write(bp, phy,
2383 MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002384 (byte_cnt | 0xa000));
2385
2386 /* Set the read command address */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002387 bnx2x_cl45_write(bp, phy,
2388 MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002389 addr);
2390
2391 /* Activate read command */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002392 bnx2x_cl45_write(bp, phy,
2393 MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002394 0x2c0f);
2395
2396 /* Wait up to 500us for command complete status */
2397 for (i = 0; i < 100; i++) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002398 bnx2x_cl45_read(bp, phy,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002399 MDIO_PMA_DEVAD,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002400 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
2401 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
2402 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
Eilon Greenstein589abe32009-02-12 08:36:55 +00002403 break;
2404 udelay(5);
2405 }
2406
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002407 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
2408 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
Eilon Greenstein589abe32009-02-12 08:36:55 +00002409 DP(NETIF_MSG_LINK,
2410 "Got bad status 0x%x when reading from SFP+ EEPROM\n",
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002411 (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
Eilon Greenstein589abe32009-02-12 08:36:55 +00002412 return -EINVAL;
2413 }
2414
2415 /* Read the buffer */
2416 for (i = 0; i < byte_cnt; i++) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002417 bnx2x_cl45_read(bp, phy,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002418 MDIO_PMA_DEVAD,
2419 MDIO_PMA_REG_8726_TWO_WIRE_DATA_BUF + i, &val);
2420 o_buf[i] = (u8)(val & MDIO_PMA_REG_8726_TWO_WIRE_DATA_MASK);
2421 }
2422
2423 for (i = 0; i < 100; i++) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002424 bnx2x_cl45_read(bp, phy,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002425 MDIO_PMA_DEVAD,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002426 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
2427 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
2428 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002429 return 0;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002430 msleep(1);
2431 }
2432 return -EINVAL;
2433}
2434
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002435static u8 bnx2x_8727_read_sfp_module_eeprom(struct bnx2x_phy *phy,
2436 struct link_params *params,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002437 u16 addr, u8 byte_cnt, u8 *o_buf)
Eilon Greenstein589abe32009-02-12 08:36:55 +00002438{
2439 struct bnx2x *bp = params->bp;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002440 u16 val, i;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002441
2442 if (byte_cnt > 16) {
2443 DP(NETIF_MSG_LINK, "Reading from eeprom is"
2444 " is limited to 0xf\n");
2445 return -EINVAL;
2446 }
2447
2448 /* Need to read from 1.8000 to clear it */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002449 bnx2x_cl45_read(bp, phy,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002450 MDIO_PMA_DEVAD,
2451 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
2452 &val);
2453
2454 /* Set the read command byte count */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002455 bnx2x_cl45_write(bp, phy,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002456 MDIO_PMA_DEVAD,
2457 MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
2458 ((byte_cnt < 2) ? 2 : byte_cnt));
2459
2460 /* Set the read command address */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002461 bnx2x_cl45_write(bp, phy,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002462 MDIO_PMA_DEVAD,
2463 MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
2464 addr);
2465 /* Set the destination address */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002466 bnx2x_cl45_write(bp, phy,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002467 MDIO_PMA_DEVAD,
2468 0x8004,
2469 MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF);
2470
2471 /* Activate read command */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002472 bnx2x_cl45_write(bp, phy,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002473 MDIO_PMA_DEVAD,
2474 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
2475 0x8002);
2476 /* Wait appropriate time for two-wire command to finish before
2477 polling the status register */
2478 msleep(1);
2479
2480 /* Wait up to 500us for command complete status */
2481 for (i = 0; i < 100; i++) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002482 bnx2x_cl45_read(bp, phy,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002483 MDIO_PMA_DEVAD,
2484 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
2485 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
2486 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
2487 break;
2488 udelay(5);
2489 }
2490
2491 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
2492 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
2493 DP(NETIF_MSG_LINK,
2494 "Got bad status 0x%x when reading from SFP+ EEPROM\n",
2495 (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
2496 return -EINVAL;
2497 }
2498
2499 /* Read the buffer */
2500 for (i = 0; i < byte_cnt; i++) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002501 bnx2x_cl45_read(bp, phy,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002502 MDIO_PMA_DEVAD,
2503 MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF + i, &val);
2504 o_buf[i] = (u8)(val & MDIO_PMA_REG_8727_TWO_WIRE_DATA_MASK);
2505 }
2506
2507 for (i = 0; i < 100; i++) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002508 bnx2x_cl45_read(bp, phy,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002509 MDIO_PMA_DEVAD,
2510 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
2511 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
2512 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
2513 return 0;;
2514 msleep(1);
2515 }
2516
2517 return -EINVAL;
2518}
2519
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002520u8 bnx2x_read_sfp_module_eeprom(struct bnx2x_phy *phy,
2521 struct link_params *params, u16 addr,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002522 u8 byte_cnt, u8 *o_buf)
2523{
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002524 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
2525 return bnx2x_8726_read_sfp_module_eeprom(phy, params, addr,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002526 byte_cnt, o_buf);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002527 else if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
2528 return bnx2x_8727_read_sfp_module_eeprom(phy, params, addr,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002529 byte_cnt, o_buf);
2530 return -EINVAL;
2531}
2532
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002533static u8 bnx2x_get_edc_mode(struct bnx2x_phy *phy,
2534 struct link_params *params,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002535 u16 *edc_mode)
2536{
2537 struct bnx2x *bp = params->bp;
2538 u8 val, check_limiting_mode = 0;
2539 *edc_mode = EDC_MODE_LIMITING;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002540
2541 /* First check for copper cable */
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002542 if (bnx2x_read_sfp_module_eeprom(phy,
2543 params,
2544 SFP_EEPROM_CON_TYPE_ADDR,
2545 1,
2546 &val) != 0) {
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002547 DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM\n");
Eilon Greenstein589abe32009-02-12 08:36:55 +00002548 return -EINVAL;
2549 }
2550
2551 switch (val) {
2552 case SFP_EEPROM_CON_TYPE_VAL_COPPER:
2553 {
2554 u8 copper_module_type;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002555
Eilon Greenstein589abe32009-02-12 08:36:55 +00002556 /* Check if its active cable( includes SFP+ module)
2557 of passive cable*/
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002558 if (bnx2x_read_sfp_module_eeprom(phy,
2559 params,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002560 SFP_EEPROM_FC_TX_TECH_ADDR,
2561 1,
2562 &copper_module_type) !=
2563 0) {
2564 DP(NETIF_MSG_LINK,
2565 "Failed to read copper-cable-type"
2566 " from SFP+ EEPROM\n");
2567 return -EINVAL;
2568 }
2569
2570 if (copper_module_type &
2571 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE) {
2572 DP(NETIF_MSG_LINK, "Active Copper cable detected\n");
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002573 check_limiting_mode = 1;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002574 } else if (copper_module_type &
2575 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE) {
2576 DP(NETIF_MSG_LINK, "Passive Copper"
2577 " cable detected\n");
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002578 *edc_mode =
2579 EDC_MODE_PASSIVE_DAC;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002580 } else {
2581 DP(NETIF_MSG_LINK, "Unknown copper-cable-"
2582 "type 0x%x !!!\n", copper_module_type);
2583 return -EINVAL;
2584 }
2585 break;
2586 }
2587 case SFP_EEPROM_CON_TYPE_VAL_LC:
2588 DP(NETIF_MSG_LINK, "Optic module detected\n");
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002589 check_limiting_mode = 1;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002590 break;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002591 default:
2592 DP(NETIF_MSG_LINK, "Unable to determine module type 0x%x !!!\n",
2593 val);
2594 return -EINVAL;
2595 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002596
2597 if (check_limiting_mode) {
2598 u8 options[SFP_EEPROM_OPTIONS_SIZE];
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002599 if (bnx2x_read_sfp_module_eeprom(phy,
2600 params,
2601 SFP_EEPROM_OPTIONS_ADDR,
2602 SFP_EEPROM_OPTIONS_SIZE,
2603 options) != 0) {
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002604 DP(NETIF_MSG_LINK, "Failed to read Option"
2605 " field from module EEPROM\n");
2606 return -EINVAL;
2607 }
2608 if ((options[0] & SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK))
2609 *edc_mode = EDC_MODE_LINEAR;
2610 else
2611 *edc_mode = EDC_MODE_LIMITING;
2612 }
2613 DP(NETIF_MSG_LINK, "EDC mode is set to 0x%x\n", *edc_mode);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002614 return 0;
2615}
Eilon Greenstein589abe32009-02-12 08:36:55 +00002616/* This function read the relevant field from the module ( SFP+ ),
2617 and verify it is compliant with this board */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002618static u8 bnx2x_verify_sfp_module(struct bnx2x_phy *phy,
2619 struct link_params *params)
Eilon Greenstein589abe32009-02-12 08:36:55 +00002620{
2621 struct bnx2x *bp = params->bp;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002622 u32 val;
2623 u32 fw_resp;
2624 char vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE+1];
2625 char vendor_pn[SFP_EEPROM_PART_NO_SIZE+1];
Eilon Greenstein589abe32009-02-12 08:36:55 +00002626
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002627 val = REG_RD(bp, params->shmem_base +
2628 offsetof(struct shmem_region, dev_info.
2629 port_feature_config[params->port].config));
2630 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
2631 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_NO_ENFORCEMENT) {
Eilon Greenstein589abe32009-02-12 08:36:55 +00002632 DP(NETIF_MSG_LINK, "NOT enforcing module verification\n");
2633 return 0;
2634 }
2635
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002636 /* Ask the FW to validate the module */
2637 if (!(params->feature_config_flags &
2638 FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY)) {
2639 DP(NETIF_MSG_LINK, "FW does not support OPT MDL "
2640 "verification\n");
2641 return -EINVAL;
2642 }
2643
2644 fw_resp = bnx2x_fw_command(bp, DRV_MSG_CODE_VRFY_OPT_MDL);
2645 if (fw_resp == FW_MSG_CODE_VRFY_OPT_MDL_SUCCESS) {
2646 DP(NETIF_MSG_LINK, "Approved module\n");
Eilon Greenstein589abe32009-02-12 08:36:55 +00002647 return 0;
2648 }
2649
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002650 /* format the warning message */
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002651 if (bnx2x_read_sfp_module_eeprom(phy,
2652 params,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002653 SFP_EEPROM_VENDOR_NAME_ADDR,
2654 SFP_EEPROM_VENDOR_NAME_SIZE,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002655 (u8 *)vendor_name))
2656 vendor_name[0] = '\0';
2657 else
2658 vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE] = '\0';
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002659 if (bnx2x_read_sfp_module_eeprom(phy,
2660 params,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002661 SFP_EEPROM_PART_NO_ADDR,
2662 SFP_EEPROM_PART_NO_SIZE,
2663 (u8 *)vendor_pn))
2664 vendor_pn[0] = '\0';
2665 else
2666 vendor_pn[SFP_EEPROM_PART_NO_SIZE] = '\0';
Eilon Greenstein589abe32009-02-12 08:36:55 +00002667
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002668 netdev_info(bp->dev, "Warning: Unqualified SFP+ module detected,"
2669 " Port %d from %s part number %s\n",
Joe Perches7995c642010-02-17 15:01:52 +00002670 params->port, vendor_name, vendor_pn);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002671 return -EINVAL;
2672}
2673
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002674static u8 bnx2x_8726_set_limiting_mode(struct bnx2x *bp,
2675 struct bnx2x_phy *phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002676 u16 edc_mode)
Eilon Greenstein589abe32009-02-12 08:36:55 +00002677{
Eilon Greensteincc1cb002009-03-02 08:00:03 +00002678 u16 cur_limiting_mode;
Eilon Greensteincc1cb002009-03-02 08:00:03 +00002679
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002680 bnx2x_cl45_read(bp, phy,
Eilon Greensteincc1cb002009-03-02 08:00:03 +00002681 MDIO_PMA_DEVAD,
2682 MDIO_PMA_REG_ROM_VER2,
2683 &cur_limiting_mode);
2684 DP(NETIF_MSG_LINK, "Current Limiting mode is 0x%x\n",
2685 cur_limiting_mode);
2686
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002687 if (edc_mode == EDC_MODE_LIMITING) {
Eilon Greenstein589abe32009-02-12 08:36:55 +00002688 DP(NETIF_MSG_LINK,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002689 "Setting LIMITING MODE\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002690 bnx2x_cl45_write(bp, phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002691 MDIO_PMA_DEVAD,
2692 MDIO_PMA_REG_ROM_VER2,
2693 EDC_MODE_LIMITING);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002694 } else { /* LRM mode ( default )*/
Eilon Greensteincc1cb002009-03-02 08:00:03 +00002695
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002696 DP(NETIF_MSG_LINK, "Setting LRM MODE\n");
Eilon Greenstein589abe32009-02-12 08:36:55 +00002697
Eilon Greenstein589abe32009-02-12 08:36:55 +00002698 /* Changing to LRM mode takes quite few seconds.
2699 So do it only if current mode is limiting
2700 ( default is LRM )*/
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002701 if (cur_limiting_mode != EDC_MODE_LIMITING)
Eilon Greenstein589abe32009-02-12 08:36:55 +00002702 return 0;
2703
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002704 bnx2x_cl45_write(bp, phy,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002705 MDIO_PMA_DEVAD,
2706 MDIO_PMA_REG_LRM_MODE,
2707 0);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002708 bnx2x_cl45_write(bp, phy,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002709 MDIO_PMA_DEVAD,
2710 MDIO_PMA_REG_ROM_VER2,
2711 0x128);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002712 bnx2x_cl45_write(bp, phy,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002713 MDIO_PMA_DEVAD,
2714 MDIO_PMA_REG_MISC_CTRL0,
2715 0x4008);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002716 bnx2x_cl45_write(bp, phy,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002717 MDIO_PMA_DEVAD,
2718 MDIO_PMA_REG_LRM_MODE,
2719 0xaaaa);
2720 }
2721 return 0;
2722}
2723
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002724static u8 bnx2x_8727_set_limiting_mode(struct bnx2x *bp,
2725 struct bnx2x_phy *phy,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002726 u16 edc_mode)
2727{
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002728 u16 phy_identifier;
2729 u16 rom_ver2_val;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002730 bnx2x_cl45_read(bp, phy,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002731 MDIO_PMA_DEVAD,
2732 MDIO_PMA_REG_PHY_IDENTIFIER,
2733 &phy_identifier);
2734
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002735 bnx2x_cl45_write(bp, phy,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002736 MDIO_PMA_DEVAD,
2737 MDIO_PMA_REG_PHY_IDENTIFIER,
2738 (phy_identifier & ~(1<<9)));
2739
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002740 bnx2x_cl45_read(bp, phy,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002741 MDIO_PMA_DEVAD,
2742 MDIO_PMA_REG_ROM_VER2,
2743 &rom_ver2_val);
2744 /* Keep the MSB 8-bits, and set the LSB 8-bits with the edc_mode */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002745 bnx2x_cl45_write(bp, phy,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002746 MDIO_PMA_DEVAD,
2747 MDIO_PMA_REG_ROM_VER2,
2748 (rom_ver2_val & 0xff00) | (edc_mode & 0x00ff));
2749
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002750 bnx2x_cl45_write(bp, phy,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002751 MDIO_PMA_DEVAD,
2752 MDIO_PMA_REG_PHY_IDENTIFIER,
2753 (phy_identifier | (1<<9)));
2754
2755 return 0;
2756}
2757
2758
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002759static u8 bnx2x_wait_for_sfp_module_initialized(struct bnx2x_phy *phy,
2760 struct link_params *params)
2761
Eilon Greenstein589abe32009-02-12 08:36:55 +00002762{
2763 u8 val;
2764 struct bnx2x *bp = params->bp;
2765 u16 timeout;
2766 /* Initialization time after hot-plug may take up to 300ms for some
2767 phys type ( e.g. JDSU ) */
2768 for (timeout = 0; timeout < 60; timeout++) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002769 if (bnx2x_read_sfp_module_eeprom(phy, params, 1, 1, &val)
Eilon Greenstein589abe32009-02-12 08:36:55 +00002770 == 0) {
2771 DP(NETIF_MSG_LINK, "SFP+ module initialization "
2772 "took %d ms\n", timeout * 5);
2773 return 0;
2774 }
2775 msleep(5);
2776 }
2777 return -EINVAL;
2778}
2779
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002780static void bnx2x_8727_power_module(struct bnx2x *bp,
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002781 struct bnx2x_phy *phy,
2782 u8 is_power_up) {
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002783 /* Make sure GPIOs are not using for LED mode */
2784 u16 val;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002785 /*
2786 * In the GPIO register, bit 4 is use to detemine if the GPIOs are
2787 * operating as INPUT or as OUTPUT. Bit 1 is for input, and 0 for
2788 * output
2789 * Bits 0-1 determine the gpios value for OUTPUT in case bit 4 val is 0
2790 * Bits 8-9 determine the gpios value for INPUT in case bit 4 val is 1
2791 * where the 1st bit is the over-current(only input), and 2nd bit is
2792 * for power( only output )
2793 */
2794
2795 /*
2796 * In case of NOC feature is disabled and power is up, set GPIO control
2797 * as input to enable listening of over-current indication
2798 */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002799 if (phy->flags & FLAGS_NOC)
2800 return;
2801 if (!(phy->flags &
2802 FLAGS_NOC) && is_power_up)
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002803 val = (1<<4);
2804 else
2805 /*
2806 * Set GPIO control to OUTPUT, and set the power bit
2807 * to according to the is_power_up
2808 */
2809 val = ((!(is_power_up)) << 1);
2810
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002811 bnx2x_cl45_write(bp, phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002812 MDIO_PMA_DEVAD,
2813 MDIO_PMA_REG_8727_GPIO_CTRL,
2814 val);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002815}
2816
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002817static u8 bnx2x_sfp_module_detection(struct bnx2x_phy *phy,
2818 struct link_params *params)
Eilon Greenstein589abe32009-02-12 08:36:55 +00002819{
2820 struct bnx2x *bp = params->bp;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002821 u16 edc_mode;
2822 u8 rc = 0;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002823
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002824 u32 val = REG_RD(bp, params->shmem_base +
2825 offsetof(struct shmem_region, dev_info.
2826 port_feature_config[params->port].config));
Eilon Greenstein589abe32009-02-12 08:36:55 +00002827
2828 DP(NETIF_MSG_LINK, "SFP+ module plugged in/out detected on port %d\n",
2829 params->port);
2830
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002831 if (bnx2x_get_edc_mode(phy, params, &edc_mode) != 0) {
Eilon Greenstein589abe32009-02-12 08:36:55 +00002832 DP(NETIF_MSG_LINK, "Failed to get valid module type\n");
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002833 return -EINVAL;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002834 } else if (bnx2x_verify_sfp_module(phy, params) !=
Eilon Greenstein589abe32009-02-12 08:36:55 +00002835 0) {
2836 /* check SFP+ module compatibility */
2837 DP(NETIF_MSG_LINK, "Module verification failed!!\n");
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002838 rc = -EINVAL;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002839 /* Turn on fault module-detected led */
2840 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
2841 MISC_REGISTERS_GPIO_HIGH,
2842 params->port);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002843 if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) &&
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002844 ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
2845 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_POWER_DOWN)) {
2846 /* Shutdown SFP+ module */
2847 DP(NETIF_MSG_LINK, "Shutdown SFP+ module!!\n");
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002848 bnx2x_8727_power_module(bp, phy, 0);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002849 return rc;
2850 }
2851 } else {
2852 /* Turn off fault module-detected led */
2853 DP(NETIF_MSG_LINK, "Turn off fault module-detected led\n");
2854 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
2855 MISC_REGISTERS_GPIO_LOW,
2856 params->port);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002857 }
2858
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002859 /* power up the SFP module */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002860 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002861 bnx2x_8727_power_module(bp, phy, 1);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002862
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002863 /* Check and set limiting mode / LRM mode on 8726.
2864 On 8727 it is done automatically */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002865 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
2866 bnx2x_8726_set_limiting_mode(bp, phy, edc_mode);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002867 else
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002868 bnx2x_8727_set_limiting_mode(bp, phy, edc_mode);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002869 /*
2870 * Enable transmit for this module if the module is approved, or
2871 * if unapproved modules should also enable the Tx laser
2872 */
2873 if (rc == 0 ||
2874 (val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) !=
2875 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002876 bnx2x_sfp_set_transmitter(bp, phy, params->port, 1);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002877 else
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002878 bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002879
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002880 return rc;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002881}
2882
2883void bnx2x_handle_module_detect_int(struct link_params *params)
2884{
2885 struct bnx2x *bp = params->bp;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002886 struct bnx2x_phy *phy = &params->phy[EXT_PHY1];
Eilon Greenstein589abe32009-02-12 08:36:55 +00002887 u32 gpio_val;
2888 u8 port = params->port;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002889
Eilon Greenstein589abe32009-02-12 08:36:55 +00002890 /* Set valid module led off */
2891 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
2892 MISC_REGISTERS_GPIO_HIGH,
2893 params->port);
2894
2895 /* Get current gpio val refelecting module plugged in / out*/
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002896 gpio_val = bnx2x_get_gpio(bp, MISC_REGISTERS_GPIO_3, port);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002897
2898 /* Call the handling function in case module is detected */
2899 if (gpio_val == 0) {
2900
2901 bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002902 MISC_REGISTERS_GPIO_INT_OUTPUT_CLR,
2903 port);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002904
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002905 if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0)
2906 bnx2x_sfp_module_detection(phy, params);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002907 else
2908 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
2909 } else {
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002910 u32 val = REG_RD(bp, params->shmem_base +
2911 offsetof(struct shmem_region, dev_info.
2912 port_feature_config[params->port].
2913 config));
2914
Eilon Greenstein589abe32009-02-12 08:36:55 +00002915 bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002916 MISC_REGISTERS_GPIO_INT_OUTPUT_SET,
2917 port);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002918 /* Module was plugged out. */
2919 /* Disable transmit for this module */
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002920 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
2921 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002922 bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002923 }
2924}
2925
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002926static void bnx2x_807x_force_10G(struct bnx2x *bp, struct bnx2x_phy *phy)
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002927{
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002928 /* Force KR or KX */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002929 bnx2x_cl45_write(bp, phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002930 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x2040);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002931 bnx2x_cl45_write(bp, phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002932 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0x000b);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002933 bnx2x_cl45_write(bp, phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002934 MDIO_PMA_DEVAD, MDIO_PMA_REG_BCM_CTRL, 0x0000);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002935 bnx2x_cl45_write(bp, phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002936 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x0000);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002937}
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002938
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002939static void bnx2x_8073_set_xaui_low_power_mode(struct bnx2x *bp,
2940 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002941{
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002942 u16 val;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002943 bnx2x_cl45_read(bp, phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002944 MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_CHIP_REV, &val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002945
2946 if (val == 0) {
2947 /* Mustn't set low power mode in 8073 A0 */
2948 return;
2949 }
2950
2951 /* Disable PLL sequencer (use read-modify-write to clear bit 13) */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002952 bnx2x_cl45_read(bp, phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002953 MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, &val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002954 val &= ~(1<<13);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002955 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002956 MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
2957
2958 /* PLL controls */
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002959 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805E, 0x1077);
2960 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805D, 0x0000);
2961 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805C, 0x030B);
2962 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805B, 0x1240);
2963 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805A, 0x2490);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002964
2965 /* Tx Controls */
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002966 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80A7, 0x0C74);
2967 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80A6, 0x9041);
2968 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80A5, 0x4640);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002969
2970 /* Rx Controls */
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002971 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80FE, 0x01C4);
2972 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80FD, 0x9249);
2973 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80FC, 0x2015);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002974
2975 /* Enable PLL sequencer (use read-modify-write to set bit 13) */
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002976 bnx2x_cl45_read(bp, phy, MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, &val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002977 val |= (1<<13);
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002978 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002979}
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002980
2981static void bnx2x_8073_set_pause_cl37(struct link_params *params,
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002982 struct bnx2x_phy *phy,
2983 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002984{
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002985 u16 cl37_val;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002986 struct bnx2x *bp = params->bp;
2987 bnx2x_cl45_read(bp, phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002988 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, &cl37_val);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002989
2990 cl37_val &= ~MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
2991 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002992 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002993 if ((vars->ieee_fc &
2994 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) ==
2995 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) {
2996 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC;
2997 }
2998 if ((vars->ieee_fc &
2999 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
3000 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
3001 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
3002 }
3003 if ((vars->ieee_fc &
3004 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
3005 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
3006 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
3007 }
3008 DP(NETIF_MSG_LINK,
3009 "Ext phy AN advertize cl37 0x%x\n", cl37_val);
3010
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003011 bnx2x_cl45_write(bp, phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003012 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, cl37_val);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003013 msleep(500);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003014}
3015
3016static void bnx2x_ext_phy_set_pause(struct link_params *params,
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003017 struct bnx2x_phy *phy,
3018 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003019{
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003020 u16 val;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003021 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003022 /* read modify write pause advertizing */
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003023 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV_PAUSE, &val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003024
3025 val &= ~MDIO_AN_REG_ADV_PAUSE_BOTH;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003026
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003027 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
3028
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003029 if ((vars->ieee_fc &
3030 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003031 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
3032 val |= MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC;
3033 }
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003034 if ((vars->ieee_fc &
3035 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003036 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003037 val |= MDIO_AN_REG_ADV_PAUSE_PAUSE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003038 }
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003039 DP(NETIF_MSG_LINK, "Ext phy AN advertize 0x%x\n", val);
3040 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV_PAUSE, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003041}
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003042
3043static void bnx2x_set_preemphasis(struct bnx2x_phy *phy,
3044 struct link_params *params)
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00003045{
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003046
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00003047 u16 bank, i = 0;
3048 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003049
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00003050 for (bank = MDIO_REG_BANK_RX0, i = 0; bank <= MDIO_REG_BANK_RX3;
3051 bank += (MDIO_REG_BANK_RX1-MDIO_REG_BANK_RX0), i++) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003052 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003053 bank,
3054 MDIO_RX0_RX_EQ_BOOST,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003055 phy->rx_preemphasis[i]);
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00003056 }
3057
3058 for (bank = MDIO_REG_BANK_TX0, i = 0; bank <= MDIO_REG_BANK_TX3;
3059 bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0), i++) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003060 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003061 bank,
3062 MDIO_TX0_TX_DRIVER,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003063 phy->tx_preemphasis[i]);
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00003064 }
3065}
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003066
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003067static void bnx2x_8481_set_led(struct bnx2x *bp,
3068 struct bnx2x_phy *phy)
Eilon Greenstein2f904462009-08-12 08:22:16 +00003069{
Yaniv Rosnera1e4be32010-09-01 09:51:33 +00003070 u16 val;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003071
3072 /* PHYC_CTL_LED_CTL */
3073 bnx2x_cl45_read(bp, phy,
Yaniv Rosnera1e4be32010-09-01 09:51:33 +00003074 MDIO_PMA_DEVAD,
3075 MDIO_PMA_REG_8481_LINK_SIGNAL, &val);
3076 val &= 0xFE00;
3077 val |= 0x0092;
Eilon Greenstein2f904462009-08-12 08:22:16 +00003078
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_LINK_SIGNAL, val);
Eilon Greenstein2f904462009-08-12 08:22:16 +00003082
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003083 bnx2x_cl45_write(bp, phy,
Yaniv Rosnera1e4be32010-09-01 09:51:33 +00003084 MDIO_PMA_DEVAD,
3085 MDIO_PMA_REG_8481_LED1_MASK,
3086 0x80);
3087
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003088 bnx2x_cl45_write(bp, phy,
Yaniv Rosnera1e4be32010-09-01 09:51:33 +00003089 MDIO_PMA_DEVAD,
3090 MDIO_PMA_REG_8481_LED2_MASK,
3091 0x18);
3092
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003093 bnx2x_cl45_write(bp, phy,
Yaniv Rosnera1e4be32010-09-01 09:51:33 +00003094 MDIO_PMA_DEVAD,
3095 MDIO_PMA_REG_8481_LED3_MASK,
3096 0x0040);
3097
Eilon Greenstein2f904462009-08-12 08:22:16 +00003098 /* 'Interrupt Mask' */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003099 bnx2x_cl45_write(bp, phy,
Yaniv Rosnera1e4be32010-09-01 09:51:33 +00003100 MDIO_AN_DEVAD,
3101 0xFFFB, 0xFFFD);
Eilon Greenstein2f904462009-08-12 08:22:16 +00003102}
Eilon Greenstein2f904462009-08-12 08:22:16 +00003103
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003104static void bnx2x_init_internal_phy(struct bnx2x_phy *phy,
3105 struct link_params *params,
3106 struct link_vars *vars)
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003107{
3108 struct bnx2x *bp = params->bp;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003109 u8 enable_cl73 = (SINGLE_MEDIA_DIRECT(params) ||
3110 (params->loopback_mode == LOOPBACK_XGXS_10));
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003111 if (!(vars->phy_flags & PHY_SGMII_FLAG)) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003112 if (SINGLE_MEDIA_DIRECT(params) &&
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00003113 (params->feature_config_flags &
3114 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED))
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003115 bnx2x_set_preemphasis(phy, params);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003116
3117 /* forced speed requested? */
Yaniv Rosner7846e472009-11-05 19:18:07 +02003118 if (vars->line_speed != SPEED_AUTO_NEG ||
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003119 (SINGLE_MEDIA_DIRECT(params) &&
Yaniv Rosner7846e472009-11-05 19:18:07 +02003120 params->loopback_mode == LOOPBACK_EXT)) {
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003121 DP(NETIF_MSG_LINK, "not SGMII, no AN\n");
3122
3123 /* disable autoneg */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003124 bnx2x_set_autoneg(phy, params, vars, 0);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003125
3126 /* program speed and duplex */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003127 bnx2x_program_serdes(phy, params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003128
3129 } else { /* AN_mode */
3130 DP(NETIF_MSG_LINK, "not SGMII, AN\n");
3131
3132 /* AN enabled */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003133 bnx2x_set_brcm_cl37_advertisment(phy, params);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003134
3135 /* program duplex & pause advertisement (for aneg) */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003136 bnx2x_set_ieee_aneg_advertisment(phy, params,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003137 vars->ieee_fc);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003138
3139 /* enable autoneg */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003140 bnx2x_set_autoneg(phy, params, vars, enable_cl73);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003141
3142 /* enable and restart AN */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003143 bnx2x_restart_autoneg(phy, params, enable_cl73);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003144 }
3145
3146 } else { /* SGMII mode */
3147 DP(NETIF_MSG_LINK, "SGMII\n");
3148
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003149 bnx2x_initialize_sgmii_process(phy, params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003150 }
3151}
3152
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003153static u16 bnx2x_wait_reset_complete(struct bnx2x *bp,
3154 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003155{
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003156 u16 cnt, ctrl;
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003157 /* Wait for soft reset to get cleared upto 1 sec */
3158 for (cnt = 0; cnt < 1000; cnt++) {
3159 bnx2x_cl45_read(bp, phy,
3160 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, &ctrl);
3161 if (!(ctrl & (1<<15)))
3162 break;
3163 msleep(1);
3164 }
3165 DP(NETIF_MSG_LINK, "control reg 0x%x (after %d ms)\n", ctrl, cnt);
3166 return cnt;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003167}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003168
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003169static u8 bnx2x_8705_config_init(struct bnx2x_phy *phy,
3170 struct link_params *params,
3171 struct link_vars *vars)
3172{
3173 struct bnx2x *bp = params->bp;
3174 DP(NETIF_MSG_LINK, "init 8705\n");
3175 /* Restore normal power mode*/
3176 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
3177 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
3178 /* HW reset */
3179 bnx2x_ext_phy_hw_reset(bp, params->port);
3180 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0xa040);
3181 bnx2x_wait_reset_complete(bp, phy);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003182
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003183 bnx2x_cl45_write(bp, phy,
3184 MDIO_PMA_DEVAD, MDIO_PMA_REG_MISC_CTRL, 0x8288);
3185 bnx2x_cl45_write(bp, phy,
3186 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, 0x7fbf);
3187 bnx2x_cl45_write(bp, phy,
3188 MDIO_PMA_DEVAD, MDIO_PMA_REG_CMU_PLL_BYPASS, 0x0100);
3189 bnx2x_cl45_write(bp, phy,
3190 MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_CNTL, 0x1);
3191 /* BCM8705 doesn't have microcode, hence the 0 */
3192 bnx2x_save_spirom_version(bp, params->port, params->shmem_base, 0);
3193 return 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003194}
3195
3196static u8 bnx2x_8706_config_init(struct bnx2x_phy *phy,
3197 struct link_params *params,
3198 struct link_vars *vars)
3199{
3200 u16 cnt, val;
3201 struct bnx2x *bp = params->bp;
3202 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
3203 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
3204 /* HW reset */
3205 bnx2x_ext_phy_hw_reset(bp, params->port);
3206 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0xa040);
3207
3208 bnx2x_wait_reset_complete(bp, phy);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003209
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003210 /* Wait until fw is loaded */
3211 for (cnt = 0; cnt < 100; cnt++) {
3212 bnx2x_cl45_read(bp, phy,
3213 MDIO_PMA_DEVAD, MDIO_PMA_REG_ROM_VER1, &val);
3214 if (val)
3215 break;
3216 msleep(10);
3217 }
3218 DP(NETIF_MSG_LINK, "XGXS 8706 is initialized after %d ms\n", cnt);
3219 if ((params->feature_config_flags &
3220 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
3221 u8 i;
3222 u16 reg;
3223 for (i = 0; i < 4; i++) {
3224 reg = MDIO_XS_8706_REG_BANK_RX0 +
3225 i*(MDIO_XS_8706_REG_BANK_RX1 -
3226 MDIO_XS_8706_REG_BANK_RX0);
3227 bnx2x_cl45_read(bp, phy, MDIO_XS_DEVAD, reg, &val);
3228 /* Clear first 3 bits of the control */
3229 val &= ~0x7;
3230 /* Set control bits according to configuration */
3231 val |= (phy->rx_preemphasis[i] & 0x7);
3232 DP(NETIF_MSG_LINK, "Setting RX Equalizer to BCM8706"
3233 " reg 0x%x <-- val 0x%x\n", reg, val);
3234 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, reg, val);
3235 }
3236 }
3237 /* Force speed */
3238 if (phy->req_line_speed == SPEED_10000) {
3239 DP(NETIF_MSG_LINK, "XGXS 8706 force 10Gbps\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003240
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003241 bnx2x_cl45_write(bp, phy,
3242 MDIO_PMA_DEVAD,
3243 MDIO_PMA_REG_DIGITAL_CTRL, 0x400);
3244 bnx2x_cl45_write(bp, phy,
3245 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 1);
3246 } else {
3247 /* Force 1Gbps using autoneg with 1G advertisment */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003248
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003249 /* Allow CL37 through CL73 */
3250 DP(NETIF_MSG_LINK, "XGXS 8706 AutoNeg\n");
3251 bnx2x_cl45_write(bp, phy,
3252 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_CL73, 0x040c);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003253
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003254 /* Enable Full-Duplex advertisment on CL37 */
3255 bnx2x_cl45_write(bp, phy,
3256 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LP, 0x0020);
3257 /* Enable CL37 AN */
3258 bnx2x_cl45_write(bp, phy,
3259 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
3260 /* 1G support */
3261 bnx2x_cl45_write(bp, phy,
3262 MDIO_AN_DEVAD, MDIO_AN_REG_ADV, (1<<5));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003263
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003264 /* Enable clause 73 AN */
3265 bnx2x_cl45_write(bp, phy,
3266 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
3267 bnx2x_cl45_write(bp, phy,
3268 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
3269 0x0400);
3270 bnx2x_cl45_write(bp, phy,
3271 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL,
3272 0x0004);
3273 }
3274 bnx2x_save_bcm_spirom_ver(bp, params->port, phy, params->shmem_base);
3275 return 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003276}
3277
3278static u8 bnx2x_8726_config_init(struct bnx2x_phy *phy,
3279 struct link_params *params,
3280 struct link_vars *vars)
3281{
3282 struct bnx2x *bp = params->bp;
3283 DP(NETIF_MSG_LINK, "Initializing BCM8726\n");
3284 /* Restore normal power mode*/
3285 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
3286 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
3287
3288 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
3289 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
3290
3291 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
3292 bnx2x_wait_reset_complete(bp, phy);
3293
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003294 bnx2x_8726_external_rom_boot(phy, params);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003295
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003296 /* Need to call module detected on initialization since
3297 the module detection triggered by actual module
3298 insertion might occur before driver is loaded, and when
3299 driver is loaded, it reset all registers, including the
3300 transmitter */
3301 bnx2x_sfp_module_detection(phy, params);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003302
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003303 if (phy->req_line_speed == SPEED_1000) {
3304 DP(NETIF_MSG_LINK, "Setting 1G force\n");
3305 bnx2x_cl45_write(bp, phy,
3306 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x40);
3307 bnx2x_cl45_write(bp, phy,
3308 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0xD);
3309 bnx2x_cl45_write(bp, phy,
3310 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x5);
3311 bnx2x_cl45_write(bp, phy,
3312 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
3313 0x400);
3314 } else if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
3315 (phy->speed_cap_mask &
3316 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G) &&
3317 ((phy->speed_cap_mask &
3318 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) !=
3319 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
3320 DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
3321 /* Set Flow control */
3322 bnx2x_ext_phy_set_pause(params, phy, vars);
3323 bnx2x_cl45_write(bp, phy,
3324 MDIO_AN_DEVAD, MDIO_AN_REG_ADV, 0x20);
3325 bnx2x_cl45_write(bp, phy,
3326 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_CL73, 0x040c);
3327 bnx2x_cl45_write(bp, phy,
3328 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, 0x0020);
3329 bnx2x_cl45_write(bp, phy,
3330 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
3331 bnx2x_cl45_write(bp, phy,
3332 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
3333 /* Enable RX-ALARM control to receive
3334 interrupt for 1G speed change */
3335 bnx2x_cl45_write(bp, phy,
3336 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x4);
3337 bnx2x_cl45_write(bp, phy,
3338 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
3339 0x400);
Eilon Greenstein589abe32009-02-12 08:36:55 +00003340
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003341 } else { /* Default 10G. Set only LASI control */
3342 bnx2x_cl45_write(bp, phy,
3343 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 1);
3344 }
Eilon Greenstein589abe32009-02-12 08:36:55 +00003345
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003346 /* Set TX PreEmphasis if needed */
3347 if ((params->feature_config_flags &
3348 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
3349 DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x,"
3350 "TX_CTRL2 0x%x\n",
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003351 phy->tx_preemphasis[0],
3352 phy->tx_preemphasis[1]);
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003353 bnx2x_cl45_write(bp, phy,
3354 MDIO_PMA_DEVAD,
3355 MDIO_PMA_REG_8726_TX_CTRL1,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003356 phy->tx_preemphasis[0]);
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00003357
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003358 bnx2x_cl45_write(bp, phy,
3359 MDIO_PMA_DEVAD,
3360 MDIO_PMA_REG_8726_TX_CTRL2,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003361 phy->tx_preemphasis[1]);
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003362 }
3363 return 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003364
3365}
3366
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003367static u8 bnx2x_8073_config_init(struct bnx2x_phy *phy,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003368 struct link_params *params,
3369 struct link_vars *vars)
3370{
3371 struct bnx2x *bp = params->bp;
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003372 u16 val = 0, tmp1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003373 u8 gpio_port;
3374 DP(NETIF_MSG_LINK, "Init 8073\n");
3375
3376 gpio_port = params->port;
3377 /* Restore normal power mode*/
3378 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
3379 MISC_REGISTERS_GPIO_OUTPUT_HIGH, gpio_port);
3380
3381 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
3382 MISC_REGISTERS_GPIO_OUTPUT_HIGH, gpio_port);
3383
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003384 /* enable LASI */
3385 bnx2x_cl45_write(bp, phy,
3386 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL, (1<<2));
3387 bnx2x_cl45_write(bp, phy,
3388 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x0004);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003389
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003390 bnx2x_8073_set_pause_cl37(params, phy, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003391
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003392 bnx2x_8073_set_xaui_low_power_mode(bp, phy);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003393
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003394 bnx2x_cl45_read(bp, phy,
3395 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &tmp1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003396
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003397 bnx2x_cl45_read(bp, phy,
3398 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &tmp1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003399
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003400 DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1): 0x%x\n", tmp1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003401
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003402 /* Enable CL37 BAM */
3403 bnx2x_cl45_read(bp, phy,
3404 MDIO_AN_DEVAD,
3405 MDIO_AN_REG_8073_BAM, &val);
3406 bnx2x_cl45_write(bp, phy,
3407 MDIO_AN_DEVAD,
3408 MDIO_AN_REG_8073_BAM, val | 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003409
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003410 if (params->loopback_mode == LOOPBACK_EXT) {
3411 bnx2x_807x_force_10G(bp, phy);
3412 DP(NETIF_MSG_LINK, "Forced speed 10G on 807X\n");
3413 return 0;
3414 } else {
3415 bnx2x_cl45_write(bp, phy,
3416 MDIO_PMA_DEVAD, MDIO_PMA_REG_BCM_CTRL, 0x0002);
3417 }
3418 if (phy->req_line_speed != SPEED_AUTO_NEG) {
3419 if (phy->req_line_speed == SPEED_10000) {
3420 val = (1<<7);
3421 } else if (phy->req_line_speed == SPEED_2500) {
3422 val = (1<<5);
3423 /* Note that 2.5G works only
3424 when used with 1G advertisment */
3425 } else
3426 val = (1<<5);
3427 } else {
3428 val = 0;
3429 if (phy->speed_cap_mask &
3430 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
3431 val |= (1<<7);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003432
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003433 /* Note that 2.5G works only when
3434 used with 1G advertisment */
3435 if (phy->speed_cap_mask &
3436 (PORT_HW_CFG_SPEED_CAPABILITY_D0_1G |
3437 PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G))
3438 val |= (1<<5);
3439 DP(NETIF_MSG_LINK, "807x autoneg val = 0x%x\n", val);
3440 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003441
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003442 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV, val);
3443 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_8073_2_5G, &tmp1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003444
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003445 if (((phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G) &&
3446 (phy->req_line_speed == SPEED_AUTO_NEG)) ||
3447 (phy->req_line_speed == SPEED_2500)) {
3448 u16 phy_ver;
3449 /* Allow 2.5G for A1 and above */
3450 bnx2x_cl45_read(bp, phy,
3451 MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_CHIP_REV,
3452 &phy_ver);
3453 DP(NETIF_MSG_LINK, "Add 2.5G\n");
3454 if (phy_ver > 0)
3455 tmp1 |= 1;
3456 else
3457 tmp1 &= 0xfffe;
3458 } else {
3459 DP(NETIF_MSG_LINK, "Disable 2.5G\n");
3460 tmp1 &= 0xfffe;
3461 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003462
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003463 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_8073_2_5G, tmp1);
3464 /* Add support for CL37 (passive mode) II */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003465
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003466 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, &tmp1);
3467 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD,
3468 (tmp1 | ((phy->req_duplex == DUPLEX_FULL) ?
3469 0x20 : 0x40)));
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003470
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003471 /* Add support for CL37 (passive mode) III */
3472 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003473
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003474 /* The SNR will improve about 2db by changing
3475 BW and FEE main tap. Rest commands are executed
3476 after link is up*/
3477 if (bnx2x_8073_is_snr_needed(bp, phy))
3478 bnx2x_cl45_write(bp, phy,
3479 MDIO_PMA_DEVAD, MDIO_PMA_REG_EDC_FFE_MAIN,
3480 0xFB0C);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003481
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003482 /* Enable FEC (Forware Error Correction) Request in the AN */
3483 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV2, &tmp1);
3484 tmp1 |= (1<<15);
3485 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV2, tmp1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003486
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003487 bnx2x_ext_phy_set_pause(params, phy, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003488
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003489 /* Restart autoneg */
3490 msleep(500);
3491 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
3492 DP(NETIF_MSG_LINK, "807x Autoneg Restart: Advertise 1G=%x, 10G=%x\n",
3493 ((val & (1<<5)) > 0), ((val & (1<<7)) > 0));
3494 return 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003495}
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003496
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003497static u8 bnx2x_8727_config_init(struct bnx2x_phy *phy,
3498 struct link_params *params,
3499 struct link_vars *vars)
3500{
3501 u16 tmp1, val, mod_abs;
3502 u16 rx_alarm_ctrl_val;
3503 u16 lasi_ctrl_val;
3504 struct bnx2x *bp = params->bp;
3505 /* Enable PMD link, MOD_ABS_FLT, and 1G link alarm */
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003506
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003507 bnx2x_wait_reset_complete(bp, phy);
3508 rx_alarm_ctrl_val = (1<<2) | (1<<5) ;
3509 lasi_ctrl_val = 0x0004;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003510
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003511 DP(NETIF_MSG_LINK, "Initializing BCM8727\n");
3512 /* enable LASI */
3513 bnx2x_cl45_write(bp, phy,
3514 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
3515 rx_alarm_ctrl_val);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003516
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003517 bnx2x_cl45_write(bp, phy,
3518 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, lasi_ctrl_val);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003519
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003520 /* Initially configure MOD_ABS to interrupt when
3521 module is presence( bit 8) */
3522 bnx2x_cl45_read(bp, phy,
3523 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
3524 /* Set EDC off by setting OPTXLOS signal input to low
3525 (bit 9).
3526 When the EDC is off it locks onto a reference clock and
3527 avoids becoming 'lost'.*/
3528 mod_abs &= ~((1<<8) | (1<<9));
3529 bnx2x_cl45_write(bp, phy,
3530 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003531
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003532
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003533 /* Make MOD_ABS give interrupt on change */
3534 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL,
3535 &val);
3536 val |= (1<<12);
3537 bnx2x_cl45_write(bp, phy,
3538 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL, val);
3539 /* Set 8727 GPIOs to input to allow reading from the
3540 8727 GPIO0 status which reflect SFP+ module
3541 over-current */
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003542
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003543 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL,
3544 &val);
3545 val &= 0xff8f; /* Reset bits 4-6 */
3546 bnx2x_cl45_write(bp, phy,
3547 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL, val);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003548
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003549 bnx2x_8727_power_module(bp, phy, 1);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003550
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003551 bnx2x_cl45_read(bp, phy,
3552 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &tmp1);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003553
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003554 bnx2x_cl45_read(bp, phy,
3555 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &tmp1);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003556
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003557 /* Set option 1G speed */
3558 if (phy->req_line_speed == SPEED_1000) {
3559 DP(NETIF_MSG_LINK, "Setting 1G force\n");
3560 bnx2x_cl45_write(bp, phy,
3561 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x40);
3562 bnx2x_cl45_write(bp, phy,
3563 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0xD);
3564 bnx2x_cl45_read(bp, phy,
3565 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, &tmp1);
3566 DP(NETIF_MSG_LINK, "1.7 = 0x%x\n", tmp1);
3567 } else if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
3568 ((phy->speed_cap_mask &
3569 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) &&
3570 ((phy->speed_cap_mask &
3571 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) !=
3572 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003573
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003574 DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
3575 bnx2x_cl45_write(bp, phy,
3576 MDIO_AN_DEVAD, MDIO_AN_REG_8727_MISC_CTRL, 0);
3577 bnx2x_cl45_write(bp, phy,
3578 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1300);
3579 } else {
3580 /**
3581 * Since the 8727 has only single reset pin, need to set the 10G
3582 * registers although it is default
3583 */
3584 bnx2x_cl45_write(bp, phy,
3585 MDIO_AN_DEVAD, MDIO_AN_REG_8727_MISC_CTRL,
3586 0x0020);
3587 bnx2x_cl45_write(bp, phy,
3588 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x0100);
3589 bnx2x_cl45_write(bp, phy,
3590 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x2040);
3591 bnx2x_cl45_write(bp, phy,
3592 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2,
3593 0x0008);
3594 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003595
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003596
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003597 /* Set 2-wire transfer rate of SFP+ module EEPROM
3598 * to 100Khz since some DACs(direct attached cables) do
3599 * not work at 400Khz.
3600 */
3601 bnx2x_cl45_write(bp, phy,
3602 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR,
3603 0xa001);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003604
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003605 /* Set TX PreEmphasis if needed */
3606 if ((params->feature_config_flags &
3607 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
3608 DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x, TX_CTRL2 0x%x\n",
3609 phy->tx_preemphasis[0],
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003610 phy->tx_preemphasis[1]);
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003611 bnx2x_cl45_write(bp, phy,
3612 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TX_CTRL1,
3613 phy->tx_preemphasis[0]);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003614
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003615 bnx2x_cl45_write(bp, phy,
3616 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TX_CTRL2,
3617 phy->tx_preemphasis[1]);
3618 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003619
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003620 return 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003621}
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003622
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003623static u8 bnx2x_7101_config_init(struct bnx2x_phy *phy,
3624 struct link_params *params,
3625 struct link_vars *vars)
3626{
3627 u16 fw_ver1, fw_ver2, val;
3628 struct bnx2x *bp = params->bp;
3629 DP(NETIF_MSG_LINK, "Setting the SFX7101 LASI indication\n");
3630
3631 /* Restore normal power mode*/
3632 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
3633 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
3634 /* HW reset */
3635 bnx2x_ext_phy_hw_reset(bp, params->port);
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003636 bnx2x_wait_reset_complete(bp, phy);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003637
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003638 bnx2x_cl45_write(bp, phy,
3639 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x1);
3640 DP(NETIF_MSG_LINK, "Setting the SFX7101 LED to blink on traffic\n");
3641 bnx2x_cl45_write(bp, phy,
3642 MDIO_PMA_DEVAD, MDIO_PMA_REG_7107_LED_CNTL, (1<<3));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003643
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003644 bnx2x_ext_phy_set_pause(params, phy, vars);
3645 /* Restart autoneg */
3646 bnx2x_cl45_read(bp, phy,
3647 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, &val);
3648 val |= 0x200;
3649 bnx2x_cl45_write(bp, phy,
3650 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, val);
Eilon Greenstein28577182009-02-12 08:37:00 +00003651
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003652 /* Save spirom version */
3653 bnx2x_cl45_read(bp, phy,
3654 MDIO_PMA_DEVAD, MDIO_PMA_REG_7101_VER1, &fw_ver1);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003655
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003656 bnx2x_cl45_read(bp, phy,
3657 MDIO_PMA_DEVAD, MDIO_PMA_REG_7101_VER2, &fw_ver2);
3658 bnx2x_save_spirom_version(bp, params->port,
3659 (u32)(fw_ver1<<16 | fw_ver2), phy->ver_addr);
3660 return 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003661}
3662
3663static u8 bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy,
3664 struct link_params *params,
3665 struct link_vars *vars)
3666{
3667 struct bnx2x *bp = params->bp;
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003668 u16 autoneg_val, an_1000_val, an_10_100_val;
3669 bnx2x_wait_reset_complete(bp, phy);
3670 bnx2x_bits_en(bp, NIG_REG_LATCH_BC_0 + params->port*4,
3671 1 << NIG_LATCH_BC_ENABLE_MI_INT);
Yaniv Rosnera1e4be32010-09-01 09:51:33 +00003672
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003673 bnx2x_cl45_write(bp, phy,
3674 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x0000);
3675 bnx2x_8481_set_led(bp, phy);
3676 /* set 1000 speed advertisement */
3677 bnx2x_cl45_read(bp, phy,
3678 MDIO_AN_DEVAD, MDIO_AN_REG_8481_1000T_CTRL,
3679 &an_1000_val);
Eilon Greenstein28577182009-02-12 08:37:00 +00003680
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003681 bnx2x_ext_phy_set_pause(params, phy, vars);
3682 bnx2x_cl45_read(bp, phy,
3683 MDIO_AN_DEVAD,
3684 MDIO_AN_REG_8481_LEGACY_AN_ADV,
3685 &an_10_100_val);
3686 bnx2x_cl45_read(bp, phy,
3687 MDIO_AN_DEVAD, MDIO_AN_REG_8481_LEGACY_MII_CTRL,
3688 &autoneg_val);
3689 /* Disable forced speed */
3690 autoneg_val &= ~((1<<6) | (1<<8) | (1<<9) | (1<<12) | (1<<13));
3691 an_10_100_val &= ~((1<<5) | (1<<6) | (1<<7) | (1<<8));
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02003692
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003693 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
3694 (phy->speed_cap_mask &
3695 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) ||
3696 (phy->req_line_speed == SPEED_1000)) {
3697 an_1000_val |= (1<<8);
3698 autoneg_val |= (1<<9 | 1<<12);
3699 if (phy->req_duplex == DUPLEX_FULL)
3700 an_1000_val |= (1<<9);
3701 DP(NETIF_MSG_LINK, "Advertising 1G\n");
3702 } else
3703 an_1000_val &= ~((1<<8) | (1<<9));
Eilon Greenstein28577182009-02-12 08:37:00 +00003704
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003705 bnx2x_cl45_write(bp, phy,
3706 MDIO_AN_DEVAD, MDIO_AN_REG_8481_1000T_CTRL,
3707 an_1000_val);
Eilon Greenstein2f904462009-08-12 08:22:16 +00003708
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003709 /* set 10 speed advertisement */
3710 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
3711 (phy->speed_cap_mask &
3712 (PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL |
3713 PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF)))) {
3714 an_10_100_val |= (1<<7);
3715 /* Enable autoneg and restart autoneg for legacy speeds */
3716 autoneg_val |= (1<<9 | 1<<12);
Yaniv Rosner46d15cc2009-11-05 19:18:30 +02003717
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003718 if (phy->req_duplex == DUPLEX_FULL)
3719 an_10_100_val |= (1<<8);
3720 DP(NETIF_MSG_LINK, "Advertising 100M\n");
3721 }
3722 /* set 10 speed advertisement */
3723 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
3724 (phy->speed_cap_mask &
3725 (PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL |
3726 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF)))) {
3727 an_10_100_val |= (1<<5);
3728 autoneg_val |= (1<<9 | 1<<12);
3729 if (phy->req_duplex == DUPLEX_FULL)
3730 an_10_100_val |= (1<<6);
3731 DP(NETIF_MSG_LINK, "Advertising 10M\n");
3732 }
Eilon Greenstein2f904462009-08-12 08:22:16 +00003733
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003734 /* Only 10/100 are allowed to work in FORCE mode */
3735 if (phy->req_line_speed == SPEED_100) {
3736 autoneg_val |= (1<<13);
3737 /* Enabled AUTO-MDIX when autoneg is disabled */
3738 bnx2x_cl45_write(bp, phy,
3739 MDIO_AN_DEVAD, MDIO_AN_REG_8481_AUX_CTRL,
3740 (1<<15 | 1<<9 | 7<<0));
3741 DP(NETIF_MSG_LINK, "Setting 100M force\n");
3742 }
3743 if (phy->req_line_speed == SPEED_10) {
3744 /* Enabled AUTO-MDIX when autoneg is disabled */
3745 bnx2x_cl45_write(bp, phy,
3746 MDIO_AN_DEVAD, MDIO_AN_REG_8481_AUX_CTRL,
3747 (1<<15 | 1<<9 | 7<<0));
3748 DP(NETIF_MSG_LINK, "Setting 10M force\n");
3749 }
Eilon Greenstein2f904462009-08-12 08:22:16 +00003750
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003751 bnx2x_cl45_write(bp, phy,
3752 MDIO_AN_DEVAD, MDIO_AN_REG_8481_LEGACY_AN_ADV,
3753 an_10_100_val);
Yaniv Rosnerac4d9442010-09-01 09:51:25 +00003754
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003755 if (phy->req_duplex == DUPLEX_FULL)
3756 autoneg_val |= (1<<8);
Yaniv Rosnerac4d9442010-09-01 09:51:25 +00003757
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003758 bnx2x_cl45_write(bp, phy,
3759 MDIO_AN_DEVAD,
3760 MDIO_AN_REG_8481_LEGACY_MII_CTRL, autoneg_val);
Yaniv Rosnerac4d9442010-09-01 09:51:25 +00003761
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003762 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
3763 (phy->speed_cap_mask &
3764 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) ||
3765 (phy->req_line_speed == SPEED_10000)) {
3766 DP(NETIF_MSG_LINK, "Advertising 10G\n");
3767 /* Restart autoneg for 10G*/
Yaniv Rosnerac4d9442010-09-01 09:51:25 +00003768
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003769 bnx2x_cl45_write(bp, phy,
3770 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL,
3771 0x3200);
3772 } else if (phy->req_line_speed != SPEED_10 &&
3773 phy->req_line_speed != SPEED_100) {
3774 bnx2x_cl45_write(bp, phy,
3775 MDIO_AN_DEVAD,
3776 MDIO_AN_REG_8481_10GBASE_T_AN_CTRL,
3777 1);
3778 }
3779 /* Save spirom version */
3780 bnx2x_save_8481_spirom_version(phy, params, params->shmem_base);
Yaniv Rosnerac4d9442010-09-01 09:51:25 +00003781
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003782 return 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003783}
3784
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003785static u8 bnx2x_848x3_config_init(struct bnx2x_phy *phy,
3786 struct link_params *params,
3787 struct link_vars *vars)
3788{
3789 struct bnx2x *bp = params->bp;
3790 u16 temp;
3791 msleep(1);
3792 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
3793 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
3794 params->port);
3795 msleep(200); /* 100 is not enough */
3796
3797 /**
3798 * BCM84823 requires that XGXS links up first @ 10G for normal
3799 * behavior
3800 */
3801 temp = vars->line_speed;
3802 vars->line_speed = SPEED_10000;
3803 bnx2x_set_autoneg(phy, params, vars, 0);
3804 bnx2x_program_serdes(phy, params, vars);
3805 vars->line_speed = temp;
3806 return bnx2x_848xx_cmn_config_init(phy, params, vars);
3807}
3808
3809static u8 bnx2x_8481_config_init(struct bnx2x_phy *phy,
3810 struct link_params *params,
3811 struct link_vars *vars)
3812{
3813 struct bnx2x *bp = params->bp;
3814 /* Restore normal power mode*/
3815 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
3816 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
3817
3818 /* HW reset */
3819 bnx2x_ext_phy_hw_reset(bp, params->port);
3820
3821 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
3822 return bnx2x_848xx_cmn_config_init(phy, params, vars);
3823}
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003824static void bnx2x_8727_handle_mod_abs(struct bnx2x_phy *phy,
3825 struct link_params *params)
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003826{
3827 struct bnx2x *bp = params->bp;
3828 u16 mod_abs, rx_alarm_status;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003829 u32 val = REG_RD(bp, params->shmem_base +
3830 offsetof(struct shmem_region, dev_info.
3831 port_feature_config[params->port].
3832 config));
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003833 bnx2x_cl45_read(bp, phy,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003834 MDIO_PMA_DEVAD,
3835 MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
3836 if (mod_abs & (1<<8)) {
3837
3838 /* Module is absent */
3839 DP(NETIF_MSG_LINK, "MOD_ABS indication "
3840 "show module is absent\n");
3841
3842 /* 1. Set mod_abs to detect next module
3843 presence event
3844 2. Set EDC off by setting OPTXLOS signal input to low
3845 (bit 9).
3846 When the EDC is off it locks onto a reference clock and
3847 avoids becoming 'lost'.*/
3848 mod_abs &= ~((1<<8)|(1<<9));
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003849 bnx2x_cl45_write(bp, phy,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003850 MDIO_PMA_DEVAD,
3851 MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
3852
3853 /* Clear RX alarm since it stays up as long as
3854 the mod_abs wasn't changed */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003855 bnx2x_cl45_read(bp, phy,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003856 MDIO_PMA_DEVAD,
3857 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
3858
3859 } else {
3860 /* Module is present */
3861 DP(NETIF_MSG_LINK, "MOD_ABS indication "
3862 "show module is present\n");
3863 /* First thing, disable transmitter,
3864 and if the module is ok, the
3865 module_detection will enable it*/
3866
3867 /* 1. Set mod_abs to detect next module
3868 absent event ( bit 8)
3869 2. Restore the default polarity of the OPRXLOS signal and
3870 this signal will then correctly indicate the presence or
3871 absence of the Rx signal. (bit 9) */
3872 mod_abs |= ((1<<8)|(1<<9));
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003873 bnx2x_cl45_write(bp, phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003874 MDIO_PMA_DEVAD,
3875 MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003876
3877 /* Clear RX alarm since it stays up as long as
3878 the mod_abs wasn't changed. This is need to be done
3879 before calling the module detection, otherwise it will clear
3880 the link update alarm */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003881 bnx2x_cl45_read(bp, phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003882 MDIO_PMA_DEVAD,
3883 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003884
3885
3886 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
3887 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003888 bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003889
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003890 if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0)
3891 bnx2x_sfp_module_detection(phy, params);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003892 else
3893 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
3894 }
3895
3896 DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n",
3897 rx_alarm_status);
3898 /* No need to check link status in case of
3899 module plugged in/out */
3900}
3901
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003902static u8 bnx2x_8705_read_status(struct bnx2x_phy *phy,
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003903 struct link_params *params,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003904 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003905{
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003906 u8 link_up = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003907 u16 val1, rx_sd;
3908 struct bnx2x *bp = params->bp;
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003909 DP(NETIF_MSG_LINK, "read status 8705\n");
3910 bnx2x_cl45_read(bp, phy,
3911 MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_STATUS, &val1);
3912 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003913
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003914 bnx2x_cl45_read(bp, phy,
3915 MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_STATUS, &val1);
3916 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003917
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003918 bnx2x_cl45_read(bp, phy,
3919 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD, &rx_sd);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003920
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003921 bnx2x_cl45_read(bp, phy,
3922 MDIO_PMA_DEVAD, 0xc809, &val1);
3923 bnx2x_cl45_read(bp, phy,
3924 MDIO_PMA_DEVAD, 0xc809, &val1);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003925
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003926 DP(NETIF_MSG_LINK, "8705 1.c809 val=0x%x\n", val1);
3927 link_up = ((rx_sd & 0x1) && (val1 & (1<<9)) && ((val1 & (1<<8)) == 0));
3928 if (link_up) {
3929 vars->line_speed = SPEED_10000;
3930 bnx2x_ext_phy_resolve_fc(phy, params, vars);
3931 }
3932 return link_up;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003933}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003934
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003935static u8 bnx2x_8706_8726_read_status(struct bnx2x_phy *phy,
3936 struct link_params *params,
3937 struct link_vars *vars)
3938{
3939 u8 link_up = 0;
3940 u16 val1, val2, rx_sd, pcs_status;
3941 struct bnx2x *bp = params->bp;
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003942 DP(NETIF_MSG_LINK, "XGXS 8706/8726\n");
3943 /* Clear RX Alarm*/
3944 bnx2x_cl45_read(bp, phy,
3945 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &val2);
3946 /* clear LASI indication*/
3947 bnx2x_cl45_read(bp, phy,
3948 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
3949 bnx2x_cl45_read(bp, phy,
3950 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val2);
3951 DP(NETIF_MSG_LINK, "8706/8726 LASI status 0x%x--> 0x%x\n", val1, val2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003952
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003953 bnx2x_cl45_read(bp, phy,
3954 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD, &rx_sd);
3955 bnx2x_cl45_read(bp, phy,
3956 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &pcs_status);
3957 bnx2x_cl45_read(bp, phy,
3958 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &val2);
3959 bnx2x_cl45_read(bp, phy,
3960 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &val2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003961
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003962 DP(NETIF_MSG_LINK, "8706/8726 rx_sd 0x%x pcs_status 0x%x 1Gbps"
3963 " link_status 0x%x\n", rx_sd, pcs_status, val2);
3964 /* link is up if both bit 0 of pmd_rx_sd and
3965 * bit 0 of pcs_status are set, or if the autoneg bit
3966 * 1 is set
3967 */
3968 link_up = ((rx_sd & pcs_status & 0x1) || (val2 & (1<<1)));
3969 if (link_up) {
3970 if (val2 & (1<<1))
3971 vars->line_speed = SPEED_1000;
3972 else
3973 vars->line_speed = SPEED_10000;
3974 bnx2x_ext_phy_resolve_fc(phy, params, vars);
3975 }
3976 return link_up;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003977}
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003978
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003979static u8 bnx2x_8706_read_status(struct bnx2x_phy *phy,
3980 struct link_params *params,
3981 struct link_vars *vars)
3982{
3983 return bnx2x_8706_8726_read_status(phy, params, vars);
3984}
3985
3986static u8 bnx2x_8726_read_status(struct bnx2x_phy *phy,
3987 struct link_params *params,
3988 struct link_vars *vars)
3989{
3990 struct bnx2x *bp = params->bp;
3991 u16 val1;
3992 u8 link_up = bnx2x_8706_8726_read_status(phy, params, vars);
3993 if (link_up) {
3994 bnx2x_cl45_read(bp, phy,
3995 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER,
3996 &val1);
3997 if (val1 & (1<<15)) {
3998 DP(NETIF_MSG_LINK, "Tx is disabled\n");
3999 link_up = 0;
4000 vars->line_speed = 0;
4001 }
4002 }
4003 return link_up;
4004}
4005static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy,
4006 struct link_params *params,
4007 struct link_vars *vars)
4008
4009{
4010 struct bnx2x *bp = params->bp;
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004011 u8 link_up = 0;
4012 u16 link_status = 0;
4013 u16 rx_alarm_status, val1;
4014 /* Check the LASI */
4015 bnx2x_cl45_read(bp, phy,
4016 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM,
4017 &rx_alarm_status);
4018 vars->line_speed = 0;
4019 DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n", rx_alarm_status);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004020
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004021 bnx2x_cl45_read(bp, phy,
4022 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004023
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004024 DP(NETIF_MSG_LINK, "8727 LASI status 0x%x\n", val1);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004025
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004026 /* Clear MSG-OUT */
4027 bnx2x_cl45_read(bp, phy,
4028 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &val1);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004029
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004030 /**
4031 * If a module is present and there is need to check
4032 * for over current
4033 */
4034 if (!(phy->flags & FLAGS_NOC) && !(rx_alarm_status & (1<<5))) {
4035 /* Check over-current using 8727 GPIO0 input*/
4036 bnx2x_cl45_read(bp, phy,
4037 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_GPIO_CTRL,
4038 &val1);
4039
4040 if ((val1 & (1<<8)) == 0) {
4041 DP(NETIF_MSG_LINK, "8727 Power fault has been detected"
4042 " on port %d\n", params->port);
4043 netdev_err(bp->dev, "Error: Power fault on Port %d has"
4044 " been detected and the power to "
4045 "that SFP+ module has been removed"
4046 " to prevent failure of the card."
4047 " Please remove the SFP+ module and"
4048 " restart the system to clear this"
4049 " error.\n",
4050 params->port);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004051
4052 /*
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004053 * Disable all RX_ALARMs except for
4054 * mod_abs
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004055 */
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004056 bnx2x_cl45_write(bp, phy,
4057 MDIO_PMA_DEVAD,
4058 MDIO_PMA_REG_RX_ALARM_CTRL, (1<<5));
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004059
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004060 bnx2x_cl45_read(bp, phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004061 MDIO_PMA_DEVAD,
4062 MDIO_PMA_REG_PHY_IDENTIFIER, &val1);
4063 /* Wait for module_absent_event */
4064 val1 |= (1<<8);
4065 bnx2x_cl45_write(bp, phy,
4066 MDIO_PMA_DEVAD,
4067 MDIO_PMA_REG_PHY_IDENTIFIER, val1);
4068 /* Clear RX alarm */
4069 bnx2x_cl45_read(bp, phy,
4070 MDIO_PMA_DEVAD,
4071 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
4072 return 0;
4073 }
4074 } /* Over current check */
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004075
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004076 /* When module absent bit is set, check module */
4077 if (rx_alarm_status & (1<<5)) {
4078 bnx2x_8727_handle_mod_abs(phy, params);
4079 /* Enable all mod_abs and link detection bits */
4080 bnx2x_cl45_write(bp, phy,
4081 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
4082 ((1<<5) | (1<<2)));
4083 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004084
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004085 /* If transmitter is disabled, ignore false link up indication */
4086 bnx2x_cl45_read(bp, phy,
4087 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, &val1);
4088 if (val1 & (1<<15)) {
4089 DP(NETIF_MSG_LINK, "Tx is disabled\n");
4090 return 0;
4091 }
4092
4093 bnx2x_cl45_read(bp, phy,
4094 MDIO_PMA_DEVAD,
4095 MDIO_PMA_REG_8073_SPEED_LINK_STATUS, &link_status);
4096
4097 /* Bits 0..2 --> speed detected,
4098 bits 13..15--> link is down */
4099 if ((link_status & (1<<2)) && (!(link_status & (1<<15)))) {
4100 link_up = 1;
4101 vars->line_speed = SPEED_10000;
4102 } else if ((link_status & (1<<0)) && (!(link_status & (1<<13)))) {
4103 link_up = 1;
4104 vars->line_speed = SPEED_1000;
4105 DP(NETIF_MSG_LINK, "port %x: External link up in 1G\n",
4106 params->port);
4107 } else {
4108 link_up = 0;
4109 DP(NETIF_MSG_LINK, "port %x: External link is down\n",
4110 params->port);
4111 }
4112 if (link_up)
4113 bnx2x_ext_phy_resolve_fc(phy, params, vars);
4114 return link_up;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004115}
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004116
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004117static u8 bnx2x_8073_read_status(struct bnx2x_phy *phy,
4118 struct link_params *params,
4119 struct link_vars *vars)
4120{
4121 struct bnx2x *bp = params->bp;
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004122 u8 link_up = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004123 u16 val1, val2;
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004124 u16 link_status = 0;
4125 u16 an1000_status = 0;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00004126
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004127 bnx2x_cl45_read(bp, phy,
4128 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004129
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004130 DP(NETIF_MSG_LINK, "8703 LASI status 0x%x\n", val1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004131
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004132 /* clear the interrupt LASI status register */
4133 bnx2x_cl45_read(bp, phy,
4134 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val2);
4135 bnx2x_cl45_read(bp, phy,
4136 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val1);
4137 DP(NETIF_MSG_LINK, "807x PCS status 0x%x->0x%x\n", val2, val1);
4138 /* Clear MSG-OUT */
4139 bnx2x_cl45_read(bp, phy,
4140 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &val1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004141
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004142 /* Check the LASI */
4143 bnx2x_cl45_read(bp, phy,
4144 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &val2);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004145
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004146 DP(NETIF_MSG_LINK, "KR 0x9003 0x%x\n", val2);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004147
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004148 /* Check the link status */
4149 bnx2x_cl45_read(bp, phy,
4150 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val2);
4151 DP(NETIF_MSG_LINK, "KR PCS status 0x%x\n", val2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004152
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004153 bnx2x_cl45_read(bp, phy,
4154 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
4155 bnx2x_cl45_read(bp, phy,
4156 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
4157 link_up = ((val1 & 4) == 4);
4158 DP(NETIF_MSG_LINK, "PMA_REG_STATUS=0x%x\n", val1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004159
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004160 if (link_up &&
4161 ((phy->req_line_speed != SPEED_10000))) {
4162 if (bnx2x_8073_xaui_wa(bp, phy) != 0)
4163 return 0;
4164 }
4165 bnx2x_cl45_read(bp, phy,
4166 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &an1000_status);
4167 bnx2x_cl45_read(bp, phy,
4168 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &an1000_status);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004169
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004170 /* Check the link status on 1.1.2 */
4171 bnx2x_cl45_read(bp, phy,
4172 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
4173 bnx2x_cl45_read(bp, phy,
4174 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
4175 DP(NETIF_MSG_LINK, "KR PMA status 0x%x->0x%x,"
4176 "an_link_status=0x%x\n", val2, val1, an1000_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004177
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004178 link_up = (((val1 & 4) == 4) || (an1000_status & (1<<1)));
4179 if (link_up && bnx2x_8073_is_snr_needed(bp, phy)) {
4180 /* The SNR will improve about 2dbby
4181 changing the BW and FEE main tap.*/
4182 /* The 1st write to change FFE main
4183 tap is set before restart AN */
4184 /* Change PLL Bandwidth in EDC
4185 register */
4186 bnx2x_cl45_write(bp, phy,
4187 MDIO_PMA_DEVAD, MDIO_PMA_REG_PLL_BANDWIDTH,
4188 0x26BC);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004189
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004190 /* Change CDR Bandwidth in EDC register */
4191 bnx2x_cl45_write(bp, phy,
4192 MDIO_PMA_DEVAD, MDIO_PMA_REG_CDR_BANDWIDTH,
4193 0x0333);
4194 }
4195 bnx2x_cl45_read(bp, phy,
4196 MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
4197 &link_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004198
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004199 /* Bits 0..2 --> speed detected, bits 13..15--> link is down */
4200 if ((link_status & (1<<2)) && (!(link_status & (1<<15)))) {
4201 link_up = 1;
4202 vars->line_speed = SPEED_10000;
4203 DP(NETIF_MSG_LINK, "port %x: External link up in 10G\n",
4204 params->port);
4205 } else if ((link_status & (1<<1)) && (!(link_status & (1<<14)))) {
4206 link_up = 1;
4207 vars->line_speed = SPEED_2500;
4208 DP(NETIF_MSG_LINK, "port %x: External link up in 2.5G\n",
4209 params->port);
4210 } else if ((link_status & (1<<0)) && (!(link_status & (1<<13)))) {
4211 link_up = 1;
4212 vars->line_speed = SPEED_1000;
4213 DP(NETIF_MSG_LINK, "port %x: External link up in 1G\n",
4214 params->port);
4215 } else {
4216 link_up = 0;
4217 DP(NETIF_MSG_LINK, "port %x: External link is down\n",
4218 params->port);
4219 }
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004220
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004221 return link_up;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004222}
4223
4224static u8 bnx2x_7101_read_status(struct bnx2x_phy *phy,
4225 struct link_params *params,
4226 struct link_vars *vars)
4227{
4228 struct bnx2x *bp = params->bp;
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004229 u8 link_up;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004230 u16 val1, val2;
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004231 bnx2x_cl45_read(bp, phy,
4232 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val2);
4233 bnx2x_cl45_read(bp, phy,
4234 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
4235 DP(NETIF_MSG_LINK, "10G-base-T LASI status 0x%x->0x%x\n",
4236 val2, val1);
4237 bnx2x_cl45_read(bp, phy,
4238 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
4239 bnx2x_cl45_read(bp, phy,
4240 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
4241 DP(NETIF_MSG_LINK, "10G-base-T PMA status 0x%x->0x%x\n",
4242 val2, val1);
4243 link_up = ((val1 & 4) == 4);
4244 /* if link is up
4245 * print the AN outcome of the SFX7101 PHY
4246 */
4247 if (link_up) {
4248 bnx2x_cl45_read(bp, phy,
4249 MDIO_AN_DEVAD, MDIO_AN_REG_MASTER_STATUS,
4250 &val2);
4251 vars->line_speed = SPEED_10000;
4252 DP(NETIF_MSG_LINK, "SFX7101 AN status 0x%x->Master=%x\n",
4253 val2, (val2 & (1<<14)));
4254 }
4255 return link_up;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004256}
4257
4258static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy,
4259 struct link_params *params,
4260 struct link_vars *vars)
4261{
4262 struct bnx2x *bp = params->bp;
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004263 u16 val, val1, val2;
4264 u8 link_up = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004265
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004266 /* Check 10G-BaseT link status */
4267 /* Check PMD signal ok */
4268 bnx2x_cl45_read(bp, phy,
4269 MDIO_AN_DEVAD, 0xFFFA, &val1);
4270 bnx2x_cl45_read(bp, phy,
4271 MDIO_PMA_DEVAD, MDIO_PMA_REG_8481_PMD_SIGNAL,
4272 &val2);
4273 DP(NETIF_MSG_LINK, "BCM848xx: PMD_SIGNAL 1.a811 = 0x%x\n", val2);
4274
4275 /* Check link 10G */
4276 if (val2 & (1<<11)) {
4277 vars->line_speed = SPEED_10000;
4278 link_up = 1;
4279 } else { /* Check Legacy speed link */
4280 u16 legacy_status, legacy_speed;
4281
4282 /* Enable expansion register 0x42 (Operation mode status) */
4283 bnx2x_cl45_write(bp, phy,
4284 MDIO_AN_DEVAD,
4285 MDIO_AN_REG_8481_EXPANSION_REG_ACCESS, 0xf42);
4286
4287 /* Get legacy speed operation status */
4288 bnx2x_cl45_read(bp, phy,
4289 MDIO_AN_DEVAD,
4290 MDIO_AN_REG_8481_EXPANSION_REG_RD_RW,
4291 &legacy_status);
4292
4293 DP(NETIF_MSG_LINK, "Legacy speed status"
4294 " = 0x%x\n", legacy_status);
4295 link_up = ((legacy_status & (1<<11)) == (1<<11));
4296 if (link_up) {
4297 legacy_speed = (legacy_status & (3<<9));
4298 if (legacy_speed == (0<<9))
4299 vars->line_speed = SPEED_10;
4300 else if (legacy_speed == (1<<9))
4301 vars->line_speed = SPEED_100;
4302 else if (legacy_speed == (2<<9))
4303 vars->line_speed = SPEED_1000;
4304 else /* Should not happen */
4305 vars->line_speed = 0;
4306
4307 if (legacy_status & (1<<8))
4308 vars->duplex = DUPLEX_FULL;
4309 else
4310 vars->duplex = DUPLEX_HALF;
4311
4312 DP(NETIF_MSG_LINK, "Link is up in %dMbps,"
4313 " is_duplex_full= %d\n", vars->line_speed,
4314 (vars->duplex == DUPLEX_FULL));
4315
4316 /* Check legacy speed AN resolution */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004317 bnx2x_cl45_read(bp, phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004318 MDIO_AN_DEVAD,
4319 MDIO_AN_REG_8481_LEGACY_MII_STATUS,
4320 &val);
4321 if (val & (1<<5))
4322 vars->link_status |=
4323 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004324 bnx2x_cl45_read(bp, phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004325 MDIO_AN_DEVAD,
4326 MDIO_AN_REG_8481_LEGACY_AN_EXPANSION,
4327 &val);
4328 if ((val & (1<<0)) == 0)
4329 vars->link_status |=
4330 LINK_STATUS_PARALLEL_DETECTION_USED;
4331 }
4332 }
4333 return link_up;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004334}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004335static void bnx2x_link_int_enable(struct link_params *params)
4336{
4337 u8 port = params->port;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004338 u32 mask;
4339 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00004340
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004341 /* setting the status to report on link up
4342 for either XGXS or SerDes */
4343
4344 if (params->switch_cfg == SWITCH_CFG_10G) {
4345 mask = (NIG_MASK_XGXS0_LINK10G |
4346 NIG_MASK_XGXS0_LINK_STATUS);
4347 DP(NETIF_MSG_LINK, "enabled XGXS interrupt\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004348 if (!(SINGLE_MEDIA_DIRECT(params)) &&
4349 params->phy[INT_PHY].type !=
4350 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004351 mask |= NIG_MASK_MI_INT;
4352 DP(NETIF_MSG_LINK, "enabled external phy int\n");
4353 }
4354
4355 } else { /* SerDes */
4356 mask = NIG_MASK_SERDES0_LINK_STATUS;
4357 DP(NETIF_MSG_LINK, "enabled SerDes interrupt\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004358 if (!(SINGLE_MEDIA_DIRECT(params)) &&
4359 params->phy[INT_PHY].type !=
4360 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_NOT_CONN) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004361 mask |= NIG_MASK_MI_INT;
4362 DP(NETIF_MSG_LINK, "enabled external phy int\n");
4363 }
4364 }
4365 bnx2x_bits_en(bp,
4366 NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
4367 mask);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00004368
4369 DP(NETIF_MSG_LINK, "port %x, is_xgxs %x, int_status 0x%x\n", port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004370 (params->switch_cfg == SWITCH_CFG_10G),
4371 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004372 DP(NETIF_MSG_LINK, " int_mask 0x%x, MI_INT %x, SERDES_LINK %x\n",
4373 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
4374 REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
4375 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS+port*0x3c));
4376 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
4377 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
4378 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
4379}
4380
Eilon Greenstein2f904462009-08-12 08:22:16 +00004381static void bnx2x_8481_rearm_latch_signal(struct bnx2x *bp, u8 port,
4382 u8 is_mi_int)
4383{
4384 u32 latch_status = 0, is_mi_int_status;
4385 /* Disable the MI INT ( external phy int )
4386 * by writing 1 to the status register. Link down indication
4387 * is high-active-signal, so in this case we need to write the
4388 * status to clear the XOR
4389 */
4390 /* Read Latched signals */
4391 latch_status = REG_RD(bp,
4392 NIG_REG_LATCH_STATUS_0 + port*8);
4393 is_mi_int_status = REG_RD(bp,
4394 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4);
4395 DP(NETIF_MSG_LINK, "original_signal = 0x%x, nig_status = 0x%x,"
4396 "latch_status = 0x%x\n",
4397 is_mi_int, is_mi_int_status, latch_status);
4398 /* Handle only those with latched-signal=up.*/
4399 if (latch_status & 1) {
4400 /* For all latched-signal=up,Write original_signal to status */
4401 if (is_mi_int)
4402 bnx2x_bits_en(bp,
4403 NIG_REG_STATUS_INTERRUPT_PORT0
4404 + port*4,
4405 NIG_STATUS_EMAC0_MI_INT);
4406 else
4407 bnx2x_bits_dis(bp,
4408 NIG_REG_STATUS_INTERRUPT_PORT0
4409 + port*4,
4410 NIG_STATUS_EMAC0_MI_INT);
4411 /* For all latched-signal=up : Re-Arm Latch signals */
4412 REG_WR(bp, NIG_REG_LATCH_STATUS_0 + port*8,
4413 (latch_status & 0xfffe) | (latch_status & 1));
4414 }
4415}
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004416
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004417/*
4418 * link management
4419 */
4420static void bnx2x_link_int_ack(struct link_params *params,
Eilon Greenstein2f904462009-08-12 08:22:16 +00004421 struct link_vars *vars, u8 is_10g,
4422 u8 is_mi_int)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004423{
4424 struct bnx2x *bp = params->bp;
4425 u8 port = params->port;
4426
4427 /* first reset all status
4428 * we assume only one line will be change at a time */
4429 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
4430 (NIG_STATUS_XGXS0_LINK10G |
4431 NIG_STATUS_XGXS0_LINK_STATUS |
4432 NIG_STATUS_SERDES0_LINK_STATUS));
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004433 if ((params->phy[EXT_PHY1].type
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02004434 == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481) ||
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004435 (params->phy[EXT_PHY1].type
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02004436 == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823)) {
Eilon Greenstein2f904462009-08-12 08:22:16 +00004437 bnx2x_8481_rearm_latch_signal(bp, port, is_mi_int);
4438 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004439 if (vars->phy_link_up) {
4440 if (is_10g) {
4441 /* Disable the 10G link interrupt
4442 * by writing 1 to the status register
4443 */
4444 DP(NETIF_MSG_LINK, "10G XGXS phy link up\n");
4445 bnx2x_bits_en(bp,
4446 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
4447 NIG_STATUS_XGXS0_LINK10G);
4448
4449 } else if (params->switch_cfg == SWITCH_CFG_10G) {
4450 /* Disable the link interrupt
4451 * by writing 1 to the relevant lane
4452 * in the status register
4453 */
4454 u32 ser_lane = ((params->lane_config &
4455 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
4456 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
4457
Eilon Greenstein2f904462009-08-12 08:22:16 +00004458 DP(NETIF_MSG_LINK, "%d speed XGXS phy link up\n",
4459 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004460 bnx2x_bits_en(bp,
4461 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
4462 ((1 << ser_lane) <<
4463 NIG_STATUS_XGXS0_LINK_STATUS_SIZE));
4464
4465 } else { /* SerDes */
4466 DP(NETIF_MSG_LINK, "SerDes phy link up\n");
4467 /* Disable the link interrupt
4468 * by writing 1 to the status register
4469 */
4470 bnx2x_bits_en(bp,
4471 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
4472 NIG_STATUS_SERDES0_LINK_STATUS);
4473 }
4474
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004475 }
4476}
4477
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004478static u8 bnx2x_7101_format_ver(u32 spirom_ver, u8 *str, u16 *len)
4479{
4480 if (*len < 5)
4481 return -EINVAL;
4482 str[0] = (spirom_ver & 0xFF);
4483 str[1] = (spirom_ver & 0xFF00) >> 8;
4484 str[2] = (spirom_ver & 0xFF0000) >> 16;
4485 str[3] = (spirom_ver & 0xFF000000) >> 24;
4486 str[4] = '\0';
4487 *len -= 5;
4488 return 0;
4489}
4490
4491static u8 bnx2x_format_ver(u32 num, u8 *str, u16 *len)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004492{
4493 u8 *str_ptr = str;
4494 u32 mask = 0xf0000000;
4495 u8 shift = 8*4;
4496 u8 digit;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004497 if (*len < 10) {
Frederik Schwarzer025dfda2008-10-16 19:02:37 +02004498 /* Need more than 10chars for this format */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004499 *str_ptr = '\0';
4500 return -EINVAL;
4501 }
4502 while (shift > 0) {
4503
4504 shift -= 4;
4505 digit = ((num & mask) >> shift);
4506 if (digit < 0xa)
4507 *str_ptr = digit + '0';
4508 else
4509 *str_ptr = digit - 0xa + 'a';
4510 str_ptr++;
4511 mask = mask >> 4;
4512 if (shift == 4*4) {
4513 *str_ptr = ':';
4514 str_ptr++;
4515 }
4516 }
4517 *str_ptr = '\0';
4518 return 0;
4519}
4520
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004521static u8 bnx2x_848xx_format_ver(u32 raw_ver, u8 *str, u16 *len)
4522{
4523 u8 status = 0;
4524 u32 spirom_ver;
4525 spirom_ver = ((raw_ver & 0xF80) >> 7) << 16 | (raw_ver & 0x7F);
4526 status = bnx2x_format_ver(spirom_ver, str, len);
4527 return status;
4528}
4529
4530static u8 bnx2x_null_format_ver(u32 spirom_ver, u8 *str, u16 *len)
4531{
4532 str[0] = '\0';
4533 (*len)--;
4534 return 0;
4535}
4536
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004537u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
4538 u8 *version, u16 len)
4539{
Julia Lawall0376d5b2009-07-19 05:26:35 +00004540 struct bnx2x *bp;
Eilon Greensteina35da8d2009-02-12 08:37:02 +00004541 u32 spirom_ver = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004542 u8 status = 0;
4543 u8 *ver_p = version;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004544 if (version == NULL || params == NULL)
4545 return -EINVAL;
Julia Lawall0376d5b2009-07-19 05:26:35 +00004546 bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004547
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004548 /* Extract first external phy*/
4549 version[0] = '\0';
4550 spirom_ver = REG_RD(bp, params->phy[EXT_PHY1].ver_addr);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00004551
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004552 if (params->phy[EXT_PHY1].format_fw_ver)
4553 status |= params->phy[EXT_PHY1].format_fw_ver(spirom_ver,
4554 ver_p,
4555 &len);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004556 return status;
4557}
4558
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004559static void bnx2x_set_xgxs_loopback(struct bnx2x_phy *phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004560 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004561{
4562 u8 port = params->port;
4563 struct bnx2x *bp = params->bp;
4564
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004565 if (phy->req_line_speed != SPEED_1000) {
Eilon Greenstein6378c022008-08-13 15:59:25 -07004566 u32 md_devad;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004567
4568 DP(NETIF_MSG_LINK, "XGXS 10G loopback enable\n");
4569
4570 /* change the uni_phy_addr in the nig */
4571 md_devad = REG_RD(bp, (NIG_REG_XGXS0_CTRL_MD_DEVAD +
4572 port*0x18));
4573
4574 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, 0x5);
4575
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004576 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004577 5,
4578 (MDIO_REG_BANK_AER_BLOCK +
4579 (MDIO_AER_BLOCK_AER_REG & 0xf)),
4580 0x2800);
4581
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004582 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004583 5,
4584 (MDIO_REG_BANK_CL73_IEEEB0 +
4585 (MDIO_CL73_IEEEB0_CL73_AN_CONTROL & 0xf)),
4586 0x6041);
Eilon Greenstein38582762009-01-14 06:44:16 +00004587 msleep(200);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004588 /* set aer mmd back */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004589 bnx2x_set_aer_mmd(params, phy);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004590
4591 /* and md_devad */
4592 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
4593 md_devad);
4594
4595 } else {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004596 u16 mii_ctrl;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004597 DP(NETIF_MSG_LINK, "XGXS 1G loopback enable\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004598 bnx2x_cl45_read(bp, phy, 5,
4599 (MDIO_REG_BANK_COMBO_IEEE0 +
4600 (MDIO_COMBO_IEEE0_MII_CONTROL & 0xf)),
4601 &mii_ctrl);
4602 bnx2x_cl45_write(bp, phy, 5,
4603 (MDIO_REG_BANK_COMBO_IEEE0 +
4604 (MDIO_COMBO_IEEE0_MII_CONTROL & 0xf)),
4605 mii_ctrl |
4606 MDIO_COMBO_IEEO_MII_CONTROL_LOOPBACK);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004607 }
4608}
4609
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004610static void bnx2x_8726_config_loopback(struct bnx2x_phy *phy,
4611 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004612{
4613 struct bnx2x *bp = params->bp;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004614 DP(NETIF_MSG_LINK, "PMA/PMD ext_phy_loopback: 8726\n");
4615 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x0001);
4616}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004617
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004618static void bnx2x_7101_config_loopback(struct bnx2x_phy *phy,
4619 struct link_params *params)
4620{
4621 struct bnx2x *bp = params->bp;
4622 /* SFX7101_XGXS_TEST1 */
4623 bnx2x_cl45_write(bp, phy,
4624 MDIO_XS_DEVAD, MDIO_XS_SFX7101_XGXS_TEST1, 0x100);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004625}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004626/*
4627 *------------------------------------------------------------------------
4628 * bnx2x_override_led_value -
4629 *
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004630 * Override the led value of the requested led
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004631 *
4632 *------------------------------------------------------------------------
4633 */
4634u8 bnx2x_override_led_value(struct bnx2x *bp, u8 port,
4635 u32 led_idx, u32 value)
4636{
4637 u32 reg_val;
4638
4639 /* If port 0 then use EMAC0, else use EMAC1*/
4640 u32 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
4641
4642 DP(NETIF_MSG_LINK,
4643 "bnx2x_override_led_value() port %x led_idx %d value %d\n",
4644 port, led_idx, value);
4645
4646 switch (led_idx) {
4647 case 0: /* 10MB led */
4648 /* Read the current value of the LED register in
4649 the EMAC block */
4650 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
4651 /* Set the OVERRIDE bit to 1 */
4652 reg_val |= EMAC_LED_OVERRIDE;
4653 /* If value is 1, set the 10M_OVERRIDE bit,
4654 otherwise reset it.*/
4655 reg_val = (value == 1) ? (reg_val | EMAC_LED_10MB_OVERRIDE) :
4656 (reg_val & ~EMAC_LED_10MB_OVERRIDE);
4657 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
4658 break;
4659 case 1: /*100MB led */
4660 /*Read the current value of the LED register in
4661 the EMAC block */
4662 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
4663 /* Set the OVERRIDE bit to 1 */
4664 reg_val |= EMAC_LED_OVERRIDE;
4665 /* If value is 1, set the 100M_OVERRIDE bit,
4666 otherwise reset it.*/
4667 reg_val = (value == 1) ? (reg_val | EMAC_LED_100MB_OVERRIDE) :
4668 (reg_val & ~EMAC_LED_100MB_OVERRIDE);
4669 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
4670 break;
4671 case 2: /* 1000MB led */
4672 /* Read the current value of the LED register in the
4673 EMAC block */
4674 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
4675 /* Set the OVERRIDE bit to 1 */
4676 reg_val |= EMAC_LED_OVERRIDE;
4677 /* If value is 1, set the 1000M_OVERRIDE bit, otherwise
4678 reset it. */
4679 reg_val = (value == 1) ? (reg_val | EMAC_LED_1000MB_OVERRIDE) :
4680 (reg_val & ~EMAC_LED_1000MB_OVERRIDE);
4681 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
4682 break;
4683 case 3: /* 2500MB led */
4684 /* Read the current value of the LED register in the
4685 EMAC block*/
4686 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
4687 /* Set the OVERRIDE bit to 1 */
4688 reg_val |= EMAC_LED_OVERRIDE;
4689 /* If value is 1, set the 2500M_OVERRIDE bit, otherwise
4690 reset it.*/
4691 reg_val = (value == 1) ? (reg_val | EMAC_LED_2500MB_OVERRIDE) :
4692 (reg_val & ~EMAC_LED_2500MB_OVERRIDE);
4693 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
4694 break;
4695 case 4: /*10G led */
4696 if (port == 0) {
4697 REG_WR(bp, NIG_REG_LED_10G_P0,
4698 value);
4699 } else {
4700 REG_WR(bp, NIG_REG_LED_10G_P1,
4701 value);
4702 }
4703 break;
4704 case 5: /* TRAFFIC led */
4705 /* Find if the traffic control is via BMAC or EMAC */
4706 if (port == 0)
4707 reg_val = REG_RD(bp, NIG_REG_NIG_EMAC0_EN);
4708 else
4709 reg_val = REG_RD(bp, NIG_REG_NIG_EMAC1_EN);
4710
4711 /* Override the traffic led in the EMAC:*/
4712 if (reg_val == 1) {
4713 /* Read the current value of the LED register in
4714 the EMAC block */
4715 reg_val = REG_RD(bp, emac_base +
4716 EMAC_REG_EMAC_LED);
4717 /* Set the TRAFFIC_OVERRIDE bit to 1 */
4718 reg_val |= EMAC_LED_OVERRIDE;
4719 /* If value is 1, set the TRAFFIC bit, otherwise
4720 reset it.*/
4721 reg_val = (value == 1) ? (reg_val | EMAC_LED_TRAFFIC) :
4722 (reg_val & ~EMAC_LED_TRAFFIC);
4723 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
4724 } else { /* Override the traffic led in the BMAC: */
4725 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
4726 + port*4, 1);
4727 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 + port*4,
4728 value);
4729 }
4730 break;
4731 default:
4732 DP(NETIF_MSG_LINK,
4733 "bnx2x_override_led_value() unknown led index %d "
4734 "(should be 0-5)\n", led_idx);
4735 return -EINVAL;
4736 }
4737
4738 return 0;
4739}
4740
4741
Yaniv Rosner7846e472009-11-05 19:18:07 +02004742u8 bnx2x_set_led(struct link_params *params, u8 mode, u32 speed)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004743{
Yaniv Rosner7846e472009-11-05 19:18:07 +02004744 u8 port = params->port;
4745 u16 hw_led_mode = params->hw_led_mode;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004746 u8 rc = 0;
Eilon Greenstein345b5d52008-08-13 15:58:12 -07004747 u32 tmp;
4748 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Yaniv Rosner7846e472009-11-05 19:18:07 +02004749 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004750 DP(NETIF_MSG_LINK, "bnx2x_set_led: port %x, mode %d\n", port, mode);
4751 DP(NETIF_MSG_LINK, "speed 0x%x, hw_led_mode 0x%x\n",
4752 speed, hw_led_mode);
4753 switch (mode) {
4754 case LED_MODE_OFF:
4755 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 0);
4756 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
4757 SHARED_HW_CFG_LED_MAC1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07004758
4759 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07004760 EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp | EMAC_LED_OVERRIDE));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004761 break;
4762
4763 case LED_MODE_OPER:
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004764 if (SINGLE_MEDIA_DIRECT(params)) {
Yaniv Rosner7846e472009-11-05 19:18:07 +02004765 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0);
4766 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1);
4767 } else {
4768 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
4769 hw_led_mode);
4770 }
4771
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004772 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 +
4773 port*4, 0);
4774 /* Set blinking rate to ~15.9Hz */
4775 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4,
4776 LED_BLINK_RATE_VAL);
4777 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 +
4778 port*4, 1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07004779 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07004780 EMAC_WR(bp, EMAC_REG_EMAC_LED,
Eilon Greenstein345b5d52008-08-13 15:58:12 -07004781 (tmp & (~EMAC_LED_OVERRIDE)));
4782
Yaniv Rosner7846e472009-11-05 19:18:07 +02004783 if (CHIP_IS_E1(bp) &&
Eilon Greenstein34f80b02008-06-23 20:33:01 -07004784 ((speed == SPEED_2500) ||
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004785 (speed == SPEED_1000) ||
4786 (speed == SPEED_100) ||
4787 (speed == SPEED_10))) {
4788 /* On Everest 1 Ax chip versions for speeds less than
4789 10G LED scheme is different */
4790 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
4791 + port*4, 1);
4792 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 +
4793 port*4, 0);
4794 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_TRAFFIC_P0 +
4795 port*4, 1);
4796 }
4797 break;
4798
4799 default:
4800 rc = -EINVAL;
4801 DP(NETIF_MSG_LINK, "bnx2x_set_led: Invalid led mode %d\n",
4802 mode);
4803 break;
4804 }
4805 return rc;
4806
4807}
4808
4809u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars)
4810{
4811 struct bnx2x *bp = params->bp;
4812 u16 gp_status = 0;
4813
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004814 CL45_RD_OVER_CL22(bp, &params->phy[INT_PHY],
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004815 MDIO_REG_BANK_GP_STATUS,
4816 MDIO_GP_STATUS_TOP_AN_STATUS1,
4817 &gp_status);
4818 /* link is up only if both local phy and external phy are up */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004819 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) {
4820 u8 ext_phy_link_up = 1;
4821 struct link_vars temp_vars;
4822 if (params->phy[EXT_PHY1].read_status)
4823 ext_phy_link_up &=
4824 params->phy[EXT_PHY1].read_status(
4825 &params->phy[EXT_PHY1],
4826 params, &temp_vars);
4827 if (ext_phy_link_up)
4828 return 0;
4829 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004830
4831 return -ESRCH;
4832}
4833
4834static u8 bnx2x_link_initialize(struct link_params *params,
4835 struct link_vars *vars)
4836{
4837 struct bnx2x *bp = params->bp;
4838 u8 port = params->port;
4839 u8 rc = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004840 u8 phy_index, non_ext_phy;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004841 struct bnx2x_phy *ext_phy = &params->phy[EXT_PHY1];
4842 struct bnx2x_phy *int_phy = &params->phy[INT_PHY];
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004843 /* Activate the external PHY */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004844
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004845 bnx2x_set_aer_mmd(params, int_phy);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004846
4847 if (vars->phy_flags & PHY_XGXS_FLAG)
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004848 bnx2x_set_master_ln(params, int_phy);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004849
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004850 rc = bnx2x_reset_unicore(params, int_phy,
4851 int_phy->type ==
4852 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004853 /* reset the SerDes and wait for reset bit return low */
4854 if (rc != 0)
4855 return rc;
4856
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004857 bnx2x_set_aer_mmd(params, int_phy);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004858
4859 /* setting the masterLn_def again after the reset */
4860 if (vars->phy_flags & PHY_XGXS_FLAG) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004861 bnx2x_set_master_ln(params, int_phy);
4862 bnx2x_set_swap_lanes(params, int_phy);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004863 }
4864
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004865 if (vars->phy_flags & PHY_XGXS_FLAG) {
Eilon Greenstein44722d12009-01-14 06:44:21 +00004866 if ((params->req_line_speed &&
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004867 ((params->req_line_speed == SPEED_100) ||
Eilon Greenstein44722d12009-01-14 06:44:21 +00004868 (params->req_line_speed == SPEED_10))) ||
4869 (!params->req_line_speed &&
4870 (params->speed_cap_mask >=
4871 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL) &&
4872 (params->speed_cap_mask <
4873 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
4874 )) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004875 vars->phy_flags |= PHY_SGMII_FLAG;
4876 } else {
4877 vars->phy_flags &= ~PHY_SGMII_FLAG;
4878 }
4879 }
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004880 /* In case of external phy existance, the line speed would be the
4881 line speed linked up by the external phy. In case it is direct only,
4882 then the line_speed during initialization will be equal to the
4883 req_line_speed*/
4884 vars->line_speed = params->req_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004885
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004886 bnx2x_calc_ieee_aneg_adv(int_phy, params, &vars->ieee_fc);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004887
4888 /* init ext phy and enable link state int */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004889 non_ext_phy = ((ext_phy->type ==
4890 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ||
Eilon Greenstein8660d8c2009-03-02 08:01:02 +00004891 (params->loopback_mode == LOOPBACK_XGXS_10));
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004892
4893 if (non_ext_phy ||
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004894 (ext_phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) ||
4895 (ext_phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706) ||
4896 (ext_phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) ||
Eilon Greenstein8660d8c2009-03-02 08:01:02 +00004897 (params->loopback_mode == LOOPBACK_EXT_PHY)) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004898 if (vars->line_speed == SPEED_AUTO_NEG)
4899 bnx2x_set_parallel_detection(int_phy, params);
4900 bnx2x_init_internal_phy(int_phy, params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004901 }
4902
4903 if (!non_ext_phy)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004904 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
4905 phy_index++) {
4906 params->phy[phy_index].config_init(
4907 &params->phy[phy_index],
4908 params, vars);
4909 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004910
4911 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004912 (NIG_STATUS_XGXS0_LINK10G |
4913 NIG_STATUS_XGXS0_LINK_STATUS |
4914 NIG_STATUS_SERDES0_LINK_STATUS));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004915
4916 return rc;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004917}
4918
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004919static void set_phy_vars(struct link_params *params)
4920{
4921 struct bnx2x *bp = params->bp;
4922 u8 actual_phy_idx, phy_index;
4923
4924 for (phy_index = INT_PHY; phy_index < params->num_phys;
4925 phy_index++) {
4926
4927 actual_phy_idx = phy_index;
4928 params->phy[actual_phy_idx].req_flow_ctrl =
4929 params->req_flow_ctrl;
4930
4931 params->phy[actual_phy_idx].req_line_speed =
4932 params->req_line_speed;
4933
4934 params->phy[actual_phy_idx].speed_cap_mask =
4935 params->speed_cap_mask;
4936
4937 params->phy[actual_phy_idx].req_duplex =
4938 params->req_duplex;
4939
4940 DP(NETIF_MSG_LINK, "req_flow_ctrl %x, req_line_speed %x,"
4941 " speed_cap_mask %x\n",
4942 params->phy[actual_phy_idx].req_flow_ctrl,
4943 params->phy[actual_phy_idx].req_line_speed,
4944 params->phy[actual_phy_idx].speed_cap_mask);
4945 }
4946}
4947
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004948u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
4949{
4950 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004951 u32 val;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00004952
4953 DP(NETIF_MSG_LINK, "Phy Initialization started\n");
4954 DP(NETIF_MSG_LINK, "req_speed %d, req_flowctrl %d\n",
4955 params->req_line_speed, params->req_flow_ctrl);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004956 vars->link_status = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004957 vars->phy_link_up = 0;
4958 vars->link_up = 0;
4959 vars->line_speed = 0;
4960 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08004961 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004962 vars->mac_type = MAC_TYPE_NONE;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004963 vars->phy_flags = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004964
4965 /* disable attentions */
4966 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4,
4967 (NIG_MASK_XGXS0_LINK_STATUS |
4968 NIG_MASK_XGXS0_LINK10G |
4969 NIG_MASK_SERDES0_LINK_STATUS |
4970 NIG_MASK_MI_INT));
4971
4972 bnx2x_emac_init(params, vars);
4973
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004974 if (params->num_phys == 0) {
4975 DP(NETIF_MSG_LINK, "No phy found for initialization !!\n");
4976 return -EINVAL;
4977 }
4978 set_phy_vars(params);
4979
4980 DP(NETIF_MSG_LINK, "Num of phys on board: %d\n", params->num_phys);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004981 if (CHIP_REV_IS_FPGA(bp)) {
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00004982
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004983 vars->link_up = 1;
4984 vars->line_speed = SPEED_10000;
4985 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08004986 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004987 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
Eilon Greenstein34f80b02008-06-23 20:33:01 -07004988 /* enable on E1.5 FPGA */
4989 if (CHIP_IS_E1H(bp)) {
4990 vars->flow_ctrl |=
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00004991 (BNX2X_FLOW_CTRL_TX |
4992 BNX2X_FLOW_CTRL_RX);
Eilon Greenstein34f80b02008-06-23 20:33:01 -07004993 vars->link_status |=
4994 (LINK_STATUS_TX_FLOW_CONTROL_ENABLED |
4995 LINK_STATUS_RX_FLOW_CONTROL_ENABLED);
4996 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004997
4998 bnx2x_emac_enable(params, vars, 0);
4999 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
5000 /* disable drain */
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005001 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005002
5003 /* update shared memory */
5004 bnx2x_update_mng(params, vars->link_status);
5005
5006 return 0;
5007
5008 } else
5009 if (CHIP_REV_IS_EMUL(bp)) {
5010
5011 vars->link_up = 1;
5012 vars->line_speed = SPEED_10000;
5013 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08005014 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005015 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
5016
5017 bnx2x_bmac_enable(params, vars, 0);
5018
5019 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
5020 /* Disable drain */
5021 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
5022 + params->port*4, 0);
5023
5024 /* update shared memory */
5025 bnx2x_update_mng(params, vars->link_status);
5026
5027 return 0;
5028
5029 } else
5030 if (params->loopback_mode == LOOPBACK_BMAC) {
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005031
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005032 vars->link_up = 1;
5033 vars->line_speed = SPEED_10000;
5034 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08005035 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005036 vars->mac_type = MAC_TYPE_BMAC;
5037
5038 vars->phy_flags = PHY_XGXS_FLAG;
5039
5040 bnx2x_phy_deassert(params, vars->phy_flags);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005041
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005042 /* set bmac loopback */
5043 bnx2x_bmac_enable(params, vars, 1);
5044
5045 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
5046 params->port*4, 0);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005047
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005048 } else if (params->loopback_mode == LOOPBACK_EMAC) {
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005049
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005050 vars->link_up = 1;
5051 vars->line_speed = SPEED_1000;
5052 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08005053 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005054 vars->mac_type = MAC_TYPE_EMAC;
5055
5056 vars->phy_flags = PHY_XGXS_FLAG;
5057
5058 bnx2x_phy_deassert(params, vars->phy_flags);
5059 /* set bmac loopback */
5060 bnx2x_emac_enable(params, vars, 1);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005061 bnx2x_emac_program(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005062 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
5063 params->port*4, 0);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005064
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005065 } else if ((params->loopback_mode == LOOPBACK_XGXS_10) ||
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005066 (params->loopback_mode == LOOPBACK_EXT_PHY)) {
5067
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
5073 vars->phy_flags = PHY_XGXS_FLAG;
5074
5075 val = REG_RD(bp,
5076 NIG_REG_XGXS0_CTRL_PHY_ADDR+
5077 params->port*0x18);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005078
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005079 bnx2x_phy_deassert(params, vars->phy_flags);
5080 bnx2x_link_initialize(params, vars);
5081
5082 vars->mac_type = MAC_TYPE_BMAC;
5083
5084 bnx2x_bmac_enable(params, vars, 0);
5085
5086 if (params->loopback_mode == LOOPBACK_XGXS_10) {
5087 /* set 10G XGXS loopback */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005088 params->phy[INT_PHY].config_loopback(
5089 &params->phy[INT_PHY],
5090 params);
5091
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005092 } else {
5093 /* set external phy loopback */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005094 u8 phy_index;
5095 for (phy_index = EXT_PHY1;
5096 phy_index < params->num_phys; phy_index++) {
5097 if (params->phy[phy_index].config_loopback)
5098 params->phy[phy_index].config_loopback(
5099 &params->phy[phy_index],
Yaniv Rosner62b29a52010-09-07 11:40:58 +00005100 params);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005101 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005102 }
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005103
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005104 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
5105 params->port*4, 0);
Eilon Greensteinba71d312009-07-21 05:47:49 +00005106
Yaniv Rosner7846e472009-11-05 19:18:07 +02005107 bnx2x_set_led(params, LED_MODE_OPER, vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005108 } else
5109 /* No loopback */
5110 {
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005111 if (params->switch_cfg == SWITCH_CFG_10G)
5112 vars->phy_flags = PHY_XGXS_FLAG;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005113 bnx2x_phy_deassert(params, vars->phy_flags);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005114 bnx2x_link_initialize(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005115 msleep(30);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005116 bnx2x_link_int_enable(params);
5117 }
5118 return 0;
5119}
5120
Eilon Greenstein589abe32009-02-12 08:36:55 +00005121
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005122static void bnx2x_8726_link_reset(struct bnx2x_phy *phy,
5123 struct link_params *params)
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005124{
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005125 struct bnx2x *bp = params->bp;
5126 DP(NETIF_MSG_LINK, "bnx2x_8726_link_reset port %d\n", params->port);
Eilon Greenstein589abe32009-02-12 08:36:55 +00005127 /* Set serial boot control for external load */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005128 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005129 MDIO_PMA_DEVAD,
5130 MDIO_PMA_REG_GEN_CTRL, 0x0001);
5131}
5132
5133static void bnx2x_8727_link_reset(struct bnx2x_phy *phy,
5134 struct link_params *params)
5135{
5136 struct bnx2x *bp = params->bp;
5137 /* Disable Transmitter */
5138 bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
5139}
5140static void bnx2x_8073_link_reset(struct bnx2x_phy *phy,
5141 struct link_params *params)
5142{
5143 struct bnx2x *bp = params->bp;
5144 u8 gpio_port;
5145 gpio_port = params->port;
5146 DP(NETIF_MSG_LINK, "Setting 8073 port %d into low power mode\n",
5147 gpio_port);
5148 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
5149 MISC_REGISTERS_GPIO_OUTPUT_LOW,
5150 gpio_port);
5151}
5152static void bnx2x_8481_link_reset(struct bnx2x_phy *phy,
5153 struct link_params *params)
5154{
5155 bnx2x_cl45_write(params->bp, phy,
5156 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x0000);
5157 bnx2x_cl45_write(params->bp, phy,
5158 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1);
5159}
5160
5161static void bnx2x_848x3_link_reset(struct bnx2x_phy *phy,
5162 struct link_params *params)
5163{
5164 struct bnx2x *bp = params->bp;
5165 u8 port = params->port;
5166 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
5167 MISC_REGISTERS_GPIO_OUTPUT_LOW,
5168 port);
5169}
5170
5171static void bnx2x_common_ext_link_reset(struct bnx2x_phy *phy,
5172 struct link_params *params)
5173{
5174 struct bnx2x *bp = params->bp;
5175 u8 gpio_port;
5176 /* HW reset */
5177 gpio_port = params->port;
5178 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
5179 MISC_REGISTERS_GPIO_OUTPUT_LOW,
5180 gpio_port);
5181 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
5182 MISC_REGISTERS_GPIO_OUTPUT_LOW,
5183 gpio_port);
5184 DP(NETIF_MSG_LINK, "reset external PHY\n");
5185}
5186
5187static void bnx2x_int_link_reset(struct bnx2x_phy *phy,
5188 struct link_params *params)
5189{
5190 /* reset the SerDes/XGXS */
5191 REG_WR(params->bp, GRCBASE_MISC +
5192 MISC_REGISTERS_RESET_REG_3_CLEAR,
5193 (0x1ff << (params->port*16)));
Eilon Greenstein589abe32009-02-12 08:36:55 +00005194}
5195
5196u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
5197 u8 reset_ext_phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005198{
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005199 struct bnx2x *bp = params->bp;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005200
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005201 u8 phy_index, port = params->port;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005202
Yaniv Rosnerd5cb9e92009-11-05 19:18:10 +02005203 DP(NETIF_MSG_LINK, "Resetting the link of port %d\n", port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005204 /* disable attentions */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005205 vars->link_status = 0;
5206 bnx2x_update_mng(params, vars->link_status);
5207 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
5208 (NIG_MASK_XGXS0_LINK_STATUS |
5209 NIG_MASK_XGXS0_LINK10G |
5210 NIG_MASK_SERDES0_LINK_STATUS |
5211 NIG_MASK_MI_INT));
5212
5213 /* activate nig drain */
5214 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
5215
5216 /* disable nig egress interface */
5217 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
5218 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
5219
5220 /* Stop BigMac rx */
5221 bnx2x_bmac_rx_disable(bp, port);
5222
5223 /* disable emac */
5224 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
5225
5226 msleep(10);
5227 /* The PHY reset is controled by GPIO 1
5228 * Hold it as vars low
5229 */
5230 /* clear link led */
Yaniv Rosner7846e472009-11-05 19:18:07 +02005231 bnx2x_set_led(params, LED_MODE_OFF, 0);
Eilon Greenstein589abe32009-02-12 08:36:55 +00005232 if (reset_ext_phy) {
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005233 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
5234 phy_index++) {
5235 if (params->phy[phy_index].link_reset)
5236 params->phy[phy_index].link_reset(
5237 &params->phy[phy_index],
5238 params);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005239 }
5240 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005241
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005242 if (params->phy[INT_PHY].link_reset)
5243 params->phy[INT_PHY].link_reset(
5244 &params->phy[INT_PHY], params);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005245 /* reset BigMac */
5246 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
5247 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
5248
5249 /* disable nig ingress interface */
5250 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0);
5251 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0);
5252 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
5253 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
5254 vars->link_up = 0;
5255 return 0;
5256}
5257
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005258
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005259static u8 bnx2x_update_link_down(struct link_params *params,
5260 struct link_vars *vars)
5261{
5262 struct bnx2x *bp = params->bp;
5263 u8 port = params->port;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005264
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005265 DP(NETIF_MSG_LINK, "Port %x: Link is down\n", port);
Yaniv Rosner7846e472009-11-05 19:18:07 +02005266 bnx2x_set_led(params, LED_MODE_OFF, 0);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005267
5268 /* indicate no mac active */
5269 vars->mac_type = MAC_TYPE_NONE;
5270
5271 /* update shared memory */
5272 vars->link_status = 0;
5273 vars->line_speed = 0;
5274 bnx2x_update_mng(params, vars->link_status);
5275
5276 /* activate nig drain */
5277 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
5278
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00005279 /* disable emac */
5280 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
5281
5282 msleep(10);
5283
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005284 /* reset BigMac */
5285 bnx2x_bmac_rx_disable(bp, params->port);
5286 REG_WR(bp, GRCBASE_MISC +
5287 MISC_REGISTERS_RESET_REG_2_CLEAR,
5288 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
5289 return 0;
5290}
5291
5292static u8 bnx2x_update_link_up(struct link_params *params,
5293 struct link_vars *vars,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005294 u8 link_10g)
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005295{
5296 struct bnx2x *bp = params->bp;
5297 u8 port = params->port;
5298 u8 rc = 0;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005299
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005300 vars->link_status |= LINK_STATUS_LINK_UP;
5301 if (link_10g) {
5302 bnx2x_bmac_enable(params, vars, 0);
Yaniv Rosner7846e472009-11-05 19:18:07 +02005303 bnx2x_set_led(params, LED_MODE_OPER, SPEED_10000);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005304 } else {
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005305 rc = bnx2x_emac_program(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005306
Yaniv Rosner0c786f02009-11-05 19:18:32 +02005307 bnx2x_emac_enable(params, vars, 0);
5308
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005309 /* AN complete? */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005310 if ((vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE)
5311 && (!(vars->phy_flags & PHY_SGMII_FLAG)) &&
5312 SINGLE_MEDIA_DIRECT(params))
5313 bnx2x_set_gmii_tx_driver(params);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005314 }
5315
5316 /* PBF - link up */
5317 rc |= bnx2x_pbf_update(params, vars->flow_ctrl,
5318 vars->line_speed);
5319
5320 /* disable drain */
5321 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 0);
5322
5323 /* update shared memory */
5324 bnx2x_update_mng(params, vars->link_status);
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00005325 msleep(20);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005326 return rc;
5327}
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005328/**
5329 * The bnx2x_link_update function should be called upon link
5330 * interrupt.
5331 * Link is considered up as follows:
5332 * - DIRECT_SINGLE_MEDIA - Only XGXS link (internal link) needs
5333 * to be up
5334 * - SINGLE_MEDIA - The link between the 577xx and the external
5335 * phy (XGXS) need to up as well as the external link of the
5336 * phy (PHY_EXT1)
5337 * - DUAL_MEDIA - The link between the 577xx and the first
5338 * external phy needs to be up, and at least one of the 2
5339 * external phy link must be up.
Yaniv Rosner62b29a52010-09-07 11:40:58 +00005340 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005341u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars)
5342{
5343 struct bnx2x *bp = params->bp;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005344 struct link_vars phy_vars[MAX_PHYS];
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005345 u8 port = params->port;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005346 u8 link_10g, phy_index;
5347 u8 ext_phy_link_up = 0, cur_link_up, rc = 0;
Eilon Greenstein2f904462009-08-12 08:22:16 +00005348 u8 is_mi_int = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005349 u16 ext_phy_line_speed = 0, prev_line_speed = vars->line_speed;
5350 u8 active_external_phy = INT_PHY;
5351 vars->link_status = 0;
5352 for (phy_index = INT_PHY; phy_index < params->num_phys;
5353 phy_index++) {
5354 phy_vars[phy_index].flow_ctrl = 0;
5355 phy_vars[phy_index].link_status = 0;
5356 phy_vars[phy_index].line_speed = 0;
5357 phy_vars[phy_index].duplex = DUPLEX_FULL;
5358 phy_vars[phy_index].phy_link_up = 0;
5359 phy_vars[phy_index].link_up = 0;
5360 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005361
5362 DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n",
Eilon Greenstein2f904462009-08-12 08:22:16 +00005363 port, (vars->phy_flags & PHY_XGXS_FLAG),
5364 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005365
Eilon Greenstein2f904462009-08-12 08:22:16 +00005366 is_mi_int = (u8)(REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT +
5367 port*0x18) > 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005368 DP(NETIF_MSG_LINK, "int_mask 0x%x MI_INT %x, SERDES_LINK %x\n",
Eilon Greenstein2f904462009-08-12 08:22:16 +00005369 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
5370 is_mi_int,
5371 REG_RD(bp,
5372 NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005373
5374 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
5375 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
5376 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
5377
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00005378 /* disable emac */
5379 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
5380
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005381 /**
5382 * Step 1:
5383 * Check external link change only for external phys, and apply
5384 * priority selection between them in case the link on both phys
5385 * is up. Note that the instead of the common vars, a temporary
5386 * vars argument is used since each phy may have different link/
5387 * speed/duplex result
5388 */
5389 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
5390 phy_index++) {
5391 struct bnx2x_phy *phy = &params->phy[phy_index];
5392 if (!phy->read_status)
5393 continue;
5394 /* Read link status and params of this ext phy */
5395 cur_link_up = phy->read_status(phy, params,
5396 &phy_vars[phy_index]);
5397 if (cur_link_up) {
5398 DP(NETIF_MSG_LINK, "phy in index %d link is up\n",
5399 phy_index);
5400 } else {
5401 DP(NETIF_MSG_LINK, "phy in index %d link is down\n",
5402 phy_index);
5403 continue;
5404 }
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005405
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005406 if (!ext_phy_link_up) {
5407 ext_phy_link_up = 1;
5408 active_external_phy = phy_index;
5409 }
5410 }
5411 prev_line_speed = vars->line_speed;
5412 /**
5413 * Step 2:
5414 * Read the status of the internal phy. In case of
5415 * DIRECT_SINGLE_MEDIA board, this link is the external link,
5416 * otherwise this is the link between the 577xx and the first
5417 * external phy
5418 */
5419 if (params->phy[INT_PHY].read_status)
5420 params->phy[INT_PHY].read_status(
5421 &params->phy[INT_PHY],
5422 params, vars);
5423 /**
5424 * The INT_PHY flow control reside in the vars. This include the
5425 * case where the speed or flow control are not set to AUTO.
5426 * Otherwise, the active external phy flow control result is set
5427 * to the vars. The ext_phy_line_speed is needed to check if the
5428 * speed is different between the internal phy and external phy.
5429 * This case may be result of intermediate link speed change.
5430 */
5431 if (active_external_phy > INT_PHY) {
5432 vars->flow_ctrl = phy_vars[active_external_phy].flow_ctrl;
5433 /**
5434 * Link speed is taken from the XGXS. AN and FC result from
5435 * the external phy.
5436 */
5437 vars->link_status |= phy_vars[active_external_phy].link_status;
5438 ext_phy_line_speed = phy_vars[active_external_phy].line_speed;
5439 vars->duplex = phy_vars[active_external_phy].duplex;
5440 if (params->phy[active_external_phy].supported &
5441 SUPPORTED_FIBRE)
5442 vars->link_status |= LINK_STATUS_SERDES_LINK;
5443 DP(NETIF_MSG_LINK, "Active external phy selected: %x\n",
5444 active_external_phy);
5445 }
5446 DP(NETIF_MSG_LINK, "vars->flow_ctrl = 0x%x, vars->link_status = 0x%x,"
5447 " ext_phy_line_speed = %d\n", vars->flow_ctrl,
5448 vars->link_status, ext_phy_line_speed);
5449 /**
5450 * Upon link speed change set the NIG into drain mode. Comes to
5451 * deals with possible FIFO glitch due to clk change when speed
5452 * is decreased without link down indicator
5453 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005454
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005455 if (vars->phy_link_up) {
5456 if (!(SINGLE_MEDIA_DIRECT(params)) && ext_phy_link_up &&
5457 (ext_phy_line_speed != vars->line_speed)) {
5458 DP(NETIF_MSG_LINK, "Internal link speed %d is"
5459 " different than the external"
5460 " link speed %d\n", vars->line_speed,
5461 ext_phy_line_speed);
5462 vars->phy_link_up = 0;
5463 } else if (prev_line_speed != vars->line_speed) {
5464 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
5465 + params->port*4, 0);
5466 msleep(1);
5467 }
5468 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005469
5470 /* anything 10 and over uses the bmac */
5471 link_10g = ((vars->line_speed == SPEED_10000) ||
5472 (vars->line_speed == SPEED_12000) ||
5473 (vars->line_speed == SPEED_12500) ||
5474 (vars->line_speed == SPEED_13000) ||
5475 (vars->line_speed == SPEED_15000) ||
5476 (vars->line_speed == SPEED_16000));
5477
Eilon Greenstein2f904462009-08-12 08:22:16 +00005478 bnx2x_link_int_ack(params, vars, link_10g, is_mi_int);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005479
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005480 /**
5481 * In case external phy link is up, and internal link is down
5482 * (not initialized yet probably after link initialization, it
5483 * needs to be initialized.
5484 * Note that after link down-up as result of cable plug, the xgxs
5485 * link would probably become up again without the need
5486 * initialize it
5487 */
5488 if (!(SINGLE_MEDIA_DIRECT(params))) {
5489 DP(NETIF_MSG_LINK, "ext_phy_link_up = %d, int_link_up = %d,"
5490 " init_preceding = %d\n", ext_phy_link_up,
5491 vars->phy_link_up,
5492 params->phy[EXT_PHY1].flags &
5493 FLAGS_INIT_XGXS_FIRST);
5494 if (!(params->phy[EXT_PHY1].flags &
5495 FLAGS_INIT_XGXS_FIRST)
5496 && ext_phy_link_up && !vars->phy_link_up) {
5497 vars->line_speed = ext_phy_line_speed;
5498 if (vars->line_speed < SPEED_1000)
5499 vars->phy_flags |= PHY_SGMII_FLAG;
5500 else
5501 vars->phy_flags &= ~PHY_SGMII_FLAG;
5502 bnx2x_init_internal_phy(&params->phy[INT_PHY],
5503 params,
5504 vars);
5505 }
5506 }
5507 /**
5508 * Link is up only if both local phy and external phy (in case of
5509 * non-direct board) are up
5510 */
5511 vars->link_up = (vars->phy_link_up &&
5512 (ext_phy_link_up ||
5513 SINGLE_MEDIA_DIRECT(params)));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005514
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005515 if (vars->link_up)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005516 rc = bnx2x_update_link_up(params, vars, link_10g);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005517 else
5518 rc = bnx2x_update_link_down(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005519
5520 return rc;
5521}
5522
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005523static void bnx2x_8481_hw_reset(struct bnx2x_phy *phy,
5524 struct link_params *params)
5525{
5526 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
5527 MISC_REGISTERS_GPIO_OUTPUT_LOW, 0);
5528 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
5529 MISC_REGISTERS_GPIO_OUTPUT_LOW, 1);
5530}
5531
5532static void bnx2x_8727_hw_reset(struct bnx2x_phy *phy,
5533 struct link_params *params) {
5534 u32 swap_val, swap_override;
5535 u8 port;
5536 /**
5537 * The PHY reset is controlled by GPIO 1. Fake the port number
5538 * to cancel the swap done in set_gpio()
5539 */
5540 struct bnx2x *bp = params->bp;
5541 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
5542 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
5543 port = (swap_val && swap_override) ^ 1;
5544 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
5545 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
5546}
5547
5548static void bnx2x_7101_hw_reset(struct bnx2x_phy *phy,
5549 struct link_params *params) {
5550 /* Low power mode is controlled by GPIO 2 */
5551 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_2,
5552 MISC_REGISTERS_GPIO_OUTPUT_LOW, params->port);
5553 /* The PHY reset is controlled by GPIO 1 */
5554 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
5555 MISC_REGISTERS_GPIO_OUTPUT_LOW, params->port);
5556}
5557/******************************************************************/
5558/* STATIC PHY DECLARATION */
5559/******************************************************************/
5560
5561static struct bnx2x_phy phy_null = {
5562 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN,
5563 .addr = 0,
5564 .flags = FLAGS_INIT_XGXS_FIRST,
5565 .def_md_devad = 0,
5566 .reserved = 0,
5567 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5568 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5569 .mdio_ctrl = 0,
5570 .supported = 0,
5571 .media_type = ETH_PHY_NOT_PRESENT,
5572 .ver_addr = 0,
5573 .req_flow_ctrl = 0,
5574 .req_line_speed = 0,
5575 .speed_cap_mask = 0,
5576 .req_duplex = 0,
5577 .rsrv = 0,
5578 .config_init = (config_init_t)NULL,
5579 .read_status = (read_status_t)NULL,
5580 .link_reset = (link_reset_t)NULL,
5581 .config_loopback = (config_loopback_t)NULL,
5582 .format_fw_ver = (format_fw_ver_t)NULL,
5583 .hw_reset = (hw_reset_t)NULL,
5584 .set_link_led = (set_link_led_t)NULL
5585};
5586
5587static struct bnx2x_phy phy_serdes = {
5588 .type = PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT,
5589 .addr = 0xff,
5590 .flags = 0,
5591 .def_md_devad = 0,
5592 .reserved = 0,
5593 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5594 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5595 .mdio_ctrl = 0,
5596 .supported = (SUPPORTED_10baseT_Half |
5597 SUPPORTED_10baseT_Full |
5598 SUPPORTED_100baseT_Half |
5599 SUPPORTED_100baseT_Full |
5600 SUPPORTED_1000baseT_Full |
5601 SUPPORTED_2500baseX_Full |
5602 SUPPORTED_TP |
5603 SUPPORTED_Autoneg |
5604 SUPPORTED_Pause |
5605 SUPPORTED_Asym_Pause),
5606 .media_type = ETH_PHY_UNSPECIFIED,
5607 .ver_addr = 0,
5608 .req_flow_ctrl = 0,
5609 .req_line_speed = 0,
5610 .speed_cap_mask = 0,
5611 .req_duplex = 0,
5612 .rsrv = 0,
5613 .config_init = (config_init_t)bnx2x_init_serdes,
5614 .read_status = (read_status_t)bnx2x_link_settings_status,
5615 .link_reset = (link_reset_t)bnx2x_int_link_reset,
5616 .config_loopback = (config_loopback_t)NULL,
5617 .format_fw_ver = (format_fw_ver_t)NULL,
5618 .hw_reset = (hw_reset_t)NULL,
5619 .set_link_led = (set_link_led_t)NULL
5620};
5621
5622static struct bnx2x_phy phy_xgxs = {
5623 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT,
5624 .addr = 0xff,
5625 .flags = 0,
5626 .def_md_devad = 0,
5627 .reserved = 0,
5628 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5629 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5630 .mdio_ctrl = 0,
5631 .supported = (SUPPORTED_10baseT_Half |
5632 SUPPORTED_10baseT_Full |
5633 SUPPORTED_100baseT_Half |
5634 SUPPORTED_100baseT_Full |
5635 SUPPORTED_1000baseT_Full |
5636 SUPPORTED_2500baseX_Full |
5637 SUPPORTED_10000baseT_Full |
5638 SUPPORTED_FIBRE |
5639 SUPPORTED_Autoneg |
5640 SUPPORTED_Pause |
5641 SUPPORTED_Asym_Pause),
5642 .media_type = ETH_PHY_UNSPECIFIED,
5643 .ver_addr = 0,
5644 .req_flow_ctrl = 0,
5645 .req_line_speed = 0,
5646 .speed_cap_mask = 0,
5647 .req_duplex = 0,
5648 .rsrv = 0,
5649 .config_init = (config_init_t)bnx2x_init_xgxs,
5650 .read_status = (read_status_t)bnx2x_link_settings_status,
5651 .link_reset = (link_reset_t)bnx2x_int_link_reset,
5652 .config_loopback = (config_loopback_t)bnx2x_set_xgxs_loopback,
5653 .format_fw_ver = (format_fw_ver_t)NULL,
5654 .hw_reset = (hw_reset_t)NULL,
5655 .set_link_led = (set_link_led_t)NULL
5656};
5657
5658static struct bnx2x_phy phy_7101 = {
5659 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5660 .addr = 0xff,
5661 .flags = FLAGS_FAN_FAILURE_DET_REQ,
5662 .def_md_devad = 0,
5663 .reserved = 0,
5664 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5665 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5666 .mdio_ctrl = 0,
5667 .supported = (SUPPORTED_10000baseT_Full |
5668 SUPPORTED_TP |
5669 SUPPORTED_Autoneg |
5670 SUPPORTED_Pause |
5671 SUPPORTED_Asym_Pause),
5672 .media_type = ETH_PHY_BASE_T,
5673 .ver_addr = 0,
5674 .req_flow_ctrl = 0,
5675 .req_line_speed = 0,
5676 .speed_cap_mask = 0,
5677 .req_duplex = 0,
5678 .rsrv = 0,
5679 .config_init = (config_init_t)bnx2x_7101_config_init,
5680 .read_status = (read_status_t)bnx2x_7101_read_status,
5681 .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
5682 .config_loopback = (config_loopback_t)bnx2x_7101_config_loopback,
5683 .format_fw_ver = (format_fw_ver_t)bnx2x_7101_format_ver,
5684 .hw_reset = (hw_reset_t)bnx2x_7101_hw_reset,
5685 .set_link_led = (set_link_led_t)NULL
5686};
5687static struct bnx2x_phy phy_8073 = {
5688 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5689 .addr = 0xff,
5690 .flags = FLAGS_HW_LOCK_REQUIRED,
5691 .def_md_devad = 0,
5692 .reserved = 0,
5693 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5694 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5695 .mdio_ctrl = 0,
5696 .supported = (SUPPORTED_10000baseT_Full |
5697 SUPPORTED_2500baseX_Full |
5698 SUPPORTED_1000baseT_Full |
5699 SUPPORTED_FIBRE |
5700 SUPPORTED_Autoneg |
5701 SUPPORTED_Pause |
5702 SUPPORTED_Asym_Pause),
5703 .media_type = ETH_PHY_UNSPECIFIED,
5704 .ver_addr = 0,
5705 .req_flow_ctrl = 0,
5706 .req_line_speed = 0,
5707 .speed_cap_mask = 0,
5708 .req_duplex = 0,
5709 .rsrv = 0,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00005710 .config_init = (config_init_t)bnx2x_8073_config_init,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005711 .read_status = (read_status_t)bnx2x_8073_read_status,
5712 .link_reset = (link_reset_t)bnx2x_8073_link_reset,
5713 .config_loopback = (config_loopback_t)NULL,
5714 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
5715 .hw_reset = (hw_reset_t)NULL,
5716 .set_link_led = (set_link_led_t)NULL
5717};
5718static struct bnx2x_phy phy_8705 = {
5719 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705,
5720 .addr = 0xff,
5721 .flags = FLAGS_INIT_XGXS_FIRST,
5722 .def_md_devad = 0,
5723 .reserved = 0,
5724 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5725 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5726 .mdio_ctrl = 0,
5727 .supported = (SUPPORTED_10000baseT_Full |
5728 SUPPORTED_FIBRE |
5729 SUPPORTED_Pause |
5730 SUPPORTED_Asym_Pause),
5731 .media_type = ETH_PHY_XFP_FIBER,
5732 .ver_addr = 0,
5733 .req_flow_ctrl = 0,
5734 .req_line_speed = 0,
5735 .speed_cap_mask = 0,
5736 .req_duplex = 0,
5737 .rsrv = 0,
5738 .config_init = (config_init_t)bnx2x_8705_config_init,
5739 .read_status = (read_status_t)bnx2x_8705_read_status,
5740 .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
5741 .config_loopback = (config_loopback_t)NULL,
5742 .format_fw_ver = (format_fw_ver_t)bnx2x_null_format_ver,
5743 .hw_reset = (hw_reset_t)NULL,
5744 .set_link_led = (set_link_led_t)NULL
5745};
5746static struct bnx2x_phy phy_8706 = {
5747 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706,
5748 .addr = 0xff,
5749 .flags = FLAGS_INIT_XGXS_FIRST,
5750 .def_md_devad = 0,
5751 .reserved = 0,
5752 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5753 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5754 .mdio_ctrl = 0,
5755 .supported = (SUPPORTED_10000baseT_Full |
5756 SUPPORTED_1000baseT_Full |
5757 SUPPORTED_FIBRE |
5758 SUPPORTED_Pause |
5759 SUPPORTED_Asym_Pause),
5760 .media_type = ETH_PHY_SFP_FIBER,
5761 .ver_addr = 0,
5762 .req_flow_ctrl = 0,
5763 .req_line_speed = 0,
5764 .speed_cap_mask = 0,
5765 .req_duplex = 0,
5766 .rsrv = 0,
5767 .config_init = (config_init_t)bnx2x_8706_config_init,
5768 .read_status = (read_status_t)bnx2x_8706_read_status,
5769 .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
5770 .config_loopback = (config_loopback_t)NULL,
5771 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
5772 .hw_reset = (hw_reset_t)NULL,
5773 .set_link_led = (set_link_led_t)NULL
5774};
5775
5776static struct bnx2x_phy phy_8726 = {
5777 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
5778 .addr = 0xff,
5779 .flags = (FLAGS_HW_LOCK_REQUIRED |
5780 FLAGS_INIT_XGXS_FIRST),
5781 .def_md_devad = 0,
5782 .reserved = 0,
5783 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5784 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5785 .mdio_ctrl = 0,
5786 .supported = (SUPPORTED_10000baseT_Full |
5787 SUPPORTED_1000baseT_Full |
5788 SUPPORTED_Autoneg |
5789 SUPPORTED_FIBRE |
5790 SUPPORTED_Pause |
5791 SUPPORTED_Asym_Pause),
5792 .media_type = ETH_PHY_SFP_FIBER,
5793 .ver_addr = 0,
5794 .req_flow_ctrl = 0,
5795 .req_line_speed = 0,
5796 .speed_cap_mask = 0,
5797 .req_duplex = 0,
5798 .rsrv = 0,
5799 .config_init = (config_init_t)bnx2x_8726_config_init,
5800 .read_status = (read_status_t)bnx2x_8726_read_status,
5801 .link_reset = (link_reset_t)bnx2x_8726_link_reset,
5802 .config_loopback = (config_loopback_t)bnx2x_8726_config_loopback,
5803 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
5804 .hw_reset = (hw_reset_t)NULL,
5805 .set_link_led = (set_link_led_t)NULL
5806};
5807
5808static struct bnx2x_phy phy_8727 = {
5809 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
5810 .addr = 0xff,
5811 .flags = FLAGS_FAN_FAILURE_DET_REQ,
5812 .def_md_devad = 0,
5813 .reserved = 0,
5814 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5815 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5816 .mdio_ctrl = 0,
5817 .supported = (SUPPORTED_10000baseT_Full |
5818 SUPPORTED_1000baseT_Full |
5819 SUPPORTED_Autoneg |
5820 SUPPORTED_FIBRE |
5821 SUPPORTED_Pause |
5822 SUPPORTED_Asym_Pause),
5823 .media_type = ETH_PHY_SFP_FIBER,
5824 .ver_addr = 0,
5825 .req_flow_ctrl = 0,
5826 .req_line_speed = 0,
5827 .speed_cap_mask = 0,
5828 .req_duplex = 0,
5829 .rsrv = 0,
5830 .config_init = (config_init_t)bnx2x_8727_config_init,
5831 .read_status = (read_status_t)bnx2x_8727_read_status,
5832 .link_reset = (link_reset_t)bnx2x_8727_link_reset,
5833 .config_loopback = (config_loopback_t)NULL,
5834 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
5835 .hw_reset = (hw_reset_t)bnx2x_8727_hw_reset,
5836 .set_link_led = (set_link_led_t)NULL
5837};
5838static struct bnx2x_phy phy_8481 = {
5839 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
5840 .addr = 0xff,
5841 .flags = FLAGS_FAN_FAILURE_DET_REQ,
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_10baseT_Half |
5848 SUPPORTED_10baseT_Full |
5849 SUPPORTED_100baseT_Half |
5850 SUPPORTED_100baseT_Full |
5851 SUPPORTED_1000baseT_Full |
5852 SUPPORTED_10000baseT_Full |
5853 SUPPORTED_TP |
5854 SUPPORTED_Autoneg |
5855 SUPPORTED_Pause |
5856 SUPPORTED_Asym_Pause),
5857 .media_type = ETH_PHY_BASE_T,
5858 .ver_addr = 0,
5859 .req_flow_ctrl = 0,
5860 .req_line_speed = 0,
5861 .speed_cap_mask = 0,
5862 .req_duplex = 0,
5863 .rsrv = 0,
5864 .config_init = (config_init_t)bnx2x_8481_config_init,
5865 .read_status = (read_status_t)bnx2x_848xx_read_status,
5866 .link_reset = (link_reset_t)bnx2x_8481_link_reset,
5867 .config_loopback = (config_loopback_t)NULL,
5868 .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver,
5869 .hw_reset = (hw_reset_t)bnx2x_8481_hw_reset,
5870 .set_link_led = (set_link_led_t)NULL
5871};
5872
5873static struct bnx2x_phy phy_84823 = {
5874 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823,
5875 .addr = 0xff,
5876 .flags = FLAGS_FAN_FAILURE_DET_REQ,
5877 .def_md_devad = 0,
5878 .reserved = 0,
5879 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5880 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5881 .mdio_ctrl = 0,
5882 .supported = (SUPPORTED_10baseT_Half |
5883 SUPPORTED_10baseT_Full |
5884 SUPPORTED_100baseT_Half |
5885 SUPPORTED_100baseT_Full |
5886 SUPPORTED_1000baseT_Full |
5887 SUPPORTED_10000baseT_Full |
5888 SUPPORTED_TP |
5889 SUPPORTED_Autoneg |
5890 SUPPORTED_Pause |
5891 SUPPORTED_Asym_Pause),
5892 .media_type = ETH_PHY_BASE_T,
5893 .ver_addr = 0,
5894 .req_flow_ctrl = 0,
5895 .req_line_speed = 0,
5896 .speed_cap_mask = 0,
5897 .req_duplex = 0,
5898 .rsrv = 0,
5899 .config_init = (config_init_t)bnx2x_848x3_config_init,
5900 .read_status = (read_status_t)bnx2x_848xx_read_status,
5901 .link_reset = (link_reset_t)bnx2x_848x3_link_reset,
5902 .config_loopback = (config_loopback_t)NULL,
5903 .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver,
5904 .hw_reset = (hw_reset_t)NULL,
5905 .set_link_led = (set_link_led_t)NULL
5906};
5907
5908/*****************************************************************/
5909/* */
5910/* Populate the phy according. Main function: bnx2x_populate_phy */
5911/* */
5912/*****************************************************************/
5913
5914static void bnx2x_populate_preemphasis(struct bnx2x *bp, u32 shmem_base,
5915 struct bnx2x_phy *phy, u8 port,
5916 u8 phy_index)
5917{
5918 /* Get the 4 lanes xgxs config rx and tx */
5919 u32 rx = 0, tx = 0, i;
5920 for (i = 0; i < 2; i++) {
5921 /**
5922 * INT_PHY and EXT_PHY1 share the same value location in the
5923 * shmem. When num_phys is greater than 1, than this value
5924 * applies only to EXT_PHY1
5925 */
5926
5927 rx = REG_RD(bp, shmem_base +
5928 offsetof(struct shmem_region,
5929 dev_info.port_hw_config[port].xgxs_config_rx[i<<1]));
5930
5931 tx = REG_RD(bp, shmem_base +
5932 offsetof(struct shmem_region,
5933 dev_info.port_hw_config[port].xgxs_config_tx[i<<1]));
5934
5935 phy->rx_preemphasis[i << 1] = ((rx>>16) & 0xffff);
5936 phy->rx_preemphasis[(i << 1) + 1] = (rx & 0xffff);
5937
5938 phy->tx_preemphasis[i << 1] = ((tx>>16) & 0xffff);
5939 phy->tx_preemphasis[(i << 1) + 1] = (tx & 0xffff);
5940 }
5941}
5942
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005943static u32 bnx2x_get_ext_phy_config(struct bnx2x *bp, u32 shmem_base,
5944 u8 phy_index, u8 port)
5945{
5946 u32 ext_phy_config = 0;
5947 switch (phy_index) {
5948 case EXT_PHY1:
5949 ext_phy_config = REG_RD(bp, shmem_base +
5950 offsetof(struct shmem_region,
5951 dev_info.port_hw_config[port].external_phy_config));
5952 break;
5953 default:
5954 DP(NETIF_MSG_LINK, "Invalid phy_index %d\n", phy_index);
5955 return -EINVAL;
5956 }
5957
5958 return ext_phy_config;
5959}
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005960static u8 bnx2x_populate_int_phy(struct bnx2x *bp, u32 shmem_base, u8 port,
5961 struct bnx2x_phy *phy)
5962{
5963 u32 phy_addr;
5964 u32 chip_id;
5965 u32 switch_cfg = (REG_RD(bp, shmem_base +
5966 offsetof(struct shmem_region,
5967 dev_info.port_feature_config[port].link_config)) &
5968 PORT_FEATURE_CONNECTED_SWITCH_MASK);
5969 chip_id = REG_RD(bp, MISC_REG_CHIP_NUM) << 16;
5970 switch (switch_cfg) {
5971 case SWITCH_CFG_1G:
5972 phy_addr = REG_RD(bp,
5973 NIG_REG_SERDES0_CTRL_PHY_ADDR +
5974 port * 0x10);
5975 *phy = phy_serdes;
5976 break;
5977 case SWITCH_CFG_10G:
5978 phy_addr = REG_RD(bp,
5979 NIG_REG_XGXS0_CTRL_PHY_ADDR +
5980 port * 0x18);
5981 *phy = phy_xgxs;
5982 break;
5983 default:
5984 DP(NETIF_MSG_LINK, "Invalid switch_cfg\n");
5985 return -EINVAL;
5986 }
5987 phy->addr = (u8)phy_addr;
5988 phy->mdio_ctrl = bnx2x_get_emac_base(bp,
5989 phy->type,
5990 port);
5991 phy->def_md_devad = DEFAULT_PHY_DEV_ADDR;
5992
5993 DP(NETIF_MSG_LINK, "Internal phy port=%d, addr=0x%x, mdio_ctl=0x%x\n",
5994 port, phy->addr, phy->mdio_ctrl);
5995
5996 bnx2x_populate_preemphasis(bp, shmem_base, phy, port, INT_PHY);
5997 return 0;
5998}
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005999
6000static u8 bnx2x_populate_ext_phy(struct bnx2x *bp,
6001 u8 phy_index,
6002 u32 shmem_base,
6003 u8 port,
6004 struct bnx2x_phy *phy)
6005{
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006006 u32 ext_phy_config, phy_type;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006007
6008 ext_phy_config = bnx2x_get_ext_phy_config(bp, shmem_base,
6009 phy_index, port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006010 phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
6011 /* Select the phy type */
6012 switch (phy_type) {
6013 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
6014 *phy = phy_8073;
6015 break;
6016 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
6017 *phy = phy_8705;
6018 break;
6019 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
6020 *phy = phy_8706;
6021 break;
6022 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
6023 *phy = phy_8726;
6024 break;
6025 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
6026 /* BCM8727_NOC => BCM8727 no over current */
6027 *phy = phy_8727;
6028 phy->flags |= FLAGS_NOC;
6029 break;
6030 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
6031 *phy = phy_8727;
6032 break;
6033 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
6034 *phy = phy_8481;
6035 break;
6036 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
6037 *phy = phy_84823;
6038 break;
6039 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
6040 *phy = phy_7101;
6041 break;
6042 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
6043 *phy = phy_null;
6044 return -EINVAL;
6045 default:
6046 *phy = phy_null;
6047 return 0;
6048 }
6049
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006050 phy->addr = XGXS_EXT_PHY_ADDR(ext_phy_config);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006051 bnx2x_populate_preemphasis(bp, shmem_base, phy, port, phy_index);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006052 phy->mdio_ctrl = bnx2x_get_emac_base(bp, phy->type, port);
Yaniv Rosner62b29a52010-09-07 11:40:58 +00006053
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006054 return 0;
6055}
6056
6057static u8 bnx2x_populate_phy(struct bnx2x *bp, u8 phy_index, u32 shmem_base,
6058 u8 port, struct bnx2x_phy *phy)
6059{
6060 u8 status = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006061 phy->type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN;
6062 if (phy_index == INT_PHY)
6063 return bnx2x_populate_int_phy(bp, shmem_base, port, phy);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006064 status = bnx2x_populate_ext_phy(bp, phy_index, shmem_base,
6065 port, phy);
6066 return status;
6067}
6068
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006069static void bnx2x_phy_def_cfg(struct link_params *params,
6070 struct bnx2x_phy *phy,
6071 u8 actual_phy_idx)
6072{
6073 struct bnx2x *bp = params->bp;
6074 u32 link_config;
6075 /* Populate the default phy configuration for MF mode */
6076 link_config = REG_RD(bp, params->shmem_base +
6077 offsetof(struct shmem_region, dev_info.
6078 port_feature_config[params->port].link_config));
6079 phy->speed_cap_mask = REG_RD(bp, params->shmem_base +
6080 offsetof(struct shmem_region, dev_info.
6081 port_hw_config[params->port].speed_capability_mask));
6082
6083 phy->req_duplex = DUPLEX_FULL;
6084 switch (link_config & PORT_FEATURE_LINK_SPEED_MASK) {
6085 case PORT_FEATURE_LINK_SPEED_10M_HALF:
6086 phy->req_duplex = DUPLEX_HALF;
6087 case PORT_FEATURE_LINK_SPEED_10M_FULL:
6088 phy->req_line_speed = SPEED_10;
6089 break;
6090 case PORT_FEATURE_LINK_SPEED_100M_HALF:
6091 phy->req_duplex = DUPLEX_HALF;
6092 case PORT_FEATURE_LINK_SPEED_100M_FULL:
6093 phy->req_line_speed = SPEED_100;
6094 break;
6095 case PORT_FEATURE_LINK_SPEED_1G:
6096 phy->req_line_speed = SPEED_1000;
6097 break;
6098 case PORT_FEATURE_LINK_SPEED_2_5G:
6099 phy->req_line_speed = SPEED_2500;
6100 break;
6101 case PORT_FEATURE_LINK_SPEED_10G_CX4:
6102 phy->req_line_speed = SPEED_10000;
6103 break;
6104 default:
6105 phy->req_line_speed = SPEED_AUTO_NEG;
6106 break;
6107 }
6108
6109 switch (link_config & PORT_FEATURE_FLOW_CONTROL_MASK) {
6110 case PORT_FEATURE_FLOW_CONTROL_AUTO:
6111 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_AUTO;
6112 break;
6113 case PORT_FEATURE_FLOW_CONTROL_TX:
6114 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_TX;
6115 break;
6116 case PORT_FEATURE_FLOW_CONTROL_RX:
6117 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_RX;
6118 break;
6119 case PORT_FEATURE_FLOW_CONTROL_BOTH:
6120 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_BOTH;
6121 break;
6122 default:
6123 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_NONE;
6124 break;
6125 }
6126}
6127
6128u8 bnx2x_phy_probe(struct link_params *params)
6129{
6130 u8 phy_index, actual_phy_idx, link_cfg_idx;
6131
6132 struct bnx2x *bp = params->bp;
6133 struct bnx2x_phy *phy;
6134 params->num_phys = 0;
6135 DP(NETIF_MSG_LINK, "Begin phy probe\n");
6136
6137 for (phy_index = INT_PHY; phy_index < MAX_PHYS;
6138 phy_index++) {
6139 link_cfg_idx = LINK_CONFIG_IDX(phy_index);
6140 actual_phy_idx = phy_index;
6141
6142 phy = &params->phy[actual_phy_idx];
6143 if (bnx2x_populate_phy(bp, phy_index, params->shmem_base,
6144 params->port,
6145 phy) != 0) {
6146 params->num_phys = 0;
6147 DP(NETIF_MSG_LINK, "phy probe failed in phy index %d\n",
6148 phy_index);
6149 for (phy_index = INT_PHY;
6150 phy_index < MAX_PHYS;
6151 phy_index++)
6152 *phy = phy_null;
6153 return -EINVAL;
6154 }
6155 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)
6156 break;
6157
6158 bnx2x_phy_def_cfg(params, phy, actual_phy_idx);
6159 params->num_phys++;
6160 }
6161
6162 DP(NETIF_MSG_LINK, "End phy probe. #phys found %x\n", params->num_phys);
6163 return 0;
6164}
6165
6166u32 bnx2x_supported_attr(struct link_params *params, u8 phy_idx)
6167{
6168 if (phy_idx < params->num_phys)
6169 return params->phy[phy_idx].supported;
6170 return 0;
6171}
6172
6173
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006174static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base)
6175{
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006176 struct bnx2x_phy phy[PORT_MAX];
6177 struct bnx2x_phy *phy_blk[PORT_MAX];
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006178 u16 val;
6179 s8 port;
6180
6181 /* PART1 - Reset both phys */
6182 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
6183 /* Extract the ext phy address for the port */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006184 if (bnx2x_populate_phy(bp, EXT_PHY1, shmem_base,
6185 port, &phy[port]) !=
6186 0) {
6187 DP(NETIF_MSG_LINK, "populate_phy failed\n");
6188 return -EINVAL;
6189 }
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006190 /* disable attentions */
6191 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
6192 (NIG_MASK_XGXS0_LINK_STATUS |
6193 NIG_MASK_XGXS0_LINK10G |
6194 NIG_MASK_SERDES0_LINK_STATUS |
6195 NIG_MASK_MI_INT));
6196
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006197 /* Need to take the phy out of low power mode in order
6198 to write to access its registers */
6199 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
6200 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
6201
6202 /* Reset the phy */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006203 bnx2x_cl45_write(bp, &phy[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006204 MDIO_PMA_DEVAD,
6205 MDIO_PMA_REG_CTRL,
6206 1<<15);
6207 }
6208
6209 /* Add delay of 150ms after reset */
6210 msleep(150);
6211
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006212 if (phy[PORT_0].addr & 0x1) {
6213 phy_blk[PORT_0] = &(phy[PORT_1]);
6214 phy_blk[PORT_1] = &(phy[PORT_0]);
6215 } else {
6216 phy_blk[PORT_0] = &(phy[PORT_0]);
6217 phy_blk[PORT_1] = &(phy[PORT_1]);
6218 }
6219
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006220 /* PART2 - Download firmware to both phys */
6221 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
6222 u16 fw_ver1;
6223
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006224 bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port],
6225 port, shmem_base);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006226
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006227 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006228 MDIO_PMA_DEVAD,
6229 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
Eilon Greenstein16b311c2009-01-14 06:44:24 +00006230 if (fw_ver1 == 0 || fw_ver1 == 0x4321) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006231 DP(NETIF_MSG_LINK,
Eilon Greenstein16b311c2009-01-14 06:44:24 +00006232 "bnx2x_8073_common_init_phy port %x:"
6233 "Download failed. fw version = 0x%x\n",
6234 port, fw_ver1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006235 return -EINVAL;
6236 }
6237
6238 /* Only set bit 10 = 1 (Tx power down) */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006239 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006240 MDIO_PMA_DEVAD,
6241 MDIO_PMA_REG_TX_POWER_DOWN, &val);
6242
6243 /* Phase1 of TX_POWER_DOWN reset */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006244 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006245 MDIO_PMA_DEVAD,
6246 MDIO_PMA_REG_TX_POWER_DOWN,
6247 (val | 1<<10));
6248 }
6249
6250 /* Toggle Transmitter: Power down and then up with 600ms
6251 delay between */
6252 msleep(600);
6253
6254 /* PART3 - complete TX_POWER_DOWN process, and set GPIO2 back to low */
6255 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Eilon Greensteinf5372252009-02-12 08:38:30 +00006256 /* Phase2 of POWER_DOWN_RESET */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006257 /* Release bit 10 (Release Tx power down) */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006258 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006259 MDIO_PMA_DEVAD,
6260 MDIO_PMA_REG_TX_POWER_DOWN, &val);
6261
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006262 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006263 MDIO_PMA_DEVAD,
6264 MDIO_PMA_REG_TX_POWER_DOWN, (val & (~(1<<10))));
6265 msleep(15);
6266
6267 /* Read modify write the SPI-ROM version select register */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006268 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006269 MDIO_PMA_DEVAD,
6270 MDIO_PMA_REG_EDC_FFE_MAIN, &val);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006271 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006272 MDIO_PMA_DEVAD,
6273 MDIO_PMA_REG_EDC_FFE_MAIN, (val | (1<<12)));
6274
6275 /* set GPIO2 back to LOW */
6276 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
6277 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
6278 }
6279 return 0;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006280}
6281
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006282static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base)
6283{
Eilon Greensteinbc7f0a02009-08-12 08:23:01 +00006284 s8 port, first_port, i;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006285 u32 swap_val, swap_override;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006286 struct bnx2x_phy phy[PORT_MAX];
6287 struct bnx2x_phy *phy_blk[PORT_MAX];
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006288 DP(NETIF_MSG_LINK, "Executing BCM8727 common init\n");
6289 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
6290 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
6291
Eilon Greensteinf57a6022009-08-12 08:23:11 +00006292 bnx2x_ext_phy_hw_reset(bp, 1 ^ (swap_val && swap_override));
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006293 msleep(5);
6294
Eilon Greensteinbc7f0a02009-08-12 08:23:01 +00006295 if (swap_val && swap_override)
6296 first_port = PORT_0;
6297 else
6298 first_port = PORT_1;
6299
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006300 /* PART1 - Reset both phys */
Eilon Greensteinbc7f0a02009-08-12 08:23:01 +00006301 for (i = 0, port = first_port; i < PORT_MAX; i++, port = !port) {
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006302 /* Extract the ext phy address for the port */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006303 if (bnx2x_populate_phy(bp, EXT_PHY1, shmem_base,
6304 port, &phy[port]) !=
6305 0) {
6306 DP(NETIF_MSG_LINK, "populate phy failed\n");
6307 return -EINVAL;
6308 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006309 /* disable attentions */
6310 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
6311 (NIG_MASK_XGXS0_LINK_STATUS |
6312 NIG_MASK_XGXS0_LINK10G |
6313 NIG_MASK_SERDES0_LINK_STATUS |
6314 NIG_MASK_MI_INT));
6315
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006316
6317 /* Reset the phy */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006318 bnx2x_cl45_write(bp, &phy[port],
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006319 MDIO_PMA_DEVAD,
6320 MDIO_PMA_REG_CTRL,
6321 1<<15);
6322 }
6323
6324 /* Add delay of 150ms after reset */
6325 msleep(150);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006326 if (phy[PORT_0].addr & 0x1) {
6327 phy_blk[PORT_0] = &(phy[PORT_1]);
6328 phy_blk[PORT_1] = &(phy[PORT_0]);
6329 } else {
6330 phy_blk[PORT_0] = &(phy[PORT_0]);
6331 phy_blk[PORT_1] = &(phy[PORT_1]);
6332 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006333 /* PART2 - Download firmware to both phys */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006334 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006335 u16 fw_ver1;
6336
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006337 bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port],
6338 port, shmem_base);
6339 bnx2x_cl45_read(bp, phy_blk[port],
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006340 MDIO_PMA_DEVAD,
6341 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
6342 if (fw_ver1 == 0 || fw_ver1 == 0x4321) {
6343 DP(NETIF_MSG_LINK,
Eilon Greensteinbc7f0a02009-08-12 08:23:01 +00006344 "bnx2x_8727_common_init_phy port %x:"
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006345 "Download failed. fw version = 0x%x\n",
6346 port, fw_ver1);
6347 return -EINVAL;
6348 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006349 }
6350
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006351 return 0;
6352}
6353
Eilon Greenstein589abe32009-02-12 08:36:55 +00006354static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp, u32 shmem_base)
6355{
Eilon Greenstein589abe32009-02-12 08:36:55 +00006356 u32 val;
6357 s8 port;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006358 struct bnx2x_phy phy;
Eilon Greenstein589abe32009-02-12 08:36:55 +00006359 /* Use port1 because of the static port-swap */
6360 /* Enable the module detection interrupt */
6361 val = REG_RD(bp, MISC_REG_GPIO_EVENT_EN);
6362 val |= ((1<<MISC_REGISTERS_GPIO_3)|
6363 (1<<(MISC_REGISTERS_GPIO_3 + MISC_REGISTERS_GPIO_PORT_SHIFT)));
6364 REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val);
6365
Eilon Greensteinf57a6022009-08-12 08:23:11 +00006366 bnx2x_ext_phy_hw_reset(bp, 1);
Eilon Greenstein589abe32009-02-12 08:36:55 +00006367 msleep(5);
6368 for (port = 0; port < PORT_MAX; port++) {
6369 /* Extract the ext phy address for the port */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006370 if (bnx2x_populate_phy(bp, EXT_PHY1, shmem_base,
6371 port, &phy) !=
6372 0) {
6373 DP(NETIF_MSG_LINK, "populate phy failed\n");
6374 return -EINVAL;
6375 }
Eilon Greenstein589abe32009-02-12 08:36:55 +00006376
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006377 /* Reset phy*/
6378 bnx2x_cl45_write(bp, &phy,
6379 MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, 0x0001);
Eilon Greenstein589abe32009-02-12 08:36:55 +00006380
Eilon Greenstein589abe32009-02-12 08:36:55 +00006381
6382 /* Set fault module detected LED on */
6383 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
6384 MISC_REGISTERS_GPIO_HIGH,
6385 port);
6386 }
6387
6388 return 0;
6389}
6390
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006391u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base)
6392{
6393 u8 rc = 0;
6394 u32 ext_phy_type;
6395
Eilon Greensteinf5372252009-02-12 08:38:30 +00006396 DP(NETIF_MSG_LINK, "Begin common phy init\n");
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006397
6398 /* Read the ext_phy_type for arbitrary port(0) */
6399 ext_phy_type = XGXS_EXT_PHY_TYPE(
6400 REG_RD(bp, shmem_base +
6401 offsetof(struct shmem_region,
6402 dev_info.port_hw_config[0].external_phy_config)));
6403
6404 switch (ext_phy_type) {
6405 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
6406 {
6407 rc = bnx2x_8073_common_init_phy(bp, shmem_base);
6408 break;
6409 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006410
6411 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
6412 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
6413 rc = bnx2x_8727_common_init_phy(bp, shmem_base);
6414 break;
6415
Eilon Greenstein589abe32009-02-12 08:36:55 +00006416 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
6417 /* GPIO1 affects both ports, so there's need to pull
6418 it for single port alone */
6419 rc = bnx2x_8726_common_init_phy(bp, shmem_base);
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02006420 break;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006421 default:
6422 DP(NETIF_MSG_LINK,
6423 "bnx2x_common_init_phy: ext_phy 0x%x not required\n",
6424 ext_phy_type);
6425 break;
6426 }
6427
6428 return rc;
6429}
6430
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006431void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006432{
6433 u16 val, cnt;
6434
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006435 bnx2x_cl45_read(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006436 MDIO_PMA_DEVAD,
6437 MDIO_PMA_REG_7101_RESET, &val);
6438
6439 for (cnt = 0; cnt < 10; cnt++) {
6440 msleep(50);
6441 /* Writes a self-clearing reset */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006442 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006443 MDIO_PMA_DEVAD,
6444 MDIO_PMA_REG_7101_RESET,
6445 (val | (1<<15)));
6446 /* Wait for clear */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006447 bnx2x_cl45_read(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006448 MDIO_PMA_DEVAD,
6449 MDIO_PMA_REG_7101_RESET, &val);
6450
6451 if ((val & (1<<15)) == 0)
6452 break;
6453 }
6454}