blob: 3be2ce03804a7d6bfc919b6ce92e8dae74be29f4 [file] [log] [blame]
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001/* Copyright 2008-2011 Broadcom Corporation
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002 *
3 * Unless you and Broadcom execute a separate written software license
4 * agreement governing use of this software, this software is licensed to you
5 * under the terms of the GNU General Public License version 2, available
6 * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL").
7 *
8 * Notwithstanding the above, under no circumstances may you combine this
9 * software in any way with any other Broadcom software provided under a
10 * license other than the GPL, without Broadcom's express prior written
11 * consent.
12 *
13 * Written by Yaniv Rosner
14 *
15 */
16
Joe Perches7995c642010-02-17 15:01:52 +000017#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
18
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070019#include <linux/kernel.h>
20#include <linux/errno.h>
21#include <linux/pci.h>
22#include <linux/netdevice.h>
23#include <linux/delay.h>
24#include <linux/ethtool.h>
25#include <linux/mutex.h>
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070026
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070027#include "bnx2x.h"
28
29/********************************************************/
Eilon Greenstein3196a882008-08-13 15:58:49 -070030#define ETH_HLEN 14
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000031/* L2 header size + 2*VLANs (8 bytes) + LLC SNAP (8 bytes) */
32#define ETH_OVREHEAD (ETH_HLEN + 8 + 8)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070033#define ETH_MIN_PACKET_SIZE 60
34#define ETH_MAX_PACKET_SIZE 1500
35#define ETH_MAX_JUMBO_PACKET_SIZE 9600
36#define MDIO_ACCESS_TIMEOUT 1000
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000037#define BMAC_CONTROL_RX_ENABLE 2
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070038
39/***********************************************************/
Eilon Greenstein3196a882008-08-13 15:58:49 -070040/* Shortcut definitions */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070041/***********************************************************/
42
Eilon Greenstein2f904462009-08-12 08:22:16 +000043#define NIG_LATCH_BC_ENABLE_MI_INT 0
44
45#define NIG_STATUS_EMAC0_MI_INT \
46 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_EMAC0_MISC_MI_INT
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070047#define NIG_STATUS_XGXS0_LINK10G \
48 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK10G
49#define NIG_STATUS_XGXS0_LINK_STATUS \
50 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS
51#define NIG_STATUS_XGXS0_LINK_STATUS_SIZE \
52 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS_SIZE
53#define NIG_STATUS_SERDES0_LINK_STATUS \
54 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_SERDES0_LINK_STATUS
55#define NIG_MASK_MI_INT \
56 NIG_MASK_INTERRUPT_PORT0_REG_MASK_EMAC0_MISC_MI_INT
57#define NIG_MASK_XGXS0_LINK10G \
58 NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK10G
59#define NIG_MASK_XGXS0_LINK_STATUS \
60 NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK_STATUS
61#define NIG_MASK_SERDES0_LINK_STATUS \
62 NIG_MASK_INTERRUPT_PORT0_REG_MASK_SERDES0_LINK_STATUS
63
64#define MDIO_AN_CL73_OR_37_COMPLETE \
65 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE | \
66 MDIO_GP_STATUS_TOP_AN_STATUS1_CL37_AUTONEG_COMPLETE)
67
68#define XGXS_RESET_BITS \
69 (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_RSTB_HW | \
70 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_IDDQ | \
71 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN | \
72 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN_SD | \
73 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_TXD_FIFO_RSTB)
74
75#define SERDES_RESET_BITS \
76 (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_RSTB_HW | \
77 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_IDDQ | \
78 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN | \
79 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN_SD)
80
81#define AUTONEG_CL37 SHARED_HW_CFG_AN_ENABLE_CL37
82#define AUTONEG_CL73 SHARED_HW_CFG_AN_ENABLE_CL73
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000083#define AUTONEG_BAM SHARED_HW_CFG_AN_ENABLE_BAM
Eilon Greenstein3196a882008-08-13 15:58:49 -070084#define AUTONEG_PARALLEL \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070085 SHARED_HW_CFG_AN_ENABLE_PARALLEL_DETECTION
Eilon Greenstein3196a882008-08-13 15:58:49 -070086#define AUTONEG_SGMII_FIBER_AUTODET \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070087 SHARED_HW_CFG_AN_EN_SGMII_FIBER_AUTO_DETECT
Eilon Greenstein3196a882008-08-13 15:58:49 -070088#define AUTONEG_REMOTE_PHY SHARED_HW_CFG_AN_ENABLE_REMOTE_PHY
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070089
90#define GP_STATUS_PAUSE_RSOLUTION_TXSIDE \
91 MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_TXSIDE
92#define GP_STATUS_PAUSE_RSOLUTION_RXSIDE \
93 MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_RXSIDE
94#define GP_STATUS_SPEED_MASK \
95 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_MASK
96#define GP_STATUS_10M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10M
97#define GP_STATUS_100M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_100M
98#define GP_STATUS_1G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G
99#define GP_STATUS_2_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_2_5G
100#define GP_STATUS_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_5G
101#define GP_STATUS_6G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_6G
102#define GP_STATUS_10G_HIG \
103 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_HIG
104#define GP_STATUS_10G_CX4 \
105 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_CX4
106#define GP_STATUS_12G_HIG \
107 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12G_HIG
108#define GP_STATUS_12_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12_5G
109#define GP_STATUS_13G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_13G
110#define GP_STATUS_15G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_15G
111#define GP_STATUS_16G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_16G
112#define GP_STATUS_1G_KX MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G_KX
113#define GP_STATUS_10G_KX4 \
114 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_KX4
115
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000116#define LINK_10THD LINK_STATUS_SPEED_AND_DUPLEX_10THD
117#define LINK_10TFD LINK_STATUS_SPEED_AND_DUPLEX_10TFD
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700118#define LINK_100TXHD LINK_STATUS_SPEED_AND_DUPLEX_100TXHD
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000119#define LINK_100T4 LINK_STATUS_SPEED_AND_DUPLEX_100T4
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700120#define LINK_100TXFD LINK_STATUS_SPEED_AND_DUPLEX_100TXFD
121#define LINK_1000THD LINK_STATUS_SPEED_AND_DUPLEX_1000THD
122#define LINK_1000TFD LINK_STATUS_SPEED_AND_DUPLEX_1000TFD
123#define LINK_1000XFD LINK_STATUS_SPEED_AND_DUPLEX_1000XFD
124#define LINK_2500THD LINK_STATUS_SPEED_AND_DUPLEX_2500THD
125#define LINK_2500TFD LINK_STATUS_SPEED_AND_DUPLEX_2500TFD
126#define LINK_2500XFD LINK_STATUS_SPEED_AND_DUPLEX_2500XFD
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000127#define LINK_10GTFD LINK_STATUS_SPEED_AND_DUPLEX_10GTFD
128#define LINK_10GXFD LINK_STATUS_SPEED_AND_DUPLEX_10GXFD
129#define LINK_12GTFD LINK_STATUS_SPEED_AND_DUPLEX_12GTFD
130#define LINK_12GXFD LINK_STATUS_SPEED_AND_DUPLEX_12GXFD
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700131#define LINK_12_5GTFD LINK_STATUS_SPEED_AND_DUPLEX_12_5GTFD
132#define LINK_12_5GXFD LINK_STATUS_SPEED_AND_DUPLEX_12_5GXFD
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000133#define LINK_13GTFD LINK_STATUS_SPEED_AND_DUPLEX_13GTFD
134#define LINK_13GXFD LINK_STATUS_SPEED_AND_DUPLEX_13GXFD
135#define LINK_15GTFD LINK_STATUS_SPEED_AND_DUPLEX_15GTFD
136#define LINK_15GXFD LINK_STATUS_SPEED_AND_DUPLEX_15GXFD
137#define LINK_16GTFD LINK_STATUS_SPEED_AND_DUPLEX_16GTFD
138#define LINK_16GXFD LINK_STATUS_SPEED_AND_DUPLEX_16GXFD
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700139
140#define PHY_XGXS_FLAG 0x1
141#define PHY_SGMII_FLAG 0x2
142#define PHY_SERDES_FLAG 0x4
143
Eilon Greenstein589abe32009-02-12 08:36:55 +0000144/* */
145#define SFP_EEPROM_CON_TYPE_ADDR 0x2
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000146 #define SFP_EEPROM_CON_TYPE_VAL_LC 0x7
Eilon Greenstein589abe32009-02-12 08:36:55 +0000147 #define SFP_EEPROM_CON_TYPE_VAL_COPPER 0x21
148
Eilon Greenstein4d295db2009-07-21 05:47:47 +0000149
150#define SFP_EEPROM_COMP_CODE_ADDR 0x3
151 #define SFP_EEPROM_COMP_CODE_SR_MASK (1<<4)
152 #define SFP_EEPROM_COMP_CODE_LR_MASK (1<<5)
153 #define SFP_EEPROM_COMP_CODE_LRM_MASK (1<<6)
154
Eilon Greenstein589abe32009-02-12 08:36:55 +0000155#define SFP_EEPROM_FC_TX_TECH_ADDR 0x8
156 #define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE 0x4
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000157 #define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE 0x8
Eilon Greenstein4d295db2009-07-21 05:47:47 +0000158
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000159#define SFP_EEPROM_OPTIONS_ADDR 0x40
Eilon Greenstein589abe32009-02-12 08:36:55 +0000160 #define SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK 0x1
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000161#define SFP_EEPROM_OPTIONS_SIZE 2
Eilon Greenstein589abe32009-02-12 08:36:55 +0000162
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000163#define EDC_MODE_LINEAR 0x0022
164#define EDC_MODE_LIMITING 0x0044
165#define EDC_MODE_PASSIVE_DAC 0x0055
Eilon Greenstein589abe32009-02-12 08:36:55 +0000166
Eilon Greenstein4d295db2009-07-21 05:47:47 +0000167
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000168#define ETS_BW_LIMIT_CREDIT_UPPER_BOUND (0x5000)
169#define ETS_BW_LIMIT_CREDIT_WEIGHT (0x5000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700170/**********************************************************/
171/* INTERFACE */
172/**********************************************************/
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000173
Yaniv Rosnercd2be892011-01-31 04:21:45 +0000174#define CL22_WR_OVER_CL45(_bp, _phy, _bank, _addr, _val) \
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000175 bnx2x_cl45_write(_bp, _phy, \
Yaniv Rosner7aa07112010-09-07 11:41:01 +0000176 (_phy)->def_md_devad, \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700177 (_bank + (_addr & 0xf)), \
178 _val)
179
Yaniv Rosnercd2be892011-01-31 04:21:45 +0000180#define CL22_RD_OVER_CL45(_bp, _phy, _bank, _addr, _val) \
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000181 bnx2x_cl45_read(_bp, _phy, \
Yaniv Rosner7aa07112010-09-07 11:41:01 +0000182 (_phy)->def_md_devad, \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700183 (_bank + (_addr & 0xf)), \
184 _val)
185
stephen hemminger8d962862010-10-21 07:50:56 +0000186static u8 bnx2x_cl45_read(struct bnx2x *bp, struct bnx2x_phy *phy,
187 u8 devad, u16 reg, u16 *ret_val);
188
189static u8 bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy,
190 u8 devad, u16 reg, u16 val);
191
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700192static u32 bnx2x_bits_en(struct bnx2x *bp, u32 reg, u32 bits)
193{
194 u32 val = REG_RD(bp, reg);
195
196 val |= bits;
197 REG_WR(bp, reg, val);
198 return val;
199}
200
201static u32 bnx2x_bits_dis(struct bnx2x *bp, u32 reg, u32 bits)
202{
203 u32 val = REG_RD(bp, reg);
204
205 val &= ~bits;
206 REG_WR(bp, reg, val);
207 return val;
208}
209
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000210/******************************************************************/
211/* ETS section */
212/******************************************************************/
213void bnx2x_ets_disabled(struct link_params *params)
214{
215 /* ETS disabled configuration*/
216 struct bnx2x *bp = params->bp;
217
218 DP(NETIF_MSG_LINK, "ETS disabled configuration\n");
219
220 /**
221 * mapping between entry priority to client number (0,1,2 -debug and
222 * management clients, 3 - COS0 client, 4 - COS client)(HIGHEST)
223 * 3bits client num.
224 * PRI4 | PRI3 | PRI2 | PRI1 | PRI0
225 * cos1-100 cos0-011 dbg1-010 dbg0-001 MCP-000
226 */
227
228 REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT, 0x4688);
229 /**
230 * Bitmap of 5bits length. Each bit specifies whether the entry behaves
231 * as strict. Bits 0,1,2 - debug and management entries, 3 -
232 * COS0 entry, 4 - COS1 entry.
233 * COS1 | COS0 | DEBUG1 | DEBUG0 | MGMT
234 * bit4 bit3 bit2 bit1 bit0
235 * MCP and debug are strict
236 */
237
238 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x7);
239 /* defines which entries (clients) are subjected to WFQ arbitration */
240 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ, 0);
241 /**
242 * For strict priority entries defines the number of consecutive
243 * slots for the highest priority.
244 */
245 REG_WR(bp, NIG_REG_P0_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100);
246 /**
247 * mapping between the CREDIT_WEIGHT registers and actual client
248 * numbers
249 */
250 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP, 0);
251 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_0, 0);
252 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_1, 0);
253
254 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_0, 0);
255 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_1, 0);
256 REG_WR(bp, PBF_REG_HIGH_PRIORITY_COS_NUM, 0);
257 /* ETS mode disable */
258 REG_WR(bp, PBF_REG_ETS_ENABLED, 0);
259 /**
260 * If ETS mode is enabled (there is no strict priority) defines a WFQ
261 * weight for COS0/COS1.
262 */
263 REG_WR(bp, PBF_REG_COS0_WEIGHT, 0x2710);
264 REG_WR(bp, PBF_REG_COS1_WEIGHT, 0x2710);
265 /* Upper bound that COS0_WEIGHT can reach in the WFQ arbiter */
266 REG_WR(bp, PBF_REG_COS0_UPPER_BOUND, 0x989680);
267 REG_WR(bp, PBF_REG_COS1_UPPER_BOUND, 0x989680);
268 /* Defines the number of consecutive slots for the strict priority */
269 REG_WR(bp, PBF_REG_NUM_STRICT_ARB_SLOTS, 0);
270}
271
272void bnx2x_ets_bw_limit_common(const struct link_params *params)
273{
274 /* ETS disabled configuration */
275 struct bnx2x *bp = params->bp;
276 DP(NETIF_MSG_LINK, "ETS enabled BW limit configuration\n");
277 /**
278 * defines which entries (clients) are subjected to WFQ arbitration
279 * COS0 0x8
280 * COS1 0x10
281 */
282 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ, 0x18);
283 /**
284 * mapping between the ARB_CREDIT_WEIGHT registers and actual
285 * client numbers (WEIGHT_0 does not actually have to represent
286 * client 0)
287 * PRI4 | PRI3 | PRI2 | PRI1 | PRI0
288 * cos1-001 cos0-000 dbg1-100 dbg0-011 MCP-010
289 */
290 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP, 0x111A);
291
292 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_0,
293 ETS_BW_LIMIT_CREDIT_UPPER_BOUND);
294 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_1,
295 ETS_BW_LIMIT_CREDIT_UPPER_BOUND);
296
297 /* ETS mode enabled*/
298 REG_WR(bp, PBF_REG_ETS_ENABLED, 1);
299
300 /* Defines the number of consecutive slots for the strict priority */
301 REG_WR(bp, PBF_REG_NUM_STRICT_ARB_SLOTS, 0);
302 /**
303 * Bitmap of 5bits length. Each bit specifies whether the entry behaves
304 * as strict. Bits 0,1,2 - debug and management entries, 3 - COS0
305 * entry, 4 - COS1 entry.
306 * COS1 | COS0 | DEBUG21 | DEBUG0 | MGMT
307 * bit4 bit3 bit2 bit1 bit0
308 * MCP and debug are strict
309 */
310 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x7);
311
312 /* Upper bound that COS0_WEIGHT can reach in the WFQ arbiter.*/
313 REG_WR(bp, PBF_REG_COS0_UPPER_BOUND,
314 ETS_BW_LIMIT_CREDIT_UPPER_BOUND);
315 REG_WR(bp, PBF_REG_COS1_UPPER_BOUND,
316 ETS_BW_LIMIT_CREDIT_UPPER_BOUND);
317}
318
319void bnx2x_ets_bw_limit(const struct link_params *params, const u32 cos0_bw,
320 const u32 cos1_bw)
321{
322 /* ETS disabled configuration*/
323 struct bnx2x *bp = params->bp;
324 const u32 total_bw = cos0_bw + cos1_bw;
325 u32 cos0_credit_weight = 0;
326 u32 cos1_credit_weight = 0;
327
328 DP(NETIF_MSG_LINK, "ETS enabled BW limit configuration\n");
329
330 if ((0 == total_bw) ||
331 (0 == cos0_bw) ||
332 (0 == cos1_bw)) {
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000333 DP(NETIF_MSG_LINK, "Total BW can't be zero\n");
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000334 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
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000357 DP(NETIF_MSG_LINK, "ETS enabled strict configuration\n");
358 /**
359 * Bitmap of 5bits length. Each bit specifies whether the entry behaves
360 * as strict. Bits 0,1,2 - debug and management entries,
361 * 3 - COS0 entry, 4 - COS1 entry.
362 * COS1 | COS0 | DEBUG21 | DEBUG0 | MGMT
363 * bit4 bit3 bit2 bit1 bit0
364 * MCP and debug are strict
365 */
366 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x1F);
367 /**
368 * For strict priority entries defines the number of consecutive slots
369 * for the highest priority.
370 */
371 REG_WR(bp, NIG_REG_P0_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100);
372 /* ETS mode disable */
373 REG_WR(bp, PBF_REG_ETS_ENABLED, 0);
374 /* Defines the number of consecutive slots for the strict priority */
375 REG_WR(bp, PBF_REG_NUM_STRICT_ARB_SLOTS, 0x100);
376
377 /* Defines the number of consecutive slots for the strict priority */
378 REG_WR(bp, PBF_REG_HIGH_PRIORITY_COS_NUM, strict_cos);
379
380 /**
381 * mapping between entry priority to client number (0,1,2 -debug and
382 * management clients, 3 - COS0 client, 4 - COS client)(HIGHEST)
383 * 3bits client num.
384 * PRI4 | PRI3 | PRI2 | PRI1 | PRI0
385 * dbg0-010 dbg1-001 cos1-100 cos0-011 MCP-000
386 * dbg0-010 dbg1-001 cos0-011 cos1-100 MCP-000
387 */
388 val = (0 == strict_cos) ? 0x2318 : 0x22E0;
389 REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT, val);
390
391 return 0;
392}
393/******************************************************************/
394/* ETS section */
395/******************************************************************/
396
397static void bnx2x_bmac2_get_pfc_stat(struct link_params *params,
398 u32 pfc_frames_sent[2],
399 u32 pfc_frames_received[2])
400{
401 /* Read pfc statistic */
402 struct bnx2x *bp = params->bp;
403 u32 bmac_addr = params->port ? NIG_REG_INGRESS_BMAC1_MEM :
404 NIG_REG_INGRESS_BMAC0_MEM;
405
406 DP(NETIF_MSG_LINK, "pfc statistic read from BMAC\n");
407
408 REG_RD_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_STAT_GTPP,
409 pfc_frames_sent, 2);
410
411 REG_RD_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_STAT_GRPP,
412 pfc_frames_received, 2);
413
414}
415static void bnx2x_emac_get_pfc_stat(struct link_params *params,
416 u32 pfc_frames_sent[2],
417 u32 pfc_frames_received[2])
418{
419 /* Read pfc statistic */
420 struct bnx2x *bp = params->bp;
421 u32 emac_base = params->port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
422 u32 val_xon = 0;
423 u32 val_xoff = 0;
424
425 DP(NETIF_MSG_LINK, "pfc statistic read from EMAC\n");
426
427 /* PFC received frames */
428 val_xoff = REG_RD(bp, emac_base +
429 EMAC_REG_RX_PFC_STATS_XOFF_RCVD);
430 val_xoff &= EMAC_REG_RX_PFC_STATS_XOFF_RCVD_COUNT;
431 val_xon = REG_RD(bp, emac_base + EMAC_REG_RX_PFC_STATS_XON_RCVD);
432 val_xon &= EMAC_REG_RX_PFC_STATS_XON_RCVD_COUNT;
433
434 pfc_frames_received[0] = val_xon + val_xoff;
435
436 /* PFC received sent */
437 val_xoff = REG_RD(bp, emac_base +
438 EMAC_REG_RX_PFC_STATS_XOFF_SENT);
439 val_xoff &= EMAC_REG_RX_PFC_STATS_XOFF_SENT_COUNT;
440 val_xon = REG_RD(bp, emac_base + EMAC_REG_RX_PFC_STATS_XON_SENT);
441 val_xon &= EMAC_REG_RX_PFC_STATS_XON_SENT_COUNT;
442
443 pfc_frames_sent[0] = val_xon + val_xoff;
444}
445
446void bnx2x_pfc_statistic(struct link_params *params, struct link_vars *vars,
447 u32 pfc_frames_sent[2],
448 u32 pfc_frames_received[2])
449{
450 /* Read pfc statistic */
451 struct bnx2x *bp = params->bp;
452 u32 val = 0;
453 DP(NETIF_MSG_LINK, "pfc statistic\n");
454
455 if (!vars->link_up)
456 return;
457
458 val = REG_RD(bp, MISC_REG_RESET_REG_2);
459 if ((val & (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << params->port))
460 == 0) {
461 DP(NETIF_MSG_LINK, "About to read stats from EMAC\n");
462 bnx2x_emac_get_pfc_stat(params, pfc_frames_sent,
463 pfc_frames_received);
464 } else {
465 DP(NETIF_MSG_LINK, "About to read stats from BMAC\n");
466 bnx2x_bmac2_get_pfc_stat(params, pfc_frames_sent,
467 pfc_frames_received);
468 }
469}
470/******************************************************************/
471/* MAC/PBF section */
472/******************************************************************/
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700473static void bnx2x_emac_init(struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000474 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700475{
476 /* reset and unreset the emac core */
477 struct bnx2x *bp = params->bp;
478 u8 port = params->port;
479 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
480 u32 val;
481 u16 timeout;
482
483 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000484 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700485 udelay(5);
486 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000487 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700488
489 /* init emac - use read-modify-write */
490 /* self clear reset */
491 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700492 EMAC_WR(bp, EMAC_REG_EMAC_MODE, (val | EMAC_MODE_RESET));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700493
494 timeout = 200;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700495 do {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700496 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
497 DP(NETIF_MSG_LINK, "EMAC reset reg is %u\n", val);
498 if (!timeout) {
499 DP(NETIF_MSG_LINK, "EMAC timeout!\n");
500 return;
501 }
502 timeout--;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700503 } while (val & EMAC_MODE_RESET);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700504
505 /* Set mac address */
506 val = ((params->mac_addr[0] << 8) |
507 params->mac_addr[1]);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700508 EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700509
510 val = ((params->mac_addr[2] << 24) |
511 (params->mac_addr[3] << 16) |
512 (params->mac_addr[4] << 8) |
513 params->mac_addr[5]);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700514 EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH + 4, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700515}
516
517static u8 bnx2x_emac_enable(struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000518 struct link_vars *vars, u8 lb)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700519{
520 struct bnx2x *bp = params->bp;
521 u8 port = params->port;
522 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
523 u32 val;
524
525 DP(NETIF_MSG_LINK, "enabling EMAC\n");
526
527 /* enable emac and not bmac */
528 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 1);
529
530 /* for paladium */
531 if (CHIP_REV_IS_EMUL(bp)) {
532 /* Use lane 1 (of lanes 0-3) */
533 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1);
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000534 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700535 }
536 /* for fpga */
537 else
538
539 if (CHIP_REV_IS_FPGA(bp)) {
540 /* Use lane 1 (of lanes 0-3) */
541 DP(NETIF_MSG_LINK, "bnx2x_emac_enable: Setting FPGA\n");
542
543 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1);
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000544 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700545 } else
546 /* ASIC */
547 if (vars->phy_flags & PHY_XGXS_FLAG) {
548 u32 ser_lane = ((params->lane_config &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000549 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
550 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700551
552 DP(NETIF_MSG_LINK, "XGXS\n");
553 /* select the master lanes (out of 0-3) */
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000554 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, ser_lane);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700555 /* select XGXS */
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000556 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700557
558 } else { /* SerDes */
559 DP(NETIF_MSG_LINK, "SerDes\n");
560 /* select SerDes */
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000561 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700562 }
563
Eilon Greenstein811a2f22009-02-12 08:37:04 +0000564 bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000565 EMAC_RX_MODE_RESET);
Eilon Greenstein811a2f22009-02-12 08:37:04 +0000566 bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000567 EMAC_TX_MODE_RESET);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700568
569 if (CHIP_REV_IS_SLOW(bp)) {
570 /* config GMII mode */
571 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000572 EMAC_WR(bp, EMAC_REG_EMAC_MODE, (val | EMAC_MODE_PORT_GMII));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700573 } else { /* ASIC */
574 /* pause enable/disable */
575 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
576 EMAC_RX_MODE_FLOW_EN);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700577
578 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000579 (EMAC_TX_MODE_EXT_PAUSE_EN |
580 EMAC_TX_MODE_FLOW_EN));
581 if (!(params->feature_config_flags &
582 FEATURE_CONFIG_PFC_ENABLED)) {
583 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
584 bnx2x_bits_en(bp, emac_base +
585 EMAC_REG_EMAC_RX_MODE,
586 EMAC_RX_MODE_FLOW_EN);
587
588 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
589 bnx2x_bits_en(bp, emac_base +
590 EMAC_REG_EMAC_TX_MODE,
591 (EMAC_TX_MODE_EXT_PAUSE_EN |
592 EMAC_TX_MODE_FLOW_EN));
593 } else
594 bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
595 EMAC_TX_MODE_FLOW_EN);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700596 }
597
598 /* KEEP_VLAN_TAG, promiscuous */
599 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_RX_MODE);
600 val |= EMAC_RX_MODE_KEEP_VLAN_TAG | EMAC_RX_MODE_PROMISCUOUS;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000601
602 /**
603 * Setting this bit causes MAC control frames (except for pause
604 * frames) to be passed on for processing. This setting has no
605 * affect on the operation of the pause frames. This bit effects
606 * all packets regardless of RX Parser packet sorting logic.
607 * Turn the PFC off to make sure we are in Xon state before
608 * enabling it.
609 */
610 EMAC_WR(bp, EMAC_REG_RX_PFC_MODE, 0);
611 if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED) {
612 DP(NETIF_MSG_LINK, "PFC is enabled\n");
613 /* Enable PFC again */
614 EMAC_WR(bp, EMAC_REG_RX_PFC_MODE,
615 EMAC_REG_RX_PFC_MODE_RX_EN |
616 EMAC_REG_RX_PFC_MODE_TX_EN |
617 EMAC_REG_RX_PFC_MODE_PRIORITIES);
618
619 EMAC_WR(bp, EMAC_REG_RX_PFC_PARAM,
620 ((0x0101 <<
621 EMAC_REG_RX_PFC_PARAM_OPCODE_BITSHIFT) |
622 (0x00ff <<
623 EMAC_REG_RX_PFC_PARAM_PRIORITY_EN_BITSHIFT)));
624 val |= EMAC_RX_MODE_KEEP_MAC_CONTROL;
625 }
Eilon Greenstein3196a882008-08-13 15:58:49 -0700626 EMAC_WR(bp, EMAC_REG_EMAC_RX_MODE, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700627
628 /* Set Loopback */
629 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
630 if (lb)
631 val |= 0x810;
632 else
633 val &= ~0x810;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700634 EMAC_WR(bp, EMAC_REG_EMAC_MODE, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700635
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +0000636 /* enable emac */
637 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 1);
638
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700639 /* enable emac for jumbo packets */
Eilon Greenstein3196a882008-08-13 15:58:49 -0700640 EMAC_WR(bp, EMAC_REG_EMAC_RX_MTU_SIZE,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700641 (EMAC_RX_MTU_SIZE_JUMBO_ENA |
642 (ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD)));
643
644 /* strip CRC */
645 REG_WR(bp, NIG_REG_NIG_INGRESS_EMAC0_NO_CRC + port*4, 0x1);
646
647 /* disable the NIG in/out to the bmac */
648 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x0);
649 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, 0x0);
650 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x0);
651
652 /* enable the NIG in/out to the emac */
653 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x1);
654 val = 0;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000655 if ((params->feature_config_flags &
656 FEATURE_CONFIG_PFC_ENABLED) ||
657 (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700658 val = 1;
659
660 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, val);
661 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x1);
662
663 if (CHIP_REV_IS_EMUL(bp)) {
664 /* take the BigMac out of reset */
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000665 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
666 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700667
668 /* enable access for bmac registers */
669 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
Eilon Greenstein6f654972009-08-12 08:23:51 +0000670 } else
671 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700672
673 vars->mac_type = MAC_TYPE_EMAC;
674 return 0;
675}
676
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000677static void bnx2x_update_pfc_bmac1(struct link_params *params,
678 struct link_vars *vars)
679{
680 u32 wb_data[2];
681 struct bnx2x *bp = params->bp;
682 u32 bmac_addr = params->port ? NIG_REG_INGRESS_BMAC1_MEM :
683 NIG_REG_INGRESS_BMAC0_MEM;
684
685 u32 val = 0x14;
686 if ((!(params->feature_config_flags &
687 FEATURE_CONFIG_PFC_ENABLED)) &&
688 (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX))
689 /* Enable BigMAC to react on received Pause packets */
690 val |= (1<<5);
691 wb_data[0] = val;
692 wb_data[1] = 0;
693 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_CONTROL, wb_data, 2);
694
695 /* tx control */
696 val = 0xc0;
697 if (!(params->feature_config_flags &
698 FEATURE_CONFIG_PFC_ENABLED) &&
699 (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
700 val |= 0x800000;
701 wb_data[0] = val;
702 wb_data[1] = 0;
703 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_CONTROL, wb_data, 2);
704}
705
706static void bnx2x_update_pfc_bmac2(struct link_params *params,
707 struct link_vars *vars,
708 u8 is_lb)
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000709{
710 /*
711 * Set rx control: Strip CRC and enable BigMAC to relay
712 * control packets to the system as well
713 */
714 u32 wb_data[2];
715 struct bnx2x *bp = params->bp;
716 u32 bmac_addr = params->port ? NIG_REG_INGRESS_BMAC1_MEM :
717 NIG_REG_INGRESS_BMAC0_MEM;
718 u32 val = 0x14;
719
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000720 if ((!(params->feature_config_flags &
721 FEATURE_CONFIG_PFC_ENABLED)) &&
722 (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX))
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000723 /* Enable BigMAC to react on received Pause packets */
724 val |= (1<<5);
725 wb_data[0] = val;
726 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000727 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_CONTROL, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000728 udelay(30);
729
730 /* Tx control */
731 val = 0xc0;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000732 if (!(params->feature_config_flags &
733 FEATURE_CONFIG_PFC_ENABLED) &&
734 (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000735 val |= 0x800000;
736 wb_data[0] = val;
737 wb_data[1] = 0;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000738 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_CONTROL, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000739
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000740 if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED) {
741 DP(NETIF_MSG_LINK, "PFC is enabled\n");
742 /* Enable PFC RX & TX & STATS and set 8 COS */
743 wb_data[0] = 0x0;
744 wb_data[0] |= (1<<0); /* RX */
745 wb_data[0] |= (1<<1); /* TX */
746 wb_data[0] |= (1<<2); /* Force initial Xon */
747 wb_data[0] |= (1<<3); /* 8 cos */
748 wb_data[0] |= (1<<5); /* STATS */
749 wb_data[1] = 0;
750 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_PFC_CONTROL,
751 wb_data, 2);
752 /* Clear the force Xon */
753 wb_data[0] &= ~(1<<2);
754 } else {
755 DP(NETIF_MSG_LINK, "PFC is disabled\n");
756 /* disable PFC RX & TX & STATS and set 8 COS */
757 wb_data[0] = 0x8;
758 wb_data[1] = 0;
759 }
760
761 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_PFC_CONTROL, wb_data, 2);
762
763 /**
764 * Set Time (based unit is 512 bit time) between automatic
765 * re-sending of PP packets amd enable automatic re-send of
766 * Per-Priroity Packet as long as pp_gen is asserted and
767 * pp_disable is low.
768 */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000769 val = 0x8000;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000770 if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED)
771 val |= (1<<16); /* enable automatic re-send */
772
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000773 wb_data[0] = val;
774 wb_data[1] = 0;
775 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_PAUSE_CONTROL,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000776 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000777
778 /* mac control */
779 val = 0x3; /* Enable RX and TX */
780 if (is_lb) {
781 val |= 0x4; /* Local loopback */
782 DP(NETIF_MSG_LINK, "enable bmac loopback\n");
783 }
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000784 /* When PFC enabled, Pass pause frames towards the NIG. */
785 if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED)
786 val |= ((1<<6)|(1<<5));
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000787
788 wb_data[0] = val;
789 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000790 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_BMAC_CONTROL, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000791}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700792
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000793static void bnx2x_update_pfc_brb(struct link_params *params,
794 struct link_vars *vars,
795 struct bnx2x_nig_brb_pfc_port_params *pfc_params)
796{
797 struct bnx2x *bp = params->bp;
798 int set_pfc = params->feature_config_flags &
799 FEATURE_CONFIG_PFC_ENABLED;
800
801 /* default - pause configuration */
802 u32 pause_xoff_th = PFC_BRB_MAC_PAUSE_XOFF_THRESHOLD_PAUSEABLE;
803 u32 pause_xon_th = PFC_BRB_MAC_PAUSE_XON_THRESHOLD_PAUSEABLE;
804 u32 full_xoff_th = PFC_BRB_MAC_FULL_XOFF_THRESHOLD_PAUSEABLE;
805 u32 full_xon_th = PFC_BRB_MAC_FULL_XON_THRESHOLD_PAUSEABLE;
806
807 if (set_pfc && pfc_params)
808 /* First COS */
809 if (!pfc_params->cos0_pauseable) {
810 pause_xoff_th =
811 PFC_BRB_MAC_PAUSE_XOFF_THRESHOLD_NON_PAUSEABLE;
812 pause_xon_th =
813 PFC_BRB_MAC_PAUSE_XON_THRESHOLD_NON_PAUSEABLE;
814 full_xoff_th =
815 PFC_BRB_MAC_FULL_XOFF_THRESHOLD_NON_PAUSEABLE;
816 full_xon_th =
817 PFC_BRB_MAC_FULL_XON_THRESHOLD_NON_PAUSEABLE;
818 }
819 /* The number of free blocks below which the pause signal to class 0
820 of MAC #n is asserted. n=0,1 */
821 REG_WR(bp, BRB1_REG_PAUSE_0_XOFF_THRESHOLD_0 , pause_xoff_th);
822 /* The number of free blocks above which the pause signal to class 0
823 of MAC #n is de-asserted. n=0,1 */
824 REG_WR(bp, BRB1_REG_PAUSE_0_XON_THRESHOLD_0 , pause_xon_th);
825 /* The number of free blocks below which the full signal to class 0
826 of MAC #n is asserted. n=0,1 */
827 REG_WR(bp, BRB1_REG_FULL_0_XOFF_THRESHOLD_0 , full_xoff_th);
828 /* The number of free blocks above which the full signal to class 0
829 of MAC #n is de-asserted. n=0,1 */
830 REG_WR(bp, BRB1_REG_FULL_0_XON_THRESHOLD_0 , full_xon_th);
831
832 if (set_pfc && pfc_params) {
833 /* Second COS */
834 if (pfc_params->cos1_pauseable) {
835 pause_xoff_th =
836 PFC_BRB_MAC_PAUSE_XOFF_THRESHOLD_PAUSEABLE;
837 pause_xon_th =
838 PFC_BRB_MAC_PAUSE_XON_THRESHOLD_PAUSEABLE;
839 full_xoff_th =
840 PFC_BRB_MAC_FULL_XOFF_THRESHOLD_PAUSEABLE;
841 full_xon_th =
842 PFC_BRB_MAC_FULL_XON_THRESHOLD_PAUSEABLE;
843 } else {
844 pause_xoff_th =
845 PFC_BRB_MAC_PAUSE_XOFF_THRESHOLD_NON_PAUSEABLE;
846 pause_xon_th =
847 PFC_BRB_MAC_PAUSE_XON_THRESHOLD_NON_PAUSEABLE;
848 full_xoff_th =
849 PFC_BRB_MAC_FULL_XOFF_THRESHOLD_NON_PAUSEABLE;
850 full_xon_th =
851 PFC_BRB_MAC_FULL_XON_THRESHOLD_NON_PAUSEABLE;
852 }
853 /**
854 * The number of free blocks below which the pause signal to
855 * class 1 of MAC #n is asserted. n=0,1
856 **/
857 REG_WR(bp, BRB1_REG_PAUSE_1_XOFF_THRESHOLD_0, pause_xoff_th);
858 /**
859 * The number of free blocks above which the pause signal to
860 * class 1 of MAC #n is de-asserted. n=0,1
861 **/
862 REG_WR(bp, BRB1_REG_PAUSE_1_XON_THRESHOLD_0, pause_xon_th);
863 /**
864 * The number of free blocks below which the full signal to
865 * class 1 of MAC #n is asserted. n=0,1
866 **/
867 REG_WR(bp, BRB1_REG_FULL_1_XOFF_THRESHOLD_0, full_xoff_th);
868 /**
869 * The number of free blocks above which the full signal to
870 * class 1 of MAC #n is de-asserted. n=0,1
871 **/
872 REG_WR(bp, BRB1_REG_FULL_1_XON_THRESHOLD_0, full_xon_th);
873 }
874}
875
876static void bnx2x_update_pfc_nig(struct link_params *params,
877 struct link_vars *vars,
878 struct bnx2x_nig_brb_pfc_port_params *nig_params)
879{
880 u32 xcm_mask = 0, ppp_enable = 0, pause_enable = 0, llfc_out_en = 0;
881 u32 llfc_enable = 0, xcm0_out_en = 0, p0_hwpfc_enable = 0;
882 u32 pkt_priority_to_cos = 0;
883 u32 val;
884 struct bnx2x *bp = params->bp;
885 int port = params->port;
886 int set_pfc = params->feature_config_flags &
887 FEATURE_CONFIG_PFC_ENABLED;
888 DP(NETIF_MSG_LINK, "updating pfc nig parameters\n");
889
890 /**
891 * When NIG_LLH0_XCM_MASK_REG_LLHX_XCM_MASK_BCN bit is set
892 * MAC control frames (that are not pause packets)
893 * will be forwarded to the XCM.
894 */
895 xcm_mask = REG_RD(bp,
896 port ? NIG_REG_LLH1_XCM_MASK :
897 NIG_REG_LLH0_XCM_MASK);
898 /**
899 * nig params will override non PFC params, since it's possible to
900 * do transition from PFC to SAFC
901 */
902 if (set_pfc) {
903 pause_enable = 0;
904 llfc_out_en = 0;
905 llfc_enable = 0;
906 ppp_enable = 1;
907 xcm_mask &= ~(port ? NIG_LLH1_XCM_MASK_REG_LLH1_XCM_MASK_BCN :
908 NIG_LLH0_XCM_MASK_REG_LLH0_XCM_MASK_BCN);
909 xcm0_out_en = 0;
910 p0_hwpfc_enable = 1;
911 } else {
912 if (nig_params) {
913 llfc_out_en = nig_params->llfc_out_en;
914 llfc_enable = nig_params->llfc_enable;
915 pause_enable = nig_params->pause_enable;
916 } else /*defaul non PFC mode - PAUSE */
917 pause_enable = 1;
918
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 = 1;
922 }
923
924 REG_WR(bp, port ? NIG_REG_LLFC_OUT_EN_1 :
925 NIG_REG_LLFC_OUT_EN_0, llfc_out_en);
926 REG_WR(bp, port ? NIG_REG_LLFC_ENABLE_1 :
927 NIG_REG_LLFC_ENABLE_0, llfc_enable);
928 REG_WR(bp, port ? NIG_REG_PAUSE_ENABLE_1 :
929 NIG_REG_PAUSE_ENABLE_0, pause_enable);
930
931 REG_WR(bp, port ? NIG_REG_PPP_ENABLE_1 :
932 NIG_REG_PPP_ENABLE_0, ppp_enable);
933
934 REG_WR(bp, port ? NIG_REG_LLH1_XCM_MASK :
935 NIG_REG_LLH0_XCM_MASK, xcm_mask);
936
937 REG_WR(bp, NIG_REG_LLFC_EGRESS_SRC_ENABLE_0, 0x7);
938
939 /* output enable for RX_XCM # IF */
940 REG_WR(bp, NIG_REG_XCM0_OUT_EN, xcm0_out_en);
941
942 /* HW PFC TX enable */
943 REG_WR(bp, NIG_REG_P0_HWPFC_ENABLE, p0_hwpfc_enable);
944
945 /* 0x2 = BMAC, 0x1= EMAC */
946 switch (vars->mac_type) {
947 case MAC_TYPE_EMAC:
948 val = 1;
949 break;
950 case MAC_TYPE_BMAC:
951 val = 0;
952 break;
953 default:
954 val = 0;
955 break;
956 }
957 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT, val);
958
959 if (nig_params) {
960 pkt_priority_to_cos = nig_params->pkt_priority_to_cos;
961
962 REG_WR(bp, port ? NIG_REG_P1_RX_COS0_PRIORITY_MASK :
963 NIG_REG_P0_RX_COS0_PRIORITY_MASK,
964 nig_params->rx_cos0_priority_mask);
965
966 REG_WR(bp, port ? NIG_REG_P1_RX_COS1_PRIORITY_MASK :
967 NIG_REG_P0_RX_COS1_PRIORITY_MASK,
968 nig_params->rx_cos1_priority_mask);
969
970 REG_WR(bp, port ? NIG_REG_LLFC_HIGH_PRIORITY_CLASSES_1 :
971 NIG_REG_LLFC_HIGH_PRIORITY_CLASSES_0,
972 nig_params->llfc_high_priority_classes);
973
974 REG_WR(bp, port ? NIG_REG_LLFC_LOW_PRIORITY_CLASSES_1 :
975 NIG_REG_LLFC_LOW_PRIORITY_CLASSES_0,
976 nig_params->llfc_low_priority_classes);
977 }
978 REG_WR(bp, port ? NIG_REG_P1_PKT_PRIORITY_TO_COS :
979 NIG_REG_P0_PKT_PRIORITY_TO_COS,
980 pkt_priority_to_cos);
981}
982
983
984void bnx2x_update_pfc(struct link_params *params,
985 struct link_vars *vars,
986 struct bnx2x_nig_brb_pfc_port_params *pfc_params)
987{
988 /**
989 * The PFC and pause are orthogonal to one another, meaning when
990 * PFC is enabled, the pause are disabled, and when PFC is
991 * disabled, pause are set according to the pause result.
992 */
993 u32 val;
994 struct bnx2x *bp = params->bp;
995
996 /* update NIG params */
997 bnx2x_update_pfc_nig(params, vars, pfc_params);
998
999 /* update BRB params */
1000 bnx2x_update_pfc_brb(params, vars, pfc_params);
1001
1002 if (!vars->link_up)
1003 return;
1004
1005 val = REG_RD(bp, MISC_REG_RESET_REG_2);
1006 if ((val & (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << params->port))
1007 == 0) {
1008 DP(NETIF_MSG_LINK, "About to update PFC in EMAC\n");
1009 bnx2x_emac_enable(params, vars, 0);
1010 return;
1011 }
1012
1013 DP(NETIF_MSG_LINK, "About to update PFC in BMAC\n");
1014 if (CHIP_IS_E2(bp))
1015 bnx2x_update_pfc_bmac2(params, vars, 0);
1016 else
1017 bnx2x_update_pfc_bmac1(params, vars);
1018
1019 val = 0;
1020 if ((params->feature_config_flags &
1021 FEATURE_CONFIG_PFC_ENABLED) ||
1022 (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
1023 val = 1;
1024 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + params->port*4, val);
1025}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001026
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001027static u8 bnx2x_bmac1_enable(struct link_params *params,
1028 struct link_vars *vars,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001029 u8 is_lb)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001030{
1031 struct bnx2x *bp = params->bp;
1032 u8 port = params->port;
1033 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
1034 NIG_REG_INGRESS_BMAC0_MEM;
1035 u32 wb_data[2];
1036 u32 val;
1037
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001038 DP(NETIF_MSG_LINK, "Enabling BigMAC1\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001039
1040 /* XGXS control */
1041 wb_data[0] = 0x3c;
1042 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001043 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_XGXS_CONTROL,
1044 wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001045
1046 /* tx MAC SA */
1047 wb_data[0] = ((params->mac_addr[2] << 24) |
1048 (params->mac_addr[3] << 16) |
1049 (params->mac_addr[4] << 8) |
1050 params->mac_addr[5]);
1051 wb_data[1] = ((params->mac_addr[0] << 8) |
1052 params->mac_addr[1]);
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001053 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_SOURCE_ADDR, wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001054
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001055 /* mac control */
1056 val = 0x3;
1057 if (is_lb) {
1058 val |= 0x4;
1059 DP(NETIF_MSG_LINK, "enable bmac loopback\n");
1060 }
1061 wb_data[0] = val;
1062 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001063 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL, wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001064
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001065 /* set rx mtu */
1066 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
1067 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001068 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_MAX_SIZE, wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001069
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001070 bnx2x_update_pfc_bmac1(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001071
1072 /* set tx mtu */
1073 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
1074 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001075 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_MAX_SIZE, wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001076
1077 /* set cnt max size */
1078 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
1079 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001080 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_CNT_MAX_SIZE, wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001081
1082 /* configure safc */
1083 wb_data[0] = 0x1000200;
1084 wb_data[1] = 0;
1085 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_LLFC_MSG_FLDS,
1086 wb_data, 2);
1087 /* fix for emulation */
1088 if (CHIP_REV_IS_EMUL(bp)) {
1089 wb_data[0] = 0xf000;
1090 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001091 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_PAUSE_THRESHOLD,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001092 wb_data, 2);
1093 }
1094
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001095
1096 return 0;
1097}
1098
1099static u8 bnx2x_bmac2_enable(struct link_params *params,
1100 struct link_vars *vars,
1101 u8 is_lb)
1102{
1103 struct bnx2x *bp = params->bp;
1104 u8 port = params->port;
1105 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
1106 NIG_REG_INGRESS_BMAC0_MEM;
1107 u32 wb_data[2];
1108
1109 DP(NETIF_MSG_LINK, "Enabling BigMAC2\n");
1110
1111 wb_data[0] = 0;
1112 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001113 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_BMAC_CONTROL, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001114 udelay(30);
1115
1116 /* XGXS control: Reset phy HW, MDIO registers, PHY PLL and BMAC */
1117 wb_data[0] = 0x3c;
1118 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001119 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_BMAC_XGXS_CONTROL,
1120 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001121
1122 udelay(30);
1123
1124 /* tx MAC SA */
1125 wb_data[0] = ((params->mac_addr[2] << 24) |
1126 (params->mac_addr[3] << 16) |
1127 (params->mac_addr[4] << 8) |
1128 params->mac_addr[5]);
1129 wb_data[1] = ((params->mac_addr[0] << 8) |
1130 params->mac_addr[1]);
1131 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_SOURCE_ADDR,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001132 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001133
1134 udelay(30);
1135
1136 /* Configure SAFC */
1137 wb_data[0] = 0x1000200;
1138 wb_data[1] = 0;
1139 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_LLFC_MSG_FLDS,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001140 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001141 udelay(30);
1142
1143 /* set rx mtu */
1144 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
1145 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001146 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_MAX_SIZE, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001147 udelay(30);
1148
1149 /* set tx mtu */
1150 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
1151 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001152 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_MAX_SIZE, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001153 udelay(30);
1154 /* set cnt max size */
1155 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD - 2;
1156 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001157 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_CNT_MAX_SIZE, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001158 udelay(30);
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001159 bnx2x_update_pfc_bmac2(params, vars, is_lb);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001160
1161 return 0;
1162}
1163
stephen hemminger8d962862010-10-21 07:50:56 +00001164static u8 bnx2x_bmac_enable(struct link_params *params,
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001165 struct link_vars *vars,
1166 u8 is_lb)
1167{
1168 u8 rc, port = params->port;
1169 struct bnx2x *bp = params->bp;
1170 u32 val;
1171 /* reset and unreset the BigMac */
1172 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001173 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
Yaniv Rosner1d9c05d2010-11-01 05:32:25 +00001174 msleep(1);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001175
1176 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001177 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001178
1179 /* enable access for bmac registers */
1180 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
1181
1182 /* Enable BMAC according to BMAC type*/
1183 if (CHIP_IS_E2(bp))
1184 rc = bnx2x_bmac2_enable(params, vars, is_lb);
1185 else
1186 rc = bnx2x_bmac1_enable(params, vars, is_lb);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001187 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0x1);
1188 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 0x0);
1189 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 0x0);
1190 val = 0;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001191 if ((params->feature_config_flags &
1192 FEATURE_CONFIG_PFC_ENABLED) ||
1193 (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001194 val = 1;
1195 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, val);
1196 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x0);
1197 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x0);
1198 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, 0x0);
1199 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x1);
1200 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x1);
1201
1202 vars->mac_type = MAC_TYPE_BMAC;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001203 return rc;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001204}
1205
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001206
1207static void bnx2x_update_mng(struct link_params *params, u32 link_status)
1208{
1209 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00001210
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001211 REG_WR(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001212 offsetof(struct shmem_region,
1213 port_mb[params->port].link_status), link_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001214}
1215
1216static void bnx2x_bmac_rx_disable(struct bnx2x *bp, u8 port)
1217{
1218 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001219 NIG_REG_INGRESS_BMAC0_MEM;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001220 u32 wb_data[2];
Eilon Greenstein3196a882008-08-13 15:58:49 -07001221 u32 nig_bmac_enable = REG_RD(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001222
1223 /* Only if the bmac is out of reset */
1224 if (REG_RD(bp, MISC_REG_RESET_REG_2) &
1225 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port) &&
1226 nig_bmac_enable) {
1227
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001228 if (CHIP_IS_E2(bp)) {
1229 /* Clear Rx Enable bit in BMAC_CONTROL register */
1230 REG_RD_DMAE(bp, bmac_addr +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001231 BIGMAC2_REGISTER_BMAC_CONTROL,
1232 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001233 wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
1234 REG_WR_DMAE(bp, bmac_addr +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001235 BIGMAC2_REGISTER_BMAC_CONTROL,
1236 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001237 } else {
1238 /* Clear Rx Enable bit in BMAC_CONTROL register */
1239 REG_RD_DMAE(bp, bmac_addr +
1240 BIGMAC_REGISTER_BMAC_CONTROL,
1241 wb_data, 2);
1242 wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
1243 REG_WR_DMAE(bp, bmac_addr +
1244 BIGMAC_REGISTER_BMAC_CONTROL,
1245 wb_data, 2);
1246 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001247 msleep(1);
1248 }
1249}
1250
1251static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001252 u32 line_speed)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001253{
1254 struct bnx2x *bp = params->bp;
1255 u8 port = params->port;
1256 u32 init_crd, crd;
1257 u32 count = 1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001258
1259 /* disable port */
1260 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x1);
1261
1262 /* wait for init credit */
1263 init_crd = REG_RD(bp, PBF_REG_P0_INIT_CRD + port*4);
1264 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
1265 DP(NETIF_MSG_LINK, "init_crd 0x%x crd 0x%x\n", init_crd, crd);
1266
1267 while ((init_crd != crd) && count) {
1268 msleep(5);
1269
1270 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
1271 count--;
1272 }
1273 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
1274 if (init_crd != crd) {
1275 DP(NETIF_MSG_LINK, "BUG! init_crd 0x%x != crd 0x%x\n",
1276 init_crd, crd);
1277 return -EINVAL;
1278 }
1279
David S. Millerc0700f92008-12-16 23:53:20 -08001280 if (flow_ctrl & BNX2X_FLOW_CTRL_RX ||
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001281 line_speed == SPEED_10 ||
1282 line_speed == SPEED_100 ||
1283 line_speed == SPEED_1000 ||
1284 line_speed == SPEED_2500) {
1285 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001286 /* update threshold */
1287 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, 0);
1288 /* update init credit */
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001289 init_crd = 778; /* (800-18-4) */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001290
1291 } else {
1292 u32 thresh = (ETH_MAX_JUMBO_PACKET_SIZE +
1293 ETH_OVREHEAD)/16;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001294 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001295 /* update threshold */
1296 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, thresh);
1297 /* update init credit */
1298 switch (line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001299 case SPEED_10000:
1300 init_crd = thresh + 553 - 22;
1301 break;
1302
1303 case SPEED_12000:
1304 init_crd = thresh + 664 - 22;
1305 break;
1306
1307 case SPEED_13000:
1308 init_crd = thresh + 742 - 22;
1309 break;
1310
1311 case SPEED_16000:
1312 init_crd = thresh + 778 - 22;
1313 break;
1314 default:
1315 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
1316 line_speed);
1317 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001318 }
1319 }
1320 REG_WR(bp, PBF_REG_P0_INIT_CRD + port*4, init_crd);
1321 DP(NETIF_MSG_LINK, "PBF updated to speed %d credit %d\n",
1322 line_speed, init_crd);
1323
1324 /* probe the credit changes */
1325 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x1);
1326 msleep(5);
1327 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x0);
1328
1329 /* enable port */
1330 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x0);
1331 return 0;
1332}
1333
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00001334static u32 bnx2x_get_emac_base(struct bnx2x *bp,
1335 u32 mdc_mdio_access, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001336{
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00001337 u32 emac_base = 0;
1338 switch (mdc_mdio_access) {
1339 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_PHY_TYPE:
1340 break;
1341 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC0:
1342 if (REG_RD(bp, NIG_REG_PORT_SWAP))
1343 emac_base = GRCBASE_EMAC1;
1344 else
1345 emac_base = GRCBASE_EMAC0;
1346 break;
1347 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1:
Eilon Greenstein589abe32009-02-12 08:36:55 +00001348 if (REG_RD(bp, NIG_REG_PORT_SWAP))
1349 emac_base = GRCBASE_EMAC0;
1350 else
1351 emac_base = GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001352 break;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00001353 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH:
1354 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
1355 break;
1356 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_SWAPPED:
Eilon Greenstein6378c022008-08-13 15:59:25 -07001357 emac_base = (port) ? GRCBASE_EMAC0 : GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001358 break;
1359 default:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001360 break;
1361 }
1362 return emac_base;
1363
1364}
1365
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001366u8 bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy,
1367 u8 devad, u16 reg, u16 val)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001368{
1369 u32 tmp, saved_mode;
1370 u8 i, rc = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001371
1372 /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
1373 * (a value of 49==0x31) and make sure that the AUTO poll is off
1374 */
Eilon Greenstein589abe32009-02-12 08:36:55 +00001375
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001376 saved_mode = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001377 tmp = saved_mode & ~(EMAC_MDIO_MODE_AUTO_POLL |
1378 EMAC_MDIO_MODE_CLOCK_CNT);
1379 tmp |= (EMAC_MDIO_MODE_CLAUSE_45 |
1380 (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001381 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, tmp);
1382 REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001383 udelay(40);
1384
1385 /* address */
1386
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001387 tmp = ((phy->addr << 21) | (devad << 16) | reg |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001388 EMAC_MDIO_COMM_COMMAND_ADDRESS |
1389 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001390 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001391
1392 for (i = 0; i < 50; i++) {
1393 udelay(10);
1394
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001395 tmp = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001396 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
1397 udelay(5);
1398 break;
1399 }
1400 }
1401 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
1402 DP(NETIF_MSG_LINK, "write phy register failed\n");
1403 rc = -EFAULT;
1404 } else {
1405 /* data */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001406 tmp = ((phy->addr << 21) | (devad << 16) | val |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001407 EMAC_MDIO_COMM_COMMAND_WRITE_45 |
1408 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001409 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001410
1411 for (i = 0; i < 50; i++) {
1412 udelay(10);
1413
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001414 tmp = REG_RD(bp, phy->mdio_ctrl +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001415 EMAC_REG_EMAC_MDIO_COMM);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001416 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
1417 udelay(5);
1418 break;
1419 }
1420 }
1421 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
1422 DP(NETIF_MSG_LINK, "write phy register failed\n");
1423 rc = -EFAULT;
1424 }
1425 }
1426
1427 /* Restore the saved mode */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001428 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001429
1430 return rc;
1431}
1432
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001433u8 bnx2x_cl45_read(struct bnx2x *bp, struct bnx2x_phy *phy,
1434 u8 devad, u16 reg, u16 *ret_val)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001435{
1436 u32 val, saved_mode;
1437 u16 i;
1438 u8 rc = 0;
1439
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001440 /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
1441 * (a value of 49==0x31) and make sure that the AUTO poll is off
1442 */
Eilon Greenstein589abe32009-02-12 08:36:55 +00001443
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001444 saved_mode = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
1445 val = saved_mode & ~((EMAC_MDIO_MODE_AUTO_POLL |
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001446 EMAC_MDIO_MODE_CLOCK_CNT));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001447 val |= (EMAC_MDIO_MODE_CLAUSE_45 |
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00001448 (49L << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001449 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, val);
1450 REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001451 udelay(40);
1452
1453 /* address */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001454 val = ((phy->addr << 21) | (devad << 16) | reg |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001455 EMAC_MDIO_COMM_COMMAND_ADDRESS |
1456 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001457 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001458
1459 for (i = 0; i < 50; i++) {
1460 udelay(10);
1461
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001462 val = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001463 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
1464 udelay(5);
1465 break;
1466 }
1467 }
1468 if (val & EMAC_MDIO_COMM_START_BUSY) {
1469 DP(NETIF_MSG_LINK, "read phy register failed\n");
1470
1471 *ret_val = 0;
1472 rc = -EFAULT;
1473
1474 } else {
1475 /* data */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001476 val = ((phy->addr << 21) | (devad << 16) |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001477 EMAC_MDIO_COMM_COMMAND_READ_45 |
1478 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001479 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001480
1481 for (i = 0; i < 50; i++) {
1482 udelay(10);
1483
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001484 val = REG_RD(bp, phy->mdio_ctrl +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001485 EMAC_REG_EMAC_MDIO_COMM);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001486 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
1487 *ret_val = (u16)(val & EMAC_MDIO_COMM_DATA);
1488 break;
1489 }
1490 }
1491 if (val & EMAC_MDIO_COMM_START_BUSY) {
1492 DP(NETIF_MSG_LINK, "read phy register failed\n");
1493
1494 *ret_val = 0;
1495 rc = -EFAULT;
1496 }
1497 }
1498
1499 /* Restore the saved mode */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001500 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001501
1502 return rc;
1503}
1504
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001505u8 bnx2x_phy_read(struct link_params *params, u8 phy_addr,
1506 u8 devad, u16 reg, u16 *ret_val)
1507{
1508 u8 phy_index;
1509 /**
1510 * Probe for the phy according to the given phy_addr, and execute
1511 * the read request on it
1512 */
1513 for (phy_index = 0; phy_index < params->num_phys; phy_index++) {
1514 if (params->phy[phy_index].addr == phy_addr) {
1515 return bnx2x_cl45_read(params->bp,
1516 &params->phy[phy_index], devad,
1517 reg, ret_val);
1518 }
1519 }
1520 return -EINVAL;
1521}
1522
1523u8 bnx2x_phy_write(struct link_params *params, u8 phy_addr,
1524 u8 devad, u16 reg, u16 val)
1525{
1526 u8 phy_index;
1527 /**
1528 * Probe for the phy according to the given phy_addr, and execute
1529 * the write request on it
1530 */
1531 for (phy_index = 0; phy_index < params->num_phys; phy_index++) {
1532 if (params->phy[phy_index].addr == phy_addr) {
1533 return bnx2x_cl45_write(params->bp,
1534 &params->phy[phy_index], devad,
1535 reg, val);
1536 }
1537 }
1538 return -EINVAL;
1539}
1540
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001541static void bnx2x_set_aer_mmd_xgxs(struct link_params *params,
1542 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001543{
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001544 u32 ser_lane;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001545 u16 offset, aer_val;
1546 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001547 ser_lane = ((params->lane_config &
1548 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
1549 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
1550
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001551 offset = phy->addr + ser_lane;
1552 if (CHIP_IS_E2(bp))
Yaniv Rosner82a0d472011-01-18 04:33:52 +00001553 aer_val = 0x3800 + offset - 1;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001554 else
1555 aer_val = 0x3800 + offset;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001556 CL22_WR_OVER_CL45(bp, phy, MDIO_REG_BANK_AER_BLOCK,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001557 MDIO_AER_BLOCK_AER_REG, aer_val);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001558}
1559static void bnx2x_set_aer_mmd_serdes(struct bnx2x *bp,
1560 struct bnx2x_phy *phy)
1561{
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001562 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001563 MDIO_REG_BANK_AER_BLOCK,
1564 MDIO_AER_BLOCK_AER_REG, 0x3800);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001565}
1566
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001567/******************************************************************/
1568/* Internal phy section */
1569/******************************************************************/
1570
1571static void bnx2x_set_serdes_access(struct bnx2x *bp, u8 port)
1572{
1573 u32 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
1574
1575 /* Set Clause 22 */
1576 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + port*0x10, 1);
1577 REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245f8000);
1578 udelay(500);
1579 REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245d000f);
1580 udelay(500);
1581 /* Set Clause 45 */
1582 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + port*0x10, 0);
1583}
1584
1585static void bnx2x_serdes_deassert(struct bnx2x *bp, u8 port)
1586{
1587 u32 val;
1588
1589 DP(NETIF_MSG_LINK, "bnx2x_serdes_deassert\n");
1590
1591 val = SERDES_RESET_BITS << (port*16);
1592
1593 /* reset and unreset the SerDes/XGXS */
1594 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR, val);
1595 udelay(500);
1596 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET, val);
1597
1598 bnx2x_set_serdes_access(bp, port);
1599
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001600 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_DEVAD + port*0x10,
1601 DEFAULT_PHY_DEV_ADDR);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001602}
1603
1604static void bnx2x_xgxs_deassert(struct link_params *params)
1605{
1606 struct bnx2x *bp = params->bp;
1607 u8 port;
1608 u32 val;
1609 DP(NETIF_MSG_LINK, "bnx2x_xgxs_deassert\n");
1610 port = params->port;
1611
1612 val = XGXS_RESET_BITS << (port*16);
1613
1614 /* reset and unreset the SerDes/XGXS */
1615 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR, val);
1616 udelay(500);
1617 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET, val);
1618
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001619 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_ST + port*0x18, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001620 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001621 params->phy[INT_PHY].def_md_devad);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001622}
1623
Yaniv Rosnera22f0782010-09-07 11:41:20 +00001624
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001625void bnx2x_link_status_update(struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001626 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001627{
1628 struct bnx2x *bp = params->bp;
1629 u8 link_10g;
1630 u8 port = params->port;
1631
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001632 vars->link_status = REG_RD(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001633 offsetof(struct shmem_region,
1634 port_mb[port].link_status));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001635
1636 vars->link_up = (vars->link_status & LINK_STATUS_LINK_UP);
1637
1638 if (vars->link_up) {
1639 DP(NETIF_MSG_LINK, "phy link up\n");
1640
1641 vars->phy_link_up = 1;
1642 vars->duplex = DUPLEX_FULL;
1643 switch (vars->link_status &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001644 LINK_STATUS_SPEED_AND_DUPLEX_MASK) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001645 case LINK_10THD:
1646 vars->duplex = DUPLEX_HALF;
1647 /* fall thru */
1648 case LINK_10TFD:
1649 vars->line_speed = SPEED_10;
1650 break;
1651
1652 case LINK_100TXHD:
1653 vars->duplex = DUPLEX_HALF;
1654 /* fall thru */
1655 case LINK_100T4:
1656 case LINK_100TXFD:
1657 vars->line_speed = SPEED_100;
1658 break;
1659
1660 case LINK_1000THD:
1661 vars->duplex = DUPLEX_HALF;
1662 /* fall thru */
1663 case LINK_1000TFD:
1664 vars->line_speed = SPEED_1000;
1665 break;
1666
1667 case LINK_2500THD:
1668 vars->duplex = DUPLEX_HALF;
1669 /* fall thru */
1670 case LINK_2500TFD:
1671 vars->line_speed = SPEED_2500;
1672 break;
1673
1674 case LINK_10GTFD:
1675 vars->line_speed = SPEED_10000;
1676 break;
1677
1678 case LINK_12GTFD:
1679 vars->line_speed = SPEED_12000;
1680 break;
1681
1682 case LINK_12_5GTFD:
1683 vars->line_speed = SPEED_12500;
1684 break;
1685
1686 case LINK_13GTFD:
1687 vars->line_speed = SPEED_13000;
1688 break;
1689
1690 case LINK_15GTFD:
1691 vars->line_speed = SPEED_15000;
1692 break;
1693
1694 case LINK_16GTFD:
1695 vars->line_speed = SPEED_16000;
1696 break;
1697
1698 default:
1699 break;
1700 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001701 vars->flow_ctrl = 0;
1702 if (vars->link_status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED)
1703 vars->flow_ctrl |= BNX2X_FLOW_CTRL_TX;
1704
1705 if (vars->link_status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED)
1706 vars->flow_ctrl |= BNX2X_FLOW_CTRL_RX;
1707
1708 if (!vars->flow_ctrl)
1709 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
1710
1711 if (vars->line_speed &&
1712 ((vars->line_speed == SPEED_10) ||
1713 (vars->line_speed == SPEED_100))) {
1714 vars->phy_flags |= PHY_SGMII_FLAG;
1715 } else {
1716 vars->phy_flags &= ~PHY_SGMII_FLAG;
1717 }
1718
1719 /* anything 10 and over uses the bmac */
1720 link_10g = ((vars->line_speed == SPEED_10000) ||
1721 (vars->line_speed == SPEED_12000) ||
1722 (vars->line_speed == SPEED_12500) ||
1723 (vars->line_speed == SPEED_13000) ||
1724 (vars->line_speed == SPEED_15000) ||
1725 (vars->line_speed == SPEED_16000));
1726 if (link_10g)
1727 vars->mac_type = MAC_TYPE_BMAC;
1728 else
1729 vars->mac_type = MAC_TYPE_EMAC;
1730
1731 } else { /* link down */
1732 DP(NETIF_MSG_LINK, "phy link down\n");
1733
1734 vars->phy_link_up = 0;
1735
1736 vars->line_speed = 0;
1737 vars->duplex = DUPLEX_FULL;
1738 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
1739
1740 /* indicate no mac active */
1741 vars->mac_type = MAC_TYPE_NONE;
1742 }
1743
1744 DP(NETIF_MSG_LINK, "link_status 0x%x phy_link_up %x\n",
1745 vars->link_status, vars->phy_link_up);
1746 DP(NETIF_MSG_LINK, "line_speed %x duplex %x flow_ctrl 0x%x\n",
1747 vars->line_speed, vars->duplex, vars->flow_ctrl);
1748}
1749
1750
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001751static void bnx2x_set_master_ln(struct link_params *params,
1752 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001753{
1754 struct bnx2x *bp = params->bp;
1755 u16 new_master_ln, ser_lane;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001756 ser_lane = ((params->lane_config &
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001757 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001758 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001759
1760 /* set the master_ln for AN */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001761 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001762 MDIO_REG_BANK_XGXS_BLOCK2,
1763 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
1764 &new_master_ln);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001765
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001766 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001767 MDIO_REG_BANK_XGXS_BLOCK2 ,
1768 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
1769 (new_master_ln | ser_lane));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001770}
1771
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001772static u8 bnx2x_reset_unicore(struct link_params *params,
1773 struct bnx2x_phy *phy,
1774 u8 set_serdes)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001775{
1776 struct bnx2x *bp = params->bp;
1777 u16 mii_control;
1778 u16 i;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001779 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001780 MDIO_REG_BANK_COMBO_IEEE0,
1781 MDIO_COMBO_IEEE0_MII_CONTROL, &mii_control);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001782
1783 /* reset the unicore */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001784 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001785 MDIO_REG_BANK_COMBO_IEEE0,
1786 MDIO_COMBO_IEEE0_MII_CONTROL,
1787 (mii_control |
1788 MDIO_COMBO_IEEO_MII_CONTROL_RESET));
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001789 if (set_serdes)
1790 bnx2x_set_serdes_access(bp, params->port);
Eilon Greensteinc1b73992009-02-12 08:37:07 +00001791
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001792 /* wait for the reset to self clear */
1793 for (i = 0; i < MDIO_ACCESS_TIMEOUT; i++) {
1794 udelay(5);
1795
1796 /* the reset erased the previous bank value */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001797 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001798 MDIO_REG_BANK_COMBO_IEEE0,
1799 MDIO_COMBO_IEEE0_MII_CONTROL,
1800 &mii_control);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001801
1802 if (!(mii_control & MDIO_COMBO_IEEO_MII_CONTROL_RESET)) {
1803 udelay(5);
1804 return 0;
1805 }
1806 }
1807
1808 DP(NETIF_MSG_LINK, "BUG! XGXS is still in reset!\n");
1809 return -EINVAL;
1810
1811}
1812
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001813static void bnx2x_set_swap_lanes(struct link_params *params,
1814 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001815{
1816 struct bnx2x *bp = params->bp;
1817 /* Each two bits represents a lane number:
1818 No swap is 0123 => 0x1b no need to enable the swap */
1819 u16 ser_lane, rx_lane_swap, tx_lane_swap;
1820
1821 ser_lane = ((params->lane_config &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001822 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
1823 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001824 rx_lane_swap = ((params->lane_config &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001825 PORT_HW_CFG_LANE_SWAP_CFG_RX_MASK) >>
1826 PORT_HW_CFG_LANE_SWAP_CFG_RX_SHIFT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001827 tx_lane_swap = ((params->lane_config &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001828 PORT_HW_CFG_LANE_SWAP_CFG_TX_MASK) >>
1829 PORT_HW_CFG_LANE_SWAP_CFG_TX_SHIFT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001830
1831 if (rx_lane_swap != 0x1b) {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001832 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001833 MDIO_REG_BANK_XGXS_BLOCK2,
1834 MDIO_XGXS_BLOCK2_RX_LN_SWAP,
1835 (rx_lane_swap |
1836 MDIO_XGXS_BLOCK2_RX_LN_SWAP_ENABLE |
1837 MDIO_XGXS_BLOCK2_RX_LN_SWAP_FORCE_ENABLE));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001838 } else {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001839 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001840 MDIO_REG_BANK_XGXS_BLOCK2,
1841 MDIO_XGXS_BLOCK2_RX_LN_SWAP, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001842 }
1843
1844 if (tx_lane_swap != 0x1b) {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001845 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001846 MDIO_REG_BANK_XGXS_BLOCK2,
1847 MDIO_XGXS_BLOCK2_TX_LN_SWAP,
1848 (tx_lane_swap |
1849 MDIO_XGXS_BLOCK2_TX_LN_SWAP_ENABLE));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001850 } else {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001851 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001852 MDIO_REG_BANK_XGXS_BLOCK2,
1853 MDIO_XGXS_BLOCK2_TX_LN_SWAP, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001854 }
1855}
1856
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001857static void bnx2x_set_parallel_detection(struct bnx2x_phy *phy,
1858 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001859{
1860 struct bnx2x *bp = params->bp;
1861 u16 control2;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001862 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001863 MDIO_REG_BANK_SERDES_DIGITAL,
1864 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
1865 &control2);
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001866 if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
Yaniv Rosner18afb0a2009-11-05 19:18:04 +02001867 control2 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
1868 else
1869 control2 &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001870 DP(NETIF_MSG_LINK, "phy->speed_cap_mask = 0x%x, control2 = 0x%x\n",
1871 phy->speed_cap_mask, control2);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001872 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001873 MDIO_REG_BANK_SERDES_DIGITAL,
1874 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
1875 control2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001876
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001877 if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00001878 (phy->speed_cap_mask &
Yaniv Rosner18afb0a2009-11-05 19:18:04 +02001879 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001880 DP(NETIF_MSG_LINK, "XGXS\n");
1881
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001882 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001883 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1884 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK,
1885 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001886
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001887 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001888 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1889 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
1890 &control2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001891
1892
1893 control2 |=
1894 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN;
1895
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001896 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001897 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1898 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
1899 control2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001900
1901 /* Disable parallel detection of HiG */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001902 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001903 MDIO_REG_BANK_XGXS_BLOCK2,
1904 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G,
1905 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_CX4_XGXS |
1906 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_HIGIG_XGXS);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001907 }
1908}
1909
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001910static void bnx2x_set_autoneg(struct bnx2x_phy *phy,
1911 struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001912 struct link_vars *vars,
1913 u8 enable_cl73)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001914{
1915 struct bnx2x *bp = params->bp;
1916 u16 reg_val;
1917
1918 /* CL37 Autoneg */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001919 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001920 MDIO_REG_BANK_COMBO_IEEE0,
1921 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001922
1923 /* CL37 Autoneg Enabled */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001924 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001925 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_AN_EN;
1926 else /* CL37 Autoneg Disabled */
1927 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1928 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN);
1929
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001930 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001931 MDIO_REG_BANK_COMBO_IEEE0,
1932 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001933
1934 /* Enable/Disable Autodetection */
1935
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001936 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001937 MDIO_REG_BANK_SERDES_DIGITAL,
1938 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, &reg_val);
Eilon Greenstein239d6862009-08-12 08:23:04 +00001939 reg_val &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN |
1940 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT);
1941 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001942 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001943 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
1944 else
1945 reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
1946
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001947 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001948 MDIO_REG_BANK_SERDES_DIGITAL,
1949 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001950
1951 /* Enable TetonII and BAM autoneg */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001952 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001953 MDIO_REG_BANK_BAM_NEXT_PAGE,
1954 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001955 &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001956 if (vars->line_speed == SPEED_AUTO_NEG) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001957 /* Enable BAM aneg Mode and TetonII aneg Mode */
1958 reg_val |= (MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
1959 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
1960 } else {
1961 /* TetonII and BAM Autoneg Disabled */
1962 reg_val &= ~(MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
1963 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
1964 }
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001965 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001966 MDIO_REG_BANK_BAM_NEXT_PAGE,
1967 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
1968 reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001969
Eilon Greenstein239d6862009-08-12 08:23:04 +00001970 if (enable_cl73) {
1971 /* Enable Cl73 FSM status bits */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001972 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001973 MDIO_REG_BANK_CL73_USERB0,
1974 MDIO_CL73_USERB0_CL73_UCTRL,
1975 0xe);
Eilon Greenstein239d6862009-08-12 08:23:04 +00001976
1977 /* Enable BAM Station Manager*/
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001978 CL22_WR_OVER_CL45(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001979 MDIO_REG_BANK_CL73_USERB0,
1980 MDIO_CL73_USERB0_CL73_BAM_CTRL1,
1981 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN |
1982 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_STATION_MNGR_EN |
1983 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN);
1984
Yaniv Rosner7846e472009-11-05 19:18:07 +02001985 /* Advertise CL73 link speeds */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001986 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001987 MDIO_REG_BANK_CL73_IEEEB1,
1988 MDIO_CL73_IEEEB1_AN_ADV2,
1989 &reg_val);
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001990 if (phy->speed_cap_mask &
Yaniv Rosner7846e472009-11-05 19:18:07 +02001991 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
1992 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001993 if (phy->speed_cap_mask &
Yaniv Rosner7846e472009-11-05 19:18:07 +02001994 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
1995 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX;
Eilon Greenstein239d6862009-08-12 08:23:04 +00001996
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001997 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001998 MDIO_REG_BANK_CL73_IEEEB1,
1999 MDIO_CL73_IEEEB1_AN_ADV2,
2000 reg_val);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002001
Eilon Greenstein239d6862009-08-12 08:23:04 +00002002 /* CL73 Autoneg Enabled */
2003 reg_val = MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN;
2004
2005 } else /* CL73 Autoneg Disabled */
2006 reg_val = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002007
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002008 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002009 MDIO_REG_BANK_CL73_IEEEB0,
2010 MDIO_CL73_IEEEB0_CL73_AN_CONTROL, reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002011}
2012
2013/* program SerDes, forced speed */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002014static void bnx2x_program_serdes(struct bnx2x_phy *phy,
2015 struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002016 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002017{
2018 struct bnx2x *bp = params->bp;
2019 u16 reg_val;
2020
Eilon Greenstein57937202009-08-12 08:23:53 +00002021 /* program duplex, disable autoneg and sgmii*/
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002022 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002023 MDIO_REG_BANK_COMBO_IEEE0,
2024 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002025 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX |
Eilon Greenstein57937202009-08-12 08:23:53 +00002026 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
2027 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK);
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002028 if (phy->req_duplex == DUPLEX_FULL)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002029 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002030 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002031 MDIO_REG_BANK_COMBO_IEEE0,
2032 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002033
2034 /* program speed
2035 - needed only if the speed is greater than 1G (2.5G or 10G) */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002036 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002037 MDIO_REG_BANK_SERDES_DIGITAL,
2038 MDIO_SERDES_DIGITAL_MISC1, &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002039 /* clearing the speed value before setting the right speed */
2040 DP(NETIF_MSG_LINK, "MDIO_REG_BANK_SERDES_DIGITAL = 0x%x\n", reg_val);
2041
2042 reg_val &= ~(MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_MASK |
2043 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
2044
2045 if (!((vars->line_speed == SPEED_1000) ||
2046 (vars->line_speed == SPEED_100) ||
2047 (vars->line_speed == SPEED_10))) {
2048
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002049 reg_val |= (MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_156_25M |
2050 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002051 if (vars->line_speed == SPEED_10000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002052 reg_val |=
2053 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_10G_CX4;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002054 if (vars->line_speed == SPEED_13000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002055 reg_val |=
2056 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_13G;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002057 }
2058
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002059 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002060 MDIO_REG_BANK_SERDES_DIGITAL,
2061 MDIO_SERDES_DIGITAL_MISC1, reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002062
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002063}
2064
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002065static void bnx2x_set_brcm_cl37_advertisment(struct bnx2x_phy *phy,
2066 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002067{
2068 struct bnx2x *bp = params->bp;
2069 u16 val = 0;
2070
2071 /* configure the 48 bits for BAM AN */
2072
2073 /* set extended capabilities */
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002074 if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002075 val |= MDIO_OVER_1G_UP1_2_5G;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002076 if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002077 val |= MDIO_OVER_1G_UP1_10G;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002078 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002079 MDIO_REG_BANK_OVER_1G,
2080 MDIO_OVER_1G_UP1, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002081
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002082 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002083 MDIO_REG_BANK_OVER_1G,
2084 MDIO_OVER_1G_UP3, 0x400);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002085}
2086
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002087static void bnx2x_calc_ieee_aneg_adv(struct bnx2x_phy *phy,
2088 struct link_params *params, u16 *ieee_fc)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002089{
Yaniv Rosnerd5cb9e92009-11-05 19:18:10 +02002090 struct bnx2x *bp = params->bp;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002091 *ieee_fc = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002092 /* resolve pause mode and advertisement
2093 * Please refer to Table 28B-3 of the 802.3ab-1999 spec */
2094
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002095 switch (phy->req_flow_ctrl) {
David S. Millerc0700f92008-12-16 23:53:20 -08002096 case BNX2X_FLOW_CTRL_AUTO:
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002097 if (params->req_fc_auto_adv == BNX2X_FLOW_CTRL_BOTH)
2098 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
2099 else
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002100 *ieee_fc |=
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002101 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002102 break;
David S. Millerc0700f92008-12-16 23:53:20 -08002103 case BNX2X_FLOW_CTRL_TX:
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002104 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002105 break;
2106
David S. Millerc0700f92008-12-16 23:53:20 -08002107 case BNX2X_FLOW_CTRL_RX:
2108 case BNX2X_FLOW_CTRL_BOTH:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002109 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002110 break;
2111
David S. Millerc0700f92008-12-16 23:53:20 -08002112 case BNX2X_FLOW_CTRL_NONE:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002113 default:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002114 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002115 break;
2116 }
Yaniv Rosnerd5cb9e92009-11-05 19:18:10 +02002117 DP(NETIF_MSG_LINK, "ieee_fc = 0x%x\n", *ieee_fc);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002118}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002119
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002120static void bnx2x_set_ieee_aneg_advertisment(struct bnx2x_phy *phy,
2121 struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002122 u16 ieee_fc)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002123{
2124 struct bnx2x *bp = params->bp;
Yaniv Rosner7846e472009-11-05 19:18:07 +02002125 u16 val;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002126 /* for AN, we are always publishing full duplex */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002127
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002128 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002129 MDIO_REG_BANK_COMBO_IEEE0,
2130 MDIO_COMBO_IEEE0_AUTO_NEG_ADV, ieee_fc);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002131 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002132 MDIO_REG_BANK_CL73_IEEEB1,
2133 MDIO_CL73_IEEEB1_AN_ADV1, &val);
Yaniv Rosner7846e472009-11-05 19:18:07 +02002134 val &= ~MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_BOTH;
2135 val |= ((ieee_fc<<3) & MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002136 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002137 MDIO_REG_BANK_CL73_IEEEB1,
2138 MDIO_CL73_IEEEB1_AN_ADV1, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002139}
2140
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002141static void bnx2x_restart_autoneg(struct bnx2x_phy *phy,
2142 struct link_params *params,
2143 u8 enable_cl73)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002144{
2145 struct bnx2x *bp = params->bp;
Eilon Greenstein3a36f2e2009-02-12 08:37:09 +00002146 u16 mii_control;
Eilon Greenstein239d6862009-08-12 08:23:04 +00002147
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002148 DP(NETIF_MSG_LINK, "bnx2x_restart_autoneg\n");
Eilon Greenstein3a36f2e2009-02-12 08:37:09 +00002149 /* Enable and restart BAM/CL37 aneg */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002150
Eilon Greenstein239d6862009-08-12 08:23:04 +00002151 if (enable_cl73) {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002152 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002153 MDIO_REG_BANK_CL73_IEEEB0,
2154 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
2155 &mii_control);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002156
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002157 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002158 MDIO_REG_BANK_CL73_IEEEB0,
2159 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
2160 (mii_control |
2161 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN |
2162 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN));
Eilon Greenstein239d6862009-08-12 08:23:04 +00002163 } else {
2164
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002165 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002166 MDIO_REG_BANK_COMBO_IEEE0,
2167 MDIO_COMBO_IEEE0_MII_CONTROL,
2168 &mii_control);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002169 DP(NETIF_MSG_LINK,
2170 "bnx2x_restart_autoneg mii_control before = 0x%x\n",
2171 mii_control);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002172 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002173 MDIO_REG_BANK_COMBO_IEEE0,
2174 MDIO_COMBO_IEEE0_MII_CONTROL,
2175 (mii_control |
2176 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
2177 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN));
Eilon Greenstein239d6862009-08-12 08:23:04 +00002178 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002179}
2180
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002181static void bnx2x_initialize_sgmii_process(struct bnx2x_phy *phy,
2182 struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002183 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002184{
2185 struct bnx2x *bp = params->bp;
2186 u16 control1;
2187
2188 /* in SGMII mode, the unicore is always slave */
2189
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002190 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002191 MDIO_REG_BANK_SERDES_DIGITAL,
2192 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
2193 &control1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002194 control1 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT;
2195 /* set sgmii mode (and not fiber) */
2196 control1 &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE |
2197 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET |
2198 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_MSTR_MODE);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002199 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002200 MDIO_REG_BANK_SERDES_DIGITAL,
2201 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
2202 control1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002203
2204 /* if forced speed */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002205 if (!(vars->line_speed == SPEED_AUTO_NEG)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002206 /* set speed, disable autoneg */
2207 u16 mii_control;
2208
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002209 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002210 MDIO_REG_BANK_COMBO_IEEE0,
2211 MDIO_COMBO_IEEE0_MII_CONTROL,
2212 &mii_control);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002213 mii_control &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
2214 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK|
2215 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX);
2216
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002217 switch (vars->line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002218 case SPEED_100:
2219 mii_control |=
2220 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_100;
2221 break;
2222 case SPEED_1000:
2223 mii_control |=
2224 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_1000;
2225 break;
2226 case SPEED_10:
2227 /* there is nothing to set for 10M */
2228 break;
2229 default:
2230 /* invalid speed for SGMII */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002231 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
2232 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002233 break;
2234 }
2235
2236 /* setting the full duplex */
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002237 if (phy->req_duplex == DUPLEX_FULL)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002238 mii_control |=
2239 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002240 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002241 MDIO_REG_BANK_COMBO_IEEE0,
2242 MDIO_COMBO_IEEE0_MII_CONTROL,
2243 mii_control);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002244
2245 } else { /* AN mode */
2246 /* enable and restart AN */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002247 bnx2x_restart_autoneg(phy, params, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002248 }
2249}
2250
2251
2252/*
2253 * link management
2254 */
2255
2256static void bnx2x_pause_resolve(struct link_vars *vars, u32 pause_result)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002257{ /* LD LP */
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002258 switch (pause_result) { /* ASYM P ASYM P */
2259 case 0xb: /* 1 0 1 1 */
David S. Millerc0700f92008-12-16 23:53:20 -08002260 vars->flow_ctrl = BNX2X_FLOW_CTRL_TX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002261 break;
2262
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002263 case 0xe: /* 1 1 1 0 */
David S. Millerc0700f92008-12-16 23:53:20 -08002264 vars->flow_ctrl = BNX2X_FLOW_CTRL_RX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002265 break;
2266
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002267 case 0x5: /* 0 1 0 1 */
2268 case 0x7: /* 0 1 1 1 */
2269 case 0xd: /* 1 1 0 1 */
2270 case 0xf: /* 1 1 1 1 */
David S. Millerc0700f92008-12-16 23:53:20 -08002271 vars->flow_ctrl = BNX2X_FLOW_CTRL_BOTH;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002272 break;
2273
2274 default:
2275 break;
2276 }
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002277 if (pause_result & (1<<0))
2278 vars->link_status |= LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE;
2279 if (pause_result & (1<<1))
2280 vars->link_status |= LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002281}
2282
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002283static u8 bnx2x_direct_parallel_detect_used(struct bnx2x_phy *phy,
2284 struct link_params *params)
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02002285{
2286 struct bnx2x *bp = params->bp;
2287 u16 pd_10g, status2_1000x;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002288 if (phy->req_line_speed != SPEED_AUTO_NEG)
2289 return 0;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002290 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002291 MDIO_REG_BANK_SERDES_DIGITAL,
2292 MDIO_SERDES_DIGITAL_A_1000X_STATUS2,
2293 &status2_1000x);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002294 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002295 MDIO_REG_BANK_SERDES_DIGITAL,
2296 MDIO_SERDES_DIGITAL_A_1000X_STATUS2,
2297 &status2_1000x);
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02002298 if (status2_1000x & MDIO_SERDES_DIGITAL_A_1000X_STATUS2_AN_DISABLED) {
2299 DP(NETIF_MSG_LINK, "1G parallel detect link on port %d\n",
2300 params->port);
2301 return 1;
2302 }
2303
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002304 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002305 MDIO_REG_BANK_10G_PARALLEL_DETECT,
2306 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_STATUS,
2307 &pd_10g);
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02002308
2309 if (pd_10g & MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_STATUS_PD_LINK) {
2310 DP(NETIF_MSG_LINK, "10G parallel detect link on port %d\n",
2311 params->port);
2312 return 1;
2313 }
2314 return 0;
2315}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002316
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002317static void bnx2x_flow_ctrl_resolve(struct bnx2x_phy *phy,
2318 struct link_params *params,
2319 struct link_vars *vars,
2320 u32 gp_status)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002321{
2322 struct bnx2x *bp = params->bp;
Eilon Greenstein3196a882008-08-13 15:58:49 -07002323 u16 ld_pause; /* local driver */
2324 u16 lp_pause; /* link partner */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002325 u16 pause_result;
2326
David S. Millerc0700f92008-12-16 23:53:20 -08002327 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002328
2329 /* resolve from gp_status in case of AN complete and not sgmii */
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002330 if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO)
2331 vars->flow_ctrl = phy->req_flow_ctrl;
2332 else if (phy->req_line_speed != SPEED_AUTO_NEG)
2333 vars->flow_ctrl = params->req_fc_auto_adv;
2334 else if ((gp_status & MDIO_AN_CL73_OR_37_COMPLETE) &&
2335 (!(vars->phy_flags & PHY_SGMII_FLAG))) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002336 if (bnx2x_direct_parallel_detect_used(phy, params)) {
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02002337 vars->flow_ctrl = params->req_fc_auto_adv;
2338 return;
2339 }
Yaniv Rosner7846e472009-11-05 19:18:07 +02002340 if ((gp_status &
2341 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
2342 MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) ==
2343 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
2344 MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) {
2345
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002346 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002347 MDIO_REG_BANK_CL73_IEEEB1,
2348 MDIO_CL73_IEEEB1_AN_ADV1,
2349 &ld_pause);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002350 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002351 MDIO_REG_BANK_CL73_IEEEB1,
2352 MDIO_CL73_IEEEB1_AN_LP_ADV1,
2353 &lp_pause);
Yaniv Rosner7846e472009-11-05 19:18:07 +02002354 pause_result = (ld_pause &
2355 MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK)
2356 >> 8;
2357 pause_result |= (lp_pause &
2358 MDIO_CL73_IEEEB1_AN_LP_ADV1_PAUSE_MASK)
2359 >> 10;
2360 DP(NETIF_MSG_LINK, "pause_result CL73 0x%x\n",
2361 pause_result);
2362 } else {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002363 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002364 MDIO_REG_BANK_COMBO_IEEE0,
2365 MDIO_COMBO_IEEE0_AUTO_NEG_ADV,
2366 &ld_pause);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002367 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002368 MDIO_REG_BANK_COMBO_IEEE0,
2369 MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1,
2370 &lp_pause);
Yaniv Rosner7846e472009-11-05 19:18:07 +02002371 pause_result = (ld_pause &
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002372 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>5;
Yaniv Rosner7846e472009-11-05 19:18:07 +02002373 pause_result |= (lp_pause &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002374 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7;
Yaniv Rosner7846e472009-11-05 19:18:07 +02002375 DP(NETIF_MSG_LINK, "pause_result CL37 0x%x\n",
2376 pause_result);
2377 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002378 bnx2x_pause_resolve(vars, pause_result);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002379 }
2380 DP(NETIF_MSG_LINK, "flow_ctrl 0x%x\n", vars->flow_ctrl);
2381}
2382
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002383static void bnx2x_check_fallback_to_cl37(struct bnx2x_phy *phy,
2384 struct link_params *params)
Eilon Greenstein239d6862009-08-12 08:23:04 +00002385{
2386 struct bnx2x *bp = params->bp;
2387 u16 rx_status, ustat_val, cl37_fsm_recieved;
2388 DP(NETIF_MSG_LINK, "bnx2x_check_fallback_to_cl37\n");
2389 /* Step 1: Make sure signal is detected */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002390 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002391 MDIO_REG_BANK_RX0,
2392 MDIO_RX0_RX_STATUS,
2393 &rx_status);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002394 if ((rx_status & MDIO_RX0_RX_STATUS_SIGDET) !=
2395 (MDIO_RX0_RX_STATUS_SIGDET)) {
2396 DP(NETIF_MSG_LINK, "Signal is not detected. Restoring CL73."
2397 "rx_status(0x80b0) = 0x%x\n", rx_status);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002398 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002399 MDIO_REG_BANK_CL73_IEEEB0,
2400 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
2401 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002402 return;
2403 }
2404 /* Step 2: Check CL73 state machine */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002405 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002406 MDIO_REG_BANK_CL73_USERB0,
2407 MDIO_CL73_USERB0_CL73_USTAT1,
2408 &ustat_val);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002409 if ((ustat_val &
2410 (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK |
2411 MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) !=
2412 (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK |
2413 MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) {
2414 DP(NETIF_MSG_LINK, "CL73 state-machine is not stable. "
2415 "ustat_val(0x8371) = 0x%x\n", ustat_val);
2416 return;
2417 }
2418 /* Step 3: Check CL37 Message Pages received to indicate LP
2419 supports only CL37 */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002420 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002421 MDIO_REG_BANK_REMOTE_PHY,
2422 MDIO_REMOTE_PHY_MISC_RX_STATUS,
2423 &cl37_fsm_recieved);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002424 if ((cl37_fsm_recieved &
2425 (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG |
2426 MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) !=
2427 (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG |
2428 MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) {
2429 DP(NETIF_MSG_LINK, "No CL37 FSM were received. "
2430 "misc_rx_status(0x8330) = 0x%x\n",
2431 cl37_fsm_recieved);
2432 return;
2433 }
2434 /* The combined cl37/cl73 fsm state information indicating that we are
2435 connected to a device which does not support cl73, but does support
2436 cl37 BAM. In this case we disable cl73 and restart cl37 auto-neg */
2437 /* Disable CL73 */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002438 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002439 MDIO_REG_BANK_CL73_IEEEB0,
2440 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
2441 0);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002442 /* Restart CL37 autoneg */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002443 bnx2x_restart_autoneg(phy, params, 0);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002444 DP(NETIF_MSG_LINK, "Disabling CL73, and restarting CL37 autoneg\n");
2445}
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002446
2447static void bnx2x_xgxs_an_resolve(struct bnx2x_phy *phy,
2448 struct link_params *params,
2449 struct link_vars *vars,
2450 u32 gp_status)
2451{
2452 if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE)
2453 vars->link_status |=
2454 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
2455
2456 if (bnx2x_direct_parallel_detect_used(phy, params))
2457 vars->link_status |=
2458 LINK_STATUS_PARALLEL_DETECTION_USED;
2459}
2460
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002461static u8 bnx2x_link_settings_status(struct bnx2x_phy *phy,
2462 struct link_params *params,
2463 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002464{
2465 struct bnx2x *bp = params->bp;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002466 u16 new_line_speed, gp_status;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002467 u8 rc = 0;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002468
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002469 /* Read gp_status */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002470 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002471 MDIO_REG_BANK_GP_STATUS,
2472 MDIO_GP_STATUS_TOP_AN_STATUS1,
2473 &gp_status);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00002474
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002475 if (phy->req_line_speed == SPEED_AUTO_NEG)
2476 vars->link_status |= LINK_STATUS_AUTO_NEGOTIATE_ENABLED;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002477 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) {
2478 DP(NETIF_MSG_LINK, "phy link up gp_status=0x%x\n",
2479 gp_status);
2480
2481 vars->phy_link_up = 1;
2482 vars->link_status |= LINK_STATUS_LINK_UP;
2483
2484 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_DUPLEX_STATUS)
2485 vars->duplex = DUPLEX_FULL;
2486 else
2487 vars->duplex = DUPLEX_HALF;
2488
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002489 if (SINGLE_MEDIA_DIRECT(params)) {
2490 bnx2x_flow_ctrl_resolve(phy, params, vars, gp_status);
2491 if (phy->req_line_speed == SPEED_AUTO_NEG)
2492 bnx2x_xgxs_an_resolve(phy, params, vars,
2493 gp_status);
2494 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002495
2496 switch (gp_status & GP_STATUS_SPEED_MASK) {
2497 case GP_STATUS_10M:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002498 new_line_speed = SPEED_10;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002499 if (vars->duplex == DUPLEX_FULL)
2500 vars->link_status |= LINK_10TFD;
2501 else
2502 vars->link_status |= LINK_10THD;
2503 break;
2504
2505 case GP_STATUS_100M:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002506 new_line_speed = SPEED_100;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002507 if (vars->duplex == DUPLEX_FULL)
2508 vars->link_status |= LINK_100TXFD;
2509 else
2510 vars->link_status |= LINK_100TXHD;
2511 break;
2512
2513 case GP_STATUS_1G:
2514 case GP_STATUS_1G_KX:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002515 new_line_speed = SPEED_1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002516 if (vars->duplex == DUPLEX_FULL)
2517 vars->link_status |= LINK_1000TFD;
2518 else
2519 vars->link_status |= LINK_1000THD;
2520 break;
2521
2522 case GP_STATUS_2_5G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002523 new_line_speed = SPEED_2500;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002524 if (vars->duplex == DUPLEX_FULL)
2525 vars->link_status |= LINK_2500TFD;
2526 else
2527 vars->link_status |= LINK_2500THD;
2528 break;
2529
2530 case GP_STATUS_5G:
2531 case GP_STATUS_6G:
2532 DP(NETIF_MSG_LINK,
2533 "link speed unsupported gp_status 0x%x\n",
2534 gp_status);
2535 return -EINVAL;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002536
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002537 case GP_STATUS_10G_KX4:
2538 case GP_STATUS_10G_HIG:
2539 case GP_STATUS_10G_CX4:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002540 new_line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002541 vars->link_status |= LINK_10GTFD;
2542 break;
2543
2544 case GP_STATUS_12G_HIG:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002545 new_line_speed = SPEED_12000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002546 vars->link_status |= LINK_12GTFD;
2547 break;
2548
2549 case GP_STATUS_12_5G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002550 new_line_speed = SPEED_12500;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002551 vars->link_status |= LINK_12_5GTFD;
2552 break;
2553
2554 case GP_STATUS_13G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002555 new_line_speed = SPEED_13000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002556 vars->link_status |= LINK_13GTFD;
2557 break;
2558
2559 case GP_STATUS_15G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002560 new_line_speed = SPEED_15000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002561 vars->link_status |= LINK_15GTFD;
2562 break;
2563
2564 case GP_STATUS_16G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002565 new_line_speed = SPEED_16000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002566 vars->link_status |= LINK_16GTFD;
2567 break;
2568
2569 default:
2570 DP(NETIF_MSG_LINK,
2571 "link speed unsupported gp_status 0x%x\n",
2572 gp_status);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002573 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002574 }
2575
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002576 vars->line_speed = new_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002577
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002578 } else { /* link_down */
2579 DP(NETIF_MSG_LINK, "phy link down\n");
2580
2581 vars->phy_link_up = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002582
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002583 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08002584 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002585 vars->mac_type = MAC_TYPE_NONE;
Eilon Greenstein239d6862009-08-12 08:23:04 +00002586
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002587 if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
2588 SINGLE_MEDIA_DIRECT(params)) {
Eilon Greenstein239d6862009-08-12 08:23:04 +00002589 /* Check signal is detected */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002590 bnx2x_check_fallback_to_cl37(phy, params);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002591 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002592 }
2593
Frans Pop2381a552010-03-24 07:57:36 +00002594 DP(NETIF_MSG_LINK, "gp_status 0x%x phy_link_up %x line_speed %x\n",
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002595 gp_status, vars->phy_link_up, vars->line_speed);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002596 DP(NETIF_MSG_LINK, "duplex %x flow_ctrl 0x%x link_status 0x%x\n",
2597 vars->duplex, vars->flow_ctrl, vars->link_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002598 return rc;
2599}
2600
Eilon Greensteined8680a2009-02-12 08:37:12 +00002601static void bnx2x_set_gmii_tx_driver(struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002602{
2603 struct bnx2x *bp = params->bp;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002604 struct bnx2x_phy *phy = &params->phy[INT_PHY];
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002605 u16 lp_up2;
2606 u16 tx_driver;
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00002607 u16 bank;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002608
2609 /* read precomp */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002610 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002611 MDIO_REG_BANK_OVER_1G,
2612 MDIO_OVER_1G_LP_UP2, &lp_up2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002613
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002614 /* bits [10:7] at lp_up2, positioned at [15:12] */
2615 lp_up2 = (((lp_up2 & MDIO_OVER_1G_LP_UP2_PREEMPHASIS_MASK) >>
2616 MDIO_OVER_1G_LP_UP2_PREEMPHASIS_SHIFT) <<
2617 MDIO_TX0_TX_DRIVER_PREEMPHASIS_SHIFT);
2618
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00002619 if (lp_up2 == 0)
2620 return;
2621
2622 for (bank = MDIO_REG_BANK_TX0; bank <= MDIO_REG_BANK_TX3;
2623 bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0)) {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002624 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002625 bank,
2626 MDIO_TX0_TX_DRIVER, &tx_driver);
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00002627
2628 /* replace tx_driver bits [15:12] */
2629 if (lp_up2 !=
2630 (tx_driver & MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK)) {
2631 tx_driver &= ~MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK;
2632 tx_driver |= lp_up2;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002633 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002634 bank,
2635 MDIO_TX0_TX_DRIVER, tx_driver);
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00002636 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002637 }
2638}
2639
2640static u8 bnx2x_emac_program(struct link_params *params,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002641 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002642{
2643 struct bnx2x *bp = params->bp;
2644 u8 port = params->port;
2645 u16 mode = 0;
2646
2647 DP(NETIF_MSG_LINK, "setting link speed & duplex\n");
2648 bnx2x_bits_dis(bp, GRCBASE_EMAC0 + port*0x400 +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002649 EMAC_REG_EMAC_MODE,
2650 (EMAC_MODE_25G_MODE |
2651 EMAC_MODE_PORT_MII_10M |
2652 EMAC_MODE_HALF_DUPLEX));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002653 switch (vars->line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002654 case SPEED_10:
2655 mode |= EMAC_MODE_PORT_MII_10M;
2656 break;
2657
2658 case SPEED_100:
2659 mode |= EMAC_MODE_PORT_MII;
2660 break;
2661
2662 case SPEED_1000:
2663 mode |= EMAC_MODE_PORT_GMII;
2664 break;
2665
2666 case SPEED_2500:
2667 mode |= (EMAC_MODE_25G_MODE | EMAC_MODE_PORT_GMII);
2668 break;
2669
2670 default:
2671 /* 10G not valid for EMAC */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002672 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
2673 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002674 return -EINVAL;
2675 }
2676
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002677 if (vars->duplex == DUPLEX_HALF)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002678 mode |= EMAC_MODE_HALF_DUPLEX;
2679 bnx2x_bits_en(bp,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002680 GRCBASE_EMAC0 + port*0x400 + EMAC_REG_EMAC_MODE,
2681 mode);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002682
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00002683 bnx2x_set_led(params, vars, LED_MODE_OPER, vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002684 return 0;
2685}
2686
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002687static void bnx2x_set_preemphasis(struct bnx2x_phy *phy,
2688 struct link_params *params)
2689{
2690
2691 u16 bank, i = 0;
2692 struct bnx2x *bp = params->bp;
2693
2694 for (bank = MDIO_REG_BANK_RX0, i = 0; bank <= MDIO_REG_BANK_RX3;
2695 bank += (MDIO_REG_BANK_RX1-MDIO_REG_BANK_RX0), i++) {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002696 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002697 bank,
2698 MDIO_RX0_RX_EQ_BOOST,
2699 phy->rx_preemphasis[i]);
2700 }
2701
2702 for (bank = MDIO_REG_BANK_TX0, i = 0; bank <= MDIO_REG_BANK_TX3;
2703 bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0), i++) {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002704 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002705 bank,
2706 MDIO_TX0_TX_DRIVER,
2707 phy->tx_preemphasis[i]);
2708 }
2709}
2710
2711static void bnx2x_init_internal_phy(struct bnx2x_phy *phy,
2712 struct link_params *params,
2713 struct link_vars *vars)
2714{
2715 struct bnx2x *bp = params->bp;
2716 u8 enable_cl73 = (SINGLE_MEDIA_DIRECT(params) ||
2717 (params->loopback_mode == LOOPBACK_XGXS));
2718 if (!(vars->phy_flags & PHY_SGMII_FLAG)) {
2719 if (SINGLE_MEDIA_DIRECT(params) &&
2720 (params->feature_config_flags &
2721 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED))
2722 bnx2x_set_preemphasis(phy, params);
2723
2724 /* forced speed requested? */
2725 if (vars->line_speed != SPEED_AUTO_NEG ||
2726 (SINGLE_MEDIA_DIRECT(params) &&
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002727 params->loopback_mode == LOOPBACK_EXT)) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002728 DP(NETIF_MSG_LINK, "not SGMII, no AN\n");
2729
2730 /* disable autoneg */
2731 bnx2x_set_autoneg(phy, params, vars, 0);
2732
2733 /* program speed and duplex */
2734 bnx2x_program_serdes(phy, params, vars);
2735
2736 } else { /* AN_mode */
2737 DP(NETIF_MSG_LINK, "not SGMII, AN\n");
2738
2739 /* AN enabled */
2740 bnx2x_set_brcm_cl37_advertisment(phy, params);
2741
2742 /* program duplex & pause advertisement (for aneg) */
2743 bnx2x_set_ieee_aneg_advertisment(phy, params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002744 vars->ieee_fc);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002745
2746 /* enable autoneg */
2747 bnx2x_set_autoneg(phy, params, vars, enable_cl73);
2748
2749 /* enable and restart AN */
2750 bnx2x_restart_autoneg(phy, params, enable_cl73);
2751 }
2752
2753 } else { /* SGMII mode */
2754 DP(NETIF_MSG_LINK, "SGMII\n");
2755
2756 bnx2x_initialize_sgmii_process(phy, params, vars);
2757 }
2758}
2759
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002760static u8 bnx2x_init_serdes(struct bnx2x_phy *phy,
2761 struct link_params *params,
2762 struct link_vars *vars)
2763{
2764 u8 rc;
2765 vars->phy_flags |= PHY_SGMII_FLAG;
2766 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002767 bnx2x_set_aer_mmd_serdes(params->bp, phy);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002768 rc = bnx2x_reset_unicore(params, phy, 1);
2769 /* reset the SerDes and wait for reset bit return low */
2770 if (rc != 0)
2771 return rc;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002772 bnx2x_set_aer_mmd_serdes(params->bp, phy);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002773
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002774 return rc;
2775}
2776
2777static u8 bnx2x_init_xgxs(struct bnx2x_phy *phy,
2778 struct link_params *params,
2779 struct link_vars *vars)
2780{
2781 u8 rc;
2782 vars->phy_flags = PHY_XGXS_FLAG;
2783 if ((phy->req_line_speed &&
2784 ((phy->req_line_speed == SPEED_100) ||
2785 (phy->req_line_speed == SPEED_10))) ||
2786 (!phy->req_line_speed &&
2787 (phy->speed_cap_mask >=
2788 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL) &&
2789 (phy->speed_cap_mask <
2790 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
2791 ))
2792 vars->phy_flags |= PHY_SGMII_FLAG;
2793 else
2794 vars->phy_flags &= ~PHY_SGMII_FLAG;
2795
2796 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002797 bnx2x_set_aer_mmd_xgxs(params, phy);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002798 bnx2x_set_master_ln(params, phy);
2799
2800 rc = bnx2x_reset_unicore(params, phy, 0);
2801 /* reset the SerDes and wait for reset bit return low */
2802 if (rc != 0)
2803 return rc;
2804
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002805 bnx2x_set_aer_mmd_xgxs(params, phy);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002806
2807 /* setting the masterLn_def again after the reset */
2808 bnx2x_set_master_ln(params, phy);
2809 bnx2x_set_swap_lanes(params, phy);
2810
2811 return rc;
2812}
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002813
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002814static u16 bnx2x_wait_reset_complete(struct bnx2x *bp,
2815 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002816{
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002817 u16 cnt, ctrl;
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002818 /* Wait for soft reset to get cleared upto 1 sec */
2819 for (cnt = 0; cnt < 1000; cnt++) {
2820 bnx2x_cl45_read(bp, phy,
2821 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, &ctrl);
2822 if (!(ctrl & (1<<15)))
2823 break;
2824 msleep(1);
2825 }
2826 DP(NETIF_MSG_LINK, "control reg 0x%x (after %d ms)\n", ctrl, cnt);
2827 return cnt;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002828}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002829
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002830static void bnx2x_link_int_enable(struct link_params *params)
2831{
2832 u8 port = params->port;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002833 u32 mask;
2834 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002835
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002836 /* setting the status to report on link up
2837 for either XGXS or SerDes */
2838
2839 if (params->switch_cfg == SWITCH_CFG_10G) {
2840 mask = (NIG_MASK_XGXS0_LINK10G |
2841 NIG_MASK_XGXS0_LINK_STATUS);
2842 DP(NETIF_MSG_LINK, "enabled XGXS interrupt\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002843 if (!(SINGLE_MEDIA_DIRECT(params)) &&
2844 params->phy[INT_PHY].type !=
2845 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002846 mask |= NIG_MASK_MI_INT;
2847 DP(NETIF_MSG_LINK, "enabled external phy int\n");
2848 }
2849
2850 } else { /* SerDes */
2851 mask = NIG_MASK_SERDES0_LINK_STATUS;
2852 DP(NETIF_MSG_LINK, "enabled SerDes interrupt\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002853 if (!(SINGLE_MEDIA_DIRECT(params)) &&
2854 params->phy[INT_PHY].type !=
2855 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_NOT_CONN) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002856 mask |= NIG_MASK_MI_INT;
2857 DP(NETIF_MSG_LINK, "enabled external phy int\n");
2858 }
2859 }
2860 bnx2x_bits_en(bp,
2861 NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
2862 mask);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002863
2864 DP(NETIF_MSG_LINK, "port %x, is_xgxs %x, int_status 0x%x\n", port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002865 (params->switch_cfg == SWITCH_CFG_10G),
2866 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002867 DP(NETIF_MSG_LINK, " int_mask 0x%x, MI_INT %x, SERDES_LINK %x\n",
2868 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
2869 REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
2870 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS+port*0x3c));
2871 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
2872 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
2873 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
2874}
2875
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002876static void bnx2x_rearm_latch_signal(struct bnx2x *bp, u8 port,
2877 u8 exp_mi_int)
Eilon Greenstein2f904462009-08-12 08:22:16 +00002878{
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002879 u32 latch_status = 0;
2880
2881 /**
2882 * Disable the MI INT ( external phy int ) by writing 1 to the
2883 * status register. Link down indication is high-active-signal,
2884 * so in this case we need to write the status to clear the XOR
Eilon Greenstein2f904462009-08-12 08:22:16 +00002885 */
2886 /* Read Latched signals */
2887 latch_status = REG_RD(bp,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002888 NIG_REG_LATCH_STATUS_0 + port*8);
2889 DP(NETIF_MSG_LINK, "latch_status = 0x%x\n", latch_status);
Eilon Greenstein2f904462009-08-12 08:22:16 +00002890 /* Handle only those with latched-signal=up.*/
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002891 if (exp_mi_int)
2892 bnx2x_bits_en(bp,
2893 NIG_REG_STATUS_INTERRUPT_PORT0
2894 + port*4,
2895 NIG_STATUS_EMAC0_MI_INT);
2896 else
2897 bnx2x_bits_dis(bp,
2898 NIG_REG_STATUS_INTERRUPT_PORT0
2899 + port*4,
2900 NIG_STATUS_EMAC0_MI_INT);
2901
Eilon Greenstein2f904462009-08-12 08:22:16 +00002902 if (latch_status & 1) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002903
Eilon Greenstein2f904462009-08-12 08:22:16 +00002904 /* For all latched-signal=up : Re-Arm Latch signals */
2905 REG_WR(bp, NIG_REG_LATCH_STATUS_0 + port*8,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002906 (latch_status & 0xfffe) | (latch_status & 1));
Eilon Greenstein2f904462009-08-12 08:22:16 +00002907 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002908 /* For all latched-signal=up,Write original_signal to status */
Eilon Greenstein2f904462009-08-12 08:22:16 +00002909}
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002910
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002911static void bnx2x_link_int_ack(struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002912 struct link_vars *vars, u8 is_10g)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002913{
2914 struct bnx2x *bp = params->bp;
2915 u8 port = params->port;
2916
2917 /* first reset all status
2918 * we assume only one line will be change at a time */
2919 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002920 (NIG_STATUS_XGXS0_LINK10G |
2921 NIG_STATUS_XGXS0_LINK_STATUS |
2922 NIG_STATUS_SERDES0_LINK_STATUS));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002923 if (vars->phy_link_up) {
2924 if (is_10g) {
2925 /* Disable the 10G link interrupt
2926 * by writing 1 to the status register
2927 */
2928 DP(NETIF_MSG_LINK, "10G XGXS phy link up\n");
2929 bnx2x_bits_en(bp,
2930 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
2931 NIG_STATUS_XGXS0_LINK10G);
2932
2933 } else if (params->switch_cfg == SWITCH_CFG_10G) {
2934 /* Disable the link interrupt
2935 * by writing 1 to the relevant lane
2936 * in the status register
2937 */
2938 u32 ser_lane = ((params->lane_config &
2939 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
2940 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
2941
Eilon Greenstein2f904462009-08-12 08:22:16 +00002942 DP(NETIF_MSG_LINK, "%d speed XGXS phy link up\n",
2943 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002944 bnx2x_bits_en(bp,
2945 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
2946 ((1 << ser_lane) <<
2947 NIG_STATUS_XGXS0_LINK_STATUS_SIZE));
2948
2949 } else { /* SerDes */
2950 DP(NETIF_MSG_LINK, "SerDes phy link up\n");
2951 /* Disable the link interrupt
2952 * by writing 1 to the status register
2953 */
2954 bnx2x_bits_en(bp,
2955 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
2956 NIG_STATUS_SERDES0_LINK_STATUS);
2957 }
2958
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002959 }
2960}
2961
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002962static u8 bnx2x_format_ver(u32 num, u8 *str, u16 *len)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002963{
2964 u8 *str_ptr = str;
2965 u32 mask = 0xf0000000;
2966 u8 shift = 8*4;
2967 u8 digit;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002968 u8 remove_leading_zeros = 1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002969 if (*len < 10) {
Frederik Schwarzer025dfda2008-10-16 19:02:37 +02002970 /* Need more than 10chars for this format */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002971 *str_ptr = '\0';
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002972 (*len)--;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002973 return -EINVAL;
2974 }
2975 while (shift > 0) {
2976
2977 shift -= 4;
2978 digit = ((num & mask) >> shift);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002979 if (digit == 0 && remove_leading_zeros) {
2980 mask = mask >> 4;
2981 continue;
2982 } else if (digit < 0xa)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002983 *str_ptr = digit + '0';
2984 else
2985 *str_ptr = digit - 0xa + 'a';
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002986 remove_leading_zeros = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002987 str_ptr++;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002988 (*len)--;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002989 mask = mask >> 4;
2990 if (shift == 4*4) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002991 *str_ptr = '.';
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002992 str_ptr++;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002993 (*len)--;
2994 remove_leading_zeros = 1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002995 }
2996 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002997 return 0;
2998}
2999
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003000
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003001static u8 bnx2x_null_format_ver(u32 spirom_ver, u8 *str, u16 *len)
3002{
3003 str[0] = '\0';
3004 (*len)--;
3005 return 0;
3006}
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003007
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003008u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
3009 u8 *version, u16 len)
3010{
Julia Lawall0376d5b2009-07-19 05:26:35 +00003011 struct bnx2x *bp;
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003012 u32 spirom_ver = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003013 u8 status = 0;
3014 u8 *ver_p = version;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003015 u16 remain_len = len;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003016 if (version == NULL || params == NULL)
3017 return -EINVAL;
Julia Lawall0376d5b2009-07-19 05:26:35 +00003018 bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003019
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003020 /* Extract first external phy*/
3021 version[0] = '\0';
3022 spirom_ver = REG_RD(bp, params->phy[EXT_PHY1].ver_addr);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003023
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003024 if (params->phy[EXT_PHY1].format_fw_ver) {
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003025 status |= params->phy[EXT_PHY1].format_fw_ver(spirom_ver,
3026 ver_p,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003027 &remain_len);
3028 ver_p += (len - remain_len);
3029 }
3030 if ((params->num_phys == MAX_PHYS) &&
3031 (params->phy[EXT_PHY2].ver_addr != 0)) {
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003032 spirom_ver = REG_RD(bp, params->phy[EXT_PHY2].ver_addr);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003033 if (params->phy[EXT_PHY2].format_fw_ver) {
3034 *ver_p = '/';
3035 ver_p++;
3036 remain_len--;
3037 status |= params->phy[EXT_PHY2].format_fw_ver(
3038 spirom_ver,
3039 ver_p,
3040 &remain_len);
3041 ver_p = version + (len - remain_len);
3042 }
3043 }
3044 *ver_p = '\0';
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003045 return status;
3046}
3047
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003048static void bnx2x_set_xgxs_loopback(struct bnx2x_phy *phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003049 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003050{
3051 u8 port = params->port;
3052 struct bnx2x *bp = params->bp;
3053
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003054 if (phy->req_line_speed != SPEED_1000) {
Eilon Greenstein6378c022008-08-13 15:59:25 -07003055 u32 md_devad;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003056
3057 DP(NETIF_MSG_LINK, "XGXS 10G loopback enable\n");
3058
3059 /* change the uni_phy_addr in the nig */
3060 md_devad = REG_RD(bp, (NIG_REG_XGXS0_CTRL_MD_DEVAD +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003061 port*0x18));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003062
3063 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, 0x5);
3064
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003065 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003066 5,
3067 (MDIO_REG_BANK_AER_BLOCK +
3068 (MDIO_AER_BLOCK_AER_REG & 0xf)),
3069 0x2800);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003070
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003071 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003072 5,
3073 (MDIO_REG_BANK_CL73_IEEEB0 +
3074 (MDIO_CL73_IEEEB0_CL73_AN_CONTROL & 0xf)),
3075 0x6041);
Eilon Greenstein38582762009-01-14 06:44:16 +00003076 msleep(200);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003077 /* set aer mmd back */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00003078 bnx2x_set_aer_mmd_xgxs(params, phy);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003079
3080 /* and md_devad */
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003081 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, md_devad);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003082 } else {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003083 u16 mii_ctrl;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003084 DP(NETIF_MSG_LINK, "XGXS 1G loopback enable\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003085 bnx2x_cl45_read(bp, phy, 5,
3086 (MDIO_REG_BANK_COMBO_IEEE0 +
3087 (MDIO_COMBO_IEEE0_MII_CONTROL & 0xf)),
3088 &mii_ctrl);
3089 bnx2x_cl45_write(bp, phy, 5,
3090 (MDIO_REG_BANK_COMBO_IEEE0 +
3091 (MDIO_COMBO_IEEE0_MII_CONTROL & 0xf)),
3092 mii_ctrl |
3093 MDIO_COMBO_IEEO_MII_CONTROL_LOOPBACK);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003094 }
3095}
3096
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003097u8 bnx2x_set_led(struct link_params *params,
3098 struct link_vars *vars, u8 mode, u32 speed)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003099{
Yaniv Rosner7846e472009-11-05 19:18:07 +02003100 u8 port = params->port;
3101 u16 hw_led_mode = params->hw_led_mode;
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003102 u8 rc = 0, phy_idx;
Eilon Greenstein345b5d52008-08-13 15:58:12 -07003103 u32 tmp;
3104 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Yaniv Rosner7846e472009-11-05 19:18:07 +02003105 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003106 DP(NETIF_MSG_LINK, "bnx2x_set_led: port %x, mode %d\n", port, mode);
3107 DP(NETIF_MSG_LINK, "speed 0x%x, hw_led_mode 0x%x\n",
3108 speed, hw_led_mode);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003109 /* In case */
3110 for (phy_idx = EXT_PHY1; phy_idx < MAX_PHYS; phy_idx++) {
3111 if (params->phy[phy_idx].set_link_led) {
3112 params->phy[phy_idx].set_link_led(
3113 &params->phy[phy_idx], params, mode);
3114 }
3115 }
3116
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003117 switch (mode) {
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003118 case LED_MODE_FRONT_PANEL_OFF:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003119 case LED_MODE_OFF:
3120 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 0);
3121 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003122 SHARED_HW_CFG_LED_MAC1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07003123
3124 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07003125 EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp | EMAC_LED_OVERRIDE));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003126 break;
3127
3128 case LED_MODE_OPER:
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003129 /**
3130 * For all other phys, OPER mode is same as ON, so in case
3131 * link is down, do nothing
3132 **/
3133 if (!vars->link_up)
3134 break;
3135 case LED_MODE_ON:
Yaniv Rosner1f483532011-01-18 04:33:31 +00003136 if (params->phy[EXT_PHY1].type ==
3137 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727 &&
3138 CHIP_IS_E2(bp) && params->num_phys == 2) {
3139 /**
3140 * This is a work-around for E2+8727 Configurations
3141 */
3142 if (mode == LED_MODE_ON ||
3143 speed == SPEED_10000){
3144 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0);
3145 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1);
3146
3147 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
3148 EMAC_WR(bp, EMAC_REG_EMAC_LED,
3149 (tmp | EMAC_LED_OVERRIDE));
3150 return rc;
3151 }
3152 } else if (SINGLE_MEDIA_DIRECT(params)) {
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003153 /**
3154 * This is a work-around for HW issue found when link
3155 * is up in CL73
3156 */
Yaniv Rosner7846e472009-11-05 19:18:07 +02003157 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0);
3158 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1);
3159 } else {
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003160 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, hw_led_mode);
Yaniv Rosner7846e472009-11-05 19:18:07 +02003161 }
3162
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003163 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 + port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003164 /* Set blinking rate to ~15.9Hz */
3165 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003166 LED_BLINK_RATE_VAL);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003167 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003168 port*4, 1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07003169 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003170 EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp & (~EMAC_LED_OVERRIDE)));
Eilon Greenstein345b5d52008-08-13 15:58:12 -07003171
Yaniv Rosner7846e472009-11-05 19:18:07 +02003172 if (CHIP_IS_E1(bp) &&
Eilon Greenstein34f80b02008-06-23 20:33:01 -07003173 ((speed == SPEED_2500) ||
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003174 (speed == SPEED_1000) ||
3175 (speed == SPEED_100) ||
3176 (speed == SPEED_10))) {
3177 /* On Everest 1 Ax chip versions for speeds less than
3178 10G LED scheme is different */
3179 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003180 + port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003181 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003182 port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003183 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_TRAFFIC_P0 +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003184 port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003185 }
3186 break;
3187
3188 default:
3189 rc = -EINVAL;
3190 DP(NETIF_MSG_LINK, "bnx2x_set_led: Invalid led mode %d\n",
3191 mode);
3192 break;
3193 }
3194 return rc;
3195
3196}
3197
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003198/**
3199 * This function comes to reflect the actual link state read DIRECTLY from the
3200 * HW
3201 */
3202u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars,
3203 u8 is_serdes)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003204{
3205 struct bnx2x *bp = params->bp;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003206 u16 gp_status = 0, phy_index = 0;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003207 u8 ext_phy_link_up = 0, serdes_phy_type;
3208 struct link_vars temp_vars;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003209
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003210 CL22_RD_OVER_CL45(bp, &params->phy[INT_PHY],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003211 MDIO_REG_BANK_GP_STATUS,
3212 MDIO_GP_STATUS_TOP_AN_STATUS1,
3213 &gp_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003214 /* link is up only if both local phy and external phy are up */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003215 if (!(gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS))
3216 return -ESRCH;
3217
3218 switch (params->num_phys) {
3219 case 1:
3220 /* No external PHY */
3221 return 0;
3222 case 2:
3223 ext_phy_link_up = params->phy[EXT_PHY1].read_status(
3224 &params->phy[EXT_PHY1],
3225 params, &temp_vars);
3226 break;
3227 case 3: /* Dual Media */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003228 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
3229 phy_index++) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003230 serdes_phy_type = ((params->phy[phy_index].media_type ==
3231 ETH_PHY_SFP_FIBER) ||
3232 (params->phy[phy_index].media_type ==
3233 ETH_PHY_XFP_FIBER));
3234
3235 if (is_serdes != serdes_phy_type)
3236 continue;
3237 if (params->phy[phy_index].read_status) {
3238 ext_phy_link_up |=
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003239 params->phy[phy_index].read_status(
3240 &params->phy[phy_index],
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003241 params, &temp_vars);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003242 }
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003243 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003244 break;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003245 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003246 if (ext_phy_link_up)
3247 return 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003248 return -ESRCH;
3249}
3250
3251static u8 bnx2x_link_initialize(struct link_params *params,
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00003252 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003253{
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003254 u8 rc = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003255 u8 phy_index, non_ext_phy;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003256 struct bnx2x *bp = params->bp;
3257 /**
3258 * In case of external phy existence, the line speed would be the
3259 * line speed linked up by the external phy. In case it is direct
3260 * only, then the line_speed during initialization will be
3261 * equal to the req_line_speed
3262 */
3263 vars->line_speed = params->phy[INT_PHY].req_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003264
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003265 /**
3266 * Initialize the internal phy in case this is a direct board
3267 * (no external phys), or this board has external phy which requires
3268 * to first.
3269 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003270
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003271 if (params->phy[INT_PHY].config_init)
3272 params->phy[INT_PHY].config_init(
3273 &params->phy[INT_PHY],
3274 params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003275
3276 /* init ext phy and enable link state int */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003277 non_ext_phy = (SINGLE_MEDIA_DIRECT(params) ||
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003278 (params->loopback_mode == LOOPBACK_XGXS));
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003279
3280 if (non_ext_phy ||
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003281 (params->phy[EXT_PHY1].flags & FLAGS_INIT_XGXS_FIRST) ||
Eilon Greenstein8660d8c2009-03-02 08:01:02 +00003282 (params->loopback_mode == LOOPBACK_EXT_PHY)) {
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003283 struct bnx2x_phy *phy = &params->phy[INT_PHY];
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003284 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003285 bnx2x_set_parallel_detection(phy, params);
3286 bnx2x_init_internal_phy(phy, params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003287 }
3288
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003289 /* Init external phy*/
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003290 if (!non_ext_phy)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003291 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
3292 phy_index++) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003293 /**
3294 * No need to initialize second phy in case of first
3295 * phy only selection. In case of second phy, we do
3296 * need to initialize the first phy, since they are
3297 * connected.
3298 **/
3299 if (phy_index == EXT_PHY2 &&
3300 (bnx2x_phy_selection(params) ==
3301 PORT_HW_CFG_PHY_SELECTION_FIRST_PHY)) {
3302 DP(NETIF_MSG_LINK, "Not initializing"
3303 "second phy\n");
3304 continue;
3305 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003306 params->phy[phy_index].config_init(
3307 &params->phy[phy_index],
3308 params, vars);
3309 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003310
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00003311 /* Reset the interrupt indication after phy was initialized */
3312 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 +
3313 params->port*4,
3314 (NIG_STATUS_XGXS0_LINK10G |
3315 NIG_STATUS_XGXS0_LINK_STATUS |
3316 NIG_STATUS_SERDES0_LINK_STATUS |
3317 NIG_MASK_MI_INT));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003318 return rc;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003319}
3320
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003321static void bnx2x_int_link_reset(struct bnx2x_phy *phy,
3322 struct link_params *params)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003323{
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003324 /* reset the SerDes/XGXS */
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003325 REG_WR(params->bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
3326 (0x1ff << (params->port*16)));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003327}
3328
3329static void bnx2x_common_ext_link_reset(struct bnx2x_phy *phy,
3330 struct link_params *params)
3331{
3332 struct bnx2x *bp = params->bp;
3333 u8 gpio_port;
3334 /* HW reset */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00003335 if (CHIP_IS_E2(bp))
3336 gpio_port = BP_PATH(bp);
3337 else
3338 gpio_port = params->port;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003339 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003340 MISC_REGISTERS_GPIO_OUTPUT_LOW,
3341 gpio_port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003342 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003343 MISC_REGISTERS_GPIO_OUTPUT_LOW,
3344 gpio_port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003345 DP(NETIF_MSG_LINK, "reset external PHY\n");
3346}
3347
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003348static u8 bnx2x_update_link_down(struct link_params *params,
3349 struct link_vars *vars)
3350{
3351 struct bnx2x *bp = params->bp;
3352 u8 port = params->port;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00003353
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003354 DP(NETIF_MSG_LINK, "Port %x: Link is down\n", port);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003355 bnx2x_set_led(params, vars, LED_MODE_OFF, 0);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003356
3357 /* indicate no mac active */
3358 vars->mac_type = MAC_TYPE_NONE;
3359
3360 /* update shared memory */
3361 vars->link_status = 0;
3362 vars->line_speed = 0;
3363 bnx2x_update_mng(params, vars->link_status);
3364
3365 /* activate nig drain */
3366 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
3367
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00003368 /* disable emac */
3369 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
3370
3371 msleep(10);
3372
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003373 /* reset BigMac */
3374 bnx2x_bmac_rx_disable(bp, params->port);
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003375 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
3376 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003377 return 0;
3378}
3379
3380static u8 bnx2x_update_link_up(struct link_params *params,
3381 struct link_vars *vars,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003382 u8 link_10g)
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003383{
3384 struct bnx2x *bp = params->bp;
3385 u8 port = params->port;
3386 u8 rc = 0;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00003387
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003388 vars->link_status |= LINK_STATUS_LINK_UP;
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003389
Yaniv Rosner7aa07112010-09-07 11:41:01 +00003390 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
3391 vars->link_status |=
3392 LINK_STATUS_TX_FLOW_CONTROL_ENABLED;
3393
3394 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
3395 vars->link_status |=
3396 LINK_STATUS_RX_FLOW_CONTROL_ENABLED;
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003397
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003398 if (link_10g) {
3399 bnx2x_bmac_enable(params, vars, 0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003400 bnx2x_set_led(params, vars,
3401 LED_MODE_OPER, SPEED_10000);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003402 } else {
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003403 rc = bnx2x_emac_program(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003404
Yaniv Rosner0c786f02009-11-05 19:18:32 +02003405 bnx2x_emac_enable(params, vars, 0);
3406
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003407 /* AN complete? */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003408 if ((vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE)
3409 && (!(vars->phy_flags & PHY_SGMII_FLAG)) &&
3410 SINGLE_MEDIA_DIRECT(params))
3411 bnx2x_set_gmii_tx_driver(params);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003412 }
3413
3414 /* PBF - link up */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00003415 if (!(CHIP_IS_E2(bp)))
3416 rc |= bnx2x_pbf_update(params, vars->flow_ctrl,
3417 vars->line_speed);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003418
3419 /* disable drain */
3420 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 0);
3421
3422 /* update shared memory */
3423 bnx2x_update_mng(params, vars->link_status);
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00003424 msleep(20);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003425 return rc;
3426}
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003427/**
3428 * The bnx2x_link_update function should be called upon link
3429 * interrupt.
3430 * Link is considered up as follows:
3431 * - DIRECT_SINGLE_MEDIA - Only XGXS link (internal link) needs
3432 * to be up
3433 * - SINGLE_MEDIA - The link between the 577xx and the external
3434 * phy (XGXS) need to up as well as the external link of the
3435 * phy (PHY_EXT1)
3436 * - DUAL_MEDIA - The link between the 577xx and the first
3437 * external phy needs to be up, and at least one of the 2
3438 * external phy link must be up.
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003439 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003440u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars)
3441{
3442 struct bnx2x *bp = params->bp;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003443 struct link_vars phy_vars[MAX_PHYS];
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003444 u8 port = params->port;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003445 u8 link_10g, phy_index;
3446 u8 ext_phy_link_up = 0, cur_link_up, rc = 0;
Eilon Greenstein2f904462009-08-12 08:22:16 +00003447 u8 is_mi_int = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003448 u16 ext_phy_line_speed = 0, prev_line_speed = vars->line_speed;
3449 u8 active_external_phy = INT_PHY;
3450 vars->link_status = 0;
3451 for (phy_index = INT_PHY; phy_index < params->num_phys;
3452 phy_index++) {
3453 phy_vars[phy_index].flow_ctrl = 0;
3454 phy_vars[phy_index].link_status = 0;
3455 phy_vars[phy_index].line_speed = 0;
3456 phy_vars[phy_index].duplex = DUPLEX_FULL;
3457 phy_vars[phy_index].phy_link_up = 0;
3458 phy_vars[phy_index].link_up = 0;
3459 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003460
3461 DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n",
Eilon Greenstein2f904462009-08-12 08:22:16 +00003462 port, (vars->phy_flags & PHY_XGXS_FLAG),
3463 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003464
Eilon Greenstein2f904462009-08-12 08:22:16 +00003465 is_mi_int = (u8)(REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003466 port*0x18) > 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003467 DP(NETIF_MSG_LINK, "int_mask 0x%x MI_INT %x, SERDES_LINK %x\n",
Eilon Greenstein2f904462009-08-12 08:22:16 +00003468 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
3469 is_mi_int,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003470 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003471
3472 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
3473 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
3474 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
3475
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00003476 /* disable emac */
3477 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
3478
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003479 /**
3480 * Step 1:
3481 * Check external link change only for external phys, and apply
3482 * priority selection between them in case the link on both phys
3483 * is up. Note that the instead of the common vars, a temporary
3484 * vars argument is used since each phy may have different link/
3485 * speed/duplex result
3486 */
3487 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
3488 phy_index++) {
3489 struct bnx2x_phy *phy = &params->phy[phy_index];
3490 if (!phy->read_status)
3491 continue;
3492 /* Read link status and params of this ext phy */
3493 cur_link_up = phy->read_status(phy, params,
3494 &phy_vars[phy_index]);
3495 if (cur_link_up) {
3496 DP(NETIF_MSG_LINK, "phy in index %d link is up\n",
3497 phy_index);
3498 } else {
3499 DP(NETIF_MSG_LINK, "phy in index %d link is down\n",
3500 phy_index);
3501 continue;
3502 }
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003503
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003504 if (!ext_phy_link_up) {
3505 ext_phy_link_up = 1;
3506 active_external_phy = phy_index;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003507 } else {
3508 switch (bnx2x_phy_selection(params)) {
3509 case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT:
3510 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
3511 /**
3512 * In this option, the first PHY makes sure to pass the
3513 * traffic through itself only.
3514 * Its not clear how to reset the link on the second phy
3515 **/
3516 active_external_phy = EXT_PHY1;
3517 break;
3518 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
3519 /**
3520 * In this option, the first PHY makes sure to pass the
3521 * traffic through the second PHY.
3522 **/
3523 active_external_phy = EXT_PHY2;
3524 break;
3525 default:
3526 /**
3527 * Link indication on both PHYs with the following cases
3528 * is invalid:
3529 * - FIRST_PHY means that second phy wasn't initialized,
3530 * hence its link is expected to be down
3531 * - SECOND_PHY means that first phy should not be able
3532 * to link up by itself (using configuration)
3533 * - DEFAULT should be overriden during initialiazation
3534 **/
3535 DP(NETIF_MSG_LINK, "Invalid link indication"
3536 "mpc=0x%x. DISABLING LINK !!!\n",
3537 params->multi_phy_config);
3538 ext_phy_link_up = 0;
3539 break;
3540 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003541 }
3542 }
3543 prev_line_speed = vars->line_speed;
3544 /**
3545 * Step 2:
3546 * Read the status of the internal phy. In case of
3547 * DIRECT_SINGLE_MEDIA board, this link is the external link,
3548 * otherwise this is the link between the 577xx and the first
3549 * external phy
3550 */
3551 if (params->phy[INT_PHY].read_status)
3552 params->phy[INT_PHY].read_status(
3553 &params->phy[INT_PHY],
3554 params, vars);
3555 /**
3556 * The INT_PHY flow control reside in the vars. This include the
3557 * case where the speed or flow control are not set to AUTO.
3558 * Otherwise, the active external phy flow control result is set
3559 * to the vars. The ext_phy_line_speed is needed to check if the
3560 * speed is different between the internal phy and external phy.
3561 * This case may be result of intermediate link speed change.
3562 */
3563 if (active_external_phy > INT_PHY) {
3564 vars->flow_ctrl = phy_vars[active_external_phy].flow_ctrl;
3565 /**
3566 * Link speed is taken from the XGXS. AN and FC result from
3567 * the external phy.
3568 */
3569 vars->link_status |= phy_vars[active_external_phy].link_status;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003570
3571 /**
3572 * if active_external_phy is first PHY and link is up - disable
3573 * disable TX on second external PHY
3574 */
3575 if (active_external_phy == EXT_PHY1) {
3576 if (params->phy[EXT_PHY2].phy_specific_func) {
3577 DP(NETIF_MSG_LINK, "Disabling TX on"
3578 " EXT_PHY2\n");
3579 params->phy[EXT_PHY2].phy_specific_func(
3580 &params->phy[EXT_PHY2],
3581 params, DISABLE_TX);
3582 }
3583 }
3584
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003585 ext_phy_line_speed = phy_vars[active_external_phy].line_speed;
3586 vars->duplex = phy_vars[active_external_phy].duplex;
3587 if (params->phy[active_external_phy].supported &
3588 SUPPORTED_FIBRE)
3589 vars->link_status |= LINK_STATUS_SERDES_LINK;
3590 DP(NETIF_MSG_LINK, "Active external phy selected: %x\n",
3591 active_external_phy);
3592 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003593
3594 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
3595 phy_index++) {
3596 if (params->phy[phy_index].flags &
3597 FLAGS_REARM_LATCH_SIGNAL) {
3598 bnx2x_rearm_latch_signal(bp, port,
3599 phy_index ==
3600 active_external_phy);
3601 break;
3602 }
3603 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003604 DP(NETIF_MSG_LINK, "vars->flow_ctrl = 0x%x, vars->link_status = 0x%x,"
3605 " ext_phy_line_speed = %d\n", vars->flow_ctrl,
3606 vars->link_status, ext_phy_line_speed);
3607 /**
3608 * Upon link speed change set the NIG into drain mode. Comes to
3609 * deals with possible FIFO glitch due to clk change when speed
3610 * is decreased without link down indicator
3611 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003612
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003613 if (vars->phy_link_up) {
3614 if (!(SINGLE_MEDIA_DIRECT(params)) && ext_phy_link_up &&
3615 (ext_phy_line_speed != vars->line_speed)) {
3616 DP(NETIF_MSG_LINK, "Internal link speed %d is"
3617 " different than the external"
3618 " link speed %d\n", vars->line_speed,
3619 ext_phy_line_speed);
3620 vars->phy_link_up = 0;
3621 } else if (prev_line_speed != vars->line_speed) {
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003622 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4,
3623 0);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003624 msleep(1);
3625 }
3626 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003627
3628 /* anything 10 and over uses the bmac */
3629 link_10g = ((vars->line_speed == SPEED_10000) ||
3630 (vars->line_speed == SPEED_12000) ||
3631 (vars->line_speed == SPEED_12500) ||
3632 (vars->line_speed == SPEED_13000) ||
3633 (vars->line_speed == SPEED_15000) ||
3634 (vars->line_speed == SPEED_16000));
3635
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003636 bnx2x_link_int_ack(params, vars, link_10g);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003637
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003638 /**
3639 * In case external phy link is up, and internal link is down
3640 * (not initialized yet probably after link initialization, it
3641 * needs to be initialized.
3642 * Note that after link down-up as result of cable plug, the xgxs
3643 * link would probably become up again without the need
3644 * initialize it
3645 */
3646 if (!(SINGLE_MEDIA_DIRECT(params))) {
3647 DP(NETIF_MSG_LINK, "ext_phy_link_up = %d, int_link_up = %d,"
3648 " init_preceding = %d\n", ext_phy_link_up,
3649 vars->phy_link_up,
3650 params->phy[EXT_PHY1].flags &
3651 FLAGS_INIT_XGXS_FIRST);
3652 if (!(params->phy[EXT_PHY1].flags &
3653 FLAGS_INIT_XGXS_FIRST)
3654 && ext_phy_link_up && !vars->phy_link_up) {
3655 vars->line_speed = ext_phy_line_speed;
3656 if (vars->line_speed < SPEED_1000)
3657 vars->phy_flags |= PHY_SGMII_FLAG;
3658 else
3659 vars->phy_flags &= ~PHY_SGMII_FLAG;
3660 bnx2x_init_internal_phy(&params->phy[INT_PHY],
3661 params,
3662 vars);
3663 }
3664 }
3665 /**
3666 * Link is up only if both local phy and external phy (in case of
3667 * non-direct board) are up
3668 */
3669 vars->link_up = (vars->phy_link_up &&
3670 (ext_phy_link_up ||
3671 SINGLE_MEDIA_DIRECT(params)));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003672
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003673 if (vars->link_up)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003674 rc = bnx2x_update_link_up(params, vars, link_10g);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003675 else
3676 rc = bnx2x_update_link_down(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003677
3678 return rc;
3679}
3680
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003681
3682/*****************************************************************************/
3683/* External Phy section */
3684/*****************************************************************************/
3685void bnx2x_ext_phy_hw_reset(struct bnx2x *bp, u8 port)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003686{
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003687 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003688 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003689 msleep(1);
3690 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003691 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003692}
3693
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003694static void bnx2x_save_spirom_version(struct bnx2x *bp, u8 port,
3695 u32 spirom_ver, u32 ver_addr)
3696{
3697 DP(NETIF_MSG_LINK, "FW version 0x%x:0x%x for port %d\n",
3698 (u16)(spirom_ver>>16), (u16)spirom_ver, port);
3699
3700 if (ver_addr)
3701 REG_WR(bp, ver_addr, spirom_ver);
3702}
3703
3704static void bnx2x_save_bcm_spirom_ver(struct bnx2x *bp,
3705 struct bnx2x_phy *phy,
3706 u8 port)
3707{
3708 u16 fw_ver1, fw_ver2;
3709
3710 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003711 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003712 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003713 MDIO_PMA_REG_ROM_VER2, &fw_ver2);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003714 bnx2x_save_spirom_version(bp, port, (u32)(fw_ver1<<16 | fw_ver2),
3715 phy->ver_addr);
3716}
3717
3718static void bnx2x_ext_phy_set_pause(struct link_params *params,
3719 struct bnx2x_phy *phy,
3720 struct link_vars *vars)
3721{
3722 u16 val;
3723 struct bnx2x *bp = params->bp;
3724 /* read modify write pause advertizing */
3725 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV_PAUSE, &val);
3726
3727 val &= ~MDIO_AN_REG_ADV_PAUSE_BOTH;
3728
3729 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
3730 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
3731 if ((vars->ieee_fc &
3732 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
3733 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003734 val |= MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003735 }
3736 if ((vars->ieee_fc &
3737 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
3738 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
3739 val |= MDIO_AN_REG_ADV_PAUSE_PAUSE;
3740 }
3741 DP(NETIF_MSG_LINK, "Ext phy AN advertize 0x%x\n", val);
3742 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV_PAUSE, val);
3743}
3744
3745static u8 bnx2x_ext_phy_resolve_fc(struct bnx2x_phy *phy,
3746 struct link_params *params,
3747 struct link_vars *vars)
3748{
3749 struct bnx2x *bp = params->bp;
3750 u16 ld_pause; /* local */
3751 u16 lp_pause; /* link partner */
3752 u16 pause_result;
3753 u8 ret = 0;
3754 /* read twice */
3755
3756 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
3757
3758 if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO)
3759 vars->flow_ctrl = phy->req_flow_ctrl;
3760 else if (phy->req_line_speed != SPEED_AUTO_NEG)
3761 vars->flow_ctrl = params->req_fc_auto_adv;
3762 else if (vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE) {
3763 ret = 1;
3764 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003765 MDIO_AN_DEVAD,
3766 MDIO_AN_REG_ADV_PAUSE, &ld_pause);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003767 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003768 MDIO_AN_DEVAD,
3769 MDIO_AN_REG_LP_AUTO_NEG, &lp_pause);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003770 pause_result = (ld_pause &
3771 MDIO_AN_REG_ADV_PAUSE_MASK) >> 8;
3772 pause_result |= (lp_pause &
3773 MDIO_AN_REG_ADV_PAUSE_MASK) >> 10;
3774 DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x\n",
3775 pause_result);
3776 bnx2x_pause_resolve(vars, pause_result);
3777 }
3778 return ret;
3779}
3780
3781static void bnx2x_ext_phy_10G_an_resolve(struct bnx2x *bp,
3782 struct bnx2x_phy *phy,
3783 struct link_vars *vars)
3784{
3785 u16 val;
3786 bnx2x_cl45_read(bp, phy,
3787 MDIO_AN_DEVAD,
3788 MDIO_AN_REG_STATUS, &val);
3789 bnx2x_cl45_read(bp, phy,
3790 MDIO_AN_DEVAD,
3791 MDIO_AN_REG_STATUS, &val);
3792 if (val & (1<<5))
3793 vars->link_status |= LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
3794 if ((val & (1<<0)) == 0)
3795 vars->link_status |= LINK_STATUS_PARALLEL_DETECTION_USED;
3796}
3797
3798/******************************************************************/
3799/* common BCM8073/BCM8727 PHY SECTION */
3800/******************************************************************/
3801static void bnx2x_8073_resolve_fc(struct bnx2x_phy *phy,
3802 struct link_params *params,
3803 struct link_vars *vars)
3804{
3805 struct bnx2x *bp = params->bp;
3806 if (phy->req_line_speed == SPEED_10 ||
3807 phy->req_line_speed == SPEED_100) {
3808 vars->flow_ctrl = phy->req_flow_ctrl;
3809 return;
3810 }
3811
3812 if (bnx2x_ext_phy_resolve_fc(phy, params, vars) &&
3813 (vars->flow_ctrl == BNX2X_FLOW_CTRL_NONE)) {
3814 u16 pause_result;
3815 u16 ld_pause; /* local */
3816 u16 lp_pause; /* link partner */
3817 bnx2x_cl45_read(bp, phy,
3818 MDIO_AN_DEVAD,
3819 MDIO_AN_REG_CL37_FC_LD, &ld_pause);
3820
3821 bnx2x_cl45_read(bp, phy,
3822 MDIO_AN_DEVAD,
3823 MDIO_AN_REG_CL37_FC_LP, &lp_pause);
3824 pause_result = (ld_pause &
3825 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 5;
3826 pause_result |= (lp_pause &
3827 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 7;
3828
3829 bnx2x_pause_resolve(vars, pause_result);
3830 DP(NETIF_MSG_LINK, "Ext PHY CL37 pause result 0x%x\n",
3831 pause_result);
3832 }
3833}
Yaniv Rosner5c99274b2011-01-18 04:33:36 +00003834static u8 bnx2x_8073_8727_external_rom_boot(struct bnx2x *bp,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003835 struct bnx2x_phy *phy,
3836 u8 port)
3837{
Yaniv Rosner5c99274b2011-01-18 04:33:36 +00003838 u32 count = 0;
3839 u16 fw_ver1, fw_msgout;
3840 u8 rc = 0;
3841
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003842 /* Boot port from external ROM */
3843 /* EDC grst */
3844 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003845 MDIO_PMA_DEVAD,
3846 MDIO_PMA_REG_GEN_CTRL,
3847 0x0001);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003848
3849 /* ucode reboot and rst */
3850 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003851 MDIO_PMA_DEVAD,
3852 MDIO_PMA_REG_GEN_CTRL,
3853 0x008c);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003854
3855 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003856 MDIO_PMA_DEVAD,
3857 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003858
3859 /* Reset internal microprocessor */
3860 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003861 MDIO_PMA_DEVAD,
3862 MDIO_PMA_REG_GEN_CTRL,
3863 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003864
3865 /* Release srst bit */
3866 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003867 MDIO_PMA_DEVAD,
3868 MDIO_PMA_REG_GEN_CTRL,
3869 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003870
Yaniv Rosner5c99274b2011-01-18 04:33:36 +00003871 /* Delay 100ms per the PHY specifications */
3872 msleep(100);
3873
3874 /* 8073 sometimes taking longer to download */
3875 do {
3876 count++;
3877 if (count > 300) {
3878 DP(NETIF_MSG_LINK,
3879 "bnx2x_8073_8727_external_rom_boot port %x:"
3880 "Download failed. fw version = 0x%x\n",
3881 port, fw_ver1);
3882 rc = -EINVAL;
3883 break;
3884 }
3885
3886 bnx2x_cl45_read(bp, phy,
3887 MDIO_PMA_DEVAD,
3888 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
3889 bnx2x_cl45_read(bp, phy,
3890 MDIO_PMA_DEVAD,
3891 MDIO_PMA_REG_M8051_MSGOUT_REG, &fw_msgout);
3892
3893 msleep(1);
3894 } while (fw_ver1 == 0 || fw_ver1 == 0x4321 ||
3895 ((fw_msgout & 0xff) != 0x03 && (phy->type ==
3896 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073)));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003897
3898 /* Clear ser_boot_ctl bit */
3899 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003900 MDIO_PMA_DEVAD,
3901 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003902 bnx2x_save_bcm_spirom_ver(bp, phy, port);
Yaniv Rosner5c99274b2011-01-18 04:33:36 +00003903
3904 DP(NETIF_MSG_LINK,
3905 "bnx2x_8073_8727_external_rom_boot port %x:"
3906 "Download complete. fw version = 0x%x\n",
3907 port, fw_ver1);
3908
3909 return rc;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003910}
3911
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003912/******************************************************************/
3913/* BCM8073 PHY SECTION */
3914/******************************************************************/
3915static u8 bnx2x_8073_is_snr_needed(struct bnx2x *bp, struct bnx2x_phy *phy)
3916{
3917 /* This is only required for 8073A1, version 102 only */
3918 u16 val;
3919
3920 /* Read 8073 HW revision*/
3921 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003922 MDIO_PMA_DEVAD,
3923 MDIO_PMA_REG_8073_CHIP_REV, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003924
3925 if (val != 1) {
3926 /* No need to workaround in 8073 A1 */
3927 return 0;
3928 }
3929
3930 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003931 MDIO_PMA_DEVAD,
3932 MDIO_PMA_REG_ROM_VER2, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003933
3934 /* SNR should be applied only for version 0x102 */
3935 if (val != 0x102)
3936 return 0;
3937
3938 return 1;
3939}
3940
3941static u8 bnx2x_8073_xaui_wa(struct bnx2x *bp, struct bnx2x_phy *phy)
3942{
3943 u16 val, cnt, cnt1 ;
3944
3945 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003946 MDIO_PMA_DEVAD,
3947 MDIO_PMA_REG_8073_CHIP_REV, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003948
3949 if (val > 0) {
3950 /* No need to workaround in 8073 A1 */
3951 return 0;
3952 }
3953 /* XAUI workaround in 8073 A0: */
3954
3955 /* After loading the boot ROM and restarting Autoneg,
3956 poll Dev1, Reg $C820: */
3957
3958 for (cnt = 0; cnt < 1000; cnt++) {
3959 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003960 MDIO_PMA_DEVAD,
3961 MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
3962 &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003963 /* If bit [14] = 0 or bit [13] = 0, continue on with
3964 system initialization (XAUI work-around not required,
3965 as these bits indicate 2.5G or 1G link up). */
3966 if (!(val & (1<<14)) || !(val & (1<<13))) {
3967 DP(NETIF_MSG_LINK, "XAUI work-around not required\n");
3968 return 0;
3969 } else if (!(val & (1<<15))) {
3970 DP(NETIF_MSG_LINK, "clc bit 15 went off\n");
3971 /* If bit 15 is 0, then poll Dev1, Reg $C841 until
3972 it's MSB (bit 15) goes to 1 (indicating that the
3973 XAUI workaround has completed),
3974 then continue on with system initialization.*/
3975 for (cnt1 = 0; cnt1 < 1000; cnt1++) {
3976 bnx2x_cl45_read(bp, phy,
3977 MDIO_PMA_DEVAD,
3978 MDIO_PMA_REG_8073_XAUI_WA, &val);
3979 if (val & (1<<15)) {
3980 DP(NETIF_MSG_LINK,
3981 "XAUI workaround has completed\n");
3982 return 0;
3983 }
3984 msleep(3);
3985 }
3986 break;
3987 }
3988 msleep(3);
3989 }
3990 DP(NETIF_MSG_LINK, "Warning: XAUI work-around timeout !!!\n");
3991 return -EINVAL;
3992}
3993
3994static void bnx2x_807x_force_10G(struct bnx2x *bp, struct bnx2x_phy *phy)
3995{
3996 /* Force KR or KX */
3997 bnx2x_cl45_write(bp, phy,
3998 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x2040);
3999 bnx2x_cl45_write(bp, phy,
4000 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0x000b);
4001 bnx2x_cl45_write(bp, phy,
4002 MDIO_PMA_DEVAD, MDIO_PMA_REG_BCM_CTRL, 0x0000);
4003 bnx2x_cl45_write(bp, phy,
4004 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x0000);
4005}
4006
4007static void bnx2x_8073_set_pause_cl37(struct link_params *params,
4008 struct bnx2x_phy *phy,
4009 struct link_vars *vars)
4010{
4011 u16 cl37_val;
4012 struct bnx2x *bp = params->bp;
4013 bnx2x_cl45_read(bp, phy,
4014 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, &cl37_val);
4015
4016 cl37_val &= ~MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
4017 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
4018 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
4019 if ((vars->ieee_fc &
4020 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) ==
4021 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) {
4022 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC;
4023 }
4024 if ((vars->ieee_fc &
4025 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
4026 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
4027 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
4028 }
4029 if ((vars->ieee_fc &
4030 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
4031 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
4032 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
4033 }
4034 DP(NETIF_MSG_LINK,
4035 "Ext phy AN advertize cl37 0x%x\n", cl37_val);
4036
4037 bnx2x_cl45_write(bp, phy,
4038 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, cl37_val);
4039 msleep(500);
4040}
4041
4042static u8 bnx2x_8073_config_init(struct bnx2x_phy *phy,
4043 struct link_params *params,
4044 struct link_vars *vars)
4045{
4046 struct bnx2x *bp = params->bp;
4047 u16 val = 0, tmp1;
4048 u8 gpio_port;
4049 DP(NETIF_MSG_LINK, "Init 8073\n");
4050
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00004051 if (CHIP_IS_E2(bp))
4052 gpio_port = BP_PATH(bp);
4053 else
4054 gpio_port = params->port;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004055 /* Restore normal power mode*/
4056 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004057 MISC_REGISTERS_GPIO_OUTPUT_HIGH, gpio_port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004058
4059 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004060 MISC_REGISTERS_GPIO_OUTPUT_HIGH, gpio_port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004061
4062 /* enable LASI */
4063 bnx2x_cl45_write(bp, phy,
4064 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL, (1<<2));
4065 bnx2x_cl45_write(bp, phy,
4066 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x0004);
4067
4068 bnx2x_8073_set_pause_cl37(params, phy, vars);
4069
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004070 bnx2x_cl45_read(bp, phy,
4071 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &tmp1);
4072
4073 bnx2x_cl45_read(bp, phy,
4074 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &tmp1);
4075
4076 DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1): 0x%x\n", tmp1);
4077
Yaniv Rosner74d7a112011-01-18 04:33:18 +00004078 /**
4079 * If this is forced speed, set to KR or KX (all other are not
4080 * supported)
4081 */
4082 /* Swap polarity if required - Must be done only in non-1G mode */
4083 if (params->lane_config & PORT_HW_CFG_SWAP_PHY_POLARITY_ENABLED) {
4084 /* Configure the 8073 to swap _P and _N of the KR lines */
4085 DP(NETIF_MSG_LINK, "Swapping polarity for the 8073\n");
4086 /* 10G Rx/Tx and 1G Tx signal polarity swap */
4087 bnx2x_cl45_read(bp, phy,
4088 MDIO_PMA_DEVAD,
4089 MDIO_PMA_REG_8073_OPT_DIGITAL_CTRL, &val);
4090 bnx2x_cl45_write(bp, phy,
4091 MDIO_PMA_DEVAD,
4092 MDIO_PMA_REG_8073_OPT_DIGITAL_CTRL,
4093 (val | (3<<9)));
4094 }
4095
4096
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004097 /* Enable CL37 BAM */
Yaniv Rosner121839b2010-11-01 05:32:38 +00004098 if (REG_RD(bp, params->shmem_base +
4099 offsetof(struct shmem_region, dev_info.
4100 port_hw_config[params->port].default_cfg)) &
4101 PORT_HW_CFG_ENABLE_BAM_ON_KR_ENABLED) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004102
Yaniv Rosner121839b2010-11-01 05:32:38 +00004103 bnx2x_cl45_read(bp, phy,
4104 MDIO_AN_DEVAD,
4105 MDIO_AN_REG_8073_BAM, &val);
4106 bnx2x_cl45_write(bp, phy,
4107 MDIO_AN_DEVAD,
4108 MDIO_AN_REG_8073_BAM, val | 1);
4109 DP(NETIF_MSG_LINK, "Enable CL37 BAM on KR\n");
4110 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004111 if (params->loopback_mode == LOOPBACK_EXT) {
4112 bnx2x_807x_force_10G(bp, phy);
4113 DP(NETIF_MSG_LINK, "Forced speed 10G on 807X\n");
4114 return 0;
4115 } else {
4116 bnx2x_cl45_write(bp, phy,
4117 MDIO_PMA_DEVAD, MDIO_PMA_REG_BCM_CTRL, 0x0002);
4118 }
4119 if (phy->req_line_speed != SPEED_AUTO_NEG) {
4120 if (phy->req_line_speed == SPEED_10000) {
4121 val = (1<<7);
4122 } else if (phy->req_line_speed == SPEED_2500) {
4123 val = (1<<5);
4124 /* Note that 2.5G works only
4125 when used with 1G advertisment */
4126 } else
4127 val = (1<<5);
4128 } else {
4129 val = 0;
4130 if (phy->speed_cap_mask &
4131 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
4132 val |= (1<<7);
4133
4134 /* Note that 2.5G works only when
4135 used with 1G advertisment */
4136 if (phy->speed_cap_mask &
4137 (PORT_HW_CFG_SPEED_CAPABILITY_D0_1G |
4138 PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G))
4139 val |= (1<<5);
4140 DP(NETIF_MSG_LINK, "807x autoneg val = 0x%x\n", val);
4141 }
4142
4143 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV, val);
4144 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_8073_2_5G, &tmp1);
4145
4146 if (((phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G) &&
4147 (phy->req_line_speed == SPEED_AUTO_NEG)) ||
4148 (phy->req_line_speed == SPEED_2500)) {
4149 u16 phy_ver;
4150 /* Allow 2.5G for A1 and above */
4151 bnx2x_cl45_read(bp, phy,
4152 MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_CHIP_REV,
4153 &phy_ver);
4154 DP(NETIF_MSG_LINK, "Add 2.5G\n");
4155 if (phy_ver > 0)
4156 tmp1 |= 1;
4157 else
4158 tmp1 &= 0xfffe;
4159 } else {
4160 DP(NETIF_MSG_LINK, "Disable 2.5G\n");
4161 tmp1 &= 0xfffe;
4162 }
4163
4164 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_8073_2_5G, tmp1);
4165 /* Add support for CL37 (passive mode) II */
4166
4167 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, &tmp1);
4168 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD,
4169 (tmp1 | ((phy->req_duplex == DUPLEX_FULL) ?
4170 0x20 : 0x40)));
4171
4172 /* Add support for CL37 (passive mode) III */
4173 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
4174
4175 /* The SNR will improve about 2db by changing
4176 BW and FEE main tap. Rest commands are executed
4177 after link is up*/
4178 if (bnx2x_8073_is_snr_needed(bp, phy))
4179 bnx2x_cl45_write(bp, phy,
4180 MDIO_PMA_DEVAD, MDIO_PMA_REG_EDC_FFE_MAIN,
4181 0xFB0C);
4182
4183 /* Enable FEC (Forware Error Correction) Request in the AN */
4184 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV2, &tmp1);
4185 tmp1 |= (1<<15);
4186 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV2, tmp1);
4187
4188 bnx2x_ext_phy_set_pause(params, phy, vars);
4189
4190 /* Restart autoneg */
4191 msleep(500);
4192 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
4193 DP(NETIF_MSG_LINK, "807x Autoneg Restart: Advertise 1G=%x, 10G=%x\n",
4194 ((val & (1<<5)) > 0), ((val & (1<<7)) > 0));
4195 return 0;
4196}
4197
4198static u8 bnx2x_8073_read_status(struct bnx2x_phy *phy,
4199 struct link_params *params,
4200 struct link_vars *vars)
4201{
4202 struct bnx2x *bp = params->bp;
4203 u8 link_up = 0;
4204 u16 val1, val2;
4205 u16 link_status = 0;
4206 u16 an1000_status = 0;
4207
4208 bnx2x_cl45_read(bp, phy,
4209 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
4210
4211 DP(NETIF_MSG_LINK, "8703 LASI status 0x%x\n", val1);
4212
4213 /* clear the interrupt LASI status register */
4214 bnx2x_cl45_read(bp, phy,
4215 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val2);
4216 bnx2x_cl45_read(bp, phy,
4217 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val1);
4218 DP(NETIF_MSG_LINK, "807x PCS status 0x%x->0x%x\n", val2, val1);
4219 /* Clear MSG-OUT */
4220 bnx2x_cl45_read(bp, phy,
4221 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &val1);
4222
4223 /* Check the LASI */
4224 bnx2x_cl45_read(bp, phy,
4225 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &val2);
4226
4227 DP(NETIF_MSG_LINK, "KR 0x9003 0x%x\n", val2);
4228
4229 /* Check the link status */
4230 bnx2x_cl45_read(bp, phy,
4231 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val2);
4232 DP(NETIF_MSG_LINK, "KR PCS status 0x%x\n", val2);
4233
4234 bnx2x_cl45_read(bp, phy,
4235 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
4236 bnx2x_cl45_read(bp, phy,
4237 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
4238 link_up = ((val1 & 4) == 4);
4239 DP(NETIF_MSG_LINK, "PMA_REG_STATUS=0x%x\n", val1);
4240
4241 if (link_up &&
4242 ((phy->req_line_speed != SPEED_10000))) {
4243 if (bnx2x_8073_xaui_wa(bp, phy) != 0)
4244 return 0;
4245 }
4246 bnx2x_cl45_read(bp, phy,
4247 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &an1000_status);
4248 bnx2x_cl45_read(bp, phy,
4249 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &an1000_status);
4250
4251 /* Check the link status on 1.1.2 */
4252 bnx2x_cl45_read(bp, phy,
4253 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
4254 bnx2x_cl45_read(bp, phy,
4255 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
4256 DP(NETIF_MSG_LINK, "KR PMA status 0x%x->0x%x,"
4257 "an_link_status=0x%x\n", val2, val1, an1000_status);
4258
4259 link_up = (((val1 & 4) == 4) || (an1000_status & (1<<1)));
4260 if (link_up && bnx2x_8073_is_snr_needed(bp, phy)) {
4261 /* The SNR will improve about 2dbby
4262 changing the BW and FEE main tap.*/
4263 /* The 1st write to change FFE main
4264 tap is set before restart AN */
4265 /* Change PLL Bandwidth in EDC
4266 register */
4267 bnx2x_cl45_write(bp, phy,
4268 MDIO_PMA_DEVAD, MDIO_PMA_REG_PLL_BANDWIDTH,
4269 0x26BC);
4270
4271 /* Change CDR Bandwidth in EDC register */
4272 bnx2x_cl45_write(bp, phy,
4273 MDIO_PMA_DEVAD, MDIO_PMA_REG_CDR_BANDWIDTH,
4274 0x0333);
4275 }
4276 bnx2x_cl45_read(bp, phy,
4277 MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
4278 &link_status);
4279
4280 /* Bits 0..2 --> speed detected, bits 13..15--> link is down */
4281 if ((link_status & (1<<2)) && (!(link_status & (1<<15)))) {
4282 link_up = 1;
4283 vars->line_speed = SPEED_10000;
4284 DP(NETIF_MSG_LINK, "port %x: External link up in 10G\n",
4285 params->port);
4286 } else if ((link_status & (1<<1)) && (!(link_status & (1<<14)))) {
4287 link_up = 1;
4288 vars->line_speed = SPEED_2500;
4289 DP(NETIF_MSG_LINK, "port %x: External link up in 2.5G\n",
4290 params->port);
4291 } else if ((link_status & (1<<0)) && (!(link_status & (1<<13)))) {
4292 link_up = 1;
4293 vars->line_speed = SPEED_1000;
4294 DP(NETIF_MSG_LINK, "port %x: External link up in 1G\n",
4295 params->port);
4296 } else {
4297 link_up = 0;
4298 DP(NETIF_MSG_LINK, "port %x: External link is down\n",
4299 params->port);
4300 }
4301
4302 if (link_up) {
Yaniv Rosner74d7a112011-01-18 04:33:18 +00004303 /* Swap polarity if required */
4304 if (params->lane_config &
4305 PORT_HW_CFG_SWAP_PHY_POLARITY_ENABLED) {
4306 /* Configure the 8073 to swap P and N of the KR lines */
4307 bnx2x_cl45_read(bp, phy,
4308 MDIO_XS_DEVAD,
4309 MDIO_XS_REG_8073_RX_CTRL_PCIE, &val1);
4310 /**
4311 * Set bit 3 to invert Rx in 1G mode and clear this bit
4312 * when it`s in 10G mode.
4313 */
4314 if (vars->line_speed == SPEED_1000) {
4315 DP(NETIF_MSG_LINK, "Swapping 1G polarity for"
4316 "the 8073\n");
4317 val1 |= (1<<3);
4318 } else
4319 val1 &= ~(1<<3);
4320
4321 bnx2x_cl45_write(bp, phy,
4322 MDIO_XS_DEVAD,
4323 MDIO_XS_REG_8073_RX_CTRL_PCIE,
4324 val1);
4325 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004326 bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
4327 bnx2x_8073_resolve_fc(phy, params, vars);
Yaniv Rosner791f18c2011-01-18 04:33:42 +00004328 vars->duplex = DUPLEX_FULL;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004329 }
4330 return link_up;
4331}
4332
4333static void bnx2x_8073_link_reset(struct bnx2x_phy *phy,
4334 struct link_params *params)
4335{
4336 struct bnx2x *bp = params->bp;
4337 u8 gpio_port;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00004338 if (CHIP_IS_E2(bp))
4339 gpio_port = BP_PATH(bp);
4340 else
4341 gpio_port = params->port;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004342 DP(NETIF_MSG_LINK, "Setting 8073 port %d into low power mode\n",
4343 gpio_port);
4344 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004345 MISC_REGISTERS_GPIO_OUTPUT_LOW,
4346 gpio_port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004347}
4348
4349/******************************************************************/
4350/* BCM8705 PHY SECTION */
4351/******************************************************************/
4352static u8 bnx2x_8705_config_init(struct bnx2x_phy *phy,
4353 struct link_params *params,
4354 struct link_vars *vars)
4355{
4356 struct bnx2x *bp = params->bp;
4357 DP(NETIF_MSG_LINK, "init 8705\n");
4358 /* Restore normal power mode*/
4359 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004360 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004361 /* HW reset */
4362 bnx2x_ext_phy_hw_reset(bp, params->port);
4363 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0xa040);
4364 bnx2x_wait_reset_complete(bp, phy);
4365
4366 bnx2x_cl45_write(bp, phy,
4367 MDIO_PMA_DEVAD, MDIO_PMA_REG_MISC_CTRL, 0x8288);
4368 bnx2x_cl45_write(bp, phy,
4369 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, 0x7fbf);
4370 bnx2x_cl45_write(bp, phy,
4371 MDIO_PMA_DEVAD, MDIO_PMA_REG_CMU_PLL_BYPASS, 0x0100);
4372 bnx2x_cl45_write(bp, phy,
4373 MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_CNTL, 0x1);
4374 /* BCM8705 doesn't have microcode, hence the 0 */
4375 bnx2x_save_spirom_version(bp, params->port, params->shmem_base, 0);
4376 return 0;
4377}
4378
4379static u8 bnx2x_8705_read_status(struct bnx2x_phy *phy,
4380 struct link_params *params,
4381 struct link_vars *vars)
4382{
4383 u8 link_up = 0;
4384 u16 val1, rx_sd;
4385 struct bnx2x *bp = params->bp;
4386 DP(NETIF_MSG_LINK, "read status 8705\n");
4387 bnx2x_cl45_read(bp, phy,
4388 MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_STATUS, &val1);
4389 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
4390
4391 bnx2x_cl45_read(bp, phy,
4392 MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_STATUS, &val1);
4393 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
4394
4395 bnx2x_cl45_read(bp, phy,
4396 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD, &rx_sd);
4397
4398 bnx2x_cl45_read(bp, phy,
4399 MDIO_PMA_DEVAD, 0xc809, &val1);
4400 bnx2x_cl45_read(bp, phy,
4401 MDIO_PMA_DEVAD, 0xc809, &val1);
4402
4403 DP(NETIF_MSG_LINK, "8705 1.c809 val=0x%x\n", val1);
4404 link_up = ((rx_sd & 0x1) && (val1 & (1<<9)) && ((val1 & (1<<8)) == 0));
4405 if (link_up) {
4406 vars->line_speed = SPEED_10000;
4407 bnx2x_ext_phy_resolve_fc(phy, params, vars);
4408 }
4409 return link_up;
4410}
4411
4412/******************************************************************/
4413/* SFP+ module Section */
4414/******************************************************************/
4415static void bnx2x_sfp_set_transmitter(struct bnx2x *bp,
4416 struct bnx2x_phy *phy,
4417 u8 port,
4418 u8 tx_en)
4419{
4420 u16 val;
4421
4422 DP(NETIF_MSG_LINK, "Setting transmitter tx_en=%x for port %x\n",
4423 tx_en, port);
4424 /* Disable/Enable transmitter ( TX laser of the SFP+ module.)*/
4425 bnx2x_cl45_read(bp, phy,
4426 MDIO_PMA_DEVAD,
4427 MDIO_PMA_REG_PHY_IDENTIFIER,
4428 &val);
4429
4430 if (tx_en)
4431 val &= ~(1<<15);
4432 else
4433 val |= (1<<15);
4434
4435 bnx2x_cl45_write(bp, phy,
4436 MDIO_PMA_DEVAD,
4437 MDIO_PMA_REG_PHY_IDENTIFIER,
4438 val);
4439}
4440
4441static u8 bnx2x_8726_read_sfp_module_eeprom(struct bnx2x_phy *phy,
4442 struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004443 u16 addr, u8 byte_cnt, u8 *o_buf)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004444{
4445 struct bnx2x *bp = params->bp;
4446 u16 val = 0;
4447 u16 i;
4448 if (byte_cnt > 16) {
4449 DP(NETIF_MSG_LINK, "Reading from eeprom is"
4450 " is limited to 0xf\n");
4451 return -EINVAL;
4452 }
4453 /* Set the read command byte count */
4454 bnx2x_cl45_write(bp, phy,
4455 MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004456 (byte_cnt | 0xa000));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004457
4458 /* Set the read command address */
4459 bnx2x_cl45_write(bp, phy,
4460 MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004461 addr);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004462
4463 /* Activate read command */
4464 bnx2x_cl45_write(bp, phy,
4465 MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004466 0x2c0f);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004467
4468 /* Wait up to 500us for command complete status */
4469 for (i = 0; i < 100; i++) {
4470 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004471 MDIO_PMA_DEVAD,
4472 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004473 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
4474 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
4475 break;
4476 udelay(5);
4477 }
4478
4479 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
4480 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
4481 DP(NETIF_MSG_LINK,
4482 "Got bad status 0x%x when reading from SFP+ EEPROM\n",
4483 (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
4484 return -EINVAL;
4485 }
4486
4487 /* Read the buffer */
4488 for (i = 0; i < byte_cnt; i++) {
4489 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004490 MDIO_PMA_DEVAD,
4491 MDIO_PMA_REG_8726_TWO_WIRE_DATA_BUF + i, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004492 o_buf[i] = (u8)(val & MDIO_PMA_REG_8726_TWO_WIRE_DATA_MASK);
4493 }
4494
4495 for (i = 0; i < 100; i++) {
4496 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004497 MDIO_PMA_DEVAD,
4498 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004499 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
4500 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
Joe Perches6f38ad92010-11-14 17:04:31 +00004501 return 0;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004502 msleep(1);
4503 }
4504 return -EINVAL;
4505}
4506
4507static u8 bnx2x_8727_read_sfp_module_eeprom(struct bnx2x_phy *phy,
4508 struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004509 u16 addr, u8 byte_cnt, u8 *o_buf)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004510{
4511 struct bnx2x *bp = params->bp;
4512 u16 val, i;
4513
4514 if (byte_cnt > 16) {
4515 DP(NETIF_MSG_LINK, "Reading from eeprom is"
4516 " is limited to 0xf\n");
4517 return -EINVAL;
4518 }
4519
4520 /* Need to read from 1.8000 to clear it */
4521 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004522 MDIO_PMA_DEVAD,
4523 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
4524 &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004525
4526 /* Set the read command byte count */
4527 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004528 MDIO_PMA_DEVAD,
4529 MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
4530 ((byte_cnt < 2) ? 2 : byte_cnt));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004531
4532 /* Set the read command address */
4533 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004534 MDIO_PMA_DEVAD,
4535 MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
4536 addr);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004537 /* Set the destination address */
4538 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004539 MDIO_PMA_DEVAD,
4540 0x8004,
4541 MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004542
4543 /* Activate read command */
4544 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004545 MDIO_PMA_DEVAD,
4546 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
4547 0x8002);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004548 /* Wait appropriate time for two-wire command to finish before
4549 polling the status register */
4550 msleep(1);
4551
4552 /* Wait up to 500us for command complete status */
4553 for (i = 0; i < 100; i++) {
4554 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004555 MDIO_PMA_DEVAD,
4556 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004557 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
4558 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
4559 break;
4560 udelay(5);
4561 }
4562
4563 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
4564 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
4565 DP(NETIF_MSG_LINK,
4566 "Got bad status 0x%x when reading from SFP+ EEPROM\n",
4567 (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
4568 return -EINVAL;
4569 }
4570
4571 /* Read the buffer */
4572 for (i = 0; i < byte_cnt; i++) {
4573 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004574 MDIO_PMA_DEVAD,
4575 MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF + i, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004576 o_buf[i] = (u8)(val & MDIO_PMA_REG_8727_TWO_WIRE_DATA_MASK);
4577 }
4578
4579 for (i = 0; i < 100; i++) {
4580 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004581 MDIO_PMA_DEVAD,
4582 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004583 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
4584 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
Joe Perches6f38ad92010-11-14 17:04:31 +00004585 return 0;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004586 msleep(1);
4587 }
4588
4589 return -EINVAL;
4590}
4591
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004592u8 bnx2x_read_sfp_module_eeprom(struct bnx2x_phy *phy,
4593 struct link_params *params, u16 addr,
4594 u8 byte_cnt, u8 *o_buf)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004595{
4596 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
4597 return bnx2x_8726_read_sfp_module_eeprom(phy, params, addr,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004598 byte_cnt, o_buf);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004599 else if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
4600 return bnx2x_8727_read_sfp_module_eeprom(phy, params, addr,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004601 byte_cnt, o_buf);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004602 return -EINVAL;
4603}
4604
4605static u8 bnx2x_get_edc_mode(struct bnx2x_phy *phy,
4606 struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004607 u16 *edc_mode)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004608{
4609 struct bnx2x *bp = params->bp;
4610 u8 val, check_limiting_mode = 0;
4611 *edc_mode = EDC_MODE_LIMITING;
4612
4613 /* First check for copper cable */
4614 if (bnx2x_read_sfp_module_eeprom(phy,
4615 params,
4616 SFP_EEPROM_CON_TYPE_ADDR,
4617 1,
4618 &val) != 0) {
4619 DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM\n");
4620 return -EINVAL;
4621 }
4622
4623 switch (val) {
4624 case SFP_EEPROM_CON_TYPE_VAL_COPPER:
4625 {
4626 u8 copper_module_type;
4627
4628 /* Check if its active cable( includes SFP+ module)
4629 of passive cable*/
4630 if (bnx2x_read_sfp_module_eeprom(phy,
4631 params,
4632 SFP_EEPROM_FC_TX_TECH_ADDR,
4633 1,
4634 &copper_module_type) !=
4635 0) {
4636 DP(NETIF_MSG_LINK,
4637 "Failed to read copper-cable-type"
4638 " from SFP+ EEPROM\n");
4639 return -EINVAL;
4640 }
4641
4642 if (copper_module_type &
4643 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE) {
4644 DP(NETIF_MSG_LINK, "Active Copper cable detected\n");
4645 check_limiting_mode = 1;
4646 } else if (copper_module_type &
4647 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE) {
4648 DP(NETIF_MSG_LINK, "Passive Copper"
4649 " cable detected\n");
4650 *edc_mode =
4651 EDC_MODE_PASSIVE_DAC;
4652 } else {
4653 DP(NETIF_MSG_LINK, "Unknown copper-cable-"
4654 "type 0x%x !!!\n", copper_module_type);
4655 return -EINVAL;
4656 }
4657 break;
4658 }
4659 case SFP_EEPROM_CON_TYPE_VAL_LC:
4660 DP(NETIF_MSG_LINK, "Optic module detected\n");
4661 check_limiting_mode = 1;
4662 break;
4663 default:
4664 DP(NETIF_MSG_LINK, "Unable to determine module type 0x%x !!!\n",
4665 val);
4666 return -EINVAL;
4667 }
4668
4669 if (check_limiting_mode) {
4670 u8 options[SFP_EEPROM_OPTIONS_SIZE];
4671 if (bnx2x_read_sfp_module_eeprom(phy,
4672 params,
4673 SFP_EEPROM_OPTIONS_ADDR,
4674 SFP_EEPROM_OPTIONS_SIZE,
4675 options) != 0) {
4676 DP(NETIF_MSG_LINK, "Failed to read Option"
4677 " field from module EEPROM\n");
4678 return -EINVAL;
4679 }
4680 if ((options[0] & SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK))
4681 *edc_mode = EDC_MODE_LINEAR;
4682 else
4683 *edc_mode = EDC_MODE_LIMITING;
4684 }
4685 DP(NETIF_MSG_LINK, "EDC mode is set to 0x%x\n", *edc_mode);
4686 return 0;
4687}
4688/* This function read the relevant field from the module ( SFP+ ),
4689 and verify it is compliant with this board */
4690static u8 bnx2x_verify_sfp_module(struct bnx2x_phy *phy,
4691 struct link_params *params)
4692{
4693 struct bnx2x *bp = params->bp;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004694 u32 val, cmd;
4695 u32 fw_resp, fw_cmd_param;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004696 char vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE+1];
4697 char vendor_pn[SFP_EEPROM_PART_NO_SIZE+1];
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004698 phy->flags &= ~FLAGS_SFP_NOT_APPROVED;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004699 val = REG_RD(bp, params->shmem_base +
4700 offsetof(struct shmem_region, dev_info.
4701 port_feature_config[params->port].config));
4702 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
4703 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_NO_ENFORCEMENT) {
4704 DP(NETIF_MSG_LINK, "NOT enforcing module verification\n");
4705 return 0;
4706 }
4707
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004708 if (params->feature_config_flags &
4709 FEATURE_CONFIG_BC_SUPPORTS_DUAL_PHY_OPT_MDL_VRFY) {
4710 /* Use specific phy request */
4711 cmd = DRV_MSG_CODE_VRFY_SPECIFIC_PHY_OPT_MDL;
4712 } else if (params->feature_config_flags &
4713 FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY) {
4714 /* Use first phy request only in case of non-dual media*/
4715 if (DUAL_MEDIA(params)) {
4716 DP(NETIF_MSG_LINK, "FW does not support OPT MDL "
4717 "verification\n");
4718 return -EINVAL;
4719 }
4720 cmd = DRV_MSG_CODE_VRFY_FIRST_PHY_OPT_MDL;
4721 } else {
4722 /* No support in OPT MDL detection */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004723 DP(NETIF_MSG_LINK, "FW does not support OPT MDL "
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004724 "verification\n");
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004725 return -EINVAL;
4726 }
Dmitry Kravkov523224a2010-10-06 03:23:26 +00004727
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004728 fw_cmd_param = FW_PARAM_SET(phy->addr, phy->type, phy->mdio_ctrl);
4729 fw_resp = bnx2x_fw_command(bp, cmd, fw_cmd_param);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004730 if (fw_resp == FW_MSG_CODE_VRFY_OPT_MDL_SUCCESS) {
4731 DP(NETIF_MSG_LINK, "Approved module\n");
4732 return 0;
4733 }
4734
4735 /* format the warning message */
4736 if (bnx2x_read_sfp_module_eeprom(phy,
4737 params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004738 SFP_EEPROM_VENDOR_NAME_ADDR,
4739 SFP_EEPROM_VENDOR_NAME_SIZE,
4740 (u8 *)vendor_name))
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004741 vendor_name[0] = '\0';
4742 else
4743 vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE] = '\0';
4744 if (bnx2x_read_sfp_module_eeprom(phy,
4745 params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004746 SFP_EEPROM_PART_NO_ADDR,
4747 SFP_EEPROM_PART_NO_SIZE,
4748 (u8 *)vendor_pn))
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004749 vendor_pn[0] = '\0';
4750 else
4751 vendor_pn[SFP_EEPROM_PART_NO_SIZE] = '\0';
4752
4753 netdev_info(bp->dev, "Warning: Unqualified SFP+ module detected,"
4754 " Port %d from %s part number %s\n",
4755 params->port, vendor_name, vendor_pn);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004756 phy->flags |= FLAGS_SFP_NOT_APPROVED;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004757 return -EINVAL;
4758}
4759
4760static u8 bnx2x_wait_for_sfp_module_initialized(struct bnx2x_phy *phy,
4761 struct link_params *params)
4762
4763{
4764 u8 val;
4765 struct bnx2x *bp = params->bp;
4766 u16 timeout;
4767 /* Initialization time after hot-plug may take up to 300ms for some
4768 phys type ( e.g. JDSU ) */
4769 for (timeout = 0; timeout < 60; timeout++) {
4770 if (bnx2x_read_sfp_module_eeprom(phy, params, 1, 1, &val)
4771 == 0) {
4772 DP(NETIF_MSG_LINK, "SFP+ module initialization "
4773 "took %d ms\n", timeout * 5);
4774 return 0;
4775 }
4776 msleep(5);
4777 }
4778 return -EINVAL;
4779}
4780
4781static void bnx2x_8727_power_module(struct bnx2x *bp,
4782 struct bnx2x_phy *phy,
4783 u8 is_power_up) {
4784 /* Make sure GPIOs are not using for LED mode */
4785 u16 val;
4786 /*
4787 * In the GPIO register, bit 4 is use to detemine if the GPIOs are
4788 * operating as INPUT or as OUTPUT. Bit 1 is for input, and 0 for
4789 * output
4790 * Bits 0-1 determine the gpios value for OUTPUT in case bit 4 val is 0
4791 * Bits 8-9 determine the gpios value for INPUT in case bit 4 val is 1
4792 * where the 1st bit is the over-current(only input), and 2nd bit is
4793 * for power( only output )
4794 */
4795
4796 /*
4797 * In case of NOC feature is disabled and power is up, set GPIO control
4798 * as input to enable listening of over-current indication
4799 */
4800 if (phy->flags & FLAGS_NOC)
4801 return;
4802 if (!(phy->flags &
4803 FLAGS_NOC) && is_power_up)
4804 val = (1<<4);
4805 else
4806 /*
4807 * Set GPIO control to OUTPUT, and set the power bit
4808 * to according to the is_power_up
4809 */
4810 val = ((!(is_power_up)) << 1);
4811
4812 bnx2x_cl45_write(bp, phy,
4813 MDIO_PMA_DEVAD,
4814 MDIO_PMA_REG_8727_GPIO_CTRL,
4815 val);
4816}
4817
4818static u8 bnx2x_8726_set_limiting_mode(struct bnx2x *bp,
4819 struct bnx2x_phy *phy,
4820 u16 edc_mode)
4821{
4822 u16 cur_limiting_mode;
4823
4824 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004825 MDIO_PMA_DEVAD,
4826 MDIO_PMA_REG_ROM_VER2,
4827 &cur_limiting_mode);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004828 DP(NETIF_MSG_LINK, "Current Limiting mode is 0x%x\n",
4829 cur_limiting_mode);
4830
4831 if (edc_mode == EDC_MODE_LIMITING) {
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004832 DP(NETIF_MSG_LINK, "Setting LIMITING MODE\n");
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004833 bnx2x_cl45_write(bp, phy,
4834 MDIO_PMA_DEVAD,
4835 MDIO_PMA_REG_ROM_VER2,
4836 EDC_MODE_LIMITING);
4837 } else { /* LRM mode ( default )*/
4838
4839 DP(NETIF_MSG_LINK, "Setting LRM MODE\n");
4840
4841 /* Changing to LRM mode takes quite few seconds.
4842 So do it only if current mode is limiting
4843 ( default is LRM )*/
4844 if (cur_limiting_mode != EDC_MODE_LIMITING)
4845 return 0;
4846
4847 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004848 MDIO_PMA_DEVAD,
4849 MDIO_PMA_REG_LRM_MODE,
4850 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004851 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004852 MDIO_PMA_DEVAD,
4853 MDIO_PMA_REG_ROM_VER2,
4854 0x128);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004855 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004856 MDIO_PMA_DEVAD,
4857 MDIO_PMA_REG_MISC_CTRL0,
4858 0x4008);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004859 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004860 MDIO_PMA_DEVAD,
4861 MDIO_PMA_REG_LRM_MODE,
4862 0xaaaa);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004863 }
4864 return 0;
4865}
4866
4867static u8 bnx2x_8727_set_limiting_mode(struct bnx2x *bp,
4868 struct bnx2x_phy *phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004869 u16 edc_mode)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004870{
4871 u16 phy_identifier;
4872 u16 rom_ver2_val;
4873 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004874 MDIO_PMA_DEVAD,
4875 MDIO_PMA_REG_PHY_IDENTIFIER,
4876 &phy_identifier);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004877
4878 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004879 MDIO_PMA_DEVAD,
4880 MDIO_PMA_REG_PHY_IDENTIFIER,
4881 (phy_identifier & ~(1<<9)));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004882
4883 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004884 MDIO_PMA_DEVAD,
4885 MDIO_PMA_REG_ROM_VER2,
4886 &rom_ver2_val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004887 /* Keep the MSB 8-bits, and set the LSB 8-bits with the edc_mode */
4888 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004889 MDIO_PMA_DEVAD,
4890 MDIO_PMA_REG_ROM_VER2,
4891 (rom_ver2_val & 0xff00) | (edc_mode & 0x00ff));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004892
4893 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004894 MDIO_PMA_DEVAD,
4895 MDIO_PMA_REG_PHY_IDENTIFIER,
4896 (phy_identifier | (1<<9)));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004897
4898 return 0;
4899}
4900
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004901static void bnx2x_8727_specific_func(struct bnx2x_phy *phy,
4902 struct link_params *params,
4903 u32 action)
4904{
4905 struct bnx2x *bp = params->bp;
4906
4907 switch (action) {
4908 case DISABLE_TX:
4909 bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
4910 break;
4911 case ENABLE_TX:
4912 if (!(phy->flags & FLAGS_SFP_NOT_APPROVED))
4913 bnx2x_sfp_set_transmitter(bp, phy, params->port, 1);
4914 break;
4915 default:
4916 DP(NETIF_MSG_LINK, "Function 0x%x not supported by 8727\n",
4917 action);
4918 return;
4919 }
4920}
4921
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004922static u8 bnx2x_sfp_module_detection(struct bnx2x_phy *phy,
4923 struct link_params *params)
4924{
4925 struct bnx2x *bp = params->bp;
4926 u16 edc_mode;
4927 u8 rc = 0;
4928
4929 u32 val = REG_RD(bp, params->shmem_base +
4930 offsetof(struct shmem_region, dev_info.
4931 port_feature_config[params->port].config));
4932
4933 DP(NETIF_MSG_LINK, "SFP+ module plugged in/out detected on port %d\n",
4934 params->port);
4935
4936 if (bnx2x_get_edc_mode(phy, params, &edc_mode) != 0) {
4937 DP(NETIF_MSG_LINK, "Failed to get valid module type\n");
4938 return -EINVAL;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004939 } else if (bnx2x_verify_sfp_module(phy, params) != 0) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004940 /* check SFP+ module compatibility */
4941 DP(NETIF_MSG_LINK, "Module verification failed!!\n");
4942 rc = -EINVAL;
4943 /* Turn on fault module-detected led */
4944 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
4945 MISC_REGISTERS_GPIO_HIGH,
4946 params->port);
4947 if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) &&
4948 ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
4949 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_POWER_DOWN)) {
4950 /* Shutdown SFP+ module */
4951 DP(NETIF_MSG_LINK, "Shutdown SFP+ module!!\n");
4952 bnx2x_8727_power_module(bp, phy, 0);
4953 return rc;
4954 }
4955 } else {
4956 /* Turn off fault module-detected led */
4957 DP(NETIF_MSG_LINK, "Turn off fault module-detected led\n");
4958 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
4959 MISC_REGISTERS_GPIO_LOW,
4960 params->port);
4961 }
4962
4963 /* power up the SFP module */
4964 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
4965 bnx2x_8727_power_module(bp, phy, 1);
4966
4967 /* Check and set limiting mode / LRM mode on 8726.
4968 On 8727 it is done automatically */
4969 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
4970 bnx2x_8726_set_limiting_mode(bp, phy, edc_mode);
4971 else
4972 bnx2x_8727_set_limiting_mode(bp, phy, edc_mode);
4973 /*
4974 * Enable transmit for this module if the module is approved, or
4975 * if unapproved modules should also enable the Tx laser
4976 */
4977 if (rc == 0 ||
4978 (val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) !=
4979 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
4980 bnx2x_sfp_set_transmitter(bp, phy, params->port, 1);
4981 else
4982 bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
4983
4984 return rc;
4985}
4986
4987void bnx2x_handle_module_detect_int(struct link_params *params)
4988{
4989 struct bnx2x *bp = params->bp;
4990 struct bnx2x_phy *phy = &params->phy[EXT_PHY1];
4991 u32 gpio_val;
4992 u8 port = params->port;
4993
4994 /* Set valid module led off */
4995 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
4996 MISC_REGISTERS_GPIO_HIGH,
4997 params->port);
4998
4999 /* Get current gpio val refelecting module plugged in / out*/
5000 gpio_val = bnx2x_get_gpio(bp, MISC_REGISTERS_GPIO_3, port);
5001
5002 /* Call the handling function in case module is detected */
5003 if (gpio_val == 0) {
5004
5005 bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
5006 MISC_REGISTERS_GPIO_INT_OUTPUT_CLR,
5007 port);
5008
5009 if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0)
5010 bnx2x_sfp_module_detection(phy, params);
5011 else
5012 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
5013 } else {
5014 u32 val = REG_RD(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005015 offsetof(struct shmem_region, dev_info.
5016 port_feature_config[params->port].
5017 config));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005018
5019 bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
5020 MISC_REGISTERS_GPIO_INT_OUTPUT_SET,
5021 port);
5022 /* Module was plugged out. */
5023 /* Disable transmit for this module */
5024 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
5025 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
5026 bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
5027 }
5028}
5029
5030/******************************************************************/
5031/* common BCM8706/BCM8726 PHY SECTION */
5032/******************************************************************/
5033static u8 bnx2x_8706_8726_read_status(struct bnx2x_phy *phy,
5034 struct link_params *params,
5035 struct link_vars *vars)
5036{
5037 u8 link_up = 0;
5038 u16 val1, val2, rx_sd, pcs_status;
5039 struct bnx2x *bp = params->bp;
5040 DP(NETIF_MSG_LINK, "XGXS 8706/8726\n");
5041 /* Clear RX Alarm*/
5042 bnx2x_cl45_read(bp, phy,
5043 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &val2);
5044 /* clear LASI indication*/
5045 bnx2x_cl45_read(bp, phy,
5046 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
5047 bnx2x_cl45_read(bp, phy,
5048 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val2);
5049 DP(NETIF_MSG_LINK, "8706/8726 LASI status 0x%x--> 0x%x\n", val1, val2);
5050
5051 bnx2x_cl45_read(bp, phy,
5052 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD, &rx_sd);
5053 bnx2x_cl45_read(bp, phy,
5054 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &pcs_status);
5055 bnx2x_cl45_read(bp, phy,
5056 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &val2);
5057 bnx2x_cl45_read(bp, phy,
5058 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &val2);
5059
5060 DP(NETIF_MSG_LINK, "8706/8726 rx_sd 0x%x pcs_status 0x%x 1Gbps"
5061 " link_status 0x%x\n", rx_sd, pcs_status, val2);
5062 /* link is up if both bit 0 of pmd_rx_sd and
5063 * bit 0 of pcs_status are set, or if the autoneg bit
5064 * 1 is set
5065 */
5066 link_up = ((rx_sd & pcs_status & 0x1) || (val2 & (1<<1)));
5067 if (link_up) {
5068 if (val2 & (1<<1))
5069 vars->line_speed = SPEED_1000;
5070 else
5071 vars->line_speed = SPEED_10000;
5072 bnx2x_ext_phy_resolve_fc(phy, params, vars);
Yaniv Rosner791f18c2011-01-18 04:33:42 +00005073 vars->duplex = DUPLEX_FULL;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005074 }
5075 return link_up;
5076}
5077
5078/******************************************************************/
5079/* BCM8706 PHY SECTION */
5080/******************************************************************/
5081static u8 bnx2x_8706_config_init(struct bnx2x_phy *phy,
5082 struct link_params *params,
5083 struct link_vars *vars)
5084{
5085 u16 cnt, val;
5086 struct bnx2x *bp = params->bp;
5087 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005088 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005089 /* HW reset */
5090 bnx2x_ext_phy_hw_reset(bp, params->port);
5091 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0xa040);
5092 bnx2x_wait_reset_complete(bp, phy);
5093
5094 /* Wait until fw is loaded */
5095 for (cnt = 0; cnt < 100; cnt++) {
5096 bnx2x_cl45_read(bp, phy,
5097 MDIO_PMA_DEVAD, MDIO_PMA_REG_ROM_VER1, &val);
5098 if (val)
5099 break;
5100 msleep(10);
5101 }
5102 DP(NETIF_MSG_LINK, "XGXS 8706 is initialized after %d ms\n", cnt);
5103 if ((params->feature_config_flags &
5104 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
5105 u8 i;
5106 u16 reg;
5107 for (i = 0; i < 4; i++) {
5108 reg = MDIO_XS_8706_REG_BANK_RX0 +
5109 i*(MDIO_XS_8706_REG_BANK_RX1 -
5110 MDIO_XS_8706_REG_BANK_RX0);
5111 bnx2x_cl45_read(bp, phy, MDIO_XS_DEVAD, reg, &val);
5112 /* Clear first 3 bits of the control */
5113 val &= ~0x7;
5114 /* Set control bits according to configuration */
5115 val |= (phy->rx_preemphasis[i] & 0x7);
5116 DP(NETIF_MSG_LINK, "Setting RX Equalizer to BCM8706"
5117 " reg 0x%x <-- val 0x%x\n", reg, val);
5118 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, reg, val);
5119 }
5120 }
5121 /* Force speed */
5122 if (phy->req_line_speed == SPEED_10000) {
5123 DP(NETIF_MSG_LINK, "XGXS 8706 force 10Gbps\n");
5124
5125 bnx2x_cl45_write(bp, phy,
5126 MDIO_PMA_DEVAD,
5127 MDIO_PMA_REG_DIGITAL_CTRL, 0x400);
5128 bnx2x_cl45_write(bp, phy,
5129 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 1);
5130 } else {
5131 /* Force 1Gbps using autoneg with 1G advertisment */
5132
5133 /* Allow CL37 through CL73 */
5134 DP(NETIF_MSG_LINK, "XGXS 8706 AutoNeg\n");
5135 bnx2x_cl45_write(bp, phy,
5136 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_CL73, 0x040c);
5137
5138 /* Enable Full-Duplex advertisment on CL37 */
5139 bnx2x_cl45_write(bp, phy,
5140 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LP, 0x0020);
5141 /* Enable CL37 AN */
5142 bnx2x_cl45_write(bp, phy,
5143 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
5144 /* 1G support */
5145 bnx2x_cl45_write(bp, phy,
5146 MDIO_AN_DEVAD, MDIO_AN_REG_ADV, (1<<5));
5147
5148 /* Enable clause 73 AN */
5149 bnx2x_cl45_write(bp, phy,
5150 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
5151 bnx2x_cl45_write(bp, phy,
5152 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
5153 0x0400);
5154 bnx2x_cl45_write(bp, phy,
5155 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL,
5156 0x0004);
5157 }
5158 bnx2x_save_bcm_spirom_ver(bp, phy, params->port);
5159 return 0;
5160}
5161
5162static u8 bnx2x_8706_read_status(struct bnx2x_phy *phy,
5163 struct link_params *params,
5164 struct link_vars *vars)
5165{
5166 return bnx2x_8706_8726_read_status(phy, params, vars);
5167}
5168
5169/******************************************************************/
5170/* BCM8726 PHY SECTION */
5171/******************************************************************/
5172static void bnx2x_8726_config_loopback(struct bnx2x_phy *phy,
5173 struct link_params *params)
5174{
5175 struct bnx2x *bp = params->bp;
5176 DP(NETIF_MSG_LINK, "PMA/PMD ext_phy_loopback: 8726\n");
5177 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x0001);
5178}
5179
5180static void bnx2x_8726_external_rom_boot(struct bnx2x_phy *phy,
5181 struct link_params *params)
5182{
5183 struct bnx2x *bp = params->bp;
5184 /* Need to wait 100ms after reset */
5185 msleep(100);
5186
5187 /* Micro controller re-boot */
5188 bnx2x_cl45_write(bp, phy,
5189 MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, 0x018B);
5190
5191 /* Set soft reset */
5192 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005193 MDIO_PMA_DEVAD,
5194 MDIO_PMA_REG_GEN_CTRL,
5195 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005196
5197 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005198 MDIO_PMA_DEVAD,
5199 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005200
5201 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005202 MDIO_PMA_DEVAD,
5203 MDIO_PMA_REG_GEN_CTRL,
5204 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005205
5206 /* wait for 150ms for microcode load */
5207 msleep(150);
5208
5209 /* Disable serial boot control, tristates pins SS_N, SCK, MOSI, MISO */
5210 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005211 MDIO_PMA_DEVAD,
5212 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005213
5214 msleep(200);
5215 bnx2x_save_bcm_spirom_ver(bp, phy, params->port);
5216}
5217
5218static u8 bnx2x_8726_read_status(struct bnx2x_phy *phy,
5219 struct link_params *params,
5220 struct link_vars *vars)
5221{
5222 struct bnx2x *bp = params->bp;
5223 u16 val1;
5224 u8 link_up = bnx2x_8706_8726_read_status(phy, params, vars);
5225 if (link_up) {
5226 bnx2x_cl45_read(bp, phy,
5227 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER,
5228 &val1);
5229 if (val1 & (1<<15)) {
5230 DP(NETIF_MSG_LINK, "Tx is disabled\n");
5231 link_up = 0;
5232 vars->line_speed = 0;
5233 }
5234 }
5235 return link_up;
5236}
5237
5238
5239static u8 bnx2x_8726_config_init(struct bnx2x_phy *phy,
5240 struct link_params *params,
5241 struct link_vars *vars)
5242{
5243 struct bnx2x *bp = params->bp;
5244 u32 val;
5245 u32 swap_val, swap_override, aeu_gpio_mask, offset;
5246 DP(NETIF_MSG_LINK, "Initializing BCM8726\n");
5247 /* Restore normal power mode*/
5248 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
5249 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
5250
5251 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
5252 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
5253
5254 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
5255 bnx2x_wait_reset_complete(bp, phy);
5256
5257 bnx2x_8726_external_rom_boot(phy, params);
5258
5259 /* Need to call module detected on initialization since
5260 the module detection triggered by actual module
5261 insertion might occur before driver is loaded, and when
5262 driver is loaded, it reset all registers, including the
5263 transmitter */
5264 bnx2x_sfp_module_detection(phy, params);
5265
5266 if (phy->req_line_speed == SPEED_1000) {
5267 DP(NETIF_MSG_LINK, "Setting 1G force\n");
5268 bnx2x_cl45_write(bp, phy,
5269 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x40);
5270 bnx2x_cl45_write(bp, phy,
5271 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0xD);
5272 bnx2x_cl45_write(bp, phy,
5273 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x5);
5274 bnx2x_cl45_write(bp, phy,
5275 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
5276 0x400);
5277 } else if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
5278 (phy->speed_cap_mask &
5279 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G) &&
5280 ((phy->speed_cap_mask &
5281 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) !=
5282 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
5283 DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
5284 /* Set Flow control */
5285 bnx2x_ext_phy_set_pause(params, phy, vars);
5286 bnx2x_cl45_write(bp, phy,
5287 MDIO_AN_DEVAD, MDIO_AN_REG_ADV, 0x20);
5288 bnx2x_cl45_write(bp, phy,
5289 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_CL73, 0x040c);
5290 bnx2x_cl45_write(bp, phy,
5291 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, 0x0020);
5292 bnx2x_cl45_write(bp, phy,
5293 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
5294 bnx2x_cl45_write(bp, phy,
5295 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
5296 /* Enable RX-ALARM control to receive
5297 interrupt for 1G speed change */
5298 bnx2x_cl45_write(bp, phy,
5299 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x4);
5300 bnx2x_cl45_write(bp, phy,
5301 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
5302 0x400);
5303
5304 } else { /* Default 10G. Set only LASI control */
5305 bnx2x_cl45_write(bp, phy,
5306 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 1);
5307 }
5308
5309 /* Set TX PreEmphasis if needed */
5310 if ((params->feature_config_flags &
5311 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
5312 DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x,"
5313 "TX_CTRL2 0x%x\n",
5314 phy->tx_preemphasis[0],
5315 phy->tx_preemphasis[1]);
5316 bnx2x_cl45_write(bp, phy,
5317 MDIO_PMA_DEVAD,
5318 MDIO_PMA_REG_8726_TX_CTRL1,
5319 phy->tx_preemphasis[0]);
5320
5321 bnx2x_cl45_write(bp, phy,
5322 MDIO_PMA_DEVAD,
5323 MDIO_PMA_REG_8726_TX_CTRL2,
5324 phy->tx_preemphasis[1]);
5325 }
5326
5327 /* Set GPIO3 to trigger SFP+ module insertion/removal */
5328 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005329 MISC_REGISTERS_GPIO_INPUT_HI_Z, params->port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005330
5331 /* The GPIO should be swapped if the swap register is set and active */
5332 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
5333 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
5334
5335 /* Select function upon port-swap configuration */
5336 if (params->port == 0) {
5337 offset = MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0;
5338 aeu_gpio_mask = (swap_val && swap_override) ?
5339 AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_1 :
5340 AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0;
5341 } else {
5342 offset = MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0;
5343 aeu_gpio_mask = (swap_val && swap_override) ?
5344 AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0 :
5345 AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_1;
5346 }
5347 val = REG_RD(bp, offset);
5348 /* add GPIO3 to group */
5349 val |= aeu_gpio_mask;
5350 REG_WR(bp, offset, val);
5351 return 0;
5352
5353}
5354
5355static void bnx2x_8726_link_reset(struct bnx2x_phy *phy,
5356 struct link_params *params)
5357{
5358 struct bnx2x *bp = params->bp;
5359 DP(NETIF_MSG_LINK, "bnx2x_8726_link_reset port %d\n", params->port);
5360 /* Set serial boot control for external load */
5361 bnx2x_cl45_write(bp, phy,
5362 MDIO_PMA_DEVAD,
5363 MDIO_PMA_REG_GEN_CTRL, 0x0001);
5364}
5365
5366/******************************************************************/
5367/* BCM8727 PHY SECTION */
5368/******************************************************************/
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005369
5370static void bnx2x_8727_set_link_led(struct bnx2x_phy *phy,
5371 struct link_params *params, u8 mode)
5372{
5373 struct bnx2x *bp = params->bp;
5374 u16 led_mode_bitmask = 0;
5375 u16 gpio_pins_bitmask = 0;
5376 u16 val;
5377 /* Only NOC flavor requires to set the LED specifically */
5378 if (!(phy->flags & FLAGS_NOC))
5379 return;
5380 switch (mode) {
5381 case LED_MODE_FRONT_PANEL_OFF:
5382 case LED_MODE_OFF:
5383 led_mode_bitmask = 0;
5384 gpio_pins_bitmask = 0x03;
5385 break;
5386 case LED_MODE_ON:
5387 led_mode_bitmask = 0;
5388 gpio_pins_bitmask = 0x02;
5389 break;
5390 case LED_MODE_OPER:
5391 led_mode_bitmask = 0x60;
5392 gpio_pins_bitmask = 0x11;
5393 break;
5394 }
5395 bnx2x_cl45_read(bp, phy,
5396 MDIO_PMA_DEVAD,
5397 MDIO_PMA_REG_8727_PCS_OPT_CTRL,
5398 &val);
5399 val &= 0xff8f;
5400 val |= led_mode_bitmask;
5401 bnx2x_cl45_write(bp, phy,
5402 MDIO_PMA_DEVAD,
5403 MDIO_PMA_REG_8727_PCS_OPT_CTRL,
5404 val);
5405 bnx2x_cl45_read(bp, phy,
5406 MDIO_PMA_DEVAD,
5407 MDIO_PMA_REG_8727_GPIO_CTRL,
5408 &val);
5409 val &= 0xffe0;
5410 val |= gpio_pins_bitmask;
5411 bnx2x_cl45_write(bp, phy,
5412 MDIO_PMA_DEVAD,
5413 MDIO_PMA_REG_8727_GPIO_CTRL,
5414 val);
5415}
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005416static void bnx2x_8727_hw_reset(struct bnx2x_phy *phy,
5417 struct link_params *params) {
5418 u32 swap_val, swap_override;
5419 u8 port;
5420 /**
5421 * The PHY reset is controlled by GPIO 1. Fake the port number
5422 * to cancel the swap done in set_gpio()
5423 */
5424 struct bnx2x *bp = params->bp;
5425 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
5426 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
5427 port = (swap_val && swap_override) ^ 1;
5428 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005429 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005430}
5431
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005432static u8 bnx2x_8727_config_init(struct bnx2x_phy *phy,
5433 struct link_params *params,
5434 struct link_vars *vars)
5435{
5436 u16 tmp1, val, mod_abs;
5437 u16 rx_alarm_ctrl_val;
5438 u16 lasi_ctrl_val;
5439 struct bnx2x *bp = params->bp;
5440 /* Enable PMD link, MOD_ABS_FLT, and 1G link alarm */
5441
5442 bnx2x_wait_reset_complete(bp, phy);
5443 rx_alarm_ctrl_val = (1<<2) | (1<<5) ;
5444 lasi_ctrl_val = 0x0004;
5445
5446 DP(NETIF_MSG_LINK, "Initializing BCM8727\n");
5447 /* enable LASI */
5448 bnx2x_cl45_write(bp, phy,
5449 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
5450 rx_alarm_ctrl_val);
5451
5452 bnx2x_cl45_write(bp, phy,
5453 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, lasi_ctrl_val);
5454
5455 /* Initially configure MOD_ABS to interrupt when
5456 module is presence( bit 8) */
5457 bnx2x_cl45_read(bp, phy,
5458 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
5459 /* Set EDC off by setting OPTXLOS signal input to low
5460 (bit 9).
5461 When the EDC is off it locks onto a reference clock and
5462 avoids becoming 'lost'.*/
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005463 mod_abs &= ~(1<<8);
5464 if (!(phy->flags & FLAGS_NOC))
5465 mod_abs &= ~(1<<9);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005466 bnx2x_cl45_write(bp, phy,
5467 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
5468
5469
5470 /* Make MOD_ABS give interrupt on change */
5471 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL,
5472 &val);
5473 val |= (1<<12);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005474 if (phy->flags & FLAGS_NOC)
5475 val |= (3<<5);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005476
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005477 /**
5478 * Set 8727 GPIOs to input to allow reading from the 8727 GPIO0
5479 * status which reflect SFP+ module over-current
5480 */
5481 if (!(phy->flags & FLAGS_NOC))
5482 val &= 0xff8f; /* Reset bits 4-6 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005483 bnx2x_cl45_write(bp, phy,
5484 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL, val);
5485
5486 bnx2x_8727_power_module(bp, phy, 1);
5487
5488 bnx2x_cl45_read(bp, phy,
5489 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &tmp1);
5490
5491 bnx2x_cl45_read(bp, phy,
5492 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &tmp1);
5493
5494 /* Set option 1G speed */
5495 if (phy->req_line_speed == SPEED_1000) {
5496 DP(NETIF_MSG_LINK, "Setting 1G force\n");
5497 bnx2x_cl45_write(bp, phy,
5498 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x40);
5499 bnx2x_cl45_write(bp, phy,
5500 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0xD);
5501 bnx2x_cl45_read(bp, phy,
5502 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, &tmp1);
5503 DP(NETIF_MSG_LINK, "1.7 = 0x%x\n", tmp1);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005504 /**
5505 * Power down the XAUI until link is up in case of dual-media
5506 * and 1G
5507 */
5508 if (DUAL_MEDIA(params)) {
5509 bnx2x_cl45_read(bp, phy,
5510 MDIO_PMA_DEVAD,
5511 MDIO_PMA_REG_8727_PCS_GP, &val);
5512 val |= (3<<10);
5513 bnx2x_cl45_write(bp, phy,
5514 MDIO_PMA_DEVAD,
5515 MDIO_PMA_REG_8727_PCS_GP, val);
5516 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005517 } else if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
5518 ((phy->speed_cap_mask &
5519 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) &&
5520 ((phy->speed_cap_mask &
5521 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) !=
5522 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
5523
5524 DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
5525 bnx2x_cl45_write(bp, phy,
5526 MDIO_AN_DEVAD, MDIO_AN_REG_8727_MISC_CTRL, 0);
5527 bnx2x_cl45_write(bp, phy,
5528 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1300);
5529 } else {
5530 /**
5531 * Since the 8727 has only single reset pin, need to set the 10G
5532 * registers although it is default
5533 */
5534 bnx2x_cl45_write(bp, phy,
5535 MDIO_AN_DEVAD, MDIO_AN_REG_8727_MISC_CTRL,
5536 0x0020);
5537 bnx2x_cl45_write(bp, phy,
5538 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x0100);
5539 bnx2x_cl45_write(bp, phy,
5540 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x2040);
5541 bnx2x_cl45_write(bp, phy,
5542 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2,
5543 0x0008);
5544 }
5545
5546 /* Set 2-wire transfer rate of SFP+ module EEPROM
5547 * to 100Khz since some DACs(direct attached cables) do
5548 * not work at 400Khz.
5549 */
5550 bnx2x_cl45_write(bp, phy,
5551 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR,
5552 0xa001);
5553
5554 /* Set TX PreEmphasis if needed */
5555 if ((params->feature_config_flags &
5556 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
5557 DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x, TX_CTRL2 0x%x\n",
5558 phy->tx_preemphasis[0],
5559 phy->tx_preemphasis[1]);
5560 bnx2x_cl45_write(bp, phy,
5561 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TX_CTRL1,
5562 phy->tx_preemphasis[0]);
5563
5564 bnx2x_cl45_write(bp, phy,
5565 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TX_CTRL2,
5566 phy->tx_preemphasis[1]);
5567 }
5568
5569 return 0;
5570}
5571
5572static void bnx2x_8727_handle_mod_abs(struct bnx2x_phy *phy,
5573 struct link_params *params)
5574{
5575 struct bnx2x *bp = params->bp;
5576 u16 mod_abs, rx_alarm_status;
5577 u32 val = REG_RD(bp, params->shmem_base +
5578 offsetof(struct shmem_region, dev_info.
5579 port_feature_config[params->port].
5580 config));
5581 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005582 MDIO_PMA_DEVAD,
5583 MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005584 if (mod_abs & (1<<8)) {
5585
5586 /* Module is absent */
5587 DP(NETIF_MSG_LINK, "MOD_ABS indication "
5588 "show module is absent\n");
5589
5590 /* 1. Set mod_abs to detect next module
5591 presence event
5592 2. Set EDC off by setting OPTXLOS signal input to low
5593 (bit 9).
5594 When the EDC is off it locks onto a reference clock and
5595 avoids becoming 'lost'.*/
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005596 mod_abs &= ~(1<<8);
5597 if (!(phy->flags & FLAGS_NOC))
5598 mod_abs &= ~(1<<9);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005599 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005600 MDIO_PMA_DEVAD,
5601 MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005602
5603 /* Clear RX alarm since it stays up as long as
5604 the mod_abs wasn't changed */
5605 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005606 MDIO_PMA_DEVAD,
5607 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005608
5609 } else {
5610 /* Module is present */
5611 DP(NETIF_MSG_LINK, "MOD_ABS indication "
5612 "show module is present\n");
5613 /* First thing, disable transmitter,
5614 and if the module is ok, the
5615 module_detection will enable it*/
5616
5617 /* 1. Set mod_abs to detect next module
5618 absent event ( bit 8)
5619 2. Restore the default polarity of the OPRXLOS signal and
5620 this signal will then correctly indicate the presence or
5621 absence of the Rx signal. (bit 9) */
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005622 mod_abs |= (1<<8);
5623 if (!(phy->flags & FLAGS_NOC))
5624 mod_abs |= (1<<9);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005625 bnx2x_cl45_write(bp, phy,
5626 MDIO_PMA_DEVAD,
5627 MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
5628
5629 /* Clear RX alarm since it stays up as long as
5630 the mod_abs wasn't changed. This is need to be done
5631 before calling the module detection, otherwise it will clear
5632 the link update alarm */
5633 bnx2x_cl45_read(bp, phy,
5634 MDIO_PMA_DEVAD,
5635 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
5636
5637
5638 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
5639 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
5640 bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
5641
5642 if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0)
5643 bnx2x_sfp_module_detection(phy, params);
5644 else
5645 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
5646 }
5647
5648 DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n",
5649 rx_alarm_status);
5650 /* No need to check link status in case of
5651 module plugged in/out */
5652}
5653
5654static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy,
5655 struct link_params *params,
5656 struct link_vars *vars)
5657
5658{
5659 struct bnx2x *bp = params->bp;
5660 u8 link_up = 0;
5661 u16 link_status = 0;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005662 u16 rx_alarm_status, lasi_ctrl, val1;
5663
5664 /* If PHY is not initialized, do not check link status */
5665 bnx2x_cl45_read(bp, phy,
5666 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL,
5667 &lasi_ctrl);
5668 if (!lasi_ctrl)
5669 return 0;
5670
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005671 /* Check the LASI */
5672 bnx2x_cl45_read(bp, phy,
5673 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM,
5674 &rx_alarm_status);
5675 vars->line_speed = 0;
5676 DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n", rx_alarm_status);
5677
5678 bnx2x_cl45_read(bp, phy,
5679 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
5680
5681 DP(NETIF_MSG_LINK, "8727 LASI status 0x%x\n", val1);
5682
5683 /* Clear MSG-OUT */
5684 bnx2x_cl45_read(bp, phy,
5685 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &val1);
5686
5687 /**
5688 * If a module is present and there is need to check
5689 * for over current
5690 */
5691 if (!(phy->flags & FLAGS_NOC) && !(rx_alarm_status & (1<<5))) {
5692 /* Check over-current using 8727 GPIO0 input*/
5693 bnx2x_cl45_read(bp, phy,
5694 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_GPIO_CTRL,
5695 &val1);
5696
5697 if ((val1 & (1<<8)) == 0) {
5698 DP(NETIF_MSG_LINK, "8727 Power fault has been detected"
5699 " on port %d\n", params->port);
5700 netdev_err(bp->dev, "Error: Power fault on Port %d has"
5701 " been detected and the power to "
5702 "that SFP+ module has been removed"
5703 " to prevent failure of the card."
5704 " Please remove the SFP+ module and"
5705 " restart the system to clear this"
5706 " error.\n",
5707 params->port);
5708
5709 /*
5710 * Disable all RX_ALARMs except for
5711 * mod_abs
5712 */
5713 bnx2x_cl45_write(bp, phy,
5714 MDIO_PMA_DEVAD,
5715 MDIO_PMA_REG_RX_ALARM_CTRL, (1<<5));
5716
5717 bnx2x_cl45_read(bp, phy,
5718 MDIO_PMA_DEVAD,
5719 MDIO_PMA_REG_PHY_IDENTIFIER, &val1);
5720 /* Wait for module_absent_event */
5721 val1 |= (1<<8);
5722 bnx2x_cl45_write(bp, phy,
5723 MDIO_PMA_DEVAD,
5724 MDIO_PMA_REG_PHY_IDENTIFIER, val1);
5725 /* Clear RX alarm */
5726 bnx2x_cl45_read(bp, phy,
5727 MDIO_PMA_DEVAD,
5728 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
5729 return 0;
5730 }
5731 } /* Over current check */
5732
5733 /* When module absent bit is set, check module */
5734 if (rx_alarm_status & (1<<5)) {
5735 bnx2x_8727_handle_mod_abs(phy, params);
5736 /* Enable all mod_abs and link detection bits */
5737 bnx2x_cl45_write(bp, phy,
5738 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
5739 ((1<<5) | (1<<2)));
5740 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005741 DP(NETIF_MSG_LINK, "Enabling 8727 TX laser if SFP is approved\n");
5742 bnx2x_8727_specific_func(phy, params, ENABLE_TX);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005743 /* If transmitter is disabled, ignore false link up indication */
5744 bnx2x_cl45_read(bp, phy,
5745 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, &val1);
5746 if (val1 & (1<<15)) {
5747 DP(NETIF_MSG_LINK, "Tx is disabled\n");
5748 return 0;
5749 }
5750
5751 bnx2x_cl45_read(bp, phy,
5752 MDIO_PMA_DEVAD,
5753 MDIO_PMA_REG_8073_SPEED_LINK_STATUS, &link_status);
5754
5755 /* Bits 0..2 --> speed detected,
5756 bits 13..15--> link is down */
5757 if ((link_status & (1<<2)) && (!(link_status & (1<<15)))) {
5758 link_up = 1;
5759 vars->line_speed = SPEED_10000;
5760 } else if ((link_status & (1<<0)) && (!(link_status & (1<<13)))) {
5761 link_up = 1;
5762 vars->line_speed = SPEED_1000;
5763 DP(NETIF_MSG_LINK, "port %x: External link up in 1G\n",
5764 params->port);
5765 } else {
5766 link_up = 0;
5767 DP(NETIF_MSG_LINK, "port %x: External link is down\n",
5768 params->port);
5769 }
Yaniv Rosner791f18c2011-01-18 04:33:42 +00005770 if (link_up) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005771 bnx2x_ext_phy_resolve_fc(phy, params, vars);
Yaniv Rosner791f18c2011-01-18 04:33:42 +00005772 vars->duplex = DUPLEX_FULL;
5773 DP(NETIF_MSG_LINK, "duplex = 0x%x\n", vars->duplex);
5774 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005775
5776 if ((DUAL_MEDIA(params)) &&
5777 (phy->req_line_speed == SPEED_1000)) {
5778 bnx2x_cl45_read(bp, phy,
5779 MDIO_PMA_DEVAD,
5780 MDIO_PMA_REG_8727_PCS_GP, &val1);
5781 /**
5782 * In case of dual-media board and 1G, power up the XAUI side,
5783 * otherwise power it down. For 10G it is done automatically
5784 */
5785 if (link_up)
5786 val1 &= ~(3<<10);
5787 else
5788 val1 |= (3<<10);
5789 bnx2x_cl45_write(bp, phy,
5790 MDIO_PMA_DEVAD,
5791 MDIO_PMA_REG_8727_PCS_GP, val1);
5792 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005793 return link_up;
5794}
5795
5796static void bnx2x_8727_link_reset(struct bnx2x_phy *phy,
5797 struct link_params *params)
5798{
5799 struct bnx2x *bp = params->bp;
5800 /* Disable Transmitter */
5801 bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005802 /* Clear LASI */
5803 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0);
5804
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005805}
5806
5807/******************************************************************/
5808/* BCM8481/BCM84823/BCM84833 PHY SECTION */
5809/******************************************************************/
5810static void bnx2x_save_848xx_spirom_version(struct bnx2x_phy *phy,
5811 struct link_params *params)
5812{
5813 u16 val, fw_ver1, fw_ver2, cnt;
5814 struct bnx2x *bp = params->bp;
5815
5816 /* For the 32 bits registers in 848xx, access via MDIO2ARM interface.*/
5817 /* (1) set register 0xc200_0014(SPI_BRIDGE_CTRL_2) to 0x03000000 */
5818 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0014);
5819 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200);
5820 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81B, 0x0000);
5821 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81C, 0x0300);
5822 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x0009);
5823
5824 for (cnt = 0; cnt < 100; cnt++) {
5825 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val);
5826 if (val & 1)
5827 break;
5828 udelay(5);
5829 }
5830 if (cnt == 100) {
5831 DP(NETIF_MSG_LINK, "Unable to read 848xx phy fw version(1)\n");
5832 bnx2x_save_spirom_version(bp, params->port, 0,
5833 phy->ver_addr);
5834 return;
5835 }
5836
5837
5838 /* 2) read register 0xc200_0000 (SPI_FW_STATUS) */
5839 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0000);
5840 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200);
5841 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x000A);
5842 for (cnt = 0; cnt < 100; cnt++) {
5843 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val);
5844 if (val & 1)
5845 break;
5846 udelay(5);
5847 }
5848 if (cnt == 100) {
5849 DP(NETIF_MSG_LINK, "Unable to read 848xx phy fw version(2)\n");
5850 bnx2x_save_spirom_version(bp, params->port, 0,
5851 phy->ver_addr);
5852 return;
5853 }
5854
5855 /* lower 16 bits of the register SPI_FW_STATUS */
5856 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81B, &fw_ver1);
5857 /* upper 16 bits of register SPI_FW_STATUS */
5858 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81C, &fw_ver2);
5859
5860 bnx2x_save_spirom_version(bp, params->port, (fw_ver2<<16) | fw_ver1,
5861 phy->ver_addr);
5862}
5863
5864static void bnx2x_848xx_set_led(struct bnx2x *bp,
5865 struct bnx2x_phy *phy)
5866{
5867 u16 val;
5868
5869 /* PHYC_CTL_LED_CTL */
5870 bnx2x_cl45_read(bp, phy,
5871 MDIO_PMA_DEVAD,
5872 MDIO_PMA_REG_8481_LINK_SIGNAL, &val);
5873 val &= 0xFE00;
5874 val |= 0x0092;
5875
5876 bnx2x_cl45_write(bp, phy,
5877 MDIO_PMA_DEVAD,
5878 MDIO_PMA_REG_8481_LINK_SIGNAL, val);
5879
5880 bnx2x_cl45_write(bp, phy,
5881 MDIO_PMA_DEVAD,
5882 MDIO_PMA_REG_8481_LED1_MASK,
5883 0x80);
5884
5885 bnx2x_cl45_write(bp, phy,
5886 MDIO_PMA_DEVAD,
5887 MDIO_PMA_REG_8481_LED2_MASK,
5888 0x18);
5889
Yaniv Rosnerf25b3c82011-01-18 04:33:47 +00005890 /* Select activity source by Tx and Rx, as suggested by PHY AE */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005891 bnx2x_cl45_write(bp, phy,
5892 MDIO_PMA_DEVAD,
5893 MDIO_PMA_REG_8481_LED3_MASK,
Yaniv Rosnerf25b3c82011-01-18 04:33:47 +00005894 0x0006);
5895
5896 /* Select the closest activity blink rate to that in 10/100/1000 */
5897 bnx2x_cl45_write(bp, phy,
5898 MDIO_PMA_DEVAD,
5899 MDIO_PMA_REG_8481_LED3_BLINK,
5900 0);
5901
5902 bnx2x_cl45_read(bp, phy,
5903 MDIO_PMA_DEVAD,
5904 MDIO_PMA_REG_84823_CTL_LED_CTL_1, &val);
5905 val |= MDIO_PMA_REG_84823_LED3_STRETCH_EN; /* stretch_en for LED3*/
5906
5907 bnx2x_cl45_write(bp, phy,
5908 MDIO_PMA_DEVAD,
5909 MDIO_PMA_REG_84823_CTL_LED_CTL_1, val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005910
5911 /* 'Interrupt Mask' */
5912 bnx2x_cl45_write(bp, phy,
5913 MDIO_AN_DEVAD,
5914 0xFFFB, 0xFFFD);
5915}
5916
5917static u8 bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005918 struct link_params *params,
5919 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005920{
5921 struct bnx2x *bp = params->bp;
5922 u16 autoneg_val, an_1000_val, an_10_100_val;
Yaniv Rosner9bffeac2010-11-01 05:32:27 +00005923
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005924 bnx2x_bits_en(bp, NIG_REG_LATCH_BC_0 + params->port*4,
5925 1 << NIG_LATCH_BC_ENABLE_MI_INT);
5926
5927 bnx2x_cl45_write(bp, phy,
5928 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x0000);
5929
5930 bnx2x_848xx_set_led(bp, phy);
5931
5932 /* set 1000 speed advertisement */
5933 bnx2x_cl45_read(bp, phy,
5934 MDIO_AN_DEVAD, MDIO_AN_REG_8481_1000T_CTRL,
5935 &an_1000_val);
5936
5937 bnx2x_ext_phy_set_pause(params, phy, vars);
5938 bnx2x_cl45_read(bp, phy,
5939 MDIO_AN_DEVAD,
5940 MDIO_AN_REG_8481_LEGACY_AN_ADV,
5941 &an_10_100_val);
5942 bnx2x_cl45_read(bp, phy,
5943 MDIO_AN_DEVAD, MDIO_AN_REG_8481_LEGACY_MII_CTRL,
5944 &autoneg_val);
5945 /* Disable forced speed */
5946 autoneg_val &= ~((1<<6) | (1<<8) | (1<<9) | (1<<12) | (1<<13));
5947 an_10_100_val &= ~((1<<5) | (1<<6) | (1<<7) | (1<<8));
5948
5949 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
5950 (phy->speed_cap_mask &
5951 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) ||
5952 (phy->req_line_speed == SPEED_1000)) {
5953 an_1000_val |= (1<<8);
5954 autoneg_val |= (1<<9 | 1<<12);
5955 if (phy->req_duplex == DUPLEX_FULL)
5956 an_1000_val |= (1<<9);
5957 DP(NETIF_MSG_LINK, "Advertising 1G\n");
5958 } else
5959 an_1000_val &= ~((1<<8) | (1<<9));
5960
5961 bnx2x_cl45_write(bp, phy,
5962 MDIO_AN_DEVAD, MDIO_AN_REG_8481_1000T_CTRL,
5963 an_1000_val);
5964
5965 /* set 10 speed advertisement */
5966 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
5967 (phy->speed_cap_mask &
5968 (PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL |
5969 PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF)))) {
5970 an_10_100_val |= (1<<7);
5971 /* Enable autoneg and restart autoneg for legacy speeds */
5972 autoneg_val |= (1<<9 | 1<<12);
5973
5974 if (phy->req_duplex == DUPLEX_FULL)
5975 an_10_100_val |= (1<<8);
5976 DP(NETIF_MSG_LINK, "Advertising 100M\n");
5977 }
5978 /* set 10 speed advertisement */
5979 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
5980 (phy->speed_cap_mask &
5981 (PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL |
5982 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF)))) {
5983 an_10_100_val |= (1<<5);
5984 autoneg_val |= (1<<9 | 1<<12);
5985 if (phy->req_duplex == DUPLEX_FULL)
5986 an_10_100_val |= (1<<6);
5987 DP(NETIF_MSG_LINK, "Advertising 10M\n");
5988 }
5989
5990 /* Only 10/100 are allowed to work in FORCE mode */
5991 if (phy->req_line_speed == SPEED_100) {
5992 autoneg_val |= (1<<13);
5993 /* Enabled AUTO-MDIX when autoneg is disabled */
5994 bnx2x_cl45_write(bp, phy,
5995 MDIO_AN_DEVAD, MDIO_AN_REG_8481_AUX_CTRL,
5996 (1<<15 | 1<<9 | 7<<0));
5997 DP(NETIF_MSG_LINK, "Setting 100M force\n");
5998 }
5999 if (phy->req_line_speed == SPEED_10) {
6000 /* Enabled AUTO-MDIX when autoneg is disabled */
6001 bnx2x_cl45_write(bp, phy,
6002 MDIO_AN_DEVAD, MDIO_AN_REG_8481_AUX_CTRL,
6003 (1<<15 | 1<<9 | 7<<0));
6004 DP(NETIF_MSG_LINK, "Setting 10M force\n");
6005 }
6006
6007 bnx2x_cl45_write(bp, phy,
6008 MDIO_AN_DEVAD, MDIO_AN_REG_8481_LEGACY_AN_ADV,
6009 an_10_100_val);
6010
6011 if (phy->req_duplex == DUPLEX_FULL)
6012 autoneg_val |= (1<<8);
6013
6014 bnx2x_cl45_write(bp, phy,
6015 MDIO_AN_DEVAD,
6016 MDIO_AN_REG_8481_LEGACY_MII_CTRL, autoneg_val);
6017
6018 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
6019 (phy->speed_cap_mask &
6020 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) ||
6021 (phy->req_line_speed == SPEED_10000)) {
6022 DP(NETIF_MSG_LINK, "Advertising 10G\n");
6023 /* Restart autoneg for 10G*/
6024
6025 bnx2x_cl45_write(bp, phy,
6026 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL,
6027 0x3200);
6028 } else if (phy->req_line_speed != SPEED_10 &&
6029 phy->req_line_speed != SPEED_100) {
6030 bnx2x_cl45_write(bp, phy,
6031 MDIO_AN_DEVAD,
6032 MDIO_AN_REG_8481_10GBASE_T_AN_CTRL,
6033 1);
6034 }
6035 /* Save spirom version */
6036 bnx2x_save_848xx_spirom_version(phy, params);
6037
6038 return 0;
6039}
6040
6041static u8 bnx2x_8481_config_init(struct bnx2x_phy *phy,
6042 struct link_params *params,
6043 struct link_vars *vars)
6044{
6045 struct bnx2x *bp = params->bp;
6046 /* Restore normal power mode*/
6047 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006048 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006049
6050 /* HW reset */
6051 bnx2x_ext_phy_hw_reset(bp, params->port);
Yaniv Rosner9bffeac2010-11-01 05:32:27 +00006052 bnx2x_wait_reset_complete(bp, phy);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006053
6054 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
6055 return bnx2x_848xx_cmn_config_init(phy, params, vars);
6056}
6057
6058static u8 bnx2x_848x3_config_init(struct bnx2x_phy *phy,
6059 struct link_params *params,
6060 struct link_vars *vars)
6061{
6062 struct bnx2x *bp = params->bp;
Yaniv Rosner6a71bbe2010-11-01 05:32:31 +00006063 u8 port, initialize = 1;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006064 u16 val;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006065 u16 temp;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006066 u32 actual_phy_selection;
6067 u8 rc = 0;
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006068
6069 /* This is just for MDIO_CTL_REG_84823_MEDIA register. */
6070
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006071 msleep(1);
Yaniv Rosner6a71bbe2010-11-01 05:32:31 +00006072 if (CHIP_IS_E2(bp))
6073 port = BP_PATH(bp);
6074 else
6075 port = params->port;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006076 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
6077 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006078 port);
Yaniv Rosner9bffeac2010-11-01 05:32:27 +00006079 bnx2x_wait_reset_complete(bp, phy);
6080 /* Wait for GPHY to come out of reset */
6081 msleep(50);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006082 /* BCM84823 requires that XGXS links up first @ 10G for normal
6083 behavior */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006084 temp = vars->line_speed;
6085 vars->line_speed = SPEED_10000;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006086 bnx2x_set_autoneg(&params->phy[INT_PHY], params, vars, 0);
6087 bnx2x_program_serdes(&params->phy[INT_PHY], params, vars);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006088 vars->line_speed = temp;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006089
6090 /* Set dual-media configuration according to configuration */
6091
6092 bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
6093 MDIO_CTL_REG_84823_MEDIA, &val);
6094 val &= ~(MDIO_CTL_REG_84823_MEDIA_MAC_MASK |
6095 MDIO_CTL_REG_84823_MEDIA_LINE_MASK |
6096 MDIO_CTL_REG_84823_MEDIA_COPPER_CORE_DOWN |
6097 MDIO_CTL_REG_84823_MEDIA_PRIORITY_MASK |
6098 MDIO_CTL_REG_84823_MEDIA_FIBER_1G);
6099 val |= MDIO_CTL_REG_84823_CTRL_MAC_XFI |
6100 MDIO_CTL_REG_84823_MEDIA_LINE_XAUI_L;
6101
6102 actual_phy_selection = bnx2x_phy_selection(params);
6103
6104 switch (actual_phy_selection) {
6105 case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT:
6106 /* Do nothing. Essentialy this is like the priority copper */
6107 break;
6108 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
6109 val |= MDIO_CTL_REG_84823_MEDIA_PRIORITY_COPPER;
6110 break;
6111 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
6112 val |= MDIO_CTL_REG_84823_MEDIA_PRIORITY_FIBER;
6113 break;
6114 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY:
6115 /* Do nothing here. The first PHY won't be initialized at all */
6116 break;
6117 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY:
6118 val |= MDIO_CTL_REG_84823_MEDIA_COPPER_CORE_DOWN;
6119 initialize = 0;
6120 break;
6121 }
6122 if (params->phy[EXT_PHY2].req_line_speed == SPEED_1000)
6123 val |= MDIO_CTL_REG_84823_MEDIA_FIBER_1G;
6124
6125 bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
6126 MDIO_CTL_REG_84823_MEDIA, val);
6127 DP(NETIF_MSG_LINK, "Multi_phy config = 0x%x, Media control = 0x%x\n",
6128 params->multi_phy_config, val);
6129
6130 if (initialize)
6131 rc = bnx2x_848xx_cmn_config_init(phy, params, vars);
6132 else
6133 bnx2x_save_848xx_spirom_version(phy, params);
6134 return rc;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006135}
6136
6137static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006138 struct link_params *params,
6139 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006140{
6141 struct bnx2x *bp = params->bp;
6142 u16 val, val1, val2;
6143 u8 link_up = 0;
6144
6145 /* Check 10G-BaseT link status */
6146 /* Check PMD signal ok */
6147 bnx2x_cl45_read(bp, phy,
6148 MDIO_AN_DEVAD, 0xFFFA, &val1);
6149 bnx2x_cl45_read(bp, phy,
6150 MDIO_PMA_DEVAD, MDIO_PMA_REG_8481_PMD_SIGNAL,
6151 &val2);
6152 DP(NETIF_MSG_LINK, "BCM848xx: PMD_SIGNAL 1.a811 = 0x%x\n", val2);
6153
6154 /* Check link 10G */
6155 if (val2 & (1<<11)) {
6156 vars->line_speed = SPEED_10000;
Yaniv Rosner791f18c2011-01-18 04:33:42 +00006157 vars->duplex = DUPLEX_FULL;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006158 link_up = 1;
6159 bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
6160 } else { /* Check Legacy speed link */
6161 u16 legacy_status, legacy_speed;
6162
6163 /* Enable expansion register 0x42 (Operation mode status) */
6164 bnx2x_cl45_write(bp, phy,
6165 MDIO_AN_DEVAD,
6166 MDIO_AN_REG_8481_EXPANSION_REG_ACCESS, 0xf42);
6167
6168 /* Get legacy speed operation status */
6169 bnx2x_cl45_read(bp, phy,
6170 MDIO_AN_DEVAD,
6171 MDIO_AN_REG_8481_EXPANSION_REG_RD_RW,
6172 &legacy_status);
6173
6174 DP(NETIF_MSG_LINK, "Legacy speed status"
6175 " = 0x%x\n", legacy_status);
6176 link_up = ((legacy_status & (1<<11)) == (1<<11));
6177 if (link_up) {
6178 legacy_speed = (legacy_status & (3<<9));
6179 if (legacy_speed == (0<<9))
6180 vars->line_speed = SPEED_10;
6181 else if (legacy_speed == (1<<9))
6182 vars->line_speed = SPEED_100;
6183 else if (legacy_speed == (2<<9))
6184 vars->line_speed = SPEED_1000;
6185 else /* Should not happen */
6186 vars->line_speed = 0;
6187
6188 if (legacy_status & (1<<8))
6189 vars->duplex = DUPLEX_FULL;
6190 else
6191 vars->duplex = DUPLEX_HALF;
6192
6193 DP(NETIF_MSG_LINK, "Link is up in %dMbps,"
6194 " is_duplex_full= %d\n", vars->line_speed,
6195 (vars->duplex == DUPLEX_FULL));
6196 /* Check legacy speed AN resolution */
6197 bnx2x_cl45_read(bp, phy,
6198 MDIO_AN_DEVAD,
6199 MDIO_AN_REG_8481_LEGACY_MII_STATUS,
6200 &val);
6201 if (val & (1<<5))
6202 vars->link_status |=
6203 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
6204 bnx2x_cl45_read(bp, phy,
6205 MDIO_AN_DEVAD,
6206 MDIO_AN_REG_8481_LEGACY_AN_EXPANSION,
6207 &val);
6208 if ((val & (1<<0)) == 0)
6209 vars->link_status |=
6210 LINK_STATUS_PARALLEL_DETECTION_USED;
6211 }
6212 }
6213 if (link_up) {
6214 DP(NETIF_MSG_LINK, "BCM84823: link speed is %d\n",
6215 vars->line_speed);
6216 bnx2x_ext_phy_resolve_fc(phy, params, vars);
6217 }
6218
6219 return link_up;
6220}
6221
6222static u8 bnx2x_848xx_format_ver(u32 raw_ver, u8 *str, u16 *len)
6223{
6224 u8 status = 0;
6225 u32 spirom_ver;
6226 spirom_ver = ((raw_ver & 0xF80) >> 7) << 16 | (raw_ver & 0x7F);
6227 status = bnx2x_format_ver(spirom_ver, str, len);
6228 return status;
6229}
6230
6231static void bnx2x_8481_hw_reset(struct bnx2x_phy *phy,
6232 struct link_params *params)
6233{
6234 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006235 MISC_REGISTERS_GPIO_OUTPUT_LOW, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006236 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006237 MISC_REGISTERS_GPIO_OUTPUT_LOW, 1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006238}
6239
6240static void bnx2x_8481_link_reset(struct bnx2x_phy *phy,
6241 struct link_params *params)
6242{
6243 bnx2x_cl45_write(params->bp, phy,
6244 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x0000);
6245 bnx2x_cl45_write(params->bp, phy,
6246 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1);
6247}
6248
6249static void bnx2x_848x3_link_reset(struct bnx2x_phy *phy,
6250 struct link_params *params)
6251{
6252 struct bnx2x *bp = params->bp;
Yaniv Rosner6a71bbe2010-11-01 05:32:31 +00006253 u8 port;
6254 if (CHIP_IS_E2(bp))
6255 port = BP_PATH(bp);
6256 else
6257 port = params->port;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006258 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006259 MISC_REGISTERS_GPIO_OUTPUT_LOW,
6260 port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006261}
6262
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006263static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy,
6264 struct link_params *params, u8 mode)
6265{
6266 struct bnx2x *bp = params->bp;
6267 u16 val;
6268
6269 switch (mode) {
6270 case LED_MODE_OFF:
6271
6272 DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE OFF\n", params->port);
6273
6274 if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
6275 SHARED_HW_CFG_LED_EXTPHY1) {
6276
6277 /* Set LED masks */
6278 bnx2x_cl45_write(bp, phy,
6279 MDIO_PMA_DEVAD,
6280 MDIO_PMA_REG_8481_LED1_MASK,
6281 0x0);
6282
6283 bnx2x_cl45_write(bp, phy,
6284 MDIO_PMA_DEVAD,
6285 MDIO_PMA_REG_8481_LED2_MASK,
6286 0x0);
6287
6288 bnx2x_cl45_write(bp, phy,
6289 MDIO_PMA_DEVAD,
6290 MDIO_PMA_REG_8481_LED3_MASK,
6291 0x0);
6292
6293 bnx2x_cl45_write(bp, phy,
6294 MDIO_PMA_DEVAD,
6295 MDIO_PMA_REG_8481_LED5_MASK,
6296 0x0);
6297
6298 } else {
6299 bnx2x_cl45_write(bp, phy,
6300 MDIO_PMA_DEVAD,
6301 MDIO_PMA_REG_8481_LED1_MASK,
6302 0x0);
6303 }
6304 break;
6305 case LED_MODE_FRONT_PANEL_OFF:
6306
6307 DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE FRONT PANEL OFF\n",
6308 params->port);
6309
6310 if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
6311 SHARED_HW_CFG_LED_EXTPHY1) {
6312
6313 /* Set LED masks */
6314 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006315 MDIO_PMA_DEVAD,
6316 MDIO_PMA_REG_8481_LED1_MASK,
6317 0x0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006318
6319 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006320 MDIO_PMA_DEVAD,
6321 MDIO_PMA_REG_8481_LED2_MASK,
6322 0x0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006323
6324 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006325 MDIO_PMA_DEVAD,
6326 MDIO_PMA_REG_8481_LED3_MASK,
6327 0x0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006328
6329 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006330 MDIO_PMA_DEVAD,
6331 MDIO_PMA_REG_8481_LED5_MASK,
6332 0x20);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006333
6334 } else {
6335 bnx2x_cl45_write(bp, phy,
6336 MDIO_PMA_DEVAD,
6337 MDIO_PMA_REG_8481_LED1_MASK,
6338 0x0);
6339 }
6340 break;
6341 case LED_MODE_ON:
6342
6343 DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE ON\n", params->port);
6344
6345 if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
6346 SHARED_HW_CFG_LED_EXTPHY1) {
6347 /* Set control reg */
6348 bnx2x_cl45_read(bp, phy,
6349 MDIO_PMA_DEVAD,
6350 MDIO_PMA_REG_8481_LINK_SIGNAL,
6351 &val);
6352 val &= 0x8000;
6353 val |= 0x2492;
6354
6355 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006356 MDIO_PMA_DEVAD,
6357 MDIO_PMA_REG_8481_LINK_SIGNAL,
6358 val);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006359
6360 /* Set LED masks */
6361 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006362 MDIO_PMA_DEVAD,
6363 MDIO_PMA_REG_8481_LED1_MASK,
6364 0x0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006365
6366 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006367 MDIO_PMA_DEVAD,
6368 MDIO_PMA_REG_8481_LED2_MASK,
6369 0x20);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006370
6371 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006372 MDIO_PMA_DEVAD,
6373 MDIO_PMA_REG_8481_LED3_MASK,
6374 0x20);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006375
6376 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006377 MDIO_PMA_DEVAD,
6378 MDIO_PMA_REG_8481_LED5_MASK,
6379 0x0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006380 } else {
6381 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006382 MDIO_PMA_DEVAD,
6383 MDIO_PMA_REG_8481_LED1_MASK,
6384 0x20);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006385 }
6386 break;
6387
6388 case LED_MODE_OPER:
6389
6390 DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE OPER\n", params->port);
6391
6392 if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
6393 SHARED_HW_CFG_LED_EXTPHY1) {
6394
6395 /* Set control reg */
6396 bnx2x_cl45_read(bp, phy,
6397 MDIO_PMA_DEVAD,
6398 MDIO_PMA_REG_8481_LINK_SIGNAL,
6399 &val);
6400
6401 if (!((val &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006402 MDIO_PMA_REG_8481_LINK_SIGNAL_LED4_ENABLE_MASK)
6403 >> MDIO_PMA_REG_8481_LINK_SIGNAL_LED4_ENABLE_SHIFT)) {
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006404 DP(NETIF_MSG_LINK, "Seting LINK_SIGNAL\n");
6405 bnx2x_cl45_write(bp, phy,
6406 MDIO_PMA_DEVAD,
6407 MDIO_PMA_REG_8481_LINK_SIGNAL,
6408 0xa492);
6409 }
6410
6411 /* Set LED masks */
6412 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006413 MDIO_PMA_DEVAD,
6414 MDIO_PMA_REG_8481_LED1_MASK,
6415 0x10);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006416
6417 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006418 MDIO_PMA_DEVAD,
6419 MDIO_PMA_REG_8481_LED2_MASK,
6420 0x80);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006421
6422 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006423 MDIO_PMA_DEVAD,
6424 MDIO_PMA_REG_8481_LED3_MASK,
6425 0x98);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006426
6427 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006428 MDIO_PMA_DEVAD,
6429 MDIO_PMA_REG_8481_LED5_MASK,
6430 0x40);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006431
6432 } else {
6433 bnx2x_cl45_write(bp, phy,
6434 MDIO_PMA_DEVAD,
6435 MDIO_PMA_REG_8481_LED1_MASK,
6436 0x80);
Yaniv Rosner53eda062011-01-30 04:14:55 +00006437
6438 /* Tell LED3 to blink on source */
6439 bnx2x_cl45_read(bp, phy,
6440 MDIO_PMA_DEVAD,
6441 MDIO_PMA_REG_8481_LINK_SIGNAL,
6442 &val);
6443 val &= ~(7<<6);
6444 val |= (1<<6); /* A83B[8:6]= 1 */
6445 bnx2x_cl45_write(bp, phy,
6446 MDIO_PMA_DEVAD,
6447 MDIO_PMA_REG_8481_LINK_SIGNAL,
6448 val);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006449 }
6450 break;
6451 }
6452}
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006453/******************************************************************/
6454/* SFX7101 PHY SECTION */
6455/******************************************************************/
6456static void bnx2x_7101_config_loopback(struct bnx2x_phy *phy,
6457 struct link_params *params)
6458{
6459 struct bnx2x *bp = params->bp;
6460 /* SFX7101_XGXS_TEST1 */
6461 bnx2x_cl45_write(bp, phy,
6462 MDIO_XS_DEVAD, MDIO_XS_SFX7101_XGXS_TEST1, 0x100);
6463}
6464
6465static u8 bnx2x_7101_config_init(struct bnx2x_phy *phy,
6466 struct link_params *params,
6467 struct link_vars *vars)
6468{
6469 u16 fw_ver1, fw_ver2, val;
6470 struct bnx2x *bp = params->bp;
6471 DP(NETIF_MSG_LINK, "Setting the SFX7101 LASI indication\n");
6472
6473 /* Restore normal power mode*/
6474 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006475 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006476 /* HW reset */
6477 bnx2x_ext_phy_hw_reset(bp, params->port);
6478 bnx2x_wait_reset_complete(bp, phy);
6479
6480 bnx2x_cl45_write(bp, phy,
6481 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x1);
6482 DP(NETIF_MSG_LINK, "Setting the SFX7101 LED to blink on traffic\n");
6483 bnx2x_cl45_write(bp, phy,
6484 MDIO_PMA_DEVAD, MDIO_PMA_REG_7107_LED_CNTL, (1<<3));
6485
6486 bnx2x_ext_phy_set_pause(params, phy, vars);
6487 /* Restart autoneg */
6488 bnx2x_cl45_read(bp, phy,
6489 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, &val);
6490 val |= 0x200;
6491 bnx2x_cl45_write(bp, phy,
6492 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, val);
6493
6494 /* Save spirom version */
6495 bnx2x_cl45_read(bp, phy,
6496 MDIO_PMA_DEVAD, MDIO_PMA_REG_7101_VER1, &fw_ver1);
6497
6498 bnx2x_cl45_read(bp, phy,
6499 MDIO_PMA_DEVAD, MDIO_PMA_REG_7101_VER2, &fw_ver2);
6500 bnx2x_save_spirom_version(bp, params->port,
6501 (u32)(fw_ver1<<16 | fw_ver2), phy->ver_addr);
6502 return 0;
6503}
6504
6505static u8 bnx2x_7101_read_status(struct bnx2x_phy *phy,
6506 struct link_params *params,
6507 struct link_vars *vars)
6508{
6509 struct bnx2x *bp = params->bp;
6510 u8 link_up;
6511 u16 val1, val2;
6512 bnx2x_cl45_read(bp, phy,
6513 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val2);
6514 bnx2x_cl45_read(bp, phy,
6515 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
6516 DP(NETIF_MSG_LINK, "10G-base-T LASI status 0x%x->0x%x\n",
6517 val2, val1);
6518 bnx2x_cl45_read(bp, phy,
6519 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
6520 bnx2x_cl45_read(bp, phy,
6521 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
6522 DP(NETIF_MSG_LINK, "10G-base-T PMA status 0x%x->0x%x\n",
6523 val2, val1);
6524 link_up = ((val1 & 4) == 4);
6525 /* if link is up
6526 * print the AN outcome of the SFX7101 PHY
6527 */
6528 if (link_up) {
6529 bnx2x_cl45_read(bp, phy,
6530 MDIO_AN_DEVAD, MDIO_AN_REG_MASTER_STATUS,
6531 &val2);
6532 vars->line_speed = SPEED_10000;
Yaniv Rosner791f18c2011-01-18 04:33:42 +00006533 vars->duplex = DUPLEX_FULL;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006534 DP(NETIF_MSG_LINK, "SFX7101 AN status 0x%x->Master=%x\n",
6535 val2, (val2 & (1<<14)));
6536 bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
6537 bnx2x_ext_phy_resolve_fc(phy, params, vars);
6538 }
6539 return link_up;
6540}
6541
6542
6543static u8 bnx2x_7101_format_ver(u32 spirom_ver, u8 *str, u16 *len)
6544{
6545 if (*len < 5)
6546 return -EINVAL;
6547 str[0] = (spirom_ver & 0xFF);
6548 str[1] = (spirom_ver & 0xFF00) >> 8;
6549 str[2] = (spirom_ver & 0xFF0000) >> 16;
6550 str[3] = (spirom_ver & 0xFF000000) >> 24;
6551 str[4] = '\0';
6552 *len -= 5;
6553 return 0;
6554}
6555
6556void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, struct bnx2x_phy *phy)
6557{
6558 u16 val, cnt;
6559
6560 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006561 MDIO_PMA_DEVAD,
6562 MDIO_PMA_REG_7101_RESET, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006563
6564 for (cnt = 0; cnt < 10; cnt++) {
6565 msleep(50);
6566 /* Writes a self-clearing reset */
6567 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006568 MDIO_PMA_DEVAD,
6569 MDIO_PMA_REG_7101_RESET,
6570 (val | (1<<15)));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006571 /* Wait for clear */
6572 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006573 MDIO_PMA_DEVAD,
6574 MDIO_PMA_REG_7101_RESET, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006575
6576 if ((val & (1<<15)) == 0)
6577 break;
6578 }
6579}
6580
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006581static void bnx2x_7101_hw_reset(struct bnx2x_phy *phy,
6582 struct link_params *params) {
6583 /* Low power mode is controlled by GPIO 2 */
6584 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006585 MISC_REGISTERS_GPIO_OUTPUT_LOW, params->port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006586 /* The PHY reset is controlled by GPIO 1 */
6587 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006588 MISC_REGISTERS_GPIO_OUTPUT_LOW, params->port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006589}
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006590
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006591static void bnx2x_7101_set_link_led(struct bnx2x_phy *phy,
6592 struct link_params *params, u8 mode)
6593{
6594 u16 val = 0;
6595 struct bnx2x *bp = params->bp;
6596 switch (mode) {
6597 case LED_MODE_FRONT_PANEL_OFF:
6598 case LED_MODE_OFF:
6599 val = 2;
6600 break;
6601 case LED_MODE_ON:
6602 val = 1;
6603 break;
6604 case LED_MODE_OPER:
6605 val = 0;
6606 break;
6607 }
6608 bnx2x_cl45_write(bp, phy,
6609 MDIO_PMA_DEVAD,
6610 MDIO_PMA_REG_7107_LINK_LED_CNTL,
6611 val);
6612}
6613
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006614/******************************************************************/
6615/* STATIC PHY DECLARATION */
6616/******************************************************************/
6617
6618static struct bnx2x_phy phy_null = {
6619 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN,
6620 .addr = 0,
6621 .flags = FLAGS_INIT_XGXS_FIRST,
6622 .def_md_devad = 0,
6623 .reserved = 0,
6624 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6625 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6626 .mdio_ctrl = 0,
6627 .supported = 0,
6628 .media_type = ETH_PHY_NOT_PRESENT,
6629 .ver_addr = 0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006630 .req_flow_ctrl = 0,
6631 .req_line_speed = 0,
6632 .speed_cap_mask = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006633 .req_duplex = 0,
6634 .rsrv = 0,
6635 .config_init = (config_init_t)NULL,
6636 .read_status = (read_status_t)NULL,
6637 .link_reset = (link_reset_t)NULL,
6638 .config_loopback = (config_loopback_t)NULL,
6639 .format_fw_ver = (format_fw_ver_t)NULL,
6640 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006641 .set_link_led = (set_link_led_t)NULL,
6642 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006643};
6644
6645static struct bnx2x_phy phy_serdes = {
6646 .type = PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT,
6647 .addr = 0xff,
6648 .flags = 0,
6649 .def_md_devad = 0,
6650 .reserved = 0,
6651 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6652 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6653 .mdio_ctrl = 0,
6654 .supported = (SUPPORTED_10baseT_Half |
6655 SUPPORTED_10baseT_Full |
6656 SUPPORTED_100baseT_Half |
6657 SUPPORTED_100baseT_Full |
6658 SUPPORTED_1000baseT_Full |
6659 SUPPORTED_2500baseX_Full |
6660 SUPPORTED_TP |
6661 SUPPORTED_Autoneg |
6662 SUPPORTED_Pause |
6663 SUPPORTED_Asym_Pause),
6664 .media_type = ETH_PHY_UNSPECIFIED,
6665 .ver_addr = 0,
6666 .req_flow_ctrl = 0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006667 .req_line_speed = 0,
6668 .speed_cap_mask = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006669 .req_duplex = 0,
6670 .rsrv = 0,
6671 .config_init = (config_init_t)bnx2x_init_serdes,
6672 .read_status = (read_status_t)bnx2x_link_settings_status,
6673 .link_reset = (link_reset_t)bnx2x_int_link_reset,
6674 .config_loopback = (config_loopback_t)NULL,
6675 .format_fw_ver = (format_fw_ver_t)NULL,
6676 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006677 .set_link_led = (set_link_led_t)NULL,
6678 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006679};
6680
6681static struct bnx2x_phy phy_xgxs = {
6682 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT,
6683 .addr = 0xff,
6684 .flags = 0,
6685 .def_md_devad = 0,
6686 .reserved = 0,
6687 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6688 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6689 .mdio_ctrl = 0,
6690 .supported = (SUPPORTED_10baseT_Half |
6691 SUPPORTED_10baseT_Full |
6692 SUPPORTED_100baseT_Half |
6693 SUPPORTED_100baseT_Full |
6694 SUPPORTED_1000baseT_Full |
6695 SUPPORTED_2500baseX_Full |
6696 SUPPORTED_10000baseT_Full |
6697 SUPPORTED_FIBRE |
6698 SUPPORTED_Autoneg |
6699 SUPPORTED_Pause |
6700 SUPPORTED_Asym_Pause),
6701 .media_type = ETH_PHY_UNSPECIFIED,
6702 .ver_addr = 0,
6703 .req_flow_ctrl = 0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006704 .req_line_speed = 0,
6705 .speed_cap_mask = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006706 .req_duplex = 0,
6707 .rsrv = 0,
6708 .config_init = (config_init_t)bnx2x_init_xgxs,
6709 .read_status = (read_status_t)bnx2x_link_settings_status,
6710 .link_reset = (link_reset_t)bnx2x_int_link_reset,
6711 .config_loopback = (config_loopback_t)bnx2x_set_xgxs_loopback,
6712 .format_fw_ver = (format_fw_ver_t)NULL,
6713 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006714 .set_link_led = (set_link_led_t)NULL,
6715 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006716};
6717
6718static struct bnx2x_phy phy_7101 = {
6719 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
6720 .addr = 0xff,
6721 .flags = FLAGS_FAN_FAILURE_DET_REQ,
6722 .def_md_devad = 0,
6723 .reserved = 0,
6724 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6725 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6726 .mdio_ctrl = 0,
6727 .supported = (SUPPORTED_10000baseT_Full |
6728 SUPPORTED_TP |
6729 SUPPORTED_Autoneg |
6730 SUPPORTED_Pause |
6731 SUPPORTED_Asym_Pause),
6732 .media_type = ETH_PHY_BASE_T,
6733 .ver_addr = 0,
6734 .req_flow_ctrl = 0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006735 .req_line_speed = 0,
6736 .speed_cap_mask = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006737 .req_duplex = 0,
6738 .rsrv = 0,
6739 .config_init = (config_init_t)bnx2x_7101_config_init,
6740 .read_status = (read_status_t)bnx2x_7101_read_status,
6741 .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
6742 .config_loopback = (config_loopback_t)bnx2x_7101_config_loopback,
6743 .format_fw_ver = (format_fw_ver_t)bnx2x_7101_format_ver,
6744 .hw_reset = (hw_reset_t)bnx2x_7101_hw_reset,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006745 .set_link_led = (set_link_led_t)bnx2x_7101_set_link_led,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006746 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006747};
6748static struct bnx2x_phy phy_8073 = {
6749 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
6750 .addr = 0xff,
6751 .flags = FLAGS_HW_LOCK_REQUIRED,
6752 .def_md_devad = 0,
6753 .reserved = 0,
6754 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6755 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6756 .mdio_ctrl = 0,
6757 .supported = (SUPPORTED_10000baseT_Full |
6758 SUPPORTED_2500baseX_Full |
6759 SUPPORTED_1000baseT_Full |
6760 SUPPORTED_FIBRE |
6761 SUPPORTED_Autoneg |
6762 SUPPORTED_Pause |
6763 SUPPORTED_Asym_Pause),
6764 .media_type = ETH_PHY_UNSPECIFIED,
6765 .ver_addr = 0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006766 .req_flow_ctrl = 0,
6767 .req_line_speed = 0,
6768 .speed_cap_mask = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006769 .req_duplex = 0,
6770 .rsrv = 0,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00006771 .config_init = (config_init_t)bnx2x_8073_config_init,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006772 .read_status = (read_status_t)bnx2x_8073_read_status,
6773 .link_reset = (link_reset_t)bnx2x_8073_link_reset,
6774 .config_loopback = (config_loopback_t)NULL,
6775 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
6776 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006777 .set_link_led = (set_link_led_t)NULL,
6778 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006779};
6780static struct bnx2x_phy phy_8705 = {
6781 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705,
6782 .addr = 0xff,
6783 .flags = FLAGS_INIT_XGXS_FIRST,
6784 .def_md_devad = 0,
6785 .reserved = 0,
6786 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6787 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6788 .mdio_ctrl = 0,
6789 .supported = (SUPPORTED_10000baseT_Full |
6790 SUPPORTED_FIBRE |
6791 SUPPORTED_Pause |
6792 SUPPORTED_Asym_Pause),
6793 .media_type = ETH_PHY_XFP_FIBER,
6794 .ver_addr = 0,
6795 .req_flow_ctrl = 0,
6796 .req_line_speed = 0,
6797 .speed_cap_mask = 0,
6798 .req_duplex = 0,
6799 .rsrv = 0,
6800 .config_init = (config_init_t)bnx2x_8705_config_init,
6801 .read_status = (read_status_t)bnx2x_8705_read_status,
6802 .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
6803 .config_loopback = (config_loopback_t)NULL,
6804 .format_fw_ver = (format_fw_ver_t)bnx2x_null_format_ver,
6805 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006806 .set_link_led = (set_link_led_t)NULL,
6807 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006808};
6809static struct bnx2x_phy phy_8706 = {
6810 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706,
6811 .addr = 0xff,
6812 .flags = FLAGS_INIT_XGXS_FIRST,
6813 .def_md_devad = 0,
6814 .reserved = 0,
6815 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6816 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6817 .mdio_ctrl = 0,
6818 .supported = (SUPPORTED_10000baseT_Full |
6819 SUPPORTED_1000baseT_Full |
6820 SUPPORTED_FIBRE |
6821 SUPPORTED_Pause |
6822 SUPPORTED_Asym_Pause),
6823 .media_type = ETH_PHY_SFP_FIBER,
6824 .ver_addr = 0,
6825 .req_flow_ctrl = 0,
6826 .req_line_speed = 0,
6827 .speed_cap_mask = 0,
6828 .req_duplex = 0,
6829 .rsrv = 0,
6830 .config_init = (config_init_t)bnx2x_8706_config_init,
6831 .read_status = (read_status_t)bnx2x_8706_read_status,
6832 .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
6833 .config_loopback = (config_loopback_t)NULL,
6834 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
6835 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006836 .set_link_led = (set_link_led_t)NULL,
6837 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006838};
6839
6840static struct bnx2x_phy phy_8726 = {
6841 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
6842 .addr = 0xff,
6843 .flags = (FLAGS_HW_LOCK_REQUIRED |
6844 FLAGS_INIT_XGXS_FIRST),
6845 .def_md_devad = 0,
6846 .reserved = 0,
6847 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6848 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6849 .mdio_ctrl = 0,
6850 .supported = (SUPPORTED_10000baseT_Full |
6851 SUPPORTED_1000baseT_Full |
6852 SUPPORTED_Autoneg |
6853 SUPPORTED_FIBRE |
6854 SUPPORTED_Pause |
6855 SUPPORTED_Asym_Pause),
6856 .media_type = ETH_PHY_SFP_FIBER,
6857 .ver_addr = 0,
6858 .req_flow_ctrl = 0,
6859 .req_line_speed = 0,
6860 .speed_cap_mask = 0,
6861 .req_duplex = 0,
6862 .rsrv = 0,
6863 .config_init = (config_init_t)bnx2x_8726_config_init,
6864 .read_status = (read_status_t)bnx2x_8726_read_status,
6865 .link_reset = (link_reset_t)bnx2x_8726_link_reset,
6866 .config_loopback = (config_loopback_t)bnx2x_8726_config_loopback,
6867 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
6868 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006869 .set_link_led = (set_link_led_t)NULL,
6870 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006871};
6872
6873static struct bnx2x_phy phy_8727 = {
6874 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
6875 .addr = 0xff,
6876 .flags = FLAGS_FAN_FAILURE_DET_REQ,
6877 .def_md_devad = 0,
6878 .reserved = 0,
6879 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6880 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6881 .mdio_ctrl = 0,
6882 .supported = (SUPPORTED_10000baseT_Full |
6883 SUPPORTED_1000baseT_Full |
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006884 SUPPORTED_FIBRE |
6885 SUPPORTED_Pause |
6886 SUPPORTED_Asym_Pause),
6887 .media_type = ETH_PHY_SFP_FIBER,
6888 .ver_addr = 0,
6889 .req_flow_ctrl = 0,
6890 .req_line_speed = 0,
6891 .speed_cap_mask = 0,
6892 .req_duplex = 0,
6893 .rsrv = 0,
6894 .config_init = (config_init_t)bnx2x_8727_config_init,
6895 .read_status = (read_status_t)bnx2x_8727_read_status,
6896 .link_reset = (link_reset_t)bnx2x_8727_link_reset,
6897 .config_loopback = (config_loopback_t)NULL,
6898 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
6899 .hw_reset = (hw_reset_t)bnx2x_8727_hw_reset,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006900 .set_link_led = (set_link_led_t)bnx2x_8727_set_link_led,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006901 .phy_specific_func = (phy_specific_func_t)bnx2x_8727_specific_func
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006902};
6903static struct bnx2x_phy phy_8481 = {
6904 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
6905 .addr = 0xff,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006906 .flags = FLAGS_FAN_FAILURE_DET_REQ |
6907 FLAGS_REARM_LATCH_SIGNAL,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006908 .def_md_devad = 0,
6909 .reserved = 0,
6910 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6911 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6912 .mdio_ctrl = 0,
6913 .supported = (SUPPORTED_10baseT_Half |
6914 SUPPORTED_10baseT_Full |
6915 SUPPORTED_100baseT_Half |
6916 SUPPORTED_100baseT_Full |
6917 SUPPORTED_1000baseT_Full |
6918 SUPPORTED_10000baseT_Full |
6919 SUPPORTED_TP |
6920 SUPPORTED_Autoneg |
6921 SUPPORTED_Pause |
6922 SUPPORTED_Asym_Pause),
6923 .media_type = ETH_PHY_BASE_T,
6924 .ver_addr = 0,
6925 .req_flow_ctrl = 0,
6926 .req_line_speed = 0,
6927 .speed_cap_mask = 0,
6928 .req_duplex = 0,
6929 .rsrv = 0,
6930 .config_init = (config_init_t)bnx2x_8481_config_init,
6931 .read_status = (read_status_t)bnx2x_848xx_read_status,
6932 .link_reset = (link_reset_t)bnx2x_8481_link_reset,
6933 .config_loopback = (config_loopback_t)NULL,
6934 .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver,
6935 .hw_reset = (hw_reset_t)bnx2x_8481_hw_reset,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006936 .set_link_led = (set_link_led_t)bnx2x_848xx_set_link_led,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006937 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006938};
6939
6940static struct bnx2x_phy phy_84823 = {
6941 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823,
6942 .addr = 0xff,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006943 .flags = FLAGS_FAN_FAILURE_DET_REQ |
6944 FLAGS_REARM_LATCH_SIGNAL,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006945 .def_md_devad = 0,
6946 .reserved = 0,
6947 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6948 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6949 .mdio_ctrl = 0,
6950 .supported = (SUPPORTED_10baseT_Half |
6951 SUPPORTED_10baseT_Full |
6952 SUPPORTED_100baseT_Half |
6953 SUPPORTED_100baseT_Full |
6954 SUPPORTED_1000baseT_Full |
6955 SUPPORTED_10000baseT_Full |
6956 SUPPORTED_TP |
6957 SUPPORTED_Autoneg |
6958 SUPPORTED_Pause |
6959 SUPPORTED_Asym_Pause),
6960 .media_type = ETH_PHY_BASE_T,
6961 .ver_addr = 0,
6962 .req_flow_ctrl = 0,
6963 .req_line_speed = 0,
6964 .speed_cap_mask = 0,
6965 .req_duplex = 0,
6966 .rsrv = 0,
6967 .config_init = (config_init_t)bnx2x_848x3_config_init,
6968 .read_status = (read_status_t)bnx2x_848xx_read_status,
6969 .link_reset = (link_reset_t)bnx2x_848x3_link_reset,
6970 .config_loopback = (config_loopback_t)NULL,
6971 .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver,
6972 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006973 .set_link_led = (set_link_led_t)bnx2x_848xx_set_link_led,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006974 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006975};
6976
6977/*****************************************************************/
6978/* */
6979/* Populate the phy according. Main function: bnx2x_populate_phy */
6980/* */
6981/*****************************************************************/
6982
6983static void bnx2x_populate_preemphasis(struct bnx2x *bp, u32 shmem_base,
6984 struct bnx2x_phy *phy, u8 port,
6985 u8 phy_index)
6986{
6987 /* Get the 4 lanes xgxs config rx and tx */
6988 u32 rx = 0, tx = 0, i;
6989 for (i = 0; i < 2; i++) {
6990 /**
6991 * INT_PHY and EXT_PHY1 share the same value location in the
6992 * shmem. When num_phys is greater than 1, than this value
6993 * applies only to EXT_PHY1
6994 */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006995 if (phy_index == INT_PHY || phy_index == EXT_PHY1) {
6996 rx = REG_RD(bp, shmem_base +
6997 offsetof(struct shmem_region,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006998 dev_info.port_hw_config[port].xgxs_config_rx[i<<1]));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006999
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007000 tx = REG_RD(bp, shmem_base +
7001 offsetof(struct shmem_region,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007002 dev_info.port_hw_config[port].xgxs_config_tx[i<<1]));
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007003 } else {
7004 rx = REG_RD(bp, shmem_base +
7005 offsetof(struct shmem_region,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007006 dev_info.port_hw_config[port].xgxs_config2_rx[i<<1]));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007007
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007008 tx = REG_RD(bp, shmem_base +
7009 offsetof(struct shmem_region,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007010 dev_info.port_hw_config[port].xgxs_config2_rx[i<<1]));
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007011 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007012
7013 phy->rx_preemphasis[i << 1] = ((rx>>16) & 0xffff);
7014 phy->rx_preemphasis[(i << 1) + 1] = (rx & 0xffff);
7015
7016 phy->tx_preemphasis[i << 1] = ((tx>>16) & 0xffff);
7017 phy->tx_preemphasis[(i << 1) + 1] = (tx & 0xffff);
7018 }
7019}
7020
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007021static u32 bnx2x_get_ext_phy_config(struct bnx2x *bp, u32 shmem_base,
7022 u8 phy_index, u8 port)
7023{
7024 u32 ext_phy_config = 0;
7025 switch (phy_index) {
7026 case EXT_PHY1:
7027 ext_phy_config = REG_RD(bp, shmem_base +
7028 offsetof(struct shmem_region,
7029 dev_info.port_hw_config[port].external_phy_config));
7030 break;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007031 case EXT_PHY2:
7032 ext_phy_config = REG_RD(bp, shmem_base +
7033 offsetof(struct shmem_region,
7034 dev_info.port_hw_config[port].external_phy_config2));
7035 break;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007036 default:
7037 DP(NETIF_MSG_LINK, "Invalid phy_index %d\n", phy_index);
7038 return -EINVAL;
7039 }
7040
7041 return ext_phy_config;
7042}
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007043static u8 bnx2x_populate_int_phy(struct bnx2x *bp, u32 shmem_base, u8 port,
7044 struct bnx2x_phy *phy)
7045{
7046 u32 phy_addr;
7047 u32 chip_id;
7048 u32 switch_cfg = (REG_RD(bp, shmem_base +
7049 offsetof(struct shmem_region,
7050 dev_info.port_feature_config[port].link_config)) &
7051 PORT_FEATURE_CONNECTED_SWITCH_MASK);
7052 chip_id = REG_RD(bp, MISC_REG_CHIP_NUM) << 16;
7053 switch (switch_cfg) {
7054 case SWITCH_CFG_1G:
7055 phy_addr = REG_RD(bp,
7056 NIG_REG_SERDES0_CTRL_PHY_ADDR +
7057 port * 0x10);
7058 *phy = phy_serdes;
7059 break;
7060 case SWITCH_CFG_10G:
7061 phy_addr = REG_RD(bp,
7062 NIG_REG_XGXS0_CTRL_PHY_ADDR +
7063 port * 0x18);
7064 *phy = phy_xgxs;
7065 break;
7066 default:
7067 DP(NETIF_MSG_LINK, "Invalid switch_cfg\n");
7068 return -EINVAL;
7069 }
7070 phy->addr = (u8)phy_addr;
7071 phy->mdio_ctrl = bnx2x_get_emac_base(bp,
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007072 SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007073 port);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007074 if (CHIP_IS_E2(bp))
7075 phy->def_md_devad = E2_DEFAULT_PHY_DEV_ADDR;
7076 else
7077 phy->def_md_devad = DEFAULT_PHY_DEV_ADDR;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007078
7079 DP(NETIF_MSG_LINK, "Internal phy port=%d, addr=0x%x, mdio_ctl=0x%x\n",
7080 port, phy->addr, phy->mdio_ctrl);
7081
7082 bnx2x_populate_preemphasis(bp, shmem_base, phy, port, INT_PHY);
7083 return 0;
7084}
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007085
7086static u8 bnx2x_populate_ext_phy(struct bnx2x *bp,
7087 u8 phy_index,
7088 u32 shmem_base,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007089 u32 shmem2_base,
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007090 u8 port,
7091 struct bnx2x_phy *phy)
7092{
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007093 u32 ext_phy_config, phy_type, config2;
7094 u32 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007095 ext_phy_config = bnx2x_get_ext_phy_config(bp, shmem_base,
7096 phy_index, port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007097 phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
7098 /* Select the phy type */
7099 switch (phy_type) {
7100 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007101 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_SWAPPED;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007102 *phy = phy_8073;
7103 break;
7104 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
7105 *phy = phy_8705;
7106 break;
7107 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
7108 *phy = phy_8706;
7109 break;
7110 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007111 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007112 *phy = phy_8726;
7113 break;
7114 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
7115 /* BCM8727_NOC => BCM8727 no over current */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007116 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007117 *phy = phy_8727;
7118 phy->flags |= FLAGS_NOC;
7119 break;
7120 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007121 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007122 *phy = phy_8727;
7123 break;
7124 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
7125 *phy = phy_8481;
7126 break;
7127 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
7128 *phy = phy_84823;
7129 break;
7130 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
7131 *phy = phy_7101;
7132 break;
7133 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
7134 *phy = phy_null;
7135 return -EINVAL;
7136 default:
7137 *phy = phy_null;
7138 return 0;
7139 }
7140
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007141 phy->addr = XGXS_EXT_PHY_ADDR(ext_phy_config);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007142 bnx2x_populate_preemphasis(bp, shmem_base, phy, port, phy_index);
Yaniv Rosner62b29a52010-09-07 11:40:58 +00007143
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007144 /**
7145 * The shmem address of the phy version is located on different
7146 * structures. In case this structure is too old, do not set
7147 * the address
7148 */
7149 config2 = REG_RD(bp, shmem_base + offsetof(struct shmem_region,
7150 dev_info.shared_hw_config.config2));
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007151 if (phy_index == EXT_PHY1) {
7152 phy->ver_addr = shmem_base + offsetof(struct shmem_region,
7153 port_mb[port].ext_phy_fw_version);
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007154
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007155 /* Check specific mdc mdio settings */
7156 if (config2 & SHARED_HW_CFG_MDC_MDIO_ACCESS1_MASK)
7157 mdc_mdio_access = config2 &
7158 SHARED_HW_CFG_MDC_MDIO_ACCESS1_MASK;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007159 } else {
7160 u32 size = REG_RD(bp, shmem2_base);
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007161
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007162 if (size >
7163 offsetof(struct shmem2_region, ext_phy_fw_version2)) {
7164 phy->ver_addr = shmem2_base +
7165 offsetof(struct shmem2_region,
7166 ext_phy_fw_version2[port]);
7167 }
7168 /* Check specific mdc mdio settings */
7169 if (config2 & SHARED_HW_CFG_MDC_MDIO_ACCESS2_MASK)
7170 mdc_mdio_access = (config2 &
7171 SHARED_HW_CFG_MDC_MDIO_ACCESS2_MASK) >>
7172 (SHARED_HW_CFG_MDC_MDIO_ACCESS2_SHIFT -
7173 SHARED_HW_CFG_MDC_MDIO_ACCESS1_SHIFT);
7174 }
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007175 phy->mdio_ctrl = bnx2x_get_emac_base(bp, mdc_mdio_access, port);
7176
7177 /**
7178 * In case mdc/mdio_access of the external phy is different than the
7179 * mdc/mdio access of the XGXS, a HW lock must be taken in each access
7180 * to prevent one port interfere with another port's CL45 operations.
7181 */
7182 if (mdc_mdio_access != SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH)
7183 phy->flags |= FLAGS_HW_LOCK_REQUIRED;
7184 DP(NETIF_MSG_LINK, "phy_type 0x%x port %d found in index %d\n",
7185 phy_type, port, phy_index);
7186 DP(NETIF_MSG_LINK, " addr=0x%x, mdio_ctl=0x%x\n",
7187 phy->addr, phy->mdio_ctrl);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007188 return 0;
7189}
7190
7191static u8 bnx2x_populate_phy(struct bnx2x *bp, u8 phy_index, u32 shmem_base,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007192 u32 shmem2_base, u8 port, struct bnx2x_phy *phy)
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007193{
7194 u8 status = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007195 phy->type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN;
7196 if (phy_index == INT_PHY)
7197 return bnx2x_populate_int_phy(bp, shmem_base, port, phy);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007198 status = bnx2x_populate_ext_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007199 port, phy);
7200 return status;
7201}
7202
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007203static void bnx2x_phy_def_cfg(struct link_params *params,
7204 struct bnx2x_phy *phy,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007205 u8 phy_index)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007206{
7207 struct bnx2x *bp = params->bp;
7208 u32 link_config;
7209 /* Populate the default phy configuration for MF mode */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007210 if (phy_index == EXT_PHY2) {
7211 link_config = REG_RD(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007212 offsetof(struct shmem_region, dev_info.
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007213 port_feature_config[params->port].link_config2));
7214 phy->speed_cap_mask = REG_RD(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007215 offsetof(struct shmem_region,
7216 dev_info.
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007217 port_hw_config[params->port].speed_capability_mask2));
7218 } else {
7219 link_config = REG_RD(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007220 offsetof(struct shmem_region, dev_info.
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007221 port_feature_config[params->port].link_config));
7222 phy->speed_cap_mask = REG_RD(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007223 offsetof(struct shmem_region,
7224 dev_info.
7225 port_hw_config[params->port].speed_capability_mask));
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007226 }
7227 DP(NETIF_MSG_LINK, "Default config phy idx %x cfg 0x%x speed_cap_mask"
7228 " 0x%x\n", phy_index, link_config, phy->speed_cap_mask);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007229
7230 phy->req_duplex = DUPLEX_FULL;
7231 switch (link_config & PORT_FEATURE_LINK_SPEED_MASK) {
7232 case PORT_FEATURE_LINK_SPEED_10M_HALF:
7233 phy->req_duplex = DUPLEX_HALF;
7234 case PORT_FEATURE_LINK_SPEED_10M_FULL:
7235 phy->req_line_speed = SPEED_10;
7236 break;
7237 case PORT_FEATURE_LINK_SPEED_100M_HALF:
7238 phy->req_duplex = DUPLEX_HALF;
7239 case PORT_FEATURE_LINK_SPEED_100M_FULL:
7240 phy->req_line_speed = SPEED_100;
7241 break;
7242 case PORT_FEATURE_LINK_SPEED_1G:
7243 phy->req_line_speed = SPEED_1000;
7244 break;
7245 case PORT_FEATURE_LINK_SPEED_2_5G:
7246 phy->req_line_speed = SPEED_2500;
7247 break;
7248 case PORT_FEATURE_LINK_SPEED_10G_CX4:
7249 phy->req_line_speed = SPEED_10000;
7250 break;
7251 default:
7252 phy->req_line_speed = SPEED_AUTO_NEG;
7253 break;
7254 }
7255
7256 switch (link_config & PORT_FEATURE_FLOW_CONTROL_MASK) {
7257 case PORT_FEATURE_FLOW_CONTROL_AUTO:
7258 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_AUTO;
7259 break;
7260 case PORT_FEATURE_FLOW_CONTROL_TX:
7261 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_TX;
7262 break;
7263 case PORT_FEATURE_FLOW_CONTROL_RX:
7264 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_RX;
7265 break;
7266 case PORT_FEATURE_FLOW_CONTROL_BOTH:
7267 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_BOTH;
7268 break;
7269 default:
7270 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_NONE;
7271 break;
7272 }
7273}
7274
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007275u32 bnx2x_phy_selection(struct link_params *params)
7276{
7277 u32 phy_config_swapped, prio_cfg;
7278 u32 return_cfg = PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT;
7279
7280 phy_config_swapped = params->multi_phy_config &
7281 PORT_HW_CFG_PHY_SWAPPED_ENABLED;
7282
7283 prio_cfg = params->multi_phy_config &
7284 PORT_HW_CFG_PHY_SELECTION_MASK;
7285
7286 if (phy_config_swapped) {
7287 switch (prio_cfg) {
7288 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
7289 return_cfg = PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY;
7290 break;
7291 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
7292 return_cfg = PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY;
7293 break;
7294 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY:
7295 return_cfg = PORT_HW_CFG_PHY_SELECTION_FIRST_PHY;
7296 break;
7297 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY:
7298 return_cfg = PORT_HW_CFG_PHY_SELECTION_SECOND_PHY;
7299 break;
7300 }
7301 } else
7302 return_cfg = prio_cfg;
7303
7304 return return_cfg;
7305}
7306
7307
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007308u8 bnx2x_phy_probe(struct link_params *params)
7309{
7310 u8 phy_index, actual_phy_idx, link_cfg_idx;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007311 u32 phy_config_swapped;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007312 struct bnx2x *bp = params->bp;
7313 struct bnx2x_phy *phy;
7314 params->num_phys = 0;
7315 DP(NETIF_MSG_LINK, "Begin phy probe\n");
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007316 phy_config_swapped = params->multi_phy_config &
7317 PORT_HW_CFG_PHY_SWAPPED_ENABLED;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007318
7319 for (phy_index = INT_PHY; phy_index < MAX_PHYS;
7320 phy_index++) {
7321 link_cfg_idx = LINK_CONFIG_IDX(phy_index);
7322 actual_phy_idx = phy_index;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007323 if (phy_config_swapped) {
7324 if (phy_index == EXT_PHY1)
7325 actual_phy_idx = EXT_PHY2;
7326 else if (phy_index == EXT_PHY2)
7327 actual_phy_idx = EXT_PHY1;
7328 }
7329 DP(NETIF_MSG_LINK, "phy_config_swapped %x, phy_index %x,"
7330 " actual_phy_idx %x\n", phy_config_swapped,
7331 phy_index, actual_phy_idx);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007332 phy = &params->phy[actual_phy_idx];
7333 if (bnx2x_populate_phy(bp, phy_index, params->shmem_base,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007334 params->shmem2_base, params->port,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007335 phy) != 0) {
7336 params->num_phys = 0;
7337 DP(NETIF_MSG_LINK, "phy probe failed in phy index %d\n",
7338 phy_index);
7339 for (phy_index = INT_PHY;
7340 phy_index < MAX_PHYS;
7341 phy_index++)
7342 *phy = phy_null;
7343 return -EINVAL;
7344 }
7345 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)
7346 break;
7347
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007348 bnx2x_phy_def_cfg(params, phy, phy_index);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007349 params->num_phys++;
7350 }
7351
7352 DP(NETIF_MSG_LINK, "End phy probe. #phys found %x\n", params->num_phys);
7353 return 0;
7354}
7355
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007356static void set_phy_vars(struct link_params *params)
7357{
7358 struct bnx2x *bp = params->bp;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007359 u8 actual_phy_idx, phy_index, link_cfg_idx;
7360 u8 phy_config_swapped = params->multi_phy_config &
7361 PORT_HW_CFG_PHY_SWAPPED_ENABLED;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007362 for (phy_index = INT_PHY; phy_index < params->num_phys;
7363 phy_index++) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007364 link_cfg_idx = LINK_CONFIG_IDX(phy_index);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007365 actual_phy_idx = phy_index;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007366 if (phy_config_swapped) {
7367 if (phy_index == EXT_PHY1)
7368 actual_phy_idx = EXT_PHY2;
7369 else if (phy_index == EXT_PHY2)
7370 actual_phy_idx = EXT_PHY1;
7371 }
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007372 params->phy[actual_phy_idx].req_flow_ctrl =
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007373 params->req_flow_ctrl[link_cfg_idx];
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007374
7375 params->phy[actual_phy_idx].req_line_speed =
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007376 params->req_line_speed[link_cfg_idx];
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007377
7378 params->phy[actual_phy_idx].speed_cap_mask =
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007379 params->speed_cap_mask[link_cfg_idx];
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007380
7381 params->phy[actual_phy_idx].req_duplex =
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007382 params->req_duplex[link_cfg_idx];
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007383
7384 DP(NETIF_MSG_LINK, "req_flow_ctrl %x, req_line_speed %x,"
7385 " speed_cap_mask %x\n",
7386 params->phy[actual_phy_idx].req_flow_ctrl,
7387 params->phy[actual_phy_idx].req_line_speed,
7388 params->phy[actual_phy_idx].speed_cap_mask);
7389 }
7390}
7391
7392u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
7393{
7394 struct bnx2x *bp = params->bp;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007395 DP(NETIF_MSG_LINK, "Phy Initialization started\n");
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007396 DP(NETIF_MSG_LINK, "(1) req_speed %d, req_flowctrl %d\n",
7397 params->req_line_speed[0], params->req_flow_ctrl[0]);
7398 DP(NETIF_MSG_LINK, "(2) req_speed %d, req_flowctrl %d\n",
7399 params->req_line_speed[1], params->req_flow_ctrl[1]);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007400 vars->link_status = 0;
7401 vars->phy_link_up = 0;
7402 vars->link_up = 0;
7403 vars->line_speed = 0;
7404 vars->duplex = DUPLEX_FULL;
7405 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
7406 vars->mac_type = MAC_TYPE_NONE;
7407 vars->phy_flags = 0;
7408
7409 /* disable attentions */
7410 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4,
7411 (NIG_MASK_XGXS0_LINK_STATUS |
7412 NIG_MASK_XGXS0_LINK10G |
7413 NIG_MASK_SERDES0_LINK_STATUS |
7414 NIG_MASK_MI_INT));
7415
7416 bnx2x_emac_init(params, vars);
7417
7418 if (params->num_phys == 0) {
7419 DP(NETIF_MSG_LINK, "No phy found for initialization !!\n");
7420 return -EINVAL;
7421 }
7422 set_phy_vars(params);
7423
7424 DP(NETIF_MSG_LINK, "Num of phys on board: %d\n", params->num_phys);
7425 if (CHIP_REV_IS_FPGA(bp)) {
7426
7427 vars->link_up = 1;
7428 vars->line_speed = SPEED_10000;
7429 vars->duplex = DUPLEX_FULL;
7430 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
7431 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
7432 /* enable on E1.5 FPGA */
7433 if (CHIP_IS_E1H(bp)) {
7434 vars->flow_ctrl |=
7435 (BNX2X_FLOW_CTRL_TX |
7436 BNX2X_FLOW_CTRL_RX);
7437 vars->link_status |=
7438 (LINK_STATUS_TX_FLOW_CONTROL_ENABLED |
7439 LINK_STATUS_RX_FLOW_CONTROL_ENABLED);
7440 }
7441
7442 bnx2x_emac_enable(params, vars, 0);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007443 if (!(CHIP_IS_E2(bp)))
7444 bnx2x_pbf_update(params, vars->flow_ctrl,
7445 vars->line_speed);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007446 /* disable drain */
7447 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
7448
7449 /* update shared memory */
7450 bnx2x_update_mng(params, vars->link_status);
7451
7452 return 0;
7453
7454 } else
7455 if (CHIP_REV_IS_EMUL(bp)) {
7456
7457 vars->link_up = 1;
7458 vars->line_speed = SPEED_10000;
7459 vars->duplex = DUPLEX_FULL;
7460 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
7461 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
7462
7463 bnx2x_bmac_enable(params, vars, 0);
7464
7465 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
7466 /* Disable drain */
7467 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
7468 + params->port*4, 0);
7469
7470 /* update shared memory */
7471 bnx2x_update_mng(params, vars->link_status);
7472
7473 return 0;
7474
7475 } else
7476 if (params->loopback_mode == LOOPBACK_BMAC) {
7477
7478 vars->link_up = 1;
7479 vars->line_speed = SPEED_10000;
7480 vars->duplex = DUPLEX_FULL;
7481 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
7482 vars->mac_type = MAC_TYPE_BMAC;
7483
7484 vars->phy_flags = PHY_XGXS_FLAG;
7485
7486 bnx2x_xgxs_deassert(params);
7487
7488 /* set bmac loopback */
7489 bnx2x_bmac_enable(params, vars, 1);
7490
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007491 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007492
7493 } else if (params->loopback_mode == LOOPBACK_EMAC) {
7494
7495 vars->link_up = 1;
7496 vars->line_speed = SPEED_1000;
7497 vars->duplex = DUPLEX_FULL;
7498 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
7499 vars->mac_type = MAC_TYPE_EMAC;
7500
7501 vars->phy_flags = PHY_XGXS_FLAG;
7502
7503 bnx2x_xgxs_deassert(params);
7504 /* set bmac loopback */
7505 bnx2x_emac_enable(params, vars, 1);
7506 bnx2x_emac_program(params, vars);
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007507 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007508
7509 } else if ((params->loopback_mode == LOOPBACK_XGXS) ||
7510 (params->loopback_mode == LOOPBACK_EXT_PHY)) {
7511
7512 vars->link_up = 1;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007513 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007514 vars->duplex = DUPLEX_FULL;
7515 if (params->req_line_speed[0] == SPEED_1000) {
7516 vars->line_speed = SPEED_1000;
7517 vars->mac_type = MAC_TYPE_EMAC;
7518 } else {
7519 vars->line_speed = SPEED_10000;
7520 vars->mac_type = MAC_TYPE_BMAC;
7521 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007522
7523 bnx2x_xgxs_deassert(params);
7524 bnx2x_link_initialize(params, vars);
7525
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007526 if (params->req_line_speed[0] == SPEED_1000) {
7527 bnx2x_emac_program(params, vars);
7528 bnx2x_emac_enable(params, vars, 0);
7529 } else
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007530 bnx2x_bmac_enable(params, vars, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007531 if (params->loopback_mode == LOOPBACK_XGXS) {
7532 /* set 10G XGXS loopback */
7533 params->phy[INT_PHY].config_loopback(
7534 &params->phy[INT_PHY],
7535 params);
7536
7537 } else {
7538 /* set external phy loopback */
7539 u8 phy_index;
7540 for (phy_index = EXT_PHY1;
7541 phy_index < params->num_phys; phy_index++) {
7542 if (params->phy[phy_index].config_loopback)
7543 params->phy[phy_index].config_loopback(
7544 &params->phy[phy_index],
7545 params);
7546 }
7547 }
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007548 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007549
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00007550 bnx2x_set_led(params, vars,
7551 LED_MODE_OPER, vars->line_speed);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007552 } else
7553 /* No loopback */
7554 {
7555 if (params->switch_cfg == SWITCH_CFG_10G)
7556 bnx2x_xgxs_deassert(params);
7557 else
7558 bnx2x_serdes_deassert(bp, params->port);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00007559
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007560 bnx2x_link_initialize(params, vars);
7561 msleep(30);
7562 bnx2x_link_int_enable(params);
7563 }
7564 return 0;
7565}
7566u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007567 u8 reset_ext_phy)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007568{
7569 struct bnx2x *bp = params->bp;
Yaniv Rosnercf1d9722010-11-01 05:32:34 +00007570 u8 phy_index, port = params->port, clear_latch_ind = 0;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007571 DP(NETIF_MSG_LINK, "Resetting the link of port %d\n", port);
7572 /* disable attentions */
7573 vars->link_status = 0;
7574 bnx2x_update_mng(params, vars->link_status);
7575 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007576 (NIG_MASK_XGXS0_LINK_STATUS |
7577 NIG_MASK_XGXS0_LINK10G |
7578 NIG_MASK_SERDES0_LINK_STATUS |
7579 NIG_MASK_MI_INT));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007580
7581 /* activate nig drain */
7582 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
7583
7584 /* disable nig egress interface */
7585 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
7586 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
7587
7588 /* Stop BigMac rx */
7589 bnx2x_bmac_rx_disable(bp, port);
7590
7591 /* disable emac */
7592 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
7593
7594 msleep(10);
7595 /* The PHY reset is controled by GPIO 1
7596 * Hold it as vars low
7597 */
7598 /* clear link led */
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00007599 bnx2x_set_led(params, vars, LED_MODE_OFF, 0);
7600
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007601 if (reset_ext_phy) {
7602 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
7603 phy_index++) {
7604 if (params->phy[phy_index].link_reset)
7605 params->phy[phy_index].link_reset(
7606 &params->phy[phy_index],
7607 params);
Yaniv Rosnercf1d9722010-11-01 05:32:34 +00007608 if (params->phy[phy_index].flags &
7609 FLAGS_REARM_LATCH_SIGNAL)
7610 clear_latch_ind = 1;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007611 }
7612 }
7613
Yaniv Rosnercf1d9722010-11-01 05:32:34 +00007614 if (clear_latch_ind) {
7615 /* Clear latching indication */
7616 bnx2x_rearm_latch_signal(bp, port, 0);
7617 bnx2x_bits_dis(bp, NIG_REG_LATCH_BC_0 + port*4,
7618 1 << NIG_LATCH_BC_ENABLE_MI_INT);
7619 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007620 if (params->phy[INT_PHY].link_reset)
7621 params->phy[INT_PHY].link_reset(
7622 &params->phy[INT_PHY], params);
7623 /* reset BigMac */
7624 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
7625 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
7626
7627 /* disable nig ingress interface */
7628 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0);
7629 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0);
7630 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
7631 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
7632 vars->link_up = 0;
7633 return 0;
7634}
7635
7636/****************************************************************************/
7637/* Common function */
7638/****************************************************************************/
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007639static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp,
7640 u32 shmem_base_path[],
7641 u32 shmem2_base_path[], u8 phy_index,
7642 u32 chip_id)
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007643{
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007644 struct bnx2x_phy phy[PORT_MAX];
7645 struct bnx2x_phy *phy_blk[PORT_MAX];
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007646 u16 val;
Yaniv Rosnerc8e64df2011-01-30 04:15:00 +00007647 s8 port = 0;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007648 s8 port_of_path = 0;
Yaniv Rosnerc8e64df2011-01-30 04:15:00 +00007649 u32 swap_val, swap_override;
7650 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
7651 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
7652 port ^= (swap_val && swap_override);
7653 bnx2x_ext_phy_hw_reset(bp, port);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007654 /* PART1 - Reset both phys */
7655 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007656 u32 shmem_base, shmem2_base;
7657 /* In E2, same phy is using for port0 of the two paths */
7658 if (CHIP_IS_E2(bp)) {
7659 shmem_base = shmem_base_path[port];
7660 shmem2_base = shmem2_base_path[port];
7661 port_of_path = 0;
7662 } else {
7663 shmem_base = shmem_base_path[0];
7664 shmem2_base = shmem2_base_path[0];
7665 port_of_path = port;
7666 }
7667
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007668 /* Extract the ext phy address for the port */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007669 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007670 port_of_path, &phy[port]) !=
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007671 0) {
7672 DP(NETIF_MSG_LINK, "populate_phy failed\n");
7673 return -EINVAL;
7674 }
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007675 /* disable attentions */
Yaniv Rosner6a71bbe2010-11-01 05:32:31 +00007676 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 +
7677 port_of_path*4,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007678 (NIG_MASK_XGXS0_LINK_STATUS |
7679 NIG_MASK_XGXS0_LINK10G |
7680 NIG_MASK_SERDES0_LINK_STATUS |
7681 NIG_MASK_MI_INT));
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007682
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007683 /* Need to take the phy out of low power mode in order
7684 to write to access its registers */
7685 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007686 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
7687 port);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007688
7689 /* Reset the phy */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007690 bnx2x_cl45_write(bp, &phy[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007691 MDIO_PMA_DEVAD,
7692 MDIO_PMA_REG_CTRL,
7693 1<<15);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007694 }
7695
7696 /* Add delay of 150ms after reset */
7697 msleep(150);
7698
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007699 if (phy[PORT_0].addr & 0x1) {
7700 phy_blk[PORT_0] = &(phy[PORT_1]);
7701 phy_blk[PORT_1] = &(phy[PORT_0]);
7702 } else {
7703 phy_blk[PORT_0] = &(phy[PORT_0]);
7704 phy_blk[PORT_1] = &(phy[PORT_1]);
7705 }
7706
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007707 /* PART2 - Download firmware to both phys */
7708 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007709 if (CHIP_IS_E2(bp))
7710 port_of_path = 0;
7711 else
7712 port_of_path = port;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007713
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007714 DP(NETIF_MSG_LINK, "Loading spirom for phy address 0x%x\n",
7715 phy_blk[port]->addr);
Yaniv Rosner5c99274b2011-01-18 04:33:36 +00007716 if (bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port],
7717 port_of_path))
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007718 return -EINVAL;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007719
7720 /* Only set bit 10 = 1 (Tx power down) */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007721 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007722 MDIO_PMA_DEVAD,
7723 MDIO_PMA_REG_TX_POWER_DOWN, &val);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007724
7725 /* Phase1 of TX_POWER_DOWN reset */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007726 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007727 MDIO_PMA_DEVAD,
7728 MDIO_PMA_REG_TX_POWER_DOWN,
7729 (val | 1<<10));
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007730 }
7731
7732 /* Toggle Transmitter: Power down and then up with 600ms
7733 delay between */
7734 msleep(600);
7735
7736 /* PART3 - complete TX_POWER_DOWN process, and set GPIO2 back to low */
7737 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Eilon Greensteinf5372252009-02-12 08:38:30 +00007738 /* Phase2 of POWER_DOWN_RESET */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007739 /* Release bit 10 (Release Tx power down) */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007740 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007741 MDIO_PMA_DEVAD,
7742 MDIO_PMA_REG_TX_POWER_DOWN, &val);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007743
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007744 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007745 MDIO_PMA_DEVAD,
7746 MDIO_PMA_REG_TX_POWER_DOWN, (val & (~(1<<10))));
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007747 msleep(15);
7748
7749 /* Read modify write the SPI-ROM version select register */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007750 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007751 MDIO_PMA_DEVAD,
7752 MDIO_PMA_REG_EDC_FFE_MAIN, &val);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007753 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007754 MDIO_PMA_DEVAD,
7755 MDIO_PMA_REG_EDC_FFE_MAIN, (val | (1<<12)));
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007756
7757 /* set GPIO2 back to LOW */
7758 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007759 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007760 }
7761 return 0;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007762}
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007763static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp,
7764 u32 shmem_base_path[],
7765 u32 shmem2_base_path[], u8 phy_index,
7766 u32 chip_id)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007767{
7768 u32 val;
7769 s8 port;
7770 struct bnx2x_phy phy;
7771 /* Use port1 because of the static port-swap */
7772 /* Enable the module detection interrupt */
7773 val = REG_RD(bp, MISC_REG_GPIO_EVENT_EN);
7774 val |= ((1<<MISC_REGISTERS_GPIO_3)|
7775 (1<<(MISC_REGISTERS_GPIO_3 + MISC_REGISTERS_GPIO_PORT_SHIFT)));
7776 REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val);
7777
Yaniv Rosner650154b2010-11-01 05:32:36 +00007778 bnx2x_ext_phy_hw_reset(bp, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007779 msleep(5);
7780 for (port = 0; port < PORT_MAX; port++) {
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007781 u32 shmem_base, shmem2_base;
7782
7783 /* In E2, same phy is using for port0 of the two paths */
7784 if (CHIP_IS_E2(bp)) {
7785 shmem_base = shmem_base_path[port];
7786 shmem2_base = shmem2_base_path[port];
7787 } else {
7788 shmem_base = shmem_base_path[0];
7789 shmem2_base = shmem2_base_path[0];
7790 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007791 /* Extract the ext phy address for the port */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007792 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007793 port, &phy) !=
7794 0) {
7795 DP(NETIF_MSG_LINK, "populate phy failed\n");
7796 return -EINVAL;
7797 }
7798
7799 /* Reset phy*/
7800 bnx2x_cl45_write(bp, &phy,
7801 MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, 0x0001);
7802
7803
7804 /* Set fault module detected LED on */
7805 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007806 MISC_REGISTERS_GPIO_HIGH,
7807 port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007808 }
7809
7810 return 0;
7811}
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007812static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp,
7813 u32 shmem_base_path[],
7814 u32 shmem2_base_path[], u8 phy_index,
7815 u32 chip_id)
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007816{
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007817 s8 port;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007818 u32 swap_val, swap_override;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007819 struct bnx2x_phy phy[PORT_MAX];
7820 struct bnx2x_phy *phy_blk[PORT_MAX];
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007821 s8 port_of_path;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007822 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
7823 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007824
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007825 port = 1;
7826
7827 bnx2x_ext_phy_hw_reset(bp, port ^ (swap_val && swap_override));
7828
7829 /* Calculate the port based on port swap */
7830 port ^= (swap_val && swap_override);
7831
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007832 msleep(5);
7833
7834 /* PART1 - Reset both phys */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007835 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007836 u32 shmem_base, shmem2_base;
7837
7838 /* In E2, same phy is using for port0 of the two paths */
7839 if (CHIP_IS_E2(bp)) {
7840 shmem_base = shmem_base_path[port];
7841 shmem2_base = shmem2_base_path[port];
7842 port_of_path = 0;
7843 } else {
7844 shmem_base = shmem_base_path[0];
7845 shmem2_base = shmem2_base_path[0];
7846 port_of_path = port;
7847 }
7848
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007849 /* Extract the ext phy address for the port */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007850 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007851 port_of_path, &phy[port]) !=
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007852 0) {
7853 DP(NETIF_MSG_LINK, "populate phy failed\n");
7854 return -EINVAL;
7855 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007856 /* disable attentions */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007857 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 +
7858 port_of_path*4,
7859 (NIG_MASK_XGXS0_LINK_STATUS |
7860 NIG_MASK_XGXS0_LINK10G |
7861 NIG_MASK_SERDES0_LINK_STATUS |
7862 NIG_MASK_MI_INT));
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007863
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007864
7865 /* Reset the phy */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007866 bnx2x_cl45_write(bp, &phy[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007867 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007868 }
7869
7870 /* Add delay of 150ms after reset */
7871 msleep(150);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007872 if (phy[PORT_0].addr & 0x1) {
7873 phy_blk[PORT_0] = &(phy[PORT_1]);
7874 phy_blk[PORT_1] = &(phy[PORT_0]);
7875 } else {
7876 phy_blk[PORT_0] = &(phy[PORT_0]);
7877 phy_blk[PORT_1] = &(phy[PORT_1]);
7878 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007879 /* PART2 - Download firmware to both phys */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007880 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007881 if (CHIP_IS_E2(bp))
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007882 port_of_path = 0;
7883 else
7884 port_of_path = port;
7885 DP(NETIF_MSG_LINK, "Loading spirom for phy address 0x%x\n",
7886 phy_blk[port]->addr);
Yaniv Rosner5c99274b2011-01-18 04:33:36 +00007887 if (bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port],
7888 port_of_path))
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007889 return -EINVAL;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007890
Yaniv Rosner5c99274b2011-01-18 04:33:36 +00007891 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007892 return 0;
7893}
7894
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007895static u8 bnx2x_ext_phy_common_init(struct bnx2x *bp, u32 shmem_base_path[],
7896 u32 shmem2_base_path[], u8 phy_index,
7897 u32 ext_phy_type, u32 chip_id)
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007898{
7899 u8 rc = 0;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007900
7901 switch (ext_phy_type) {
7902 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007903 rc = bnx2x_8073_common_init_phy(bp, shmem_base_path,
7904 shmem2_base_path,
7905 phy_index, chip_id);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007906 break;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007907
7908 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
7909 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007910 rc = bnx2x_8727_common_init_phy(bp, shmem_base_path,
7911 shmem2_base_path,
7912 phy_index, chip_id);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007913 break;
7914
Eilon Greenstein589abe32009-02-12 08:36:55 +00007915 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
7916 /* GPIO1 affects both ports, so there's need to pull
7917 it for single port alone */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007918 rc = bnx2x_8726_common_init_phy(bp, shmem_base_path,
7919 shmem2_base_path,
7920 phy_index, chip_id);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007921 break;
7922 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
7923 rc = -EINVAL;
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02007924 break;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007925 default:
7926 DP(NETIF_MSG_LINK,
7927 "bnx2x_common_init_phy: ext_phy 0x%x not required\n",
7928 ext_phy_type);
7929 break;
7930 }
7931
7932 return rc;
7933}
7934
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007935u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base_path[],
7936 u32 shmem2_base_path[], u32 chip_id)
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007937{
7938 u8 rc = 0;
Yaniv Rosnerb21a3422011-01-18 04:33:24 +00007939 u32 phy_ver;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007940 u8 phy_index;
7941 u32 ext_phy_type, ext_phy_config;
7942 DP(NETIF_MSG_LINK, "Begin common phy init\n");
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00007943
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007944 if (CHIP_REV_IS_EMUL(bp))
7945 return 0;
7946
Yaniv Rosnerb21a3422011-01-18 04:33:24 +00007947 /* Check if common init was already done */
7948 phy_ver = REG_RD(bp, shmem_base_path[0] +
7949 offsetof(struct shmem_region,
7950 port_mb[PORT_0].ext_phy_fw_version));
7951 if (phy_ver) {
7952 DP(NETIF_MSG_LINK, "Not doing common init; phy ver is 0x%x\n",
7953 phy_ver);
7954 return 0;
7955 }
7956
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007957 /* Read the ext_phy_type for arbitrary port(0) */
7958 for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
7959 phy_index++) {
7960 ext_phy_config = bnx2x_get_ext_phy_config(bp,
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007961 shmem_base_path[0],
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007962 phy_index, 0);
7963 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007964 rc |= bnx2x_ext_phy_common_init(bp, shmem_base_path,
7965 shmem2_base_path,
7966 phy_index, ext_phy_type,
7967 chip_id);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007968 }
7969 return rc;
7970}
7971
7972u8 bnx2x_hw_lock_required(struct bnx2x *bp, u32 shmem_base, u32 shmem2_base)
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00007973{
7974 u8 phy_index;
7975 struct bnx2x_phy phy;
7976 for (phy_index = INT_PHY; phy_index < MAX_PHYS;
7977 phy_index++) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007978 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00007979 0, &phy) != 0) {
7980 DP(NETIF_MSG_LINK, "populate phy failed\n");
7981 return 0;
7982 }
7983
7984 if (phy.flags & FLAGS_HW_LOCK_REQUIRED)
7985 return 1;
7986 }
7987 return 0;
7988}
7989
7990u8 bnx2x_fan_failure_det_req(struct bnx2x *bp,
7991 u32 shmem_base,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007992 u32 shmem2_base,
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00007993 u8 port)
7994{
7995 u8 phy_index, fan_failure_det_req = 0;
7996 struct bnx2x_phy phy;
7997 for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
7998 phy_index++) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007999 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00008000 port, &phy)
8001 != 0) {
8002 DP(NETIF_MSG_LINK, "populate phy failed\n");
8003 return 0;
8004 }
8005 fan_failure_det_req |= (phy.flags &
8006 FLAGS_FAN_FAILURE_DET_REQ);
8007 }
8008 return fan_failure_det_req;
8009}
8010
8011void bnx2x_hw_reset_phy(struct link_params *params)
8012{
8013 u8 phy_index;
8014 for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
8015 phy_index++) {
8016 if (params->phy[phy_index].hw_reset) {
8017 params->phy[phy_index].hw_reset(
8018 &params->phy[phy_index],
8019 params);
8020 params->phy[phy_index] = phy_null;
8021 }
8022 }
8023}