blob: 3e99bf9c42b9a83ae18437538f42322e38413d28 [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
Dmitry Kravkov523224a2010-10-06 03:23:26 +000031#define ETH_OVREHEAD (ETH_HLEN + 8 + 8)/* 16 for CRC + VLAN + LLC */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070032#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
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000380static void bnx2x_update_bmac2(struct link_params *params,
381 struct link_vars *vars,
382 u8 is_lb)
383{
384 /*
385 * Set rx control: Strip CRC and enable BigMAC to relay
386 * control packets to the system as well
387 */
388 u32 wb_data[2];
389 struct bnx2x *bp = params->bp;
390 u32 bmac_addr = params->port ? NIG_REG_INGRESS_BMAC1_MEM :
391 NIG_REG_INGRESS_BMAC0_MEM;
392 u32 val = 0x14;
393
394 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
395 /* Enable BigMAC to react on received Pause packets */
396 val |= (1<<5);
397 wb_data[0] = val;
398 wb_data[1] = 0;
399 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_CONTROL,
400 wb_data, 2);
401 udelay(30);
402
403 /* Tx control */
404 val = 0xc0;
405 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
406 val |= 0x800000;
407 wb_data[0] = val;
408 wb_data[1] = 0;
409 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_CONTROL,
410 wb_data, 2);
411
412 val = 0x8000;
413 wb_data[0] = val;
414 wb_data[1] = 0;
415 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_PAUSE_CONTROL,
416 wb_data, 2);
417
418 /* mac control */
419 val = 0x3; /* Enable RX and TX */
420 if (is_lb) {
421 val |= 0x4; /* Local loopback */
422 DP(NETIF_MSG_LINK, "enable bmac loopback\n");
423 }
424
425 wb_data[0] = val;
426 wb_data[1] = 0;
427 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_BMAC_CONTROL,
428 wb_data, 2);
429}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700430
431
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000432static u8 bnx2x_bmac1_enable(struct link_params *params,
433 struct link_vars *vars,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700434 u8 is_lb)
435{
436 struct bnx2x *bp = params->bp;
437 u8 port = params->port;
438 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
439 NIG_REG_INGRESS_BMAC0_MEM;
440 u32 wb_data[2];
441 u32 val;
442
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000443 DP(NETIF_MSG_LINK, "Enabling BigMAC1\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700444
445 /* XGXS control */
446 wb_data[0] = 0x3c;
447 wb_data[1] = 0;
448 REG_WR_DMAE(bp, bmac_addr +
449 BIGMAC_REGISTER_BMAC_XGXS_CONTROL,
450 wb_data, 2);
451
452 /* tx MAC SA */
453 wb_data[0] = ((params->mac_addr[2] << 24) |
454 (params->mac_addr[3] << 16) |
455 (params->mac_addr[4] << 8) |
456 params->mac_addr[5]);
457 wb_data[1] = ((params->mac_addr[0] << 8) |
458 params->mac_addr[1]);
459 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_SOURCE_ADDR,
460 wb_data, 2);
461
462 /* tx control */
463 val = 0xc0;
David S. Millerc0700f92008-12-16 23:53:20 -0800464 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700465 val |= 0x800000;
466 wb_data[0] = val;
467 wb_data[1] = 0;
468 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_CONTROL,
469 wb_data, 2);
470
471 /* mac control */
472 val = 0x3;
473 if (is_lb) {
474 val |= 0x4;
475 DP(NETIF_MSG_LINK, "enable bmac loopback\n");
476 }
477 wb_data[0] = val;
478 wb_data[1] = 0;
479 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
480 wb_data, 2);
481
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700482 /* set rx mtu */
483 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
484 wb_data[1] = 0;
485 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_MAX_SIZE,
486 wb_data, 2);
487
488 /* rx control set to don't strip crc */
489 val = 0x14;
David S. Millerc0700f92008-12-16 23:53:20 -0800490 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700491 val |= 0x20;
492 wb_data[0] = val;
493 wb_data[1] = 0;
494 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_CONTROL,
495 wb_data, 2);
496
497 /* set tx mtu */
498 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
499 wb_data[1] = 0;
500 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_MAX_SIZE,
501 wb_data, 2);
502
503 /* set cnt max size */
504 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
505 wb_data[1] = 0;
506 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_CNT_MAX_SIZE,
507 wb_data, 2);
508
509 /* configure safc */
510 wb_data[0] = 0x1000200;
511 wb_data[1] = 0;
512 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_LLFC_MSG_FLDS,
513 wb_data, 2);
514 /* fix for emulation */
515 if (CHIP_REV_IS_EMUL(bp)) {
516 wb_data[0] = 0xf000;
517 wb_data[1] = 0;
518 REG_WR_DMAE(bp,
519 bmac_addr + BIGMAC_REGISTER_TX_PAUSE_THRESHOLD,
520 wb_data, 2);
521 }
522
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000523
524 return 0;
525}
526
527static u8 bnx2x_bmac2_enable(struct link_params *params,
528 struct link_vars *vars,
529 u8 is_lb)
530{
531 struct bnx2x *bp = params->bp;
532 u8 port = params->port;
533 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
534 NIG_REG_INGRESS_BMAC0_MEM;
535 u32 wb_data[2];
536
537 DP(NETIF_MSG_LINK, "Enabling BigMAC2\n");
538
539 wb_data[0] = 0;
540 wb_data[1] = 0;
541 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_BMAC_CONTROL,
542 wb_data, 2);
543 udelay(30);
544
545 /* XGXS control: Reset phy HW, MDIO registers, PHY PLL and BMAC */
546 wb_data[0] = 0x3c;
547 wb_data[1] = 0;
548 REG_WR_DMAE(bp, bmac_addr +
549 BIGMAC2_REGISTER_BMAC_XGXS_CONTROL,
550 wb_data, 2);
551
552 udelay(30);
553
554 /* tx MAC SA */
555 wb_data[0] = ((params->mac_addr[2] << 24) |
556 (params->mac_addr[3] << 16) |
557 (params->mac_addr[4] << 8) |
558 params->mac_addr[5]);
559 wb_data[1] = ((params->mac_addr[0] << 8) |
560 params->mac_addr[1]);
561 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_SOURCE_ADDR,
562 wb_data, 2);
563
564 udelay(30);
565
566 /* Configure SAFC */
567 wb_data[0] = 0x1000200;
568 wb_data[1] = 0;
569 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_LLFC_MSG_FLDS,
570 wb_data, 2);
571 udelay(30);
572
573 /* set rx mtu */
574 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
575 wb_data[1] = 0;
576 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_MAX_SIZE,
577 wb_data, 2);
578 udelay(30);
579
580 /* set tx mtu */
581 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
582 wb_data[1] = 0;
583 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_MAX_SIZE,
584 wb_data, 2);
585 udelay(30);
586 /* set cnt max size */
587 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD - 2;
588 wb_data[1] = 0;
589 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_CNT_MAX_SIZE,
590 wb_data, 2);
591 udelay(30);
592 bnx2x_update_bmac2(params, vars, is_lb);
593
594 return 0;
595}
596
597u8 bnx2x_bmac_enable(struct link_params *params,
598 struct link_vars *vars,
599 u8 is_lb)
600{
601 u8 rc, port = params->port;
602 struct bnx2x *bp = params->bp;
603 u32 val;
604 /* reset and unreset the BigMac */
605 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
606 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
607 udelay(10);
608
609 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
610 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
611
612 /* enable access for bmac registers */
613 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
614
615 /* Enable BMAC according to BMAC type*/
616 if (CHIP_IS_E2(bp))
617 rc = bnx2x_bmac2_enable(params, vars, is_lb);
618 else
619 rc = bnx2x_bmac1_enable(params, vars, is_lb);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700620 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0x1);
621 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 0x0);
622 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 0x0);
623 val = 0;
David S. Millerc0700f92008-12-16 23:53:20 -0800624 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700625 val = 1;
626 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, val);
627 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x0);
628 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x0);
629 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, 0x0);
630 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x1);
631 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x1);
632
633 vars->mac_type = MAC_TYPE_BMAC;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000634 return rc;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700635}
636
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700637
638static void bnx2x_update_mng(struct link_params *params, u32 link_status)
639{
640 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +0000641
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700642 REG_WR(bp, params->shmem_base +
643 offsetof(struct shmem_region,
644 port_mb[params->port].link_status),
645 link_status);
646}
647
648static void bnx2x_bmac_rx_disable(struct bnx2x *bp, u8 port)
649{
650 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
651 NIG_REG_INGRESS_BMAC0_MEM;
652 u32 wb_data[2];
Eilon Greenstein3196a882008-08-13 15:58:49 -0700653 u32 nig_bmac_enable = REG_RD(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700654
655 /* Only if the bmac is out of reset */
656 if (REG_RD(bp, MISC_REG_RESET_REG_2) &
657 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port) &&
658 nig_bmac_enable) {
659
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000660 if (CHIP_IS_E2(bp)) {
661 /* Clear Rx Enable bit in BMAC_CONTROL register */
662 REG_RD_DMAE(bp, bmac_addr +
663 BIGMAC2_REGISTER_BMAC_CONTROL,
664 wb_data, 2);
665 wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
666 REG_WR_DMAE(bp, bmac_addr +
667 BIGMAC2_REGISTER_BMAC_CONTROL,
668 wb_data, 2);
669 } else {
670 /* Clear Rx Enable bit in BMAC_CONTROL register */
671 REG_RD_DMAE(bp, bmac_addr +
672 BIGMAC_REGISTER_BMAC_CONTROL,
673 wb_data, 2);
674 wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
675 REG_WR_DMAE(bp, bmac_addr +
676 BIGMAC_REGISTER_BMAC_CONTROL,
677 wb_data, 2);
678 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700679 msleep(1);
680 }
681}
682
683static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl,
684 u32 line_speed)
685{
686 struct bnx2x *bp = params->bp;
687 u8 port = params->port;
688 u32 init_crd, crd;
689 u32 count = 1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700690
691 /* disable port */
692 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x1);
693
694 /* wait for init credit */
695 init_crd = REG_RD(bp, PBF_REG_P0_INIT_CRD + port*4);
696 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
697 DP(NETIF_MSG_LINK, "init_crd 0x%x crd 0x%x\n", init_crd, crd);
698
699 while ((init_crd != crd) && count) {
700 msleep(5);
701
702 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
703 count--;
704 }
705 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
706 if (init_crd != crd) {
707 DP(NETIF_MSG_LINK, "BUG! init_crd 0x%x != crd 0x%x\n",
708 init_crd, crd);
709 return -EINVAL;
710 }
711
David S. Millerc0700f92008-12-16 23:53:20 -0800712 if (flow_ctrl & BNX2X_FLOW_CTRL_RX ||
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700713 line_speed == SPEED_10 ||
714 line_speed == SPEED_100 ||
715 line_speed == SPEED_1000 ||
716 line_speed == SPEED_2500) {
717 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700718 /* update threshold */
719 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, 0);
720 /* update init credit */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700721 init_crd = 778; /* (800-18-4) */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700722
723 } else {
724 u32 thresh = (ETH_MAX_JUMBO_PACKET_SIZE +
725 ETH_OVREHEAD)/16;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700726 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700727 /* update threshold */
728 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, thresh);
729 /* update init credit */
730 switch (line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700731 case SPEED_10000:
732 init_crd = thresh + 553 - 22;
733 break;
734
735 case SPEED_12000:
736 init_crd = thresh + 664 - 22;
737 break;
738
739 case SPEED_13000:
740 init_crd = thresh + 742 - 22;
741 break;
742
743 case SPEED_16000:
744 init_crd = thresh + 778 - 22;
745 break;
746 default:
747 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
748 line_speed);
749 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700750 }
751 }
752 REG_WR(bp, PBF_REG_P0_INIT_CRD + port*4, init_crd);
753 DP(NETIF_MSG_LINK, "PBF updated to speed %d credit %d\n",
754 line_speed, init_crd);
755
756 /* probe the credit changes */
757 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x1);
758 msleep(5);
759 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x0);
760
761 /* enable port */
762 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x0);
763 return 0;
764}
765
Yaniv Rosnerc18aa152010-09-07 11:41:07 +0000766static u32 bnx2x_get_emac_base(struct bnx2x *bp,
767 u32 mdc_mdio_access, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700768{
Yaniv Rosnerc18aa152010-09-07 11:41:07 +0000769 u32 emac_base = 0;
770 switch (mdc_mdio_access) {
771 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_PHY_TYPE:
772 break;
773 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC0:
774 if (REG_RD(bp, NIG_REG_PORT_SWAP))
775 emac_base = GRCBASE_EMAC1;
776 else
777 emac_base = GRCBASE_EMAC0;
778 break;
779 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1:
Eilon Greenstein589abe32009-02-12 08:36:55 +0000780 if (REG_RD(bp, NIG_REG_PORT_SWAP))
781 emac_base = GRCBASE_EMAC0;
782 else
783 emac_base = GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700784 break;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +0000785 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH:
786 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
787 break;
788 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_SWAPPED:
Eilon Greenstein6378c022008-08-13 15:59:25 -0700789 emac_base = (port) ? GRCBASE_EMAC0 : GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700790 break;
791 default:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700792 break;
793 }
794 return emac_base;
795
796}
797
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000798u8 bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy,
799 u8 devad, u16 reg, u16 val)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700800{
801 u32 tmp, saved_mode;
802 u8 i, rc = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700803
804 /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
805 * (a value of 49==0x31) and make sure that the AUTO poll is off
806 */
Eilon Greenstein589abe32009-02-12 08:36:55 +0000807
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000808 saved_mode = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700809 tmp = saved_mode & ~(EMAC_MDIO_MODE_AUTO_POLL |
810 EMAC_MDIO_MODE_CLOCK_CNT);
811 tmp |= (EMAC_MDIO_MODE_CLAUSE_45 |
812 (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000813 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, tmp);
814 REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700815 udelay(40);
816
817 /* address */
818
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000819 tmp = ((phy->addr << 21) | (devad << 16) | reg |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700820 EMAC_MDIO_COMM_COMMAND_ADDRESS |
821 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000822 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700823
824 for (i = 0; i < 50; i++) {
825 udelay(10);
826
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000827 tmp = REG_RD(bp, phy->mdio_ctrl +
828 EMAC_REG_EMAC_MDIO_COMM);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700829 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
830 udelay(5);
831 break;
832 }
833 }
834 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
835 DP(NETIF_MSG_LINK, "write phy register failed\n");
836 rc = -EFAULT;
837 } else {
838 /* data */
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000839 tmp = ((phy->addr << 21) | (devad << 16) | val |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700840 EMAC_MDIO_COMM_COMMAND_WRITE_45 |
841 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000842 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700843
844 for (i = 0; i < 50; i++) {
845 udelay(10);
846
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000847 tmp = REG_RD(bp, phy->mdio_ctrl +
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700848 EMAC_REG_EMAC_MDIO_COMM);
849 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
850 udelay(5);
851 break;
852 }
853 }
854 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
855 DP(NETIF_MSG_LINK, "write phy register failed\n");
856 rc = -EFAULT;
857 }
858 }
859
860 /* Restore the saved mode */
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000861 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700862
863 return rc;
864}
865
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000866u8 bnx2x_cl45_read(struct bnx2x *bp, struct bnx2x_phy *phy,
867 u8 devad, u16 reg, u16 *ret_val)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700868{
869 u32 val, saved_mode;
870 u16 i;
871 u8 rc = 0;
872
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700873 /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
874 * (a value of 49==0x31) and make sure that the AUTO poll is off
875 */
Eilon Greenstein589abe32009-02-12 08:36:55 +0000876
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000877 saved_mode = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
878 val = saved_mode & ~((EMAC_MDIO_MODE_AUTO_POLL |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700879 EMAC_MDIO_MODE_CLOCK_CNT));
880 val |= (EMAC_MDIO_MODE_CLAUSE_45 |
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +0000881 (49L << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000882 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, val);
883 REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700884 udelay(40);
885
886 /* address */
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000887 val = ((phy->addr << 21) | (devad << 16) | reg |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700888 EMAC_MDIO_COMM_COMMAND_ADDRESS |
889 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000890 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700891
892 for (i = 0; i < 50; i++) {
893 udelay(10);
894
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000895 val = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700896 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
897 udelay(5);
898 break;
899 }
900 }
901 if (val & EMAC_MDIO_COMM_START_BUSY) {
902 DP(NETIF_MSG_LINK, "read phy register failed\n");
903
904 *ret_val = 0;
905 rc = -EFAULT;
906
907 } else {
908 /* data */
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000909 val = ((phy->addr << 21) | (devad << 16) |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700910 EMAC_MDIO_COMM_COMMAND_READ_45 |
911 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000912 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700913
914 for (i = 0; i < 50; i++) {
915 udelay(10);
916
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000917 val = REG_RD(bp, phy->mdio_ctrl +
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700918 EMAC_REG_EMAC_MDIO_COMM);
919 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
920 *ret_val = (u16)(val & EMAC_MDIO_COMM_DATA);
921 break;
922 }
923 }
924 if (val & EMAC_MDIO_COMM_START_BUSY) {
925 DP(NETIF_MSG_LINK, "read phy register failed\n");
926
927 *ret_val = 0;
928 rc = -EFAULT;
929 }
930 }
931
932 /* Restore the saved mode */
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000933 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700934
935 return rc;
936}
937
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000938u8 bnx2x_phy_read(struct link_params *params, u8 phy_addr,
939 u8 devad, u16 reg, u16 *ret_val)
940{
941 u8 phy_index;
942 /**
943 * Probe for the phy according to the given phy_addr, and execute
944 * the read request on it
945 */
946 for (phy_index = 0; phy_index < params->num_phys; phy_index++) {
947 if (params->phy[phy_index].addr == phy_addr) {
948 return bnx2x_cl45_read(params->bp,
949 &params->phy[phy_index], devad,
950 reg, ret_val);
951 }
952 }
953 return -EINVAL;
954}
955
956u8 bnx2x_phy_write(struct link_params *params, u8 phy_addr,
957 u8 devad, u16 reg, u16 val)
958{
959 u8 phy_index;
960 /**
961 * Probe for the phy according to the given phy_addr, and execute
962 * the write request on it
963 */
964 for (phy_index = 0; phy_index < params->num_phys; phy_index++) {
965 if (params->phy[phy_index].addr == phy_addr) {
966 return bnx2x_cl45_write(params->bp,
967 &params->phy[phy_index], devad,
968 reg, val);
969 }
970 }
971 return -EINVAL;
972}
973
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000974static void bnx2x_set_aer_mmd_xgxs(struct link_params *params,
975 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700976{
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700977 u32 ser_lane;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000978 u16 offset, aer_val;
979 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700980 ser_lane = ((params->lane_config &
981 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
982 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
983
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000984 offset = phy->addr + ser_lane;
985 if (CHIP_IS_E2(bp))
986 aer_val = 0x2800 + offset - 1;
987 else
988 aer_val = 0x3800 + offset;
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000989 CL45_WR_OVER_CL22(bp, phy,
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000990 MDIO_REG_BANK_AER_BLOCK,
991 MDIO_AER_BLOCK_AER_REG, aer_val);
992}
993static void bnx2x_set_aer_mmd_serdes(struct bnx2x *bp,
994 struct bnx2x_phy *phy)
995{
996 CL45_WR_OVER_CL22(bp, phy,
997 MDIO_REG_BANK_AER_BLOCK,
998 MDIO_AER_BLOCK_AER_REG, 0x3800);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700999}
1000
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001001/******************************************************************/
1002/* Internal phy section */
1003/******************************************************************/
1004
1005static void bnx2x_set_serdes_access(struct bnx2x *bp, u8 port)
1006{
1007 u32 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
1008
1009 /* Set Clause 22 */
1010 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + port*0x10, 1);
1011 REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245f8000);
1012 udelay(500);
1013 REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245d000f);
1014 udelay(500);
1015 /* Set Clause 45 */
1016 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + port*0x10, 0);
1017}
1018
1019static void bnx2x_serdes_deassert(struct bnx2x *bp, u8 port)
1020{
1021 u32 val;
1022
1023 DP(NETIF_MSG_LINK, "bnx2x_serdes_deassert\n");
1024
1025 val = SERDES_RESET_BITS << (port*16);
1026
1027 /* reset and unreset the SerDes/XGXS */
1028 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR, val);
1029 udelay(500);
1030 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET, val);
1031
1032 bnx2x_set_serdes_access(bp, port);
1033
1034 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_DEVAD +
1035 port*0x10,
1036 DEFAULT_PHY_DEV_ADDR);
1037}
1038
1039static void bnx2x_xgxs_deassert(struct link_params *params)
1040{
1041 struct bnx2x *bp = params->bp;
1042 u8 port;
1043 u32 val;
1044 DP(NETIF_MSG_LINK, "bnx2x_xgxs_deassert\n");
1045 port = params->port;
1046
1047 val = XGXS_RESET_BITS << (port*16);
1048
1049 /* reset and unreset the SerDes/XGXS */
1050 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR, val);
1051 udelay(500);
1052 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET, val);
1053
1054 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_ST +
1055 port*0x18, 0);
1056 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
1057 params->phy[INT_PHY].def_md_devad);
1058}
1059
Yaniv Rosnera22f0782010-09-07 11:41:20 +00001060
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001061void bnx2x_link_status_update(struct link_params *params,
1062 struct link_vars *vars)
1063{
1064 struct bnx2x *bp = params->bp;
1065 u8 link_10g;
1066 u8 port = params->port;
1067
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001068 vars->link_status = REG_RD(bp, params->shmem_base +
1069 offsetof(struct shmem_region,
1070 port_mb[port].link_status));
1071
1072 vars->link_up = (vars->link_status & LINK_STATUS_LINK_UP);
1073
1074 if (vars->link_up) {
1075 DP(NETIF_MSG_LINK, "phy link up\n");
1076
1077 vars->phy_link_up = 1;
1078 vars->duplex = DUPLEX_FULL;
1079 switch (vars->link_status &
1080 LINK_STATUS_SPEED_AND_DUPLEX_MASK) {
1081 case LINK_10THD:
1082 vars->duplex = DUPLEX_HALF;
1083 /* fall thru */
1084 case LINK_10TFD:
1085 vars->line_speed = SPEED_10;
1086 break;
1087
1088 case LINK_100TXHD:
1089 vars->duplex = DUPLEX_HALF;
1090 /* fall thru */
1091 case LINK_100T4:
1092 case LINK_100TXFD:
1093 vars->line_speed = SPEED_100;
1094 break;
1095
1096 case LINK_1000THD:
1097 vars->duplex = DUPLEX_HALF;
1098 /* fall thru */
1099 case LINK_1000TFD:
1100 vars->line_speed = SPEED_1000;
1101 break;
1102
1103 case LINK_2500THD:
1104 vars->duplex = DUPLEX_HALF;
1105 /* fall thru */
1106 case LINK_2500TFD:
1107 vars->line_speed = SPEED_2500;
1108 break;
1109
1110 case LINK_10GTFD:
1111 vars->line_speed = SPEED_10000;
1112 break;
1113
1114 case LINK_12GTFD:
1115 vars->line_speed = SPEED_12000;
1116 break;
1117
1118 case LINK_12_5GTFD:
1119 vars->line_speed = SPEED_12500;
1120 break;
1121
1122 case LINK_13GTFD:
1123 vars->line_speed = SPEED_13000;
1124 break;
1125
1126 case LINK_15GTFD:
1127 vars->line_speed = SPEED_15000;
1128 break;
1129
1130 case LINK_16GTFD:
1131 vars->line_speed = SPEED_16000;
1132 break;
1133
1134 default:
1135 break;
1136 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001137 vars->flow_ctrl = 0;
1138 if (vars->link_status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED)
1139 vars->flow_ctrl |= BNX2X_FLOW_CTRL_TX;
1140
1141 if (vars->link_status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED)
1142 vars->flow_ctrl |= BNX2X_FLOW_CTRL_RX;
1143
1144 if (!vars->flow_ctrl)
1145 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
1146
1147 if (vars->line_speed &&
1148 ((vars->line_speed == SPEED_10) ||
1149 (vars->line_speed == SPEED_100))) {
1150 vars->phy_flags |= PHY_SGMII_FLAG;
1151 } else {
1152 vars->phy_flags &= ~PHY_SGMII_FLAG;
1153 }
1154
1155 /* anything 10 and over uses the bmac */
1156 link_10g = ((vars->line_speed == SPEED_10000) ||
1157 (vars->line_speed == SPEED_12000) ||
1158 (vars->line_speed == SPEED_12500) ||
1159 (vars->line_speed == SPEED_13000) ||
1160 (vars->line_speed == SPEED_15000) ||
1161 (vars->line_speed == SPEED_16000));
1162 if (link_10g)
1163 vars->mac_type = MAC_TYPE_BMAC;
1164 else
1165 vars->mac_type = MAC_TYPE_EMAC;
1166
1167 } else { /* link down */
1168 DP(NETIF_MSG_LINK, "phy link down\n");
1169
1170 vars->phy_link_up = 0;
1171
1172 vars->line_speed = 0;
1173 vars->duplex = DUPLEX_FULL;
1174 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
1175
1176 /* indicate no mac active */
1177 vars->mac_type = MAC_TYPE_NONE;
1178 }
1179
1180 DP(NETIF_MSG_LINK, "link_status 0x%x phy_link_up %x\n",
1181 vars->link_status, vars->phy_link_up);
1182 DP(NETIF_MSG_LINK, "line_speed %x duplex %x flow_ctrl 0x%x\n",
1183 vars->line_speed, vars->duplex, vars->flow_ctrl);
1184}
1185
1186
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001187static void bnx2x_set_master_ln(struct link_params *params,
1188 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001189{
1190 struct bnx2x *bp = params->bp;
1191 u16 new_master_ln, ser_lane;
1192 ser_lane = ((params->lane_config &
1193 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
1194 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
1195
1196 /* set the master_ln for AN */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001197 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001198 MDIO_REG_BANK_XGXS_BLOCK2,
1199 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
1200 &new_master_ln);
1201
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001202 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001203 MDIO_REG_BANK_XGXS_BLOCK2 ,
1204 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
1205 (new_master_ln | ser_lane));
1206}
1207
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001208static u8 bnx2x_reset_unicore(struct link_params *params,
1209 struct bnx2x_phy *phy,
1210 u8 set_serdes)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001211{
1212 struct bnx2x *bp = params->bp;
1213 u16 mii_control;
1214 u16 i;
1215
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001216 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001217 MDIO_REG_BANK_COMBO_IEEE0,
1218 MDIO_COMBO_IEEE0_MII_CONTROL, &mii_control);
1219
1220 /* reset the unicore */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001221 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001222 MDIO_REG_BANK_COMBO_IEEE0,
1223 MDIO_COMBO_IEEE0_MII_CONTROL,
1224 (mii_control |
1225 MDIO_COMBO_IEEO_MII_CONTROL_RESET));
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001226 if (set_serdes)
1227 bnx2x_set_serdes_access(bp, params->port);
Eilon Greensteinc1b73992009-02-12 08:37:07 +00001228
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001229 /* wait for the reset to self clear */
1230 for (i = 0; i < MDIO_ACCESS_TIMEOUT; i++) {
1231 udelay(5);
1232
1233 /* the reset erased the previous bank value */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001234 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001235 MDIO_REG_BANK_COMBO_IEEE0,
1236 MDIO_COMBO_IEEE0_MII_CONTROL,
1237 &mii_control);
1238
1239 if (!(mii_control & MDIO_COMBO_IEEO_MII_CONTROL_RESET)) {
1240 udelay(5);
1241 return 0;
1242 }
1243 }
1244
1245 DP(NETIF_MSG_LINK, "BUG! XGXS is still in reset!\n");
1246 return -EINVAL;
1247
1248}
1249
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001250static void bnx2x_set_swap_lanes(struct link_params *params,
1251 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001252{
1253 struct bnx2x *bp = params->bp;
1254 /* Each two bits represents a lane number:
1255 No swap is 0123 => 0x1b no need to enable the swap */
1256 u16 ser_lane, rx_lane_swap, tx_lane_swap;
1257
1258 ser_lane = ((params->lane_config &
1259 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
1260 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
1261 rx_lane_swap = ((params->lane_config &
1262 PORT_HW_CFG_LANE_SWAP_CFG_RX_MASK) >>
1263 PORT_HW_CFG_LANE_SWAP_CFG_RX_SHIFT);
1264 tx_lane_swap = ((params->lane_config &
1265 PORT_HW_CFG_LANE_SWAP_CFG_TX_MASK) >>
1266 PORT_HW_CFG_LANE_SWAP_CFG_TX_SHIFT);
1267
1268 if (rx_lane_swap != 0x1b) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001269 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001270 MDIO_REG_BANK_XGXS_BLOCK2,
1271 MDIO_XGXS_BLOCK2_RX_LN_SWAP,
1272 (rx_lane_swap |
1273 MDIO_XGXS_BLOCK2_RX_LN_SWAP_ENABLE |
1274 MDIO_XGXS_BLOCK2_RX_LN_SWAP_FORCE_ENABLE));
1275 } else {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001276 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001277 MDIO_REG_BANK_XGXS_BLOCK2,
1278 MDIO_XGXS_BLOCK2_RX_LN_SWAP, 0);
1279 }
1280
1281 if (tx_lane_swap != 0x1b) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001282 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001283 MDIO_REG_BANK_XGXS_BLOCK2,
1284 MDIO_XGXS_BLOCK2_TX_LN_SWAP,
1285 (tx_lane_swap |
1286 MDIO_XGXS_BLOCK2_TX_LN_SWAP_ENABLE));
1287 } else {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001288 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001289 MDIO_REG_BANK_XGXS_BLOCK2,
1290 MDIO_XGXS_BLOCK2_TX_LN_SWAP, 0);
1291 }
1292}
1293
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001294static void bnx2x_set_parallel_detection(struct bnx2x_phy *phy,
1295 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001296{
1297 struct bnx2x *bp = params->bp;
1298 u16 control2;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001299 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001300 MDIO_REG_BANK_SERDES_DIGITAL,
1301 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
1302 &control2);
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001303 if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
Yaniv Rosner18afb0a2009-11-05 19:18:04 +02001304 control2 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
1305 else
1306 control2 &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001307 DP(NETIF_MSG_LINK, "phy->speed_cap_mask = 0x%x, control2 = 0x%x\n",
1308 phy->speed_cap_mask, control2);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001309 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001310 MDIO_REG_BANK_SERDES_DIGITAL,
1311 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
1312 control2);
1313
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001314 if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00001315 (phy->speed_cap_mask &
Yaniv Rosner18afb0a2009-11-05 19:18:04 +02001316 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001317 DP(NETIF_MSG_LINK, "XGXS\n");
1318
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001319 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001320 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1321 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK,
1322 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT);
1323
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001324 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001325 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1326 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
1327 &control2);
1328
1329
1330 control2 |=
1331 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN;
1332
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001333 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001334 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1335 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
1336 control2);
1337
1338 /* Disable parallel detection of HiG */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001339 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001340 MDIO_REG_BANK_XGXS_BLOCK2,
1341 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G,
1342 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_CX4_XGXS |
1343 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_HIGIG_XGXS);
1344 }
1345}
1346
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001347static void bnx2x_set_autoneg(struct bnx2x_phy *phy,
1348 struct link_params *params,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001349 struct link_vars *vars,
1350 u8 enable_cl73)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001351{
1352 struct bnx2x *bp = params->bp;
1353 u16 reg_val;
1354
1355 /* CL37 Autoneg */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001356 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001357 MDIO_REG_BANK_COMBO_IEEE0,
1358 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
1359
1360 /* CL37 Autoneg Enabled */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001361 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001362 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_AN_EN;
1363 else /* CL37 Autoneg Disabled */
1364 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1365 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN);
1366
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001367 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001368 MDIO_REG_BANK_COMBO_IEEE0,
1369 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
1370
1371 /* Enable/Disable Autodetection */
1372
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001373 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001374 MDIO_REG_BANK_SERDES_DIGITAL,
1375 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, &reg_val);
Eilon Greenstein239d6862009-08-12 08:23:04 +00001376 reg_val &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN |
1377 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT);
1378 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001379 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001380 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
1381 else
1382 reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
1383
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001384 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001385 MDIO_REG_BANK_SERDES_DIGITAL,
1386 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, reg_val);
1387
1388 /* Enable TetonII and BAM autoneg */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001389 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001390 MDIO_REG_BANK_BAM_NEXT_PAGE,
1391 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
1392 &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001393 if (vars->line_speed == SPEED_AUTO_NEG) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001394 /* Enable BAM aneg Mode and TetonII aneg Mode */
1395 reg_val |= (MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
1396 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
1397 } else {
1398 /* TetonII and BAM Autoneg Disabled */
1399 reg_val &= ~(MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
1400 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
1401 }
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001402 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001403 MDIO_REG_BANK_BAM_NEXT_PAGE,
1404 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
1405 reg_val);
1406
Eilon Greenstein239d6862009-08-12 08:23:04 +00001407 if (enable_cl73) {
1408 /* Enable Cl73 FSM status bits */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001409 CL45_WR_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001410 MDIO_REG_BANK_CL73_USERB0,
1411 MDIO_CL73_USERB0_CL73_UCTRL,
Yaniv Rosner7846e472009-11-05 19:18:07 +02001412 0xe);
Eilon Greenstein239d6862009-08-12 08:23:04 +00001413
1414 /* Enable BAM Station Manager*/
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001415 CL45_WR_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001416 MDIO_REG_BANK_CL73_USERB0,
1417 MDIO_CL73_USERB0_CL73_BAM_CTRL1,
1418 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN |
1419 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_STATION_MNGR_EN |
1420 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN);
1421
Yaniv Rosner7846e472009-11-05 19:18:07 +02001422 /* Advertise CL73 link speeds */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001423 CL45_RD_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001424 MDIO_REG_BANK_CL73_IEEEB1,
1425 MDIO_CL73_IEEEB1_AN_ADV2,
1426 &reg_val);
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001427 if (phy->speed_cap_mask &
Yaniv Rosner7846e472009-11-05 19:18:07 +02001428 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
1429 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001430 if (phy->speed_cap_mask &
Yaniv Rosner7846e472009-11-05 19:18:07 +02001431 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
1432 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX;
Eilon Greenstein239d6862009-08-12 08:23:04 +00001433
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001434 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001435 MDIO_REG_BANK_CL73_IEEEB1,
1436 MDIO_CL73_IEEEB1_AN_ADV2,
1437 reg_val);
Eilon Greenstein239d6862009-08-12 08:23:04 +00001438
Eilon Greenstein239d6862009-08-12 08:23:04 +00001439 /* CL73 Autoneg Enabled */
1440 reg_val = MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN;
1441
1442 } else /* CL73 Autoneg Disabled */
1443 reg_val = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001444
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001445 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001446 MDIO_REG_BANK_CL73_IEEEB0,
1447 MDIO_CL73_IEEEB0_CL73_AN_CONTROL, reg_val);
1448}
1449
1450/* program SerDes, forced speed */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001451static void bnx2x_program_serdes(struct bnx2x_phy *phy,
1452 struct link_params *params,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001453 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001454{
1455 struct bnx2x *bp = params->bp;
1456 u16 reg_val;
1457
Eilon Greenstein57937202009-08-12 08:23:53 +00001458 /* program duplex, disable autoneg and sgmii*/
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001459 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001460 MDIO_REG_BANK_COMBO_IEEE0,
1461 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
1462 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX |
Eilon Greenstein57937202009-08-12 08:23:53 +00001463 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1464 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK);
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001465 if (phy->req_duplex == DUPLEX_FULL)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001466 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001467 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001468 MDIO_REG_BANK_COMBO_IEEE0,
1469 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
1470
1471 /* program speed
1472 - needed only if the speed is greater than 1G (2.5G or 10G) */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001473 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001474 MDIO_REG_BANK_SERDES_DIGITAL,
1475 MDIO_SERDES_DIGITAL_MISC1, &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001476 /* clearing the speed value before setting the right speed */
1477 DP(NETIF_MSG_LINK, "MDIO_REG_BANK_SERDES_DIGITAL = 0x%x\n", reg_val);
1478
1479 reg_val &= ~(MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_MASK |
1480 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
1481
1482 if (!((vars->line_speed == SPEED_1000) ||
1483 (vars->line_speed == SPEED_100) ||
1484 (vars->line_speed == SPEED_10))) {
1485
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001486 reg_val |= (MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_156_25M |
1487 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001488 if (vars->line_speed == SPEED_10000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001489 reg_val |=
1490 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_10G_CX4;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001491 if (vars->line_speed == SPEED_13000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001492 reg_val |=
1493 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_13G;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001494 }
1495
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001496 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001497 MDIO_REG_BANK_SERDES_DIGITAL,
1498 MDIO_SERDES_DIGITAL_MISC1, reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001499
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001500}
1501
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001502static void bnx2x_set_brcm_cl37_advertisment(struct bnx2x_phy *phy,
1503 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001504{
1505 struct bnx2x *bp = params->bp;
1506 u16 val = 0;
1507
1508 /* configure the 48 bits for BAM AN */
1509
1510 /* set extended capabilities */
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001511 if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001512 val |= MDIO_OVER_1G_UP1_2_5G;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001513 if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001514 val |= MDIO_OVER_1G_UP1_10G;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001515 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001516 MDIO_REG_BANK_OVER_1G,
1517 MDIO_OVER_1G_UP1, val);
1518
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001519 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001520 MDIO_REG_BANK_OVER_1G,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001521 MDIO_OVER_1G_UP3, 0x400);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001522}
1523
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001524static void bnx2x_calc_ieee_aneg_adv(struct bnx2x_phy *phy,
1525 struct link_params *params, u16 *ieee_fc)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001526{
Yaniv Rosnerd5cb9e92009-11-05 19:18:10 +02001527 struct bnx2x *bp = params->bp;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001528 *ieee_fc = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001529 /* resolve pause mode and advertisement
1530 * Please refer to Table 28B-3 of the 802.3ab-1999 spec */
1531
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001532 switch (phy->req_flow_ctrl) {
David S. Millerc0700f92008-12-16 23:53:20 -08001533 case BNX2X_FLOW_CTRL_AUTO:
1534 if (params->req_fc_auto_adv == BNX2X_FLOW_CTRL_BOTH) {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001535 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001536 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
1537 } else {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001538 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001539 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
1540 }
1541 break;
David S. Millerc0700f92008-12-16 23:53:20 -08001542 case BNX2X_FLOW_CTRL_TX:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001543 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001544 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
1545 break;
1546
David S. Millerc0700f92008-12-16 23:53:20 -08001547 case BNX2X_FLOW_CTRL_RX:
1548 case BNX2X_FLOW_CTRL_BOTH:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001549 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001550 break;
1551
David S. Millerc0700f92008-12-16 23:53:20 -08001552 case BNX2X_FLOW_CTRL_NONE:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001553 default:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001554 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001555 break;
1556 }
Yaniv Rosnerd5cb9e92009-11-05 19:18:10 +02001557 DP(NETIF_MSG_LINK, "ieee_fc = 0x%x\n", *ieee_fc);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001558}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001559
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001560static void bnx2x_set_ieee_aneg_advertisment(struct bnx2x_phy *phy,
1561 struct link_params *params,
Eilon Greenstein1ef70b92009-08-12 08:23:59 +00001562 u16 ieee_fc)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001563{
1564 struct bnx2x *bp = params->bp;
Yaniv Rosner7846e472009-11-05 19:18:07 +02001565 u16 val;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001566 /* for AN, we are always publishing full duplex */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001567
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001568 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001569 MDIO_REG_BANK_COMBO_IEEE0,
Eilon Greenstein1ef70b92009-08-12 08:23:59 +00001570 MDIO_COMBO_IEEE0_AUTO_NEG_ADV, ieee_fc);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001571 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner7846e472009-11-05 19:18:07 +02001572 MDIO_REG_BANK_CL73_IEEEB1,
1573 MDIO_CL73_IEEEB1_AN_ADV1, &val);
1574 val &= ~MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_BOTH;
1575 val |= ((ieee_fc<<3) & MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001576 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosner7846e472009-11-05 19:18:07 +02001577 MDIO_REG_BANK_CL73_IEEEB1,
1578 MDIO_CL73_IEEEB1_AN_ADV1, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001579}
1580
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001581static void bnx2x_restart_autoneg(struct bnx2x_phy *phy,
1582 struct link_params *params,
1583 u8 enable_cl73)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001584{
1585 struct bnx2x *bp = params->bp;
Eilon Greenstein3a36f2e2009-02-12 08:37:09 +00001586 u16 mii_control;
Eilon Greenstein239d6862009-08-12 08:23:04 +00001587
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001588 DP(NETIF_MSG_LINK, "bnx2x_restart_autoneg\n");
Eilon Greenstein3a36f2e2009-02-12 08:37:09 +00001589 /* Enable and restart BAM/CL37 aneg */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001590
Eilon Greenstein239d6862009-08-12 08:23:04 +00001591 if (enable_cl73) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001592 CL45_RD_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001593 MDIO_REG_BANK_CL73_IEEEB0,
1594 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1595 &mii_control);
1596
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001597 CL45_WR_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001598 MDIO_REG_BANK_CL73_IEEEB0,
1599 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1600 (mii_control |
1601 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN |
1602 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN));
1603 } else {
1604
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001605 CL45_RD_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001606 MDIO_REG_BANK_COMBO_IEEE0,
1607 MDIO_COMBO_IEEE0_MII_CONTROL,
1608 &mii_control);
1609 DP(NETIF_MSG_LINK,
1610 "bnx2x_restart_autoneg mii_control before = 0x%x\n",
1611 mii_control);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001612 CL45_WR_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001613 MDIO_REG_BANK_COMBO_IEEE0,
1614 MDIO_COMBO_IEEE0_MII_CONTROL,
1615 (mii_control |
1616 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1617 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN));
1618 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001619}
1620
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001621static void bnx2x_initialize_sgmii_process(struct bnx2x_phy *phy,
1622 struct link_params *params,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001623 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001624{
1625 struct bnx2x *bp = params->bp;
1626 u16 control1;
1627
1628 /* in SGMII mode, the unicore is always slave */
1629
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001630 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001631 MDIO_REG_BANK_SERDES_DIGITAL,
1632 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
1633 &control1);
1634 control1 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT;
1635 /* set sgmii mode (and not fiber) */
1636 control1 &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE |
1637 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET |
1638 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_MSTR_MODE);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001639 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001640 MDIO_REG_BANK_SERDES_DIGITAL,
1641 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
1642 control1);
1643
1644 /* if forced speed */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001645 if (!(vars->line_speed == SPEED_AUTO_NEG)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001646 /* set speed, disable autoneg */
1647 u16 mii_control;
1648
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001649 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001650 MDIO_REG_BANK_COMBO_IEEE0,
1651 MDIO_COMBO_IEEE0_MII_CONTROL,
1652 &mii_control);
1653 mii_control &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1654 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK|
1655 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX);
1656
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001657 switch (vars->line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001658 case SPEED_100:
1659 mii_control |=
1660 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_100;
1661 break;
1662 case SPEED_1000:
1663 mii_control |=
1664 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_1000;
1665 break;
1666 case SPEED_10:
1667 /* there is nothing to set for 10M */
1668 break;
1669 default:
1670 /* invalid speed for SGMII */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001671 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
1672 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001673 break;
1674 }
1675
1676 /* setting the full duplex */
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001677 if (phy->req_duplex == DUPLEX_FULL)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001678 mii_control |=
1679 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001680 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001681 MDIO_REG_BANK_COMBO_IEEE0,
1682 MDIO_COMBO_IEEE0_MII_CONTROL,
1683 mii_control);
1684
1685 } else { /* AN mode */
1686 /* enable and restart AN */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001687 bnx2x_restart_autoneg(phy, params, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001688 }
1689}
1690
1691
1692/*
1693 * link management
1694 */
1695
1696static void bnx2x_pause_resolve(struct link_vars *vars, u32 pause_result)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001697{ /* LD LP */
1698 switch (pause_result) { /* ASYM P ASYM P */
1699 case 0xb: /* 1 0 1 1 */
David S. Millerc0700f92008-12-16 23:53:20 -08001700 vars->flow_ctrl = BNX2X_FLOW_CTRL_TX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001701 break;
1702
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001703 case 0xe: /* 1 1 1 0 */
David S. Millerc0700f92008-12-16 23:53:20 -08001704 vars->flow_ctrl = BNX2X_FLOW_CTRL_RX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001705 break;
1706
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001707 case 0x5: /* 0 1 0 1 */
1708 case 0x7: /* 0 1 1 1 */
1709 case 0xd: /* 1 1 0 1 */
1710 case 0xf: /* 1 1 1 1 */
David S. Millerc0700f92008-12-16 23:53:20 -08001711 vars->flow_ctrl = BNX2X_FLOW_CTRL_BOTH;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001712 break;
1713
1714 default:
1715 break;
1716 }
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001717 if (pause_result & (1<<0))
1718 vars->link_status |= LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE;
1719 if (pause_result & (1<<1))
1720 vars->link_status |= LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001721}
1722
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001723static u8 bnx2x_direct_parallel_detect_used(struct bnx2x_phy *phy,
1724 struct link_params *params)
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02001725{
1726 struct bnx2x *bp = params->bp;
1727 u16 pd_10g, status2_1000x;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001728 if (phy->req_line_speed != SPEED_AUTO_NEG)
1729 return 0;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001730 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02001731 MDIO_REG_BANK_SERDES_DIGITAL,
1732 MDIO_SERDES_DIGITAL_A_1000X_STATUS2,
1733 &status2_1000x);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001734 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02001735 MDIO_REG_BANK_SERDES_DIGITAL,
1736 MDIO_SERDES_DIGITAL_A_1000X_STATUS2,
1737 &status2_1000x);
1738 if (status2_1000x & MDIO_SERDES_DIGITAL_A_1000X_STATUS2_AN_DISABLED) {
1739 DP(NETIF_MSG_LINK, "1G parallel detect link on port %d\n",
1740 params->port);
1741 return 1;
1742 }
1743
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001744 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02001745 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1746 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_STATUS,
1747 &pd_10g);
1748
1749 if (pd_10g & MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_STATUS_PD_LINK) {
1750 DP(NETIF_MSG_LINK, "10G parallel detect link on port %d\n",
1751 params->port);
1752 return 1;
1753 }
1754 return 0;
1755}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001756
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001757static void bnx2x_flow_ctrl_resolve(struct bnx2x_phy *phy,
1758 struct link_params *params,
1759 struct link_vars *vars,
1760 u32 gp_status)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001761{
1762 struct bnx2x *bp = params->bp;
Eilon Greenstein3196a882008-08-13 15:58:49 -07001763 u16 ld_pause; /* local driver */
1764 u16 lp_pause; /* link partner */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001765 u16 pause_result;
1766
David S. Millerc0700f92008-12-16 23:53:20 -08001767 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001768
1769 /* resolve from gp_status in case of AN complete and not sgmii */
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001770 if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO)
1771 vars->flow_ctrl = phy->req_flow_ctrl;
1772 else if (phy->req_line_speed != SPEED_AUTO_NEG)
1773 vars->flow_ctrl = params->req_fc_auto_adv;
1774 else if ((gp_status & MDIO_AN_CL73_OR_37_COMPLETE) &&
1775 (!(vars->phy_flags & PHY_SGMII_FLAG))) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001776 if (bnx2x_direct_parallel_detect_used(phy, params)) {
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02001777 vars->flow_ctrl = params->req_fc_auto_adv;
1778 return;
1779 }
Yaniv Rosner7846e472009-11-05 19:18:07 +02001780 if ((gp_status &
1781 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
1782 MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) ==
1783 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
1784 MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) {
1785
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001786 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner7846e472009-11-05 19:18:07 +02001787 MDIO_REG_BANK_CL73_IEEEB1,
1788 MDIO_CL73_IEEEB1_AN_ADV1,
1789 &ld_pause);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001790 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner7846e472009-11-05 19:18:07 +02001791 MDIO_REG_BANK_CL73_IEEEB1,
1792 MDIO_CL73_IEEEB1_AN_LP_ADV1,
1793 &lp_pause);
1794 pause_result = (ld_pause &
1795 MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK)
1796 >> 8;
1797 pause_result |= (lp_pause &
1798 MDIO_CL73_IEEEB1_AN_LP_ADV1_PAUSE_MASK)
1799 >> 10;
1800 DP(NETIF_MSG_LINK, "pause_result CL73 0x%x\n",
1801 pause_result);
1802 } else {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001803 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner7846e472009-11-05 19:18:07 +02001804 MDIO_REG_BANK_COMBO_IEEE0,
1805 MDIO_COMBO_IEEE0_AUTO_NEG_ADV,
1806 &ld_pause);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001807 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner7846e472009-11-05 19:18:07 +02001808 MDIO_REG_BANK_COMBO_IEEE0,
1809 MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1,
1810 &lp_pause);
1811 pause_result = (ld_pause &
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001812 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>5;
Yaniv Rosner7846e472009-11-05 19:18:07 +02001813 pause_result |= (lp_pause &
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001814 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7;
Yaniv Rosner7846e472009-11-05 19:18:07 +02001815 DP(NETIF_MSG_LINK, "pause_result CL37 0x%x\n",
1816 pause_result);
1817 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001818 bnx2x_pause_resolve(vars, pause_result);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001819 }
1820 DP(NETIF_MSG_LINK, "flow_ctrl 0x%x\n", vars->flow_ctrl);
1821}
1822
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001823static void bnx2x_check_fallback_to_cl37(struct bnx2x_phy *phy,
1824 struct link_params *params)
Eilon Greenstein239d6862009-08-12 08:23:04 +00001825{
1826 struct bnx2x *bp = params->bp;
1827 u16 rx_status, ustat_val, cl37_fsm_recieved;
1828 DP(NETIF_MSG_LINK, "bnx2x_check_fallback_to_cl37\n");
1829 /* Step 1: Make sure signal is detected */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001830 CL45_RD_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001831 MDIO_REG_BANK_RX0,
1832 MDIO_RX0_RX_STATUS,
1833 &rx_status);
1834 if ((rx_status & MDIO_RX0_RX_STATUS_SIGDET) !=
1835 (MDIO_RX0_RX_STATUS_SIGDET)) {
1836 DP(NETIF_MSG_LINK, "Signal is not detected. Restoring CL73."
1837 "rx_status(0x80b0) = 0x%x\n", rx_status);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001838 CL45_WR_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001839 MDIO_REG_BANK_CL73_IEEEB0,
1840 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1841 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN);
1842 return;
1843 }
1844 /* Step 2: Check CL73 state machine */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001845 CL45_RD_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001846 MDIO_REG_BANK_CL73_USERB0,
1847 MDIO_CL73_USERB0_CL73_USTAT1,
1848 &ustat_val);
1849 if ((ustat_val &
1850 (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK |
1851 MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) !=
1852 (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK |
1853 MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) {
1854 DP(NETIF_MSG_LINK, "CL73 state-machine is not stable. "
1855 "ustat_val(0x8371) = 0x%x\n", ustat_val);
1856 return;
1857 }
1858 /* Step 3: Check CL37 Message Pages received to indicate LP
1859 supports only CL37 */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001860 CL45_RD_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001861 MDIO_REG_BANK_REMOTE_PHY,
1862 MDIO_REMOTE_PHY_MISC_RX_STATUS,
1863 &cl37_fsm_recieved);
1864 if ((cl37_fsm_recieved &
1865 (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG |
1866 MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) !=
1867 (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG |
1868 MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) {
1869 DP(NETIF_MSG_LINK, "No CL37 FSM were received. "
1870 "misc_rx_status(0x8330) = 0x%x\n",
1871 cl37_fsm_recieved);
1872 return;
1873 }
1874 /* The combined cl37/cl73 fsm state information indicating that we are
1875 connected to a device which does not support cl73, but does support
1876 cl37 BAM. In this case we disable cl73 and restart cl37 auto-neg */
1877 /* Disable CL73 */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001878 CL45_WR_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001879 MDIO_REG_BANK_CL73_IEEEB0,
1880 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1881 0);
1882 /* Restart CL37 autoneg */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001883 bnx2x_restart_autoneg(phy, params, 0);
Eilon Greenstein239d6862009-08-12 08:23:04 +00001884 DP(NETIF_MSG_LINK, "Disabling CL73, and restarting CL37 autoneg\n");
1885}
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001886
1887static void bnx2x_xgxs_an_resolve(struct bnx2x_phy *phy,
1888 struct link_params *params,
1889 struct link_vars *vars,
1890 u32 gp_status)
1891{
1892 if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE)
1893 vars->link_status |=
1894 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
1895
1896 if (bnx2x_direct_parallel_detect_used(phy, params))
1897 vars->link_status |=
1898 LINK_STATUS_PARALLEL_DETECTION_USED;
1899}
1900
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00001901static u8 bnx2x_link_settings_status(struct bnx2x_phy *phy,
1902 struct link_params *params,
1903 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001904{
1905 struct bnx2x *bp = params->bp;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00001906 u16 new_line_speed , gp_status;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001907 u8 rc = 0;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00001908
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00001909 /* Read gp_status */
1910 CL45_RD_OVER_CL22(bp, phy,
1911 MDIO_REG_BANK_GP_STATUS,
1912 MDIO_GP_STATUS_TOP_AN_STATUS1,
1913 &gp_status);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00001914
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001915 if (phy->req_line_speed == SPEED_AUTO_NEG)
1916 vars->link_status |= LINK_STATUS_AUTO_NEGOTIATE_ENABLED;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001917 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) {
1918 DP(NETIF_MSG_LINK, "phy link up gp_status=0x%x\n",
1919 gp_status);
1920
1921 vars->phy_link_up = 1;
1922 vars->link_status |= LINK_STATUS_LINK_UP;
1923
1924 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_DUPLEX_STATUS)
1925 vars->duplex = DUPLEX_FULL;
1926 else
1927 vars->duplex = DUPLEX_HALF;
1928
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001929 if (SINGLE_MEDIA_DIRECT(params)) {
1930 bnx2x_flow_ctrl_resolve(phy, params, vars, gp_status);
1931 if (phy->req_line_speed == SPEED_AUTO_NEG)
1932 bnx2x_xgxs_an_resolve(phy, params, vars,
1933 gp_status);
1934 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001935
1936 switch (gp_status & GP_STATUS_SPEED_MASK) {
1937 case GP_STATUS_10M:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001938 new_line_speed = SPEED_10;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001939 if (vars->duplex == DUPLEX_FULL)
1940 vars->link_status |= LINK_10TFD;
1941 else
1942 vars->link_status |= LINK_10THD;
1943 break;
1944
1945 case GP_STATUS_100M:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001946 new_line_speed = SPEED_100;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001947 if (vars->duplex == DUPLEX_FULL)
1948 vars->link_status |= LINK_100TXFD;
1949 else
1950 vars->link_status |= LINK_100TXHD;
1951 break;
1952
1953 case GP_STATUS_1G:
1954 case GP_STATUS_1G_KX:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001955 new_line_speed = SPEED_1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001956 if (vars->duplex == DUPLEX_FULL)
1957 vars->link_status |= LINK_1000TFD;
1958 else
1959 vars->link_status |= LINK_1000THD;
1960 break;
1961
1962 case GP_STATUS_2_5G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001963 new_line_speed = SPEED_2500;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001964 if (vars->duplex == DUPLEX_FULL)
1965 vars->link_status |= LINK_2500TFD;
1966 else
1967 vars->link_status |= LINK_2500THD;
1968 break;
1969
1970 case GP_STATUS_5G:
1971 case GP_STATUS_6G:
1972 DP(NETIF_MSG_LINK,
1973 "link speed unsupported gp_status 0x%x\n",
1974 gp_status);
1975 return -EINVAL;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00001976
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001977 case GP_STATUS_10G_KX4:
1978 case GP_STATUS_10G_HIG:
1979 case GP_STATUS_10G_CX4:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001980 new_line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001981 vars->link_status |= LINK_10GTFD;
1982 break;
1983
1984 case GP_STATUS_12G_HIG:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001985 new_line_speed = SPEED_12000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001986 vars->link_status |= LINK_12GTFD;
1987 break;
1988
1989 case GP_STATUS_12_5G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001990 new_line_speed = SPEED_12500;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001991 vars->link_status |= LINK_12_5GTFD;
1992 break;
1993
1994 case GP_STATUS_13G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001995 new_line_speed = SPEED_13000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001996 vars->link_status |= LINK_13GTFD;
1997 break;
1998
1999 case GP_STATUS_15G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002000 new_line_speed = SPEED_15000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002001 vars->link_status |= LINK_15GTFD;
2002 break;
2003
2004 case GP_STATUS_16G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002005 new_line_speed = SPEED_16000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002006 vars->link_status |= LINK_16GTFD;
2007 break;
2008
2009 default:
2010 DP(NETIF_MSG_LINK,
2011 "link speed unsupported gp_status 0x%x\n",
2012 gp_status);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002013 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002014 }
2015
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002016 vars->line_speed = new_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002017
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002018 } else { /* link_down */
2019 DP(NETIF_MSG_LINK, "phy link down\n");
2020
2021 vars->phy_link_up = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002022
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002023 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08002024 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002025 vars->mac_type = MAC_TYPE_NONE;
Eilon Greenstein239d6862009-08-12 08:23:04 +00002026
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002027 if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
2028 SINGLE_MEDIA_DIRECT(params)) {
Eilon Greenstein239d6862009-08-12 08:23:04 +00002029 /* Check signal is detected */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002030 bnx2x_check_fallback_to_cl37(phy, params);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002031 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002032 }
2033
Frans Pop2381a552010-03-24 07:57:36 +00002034 DP(NETIF_MSG_LINK, "gp_status 0x%x phy_link_up %x line_speed %x\n",
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002035 gp_status, vars->phy_link_up, vars->line_speed);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002036 DP(NETIF_MSG_LINK, "duplex %x flow_ctrl 0x%x link_status 0x%x\n",
2037 vars->duplex, vars->flow_ctrl, vars->link_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002038 return rc;
2039}
2040
Eilon Greensteined8680a2009-02-12 08:37:12 +00002041static void bnx2x_set_gmii_tx_driver(struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002042{
2043 struct bnx2x *bp = params->bp;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002044 struct bnx2x_phy *phy = &params->phy[INT_PHY];
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002045 u16 lp_up2;
2046 u16 tx_driver;
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00002047 u16 bank;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002048
2049 /* read precomp */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002050 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002051 MDIO_REG_BANK_OVER_1G,
2052 MDIO_OVER_1G_LP_UP2, &lp_up2);
2053
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002054 /* bits [10:7] at lp_up2, positioned at [15:12] */
2055 lp_up2 = (((lp_up2 & MDIO_OVER_1G_LP_UP2_PREEMPHASIS_MASK) >>
2056 MDIO_OVER_1G_LP_UP2_PREEMPHASIS_SHIFT) <<
2057 MDIO_TX0_TX_DRIVER_PREEMPHASIS_SHIFT);
2058
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00002059 if (lp_up2 == 0)
2060 return;
2061
2062 for (bank = MDIO_REG_BANK_TX0; bank <= MDIO_REG_BANK_TX3;
2063 bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0)) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002064 CL45_RD_OVER_CL22(bp, phy,
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00002065 bank,
2066 MDIO_TX0_TX_DRIVER, &tx_driver);
2067
2068 /* replace tx_driver bits [15:12] */
2069 if (lp_up2 !=
2070 (tx_driver & MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK)) {
2071 tx_driver &= ~MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK;
2072 tx_driver |= lp_up2;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002073 CL45_WR_OVER_CL22(bp, phy,
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00002074 bank,
2075 MDIO_TX0_TX_DRIVER, tx_driver);
2076 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002077 }
2078}
2079
2080static u8 bnx2x_emac_program(struct link_params *params,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002081 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002082{
2083 struct bnx2x *bp = params->bp;
2084 u8 port = params->port;
2085 u16 mode = 0;
2086
2087 DP(NETIF_MSG_LINK, "setting link speed & duplex\n");
2088 bnx2x_bits_dis(bp, GRCBASE_EMAC0 + port*0x400 +
2089 EMAC_REG_EMAC_MODE,
2090 (EMAC_MODE_25G_MODE |
2091 EMAC_MODE_PORT_MII_10M |
2092 EMAC_MODE_HALF_DUPLEX));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002093 switch (vars->line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002094 case SPEED_10:
2095 mode |= EMAC_MODE_PORT_MII_10M;
2096 break;
2097
2098 case SPEED_100:
2099 mode |= EMAC_MODE_PORT_MII;
2100 break;
2101
2102 case SPEED_1000:
2103 mode |= EMAC_MODE_PORT_GMII;
2104 break;
2105
2106 case SPEED_2500:
2107 mode |= (EMAC_MODE_25G_MODE | EMAC_MODE_PORT_GMII);
2108 break;
2109
2110 default:
2111 /* 10G not valid for EMAC */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002112 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
2113 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002114 return -EINVAL;
2115 }
2116
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002117 if (vars->duplex == DUPLEX_HALF)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002118 mode |= EMAC_MODE_HALF_DUPLEX;
2119 bnx2x_bits_en(bp,
2120 GRCBASE_EMAC0 + port*0x400 + EMAC_REG_EMAC_MODE,
2121 mode);
2122
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00002123 bnx2x_set_led(params, vars, LED_MODE_OPER, vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002124 return 0;
2125}
2126
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002127static void bnx2x_set_preemphasis(struct bnx2x_phy *phy,
2128 struct link_params *params)
2129{
2130
2131 u16 bank, i = 0;
2132 struct bnx2x *bp = params->bp;
2133
2134 for (bank = MDIO_REG_BANK_RX0, i = 0; bank <= MDIO_REG_BANK_RX3;
2135 bank += (MDIO_REG_BANK_RX1-MDIO_REG_BANK_RX0), i++) {
2136 CL45_WR_OVER_CL22(bp, phy,
2137 bank,
2138 MDIO_RX0_RX_EQ_BOOST,
2139 phy->rx_preemphasis[i]);
2140 }
2141
2142 for (bank = MDIO_REG_BANK_TX0, i = 0; bank <= MDIO_REG_BANK_TX3;
2143 bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0), i++) {
2144 CL45_WR_OVER_CL22(bp, phy,
2145 bank,
2146 MDIO_TX0_TX_DRIVER,
2147 phy->tx_preemphasis[i]);
2148 }
2149}
2150
2151static void bnx2x_init_internal_phy(struct bnx2x_phy *phy,
2152 struct link_params *params,
2153 struct link_vars *vars)
2154{
2155 struct bnx2x *bp = params->bp;
2156 u8 enable_cl73 = (SINGLE_MEDIA_DIRECT(params) ||
2157 (params->loopback_mode == LOOPBACK_XGXS));
2158 if (!(vars->phy_flags & PHY_SGMII_FLAG)) {
2159 if (SINGLE_MEDIA_DIRECT(params) &&
2160 (params->feature_config_flags &
2161 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED))
2162 bnx2x_set_preemphasis(phy, params);
2163
2164 /* forced speed requested? */
2165 if (vars->line_speed != SPEED_AUTO_NEG ||
2166 (SINGLE_MEDIA_DIRECT(params) &&
2167 params->loopback_mode == LOOPBACK_EXT)) {
2168 DP(NETIF_MSG_LINK, "not SGMII, no AN\n");
2169
2170 /* disable autoneg */
2171 bnx2x_set_autoneg(phy, params, vars, 0);
2172
2173 /* program speed and duplex */
2174 bnx2x_program_serdes(phy, params, vars);
2175
2176 } else { /* AN_mode */
2177 DP(NETIF_MSG_LINK, "not SGMII, AN\n");
2178
2179 /* AN enabled */
2180 bnx2x_set_brcm_cl37_advertisment(phy, params);
2181
2182 /* program duplex & pause advertisement (for aneg) */
2183 bnx2x_set_ieee_aneg_advertisment(phy, params,
2184 vars->ieee_fc);
2185
2186 /* enable autoneg */
2187 bnx2x_set_autoneg(phy, params, vars, enable_cl73);
2188
2189 /* enable and restart AN */
2190 bnx2x_restart_autoneg(phy, params, enable_cl73);
2191 }
2192
2193 } else { /* SGMII mode */
2194 DP(NETIF_MSG_LINK, "SGMII\n");
2195
2196 bnx2x_initialize_sgmii_process(phy, params, vars);
2197 }
2198}
2199
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002200static u8 bnx2x_init_serdes(struct bnx2x_phy *phy,
2201 struct link_params *params,
2202 struct link_vars *vars)
2203{
2204 u8 rc;
2205 vars->phy_flags |= PHY_SGMII_FLAG;
2206 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002207 bnx2x_set_aer_mmd_serdes(params->bp, phy);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002208 rc = bnx2x_reset_unicore(params, phy, 1);
2209 /* reset the SerDes and wait for reset bit return low */
2210 if (rc != 0)
2211 return rc;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002212 bnx2x_set_aer_mmd_serdes(params->bp, phy);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002213
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002214 return rc;
2215}
2216
2217static u8 bnx2x_init_xgxs(struct bnx2x_phy *phy,
2218 struct link_params *params,
2219 struct link_vars *vars)
2220{
2221 u8 rc;
2222 vars->phy_flags = PHY_XGXS_FLAG;
2223 if ((phy->req_line_speed &&
2224 ((phy->req_line_speed == SPEED_100) ||
2225 (phy->req_line_speed == SPEED_10))) ||
2226 (!phy->req_line_speed &&
2227 (phy->speed_cap_mask >=
2228 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL) &&
2229 (phy->speed_cap_mask <
2230 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
2231 ))
2232 vars->phy_flags |= PHY_SGMII_FLAG;
2233 else
2234 vars->phy_flags &= ~PHY_SGMII_FLAG;
2235
2236 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002237 bnx2x_set_aer_mmd_xgxs(params, phy);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002238 bnx2x_set_master_ln(params, phy);
2239
2240 rc = bnx2x_reset_unicore(params, phy, 0);
2241 /* reset the SerDes and wait for reset bit return low */
2242 if (rc != 0)
2243 return rc;
2244
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002245 bnx2x_set_aer_mmd_xgxs(params, phy);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002246
2247 /* setting the masterLn_def again after the reset */
2248 bnx2x_set_master_ln(params, phy);
2249 bnx2x_set_swap_lanes(params, phy);
2250
2251 return rc;
2252}
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002253
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002254static u16 bnx2x_wait_reset_complete(struct bnx2x *bp,
2255 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002256{
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002257 u16 cnt, ctrl;
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002258 /* Wait for soft reset to get cleared upto 1 sec */
2259 for (cnt = 0; cnt < 1000; cnt++) {
2260 bnx2x_cl45_read(bp, phy,
2261 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, &ctrl);
2262 if (!(ctrl & (1<<15)))
2263 break;
2264 msleep(1);
2265 }
2266 DP(NETIF_MSG_LINK, "control reg 0x%x (after %d ms)\n", ctrl, cnt);
2267 return cnt;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002268}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002269
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002270static void bnx2x_link_int_enable(struct link_params *params)
2271{
2272 u8 port = params->port;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002273 u32 mask;
2274 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002275
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002276 /* setting the status to report on link up
2277 for either XGXS or SerDes */
2278
2279 if (params->switch_cfg == SWITCH_CFG_10G) {
2280 mask = (NIG_MASK_XGXS0_LINK10G |
2281 NIG_MASK_XGXS0_LINK_STATUS);
2282 DP(NETIF_MSG_LINK, "enabled XGXS interrupt\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002283 if (!(SINGLE_MEDIA_DIRECT(params)) &&
2284 params->phy[INT_PHY].type !=
2285 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002286 mask |= NIG_MASK_MI_INT;
2287 DP(NETIF_MSG_LINK, "enabled external phy int\n");
2288 }
2289
2290 } else { /* SerDes */
2291 mask = NIG_MASK_SERDES0_LINK_STATUS;
2292 DP(NETIF_MSG_LINK, "enabled SerDes interrupt\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002293 if (!(SINGLE_MEDIA_DIRECT(params)) &&
2294 params->phy[INT_PHY].type !=
2295 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_NOT_CONN) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002296 mask |= NIG_MASK_MI_INT;
2297 DP(NETIF_MSG_LINK, "enabled external phy int\n");
2298 }
2299 }
2300 bnx2x_bits_en(bp,
2301 NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
2302 mask);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002303
2304 DP(NETIF_MSG_LINK, "port %x, is_xgxs %x, int_status 0x%x\n", port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002305 (params->switch_cfg == SWITCH_CFG_10G),
2306 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002307 DP(NETIF_MSG_LINK, " int_mask 0x%x, MI_INT %x, SERDES_LINK %x\n",
2308 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
2309 REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
2310 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS+port*0x3c));
2311 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
2312 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
2313 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
2314}
2315
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002316static void bnx2x_rearm_latch_signal(struct bnx2x *bp, u8 port,
2317 u8 exp_mi_int)
Eilon Greenstein2f904462009-08-12 08:22:16 +00002318{
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002319 u32 latch_status = 0;
2320
2321 /**
2322 * Disable the MI INT ( external phy int ) by writing 1 to the
2323 * status register. Link down indication is high-active-signal,
2324 * so in this case we need to write the status to clear the XOR
Eilon Greenstein2f904462009-08-12 08:22:16 +00002325 */
2326 /* Read Latched signals */
2327 latch_status = REG_RD(bp,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002328 NIG_REG_LATCH_STATUS_0 + port*8);
2329 DP(NETIF_MSG_LINK, "latch_status = 0x%x\n", latch_status);
Eilon Greenstein2f904462009-08-12 08:22:16 +00002330 /* Handle only those with latched-signal=up.*/
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002331 if (exp_mi_int)
2332 bnx2x_bits_en(bp,
2333 NIG_REG_STATUS_INTERRUPT_PORT0
2334 + port*4,
2335 NIG_STATUS_EMAC0_MI_INT);
2336 else
2337 bnx2x_bits_dis(bp,
2338 NIG_REG_STATUS_INTERRUPT_PORT0
2339 + port*4,
2340 NIG_STATUS_EMAC0_MI_INT);
2341
Eilon Greenstein2f904462009-08-12 08:22:16 +00002342 if (latch_status & 1) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002343
Eilon Greenstein2f904462009-08-12 08:22:16 +00002344 /* For all latched-signal=up : Re-Arm Latch signals */
2345 REG_WR(bp, NIG_REG_LATCH_STATUS_0 + port*8,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00002346 (latch_status & 0xfffe) | (latch_status & 1));
Eilon Greenstein2f904462009-08-12 08:22:16 +00002347 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002348 /* For all latched-signal=up,Write original_signal to status */
Eilon Greenstein2f904462009-08-12 08:22:16 +00002349}
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002350
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002351static void bnx2x_link_int_ack(struct link_params *params,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002352 struct link_vars *vars, u8 is_10g)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002353{
2354 struct bnx2x *bp = params->bp;
2355 u8 port = params->port;
2356
2357 /* first reset all status
2358 * we assume only one line will be change at a time */
2359 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
2360 (NIG_STATUS_XGXS0_LINK10G |
2361 NIG_STATUS_XGXS0_LINK_STATUS |
2362 NIG_STATUS_SERDES0_LINK_STATUS));
2363 if (vars->phy_link_up) {
2364 if (is_10g) {
2365 /* Disable the 10G link interrupt
2366 * by writing 1 to the status register
2367 */
2368 DP(NETIF_MSG_LINK, "10G XGXS phy link up\n");
2369 bnx2x_bits_en(bp,
2370 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
2371 NIG_STATUS_XGXS0_LINK10G);
2372
2373 } else if (params->switch_cfg == SWITCH_CFG_10G) {
2374 /* Disable the link interrupt
2375 * by writing 1 to the relevant lane
2376 * in the status register
2377 */
2378 u32 ser_lane = ((params->lane_config &
2379 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
2380 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
2381
Eilon Greenstein2f904462009-08-12 08:22:16 +00002382 DP(NETIF_MSG_LINK, "%d speed XGXS phy link up\n",
2383 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002384 bnx2x_bits_en(bp,
2385 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
2386 ((1 << ser_lane) <<
2387 NIG_STATUS_XGXS0_LINK_STATUS_SIZE));
2388
2389 } else { /* SerDes */
2390 DP(NETIF_MSG_LINK, "SerDes phy link up\n");
2391 /* Disable the link interrupt
2392 * by writing 1 to the status register
2393 */
2394 bnx2x_bits_en(bp,
2395 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
2396 NIG_STATUS_SERDES0_LINK_STATUS);
2397 }
2398
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002399 }
2400}
2401
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002402static u8 bnx2x_format_ver(u32 num, u8 *str, u16 *len)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002403{
2404 u8 *str_ptr = str;
2405 u32 mask = 0xf0000000;
2406 u8 shift = 8*4;
2407 u8 digit;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002408 u8 remove_leading_zeros = 1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002409 if (*len < 10) {
Frederik Schwarzer025dfda2008-10-16 19:02:37 +02002410 /* Need more than 10chars for this format */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002411 *str_ptr = '\0';
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002412 (*len)--;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002413 return -EINVAL;
2414 }
2415 while (shift > 0) {
2416
2417 shift -= 4;
2418 digit = ((num & mask) >> shift);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002419 if (digit == 0 && remove_leading_zeros) {
2420 mask = mask >> 4;
2421 continue;
2422 } else if (digit < 0xa)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002423 *str_ptr = digit + '0';
2424 else
2425 *str_ptr = digit - 0xa + 'a';
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002426 remove_leading_zeros = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002427 str_ptr++;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002428 (*len)--;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002429 mask = mask >> 4;
2430 if (shift == 4*4) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002431 *str_ptr = '.';
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002432 str_ptr++;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002433 (*len)--;
2434 remove_leading_zeros = 1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002435 }
2436 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002437 return 0;
2438}
2439
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002440
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002441static u8 bnx2x_null_format_ver(u32 spirom_ver, u8 *str, u16 *len)
2442{
2443 str[0] = '\0';
2444 (*len)--;
2445 return 0;
2446}
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002447
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002448u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
2449 u8 *version, u16 len)
2450{
Julia Lawall0376d5b2009-07-19 05:26:35 +00002451 struct bnx2x *bp;
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002452 u32 spirom_ver = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002453 u8 status = 0;
2454 u8 *ver_p = version;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002455 u16 remain_len = len;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002456 if (version == NULL || params == NULL)
2457 return -EINVAL;
Julia Lawall0376d5b2009-07-19 05:26:35 +00002458 bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002459
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002460 /* Extract first external phy*/
2461 version[0] = '\0';
2462 spirom_ver = REG_RD(bp, params->phy[EXT_PHY1].ver_addr);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002463
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002464 if (params->phy[EXT_PHY1].format_fw_ver) {
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002465 status |= params->phy[EXT_PHY1].format_fw_ver(spirom_ver,
2466 ver_p,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002467 &remain_len);
2468 ver_p += (len - remain_len);
2469 }
2470 if ((params->num_phys == MAX_PHYS) &&
2471 (params->phy[EXT_PHY2].ver_addr != 0)) {
2472 spirom_ver = REG_RD(bp,
2473 params->phy[EXT_PHY2].ver_addr);
2474 if (params->phy[EXT_PHY2].format_fw_ver) {
2475 *ver_p = '/';
2476 ver_p++;
2477 remain_len--;
2478 status |= params->phy[EXT_PHY2].format_fw_ver(
2479 spirom_ver,
2480 ver_p,
2481 &remain_len);
2482 ver_p = version + (len - remain_len);
2483 }
2484 }
2485 *ver_p = '\0';
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002486 return status;
2487}
2488
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002489static void bnx2x_set_xgxs_loopback(struct bnx2x_phy *phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002490 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002491{
2492 u8 port = params->port;
2493 struct bnx2x *bp = params->bp;
2494
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002495 if (phy->req_line_speed != SPEED_1000) {
Eilon Greenstein6378c022008-08-13 15:59:25 -07002496 u32 md_devad;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002497
2498 DP(NETIF_MSG_LINK, "XGXS 10G loopback enable\n");
2499
2500 /* change the uni_phy_addr in the nig */
2501 md_devad = REG_RD(bp, (NIG_REG_XGXS0_CTRL_MD_DEVAD +
2502 port*0x18));
2503
2504 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, 0x5);
2505
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002506 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002507 5,
2508 (MDIO_REG_BANK_AER_BLOCK +
2509 (MDIO_AER_BLOCK_AER_REG & 0xf)),
2510 0x2800);
2511
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002512 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002513 5,
2514 (MDIO_REG_BANK_CL73_IEEEB0 +
2515 (MDIO_CL73_IEEEB0_CL73_AN_CONTROL & 0xf)),
2516 0x6041);
Eilon Greenstein38582762009-01-14 06:44:16 +00002517 msleep(200);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002518 /* set aer mmd back */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002519 bnx2x_set_aer_mmd_xgxs(params, phy);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002520
2521 /* and md_devad */
2522 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
2523 md_devad);
2524
2525 } else {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002526 u16 mii_ctrl;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002527 DP(NETIF_MSG_LINK, "XGXS 1G loopback enable\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002528 bnx2x_cl45_read(bp, phy, 5,
2529 (MDIO_REG_BANK_COMBO_IEEE0 +
2530 (MDIO_COMBO_IEEE0_MII_CONTROL & 0xf)),
2531 &mii_ctrl);
2532 bnx2x_cl45_write(bp, phy, 5,
2533 (MDIO_REG_BANK_COMBO_IEEE0 +
2534 (MDIO_COMBO_IEEE0_MII_CONTROL & 0xf)),
2535 mii_ctrl |
2536 MDIO_COMBO_IEEO_MII_CONTROL_LOOPBACK);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002537 }
2538}
2539
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002540/*
2541 *------------------------------------------------------------------------
2542 * bnx2x_override_led_value -
2543 *
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002544 * Override the led value of the requested led
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002545 *
2546 *------------------------------------------------------------------------
2547 */
2548u8 bnx2x_override_led_value(struct bnx2x *bp, u8 port,
2549 u32 led_idx, u32 value)
2550{
2551 u32 reg_val;
2552
2553 /* If port 0 then use EMAC0, else use EMAC1*/
2554 u32 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
2555
2556 DP(NETIF_MSG_LINK,
2557 "bnx2x_override_led_value() port %x led_idx %d value %d\n",
2558 port, led_idx, value);
2559
2560 switch (led_idx) {
2561 case 0: /* 10MB led */
2562 /* Read the current value of the LED register in
2563 the EMAC block */
2564 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
2565 /* Set the OVERRIDE bit to 1 */
2566 reg_val |= EMAC_LED_OVERRIDE;
2567 /* If value is 1, set the 10M_OVERRIDE bit,
2568 otherwise reset it.*/
2569 reg_val = (value == 1) ? (reg_val | EMAC_LED_10MB_OVERRIDE) :
2570 (reg_val & ~EMAC_LED_10MB_OVERRIDE);
2571 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
2572 break;
2573 case 1: /*100MB led */
2574 /*Read the current value of the LED register in
2575 the EMAC block */
2576 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
2577 /* Set the OVERRIDE bit to 1 */
2578 reg_val |= EMAC_LED_OVERRIDE;
2579 /* If value is 1, set the 100M_OVERRIDE bit,
2580 otherwise reset it.*/
2581 reg_val = (value == 1) ? (reg_val | EMAC_LED_100MB_OVERRIDE) :
2582 (reg_val & ~EMAC_LED_100MB_OVERRIDE);
2583 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
2584 break;
2585 case 2: /* 1000MB led */
2586 /* Read the current value of the LED register in the
2587 EMAC block */
2588 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
2589 /* Set the OVERRIDE bit to 1 */
2590 reg_val |= EMAC_LED_OVERRIDE;
2591 /* If value is 1, set the 1000M_OVERRIDE bit, otherwise
2592 reset it. */
2593 reg_val = (value == 1) ? (reg_val | EMAC_LED_1000MB_OVERRIDE) :
2594 (reg_val & ~EMAC_LED_1000MB_OVERRIDE);
2595 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
2596 break;
2597 case 3: /* 2500MB led */
2598 /* Read the current value of the LED register in the
2599 EMAC block*/
2600 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
2601 /* Set the OVERRIDE bit to 1 */
2602 reg_val |= EMAC_LED_OVERRIDE;
2603 /* If value is 1, set the 2500M_OVERRIDE bit, otherwise
2604 reset it.*/
2605 reg_val = (value == 1) ? (reg_val | EMAC_LED_2500MB_OVERRIDE) :
2606 (reg_val & ~EMAC_LED_2500MB_OVERRIDE);
2607 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
2608 break;
2609 case 4: /*10G led */
2610 if (port == 0) {
2611 REG_WR(bp, NIG_REG_LED_10G_P0,
2612 value);
2613 } else {
2614 REG_WR(bp, NIG_REG_LED_10G_P1,
2615 value);
2616 }
2617 break;
2618 case 5: /* TRAFFIC led */
2619 /* Find if the traffic control is via BMAC or EMAC */
2620 if (port == 0)
2621 reg_val = REG_RD(bp, NIG_REG_NIG_EMAC0_EN);
2622 else
2623 reg_val = REG_RD(bp, NIG_REG_NIG_EMAC1_EN);
2624
2625 /* Override the traffic led in the EMAC:*/
2626 if (reg_val == 1) {
2627 /* Read the current value of the LED register in
2628 the EMAC block */
2629 reg_val = REG_RD(bp, emac_base +
2630 EMAC_REG_EMAC_LED);
2631 /* Set the TRAFFIC_OVERRIDE bit to 1 */
2632 reg_val |= EMAC_LED_OVERRIDE;
2633 /* If value is 1, set the TRAFFIC bit, otherwise
2634 reset it.*/
2635 reg_val = (value == 1) ? (reg_val | EMAC_LED_TRAFFIC) :
2636 (reg_val & ~EMAC_LED_TRAFFIC);
2637 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
2638 } else { /* Override the traffic led in the BMAC: */
2639 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
2640 + port*4, 1);
2641 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 + port*4,
2642 value);
2643 }
2644 break;
2645 default:
2646 DP(NETIF_MSG_LINK,
2647 "bnx2x_override_led_value() unknown led index %d "
2648 "(should be 0-5)\n", led_idx);
2649 return -EINVAL;
2650 }
2651
2652 return 0;
2653}
2654
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00002655
2656u8 bnx2x_set_led(struct link_params *params,
2657 struct link_vars *vars, u8 mode, u32 speed)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002658{
Yaniv Rosner7846e472009-11-05 19:18:07 +02002659 u8 port = params->port;
2660 u16 hw_led_mode = params->hw_led_mode;
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00002661 u8 rc = 0, phy_idx;
Eilon Greenstein345b5d52008-08-13 15:58:12 -07002662 u32 tmp;
2663 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Yaniv Rosner7846e472009-11-05 19:18:07 +02002664 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002665 DP(NETIF_MSG_LINK, "bnx2x_set_led: port %x, mode %d\n", port, mode);
2666 DP(NETIF_MSG_LINK, "speed 0x%x, hw_led_mode 0x%x\n",
2667 speed, hw_led_mode);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00002668 /* In case */
2669 for (phy_idx = EXT_PHY1; phy_idx < MAX_PHYS; phy_idx++) {
2670 if (params->phy[phy_idx].set_link_led) {
2671 params->phy[phy_idx].set_link_led(
2672 &params->phy[phy_idx], params, mode);
2673 }
2674 }
2675
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002676 switch (mode) {
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00002677 case LED_MODE_FRONT_PANEL_OFF:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002678 case LED_MODE_OFF:
2679 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 0);
2680 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
2681 SHARED_HW_CFG_LED_MAC1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07002682
2683 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07002684 EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp | EMAC_LED_OVERRIDE));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002685 break;
2686
2687 case LED_MODE_OPER:
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00002688 /**
2689 * For all other phys, OPER mode is same as ON, so in case
2690 * link is down, do nothing
2691 **/
2692 if (!vars->link_up)
2693 break;
2694 case LED_MODE_ON:
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002695 if (SINGLE_MEDIA_DIRECT(params)) {
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00002696 /**
2697 * This is a work-around for HW issue found when link
2698 * is up in CL73
2699 */
Yaniv Rosner7846e472009-11-05 19:18:07 +02002700 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0);
2701 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1);
2702 } else {
2703 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
2704 hw_led_mode);
2705 }
2706
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002707 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 +
2708 port*4, 0);
2709 /* Set blinking rate to ~15.9Hz */
2710 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4,
2711 LED_BLINK_RATE_VAL);
2712 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 +
2713 port*4, 1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07002714 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07002715 EMAC_WR(bp, EMAC_REG_EMAC_LED,
Eilon Greenstein345b5d52008-08-13 15:58:12 -07002716 (tmp & (~EMAC_LED_OVERRIDE)));
2717
Yaniv Rosner7846e472009-11-05 19:18:07 +02002718 if (CHIP_IS_E1(bp) &&
Eilon Greenstein34f80b02008-06-23 20:33:01 -07002719 ((speed == SPEED_2500) ||
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002720 (speed == SPEED_1000) ||
2721 (speed == SPEED_100) ||
2722 (speed == SPEED_10))) {
2723 /* On Everest 1 Ax chip versions for speeds less than
2724 10G LED scheme is different */
2725 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
2726 + port*4, 1);
2727 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 +
2728 port*4, 0);
2729 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_TRAFFIC_P0 +
2730 port*4, 1);
2731 }
2732 break;
2733
2734 default:
2735 rc = -EINVAL;
2736 DP(NETIF_MSG_LINK, "bnx2x_set_led: Invalid led mode %d\n",
2737 mode);
2738 break;
2739 }
2740 return rc;
2741
2742}
2743
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002744/**
2745 * This function comes to reflect the actual link state read DIRECTLY from the
2746 * HW
2747 */
2748u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars,
2749 u8 is_serdes)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002750{
2751 struct bnx2x *bp = params->bp;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002752 u16 gp_status = 0, phy_index = 0;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002753 u8 ext_phy_link_up = 0, serdes_phy_type;
2754 struct link_vars temp_vars;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002755
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002756 CL45_RD_OVER_CL22(bp, &params->phy[INT_PHY],
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002757 MDIO_REG_BANK_GP_STATUS,
2758 MDIO_GP_STATUS_TOP_AN_STATUS1,
2759 &gp_status);
2760 /* link is up only if both local phy and external phy are up */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002761 if (!(gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS))
2762 return -ESRCH;
2763
2764 switch (params->num_phys) {
2765 case 1:
2766 /* No external PHY */
2767 return 0;
2768 case 2:
2769 ext_phy_link_up = params->phy[EXT_PHY1].read_status(
2770 &params->phy[EXT_PHY1],
2771 params, &temp_vars);
2772 break;
2773 case 3: /* Dual Media */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002774 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
2775 phy_index++) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002776 serdes_phy_type = ((params->phy[phy_index].media_type ==
2777 ETH_PHY_SFP_FIBER) ||
2778 (params->phy[phy_index].media_type ==
2779 ETH_PHY_XFP_FIBER));
2780
2781 if (is_serdes != serdes_phy_type)
2782 continue;
2783 if (params->phy[phy_index].read_status) {
2784 ext_phy_link_up |=
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002785 params->phy[phy_index].read_status(
2786 &params->phy[phy_index],
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002787 params, &temp_vars);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002788 }
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002789 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002790 break;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002791 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002792 if (ext_phy_link_up)
2793 return 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002794 return -ESRCH;
2795}
2796
2797static u8 bnx2x_link_initialize(struct link_params *params,
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00002798 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002799{
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002800 u8 rc = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002801 u8 phy_index, non_ext_phy;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002802 struct bnx2x *bp = params->bp;
2803 /**
2804 * In case of external phy existence, the line speed would be the
2805 * line speed linked up by the external phy. In case it is direct
2806 * only, then the line_speed during initialization will be
2807 * equal to the req_line_speed
2808 */
2809 vars->line_speed = params->phy[INT_PHY].req_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002810
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002811 /**
2812 * Initialize the internal phy in case this is a direct board
2813 * (no external phys), or this board has external phy which requires
2814 * to first.
2815 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002816
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002817 if (params->phy[INT_PHY].config_init)
2818 params->phy[INT_PHY].config_init(
2819 &params->phy[INT_PHY],
2820 params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002821
2822 /* init ext phy and enable link state int */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002823 non_ext_phy = (SINGLE_MEDIA_DIRECT(params) ||
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002824 (params->loopback_mode == LOOPBACK_XGXS));
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002825
2826 if (non_ext_phy ||
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002827 (params->phy[EXT_PHY1].flags & FLAGS_INIT_XGXS_FIRST) ||
Eilon Greenstein8660d8c2009-03-02 08:01:02 +00002828 (params->loopback_mode == LOOPBACK_EXT_PHY)) {
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002829 struct bnx2x_phy *phy = &params->phy[INT_PHY];
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002830 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002831 bnx2x_set_parallel_detection(phy, params);
2832 bnx2x_init_internal_phy(phy, params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002833 }
2834
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002835 /* Init external phy*/
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002836 if (!non_ext_phy)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002837 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
2838 phy_index++) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002839 /**
2840 * No need to initialize second phy in case of first
2841 * phy only selection. In case of second phy, we do
2842 * need to initialize the first phy, since they are
2843 * connected.
2844 **/
2845 if (phy_index == EXT_PHY2 &&
2846 (bnx2x_phy_selection(params) ==
2847 PORT_HW_CFG_PHY_SELECTION_FIRST_PHY)) {
2848 DP(NETIF_MSG_LINK, "Not initializing"
2849 "second phy\n");
2850 continue;
2851 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002852 params->phy[phy_index].config_init(
2853 &params->phy[phy_index],
2854 params, vars);
2855 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002856
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00002857 /* Reset the interrupt indication after phy was initialized */
2858 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 +
2859 params->port*4,
2860 (NIG_STATUS_XGXS0_LINK10G |
2861 NIG_STATUS_XGXS0_LINK_STATUS |
2862 NIG_STATUS_SERDES0_LINK_STATUS |
2863 NIG_MASK_MI_INT));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002864 return rc;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002865}
2866
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002867static void bnx2x_int_link_reset(struct bnx2x_phy *phy,
2868 struct link_params *params)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002869{
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002870 /* reset the SerDes/XGXS */
2871 REG_WR(params->bp, GRCBASE_MISC +
2872 MISC_REGISTERS_RESET_REG_3_CLEAR,
2873 (0x1ff << (params->port*16)));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002874}
2875
2876static void bnx2x_common_ext_link_reset(struct bnx2x_phy *phy,
2877 struct link_params *params)
2878{
2879 struct bnx2x *bp = params->bp;
2880 u8 gpio_port;
2881 /* HW reset */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002882 if (CHIP_IS_E2(bp))
2883 gpio_port = BP_PATH(bp);
2884 else
2885 gpio_port = params->port;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002886 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
2887 MISC_REGISTERS_GPIO_OUTPUT_LOW,
2888 gpio_port);
2889 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
2890 MISC_REGISTERS_GPIO_OUTPUT_LOW,
2891 gpio_port);
2892 DP(NETIF_MSG_LINK, "reset external PHY\n");
2893}
2894
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002895static u8 bnx2x_update_link_down(struct link_params *params,
2896 struct link_vars *vars)
2897{
2898 struct bnx2x *bp = params->bp;
2899 u8 port = params->port;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002900
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002901 DP(NETIF_MSG_LINK, "Port %x: Link is down\n", port);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00002902 bnx2x_set_led(params, vars, LED_MODE_OFF, 0);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002903
2904 /* indicate no mac active */
2905 vars->mac_type = MAC_TYPE_NONE;
2906
2907 /* update shared memory */
2908 vars->link_status = 0;
2909 vars->line_speed = 0;
2910 bnx2x_update_mng(params, vars->link_status);
2911
2912 /* activate nig drain */
2913 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
2914
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002915 /* disable emac */
2916 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
2917
2918 msleep(10);
2919
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002920 /* reset BigMac */
2921 bnx2x_bmac_rx_disable(bp, params->port);
2922 REG_WR(bp, GRCBASE_MISC +
2923 MISC_REGISTERS_RESET_REG_2_CLEAR,
2924 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
2925 return 0;
2926}
2927
2928static u8 bnx2x_update_link_up(struct link_params *params,
2929 struct link_vars *vars,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002930 u8 link_10g)
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002931{
2932 struct bnx2x *bp = params->bp;
2933 u8 port = params->port;
2934 u8 rc = 0;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002935
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002936 vars->link_status |= LINK_STATUS_LINK_UP;
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00002937
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002938 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
2939 vars->link_status |=
2940 LINK_STATUS_TX_FLOW_CONTROL_ENABLED;
2941
2942 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
2943 vars->link_status |=
2944 LINK_STATUS_RX_FLOW_CONTROL_ENABLED;
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00002945
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002946 if (link_10g) {
2947 bnx2x_bmac_enable(params, vars, 0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00002948 bnx2x_set_led(params, vars,
2949 LED_MODE_OPER, SPEED_10000);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002950 } else {
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002951 rc = bnx2x_emac_program(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002952
Yaniv Rosner0c786f02009-11-05 19:18:32 +02002953 bnx2x_emac_enable(params, vars, 0);
2954
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002955 /* AN complete? */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002956 if ((vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE)
2957 && (!(vars->phy_flags & PHY_SGMII_FLAG)) &&
2958 SINGLE_MEDIA_DIRECT(params))
2959 bnx2x_set_gmii_tx_driver(params);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002960 }
2961
2962 /* PBF - link up */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002963 if (!(CHIP_IS_E2(bp)))
2964 rc |= bnx2x_pbf_update(params, vars->flow_ctrl,
2965 vars->line_speed);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002966
2967 /* disable drain */
2968 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 0);
2969
2970 /* update shared memory */
2971 bnx2x_update_mng(params, vars->link_status);
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002972 msleep(20);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002973 return rc;
2974}
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002975/**
2976 * The bnx2x_link_update function should be called upon link
2977 * interrupt.
2978 * Link is considered up as follows:
2979 * - DIRECT_SINGLE_MEDIA - Only XGXS link (internal link) needs
2980 * to be up
2981 * - SINGLE_MEDIA - The link between the 577xx and the external
2982 * phy (XGXS) need to up as well as the external link of the
2983 * phy (PHY_EXT1)
2984 * - DUAL_MEDIA - The link between the 577xx and the first
2985 * external phy needs to be up, and at least one of the 2
2986 * external phy link must be up.
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002987 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002988u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars)
2989{
2990 struct bnx2x *bp = params->bp;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002991 struct link_vars phy_vars[MAX_PHYS];
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002992 u8 port = params->port;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002993 u8 link_10g, phy_index;
2994 u8 ext_phy_link_up = 0, cur_link_up, rc = 0;
Eilon Greenstein2f904462009-08-12 08:22:16 +00002995 u8 is_mi_int = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002996 u16 ext_phy_line_speed = 0, prev_line_speed = vars->line_speed;
2997 u8 active_external_phy = INT_PHY;
2998 vars->link_status = 0;
2999 for (phy_index = INT_PHY; phy_index < params->num_phys;
3000 phy_index++) {
3001 phy_vars[phy_index].flow_ctrl = 0;
3002 phy_vars[phy_index].link_status = 0;
3003 phy_vars[phy_index].line_speed = 0;
3004 phy_vars[phy_index].duplex = DUPLEX_FULL;
3005 phy_vars[phy_index].phy_link_up = 0;
3006 phy_vars[phy_index].link_up = 0;
3007 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003008
3009 DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n",
Eilon Greenstein2f904462009-08-12 08:22:16 +00003010 port, (vars->phy_flags & PHY_XGXS_FLAG),
3011 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003012
Eilon Greenstein2f904462009-08-12 08:22:16 +00003013 is_mi_int = (u8)(REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT +
3014 port*0x18) > 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003015 DP(NETIF_MSG_LINK, "int_mask 0x%x MI_INT %x, SERDES_LINK %x\n",
Eilon Greenstein2f904462009-08-12 08:22:16 +00003016 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
3017 is_mi_int,
3018 REG_RD(bp,
3019 NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003020
3021 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
3022 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
3023 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
3024
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00003025 /* disable emac */
3026 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
3027
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003028 /**
3029 * Step 1:
3030 * Check external link change only for external phys, and apply
3031 * priority selection between them in case the link on both phys
3032 * is up. Note that the instead of the common vars, a temporary
3033 * vars argument is used since each phy may have different link/
3034 * speed/duplex result
3035 */
3036 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
3037 phy_index++) {
3038 struct bnx2x_phy *phy = &params->phy[phy_index];
3039 if (!phy->read_status)
3040 continue;
3041 /* Read link status and params of this ext phy */
3042 cur_link_up = phy->read_status(phy, params,
3043 &phy_vars[phy_index]);
3044 if (cur_link_up) {
3045 DP(NETIF_MSG_LINK, "phy in index %d link is up\n",
3046 phy_index);
3047 } else {
3048 DP(NETIF_MSG_LINK, "phy in index %d link is down\n",
3049 phy_index);
3050 continue;
3051 }
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003052
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003053 if (!ext_phy_link_up) {
3054 ext_phy_link_up = 1;
3055 active_external_phy = phy_index;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003056 } else {
3057 switch (bnx2x_phy_selection(params)) {
3058 case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT:
3059 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
3060 /**
3061 * In this option, the first PHY makes sure to pass the
3062 * traffic through itself only.
3063 * Its not clear how to reset the link on the second phy
3064 **/
3065 active_external_phy = EXT_PHY1;
3066 break;
3067 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
3068 /**
3069 * In this option, the first PHY makes sure to pass the
3070 * traffic through the second PHY.
3071 **/
3072 active_external_phy = EXT_PHY2;
3073 break;
3074 default:
3075 /**
3076 * Link indication on both PHYs with the following cases
3077 * is invalid:
3078 * - FIRST_PHY means that second phy wasn't initialized,
3079 * hence its link is expected to be down
3080 * - SECOND_PHY means that first phy should not be able
3081 * to link up by itself (using configuration)
3082 * - DEFAULT should be overriden during initialiazation
3083 **/
3084 DP(NETIF_MSG_LINK, "Invalid link indication"
3085 "mpc=0x%x. DISABLING LINK !!!\n",
3086 params->multi_phy_config);
3087 ext_phy_link_up = 0;
3088 break;
3089 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003090 }
3091 }
3092 prev_line_speed = vars->line_speed;
3093 /**
3094 * Step 2:
3095 * Read the status of the internal phy. In case of
3096 * DIRECT_SINGLE_MEDIA board, this link is the external link,
3097 * otherwise this is the link between the 577xx and the first
3098 * external phy
3099 */
3100 if (params->phy[INT_PHY].read_status)
3101 params->phy[INT_PHY].read_status(
3102 &params->phy[INT_PHY],
3103 params, vars);
3104 /**
3105 * The INT_PHY flow control reside in the vars. This include the
3106 * case where the speed or flow control are not set to AUTO.
3107 * Otherwise, the active external phy flow control result is set
3108 * to the vars. The ext_phy_line_speed is needed to check if the
3109 * speed is different between the internal phy and external phy.
3110 * This case may be result of intermediate link speed change.
3111 */
3112 if (active_external_phy > INT_PHY) {
3113 vars->flow_ctrl = phy_vars[active_external_phy].flow_ctrl;
3114 /**
3115 * Link speed is taken from the XGXS. AN and FC result from
3116 * the external phy.
3117 */
3118 vars->link_status |= phy_vars[active_external_phy].link_status;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003119
3120 /**
3121 * if active_external_phy is first PHY and link is up - disable
3122 * disable TX on second external PHY
3123 */
3124 if (active_external_phy == EXT_PHY1) {
3125 if (params->phy[EXT_PHY2].phy_specific_func) {
3126 DP(NETIF_MSG_LINK, "Disabling TX on"
3127 " EXT_PHY2\n");
3128 params->phy[EXT_PHY2].phy_specific_func(
3129 &params->phy[EXT_PHY2],
3130 params, DISABLE_TX);
3131 }
3132 }
3133
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003134 ext_phy_line_speed = phy_vars[active_external_phy].line_speed;
3135 vars->duplex = phy_vars[active_external_phy].duplex;
3136 if (params->phy[active_external_phy].supported &
3137 SUPPORTED_FIBRE)
3138 vars->link_status |= LINK_STATUS_SERDES_LINK;
3139 DP(NETIF_MSG_LINK, "Active external phy selected: %x\n",
3140 active_external_phy);
3141 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003142
3143 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
3144 phy_index++) {
3145 if (params->phy[phy_index].flags &
3146 FLAGS_REARM_LATCH_SIGNAL) {
3147 bnx2x_rearm_latch_signal(bp, port,
3148 phy_index ==
3149 active_external_phy);
3150 break;
3151 }
3152 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003153 DP(NETIF_MSG_LINK, "vars->flow_ctrl = 0x%x, vars->link_status = 0x%x,"
3154 " ext_phy_line_speed = %d\n", vars->flow_ctrl,
3155 vars->link_status, ext_phy_line_speed);
3156 /**
3157 * Upon link speed change set the NIG into drain mode. Comes to
3158 * deals with possible FIFO glitch due to clk change when speed
3159 * is decreased without link down indicator
3160 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003161
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003162 if (vars->phy_link_up) {
3163 if (!(SINGLE_MEDIA_DIRECT(params)) && ext_phy_link_up &&
3164 (ext_phy_line_speed != vars->line_speed)) {
3165 DP(NETIF_MSG_LINK, "Internal link speed %d is"
3166 " different than the external"
3167 " link speed %d\n", vars->line_speed,
3168 ext_phy_line_speed);
3169 vars->phy_link_up = 0;
3170 } else if (prev_line_speed != vars->line_speed) {
3171 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
3172 + params->port*4, 0);
3173 msleep(1);
3174 }
3175 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003176
3177 /* anything 10 and over uses the bmac */
3178 link_10g = ((vars->line_speed == SPEED_10000) ||
3179 (vars->line_speed == SPEED_12000) ||
3180 (vars->line_speed == SPEED_12500) ||
3181 (vars->line_speed == SPEED_13000) ||
3182 (vars->line_speed == SPEED_15000) ||
3183 (vars->line_speed == SPEED_16000));
3184
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003185 bnx2x_link_int_ack(params, vars, link_10g);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003186
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003187 /**
3188 * In case external phy link is up, and internal link is down
3189 * (not initialized yet probably after link initialization, it
3190 * needs to be initialized.
3191 * Note that after link down-up as result of cable plug, the xgxs
3192 * link would probably become up again without the need
3193 * initialize it
3194 */
3195 if (!(SINGLE_MEDIA_DIRECT(params))) {
3196 DP(NETIF_MSG_LINK, "ext_phy_link_up = %d, int_link_up = %d,"
3197 " init_preceding = %d\n", ext_phy_link_up,
3198 vars->phy_link_up,
3199 params->phy[EXT_PHY1].flags &
3200 FLAGS_INIT_XGXS_FIRST);
3201 if (!(params->phy[EXT_PHY1].flags &
3202 FLAGS_INIT_XGXS_FIRST)
3203 && ext_phy_link_up && !vars->phy_link_up) {
3204 vars->line_speed = ext_phy_line_speed;
3205 if (vars->line_speed < SPEED_1000)
3206 vars->phy_flags |= PHY_SGMII_FLAG;
3207 else
3208 vars->phy_flags &= ~PHY_SGMII_FLAG;
3209 bnx2x_init_internal_phy(&params->phy[INT_PHY],
3210 params,
3211 vars);
3212 }
3213 }
3214 /**
3215 * Link is up only if both local phy and external phy (in case of
3216 * non-direct board) are up
3217 */
3218 vars->link_up = (vars->phy_link_up &&
3219 (ext_phy_link_up ||
3220 SINGLE_MEDIA_DIRECT(params)));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003221
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003222 if (vars->link_up)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003223 rc = bnx2x_update_link_up(params, vars, link_10g);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003224 else
3225 rc = bnx2x_update_link_down(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003226
3227 return rc;
3228}
3229
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003230
3231/*****************************************************************************/
3232/* External Phy section */
3233/*****************************************************************************/
3234void bnx2x_ext_phy_hw_reset(struct bnx2x *bp, u8 port)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003235{
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003236 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
3237 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
3238 msleep(1);
3239 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
3240 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003241}
3242
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003243static void bnx2x_save_spirom_version(struct bnx2x *bp, u8 port,
3244 u32 spirom_ver, u32 ver_addr)
3245{
3246 DP(NETIF_MSG_LINK, "FW version 0x%x:0x%x for port %d\n",
3247 (u16)(spirom_ver>>16), (u16)spirom_ver, port);
3248
3249 if (ver_addr)
3250 REG_WR(bp, ver_addr, spirom_ver);
3251}
3252
3253static void bnx2x_save_bcm_spirom_ver(struct bnx2x *bp,
3254 struct bnx2x_phy *phy,
3255 u8 port)
3256{
3257 u16 fw_ver1, fw_ver2;
3258
3259 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
3260 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
3261 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
3262 MDIO_PMA_REG_ROM_VER2, &fw_ver2);
3263 bnx2x_save_spirom_version(bp, port, (u32)(fw_ver1<<16 | fw_ver2),
3264 phy->ver_addr);
3265}
3266
3267static void bnx2x_ext_phy_set_pause(struct link_params *params,
3268 struct bnx2x_phy *phy,
3269 struct link_vars *vars)
3270{
3271 u16 val;
3272 struct bnx2x *bp = params->bp;
3273 /* read modify write pause advertizing */
3274 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV_PAUSE, &val);
3275
3276 val &= ~MDIO_AN_REG_ADV_PAUSE_BOTH;
3277
3278 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
3279 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
3280 if ((vars->ieee_fc &
3281 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
3282 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
3283 val |= MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC;
3284 }
3285 if ((vars->ieee_fc &
3286 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
3287 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
3288 val |= MDIO_AN_REG_ADV_PAUSE_PAUSE;
3289 }
3290 DP(NETIF_MSG_LINK, "Ext phy AN advertize 0x%x\n", val);
3291 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV_PAUSE, val);
3292}
3293
3294static u8 bnx2x_ext_phy_resolve_fc(struct bnx2x_phy *phy,
3295 struct link_params *params,
3296 struct link_vars *vars)
3297{
3298 struct bnx2x *bp = params->bp;
3299 u16 ld_pause; /* local */
3300 u16 lp_pause; /* link partner */
3301 u16 pause_result;
3302 u8 ret = 0;
3303 /* read twice */
3304
3305 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
3306
3307 if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO)
3308 vars->flow_ctrl = phy->req_flow_ctrl;
3309 else if (phy->req_line_speed != SPEED_AUTO_NEG)
3310 vars->flow_ctrl = params->req_fc_auto_adv;
3311 else if (vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE) {
3312 ret = 1;
3313 bnx2x_cl45_read(bp, phy,
3314 MDIO_AN_DEVAD,
3315 MDIO_AN_REG_ADV_PAUSE, &ld_pause);
3316 bnx2x_cl45_read(bp, phy,
3317 MDIO_AN_DEVAD,
3318 MDIO_AN_REG_LP_AUTO_NEG, &lp_pause);
3319 pause_result = (ld_pause &
3320 MDIO_AN_REG_ADV_PAUSE_MASK) >> 8;
3321 pause_result |= (lp_pause &
3322 MDIO_AN_REG_ADV_PAUSE_MASK) >> 10;
3323 DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x\n",
3324 pause_result);
3325 bnx2x_pause_resolve(vars, pause_result);
3326 }
3327 return ret;
3328}
3329
3330static void bnx2x_ext_phy_10G_an_resolve(struct bnx2x *bp,
3331 struct bnx2x_phy *phy,
3332 struct link_vars *vars)
3333{
3334 u16 val;
3335 bnx2x_cl45_read(bp, phy,
3336 MDIO_AN_DEVAD,
3337 MDIO_AN_REG_STATUS, &val);
3338 bnx2x_cl45_read(bp, phy,
3339 MDIO_AN_DEVAD,
3340 MDIO_AN_REG_STATUS, &val);
3341 if (val & (1<<5))
3342 vars->link_status |= LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
3343 if ((val & (1<<0)) == 0)
3344 vars->link_status |= LINK_STATUS_PARALLEL_DETECTION_USED;
3345}
3346
3347/******************************************************************/
3348/* common BCM8073/BCM8727 PHY SECTION */
3349/******************************************************************/
3350static void bnx2x_8073_resolve_fc(struct bnx2x_phy *phy,
3351 struct link_params *params,
3352 struct link_vars *vars)
3353{
3354 struct bnx2x *bp = params->bp;
3355 if (phy->req_line_speed == SPEED_10 ||
3356 phy->req_line_speed == SPEED_100) {
3357 vars->flow_ctrl = phy->req_flow_ctrl;
3358 return;
3359 }
3360
3361 if (bnx2x_ext_phy_resolve_fc(phy, params, vars) &&
3362 (vars->flow_ctrl == BNX2X_FLOW_CTRL_NONE)) {
3363 u16 pause_result;
3364 u16 ld_pause; /* local */
3365 u16 lp_pause; /* link partner */
3366 bnx2x_cl45_read(bp, phy,
3367 MDIO_AN_DEVAD,
3368 MDIO_AN_REG_CL37_FC_LD, &ld_pause);
3369
3370 bnx2x_cl45_read(bp, phy,
3371 MDIO_AN_DEVAD,
3372 MDIO_AN_REG_CL37_FC_LP, &lp_pause);
3373 pause_result = (ld_pause &
3374 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 5;
3375 pause_result |= (lp_pause &
3376 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 7;
3377
3378 bnx2x_pause_resolve(vars, pause_result);
3379 DP(NETIF_MSG_LINK, "Ext PHY CL37 pause result 0x%x\n",
3380 pause_result);
3381 }
3382}
3383
3384static void bnx2x_8073_8727_external_rom_boot(struct bnx2x *bp,
3385 struct bnx2x_phy *phy,
3386 u8 port)
3387{
3388 /* Boot port from external ROM */
3389 /* EDC grst */
3390 bnx2x_cl45_write(bp, phy,
3391 MDIO_PMA_DEVAD,
3392 MDIO_PMA_REG_GEN_CTRL,
3393 0x0001);
3394
3395 /* ucode reboot and rst */
3396 bnx2x_cl45_write(bp, phy,
3397 MDIO_PMA_DEVAD,
3398 MDIO_PMA_REG_GEN_CTRL,
3399 0x008c);
3400
3401 bnx2x_cl45_write(bp, phy,
3402 MDIO_PMA_DEVAD,
3403 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
3404
3405 /* Reset internal microprocessor */
3406 bnx2x_cl45_write(bp, phy,
3407 MDIO_PMA_DEVAD,
3408 MDIO_PMA_REG_GEN_CTRL,
3409 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
3410
3411 /* Release srst bit */
3412 bnx2x_cl45_write(bp, phy,
3413 MDIO_PMA_DEVAD,
3414 MDIO_PMA_REG_GEN_CTRL,
3415 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
3416
3417 /* wait for 120ms for code download via SPI port */
3418 msleep(120);
3419
3420 /* Clear ser_boot_ctl bit */
3421 bnx2x_cl45_write(bp, phy,
3422 MDIO_PMA_DEVAD,
3423 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
3424 bnx2x_save_bcm_spirom_ver(bp, phy, port);
3425}
3426
3427static void bnx2x_8073_set_xaui_low_power_mode(struct bnx2x *bp,
3428 struct bnx2x_phy *phy)
3429{
3430 u16 val;
3431 bnx2x_cl45_read(bp, phy,
3432 MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_CHIP_REV, &val);
3433
3434 if (val == 0) {
3435 /* Mustn't set low power mode in 8073 A0 */
3436 return;
3437 }
3438
3439 /* Disable PLL sequencer (use read-modify-write to clear bit 13) */
3440 bnx2x_cl45_read(bp, phy,
3441 MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, &val);
3442 val &= ~(1<<13);
3443 bnx2x_cl45_write(bp, phy,
3444 MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
3445
3446 /* PLL controls */
3447 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805E, 0x1077);
3448 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805D, 0x0000);
3449 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805C, 0x030B);
3450 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805B, 0x1240);
3451 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805A, 0x2490);
3452
3453 /* Tx Controls */
3454 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80A7, 0x0C74);
3455 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80A6, 0x9041);
3456 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80A5, 0x4640);
3457
3458 /* Rx Controls */
3459 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80FE, 0x01C4);
3460 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80FD, 0x9249);
3461 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80FC, 0x2015);
3462
3463 /* Enable PLL sequencer (use read-modify-write to set bit 13) */
3464 bnx2x_cl45_read(bp, phy, MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, &val);
3465 val |= (1<<13);
3466 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
3467}
3468
3469/******************************************************************/
3470/* BCM8073 PHY SECTION */
3471/******************************************************************/
3472static u8 bnx2x_8073_is_snr_needed(struct bnx2x *bp, struct bnx2x_phy *phy)
3473{
3474 /* This is only required for 8073A1, version 102 only */
3475 u16 val;
3476
3477 /* Read 8073 HW revision*/
3478 bnx2x_cl45_read(bp, phy,
3479 MDIO_PMA_DEVAD,
3480 MDIO_PMA_REG_8073_CHIP_REV, &val);
3481
3482 if (val != 1) {
3483 /* No need to workaround in 8073 A1 */
3484 return 0;
3485 }
3486
3487 bnx2x_cl45_read(bp, phy,
3488 MDIO_PMA_DEVAD,
3489 MDIO_PMA_REG_ROM_VER2, &val);
3490
3491 /* SNR should be applied only for version 0x102 */
3492 if (val != 0x102)
3493 return 0;
3494
3495 return 1;
3496}
3497
3498static u8 bnx2x_8073_xaui_wa(struct bnx2x *bp, struct bnx2x_phy *phy)
3499{
3500 u16 val, cnt, cnt1 ;
3501
3502 bnx2x_cl45_read(bp, phy,
3503 MDIO_PMA_DEVAD,
3504 MDIO_PMA_REG_8073_CHIP_REV, &val);
3505
3506 if (val > 0) {
3507 /* No need to workaround in 8073 A1 */
3508 return 0;
3509 }
3510 /* XAUI workaround in 8073 A0: */
3511
3512 /* After loading the boot ROM and restarting Autoneg,
3513 poll Dev1, Reg $C820: */
3514
3515 for (cnt = 0; cnt < 1000; cnt++) {
3516 bnx2x_cl45_read(bp, phy,
3517 MDIO_PMA_DEVAD,
3518 MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
3519 &val);
3520 /* If bit [14] = 0 or bit [13] = 0, continue on with
3521 system initialization (XAUI work-around not required,
3522 as these bits indicate 2.5G or 1G link up). */
3523 if (!(val & (1<<14)) || !(val & (1<<13))) {
3524 DP(NETIF_MSG_LINK, "XAUI work-around not required\n");
3525 return 0;
3526 } else if (!(val & (1<<15))) {
3527 DP(NETIF_MSG_LINK, "clc bit 15 went off\n");
3528 /* If bit 15 is 0, then poll Dev1, Reg $C841 until
3529 it's MSB (bit 15) goes to 1 (indicating that the
3530 XAUI workaround has completed),
3531 then continue on with system initialization.*/
3532 for (cnt1 = 0; cnt1 < 1000; cnt1++) {
3533 bnx2x_cl45_read(bp, phy,
3534 MDIO_PMA_DEVAD,
3535 MDIO_PMA_REG_8073_XAUI_WA, &val);
3536 if (val & (1<<15)) {
3537 DP(NETIF_MSG_LINK,
3538 "XAUI workaround has completed\n");
3539 return 0;
3540 }
3541 msleep(3);
3542 }
3543 break;
3544 }
3545 msleep(3);
3546 }
3547 DP(NETIF_MSG_LINK, "Warning: XAUI work-around timeout !!!\n");
3548 return -EINVAL;
3549}
3550
3551static void bnx2x_807x_force_10G(struct bnx2x *bp, struct bnx2x_phy *phy)
3552{
3553 /* Force KR or KX */
3554 bnx2x_cl45_write(bp, phy,
3555 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x2040);
3556 bnx2x_cl45_write(bp, phy,
3557 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0x000b);
3558 bnx2x_cl45_write(bp, phy,
3559 MDIO_PMA_DEVAD, MDIO_PMA_REG_BCM_CTRL, 0x0000);
3560 bnx2x_cl45_write(bp, phy,
3561 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x0000);
3562}
3563
3564static void bnx2x_8073_set_pause_cl37(struct link_params *params,
3565 struct bnx2x_phy *phy,
3566 struct link_vars *vars)
3567{
3568 u16 cl37_val;
3569 struct bnx2x *bp = params->bp;
3570 bnx2x_cl45_read(bp, phy,
3571 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, &cl37_val);
3572
3573 cl37_val &= ~MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
3574 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
3575 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
3576 if ((vars->ieee_fc &
3577 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) ==
3578 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) {
3579 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC;
3580 }
3581 if ((vars->ieee_fc &
3582 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
3583 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
3584 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
3585 }
3586 if ((vars->ieee_fc &
3587 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
3588 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
3589 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
3590 }
3591 DP(NETIF_MSG_LINK,
3592 "Ext phy AN advertize cl37 0x%x\n", cl37_val);
3593
3594 bnx2x_cl45_write(bp, phy,
3595 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, cl37_val);
3596 msleep(500);
3597}
3598
3599static u8 bnx2x_8073_config_init(struct bnx2x_phy *phy,
3600 struct link_params *params,
3601 struct link_vars *vars)
3602{
3603 struct bnx2x *bp = params->bp;
3604 u16 val = 0, tmp1;
3605 u8 gpio_port;
3606 DP(NETIF_MSG_LINK, "Init 8073\n");
3607
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00003608 if (CHIP_IS_E2(bp))
3609 gpio_port = BP_PATH(bp);
3610 else
3611 gpio_port = params->port;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003612 /* Restore normal power mode*/
3613 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
3614 MISC_REGISTERS_GPIO_OUTPUT_HIGH, gpio_port);
3615
3616 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
3617 MISC_REGISTERS_GPIO_OUTPUT_HIGH, gpio_port);
3618
3619 /* enable LASI */
3620 bnx2x_cl45_write(bp, phy,
3621 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL, (1<<2));
3622 bnx2x_cl45_write(bp, phy,
3623 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x0004);
3624
3625 bnx2x_8073_set_pause_cl37(params, phy, vars);
3626
3627 bnx2x_8073_set_xaui_low_power_mode(bp, phy);
3628
3629 bnx2x_cl45_read(bp, phy,
3630 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &tmp1);
3631
3632 bnx2x_cl45_read(bp, phy,
3633 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &tmp1);
3634
3635 DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1): 0x%x\n", tmp1);
3636
3637 /* Enable CL37 BAM */
3638 bnx2x_cl45_read(bp, phy,
3639 MDIO_AN_DEVAD,
3640 MDIO_AN_REG_8073_BAM, &val);
3641 bnx2x_cl45_write(bp, phy,
3642 MDIO_AN_DEVAD,
3643 MDIO_AN_REG_8073_BAM, val | 1);
3644
3645 if (params->loopback_mode == LOOPBACK_EXT) {
3646 bnx2x_807x_force_10G(bp, phy);
3647 DP(NETIF_MSG_LINK, "Forced speed 10G on 807X\n");
3648 return 0;
3649 } else {
3650 bnx2x_cl45_write(bp, phy,
3651 MDIO_PMA_DEVAD, MDIO_PMA_REG_BCM_CTRL, 0x0002);
3652 }
3653 if (phy->req_line_speed != SPEED_AUTO_NEG) {
3654 if (phy->req_line_speed == SPEED_10000) {
3655 val = (1<<7);
3656 } else if (phy->req_line_speed == SPEED_2500) {
3657 val = (1<<5);
3658 /* Note that 2.5G works only
3659 when used with 1G advertisment */
3660 } else
3661 val = (1<<5);
3662 } else {
3663 val = 0;
3664 if (phy->speed_cap_mask &
3665 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
3666 val |= (1<<7);
3667
3668 /* Note that 2.5G works only when
3669 used with 1G advertisment */
3670 if (phy->speed_cap_mask &
3671 (PORT_HW_CFG_SPEED_CAPABILITY_D0_1G |
3672 PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G))
3673 val |= (1<<5);
3674 DP(NETIF_MSG_LINK, "807x autoneg val = 0x%x\n", val);
3675 }
3676
3677 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV, val);
3678 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_8073_2_5G, &tmp1);
3679
3680 if (((phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G) &&
3681 (phy->req_line_speed == SPEED_AUTO_NEG)) ||
3682 (phy->req_line_speed == SPEED_2500)) {
3683 u16 phy_ver;
3684 /* Allow 2.5G for A1 and above */
3685 bnx2x_cl45_read(bp, phy,
3686 MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_CHIP_REV,
3687 &phy_ver);
3688 DP(NETIF_MSG_LINK, "Add 2.5G\n");
3689 if (phy_ver > 0)
3690 tmp1 |= 1;
3691 else
3692 tmp1 &= 0xfffe;
3693 } else {
3694 DP(NETIF_MSG_LINK, "Disable 2.5G\n");
3695 tmp1 &= 0xfffe;
3696 }
3697
3698 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_8073_2_5G, tmp1);
3699 /* Add support for CL37 (passive mode) II */
3700
3701 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, &tmp1);
3702 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD,
3703 (tmp1 | ((phy->req_duplex == DUPLEX_FULL) ?
3704 0x20 : 0x40)));
3705
3706 /* Add support for CL37 (passive mode) III */
3707 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
3708
3709 /* The SNR will improve about 2db by changing
3710 BW and FEE main tap. Rest commands are executed
3711 after link is up*/
3712 if (bnx2x_8073_is_snr_needed(bp, phy))
3713 bnx2x_cl45_write(bp, phy,
3714 MDIO_PMA_DEVAD, MDIO_PMA_REG_EDC_FFE_MAIN,
3715 0xFB0C);
3716
3717 /* Enable FEC (Forware Error Correction) Request in the AN */
3718 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV2, &tmp1);
3719 tmp1 |= (1<<15);
3720 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV2, tmp1);
3721
3722 bnx2x_ext_phy_set_pause(params, phy, vars);
3723
3724 /* Restart autoneg */
3725 msleep(500);
3726 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
3727 DP(NETIF_MSG_LINK, "807x Autoneg Restart: Advertise 1G=%x, 10G=%x\n",
3728 ((val & (1<<5)) > 0), ((val & (1<<7)) > 0));
3729 return 0;
3730}
3731
3732static u8 bnx2x_8073_read_status(struct bnx2x_phy *phy,
3733 struct link_params *params,
3734 struct link_vars *vars)
3735{
3736 struct bnx2x *bp = params->bp;
3737 u8 link_up = 0;
3738 u16 val1, val2;
3739 u16 link_status = 0;
3740 u16 an1000_status = 0;
3741
3742 bnx2x_cl45_read(bp, phy,
3743 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
3744
3745 DP(NETIF_MSG_LINK, "8703 LASI status 0x%x\n", val1);
3746
3747 /* clear the interrupt LASI status register */
3748 bnx2x_cl45_read(bp, phy,
3749 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val2);
3750 bnx2x_cl45_read(bp, phy,
3751 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val1);
3752 DP(NETIF_MSG_LINK, "807x PCS status 0x%x->0x%x\n", val2, val1);
3753 /* Clear MSG-OUT */
3754 bnx2x_cl45_read(bp, phy,
3755 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &val1);
3756
3757 /* Check the LASI */
3758 bnx2x_cl45_read(bp, phy,
3759 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &val2);
3760
3761 DP(NETIF_MSG_LINK, "KR 0x9003 0x%x\n", val2);
3762
3763 /* Check the link status */
3764 bnx2x_cl45_read(bp, phy,
3765 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val2);
3766 DP(NETIF_MSG_LINK, "KR PCS status 0x%x\n", val2);
3767
3768 bnx2x_cl45_read(bp, phy,
3769 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
3770 bnx2x_cl45_read(bp, phy,
3771 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
3772 link_up = ((val1 & 4) == 4);
3773 DP(NETIF_MSG_LINK, "PMA_REG_STATUS=0x%x\n", val1);
3774
3775 if (link_up &&
3776 ((phy->req_line_speed != SPEED_10000))) {
3777 if (bnx2x_8073_xaui_wa(bp, phy) != 0)
3778 return 0;
3779 }
3780 bnx2x_cl45_read(bp, phy,
3781 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &an1000_status);
3782 bnx2x_cl45_read(bp, phy,
3783 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &an1000_status);
3784
3785 /* Check the link status on 1.1.2 */
3786 bnx2x_cl45_read(bp, phy,
3787 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
3788 bnx2x_cl45_read(bp, phy,
3789 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
3790 DP(NETIF_MSG_LINK, "KR PMA status 0x%x->0x%x,"
3791 "an_link_status=0x%x\n", val2, val1, an1000_status);
3792
3793 link_up = (((val1 & 4) == 4) || (an1000_status & (1<<1)));
3794 if (link_up && bnx2x_8073_is_snr_needed(bp, phy)) {
3795 /* The SNR will improve about 2dbby
3796 changing the BW and FEE main tap.*/
3797 /* The 1st write to change FFE main
3798 tap is set before restart AN */
3799 /* Change PLL Bandwidth in EDC
3800 register */
3801 bnx2x_cl45_write(bp, phy,
3802 MDIO_PMA_DEVAD, MDIO_PMA_REG_PLL_BANDWIDTH,
3803 0x26BC);
3804
3805 /* Change CDR Bandwidth in EDC register */
3806 bnx2x_cl45_write(bp, phy,
3807 MDIO_PMA_DEVAD, MDIO_PMA_REG_CDR_BANDWIDTH,
3808 0x0333);
3809 }
3810 bnx2x_cl45_read(bp, phy,
3811 MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
3812 &link_status);
3813
3814 /* Bits 0..2 --> speed detected, bits 13..15--> link is down */
3815 if ((link_status & (1<<2)) && (!(link_status & (1<<15)))) {
3816 link_up = 1;
3817 vars->line_speed = SPEED_10000;
3818 DP(NETIF_MSG_LINK, "port %x: External link up in 10G\n",
3819 params->port);
3820 } else if ((link_status & (1<<1)) && (!(link_status & (1<<14)))) {
3821 link_up = 1;
3822 vars->line_speed = SPEED_2500;
3823 DP(NETIF_MSG_LINK, "port %x: External link up in 2.5G\n",
3824 params->port);
3825 } else if ((link_status & (1<<0)) && (!(link_status & (1<<13)))) {
3826 link_up = 1;
3827 vars->line_speed = SPEED_1000;
3828 DP(NETIF_MSG_LINK, "port %x: External link up in 1G\n",
3829 params->port);
3830 } else {
3831 link_up = 0;
3832 DP(NETIF_MSG_LINK, "port %x: External link is down\n",
3833 params->port);
3834 }
3835
3836 if (link_up) {
3837 bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
3838 bnx2x_8073_resolve_fc(phy, params, vars);
3839 }
3840 return link_up;
3841}
3842
3843static void bnx2x_8073_link_reset(struct bnx2x_phy *phy,
3844 struct link_params *params)
3845{
3846 struct bnx2x *bp = params->bp;
3847 u8 gpio_port;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00003848 if (CHIP_IS_E2(bp))
3849 gpio_port = BP_PATH(bp);
3850 else
3851 gpio_port = params->port;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003852 DP(NETIF_MSG_LINK, "Setting 8073 port %d into low power mode\n",
3853 gpio_port);
3854 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
3855 MISC_REGISTERS_GPIO_OUTPUT_LOW,
3856 gpio_port);
3857}
3858
3859/******************************************************************/
3860/* BCM8705 PHY SECTION */
3861/******************************************************************/
3862static u8 bnx2x_8705_config_init(struct bnx2x_phy *phy,
3863 struct link_params *params,
3864 struct link_vars *vars)
3865{
3866 struct bnx2x *bp = params->bp;
3867 DP(NETIF_MSG_LINK, "init 8705\n");
3868 /* Restore normal power mode*/
3869 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
3870 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
3871 /* HW reset */
3872 bnx2x_ext_phy_hw_reset(bp, params->port);
3873 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0xa040);
3874 bnx2x_wait_reset_complete(bp, phy);
3875
3876 bnx2x_cl45_write(bp, phy,
3877 MDIO_PMA_DEVAD, MDIO_PMA_REG_MISC_CTRL, 0x8288);
3878 bnx2x_cl45_write(bp, phy,
3879 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, 0x7fbf);
3880 bnx2x_cl45_write(bp, phy,
3881 MDIO_PMA_DEVAD, MDIO_PMA_REG_CMU_PLL_BYPASS, 0x0100);
3882 bnx2x_cl45_write(bp, phy,
3883 MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_CNTL, 0x1);
3884 /* BCM8705 doesn't have microcode, hence the 0 */
3885 bnx2x_save_spirom_version(bp, params->port, params->shmem_base, 0);
3886 return 0;
3887}
3888
3889static u8 bnx2x_8705_read_status(struct bnx2x_phy *phy,
3890 struct link_params *params,
3891 struct link_vars *vars)
3892{
3893 u8 link_up = 0;
3894 u16 val1, rx_sd;
3895 struct bnx2x *bp = params->bp;
3896 DP(NETIF_MSG_LINK, "read status 8705\n");
3897 bnx2x_cl45_read(bp, phy,
3898 MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_STATUS, &val1);
3899 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
3900
3901 bnx2x_cl45_read(bp, phy,
3902 MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_STATUS, &val1);
3903 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
3904
3905 bnx2x_cl45_read(bp, phy,
3906 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD, &rx_sd);
3907
3908 bnx2x_cl45_read(bp, phy,
3909 MDIO_PMA_DEVAD, 0xc809, &val1);
3910 bnx2x_cl45_read(bp, phy,
3911 MDIO_PMA_DEVAD, 0xc809, &val1);
3912
3913 DP(NETIF_MSG_LINK, "8705 1.c809 val=0x%x\n", val1);
3914 link_up = ((rx_sd & 0x1) && (val1 & (1<<9)) && ((val1 & (1<<8)) == 0));
3915 if (link_up) {
3916 vars->line_speed = SPEED_10000;
3917 bnx2x_ext_phy_resolve_fc(phy, params, vars);
3918 }
3919 return link_up;
3920}
3921
3922/******************************************************************/
3923/* SFP+ module Section */
3924/******************************************************************/
3925static void bnx2x_sfp_set_transmitter(struct bnx2x *bp,
3926 struct bnx2x_phy *phy,
3927 u8 port,
3928 u8 tx_en)
3929{
3930 u16 val;
3931
3932 DP(NETIF_MSG_LINK, "Setting transmitter tx_en=%x for port %x\n",
3933 tx_en, port);
3934 /* Disable/Enable transmitter ( TX laser of the SFP+ module.)*/
3935 bnx2x_cl45_read(bp, phy,
3936 MDIO_PMA_DEVAD,
3937 MDIO_PMA_REG_PHY_IDENTIFIER,
3938 &val);
3939
3940 if (tx_en)
3941 val &= ~(1<<15);
3942 else
3943 val |= (1<<15);
3944
3945 bnx2x_cl45_write(bp, phy,
3946 MDIO_PMA_DEVAD,
3947 MDIO_PMA_REG_PHY_IDENTIFIER,
3948 val);
3949}
3950
3951static u8 bnx2x_8726_read_sfp_module_eeprom(struct bnx2x_phy *phy,
3952 struct link_params *params,
3953 u16 addr, u8 byte_cnt, u8 *o_buf)
3954{
3955 struct bnx2x *bp = params->bp;
3956 u16 val = 0;
3957 u16 i;
3958 if (byte_cnt > 16) {
3959 DP(NETIF_MSG_LINK, "Reading from eeprom is"
3960 " is limited to 0xf\n");
3961 return -EINVAL;
3962 }
3963 /* Set the read command byte count */
3964 bnx2x_cl45_write(bp, phy,
3965 MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
3966 (byte_cnt | 0xa000));
3967
3968 /* Set the read command address */
3969 bnx2x_cl45_write(bp, phy,
3970 MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
3971 addr);
3972
3973 /* Activate read command */
3974 bnx2x_cl45_write(bp, phy,
3975 MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
3976 0x2c0f);
3977
3978 /* Wait up to 500us for command complete status */
3979 for (i = 0; i < 100; i++) {
3980 bnx2x_cl45_read(bp, phy,
3981 MDIO_PMA_DEVAD,
3982 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
3983 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
3984 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
3985 break;
3986 udelay(5);
3987 }
3988
3989 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
3990 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
3991 DP(NETIF_MSG_LINK,
3992 "Got bad status 0x%x when reading from SFP+ EEPROM\n",
3993 (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
3994 return -EINVAL;
3995 }
3996
3997 /* Read the buffer */
3998 for (i = 0; i < byte_cnt; i++) {
3999 bnx2x_cl45_read(bp, phy,
4000 MDIO_PMA_DEVAD,
4001 MDIO_PMA_REG_8726_TWO_WIRE_DATA_BUF + i, &val);
4002 o_buf[i] = (u8)(val & MDIO_PMA_REG_8726_TWO_WIRE_DATA_MASK);
4003 }
4004
4005 for (i = 0; i < 100; i++) {
4006 bnx2x_cl45_read(bp, phy,
4007 MDIO_PMA_DEVAD,
4008 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
4009 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
4010 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
4011 return 0;;
4012 msleep(1);
4013 }
4014 return -EINVAL;
4015}
4016
4017static u8 bnx2x_8727_read_sfp_module_eeprom(struct bnx2x_phy *phy,
4018 struct link_params *params,
4019 u16 addr, u8 byte_cnt, u8 *o_buf)
4020{
4021 struct bnx2x *bp = params->bp;
4022 u16 val, i;
4023
4024 if (byte_cnt > 16) {
4025 DP(NETIF_MSG_LINK, "Reading from eeprom is"
4026 " is limited to 0xf\n");
4027 return -EINVAL;
4028 }
4029
4030 /* Need to read from 1.8000 to clear it */
4031 bnx2x_cl45_read(bp, phy,
4032 MDIO_PMA_DEVAD,
4033 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
4034 &val);
4035
4036 /* Set the read command byte count */
4037 bnx2x_cl45_write(bp, phy,
4038 MDIO_PMA_DEVAD,
4039 MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
4040 ((byte_cnt < 2) ? 2 : byte_cnt));
4041
4042 /* Set the read command address */
4043 bnx2x_cl45_write(bp, phy,
4044 MDIO_PMA_DEVAD,
4045 MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
4046 addr);
4047 /* Set the destination address */
4048 bnx2x_cl45_write(bp, phy,
4049 MDIO_PMA_DEVAD,
4050 0x8004,
4051 MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF);
4052
4053 /* Activate read command */
4054 bnx2x_cl45_write(bp, phy,
4055 MDIO_PMA_DEVAD,
4056 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
4057 0x8002);
4058 /* Wait appropriate time for two-wire command to finish before
4059 polling the status register */
4060 msleep(1);
4061
4062 /* Wait up to 500us for command complete status */
4063 for (i = 0; i < 100; i++) {
4064 bnx2x_cl45_read(bp, phy,
4065 MDIO_PMA_DEVAD,
4066 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
4067 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
4068 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
4069 break;
4070 udelay(5);
4071 }
4072
4073 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
4074 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
4075 DP(NETIF_MSG_LINK,
4076 "Got bad status 0x%x when reading from SFP+ EEPROM\n",
4077 (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
4078 return -EINVAL;
4079 }
4080
4081 /* Read the buffer */
4082 for (i = 0; i < byte_cnt; i++) {
4083 bnx2x_cl45_read(bp, phy,
4084 MDIO_PMA_DEVAD,
4085 MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF + i, &val);
4086 o_buf[i] = (u8)(val & MDIO_PMA_REG_8727_TWO_WIRE_DATA_MASK);
4087 }
4088
4089 for (i = 0; i < 100; i++) {
4090 bnx2x_cl45_read(bp, phy,
4091 MDIO_PMA_DEVAD,
4092 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
4093 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
4094 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
4095 return 0;;
4096 msleep(1);
4097 }
4098
4099 return -EINVAL;
4100}
4101
4102u8 bnx2x_read_sfp_module_eeprom(struct bnx2x_phy *phy,
4103 struct link_params *params, u16 addr,
4104 u8 byte_cnt, u8 *o_buf)
4105{
4106 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
4107 return bnx2x_8726_read_sfp_module_eeprom(phy, params, addr,
4108 byte_cnt, o_buf);
4109 else if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
4110 return bnx2x_8727_read_sfp_module_eeprom(phy, params, addr,
4111 byte_cnt, o_buf);
4112 return -EINVAL;
4113}
4114
4115static u8 bnx2x_get_edc_mode(struct bnx2x_phy *phy,
4116 struct link_params *params,
4117 u16 *edc_mode)
4118{
4119 struct bnx2x *bp = params->bp;
4120 u8 val, check_limiting_mode = 0;
4121 *edc_mode = EDC_MODE_LIMITING;
4122
4123 /* First check for copper cable */
4124 if (bnx2x_read_sfp_module_eeprom(phy,
4125 params,
4126 SFP_EEPROM_CON_TYPE_ADDR,
4127 1,
4128 &val) != 0) {
4129 DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM\n");
4130 return -EINVAL;
4131 }
4132
4133 switch (val) {
4134 case SFP_EEPROM_CON_TYPE_VAL_COPPER:
4135 {
4136 u8 copper_module_type;
4137
4138 /* Check if its active cable( includes SFP+ module)
4139 of passive cable*/
4140 if (bnx2x_read_sfp_module_eeprom(phy,
4141 params,
4142 SFP_EEPROM_FC_TX_TECH_ADDR,
4143 1,
4144 &copper_module_type) !=
4145 0) {
4146 DP(NETIF_MSG_LINK,
4147 "Failed to read copper-cable-type"
4148 " from SFP+ EEPROM\n");
4149 return -EINVAL;
4150 }
4151
4152 if (copper_module_type &
4153 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE) {
4154 DP(NETIF_MSG_LINK, "Active Copper cable detected\n");
4155 check_limiting_mode = 1;
4156 } else if (copper_module_type &
4157 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE) {
4158 DP(NETIF_MSG_LINK, "Passive Copper"
4159 " cable detected\n");
4160 *edc_mode =
4161 EDC_MODE_PASSIVE_DAC;
4162 } else {
4163 DP(NETIF_MSG_LINK, "Unknown copper-cable-"
4164 "type 0x%x !!!\n", copper_module_type);
4165 return -EINVAL;
4166 }
4167 break;
4168 }
4169 case SFP_EEPROM_CON_TYPE_VAL_LC:
4170 DP(NETIF_MSG_LINK, "Optic module detected\n");
4171 check_limiting_mode = 1;
4172 break;
4173 default:
4174 DP(NETIF_MSG_LINK, "Unable to determine module type 0x%x !!!\n",
4175 val);
4176 return -EINVAL;
4177 }
4178
4179 if (check_limiting_mode) {
4180 u8 options[SFP_EEPROM_OPTIONS_SIZE];
4181 if (bnx2x_read_sfp_module_eeprom(phy,
4182 params,
4183 SFP_EEPROM_OPTIONS_ADDR,
4184 SFP_EEPROM_OPTIONS_SIZE,
4185 options) != 0) {
4186 DP(NETIF_MSG_LINK, "Failed to read Option"
4187 " field from module EEPROM\n");
4188 return -EINVAL;
4189 }
4190 if ((options[0] & SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK))
4191 *edc_mode = EDC_MODE_LINEAR;
4192 else
4193 *edc_mode = EDC_MODE_LIMITING;
4194 }
4195 DP(NETIF_MSG_LINK, "EDC mode is set to 0x%x\n", *edc_mode);
4196 return 0;
4197}
4198/* This function read the relevant field from the module ( SFP+ ),
4199 and verify it is compliant with this board */
4200static u8 bnx2x_verify_sfp_module(struct bnx2x_phy *phy,
4201 struct link_params *params)
4202{
4203 struct bnx2x *bp = params->bp;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004204 u32 val, cmd;
4205 u32 fw_resp, fw_cmd_param;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004206 char vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE+1];
4207 char vendor_pn[SFP_EEPROM_PART_NO_SIZE+1];
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004208 phy->flags &= ~FLAGS_SFP_NOT_APPROVED;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004209 val = REG_RD(bp, params->shmem_base +
4210 offsetof(struct shmem_region, dev_info.
4211 port_feature_config[params->port].config));
4212 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
4213 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_NO_ENFORCEMENT) {
4214 DP(NETIF_MSG_LINK, "NOT enforcing module verification\n");
4215 return 0;
4216 }
4217
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004218 if (params->feature_config_flags &
4219 FEATURE_CONFIG_BC_SUPPORTS_DUAL_PHY_OPT_MDL_VRFY) {
4220 /* Use specific phy request */
4221 cmd = DRV_MSG_CODE_VRFY_SPECIFIC_PHY_OPT_MDL;
4222 } else if (params->feature_config_flags &
4223 FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY) {
4224 /* Use first phy request only in case of non-dual media*/
4225 if (DUAL_MEDIA(params)) {
4226 DP(NETIF_MSG_LINK, "FW does not support OPT MDL "
4227 "verification\n");
4228 return -EINVAL;
4229 }
4230 cmd = DRV_MSG_CODE_VRFY_FIRST_PHY_OPT_MDL;
4231 } else {
4232 /* No support in OPT MDL detection */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004233 DP(NETIF_MSG_LINK, "FW does not support OPT MDL "
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004234 "verification\n");
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004235 return -EINVAL;
4236 }
Dmitry Kravkov523224a2010-10-06 03:23:26 +00004237
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004238 fw_cmd_param = FW_PARAM_SET(phy->addr, phy->type, phy->mdio_ctrl);
4239 fw_resp = bnx2x_fw_command(bp, cmd, fw_cmd_param);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004240 if (fw_resp == FW_MSG_CODE_VRFY_OPT_MDL_SUCCESS) {
4241 DP(NETIF_MSG_LINK, "Approved module\n");
4242 return 0;
4243 }
4244
4245 /* format the warning message */
4246 if (bnx2x_read_sfp_module_eeprom(phy,
4247 params,
4248 SFP_EEPROM_VENDOR_NAME_ADDR,
4249 SFP_EEPROM_VENDOR_NAME_SIZE,
4250 (u8 *)vendor_name))
4251 vendor_name[0] = '\0';
4252 else
4253 vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE] = '\0';
4254 if (bnx2x_read_sfp_module_eeprom(phy,
4255 params,
4256 SFP_EEPROM_PART_NO_ADDR,
4257 SFP_EEPROM_PART_NO_SIZE,
4258 (u8 *)vendor_pn))
4259 vendor_pn[0] = '\0';
4260 else
4261 vendor_pn[SFP_EEPROM_PART_NO_SIZE] = '\0';
4262
4263 netdev_info(bp->dev, "Warning: Unqualified SFP+ module detected,"
4264 " Port %d from %s part number %s\n",
4265 params->port, vendor_name, vendor_pn);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004266 phy->flags |= FLAGS_SFP_NOT_APPROVED;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004267 return -EINVAL;
4268}
4269
4270static u8 bnx2x_wait_for_sfp_module_initialized(struct bnx2x_phy *phy,
4271 struct link_params *params)
4272
4273{
4274 u8 val;
4275 struct bnx2x *bp = params->bp;
4276 u16 timeout;
4277 /* Initialization time after hot-plug may take up to 300ms for some
4278 phys type ( e.g. JDSU ) */
4279 for (timeout = 0; timeout < 60; timeout++) {
4280 if (bnx2x_read_sfp_module_eeprom(phy, params, 1, 1, &val)
4281 == 0) {
4282 DP(NETIF_MSG_LINK, "SFP+ module initialization "
4283 "took %d ms\n", timeout * 5);
4284 return 0;
4285 }
4286 msleep(5);
4287 }
4288 return -EINVAL;
4289}
4290
4291static void bnx2x_8727_power_module(struct bnx2x *bp,
4292 struct bnx2x_phy *phy,
4293 u8 is_power_up) {
4294 /* Make sure GPIOs are not using for LED mode */
4295 u16 val;
4296 /*
4297 * In the GPIO register, bit 4 is use to detemine if the GPIOs are
4298 * operating as INPUT or as OUTPUT. Bit 1 is for input, and 0 for
4299 * output
4300 * Bits 0-1 determine the gpios value for OUTPUT in case bit 4 val is 0
4301 * Bits 8-9 determine the gpios value for INPUT in case bit 4 val is 1
4302 * where the 1st bit is the over-current(only input), and 2nd bit is
4303 * for power( only output )
4304 */
4305
4306 /*
4307 * In case of NOC feature is disabled and power is up, set GPIO control
4308 * as input to enable listening of over-current indication
4309 */
4310 if (phy->flags & FLAGS_NOC)
4311 return;
4312 if (!(phy->flags &
4313 FLAGS_NOC) && is_power_up)
4314 val = (1<<4);
4315 else
4316 /*
4317 * Set GPIO control to OUTPUT, and set the power bit
4318 * to according to the is_power_up
4319 */
4320 val = ((!(is_power_up)) << 1);
4321
4322 bnx2x_cl45_write(bp, phy,
4323 MDIO_PMA_DEVAD,
4324 MDIO_PMA_REG_8727_GPIO_CTRL,
4325 val);
4326}
4327
4328static u8 bnx2x_8726_set_limiting_mode(struct bnx2x *bp,
4329 struct bnx2x_phy *phy,
4330 u16 edc_mode)
4331{
4332 u16 cur_limiting_mode;
4333
4334 bnx2x_cl45_read(bp, phy,
4335 MDIO_PMA_DEVAD,
4336 MDIO_PMA_REG_ROM_VER2,
4337 &cur_limiting_mode);
4338 DP(NETIF_MSG_LINK, "Current Limiting mode is 0x%x\n",
4339 cur_limiting_mode);
4340
4341 if (edc_mode == EDC_MODE_LIMITING) {
4342 DP(NETIF_MSG_LINK,
4343 "Setting LIMITING MODE\n");
4344 bnx2x_cl45_write(bp, phy,
4345 MDIO_PMA_DEVAD,
4346 MDIO_PMA_REG_ROM_VER2,
4347 EDC_MODE_LIMITING);
4348 } else { /* LRM mode ( default )*/
4349
4350 DP(NETIF_MSG_LINK, "Setting LRM MODE\n");
4351
4352 /* Changing to LRM mode takes quite few seconds.
4353 So do it only if current mode is limiting
4354 ( default is LRM )*/
4355 if (cur_limiting_mode != EDC_MODE_LIMITING)
4356 return 0;
4357
4358 bnx2x_cl45_write(bp, phy,
4359 MDIO_PMA_DEVAD,
4360 MDIO_PMA_REG_LRM_MODE,
4361 0);
4362 bnx2x_cl45_write(bp, phy,
4363 MDIO_PMA_DEVAD,
4364 MDIO_PMA_REG_ROM_VER2,
4365 0x128);
4366 bnx2x_cl45_write(bp, phy,
4367 MDIO_PMA_DEVAD,
4368 MDIO_PMA_REG_MISC_CTRL0,
4369 0x4008);
4370 bnx2x_cl45_write(bp, phy,
4371 MDIO_PMA_DEVAD,
4372 MDIO_PMA_REG_LRM_MODE,
4373 0xaaaa);
4374 }
4375 return 0;
4376}
4377
4378static u8 bnx2x_8727_set_limiting_mode(struct bnx2x *bp,
4379 struct bnx2x_phy *phy,
4380 u16 edc_mode)
4381{
4382 u16 phy_identifier;
4383 u16 rom_ver2_val;
4384 bnx2x_cl45_read(bp, phy,
4385 MDIO_PMA_DEVAD,
4386 MDIO_PMA_REG_PHY_IDENTIFIER,
4387 &phy_identifier);
4388
4389 bnx2x_cl45_write(bp, phy,
4390 MDIO_PMA_DEVAD,
4391 MDIO_PMA_REG_PHY_IDENTIFIER,
4392 (phy_identifier & ~(1<<9)));
4393
4394 bnx2x_cl45_read(bp, phy,
4395 MDIO_PMA_DEVAD,
4396 MDIO_PMA_REG_ROM_VER2,
4397 &rom_ver2_val);
4398 /* Keep the MSB 8-bits, and set the LSB 8-bits with the edc_mode */
4399 bnx2x_cl45_write(bp, phy,
4400 MDIO_PMA_DEVAD,
4401 MDIO_PMA_REG_ROM_VER2,
4402 (rom_ver2_val & 0xff00) | (edc_mode & 0x00ff));
4403
4404 bnx2x_cl45_write(bp, phy,
4405 MDIO_PMA_DEVAD,
4406 MDIO_PMA_REG_PHY_IDENTIFIER,
4407 (phy_identifier | (1<<9)));
4408
4409 return 0;
4410}
4411
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004412static void bnx2x_8727_specific_func(struct bnx2x_phy *phy,
4413 struct link_params *params,
4414 u32 action)
4415{
4416 struct bnx2x *bp = params->bp;
4417
4418 switch (action) {
4419 case DISABLE_TX:
4420 bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
4421 break;
4422 case ENABLE_TX:
4423 if (!(phy->flags & FLAGS_SFP_NOT_APPROVED))
4424 bnx2x_sfp_set_transmitter(bp, phy, params->port, 1);
4425 break;
4426 default:
4427 DP(NETIF_MSG_LINK, "Function 0x%x not supported by 8727\n",
4428 action);
4429 return;
4430 }
4431}
4432
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004433static u8 bnx2x_sfp_module_detection(struct bnx2x_phy *phy,
4434 struct link_params *params)
4435{
4436 struct bnx2x *bp = params->bp;
4437 u16 edc_mode;
4438 u8 rc = 0;
4439
4440 u32 val = REG_RD(bp, params->shmem_base +
4441 offsetof(struct shmem_region, dev_info.
4442 port_feature_config[params->port].config));
4443
4444 DP(NETIF_MSG_LINK, "SFP+ module plugged in/out detected on port %d\n",
4445 params->port);
4446
4447 if (bnx2x_get_edc_mode(phy, params, &edc_mode) != 0) {
4448 DP(NETIF_MSG_LINK, "Failed to get valid module type\n");
4449 return -EINVAL;
4450 } else if (bnx2x_verify_sfp_module(phy, params) !=
4451 0) {
4452 /* check SFP+ module compatibility */
4453 DP(NETIF_MSG_LINK, "Module verification failed!!\n");
4454 rc = -EINVAL;
4455 /* Turn on fault module-detected led */
4456 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
4457 MISC_REGISTERS_GPIO_HIGH,
4458 params->port);
4459 if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) &&
4460 ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
4461 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_POWER_DOWN)) {
4462 /* Shutdown SFP+ module */
4463 DP(NETIF_MSG_LINK, "Shutdown SFP+ module!!\n");
4464 bnx2x_8727_power_module(bp, phy, 0);
4465 return rc;
4466 }
4467 } else {
4468 /* Turn off fault module-detected led */
4469 DP(NETIF_MSG_LINK, "Turn off fault module-detected led\n");
4470 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
4471 MISC_REGISTERS_GPIO_LOW,
4472 params->port);
4473 }
4474
4475 /* power up the SFP module */
4476 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
4477 bnx2x_8727_power_module(bp, phy, 1);
4478
4479 /* Check and set limiting mode / LRM mode on 8726.
4480 On 8727 it is done automatically */
4481 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
4482 bnx2x_8726_set_limiting_mode(bp, phy, edc_mode);
4483 else
4484 bnx2x_8727_set_limiting_mode(bp, phy, edc_mode);
4485 /*
4486 * Enable transmit for this module if the module is approved, or
4487 * if unapproved modules should also enable the Tx laser
4488 */
4489 if (rc == 0 ||
4490 (val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) !=
4491 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
4492 bnx2x_sfp_set_transmitter(bp, phy, params->port, 1);
4493 else
4494 bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
4495
4496 return rc;
4497}
4498
4499void bnx2x_handle_module_detect_int(struct link_params *params)
4500{
4501 struct bnx2x *bp = params->bp;
4502 struct bnx2x_phy *phy = &params->phy[EXT_PHY1];
4503 u32 gpio_val;
4504 u8 port = params->port;
4505
4506 /* Set valid module led off */
4507 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
4508 MISC_REGISTERS_GPIO_HIGH,
4509 params->port);
4510
4511 /* Get current gpio val refelecting module plugged in / out*/
4512 gpio_val = bnx2x_get_gpio(bp, MISC_REGISTERS_GPIO_3, port);
4513
4514 /* Call the handling function in case module is detected */
4515 if (gpio_val == 0) {
4516
4517 bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
4518 MISC_REGISTERS_GPIO_INT_OUTPUT_CLR,
4519 port);
4520
4521 if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0)
4522 bnx2x_sfp_module_detection(phy, params);
4523 else
4524 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
4525 } else {
4526 u32 val = REG_RD(bp, params->shmem_base +
4527 offsetof(struct shmem_region, dev_info.
4528 port_feature_config[params->port].
4529 config));
4530
4531 bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
4532 MISC_REGISTERS_GPIO_INT_OUTPUT_SET,
4533 port);
4534 /* Module was plugged out. */
4535 /* Disable transmit for this module */
4536 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
4537 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
4538 bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
4539 }
4540}
4541
4542/******************************************************************/
4543/* common BCM8706/BCM8726 PHY SECTION */
4544/******************************************************************/
4545static u8 bnx2x_8706_8726_read_status(struct bnx2x_phy *phy,
4546 struct link_params *params,
4547 struct link_vars *vars)
4548{
4549 u8 link_up = 0;
4550 u16 val1, val2, rx_sd, pcs_status;
4551 struct bnx2x *bp = params->bp;
4552 DP(NETIF_MSG_LINK, "XGXS 8706/8726\n");
4553 /* Clear RX Alarm*/
4554 bnx2x_cl45_read(bp, phy,
4555 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &val2);
4556 /* clear LASI indication*/
4557 bnx2x_cl45_read(bp, phy,
4558 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
4559 bnx2x_cl45_read(bp, phy,
4560 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val2);
4561 DP(NETIF_MSG_LINK, "8706/8726 LASI status 0x%x--> 0x%x\n", val1, val2);
4562
4563 bnx2x_cl45_read(bp, phy,
4564 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD, &rx_sd);
4565 bnx2x_cl45_read(bp, phy,
4566 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &pcs_status);
4567 bnx2x_cl45_read(bp, phy,
4568 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &val2);
4569 bnx2x_cl45_read(bp, phy,
4570 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &val2);
4571
4572 DP(NETIF_MSG_LINK, "8706/8726 rx_sd 0x%x pcs_status 0x%x 1Gbps"
4573 " link_status 0x%x\n", rx_sd, pcs_status, val2);
4574 /* link is up if both bit 0 of pmd_rx_sd and
4575 * bit 0 of pcs_status are set, or if the autoneg bit
4576 * 1 is set
4577 */
4578 link_up = ((rx_sd & pcs_status & 0x1) || (val2 & (1<<1)));
4579 if (link_up) {
4580 if (val2 & (1<<1))
4581 vars->line_speed = SPEED_1000;
4582 else
4583 vars->line_speed = SPEED_10000;
4584 bnx2x_ext_phy_resolve_fc(phy, params, vars);
4585 }
4586 return link_up;
4587}
4588
4589/******************************************************************/
4590/* BCM8706 PHY SECTION */
4591/******************************************************************/
4592static u8 bnx2x_8706_config_init(struct bnx2x_phy *phy,
4593 struct link_params *params,
4594 struct link_vars *vars)
4595{
4596 u16 cnt, val;
4597 struct bnx2x *bp = params->bp;
4598 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
4599 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
4600 /* HW reset */
4601 bnx2x_ext_phy_hw_reset(bp, params->port);
4602 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0xa040);
4603 bnx2x_wait_reset_complete(bp, phy);
4604
4605 /* Wait until fw is loaded */
4606 for (cnt = 0; cnt < 100; cnt++) {
4607 bnx2x_cl45_read(bp, phy,
4608 MDIO_PMA_DEVAD, MDIO_PMA_REG_ROM_VER1, &val);
4609 if (val)
4610 break;
4611 msleep(10);
4612 }
4613 DP(NETIF_MSG_LINK, "XGXS 8706 is initialized after %d ms\n", cnt);
4614 if ((params->feature_config_flags &
4615 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
4616 u8 i;
4617 u16 reg;
4618 for (i = 0; i < 4; i++) {
4619 reg = MDIO_XS_8706_REG_BANK_RX0 +
4620 i*(MDIO_XS_8706_REG_BANK_RX1 -
4621 MDIO_XS_8706_REG_BANK_RX0);
4622 bnx2x_cl45_read(bp, phy, MDIO_XS_DEVAD, reg, &val);
4623 /* Clear first 3 bits of the control */
4624 val &= ~0x7;
4625 /* Set control bits according to configuration */
4626 val |= (phy->rx_preemphasis[i] & 0x7);
4627 DP(NETIF_MSG_LINK, "Setting RX Equalizer to BCM8706"
4628 " reg 0x%x <-- val 0x%x\n", reg, val);
4629 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, reg, val);
4630 }
4631 }
4632 /* Force speed */
4633 if (phy->req_line_speed == SPEED_10000) {
4634 DP(NETIF_MSG_LINK, "XGXS 8706 force 10Gbps\n");
4635
4636 bnx2x_cl45_write(bp, phy,
4637 MDIO_PMA_DEVAD,
4638 MDIO_PMA_REG_DIGITAL_CTRL, 0x400);
4639 bnx2x_cl45_write(bp, phy,
4640 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 1);
4641 } else {
4642 /* Force 1Gbps using autoneg with 1G advertisment */
4643
4644 /* Allow CL37 through CL73 */
4645 DP(NETIF_MSG_LINK, "XGXS 8706 AutoNeg\n");
4646 bnx2x_cl45_write(bp, phy,
4647 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_CL73, 0x040c);
4648
4649 /* Enable Full-Duplex advertisment on CL37 */
4650 bnx2x_cl45_write(bp, phy,
4651 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LP, 0x0020);
4652 /* Enable CL37 AN */
4653 bnx2x_cl45_write(bp, phy,
4654 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
4655 /* 1G support */
4656 bnx2x_cl45_write(bp, phy,
4657 MDIO_AN_DEVAD, MDIO_AN_REG_ADV, (1<<5));
4658
4659 /* Enable clause 73 AN */
4660 bnx2x_cl45_write(bp, phy,
4661 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
4662 bnx2x_cl45_write(bp, phy,
4663 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
4664 0x0400);
4665 bnx2x_cl45_write(bp, phy,
4666 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL,
4667 0x0004);
4668 }
4669 bnx2x_save_bcm_spirom_ver(bp, phy, params->port);
4670 return 0;
4671}
4672
4673static u8 bnx2x_8706_read_status(struct bnx2x_phy *phy,
4674 struct link_params *params,
4675 struct link_vars *vars)
4676{
4677 return bnx2x_8706_8726_read_status(phy, params, vars);
4678}
4679
4680/******************************************************************/
4681/* BCM8726 PHY SECTION */
4682/******************************************************************/
4683static void bnx2x_8726_config_loopback(struct bnx2x_phy *phy,
4684 struct link_params *params)
4685{
4686 struct bnx2x *bp = params->bp;
4687 DP(NETIF_MSG_LINK, "PMA/PMD ext_phy_loopback: 8726\n");
4688 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x0001);
4689}
4690
4691static void bnx2x_8726_external_rom_boot(struct bnx2x_phy *phy,
4692 struct link_params *params)
4693{
4694 struct bnx2x *bp = params->bp;
4695 /* Need to wait 100ms after reset */
4696 msleep(100);
4697
4698 /* Micro controller re-boot */
4699 bnx2x_cl45_write(bp, phy,
4700 MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, 0x018B);
4701
4702 /* Set soft reset */
4703 bnx2x_cl45_write(bp, phy,
4704 MDIO_PMA_DEVAD,
4705 MDIO_PMA_REG_GEN_CTRL,
4706 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
4707
4708 bnx2x_cl45_write(bp, phy,
4709 MDIO_PMA_DEVAD,
4710 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
4711
4712 bnx2x_cl45_write(bp, phy,
4713 MDIO_PMA_DEVAD,
4714 MDIO_PMA_REG_GEN_CTRL,
4715 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
4716
4717 /* wait for 150ms for microcode load */
4718 msleep(150);
4719
4720 /* Disable serial boot control, tristates pins SS_N, SCK, MOSI, MISO */
4721 bnx2x_cl45_write(bp, phy,
4722 MDIO_PMA_DEVAD,
4723 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
4724
4725 msleep(200);
4726 bnx2x_save_bcm_spirom_ver(bp, phy, params->port);
4727}
4728
4729static u8 bnx2x_8726_read_status(struct bnx2x_phy *phy,
4730 struct link_params *params,
4731 struct link_vars *vars)
4732{
4733 struct bnx2x *bp = params->bp;
4734 u16 val1;
4735 u8 link_up = bnx2x_8706_8726_read_status(phy, params, vars);
4736 if (link_up) {
4737 bnx2x_cl45_read(bp, phy,
4738 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER,
4739 &val1);
4740 if (val1 & (1<<15)) {
4741 DP(NETIF_MSG_LINK, "Tx is disabled\n");
4742 link_up = 0;
4743 vars->line_speed = 0;
4744 }
4745 }
4746 return link_up;
4747}
4748
4749
4750static u8 bnx2x_8726_config_init(struct bnx2x_phy *phy,
4751 struct link_params *params,
4752 struct link_vars *vars)
4753{
4754 struct bnx2x *bp = params->bp;
4755 u32 val;
4756 u32 swap_val, swap_override, aeu_gpio_mask, offset;
4757 DP(NETIF_MSG_LINK, "Initializing BCM8726\n");
4758 /* Restore normal power mode*/
4759 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
4760 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
4761
4762 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
4763 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
4764
4765 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
4766 bnx2x_wait_reset_complete(bp, phy);
4767
4768 bnx2x_8726_external_rom_boot(phy, params);
4769
4770 /* Need to call module detected on initialization since
4771 the module detection triggered by actual module
4772 insertion might occur before driver is loaded, and when
4773 driver is loaded, it reset all registers, including the
4774 transmitter */
4775 bnx2x_sfp_module_detection(phy, params);
4776
4777 if (phy->req_line_speed == SPEED_1000) {
4778 DP(NETIF_MSG_LINK, "Setting 1G force\n");
4779 bnx2x_cl45_write(bp, phy,
4780 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x40);
4781 bnx2x_cl45_write(bp, phy,
4782 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0xD);
4783 bnx2x_cl45_write(bp, phy,
4784 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x5);
4785 bnx2x_cl45_write(bp, phy,
4786 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
4787 0x400);
4788 } else if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
4789 (phy->speed_cap_mask &
4790 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G) &&
4791 ((phy->speed_cap_mask &
4792 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) !=
4793 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
4794 DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
4795 /* Set Flow control */
4796 bnx2x_ext_phy_set_pause(params, phy, vars);
4797 bnx2x_cl45_write(bp, phy,
4798 MDIO_AN_DEVAD, MDIO_AN_REG_ADV, 0x20);
4799 bnx2x_cl45_write(bp, phy,
4800 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_CL73, 0x040c);
4801 bnx2x_cl45_write(bp, phy,
4802 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, 0x0020);
4803 bnx2x_cl45_write(bp, phy,
4804 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
4805 bnx2x_cl45_write(bp, phy,
4806 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
4807 /* Enable RX-ALARM control to receive
4808 interrupt for 1G speed change */
4809 bnx2x_cl45_write(bp, phy,
4810 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x4);
4811 bnx2x_cl45_write(bp, phy,
4812 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
4813 0x400);
4814
4815 } else { /* Default 10G. Set only LASI control */
4816 bnx2x_cl45_write(bp, phy,
4817 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 1);
4818 }
4819
4820 /* Set TX PreEmphasis if needed */
4821 if ((params->feature_config_flags &
4822 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
4823 DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x,"
4824 "TX_CTRL2 0x%x\n",
4825 phy->tx_preemphasis[0],
4826 phy->tx_preemphasis[1]);
4827 bnx2x_cl45_write(bp, phy,
4828 MDIO_PMA_DEVAD,
4829 MDIO_PMA_REG_8726_TX_CTRL1,
4830 phy->tx_preemphasis[0]);
4831
4832 bnx2x_cl45_write(bp, phy,
4833 MDIO_PMA_DEVAD,
4834 MDIO_PMA_REG_8726_TX_CTRL2,
4835 phy->tx_preemphasis[1]);
4836 }
4837
4838 /* Set GPIO3 to trigger SFP+ module insertion/removal */
4839 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
4840 MISC_REGISTERS_GPIO_INPUT_HI_Z, params->port);
4841
4842 /* The GPIO should be swapped if the swap register is set and active */
4843 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
4844 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
4845
4846 /* Select function upon port-swap configuration */
4847 if (params->port == 0) {
4848 offset = MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0;
4849 aeu_gpio_mask = (swap_val && swap_override) ?
4850 AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_1 :
4851 AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0;
4852 } else {
4853 offset = MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0;
4854 aeu_gpio_mask = (swap_val && swap_override) ?
4855 AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0 :
4856 AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_1;
4857 }
4858 val = REG_RD(bp, offset);
4859 /* add GPIO3 to group */
4860 val |= aeu_gpio_mask;
4861 REG_WR(bp, offset, val);
4862 return 0;
4863
4864}
4865
4866static void bnx2x_8726_link_reset(struct bnx2x_phy *phy,
4867 struct link_params *params)
4868{
4869 struct bnx2x *bp = params->bp;
4870 DP(NETIF_MSG_LINK, "bnx2x_8726_link_reset port %d\n", params->port);
4871 /* Set serial boot control for external load */
4872 bnx2x_cl45_write(bp, phy,
4873 MDIO_PMA_DEVAD,
4874 MDIO_PMA_REG_GEN_CTRL, 0x0001);
4875}
4876
4877/******************************************************************/
4878/* BCM8727 PHY SECTION */
4879/******************************************************************/
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00004880
4881static void bnx2x_8727_set_link_led(struct bnx2x_phy *phy,
4882 struct link_params *params, u8 mode)
4883{
4884 struct bnx2x *bp = params->bp;
4885 u16 led_mode_bitmask = 0;
4886 u16 gpio_pins_bitmask = 0;
4887 u16 val;
4888 /* Only NOC flavor requires to set the LED specifically */
4889 if (!(phy->flags & FLAGS_NOC))
4890 return;
4891 switch (mode) {
4892 case LED_MODE_FRONT_PANEL_OFF:
4893 case LED_MODE_OFF:
4894 led_mode_bitmask = 0;
4895 gpio_pins_bitmask = 0x03;
4896 break;
4897 case LED_MODE_ON:
4898 led_mode_bitmask = 0;
4899 gpio_pins_bitmask = 0x02;
4900 break;
4901 case LED_MODE_OPER:
4902 led_mode_bitmask = 0x60;
4903 gpio_pins_bitmask = 0x11;
4904 break;
4905 }
4906 bnx2x_cl45_read(bp, phy,
4907 MDIO_PMA_DEVAD,
4908 MDIO_PMA_REG_8727_PCS_OPT_CTRL,
4909 &val);
4910 val &= 0xff8f;
4911 val |= led_mode_bitmask;
4912 bnx2x_cl45_write(bp, phy,
4913 MDIO_PMA_DEVAD,
4914 MDIO_PMA_REG_8727_PCS_OPT_CTRL,
4915 val);
4916 bnx2x_cl45_read(bp, phy,
4917 MDIO_PMA_DEVAD,
4918 MDIO_PMA_REG_8727_GPIO_CTRL,
4919 &val);
4920 val &= 0xffe0;
4921 val |= gpio_pins_bitmask;
4922 bnx2x_cl45_write(bp, phy,
4923 MDIO_PMA_DEVAD,
4924 MDIO_PMA_REG_8727_GPIO_CTRL,
4925 val);
4926}
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004927static void bnx2x_8727_hw_reset(struct bnx2x_phy *phy,
4928 struct link_params *params) {
4929 u32 swap_val, swap_override;
4930 u8 port;
4931 /**
4932 * The PHY reset is controlled by GPIO 1. Fake the port number
4933 * to cancel the swap done in set_gpio()
4934 */
4935 struct bnx2x *bp = params->bp;
4936 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
4937 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
4938 port = (swap_val && swap_override) ^ 1;
4939 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
4940 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
4941}
4942
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004943static u8 bnx2x_8727_config_init(struct bnx2x_phy *phy,
4944 struct link_params *params,
4945 struct link_vars *vars)
4946{
4947 u16 tmp1, val, mod_abs;
4948 u16 rx_alarm_ctrl_val;
4949 u16 lasi_ctrl_val;
4950 struct bnx2x *bp = params->bp;
4951 /* Enable PMD link, MOD_ABS_FLT, and 1G link alarm */
4952
4953 bnx2x_wait_reset_complete(bp, phy);
4954 rx_alarm_ctrl_val = (1<<2) | (1<<5) ;
4955 lasi_ctrl_val = 0x0004;
4956
4957 DP(NETIF_MSG_LINK, "Initializing BCM8727\n");
4958 /* enable LASI */
4959 bnx2x_cl45_write(bp, phy,
4960 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
4961 rx_alarm_ctrl_val);
4962
4963 bnx2x_cl45_write(bp, phy,
4964 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, lasi_ctrl_val);
4965
4966 /* Initially configure MOD_ABS to interrupt when
4967 module is presence( bit 8) */
4968 bnx2x_cl45_read(bp, phy,
4969 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
4970 /* Set EDC off by setting OPTXLOS signal input to low
4971 (bit 9).
4972 When the EDC is off it locks onto a reference clock and
4973 avoids becoming 'lost'.*/
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00004974 mod_abs &= ~(1<<8);
4975 if (!(phy->flags & FLAGS_NOC))
4976 mod_abs &= ~(1<<9);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004977 bnx2x_cl45_write(bp, phy,
4978 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
4979
4980
4981 /* Make MOD_ABS give interrupt on change */
4982 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL,
4983 &val);
4984 val |= (1<<12);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00004985 if (phy->flags & FLAGS_NOC)
4986 val |= (3<<5);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004987
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00004988 /**
4989 * Set 8727 GPIOs to input to allow reading from the 8727 GPIO0
4990 * status which reflect SFP+ module over-current
4991 */
4992 if (!(phy->flags & FLAGS_NOC))
4993 val &= 0xff8f; /* Reset bits 4-6 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004994 bnx2x_cl45_write(bp, phy,
4995 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL, val);
4996
4997 bnx2x_8727_power_module(bp, phy, 1);
4998
4999 bnx2x_cl45_read(bp, phy,
5000 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &tmp1);
5001
5002 bnx2x_cl45_read(bp, phy,
5003 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &tmp1);
5004
5005 /* Set option 1G speed */
5006 if (phy->req_line_speed == SPEED_1000) {
5007 DP(NETIF_MSG_LINK, "Setting 1G force\n");
5008 bnx2x_cl45_write(bp, phy,
5009 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x40);
5010 bnx2x_cl45_write(bp, phy,
5011 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0xD);
5012 bnx2x_cl45_read(bp, phy,
5013 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, &tmp1);
5014 DP(NETIF_MSG_LINK, "1.7 = 0x%x\n", tmp1);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005015 /**
5016 * Power down the XAUI until link is up in case of dual-media
5017 * and 1G
5018 */
5019 if (DUAL_MEDIA(params)) {
5020 bnx2x_cl45_read(bp, phy,
5021 MDIO_PMA_DEVAD,
5022 MDIO_PMA_REG_8727_PCS_GP, &val);
5023 val |= (3<<10);
5024 bnx2x_cl45_write(bp, phy,
5025 MDIO_PMA_DEVAD,
5026 MDIO_PMA_REG_8727_PCS_GP, val);
5027 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005028 } else if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
5029 ((phy->speed_cap_mask &
5030 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) &&
5031 ((phy->speed_cap_mask &
5032 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) !=
5033 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
5034
5035 DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
5036 bnx2x_cl45_write(bp, phy,
5037 MDIO_AN_DEVAD, MDIO_AN_REG_8727_MISC_CTRL, 0);
5038 bnx2x_cl45_write(bp, phy,
5039 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1300);
5040 } else {
5041 /**
5042 * Since the 8727 has only single reset pin, need to set the 10G
5043 * registers although it is default
5044 */
5045 bnx2x_cl45_write(bp, phy,
5046 MDIO_AN_DEVAD, MDIO_AN_REG_8727_MISC_CTRL,
5047 0x0020);
5048 bnx2x_cl45_write(bp, phy,
5049 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x0100);
5050 bnx2x_cl45_write(bp, phy,
5051 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x2040);
5052 bnx2x_cl45_write(bp, phy,
5053 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2,
5054 0x0008);
5055 }
5056
5057 /* Set 2-wire transfer rate of SFP+ module EEPROM
5058 * to 100Khz since some DACs(direct attached cables) do
5059 * not work at 400Khz.
5060 */
5061 bnx2x_cl45_write(bp, phy,
5062 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR,
5063 0xa001);
5064
5065 /* Set TX PreEmphasis if needed */
5066 if ((params->feature_config_flags &
5067 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
5068 DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x, TX_CTRL2 0x%x\n",
5069 phy->tx_preemphasis[0],
5070 phy->tx_preemphasis[1]);
5071 bnx2x_cl45_write(bp, phy,
5072 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TX_CTRL1,
5073 phy->tx_preemphasis[0]);
5074
5075 bnx2x_cl45_write(bp, phy,
5076 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TX_CTRL2,
5077 phy->tx_preemphasis[1]);
5078 }
5079
5080 return 0;
5081}
5082
5083static void bnx2x_8727_handle_mod_abs(struct bnx2x_phy *phy,
5084 struct link_params *params)
5085{
5086 struct bnx2x *bp = params->bp;
5087 u16 mod_abs, rx_alarm_status;
5088 u32 val = REG_RD(bp, params->shmem_base +
5089 offsetof(struct shmem_region, dev_info.
5090 port_feature_config[params->port].
5091 config));
5092 bnx2x_cl45_read(bp, phy,
5093 MDIO_PMA_DEVAD,
5094 MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
5095 if (mod_abs & (1<<8)) {
5096
5097 /* Module is absent */
5098 DP(NETIF_MSG_LINK, "MOD_ABS indication "
5099 "show module is absent\n");
5100
5101 /* 1. Set mod_abs to detect next module
5102 presence event
5103 2. Set EDC off by setting OPTXLOS signal input to low
5104 (bit 9).
5105 When the EDC is off it locks onto a reference clock and
5106 avoids becoming 'lost'.*/
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005107 mod_abs &= ~(1<<8);
5108 if (!(phy->flags & FLAGS_NOC))
5109 mod_abs &= ~(1<<9);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005110 bnx2x_cl45_write(bp, phy,
5111 MDIO_PMA_DEVAD,
5112 MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
5113
5114 /* Clear RX alarm since it stays up as long as
5115 the mod_abs wasn't changed */
5116 bnx2x_cl45_read(bp, phy,
5117 MDIO_PMA_DEVAD,
5118 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
5119
5120 } else {
5121 /* Module is present */
5122 DP(NETIF_MSG_LINK, "MOD_ABS indication "
5123 "show module is present\n");
5124 /* First thing, disable transmitter,
5125 and if the module is ok, the
5126 module_detection will enable it*/
5127
5128 /* 1. Set mod_abs to detect next module
5129 absent event ( bit 8)
5130 2. Restore the default polarity of the OPRXLOS signal and
5131 this signal will then correctly indicate the presence or
5132 absence of the Rx signal. (bit 9) */
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005133 mod_abs |= (1<<8);
5134 if (!(phy->flags & FLAGS_NOC))
5135 mod_abs |= (1<<9);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005136 bnx2x_cl45_write(bp, phy,
5137 MDIO_PMA_DEVAD,
5138 MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
5139
5140 /* Clear RX alarm since it stays up as long as
5141 the mod_abs wasn't changed. This is need to be done
5142 before calling the module detection, otherwise it will clear
5143 the link update alarm */
5144 bnx2x_cl45_read(bp, phy,
5145 MDIO_PMA_DEVAD,
5146 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
5147
5148
5149 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
5150 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
5151 bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
5152
5153 if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0)
5154 bnx2x_sfp_module_detection(phy, params);
5155 else
5156 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
5157 }
5158
5159 DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n",
5160 rx_alarm_status);
5161 /* No need to check link status in case of
5162 module plugged in/out */
5163}
5164
5165static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy,
5166 struct link_params *params,
5167 struct link_vars *vars)
5168
5169{
5170 struct bnx2x *bp = params->bp;
5171 u8 link_up = 0;
5172 u16 link_status = 0;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005173 u16 rx_alarm_status, lasi_ctrl, val1;
5174
5175 /* If PHY is not initialized, do not check link status */
5176 bnx2x_cl45_read(bp, phy,
5177 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL,
5178 &lasi_ctrl);
5179 if (!lasi_ctrl)
5180 return 0;
5181
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005182 /* Check the LASI */
5183 bnx2x_cl45_read(bp, phy,
5184 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM,
5185 &rx_alarm_status);
5186 vars->line_speed = 0;
5187 DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n", rx_alarm_status);
5188
5189 bnx2x_cl45_read(bp, phy,
5190 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
5191
5192 DP(NETIF_MSG_LINK, "8727 LASI status 0x%x\n", val1);
5193
5194 /* Clear MSG-OUT */
5195 bnx2x_cl45_read(bp, phy,
5196 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &val1);
5197
5198 /**
5199 * If a module is present and there is need to check
5200 * for over current
5201 */
5202 if (!(phy->flags & FLAGS_NOC) && !(rx_alarm_status & (1<<5))) {
5203 /* Check over-current using 8727 GPIO0 input*/
5204 bnx2x_cl45_read(bp, phy,
5205 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_GPIO_CTRL,
5206 &val1);
5207
5208 if ((val1 & (1<<8)) == 0) {
5209 DP(NETIF_MSG_LINK, "8727 Power fault has been detected"
5210 " on port %d\n", params->port);
5211 netdev_err(bp->dev, "Error: Power fault on Port %d has"
5212 " been detected and the power to "
5213 "that SFP+ module has been removed"
5214 " to prevent failure of the card."
5215 " Please remove the SFP+ module and"
5216 " restart the system to clear this"
5217 " error.\n",
5218 params->port);
5219
5220 /*
5221 * Disable all RX_ALARMs except for
5222 * mod_abs
5223 */
5224 bnx2x_cl45_write(bp, phy,
5225 MDIO_PMA_DEVAD,
5226 MDIO_PMA_REG_RX_ALARM_CTRL, (1<<5));
5227
5228 bnx2x_cl45_read(bp, phy,
5229 MDIO_PMA_DEVAD,
5230 MDIO_PMA_REG_PHY_IDENTIFIER, &val1);
5231 /* Wait for module_absent_event */
5232 val1 |= (1<<8);
5233 bnx2x_cl45_write(bp, phy,
5234 MDIO_PMA_DEVAD,
5235 MDIO_PMA_REG_PHY_IDENTIFIER, val1);
5236 /* Clear RX alarm */
5237 bnx2x_cl45_read(bp, phy,
5238 MDIO_PMA_DEVAD,
5239 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
5240 return 0;
5241 }
5242 } /* Over current check */
5243
5244 /* When module absent bit is set, check module */
5245 if (rx_alarm_status & (1<<5)) {
5246 bnx2x_8727_handle_mod_abs(phy, params);
5247 /* Enable all mod_abs and link detection bits */
5248 bnx2x_cl45_write(bp, phy,
5249 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
5250 ((1<<5) | (1<<2)));
5251 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005252 DP(NETIF_MSG_LINK, "Enabling 8727 TX laser if SFP is approved\n");
5253 bnx2x_8727_specific_func(phy, params, ENABLE_TX);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005254 /* If transmitter is disabled, ignore false link up indication */
5255 bnx2x_cl45_read(bp, phy,
5256 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, &val1);
5257 if (val1 & (1<<15)) {
5258 DP(NETIF_MSG_LINK, "Tx is disabled\n");
5259 return 0;
5260 }
5261
5262 bnx2x_cl45_read(bp, phy,
5263 MDIO_PMA_DEVAD,
5264 MDIO_PMA_REG_8073_SPEED_LINK_STATUS, &link_status);
5265
5266 /* Bits 0..2 --> speed detected,
5267 bits 13..15--> link is down */
5268 if ((link_status & (1<<2)) && (!(link_status & (1<<15)))) {
5269 link_up = 1;
5270 vars->line_speed = SPEED_10000;
5271 } else if ((link_status & (1<<0)) && (!(link_status & (1<<13)))) {
5272 link_up = 1;
5273 vars->line_speed = SPEED_1000;
5274 DP(NETIF_MSG_LINK, "port %x: External link up in 1G\n",
5275 params->port);
5276 } else {
5277 link_up = 0;
5278 DP(NETIF_MSG_LINK, "port %x: External link is down\n",
5279 params->port);
5280 }
5281 if (link_up)
5282 bnx2x_ext_phy_resolve_fc(phy, params, vars);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005283
5284 if ((DUAL_MEDIA(params)) &&
5285 (phy->req_line_speed == SPEED_1000)) {
5286 bnx2x_cl45_read(bp, phy,
5287 MDIO_PMA_DEVAD,
5288 MDIO_PMA_REG_8727_PCS_GP, &val1);
5289 /**
5290 * In case of dual-media board and 1G, power up the XAUI side,
5291 * otherwise power it down. For 10G it is done automatically
5292 */
5293 if (link_up)
5294 val1 &= ~(3<<10);
5295 else
5296 val1 |= (3<<10);
5297 bnx2x_cl45_write(bp, phy,
5298 MDIO_PMA_DEVAD,
5299 MDIO_PMA_REG_8727_PCS_GP, val1);
5300 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005301 return link_up;
5302}
5303
5304static void bnx2x_8727_link_reset(struct bnx2x_phy *phy,
5305 struct link_params *params)
5306{
5307 struct bnx2x *bp = params->bp;
5308 /* Disable Transmitter */
5309 bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005310 /* Clear LASI */
5311 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0);
5312
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005313}
5314
5315/******************************************************************/
5316/* BCM8481/BCM84823/BCM84833 PHY SECTION */
5317/******************************************************************/
5318static void bnx2x_save_848xx_spirom_version(struct bnx2x_phy *phy,
5319 struct link_params *params)
5320{
5321 u16 val, fw_ver1, fw_ver2, cnt;
5322 struct bnx2x *bp = params->bp;
5323
5324 /* For the 32 bits registers in 848xx, access via MDIO2ARM interface.*/
5325 /* (1) set register 0xc200_0014(SPI_BRIDGE_CTRL_2) to 0x03000000 */
5326 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0014);
5327 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200);
5328 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81B, 0x0000);
5329 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81C, 0x0300);
5330 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x0009);
5331
5332 for (cnt = 0; cnt < 100; cnt++) {
5333 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val);
5334 if (val & 1)
5335 break;
5336 udelay(5);
5337 }
5338 if (cnt == 100) {
5339 DP(NETIF_MSG_LINK, "Unable to read 848xx phy fw version(1)\n");
5340 bnx2x_save_spirom_version(bp, params->port, 0,
5341 phy->ver_addr);
5342 return;
5343 }
5344
5345
5346 /* 2) read register 0xc200_0000 (SPI_FW_STATUS) */
5347 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0000);
5348 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200);
5349 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x000A);
5350 for (cnt = 0; cnt < 100; cnt++) {
5351 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val);
5352 if (val & 1)
5353 break;
5354 udelay(5);
5355 }
5356 if (cnt == 100) {
5357 DP(NETIF_MSG_LINK, "Unable to read 848xx phy fw version(2)\n");
5358 bnx2x_save_spirom_version(bp, params->port, 0,
5359 phy->ver_addr);
5360 return;
5361 }
5362
5363 /* lower 16 bits of the register SPI_FW_STATUS */
5364 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81B, &fw_ver1);
5365 /* upper 16 bits of register SPI_FW_STATUS */
5366 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81C, &fw_ver2);
5367
5368 bnx2x_save_spirom_version(bp, params->port, (fw_ver2<<16) | fw_ver1,
5369 phy->ver_addr);
5370}
5371
5372static void bnx2x_848xx_set_led(struct bnx2x *bp,
5373 struct bnx2x_phy *phy)
5374{
5375 u16 val;
5376
5377 /* PHYC_CTL_LED_CTL */
5378 bnx2x_cl45_read(bp, phy,
5379 MDIO_PMA_DEVAD,
5380 MDIO_PMA_REG_8481_LINK_SIGNAL, &val);
5381 val &= 0xFE00;
5382 val |= 0x0092;
5383
5384 bnx2x_cl45_write(bp, phy,
5385 MDIO_PMA_DEVAD,
5386 MDIO_PMA_REG_8481_LINK_SIGNAL, val);
5387
5388 bnx2x_cl45_write(bp, phy,
5389 MDIO_PMA_DEVAD,
5390 MDIO_PMA_REG_8481_LED1_MASK,
5391 0x80);
5392
5393 bnx2x_cl45_write(bp, phy,
5394 MDIO_PMA_DEVAD,
5395 MDIO_PMA_REG_8481_LED2_MASK,
5396 0x18);
5397
5398 bnx2x_cl45_write(bp, phy,
5399 MDIO_PMA_DEVAD,
5400 MDIO_PMA_REG_8481_LED3_MASK,
5401 0x0040);
5402
5403 /* 'Interrupt Mask' */
5404 bnx2x_cl45_write(bp, phy,
5405 MDIO_AN_DEVAD,
5406 0xFFFB, 0xFFFD);
5407}
5408
5409static u8 bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005410 struct link_params *params,
5411 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005412{
5413 struct bnx2x *bp = params->bp;
5414 u16 autoneg_val, an_1000_val, an_10_100_val;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005415 bnx2x_wait_reset_complete(bp, phy);
5416 bnx2x_bits_en(bp, NIG_REG_LATCH_BC_0 + params->port*4,
5417 1 << NIG_LATCH_BC_ENABLE_MI_INT);
5418
5419 bnx2x_cl45_write(bp, phy,
5420 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x0000);
5421
5422 bnx2x_848xx_set_led(bp, phy);
5423
5424 /* set 1000 speed advertisement */
5425 bnx2x_cl45_read(bp, phy,
5426 MDIO_AN_DEVAD, MDIO_AN_REG_8481_1000T_CTRL,
5427 &an_1000_val);
5428
5429 bnx2x_ext_phy_set_pause(params, phy, vars);
5430 bnx2x_cl45_read(bp, phy,
5431 MDIO_AN_DEVAD,
5432 MDIO_AN_REG_8481_LEGACY_AN_ADV,
5433 &an_10_100_val);
5434 bnx2x_cl45_read(bp, phy,
5435 MDIO_AN_DEVAD, MDIO_AN_REG_8481_LEGACY_MII_CTRL,
5436 &autoneg_val);
5437 /* Disable forced speed */
5438 autoneg_val &= ~((1<<6) | (1<<8) | (1<<9) | (1<<12) | (1<<13));
5439 an_10_100_val &= ~((1<<5) | (1<<6) | (1<<7) | (1<<8));
5440
5441 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
5442 (phy->speed_cap_mask &
5443 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) ||
5444 (phy->req_line_speed == SPEED_1000)) {
5445 an_1000_val |= (1<<8);
5446 autoneg_val |= (1<<9 | 1<<12);
5447 if (phy->req_duplex == DUPLEX_FULL)
5448 an_1000_val |= (1<<9);
5449 DP(NETIF_MSG_LINK, "Advertising 1G\n");
5450 } else
5451 an_1000_val &= ~((1<<8) | (1<<9));
5452
5453 bnx2x_cl45_write(bp, phy,
5454 MDIO_AN_DEVAD, MDIO_AN_REG_8481_1000T_CTRL,
5455 an_1000_val);
5456
5457 /* set 10 speed advertisement */
5458 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
5459 (phy->speed_cap_mask &
5460 (PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL |
5461 PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF)))) {
5462 an_10_100_val |= (1<<7);
5463 /* Enable autoneg and restart autoneg for legacy speeds */
5464 autoneg_val |= (1<<9 | 1<<12);
5465
5466 if (phy->req_duplex == DUPLEX_FULL)
5467 an_10_100_val |= (1<<8);
5468 DP(NETIF_MSG_LINK, "Advertising 100M\n");
5469 }
5470 /* set 10 speed advertisement */
5471 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
5472 (phy->speed_cap_mask &
5473 (PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL |
5474 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF)))) {
5475 an_10_100_val |= (1<<5);
5476 autoneg_val |= (1<<9 | 1<<12);
5477 if (phy->req_duplex == DUPLEX_FULL)
5478 an_10_100_val |= (1<<6);
5479 DP(NETIF_MSG_LINK, "Advertising 10M\n");
5480 }
5481
5482 /* Only 10/100 are allowed to work in FORCE mode */
5483 if (phy->req_line_speed == SPEED_100) {
5484 autoneg_val |= (1<<13);
5485 /* Enabled AUTO-MDIX when autoneg is disabled */
5486 bnx2x_cl45_write(bp, phy,
5487 MDIO_AN_DEVAD, MDIO_AN_REG_8481_AUX_CTRL,
5488 (1<<15 | 1<<9 | 7<<0));
5489 DP(NETIF_MSG_LINK, "Setting 100M force\n");
5490 }
5491 if (phy->req_line_speed == SPEED_10) {
5492 /* Enabled AUTO-MDIX when autoneg is disabled */
5493 bnx2x_cl45_write(bp, phy,
5494 MDIO_AN_DEVAD, MDIO_AN_REG_8481_AUX_CTRL,
5495 (1<<15 | 1<<9 | 7<<0));
5496 DP(NETIF_MSG_LINK, "Setting 10M force\n");
5497 }
5498
5499 bnx2x_cl45_write(bp, phy,
5500 MDIO_AN_DEVAD, MDIO_AN_REG_8481_LEGACY_AN_ADV,
5501 an_10_100_val);
5502
5503 if (phy->req_duplex == DUPLEX_FULL)
5504 autoneg_val |= (1<<8);
5505
5506 bnx2x_cl45_write(bp, phy,
5507 MDIO_AN_DEVAD,
5508 MDIO_AN_REG_8481_LEGACY_MII_CTRL, autoneg_val);
5509
5510 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
5511 (phy->speed_cap_mask &
5512 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) ||
5513 (phy->req_line_speed == SPEED_10000)) {
5514 DP(NETIF_MSG_LINK, "Advertising 10G\n");
5515 /* Restart autoneg for 10G*/
5516
5517 bnx2x_cl45_write(bp, phy,
5518 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL,
5519 0x3200);
5520 } else if (phy->req_line_speed != SPEED_10 &&
5521 phy->req_line_speed != SPEED_100) {
5522 bnx2x_cl45_write(bp, phy,
5523 MDIO_AN_DEVAD,
5524 MDIO_AN_REG_8481_10GBASE_T_AN_CTRL,
5525 1);
5526 }
5527 /* Save spirom version */
5528 bnx2x_save_848xx_spirom_version(phy, params);
5529
5530 return 0;
5531}
5532
5533static u8 bnx2x_8481_config_init(struct bnx2x_phy *phy,
5534 struct link_params *params,
5535 struct link_vars *vars)
5536{
5537 struct bnx2x *bp = params->bp;
5538 /* Restore normal power mode*/
5539 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
5540 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
5541
5542 /* HW reset */
5543 bnx2x_ext_phy_hw_reset(bp, params->port);
5544
5545 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
5546 return bnx2x_848xx_cmn_config_init(phy, params, vars);
5547}
5548
5549static u8 bnx2x_848x3_config_init(struct bnx2x_phy *phy,
5550 struct link_params *params,
5551 struct link_vars *vars)
5552{
5553 struct bnx2x *bp = params->bp;
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005554 u8 port = params->port, initialize = 1;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005555 u16 val;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005556 u16 temp;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005557 u32 actual_phy_selection;
5558 u8 rc = 0;
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005559
5560 /* This is just for MDIO_CTL_REG_84823_MEDIA register. */
5561
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005562 msleep(1);
5563 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
5564 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005565 port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005566 msleep(200); /* 100 is not enough */
5567
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005568 /* BCM84823 requires that XGXS links up first @ 10G for normal
5569 behavior */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005570 temp = vars->line_speed;
5571 vars->line_speed = SPEED_10000;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005572 bnx2x_set_autoneg(&params->phy[INT_PHY], params, vars, 0);
5573 bnx2x_program_serdes(&params->phy[INT_PHY], params, vars);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005574 vars->line_speed = temp;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005575
5576 /* Set dual-media configuration according to configuration */
5577
5578 bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
5579 MDIO_CTL_REG_84823_MEDIA, &val);
5580 val &= ~(MDIO_CTL_REG_84823_MEDIA_MAC_MASK |
5581 MDIO_CTL_REG_84823_MEDIA_LINE_MASK |
5582 MDIO_CTL_REG_84823_MEDIA_COPPER_CORE_DOWN |
5583 MDIO_CTL_REG_84823_MEDIA_PRIORITY_MASK |
5584 MDIO_CTL_REG_84823_MEDIA_FIBER_1G);
5585 val |= MDIO_CTL_REG_84823_CTRL_MAC_XFI |
5586 MDIO_CTL_REG_84823_MEDIA_LINE_XAUI_L;
5587
5588 actual_phy_selection = bnx2x_phy_selection(params);
5589
5590 switch (actual_phy_selection) {
5591 case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT:
5592 /* Do nothing. Essentialy this is like the priority copper */
5593 break;
5594 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
5595 val |= MDIO_CTL_REG_84823_MEDIA_PRIORITY_COPPER;
5596 break;
5597 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
5598 val |= MDIO_CTL_REG_84823_MEDIA_PRIORITY_FIBER;
5599 break;
5600 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY:
5601 /* Do nothing here. The first PHY won't be initialized at all */
5602 break;
5603 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY:
5604 val |= MDIO_CTL_REG_84823_MEDIA_COPPER_CORE_DOWN;
5605 initialize = 0;
5606 break;
5607 }
5608 if (params->phy[EXT_PHY2].req_line_speed == SPEED_1000)
5609 val |= MDIO_CTL_REG_84823_MEDIA_FIBER_1G;
5610
5611 bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
5612 MDIO_CTL_REG_84823_MEDIA, val);
5613 DP(NETIF_MSG_LINK, "Multi_phy config = 0x%x, Media control = 0x%x\n",
5614 params->multi_phy_config, val);
5615
5616 if (initialize)
5617 rc = bnx2x_848xx_cmn_config_init(phy, params, vars);
5618 else
5619 bnx2x_save_848xx_spirom_version(phy, params);
5620 return rc;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005621}
5622
5623static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy,
5624 struct link_params *params,
5625 struct link_vars *vars)
5626{
5627 struct bnx2x *bp = params->bp;
5628 u16 val, val1, val2;
5629 u8 link_up = 0;
5630
5631 /* Check 10G-BaseT link status */
5632 /* Check PMD signal ok */
5633 bnx2x_cl45_read(bp, phy,
5634 MDIO_AN_DEVAD, 0xFFFA, &val1);
5635 bnx2x_cl45_read(bp, phy,
5636 MDIO_PMA_DEVAD, MDIO_PMA_REG_8481_PMD_SIGNAL,
5637 &val2);
5638 DP(NETIF_MSG_LINK, "BCM848xx: PMD_SIGNAL 1.a811 = 0x%x\n", val2);
5639
5640 /* Check link 10G */
5641 if (val2 & (1<<11)) {
5642 vars->line_speed = SPEED_10000;
5643 link_up = 1;
5644 bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
5645 } else { /* Check Legacy speed link */
5646 u16 legacy_status, legacy_speed;
5647
5648 /* Enable expansion register 0x42 (Operation mode status) */
5649 bnx2x_cl45_write(bp, phy,
5650 MDIO_AN_DEVAD,
5651 MDIO_AN_REG_8481_EXPANSION_REG_ACCESS, 0xf42);
5652
5653 /* Get legacy speed operation status */
5654 bnx2x_cl45_read(bp, phy,
5655 MDIO_AN_DEVAD,
5656 MDIO_AN_REG_8481_EXPANSION_REG_RD_RW,
5657 &legacy_status);
5658
5659 DP(NETIF_MSG_LINK, "Legacy speed status"
5660 " = 0x%x\n", legacy_status);
5661 link_up = ((legacy_status & (1<<11)) == (1<<11));
5662 if (link_up) {
5663 legacy_speed = (legacy_status & (3<<9));
5664 if (legacy_speed == (0<<9))
5665 vars->line_speed = SPEED_10;
5666 else if (legacy_speed == (1<<9))
5667 vars->line_speed = SPEED_100;
5668 else if (legacy_speed == (2<<9))
5669 vars->line_speed = SPEED_1000;
5670 else /* Should not happen */
5671 vars->line_speed = 0;
5672
5673 if (legacy_status & (1<<8))
5674 vars->duplex = DUPLEX_FULL;
5675 else
5676 vars->duplex = DUPLEX_HALF;
5677
5678 DP(NETIF_MSG_LINK, "Link is up in %dMbps,"
5679 " is_duplex_full= %d\n", vars->line_speed,
5680 (vars->duplex == DUPLEX_FULL));
5681 /* Check legacy speed AN resolution */
5682 bnx2x_cl45_read(bp, phy,
5683 MDIO_AN_DEVAD,
5684 MDIO_AN_REG_8481_LEGACY_MII_STATUS,
5685 &val);
5686 if (val & (1<<5))
5687 vars->link_status |=
5688 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
5689 bnx2x_cl45_read(bp, phy,
5690 MDIO_AN_DEVAD,
5691 MDIO_AN_REG_8481_LEGACY_AN_EXPANSION,
5692 &val);
5693 if ((val & (1<<0)) == 0)
5694 vars->link_status |=
5695 LINK_STATUS_PARALLEL_DETECTION_USED;
5696 }
5697 }
5698 if (link_up) {
5699 DP(NETIF_MSG_LINK, "BCM84823: link speed is %d\n",
5700 vars->line_speed);
5701 bnx2x_ext_phy_resolve_fc(phy, params, vars);
5702 }
5703
5704 return link_up;
5705}
5706
5707static u8 bnx2x_848xx_format_ver(u32 raw_ver, u8 *str, u16 *len)
5708{
5709 u8 status = 0;
5710 u32 spirom_ver;
5711 spirom_ver = ((raw_ver & 0xF80) >> 7) << 16 | (raw_ver & 0x7F);
5712 status = bnx2x_format_ver(spirom_ver, str, len);
5713 return status;
5714}
5715
5716static void bnx2x_8481_hw_reset(struct bnx2x_phy *phy,
5717 struct link_params *params)
5718{
5719 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
5720 MISC_REGISTERS_GPIO_OUTPUT_LOW, 0);
5721 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
5722 MISC_REGISTERS_GPIO_OUTPUT_LOW, 1);
5723}
5724
5725static void bnx2x_8481_link_reset(struct bnx2x_phy *phy,
5726 struct link_params *params)
5727{
5728 bnx2x_cl45_write(params->bp, phy,
5729 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x0000);
5730 bnx2x_cl45_write(params->bp, phy,
5731 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1);
5732}
5733
5734static void bnx2x_848x3_link_reset(struct bnx2x_phy *phy,
5735 struct link_params *params)
5736{
5737 struct bnx2x *bp = params->bp;
5738 u8 port = params->port;
5739 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
5740 MISC_REGISTERS_GPIO_OUTPUT_LOW,
5741 port);
5742}
5743
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005744static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy,
5745 struct link_params *params, u8 mode)
5746{
5747 struct bnx2x *bp = params->bp;
5748 u16 val;
5749
5750 switch (mode) {
5751 case LED_MODE_OFF:
5752
5753 DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE OFF\n", params->port);
5754
5755 if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
5756 SHARED_HW_CFG_LED_EXTPHY1) {
5757
5758 /* Set LED masks */
5759 bnx2x_cl45_write(bp, phy,
5760 MDIO_PMA_DEVAD,
5761 MDIO_PMA_REG_8481_LED1_MASK,
5762 0x0);
5763
5764 bnx2x_cl45_write(bp, phy,
5765 MDIO_PMA_DEVAD,
5766 MDIO_PMA_REG_8481_LED2_MASK,
5767 0x0);
5768
5769 bnx2x_cl45_write(bp, phy,
5770 MDIO_PMA_DEVAD,
5771 MDIO_PMA_REG_8481_LED3_MASK,
5772 0x0);
5773
5774 bnx2x_cl45_write(bp, phy,
5775 MDIO_PMA_DEVAD,
5776 MDIO_PMA_REG_8481_LED5_MASK,
5777 0x0);
5778
5779 } else {
5780 bnx2x_cl45_write(bp, phy,
5781 MDIO_PMA_DEVAD,
5782 MDIO_PMA_REG_8481_LED1_MASK,
5783 0x0);
5784 }
5785 break;
5786 case LED_MODE_FRONT_PANEL_OFF:
5787
5788 DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE FRONT PANEL OFF\n",
5789 params->port);
5790
5791 if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
5792 SHARED_HW_CFG_LED_EXTPHY1) {
5793
5794 /* Set LED masks */
5795 bnx2x_cl45_write(bp, phy,
5796 MDIO_PMA_DEVAD,
5797 MDIO_PMA_REG_8481_LED1_MASK,
5798 0x0);
5799
5800 bnx2x_cl45_write(bp, phy,
5801 MDIO_PMA_DEVAD,
5802 MDIO_PMA_REG_8481_LED2_MASK,
5803 0x0);
5804
5805 bnx2x_cl45_write(bp, phy,
5806 MDIO_PMA_DEVAD,
5807 MDIO_PMA_REG_8481_LED3_MASK,
5808 0x0);
5809
5810 bnx2x_cl45_write(bp, phy,
5811 MDIO_PMA_DEVAD,
5812 MDIO_PMA_REG_8481_LED5_MASK,
5813 0x20);
5814
5815 } else {
5816 bnx2x_cl45_write(bp, phy,
5817 MDIO_PMA_DEVAD,
5818 MDIO_PMA_REG_8481_LED1_MASK,
5819 0x0);
5820 }
5821 break;
5822 case LED_MODE_ON:
5823
5824 DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE ON\n", params->port);
5825
5826 if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
5827 SHARED_HW_CFG_LED_EXTPHY1) {
5828 /* Set control reg */
5829 bnx2x_cl45_read(bp, phy,
5830 MDIO_PMA_DEVAD,
5831 MDIO_PMA_REG_8481_LINK_SIGNAL,
5832 &val);
5833 val &= 0x8000;
5834 val |= 0x2492;
5835
5836 bnx2x_cl45_write(bp, phy,
5837 MDIO_PMA_DEVAD,
5838 MDIO_PMA_REG_8481_LINK_SIGNAL,
5839 val);
5840
5841 /* Set LED masks */
5842 bnx2x_cl45_write(bp, phy,
5843 MDIO_PMA_DEVAD,
5844 MDIO_PMA_REG_8481_LED1_MASK,
5845 0x0);
5846
5847 bnx2x_cl45_write(bp, phy,
5848 MDIO_PMA_DEVAD,
5849 MDIO_PMA_REG_8481_LED2_MASK,
5850 0x20);
5851
5852 bnx2x_cl45_write(bp, phy,
5853 MDIO_PMA_DEVAD,
5854 MDIO_PMA_REG_8481_LED3_MASK,
5855 0x20);
5856
5857 bnx2x_cl45_write(bp, phy,
5858 MDIO_PMA_DEVAD,
5859 MDIO_PMA_REG_8481_LED5_MASK,
5860 0x0);
5861 } else {
5862 bnx2x_cl45_write(bp, phy,
5863 MDIO_PMA_DEVAD,
5864 MDIO_PMA_REG_8481_LED1_MASK,
5865 0x20);
5866 }
5867 break;
5868
5869 case LED_MODE_OPER:
5870
5871 DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE OPER\n", params->port);
5872
5873 if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
5874 SHARED_HW_CFG_LED_EXTPHY1) {
5875
5876 /* Set control reg */
5877 bnx2x_cl45_read(bp, phy,
5878 MDIO_PMA_DEVAD,
5879 MDIO_PMA_REG_8481_LINK_SIGNAL,
5880 &val);
5881
5882 if (!((val &
5883 MDIO_PMA_REG_8481_LINK_SIGNAL_LED4_ENABLE_MASK)
5884 >> MDIO_PMA_REG_8481_LINK_SIGNAL_LED4_ENABLE_SHIFT)){
5885 DP(NETIF_MSG_LINK, "Seting LINK_SIGNAL\n");
5886 bnx2x_cl45_write(bp, phy,
5887 MDIO_PMA_DEVAD,
5888 MDIO_PMA_REG_8481_LINK_SIGNAL,
5889 0xa492);
5890 }
5891
5892 /* Set LED masks */
5893 bnx2x_cl45_write(bp, phy,
5894 MDIO_PMA_DEVAD,
5895 MDIO_PMA_REG_8481_LED1_MASK,
5896 0x10);
5897
5898 bnx2x_cl45_write(bp, phy,
5899 MDIO_PMA_DEVAD,
5900 MDIO_PMA_REG_8481_LED2_MASK,
5901 0x80);
5902
5903 bnx2x_cl45_write(bp, phy,
5904 MDIO_PMA_DEVAD,
5905 MDIO_PMA_REG_8481_LED3_MASK,
5906 0x98);
5907
5908 bnx2x_cl45_write(bp, phy,
5909 MDIO_PMA_DEVAD,
5910 MDIO_PMA_REG_8481_LED5_MASK,
5911 0x40);
5912
5913 } else {
5914 bnx2x_cl45_write(bp, phy,
5915 MDIO_PMA_DEVAD,
5916 MDIO_PMA_REG_8481_LED1_MASK,
5917 0x80);
5918 }
5919 break;
5920 }
5921}
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005922/******************************************************************/
5923/* SFX7101 PHY SECTION */
5924/******************************************************************/
5925static void bnx2x_7101_config_loopback(struct bnx2x_phy *phy,
5926 struct link_params *params)
5927{
5928 struct bnx2x *bp = params->bp;
5929 /* SFX7101_XGXS_TEST1 */
5930 bnx2x_cl45_write(bp, phy,
5931 MDIO_XS_DEVAD, MDIO_XS_SFX7101_XGXS_TEST1, 0x100);
5932}
5933
5934static u8 bnx2x_7101_config_init(struct bnx2x_phy *phy,
5935 struct link_params *params,
5936 struct link_vars *vars)
5937{
5938 u16 fw_ver1, fw_ver2, val;
5939 struct bnx2x *bp = params->bp;
5940 DP(NETIF_MSG_LINK, "Setting the SFX7101 LASI indication\n");
5941
5942 /* Restore normal power mode*/
5943 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
5944 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
5945 /* HW reset */
5946 bnx2x_ext_phy_hw_reset(bp, params->port);
5947 bnx2x_wait_reset_complete(bp, phy);
5948
5949 bnx2x_cl45_write(bp, phy,
5950 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x1);
5951 DP(NETIF_MSG_LINK, "Setting the SFX7101 LED to blink on traffic\n");
5952 bnx2x_cl45_write(bp, phy,
5953 MDIO_PMA_DEVAD, MDIO_PMA_REG_7107_LED_CNTL, (1<<3));
5954
5955 bnx2x_ext_phy_set_pause(params, phy, vars);
5956 /* Restart autoneg */
5957 bnx2x_cl45_read(bp, phy,
5958 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, &val);
5959 val |= 0x200;
5960 bnx2x_cl45_write(bp, phy,
5961 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, val);
5962
5963 /* Save spirom version */
5964 bnx2x_cl45_read(bp, phy,
5965 MDIO_PMA_DEVAD, MDIO_PMA_REG_7101_VER1, &fw_ver1);
5966
5967 bnx2x_cl45_read(bp, phy,
5968 MDIO_PMA_DEVAD, MDIO_PMA_REG_7101_VER2, &fw_ver2);
5969 bnx2x_save_spirom_version(bp, params->port,
5970 (u32)(fw_ver1<<16 | fw_ver2), phy->ver_addr);
5971 return 0;
5972}
5973
5974static u8 bnx2x_7101_read_status(struct bnx2x_phy *phy,
5975 struct link_params *params,
5976 struct link_vars *vars)
5977{
5978 struct bnx2x *bp = params->bp;
5979 u8 link_up;
5980 u16 val1, val2;
5981 bnx2x_cl45_read(bp, phy,
5982 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val2);
5983 bnx2x_cl45_read(bp, phy,
5984 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
5985 DP(NETIF_MSG_LINK, "10G-base-T LASI status 0x%x->0x%x\n",
5986 val2, val1);
5987 bnx2x_cl45_read(bp, phy,
5988 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
5989 bnx2x_cl45_read(bp, phy,
5990 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
5991 DP(NETIF_MSG_LINK, "10G-base-T PMA status 0x%x->0x%x\n",
5992 val2, val1);
5993 link_up = ((val1 & 4) == 4);
5994 /* if link is up
5995 * print the AN outcome of the SFX7101 PHY
5996 */
5997 if (link_up) {
5998 bnx2x_cl45_read(bp, phy,
5999 MDIO_AN_DEVAD, MDIO_AN_REG_MASTER_STATUS,
6000 &val2);
6001 vars->line_speed = SPEED_10000;
6002 DP(NETIF_MSG_LINK, "SFX7101 AN status 0x%x->Master=%x\n",
6003 val2, (val2 & (1<<14)));
6004 bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
6005 bnx2x_ext_phy_resolve_fc(phy, params, vars);
6006 }
6007 return link_up;
6008}
6009
6010
6011static u8 bnx2x_7101_format_ver(u32 spirom_ver, u8 *str, u16 *len)
6012{
6013 if (*len < 5)
6014 return -EINVAL;
6015 str[0] = (spirom_ver & 0xFF);
6016 str[1] = (spirom_ver & 0xFF00) >> 8;
6017 str[2] = (spirom_ver & 0xFF0000) >> 16;
6018 str[3] = (spirom_ver & 0xFF000000) >> 24;
6019 str[4] = '\0';
6020 *len -= 5;
6021 return 0;
6022}
6023
6024void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, struct bnx2x_phy *phy)
6025{
6026 u16 val, cnt;
6027
6028 bnx2x_cl45_read(bp, phy,
6029 MDIO_PMA_DEVAD,
6030 MDIO_PMA_REG_7101_RESET, &val);
6031
6032 for (cnt = 0; cnt < 10; cnt++) {
6033 msleep(50);
6034 /* Writes a self-clearing reset */
6035 bnx2x_cl45_write(bp, phy,
6036 MDIO_PMA_DEVAD,
6037 MDIO_PMA_REG_7101_RESET,
6038 (val | (1<<15)));
6039 /* Wait for clear */
6040 bnx2x_cl45_read(bp, phy,
6041 MDIO_PMA_DEVAD,
6042 MDIO_PMA_REG_7101_RESET, &val);
6043
6044 if ((val & (1<<15)) == 0)
6045 break;
6046 }
6047}
6048
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006049static void bnx2x_7101_hw_reset(struct bnx2x_phy *phy,
6050 struct link_params *params) {
6051 /* Low power mode is controlled by GPIO 2 */
6052 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_2,
6053 MISC_REGISTERS_GPIO_OUTPUT_LOW, params->port);
6054 /* The PHY reset is controlled by GPIO 1 */
6055 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
6056 MISC_REGISTERS_GPIO_OUTPUT_LOW, params->port);
6057}
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006058
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006059static void bnx2x_7101_set_link_led(struct bnx2x_phy *phy,
6060 struct link_params *params, u8 mode)
6061{
6062 u16 val = 0;
6063 struct bnx2x *bp = params->bp;
6064 switch (mode) {
6065 case LED_MODE_FRONT_PANEL_OFF:
6066 case LED_MODE_OFF:
6067 val = 2;
6068 break;
6069 case LED_MODE_ON:
6070 val = 1;
6071 break;
6072 case LED_MODE_OPER:
6073 val = 0;
6074 break;
6075 }
6076 bnx2x_cl45_write(bp, phy,
6077 MDIO_PMA_DEVAD,
6078 MDIO_PMA_REG_7107_LINK_LED_CNTL,
6079 val);
6080}
6081
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006082/******************************************************************/
6083/* STATIC PHY DECLARATION */
6084/******************************************************************/
6085
6086static struct bnx2x_phy phy_null = {
6087 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN,
6088 .addr = 0,
6089 .flags = FLAGS_INIT_XGXS_FIRST,
6090 .def_md_devad = 0,
6091 .reserved = 0,
6092 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6093 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6094 .mdio_ctrl = 0,
6095 .supported = 0,
6096 .media_type = ETH_PHY_NOT_PRESENT,
6097 .ver_addr = 0,
6098 .req_flow_ctrl = 0,
6099 .req_line_speed = 0,
6100 .speed_cap_mask = 0,
6101 .req_duplex = 0,
6102 .rsrv = 0,
6103 .config_init = (config_init_t)NULL,
6104 .read_status = (read_status_t)NULL,
6105 .link_reset = (link_reset_t)NULL,
6106 .config_loopback = (config_loopback_t)NULL,
6107 .format_fw_ver = (format_fw_ver_t)NULL,
6108 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006109 .set_link_led = (set_link_led_t)NULL,
6110 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006111};
6112
6113static struct bnx2x_phy phy_serdes = {
6114 .type = PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT,
6115 .addr = 0xff,
6116 .flags = 0,
6117 .def_md_devad = 0,
6118 .reserved = 0,
6119 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6120 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6121 .mdio_ctrl = 0,
6122 .supported = (SUPPORTED_10baseT_Half |
6123 SUPPORTED_10baseT_Full |
6124 SUPPORTED_100baseT_Half |
6125 SUPPORTED_100baseT_Full |
6126 SUPPORTED_1000baseT_Full |
6127 SUPPORTED_2500baseX_Full |
6128 SUPPORTED_TP |
6129 SUPPORTED_Autoneg |
6130 SUPPORTED_Pause |
6131 SUPPORTED_Asym_Pause),
6132 .media_type = ETH_PHY_UNSPECIFIED,
6133 .ver_addr = 0,
6134 .req_flow_ctrl = 0,
6135 .req_line_speed = 0,
6136 .speed_cap_mask = 0,
6137 .req_duplex = 0,
6138 .rsrv = 0,
6139 .config_init = (config_init_t)bnx2x_init_serdes,
6140 .read_status = (read_status_t)bnx2x_link_settings_status,
6141 .link_reset = (link_reset_t)bnx2x_int_link_reset,
6142 .config_loopback = (config_loopback_t)NULL,
6143 .format_fw_ver = (format_fw_ver_t)NULL,
6144 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006145 .set_link_led = (set_link_led_t)NULL,
6146 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006147};
6148
6149static struct bnx2x_phy phy_xgxs = {
6150 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT,
6151 .addr = 0xff,
6152 .flags = 0,
6153 .def_md_devad = 0,
6154 .reserved = 0,
6155 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6156 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6157 .mdio_ctrl = 0,
6158 .supported = (SUPPORTED_10baseT_Half |
6159 SUPPORTED_10baseT_Full |
6160 SUPPORTED_100baseT_Half |
6161 SUPPORTED_100baseT_Full |
6162 SUPPORTED_1000baseT_Full |
6163 SUPPORTED_2500baseX_Full |
6164 SUPPORTED_10000baseT_Full |
6165 SUPPORTED_FIBRE |
6166 SUPPORTED_Autoneg |
6167 SUPPORTED_Pause |
6168 SUPPORTED_Asym_Pause),
6169 .media_type = ETH_PHY_UNSPECIFIED,
6170 .ver_addr = 0,
6171 .req_flow_ctrl = 0,
6172 .req_line_speed = 0,
6173 .speed_cap_mask = 0,
6174 .req_duplex = 0,
6175 .rsrv = 0,
6176 .config_init = (config_init_t)bnx2x_init_xgxs,
6177 .read_status = (read_status_t)bnx2x_link_settings_status,
6178 .link_reset = (link_reset_t)bnx2x_int_link_reset,
6179 .config_loopback = (config_loopback_t)bnx2x_set_xgxs_loopback,
6180 .format_fw_ver = (format_fw_ver_t)NULL,
6181 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006182 .set_link_led = (set_link_led_t)NULL,
6183 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006184};
6185
6186static struct bnx2x_phy phy_7101 = {
6187 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
6188 .addr = 0xff,
6189 .flags = FLAGS_FAN_FAILURE_DET_REQ,
6190 .def_md_devad = 0,
6191 .reserved = 0,
6192 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6193 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6194 .mdio_ctrl = 0,
6195 .supported = (SUPPORTED_10000baseT_Full |
6196 SUPPORTED_TP |
6197 SUPPORTED_Autoneg |
6198 SUPPORTED_Pause |
6199 SUPPORTED_Asym_Pause),
6200 .media_type = ETH_PHY_BASE_T,
6201 .ver_addr = 0,
6202 .req_flow_ctrl = 0,
6203 .req_line_speed = 0,
6204 .speed_cap_mask = 0,
6205 .req_duplex = 0,
6206 .rsrv = 0,
6207 .config_init = (config_init_t)bnx2x_7101_config_init,
6208 .read_status = (read_status_t)bnx2x_7101_read_status,
6209 .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
6210 .config_loopback = (config_loopback_t)bnx2x_7101_config_loopback,
6211 .format_fw_ver = (format_fw_ver_t)bnx2x_7101_format_ver,
6212 .hw_reset = (hw_reset_t)bnx2x_7101_hw_reset,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006213 .set_link_led = (set_link_led_t)bnx2x_7101_set_link_led,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006214 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006215};
6216static struct bnx2x_phy phy_8073 = {
6217 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
6218 .addr = 0xff,
6219 .flags = FLAGS_HW_LOCK_REQUIRED,
6220 .def_md_devad = 0,
6221 .reserved = 0,
6222 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6223 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6224 .mdio_ctrl = 0,
6225 .supported = (SUPPORTED_10000baseT_Full |
6226 SUPPORTED_2500baseX_Full |
6227 SUPPORTED_1000baseT_Full |
6228 SUPPORTED_FIBRE |
6229 SUPPORTED_Autoneg |
6230 SUPPORTED_Pause |
6231 SUPPORTED_Asym_Pause),
6232 .media_type = ETH_PHY_UNSPECIFIED,
6233 .ver_addr = 0,
6234 .req_flow_ctrl = 0,
6235 .req_line_speed = 0,
6236 .speed_cap_mask = 0,
6237 .req_duplex = 0,
6238 .rsrv = 0,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00006239 .config_init = (config_init_t)bnx2x_8073_config_init,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006240 .read_status = (read_status_t)bnx2x_8073_read_status,
6241 .link_reset = (link_reset_t)bnx2x_8073_link_reset,
6242 .config_loopback = (config_loopback_t)NULL,
6243 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
6244 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006245 .set_link_led = (set_link_led_t)NULL,
6246 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006247};
6248static struct bnx2x_phy phy_8705 = {
6249 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705,
6250 .addr = 0xff,
6251 .flags = FLAGS_INIT_XGXS_FIRST,
6252 .def_md_devad = 0,
6253 .reserved = 0,
6254 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6255 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6256 .mdio_ctrl = 0,
6257 .supported = (SUPPORTED_10000baseT_Full |
6258 SUPPORTED_FIBRE |
6259 SUPPORTED_Pause |
6260 SUPPORTED_Asym_Pause),
6261 .media_type = ETH_PHY_XFP_FIBER,
6262 .ver_addr = 0,
6263 .req_flow_ctrl = 0,
6264 .req_line_speed = 0,
6265 .speed_cap_mask = 0,
6266 .req_duplex = 0,
6267 .rsrv = 0,
6268 .config_init = (config_init_t)bnx2x_8705_config_init,
6269 .read_status = (read_status_t)bnx2x_8705_read_status,
6270 .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
6271 .config_loopback = (config_loopback_t)NULL,
6272 .format_fw_ver = (format_fw_ver_t)bnx2x_null_format_ver,
6273 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006274 .set_link_led = (set_link_led_t)NULL,
6275 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006276};
6277static struct bnx2x_phy phy_8706 = {
6278 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706,
6279 .addr = 0xff,
6280 .flags = FLAGS_INIT_XGXS_FIRST,
6281 .def_md_devad = 0,
6282 .reserved = 0,
6283 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6284 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6285 .mdio_ctrl = 0,
6286 .supported = (SUPPORTED_10000baseT_Full |
6287 SUPPORTED_1000baseT_Full |
6288 SUPPORTED_FIBRE |
6289 SUPPORTED_Pause |
6290 SUPPORTED_Asym_Pause),
6291 .media_type = ETH_PHY_SFP_FIBER,
6292 .ver_addr = 0,
6293 .req_flow_ctrl = 0,
6294 .req_line_speed = 0,
6295 .speed_cap_mask = 0,
6296 .req_duplex = 0,
6297 .rsrv = 0,
6298 .config_init = (config_init_t)bnx2x_8706_config_init,
6299 .read_status = (read_status_t)bnx2x_8706_read_status,
6300 .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
6301 .config_loopback = (config_loopback_t)NULL,
6302 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
6303 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006304 .set_link_led = (set_link_led_t)NULL,
6305 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006306};
6307
6308static struct bnx2x_phy phy_8726 = {
6309 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
6310 .addr = 0xff,
6311 .flags = (FLAGS_HW_LOCK_REQUIRED |
6312 FLAGS_INIT_XGXS_FIRST),
6313 .def_md_devad = 0,
6314 .reserved = 0,
6315 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6316 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6317 .mdio_ctrl = 0,
6318 .supported = (SUPPORTED_10000baseT_Full |
6319 SUPPORTED_1000baseT_Full |
6320 SUPPORTED_Autoneg |
6321 SUPPORTED_FIBRE |
6322 SUPPORTED_Pause |
6323 SUPPORTED_Asym_Pause),
6324 .media_type = ETH_PHY_SFP_FIBER,
6325 .ver_addr = 0,
6326 .req_flow_ctrl = 0,
6327 .req_line_speed = 0,
6328 .speed_cap_mask = 0,
6329 .req_duplex = 0,
6330 .rsrv = 0,
6331 .config_init = (config_init_t)bnx2x_8726_config_init,
6332 .read_status = (read_status_t)bnx2x_8726_read_status,
6333 .link_reset = (link_reset_t)bnx2x_8726_link_reset,
6334 .config_loopback = (config_loopback_t)bnx2x_8726_config_loopback,
6335 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
6336 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006337 .set_link_led = (set_link_led_t)NULL,
6338 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006339};
6340
6341static struct bnx2x_phy phy_8727 = {
6342 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
6343 .addr = 0xff,
6344 .flags = FLAGS_FAN_FAILURE_DET_REQ,
6345 .def_md_devad = 0,
6346 .reserved = 0,
6347 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6348 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6349 .mdio_ctrl = 0,
6350 .supported = (SUPPORTED_10000baseT_Full |
6351 SUPPORTED_1000baseT_Full |
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006352 SUPPORTED_FIBRE |
6353 SUPPORTED_Pause |
6354 SUPPORTED_Asym_Pause),
6355 .media_type = ETH_PHY_SFP_FIBER,
6356 .ver_addr = 0,
6357 .req_flow_ctrl = 0,
6358 .req_line_speed = 0,
6359 .speed_cap_mask = 0,
6360 .req_duplex = 0,
6361 .rsrv = 0,
6362 .config_init = (config_init_t)bnx2x_8727_config_init,
6363 .read_status = (read_status_t)bnx2x_8727_read_status,
6364 .link_reset = (link_reset_t)bnx2x_8727_link_reset,
6365 .config_loopback = (config_loopback_t)NULL,
6366 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
6367 .hw_reset = (hw_reset_t)bnx2x_8727_hw_reset,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006368 .set_link_led = (set_link_led_t)bnx2x_8727_set_link_led,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006369 .phy_specific_func = (phy_specific_func_t)bnx2x_8727_specific_func
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006370};
6371static struct bnx2x_phy phy_8481 = {
6372 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
6373 .addr = 0xff,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006374 .flags = FLAGS_FAN_FAILURE_DET_REQ |
6375 FLAGS_REARM_LATCH_SIGNAL,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006376 .def_md_devad = 0,
6377 .reserved = 0,
6378 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6379 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6380 .mdio_ctrl = 0,
6381 .supported = (SUPPORTED_10baseT_Half |
6382 SUPPORTED_10baseT_Full |
6383 SUPPORTED_100baseT_Half |
6384 SUPPORTED_100baseT_Full |
6385 SUPPORTED_1000baseT_Full |
6386 SUPPORTED_10000baseT_Full |
6387 SUPPORTED_TP |
6388 SUPPORTED_Autoneg |
6389 SUPPORTED_Pause |
6390 SUPPORTED_Asym_Pause),
6391 .media_type = ETH_PHY_BASE_T,
6392 .ver_addr = 0,
6393 .req_flow_ctrl = 0,
6394 .req_line_speed = 0,
6395 .speed_cap_mask = 0,
6396 .req_duplex = 0,
6397 .rsrv = 0,
6398 .config_init = (config_init_t)bnx2x_8481_config_init,
6399 .read_status = (read_status_t)bnx2x_848xx_read_status,
6400 .link_reset = (link_reset_t)bnx2x_8481_link_reset,
6401 .config_loopback = (config_loopback_t)NULL,
6402 .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver,
6403 .hw_reset = (hw_reset_t)bnx2x_8481_hw_reset,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006404 .set_link_led = (set_link_led_t)bnx2x_848xx_set_link_led,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006405 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006406};
6407
6408static struct bnx2x_phy phy_84823 = {
6409 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823,
6410 .addr = 0xff,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006411 .flags = FLAGS_FAN_FAILURE_DET_REQ |
6412 FLAGS_REARM_LATCH_SIGNAL,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006413 .def_md_devad = 0,
6414 .reserved = 0,
6415 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6416 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6417 .mdio_ctrl = 0,
6418 .supported = (SUPPORTED_10baseT_Half |
6419 SUPPORTED_10baseT_Full |
6420 SUPPORTED_100baseT_Half |
6421 SUPPORTED_100baseT_Full |
6422 SUPPORTED_1000baseT_Full |
6423 SUPPORTED_10000baseT_Full |
6424 SUPPORTED_TP |
6425 SUPPORTED_Autoneg |
6426 SUPPORTED_Pause |
6427 SUPPORTED_Asym_Pause),
6428 .media_type = ETH_PHY_BASE_T,
6429 .ver_addr = 0,
6430 .req_flow_ctrl = 0,
6431 .req_line_speed = 0,
6432 .speed_cap_mask = 0,
6433 .req_duplex = 0,
6434 .rsrv = 0,
6435 .config_init = (config_init_t)bnx2x_848x3_config_init,
6436 .read_status = (read_status_t)bnx2x_848xx_read_status,
6437 .link_reset = (link_reset_t)bnx2x_848x3_link_reset,
6438 .config_loopback = (config_loopback_t)NULL,
6439 .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver,
6440 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006441 .set_link_led = (set_link_led_t)bnx2x_848xx_set_link_led,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006442 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006443};
6444
6445/*****************************************************************/
6446/* */
6447/* Populate the phy according. Main function: bnx2x_populate_phy */
6448/* */
6449/*****************************************************************/
6450
6451static void bnx2x_populate_preemphasis(struct bnx2x *bp, u32 shmem_base,
6452 struct bnx2x_phy *phy, u8 port,
6453 u8 phy_index)
6454{
6455 /* Get the 4 lanes xgxs config rx and tx */
6456 u32 rx = 0, tx = 0, i;
6457 for (i = 0; i < 2; i++) {
6458 /**
6459 * INT_PHY and EXT_PHY1 share the same value location in the
6460 * shmem. When num_phys is greater than 1, than this value
6461 * applies only to EXT_PHY1
6462 */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006463 if (phy_index == INT_PHY || phy_index == EXT_PHY1) {
6464 rx = REG_RD(bp, shmem_base +
6465 offsetof(struct shmem_region,
6466 dev_info.port_hw_config[port].xgxs_config_rx[i<<1]));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006467
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006468 tx = REG_RD(bp, shmem_base +
6469 offsetof(struct shmem_region,
6470 dev_info.port_hw_config[port].xgxs_config_tx[i<<1]));
6471 } else {
6472 rx = REG_RD(bp, shmem_base +
6473 offsetof(struct shmem_region,
6474 dev_info.port_hw_config[port].xgxs_config2_rx[i<<1]));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006475
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006476 tx = REG_RD(bp, shmem_base +
6477 offsetof(struct shmem_region,
6478 dev_info.port_hw_config[port].xgxs_config2_rx[i<<1]));
6479 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006480
6481 phy->rx_preemphasis[i << 1] = ((rx>>16) & 0xffff);
6482 phy->rx_preemphasis[(i << 1) + 1] = (rx & 0xffff);
6483
6484 phy->tx_preemphasis[i << 1] = ((tx>>16) & 0xffff);
6485 phy->tx_preemphasis[(i << 1) + 1] = (tx & 0xffff);
6486 }
6487}
6488
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006489static u32 bnx2x_get_ext_phy_config(struct bnx2x *bp, u32 shmem_base,
6490 u8 phy_index, u8 port)
6491{
6492 u32 ext_phy_config = 0;
6493 switch (phy_index) {
6494 case EXT_PHY1:
6495 ext_phy_config = REG_RD(bp, shmem_base +
6496 offsetof(struct shmem_region,
6497 dev_info.port_hw_config[port].external_phy_config));
6498 break;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006499 case EXT_PHY2:
6500 ext_phy_config = REG_RD(bp, shmem_base +
6501 offsetof(struct shmem_region,
6502 dev_info.port_hw_config[port].external_phy_config2));
6503 break;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006504 default:
6505 DP(NETIF_MSG_LINK, "Invalid phy_index %d\n", phy_index);
6506 return -EINVAL;
6507 }
6508
6509 return ext_phy_config;
6510}
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006511static u8 bnx2x_populate_int_phy(struct bnx2x *bp, u32 shmem_base, u8 port,
6512 struct bnx2x_phy *phy)
6513{
6514 u32 phy_addr;
6515 u32 chip_id;
6516 u32 switch_cfg = (REG_RD(bp, shmem_base +
6517 offsetof(struct shmem_region,
6518 dev_info.port_feature_config[port].link_config)) &
6519 PORT_FEATURE_CONNECTED_SWITCH_MASK);
6520 chip_id = REG_RD(bp, MISC_REG_CHIP_NUM) << 16;
6521 switch (switch_cfg) {
6522 case SWITCH_CFG_1G:
6523 phy_addr = REG_RD(bp,
6524 NIG_REG_SERDES0_CTRL_PHY_ADDR +
6525 port * 0x10);
6526 *phy = phy_serdes;
6527 break;
6528 case SWITCH_CFG_10G:
6529 phy_addr = REG_RD(bp,
6530 NIG_REG_XGXS0_CTRL_PHY_ADDR +
6531 port * 0x18);
6532 *phy = phy_xgxs;
6533 break;
6534 default:
6535 DP(NETIF_MSG_LINK, "Invalid switch_cfg\n");
6536 return -EINVAL;
6537 }
6538 phy->addr = (u8)phy_addr;
6539 phy->mdio_ctrl = bnx2x_get_emac_base(bp,
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00006540 SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006541 port);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00006542 if (CHIP_IS_E2(bp))
6543 phy->def_md_devad = E2_DEFAULT_PHY_DEV_ADDR;
6544 else
6545 phy->def_md_devad = DEFAULT_PHY_DEV_ADDR;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006546
6547 DP(NETIF_MSG_LINK, "Internal phy port=%d, addr=0x%x, mdio_ctl=0x%x\n",
6548 port, phy->addr, phy->mdio_ctrl);
6549
6550 bnx2x_populate_preemphasis(bp, shmem_base, phy, port, INT_PHY);
6551 return 0;
6552}
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006553
6554static u8 bnx2x_populate_ext_phy(struct bnx2x *bp,
6555 u8 phy_index,
6556 u32 shmem_base,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006557 u32 shmem2_base,
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006558 u8 port,
6559 struct bnx2x_phy *phy)
6560{
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00006561 u32 ext_phy_config, phy_type, config2;
6562 u32 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006563 ext_phy_config = bnx2x_get_ext_phy_config(bp, shmem_base,
6564 phy_index, port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006565 phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
6566 /* Select the phy type */
6567 switch (phy_type) {
6568 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00006569 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_SWAPPED;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006570 *phy = phy_8073;
6571 break;
6572 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
6573 *phy = phy_8705;
6574 break;
6575 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
6576 *phy = phy_8706;
6577 break;
6578 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00006579 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006580 *phy = phy_8726;
6581 break;
6582 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
6583 /* BCM8727_NOC => BCM8727 no over current */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00006584 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006585 *phy = phy_8727;
6586 phy->flags |= FLAGS_NOC;
6587 break;
6588 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00006589 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006590 *phy = phy_8727;
6591 break;
6592 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
6593 *phy = phy_8481;
6594 break;
6595 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
6596 *phy = phy_84823;
6597 break;
6598 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
6599 *phy = phy_7101;
6600 break;
6601 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
6602 *phy = phy_null;
6603 return -EINVAL;
6604 default:
6605 *phy = phy_null;
6606 return 0;
6607 }
6608
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006609 phy->addr = XGXS_EXT_PHY_ADDR(ext_phy_config);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006610 bnx2x_populate_preemphasis(bp, shmem_base, phy, port, phy_index);
Yaniv Rosner62b29a52010-09-07 11:40:58 +00006611
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00006612 /**
6613 * The shmem address of the phy version is located on different
6614 * structures. In case this structure is too old, do not set
6615 * the address
6616 */
6617 config2 = REG_RD(bp, shmem_base + offsetof(struct shmem_region,
6618 dev_info.shared_hw_config.config2));
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006619 if (phy_index == EXT_PHY1) {
6620 phy->ver_addr = shmem_base + offsetof(struct shmem_region,
6621 port_mb[port].ext_phy_fw_version);
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00006622
6623 /* Check specific mdc mdio settings */
6624 if (config2 & SHARED_HW_CFG_MDC_MDIO_ACCESS1_MASK)
6625 mdc_mdio_access = config2 &
6626 SHARED_HW_CFG_MDC_MDIO_ACCESS1_MASK;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006627 } else {
6628 u32 size = REG_RD(bp, shmem2_base);
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00006629
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006630 if (size >
6631 offsetof(struct shmem2_region, ext_phy_fw_version2)) {
6632 phy->ver_addr = shmem2_base +
6633 offsetof(struct shmem2_region,
6634 ext_phy_fw_version2[port]);
6635 }
6636 /* Check specific mdc mdio settings */
6637 if (config2 & SHARED_HW_CFG_MDC_MDIO_ACCESS2_MASK)
6638 mdc_mdio_access = (config2 &
6639 SHARED_HW_CFG_MDC_MDIO_ACCESS2_MASK) >>
6640 (SHARED_HW_CFG_MDC_MDIO_ACCESS2_SHIFT -
6641 SHARED_HW_CFG_MDC_MDIO_ACCESS1_SHIFT);
6642 }
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00006643 phy->mdio_ctrl = bnx2x_get_emac_base(bp, mdc_mdio_access, port);
6644
6645 /**
6646 * In case mdc/mdio_access of the external phy is different than the
6647 * mdc/mdio access of the XGXS, a HW lock must be taken in each access
6648 * to prevent one port interfere with another port's CL45 operations.
6649 */
6650 if (mdc_mdio_access != SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH)
6651 phy->flags |= FLAGS_HW_LOCK_REQUIRED;
6652 DP(NETIF_MSG_LINK, "phy_type 0x%x port %d found in index %d\n",
6653 phy_type, port, phy_index);
6654 DP(NETIF_MSG_LINK, " addr=0x%x, mdio_ctl=0x%x\n",
6655 phy->addr, phy->mdio_ctrl);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006656 return 0;
6657}
6658
6659static u8 bnx2x_populate_phy(struct bnx2x *bp, u8 phy_index, u32 shmem_base,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006660 u32 shmem2_base, u8 port, struct bnx2x_phy *phy)
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006661{
6662 u8 status = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006663 phy->type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN;
6664 if (phy_index == INT_PHY)
6665 return bnx2x_populate_int_phy(bp, shmem_base, port, phy);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006666 status = bnx2x_populate_ext_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006667 port, phy);
6668 return status;
6669}
6670
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006671static void bnx2x_phy_def_cfg(struct link_params *params,
6672 struct bnx2x_phy *phy,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006673 u8 phy_index)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006674{
6675 struct bnx2x *bp = params->bp;
6676 u32 link_config;
6677 /* Populate the default phy configuration for MF mode */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006678 if (phy_index == EXT_PHY2) {
6679 link_config = REG_RD(bp, params->shmem_base +
6680 offsetof(struct shmem_region, dev_info.
6681 port_feature_config[params->port].link_config2));
6682 phy->speed_cap_mask = REG_RD(bp, params->shmem_base +
6683 offsetof(struct shmem_region, dev_info.
6684 port_hw_config[params->port].speed_capability_mask2));
6685 } else {
6686 link_config = REG_RD(bp, params->shmem_base +
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006687 offsetof(struct shmem_region, dev_info.
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006688 port_feature_config[params->port].link_config));
6689 phy->speed_cap_mask = REG_RD(bp, params->shmem_base +
6690 offsetof(struct shmem_region, dev_info.
6691 port_hw_config[params->port].speed_capability_mask));
6692 }
6693 DP(NETIF_MSG_LINK, "Default config phy idx %x cfg 0x%x speed_cap_mask"
6694 " 0x%x\n", phy_index, link_config, phy->speed_cap_mask);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006695
6696 phy->req_duplex = DUPLEX_FULL;
6697 switch (link_config & PORT_FEATURE_LINK_SPEED_MASK) {
6698 case PORT_FEATURE_LINK_SPEED_10M_HALF:
6699 phy->req_duplex = DUPLEX_HALF;
6700 case PORT_FEATURE_LINK_SPEED_10M_FULL:
6701 phy->req_line_speed = SPEED_10;
6702 break;
6703 case PORT_FEATURE_LINK_SPEED_100M_HALF:
6704 phy->req_duplex = DUPLEX_HALF;
6705 case PORT_FEATURE_LINK_SPEED_100M_FULL:
6706 phy->req_line_speed = SPEED_100;
6707 break;
6708 case PORT_FEATURE_LINK_SPEED_1G:
6709 phy->req_line_speed = SPEED_1000;
6710 break;
6711 case PORT_FEATURE_LINK_SPEED_2_5G:
6712 phy->req_line_speed = SPEED_2500;
6713 break;
6714 case PORT_FEATURE_LINK_SPEED_10G_CX4:
6715 phy->req_line_speed = SPEED_10000;
6716 break;
6717 default:
6718 phy->req_line_speed = SPEED_AUTO_NEG;
6719 break;
6720 }
6721
6722 switch (link_config & PORT_FEATURE_FLOW_CONTROL_MASK) {
6723 case PORT_FEATURE_FLOW_CONTROL_AUTO:
6724 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_AUTO;
6725 break;
6726 case PORT_FEATURE_FLOW_CONTROL_TX:
6727 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_TX;
6728 break;
6729 case PORT_FEATURE_FLOW_CONTROL_RX:
6730 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_RX;
6731 break;
6732 case PORT_FEATURE_FLOW_CONTROL_BOTH:
6733 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_BOTH;
6734 break;
6735 default:
6736 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_NONE;
6737 break;
6738 }
6739}
6740
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006741u32 bnx2x_phy_selection(struct link_params *params)
6742{
6743 u32 phy_config_swapped, prio_cfg;
6744 u32 return_cfg = PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT;
6745
6746 phy_config_swapped = params->multi_phy_config &
6747 PORT_HW_CFG_PHY_SWAPPED_ENABLED;
6748
6749 prio_cfg = params->multi_phy_config &
6750 PORT_HW_CFG_PHY_SELECTION_MASK;
6751
6752 if (phy_config_swapped) {
6753 switch (prio_cfg) {
6754 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
6755 return_cfg = PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY;
6756 break;
6757 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
6758 return_cfg = PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY;
6759 break;
6760 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY:
6761 return_cfg = PORT_HW_CFG_PHY_SELECTION_FIRST_PHY;
6762 break;
6763 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY:
6764 return_cfg = PORT_HW_CFG_PHY_SELECTION_SECOND_PHY;
6765 break;
6766 }
6767 } else
6768 return_cfg = prio_cfg;
6769
6770 return return_cfg;
6771}
6772
6773
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006774u8 bnx2x_phy_probe(struct link_params *params)
6775{
6776 u8 phy_index, actual_phy_idx, link_cfg_idx;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006777 u32 phy_config_swapped;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006778 struct bnx2x *bp = params->bp;
6779 struct bnx2x_phy *phy;
6780 params->num_phys = 0;
6781 DP(NETIF_MSG_LINK, "Begin phy probe\n");
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006782 phy_config_swapped = params->multi_phy_config &
6783 PORT_HW_CFG_PHY_SWAPPED_ENABLED;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006784
6785 for (phy_index = INT_PHY; phy_index < MAX_PHYS;
6786 phy_index++) {
6787 link_cfg_idx = LINK_CONFIG_IDX(phy_index);
6788 actual_phy_idx = phy_index;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006789 if (phy_config_swapped) {
6790 if (phy_index == EXT_PHY1)
6791 actual_phy_idx = EXT_PHY2;
6792 else if (phy_index == EXT_PHY2)
6793 actual_phy_idx = EXT_PHY1;
6794 }
6795 DP(NETIF_MSG_LINK, "phy_config_swapped %x, phy_index %x,"
6796 " actual_phy_idx %x\n", phy_config_swapped,
6797 phy_index, actual_phy_idx);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006798 phy = &params->phy[actual_phy_idx];
6799 if (bnx2x_populate_phy(bp, phy_index, params->shmem_base,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006800 params->shmem2_base, params->port,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006801 phy) != 0) {
6802 params->num_phys = 0;
6803 DP(NETIF_MSG_LINK, "phy probe failed in phy index %d\n",
6804 phy_index);
6805 for (phy_index = INT_PHY;
6806 phy_index < MAX_PHYS;
6807 phy_index++)
6808 *phy = phy_null;
6809 return -EINVAL;
6810 }
6811 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)
6812 break;
6813
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006814 bnx2x_phy_def_cfg(params, phy, phy_index);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006815 params->num_phys++;
6816 }
6817
6818 DP(NETIF_MSG_LINK, "End phy probe. #phys found %x\n", params->num_phys);
6819 return 0;
6820}
6821
6822u32 bnx2x_supported_attr(struct link_params *params, u8 phy_idx)
6823{
6824 if (phy_idx < params->num_phys)
6825 return params->phy[phy_idx].supported;
6826 return 0;
6827}
6828
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006829static void set_phy_vars(struct link_params *params)
6830{
6831 struct bnx2x *bp = params->bp;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006832 u8 actual_phy_idx, phy_index, link_cfg_idx;
6833 u8 phy_config_swapped = params->multi_phy_config &
6834 PORT_HW_CFG_PHY_SWAPPED_ENABLED;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006835 for (phy_index = INT_PHY; phy_index < params->num_phys;
6836 phy_index++) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006837 link_cfg_idx = LINK_CONFIG_IDX(phy_index);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006838 actual_phy_idx = phy_index;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006839 if (phy_config_swapped) {
6840 if (phy_index == EXT_PHY1)
6841 actual_phy_idx = EXT_PHY2;
6842 else if (phy_index == EXT_PHY2)
6843 actual_phy_idx = EXT_PHY1;
6844 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006845 params->phy[actual_phy_idx].req_flow_ctrl =
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006846 params->req_flow_ctrl[link_cfg_idx];
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006847
6848 params->phy[actual_phy_idx].req_line_speed =
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006849 params->req_line_speed[link_cfg_idx];
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006850
6851 params->phy[actual_phy_idx].speed_cap_mask =
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006852 params->speed_cap_mask[link_cfg_idx];
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006853
6854 params->phy[actual_phy_idx].req_duplex =
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006855 params->req_duplex[link_cfg_idx];
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006856
6857 DP(NETIF_MSG_LINK, "req_flow_ctrl %x, req_line_speed %x,"
6858 " speed_cap_mask %x\n",
6859 params->phy[actual_phy_idx].req_flow_ctrl,
6860 params->phy[actual_phy_idx].req_line_speed,
6861 params->phy[actual_phy_idx].speed_cap_mask);
6862 }
6863}
6864
6865u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
6866{
6867 struct bnx2x *bp = params->bp;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006868 DP(NETIF_MSG_LINK, "Phy Initialization started\n");
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006869 DP(NETIF_MSG_LINK, "(1) req_speed %d, req_flowctrl %d\n",
6870 params->req_line_speed[0], params->req_flow_ctrl[0]);
6871 DP(NETIF_MSG_LINK, "(2) req_speed %d, req_flowctrl %d\n",
6872 params->req_line_speed[1], params->req_flow_ctrl[1]);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006873 vars->link_status = 0;
6874 vars->phy_link_up = 0;
6875 vars->link_up = 0;
6876 vars->line_speed = 0;
6877 vars->duplex = DUPLEX_FULL;
6878 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
6879 vars->mac_type = MAC_TYPE_NONE;
6880 vars->phy_flags = 0;
6881
6882 /* disable attentions */
6883 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4,
6884 (NIG_MASK_XGXS0_LINK_STATUS |
6885 NIG_MASK_XGXS0_LINK10G |
6886 NIG_MASK_SERDES0_LINK_STATUS |
6887 NIG_MASK_MI_INT));
6888
6889 bnx2x_emac_init(params, vars);
6890
6891 if (params->num_phys == 0) {
6892 DP(NETIF_MSG_LINK, "No phy found for initialization !!\n");
6893 return -EINVAL;
6894 }
6895 set_phy_vars(params);
6896
6897 DP(NETIF_MSG_LINK, "Num of phys on board: %d\n", params->num_phys);
6898 if (CHIP_REV_IS_FPGA(bp)) {
6899
6900 vars->link_up = 1;
6901 vars->line_speed = SPEED_10000;
6902 vars->duplex = DUPLEX_FULL;
6903 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
6904 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
6905 /* enable on E1.5 FPGA */
6906 if (CHIP_IS_E1H(bp)) {
6907 vars->flow_ctrl |=
6908 (BNX2X_FLOW_CTRL_TX |
6909 BNX2X_FLOW_CTRL_RX);
6910 vars->link_status |=
6911 (LINK_STATUS_TX_FLOW_CONTROL_ENABLED |
6912 LINK_STATUS_RX_FLOW_CONTROL_ENABLED);
6913 }
6914
6915 bnx2x_emac_enable(params, vars, 0);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00006916 if (!(CHIP_IS_E2(bp)))
6917 bnx2x_pbf_update(params, vars->flow_ctrl,
6918 vars->line_speed);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006919 /* disable drain */
6920 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
6921
6922 /* update shared memory */
6923 bnx2x_update_mng(params, vars->link_status);
6924
6925 return 0;
6926
6927 } else
6928 if (CHIP_REV_IS_EMUL(bp)) {
6929
6930 vars->link_up = 1;
6931 vars->line_speed = SPEED_10000;
6932 vars->duplex = DUPLEX_FULL;
6933 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
6934 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
6935
6936 bnx2x_bmac_enable(params, vars, 0);
6937
6938 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
6939 /* Disable drain */
6940 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
6941 + params->port*4, 0);
6942
6943 /* update shared memory */
6944 bnx2x_update_mng(params, vars->link_status);
6945
6946 return 0;
6947
6948 } else
6949 if (params->loopback_mode == LOOPBACK_BMAC) {
6950
6951 vars->link_up = 1;
6952 vars->line_speed = SPEED_10000;
6953 vars->duplex = DUPLEX_FULL;
6954 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
6955 vars->mac_type = MAC_TYPE_BMAC;
6956
6957 vars->phy_flags = PHY_XGXS_FLAG;
6958
6959 bnx2x_xgxs_deassert(params);
6960
6961 /* set bmac loopback */
6962 bnx2x_bmac_enable(params, vars, 1);
6963
6964 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
6965 params->port*4, 0);
6966
6967 } else if (params->loopback_mode == LOOPBACK_EMAC) {
6968
6969 vars->link_up = 1;
6970 vars->line_speed = SPEED_1000;
6971 vars->duplex = DUPLEX_FULL;
6972 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
6973 vars->mac_type = MAC_TYPE_EMAC;
6974
6975 vars->phy_flags = PHY_XGXS_FLAG;
6976
6977 bnx2x_xgxs_deassert(params);
6978 /* set bmac loopback */
6979 bnx2x_emac_enable(params, vars, 1);
6980 bnx2x_emac_program(params, vars);
6981 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
6982 params->port*4, 0);
6983
6984 } else if ((params->loopback_mode == LOOPBACK_XGXS) ||
6985 (params->loopback_mode == LOOPBACK_EXT_PHY)) {
6986
6987 vars->link_up = 1;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006988 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006989 vars->duplex = DUPLEX_FULL;
6990 if (params->req_line_speed[0] == SPEED_1000) {
6991 vars->line_speed = SPEED_1000;
6992 vars->mac_type = MAC_TYPE_EMAC;
6993 } else {
6994 vars->line_speed = SPEED_10000;
6995 vars->mac_type = MAC_TYPE_BMAC;
6996 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006997
6998 bnx2x_xgxs_deassert(params);
6999 bnx2x_link_initialize(params, vars);
7000
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007001 if (params->req_line_speed[0] == SPEED_1000) {
7002 bnx2x_emac_program(params, vars);
7003 bnx2x_emac_enable(params, vars, 0);
7004 } else
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007005 bnx2x_bmac_enable(params, vars, 0);
7006
7007 if (params->loopback_mode == LOOPBACK_XGXS) {
7008 /* set 10G XGXS loopback */
7009 params->phy[INT_PHY].config_loopback(
7010 &params->phy[INT_PHY],
7011 params);
7012
7013 } else {
7014 /* set external phy loopback */
7015 u8 phy_index;
7016 for (phy_index = EXT_PHY1;
7017 phy_index < params->num_phys; phy_index++) {
7018 if (params->phy[phy_index].config_loopback)
7019 params->phy[phy_index].config_loopback(
7020 &params->phy[phy_index],
7021 params);
7022 }
7023 }
7024
7025 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
7026 params->port*4, 0);
7027
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00007028 bnx2x_set_led(params, vars,
7029 LED_MODE_OPER, vars->line_speed);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007030 } else
7031 /* No loopback */
7032 {
7033 if (params->switch_cfg == SWITCH_CFG_10G)
7034 bnx2x_xgxs_deassert(params);
7035 else
7036 bnx2x_serdes_deassert(bp, params->port);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00007037
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007038 bnx2x_link_initialize(params, vars);
7039 msleep(30);
7040 bnx2x_link_int_enable(params);
7041 }
7042 return 0;
7043}
7044u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
7045 u8 reset_ext_phy)
7046{
7047 struct bnx2x *bp = params->bp;
7048 u8 phy_index, port = params->port;
7049 DP(NETIF_MSG_LINK, "Resetting the link of port %d\n", port);
7050 /* disable attentions */
7051 vars->link_status = 0;
7052 bnx2x_update_mng(params, vars->link_status);
7053 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
7054 (NIG_MASK_XGXS0_LINK_STATUS |
7055 NIG_MASK_XGXS0_LINK10G |
7056 NIG_MASK_SERDES0_LINK_STATUS |
7057 NIG_MASK_MI_INT));
7058
7059 /* activate nig drain */
7060 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
7061
7062 /* disable nig egress interface */
7063 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
7064 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
7065
7066 /* Stop BigMac rx */
7067 bnx2x_bmac_rx_disable(bp, port);
7068
7069 /* disable emac */
7070 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
7071
7072 msleep(10);
7073 /* The PHY reset is controled by GPIO 1
7074 * Hold it as vars low
7075 */
7076 /* clear link led */
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00007077 bnx2x_set_led(params, vars, LED_MODE_OFF, 0);
7078
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007079 if (reset_ext_phy) {
7080 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
7081 phy_index++) {
7082 if (params->phy[phy_index].link_reset)
7083 params->phy[phy_index].link_reset(
7084 &params->phy[phy_index],
7085 params);
7086 }
7087 }
7088
7089 if (params->phy[INT_PHY].link_reset)
7090 params->phy[INT_PHY].link_reset(
7091 &params->phy[INT_PHY], params);
7092 /* reset BigMac */
7093 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
7094 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
7095
7096 /* disable nig ingress interface */
7097 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0);
7098 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0);
7099 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
7100 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
7101 vars->link_up = 0;
7102 return 0;
7103}
7104
7105/****************************************************************************/
7106/* Common function */
7107/****************************************************************************/
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007108static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp,
7109 u32 shmem_base_path[],
7110 u32 shmem2_base_path[], u8 phy_index,
7111 u32 chip_id)
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007112{
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007113 struct bnx2x_phy phy[PORT_MAX];
7114 struct bnx2x_phy *phy_blk[PORT_MAX];
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007115 u16 val;
7116 s8 port;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007117 s8 port_of_path = 0;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007118
7119 /* PART1 - Reset both phys */
7120 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007121 u32 shmem_base, shmem2_base;
7122 /* In E2, same phy is using for port0 of the two paths */
7123 if (CHIP_IS_E2(bp)) {
7124 shmem_base = shmem_base_path[port];
7125 shmem2_base = shmem2_base_path[port];
7126 port_of_path = 0;
7127 } else {
7128 shmem_base = shmem_base_path[0];
7129 shmem2_base = shmem2_base_path[0];
7130 port_of_path = port;
7131 }
7132
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007133 /* Extract the ext phy address for the port */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007134 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007135 port_of_path, &phy[port]) !=
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007136 0) {
7137 DP(NETIF_MSG_LINK, "populate_phy failed\n");
7138 return -EINVAL;
7139 }
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007140 /* disable attentions */
7141 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
7142 (NIG_MASK_XGXS0_LINK_STATUS |
7143 NIG_MASK_XGXS0_LINK10G |
7144 NIG_MASK_SERDES0_LINK_STATUS |
7145 NIG_MASK_MI_INT));
7146
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007147 /* Need to take the phy out of low power mode in order
7148 to write to access its registers */
7149 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
7150 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
7151
7152 /* Reset the phy */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007153 bnx2x_cl45_write(bp, &phy[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007154 MDIO_PMA_DEVAD,
7155 MDIO_PMA_REG_CTRL,
7156 1<<15);
7157 }
7158
7159 /* Add delay of 150ms after reset */
7160 msleep(150);
7161
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007162 if (phy[PORT_0].addr & 0x1) {
7163 phy_blk[PORT_0] = &(phy[PORT_1]);
7164 phy_blk[PORT_1] = &(phy[PORT_0]);
7165 } else {
7166 phy_blk[PORT_0] = &(phy[PORT_0]);
7167 phy_blk[PORT_1] = &(phy[PORT_1]);
7168 }
7169
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007170 /* PART2 - Download firmware to both phys */
7171 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
7172 u16 fw_ver1;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007173 if (CHIP_IS_E2(bp))
7174 port_of_path = 0;
7175 else
7176 port_of_path = port;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007177
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007178 DP(NETIF_MSG_LINK, "Loading spirom for phy address 0x%x\n",
7179 phy_blk[port]->addr);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007180 bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port],
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007181 port_of_path);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007182
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007183 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007184 MDIO_PMA_DEVAD,
7185 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
Eilon Greenstein16b311c2009-01-14 06:44:24 +00007186 if (fw_ver1 == 0 || fw_ver1 == 0x4321) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007187 DP(NETIF_MSG_LINK,
Eilon Greenstein16b311c2009-01-14 06:44:24 +00007188 "bnx2x_8073_common_init_phy port %x:"
7189 "Download failed. fw version = 0x%x\n",
7190 port, fw_ver1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007191 return -EINVAL;
7192 }
7193
7194 /* Only set bit 10 = 1 (Tx power down) */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007195 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007196 MDIO_PMA_DEVAD,
7197 MDIO_PMA_REG_TX_POWER_DOWN, &val);
7198
7199 /* Phase1 of TX_POWER_DOWN reset */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007200 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007201 MDIO_PMA_DEVAD,
7202 MDIO_PMA_REG_TX_POWER_DOWN,
7203 (val | 1<<10));
7204 }
7205
7206 /* Toggle Transmitter: Power down and then up with 600ms
7207 delay between */
7208 msleep(600);
7209
7210 /* PART3 - complete TX_POWER_DOWN process, and set GPIO2 back to low */
7211 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Eilon Greensteinf5372252009-02-12 08:38:30 +00007212 /* Phase2 of POWER_DOWN_RESET */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007213 /* Release bit 10 (Release Tx power down) */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007214 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007215 MDIO_PMA_DEVAD,
7216 MDIO_PMA_REG_TX_POWER_DOWN, &val);
7217
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007218 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007219 MDIO_PMA_DEVAD,
7220 MDIO_PMA_REG_TX_POWER_DOWN, (val & (~(1<<10))));
7221 msleep(15);
7222
7223 /* Read modify write the SPI-ROM version select register */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007224 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007225 MDIO_PMA_DEVAD,
7226 MDIO_PMA_REG_EDC_FFE_MAIN, &val);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007227 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007228 MDIO_PMA_DEVAD,
7229 MDIO_PMA_REG_EDC_FFE_MAIN, (val | (1<<12)));
7230
7231 /* set GPIO2 back to LOW */
7232 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
7233 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
7234 }
7235 return 0;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007236}
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007237static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp,
7238 u32 shmem_base_path[],
7239 u32 shmem2_base_path[], u8 phy_index,
7240 u32 chip_id)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007241{
7242 u32 val;
7243 s8 port;
7244 struct bnx2x_phy phy;
7245 /* Use port1 because of the static port-swap */
7246 /* Enable the module detection interrupt */
7247 val = REG_RD(bp, MISC_REG_GPIO_EVENT_EN);
7248 val |= ((1<<MISC_REGISTERS_GPIO_3)|
7249 (1<<(MISC_REGISTERS_GPIO_3 + MISC_REGISTERS_GPIO_PORT_SHIFT)));
7250 REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val);
7251
7252 bnx2x_ext_phy_hw_reset(bp, 1);
7253 msleep(5);
7254 for (port = 0; port < PORT_MAX; port++) {
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007255 u32 shmem_base, shmem2_base;
7256
7257 /* In E2, same phy is using for port0 of the two paths */
7258 if (CHIP_IS_E2(bp)) {
7259 shmem_base = shmem_base_path[port];
7260 shmem2_base = shmem2_base_path[port];
7261 } else {
7262 shmem_base = shmem_base_path[0];
7263 shmem2_base = shmem2_base_path[0];
7264 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007265 /* Extract the ext phy address for the port */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007266 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007267 port, &phy) !=
7268 0) {
7269 DP(NETIF_MSG_LINK, "populate phy failed\n");
7270 return -EINVAL;
7271 }
7272
7273 /* Reset phy*/
7274 bnx2x_cl45_write(bp, &phy,
7275 MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, 0x0001);
7276
7277
7278 /* Set fault module detected LED on */
7279 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
7280 MISC_REGISTERS_GPIO_HIGH,
7281 port);
7282 }
7283
7284 return 0;
7285}
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007286static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp,
7287 u32 shmem_base_path[],
7288 u32 shmem2_base_path[], u8 phy_index,
7289 u32 chip_id)
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007290{
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007291 s8 port;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007292 u32 swap_val, swap_override;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007293 struct bnx2x_phy phy[PORT_MAX];
7294 struct bnx2x_phy *phy_blk[PORT_MAX];
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007295 s8 port_of_path;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007296 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
7297 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
7298
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007299 port = 1;
7300
7301 bnx2x_ext_phy_hw_reset(bp, port ^ (swap_val && swap_override));
7302
7303 /* Calculate the port based on port swap */
7304 port ^= (swap_val && swap_override);
7305
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007306 msleep(5);
7307
7308 /* PART1 - Reset both phys */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007309 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007310 u32 shmem_base, shmem2_base;
7311
7312 /* In E2, same phy is using for port0 of the two paths */
7313 if (CHIP_IS_E2(bp)) {
7314 shmem_base = shmem_base_path[port];
7315 shmem2_base = shmem2_base_path[port];
7316 port_of_path = 0;
7317 } else {
7318 shmem_base = shmem_base_path[0];
7319 shmem2_base = shmem2_base_path[0];
7320 port_of_path = port;
7321 }
7322
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007323 /* Extract the ext phy address for the port */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007324 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007325 port_of_path, &phy[port]) !=
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007326 0) {
7327 DP(NETIF_MSG_LINK, "populate phy failed\n");
7328 return -EINVAL;
7329 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007330 /* disable attentions */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007331 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 +
7332 port_of_path*4,
7333 (NIG_MASK_XGXS0_LINK_STATUS |
7334 NIG_MASK_XGXS0_LINK10G |
7335 NIG_MASK_SERDES0_LINK_STATUS |
7336 NIG_MASK_MI_INT));
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007337
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007338
7339 /* Reset the phy */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007340 bnx2x_cl45_write(bp, &phy[port],
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007341 MDIO_PMA_DEVAD,
7342 MDIO_PMA_REG_CTRL,
7343 1<<15);
7344 }
7345
7346 /* Add delay of 150ms after reset */
7347 msleep(150);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007348 if (phy[PORT_0].addr & 0x1) {
7349 phy_blk[PORT_0] = &(phy[PORT_1]);
7350 phy_blk[PORT_1] = &(phy[PORT_0]);
7351 } else {
7352 phy_blk[PORT_0] = &(phy[PORT_0]);
7353 phy_blk[PORT_1] = &(phy[PORT_1]);
7354 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007355 /* PART2 - Download firmware to both phys */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007356 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007357 u16 fw_ver1;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007358 if (CHIP_IS_E2(bp))
7359 port_of_path = 0;
7360 else
7361 port_of_path = port;
7362 DP(NETIF_MSG_LINK, "Loading spirom for phy address 0x%x\n",
7363 phy_blk[port]->addr);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007364 bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port],
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007365 port_of_path);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007366 bnx2x_cl45_read(bp, phy_blk[port],
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007367 MDIO_PMA_DEVAD,
7368 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
7369 if (fw_ver1 == 0 || fw_ver1 == 0x4321) {
7370 DP(NETIF_MSG_LINK,
Eilon Greensteinbc7f0a02009-08-12 08:23:01 +00007371 "bnx2x_8727_common_init_phy port %x:"
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007372 "Download failed. fw version = 0x%x\n",
7373 port, fw_ver1);
7374 return -EINVAL;
7375 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007376 }
7377
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007378 return 0;
7379}
7380
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007381static u8 bnx2x_ext_phy_common_init(struct bnx2x *bp, u32 shmem_base_path[],
7382 u32 shmem2_base_path[], u8 phy_index,
7383 u32 ext_phy_type, u32 chip_id)
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007384{
7385 u8 rc = 0;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007386
7387 switch (ext_phy_type) {
7388 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007389 rc = bnx2x_8073_common_init_phy(bp, shmem_base_path,
7390 shmem2_base_path,
7391 phy_index, chip_id);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007392 break;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007393
7394 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
7395 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007396 rc = bnx2x_8727_common_init_phy(bp, shmem_base_path,
7397 shmem2_base_path,
7398 phy_index, chip_id);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007399 break;
7400
Eilon Greenstein589abe32009-02-12 08:36:55 +00007401 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
7402 /* GPIO1 affects both ports, so there's need to pull
7403 it for single port alone */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007404 rc = bnx2x_8726_common_init_phy(bp, shmem_base_path,
7405 shmem2_base_path,
7406 phy_index, chip_id);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007407 break;
7408 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
7409 rc = -EINVAL;
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02007410 break;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007411 default:
7412 DP(NETIF_MSG_LINK,
7413 "bnx2x_common_init_phy: ext_phy 0x%x not required\n",
7414 ext_phy_type);
7415 break;
7416 }
7417
7418 return rc;
7419}
7420
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007421u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base_path[],
7422 u32 shmem2_base_path[], u32 chip_id)
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007423{
7424 u8 rc = 0;
7425 u8 phy_index;
7426 u32 ext_phy_type, ext_phy_config;
7427 DP(NETIF_MSG_LINK, "Begin common phy init\n");
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00007428
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007429 if (CHIP_REV_IS_EMUL(bp))
7430 return 0;
7431
7432 /* Read the ext_phy_type for arbitrary port(0) */
7433 for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
7434 phy_index++) {
7435 ext_phy_config = bnx2x_get_ext_phy_config(bp,
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007436 shmem_base_path[0],
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007437 phy_index, 0);
7438 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007439 rc |= bnx2x_ext_phy_common_init(bp, shmem_base_path,
7440 shmem2_base_path,
7441 phy_index, ext_phy_type,
7442 chip_id);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007443 }
7444 return rc;
7445}
7446
7447u8 bnx2x_hw_lock_required(struct bnx2x *bp, u32 shmem_base, u32 shmem2_base)
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00007448{
7449 u8 phy_index;
7450 struct bnx2x_phy phy;
7451 for (phy_index = INT_PHY; phy_index < MAX_PHYS;
7452 phy_index++) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007453 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00007454 0, &phy) != 0) {
7455 DP(NETIF_MSG_LINK, "populate phy failed\n");
7456 return 0;
7457 }
7458
7459 if (phy.flags & FLAGS_HW_LOCK_REQUIRED)
7460 return 1;
7461 }
7462 return 0;
7463}
7464
7465u8 bnx2x_fan_failure_det_req(struct bnx2x *bp,
7466 u32 shmem_base,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007467 u32 shmem2_base,
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00007468 u8 port)
7469{
7470 u8 phy_index, fan_failure_det_req = 0;
7471 struct bnx2x_phy phy;
7472 for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
7473 phy_index++) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007474 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00007475 port, &phy)
7476 != 0) {
7477 DP(NETIF_MSG_LINK, "populate phy failed\n");
7478 return 0;
7479 }
7480 fan_failure_det_req |= (phy.flags &
7481 FLAGS_FAN_FAILURE_DET_REQ);
7482 }
7483 return fan_failure_det_req;
7484}
7485
7486void bnx2x_hw_reset_phy(struct link_params *params)
7487{
7488 u8 phy_index;
7489 for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
7490 phy_index++) {
7491 if (params->phy[phy_index].hw_reset) {
7492 params->phy[phy_index].hw_reset(
7493 &params->phy[phy_index],
7494 params);
7495 params->phy[phy_index] = phy_null;
7496 }
7497 }
7498}