blob: 97cbee2927fc6ad8520f8db817ec71eb7d678209 [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
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000167#define ETS_BW_LIMIT_CREDIT_UPPER_BOUND (0x5000)
168#define ETS_BW_LIMIT_CREDIT_WEIGHT (0x5000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700169/**********************************************************/
170/* INTERFACE */
171/**********************************************************/
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000172
173#define CL45_WR_OVER_CL22(_bp, _phy, _bank, _addr, _val) \
174 bnx2x_cl45_write(_bp, _phy, \
Yaniv Rosner7aa07112010-09-07 11:41:01 +0000175 (_phy)->def_md_devad, \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700176 (_bank + (_addr & 0xf)), \
177 _val)
178
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000179#define CL45_RD_OVER_CL22(_bp, _phy, _bank, _addr, _val) \
180 bnx2x_cl45_read(_bp, _phy, \
Yaniv Rosner7aa07112010-09-07 11:41:01 +0000181 (_phy)->def_md_devad, \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700182 (_bank + (_addr & 0xf)), \
183 _val)
184
stephen hemminger8d962862010-10-21 07:50:56 +0000185static u8 bnx2x_cl45_read(struct bnx2x *bp, struct bnx2x_phy *phy,
186 u8 devad, u16 reg, u16 *ret_val);
187
188static u8 bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy,
189 u8 devad, u16 reg, u16 val);
190
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700191static u32 bnx2x_bits_en(struct bnx2x *bp, u32 reg, u32 bits)
192{
193 u32 val = REG_RD(bp, reg);
194
195 val |= bits;
196 REG_WR(bp, reg, val);
197 return val;
198}
199
200static u32 bnx2x_bits_dis(struct bnx2x *bp, u32 reg, u32 bits)
201{
202 u32 val = REG_RD(bp, reg);
203
204 val &= ~bits;
205 REG_WR(bp, reg, val);
206 return val;
207}
208
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000209/******************************************************************/
210/* ETS section */
211/******************************************************************/
212void bnx2x_ets_disabled(struct link_params *params)
213{
214 /* ETS disabled configuration*/
215 struct bnx2x *bp = params->bp;
216
217 DP(NETIF_MSG_LINK, "ETS disabled configuration\n");
218
219 /**
220 * mapping between entry priority to client number (0,1,2 -debug and
221 * management clients, 3 - COS0 client, 4 - COS client)(HIGHEST)
222 * 3bits client num.
223 * PRI4 | PRI3 | PRI2 | PRI1 | PRI0
224 * cos1-100 cos0-011 dbg1-010 dbg0-001 MCP-000
225 */
226
227 REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT, 0x4688);
228 /**
229 * Bitmap of 5bits length. Each bit specifies whether the entry behaves
230 * as strict. Bits 0,1,2 - debug and management entries, 3 -
231 * COS0 entry, 4 - COS1 entry.
232 * COS1 | COS0 | DEBUG1 | DEBUG0 | MGMT
233 * bit4 bit3 bit2 bit1 bit0
234 * MCP and debug are strict
235 */
236
237 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x7);
238 /* defines which entries (clients) are subjected to WFQ arbitration */
239 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ, 0);
240 /**
241 * For strict priority entries defines the number of consecutive
242 * slots for the highest priority.
243 */
244 REG_WR(bp, NIG_REG_P0_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100);
245 /**
246 * mapping between the CREDIT_WEIGHT registers and actual client
247 * numbers
248 */
249 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP, 0);
250 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_0, 0);
251 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_1, 0);
252
253 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_0, 0);
254 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_1, 0);
255 REG_WR(bp, PBF_REG_HIGH_PRIORITY_COS_NUM, 0);
256 /* ETS mode disable */
257 REG_WR(bp, PBF_REG_ETS_ENABLED, 0);
258 /**
259 * If ETS mode is enabled (there is no strict priority) defines a WFQ
260 * weight for COS0/COS1.
261 */
262 REG_WR(bp, PBF_REG_COS0_WEIGHT, 0x2710);
263 REG_WR(bp, PBF_REG_COS1_WEIGHT, 0x2710);
264 /* Upper bound that COS0_WEIGHT can reach in the WFQ arbiter */
265 REG_WR(bp, PBF_REG_COS0_UPPER_BOUND, 0x989680);
266 REG_WR(bp, PBF_REG_COS1_UPPER_BOUND, 0x989680);
267 /* Defines the number of consecutive slots for the strict priority */
268 REG_WR(bp, PBF_REG_NUM_STRICT_ARB_SLOTS, 0);
269}
270
271void bnx2x_ets_bw_limit_common(const struct link_params *params)
272{
273 /* ETS disabled configuration */
274 struct bnx2x *bp = params->bp;
275 DP(NETIF_MSG_LINK, "ETS enabled BW limit configuration\n");
276 /**
277 * defines which entries (clients) are subjected to WFQ arbitration
278 * COS0 0x8
279 * COS1 0x10
280 */
281 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ, 0x18);
282 /**
283 * mapping between the ARB_CREDIT_WEIGHT registers and actual
284 * client numbers (WEIGHT_0 does not actually have to represent
285 * client 0)
286 * PRI4 | PRI3 | PRI2 | PRI1 | PRI0
287 * cos1-001 cos0-000 dbg1-100 dbg0-011 MCP-010
288 */
289 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP, 0x111A);
290
291 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_0,
292 ETS_BW_LIMIT_CREDIT_UPPER_BOUND);
293 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_1,
294 ETS_BW_LIMIT_CREDIT_UPPER_BOUND);
295
296 /* ETS mode enabled*/
297 REG_WR(bp, PBF_REG_ETS_ENABLED, 1);
298
299 /* Defines the number of consecutive slots for the strict priority */
300 REG_WR(bp, PBF_REG_NUM_STRICT_ARB_SLOTS, 0);
301 /**
302 * Bitmap of 5bits length. Each bit specifies whether the entry behaves
303 * as strict. Bits 0,1,2 - debug and management entries, 3 - COS0
304 * entry, 4 - COS1 entry.
305 * COS1 | COS0 | DEBUG21 | DEBUG0 | MGMT
306 * bit4 bit3 bit2 bit1 bit0
307 * MCP and debug are strict
308 */
309 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x7);
310
311 /* Upper bound that COS0_WEIGHT can reach in the WFQ arbiter.*/
312 REG_WR(bp, PBF_REG_COS0_UPPER_BOUND,
313 ETS_BW_LIMIT_CREDIT_UPPER_BOUND);
314 REG_WR(bp, PBF_REG_COS1_UPPER_BOUND,
315 ETS_BW_LIMIT_CREDIT_UPPER_BOUND);
316}
317
318void bnx2x_ets_bw_limit(const struct link_params *params, const u32 cos0_bw,
319 const u32 cos1_bw)
320{
321 /* ETS disabled configuration*/
322 struct bnx2x *bp = params->bp;
323 const u32 total_bw = cos0_bw + cos1_bw;
324 u32 cos0_credit_weight = 0;
325 u32 cos1_credit_weight = 0;
326
327 DP(NETIF_MSG_LINK, "ETS enabled BW limit configuration\n");
328
329 if ((0 == total_bw) ||
330 (0 == cos0_bw) ||
331 (0 == cos1_bw)) {
332 DP(NETIF_MSG_LINK,
333 "bnx2x_ets_bw_limit: Total BW can't be zero\n");
334 return;
335 }
336
337 cos0_credit_weight = (cos0_bw * ETS_BW_LIMIT_CREDIT_WEIGHT)/
338 total_bw;
339 cos1_credit_weight = (cos1_bw * ETS_BW_LIMIT_CREDIT_WEIGHT)/
340 total_bw;
341
342 bnx2x_ets_bw_limit_common(params);
343
344 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_0, cos0_credit_weight);
345 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_1, cos1_credit_weight);
346
347 REG_WR(bp, PBF_REG_COS0_WEIGHT, cos0_credit_weight);
348 REG_WR(bp, PBF_REG_COS1_WEIGHT, cos1_credit_weight);
349}
350
351u8 bnx2x_ets_strict(const struct link_params *params, const u8 strict_cos)
352{
353 /* ETS disabled configuration*/
354 struct bnx2x *bp = params->bp;
355 u32 val = 0;
356
357 if ((1 < strict_cos) && (NULL == params))
358 return -EINVAL;
359
360 DP(NETIF_MSG_LINK, "ETS enabled strict configuration\n");
361 /**
362 * Bitmap of 5bits length. Each bit specifies whether the entry behaves
363 * as strict. Bits 0,1,2 - debug and management entries,
364 * 3 - COS0 entry, 4 - COS1 entry.
365 * COS1 | COS0 | DEBUG21 | DEBUG0 | MGMT
366 * bit4 bit3 bit2 bit1 bit0
367 * MCP and debug are strict
368 */
369 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x1F);
370 /**
371 * For strict priority entries defines the number of consecutive slots
372 * for the highest priority.
373 */
374 REG_WR(bp, NIG_REG_P0_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100);
375 /* ETS mode disable */
376 REG_WR(bp, PBF_REG_ETS_ENABLED, 0);
377 /* Defines the number of consecutive slots for the strict priority */
378 REG_WR(bp, PBF_REG_NUM_STRICT_ARB_SLOTS, 0x100);
379
380 /* Defines the number of consecutive slots for the strict priority */
381 REG_WR(bp, PBF_REG_HIGH_PRIORITY_COS_NUM, strict_cos);
382
383 /**
384 * mapping between entry priority to client number (0,1,2 -debug and
385 * management clients, 3 - COS0 client, 4 - COS client)(HIGHEST)
386 * 3bits client num.
387 * PRI4 | PRI3 | PRI2 | PRI1 | PRI0
388 * dbg0-010 dbg1-001 cos1-100 cos0-011 MCP-000
389 * dbg0-010 dbg1-001 cos0-011 cos1-100 MCP-000
390 */
391 val = (0 == strict_cos) ? 0x2318 : 0x22E0;
392 REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT, val);
393
394 return 0;
395}
396/******************************************************************/
397/* ETS section */
398/******************************************************************/
399
400static void bnx2x_bmac2_get_pfc_stat(struct link_params *params,
401 u32 pfc_frames_sent[2],
402 u32 pfc_frames_received[2])
403{
404 /* Read pfc statistic */
405 struct bnx2x *bp = params->bp;
406 u32 bmac_addr = params->port ? NIG_REG_INGRESS_BMAC1_MEM :
407 NIG_REG_INGRESS_BMAC0_MEM;
408
409 DP(NETIF_MSG_LINK, "pfc statistic read from BMAC\n");
410
411 REG_RD_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_STAT_GTPP,
412 pfc_frames_sent, 2);
413
414 REG_RD_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_STAT_GRPP,
415 pfc_frames_received, 2);
416
417}
418static void bnx2x_emac_get_pfc_stat(struct link_params *params,
419 u32 pfc_frames_sent[2],
420 u32 pfc_frames_received[2])
421{
422 /* Read pfc statistic */
423 struct bnx2x *bp = params->bp;
424 u32 emac_base = params->port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
425 u32 val_xon = 0;
426 u32 val_xoff = 0;
427
428 DP(NETIF_MSG_LINK, "pfc statistic read from EMAC\n");
429
430 /* PFC received frames */
431 val_xoff = REG_RD(bp, emac_base +
432 EMAC_REG_RX_PFC_STATS_XOFF_RCVD);
433 val_xoff &= EMAC_REG_RX_PFC_STATS_XOFF_RCVD_COUNT;
434 val_xon = REG_RD(bp, emac_base + EMAC_REG_RX_PFC_STATS_XON_RCVD);
435 val_xon &= EMAC_REG_RX_PFC_STATS_XON_RCVD_COUNT;
436
437 pfc_frames_received[0] = val_xon + val_xoff;
438
439 /* PFC received sent */
440 val_xoff = REG_RD(bp, emac_base +
441 EMAC_REG_RX_PFC_STATS_XOFF_SENT);
442 val_xoff &= EMAC_REG_RX_PFC_STATS_XOFF_SENT_COUNT;
443 val_xon = REG_RD(bp, emac_base + EMAC_REG_RX_PFC_STATS_XON_SENT);
444 val_xon &= EMAC_REG_RX_PFC_STATS_XON_SENT_COUNT;
445
446 pfc_frames_sent[0] = val_xon + val_xoff;
447}
448
449void bnx2x_pfc_statistic(struct link_params *params, struct link_vars *vars,
450 u32 pfc_frames_sent[2],
451 u32 pfc_frames_received[2])
452{
453 /* Read pfc statistic */
454 struct bnx2x *bp = params->bp;
455 u32 val = 0;
456 DP(NETIF_MSG_LINK, "pfc statistic\n");
457
458 if (!vars->link_up)
459 return;
460
461 val = REG_RD(bp, MISC_REG_RESET_REG_2);
462 if ((val & (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << params->port))
463 == 0) {
464 DP(NETIF_MSG_LINK, "About to read stats from EMAC\n");
465 bnx2x_emac_get_pfc_stat(params, pfc_frames_sent,
466 pfc_frames_received);
467 } else {
468 DP(NETIF_MSG_LINK, "About to read stats from BMAC\n");
469 bnx2x_bmac2_get_pfc_stat(params, pfc_frames_sent,
470 pfc_frames_received);
471 }
472}
473/******************************************************************/
474/* MAC/PBF section */
475/******************************************************************/
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700476static void bnx2x_emac_init(struct link_params *params,
477 struct link_vars *vars)
478{
479 /* reset and unreset the emac core */
480 struct bnx2x *bp = params->bp;
481 u8 port = params->port;
482 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
483 u32 val;
484 u16 timeout;
485
486 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
487 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
488 udelay(5);
489 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
490 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
491
492 /* init emac - use read-modify-write */
493 /* self clear reset */
494 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700495 EMAC_WR(bp, EMAC_REG_EMAC_MODE, (val | EMAC_MODE_RESET));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700496
497 timeout = 200;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700498 do {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700499 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
500 DP(NETIF_MSG_LINK, "EMAC reset reg is %u\n", val);
501 if (!timeout) {
502 DP(NETIF_MSG_LINK, "EMAC timeout!\n");
503 return;
504 }
505 timeout--;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700506 } while (val & EMAC_MODE_RESET);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700507
508 /* Set mac address */
509 val = ((params->mac_addr[0] << 8) |
510 params->mac_addr[1]);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700511 EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700512
513 val = ((params->mac_addr[2] << 24) |
514 (params->mac_addr[3] << 16) |
515 (params->mac_addr[4] << 8) |
516 params->mac_addr[5]);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700517 EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH + 4, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700518}
519
520static u8 bnx2x_emac_enable(struct link_params *params,
521 struct link_vars *vars, u8 lb)
522{
523 struct bnx2x *bp = params->bp;
524 u8 port = params->port;
525 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
526 u32 val;
527
528 DP(NETIF_MSG_LINK, "enabling EMAC\n");
529
530 /* enable emac and not bmac */
531 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 1);
532
533 /* for paladium */
534 if (CHIP_REV_IS_EMUL(bp)) {
535 /* Use lane 1 (of lanes 0-3) */
536 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1);
537 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
538 port*4, 1);
539 }
540 /* for fpga */
541 else
542
543 if (CHIP_REV_IS_FPGA(bp)) {
544 /* Use lane 1 (of lanes 0-3) */
545 DP(NETIF_MSG_LINK, "bnx2x_emac_enable: Setting FPGA\n");
546
547 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1);
548 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4,
549 0);
550 } else
551 /* ASIC */
552 if (vars->phy_flags & PHY_XGXS_FLAG) {
553 u32 ser_lane = ((params->lane_config &
554 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
555 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
556
557 DP(NETIF_MSG_LINK, "XGXS\n");
558 /* select the master lanes (out of 0-3) */
559 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 +
560 port*4, ser_lane);
561 /* select XGXS */
562 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
563 port*4, 1);
564
565 } else { /* SerDes */
566 DP(NETIF_MSG_LINK, "SerDes\n");
567 /* select SerDes */
568 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
569 port*4, 0);
570 }
571
Eilon Greenstein811a2f22009-02-12 08:37:04 +0000572 bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
573 EMAC_RX_MODE_RESET);
574 bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
575 EMAC_TX_MODE_RESET);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700576
577 if (CHIP_REV_IS_SLOW(bp)) {
578 /* config GMII mode */
579 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700580 EMAC_WR(bp, EMAC_REG_EMAC_MODE,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700581 (val | EMAC_MODE_PORT_GMII));
582 } else { /* ASIC */
583 /* pause enable/disable */
584 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
585 EMAC_RX_MODE_FLOW_EN);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700586
587 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000588 (EMAC_TX_MODE_EXT_PAUSE_EN |
589 EMAC_TX_MODE_FLOW_EN));
590 if (!(params->feature_config_flags &
591 FEATURE_CONFIG_PFC_ENABLED)) {
592 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
593 bnx2x_bits_en(bp, emac_base +
594 EMAC_REG_EMAC_RX_MODE,
595 EMAC_RX_MODE_FLOW_EN);
596
597 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
598 bnx2x_bits_en(bp, emac_base +
599 EMAC_REG_EMAC_TX_MODE,
600 (EMAC_TX_MODE_EXT_PAUSE_EN |
601 EMAC_TX_MODE_FLOW_EN));
602 } else
603 bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
604 EMAC_TX_MODE_FLOW_EN);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700605 }
606
607 /* KEEP_VLAN_TAG, promiscuous */
608 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_RX_MODE);
609 val |= EMAC_RX_MODE_KEEP_VLAN_TAG | EMAC_RX_MODE_PROMISCUOUS;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000610
611 /**
612 * Setting this bit causes MAC control frames (except for pause
613 * frames) to be passed on for processing. This setting has no
614 * affect on the operation of the pause frames. This bit effects
615 * all packets regardless of RX Parser packet sorting logic.
616 * Turn the PFC off to make sure we are in Xon state before
617 * enabling it.
618 */
619 EMAC_WR(bp, EMAC_REG_RX_PFC_MODE, 0);
620 if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED) {
621 DP(NETIF_MSG_LINK, "PFC is enabled\n");
622 /* Enable PFC again */
623 EMAC_WR(bp, EMAC_REG_RX_PFC_MODE,
624 EMAC_REG_RX_PFC_MODE_RX_EN |
625 EMAC_REG_RX_PFC_MODE_TX_EN |
626 EMAC_REG_RX_PFC_MODE_PRIORITIES);
627
628 EMAC_WR(bp, EMAC_REG_RX_PFC_PARAM,
629 ((0x0101 <<
630 EMAC_REG_RX_PFC_PARAM_OPCODE_BITSHIFT) |
631 (0x00ff <<
632 EMAC_REG_RX_PFC_PARAM_PRIORITY_EN_BITSHIFT)));
633 val |= EMAC_RX_MODE_KEEP_MAC_CONTROL;
634 }
Eilon Greenstein3196a882008-08-13 15:58:49 -0700635 EMAC_WR(bp, EMAC_REG_EMAC_RX_MODE, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700636
637 /* Set Loopback */
638 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
639 if (lb)
640 val |= 0x810;
641 else
642 val &= ~0x810;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700643 EMAC_WR(bp, EMAC_REG_EMAC_MODE, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700644
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +0000645 /* enable emac */
646 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 1);
647
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700648 /* enable emac for jumbo packets */
Eilon Greenstein3196a882008-08-13 15:58:49 -0700649 EMAC_WR(bp, EMAC_REG_EMAC_RX_MTU_SIZE,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700650 (EMAC_RX_MTU_SIZE_JUMBO_ENA |
651 (ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD)));
652
653 /* strip CRC */
654 REG_WR(bp, NIG_REG_NIG_INGRESS_EMAC0_NO_CRC + port*4, 0x1);
655
656 /* disable the NIG in/out to the bmac */
657 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x0);
658 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, 0x0);
659 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x0);
660
661 /* enable the NIG in/out to the emac */
662 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x1);
663 val = 0;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000664 if ((params->feature_config_flags &
665 FEATURE_CONFIG_PFC_ENABLED) ||
666 (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700667 val = 1;
668
669 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, val);
670 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x1);
671
672 if (CHIP_REV_IS_EMUL(bp)) {
673 /* take the BigMac out of reset */
674 REG_WR(bp,
675 GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
676 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
677
678 /* enable access for bmac registers */
679 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
Eilon Greenstein6f654972009-08-12 08:23:51 +0000680 } else
681 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700682
683 vars->mac_type = MAC_TYPE_EMAC;
684 return 0;
685}
686
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000687static void bnx2x_update_pfc_bmac1(struct link_params *params,
688 struct link_vars *vars)
689{
690 u32 wb_data[2];
691 struct bnx2x *bp = params->bp;
692 u32 bmac_addr = params->port ? NIG_REG_INGRESS_BMAC1_MEM :
693 NIG_REG_INGRESS_BMAC0_MEM;
694
695 u32 val = 0x14;
696 if ((!(params->feature_config_flags &
697 FEATURE_CONFIG_PFC_ENABLED)) &&
698 (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX))
699 /* Enable BigMAC to react on received Pause packets */
700 val |= (1<<5);
701 wb_data[0] = val;
702 wb_data[1] = 0;
703 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_CONTROL, wb_data, 2);
704
705 /* tx control */
706 val = 0xc0;
707 if (!(params->feature_config_flags &
708 FEATURE_CONFIG_PFC_ENABLED) &&
709 (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
710 val |= 0x800000;
711 wb_data[0] = val;
712 wb_data[1] = 0;
713 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_CONTROL, wb_data, 2);
714}
715
716static void bnx2x_update_pfc_bmac2(struct link_params *params,
717 struct link_vars *vars,
718 u8 is_lb)
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000719{
720 /*
721 * Set rx control: Strip CRC and enable BigMAC to relay
722 * control packets to the system as well
723 */
724 u32 wb_data[2];
725 struct bnx2x *bp = params->bp;
726 u32 bmac_addr = params->port ? NIG_REG_INGRESS_BMAC1_MEM :
727 NIG_REG_INGRESS_BMAC0_MEM;
728 u32 val = 0x14;
729
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000730 if ((!(params->feature_config_flags &
731 FEATURE_CONFIG_PFC_ENABLED)) &&
732 (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX))
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000733 /* Enable BigMAC to react on received Pause packets */
734 val |= (1<<5);
735 wb_data[0] = val;
736 wb_data[1] = 0;
737 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_CONTROL,
738 wb_data, 2);
739 udelay(30);
740
741 /* Tx control */
742 val = 0xc0;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000743 if (!(params->feature_config_flags &
744 FEATURE_CONFIG_PFC_ENABLED) &&
745 (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000746 val |= 0x800000;
747 wb_data[0] = val;
748 wb_data[1] = 0;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000749 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_CONTROL, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000750
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000751 if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED) {
752 DP(NETIF_MSG_LINK, "PFC is enabled\n");
753 /* Enable PFC RX & TX & STATS and set 8 COS */
754 wb_data[0] = 0x0;
755 wb_data[0] |= (1<<0); /* RX */
756 wb_data[0] |= (1<<1); /* TX */
757 wb_data[0] |= (1<<2); /* Force initial Xon */
758 wb_data[0] |= (1<<3); /* 8 cos */
759 wb_data[0] |= (1<<5); /* STATS */
760 wb_data[1] = 0;
761 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_PFC_CONTROL,
762 wb_data, 2);
763 /* Clear the force Xon */
764 wb_data[0] &= ~(1<<2);
765 } else {
766 DP(NETIF_MSG_LINK, "PFC is disabled\n");
767 /* disable PFC RX & TX & STATS and set 8 COS */
768 wb_data[0] = 0x8;
769 wb_data[1] = 0;
770 }
771
772 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_PFC_CONTROL, wb_data, 2);
773
774 /**
775 * Set Time (based unit is 512 bit time) between automatic
776 * re-sending of PP packets amd enable automatic re-send of
777 * Per-Priroity Packet as long as pp_gen is asserted and
778 * pp_disable is low.
779 */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000780 val = 0x8000;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000781 if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED)
782 val |= (1<<16); /* enable automatic re-send */
783
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000784 wb_data[0] = val;
785 wb_data[1] = 0;
786 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_PAUSE_CONTROL,
787 wb_data, 2);
788
789 /* mac control */
790 val = 0x3; /* Enable RX and TX */
791 if (is_lb) {
792 val |= 0x4; /* Local loopback */
793 DP(NETIF_MSG_LINK, "enable bmac loopback\n");
794 }
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000795 /* When PFC enabled, Pass pause frames towards the NIG. */
796 if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED)
797 val |= ((1<<6)|(1<<5));
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000798
799 wb_data[0] = val;
800 wb_data[1] = 0;
801 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_BMAC_CONTROL,
802 wb_data, 2);
803}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700804
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000805static void bnx2x_update_pfc_brb(struct link_params *params,
806 struct link_vars *vars,
807 struct bnx2x_nig_brb_pfc_port_params *pfc_params)
808{
809 struct bnx2x *bp = params->bp;
810 int set_pfc = params->feature_config_flags &
811 FEATURE_CONFIG_PFC_ENABLED;
812
813 /* default - pause configuration */
814 u32 pause_xoff_th = PFC_BRB_MAC_PAUSE_XOFF_THRESHOLD_PAUSEABLE;
815 u32 pause_xon_th = PFC_BRB_MAC_PAUSE_XON_THRESHOLD_PAUSEABLE;
816 u32 full_xoff_th = PFC_BRB_MAC_FULL_XOFF_THRESHOLD_PAUSEABLE;
817 u32 full_xon_th = PFC_BRB_MAC_FULL_XON_THRESHOLD_PAUSEABLE;
818
819 if (set_pfc && pfc_params)
820 /* First COS */
821 if (!pfc_params->cos0_pauseable) {
822 pause_xoff_th =
823 PFC_BRB_MAC_PAUSE_XOFF_THRESHOLD_NON_PAUSEABLE;
824 pause_xon_th =
825 PFC_BRB_MAC_PAUSE_XON_THRESHOLD_NON_PAUSEABLE;
826 full_xoff_th =
827 PFC_BRB_MAC_FULL_XOFF_THRESHOLD_NON_PAUSEABLE;
828 full_xon_th =
829 PFC_BRB_MAC_FULL_XON_THRESHOLD_NON_PAUSEABLE;
830 }
831 /* The number of free blocks below which the pause signal to class 0
832 of MAC #n is asserted. n=0,1 */
833 REG_WR(bp, BRB1_REG_PAUSE_0_XOFF_THRESHOLD_0 , pause_xoff_th);
834 /* The number of free blocks above which the pause signal to class 0
835 of MAC #n is de-asserted. n=0,1 */
836 REG_WR(bp, BRB1_REG_PAUSE_0_XON_THRESHOLD_0 , pause_xon_th);
837 /* The number of free blocks below which the full signal to class 0
838 of MAC #n is asserted. n=0,1 */
839 REG_WR(bp, BRB1_REG_FULL_0_XOFF_THRESHOLD_0 , full_xoff_th);
840 /* The number of free blocks above which the full signal to class 0
841 of MAC #n is de-asserted. n=0,1 */
842 REG_WR(bp, BRB1_REG_FULL_0_XON_THRESHOLD_0 , full_xon_th);
843
844 if (set_pfc && pfc_params) {
845 /* Second COS */
846 if (pfc_params->cos1_pauseable) {
847 pause_xoff_th =
848 PFC_BRB_MAC_PAUSE_XOFF_THRESHOLD_PAUSEABLE;
849 pause_xon_th =
850 PFC_BRB_MAC_PAUSE_XON_THRESHOLD_PAUSEABLE;
851 full_xoff_th =
852 PFC_BRB_MAC_FULL_XOFF_THRESHOLD_PAUSEABLE;
853 full_xon_th =
854 PFC_BRB_MAC_FULL_XON_THRESHOLD_PAUSEABLE;
855 } else {
856 pause_xoff_th =
857 PFC_BRB_MAC_PAUSE_XOFF_THRESHOLD_NON_PAUSEABLE;
858 pause_xon_th =
859 PFC_BRB_MAC_PAUSE_XON_THRESHOLD_NON_PAUSEABLE;
860 full_xoff_th =
861 PFC_BRB_MAC_FULL_XOFF_THRESHOLD_NON_PAUSEABLE;
862 full_xon_th =
863 PFC_BRB_MAC_FULL_XON_THRESHOLD_NON_PAUSEABLE;
864 }
865 /**
866 * The number of free blocks below which the pause signal to
867 * class 1 of MAC #n is asserted. n=0,1
868 **/
869 REG_WR(bp, BRB1_REG_PAUSE_1_XOFF_THRESHOLD_0, pause_xoff_th);
870 /**
871 * The number of free blocks above which the pause signal to
872 * class 1 of MAC #n is de-asserted. n=0,1
873 **/
874 REG_WR(bp, BRB1_REG_PAUSE_1_XON_THRESHOLD_0, pause_xon_th);
875 /**
876 * The number of free blocks below which the full signal to
877 * class 1 of MAC #n is asserted. n=0,1
878 **/
879 REG_WR(bp, BRB1_REG_FULL_1_XOFF_THRESHOLD_0, full_xoff_th);
880 /**
881 * The number of free blocks above which the full signal to
882 * class 1 of MAC #n is de-asserted. n=0,1
883 **/
884 REG_WR(bp, BRB1_REG_FULL_1_XON_THRESHOLD_0, full_xon_th);
885 }
886}
887
888static void bnx2x_update_pfc_nig(struct link_params *params,
889 struct link_vars *vars,
890 struct bnx2x_nig_brb_pfc_port_params *nig_params)
891{
892 u32 xcm_mask = 0, ppp_enable = 0, pause_enable = 0, llfc_out_en = 0;
893 u32 llfc_enable = 0, xcm0_out_en = 0, p0_hwpfc_enable = 0;
894 u32 pkt_priority_to_cos = 0;
895 u32 val;
896 struct bnx2x *bp = params->bp;
897 int port = params->port;
898 int set_pfc = params->feature_config_flags &
899 FEATURE_CONFIG_PFC_ENABLED;
900 DP(NETIF_MSG_LINK, "updating pfc nig parameters\n");
901
902 /**
903 * When NIG_LLH0_XCM_MASK_REG_LLHX_XCM_MASK_BCN bit is set
904 * MAC control frames (that are not pause packets)
905 * will be forwarded to the XCM.
906 */
907 xcm_mask = REG_RD(bp,
908 port ? NIG_REG_LLH1_XCM_MASK :
909 NIG_REG_LLH0_XCM_MASK);
910 /**
911 * nig params will override non PFC params, since it's possible to
912 * do transition from PFC to SAFC
913 */
914 if (set_pfc) {
915 pause_enable = 0;
916 llfc_out_en = 0;
917 llfc_enable = 0;
918 ppp_enable = 1;
919 xcm_mask &= ~(port ? NIG_LLH1_XCM_MASK_REG_LLH1_XCM_MASK_BCN :
920 NIG_LLH0_XCM_MASK_REG_LLH0_XCM_MASK_BCN);
921 xcm0_out_en = 0;
922 p0_hwpfc_enable = 1;
923 } else {
924 if (nig_params) {
925 llfc_out_en = nig_params->llfc_out_en;
926 llfc_enable = nig_params->llfc_enable;
927 pause_enable = nig_params->pause_enable;
928 } else /*defaul non PFC mode - PAUSE */
929 pause_enable = 1;
930
931 xcm_mask |= (port ? NIG_LLH1_XCM_MASK_REG_LLH1_XCM_MASK_BCN :
932 NIG_LLH0_XCM_MASK_REG_LLH0_XCM_MASK_BCN);
933 xcm0_out_en = 1;
934 }
935
936 REG_WR(bp, port ? NIG_REG_LLFC_OUT_EN_1 :
937 NIG_REG_LLFC_OUT_EN_0, llfc_out_en);
938 REG_WR(bp, port ? NIG_REG_LLFC_ENABLE_1 :
939 NIG_REG_LLFC_ENABLE_0, llfc_enable);
940 REG_WR(bp, port ? NIG_REG_PAUSE_ENABLE_1 :
941 NIG_REG_PAUSE_ENABLE_0, pause_enable);
942
943 REG_WR(bp, port ? NIG_REG_PPP_ENABLE_1 :
944 NIG_REG_PPP_ENABLE_0, ppp_enable);
945
946 REG_WR(bp, port ? NIG_REG_LLH1_XCM_MASK :
947 NIG_REG_LLH0_XCM_MASK, xcm_mask);
948
949 REG_WR(bp, NIG_REG_LLFC_EGRESS_SRC_ENABLE_0, 0x7);
950
951 /* output enable for RX_XCM # IF */
952 REG_WR(bp, NIG_REG_XCM0_OUT_EN, xcm0_out_en);
953
954 /* HW PFC TX enable */
955 REG_WR(bp, NIG_REG_P0_HWPFC_ENABLE, p0_hwpfc_enable);
956
957 /* 0x2 = BMAC, 0x1= EMAC */
958 switch (vars->mac_type) {
959 case MAC_TYPE_EMAC:
960 val = 1;
961 break;
962 case MAC_TYPE_BMAC:
963 val = 0;
964 break;
965 default:
966 val = 0;
967 break;
968 }
969 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT, val);
970
971 if (nig_params) {
972 pkt_priority_to_cos = nig_params->pkt_priority_to_cos;
973
974 REG_WR(bp, port ? NIG_REG_P1_RX_COS0_PRIORITY_MASK :
975 NIG_REG_P0_RX_COS0_PRIORITY_MASK,
976 nig_params->rx_cos0_priority_mask);
977
978 REG_WR(bp, port ? NIG_REG_P1_RX_COS1_PRIORITY_MASK :
979 NIG_REG_P0_RX_COS1_PRIORITY_MASK,
980 nig_params->rx_cos1_priority_mask);
981
982 REG_WR(bp, port ? NIG_REG_LLFC_HIGH_PRIORITY_CLASSES_1 :
983 NIG_REG_LLFC_HIGH_PRIORITY_CLASSES_0,
984 nig_params->llfc_high_priority_classes);
985
986 REG_WR(bp, port ? NIG_REG_LLFC_LOW_PRIORITY_CLASSES_1 :
987 NIG_REG_LLFC_LOW_PRIORITY_CLASSES_0,
988 nig_params->llfc_low_priority_classes);
989 }
990 REG_WR(bp, port ? NIG_REG_P1_PKT_PRIORITY_TO_COS :
991 NIG_REG_P0_PKT_PRIORITY_TO_COS,
992 pkt_priority_to_cos);
993}
994
995
996void bnx2x_update_pfc(struct link_params *params,
997 struct link_vars *vars,
998 struct bnx2x_nig_brb_pfc_port_params *pfc_params)
999{
1000 /**
1001 * The PFC and pause are orthogonal to one another, meaning when
1002 * PFC is enabled, the pause are disabled, and when PFC is
1003 * disabled, pause are set according to the pause result.
1004 */
1005 u32 val;
1006 struct bnx2x *bp = params->bp;
1007
1008 /* update NIG params */
1009 bnx2x_update_pfc_nig(params, vars, pfc_params);
1010
1011 /* update BRB params */
1012 bnx2x_update_pfc_brb(params, vars, pfc_params);
1013
1014 if (!vars->link_up)
1015 return;
1016
1017 val = REG_RD(bp, MISC_REG_RESET_REG_2);
1018 if ((val & (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << params->port))
1019 == 0) {
1020 DP(NETIF_MSG_LINK, "About to update PFC in EMAC\n");
1021 bnx2x_emac_enable(params, vars, 0);
1022 return;
1023 }
1024
1025 DP(NETIF_MSG_LINK, "About to update PFC in BMAC\n");
1026 if (CHIP_IS_E2(bp))
1027 bnx2x_update_pfc_bmac2(params, vars, 0);
1028 else
1029 bnx2x_update_pfc_bmac1(params, vars);
1030
1031 val = 0;
1032 if ((params->feature_config_flags &
1033 FEATURE_CONFIG_PFC_ENABLED) ||
1034 (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
1035 val = 1;
1036 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + params->port*4, val);
1037}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001038
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001039static u8 bnx2x_bmac1_enable(struct link_params *params,
1040 struct link_vars *vars,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001041 u8 is_lb)
1042{
1043 struct bnx2x *bp = params->bp;
1044 u8 port = params->port;
1045 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
1046 NIG_REG_INGRESS_BMAC0_MEM;
1047 u32 wb_data[2];
1048 u32 val;
1049
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001050 DP(NETIF_MSG_LINK, "Enabling BigMAC1\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001051
1052 /* XGXS control */
1053 wb_data[0] = 0x3c;
1054 wb_data[1] = 0;
1055 REG_WR_DMAE(bp, bmac_addr +
1056 BIGMAC_REGISTER_BMAC_XGXS_CONTROL,
1057 wb_data, 2);
1058
1059 /* tx MAC SA */
1060 wb_data[0] = ((params->mac_addr[2] << 24) |
1061 (params->mac_addr[3] << 16) |
1062 (params->mac_addr[4] << 8) |
1063 params->mac_addr[5]);
1064 wb_data[1] = ((params->mac_addr[0] << 8) |
1065 params->mac_addr[1]);
1066 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_SOURCE_ADDR,
1067 wb_data, 2);
1068
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001069 /* mac control */
1070 val = 0x3;
1071 if (is_lb) {
1072 val |= 0x4;
1073 DP(NETIF_MSG_LINK, "enable bmac loopback\n");
1074 }
1075 wb_data[0] = val;
1076 wb_data[1] = 0;
1077 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
1078 wb_data, 2);
1079
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001080 /* set rx mtu */
1081 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
1082 wb_data[1] = 0;
1083 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_MAX_SIZE,
1084 wb_data, 2);
1085
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001086 bnx2x_update_pfc_bmac1(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001087
1088 /* set tx mtu */
1089 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
1090 wb_data[1] = 0;
1091 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_MAX_SIZE,
1092 wb_data, 2);
1093
1094 /* set cnt max size */
1095 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
1096 wb_data[1] = 0;
1097 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_CNT_MAX_SIZE,
1098 wb_data, 2);
1099
1100 /* configure safc */
1101 wb_data[0] = 0x1000200;
1102 wb_data[1] = 0;
1103 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_LLFC_MSG_FLDS,
1104 wb_data, 2);
1105 /* fix for emulation */
1106 if (CHIP_REV_IS_EMUL(bp)) {
1107 wb_data[0] = 0xf000;
1108 wb_data[1] = 0;
1109 REG_WR_DMAE(bp,
1110 bmac_addr + BIGMAC_REGISTER_TX_PAUSE_THRESHOLD,
1111 wb_data, 2);
1112 }
1113
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001114
1115 return 0;
1116}
1117
1118static u8 bnx2x_bmac2_enable(struct link_params *params,
1119 struct link_vars *vars,
1120 u8 is_lb)
1121{
1122 struct bnx2x *bp = params->bp;
1123 u8 port = params->port;
1124 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
1125 NIG_REG_INGRESS_BMAC0_MEM;
1126 u32 wb_data[2];
1127
1128 DP(NETIF_MSG_LINK, "Enabling BigMAC2\n");
1129
1130 wb_data[0] = 0;
1131 wb_data[1] = 0;
1132 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_BMAC_CONTROL,
1133 wb_data, 2);
1134 udelay(30);
1135
1136 /* XGXS control: Reset phy HW, MDIO registers, PHY PLL and BMAC */
1137 wb_data[0] = 0x3c;
1138 wb_data[1] = 0;
1139 REG_WR_DMAE(bp, bmac_addr +
1140 BIGMAC2_REGISTER_BMAC_XGXS_CONTROL,
1141 wb_data, 2);
1142
1143 udelay(30);
1144
1145 /* tx MAC SA */
1146 wb_data[0] = ((params->mac_addr[2] << 24) |
1147 (params->mac_addr[3] << 16) |
1148 (params->mac_addr[4] << 8) |
1149 params->mac_addr[5]);
1150 wb_data[1] = ((params->mac_addr[0] << 8) |
1151 params->mac_addr[1]);
1152 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_SOURCE_ADDR,
1153 wb_data, 2);
1154
1155 udelay(30);
1156
1157 /* Configure SAFC */
1158 wb_data[0] = 0x1000200;
1159 wb_data[1] = 0;
1160 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_LLFC_MSG_FLDS,
1161 wb_data, 2);
1162 udelay(30);
1163
1164 /* set rx mtu */
1165 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
1166 wb_data[1] = 0;
1167 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_MAX_SIZE,
1168 wb_data, 2);
1169 udelay(30);
1170
1171 /* set tx mtu */
1172 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
1173 wb_data[1] = 0;
1174 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_MAX_SIZE,
1175 wb_data, 2);
1176 udelay(30);
1177 /* set cnt max size */
1178 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD - 2;
1179 wb_data[1] = 0;
1180 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_CNT_MAX_SIZE,
1181 wb_data, 2);
1182 udelay(30);
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001183 bnx2x_update_pfc_bmac2(params, vars, is_lb);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001184
1185 return 0;
1186}
1187
stephen hemminger8d962862010-10-21 07:50:56 +00001188static u8 bnx2x_bmac_enable(struct link_params *params,
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001189 struct link_vars *vars,
1190 u8 is_lb)
1191{
1192 u8 rc, port = params->port;
1193 struct bnx2x *bp = params->bp;
1194 u32 val;
1195 /* reset and unreset the BigMac */
1196 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
1197 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
Yaniv Rosner1d9c05d2010-11-01 05:32:25 +00001198 msleep(1);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001199
1200 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
1201 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
1202
1203 /* enable access for bmac registers */
1204 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
1205
1206 /* Enable BMAC according to BMAC type*/
1207 if (CHIP_IS_E2(bp))
1208 rc = bnx2x_bmac2_enable(params, vars, is_lb);
1209 else
1210 rc = bnx2x_bmac1_enable(params, vars, is_lb);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001211 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0x1);
1212 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 0x0);
1213 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 0x0);
1214 val = 0;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001215 if ((params->feature_config_flags &
1216 FEATURE_CONFIG_PFC_ENABLED) ||
1217 (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001218 val = 1;
1219 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, val);
1220 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x0);
1221 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x0);
1222 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, 0x0);
1223 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x1);
1224 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x1);
1225
1226 vars->mac_type = MAC_TYPE_BMAC;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001227 return rc;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001228}
1229
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001230
1231static void bnx2x_update_mng(struct link_params *params, u32 link_status)
1232{
1233 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00001234
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001235 REG_WR(bp, params->shmem_base +
1236 offsetof(struct shmem_region,
1237 port_mb[params->port].link_status),
1238 link_status);
1239}
1240
1241static void bnx2x_bmac_rx_disable(struct bnx2x *bp, u8 port)
1242{
1243 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
1244 NIG_REG_INGRESS_BMAC0_MEM;
1245 u32 wb_data[2];
Eilon Greenstein3196a882008-08-13 15:58:49 -07001246 u32 nig_bmac_enable = REG_RD(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001247
1248 /* Only if the bmac is out of reset */
1249 if (REG_RD(bp, MISC_REG_RESET_REG_2) &
1250 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port) &&
1251 nig_bmac_enable) {
1252
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001253 if (CHIP_IS_E2(bp)) {
1254 /* Clear Rx Enable bit in BMAC_CONTROL register */
1255 REG_RD_DMAE(bp, bmac_addr +
1256 BIGMAC2_REGISTER_BMAC_CONTROL,
1257 wb_data, 2);
1258 wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
1259 REG_WR_DMAE(bp, bmac_addr +
1260 BIGMAC2_REGISTER_BMAC_CONTROL,
1261 wb_data, 2);
1262 } else {
1263 /* Clear Rx Enable bit in BMAC_CONTROL register */
1264 REG_RD_DMAE(bp, bmac_addr +
1265 BIGMAC_REGISTER_BMAC_CONTROL,
1266 wb_data, 2);
1267 wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
1268 REG_WR_DMAE(bp, bmac_addr +
1269 BIGMAC_REGISTER_BMAC_CONTROL,
1270 wb_data, 2);
1271 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001272 msleep(1);
1273 }
1274}
1275
1276static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl,
1277 u32 line_speed)
1278{
1279 struct bnx2x *bp = params->bp;
1280 u8 port = params->port;
1281 u32 init_crd, crd;
1282 u32 count = 1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001283
1284 /* disable port */
1285 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x1);
1286
1287 /* wait for init credit */
1288 init_crd = REG_RD(bp, PBF_REG_P0_INIT_CRD + port*4);
1289 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
1290 DP(NETIF_MSG_LINK, "init_crd 0x%x crd 0x%x\n", init_crd, crd);
1291
1292 while ((init_crd != crd) && count) {
1293 msleep(5);
1294
1295 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
1296 count--;
1297 }
1298 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
1299 if (init_crd != crd) {
1300 DP(NETIF_MSG_LINK, "BUG! init_crd 0x%x != crd 0x%x\n",
1301 init_crd, crd);
1302 return -EINVAL;
1303 }
1304
David S. Millerc0700f92008-12-16 23:53:20 -08001305 if (flow_ctrl & BNX2X_FLOW_CTRL_RX ||
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001306 line_speed == SPEED_10 ||
1307 line_speed == SPEED_100 ||
1308 line_speed == SPEED_1000 ||
1309 line_speed == SPEED_2500) {
1310 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001311 /* update threshold */
1312 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, 0);
1313 /* update init credit */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001314 init_crd = 778; /* (800-18-4) */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001315
1316 } else {
1317 u32 thresh = (ETH_MAX_JUMBO_PACKET_SIZE +
1318 ETH_OVREHEAD)/16;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001319 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001320 /* update threshold */
1321 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, thresh);
1322 /* update init credit */
1323 switch (line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001324 case SPEED_10000:
1325 init_crd = thresh + 553 - 22;
1326 break;
1327
1328 case SPEED_12000:
1329 init_crd = thresh + 664 - 22;
1330 break;
1331
1332 case SPEED_13000:
1333 init_crd = thresh + 742 - 22;
1334 break;
1335
1336 case SPEED_16000:
1337 init_crd = thresh + 778 - 22;
1338 break;
1339 default:
1340 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
1341 line_speed);
1342 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001343 }
1344 }
1345 REG_WR(bp, PBF_REG_P0_INIT_CRD + port*4, init_crd);
1346 DP(NETIF_MSG_LINK, "PBF updated to speed %d credit %d\n",
1347 line_speed, init_crd);
1348
1349 /* probe the credit changes */
1350 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x1);
1351 msleep(5);
1352 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x0);
1353
1354 /* enable port */
1355 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x0);
1356 return 0;
1357}
1358
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00001359static u32 bnx2x_get_emac_base(struct bnx2x *bp,
1360 u32 mdc_mdio_access, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001361{
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00001362 u32 emac_base = 0;
1363 switch (mdc_mdio_access) {
1364 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_PHY_TYPE:
1365 break;
1366 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC0:
1367 if (REG_RD(bp, NIG_REG_PORT_SWAP))
1368 emac_base = GRCBASE_EMAC1;
1369 else
1370 emac_base = GRCBASE_EMAC0;
1371 break;
1372 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1:
Eilon Greenstein589abe32009-02-12 08:36:55 +00001373 if (REG_RD(bp, NIG_REG_PORT_SWAP))
1374 emac_base = GRCBASE_EMAC0;
1375 else
1376 emac_base = GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001377 break;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00001378 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH:
1379 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
1380 break;
1381 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_SWAPPED:
Eilon Greenstein6378c022008-08-13 15:59:25 -07001382 emac_base = (port) ? GRCBASE_EMAC0 : GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001383 break;
1384 default:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001385 break;
1386 }
1387 return emac_base;
1388
1389}
1390
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001391u8 bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy,
1392 u8 devad, u16 reg, u16 val)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001393{
1394 u32 tmp, saved_mode;
1395 u8 i, rc = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001396
1397 /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
1398 * (a value of 49==0x31) and make sure that the AUTO poll is off
1399 */
Eilon Greenstein589abe32009-02-12 08:36:55 +00001400
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001401 saved_mode = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001402 tmp = saved_mode & ~(EMAC_MDIO_MODE_AUTO_POLL |
1403 EMAC_MDIO_MODE_CLOCK_CNT);
1404 tmp |= (EMAC_MDIO_MODE_CLAUSE_45 |
1405 (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001406 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, tmp);
1407 REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001408 udelay(40);
1409
1410 /* address */
1411
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001412 tmp = ((phy->addr << 21) | (devad << 16) | reg |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001413 EMAC_MDIO_COMM_COMMAND_ADDRESS |
1414 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001415 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001416
1417 for (i = 0; i < 50; i++) {
1418 udelay(10);
1419
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001420 tmp = REG_RD(bp, phy->mdio_ctrl +
1421 EMAC_REG_EMAC_MDIO_COMM);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001422 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
1423 udelay(5);
1424 break;
1425 }
1426 }
1427 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
1428 DP(NETIF_MSG_LINK, "write phy register failed\n");
1429 rc = -EFAULT;
1430 } else {
1431 /* data */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001432 tmp = ((phy->addr << 21) | (devad << 16) | val |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001433 EMAC_MDIO_COMM_COMMAND_WRITE_45 |
1434 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001435 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001436
1437 for (i = 0; i < 50; i++) {
1438 udelay(10);
1439
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001440 tmp = REG_RD(bp, phy->mdio_ctrl +
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001441 EMAC_REG_EMAC_MDIO_COMM);
1442 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
1443 udelay(5);
1444 break;
1445 }
1446 }
1447 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
1448 DP(NETIF_MSG_LINK, "write phy register failed\n");
1449 rc = -EFAULT;
1450 }
1451 }
1452
1453 /* Restore the saved mode */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001454 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001455
1456 return rc;
1457}
1458
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001459u8 bnx2x_cl45_read(struct bnx2x *bp, struct bnx2x_phy *phy,
1460 u8 devad, u16 reg, u16 *ret_val)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001461{
1462 u32 val, saved_mode;
1463 u16 i;
1464 u8 rc = 0;
1465
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001466 /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
1467 * (a value of 49==0x31) and make sure that the AUTO poll is off
1468 */
Eilon Greenstein589abe32009-02-12 08:36:55 +00001469
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001470 saved_mode = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
1471 val = saved_mode & ~((EMAC_MDIO_MODE_AUTO_POLL |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001472 EMAC_MDIO_MODE_CLOCK_CNT));
1473 val |= (EMAC_MDIO_MODE_CLAUSE_45 |
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00001474 (49L << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001475 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, val);
1476 REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001477 udelay(40);
1478
1479 /* address */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001480 val = ((phy->addr << 21) | (devad << 16) | reg |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001481 EMAC_MDIO_COMM_COMMAND_ADDRESS |
1482 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001483 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001484
1485 for (i = 0; i < 50; i++) {
1486 udelay(10);
1487
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001488 val = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001489 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
1490 udelay(5);
1491 break;
1492 }
1493 }
1494 if (val & EMAC_MDIO_COMM_START_BUSY) {
1495 DP(NETIF_MSG_LINK, "read phy register failed\n");
1496
1497 *ret_val = 0;
1498 rc = -EFAULT;
1499
1500 } else {
1501 /* data */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001502 val = ((phy->addr << 21) | (devad << 16) |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001503 EMAC_MDIO_COMM_COMMAND_READ_45 |
1504 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001505 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001506
1507 for (i = 0; i < 50; i++) {
1508 udelay(10);
1509
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001510 val = REG_RD(bp, phy->mdio_ctrl +
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001511 EMAC_REG_EMAC_MDIO_COMM);
1512 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
1513 *ret_val = (u16)(val & EMAC_MDIO_COMM_DATA);
1514 break;
1515 }
1516 }
1517 if (val & EMAC_MDIO_COMM_START_BUSY) {
1518 DP(NETIF_MSG_LINK, "read phy register failed\n");
1519
1520 *ret_val = 0;
1521 rc = -EFAULT;
1522 }
1523 }
1524
1525 /* Restore the saved mode */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001526 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001527
1528 return rc;
1529}
1530
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001531u8 bnx2x_phy_read(struct link_params *params, u8 phy_addr,
1532 u8 devad, u16 reg, u16 *ret_val)
1533{
1534 u8 phy_index;
1535 /**
1536 * Probe for the phy according to the given phy_addr, and execute
1537 * the read request on it
1538 */
1539 for (phy_index = 0; phy_index < params->num_phys; phy_index++) {
1540 if (params->phy[phy_index].addr == phy_addr) {
1541 return bnx2x_cl45_read(params->bp,
1542 &params->phy[phy_index], devad,
1543 reg, ret_val);
1544 }
1545 }
1546 return -EINVAL;
1547}
1548
1549u8 bnx2x_phy_write(struct link_params *params, u8 phy_addr,
1550 u8 devad, u16 reg, u16 val)
1551{
1552 u8 phy_index;
1553 /**
1554 * Probe for the phy according to the given phy_addr, and execute
1555 * the write request on it
1556 */
1557 for (phy_index = 0; phy_index < params->num_phys; phy_index++) {
1558 if (params->phy[phy_index].addr == phy_addr) {
1559 return bnx2x_cl45_write(params->bp,
1560 &params->phy[phy_index], devad,
1561 reg, val);
1562 }
1563 }
1564 return -EINVAL;
1565}
1566
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001567static void bnx2x_set_aer_mmd_xgxs(struct link_params *params,
1568 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001569{
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001570 u32 ser_lane;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001571 u16 offset, aer_val;
1572 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001573 ser_lane = ((params->lane_config &
1574 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
1575 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
1576
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001577 offset = phy->addr + ser_lane;
1578 if (CHIP_IS_E2(bp))
1579 aer_val = 0x2800 + offset - 1;
1580 else
1581 aer_val = 0x3800 + offset;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001582 CL45_WR_OVER_CL22(bp, phy,
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001583 MDIO_REG_BANK_AER_BLOCK,
1584 MDIO_AER_BLOCK_AER_REG, aer_val);
1585}
1586static void bnx2x_set_aer_mmd_serdes(struct bnx2x *bp,
1587 struct bnx2x_phy *phy)
1588{
1589 CL45_WR_OVER_CL22(bp, phy,
1590 MDIO_REG_BANK_AER_BLOCK,
1591 MDIO_AER_BLOCK_AER_REG, 0x3800);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001592}
1593
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001594/******************************************************************/
1595/* Internal phy section */
1596/******************************************************************/
1597
1598static void bnx2x_set_serdes_access(struct bnx2x *bp, u8 port)
1599{
1600 u32 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
1601
1602 /* Set Clause 22 */
1603 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + port*0x10, 1);
1604 REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245f8000);
1605 udelay(500);
1606 REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245d000f);
1607 udelay(500);
1608 /* Set Clause 45 */
1609 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + port*0x10, 0);
1610}
1611
1612static void bnx2x_serdes_deassert(struct bnx2x *bp, u8 port)
1613{
1614 u32 val;
1615
1616 DP(NETIF_MSG_LINK, "bnx2x_serdes_deassert\n");
1617
1618 val = SERDES_RESET_BITS << (port*16);
1619
1620 /* reset and unreset the SerDes/XGXS */
1621 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR, val);
1622 udelay(500);
1623 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET, val);
1624
1625 bnx2x_set_serdes_access(bp, port);
1626
1627 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_DEVAD +
1628 port*0x10,
1629 DEFAULT_PHY_DEV_ADDR);
1630}
1631
1632static void bnx2x_xgxs_deassert(struct link_params *params)
1633{
1634 struct bnx2x *bp = params->bp;
1635 u8 port;
1636 u32 val;
1637 DP(NETIF_MSG_LINK, "bnx2x_xgxs_deassert\n");
1638 port = params->port;
1639
1640 val = XGXS_RESET_BITS << (port*16);
1641
1642 /* reset and unreset the SerDes/XGXS */
1643 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR, val);
1644 udelay(500);
1645 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET, val);
1646
1647 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_ST +
1648 port*0x18, 0);
1649 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
1650 params->phy[INT_PHY].def_md_devad);
1651}
1652
Yaniv Rosnera22f0782010-09-07 11:41:20 +00001653
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001654void bnx2x_link_status_update(struct link_params *params,
1655 struct link_vars *vars)
1656{
1657 struct bnx2x *bp = params->bp;
1658 u8 link_10g;
1659 u8 port = params->port;
1660
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001661 vars->link_status = REG_RD(bp, params->shmem_base +
1662 offsetof(struct shmem_region,
1663 port_mb[port].link_status));
1664
1665 vars->link_up = (vars->link_status & LINK_STATUS_LINK_UP);
1666
1667 if (vars->link_up) {
1668 DP(NETIF_MSG_LINK, "phy link up\n");
1669
1670 vars->phy_link_up = 1;
1671 vars->duplex = DUPLEX_FULL;
1672 switch (vars->link_status &
1673 LINK_STATUS_SPEED_AND_DUPLEX_MASK) {
1674 case LINK_10THD:
1675 vars->duplex = DUPLEX_HALF;
1676 /* fall thru */
1677 case LINK_10TFD:
1678 vars->line_speed = SPEED_10;
1679 break;
1680
1681 case LINK_100TXHD:
1682 vars->duplex = DUPLEX_HALF;
1683 /* fall thru */
1684 case LINK_100T4:
1685 case LINK_100TXFD:
1686 vars->line_speed = SPEED_100;
1687 break;
1688
1689 case LINK_1000THD:
1690 vars->duplex = DUPLEX_HALF;
1691 /* fall thru */
1692 case LINK_1000TFD:
1693 vars->line_speed = SPEED_1000;
1694 break;
1695
1696 case LINK_2500THD:
1697 vars->duplex = DUPLEX_HALF;
1698 /* fall thru */
1699 case LINK_2500TFD:
1700 vars->line_speed = SPEED_2500;
1701 break;
1702
1703 case LINK_10GTFD:
1704 vars->line_speed = SPEED_10000;
1705 break;
1706
1707 case LINK_12GTFD:
1708 vars->line_speed = SPEED_12000;
1709 break;
1710
1711 case LINK_12_5GTFD:
1712 vars->line_speed = SPEED_12500;
1713 break;
1714
1715 case LINK_13GTFD:
1716 vars->line_speed = SPEED_13000;
1717 break;
1718
1719 case LINK_15GTFD:
1720 vars->line_speed = SPEED_15000;
1721 break;
1722
1723 case LINK_16GTFD:
1724 vars->line_speed = SPEED_16000;
1725 break;
1726
1727 default:
1728 break;
1729 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001730 vars->flow_ctrl = 0;
1731 if (vars->link_status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED)
1732 vars->flow_ctrl |= BNX2X_FLOW_CTRL_TX;
1733
1734 if (vars->link_status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED)
1735 vars->flow_ctrl |= BNX2X_FLOW_CTRL_RX;
1736
1737 if (!vars->flow_ctrl)
1738 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
1739
1740 if (vars->line_speed &&
1741 ((vars->line_speed == SPEED_10) ||
1742 (vars->line_speed == SPEED_100))) {
1743 vars->phy_flags |= PHY_SGMII_FLAG;
1744 } else {
1745 vars->phy_flags &= ~PHY_SGMII_FLAG;
1746 }
1747
1748 /* anything 10 and over uses the bmac */
1749 link_10g = ((vars->line_speed == SPEED_10000) ||
1750 (vars->line_speed == SPEED_12000) ||
1751 (vars->line_speed == SPEED_12500) ||
1752 (vars->line_speed == SPEED_13000) ||
1753 (vars->line_speed == SPEED_15000) ||
1754 (vars->line_speed == SPEED_16000));
1755 if (link_10g)
1756 vars->mac_type = MAC_TYPE_BMAC;
1757 else
1758 vars->mac_type = MAC_TYPE_EMAC;
1759
1760 } else { /* link down */
1761 DP(NETIF_MSG_LINK, "phy link down\n");
1762
1763 vars->phy_link_up = 0;
1764
1765 vars->line_speed = 0;
1766 vars->duplex = DUPLEX_FULL;
1767 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
1768
1769 /* indicate no mac active */
1770 vars->mac_type = MAC_TYPE_NONE;
1771 }
1772
1773 DP(NETIF_MSG_LINK, "link_status 0x%x phy_link_up %x\n",
1774 vars->link_status, vars->phy_link_up);
1775 DP(NETIF_MSG_LINK, "line_speed %x duplex %x flow_ctrl 0x%x\n",
1776 vars->line_speed, vars->duplex, vars->flow_ctrl);
1777}
1778
1779
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001780static void bnx2x_set_master_ln(struct link_params *params,
1781 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001782{
1783 struct bnx2x *bp = params->bp;
1784 u16 new_master_ln, ser_lane;
1785 ser_lane = ((params->lane_config &
1786 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
1787 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
1788
1789 /* set the master_ln for AN */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001790 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001791 MDIO_REG_BANK_XGXS_BLOCK2,
1792 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
1793 &new_master_ln);
1794
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001795 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001796 MDIO_REG_BANK_XGXS_BLOCK2 ,
1797 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
1798 (new_master_ln | ser_lane));
1799}
1800
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001801static u8 bnx2x_reset_unicore(struct link_params *params,
1802 struct bnx2x_phy *phy,
1803 u8 set_serdes)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001804{
1805 struct bnx2x *bp = params->bp;
1806 u16 mii_control;
1807 u16 i;
1808
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001809 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001810 MDIO_REG_BANK_COMBO_IEEE0,
1811 MDIO_COMBO_IEEE0_MII_CONTROL, &mii_control);
1812
1813 /* reset the unicore */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001814 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001815 MDIO_REG_BANK_COMBO_IEEE0,
1816 MDIO_COMBO_IEEE0_MII_CONTROL,
1817 (mii_control |
1818 MDIO_COMBO_IEEO_MII_CONTROL_RESET));
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001819 if (set_serdes)
1820 bnx2x_set_serdes_access(bp, params->port);
Eilon Greensteinc1b73992009-02-12 08:37:07 +00001821
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001822 /* wait for the reset to self clear */
1823 for (i = 0; i < MDIO_ACCESS_TIMEOUT; i++) {
1824 udelay(5);
1825
1826 /* the reset erased the previous bank value */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001827 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001828 MDIO_REG_BANK_COMBO_IEEE0,
1829 MDIO_COMBO_IEEE0_MII_CONTROL,
1830 &mii_control);
1831
1832 if (!(mii_control & MDIO_COMBO_IEEO_MII_CONTROL_RESET)) {
1833 udelay(5);
1834 return 0;
1835 }
1836 }
1837
1838 DP(NETIF_MSG_LINK, "BUG! XGXS is still in reset!\n");
1839 return -EINVAL;
1840
1841}
1842
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001843static void bnx2x_set_swap_lanes(struct link_params *params,
1844 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001845{
1846 struct bnx2x *bp = params->bp;
1847 /* Each two bits represents a lane number:
1848 No swap is 0123 => 0x1b no need to enable the swap */
1849 u16 ser_lane, rx_lane_swap, tx_lane_swap;
1850
1851 ser_lane = ((params->lane_config &
1852 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
1853 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
1854 rx_lane_swap = ((params->lane_config &
1855 PORT_HW_CFG_LANE_SWAP_CFG_RX_MASK) >>
1856 PORT_HW_CFG_LANE_SWAP_CFG_RX_SHIFT);
1857 tx_lane_swap = ((params->lane_config &
1858 PORT_HW_CFG_LANE_SWAP_CFG_TX_MASK) >>
1859 PORT_HW_CFG_LANE_SWAP_CFG_TX_SHIFT);
1860
1861 if (rx_lane_swap != 0x1b) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001862 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001863 MDIO_REG_BANK_XGXS_BLOCK2,
1864 MDIO_XGXS_BLOCK2_RX_LN_SWAP,
1865 (rx_lane_swap |
1866 MDIO_XGXS_BLOCK2_RX_LN_SWAP_ENABLE |
1867 MDIO_XGXS_BLOCK2_RX_LN_SWAP_FORCE_ENABLE));
1868 } else {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001869 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001870 MDIO_REG_BANK_XGXS_BLOCK2,
1871 MDIO_XGXS_BLOCK2_RX_LN_SWAP, 0);
1872 }
1873
1874 if (tx_lane_swap != 0x1b) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001875 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001876 MDIO_REG_BANK_XGXS_BLOCK2,
1877 MDIO_XGXS_BLOCK2_TX_LN_SWAP,
1878 (tx_lane_swap |
1879 MDIO_XGXS_BLOCK2_TX_LN_SWAP_ENABLE));
1880 } else {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001881 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001882 MDIO_REG_BANK_XGXS_BLOCK2,
1883 MDIO_XGXS_BLOCK2_TX_LN_SWAP, 0);
1884 }
1885}
1886
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001887static void bnx2x_set_parallel_detection(struct bnx2x_phy *phy,
1888 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001889{
1890 struct bnx2x *bp = params->bp;
1891 u16 control2;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001892 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001893 MDIO_REG_BANK_SERDES_DIGITAL,
1894 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
1895 &control2);
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001896 if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
Yaniv Rosner18afb0a2009-11-05 19:18:04 +02001897 control2 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
1898 else
1899 control2 &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001900 DP(NETIF_MSG_LINK, "phy->speed_cap_mask = 0x%x, control2 = 0x%x\n",
1901 phy->speed_cap_mask, control2);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001902 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001903 MDIO_REG_BANK_SERDES_DIGITAL,
1904 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
1905 control2);
1906
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001907 if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00001908 (phy->speed_cap_mask &
Yaniv Rosner18afb0a2009-11-05 19:18:04 +02001909 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001910 DP(NETIF_MSG_LINK, "XGXS\n");
1911
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001912 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001913 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1914 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK,
1915 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT);
1916
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001917 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001918 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1919 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
1920 &control2);
1921
1922
1923 control2 |=
1924 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN;
1925
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001926 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001927 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1928 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
1929 control2);
1930
1931 /* Disable parallel detection of HiG */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001932 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001933 MDIO_REG_BANK_XGXS_BLOCK2,
1934 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G,
1935 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_CX4_XGXS |
1936 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_HIGIG_XGXS);
1937 }
1938}
1939
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001940static void bnx2x_set_autoneg(struct bnx2x_phy *phy,
1941 struct link_params *params,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001942 struct link_vars *vars,
1943 u8 enable_cl73)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001944{
1945 struct bnx2x *bp = params->bp;
1946 u16 reg_val;
1947
1948 /* CL37 Autoneg */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001949 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001950 MDIO_REG_BANK_COMBO_IEEE0,
1951 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
1952
1953 /* CL37 Autoneg Enabled */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001954 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001955 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_AN_EN;
1956 else /* CL37 Autoneg Disabled */
1957 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1958 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN);
1959
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001960 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001961 MDIO_REG_BANK_COMBO_IEEE0,
1962 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
1963
1964 /* Enable/Disable Autodetection */
1965
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001966 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001967 MDIO_REG_BANK_SERDES_DIGITAL,
1968 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, &reg_val);
Eilon Greenstein239d6862009-08-12 08:23:04 +00001969 reg_val &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN |
1970 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT);
1971 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001972 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001973 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
1974 else
1975 reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
1976
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001977 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001978 MDIO_REG_BANK_SERDES_DIGITAL,
1979 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, reg_val);
1980
1981 /* Enable TetonII and BAM autoneg */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001982 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001983 MDIO_REG_BANK_BAM_NEXT_PAGE,
1984 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
1985 &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001986 if (vars->line_speed == SPEED_AUTO_NEG) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001987 /* Enable BAM aneg Mode and TetonII aneg Mode */
1988 reg_val |= (MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
1989 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
1990 } else {
1991 /* TetonII and BAM Autoneg Disabled */
1992 reg_val &= ~(MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
1993 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
1994 }
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001995 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001996 MDIO_REG_BANK_BAM_NEXT_PAGE,
1997 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
1998 reg_val);
1999
Eilon Greenstein239d6862009-08-12 08:23:04 +00002000 if (enable_cl73) {
2001 /* Enable Cl73 FSM status bits */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002002 CL45_WR_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00002003 MDIO_REG_BANK_CL73_USERB0,
2004 MDIO_CL73_USERB0_CL73_UCTRL,
Yaniv Rosner7846e472009-11-05 19:18:07 +02002005 0xe);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002006
2007 /* Enable BAM Station Manager*/
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002008 CL45_WR_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00002009 MDIO_REG_BANK_CL73_USERB0,
2010 MDIO_CL73_USERB0_CL73_BAM_CTRL1,
2011 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN |
2012 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_STATION_MNGR_EN |
2013 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN);
2014
Yaniv Rosner7846e472009-11-05 19:18:07 +02002015 /* Advertise CL73 link speeds */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002016 CL45_RD_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00002017 MDIO_REG_BANK_CL73_IEEEB1,
2018 MDIO_CL73_IEEEB1_AN_ADV2,
2019 &reg_val);
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002020 if (phy->speed_cap_mask &
Yaniv Rosner7846e472009-11-05 19:18:07 +02002021 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
2022 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002023 if (phy->speed_cap_mask &
Yaniv Rosner7846e472009-11-05 19:18:07 +02002024 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
2025 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX;
Eilon Greenstein239d6862009-08-12 08:23:04 +00002026
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002027 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002028 MDIO_REG_BANK_CL73_IEEEB1,
2029 MDIO_CL73_IEEEB1_AN_ADV2,
2030 reg_val);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002031
Eilon Greenstein239d6862009-08-12 08:23:04 +00002032 /* CL73 Autoneg Enabled */
2033 reg_val = MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN;
2034
2035 } else /* CL73 Autoneg Disabled */
2036 reg_val = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002037
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002038 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002039 MDIO_REG_BANK_CL73_IEEEB0,
2040 MDIO_CL73_IEEEB0_CL73_AN_CONTROL, reg_val);
2041}
2042
2043/* program SerDes, forced speed */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002044static void bnx2x_program_serdes(struct bnx2x_phy *phy,
2045 struct link_params *params,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002046 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002047{
2048 struct bnx2x *bp = params->bp;
2049 u16 reg_val;
2050
Eilon Greenstein57937202009-08-12 08:23:53 +00002051 /* program duplex, disable autoneg and sgmii*/
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002052 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002053 MDIO_REG_BANK_COMBO_IEEE0,
2054 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
2055 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX |
Eilon Greenstein57937202009-08-12 08:23:53 +00002056 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
2057 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK);
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002058 if (phy->req_duplex == DUPLEX_FULL)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002059 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002060 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002061 MDIO_REG_BANK_COMBO_IEEE0,
2062 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
2063
2064 /* program speed
2065 - needed only if the speed is greater than 1G (2.5G or 10G) */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002066 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002067 MDIO_REG_BANK_SERDES_DIGITAL,
2068 MDIO_SERDES_DIGITAL_MISC1, &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002069 /* clearing the speed value before setting the right speed */
2070 DP(NETIF_MSG_LINK, "MDIO_REG_BANK_SERDES_DIGITAL = 0x%x\n", reg_val);
2071
2072 reg_val &= ~(MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_MASK |
2073 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
2074
2075 if (!((vars->line_speed == SPEED_1000) ||
2076 (vars->line_speed == SPEED_100) ||
2077 (vars->line_speed == SPEED_10))) {
2078
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002079 reg_val |= (MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_156_25M |
2080 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002081 if (vars->line_speed == SPEED_10000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002082 reg_val |=
2083 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_10G_CX4;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002084 if (vars->line_speed == SPEED_13000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002085 reg_val |=
2086 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_13G;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002087 }
2088
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002089 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002090 MDIO_REG_BANK_SERDES_DIGITAL,
2091 MDIO_SERDES_DIGITAL_MISC1, reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002092
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002093}
2094
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002095static void bnx2x_set_brcm_cl37_advertisment(struct bnx2x_phy *phy,
2096 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002097{
2098 struct bnx2x *bp = params->bp;
2099 u16 val = 0;
2100
2101 /* configure the 48 bits for BAM AN */
2102
2103 /* set extended capabilities */
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002104 if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002105 val |= MDIO_OVER_1G_UP1_2_5G;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002106 if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002107 val |= MDIO_OVER_1G_UP1_10G;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002108 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002109 MDIO_REG_BANK_OVER_1G,
2110 MDIO_OVER_1G_UP1, val);
2111
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002112 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002113 MDIO_REG_BANK_OVER_1G,
Eilon Greenstein239d6862009-08-12 08:23:04 +00002114 MDIO_OVER_1G_UP3, 0x400);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002115}
2116
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002117static void bnx2x_calc_ieee_aneg_adv(struct bnx2x_phy *phy,
2118 struct link_params *params, u16 *ieee_fc)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002119{
Yaniv Rosnerd5cb9e92009-11-05 19:18:10 +02002120 struct bnx2x *bp = params->bp;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002121 *ieee_fc = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002122 /* resolve pause mode and advertisement
2123 * Please refer to Table 28B-3 of the 802.3ab-1999 spec */
2124
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002125 switch (phy->req_flow_ctrl) {
David S. Millerc0700f92008-12-16 23:53:20 -08002126 case BNX2X_FLOW_CTRL_AUTO:
2127 if (params->req_fc_auto_adv == BNX2X_FLOW_CTRL_BOTH) {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002128 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002129 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
2130 } else {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002131 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002132 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
2133 }
2134 break;
David S. Millerc0700f92008-12-16 23:53:20 -08002135 case BNX2X_FLOW_CTRL_TX:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002136 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002137 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
2138 break;
2139
David S. Millerc0700f92008-12-16 23:53:20 -08002140 case BNX2X_FLOW_CTRL_RX:
2141 case BNX2X_FLOW_CTRL_BOTH:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002142 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002143 break;
2144
David S. Millerc0700f92008-12-16 23:53:20 -08002145 case BNX2X_FLOW_CTRL_NONE:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002146 default:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002147 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002148 break;
2149 }
Yaniv Rosnerd5cb9e92009-11-05 19:18:10 +02002150 DP(NETIF_MSG_LINK, "ieee_fc = 0x%x\n", *ieee_fc);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002151}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002152
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002153static void bnx2x_set_ieee_aneg_advertisment(struct bnx2x_phy *phy,
2154 struct link_params *params,
Eilon Greenstein1ef70b92009-08-12 08:23:59 +00002155 u16 ieee_fc)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002156{
2157 struct bnx2x *bp = params->bp;
Yaniv Rosner7846e472009-11-05 19:18:07 +02002158 u16 val;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002159 /* for AN, we are always publishing full duplex */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002160
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002161 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002162 MDIO_REG_BANK_COMBO_IEEE0,
Eilon Greenstein1ef70b92009-08-12 08:23:59 +00002163 MDIO_COMBO_IEEE0_AUTO_NEG_ADV, ieee_fc);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002164 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner7846e472009-11-05 19:18:07 +02002165 MDIO_REG_BANK_CL73_IEEEB1,
2166 MDIO_CL73_IEEEB1_AN_ADV1, &val);
2167 val &= ~MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_BOTH;
2168 val |= ((ieee_fc<<3) & MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002169 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosner7846e472009-11-05 19:18:07 +02002170 MDIO_REG_BANK_CL73_IEEEB1,
2171 MDIO_CL73_IEEEB1_AN_ADV1, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002172}
2173
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002174static void bnx2x_restart_autoneg(struct bnx2x_phy *phy,
2175 struct link_params *params,
2176 u8 enable_cl73)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002177{
2178 struct bnx2x *bp = params->bp;
Eilon Greenstein3a36f2e2009-02-12 08:37:09 +00002179 u16 mii_control;
Eilon Greenstein239d6862009-08-12 08:23:04 +00002180
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002181 DP(NETIF_MSG_LINK, "bnx2x_restart_autoneg\n");
Eilon Greenstein3a36f2e2009-02-12 08:37:09 +00002182 /* Enable and restart BAM/CL37 aneg */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002183
Eilon Greenstein239d6862009-08-12 08:23:04 +00002184 if (enable_cl73) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002185 CL45_RD_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00002186 MDIO_REG_BANK_CL73_IEEEB0,
2187 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
2188 &mii_control);
2189
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002190 CL45_WR_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00002191 MDIO_REG_BANK_CL73_IEEEB0,
2192 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
2193 (mii_control |
2194 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN |
2195 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN));
2196 } else {
2197
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002198 CL45_RD_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00002199 MDIO_REG_BANK_COMBO_IEEE0,
2200 MDIO_COMBO_IEEE0_MII_CONTROL,
2201 &mii_control);
2202 DP(NETIF_MSG_LINK,
2203 "bnx2x_restart_autoneg mii_control before = 0x%x\n",
2204 mii_control);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002205 CL45_WR_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00002206 MDIO_REG_BANK_COMBO_IEEE0,
2207 MDIO_COMBO_IEEE0_MII_CONTROL,
2208 (mii_control |
2209 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
2210 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN));
2211 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002212}
2213
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002214static void bnx2x_initialize_sgmii_process(struct bnx2x_phy *phy,
2215 struct link_params *params,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002216 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002217{
2218 struct bnx2x *bp = params->bp;
2219 u16 control1;
2220
2221 /* in SGMII mode, the unicore is always slave */
2222
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002223 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002224 MDIO_REG_BANK_SERDES_DIGITAL,
2225 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
2226 &control1);
2227 control1 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT;
2228 /* set sgmii mode (and not fiber) */
2229 control1 &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE |
2230 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET |
2231 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_MSTR_MODE);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002232 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002233 MDIO_REG_BANK_SERDES_DIGITAL,
2234 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
2235 control1);
2236
2237 /* if forced speed */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002238 if (!(vars->line_speed == SPEED_AUTO_NEG)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002239 /* set speed, disable autoneg */
2240 u16 mii_control;
2241
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002242 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002243 MDIO_REG_BANK_COMBO_IEEE0,
2244 MDIO_COMBO_IEEE0_MII_CONTROL,
2245 &mii_control);
2246 mii_control &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
2247 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK|
2248 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX);
2249
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002250 switch (vars->line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002251 case SPEED_100:
2252 mii_control |=
2253 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_100;
2254 break;
2255 case SPEED_1000:
2256 mii_control |=
2257 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_1000;
2258 break;
2259 case SPEED_10:
2260 /* there is nothing to set for 10M */
2261 break;
2262 default:
2263 /* invalid speed for SGMII */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002264 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
2265 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002266 break;
2267 }
2268
2269 /* setting the full duplex */
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002270 if (phy->req_duplex == DUPLEX_FULL)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002271 mii_control |=
2272 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002273 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002274 MDIO_REG_BANK_COMBO_IEEE0,
2275 MDIO_COMBO_IEEE0_MII_CONTROL,
2276 mii_control);
2277
2278 } else { /* AN mode */
2279 /* enable and restart AN */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002280 bnx2x_restart_autoneg(phy, params, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002281 }
2282}
2283
2284
2285/*
2286 * link management
2287 */
2288
2289static void bnx2x_pause_resolve(struct link_vars *vars, u32 pause_result)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002290{ /* LD LP */
2291 switch (pause_result) { /* ASYM P ASYM P */
2292 case 0xb: /* 1 0 1 1 */
David S. Millerc0700f92008-12-16 23:53:20 -08002293 vars->flow_ctrl = BNX2X_FLOW_CTRL_TX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002294 break;
2295
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002296 case 0xe: /* 1 1 1 0 */
David S. Millerc0700f92008-12-16 23:53:20 -08002297 vars->flow_ctrl = BNX2X_FLOW_CTRL_RX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002298 break;
2299
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002300 case 0x5: /* 0 1 0 1 */
2301 case 0x7: /* 0 1 1 1 */
2302 case 0xd: /* 1 1 0 1 */
2303 case 0xf: /* 1 1 1 1 */
David S. Millerc0700f92008-12-16 23:53:20 -08002304 vars->flow_ctrl = BNX2X_FLOW_CTRL_BOTH;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002305 break;
2306
2307 default:
2308 break;
2309 }
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002310 if (pause_result & (1<<0))
2311 vars->link_status |= LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE;
2312 if (pause_result & (1<<1))
2313 vars->link_status |= LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002314}
2315
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002316static u8 bnx2x_direct_parallel_detect_used(struct bnx2x_phy *phy,
2317 struct link_params *params)
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02002318{
2319 struct bnx2x *bp = params->bp;
2320 u16 pd_10g, status2_1000x;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002321 if (phy->req_line_speed != SPEED_AUTO_NEG)
2322 return 0;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002323 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02002324 MDIO_REG_BANK_SERDES_DIGITAL,
2325 MDIO_SERDES_DIGITAL_A_1000X_STATUS2,
2326 &status2_1000x);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002327 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02002328 MDIO_REG_BANK_SERDES_DIGITAL,
2329 MDIO_SERDES_DIGITAL_A_1000X_STATUS2,
2330 &status2_1000x);
2331 if (status2_1000x & MDIO_SERDES_DIGITAL_A_1000X_STATUS2_AN_DISABLED) {
2332 DP(NETIF_MSG_LINK, "1G parallel detect link on port %d\n",
2333 params->port);
2334 return 1;
2335 }
2336
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002337 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02002338 MDIO_REG_BANK_10G_PARALLEL_DETECT,
2339 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_STATUS,
2340 &pd_10g);
2341
2342 if (pd_10g & MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_STATUS_PD_LINK) {
2343 DP(NETIF_MSG_LINK, "10G parallel detect link on port %d\n",
2344 params->port);
2345 return 1;
2346 }
2347 return 0;
2348}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002349
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002350static void bnx2x_flow_ctrl_resolve(struct bnx2x_phy *phy,
2351 struct link_params *params,
2352 struct link_vars *vars,
2353 u32 gp_status)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002354{
2355 struct bnx2x *bp = params->bp;
Eilon Greenstein3196a882008-08-13 15:58:49 -07002356 u16 ld_pause; /* local driver */
2357 u16 lp_pause; /* link partner */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002358 u16 pause_result;
2359
David S. Millerc0700f92008-12-16 23:53:20 -08002360 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002361
2362 /* resolve from gp_status in case of AN complete and not sgmii */
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002363 if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO)
2364 vars->flow_ctrl = phy->req_flow_ctrl;
2365 else if (phy->req_line_speed != SPEED_AUTO_NEG)
2366 vars->flow_ctrl = params->req_fc_auto_adv;
2367 else if ((gp_status & MDIO_AN_CL73_OR_37_COMPLETE) &&
2368 (!(vars->phy_flags & PHY_SGMII_FLAG))) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002369 if (bnx2x_direct_parallel_detect_used(phy, params)) {
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02002370 vars->flow_ctrl = params->req_fc_auto_adv;
2371 return;
2372 }
Yaniv Rosner7846e472009-11-05 19:18:07 +02002373 if ((gp_status &
2374 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
2375 MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) ==
2376 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
2377 MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) {
2378
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002379 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner7846e472009-11-05 19:18:07 +02002380 MDIO_REG_BANK_CL73_IEEEB1,
2381 MDIO_CL73_IEEEB1_AN_ADV1,
2382 &ld_pause);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002383 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner7846e472009-11-05 19:18:07 +02002384 MDIO_REG_BANK_CL73_IEEEB1,
2385 MDIO_CL73_IEEEB1_AN_LP_ADV1,
2386 &lp_pause);
2387 pause_result = (ld_pause &
2388 MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK)
2389 >> 8;
2390 pause_result |= (lp_pause &
2391 MDIO_CL73_IEEEB1_AN_LP_ADV1_PAUSE_MASK)
2392 >> 10;
2393 DP(NETIF_MSG_LINK, "pause_result CL73 0x%x\n",
2394 pause_result);
2395 } else {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002396 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner7846e472009-11-05 19:18:07 +02002397 MDIO_REG_BANK_COMBO_IEEE0,
2398 MDIO_COMBO_IEEE0_AUTO_NEG_ADV,
2399 &ld_pause);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002400 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner7846e472009-11-05 19:18:07 +02002401 MDIO_REG_BANK_COMBO_IEEE0,
2402 MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1,
2403 &lp_pause);
2404 pause_result = (ld_pause &
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002405 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>5;
Yaniv Rosner7846e472009-11-05 19:18:07 +02002406 pause_result |= (lp_pause &
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002407 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7;
Yaniv Rosner7846e472009-11-05 19:18:07 +02002408 DP(NETIF_MSG_LINK, "pause_result CL37 0x%x\n",
2409 pause_result);
2410 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002411 bnx2x_pause_resolve(vars, pause_result);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002412 }
2413 DP(NETIF_MSG_LINK, "flow_ctrl 0x%x\n", vars->flow_ctrl);
2414}
2415
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002416static void bnx2x_check_fallback_to_cl37(struct bnx2x_phy *phy,
2417 struct link_params *params)
Eilon Greenstein239d6862009-08-12 08:23:04 +00002418{
2419 struct bnx2x *bp = params->bp;
2420 u16 rx_status, ustat_val, cl37_fsm_recieved;
2421 DP(NETIF_MSG_LINK, "bnx2x_check_fallback_to_cl37\n");
2422 /* Step 1: Make sure signal is detected */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002423 CL45_RD_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00002424 MDIO_REG_BANK_RX0,
2425 MDIO_RX0_RX_STATUS,
2426 &rx_status);
2427 if ((rx_status & MDIO_RX0_RX_STATUS_SIGDET) !=
2428 (MDIO_RX0_RX_STATUS_SIGDET)) {
2429 DP(NETIF_MSG_LINK, "Signal is not detected. Restoring CL73."
2430 "rx_status(0x80b0) = 0x%x\n", rx_status);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002431 CL45_WR_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00002432 MDIO_REG_BANK_CL73_IEEEB0,
2433 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
2434 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN);
2435 return;
2436 }
2437 /* Step 2: Check CL73 state machine */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002438 CL45_RD_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00002439 MDIO_REG_BANK_CL73_USERB0,
2440 MDIO_CL73_USERB0_CL73_USTAT1,
2441 &ustat_val);
2442 if ((ustat_val &
2443 (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK |
2444 MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) !=
2445 (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK |
2446 MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) {
2447 DP(NETIF_MSG_LINK, "CL73 state-machine is not stable. "
2448 "ustat_val(0x8371) = 0x%x\n", ustat_val);
2449 return;
2450 }
2451 /* Step 3: Check CL37 Message Pages received to indicate LP
2452 supports only CL37 */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002453 CL45_RD_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00002454 MDIO_REG_BANK_REMOTE_PHY,
2455 MDIO_REMOTE_PHY_MISC_RX_STATUS,
2456 &cl37_fsm_recieved);
2457 if ((cl37_fsm_recieved &
2458 (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG |
2459 MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) !=
2460 (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG |
2461 MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) {
2462 DP(NETIF_MSG_LINK, "No CL37 FSM were received. "
2463 "misc_rx_status(0x8330) = 0x%x\n",
2464 cl37_fsm_recieved);
2465 return;
2466 }
2467 /* The combined cl37/cl73 fsm state information indicating that we are
2468 connected to a device which does not support cl73, but does support
2469 cl37 BAM. In this case we disable cl73 and restart cl37 auto-neg */
2470 /* Disable CL73 */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002471 CL45_WR_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00002472 MDIO_REG_BANK_CL73_IEEEB0,
2473 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
2474 0);
2475 /* Restart CL37 autoneg */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002476 bnx2x_restart_autoneg(phy, params, 0);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002477 DP(NETIF_MSG_LINK, "Disabling CL73, and restarting CL37 autoneg\n");
2478}
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002479
2480static void bnx2x_xgxs_an_resolve(struct bnx2x_phy *phy,
2481 struct link_params *params,
2482 struct link_vars *vars,
2483 u32 gp_status)
2484{
2485 if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE)
2486 vars->link_status |=
2487 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
2488
2489 if (bnx2x_direct_parallel_detect_used(phy, params))
2490 vars->link_status |=
2491 LINK_STATUS_PARALLEL_DETECTION_USED;
2492}
2493
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002494static u8 bnx2x_link_settings_status(struct bnx2x_phy *phy,
2495 struct link_params *params,
2496 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002497{
2498 struct bnx2x *bp = params->bp;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002499 u16 new_line_speed , gp_status;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002500 u8 rc = 0;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002501
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002502 /* Read gp_status */
2503 CL45_RD_OVER_CL22(bp, phy,
2504 MDIO_REG_BANK_GP_STATUS,
2505 MDIO_GP_STATUS_TOP_AN_STATUS1,
2506 &gp_status);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00002507
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002508 if (phy->req_line_speed == SPEED_AUTO_NEG)
2509 vars->link_status |= LINK_STATUS_AUTO_NEGOTIATE_ENABLED;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002510 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) {
2511 DP(NETIF_MSG_LINK, "phy link up gp_status=0x%x\n",
2512 gp_status);
2513
2514 vars->phy_link_up = 1;
2515 vars->link_status |= LINK_STATUS_LINK_UP;
2516
2517 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_DUPLEX_STATUS)
2518 vars->duplex = DUPLEX_FULL;
2519 else
2520 vars->duplex = DUPLEX_HALF;
2521
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002522 if (SINGLE_MEDIA_DIRECT(params)) {
2523 bnx2x_flow_ctrl_resolve(phy, params, vars, gp_status);
2524 if (phy->req_line_speed == SPEED_AUTO_NEG)
2525 bnx2x_xgxs_an_resolve(phy, params, vars,
2526 gp_status);
2527 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002528
2529 switch (gp_status & GP_STATUS_SPEED_MASK) {
2530 case GP_STATUS_10M:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002531 new_line_speed = SPEED_10;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002532 if (vars->duplex == DUPLEX_FULL)
2533 vars->link_status |= LINK_10TFD;
2534 else
2535 vars->link_status |= LINK_10THD;
2536 break;
2537
2538 case GP_STATUS_100M:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002539 new_line_speed = SPEED_100;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002540 if (vars->duplex == DUPLEX_FULL)
2541 vars->link_status |= LINK_100TXFD;
2542 else
2543 vars->link_status |= LINK_100TXHD;
2544 break;
2545
2546 case GP_STATUS_1G:
2547 case GP_STATUS_1G_KX:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002548 new_line_speed = SPEED_1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002549 if (vars->duplex == DUPLEX_FULL)
2550 vars->link_status |= LINK_1000TFD;
2551 else
2552 vars->link_status |= LINK_1000THD;
2553 break;
2554
2555 case GP_STATUS_2_5G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002556 new_line_speed = SPEED_2500;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002557 if (vars->duplex == DUPLEX_FULL)
2558 vars->link_status |= LINK_2500TFD;
2559 else
2560 vars->link_status |= LINK_2500THD;
2561 break;
2562
2563 case GP_STATUS_5G:
2564 case GP_STATUS_6G:
2565 DP(NETIF_MSG_LINK,
2566 "link speed unsupported gp_status 0x%x\n",
2567 gp_status);
2568 return -EINVAL;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002569
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002570 case GP_STATUS_10G_KX4:
2571 case GP_STATUS_10G_HIG:
2572 case GP_STATUS_10G_CX4:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002573 new_line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002574 vars->link_status |= LINK_10GTFD;
2575 break;
2576
2577 case GP_STATUS_12G_HIG:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002578 new_line_speed = SPEED_12000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002579 vars->link_status |= LINK_12GTFD;
2580 break;
2581
2582 case GP_STATUS_12_5G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002583 new_line_speed = SPEED_12500;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002584 vars->link_status |= LINK_12_5GTFD;
2585 break;
2586
2587 case GP_STATUS_13G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002588 new_line_speed = SPEED_13000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002589 vars->link_status |= LINK_13GTFD;
2590 break;
2591
2592 case GP_STATUS_15G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002593 new_line_speed = SPEED_15000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002594 vars->link_status |= LINK_15GTFD;
2595 break;
2596
2597 case GP_STATUS_16G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002598 new_line_speed = SPEED_16000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002599 vars->link_status |= LINK_16GTFD;
2600 break;
2601
2602 default:
2603 DP(NETIF_MSG_LINK,
2604 "link speed unsupported gp_status 0x%x\n",
2605 gp_status);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002606 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002607 }
2608
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002609 vars->line_speed = new_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002610
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002611 } else { /* link_down */
2612 DP(NETIF_MSG_LINK, "phy link down\n");
2613
2614 vars->phy_link_up = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002615
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002616 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08002617 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002618 vars->mac_type = MAC_TYPE_NONE;
Eilon Greenstein239d6862009-08-12 08:23:04 +00002619
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002620 if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
2621 SINGLE_MEDIA_DIRECT(params)) {
Eilon Greenstein239d6862009-08-12 08:23:04 +00002622 /* Check signal is detected */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002623 bnx2x_check_fallback_to_cl37(phy, params);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002624 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002625 }
2626
Frans Pop2381a552010-03-24 07:57:36 +00002627 DP(NETIF_MSG_LINK, "gp_status 0x%x phy_link_up %x line_speed %x\n",
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002628 gp_status, vars->phy_link_up, vars->line_speed);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002629 DP(NETIF_MSG_LINK, "duplex %x flow_ctrl 0x%x link_status 0x%x\n",
2630 vars->duplex, vars->flow_ctrl, vars->link_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002631 return rc;
2632}
2633
Eilon Greensteined8680a2009-02-12 08:37:12 +00002634static void bnx2x_set_gmii_tx_driver(struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002635{
2636 struct bnx2x *bp = params->bp;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002637 struct bnx2x_phy *phy = &params->phy[INT_PHY];
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002638 u16 lp_up2;
2639 u16 tx_driver;
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00002640 u16 bank;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002641
2642 /* read precomp */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002643 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002644 MDIO_REG_BANK_OVER_1G,
2645 MDIO_OVER_1G_LP_UP2, &lp_up2);
2646
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002647 /* bits [10:7] at lp_up2, positioned at [15:12] */
2648 lp_up2 = (((lp_up2 & MDIO_OVER_1G_LP_UP2_PREEMPHASIS_MASK) >>
2649 MDIO_OVER_1G_LP_UP2_PREEMPHASIS_SHIFT) <<
2650 MDIO_TX0_TX_DRIVER_PREEMPHASIS_SHIFT);
2651
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00002652 if (lp_up2 == 0)
2653 return;
2654
2655 for (bank = MDIO_REG_BANK_TX0; bank <= MDIO_REG_BANK_TX3;
2656 bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0)) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002657 CL45_RD_OVER_CL22(bp, phy,
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00002658 bank,
2659 MDIO_TX0_TX_DRIVER, &tx_driver);
2660
2661 /* replace tx_driver bits [15:12] */
2662 if (lp_up2 !=
2663 (tx_driver & MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK)) {
2664 tx_driver &= ~MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK;
2665 tx_driver |= lp_up2;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002666 CL45_WR_OVER_CL22(bp, phy,
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00002667 bank,
2668 MDIO_TX0_TX_DRIVER, tx_driver);
2669 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002670 }
2671}
2672
2673static u8 bnx2x_emac_program(struct link_params *params,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002674 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002675{
2676 struct bnx2x *bp = params->bp;
2677 u8 port = params->port;
2678 u16 mode = 0;
2679
2680 DP(NETIF_MSG_LINK, "setting link speed & duplex\n");
2681 bnx2x_bits_dis(bp, GRCBASE_EMAC0 + port*0x400 +
2682 EMAC_REG_EMAC_MODE,
2683 (EMAC_MODE_25G_MODE |
2684 EMAC_MODE_PORT_MII_10M |
2685 EMAC_MODE_HALF_DUPLEX));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002686 switch (vars->line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002687 case SPEED_10:
2688 mode |= EMAC_MODE_PORT_MII_10M;
2689 break;
2690
2691 case SPEED_100:
2692 mode |= EMAC_MODE_PORT_MII;
2693 break;
2694
2695 case SPEED_1000:
2696 mode |= EMAC_MODE_PORT_GMII;
2697 break;
2698
2699 case SPEED_2500:
2700 mode |= (EMAC_MODE_25G_MODE | EMAC_MODE_PORT_GMII);
2701 break;
2702
2703 default:
2704 /* 10G not valid for EMAC */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002705 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
2706 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002707 return -EINVAL;
2708 }
2709
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002710 if (vars->duplex == DUPLEX_HALF)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002711 mode |= EMAC_MODE_HALF_DUPLEX;
2712 bnx2x_bits_en(bp,
2713 GRCBASE_EMAC0 + port*0x400 + EMAC_REG_EMAC_MODE,
2714 mode);
2715
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00002716 bnx2x_set_led(params, vars, LED_MODE_OPER, vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002717 return 0;
2718}
2719
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002720static void bnx2x_set_preemphasis(struct bnx2x_phy *phy,
2721 struct link_params *params)
2722{
2723
2724 u16 bank, i = 0;
2725 struct bnx2x *bp = params->bp;
2726
2727 for (bank = MDIO_REG_BANK_RX0, i = 0; bank <= MDIO_REG_BANK_RX3;
2728 bank += (MDIO_REG_BANK_RX1-MDIO_REG_BANK_RX0), i++) {
2729 CL45_WR_OVER_CL22(bp, phy,
2730 bank,
2731 MDIO_RX0_RX_EQ_BOOST,
2732 phy->rx_preemphasis[i]);
2733 }
2734
2735 for (bank = MDIO_REG_BANK_TX0, i = 0; bank <= MDIO_REG_BANK_TX3;
2736 bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0), i++) {
2737 CL45_WR_OVER_CL22(bp, phy,
2738 bank,
2739 MDIO_TX0_TX_DRIVER,
2740 phy->tx_preemphasis[i]);
2741 }
2742}
2743
2744static void bnx2x_init_internal_phy(struct bnx2x_phy *phy,
2745 struct link_params *params,
2746 struct link_vars *vars)
2747{
2748 struct bnx2x *bp = params->bp;
2749 u8 enable_cl73 = (SINGLE_MEDIA_DIRECT(params) ||
2750 (params->loopback_mode == LOOPBACK_XGXS));
2751 if (!(vars->phy_flags & PHY_SGMII_FLAG)) {
2752 if (SINGLE_MEDIA_DIRECT(params) &&
2753 (params->feature_config_flags &
2754 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED))
2755 bnx2x_set_preemphasis(phy, params);
2756
2757 /* forced speed requested? */
2758 if (vars->line_speed != SPEED_AUTO_NEG ||
2759 (SINGLE_MEDIA_DIRECT(params) &&
2760 params->loopback_mode == LOOPBACK_EXT)) {
2761 DP(NETIF_MSG_LINK, "not SGMII, no AN\n");
2762
2763 /* disable autoneg */
2764 bnx2x_set_autoneg(phy, params, vars, 0);
2765
2766 /* program speed and duplex */
2767 bnx2x_program_serdes(phy, params, vars);
2768
2769 } else { /* AN_mode */
2770 DP(NETIF_MSG_LINK, "not SGMII, AN\n");
2771
2772 /* AN enabled */
2773 bnx2x_set_brcm_cl37_advertisment(phy, params);
2774
2775 /* program duplex & pause advertisement (for aneg) */
2776 bnx2x_set_ieee_aneg_advertisment(phy, params,
2777 vars->ieee_fc);
2778
2779 /* enable autoneg */
2780 bnx2x_set_autoneg(phy, params, vars, enable_cl73);
2781
2782 /* enable and restart AN */
2783 bnx2x_restart_autoneg(phy, params, enable_cl73);
2784 }
2785
2786 } else { /* SGMII mode */
2787 DP(NETIF_MSG_LINK, "SGMII\n");
2788
2789 bnx2x_initialize_sgmii_process(phy, params, vars);
2790 }
2791}
2792
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002793static u8 bnx2x_init_serdes(struct bnx2x_phy *phy,
2794 struct link_params *params,
2795 struct link_vars *vars)
2796{
2797 u8 rc;
2798 vars->phy_flags |= PHY_SGMII_FLAG;
2799 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002800 bnx2x_set_aer_mmd_serdes(params->bp, phy);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002801 rc = bnx2x_reset_unicore(params, phy, 1);
2802 /* reset the SerDes and wait for reset bit return low */
2803 if (rc != 0)
2804 return rc;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002805 bnx2x_set_aer_mmd_serdes(params->bp, phy);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002806
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002807 return rc;
2808}
2809
2810static u8 bnx2x_init_xgxs(struct bnx2x_phy *phy,
2811 struct link_params *params,
2812 struct link_vars *vars)
2813{
2814 u8 rc;
2815 vars->phy_flags = PHY_XGXS_FLAG;
2816 if ((phy->req_line_speed &&
2817 ((phy->req_line_speed == SPEED_100) ||
2818 (phy->req_line_speed == SPEED_10))) ||
2819 (!phy->req_line_speed &&
2820 (phy->speed_cap_mask >=
2821 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL) &&
2822 (phy->speed_cap_mask <
2823 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
2824 ))
2825 vars->phy_flags |= PHY_SGMII_FLAG;
2826 else
2827 vars->phy_flags &= ~PHY_SGMII_FLAG;
2828
2829 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002830 bnx2x_set_aer_mmd_xgxs(params, phy);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002831 bnx2x_set_master_ln(params, phy);
2832
2833 rc = bnx2x_reset_unicore(params, phy, 0);
2834 /* reset the SerDes and wait for reset bit return low */
2835 if (rc != 0)
2836 return rc;
2837
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002838 bnx2x_set_aer_mmd_xgxs(params, phy);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002839
2840 /* setting the masterLn_def again after the reset */
2841 bnx2x_set_master_ln(params, phy);
2842 bnx2x_set_swap_lanes(params, phy);
2843
2844 return rc;
2845}
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002846
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002847static u16 bnx2x_wait_reset_complete(struct bnx2x *bp,
2848 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002849{
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002850 u16 cnt, ctrl;
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002851 /* Wait for soft reset to get cleared upto 1 sec */
2852 for (cnt = 0; cnt < 1000; cnt++) {
2853 bnx2x_cl45_read(bp, phy,
2854 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, &ctrl);
2855 if (!(ctrl & (1<<15)))
2856 break;
2857 msleep(1);
2858 }
2859 DP(NETIF_MSG_LINK, "control reg 0x%x (after %d ms)\n", ctrl, cnt);
2860 return cnt;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002861}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002862
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002863static void bnx2x_link_int_enable(struct link_params *params)
2864{
2865 u8 port = params->port;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002866 u32 mask;
2867 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002868
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002869 /* setting the status to report on link up
2870 for either XGXS or SerDes */
2871
2872 if (params->switch_cfg == SWITCH_CFG_10G) {
2873 mask = (NIG_MASK_XGXS0_LINK10G |
2874 NIG_MASK_XGXS0_LINK_STATUS);
2875 DP(NETIF_MSG_LINK, "enabled XGXS interrupt\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002876 if (!(SINGLE_MEDIA_DIRECT(params)) &&
2877 params->phy[INT_PHY].type !=
2878 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002879 mask |= NIG_MASK_MI_INT;
2880 DP(NETIF_MSG_LINK, "enabled external phy int\n");
2881 }
2882
2883 } else { /* SerDes */
2884 mask = NIG_MASK_SERDES0_LINK_STATUS;
2885 DP(NETIF_MSG_LINK, "enabled SerDes interrupt\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002886 if (!(SINGLE_MEDIA_DIRECT(params)) &&
2887 params->phy[INT_PHY].type !=
2888 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_NOT_CONN) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002889 mask |= NIG_MASK_MI_INT;
2890 DP(NETIF_MSG_LINK, "enabled external phy int\n");
2891 }
2892 }
2893 bnx2x_bits_en(bp,
2894 NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
2895 mask);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002896
2897 DP(NETIF_MSG_LINK, "port %x, is_xgxs %x, int_status 0x%x\n", port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002898 (params->switch_cfg == SWITCH_CFG_10G),
2899 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002900 DP(NETIF_MSG_LINK, " int_mask 0x%x, MI_INT %x, SERDES_LINK %x\n",
2901 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
2902 REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
2903 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS+port*0x3c));
2904 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
2905 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
2906 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
2907}
2908
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002909static void bnx2x_rearm_latch_signal(struct bnx2x *bp, u8 port,
2910 u8 exp_mi_int)
Eilon Greenstein2f904462009-08-12 08:22:16 +00002911{
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002912 u32 latch_status = 0;
2913
2914 /**
2915 * Disable the MI INT ( external phy int ) by writing 1 to the
2916 * status register. Link down indication is high-active-signal,
2917 * so in this case we need to write the status to clear the XOR
Eilon Greenstein2f904462009-08-12 08:22:16 +00002918 */
2919 /* Read Latched signals */
2920 latch_status = REG_RD(bp,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002921 NIG_REG_LATCH_STATUS_0 + port*8);
2922 DP(NETIF_MSG_LINK, "latch_status = 0x%x\n", latch_status);
Eilon Greenstein2f904462009-08-12 08:22:16 +00002923 /* Handle only those with latched-signal=up.*/
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002924 if (exp_mi_int)
2925 bnx2x_bits_en(bp,
2926 NIG_REG_STATUS_INTERRUPT_PORT0
2927 + port*4,
2928 NIG_STATUS_EMAC0_MI_INT);
2929 else
2930 bnx2x_bits_dis(bp,
2931 NIG_REG_STATUS_INTERRUPT_PORT0
2932 + port*4,
2933 NIG_STATUS_EMAC0_MI_INT);
2934
Eilon Greenstein2f904462009-08-12 08:22:16 +00002935 if (latch_status & 1) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002936
Eilon Greenstein2f904462009-08-12 08:22:16 +00002937 /* For all latched-signal=up : Re-Arm Latch signals */
2938 REG_WR(bp, NIG_REG_LATCH_STATUS_0 + port*8,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00002939 (latch_status & 0xfffe) | (latch_status & 1));
Eilon Greenstein2f904462009-08-12 08:22:16 +00002940 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002941 /* For all latched-signal=up,Write original_signal to status */
Eilon Greenstein2f904462009-08-12 08:22:16 +00002942}
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002943
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002944static void bnx2x_link_int_ack(struct link_params *params,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002945 struct link_vars *vars, u8 is_10g)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002946{
2947 struct bnx2x *bp = params->bp;
2948 u8 port = params->port;
2949
2950 /* first reset all status
2951 * we assume only one line will be change at a time */
2952 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
2953 (NIG_STATUS_XGXS0_LINK10G |
2954 NIG_STATUS_XGXS0_LINK_STATUS |
2955 NIG_STATUS_SERDES0_LINK_STATUS));
2956 if (vars->phy_link_up) {
2957 if (is_10g) {
2958 /* Disable the 10G link interrupt
2959 * by writing 1 to the status register
2960 */
2961 DP(NETIF_MSG_LINK, "10G XGXS phy link up\n");
2962 bnx2x_bits_en(bp,
2963 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
2964 NIG_STATUS_XGXS0_LINK10G);
2965
2966 } else if (params->switch_cfg == SWITCH_CFG_10G) {
2967 /* Disable the link interrupt
2968 * by writing 1 to the relevant lane
2969 * in the status register
2970 */
2971 u32 ser_lane = ((params->lane_config &
2972 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
2973 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
2974
Eilon Greenstein2f904462009-08-12 08:22:16 +00002975 DP(NETIF_MSG_LINK, "%d speed XGXS phy link up\n",
2976 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002977 bnx2x_bits_en(bp,
2978 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
2979 ((1 << ser_lane) <<
2980 NIG_STATUS_XGXS0_LINK_STATUS_SIZE));
2981
2982 } else { /* SerDes */
2983 DP(NETIF_MSG_LINK, "SerDes phy link up\n");
2984 /* Disable the link interrupt
2985 * by writing 1 to the status register
2986 */
2987 bnx2x_bits_en(bp,
2988 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
2989 NIG_STATUS_SERDES0_LINK_STATUS);
2990 }
2991
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002992 }
2993}
2994
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002995static u8 bnx2x_format_ver(u32 num, u8 *str, u16 *len)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002996{
2997 u8 *str_ptr = str;
2998 u32 mask = 0xf0000000;
2999 u8 shift = 8*4;
3000 u8 digit;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003001 u8 remove_leading_zeros = 1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003002 if (*len < 10) {
Frederik Schwarzer025dfda2008-10-16 19:02:37 +02003003 /* Need more than 10chars for this format */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003004 *str_ptr = '\0';
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003005 (*len)--;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003006 return -EINVAL;
3007 }
3008 while (shift > 0) {
3009
3010 shift -= 4;
3011 digit = ((num & mask) >> shift);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003012 if (digit == 0 && remove_leading_zeros) {
3013 mask = mask >> 4;
3014 continue;
3015 } else if (digit < 0xa)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003016 *str_ptr = digit + '0';
3017 else
3018 *str_ptr = digit - 0xa + 'a';
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003019 remove_leading_zeros = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003020 str_ptr++;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003021 (*len)--;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003022 mask = mask >> 4;
3023 if (shift == 4*4) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003024 *str_ptr = '.';
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003025 str_ptr++;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003026 (*len)--;
3027 remove_leading_zeros = 1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003028 }
3029 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003030 return 0;
3031}
3032
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003033
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003034static u8 bnx2x_null_format_ver(u32 spirom_ver, u8 *str, u16 *len)
3035{
3036 str[0] = '\0';
3037 (*len)--;
3038 return 0;
3039}
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003040
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003041u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
3042 u8 *version, u16 len)
3043{
Julia Lawall0376d5b2009-07-19 05:26:35 +00003044 struct bnx2x *bp;
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003045 u32 spirom_ver = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003046 u8 status = 0;
3047 u8 *ver_p = version;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003048 u16 remain_len = len;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003049 if (version == NULL || params == NULL)
3050 return -EINVAL;
Julia Lawall0376d5b2009-07-19 05:26:35 +00003051 bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003052
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003053 /* Extract first external phy*/
3054 version[0] = '\0';
3055 spirom_ver = REG_RD(bp, params->phy[EXT_PHY1].ver_addr);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003056
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003057 if (params->phy[EXT_PHY1].format_fw_ver) {
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003058 status |= params->phy[EXT_PHY1].format_fw_ver(spirom_ver,
3059 ver_p,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003060 &remain_len);
3061 ver_p += (len - remain_len);
3062 }
3063 if ((params->num_phys == MAX_PHYS) &&
3064 (params->phy[EXT_PHY2].ver_addr != 0)) {
3065 spirom_ver = REG_RD(bp,
3066 params->phy[EXT_PHY2].ver_addr);
3067 if (params->phy[EXT_PHY2].format_fw_ver) {
3068 *ver_p = '/';
3069 ver_p++;
3070 remain_len--;
3071 status |= params->phy[EXT_PHY2].format_fw_ver(
3072 spirom_ver,
3073 ver_p,
3074 &remain_len);
3075 ver_p = version + (len - remain_len);
3076 }
3077 }
3078 *ver_p = '\0';
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003079 return status;
3080}
3081
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003082static void bnx2x_set_xgxs_loopback(struct bnx2x_phy *phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003083 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003084{
3085 u8 port = params->port;
3086 struct bnx2x *bp = params->bp;
3087
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003088 if (phy->req_line_speed != SPEED_1000) {
Eilon Greenstein6378c022008-08-13 15:59:25 -07003089 u32 md_devad;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003090
3091 DP(NETIF_MSG_LINK, "XGXS 10G loopback enable\n");
3092
3093 /* change the uni_phy_addr in the nig */
3094 md_devad = REG_RD(bp, (NIG_REG_XGXS0_CTRL_MD_DEVAD +
3095 port*0x18));
3096
3097 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, 0x5);
3098
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003099 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003100 5,
3101 (MDIO_REG_BANK_AER_BLOCK +
3102 (MDIO_AER_BLOCK_AER_REG & 0xf)),
3103 0x2800);
3104
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003105 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003106 5,
3107 (MDIO_REG_BANK_CL73_IEEEB0 +
3108 (MDIO_CL73_IEEEB0_CL73_AN_CONTROL & 0xf)),
3109 0x6041);
Eilon Greenstein38582762009-01-14 06:44:16 +00003110 msleep(200);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003111 /* set aer mmd back */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00003112 bnx2x_set_aer_mmd_xgxs(params, phy);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003113
3114 /* and md_devad */
3115 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
3116 md_devad);
3117
3118 } else {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003119 u16 mii_ctrl;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003120 DP(NETIF_MSG_LINK, "XGXS 1G loopback enable\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003121 bnx2x_cl45_read(bp, phy, 5,
3122 (MDIO_REG_BANK_COMBO_IEEE0 +
3123 (MDIO_COMBO_IEEE0_MII_CONTROL & 0xf)),
3124 &mii_ctrl);
3125 bnx2x_cl45_write(bp, phy, 5,
3126 (MDIO_REG_BANK_COMBO_IEEE0 +
3127 (MDIO_COMBO_IEEE0_MII_CONTROL & 0xf)),
3128 mii_ctrl |
3129 MDIO_COMBO_IEEO_MII_CONTROL_LOOPBACK);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003130 }
3131}
3132
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003133u8 bnx2x_set_led(struct link_params *params,
3134 struct link_vars *vars, u8 mode, u32 speed)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003135{
Yaniv Rosner7846e472009-11-05 19:18:07 +02003136 u8 port = params->port;
3137 u16 hw_led_mode = params->hw_led_mode;
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003138 u8 rc = 0, phy_idx;
Eilon Greenstein345b5d52008-08-13 15:58:12 -07003139 u32 tmp;
3140 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Yaniv Rosner7846e472009-11-05 19:18:07 +02003141 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003142 DP(NETIF_MSG_LINK, "bnx2x_set_led: port %x, mode %d\n", port, mode);
3143 DP(NETIF_MSG_LINK, "speed 0x%x, hw_led_mode 0x%x\n",
3144 speed, hw_led_mode);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003145 /* In case */
3146 for (phy_idx = EXT_PHY1; phy_idx < MAX_PHYS; phy_idx++) {
3147 if (params->phy[phy_idx].set_link_led) {
3148 params->phy[phy_idx].set_link_led(
3149 &params->phy[phy_idx], params, mode);
3150 }
3151 }
3152
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003153 switch (mode) {
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003154 case LED_MODE_FRONT_PANEL_OFF:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003155 case LED_MODE_OFF:
3156 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 0);
3157 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
3158 SHARED_HW_CFG_LED_MAC1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07003159
3160 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07003161 EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp | EMAC_LED_OVERRIDE));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003162 break;
3163
3164 case LED_MODE_OPER:
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003165 /**
3166 * For all other phys, OPER mode is same as ON, so in case
3167 * link is down, do nothing
3168 **/
3169 if (!vars->link_up)
3170 break;
3171 case LED_MODE_ON:
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003172 if (SINGLE_MEDIA_DIRECT(params)) {
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003173 /**
3174 * This is a work-around for HW issue found when link
3175 * is up in CL73
3176 */
Yaniv Rosner7846e472009-11-05 19:18:07 +02003177 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0);
3178 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1);
3179 } else {
3180 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
3181 hw_led_mode);
3182 }
3183
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003184 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 +
3185 port*4, 0);
3186 /* Set blinking rate to ~15.9Hz */
3187 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4,
3188 LED_BLINK_RATE_VAL);
3189 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 +
3190 port*4, 1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07003191 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07003192 EMAC_WR(bp, EMAC_REG_EMAC_LED,
Eilon Greenstein345b5d52008-08-13 15:58:12 -07003193 (tmp & (~EMAC_LED_OVERRIDE)));
3194
Yaniv Rosner7846e472009-11-05 19:18:07 +02003195 if (CHIP_IS_E1(bp) &&
Eilon Greenstein34f80b02008-06-23 20:33:01 -07003196 ((speed == SPEED_2500) ||
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003197 (speed == SPEED_1000) ||
3198 (speed == SPEED_100) ||
3199 (speed == SPEED_10))) {
3200 /* On Everest 1 Ax chip versions for speeds less than
3201 10G LED scheme is different */
3202 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
3203 + port*4, 1);
3204 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 +
3205 port*4, 0);
3206 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_TRAFFIC_P0 +
3207 port*4, 1);
3208 }
3209 break;
3210
3211 default:
3212 rc = -EINVAL;
3213 DP(NETIF_MSG_LINK, "bnx2x_set_led: Invalid led mode %d\n",
3214 mode);
3215 break;
3216 }
3217 return rc;
3218
3219}
3220
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003221/**
3222 * This function comes to reflect the actual link state read DIRECTLY from the
3223 * HW
3224 */
3225u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars,
3226 u8 is_serdes)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003227{
3228 struct bnx2x *bp = params->bp;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003229 u16 gp_status = 0, phy_index = 0;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003230 u8 ext_phy_link_up = 0, serdes_phy_type;
3231 struct link_vars temp_vars;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003232
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003233 CL45_RD_OVER_CL22(bp, &params->phy[INT_PHY],
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003234 MDIO_REG_BANK_GP_STATUS,
3235 MDIO_GP_STATUS_TOP_AN_STATUS1,
3236 &gp_status);
3237 /* link is up only if both local phy and external phy are up */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003238 if (!(gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS))
3239 return -ESRCH;
3240
3241 switch (params->num_phys) {
3242 case 1:
3243 /* No external PHY */
3244 return 0;
3245 case 2:
3246 ext_phy_link_up = params->phy[EXT_PHY1].read_status(
3247 &params->phy[EXT_PHY1],
3248 params, &temp_vars);
3249 break;
3250 case 3: /* Dual Media */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003251 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
3252 phy_index++) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003253 serdes_phy_type = ((params->phy[phy_index].media_type ==
3254 ETH_PHY_SFP_FIBER) ||
3255 (params->phy[phy_index].media_type ==
3256 ETH_PHY_XFP_FIBER));
3257
3258 if (is_serdes != serdes_phy_type)
3259 continue;
3260 if (params->phy[phy_index].read_status) {
3261 ext_phy_link_up |=
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003262 params->phy[phy_index].read_status(
3263 &params->phy[phy_index],
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003264 params, &temp_vars);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003265 }
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003266 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003267 break;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003268 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003269 if (ext_phy_link_up)
3270 return 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003271 return -ESRCH;
3272}
3273
3274static u8 bnx2x_link_initialize(struct link_params *params,
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00003275 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003276{
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003277 u8 rc = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003278 u8 phy_index, non_ext_phy;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003279 struct bnx2x *bp = params->bp;
3280 /**
3281 * In case of external phy existence, the line speed would be the
3282 * line speed linked up by the external phy. In case it is direct
3283 * only, then the line_speed during initialization will be
3284 * equal to the req_line_speed
3285 */
3286 vars->line_speed = params->phy[INT_PHY].req_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003287
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003288 /**
3289 * Initialize the internal phy in case this is a direct board
3290 * (no external phys), or this board has external phy which requires
3291 * to first.
3292 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003293
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003294 if (params->phy[INT_PHY].config_init)
3295 params->phy[INT_PHY].config_init(
3296 &params->phy[INT_PHY],
3297 params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003298
3299 /* init ext phy and enable link state int */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003300 non_ext_phy = (SINGLE_MEDIA_DIRECT(params) ||
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003301 (params->loopback_mode == LOOPBACK_XGXS));
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003302
3303 if (non_ext_phy ||
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003304 (params->phy[EXT_PHY1].flags & FLAGS_INIT_XGXS_FIRST) ||
Eilon Greenstein8660d8c2009-03-02 08:01:02 +00003305 (params->loopback_mode == LOOPBACK_EXT_PHY)) {
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003306 struct bnx2x_phy *phy = &params->phy[INT_PHY];
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003307 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003308 bnx2x_set_parallel_detection(phy, params);
3309 bnx2x_init_internal_phy(phy, params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003310 }
3311
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003312 /* Init external phy*/
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003313 if (!non_ext_phy)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003314 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
3315 phy_index++) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003316 /**
3317 * No need to initialize second phy in case of first
3318 * phy only selection. In case of second phy, we do
3319 * need to initialize the first phy, since they are
3320 * connected.
3321 **/
3322 if (phy_index == EXT_PHY2 &&
3323 (bnx2x_phy_selection(params) ==
3324 PORT_HW_CFG_PHY_SELECTION_FIRST_PHY)) {
3325 DP(NETIF_MSG_LINK, "Not initializing"
3326 "second phy\n");
3327 continue;
3328 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003329 params->phy[phy_index].config_init(
3330 &params->phy[phy_index],
3331 params, vars);
3332 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003333
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00003334 /* Reset the interrupt indication after phy was initialized */
3335 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 +
3336 params->port*4,
3337 (NIG_STATUS_XGXS0_LINK10G |
3338 NIG_STATUS_XGXS0_LINK_STATUS |
3339 NIG_STATUS_SERDES0_LINK_STATUS |
3340 NIG_MASK_MI_INT));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003341 return rc;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003342}
3343
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003344static void bnx2x_int_link_reset(struct bnx2x_phy *phy,
3345 struct link_params *params)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003346{
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003347 /* reset the SerDes/XGXS */
3348 REG_WR(params->bp, GRCBASE_MISC +
3349 MISC_REGISTERS_RESET_REG_3_CLEAR,
3350 (0x1ff << (params->port*16)));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003351}
3352
3353static void bnx2x_common_ext_link_reset(struct bnx2x_phy *phy,
3354 struct link_params *params)
3355{
3356 struct bnx2x *bp = params->bp;
3357 u8 gpio_port;
3358 /* HW reset */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00003359 if (CHIP_IS_E2(bp))
3360 gpio_port = BP_PATH(bp);
3361 else
3362 gpio_port = params->port;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003363 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
3364 MISC_REGISTERS_GPIO_OUTPUT_LOW,
3365 gpio_port);
3366 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
3367 MISC_REGISTERS_GPIO_OUTPUT_LOW,
3368 gpio_port);
3369 DP(NETIF_MSG_LINK, "reset external PHY\n");
3370}
3371
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003372static u8 bnx2x_update_link_down(struct link_params *params,
3373 struct link_vars *vars)
3374{
3375 struct bnx2x *bp = params->bp;
3376 u8 port = params->port;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00003377
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003378 DP(NETIF_MSG_LINK, "Port %x: Link is down\n", port);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003379 bnx2x_set_led(params, vars, LED_MODE_OFF, 0);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003380
3381 /* indicate no mac active */
3382 vars->mac_type = MAC_TYPE_NONE;
3383
3384 /* update shared memory */
3385 vars->link_status = 0;
3386 vars->line_speed = 0;
3387 bnx2x_update_mng(params, vars->link_status);
3388
3389 /* activate nig drain */
3390 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
3391
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00003392 /* disable emac */
3393 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
3394
3395 msleep(10);
3396
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003397 /* reset BigMac */
3398 bnx2x_bmac_rx_disable(bp, params->port);
3399 REG_WR(bp, GRCBASE_MISC +
3400 MISC_REGISTERS_RESET_REG_2_CLEAR,
3401 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
3402 return 0;
3403}
3404
3405static u8 bnx2x_update_link_up(struct link_params *params,
3406 struct link_vars *vars,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003407 u8 link_10g)
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003408{
3409 struct bnx2x *bp = params->bp;
3410 u8 port = params->port;
3411 u8 rc = 0;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00003412
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003413 vars->link_status |= LINK_STATUS_LINK_UP;
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003414
Yaniv Rosner7aa07112010-09-07 11:41:01 +00003415 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
3416 vars->link_status |=
3417 LINK_STATUS_TX_FLOW_CONTROL_ENABLED;
3418
3419 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
3420 vars->link_status |=
3421 LINK_STATUS_RX_FLOW_CONTROL_ENABLED;
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003422
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003423 if (link_10g) {
3424 bnx2x_bmac_enable(params, vars, 0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003425 bnx2x_set_led(params, vars,
3426 LED_MODE_OPER, SPEED_10000);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003427 } else {
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003428 rc = bnx2x_emac_program(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003429
Yaniv Rosner0c786f02009-11-05 19:18:32 +02003430 bnx2x_emac_enable(params, vars, 0);
3431
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003432 /* AN complete? */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003433 if ((vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE)
3434 && (!(vars->phy_flags & PHY_SGMII_FLAG)) &&
3435 SINGLE_MEDIA_DIRECT(params))
3436 bnx2x_set_gmii_tx_driver(params);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003437 }
3438
3439 /* PBF - link up */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00003440 if (!(CHIP_IS_E2(bp)))
3441 rc |= bnx2x_pbf_update(params, vars->flow_ctrl,
3442 vars->line_speed);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003443
3444 /* disable drain */
3445 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 0);
3446
3447 /* update shared memory */
3448 bnx2x_update_mng(params, vars->link_status);
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00003449 msleep(20);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003450 return rc;
3451}
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003452/**
3453 * The bnx2x_link_update function should be called upon link
3454 * interrupt.
3455 * Link is considered up as follows:
3456 * - DIRECT_SINGLE_MEDIA - Only XGXS link (internal link) needs
3457 * to be up
3458 * - SINGLE_MEDIA - The link between the 577xx and the external
3459 * phy (XGXS) need to up as well as the external link of the
3460 * phy (PHY_EXT1)
3461 * - DUAL_MEDIA - The link between the 577xx and the first
3462 * external phy needs to be up, and at least one of the 2
3463 * external phy link must be up.
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003464 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003465u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars)
3466{
3467 struct bnx2x *bp = params->bp;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003468 struct link_vars phy_vars[MAX_PHYS];
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003469 u8 port = params->port;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003470 u8 link_10g, phy_index;
3471 u8 ext_phy_link_up = 0, cur_link_up, rc = 0;
Eilon Greenstein2f904462009-08-12 08:22:16 +00003472 u8 is_mi_int = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003473 u16 ext_phy_line_speed = 0, prev_line_speed = vars->line_speed;
3474 u8 active_external_phy = INT_PHY;
3475 vars->link_status = 0;
3476 for (phy_index = INT_PHY; phy_index < params->num_phys;
3477 phy_index++) {
3478 phy_vars[phy_index].flow_ctrl = 0;
3479 phy_vars[phy_index].link_status = 0;
3480 phy_vars[phy_index].line_speed = 0;
3481 phy_vars[phy_index].duplex = DUPLEX_FULL;
3482 phy_vars[phy_index].phy_link_up = 0;
3483 phy_vars[phy_index].link_up = 0;
3484 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003485
3486 DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n",
Eilon Greenstein2f904462009-08-12 08:22:16 +00003487 port, (vars->phy_flags & PHY_XGXS_FLAG),
3488 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003489
Eilon Greenstein2f904462009-08-12 08:22:16 +00003490 is_mi_int = (u8)(REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT +
3491 port*0x18) > 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003492 DP(NETIF_MSG_LINK, "int_mask 0x%x MI_INT %x, SERDES_LINK %x\n",
Eilon Greenstein2f904462009-08-12 08:22:16 +00003493 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
3494 is_mi_int,
3495 REG_RD(bp,
3496 NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003497
3498 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
3499 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
3500 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
3501
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00003502 /* disable emac */
3503 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
3504
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003505 /**
3506 * Step 1:
3507 * Check external link change only for external phys, and apply
3508 * priority selection between them in case the link on both phys
3509 * is up. Note that the instead of the common vars, a temporary
3510 * vars argument is used since each phy may have different link/
3511 * speed/duplex result
3512 */
3513 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
3514 phy_index++) {
3515 struct bnx2x_phy *phy = &params->phy[phy_index];
3516 if (!phy->read_status)
3517 continue;
3518 /* Read link status and params of this ext phy */
3519 cur_link_up = phy->read_status(phy, params,
3520 &phy_vars[phy_index]);
3521 if (cur_link_up) {
3522 DP(NETIF_MSG_LINK, "phy in index %d link is up\n",
3523 phy_index);
3524 } else {
3525 DP(NETIF_MSG_LINK, "phy in index %d link is down\n",
3526 phy_index);
3527 continue;
3528 }
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003529
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003530 if (!ext_phy_link_up) {
3531 ext_phy_link_up = 1;
3532 active_external_phy = phy_index;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003533 } else {
3534 switch (bnx2x_phy_selection(params)) {
3535 case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT:
3536 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
3537 /**
3538 * In this option, the first PHY makes sure to pass the
3539 * traffic through itself only.
3540 * Its not clear how to reset the link on the second phy
3541 **/
3542 active_external_phy = EXT_PHY1;
3543 break;
3544 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
3545 /**
3546 * In this option, the first PHY makes sure to pass the
3547 * traffic through the second PHY.
3548 **/
3549 active_external_phy = EXT_PHY2;
3550 break;
3551 default:
3552 /**
3553 * Link indication on both PHYs with the following cases
3554 * is invalid:
3555 * - FIRST_PHY means that second phy wasn't initialized,
3556 * hence its link is expected to be down
3557 * - SECOND_PHY means that first phy should not be able
3558 * to link up by itself (using configuration)
3559 * - DEFAULT should be overriden during initialiazation
3560 **/
3561 DP(NETIF_MSG_LINK, "Invalid link indication"
3562 "mpc=0x%x. DISABLING LINK !!!\n",
3563 params->multi_phy_config);
3564 ext_phy_link_up = 0;
3565 break;
3566 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003567 }
3568 }
3569 prev_line_speed = vars->line_speed;
3570 /**
3571 * Step 2:
3572 * Read the status of the internal phy. In case of
3573 * DIRECT_SINGLE_MEDIA board, this link is the external link,
3574 * otherwise this is the link between the 577xx and the first
3575 * external phy
3576 */
3577 if (params->phy[INT_PHY].read_status)
3578 params->phy[INT_PHY].read_status(
3579 &params->phy[INT_PHY],
3580 params, vars);
3581 /**
3582 * The INT_PHY flow control reside in the vars. This include the
3583 * case where the speed or flow control are not set to AUTO.
3584 * Otherwise, the active external phy flow control result is set
3585 * to the vars. The ext_phy_line_speed is needed to check if the
3586 * speed is different between the internal phy and external phy.
3587 * This case may be result of intermediate link speed change.
3588 */
3589 if (active_external_phy > INT_PHY) {
3590 vars->flow_ctrl = phy_vars[active_external_phy].flow_ctrl;
3591 /**
3592 * Link speed is taken from the XGXS. AN and FC result from
3593 * the external phy.
3594 */
3595 vars->link_status |= phy_vars[active_external_phy].link_status;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003596
3597 /**
3598 * if active_external_phy is first PHY and link is up - disable
3599 * disable TX on second external PHY
3600 */
3601 if (active_external_phy == EXT_PHY1) {
3602 if (params->phy[EXT_PHY2].phy_specific_func) {
3603 DP(NETIF_MSG_LINK, "Disabling TX on"
3604 " EXT_PHY2\n");
3605 params->phy[EXT_PHY2].phy_specific_func(
3606 &params->phy[EXT_PHY2],
3607 params, DISABLE_TX);
3608 }
3609 }
3610
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003611 ext_phy_line_speed = phy_vars[active_external_phy].line_speed;
3612 vars->duplex = phy_vars[active_external_phy].duplex;
3613 if (params->phy[active_external_phy].supported &
3614 SUPPORTED_FIBRE)
3615 vars->link_status |= LINK_STATUS_SERDES_LINK;
3616 DP(NETIF_MSG_LINK, "Active external phy selected: %x\n",
3617 active_external_phy);
3618 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003619
3620 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
3621 phy_index++) {
3622 if (params->phy[phy_index].flags &
3623 FLAGS_REARM_LATCH_SIGNAL) {
3624 bnx2x_rearm_latch_signal(bp, port,
3625 phy_index ==
3626 active_external_phy);
3627 break;
3628 }
3629 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003630 DP(NETIF_MSG_LINK, "vars->flow_ctrl = 0x%x, vars->link_status = 0x%x,"
3631 " ext_phy_line_speed = %d\n", vars->flow_ctrl,
3632 vars->link_status, ext_phy_line_speed);
3633 /**
3634 * Upon link speed change set the NIG into drain mode. Comes to
3635 * deals with possible FIFO glitch due to clk change when speed
3636 * is decreased without link down indicator
3637 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003638
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003639 if (vars->phy_link_up) {
3640 if (!(SINGLE_MEDIA_DIRECT(params)) && ext_phy_link_up &&
3641 (ext_phy_line_speed != vars->line_speed)) {
3642 DP(NETIF_MSG_LINK, "Internal link speed %d is"
3643 " different than the external"
3644 " link speed %d\n", vars->line_speed,
3645 ext_phy_line_speed);
3646 vars->phy_link_up = 0;
3647 } else if (prev_line_speed != vars->line_speed) {
3648 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
3649 + params->port*4, 0);
3650 msleep(1);
3651 }
3652 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003653
3654 /* anything 10 and over uses the bmac */
3655 link_10g = ((vars->line_speed == SPEED_10000) ||
3656 (vars->line_speed == SPEED_12000) ||
3657 (vars->line_speed == SPEED_12500) ||
3658 (vars->line_speed == SPEED_13000) ||
3659 (vars->line_speed == SPEED_15000) ||
3660 (vars->line_speed == SPEED_16000));
3661
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003662 bnx2x_link_int_ack(params, vars, link_10g);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003663
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003664 /**
3665 * In case external phy link is up, and internal link is down
3666 * (not initialized yet probably after link initialization, it
3667 * needs to be initialized.
3668 * Note that after link down-up as result of cable plug, the xgxs
3669 * link would probably become up again without the need
3670 * initialize it
3671 */
3672 if (!(SINGLE_MEDIA_DIRECT(params))) {
3673 DP(NETIF_MSG_LINK, "ext_phy_link_up = %d, int_link_up = %d,"
3674 " init_preceding = %d\n", ext_phy_link_up,
3675 vars->phy_link_up,
3676 params->phy[EXT_PHY1].flags &
3677 FLAGS_INIT_XGXS_FIRST);
3678 if (!(params->phy[EXT_PHY1].flags &
3679 FLAGS_INIT_XGXS_FIRST)
3680 && ext_phy_link_up && !vars->phy_link_up) {
3681 vars->line_speed = ext_phy_line_speed;
3682 if (vars->line_speed < SPEED_1000)
3683 vars->phy_flags |= PHY_SGMII_FLAG;
3684 else
3685 vars->phy_flags &= ~PHY_SGMII_FLAG;
3686 bnx2x_init_internal_phy(&params->phy[INT_PHY],
3687 params,
3688 vars);
3689 }
3690 }
3691 /**
3692 * Link is up only if both local phy and external phy (in case of
3693 * non-direct board) are up
3694 */
3695 vars->link_up = (vars->phy_link_up &&
3696 (ext_phy_link_up ||
3697 SINGLE_MEDIA_DIRECT(params)));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003698
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003699 if (vars->link_up)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003700 rc = bnx2x_update_link_up(params, vars, link_10g);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003701 else
3702 rc = bnx2x_update_link_down(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003703
3704 return rc;
3705}
3706
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003707
3708/*****************************************************************************/
3709/* External Phy section */
3710/*****************************************************************************/
3711void bnx2x_ext_phy_hw_reset(struct bnx2x *bp, u8 port)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003712{
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003713 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
3714 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
3715 msleep(1);
3716 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
3717 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003718}
3719
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003720static void bnx2x_save_spirom_version(struct bnx2x *bp, u8 port,
3721 u32 spirom_ver, u32 ver_addr)
3722{
3723 DP(NETIF_MSG_LINK, "FW version 0x%x:0x%x for port %d\n",
3724 (u16)(spirom_ver>>16), (u16)spirom_ver, port);
3725
3726 if (ver_addr)
3727 REG_WR(bp, ver_addr, spirom_ver);
3728}
3729
3730static void bnx2x_save_bcm_spirom_ver(struct bnx2x *bp,
3731 struct bnx2x_phy *phy,
3732 u8 port)
3733{
3734 u16 fw_ver1, fw_ver2;
3735
3736 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
3737 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
3738 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
3739 MDIO_PMA_REG_ROM_VER2, &fw_ver2);
3740 bnx2x_save_spirom_version(bp, port, (u32)(fw_ver1<<16 | fw_ver2),
3741 phy->ver_addr);
3742}
3743
3744static void bnx2x_ext_phy_set_pause(struct link_params *params,
3745 struct bnx2x_phy *phy,
3746 struct link_vars *vars)
3747{
3748 u16 val;
3749 struct bnx2x *bp = params->bp;
3750 /* read modify write pause advertizing */
3751 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV_PAUSE, &val);
3752
3753 val &= ~MDIO_AN_REG_ADV_PAUSE_BOTH;
3754
3755 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
3756 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
3757 if ((vars->ieee_fc &
3758 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
3759 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
3760 val |= MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC;
3761 }
3762 if ((vars->ieee_fc &
3763 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
3764 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
3765 val |= MDIO_AN_REG_ADV_PAUSE_PAUSE;
3766 }
3767 DP(NETIF_MSG_LINK, "Ext phy AN advertize 0x%x\n", val);
3768 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV_PAUSE, val);
3769}
3770
3771static u8 bnx2x_ext_phy_resolve_fc(struct bnx2x_phy *phy,
3772 struct link_params *params,
3773 struct link_vars *vars)
3774{
3775 struct bnx2x *bp = params->bp;
3776 u16 ld_pause; /* local */
3777 u16 lp_pause; /* link partner */
3778 u16 pause_result;
3779 u8 ret = 0;
3780 /* read twice */
3781
3782 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
3783
3784 if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO)
3785 vars->flow_ctrl = phy->req_flow_ctrl;
3786 else if (phy->req_line_speed != SPEED_AUTO_NEG)
3787 vars->flow_ctrl = params->req_fc_auto_adv;
3788 else if (vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE) {
3789 ret = 1;
3790 bnx2x_cl45_read(bp, phy,
3791 MDIO_AN_DEVAD,
3792 MDIO_AN_REG_ADV_PAUSE, &ld_pause);
3793 bnx2x_cl45_read(bp, phy,
3794 MDIO_AN_DEVAD,
3795 MDIO_AN_REG_LP_AUTO_NEG, &lp_pause);
3796 pause_result = (ld_pause &
3797 MDIO_AN_REG_ADV_PAUSE_MASK) >> 8;
3798 pause_result |= (lp_pause &
3799 MDIO_AN_REG_ADV_PAUSE_MASK) >> 10;
3800 DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x\n",
3801 pause_result);
3802 bnx2x_pause_resolve(vars, pause_result);
3803 }
3804 return ret;
3805}
3806
3807static void bnx2x_ext_phy_10G_an_resolve(struct bnx2x *bp,
3808 struct bnx2x_phy *phy,
3809 struct link_vars *vars)
3810{
3811 u16 val;
3812 bnx2x_cl45_read(bp, phy,
3813 MDIO_AN_DEVAD,
3814 MDIO_AN_REG_STATUS, &val);
3815 bnx2x_cl45_read(bp, phy,
3816 MDIO_AN_DEVAD,
3817 MDIO_AN_REG_STATUS, &val);
3818 if (val & (1<<5))
3819 vars->link_status |= LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
3820 if ((val & (1<<0)) == 0)
3821 vars->link_status |= LINK_STATUS_PARALLEL_DETECTION_USED;
3822}
3823
3824/******************************************************************/
3825/* common BCM8073/BCM8727 PHY SECTION */
3826/******************************************************************/
3827static void bnx2x_8073_resolve_fc(struct bnx2x_phy *phy,
3828 struct link_params *params,
3829 struct link_vars *vars)
3830{
3831 struct bnx2x *bp = params->bp;
3832 if (phy->req_line_speed == SPEED_10 ||
3833 phy->req_line_speed == SPEED_100) {
3834 vars->flow_ctrl = phy->req_flow_ctrl;
3835 return;
3836 }
3837
3838 if (bnx2x_ext_phy_resolve_fc(phy, params, vars) &&
3839 (vars->flow_ctrl == BNX2X_FLOW_CTRL_NONE)) {
3840 u16 pause_result;
3841 u16 ld_pause; /* local */
3842 u16 lp_pause; /* link partner */
3843 bnx2x_cl45_read(bp, phy,
3844 MDIO_AN_DEVAD,
3845 MDIO_AN_REG_CL37_FC_LD, &ld_pause);
3846
3847 bnx2x_cl45_read(bp, phy,
3848 MDIO_AN_DEVAD,
3849 MDIO_AN_REG_CL37_FC_LP, &lp_pause);
3850 pause_result = (ld_pause &
3851 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 5;
3852 pause_result |= (lp_pause &
3853 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 7;
3854
3855 bnx2x_pause_resolve(vars, pause_result);
3856 DP(NETIF_MSG_LINK, "Ext PHY CL37 pause result 0x%x\n",
3857 pause_result);
3858 }
3859}
3860
3861static void bnx2x_8073_8727_external_rom_boot(struct bnx2x *bp,
3862 struct bnx2x_phy *phy,
3863 u8 port)
3864{
3865 /* Boot port from external ROM */
3866 /* EDC grst */
3867 bnx2x_cl45_write(bp, phy,
3868 MDIO_PMA_DEVAD,
3869 MDIO_PMA_REG_GEN_CTRL,
3870 0x0001);
3871
3872 /* ucode reboot and rst */
3873 bnx2x_cl45_write(bp, phy,
3874 MDIO_PMA_DEVAD,
3875 MDIO_PMA_REG_GEN_CTRL,
3876 0x008c);
3877
3878 bnx2x_cl45_write(bp, phy,
3879 MDIO_PMA_DEVAD,
3880 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
3881
3882 /* Reset internal microprocessor */
3883 bnx2x_cl45_write(bp, phy,
3884 MDIO_PMA_DEVAD,
3885 MDIO_PMA_REG_GEN_CTRL,
3886 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
3887
3888 /* Release srst bit */
3889 bnx2x_cl45_write(bp, phy,
3890 MDIO_PMA_DEVAD,
3891 MDIO_PMA_REG_GEN_CTRL,
3892 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
3893
3894 /* wait for 120ms for code download via SPI port */
3895 msleep(120);
3896
3897 /* Clear ser_boot_ctl bit */
3898 bnx2x_cl45_write(bp, phy,
3899 MDIO_PMA_DEVAD,
3900 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
3901 bnx2x_save_bcm_spirom_ver(bp, phy, port);
3902}
3903
3904static void bnx2x_8073_set_xaui_low_power_mode(struct bnx2x *bp,
3905 struct bnx2x_phy *phy)
3906{
3907 u16 val;
3908 bnx2x_cl45_read(bp, phy,
3909 MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_CHIP_REV, &val);
3910
3911 if (val == 0) {
3912 /* Mustn't set low power mode in 8073 A0 */
3913 return;
3914 }
3915
3916 /* Disable PLL sequencer (use read-modify-write to clear bit 13) */
3917 bnx2x_cl45_read(bp, phy,
3918 MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, &val);
3919 val &= ~(1<<13);
3920 bnx2x_cl45_write(bp, phy,
3921 MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
3922
3923 /* PLL controls */
3924 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805E, 0x1077);
3925 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805D, 0x0000);
3926 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805C, 0x030B);
3927 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805B, 0x1240);
3928 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805A, 0x2490);
3929
3930 /* Tx Controls */
3931 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80A7, 0x0C74);
3932 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80A6, 0x9041);
3933 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80A5, 0x4640);
3934
3935 /* Rx Controls */
3936 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80FE, 0x01C4);
3937 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80FD, 0x9249);
3938 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80FC, 0x2015);
3939
3940 /* Enable PLL sequencer (use read-modify-write to set bit 13) */
3941 bnx2x_cl45_read(bp, phy, MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, &val);
3942 val |= (1<<13);
3943 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
3944}
3945
3946/******************************************************************/
3947/* BCM8073 PHY SECTION */
3948/******************************************************************/
3949static u8 bnx2x_8073_is_snr_needed(struct bnx2x *bp, struct bnx2x_phy *phy)
3950{
3951 /* This is only required for 8073A1, version 102 only */
3952 u16 val;
3953
3954 /* Read 8073 HW revision*/
3955 bnx2x_cl45_read(bp, phy,
3956 MDIO_PMA_DEVAD,
3957 MDIO_PMA_REG_8073_CHIP_REV, &val);
3958
3959 if (val != 1) {
3960 /* No need to workaround in 8073 A1 */
3961 return 0;
3962 }
3963
3964 bnx2x_cl45_read(bp, phy,
3965 MDIO_PMA_DEVAD,
3966 MDIO_PMA_REG_ROM_VER2, &val);
3967
3968 /* SNR should be applied only for version 0x102 */
3969 if (val != 0x102)
3970 return 0;
3971
3972 return 1;
3973}
3974
3975static u8 bnx2x_8073_xaui_wa(struct bnx2x *bp, struct bnx2x_phy *phy)
3976{
3977 u16 val, cnt, cnt1 ;
3978
3979 bnx2x_cl45_read(bp, phy,
3980 MDIO_PMA_DEVAD,
3981 MDIO_PMA_REG_8073_CHIP_REV, &val);
3982
3983 if (val > 0) {
3984 /* No need to workaround in 8073 A1 */
3985 return 0;
3986 }
3987 /* XAUI workaround in 8073 A0: */
3988
3989 /* After loading the boot ROM and restarting Autoneg,
3990 poll Dev1, Reg $C820: */
3991
3992 for (cnt = 0; cnt < 1000; cnt++) {
3993 bnx2x_cl45_read(bp, phy,
3994 MDIO_PMA_DEVAD,
3995 MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
3996 &val);
3997 /* If bit [14] = 0 or bit [13] = 0, continue on with
3998 system initialization (XAUI work-around not required,
3999 as these bits indicate 2.5G or 1G link up). */
4000 if (!(val & (1<<14)) || !(val & (1<<13))) {
4001 DP(NETIF_MSG_LINK, "XAUI work-around not required\n");
4002 return 0;
4003 } else if (!(val & (1<<15))) {
4004 DP(NETIF_MSG_LINK, "clc bit 15 went off\n");
4005 /* If bit 15 is 0, then poll Dev1, Reg $C841 until
4006 it's MSB (bit 15) goes to 1 (indicating that the
4007 XAUI workaround has completed),
4008 then continue on with system initialization.*/
4009 for (cnt1 = 0; cnt1 < 1000; cnt1++) {
4010 bnx2x_cl45_read(bp, phy,
4011 MDIO_PMA_DEVAD,
4012 MDIO_PMA_REG_8073_XAUI_WA, &val);
4013 if (val & (1<<15)) {
4014 DP(NETIF_MSG_LINK,
4015 "XAUI workaround has completed\n");
4016 return 0;
4017 }
4018 msleep(3);
4019 }
4020 break;
4021 }
4022 msleep(3);
4023 }
4024 DP(NETIF_MSG_LINK, "Warning: XAUI work-around timeout !!!\n");
4025 return -EINVAL;
4026}
4027
4028static void bnx2x_807x_force_10G(struct bnx2x *bp, struct bnx2x_phy *phy)
4029{
4030 /* Force KR or KX */
4031 bnx2x_cl45_write(bp, phy,
4032 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x2040);
4033 bnx2x_cl45_write(bp, phy,
4034 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0x000b);
4035 bnx2x_cl45_write(bp, phy,
4036 MDIO_PMA_DEVAD, MDIO_PMA_REG_BCM_CTRL, 0x0000);
4037 bnx2x_cl45_write(bp, phy,
4038 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x0000);
4039}
4040
4041static void bnx2x_8073_set_pause_cl37(struct link_params *params,
4042 struct bnx2x_phy *phy,
4043 struct link_vars *vars)
4044{
4045 u16 cl37_val;
4046 struct bnx2x *bp = params->bp;
4047 bnx2x_cl45_read(bp, phy,
4048 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, &cl37_val);
4049
4050 cl37_val &= ~MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
4051 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
4052 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
4053 if ((vars->ieee_fc &
4054 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) ==
4055 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) {
4056 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC;
4057 }
4058 if ((vars->ieee_fc &
4059 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
4060 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
4061 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
4062 }
4063 if ((vars->ieee_fc &
4064 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
4065 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
4066 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
4067 }
4068 DP(NETIF_MSG_LINK,
4069 "Ext phy AN advertize cl37 0x%x\n", cl37_val);
4070
4071 bnx2x_cl45_write(bp, phy,
4072 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, cl37_val);
4073 msleep(500);
4074}
4075
4076static u8 bnx2x_8073_config_init(struct bnx2x_phy *phy,
4077 struct link_params *params,
4078 struct link_vars *vars)
4079{
4080 struct bnx2x *bp = params->bp;
4081 u16 val = 0, tmp1;
4082 u8 gpio_port;
4083 DP(NETIF_MSG_LINK, "Init 8073\n");
4084
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00004085 if (CHIP_IS_E2(bp))
4086 gpio_port = BP_PATH(bp);
4087 else
4088 gpio_port = params->port;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004089 /* Restore normal power mode*/
4090 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
4091 MISC_REGISTERS_GPIO_OUTPUT_HIGH, gpio_port);
4092
4093 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
4094 MISC_REGISTERS_GPIO_OUTPUT_HIGH, gpio_port);
4095
4096 /* enable LASI */
4097 bnx2x_cl45_write(bp, phy,
4098 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL, (1<<2));
4099 bnx2x_cl45_write(bp, phy,
4100 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x0004);
4101
4102 bnx2x_8073_set_pause_cl37(params, phy, vars);
4103
4104 bnx2x_8073_set_xaui_low_power_mode(bp, phy);
4105
4106 bnx2x_cl45_read(bp, phy,
4107 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &tmp1);
4108
4109 bnx2x_cl45_read(bp, phy,
4110 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &tmp1);
4111
4112 DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1): 0x%x\n", tmp1);
4113
4114 /* Enable CL37 BAM */
Yaniv Rosner121839b2010-11-01 05:32:38 +00004115 if (REG_RD(bp, params->shmem_base +
4116 offsetof(struct shmem_region, dev_info.
4117 port_hw_config[params->port].default_cfg)) &
4118 PORT_HW_CFG_ENABLE_BAM_ON_KR_ENABLED) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004119
Yaniv Rosner121839b2010-11-01 05:32:38 +00004120 bnx2x_cl45_read(bp, phy,
4121 MDIO_AN_DEVAD,
4122 MDIO_AN_REG_8073_BAM, &val);
4123 bnx2x_cl45_write(bp, phy,
4124 MDIO_AN_DEVAD,
4125 MDIO_AN_REG_8073_BAM, val | 1);
4126 DP(NETIF_MSG_LINK, "Enable CL37 BAM on KR\n");
4127 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004128 if (params->loopback_mode == LOOPBACK_EXT) {
4129 bnx2x_807x_force_10G(bp, phy);
4130 DP(NETIF_MSG_LINK, "Forced speed 10G on 807X\n");
4131 return 0;
4132 } else {
4133 bnx2x_cl45_write(bp, phy,
4134 MDIO_PMA_DEVAD, MDIO_PMA_REG_BCM_CTRL, 0x0002);
4135 }
4136 if (phy->req_line_speed != SPEED_AUTO_NEG) {
4137 if (phy->req_line_speed == SPEED_10000) {
4138 val = (1<<7);
4139 } else if (phy->req_line_speed == SPEED_2500) {
4140 val = (1<<5);
4141 /* Note that 2.5G works only
4142 when used with 1G advertisment */
4143 } else
4144 val = (1<<5);
4145 } else {
4146 val = 0;
4147 if (phy->speed_cap_mask &
4148 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
4149 val |= (1<<7);
4150
4151 /* Note that 2.5G works only when
4152 used with 1G advertisment */
4153 if (phy->speed_cap_mask &
4154 (PORT_HW_CFG_SPEED_CAPABILITY_D0_1G |
4155 PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G))
4156 val |= (1<<5);
4157 DP(NETIF_MSG_LINK, "807x autoneg val = 0x%x\n", val);
4158 }
4159
4160 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV, val);
4161 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_8073_2_5G, &tmp1);
4162
4163 if (((phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G) &&
4164 (phy->req_line_speed == SPEED_AUTO_NEG)) ||
4165 (phy->req_line_speed == SPEED_2500)) {
4166 u16 phy_ver;
4167 /* Allow 2.5G for A1 and above */
4168 bnx2x_cl45_read(bp, phy,
4169 MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_CHIP_REV,
4170 &phy_ver);
4171 DP(NETIF_MSG_LINK, "Add 2.5G\n");
4172 if (phy_ver > 0)
4173 tmp1 |= 1;
4174 else
4175 tmp1 &= 0xfffe;
4176 } else {
4177 DP(NETIF_MSG_LINK, "Disable 2.5G\n");
4178 tmp1 &= 0xfffe;
4179 }
4180
4181 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_8073_2_5G, tmp1);
4182 /* Add support for CL37 (passive mode) II */
4183
4184 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, &tmp1);
4185 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD,
4186 (tmp1 | ((phy->req_duplex == DUPLEX_FULL) ?
4187 0x20 : 0x40)));
4188
4189 /* Add support for CL37 (passive mode) III */
4190 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
4191
4192 /* The SNR will improve about 2db by changing
4193 BW and FEE main tap. Rest commands are executed
4194 after link is up*/
4195 if (bnx2x_8073_is_snr_needed(bp, phy))
4196 bnx2x_cl45_write(bp, phy,
4197 MDIO_PMA_DEVAD, MDIO_PMA_REG_EDC_FFE_MAIN,
4198 0xFB0C);
4199
4200 /* Enable FEC (Forware Error Correction) Request in the AN */
4201 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV2, &tmp1);
4202 tmp1 |= (1<<15);
4203 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV2, tmp1);
4204
4205 bnx2x_ext_phy_set_pause(params, phy, vars);
4206
4207 /* Restart autoneg */
4208 msleep(500);
4209 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
4210 DP(NETIF_MSG_LINK, "807x Autoneg Restart: Advertise 1G=%x, 10G=%x\n",
4211 ((val & (1<<5)) > 0), ((val & (1<<7)) > 0));
4212 return 0;
4213}
4214
4215static u8 bnx2x_8073_read_status(struct bnx2x_phy *phy,
4216 struct link_params *params,
4217 struct link_vars *vars)
4218{
4219 struct bnx2x *bp = params->bp;
4220 u8 link_up = 0;
4221 u16 val1, val2;
4222 u16 link_status = 0;
4223 u16 an1000_status = 0;
4224
4225 bnx2x_cl45_read(bp, phy,
4226 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
4227
4228 DP(NETIF_MSG_LINK, "8703 LASI status 0x%x\n", val1);
4229
4230 /* clear the interrupt LASI status register */
4231 bnx2x_cl45_read(bp, phy,
4232 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val2);
4233 bnx2x_cl45_read(bp, phy,
4234 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val1);
4235 DP(NETIF_MSG_LINK, "807x PCS status 0x%x->0x%x\n", val2, val1);
4236 /* Clear MSG-OUT */
4237 bnx2x_cl45_read(bp, phy,
4238 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &val1);
4239
4240 /* Check the LASI */
4241 bnx2x_cl45_read(bp, phy,
4242 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &val2);
4243
4244 DP(NETIF_MSG_LINK, "KR 0x9003 0x%x\n", val2);
4245
4246 /* Check the link status */
4247 bnx2x_cl45_read(bp, phy,
4248 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val2);
4249 DP(NETIF_MSG_LINK, "KR PCS status 0x%x\n", val2);
4250
4251 bnx2x_cl45_read(bp, phy,
4252 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
4253 bnx2x_cl45_read(bp, phy,
4254 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
4255 link_up = ((val1 & 4) == 4);
4256 DP(NETIF_MSG_LINK, "PMA_REG_STATUS=0x%x\n", val1);
4257
4258 if (link_up &&
4259 ((phy->req_line_speed != SPEED_10000))) {
4260 if (bnx2x_8073_xaui_wa(bp, phy) != 0)
4261 return 0;
4262 }
4263 bnx2x_cl45_read(bp, phy,
4264 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &an1000_status);
4265 bnx2x_cl45_read(bp, phy,
4266 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &an1000_status);
4267
4268 /* Check the link status on 1.1.2 */
4269 bnx2x_cl45_read(bp, phy,
4270 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
4271 bnx2x_cl45_read(bp, phy,
4272 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
4273 DP(NETIF_MSG_LINK, "KR PMA status 0x%x->0x%x,"
4274 "an_link_status=0x%x\n", val2, val1, an1000_status);
4275
4276 link_up = (((val1 & 4) == 4) || (an1000_status & (1<<1)));
4277 if (link_up && bnx2x_8073_is_snr_needed(bp, phy)) {
4278 /* The SNR will improve about 2dbby
4279 changing the BW and FEE main tap.*/
4280 /* The 1st write to change FFE main
4281 tap is set before restart AN */
4282 /* Change PLL Bandwidth in EDC
4283 register */
4284 bnx2x_cl45_write(bp, phy,
4285 MDIO_PMA_DEVAD, MDIO_PMA_REG_PLL_BANDWIDTH,
4286 0x26BC);
4287
4288 /* Change CDR Bandwidth in EDC register */
4289 bnx2x_cl45_write(bp, phy,
4290 MDIO_PMA_DEVAD, MDIO_PMA_REG_CDR_BANDWIDTH,
4291 0x0333);
4292 }
4293 bnx2x_cl45_read(bp, phy,
4294 MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
4295 &link_status);
4296
4297 /* Bits 0..2 --> speed detected, bits 13..15--> link is down */
4298 if ((link_status & (1<<2)) && (!(link_status & (1<<15)))) {
4299 link_up = 1;
4300 vars->line_speed = SPEED_10000;
4301 DP(NETIF_MSG_LINK, "port %x: External link up in 10G\n",
4302 params->port);
4303 } else if ((link_status & (1<<1)) && (!(link_status & (1<<14)))) {
4304 link_up = 1;
4305 vars->line_speed = SPEED_2500;
4306 DP(NETIF_MSG_LINK, "port %x: External link up in 2.5G\n",
4307 params->port);
4308 } else if ((link_status & (1<<0)) && (!(link_status & (1<<13)))) {
4309 link_up = 1;
4310 vars->line_speed = SPEED_1000;
4311 DP(NETIF_MSG_LINK, "port %x: External link up in 1G\n",
4312 params->port);
4313 } else {
4314 link_up = 0;
4315 DP(NETIF_MSG_LINK, "port %x: External link is down\n",
4316 params->port);
4317 }
4318
4319 if (link_up) {
4320 bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
4321 bnx2x_8073_resolve_fc(phy, params, vars);
4322 }
4323 return link_up;
4324}
4325
4326static void bnx2x_8073_link_reset(struct bnx2x_phy *phy,
4327 struct link_params *params)
4328{
4329 struct bnx2x *bp = params->bp;
4330 u8 gpio_port;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00004331 if (CHIP_IS_E2(bp))
4332 gpio_port = BP_PATH(bp);
4333 else
4334 gpio_port = params->port;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004335 DP(NETIF_MSG_LINK, "Setting 8073 port %d into low power mode\n",
4336 gpio_port);
4337 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
4338 MISC_REGISTERS_GPIO_OUTPUT_LOW,
4339 gpio_port);
4340}
4341
4342/******************************************************************/
4343/* BCM8705 PHY SECTION */
4344/******************************************************************/
4345static u8 bnx2x_8705_config_init(struct bnx2x_phy *phy,
4346 struct link_params *params,
4347 struct link_vars *vars)
4348{
4349 struct bnx2x *bp = params->bp;
4350 DP(NETIF_MSG_LINK, "init 8705\n");
4351 /* Restore normal power mode*/
4352 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
4353 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
4354 /* HW reset */
4355 bnx2x_ext_phy_hw_reset(bp, params->port);
4356 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0xa040);
4357 bnx2x_wait_reset_complete(bp, phy);
4358
4359 bnx2x_cl45_write(bp, phy,
4360 MDIO_PMA_DEVAD, MDIO_PMA_REG_MISC_CTRL, 0x8288);
4361 bnx2x_cl45_write(bp, phy,
4362 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, 0x7fbf);
4363 bnx2x_cl45_write(bp, phy,
4364 MDIO_PMA_DEVAD, MDIO_PMA_REG_CMU_PLL_BYPASS, 0x0100);
4365 bnx2x_cl45_write(bp, phy,
4366 MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_CNTL, 0x1);
4367 /* BCM8705 doesn't have microcode, hence the 0 */
4368 bnx2x_save_spirom_version(bp, params->port, params->shmem_base, 0);
4369 return 0;
4370}
4371
4372static u8 bnx2x_8705_read_status(struct bnx2x_phy *phy,
4373 struct link_params *params,
4374 struct link_vars *vars)
4375{
4376 u8 link_up = 0;
4377 u16 val1, rx_sd;
4378 struct bnx2x *bp = params->bp;
4379 DP(NETIF_MSG_LINK, "read status 8705\n");
4380 bnx2x_cl45_read(bp, phy,
4381 MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_STATUS, &val1);
4382 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
4383
4384 bnx2x_cl45_read(bp, phy,
4385 MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_STATUS, &val1);
4386 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
4387
4388 bnx2x_cl45_read(bp, phy,
4389 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD, &rx_sd);
4390
4391 bnx2x_cl45_read(bp, phy,
4392 MDIO_PMA_DEVAD, 0xc809, &val1);
4393 bnx2x_cl45_read(bp, phy,
4394 MDIO_PMA_DEVAD, 0xc809, &val1);
4395
4396 DP(NETIF_MSG_LINK, "8705 1.c809 val=0x%x\n", val1);
4397 link_up = ((rx_sd & 0x1) && (val1 & (1<<9)) && ((val1 & (1<<8)) == 0));
4398 if (link_up) {
4399 vars->line_speed = SPEED_10000;
4400 bnx2x_ext_phy_resolve_fc(phy, params, vars);
4401 }
4402 return link_up;
4403}
4404
4405/******************************************************************/
4406/* SFP+ module Section */
4407/******************************************************************/
4408static void bnx2x_sfp_set_transmitter(struct bnx2x *bp,
4409 struct bnx2x_phy *phy,
4410 u8 port,
4411 u8 tx_en)
4412{
4413 u16 val;
4414
4415 DP(NETIF_MSG_LINK, "Setting transmitter tx_en=%x for port %x\n",
4416 tx_en, port);
4417 /* Disable/Enable transmitter ( TX laser of the SFP+ module.)*/
4418 bnx2x_cl45_read(bp, phy,
4419 MDIO_PMA_DEVAD,
4420 MDIO_PMA_REG_PHY_IDENTIFIER,
4421 &val);
4422
4423 if (tx_en)
4424 val &= ~(1<<15);
4425 else
4426 val |= (1<<15);
4427
4428 bnx2x_cl45_write(bp, phy,
4429 MDIO_PMA_DEVAD,
4430 MDIO_PMA_REG_PHY_IDENTIFIER,
4431 val);
4432}
4433
4434static u8 bnx2x_8726_read_sfp_module_eeprom(struct bnx2x_phy *phy,
4435 struct link_params *params,
4436 u16 addr, u8 byte_cnt, u8 *o_buf)
4437{
4438 struct bnx2x *bp = params->bp;
4439 u16 val = 0;
4440 u16 i;
4441 if (byte_cnt > 16) {
4442 DP(NETIF_MSG_LINK, "Reading from eeprom is"
4443 " is limited to 0xf\n");
4444 return -EINVAL;
4445 }
4446 /* Set the read command byte count */
4447 bnx2x_cl45_write(bp, phy,
4448 MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
4449 (byte_cnt | 0xa000));
4450
4451 /* Set the read command address */
4452 bnx2x_cl45_write(bp, phy,
4453 MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
4454 addr);
4455
4456 /* Activate read command */
4457 bnx2x_cl45_write(bp, phy,
4458 MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
4459 0x2c0f);
4460
4461 /* Wait up to 500us for command complete status */
4462 for (i = 0; i < 100; i++) {
4463 bnx2x_cl45_read(bp, phy,
4464 MDIO_PMA_DEVAD,
4465 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
4466 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
4467 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
4468 break;
4469 udelay(5);
4470 }
4471
4472 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
4473 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
4474 DP(NETIF_MSG_LINK,
4475 "Got bad status 0x%x when reading from SFP+ EEPROM\n",
4476 (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
4477 return -EINVAL;
4478 }
4479
4480 /* Read the buffer */
4481 for (i = 0; i < byte_cnt; i++) {
4482 bnx2x_cl45_read(bp, phy,
4483 MDIO_PMA_DEVAD,
4484 MDIO_PMA_REG_8726_TWO_WIRE_DATA_BUF + i, &val);
4485 o_buf[i] = (u8)(val & MDIO_PMA_REG_8726_TWO_WIRE_DATA_MASK);
4486 }
4487
4488 for (i = 0; i < 100; i++) {
4489 bnx2x_cl45_read(bp, phy,
4490 MDIO_PMA_DEVAD,
4491 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
4492 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
4493 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
Joe Perches6f38ad92010-11-14 17:04:31 +00004494 return 0;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004495 msleep(1);
4496 }
4497 return -EINVAL;
4498}
4499
4500static u8 bnx2x_8727_read_sfp_module_eeprom(struct bnx2x_phy *phy,
4501 struct link_params *params,
4502 u16 addr, u8 byte_cnt, u8 *o_buf)
4503{
4504 struct bnx2x *bp = params->bp;
4505 u16 val, i;
4506
4507 if (byte_cnt > 16) {
4508 DP(NETIF_MSG_LINK, "Reading from eeprom is"
4509 " is limited to 0xf\n");
4510 return -EINVAL;
4511 }
4512
4513 /* Need to read from 1.8000 to clear it */
4514 bnx2x_cl45_read(bp, phy,
4515 MDIO_PMA_DEVAD,
4516 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
4517 &val);
4518
4519 /* Set the read command byte count */
4520 bnx2x_cl45_write(bp, phy,
4521 MDIO_PMA_DEVAD,
4522 MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
4523 ((byte_cnt < 2) ? 2 : byte_cnt));
4524
4525 /* Set the read command address */
4526 bnx2x_cl45_write(bp, phy,
4527 MDIO_PMA_DEVAD,
4528 MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
4529 addr);
4530 /* Set the destination address */
4531 bnx2x_cl45_write(bp, phy,
4532 MDIO_PMA_DEVAD,
4533 0x8004,
4534 MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF);
4535
4536 /* Activate read command */
4537 bnx2x_cl45_write(bp, phy,
4538 MDIO_PMA_DEVAD,
4539 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
4540 0x8002);
4541 /* Wait appropriate time for two-wire command to finish before
4542 polling the status register */
4543 msleep(1);
4544
4545 /* Wait up to 500us for command complete status */
4546 for (i = 0; i < 100; i++) {
4547 bnx2x_cl45_read(bp, phy,
4548 MDIO_PMA_DEVAD,
4549 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
4550 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
4551 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
4552 break;
4553 udelay(5);
4554 }
4555
4556 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
4557 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
4558 DP(NETIF_MSG_LINK,
4559 "Got bad status 0x%x when reading from SFP+ EEPROM\n",
4560 (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
4561 return -EINVAL;
4562 }
4563
4564 /* Read the buffer */
4565 for (i = 0; i < byte_cnt; i++) {
4566 bnx2x_cl45_read(bp, phy,
4567 MDIO_PMA_DEVAD,
4568 MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF + i, &val);
4569 o_buf[i] = (u8)(val & MDIO_PMA_REG_8727_TWO_WIRE_DATA_MASK);
4570 }
4571
4572 for (i = 0; i < 100; i++) {
4573 bnx2x_cl45_read(bp, phy,
4574 MDIO_PMA_DEVAD,
4575 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
4576 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
4577 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
Joe Perches6f38ad92010-11-14 17:04:31 +00004578 return 0;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004579 msleep(1);
4580 }
4581
4582 return -EINVAL;
4583}
4584
stephen hemminger8d962862010-10-21 07:50:56 +00004585static u8 bnx2x_read_sfp_module_eeprom(struct bnx2x_phy *phy,
4586 struct link_params *params, u16 addr,
4587 u8 byte_cnt, u8 *o_buf)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004588{
4589 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
4590 return bnx2x_8726_read_sfp_module_eeprom(phy, params, addr,
4591 byte_cnt, o_buf);
4592 else if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
4593 return bnx2x_8727_read_sfp_module_eeprom(phy, params, addr,
4594 byte_cnt, o_buf);
4595 return -EINVAL;
4596}
4597
4598static u8 bnx2x_get_edc_mode(struct bnx2x_phy *phy,
4599 struct link_params *params,
4600 u16 *edc_mode)
4601{
4602 struct bnx2x *bp = params->bp;
4603 u8 val, check_limiting_mode = 0;
4604 *edc_mode = EDC_MODE_LIMITING;
4605
4606 /* First check for copper cable */
4607 if (bnx2x_read_sfp_module_eeprom(phy,
4608 params,
4609 SFP_EEPROM_CON_TYPE_ADDR,
4610 1,
4611 &val) != 0) {
4612 DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM\n");
4613 return -EINVAL;
4614 }
4615
4616 switch (val) {
4617 case SFP_EEPROM_CON_TYPE_VAL_COPPER:
4618 {
4619 u8 copper_module_type;
4620
4621 /* Check if its active cable( includes SFP+ module)
4622 of passive cable*/
4623 if (bnx2x_read_sfp_module_eeprom(phy,
4624 params,
4625 SFP_EEPROM_FC_TX_TECH_ADDR,
4626 1,
4627 &copper_module_type) !=
4628 0) {
4629 DP(NETIF_MSG_LINK,
4630 "Failed to read copper-cable-type"
4631 " from SFP+ EEPROM\n");
4632 return -EINVAL;
4633 }
4634
4635 if (copper_module_type &
4636 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE) {
4637 DP(NETIF_MSG_LINK, "Active Copper cable detected\n");
4638 check_limiting_mode = 1;
4639 } else if (copper_module_type &
4640 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE) {
4641 DP(NETIF_MSG_LINK, "Passive Copper"
4642 " cable detected\n");
4643 *edc_mode =
4644 EDC_MODE_PASSIVE_DAC;
4645 } else {
4646 DP(NETIF_MSG_LINK, "Unknown copper-cable-"
4647 "type 0x%x !!!\n", copper_module_type);
4648 return -EINVAL;
4649 }
4650 break;
4651 }
4652 case SFP_EEPROM_CON_TYPE_VAL_LC:
4653 DP(NETIF_MSG_LINK, "Optic module detected\n");
4654 check_limiting_mode = 1;
4655 break;
4656 default:
4657 DP(NETIF_MSG_LINK, "Unable to determine module type 0x%x !!!\n",
4658 val);
4659 return -EINVAL;
4660 }
4661
4662 if (check_limiting_mode) {
4663 u8 options[SFP_EEPROM_OPTIONS_SIZE];
4664 if (bnx2x_read_sfp_module_eeprom(phy,
4665 params,
4666 SFP_EEPROM_OPTIONS_ADDR,
4667 SFP_EEPROM_OPTIONS_SIZE,
4668 options) != 0) {
4669 DP(NETIF_MSG_LINK, "Failed to read Option"
4670 " field from module EEPROM\n");
4671 return -EINVAL;
4672 }
4673 if ((options[0] & SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK))
4674 *edc_mode = EDC_MODE_LINEAR;
4675 else
4676 *edc_mode = EDC_MODE_LIMITING;
4677 }
4678 DP(NETIF_MSG_LINK, "EDC mode is set to 0x%x\n", *edc_mode);
4679 return 0;
4680}
4681/* This function read the relevant field from the module ( SFP+ ),
4682 and verify it is compliant with this board */
4683static u8 bnx2x_verify_sfp_module(struct bnx2x_phy *phy,
4684 struct link_params *params)
4685{
4686 struct bnx2x *bp = params->bp;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004687 u32 val, cmd;
4688 u32 fw_resp, fw_cmd_param;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004689 char vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE+1];
4690 char vendor_pn[SFP_EEPROM_PART_NO_SIZE+1];
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004691 phy->flags &= ~FLAGS_SFP_NOT_APPROVED;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004692 val = REG_RD(bp, params->shmem_base +
4693 offsetof(struct shmem_region, dev_info.
4694 port_feature_config[params->port].config));
4695 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
4696 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_NO_ENFORCEMENT) {
4697 DP(NETIF_MSG_LINK, "NOT enforcing module verification\n");
4698 return 0;
4699 }
4700
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004701 if (params->feature_config_flags &
4702 FEATURE_CONFIG_BC_SUPPORTS_DUAL_PHY_OPT_MDL_VRFY) {
4703 /* Use specific phy request */
4704 cmd = DRV_MSG_CODE_VRFY_SPECIFIC_PHY_OPT_MDL;
4705 } else if (params->feature_config_flags &
4706 FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY) {
4707 /* Use first phy request only in case of non-dual media*/
4708 if (DUAL_MEDIA(params)) {
4709 DP(NETIF_MSG_LINK, "FW does not support OPT MDL "
4710 "verification\n");
4711 return -EINVAL;
4712 }
4713 cmd = DRV_MSG_CODE_VRFY_FIRST_PHY_OPT_MDL;
4714 } else {
4715 /* No support in OPT MDL detection */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004716 DP(NETIF_MSG_LINK, "FW does not support OPT MDL "
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004717 "verification\n");
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004718 return -EINVAL;
4719 }
Dmitry Kravkov523224a2010-10-06 03:23:26 +00004720
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004721 fw_cmd_param = FW_PARAM_SET(phy->addr, phy->type, phy->mdio_ctrl);
4722 fw_resp = bnx2x_fw_command(bp, cmd, fw_cmd_param);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004723 if (fw_resp == FW_MSG_CODE_VRFY_OPT_MDL_SUCCESS) {
4724 DP(NETIF_MSG_LINK, "Approved module\n");
4725 return 0;
4726 }
4727
4728 /* format the warning message */
4729 if (bnx2x_read_sfp_module_eeprom(phy,
4730 params,
4731 SFP_EEPROM_VENDOR_NAME_ADDR,
4732 SFP_EEPROM_VENDOR_NAME_SIZE,
4733 (u8 *)vendor_name))
4734 vendor_name[0] = '\0';
4735 else
4736 vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE] = '\0';
4737 if (bnx2x_read_sfp_module_eeprom(phy,
4738 params,
4739 SFP_EEPROM_PART_NO_ADDR,
4740 SFP_EEPROM_PART_NO_SIZE,
4741 (u8 *)vendor_pn))
4742 vendor_pn[0] = '\0';
4743 else
4744 vendor_pn[SFP_EEPROM_PART_NO_SIZE] = '\0';
4745
4746 netdev_info(bp->dev, "Warning: Unqualified SFP+ module detected,"
4747 " Port %d from %s part number %s\n",
4748 params->port, vendor_name, vendor_pn);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004749 phy->flags |= FLAGS_SFP_NOT_APPROVED;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004750 return -EINVAL;
4751}
4752
4753static u8 bnx2x_wait_for_sfp_module_initialized(struct bnx2x_phy *phy,
4754 struct link_params *params)
4755
4756{
4757 u8 val;
4758 struct bnx2x *bp = params->bp;
4759 u16 timeout;
4760 /* Initialization time after hot-plug may take up to 300ms for some
4761 phys type ( e.g. JDSU ) */
4762 for (timeout = 0; timeout < 60; timeout++) {
4763 if (bnx2x_read_sfp_module_eeprom(phy, params, 1, 1, &val)
4764 == 0) {
4765 DP(NETIF_MSG_LINK, "SFP+ module initialization "
4766 "took %d ms\n", timeout * 5);
4767 return 0;
4768 }
4769 msleep(5);
4770 }
4771 return -EINVAL;
4772}
4773
4774static void bnx2x_8727_power_module(struct bnx2x *bp,
4775 struct bnx2x_phy *phy,
4776 u8 is_power_up) {
4777 /* Make sure GPIOs are not using for LED mode */
4778 u16 val;
4779 /*
4780 * In the GPIO register, bit 4 is use to detemine if the GPIOs are
4781 * operating as INPUT or as OUTPUT. Bit 1 is for input, and 0 for
4782 * output
4783 * Bits 0-1 determine the gpios value for OUTPUT in case bit 4 val is 0
4784 * Bits 8-9 determine the gpios value for INPUT in case bit 4 val is 1
4785 * where the 1st bit is the over-current(only input), and 2nd bit is
4786 * for power( only output )
4787 */
4788
4789 /*
4790 * In case of NOC feature is disabled and power is up, set GPIO control
4791 * as input to enable listening of over-current indication
4792 */
4793 if (phy->flags & FLAGS_NOC)
4794 return;
4795 if (!(phy->flags &
4796 FLAGS_NOC) && is_power_up)
4797 val = (1<<4);
4798 else
4799 /*
4800 * Set GPIO control to OUTPUT, and set the power bit
4801 * to according to the is_power_up
4802 */
4803 val = ((!(is_power_up)) << 1);
4804
4805 bnx2x_cl45_write(bp, phy,
4806 MDIO_PMA_DEVAD,
4807 MDIO_PMA_REG_8727_GPIO_CTRL,
4808 val);
4809}
4810
4811static u8 bnx2x_8726_set_limiting_mode(struct bnx2x *bp,
4812 struct bnx2x_phy *phy,
4813 u16 edc_mode)
4814{
4815 u16 cur_limiting_mode;
4816
4817 bnx2x_cl45_read(bp, phy,
4818 MDIO_PMA_DEVAD,
4819 MDIO_PMA_REG_ROM_VER2,
4820 &cur_limiting_mode);
4821 DP(NETIF_MSG_LINK, "Current Limiting mode is 0x%x\n",
4822 cur_limiting_mode);
4823
4824 if (edc_mode == EDC_MODE_LIMITING) {
4825 DP(NETIF_MSG_LINK,
4826 "Setting LIMITING MODE\n");
4827 bnx2x_cl45_write(bp, phy,
4828 MDIO_PMA_DEVAD,
4829 MDIO_PMA_REG_ROM_VER2,
4830 EDC_MODE_LIMITING);
4831 } else { /* LRM mode ( default )*/
4832
4833 DP(NETIF_MSG_LINK, "Setting LRM MODE\n");
4834
4835 /* Changing to LRM mode takes quite few seconds.
4836 So do it only if current mode is limiting
4837 ( default is LRM )*/
4838 if (cur_limiting_mode != EDC_MODE_LIMITING)
4839 return 0;
4840
4841 bnx2x_cl45_write(bp, phy,
4842 MDIO_PMA_DEVAD,
4843 MDIO_PMA_REG_LRM_MODE,
4844 0);
4845 bnx2x_cl45_write(bp, phy,
4846 MDIO_PMA_DEVAD,
4847 MDIO_PMA_REG_ROM_VER2,
4848 0x128);
4849 bnx2x_cl45_write(bp, phy,
4850 MDIO_PMA_DEVAD,
4851 MDIO_PMA_REG_MISC_CTRL0,
4852 0x4008);
4853 bnx2x_cl45_write(bp, phy,
4854 MDIO_PMA_DEVAD,
4855 MDIO_PMA_REG_LRM_MODE,
4856 0xaaaa);
4857 }
4858 return 0;
4859}
4860
4861static u8 bnx2x_8727_set_limiting_mode(struct bnx2x *bp,
4862 struct bnx2x_phy *phy,
4863 u16 edc_mode)
4864{
4865 u16 phy_identifier;
4866 u16 rom_ver2_val;
4867 bnx2x_cl45_read(bp, phy,
4868 MDIO_PMA_DEVAD,
4869 MDIO_PMA_REG_PHY_IDENTIFIER,
4870 &phy_identifier);
4871
4872 bnx2x_cl45_write(bp, phy,
4873 MDIO_PMA_DEVAD,
4874 MDIO_PMA_REG_PHY_IDENTIFIER,
4875 (phy_identifier & ~(1<<9)));
4876
4877 bnx2x_cl45_read(bp, phy,
4878 MDIO_PMA_DEVAD,
4879 MDIO_PMA_REG_ROM_VER2,
4880 &rom_ver2_val);
4881 /* Keep the MSB 8-bits, and set the LSB 8-bits with the edc_mode */
4882 bnx2x_cl45_write(bp, phy,
4883 MDIO_PMA_DEVAD,
4884 MDIO_PMA_REG_ROM_VER2,
4885 (rom_ver2_val & 0xff00) | (edc_mode & 0x00ff));
4886
4887 bnx2x_cl45_write(bp, phy,
4888 MDIO_PMA_DEVAD,
4889 MDIO_PMA_REG_PHY_IDENTIFIER,
4890 (phy_identifier | (1<<9)));
4891
4892 return 0;
4893}
4894
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004895static void bnx2x_8727_specific_func(struct bnx2x_phy *phy,
4896 struct link_params *params,
4897 u32 action)
4898{
4899 struct bnx2x *bp = params->bp;
4900
4901 switch (action) {
4902 case DISABLE_TX:
4903 bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
4904 break;
4905 case ENABLE_TX:
4906 if (!(phy->flags & FLAGS_SFP_NOT_APPROVED))
4907 bnx2x_sfp_set_transmitter(bp, phy, params->port, 1);
4908 break;
4909 default:
4910 DP(NETIF_MSG_LINK, "Function 0x%x not supported by 8727\n",
4911 action);
4912 return;
4913 }
4914}
4915
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004916static u8 bnx2x_sfp_module_detection(struct bnx2x_phy *phy,
4917 struct link_params *params)
4918{
4919 struct bnx2x *bp = params->bp;
4920 u16 edc_mode;
4921 u8 rc = 0;
4922
4923 u32 val = REG_RD(bp, params->shmem_base +
4924 offsetof(struct shmem_region, dev_info.
4925 port_feature_config[params->port].config));
4926
4927 DP(NETIF_MSG_LINK, "SFP+ module plugged in/out detected on port %d\n",
4928 params->port);
4929
4930 if (bnx2x_get_edc_mode(phy, params, &edc_mode) != 0) {
4931 DP(NETIF_MSG_LINK, "Failed to get valid module type\n");
4932 return -EINVAL;
4933 } else if (bnx2x_verify_sfp_module(phy, params) !=
4934 0) {
4935 /* check SFP+ module compatibility */
4936 DP(NETIF_MSG_LINK, "Module verification failed!!\n");
4937 rc = -EINVAL;
4938 /* Turn on fault module-detected led */
4939 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
4940 MISC_REGISTERS_GPIO_HIGH,
4941 params->port);
4942 if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) &&
4943 ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
4944 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_POWER_DOWN)) {
4945 /* Shutdown SFP+ module */
4946 DP(NETIF_MSG_LINK, "Shutdown SFP+ module!!\n");
4947 bnx2x_8727_power_module(bp, phy, 0);
4948 return rc;
4949 }
4950 } else {
4951 /* Turn off fault module-detected led */
4952 DP(NETIF_MSG_LINK, "Turn off fault module-detected led\n");
4953 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
4954 MISC_REGISTERS_GPIO_LOW,
4955 params->port);
4956 }
4957
4958 /* power up the SFP module */
4959 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
4960 bnx2x_8727_power_module(bp, phy, 1);
4961
4962 /* Check and set limiting mode / LRM mode on 8726.
4963 On 8727 it is done automatically */
4964 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
4965 bnx2x_8726_set_limiting_mode(bp, phy, edc_mode);
4966 else
4967 bnx2x_8727_set_limiting_mode(bp, phy, edc_mode);
4968 /*
4969 * Enable transmit for this module if the module is approved, or
4970 * if unapproved modules should also enable the Tx laser
4971 */
4972 if (rc == 0 ||
4973 (val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) !=
4974 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
4975 bnx2x_sfp_set_transmitter(bp, phy, params->port, 1);
4976 else
4977 bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
4978
4979 return rc;
4980}
4981
4982void bnx2x_handle_module_detect_int(struct link_params *params)
4983{
4984 struct bnx2x *bp = params->bp;
4985 struct bnx2x_phy *phy = &params->phy[EXT_PHY1];
4986 u32 gpio_val;
4987 u8 port = params->port;
4988
4989 /* Set valid module led off */
4990 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
4991 MISC_REGISTERS_GPIO_HIGH,
4992 params->port);
4993
4994 /* Get current gpio val refelecting module plugged in / out*/
4995 gpio_val = bnx2x_get_gpio(bp, MISC_REGISTERS_GPIO_3, port);
4996
4997 /* Call the handling function in case module is detected */
4998 if (gpio_val == 0) {
4999
5000 bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
5001 MISC_REGISTERS_GPIO_INT_OUTPUT_CLR,
5002 port);
5003
5004 if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0)
5005 bnx2x_sfp_module_detection(phy, params);
5006 else
5007 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
5008 } else {
5009 u32 val = REG_RD(bp, params->shmem_base +
5010 offsetof(struct shmem_region, dev_info.
5011 port_feature_config[params->port].
5012 config));
5013
5014 bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
5015 MISC_REGISTERS_GPIO_INT_OUTPUT_SET,
5016 port);
5017 /* Module was plugged out. */
5018 /* Disable transmit for this module */
5019 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
5020 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
5021 bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
5022 }
5023}
5024
5025/******************************************************************/
5026/* common BCM8706/BCM8726 PHY SECTION */
5027/******************************************************************/
5028static u8 bnx2x_8706_8726_read_status(struct bnx2x_phy *phy,
5029 struct link_params *params,
5030 struct link_vars *vars)
5031{
5032 u8 link_up = 0;
5033 u16 val1, val2, rx_sd, pcs_status;
5034 struct bnx2x *bp = params->bp;
5035 DP(NETIF_MSG_LINK, "XGXS 8706/8726\n");
5036 /* Clear RX Alarm*/
5037 bnx2x_cl45_read(bp, phy,
5038 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &val2);
5039 /* clear LASI indication*/
5040 bnx2x_cl45_read(bp, phy,
5041 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
5042 bnx2x_cl45_read(bp, phy,
5043 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val2);
5044 DP(NETIF_MSG_LINK, "8706/8726 LASI status 0x%x--> 0x%x\n", val1, val2);
5045
5046 bnx2x_cl45_read(bp, phy,
5047 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD, &rx_sd);
5048 bnx2x_cl45_read(bp, phy,
5049 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &pcs_status);
5050 bnx2x_cl45_read(bp, phy,
5051 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &val2);
5052 bnx2x_cl45_read(bp, phy,
5053 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &val2);
5054
5055 DP(NETIF_MSG_LINK, "8706/8726 rx_sd 0x%x pcs_status 0x%x 1Gbps"
5056 " link_status 0x%x\n", rx_sd, pcs_status, val2);
5057 /* link is up if both bit 0 of pmd_rx_sd and
5058 * bit 0 of pcs_status are set, or if the autoneg bit
5059 * 1 is set
5060 */
5061 link_up = ((rx_sd & pcs_status & 0x1) || (val2 & (1<<1)));
5062 if (link_up) {
5063 if (val2 & (1<<1))
5064 vars->line_speed = SPEED_1000;
5065 else
5066 vars->line_speed = SPEED_10000;
5067 bnx2x_ext_phy_resolve_fc(phy, params, vars);
5068 }
5069 return link_up;
5070}
5071
5072/******************************************************************/
5073/* BCM8706 PHY SECTION */
5074/******************************************************************/
5075static u8 bnx2x_8706_config_init(struct bnx2x_phy *phy,
5076 struct link_params *params,
5077 struct link_vars *vars)
5078{
5079 u16 cnt, val;
5080 struct bnx2x *bp = params->bp;
5081 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
5082 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
5083 /* HW reset */
5084 bnx2x_ext_phy_hw_reset(bp, params->port);
5085 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0xa040);
5086 bnx2x_wait_reset_complete(bp, phy);
5087
5088 /* Wait until fw is loaded */
5089 for (cnt = 0; cnt < 100; cnt++) {
5090 bnx2x_cl45_read(bp, phy,
5091 MDIO_PMA_DEVAD, MDIO_PMA_REG_ROM_VER1, &val);
5092 if (val)
5093 break;
5094 msleep(10);
5095 }
5096 DP(NETIF_MSG_LINK, "XGXS 8706 is initialized after %d ms\n", cnt);
5097 if ((params->feature_config_flags &
5098 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
5099 u8 i;
5100 u16 reg;
5101 for (i = 0; i < 4; i++) {
5102 reg = MDIO_XS_8706_REG_BANK_RX0 +
5103 i*(MDIO_XS_8706_REG_BANK_RX1 -
5104 MDIO_XS_8706_REG_BANK_RX0);
5105 bnx2x_cl45_read(bp, phy, MDIO_XS_DEVAD, reg, &val);
5106 /* Clear first 3 bits of the control */
5107 val &= ~0x7;
5108 /* Set control bits according to configuration */
5109 val |= (phy->rx_preemphasis[i] & 0x7);
5110 DP(NETIF_MSG_LINK, "Setting RX Equalizer to BCM8706"
5111 " reg 0x%x <-- val 0x%x\n", reg, val);
5112 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, reg, val);
5113 }
5114 }
5115 /* Force speed */
5116 if (phy->req_line_speed == SPEED_10000) {
5117 DP(NETIF_MSG_LINK, "XGXS 8706 force 10Gbps\n");
5118
5119 bnx2x_cl45_write(bp, phy,
5120 MDIO_PMA_DEVAD,
5121 MDIO_PMA_REG_DIGITAL_CTRL, 0x400);
5122 bnx2x_cl45_write(bp, phy,
5123 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 1);
5124 } else {
5125 /* Force 1Gbps using autoneg with 1G advertisment */
5126
5127 /* Allow CL37 through CL73 */
5128 DP(NETIF_MSG_LINK, "XGXS 8706 AutoNeg\n");
5129 bnx2x_cl45_write(bp, phy,
5130 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_CL73, 0x040c);
5131
5132 /* Enable Full-Duplex advertisment on CL37 */
5133 bnx2x_cl45_write(bp, phy,
5134 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LP, 0x0020);
5135 /* Enable CL37 AN */
5136 bnx2x_cl45_write(bp, phy,
5137 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
5138 /* 1G support */
5139 bnx2x_cl45_write(bp, phy,
5140 MDIO_AN_DEVAD, MDIO_AN_REG_ADV, (1<<5));
5141
5142 /* Enable clause 73 AN */
5143 bnx2x_cl45_write(bp, phy,
5144 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
5145 bnx2x_cl45_write(bp, phy,
5146 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
5147 0x0400);
5148 bnx2x_cl45_write(bp, phy,
5149 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL,
5150 0x0004);
5151 }
5152 bnx2x_save_bcm_spirom_ver(bp, phy, params->port);
5153 return 0;
5154}
5155
5156static u8 bnx2x_8706_read_status(struct bnx2x_phy *phy,
5157 struct link_params *params,
5158 struct link_vars *vars)
5159{
5160 return bnx2x_8706_8726_read_status(phy, params, vars);
5161}
5162
5163/******************************************************************/
5164/* BCM8726 PHY SECTION */
5165/******************************************************************/
5166static void bnx2x_8726_config_loopback(struct bnx2x_phy *phy,
5167 struct link_params *params)
5168{
5169 struct bnx2x *bp = params->bp;
5170 DP(NETIF_MSG_LINK, "PMA/PMD ext_phy_loopback: 8726\n");
5171 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x0001);
5172}
5173
5174static void bnx2x_8726_external_rom_boot(struct bnx2x_phy *phy,
5175 struct link_params *params)
5176{
5177 struct bnx2x *bp = params->bp;
5178 /* Need to wait 100ms after reset */
5179 msleep(100);
5180
5181 /* Micro controller re-boot */
5182 bnx2x_cl45_write(bp, phy,
5183 MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, 0x018B);
5184
5185 /* Set soft reset */
5186 bnx2x_cl45_write(bp, phy,
5187 MDIO_PMA_DEVAD,
5188 MDIO_PMA_REG_GEN_CTRL,
5189 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
5190
5191 bnx2x_cl45_write(bp, phy,
5192 MDIO_PMA_DEVAD,
5193 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
5194
5195 bnx2x_cl45_write(bp, phy,
5196 MDIO_PMA_DEVAD,
5197 MDIO_PMA_REG_GEN_CTRL,
5198 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
5199
5200 /* wait for 150ms for microcode load */
5201 msleep(150);
5202
5203 /* Disable serial boot control, tristates pins SS_N, SCK, MOSI, MISO */
5204 bnx2x_cl45_write(bp, phy,
5205 MDIO_PMA_DEVAD,
5206 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
5207
5208 msleep(200);
5209 bnx2x_save_bcm_spirom_ver(bp, phy, params->port);
5210}
5211
5212static u8 bnx2x_8726_read_status(struct bnx2x_phy *phy,
5213 struct link_params *params,
5214 struct link_vars *vars)
5215{
5216 struct bnx2x *bp = params->bp;
5217 u16 val1;
5218 u8 link_up = bnx2x_8706_8726_read_status(phy, params, vars);
5219 if (link_up) {
5220 bnx2x_cl45_read(bp, phy,
5221 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER,
5222 &val1);
5223 if (val1 & (1<<15)) {
5224 DP(NETIF_MSG_LINK, "Tx is disabled\n");
5225 link_up = 0;
5226 vars->line_speed = 0;
5227 }
5228 }
5229 return link_up;
5230}
5231
5232
5233static u8 bnx2x_8726_config_init(struct bnx2x_phy *phy,
5234 struct link_params *params,
5235 struct link_vars *vars)
5236{
5237 struct bnx2x *bp = params->bp;
5238 u32 val;
5239 u32 swap_val, swap_override, aeu_gpio_mask, offset;
5240 DP(NETIF_MSG_LINK, "Initializing BCM8726\n");
5241 /* Restore normal power mode*/
5242 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
5243 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
5244
5245 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
5246 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
5247
5248 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
5249 bnx2x_wait_reset_complete(bp, phy);
5250
5251 bnx2x_8726_external_rom_boot(phy, params);
5252
5253 /* Need to call module detected on initialization since
5254 the module detection triggered by actual module
5255 insertion might occur before driver is loaded, and when
5256 driver is loaded, it reset all registers, including the
5257 transmitter */
5258 bnx2x_sfp_module_detection(phy, params);
5259
5260 if (phy->req_line_speed == SPEED_1000) {
5261 DP(NETIF_MSG_LINK, "Setting 1G force\n");
5262 bnx2x_cl45_write(bp, phy,
5263 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x40);
5264 bnx2x_cl45_write(bp, phy,
5265 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0xD);
5266 bnx2x_cl45_write(bp, phy,
5267 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x5);
5268 bnx2x_cl45_write(bp, phy,
5269 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
5270 0x400);
5271 } else if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
5272 (phy->speed_cap_mask &
5273 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G) &&
5274 ((phy->speed_cap_mask &
5275 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) !=
5276 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
5277 DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
5278 /* Set Flow control */
5279 bnx2x_ext_phy_set_pause(params, phy, vars);
5280 bnx2x_cl45_write(bp, phy,
5281 MDIO_AN_DEVAD, MDIO_AN_REG_ADV, 0x20);
5282 bnx2x_cl45_write(bp, phy,
5283 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_CL73, 0x040c);
5284 bnx2x_cl45_write(bp, phy,
5285 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, 0x0020);
5286 bnx2x_cl45_write(bp, phy,
5287 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
5288 bnx2x_cl45_write(bp, phy,
5289 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
5290 /* Enable RX-ALARM control to receive
5291 interrupt for 1G speed change */
5292 bnx2x_cl45_write(bp, phy,
5293 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x4);
5294 bnx2x_cl45_write(bp, phy,
5295 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
5296 0x400);
5297
5298 } else { /* Default 10G. Set only LASI control */
5299 bnx2x_cl45_write(bp, phy,
5300 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 1);
5301 }
5302
5303 /* Set TX PreEmphasis if needed */
5304 if ((params->feature_config_flags &
5305 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
5306 DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x,"
5307 "TX_CTRL2 0x%x\n",
5308 phy->tx_preemphasis[0],
5309 phy->tx_preemphasis[1]);
5310 bnx2x_cl45_write(bp, phy,
5311 MDIO_PMA_DEVAD,
5312 MDIO_PMA_REG_8726_TX_CTRL1,
5313 phy->tx_preemphasis[0]);
5314
5315 bnx2x_cl45_write(bp, phy,
5316 MDIO_PMA_DEVAD,
5317 MDIO_PMA_REG_8726_TX_CTRL2,
5318 phy->tx_preemphasis[1]);
5319 }
5320
5321 /* Set GPIO3 to trigger SFP+ module insertion/removal */
5322 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
5323 MISC_REGISTERS_GPIO_INPUT_HI_Z, params->port);
5324
5325 /* The GPIO should be swapped if the swap register is set and active */
5326 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
5327 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
5328
5329 /* Select function upon port-swap configuration */
5330 if (params->port == 0) {
5331 offset = MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0;
5332 aeu_gpio_mask = (swap_val && swap_override) ?
5333 AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_1 :
5334 AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0;
5335 } else {
5336 offset = MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0;
5337 aeu_gpio_mask = (swap_val && swap_override) ?
5338 AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0 :
5339 AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_1;
5340 }
5341 val = REG_RD(bp, offset);
5342 /* add GPIO3 to group */
5343 val |= aeu_gpio_mask;
5344 REG_WR(bp, offset, val);
5345 return 0;
5346
5347}
5348
5349static void bnx2x_8726_link_reset(struct bnx2x_phy *phy,
5350 struct link_params *params)
5351{
5352 struct bnx2x *bp = params->bp;
5353 DP(NETIF_MSG_LINK, "bnx2x_8726_link_reset port %d\n", params->port);
5354 /* Set serial boot control for external load */
5355 bnx2x_cl45_write(bp, phy,
5356 MDIO_PMA_DEVAD,
5357 MDIO_PMA_REG_GEN_CTRL, 0x0001);
5358}
5359
5360/******************************************************************/
5361/* BCM8727 PHY SECTION */
5362/******************************************************************/
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005363
5364static void bnx2x_8727_set_link_led(struct bnx2x_phy *phy,
5365 struct link_params *params, u8 mode)
5366{
5367 struct bnx2x *bp = params->bp;
5368 u16 led_mode_bitmask = 0;
5369 u16 gpio_pins_bitmask = 0;
5370 u16 val;
5371 /* Only NOC flavor requires to set the LED specifically */
5372 if (!(phy->flags & FLAGS_NOC))
5373 return;
5374 switch (mode) {
5375 case LED_MODE_FRONT_PANEL_OFF:
5376 case LED_MODE_OFF:
5377 led_mode_bitmask = 0;
5378 gpio_pins_bitmask = 0x03;
5379 break;
5380 case LED_MODE_ON:
5381 led_mode_bitmask = 0;
5382 gpio_pins_bitmask = 0x02;
5383 break;
5384 case LED_MODE_OPER:
5385 led_mode_bitmask = 0x60;
5386 gpio_pins_bitmask = 0x11;
5387 break;
5388 }
5389 bnx2x_cl45_read(bp, phy,
5390 MDIO_PMA_DEVAD,
5391 MDIO_PMA_REG_8727_PCS_OPT_CTRL,
5392 &val);
5393 val &= 0xff8f;
5394 val |= led_mode_bitmask;
5395 bnx2x_cl45_write(bp, phy,
5396 MDIO_PMA_DEVAD,
5397 MDIO_PMA_REG_8727_PCS_OPT_CTRL,
5398 val);
5399 bnx2x_cl45_read(bp, phy,
5400 MDIO_PMA_DEVAD,
5401 MDIO_PMA_REG_8727_GPIO_CTRL,
5402 &val);
5403 val &= 0xffe0;
5404 val |= gpio_pins_bitmask;
5405 bnx2x_cl45_write(bp, phy,
5406 MDIO_PMA_DEVAD,
5407 MDIO_PMA_REG_8727_GPIO_CTRL,
5408 val);
5409}
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005410static void bnx2x_8727_hw_reset(struct bnx2x_phy *phy,
5411 struct link_params *params) {
5412 u32 swap_val, swap_override;
5413 u8 port;
5414 /**
5415 * The PHY reset is controlled by GPIO 1. Fake the port number
5416 * to cancel the swap done in set_gpio()
5417 */
5418 struct bnx2x *bp = params->bp;
5419 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
5420 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
5421 port = (swap_val && swap_override) ^ 1;
5422 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
5423 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
5424}
5425
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005426static u8 bnx2x_8727_config_init(struct bnx2x_phy *phy,
5427 struct link_params *params,
5428 struct link_vars *vars)
5429{
5430 u16 tmp1, val, mod_abs;
5431 u16 rx_alarm_ctrl_val;
5432 u16 lasi_ctrl_val;
5433 struct bnx2x *bp = params->bp;
5434 /* Enable PMD link, MOD_ABS_FLT, and 1G link alarm */
5435
5436 bnx2x_wait_reset_complete(bp, phy);
5437 rx_alarm_ctrl_val = (1<<2) | (1<<5) ;
5438 lasi_ctrl_val = 0x0004;
5439
5440 DP(NETIF_MSG_LINK, "Initializing BCM8727\n");
5441 /* enable LASI */
5442 bnx2x_cl45_write(bp, phy,
5443 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
5444 rx_alarm_ctrl_val);
5445
5446 bnx2x_cl45_write(bp, phy,
5447 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, lasi_ctrl_val);
5448
5449 /* Initially configure MOD_ABS to interrupt when
5450 module is presence( bit 8) */
5451 bnx2x_cl45_read(bp, phy,
5452 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
5453 /* Set EDC off by setting OPTXLOS signal input to low
5454 (bit 9).
5455 When the EDC is off it locks onto a reference clock and
5456 avoids becoming 'lost'.*/
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005457 mod_abs &= ~(1<<8);
5458 if (!(phy->flags & FLAGS_NOC))
5459 mod_abs &= ~(1<<9);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005460 bnx2x_cl45_write(bp, phy,
5461 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
5462
5463
5464 /* Make MOD_ABS give interrupt on change */
5465 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL,
5466 &val);
5467 val |= (1<<12);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005468 if (phy->flags & FLAGS_NOC)
5469 val |= (3<<5);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005470
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005471 /**
5472 * Set 8727 GPIOs to input to allow reading from the 8727 GPIO0
5473 * status which reflect SFP+ module over-current
5474 */
5475 if (!(phy->flags & FLAGS_NOC))
5476 val &= 0xff8f; /* Reset bits 4-6 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005477 bnx2x_cl45_write(bp, phy,
5478 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL, val);
5479
5480 bnx2x_8727_power_module(bp, phy, 1);
5481
5482 bnx2x_cl45_read(bp, phy,
5483 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &tmp1);
5484
5485 bnx2x_cl45_read(bp, phy,
5486 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &tmp1);
5487
5488 /* Set option 1G speed */
5489 if (phy->req_line_speed == SPEED_1000) {
5490 DP(NETIF_MSG_LINK, "Setting 1G force\n");
5491 bnx2x_cl45_write(bp, phy,
5492 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x40);
5493 bnx2x_cl45_write(bp, phy,
5494 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0xD);
5495 bnx2x_cl45_read(bp, phy,
5496 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, &tmp1);
5497 DP(NETIF_MSG_LINK, "1.7 = 0x%x\n", tmp1);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005498 /**
5499 * Power down the XAUI until link is up in case of dual-media
5500 * and 1G
5501 */
5502 if (DUAL_MEDIA(params)) {
5503 bnx2x_cl45_read(bp, phy,
5504 MDIO_PMA_DEVAD,
5505 MDIO_PMA_REG_8727_PCS_GP, &val);
5506 val |= (3<<10);
5507 bnx2x_cl45_write(bp, phy,
5508 MDIO_PMA_DEVAD,
5509 MDIO_PMA_REG_8727_PCS_GP, val);
5510 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005511 } else if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
5512 ((phy->speed_cap_mask &
5513 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) &&
5514 ((phy->speed_cap_mask &
5515 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) !=
5516 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
5517
5518 DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
5519 bnx2x_cl45_write(bp, phy,
5520 MDIO_AN_DEVAD, MDIO_AN_REG_8727_MISC_CTRL, 0);
5521 bnx2x_cl45_write(bp, phy,
5522 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1300);
5523 } else {
5524 /**
5525 * Since the 8727 has only single reset pin, need to set the 10G
5526 * registers although it is default
5527 */
5528 bnx2x_cl45_write(bp, phy,
5529 MDIO_AN_DEVAD, MDIO_AN_REG_8727_MISC_CTRL,
5530 0x0020);
5531 bnx2x_cl45_write(bp, phy,
5532 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x0100);
5533 bnx2x_cl45_write(bp, phy,
5534 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x2040);
5535 bnx2x_cl45_write(bp, phy,
5536 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2,
5537 0x0008);
5538 }
5539
5540 /* Set 2-wire transfer rate of SFP+ module EEPROM
5541 * to 100Khz since some DACs(direct attached cables) do
5542 * not work at 400Khz.
5543 */
5544 bnx2x_cl45_write(bp, phy,
5545 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR,
5546 0xa001);
5547
5548 /* Set TX PreEmphasis if needed */
5549 if ((params->feature_config_flags &
5550 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
5551 DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x, TX_CTRL2 0x%x\n",
5552 phy->tx_preemphasis[0],
5553 phy->tx_preemphasis[1]);
5554 bnx2x_cl45_write(bp, phy,
5555 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TX_CTRL1,
5556 phy->tx_preemphasis[0]);
5557
5558 bnx2x_cl45_write(bp, phy,
5559 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TX_CTRL2,
5560 phy->tx_preemphasis[1]);
5561 }
5562
5563 return 0;
5564}
5565
5566static void bnx2x_8727_handle_mod_abs(struct bnx2x_phy *phy,
5567 struct link_params *params)
5568{
5569 struct bnx2x *bp = params->bp;
5570 u16 mod_abs, rx_alarm_status;
5571 u32 val = REG_RD(bp, params->shmem_base +
5572 offsetof(struct shmem_region, dev_info.
5573 port_feature_config[params->port].
5574 config));
5575 bnx2x_cl45_read(bp, phy,
5576 MDIO_PMA_DEVAD,
5577 MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
5578 if (mod_abs & (1<<8)) {
5579
5580 /* Module is absent */
5581 DP(NETIF_MSG_LINK, "MOD_ABS indication "
5582 "show module is absent\n");
5583
5584 /* 1. Set mod_abs to detect next module
5585 presence event
5586 2. Set EDC off by setting OPTXLOS signal input to low
5587 (bit 9).
5588 When the EDC is off it locks onto a reference clock and
5589 avoids becoming 'lost'.*/
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005590 mod_abs &= ~(1<<8);
5591 if (!(phy->flags & FLAGS_NOC))
5592 mod_abs &= ~(1<<9);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005593 bnx2x_cl45_write(bp, phy,
5594 MDIO_PMA_DEVAD,
5595 MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
5596
5597 /* Clear RX alarm since it stays up as long as
5598 the mod_abs wasn't changed */
5599 bnx2x_cl45_read(bp, phy,
5600 MDIO_PMA_DEVAD,
5601 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
5602
5603 } else {
5604 /* Module is present */
5605 DP(NETIF_MSG_LINK, "MOD_ABS indication "
5606 "show module is present\n");
5607 /* First thing, disable transmitter,
5608 and if the module is ok, the
5609 module_detection will enable it*/
5610
5611 /* 1. Set mod_abs to detect next module
5612 absent event ( bit 8)
5613 2. Restore the default polarity of the OPRXLOS signal and
5614 this signal will then correctly indicate the presence or
5615 absence of the Rx signal. (bit 9) */
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005616 mod_abs |= (1<<8);
5617 if (!(phy->flags & FLAGS_NOC))
5618 mod_abs |= (1<<9);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005619 bnx2x_cl45_write(bp, phy,
5620 MDIO_PMA_DEVAD,
5621 MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
5622
5623 /* Clear RX alarm since it stays up as long as
5624 the mod_abs wasn't changed. This is need to be done
5625 before calling the module detection, otherwise it will clear
5626 the link update alarm */
5627 bnx2x_cl45_read(bp, phy,
5628 MDIO_PMA_DEVAD,
5629 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
5630
5631
5632 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
5633 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
5634 bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
5635
5636 if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0)
5637 bnx2x_sfp_module_detection(phy, params);
5638 else
5639 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
5640 }
5641
5642 DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n",
5643 rx_alarm_status);
5644 /* No need to check link status in case of
5645 module plugged in/out */
5646}
5647
5648static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy,
5649 struct link_params *params,
5650 struct link_vars *vars)
5651
5652{
5653 struct bnx2x *bp = params->bp;
5654 u8 link_up = 0;
5655 u16 link_status = 0;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005656 u16 rx_alarm_status, lasi_ctrl, val1;
5657
5658 /* If PHY is not initialized, do not check link status */
5659 bnx2x_cl45_read(bp, phy,
5660 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL,
5661 &lasi_ctrl);
5662 if (!lasi_ctrl)
5663 return 0;
5664
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005665 /* Check the LASI */
5666 bnx2x_cl45_read(bp, phy,
5667 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM,
5668 &rx_alarm_status);
5669 vars->line_speed = 0;
5670 DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n", rx_alarm_status);
5671
5672 bnx2x_cl45_read(bp, phy,
5673 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
5674
5675 DP(NETIF_MSG_LINK, "8727 LASI status 0x%x\n", val1);
5676
5677 /* Clear MSG-OUT */
5678 bnx2x_cl45_read(bp, phy,
5679 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &val1);
5680
5681 /**
5682 * If a module is present and there is need to check
5683 * for over current
5684 */
5685 if (!(phy->flags & FLAGS_NOC) && !(rx_alarm_status & (1<<5))) {
5686 /* Check over-current using 8727 GPIO0 input*/
5687 bnx2x_cl45_read(bp, phy,
5688 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_GPIO_CTRL,
5689 &val1);
5690
5691 if ((val1 & (1<<8)) == 0) {
5692 DP(NETIF_MSG_LINK, "8727 Power fault has been detected"
5693 " on port %d\n", params->port);
5694 netdev_err(bp->dev, "Error: Power fault on Port %d has"
5695 " been detected and the power to "
5696 "that SFP+ module has been removed"
5697 " to prevent failure of the card."
5698 " Please remove the SFP+ module and"
5699 " restart the system to clear this"
5700 " error.\n",
5701 params->port);
5702
5703 /*
5704 * Disable all RX_ALARMs except for
5705 * mod_abs
5706 */
5707 bnx2x_cl45_write(bp, phy,
5708 MDIO_PMA_DEVAD,
5709 MDIO_PMA_REG_RX_ALARM_CTRL, (1<<5));
5710
5711 bnx2x_cl45_read(bp, phy,
5712 MDIO_PMA_DEVAD,
5713 MDIO_PMA_REG_PHY_IDENTIFIER, &val1);
5714 /* Wait for module_absent_event */
5715 val1 |= (1<<8);
5716 bnx2x_cl45_write(bp, phy,
5717 MDIO_PMA_DEVAD,
5718 MDIO_PMA_REG_PHY_IDENTIFIER, val1);
5719 /* Clear RX alarm */
5720 bnx2x_cl45_read(bp, phy,
5721 MDIO_PMA_DEVAD,
5722 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
5723 return 0;
5724 }
5725 } /* Over current check */
5726
5727 /* When module absent bit is set, check module */
5728 if (rx_alarm_status & (1<<5)) {
5729 bnx2x_8727_handle_mod_abs(phy, params);
5730 /* Enable all mod_abs and link detection bits */
5731 bnx2x_cl45_write(bp, phy,
5732 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
5733 ((1<<5) | (1<<2)));
5734 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005735 DP(NETIF_MSG_LINK, "Enabling 8727 TX laser if SFP is approved\n");
5736 bnx2x_8727_specific_func(phy, params, ENABLE_TX);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005737 /* If transmitter is disabled, ignore false link up indication */
5738 bnx2x_cl45_read(bp, phy,
5739 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, &val1);
5740 if (val1 & (1<<15)) {
5741 DP(NETIF_MSG_LINK, "Tx is disabled\n");
5742 return 0;
5743 }
5744
5745 bnx2x_cl45_read(bp, phy,
5746 MDIO_PMA_DEVAD,
5747 MDIO_PMA_REG_8073_SPEED_LINK_STATUS, &link_status);
5748
5749 /* Bits 0..2 --> speed detected,
5750 bits 13..15--> link is down */
5751 if ((link_status & (1<<2)) && (!(link_status & (1<<15)))) {
5752 link_up = 1;
5753 vars->line_speed = SPEED_10000;
5754 } else if ((link_status & (1<<0)) && (!(link_status & (1<<13)))) {
5755 link_up = 1;
5756 vars->line_speed = SPEED_1000;
5757 DP(NETIF_MSG_LINK, "port %x: External link up in 1G\n",
5758 params->port);
5759 } else {
5760 link_up = 0;
5761 DP(NETIF_MSG_LINK, "port %x: External link is down\n",
5762 params->port);
5763 }
5764 if (link_up)
5765 bnx2x_ext_phy_resolve_fc(phy, params, vars);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005766
5767 if ((DUAL_MEDIA(params)) &&
5768 (phy->req_line_speed == SPEED_1000)) {
5769 bnx2x_cl45_read(bp, phy,
5770 MDIO_PMA_DEVAD,
5771 MDIO_PMA_REG_8727_PCS_GP, &val1);
5772 /**
5773 * In case of dual-media board and 1G, power up the XAUI side,
5774 * otherwise power it down. For 10G it is done automatically
5775 */
5776 if (link_up)
5777 val1 &= ~(3<<10);
5778 else
5779 val1 |= (3<<10);
5780 bnx2x_cl45_write(bp, phy,
5781 MDIO_PMA_DEVAD,
5782 MDIO_PMA_REG_8727_PCS_GP, val1);
5783 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005784 return link_up;
5785}
5786
5787static void bnx2x_8727_link_reset(struct bnx2x_phy *phy,
5788 struct link_params *params)
5789{
5790 struct bnx2x *bp = params->bp;
5791 /* Disable Transmitter */
5792 bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005793 /* Clear LASI */
5794 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0);
5795
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005796}
5797
5798/******************************************************************/
5799/* BCM8481/BCM84823/BCM84833 PHY SECTION */
5800/******************************************************************/
5801static void bnx2x_save_848xx_spirom_version(struct bnx2x_phy *phy,
5802 struct link_params *params)
5803{
5804 u16 val, fw_ver1, fw_ver2, cnt;
5805 struct bnx2x *bp = params->bp;
5806
5807 /* For the 32 bits registers in 848xx, access via MDIO2ARM interface.*/
5808 /* (1) set register 0xc200_0014(SPI_BRIDGE_CTRL_2) to 0x03000000 */
5809 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0014);
5810 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200);
5811 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81B, 0x0000);
5812 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81C, 0x0300);
5813 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x0009);
5814
5815 for (cnt = 0; cnt < 100; cnt++) {
5816 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val);
5817 if (val & 1)
5818 break;
5819 udelay(5);
5820 }
5821 if (cnt == 100) {
5822 DP(NETIF_MSG_LINK, "Unable to read 848xx phy fw version(1)\n");
5823 bnx2x_save_spirom_version(bp, params->port, 0,
5824 phy->ver_addr);
5825 return;
5826 }
5827
5828
5829 /* 2) read register 0xc200_0000 (SPI_FW_STATUS) */
5830 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0000);
5831 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200);
5832 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x000A);
5833 for (cnt = 0; cnt < 100; cnt++) {
5834 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val);
5835 if (val & 1)
5836 break;
5837 udelay(5);
5838 }
5839 if (cnt == 100) {
5840 DP(NETIF_MSG_LINK, "Unable to read 848xx phy fw version(2)\n");
5841 bnx2x_save_spirom_version(bp, params->port, 0,
5842 phy->ver_addr);
5843 return;
5844 }
5845
5846 /* lower 16 bits of the register SPI_FW_STATUS */
5847 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81B, &fw_ver1);
5848 /* upper 16 bits of register SPI_FW_STATUS */
5849 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81C, &fw_ver2);
5850
5851 bnx2x_save_spirom_version(bp, params->port, (fw_ver2<<16) | fw_ver1,
5852 phy->ver_addr);
5853}
5854
5855static void bnx2x_848xx_set_led(struct bnx2x *bp,
5856 struct bnx2x_phy *phy)
5857{
5858 u16 val;
5859
5860 /* PHYC_CTL_LED_CTL */
5861 bnx2x_cl45_read(bp, phy,
5862 MDIO_PMA_DEVAD,
5863 MDIO_PMA_REG_8481_LINK_SIGNAL, &val);
5864 val &= 0xFE00;
5865 val |= 0x0092;
5866
5867 bnx2x_cl45_write(bp, phy,
5868 MDIO_PMA_DEVAD,
5869 MDIO_PMA_REG_8481_LINK_SIGNAL, val);
5870
5871 bnx2x_cl45_write(bp, phy,
5872 MDIO_PMA_DEVAD,
5873 MDIO_PMA_REG_8481_LED1_MASK,
5874 0x80);
5875
5876 bnx2x_cl45_write(bp, phy,
5877 MDIO_PMA_DEVAD,
5878 MDIO_PMA_REG_8481_LED2_MASK,
5879 0x18);
5880
5881 bnx2x_cl45_write(bp, phy,
5882 MDIO_PMA_DEVAD,
5883 MDIO_PMA_REG_8481_LED3_MASK,
5884 0x0040);
5885
5886 /* 'Interrupt Mask' */
5887 bnx2x_cl45_write(bp, phy,
5888 MDIO_AN_DEVAD,
5889 0xFFFB, 0xFFFD);
5890}
5891
5892static u8 bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005893 struct link_params *params,
5894 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005895{
5896 struct bnx2x *bp = params->bp;
5897 u16 autoneg_val, an_1000_val, an_10_100_val;
Yaniv Rosner9bffeac2010-11-01 05:32:27 +00005898
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005899 bnx2x_bits_en(bp, NIG_REG_LATCH_BC_0 + params->port*4,
5900 1 << NIG_LATCH_BC_ENABLE_MI_INT);
5901
5902 bnx2x_cl45_write(bp, phy,
5903 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x0000);
5904
5905 bnx2x_848xx_set_led(bp, phy);
5906
5907 /* set 1000 speed advertisement */
5908 bnx2x_cl45_read(bp, phy,
5909 MDIO_AN_DEVAD, MDIO_AN_REG_8481_1000T_CTRL,
5910 &an_1000_val);
5911
5912 bnx2x_ext_phy_set_pause(params, phy, vars);
5913 bnx2x_cl45_read(bp, phy,
5914 MDIO_AN_DEVAD,
5915 MDIO_AN_REG_8481_LEGACY_AN_ADV,
5916 &an_10_100_val);
5917 bnx2x_cl45_read(bp, phy,
5918 MDIO_AN_DEVAD, MDIO_AN_REG_8481_LEGACY_MII_CTRL,
5919 &autoneg_val);
5920 /* Disable forced speed */
5921 autoneg_val &= ~((1<<6) | (1<<8) | (1<<9) | (1<<12) | (1<<13));
5922 an_10_100_val &= ~((1<<5) | (1<<6) | (1<<7) | (1<<8));
5923
5924 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
5925 (phy->speed_cap_mask &
5926 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) ||
5927 (phy->req_line_speed == SPEED_1000)) {
5928 an_1000_val |= (1<<8);
5929 autoneg_val |= (1<<9 | 1<<12);
5930 if (phy->req_duplex == DUPLEX_FULL)
5931 an_1000_val |= (1<<9);
5932 DP(NETIF_MSG_LINK, "Advertising 1G\n");
5933 } else
5934 an_1000_val &= ~((1<<8) | (1<<9));
5935
5936 bnx2x_cl45_write(bp, phy,
5937 MDIO_AN_DEVAD, MDIO_AN_REG_8481_1000T_CTRL,
5938 an_1000_val);
5939
5940 /* set 10 speed advertisement */
5941 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
5942 (phy->speed_cap_mask &
5943 (PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL |
5944 PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF)))) {
5945 an_10_100_val |= (1<<7);
5946 /* Enable autoneg and restart autoneg for legacy speeds */
5947 autoneg_val |= (1<<9 | 1<<12);
5948
5949 if (phy->req_duplex == DUPLEX_FULL)
5950 an_10_100_val |= (1<<8);
5951 DP(NETIF_MSG_LINK, "Advertising 100M\n");
5952 }
5953 /* set 10 speed advertisement */
5954 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
5955 (phy->speed_cap_mask &
5956 (PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL |
5957 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF)))) {
5958 an_10_100_val |= (1<<5);
5959 autoneg_val |= (1<<9 | 1<<12);
5960 if (phy->req_duplex == DUPLEX_FULL)
5961 an_10_100_val |= (1<<6);
5962 DP(NETIF_MSG_LINK, "Advertising 10M\n");
5963 }
5964
5965 /* Only 10/100 are allowed to work in FORCE mode */
5966 if (phy->req_line_speed == SPEED_100) {
5967 autoneg_val |= (1<<13);
5968 /* Enabled AUTO-MDIX when autoneg is disabled */
5969 bnx2x_cl45_write(bp, phy,
5970 MDIO_AN_DEVAD, MDIO_AN_REG_8481_AUX_CTRL,
5971 (1<<15 | 1<<9 | 7<<0));
5972 DP(NETIF_MSG_LINK, "Setting 100M force\n");
5973 }
5974 if (phy->req_line_speed == SPEED_10) {
5975 /* Enabled AUTO-MDIX when autoneg is disabled */
5976 bnx2x_cl45_write(bp, phy,
5977 MDIO_AN_DEVAD, MDIO_AN_REG_8481_AUX_CTRL,
5978 (1<<15 | 1<<9 | 7<<0));
5979 DP(NETIF_MSG_LINK, "Setting 10M force\n");
5980 }
5981
5982 bnx2x_cl45_write(bp, phy,
5983 MDIO_AN_DEVAD, MDIO_AN_REG_8481_LEGACY_AN_ADV,
5984 an_10_100_val);
5985
5986 if (phy->req_duplex == DUPLEX_FULL)
5987 autoneg_val |= (1<<8);
5988
5989 bnx2x_cl45_write(bp, phy,
5990 MDIO_AN_DEVAD,
5991 MDIO_AN_REG_8481_LEGACY_MII_CTRL, autoneg_val);
5992
5993 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
5994 (phy->speed_cap_mask &
5995 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) ||
5996 (phy->req_line_speed == SPEED_10000)) {
5997 DP(NETIF_MSG_LINK, "Advertising 10G\n");
5998 /* Restart autoneg for 10G*/
5999
6000 bnx2x_cl45_write(bp, phy,
6001 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL,
6002 0x3200);
6003 } else if (phy->req_line_speed != SPEED_10 &&
6004 phy->req_line_speed != SPEED_100) {
6005 bnx2x_cl45_write(bp, phy,
6006 MDIO_AN_DEVAD,
6007 MDIO_AN_REG_8481_10GBASE_T_AN_CTRL,
6008 1);
6009 }
6010 /* Save spirom version */
6011 bnx2x_save_848xx_spirom_version(phy, params);
6012
6013 return 0;
6014}
6015
6016static u8 bnx2x_8481_config_init(struct bnx2x_phy *phy,
6017 struct link_params *params,
6018 struct link_vars *vars)
6019{
6020 struct bnx2x *bp = params->bp;
6021 /* Restore normal power mode*/
6022 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
6023 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
6024
6025 /* HW reset */
6026 bnx2x_ext_phy_hw_reset(bp, params->port);
Yaniv Rosner9bffeac2010-11-01 05:32:27 +00006027 bnx2x_wait_reset_complete(bp, phy);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006028
6029 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
6030 return bnx2x_848xx_cmn_config_init(phy, params, vars);
6031}
6032
6033static u8 bnx2x_848x3_config_init(struct bnx2x_phy *phy,
6034 struct link_params *params,
6035 struct link_vars *vars)
6036{
6037 struct bnx2x *bp = params->bp;
Yaniv Rosner6a71bbe2010-11-01 05:32:31 +00006038 u8 port, initialize = 1;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006039 u16 val;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006040 u16 temp;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006041 u32 actual_phy_selection;
6042 u8 rc = 0;
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006043
6044 /* This is just for MDIO_CTL_REG_84823_MEDIA register. */
6045
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006046 msleep(1);
Yaniv Rosner6a71bbe2010-11-01 05:32:31 +00006047 if (CHIP_IS_E2(bp))
6048 port = BP_PATH(bp);
6049 else
6050 port = params->port;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006051 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
6052 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006053 port);
Yaniv Rosner9bffeac2010-11-01 05:32:27 +00006054 bnx2x_wait_reset_complete(bp, phy);
6055 /* Wait for GPHY to come out of reset */
6056 msleep(50);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006057 /* BCM84823 requires that XGXS links up first @ 10G for normal
6058 behavior */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006059 temp = vars->line_speed;
6060 vars->line_speed = SPEED_10000;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006061 bnx2x_set_autoneg(&params->phy[INT_PHY], params, vars, 0);
6062 bnx2x_program_serdes(&params->phy[INT_PHY], params, vars);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006063 vars->line_speed = temp;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006064
6065 /* Set dual-media configuration according to configuration */
6066
6067 bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
6068 MDIO_CTL_REG_84823_MEDIA, &val);
6069 val &= ~(MDIO_CTL_REG_84823_MEDIA_MAC_MASK |
6070 MDIO_CTL_REG_84823_MEDIA_LINE_MASK |
6071 MDIO_CTL_REG_84823_MEDIA_COPPER_CORE_DOWN |
6072 MDIO_CTL_REG_84823_MEDIA_PRIORITY_MASK |
6073 MDIO_CTL_REG_84823_MEDIA_FIBER_1G);
6074 val |= MDIO_CTL_REG_84823_CTRL_MAC_XFI |
6075 MDIO_CTL_REG_84823_MEDIA_LINE_XAUI_L;
6076
6077 actual_phy_selection = bnx2x_phy_selection(params);
6078
6079 switch (actual_phy_selection) {
6080 case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT:
6081 /* Do nothing. Essentialy this is like the priority copper */
6082 break;
6083 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
6084 val |= MDIO_CTL_REG_84823_MEDIA_PRIORITY_COPPER;
6085 break;
6086 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
6087 val |= MDIO_CTL_REG_84823_MEDIA_PRIORITY_FIBER;
6088 break;
6089 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY:
6090 /* Do nothing here. The first PHY won't be initialized at all */
6091 break;
6092 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY:
6093 val |= MDIO_CTL_REG_84823_MEDIA_COPPER_CORE_DOWN;
6094 initialize = 0;
6095 break;
6096 }
6097 if (params->phy[EXT_PHY2].req_line_speed == SPEED_1000)
6098 val |= MDIO_CTL_REG_84823_MEDIA_FIBER_1G;
6099
6100 bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
6101 MDIO_CTL_REG_84823_MEDIA, val);
6102 DP(NETIF_MSG_LINK, "Multi_phy config = 0x%x, Media control = 0x%x\n",
6103 params->multi_phy_config, val);
6104
6105 if (initialize)
6106 rc = bnx2x_848xx_cmn_config_init(phy, params, vars);
6107 else
6108 bnx2x_save_848xx_spirom_version(phy, params);
6109 return rc;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006110}
6111
6112static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy,
6113 struct link_params *params,
6114 struct link_vars *vars)
6115{
6116 struct bnx2x *bp = params->bp;
6117 u16 val, val1, val2;
6118 u8 link_up = 0;
6119
6120 /* Check 10G-BaseT link status */
6121 /* Check PMD signal ok */
6122 bnx2x_cl45_read(bp, phy,
6123 MDIO_AN_DEVAD, 0xFFFA, &val1);
6124 bnx2x_cl45_read(bp, phy,
6125 MDIO_PMA_DEVAD, MDIO_PMA_REG_8481_PMD_SIGNAL,
6126 &val2);
6127 DP(NETIF_MSG_LINK, "BCM848xx: PMD_SIGNAL 1.a811 = 0x%x\n", val2);
6128
6129 /* Check link 10G */
6130 if (val2 & (1<<11)) {
6131 vars->line_speed = SPEED_10000;
6132 link_up = 1;
6133 bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
6134 } else { /* Check Legacy speed link */
6135 u16 legacy_status, legacy_speed;
6136
6137 /* Enable expansion register 0x42 (Operation mode status) */
6138 bnx2x_cl45_write(bp, phy,
6139 MDIO_AN_DEVAD,
6140 MDIO_AN_REG_8481_EXPANSION_REG_ACCESS, 0xf42);
6141
6142 /* Get legacy speed operation status */
6143 bnx2x_cl45_read(bp, phy,
6144 MDIO_AN_DEVAD,
6145 MDIO_AN_REG_8481_EXPANSION_REG_RD_RW,
6146 &legacy_status);
6147
6148 DP(NETIF_MSG_LINK, "Legacy speed status"
6149 " = 0x%x\n", legacy_status);
6150 link_up = ((legacy_status & (1<<11)) == (1<<11));
6151 if (link_up) {
6152 legacy_speed = (legacy_status & (3<<9));
6153 if (legacy_speed == (0<<9))
6154 vars->line_speed = SPEED_10;
6155 else if (legacy_speed == (1<<9))
6156 vars->line_speed = SPEED_100;
6157 else if (legacy_speed == (2<<9))
6158 vars->line_speed = SPEED_1000;
6159 else /* Should not happen */
6160 vars->line_speed = 0;
6161
6162 if (legacy_status & (1<<8))
6163 vars->duplex = DUPLEX_FULL;
6164 else
6165 vars->duplex = DUPLEX_HALF;
6166
6167 DP(NETIF_MSG_LINK, "Link is up in %dMbps,"
6168 " is_duplex_full= %d\n", vars->line_speed,
6169 (vars->duplex == DUPLEX_FULL));
6170 /* Check legacy speed AN resolution */
6171 bnx2x_cl45_read(bp, phy,
6172 MDIO_AN_DEVAD,
6173 MDIO_AN_REG_8481_LEGACY_MII_STATUS,
6174 &val);
6175 if (val & (1<<5))
6176 vars->link_status |=
6177 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
6178 bnx2x_cl45_read(bp, phy,
6179 MDIO_AN_DEVAD,
6180 MDIO_AN_REG_8481_LEGACY_AN_EXPANSION,
6181 &val);
6182 if ((val & (1<<0)) == 0)
6183 vars->link_status |=
6184 LINK_STATUS_PARALLEL_DETECTION_USED;
6185 }
6186 }
6187 if (link_up) {
6188 DP(NETIF_MSG_LINK, "BCM84823: link speed is %d\n",
6189 vars->line_speed);
6190 bnx2x_ext_phy_resolve_fc(phy, params, vars);
6191 }
6192
6193 return link_up;
6194}
6195
6196static u8 bnx2x_848xx_format_ver(u32 raw_ver, u8 *str, u16 *len)
6197{
6198 u8 status = 0;
6199 u32 spirom_ver;
6200 spirom_ver = ((raw_ver & 0xF80) >> 7) << 16 | (raw_ver & 0x7F);
6201 status = bnx2x_format_ver(spirom_ver, str, len);
6202 return status;
6203}
6204
6205static void bnx2x_8481_hw_reset(struct bnx2x_phy *phy,
6206 struct link_params *params)
6207{
6208 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
6209 MISC_REGISTERS_GPIO_OUTPUT_LOW, 0);
6210 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
6211 MISC_REGISTERS_GPIO_OUTPUT_LOW, 1);
6212}
6213
6214static void bnx2x_8481_link_reset(struct bnx2x_phy *phy,
6215 struct link_params *params)
6216{
6217 bnx2x_cl45_write(params->bp, phy,
6218 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x0000);
6219 bnx2x_cl45_write(params->bp, phy,
6220 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1);
6221}
6222
6223static void bnx2x_848x3_link_reset(struct bnx2x_phy *phy,
6224 struct link_params *params)
6225{
6226 struct bnx2x *bp = params->bp;
Yaniv Rosner6a71bbe2010-11-01 05:32:31 +00006227 u8 port;
6228 if (CHIP_IS_E2(bp))
6229 port = BP_PATH(bp);
6230 else
6231 port = params->port;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006232 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
6233 MISC_REGISTERS_GPIO_OUTPUT_LOW,
6234 port);
6235}
6236
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006237static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy,
6238 struct link_params *params, u8 mode)
6239{
6240 struct bnx2x *bp = params->bp;
6241 u16 val;
6242
6243 switch (mode) {
6244 case LED_MODE_OFF:
6245
6246 DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE OFF\n", params->port);
6247
6248 if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
6249 SHARED_HW_CFG_LED_EXTPHY1) {
6250
6251 /* Set LED masks */
6252 bnx2x_cl45_write(bp, phy,
6253 MDIO_PMA_DEVAD,
6254 MDIO_PMA_REG_8481_LED1_MASK,
6255 0x0);
6256
6257 bnx2x_cl45_write(bp, phy,
6258 MDIO_PMA_DEVAD,
6259 MDIO_PMA_REG_8481_LED2_MASK,
6260 0x0);
6261
6262 bnx2x_cl45_write(bp, phy,
6263 MDIO_PMA_DEVAD,
6264 MDIO_PMA_REG_8481_LED3_MASK,
6265 0x0);
6266
6267 bnx2x_cl45_write(bp, phy,
6268 MDIO_PMA_DEVAD,
6269 MDIO_PMA_REG_8481_LED5_MASK,
6270 0x0);
6271
6272 } else {
6273 bnx2x_cl45_write(bp, phy,
6274 MDIO_PMA_DEVAD,
6275 MDIO_PMA_REG_8481_LED1_MASK,
6276 0x0);
6277 }
6278 break;
6279 case LED_MODE_FRONT_PANEL_OFF:
6280
6281 DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE FRONT PANEL OFF\n",
6282 params->port);
6283
6284 if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
6285 SHARED_HW_CFG_LED_EXTPHY1) {
6286
6287 /* Set LED masks */
6288 bnx2x_cl45_write(bp, phy,
6289 MDIO_PMA_DEVAD,
6290 MDIO_PMA_REG_8481_LED1_MASK,
6291 0x0);
6292
6293 bnx2x_cl45_write(bp, phy,
6294 MDIO_PMA_DEVAD,
6295 MDIO_PMA_REG_8481_LED2_MASK,
6296 0x0);
6297
6298 bnx2x_cl45_write(bp, phy,
6299 MDIO_PMA_DEVAD,
6300 MDIO_PMA_REG_8481_LED3_MASK,
6301 0x0);
6302
6303 bnx2x_cl45_write(bp, phy,
6304 MDIO_PMA_DEVAD,
6305 MDIO_PMA_REG_8481_LED5_MASK,
6306 0x20);
6307
6308 } else {
6309 bnx2x_cl45_write(bp, phy,
6310 MDIO_PMA_DEVAD,
6311 MDIO_PMA_REG_8481_LED1_MASK,
6312 0x0);
6313 }
6314 break;
6315 case LED_MODE_ON:
6316
6317 DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE ON\n", params->port);
6318
6319 if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
6320 SHARED_HW_CFG_LED_EXTPHY1) {
6321 /* Set control reg */
6322 bnx2x_cl45_read(bp, phy,
6323 MDIO_PMA_DEVAD,
6324 MDIO_PMA_REG_8481_LINK_SIGNAL,
6325 &val);
6326 val &= 0x8000;
6327 val |= 0x2492;
6328
6329 bnx2x_cl45_write(bp, phy,
6330 MDIO_PMA_DEVAD,
6331 MDIO_PMA_REG_8481_LINK_SIGNAL,
6332 val);
6333
6334 /* Set LED masks */
6335 bnx2x_cl45_write(bp, phy,
6336 MDIO_PMA_DEVAD,
6337 MDIO_PMA_REG_8481_LED1_MASK,
6338 0x0);
6339
6340 bnx2x_cl45_write(bp, phy,
6341 MDIO_PMA_DEVAD,
6342 MDIO_PMA_REG_8481_LED2_MASK,
6343 0x20);
6344
6345 bnx2x_cl45_write(bp, phy,
6346 MDIO_PMA_DEVAD,
6347 MDIO_PMA_REG_8481_LED3_MASK,
6348 0x20);
6349
6350 bnx2x_cl45_write(bp, phy,
6351 MDIO_PMA_DEVAD,
6352 MDIO_PMA_REG_8481_LED5_MASK,
6353 0x0);
6354 } else {
6355 bnx2x_cl45_write(bp, phy,
6356 MDIO_PMA_DEVAD,
6357 MDIO_PMA_REG_8481_LED1_MASK,
6358 0x20);
6359 }
6360 break;
6361
6362 case LED_MODE_OPER:
6363
6364 DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE OPER\n", params->port);
6365
6366 if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
6367 SHARED_HW_CFG_LED_EXTPHY1) {
6368
6369 /* Set control reg */
6370 bnx2x_cl45_read(bp, phy,
6371 MDIO_PMA_DEVAD,
6372 MDIO_PMA_REG_8481_LINK_SIGNAL,
6373 &val);
6374
6375 if (!((val &
6376 MDIO_PMA_REG_8481_LINK_SIGNAL_LED4_ENABLE_MASK)
6377 >> MDIO_PMA_REG_8481_LINK_SIGNAL_LED4_ENABLE_SHIFT)){
6378 DP(NETIF_MSG_LINK, "Seting LINK_SIGNAL\n");
6379 bnx2x_cl45_write(bp, phy,
6380 MDIO_PMA_DEVAD,
6381 MDIO_PMA_REG_8481_LINK_SIGNAL,
6382 0xa492);
6383 }
6384
6385 /* Set LED masks */
6386 bnx2x_cl45_write(bp, phy,
6387 MDIO_PMA_DEVAD,
6388 MDIO_PMA_REG_8481_LED1_MASK,
6389 0x10);
6390
6391 bnx2x_cl45_write(bp, phy,
6392 MDIO_PMA_DEVAD,
6393 MDIO_PMA_REG_8481_LED2_MASK,
6394 0x80);
6395
6396 bnx2x_cl45_write(bp, phy,
6397 MDIO_PMA_DEVAD,
6398 MDIO_PMA_REG_8481_LED3_MASK,
6399 0x98);
6400
6401 bnx2x_cl45_write(bp, phy,
6402 MDIO_PMA_DEVAD,
6403 MDIO_PMA_REG_8481_LED5_MASK,
6404 0x40);
6405
6406 } else {
6407 bnx2x_cl45_write(bp, phy,
6408 MDIO_PMA_DEVAD,
6409 MDIO_PMA_REG_8481_LED1_MASK,
6410 0x80);
6411 }
6412 break;
6413 }
6414}
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006415/******************************************************************/
6416/* SFX7101 PHY SECTION */
6417/******************************************************************/
6418static void bnx2x_7101_config_loopback(struct bnx2x_phy *phy,
6419 struct link_params *params)
6420{
6421 struct bnx2x *bp = params->bp;
6422 /* SFX7101_XGXS_TEST1 */
6423 bnx2x_cl45_write(bp, phy,
6424 MDIO_XS_DEVAD, MDIO_XS_SFX7101_XGXS_TEST1, 0x100);
6425}
6426
6427static u8 bnx2x_7101_config_init(struct bnx2x_phy *phy,
6428 struct link_params *params,
6429 struct link_vars *vars)
6430{
6431 u16 fw_ver1, fw_ver2, val;
6432 struct bnx2x *bp = params->bp;
6433 DP(NETIF_MSG_LINK, "Setting the SFX7101 LASI indication\n");
6434
6435 /* Restore normal power mode*/
6436 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
6437 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
6438 /* HW reset */
6439 bnx2x_ext_phy_hw_reset(bp, params->port);
6440 bnx2x_wait_reset_complete(bp, phy);
6441
6442 bnx2x_cl45_write(bp, phy,
6443 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x1);
6444 DP(NETIF_MSG_LINK, "Setting the SFX7101 LED to blink on traffic\n");
6445 bnx2x_cl45_write(bp, phy,
6446 MDIO_PMA_DEVAD, MDIO_PMA_REG_7107_LED_CNTL, (1<<3));
6447
6448 bnx2x_ext_phy_set_pause(params, phy, vars);
6449 /* Restart autoneg */
6450 bnx2x_cl45_read(bp, phy,
6451 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, &val);
6452 val |= 0x200;
6453 bnx2x_cl45_write(bp, phy,
6454 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, val);
6455
6456 /* Save spirom version */
6457 bnx2x_cl45_read(bp, phy,
6458 MDIO_PMA_DEVAD, MDIO_PMA_REG_7101_VER1, &fw_ver1);
6459
6460 bnx2x_cl45_read(bp, phy,
6461 MDIO_PMA_DEVAD, MDIO_PMA_REG_7101_VER2, &fw_ver2);
6462 bnx2x_save_spirom_version(bp, params->port,
6463 (u32)(fw_ver1<<16 | fw_ver2), phy->ver_addr);
6464 return 0;
6465}
6466
6467static u8 bnx2x_7101_read_status(struct bnx2x_phy *phy,
6468 struct link_params *params,
6469 struct link_vars *vars)
6470{
6471 struct bnx2x *bp = params->bp;
6472 u8 link_up;
6473 u16 val1, val2;
6474 bnx2x_cl45_read(bp, phy,
6475 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val2);
6476 bnx2x_cl45_read(bp, phy,
6477 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
6478 DP(NETIF_MSG_LINK, "10G-base-T LASI status 0x%x->0x%x\n",
6479 val2, val1);
6480 bnx2x_cl45_read(bp, phy,
6481 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
6482 bnx2x_cl45_read(bp, phy,
6483 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
6484 DP(NETIF_MSG_LINK, "10G-base-T PMA status 0x%x->0x%x\n",
6485 val2, val1);
6486 link_up = ((val1 & 4) == 4);
6487 /* if link is up
6488 * print the AN outcome of the SFX7101 PHY
6489 */
6490 if (link_up) {
6491 bnx2x_cl45_read(bp, phy,
6492 MDIO_AN_DEVAD, MDIO_AN_REG_MASTER_STATUS,
6493 &val2);
6494 vars->line_speed = SPEED_10000;
6495 DP(NETIF_MSG_LINK, "SFX7101 AN status 0x%x->Master=%x\n",
6496 val2, (val2 & (1<<14)));
6497 bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
6498 bnx2x_ext_phy_resolve_fc(phy, params, vars);
6499 }
6500 return link_up;
6501}
6502
6503
6504static u8 bnx2x_7101_format_ver(u32 spirom_ver, u8 *str, u16 *len)
6505{
6506 if (*len < 5)
6507 return -EINVAL;
6508 str[0] = (spirom_ver & 0xFF);
6509 str[1] = (spirom_ver & 0xFF00) >> 8;
6510 str[2] = (spirom_ver & 0xFF0000) >> 16;
6511 str[3] = (spirom_ver & 0xFF000000) >> 24;
6512 str[4] = '\0';
6513 *len -= 5;
6514 return 0;
6515}
6516
6517void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, struct bnx2x_phy *phy)
6518{
6519 u16 val, cnt;
6520
6521 bnx2x_cl45_read(bp, phy,
6522 MDIO_PMA_DEVAD,
6523 MDIO_PMA_REG_7101_RESET, &val);
6524
6525 for (cnt = 0; cnt < 10; cnt++) {
6526 msleep(50);
6527 /* Writes a self-clearing reset */
6528 bnx2x_cl45_write(bp, phy,
6529 MDIO_PMA_DEVAD,
6530 MDIO_PMA_REG_7101_RESET,
6531 (val | (1<<15)));
6532 /* Wait for clear */
6533 bnx2x_cl45_read(bp, phy,
6534 MDIO_PMA_DEVAD,
6535 MDIO_PMA_REG_7101_RESET, &val);
6536
6537 if ((val & (1<<15)) == 0)
6538 break;
6539 }
6540}
6541
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006542static void bnx2x_7101_hw_reset(struct bnx2x_phy *phy,
6543 struct link_params *params) {
6544 /* Low power mode is controlled by GPIO 2 */
6545 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_2,
6546 MISC_REGISTERS_GPIO_OUTPUT_LOW, params->port);
6547 /* The PHY reset is controlled by GPIO 1 */
6548 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
6549 MISC_REGISTERS_GPIO_OUTPUT_LOW, params->port);
6550}
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006551
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006552static void bnx2x_7101_set_link_led(struct bnx2x_phy *phy,
6553 struct link_params *params, u8 mode)
6554{
6555 u16 val = 0;
6556 struct bnx2x *bp = params->bp;
6557 switch (mode) {
6558 case LED_MODE_FRONT_PANEL_OFF:
6559 case LED_MODE_OFF:
6560 val = 2;
6561 break;
6562 case LED_MODE_ON:
6563 val = 1;
6564 break;
6565 case LED_MODE_OPER:
6566 val = 0;
6567 break;
6568 }
6569 bnx2x_cl45_write(bp, phy,
6570 MDIO_PMA_DEVAD,
6571 MDIO_PMA_REG_7107_LINK_LED_CNTL,
6572 val);
6573}
6574
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006575/******************************************************************/
6576/* STATIC PHY DECLARATION */
6577/******************************************************************/
6578
6579static struct bnx2x_phy phy_null = {
6580 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN,
6581 .addr = 0,
6582 .flags = FLAGS_INIT_XGXS_FIRST,
6583 .def_md_devad = 0,
6584 .reserved = 0,
6585 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6586 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6587 .mdio_ctrl = 0,
6588 .supported = 0,
6589 .media_type = ETH_PHY_NOT_PRESENT,
6590 .ver_addr = 0,
6591 .req_flow_ctrl = 0,
6592 .req_line_speed = 0,
6593 .speed_cap_mask = 0,
6594 .req_duplex = 0,
6595 .rsrv = 0,
6596 .config_init = (config_init_t)NULL,
6597 .read_status = (read_status_t)NULL,
6598 .link_reset = (link_reset_t)NULL,
6599 .config_loopback = (config_loopback_t)NULL,
6600 .format_fw_ver = (format_fw_ver_t)NULL,
6601 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006602 .set_link_led = (set_link_led_t)NULL,
6603 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006604};
6605
6606static struct bnx2x_phy phy_serdes = {
6607 .type = PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT,
6608 .addr = 0xff,
6609 .flags = 0,
6610 .def_md_devad = 0,
6611 .reserved = 0,
6612 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6613 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6614 .mdio_ctrl = 0,
6615 .supported = (SUPPORTED_10baseT_Half |
6616 SUPPORTED_10baseT_Full |
6617 SUPPORTED_100baseT_Half |
6618 SUPPORTED_100baseT_Full |
6619 SUPPORTED_1000baseT_Full |
6620 SUPPORTED_2500baseX_Full |
6621 SUPPORTED_TP |
6622 SUPPORTED_Autoneg |
6623 SUPPORTED_Pause |
6624 SUPPORTED_Asym_Pause),
6625 .media_type = ETH_PHY_UNSPECIFIED,
6626 .ver_addr = 0,
6627 .req_flow_ctrl = 0,
6628 .req_line_speed = 0,
6629 .speed_cap_mask = 0,
6630 .req_duplex = 0,
6631 .rsrv = 0,
6632 .config_init = (config_init_t)bnx2x_init_serdes,
6633 .read_status = (read_status_t)bnx2x_link_settings_status,
6634 .link_reset = (link_reset_t)bnx2x_int_link_reset,
6635 .config_loopback = (config_loopback_t)NULL,
6636 .format_fw_ver = (format_fw_ver_t)NULL,
6637 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006638 .set_link_led = (set_link_led_t)NULL,
6639 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006640};
6641
6642static struct bnx2x_phy phy_xgxs = {
6643 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT,
6644 .addr = 0xff,
6645 .flags = 0,
6646 .def_md_devad = 0,
6647 .reserved = 0,
6648 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6649 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6650 .mdio_ctrl = 0,
6651 .supported = (SUPPORTED_10baseT_Half |
6652 SUPPORTED_10baseT_Full |
6653 SUPPORTED_100baseT_Half |
6654 SUPPORTED_100baseT_Full |
6655 SUPPORTED_1000baseT_Full |
6656 SUPPORTED_2500baseX_Full |
6657 SUPPORTED_10000baseT_Full |
6658 SUPPORTED_FIBRE |
6659 SUPPORTED_Autoneg |
6660 SUPPORTED_Pause |
6661 SUPPORTED_Asym_Pause),
6662 .media_type = ETH_PHY_UNSPECIFIED,
6663 .ver_addr = 0,
6664 .req_flow_ctrl = 0,
6665 .req_line_speed = 0,
6666 .speed_cap_mask = 0,
6667 .req_duplex = 0,
6668 .rsrv = 0,
6669 .config_init = (config_init_t)bnx2x_init_xgxs,
6670 .read_status = (read_status_t)bnx2x_link_settings_status,
6671 .link_reset = (link_reset_t)bnx2x_int_link_reset,
6672 .config_loopback = (config_loopback_t)bnx2x_set_xgxs_loopback,
6673 .format_fw_ver = (format_fw_ver_t)NULL,
6674 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006675 .set_link_led = (set_link_led_t)NULL,
6676 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006677};
6678
6679static struct bnx2x_phy phy_7101 = {
6680 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
6681 .addr = 0xff,
6682 .flags = FLAGS_FAN_FAILURE_DET_REQ,
6683 .def_md_devad = 0,
6684 .reserved = 0,
6685 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6686 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6687 .mdio_ctrl = 0,
6688 .supported = (SUPPORTED_10000baseT_Full |
6689 SUPPORTED_TP |
6690 SUPPORTED_Autoneg |
6691 SUPPORTED_Pause |
6692 SUPPORTED_Asym_Pause),
6693 .media_type = ETH_PHY_BASE_T,
6694 .ver_addr = 0,
6695 .req_flow_ctrl = 0,
6696 .req_line_speed = 0,
6697 .speed_cap_mask = 0,
6698 .req_duplex = 0,
6699 .rsrv = 0,
6700 .config_init = (config_init_t)bnx2x_7101_config_init,
6701 .read_status = (read_status_t)bnx2x_7101_read_status,
6702 .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
6703 .config_loopback = (config_loopback_t)bnx2x_7101_config_loopback,
6704 .format_fw_ver = (format_fw_ver_t)bnx2x_7101_format_ver,
6705 .hw_reset = (hw_reset_t)bnx2x_7101_hw_reset,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006706 .set_link_led = (set_link_led_t)bnx2x_7101_set_link_led,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006707 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006708};
6709static struct bnx2x_phy phy_8073 = {
6710 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
6711 .addr = 0xff,
6712 .flags = FLAGS_HW_LOCK_REQUIRED,
6713 .def_md_devad = 0,
6714 .reserved = 0,
6715 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6716 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6717 .mdio_ctrl = 0,
6718 .supported = (SUPPORTED_10000baseT_Full |
6719 SUPPORTED_2500baseX_Full |
6720 SUPPORTED_1000baseT_Full |
6721 SUPPORTED_FIBRE |
6722 SUPPORTED_Autoneg |
6723 SUPPORTED_Pause |
6724 SUPPORTED_Asym_Pause),
6725 .media_type = ETH_PHY_UNSPECIFIED,
6726 .ver_addr = 0,
6727 .req_flow_ctrl = 0,
6728 .req_line_speed = 0,
6729 .speed_cap_mask = 0,
6730 .req_duplex = 0,
6731 .rsrv = 0,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00006732 .config_init = (config_init_t)bnx2x_8073_config_init,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006733 .read_status = (read_status_t)bnx2x_8073_read_status,
6734 .link_reset = (link_reset_t)bnx2x_8073_link_reset,
6735 .config_loopback = (config_loopback_t)NULL,
6736 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
6737 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006738 .set_link_led = (set_link_led_t)NULL,
6739 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006740};
6741static struct bnx2x_phy phy_8705 = {
6742 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705,
6743 .addr = 0xff,
6744 .flags = FLAGS_INIT_XGXS_FIRST,
6745 .def_md_devad = 0,
6746 .reserved = 0,
6747 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6748 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6749 .mdio_ctrl = 0,
6750 .supported = (SUPPORTED_10000baseT_Full |
6751 SUPPORTED_FIBRE |
6752 SUPPORTED_Pause |
6753 SUPPORTED_Asym_Pause),
6754 .media_type = ETH_PHY_XFP_FIBER,
6755 .ver_addr = 0,
6756 .req_flow_ctrl = 0,
6757 .req_line_speed = 0,
6758 .speed_cap_mask = 0,
6759 .req_duplex = 0,
6760 .rsrv = 0,
6761 .config_init = (config_init_t)bnx2x_8705_config_init,
6762 .read_status = (read_status_t)bnx2x_8705_read_status,
6763 .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
6764 .config_loopback = (config_loopback_t)NULL,
6765 .format_fw_ver = (format_fw_ver_t)bnx2x_null_format_ver,
6766 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006767 .set_link_led = (set_link_led_t)NULL,
6768 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006769};
6770static struct bnx2x_phy phy_8706 = {
6771 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706,
6772 .addr = 0xff,
6773 .flags = FLAGS_INIT_XGXS_FIRST,
6774 .def_md_devad = 0,
6775 .reserved = 0,
6776 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6777 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6778 .mdio_ctrl = 0,
6779 .supported = (SUPPORTED_10000baseT_Full |
6780 SUPPORTED_1000baseT_Full |
6781 SUPPORTED_FIBRE |
6782 SUPPORTED_Pause |
6783 SUPPORTED_Asym_Pause),
6784 .media_type = ETH_PHY_SFP_FIBER,
6785 .ver_addr = 0,
6786 .req_flow_ctrl = 0,
6787 .req_line_speed = 0,
6788 .speed_cap_mask = 0,
6789 .req_duplex = 0,
6790 .rsrv = 0,
6791 .config_init = (config_init_t)bnx2x_8706_config_init,
6792 .read_status = (read_status_t)bnx2x_8706_read_status,
6793 .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
6794 .config_loopback = (config_loopback_t)NULL,
6795 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
6796 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006797 .set_link_led = (set_link_led_t)NULL,
6798 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006799};
6800
6801static struct bnx2x_phy phy_8726 = {
6802 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
6803 .addr = 0xff,
6804 .flags = (FLAGS_HW_LOCK_REQUIRED |
6805 FLAGS_INIT_XGXS_FIRST),
6806 .def_md_devad = 0,
6807 .reserved = 0,
6808 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6809 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6810 .mdio_ctrl = 0,
6811 .supported = (SUPPORTED_10000baseT_Full |
6812 SUPPORTED_1000baseT_Full |
6813 SUPPORTED_Autoneg |
6814 SUPPORTED_FIBRE |
6815 SUPPORTED_Pause |
6816 SUPPORTED_Asym_Pause),
6817 .media_type = ETH_PHY_SFP_FIBER,
6818 .ver_addr = 0,
6819 .req_flow_ctrl = 0,
6820 .req_line_speed = 0,
6821 .speed_cap_mask = 0,
6822 .req_duplex = 0,
6823 .rsrv = 0,
6824 .config_init = (config_init_t)bnx2x_8726_config_init,
6825 .read_status = (read_status_t)bnx2x_8726_read_status,
6826 .link_reset = (link_reset_t)bnx2x_8726_link_reset,
6827 .config_loopback = (config_loopback_t)bnx2x_8726_config_loopback,
6828 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
6829 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006830 .set_link_led = (set_link_led_t)NULL,
6831 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006832};
6833
6834static struct bnx2x_phy phy_8727 = {
6835 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
6836 .addr = 0xff,
6837 .flags = FLAGS_FAN_FAILURE_DET_REQ,
6838 .def_md_devad = 0,
6839 .reserved = 0,
6840 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6841 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6842 .mdio_ctrl = 0,
6843 .supported = (SUPPORTED_10000baseT_Full |
6844 SUPPORTED_1000baseT_Full |
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006845 SUPPORTED_FIBRE |
6846 SUPPORTED_Pause |
6847 SUPPORTED_Asym_Pause),
6848 .media_type = ETH_PHY_SFP_FIBER,
6849 .ver_addr = 0,
6850 .req_flow_ctrl = 0,
6851 .req_line_speed = 0,
6852 .speed_cap_mask = 0,
6853 .req_duplex = 0,
6854 .rsrv = 0,
6855 .config_init = (config_init_t)bnx2x_8727_config_init,
6856 .read_status = (read_status_t)bnx2x_8727_read_status,
6857 .link_reset = (link_reset_t)bnx2x_8727_link_reset,
6858 .config_loopback = (config_loopback_t)NULL,
6859 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
6860 .hw_reset = (hw_reset_t)bnx2x_8727_hw_reset,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006861 .set_link_led = (set_link_led_t)bnx2x_8727_set_link_led,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006862 .phy_specific_func = (phy_specific_func_t)bnx2x_8727_specific_func
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006863};
6864static struct bnx2x_phy phy_8481 = {
6865 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
6866 .addr = 0xff,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006867 .flags = FLAGS_FAN_FAILURE_DET_REQ |
6868 FLAGS_REARM_LATCH_SIGNAL,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006869 .def_md_devad = 0,
6870 .reserved = 0,
6871 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6872 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6873 .mdio_ctrl = 0,
6874 .supported = (SUPPORTED_10baseT_Half |
6875 SUPPORTED_10baseT_Full |
6876 SUPPORTED_100baseT_Half |
6877 SUPPORTED_100baseT_Full |
6878 SUPPORTED_1000baseT_Full |
6879 SUPPORTED_10000baseT_Full |
6880 SUPPORTED_TP |
6881 SUPPORTED_Autoneg |
6882 SUPPORTED_Pause |
6883 SUPPORTED_Asym_Pause),
6884 .media_type = ETH_PHY_BASE_T,
6885 .ver_addr = 0,
6886 .req_flow_ctrl = 0,
6887 .req_line_speed = 0,
6888 .speed_cap_mask = 0,
6889 .req_duplex = 0,
6890 .rsrv = 0,
6891 .config_init = (config_init_t)bnx2x_8481_config_init,
6892 .read_status = (read_status_t)bnx2x_848xx_read_status,
6893 .link_reset = (link_reset_t)bnx2x_8481_link_reset,
6894 .config_loopback = (config_loopback_t)NULL,
6895 .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver,
6896 .hw_reset = (hw_reset_t)bnx2x_8481_hw_reset,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006897 .set_link_led = (set_link_led_t)bnx2x_848xx_set_link_led,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006898 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006899};
6900
6901static struct bnx2x_phy phy_84823 = {
6902 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823,
6903 .addr = 0xff,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006904 .flags = FLAGS_FAN_FAILURE_DET_REQ |
6905 FLAGS_REARM_LATCH_SIGNAL,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006906 .def_md_devad = 0,
6907 .reserved = 0,
6908 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6909 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6910 .mdio_ctrl = 0,
6911 .supported = (SUPPORTED_10baseT_Half |
6912 SUPPORTED_10baseT_Full |
6913 SUPPORTED_100baseT_Half |
6914 SUPPORTED_100baseT_Full |
6915 SUPPORTED_1000baseT_Full |
6916 SUPPORTED_10000baseT_Full |
6917 SUPPORTED_TP |
6918 SUPPORTED_Autoneg |
6919 SUPPORTED_Pause |
6920 SUPPORTED_Asym_Pause),
6921 .media_type = ETH_PHY_BASE_T,
6922 .ver_addr = 0,
6923 .req_flow_ctrl = 0,
6924 .req_line_speed = 0,
6925 .speed_cap_mask = 0,
6926 .req_duplex = 0,
6927 .rsrv = 0,
6928 .config_init = (config_init_t)bnx2x_848x3_config_init,
6929 .read_status = (read_status_t)bnx2x_848xx_read_status,
6930 .link_reset = (link_reset_t)bnx2x_848x3_link_reset,
6931 .config_loopback = (config_loopback_t)NULL,
6932 .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver,
6933 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006934 .set_link_led = (set_link_led_t)bnx2x_848xx_set_link_led,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006935 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006936};
6937
6938/*****************************************************************/
6939/* */
6940/* Populate the phy according. Main function: bnx2x_populate_phy */
6941/* */
6942/*****************************************************************/
6943
6944static void bnx2x_populate_preemphasis(struct bnx2x *bp, u32 shmem_base,
6945 struct bnx2x_phy *phy, u8 port,
6946 u8 phy_index)
6947{
6948 /* Get the 4 lanes xgxs config rx and tx */
6949 u32 rx = 0, tx = 0, i;
6950 for (i = 0; i < 2; i++) {
6951 /**
6952 * INT_PHY and EXT_PHY1 share the same value location in the
6953 * shmem. When num_phys is greater than 1, than this value
6954 * applies only to EXT_PHY1
6955 */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006956 if (phy_index == INT_PHY || phy_index == EXT_PHY1) {
6957 rx = REG_RD(bp, shmem_base +
6958 offsetof(struct shmem_region,
6959 dev_info.port_hw_config[port].xgxs_config_rx[i<<1]));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006960
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006961 tx = REG_RD(bp, shmem_base +
6962 offsetof(struct shmem_region,
6963 dev_info.port_hw_config[port].xgxs_config_tx[i<<1]));
6964 } else {
6965 rx = REG_RD(bp, shmem_base +
6966 offsetof(struct shmem_region,
6967 dev_info.port_hw_config[port].xgxs_config2_rx[i<<1]));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006968
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006969 tx = REG_RD(bp, shmem_base +
6970 offsetof(struct shmem_region,
6971 dev_info.port_hw_config[port].xgxs_config2_rx[i<<1]));
6972 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006973
6974 phy->rx_preemphasis[i << 1] = ((rx>>16) & 0xffff);
6975 phy->rx_preemphasis[(i << 1) + 1] = (rx & 0xffff);
6976
6977 phy->tx_preemphasis[i << 1] = ((tx>>16) & 0xffff);
6978 phy->tx_preemphasis[(i << 1) + 1] = (tx & 0xffff);
6979 }
6980}
6981
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006982static u32 bnx2x_get_ext_phy_config(struct bnx2x *bp, u32 shmem_base,
6983 u8 phy_index, u8 port)
6984{
6985 u32 ext_phy_config = 0;
6986 switch (phy_index) {
6987 case EXT_PHY1:
6988 ext_phy_config = REG_RD(bp, shmem_base +
6989 offsetof(struct shmem_region,
6990 dev_info.port_hw_config[port].external_phy_config));
6991 break;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006992 case EXT_PHY2:
6993 ext_phy_config = REG_RD(bp, shmem_base +
6994 offsetof(struct shmem_region,
6995 dev_info.port_hw_config[port].external_phy_config2));
6996 break;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006997 default:
6998 DP(NETIF_MSG_LINK, "Invalid phy_index %d\n", phy_index);
6999 return -EINVAL;
7000 }
7001
7002 return ext_phy_config;
7003}
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007004static u8 bnx2x_populate_int_phy(struct bnx2x *bp, u32 shmem_base, u8 port,
7005 struct bnx2x_phy *phy)
7006{
7007 u32 phy_addr;
7008 u32 chip_id;
7009 u32 switch_cfg = (REG_RD(bp, shmem_base +
7010 offsetof(struct shmem_region,
7011 dev_info.port_feature_config[port].link_config)) &
7012 PORT_FEATURE_CONNECTED_SWITCH_MASK);
7013 chip_id = REG_RD(bp, MISC_REG_CHIP_NUM) << 16;
7014 switch (switch_cfg) {
7015 case SWITCH_CFG_1G:
7016 phy_addr = REG_RD(bp,
7017 NIG_REG_SERDES0_CTRL_PHY_ADDR +
7018 port * 0x10);
7019 *phy = phy_serdes;
7020 break;
7021 case SWITCH_CFG_10G:
7022 phy_addr = REG_RD(bp,
7023 NIG_REG_XGXS0_CTRL_PHY_ADDR +
7024 port * 0x18);
7025 *phy = phy_xgxs;
7026 break;
7027 default:
7028 DP(NETIF_MSG_LINK, "Invalid switch_cfg\n");
7029 return -EINVAL;
7030 }
7031 phy->addr = (u8)phy_addr;
7032 phy->mdio_ctrl = bnx2x_get_emac_base(bp,
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007033 SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007034 port);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007035 if (CHIP_IS_E2(bp))
7036 phy->def_md_devad = E2_DEFAULT_PHY_DEV_ADDR;
7037 else
7038 phy->def_md_devad = DEFAULT_PHY_DEV_ADDR;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007039
7040 DP(NETIF_MSG_LINK, "Internal phy port=%d, addr=0x%x, mdio_ctl=0x%x\n",
7041 port, phy->addr, phy->mdio_ctrl);
7042
7043 bnx2x_populate_preemphasis(bp, shmem_base, phy, port, INT_PHY);
7044 return 0;
7045}
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007046
7047static u8 bnx2x_populate_ext_phy(struct bnx2x *bp,
7048 u8 phy_index,
7049 u32 shmem_base,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007050 u32 shmem2_base,
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007051 u8 port,
7052 struct bnx2x_phy *phy)
7053{
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007054 u32 ext_phy_config, phy_type, config2;
7055 u32 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007056 ext_phy_config = bnx2x_get_ext_phy_config(bp, shmem_base,
7057 phy_index, port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007058 phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
7059 /* Select the phy type */
7060 switch (phy_type) {
7061 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007062 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_SWAPPED;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007063 *phy = phy_8073;
7064 break;
7065 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
7066 *phy = phy_8705;
7067 break;
7068 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
7069 *phy = phy_8706;
7070 break;
7071 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007072 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007073 *phy = phy_8726;
7074 break;
7075 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
7076 /* BCM8727_NOC => BCM8727 no over current */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007077 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007078 *phy = phy_8727;
7079 phy->flags |= FLAGS_NOC;
7080 break;
7081 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007082 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007083 *phy = phy_8727;
7084 break;
7085 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
7086 *phy = phy_8481;
7087 break;
7088 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
7089 *phy = phy_84823;
7090 break;
7091 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
7092 *phy = phy_7101;
7093 break;
7094 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
7095 *phy = phy_null;
7096 return -EINVAL;
7097 default:
7098 *phy = phy_null;
7099 return 0;
7100 }
7101
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007102 phy->addr = XGXS_EXT_PHY_ADDR(ext_phy_config);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007103 bnx2x_populate_preemphasis(bp, shmem_base, phy, port, phy_index);
Yaniv Rosner62b29a52010-09-07 11:40:58 +00007104
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007105 /**
7106 * The shmem address of the phy version is located on different
7107 * structures. In case this structure is too old, do not set
7108 * the address
7109 */
7110 config2 = REG_RD(bp, shmem_base + offsetof(struct shmem_region,
7111 dev_info.shared_hw_config.config2));
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007112 if (phy_index == EXT_PHY1) {
7113 phy->ver_addr = shmem_base + offsetof(struct shmem_region,
7114 port_mb[port].ext_phy_fw_version);
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007115
7116 /* Check specific mdc mdio settings */
7117 if (config2 & SHARED_HW_CFG_MDC_MDIO_ACCESS1_MASK)
7118 mdc_mdio_access = config2 &
7119 SHARED_HW_CFG_MDC_MDIO_ACCESS1_MASK;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007120 } else {
7121 u32 size = REG_RD(bp, shmem2_base);
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007122
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007123 if (size >
7124 offsetof(struct shmem2_region, ext_phy_fw_version2)) {
7125 phy->ver_addr = shmem2_base +
7126 offsetof(struct shmem2_region,
7127 ext_phy_fw_version2[port]);
7128 }
7129 /* Check specific mdc mdio settings */
7130 if (config2 & SHARED_HW_CFG_MDC_MDIO_ACCESS2_MASK)
7131 mdc_mdio_access = (config2 &
7132 SHARED_HW_CFG_MDC_MDIO_ACCESS2_MASK) >>
7133 (SHARED_HW_CFG_MDC_MDIO_ACCESS2_SHIFT -
7134 SHARED_HW_CFG_MDC_MDIO_ACCESS1_SHIFT);
7135 }
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007136 phy->mdio_ctrl = bnx2x_get_emac_base(bp, mdc_mdio_access, port);
7137
7138 /**
7139 * In case mdc/mdio_access of the external phy is different than the
7140 * mdc/mdio access of the XGXS, a HW lock must be taken in each access
7141 * to prevent one port interfere with another port's CL45 operations.
7142 */
7143 if (mdc_mdio_access != SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH)
7144 phy->flags |= FLAGS_HW_LOCK_REQUIRED;
7145 DP(NETIF_MSG_LINK, "phy_type 0x%x port %d found in index %d\n",
7146 phy_type, port, phy_index);
7147 DP(NETIF_MSG_LINK, " addr=0x%x, mdio_ctl=0x%x\n",
7148 phy->addr, phy->mdio_ctrl);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007149 return 0;
7150}
7151
7152static u8 bnx2x_populate_phy(struct bnx2x *bp, u8 phy_index, u32 shmem_base,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007153 u32 shmem2_base, u8 port, struct bnx2x_phy *phy)
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007154{
7155 u8 status = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007156 phy->type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN;
7157 if (phy_index == INT_PHY)
7158 return bnx2x_populate_int_phy(bp, shmem_base, port, phy);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007159 status = bnx2x_populate_ext_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007160 port, phy);
7161 return status;
7162}
7163
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007164static void bnx2x_phy_def_cfg(struct link_params *params,
7165 struct bnx2x_phy *phy,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007166 u8 phy_index)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007167{
7168 struct bnx2x *bp = params->bp;
7169 u32 link_config;
7170 /* Populate the default phy configuration for MF mode */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007171 if (phy_index == EXT_PHY2) {
7172 link_config = REG_RD(bp, params->shmem_base +
7173 offsetof(struct shmem_region, dev_info.
7174 port_feature_config[params->port].link_config2));
7175 phy->speed_cap_mask = REG_RD(bp, params->shmem_base +
7176 offsetof(struct shmem_region, dev_info.
7177 port_hw_config[params->port].speed_capability_mask2));
7178 } else {
7179 link_config = REG_RD(bp, params->shmem_base +
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007180 offsetof(struct shmem_region, dev_info.
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007181 port_feature_config[params->port].link_config));
7182 phy->speed_cap_mask = REG_RD(bp, params->shmem_base +
7183 offsetof(struct shmem_region, dev_info.
7184 port_hw_config[params->port].speed_capability_mask));
7185 }
7186 DP(NETIF_MSG_LINK, "Default config phy idx %x cfg 0x%x speed_cap_mask"
7187 " 0x%x\n", phy_index, link_config, phy->speed_cap_mask);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007188
7189 phy->req_duplex = DUPLEX_FULL;
7190 switch (link_config & PORT_FEATURE_LINK_SPEED_MASK) {
7191 case PORT_FEATURE_LINK_SPEED_10M_HALF:
7192 phy->req_duplex = DUPLEX_HALF;
7193 case PORT_FEATURE_LINK_SPEED_10M_FULL:
7194 phy->req_line_speed = SPEED_10;
7195 break;
7196 case PORT_FEATURE_LINK_SPEED_100M_HALF:
7197 phy->req_duplex = DUPLEX_HALF;
7198 case PORT_FEATURE_LINK_SPEED_100M_FULL:
7199 phy->req_line_speed = SPEED_100;
7200 break;
7201 case PORT_FEATURE_LINK_SPEED_1G:
7202 phy->req_line_speed = SPEED_1000;
7203 break;
7204 case PORT_FEATURE_LINK_SPEED_2_5G:
7205 phy->req_line_speed = SPEED_2500;
7206 break;
7207 case PORT_FEATURE_LINK_SPEED_10G_CX4:
7208 phy->req_line_speed = SPEED_10000;
7209 break;
7210 default:
7211 phy->req_line_speed = SPEED_AUTO_NEG;
7212 break;
7213 }
7214
7215 switch (link_config & PORT_FEATURE_FLOW_CONTROL_MASK) {
7216 case PORT_FEATURE_FLOW_CONTROL_AUTO:
7217 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_AUTO;
7218 break;
7219 case PORT_FEATURE_FLOW_CONTROL_TX:
7220 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_TX;
7221 break;
7222 case PORT_FEATURE_FLOW_CONTROL_RX:
7223 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_RX;
7224 break;
7225 case PORT_FEATURE_FLOW_CONTROL_BOTH:
7226 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_BOTH;
7227 break;
7228 default:
7229 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_NONE;
7230 break;
7231 }
7232}
7233
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007234u32 bnx2x_phy_selection(struct link_params *params)
7235{
7236 u32 phy_config_swapped, prio_cfg;
7237 u32 return_cfg = PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT;
7238
7239 phy_config_swapped = params->multi_phy_config &
7240 PORT_HW_CFG_PHY_SWAPPED_ENABLED;
7241
7242 prio_cfg = params->multi_phy_config &
7243 PORT_HW_CFG_PHY_SELECTION_MASK;
7244
7245 if (phy_config_swapped) {
7246 switch (prio_cfg) {
7247 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
7248 return_cfg = PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY;
7249 break;
7250 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
7251 return_cfg = PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY;
7252 break;
7253 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY:
7254 return_cfg = PORT_HW_CFG_PHY_SELECTION_FIRST_PHY;
7255 break;
7256 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY:
7257 return_cfg = PORT_HW_CFG_PHY_SELECTION_SECOND_PHY;
7258 break;
7259 }
7260 } else
7261 return_cfg = prio_cfg;
7262
7263 return return_cfg;
7264}
7265
7266
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007267u8 bnx2x_phy_probe(struct link_params *params)
7268{
7269 u8 phy_index, actual_phy_idx, link_cfg_idx;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007270 u32 phy_config_swapped;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007271 struct bnx2x *bp = params->bp;
7272 struct bnx2x_phy *phy;
7273 params->num_phys = 0;
7274 DP(NETIF_MSG_LINK, "Begin phy probe\n");
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007275 phy_config_swapped = params->multi_phy_config &
7276 PORT_HW_CFG_PHY_SWAPPED_ENABLED;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007277
7278 for (phy_index = INT_PHY; phy_index < MAX_PHYS;
7279 phy_index++) {
7280 link_cfg_idx = LINK_CONFIG_IDX(phy_index);
7281 actual_phy_idx = phy_index;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007282 if (phy_config_swapped) {
7283 if (phy_index == EXT_PHY1)
7284 actual_phy_idx = EXT_PHY2;
7285 else if (phy_index == EXT_PHY2)
7286 actual_phy_idx = EXT_PHY1;
7287 }
7288 DP(NETIF_MSG_LINK, "phy_config_swapped %x, phy_index %x,"
7289 " actual_phy_idx %x\n", phy_config_swapped,
7290 phy_index, actual_phy_idx);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007291 phy = &params->phy[actual_phy_idx];
7292 if (bnx2x_populate_phy(bp, phy_index, params->shmem_base,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007293 params->shmem2_base, params->port,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007294 phy) != 0) {
7295 params->num_phys = 0;
7296 DP(NETIF_MSG_LINK, "phy probe failed in phy index %d\n",
7297 phy_index);
7298 for (phy_index = INT_PHY;
7299 phy_index < MAX_PHYS;
7300 phy_index++)
7301 *phy = phy_null;
7302 return -EINVAL;
7303 }
7304 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)
7305 break;
7306
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007307 bnx2x_phy_def_cfg(params, phy, phy_index);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007308 params->num_phys++;
7309 }
7310
7311 DP(NETIF_MSG_LINK, "End phy probe. #phys found %x\n", params->num_phys);
7312 return 0;
7313}
7314
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007315static void set_phy_vars(struct link_params *params)
7316{
7317 struct bnx2x *bp = params->bp;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007318 u8 actual_phy_idx, phy_index, link_cfg_idx;
7319 u8 phy_config_swapped = params->multi_phy_config &
7320 PORT_HW_CFG_PHY_SWAPPED_ENABLED;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007321 for (phy_index = INT_PHY; phy_index < params->num_phys;
7322 phy_index++) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007323 link_cfg_idx = LINK_CONFIG_IDX(phy_index);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007324 actual_phy_idx = phy_index;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007325 if (phy_config_swapped) {
7326 if (phy_index == EXT_PHY1)
7327 actual_phy_idx = EXT_PHY2;
7328 else if (phy_index == EXT_PHY2)
7329 actual_phy_idx = EXT_PHY1;
7330 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007331 params->phy[actual_phy_idx].req_flow_ctrl =
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007332 params->req_flow_ctrl[link_cfg_idx];
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007333
7334 params->phy[actual_phy_idx].req_line_speed =
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007335 params->req_line_speed[link_cfg_idx];
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007336
7337 params->phy[actual_phy_idx].speed_cap_mask =
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007338 params->speed_cap_mask[link_cfg_idx];
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007339
7340 params->phy[actual_phy_idx].req_duplex =
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007341 params->req_duplex[link_cfg_idx];
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007342
7343 DP(NETIF_MSG_LINK, "req_flow_ctrl %x, req_line_speed %x,"
7344 " speed_cap_mask %x\n",
7345 params->phy[actual_phy_idx].req_flow_ctrl,
7346 params->phy[actual_phy_idx].req_line_speed,
7347 params->phy[actual_phy_idx].speed_cap_mask);
7348 }
7349}
7350
7351u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
7352{
7353 struct bnx2x *bp = params->bp;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007354 DP(NETIF_MSG_LINK, "Phy Initialization started\n");
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007355 DP(NETIF_MSG_LINK, "(1) req_speed %d, req_flowctrl %d\n",
7356 params->req_line_speed[0], params->req_flow_ctrl[0]);
7357 DP(NETIF_MSG_LINK, "(2) req_speed %d, req_flowctrl %d\n",
7358 params->req_line_speed[1], params->req_flow_ctrl[1]);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007359 vars->link_status = 0;
7360 vars->phy_link_up = 0;
7361 vars->link_up = 0;
7362 vars->line_speed = 0;
7363 vars->duplex = DUPLEX_FULL;
7364 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
7365 vars->mac_type = MAC_TYPE_NONE;
7366 vars->phy_flags = 0;
7367
7368 /* disable attentions */
7369 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4,
7370 (NIG_MASK_XGXS0_LINK_STATUS |
7371 NIG_MASK_XGXS0_LINK10G |
7372 NIG_MASK_SERDES0_LINK_STATUS |
7373 NIG_MASK_MI_INT));
7374
7375 bnx2x_emac_init(params, vars);
7376
7377 if (params->num_phys == 0) {
7378 DP(NETIF_MSG_LINK, "No phy found for initialization !!\n");
7379 return -EINVAL;
7380 }
7381 set_phy_vars(params);
7382
7383 DP(NETIF_MSG_LINK, "Num of phys on board: %d\n", params->num_phys);
7384 if (CHIP_REV_IS_FPGA(bp)) {
7385
7386 vars->link_up = 1;
7387 vars->line_speed = SPEED_10000;
7388 vars->duplex = DUPLEX_FULL;
7389 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
7390 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
7391 /* enable on E1.5 FPGA */
7392 if (CHIP_IS_E1H(bp)) {
7393 vars->flow_ctrl |=
7394 (BNX2X_FLOW_CTRL_TX |
7395 BNX2X_FLOW_CTRL_RX);
7396 vars->link_status |=
7397 (LINK_STATUS_TX_FLOW_CONTROL_ENABLED |
7398 LINK_STATUS_RX_FLOW_CONTROL_ENABLED);
7399 }
7400
7401 bnx2x_emac_enable(params, vars, 0);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007402 if (!(CHIP_IS_E2(bp)))
7403 bnx2x_pbf_update(params, vars->flow_ctrl,
7404 vars->line_speed);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007405 /* disable drain */
7406 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
7407
7408 /* update shared memory */
7409 bnx2x_update_mng(params, vars->link_status);
7410
7411 return 0;
7412
7413 } else
7414 if (CHIP_REV_IS_EMUL(bp)) {
7415
7416 vars->link_up = 1;
7417 vars->line_speed = SPEED_10000;
7418 vars->duplex = DUPLEX_FULL;
7419 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
7420 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
7421
7422 bnx2x_bmac_enable(params, vars, 0);
7423
7424 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
7425 /* Disable drain */
7426 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
7427 + params->port*4, 0);
7428
7429 /* update shared memory */
7430 bnx2x_update_mng(params, vars->link_status);
7431
7432 return 0;
7433
7434 } else
7435 if (params->loopback_mode == LOOPBACK_BMAC) {
7436
7437 vars->link_up = 1;
7438 vars->line_speed = SPEED_10000;
7439 vars->duplex = DUPLEX_FULL;
7440 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
7441 vars->mac_type = MAC_TYPE_BMAC;
7442
7443 vars->phy_flags = PHY_XGXS_FLAG;
7444
7445 bnx2x_xgxs_deassert(params);
7446
7447 /* set bmac loopback */
7448 bnx2x_bmac_enable(params, vars, 1);
7449
7450 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
7451 params->port*4, 0);
7452
7453 } else if (params->loopback_mode == LOOPBACK_EMAC) {
7454
7455 vars->link_up = 1;
7456 vars->line_speed = SPEED_1000;
7457 vars->duplex = DUPLEX_FULL;
7458 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
7459 vars->mac_type = MAC_TYPE_EMAC;
7460
7461 vars->phy_flags = PHY_XGXS_FLAG;
7462
7463 bnx2x_xgxs_deassert(params);
7464 /* set bmac loopback */
7465 bnx2x_emac_enable(params, vars, 1);
7466 bnx2x_emac_program(params, vars);
7467 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
7468 params->port*4, 0);
7469
7470 } else if ((params->loopback_mode == LOOPBACK_XGXS) ||
7471 (params->loopback_mode == LOOPBACK_EXT_PHY)) {
7472
7473 vars->link_up = 1;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007474 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007475 vars->duplex = DUPLEX_FULL;
7476 if (params->req_line_speed[0] == SPEED_1000) {
7477 vars->line_speed = SPEED_1000;
7478 vars->mac_type = MAC_TYPE_EMAC;
7479 } else {
7480 vars->line_speed = SPEED_10000;
7481 vars->mac_type = MAC_TYPE_BMAC;
7482 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007483
7484 bnx2x_xgxs_deassert(params);
7485 bnx2x_link_initialize(params, vars);
7486
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007487 if (params->req_line_speed[0] == SPEED_1000) {
7488 bnx2x_emac_program(params, vars);
7489 bnx2x_emac_enable(params, vars, 0);
7490 } else
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007491 bnx2x_bmac_enable(params, vars, 0);
7492
7493 if (params->loopback_mode == LOOPBACK_XGXS) {
7494 /* set 10G XGXS loopback */
7495 params->phy[INT_PHY].config_loopback(
7496 &params->phy[INT_PHY],
7497 params);
7498
7499 } else {
7500 /* set external phy loopback */
7501 u8 phy_index;
7502 for (phy_index = EXT_PHY1;
7503 phy_index < params->num_phys; phy_index++) {
7504 if (params->phy[phy_index].config_loopback)
7505 params->phy[phy_index].config_loopback(
7506 &params->phy[phy_index],
7507 params);
7508 }
7509 }
7510
7511 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
7512 params->port*4, 0);
7513
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00007514 bnx2x_set_led(params, vars,
7515 LED_MODE_OPER, vars->line_speed);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007516 } else
7517 /* No loopback */
7518 {
7519 if (params->switch_cfg == SWITCH_CFG_10G)
7520 bnx2x_xgxs_deassert(params);
7521 else
7522 bnx2x_serdes_deassert(bp, params->port);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00007523
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007524 bnx2x_link_initialize(params, vars);
7525 msleep(30);
7526 bnx2x_link_int_enable(params);
7527 }
7528 return 0;
7529}
7530u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
7531 u8 reset_ext_phy)
7532{
7533 struct bnx2x *bp = params->bp;
Yaniv Rosnercf1d9722010-11-01 05:32:34 +00007534 u8 phy_index, port = params->port, clear_latch_ind = 0;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007535 DP(NETIF_MSG_LINK, "Resetting the link of port %d\n", port);
7536 /* disable attentions */
7537 vars->link_status = 0;
7538 bnx2x_update_mng(params, vars->link_status);
7539 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
7540 (NIG_MASK_XGXS0_LINK_STATUS |
7541 NIG_MASK_XGXS0_LINK10G |
7542 NIG_MASK_SERDES0_LINK_STATUS |
7543 NIG_MASK_MI_INT));
7544
7545 /* activate nig drain */
7546 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
7547
7548 /* disable nig egress interface */
7549 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
7550 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
7551
7552 /* Stop BigMac rx */
7553 bnx2x_bmac_rx_disable(bp, port);
7554
7555 /* disable emac */
7556 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
7557
7558 msleep(10);
7559 /* The PHY reset is controled by GPIO 1
7560 * Hold it as vars low
7561 */
7562 /* clear link led */
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00007563 bnx2x_set_led(params, vars, LED_MODE_OFF, 0);
7564
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007565 if (reset_ext_phy) {
7566 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
7567 phy_index++) {
7568 if (params->phy[phy_index].link_reset)
7569 params->phy[phy_index].link_reset(
7570 &params->phy[phy_index],
7571 params);
Yaniv Rosnercf1d9722010-11-01 05:32:34 +00007572 if (params->phy[phy_index].flags &
7573 FLAGS_REARM_LATCH_SIGNAL)
7574 clear_latch_ind = 1;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007575 }
7576 }
7577
Yaniv Rosnercf1d9722010-11-01 05:32:34 +00007578 if (clear_latch_ind) {
7579 /* Clear latching indication */
7580 bnx2x_rearm_latch_signal(bp, port, 0);
7581 bnx2x_bits_dis(bp, NIG_REG_LATCH_BC_0 + port*4,
7582 1 << NIG_LATCH_BC_ENABLE_MI_INT);
7583 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007584 if (params->phy[INT_PHY].link_reset)
7585 params->phy[INT_PHY].link_reset(
7586 &params->phy[INT_PHY], params);
7587 /* reset BigMac */
7588 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
7589 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
7590
7591 /* disable nig ingress interface */
7592 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0);
7593 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0);
7594 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
7595 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
7596 vars->link_up = 0;
7597 return 0;
7598}
7599
7600/****************************************************************************/
7601/* Common function */
7602/****************************************************************************/
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007603static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp,
7604 u32 shmem_base_path[],
7605 u32 shmem2_base_path[], u8 phy_index,
7606 u32 chip_id)
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007607{
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007608 struct bnx2x_phy phy[PORT_MAX];
7609 struct bnx2x_phy *phy_blk[PORT_MAX];
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007610 u16 val;
7611 s8 port;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007612 s8 port_of_path = 0;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007613
Yaniv Rosner1d03f062010-11-01 05:32:41 +00007614 bnx2x_ext_phy_hw_reset(bp, 0);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007615 /* PART1 - Reset both phys */
7616 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007617 u32 shmem_base, shmem2_base;
7618 /* In E2, same phy is using for port0 of the two paths */
7619 if (CHIP_IS_E2(bp)) {
7620 shmem_base = shmem_base_path[port];
7621 shmem2_base = shmem2_base_path[port];
7622 port_of_path = 0;
7623 } else {
7624 shmem_base = shmem_base_path[0];
7625 shmem2_base = shmem2_base_path[0];
7626 port_of_path = port;
7627 }
7628
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007629 /* Extract the ext phy address for the port */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007630 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007631 port_of_path, &phy[port]) !=
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007632 0) {
7633 DP(NETIF_MSG_LINK, "populate_phy failed\n");
7634 return -EINVAL;
7635 }
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007636 /* disable attentions */
Yaniv Rosner6a71bbe2010-11-01 05:32:31 +00007637 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 +
7638 port_of_path*4,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007639 (NIG_MASK_XGXS0_LINK_STATUS |
7640 NIG_MASK_XGXS0_LINK10G |
7641 NIG_MASK_SERDES0_LINK_STATUS |
7642 NIG_MASK_MI_INT));
7643
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007644 /* Need to take the phy out of low power mode in order
7645 to write to access its registers */
7646 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
7647 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
7648
7649 /* Reset the phy */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007650 bnx2x_cl45_write(bp, &phy[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007651 MDIO_PMA_DEVAD,
7652 MDIO_PMA_REG_CTRL,
7653 1<<15);
7654 }
7655
7656 /* Add delay of 150ms after reset */
7657 msleep(150);
7658
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007659 if (phy[PORT_0].addr & 0x1) {
7660 phy_blk[PORT_0] = &(phy[PORT_1]);
7661 phy_blk[PORT_1] = &(phy[PORT_0]);
7662 } else {
7663 phy_blk[PORT_0] = &(phy[PORT_0]);
7664 phy_blk[PORT_1] = &(phy[PORT_1]);
7665 }
7666
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007667 /* PART2 - Download firmware to both phys */
7668 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
7669 u16 fw_ver1;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007670 if (CHIP_IS_E2(bp))
7671 port_of_path = 0;
7672 else
7673 port_of_path = port;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007674
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007675 DP(NETIF_MSG_LINK, "Loading spirom for phy address 0x%x\n",
7676 phy_blk[port]->addr);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007677 bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port],
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007678 port_of_path);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007679
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007680 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007681 MDIO_PMA_DEVAD,
7682 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
Eilon Greenstein16b311c2009-01-14 06:44:24 +00007683 if (fw_ver1 == 0 || fw_ver1 == 0x4321) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007684 DP(NETIF_MSG_LINK,
Eilon Greenstein16b311c2009-01-14 06:44:24 +00007685 "bnx2x_8073_common_init_phy port %x:"
7686 "Download failed. fw version = 0x%x\n",
7687 port, fw_ver1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007688 return -EINVAL;
7689 }
7690
7691 /* Only set bit 10 = 1 (Tx power down) */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007692 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007693 MDIO_PMA_DEVAD,
7694 MDIO_PMA_REG_TX_POWER_DOWN, &val);
7695
7696 /* Phase1 of TX_POWER_DOWN reset */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007697 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007698 MDIO_PMA_DEVAD,
7699 MDIO_PMA_REG_TX_POWER_DOWN,
7700 (val | 1<<10));
7701 }
7702
7703 /* Toggle Transmitter: Power down and then up with 600ms
7704 delay between */
7705 msleep(600);
7706
7707 /* PART3 - complete TX_POWER_DOWN process, and set GPIO2 back to low */
7708 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Eilon Greensteinf5372252009-02-12 08:38:30 +00007709 /* Phase2 of POWER_DOWN_RESET */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007710 /* Release bit 10 (Release Tx power down) */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007711 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007712 MDIO_PMA_DEVAD,
7713 MDIO_PMA_REG_TX_POWER_DOWN, &val);
7714
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007715 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007716 MDIO_PMA_DEVAD,
7717 MDIO_PMA_REG_TX_POWER_DOWN, (val & (~(1<<10))));
7718 msleep(15);
7719
7720 /* Read modify write the SPI-ROM version select register */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007721 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007722 MDIO_PMA_DEVAD,
7723 MDIO_PMA_REG_EDC_FFE_MAIN, &val);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007724 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007725 MDIO_PMA_DEVAD,
7726 MDIO_PMA_REG_EDC_FFE_MAIN, (val | (1<<12)));
7727
7728 /* set GPIO2 back to LOW */
7729 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
7730 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
7731 }
7732 return 0;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007733}
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007734static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp,
7735 u32 shmem_base_path[],
7736 u32 shmem2_base_path[], u8 phy_index,
7737 u32 chip_id)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007738{
7739 u32 val;
7740 s8 port;
7741 struct bnx2x_phy phy;
7742 /* Use port1 because of the static port-swap */
7743 /* Enable the module detection interrupt */
7744 val = REG_RD(bp, MISC_REG_GPIO_EVENT_EN);
7745 val |= ((1<<MISC_REGISTERS_GPIO_3)|
7746 (1<<(MISC_REGISTERS_GPIO_3 + MISC_REGISTERS_GPIO_PORT_SHIFT)));
7747 REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val);
7748
Yaniv Rosner650154b2010-11-01 05:32:36 +00007749 bnx2x_ext_phy_hw_reset(bp, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007750 msleep(5);
7751 for (port = 0; port < PORT_MAX; port++) {
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007752 u32 shmem_base, shmem2_base;
7753
7754 /* In E2, same phy is using for port0 of the two paths */
7755 if (CHIP_IS_E2(bp)) {
7756 shmem_base = shmem_base_path[port];
7757 shmem2_base = shmem2_base_path[port];
7758 } else {
7759 shmem_base = shmem_base_path[0];
7760 shmem2_base = shmem2_base_path[0];
7761 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007762 /* Extract the ext phy address for the port */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007763 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007764 port, &phy) !=
7765 0) {
7766 DP(NETIF_MSG_LINK, "populate phy failed\n");
7767 return -EINVAL;
7768 }
7769
7770 /* Reset phy*/
7771 bnx2x_cl45_write(bp, &phy,
7772 MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, 0x0001);
7773
7774
7775 /* Set fault module detected LED on */
7776 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
7777 MISC_REGISTERS_GPIO_HIGH,
7778 port);
7779 }
7780
7781 return 0;
7782}
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007783static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp,
7784 u32 shmem_base_path[],
7785 u32 shmem2_base_path[], u8 phy_index,
7786 u32 chip_id)
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007787{
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007788 s8 port;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007789 u32 swap_val, swap_override;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007790 struct bnx2x_phy phy[PORT_MAX];
7791 struct bnx2x_phy *phy_blk[PORT_MAX];
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007792 s8 port_of_path;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007793 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
7794 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
7795
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007796 port = 1;
7797
7798 bnx2x_ext_phy_hw_reset(bp, port ^ (swap_val && swap_override));
7799
7800 /* Calculate the port based on port swap */
7801 port ^= (swap_val && swap_override);
7802
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007803 msleep(5);
7804
7805 /* PART1 - Reset both phys */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007806 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007807 u32 shmem_base, shmem2_base;
7808
7809 /* In E2, same phy is using for port0 of the two paths */
7810 if (CHIP_IS_E2(bp)) {
7811 shmem_base = shmem_base_path[port];
7812 shmem2_base = shmem2_base_path[port];
7813 port_of_path = 0;
7814 } else {
7815 shmem_base = shmem_base_path[0];
7816 shmem2_base = shmem2_base_path[0];
7817 port_of_path = port;
7818 }
7819
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007820 /* Extract the ext phy address for the port */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007821 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007822 port_of_path, &phy[port]) !=
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007823 0) {
7824 DP(NETIF_MSG_LINK, "populate phy failed\n");
7825 return -EINVAL;
7826 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007827 /* disable attentions */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007828 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 +
7829 port_of_path*4,
7830 (NIG_MASK_XGXS0_LINK_STATUS |
7831 NIG_MASK_XGXS0_LINK10G |
7832 NIG_MASK_SERDES0_LINK_STATUS |
7833 NIG_MASK_MI_INT));
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007834
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007835
7836 /* Reset the phy */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007837 bnx2x_cl45_write(bp, &phy[port],
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007838 MDIO_PMA_DEVAD,
7839 MDIO_PMA_REG_CTRL,
7840 1<<15);
7841 }
7842
7843 /* Add delay of 150ms after reset */
7844 msleep(150);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007845 if (phy[PORT_0].addr & 0x1) {
7846 phy_blk[PORT_0] = &(phy[PORT_1]);
7847 phy_blk[PORT_1] = &(phy[PORT_0]);
7848 } else {
7849 phy_blk[PORT_0] = &(phy[PORT_0]);
7850 phy_blk[PORT_1] = &(phy[PORT_1]);
7851 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007852 /* PART2 - Download firmware to both phys */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007853 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007854 u16 fw_ver1;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007855 if (CHIP_IS_E2(bp))
7856 port_of_path = 0;
7857 else
7858 port_of_path = port;
7859 DP(NETIF_MSG_LINK, "Loading spirom for phy address 0x%x\n",
7860 phy_blk[port]->addr);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007861 bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port],
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007862 port_of_path);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007863 bnx2x_cl45_read(bp, phy_blk[port],
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007864 MDIO_PMA_DEVAD,
7865 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
7866 if (fw_ver1 == 0 || fw_ver1 == 0x4321) {
7867 DP(NETIF_MSG_LINK,
Eilon Greensteinbc7f0a02009-08-12 08:23:01 +00007868 "bnx2x_8727_common_init_phy port %x:"
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007869 "Download failed. fw version = 0x%x\n",
7870 port, fw_ver1);
7871 return -EINVAL;
7872 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007873 }
7874
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007875 return 0;
7876}
7877
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007878static u8 bnx2x_ext_phy_common_init(struct bnx2x *bp, u32 shmem_base_path[],
7879 u32 shmem2_base_path[], u8 phy_index,
7880 u32 ext_phy_type, u32 chip_id)
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007881{
7882 u8 rc = 0;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007883
7884 switch (ext_phy_type) {
7885 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007886 rc = bnx2x_8073_common_init_phy(bp, shmem_base_path,
7887 shmem2_base_path,
7888 phy_index, chip_id);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007889 break;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007890
7891 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
7892 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007893 rc = bnx2x_8727_common_init_phy(bp, shmem_base_path,
7894 shmem2_base_path,
7895 phy_index, chip_id);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007896 break;
7897
Eilon Greenstein589abe32009-02-12 08:36:55 +00007898 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
7899 /* GPIO1 affects both ports, so there's need to pull
7900 it for single port alone */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007901 rc = bnx2x_8726_common_init_phy(bp, shmem_base_path,
7902 shmem2_base_path,
7903 phy_index, chip_id);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007904 break;
7905 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
7906 rc = -EINVAL;
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02007907 break;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007908 default:
7909 DP(NETIF_MSG_LINK,
7910 "bnx2x_common_init_phy: ext_phy 0x%x not required\n",
7911 ext_phy_type);
7912 break;
7913 }
7914
7915 return rc;
7916}
7917
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007918u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base_path[],
7919 u32 shmem2_base_path[], u32 chip_id)
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007920{
7921 u8 rc = 0;
7922 u8 phy_index;
7923 u32 ext_phy_type, ext_phy_config;
7924 DP(NETIF_MSG_LINK, "Begin common phy init\n");
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00007925
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007926 if (CHIP_REV_IS_EMUL(bp))
7927 return 0;
7928
7929 /* Read the ext_phy_type for arbitrary port(0) */
7930 for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
7931 phy_index++) {
7932 ext_phy_config = bnx2x_get_ext_phy_config(bp,
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007933 shmem_base_path[0],
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007934 phy_index, 0);
7935 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007936 rc |= bnx2x_ext_phy_common_init(bp, shmem_base_path,
7937 shmem2_base_path,
7938 phy_index, ext_phy_type,
7939 chip_id);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007940 }
7941 return rc;
7942}
7943
7944u8 bnx2x_hw_lock_required(struct bnx2x *bp, u32 shmem_base, u32 shmem2_base)
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00007945{
7946 u8 phy_index;
7947 struct bnx2x_phy phy;
7948 for (phy_index = INT_PHY; phy_index < MAX_PHYS;
7949 phy_index++) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007950 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00007951 0, &phy) != 0) {
7952 DP(NETIF_MSG_LINK, "populate phy failed\n");
7953 return 0;
7954 }
7955
7956 if (phy.flags & FLAGS_HW_LOCK_REQUIRED)
7957 return 1;
7958 }
7959 return 0;
7960}
7961
7962u8 bnx2x_fan_failure_det_req(struct bnx2x *bp,
7963 u32 shmem_base,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007964 u32 shmem2_base,
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00007965 u8 port)
7966{
7967 u8 phy_index, fan_failure_det_req = 0;
7968 struct bnx2x_phy phy;
7969 for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
7970 phy_index++) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007971 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00007972 port, &phy)
7973 != 0) {
7974 DP(NETIF_MSG_LINK, "populate phy failed\n");
7975 return 0;
7976 }
7977 fan_failure_det_req |= (phy.flags &
7978 FLAGS_FAN_FAILURE_DET_REQ);
7979 }
7980 return fan_failure_det_req;
7981}
7982
7983void bnx2x_hw_reset_phy(struct link_params *params)
7984{
7985 u8 phy_index;
7986 for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
7987 phy_index++) {
7988 if (params->phy[phy_index].hw_reset) {
7989 params->phy[phy_index].hw_reset(
7990 &params->phy[phy_index],
7991 params);
7992 params->phy[phy_index] = phy_null;
7993 }
7994 }
7995}