blob: 9fadcdbe41154a27a87f102f2d9a01dd1e215971 [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
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000220 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000221 * 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);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000229 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000230 * 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);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000241 /*
242 * For strict priority entries defines the number of consecutive
243 * slots for the highest priority.
244 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000245 REG_WR(bp, NIG_REG_P0_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000246 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000247 * 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);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000259 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000260 * 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");
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000277 /*
278 * defines which entries (clients) are subjected to WFQ arbitration
279 * COS0 0x8
280 * COS1 0x10
281 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000282 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ, 0x18);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000283 /*
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 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000290 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);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000302 /*
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 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000310 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");
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000358 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000359 * 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);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000367 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000368 * 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
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000380 /*
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 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000388 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
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000602 /*
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 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000610 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
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000763 /*
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 }
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000819 /*
820 * The number of free blocks below which the pause signal to class 0
821 * of MAC #n is asserted. n=0,1
822 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000823 REG_WR(bp, BRB1_REG_PAUSE_0_XOFF_THRESHOLD_0 , pause_xoff_th);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000824 /*
825 * The number of free blocks above which the pause signal to class 0
826 * of MAC #n is de-asserted. n=0,1
827 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000828 REG_WR(bp, BRB1_REG_PAUSE_0_XON_THRESHOLD_0 , pause_xon_th);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000829 /*
830 * The number of free blocks below which the full signal to class 0
831 * of MAC #n is asserted. n=0,1
832 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000833 REG_WR(bp, BRB1_REG_FULL_0_XOFF_THRESHOLD_0 , full_xoff_th);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000834 /*
835 * The number of free blocks above which the full signal to class 0
836 * of MAC #n is de-asserted. n=0,1
837 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000838 REG_WR(bp, BRB1_REG_FULL_0_XON_THRESHOLD_0 , full_xon_th);
839
840 if (set_pfc && pfc_params) {
841 /* Second COS */
842 if (pfc_params->cos1_pauseable) {
843 pause_xoff_th =
844 PFC_BRB_MAC_PAUSE_XOFF_THRESHOLD_PAUSEABLE;
845 pause_xon_th =
846 PFC_BRB_MAC_PAUSE_XON_THRESHOLD_PAUSEABLE;
847 full_xoff_th =
848 PFC_BRB_MAC_FULL_XOFF_THRESHOLD_PAUSEABLE;
849 full_xon_th =
850 PFC_BRB_MAC_FULL_XON_THRESHOLD_PAUSEABLE;
851 } else {
852 pause_xoff_th =
853 PFC_BRB_MAC_PAUSE_XOFF_THRESHOLD_NON_PAUSEABLE;
854 pause_xon_th =
855 PFC_BRB_MAC_PAUSE_XON_THRESHOLD_NON_PAUSEABLE;
856 full_xoff_th =
857 PFC_BRB_MAC_FULL_XOFF_THRESHOLD_NON_PAUSEABLE;
858 full_xon_th =
859 PFC_BRB_MAC_FULL_XON_THRESHOLD_NON_PAUSEABLE;
860 }
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000861 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000862 * The number of free blocks below which the pause signal to
863 * class 1 of MAC #n is asserted. n=0,1
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000864 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000865 REG_WR(bp, BRB1_REG_PAUSE_1_XOFF_THRESHOLD_0, pause_xoff_th);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000866 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000867 * The number of free blocks above which the pause signal to
868 * class 1 of MAC #n is de-asserted. n=0,1
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000869 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000870 REG_WR(bp, BRB1_REG_PAUSE_1_XON_THRESHOLD_0, pause_xon_th);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000871 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000872 * The number of free blocks below which the full signal to
873 * class 1 of MAC #n is asserted. n=0,1
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000874 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000875 REG_WR(bp, BRB1_REG_FULL_1_XOFF_THRESHOLD_0, full_xoff_th);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000876 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000877 * The number of free blocks above which the full signal to
878 * class 1 of MAC #n is de-asserted. n=0,1
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000879 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000880 REG_WR(bp, BRB1_REG_FULL_1_XON_THRESHOLD_0, full_xon_th);
881 }
882}
883
884static void bnx2x_update_pfc_nig(struct link_params *params,
885 struct link_vars *vars,
886 struct bnx2x_nig_brb_pfc_port_params *nig_params)
887{
888 u32 xcm_mask = 0, ppp_enable = 0, pause_enable = 0, llfc_out_en = 0;
889 u32 llfc_enable = 0, xcm0_out_en = 0, p0_hwpfc_enable = 0;
890 u32 pkt_priority_to_cos = 0;
891 u32 val;
892 struct bnx2x *bp = params->bp;
893 int port = params->port;
894 int set_pfc = params->feature_config_flags &
895 FEATURE_CONFIG_PFC_ENABLED;
896 DP(NETIF_MSG_LINK, "updating pfc nig parameters\n");
897
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000898 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000899 * When NIG_LLH0_XCM_MASK_REG_LLHX_XCM_MASK_BCN bit is set
900 * MAC control frames (that are not pause packets)
901 * will be forwarded to the XCM.
902 */
903 xcm_mask = REG_RD(bp,
904 port ? NIG_REG_LLH1_XCM_MASK :
905 NIG_REG_LLH0_XCM_MASK);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000906 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000907 * nig params will override non PFC params, since it's possible to
908 * do transition from PFC to SAFC
909 */
910 if (set_pfc) {
911 pause_enable = 0;
912 llfc_out_en = 0;
913 llfc_enable = 0;
914 ppp_enable = 1;
915 xcm_mask &= ~(port ? NIG_LLH1_XCM_MASK_REG_LLH1_XCM_MASK_BCN :
916 NIG_LLH0_XCM_MASK_REG_LLH0_XCM_MASK_BCN);
917 xcm0_out_en = 0;
918 p0_hwpfc_enable = 1;
919 } else {
920 if (nig_params) {
921 llfc_out_en = nig_params->llfc_out_en;
922 llfc_enable = nig_params->llfc_enable;
923 pause_enable = nig_params->pause_enable;
924 } else /*defaul non PFC mode - PAUSE */
925 pause_enable = 1;
926
927 xcm_mask |= (port ? NIG_LLH1_XCM_MASK_REG_LLH1_XCM_MASK_BCN :
928 NIG_LLH0_XCM_MASK_REG_LLH0_XCM_MASK_BCN);
929 xcm0_out_en = 1;
930 }
931
932 REG_WR(bp, port ? NIG_REG_LLFC_OUT_EN_1 :
933 NIG_REG_LLFC_OUT_EN_0, llfc_out_en);
934 REG_WR(bp, port ? NIG_REG_LLFC_ENABLE_1 :
935 NIG_REG_LLFC_ENABLE_0, llfc_enable);
936 REG_WR(bp, port ? NIG_REG_PAUSE_ENABLE_1 :
937 NIG_REG_PAUSE_ENABLE_0, pause_enable);
938
939 REG_WR(bp, port ? NIG_REG_PPP_ENABLE_1 :
940 NIG_REG_PPP_ENABLE_0, ppp_enable);
941
942 REG_WR(bp, port ? NIG_REG_LLH1_XCM_MASK :
943 NIG_REG_LLH0_XCM_MASK, xcm_mask);
944
945 REG_WR(bp, NIG_REG_LLFC_EGRESS_SRC_ENABLE_0, 0x7);
946
947 /* output enable for RX_XCM # IF */
948 REG_WR(bp, NIG_REG_XCM0_OUT_EN, xcm0_out_en);
949
950 /* HW PFC TX enable */
951 REG_WR(bp, NIG_REG_P0_HWPFC_ENABLE, p0_hwpfc_enable);
952
953 /* 0x2 = BMAC, 0x1= EMAC */
954 switch (vars->mac_type) {
955 case MAC_TYPE_EMAC:
956 val = 1;
957 break;
958 case MAC_TYPE_BMAC:
959 val = 0;
960 break;
961 default:
962 val = 0;
963 break;
964 }
965 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT, val);
966
967 if (nig_params) {
968 pkt_priority_to_cos = nig_params->pkt_priority_to_cos;
969
970 REG_WR(bp, port ? NIG_REG_P1_RX_COS0_PRIORITY_MASK :
971 NIG_REG_P0_RX_COS0_PRIORITY_MASK,
972 nig_params->rx_cos0_priority_mask);
973
974 REG_WR(bp, port ? NIG_REG_P1_RX_COS1_PRIORITY_MASK :
975 NIG_REG_P0_RX_COS1_PRIORITY_MASK,
976 nig_params->rx_cos1_priority_mask);
977
978 REG_WR(bp, port ? NIG_REG_LLFC_HIGH_PRIORITY_CLASSES_1 :
979 NIG_REG_LLFC_HIGH_PRIORITY_CLASSES_0,
980 nig_params->llfc_high_priority_classes);
981
982 REG_WR(bp, port ? NIG_REG_LLFC_LOW_PRIORITY_CLASSES_1 :
983 NIG_REG_LLFC_LOW_PRIORITY_CLASSES_0,
984 nig_params->llfc_low_priority_classes);
985 }
986 REG_WR(bp, port ? NIG_REG_P1_PKT_PRIORITY_TO_COS :
987 NIG_REG_P0_PKT_PRIORITY_TO_COS,
988 pkt_priority_to_cos);
989}
990
991
992void bnx2x_update_pfc(struct link_params *params,
993 struct link_vars *vars,
994 struct bnx2x_nig_brb_pfc_port_params *pfc_params)
995{
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000996 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000997 * The PFC and pause are orthogonal to one another, meaning when
998 * PFC is enabled, the pause are disabled, and when PFC is
999 * disabled, pause are set according to the pause result.
1000 */
1001 u32 val;
1002 struct bnx2x *bp = params->bp;
1003
1004 /* update NIG params */
1005 bnx2x_update_pfc_nig(params, vars, pfc_params);
1006
1007 /* update BRB params */
1008 bnx2x_update_pfc_brb(params, vars, pfc_params);
1009
1010 if (!vars->link_up)
1011 return;
1012
1013 val = REG_RD(bp, MISC_REG_RESET_REG_2);
1014 if ((val & (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << params->port))
1015 == 0) {
1016 DP(NETIF_MSG_LINK, "About to update PFC in EMAC\n");
1017 bnx2x_emac_enable(params, vars, 0);
1018 return;
1019 }
1020
1021 DP(NETIF_MSG_LINK, "About to update PFC in BMAC\n");
1022 if (CHIP_IS_E2(bp))
1023 bnx2x_update_pfc_bmac2(params, vars, 0);
1024 else
1025 bnx2x_update_pfc_bmac1(params, vars);
1026
1027 val = 0;
1028 if ((params->feature_config_flags &
1029 FEATURE_CONFIG_PFC_ENABLED) ||
1030 (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
1031 val = 1;
1032 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + params->port*4, val);
1033}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001034
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001035static u8 bnx2x_bmac1_enable(struct link_params *params,
1036 struct link_vars *vars,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001037 u8 is_lb)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001038{
1039 struct bnx2x *bp = params->bp;
1040 u8 port = params->port;
1041 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
1042 NIG_REG_INGRESS_BMAC0_MEM;
1043 u32 wb_data[2];
1044 u32 val;
1045
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001046 DP(NETIF_MSG_LINK, "Enabling BigMAC1\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001047
1048 /* XGXS control */
1049 wb_data[0] = 0x3c;
1050 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001051 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_XGXS_CONTROL,
1052 wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001053
1054 /* tx MAC SA */
1055 wb_data[0] = ((params->mac_addr[2] << 24) |
1056 (params->mac_addr[3] << 16) |
1057 (params->mac_addr[4] << 8) |
1058 params->mac_addr[5]);
1059 wb_data[1] = ((params->mac_addr[0] << 8) |
1060 params->mac_addr[1]);
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001061 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_SOURCE_ADDR, wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001062
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001063 /* mac control */
1064 val = 0x3;
1065 if (is_lb) {
1066 val |= 0x4;
1067 DP(NETIF_MSG_LINK, "enable bmac loopback\n");
1068 }
1069 wb_data[0] = val;
1070 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001071 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL, wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001072
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001073 /* set rx mtu */
1074 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
1075 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001076 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_MAX_SIZE, wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001077
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001078 bnx2x_update_pfc_bmac1(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001079
1080 /* set tx mtu */
1081 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
1082 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001083 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_MAX_SIZE, wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001084
1085 /* set cnt max size */
1086 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
1087 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001088 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_CNT_MAX_SIZE, wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001089
1090 /* configure safc */
1091 wb_data[0] = 0x1000200;
1092 wb_data[1] = 0;
1093 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_LLFC_MSG_FLDS,
1094 wb_data, 2);
1095 /* fix for emulation */
1096 if (CHIP_REV_IS_EMUL(bp)) {
1097 wb_data[0] = 0xf000;
1098 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001099 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_PAUSE_THRESHOLD,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001100 wb_data, 2);
1101 }
1102
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001103
1104 return 0;
1105}
1106
1107static u8 bnx2x_bmac2_enable(struct link_params *params,
1108 struct link_vars *vars,
1109 u8 is_lb)
1110{
1111 struct bnx2x *bp = params->bp;
1112 u8 port = params->port;
1113 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
1114 NIG_REG_INGRESS_BMAC0_MEM;
1115 u32 wb_data[2];
1116
1117 DP(NETIF_MSG_LINK, "Enabling BigMAC2\n");
1118
1119 wb_data[0] = 0;
1120 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001121 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_BMAC_CONTROL, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001122 udelay(30);
1123
1124 /* XGXS control: Reset phy HW, MDIO registers, PHY PLL and BMAC */
1125 wb_data[0] = 0x3c;
1126 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001127 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_BMAC_XGXS_CONTROL,
1128 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001129
1130 udelay(30);
1131
1132 /* tx MAC SA */
1133 wb_data[0] = ((params->mac_addr[2] << 24) |
1134 (params->mac_addr[3] << 16) |
1135 (params->mac_addr[4] << 8) |
1136 params->mac_addr[5]);
1137 wb_data[1] = ((params->mac_addr[0] << 8) |
1138 params->mac_addr[1]);
1139 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_SOURCE_ADDR,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001140 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001141
1142 udelay(30);
1143
1144 /* Configure SAFC */
1145 wb_data[0] = 0x1000200;
1146 wb_data[1] = 0;
1147 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_LLFC_MSG_FLDS,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001148 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001149 udelay(30);
1150
1151 /* set rx mtu */
1152 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
1153 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001154 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_MAX_SIZE, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001155 udelay(30);
1156
1157 /* set tx mtu */
1158 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
1159 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001160 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_MAX_SIZE, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001161 udelay(30);
1162 /* set cnt max size */
1163 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD - 2;
1164 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001165 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_CNT_MAX_SIZE, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001166 udelay(30);
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001167 bnx2x_update_pfc_bmac2(params, vars, is_lb);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001168
1169 return 0;
1170}
1171
stephen hemminger8d962862010-10-21 07:50:56 +00001172static u8 bnx2x_bmac_enable(struct link_params *params,
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001173 struct link_vars *vars,
1174 u8 is_lb)
1175{
1176 u8 rc, port = params->port;
1177 struct bnx2x *bp = params->bp;
1178 u32 val;
1179 /* reset and unreset the BigMac */
1180 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001181 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
Yaniv Rosner1d9c05d2010-11-01 05:32:25 +00001182 msleep(1);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001183
1184 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001185 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001186
1187 /* enable access for bmac registers */
1188 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
1189
1190 /* Enable BMAC according to BMAC type*/
1191 if (CHIP_IS_E2(bp))
1192 rc = bnx2x_bmac2_enable(params, vars, is_lb);
1193 else
1194 rc = bnx2x_bmac1_enable(params, vars, is_lb);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001195 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0x1);
1196 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 0x0);
1197 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 0x0);
1198 val = 0;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001199 if ((params->feature_config_flags &
1200 FEATURE_CONFIG_PFC_ENABLED) ||
1201 (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001202 val = 1;
1203 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, val);
1204 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x0);
1205 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x0);
1206 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, 0x0);
1207 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x1);
1208 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x1);
1209
1210 vars->mac_type = MAC_TYPE_BMAC;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001211 return rc;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001212}
1213
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001214
1215static void bnx2x_update_mng(struct link_params *params, u32 link_status)
1216{
1217 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00001218
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001219 REG_WR(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001220 offsetof(struct shmem_region,
1221 port_mb[params->port].link_status), link_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001222}
1223
1224static void bnx2x_bmac_rx_disable(struct bnx2x *bp, u8 port)
1225{
1226 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001227 NIG_REG_INGRESS_BMAC0_MEM;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001228 u32 wb_data[2];
Eilon Greenstein3196a882008-08-13 15:58:49 -07001229 u32 nig_bmac_enable = REG_RD(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001230
1231 /* Only if the bmac is out of reset */
1232 if (REG_RD(bp, MISC_REG_RESET_REG_2) &
1233 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port) &&
1234 nig_bmac_enable) {
1235
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001236 if (CHIP_IS_E2(bp)) {
1237 /* Clear Rx Enable bit in BMAC_CONTROL register */
1238 REG_RD_DMAE(bp, bmac_addr +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001239 BIGMAC2_REGISTER_BMAC_CONTROL,
1240 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001241 wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
1242 REG_WR_DMAE(bp, bmac_addr +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001243 BIGMAC2_REGISTER_BMAC_CONTROL,
1244 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001245 } else {
1246 /* Clear Rx Enable bit in BMAC_CONTROL register */
1247 REG_RD_DMAE(bp, bmac_addr +
1248 BIGMAC_REGISTER_BMAC_CONTROL,
1249 wb_data, 2);
1250 wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
1251 REG_WR_DMAE(bp, bmac_addr +
1252 BIGMAC_REGISTER_BMAC_CONTROL,
1253 wb_data, 2);
1254 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001255 msleep(1);
1256 }
1257}
1258
1259static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001260 u32 line_speed)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001261{
1262 struct bnx2x *bp = params->bp;
1263 u8 port = params->port;
1264 u32 init_crd, crd;
1265 u32 count = 1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001266
1267 /* disable port */
1268 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x1);
1269
1270 /* wait for init credit */
1271 init_crd = REG_RD(bp, PBF_REG_P0_INIT_CRD + port*4);
1272 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
1273 DP(NETIF_MSG_LINK, "init_crd 0x%x crd 0x%x\n", init_crd, crd);
1274
1275 while ((init_crd != crd) && count) {
1276 msleep(5);
1277
1278 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
1279 count--;
1280 }
1281 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
1282 if (init_crd != crd) {
1283 DP(NETIF_MSG_LINK, "BUG! init_crd 0x%x != crd 0x%x\n",
1284 init_crd, crd);
1285 return -EINVAL;
1286 }
1287
David S. Millerc0700f92008-12-16 23:53:20 -08001288 if (flow_ctrl & BNX2X_FLOW_CTRL_RX ||
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001289 line_speed == SPEED_10 ||
1290 line_speed == SPEED_100 ||
1291 line_speed == SPEED_1000 ||
1292 line_speed == SPEED_2500) {
1293 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001294 /* update threshold */
1295 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, 0);
1296 /* update init credit */
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001297 init_crd = 778; /* (800-18-4) */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001298
1299 } else {
1300 u32 thresh = (ETH_MAX_JUMBO_PACKET_SIZE +
1301 ETH_OVREHEAD)/16;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001302 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001303 /* update threshold */
1304 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, thresh);
1305 /* update init credit */
1306 switch (line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001307 case SPEED_10000:
1308 init_crd = thresh + 553 - 22;
1309 break;
1310
1311 case SPEED_12000:
1312 init_crd = thresh + 664 - 22;
1313 break;
1314
1315 case SPEED_13000:
1316 init_crd = thresh + 742 - 22;
1317 break;
1318
1319 case SPEED_16000:
1320 init_crd = thresh + 778 - 22;
1321 break;
1322 default:
1323 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
1324 line_speed);
1325 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001326 }
1327 }
1328 REG_WR(bp, PBF_REG_P0_INIT_CRD + port*4, init_crd);
1329 DP(NETIF_MSG_LINK, "PBF updated to speed %d credit %d\n",
1330 line_speed, init_crd);
1331
1332 /* probe the credit changes */
1333 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x1);
1334 msleep(5);
1335 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x0);
1336
1337 /* enable port */
1338 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x0);
1339 return 0;
1340}
1341
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001342/*
1343 * get_emac_base
1344 *
1345 * @param cb
1346 * @param mdc_mdio_access
1347 * @param port
1348 *
1349 * @return u32
1350 *
1351 * This function selects the MDC/MDIO access (through emac0 or
1352 * emac1) depend on the mdc_mdio_access, port, port swapped. Each
1353 * phy has a default access mode, which could also be overridden
1354 * by nvram configuration. This parameter, whether this is the
1355 * default phy configuration, or the nvram overrun
1356 * configuration, is passed here as mdc_mdio_access and selects
1357 * the emac_base for the CL45 read/writes operations
1358 */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00001359static u32 bnx2x_get_emac_base(struct bnx2x *bp,
1360 u32 mdc_mdio_access, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001361{
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00001362 u32 emac_base = 0;
1363 switch (mdc_mdio_access) {
1364 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_PHY_TYPE:
1365 break;
1366 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC0:
1367 if (REG_RD(bp, NIG_REG_PORT_SWAP))
1368 emac_base = GRCBASE_EMAC1;
1369 else
1370 emac_base = GRCBASE_EMAC0;
1371 break;
1372 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1:
Eilon Greenstein589abe32009-02-12 08:36:55 +00001373 if (REG_RD(bp, NIG_REG_PORT_SWAP))
1374 emac_base = GRCBASE_EMAC0;
1375 else
1376 emac_base = GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001377 break;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00001378 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH:
1379 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
1380 break;
1381 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_SWAPPED:
Eilon Greenstein6378c022008-08-13 15:59:25 -07001382 emac_base = (port) ? GRCBASE_EMAC0 : GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001383 break;
1384 default:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001385 break;
1386 }
1387 return emac_base;
1388
1389}
1390
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001391/******************************************************************/
1392/* CL45 access functions */
1393/******************************************************************/
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001394u8 bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy,
1395 u8 devad, u16 reg, u16 val)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001396{
1397 u32 tmp, saved_mode;
1398 u8 i, rc = 0;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001399 /*
1400 * Set clause 45 mode, slow down the MDIO clock to 2.5MHz
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001401 * (a value of 49==0x31) and make sure that the AUTO poll is off
1402 */
Eilon Greenstein589abe32009-02-12 08:36:55 +00001403
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001404 saved_mode = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001405 tmp = saved_mode & ~(EMAC_MDIO_MODE_AUTO_POLL |
1406 EMAC_MDIO_MODE_CLOCK_CNT);
1407 tmp |= (EMAC_MDIO_MODE_CLAUSE_45 |
1408 (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001409 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, tmp);
1410 REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001411 udelay(40);
1412
1413 /* address */
1414
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001415 tmp = ((phy->addr << 21) | (devad << 16) | reg |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001416 EMAC_MDIO_COMM_COMMAND_ADDRESS |
1417 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001418 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001419
1420 for (i = 0; i < 50; i++) {
1421 udelay(10);
1422
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001423 tmp = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001424 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
1425 udelay(5);
1426 break;
1427 }
1428 }
1429 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
1430 DP(NETIF_MSG_LINK, "write phy register failed\n");
1431 rc = -EFAULT;
1432 } else {
1433 /* data */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001434 tmp = ((phy->addr << 21) | (devad << 16) | val |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001435 EMAC_MDIO_COMM_COMMAND_WRITE_45 |
1436 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001437 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001438
1439 for (i = 0; i < 50; i++) {
1440 udelay(10);
1441
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001442 tmp = REG_RD(bp, phy->mdio_ctrl +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001443 EMAC_REG_EMAC_MDIO_COMM);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001444 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
1445 udelay(5);
1446 break;
1447 }
1448 }
1449 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
1450 DP(NETIF_MSG_LINK, "write phy register failed\n");
1451 rc = -EFAULT;
1452 }
1453 }
1454
1455 /* Restore the saved mode */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001456 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001457
1458 return rc;
1459}
1460
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001461u8 bnx2x_cl45_read(struct bnx2x *bp, struct bnx2x_phy *phy,
1462 u8 devad, u16 reg, u16 *ret_val)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001463{
1464 u32 val, saved_mode;
1465 u16 i;
1466 u8 rc = 0;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001467 /*
1468 * Set clause 45 mode, slow down the MDIO clock to 2.5MHz
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001469 * (a value of 49==0x31) and make sure that the AUTO poll is off
1470 */
Eilon Greenstein589abe32009-02-12 08:36:55 +00001471
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001472 saved_mode = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
1473 val = saved_mode & ~((EMAC_MDIO_MODE_AUTO_POLL |
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001474 EMAC_MDIO_MODE_CLOCK_CNT));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001475 val |= (EMAC_MDIO_MODE_CLAUSE_45 |
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00001476 (49L << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001477 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, val);
1478 REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001479 udelay(40);
1480
1481 /* address */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001482 val = ((phy->addr << 21) | (devad << 16) | reg |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001483 EMAC_MDIO_COMM_COMMAND_ADDRESS |
1484 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001485 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001486
1487 for (i = 0; i < 50; i++) {
1488 udelay(10);
1489
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001490 val = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001491 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
1492 udelay(5);
1493 break;
1494 }
1495 }
1496 if (val & EMAC_MDIO_COMM_START_BUSY) {
1497 DP(NETIF_MSG_LINK, "read phy register failed\n");
1498
1499 *ret_val = 0;
1500 rc = -EFAULT;
1501
1502 } else {
1503 /* data */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001504 val = ((phy->addr << 21) | (devad << 16) |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001505 EMAC_MDIO_COMM_COMMAND_READ_45 |
1506 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001507 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001508
1509 for (i = 0; i < 50; i++) {
1510 udelay(10);
1511
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001512 val = REG_RD(bp, phy->mdio_ctrl +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001513 EMAC_REG_EMAC_MDIO_COMM);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001514 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
1515 *ret_val = (u16)(val & EMAC_MDIO_COMM_DATA);
1516 break;
1517 }
1518 }
1519 if (val & EMAC_MDIO_COMM_START_BUSY) {
1520 DP(NETIF_MSG_LINK, "read phy register failed\n");
1521
1522 *ret_val = 0;
1523 rc = -EFAULT;
1524 }
1525 }
1526
1527 /* Restore the saved mode */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001528 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001529
1530 return rc;
1531}
1532
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001533u8 bnx2x_phy_read(struct link_params *params, u8 phy_addr,
1534 u8 devad, u16 reg, u16 *ret_val)
1535{
1536 u8 phy_index;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001537 /*
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001538 * Probe for the phy according to the given phy_addr, and execute
1539 * the read request on it
1540 */
1541 for (phy_index = 0; phy_index < params->num_phys; phy_index++) {
1542 if (params->phy[phy_index].addr == phy_addr) {
1543 return bnx2x_cl45_read(params->bp,
1544 &params->phy[phy_index], devad,
1545 reg, ret_val);
1546 }
1547 }
1548 return -EINVAL;
1549}
1550
1551u8 bnx2x_phy_write(struct link_params *params, u8 phy_addr,
1552 u8 devad, u16 reg, u16 val)
1553{
1554 u8 phy_index;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001555 /*
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001556 * Probe for the phy according to the given phy_addr, and execute
1557 * the write request on it
1558 */
1559 for (phy_index = 0; phy_index < params->num_phys; phy_index++) {
1560 if (params->phy[phy_index].addr == phy_addr) {
1561 return bnx2x_cl45_write(params->bp,
1562 &params->phy[phy_index], devad,
1563 reg, val);
1564 }
1565 }
1566 return -EINVAL;
1567}
1568
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001569static void bnx2x_set_aer_mmd_xgxs(struct link_params *params,
1570 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001571{
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001572 u32 ser_lane;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001573 u16 offset, aer_val;
1574 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001575 ser_lane = ((params->lane_config &
1576 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
1577 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
1578
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001579 offset = phy->addr + ser_lane;
1580 if (CHIP_IS_E2(bp))
Yaniv Rosner82a0d472011-01-18 04:33:52 +00001581 aer_val = 0x3800 + offset - 1;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001582 else
1583 aer_val = 0x3800 + offset;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001584 CL22_WR_OVER_CL45(bp, phy, MDIO_REG_BANK_AER_BLOCK,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001585 MDIO_AER_BLOCK_AER_REG, aer_val);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001586}
1587static void bnx2x_set_aer_mmd_serdes(struct bnx2x *bp,
1588 struct bnx2x_phy *phy)
1589{
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001590 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001591 MDIO_REG_BANK_AER_BLOCK,
1592 MDIO_AER_BLOCK_AER_REG, 0x3800);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001593}
1594
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001595/******************************************************************/
1596/* Internal phy section */
1597/******************************************************************/
1598
1599static void bnx2x_set_serdes_access(struct bnx2x *bp, u8 port)
1600{
1601 u32 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
1602
1603 /* Set Clause 22 */
1604 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + port*0x10, 1);
1605 REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245f8000);
1606 udelay(500);
1607 REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245d000f);
1608 udelay(500);
1609 /* Set Clause 45 */
1610 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + port*0x10, 0);
1611}
1612
1613static void bnx2x_serdes_deassert(struct bnx2x *bp, u8 port)
1614{
1615 u32 val;
1616
1617 DP(NETIF_MSG_LINK, "bnx2x_serdes_deassert\n");
1618
1619 val = SERDES_RESET_BITS << (port*16);
1620
1621 /* reset and unreset the SerDes/XGXS */
1622 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR, val);
1623 udelay(500);
1624 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET, val);
1625
1626 bnx2x_set_serdes_access(bp, port);
1627
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001628 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_DEVAD + port*0x10,
1629 DEFAULT_PHY_DEV_ADDR);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001630}
1631
1632static void bnx2x_xgxs_deassert(struct link_params *params)
1633{
1634 struct bnx2x *bp = params->bp;
1635 u8 port;
1636 u32 val;
1637 DP(NETIF_MSG_LINK, "bnx2x_xgxs_deassert\n");
1638 port = params->port;
1639
1640 val = XGXS_RESET_BITS << (port*16);
1641
1642 /* reset and unreset the SerDes/XGXS */
1643 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR, val);
1644 udelay(500);
1645 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET, val);
1646
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001647 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_ST + port*0x18, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001648 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001649 params->phy[INT_PHY].def_md_devad);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001650}
1651
Yaniv Rosnera22f0782010-09-07 11:41:20 +00001652
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001653void bnx2x_link_status_update(struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001654 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001655{
1656 struct bnx2x *bp = params->bp;
1657 u8 link_10g;
1658 u8 port = params->port;
1659
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001660 vars->link_status = REG_RD(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001661 offsetof(struct shmem_region,
1662 port_mb[port].link_status));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001663
1664 vars->link_up = (vars->link_status & LINK_STATUS_LINK_UP);
1665
1666 if (vars->link_up) {
1667 DP(NETIF_MSG_LINK, "phy link up\n");
1668
1669 vars->phy_link_up = 1;
1670 vars->duplex = DUPLEX_FULL;
1671 switch (vars->link_status &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001672 LINK_STATUS_SPEED_AND_DUPLEX_MASK) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001673 case LINK_10THD:
1674 vars->duplex = DUPLEX_HALF;
1675 /* fall thru */
1676 case LINK_10TFD:
1677 vars->line_speed = SPEED_10;
1678 break;
1679
1680 case LINK_100TXHD:
1681 vars->duplex = DUPLEX_HALF;
1682 /* fall thru */
1683 case LINK_100T4:
1684 case LINK_100TXFD:
1685 vars->line_speed = SPEED_100;
1686 break;
1687
1688 case LINK_1000THD:
1689 vars->duplex = DUPLEX_HALF;
1690 /* fall thru */
1691 case LINK_1000TFD:
1692 vars->line_speed = SPEED_1000;
1693 break;
1694
1695 case LINK_2500THD:
1696 vars->duplex = DUPLEX_HALF;
1697 /* fall thru */
1698 case LINK_2500TFD:
1699 vars->line_speed = SPEED_2500;
1700 break;
1701
1702 case LINK_10GTFD:
1703 vars->line_speed = SPEED_10000;
1704 break;
1705
1706 case LINK_12GTFD:
1707 vars->line_speed = SPEED_12000;
1708 break;
1709
1710 case LINK_12_5GTFD:
1711 vars->line_speed = SPEED_12500;
1712 break;
1713
1714 case LINK_13GTFD:
1715 vars->line_speed = SPEED_13000;
1716 break;
1717
1718 case LINK_15GTFD:
1719 vars->line_speed = SPEED_15000;
1720 break;
1721
1722 case LINK_16GTFD:
1723 vars->line_speed = SPEED_16000;
1724 break;
1725
1726 default:
1727 break;
1728 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001729 vars->flow_ctrl = 0;
1730 if (vars->link_status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED)
1731 vars->flow_ctrl |= BNX2X_FLOW_CTRL_TX;
1732
1733 if (vars->link_status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED)
1734 vars->flow_ctrl |= BNX2X_FLOW_CTRL_RX;
1735
1736 if (!vars->flow_ctrl)
1737 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
1738
1739 if (vars->line_speed &&
1740 ((vars->line_speed == SPEED_10) ||
1741 (vars->line_speed == SPEED_100))) {
1742 vars->phy_flags |= PHY_SGMII_FLAG;
1743 } else {
1744 vars->phy_flags &= ~PHY_SGMII_FLAG;
1745 }
1746
1747 /* anything 10 and over uses the bmac */
1748 link_10g = ((vars->line_speed == SPEED_10000) ||
1749 (vars->line_speed == SPEED_12000) ||
1750 (vars->line_speed == SPEED_12500) ||
1751 (vars->line_speed == SPEED_13000) ||
1752 (vars->line_speed == SPEED_15000) ||
1753 (vars->line_speed == SPEED_16000));
1754 if (link_10g)
1755 vars->mac_type = MAC_TYPE_BMAC;
1756 else
1757 vars->mac_type = MAC_TYPE_EMAC;
1758
1759 } else { /* link down */
1760 DP(NETIF_MSG_LINK, "phy link down\n");
1761
1762 vars->phy_link_up = 0;
1763
1764 vars->line_speed = 0;
1765 vars->duplex = DUPLEX_FULL;
1766 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
1767
1768 /* indicate no mac active */
1769 vars->mac_type = MAC_TYPE_NONE;
1770 }
1771
1772 DP(NETIF_MSG_LINK, "link_status 0x%x phy_link_up %x\n",
1773 vars->link_status, vars->phy_link_up);
1774 DP(NETIF_MSG_LINK, "line_speed %x duplex %x flow_ctrl 0x%x\n",
1775 vars->line_speed, vars->duplex, vars->flow_ctrl);
1776}
1777
1778
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001779static void bnx2x_set_master_ln(struct link_params *params,
1780 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001781{
1782 struct bnx2x *bp = params->bp;
1783 u16 new_master_ln, ser_lane;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001784 ser_lane = ((params->lane_config &
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001785 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001786 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001787
1788 /* set the master_ln for AN */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001789 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001790 MDIO_REG_BANK_XGXS_BLOCK2,
1791 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
1792 &new_master_ln);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001793
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001794 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001795 MDIO_REG_BANK_XGXS_BLOCK2 ,
1796 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
1797 (new_master_ln | ser_lane));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001798}
1799
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001800static u8 bnx2x_reset_unicore(struct link_params *params,
1801 struct bnx2x_phy *phy,
1802 u8 set_serdes)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001803{
1804 struct bnx2x *bp = params->bp;
1805 u16 mii_control;
1806 u16 i;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001807 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001808 MDIO_REG_BANK_COMBO_IEEE0,
1809 MDIO_COMBO_IEEE0_MII_CONTROL, &mii_control);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001810
1811 /* reset the unicore */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001812 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001813 MDIO_REG_BANK_COMBO_IEEE0,
1814 MDIO_COMBO_IEEE0_MII_CONTROL,
1815 (mii_control |
1816 MDIO_COMBO_IEEO_MII_CONTROL_RESET));
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001817 if (set_serdes)
1818 bnx2x_set_serdes_access(bp, params->port);
Eilon Greensteinc1b73992009-02-12 08:37:07 +00001819
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001820 /* wait for the reset to self clear */
1821 for (i = 0; i < MDIO_ACCESS_TIMEOUT; i++) {
1822 udelay(5);
1823
1824 /* the reset erased the previous bank value */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001825 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001826 MDIO_REG_BANK_COMBO_IEEE0,
1827 MDIO_COMBO_IEEE0_MII_CONTROL,
1828 &mii_control);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001829
1830 if (!(mii_control & MDIO_COMBO_IEEO_MII_CONTROL_RESET)) {
1831 udelay(5);
1832 return 0;
1833 }
1834 }
1835
1836 DP(NETIF_MSG_LINK, "BUG! XGXS is still in reset!\n");
1837 return -EINVAL;
1838
1839}
1840
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001841static void bnx2x_set_swap_lanes(struct link_params *params,
1842 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001843{
1844 struct bnx2x *bp = params->bp;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001845 /*
1846 * Each two bits represents a lane number:
1847 * No swap is 0123 => 0x1b no need to enable the swap
1848 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001849 u16 ser_lane, rx_lane_swap, tx_lane_swap;
1850
1851 ser_lane = ((params->lane_config &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001852 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
1853 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001854 rx_lane_swap = ((params->lane_config &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001855 PORT_HW_CFG_LANE_SWAP_CFG_RX_MASK) >>
1856 PORT_HW_CFG_LANE_SWAP_CFG_RX_SHIFT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001857 tx_lane_swap = ((params->lane_config &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001858 PORT_HW_CFG_LANE_SWAP_CFG_TX_MASK) >>
1859 PORT_HW_CFG_LANE_SWAP_CFG_TX_SHIFT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001860
1861 if (rx_lane_swap != 0x1b) {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001862 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001863 MDIO_REG_BANK_XGXS_BLOCK2,
1864 MDIO_XGXS_BLOCK2_RX_LN_SWAP,
1865 (rx_lane_swap |
1866 MDIO_XGXS_BLOCK2_RX_LN_SWAP_ENABLE |
1867 MDIO_XGXS_BLOCK2_RX_LN_SWAP_FORCE_ENABLE));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001868 } else {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001869 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001870 MDIO_REG_BANK_XGXS_BLOCK2,
1871 MDIO_XGXS_BLOCK2_RX_LN_SWAP, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001872 }
1873
1874 if (tx_lane_swap != 0x1b) {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001875 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001876 MDIO_REG_BANK_XGXS_BLOCK2,
1877 MDIO_XGXS_BLOCK2_TX_LN_SWAP,
1878 (tx_lane_swap |
1879 MDIO_XGXS_BLOCK2_TX_LN_SWAP_ENABLE));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001880 } else {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001881 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001882 MDIO_REG_BANK_XGXS_BLOCK2,
1883 MDIO_XGXS_BLOCK2_TX_LN_SWAP, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001884 }
1885}
1886
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001887static void bnx2x_set_parallel_detection(struct bnx2x_phy *phy,
1888 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001889{
1890 struct bnx2x *bp = params->bp;
1891 u16 control2;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001892 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001893 MDIO_REG_BANK_SERDES_DIGITAL,
1894 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
1895 &control2);
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001896 if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
Yaniv Rosner18afb0a2009-11-05 19:18:04 +02001897 control2 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
1898 else
1899 control2 &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001900 DP(NETIF_MSG_LINK, "phy->speed_cap_mask = 0x%x, control2 = 0x%x\n",
1901 phy->speed_cap_mask, control2);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001902 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001903 MDIO_REG_BANK_SERDES_DIGITAL,
1904 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
1905 control2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001906
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001907 if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00001908 (phy->speed_cap_mask &
Yaniv Rosner18afb0a2009-11-05 19:18:04 +02001909 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001910 DP(NETIF_MSG_LINK, "XGXS\n");
1911
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001912 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001913 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1914 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK,
1915 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001916
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001917 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001918 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1919 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
1920 &control2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001921
1922
1923 control2 |=
1924 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN;
1925
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001926 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001927 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1928 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
1929 control2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001930
1931 /* Disable parallel detection of HiG */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001932 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001933 MDIO_REG_BANK_XGXS_BLOCK2,
1934 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G,
1935 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_CX4_XGXS |
1936 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_HIGIG_XGXS);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001937 }
1938}
1939
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001940static void bnx2x_set_autoneg(struct bnx2x_phy *phy,
1941 struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001942 struct link_vars *vars,
1943 u8 enable_cl73)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001944{
1945 struct bnx2x *bp = params->bp;
1946 u16 reg_val;
1947
1948 /* CL37 Autoneg */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001949 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001950 MDIO_REG_BANK_COMBO_IEEE0,
1951 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001952
1953 /* CL37 Autoneg Enabled */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001954 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001955 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_AN_EN;
1956 else /* CL37 Autoneg Disabled */
1957 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1958 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN);
1959
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001960 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001961 MDIO_REG_BANK_COMBO_IEEE0,
1962 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001963
1964 /* Enable/Disable Autodetection */
1965
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001966 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001967 MDIO_REG_BANK_SERDES_DIGITAL,
1968 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, &reg_val);
Eilon Greenstein239d6862009-08-12 08:23:04 +00001969 reg_val &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN |
1970 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT);
1971 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001972 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001973 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
1974 else
1975 reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
1976
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001977 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001978 MDIO_REG_BANK_SERDES_DIGITAL,
1979 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001980
1981 /* Enable TetonII and BAM autoneg */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001982 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001983 MDIO_REG_BANK_BAM_NEXT_PAGE,
1984 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001985 &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001986 if (vars->line_speed == SPEED_AUTO_NEG) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001987 /* Enable BAM aneg Mode and TetonII aneg Mode */
1988 reg_val |= (MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
1989 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
1990 } else {
1991 /* TetonII and BAM Autoneg Disabled */
1992 reg_val &= ~(MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
1993 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
1994 }
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001995 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001996 MDIO_REG_BANK_BAM_NEXT_PAGE,
1997 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
1998 reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001999
Eilon Greenstein239d6862009-08-12 08:23:04 +00002000 if (enable_cl73) {
2001 /* Enable Cl73 FSM status bits */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002002 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002003 MDIO_REG_BANK_CL73_USERB0,
2004 MDIO_CL73_USERB0_CL73_UCTRL,
2005 0xe);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002006
2007 /* Enable BAM Station Manager*/
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002008 CL22_WR_OVER_CL45(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00002009 MDIO_REG_BANK_CL73_USERB0,
2010 MDIO_CL73_USERB0_CL73_BAM_CTRL1,
2011 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN |
2012 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_STATION_MNGR_EN |
2013 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN);
2014
Yaniv Rosner7846e472009-11-05 19:18:07 +02002015 /* Advertise CL73 link speeds */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002016 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002017 MDIO_REG_BANK_CL73_IEEEB1,
2018 MDIO_CL73_IEEEB1_AN_ADV2,
2019 &reg_val);
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002020 if (phy->speed_cap_mask &
Yaniv Rosner7846e472009-11-05 19:18:07 +02002021 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
2022 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002023 if (phy->speed_cap_mask &
Yaniv Rosner7846e472009-11-05 19:18:07 +02002024 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
2025 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX;
Eilon Greenstein239d6862009-08-12 08:23:04 +00002026
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002027 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002028 MDIO_REG_BANK_CL73_IEEEB1,
2029 MDIO_CL73_IEEEB1_AN_ADV2,
2030 reg_val);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002031
Eilon Greenstein239d6862009-08-12 08:23:04 +00002032 /* CL73 Autoneg Enabled */
2033 reg_val = MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN;
2034
2035 } else /* CL73 Autoneg Disabled */
2036 reg_val = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002037
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002038 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002039 MDIO_REG_BANK_CL73_IEEEB0,
2040 MDIO_CL73_IEEEB0_CL73_AN_CONTROL, reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002041}
2042
2043/* program SerDes, forced speed */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002044static void bnx2x_program_serdes(struct bnx2x_phy *phy,
2045 struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002046 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002047{
2048 struct bnx2x *bp = params->bp;
2049 u16 reg_val;
2050
Eilon Greenstein57937202009-08-12 08:23:53 +00002051 /* program duplex, disable autoneg and sgmii*/
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002052 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002053 MDIO_REG_BANK_COMBO_IEEE0,
2054 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002055 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX |
Eilon Greenstein57937202009-08-12 08:23:53 +00002056 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
2057 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK);
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002058 if (phy->req_duplex == DUPLEX_FULL)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002059 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002060 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002061 MDIO_REG_BANK_COMBO_IEEE0,
2062 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002063
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002064 /*
2065 * program speed
2066 * - needed only if the speed is greater than 1G (2.5G or 10G)
2067 */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002068 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002069 MDIO_REG_BANK_SERDES_DIGITAL,
2070 MDIO_SERDES_DIGITAL_MISC1, &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002071 /* clearing the speed value before setting the right speed */
2072 DP(NETIF_MSG_LINK, "MDIO_REG_BANK_SERDES_DIGITAL = 0x%x\n", reg_val);
2073
2074 reg_val &= ~(MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_MASK |
2075 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
2076
2077 if (!((vars->line_speed == SPEED_1000) ||
2078 (vars->line_speed == SPEED_100) ||
2079 (vars->line_speed == SPEED_10))) {
2080
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002081 reg_val |= (MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_156_25M |
2082 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002083 if (vars->line_speed == SPEED_10000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002084 reg_val |=
2085 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_10G_CX4;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002086 if (vars->line_speed == SPEED_13000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002087 reg_val |=
2088 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_13G;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002089 }
2090
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002091 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002092 MDIO_REG_BANK_SERDES_DIGITAL,
2093 MDIO_SERDES_DIGITAL_MISC1, reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002094
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002095}
2096
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002097static void bnx2x_set_brcm_cl37_advertisment(struct bnx2x_phy *phy,
2098 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002099{
2100 struct bnx2x *bp = params->bp;
2101 u16 val = 0;
2102
2103 /* configure the 48 bits for BAM AN */
2104
2105 /* set extended capabilities */
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002106 if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002107 val |= MDIO_OVER_1G_UP1_2_5G;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002108 if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002109 val |= MDIO_OVER_1G_UP1_10G;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002110 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002111 MDIO_REG_BANK_OVER_1G,
2112 MDIO_OVER_1G_UP1, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002113
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002114 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002115 MDIO_REG_BANK_OVER_1G,
2116 MDIO_OVER_1G_UP3, 0x400);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002117}
2118
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002119static void bnx2x_calc_ieee_aneg_adv(struct bnx2x_phy *phy,
2120 struct link_params *params, u16 *ieee_fc)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002121{
Yaniv Rosnerd5cb9e92009-11-05 19:18:10 +02002122 struct bnx2x *bp = params->bp;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002123 *ieee_fc = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002124 /*
2125 * Resolve pause mode and advertisement.
2126 * Please refer to Table 28B-3 of the 802.3ab-1999 spec
2127 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002128
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002129 switch (phy->req_flow_ctrl) {
David S. Millerc0700f92008-12-16 23:53:20 -08002130 case BNX2X_FLOW_CTRL_AUTO:
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002131 if (params->req_fc_auto_adv == BNX2X_FLOW_CTRL_BOTH)
2132 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
2133 else
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002134 *ieee_fc |=
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002135 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002136 break;
David S. Millerc0700f92008-12-16 23:53:20 -08002137 case BNX2X_FLOW_CTRL_TX:
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002138 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002139 break;
2140
David S. Millerc0700f92008-12-16 23:53:20 -08002141 case BNX2X_FLOW_CTRL_RX:
2142 case BNX2X_FLOW_CTRL_BOTH:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002143 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002144 break;
2145
David S. Millerc0700f92008-12-16 23:53:20 -08002146 case BNX2X_FLOW_CTRL_NONE:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002147 default:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002148 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002149 break;
2150 }
Yaniv Rosnerd5cb9e92009-11-05 19:18:10 +02002151 DP(NETIF_MSG_LINK, "ieee_fc = 0x%x\n", *ieee_fc);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002152}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002153
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002154static void bnx2x_set_ieee_aneg_advertisment(struct bnx2x_phy *phy,
2155 struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002156 u16 ieee_fc)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002157{
2158 struct bnx2x *bp = params->bp;
Yaniv Rosner7846e472009-11-05 19:18:07 +02002159 u16 val;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002160 /* for AN, we are always publishing full duplex */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002161
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002162 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002163 MDIO_REG_BANK_COMBO_IEEE0,
2164 MDIO_COMBO_IEEE0_AUTO_NEG_ADV, ieee_fc);
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_CL73_IEEEB1,
2167 MDIO_CL73_IEEEB1_AN_ADV1, &val);
Yaniv Rosner7846e472009-11-05 19:18:07 +02002168 val &= ~MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_BOTH;
2169 val |= ((ieee_fc<<3) & MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002170 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002171 MDIO_REG_BANK_CL73_IEEEB1,
2172 MDIO_CL73_IEEEB1_AN_ADV1, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002173}
2174
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002175static void bnx2x_restart_autoneg(struct bnx2x_phy *phy,
2176 struct link_params *params,
2177 u8 enable_cl73)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002178{
2179 struct bnx2x *bp = params->bp;
Eilon Greenstein3a36f2e2009-02-12 08:37:09 +00002180 u16 mii_control;
Eilon Greenstein239d6862009-08-12 08:23:04 +00002181
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002182 DP(NETIF_MSG_LINK, "bnx2x_restart_autoneg\n");
Eilon Greenstein3a36f2e2009-02-12 08:37:09 +00002183 /* Enable and restart BAM/CL37 aneg */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002184
Eilon Greenstein239d6862009-08-12 08:23:04 +00002185 if (enable_cl73) {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002186 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002187 MDIO_REG_BANK_CL73_IEEEB0,
2188 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
2189 &mii_control);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002190
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002191 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002192 MDIO_REG_BANK_CL73_IEEEB0,
2193 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
2194 (mii_control |
2195 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN |
2196 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN));
Eilon Greenstein239d6862009-08-12 08:23:04 +00002197 } else {
2198
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002199 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002200 MDIO_REG_BANK_COMBO_IEEE0,
2201 MDIO_COMBO_IEEE0_MII_CONTROL,
2202 &mii_control);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002203 DP(NETIF_MSG_LINK,
2204 "bnx2x_restart_autoneg mii_control before = 0x%x\n",
2205 mii_control);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002206 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002207 MDIO_REG_BANK_COMBO_IEEE0,
2208 MDIO_COMBO_IEEE0_MII_CONTROL,
2209 (mii_control |
2210 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
2211 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN));
Eilon Greenstein239d6862009-08-12 08:23:04 +00002212 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002213}
2214
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002215static void bnx2x_initialize_sgmii_process(struct bnx2x_phy *phy,
2216 struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002217 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002218{
2219 struct bnx2x *bp = params->bp;
2220 u16 control1;
2221
2222 /* in SGMII mode, the unicore is always slave */
2223
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002224 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002225 MDIO_REG_BANK_SERDES_DIGITAL,
2226 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
2227 &control1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002228 control1 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT;
2229 /* set sgmii mode (and not fiber) */
2230 control1 &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE |
2231 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET |
2232 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_MSTR_MODE);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002233 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002234 MDIO_REG_BANK_SERDES_DIGITAL,
2235 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
2236 control1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002237
2238 /* if forced speed */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002239 if (!(vars->line_speed == SPEED_AUTO_NEG)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002240 /* set speed, disable autoneg */
2241 u16 mii_control;
2242
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002243 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002244 MDIO_REG_BANK_COMBO_IEEE0,
2245 MDIO_COMBO_IEEE0_MII_CONTROL,
2246 &mii_control);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002247 mii_control &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
2248 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK|
2249 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX);
2250
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002251 switch (vars->line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002252 case SPEED_100:
2253 mii_control |=
2254 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_100;
2255 break;
2256 case SPEED_1000:
2257 mii_control |=
2258 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_1000;
2259 break;
2260 case SPEED_10:
2261 /* there is nothing to set for 10M */
2262 break;
2263 default:
2264 /* invalid speed for SGMII */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002265 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
2266 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002267 break;
2268 }
2269
2270 /* setting the full duplex */
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002271 if (phy->req_duplex == DUPLEX_FULL)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002272 mii_control |=
2273 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002274 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002275 MDIO_REG_BANK_COMBO_IEEE0,
2276 MDIO_COMBO_IEEE0_MII_CONTROL,
2277 mii_control);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002278
2279 } else { /* AN mode */
2280 /* enable and restart AN */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002281 bnx2x_restart_autoneg(phy, params, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002282 }
2283}
2284
2285
2286/*
2287 * link management
2288 */
2289
2290static void bnx2x_pause_resolve(struct link_vars *vars, u32 pause_result)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002291{ /* LD LP */
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002292 switch (pause_result) { /* ASYM P ASYM P */
2293 case 0xb: /* 1 0 1 1 */
David S. Millerc0700f92008-12-16 23:53:20 -08002294 vars->flow_ctrl = BNX2X_FLOW_CTRL_TX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002295 break;
2296
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002297 case 0xe: /* 1 1 1 0 */
David S. Millerc0700f92008-12-16 23:53:20 -08002298 vars->flow_ctrl = BNX2X_FLOW_CTRL_RX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002299 break;
2300
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002301 case 0x5: /* 0 1 0 1 */
2302 case 0x7: /* 0 1 1 1 */
2303 case 0xd: /* 1 1 0 1 */
2304 case 0xf: /* 1 1 1 1 */
David S. Millerc0700f92008-12-16 23:53:20 -08002305 vars->flow_ctrl = BNX2X_FLOW_CTRL_BOTH;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002306 break;
2307
2308 default:
2309 break;
2310 }
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002311 if (pause_result & (1<<0))
2312 vars->link_status |= LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE;
2313 if (pause_result & (1<<1))
2314 vars->link_status |= LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002315}
2316
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002317static u8 bnx2x_direct_parallel_detect_used(struct bnx2x_phy *phy,
2318 struct link_params *params)
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02002319{
2320 struct bnx2x *bp = params->bp;
2321 u16 pd_10g, status2_1000x;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002322 if (phy->req_line_speed != SPEED_AUTO_NEG)
2323 return 0;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002324 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002325 MDIO_REG_BANK_SERDES_DIGITAL,
2326 MDIO_SERDES_DIGITAL_A_1000X_STATUS2,
2327 &status2_1000x);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002328 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002329 MDIO_REG_BANK_SERDES_DIGITAL,
2330 MDIO_SERDES_DIGITAL_A_1000X_STATUS2,
2331 &status2_1000x);
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02002332 if (status2_1000x & MDIO_SERDES_DIGITAL_A_1000X_STATUS2_AN_DISABLED) {
2333 DP(NETIF_MSG_LINK, "1G parallel detect link on port %d\n",
2334 params->port);
2335 return 1;
2336 }
2337
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002338 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002339 MDIO_REG_BANK_10G_PARALLEL_DETECT,
2340 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_STATUS,
2341 &pd_10g);
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02002342
2343 if (pd_10g & MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_STATUS_PD_LINK) {
2344 DP(NETIF_MSG_LINK, "10G parallel detect link on port %d\n",
2345 params->port);
2346 return 1;
2347 }
2348 return 0;
2349}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002350
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002351static void bnx2x_flow_ctrl_resolve(struct bnx2x_phy *phy,
2352 struct link_params *params,
2353 struct link_vars *vars,
2354 u32 gp_status)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002355{
2356 struct bnx2x *bp = params->bp;
Eilon Greenstein3196a882008-08-13 15:58:49 -07002357 u16 ld_pause; /* local driver */
2358 u16 lp_pause; /* link partner */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002359 u16 pause_result;
2360
David S. Millerc0700f92008-12-16 23:53:20 -08002361 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002362
2363 /* resolve from gp_status in case of AN complete and not sgmii */
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002364 if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO)
2365 vars->flow_ctrl = phy->req_flow_ctrl;
2366 else if (phy->req_line_speed != SPEED_AUTO_NEG)
2367 vars->flow_ctrl = params->req_fc_auto_adv;
2368 else if ((gp_status & MDIO_AN_CL73_OR_37_COMPLETE) &&
2369 (!(vars->phy_flags & PHY_SGMII_FLAG))) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002370 if (bnx2x_direct_parallel_detect_used(phy, params)) {
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02002371 vars->flow_ctrl = params->req_fc_auto_adv;
2372 return;
2373 }
Yaniv Rosner7846e472009-11-05 19:18:07 +02002374 if ((gp_status &
2375 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
2376 MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) ==
2377 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
2378 MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) {
2379
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002380 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002381 MDIO_REG_BANK_CL73_IEEEB1,
2382 MDIO_CL73_IEEEB1_AN_ADV1,
2383 &ld_pause);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002384 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002385 MDIO_REG_BANK_CL73_IEEEB1,
2386 MDIO_CL73_IEEEB1_AN_LP_ADV1,
2387 &lp_pause);
Yaniv Rosner7846e472009-11-05 19:18:07 +02002388 pause_result = (ld_pause &
2389 MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK)
2390 >> 8;
2391 pause_result |= (lp_pause &
2392 MDIO_CL73_IEEEB1_AN_LP_ADV1_PAUSE_MASK)
2393 >> 10;
2394 DP(NETIF_MSG_LINK, "pause_result CL73 0x%x\n",
2395 pause_result);
2396 } else {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002397 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002398 MDIO_REG_BANK_COMBO_IEEE0,
2399 MDIO_COMBO_IEEE0_AUTO_NEG_ADV,
2400 &ld_pause);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002401 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002402 MDIO_REG_BANK_COMBO_IEEE0,
2403 MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1,
2404 &lp_pause);
Yaniv Rosner7846e472009-11-05 19:18:07 +02002405 pause_result = (ld_pause &
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002406 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>5;
Yaniv Rosner7846e472009-11-05 19:18:07 +02002407 pause_result |= (lp_pause &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002408 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7;
Yaniv Rosner7846e472009-11-05 19:18:07 +02002409 DP(NETIF_MSG_LINK, "pause_result CL37 0x%x\n",
2410 pause_result);
2411 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002412 bnx2x_pause_resolve(vars, pause_result);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002413 }
2414 DP(NETIF_MSG_LINK, "flow_ctrl 0x%x\n", vars->flow_ctrl);
2415}
2416
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002417static void bnx2x_check_fallback_to_cl37(struct bnx2x_phy *phy,
2418 struct link_params *params)
Eilon Greenstein239d6862009-08-12 08:23:04 +00002419{
2420 struct bnx2x *bp = params->bp;
2421 u16 rx_status, ustat_val, cl37_fsm_recieved;
2422 DP(NETIF_MSG_LINK, "bnx2x_check_fallback_to_cl37\n");
2423 /* Step 1: Make sure signal is detected */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002424 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002425 MDIO_REG_BANK_RX0,
2426 MDIO_RX0_RX_STATUS,
2427 &rx_status);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002428 if ((rx_status & MDIO_RX0_RX_STATUS_SIGDET) !=
2429 (MDIO_RX0_RX_STATUS_SIGDET)) {
2430 DP(NETIF_MSG_LINK, "Signal is not detected. Restoring CL73."
2431 "rx_status(0x80b0) = 0x%x\n", rx_status);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002432 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002433 MDIO_REG_BANK_CL73_IEEEB0,
2434 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
2435 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002436 return;
2437 }
2438 /* Step 2: Check CL73 state machine */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002439 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002440 MDIO_REG_BANK_CL73_USERB0,
2441 MDIO_CL73_USERB0_CL73_USTAT1,
2442 &ustat_val);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002443 if ((ustat_val &
2444 (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK |
2445 MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) !=
2446 (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK |
2447 MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) {
2448 DP(NETIF_MSG_LINK, "CL73 state-machine is not stable. "
2449 "ustat_val(0x8371) = 0x%x\n", ustat_val);
2450 return;
2451 }
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002452 /*
2453 * Step 3: Check CL37 Message Pages received to indicate LP
2454 * supports only CL37
2455 */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002456 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002457 MDIO_REG_BANK_REMOTE_PHY,
2458 MDIO_REMOTE_PHY_MISC_RX_STATUS,
2459 &cl37_fsm_recieved);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002460 if ((cl37_fsm_recieved &
2461 (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG |
2462 MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) !=
2463 (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG |
2464 MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) {
2465 DP(NETIF_MSG_LINK, "No CL37 FSM were received. "
2466 "misc_rx_status(0x8330) = 0x%x\n",
2467 cl37_fsm_recieved);
2468 return;
2469 }
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002470 /*
2471 * The combined cl37/cl73 fsm state information indicating that
2472 * we are connected to a device which does not support cl73, but
2473 * does support cl37 BAM. In this case we disable cl73 and
2474 * restart cl37 auto-neg
2475 */
2476
Eilon Greenstein239d6862009-08-12 08:23:04 +00002477 /* Disable CL73 */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002478 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002479 MDIO_REG_BANK_CL73_IEEEB0,
2480 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
2481 0);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002482 /* Restart CL37 autoneg */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002483 bnx2x_restart_autoneg(phy, params, 0);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002484 DP(NETIF_MSG_LINK, "Disabling CL73, and restarting CL37 autoneg\n");
2485}
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002486
2487static void bnx2x_xgxs_an_resolve(struct bnx2x_phy *phy,
2488 struct link_params *params,
2489 struct link_vars *vars,
2490 u32 gp_status)
2491{
2492 if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE)
2493 vars->link_status |=
2494 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
2495
2496 if (bnx2x_direct_parallel_detect_used(phy, params))
2497 vars->link_status |=
2498 LINK_STATUS_PARALLEL_DETECTION_USED;
2499}
2500
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002501static u8 bnx2x_link_settings_status(struct bnx2x_phy *phy,
2502 struct link_params *params,
2503 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002504{
2505 struct bnx2x *bp = params->bp;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002506 u16 new_line_speed, gp_status;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002507 u8 rc = 0;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002508
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002509 /* Read gp_status */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002510 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002511 MDIO_REG_BANK_GP_STATUS,
2512 MDIO_GP_STATUS_TOP_AN_STATUS1,
2513 &gp_status);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00002514
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002515 if (phy->req_line_speed == SPEED_AUTO_NEG)
2516 vars->link_status |= LINK_STATUS_AUTO_NEGOTIATE_ENABLED;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002517 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) {
2518 DP(NETIF_MSG_LINK, "phy link up gp_status=0x%x\n",
2519 gp_status);
2520
2521 vars->phy_link_up = 1;
2522 vars->link_status |= LINK_STATUS_LINK_UP;
2523
2524 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_DUPLEX_STATUS)
2525 vars->duplex = DUPLEX_FULL;
2526 else
2527 vars->duplex = DUPLEX_HALF;
2528
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002529 if (SINGLE_MEDIA_DIRECT(params)) {
2530 bnx2x_flow_ctrl_resolve(phy, params, vars, gp_status);
2531 if (phy->req_line_speed == SPEED_AUTO_NEG)
2532 bnx2x_xgxs_an_resolve(phy, params, vars,
2533 gp_status);
2534 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002535
2536 switch (gp_status & GP_STATUS_SPEED_MASK) {
2537 case GP_STATUS_10M:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002538 new_line_speed = SPEED_10;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002539 if (vars->duplex == DUPLEX_FULL)
2540 vars->link_status |= LINK_10TFD;
2541 else
2542 vars->link_status |= LINK_10THD;
2543 break;
2544
2545 case GP_STATUS_100M:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002546 new_line_speed = SPEED_100;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002547 if (vars->duplex == DUPLEX_FULL)
2548 vars->link_status |= LINK_100TXFD;
2549 else
2550 vars->link_status |= LINK_100TXHD;
2551 break;
2552
2553 case GP_STATUS_1G:
2554 case GP_STATUS_1G_KX:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002555 new_line_speed = SPEED_1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002556 if (vars->duplex == DUPLEX_FULL)
2557 vars->link_status |= LINK_1000TFD;
2558 else
2559 vars->link_status |= LINK_1000THD;
2560 break;
2561
2562 case GP_STATUS_2_5G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002563 new_line_speed = SPEED_2500;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002564 if (vars->duplex == DUPLEX_FULL)
2565 vars->link_status |= LINK_2500TFD;
2566 else
2567 vars->link_status |= LINK_2500THD;
2568 break;
2569
2570 case GP_STATUS_5G:
2571 case GP_STATUS_6G:
2572 DP(NETIF_MSG_LINK,
2573 "link speed unsupported gp_status 0x%x\n",
2574 gp_status);
2575 return -EINVAL;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002576
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002577 case GP_STATUS_10G_KX4:
2578 case GP_STATUS_10G_HIG:
2579 case GP_STATUS_10G_CX4:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002580 new_line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002581 vars->link_status |= LINK_10GTFD;
2582 break;
2583
2584 case GP_STATUS_12G_HIG:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002585 new_line_speed = SPEED_12000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002586 vars->link_status |= LINK_12GTFD;
2587 break;
2588
2589 case GP_STATUS_12_5G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002590 new_line_speed = SPEED_12500;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002591 vars->link_status |= LINK_12_5GTFD;
2592 break;
2593
2594 case GP_STATUS_13G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002595 new_line_speed = SPEED_13000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002596 vars->link_status |= LINK_13GTFD;
2597 break;
2598
2599 case GP_STATUS_15G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002600 new_line_speed = SPEED_15000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002601 vars->link_status |= LINK_15GTFD;
2602 break;
2603
2604 case GP_STATUS_16G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002605 new_line_speed = SPEED_16000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002606 vars->link_status |= LINK_16GTFD;
2607 break;
2608
2609 default:
2610 DP(NETIF_MSG_LINK,
2611 "link speed unsupported gp_status 0x%x\n",
2612 gp_status);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002613 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002614 }
2615
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002616 vars->line_speed = new_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002617
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002618 } else { /* link_down */
2619 DP(NETIF_MSG_LINK, "phy link down\n");
2620
2621 vars->phy_link_up = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002622
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002623 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08002624 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002625 vars->mac_type = MAC_TYPE_NONE;
Eilon Greenstein239d6862009-08-12 08:23:04 +00002626
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002627 if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
2628 SINGLE_MEDIA_DIRECT(params)) {
Eilon Greenstein239d6862009-08-12 08:23:04 +00002629 /* Check signal is detected */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002630 bnx2x_check_fallback_to_cl37(phy, params);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002631 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002632 }
2633
Frans Pop2381a552010-03-24 07:57:36 +00002634 DP(NETIF_MSG_LINK, "gp_status 0x%x phy_link_up %x line_speed %x\n",
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002635 gp_status, vars->phy_link_up, vars->line_speed);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002636 DP(NETIF_MSG_LINK, "duplex %x flow_ctrl 0x%x link_status 0x%x\n",
2637 vars->duplex, vars->flow_ctrl, vars->link_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002638 return rc;
2639}
2640
Eilon Greensteined8680a2009-02-12 08:37:12 +00002641static void bnx2x_set_gmii_tx_driver(struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002642{
2643 struct bnx2x *bp = params->bp;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002644 struct bnx2x_phy *phy = &params->phy[INT_PHY];
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002645 u16 lp_up2;
2646 u16 tx_driver;
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00002647 u16 bank;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002648
2649 /* read precomp */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002650 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002651 MDIO_REG_BANK_OVER_1G,
2652 MDIO_OVER_1G_LP_UP2, &lp_up2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002653
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002654 /* bits [10:7] at lp_up2, positioned at [15:12] */
2655 lp_up2 = (((lp_up2 & MDIO_OVER_1G_LP_UP2_PREEMPHASIS_MASK) >>
2656 MDIO_OVER_1G_LP_UP2_PREEMPHASIS_SHIFT) <<
2657 MDIO_TX0_TX_DRIVER_PREEMPHASIS_SHIFT);
2658
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00002659 if (lp_up2 == 0)
2660 return;
2661
2662 for (bank = MDIO_REG_BANK_TX0; bank <= MDIO_REG_BANK_TX3;
2663 bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0)) {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002664 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002665 bank,
2666 MDIO_TX0_TX_DRIVER, &tx_driver);
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00002667
2668 /* replace tx_driver bits [15:12] */
2669 if (lp_up2 !=
2670 (tx_driver & MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK)) {
2671 tx_driver &= ~MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK;
2672 tx_driver |= lp_up2;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002673 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002674 bank,
2675 MDIO_TX0_TX_DRIVER, tx_driver);
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00002676 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002677 }
2678}
2679
2680static u8 bnx2x_emac_program(struct link_params *params,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002681 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002682{
2683 struct bnx2x *bp = params->bp;
2684 u8 port = params->port;
2685 u16 mode = 0;
2686
2687 DP(NETIF_MSG_LINK, "setting link speed & duplex\n");
2688 bnx2x_bits_dis(bp, GRCBASE_EMAC0 + port*0x400 +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002689 EMAC_REG_EMAC_MODE,
2690 (EMAC_MODE_25G_MODE |
2691 EMAC_MODE_PORT_MII_10M |
2692 EMAC_MODE_HALF_DUPLEX));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002693 switch (vars->line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002694 case SPEED_10:
2695 mode |= EMAC_MODE_PORT_MII_10M;
2696 break;
2697
2698 case SPEED_100:
2699 mode |= EMAC_MODE_PORT_MII;
2700 break;
2701
2702 case SPEED_1000:
2703 mode |= EMAC_MODE_PORT_GMII;
2704 break;
2705
2706 case SPEED_2500:
2707 mode |= (EMAC_MODE_25G_MODE | EMAC_MODE_PORT_GMII);
2708 break;
2709
2710 default:
2711 /* 10G not valid for EMAC */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002712 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
2713 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002714 return -EINVAL;
2715 }
2716
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002717 if (vars->duplex == DUPLEX_HALF)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002718 mode |= EMAC_MODE_HALF_DUPLEX;
2719 bnx2x_bits_en(bp,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002720 GRCBASE_EMAC0 + port*0x400 + EMAC_REG_EMAC_MODE,
2721 mode);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002722
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00002723 bnx2x_set_led(params, vars, LED_MODE_OPER, vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002724 return 0;
2725}
2726
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002727static void bnx2x_set_preemphasis(struct bnx2x_phy *phy,
2728 struct link_params *params)
2729{
2730
2731 u16 bank, i = 0;
2732 struct bnx2x *bp = params->bp;
2733
2734 for (bank = MDIO_REG_BANK_RX0, i = 0; bank <= MDIO_REG_BANK_RX3;
2735 bank += (MDIO_REG_BANK_RX1-MDIO_REG_BANK_RX0), i++) {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002736 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002737 bank,
2738 MDIO_RX0_RX_EQ_BOOST,
2739 phy->rx_preemphasis[i]);
2740 }
2741
2742 for (bank = MDIO_REG_BANK_TX0, i = 0; bank <= MDIO_REG_BANK_TX3;
2743 bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0), i++) {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002744 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002745 bank,
2746 MDIO_TX0_TX_DRIVER,
2747 phy->tx_preemphasis[i]);
2748 }
2749}
2750
2751static void bnx2x_init_internal_phy(struct bnx2x_phy *phy,
2752 struct link_params *params,
2753 struct link_vars *vars)
2754{
2755 struct bnx2x *bp = params->bp;
2756 u8 enable_cl73 = (SINGLE_MEDIA_DIRECT(params) ||
2757 (params->loopback_mode == LOOPBACK_XGXS));
2758 if (!(vars->phy_flags & PHY_SGMII_FLAG)) {
2759 if (SINGLE_MEDIA_DIRECT(params) &&
2760 (params->feature_config_flags &
2761 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED))
2762 bnx2x_set_preemphasis(phy, params);
2763
2764 /* forced speed requested? */
2765 if (vars->line_speed != SPEED_AUTO_NEG ||
2766 (SINGLE_MEDIA_DIRECT(params) &&
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002767 params->loopback_mode == LOOPBACK_EXT)) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002768 DP(NETIF_MSG_LINK, "not SGMII, no AN\n");
2769
2770 /* disable autoneg */
2771 bnx2x_set_autoneg(phy, params, vars, 0);
2772
2773 /* program speed and duplex */
2774 bnx2x_program_serdes(phy, params, vars);
2775
2776 } else { /* AN_mode */
2777 DP(NETIF_MSG_LINK, "not SGMII, AN\n");
2778
2779 /* AN enabled */
2780 bnx2x_set_brcm_cl37_advertisment(phy, params);
2781
2782 /* program duplex & pause advertisement (for aneg) */
2783 bnx2x_set_ieee_aneg_advertisment(phy, params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002784 vars->ieee_fc);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002785
2786 /* enable autoneg */
2787 bnx2x_set_autoneg(phy, params, vars, enable_cl73);
2788
2789 /* enable and restart AN */
2790 bnx2x_restart_autoneg(phy, params, enable_cl73);
2791 }
2792
2793 } else { /* SGMII mode */
2794 DP(NETIF_MSG_LINK, "SGMII\n");
2795
2796 bnx2x_initialize_sgmii_process(phy, params, vars);
2797 }
2798}
2799
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002800static u8 bnx2x_init_serdes(struct bnx2x_phy *phy,
2801 struct link_params *params,
2802 struct link_vars *vars)
2803{
2804 u8 rc;
2805 vars->phy_flags |= PHY_SGMII_FLAG;
2806 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002807 bnx2x_set_aer_mmd_serdes(params->bp, phy);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002808 rc = bnx2x_reset_unicore(params, phy, 1);
2809 /* reset the SerDes and wait for reset bit return low */
2810 if (rc != 0)
2811 return rc;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002812 bnx2x_set_aer_mmd_serdes(params->bp, phy);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002813
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002814 return rc;
2815}
2816
2817static u8 bnx2x_init_xgxs(struct bnx2x_phy *phy,
2818 struct link_params *params,
2819 struct link_vars *vars)
2820{
2821 u8 rc;
2822 vars->phy_flags = PHY_XGXS_FLAG;
2823 if ((phy->req_line_speed &&
2824 ((phy->req_line_speed == SPEED_100) ||
2825 (phy->req_line_speed == SPEED_10))) ||
2826 (!phy->req_line_speed &&
2827 (phy->speed_cap_mask >=
2828 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL) &&
2829 (phy->speed_cap_mask <
2830 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
2831 ))
2832 vars->phy_flags |= PHY_SGMII_FLAG;
2833 else
2834 vars->phy_flags &= ~PHY_SGMII_FLAG;
2835
2836 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002837 bnx2x_set_aer_mmd_xgxs(params, phy);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002838 bnx2x_set_master_ln(params, phy);
2839
2840 rc = bnx2x_reset_unicore(params, phy, 0);
2841 /* reset the SerDes and wait for reset bit return low */
2842 if (rc != 0)
2843 return rc;
2844
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002845 bnx2x_set_aer_mmd_xgxs(params, phy);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002846
2847 /* setting the masterLn_def again after the reset */
2848 bnx2x_set_master_ln(params, phy);
2849 bnx2x_set_swap_lanes(params, phy);
2850
2851 return rc;
2852}
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002853
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002854static u16 bnx2x_wait_reset_complete(struct bnx2x *bp,
2855 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002856{
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002857 u16 cnt, ctrl;
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002858 /* Wait for soft reset to get cleared upto 1 sec */
2859 for (cnt = 0; cnt < 1000; cnt++) {
2860 bnx2x_cl45_read(bp, phy,
2861 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, &ctrl);
2862 if (!(ctrl & (1<<15)))
2863 break;
2864 msleep(1);
2865 }
2866 DP(NETIF_MSG_LINK, "control reg 0x%x (after %d ms)\n", ctrl, cnt);
2867 return cnt;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002868}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002869
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002870static void bnx2x_link_int_enable(struct link_params *params)
2871{
2872 u8 port = params->port;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002873 u32 mask;
2874 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002875
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002876 /* Setting the status to report on link up for either XGXS or SerDes */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002877 if (params->switch_cfg == SWITCH_CFG_10G) {
2878 mask = (NIG_MASK_XGXS0_LINK10G |
2879 NIG_MASK_XGXS0_LINK_STATUS);
2880 DP(NETIF_MSG_LINK, "enabled XGXS interrupt\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002881 if (!(SINGLE_MEDIA_DIRECT(params)) &&
2882 params->phy[INT_PHY].type !=
2883 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002884 mask |= NIG_MASK_MI_INT;
2885 DP(NETIF_MSG_LINK, "enabled external phy int\n");
2886 }
2887
2888 } else { /* SerDes */
2889 mask = NIG_MASK_SERDES0_LINK_STATUS;
2890 DP(NETIF_MSG_LINK, "enabled SerDes interrupt\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002891 if (!(SINGLE_MEDIA_DIRECT(params)) &&
2892 params->phy[INT_PHY].type !=
2893 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_NOT_CONN) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002894 mask |= NIG_MASK_MI_INT;
2895 DP(NETIF_MSG_LINK, "enabled external phy int\n");
2896 }
2897 }
2898 bnx2x_bits_en(bp,
2899 NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
2900 mask);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002901
2902 DP(NETIF_MSG_LINK, "port %x, is_xgxs %x, int_status 0x%x\n", port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002903 (params->switch_cfg == SWITCH_CFG_10G),
2904 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002905 DP(NETIF_MSG_LINK, " int_mask 0x%x, MI_INT %x, SERDES_LINK %x\n",
2906 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
2907 REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
2908 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS+port*0x3c));
2909 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
2910 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
2911 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
2912}
2913
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002914static void bnx2x_rearm_latch_signal(struct bnx2x *bp, u8 port,
2915 u8 exp_mi_int)
Eilon Greenstein2f904462009-08-12 08:22:16 +00002916{
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002917 u32 latch_status = 0;
2918
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002919 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002920 * Disable the MI INT ( external phy int ) by writing 1 to the
2921 * status register. Link down indication is high-active-signal,
2922 * so in this case we need to write the status to clear the XOR
Eilon Greenstein2f904462009-08-12 08:22:16 +00002923 */
2924 /* Read Latched signals */
2925 latch_status = REG_RD(bp,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002926 NIG_REG_LATCH_STATUS_0 + port*8);
2927 DP(NETIF_MSG_LINK, "latch_status = 0x%x\n", latch_status);
Eilon Greenstein2f904462009-08-12 08:22:16 +00002928 /* Handle only those with latched-signal=up.*/
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002929 if (exp_mi_int)
2930 bnx2x_bits_en(bp,
2931 NIG_REG_STATUS_INTERRUPT_PORT0
2932 + port*4,
2933 NIG_STATUS_EMAC0_MI_INT);
2934 else
2935 bnx2x_bits_dis(bp,
2936 NIG_REG_STATUS_INTERRUPT_PORT0
2937 + port*4,
2938 NIG_STATUS_EMAC0_MI_INT);
2939
Eilon Greenstein2f904462009-08-12 08:22:16 +00002940 if (latch_status & 1) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002941
Eilon Greenstein2f904462009-08-12 08:22:16 +00002942 /* For all latched-signal=up : Re-Arm Latch signals */
2943 REG_WR(bp, NIG_REG_LATCH_STATUS_0 + port*8,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002944 (latch_status & 0xfffe) | (latch_status & 1));
Eilon Greenstein2f904462009-08-12 08:22:16 +00002945 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002946 /* For all latched-signal=up,Write original_signal to status */
Eilon Greenstein2f904462009-08-12 08:22:16 +00002947}
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002948
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002949static void bnx2x_link_int_ack(struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002950 struct link_vars *vars, u8 is_10g)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002951{
2952 struct bnx2x *bp = params->bp;
2953 u8 port = params->port;
2954
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002955 /*
2956 * First reset all status we assume only one line will be
2957 * change at a time
2958 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002959 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002960 (NIG_STATUS_XGXS0_LINK10G |
2961 NIG_STATUS_XGXS0_LINK_STATUS |
2962 NIG_STATUS_SERDES0_LINK_STATUS));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002963 if (vars->phy_link_up) {
2964 if (is_10g) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002965 /*
2966 * Disable the 10G link interrupt by writing 1 to the
2967 * status register
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002968 */
2969 DP(NETIF_MSG_LINK, "10G XGXS phy link up\n");
2970 bnx2x_bits_en(bp,
2971 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
2972 NIG_STATUS_XGXS0_LINK10G);
2973
2974 } else if (params->switch_cfg == SWITCH_CFG_10G) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002975 /*
2976 * Disable the link interrupt by writing 1 to the
2977 * relevant lane in the status register
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002978 */
2979 u32 ser_lane = ((params->lane_config &
2980 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
2981 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
2982
Eilon Greenstein2f904462009-08-12 08:22:16 +00002983 DP(NETIF_MSG_LINK, "%d speed XGXS phy link up\n",
2984 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002985 bnx2x_bits_en(bp,
2986 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
2987 ((1 << ser_lane) <<
2988 NIG_STATUS_XGXS0_LINK_STATUS_SIZE));
2989
2990 } else { /* SerDes */
2991 DP(NETIF_MSG_LINK, "SerDes phy link up\n");
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002992 /*
2993 * Disable the link interrupt by writing 1 to the status
2994 * register
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002995 */
2996 bnx2x_bits_en(bp,
2997 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
2998 NIG_STATUS_SERDES0_LINK_STATUS);
2999 }
3000
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003001 }
3002}
3003
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003004static u8 bnx2x_format_ver(u32 num, u8 *str, u16 *len)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003005{
3006 u8 *str_ptr = str;
3007 u32 mask = 0xf0000000;
3008 u8 shift = 8*4;
3009 u8 digit;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003010 u8 remove_leading_zeros = 1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003011 if (*len < 10) {
Frederik Schwarzer025dfda2008-10-16 19:02:37 +02003012 /* Need more than 10chars for this format */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003013 *str_ptr = '\0';
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003014 (*len)--;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003015 return -EINVAL;
3016 }
3017 while (shift > 0) {
3018
3019 shift -= 4;
3020 digit = ((num & mask) >> shift);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003021 if (digit == 0 && remove_leading_zeros) {
3022 mask = mask >> 4;
3023 continue;
3024 } else if (digit < 0xa)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003025 *str_ptr = digit + '0';
3026 else
3027 *str_ptr = digit - 0xa + 'a';
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003028 remove_leading_zeros = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003029 str_ptr++;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003030 (*len)--;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003031 mask = mask >> 4;
3032 if (shift == 4*4) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003033 *str_ptr = '.';
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003034 str_ptr++;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003035 (*len)--;
3036 remove_leading_zeros = 1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003037 }
3038 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003039 return 0;
3040}
3041
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003042
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003043static u8 bnx2x_null_format_ver(u32 spirom_ver, u8 *str, u16 *len)
3044{
3045 str[0] = '\0';
3046 (*len)--;
3047 return 0;
3048}
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003049
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003050u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
3051 u8 *version, u16 len)
3052{
Julia Lawall0376d5b2009-07-19 05:26:35 +00003053 struct bnx2x *bp;
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003054 u32 spirom_ver = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003055 u8 status = 0;
3056 u8 *ver_p = version;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003057 u16 remain_len = len;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003058 if (version == NULL || params == NULL)
3059 return -EINVAL;
Julia Lawall0376d5b2009-07-19 05:26:35 +00003060 bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003061
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003062 /* Extract first external phy*/
3063 version[0] = '\0';
3064 spirom_ver = REG_RD(bp, params->phy[EXT_PHY1].ver_addr);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003065
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003066 if (params->phy[EXT_PHY1].format_fw_ver) {
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003067 status |= params->phy[EXT_PHY1].format_fw_ver(spirom_ver,
3068 ver_p,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003069 &remain_len);
3070 ver_p += (len - remain_len);
3071 }
3072 if ((params->num_phys == MAX_PHYS) &&
3073 (params->phy[EXT_PHY2].ver_addr != 0)) {
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003074 spirom_ver = REG_RD(bp, params->phy[EXT_PHY2].ver_addr);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003075 if (params->phy[EXT_PHY2].format_fw_ver) {
3076 *ver_p = '/';
3077 ver_p++;
3078 remain_len--;
3079 status |= params->phy[EXT_PHY2].format_fw_ver(
3080 spirom_ver,
3081 ver_p,
3082 &remain_len);
3083 ver_p = version + (len - remain_len);
3084 }
3085 }
3086 *ver_p = '\0';
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003087 return status;
3088}
3089
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003090static void bnx2x_set_xgxs_loopback(struct bnx2x_phy *phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003091 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003092{
3093 u8 port = params->port;
3094 struct bnx2x *bp = params->bp;
3095
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003096 if (phy->req_line_speed != SPEED_1000) {
Eilon Greenstein6378c022008-08-13 15:59:25 -07003097 u32 md_devad;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003098
3099 DP(NETIF_MSG_LINK, "XGXS 10G loopback enable\n");
3100
3101 /* change the uni_phy_addr in the nig */
3102 md_devad = REG_RD(bp, (NIG_REG_XGXS0_CTRL_MD_DEVAD +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003103 port*0x18));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003104
3105 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, 0x5);
3106
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003107 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003108 5,
3109 (MDIO_REG_BANK_AER_BLOCK +
3110 (MDIO_AER_BLOCK_AER_REG & 0xf)),
3111 0x2800);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003112
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003113 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003114 5,
3115 (MDIO_REG_BANK_CL73_IEEEB0 +
3116 (MDIO_CL73_IEEEB0_CL73_AN_CONTROL & 0xf)),
3117 0x6041);
Eilon Greenstein38582762009-01-14 06:44:16 +00003118 msleep(200);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003119 /* set aer mmd back */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00003120 bnx2x_set_aer_mmd_xgxs(params, phy);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003121
3122 /* and md_devad */
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003123 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, md_devad);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003124 } else {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003125 u16 mii_ctrl;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003126 DP(NETIF_MSG_LINK, "XGXS 1G loopback enable\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003127 bnx2x_cl45_read(bp, phy, 5,
3128 (MDIO_REG_BANK_COMBO_IEEE0 +
3129 (MDIO_COMBO_IEEE0_MII_CONTROL & 0xf)),
3130 &mii_ctrl);
3131 bnx2x_cl45_write(bp, phy, 5,
3132 (MDIO_REG_BANK_COMBO_IEEE0 +
3133 (MDIO_COMBO_IEEE0_MII_CONTROL & 0xf)),
3134 mii_ctrl |
3135 MDIO_COMBO_IEEO_MII_CONTROL_LOOPBACK);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003136 }
3137}
3138
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003139u8 bnx2x_set_led(struct link_params *params,
3140 struct link_vars *vars, u8 mode, u32 speed)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003141{
Yaniv Rosner7846e472009-11-05 19:18:07 +02003142 u8 port = params->port;
3143 u16 hw_led_mode = params->hw_led_mode;
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003144 u8 rc = 0, phy_idx;
Eilon Greenstein345b5d52008-08-13 15:58:12 -07003145 u32 tmp;
3146 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Yaniv Rosner7846e472009-11-05 19:18:07 +02003147 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003148 DP(NETIF_MSG_LINK, "bnx2x_set_led: port %x, mode %d\n", port, mode);
3149 DP(NETIF_MSG_LINK, "speed 0x%x, hw_led_mode 0x%x\n",
3150 speed, hw_led_mode);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003151 /* In case */
3152 for (phy_idx = EXT_PHY1; phy_idx < MAX_PHYS; phy_idx++) {
3153 if (params->phy[phy_idx].set_link_led) {
3154 params->phy[phy_idx].set_link_led(
3155 &params->phy[phy_idx], params, mode);
3156 }
3157 }
3158
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003159 switch (mode) {
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003160 case LED_MODE_FRONT_PANEL_OFF:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003161 case LED_MODE_OFF:
3162 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 0);
3163 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003164 SHARED_HW_CFG_LED_MAC1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07003165
3166 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07003167 EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp | EMAC_LED_OVERRIDE));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003168 break;
3169
3170 case LED_MODE_OPER:
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003171 /*
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003172 * For all other phys, OPER mode is same as ON, so in case
3173 * link is down, do nothing
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003174 */
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003175 if (!vars->link_up)
3176 break;
3177 case LED_MODE_ON:
Yaniv Rosner1f483532011-01-18 04:33:31 +00003178 if (params->phy[EXT_PHY1].type ==
3179 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727 &&
3180 CHIP_IS_E2(bp) && params->num_phys == 2) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003181 /*
3182 * This is a work-around for E2+8727 Configurations
3183 */
Yaniv Rosner1f483532011-01-18 04:33:31 +00003184 if (mode == LED_MODE_ON ||
3185 speed == SPEED_10000){
3186 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0);
3187 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1);
3188
3189 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
3190 EMAC_WR(bp, EMAC_REG_EMAC_LED,
3191 (tmp | EMAC_LED_OVERRIDE));
3192 return rc;
3193 }
3194 } else if (SINGLE_MEDIA_DIRECT(params)) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003195 /*
3196 * This is a work-around for HW issue found when link
3197 * is up in CL73
3198 */
Yaniv Rosner7846e472009-11-05 19:18:07 +02003199 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0);
3200 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1);
3201 } else {
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003202 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, hw_led_mode);
Yaniv Rosner7846e472009-11-05 19:18:07 +02003203 }
3204
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003205 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 + port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003206 /* Set blinking rate to ~15.9Hz */
3207 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003208 LED_BLINK_RATE_VAL);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003209 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003210 port*4, 1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07003211 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003212 EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp & (~EMAC_LED_OVERRIDE)));
Eilon Greenstein345b5d52008-08-13 15:58:12 -07003213
Yaniv Rosner7846e472009-11-05 19:18:07 +02003214 if (CHIP_IS_E1(bp) &&
Eilon Greenstein34f80b02008-06-23 20:33:01 -07003215 ((speed == SPEED_2500) ||
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003216 (speed == SPEED_1000) ||
3217 (speed == SPEED_100) ||
3218 (speed == SPEED_10))) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003219 /*
3220 * On Everest 1 Ax chip versions for speeds less than
3221 * 10G LED scheme is different
3222 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003223 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003224 + port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003225 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003226 port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003227 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_TRAFFIC_P0 +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003228 port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003229 }
3230 break;
3231
3232 default:
3233 rc = -EINVAL;
3234 DP(NETIF_MSG_LINK, "bnx2x_set_led: Invalid led mode %d\n",
3235 mode);
3236 break;
3237 }
3238 return rc;
3239
3240}
3241
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003242/*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003243 * This function comes to reflect the actual link state read DIRECTLY from the
3244 * HW
3245 */
3246u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars,
3247 u8 is_serdes)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003248{
3249 struct bnx2x *bp = params->bp;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003250 u16 gp_status = 0, phy_index = 0;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003251 u8 ext_phy_link_up = 0, serdes_phy_type;
3252 struct link_vars temp_vars;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003253
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003254 CL22_RD_OVER_CL45(bp, &params->phy[INT_PHY],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003255 MDIO_REG_BANK_GP_STATUS,
3256 MDIO_GP_STATUS_TOP_AN_STATUS1,
3257 &gp_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003258 /* link is up only if both local phy and external phy are up */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003259 if (!(gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS))
3260 return -ESRCH;
3261
3262 switch (params->num_phys) {
3263 case 1:
3264 /* No external PHY */
3265 return 0;
3266 case 2:
3267 ext_phy_link_up = params->phy[EXT_PHY1].read_status(
3268 &params->phy[EXT_PHY1],
3269 params, &temp_vars);
3270 break;
3271 case 3: /* Dual Media */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003272 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
3273 phy_index++) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003274 serdes_phy_type = ((params->phy[phy_index].media_type ==
3275 ETH_PHY_SFP_FIBER) ||
3276 (params->phy[phy_index].media_type ==
3277 ETH_PHY_XFP_FIBER));
3278
3279 if (is_serdes != serdes_phy_type)
3280 continue;
3281 if (params->phy[phy_index].read_status) {
3282 ext_phy_link_up |=
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003283 params->phy[phy_index].read_status(
3284 &params->phy[phy_index],
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003285 params, &temp_vars);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003286 }
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003287 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003288 break;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003289 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003290 if (ext_phy_link_up)
3291 return 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003292 return -ESRCH;
3293}
3294
3295static u8 bnx2x_link_initialize(struct link_params *params,
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00003296 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003297{
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003298 u8 rc = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003299 u8 phy_index, non_ext_phy;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003300 struct bnx2x *bp = params->bp;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003301 /*
3302 * In case of external phy existence, the line speed would be the
3303 * line speed linked up by the external phy. In case it is direct
3304 * only, then the line_speed during initialization will be
3305 * equal to the req_line_speed
3306 */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003307 vars->line_speed = params->phy[INT_PHY].req_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003308
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003309 /*
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003310 * Initialize the internal phy in case this is a direct board
3311 * (no external phys), or this board has external phy which requires
3312 * to first.
3313 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003314
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003315 if (params->phy[INT_PHY].config_init)
3316 params->phy[INT_PHY].config_init(
3317 &params->phy[INT_PHY],
3318 params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003319
3320 /* init ext phy and enable link state int */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003321 non_ext_phy = (SINGLE_MEDIA_DIRECT(params) ||
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003322 (params->loopback_mode == LOOPBACK_XGXS));
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003323
3324 if (non_ext_phy ||
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003325 (params->phy[EXT_PHY1].flags & FLAGS_INIT_XGXS_FIRST) ||
Eilon Greenstein8660d8c2009-03-02 08:01:02 +00003326 (params->loopback_mode == LOOPBACK_EXT_PHY)) {
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003327 struct bnx2x_phy *phy = &params->phy[INT_PHY];
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003328 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003329 bnx2x_set_parallel_detection(phy, params);
3330 bnx2x_init_internal_phy(phy, params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003331 }
3332
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003333 /* Init external phy*/
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003334 if (!non_ext_phy)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003335 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
3336 phy_index++) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003337 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003338 * No need to initialize second phy in case of first
3339 * phy only selection. In case of second phy, we do
3340 * need to initialize the first phy, since they are
3341 * connected.
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003342 */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003343 if (phy_index == EXT_PHY2 &&
3344 (bnx2x_phy_selection(params) ==
3345 PORT_HW_CFG_PHY_SELECTION_FIRST_PHY)) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003346 DP(NETIF_MSG_LINK, "Ignoring second phy\n");
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003347 continue;
3348 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003349 params->phy[phy_index].config_init(
3350 &params->phy[phy_index],
3351 params, vars);
3352 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003353
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00003354 /* Reset the interrupt indication after phy was initialized */
3355 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 +
3356 params->port*4,
3357 (NIG_STATUS_XGXS0_LINK10G |
3358 NIG_STATUS_XGXS0_LINK_STATUS |
3359 NIG_STATUS_SERDES0_LINK_STATUS |
3360 NIG_MASK_MI_INT));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003361 return rc;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003362}
3363
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003364static void bnx2x_int_link_reset(struct bnx2x_phy *phy,
3365 struct link_params *params)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003366{
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003367 /* reset the SerDes/XGXS */
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003368 REG_WR(params->bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
3369 (0x1ff << (params->port*16)));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003370}
3371
3372static void bnx2x_common_ext_link_reset(struct bnx2x_phy *phy,
3373 struct link_params *params)
3374{
3375 struct bnx2x *bp = params->bp;
3376 u8 gpio_port;
3377 /* HW reset */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00003378 if (CHIP_IS_E2(bp))
3379 gpio_port = BP_PATH(bp);
3380 else
3381 gpio_port = params->port;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003382 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003383 MISC_REGISTERS_GPIO_OUTPUT_LOW,
3384 gpio_port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003385 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003386 MISC_REGISTERS_GPIO_OUTPUT_LOW,
3387 gpio_port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003388 DP(NETIF_MSG_LINK, "reset external PHY\n");
3389}
3390
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003391static u8 bnx2x_update_link_down(struct link_params *params,
3392 struct link_vars *vars)
3393{
3394 struct bnx2x *bp = params->bp;
3395 u8 port = params->port;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00003396
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003397 DP(NETIF_MSG_LINK, "Port %x: Link is down\n", port);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003398 bnx2x_set_led(params, vars, LED_MODE_OFF, 0);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003399
3400 /* indicate no mac active */
3401 vars->mac_type = MAC_TYPE_NONE;
3402
3403 /* update shared memory */
3404 vars->link_status = 0;
3405 vars->line_speed = 0;
3406 bnx2x_update_mng(params, vars->link_status);
3407
3408 /* activate nig drain */
3409 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
3410
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00003411 /* disable emac */
3412 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
3413
3414 msleep(10);
3415
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003416 /* reset BigMac */
3417 bnx2x_bmac_rx_disable(bp, params->port);
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003418 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
3419 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003420 return 0;
3421}
3422
3423static u8 bnx2x_update_link_up(struct link_params *params,
3424 struct link_vars *vars,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003425 u8 link_10g)
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003426{
3427 struct bnx2x *bp = params->bp;
3428 u8 port = params->port;
3429 u8 rc = 0;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00003430
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003431 vars->link_status |= LINK_STATUS_LINK_UP;
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003432
Yaniv Rosner7aa07112010-09-07 11:41:01 +00003433 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
3434 vars->link_status |=
3435 LINK_STATUS_TX_FLOW_CONTROL_ENABLED;
3436
3437 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
3438 vars->link_status |=
3439 LINK_STATUS_RX_FLOW_CONTROL_ENABLED;
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003440
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003441 if (link_10g) {
3442 bnx2x_bmac_enable(params, vars, 0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003443 bnx2x_set_led(params, vars,
3444 LED_MODE_OPER, SPEED_10000);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003445 } else {
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003446 rc = bnx2x_emac_program(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003447
Yaniv Rosner0c786f02009-11-05 19:18:32 +02003448 bnx2x_emac_enable(params, vars, 0);
3449
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003450 /* AN complete? */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003451 if ((vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE)
3452 && (!(vars->phy_flags & PHY_SGMII_FLAG)) &&
3453 SINGLE_MEDIA_DIRECT(params))
3454 bnx2x_set_gmii_tx_driver(params);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003455 }
3456
3457 /* PBF - link up */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00003458 if (!(CHIP_IS_E2(bp)))
3459 rc |= bnx2x_pbf_update(params, vars->flow_ctrl,
3460 vars->line_speed);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003461
3462 /* disable drain */
3463 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 0);
3464
3465 /* update shared memory */
3466 bnx2x_update_mng(params, vars->link_status);
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00003467 msleep(20);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003468 return rc;
3469}
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003470/*
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003471 * The bnx2x_link_update function should be called upon link
3472 * interrupt.
3473 * Link is considered up as follows:
3474 * - DIRECT_SINGLE_MEDIA - Only XGXS link (internal link) needs
3475 * to be up
3476 * - SINGLE_MEDIA - The link between the 577xx and the external
3477 * phy (XGXS) need to up as well as the external link of the
3478 * phy (PHY_EXT1)
3479 * - DUAL_MEDIA - The link between the 577xx and the first
3480 * external phy needs to be up, and at least one of the 2
3481 * external phy link must be up.
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003482 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003483u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars)
3484{
3485 struct bnx2x *bp = params->bp;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003486 struct link_vars phy_vars[MAX_PHYS];
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003487 u8 port = params->port;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003488 u8 link_10g, phy_index;
3489 u8 ext_phy_link_up = 0, cur_link_up, rc = 0;
Eilon Greenstein2f904462009-08-12 08:22:16 +00003490 u8 is_mi_int = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003491 u16 ext_phy_line_speed = 0, prev_line_speed = vars->line_speed;
3492 u8 active_external_phy = INT_PHY;
3493 vars->link_status = 0;
3494 for (phy_index = INT_PHY; phy_index < params->num_phys;
3495 phy_index++) {
3496 phy_vars[phy_index].flow_ctrl = 0;
3497 phy_vars[phy_index].link_status = 0;
3498 phy_vars[phy_index].line_speed = 0;
3499 phy_vars[phy_index].duplex = DUPLEX_FULL;
3500 phy_vars[phy_index].phy_link_up = 0;
3501 phy_vars[phy_index].link_up = 0;
3502 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003503
3504 DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n",
Eilon Greenstein2f904462009-08-12 08:22:16 +00003505 port, (vars->phy_flags & PHY_XGXS_FLAG),
3506 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003507
Eilon Greenstein2f904462009-08-12 08:22:16 +00003508 is_mi_int = (u8)(REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003509 port*0x18) > 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003510 DP(NETIF_MSG_LINK, "int_mask 0x%x MI_INT %x, SERDES_LINK %x\n",
Eilon Greenstein2f904462009-08-12 08:22:16 +00003511 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
3512 is_mi_int,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003513 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003514
3515 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
3516 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
3517 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
3518
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00003519 /* disable emac */
3520 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
3521
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003522 /*
3523 * Step 1:
3524 * Check external link change only for external phys, and apply
3525 * priority selection between them in case the link on both phys
3526 * is up. Note that the instead of the common vars, a temporary
3527 * vars argument is used since each phy may have different link/
3528 * speed/duplex result
3529 */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003530 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
3531 phy_index++) {
3532 struct bnx2x_phy *phy = &params->phy[phy_index];
3533 if (!phy->read_status)
3534 continue;
3535 /* Read link status and params of this ext phy */
3536 cur_link_up = phy->read_status(phy, params,
3537 &phy_vars[phy_index]);
3538 if (cur_link_up) {
3539 DP(NETIF_MSG_LINK, "phy in index %d link is up\n",
3540 phy_index);
3541 } else {
3542 DP(NETIF_MSG_LINK, "phy in index %d link is down\n",
3543 phy_index);
3544 continue;
3545 }
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003546
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003547 if (!ext_phy_link_up) {
3548 ext_phy_link_up = 1;
3549 active_external_phy = phy_index;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003550 } else {
3551 switch (bnx2x_phy_selection(params)) {
3552 case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT:
3553 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003554 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003555 * In this option, the first PHY makes sure to pass the
3556 * traffic through itself only.
3557 * Its not clear how to reset the link on the second phy
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003558 */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003559 active_external_phy = EXT_PHY1;
3560 break;
3561 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003562 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003563 * In this option, the first PHY makes sure to pass the
3564 * traffic through the second PHY.
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003565 */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003566 active_external_phy = EXT_PHY2;
3567 break;
3568 default:
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003569 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003570 * Link indication on both PHYs with the following cases
3571 * is invalid:
3572 * - FIRST_PHY means that second phy wasn't initialized,
3573 * hence its link is expected to be down
3574 * - SECOND_PHY means that first phy should not be able
3575 * to link up by itself (using configuration)
3576 * - DEFAULT should be overriden during initialiazation
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003577 */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003578 DP(NETIF_MSG_LINK, "Invalid link indication"
3579 "mpc=0x%x. DISABLING LINK !!!\n",
3580 params->multi_phy_config);
3581 ext_phy_link_up = 0;
3582 break;
3583 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003584 }
3585 }
3586 prev_line_speed = vars->line_speed;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003587 /*
3588 * Step 2:
3589 * Read the status of the internal phy. In case of
3590 * DIRECT_SINGLE_MEDIA board, this link is the external link,
3591 * otherwise this is the link between the 577xx and the first
3592 * external phy
3593 */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003594 if (params->phy[INT_PHY].read_status)
3595 params->phy[INT_PHY].read_status(
3596 &params->phy[INT_PHY],
3597 params, vars);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003598 /*
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003599 * The INT_PHY flow control reside in the vars. This include the
3600 * case where the speed or flow control are not set to AUTO.
3601 * Otherwise, the active external phy flow control result is set
3602 * to the vars. The ext_phy_line_speed is needed to check if the
3603 * speed is different between the internal phy and external phy.
3604 * This case may be result of intermediate link speed change.
3605 */
3606 if (active_external_phy > INT_PHY) {
3607 vars->flow_ctrl = phy_vars[active_external_phy].flow_ctrl;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003608 /*
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003609 * Link speed is taken from the XGXS. AN and FC result from
3610 * the external phy.
3611 */
3612 vars->link_status |= phy_vars[active_external_phy].link_status;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003613
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003614 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003615 * if active_external_phy is first PHY and link is up - disable
3616 * disable TX on second external PHY
3617 */
3618 if (active_external_phy == EXT_PHY1) {
3619 if (params->phy[EXT_PHY2].phy_specific_func) {
3620 DP(NETIF_MSG_LINK, "Disabling TX on"
3621 " EXT_PHY2\n");
3622 params->phy[EXT_PHY2].phy_specific_func(
3623 &params->phy[EXT_PHY2],
3624 params, DISABLE_TX);
3625 }
3626 }
3627
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003628 ext_phy_line_speed = phy_vars[active_external_phy].line_speed;
3629 vars->duplex = phy_vars[active_external_phy].duplex;
3630 if (params->phy[active_external_phy].supported &
3631 SUPPORTED_FIBRE)
3632 vars->link_status |= LINK_STATUS_SERDES_LINK;
3633 DP(NETIF_MSG_LINK, "Active external phy selected: %x\n",
3634 active_external_phy);
3635 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003636
3637 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
3638 phy_index++) {
3639 if (params->phy[phy_index].flags &
3640 FLAGS_REARM_LATCH_SIGNAL) {
3641 bnx2x_rearm_latch_signal(bp, port,
3642 phy_index ==
3643 active_external_phy);
3644 break;
3645 }
3646 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003647 DP(NETIF_MSG_LINK, "vars->flow_ctrl = 0x%x, vars->link_status = 0x%x,"
3648 " ext_phy_line_speed = %d\n", vars->flow_ctrl,
3649 vars->link_status, ext_phy_line_speed);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003650 /*
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003651 * Upon link speed change set the NIG into drain mode. Comes to
3652 * deals with possible FIFO glitch due to clk change when speed
3653 * is decreased without link down indicator
3654 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003655
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003656 if (vars->phy_link_up) {
3657 if (!(SINGLE_MEDIA_DIRECT(params)) && ext_phy_link_up &&
3658 (ext_phy_line_speed != vars->line_speed)) {
3659 DP(NETIF_MSG_LINK, "Internal link speed %d is"
3660 " different than the external"
3661 " link speed %d\n", vars->line_speed,
3662 ext_phy_line_speed);
3663 vars->phy_link_up = 0;
3664 } else if (prev_line_speed != vars->line_speed) {
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003665 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4,
3666 0);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003667 msleep(1);
3668 }
3669 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003670
3671 /* anything 10 and over uses the bmac */
3672 link_10g = ((vars->line_speed == SPEED_10000) ||
3673 (vars->line_speed == SPEED_12000) ||
3674 (vars->line_speed == SPEED_12500) ||
3675 (vars->line_speed == SPEED_13000) ||
3676 (vars->line_speed == SPEED_15000) ||
3677 (vars->line_speed == SPEED_16000));
3678
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003679 bnx2x_link_int_ack(params, vars, link_10g);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003680
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003681 /*
3682 * In case external phy link is up, and internal link is down
3683 * (not initialized yet probably after link initialization, it
3684 * needs to be initialized.
3685 * Note that after link down-up as result of cable plug, the xgxs
3686 * link would probably become up again without the need
3687 * initialize it
3688 */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003689 if (!(SINGLE_MEDIA_DIRECT(params))) {
3690 DP(NETIF_MSG_LINK, "ext_phy_link_up = %d, int_link_up = %d,"
3691 " init_preceding = %d\n", ext_phy_link_up,
3692 vars->phy_link_up,
3693 params->phy[EXT_PHY1].flags &
3694 FLAGS_INIT_XGXS_FIRST);
3695 if (!(params->phy[EXT_PHY1].flags &
3696 FLAGS_INIT_XGXS_FIRST)
3697 && ext_phy_link_up && !vars->phy_link_up) {
3698 vars->line_speed = ext_phy_line_speed;
3699 if (vars->line_speed < SPEED_1000)
3700 vars->phy_flags |= PHY_SGMII_FLAG;
3701 else
3702 vars->phy_flags &= ~PHY_SGMII_FLAG;
3703 bnx2x_init_internal_phy(&params->phy[INT_PHY],
3704 params,
3705 vars);
3706 }
3707 }
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003708 /*
3709 * Link is up only if both local phy and external phy (in case of
3710 * non-direct board) are up
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003711 */
3712 vars->link_up = (vars->phy_link_up &&
3713 (ext_phy_link_up ||
3714 SINGLE_MEDIA_DIRECT(params)));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003715
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003716 if (vars->link_up)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003717 rc = bnx2x_update_link_up(params, vars, link_10g);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003718 else
3719 rc = bnx2x_update_link_down(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003720
3721 return rc;
3722}
3723
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003724
3725/*****************************************************************************/
3726/* External Phy section */
3727/*****************************************************************************/
3728void bnx2x_ext_phy_hw_reset(struct bnx2x *bp, u8 port)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003729{
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003730 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003731 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003732 msleep(1);
3733 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003734 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003735}
3736
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003737static void bnx2x_save_spirom_version(struct bnx2x *bp, u8 port,
3738 u32 spirom_ver, u32 ver_addr)
3739{
3740 DP(NETIF_MSG_LINK, "FW version 0x%x:0x%x for port %d\n",
3741 (u16)(spirom_ver>>16), (u16)spirom_ver, port);
3742
3743 if (ver_addr)
3744 REG_WR(bp, ver_addr, spirom_ver);
3745}
3746
3747static void bnx2x_save_bcm_spirom_ver(struct bnx2x *bp,
3748 struct bnx2x_phy *phy,
3749 u8 port)
3750{
3751 u16 fw_ver1, fw_ver2;
3752
3753 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003754 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003755 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003756 MDIO_PMA_REG_ROM_VER2, &fw_ver2);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003757 bnx2x_save_spirom_version(bp, port, (u32)(fw_ver1<<16 | fw_ver2),
3758 phy->ver_addr);
3759}
3760
3761static void bnx2x_ext_phy_set_pause(struct link_params *params,
3762 struct bnx2x_phy *phy,
3763 struct link_vars *vars)
3764{
3765 u16 val;
3766 struct bnx2x *bp = params->bp;
3767 /* read modify write pause advertizing */
3768 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV_PAUSE, &val);
3769
3770 val &= ~MDIO_AN_REG_ADV_PAUSE_BOTH;
3771
3772 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
3773 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
3774 if ((vars->ieee_fc &
3775 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
3776 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003777 val |= MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003778 }
3779 if ((vars->ieee_fc &
3780 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
3781 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
3782 val |= MDIO_AN_REG_ADV_PAUSE_PAUSE;
3783 }
3784 DP(NETIF_MSG_LINK, "Ext phy AN advertize 0x%x\n", val);
3785 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV_PAUSE, val);
3786}
3787
3788static u8 bnx2x_ext_phy_resolve_fc(struct bnx2x_phy *phy,
3789 struct link_params *params,
3790 struct link_vars *vars)
3791{
3792 struct bnx2x *bp = params->bp;
3793 u16 ld_pause; /* local */
3794 u16 lp_pause; /* link partner */
3795 u16 pause_result;
3796 u8 ret = 0;
3797 /* read twice */
3798
3799 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
3800
3801 if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO)
3802 vars->flow_ctrl = phy->req_flow_ctrl;
3803 else if (phy->req_line_speed != SPEED_AUTO_NEG)
3804 vars->flow_ctrl = params->req_fc_auto_adv;
3805 else if (vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE) {
3806 ret = 1;
3807 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003808 MDIO_AN_DEVAD,
3809 MDIO_AN_REG_ADV_PAUSE, &ld_pause);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003810 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003811 MDIO_AN_DEVAD,
3812 MDIO_AN_REG_LP_AUTO_NEG, &lp_pause);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003813 pause_result = (ld_pause &
3814 MDIO_AN_REG_ADV_PAUSE_MASK) >> 8;
3815 pause_result |= (lp_pause &
3816 MDIO_AN_REG_ADV_PAUSE_MASK) >> 10;
3817 DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x\n",
3818 pause_result);
3819 bnx2x_pause_resolve(vars, pause_result);
3820 }
3821 return ret;
3822}
3823
3824static void bnx2x_ext_phy_10G_an_resolve(struct bnx2x *bp,
3825 struct bnx2x_phy *phy,
3826 struct link_vars *vars)
3827{
3828 u16 val;
3829 bnx2x_cl45_read(bp, phy,
3830 MDIO_AN_DEVAD,
3831 MDIO_AN_REG_STATUS, &val);
3832 bnx2x_cl45_read(bp, phy,
3833 MDIO_AN_DEVAD,
3834 MDIO_AN_REG_STATUS, &val);
3835 if (val & (1<<5))
3836 vars->link_status |= LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
3837 if ((val & (1<<0)) == 0)
3838 vars->link_status |= LINK_STATUS_PARALLEL_DETECTION_USED;
3839}
3840
3841/******************************************************************/
3842/* common BCM8073/BCM8727 PHY SECTION */
3843/******************************************************************/
3844static void bnx2x_8073_resolve_fc(struct bnx2x_phy *phy,
3845 struct link_params *params,
3846 struct link_vars *vars)
3847{
3848 struct bnx2x *bp = params->bp;
3849 if (phy->req_line_speed == SPEED_10 ||
3850 phy->req_line_speed == SPEED_100) {
3851 vars->flow_ctrl = phy->req_flow_ctrl;
3852 return;
3853 }
3854
3855 if (bnx2x_ext_phy_resolve_fc(phy, params, vars) &&
3856 (vars->flow_ctrl == BNX2X_FLOW_CTRL_NONE)) {
3857 u16 pause_result;
3858 u16 ld_pause; /* local */
3859 u16 lp_pause; /* link partner */
3860 bnx2x_cl45_read(bp, phy,
3861 MDIO_AN_DEVAD,
3862 MDIO_AN_REG_CL37_FC_LD, &ld_pause);
3863
3864 bnx2x_cl45_read(bp, phy,
3865 MDIO_AN_DEVAD,
3866 MDIO_AN_REG_CL37_FC_LP, &lp_pause);
3867 pause_result = (ld_pause &
3868 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 5;
3869 pause_result |= (lp_pause &
3870 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 7;
3871
3872 bnx2x_pause_resolve(vars, pause_result);
3873 DP(NETIF_MSG_LINK, "Ext PHY CL37 pause result 0x%x\n",
3874 pause_result);
3875 }
3876}
Yaniv Rosner5c99274b2011-01-18 04:33:36 +00003877static u8 bnx2x_8073_8727_external_rom_boot(struct bnx2x *bp,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003878 struct bnx2x_phy *phy,
3879 u8 port)
3880{
Yaniv Rosner5c99274b2011-01-18 04:33:36 +00003881 u32 count = 0;
3882 u16 fw_ver1, fw_msgout;
3883 u8 rc = 0;
3884
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003885 /* Boot port from external ROM */
3886 /* EDC grst */
3887 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003888 MDIO_PMA_DEVAD,
3889 MDIO_PMA_REG_GEN_CTRL,
3890 0x0001);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003891
3892 /* ucode reboot and rst */
3893 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003894 MDIO_PMA_DEVAD,
3895 MDIO_PMA_REG_GEN_CTRL,
3896 0x008c);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003897
3898 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003899 MDIO_PMA_DEVAD,
3900 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003901
3902 /* Reset internal microprocessor */
3903 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003904 MDIO_PMA_DEVAD,
3905 MDIO_PMA_REG_GEN_CTRL,
3906 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003907
3908 /* Release srst bit */
3909 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003910 MDIO_PMA_DEVAD,
3911 MDIO_PMA_REG_GEN_CTRL,
3912 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003913
Yaniv Rosner5c99274b2011-01-18 04:33:36 +00003914 /* Delay 100ms per the PHY specifications */
3915 msleep(100);
3916
3917 /* 8073 sometimes taking longer to download */
3918 do {
3919 count++;
3920 if (count > 300) {
3921 DP(NETIF_MSG_LINK,
3922 "bnx2x_8073_8727_external_rom_boot port %x:"
3923 "Download failed. fw version = 0x%x\n",
3924 port, fw_ver1);
3925 rc = -EINVAL;
3926 break;
3927 }
3928
3929 bnx2x_cl45_read(bp, phy,
3930 MDIO_PMA_DEVAD,
3931 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
3932 bnx2x_cl45_read(bp, phy,
3933 MDIO_PMA_DEVAD,
3934 MDIO_PMA_REG_M8051_MSGOUT_REG, &fw_msgout);
3935
3936 msleep(1);
3937 } while (fw_ver1 == 0 || fw_ver1 == 0x4321 ||
3938 ((fw_msgout & 0xff) != 0x03 && (phy->type ==
3939 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073)));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003940
3941 /* Clear ser_boot_ctl bit */
3942 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003943 MDIO_PMA_DEVAD,
3944 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003945 bnx2x_save_bcm_spirom_ver(bp, phy, port);
Yaniv Rosner5c99274b2011-01-18 04:33:36 +00003946
3947 DP(NETIF_MSG_LINK,
3948 "bnx2x_8073_8727_external_rom_boot port %x:"
3949 "Download complete. fw version = 0x%x\n",
3950 port, fw_ver1);
3951
3952 return rc;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003953}
3954
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003955/******************************************************************/
3956/* BCM8073 PHY SECTION */
3957/******************************************************************/
3958static u8 bnx2x_8073_is_snr_needed(struct bnx2x *bp, struct bnx2x_phy *phy)
3959{
3960 /* This is only required for 8073A1, version 102 only */
3961 u16 val;
3962
3963 /* Read 8073 HW revision*/
3964 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003965 MDIO_PMA_DEVAD,
3966 MDIO_PMA_REG_8073_CHIP_REV, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003967
3968 if (val != 1) {
3969 /* No need to workaround in 8073 A1 */
3970 return 0;
3971 }
3972
3973 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003974 MDIO_PMA_DEVAD,
3975 MDIO_PMA_REG_ROM_VER2, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003976
3977 /* SNR should be applied only for version 0x102 */
3978 if (val != 0x102)
3979 return 0;
3980
3981 return 1;
3982}
3983
3984static u8 bnx2x_8073_xaui_wa(struct bnx2x *bp, struct bnx2x_phy *phy)
3985{
3986 u16 val, cnt, cnt1 ;
3987
3988 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003989 MDIO_PMA_DEVAD,
3990 MDIO_PMA_REG_8073_CHIP_REV, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003991
3992 if (val > 0) {
3993 /* No need to workaround in 8073 A1 */
3994 return 0;
3995 }
3996 /* XAUI workaround in 8073 A0: */
3997
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003998 /*
3999 * After loading the boot ROM and restarting Autoneg, poll
4000 * Dev1, Reg $C820:
4001 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004002
4003 for (cnt = 0; cnt < 1000; cnt++) {
4004 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004005 MDIO_PMA_DEVAD,
4006 MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
4007 &val);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004008 /*
4009 * If bit [14] = 0 or bit [13] = 0, continue on with
4010 * system initialization (XAUI work-around not required, as
4011 * these bits indicate 2.5G or 1G link up).
4012 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004013 if (!(val & (1<<14)) || !(val & (1<<13))) {
4014 DP(NETIF_MSG_LINK, "XAUI work-around not required\n");
4015 return 0;
4016 } else if (!(val & (1<<15))) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004017 DP(NETIF_MSG_LINK, "bit 15 went off\n");
4018 /*
4019 * If bit 15 is 0, then poll Dev1, Reg $C841 until it's
4020 * MSB (bit15) goes to 1 (indicating that the XAUI
4021 * workaround has completed), then continue on with
4022 * system initialization.
4023 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004024 for (cnt1 = 0; cnt1 < 1000; cnt1++) {
4025 bnx2x_cl45_read(bp, phy,
4026 MDIO_PMA_DEVAD,
4027 MDIO_PMA_REG_8073_XAUI_WA, &val);
4028 if (val & (1<<15)) {
4029 DP(NETIF_MSG_LINK,
4030 "XAUI workaround has completed\n");
4031 return 0;
4032 }
4033 msleep(3);
4034 }
4035 break;
4036 }
4037 msleep(3);
4038 }
4039 DP(NETIF_MSG_LINK, "Warning: XAUI work-around timeout !!!\n");
4040 return -EINVAL;
4041}
4042
4043static void bnx2x_807x_force_10G(struct bnx2x *bp, struct bnx2x_phy *phy)
4044{
4045 /* Force KR or KX */
4046 bnx2x_cl45_write(bp, phy,
4047 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x2040);
4048 bnx2x_cl45_write(bp, phy,
4049 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0x000b);
4050 bnx2x_cl45_write(bp, phy,
4051 MDIO_PMA_DEVAD, MDIO_PMA_REG_BCM_CTRL, 0x0000);
4052 bnx2x_cl45_write(bp, phy,
4053 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x0000);
4054}
4055
4056static void bnx2x_8073_set_pause_cl37(struct link_params *params,
4057 struct bnx2x_phy *phy,
4058 struct link_vars *vars)
4059{
4060 u16 cl37_val;
4061 struct bnx2x *bp = params->bp;
4062 bnx2x_cl45_read(bp, phy,
4063 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, &cl37_val);
4064
4065 cl37_val &= ~MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
4066 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
4067 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
4068 if ((vars->ieee_fc &
4069 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) ==
4070 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) {
4071 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC;
4072 }
4073 if ((vars->ieee_fc &
4074 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
4075 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
4076 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
4077 }
4078 if ((vars->ieee_fc &
4079 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
4080 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
4081 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
4082 }
4083 DP(NETIF_MSG_LINK,
4084 "Ext phy AN advertize cl37 0x%x\n", cl37_val);
4085
4086 bnx2x_cl45_write(bp, phy,
4087 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, cl37_val);
4088 msleep(500);
4089}
4090
4091static u8 bnx2x_8073_config_init(struct bnx2x_phy *phy,
4092 struct link_params *params,
4093 struct link_vars *vars)
4094{
4095 struct bnx2x *bp = params->bp;
4096 u16 val = 0, tmp1;
4097 u8 gpio_port;
4098 DP(NETIF_MSG_LINK, "Init 8073\n");
4099
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00004100 if (CHIP_IS_E2(bp))
4101 gpio_port = BP_PATH(bp);
4102 else
4103 gpio_port = params->port;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004104 /* Restore normal power mode*/
4105 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004106 MISC_REGISTERS_GPIO_OUTPUT_HIGH, gpio_port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004107
4108 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004109 MISC_REGISTERS_GPIO_OUTPUT_HIGH, gpio_port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004110
4111 /* enable LASI */
4112 bnx2x_cl45_write(bp, phy,
4113 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL, (1<<2));
4114 bnx2x_cl45_write(bp, phy,
4115 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x0004);
4116
4117 bnx2x_8073_set_pause_cl37(params, phy, vars);
4118
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004119 bnx2x_cl45_read(bp, phy,
4120 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &tmp1);
4121
4122 bnx2x_cl45_read(bp, phy,
4123 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &tmp1);
4124
4125 DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1): 0x%x\n", tmp1);
4126
Yaniv Rosner74d7a112011-01-18 04:33:18 +00004127 /* Swap polarity if required - Must be done only in non-1G mode */
4128 if (params->lane_config & PORT_HW_CFG_SWAP_PHY_POLARITY_ENABLED) {
4129 /* Configure the 8073 to swap _P and _N of the KR lines */
4130 DP(NETIF_MSG_LINK, "Swapping polarity for the 8073\n");
4131 /* 10G Rx/Tx and 1G Tx signal polarity swap */
4132 bnx2x_cl45_read(bp, phy,
4133 MDIO_PMA_DEVAD,
4134 MDIO_PMA_REG_8073_OPT_DIGITAL_CTRL, &val);
4135 bnx2x_cl45_write(bp, phy,
4136 MDIO_PMA_DEVAD,
4137 MDIO_PMA_REG_8073_OPT_DIGITAL_CTRL,
4138 (val | (3<<9)));
4139 }
4140
4141
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004142 /* Enable CL37 BAM */
Yaniv Rosner121839b2010-11-01 05:32:38 +00004143 if (REG_RD(bp, params->shmem_base +
4144 offsetof(struct shmem_region, dev_info.
4145 port_hw_config[params->port].default_cfg)) &
4146 PORT_HW_CFG_ENABLE_BAM_ON_KR_ENABLED) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004147
Yaniv Rosner121839b2010-11-01 05:32:38 +00004148 bnx2x_cl45_read(bp, phy,
4149 MDIO_AN_DEVAD,
4150 MDIO_AN_REG_8073_BAM, &val);
4151 bnx2x_cl45_write(bp, phy,
4152 MDIO_AN_DEVAD,
4153 MDIO_AN_REG_8073_BAM, val | 1);
4154 DP(NETIF_MSG_LINK, "Enable CL37 BAM on KR\n");
4155 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004156 if (params->loopback_mode == LOOPBACK_EXT) {
4157 bnx2x_807x_force_10G(bp, phy);
4158 DP(NETIF_MSG_LINK, "Forced speed 10G on 807X\n");
4159 return 0;
4160 } else {
4161 bnx2x_cl45_write(bp, phy,
4162 MDIO_PMA_DEVAD, MDIO_PMA_REG_BCM_CTRL, 0x0002);
4163 }
4164 if (phy->req_line_speed != SPEED_AUTO_NEG) {
4165 if (phy->req_line_speed == SPEED_10000) {
4166 val = (1<<7);
4167 } else if (phy->req_line_speed == SPEED_2500) {
4168 val = (1<<5);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004169 /*
4170 * Note that 2.5G works only when used with 1G
4171 * advertisment
4172 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004173 } else
4174 val = (1<<5);
4175 } else {
4176 val = 0;
4177 if (phy->speed_cap_mask &
4178 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
4179 val |= (1<<7);
4180
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004181 /* Note that 2.5G works only when used with 1G advertisment */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004182 if (phy->speed_cap_mask &
4183 (PORT_HW_CFG_SPEED_CAPABILITY_D0_1G |
4184 PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G))
4185 val |= (1<<5);
4186 DP(NETIF_MSG_LINK, "807x autoneg val = 0x%x\n", val);
4187 }
4188
4189 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV, val);
4190 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_8073_2_5G, &tmp1);
4191
4192 if (((phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G) &&
4193 (phy->req_line_speed == SPEED_AUTO_NEG)) ||
4194 (phy->req_line_speed == SPEED_2500)) {
4195 u16 phy_ver;
4196 /* Allow 2.5G for A1 and above */
4197 bnx2x_cl45_read(bp, phy,
4198 MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_CHIP_REV,
4199 &phy_ver);
4200 DP(NETIF_MSG_LINK, "Add 2.5G\n");
4201 if (phy_ver > 0)
4202 tmp1 |= 1;
4203 else
4204 tmp1 &= 0xfffe;
4205 } else {
4206 DP(NETIF_MSG_LINK, "Disable 2.5G\n");
4207 tmp1 &= 0xfffe;
4208 }
4209
4210 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_8073_2_5G, tmp1);
4211 /* Add support for CL37 (passive mode) II */
4212
4213 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, &tmp1);
4214 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD,
4215 (tmp1 | ((phy->req_duplex == DUPLEX_FULL) ?
4216 0x20 : 0x40)));
4217
4218 /* Add support for CL37 (passive mode) III */
4219 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
4220
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004221 /*
4222 * The SNR will improve about 2db by changing BW and FEE main
4223 * tap. Rest commands are executed after link is up
4224 * Change FFE main cursor to 5 in EDC register
4225 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004226 if (bnx2x_8073_is_snr_needed(bp, phy))
4227 bnx2x_cl45_write(bp, phy,
4228 MDIO_PMA_DEVAD, MDIO_PMA_REG_EDC_FFE_MAIN,
4229 0xFB0C);
4230
4231 /* Enable FEC (Forware Error Correction) Request in the AN */
4232 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV2, &tmp1);
4233 tmp1 |= (1<<15);
4234 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV2, tmp1);
4235
4236 bnx2x_ext_phy_set_pause(params, phy, vars);
4237
4238 /* Restart autoneg */
4239 msleep(500);
4240 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
4241 DP(NETIF_MSG_LINK, "807x Autoneg Restart: Advertise 1G=%x, 10G=%x\n",
4242 ((val & (1<<5)) > 0), ((val & (1<<7)) > 0));
4243 return 0;
4244}
4245
4246static u8 bnx2x_8073_read_status(struct bnx2x_phy *phy,
4247 struct link_params *params,
4248 struct link_vars *vars)
4249{
4250 struct bnx2x *bp = params->bp;
4251 u8 link_up = 0;
4252 u16 val1, val2;
4253 u16 link_status = 0;
4254 u16 an1000_status = 0;
4255
4256 bnx2x_cl45_read(bp, phy,
4257 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
4258
4259 DP(NETIF_MSG_LINK, "8703 LASI status 0x%x\n", val1);
4260
4261 /* clear the interrupt LASI status register */
4262 bnx2x_cl45_read(bp, phy,
4263 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val2);
4264 bnx2x_cl45_read(bp, phy,
4265 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val1);
4266 DP(NETIF_MSG_LINK, "807x PCS status 0x%x->0x%x\n", val2, val1);
4267 /* Clear MSG-OUT */
4268 bnx2x_cl45_read(bp, phy,
4269 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &val1);
4270
4271 /* Check the LASI */
4272 bnx2x_cl45_read(bp, phy,
4273 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &val2);
4274
4275 DP(NETIF_MSG_LINK, "KR 0x9003 0x%x\n", val2);
4276
4277 /* Check the link status */
4278 bnx2x_cl45_read(bp, phy,
4279 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val2);
4280 DP(NETIF_MSG_LINK, "KR PCS status 0x%x\n", val2);
4281
4282 bnx2x_cl45_read(bp, phy,
4283 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
4284 bnx2x_cl45_read(bp, phy,
4285 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
4286 link_up = ((val1 & 4) == 4);
4287 DP(NETIF_MSG_LINK, "PMA_REG_STATUS=0x%x\n", val1);
4288
4289 if (link_up &&
4290 ((phy->req_line_speed != SPEED_10000))) {
4291 if (bnx2x_8073_xaui_wa(bp, phy) != 0)
4292 return 0;
4293 }
4294 bnx2x_cl45_read(bp, phy,
4295 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &an1000_status);
4296 bnx2x_cl45_read(bp, phy,
4297 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &an1000_status);
4298
4299 /* Check the link status on 1.1.2 */
4300 bnx2x_cl45_read(bp, phy,
4301 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
4302 bnx2x_cl45_read(bp, phy,
4303 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
4304 DP(NETIF_MSG_LINK, "KR PMA status 0x%x->0x%x,"
4305 "an_link_status=0x%x\n", val2, val1, an1000_status);
4306
4307 link_up = (((val1 & 4) == 4) || (an1000_status & (1<<1)));
4308 if (link_up && bnx2x_8073_is_snr_needed(bp, phy)) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004309 /*
4310 * The SNR will improve about 2dbby changing the BW and FEE main
4311 * tap. The 1st write to change FFE main tap is set before
4312 * restart AN. Change PLL Bandwidth in EDC register
4313 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004314 bnx2x_cl45_write(bp, phy,
4315 MDIO_PMA_DEVAD, MDIO_PMA_REG_PLL_BANDWIDTH,
4316 0x26BC);
4317
4318 /* Change CDR Bandwidth in EDC register */
4319 bnx2x_cl45_write(bp, phy,
4320 MDIO_PMA_DEVAD, MDIO_PMA_REG_CDR_BANDWIDTH,
4321 0x0333);
4322 }
4323 bnx2x_cl45_read(bp, phy,
4324 MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
4325 &link_status);
4326
4327 /* Bits 0..2 --> speed detected, bits 13..15--> link is down */
4328 if ((link_status & (1<<2)) && (!(link_status & (1<<15)))) {
4329 link_up = 1;
4330 vars->line_speed = SPEED_10000;
4331 DP(NETIF_MSG_LINK, "port %x: External link up in 10G\n",
4332 params->port);
4333 } else if ((link_status & (1<<1)) && (!(link_status & (1<<14)))) {
4334 link_up = 1;
4335 vars->line_speed = SPEED_2500;
4336 DP(NETIF_MSG_LINK, "port %x: External link up in 2.5G\n",
4337 params->port);
4338 } else if ((link_status & (1<<0)) && (!(link_status & (1<<13)))) {
4339 link_up = 1;
4340 vars->line_speed = SPEED_1000;
4341 DP(NETIF_MSG_LINK, "port %x: External link up in 1G\n",
4342 params->port);
4343 } else {
4344 link_up = 0;
4345 DP(NETIF_MSG_LINK, "port %x: External link is down\n",
4346 params->port);
4347 }
4348
4349 if (link_up) {
Yaniv Rosner74d7a112011-01-18 04:33:18 +00004350 /* Swap polarity if required */
4351 if (params->lane_config &
4352 PORT_HW_CFG_SWAP_PHY_POLARITY_ENABLED) {
4353 /* Configure the 8073 to swap P and N of the KR lines */
4354 bnx2x_cl45_read(bp, phy,
4355 MDIO_XS_DEVAD,
4356 MDIO_XS_REG_8073_RX_CTRL_PCIE, &val1);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004357 /*
4358 * Set bit 3 to invert Rx in 1G mode and clear this bit
4359 * when it`s in 10G mode.
4360 */
Yaniv Rosner74d7a112011-01-18 04:33:18 +00004361 if (vars->line_speed == SPEED_1000) {
4362 DP(NETIF_MSG_LINK, "Swapping 1G polarity for"
4363 "the 8073\n");
4364 val1 |= (1<<3);
4365 } else
4366 val1 &= ~(1<<3);
4367
4368 bnx2x_cl45_write(bp, phy,
4369 MDIO_XS_DEVAD,
4370 MDIO_XS_REG_8073_RX_CTRL_PCIE,
4371 val1);
4372 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004373 bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
4374 bnx2x_8073_resolve_fc(phy, params, vars);
Yaniv Rosner791f18c2011-01-18 04:33:42 +00004375 vars->duplex = DUPLEX_FULL;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004376 }
4377 return link_up;
4378}
4379
4380static void bnx2x_8073_link_reset(struct bnx2x_phy *phy,
4381 struct link_params *params)
4382{
4383 struct bnx2x *bp = params->bp;
4384 u8 gpio_port;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00004385 if (CHIP_IS_E2(bp))
4386 gpio_port = BP_PATH(bp);
4387 else
4388 gpio_port = params->port;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004389 DP(NETIF_MSG_LINK, "Setting 8073 port %d into low power mode\n",
4390 gpio_port);
4391 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004392 MISC_REGISTERS_GPIO_OUTPUT_LOW,
4393 gpio_port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004394}
4395
4396/******************************************************************/
4397/* BCM8705 PHY SECTION */
4398/******************************************************************/
4399static u8 bnx2x_8705_config_init(struct bnx2x_phy *phy,
4400 struct link_params *params,
4401 struct link_vars *vars)
4402{
4403 struct bnx2x *bp = params->bp;
4404 DP(NETIF_MSG_LINK, "init 8705\n");
4405 /* Restore normal power mode*/
4406 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004407 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004408 /* HW reset */
4409 bnx2x_ext_phy_hw_reset(bp, params->port);
4410 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0xa040);
4411 bnx2x_wait_reset_complete(bp, phy);
4412
4413 bnx2x_cl45_write(bp, phy,
4414 MDIO_PMA_DEVAD, MDIO_PMA_REG_MISC_CTRL, 0x8288);
4415 bnx2x_cl45_write(bp, phy,
4416 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, 0x7fbf);
4417 bnx2x_cl45_write(bp, phy,
4418 MDIO_PMA_DEVAD, MDIO_PMA_REG_CMU_PLL_BYPASS, 0x0100);
4419 bnx2x_cl45_write(bp, phy,
4420 MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_CNTL, 0x1);
4421 /* BCM8705 doesn't have microcode, hence the 0 */
4422 bnx2x_save_spirom_version(bp, params->port, params->shmem_base, 0);
4423 return 0;
4424}
4425
4426static u8 bnx2x_8705_read_status(struct bnx2x_phy *phy,
4427 struct link_params *params,
4428 struct link_vars *vars)
4429{
4430 u8 link_up = 0;
4431 u16 val1, rx_sd;
4432 struct bnx2x *bp = params->bp;
4433 DP(NETIF_MSG_LINK, "read status 8705\n");
4434 bnx2x_cl45_read(bp, phy,
4435 MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_STATUS, &val1);
4436 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
4437
4438 bnx2x_cl45_read(bp, phy,
4439 MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_STATUS, &val1);
4440 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
4441
4442 bnx2x_cl45_read(bp, phy,
4443 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD, &rx_sd);
4444
4445 bnx2x_cl45_read(bp, phy,
4446 MDIO_PMA_DEVAD, 0xc809, &val1);
4447 bnx2x_cl45_read(bp, phy,
4448 MDIO_PMA_DEVAD, 0xc809, &val1);
4449
4450 DP(NETIF_MSG_LINK, "8705 1.c809 val=0x%x\n", val1);
4451 link_up = ((rx_sd & 0x1) && (val1 & (1<<9)) && ((val1 & (1<<8)) == 0));
4452 if (link_up) {
4453 vars->line_speed = SPEED_10000;
4454 bnx2x_ext_phy_resolve_fc(phy, params, vars);
4455 }
4456 return link_up;
4457}
4458
4459/******************************************************************/
4460/* SFP+ module Section */
4461/******************************************************************/
4462static void bnx2x_sfp_set_transmitter(struct bnx2x *bp,
4463 struct bnx2x_phy *phy,
4464 u8 port,
4465 u8 tx_en)
4466{
4467 u16 val;
4468
4469 DP(NETIF_MSG_LINK, "Setting transmitter tx_en=%x for port %x\n",
4470 tx_en, port);
4471 /* Disable/Enable transmitter ( TX laser of the SFP+ module.)*/
4472 bnx2x_cl45_read(bp, phy,
4473 MDIO_PMA_DEVAD,
4474 MDIO_PMA_REG_PHY_IDENTIFIER,
4475 &val);
4476
4477 if (tx_en)
4478 val &= ~(1<<15);
4479 else
4480 val |= (1<<15);
4481
4482 bnx2x_cl45_write(bp, phy,
4483 MDIO_PMA_DEVAD,
4484 MDIO_PMA_REG_PHY_IDENTIFIER,
4485 val);
4486}
4487
4488static u8 bnx2x_8726_read_sfp_module_eeprom(struct bnx2x_phy *phy,
4489 struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004490 u16 addr, u8 byte_cnt, u8 *o_buf)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004491{
4492 struct bnx2x *bp = params->bp;
4493 u16 val = 0;
4494 u16 i;
4495 if (byte_cnt > 16) {
4496 DP(NETIF_MSG_LINK, "Reading from eeprom is"
4497 " is limited to 0xf\n");
4498 return -EINVAL;
4499 }
4500 /* Set the read command byte count */
4501 bnx2x_cl45_write(bp, phy,
4502 MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004503 (byte_cnt | 0xa000));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004504
4505 /* Set the read command address */
4506 bnx2x_cl45_write(bp, phy,
4507 MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004508 addr);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004509
4510 /* Activate read command */
4511 bnx2x_cl45_write(bp, phy,
4512 MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004513 0x2c0f);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004514
4515 /* Wait up to 500us for command complete status */
4516 for (i = 0; i < 100; i++) {
4517 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004518 MDIO_PMA_DEVAD,
4519 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004520 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
4521 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
4522 break;
4523 udelay(5);
4524 }
4525
4526 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
4527 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
4528 DP(NETIF_MSG_LINK,
4529 "Got bad status 0x%x when reading from SFP+ EEPROM\n",
4530 (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
4531 return -EINVAL;
4532 }
4533
4534 /* Read the buffer */
4535 for (i = 0; i < byte_cnt; i++) {
4536 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004537 MDIO_PMA_DEVAD,
4538 MDIO_PMA_REG_8726_TWO_WIRE_DATA_BUF + i, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004539 o_buf[i] = (u8)(val & MDIO_PMA_REG_8726_TWO_WIRE_DATA_MASK);
4540 }
4541
4542 for (i = 0; i < 100; i++) {
4543 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004544 MDIO_PMA_DEVAD,
4545 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004546 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
4547 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
Joe Perches6f38ad92010-11-14 17:04:31 +00004548 return 0;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004549 msleep(1);
4550 }
4551 return -EINVAL;
4552}
4553
4554static u8 bnx2x_8727_read_sfp_module_eeprom(struct bnx2x_phy *phy,
4555 struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004556 u16 addr, u8 byte_cnt, u8 *o_buf)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004557{
4558 struct bnx2x *bp = params->bp;
4559 u16 val, i;
4560
4561 if (byte_cnt > 16) {
4562 DP(NETIF_MSG_LINK, "Reading from eeprom is"
4563 " is limited to 0xf\n");
4564 return -EINVAL;
4565 }
4566
4567 /* Need to read from 1.8000 to clear it */
4568 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004569 MDIO_PMA_DEVAD,
4570 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
4571 &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004572
4573 /* Set the read command byte count */
4574 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004575 MDIO_PMA_DEVAD,
4576 MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
4577 ((byte_cnt < 2) ? 2 : byte_cnt));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004578
4579 /* Set the read command address */
4580 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004581 MDIO_PMA_DEVAD,
4582 MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
4583 addr);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004584 /* Set the destination address */
4585 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004586 MDIO_PMA_DEVAD,
4587 0x8004,
4588 MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004589
4590 /* Activate read command */
4591 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004592 MDIO_PMA_DEVAD,
4593 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
4594 0x8002);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004595 /*
4596 * Wait appropriate time for two-wire command to finish before
4597 * polling the status register
4598 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004599 msleep(1);
4600
4601 /* Wait up to 500us for command complete status */
4602 for (i = 0; i < 100; i++) {
4603 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004604 MDIO_PMA_DEVAD,
4605 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004606 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
4607 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
4608 break;
4609 udelay(5);
4610 }
4611
4612 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
4613 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
4614 DP(NETIF_MSG_LINK,
4615 "Got bad status 0x%x when reading from SFP+ EEPROM\n",
4616 (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
4617 return -EINVAL;
4618 }
4619
4620 /* Read the buffer */
4621 for (i = 0; i < byte_cnt; i++) {
4622 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004623 MDIO_PMA_DEVAD,
4624 MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF + i, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004625 o_buf[i] = (u8)(val & MDIO_PMA_REG_8727_TWO_WIRE_DATA_MASK);
4626 }
4627
4628 for (i = 0; i < 100; i++) {
4629 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004630 MDIO_PMA_DEVAD,
4631 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004632 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
4633 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
Joe Perches6f38ad92010-11-14 17:04:31 +00004634 return 0;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004635 msleep(1);
4636 }
4637
4638 return -EINVAL;
4639}
4640
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004641u8 bnx2x_read_sfp_module_eeprom(struct bnx2x_phy *phy,
4642 struct link_params *params, u16 addr,
4643 u8 byte_cnt, u8 *o_buf)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004644{
4645 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
4646 return bnx2x_8726_read_sfp_module_eeprom(phy, params, addr,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004647 byte_cnt, o_buf);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004648 else if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
4649 return bnx2x_8727_read_sfp_module_eeprom(phy, params, addr,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004650 byte_cnt, o_buf);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004651 return -EINVAL;
4652}
4653
4654static u8 bnx2x_get_edc_mode(struct bnx2x_phy *phy,
4655 struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004656 u16 *edc_mode)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004657{
4658 struct bnx2x *bp = params->bp;
4659 u8 val, check_limiting_mode = 0;
4660 *edc_mode = EDC_MODE_LIMITING;
4661
4662 /* First check for copper cable */
4663 if (bnx2x_read_sfp_module_eeprom(phy,
4664 params,
4665 SFP_EEPROM_CON_TYPE_ADDR,
4666 1,
4667 &val) != 0) {
4668 DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM\n");
4669 return -EINVAL;
4670 }
4671
4672 switch (val) {
4673 case SFP_EEPROM_CON_TYPE_VAL_COPPER:
4674 {
4675 u8 copper_module_type;
4676
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004677 /*
4678 * Check if its active cable (includes SFP+ module)
4679 * of passive cable
4680 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004681 if (bnx2x_read_sfp_module_eeprom(phy,
4682 params,
4683 SFP_EEPROM_FC_TX_TECH_ADDR,
4684 1,
4685 &copper_module_type) !=
4686 0) {
4687 DP(NETIF_MSG_LINK,
4688 "Failed to read copper-cable-type"
4689 " from SFP+ EEPROM\n");
4690 return -EINVAL;
4691 }
4692
4693 if (copper_module_type &
4694 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE) {
4695 DP(NETIF_MSG_LINK, "Active Copper cable detected\n");
4696 check_limiting_mode = 1;
4697 } else if (copper_module_type &
4698 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE) {
4699 DP(NETIF_MSG_LINK, "Passive Copper"
4700 " cable detected\n");
4701 *edc_mode =
4702 EDC_MODE_PASSIVE_DAC;
4703 } else {
4704 DP(NETIF_MSG_LINK, "Unknown copper-cable-"
4705 "type 0x%x !!!\n", copper_module_type);
4706 return -EINVAL;
4707 }
4708 break;
4709 }
4710 case SFP_EEPROM_CON_TYPE_VAL_LC:
4711 DP(NETIF_MSG_LINK, "Optic module detected\n");
4712 check_limiting_mode = 1;
4713 break;
4714 default:
4715 DP(NETIF_MSG_LINK, "Unable to determine module type 0x%x !!!\n",
4716 val);
4717 return -EINVAL;
4718 }
4719
4720 if (check_limiting_mode) {
4721 u8 options[SFP_EEPROM_OPTIONS_SIZE];
4722 if (bnx2x_read_sfp_module_eeprom(phy,
4723 params,
4724 SFP_EEPROM_OPTIONS_ADDR,
4725 SFP_EEPROM_OPTIONS_SIZE,
4726 options) != 0) {
4727 DP(NETIF_MSG_LINK, "Failed to read Option"
4728 " field from module EEPROM\n");
4729 return -EINVAL;
4730 }
4731 if ((options[0] & SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK))
4732 *edc_mode = EDC_MODE_LINEAR;
4733 else
4734 *edc_mode = EDC_MODE_LIMITING;
4735 }
4736 DP(NETIF_MSG_LINK, "EDC mode is set to 0x%x\n", *edc_mode);
4737 return 0;
4738}
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004739/*
4740 * This function read the relevant field from the module (SFP+), and verify it
4741 * is compliant with this board
4742 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004743static u8 bnx2x_verify_sfp_module(struct bnx2x_phy *phy,
4744 struct link_params *params)
4745{
4746 struct bnx2x *bp = params->bp;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004747 u32 val, cmd;
4748 u32 fw_resp, fw_cmd_param;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004749 char vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE+1];
4750 char vendor_pn[SFP_EEPROM_PART_NO_SIZE+1];
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004751 phy->flags &= ~FLAGS_SFP_NOT_APPROVED;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004752 val = REG_RD(bp, params->shmem_base +
4753 offsetof(struct shmem_region, dev_info.
4754 port_feature_config[params->port].config));
4755 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
4756 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_NO_ENFORCEMENT) {
4757 DP(NETIF_MSG_LINK, "NOT enforcing module verification\n");
4758 return 0;
4759 }
4760
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004761 if (params->feature_config_flags &
4762 FEATURE_CONFIG_BC_SUPPORTS_DUAL_PHY_OPT_MDL_VRFY) {
4763 /* Use specific phy request */
4764 cmd = DRV_MSG_CODE_VRFY_SPECIFIC_PHY_OPT_MDL;
4765 } else if (params->feature_config_flags &
4766 FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY) {
4767 /* Use first phy request only in case of non-dual media*/
4768 if (DUAL_MEDIA(params)) {
4769 DP(NETIF_MSG_LINK, "FW does not support OPT MDL "
4770 "verification\n");
4771 return -EINVAL;
4772 }
4773 cmd = DRV_MSG_CODE_VRFY_FIRST_PHY_OPT_MDL;
4774 } else {
4775 /* No support in OPT MDL detection */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004776 DP(NETIF_MSG_LINK, "FW does not support OPT MDL "
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004777 "verification\n");
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004778 return -EINVAL;
4779 }
Dmitry Kravkov523224a2010-10-06 03:23:26 +00004780
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004781 fw_cmd_param = FW_PARAM_SET(phy->addr, phy->type, phy->mdio_ctrl);
4782 fw_resp = bnx2x_fw_command(bp, cmd, fw_cmd_param);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004783 if (fw_resp == FW_MSG_CODE_VRFY_OPT_MDL_SUCCESS) {
4784 DP(NETIF_MSG_LINK, "Approved module\n");
4785 return 0;
4786 }
4787
4788 /* format the warning message */
4789 if (bnx2x_read_sfp_module_eeprom(phy,
4790 params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004791 SFP_EEPROM_VENDOR_NAME_ADDR,
4792 SFP_EEPROM_VENDOR_NAME_SIZE,
4793 (u8 *)vendor_name))
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004794 vendor_name[0] = '\0';
4795 else
4796 vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE] = '\0';
4797 if (bnx2x_read_sfp_module_eeprom(phy,
4798 params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004799 SFP_EEPROM_PART_NO_ADDR,
4800 SFP_EEPROM_PART_NO_SIZE,
4801 (u8 *)vendor_pn))
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004802 vendor_pn[0] = '\0';
4803 else
4804 vendor_pn[SFP_EEPROM_PART_NO_SIZE] = '\0';
4805
4806 netdev_info(bp->dev, "Warning: Unqualified SFP+ module detected,"
4807 " Port %d from %s part number %s\n",
4808 params->port, vendor_name, vendor_pn);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004809 phy->flags |= FLAGS_SFP_NOT_APPROVED;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004810 return -EINVAL;
4811}
4812
4813static u8 bnx2x_wait_for_sfp_module_initialized(struct bnx2x_phy *phy,
4814 struct link_params *params)
4815
4816{
4817 u8 val;
4818 struct bnx2x *bp = params->bp;
4819 u16 timeout;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004820 /*
4821 * Initialization time after hot-plug may take up to 300ms for
4822 * some phys type ( e.g. JDSU )
4823 */
4824
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004825 for (timeout = 0; timeout < 60; timeout++) {
4826 if (bnx2x_read_sfp_module_eeprom(phy, params, 1, 1, &val)
4827 == 0) {
4828 DP(NETIF_MSG_LINK, "SFP+ module initialization "
4829 "took %d ms\n", timeout * 5);
4830 return 0;
4831 }
4832 msleep(5);
4833 }
4834 return -EINVAL;
4835}
4836
4837static void bnx2x_8727_power_module(struct bnx2x *bp,
4838 struct bnx2x_phy *phy,
4839 u8 is_power_up) {
4840 /* Make sure GPIOs are not using for LED mode */
4841 u16 val;
4842 /*
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004843 * In the GPIO register, bit 4 is use to determine if the GPIOs are
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004844 * operating as INPUT or as OUTPUT. Bit 1 is for input, and 0 for
4845 * output
4846 * Bits 0-1 determine the gpios value for OUTPUT in case bit 4 val is 0
4847 * Bits 8-9 determine the gpios value for INPUT in case bit 4 val is 1
4848 * where the 1st bit is the over-current(only input), and 2nd bit is
4849 * for power( only output )
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004850 *
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004851 * In case of NOC feature is disabled and power is up, set GPIO control
4852 * as input to enable listening of over-current indication
4853 */
4854 if (phy->flags & FLAGS_NOC)
4855 return;
4856 if (!(phy->flags &
4857 FLAGS_NOC) && is_power_up)
4858 val = (1<<4);
4859 else
4860 /*
4861 * Set GPIO control to OUTPUT, and set the power bit
4862 * to according to the is_power_up
4863 */
4864 val = ((!(is_power_up)) << 1);
4865
4866 bnx2x_cl45_write(bp, phy,
4867 MDIO_PMA_DEVAD,
4868 MDIO_PMA_REG_8727_GPIO_CTRL,
4869 val);
4870}
4871
4872static u8 bnx2x_8726_set_limiting_mode(struct bnx2x *bp,
4873 struct bnx2x_phy *phy,
4874 u16 edc_mode)
4875{
4876 u16 cur_limiting_mode;
4877
4878 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004879 MDIO_PMA_DEVAD,
4880 MDIO_PMA_REG_ROM_VER2,
4881 &cur_limiting_mode);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004882 DP(NETIF_MSG_LINK, "Current Limiting mode is 0x%x\n",
4883 cur_limiting_mode);
4884
4885 if (edc_mode == EDC_MODE_LIMITING) {
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004886 DP(NETIF_MSG_LINK, "Setting LIMITING MODE\n");
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004887 bnx2x_cl45_write(bp, phy,
4888 MDIO_PMA_DEVAD,
4889 MDIO_PMA_REG_ROM_VER2,
4890 EDC_MODE_LIMITING);
4891 } else { /* LRM mode ( default )*/
4892
4893 DP(NETIF_MSG_LINK, "Setting LRM MODE\n");
4894
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004895 /*
4896 * Changing to LRM mode takes quite few seconds. So do it only
4897 * if current mode is limiting (default is LRM)
4898 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004899 if (cur_limiting_mode != EDC_MODE_LIMITING)
4900 return 0;
4901
4902 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004903 MDIO_PMA_DEVAD,
4904 MDIO_PMA_REG_LRM_MODE,
4905 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004906 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004907 MDIO_PMA_DEVAD,
4908 MDIO_PMA_REG_ROM_VER2,
4909 0x128);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004910 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004911 MDIO_PMA_DEVAD,
4912 MDIO_PMA_REG_MISC_CTRL0,
4913 0x4008);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004914 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004915 MDIO_PMA_DEVAD,
4916 MDIO_PMA_REG_LRM_MODE,
4917 0xaaaa);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004918 }
4919 return 0;
4920}
4921
4922static u8 bnx2x_8727_set_limiting_mode(struct bnx2x *bp,
4923 struct bnx2x_phy *phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004924 u16 edc_mode)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004925{
4926 u16 phy_identifier;
4927 u16 rom_ver2_val;
4928 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004929 MDIO_PMA_DEVAD,
4930 MDIO_PMA_REG_PHY_IDENTIFIER,
4931 &phy_identifier);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004932
4933 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004934 MDIO_PMA_DEVAD,
4935 MDIO_PMA_REG_PHY_IDENTIFIER,
4936 (phy_identifier & ~(1<<9)));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004937
4938 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004939 MDIO_PMA_DEVAD,
4940 MDIO_PMA_REG_ROM_VER2,
4941 &rom_ver2_val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004942 /* Keep the MSB 8-bits, and set the LSB 8-bits with the edc_mode */
4943 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004944 MDIO_PMA_DEVAD,
4945 MDIO_PMA_REG_ROM_VER2,
4946 (rom_ver2_val & 0xff00) | (edc_mode & 0x00ff));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004947
4948 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004949 MDIO_PMA_DEVAD,
4950 MDIO_PMA_REG_PHY_IDENTIFIER,
4951 (phy_identifier | (1<<9)));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004952
4953 return 0;
4954}
4955
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004956static void bnx2x_8727_specific_func(struct bnx2x_phy *phy,
4957 struct link_params *params,
4958 u32 action)
4959{
4960 struct bnx2x *bp = params->bp;
4961
4962 switch (action) {
4963 case DISABLE_TX:
4964 bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
4965 break;
4966 case ENABLE_TX:
4967 if (!(phy->flags & FLAGS_SFP_NOT_APPROVED))
4968 bnx2x_sfp_set_transmitter(bp, phy, params->port, 1);
4969 break;
4970 default:
4971 DP(NETIF_MSG_LINK, "Function 0x%x not supported by 8727\n",
4972 action);
4973 return;
4974 }
4975}
4976
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004977static u8 bnx2x_sfp_module_detection(struct bnx2x_phy *phy,
4978 struct link_params *params)
4979{
4980 struct bnx2x *bp = params->bp;
4981 u16 edc_mode;
4982 u8 rc = 0;
4983
4984 u32 val = REG_RD(bp, params->shmem_base +
4985 offsetof(struct shmem_region, dev_info.
4986 port_feature_config[params->port].config));
4987
4988 DP(NETIF_MSG_LINK, "SFP+ module plugged in/out detected on port %d\n",
4989 params->port);
4990
4991 if (bnx2x_get_edc_mode(phy, params, &edc_mode) != 0) {
4992 DP(NETIF_MSG_LINK, "Failed to get valid module type\n");
4993 return -EINVAL;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004994 } else if (bnx2x_verify_sfp_module(phy, params) != 0) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004995 /* check SFP+ module compatibility */
4996 DP(NETIF_MSG_LINK, "Module verification failed!!\n");
4997 rc = -EINVAL;
4998 /* Turn on fault module-detected led */
4999 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
5000 MISC_REGISTERS_GPIO_HIGH,
5001 params->port);
5002 if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) &&
5003 ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
5004 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_POWER_DOWN)) {
5005 /* Shutdown SFP+ module */
5006 DP(NETIF_MSG_LINK, "Shutdown SFP+ module!!\n");
5007 bnx2x_8727_power_module(bp, phy, 0);
5008 return rc;
5009 }
5010 } else {
5011 /* Turn off fault module-detected led */
5012 DP(NETIF_MSG_LINK, "Turn off fault module-detected led\n");
5013 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
5014 MISC_REGISTERS_GPIO_LOW,
5015 params->port);
5016 }
5017
5018 /* power up the SFP module */
5019 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
5020 bnx2x_8727_power_module(bp, phy, 1);
5021
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005022 /*
5023 * Check and set limiting mode / LRM mode on 8726. On 8727 it
5024 * is done automatically
5025 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005026 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
5027 bnx2x_8726_set_limiting_mode(bp, phy, edc_mode);
5028 else
5029 bnx2x_8727_set_limiting_mode(bp, phy, edc_mode);
5030 /*
5031 * Enable transmit for this module if the module is approved, or
5032 * if unapproved modules should also enable the Tx laser
5033 */
5034 if (rc == 0 ||
5035 (val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) !=
5036 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
5037 bnx2x_sfp_set_transmitter(bp, phy, params->port, 1);
5038 else
5039 bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
5040
5041 return rc;
5042}
5043
5044void bnx2x_handle_module_detect_int(struct link_params *params)
5045{
5046 struct bnx2x *bp = params->bp;
5047 struct bnx2x_phy *phy = &params->phy[EXT_PHY1];
5048 u32 gpio_val;
5049 u8 port = params->port;
5050
5051 /* Set valid module led off */
5052 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
5053 MISC_REGISTERS_GPIO_HIGH,
5054 params->port);
5055
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005056 /* Get current gpio val reflecting module plugged in / out*/
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005057 gpio_val = bnx2x_get_gpio(bp, MISC_REGISTERS_GPIO_3, port);
5058
5059 /* Call the handling function in case module is detected */
5060 if (gpio_val == 0) {
5061
5062 bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
5063 MISC_REGISTERS_GPIO_INT_OUTPUT_CLR,
5064 port);
5065
5066 if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0)
5067 bnx2x_sfp_module_detection(phy, params);
5068 else
5069 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
5070 } else {
5071 u32 val = REG_RD(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005072 offsetof(struct shmem_region, dev_info.
5073 port_feature_config[params->port].
5074 config));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005075
5076 bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
5077 MISC_REGISTERS_GPIO_INT_OUTPUT_SET,
5078 port);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005079 /*
5080 * Module was plugged out.
5081 * Disable transmit for this module
5082 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005083 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
5084 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
5085 bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
5086 }
5087}
5088
5089/******************************************************************/
5090/* common BCM8706/BCM8726 PHY SECTION */
5091/******************************************************************/
5092static u8 bnx2x_8706_8726_read_status(struct bnx2x_phy *phy,
5093 struct link_params *params,
5094 struct link_vars *vars)
5095{
5096 u8 link_up = 0;
5097 u16 val1, val2, rx_sd, pcs_status;
5098 struct bnx2x *bp = params->bp;
5099 DP(NETIF_MSG_LINK, "XGXS 8706/8726\n");
5100 /* Clear RX Alarm*/
5101 bnx2x_cl45_read(bp, phy,
5102 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &val2);
5103 /* clear LASI indication*/
5104 bnx2x_cl45_read(bp, phy,
5105 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
5106 bnx2x_cl45_read(bp, phy,
5107 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val2);
5108 DP(NETIF_MSG_LINK, "8706/8726 LASI status 0x%x--> 0x%x\n", val1, val2);
5109
5110 bnx2x_cl45_read(bp, phy,
5111 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD, &rx_sd);
5112 bnx2x_cl45_read(bp, phy,
5113 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &pcs_status);
5114 bnx2x_cl45_read(bp, phy,
5115 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &val2);
5116 bnx2x_cl45_read(bp, phy,
5117 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &val2);
5118
5119 DP(NETIF_MSG_LINK, "8706/8726 rx_sd 0x%x pcs_status 0x%x 1Gbps"
5120 " link_status 0x%x\n", rx_sd, pcs_status, val2);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005121 /*
5122 * link is up if both bit 0 of pmd_rx_sd and bit 0 of pcs_status
5123 * are set, or if the autoneg bit 1 is set
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005124 */
5125 link_up = ((rx_sd & pcs_status & 0x1) || (val2 & (1<<1)));
5126 if (link_up) {
5127 if (val2 & (1<<1))
5128 vars->line_speed = SPEED_1000;
5129 else
5130 vars->line_speed = SPEED_10000;
5131 bnx2x_ext_phy_resolve_fc(phy, params, vars);
Yaniv Rosner791f18c2011-01-18 04:33:42 +00005132 vars->duplex = DUPLEX_FULL;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005133 }
5134 return link_up;
5135}
5136
5137/******************************************************************/
5138/* BCM8706 PHY SECTION */
5139/******************************************************************/
5140static u8 bnx2x_8706_config_init(struct bnx2x_phy *phy,
5141 struct link_params *params,
5142 struct link_vars *vars)
5143{
5144 u16 cnt, val;
5145 struct bnx2x *bp = params->bp;
5146 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005147 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005148 /* HW reset */
5149 bnx2x_ext_phy_hw_reset(bp, params->port);
5150 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0xa040);
5151 bnx2x_wait_reset_complete(bp, phy);
5152
5153 /* Wait until fw is loaded */
5154 for (cnt = 0; cnt < 100; cnt++) {
5155 bnx2x_cl45_read(bp, phy,
5156 MDIO_PMA_DEVAD, MDIO_PMA_REG_ROM_VER1, &val);
5157 if (val)
5158 break;
5159 msleep(10);
5160 }
5161 DP(NETIF_MSG_LINK, "XGXS 8706 is initialized after %d ms\n", cnt);
5162 if ((params->feature_config_flags &
5163 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
5164 u8 i;
5165 u16 reg;
5166 for (i = 0; i < 4; i++) {
5167 reg = MDIO_XS_8706_REG_BANK_RX0 +
5168 i*(MDIO_XS_8706_REG_BANK_RX1 -
5169 MDIO_XS_8706_REG_BANK_RX0);
5170 bnx2x_cl45_read(bp, phy, MDIO_XS_DEVAD, reg, &val);
5171 /* Clear first 3 bits of the control */
5172 val &= ~0x7;
5173 /* Set control bits according to configuration */
5174 val |= (phy->rx_preemphasis[i] & 0x7);
5175 DP(NETIF_MSG_LINK, "Setting RX Equalizer to BCM8706"
5176 " reg 0x%x <-- val 0x%x\n", reg, val);
5177 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, reg, val);
5178 }
5179 }
5180 /* Force speed */
5181 if (phy->req_line_speed == SPEED_10000) {
5182 DP(NETIF_MSG_LINK, "XGXS 8706 force 10Gbps\n");
5183
5184 bnx2x_cl45_write(bp, phy,
5185 MDIO_PMA_DEVAD,
5186 MDIO_PMA_REG_DIGITAL_CTRL, 0x400);
5187 bnx2x_cl45_write(bp, phy,
5188 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 1);
5189 } else {
5190 /* Force 1Gbps using autoneg with 1G advertisment */
5191
5192 /* Allow CL37 through CL73 */
5193 DP(NETIF_MSG_LINK, "XGXS 8706 AutoNeg\n");
5194 bnx2x_cl45_write(bp, phy,
5195 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_CL73, 0x040c);
5196
5197 /* Enable Full-Duplex advertisment on CL37 */
5198 bnx2x_cl45_write(bp, phy,
5199 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LP, 0x0020);
5200 /* Enable CL37 AN */
5201 bnx2x_cl45_write(bp, phy,
5202 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
5203 /* 1G support */
5204 bnx2x_cl45_write(bp, phy,
5205 MDIO_AN_DEVAD, MDIO_AN_REG_ADV, (1<<5));
5206
5207 /* Enable clause 73 AN */
5208 bnx2x_cl45_write(bp, phy,
5209 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
5210 bnx2x_cl45_write(bp, phy,
5211 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
5212 0x0400);
5213 bnx2x_cl45_write(bp, phy,
5214 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL,
5215 0x0004);
5216 }
5217 bnx2x_save_bcm_spirom_ver(bp, phy, params->port);
5218 return 0;
5219}
5220
5221static u8 bnx2x_8706_read_status(struct bnx2x_phy *phy,
5222 struct link_params *params,
5223 struct link_vars *vars)
5224{
5225 return bnx2x_8706_8726_read_status(phy, params, vars);
5226}
5227
5228/******************************************************************/
5229/* BCM8726 PHY SECTION */
5230/******************************************************************/
5231static void bnx2x_8726_config_loopback(struct bnx2x_phy *phy,
5232 struct link_params *params)
5233{
5234 struct bnx2x *bp = params->bp;
5235 DP(NETIF_MSG_LINK, "PMA/PMD ext_phy_loopback: 8726\n");
5236 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x0001);
5237}
5238
5239static void bnx2x_8726_external_rom_boot(struct bnx2x_phy *phy,
5240 struct link_params *params)
5241{
5242 struct bnx2x *bp = params->bp;
5243 /* Need to wait 100ms after reset */
5244 msleep(100);
5245
5246 /* Micro controller re-boot */
5247 bnx2x_cl45_write(bp, phy,
5248 MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, 0x018B);
5249
5250 /* Set soft reset */
5251 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005252 MDIO_PMA_DEVAD,
5253 MDIO_PMA_REG_GEN_CTRL,
5254 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005255
5256 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005257 MDIO_PMA_DEVAD,
5258 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005259
5260 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005261 MDIO_PMA_DEVAD,
5262 MDIO_PMA_REG_GEN_CTRL,
5263 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005264
5265 /* wait for 150ms for microcode load */
5266 msleep(150);
5267
5268 /* Disable serial boot control, tristates pins SS_N, SCK, MOSI, MISO */
5269 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005270 MDIO_PMA_DEVAD,
5271 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005272
5273 msleep(200);
5274 bnx2x_save_bcm_spirom_ver(bp, phy, params->port);
5275}
5276
5277static u8 bnx2x_8726_read_status(struct bnx2x_phy *phy,
5278 struct link_params *params,
5279 struct link_vars *vars)
5280{
5281 struct bnx2x *bp = params->bp;
5282 u16 val1;
5283 u8 link_up = bnx2x_8706_8726_read_status(phy, params, vars);
5284 if (link_up) {
5285 bnx2x_cl45_read(bp, phy,
5286 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER,
5287 &val1);
5288 if (val1 & (1<<15)) {
5289 DP(NETIF_MSG_LINK, "Tx is disabled\n");
5290 link_up = 0;
5291 vars->line_speed = 0;
5292 }
5293 }
5294 return link_up;
5295}
5296
5297
5298static u8 bnx2x_8726_config_init(struct bnx2x_phy *phy,
5299 struct link_params *params,
5300 struct link_vars *vars)
5301{
5302 struct bnx2x *bp = params->bp;
5303 u32 val;
5304 u32 swap_val, swap_override, aeu_gpio_mask, offset;
5305 DP(NETIF_MSG_LINK, "Initializing BCM8726\n");
5306 /* Restore normal power mode*/
5307 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
5308 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
5309
5310 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
5311 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
5312
5313 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
5314 bnx2x_wait_reset_complete(bp, phy);
5315
5316 bnx2x_8726_external_rom_boot(phy, params);
5317
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005318 /*
5319 * Need to call module detected on initialization since the module
5320 * detection triggered by actual module insertion might occur before
5321 * driver is loaded, and when driver is loaded, it reset all
5322 * registers, including the transmitter
5323 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005324 bnx2x_sfp_module_detection(phy, params);
5325
5326 if (phy->req_line_speed == SPEED_1000) {
5327 DP(NETIF_MSG_LINK, "Setting 1G force\n");
5328 bnx2x_cl45_write(bp, phy,
5329 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x40);
5330 bnx2x_cl45_write(bp, phy,
5331 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0xD);
5332 bnx2x_cl45_write(bp, phy,
5333 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x5);
5334 bnx2x_cl45_write(bp, phy,
5335 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
5336 0x400);
5337 } else if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
5338 (phy->speed_cap_mask &
5339 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G) &&
5340 ((phy->speed_cap_mask &
5341 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) !=
5342 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
5343 DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
5344 /* Set Flow control */
5345 bnx2x_ext_phy_set_pause(params, phy, vars);
5346 bnx2x_cl45_write(bp, phy,
5347 MDIO_AN_DEVAD, MDIO_AN_REG_ADV, 0x20);
5348 bnx2x_cl45_write(bp, phy,
5349 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_CL73, 0x040c);
5350 bnx2x_cl45_write(bp, phy,
5351 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, 0x0020);
5352 bnx2x_cl45_write(bp, phy,
5353 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
5354 bnx2x_cl45_write(bp, phy,
5355 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005356 /*
5357 * Enable RX-ALARM control to receive interrupt for 1G speed
5358 * change
5359 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005360 bnx2x_cl45_write(bp, phy,
5361 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x4);
5362 bnx2x_cl45_write(bp, phy,
5363 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
5364 0x400);
5365
5366 } else { /* Default 10G. Set only LASI control */
5367 bnx2x_cl45_write(bp, phy,
5368 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 1);
5369 }
5370
5371 /* Set TX PreEmphasis if needed */
5372 if ((params->feature_config_flags &
5373 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
5374 DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x,"
5375 "TX_CTRL2 0x%x\n",
5376 phy->tx_preemphasis[0],
5377 phy->tx_preemphasis[1]);
5378 bnx2x_cl45_write(bp, phy,
5379 MDIO_PMA_DEVAD,
5380 MDIO_PMA_REG_8726_TX_CTRL1,
5381 phy->tx_preemphasis[0]);
5382
5383 bnx2x_cl45_write(bp, phy,
5384 MDIO_PMA_DEVAD,
5385 MDIO_PMA_REG_8726_TX_CTRL2,
5386 phy->tx_preemphasis[1]);
5387 }
5388
5389 /* Set GPIO3 to trigger SFP+ module insertion/removal */
5390 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005391 MISC_REGISTERS_GPIO_INPUT_HI_Z, params->port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005392
5393 /* The GPIO should be swapped if the swap register is set and active */
5394 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
5395 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
5396
5397 /* Select function upon port-swap configuration */
5398 if (params->port == 0) {
5399 offset = MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0;
5400 aeu_gpio_mask = (swap_val && swap_override) ?
5401 AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_1 :
5402 AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0;
5403 } else {
5404 offset = MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0;
5405 aeu_gpio_mask = (swap_val && swap_override) ?
5406 AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0 :
5407 AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_1;
5408 }
5409 val = REG_RD(bp, offset);
5410 /* add GPIO3 to group */
5411 val |= aeu_gpio_mask;
5412 REG_WR(bp, offset, val);
5413 return 0;
5414
5415}
5416
5417static void bnx2x_8726_link_reset(struct bnx2x_phy *phy,
5418 struct link_params *params)
5419{
5420 struct bnx2x *bp = params->bp;
5421 DP(NETIF_MSG_LINK, "bnx2x_8726_link_reset port %d\n", params->port);
5422 /* Set serial boot control for external load */
5423 bnx2x_cl45_write(bp, phy,
5424 MDIO_PMA_DEVAD,
5425 MDIO_PMA_REG_GEN_CTRL, 0x0001);
5426}
5427
5428/******************************************************************/
5429/* BCM8727 PHY SECTION */
5430/******************************************************************/
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005431
5432static void bnx2x_8727_set_link_led(struct bnx2x_phy *phy,
5433 struct link_params *params, u8 mode)
5434{
5435 struct bnx2x *bp = params->bp;
5436 u16 led_mode_bitmask = 0;
5437 u16 gpio_pins_bitmask = 0;
5438 u16 val;
5439 /* Only NOC flavor requires to set the LED specifically */
5440 if (!(phy->flags & FLAGS_NOC))
5441 return;
5442 switch (mode) {
5443 case LED_MODE_FRONT_PANEL_OFF:
5444 case LED_MODE_OFF:
5445 led_mode_bitmask = 0;
5446 gpio_pins_bitmask = 0x03;
5447 break;
5448 case LED_MODE_ON:
5449 led_mode_bitmask = 0;
5450 gpio_pins_bitmask = 0x02;
5451 break;
5452 case LED_MODE_OPER:
5453 led_mode_bitmask = 0x60;
5454 gpio_pins_bitmask = 0x11;
5455 break;
5456 }
5457 bnx2x_cl45_read(bp, phy,
5458 MDIO_PMA_DEVAD,
5459 MDIO_PMA_REG_8727_PCS_OPT_CTRL,
5460 &val);
5461 val &= 0xff8f;
5462 val |= led_mode_bitmask;
5463 bnx2x_cl45_write(bp, phy,
5464 MDIO_PMA_DEVAD,
5465 MDIO_PMA_REG_8727_PCS_OPT_CTRL,
5466 val);
5467 bnx2x_cl45_read(bp, phy,
5468 MDIO_PMA_DEVAD,
5469 MDIO_PMA_REG_8727_GPIO_CTRL,
5470 &val);
5471 val &= 0xffe0;
5472 val |= gpio_pins_bitmask;
5473 bnx2x_cl45_write(bp, phy,
5474 MDIO_PMA_DEVAD,
5475 MDIO_PMA_REG_8727_GPIO_CTRL,
5476 val);
5477}
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005478static void bnx2x_8727_hw_reset(struct bnx2x_phy *phy,
5479 struct link_params *params) {
5480 u32 swap_val, swap_override;
5481 u8 port;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005482 /*
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005483 * The PHY reset is controlled by GPIO 1. Fake the port number
5484 * to cancel the swap done in set_gpio()
5485 */
5486 struct bnx2x *bp = params->bp;
5487 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
5488 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
5489 port = (swap_val && swap_override) ^ 1;
5490 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005491 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005492}
5493
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005494static u8 bnx2x_8727_config_init(struct bnx2x_phy *phy,
5495 struct link_params *params,
5496 struct link_vars *vars)
5497{
5498 u16 tmp1, val, mod_abs;
5499 u16 rx_alarm_ctrl_val;
5500 u16 lasi_ctrl_val;
5501 struct bnx2x *bp = params->bp;
5502 /* Enable PMD link, MOD_ABS_FLT, and 1G link alarm */
5503
5504 bnx2x_wait_reset_complete(bp, phy);
5505 rx_alarm_ctrl_val = (1<<2) | (1<<5) ;
5506 lasi_ctrl_val = 0x0004;
5507
5508 DP(NETIF_MSG_LINK, "Initializing BCM8727\n");
5509 /* enable LASI */
5510 bnx2x_cl45_write(bp, phy,
5511 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
5512 rx_alarm_ctrl_val);
5513
5514 bnx2x_cl45_write(bp, phy,
5515 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, lasi_ctrl_val);
5516
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005517 /*
5518 * Initially configure MOD_ABS to interrupt when module is
5519 * presence( bit 8)
5520 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005521 bnx2x_cl45_read(bp, phy,
5522 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005523 /*
5524 * Set EDC off by setting OPTXLOS signal input to low (bit 9).
5525 * When the EDC is off it locks onto a reference clock and avoids
5526 * becoming 'lost'
5527 */
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005528 mod_abs &= ~(1<<8);
5529 if (!(phy->flags & FLAGS_NOC))
5530 mod_abs &= ~(1<<9);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005531 bnx2x_cl45_write(bp, phy,
5532 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
5533
5534
5535 /* Make MOD_ABS give interrupt on change */
5536 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL,
5537 &val);
5538 val |= (1<<12);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005539 if (phy->flags & FLAGS_NOC)
5540 val |= (3<<5);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005541
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005542 /*
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005543 * Set 8727 GPIOs to input to allow reading from the 8727 GPIO0
5544 * status which reflect SFP+ module over-current
5545 */
5546 if (!(phy->flags & FLAGS_NOC))
5547 val &= 0xff8f; /* Reset bits 4-6 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005548 bnx2x_cl45_write(bp, phy,
5549 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL, val);
5550
5551 bnx2x_8727_power_module(bp, phy, 1);
5552
5553 bnx2x_cl45_read(bp, phy,
5554 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &tmp1);
5555
5556 bnx2x_cl45_read(bp, phy,
5557 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &tmp1);
5558
5559 /* Set option 1G speed */
5560 if (phy->req_line_speed == SPEED_1000) {
5561 DP(NETIF_MSG_LINK, "Setting 1G force\n");
5562 bnx2x_cl45_write(bp, phy,
5563 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x40);
5564 bnx2x_cl45_write(bp, phy,
5565 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0xD);
5566 bnx2x_cl45_read(bp, phy,
5567 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, &tmp1);
5568 DP(NETIF_MSG_LINK, "1.7 = 0x%x\n", tmp1);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005569 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005570 * Power down the XAUI until link is up in case of dual-media
5571 * and 1G
5572 */
5573 if (DUAL_MEDIA(params)) {
5574 bnx2x_cl45_read(bp, phy,
5575 MDIO_PMA_DEVAD,
5576 MDIO_PMA_REG_8727_PCS_GP, &val);
5577 val |= (3<<10);
5578 bnx2x_cl45_write(bp, phy,
5579 MDIO_PMA_DEVAD,
5580 MDIO_PMA_REG_8727_PCS_GP, val);
5581 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005582 } else if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
5583 ((phy->speed_cap_mask &
5584 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) &&
5585 ((phy->speed_cap_mask &
5586 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) !=
5587 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
5588
5589 DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
5590 bnx2x_cl45_write(bp, phy,
5591 MDIO_AN_DEVAD, MDIO_AN_REG_8727_MISC_CTRL, 0);
5592 bnx2x_cl45_write(bp, phy,
5593 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1300);
5594 } else {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005595 /*
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005596 * Since the 8727 has only single reset pin, need to set the 10G
5597 * registers although it is default
5598 */
5599 bnx2x_cl45_write(bp, phy,
5600 MDIO_AN_DEVAD, MDIO_AN_REG_8727_MISC_CTRL,
5601 0x0020);
5602 bnx2x_cl45_write(bp, phy,
5603 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x0100);
5604 bnx2x_cl45_write(bp, phy,
5605 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x2040);
5606 bnx2x_cl45_write(bp, phy,
5607 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2,
5608 0x0008);
5609 }
5610
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005611 /*
5612 * Set 2-wire transfer rate of SFP+ module EEPROM
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005613 * to 100Khz since some DACs(direct attached cables) do
5614 * not work at 400Khz.
5615 */
5616 bnx2x_cl45_write(bp, phy,
5617 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR,
5618 0xa001);
5619
5620 /* Set TX PreEmphasis if needed */
5621 if ((params->feature_config_flags &
5622 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
5623 DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x, TX_CTRL2 0x%x\n",
5624 phy->tx_preemphasis[0],
5625 phy->tx_preemphasis[1]);
5626 bnx2x_cl45_write(bp, phy,
5627 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TX_CTRL1,
5628 phy->tx_preemphasis[0]);
5629
5630 bnx2x_cl45_write(bp, phy,
5631 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TX_CTRL2,
5632 phy->tx_preemphasis[1]);
5633 }
5634
5635 return 0;
5636}
5637
5638static void bnx2x_8727_handle_mod_abs(struct bnx2x_phy *phy,
5639 struct link_params *params)
5640{
5641 struct bnx2x *bp = params->bp;
5642 u16 mod_abs, rx_alarm_status;
5643 u32 val = REG_RD(bp, params->shmem_base +
5644 offsetof(struct shmem_region, dev_info.
5645 port_feature_config[params->port].
5646 config));
5647 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005648 MDIO_PMA_DEVAD,
5649 MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005650 if (mod_abs & (1<<8)) {
5651
5652 /* Module is absent */
5653 DP(NETIF_MSG_LINK, "MOD_ABS indication "
5654 "show module is absent\n");
5655
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005656 /*
5657 * 1. Set mod_abs to detect next module
5658 * presence event
5659 * 2. Set EDC off by setting OPTXLOS signal input to low
5660 * (bit 9).
5661 * When the EDC is off it locks onto a reference clock and
5662 * avoids becoming 'lost'.
5663 */
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005664 mod_abs &= ~(1<<8);
5665 if (!(phy->flags & FLAGS_NOC))
5666 mod_abs &= ~(1<<9);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005667 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005668 MDIO_PMA_DEVAD,
5669 MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005670
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005671 /*
5672 * Clear RX alarm since it stays up as long as
5673 * the mod_abs wasn't changed
5674 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005675 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005676 MDIO_PMA_DEVAD,
5677 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005678
5679 } else {
5680 /* Module is present */
5681 DP(NETIF_MSG_LINK, "MOD_ABS indication "
5682 "show module is present\n");
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005683 /*
5684 * First disable transmitter, and if the module is ok, the
5685 * module_detection will enable it
5686 * 1. Set mod_abs to detect next module absent event ( bit 8)
5687 * 2. Restore the default polarity of the OPRXLOS signal and
5688 * this signal will then correctly indicate the presence or
5689 * absence of the Rx signal. (bit 9)
5690 */
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005691 mod_abs |= (1<<8);
5692 if (!(phy->flags & FLAGS_NOC))
5693 mod_abs |= (1<<9);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005694 bnx2x_cl45_write(bp, phy,
5695 MDIO_PMA_DEVAD,
5696 MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
5697
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005698 /*
5699 * Clear RX alarm since it stays up as long as the mod_abs
5700 * wasn't changed. This is need to be done before calling the
5701 * module detection, otherwise it will clear* the link update
5702 * alarm
5703 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005704 bnx2x_cl45_read(bp, phy,
5705 MDIO_PMA_DEVAD,
5706 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
5707
5708
5709 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
5710 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
5711 bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
5712
5713 if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0)
5714 bnx2x_sfp_module_detection(phy, params);
5715 else
5716 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
5717 }
5718
5719 DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n",
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005720 rx_alarm_status);
5721 /* No need to check link status in case of module plugged in/out */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005722}
5723
5724static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy,
5725 struct link_params *params,
5726 struct link_vars *vars)
5727
5728{
5729 struct bnx2x *bp = params->bp;
5730 u8 link_up = 0;
5731 u16 link_status = 0;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005732 u16 rx_alarm_status, lasi_ctrl, val1;
5733
5734 /* If PHY is not initialized, do not check link status */
5735 bnx2x_cl45_read(bp, phy,
5736 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL,
5737 &lasi_ctrl);
5738 if (!lasi_ctrl)
5739 return 0;
5740
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005741 /* Check the LASI */
5742 bnx2x_cl45_read(bp, phy,
5743 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM,
5744 &rx_alarm_status);
5745 vars->line_speed = 0;
5746 DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n", rx_alarm_status);
5747
5748 bnx2x_cl45_read(bp, phy,
5749 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
5750
5751 DP(NETIF_MSG_LINK, "8727 LASI status 0x%x\n", val1);
5752
5753 /* Clear MSG-OUT */
5754 bnx2x_cl45_read(bp, phy,
5755 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &val1);
5756
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005757 /*
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005758 * If a module is present and there is need to check
5759 * for over current
5760 */
5761 if (!(phy->flags & FLAGS_NOC) && !(rx_alarm_status & (1<<5))) {
5762 /* Check over-current using 8727 GPIO0 input*/
5763 bnx2x_cl45_read(bp, phy,
5764 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_GPIO_CTRL,
5765 &val1);
5766
5767 if ((val1 & (1<<8)) == 0) {
5768 DP(NETIF_MSG_LINK, "8727 Power fault has been detected"
5769 " on port %d\n", params->port);
5770 netdev_err(bp->dev, "Error: Power fault on Port %d has"
5771 " been detected and the power to "
5772 "that SFP+ module has been removed"
5773 " to prevent failure of the card."
5774 " Please remove the SFP+ module and"
5775 " restart the system to clear this"
5776 " error.\n",
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005777 params->port);
5778 /* Disable all RX_ALARMs except for mod_abs */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005779 bnx2x_cl45_write(bp, phy,
5780 MDIO_PMA_DEVAD,
5781 MDIO_PMA_REG_RX_ALARM_CTRL, (1<<5));
5782
5783 bnx2x_cl45_read(bp, phy,
5784 MDIO_PMA_DEVAD,
5785 MDIO_PMA_REG_PHY_IDENTIFIER, &val1);
5786 /* Wait for module_absent_event */
5787 val1 |= (1<<8);
5788 bnx2x_cl45_write(bp, phy,
5789 MDIO_PMA_DEVAD,
5790 MDIO_PMA_REG_PHY_IDENTIFIER, val1);
5791 /* Clear RX alarm */
5792 bnx2x_cl45_read(bp, phy,
5793 MDIO_PMA_DEVAD,
5794 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
5795 return 0;
5796 }
5797 } /* Over current check */
5798
5799 /* When module absent bit is set, check module */
5800 if (rx_alarm_status & (1<<5)) {
5801 bnx2x_8727_handle_mod_abs(phy, params);
5802 /* Enable all mod_abs and link detection bits */
5803 bnx2x_cl45_write(bp, phy,
5804 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
5805 ((1<<5) | (1<<2)));
5806 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005807 DP(NETIF_MSG_LINK, "Enabling 8727 TX laser if SFP is approved\n");
5808 bnx2x_8727_specific_func(phy, params, ENABLE_TX);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005809 /* If transmitter is disabled, ignore false link up indication */
5810 bnx2x_cl45_read(bp, phy,
5811 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, &val1);
5812 if (val1 & (1<<15)) {
5813 DP(NETIF_MSG_LINK, "Tx is disabled\n");
5814 return 0;
5815 }
5816
5817 bnx2x_cl45_read(bp, phy,
5818 MDIO_PMA_DEVAD,
5819 MDIO_PMA_REG_8073_SPEED_LINK_STATUS, &link_status);
5820
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005821 /*
5822 * Bits 0..2 --> speed detected,
5823 * Bits 13..15--> link is down
5824 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005825 if ((link_status & (1<<2)) && (!(link_status & (1<<15)))) {
5826 link_up = 1;
5827 vars->line_speed = SPEED_10000;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005828 DP(NETIF_MSG_LINK, "port %x: External link up in 10G\n",
5829 params->port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005830 } else if ((link_status & (1<<0)) && (!(link_status & (1<<13)))) {
5831 link_up = 1;
5832 vars->line_speed = SPEED_1000;
5833 DP(NETIF_MSG_LINK, "port %x: External link up in 1G\n",
5834 params->port);
5835 } else {
5836 link_up = 0;
5837 DP(NETIF_MSG_LINK, "port %x: External link is down\n",
5838 params->port);
5839 }
Yaniv Rosner791f18c2011-01-18 04:33:42 +00005840 if (link_up) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005841 bnx2x_ext_phy_resolve_fc(phy, params, vars);
Yaniv Rosner791f18c2011-01-18 04:33:42 +00005842 vars->duplex = DUPLEX_FULL;
5843 DP(NETIF_MSG_LINK, "duplex = 0x%x\n", vars->duplex);
5844 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005845
5846 if ((DUAL_MEDIA(params)) &&
5847 (phy->req_line_speed == SPEED_1000)) {
5848 bnx2x_cl45_read(bp, phy,
5849 MDIO_PMA_DEVAD,
5850 MDIO_PMA_REG_8727_PCS_GP, &val1);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005851 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005852 * In case of dual-media board and 1G, power up the XAUI side,
5853 * otherwise power it down. For 10G it is done automatically
5854 */
5855 if (link_up)
5856 val1 &= ~(3<<10);
5857 else
5858 val1 |= (3<<10);
5859 bnx2x_cl45_write(bp, phy,
5860 MDIO_PMA_DEVAD,
5861 MDIO_PMA_REG_8727_PCS_GP, val1);
5862 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005863 return link_up;
5864}
5865
5866static void bnx2x_8727_link_reset(struct bnx2x_phy *phy,
5867 struct link_params *params)
5868{
5869 struct bnx2x *bp = params->bp;
5870 /* Disable Transmitter */
5871 bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005872 /* Clear LASI */
5873 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0);
5874
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005875}
5876
5877/******************************************************************/
5878/* BCM8481/BCM84823/BCM84833 PHY SECTION */
5879/******************************************************************/
5880static void bnx2x_save_848xx_spirom_version(struct bnx2x_phy *phy,
5881 struct link_params *params)
5882{
5883 u16 val, fw_ver1, fw_ver2, cnt;
5884 struct bnx2x *bp = params->bp;
5885
5886 /* For the 32 bits registers in 848xx, access via MDIO2ARM interface.*/
5887 /* (1) set register 0xc200_0014(SPI_BRIDGE_CTRL_2) to 0x03000000 */
5888 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0014);
5889 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200);
5890 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81B, 0x0000);
5891 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81C, 0x0300);
5892 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x0009);
5893
5894 for (cnt = 0; cnt < 100; cnt++) {
5895 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val);
5896 if (val & 1)
5897 break;
5898 udelay(5);
5899 }
5900 if (cnt == 100) {
5901 DP(NETIF_MSG_LINK, "Unable to read 848xx phy fw version(1)\n");
5902 bnx2x_save_spirom_version(bp, params->port, 0,
5903 phy->ver_addr);
5904 return;
5905 }
5906
5907
5908 /* 2) read register 0xc200_0000 (SPI_FW_STATUS) */
5909 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0000);
5910 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200);
5911 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x000A);
5912 for (cnt = 0; cnt < 100; cnt++) {
5913 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val);
5914 if (val & 1)
5915 break;
5916 udelay(5);
5917 }
5918 if (cnt == 100) {
5919 DP(NETIF_MSG_LINK, "Unable to read 848xx phy fw version(2)\n");
5920 bnx2x_save_spirom_version(bp, params->port, 0,
5921 phy->ver_addr);
5922 return;
5923 }
5924
5925 /* lower 16 bits of the register SPI_FW_STATUS */
5926 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81B, &fw_ver1);
5927 /* upper 16 bits of register SPI_FW_STATUS */
5928 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81C, &fw_ver2);
5929
5930 bnx2x_save_spirom_version(bp, params->port, (fw_ver2<<16) | fw_ver1,
5931 phy->ver_addr);
5932}
5933
5934static void bnx2x_848xx_set_led(struct bnx2x *bp,
5935 struct bnx2x_phy *phy)
5936{
5937 u16 val;
5938
5939 /* PHYC_CTL_LED_CTL */
5940 bnx2x_cl45_read(bp, phy,
5941 MDIO_PMA_DEVAD,
5942 MDIO_PMA_REG_8481_LINK_SIGNAL, &val);
5943 val &= 0xFE00;
5944 val |= 0x0092;
5945
5946 bnx2x_cl45_write(bp, phy,
5947 MDIO_PMA_DEVAD,
5948 MDIO_PMA_REG_8481_LINK_SIGNAL, val);
5949
5950 bnx2x_cl45_write(bp, phy,
5951 MDIO_PMA_DEVAD,
5952 MDIO_PMA_REG_8481_LED1_MASK,
5953 0x80);
5954
5955 bnx2x_cl45_write(bp, phy,
5956 MDIO_PMA_DEVAD,
5957 MDIO_PMA_REG_8481_LED2_MASK,
5958 0x18);
5959
Yaniv Rosnerf25b3c82011-01-18 04:33:47 +00005960 /* Select activity source by Tx and Rx, as suggested by PHY AE */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005961 bnx2x_cl45_write(bp, phy,
5962 MDIO_PMA_DEVAD,
5963 MDIO_PMA_REG_8481_LED3_MASK,
Yaniv Rosnerf25b3c82011-01-18 04:33:47 +00005964 0x0006);
5965
5966 /* Select the closest activity blink rate to that in 10/100/1000 */
5967 bnx2x_cl45_write(bp, phy,
5968 MDIO_PMA_DEVAD,
5969 MDIO_PMA_REG_8481_LED3_BLINK,
5970 0);
5971
5972 bnx2x_cl45_read(bp, phy,
5973 MDIO_PMA_DEVAD,
5974 MDIO_PMA_REG_84823_CTL_LED_CTL_1, &val);
5975 val |= MDIO_PMA_REG_84823_LED3_STRETCH_EN; /* stretch_en for LED3*/
5976
5977 bnx2x_cl45_write(bp, phy,
5978 MDIO_PMA_DEVAD,
5979 MDIO_PMA_REG_84823_CTL_LED_CTL_1, val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005980
5981 /* 'Interrupt Mask' */
5982 bnx2x_cl45_write(bp, phy,
5983 MDIO_AN_DEVAD,
5984 0xFFFB, 0xFFFD);
5985}
5986
5987static u8 bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005988 struct link_params *params,
5989 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005990{
5991 struct bnx2x *bp = params->bp;
5992 u16 autoneg_val, an_1000_val, an_10_100_val;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005993 /*
5994 * This phy uses the NIG latch mechanism since link indication
5995 * arrives through its LED4 and not via its LASI signal, so we
5996 * get steady signal instead of clear on read
5997 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005998 bnx2x_bits_en(bp, NIG_REG_LATCH_BC_0 + params->port*4,
5999 1 << NIG_LATCH_BC_ENABLE_MI_INT);
6000
6001 bnx2x_cl45_write(bp, phy,
6002 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x0000);
6003
6004 bnx2x_848xx_set_led(bp, phy);
6005
6006 /* set 1000 speed advertisement */
6007 bnx2x_cl45_read(bp, phy,
6008 MDIO_AN_DEVAD, MDIO_AN_REG_8481_1000T_CTRL,
6009 &an_1000_val);
6010
6011 bnx2x_ext_phy_set_pause(params, phy, vars);
6012 bnx2x_cl45_read(bp, phy,
6013 MDIO_AN_DEVAD,
6014 MDIO_AN_REG_8481_LEGACY_AN_ADV,
6015 &an_10_100_val);
6016 bnx2x_cl45_read(bp, phy,
6017 MDIO_AN_DEVAD, MDIO_AN_REG_8481_LEGACY_MII_CTRL,
6018 &autoneg_val);
6019 /* Disable forced speed */
6020 autoneg_val &= ~((1<<6) | (1<<8) | (1<<9) | (1<<12) | (1<<13));
6021 an_10_100_val &= ~((1<<5) | (1<<6) | (1<<7) | (1<<8));
6022
6023 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
6024 (phy->speed_cap_mask &
6025 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) ||
6026 (phy->req_line_speed == SPEED_1000)) {
6027 an_1000_val |= (1<<8);
6028 autoneg_val |= (1<<9 | 1<<12);
6029 if (phy->req_duplex == DUPLEX_FULL)
6030 an_1000_val |= (1<<9);
6031 DP(NETIF_MSG_LINK, "Advertising 1G\n");
6032 } else
6033 an_1000_val &= ~((1<<8) | (1<<9));
6034
6035 bnx2x_cl45_write(bp, phy,
6036 MDIO_AN_DEVAD, MDIO_AN_REG_8481_1000T_CTRL,
6037 an_1000_val);
6038
6039 /* set 10 speed advertisement */
6040 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
6041 (phy->speed_cap_mask &
6042 (PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL |
6043 PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF)))) {
6044 an_10_100_val |= (1<<7);
6045 /* Enable autoneg and restart autoneg for legacy speeds */
6046 autoneg_val |= (1<<9 | 1<<12);
6047
6048 if (phy->req_duplex == DUPLEX_FULL)
6049 an_10_100_val |= (1<<8);
6050 DP(NETIF_MSG_LINK, "Advertising 100M\n");
6051 }
6052 /* set 10 speed advertisement */
6053 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
6054 (phy->speed_cap_mask &
6055 (PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL |
6056 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF)))) {
6057 an_10_100_val |= (1<<5);
6058 autoneg_val |= (1<<9 | 1<<12);
6059 if (phy->req_duplex == DUPLEX_FULL)
6060 an_10_100_val |= (1<<6);
6061 DP(NETIF_MSG_LINK, "Advertising 10M\n");
6062 }
6063
6064 /* Only 10/100 are allowed to work in FORCE mode */
6065 if (phy->req_line_speed == SPEED_100) {
6066 autoneg_val |= (1<<13);
6067 /* Enabled AUTO-MDIX when autoneg is disabled */
6068 bnx2x_cl45_write(bp, phy,
6069 MDIO_AN_DEVAD, MDIO_AN_REG_8481_AUX_CTRL,
6070 (1<<15 | 1<<9 | 7<<0));
6071 DP(NETIF_MSG_LINK, "Setting 100M force\n");
6072 }
6073 if (phy->req_line_speed == SPEED_10) {
6074 /* Enabled AUTO-MDIX when autoneg is disabled */
6075 bnx2x_cl45_write(bp, phy,
6076 MDIO_AN_DEVAD, MDIO_AN_REG_8481_AUX_CTRL,
6077 (1<<15 | 1<<9 | 7<<0));
6078 DP(NETIF_MSG_LINK, "Setting 10M force\n");
6079 }
6080
6081 bnx2x_cl45_write(bp, phy,
6082 MDIO_AN_DEVAD, MDIO_AN_REG_8481_LEGACY_AN_ADV,
6083 an_10_100_val);
6084
6085 if (phy->req_duplex == DUPLEX_FULL)
6086 autoneg_val |= (1<<8);
6087
6088 bnx2x_cl45_write(bp, phy,
6089 MDIO_AN_DEVAD,
6090 MDIO_AN_REG_8481_LEGACY_MII_CTRL, autoneg_val);
6091
6092 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
6093 (phy->speed_cap_mask &
6094 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) ||
6095 (phy->req_line_speed == SPEED_10000)) {
6096 DP(NETIF_MSG_LINK, "Advertising 10G\n");
6097 /* Restart autoneg for 10G*/
6098
6099 bnx2x_cl45_write(bp, phy,
6100 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL,
6101 0x3200);
6102 } else if (phy->req_line_speed != SPEED_10 &&
6103 phy->req_line_speed != SPEED_100) {
6104 bnx2x_cl45_write(bp, phy,
6105 MDIO_AN_DEVAD,
6106 MDIO_AN_REG_8481_10GBASE_T_AN_CTRL,
6107 1);
6108 }
6109 /* Save spirom version */
6110 bnx2x_save_848xx_spirom_version(phy, params);
6111
6112 return 0;
6113}
6114
6115static u8 bnx2x_8481_config_init(struct bnx2x_phy *phy,
6116 struct link_params *params,
6117 struct link_vars *vars)
6118{
6119 struct bnx2x *bp = params->bp;
6120 /* Restore normal power mode*/
6121 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006122 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006123
6124 /* HW reset */
6125 bnx2x_ext_phy_hw_reset(bp, params->port);
Yaniv Rosner9bffeac2010-11-01 05:32:27 +00006126 bnx2x_wait_reset_complete(bp, phy);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006127
6128 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
6129 return bnx2x_848xx_cmn_config_init(phy, params, vars);
6130}
6131
6132static u8 bnx2x_848x3_config_init(struct bnx2x_phy *phy,
6133 struct link_params *params,
6134 struct link_vars *vars)
6135{
6136 struct bnx2x *bp = params->bp;
Yaniv Rosner6a71bbe2010-11-01 05:32:31 +00006137 u8 port, initialize = 1;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006138 u16 val;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006139 u16 temp;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006140 u32 actual_phy_selection;
6141 u8 rc = 0;
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006142
6143 /* This is just for MDIO_CTL_REG_84823_MEDIA register. */
6144
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006145 msleep(1);
Yaniv Rosner6a71bbe2010-11-01 05:32:31 +00006146 if (CHIP_IS_E2(bp))
6147 port = BP_PATH(bp);
6148 else
6149 port = params->port;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006150 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
6151 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006152 port);
Yaniv Rosner9bffeac2010-11-01 05:32:27 +00006153 bnx2x_wait_reset_complete(bp, phy);
6154 /* Wait for GPHY to come out of reset */
6155 msleep(50);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006156 /*
6157 * BCM84823 requires that XGXS links up first @ 10G for normal behavior
6158 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006159 temp = vars->line_speed;
6160 vars->line_speed = SPEED_10000;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006161 bnx2x_set_autoneg(&params->phy[INT_PHY], params, vars, 0);
6162 bnx2x_program_serdes(&params->phy[INT_PHY], params, vars);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006163 vars->line_speed = temp;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006164
6165 /* Set dual-media configuration according to configuration */
6166
6167 bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
6168 MDIO_CTL_REG_84823_MEDIA, &val);
6169 val &= ~(MDIO_CTL_REG_84823_MEDIA_MAC_MASK |
6170 MDIO_CTL_REG_84823_MEDIA_LINE_MASK |
6171 MDIO_CTL_REG_84823_MEDIA_COPPER_CORE_DOWN |
6172 MDIO_CTL_REG_84823_MEDIA_PRIORITY_MASK |
6173 MDIO_CTL_REG_84823_MEDIA_FIBER_1G);
6174 val |= MDIO_CTL_REG_84823_CTRL_MAC_XFI |
6175 MDIO_CTL_REG_84823_MEDIA_LINE_XAUI_L;
6176
6177 actual_phy_selection = bnx2x_phy_selection(params);
6178
6179 switch (actual_phy_selection) {
6180 case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT:
6181 /* Do nothing. Essentialy this is like the priority copper */
6182 break;
6183 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
6184 val |= MDIO_CTL_REG_84823_MEDIA_PRIORITY_COPPER;
6185 break;
6186 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
6187 val |= MDIO_CTL_REG_84823_MEDIA_PRIORITY_FIBER;
6188 break;
6189 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY:
6190 /* Do nothing here. The first PHY won't be initialized at all */
6191 break;
6192 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY:
6193 val |= MDIO_CTL_REG_84823_MEDIA_COPPER_CORE_DOWN;
6194 initialize = 0;
6195 break;
6196 }
6197 if (params->phy[EXT_PHY2].req_line_speed == SPEED_1000)
6198 val |= MDIO_CTL_REG_84823_MEDIA_FIBER_1G;
6199
6200 bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
6201 MDIO_CTL_REG_84823_MEDIA, val);
6202 DP(NETIF_MSG_LINK, "Multi_phy config = 0x%x, Media control = 0x%x\n",
6203 params->multi_phy_config, val);
6204
6205 if (initialize)
6206 rc = bnx2x_848xx_cmn_config_init(phy, params, vars);
6207 else
6208 bnx2x_save_848xx_spirom_version(phy, params);
6209 return rc;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006210}
6211
6212static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006213 struct link_params *params,
6214 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006215{
6216 struct bnx2x *bp = params->bp;
6217 u16 val, val1, val2;
6218 u8 link_up = 0;
6219
6220 /* Check 10G-BaseT link status */
6221 /* Check PMD signal ok */
6222 bnx2x_cl45_read(bp, phy,
6223 MDIO_AN_DEVAD, 0xFFFA, &val1);
6224 bnx2x_cl45_read(bp, phy,
6225 MDIO_PMA_DEVAD, MDIO_PMA_REG_8481_PMD_SIGNAL,
6226 &val2);
6227 DP(NETIF_MSG_LINK, "BCM848xx: PMD_SIGNAL 1.a811 = 0x%x\n", val2);
6228
6229 /* Check link 10G */
6230 if (val2 & (1<<11)) {
6231 vars->line_speed = SPEED_10000;
Yaniv Rosner791f18c2011-01-18 04:33:42 +00006232 vars->duplex = DUPLEX_FULL;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006233 link_up = 1;
6234 bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
6235 } else { /* Check Legacy speed link */
6236 u16 legacy_status, legacy_speed;
6237
6238 /* Enable expansion register 0x42 (Operation mode status) */
6239 bnx2x_cl45_write(bp, phy,
6240 MDIO_AN_DEVAD,
6241 MDIO_AN_REG_8481_EXPANSION_REG_ACCESS, 0xf42);
6242
6243 /* Get legacy speed operation status */
6244 bnx2x_cl45_read(bp, phy,
6245 MDIO_AN_DEVAD,
6246 MDIO_AN_REG_8481_EXPANSION_REG_RD_RW,
6247 &legacy_status);
6248
6249 DP(NETIF_MSG_LINK, "Legacy speed status"
6250 " = 0x%x\n", legacy_status);
6251 link_up = ((legacy_status & (1<<11)) == (1<<11));
6252 if (link_up) {
6253 legacy_speed = (legacy_status & (3<<9));
6254 if (legacy_speed == (0<<9))
6255 vars->line_speed = SPEED_10;
6256 else if (legacy_speed == (1<<9))
6257 vars->line_speed = SPEED_100;
6258 else if (legacy_speed == (2<<9))
6259 vars->line_speed = SPEED_1000;
6260 else /* Should not happen */
6261 vars->line_speed = 0;
6262
6263 if (legacy_status & (1<<8))
6264 vars->duplex = DUPLEX_FULL;
6265 else
6266 vars->duplex = DUPLEX_HALF;
6267
6268 DP(NETIF_MSG_LINK, "Link is up in %dMbps,"
6269 " is_duplex_full= %d\n", vars->line_speed,
6270 (vars->duplex == DUPLEX_FULL));
6271 /* Check legacy speed AN resolution */
6272 bnx2x_cl45_read(bp, phy,
6273 MDIO_AN_DEVAD,
6274 MDIO_AN_REG_8481_LEGACY_MII_STATUS,
6275 &val);
6276 if (val & (1<<5))
6277 vars->link_status |=
6278 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
6279 bnx2x_cl45_read(bp, phy,
6280 MDIO_AN_DEVAD,
6281 MDIO_AN_REG_8481_LEGACY_AN_EXPANSION,
6282 &val);
6283 if ((val & (1<<0)) == 0)
6284 vars->link_status |=
6285 LINK_STATUS_PARALLEL_DETECTION_USED;
6286 }
6287 }
6288 if (link_up) {
6289 DP(NETIF_MSG_LINK, "BCM84823: link speed is %d\n",
6290 vars->line_speed);
6291 bnx2x_ext_phy_resolve_fc(phy, params, vars);
6292 }
6293
6294 return link_up;
6295}
6296
6297static u8 bnx2x_848xx_format_ver(u32 raw_ver, u8 *str, u16 *len)
6298{
6299 u8 status = 0;
6300 u32 spirom_ver;
6301 spirom_ver = ((raw_ver & 0xF80) >> 7) << 16 | (raw_ver & 0x7F);
6302 status = bnx2x_format_ver(spirom_ver, str, len);
6303 return status;
6304}
6305
6306static void bnx2x_8481_hw_reset(struct bnx2x_phy *phy,
6307 struct link_params *params)
6308{
6309 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006310 MISC_REGISTERS_GPIO_OUTPUT_LOW, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006311 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006312 MISC_REGISTERS_GPIO_OUTPUT_LOW, 1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006313}
6314
6315static void bnx2x_8481_link_reset(struct bnx2x_phy *phy,
6316 struct link_params *params)
6317{
6318 bnx2x_cl45_write(params->bp, phy,
6319 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x0000);
6320 bnx2x_cl45_write(params->bp, phy,
6321 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1);
6322}
6323
6324static void bnx2x_848x3_link_reset(struct bnx2x_phy *phy,
6325 struct link_params *params)
6326{
6327 struct bnx2x *bp = params->bp;
Yaniv Rosner6a71bbe2010-11-01 05:32:31 +00006328 u8 port;
6329 if (CHIP_IS_E2(bp))
6330 port = BP_PATH(bp);
6331 else
6332 port = params->port;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006333 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006334 MISC_REGISTERS_GPIO_OUTPUT_LOW,
6335 port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006336}
6337
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006338static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy,
6339 struct link_params *params, u8 mode)
6340{
6341 struct bnx2x *bp = params->bp;
6342 u16 val;
6343
6344 switch (mode) {
6345 case LED_MODE_OFF:
6346
6347 DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE OFF\n", params->port);
6348
6349 if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
6350 SHARED_HW_CFG_LED_EXTPHY1) {
6351
6352 /* Set LED masks */
6353 bnx2x_cl45_write(bp, phy,
6354 MDIO_PMA_DEVAD,
6355 MDIO_PMA_REG_8481_LED1_MASK,
6356 0x0);
6357
6358 bnx2x_cl45_write(bp, phy,
6359 MDIO_PMA_DEVAD,
6360 MDIO_PMA_REG_8481_LED2_MASK,
6361 0x0);
6362
6363 bnx2x_cl45_write(bp, phy,
6364 MDIO_PMA_DEVAD,
6365 MDIO_PMA_REG_8481_LED3_MASK,
6366 0x0);
6367
6368 bnx2x_cl45_write(bp, phy,
6369 MDIO_PMA_DEVAD,
6370 MDIO_PMA_REG_8481_LED5_MASK,
6371 0x0);
6372
6373 } else {
6374 bnx2x_cl45_write(bp, phy,
6375 MDIO_PMA_DEVAD,
6376 MDIO_PMA_REG_8481_LED1_MASK,
6377 0x0);
6378 }
6379 break;
6380 case LED_MODE_FRONT_PANEL_OFF:
6381
6382 DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE FRONT PANEL OFF\n",
6383 params->port);
6384
6385 if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
6386 SHARED_HW_CFG_LED_EXTPHY1) {
6387
6388 /* Set LED masks */
6389 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006390 MDIO_PMA_DEVAD,
6391 MDIO_PMA_REG_8481_LED1_MASK,
6392 0x0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006393
6394 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006395 MDIO_PMA_DEVAD,
6396 MDIO_PMA_REG_8481_LED2_MASK,
6397 0x0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006398
6399 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006400 MDIO_PMA_DEVAD,
6401 MDIO_PMA_REG_8481_LED3_MASK,
6402 0x0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006403
6404 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006405 MDIO_PMA_DEVAD,
6406 MDIO_PMA_REG_8481_LED5_MASK,
6407 0x20);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006408
6409 } else {
6410 bnx2x_cl45_write(bp, phy,
6411 MDIO_PMA_DEVAD,
6412 MDIO_PMA_REG_8481_LED1_MASK,
6413 0x0);
6414 }
6415 break;
6416 case LED_MODE_ON:
6417
6418 DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE ON\n", params->port);
6419
6420 if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
6421 SHARED_HW_CFG_LED_EXTPHY1) {
6422 /* Set control reg */
6423 bnx2x_cl45_read(bp, phy,
6424 MDIO_PMA_DEVAD,
6425 MDIO_PMA_REG_8481_LINK_SIGNAL,
6426 &val);
6427 val &= 0x8000;
6428 val |= 0x2492;
6429
6430 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006431 MDIO_PMA_DEVAD,
6432 MDIO_PMA_REG_8481_LINK_SIGNAL,
6433 val);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006434
6435 /* Set LED masks */
6436 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006437 MDIO_PMA_DEVAD,
6438 MDIO_PMA_REG_8481_LED1_MASK,
6439 0x0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006440
6441 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006442 MDIO_PMA_DEVAD,
6443 MDIO_PMA_REG_8481_LED2_MASK,
6444 0x20);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006445
6446 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006447 MDIO_PMA_DEVAD,
6448 MDIO_PMA_REG_8481_LED3_MASK,
6449 0x20);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006450
6451 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006452 MDIO_PMA_DEVAD,
6453 MDIO_PMA_REG_8481_LED5_MASK,
6454 0x0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006455 } else {
6456 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006457 MDIO_PMA_DEVAD,
6458 MDIO_PMA_REG_8481_LED1_MASK,
6459 0x20);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006460 }
6461 break;
6462
6463 case LED_MODE_OPER:
6464
6465 DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE OPER\n", params->port);
6466
6467 if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
6468 SHARED_HW_CFG_LED_EXTPHY1) {
6469
6470 /* Set control reg */
6471 bnx2x_cl45_read(bp, phy,
6472 MDIO_PMA_DEVAD,
6473 MDIO_PMA_REG_8481_LINK_SIGNAL,
6474 &val);
6475
6476 if (!((val &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006477 MDIO_PMA_REG_8481_LINK_SIGNAL_LED4_ENABLE_MASK)
6478 >> MDIO_PMA_REG_8481_LINK_SIGNAL_LED4_ENABLE_SHIFT)) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006479 DP(NETIF_MSG_LINK, "Setting LINK_SIGNAL\n");
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006480 bnx2x_cl45_write(bp, phy,
6481 MDIO_PMA_DEVAD,
6482 MDIO_PMA_REG_8481_LINK_SIGNAL,
6483 0xa492);
6484 }
6485
6486 /* Set LED masks */
6487 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006488 MDIO_PMA_DEVAD,
6489 MDIO_PMA_REG_8481_LED1_MASK,
6490 0x10);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006491
6492 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006493 MDIO_PMA_DEVAD,
6494 MDIO_PMA_REG_8481_LED2_MASK,
6495 0x80);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006496
6497 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006498 MDIO_PMA_DEVAD,
6499 MDIO_PMA_REG_8481_LED3_MASK,
6500 0x98);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006501
6502 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006503 MDIO_PMA_DEVAD,
6504 MDIO_PMA_REG_8481_LED5_MASK,
6505 0x40);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006506
6507 } else {
6508 bnx2x_cl45_write(bp, phy,
6509 MDIO_PMA_DEVAD,
6510 MDIO_PMA_REG_8481_LED1_MASK,
6511 0x80);
Yaniv Rosner53eda062011-01-30 04:14:55 +00006512
6513 /* Tell LED3 to blink on source */
6514 bnx2x_cl45_read(bp, phy,
6515 MDIO_PMA_DEVAD,
6516 MDIO_PMA_REG_8481_LINK_SIGNAL,
6517 &val);
6518 val &= ~(7<<6);
6519 val |= (1<<6); /* A83B[8:6]= 1 */
6520 bnx2x_cl45_write(bp, phy,
6521 MDIO_PMA_DEVAD,
6522 MDIO_PMA_REG_8481_LINK_SIGNAL,
6523 val);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006524 }
6525 break;
6526 }
6527}
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006528/******************************************************************/
6529/* SFX7101 PHY SECTION */
6530/******************************************************************/
6531static void bnx2x_7101_config_loopback(struct bnx2x_phy *phy,
6532 struct link_params *params)
6533{
6534 struct bnx2x *bp = params->bp;
6535 /* SFX7101_XGXS_TEST1 */
6536 bnx2x_cl45_write(bp, phy,
6537 MDIO_XS_DEVAD, MDIO_XS_SFX7101_XGXS_TEST1, 0x100);
6538}
6539
6540static u8 bnx2x_7101_config_init(struct bnx2x_phy *phy,
6541 struct link_params *params,
6542 struct link_vars *vars)
6543{
6544 u16 fw_ver1, fw_ver2, val;
6545 struct bnx2x *bp = params->bp;
6546 DP(NETIF_MSG_LINK, "Setting the SFX7101 LASI indication\n");
6547
6548 /* Restore normal power mode*/
6549 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006550 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006551 /* HW reset */
6552 bnx2x_ext_phy_hw_reset(bp, params->port);
6553 bnx2x_wait_reset_complete(bp, phy);
6554
6555 bnx2x_cl45_write(bp, phy,
6556 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x1);
6557 DP(NETIF_MSG_LINK, "Setting the SFX7101 LED to blink on traffic\n");
6558 bnx2x_cl45_write(bp, phy,
6559 MDIO_PMA_DEVAD, MDIO_PMA_REG_7107_LED_CNTL, (1<<3));
6560
6561 bnx2x_ext_phy_set_pause(params, phy, vars);
6562 /* Restart autoneg */
6563 bnx2x_cl45_read(bp, phy,
6564 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, &val);
6565 val |= 0x200;
6566 bnx2x_cl45_write(bp, phy,
6567 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, val);
6568
6569 /* Save spirom version */
6570 bnx2x_cl45_read(bp, phy,
6571 MDIO_PMA_DEVAD, MDIO_PMA_REG_7101_VER1, &fw_ver1);
6572
6573 bnx2x_cl45_read(bp, phy,
6574 MDIO_PMA_DEVAD, MDIO_PMA_REG_7101_VER2, &fw_ver2);
6575 bnx2x_save_spirom_version(bp, params->port,
6576 (u32)(fw_ver1<<16 | fw_ver2), phy->ver_addr);
6577 return 0;
6578}
6579
6580static u8 bnx2x_7101_read_status(struct bnx2x_phy *phy,
6581 struct link_params *params,
6582 struct link_vars *vars)
6583{
6584 struct bnx2x *bp = params->bp;
6585 u8 link_up;
6586 u16 val1, val2;
6587 bnx2x_cl45_read(bp, phy,
6588 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val2);
6589 bnx2x_cl45_read(bp, phy,
6590 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
6591 DP(NETIF_MSG_LINK, "10G-base-T LASI status 0x%x->0x%x\n",
6592 val2, val1);
6593 bnx2x_cl45_read(bp, phy,
6594 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
6595 bnx2x_cl45_read(bp, phy,
6596 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
6597 DP(NETIF_MSG_LINK, "10G-base-T PMA status 0x%x->0x%x\n",
6598 val2, val1);
6599 link_up = ((val1 & 4) == 4);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006600 /* if link is up print the AN outcome of the SFX7101 PHY */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006601 if (link_up) {
6602 bnx2x_cl45_read(bp, phy,
6603 MDIO_AN_DEVAD, MDIO_AN_REG_MASTER_STATUS,
6604 &val2);
6605 vars->line_speed = SPEED_10000;
Yaniv Rosner791f18c2011-01-18 04:33:42 +00006606 vars->duplex = DUPLEX_FULL;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006607 DP(NETIF_MSG_LINK, "SFX7101 AN status 0x%x->Master=%x\n",
6608 val2, (val2 & (1<<14)));
6609 bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
6610 bnx2x_ext_phy_resolve_fc(phy, params, vars);
6611 }
6612 return link_up;
6613}
6614
6615
6616static u8 bnx2x_7101_format_ver(u32 spirom_ver, u8 *str, u16 *len)
6617{
6618 if (*len < 5)
6619 return -EINVAL;
6620 str[0] = (spirom_ver & 0xFF);
6621 str[1] = (spirom_ver & 0xFF00) >> 8;
6622 str[2] = (spirom_ver & 0xFF0000) >> 16;
6623 str[3] = (spirom_ver & 0xFF000000) >> 24;
6624 str[4] = '\0';
6625 *len -= 5;
6626 return 0;
6627}
6628
6629void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, struct bnx2x_phy *phy)
6630{
6631 u16 val, cnt;
6632
6633 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006634 MDIO_PMA_DEVAD,
6635 MDIO_PMA_REG_7101_RESET, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006636
6637 for (cnt = 0; cnt < 10; cnt++) {
6638 msleep(50);
6639 /* Writes a self-clearing reset */
6640 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006641 MDIO_PMA_DEVAD,
6642 MDIO_PMA_REG_7101_RESET,
6643 (val | (1<<15)));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006644 /* Wait for clear */
6645 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006646 MDIO_PMA_DEVAD,
6647 MDIO_PMA_REG_7101_RESET, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006648
6649 if ((val & (1<<15)) == 0)
6650 break;
6651 }
6652}
6653
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006654static void bnx2x_7101_hw_reset(struct bnx2x_phy *phy,
6655 struct link_params *params) {
6656 /* Low power mode is controlled by GPIO 2 */
6657 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006658 MISC_REGISTERS_GPIO_OUTPUT_LOW, params->port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006659 /* The PHY reset is controlled by GPIO 1 */
6660 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006661 MISC_REGISTERS_GPIO_OUTPUT_LOW, params->port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006662}
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006663
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006664static void bnx2x_7101_set_link_led(struct bnx2x_phy *phy,
6665 struct link_params *params, u8 mode)
6666{
6667 u16 val = 0;
6668 struct bnx2x *bp = params->bp;
6669 switch (mode) {
6670 case LED_MODE_FRONT_PANEL_OFF:
6671 case LED_MODE_OFF:
6672 val = 2;
6673 break;
6674 case LED_MODE_ON:
6675 val = 1;
6676 break;
6677 case LED_MODE_OPER:
6678 val = 0;
6679 break;
6680 }
6681 bnx2x_cl45_write(bp, phy,
6682 MDIO_PMA_DEVAD,
6683 MDIO_PMA_REG_7107_LINK_LED_CNTL,
6684 val);
6685}
6686
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006687/******************************************************************/
6688/* STATIC PHY DECLARATION */
6689/******************************************************************/
6690
6691static struct bnx2x_phy phy_null = {
6692 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN,
6693 .addr = 0,
6694 .flags = FLAGS_INIT_XGXS_FIRST,
6695 .def_md_devad = 0,
6696 .reserved = 0,
6697 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6698 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6699 .mdio_ctrl = 0,
6700 .supported = 0,
6701 .media_type = ETH_PHY_NOT_PRESENT,
6702 .ver_addr = 0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006703 .req_flow_ctrl = 0,
6704 .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)NULL,
6709 .read_status = (read_status_t)NULL,
6710 .link_reset = (link_reset_t)NULL,
6711 .config_loopback = (config_loopback_t)NULL,
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_serdes = {
6719 .type = PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT,
6720 .addr = 0xff,
6721 .flags = 0,
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_10baseT_Half |
6728 SUPPORTED_10baseT_Full |
6729 SUPPORTED_100baseT_Half |
6730 SUPPORTED_100baseT_Full |
6731 SUPPORTED_1000baseT_Full |
6732 SUPPORTED_2500baseX_Full |
6733 SUPPORTED_TP |
6734 SUPPORTED_Autoneg |
6735 SUPPORTED_Pause |
6736 SUPPORTED_Asym_Pause),
6737 .media_type = ETH_PHY_UNSPECIFIED,
6738 .ver_addr = 0,
6739 .req_flow_ctrl = 0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006740 .req_line_speed = 0,
6741 .speed_cap_mask = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006742 .req_duplex = 0,
6743 .rsrv = 0,
6744 .config_init = (config_init_t)bnx2x_init_serdes,
6745 .read_status = (read_status_t)bnx2x_link_settings_status,
6746 .link_reset = (link_reset_t)bnx2x_int_link_reset,
6747 .config_loopback = (config_loopback_t)NULL,
6748 .format_fw_ver = (format_fw_ver_t)NULL,
6749 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006750 .set_link_led = (set_link_led_t)NULL,
6751 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006752};
6753
6754static struct bnx2x_phy phy_xgxs = {
6755 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT,
6756 .addr = 0xff,
6757 .flags = 0,
6758 .def_md_devad = 0,
6759 .reserved = 0,
6760 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6761 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6762 .mdio_ctrl = 0,
6763 .supported = (SUPPORTED_10baseT_Half |
6764 SUPPORTED_10baseT_Full |
6765 SUPPORTED_100baseT_Half |
6766 SUPPORTED_100baseT_Full |
6767 SUPPORTED_1000baseT_Full |
6768 SUPPORTED_2500baseX_Full |
6769 SUPPORTED_10000baseT_Full |
6770 SUPPORTED_FIBRE |
6771 SUPPORTED_Autoneg |
6772 SUPPORTED_Pause |
6773 SUPPORTED_Asym_Pause),
6774 .media_type = ETH_PHY_UNSPECIFIED,
6775 .ver_addr = 0,
6776 .req_flow_ctrl = 0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006777 .req_line_speed = 0,
6778 .speed_cap_mask = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006779 .req_duplex = 0,
6780 .rsrv = 0,
6781 .config_init = (config_init_t)bnx2x_init_xgxs,
6782 .read_status = (read_status_t)bnx2x_link_settings_status,
6783 .link_reset = (link_reset_t)bnx2x_int_link_reset,
6784 .config_loopback = (config_loopback_t)bnx2x_set_xgxs_loopback,
6785 .format_fw_ver = (format_fw_ver_t)NULL,
6786 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006787 .set_link_led = (set_link_led_t)NULL,
6788 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006789};
6790
6791static struct bnx2x_phy phy_7101 = {
6792 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
6793 .addr = 0xff,
6794 .flags = FLAGS_FAN_FAILURE_DET_REQ,
6795 .def_md_devad = 0,
6796 .reserved = 0,
6797 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6798 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6799 .mdio_ctrl = 0,
6800 .supported = (SUPPORTED_10000baseT_Full |
6801 SUPPORTED_TP |
6802 SUPPORTED_Autoneg |
6803 SUPPORTED_Pause |
6804 SUPPORTED_Asym_Pause),
6805 .media_type = ETH_PHY_BASE_T,
6806 .ver_addr = 0,
6807 .req_flow_ctrl = 0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006808 .req_line_speed = 0,
6809 .speed_cap_mask = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006810 .req_duplex = 0,
6811 .rsrv = 0,
6812 .config_init = (config_init_t)bnx2x_7101_config_init,
6813 .read_status = (read_status_t)bnx2x_7101_read_status,
6814 .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
6815 .config_loopback = (config_loopback_t)bnx2x_7101_config_loopback,
6816 .format_fw_ver = (format_fw_ver_t)bnx2x_7101_format_ver,
6817 .hw_reset = (hw_reset_t)bnx2x_7101_hw_reset,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006818 .set_link_led = (set_link_led_t)bnx2x_7101_set_link_led,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006819 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006820};
6821static struct bnx2x_phy phy_8073 = {
6822 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
6823 .addr = 0xff,
6824 .flags = FLAGS_HW_LOCK_REQUIRED,
6825 .def_md_devad = 0,
6826 .reserved = 0,
6827 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6828 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6829 .mdio_ctrl = 0,
6830 .supported = (SUPPORTED_10000baseT_Full |
6831 SUPPORTED_2500baseX_Full |
6832 SUPPORTED_1000baseT_Full |
6833 SUPPORTED_FIBRE |
6834 SUPPORTED_Autoneg |
6835 SUPPORTED_Pause |
6836 SUPPORTED_Asym_Pause),
6837 .media_type = ETH_PHY_UNSPECIFIED,
6838 .ver_addr = 0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006839 .req_flow_ctrl = 0,
6840 .req_line_speed = 0,
6841 .speed_cap_mask = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006842 .req_duplex = 0,
6843 .rsrv = 0,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00006844 .config_init = (config_init_t)bnx2x_8073_config_init,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006845 .read_status = (read_status_t)bnx2x_8073_read_status,
6846 .link_reset = (link_reset_t)bnx2x_8073_link_reset,
6847 .config_loopback = (config_loopback_t)NULL,
6848 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
6849 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006850 .set_link_led = (set_link_led_t)NULL,
6851 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006852};
6853static struct bnx2x_phy phy_8705 = {
6854 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705,
6855 .addr = 0xff,
6856 .flags = FLAGS_INIT_XGXS_FIRST,
6857 .def_md_devad = 0,
6858 .reserved = 0,
6859 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6860 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6861 .mdio_ctrl = 0,
6862 .supported = (SUPPORTED_10000baseT_Full |
6863 SUPPORTED_FIBRE |
6864 SUPPORTED_Pause |
6865 SUPPORTED_Asym_Pause),
6866 .media_type = ETH_PHY_XFP_FIBER,
6867 .ver_addr = 0,
6868 .req_flow_ctrl = 0,
6869 .req_line_speed = 0,
6870 .speed_cap_mask = 0,
6871 .req_duplex = 0,
6872 .rsrv = 0,
6873 .config_init = (config_init_t)bnx2x_8705_config_init,
6874 .read_status = (read_status_t)bnx2x_8705_read_status,
6875 .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
6876 .config_loopback = (config_loopback_t)NULL,
6877 .format_fw_ver = (format_fw_ver_t)bnx2x_null_format_ver,
6878 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006879 .set_link_led = (set_link_led_t)NULL,
6880 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006881};
6882static struct bnx2x_phy phy_8706 = {
6883 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706,
6884 .addr = 0xff,
6885 .flags = FLAGS_INIT_XGXS_FIRST,
6886 .def_md_devad = 0,
6887 .reserved = 0,
6888 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6889 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6890 .mdio_ctrl = 0,
6891 .supported = (SUPPORTED_10000baseT_Full |
6892 SUPPORTED_1000baseT_Full |
6893 SUPPORTED_FIBRE |
6894 SUPPORTED_Pause |
6895 SUPPORTED_Asym_Pause),
6896 .media_type = ETH_PHY_SFP_FIBER,
6897 .ver_addr = 0,
6898 .req_flow_ctrl = 0,
6899 .req_line_speed = 0,
6900 .speed_cap_mask = 0,
6901 .req_duplex = 0,
6902 .rsrv = 0,
6903 .config_init = (config_init_t)bnx2x_8706_config_init,
6904 .read_status = (read_status_t)bnx2x_8706_read_status,
6905 .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
6906 .config_loopback = (config_loopback_t)NULL,
6907 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
6908 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006909 .set_link_led = (set_link_led_t)NULL,
6910 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006911};
6912
6913static struct bnx2x_phy phy_8726 = {
6914 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
6915 .addr = 0xff,
6916 .flags = (FLAGS_HW_LOCK_REQUIRED |
6917 FLAGS_INIT_XGXS_FIRST),
6918 .def_md_devad = 0,
6919 .reserved = 0,
6920 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6921 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6922 .mdio_ctrl = 0,
6923 .supported = (SUPPORTED_10000baseT_Full |
6924 SUPPORTED_1000baseT_Full |
6925 SUPPORTED_Autoneg |
6926 SUPPORTED_FIBRE |
6927 SUPPORTED_Pause |
6928 SUPPORTED_Asym_Pause),
6929 .media_type = ETH_PHY_SFP_FIBER,
6930 .ver_addr = 0,
6931 .req_flow_ctrl = 0,
6932 .req_line_speed = 0,
6933 .speed_cap_mask = 0,
6934 .req_duplex = 0,
6935 .rsrv = 0,
6936 .config_init = (config_init_t)bnx2x_8726_config_init,
6937 .read_status = (read_status_t)bnx2x_8726_read_status,
6938 .link_reset = (link_reset_t)bnx2x_8726_link_reset,
6939 .config_loopback = (config_loopback_t)bnx2x_8726_config_loopback,
6940 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
6941 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006942 .set_link_led = (set_link_led_t)NULL,
6943 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006944};
6945
6946static struct bnx2x_phy phy_8727 = {
6947 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
6948 .addr = 0xff,
6949 .flags = FLAGS_FAN_FAILURE_DET_REQ,
6950 .def_md_devad = 0,
6951 .reserved = 0,
6952 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6953 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6954 .mdio_ctrl = 0,
6955 .supported = (SUPPORTED_10000baseT_Full |
6956 SUPPORTED_1000baseT_Full |
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006957 SUPPORTED_FIBRE |
6958 SUPPORTED_Pause |
6959 SUPPORTED_Asym_Pause),
6960 .media_type = ETH_PHY_SFP_FIBER,
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_8727_config_init,
6968 .read_status = (read_status_t)bnx2x_8727_read_status,
6969 .link_reset = (link_reset_t)bnx2x_8727_link_reset,
6970 .config_loopback = (config_loopback_t)NULL,
6971 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
6972 .hw_reset = (hw_reset_t)bnx2x_8727_hw_reset,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006973 .set_link_led = (set_link_led_t)bnx2x_8727_set_link_led,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006974 .phy_specific_func = (phy_specific_func_t)bnx2x_8727_specific_func
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006975};
6976static struct bnx2x_phy phy_8481 = {
6977 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
6978 .addr = 0xff,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006979 .flags = FLAGS_FAN_FAILURE_DET_REQ |
6980 FLAGS_REARM_LATCH_SIGNAL,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006981 .def_md_devad = 0,
6982 .reserved = 0,
6983 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6984 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6985 .mdio_ctrl = 0,
6986 .supported = (SUPPORTED_10baseT_Half |
6987 SUPPORTED_10baseT_Full |
6988 SUPPORTED_100baseT_Half |
6989 SUPPORTED_100baseT_Full |
6990 SUPPORTED_1000baseT_Full |
6991 SUPPORTED_10000baseT_Full |
6992 SUPPORTED_TP |
6993 SUPPORTED_Autoneg |
6994 SUPPORTED_Pause |
6995 SUPPORTED_Asym_Pause),
6996 .media_type = ETH_PHY_BASE_T,
6997 .ver_addr = 0,
6998 .req_flow_ctrl = 0,
6999 .req_line_speed = 0,
7000 .speed_cap_mask = 0,
7001 .req_duplex = 0,
7002 .rsrv = 0,
7003 .config_init = (config_init_t)bnx2x_8481_config_init,
7004 .read_status = (read_status_t)bnx2x_848xx_read_status,
7005 .link_reset = (link_reset_t)bnx2x_8481_link_reset,
7006 .config_loopback = (config_loopback_t)NULL,
7007 .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver,
7008 .hw_reset = (hw_reset_t)bnx2x_8481_hw_reset,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00007009 .set_link_led = (set_link_led_t)bnx2x_848xx_set_link_led,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007010 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007011};
7012
7013static struct bnx2x_phy phy_84823 = {
7014 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823,
7015 .addr = 0xff,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007016 .flags = FLAGS_FAN_FAILURE_DET_REQ |
7017 FLAGS_REARM_LATCH_SIGNAL,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007018 .def_md_devad = 0,
7019 .reserved = 0,
7020 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7021 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7022 .mdio_ctrl = 0,
7023 .supported = (SUPPORTED_10baseT_Half |
7024 SUPPORTED_10baseT_Full |
7025 SUPPORTED_100baseT_Half |
7026 SUPPORTED_100baseT_Full |
7027 SUPPORTED_1000baseT_Full |
7028 SUPPORTED_10000baseT_Full |
7029 SUPPORTED_TP |
7030 SUPPORTED_Autoneg |
7031 SUPPORTED_Pause |
7032 SUPPORTED_Asym_Pause),
7033 .media_type = ETH_PHY_BASE_T,
7034 .ver_addr = 0,
7035 .req_flow_ctrl = 0,
7036 .req_line_speed = 0,
7037 .speed_cap_mask = 0,
7038 .req_duplex = 0,
7039 .rsrv = 0,
7040 .config_init = (config_init_t)bnx2x_848x3_config_init,
7041 .read_status = (read_status_t)bnx2x_848xx_read_status,
7042 .link_reset = (link_reset_t)bnx2x_848x3_link_reset,
7043 .config_loopback = (config_loopback_t)NULL,
7044 .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver,
7045 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00007046 .set_link_led = (set_link_led_t)bnx2x_848xx_set_link_led,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007047 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007048};
7049
7050/*****************************************************************/
7051/* */
7052/* Populate the phy according. Main function: bnx2x_populate_phy */
7053/* */
7054/*****************************************************************/
7055
7056static void bnx2x_populate_preemphasis(struct bnx2x *bp, u32 shmem_base,
7057 struct bnx2x_phy *phy, u8 port,
7058 u8 phy_index)
7059{
7060 /* Get the 4 lanes xgxs config rx and tx */
7061 u32 rx = 0, tx = 0, i;
7062 for (i = 0; i < 2; i++) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007063 /*
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007064 * INT_PHY and EXT_PHY1 share the same value location in the
7065 * shmem. When num_phys is greater than 1, than this value
7066 * applies only to EXT_PHY1
7067 */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007068 if (phy_index == INT_PHY || phy_index == EXT_PHY1) {
7069 rx = REG_RD(bp, shmem_base +
7070 offsetof(struct shmem_region,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007071 dev_info.port_hw_config[port].xgxs_config_rx[i<<1]));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007072
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007073 tx = REG_RD(bp, shmem_base +
7074 offsetof(struct shmem_region,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007075 dev_info.port_hw_config[port].xgxs_config_tx[i<<1]));
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007076 } else {
7077 rx = REG_RD(bp, shmem_base +
7078 offsetof(struct shmem_region,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007079 dev_info.port_hw_config[port].xgxs_config2_rx[i<<1]));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007080
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007081 tx = REG_RD(bp, shmem_base +
7082 offsetof(struct shmem_region,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007083 dev_info.port_hw_config[port].xgxs_config2_rx[i<<1]));
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007084 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007085
7086 phy->rx_preemphasis[i << 1] = ((rx>>16) & 0xffff);
7087 phy->rx_preemphasis[(i << 1) + 1] = (rx & 0xffff);
7088
7089 phy->tx_preemphasis[i << 1] = ((tx>>16) & 0xffff);
7090 phy->tx_preemphasis[(i << 1) + 1] = (tx & 0xffff);
7091 }
7092}
7093
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007094static u32 bnx2x_get_ext_phy_config(struct bnx2x *bp, u32 shmem_base,
7095 u8 phy_index, u8 port)
7096{
7097 u32 ext_phy_config = 0;
7098 switch (phy_index) {
7099 case EXT_PHY1:
7100 ext_phy_config = REG_RD(bp, shmem_base +
7101 offsetof(struct shmem_region,
7102 dev_info.port_hw_config[port].external_phy_config));
7103 break;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007104 case EXT_PHY2:
7105 ext_phy_config = REG_RD(bp, shmem_base +
7106 offsetof(struct shmem_region,
7107 dev_info.port_hw_config[port].external_phy_config2));
7108 break;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007109 default:
7110 DP(NETIF_MSG_LINK, "Invalid phy_index %d\n", phy_index);
7111 return -EINVAL;
7112 }
7113
7114 return ext_phy_config;
7115}
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007116static u8 bnx2x_populate_int_phy(struct bnx2x *bp, u32 shmem_base, u8 port,
7117 struct bnx2x_phy *phy)
7118{
7119 u32 phy_addr;
7120 u32 chip_id;
7121 u32 switch_cfg = (REG_RD(bp, shmem_base +
7122 offsetof(struct shmem_region,
7123 dev_info.port_feature_config[port].link_config)) &
7124 PORT_FEATURE_CONNECTED_SWITCH_MASK);
7125 chip_id = REG_RD(bp, MISC_REG_CHIP_NUM) << 16;
7126 switch (switch_cfg) {
7127 case SWITCH_CFG_1G:
7128 phy_addr = REG_RD(bp,
7129 NIG_REG_SERDES0_CTRL_PHY_ADDR +
7130 port * 0x10);
7131 *phy = phy_serdes;
7132 break;
7133 case SWITCH_CFG_10G:
7134 phy_addr = REG_RD(bp,
7135 NIG_REG_XGXS0_CTRL_PHY_ADDR +
7136 port * 0x18);
7137 *phy = phy_xgxs;
7138 break;
7139 default:
7140 DP(NETIF_MSG_LINK, "Invalid switch_cfg\n");
7141 return -EINVAL;
7142 }
7143 phy->addr = (u8)phy_addr;
7144 phy->mdio_ctrl = bnx2x_get_emac_base(bp,
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007145 SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007146 port);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007147 if (CHIP_IS_E2(bp))
7148 phy->def_md_devad = E2_DEFAULT_PHY_DEV_ADDR;
7149 else
7150 phy->def_md_devad = DEFAULT_PHY_DEV_ADDR;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007151
7152 DP(NETIF_MSG_LINK, "Internal phy port=%d, addr=0x%x, mdio_ctl=0x%x\n",
7153 port, phy->addr, phy->mdio_ctrl);
7154
7155 bnx2x_populate_preemphasis(bp, shmem_base, phy, port, INT_PHY);
7156 return 0;
7157}
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007158
7159static u8 bnx2x_populate_ext_phy(struct bnx2x *bp,
7160 u8 phy_index,
7161 u32 shmem_base,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007162 u32 shmem2_base,
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007163 u8 port,
7164 struct bnx2x_phy *phy)
7165{
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007166 u32 ext_phy_config, phy_type, config2;
7167 u32 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007168 ext_phy_config = bnx2x_get_ext_phy_config(bp, shmem_base,
7169 phy_index, port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007170 phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
7171 /* Select the phy type */
7172 switch (phy_type) {
7173 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007174 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_SWAPPED;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007175 *phy = phy_8073;
7176 break;
7177 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
7178 *phy = phy_8705;
7179 break;
7180 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
7181 *phy = phy_8706;
7182 break;
7183 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007184 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007185 *phy = phy_8726;
7186 break;
7187 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
7188 /* BCM8727_NOC => BCM8727 no over current */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007189 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007190 *phy = phy_8727;
7191 phy->flags |= FLAGS_NOC;
7192 break;
7193 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007194 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007195 *phy = phy_8727;
7196 break;
7197 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
7198 *phy = phy_8481;
7199 break;
7200 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
7201 *phy = phy_84823;
7202 break;
7203 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
7204 *phy = phy_7101;
7205 break;
7206 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
7207 *phy = phy_null;
7208 return -EINVAL;
7209 default:
7210 *phy = phy_null;
7211 return 0;
7212 }
7213
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007214 phy->addr = XGXS_EXT_PHY_ADDR(ext_phy_config);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007215 bnx2x_populate_preemphasis(bp, shmem_base, phy, port, phy_index);
Yaniv Rosner62b29a52010-09-07 11:40:58 +00007216
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007217 /*
7218 * The shmem address of the phy version is located on different
7219 * structures. In case this structure is too old, do not set
7220 * the address
7221 */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007222 config2 = REG_RD(bp, shmem_base + offsetof(struct shmem_region,
7223 dev_info.shared_hw_config.config2));
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007224 if (phy_index == EXT_PHY1) {
7225 phy->ver_addr = shmem_base + offsetof(struct shmem_region,
7226 port_mb[port].ext_phy_fw_version);
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007227
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007228 /* Check specific mdc mdio settings */
7229 if (config2 & SHARED_HW_CFG_MDC_MDIO_ACCESS1_MASK)
7230 mdc_mdio_access = config2 &
7231 SHARED_HW_CFG_MDC_MDIO_ACCESS1_MASK;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007232 } else {
7233 u32 size = REG_RD(bp, shmem2_base);
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007234
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007235 if (size >
7236 offsetof(struct shmem2_region, ext_phy_fw_version2)) {
7237 phy->ver_addr = shmem2_base +
7238 offsetof(struct shmem2_region,
7239 ext_phy_fw_version2[port]);
7240 }
7241 /* Check specific mdc mdio settings */
7242 if (config2 & SHARED_HW_CFG_MDC_MDIO_ACCESS2_MASK)
7243 mdc_mdio_access = (config2 &
7244 SHARED_HW_CFG_MDC_MDIO_ACCESS2_MASK) >>
7245 (SHARED_HW_CFG_MDC_MDIO_ACCESS2_SHIFT -
7246 SHARED_HW_CFG_MDC_MDIO_ACCESS1_SHIFT);
7247 }
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007248 phy->mdio_ctrl = bnx2x_get_emac_base(bp, mdc_mdio_access, port);
7249
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007250 /*
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007251 * In case mdc/mdio_access of the external phy is different than the
7252 * mdc/mdio access of the XGXS, a HW lock must be taken in each access
7253 * to prevent one port interfere with another port's CL45 operations.
7254 */
7255 if (mdc_mdio_access != SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH)
7256 phy->flags |= FLAGS_HW_LOCK_REQUIRED;
7257 DP(NETIF_MSG_LINK, "phy_type 0x%x port %d found in index %d\n",
7258 phy_type, port, phy_index);
7259 DP(NETIF_MSG_LINK, " addr=0x%x, mdio_ctl=0x%x\n",
7260 phy->addr, phy->mdio_ctrl);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007261 return 0;
7262}
7263
7264static u8 bnx2x_populate_phy(struct bnx2x *bp, u8 phy_index, u32 shmem_base,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007265 u32 shmem2_base, u8 port, struct bnx2x_phy *phy)
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007266{
7267 u8 status = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007268 phy->type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN;
7269 if (phy_index == INT_PHY)
7270 return bnx2x_populate_int_phy(bp, shmem_base, port, phy);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007271 status = bnx2x_populate_ext_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007272 port, phy);
7273 return status;
7274}
7275
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007276static void bnx2x_phy_def_cfg(struct link_params *params,
7277 struct bnx2x_phy *phy,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007278 u8 phy_index)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007279{
7280 struct bnx2x *bp = params->bp;
7281 u32 link_config;
7282 /* Populate the default phy configuration for MF mode */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007283 if (phy_index == EXT_PHY2) {
7284 link_config = REG_RD(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007285 offsetof(struct shmem_region, dev_info.
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007286 port_feature_config[params->port].link_config2));
7287 phy->speed_cap_mask = REG_RD(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007288 offsetof(struct shmem_region,
7289 dev_info.
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007290 port_hw_config[params->port].speed_capability_mask2));
7291 } else {
7292 link_config = REG_RD(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007293 offsetof(struct shmem_region, dev_info.
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007294 port_feature_config[params->port].link_config));
7295 phy->speed_cap_mask = REG_RD(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007296 offsetof(struct shmem_region,
7297 dev_info.
7298 port_hw_config[params->port].speed_capability_mask));
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007299 }
7300 DP(NETIF_MSG_LINK, "Default config phy idx %x cfg 0x%x speed_cap_mask"
7301 " 0x%x\n", phy_index, link_config, phy->speed_cap_mask);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007302
7303 phy->req_duplex = DUPLEX_FULL;
7304 switch (link_config & PORT_FEATURE_LINK_SPEED_MASK) {
7305 case PORT_FEATURE_LINK_SPEED_10M_HALF:
7306 phy->req_duplex = DUPLEX_HALF;
7307 case PORT_FEATURE_LINK_SPEED_10M_FULL:
7308 phy->req_line_speed = SPEED_10;
7309 break;
7310 case PORT_FEATURE_LINK_SPEED_100M_HALF:
7311 phy->req_duplex = DUPLEX_HALF;
7312 case PORT_FEATURE_LINK_SPEED_100M_FULL:
7313 phy->req_line_speed = SPEED_100;
7314 break;
7315 case PORT_FEATURE_LINK_SPEED_1G:
7316 phy->req_line_speed = SPEED_1000;
7317 break;
7318 case PORT_FEATURE_LINK_SPEED_2_5G:
7319 phy->req_line_speed = SPEED_2500;
7320 break;
7321 case PORT_FEATURE_LINK_SPEED_10G_CX4:
7322 phy->req_line_speed = SPEED_10000;
7323 break;
7324 default:
7325 phy->req_line_speed = SPEED_AUTO_NEG;
7326 break;
7327 }
7328
7329 switch (link_config & PORT_FEATURE_FLOW_CONTROL_MASK) {
7330 case PORT_FEATURE_FLOW_CONTROL_AUTO:
7331 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_AUTO;
7332 break;
7333 case PORT_FEATURE_FLOW_CONTROL_TX:
7334 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_TX;
7335 break;
7336 case PORT_FEATURE_FLOW_CONTROL_RX:
7337 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_RX;
7338 break;
7339 case PORT_FEATURE_FLOW_CONTROL_BOTH:
7340 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_BOTH;
7341 break;
7342 default:
7343 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_NONE;
7344 break;
7345 }
7346}
7347
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007348u32 bnx2x_phy_selection(struct link_params *params)
7349{
7350 u32 phy_config_swapped, prio_cfg;
7351 u32 return_cfg = PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT;
7352
7353 phy_config_swapped = params->multi_phy_config &
7354 PORT_HW_CFG_PHY_SWAPPED_ENABLED;
7355
7356 prio_cfg = params->multi_phy_config &
7357 PORT_HW_CFG_PHY_SELECTION_MASK;
7358
7359 if (phy_config_swapped) {
7360 switch (prio_cfg) {
7361 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
7362 return_cfg = PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY;
7363 break;
7364 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
7365 return_cfg = PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY;
7366 break;
7367 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY:
7368 return_cfg = PORT_HW_CFG_PHY_SELECTION_FIRST_PHY;
7369 break;
7370 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY:
7371 return_cfg = PORT_HW_CFG_PHY_SELECTION_SECOND_PHY;
7372 break;
7373 }
7374 } else
7375 return_cfg = prio_cfg;
7376
7377 return return_cfg;
7378}
7379
7380
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007381u8 bnx2x_phy_probe(struct link_params *params)
7382{
7383 u8 phy_index, actual_phy_idx, link_cfg_idx;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007384 u32 phy_config_swapped;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007385 struct bnx2x *bp = params->bp;
7386 struct bnx2x_phy *phy;
7387 params->num_phys = 0;
7388 DP(NETIF_MSG_LINK, "Begin phy probe\n");
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007389 phy_config_swapped = params->multi_phy_config &
7390 PORT_HW_CFG_PHY_SWAPPED_ENABLED;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007391
7392 for (phy_index = INT_PHY; phy_index < MAX_PHYS;
7393 phy_index++) {
7394 link_cfg_idx = LINK_CONFIG_IDX(phy_index);
7395 actual_phy_idx = phy_index;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007396 if (phy_config_swapped) {
7397 if (phy_index == EXT_PHY1)
7398 actual_phy_idx = EXT_PHY2;
7399 else if (phy_index == EXT_PHY2)
7400 actual_phy_idx = EXT_PHY1;
7401 }
7402 DP(NETIF_MSG_LINK, "phy_config_swapped %x, phy_index %x,"
7403 " actual_phy_idx %x\n", phy_config_swapped,
7404 phy_index, actual_phy_idx);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007405 phy = &params->phy[actual_phy_idx];
7406 if (bnx2x_populate_phy(bp, phy_index, params->shmem_base,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007407 params->shmem2_base, params->port,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007408 phy) != 0) {
7409 params->num_phys = 0;
7410 DP(NETIF_MSG_LINK, "phy probe failed in phy index %d\n",
7411 phy_index);
7412 for (phy_index = INT_PHY;
7413 phy_index < MAX_PHYS;
7414 phy_index++)
7415 *phy = phy_null;
7416 return -EINVAL;
7417 }
7418 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)
7419 break;
7420
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007421 bnx2x_phy_def_cfg(params, phy, phy_index);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007422 params->num_phys++;
7423 }
7424
7425 DP(NETIF_MSG_LINK, "End phy probe. #phys found %x\n", params->num_phys);
7426 return 0;
7427}
7428
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007429static void set_phy_vars(struct link_params *params)
7430{
7431 struct bnx2x *bp = params->bp;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007432 u8 actual_phy_idx, phy_index, link_cfg_idx;
7433 u8 phy_config_swapped = params->multi_phy_config &
7434 PORT_HW_CFG_PHY_SWAPPED_ENABLED;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007435 for (phy_index = INT_PHY; phy_index < params->num_phys;
7436 phy_index++) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007437 link_cfg_idx = LINK_CONFIG_IDX(phy_index);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007438 actual_phy_idx = phy_index;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007439 if (phy_config_swapped) {
7440 if (phy_index == EXT_PHY1)
7441 actual_phy_idx = EXT_PHY2;
7442 else if (phy_index == EXT_PHY2)
7443 actual_phy_idx = EXT_PHY1;
7444 }
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007445 params->phy[actual_phy_idx].req_flow_ctrl =
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007446 params->req_flow_ctrl[link_cfg_idx];
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007447
7448 params->phy[actual_phy_idx].req_line_speed =
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007449 params->req_line_speed[link_cfg_idx];
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007450
7451 params->phy[actual_phy_idx].speed_cap_mask =
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007452 params->speed_cap_mask[link_cfg_idx];
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007453
7454 params->phy[actual_phy_idx].req_duplex =
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007455 params->req_duplex[link_cfg_idx];
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007456
7457 DP(NETIF_MSG_LINK, "req_flow_ctrl %x, req_line_speed %x,"
7458 " speed_cap_mask %x\n",
7459 params->phy[actual_phy_idx].req_flow_ctrl,
7460 params->phy[actual_phy_idx].req_line_speed,
7461 params->phy[actual_phy_idx].speed_cap_mask);
7462 }
7463}
7464
7465u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
7466{
7467 struct bnx2x *bp = params->bp;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007468 DP(NETIF_MSG_LINK, "Phy Initialization started\n");
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007469 DP(NETIF_MSG_LINK, "(1) req_speed %d, req_flowctrl %d\n",
7470 params->req_line_speed[0], params->req_flow_ctrl[0]);
7471 DP(NETIF_MSG_LINK, "(2) req_speed %d, req_flowctrl %d\n",
7472 params->req_line_speed[1], params->req_flow_ctrl[1]);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007473 vars->link_status = 0;
7474 vars->phy_link_up = 0;
7475 vars->link_up = 0;
7476 vars->line_speed = 0;
7477 vars->duplex = DUPLEX_FULL;
7478 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
7479 vars->mac_type = MAC_TYPE_NONE;
7480 vars->phy_flags = 0;
7481
7482 /* disable attentions */
7483 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4,
7484 (NIG_MASK_XGXS0_LINK_STATUS |
7485 NIG_MASK_XGXS0_LINK10G |
7486 NIG_MASK_SERDES0_LINK_STATUS |
7487 NIG_MASK_MI_INT));
7488
7489 bnx2x_emac_init(params, vars);
7490
7491 if (params->num_phys == 0) {
7492 DP(NETIF_MSG_LINK, "No phy found for initialization !!\n");
7493 return -EINVAL;
7494 }
7495 set_phy_vars(params);
7496
7497 DP(NETIF_MSG_LINK, "Num of phys on board: %d\n", params->num_phys);
7498 if (CHIP_REV_IS_FPGA(bp)) {
7499
7500 vars->link_up = 1;
7501 vars->line_speed = SPEED_10000;
7502 vars->duplex = DUPLEX_FULL;
7503 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
7504 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
7505 /* enable on E1.5 FPGA */
7506 if (CHIP_IS_E1H(bp)) {
7507 vars->flow_ctrl |=
7508 (BNX2X_FLOW_CTRL_TX |
7509 BNX2X_FLOW_CTRL_RX);
7510 vars->link_status |=
7511 (LINK_STATUS_TX_FLOW_CONTROL_ENABLED |
7512 LINK_STATUS_RX_FLOW_CONTROL_ENABLED);
7513 }
7514
7515 bnx2x_emac_enable(params, vars, 0);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007516 if (!(CHIP_IS_E2(bp)))
7517 bnx2x_pbf_update(params, vars->flow_ctrl,
7518 vars->line_speed);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007519 /* disable drain */
7520 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
7521
7522 /* update shared memory */
7523 bnx2x_update_mng(params, vars->link_status);
7524
7525 return 0;
7526
7527 } else
7528 if (CHIP_REV_IS_EMUL(bp)) {
7529
7530 vars->link_up = 1;
7531 vars->line_speed = SPEED_10000;
7532 vars->duplex = DUPLEX_FULL;
7533 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
7534 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
7535
7536 bnx2x_bmac_enable(params, vars, 0);
7537
7538 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
7539 /* Disable drain */
7540 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
7541 + params->port*4, 0);
7542
7543 /* update shared memory */
7544 bnx2x_update_mng(params, vars->link_status);
7545
7546 return 0;
7547
7548 } else
7549 if (params->loopback_mode == LOOPBACK_BMAC) {
7550
7551 vars->link_up = 1;
7552 vars->line_speed = SPEED_10000;
7553 vars->duplex = DUPLEX_FULL;
7554 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
7555 vars->mac_type = MAC_TYPE_BMAC;
7556
7557 vars->phy_flags = PHY_XGXS_FLAG;
7558
7559 bnx2x_xgxs_deassert(params);
7560
7561 /* set bmac loopback */
7562 bnx2x_bmac_enable(params, vars, 1);
7563
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007564 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007565
7566 } else if (params->loopback_mode == LOOPBACK_EMAC) {
7567
7568 vars->link_up = 1;
7569 vars->line_speed = SPEED_1000;
7570 vars->duplex = DUPLEX_FULL;
7571 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
7572 vars->mac_type = MAC_TYPE_EMAC;
7573
7574 vars->phy_flags = PHY_XGXS_FLAG;
7575
7576 bnx2x_xgxs_deassert(params);
7577 /* set bmac loopback */
7578 bnx2x_emac_enable(params, vars, 1);
7579 bnx2x_emac_program(params, vars);
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007580 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007581
7582 } else if ((params->loopback_mode == LOOPBACK_XGXS) ||
7583 (params->loopback_mode == LOOPBACK_EXT_PHY)) {
7584
7585 vars->link_up = 1;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007586 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007587 vars->duplex = DUPLEX_FULL;
7588 if (params->req_line_speed[0] == SPEED_1000) {
7589 vars->line_speed = SPEED_1000;
7590 vars->mac_type = MAC_TYPE_EMAC;
7591 } else {
7592 vars->line_speed = SPEED_10000;
7593 vars->mac_type = MAC_TYPE_BMAC;
7594 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007595
7596 bnx2x_xgxs_deassert(params);
7597 bnx2x_link_initialize(params, vars);
7598
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007599 if (params->req_line_speed[0] == SPEED_1000) {
7600 bnx2x_emac_program(params, vars);
7601 bnx2x_emac_enable(params, vars, 0);
7602 } else
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007603 bnx2x_bmac_enable(params, vars, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007604 if (params->loopback_mode == LOOPBACK_XGXS) {
7605 /* set 10G XGXS loopback */
7606 params->phy[INT_PHY].config_loopback(
7607 &params->phy[INT_PHY],
7608 params);
7609
7610 } else {
7611 /* set external phy loopback */
7612 u8 phy_index;
7613 for (phy_index = EXT_PHY1;
7614 phy_index < params->num_phys; phy_index++) {
7615 if (params->phy[phy_index].config_loopback)
7616 params->phy[phy_index].config_loopback(
7617 &params->phy[phy_index],
7618 params);
7619 }
7620 }
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007621 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007622
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00007623 bnx2x_set_led(params, vars,
7624 LED_MODE_OPER, vars->line_speed);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007625 } else
7626 /* No loopback */
7627 {
7628 if (params->switch_cfg == SWITCH_CFG_10G)
7629 bnx2x_xgxs_deassert(params);
7630 else
7631 bnx2x_serdes_deassert(bp, params->port);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00007632
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007633 bnx2x_link_initialize(params, vars);
7634 msleep(30);
7635 bnx2x_link_int_enable(params);
7636 }
7637 return 0;
7638}
7639u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007640 u8 reset_ext_phy)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007641{
7642 struct bnx2x *bp = params->bp;
Yaniv Rosnercf1d9722010-11-01 05:32:34 +00007643 u8 phy_index, port = params->port, clear_latch_ind = 0;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007644 DP(NETIF_MSG_LINK, "Resetting the link of port %d\n", port);
7645 /* disable attentions */
7646 vars->link_status = 0;
7647 bnx2x_update_mng(params, vars->link_status);
7648 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007649 (NIG_MASK_XGXS0_LINK_STATUS |
7650 NIG_MASK_XGXS0_LINK10G |
7651 NIG_MASK_SERDES0_LINK_STATUS |
7652 NIG_MASK_MI_INT));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007653
7654 /* activate nig drain */
7655 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
7656
7657 /* disable nig egress interface */
7658 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
7659 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
7660
7661 /* Stop BigMac rx */
7662 bnx2x_bmac_rx_disable(bp, port);
7663
7664 /* disable emac */
7665 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
7666
7667 msleep(10);
7668 /* The PHY reset is controled by GPIO 1
7669 * Hold it as vars low
7670 */
7671 /* clear link led */
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00007672 bnx2x_set_led(params, vars, LED_MODE_OFF, 0);
7673
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007674 if (reset_ext_phy) {
7675 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
7676 phy_index++) {
7677 if (params->phy[phy_index].link_reset)
7678 params->phy[phy_index].link_reset(
7679 &params->phy[phy_index],
7680 params);
Yaniv Rosnercf1d9722010-11-01 05:32:34 +00007681 if (params->phy[phy_index].flags &
7682 FLAGS_REARM_LATCH_SIGNAL)
7683 clear_latch_ind = 1;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007684 }
7685 }
7686
Yaniv Rosnercf1d9722010-11-01 05:32:34 +00007687 if (clear_latch_ind) {
7688 /* Clear latching indication */
7689 bnx2x_rearm_latch_signal(bp, port, 0);
7690 bnx2x_bits_dis(bp, NIG_REG_LATCH_BC_0 + port*4,
7691 1 << NIG_LATCH_BC_ENABLE_MI_INT);
7692 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007693 if (params->phy[INT_PHY].link_reset)
7694 params->phy[INT_PHY].link_reset(
7695 &params->phy[INT_PHY], params);
7696 /* reset BigMac */
7697 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
7698 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
7699
7700 /* disable nig ingress interface */
7701 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0);
7702 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0);
7703 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
7704 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
7705 vars->link_up = 0;
7706 return 0;
7707}
7708
7709/****************************************************************************/
7710/* Common function */
7711/****************************************************************************/
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007712static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp,
7713 u32 shmem_base_path[],
7714 u32 shmem2_base_path[], u8 phy_index,
7715 u32 chip_id)
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007716{
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007717 struct bnx2x_phy phy[PORT_MAX];
7718 struct bnx2x_phy *phy_blk[PORT_MAX];
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007719 u16 val;
Yaniv Rosnerc8e64df2011-01-30 04:15:00 +00007720 s8 port = 0;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007721 s8 port_of_path = 0;
Yaniv Rosnerc8e64df2011-01-30 04:15:00 +00007722 u32 swap_val, swap_override;
7723 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
7724 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
7725 port ^= (swap_val && swap_override);
7726 bnx2x_ext_phy_hw_reset(bp, port);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007727 /* PART1 - Reset both phys */
7728 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007729 u32 shmem_base, shmem2_base;
7730 /* In E2, same phy is using for port0 of the two paths */
7731 if (CHIP_IS_E2(bp)) {
7732 shmem_base = shmem_base_path[port];
7733 shmem2_base = shmem2_base_path[port];
7734 port_of_path = 0;
7735 } else {
7736 shmem_base = shmem_base_path[0];
7737 shmem2_base = shmem2_base_path[0];
7738 port_of_path = port;
7739 }
7740
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007741 /* Extract the ext phy address for the port */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007742 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007743 port_of_path, &phy[port]) !=
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007744 0) {
7745 DP(NETIF_MSG_LINK, "populate_phy failed\n");
7746 return -EINVAL;
7747 }
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007748 /* disable attentions */
Yaniv Rosner6a71bbe2010-11-01 05:32:31 +00007749 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 +
7750 port_of_path*4,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007751 (NIG_MASK_XGXS0_LINK_STATUS |
7752 NIG_MASK_XGXS0_LINK10G |
7753 NIG_MASK_SERDES0_LINK_STATUS |
7754 NIG_MASK_MI_INT));
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007755
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007756 /* Need to take the phy out of low power mode in order
7757 to write to access its registers */
7758 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007759 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
7760 port);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007761
7762 /* Reset the phy */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007763 bnx2x_cl45_write(bp, &phy[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007764 MDIO_PMA_DEVAD,
7765 MDIO_PMA_REG_CTRL,
7766 1<<15);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007767 }
7768
7769 /* Add delay of 150ms after reset */
7770 msleep(150);
7771
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007772 if (phy[PORT_0].addr & 0x1) {
7773 phy_blk[PORT_0] = &(phy[PORT_1]);
7774 phy_blk[PORT_1] = &(phy[PORT_0]);
7775 } else {
7776 phy_blk[PORT_0] = &(phy[PORT_0]);
7777 phy_blk[PORT_1] = &(phy[PORT_1]);
7778 }
7779
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007780 /* PART2 - Download firmware to both phys */
7781 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007782 if (CHIP_IS_E2(bp))
7783 port_of_path = 0;
7784 else
7785 port_of_path = port;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007786
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007787 DP(NETIF_MSG_LINK, "Loading spirom for phy address 0x%x\n",
7788 phy_blk[port]->addr);
Yaniv Rosner5c99274b2011-01-18 04:33:36 +00007789 if (bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port],
7790 port_of_path))
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007791 return -EINVAL;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007792
7793 /* Only set bit 10 = 1 (Tx power down) */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007794 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007795 MDIO_PMA_DEVAD,
7796 MDIO_PMA_REG_TX_POWER_DOWN, &val);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007797
7798 /* Phase1 of TX_POWER_DOWN reset */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007799 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007800 MDIO_PMA_DEVAD,
7801 MDIO_PMA_REG_TX_POWER_DOWN,
7802 (val | 1<<10));
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007803 }
7804
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007805 /*
7806 * Toggle Transmitter: Power down and then up with 600ms delay
7807 * between
7808 */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007809 msleep(600);
7810
7811 /* PART3 - complete TX_POWER_DOWN process, and set GPIO2 back to low */
7812 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Eilon Greensteinf5372252009-02-12 08:38:30 +00007813 /* Phase2 of POWER_DOWN_RESET */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007814 /* Release bit 10 (Release Tx power down) */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007815 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007816 MDIO_PMA_DEVAD,
7817 MDIO_PMA_REG_TX_POWER_DOWN, &val);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007818
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007819 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007820 MDIO_PMA_DEVAD,
7821 MDIO_PMA_REG_TX_POWER_DOWN, (val & (~(1<<10))));
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007822 msleep(15);
7823
7824 /* Read modify write the SPI-ROM version select register */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007825 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007826 MDIO_PMA_DEVAD,
7827 MDIO_PMA_REG_EDC_FFE_MAIN, &val);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007828 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007829 MDIO_PMA_DEVAD,
7830 MDIO_PMA_REG_EDC_FFE_MAIN, (val | (1<<12)));
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007831
7832 /* set GPIO2 back to LOW */
7833 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007834 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007835 }
7836 return 0;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007837}
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007838static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp,
7839 u32 shmem_base_path[],
7840 u32 shmem2_base_path[], u8 phy_index,
7841 u32 chip_id)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007842{
7843 u32 val;
7844 s8 port;
7845 struct bnx2x_phy phy;
7846 /* Use port1 because of the static port-swap */
7847 /* Enable the module detection interrupt */
7848 val = REG_RD(bp, MISC_REG_GPIO_EVENT_EN);
7849 val |= ((1<<MISC_REGISTERS_GPIO_3)|
7850 (1<<(MISC_REGISTERS_GPIO_3 + MISC_REGISTERS_GPIO_PORT_SHIFT)));
7851 REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val);
7852
Yaniv Rosner650154b2010-11-01 05:32:36 +00007853 bnx2x_ext_phy_hw_reset(bp, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007854 msleep(5);
7855 for (port = 0; port < PORT_MAX; port++) {
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007856 u32 shmem_base, shmem2_base;
7857
7858 /* In E2, same phy is using for port0 of the two paths */
7859 if (CHIP_IS_E2(bp)) {
7860 shmem_base = shmem_base_path[port];
7861 shmem2_base = shmem2_base_path[port];
7862 } else {
7863 shmem_base = shmem_base_path[0];
7864 shmem2_base = shmem2_base_path[0];
7865 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007866 /* Extract the ext phy address for the port */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007867 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007868 port, &phy) !=
7869 0) {
7870 DP(NETIF_MSG_LINK, "populate phy failed\n");
7871 return -EINVAL;
7872 }
7873
7874 /* Reset phy*/
7875 bnx2x_cl45_write(bp, &phy,
7876 MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, 0x0001);
7877
7878
7879 /* Set fault module detected LED on */
7880 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007881 MISC_REGISTERS_GPIO_HIGH,
7882 port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007883 }
7884
7885 return 0;
7886}
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007887static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp,
7888 u32 shmem_base_path[],
7889 u32 shmem2_base_path[], u8 phy_index,
7890 u32 chip_id)
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007891{
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007892 s8 port;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007893 u32 swap_val, swap_override;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007894 struct bnx2x_phy phy[PORT_MAX];
7895 struct bnx2x_phy *phy_blk[PORT_MAX];
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007896 s8 port_of_path;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007897 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
7898 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007899
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007900 port = 1;
7901
7902 bnx2x_ext_phy_hw_reset(bp, port ^ (swap_val && swap_override));
7903
7904 /* Calculate the port based on port swap */
7905 port ^= (swap_val && swap_override);
7906
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007907 msleep(5);
7908
7909 /* PART1 - Reset both phys */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007910 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007911 u32 shmem_base, shmem2_base;
7912
7913 /* In E2, same phy is using for port0 of the two paths */
7914 if (CHIP_IS_E2(bp)) {
7915 shmem_base = shmem_base_path[port];
7916 shmem2_base = shmem2_base_path[port];
7917 port_of_path = 0;
7918 } else {
7919 shmem_base = shmem_base_path[0];
7920 shmem2_base = shmem2_base_path[0];
7921 port_of_path = port;
7922 }
7923
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007924 /* Extract the ext phy address for the port */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007925 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007926 port_of_path, &phy[port]) !=
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007927 0) {
7928 DP(NETIF_MSG_LINK, "populate phy failed\n");
7929 return -EINVAL;
7930 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007931 /* disable attentions */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007932 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 +
7933 port_of_path*4,
7934 (NIG_MASK_XGXS0_LINK_STATUS |
7935 NIG_MASK_XGXS0_LINK10G |
7936 NIG_MASK_SERDES0_LINK_STATUS |
7937 NIG_MASK_MI_INT));
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007938
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007939
7940 /* Reset the phy */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007941 bnx2x_cl45_write(bp, &phy[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007942 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007943 }
7944
7945 /* Add delay of 150ms after reset */
7946 msleep(150);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007947 if (phy[PORT_0].addr & 0x1) {
7948 phy_blk[PORT_0] = &(phy[PORT_1]);
7949 phy_blk[PORT_1] = &(phy[PORT_0]);
7950 } else {
7951 phy_blk[PORT_0] = &(phy[PORT_0]);
7952 phy_blk[PORT_1] = &(phy[PORT_1]);
7953 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007954 /* PART2 - Download firmware to both phys */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007955 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007956 if (CHIP_IS_E2(bp))
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007957 port_of_path = 0;
7958 else
7959 port_of_path = port;
7960 DP(NETIF_MSG_LINK, "Loading spirom for phy address 0x%x\n",
7961 phy_blk[port]->addr);
Yaniv Rosner5c99274b2011-01-18 04:33:36 +00007962 if (bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port],
7963 port_of_path))
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007964 return -EINVAL;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007965
Yaniv Rosner5c99274b2011-01-18 04:33:36 +00007966 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007967 return 0;
7968}
7969
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007970static u8 bnx2x_ext_phy_common_init(struct bnx2x *bp, u32 shmem_base_path[],
7971 u32 shmem2_base_path[], u8 phy_index,
7972 u32 ext_phy_type, u32 chip_id)
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007973{
7974 u8 rc = 0;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007975
7976 switch (ext_phy_type) {
7977 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007978 rc = bnx2x_8073_common_init_phy(bp, shmem_base_path,
7979 shmem2_base_path,
7980 phy_index, chip_id);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007981 break;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007982
7983 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
7984 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007985 rc = bnx2x_8727_common_init_phy(bp, shmem_base_path,
7986 shmem2_base_path,
7987 phy_index, chip_id);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007988 break;
7989
Eilon Greenstein589abe32009-02-12 08:36:55 +00007990 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007991 /*
7992 * GPIO1 affects both ports, so there's need to pull
7993 * it for single port alone
7994 */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007995 rc = bnx2x_8726_common_init_phy(bp, shmem_base_path,
7996 shmem2_base_path,
7997 phy_index, chip_id);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007998 break;
7999 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
8000 rc = -EINVAL;
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02008001 break;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008002 default:
8003 DP(NETIF_MSG_LINK,
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008004 "ext_phy 0x%x common init not required\n",
8005 ext_phy_type);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008006 break;
8007 }
8008
8009 return rc;
8010}
8011
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00008012u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base_path[],
8013 u32 shmem2_base_path[], u32 chip_id)
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008014{
8015 u8 rc = 0;
Yaniv Rosnerb21a3422011-01-18 04:33:24 +00008016 u32 phy_ver;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008017 u8 phy_index;
8018 u32 ext_phy_type, ext_phy_config;
8019 DP(NETIF_MSG_LINK, "Begin common phy init\n");
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00008020
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008021 if (CHIP_REV_IS_EMUL(bp))
8022 return 0;
8023
Yaniv Rosnerb21a3422011-01-18 04:33:24 +00008024 /* Check if common init was already done */
8025 phy_ver = REG_RD(bp, shmem_base_path[0] +
8026 offsetof(struct shmem_region,
8027 port_mb[PORT_0].ext_phy_fw_version));
8028 if (phy_ver) {
8029 DP(NETIF_MSG_LINK, "Not doing common init; phy ver is 0x%x\n",
8030 phy_ver);
8031 return 0;
8032 }
8033
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008034 /* Read the ext_phy_type for arbitrary port(0) */
8035 for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
8036 phy_index++) {
8037 ext_phy_config = bnx2x_get_ext_phy_config(bp,
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00008038 shmem_base_path[0],
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008039 phy_index, 0);
8040 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00008041 rc |= bnx2x_ext_phy_common_init(bp, shmem_base_path,
8042 shmem2_base_path,
8043 phy_index, ext_phy_type,
8044 chip_id);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008045 }
8046 return rc;
8047}
8048
8049u8 bnx2x_hw_lock_required(struct bnx2x *bp, u32 shmem_base, u32 shmem2_base)
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00008050{
8051 u8 phy_index;
8052 struct bnx2x_phy phy;
8053 for (phy_index = INT_PHY; phy_index < MAX_PHYS;
8054 phy_index++) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008055 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00008056 0, &phy) != 0) {
8057 DP(NETIF_MSG_LINK, "populate phy failed\n");
8058 return 0;
8059 }
8060
8061 if (phy.flags & FLAGS_HW_LOCK_REQUIRED)
8062 return 1;
8063 }
8064 return 0;
8065}
8066
8067u8 bnx2x_fan_failure_det_req(struct bnx2x *bp,
8068 u32 shmem_base,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008069 u32 shmem2_base,
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00008070 u8 port)
8071{
8072 u8 phy_index, fan_failure_det_req = 0;
8073 struct bnx2x_phy phy;
8074 for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
8075 phy_index++) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008076 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00008077 port, &phy)
8078 != 0) {
8079 DP(NETIF_MSG_LINK, "populate phy failed\n");
8080 return 0;
8081 }
8082 fan_failure_det_req |= (phy.flags &
8083 FLAGS_FAN_FAILURE_DET_REQ);
8084 }
8085 return fan_failure_det_req;
8086}
8087
8088void bnx2x_hw_reset_phy(struct link_params *params)
8089{
8090 u8 phy_index;
8091 for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
8092 phy_index++) {
8093 if (params->phy[phy_index].hw_reset) {
8094 params->phy[phy_index].hw_reset(
8095 &params->phy[phy_index],
8096 params);
8097 params->phy[phy_index] = phy_null;
8098 }
8099 }
8100}