blob: e2509aab9f0d6ea75a71294e765c75b0a6e3adba [file] [log] [blame]
Eilon Greensteind05c26c2009-01-17 23:26:13 -08001/* Copyright 2008-2009 Broadcom Corporation
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002 *
3 * Unless you and Broadcom execute a separate written software license
4 * agreement governing use of this software, this software is licensed to you
5 * under the terms of the GNU General Public License version 2, available
6 * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL").
7 *
8 * Notwithstanding the above, under no circumstances may you combine this
9 * software in any way with any other Broadcom software provided under a
10 * license other than the GPL, without Broadcom's express prior written
11 * consent.
12 *
13 * Written by Yaniv Rosner
14 *
15 */
16
Joe Perches7995c642010-02-17 15:01:52 +000017#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
18
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070019#include <linux/kernel.h>
20#include <linux/errno.h>
21#include <linux/pci.h>
22#include <linux/netdevice.h>
23#include <linux/delay.h>
24#include <linux/ethtool.h>
25#include <linux/mutex.h>
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070026
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070027#include "bnx2x.h"
28
29/********************************************************/
Eilon Greenstein3196a882008-08-13 15:58:49 -070030#define ETH_HLEN 14
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070031#define ETH_OVREHEAD (ETH_HLEN + 8)/* 8 for CRC + VLAN*/
32#define ETH_MIN_PACKET_SIZE 60
33#define ETH_MAX_PACKET_SIZE 1500
34#define ETH_MAX_JUMBO_PACKET_SIZE 9600
35#define MDIO_ACCESS_TIMEOUT 1000
36#define BMAC_CONTROL_RX_ENABLE 2
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070037
38/***********************************************************/
Eilon Greenstein3196a882008-08-13 15:58:49 -070039/* Shortcut definitions */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070040/***********************************************************/
41
Eilon Greenstein2f904462009-08-12 08:22:16 +000042#define NIG_LATCH_BC_ENABLE_MI_INT 0
43
44#define NIG_STATUS_EMAC0_MI_INT \
45 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_EMAC0_MISC_MI_INT
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070046#define NIG_STATUS_XGXS0_LINK10G \
47 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK10G
48#define NIG_STATUS_XGXS0_LINK_STATUS \
49 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS
50#define NIG_STATUS_XGXS0_LINK_STATUS_SIZE \
51 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS_SIZE
52#define NIG_STATUS_SERDES0_LINK_STATUS \
53 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_SERDES0_LINK_STATUS
54#define NIG_MASK_MI_INT \
55 NIG_MASK_INTERRUPT_PORT0_REG_MASK_EMAC0_MISC_MI_INT
56#define NIG_MASK_XGXS0_LINK10G \
57 NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK10G
58#define NIG_MASK_XGXS0_LINK_STATUS \
59 NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK_STATUS
60#define NIG_MASK_SERDES0_LINK_STATUS \
61 NIG_MASK_INTERRUPT_PORT0_REG_MASK_SERDES0_LINK_STATUS
62
63#define MDIO_AN_CL73_OR_37_COMPLETE \
64 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE | \
65 MDIO_GP_STATUS_TOP_AN_STATUS1_CL37_AUTONEG_COMPLETE)
66
67#define XGXS_RESET_BITS \
68 (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_RSTB_HW | \
69 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_IDDQ | \
70 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN | \
71 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN_SD | \
72 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_TXD_FIFO_RSTB)
73
74#define SERDES_RESET_BITS \
75 (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_RSTB_HW | \
76 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_IDDQ | \
77 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN | \
78 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN_SD)
79
80#define AUTONEG_CL37 SHARED_HW_CFG_AN_ENABLE_CL37
81#define AUTONEG_CL73 SHARED_HW_CFG_AN_ENABLE_CL73
Eilon Greenstein3196a882008-08-13 15:58:49 -070082#define AUTONEG_BAM SHARED_HW_CFG_AN_ENABLE_BAM
83#define AUTONEG_PARALLEL \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070084 SHARED_HW_CFG_AN_ENABLE_PARALLEL_DETECTION
Eilon Greenstein3196a882008-08-13 15:58:49 -070085#define AUTONEG_SGMII_FIBER_AUTODET \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070086 SHARED_HW_CFG_AN_EN_SGMII_FIBER_AUTO_DETECT
Eilon Greenstein3196a882008-08-13 15:58:49 -070087#define AUTONEG_REMOTE_PHY SHARED_HW_CFG_AN_ENABLE_REMOTE_PHY
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070088
89#define GP_STATUS_PAUSE_RSOLUTION_TXSIDE \
90 MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_TXSIDE
91#define GP_STATUS_PAUSE_RSOLUTION_RXSIDE \
92 MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_RXSIDE
93#define GP_STATUS_SPEED_MASK \
94 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_MASK
95#define GP_STATUS_10M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10M
96#define GP_STATUS_100M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_100M
97#define GP_STATUS_1G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G
98#define GP_STATUS_2_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_2_5G
99#define GP_STATUS_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_5G
100#define GP_STATUS_6G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_6G
101#define GP_STATUS_10G_HIG \
102 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_HIG
103#define GP_STATUS_10G_CX4 \
104 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_CX4
105#define GP_STATUS_12G_HIG \
106 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12G_HIG
107#define GP_STATUS_12_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12_5G
108#define GP_STATUS_13G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_13G
109#define GP_STATUS_15G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_15G
110#define GP_STATUS_16G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_16G
111#define GP_STATUS_1G_KX MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G_KX
112#define GP_STATUS_10G_KX4 \
113 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_KX4
114
115#define LINK_10THD LINK_STATUS_SPEED_AND_DUPLEX_10THD
116#define LINK_10TFD LINK_STATUS_SPEED_AND_DUPLEX_10TFD
117#define LINK_100TXHD LINK_STATUS_SPEED_AND_DUPLEX_100TXHD
118#define LINK_100T4 LINK_STATUS_SPEED_AND_DUPLEX_100T4
119#define LINK_100TXFD LINK_STATUS_SPEED_AND_DUPLEX_100TXFD
120#define LINK_1000THD LINK_STATUS_SPEED_AND_DUPLEX_1000THD
121#define LINK_1000TFD LINK_STATUS_SPEED_AND_DUPLEX_1000TFD
122#define LINK_1000XFD LINK_STATUS_SPEED_AND_DUPLEX_1000XFD
123#define LINK_2500THD LINK_STATUS_SPEED_AND_DUPLEX_2500THD
124#define LINK_2500TFD LINK_STATUS_SPEED_AND_DUPLEX_2500TFD
125#define LINK_2500XFD LINK_STATUS_SPEED_AND_DUPLEX_2500XFD
126#define LINK_10GTFD LINK_STATUS_SPEED_AND_DUPLEX_10GTFD
127#define LINK_10GXFD LINK_STATUS_SPEED_AND_DUPLEX_10GXFD
128#define LINK_12GTFD LINK_STATUS_SPEED_AND_DUPLEX_12GTFD
129#define LINK_12GXFD LINK_STATUS_SPEED_AND_DUPLEX_12GXFD
130#define LINK_12_5GTFD LINK_STATUS_SPEED_AND_DUPLEX_12_5GTFD
131#define LINK_12_5GXFD LINK_STATUS_SPEED_AND_DUPLEX_12_5GXFD
132#define LINK_13GTFD LINK_STATUS_SPEED_AND_DUPLEX_13GTFD
133#define LINK_13GXFD LINK_STATUS_SPEED_AND_DUPLEX_13GXFD
134#define LINK_15GTFD LINK_STATUS_SPEED_AND_DUPLEX_15GTFD
135#define LINK_15GXFD LINK_STATUS_SPEED_AND_DUPLEX_15GXFD
136#define LINK_16GTFD LINK_STATUS_SPEED_AND_DUPLEX_16GTFD
137#define LINK_16GXFD LINK_STATUS_SPEED_AND_DUPLEX_16GXFD
138
139#define PHY_XGXS_FLAG 0x1
140#define PHY_SGMII_FLAG 0x2
141#define PHY_SERDES_FLAG 0x4
142
Eilon Greenstein589abe32009-02-12 08:36:55 +0000143/* */
144#define SFP_EEPROM_CON_TYPE_ADDR 0x2
145 #define SFP_EEPROM_CON_TYPE_VAL_LC 0x7
146 #define SFP_EEPROM_CON_TYPE_VAL_COPPER 0x21
147
Eilon Greenstein4d295db2009-07-21 05:47:47 +0000148
149#define SFP_EEPROM_COMP_CODE_ADDR 0x3
150 #define SFP_EEPROM_COMP_CODE_SR_MASK (1<<4)
151 #define SFP_EEPROM_COMP_CODE_LR_MASK (1<<5)
152 #define SFP_EEPROM_COMP_CODE_LRM_MASK (1<<6)
153
Eilon Greenstein589abe32009-02-12 08:36:55 +0000154#define SFP_EEPROM_FC_TX_TECH_ADDR 0x8
155 #define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE 0x4
156 #define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE 0x8
Eilon Greenstein4d295db2009-07-21 05:47:47 +0000157
Eilon Greenstein589abe32009-02-12 08:36:55 +0000158#define SFP_EEPROM_OPTIONS_ADDR 0x40
159 #define SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK 0x1
160#define SFP_EEPROM_OPTIONS_SIZE 2
161
Eilon Greenstein4d295db2009-07-21 05:47:47 +0000162#define EDC_MODE_LINEAR 0x0022
163#define EDC_MODE_LIMITING 0x0044
164#define EDC_MODE_PASSIVE_DAC 0x0055
Eilon Greenstein589abe32009-02-12 08:36:55 +0000165
Eilon Greenstein4d295db2009-07-21 05:47:47 +0000166
167
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700168/**********************************************************/
169/* INTERFACE */
170/**********************************************************/
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000171
172#define CL45_WR_OVER_CL22(_bp, _phy, _bank, _addr, _val) \
173 bnx2x_cl45_write(_bp, _phy, \
Yaniv Rosner7aa07112010-09-07 11:41:01 +0000174 (_phy)->def_md_devad, \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700175 (_bank + (_addr & 0xf)), \
176 _val)
177
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000178#define CL45_RD_OVER_CL22(_bp, _phy, _bank, _addr, _val) \
179 bnx2x_cl45_read(_bp, _phy, \
Yaniv Rosner7aa07112010-09-07 11:41:01 +0000180 (_phy)->def_md_devad, \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700181 (_bank + (_addr & 0xf)), \
182 _val)
183
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700184static u32 bnx2x_bits_en(struct bnx2x *bp, u32 reg, u32 bits)
185{
186 u32 val = REG_RD(bp, reg);
187
188 val |= bits;
189 REG_WR(bp, reg, val);
190 return val;
191}
192
193static u32 bnx2x_bits_dis(struct bnx2x *bp, u32 reg, u32 bits)
194{
195 u32 val = REG_RD(bp, reg);
196
197 val &= ~bits;
198 REG_WR(bp, reg, val);
199 return val;
200}
201
202static void bnx2x_emac_init(struct link_params *params,
203 struct link_vars *vars)
204{
205 /* reset and unreset the emac core */
206 struct bnx2x *bp = params->bp;
207 u8 port = params->port;
208 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
209 u32 val;
210 u16 timeout;
211
212 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
213 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
214 udelay(5);
215 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
216 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
217
218 /* init emac - use read-modify-write */
219 /* self clear reset */
220 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700221 EMAC_WR(bp, EMAC_REG_EMAC_MODE, (val | EMAC_MODE_RESET));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700222
223 timeout = 200;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700224 do {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700225 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
226 DP(NETIF_MSG_LINK, "EMAC reset reg is %u\n", val);
227 if (!timeout) {
228 DP(NETIF_MSG_LINK, "EMAC timeout!\n");
229 return;
230 }
231 timeout--;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700232 } while (val & EMAC_MODE_RESET);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700233
234 /* Set mac address */
235 val = ((params->mac_addr[0] << 8) |
236 params->mac_addr[1]);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700237 EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700238
239 val = ((params->mac_addr[2] << 24) |
240 (params->mac_addr[3] << 16) |
241 (params->mac_addr[4] << 8) |
242 params->mac_addr[5]);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700243 EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH + 4, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700244}
245
246static u8 bnx2x_emac_enable(struct link_params *params,
247 struct link_vars *vars, u8 lb)
248{
249 struct bnx2x *bp = params->bp;
250 u8 port = params->port;
251 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
252 u32 val;
253
254 DP(NETIF_MSG_LINK, "enabling EMAC\n");
255
256 /* enable emac and not bmac */
257 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 1);
258
259 /* for paladium */
260 if (CHIP_REV_IS_EMUL(bp)) {
261 /* Use lane 1 (of lanes 0-3) */
262 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1);
263 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
264 port*4, 1);
265 }
266 /* for fpga */
267 else
268
269 if (CHIP_REV_IS_FPGA(bp)) {
270 /* Use lane 1 (of lanes 0-3) */
271 DP(NETIF_MSG_LINK, "bnx2x_emac_enable: Setting FPGA\n");
272
273 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1);
274 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4,
275 0);
276 } else
277 /* ASIC */
278 if (vars->phy_flags & PHY_XGXS_FLAG) {
279 u32 ser_lane = ((params->lane_config &
280 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
281 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
282
283 DP(NETIF_MSG_LINK, "XGXS\n");
284 /* select the master lanes (out of 0-3) */
285 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 +
286 port*4, ser_lane);
287 /* select XGXS */
288 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
289 port*4, 1);
290
291 } else { /* SerDes */
292 DP(NETIF_MSG_LINK, "SerDes\n");
293 /* select SerDes */
294 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
295 port*4, 0);
296 }
297
Eilon Greenstein811a2f22009-02-12 08:37:04 +0000298 bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
299 EMAC_RX_MODE_RESET);
300 bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
301 EMAC_TX_MODE_RESET);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700302
303 if (CHIP_REV_IS_SLOW(bp)) {
304 /* config GMII mode */
305 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700306 EMAC_WR(bp, EMAC_REG_EMAC_MODE,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700307 (val | EMAC_MODE_PORT_GMII));
308 } else { /* ASIC */
309 /* pause enable/disable */
310 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
311 EMAC_RX_MODE_FLOW_EN);
David S. Millerc0700f92008-12-16 23:53:20 -0800312 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700313 bnx2x_bits_en(bp, emac_base +
314 EMAC_REG_EMAC_RX_MODE,
315 EMAC_RX_MODE_FLOW_EN);
316
317 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700318 (EMAC_TX_MODE_EXT_PAUSE_EN |
319 EMAC_TX_MODE_FLOW_EN));
David S. Millerc0700f92008-12-16 23:53:20 -0800320 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700321 bnx2x_bits_en(bp, emac_base +
322 EMAC_REG_EMAC_TX_MODE,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700323 (EMAC_TX_MODE_EXT_PAUSE_EN |
324 EMAC_TX_MODE_FLOW_EN));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700325 }
326
327 /* KEEP_VLAN_TAG, promiscuous */
328 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_RX_MODE);
329 val |= EMAC_RX_MODE_KEEP_VLAN_TAG | EMAC_RX_MODE_PROMISCUOUS;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700330 EMAC_WR(bp, EMAC_REG_EMAC_RX_MODE, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700331
332 /* Set Loopback */
333 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
334 if (lb)
335 val |= 0x810;
336 else
337 val &= ~0x810;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700338 EMAC_WR(bp, EMAC_REG_EMAC_MODE, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700339
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +0000340 /* enable emac */
341 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 1);
342
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700343 /* enable emac for jumbo packets */
Eilon Greenstein3196a882008-08-13 15:58:49 -0700344 EMAC_WR(bp, EMAC_REG_EMAC_RX_MTU_SIZE,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700345 (EMAC_RX_MTU_SIZE_JUMBO_ENA |
346 (ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD)));
347
348 /* strip CRC */
349 REG_WR(bp, NIG_REG_NIG_INGRESS_EMAC0_NO_CRC + port*4, 0x1);
350
351 /* disable the NIG in/out to the bmac */
352 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x0);
353 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, 0x0);
354 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x0);
355
356 /* enable the NIG in/out to the emac */
357 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x1);
358 val = 0;
David S. Millerc0700f92008-12-16 23:53:20 -0800359 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700360 val = 1;
361
362 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, val);
363 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x1);
364
365 if (CHIP_REV_IS_EMUL(bp)) {
366 /* take the BigMac out of reset */
367 REG_WR(bp,
368 GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
369 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
370
371 /* enable access for bmac registers */
372 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
Eilon Greenstein6f654972009-08-12 08:23:51 +0000373 } else
374 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700375
376 vars->mac_type = MAC_TYPE_EMAC;
377 return 0;
378}
379
380
381
382static u8 bnx2x_bmac_enable(struct link_params *params, struct link_vars *vars,
383 u8 is_lb)
384{
385 struct bnx2x *bp = params->bp;
386 u8 port = params->port;
387 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
388 NIG_REG_INGRESS_BMAC0_MEM;
389 u32 wb_data[2];
390 u32 val;
391
392 DP(NETIF_MSG_LINK, "Enabling BigMAC\n");
393 /* reset and unreset the BigMac */
394 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
395 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
396 msleep(1);
397
398 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
399 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
400
401 /* enable access for bmac registers */
402 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
403
404 /* XGXS control */
405 wb_data[0] = 0x3c;
406 wb_data[1] = 0;
407 REG_WR_DMAE(bp, bmac_addr +
408 BIGMAC_REGISTER_BMAC_XGXS_CONTROL,
409 wb_data, 2);
410
411 /* tx MAC SA */
412 wb_data[0] = ((params->mac_addr[2] << 24) |
413 (params->mac_addr[3] << 16) |
414 (params->mac_addr[4] << 8) |
415 params->mac_addr[5]);
416 wb_data[1] = ((params->mac_addr[0] << 8) |
417 params->mac_addr[1]);
418 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_SOURCE_ADDR,
419 wb_data, 2);
420
421 /* tx control */
422 val = 0xc0;
David S. Millerc0700f92008-12-16 23:53:20 -0800423 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700424 val |= 0x800000;
425 wb_data[0] = val;
426 wb_data[1] = 0;
427 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_CONTROL,
428 wb_data, 2);
429
430 /* mac control */
431 val = 0x3;
432 if (is_lb) {
433 val |= 0x4;
434 DP(NETIF_MSG_LINK, "enable bmac loopback\n");
435 }
436 wb_data[0] = val;
437 wb_data[1] = 0;
438 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
439 wb_data, 2);
440
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700441 /* set rx mtu */
442 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
443 wb_data[1] = 0;
444 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_MAX_SIZE,
445 wb_data, 2);
446
447 /* rx control set to don't strip crc */
448 val = 0x14;
David S. Millerc0700f92008-12-16 23:53:20 -0800449 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700450 val |= 0x20;
451 wb_data[0] = val;
452 wb_data[1] = 0;
453 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_CONTROL,
454 wb_data, 2);
455
456 /* set tx mtu */
457 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
458 wb_data[1] = 0;
459 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_MAX_SIZE,
460 wb_data, 2);
461
462 /* set cnt max size */
463 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
464 wb_data[1] = 0;
465 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_CNT_MAX_SIZE,
466 wb_data, 2);
467
468 /* configure safc */
469 wb_data[0] = 0x1000200;
470 wb_data[1] = 0;
471 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_LLFC_MSG_FLDS,
472 wb_data, 2);
473 /* fix for emulation */
474 if (CHIP_REV_IS_EMUL(bp)) {
475 wb_data[0] = 0xf000;
476 wb_data[1] = 0;
477 REG_WR_DMAE(bp,
478 bmac_addr + BIGMAC_REGISTER_TX_PAUSE_THRESHOLD,
479 wb_data, 2);
480 }
481
482 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0x1);
483 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 0x0);
484 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 0x0);
485 val = 0;
David S. Millerc0700f92008-12-16 23:53:20 -0800486 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700487 val = 1;
488 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, val);
489 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x0);
490 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x0);
491 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, 0x0);
492 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x1);
493 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x1);
494
495 vars->mac_type = MAC_TYPE_BMAC;
496 return 0;
497}
498
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700499
500static void bnx2x_update_mng(struct link_params *params, u32 link_status)
501{
502 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +0000503
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700504 REG_WR(bp, params->shmem_base +
505 offsetof(struct shmem_region,
506 port_mb[params->port].link_status),
507 link_status);
508}
509
510static void bnx2x_bmac_rx_disable(struct bnx2x *bp, u8 port)
511{
512 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
513 NIG_REG_INGRESS_BMAC0_MEM;
514 u32 wb_data[2];
Eilon Greenstein3196a882008-08-13 15:58:49 -0700515 u32 nig_bmac_enable = REG_RD(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700516
517 /* Only if the bmac is out of reset */
518 if (REG_RD(bp, MISC_REG_RESET_REG_2) &
519 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port) &&
520 nig_bmac_enable) {
521
522 /* Clear Rx Enable bit in BMAC_CONTROL register */
523 REG_RD_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
524 wb_data, 2);
525 wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
526 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
527 wb_data, 2);
528
529 msleep(1);
530 }
531}
532
533static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl,
534 u32 line_speed)
535{
536 struct bnx2x *bp = params->bp;
537 u8 port = params->port;
538 u32 init_crd, crd;
539 u32 count = 1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700540
541 /* disable port */
542 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x1);
543
544 /* wait for init credit */
545 init_crd = REG_RD(bp, PBF_REG_P0_INIT_CRD + port*4);
546 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
547 DP(NETIF_MSG_LINK, "init_crd 0x%x crd 0x%x\n", init_crd, crd);
548
549 while ((init_crd != crd) && count) {
550 msleep(5);
551
552 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
553 count--;
554 }
555 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
556 if (init_crd != crd) {
557 DP(NETIF_MSG_LINK, "BUG! init_crd 0x%x != crd 0x%x\n",
558 init_crd, crd);
559 return -EINVAL;
560 }
561
David S. Millerc0700f92008-12-16 23:53:20 -0800562 if (flow_ctrl & BNX2X_FLOW_CTRL_RX ||
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700563 line_speed == SPEED_10 ||
564 line_speed == SPEED_100 ||
565 line_speed == SPEED_1000 ||
566 line_speed == SPEED_2500) {
567 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700568 /* update threshold */
569 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, 0);
570 /* update init credit */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700571 init_crd = 778; /* (800-18-4) */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700572
573 } else {
574 u32 thresh = (ETH_MAX_JUMBO_PACKET_SIZE +
575 ETH_OVREHEAD)/16;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700576 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700577 /* update threshold */
578 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, thresh);
579 /* update init credit */
580 switch (line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700581 case SPEED_10000:
582 init_crd = thresh + 553 - 22;
583 break;
584
585 case SPEED_12000:
586 init_crd = thresh + 664 - 22;
587 break;
588
589 case SPEED_13000:
590 init_crd = thresh + 742 - 22;
591 break;
592
593 case SPEED_16000:
594 init_crd = thresh + 778 - 22;
595 break;
596 default:
597 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
598 line_speed);
599 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700600 }
601 }
602 REG_WR(bp, PBF_REG_P0_INIT_CRD + port*4, init_crd);
603 DP(NETIF_MSG_LINK, "PBF updated to speed %d credit %d\n",
604 line_speed, init_crd);
605
606 /* probe the credit changes */
607 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x1);
608 msleep(5);
609 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x0);
610
611 /* enable port */
612 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x0);
613 return 0;
614}
615
Yaniv Rosnerc18aa152010-09-07 11:41:07 +0000616static u32 bnx2x_get_emac_base(struct bnx2x *bp,
617 u32 mdc_mdio_access, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700618{
Yaniv Rosnerc18aa152010-09-07 11:41:07 +0000619 u32 emac_base = 0;
620 switch (mdc_mdio_access) {
621 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_PHY_TYPE:
622 break;
623 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC0:
624 if (REG_RD(bp, NIG_REG_PORT_SWAP))
625 emac_base = GRCBASE_EMAC1;
626 else
627 emac_base = GRCBASE_EMAC0;
628 break;
629 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1:
Eilon Greenstein589abe32009-02-12 08:36:55 +0000630 if (REG_RD(bp, NIG_REG_PORT_SWAP))
631 emac_base = GRCBASE_EMAC0;
632 else
633 emac_base = GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700634 break;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +0000635 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH:
636 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
637 break;
638 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_SWAPPED:
Eilon Greenstein6378c022008-08-13 15:59:25 -0700639 emac_base = (port) ? GRCBASE_EMAC0 : GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700640 break;
641 default:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700642 break;
643 }
644 return emac_base;
645
646}
647
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000648u8 bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy,
649 u8 devad, u16 reg, u16 val)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700650{
651 u32 tmp, saved_mode;
652 u8 i, rc = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700653
654 /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
655 * (a value of 49==0x31) and make sure that the AUTO poll is off
656 */
Eilon Greenstein589abe32009-02-12 08:36:55 +0000657
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000658 saved_mode = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700659 tmp = saved_mode & ~(EMAC_MDIO_MODE_AUTO_POLL |
660 EMAC_MDIO_MODE_CLOCK_CNT);
661 tmp |= (EMAC_MDIO_MODE_CLAUSE_45 |
662 (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000663 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, tmp);
664 REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700665 udelay(40);
666
667 /* address */
668
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000669 tmp = ((phy->addr << 21) | (devad << 16) | reg |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700670 EMAC_MDIO_COMM_COMMAND_ADDRESS |
671 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000672 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700673
674 for (i = 0; i < 50; i++) {
675 udelay(10);
676
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000677 tmp = REG_RD(bp, phy->mdio_ctrl +
678 EMAC_REG_EMAC_MDIO_COMM);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700679 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
680 udelay(5);
681 break;
682 }
683 }
684 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
685 DP(NETIF_MSG_LINK, "write phy register failed\n");
686 rc = -EFAULT;
687 } else {
688 /* data */
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000689 tmp = ((phy->addr << 21) | (devad << 16) | val |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700690 EMAC_MDIO_COMM_COMMAND_WRITE_45 |
691 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000692 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700693
694 for (i = 0; i < 50; i++) {
695 udelay(10);
696
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000697 tmp = REG_RD(bp, phy->mdio_ctrl +
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700698 EMAC_REG_EMAC_MDIO_COMM);
699 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
700 udelay(5);
701 break;
702 }
703 }
704 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
705 DP(NETIF_MSG_LINK, "write phy register failed\n");
706 rc = -EFAULT;
707 }
708 }
709
710 /* Restore the saved mode */
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000711 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700712
713 return rc;
714}
715
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000716u8 bnx2x_cl45_read(struct bnx2x *bp, struct bnx2x_phy *phy,
717 u8 devad, u16 reg, u16 *ret_val)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700718{
719 u32 val, saved_mode;
720 u16 i;
721 u8 rc = 0;
722
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700723 /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
724 * (a value of 49==0x31) and make sure that the AUTO poll is off
725 */
Eilon Greenstein589abe32009-02-12 08:36:55 +0000726
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000727 saved_mode = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
728 val = saved_mode & ~((EMAC_MDIO_MODE_AUTO_POLL |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700729 EMAC_MDIO_MODE_CLOCK_CNT));
730 val |= (EMAC_MDIO_MODE_CLAUSE_45 |
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +0000731 (49L << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000732 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, val);
733 REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700734 udelay(40);
735
736 /* address */
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000737 val = ((phy->addr << 21) | (devad << 16) | reg |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700738 EMAC_MDIO_COMM_COMMAND_ADDRESS |
739 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000740 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700741
742 for (i = 0; i < 50; i++) {
743 udelay(10);
744
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000745 val = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700746 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
747 udelay(5);
748 break;
749 }
750 }
751 if (val & EMAC_MDIO_COMM_START_BUSY) {
752 DP(NETIF_MSG_LINK, "read phy register failed\n");
753
754 *ret_val = 0;
755 rc = -EFAULT;
756
757 } else {
758 /* data */
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000759 val = ((phy->addr << 21) | (devad << 16) |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700760 EMAC_MDIO_COMM_COMMAND_READ_45 |
761 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000762 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700763
764 for (i = 0; i < 50; i++) {
765 udelay(10);
766
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000767 val = REG_RD(bp, phy->mdio_ctrl +
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700768 EMAC_REG_EMAC_MDIO_COMM);
769 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
770 *ret_val = (u16)(val & EMAC_MDIO_COMM_DATA);
771 break;
772 }
773 }
774 if (val & EMAC_MDIO_COMM_START_BUSY) {
775 DP(NETIF_MSG_LINK, "read phy register failed\n");
776
777 *ret_val = 0;
778 rc = -EFAULT;
779 }
780 }
781
782 /* Restore the saved mode */
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000783 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700784
785 return rc;
786}
787
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000788u8 bnx2x_phy_read(struct link_params *params, u8 phy_addr,
789 u8 devad, u16 reg, u16 *ret_val)
790{
791 u8 phy_index;
792 /**
793 * Probe for the phy according to the given phy_addr, and execute
794 * the read request on it
795 */
796 for (phy_index = 0; phy_index < params->num_phys; phy_index++) {
797 if (params->phy[phy_index].addr == phy_addr) {
798 return bnx2x_cl45_read(params->bp,
799 &params->phy[phy_index], devad,
800 reg, ret_val);
801 }
802 }
803 return -EINVAL;
804}
805
806u8 bnx2x_phy_write(struct link_params *params, u8 phy_addr,
807 u8 devad, u16 reg, u16 val)
808{
809 u8 phy_index;
810 /**
811 * Probe for the phy according to the given phy_addr, and execute
812 * the write request on it
813 */
814 for (phy_index = 0; phy_index < params->num_phys; phy_index++) {
815 if (params->phy[phy_index].addr == phy_addr) {
816 return bnx2x_cl45_write(params->bp,
817 &params->phy[phy_index], devad,
818 reg, val);
819 }
820 }
821 return -EINVAL;
822}
823
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700824static void bnx2x_set_aer_mmd(struct link_params *params,
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000825 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700826{
827 struct bnx2x *bp = params->bp;
828 u32 ser_lane;
829 u16 offset;
830
831 ser_lane = ((params->lane_config &
832 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
833 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
834
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000835 offset = (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ?
836 (phy->addr + ser_lane) : 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700837
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000838 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700839 MDIO_REG_BANK_AER_BLOCK,
840 MDIO_AER_BLOCK_AER_REG, 0x3800 + offset);
841}
842
Yaniv Rosnerde6eae12010-09-07 11:41:13 +0000843/******************************************************************/
844/* Internal phy section */
845/******************************************************************/
846
847static void bnx2x_set_serdes_access(struct bnx2x *bp, u8 port)
848{
849 u32 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
850
851 /* Set Clause 22 */
852 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + port*0x10, 1);
853 REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245f8000);
854 udelay(500);
855 REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245d000f);
856 udelay(500);
857 /* Set Clause 45 */
858 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + port*0x10, 0);
859}
860
861static void bnx2x_serdes_deassert(struct bnx2x *bp, u8 port)
862{
863 u32 val;
864
865 DP(NETIF_MSG_LINK, "bnx2x_serdes_deassert\n");
866
867 val = SERDES_RESET_BITS << (port*16);
868
869 /* reset and unreset the SerDes/XGXS */
870 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR, val);
871 udelay(500);
872 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET, val);
873
874 bnx2x_set_serdes_access(bp, port);
875
876 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_DEVAD +
877 port*0x10,
878 DEFAULT_PHY_DEV_ADDR);
879}
880
881static void bnx2x_xgxs_deassert(struct link_params *params)
882{
883 struct bnx2x *bp = params->bp;
884 u8 port;
885 u32 val;
886 DP(NETIF_MSG_LINK, "bnx2x_xgxs_deassert\n");
887 port = params->port;
888
889 val = XGXS_RESET_BITS << (port*16);
890
891 /* reset and unreset the SerDes/XGXS */
892 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR, val);
893 udelay(500);
894 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET, val);
895
896 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_ST +
897 port*0x18, 0);
898 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
899 params->phy[INT_PHY].def_md_devad);
900}
901
902void bnx2x_link_status_update(struct link_params *params,
903 struct link_vars *vars)
904{
905 struct bnx2x *bp = params->bp;
906 u8 link_10g;
907 u8 port = params->port;
908
909 if (params->switch_cfg == SWITCH_CFG_1G)
910 vars->phy_flags = PHY_SERDES_FLAG;
911 else
912 vars->phy_flags = PHY_XGXS_FLAG;
913 vars->link_status = REG_RD(bp, params->shmem_base +
914 offsetof(struct shmem_region,
915 port_mb[port].link_status));
916
917 vars->link_up = (vars->link_status & LINK_STATUS_LINK_UP);
918
919 if (vars->link_up) {
920 DP(NETIF_MSG_LINK, "phy link up\n");
921
922 vars->phy_link_up = 1;
923 vars->duplex = DUPLEX_FULL;
924 switch (vars->link_status &
925 LINK_STATUS_SPEED_AND_DUPLEX_MASK) {
926 case LINK_10THD:
927 vars->duplex = DUPLEX_HALF;
928 /* fall thru */
929 case LINK_10TFD:
930 vars->line_speed = SPEED_10;
931 break;
932
933 case LINK_100TXHD:
934 vars->duplex = DUPLEX_HALF;
935 /* fall thru */
936 case LINK_100T4:
937 case LINK_100TXFD:
938 vars->line_speed = SPEED_100;
939 break;
940
941 case LINK_1000THD:
942 vars->duplex = DUPLEX_HALF;
943 /* fall thru */
944 case LINK_1000TFD:
945 vars->line_speed = SPEED_1000;
946 break;
947
948 case LINK_2500THD:
949 vars->duplex = DUPLEX_HALF;
950 /* fall thru */
951 case LINK_2500TFD:
952 vars->line_speed = SPEED_2500;
953 break;
954
955 case LINK_10GTFD:
956 vars->line_speed = SPEED_10000;
957 break;
958
959 case LINK_12GTFD:
960 vars->line_speed = SPEED_12000;
961 break;
962
963 case LINK_12_5GTFD:
964 vars->line_speed = SPEED_12500;
965 break;
966
967 case LINK_13GTFD:
968 vars->line_speed = SPEED_13000;
969 break;
970
971 case LINK_15GTFD:
972 vars->line_speed = SPEED_15000;
973 break;
974
975 case LINK_16GTFD:
976 vars->line_speed = SPEED_16000;
977 break;
978
979 default:
980 break;
981 }
982
983 vars->flow_ctrl = 0;
984 if (vars->link_status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED)
985 vars->flow_ctrl |= BNX2X_FLOW_CTRL_TX;
986
987 if (vars->link_status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED)
988 vars->flow_ctrl |= BNX2X_FLOW_CTRL_RX;
989
990 if (!vars->flow_ctrl)
991 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
992
993 if (vars->line_speed &&
994 ((vars->line_speed == SPEED_10) ||
995 (vars->line_speed == SPEED_100))) {
996 vars->phy_flags |= PHY_SGMII_FLAG;
997 } else {
998 vars->phy_flags &= ~PHY_SGMII_FLAG;
999 }
1000
1001 /* anything 10 and over uses the bmac */
1002 link_10g = ((vars->line_speed == SPEED_10000) ||
1003 (vars->line_speed == SPEED_12000) ||
1004 (vars->line_speed == SPEED_12500) ||
1005 (vars->line_speed == SPEED_13000) ||
1006 (vars->line_speed == SPEED_15000) ||
1007 (vars->line_speed == SPEED_16000));
1008 if (link_10g)
1009 vars->mac_type = MAC_TYPE_BMAC;
1010 else
1011 vars->mac_type = MAC_TYPE_EMAC;
1012
1013 } else { /* link down */
1014 DP(NETIF_MSG_LINK, "phy link down\n");
1015
1016 vars->phy_link_up = 0;
1017
1018 vars->line_speed = 0;
1019 vars->duplex = DUPLEX_FULL;
1020 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
1021
1022 /* indicate no mac active */
1023 vars->mac_type = MAC_TYPE_NONE;
1024 }
1025
1026 DP(NETIF_MSG_LINK, "link_status 0x%x phy_link_up %x\n",
1027 vars->link_status, vars->phy_link_up);
1028 DP(NETIF_MSG_LINK, "line_speed %x duplex %x flow_ctrl 0x%x\n",
1029 vars->line_speed, vars->duplex, vars->flow_ctrl);
1030}
1031
1032
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001033static void bnx2x_set_master_ln(struct link_params *params,
1034 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001035{
1036 struct bnx2x *bp = params->bp;
1037 u16 new_master_ln, ser_lane;
1038 ser_lane = ((params->lane_config &
1039 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
1040 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
1041
1042 /* set the master_ln for AN */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001043 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001044 MDIO_REG_BANK_XGXS_BLOCK2,
1045 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
1046 &new_master_ln);
1047
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001048 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001049 MDIO_REG_BANK_XGXS_BLOCK2 ,
1050 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
1051 (new_master_ln | ser_lane));
1052}
1053
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001054static u8 bnx2x_reset_unicore(struct link_params *params,
1055 struct bnx2x_phy *phy,
1056 u8 set_serdes)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001057{
1058 struct bnx2x *bp = params->bp;
1059 u16 mii_control;
1060 u16 i;
1061
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001062 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001063 MDIO_REG_BANK_COMBO_IEEE0,
1064 MDIO_COMBO_IEEE0_MII_CONTROL, &mii_control);
1065
1066 /* reset the unicore */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001067 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001068 MDIO_REG_BANK_COMBO_IEEE0,
1069 MDIO_COMBO_IEEE0_MII_CONTROL,
1070 (mii_control |
1071 MDIO_COMBO_IEEO_MII_CONTROL_RESET));
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001072 if (set_serdes)
1073 bnx2x_set_serdes_access(bp, params->port);
Eilon Greensteinc1b73992009-02-12 08:37:07 +00001074
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001075 /* wait for the reset to self clear */
1076 for (i = 0; i < MDIO_ACCESS_TIMEOUT; i++) {
1077 udelay(5);
1078
1079 /* the reset erased the previous bank value */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001080 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001081 MDIO_REG_BANK_COMBO_IEEE0,
1082 MDIO_COMBO_IEEE0_MII_CONTROL,
1083 &mii_control);
1084
1085 if (!(mii_control & MDIO_COMBO_IEEO_MII_CONTROL_RESET)) {
1086 udelay(5);
1087 return 0;
1088 }
1089 }
1090
1091 DP(NETIF_MSG_LINK, "BUG! XGXS is still in reset!\n");
1092 return -EINVAL;
1093
1094}
1095
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001096static void bnx2x_set_swap_lanes(struct link_params *params,
1097 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001098{
1099 struct bnx2x *bp = params->bp;
1100 /* Each two bits represents a lane number:
1101 No swap is 0123 => 0x1b no need to enable the swap */
1102 u16 ser_lane, rx_lane_swap, tx_lane_swap;
1103
1104 ser_lane = ((params->lane_config &
1105 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
1106 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
1107 rx_lane_swap = ((params->lane_config &
1108 PORT_HW_CFG_LANE_SWAP_CFG_RX_MASK) >>
1109 PORT_HW_CFG_LANE_SWAP_CFG_RX_SHIFT);
1110 tx_lane_swap = ((params->lane_config &
1111 PORT_HW_CFG_LANE_SWAP_CFG_TX_MASK) >>
1112 PORT_HW_CFG_LANE_SWAP_CFG_TX_SHIFT);
1113
1114 if (rx_lane_swap != 0x1b) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001115 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001116 MDIO_REG_BANK_XGXS_BLOCK2,
1117 MDIO_XGXS_BLOCK2_RX_LN_SWAP,
1118 (rx_lane_swap |
1119 MDIO_XGXS_BLOCK2_RX_LN_SWAP_ENABLE |
1120 MDIO_XGXS_BLOCK2_RX_LN_SWAP_FORCE_ENABLE));
1121 } else {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001122 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001123 MDIO_REG_BANK_XGXS_BLOCK2,
1124 MDIO_XGXS_BLOCK2_RX_LN_SWAP, 0);
1125 }
1126
1127 if (tx_lane_swap != 0x1b) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001128 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001129 MDIO_REG_BANK_XGXS_BLOCK2,
1130 MDIO_XGXS_BLOCK2_TX_LN_SWAP,
1131 (tx_lane_swap |
1132 MDIO_XGXS_BLOCK2_TX_LN_SWAP_ENABLE));
1133 } else {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001134 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001135 MDIO_REG_BANK_XGXS_BLOCK2,
1136 MDIO_XGXS_BLOCK2_TX_LN_SWAP, 0);
1137 }
1138}
1139
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001140static void bnx2x_set_parallel_detection(struct bnx2x_phy *phy,
1141 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001142{
1143 struct bnx2x *bp = params->bp;
1144 u16 control2;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001145 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001146 MDIO_REG_BANK_SERDES_DIGITAL,
1147 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
1148 &control2);
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001149 if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
Yaniv Rosner18afb0a2009-11-05 19:18:04 +02001150 control2 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
1151 else
1152 control2 &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001153 DP(NETIF_MSG_LINK, "phy->speed_cap_mask = 0x%x, control2 = 0x%x\n",
1154 phy->speed_cap_mask, control2);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001155 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001156 MDIO_REG_BANK_SERDES_DIGITAL,
1157 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
1158 control2);
1159
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001160 if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00001161 (phy->speed_cap_mask &
Yaniv Rosner18afb0a2009-11-05 19:18:04 +02001162 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001163 DP(NETIF_MSG_LINK, "XGXS\n");
1164
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001165 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001166 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1167 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK,
1168 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT);
1169
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001170 CL45_RD_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
1176 control2 |=
1177 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN;
1178
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001179 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001180 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1181 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
1182 control2);
1183
1184 /* Disable parallel detection of HiG */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001185 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001186 MDIO_REG_BANK_XGXS_BLOCK2,
1187 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G,
1188 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_CX4_XGXS |
1189 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_HIGIG_XGXS);
1190 }
1191}
1192
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001193static void bnx2x_set_autoneg(struct bnx2x_phy *phy,
1194 struct link_params *params,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001195 struct link_vars *vars,
1196 u8 enable_cl73)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001197{
1198 struct bnx2x *bp = params->bp;
1199 u16 reg_val;
1200
1201 /* CL37 Autoneg */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001202 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001203 MDIO_REG_BANK_COMBO_IEEE0,
1204 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
1205
1206 /* CL37 Autoneg Enabled */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001207 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001208 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_AN_EN;
1209 else /* CL37 Autoneg Disabled */
1210 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1211 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN);
1212
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001213 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001214 MDIO_REG_BANK_COMBO_IEEE0,
1215 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
1216
1217 /* Enable/Disable Autodetection */
1218
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001219 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001220 MDIO_REG_BANK_SERDES_DIGITAL,
1221 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, &reg_val);
Eilon Greenstein239d6862009-08-12 08:23:04 +00001222 reg_val &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN |
1223 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT);
1224 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001225 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001226 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
1227 else
1228 reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
1229
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001230 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001231 MDIO_REG_BANK_SERDES_DIGITAL,
1232 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, reg_val);
1233
1234 /* Enable TetonII and BAM autoneg */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001235 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001236 MDIO_REG_BANK_BAM_NEXT_PAGE,
1237 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
1238 &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001239 if (vars->line_speed == SPEED_AUTO_NEG) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001240 /* Enable BAM aneg Mode and TetonII aneg Mode */
1241 reg_val |= (MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
1242 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
1243 } else {
1244 /* TetonII and BAM Autoneg Disabled */
1245 reg_val &= ~(MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
1246 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
1247 }
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001248 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001249 MDIO_REG_BANK_BAM_NEXT_PAGE,
1250 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
1251 reg_val);
1252
Eilon Greenstein239d6862009-08-12 08:23:04 +00001253 if (enable_cl73) {
1254 /* Enable Cl73 FSM status bits */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001255 CL45_WR_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001256 MDIO_REG_BANK_CL73_USERB0,
1257 MDIO_CL73_USERB0_CL73_UCTRL,
Yaniv Rosner7846e472009-11-05 19:18:07 +02001258 0xe);
Eilon Greenstein239d6862009-08-12 08:23:04 +00001259
1260 /* Enable BAM Station Manager*/
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001261 CL45_WR_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001262 MDIO_REG_BANK_CL73_USERB0,
1263 MDIO_CL73_USERB0_CL73_BAM_CTRL1,
1264 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN |
1265 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_STATION_MNGR_EN |
1266 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN);
1267
Yaniv Rosner7846e472009-11-05 19:18:07 +02001268 /* Advertise CL73 link speeds */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001269 CL45_RD_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001270 MDIO_REG_BANK_CL73_IEEEB1,
1271 MDIO_CL73_IEEEB1_AN_ADV2,
1272 &reg_val);
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001273 if (phy->speed_cap_mask &
Yaniv Rosner7846e472009-11-05 19:18:07 +02001274 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
1275 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001276 if (phy->speed_cap_mask &
Yaniv Rosner7846e472009-11-05 19:18:07 +02001277 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
1278 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX;
Eilon Greenstein239d6862009-08-12 08:23:04 +00001279
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001280 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001281 MDIO_REG_BANK_CL73_IEEEB1,
1282 MDIO_CL73_IEEEB1_AN_ADV2,
1283 reg_val);
Eilon Greenstein239d6862009-08-12 08:23:04 +00001284
Eilon Greenstein239d6862009-08-12 08:23:04 +00001285 /* CL73 Autoneg Enabled */
1286 reg_val = MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN;
1287
1288 } else /* CL73 Autoneg Disabled */
1289 reg_val = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001290
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001291 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001292 MDIO_REG_BANK_CL73_IEEEB0,
1293 MDIO_CL73_IEEEB0_CL73_AN_CONTROL, reg_val);
1294}
1295
1296/* program SerDes, forced speed */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001297static void bnx2x_program_serdes(struct bnx2x_phy *phy,
1298 struct link_params *params,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001299 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001300{
1301 struct bnx2x *bp = params->bp;
1302 u16 reg_val;
1303
Eilon Greenstein57937202009-08-12 08:23:53 +00001304 /* program duplex, disable autoneg and sgmii*/
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001305 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001306 MDIO_REG_BANK_COMBO_IEEE0,
1307 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
1308 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX |
Eilon Greenstein57937202009-08-12 08:23:53 +00001309 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1310 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK);
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001311 if (phy->req_duplex == DUPLEX_FULL)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001312 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001313 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001314 MDIO_REG_BANK_COMBO_IEEE0,
1315 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
1316
1317 /* program speed
1318 - needed only if the speed is greater than 1G (2.5G or 10G) */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001319 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001320 MDIO_REG_BANK_SERDES_DIGITAL,
1321 MDIO_SERDES_DIGITAL_MISC1, &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001322 /* clearing the speed value before setting the right speed */
1323 DP(NETIF_MSG_LINK, "MDIO_REG_BANK_SERDES_DIGITAL = 0x%x\n", reg_val);
1324
1325 reg_val &= ~(MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_MASK |
1326 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
1327
1328 if (!((vars->line_speed == SPEED_1000) ||
1329 (vars->line_speed == SPEED_100) ||
1330 (vars->line_speed == SPEED_10))) {
1331
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001332 reg_val |= (MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_156_25M |
1333 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001334 if (vars->line_speed == SPEED_10000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001335 reg_val |=
1336 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_10G_CX4;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001337 if (vars->line_speed == SPEED_13000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001338 reg_val |=
1339 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_13G;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001340 }
1341
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001342 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001343 MDIO_REG_BANK_SERDES_DIGITAL,
1344 MDIO_SERDES_DIGITAL_MISC1, reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001345
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001346}
1347
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001348static void bnx2x_set_brcm_cl37_advertisment(struct bnx2x_phy *phy,
1349 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001350{
1351 struct bnx2x *bp = params->bp;
1352 u16 val = 0;
1353
1354 /* configure the 48 bits for BAM AN */
1355
1356 /* set extended capabilities */
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001357 if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001358 val |= MDIO_OVER_1G_UP1_2_5G;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001359 if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001360 val |= MDIO_OVER_1G_UP1_10G;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001361 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001362 MDIO_REG_BANK_OVER_1G,
1363 MDIO_OVER_1G_UP1, val);
1364
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001365 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001366 MDIO_REG_BANK_OVER_1G,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001367 MDIO_OVER_1G_UP3, 0x400);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001368}
1369
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001370static void bnx2x_calc_ieee_aneg_adv(struct bnx2x_phy *phy,
1371 struct link_params *params, u16 *ieee_fc)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001372{
Yaniv Rosnerd5cb9e92009-11-05 19:18:10 +02001373 struct bnx2x *bp = params->bp;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001374 *ieee_fc = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001375 /* resolve pause mode and advertisement
1376 * Please refer to Table 28B-3 of the 802.3ab-1999 spec */
1377
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001378 switch (phy->req_flow_ctrl) {
David S. Millerc0700f92008-12-16 23:53:20 -08001379 case BNX2X_FLOW_CTRL_AUTO:
1380 if (params->req_fc_auto_adv == BNX2X_FLOW_CTRL_BOTH) {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001381 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001382 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
1383 } else {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001384 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001385 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
1386 }
1387 break;
David S. Millerc0700f92008-12-16 23:53:20 -08001388 case BNX2X_FLOW_CTRL_TX:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001389 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001390 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
1391 break;
1392
David S. Millerc0700f92008-12-16 23:53:20 -08001393 case BNX2X_FLOW_CTRL_RX:
1394 case BNX2X_FLOW_CTRL_BOTH:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001395 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001396 break;
1397
David S. Millerc0700f92008-12-16 23:53:20 -08001398 case BNX2X_FLOW_CTRL_NONE:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001399 default:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001400 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001401 break;
1402 }
Yaniv Rosnerd5cb9e92009-11-05 19:18:10 +02001403 DP(NETIF_MSG_LINK, "ieee_fc = 0x%x\n", *ieee_fc);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001404}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001405
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001406static void bnx2x_set_ieee_aneg_advertisment(struct bnx2x_phy *phy,
1407 struct link_params *params,
Eilon Greenstein1ef70b92009-08-12 08:23:59 +00001408 u16 ieee_fc)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001409{
1410 struct bnx2x *bp = params->bp;
Yaniv Rosner7846e472009-11-05 19:18:07 +02001411 u16 val;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001412 /* for AN, we are always publishing full duplex */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001413
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001414 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001415 MDIO_REG_BANK_COMBO_IEEE0,
Eilon Greenstein1ef70b92009-08-12 08:23:59 +00001416 MDIO_COMBO_IEEE0_AUTO_NEG_ADV, ieee_fc);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001417 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner7846e472009-11-05 19:18:07 +02001418 MDIO_REG_BANK_CL73_IEEEB1,
1419 MDIO_CL73_IEEEB1_AN_ADV1, &val);
1420 val &= ~MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_BOTH;
1421 val |= ((ieee_fc<<3) & MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001422 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosner7846e472009-11-05 19:18:07 +02001423 MDIO_REG_BANK_CL73_IEEEB1,
1424 MDIO_CL73_IEEEB1_AN_ADV1, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001425}
1426
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001427static void bnx2x_restart_autoneg(struct bnx2x_phy *phy,
1428 struct link_params *params,
1429 u8 enable_cl73)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001430{
1431 struct bnx2x *bp = params->bp;
Eilon Greenstein3a36f2e2009-02-12 08:37:09 +00001432 u16 mii_control;
Eilon Greenstein239d6862009-08-12 08:23:04 +00001433
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001434 DP(NETIF_MSG_LINK, "bnx2x_restart_autoneg\n");
Eilon Greenstein3a36f2e2009-02-12 08:37:09 +00001435 /* Enable and restart BAM/CL37 aneg */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001436
Eilon Greenstein239d6862009-08-12 08:23:04 +00001437 if (enable_cl73) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001438 CL45_RD_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001439 MDIO_REG_BANK_CL73_IEEEB0,
1440 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1441 &mii_control);
1442
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001443 CL45_WR_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001444 MDIO_REG_BANK_CL73_IEEEB0,
1445 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1446 (mii_control |
1447 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN |
1448 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN));
1449 } else {
1450
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001451 CL45_RD_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001452 MDIO_REG_BANK_COMBO_IEEE0,
1453 MDIO_COMBO_IEEE0_MII_CONTROL,
1454 &mii_control);
1455 DP(NETIF_MSG_LINK,
1456 "bnx2x_restart_autoneg mii_control before = 0x%x\n",
1457 mii_control);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001458 CL45_WR_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001459 MDIO_REG_BANK_COMBO_IEEE0,
1460 MDIO_COMBO_IEEE0_MII_CONTROL,
1461 (mii_control |
1462 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1463 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN));
1464 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001465}
1466
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001467static void bnx2x_initialize_sgmii_process(struct bnx2x_phy *phy,
1468 struct link_params *params,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001469 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001470{
1471 struct bnx2x *bp = params->bp;
1472 u16 control1;
1473
1474 /* in SGMII mode, the unicore is always slave */
1475
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001476 CL45_RD_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 control1 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT;
1481 /* set sgmii mode (and not fiber) */
1482 control1 &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE |
1483 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET |
1484 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_MSTR_MODE);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001485 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001486 MDIO_REG_BANK_SERDES_DIGITAL,
1487 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
1488 control1);
1489
1490 /* if forced speed */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001491 if (!(vars->line_speed == SPEED_AUTO_NEG)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001492 /* set speed, disable autoneg */
1493 u16 mii_control;
1494
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001495 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001496 MDIO_REG_BANK_COMBO_IEEE0,
1497 MDIO_COMBO_IEEE0_MII_CONTROL,
1498 &mii_control);
1499 mii_control &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1500 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK|
1501 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX);
1502
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001503 switch (vars->line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001504 case SPEED_100:
1505 mii_control |=
1506 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_100;
1507 break;
1508 case SPEED_1000:
1509 mii_control |=
1510 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_1000;
1511 break;
1512 case SPEED_10:
1513 /* there is nothing to set for 10M */
1514 break;
1515 default:
1516 /* invalid speed for SGMII */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001517 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
1518 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001519 break;
1520 }
1521
1522 /* setting the full duplex */
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001523 if (phy->req_duplex == DUPLEX_FULL)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001524 mii_control |=
1525 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001526 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001527 MDIO_REG_BANK_COMBO_IEEE0,
1528 MDIO_COMBO_IEEE0_MII_CONTROL,
1529 mii_control);
1530
1531 } else { /* AN mode */
1532 /* enable and restart AN */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001533 bnx2x_restart_autoneg(phy, params, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001534 }
1535}
1536
1537
1538/*
1539 * link management
1540 */
1541
1542static void bnx2x_pause_resolve(struct link_vars *vars, u32 pause_result)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001543{ /* LD LP */
1544 switch (pause_result) { /* ASYM P ASYM P */
1545 case 0xb: /* 1 0 1 1 */
David S. Millerc0700f92008-12-16 23:53:20 -08001546 vars->flow_ctrl = BNX2X_FLOW_CTRL_TX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001547 break;
1548
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001549 case 0xe: /* 1 1 1 0 */
David S. Millerc0700f92008-12-16 23:53:20 -08001550 vars->flow_ctrl = BNX2X_FLOW_CTRL_RX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001551 break;
1552
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001553 case 0x5: /* 0 1 0 1 */
1554 case 0x7: /* 0 1 1 1 */
1555 case 0xd: /* 1 1 0 1 */
1556 case 0xf: /* 1 1 1 1 */
David S. Millerc0700f92008-12-16 23:53:20 -08001557 vars->flow_ctrl = BNX2X_FLOW_CTRL_BOTH;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001558 break;
1559
1560 default:
1561 break;
1562 }
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001563 if (pause_result & (1<<0))
1564 vars->link_status |= LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE;
1565 if (pause_result & (1<<1))
1566 vars->link_status |= LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE;
1567
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001568}
1569
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001570static u8 bnx2x_direct_parallel_detect_used(struct bnx2x_phy *phy,
1571 struct link_params *params)
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02001572{
1573 struct bnx2x *bp = params->bp;
1574 u16 pd_10g, status2_1000x;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001575 if (phy->req_line_speed != SPEED_AUTO_NEG)
1576 return 0;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001577 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02001578 MDIO_REG_BANK_SERDES_DIGITAL,
1579 MDIO_SERDES_DIGITAL_A_1000X_STATUS2,
1580 &status2_1000x);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001581 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02001582 MDIO_REG_BANK_SERDES_DIGITAL,
1583 MDIO_SERDES_DIGITAL_A_1000X_STATUS2,
1584 &status2_1000x);
1585 if (status2_1000x & MDIO_SERDES_DIGITAL_A_1000X_STATUS2_AN_DISABLED) {
1586 DP(NETIF_MSG_LINK, "1G parallel detect link on port %d\n",
1587 params->port);
1588 return 1;
1589 }
1590
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001591 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02001592 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1593 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_STATUS,
1594 &pd_10g);
1595
1596 if (pd_10g & MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_STATUS_PD_LINK) {
1597 DP(NETIF_MSG_LINK, "10G parallel detect link on port %d\n",
1598 params->port);
1599 return 1;
1600 }
1601 return 0;
1602}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001603
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001604static void bnx2x_flow_ctrl_resolve(struct bnx2x_phy *phy,
1605 struct link_params *params,
1606 struct link_vars *vars,
1607 u32 gp_status)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001608{
1609 struct bnx2x *bp = params->bp;
Eilon Greenstein3196a882008-08-13 15:58:49 -07001610 u16 ld_pause; /* local driver */
1611 u16 lp_pause; /* link partner */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001612 u16 pause_result;
1613
David S. Millerc0700f92008-12-16 23:53:20 -08001614 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001615
1616 /* resolve from gp_status in case of AN complete and not sgmii */
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001617 if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO)
1618 vars->flow_ctrl = phy->req_flow_ctrl;
1619 else if (phy->req_line_speed != SPEED_AUTO_NEG)
1620 vars->flow_ctrl = params->req_fc_auto_adv;
1621 else if ((gp_status & MDIO_AN_CL73_OR_37_COMPLETE) &&
1622 (!(vars->phy_flags & PHY_SGMII_FLAG))) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001623 if (bnx2x_direct_parallel_detect_used(phy, params)) {
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02001624 vars->flow_ctrl = params->req_fc_auto_adv;
1625 return;
1626 }
Yaniv Rosner7846e472009-11-05 19:18:07 +02001627 if ((gp_status &
1628 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
1629 MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) ==
1630 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
1631 MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) {
1632
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001633 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner7846e472009-11-05 19:18:07 +02001634 MDIO_REG_BANK_CL73_IEEEB1,
1635 MDIO_CL73_IEEEB1_AN_ADV1,
1636 &ld_pause);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001637 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner7846e472009-11-05 19:18:07 +02001638 MDIO_REG_BANK_CL73_IEEEB1,
1639 MDIO_CL73_IEEEB1_AN_LP_ADV1,
1640 &lp_pause);
1641 pause_result = (ld_pause &
1642 MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK)
1643 >> 8;
1644 pause_result |= (lp_pause &
1645 MDIO_CL73_IEEEB1_AN_LP_ADV1_PAUSE_MASK)
1646 >> 10;
1647 DP(NETIF_MSG_LINK, "pause_result CL73 0x%x\n",
1648 pause_result);
1649 } else {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001650 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner7846e472009-11-05 19:18:07 +02001651 MDIO_REG_BANK_COMBO_IEEE0,
1652 MDIO_COMBO_IEEE0_AUTO_NEG_ADV,
1653 &ld_pause);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001654 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner7846e472009-11-05 19:18:07 +02001655 MDIO_REG_BANK_COMBO_IEEE0,
1656 MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1,
1657 &lp_pause);
1658 pause_result = (ld_pause &
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001659 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>5;
Yaniv Rosner7846e472009-11-05 19:18:07 +02001660 pause_result |= (lp_pause &
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001661 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7;
Yaniv Rosner7846e472009-11-05 19:18:07 +02001662 DP(NETIF_MSG_LINK, "pause_result CL37 0x%x\n",
1663 pause_result);
1664 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001665 bnx2x_pause_resolve(vars, pause_result);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001666 }
1667 DP(NETIF_MSG_LINK, "flow_ctrl 0x%x\n", vars->flow_ctrl);
1668}
1669
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001670static void bnx2x_check_fallback_to_cl37(struct bnx2x_phy *phy,
1671 struct link_params *params)
Eilon Greenstein239d6862009-08-12 08:23:04 +00001672{
1673 struct bnx2x *bp = params->bp;
1674 u16 rx_status, ustat_val, cl37_fsm_recieved;
1675 DP(NETIF_MSG_LINK, "bnx2x_check_fallback_to_cl37\n");
1676 /* Step 1: Make sure signal is detected */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001677 CL45_RD_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001678 MDIO_REG_BANK_RX0,
1679 MDIO_RX0_RX_STATUS,
1680 &rx_status);
1681 if ((rx_status & MDIO_RX0_RX_STATUS_SIGDET) !=
1682 (MDIO_RX0_RX_STATUS_SIGDET)) {
1683 DP(NETIF_MSG_LINK, "Signal is not detected. Restoring CL73."
1684 "rx_status(0x80b0) = 0x%x\n", rx_status);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001685 CL45_WR_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001686 MDIO_REG_BANK_CL73_IEEEB0,
1687 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1688 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN);
1689 return;
1690 }
1691 /* Step 2: Check CL73 state machine */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001692 CL45_RD_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001693 MDIO_REG_BANK_CL73_USERB0,
1694 MDIO_CL73_USERB0_CL73_USTAT1,
1695 &ustat_val);
1696 if ((ustat_val &
1697 (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK |
1698 MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) !=
1699 (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK |
1700 MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) {
1701 DP(NETIF_MSG_LINK, "CL73 state-machine is not stable. "
1702 "ustat_val(0x8371) = 0x%x\n", ustat_val);
1703 return;
1704 }
1705 /* Step 3: Check CL37 Message Pages received to indicate LP
1706 supports only CL37 */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001707 CL45_RD_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001708 MDIO_REG_BANK_REMOTE_PHY,
1709 MDIO_REMOTE_PHY_MISC_RX_STATUS,
1710 &cl37_fsm_recieved);
1711 if ((cl37_fsm_recieved &
1712 (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG |
1713 MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) !=
1714 (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG |
1715 MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) {
1716 DP(NETIF_MSG_LINK, "No CL37 FSM were received. "
1717 "misc_rx_status(0x8330) = 0x%x\n",
1718 cl37_fsm_recieved);
1719 return;
1720 }
1721 /* The combined cl37/cl73 fsm state information indicating that we are
1722 connected to a device which does not support cl73, but does support
1723 cl37 BAM. In this case we disable cl73 and restart cl37 auto-neg */
1724 /* Disable CL73 */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001725 CL45_WR_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001726 MDIO_REG_BANK_CL73_IEEEB0,
1727 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1728 0);
1729 /* Restart CL37 autoneg */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001730 bnx2x_restart_autoneg(phy, params, 0);
Eilon Greenstein239d6862009-08-12 08:23:04 +00001731 DP(NETIF_MSG_LINK, "Disabling CL73, and restarting CL37 autoneg\n");
1732}
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001733
1734static void bnx2x_xgxs_an_resolve(struct bnx2x_phy *phy,
1735 struct link_params *params,
1736 struct link_vars *vars,
1737 u32 gp_status)
1738{
1739 if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE)
1740 vars->link_status |=
1741 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
1742
1743 if (bnx2x_direct_parallel_detect_used(phy, params))
1744 vars->link_status |=
1745 LINK_STATUS_PARALLEL_DETECTION_USED;
1746}
1747
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00001748static u8 bnx2x_link_settings_status(struct bnx2x_phy *phy,
1749 struct link_params *params,
1750 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001751{
1752 struct bnx2x *bp = params->bp;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00001753 u16 new_line_speed , gp_status;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001754 u8 rc = 0;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00001755
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00001756 /* Read gp_status */
1757 CL45_RD_OVER_CL22(bp, phy,
1758 MDIO_REG_BANK_GP_STATUS,
1759 MDIO_GP_STATUS_TOP_AN_STATUS1,
1760 &gp_status);
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001761 if (phy->req_line_speed == SPEED_AUTO_NEG)
1762 vars->link_status |= LINK_STATUS_AUTO_NEGOTIATE_ENABLED;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001763 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) {
1764 DP(NETIF_MSG_LINK, "phy link up gp_status=0x%x\n",
1765 gp_status);
1766
1767 vars->phy_link_up = 1;
1768 vars->link_status |= LINK_STATUS_LINK_UP;
1769
1770 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_DUPLEX_STATUS)
1771 vars->duplex = DUPLEX_FULL;
1772 else
1773 vars->duplex = DUPLEX_HALF;
1774
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001775 if (SINGLE_MEDIA_DIRECT(params)) {
1776 bnx2x_flow_ctrl_resolve(phy, params, vars, gp_status);
1777 if (phy->req_line_speed == SPEED_AUTO_NEG)
1778 bnx2x_xgxs_an_resolve(phy, params, vars,
1779 gp_status);
1780 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001781
1782 switch (gp_status & GP_STATUS_SPEED_MASK) {
1783 case GP_STATUS_10M:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001784 new_line_speed = SPEED_10;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001785 if (vars->duplex == DUPLEX_FULL)
1786 vars->link_status |= LINK_10TFD;
1787 else
1788 vars->link_status |= LINK_10THD;
1789 break;
1790
1791 case GP_STATUS_100M:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001792 new_line_speed = SPEED_100;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001793 if (vars->duplex == DUPLEX_FULL)
1794 vars->link_status |= LINK_100TXFD;
1795 else
1796 vars->link_status |= LINK_100TXHD;
1797 break;
1798
1799 case GP_STATUS_1G:
1800 case GP_STATUS_1G_KX:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001801 new_line_speed = SPEED_1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001802 if (vars->duplex == DUPLEX_FULL)
1803 vars->link_status |= LINK_1000TFD;
1804 else
1805 vars->link_status |= LINK_1000THD;
1806 break;
1807
1808 case GP_STATUS_2_5G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001809 new_line_speed = SPEED_2500;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001810 if (vars->duplex == DUPLEX_FULL)
1811 vars->link_status |= LINK_2500TFD;
1812 else
1813 vars->link_status |= LINK_2500THD;
1814 break;
1815
1816 case GP_STATUS_5G:
1817 case GP_STATUS_6G:
1818 DP(NETIF_MSG_LINK,
1819 "link speed unsupported gp_status 0x%x\n",
1820 gp_status);
1821 return -EINVAL;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00001822
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001823 case GP_STATUS_10G_KX4:
1824 case GP_STATUS_10G_HIG:
1825 case GP_STATUS_10G_CX4:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001826 new_line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001827 vars->link_status |= LINK_10GTFD;
1828 break;
1829
1830 case GP_STATUS_12G_HIG:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001831 new_line_speed = SPEED_12000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001832 vars->link_status |= LINK_12GTFD;
1833 break;
1834
1835 case GP_STATUS_12_5G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001836 new_line_speed = SPEED_12500;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001837 vars->link_status |= LINK_12_5GTFD;
1838 break;
1839
1840 case GP_STATUS_13G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001841 new_line_speed = SPEED_13000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001842 vars->link_status |= LINK_13GTFD;
1843 break;
1844
1845 case GP_STATUS_15G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001846 new_line_speed = SPEED_15000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001847 vars->link_status |= LINK_15GTFD;
1848 break;
1849
1850 case GP_STATUS_16G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001851 new_line_speed = SPEED_16000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001852 vars->link_status |= LINK_16GTFD;
1853 break;
1854
1855 default:
1856 DP(NETIF_MSG_LINK,
1857 "link speed unsupported gp_status 0x%x\n",
1858 gp_status);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00001859 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001860 }
1861
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001862 vars->line_speed = new_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001863
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001864
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001865 } else { /* link_down */
1866 DP(NETIF_MSG_LINK, "phy link down\n");
1867
1868 vars->phy_link_up = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07001869
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001870 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08001871 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001872 vars->mac_type = MAC_TYPE_NONE;
Eilon Greenstein239d6862009-08-12 08:23:04 +00001873
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00001874 if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
1875 SINGLE_MEDIA_DIRECT(params)) {
Eilon Greenstein239d6862009-08-12 08:23:04 +00001876 /* Check signal is detected */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00001877 bnx2x_check_fallback_to_cl37(phy, params);
Eilon Greenstein239d6862009-08-12 08:23:04 +00001878 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001879 }
1880
Frans Pop2381a552010-03-24 07:57:36 +00001881 DP(NETIF_MSG_LINK, "gp_status 0x%x phy_link_up %x line_speed %x\n",
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001882 gp_status, vars->phy_link_up, vars->line_speed);
1883 DP(NETIF_MSG_LINK, "duplex %x flow_ctrl 0x%x"
1884 " autoneg 0x%x\n",
1885 vars->duplex,
1886 vars->flow_ctrl, vars->autoneg);
1887 DP(NETIF_MSG_LINK, "link_status 0x%x\n", vars->link_status);
1888
1889 return rc;
1890}
1891
Eilon Greensteined8680a2009-02-12 08:37:12 +00001892static void bnx2x_set_gmii_tx_driver(struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001893{
1894 struct bnx2x *bp = params->bp;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001895 struct bnx2x_phy *phy = &params->phy[INT_PHY];
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001896 u16 lp_up2;
1897 u16 tx_driver;
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00001898 u16 bank;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001899
1900 /* read precomp */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001901 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001902 MDIO_REG_BANK_OVER_1G,
1903 MDIO_OVER_1G_LP_UP2, &lp_up2);
1904
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001905 /* bits [10:7] at lp_up2, positioned at [15:12] */
1906 lp_up2 = (((lp_up2 & MDIO_OVER_1G_LP_UP2_PREEMPHASIS_MASK) >>
1907 MDIO_OVER_1G_LP_UP2_PREEMPHASIS_SHIFT) <<
1908 MDIO_TX0_TX_DRIVER_PREEMPHASIS_SHIFT);
1909
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00001910 if (lp_up2 == 0)
1911 return;
1912
1913 for (bank = MDIO_REG_BANK_TX0; bank <= MDIO_REG_BANK_TX3;
1914 bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0)) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001915 CL45_RD_OVER_CL22(bp, phy,
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00001916 bank,
1917 MDIO_TX0_TX_DRIVER, &tx_driver);
1918
1919 /* replace tx_driver bits [15:12] */
1920 if (lp_up2 !=
1921 (tx_driver & MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK)) {
1922 tx_driver &= ~MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK;
1923 tx_driver |= lp_up2;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001924 CL45_WR_OVER_CL22(bp, phy,
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00001925 bank,
1926 MDIO_TX0_TX_DRIVER, tx_driver);
1927 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001928 }
1929}
1930
1931static u8 bnx2x_emac_program(struct link_params *params,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00001932 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001933{
1934 struct bnx2x *bp = params->bp;
1935 u8 port = params->port;
1936 u16 mode = 0;
1937
1938 DP(NETIF_MSG_LINK, "setting link speed & duplex\n");
1939 bnx2x_bits_dis(bp, GRCBASE_EMAC0 + port*0x400 +
1940 EMAC_REG_EMAC_MODE,
1941 (EMAC_MODE_25G_MODE |
1942 EMAC_MODE_PORT_MII_10M |
1943 EMAC_MODE_HALF_DUPLEX));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00001944 switch (vars->line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001945 case SPEED_10:
1946 mode |= EMAC_MODE_PORT_MII_10M;
1947 break;
1948
1949 case SPEED_100:
1950 mode |= EMAC_MODE_PORT_MII;
1951 break;
1952
1953 case SPEED_1000:
1954 mode |= EMAC_MODE_PORT_GMII;
1955 break;
1956
1957 case SPEED_2500:
1958 mode |= (EMAC_MODE_25G_MODE | EMAC_MODE_PORT_GMII);
1959 break;
1960
1961 default:
1962 /* 10G not valid for EMAC */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00001963 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
1964 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001965 return -EINVAL;
1966 }
1967
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00001968 if (vars->duplex == DUPLEX_HALF)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001969 mode |= EMAC_MODE_HALF_DUPLEX;
1970 bnx2x_bits_en(bp,
1971 GRCBASE_EMAC0 + port*0x400 + EMAC_REG_EMAC_MODE,
1972 mode);
1973
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00001974 bnx2x_set_led(params, LED_MODE_OPER, vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001975 return 0;
1976}
1977
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001978static void bnx2x_set_preemphasis(struct bnx2x_phy *phy,
1979 struct link_params *params)
1980{
1981
1982 u16 bank, i = 0;
1983 struct bnx2x *bp = params->bp;
1984
1985 for (bank = MDIO_REG_BANK_RX0, i = 0; bank <= MDIO_REG_BANK_RX3;
1986 bank += (MDIO_REG_BANK_RX1-MDIO_REG_BANK_RX0), i++) {
1987 CL45_WR_OVER_CL22(bp, phy,
1988 bank,
1989 MDIO_RX0_RX_EQ_BOOST,
1990 phy->rx_preemphasis[i]);
1991 }
1992
1993 for (bank = MDIO_REG_BANK_TX0, i = 0; bank <= MDIO_REG_BANK_TX3;
1994 bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0), i++) {
1995 CL45_WR_OVER_CL22(bp, phy,
1996 bank,
1997 MDIO_TX0_TX_DRIVER,
1998 phy->tx_preemphasis[i]);
1999 }
2000}
2001
2002static void bnx2x_init_internal_phy(struct bnx2x_phy *phy,
2003 struct link_params *params,
2004 struct link_vars *vars)
2005{
2006 struct bnx2x *bp = params->bp;
2007 u8 enable_cl73 = (SINGLE_MEDIA_DIRECT(params) ||
2008 (params->loopback_mode == LOOPBACK_XGXS));
2009 if (!(vars->phy_flags & PHY_SGMII_FLAG)) {
2010 if (SINGLE_MEDIA_DIRECT(params) &&
2011 (params->feature_config_flags &
2012 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED))
2013 bnx2x_set_preemphasis(phy, params);
2014
2015 /* forced speed requested? */
2016 if (vars->line_speed != SPEED_AUTO_NEG ||
2017 (SINGLE_MEDIA_DIRECT(params) &&
2018 params->loopback_mode == LOOPBACK_EXT)) {
2019 DP(NETIF_MSG_LINK, "not SGMII, no AN\n");
2020
2021 /* disable autoneg */
2022 bnx2x_set_autoneg(phy, params, vars, 0);
2023
2024 /* program speed and duplex */
2025 bnx2x_program_serdes(phy, params, vars);
2026
2027 } else { /* AN_mode */
2028 DP(NETIF_MSG_LINK, "not SGMII, AN\n");
2029
2030 /* AN enabled */
2031 bnx2x_set_brcm_cl37_advertisment(phy, params);
2032
2033 /* program duplex & pause advertisement (for aneg) */
2034 bnx2x_set_ieee_aneg_advertisment(phy, params,
2035 vars->ieee_fc);
2036
2037 /* enable autoneg */
2038 bnx2x_set_autoneg(phy, params, vars, enable_cl73);
2039
2040 /* enable and restart AN */
2041 bnx2x_restart_autoneg(phy, params, enable_cl73);
2042 }
2043
2044 } else { /* SGMII mode */
2045 DP(NETIF_MSG_LINK, "SGMII\n");
2046
2047 bnx2x_initialize_sgmii_process(phy, params, vars);
2048 }
2049}
2050
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002051static u8 bnx2x_init_serdes(struct bnx2x_phy *phy,
2052 struct link_params *params,
2053 struct link_vars *vars)
2054{
2055 u8 rc;
2056 vars->phy_flags |= PHY_SGMII_FLAG;
2057 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
2058 bnx2x_set_aer_mmd(params, phy);
2059 rc = bnx2x_reset_unicore(params, phy, 1);
2060 /* reset the SerDes and wait for reset bit return low */
2061 if (rc != 0)
2062 return rc;
2063 bnx2x_set_aer_mmd(params, phy);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002064
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002065 return rc;
2066}
2067
2068static u8 bnx2x_init_xgxs(struct bnx2x_phy *phy,
2069 struct link_params *params,
2070 struct link_vars *vars)
2071{
2072 u8 rc;
2073 vars->phy_flags = PHY_XGXS_FLAG;
2074 if ((phy->req_line_speed &&
2075 ((phy->req_line_speed == SPEED_100) ||
2076 (phy->req_line_speed == SPEED_10))) ||
2077 (!phy->req_line_speed &&
2078 (phy->speed_cap_mask >=
2079 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL) &&
2080 (phy->speed_cap_mask <
2081 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
2082 ))
2083 vars->phy_flags |= PHY_SGMII_FLAG;
2084 else
2085 vars->phy_flags &= ~PHY_SGMII_FLAG;
2086
2087 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
2088 bnx2x_set_aer_mmd(params, phy);
2089 bnx2x_set_master_ln(params, phy);
2090
2091 rc = bnx2x_reset_unicore(params, phy, 0);
2092 /* reset the SerDes and wait for reset bit return low */
2093 if (rc != 0)
2094 return rc;
2095
2096 bnx2x_set_aer_mmd(params, phy);
2097
2098 /* setting the masterLn_def again after the reset */
2099 bnx2x_set_master_ln(params, phy);
2100 bnx2x_set_swap_lanes(params, phy);
2101
2102 return rc;
2103}
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002104
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002105static u16 bnx2x_wait_reset_complete(struct bnx2x *bp,
2106 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002107{
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002108 u16 cnt, ctrl;
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002109 /* Wait for soft reset to get cleared upto 1 sec */
2110 for (cnt = 0; cnt < 1000; cnt++) {
2111 bnx2x_cl45_read(bp, phy,
2112 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, &ctrl);
2113 if (!(ctrl & (1<<15)))
2114 break;
2115 msleep(1);
2116 }
2117 DP(NETIF_MSG_LINK, "control reg 0x%x (after %d ms)\n", ctrl, cnt);
2118 return cnt;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002119}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002120
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002121static void bnx2x_link_int_enable(struct link_params *params)
2122{
2123 u8 port = params->port;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002124 u32 mask;
2125 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002126
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002127 /* setting the status to report on link up
2128 for either XGXS or SerDes */
2129
2130 if (params->switch_cfg == SWITCH_CFG_10G) {
2131 mask = (NIG_MASK_XGXS0_LINK10G |
2132 NIG_MASK_XGXS0_LINK_STATUS);
2133 DP(NETIF_MSG_LINK, "enabled XGXS interrupt\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002134 if (!(SINGLE_MEDIA_DIRECT(params)) &&
2135 params->phy[INT_PHY].type !=
2136 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002137 mask |= NIG_MASK_MI_INT;
2138 DP(NETIF_MSG_LINK, "enabled external phy int\n");
2139 }
2140
2141 } else { /* SerDes */
2142 mask = NIG_MASK_SERDES0_LINK_STATUS;
2143 DP(NETIF_MSG_LINK, "enabled SerDes interrupt\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002144 if (!(SINGLE_MEDIA_DIRECT(params)) &&
2145 params->phy[INT_PHY].type !=
2146 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_NOT_CONN) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002147 mask |= NIG_MASK_MI_INT;
2148 DP(NETIF_MSG_LINK, "enabled external phy int\n");
2149 }
2150 }
2151 bnx2x_bits_en(bp,
2152 NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
2153 mask);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002154
2155 DP(NETIF_MSG_LINK, "port %x, is_xgxs %x, int_status 0x%x\n", port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002156 (params->switch_cfg == SWITCH_CFG_10G),
2157 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002158 DP(NETIF_MSG_LINK, " int_mask 0x%x, MI_INT %x, SERDES_LINK %x\n",
2159 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
2160 REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
2161 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS+port*0x3c));
2162 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
2163 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
2164 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
2165}
2166
Eilon Greenstein2f904462009-08-12 08:22:16 +00002167static void bnx2x_8481_rearm_latch_signal(struct bnx2x *bp, u8 port,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002168 u8 is_mi_int)
Eilon Greenstein2f904462009-08-12 08:22:16 +00002169{
2170 u32 latch_status = 0, is_mi_int_status;
2171 /* Disable the MI INT ( external phy int )
2172 * by writing 1 to the status register. Link down indication
2173 * is high-active-signal, so in this case we need to write the
2174 * status to clear the XOR
2175 */
2176 /* Read Latched signals */
2177 latch_status = REG_RD(bp,
2178 NIG_REG_LATCH_STATUS_0 + port*8);
2179 is_mi_int_status = REG_RD(bp,
2180 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4);
2181 DP(NETIF_MSG_LINK, "original_signal = 0x%x, nig_status = 0x%x,"
2182 "latch_status = 0x%x\n",
2183 is_mi_int, is_mi_int_status, latch_status);
2184 /* Handle only those with latched-signal=up.*/
2185 if (latch_status & 1) {
2186 /* For all latched-signal=up,Write original_signal to status */
2187 if (is_mi_int)
2188 bnx2x_bits_en(bp,
2189 NIG_REG_STATUS_INTERRUPT_PORT0
2190 + port*4,
2191 NIG_STATUS_EMAC0_MI_INT);
2192 else
2193 bnx2x_bits_dis(bp,
2194 NIG_REG_STATUS_INTERRUPT_PORT0
2195 + port*4,
2196 NIG_STATUS_EMAC0_MI_INT);
2197 /* For all latched-signal=up : Re-Arm Latch signals */
2198 REG_WR(bp, NIG_REG_LATCH_STATUS_0 + port*8,
2199 (latch_status & 0xfffe) | (latch_status & 1));
2200 }
2201}
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002202
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002203static void bnx2x_link_int_ack(struct link_params *params,
Eilon Greenstein2f904462009-08-12 08:22:16 +00002204 struct link_vars *vars, u8 is_10g,
2205 u8 is_mi_int)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002206{
2207 struct bnx2x *bp = params->bp;
2208 u8 port = params->port;
2209
2210 /* first reset all status
2211 * we assume only one line will be change at a time */
2212 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
2213 (NIG_STATUS_XGXS0_LINK10G |
2214 NIG_STATUS_XGXS0_LINK_STATUS |
2215 NIG_STATUS_SERDES0_LINK_STATUS));
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002216 if ((params->phy[EXT_PHY1].type
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02002217 == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481) ||
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002218 (params->phy[EXT_PHY1].type
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02002219 == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823)) {
Eilon Greenstein2f904462009-08-12 08:22:16 +00002220 bnx2x_8481_rearm_latch_signal(bp, port, is_mi_int);
2221 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002222 if (vars->phy_link_up) {
2223 if (is_10g) {
2224 /* Disable the 10G link interrupt
2225 * by writing 1 to the status register
2226 */
2227 DP(NETIF_MSG_LINK, "10G XGXS phy link up\n");
2228 bnx2x_bits_en(bp,
2229 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
2230 NIG_STATUS_XGXS0_LINK10G);
2231
2232 } else if (params->switch_cfg == SWITCH_CFG_10G) {
2233 /* Disable the link interrupt
2234 * by writing 1 to the relevant lane
2235 * in the status register
2236 */
2237 u32 ser_lane = ((params->lane_config &
2238 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
2239 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
2240
Eilon Greenstein2f904462009-08-12 08:22:16 +00002241 DP(NETIF_MSG_LINK, "%d speed XGXS phy link up\n",
2242 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002243 bnx2x_bits_en(bp,
2244 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
2245 ((1 << ser_lane) <<
2246 NIG_STATUS_XGXS0_LINK_STATUS_SIZE));
2247
2248 } else { /* SerDes */
2249 DP(NETIF_MSG_LINK, "SerDes phy link up\n");
2250 /* Disable the link interrupt
2251 * by writing 1 to the status register
2252 */
2253 bnx2x_bits_en(bp,
2254 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
2255 NIG_STATUS_SERDES0_LINK_STATUS);
2256 }
2257
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002258 }
2259}
2260
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002261static u8 bnx2x_format_ver(u32 num, u8 *str, u16 *len)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002262{
2263 u8 *str_ptr = str;
2264 u32 mask = 0xf0000000;
2265 u8 shift = 8*4;
2266 u8 digit;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002267 if (*len < 10) {
Frederik Schwarzer025dfda2008-10-16 19:02:37 +02002268 /* Need more than 10chars for this format */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002269 *str_ptr = '\0';
2270 return -EINVAL;
2271 }
2272 while (shift > 0) {
2273
2274 shift -= 4;
2275 digit = ((num & mask) >> shift);
2276 if (digit < 0xa)
2277 *str_ptr = digit + '0';
2278 else
2279 *str_ptr = digit - 0xa + 'a';
2280 str_ptr++;
2281 mask = mask >> 4;
2282 if (shift == 4*4) {
2283 *str_ptr = ':';
2284 str_ptr++;
2285 }
2286 }
2287 *str_ptr = '\0';
2288 return 0;
2289}
2290
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002291static u8 bnx2x_null_format_ver(u32 spirom_ver, u8 *str, u16 *len)
2292{
2293 str[0] = '\0';
2294 (*len)--;
2295 return 0;
2296}
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002297
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002298u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
2299 u8 *version, u16 len)
2300{
Julia Lawall0376d5b2009-07-19 05:26:35 +00002301 struct bnx2x *bp;
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002302 u32 spirom_ver = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002303 u8 status = 0;
2304 u8 *ver_p = version;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002305 if (version == NULL || params == NULL)
2306 return -EINVAL;
Julia Lawall0376d5b2009-07-19 05:26:35 +00002307 bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002308
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002309 /* Extract first external phy*/
2310 version[0] = '\0';
2311 spirom_ver = REG_RD(bp, params->phy[EXT_PHY1].ver_addr);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002312
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002313 if (params->phy[EXT_PHY1].format_fw_ver)
2314 status |= params->phy[EXT_PHY1].format_fw_ver(spirom_ver,
2315 ver_p,
2316 &len);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002317 return status;
2318}
2319
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002320static void bnx2x_set_xgxs_loopback(struct bnx2x_phy *phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002321 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002322{
2323 u8 port = params->port;
2324 struct bnx2x *bp = params->bp;
2325
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002326 if (phy->req_line_speed != SPEED_1000) {
Eilon Greenstein6378c022008-08-13 15:59:25 -07002327 u32 md_devad;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002328
2329 DP(NETIF_MSG_LINK, "XGXS 10G loopback enable\n");
2330
2331 /* change the uni_phy_addr in the nig */
2332 md_devad = REG_RD(bp, (NIG_REG_XGXS0_CTRL_MD_DEVAD +
2333 port*0x18));
2334
2335 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, 0x5);
2336
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002337 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002338 5,
2339 (MDIO_REG_BANK_AER_BLOCK +
2340 (MDIO_AER_BLOCK_AER_REG & 0xf)),
2341 0x2800);
2342
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002343 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002344 5,
2345 (MDIO_REG_BANK_CL73_IEEEB0 +
2346 (MDIO_CL73_IEEEB0_CL73_AN_CONTROL & 0xf)),
2347 0x6041);
Eilon Greenstein38582762009-01-14 06:44:16 +00002348 msleep(200);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002349 /* set aer mmd back */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002350 bnx2x_set_aer_mmd(params, phy);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002351
2352 /* and md_devad */
2353 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
2354 md_devad);
2355
2356 } else {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002357 u16 mii_ctrl;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002358 DP(NETIF_MSG_LINK, "XGXS 1G loopback enable\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002359 bnx2x_cl45_read(bp, phy, 5,
2360 (MDIO_REG_BANK_COMBO_IEEE0 +
2361 (MDIO_COMBO_IEEE0_MII_CONTROL & 0xf)),
2362 &mii_ctrl);
2363 bnx2x_cl45_write(bp, phy, 5,
2364 (MDIO_REG_BANK_COMBO_IEEE0 +
2365 (MDIO_COMBO_IEEE0_MII_CONTROL & 0xf)),
2366 mii_ctrl |
2367 MDIO_COMBO_IEEO_MII_CONTROL_LOOPBACK);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002368 }
2369}
2370
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002371/*
2372 *------------------------------------------------------------------------
2373 * bnx2x_override_led_value -
2374 *
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002375 * Override the led value of the requested led
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002376 *
2377 *------------------------------------------------------------------------
2378 */
2379u8 bnx2x_override_led_value(struct bnx2x *bp, u8 port,
2380 u32 led_idx, u32 value)
2381{
2382 u32 reg_val;
2383
2384 /* If port 0 then use EMAC0, else use EMAC1*/
2385 u32 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
2386
2387 DP(NETIF_MSG_LINK,
2388 "bnx2x_override_led_value() port %x led_idx %d value %d\n",
2389 port, led_idx, value);
2390
2391 switch (led_idx) {
2392 case 0: /* 10MB led */
2393 /* Read the current value of the LED register in
2394 the EMAC block */
2395 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
2396 /* Set the OVERRIDE bit to 1 */
2397 reg_val |= EMAC_LED_OVERRIDE;
2398 /* If value is 1, set the 10M_OVERRIDE bit,
2399 otherwise reset it.*/
2400 reg_val = (value == 1) ? (reg_val | EMAC_LED_10MB_OVERRIDE) :
2401 (reg_val & ~EMAC_LED_10MB_OVERRIDE);
2402 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
2403 break;
2404 case 1: /*100MB led */
2405 /*Read the current value of the LED register in
2406 the EMAC block */
2407 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
2408 /* Set the OVERRIDE bit to 1 */
2409 reg_val |= EMAC_LED_OVERRIDE;
2410 /* If value is 1, set the 100M_OVERRIDE bit,
2411 otherwise reset it.*/
2412 reg_val = (value == 1) ? (reg_val | EMAC_LED_100MB_OVERRIDE) :
2413 (reg_val & ~EMAC_LED_100MB_OVERRIDE);
2414 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
2415 break;
2416 case 2: /* 1000MB led */
2417 /* Read the current value of the LED register in the
2418 EMAC block */
2419 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
2420 /* Set the OVERRIDE bit to 1 */
2421 reg_val |= EMAC_LED_OVERRIDE;
2422 /* If value is 1, set the 1000M_OVERRIDE bit, otherwise
2423 reset it. */
2424 reg_val = (value == 1) ? (reg_val | EMAC_LED_1000MB_OVERRIDE) :
2425 (reg_val & ~EMAC_LED_1000MB_OVERRIDE);
2426 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
2427 break;
2428 case 3: /* 2500MB led */
2429 /* Read the current value of the LED register in the
2430 EMAC block*/
2431 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
2432 /* Set the OVERRIDE bit to 1 */
2433 reg_val |= EMAC_LED_OVERRIDE;
2434 /* If value is 1, set the 2500M_OVERRIDE bit, otherwise
2435 reset it.*/
2436 reg_val = (value == 1) ? (reg_val | EMAC_LED_2500MB_OVERRIDE) :
2437 (reg_val & ~EMAC_LED_2500MB_OVERRIDE);
2438 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
2439 break;
2440 case 4: /*10G led */
2441 if (port == 0) {
2442 REG_WR(bp, NIG_REG_LED_10G_P0,
2443 value);
2444 } else {
2445 REG_WR(bp, NIG_REG_LED_10G_P1,
2446 value);
2447 }
2448 break;
2449 case 5: /* TRAFFIC led */
2450 /* Find if the traffic control is via BMAC or EMAC */
2451 if (port == 0)
2452 reg_val = REG_RD(bp, NIG_REG_NIG_EMAC0_EN);
2453 else
2454 reg_val = REG_RD(bp, NIG_REG_NIG_EMAC1_EN);
2455
2456 /* Override the traffic led in the EMAC:*/
2457 if (reg_val == 1) {
2458 /* Read the current value of the LED register in
2459 the EMAC block */
2460 reg_val = REG_RD(bp, emac_base +
2461 EMAC_REG_EMAC_LED);
2462 /* Set the TRAFFIC_OVERRIDE bit to 1 */
2463 reg_val |= EMAC_LED_OVERRIDE;
2464 /* If value is 1, set the TRAFFIC bit, otherwise
2465 reset it.*/
2466 reg_val = (value == 1) ? (reg_val | EMAC_LED_TRAFFIC) :
2467 (reg_val & ~EMAC_LED_TRAFFIC);
2468 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
2469 } else { /* Override the traffic led in the BMAC: */
2470 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
2471 + port*4, 1);
2472 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 + port*4,
2473 value);
2474 }
2475 break;
2476 default:
2477 DP(NETIF_MSG_LINK,
2478 "bnx2x_override_led_value() unknown led index %d "
2479 "(should be 0-5)\n", led_idx);
2480 return -EINVAL;
2481 }
2482
2483 return 0;
2484}
2485
Yaniv Rosner7846e472009-11-05 19:18:07 +02002486u8 bnx2x_set_led(struct link_params *params, u8 mode, u32 speed)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002487{
Yaniv Rosner7846e472009-11-05 19:18:07 +02002488 u8 port = params->port;
2489 u16 hw_led_mode = params->hw_led_mode;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002490 u8 rc = 0;
Eilon Greenstein345b5d52008-08-13 15:58:12 -07002491 u32 tmp;
2492 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Yaniv Rosner7846e472009-11-05 19:18:07 +02002493 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002494 DP(NETIF_MSG_LINK, "bnx2x_set_led: port %x, mode %d\n", port, mode);
2495 DP(NETIF_MSG_LINK, "speed 0x%x, hw_led_mode 0x%x\n",
2496 speed, hw_led_mode);
2497 switch (mode) {
2498 case LED_MODE_OFF:
2499 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 0);
2500 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
2501 SHARED_HW_CFG_LED_MAC1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07002502
2503 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07002504 EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp | EMAC_LED_OVERRIDE));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002505 break;
2506
2507 case LED_MODE_OPER:
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002508 if (SINGLE_MEDIA_DIRECT(params)) {
Yaniv Rosner7846e472009-11-05 19:18:07 +02002509 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0);
2510 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1);
2511 } else {
2512 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
2513 hw_led_mode);
2514 }
2515
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002516 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 +
2517 port*4, 0);
2518 /* Set blinking rate to ~15.9Hz */
2519 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4,
2520 LED_BLINK_RATE_VAL);
2521 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 +
2522 port*4, 1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07002523 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07002524 EMAC_WR(bp, EMAC_REG_EMAC_LED,
Eilon Greenstein345b5d52008-08-13 15:58:12 -07002525 (tmp & (~EMAC_LED_OVERRIDE)));
2526
Yaniv Rosner7846e472009-11-05 19:18:07 +02002527 if (CHIP_IS_E1(bp) &&
Eilon Greenstein34f80b02008-06-23 20:33:01 -07002528 ((speed == SPEED_2500) ||
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002529 (speed == SPEED_1000) ||
2530 (speed == SPEED_100) ||
2531 (speed == SPEED_10))) {
2532 /* On Everest 1 Ax chip versions for speeds less than
2533 10G LED scheme is different */
2534 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
2535 + port*4, 1);
2536 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 +
2537 port*4, 0);
2538 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_TRAFFIC_P0 +
2539 port*4, 1);
2540 }
2541 break;
2542
2543 default:
2544 rc = -EINVAL;
2545 DP(NETIF_MSG_LINK, "bnx2x_set_led: Invalid led mode %d\n",
2546 mode);
2547 break;
2548 }
2549 return rc;
2550
2551}
2552
2553u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars)
2554{
2555 struct bnx2x *bp = params->bp;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002556 u16 gp_status = 0, phy_index = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002557
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002558 CL45_RD_OVER_CL22(bp, &params->phy[INT_PHY],
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002559 MDIO_REG_BANK_GP_STATUS,
2560 MDIO_GP_STATUS_TOP_AN_STATUS1,
2561 &gp_status);
2562 /* link is up only if both local phy and external phy are up */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002563 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) {
2564 u8 ext_phy_link_up = 1;
2565 struct link_vars temp_vars;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002566 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
2567 phy_index++) {
2568 if (params->phy[phy_index].read_status)
2569 ext_phy_link_up &=
2570 params->phy[phy_index].read_status(
2571 &params->phy[phy_index],
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002572 params, &temp_vars);
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002573 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002574 if (ext_phy_link_up)
2575 return 0;
2576 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002577 return -ESRCH;
2578}
2579
2580static u8 bnx2x_link_initialize(struct link_params *params,
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00002581 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002582{
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002583 u8 rc = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002584 u8 phy_index, non_ext_phy;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002585 struct bnx2x *bp = params->bp;
2586 /**
2587 * In case of external phy existence, the line speed would be the
2588 * line speed linked up by the external phy. In case it is direct
2589 * only, then the line_speed during initialization will be
2590 * equal to the req_line_speed
2591 */
2592 vars->line_speed = params->phy[INT_PHY].req_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002593
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002594 /**
2595 * Initialize the internal phy in case this is a direct board
2596 * (no external phys), or this board has external phy which requires
2597 * to first.
2598 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002599
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002600 if (params->phy[INT_PHY].config_init)
2601 params->phy[INT_PHY].config_init(
2602 &params->phy[INT_PHY],
2603 params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002604
2605 /* init ext phy and enable link state int */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002606 non_ext_phy = (SINGLE_MEDIA_DIRECT(params) ||
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002607 (params->loopback_mode == LOOPBACK_XGXS));
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002608
2609 if (non_ext_phy ||
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002610 (params->phy[EXT_PHY1].flags & FLAGS_INIT_XGXS_FIRST) ||
Eilon Greenstein8660d8c2009-03-02 08:01:02 +00002611 (params->loopback_mode == LOOPBACK_EXT_PHY)) {
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002612 struct bnx2x_phy *phy = &params->phy[INT_PHY];
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002613 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002614 bnx2x_set_parallel_detection(phy, params);
2615 bnx2x_init_internal_phy(phy, params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002616 }
2617
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002618 /* Init external phy*/
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002619 if (!non_ext_phy)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002620 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
2621 phy_index++) {
2622 params->phy[phy_index].config_init(
2623 &params->phy[phy_index],
2624 params, vars);
2625 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002626
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00002627 /* Reset the interrupt indication after phy was initialized */
2628 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 +
2629 params->port*4,
2630 (NIG_STATUS_XGXS0_LINK10G |
2631 NIG_STATUS_XGXS0_LINK_STATUS |
2632 NIG_STATUS_SERDES0_LINK_STATUS |
2633 NIG_MASK_MI_INT));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002634 return rc;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002635}
2636
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002637static void bnx2x_int_link_reset(struct bnx2x_phy *phy,
2638 struct link_params *params)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002639{
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002640 /* reset the SerDes/XGXS */
2641 REG_WR(params->bp, GRCBASE_MISC +
2642 MISC_REGISTERS_RESET_REG_3_CLEAR,
2643 (0x1ff << (params->port*16)));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002644}
2645
2646static void bnx2x_common_ext_link_reset(struct bnx2x_phy *phy,
2647 struct link_params *params)
2648{
2649 struct bnx2x *bp = params->bp;
2650 u8 gpio_port;
2651 /* HW reset */
2652 gpio_port = params->port;
2653 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
2654 MISC_REGISTERS_GPIO_OUTPUT_LOW,
2655 gpio_port);
2656 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
2657 MISC_REGISTERS_GPIO_OUTPUT_LOW,
2658 gpio_port);
2659 DP(NETIF_MSG_LINK, "reset external PHY\n");
2660}
2661
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002662static u8 bnx2x_update_link_down(struct link_params *params,
2663 struct link_vars *vars)
2664{
2665 struct bnx2x *bp = params->bp;
2666 u8 port = params->port;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002667
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002668 DP(NETIF_MSG_LINK, "Port %x: Link is down\n", port);
Yaniv Rosner7846e472009-11-05 19:18:07 +02002669 bnx2x_set_led(params, LED_MODE_OFF, 0);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002670
2671 /* indicate no mac active */
2672 vars->mac_type = MAC_TYPE_NONE;
2673
2674 /* update shared memory */
2675 vars->link_status = 0;
2676 vars->line_speed = 0;
2677 bnx2x_update_mng(params, vars->link_status);
2678
2679 /* activate nig drain */
2680 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
2681
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002682 /* disable emac */
2683 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
2684
2685 msleep(10);
2686
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002687 /* reset BigMac */
2688 bnx2x_bmac_rx_disable(bp, params->port);
2689 REG_WR(bp, GRCBASE_MISC +
2690 MISC_REGISTERS_RESET_REG_2_CLEAR,
2691 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
2692 return 0;
2693}
2694
2695static u8 bnx2x_update_link_up(struct link_params *params,
2696 struct link_vars *vars,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002697 u8 link_10g)
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002698{
2699 struct bnx2x *bp = params->bp;
2700 u8 port = params->port;
2701 u8 rc = 0;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002702
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002703 vars->link_status |= LINK_STATUS_LINK_UP;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002704 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
2705 vars->link_status |=
2706 LINK_STATUS_TX_FLOW_CONTROL_ENABLED;
2707
2708 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
2709 vars->link_status |=
2710 LINK_STATUS_RX_FLOW_CONTROL_ENABLED;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002711 if (link_10g) {
2712 bnx2x_bmac_enable(params, vars, 0);
Yaniv Rosner7846e472009-11-05 19:18:07 +02002713 bnx2x_set_led(params, LED_MODE_OPER, SPEED_10000);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002714 } else {
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002715 rc = bnx2x_emac_program(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002716
Yaniv Rosner0c786f02009-11-05 19:18:32 +02002717 bnx2x_emac_enable(params, vars, 0);
2718
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002719 /* AN complete? */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002720 if ((vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE)
2721 && (!(vars->phy_flags & PHY_SGMII_FLAG)) &&
2722 SINGLE_MEDIA_DIRECT(params))
2723 bnx2x_set_gmii_tx_driver(params);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002724 }
2725
2726 /* PBF - link up */
2727 rc |= bnx2x_pbf_update(params, vars->flow_ctrl,
2728 vars->line_speed);
2729
2730 /* disable drain */
2731 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 0);
2732
2733 /* update shared memory */
2734 bnx2x_update_mng(params, vars->link_status);
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002735 msleep(20);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002736 return rc;
2737}
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002738/**
2739 * The bnx2x_link_update function should be called upon link
2740 * interrupt.
2741 * Link is considered up as follows:
2742 * - DIRECT_SINGLE_MEDIA - Only XGXS link (internal link) needs
2743 * to be up
2744 * - SINGLE_MEDIA - The link between the 577xx and the external
2745 * phy (XGXS) need to up as well as the external link of the
2746 * phy (PHY_EXT1)
2747 * - DUAL_MEDIA - The link between the 577xx and the first
2748 * external phy needs to be up, and at least one of the 2
2749 * external phy link must be up.
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002750 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002751u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars)
2752{
2753 struct bnx2x *bp = params->bp;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002754 struct link_vars phy_vars[MAX_PHYS];
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002755 u8 port = params->port;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002756 u8 link_10g, phy_index;
2757 u8 ext_phy_link_up = 0, cur_link_up, rc = 0;
Eilon Greenstein2f904462009-08-12 08:22:16 +00002758 u8 is_mi_int = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002759 u16 ext_phy_line_speed = 0, prev_line_speed = vars->line_speed;
2760 u8 active_external_phy = INT_PHY;
2761 vars->link_status = 0;
2762 for (phy_index = INT_PHY; phy_index < params->num_phys;
2763 phy_index++) {
2764 phy_vars[phy_index].flow_ctrl = 0;
2765 phy_vars[phy_index].link_status = 0;
2766 phy_vars[phy_index].line_speed = 0;
2767 phy_vars[phy_index].duplex = DUPLEX_FULL;
2768 phy_vars[phy_index].phy_link_up = 0;
2769 phy_vars[phy_index].link_up = 0;
2770 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002771
2772 DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n",
Eilon Greenstein2f904462009-08-12 08:22:16 +00002773 port, (vars->phy_flags & PHY_XGXS_FLAG),
2774 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002775
Eilon Greenstein2f904462009-08-12 08:22:16 +00002776 is_mi_int = (u8)(REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT +
2777 port*0x18) > 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002778 DP(NETIF_MSG_LINK, "int_mask 0x%x MI_INT %x, SERDES_LINK %x\n",
Eilon Greenstein2f904462009-08-12 08:22:16 +00002779 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
2780 is_mi_int,
2781 REG_RD(bp,
2782 NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002783
2784 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
2785 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
2786 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
2787
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002788 /* disable emac */
2789 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
2790
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002791 /**
2792 * Step 1:
2793 * Check external link change only for external phys, and apply
2794 * priority selection between them in case the link on both phys
2795 * is up. Note that the instead of the common vars, a temporary
2796 * vars argument is used since each phy may have different link/
2797 * speed/duplex result
2798 */
2799 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
2800 phy_index++) {
2801 struct bnx2x_phy *phy = &params->phy[phy_index];
2802 if (!phy->read_status)
2803 continue;
2804 /* Read link status and params of this ext phy */
2805 cur_link_up = phy->read_status(phy, params,
2806 &phy_vars[phy_index]);
2807 if (cur_link_up) {
2808 DP(NETIF_MSG_LINK, "phy in index %d link is up\n",
2809 phy_index);
2810 } else {
2811 DP(NETIF_MSG_LINK, "phy in index %d link is down\n",
2812 phy_index);
2813 continue;
2814 }
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002815
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002816 if (!ext_phy_link_up) {
2817 ext_phy_link_up = 1;
2818 active_external_phy = phy_index;
2819 }
2820 }
2821 prev_line_speed = vars->line_speed;
2822 /**
2823 * Step 2:
2824 * Read the status of the internal phy. In case of
2825 * DIRECT_SINGLE_MEDIA board, this link is the external link,
2826 * otherwise this is the link between the 577xx and the first
2827 * external phy
2828 */
2829 if (params->phy[INT_PHY].read_status)
2830 params->phy[INT_PHY].read_status(
2831 &params->phy[INT_PHY],
2832 params, vars);
2833 /**
2834 * The INT_PHY flow control reside in the vars. This include the
2835 * case where the speed or flow control are not set to AUTO.
2836 * Otherwise, the active external phy flow control result is set
2837 * to the vars. The ext_phy_line_speed is needed to check if the
2838 * speed is different between the internal phy and external phy.
2839 * This case may be result of intermediate link speed change.
2840 */
2841 if (active_external_phy > INT_PHY) {
2842 vars->flow_ctrl = phy_vars[active_external_phy].flow_ctrl;
2843 /**
2844 * Link speed is taken from the XGXS. AN and FC result from
2845 * the external phy.
2846 */
2847 vars->link_status |= phy_vars[active_external_phy].link_status;
2848 ext_phy_line_speed = phy_vars[active_external_phy].line_speed;
2849 vars->duplex = phy_vars[active_external_phy].duplex;
2850 if (params->phy[active_external_phy].supported &
2851 SUPPORTED_FIBRE)
2852 vars->link_status |= LINK_STATUS_SERDES_LINK;
2853 DP(NETIF_MSG_LINK, "Active external phy selected: %x\n",
2854 active_external_phy);
2855 }
2856 DP(NETIF_MSG_LINK, "vars->flow_ctrl = 0x%x, vars->link_status = 0x%x,"
2857 " ext_phy_line_speed = %d\n", vars->flow_ctrl,
2858 vars->link_status, ext_phy_line_speed);
2859 /**
2860 * Upon link speed change set the NIG into drain mode. Comes to
2861 * deals with possible FIFO glitch due to clk change when speed
2862 * is decreased without link down indicator
2863 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002864
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002865 if (vars->phy_link_up) {
2866 if (!(SINGLE_MEDIA_DIRECT(params)) && ext_phy_link_up &&
2867 (ext_phy_line_speed != vars->line_speed)) {
2868 DP(NETIF_MSG_LINK, "Internal link speed %d is"
2869 " different than the external"
2870 " link speed %d\n", vars->line_speed,
2871 ext_phy_line_speed);
2872 vars->phy_link_up = 0;
2873 } else if (prev_line_speed != vars->line_speed) {
2874 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
2875 + params->port*4, 0);
2876 msleep(1);
2877 }
2878 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002879
2880 /* anything 10 and over uses the bmac */
2881 link_10g = ((vars->line_speed == SPEED_10000) ||
2882 (vars->line_speed == SPEED_12000) ||
2883 (vars->line_speed == SPEED_12500) ||
2884 (vars->line_speed == SPEED_13000) ||
2885 (vars->line_speed == SPEED_15000) ||
2886 (vars->line_speed == SPEED_16000));
2887
Eilon Greenstein2f904462009-08-12 08:22:16 +00002888 bnx2x_link_int_ack(params, vars, link_10g, is_mi_int);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002889
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002890 /**
2891 * In case external phy link is up, and internal link is down
2892 * (not initialized yet probably after link initialization, it
2893 * needs to be initialized.
2894 * Note that after link down-up as result of cable plug, the xgxs
2895 * link would probably become up again without the need
2896 * initialize it
2897 */
2898 if (!(SINGLE_MEDIA_DIRECT(params))) {
2899 DP(NETIF_MSG_LINK, "ext_phy_link_up = %d, int_link_up = %d,"
2900 " init_preceding = %d\n", ext_phy_link_up,
2901 vars->phy_link_up,
2902 params->phy[EXT_PHY1].flags &
2903 FLAGS_INIT_XGXS_FIRST);
2904 if (!(params->phy[EXT_PHY1].flags &
2905 FLAGS_INIT_XGXS_FIRST)
2906 && ext_phy_link_up && !vars->phy_link_up) {
2907 vars->line_speed = ext_phy_line_speed;
2908 if (vars->line_speed < SPEED_1000)
2909 vars->phy_flags |= PHY_SGMII_FLAG;
2910 else
2911 vars->phy_flags &= ~PHY_SGMII_FLAG;
2912 bnx2x_init_internal_phy(&params->phy[INT_PHY],
2913 params,
2914 vars);
2915 }
2916 }
2917 /**
2918 * Link is up only if both local phy and external phy (in case of
2919 * non-direct board) are up
2920 */
2921 vars->link_up = (vars->phy_link_up &&
2922 (ext_phy_link_up ||
2923 SINGLE_MEDIA_DIRECT(params)));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002924
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002925 if (vars->link_up)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002926 rc = bnx2x_update_link_up(params, vars, link_10g);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002927 else
2928 rc = bnx2x_update_link_down(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002929
2930 return rc;
2931}
2932
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002933
2934/*****************************************************************************/
2935/* External Phy section */
2936/*****************************************************************************/
2937void bnx2x_ext_phy_hw_reset(struct bnx2x *bp, u8 port)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002938{
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002939 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
2940 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
2941 msleep(1);
2942 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
2943 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002944}
2945
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002946static void bnx2x_save_spirom_version(struct bnx2x *bp, u8 port,
2947 u32 spirom_ver, u32 ver_addr)
2948{
2949 DP(NETIF_MSG_LINK, "FW version 0x%x:0x%x for port %d\n",
2950 (u16)(spirom_ver>>16), (u16)spirom_ver, port);
2951
2952 if (ver_addr)
2953 REG_WR(bp, ver_addr, spirom_ver);
2954}
2955
2956static void bnx2x_save_bcm_spirom_ver(struct bnx2x *bp,
2957 struct bnx2x_phy *phy,
2958 u8 port)
2959{
2960 u16 fw_ver1, fw_ver2;
2961
2962 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
2963 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
2964 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
2965 MDIO_PMA_REG_ROM_VER2, &fw_ver2);
2966 bnx2x_save_spirom_version(bp, port, (u32)(fw_ver1<<16 | fw_ver2),
2967 phy->ver_addr);
2968}
2969
2970static void bnx2x_ext_phy_set_pause(struct link_params *params,
2971 struct bnx2x_phy *phy,
2972 struct link_vars *vars)
2973{
2974 u16 val;
2975 struct bnx2x *bp = params->bp;
2976 /* read modify write pause advertizing */
2977 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV_PAUSE, &val);
2978
2979 val &= ~MDIO_AN_REG_ADV_PAUSE_BOTH;
2980
2981 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
2982 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
2983 if ((vars->ieee_fc &
2984 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
2985 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
2986 val |= MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC;
2987 }
2988 if ((vars->ieee_fc &
2989 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
2990 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
2991 val |= MDIO_AN_REG_ADV_PAUSE_PAUSE;
2992 }
2993 DP(NETIF_MSG_LINK, "Ext phy AN advertize 0x%x\n", val);
2994 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV_PAUSE, val);
2995}
2996
2997static u8 bnx2x_ext_phy_resolve_fc(struct bnx2x_phy *phy,
2998 struct link_params *params,
2999 struct link_vars *vars)
3000{
3001 struct bnx2x *bp = params->bp;
3002 u16 ld_pause; /* local */
3003 u16 lp_pause; /* link partner */
3004 u16 pause_result;
3005 u8 ret = 0;
3006 /* read twice */
3007
3008 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
3009
3010 if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO)
3011 vars->flow_ctrl = phy->req_flow_ctrl;
3012 else if (phy->req_line_speed != SPEED_AUTO_NEG)
3013 vars->flow_ctrl = params->req_fc_auto_adv;
3014 else if (vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE) {
3015 ret = 1;
3016 bnx2x_cl45_read(bp, phy,
3017 MDIO_AN_DEVAD,
3018 MDIO_AN_REG_ADV_PAUSE, &ld_pause);
3019 bnx2x_cl45_read(bp, phy,
3020 MDIO_AN_DEVAD,
3021 MDIO_AN_REG_LP_AUTO_NEG, &lp_pause);
3022 pause_result = (ld_pause &
3023 MDIO_AN_REG_ADV_PAUSE_MASK) >> 8;
3024 pause_result |= (lp_pause &
3025 MDIO_AN_REG_ADV_PAUSE_MASK) >> 10;
3026 DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x\n",
3027 pause_result);
3028 bnx2x_pause_resolve(vars, pause_result);
3029 }
3030 return ret;
3031}
3032
3033static void bnx2x_ext_phy_10G_an_resolve(struct bnx2x *bp,
3034 struct bnx2x_phy *phy,
3035 struct link_vars *vars)
3036{
3037 u16 val;
3038 bnx2x_cl45_read(bp, phy,
3039 MDIO_AN_DEVAD,
3040 MDIO_AN_REG_STATUS, &val);
3041 bnx2x_cl45_read(bp, phy,
3042 MDIO_AN_DEVAD,
3043 MDIO_AN_REG_STATUS, &val);
3044 if (val & (1<<5))
3045 vars->link_status |= LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
3046 if ((val & (1<<0)) == 0)
3047 vars->link_status |= LINK_STATUS_PARALLEL_DETECTION_USED;
3048}
3049
3050/******************************************************************/
3051/* common BCM8073/BCM8727 PHY SECTION */
3052/******************************************************************/
3053static void bnx2x_8073_resolve_fc(struct bnx2x_phy *phy,
3054 struct link_params *params,
3055 struct link_vars *vars)
3056{
3057 struct bnx2x *bp = params->bp;
3058 if (phy->req_line_speed == SPEED_10 ||
3059 phy->req_line_speed == SPEED_100) {
3060 vars->flow_ctrl = phy->req_flow_ctrl;
3061 return;
3062 }
3063
3064 if (bnx2x_ext_phy_resolve_fc(phy, params, vars) &&
3065 (vars->flow_ctrl == BNX2X_FLOW_CTRL_NONE)) {
3066 u16 pause_result;
3067 u16 ld_pause; /* local */
3068 u16 lp_pause; /* link partner */
3069 bnx2x_cl45_read(bp, phy,
3070 MDIO_AN_DEVAD,
3071 MDIO_AN_REG_CL37_FC_LD, &ld_pause);
3072
3073 bnx2x_cl45_read(bp, phy,
3074 MDIO_AN_DEVAD,
3075 MDIO_AN_REG_CL37_FC_LP, &lp_pause);
3076 pause_result = (ld_pause &
3077 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 5;
3078 pause_result |= (lp_pause &
3079 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 7;
3080
3081 bnx2x_pause_resolve(vars, pause_result);
3082 DP(NETIF_MSG_LINK, "Ext PHY CL37 pause result 0x%x\n",
3083 pause_result);
3084 }
3085}
3086
3087static void bnx2x_8073_8727_external_rom_boot(struct bnx2x *bp,
3088 struct bnx2x_phy *phy,
3089 u8 port)
3090{
3091 /* Boot port from external ROM */
3092 /* EDC grst */
3093 bnx2x_cl45_write(bp, phy,
3094 MDIO_PMA_DEVAD,
3095 MDIO_PMA_REG_GEN_CTRL,
3096 0x0001);
3097
3098 /* ucode reboot and rst */
3099 bnx2x_cl45_write(bp, phy,
3100 MDIO_PMA_DEVAD,
3101 MDIO_PMA_REG_GEN_CTRL,
3102 0x008c);
3103
3104 bnx2x_cl45_write(bp, phy,
3105 MDIO_PMA_DEVAD,
3106 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
3107
3108 /* Reset internal microprocessor */
3109 bnx2x_cl45_write(bp, phy,
3110 MDIO_PMA_DEVAD,
3111 MDIO_PMA_REG_GEN_CTRL,
3112 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
3113
3114 /* Release srst bit */
3115 bnx2x_cl45_write(bp, phy,
3116 MDIO_PMA_DEVAD,
3117 MDIO_PMA_REG_GEN_CTRL,
3118 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
3119
3120 /* wait for 120ms for code download via SPI port */
3121 msleep(120);
3122
3123 /* Clear ser_boot_ctl bit */
3124 bnx2x_cl45_write(bp, phy,
3125 MDIO_PMA_DEVAD,
3126 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
3127 bnx2x_save_bcm_spirom_ver(bp, phy, port);
3128}
3129
3130static void bnx2x_8073_set_xaui_low_power_mode(struct bnx2x *bp,
3131 struct bnx2x_phy *phy)
3132{
3133 u16 val;
3134 bnx2x_cl45_read(bp, phy,
3135 MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_CHIP_REV, &val);
3136
3137 if (val == 0) {
3138 /* Mustn't set low power mode in 8073 A0 */
3139 return;
3140 }
3141
3142 /* Disable PLL sequencer (use read-modify-write to clear bit 13) */
3143 bnx2x_cl45_read(bp, phy,
3144 MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, &val);
3145 val &= ~(1<<13);
3146 bnx2x_cl45_write(bp, phy,
3147 MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
3148
3149 /* PLL controls */
3150 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805E, 0x1077);
3151 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805D, 0x0000);
3152 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805C, 0x030B);
3153 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805B, 0x1240);
3154 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805A, 0x2490);
3155
3156 /* Tx Controls */
3157 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80A7, 0x0C74);
3158 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80A6, 0x9041);
3159 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80A5, 0x4640);
3160
3161 /* Rx Controls */
3162 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80FE, 0x01C4);
3163 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80FD, 0x9249);
3164 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80FC, 0x2015);
3165
3166 /* Enable PLL sequencer (use read-modify-write to set bit 13) */
3167 bnx2x_cl45_read(bp, phy, MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, &val);
3168 val |= (1<<13);
3169 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
3170}
3171
3172/******************************************************************/
3173/* BCM8073 PHY SECTION */
3174/******************************************************************/
3175static u8 bnx2x_8073_is_snr_needed(struct bnx2x *bp, struct bnx2x_phy *phy)
3176{
3177 /* This is only required for 8073A1, version 102 only */
3178 u16 val;
3179
3180 /* Read 8073 HW revision*/
3181 bnx2x_cl45_read(bp, phy,
3182 MDIO_PMA_DEVAD,
3183 MDIO_PMA_REG_8073_CHIP_REV, &val);
3184
3185 if (val != 1) {
3186 /* No need to workaround in 8073 A1 */
3187 return 0;
3188 }
3189
3190 bnx2x_cl45_read(bp, phy,
3191 MDIO_PMA_DEVAD,
3192 MDIO_PMA_REG_ROM_VER2, &val);
3193
3194 /* SNR should be applied only for version 0x102 */
3195 if (val != 0x102)
3196 return 0;
3197
3198 return 1;
3199}
3200
3201static u8 bnx2x_8073_xaui_wa(struct bnx2x *bp, struct bnx2x_phy *phy)
3202{
3203 u16 val, cnt, cnt1 ;
3204
3205 bnx2x_cl45_read(bp, phy,
3206 MDIO_PMA_DEVAD,
3207 MDIO_PMA_REG_8073_CHIP_REV, &val);
3208
3209 if (val > 0) {
3210 /* No need to workaround in 8073 A1 */
3211 return 0;
3212 }
3213 /* XAUI workaround in 8073 A0: */
3214
3215 /* After loading the boot ROM and restarting Autoneg,
3216 poll Dev1, Reg $C820: */
3217
3218 for (cnt = 0; cnt < 1000; cnt++) {
3219 bnx2x_cl45_read(bp, phy,
3220 MDIO_PMA_DEVAD,
3221 MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
3222 &val);
3223 /* If bit [14] = 0 or bit [13] = 0, continue on with
3224 system initialization (XAUI work-around not required,
3225 as these bits indicate 2.5G or 1G link up). */
3226 if (!(val & (1<<14)) || !(val & (1<<13))) {
3227 DP(NETIF_MSG_LINK, "XAUI work-around not required\n");
3228 return 0;
3229 } else if (!(val & (1<<15))) {
3230 DP(NETIF_MSG_LINK, "clc bit 15 went off\n");
3231 /* If bit 15 is 0, then poll Dev1, Reg $C841 until
3232 it's MSB (bit 15) goes to 1 (indicating that the
3233 XAUI workaround has completed),
3234 then continue on with system initialization.*/
3235 for (cnt1 = 0; cnt1 < 1000; cnt1++) {
3236 bnx2x_cl45_read(bp, phy,
3237 MDIO_PMA_DEVAD,
3238 MDIO_PMA_REG_8073_XAUI_WA, &val);
3239 if (val & (1<<15)) {
3240 DP(NETIF_MSG_LINK,
3241 "XAUI workaround has completed\n");
3242 return 0;
3243 }
3244 msleep(3);
3245 }
3246 break;
3247 }
3248 msleep(3);
3249 }
3250 DP(NETIF_MSG_LINK, "Warning: XAUI work-around timeout !!!\n");
3251 return -EINVAL;
3252}
3253
3254static void bnx2x_807x_force_10G(struct bnx2x *bp, struct bnx2x_phy *phy)
3255{
3256 /* Force KR or KX */
3257 bnx2x_cl45_write(bp, phy,
3258 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x2040);
3259 bnx2x_cl45_write(bp, phy,
3260 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0x000b);
3261 bnx2x_cl45_write(bp, phy,
3262 MDIO_PMA_DEVAD, MDIO_PMA_REG_BCM_CTRL, 0x0000);
3263 bnx2x_cl45_write(bp, phy,
3264 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x0000);
3265}
3266
3267static void bnx2x_8073_set_pause_cl37(struct link_params *params,
3268 struct bnx2x_phy *phy,
3269 struct link_vars *vars)
3270{
3271 u16 cl37_val;
3272 struct bnx2x *bp = params->bp;
3273 bnx2x_cl45_read(bp, phy,
3274 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, &cl37_val);
3275
3276 cl37_val &= ~MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
3277 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
3278 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
3279 if ((vars->ieee_fc &
3280 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) ==
3281 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) {
3282 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC;
3283 }
3284 if ((vars->ieee_fc &
3285 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
3286 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
3287 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
3288 }
3289 if ((vars->ieee_fc &
3290 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
3291 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
3292 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
3293 }
3294 DP(NETIF_MSG_LINK,
3295 "Ext phy AN advertize cl37 0x%x\n", cl37_val);
3296
3297 bnx2x_cl45_write(bp, phy,
3298 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, cl37_val);
3299 msleep(500);
3300}
3301
3302static u8 bnx2x_8073_config_init(struct bnx2x_phy *phy,
3303 struct link_params *params,
3304 struct link_vars *vars)
3305{
3306 struct bnx2x *bp = params->bp;
3307 u16 val = 0, tmp1;
3308 u8 gpio_port;
3309 DP(NETIF_MSG_LINK, "Init 8073\n");
3310
3311 gpio_port = params->port;
3312 /* Restore normal power mode*/
3313 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
3314 MISC_REGISTERS_GPIO_OUTPUT_HIGH, gpio_port);
3315
3316 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
3317 MISC_REGISTERS_GPIO_OUTPUT_HIGH, gpio_port);
3318
3319 /* enable LASI */
3320 bnx2x_cl45_write(bp, phy,
3321 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL, (1<<2));
3322 bnx2x_cl45_write(bp, phy,
3323 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x0004);
3324
3325 bnx2x_8073_set_pause_cl37(params, phy, vars);
3326
3327 bnx2x_8073_set_xaui_low_power_mode(bp, phy);
3328
3329 bnx2x_cl45_read(bp, phy,
3330 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &tmp1);
3331
3332 bnx2x_cl45_read(bp, phy,
3333 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &tmp1);
3334
3335 DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1): 0x%x\n", tmp1);
3336
3337 /* Enable CL37 BAM */
3338 bnx2x_cl45_read(bp, phy,
3339 MDIO_AN_DEVAD,
3340 MDIO_AN_REG_8073_BAM, &val);
3341 bnx2x_cl45_write(bp, phy,
3342 MDIO_AN_DEVAD,
3343 MDIO_AN_REG_8073_BAM, val | 1);
3344
3345 if (params->loopback_mode == LOOPBACK_EXT) {
3346 bnx2x_807x_force_10G(bp, phy);
3347 DP(NETIF_MSG_LINK, "Forced speed 10G on 807X\n");
3348 return 0;
3349 } else {
3350 bnx2x_cl45_write(bp, phy,
3351 MDIO_PMA_DEVAD, MDIO_PMA_REG_BCM_CTRL, 0x0002);
3352 }
3353 if (phy->req_line_speed != SPEED_AUTO_NEG) {
3354 if (phy->req_line_speed == SPEED_10000) {
3355 val = (1<<7);
3356 } else if (phy->req_line_speed == SPEED_2500) {
3357 val = (1<<5);
3358 /* Note that 2.5G works only
3359 when used with 1G advertisment */
3360 } else
3361 val = (1<<5);
3362 } else {
3363 val = 0;
3364 if (phy->speed_cap_mask &
3365 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
3366 val |= (1<<7);
3367
3368 /* Note that 2.5G works only when
3369 used with 1G advertisment */
3370 if (phy->speed_cap_mask &
3371 (PORT_HW_CFG_SPEED_CAPABILITY_D0_1G |
3372 PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G))
3373 val |= (1<<5);
3374 DP(NETIF_MSG_LINK, "807x autoneg val = 0x%x\n", val);
3375 }
3376
3377 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV, val);
3378 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_8073_2_5G, &tmp1);
3379
3380 if (((phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G) &&
3381 (phy->req_line_speed == SPEED_AUTO_NEG)) ||
3382 (phy->req_line_speed == SPEED_2500)) {
3383 u16 phy_ver;
3384 /* Allow 2.5G for A1 and above */
3385 bnx2x_cl45_read(bp, phy,
3386 MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_CHIP_REV,
3387 &phy_ver);
3388 DP(NETIF_MSG_LINK, "Add 2.5G\n");
3389 if (phy_ver > 0)
3390 tmp1 |= 1;
3391 else
3392 tmp1 &= 0xfffe;
3393 } else {
3394 DP(NETIF_MSG_LINK, "Disable 2.5G\n");
3395 tmp1 &= 0xfffe;
3396 }
3397
3398 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_8073_2_5G, tmp1);
3399 /* Add support for CL37 (passive mode) II */
3400
3401 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, &tmp1);
3402 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD,
3403 (tmp1 | ((phy->req_duplex == DUPLEX_FULL) ?
3404 0x20 : 0x40)));
3405
3406 /* Add support for CL37 (passive mode) III */
3407 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
3408
3409 /* The SNR will improve about 2db by changing
3410 BW and FEE main tap. Rest commands are executed
3411 after link is up*/
3412 if (bnx2x_8073_is_snr_needed(bp, phy))
3413 bnx2x_cl45_write(bp, phy,
3414 MDIO_PMA_DEVAD, MDIO_PMA_REG_EDC_FFE_MAIN,
3415 0xFB0C);
3416
3417 /* Enable FEC (Forware Error Correction) Request in the AN */
3418 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV2, &tmp1);
3419 tmp1 |= (1<<15);
3420 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV2, tmp1);
3421
3422 bnx2x_ext_phy_set_pause(params, phy, vars);
3423
3424 /* Restart autoneg */
3425 msleep(500);
3426 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
3427 DP(NETIF_MSG_LINK, "807x Autoneg Restart: Advertise 1G=%x, 10G=%x\n",
3428 ((val & (1<<5)) > 0), ((val & (1<<7)) > 0));
3429 return 0;
3430}
3431
3432static u8 bnx2x_8073_read_status(struct bnx2x_phy *phy,
3433 struct link_params *params,
3434 struct link_vars *vars)
3435{
3436 struct bnx2x *bp = params->bp;
3437 u8 link_up = 0;
3438 u16 val1, val2;
3439 u16 link_status = 0;
3440 u16 an1000_status = 0;
3441
3442 bnx2x_cl45_read(bp, phy,
3443 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
3444
3445 DP(NETIF_MSG_LINK, "8703 LASI status 0x%x\n", val1);
3446
3447 /* clear the interrupt LASI status register */
3448 bnx2x_cl45_read(bp, phy,
3449 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val2);
3450 bnx2x_cl45_read(bp, phy,
3451 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val1);
3452 DP(NETIF_MSG_LINK, "807x PCS status 0x%x->0x%x\n", val2, val1);
3453 /* Clear MSG-OUT */
3454 bnx2x_cl45_read(bp, phy,
3455 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &val1);
3456
3457 /* Check the LASI */
3458 bnx2x_cl45_read(bp, phy,
3459 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &val2);
3460
3461 DP(NETIF_MSG_LINK, "KR 0x9003 0x%x\n", val2);
3462
3463 /* Check the link status */
3464 bnx2x_cl45_read(bp, phy,
3465 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val2);
3466 DP(NETIF_MSG_LINK, "KR PCS status 0x%x\n", val2);
3467
3468 bnx2x_cl45_read(bp, phy,
3469 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
3470 bnx2x_cl45_read(bp, phy,
3471 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
3472 link_up = ((val1 & 4) == 4);
3473 DP(NETIF_MSG_LINK, "PMA_REG_STATUS=0x%x\n", val1);
3474
3475 if (link_up &&
3476 ((phy->req_line_speed != SPEED_10000))) {
3477 if (bnx2x_8073_xaui_wa(bp, phy) != 0)
3478 return 0;
3479 }
3480 bnx2x_cl45_read(bp, phy,
3481 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &an1000_status);
3482 bnx2x_cl45_read(bp, phy,
3483 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &an1000_status);
3484
3485 /* Check the link status on 1.1.2 */
3486 bnx2x_cl45_read(bp, phy,
3487 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
3488 bnx2x_cl45_read(bp, phy,
3489 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
3490 DP(NETIF_MSG_LINK, "KR PMA status 0x%x->0x%x,"
3491 "an_link_status=0x%x\n", val2, val1, an1000_status);
3492
3493 link_up = (((val1 & 4) == 4) || (an1000_status & (1<<1)));
3494 if (link_up && bnx2x_8073_is_snr_needed(bp, phy)) {
3495 /* The SNR will improve about 2dbby
3496 changing the BW and FEE main tap.*/
3497 /* The 1st write to change FFE main
3498 tap is set before restart AN */
3499 /* Change PLL Bandwidth in EDC
3500 register */
3501 bnx2x_cl45_write(bp, phy,
3502 MDIO_PMA_DEVAD, MDIO_PMA_REG_PLL_BANDWIDTH,
3503 0x26BC);
3504
3505 /* Change CDR Bandwidth in EDC register */
3506 bnx2x_cl45_write(bp, phy,
3507 MDIO_PMA_DEVAD, MDIO_PMA_REG_CDR_BANDWIDTH,
3508 0x0333);
3509 }
3510 bnx2x_cl45_read(bp, phy,
3511 MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
3512 &link_status);
3513
3514 /* Bits 0..2 --> speed detected, bits 13..15--> link is down */
3515 if ((link_status & (1<<2)) && (!(link_status & (1<<15)))) {
3516 link_up = 1;
3517 vars->line_speed = SPEED_10000;
3518 DP(NETIF_MSG_LINK, "port %x: External link up in 10G\n",
3519 params->port);
3520 } else if ((link_status & (1<<1)) && (!(link_status & (1<<14)))) {
3521 link_up = 1;
3522 vars->line_speed = SPEED_2500;
3523 DP(NETIF_MSG_LINK, "port %x: External link up in 2.5G\n",
3524 params->port);
3525 } else if ((link_status & (1<<0)) && (!(link_status & (1<<13)))) {
3526 link_up = 1;
3527 vars->line_speed = SPEED_1000;
3528 DP(NETIF_MSG_LINK, "port %x: External link up in 1G\n",
3529 params->port);
3530 } else {
3531 link_up = 0;
3532 DP(NETIF_MSG_LINK, "port %x: External link is down\n",
3533 params->port);
3534 }
3535
3536 if (link_up) {
3537 bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
3538 bnx2x_8073_resolve_fc(phy, params, vars);
3539 }
3540 return link_up;
3541}
3542
3543static void bnx2x_8073_link_reset(struct bnx2x_phy *phy,
3544 struct link_params *params)
3545{
3546 struct bnx2x *bp = params->bp;
3547 u8 gpio_port;
3548 gpio_port = params->port;
3549 DP(NETIF_MSG_LINK, "Setting 8073 port %d into low power mode\n",
3550 gpio_port);
3551 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
3552 MISC_REGISTERS_GPIO_OUTPUT_LOW,
3553 gpio_port);
3554}
3555
3556/******************************************************************/
3557/* BCM8705 PHY SECTION */
3558/******************************************************************/
3559static u8 bnx2x_8705_config_init(struct bnx2x_phy *phy,
3560 struct link_params *params,
3561 struct link_vars *vars)
3562{
3563 struct bnx2x *bp = params->bp;
3564 DP(NETIF_MSG_LINK, "init 8705\n");
3565 /* Restore normal power mode*/
3566 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
3567 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
3568 /* HW reset */
3569 bnx2x_ext_phy_hw_reset(bp, params->port);
3570 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0xa040);
3571 bnx2x_wait_reset_complete(bp, phy);
3572
3573 bnx2x_cl45_write(bp, phy,
3574 MDIO_PMA_DEVAD, MDIO_PMA_REG_MISC_CTRL, 0x8288);
3575 bnx2x_cl45_write(bp, phy,
3576 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, 0x7fbf);
3577 bnx2x_cl45_write(bp, phy,
3578 MDIO_PMA_DEVAD, MDIO_PMA_REG_CMU_PLL_BYPASS, 0x0100);
3579 bnx2x_cl45_write(bp, phy,
3580 MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_CNTL, 0x1);
3581 /* BCM8705 doesn't have microcode, hence the 0 */
3582 bnx2x_save_spirom_version(bp, params->port, params->shmem_base, 0);
3583 return 0;
3584}
3585
3586static u8 bnx2x_8705_read_status(struct bnx2x_phy *phy,
3587 struct link_params *params,
3588 struct link_vars *vars)
3589{
3590 u8 link_up = 0;
3591 u16 val1, rx_sd;
3592 struct bnx2x *bp = params->bp;
3593 DP(NETIF_MSG_LINK, "read status 8705\n");
3594 bnx2x_cl45_read(bp, phy,
3595 MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_STATUS, &val1);
3596 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
3597
3598 bnx2x_cl45_read(bp, phy,
3599 MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_STATUS, &val1);
3600 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
3601
3602 bnx2x_cl45_read(bp, phy,
3603 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD, &rx_sd);
3604
3605 bnx2x_cl45_read(bp, phy,
3606 MDIO_PMA_DEVAD, 0xc809, &val1);
3607 bnx2x_cl45_read(bp, phy,
3608 MDIO_PMA_DEVAD, 0xc809, &val1);
3609
3610 DP(NETIF_MSG_LINK, "8705 1.c809 val=0x%x\n", val1);
3611 link_up = ((rx_sd & 0x1) && (val1 & (1<<9)) && ((val1 & (1<<8)) == 0));
3612 if (link_up) {
3613 vars->line_speed = SPEED_10000;
3614 bnx2x_ext_phy_resolve_fc(phy, params, vars);
3615 }
3616 return link_up;
3617}
3618
3619/******************************************************************/
3620/* SFP+ module Section */
3621/******************************************************************/
3622static void bnx2x_sfp_set_transmitter(struct bnx2x *bp,
3623 struct bnx2x_phy *phy,
3624 u8 port,
3625 u8 tx_en)
3626{
3627 u16 val;
3628
3629 DP(NETIF_MSG_LINK, "Setting transmitter tx_en=%x for port %x\n",
3630 tx_en, port);
3631 /* Disable/Enable transmitter ( TX laser of the SFP+ module.)*/
3632 bnx2x_cl45_read(bp, phy,
3633 MDIO_PMA_DEVAD,
3634 MDIO_PMA_REG_PHY_IDENTIFIER,
3635 &val);
3636
3637 if (tx_en)
3638 val &= ~(1<<15);
3639 else
3640 val |= (1<<15);
3641
3642 bnx2x_cl45_write(bp, phy,
3643 MDIO_PMA_DEVAD,
3644 MDIO_PMA_REG_PHY_IDENTIFIER,
3645 val);
3646}
3647
3648static u8 bnx2x_8726_read_sfp_module_eeprom(struct bnx2x_phy *phy,
3649 struct link_params *params,
3650 u16 addr, u8 byte_cnt, u8 *o_buf)
3651{
3652 struct bnx2x *bp = params->bp;
3653 u16 val = 0;
3654 u16 i;
3655 if (byte_cnt > 16) {
3656 DP(NETIF_MSG_LINK, "Reading from eeprom is"
3657 " is limited to 0xf\n");
3658 return -EINVAL;
3659 }
3660 /* Set the read command byte count */
3661 bnx2x_cl45_write(bp, phy,
3662 MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
3663 (byte_cnt | 0xa000));
3664
3665 /* Set the read command address */
3666 bnx2x_cl45_write(bp, phy,
3667 MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
3668 addr);
3669
3670 /* Activate read command */
3671 bnx2x_cl45_write(bp, phy,
3672 MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
3673 0x2c0f);
3674
3675 /* Wait up to 500us for command complete status */
3676 for (i = 0; i < 100; i++) {
3677 bnx2x_cl45_read(bp, phy,
3678 MDIO_PMA_DEVAD,
3679 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
3680 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
3681 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
3682 break;
3683 udelay(5);
3684 }
3685
3686 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
3687 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
3688 DP(NETIF_MSG_LINK,
3689 "Got bad status 0x%x when reading from SFP+ EEPROM\n",
3690 (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
3691 return -EINVAL;
3692 }
3693
3694 /* Read the buffer */
3695 for (i = 0; i < byte_cnt; i++) {
3696 bnx2x_cl45_read(bp, phy,
3697 MDIO_PMA_DEVAD,
3698 MDIO_PMA_REG_8726_TWO_WIRE_DATA_BUF + i, &val);
3699 o_buf[i] = (u8)(val & MDIO_PMA_REG_8726_TWO_WIRE_DATA_MASK);
3700 }
3701
3702 for (i = 0; i < 100; i++) {
3703 bnx2x_cl45_read(bp, phy,
3704 MDIO_PMA_DEVAD,
3705 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
3706 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
3707 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
3708 return 0;;
3709 msleep(1);
3710 }
3711 return -EINVAL;
3712}
3713
3714static u8 bnx2x_8727_read_sfp_module_eeprom(struct bnx2x_phy *phy,
3715 struct link_params *params,
3716 u16 addr, u8 byte_cnt, u8 *o_buf)
3717{
3718 struct bnx2x *bp = params->bp;
3719 u16 val, i;
3720
3721 if (byte_cnt > 16) {
3722 DP(NETIF_MSG_LINK, "Reading from eeprom is"
3723 " is limited to 0xf\n");
3724 return -EINVAL;
3725 }
3726
3727 /* Need to read from 1.8000 to clear it */
3728 bnx2x_cl45_read(bp, phy,
3729 MDIO_PMA_DEVAD,
3730 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
3731 &val);
3732
3733 /* Set the read command byte count */
3734 bnx2x_cl45_write(bp, phy,
3735 MDIO_PMA_DEVAD,
3736 MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
3737 ((byte_cnt < 2) ? 2 : byte_cnt));
3738
3739 /* Set the read command address */
3740 bnx2x_cl45_write(bp, phy,
3741 MDIO_PMA_DEVAD,
3742 MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
3743 addr);
3744 /* Set the destination address */
3745 bnx2x_cl45_write(bp, phy,
3746 MDIO_PMA_DEVAD,
3747 0x8004,
3748 MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF);
3749
3750 /* Activate read command */
3751 bnx2x_cl45_write(bp, phy,
3752 MDIO_PMA_DEVAD,
3753 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
3754 0x8002);
3755 /* Wait appropriate time for two-wire command to finish before
3756 polling the status register */
3757 msleep(1);
3758
3759 /* Wait up to 500us for command complete status */
3760 for (i = 0; i < 100; i++) {
3761 bnx2x_cl45_read(bp, phy,
3762 MDIO_PMA_DEVAD,
3763 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
3764 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
3765 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
3766 break;
3767 udelay(5);
3768 }
3769
3770 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
3771 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
3772 DP(NETIF_MSG_LINK,
3773 "Got bad status 0x%x when reading from SFP+ EEPROM\n",
3774 (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
3775 return -EINVAL;
3776 }
3777
3778 /* Read the buffer */
3779 for (i = 0; i < byte_cnt; i++) {
3780 bnx2x_cl45_read(bp, phy,
3781 MDIO_PMA_DEVAD,
3782 MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF + i, &val);
3783 o_buf[i] = (u8)(val & MDIO_PMA_REG_8727_TWO_WIRE_DATA_MASK);
3784 }
3785
3786 for (i = 0; i < 100; i++) {
3787 bnx2x_cl45_read(bp, phy,
3788 MDIO_PMA_DEVAD,
3789 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
3790 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
3791 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
3792 return 0;;
3793 msleep(1);
3794 }
3795
3796 return -EINVAL;
3797}
3798
3799u8 bnx2x_read_sfp_module_eeprom(struct bnx2x_phy *phy,
3800 struct link_params *params, u16 addr,
3801 u8 byte_cnt, u8 *o_buf)
3802{
3803 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
3804 return bnx2x_8726_read_sfp_module_eeprom(phy, params, addr,
3805 byte_cnt, o_buf);
3806 else if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
3807 return bnx2x_8727_read_sfp_module_eeprom(phy, params, addr,
3808 byte_cnt, o_buf);
3809 return -EINVAL;
3810}
3811
3812static u8 bnx2x_get_edc_mode(struct bnx2x_phy *phy,
3813 struct link_params *params,
3814 u16 *edc_mode)
3815{
3816 struct bnx2x *bp = params->bp;
3817 u8 val, check_limiting_mode = 0;
3818 *edc_mode = EDC_MODE_LIMITING;
3819
3820 /* First check for copper cable */
3821 if (bnx2x_read_sfp_module_eeprom(phy,
3822 params,
3823 SFP_EEPROM_CON_TYPE_ADDR,
3824 1,
3825 &val) != 0) {
3826 DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM\n");
3827 return -EINVAL;
3828 }
3829
3830 switch (val) {
3831 case SFP_EEPROM_CON_TYPE_VAL_COPPER:
3832 {
3833 u8 copper_module_type;
3834
3835 /* Check if its active cable( includes SFP+ module)
3836 of passive cable*/
3837 if (bnx2x_read_sfp_module_eeprom(phy,
3838 params,
3839 SFP_EEPROM_FC_TX_TECH_ADDR,
3840 1,
3841 &copper_module_type) !=
3842 0) {
3843 DP(NETIF_MSG_LINK,
3844 "Failed to read copper-cable-type"
3845 " from SFP+ EEPROM\n");
3846 return -EINVAL;
3847 }
3848
3849 if (copper_module_type &
3850 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE) {
3851 DP(NETIF_MSG_LINK, "Active Copper cable detected\n");
3852 check_limiting_mode = 1;
3853 } else if (copper_module_type &
3854 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE) {
3855 DP(NETIF_MSG_LINK, "Passive Copper"
3856 " cable detected\n");
3857 *edc_mode =
3858 EDC_MODE_PASSIVE_DAC;
3859 } else {
3860 DP(NETIF_MSG_LINK, "Unknown copper-cable-"
3861 "type 0x%x !!!\n", copper_module_type);
3862 return -EINVAL;
3863 }
3864 break;
3865 }
3866 case SFP_EEPROM_CON_TYPE_VAL_LC:
3867 DP(NETIF_MSG_LINK, "Optic module detected\n");
3868 check_limiting_mode = 1;
3869 break;
3870 default:
3871 DP(NETIF_MSG_LINK, "Unable to determine module type 0x%x !!!\n",
3872 val);
3873 return -EINVAL;
3874 }
3875
3876 if (check_limiting_mode) {
3877 u8 options[SFP_EEPROM_OPTIONS_SIZE];
3878 if (bnx2x_read_sfp_module_eeprom(phy,
3879 params,
3880 SFP_EEPROM_OPTIONS_ADDR,
3881 SFP_EEPROM_OPTIONS_SIZE,
3882 options) != 0) {
3883 DP(NETIF_MSG_LINK, "Failed to read Option"
3884 " field from module EEPROM\n");
3885 return -EINVAL;
3886 }
3887 if ((options[0] & SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK))
3888 *edc_mode = EDC_MODE_LINEAR;
3889 else
3890 *edc_mode = EDC_MODE_LIMITING;
3891 }
3892 DP(NETIF_MSG_LINK, "EDC mode is set to 0x%x\n", *edc_mode);
3893 return 0;
3894}
3895/* This function read the relevant field from the module ( SFP+ ),
3896 and verify it is compliant with this board */
3897static u8 bnx2x_verify_sfp_module(struct bnx2x_phy *phy,
3898 struct link_params *params)
3899{
3900 struct bnx2x *bp = params->bp;
3901 u32 val;
3902 u32 fw_resp;
3903 char vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE+1];
3904 char vendor_pn[SFP_EEPROM_PART_NO_SIZE+1];
3905
3906 val = REG_RD(bp, params->shmem_base +
3907 offsetof(struct shmem_region, dev_info.
3908 port_feature_config[params->port].config));
3909 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
3910 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_NO_ENFORCEMENT) {
3911 DP(NETIF_MSG_LINK, "NOT enforcing module verification\n");
3912 return 0;
3913 }
3914
3915 /* Ask the FW to validate the module */
3916 if (!(params->feature_config_flags &
3917 FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY)) {
3918 DP(NETIF_MSG_LINK, "FW does not support OPT MDL "
3919 "verification\n");
3920 return -EINVAL;
3921 }
3922
3923 fw_resp = bnx2x_fw_command(bp, DRV_MSG_CODE_VRFY_OPT_MDL);
3924 if (fw_resp == FW_MSG_CODE_VRFY_OPT_MDL_SUCCESS) {
3925 DP(NETIF_MSG_LINK, "Approved module\n");
3926 return 0;
3927 }
3928
3929 /* format the warning message */
3930 if (bnx2x_read_sfp_module_eeprom(phy,
3931 params,
3932 SFP_EEPROM_VENDOR_NAME_ADDR,
3933 SFP_EEPROM_VENDOR_NAME_SIZE,
3934 (u8 *)vendor_name))
3935 vendor_name[0] = '\0';
3936 else
3937 vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE] = '\0';
3938 if (bnx2x_read_sfp_module_eeprom(phy,
3939 params,
3940 SFP_EEPROM_PART_NO_ADDR,
3941 SFP_EEPROM_PART_NO_SIZE,
3942 (u8 *)vendor_pn))
3943 vendor_pn[0] = '\0';
3944 else
3945 vendor_pn[SFP_EEPROM_PART_NO_SIZE] = '\0';
3946
3947 netdev_info(bp->dev, "Warning: Unqualified SFP+ module detected,"
3948 " Port %d from %s part number %s\n",
3949 params->port, vendor_name, vendor_pn);
3950 return -EINVAL;
3951}
3952
3953static u8 bnx2x_wait_for_sfp_module_initialized(struct bnx2x_phy *phy,
3954 struct link_params *params)
3955
3956{
3957 u8 val;
3958 struct bnx2x *bp = params->bp;
3959 u16 timeout;
3960 /* Initialization time after hot-plug may take up to 300ms for some
3961 phys type ( e.g. JDSU ) */
3962 for (timeout = 0; timeout < 60; timeout++) {
3963 if (bnx2x_read_sfp_module_eeprom(phy, params, 1, 1, &val)
3964 == 0) {
3965 DP(NETIF_MSG_LINK, "SFP+ module initialization "
3966 "took %d ms\n", timeout * 5);
3967 return 0;
3968 }
3969 msleep(5);
3970 }
3971 return -EINVAL;
3972}
3973
3974static void bnx2x_8727_power_module(struct bnx2x *bp,
3975 struct bnx2x_phy *phy,
3976 u8 is_power_up) {
3977 /* Make sure GPIOs are not using for LED mode */
3978 u16 val;
3979 /*
3980 * In the GPIO register, bit 4 is use to detemine if the GPIOs are
3981 * operating as INPUT or as OUTPUT. Bit 1 is for input, and 0 for
3982 * output
3983 * Bits 0-1 determine the gpios value for OUTPUT in case bit 4 val is 0
3984 * Bits 8-9 determine the gpios value for INPUT in case bit 4 val is 1
3985 * where the 1st bit is the over-current(only input), and 2nd bit is
3986 * for power( only output )
3987 */
3988
3989 /*
3990 * In case of NOC feature is disabled and power is up, set GPIO control
3991 * as input to enable listening of over-current indication
3992 */
3993 if (phy->flags & FLAGS_NOC)
3994 return;
3995 if (!(phy->flags &
3996 FLAGS_NOC) && is_power_up)
3997 val = (1<<4);
3998 else
3999 /*
4000 * Set GPIO control to OUTPUT, and set the power bit
4001 * to according to the is_power_up
4002 */
4003 val = ((!(is_power_up)) << 1);
4004
4005 bnx2x_cl45_write(bp, phy,
4006 MDIO_PMA_DEVAD,
4007 MDIO_PMA_REG_8727_GPIO_CTRL,
4008 val);
4009}
4010
4011static u8 bnx2x_8726_set_limiting_mode(struct bnx2x *bp,
4012 struct bnx2x_phy *phy,
4013 u16 edc_mode)
4014{
4015 u16 cur_limiting_mode;
4016
4017 bnx2x_cl45_read(bp, phy,
4018 MDIO_PMA_DEVAD,
4019 MDIO_PMA_REG_ROM_VER2,
4020 &cur_limiting_mode);
4021 DP(NETIF_MSG_LINK, "Current Limiting mode is 0x%x\n",
4022 cur_limiting_mode);
4023
4024 if (edc_mode == EDC_MODE_LIMITING) {
4025 DP(NETIF_MSG_LINK,
4026 "Setting LIMITING MODE\n");
4027 bnx2x_cl45_write(bp, phy,
4028 MDIO_PMA_DEVAD,
4029 MDIO_PMA_REG_ROM_VER2,
4030 EDC_MODE_LIMITING);
4031 } else { /* LRM mode ( default )*/
4032
4033 DP(NETIF_MSG_LINK, "Setting LRM MODE\n");
4034
4035 /* Changing to LRM mode takes quite few seconds.
4036 So do it only if current mode is limiting
4037 ( default is LRM )*/
4038 if (cur_limiting_mode != EDC_MODE_LIMITING)
4039 return 0;
4040
4041 bnx2x_cl45_write(bp, phy,
4042 MDIO_PMA_DEVAD,
4043 MDIO_PMA_REG_LRM_MODE,
4044 0);
4045 bnx2x_cl45_write(bp, phy,
4046 MDIO_PMA_DEVAD,
4047 MDIO_PMA_REG_ROM_VER2,
4048 0x128);
4049 bnx2x_cl45_write(bp, phy,
4050 MDIO_PMA_DEVAD,
4051 MDIO_PMA_REG_MISC_CTRL0,
4052 0x4008);
4053 bnx2x_cl45_write(bp, phy,
4054 MDIO_PMA_DEVAD,
4055 MDIO_PMA_REG_LRM_MODE,
4056 0xaaaa);
4057 }
4058 return 0;
4059}
4060
4061static u8 bnx2x_8727_set_limiting_mode(struct bnx2x *bp,
4062 struct bnx2x_phy *phy,
4063 u16 edc_mode)
4064{
4065 u16 phy_identifier;
4066 u16 rom_ver2_val;
4067 bnx2x_cl45_read(bp, phy,
4068 MDIO_PMA_DEVAD,
4069 MDIO_PMA_REG_PHY_IDENTIFIER,
4070 &phy_identifier);
4071
4072 bnx2x_cl45_write(bp, phy,
4073 MDIO_PMA_DEVAD,
4074 MDIO_PMA_REG_PHY_IDENTIFIER,
4075 (phy_identifier & ~(1<<9)));
4076
4077 bnx2x_cl45_read(bp, phy,
4078 MDIO_PMA_DEVAD,
4079 MDIO_PMA_REG_ROM_VER2,
4080 &rom_ver2_val);
4081 /* Keep the MSB 8-bits, and set the LSB 8-bits with the edc_mode */
4082 bnx2x_cl45_write(bp, phy,
4083 MDIO_PMA_DEVAD,
4084 MDIO_PMA_REG_ROM_VER2,
4085 (rom_ver2_val & 0xff00) | (edc_mode & 0x00ff));
4086
4087 bnx2x_cl45_write(bp, phy,
4088 MDIO_PMA_DEVAD,
4089 MDIO_PMA_REG_PHY_IDENTIFIER,
4090 (phy_identifier | (1<<9)));
4091
4092 return 0;
4093}
4094
4095static u8 bnx2x_sfp_module_detection(struct bnx2x_phy *phy,
4096 struct link_params *params)
4097{
4098 struct bnx2x *bp = params->bp;
4099 u16 edc_mode;
4100 u8 rc = 0;
4101
4102 u32 val = REG_RD(bp, params->shmem_base +
4103 offsetof(struct shmem_region, dev_info.
4104 port_feature_config[params->port].config));
4105
4106 DP(NETIF_MSG_LINK, "SFP+ module plugged in/out detected on port %d\n",
4107 params->port);
4108
4109 if (bnx2x_get_edc_mode(phy, params, &edc_mode) != 0) {
4110 DP(NETIF_MSG_LINK, "Failed to get valid module type\n");
4111 return -EINVAL;
4112 } else if (bnx2x_verify_sfp_module(phy, params) !=
4113 0) {
4114 /* check SFP+ module compatibility */
4115 DP(NETIF_MSG_LINK, "Module verification failed!!\n");
4116 rc = -EINVAL;
4117 /* Turn on fault module-detected led */
4118 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
4119 MISC_REGISTERS_GPIO_HIGH,
4120 params->port);
4121 if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) &&
4122 ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
4123 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_POWER_DOWN)) {
4124 /* Shutdown SFP+ module */
4125 DP(NETIF_MSG_LINK, "Shutdown SFP+ module!!\n");
4126 bnx2x_8727_power_module(bp, phy, 0);
4127 return rc;
4128 }
4129 } else {
4130 /* Turn off fault module-detected led */
4131 DP(NETIF_MSG_LINK, "Turn off fault module-detected led\n");
4132 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
4133 MISC_REGISTERS_GPIO_LOW,
4134 params->port);
4135 }
4136
4137 /* power up the SFP module */
4138 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
4139 bnx2x_8727_power_module(bp, phy, 1);
4140
4141 /* Check and set limiting mode / LRM mode on 8726.
4142 On 8727 it is done automatically */
4143 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
4144 bnx2x_8726_set_limiting_mode(bp, phy, edc_mode);
4145 else
4146 bnx2x_8727_set_limiting_mode(bp, phy, edc_mode);
4147 /*
4148 * Enable transmit for this module if the module is approved, or
4149 * if unapproved modules should also enable the Tx laser
4150 */
4151 if (rc == 0 ||
4152 (val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) !=
4153 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
4154 bnx2x_sfp_set_transmitter(bp, phy, params->port, 1);
4155 else
4156 bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
4157
4158 return rc;
4159}
4160
4161void bnx2x_handle_module_detect_int(struct link_params *params)
4162{
4163 struct bnx2x *bp = params->bp;
4164 struct bnx2x_phy *phy = &params->phy[EXT_PHY1];
4165 u32 gpio_val;
4166 u8 port = params->port;
4167
4168 /* Set valid module led off */
4169 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
4170 MISC_REGISTERS_GPIO_HIGH,
4171 params->port);
4172
4173 /* Get current gpio val refelecting module plugged in / out*/
4174 gpio_val = bnx2x_get_gpio(bp, MISC_REGISTERS_GPIO_3, port);
4175
4176 /* Call the handling function in case module is detected */
4177 if (gpio_val == 0) {
4178
4179 bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
4180 MISC_REGISTERS_GPIO_INT_OUTPUT_CLR,
4181 port);
4182
4183 if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0)
4184 bnx2x_sfp_module_detection(phy, params);
4185 else
4186 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
4187 } else {
4188 u32 val = REG_RD(bp, params->shmem_base +
4189 offsetof(struct shmem_region, dev_info.
4190 port_feature_config[params->port].
4191 config));
4192
4193 bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
4194 MISC_REGISTERS_GPIO_INT_OUTPUT_SET,
4195 port);
4196 /* Module was plugged out. */
4197 /* Disable transmit for this module */
4198 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
4199 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
4200 bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
4201 }
4202}
4203
4204/******************************************************************/
4205/* common BCM8706/BCM8726 PHY SECTION */
4206/******************************************************************/
4207static u8 bnx2x_8706_8726_read_status(struct bnx2x_phy *phy,
4208 struct link_params *params,
4209 struct link_vars *vars)
4210{
4211 u8 link_up = 0;
4212 u16 val1, val2, rx_sd, pcs_status;
4213 struct bnx2x *bp = params->bp;
4214 DP(NETIF_MSG_LINK, "XGXS 8706/8726\n");
4215 /* Clear RX Alarm*/
4216 bnx2x_cl45_read(bp, phy,
4217 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &val2);
4218 /* clear LASI indication*/
4219 bnx2x_cl45_read(bp, phy,
4220 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
4221 bnx2x_cl45_read(bp, phy,
4222 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val2);
4223 DP(NETIF_MSG_LINK, "8706/8726 LASI status 0x%x--> 0x%x\n", val1, val2);
4224
4225 bnx2x_cl45_read(bp, phy,
4226 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD, &rx_sd);
4227 bnx2x_cl45_read(bp, phy,
4228 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &pcs_status);
4229 bnx2x_cl45_read(bp, phy,
4230 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &val2);
4231 bnx2x_cl45_read(bp, phy,
4232 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &val2);
4233
4234 DP(NETIF_MSG_LINK, "8706/8726 rx_sd 0x%x pcs_status 0x%x 1Gbps"
4235 " link_status 0x%x\n", rx_sd, pcs_status, val2);
4236 /* link is up if both bit 0 of pmd_rx_sd and
4237 * bit 0 of pcs_status are set, or if the autoneg bit
4238 * 1 is set
4239 */
4240 link_up = ((rx_sd & pcs_status & 0x1) || (val2 & (1<<1)));
4241 if (link_up) {
4242 if (val2 & (1<<1))
4243 vars->line_speed = SPEED_1000;
4244 else
4245 vars->line_speed = SPEED_10000;
4246 bnx2x_ext_phy_resolve_fc(phy, params, vars);
4247 }
4248 return link_up;
4249}
4250
4251/******************************************************************/
4252/* BCM8706 PHY SECTION */
4253/******************************************************************/
4254static u8 bnx2x_8706_config_init(struct bnx2x_phy *phy,
4255 struct link_params *params,
4256 struct link_vars *vars)
4257{
4258 u16 cnt, val;
4259 struct bnx2x *bp = params->bp;
4260 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
4261 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
4262 /* HW reset */
4263 bnx2x_ext_phy_hw_reset(bp, params->port);
4264 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0xa040);
4265 bnx2x_wait_reset_complete(bp, phy);
4266
4267 /* Wait until fw is loaded */
4268 for (cnt = 0; cnt < 100; cnt++) {
4269 bnx2x_cl45_read(bp, phy,
4270 MDIO_PMA_DEVAD, MDIO_PMA_REG_ROM_VER1, &val);
4271 if (val)
4272 break;
4273 msleep(10);
4274 }
4275 DP(NETIF_MSG_LINK, "XGXS 8706 is initialized after %d ms\n", cnt);
4276 if ((params->feature_config_flags &
4277 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
4278 u8 i;
4279 u16 reg;
4280 for (i = 0; i < 4; i++) {
4281 reg = MDIO_XS_8706_REG_BANK_RX0 +
4282 i*(MDIO_XS_8706_REG_BANK_RX1 -
4283 MDIO_XS_8706_REG_BANK_RX0);
4284 bnx2x_cl45_read(bp, phy, MDIO_XS_DEVAD, reg, &val);
4285 /* Clear first 3 bits of the control */
4286 val &= ~0x7;
4287 /* Set control bits according to configuration */
4288 val |= (phy->rx_preemphasis[i] & 0x7);
4289 DP(NETIF_MSG_LINK, "Setting RX Equalizer to BCM8706"
4290 " reg 0x%x <-- val 0x%x\n", reg, val);
4291 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, reg, val);
4292 }
4293 }
4294 /* Force speed */
4295 if (phy->req_line_speed == SPEED_10000) {
4296 DP(NETIF_MSG_LINK, "XGXS 8706 force 10Gbps\n");
4297
4298 bnx2x_cl45_write(bp, phy,
4299 MDIO_PMA_DEVAD,
4300 MDIO_PMA_REG_DIGITAL_CTRL, 0x400);
4301 bnx2x_cl45_write(bp, phy,
4302 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 1);
4303 } else {
4304 /* Force 1Gbps using autoneg with 1G advertisment */
4305
4306 /* Allow CL37 through CL73 */
4307 DP(NETIF_MSG_LINK, "XGXS 8706 AutoNeg\n");
4308 bnx2x_cl45_write(bp, phy,
4309 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_CL73, 0x040c);
4310
4311 /* Enable Full-Duplex advertisment on CL37 */
4312 bnx2x_cl45_write(bp, phy,
4313 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LP, 0x0020);
4314 /* Enable CL37 AN */
4315 bnx2x_cl45_write(bp, phy,
4316 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
4317 /* 1G support */
4318 bnx2x_cl45_write(bp, phy,
4319 MDIO_AN_DEVAD, MDIO_AN_REG_ADV, (1<<5));
4320
4321 /* Enable clause 73 AN */
4322 bnx2x_cl45_write(bp, phy,
4323 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
4324 bnx2x_cl45_write(bp, phy,
4325 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
4326 0x0400);
4327 bnx2x_cl45_write(bp, phy,
4328 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL,
4329 0x0004);
4330 }
4331 bnx2x_save_bcm_spirom_ver(bp, phy, params->port);
4332 return 0;
4333}
4334
4335static u8 bnx2x_8706_read_status(struct bnx2x_phy *phy,
4336 struct link_params *params,
4337 struct link_vars *vars)
4338{
4339 return bnx2x_8706_8726_read_status(phy, params, vars);
4340}
4341
4342/******************************************************************/
4343/* BCM8726 PHY SECTION */
4344/******************************************************************/
4345static void bnx2x_8726_config_loopback(struct bnx2x_phy *phy,
4346 struct link_params *params)
4347{
4348 struct bnx2x *bp = params->bp;
4349 DP(NETIF_MSG_LINK, "PMA/PMD ext_phy_loopback: 8726\n");
4350 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x0001);
4351}
4352
4353static void bnx2x_8726_external_rom_boot(struct bnx2x_phy *phy,
4354 struct link_params *params)
4355{
4356 struct bnx2x *bp = params->bp;
4357 /* Need to wait 100ms after reset */
4358 msleep(100);
4359
4360 /* Micro controller re-boot */
4361 bnx2x_cl45_write(bp, phy,
4362 MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, 0x018B);
4363
4364 /* Set soft reset */
4365 bnx2x_cl45_write(bp, phy,
4366 MDIO_PMA_DEVAD,
4367 MDIO_PMA_REG_GEN_CTRL,
4368 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
4369
4370 bnx2x_cl45_write(bp, phy,
4371 MDIO_PMA_DEVAD,
4372 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
4373
4374 bnx2x_cl45_write(bp, phy,
4375 MDIO_PMA_DEVAD,
4376 MDIO_PMA_REG_GEN_CTRL,
4377 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
4378
4379 /* wait for 150ms for microcode load */
4380 msleep(150);
4381
4382 /* Disable serial boot control, tristates pins SS_N, SCK, MOSI, MISO */
4383 bnx2x_cl45_write(bp, phy,
4384 MDIO_PMA_DEVAD,
4385 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
4386
4387 msleep(200);
4388 bnx2x_save_bcm_spirom_ver(bp, phy, params->port);
4389}
4390
4391static u8 bnx2x_8726_read_status(struct bnx2x_phy *phy,
4392 struct link_params *params,
4393 struct link_vars *vars)
4394{
4395 struct bnx2x *bp = params->bp;
4396 u16 val1;
4397 u8 link_up = bnx2x_8706_8726_read_status(phy, params, vars);
4398 if (link_up) {
4399 bnx2x_cl45_read(bp, phy,
4400 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER,
4401 &val1);
4402 if (val1 & (1<<15)) {
4403 DP(NETIF_MSG_LINK, "Tx is disabled\n");
4404 link_up = 0;
4405 vars->line_speed = 0;
4406 }
4407 }
4408 return link_up;
4409}
4410
4411
4412static u8 bnx2x_8726_config_init(struct bnx2x_phy *phy,
4413 struct link_params *params,
4414 struct link_vars *vars)
4415{
4416 struct bnx2x *bp = params->bp;
4417 u32 val;
4418 u32 swap_val, swap_override, aeu_gpio_mask, offset;
4419 DP(NETIF_MSG_LINK, "Initializing BCM8726\n");
4420 /* Restore normal power mode*/
4421 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
4422 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
4423
4424 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
4425 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
4426
4427 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
4428 bnx2x_wait_reset_complete(bp, phy);
4429
4430 bnx2x_8726_external_rom_boot(phy, params);
4431
4432 /* Need to call module detected on initialization since
4433 the module detection triggered by actual module
4434 insertion might occur before driver is loaded, and when
4435 driver is loaded, it reset all registers, including the
4436 transmitter */
4437 bnx2x_sfp_module_detection(phy, params);
4438
4439 if (phy->req_line_speed == SPEED_1000) {
4440 DP(NETIF_MSG_LINK, "Setting 1G force\n");
4441 bnx2x_cl45_write(bp, phy,
4442 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x40);
4443 bnx2x_cl45_write(bp, phy,
4444 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0xD);
4445 bnx2x_cl45_write(bp, phy,
4446 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x5);
4447 bnx2x_cl45_write(bp, phy,
4448 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
4449 0x400);
4450 } else if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
4451 (phy->speed_cap_mask &
4452 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G) &&
4453 ((phy->speed_cap_mask &
4454 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) !=
4455 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
4456 DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
4457 /* Set Flow control */
4458 bnx2x_ext_phy_set_pause(params, phy, vars);
4459 bnx2x_cl45_write(bp, phy,
4460 MDIO_AN_DEVAD, MDIO_AN_REG_ADV, 0x20);
4461 bnx2x_cl45_write(bp, phy,
4462 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_CL73, 0x040c);
4463 bnx2x_cl45_write(bp, phy,
4464 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, 0x0020);
4465 bnx2x_cl45_write(bp, phy,
4466 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
4467 bnx2x_cl45_write(bp, phy,
4468 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
4469 /* Enable RX-ALARM control to receive
4470 interrupt for 1G speed change */
4471 bnx2x_cl45_write(bp, phy,
4472 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x4);
4473 bnx2x_cl45_write(bp, phy,
4474 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
4475 0x400);
4476
4477 } else { /* Default 10G. Set only LASI control */
4478 bnx2x_cl45_write(bp, phy,
4479 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 1);
4480 }
4481
4482 /* Set TX PreEmphasis if needed */
4483 if ((params->feature_config_flags &
4484 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
4485 DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x,"
4486 "TX_CTRL2 0x%x\n",
4487 phy->tx_preemphasis[0],
4488 phy->tx_preemphasis[1]);
4489 bnx2x_cl45_write(bp, phy,
4490 MDIO_PMA_DEVAD,
4491 MDIO_PMA_REG_8726_TX_CTRL1,
4492 phy->tx_preemphasis[0]);
4493
4494 bnx2x_cl45_write(bp, phy,
4495 MDIO_PMA_DEVAD,
4496 MDIO_PMA_REG_8726_TX_CTRL2,
4497 phy->tx_preemphasis[1]);
4498 }
4499
4500 /* Set GPIO3 to trigger SFP+ module insertion/removal */
4501 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
4502 MISC_REGISTERS_GPIO_INPUT_HI_Z, params->port);
4503
4504 /* The GPIO should be swapped if the swap register is set and active */
4505 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
4506 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
4507
4508 /* Select function upon port-swap configuration */
4509 if (params->port == 0) {
4510 offset = MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0;
4511 aeu_gpio_mask = (swap_val && swap_override) ?
4512 AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_1 :
4513 AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0;
4514 } else {
4515 offset = MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0;
4516 aeu_gpio_mask = (swap_val && swap_override) ?
4517 AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0 :
4518 AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_1;
4519 }
4520 val = REG_RD(bp, offset);
4521 /* add GPIO3 to group */
4522 val |= aeu_gpio_mask;
4523 REG_WR(bp, offset, val);
4524 return 0;
4525
4526}
4527
4528static void bnx2x_8726_link_reset(struct bnx2x_phy *phy,
4529 struct link_params *params)
4530{
4531 struct bnx2x *bp = params->bp;
4532 DP(NETIF_MSG_LINK, "bnx2x_8726_link_reset port %d\n", params->port);
4533 /* Set serial boot control for external load */
4534 bnx2x_cl45_write(bp, phy,
4535 MDIO_PMA_DEVAD,
4536 MDIO_PMA_REG_GEN_CTRL, 0x0001);
4537}
4538
4539/******************************************************************/
4540/* BCM8727 PHY SECTION */
4541/******************************************************************/
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004542static void bnx2x_8727_hw_reset(struct bnx2x_phy *phy,
4543 struct link_params *params) {
4544 u32 swap_val, swap_override;
4545 u8 port;
4546 /**
4547 * The PHY reset is controlled by GPIO 1. Fake the port number
4548 * to cancel the swap done in set_gpio()
4549 */
4550 struct bnx2x *bp = params->bp;
4551 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
4552 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
4553 port = (swap_val && swap_override) ^ 1;
4554 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
4555 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
4556}
4557
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004558static u8 bnx2x_8727_config_init(struct bnx2x_phy *phy,
4559 struct link_params *params,
4560 struct link_vars *vars)
4561{
4562 u16 tmp1, val, mod_abs;
4563 u16 rx_alarm_ctrl_val;
4564 u16 lasi_ctrl_val;
4565 struct bnx2x *bp = params->bp;
4566 /* Enable PMD link, MOD_ABS_FLT, and 1G link alarm */
4567
4568 bnx2x_wait_reset_complete(bp, phy);
4569 rx_alarm_ctrl_val = (1<<2) | (1<<5) ;
4570 lasi_ctrl_val = 0x0004;
4571
4572 DP(NETIF_MSG_LINK, "Initializing BCM8727\n");
4573 /* enable LASI */
4574 bnx2x_cl45_write(bp, phy,
4575 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
4576 rx_alarm_ctrl_val);
4577
4578 bnx2x_cl45_write(bp, phy,
4579 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, lasi_ctrl_val);
4580
4581 /* Initially configure MOD_ABS to interrupt when
4582 module is presence( bit 8) */
4583 bnx2x_cl45_read(bp, phy,
4584 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
4585 /* Set EDC off by setting OPTXLOS signal input to low
4586 (bit 9).
4587 When the EDC is off it locks onto a reference clock and
4588 avoids becoming 'lost'.*/
4589 mod_abs &= ~((1<<8) | (1<<9));
4590 bnx2x_cl45_write(bp, phy,
4591 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
4592
4593
4594 /* Make MOD_ABS give interrupt on change */
4595 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL,
4596 &val);
4597 val |= (1<<12);
4598 bnx2x_cl45_write(bp, phy,
4599 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL, val);
4600 /* Set 8727 GPIOs to input to allow reading from the
4601 8727 GPIO0 status which reflect SFP+ module
4602 over-current */
4603
4604 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL,
4605 &val);
4606 val &= 0xff8f; /* Reset bits 4-6 */
4607 bnx2x_cl45_write(bp, phy,
4608 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL, val);
4609
4610 bnx2x_8727_power_module(bp, phy, 1);
4611
4612 bnx2x_cl45_read(bp, phy,
4613 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &tmp1);
4614
4615 bnx2x_cl45_read(bp, phy,
4616 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &tmp1);
4617
4618 /* Set option 1G speed */
4619 if (phy->req_line_speed == SPEED_1000) {
4620 DP(NETIF_MSG_LINK, "Setting 1G force\n");
4621 bnx2x_cl45_write(bp, phy,
4622 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x40);
4623 bnx2x_cl45_write(bp, phy,
4624 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0xD);
4625 bnx2x_cl45_read(bp, phy,
4626 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, &tmp1);
4627 DP(NETIF_MSG_LINK, "1.7 = 0x%x\n", tmp1);
4628 } else if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
4629 ((phy->speed_cap_mask &
4630 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) &&
4631 ((phy->speed_cap_mask &
4632 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) !=
4633 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
4634
4635 DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
4636 bnx2x_cl45_write(bp, phy,
4637 MDIO_AN_DEVAD, MDIO_AN_REG_8727_MISC_CTRL, 0);
4638 bnx2x_cl45_write(bp, phy,
4639 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1300);
4640 } else {
4641 /**
4642 * Since the 8727 has only single reset pin, need to set the 10G
4643 * registers although it is default
4644 */
4645 bnx2x_cl45_write(bp, phy,
4646 MDIO_AN_DEVAD, MDIO_AN_REG_8727_MISC_CTRL,
4647 0x0020);
4648 bnx2x_cl45_write(bp, phy,
4649 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x0100);
4650 bnx2x_cl45_write(bp, phy,
4651 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x2040);
4652 bnx2x_cl45_write(bp, phy,
4653 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2,
4654 0x0008);
4655 }
4656
4657 /* Set 2-wire transfer rate of SFP+ module EEPROM
4658 * to 100Khz since some DACs(direct attached cables) do
4659 * not work at 400Khz.
4660 */
4661 bnx2x_cl45_write(bp, phy,
4662 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR,
4663 0xa001);
4664
4665 /* Set TX PreEmphasis if needed */
4666 if ((params->feature_config_flags &
4667 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
4668 DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x, TX_CTRL2 0x%x\n",
4669 phy->tx_preemphasis[0],
4670 phy->tx_preemphasis[1]);
4671 bnx2x_cl45_write(bp, phy,
4672 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TX_CTRL1,
4673 phy->tx_preemphasis[0]);
4674
4675 bnx2x_cl45_write(bp, phy,
4676 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TX_CTRL2,
4677 phy->tx_preemphasis[1]);
4678 }
4679
4680 return 0;
4681}
4682
4683static void bnx2x_8727_handle_mod_abs(struct bnx2x_phy *phy,
4684 struct link_params *params)
4685{
4686 struct bnx2x *bp = params->bp;
4687 u16 mod_abs, rx_alarm_status;
4688 u32 val = REG_RD(bp, params->shmem_base +
4689 offsetof(struct shmem_region, dev_info.
4690 port_feature_config[params->port].
4691 config));
4692 bnx2x_cl45_read(bp, phy,
4693 MDIO_PMA_DEVAD,
4694 MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
4695 if (mod_abs & (1<<8)) {
4696
4697 /* Module is absent */
4698 DP(NETIF_MSG_LINK, "MOD_ABS indication "
4699 "show module is absent\n");
4700
4701 /* 1. Set mod_abs to detect next module
4702 presence event
4703 2. Set EDC off by setting OPTXLOS signal input to low
4704 (bit 9).
4705 When the EDC is off it locks onto a reference clock and
4706 avoids becoming 'lost'.*/
4707 mod_abs &= ~((1<<8)|(1<<9));
4708 bnx2x_cl45_write(bp, phy,
4709 MDIO_PMA_DEVAD,
4710 MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
4711
4712 /* Clear RX alarm since it stays up as long as
4713 the mod_abs wasn't changed */
4714 bnx2x_cl45_read(bp, phy,
4715 MDIO_PMA_DEVAD,
4716 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
4717
4718 } else {
4719 /* Module is present */
4720 DP(NETIF_MSG_LINK, "MOD_ABS indication "
4721 "show module is present\n");
4722 /* First thing, disable transmitter,
4723 and if the module is ok, the
4724 module_detection will enable it*/
4725
4726 /* 1. Set mod_abs to detect next module
4727 absent event ( bit 8)
4728 2. Restore the default polarity of the OPRXLOS signal and
4729 this signal will then correctly indicate the presence or
4730 absence of the Rx signal. (bit 9) */
4731 mod_abs |= ((1<<8)|(1<<9));
4732 bnx2x_cl45_write(bp, phy,
4733 MDIO_PMA_DEVAD,
4734 MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
4735
4736 /* Clear RX alarm since it stays up as long as
4737 the mod_abs wasn't changed. This is need to be done
4738 before calling the module detection, otherwise it will clear
4739 the link update alarm */
4740 bnx2x_cl45_read(bp, phy,
4741 MDIO_PMA_DEVAD,
4742 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
4743
4744
4745 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
4746 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
4747 bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
4748
4749 if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0)
4750 bnx2x_sfp_module_detection(phy, params);
4751 else
4752 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
4753 }
4754
4755 DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n",
4756 rx_alarm_status);
4757 /* No need to check link status in case of
4758 module plugged in/out */
4759}
4760
4761static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy,
4762 struct link_params *params,
4763 struct link_vars *vars)
4764
4765{
4766 struct bnx2x *bp = params->bp;
4767 u8 link_up = 0;
4768 u16 link_status = 0;
4769 u16 rx_alarm_status, val1;
4770 /* Check the LASI */
4771 bnx2x_cl45_read(bp, phy,
4772 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM,
4773 &rx_alarm_status);
4774 vars->line_speed = 0;
4775 DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n", rx_alarm_status);
4776
4777 bnx2x_cl45_read(bp, phy,
4778 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
4779
4780 DP(NETIF_MSG_LINK, "8727 LASI status 0x%x\n", val1);
4781
4782 /* Clear MSG-OUT */
4783 bnx2x_cl45_read(bp, phy,
4784 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &val1);
4785
4786 /**
4787 * If a module is present and there is need to check
4788 * for over current
4789 */
4790 if (!(phy->flags & FLAGS_NOC) && !(rx_alarm_status & (1<<5))) {
4791 /* Check over-current using 8727 GPIO0 input*/
4792 bnx2x_cl45_read(bp, phy,
4793 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_GPIO_CTRL,
4794 &val1);
4795
4796 if ((val1 & (1<<8)) == 0) {
4797 DP(NETIF_MSG_LINK, "8727 Power fault has been detected"
4798 " on port %d\n", params->port);
4799 netdev_err(bp->dev, "Error: Power fault on Port %d has"
4800 " been detected and the power to "
4801 "that SFP+ module has been removed"
4802 " to prevent failure of the card."
4803 " Please remove the SFP+ module and"
4804 " restart the system to clear this"
4805 " error.\n",
4806 params->port);
4807
4808 /*
4809 * Disable all RX_ALARMs except for
4810 * mod_abs
4811 */
4812 bnx2x_cl45_write(bp, phy,
4813 MDIO_PMA_DEVAD,
4814 MDIO_PMA_REG_RX_ALARM_CTRL, (1<<5));
4815
4816 bnx2x_cl45_read(bp, phy,
4817 MDIO_PMA_DEVAD,
4818 MDIO_PMA_REG_PHY_IDENTIFIER, &val1);
4819 /* Wait for module_absent_event */
4820 val1 |= (1<<8);
4821 bnx2x_cl45_write(bp, phy,
4822 MDIO_PMA_DEVAD,
4823 MDIO_PMA_REG_PHY_IDENTIFIER, val1);
4824 /* Clear RX alarm */
4825 bnx2x_cl45_read(bp, phy,
4826 MDIO_PMA_DEVAD,
4827 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
4828 return 0;
4829 }
4830 } /* Over current check */
4831
4832 /* When module absent bit is set, check module */
4833 if (rx_alarm_status & (1<<5)) {
4834 bnx2x_8727_handle_mod_abs(phy, params);
4835 /* Enable all mod_abs and link detection bits */
4836 bnx2x_cl45_write(bp, phy,
4837 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
4838 ((1<<5) | (1<<2)));
4839 }
4840
4841 /* If transmitter is disabled, ignore false link up indication */
4842 bnx2x_cl45_read(bp, phy,
4843 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, &val1);
4844 if (val1 & (1<<15)) {
4845 DP(NETIF_MSG_LINK, "Tx is disabled\n");
4846 return 0;
4847 }
4848
4849 bnx2x_cl45_read(bp, phy,
4850 MDIO_PMA_DEVAD,
4851 MDIO_PMA_REG_8073_SPEED_LINK_STATUS, &link_status);
4852
4853 /* Bits 0..2 --> speed detected,
4854 bits 13..15--> link is down */
4855 if ((link_status & (1<<2)) && (!(link_status & (1<<15)))) {
4856 link_up = 1;
4857 vars->line_speed = SPEED_10000;
4858 } else if ((link_status & (1<<0)) && (!(link_status & (1<<13)))) {
4859 link_up = 1;
4860 vars->line_speed = SPEED_1000;
4861 DP(NETIF_MSG_LINK, "port %x: External link up in 1G\n",
4862 params->port);
4863 } else {
4864 link_up = 0;
4865 DP(NETIF_MSG_LINK, "port %x: External link is down\n",
4866 params->port);
4867 }
4868 if (link_up)
4869 bnx2x_ext_phy_resolve_fc(phy, params, vars);
4870 return link_up;
4871}
4872
4873static void bnx2x_8727_link_reset(struct bnx2x_phy *phy,
4874 struct link_params *params)
4875{
4876 struct bnx2x *bp = params->bp;
4877 /* Disable Transmitter */
4878 bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
4879}
4880
4881/******************************************************************/
4882/* BCM8481/BCM84823/BCM84833 PHY SECTION */
4883/******************************************************************/
4884static void bnx2x_save_848xx_spirom_version(struct bnx2x_phy *phy,
4885 struct link_params *params)
4886{
4887 u16 val, fw_ver1, fw_ver2, cnt;
4888 struct bnx2x *bp = params->bp;
4889
4890 /* For the 32 bits registers in 848xx, access via MDIO2ARM interface.*/
4891 /* (1) set register 0xc200_0014(SPI_BRIDGE_CTRL_2) to 0x03000000 */
4892 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0014);
4893 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200);
4894 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81B, 0x0000);
4895 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81C, 0x0300);
4896 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x0009);
4897
4898 for (cnt = 0; cnt < 100; cnt++) {
4899 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val);
4900 if (val & 1)
4901 break;
4902 udelay(5);
4903 }
4904 if (cnt == 100) {
4905 DP(NETIF_MSG_LINK, "Unable to read 848xx phy fw version(1)\n");
4906 bnx2x_save_spirom_version(bp, params->port, 0,
4907 phy->ver_addr);
4908 return;
4909 }
4910
4911
4912 /* 2) read register 0xc200_0000 (SPI_FW_STATUS) */
4913 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0000);
4914 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200);
4915 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x000A);
4916 for (cnt = 0; cnt < 100; cnt++) {
4917 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val);
4918 if (val & 1)
4919 break;
4920 udelay(5);
4921 }
4922 if (cnt == 100) {
4923 DP(NETIF_MSG_LINK, "Unable to read 848xx phy fw version(2)\n");
4924 bnx2x_save_spirom_version(bp, params->port, 0,
4925 phy->ver_addr);
4926 return;
4927 }
4928
4929 /* lower 16 bits of the register SPI_FW_STATUS */
4930 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81B, &fw_ver1);
4931 /* upper 16 bits of register SPI_FW_STATUS */
4932 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81C, &fw_ver2);
4933
4934 bnx2x_save_spirom_version(bp, params->port, (fw_ver2<<16) | fw_ver1,
4935 phy->ver_addr);
4936}
4937
4938static void bnx2x_848xx_set_led(struct bnx2x *bp,
4939 struct bnx2x_phy *phy)
4940{
4941 u16 val;
4942
4943 /* PHYC_CTL_LED_CTL */
4944 bnx2x_cl45_read(bp, phy,
4945 MDIO_PMA_DEVAD,
4946 MDIO_PMA_REG_8481_LINK_SIGNAL, &val);
4947 val &= 0xFE00;
4948 val |= 0x0092;
4949
4950 bnx2x_cl45_write(bp, phy,
4951 MDIO_PMA_DEVAD,
4952 MDIO_PMA_REG_8481_LINK_SIGNAL, val);
4953
4954 bnx2x_cl45_write(bp, phy,
4955 MDIO_PMA_DEVAD,
4956 MDIO_PMA_REG_8481_LED1_MASK,
4957 0x80);
4958
4959 bnx2x_cl45_write(bp, phy,
4960 MDIO_PMA_DEVAD,
4961 MDIO_PMA_REG_8481_LED2_MASK,
4962 0x18);
4963
4964 bnx2x_cl45_write(bp, phy,
4965 MDIO_PMA_DEVAD,
4966 MDIO_PMA_REG_8481_LED3_MASK,
4967 0x0040);
4968
4969 /* 'Interrupt Mask' */
4970 bnx2x_cl45_write(bp, phy,
4971 MDIO_AN_DEVAD,
4972 0xFFFB, 0xFFFD);
4973}
4974
4975static u8 bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy,
4976 struct link_params *params,
4977 struct link_vars *vars)
4978{
4979 struct bnx2x *bp = params->bp;
4980 u16 autoneg_val, an_1000_val, an_10_100_val;
4981 /**
4982 * This phy uses the NIG latch mechanism since link indication
4983 * arrives through its LED4 and not via its LASI signal, so we
4984 * get steady signal instead of clear on read
4985 */
4986 bnx2x_wait_reset_complete(bp, phy);
4987 bnx2x_bits_en(bp, NIG_REG_LATCH_BC_0 + params->port*4,
4988 1 << NIG_LATCH_BC_ENABLE_MI_INT);
4989
4990 bnx2x_cl45_write(bp, phy,
4991 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x0000);
4992
4993 bnx2x_848xx_set_led(bp, phy);
4994
4995 /* set 1000 speed advertisement */
4996 bnx2x_cl45_read(bp, phy,
4997 MDIO_AN_DEVAD, MDIO_AN_REG_8481_1000T_CTRL,
4998 &an_1000_val);
4999
5000 bnx2x_ext_phy_set_pause(params, phy, vars);
5001 bnx2x_cl45_read(bp, phy,
5002 MDIO_AN_DEVAD,
5003 MDIO_AN_REG_8481_LEGACY_AN_ADV,
5004 &an_10_100_val);
5005 bnx2x_cl45_read(bp, phy,
5006 MDIO_AN_DEVAD, MDIO_AN_REG_8481_LEGACY_MII_CTRL,
5007 &autoneg_val);
5008 /* Disable forced speed */
5009 autoneg_val &= ~((1<<6) | (1<<8) | (1<<9) | (1<<12) | (1<<13));
5010 an_10_100_val &= ~((1<<5) | (1<<6) | (1<<7) | (1<<8));
5011
5012 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
5013 (phy->speed_cap_mask &
5014 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) ||
5015 (phy->req_line_speed == SPEED_1000)) {
5016 an_1000_val |= (1<<8);
5017 autoneg_val |= (1<<9 | 1<<12);
5018 if (phy->req_duplex == DUPLEX_FULL)
5019 an_1000_val |= (1<<9);
5020 DP(NETIF_MSG_LINK, "Advertising 1G\n");
5021 } else
5022 an_1000_val &= ~((1<<8) | (1<<9));
5023
5024 bnx2x_cl45_write(bp, phy,
5025 MDIO_AN_DEVAD, MDIO_AN_REG_8481_1000T_CTRL,
5026 an_1000_val);
5027
5028 /* set 10 speed advertisement */
5029 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
5030 (phy->speed_cap_mask &
5031 (PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL |
5032 PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF)))) {
5033 an_10_100_val |= (1<<7);
5034 /* Enable autoneg and restart autoneg for legacy speeds */
5035 autoneg_val |= (1<<9 | 1<<12);
5036
5037 if (phy->req_duplex == DUPLEX_FULL)
5038 an_10_100_val |= (1<<8);
5039 DP(NETIF_MSG_LINK, "Advertising 100M\n");
5040 }
5041 /* set 10 speed advertisement */
5042 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
5043 (phy->speed_cap_mask &
5044 (PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL |
5045 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF)))) {
5046 an_10_100_val |= (1<<5);
5047 autoneg_val |= (1<<9 | 1<<12);
5048 if (phy->req_duplex == DUPLEX_FULL)
5049 an_10_100_val |= (1<<6);
5050 DP(NETIF_MSG_LINK, "Advertising 10M\n");
5051 }
5052
5053 /* Only 10/100 are allowed to work in FORCE mode */
5054 if (phy->req_line_speed == SPEED_100) {
5055 autoneg_val |= (1<<13);
5056 /* Enabled AUTO-MDIX when autoneg is disabled */
5057 bnx2x_cl45_write(bp, phy,
5058 MDIO_AN_DEVAD, MDIO_AN_REG_8481_AUX_CTRL,
5059 (1<<15 | 1<<9 | 7<<0));
5060 DP(NETIF_MSG_LINK, "Setting 100M force\n");
5061 }
5062 if (phy->req_line_speed == SPEED_10) {
5063 /* Enabled AUTO-MDIX when autoneg is disabled */
5064 bnx2x_cl45_write(bp, phy,
5065 MDIO_AN_DEVAD, MDIO_AN_REG_8481_AUX_CTRL,
5066 (1<<15 | 1<<9 | 7<<0));
5067 DP(NETIF_MSG_LINK, "Setting 10M force\n");
5068 }
5069
5070 bnx2x_cl45_write(bp, phy,
5071 MDIO_AN_DEVAD, MDIO_AN_REG_8481_LEGACY_AN_ADV,
5072 an_10_100_val);
5073
5074 if (phy->req_duplex == DUPLEX_FULL)
5075 autoneg_val |= (1<<8);
5076
5077 bnx2x_cl45_write(bp, phy,
5078 MDIO_AN_DEVAD,
5079 MDIO_AN_REG_8481_LEGACY_MII_CTRL, autoneg_val);
5080
5081 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
5082 (phy->speed_cap_mask &
5083 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) ||
5084 (phy->req_line_speed == SPEED_10000)) {
5085 DP(NETIF_MSG_LINK, "Advertising 10G\n");
5086 /* Restart autoneg for 10G*/
5087
5088 bnx2x_cl45_write(bp, phy,
5089 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL,
5090 0x3200);
5091 } else if (phy->req_line_speed != SPEED_10 &&
5092 phy->req_line_speed != SPEED_100) {
5093 bnx2x_cl45_write(bp, phy,
5094 MDIO_AN_DEVAD,
5095 MDIO_AN_REG_8481_10GBASE_T_AN_CTRL,
5096 1);
5097 }
5098 /* Save spirom version */
5099 bnx2x_save_848xx_spirom_version(phy, params);
5100
5101 return 0;
5102}
5103
5104static u8 bnx2x_8481_config_init(struct bnx2x_phy *phy,
5105 struct link_params *params,
5106 struct link_vars *vars)
5107{
5108 struct bnx2x *bp = params->bp;
5109 /* Restore normal power mode*/
5110 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
5111 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
5112
5113 /* HW reset */
5114 bnx2x_ext_phy_hw_reset(bp, params->port);
5115
5116 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
5117 return bnx2x_848xx_cmn_config_init(phy, params, vars);
5118}
5119
5120static u8 bnx2x_848x3_config_init(struct bnx2x_phy *phy,
5121 struct link_params *params,
5122 struct link_vars *vars)
5123{
5124 struct bnx2x *bp = params->bp;
5125 u16 temp;
5126 msleep(1);
5127 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
5128 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
5129 params->port);
5130 msleep(200); /* 100 is not enough */
5131
5132 /**
5133 * BCM84823 requires that XGXS links up first @ 10G for normal
5134 * behavior
5135 */
5136 temp = vars->line_speed;
5137 vars->line_speed = SPEED_10000;
5138 bnx2x_set_autoneg(phy, params, vars, 0);
5139 bnx2x_program_serdes(phy, params, vars);
5140 vars->line_speed = temp;
5141 return bnx2x_848xx_cmn_config_init(phy, params, vars);
5142}
5143
5144static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy,
5145 struct link_params *params,
5146 struct link_vars *vars)
5147{
5148 struct bnx2x *bp = params->bp;
5149 u16 val, val1, val2;
5150 u8 link_up = 0;
5151
5152 /* Check 10G-BaseT link status */
5153 /* Check PMD signal ok */
5154 bnx2x_cl45_read(bp, phy,
5155 MDIO_AN_DEVAD, 0xFFFA, &val1);
5156 bnx2x_cl45_read(bp, phy,
5157 MDIO_PMA_DEVAD, MDIO_PMA_REG_8481_PMD_SIGNAL,
5158 &val2);
5159 DP(NETIF_MSG_LINK, "BCM848xx: PMD_SIGNAL 1.a811 = 0x%x\n", val2);
5160
5161 /* Check link 10G */
5162 if (val2 & (1<<11)) {
5163 vars->line_speed = SPEED_10000;
5164 link_up = 1;
5165 bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
5166 } else { /* Check Legacy speed link */
5167 u16 legacy_status, legacy_speed;
5168
5169 /* Enable expansion register 0x42 (Operation mode status) */
5170 bnx2x_cl45_write(bp, phy,
5171 MDIO_AN_DEVAD,
5172 MDIO_AN_REG_8481_EXPANSION_REG_ACCESS, 0xf42);
5173
5174 /* Get legacy speed operation status */
5175 bnx2x_cl45_read(bp, phy,
5176 MDIO_AN_DEVAD,
5177 MDIO_AN_REG_8481_EXPANSION_REG_RD_RW,
5178 &legacy_status);
5179
5180 DP(NETIF_MSG_LINK, "Legacy speed status"
5181 " = 0x%x\n", legacy_status);
5182 link_up = ((legacy_status & (1<<11)) == (1<<11));
5183 if (link_up) {
5184 legacy_speed = (legacy_status & (3<<9));
5185 if (legacy_speed == (0<<9))
5186 vars->line_speed = SPEED_10;
5187 else if (legacy_speed == (1<<9))
5188 vars->line_speed = SPEED_100;
5189 else if (legacy_speed == (2<<9))
5190 vars->line_speed = SPEED_1000;
5191 else /* Should not happen */
5192 vars->line_speed = 0;
5193
5194 if (legacy_status & (1<<8))
5195 vars->duplex = DUPLEX_FULL;
5196 else
5197 vars->duplex = DUPLEX_HALF;
5198
5199 DP(NETIF_MSG_LINK, "Link is up in %dMbps,"
5200 " is_duplex_full= %d\n", vars->line_speed,
5201 (vars->duplex == DUPLEX_FULL));
5202 /* Check legacy speed AN resolution */
5203 bnx2x_cl45_read(bp, phy,
5204 MDIO_AN_DEVAD,
5205 MDIO_AN_REG_8481_LEGACY_MII_STATUS,
5206 &val);
5207 if (val & (1<<5))
5208 vars->link_status |=
5209 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
5210 bnx2x_cl45_read(bp, phy,
5211 MDIO_AN_DEVAD,
5212 MDIO_AN_REG_8481_LEGACY_AN_EXPANSION,
5213 &val);
5214 if ((val & (1<<0)) == 0)
5215 vars->link_status |=
5216 LINK_STATUS_PARALLEL_DETECTION_USED;
5217 }
5218 }
5219 if (link_up) {
5220 DP(NETIF_MSG_LINK, "BCM84823: link speed is %d\n",
5221 vars->line_speed);
5222 bnx2x_ext_phy_resolve_fc(phy, params, vars);
5223 }
5224
5225 return link_up;
5226}
5227
5228static u8 bnx2x_848xx_format_ver(u32 raw_ver, u8 *str, u16 *len)
5229{
5230 u8 status = 0;
5231 u32 spirom_ver;
5232 spirom_ver = ((raw_ver & 0xF80) >> 7) << 16 | (raw_ver & 0x7F);
5233 status = bnx2x_format_ver(spirom_ver, str, len);
5234 return status;
5235}
5236
5237static void bnx2x_8481_hw_reset(struct bnx2x_phy *phy,
5238 struct link_params *params)
5239{
5240 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
5241 MISC_REGISTERS_GPIO_OUTPUT_LOW, 0);
5242 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
5243 MISC_REGISTERS_GPIO_OUTPUT_LOW, 1);
5244}
5245
5246static void bnx2x_8481_link_reset(struct bnx2x_phy *phy,
5247 struct link_params *params)
5248{
5249 bnx2x_cl45_write(params->bp, phy,
5250 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x0000);
5251 bnx2x_cl45_write(params->bp, phy,
5252 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1);
5253}
5254
5255static void bnx2x_848x3_link_reset(struct bnx2x_phy *phy,
5256 struct link_params *params)
5257{
5258 struct bnx2x *bp = params->bp;
5259 u8 port = params->port;
5260 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
5261 MISC_REGISTERS_GPIO_OUTPUT_LOW,
5262 port);
5263}
5264
5265/******************************************************************/
5266/* SFX7101 PHY SECTION */
5267/******************************************************************/
5268static void bnx2x_7101_config_loopback(struct bnx2x_phy *phy,
5269 struct link_params *params)
5270{
5271 struct bnx2x *bp = params->bp;
5272 /* SFX7101_XGXS_TEST1 */
5273 bnx2x_cl45_write(bp, phy,
5274 MDIO_XS_DEVAD, MDIO_XS_SFX7101_XGXS_TEST1, 0x100);
5275}
5276
5277static u8 bnx2x_7101_config_init(struct bnx2x_phy *phy,
5278 struct link_params *params,
5279 struct link_vars *vars)
5280{
5281 u16 fw_ver1, fw_ver2, val;
5282 struct bnx2x *bp = params->bp;
5283 DP(NETIF_MSG_LINK, "Setting the SFX7101 LASI indication\n");
5284
5285 /* Restore normal power mode*/
5286 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
5287 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
5288 /* HW reset */
5289 bnx2x_ext_phy_hw_reset(bp, params->port);
5290 bnx2x_wait_reset_complete(bp, phy);
5291
5292 bnx2x_cl45_write(bp, phy,
5293 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x1);
5294 DP(NETIF_MSG_LINK, "Setting the SFX7101 LED to blink on traffic\n");
5295 bnx2x_cl45_write(bp, phy,
5296 MDIO_PMA_DEVAD, MDIO_PMA_REG_7107_LED_CNTL, (1<<3));
5297
5298 bnx2x_ext_phy_set_pause(params, phy, vars);
5299 /* Restart autoneg */
5300 bnx2x_cl45_read(bp, phy,
5301 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, &val);
5302 val |= 0x200;
5303 bnx2x_cl45_write(bp, phy,
5304 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, val);
5305
5306 /* Save spirom version */
5307 bnx2x_cl45_read(bp, phy,
5308 MDIO_PMA_DEVAD, MDIO_PMA_REG_7101_VER1, &fw_ver1);
5309
5310 bnx2x_cl45_read(bp, phy,
5311 MDIO_PMA_DEVAD, MDIO_PMA_REG_7101_VER2, &fw_ver2);
5312 bnx2x_save_spirom_version(bp, params->port,
5313 (u32)(fw_ver1<<16 | fw_ver2), phy->ver_addr);
5314 return 0;
5315}
5316
5317static u8 bnx2x_7101_read_status(struct bnx2x_phy *phy,
5318 struct link_params *params,
5319 struct link_vars *vars)
5320{
5321 struct bnx2x *bp = params->bp;
5322 u8 link_up;
5323 u16 val1, val2;
5324 bnx2x_cl45_read(bp, phy,
5325 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val2);
5326 bnx2x_cl45_read(bp, phy,
5327 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
5328 DP(NETIF_MSG_LINK, "10G-base-T LASI status 0x%x->0x%x\n",
5329 val2, val1);
5330 bnx2x_cl45_read(bp, phy,
5331 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
5332 bnx2x_cl45_read(bp, phy,
5333 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
5334 DP(NETIF_MSG_LINK, "10G-base-T PMA status 0x%x->0x%x\n",
5335 val2, val1);
5336 link_up = ((val1 & 4) == 4);
5337 /* if link is up
5338 * print the AN outcome of the SFX7101 PHY
5339 */
5340 if (link_up) {
5341 bnx2x_cl45_read(bp, phy,
5342 MDIO_AN_DEVAD, MDIO_AN_REG_MASTER_STATUS,
5343 &val2);
5344 vars->line_speed = SPEED_10000;
5345 DP(NETIF_MSG_LINK, "SFX7101 AN status 0x%x->Master=%x\n",
5346 val2, (val2 & (1<<14)));
5347 bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
5348 bnx2x_ext_phy_resolve_fc(phy, params, vars);
5349 }
5350 return link_up;
5351}
5352
5353
5354static u8 bnx2x_7101_format_ver(u32 spirom_ver, u8 *str, u16 *len)
5355{
5356 if (*len < 5)
5357 return -EINVAL;
5358 str[0] = (spirom_ver & 0xFF);
5359 str[1] = (spirom_ver & 0xFF00) >> 8;
5360 str[2] = (spirom_ver & 0xFF0000) >> 16;
5361 str[3] = (spirom_ver & 0xFF000000) >> 24;
5362 str[4] = '\0';
5363 *len -= 5;
5364 return 0;
5365}
5366
5367void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, struct bnx2x_phy *phy)
5368{
5369 u16 val, cnt;
5370
5371 bnx2x_cl45_read(bp, phy,
5372 MDIO_PMA_DEVAD,
5373 MDIO_PMA_REG_7101_RESET, &val);
5374
5375 for (cnt = 0; cnt < 10; cnt++) {
5376 msleep(50);
5377 /* Writes a self-clearing reset */
5378 bnx2x_cl45_write(bp, phy,
5379 MDIO_PMA_DEVAD,
5380 MDIO_PMA_REG_7101_RESET,
5381 (val | (1<<15)));
5382 /* Wait for clear */
5383 bnx2x_cl45_read(bp, phy,
5384 MDIO_PMA_DEVAD,
5385 MDIO_PMA_REG_7101_RESET, &val);
5386
5387 if ((val & (1<<15)) == 0)
5388 break;
5389 }
5390}
5391
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005392static void bnx2x_7101_hw_reset(struct bnx2x_phy *phy,
5393 struct link_params *params) {
5394 /* Low power mode is controlled by GPIO 2 */
5395 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_2,
5396 MISC_REGISTERS_GPIO_OUTPUT_LOW, params->port);
5397 /* The PHY reset is controlled by GPIO 1 */
5398 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
5399 MISC_REGISTERS_GPIO_OUTPUT_LOW, params->port);
5400}
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005401
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005402/******************************************************************/
5403/* STATIC PHY DECLARATION */
5404/******************************************************************/
5405
5406static struct bnx2x_phy phy_null = {
5407 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN,
5408 .addr = 0,
5409 .flags = FLAGS_INIT_XGXS_FIRST,
5410 .def_md_devad = 0,
5411 .reserved = 0,
5412 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5413 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5414 .mdio_ctrl = 0,
5415 .supported = 0,
5416 .media_type = ETH_PHY_NOT_PRESENT,
5417 .ver_addr = 0,
5418 .req_flow_ctrl = 0,
5419 .req_line_speed = 0,
5420 .speed_cap_mask = 0,
5421 .req_duplex = 0,
5422 .rsrv = 0,
5423 .config_init = (config_init_t)NULL,
5424 .read_status = (read_status_t)NULL,
5425 .link_reset = (link_reset_t)NULL,
5426 .config_loopback = (config_loopback_t)NULL,
5427 .format_fw_ver = (format_fw_ver_t)NULL,
5428 .hw_reset = (hw_reset_t)NULL,
5429 .set_link_led = (set_link_led_t)NULL
5430};
5431
5432static struct bnx2x_phy phy_serdes = {
5433 .type = PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT,
5434 .addr = 0xff,
5435 .flags = 0,
5436 .def_md_devad = 0,
5437 .reserved = 0,
5438 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5439 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5440 .mdio_ctrl = 0,
5441 .supported = (SUPPORTED_10baseT_Half |
5442 SUPPORTED_10baseT_Full |
5443 SUPPORTED_100baseT_Half |
5444 SUPPORTED_100baseT_Full |
5445 SUPPORTED_1000baseT_Full |
5446 SUPPORTED_2500baseX_Full |
5447 SUPPORTED_TP |
5448 SUPPORTED_Autoneg |
5449 SUPPORTED_Pause |
5450 SUPPORTED_Asym_Pause),
5451 .media_type = ETH_PHY_UNSPECIFIED,
5452 .ver_addr = 0,
5453 .req_flow_ctrl = 0,
5454 .req_line_speed = 0,
5455 .speed_cap_mask = 0,
5456 .req_duplex = 0,
5457 .rsrv = 0,
5458 .config_init = (config_init_t)bnx2x_init_serdes,
5459 .read_status = (read_status_t)bnx2x_link_settings_status,
5460 .link_reset = (link_reset_t)bnx2x_int_link_reset,
5461 .config_loopback = (config_loopback_t)NULL,
5462 .format_fw_ver = (format_fw_ver_t)NULL,
5463 .hw_reset = (hw_reset_t)NULL,
5464 .set_link_led = (set_link_led_t)NULL
5465};
5466
5467static struct bnx2x_phy phy_xgxs = {
5468 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT,
5469 .addr = 0xff,
5470 .flags = 0,
5471 .def_md_devad = 0,
5472 .reserved = 0,
5473 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5474 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5475 .mdio_ctrl = 0,
5476 .supported = (SUPPORTED_10baseT_Half |
5477 SUPPORTED_10baseT_Full |
5478 SUPPORTED_100baseT_Half |
5479 SUPPORTED_100baseT_Full |
5480 SUPPORTED_1000baseT_Full |
5481 SUPPORTED_2500baseX_Full |
5482 SUPPORTED_10000baseT_Full |
5483 SUPPORTED_FIBRE |
5484 SUPPORTED_Autoneg |
5485 SUPPORTED_Pause |
5486 SUPPORTED_Asym_Pause),
5487 .media_type = ETH_PHY_UNSPECIFIED,
5488 .ver_addr = 0,
5489 .req_flow_ctrl = 0,
5490 .req_line_speed = 0,
5491 .speed_cap_mask = 0,
5492 .req_duplex = 0,
5493 .rsrv = 0,
5494 .config_init = (config_init_t)bnx2x_init_xgxs,
5495 .read_status = (read_status_t)bnx2x_link_settings_status,
5496 .link_reset = (link_reset_t)bnx2x_int_link_reset,
5497 .config_loopback = (config_loopback_t)bnx2x_set_xgxs_loopback,
5498 .format_fw_ver = (format_fw_ver_t)NULL,
5499 .hw_reset = (hw_reset_t)NULL,
5500 .set_link_led = (set_link_led_t)NULL
5501};
5502
5503static struct bnx2x_phy phy_7101 = {
5504 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5505 .addr = 0xff,
5506 .flags = FLAGS_FAN_FAILURE_DET_REQ,
5507 .def_md_devad = 0,
5508 .reserved = 0,
5509 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5510 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5511 .mdio_ctrl = 0,
5512 .supported = (SUPPORTED_10000baseT_Full |
5513 SUPPORTED_TP |
5514 SUPPORTED_Autoneg |
5515 SUPPORTED_Pause |
5516 SUPPORTED_Asym_Pause),
5517 .media_type = ETH_PHY_BASE_T,
5518 .ver_addr = 0,
5519 .req_flow_ctrl = 0,
5520 .req_line_speed = 0,
5521 .speed_cap_mask = 0,
5522 .req_duplex = 0,
5523 .rsrv = 0,
5524 .config_init = (config_init_t)bnx2x_7101_config_init,
5525 .read_status = (read_status_t)bnx2x_7101_read_status,
5526 .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
5527 .config_loopback = (config_loopback_t)bnx2x_7101_config_loopback,
5528 .format_fw_ver = (format_fw_ver_t)bnx2x_7101_format_ver,
5529 .hw_reset = (hw_reset_t)bnx2x_7101_hw_reset,
5530 .set_link_led = (set_link_led_t)NULL
5531};
5532static struct bnx2x_phy phy_8073 = {
5533 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5534 .addr = 0xff,
5535 .flags = FLAGS_HW_LOCK_REQUIRED,
5536 .def_md_devad = 0,
5537 .reserved = 0,
5538 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5539 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5540 .mdio_ctrl = 0,
5541 .supported = (SUPPORTED_10000baseT_Full |
5542 SUPPORTED_2500baseX_Full |
5543 SUPPORTED_1000baseT_Full |
5544 SUPPORTED_FIBRE |
5545 SUPPORTED_Autoneg |
5546 SUPPORTED_Pause |
5547 SUPPORTED_Asym_Pause),
5548 .media_type = ETH_PHY_UNSPECIFIED,
5549 .ver_addr = 0,
5550 .req_flow_ctrl = 0,
5551 .req_line_speed = 0,
5552 .speed_cap_mask = 0,
5553 .req_duplex = 0,
5554 .rsrv = 0,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00005555 .config_init = (config_init_t)bnx2x_8073_config_init,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005556 .read_status = (read_status_t)bnx2x_8073_read_status,
5557 .link_reset = (link_reset_t)bnx2x_8073_link_reset,
5558 .config_loopback = (config_loopback_t)NULL,
5559 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
5560 .hw_reset = (hw_reset_t)NULL,
5561 .set_link_led = (set_link_led_t)NULL
5562};
5563static struct bnx2x_phy phy_8705 = {
5564 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705,
5565 .addr = 0xff,
5566 .flags = FLAGS_INIT_XGXS_FIRST,
5567 .def_md_devad = 0,
5568 .reserved = 0,
5569 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5570 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5571 .mdio_ctrl = 0,
5572 .supported = (SUPPORTED_10000baseT_Full |
5573 SUPPORTED_FIBRE |
5574 SUPPORTED_Pause |
5575 SUPPORTED_Asym_Pause),
5576 .media_type = ETH_PHY_XFP_FIBER,
5577 .ver_addr = 0,
5578 .req_flow_ctrl = 0,
5579 .req_line_speed = 0,
5580 .speed_cap_mask = 0,
5581 .req_duplex = 0,
5582 .rsrv = 0,
5583 .config_init = (config_init_t)bnx2x_8705_config_init,
5584 .read_status = (read_status_t)bnx2x_8705_read_status,
5585 .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
5586 .config_loopback = (config_loopback_t)NULL,
5587 .format_fw_ver = (format_fw_ver_t)bnx2x_null_format_ver,
5588 .hw_reset = (hw_reset_t)NULL,
5589 .set_link_led = (set_link_led_t)NULL
5590};
5591static struct bnx2x_phy phy_8706 = {
5592 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706,
5593 .addr = 0xff,
5594 .flags = FLAGS_INIT_XGXS_FIRST,
5595 .def_md_devad = 0,
5596 .reserved = 0,
5597 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5598 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5599 .mdio_ctrl = 0,
5600 .supported = (SUPPORTED_10000baseT_Full |
5601 SUPPORTED_1000baseT_Full |
5602 SUPPORTED_FIBRE |
5603 SUPPORTED_Pause |
5604 SUPPORTED_Asym_Pause),
5605 .media_type = ETH_PHY_SFP_FIBER,
5606 .ver_addr = 0,
5607 .req_flow_ctrl = 0,
5608 .req_line_speed = 0,
5609 .speed_cap_mask = 0,
5610 .req_duplex = 0,
5611 .rsrv = 0,
5612 .config_init = (config_init_t)bnx2x_8706_config_init,
5613 .read_status = (read_status_t)bnx2x_8706_read_status,
5614 .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
5615 .config_loopback = (config_loopback_t)NULL,
5616 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
5617 .hw_reset = (hw_reset_t)NULL,
5618 .set_link_led = (set_link_led_t)NULL
5619};
5620
5621static struct bnx2x_phy phy_8726 = {
5622 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
5623 .addr = 0xff,
5624 .flags = (FLAGS_HW_LOCK_REQUIRED |
5625 FLAGS_INIT_XGXS_FIRST),
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_10000baseT_Full |
5632 SUPPORTED_1000baseT_Full |
5633 SUPPORTED_Autoneg |
5634 SUPPORTED_FIBRE |
5635 SUPPORTED_Pause |
5636 SUPPORTED_Asym_Pause),
5637 .media_type = ETH_PHY_SFP_FIBER,
5638 .ver_addr = 0,
5639 .req_flow_ctrl = 0,
5640 .req_line_speed = 0,
5641 .speed_cap_mask = 0,
5642 .req_duplex = 0,
5643 .rsrv = 0,
5644 .config_init = (config_init_t)bnx2x_8726_config_init,
5645 .read_status = (read_status_t)bnx2x_8726_read_status,
5646 .link_reset = (link_reset_t)bnx2x_8726_link_reset,
5647 .config_loopback = (config_loopback_t)bnx2x_8726_config_loopback,
5648 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
5649 .hw_reset = (hw_reset_t)NULL,
5650 .set_link_led = (set_link_led_t)NULL
5651};
5652
5653static struct bnx2x_phy phy_8727 = {
5654 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
5655 .addr = 0xff,
5656 .flags = FLAGS_FAN_FAILURE_DET_REQ,
5657 .def_md_devad = 0,
5658 .reserved = 0,
5659 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5660 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5661 .mdio_ctrl = 0,
5662 .supported = (SUPPORTED_10000baseT_Full |
5663 SUPPORTED_1000baseT_Full |
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005664 SUPPORTED_FIBRE |
5665 SUPPORTED_Pause |
5666 SUPPORTED_Asym_Pause),
5667 .media_type = ETH_PHY_SFP_FIBER,
5668 .ver_addr = 0,
5669 .req_flow_ctrl = 0,
5670 .req_line_speed = 0,
5671 .speed_cap_mask = 0,
5672 .req_duplex = 0,
5673 .rsrv = 0,
5674 .config_init = (config_init_t)bnx2x_8727_config_init,
5675 .read_status = (read_status_t)bnx2x_8727_read_status,
5676 .link_reset = (link_reset_t)bnx2x_8727_link_reset,
5677 .config_loopback = (config_loopback_t)NULL,
5678 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
5679 .hw_reset = (hw_reset_t)bnx2x_8727_hw_reset,
5680 .set_link_led = (set_link_led_t)NULL
5681};
5682static struct bnx2x_phy phy_8481 = {
5683 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
5684 .addr = 0xff,
5685 .flags = FLAGS_FAN_FAILURE_DET_REQ,
5686 .def_md_devad = 0,
5687 .reserved = 0,
5688 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5689 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5690 .mdio_ctrl = 0,
5691 .supported = (SUPPORTED_10baseT_Half |
5692 SUPPORTED_10baseT_Full |
5693 SUPPORTED_100baseT_Half |
5694 SUPPORTED_100baseT_Full |
5695 SUPPORTED_1000baseT_Full |
5696 SUPPORTED_10000baseT_Full |
5697 SUPPORTED_TP |
5698 SUPPORTED_Autoneg |
5699 SUPPORTED_Pause |
5700 SUPPORTED_Asym_Pause),
5701 .media_type = ETH_PHY_BASE_T,
5702 .ver_addr = 0,
5703 .req_flow_ctrl = 0,
5704 .req_line_speed = 0,
5705 .speed_cap_mask = 0,
5706 .req_duplex = 0,
5707 .rsrv = 0,
5708 .config_init = (config_init_t)bnx2x_8481_config_init,
5709 .read_status = (read_status_t)bnx2x_848xx_read_status,
5710 .link_reset = (link_reset_t)bnx2x_8481_link_reset,
5711 .config_loopback = (config_loopback_t)NULL,
5712 .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver,
5713 .hw_reset = (hw_reset_t)bnx2x_8481_hw_reset,
5714 .set_link_led = (set_link_led_t)NULL
5715};
5716
5717static struct bnx2x_phy phy_84823 = {
5718 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823,
5719 .addr = 0xff,
5720 .flags = FLAGS_FAN_FAILURE_DET_REQ,
5721 .def_md_devad = 0,
5722 .reserved = 0,
5723 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5724 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5725 .mdio_ctrl = 0,
5726 .supported = (SUPPORTED_10baseT_Half |
5727 SUPPORTED_10baseT_Full |
5728 SUPPORTED_100baseT_Half |
5729 SUPPORTED_100baseT_Full |
5730 SUPPORTED_1000baseT_Full |
5731 SUPPORTED_10000baseT_Full |
5732 SUPPORTED_TP |
5733 SUPPORTED_Autoneg |
5734 SUPPORTED_Pause |
5735 SUPPORTED_Asym_Pause),
5736 .media_type = ETH_PHY_BASE_T,
5737 .ver_addr = 0,
5738 .req_flow_ctrl = 0,
5739 .req_line_speed = 0,
5740 .speed_cap_mask = 0,
5741 .req_duplex = 0,
5742 .rsrv = 0,
5743 .config_init = (config_init_t)bnx2x_848x3_config_init,
5744 .read_status = (read_status_t)bnx2x_848xx_read_status,
5745 .link_reset = (link_reset_t)bnx2x_848x3_link_reset,
5746 .config_loopback = (config_loopback_t)NULL,
5747 .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver,
5748 .hw_reset = (hw_reset_t)NULL,
5749 .set_link_led = (set_link_led_t)NULL
5750};
5751
5752/*****************************************************************/
5753/* */
5754/* Populate the phy according. Main function: bnx2x_populate_phy */
5755/* */
5756/*****************************************************************/
5757
5758static void bnx2x_populate_preemphasis(struct bnx2x *bp, u32 shmem_base,
5759 struct bnx2x_phy *phy, u8 port,
5760 u8 phy_index)
5761{
5762 /* Get the 4 lanes xgxs config rx and tx */
5763 u32 rx = 0, tx = 0, i;
5764 for (i = 0; i < 2; i++) {
5765 /**
5766 * INT_PHY and EXT_PHY1 share the same value location in the
5767 * shmem. When num_phys is greater than 1, than this value
5768 * applies only to EXT_PHY1
5769 */
5770
5771 rx = REG_RD(bp, shmem_base +
5772 offsetof(struct shmem_region,
5773 dev_info.port_hw_config[port].xgxs_config_rx[i<<1]));
5774
5775 tx = REG_RD(bp, shmem_base +
5776 offsetof(struct shmem_region,
5777 dev_info.port_hw_config[port].xgxs_config_tx[i<<1]));
5778
5779 phy->rx_preemphasis[i << 1] = ((rx>>16) & 0xffff);
5780 phy->rx_preemphasis[(i << 1) + 1] = (rx & 0xffff);
5781
5782 phy->tx_preemphasis[i << 1] = ((tx>>16) & 0xffff);
5783 phy->tx_preemphasis[(i << 1) + 1] = (tx & 0xffff);
5784 }
5785}
5786
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005787static u32 bnx2x_get_ext_phy_config(struct bnx2x *bp, u32 shmem_base,
5788 u8 phy_index, u8 port)
5789{
5790 u32 ext_phy_config = 0;
5791 switch (phy_index) {
5792 case EXT_PHY1:
5793 ext_phy_config = REG_RD(bp, shmem_base +
5794 offsetof(struct shmem_region,
5795 dev_info.port_hw_config[port].external_phy_config));
5796 break;
5797 default:
5798 DP(NETIF_MSG_LINK, "Invalid phy_index %d\n", phy_index);
5799 return -EINVAL;
5800 }
5801
5802 return ext_phy_config;
5803}
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005804static u8 bnx2x_populate_int_phy(struct bnx2x *bp, u32 shmem_base, u8 port,
5805 struct bnx2x_phy *phy)
5806{
5807 u32 phy_addr;
5808 u32 chip_id;
5809 u32 switch_cfg = (REG_RD(bp, shmem_base +
5810 offsetof(struct shmem_region,
5811 dev_info.port_feature_config[port].link_config)) &
5812 PORT_FEATURE_CONNECTED_SWITCH_MASK);
5813 chip_id = REG_RD(bp, MISC_REG_CHIP_NUM) << 16;
5814 switch (switch_cfg) {
5815 case SWITCH_CFG_1G:
5816 phy_addr = REG_RD(bp,
5817 NIG_REG_SERDES0_CTRL_PHY_ADDR +
5818 port * 0x10);
5819 *phy = phy_serdes;
5820 break;
5821 case SWITCH_CFG_10G:
5822 phy_addr = REG_RD(bp,
5823 NIG_REG_XGXS0_CTRL_PHY_ADDR +
5824 port * 0x18);
5825 *phy = phy_xgxs;
5826 break;
5827 default:
5828 DP(NETIF_MSG_LINK, "Invalid switch_cfg\n");
5829 return -EINVAL;
5830 }
5831 phy->addr = (u8)phy_addr;
5832 phy->mdio_ctrl = bnx2x_get_emac_base(bp,
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00005833 SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005834 port);
5835 phy->def_md_devad = DEFAULT_PHY_DEV_ADDR;
5836
5837 DP(NETIF_MSG_LINK, "Internal phy port=%d, addr=0x%x, mdio_ctl=0x%x\n",
5838 port, phy->addr, phy->mdio_ctrl);
5839
5840 bnx2x_populate_preemphasis(bp, shmem_base, phy, port, INT_PHY);
5841 return 0;
5842}
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005843
5844static u8 bnx2x_populate_ext_phy(struct bnx2x *bp,
5845 u8 phy_index,
5846 u32 shmem_base,
5847 u8 port,
5848 struct bnx2x_phy *phy)
5849{
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00005850 u32 ext_phy_config, phy_type, config2;
5851 u32 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005852 ext_phy_config = bnx2x_get_ext_phy_config(bp, shmem_base,
5853 phy_index, port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005854 phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
5855 /* Select the phy type */
5856 switch (phy_type) {
5857 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00005858 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_SWAPPED;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005859 *phy = phy_8073;
5860 break;
5861 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
5862 *phy = phy_8705;
5863 break;
5864 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
5865 *phy = phy_8706;
5866 break;
5867 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00005868 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005869 *phy = phy_8726;
5870 break;
5871 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
5872 /* BCM8727_NOC => BCM8727 no over current */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00005873 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005874 *phy = phy_8727;
5875 phy->flags |= FLAGS_NOC;
5876 break;
5877 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00005878 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005879 *phy = phy_8727;
5880 break;
5881 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
5882 *phy = phy_8481;
5883 break;
5884 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
5885 *phy = phy_84823;
5886 break;
5887 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
5888 *phy = phy_7101;
5889 break;
5890 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
5891 *phy = phy_null;
5892 return -EINVAL;
5893 default:
5894 *phy = phy_null;
5895 return 0;
5896 }
5897
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005898 phy->addr = XGXS_EXT_PHY_ADDR(ext_phy_config);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005899 bnx2x_populate_preemphasis(bp, shmem_base, phy, port, phy_index);
Yaniv Rosner62b29a52010-09-07 11:40:58 +00005900
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00005901 /**
5902 * The shmem address of the phy version is located on different
5903 * structures. In case this structure is too old, do not set
5904 * the address
5905 */
5906 config2 = REG_RD(bp, shmem_base + offsetof(struct shmem_region,
5907 dev_info.shared_hw_config.config2));
5908
5909 phy->ver_addr = shmem_base + offsetof(struct shmem_region,
5910 port_mb[port].ext_phy_fw_version);
5911
5912 /* Check specific mdc mdio settings */
5913 if (config2 & SHARED_HW_CFG_MDC_MDIO_ACCESS1_MASK)
5914 mdc_mdio_access = config2 &
5915 SHARED_HW_CFG_MDC_MDIO_ACCESS1_MASK;
5916
5917 phy->mdio_ctrl = bnx2x_get_emac_base(bp, mdc_mdio_access, port);
5918
5919 /**
5920 * In case mdc/mdio_access of the external phy is different than the
5921 * mdc/mdio access of the XGXS, a HW lock must be taken in each access
5922 * to prevent one port interfere with another port's CL45 operations.
5923 */
5924 if (mdc_mdio_access != SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH)
5925 phy->flags |= FLAGS_HW_LOCK_REQUIRED;
5926 DP(NETIF_MSG_LINK, "phy_type 0x%x port %d found in index %d\n",
5927 phy_type, port, phy_index);
5928 DP(NETIF_MSG_LINK, " addr=0x%x, mdio_ctl=0x%x\n",
5929 phy->addr, phy->mdio_ctrl);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005930 return 0;
5931}
5932
5933static u8 bnx2x_populate_phy(struct bnx2x *bp, u8 phy_index, u32 shmem_base,
5934 u8 port, struct bnx2x_phy *phy)
5935{
5936 u8 status = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005937 phy->type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN;
5938 if (phy_index == INT_PHY)
5939 return bnx2x_populate_int_phy(bp, shmem_base, port, phy);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005940 status = bnx2x_populate_ext_phy(bp, phy_index, shmem_base,
5941 port, phy);
5942 return status;
5943}
5944
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005945static void bnx2x_phy_def_cfg(struct link_params *params,
5946 struct bnx2x_phy *phy,
5947 u8 actual_phy_idx)
5948{
5949 struct bnx2x *bp = params->bp;
5950 u32 link_config;
5951 /* Populate the default phy configuration for MF mode */
5952 link_config = REG_RD(bp, params->shmem_base +
5953 offsetof(struct shmem_region, dev_info.
5954 port_feature_config[params->port].link_config));
5955 phy->speed_cap_mask = REG_RD(bp, params->shmem_base +
5956 offsetof(struct shmem_region, dev_info.
5957 port_hw_config[params->port].speed_capability_mask));
5958
5959 phy->req_duplex = DUPLEX_FULL;
5960 switch (link_config & PORT_FEATURE_LINK_SPEED_MASK) {
5961 case PORT_FEATURE_LINK_SPEED_10M_HALF:
5962 phy->req_duplex = DUPLEX_HALF;
5963 case PORT_FEATURE_LINK_SPEED_10M_FULL:
5964 phy->req_line_speed = SPEED_10;
5965 break;
5966 case PORT_FEATURE_LINK_SPEED_100M_HALF:
5967 phy->req_duplex = DUPLEX_HALF;
5968 case PORT_FEATURE_LINK_SPEED_100M_FULL:
5969 phy->req_line_speed = SPEED_100;
5970 break;
5971 case PORT_FEATURE_LINK_SPEED_1G:
5972 phy->req_line_speed = SPEED_1000;
5973 break;
5974 case PORT_FEATURE_LINK_SPEED_2_5G:
5975 phy->req_line_speed = SPEED_2500;
5976 break;
5977 case PORT_FEATURE_LINK_SPEED_10G_CX4:
5978 phy->req_line_speed = SPEED_10000;
5979 break;
5980 default:
5981 phy->req_line_speed = SPEED_AUTO_NEG;
5982 break;
5983 }
5984
5985 switch (link_config & PORT_FEATURE_FLOW_CONTROL_MASK) {
5986 case PORT_FEATURE_FLOW_CONTROL_AUTO:
5987 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_AUTO;
5988 break;
5989 case PORT_FEATURE_FLOW_CONTROL_TX:
5990 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_TX;
5991 break;
5992 case PORT_FEATURE_FLOW_CONTROL_RX:
5993 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_RX;
5994 break;
5995 case PORT_FEATURE_FLOW_CONTROL_BOTH:
5996 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_BOTH;
5997 break;
5998 default:
5999 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_NONE;
6000 break;
6001 }
6002}
6003
6004u8 bnx2x_phy_probe(struct link_params *params)
6005{
6006 u8 phy_index, actual_phy_idx, link_cfg_idx;
6007
6008 struct bnx2x *bp = params->bp;
6009 struct bnx2x_phy *phy;
6010 params->num_phys = 0;
6011 DP(NETIF_MSG_LINK, "Begin phy probe\n");
6012
6013 for (phy_index = INT_PHY; phy_index < MAX_PHYS;
6014 phy_index++) {
6015 link_cfg_idx = LINK_CONFIG_IDX(phy_index);
6016 actual_phy_idx = phy_index;
6017
6018 phy = &params->phy[actual_phy_idx];
6019 if (bnx2x_populate_phy(bp, phy_index, params->shmem_base,
6020 params->port,
6021 phy) != 0) {
6022 params->num_phys = 0;
6023 DP(NETIF_MSG_LINK, "phy probe failed in phy index %d\n",
6024 phy_index);
6025 for (phy_index = INT_PHY;
6026 phy_index < MAX_PHYS;
6027 phy_index++)
6028 *phy = phy_null;
6029 return -EINVAL;
6030 }
6031 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)
6032 break;
6033
6034 bnx2x_phy_def_cfg(params, phy, actual_phy_idx);
6035 params->num_phys++;
6036 }
6037
6038 DP(NETIF_MSG_LINK, "End phy probe. #phys found %x\n", params->num_phys);
6039 return 0;
6040}
6041
6042u32 bnx2x_supported_attr(struct link_params *params, u8 phy_idx)
6043{
6044 if (phy_idx < params->num_phys)
6045 return params->phy[phy_idx].supported;
6046 return 0;
6047}
6048
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006049static void set_phy_vars(struct link_params *params)
6050{
6051 struct bnx2x *bp = params->bp;
6052 u8 actual_phy_idx, phy_index;
6053
6054 for (phy_index = INT_PHY; phy_index < params->num_phys;
6055 phy_index++) {
6056
6057 actual_phy_idx = phy_index;
6058 params->phy[actual_phy_idx].req_flow_ctrl =
6059 params->req_flow_ctrl;
6060
6061 params->phy[actual_phy_idx].req_line_speed =
6062 params->req_line_speed;
6063
6064 params->phy[actual_phy_idx].speed_cap_mask =
6065 params->speed_cap_mask;
6066
6067 params->phy[actual_phy_idx].req_duplex =
6068 params->req_duplex;
6069
6070 DP(NETIF_MSG_LINK, "req_flow_ctrl %x, req_line_speed %x,"
6071 " speed_cap_mask %x\n",
6072 params->phy[actual_phy_idx].req_flow_ctrl,
6073 params->phy[actual_phy_idx].req_line_speed,
6074 params->phy[actual_phy_idx].speed_cap_mask);
6075 }
6076}
6077
6078u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
6079{
6080 struct bnx2x *bp = params->bp;
6081 u32 val;
6082
6083 DP(NETIF_MSG_LINK, "Phy Initialization started\n");
6084 DP(NETIF_MSG_LINK, "req_speed %d, req_flowctrl %d\n",
6085 params->req_line_speed, params->req_flow_ctrl);
6086 vars->link_status = 0;
6087 vars->phy_link_up = 0;
6088 vars->link_up = 0;
6089 vars->line_speed = 0;
6090 vars->duplex = DUPLEX_FULL;
6091 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
6092 vars->mac_type = MAC_TYPE_NONE;
6093 vars->phy_flags = 0;
6094
6095 /* disable attentions */
6096 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4,
6097 (NIG_MASK_XGXS0_LINK_STATUS |
6098 NIG_MASK_XGXS0_LINK10G |
6099 NIG_MASK_SERDES0_LINK_STATUS |
6100 NIG_MASK_MI_INT));
6101
6102 bnx2x_emac_init(params, vars);
6103
6104 if (params->num_phys == 0) {
6105 DP(NETIF_MSG_LINK, "No phy found for initialization !!\n");
6106 return -EINVAL;
6107 }
6108 set_phy_vars(params);
6109
6110 DP(NETIF_MSG_LINK, "Num of phys on board: %d\n", params->num_phys);
6111 if (CHIP_REV_IS_FPGA(bp)) {
6112
6113 vars->link_up = 1;
6114 vars->line_speed = SPEED_10000;
6115 vars->duplex = DUPLEX_FULL;
6116 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
6117 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
6118 /* enable on E1.5 FPGA */
6119 if (CHIP_IS_E1H(bp)) {
6120 vars->flow_ctrl |=
6121 (BNX2X_FLOW_CTRL_TX |
6122 BNX2X_FLOW_CTRL_RX);
6123 vars->link_status |=
6124 (LINK_STATUS_TX_FLOW_CONTROL_ENABLED |
6125 LINK_STATUS_RX_FLOW_CONTROL_ENABLED);
6126 }
6127
6128 bnx2x_emac_enable(params, vars, 0);
6129 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
6130 /* disable drain */
6131 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
6132
6133 /* update shared memory */
6134 bnx2x_update_mng(params, vars->link_status);
6135
6136 return 0;
6137
6138 } else
6139 if (CHIP_REV_IS_EMUL(bp)) {
6140
6141 vars->link_up = 1;
6142 vars->line_speed = SPEED_10000;
6143 vars->duplex = DUPLEX_FULL;
6144 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
6145 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
6146
6147 bnx2x_bmac_enable(params, vars, 0);
6148
6149 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
6150 /* Disable drain */
6151 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
6152 + params->port*4, 0);
6153
6154 /* update shared memory */
6155 bnx2x_update_mng(params, vars->link_status);
6156
6157 return 0;
6158
6159 } else
6160 if (params->loopback_mode == LOOPBACK_BMAC) {
6161
6162 vars->link_up = 1;
6163 vars->line_speed = SPEED_10000;
6164 vars->duplex = DUPLEX_FULL;
6165 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
6166 vars->mac_type = MAC_TYPE_BMAC;
6167
6168 vars->phy_flags = PHY_XGXS_FLAG;
6169
6170 bnx2x_xgxs_deassert(params);
6171
6172 /* set bmac loopback */
6173 bnx2x_bmac_enable(params, vars, 1);
6174
6175 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
6176 params->port*4, 0);
6177
6178 } else if (params->loopback_mode == LOOPBACK_EMAC) {
6179
6180 vars->link_up = 1;
6181 vars->line_speed = SPEED_1000;
6182 vars->duplex = DUPLEX_FULL;
6183 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
6184 vars->mac_type = MAC_TYPE_EMAC;
6185
6186 vars->phy_flags = PHY_XGXS_FLAG;
6187
6188 bnx2x_xgxs_deassert(params);
6189 /* set bmac loopback */
6190 bnx2x_emac_enable(params, vars, 1);
6191 bnx2x_emac_program(params, vars);
6192 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
6193 params->port*4, 0);
6194
6195 } else if ((params->loopback_mode == LOOPBACK_XGXS) ||
6196 (params->loopback_mode == LOOPBACK_EXT_PHY)) {
6197
6198 vars->link_up = 1;
6199 vars->line_speed = SPEED_10000;
6200 vars->duplex = DUPLEX_FULL;
6201 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
6202
6203 vars->phy_flags = PHY_XGXS_FLAG;
6204
6205 val = REG_RD(bp,
6206 NIG_REG_XGXS0_CTRL_PHY_ADDR+
6207 params->port*0x18);
6208
6209 bnx2x_xgxs_deassert(params);
6210 bnx2x_link_initialize(params, vars);
6211
6212 vars->mac_type = MAC_TYPE_BMAC;
6213
6214 bnx2x_bmac_enable(params, vars, 0);
6215
6216 if (params->loopback_mode == LOOPBACK_XGXS) {
6217 /* set 10G XGXS loopback */
6218 params->phy[INT_PHY].config_loopback(
6219 &params->phy[INT_PHY],
6220 params);
6221
6222 } else {
6223 /* set external phy loopback */
6224 u8 phy_index;
6225 for (phy_index = EXT_PHY1;
6226 phy_index < params->num_phys; phy_index++) {
6227 if (params->phy[phy_index].config_loopback)
6228 params->phy[phy_index].config_loopback(
6229 &params->phy[phy_index],
6230 params);
6231 }
6232 }
6233
6234 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
6235 params->port*4, 0);
6236
6237 bnx2x_set_led(params, LED_MODE_OPER, vars->line_speed);
6238 } else
6239 /* No loopback */
6240 {
6241 if (params->switch_cfg == SWITCH_CFG_10G)
6242 bnx2x_xgxs_deassert(params);
6243 else
6244 bnx2x_serdes_deassert(bp, params->port);
6245 bnx2x_link_initialize(params, vars);
6246 msleep(30);
6247 bnx2x_link_int_enable(params);
6248 }
6249 return 0;
6250}
6251u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
6252 u8 reset_ext_phy)
6253{
6254 struct bnx2x *bp = params->bp;
6255 u8 phy_index, port = params->port;
6256 DP(NETIF_MSG_LINK, "Resetting the link of port %d\n", port);
6257 /* disable attentions */
6258 vars->link_status = 0;
6259 bnx2x_update_mng(params, vars->link_status);
6260 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
6261 (NIG_MASK_XGXS0_LINK_STATUS |
6262 NIG_MASK_XGXS0_LINK10G |
6263 NIG_MASK_SERDES0_LINK_STATUS |
6264 NIG_MASK_MI_INT));
6265
6266 /* activate nig drain */
6267 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
6268
6269 /* disable nig egress interface */
6270 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
6271 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
6272
6273 /* Stop BigMac rx */
6274 bnx2x_bmac_rx_disable(bp, port);
6275
6276 /* disable emac */
6277 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
6278
6279 msleep(10);
6280 /* The PHY reset is controled by GPIO 1
6281 * Hold it as vars low
6282 */
6283 /* clear link led */
6284 bnx2x_set_led(params, LED_MODE_OFF, 0);
6285 if (reset_ext_phy) {
6286 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
6287 phy_index++) {
6288 if (params->phy[phy_index].link_reset)
6289 params->phy[phy_index].link_reset(
6290 &params->phy[phy_index],
6291 params);
6292 }
6293 }
6294
6295 if (params->phy[INT_PHY].link_reset)
6296 params->phy[INT_PHY].link_reset(
6297 &params->phy[INT_PHY], params);
6298 /* reset BigMac */
6299 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
6300 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
6301
6302 /* disable nig ingress interface */
6303 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0);
6304 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0);
6305 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
6306 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
6307 vars->link_up = 0;
6308 return 0;
6309}
6310
6311/****************************************************************************/
6312/* Common function */
6313/****************************************************************************/
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006314static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base)
6315{
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006316 struct bnx2x_phy phy[PORT_MAX];
6317 struct bnx2x_phy *phy_blk[PORT_MAX];
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006318 u16 val;
6319 s8 port;
6320
6321 /* PART1 - Reset both phys */
6322 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
6323 /* Extract the ext phy address for the port */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006324 if (bnx2x_populate_phy(bp, EXT_PHY1, shmem_base,
6325 port, &phy[port]) !=
6326 0) {
6327 DP(NETIF_MSG_LINK, "populate_phy failed\n");
6328 return -EINVAL;
6329 }
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006330 /* disable attentions */
6331 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
6332 (NIG_MASK_XGXS0_LINK_STATUS |
6333 NIG_MASK_XGXS0_LINK10G |
6334 NIG_MASK_SERDES0_LINK_STATUS |
6335 NIG_MASK_MI_INT));
6336
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006337 /* Need to take the phy out of low power mode in order
6338 to write to access its registers */
6339 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
6340 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
6341
6342 /* Reset the phy */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006343 bnx2x_cl45_write(bp, &phy[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006344 MDIO_PMA_DEVAD,
6345 MDIO_PMA_REG_CTRL,
6346 1<<15);
6347 }
6348
6349 /* Add delay of 150ms after reset */
6350 msleep(150);
6351
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006352 if (phy[PORT_0].addr & 0x1) {
6353 phy_blk[PORT_0] = &(phy[PORT_1]);
6354 phy_blk[PORT_1] = &(phy[PORT_0]);
6355 } else {
6356 phy_blk[PORT_0] = &(phy[PORT_0]);
6357 phy_blk[PORT_1] = &(phy[PORT_1]);
6358 }
6359
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006360 /* PART2 - Download firmware to both phys */
6361 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
6362 u16 fw_ver1;
6363
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006364 bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port],
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00006365 port);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006366
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006367 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006368 MDIO_PMA_DEVAD,
6369 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
Eilon Greenstein16b311c2009-01-14 06:44:24 +00006370 if (fw_ver1 == 0 || fw_ver1 == 0x4321) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006371 DP(NETIF_MSG_LINK,
Eilon Greenstein16b311c2009-01-14 06:44:24 +00006372 "bnx2x_8073_common_init_phy port %x:"
6373 "Download failed. fw version = 0x%x\n",
6374 port, fw_ver1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006375 return -EINVAL;
6376 }
6377
6378 /* Only set bit 10 = 1 (Tx power down) */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006379 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006380 MDIO_PMA_DEVAD,
6381 MDIO_PMA_REG_TX_POWER_DOWN, &val);
6382
6383 /* Phase1 of TX_POWER_DOWN reset */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006384 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006385 MDIO_PMA_DEVAD,
6386 MDIO_PMA_REG_TX_POWER_DOWN,
6387 (val | 1<<10));
6388 }
6389
6390 /* Toggle Transmitter: Power down and then up with 600ms
6391 delay between */
6392 msleep(600);
6393
6394 /* PART3 - complete TX_POWER_DOWN process, and set GPIO2 back to low */
6395 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Eilon Greensteinf5372252009-02-12 08:38:30 +00006396 /* Phase2 of POWER_DOWN_RESET */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006397 /* Release bit 10 (Release Tx power down) */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006398 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006399 MDIO_PMA_DEVAD,
6400 MDIO_PMA_REG_TX_POWER_DOWN, &val);
6401
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006402 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006403 MDIO_PMA_DEVAD,
6404 MDIO_PMA_REG_TX_POWER_DOWN, (val & (~(1<<10))));
6405 msleep(15);
6406
6407 /* Read modify write the SPI-ROM version select register */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006408 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006409 MDIO_PMA_DEVAD,
6410 MDIO_PMA_REG_EDC_FFE_MAIN, &val);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006411 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006412 MDIO_PMA_DEVAD,
6413 MDIO_PMA_REG_EDC_FFE_MAIN, (val | (1<<12)));
6414
6415 /* set GPIO2 back to LOW */
6416 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
6417 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
6418 }
6419 return 0;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006420}
6421
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006422static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp, u32 shmem_base)
6423{
6424 u32 val;
6425 s8 port;
6426 struct bnx2x_phy phy;
6427 /* Use port1 because of the static port-swap */
6428 /* Enable the module detection interrupt */
6429 val = REG_RD(bp, MISC_REG_GPIO_EVENT_EN);
6430 val |= ((1<<MISC_REGISTERS_GPIO_3)|
6431 (1<<(MISC_REGISTERS_GPIO_3 + MISC_REGISTERS_GPIO_PORT_SHIFT)));
6432 REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val);
6433
6434 bnx2x_ext_phy_hw_reset(bp, 1);
6435 msleep(5);
6436 for (port = 0; port < PORT_MAX; port++) {
6437 /* Extract the ext phy address for the port */
6438 if (bnx2x_populate_phy(bp, EXT_PHY1, shmem_base,
6439 port, &phy) !=
6440 0) {
6441 DP(NETIF_MSG_LINK, "populate phy failed\n");
6442 return -EINVAL;
6443 }
6444
6445 /* Reset phy*/
6446 bnx2x_cl45_write(bp, &phy,
6447 MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, 0x0001);
6448
6449
6450 /* Set fault module detected LED on */
6451 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
6452 MISC_REGISTERS_GPIO_HIGH,
6453 port);
6454 }
6455
6456 return 0;
6457}
6458
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006459static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base)
6460{
Eilon Greensteinbc7f0a02009-08-12 08:23:01 +00006461 s8 port, first_port, i;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006462 u32 swap_val, swap_override;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006463 struct bnx2x_phy phy[PORT_MAX];
6464 struct bnx2x_phy *phy_blk[PORT_MAX];
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006465 DP(NETIF_MSG_LINK, "Executing BCM8727 common init\n");
6466 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
6467 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
6468
Eilon Greensteinf57a6022009-08-12 08:23:11 +00006469 bnx2x_ext_phy_hw_reset(bp, 1 ^ (swap_val && swap_override));
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006470 msleep(5);
6471
Eilon Greensteinbc7f0a02009-08-12 08:23:01 +00006472 if (swap_val && swap_override)
6473 first_port = PORT_0;
6474 else
6475 first_port = PORT_1;
6476
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006477 /* PART1 - Reset both phys */
Eilon Greensteinbc7f0a02009-08-12 08:23:01 +00006478 for (i = 0, port = first_port; i < PORT_MAX; i++, port = !port) {
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006479 /* Extract the ext phy address for the port */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006480 if (bnx2x_populate_phy(bp, EXT_PHY1, shmem_base,
6481 port, &phy[port]) !=
6482 0) {
6483 DP(NETIF_MSG_LINK, "populate phy failed\n");
6484 return -EINVAL;
6485 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006486 /* disable attentions */
6487 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
6488 (NIG_MASK_XGXS0_LINK_STATUS |
6489 NIG_MASK_XGXS0_LINK10G |
6490 NIG_MASK_SERDES0_LINK_STATUS |
6491 NIG_MASK_MI_INT));
6492
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006493
6494 /* Reset the phy */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006495 bnx2x_cl45_write(bp, &phy[port],
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006496 MDIO_PMA_DEVAD,
6497 MDIO_PMA_REG_CTRL,
6498 1<<15);
6499 }
6500
6501 /* Add delay of 150ms after reset */
6502 msleep(150);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006503 if (phy[PORT_0].addr & 0x1) {
6504 phy_blk[PORT_0] = &(phy[PORT_1]);
6505 phy_blk[PORT_1] = &(phy[PORT_0]);
6506 } else {
6507 phy_blk[PORT_0] = &(phy[PORT_0]);
6508 phy_blk[PORT_1] = &(phy[PORT_1]);
6509 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006510 /* PART2 - Download firmware to both phys */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006511 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006512 u16 fw_ver1;
6513
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006514 bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port],
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00006515 port);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006516 bnx2x_cl45_read(bp, phy_blk[port],
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006517 MDIO_PMA_DEVAD,
6518 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
6519 if (fw_ver1 == 0 || fw_ver1 == 0x4321) {
6520 DP(NETIF_MSG_LINK,
Eilon Greensteinbc7f0a02009-08-12 08:23:01 +00006521 "bnx2x_8727_common_init_phy port %x:"
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006522 "Download failed. fw version = 0x%x\n",
6523 port, fw_ver1);
6524 return -EINVAL;
6525 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006526 }
6527
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006528 return 0;
6529}
6530
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006531u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base)
6532{
6533 u8 rc = 0;
6534 u32 ext_phy_type;
6535
Eilon Greensteinf5372252009-02-12 08:38:30 +00006536 DP(NETIF_MSG_LINK, "Begin common phy init\n");
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006537
6538 /* Read the ext_phy_type for arbitrary port(0) */
6539 ext_phy_type = XGXS_EXT_PHY_TYPE(
6540 REG_RD(bp, shmem_base +
6541 offsetof(struct shmem_region,
6542 dev_info.port_hw_config[0].external_phy_config)));
6543
6544 switch (ext_phy_type) {
6545 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
6546 {
6547 rc = bnx2x_8073_common_init_phy(bp, shmem_base);
6548 break;
6549 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006550
6551 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
6552 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
6553 rc = bnx2x_8727_common_init_phy(bp, shmem_base);
6554 break;
6555
Eilon Greenstein589abe32009-02-12 08:36:55 +00006556 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
6557 /* GPIO1 affects both ports, so there's need to pull
6558 it for single port alone */
6559 rc = bnx2x_8726_common_init_phy(bp, shmem_base);
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02006560 break;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006561 default:
6562 DP(NETIF_MSG_LINK,
6563 "bnx2x_common_init_phy: ext_phy 0x%x not required\n",
6564 ext_phy_type);
6565 break;
6566 }
6567
6568 return rc;
6569}
6570
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00006571
6572u8 bnx2x_hw_lock_required(struct bnx2x *bp, u32 shmem_base)
6573{
6574 u8 phy_index;
6575 struct bnx2x_phy phy;
6576 for (phy_index = INT_PHY; phy_index < MAX_PHYS;
6577 phy_index++) {
6578 if (bnx2x_populate_phy(bp, phy_index, shmem_base,
6579 0, &phy) != 0) {
6580 DP(NETIF_MSG_LINK, "populate phy failed\n");
6581 return 0;
6582 }
6583
6584 if (phy.flags & FLAGS_HW_LOCK_REQUIRED)
6585 return 1;
6586 }
6587 return 0;
6588}
6589
6590u8 bnx2x_fan_failure_det_req(struct bnx2x *bp,
6591 u32 shmem_base,
6592 u8 port)
6593{
6594 u8 phy_index, fan_failure_det_req = 0;
6595 struct bnx2x_phy phy;
6596 for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
6597 phy_index++) {
6598 if (bnx2x_populate_phy(bp, phy_index, shmem_base,
6599 port, &phy)
6600 != 0) {
6601 DP(NETIF_MSG_LINK, "populate phy failed\n");
6602 return 0;
6603 }
6604 fan_failure_det_req |= (phy.flags &
6605 FLAGS_FAN_FAILURE_DET_REQ);
6606 }
6607 return fan_failure_det_req;
6608}
6609
6610void bnx2x_hw_reset_phy(struct link_params *params)
6611{
6612 u8 phy_index;
6613 for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
6614 phy_index++) {
6615 if (params->phy[phy_index].hw_reset) {
6616 params->phy[phy_index].hw_reset(
6617 &params->phy[phy_index],
6618 params);
6619 params->phy[phy_index] = phy_null;
6620 }
6621 }
6622}