blob: 15b5bc17433194e102b5bfeda80c0e1a497239c4 [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
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700186static u32 bnx2x_bits_en(struct bnx2x *bp, u32 reg, u32 bits)
187{
188 u32 val = REG_RD(bp, reg);
189
190 val |= bits;
191 REG_WR(bp, reg, val);
192 return val;
193}
194
195static u32 bnx2x_bits_dis(struct bnx2x *bp, u32 reg, u32 bits)
196{
197 u32 val = REG_RD(bp, reg);
198
199 val &= ~bits;
200 REG_WR(bp, reg, val);
201 return val;
202}
203
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000204/******************************************************************/
205/* ETS section */
206/******************************************************************/
207void bnx2x_ets_disabled(struct link_params *params)
208{
209 /* ETS disabled configuration*/
210 struct bnx2x *bp = params->bp;
211
212 DP(NETIF_MSG_LINK, "ETS disabled configuration\n");
213
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000214 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000215 * mapping between entry priority to client number (0,1,2 -debug and
216 * management clients, 3 - COS0 client, 4 - COS client)(HIGHEST)
217 * 3bits client num.
218 * PRI4 | PRI3 | PRI2 | PRI1 | PRI0
219 * cos1-100 cos0-011 dbg1-010 dbg0-001 MCP-000
220 */
221
222 REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT, 0x4688);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000223 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000224 * Bitmap of 5bits length. Each bit specifies whether the entry behaves
225 * as strict. Bits 0,1,2 - debug and management entries, 3 -
226 * COS0 entry, 4 - COS1 entry.
227 * COS1 | COS0 | DEBUG1 | DEBUG0 | MGMT
228 * bit4 bit3 bit2 bit1 bit0
229 * MCP and debug are strict
230 */
231
232 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x7);
233 /* defines which entries (clients) are subjected to WFQ arbitration */
234 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ, 0);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000235 /*
236 * For strict priority entries defines the number of consecutive
237 * slots for the highest priority.
238 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000239 REG_WR(bp, NIG_REG_P0_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000240 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000241 * mapping between the CREDIT_WEIGHT registers and actual client
242 * numbers
243 */
244 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP, 0);
245 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_0, 0);
246 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_1, 0);
247
248 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_0, 0);
249 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_1, 0);
250 REG_WR(bp, PBF_REG_HIGH_PRIORITY_COS_NUM, 0);
251 /* ETS mode disable */
252 REG_WR(bp, PBF_REG_ETS_ENABLED, 0);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000253 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000254 * If ETS mode is enabled (there is no strict priority) defines a WFQ
255 * weight for COS0/COS1.
256 */
257 REG_WR(bp, PBF_REG_COS0_WEIGHT, 0x2710);
258 REG_WR(bp, PBF_REG_COS1_WEIGHT, 0x2710);
259 /* Upper bound that COS0_WEIGHT can reach in the WFQ arbiter */
260 REG_WR(bp, PBF_REG_COS0_UPPER_BOUND, 0x989680);
261 REG_WR(bp, PBF_REG_COS1_UPPER_BOUND, 0x989680);
262 /* Defines the number of consecutive slots for the strict priority */
263 REG_WR(bp, PBF_REG_NUM_STRICT_ARB_SLOTS, 0);
264}
265
Yaniv Rosner65a001b2011-01-31 04:22:03 +0000266static void bnx2x_ets_bw_limit_common(const struct link_params *params)
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000267{
268 /* ETS disabled configuration */
269 struct bnx2x *bp = params->bp;
270 DP(NETIF_MSG_LINK, "ETS enabled BW limit configuration\n");
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000271 /*
272 * defines which entries (clients) are subjected to WFQ arbitration
273 * COS0 0x8
274 * COS1 0x10
275 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000276 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ, 0x18);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000277 /*
278 * mapping between the ARB_CREDIT_WEIGHT registers and actual
279 * client numbers (WEIGHT_0 does not actually have to represent
280 * client 0)
281 * PRI4 | PRI3 | PRI2 | PRI1 | PRI0
282 * cos1-001 cos0-000 dbg1-100 dbg0-011 MCP-010
283 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000284 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP, 0x111A);
285
286 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_0,
287 ETS_BW_LIMIT_CREDIT_UPPER_BOUND);
288 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_1,
289 ETS_BW_LIMIT_CREDIT_UPPER_BOUND);
290
291 /* ETS mode enabled*/
292 REG_WR(bp, PBF_REG_ETS_ENABLED, 1);
293
294 /* Defines the number of consecutive slots for the strict priority */
295 REG_WR(bp, PBF_REG_NUM_STRICT_ARB_SLOTS, 0);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000296 /*
297 * Bitmap of 5bits length. Each bit specifies whether the entry behaves
298 * as strict. Bits 0,1,2 - debug and management entries, 3 - COS0
299 * entry, 4 - COS1 entry.
300 * COS1 | COS0 | DEBUG21 | DEBUG0 | MGMT
301 * bit4 bit3 bit2 bit1 bit0
302 * MCP and debug are strict
303 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000304 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x7);
305
306 /* Upper bound that COS0_WEIGHT can reach in the WFQ arbiter.*/
307 REG_WR(bp, PBF_REG_COS0_UPPER_BOUND,
308 ETS_BW_LIMIT_CREDIT_UPPER_BOUND);
309 REG_WR(bp, PBF_REG_COS1_UPPER_BOUND,
310 ETS_BW_LIMIT_CREDIT_UPPER_BOUND);
311}
312
313void bnx2x_ets_bw_limit(const struct link_params *params, const u32 cos0_bw,
314 const u32 cos1_bw)
315{
316 /* ETS disabled configuration*/
317 struct bnx2x *bp = params->bp;
318 const u32 total_bw = cos0_bw + cos1_bw;
319 u32 cos0_credit_weight = 0;
320 u32 cos1_credit_weight = 0;
321
322 DP(NETIF_MSG_LINK, "ETS enabled BW limit configuration\n");
323
324 if ((0 == total_bw) ||
325 (0 == cos0_bw) ||
326 (0 == cos1_bw)) {
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000327 DP(NETIF_MSG_LINK, "Total BW can't be zero\n");
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000328 return;
329 }
330
331 cos0_credit_weight = (cos0_bw * ETS_BW_LIMIT_CREDIT_WEIGHT)/
332 total_bw;
333 cos1_credit_weight = (cos1_bw * ETS_BW_LIMIT_CREDIT_WEIGHT)/
334 total_bw;
335
336 bnx2x_ets_bw_limit_common(params);
337
338 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_0, cos0_credit_weight);
339 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_1, cos1_credit_weight);
340
341 REG_WR(bp, PBF_REG_COS0_WEIGHT, cos0_credit_weight);
342 REG_WR(bp, PBF_REG_COS1_WEIGHT, cos1_credit_weight);
343}
344
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +0000345int bnx2x_ets_strict(const struct link_params *params, const u8 strict_cos)
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000346{
347 /* ETS disabled configuration*/
348 struct bnx2x *bp = params->bp;
349 u32 val = 0;
350
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000351 DP(NETIF_MSG_LINK, "ETS enabled strict configuration\n");
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000352 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000353 * Bitmap of 5bits length. Each bit specifies whether the entry behaves
354 * as strict. Bits 0,1,2 - debug and management entries,
355 * 3 - COS0 entry, 4 - COS1 entry.
356 * COS1 | COS0 | DEBUG21 | DEBUG0 | MGMT
357 * bit4 bit3 bit2 bit1 bit0
358 * MCP and debug are strict
359 */
360 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x1F);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000361 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000362 * For strict priority entries defines the number of consecutive slots
363 * for the highest priority.
364 */
365 REG_WR(bp, NIG_REG_P0_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100);
366 /* ETS mode disable */
367 REG_WR(bp, PBF_REG_ETS_ENABLED, 0);
368 /* Defines the number of consecutive slots for the strict priority */
369 REG_WR(bp, PBF_REG_NUM_STRICT_ARB_SLOTS, 0x100);
370
371 /* Defines the number of consecutive slots for the strict priority */
372 REG_WR(bp, PBF_REG_HIGH_PRIORITY_COS_NUM, strict_cos);
373
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000374 /*
375 * mapping between entry priority to client number (0,1,2 -debug and
376 * management clients, 3 - COS0 client, 4 - COS client)(HIGHEST)
377 * 3bits client num.
378 * PRI4 | PRI3 | PRI2 | PRI1 | PRI0
379 * dbg0-010 dbg1-001 cos1-100 cos0-011 MCP-000
380 * dbg0-010 dbg1-001 cos0-011 cos1-100 MCP-000
381 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000382 val = (0 == strict_cos) ? 0x2318 : 0x22E0;
383 REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT, val);
384
385 return 0;
386}
387/******************************************************************/
Dmitry Kravkove8920672011-05-04 23:52:40 +0000388/* PFC section */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000389/******************************************************************/
390
391static void bnx2x_bmac2_get_pfc_stat(struct link_params *params,
392 u32 pfc_frames_sent[2],
393 u32 pfc_frames_received[2])
394{
395 /* Read pfc statistic */
396 struct bnx2x *bp = params->bp;
397 u32 bmac_addr = params->port ? NIG_REG_INGRESS_BMAC1_MEM :
398 NIG_REG_INGRESS_BMAC0_MEM;
399
400 DP(NETIF_MSG_LINK, "pfc statistic read from BMAC\n");
401
402 REG_RD_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_STAT_GTPP,
403 pfc_frames_sent, 2);
404
405 REG_RD_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_STAT_GRPP,
406 pfc_frames_received, 2);
407
408}
409static void bnx2x_emac_get_pfc_stat(struct link_params *params,
410 u32 pfc_frames_sent[2],
411 u32 pfc_frames_received[2])
412{
413 /* Read pfc statistic */
414 struct bnx2x *bp = params->bp;
415 u32 emac_base = params->port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
416 u32 val_xon = 0;
417 u32 val_xoff = 0;
418
419 DP(NETIF_MSG_LINK, "pfc statistic read from EMAC\n");
420
421 /* PFC received frames */
422 val_xoff = REG_RD(bp, emac_base +
423 EMAC_REG_RX_PFC_STATS_XOFF_RCVD);
424 val_xoff &= EMAC_REG_RX_PFC_STATS_XOFF_RCVD_COUNT;
425 val_xon = REG_RD(bp, emac_base + EMAC_REG_RX_PFC_STATS_XON_RCVD);
426 val_xon &= EMAC_REG_RX_PFC_STATS_XON_RCVD_COUNT;
427
428 pfc_frames_received[0] = val_xon + val_xoff;
429
430 /* PFC received sent */
431 val_xoff = REG_RD(bp, emac_base +
432 EMAC_REG_RX_PFC_STATS_XOFF_SENT);
433 val_xoff &= EMAC_REG_RX_PFC_STATS_XOFF_SENT_COUNT;
434 val_xon = REG_RD(bp, emac_base + EMAC_REG_RX_PFC_STATS_XON_SENT);
435 val_xon &= EMAC_REG_RX_PFC_STATS_XON_SENT_COUNT;
436
437 pfc_frames_sent[0] = val_xon + val_xoff;
438}
439
440void bnx2x_pfc_statistic(struct link_params *params, struct link_vars *vars,
441 u32 pfc_frames_sent[2],
442 u32 pfc_frames_received[2])
443{
444 /* Read pfc statistic */
445 struct bnx2x *bp = params->bp;
446 u32 val = 0;
447 DP(NETIF_MSG_LINK, "pfc statistic\n");
448
449 if (!vars->link_up)
450 return;
451
452 val = REG_RD(bp, MISC_REG_RESET_REG_2);
453 if ((val & (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << params->port))
454 == 0) {
455 DP(NETIF_MSG_LINK, "About to read stats from EMAC\n");
456 bnx2x_emac_get_pfc_stat(params, pfc_frames_sent,
457 pfc_frames_received);
458 } else {
459 DP(NETIF_MSG_LINK, "About to read stats from BMAC\n");
460 bnx2x_bmac2_get_pfc_stat(params, pfc_frames_sent,
461 pfc_frames_received);
462 }
463}
464/******************************************************************/
465/* MAC/PBF section */
466/******************************************************************/
Yaniv Rosnera198c142011-05-31 21:29:42 +0000467static void bnx2x_set_mdio_clk(struct bnx2x *bp, u32 chip_id, u8 port)
468{
469 u32 mode, emac_base;
470 /**
471 * Set clause 45 mode, slow down the MDIO clock to 2.5MHz
472 * (a value of 49==0x31) and make sure that the AUTO poll is off
473 */
474
475 if (CHIP_IS_E2(bp))
476 emac_base = GRCBASE_EMAC0;
477 else
478 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
479 mode = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
480 mode &= ~(EMAC_MDIO_MODE_AUTO_POLL |
481 EMAC_MDIO_MODE_CLOCK_CNT);
482 mode |= (49L << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT);
483
484 mode |= (EMAC_MDIO_MODE_CLAUSE_45);
485 REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE, mode);
486
487 udelay(40);
488}
489
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700490static void bnx2x_emac_init(struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000491 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700492{
493 /* reset and unreset the emac core */
494 struct bnx2x *bp = params->bp;
495 u8 port = params->port;
496 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
497 u32 val;
498 u16 timeout;
499
500 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000501 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700502 udelay(5);
503 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000504 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700505
506 /* init emac - use read-modify-write */
507 /* self clear reset */
508 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700509 EMAC_WR(bp, EMAC_REG_EMAC_MODE, (val | EMAC_MODE_RESET));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700510
511 timeout = 200;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700512 do {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700513 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
514 DP(NETIF_MSG_LINK, "EMAC reset reg is %u\n", val);
515 if (!timeout) {
516 DP(NETIF_MSG_LINK, "EMAC timeout!\n");
517 return;
518 }
519 timeout--;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700520 } while (val & EMAC_MODE_RESET);
Yaniv Rosnera198c142011-05-31 21:29:42 +0000521 bnx2x_set_mdio_clk(bp, params->chip_id, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700522 /* Set mac address */
523 val = ((params->mac_addr[0] << 8) |
524 params->mac_addr[1]);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700525 EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700526
527 val = ((params->mac_addr[2] << 24) |
528 (params->mac_addr[3] << 16) |
529 (params->mac_addr[4] << 8) |
530 params->mac_addr[5]);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700531 EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH + 4, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700532}
533
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +0000534static int bnx2x_emac_enable(struct link_params *params,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +0000535 struct link_vars *vars, u8 lb)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700536{
537 struct bnx2x *bp = params->bp;
538 u8 port = params->port;
539 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
540 u32 val;
541
542 DP(NETIF_MSG_LINK, "enabling EMAC\n");
543
544 /* enable emac and not bmac */
545 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 1);
546
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700547 /* ASIC */
548 if (vars->phy_flags & PHY_XGXS_FLAG) {
549 u32 ser_lane = ((params->lane_config &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000550 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
551 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700552
553 DP(NETIF_MSG_LINK, "XGXS\n");
554 /* select the master lanes (out of 0-3) */
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000555 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, ser_lane);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700556 /* select XGXS */
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000557 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700558
559 } else { /* SerDes */
560 DP(NETIF_MSG_LINK, "SerDes\n");
561 /* select SerDes */
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000562 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700563 }
564
Eilon Greenstein811a2f22009-02-12 08:37:04 +0000565 bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000566 EMAC_RX_MODE_RESET);
Eilon Greenstein811a2f22009-02-12 08:37:04 +0000567 bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000568 EMAC_TX_MODE_RESET);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700569
570 if (CHIP_REV_IS_SLOW(bp)) {
571 /* config GMII mode */
572 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000573 EMAC_WR(bp, EMAC_REG_EMAC_MODE, (val | EMAC_MODE_PORT_GMII));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700574 } else { /* ASIC */
575 /* pause enable/disable */
576 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
577 EMAC_RX_MODE_FLOW_EN);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700578
579 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000580 (EMAC_TX_MODE_EXT_PAUSE_EN |
581 EMAC_TX_MODE_FLOW_EN));
582 if (!(params->feature_config_flags &
583 FEATURE_CONFIG_PFC_ENABLED)) {
584 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
585 bnx2x_bits_en(bp, emac_base +
586 EMAC_REG_EMAC_RX_MODE,
587 EMAC_RX_MODE_FLOW_EN);
588
589 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
590 bnx2x_bits_en(bp, emac_base +
591 EMAC_REG_EMAC_TX_MODE,
592 (EMAC_TX_MODE_EXT_PAUSE_EN |
593 EMAC_TX_MODE_FLOW_EN));
594 } else
595 bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
596 EMAC_TX_MODE_FLOW_EN);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700597 }
598
599 /* KEEP_VLAN_TAG, promiscuous */
600 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_RX_MODE);
601 val |= EMAC_RX_MODE_KEEP_VLAN_TAG | EMAC_RX_MODE_PROMISCUOUS;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000602
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000603 /*
604 * Setting this bit causes MAC control frames (except for pause
605 * frames) to be passed on for processing. This setting has no
606 * affect on the operation of the pause frames. This bit effects
607 * all packets regardless of RX Parser packet sorting logic.
608 * Turn the PFC off to make sure we are in Xon state before
609 * enabling it.
610 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000611 EMAC_WR(bp, EMAC_REG_RX_PFC_MODE, 0);
612 if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED) {
613 DP(NETIF_MSG_LINK, "PFC is enabled\n");
614 /* Enable PFC again */
615 EMAC_WR(bp, EMAC_REG_RX_PFC_MODE,
616 EMAC_REG_RX_PFC_MODE_RX_EN |
617 EMAC_REG_RX_PFC_MODE_TX_EN |
618 EMAC_REG_RX_PFC_MODE_PRIORITIES);
619
620 EMAC_WR(bp, EMAC_REG_RX_PFC_PARAM,
621 ((0x0101 <<
622 EMAC_REG_RX_PFC_PARAM_OPCODE_BITSHIFT) |
623 (0x00ff <<
624 EMAC_REG_RX_PFC_PARAM_PRIORITY_EN_BITSHIFT)));
625 val |= EMAC_RX_MODE_KEEP_MAC_CONTROL;
626 }
Eilon Greenstein3196a882008-08-13 15:58:49 -0700627 EMAC_WR(bp, EMAC_REG_EMAC_RX_MODE, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700628
629 /* Set Loopback */
630 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
631 if (lb)
632 val |= 0x810;
633 else
634 val &= ~0x810;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700635 EMAC_WR(bp, EMAC_REG_EMAC_MODE, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700636
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +0000637 /* enable emac */
638 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 1);
639
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700640 /* enable emac for jumbo packets */
Eilon Greenstein3196a882008-08-13 15:58:49 -0700641 EMAC_WR(bp, EMAC_REG_EMAC_RX_MTU_SIZE,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700642 (EMAC_RX_MTU_SIZE_JUMBO_ENA |
643 (ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD)));
644
645 /* strip CRC */
646 REG_WR(bp, NIG_REG_NIG_INGRESS_EMAC0_NO_CRC + port*4, 0x1);
647
648 /* disable the NIG in/out to the bmac */
649 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x0);
650 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, 0x0);
651 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x0);
652
653 /* enable the NIG in/out to the emac */
654 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x1);
655 val = 0;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000656 if ((params->feature_config_flags &
657 FEATURE_CONFIG_PFC_ENABLED) ||
658 (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700659 val = 1;
660
661 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, val);
662 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x1);
663
Yaniv Rosner02a23162011-01-31 04:22:53 +0000664 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700665
666 vars->mac_type = MAC_TYPE_EMAC;
667 return 0;
668}
669
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000670static void bnx2x_update_pfc_bmac1(struct link_params *params,
671 struct link_vars *vars)
672{
673 u32 wb_data[2];
674 struct bnx2x *bp = params->bp;
675 u32 bmac_addr = params->port ? NIG_REG_INGRESS_BMAC1_MEM :
676 NIG_REG_INGRESS_BMAC0_MEM;
677
678 u32 val = 0x14;
679 if ((!(params->feature_config_flags &
680 FEATURE_CONFIG_PFC_ENABLED)) &&
681 (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX))
682 /* Enable BigMAC to react on received Pause packets */
683 val |= (1<<5);
684 wb_data[0] = val;
685 wb_data[1] = 0;
686 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_CONTROL, wb_data, 2);
687
688 /* tx control */
689 val = 0xc0;
690 if (!(params->feature_config_flags &
691 FEATURE_CONFIG_PFC_ENABLED) &&
692 (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
693 val |= 0x800000;
694 wb_data[0] = val;
695 wb_data[1] = 0;
696 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_CONTROL, wb_data, 2);
697}
698
699static void bnx2x_update_pfc_bmac2(struct link_params *params,
700 struct link_vars *vars,
701 u8 is_lb)
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000702{
703 /*
704 * Set rx control: Strip CRC and enable BigMAC to relay
705 * control packets to the system as well
706 */
707 u32 wb_data[2];
708 struct bnx2x *bp = params->bp;
709 u32 bmac_addr = params->port ? NIG_REG_INGRESS_BMAC1_MEM :
710 NIG_REG_INGRESS_BMAC0_MEM;
711 u32 val = 0x14;
712
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000713 if ((!(params->feature_config_flags &
714 FEATURE_CONFIG_PFC_ENABLED)) &&
715 (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX))
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000716 /* Enable BigMAC to react on received Pause packets */
717 val |= (1<<5);
718 wb_data[0] = val;
719 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000720 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_CONTROL, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000721 udelay(30);
722
723 /* Tx control */
724 val = 0xc0;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000725 if (!(params->feature_config_flags &
726 FEATURE_CONFIG_PFC_ENABLED) &&
727 (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000728 val |= 0x800000;
729 wb_data[0] = val;
730 wb_data[1] = 0;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000731 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_CONTROL, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000732
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000733 if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED) {
734 DP(NETIF_MSG_LINK, "PFC is enabled\n");
735 /* Enable PFC RX & TX & STATS and set 8 COS */
736 wb_data[0] = 0x0;
737 wb_data[0] |= (1<<0); /* RX */
738 wb_data[0] |= (1<<1); /* TX */
739 wb_data[0] |= (1<<2); /* Force initial Xon */
740 wb_data[0] |= (1<<3); /* 8 cos */
741 wb_data[0] |= (1<<5); /* STATS */
742 wb_data[1] = 0;
743 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_PFC_CONTROL,
744 wb_data, 2);
745 /* Clear the force Xon */
746 wb_data[0] &= ~(1<<2);
747 } else {
748 DP(NETIF_MSG_LINK, "PFC is disabled\n");
749 /* disable PFC RX & TX & STATS and set 8 COS */
750 wb_data[0] = 0x8;
751 wb_data[1] = 0;
752 }
753
754 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_PFC_CONTROL, wb_data, 2);
755
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000756 /*
757 * Set Time (based unit is 512 bit time) between automatic
758 * re-sending of PP packets amd enable automatic re-send of
759 * Per-Priroity Packet as long as pp_gen is asserted and
760 * pp_disable is low.
761 */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000762 val = 0x8000;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000763 if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED)
764 val |= (1<<16); /* enable automatic re-send */
765
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000766 wb_data[0] = val;
767 wb_data[1] = 0;
768 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_PAUSE_CONTROL,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000769 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000770
771 /* mac control */
772 val = 0x3; /* Enable RX and TX */
773 if (is_lb) {
774 val |= 0x4; /* Local loopback */
775 DP(NETIF_MSG_LINK, "enable bmac loopback\n");
776 }
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000777 /* When PFC enabled, Pass pause frames towards the NIG. */
778 if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED)
779 val |= ((1<<6)|(1<<5));
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000780
781 wb_data[0] = val;
782 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000783 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_BMAC_CONTROL, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000784}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700785
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000786static void bnx2x_update_pfc_brb(struct link_params *params,
787 struct link_vars *vars,
788 struct bnx2x_nig_brb_pfc_port_params *pfc_params)
789{
790 struct bnx2x *bp = params->bp;
791 int set_pfc = params->feature_config_flags &
792 FEATURE_CONFIG_PFC_ENABLED;
793
794 /* default - pause configuration */
795 u32 pause_xoff_th = PFC_BRB_MAC_PAUSE_XOFF_THRESHOLD_PAUSEABLE;
796 u32 pause_xon_th = PFC_BRB_MAC_PAUSE_XON_THRESHOLD_PAUSEABLE;
797 u32 full_xoff_th = PFC_BRB_MAC_FULL_XOFF_THRESHOLD_PAUSEABLE;
798 u32 full_xon_th = PFC_BRB_MAC_FULL_XON_THRESHOLD_PAUSEABLE;
799
800 if (set_pfc && pfc_params)
801 /* First COS */
802 if (!pfc_params->cos0_pauseable) {
803 pause_xoff_th =
804 PFC_BRB_MAC_PAUSE_XOFF_THRESHOLD_NON_PAUSEABLE;
805 pause_xon_th =
806 PFC_BRB_MAC_PAUSE_XON_THRESHOLD_NON_PAUSEABLE;
807 full_xoff_th =
808 PFC_BRB_MAC_FULL_XOFF_THRESHOLD_NON_PAUSEABLE;
809 full_xon_th =
810 PFC_BRB_MAC_FULL_XON_THRESHOLD_NON_PAUSEABLE;
811 }
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000812 /*
813 * The number of free blocks below which the pause signal to class 0
814 * of MAC #n is asserted. n=0,1
815 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000816 REG_WR(bp, BRB1_REG_PAUSE_0_XOFF_THRESHOLD_0 , pause_xoff_th);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000817 /*
818 * The number of free blocks above which the pause signal to class 0
819 * of MAC #n is de-asserted. n=0,1
820 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000821 REG_WR(bp, BRB1_REG_PAUSE_0_XON_THRESHOLD_0 , pause_xon_th);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000822 /*
823 * The number of free blocks below which the full signal to class 0
824 * of MAC #n is asserted. n=0,1
825 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000826 REG_WR(bp, BRB1_REG_FULL_0_XOFF_THRESHOLD_0 , full_xoff_th);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000827 /*
828 * The number of free blocks above which the full signal to class 0
829 * of MAC #n is de-asserted. n=0,1
830 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000831 REG_WR(bp, BRB1_REG_FULL_0_XON_THRESHOLD_0 , full_xon_th);
832
833 if (set_pfc && pfc_params) {
834 /* Second COS */
835 if (pfc_params->cos1_pauseable) {
836 pause_xoff_th =
837 PFC_BRB_MAC_PAUSE_XOFF_THRESHOLD_PAUSEABLE;
838 pause_xon_th =
839 PFC_BRB_MAC_PAUSE_XON_THRESHOLD_PAUSEABLE;
840 full_xoff_th =
841 PFC_BRB_MAC_FULL_XOFF_THRESHOLD_PAUSEABLE;
842 full_xon_th =
843 PFC_BRB_MAC_FULL_XON_THRESHOLD_PAUSEABLE;
844 } else {
845 pause_xoff_th =
846 PFC_BRB_MAC_PAUSE_XOFF_THRESHOLD_NON_PAUSEABLE;
847 pause_xon_th =
848 PFC_BRB_MAC_PAUSE_XON_THRESHOLD_NON_PAUSEABLE;
849 full_xoff_th =
850 PFC_BRB_MAC_FULL_XOFF_THRESHOLD_NON_PAUSEABLE;
851 full_xon_th =
852 PFC_BRB_MAC_FULL_XON_THRESHOLD_NON_PAUSEABLE;
853 }
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000854 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000855 * The number of free blocks below which the pause signal to
856 * class 1 of MAC #n is asserted. n=0,1
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000857 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000858 REG_WR(bp, BRB1_REG_PAUSE_1_XOFF_THRESHOLD_0, pause_xoff_th);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000859 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000860 * The number of free blocks above which the pause signal to
861 * class 1 of MAC #n is de-asserted. n=0,1
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000862 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000863 REG_WR(bp, BRB1_REG_PAUSE_1_XON_THRESHOLD_0, pause_xon_th);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000864 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000865 * The number of free blocks below which the full signal to
866 * class 1 of MAC #n is asserted. n=0,1
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000867 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000868 REG_WR(bp, BRB1_REG_FULL_1_XOFF_THRESHOLD_0, full_xoff_th);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000869 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000870 * The number of free blocks above which the full signal to
871 * class 1 of MAC #n is de-asserted. n=0,1
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000872 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000873 REG_WR(bp, BRB1_REG_FULL_1_XON_THRESHOLD_0, full_xon_th);
874 }
875}
876
877static void bnx2x_update_pfc_nig(struct link_params *params,
878 struct link_vars *vars,
879 struct bnx2x_nig_brb_pfc_port_params *nig_params)
880{
881 u32 xcm_mask = 0, ppp_enable = 0, pause_enable = 0, llfc_out_en = 0;
882 u32 llfc_enable = 0, xcm0_out_en = 0, p0_hwpfc_enable = 0;
883 u32 pkt_priority_to_cos = 0;
884 u32 val;
885 struct bnx2x *bp = params->bp;
886 int port = params->port;
887 int set_pfc = params->feature_config_flags &
888 FEATURE_CONFIG_PFC_ENABLED;
889 DP(NETIF_MSG_LINK, "updating pfc nig parameters\n");
890
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000891 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000892 * When NIG_LLH0_XCM_MASK_REG_LLHX_XCM_MASK_BCN bit is set
893 * MAC control frames (that are not pause packets)
894 * will be forwarded to the XCM.
895 */
896 xcm_mask = REG_RD(bp,
897 port ? NIG_REG_LLH1_XCM_MASK :
898 NIG_REG_LLH0_XCM_MASK);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000899 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000900 * nig params will override non PFC params, since it's possible to
901 * do transition from PFC to SAFC
902 */
903 if (set_pfc) {
904 pause_enable = 0;
905 llfc_out_en = 0;
906 llfc_enable = 0;
907 ppp_enable = 1;
908 xcm_mask &= ~(port ? NIG_LLH1_XCM_MASK_REG_LLH1_XCM_MASK_BCN :
909 NIG_LLH0_XCM_MASK_REG_LLH0_XCM_MASK_BCN);
910 xcm0_out_en = 0;
911 p0_hwpfc_enable = 1;
912 } else {
913 if (nig_params) {
914 llfc_out_en = nig_params->llfc_out_en;
915 llfc_enable = nig_params->llfc_enable;
916 pause_enable = nig_params->pause_enable;
917 } else /*defaul non PFC mode - PAUSE */
918 pause_enable = 1;
919
920 xcm_mask |= (port ? NIG_LLH1_XCM_MASK_REG_LLH1_XCM_MASK_BCN :
921 NIG_LLH0_XCM_MASK_REG_LLH0_XCM_MASK_BCN);
922 xcm0_out_en = 1;
923 }
924
925 REG_WR(bp, port ? NIG_REG_LLFC_OUT_EN_1 :
926 NIG_REG_LLFC_OUT_EN_0, llfc_out_en);
927 REG_WR(bp, port ? NIG_REG_LLFC_ENABLE_1 :
928 NIG_REG_LLFC_ENABLE_0, llfc_enable);
929 REG_WR(bp, port ? NIG_REG_PAUSE_ENABLE_1 :
930 NIG_REG_PAUSE_ENABLE_0, pause_enable);
931
932 REG_WR(bp, port ? NIG_REG_PPP_ENABLE_1 :
933 NIG_REG_PPP_ENABLE_0, ppp_enable);
934
935 REG_WR(bp, port ? NIG_REG_LLH1_XCM_MASK :
936 NIG_REG_LLH0_XCM_MASK, xcm_mask);
937
938 REG_WR(bp, NIG_REG_LLFC_EGRESS_SRC_ENABLE_0, 0x7);
939
940 /* output enable for RX_XCM # IF */
941 REG_WR(bp, NIG_REG_XCM0_OUT_EN, xcm0_out_en);
942
943 /* HW PFC TX enable */
944 REG_WR(bp, NIG_REG_P0_HWPFC_ENABLE, p0_hwpfc_enable);
945
946 /* 0x2 = BMAC, 0x1= EMAC */
947 switch (vars->mac_type) {
948 case MAC_TYPE_EMAC:
949 val = 1;
950 break;
951 case MAC_TYPE_BMAC:
952 val = 0;
953 break;
954 default:
955 val = 0;
956 break;
957 }
958 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT, val);
959
960 if (nig_params) {
961 pkt_priority_to_cos = nig_params->pkt_priority_to_cos;
962
963 REG_WR(bp, port ? NIG_REG_P1_RX_COS0_PRIORITY_MASK :
964 NIG_REG_P0_RX_COS0_PRIORITY_MASK,
965 nig_params->rx_cos0_priority_mask);
966
967 REG_WR(bp, port ? NIG_REG_P1_RX_COS1_PRIORITY_MASK :
968 NIG_REG_P0_RX_COS1_PRIORITY_MASK,
969 nig_params->rx_cos1_priority_mask);
970
971 REG_WR(bp, port ? NIG_REG_LLFC_HIGH_PRIORITY_CLASSES_1 :
972 NIG_REG_LLFC_HIGH_PRIORITY_CLASSES_0,
973 nig_params->llfc_high_priority_classes);
974
975 REG_WR(bp, port ? NIG_REG_LLFC_LOW_PRIORITY_CLASSES_1 :
976 NIG_REG_LLFC_LOW_PRIORITY_CLASSES_0,
977 nig_params->llfc_low_priority_classes);
978 }
979 REG_WR(bp, port ? NIG_REG_P1_PKT_PRIORITY_TO_COS :
980 NIG_REG_P0_PKT_PRIORITY_TO_COS,
981 pkt_priority_to_cos);
982}
983
984
985void bnx2x_update_pfc(struct link_params *params,
986 struct link_vars *vars,
987 struct bnx2x_nig_brb_pfc_port_params *pfc_params)
988{
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000989 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000990 * The PFC and pause are orthogonal to one another, meaning when
991 * PFC is enabled, the pause are disabled, and when PFC is
992 * disabled, pause are set according to the pause result.
993 */
994 u32 val;
995 struct bnx2x *bp = params->bp;
996
997 /* update NIG params */
998 bnx2x_update_pfc_nig(params, vars, pfc_params);
999
1000 /* update BRB params */
1001 bnx2x_update_pfc_brb(params, vars, pfc_params);
1002
1003 if (!vars->link_up)
1004 return;
1005
1006 val = REG_RD(bp, MISC_REG_RESET_REG_2);
1007 if ((val & (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << params->port))
1008 == 0) {
1009 DP(NETIF_MSG_LINK, "About to update PFC in EMAC\n");
1010 bnx2x_emac_enable(params, vars, 0);
1011 return;
1012 }
1013
1014 DP(NETIF_MSG_LINK, "About to update PFC in BMAC\n");
1015 if (CHIP_IS_E2(bp))
1016 bnx2x_update_pfc_bmac2(params, vars, 0);
1017 else
1018 bnx2x_update_pfc_bmac1(params, vars);
1019
1020 val = 0;
1021 if ((params->feature_config_flags &
1022 FEATURE_CONFIG_PFC_ENABLED) ||
1023 (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
1024 val = 1;
1025 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + params->port*4, val);
1026}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001027
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00001028static int bnx2x_bmac1_enable(struct link_params *params,
1029 struct link_vars *vars,
1030 u8 is_lb)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001031{
1032 struct bnx2x *bp = params->bp;
1033 u8 port = params->port;
1034 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
1035 NIG_REG_INGRESS_BMAC0_MEM;
1036 u32 wb_data[2];
1037 u32 val;
1038
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001039 DP(NETIF_MSG_LINK, "Enabling BigMAC1\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001040
1041 /* XGXS control */
1042 wb_data[0] = 0x3c;
1043 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001044 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_XGXS_CONTROL,
1045 wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001046
1047 /* tx MAC SA */
1048 wb_data[0] = ((params->mac_addr[2] << 24) |
1049 (params->mac_addr[3] << 16) |
1050 (params->mac_addr[4] << 8) |
1051 params->mac_addr[5]);
1052 wb_data[1] = ((params->mac_addr[0] << 8) |
1053 params->mac_addr[1]);
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001054 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_SOURCE_ADDR, wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001055
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001056 /* mac control */
1057 val = 0x3;
1058 if (is_lb) {
1059 val |= 0x4;
1060 DP(NETIF_MSG_LINK, "enable bmac loopback\n");
1061 }
1062 wb_data[0] = val;
1063 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001064 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL, wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001065
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001066 /* set rx mtu */
1067 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
1068 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001069 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_MAX_SIZE, wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001070
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001071 bnx2x_update_pfc_bmac1(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001072
1073 /* set tx 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_TX_MAX_SIZE, wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001077
1078 /* set cnt max size */
1079 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
1080 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001081 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_CNT_MAX_SIZE, wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001082
1083 /* configure safc */
1084 wb_data[0] = 0x1000200;
1085 wb_data[1] = 0;
1086 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_LLFC_MSG_FLDS,
1087 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001088
1089 return 0;
1090}
1091
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00001092static int bnx2x_bmac2_enable(struct link_params *params,
1093 struct link_vars *vars,
1094 u8 is_lb)
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001095{
1096 struct bnx2x *bp = params->bp;
1097 u8 port = params->port;
1098 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
1099 NIG_REG_INGRESS_BMAC0_MEM;
1100 u32 wb_data[2];
1101
1102 DP(NETIF_MSG_LINK, "Enabling BigMAC2\n");
1103
1104 wb_data[0] = 0;
1105 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001106 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_BMAC_CONTROL, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001107 udelay(30);
1108
1109 /* XGXS control: Reset phy HW, MDIO registers, PHY PLL and BMAC */
1110 wb_data[0] = 0x3c;
1111 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001112 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_BMAC_XGXS_CONTROL,
1113 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001114
1115 udelay(30);
1116
1117 /* tx MAC SA */
1118 wb_data[0] = ((params->mac_addr[2] << 24) |
1119 (params->mac_addr[3] << 16) |
1120 (params->mac_addr[4] << 8) |
1121 params->mac_addr[5]);
1122 wb_data[1] = ((params->mac_addr[0] << 8) |
1123 params->mac_addr[1]);
1124 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_SOURCE_ADDR,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001125 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001126
1127 udelay(30);
1128
1129 /* Configure SAFC */
1130 wb_data[0] = 0x1000200;
1131 wb_data[1] = 0;
1132 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_LLFC_MSG_FLDS,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001133 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001134 udelay(30);
1135
1136 /* set rx mtu */
1137 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
1138 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001139 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_MAX_SIZE, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001140 udelay(30);
1141
1142 /* set tx mtu */
1143 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
1144 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001145 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_MAX_SIZE, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001146 udelay(30);
1147 /* set cnt max size */
1148 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD - 2;
1149 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001150 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_CNT_MAX_SIZE, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001151 udelay(30);
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001152 bnx2x_update_pfc_bmac2(params, vars, is_lb);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001153
1154 return 0;
1155}
1156
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00001157static int bnx2x_bmac_enable(struct link_params *params,
1158 struct link_vars *vars,
1159 u8 is_lb)
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001160{
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00001161 int rc = 0;
1162 u8 port = params->port;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001163 struct bnx2x *bp = params->bp;
1164 u32 val;
1165 /* reset and unreset the BigMac */
1166 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001167 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
Yaniv Rosner1d9c05d2010-11-01 05:32:25 +00001168 msleep(1);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001169
1170 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001171 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001172
1173 /* enable access for bmac registers */
1174 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
1175
1176 /* Enable BMAC according to BMAC type*/
1177 if (CHIP_IS_E2(bp))
1178 rc = bnx2x_bmac2_enable(params, vars, is_lb);
1179 else
1180 rc = bnx2x_bmac1_enable(params, vars, is_lb);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001181 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0x1);
1182 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 0x0);
1183 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 0x0);
1184 val = 0;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001185 if ((params->feature_config_flags &
1186 FEATURE_CONFIG_PFC_ENABLED) ||
1187 (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001188 val = 1;
1189 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, val);
1190 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x0);
1191 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x0);
1192 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, 0x0);
1193 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x1);
1194 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x1);
1195
1196 vars->mac_type = MAC_TYPE_BMAC;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001197 return rc;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001198}
1199
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001200
1201static void bnx2x_update_mng(struct link_params *params, u32 link_status)
1202{
1203 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00001204
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001205 REG_WR(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001206 offsetof(struct shmem_region,
1207 port_mb[params->port].link_status), link_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001208}
1209
1210static void bnx2x_bmac_rx_disable(struct bnx2x *bp, u8 port)
1211{
1212 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001213 NIG_REG_INGRESS_BMAC0_MEM;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001214 u32 wb_data[2];
Eilon Greenstein3196a882008-08-13 15:58:49 -07001215 u32 nig_bmac_enable = REG_RD(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001216
1217 /* Only if the bmac is out of reset */
1218 if (REG_RD(bp, MISC_REG_RESET_REG_2) &
1219 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port) &&
1220 nig_bmac_enable) {
1221
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001222 if (CHIP_IS_E2(bp)) {
1223 /* Clear Rx Enable bit in BMAC_CONTROL register */
1224 REG_RD_DMAE(bp, bmac_addr +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001225 BIGMAC2_REGISTER_BMAC_CONTROL,
1226 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001227 wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
1228 REG_WR_DMAE(bp, bmac_addr +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001229 BIGMAC2_REGISTER_BMAC_CONTROL,
1230 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001231 } else {
1232 /* Clear Rx Enable bit in BMAC_CONTROL register */
1233 REG_RD_DMAE(bp, bmac_addr +
1234 BIGMAC_REGISTER_BMAC_CONTROL,
1235 wb_data, 2);
1236 wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
1237 REG_WR_DMAE(bp, bmac_addr +
1238 BIGMAC_REGISTER_BMAC_CONTROL,
1239 wb_data, 2);
1240 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001241 msleep(1);
1242 }
1243}
1244
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00001245static int bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl,
1246 u32 line_speed)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001247{
1248 struct bnx2x *bp = params->bp;
1249 u8 port = params->port;
1250 u32 init_crd, crd;
1251 u32 count = 1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001252
1253 /* disable port */
1254 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x1);
1255
1256 /* wait for init credit */
1257 init_crd = REG_RD(bp, PBF_REG_P0_INIT_CRD + port*4);
1258 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
1259 DP(NETIF_MSG_LINK, "init_crd 0x%x crd 0x%x\n", init_crd, crd);
1260
1261 while ((init_crd != crd) && count) {
1262 msleep(5);
1263
1264 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
1265 count--;
1266 }
1267 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
1268 if (init_crd != crd) {
1269 DP(NETIF_MSG_LINK, "BUG! init_crd 0x%x != crd 0x%x\n",
1270 init_crd, crd);
1271 return -EINVAL;
1272 }
1273
David S. Millerc0700f92008-12-16 23:53:20 -08001274 if (flow_ctrl & BNX2X_FLOW_CTRL_RX ||
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001275 line_speed == SPEED_10 ||
1276 line_speed == SPEED_100 ||
1277 line_speed == SPEED_1000 ||
1278 line_speed == SPEED_2500) {
1279 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001280 /* update threshold */
1281 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, 0);
1282 /* update init credit */
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001283 init_crd = 778; /* (800-18-4) */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001284
1285 } else {
1286 u32 thresh = (ETH_MAX_JUMBO_PACKET_SIZE +
1287 ETH_OVREHEAD)/16;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001288 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001289 /* update threshold */
1290 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, thresh);
1291 /* update init credit */
1292 switch (line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001293 case SPEED_10000:
1294 init_crd = thresh + 553 - 22;
1295 break;
1296
1297 case SPEED_12000:
1298 init_crd = thresh + 664 - 22;
1299 break;
1300
1301 case SPEED_13000:
1302 init_crd = thresh + 742 - 22;
1303 break;
1304
1305 case SPEED_16000:
1306 init_crd = thresh + 778 - 22;
1307 break;
1308 default:
1309 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
1310 line_speed);
1311 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001312 }
1313 }
1314 REG_WR(bp, PBF_REG_P0_INIT_CRD + port*4, init_crd);
1315 DP(NETIF_MSG_LINK, "PBF updated to speed %d credit %d\n",
1316 line_speed, init_crd);
1317
1318 /* probe the credit changes */
1319 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x1);
1320 msleep(5);
1321 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x0);
1322
1323 /* enable port */
1324 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x0);
1325 return 0;
1326}
1327
Dmitry Kravkove8920672011-05-04 23:52:40 +00001328/**
1329 * bnx2x_get_emac_base - retrive emac base address
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001330 *
Dmitry Kravkove8920672011-05-04 23:52:40 +00001331 * @bp: driver handle
1332 * @mdc_mdio_access: access type
1333 * @port: port id
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001334 *
1335 * This function selects the MDC/MDIO access (through emac0 or
1336 * emac1) depend on the mdc_mdio_access, port, port swapped. Each
1337 * phy has a default access mode, which could also be overridden
1338 * by nvram configuration. This parameter, whether this is the
1339 * default phy configuration, or the nvram overrun
1340 * configuration, is passed here as mdc_mdio_access and selects
1341 * the emac_base for the CL45 read/writes operations
1342 */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00001343static u32 bnx2x_get_emac_base(struct bnx2x *bp,
1344 u32 mdc_mdio_access, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001345{
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00001346 u32 emac_base = 0;
1347 switch (mdc_mdio_access) {
1348 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_PHY_TYPE:
1349 break;
1350 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC0:
1351 if (REG_RD(bp, NIG_REG_PORT_SWAP))
1352 emac_base = GRCBASE_EMAC1;
1353 else
1354 emac_base = GRCBASE_EMAC0;
1355 break;
1356 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1:
Eilon Greenstein589abe32009-02-12 08:36:55 +00001357 if (REG_RD(bp, NIG_REG_PORT_SWAP))
1358 emac_base = GRCBASE_EMAC0;
1359 else
1360 emac_base = GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001361 break;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00001362 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH:
1363 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
1364 break;
1365 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_SWAPPED:
Eilon Greenstein6378c022008-08-13 15:59:25 -07001366 emac_base = (port) ? GRCBASE_EMAC0 : GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001367 break;
1368 default:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001369 break;
1370 }
1371 return emac_base;
1372
1373}
1374
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001375/******************************************************************/
1376/* CL45 access functions */
1377/******************************************************************/
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00001378static int bnx2x_cl45_read(struct bnx2x *bp, struct bnx2x_phy *phy,
1379 u8 devad, u16 reg, u16 *ret_val)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001380{
Yaniv Rosnera198c142011-05-31 21:29:42 +00001381 u32 val;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001382 u16 i;
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00001383 int rc = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001384
1385 /* address */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001386 val = ((phy->addr << 21) | (devad << 16) | reg |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001387 EMAC_MDIO_COMM_COMMAND_ADDRESS |
1388 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001389 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001390
1391 for (i = 0; i < 50; i++) {
1392 udelay(10);
1393
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001394 val = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001395 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
1396 udelay(5);
1397 break;
1398 }
1399 }
1400 if (val & EMAC_MDIO_COMM_START_BUSY) {
1401 DP(NETIF_MSG_LINK, "read phy register failed\n");
Yaniv Rosner6d870c32011-01-31 04:22:20 +00001402 netdev_err(bp->dev, "MDC/MDIO access timeout\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001403 *ret_val = 0;
1404 rc = -EFAULT;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001405 } else {
1406 /* data */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001407 val = ((phy->addr << 21) | (devad << 16) |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001408 EMAC_MDIO_COMM_COMMAND_READ_45 |
1409 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001410 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001411
1412 for (i = 0; i < 50; i++) {
1413 udelay(10);
1414
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001415 val = REG_RD(bp, phy->mdio_ctrl +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001416 EMAC_REG_EMAC_MDIO_COMM);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001417 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
1418 *ret_val = (u16)(val & EMAC_MDIO_COMM_DATA);
1419 break;
1420 }
1421 }
1422 if (val & EMAC_MDIO_COMM_START_BUSY) {
1423 DP(NETIF_MSG_LINK, "read phy register failed\n");
Yaniv Rosner6d870c32011-01-31 04:22:20 +00001424 netdev_err(bp->dev, "MDC/MDIO access timeout\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001425 *ret_val = 0;
1426 rc = -EFAULT;
1427 }
1428 }
1429
Yaniv Rosnera198c142011-05-31 21:29:42 +00001430 return rc;
1431}
1432
1433static int bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy,
1434 u8 devad, u16 reg, u16 val)
1435{
1436 u32 tmp;
1437 u8 i;
1438 int rc = 0;
1439
1440 /* address */
1441
1442 tmp = ((phy->addr << 21) | (devad << 16) | reg |
1443 EMAC_MDIO_COMM_COMMAND_ADDRESS |
1444 EMAC_MDIO_COMM_START_BUSY);
1445 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
1446
1447 for (i = 0; i < 50; i++) {
1448 udelay(10);
1449
1450 tmp = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
1451 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
1452 udelay(5);
1453 break;
1454 }
1455 }
1456 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
1457 DP(NETIF_MSG_LINK, "write phy register failed\n");
1458 netdev_err(bp->dev, "MDC/MDIO access timeout\n");
1459 rc = -EFAULT;
1460
1461 } else {
1462 /* data */
1463 tmp = ((phy->addr << 21) | (devad << 16) | val |
1464 EMAC_MDIO_COMM_COMMAND_WRITE_45 |
1465 EMAC_MDIO_COMM_START_BUSY);
1466 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
1467
1468 for (i = 0; i < 50; i++) {
1469 udelay(10);
1470
1471 tmp = REG_RD(bp, phy->mdio_ctrl +
1472 EMAC_REG_EMAC_MDIO_COMM);
1473 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
1474 udelay(5);
1475 break;
1476 }
1477 }
1478 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
1479 DP(NETIF_MSG_LINK, "write phy register failed\n");
1480 netdev_err(bp->dev, "MDC/MDIO access timeout\n");
1481 rc = -EFAULT;
1482 }
1483 }
1484
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001485
1486 return rc;
1487}
1488
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00001489int bnx2x_phy_read(struct link_params *params, u8 phy_addr,
1490 u8 devad, u16 reg, u16 *ret_val)
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001491{
1492 u8 phy_index;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001493 /*
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001494 * Probe for the phy according to the given phy_addr, and execute
1495 * the read request on it
1496 */
1497 for (phy_index = 0; phy_index < params->num_phys; phy_index++) {
1498 if (params->phy[phy_index].addr == phy_addr) {
1499 return bnx2x_cl45_read(params->bp,
1500 &params->phy[phy_index], devad,
1501 reg, ret_val);
1502 }
1503 }
1504 return -EINVAL;
1505}
1506
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00001507int bnx2x_phy_write(struct link_params *params, u8 phy_addr,
1508 u8 devad, u16 reg, u16 val)
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001509{
1510 u8 phy_index;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001511 /*
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001512 * Probe for the phy according to the given phy_addr, and execute
1513 * the write request on it
1514 */
1515 for (phy_index = 0; phy_index < params->num_phys; phy_index++) {
1516 if (params->phy[phy_index].addr == phy_addr) {
1517 return bnx2x_cl45_write(params->bp,
1518 &params->phy[phy_index], devad,
1519 reg, val);
1520 }
1521 }
1522 return -EINVAL;
1523}
1524
Yaniv Rosnerec146a62011-05-31 21:29:27 +00001525static void bnx2x_set_aer_mmd(struct link_params *params,
1526 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001527{
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001528 u32 ser_lane;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001529 u16 offset, aer_val;
1530 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001531 ser_lane = ((params->lane_config &
1532 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
1533 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
1534
Yaniv Rosnerec146a62011-05-31 21:29:27 +00001535 offset = (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ?
1536 (phy->addr + ser_lane) : 0;
1537
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001538 if (CHIP_IS_E2(bp))
Yaniv Rosner82a0d472011-01-18 04:33:52 +00001539 aer_val = 0x3800 + offset - 1;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001540 else
1541 aer_val = 0x3800 + offset;
Yaniv Rosnerec146a62011-05-31 21:29:27 +00001542 DP(NETIF_MSG_LINK, "Set AER to 0x%x\n", aer_val);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001543 CL22_WR_OVER_CL45(bp, phy, MDIO_REG_BANK_AER_BLOCK,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001544 MDIO_AER_BLOCK_AER_REG, aer_val);
Yaniv Rosnerec146a62011-05-31 21:29:27 +00001545
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001546}
1547
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001548/******************************************************************/
1549/* Internal phy section */
1550/******************************************************************/
1551
1552static void bnx2x_set_serdes_access(struct bnx2x *bp, u8 port)
1553{
1554 u32 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
1555
1556 /* Set Clause 22 */
1557 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + port*0x10, 1);
1558 REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245f8000);
1559 udelay(500);
1560 REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245d000f);
1561 udelay(500);
1562 /* Set Clause 45 */
1563 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + port*0x10, 0);
1564}
1565
1566static void bnx2x_serdes_deassert(struct bnx2x *bp, u8 port)
1567{
1568 u32 val;
1569
1570 DP(NETIF_MSG_LINK, "bnx2x_serdes_deassert\n");
1571
1572 val = SERDES_RESET_BITS << (port*16);
1573
1574 /* reset and unreset the SerDes/XGXS */
1575 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR, val);
1576 udelay(500);
1577 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET, val);
1578
1579 bnx2x_set_serdes_access(bp, port);
1580
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001581 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_DEVAD + port*0x10,
1582 DEFAULT_PHY_DEV_ADDR);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001583}
1584
1585static void bnx2x_xgxs_deassert(struct link_params *params)
1586{
1587 struct bnx2x *bp = params->bp;
1588 u8 port;
1589 u32 val;
1590 DP(NETIF_MSG_LINK, "bnx2x_xgxs_deassert\n");
1591 port = params->port;
1592
1593 val = XGXS_RESET_BITS << (port*16);
1594
1595 /* reset and unreset the SerDes/XGXS */
1596 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR, val);
1597 udelay(500);
1598 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET, val);
1599
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001600 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_ST + port*0x18, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001601 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001602 params->phy[INT_PHY].def_md_devad);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001603}
1604
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00001605static void bnx2x_calc_ieee_aneg_adv(struct bnx2x_phy *phy,
1606 struct link_params *params, u16 *ieee_fc)
1607{
1608 struct bnx2x *bp = params->bp;
1609 *ieee_fc = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX;
1610 /**
1611 * resolve pause mode and advertisement Please refer to Table
1612 * 28B-3 of the 802.3ab-1999 spec
1613 */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00001614
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00001615 switch (phy->req_flow_ctrl) {
1616 case BNX2X_FLOW_CTRL_AUTO:
1617 if (params->req_fc_auto_adv == BNX2X_FLOW_CTRL_BOTH)
1618 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
1619 else
1620 *ieee_fc |=
1621 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
1622 break;
1623
1624 case BNX2X_FLOW_CTRL_TX:
1625 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
1626 break;
1627
1628 case BNX2X_FLOW_CTRL_RX:
1629 case BNX2X_FLOW_CTRL_BOTH:
1630 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
1631 break;
1632
1633 case BNX2X_FLOW_CTRL_NONE:
1634 default:
1635 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE;
1636 break;
1637 }
1638 DP(NETIF_MSG_LINK, "ieee_fc = 0x%x\n", *ieee_fc);
1639}
1640
1641static void set_phy_vars(struct link_params *params,
1642 struct link_vars *vars)
1643{
1644 struct bnx2x *bp = params->bp;
1645 u8 actual_phy_idx, phy_index, link_cfg_idx;
1646 u8 phy_config_swapped = params->multi_phy_config &
1647 PORT_HW_CFG_PHY_SWAPPED_ENABLED;
1648 for (phy_index = INT_PHY; phy_index < params->num_phys;
1649 phy_index++) {
1650 link_cfg_idx = LINK_CONFIG_IDX(phy_index);
1651 actual_phy_idx = phy_index;
1652 if (phy_config_swapped) {
1653 if (phy_index == EXT_PHY1)
1654 actual_phy_idx = EXT_PHY2;
1655 else if (phy_index == EXT_PHY2)
1656 actual_phy_idx = EXT_PHY1;
1657 }
1658 params->phy[actual_phy_idx].req_flow_ctrl =
1659 params->req_flow_ctrl[link_cfg_idx];
1660
1661 params->phy[actual_phy_idx].req_line_speed =
1662 params->req_line_speed[link_cfg_idx];
1663
1664 params->phy[actual_phy_idx].speed_cap_mask =
1665 params->speed_cap_mask[link_cfg_idx];
1666
1667 params->phy[actual_phy_idx].req_duplex =
1668 params->req_duplex[link_cfg_idx];
1669
1670 if (params->req_line_speed[link_cfg_idx] ==
1671 SPEED_AUTO_NEG)
1672 vars->link_status |= LINK_STATUS_AUTO_NEGOTIATE_ENABLED;
1673
1674 DP(NETIF_MSG_LINK, "req_flow_ctrl %x, req_line_speed %x,"
1675 " speed_cap_mask %x\n",
1676 params->phy[actual_phy_idx].req_flow_ctrl,
1677 params->phy[actual_phy_idx].req_line_speed,
1678 params->phy[actual_phy_idx].speed_cap_mask);
1679 }
1680}
1681
1682static void bnx2x_ext_phy_set_pause(struct link_params *params,
1683 struct bnx2x_phy *phy,
1684 struct link_vars *vars)
1685{
1686 u16 val;
1687 struct bnx2x *bp = params->bp;
1688 /* read modify write pause advertizing */
1689 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV_PAUSE, &val);
1690
1691 val &= ~MDIO_AN_REG_ADV_PAUSE_BOTH;
1692
1693 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
1694 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
1695 if ((vars->ieee_fc &
1696 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
1697 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
1698 val |= MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC;
1699 }
1700 if ((vars->ieee_fc &
1701 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
1702 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
1703 val |= MDIO_AN_REG_ADV_PAUSE_PAUSE;
1704 }
1705 DP(NETIF_MSG_LINK, "Ext phy AN advertize 0x%x\n", val);
1706 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV_PAUSE, val);
1707}
1708
1709static void bnx2x_pause_resolve(struct link_vars *vars, u32 pause_result)
1710{ /* LD LP */
1711 switch (pause_result) { /* ASYM P ASYM P */
1712 case 0xb: /* 1 0 1 1 */
1713 vars->flow_ctrl = BNX2X_FLOW_CTRL_TX;
1714 break;
1715
1716 case 0xe: /* 1 1 1 0 */
1717 vars->flow_ctrl = BNX2X_FLOW_CTRL_RX;
1718 break;
1719
1720 case 0x5: /* 0 1 0 1 */
1721 case 0x7: /* 0 1 1 1 */
1722 case 0xd: /* 1 1 0 1 */
1723 case 0xf: /* 1 1 1 1 */
1724 vars->flow_ctrl = BNX2X_FLOW_CTRL_BOTH;
1725 break;
1726
1727 default:
1728 break;
1729 }
1730 if (pause_result & (1<<0))
1731 vars->link_status |= LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE;
1732 if (pause_result & (1<<1))
1733 vars->link_status |= LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE;
1734}
1735
1736static u8 bnx2x_ext_phy_resolve_fc(struct bnx2x_phy *phy,
1737 struct link_params *params,
1738 struct link_vars *vars)
1739{
1740 struct bnx2x *bp = params->bp;
1741 u16 ld_pause; /* local */
1742 u16 lp_pause; /* link partner */
1743 u16 pause_result;
1744 u8 ret = 0;
1745 /* read twice */
1746
1747 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
1748
1749 if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO)
1750 vars->flow_ctrl = phy->req_flow_ctrl;
1751 else if (phy->req_line_speed != SPEED_AUTO_NEG)
1752 vars->flow_ctrl = params->req_fc_auto_adv;
1753 else if (vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE) {
1754 ret = 1;
1755 bnx2x_cl45_read(bp, phy,
1756 MDIO_AN_DEVAD,
1757 MDIO_AN_REG_ADV_PAUSE, &ld_pause);
1758 bnx2x_cl45_read(bp, phy,
1759 MDIO_AN_DEVAD,
1760 MDIO_AN_REG_LP_AUTO_NEG, &lp_pause);
1761 pause_result = (ld_pause &
1762 MDIO_AN_REG_ADV_PAUSE_MASK) >> 8;
1763 pause_result |= (lp_pause &
1764 MDIO_AN_REG_ADV_PAUSE_MASK) >> 10;
1765 DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x\n",
1766 pause_result);
1767 bnx2x_pause_resolve(vars, pause_result);
1768 }
1769 return ret;
1770}
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001771void bnx2x_link_status_update(struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001772 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001773{
1774 struct bnx2x *bp = params->bp;
1775 u8 link_10g;
1776 u8 port = params->port;
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00001777 u32 sync_offset, media_types;
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00001778 /* Update PHY configuration */
1779 set_phy_vars(params, vars);
1780
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001781 vars->link_status = REG_RD(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001782 offsetof(struct shmem_region,
1783 port_mb[port].link_status));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001784
1785 vars->link_up = (vars->link_status & LINK_STATUS_LINK_UP);
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00001786 vars->phy_flags = PHY_XGXS_FLAG;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001787 if (vars->link_up) {
1788 DP(NETIF_MSG_LINK, "phy link up\n");
1789
1790 vars->phy_link_up = 1;
1791 vars->duplex = DUPLEX_FULL;
1792 switch (vars->link_status &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001793 LINK_STATUS_SPEED_AND_DUPLEX_MASK) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001794 case LINK_10THD:
1795 vars->duplex = DUPLEX_HALF;
1796 /* fall thru */
1797 case LINK_10TFD:
1798 vars->line_speed = SPEED_10;
1799 break;
1800
1801 case LINK_100TXHD:
1802 vars->duplex = DUPLEX_HALF;
1803 /* fall thru */
1804 case LINK_100T4:
1805 case LINK_100TXFD:
1806 vars->line_speed = SPEED_100;
1807 break;
1808
1809 case LINK_1000THD:
1810 vars->duplex = DUPLEX_HALF;
1811 /* fall thru */
1812 case LINK_1000TFD:
1813 vars->line_speed = SPEED_1000;
1814 break;
1815
1816 case LINK_2500THD:
1817 vars->duplex = DUPLEX_HALF;
1818 /* fall thru */
1819 case LINK_2500TFD:
1820 vars->line_speed = SPEED_2500;
1821 break;
1822
1823 case LINK_10GTFD:
1824 vars->line_speed = SPEED_10000;
1825 break;
1826
1827 case LINK_12GTFD:
1828 vars->line_speed = SPEED_12000;
1829 break;
1830
1831 case LINK_12_5GTFD:
1832 vars->line_speed = SPEED_12500;
1833 break;
1834
1835 case LINK_13GTFD:
1836 vars->line_speed = SPEED_13000;
1837 break;
1838
1839 case LINK_15GTFD:
1840 vars->line_speed = SPEED_15000;
1841 break;
1842
1843 case LINK_16GTFD:
1844 vars->line_speed = SPEED_16000;
1845 break;
1846
1847 default:
1848 break;
1849 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001850 vars->flow_ctrl = 0;
1851 if (vars->link_status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED)
1852 vars->flow_ctrl |= BNX2X_FLOW_CTRL_TX;
1853
1854 if (vars->link_status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED)
1855 vars->flow_ctrl |= BNX2X_FLOW_CTRL_RX;
1856
1857 if (!vars->flow_ctrl)
1858 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
1859
1860 if (vars->line_speed &&
1861 ((vars->line_speed == SPEED_10) ||
1862 (vars->line_speed == SPEED_100))) {
1863 vars->phy_flags |= PHY_SGMII_FLAG;
1864 } else {
1865 vars->phy_flags &= ~PHY_SGMII_FLAG;
1866 }
1867
1868 /* anything 10 and over uses the bmac */
1869 link_10g = ((vars->line_speed == SPEED_10000) ||
1870 (vars->line_speed == SPEED_12000) ||
1871 (vars->line_speed == SPEED_12500) ||
1872 (vars->line_speed == SPEED_13000) ||
1873 (vars->line_speed == SPEED_15000) ||
1874 (vars->line_speed == SPEED_16000));
1875 if (link_10g)
1876 vars->mac_type = MAC_TYPE_BMAC;
1877 else
1878 vars->mac_type = MAC_TYPE_EMAC;
1879
1880 } else { /* link down */
1881 DP(NETIF_MSG_LINK, "phy link down\n");
1882
1883 vars->phy_link_up = 0;
1884
1885 vars->line_speed = 0;
1886 vars->duplex = DUPLEX_FULL;
1887 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
1888
1889 /* indicate no mac active */
1890 vars->mac_type = MAC_TYPE_NONE;
1891 }
1892
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00001893 /* Sync media type */
1894 sync_offset = params->shmem_base +
1895 offsetof(struct shmem_region,
1896 dev_info.port_hw_config[port].media_type);
1897 media_types = REG_RD(bp, sync_offset);
1898
1899 params->phy[INT_PHY].media_type =
1900 (media_types & PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK) >>
1901 PORT_HW_CFG_MEDIA_TYPE_PHY0_SHIFT;
1902 params->phy[EXT_PHY1].media_type =
1903 (media_types & PORT_HW_CFG_MEDIA_TYPE_PHY1_MASK) >>
1904 PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT;
1905 params->phy[EXT_PHY2].media_type =
1906 (media_types & PORT_HW_CFG_MEDIA_TYPE_PHY2_MASK) >>
1907 PORT_HW_CFG_MEDIA_TYPE_PHY2_SHIFT;
1908 DP(NETIF_MSG_LINK, "media_types = 0x%x\n", media_types);
1909
Yaniv Rosner020c7e32011-05-31 21:28:43 +00001910 /* Sync AEU offset */
1911 sync_offset = params->shmem_base +
1912 offsetof(struct shmem_region,
1913 dev_info.port_hw_config[port].aeu_int_mask);
1914
1915 vars->aeu_int_mask = REG_RD(bp, sync_offset);
1916
1917 DP(NETIF_MSG_LINK, "link_status 0x%x phy_link_up %x int_mask 0x%x\n",
1918 vars->link_status, vars->phy_link_up, vars->aeu_int_mask);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001919 DP(NETIF_MSG_LINK, "line_speed %x duplex %x flow_ctrl 0x%x\n",
1920 vars->line_speed, vars->duplex, vars->flow_ctrl);
1921}
1922
1923
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001924static void bnx2x_set_master_ln(struct link_params *params,
1925 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001926{
1927 struct bnx2x *bp = params->bp;
1928 u16 new_master_ln, ser_lane;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001929 ser_lane = ((params->lane_config &
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001930 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001931 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001932
1933 /* set the master_ln for AN */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001934 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001935 MDIO_REG_BANK_XGXS_BLOCK2,
1936 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
1937 &new_master_ln);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001938
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001939 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001940 MDIO_REG_BANK_XGXS_BLOCK2 ,
1941 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
1942 (new_master_ln | ser_lane));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001943}
1944
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00001945static int bnx2x_reset_unicore(struct link_params *params,
1946 struct bnx2x_phy *phy,
1947 u8 set_serdes)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001948{
1949 struct bnx2x *bp = params->bp;
1950 u16 mii_control;
1951 u16 i;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001952 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001953 MDIO_REG_BANK_COMBO_IEEE0,
1954 MDIO_COMBO_IEEE0_MII_CONTROL, &mii_control);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001955
1956 /* reset the unicore */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001957 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001958 MDIO_REG_BANK_COMBO_IEEE0,
1959 MDIO_COMBO_IEEE0_MII_CONTROL,
1960 (mii_control |
1961 MDIO_COMBO_IEEO_MII_CONTROL_RESET));
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001962 if (set_serdes)
1963 bnx2x_set_serdes_access(bp, params->port);
Eilon Greensteinc1b73992009-02-12 08:37:07 +00001964
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001965 /* wait for the reset to self clear */
1966 for (i = 0; i < MDIO_ACCESS_TIMEOUT; i++) {
1967 udelay(5);
1968
1969 /* the reset erased the previous bank value */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001970 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001971 MDIO_REG_BANK_COMBO_IEEE0,
1972 MDIO_COMBO_IEEE0_MII_CONTROL,
1973 &mii_control);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001974
1975 if (!(mii_control & MDIO_COMBO_IEEO_MII_CONTROL_RESET)) {
1976 udelay(5);
1977 return 0;
1978 }
1979 }
1980
Yaniv Rosner6d870c32011-01-31 04:22:20 +00001981 netdev_err(bp->dev, "Warning: PHY was not initialized,"
1982 " Port %d\n",
1983 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001984 DP(NETIF_MSG_LINK, "BUG! XGXS is still in reset!\n");
1985 return -EINVAL;
1986
1987}
1988
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001989static void bnx2x_set_swap_lanes(struct link_params *params,
1990 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001991{
1992 struct bnx2x *bp = params->bp;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001993 /*
1994 * Each two bits represents a lane number:
1995 * No swap is 0123 => 0x1b no need to enable the swap
1996 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001997 u16 ser_lane, rx_lane_swap, tx_lane_swap;
1998
1999 ser_lane = ((params->lane_config &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002000 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
2001 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002002 rx_lane_swap = ((params->lane_config &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002003 PORT_HW_CFG_LANE_SWAP_CFG_RX_MASK) >>
2004 PORT_HW_CFG_LANE_SWAP_CFG_RX_SHIFT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002005 tx_lane_swap = ((params->lane_config &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002006 PORT_HW_CFG_LANE_SWAP_CFG_TX_MASK) >>
2007 PORT_HW_CFG_LANE_SWAP_CFG_TX_SHIFT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002008
2009 if (rx_lane_swap != 0x1b) {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002010 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002011 MDIO_REG_BANK_XGXS_BLOCK2,
2012 MDIO_XGXS_BLOCK2_RX_LN_SWAP,
2013 (rx_lane_swap |
2014 MDIO_XGXS_BLOCK2_RX_LN_SWAP_ENABLE |
2015 MDIO_XGXS_BLOCK2_RX_LN_SWAP_FORCE_ENABLE));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002016 } else {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002017 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002018 MDIO_REG_BANK_XGXS_BLOCK2,
2019 MDIO_XGXS_BLOCK2_RX_LN_SWAP, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002020 }
2021
2022 if (tx_lane_swap != 0x1b) {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002023 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002024 MDIO_REG_BANK_XGXS_BLOCK2,
2025 MDIO_XGXS_BLOCK2_TX_LN_SWAP,
2026 (tx_lane_swap |
2027 MDIO_XGXS_BLOCK2_TX_LN_SWAP_ENABLE));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002028 } else {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002029 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002030 MDIO_REG_BANK_XGXS_BLOCK2,
2031 MDIO_XGXS_BLOCK2_TX_LN_SWAP, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002032 }
2033}
2034
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002035static void bnx2x_set_parallel_detection(struct bnx2x_phy *phy,
2036 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002037{
2038 struct bnx2x *bp = params->bp;
2039 u16 control2;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002040 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002041 MDIO_REG_BANK_SERDES_DIGITAL,
2042 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
2043 &control2);
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002044 if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
Yaniv Rosner18afb0a2009-11-05 19:18:04 +02002045 control2 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
2046 else
2047 control2 &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002048 DP(NETIF_MSG_LINK, "phy->speed_cap_mask = 0x%x, control2 = 0x%x\n",
2049 phy->speed_cap_mask, control2);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002050 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002051 MDIO_REG_BANK_SERDES_DIGITAL,
2052 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
2053 control2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002054
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002055 if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002056 (phy->speed_cap_mask &
Yaniv Rosner18afb0a2009-11-05 19:18:04 +02002057 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002058 DP(NETIF_MSG_LINK, "XGXS\n");
2059
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_10G_PARALLEL_DETECT,
2062 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK,
2063 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002064
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002065 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002066 MDIO_REG_BANK_10G_PARALLEL_DETECT,
2067 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
2068 &control2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002069
2070
2071 control2 |=
2072 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN;
2073
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002074 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002075 MDIO_REG_BANK_10G_PARALLEL_DETECT,
2076 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
2077 control2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002078
2079 /* Disable parallel detection of HiG */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002080 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002081 MDIO_REG_BANK_XGXS_BLOCK2,
2082 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G,
2083 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_CX4_XGXS |
2084 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_HIGIG_XGXS);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002085 }
2086}
2087
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002088static void bnx2x_set_autoneg(struct bnx2x_phy *phy,
2089 struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002090 struct link_vars *vars,
2091 u8 enable_cl73)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002092{
2093 struct bnx2x *bp = params->bp;
2094 u16 reg_val;
2095
2096 /* CL37 Autoneg */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002097 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002098 MDIO_REG_BANK_COMBO_IEEE0,
2099 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002100
2101 /* CL37 Autoneg Enabled */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002102 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002103 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_AN_EN;
2104 else /* CL37 Autoneg Disabled */
2105 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
2106 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN);
2107
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002108 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002109 MDIO_REG_BANK_COMBO_IEEE0,
2110 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002111
2112 /* Enable/Disable Autodetection */
2113
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002114 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002115 MDIO_REG_BANK_SERDES_DIGITAL,
2116 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, &reg_val);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002117 reg_val &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN |
2118 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT);
2119 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002120 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002121 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
2122 else
2123 reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
2124
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002125 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002126 MDIO_REG_BANK_SERDES_DIGITAL,
2127 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002128
2129 /* Enable TetonII and BAM autoneg */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002130 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002131 MDIO_REG_BANK_BAM_NEXT_PAGE,
2132 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002133 &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002134 if (vars->line_speed == SPEED_AUTO_NEG) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002135 /* Enable BAM aneg Mode and TetonII aneg Mode */
2136 reg_val |= (MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
2137 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
2138 } else {
2139 /* TetonII and BAM Autoneg Disabled */
2140 reg_val &= ~(MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
2141 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
2142 }
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002143 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002144 MDIO_REG_BANK_BAM_NEXT_PAGE,
2145 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
2146 reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002147
Eilon Greenstein239d6862009-08-12 08:23:04 +00002148 if (enable_cl73) {
2149 /* Enable Cl73 FSM status bits */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002150 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002151 MDIO_REG_BANK_CL73_USERB0,
2152 MDIO_CL73_USERB0_CL73_UCTRL,
2153 0xe);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002154
2155 /* Enable BAM Station Manager*/
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002156 CL22_WR_OVER_CL45(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00002157 MDIO_REG_BANK_CL73_USERB0,
2158 MDIO_CL73_USERB0_CL73_BAM_CTRL1,
2159 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN |
2160 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_STATION_MNGR_EN |
2161 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN);
2162
Yaniv Rosner7846e472009-11-05 19:18:07 +02002163 /* Advertise CL73 link speeds */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002164 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002165 MDIO_REG_BANK_CL73_IEEEB1,
2166 MDIO_CL73_IEEEB1_AN_ADV2,
2167 &reg_val);
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002168 if (phy->speed_cap_mask &
Yaniv Rosner7846e472009-11-05 19:18:07 +02002169 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
2170 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002171 if (phy->speed_cap_mask &
Yaniv Rosner7846e472009-11-05 19:18:07 +02002172 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
2173 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX;
Eilon Greenstein239d6862009-08-12 08:23:04 +00002174
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002175 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002176 MDIO_REG_BANK_CL73_IEEEB1,
2177 MDIO_CL73_IEEEB1_AN_ADV2,
2178 reg_val);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002179
Eilon Greenstein239d6862009-08-12 08:23:04 +00002180 /* CL73 Autoneg Enabled */
2181 reg_val = MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN;
2182
2183 } else /* CL73 Autoneg Disabled */
2184 reg_val = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002185
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002186 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002187 MDIO_REG_BANK_CL73_IEEEB0,
2188 MDIO_CL73_IEEEB0_CL73_AN_CONTROL, reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002189}
2190
2191/* program SerDes, forced speed */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002192static void bnx2x_program_serdes(struct bnx2x_phy *phy,
2193 struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002194 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002195{
2196 struct bnx2x *bp = params->bp;
2197 u16 reg_val;
2198
Eilon Greenstein57937202009-08-12 08:23:53 +00002199 /* program duplex, disable autoneg and sgmii*/
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002200 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002201 MDIO_REG_BANK_COMBO_IEEE0,
2202 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002203 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX |
Eilon Greenstein57937202009-08-12 08:23:53 +00002204 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
2205 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK);
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002206 if (phy->req_duplex == DUPLEX_FULL)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002207 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002208 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002209 MDIO_REG_BANK_COMBO_IEEE0,
2210 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002211
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002212 /*
2213 * program speed
2214 * - needed only if the speed is greater than 1G (2.5G or 10G)
2215 */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002216 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002217 MDIO_REG_BANK_SERDES_DIGITAL,
2218 MDIO_SERDES_DIGITAL_MISC1, &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002219 /* clearing the speed value before setting the right speed */
2220 DP(NETIF_MSG_LINK, "MDIO_REG_BANK_SERDES_DIGITAL = 0x%x\n", reg_val);
2221
2222 reg_val &= ~(MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_MASK |
2223 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
2224
2225 if (!((vars->line_speed == SPEED_1000) ||
2226 (vars->line_speed == SPEED_100) ||
2227 (vars->line_speed == SPEED_10))) {
2228
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002229 reg_val |= (MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_156_25M |
2230 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002231 if (vars->line_speed == SPEED_10000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002232 reg_val |=
2233 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_10G_CX4;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002234 if (vars->line_speed == SPEED_13000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002235 reg_val |=
2236 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_13G;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002237 }
2238
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002239 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002240 MDIO_REG_BANK_SERDES_DIGITAL,
2241 MDIO_SERDES_DIGITAL_MISC1, reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002242
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002243}
2244
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00002245static void bnx2x_set_brcm_cl37_advertisement(struct bnx2x_phy *phy,
2246 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002247{
2248 struct bnx2x *bp = params->bp;
2249 u16 val = 0;
2250
2251 /* configure the 48 bits for BAM AN */
2252
2253 /* set extended capabilities */
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002254 if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002255 val |= MDIO_OVER_1G_UP1_2_5G;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002256 if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002257 val |= MDIO_OVER_1G_UP1_10G;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002258 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002259 MDIO_REG_BANK_OVER_1G,
2260 MDIO_OVER_1G_UP1, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002261
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002262 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002263 MDIO_REG_BANK_OVER_1G,
2264 MDIO_OVER_1G_UP3, 0x400);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002265}
2266
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00002267static void bnx2x_set_ieee_aneg_advertisement(struct bnx2x_phy *phy,
2268 struct link_params *params,
2269 u16 ieee_fc)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002270{
2271 struct bnx2x *bp = params->bp;
Yaniv Rosner7846e472009-11-05 19:18:07 +02002272 u16 val;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002273 /* for AN, we are always publishing full duplex */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002274
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002275 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002276 MDIO_REG_BANK_COMBO_IEEE0,
2277 MDIO_COMBO_IEEE0_AUTO_NEG_ADV, ieee_fc);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002278 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002279 MDIO_REG_BANK_CL73_IEEEB1,
2280 MDIO_CL73_IEEEB1_AN_ADV1, &val);
Yaniv Rosner7846e472009-11-05 19:18:07 +02002281 val &= ~MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_BOTH;
2282 val |= ((ieee_fc<<3) & MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002283 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002284 MDIO_REG_BANK_CL73_IEEEB1,
2285 MDIO_CL73_IEEEB1_AN_ADV1, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002286}
2287
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002288static void bnx2x_restart_autoneg(struct bnx2x_phy *phy,
2289 struct link_params *params,
2290 u8 enable_cl73)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002291{
2292 struct bnx2x *bp = params->bp;
Eilon Greenstein3a36f2e2009-02-12 08:37:09 +00002293 u16 mii_control;
Eilon Greenstein239d6862009-08-12 08:23:04 +00002294
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002295 DP(NETIF_MSG_LINK, "bnx2x_restart_autoneg\n");
Eilon Greenstein3a36f2e2009-02-12 08:37:09 +00002296 /* Enable and restart BAM/CL37 aneg */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002297
Eilon Greenstein239d6862009-08-12 08:23:04 +00002298 if (enable_cl73) {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002299 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002300 MDIO_REG_BANK_CL73_IEEEB0,
2301 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
2302 &mii_control);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002303
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002304 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002305 MDIO_REG_BANK_CL73_IEEEB0,
2306 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
2307 (mii_control |
2308 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN |
2309 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN));
Eilon Greenstein239d6862009-08-12 08:23:04 +00002310 } else {
2311
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002312 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002313 MDIO_REG_BANK_COMBO_IEEE0,
2314 MDIO_COMBO_IEEE0_MII_CONTROL,
2315 &mii_control);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002316 DP(NETIF_MSG_LINK,
2317 "bnx2x_restart_autoneg mii_control before = 0x%x\n",
2318 mii_control);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002319 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002320 MDIO_REG_BANK_COMBO_IEEE0,
2321 MDIO_COMBO_IEEE0_MII_CONTROL,
2322 (mii_control |
2323 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
2324 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN));
Eilon Greenstein239d6862009-08-12 08:23:04 +00002325 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002326}
2327
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002328static void bnx2x_initialize_sgmii_process(struct bnx2x_phy *phy,
2329 struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002330 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002331{
2332 struct bnx2x *bp = params->bp;
2333 u16 control1;
2334
2335 /* in SGMII mode, the unicore is always slave */
2336
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002337 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002338 MDIO_REG_BANK_SERDES_DIGITAL,
2339 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
2340 &control1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002341 control1 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT;
2342 /* set sgmii mode (and not fiber) */
2343 control1 &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE |
2344 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET |
2345 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_MSTR_MODE);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002346 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002347 MDIO_REG_BANK_SERDES_DIGITAL,
2348 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
2349 control1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002350
2351 /* if forced speed */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002352 if (!(vars->line_speed == SPEED_AUTO_NEG)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002353 /* set speed, disable autoneg */
2354 u16 mii_control;
2355
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002356 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002357 MDIO_REG_BANK_COMBO_IEEE0,
2358 MDIO_COMBO_IEEE0_MII_CONTROL,
2359 &mii_control);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002360 mii_control &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
2361 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK|
2362 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX);
2363
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002364 switch (vars->line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002365 case SPEED_100:
2366 mii_control |=
2367 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_100;
2368 break;
2369 case SPEED_1000:
2370 mii_control |=
2371 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_1000;
2372 break;
2373 case SPEED_10:
2374 /* there is nothing to set for 10M */
2375 break;
2376 default:
2377 /* invalid speed for SGMII */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002378 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
2379 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002380 break;
2381 }
2382
2383 /* setting the full duplex */
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002384 if (phy->req_duplex == DUPLEX_FULL)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002385 mii_control |=
2386 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002387 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002388 MDIO_REG_BANK_COMBO_IEEE0,
2389 MDIO_COMBO_IEEE0_MII_CONTROL,
2390 mii_control);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002391
2392 } else { /* AN mode */
2393 /* enable and restart AN */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002394 bnx2x_restart_autoneg(phy, params, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002395 }
2396}
2397
2398
2399/*
2400 * link management
2401 */
2402
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00002403static int bnx2x_direct_parallel_detect_used(struct bnx2x_phy *phy,
2404 struct link_params *params)
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02002405{
2406 struct bnx2x *bp = params->bp;
2407 u16 pd_10g, status2_1000x;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002408 if (phy->req_line_speed != SPEED_AUTO_NEG)
2409 return 0;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002410 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002411 MDIO_REG_BANK_SERDES_DIGITAL,
2412 MDIO_SERDES_DIGITAL_A_1000X_STATUS2,
2413 &status2_1000x);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002414 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002415 MDIO_REG_BANK_SERDES_DIGITAL,
2416 MDIO_SERDES_DIGITAL_A_1000X_STATUS2,
2417 &status2_1000x);
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02002418 if (status2_1000x & MDIO_SERDES_DIGITAL_A_1000X_STATUS2_AN_DISABLED) {
2419 DP(NETIF_MSG_LINK, "1G parallel detect link on port %d\n",
2420 params->port);
2421 return 1;
2422 }
2423
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_10G_PARALLEL_DETECT,
2426 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_STATUS,
2427 &pd_10g);
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02002428
2429 if (pd_10g & MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_STATUS_PD_LINK) {
2430 DP(NETIF_MSG_LINK, "10G parallel detect link on port %d\n",
2431 params->port);
2432 return 1;
2433 }
2434 return 0;
2435}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002436
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002437static void bnx2x_flow_ctrl_resolve(struct bnx2x_phy *phy,
2438 struct link_params *params,
2439 struct link_vars *vars,
2440 u32 gp_status)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002441{
2442 struct bnx2x *bp = params->bp;
Eilon Greenstein3196a882008-08-13 15:58:49 -07002443 u16 ld_pause; /* local driver */
2444 u16 lp_pause; /* link partner */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002445 u16 pause_result;
2446
David S. Millerc0700f92008-12-16 23:53:20 -08002447 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002448
2449 /* resolve from gp_status in case of AN complete and not sgmii */
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002450 if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO)
2451 vars->flow_ctrl = phy->req_flow_ctrl;
2452 else if (phy->req_line_speed != SPEED_AUTO_NEG)
2453 vars->flow_ctrl = params->req_fc_auto_adv;
2454 else if ((gp_status & MDIO_AN_CL73_OR_37_COMPLETE) &&
2455 (!(vars->phy_flags & PHY_SGMII_FLAG))) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002456 if (bnx2x_direct_parallel_detect_used(phy, params)) {
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02002457 vars->flow_ctrl = params->req_fc_auto_adv;
2458 return;
2459 }
Yaniv Rosner7846e472009-11-05 19:18:07 +02002460 if ((gp_status &
2461 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
2462 MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) ==
2463 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
2464 MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) {
2465
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002466 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002467 MDIO_REG_BANK_CL73_IEEEB1,
2468 MDIO_CL73_IEEEB1_AN_ADV1,
2469 &ld_pause);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002470 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002471 MDIO_REG_BANK_CL73_IEEEB1,
2472 MDIO_CL73_IEEEB1_AN_LP_ADV1,
2473 &lp_pause);
Yaniv Rosner7846e472009-11-05 19:18:07 +02002474 pause_result = (ld_pause &
2475 MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK)
2476 >> 8;
2477 pause_result |= (lp_pause &
2478 MDIO_CL73_IEEEB1_AN_LP_ADV1_PAUSE_MASK)
2479 >> 10;
2480 DP(NETIF_MSG_LINK, "pause_result CL73 0x%x\n",
2481 pause_result);
2482 } else {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002483 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002484 MDIO_REG_BANK_COMBO_IEEE0,
2485 MDIO_COMBO_IEEE0_AUTO_NEG_ADV,
2486 &ld_pause);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002487 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002488 MDIO_REG_BANK_COMBO_IEEE0,
2489 MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1,
2490 &lp_pause);
Yaniv Rosner7846e472009-11-05 19:18:07 +02002491 pause_result = (ld_pause &
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002492 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>5;
Yaniv Rosner7846e472009-11-05 19:18:07 +02002493 pause_result |= (lp_pause &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002494 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7;
Yaniv Rosner7846e472009-11-05 19:18:07 +02002495 DP(NETIF_MSG_LINK, "pause_result CL37 0x%x\n",
2496 pause_result);
2497 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002498 bnx2x_pause_resolve(vars, pause_result);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002499 }
2500 DP(NETIF_MSG_LINK, "flow_ctrl 0x%x\n", vars->flow_ctrl);
2501}
2502
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002503static void bnx2x_check_fallback_to_cl37(struct bnx2x_phy *phy,
2504 struct link_params *params)
Eilon Greenstein239d6862009-08-12 08:23:04 +00002505{
2506 struct bnx2x *bp = params->bp;
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00002507 u16 rx_status, ustat_val, cl37_fsm_received;
Eilon Greenstein239d6862009-08-12 08:23:04 +00002508 DP(NETIF_MSG_LINK, "bnx2x_check_fallback_to_cl37\n");
2509 /* Step 1: Make sure signal is detected */
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_RX0,
2512 MDIO_RX0_RX_STATUS,
2513 &rx_status);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002514 if ((rx_status & MDIO_RX0_RX_STATUS_SIGDET) !=
2515 (MDIO_RX0_RX_STATUS_SIGDET)) {
2516 DP(NETIF_MSG_LINK, "Signal is not detected. Restoring CL73."
2517 "rx_status(0x80b0) = 0x%x\n", rx_status);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002518 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002519 MDIO_REG_BANK_CL73_IEEEB0,
2520 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
2521 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002522 return;
2523 }
2524 /* Step 2: Check CL73 state machine */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002525 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002526 MDIO_REG_BANK_CL73_USERB0,
2527 MDIO_CL73_USERB0_CL73_USTAT1,
2528 &ustat_val);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002529 if ((ustat_val &
2530 (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK |
2531 MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) !=
2532 (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK |
2533 MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) {
2534 DP(NETIF_MSG_LINK, "CL73 state-machine is not stable. "
2535 "ustat_val(0x8371) = 0x%x\n", ustat_val);
2536 return;
2537 }
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002538 /*
2539 * Step 3: Check CL37 Message Pages received to indicate LP
2540 * supports only CL37
2541 */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002542 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002543 MDIO_REG_BANK_REMOTE_PHY,
2544 MDIO_REMOTE_PHY_MISC_RX_STATUS,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00002545 &cl37_fsm_received);
2546 if ((cl37_fsm_received &
Eilon Greenstein239d6862009-08-12 08:23:04 +00002547 (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG |
2548 MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) !=
2549 (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG |
2550 MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) {
2551 DP(NETIF_MSG_LINK, "No CL37 FSM were received. "
2552 "misc_rx_status(0x8330) = 0x%x\n",
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00002553 cl37_fsm_received);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002554 return;
2555 }
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002556 /*
2557 * The combined cl37/cl73 fsm state information indicating that
2558 * we are connected to a device which does not support cl73, but
2559 * does support cl37 BAM. In this case we disable cl73 and
2560 * restart cl37 auto-neg
2561 */
2562
Eilon Greenstein239d6862009-08-12 08:23:04 +00002563 /* Disable CL73 */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002564 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002565 MDIO_REG_BANK_CL73_IEEEB0,
2566 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
2567 0);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002568 /* Restart CL37 autoneg */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002569 bnx2x_restart_autoneg(phy, params, 0);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002570 DP(NETIF_MSG_LINK, "Disabling CL73, and restarting CL37 autoneg\n");
2571}
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002572
2573static void bnx2x_xgxs_an_resolve(struct bnx2x_phy *phy,
2574 struct link_params *params,
2575 struct link_vars *vars,
2576 u32 gp_status)
2577{
2578 if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE)
2579 vars->link_status |=
2580 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
2581
2582 if (bnx2x_direct_parallel_detect_used(phy, params))
2583 vars->link_status |=
2584 LINK_STATUS_PARALLEL_DETECTION_USED;
2585}
2586
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00002587static int bnx2x_link_settings_status(struct bnx2x_phy *phy,
2588 struct link_params *params,
2589 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002590{
2591 struct bnx2x *bp = params->bp;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002592 u16 new_line_speed, gp_status;
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00002593 int rc = 0;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002594
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002595 /* Read gp_status */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002596 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002597 MDIO_REG_BANK_GP_STATUS,
2598 MDIO_GP_STATUS_TOP_AN_STATUS1,
2599 &gp_status);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00002600
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002601 if (phy->req_line_speed == SPEED_AUTO_NEG)
2602 vars->link_status |= LINK_STATUS_AUTO_NEGOTIATE_ENABLED;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002603 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) {
2604 DP(NETIF_MSG_LINK, "phy link up gp_status=0x%x\n",
2605 gp_status);
2606
2607 vars->phy_link_up = 1;
2608 vars->link_status |= LINK_STATUS_LINK_UP;
2609
2610 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_DUPLEX_STATUS)
2611 vars->duplex = DUPLEX_FULL;
2612 else
2613 vars->duplex = DUPLEX_HALF;
2614
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002615 if (SINGLE_MEDIA_DIRECT(params)) {
2616 bnx2x_flow_ctrl_resolve(phy, params, vars, gp_status);
2617 if (phy->req_line_speed == SPEED_AUTO_NEG)
2618 bnx2x_xgxs_an_resolve(phy, params, vars,
2619 gp_status);
2620 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002621
2622 switch (gp_status & GP_STATUS_SPEED_MASK) {
2623 case GP_STATUS_10M:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002624 new_line_speed = SPEED_10;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002625 if (vars->duplex == DUPLEX_FULL)
2626 vars->link_status |= LINK_10TFD;
2627 else
2628 vars->link_status |= LINK_10THD;
2629 break;
2630
2631 case GP_STATUS_100M:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002632 new_line_speed = SPEED_100;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002633 if (vars->duplex == DUPLEX_FULL)
2634 vars->link_status |= LINK_100TXFD;
2635 else
2636 vars->link_status |= LINK_100TXHD;
2637 break;
2638
2639 case GP_STATUS_1G:
2640 case GP_STATUS_1G_KX:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002641 new_line_speed = SPEED_1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002642 if (vars->duplex == DUPLEX_FULL)
2643 vars->link_status |= LINK_1000TFD;
2644 else
2645 vars->link_status |= LINK_1000THD;
2646 break;
2647
2648 case GP_STATUS_2_5G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002649 new_line_speed = SPEED_2500;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002650 if (vars->duplex == DUPLEX_FULL)
2651 vars->link_status |= LINK_2500TFD;
2652 else
2653 vars->link_status |= LINK_2500THD;
2654 break;
2655
2656 case GP_STATUS_5G:
2657 case GP_STATUS_6G:
2658 DP(NETIF_MSG_LINK,
2659 "link speed unsupported gp_status 0x%x\n",
2660 gp_status);
2661 return -EINVAL;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002662
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002663 case GP_STATUS_10G_KX4:
2664 case GP_STATUS_10G_HIG:
2665 case GP_STATUS_10G_CX4:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002666 new_line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002667 vars->link_status |= LINK_10GTFD;
2668 break;
2669
2670 case GP_STATUS_12G_HIG:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002671 new_line_speed = SPEED_12000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002672 vars->link_status |= LINK_12GTFD;
2673 break;
2674
2675 case GP_STATUS_12_5G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002676 new_line_speed = SPEED_12500;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002677 vars->link_status |= LINK_12_5GTFD;
2678 break;
2679
2680 case GP_STATUS_13G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002681 new_line_speed = SPEED_13000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002682 vars->link_status |= LINK_13GTFD;
2683 break;
2684
2685 case GP_STATUS_15G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002686 new_line_speed = SPEED_15000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002687 vars->link_status |= LINK_15GTFD;
2688 break;
2689
2690 case GP_STATUS_16G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002691 new_line_speed = SPEED_16000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002692 vars->link_status |= LINK_16GTFD;
2693 break;
2694
2695 default:
2696 DP(NETIF_MSG_LINK,
2697 "link speed unsupported gp_status 0x%x\n",
2698 gp_status);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002699 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002700 }
2701
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002702 vars->line_speed = new_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002703
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002704 } else { /* link_down */
2705 DP(NETIF_MSG_LINK, "phy link down\n");
2706
2707 vars->phy_link_up = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002708
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002709 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08002710 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002711 vars->mac_type = MAC_TYPE_NONE;
Eilon Greenstein239d6862009-08-12 08:23:04 +00002712
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002713 if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
2714 SINGLE_MEDIA_DIRECT(params)) {
Eilon Greenstein239d6862009-08-12 08:23:04 +00002715 /* Check signal is detected */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002716 bnx2x_check_fallback_to_cl37(phy, params);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002717 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002718 }
2719
Frans Pop2381a552010-03-24 07:57:36 +00002720 DP(NETIF_MSG_LINK, "gp_status 0x%x phy_link_up %x line_speed %x\n",
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002721 gp_status, vars->phy_link_up, vars->line_speed);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002722 DP(NETIF_MSG_LINK, "duplex %x flow_ctrl 0x%x link_status 0x%x\n",
2723 vars->duplex, vars->flow_ctrl, vars->link_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002724 return rc;
2725}
2726
Eilon Greensteined8680a2009-02-12 08:37:12 +00002727static void bnx2x_set_gmii_tx_driver(struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002728{
2729 struct bnx2x *bp = params->bp;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002730 struct bnx2x_phy *phy = &params->phy[INT_PHY];
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002731 u16 lp_up2;
2732 u16 tx_driver;
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00002733 u16 bank;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002734
2735 /* read precomp */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002736 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002737 MDIO_REG_BANK_OVER_1G,
2738 MDIO_OVER_1G_LP_UP2, &lp_up2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002739
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002740 /* bits [10:7] at lp_up2, positioned at [15:12] */
2741 lp_up2 = (((lp_up2 & MDIO_OVER_1G_LP_UP2_PREEMPHASIS_MASK) >>
2742 MDIO_OVER_1G_LP_UP2_PREEMPHASIS_SHIFT) <<
2743 MDIO_TX0_TX_DRIVER_PREEMPHASIS_SHIFT);
2744
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00002745 if (lp_up2 == 0)
2746 return;
2747
2748 for (bank = MDIO_REG_BANK_TX0; bank <= MDIO_REG_BANK_TX3;
2749 bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0)) {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002750 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002751 bank,
2752 MDIO_TX0_TX_DRIVER, &tx_driver);
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00002753
2754 /* replace tx_driver bits [15:12] */
2755 if (lp_up2 !=
2756 (tx_driver & MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK)) {
2757 tx_driver &= ~MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK;
2758 tx_driver |= lp_up2;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002759 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002760 bank,
2761 MDIO_TX0_TX_DRIVER, tx_driver);
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00002762 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002763 }
2764}
2765
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00002766static int bnx2x_emac_program(struct link_params *params,
2767 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002768{
2769 struct bnx2x *bp = params->bp;
2770 u8 port = params->port;
2771 u16 mode = 0;
2772
2773 DP(NETIF_MSG_LINK, "setting link speed & duplex\n");
2774 bnx2x_bits_dis(bp, GRCBASE_EMAC0 + port*0x400 +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002775 EMAC_REG_EMAC_MODE,
2776 (EMAC_MODE_25G_MODE |
2777 EMAC_MODE_PORT_MII_10M |
2778 EMAC_MODE_HALF_DUPLEX));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002779 switch (vars->line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002780 case SPEED_10:
2781 mode |= EMAC_MODE_PORT_MII_10M;
2782 break;
2783
2784 case SPEED_100:
2785 mode |= EMAC_MODE_PORT_MII;
2786 break;
2787
2788 case SPEED_1000:
2789 mode |= EMAC_MODE_PORT_GMII;
2790 break;
2791
2792 case SPEED_2500:
2793 mode |= (EMAC_MODE_25G_MODE | EMAC_MODE_PORT_GMII);
2794 break;
2795
2796 default:
2797 /* 10G not valid for EMAC */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002798 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
2799 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002800 return -EINVAL;
2801 }
2802
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002803 if (vars->duplex == DUPLEX_HALF)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002804 mode |= EMAC_MODE_HALF_DUPLEX;
2805 bnx2x_bits_en(bp,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002806 GRCBASE_EMAC0 + port*0x400 + EMAC_REG_EMAC_MODE,
2807 mode);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002808
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00002809 bnx2x_set_led(params, vars, LED_MODE_OPER, vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002810 return 0;
2811}
2812
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002813static void bnx2x_set_preemphasis(struct bnx2x_phy *phy,
2814 struct link_params *params)
2815{
2816
2817 u16 bank, i = 0;
2818 struct bnx2x *bp = params->bp;
2819
2820 for (bank = MDIO_REG_BANK_RX0, i = 0; bank <= MDIO_REG_BANK_RX3;
2821 bank += (MDIO_REG_BANK_RX1-MDIO_REG_BANK_RX0), i++) {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002822 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002823 bank,
2824 MDIO_RX0_RX_EQ_BOOST,
2825 phy->rx_preemphasis[i]);
2826 }
2827
2828 for (bank = MDIO_REG_BANK_TX0, i = 0; bank <= MDIO_REG_BANK_TX3;
2829 bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0), i++) {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002830 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002831 bank,
2832 MDIO_TX0_TX_DRIVER,
2833 phy->tx_preemphasis[i]);
2834 }
2835}
2836
Yaniv Rosnerec146a62011-05-31 21:29:27 +00002837static void bnx2x_xgxs_config_init(struct bnx2x_phy *phy,
2838 struct link_params *params,
2839 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002840{
2841 struct bnx2x *bp = params->bp;
2842 u8 enable_cl73 = (SINGLE_MEDIA_DIRECT(params) ||
2843 (params->loopback_mode == LOOPBACK_XGXS));
2844 if (!(vars->phy_flags & PHY_SGMII_FLAG)) {
2845 if (SINGLE_MEDIA_DIRECT(params) &&
2846 (params->feature_config_flags &
2847 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED))
2848 bnx2x_set_preemphasis(phy, params);
2849
2850 /* forced speed requested? */
2851 if (vars->line_speed != SPEED_AUTO_NEG ||
2852 (SINGLE_MEDIA_DIRECT(params) &&
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002853 params->loopback_mode == LOOPBACK_EXT)) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002854 DP(NETIF_MSG_LINK, "not SGMII, no AN\n");
2855
2856 /* disable autoneg */
2857 bnx2x_set_autoneg(phy, params, vars, 0);
2858
2859 /* program speed and duplex */
2860 bnx2x_program_serdes(phy, params, vars);
2861
2862 } else { /* AN_mode */
2863 DP(NETIF_MSG_LINK, "not SGMII, AN\n");
2864
2865 /* AN enabled */
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00002866 bnx2x_set_brcm_cl37_advertisement(phy, params);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002867
2868 /* program duplex & pause advertisement (for aneg) */
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00002869 bnx2x_set_ieee_aneg_advertisement(phy, params,
2870 vars->ieee_fc);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002871
2872 /* enable autoneg */
2873 bnx2x_set_autoneg(phy, params, vars, enable_cl73);
2874
2875 /* enable and restart AN */
2876 bnx2x_restart_autoneg(phy, params, enable_cl73);
2877 }
2878
2879 } else { /* SGMII mode */
2880 DP(NETIF_MSG_LINK, "SGMII\n");
2881
2882 bnx2x_initialize_sgmii_process(phy, params, vars);
2883 }
2884}
2885
Yaniv Rosnerec146a62011-05-31 21:29:27 +00002886static int bnx2x_prepare_xgxs(struct bnx2x_phy *phy,
2887 struct link_params *params,
2888 struct link_vars *vars)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002889{
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00002890 int rc;
Yaniv Rosnerec146a62011-05-31 21:29:27 +00002891 vars->phy_flags |= PHY_XGXS_FLAG;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002892 if ((phy->req_line_speed &&
2893 ((phy->req_line_speed == SPEED_100) ||
2894 (phy->req_line_speed == SPEED_10))) ||
2895 (!phy->req_line_speed &&
2896 (phy->speed_cap_mask >=
2897 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL) &&
2898 (phy->speed_cap_mask <
Yaniv Rosnerec146a62011-05-31 21:29:27 +00002899 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) ||
2900 (phy->type == PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT_SD))
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002901 vars->phy_flags |= PHY_SGMII_FLAG;
2902 else
2903 vars->phy_flags &= ~PHY_SGMII_FLAG;
2904
2905 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
Yaniv Rosnerec146a62011-05-31 21:29:27 +00002906 bnx2x_set_aer_mmd(params, phy);
2907 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT)
2908 bnx2x_set_master_ln(params, phy);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002909
2910 rc = bnx2x_reset_unicore(params, phy, 0);
2911 /* reset the SerDes and wait for reset bit return low */
2912 if (rc != 0)
2913 return rc;
2914
Yaniv Rosnerec146a62011-05-31 21:29:27 +00002915 bnx2x_set_aer_mmd(params, phy);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002916 /* setting the masterLn_def again after the reset */
Yaniv Rosnerec146a62011-05-31 21:29:27 +00002917 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) {
2918 bnx2x_set_master_ln(params, phy);
2919 bnx2x_set_swap_lanes(params, phy);
2920 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002921
2922 return rc;
2923}
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002924
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002925static u16 bnx2x_wait_reset_complete(struct bnx2x *bp,
Yaniv Rosner6d870c32011-01-31 04:22:20 +00002926 struct bnx2x_phy *phy,
2927 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002928{
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002929 u16 cnt, ctrl;
Lucas De Marchi25985ed2011-03-30 22:57:33 -03002930 /* Wait for soft reset to get cleared up to 1 sec */
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002931 for (cnt = 0; cnt < 1000; cnt++) {
2932 bnx2x_cl45_read(bp, phy,
2933 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, &ctrl);
2934 if (!(ctrl & (1<<15)))
2935 break;
2936 msleep(1);
2937 }
Yaniv Rosner6d870c32011-01-31 04:22:20 +00002938
2939 if (cnt == 1000)
2940 netdev_err(bp->dev, "Warning: PHY was not initialized,"
2941 " Port %d\n",
2942 params->port);
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002943 DP(NETIF_MSG_LINK, "control reg 0x%x (after %d ms)\n", ctrl, cnt);
2944 return cnt;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002945}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002946
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002947static void bnx2x_link_int_enable(struct link_params *params)
2948{
2949 u8 port = params->port;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002950 u32 mask;
2951 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002952
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002953 /* Setting the status to report on link up for either XGXS or SerDes */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002954 if (params->switch_cfg == SWITCH_CFG_10G) {
2955 mask = (NIG_MASK_XGXS0_LINK10G |
2956 NIG_MASK_XGXS0_LINK_STATUS);
2957 DP(NETIF_MSG_LINK, "enabled XGXS interrupt\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002958 if (!(SINGLE_MEDIA_DIRECT(params)) &&
2959 params->phy[INT_PHY].type !=
2960 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002961 mask |= NIG_MASK_MI_INT;
2962 DP(NETIF_MSG_LINK, "enabled external phy int\n");
2963 }
2964
2965 } else { /* SerDes */
2966 mask = NIG_MASK_SERDES0_LINK_STATUS;
2967 DP(NETIF_MSG_LINK, "enabled SerDes interrupt\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002968 if (!(SINGLE_MEDIA_DIRECT(params)) &&
2969 params->phy[INT_PHY].type !=
2970 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_NOT_CONN) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002971 mask |= NIG_MASK_MI_INT;
2972 DP(NETIF_MSG_LINK, "enabled external phy int\n");
2973 }
2974 }
2975 bnx2x_bits_en(bp,
2976 NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
2977 mask);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002978
2979 DP(NETIF_MSG_LINK, "port %x, is_xgxs %x, int_status 0x%x\n", port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002980 (params->switch_cfg == SWITCH_CFG_10G),
2981 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002982 DP(NETIF_MSG_LINK, " int_mask 0x%x, MI_INT %x, SERDES_LINK %x\n",
2983 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
2984 REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
2985 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS+port*0x3c));
2986 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
2987 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
2988 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
2989}
2990
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002991static void bnx2x_rearm_latch_signal(struct bnx2x *bp, u8 port,
2992 u8 exp_mi_int)
Eilon Greenstein2f904462009-08-12 08:22:16 +00002993{
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002994 u32 latch_status = 0;
2995
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002996 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002997 * Disable the MI INT ( external phy int ) by writing 1 to the
2998 * status register. Link down indication is high-active-signal,
2999 * so in this case we need to write the status to clear the XOR
Eilon Greenstein2f904462009-08-12 08:22:16 +00003000 */
3001 /* Read Latched signals */
3002 latch_status = REG_RD(bp,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003003 NIG_REG_LATCH_STATUS_0 + port*8);
3004 DP(NETIF_MSG_LINK, "latch_status = 0x%x\n", latch_status);
Eilon Greenstein2f904462009-08-12 08:22:16 +00003005 /* Handle only those with latched-signal=up.*/
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003006 if (exp_mi_int)
3007 bnx2x_bits_en(bp,
3008 NIG_REG_STATUS_INTERRUPT_PORT0
3009 + port*4,
3010 NIG_STATUS_EMAC0_MI_INT);
3011 else
3012 bnx2x_bits_dis(bp,
3013 NIG_REG_STATUS_INTERRUPT_PORT0
3014 + port*4,
3015 NIG_STATUS_EMAC0_MI_INT);
3016
Eilon Greenstein2f904462009-08-12 08:22:16 +00003017 if (latch_status & 1) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003018
Eilon Greenstein2f904462009-08-12 08:22:16 +00003019 /* For all latched-signal=up : Re-Arm Latch signals */
3020 REG_WR(bp, NIG_REG_LATCH_STATUS_0 + port*8,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003021 (latch_status & 0xfffe) | (latch_status & 1));
Eilon Greenstein2f904462009-08-12 08:22:16 +00003022 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003023 /* For all latched-signal=up,Write original_signal to status */
Eilon Greenstein2f904462009-08-12 08:22:16 +00003024}
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003025
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003026static void bnx2x_link_int_ack(struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003027 struct link_vars *vars, u8 is_10g)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003028{
3029 struct bnx2x *bp = params->bp;
3030 u8 port = params->port;
3031
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003032 /*
3033 * First reset all status we assume only one line will be
3034 * change at a time
3035 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003036 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003037 (NIG_STATUS_XGXS0_LINK10G |
3038 NIG_STATUS_XGXS0_LINK_STATUS |
3039 NIG_STATUS_SERDES0_LINK_STATUS));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003040 if (vars->phy_link_up) {
3041 if (is_10g) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003042 /*
3043 * Disable the 10G link interrupt by writing 1 to the
3044 * status register
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003045 */
3046 DP(NETIF_MSG_LINK, "10G XGXS phy link up\n");
3047 bnx2x_bits_en(bp,
3048 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
3049 NIG_STATUS_XGXS0_LINK10G);
3050
3051 } else if (params->switch_cfg == SWITCH_CFG_10G) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003052 /*
3053 * Disable the link interrupt by writing 1 to the
3054 * relevant lane in the status register
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003055 */
3056 u32 ser_lane = ((params->lane_config &
3057 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
3058 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
3059
Eilon Greenstein2f904462009-08-12 08:22:16 +00003060 DP(NETIF_MSG_LINK, "%d speed XGXS phy link up\n",
3061 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003062 bnx2x_bits_en(bp,
3063 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
3064 ((1 << ser_lane) <<
3065 NIG_STATUS_XGXS0_LINK_STATUS_SIZE));
3066
3067 } else { /* SerDes */
3068 DP(NETIF_MSG_LINK, "SerDes phy link up\n");
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003069 /*
3070 * Disable the link interrupt by writing 1 to the status
3071 * register
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003072 */
3073 bnx2x_bits_en(bp,
3074 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
3075 NIG_STATUS_SERDES0_LINK_STATUS);
3076 }
3077
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003078 }
3079}
3080
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00003081static int bnx2x_format_ver(u32 num, u8 *str, u16 *len)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003082{
3083 u8 *str_ptr = str;
3084 u32 mask = 0xf0000000;
3085 u8 shift = 8*4;
3086 u8 digit;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003087 u8 remove_leading_zeros = 1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003088 if (*len < 10) {
Frederik Schwarzer025dfda2008-10-16 19:02:37 +02003089 /* Need more than 10chars for this format */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003090 *str_ptr = '\0';
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003091 (*len)--;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003092 return -EINVAL;
3093 }
3094 while (shift > 0) {
3095
3096 shift -= 4;
3097 digit = ((num & mask) >> shift);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003098 if (digit == 0 && remove_leading_zeros) {
3099 mask = mask >> 4;
3100 continue;
3101 } else if (digit < 0xa)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003102 *str_ptr = digit + '0';
3103 else
3104 *str_ptr = digit - 0xa + 'a';
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003105 remove_leading_zeros = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003106 str_ptr++;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003107 (*len)--;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003108 mask = mask >> 4;
3109 if (shift == 4*4) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003110 *str_ptr = '.';
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003111 str_ptr++;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003112 (*len)--;
3113 remove_leading_zeros = 1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003114 }
3115 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003116 return 0;
3117}
3118
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003119
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00003120static int bnx2x_null_format_ver(u32 spirom_ver, u8 *str, u16 *len)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003121{
3122 str[0] = '\0';
3123 (*len)--;
3124 return 0;
3125}
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003126
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00003127int bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
3128 u8 *version, u16 len)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003129{
Julia Lawall0376d5b2009-07-19 05:26:35 +00003130 struct bnx2x *bp;
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003131 u32 spirom_ver = 0;
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00003132 int status = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003133 u8 *ver_p = version;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003134 u16 remain_len = len;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003135 if (version == NULL || params == NULL)
3136 return -EINVAL;
Julia Lawall0376d5b2009-07-19 05:26:35 +00003137 bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003138
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003139 /* Extract first external phy*/
3140 version[0] = '\0';
3141 spirom_ver = REG_RD(bp, params->phy[EXT_PHY1].ver_addr);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003142
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003143 if (params->phy[EXT_PHY1].format_fw_ver) {
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003144 status |= params->phy[EXT_PHY1].format_fw_ver(spirom_ver,
3145 ver_p,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003146 &remain_len);
3147 ver_p += (len - remain_len);
3148 }
3149 if ((params->num_phys == MAX_PHYS) &&
3150 (params->phy[EXT_PHY2].ver_addr != 0)) {
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003151 spirom_ver = REG_RD(bp, params->phy[EXT_PHY2].ver_addr);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003152 if (params->phy[EXT_PHY2].format_fw_ver) {
3153 *ver_p = '/';
3154 ver_p++;
3155 remain_len--;
3156 status |= params->phy[EXT_PHY2].format_fw_ver(
3157 spirom_ver,
3158 ver_p,
3159 &remain_len);
3160 ver_p = version + (len - remain_len);
3161 }
3162 }
3163 *ver_p = '\0';
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003164 return status;
3165}
3166
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003167static void bnx2x_set_xgxs_loopback(struct bnx2x_phy *phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003168 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003169{
3170 u8 port = params->port;
3171 struct bnx2x *bp = params->bp;
3172
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003173 if (phy->req_line_speed != SPEED_1000) {
Eilon Greenstein6378c022008-08-13 15:59:25 -07003174 u32 md_devad;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003175
3176 DP(NETIF_MSG_LINK, "XGXS 10G loopback enable\n");
3177
3178 /* change the uni_phy_addr in the nig */
3179 md_devad = REG_RD(bp, (NIG_REG_XGXS0_CTRL_MD_DEVAD +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003180 port*0x18));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003181
3182 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, 0x5);
3183
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003184 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003185 5,
3186 (MDIO_REG_BANK_AER_BLOCK +
3187 (MDIO_AER_BLOCK_AER_REG & 0xf)),
3188 0x2800);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003189
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003190 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003191 5,
3192 (MDIO_REG_BANK_CL73_IEEEB0 +
3193 (MDIO_CL73_IEEEB0_CL73_AN_CONTROL & 0xf)),
3194 0x6041);
Eilon Greenstein38582762009-01-14 06:44:16 +00003195 msleep(200);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003196 /* set aer mmd back */
Yaniv Rosnerec146a62011-05-31 21:29:27 +00003197 bnx2x_set_aer_mmd(params, phy);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003198
3199 /* and md_devad */
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003200 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, md_devad);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003201 } else {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003202 u16 mii_ctrl;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003203 DP(NETIF_MSG_LINK, "XGXS 1G loopback enable\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003204 bnx2x_cl45_read(bp, phy, 5,
3205 (MDIO_REG_BANK_COMBO_IEEE0 +
3206 (MDIO_COMBO_IEEE0_MII_CONTROL & 0xf)),
3207 &mii_ctrl);
3208 bnx2x_cl45_write(bp, phy, 5,
3209 (MDIO_REG_BANK_COMBO_IEEE0 +
3210 (MDIO_COMBO_IEEE0_MII_CONTROL & 0xf)),
3211 mii_ctrl |
3212 MDIO_COMBO_IEEO_MII_CONTROL_LOOPBACK);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003213 }
3214}
3215
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00003216int bnx2x_set_led(struct link_params *params,
3217 struct link_vars *vars, u8 mode, u32 speed)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003218{
Yaniv Rosner7846e472009-11-05 19:18:07 +02003219 u8 port = params->port;
3220 u16 hw_led_mode = params->hw_led_mode;
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00003221 int rc = 0;
3222 u8 phy_idx;
Eilon Greenstein345b5d52008-08-13 15:58:12 -07003223 u32 tmp;
3224 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Yaniv Rosner7846e472009-11-05 19:18:07 +02003225 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003226 DP(NETIF_MSG_LINK, "bnx2x_set_led: port %x, mode %d\n", port, mode);
3227 DP(NETIF_MSG_LINK, "speed 0x%x, hw_led_mode 0x%x\n",
3228 speed, hw_led_mode);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003229 /* In case */
3230 for (phy_idx = EXT_PHY1; phy_idx < MAX_PHYS; phy_idx++) {
3231 if (params->phy[phy_idx].set_link_led) {
3232 params->phy[phy_idx].set_link_led(
3233 &params->phy[phy_idx], params, mode);
3234 }
3235 }
3236
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003237 switch (mode) {
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003238 case LED_MODE_FRONT_PANEL_OFF:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003239 case LED_MODE_OFF:
3240 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 0);
3241 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003242 SHARED_HW_CFG_LED_MAC1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07003243
3244 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07003245 EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp | EMAC_LED_OVERRIDE));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003246 break;
3247
3248 case LED_MODE_OPER:
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003249 /*
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003250 * For all other phys, OPER mode is same as ON, so in case
3251 * link is down, do nothing
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003252 */
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003253 if (!vars->link_up)
3254 break;
3255 case LED_MODE_ON:
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00003256 if (((params->phy[EXT_PHY1].type ==
3257 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) ||
3258 (params->phy[EXT_PHY1].type ==
3259 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722)) &&
Yaniv Rosner1f483532011-01-18 04:33:31 +00003260 CHIP_IS_E2(bp) && params->num_phys == 2) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003261 /*
3262 * This is a work-around for E2+8727 Configurations
3263 */
Yaniv Rosner1f483532011-01-18 04:33:31 +00003264 if (mode == LED_MODE_ON ||
3265 speed == SPEED_10000){
3266 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0);
3267 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1);
3268
3269 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
3270 EMAC_WR(bp, EMAC_REG_EMAC_LED,
3271 (tmp | EMAC_LED_OVERRIDE));
3272 return rc;
3273 }
3274 } else if (SINGLE_MEDIA_DIRECT(params)) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003275 /*
3276 * This is a work-around for HW issue found when link
3277 * is up in CL73
3278 */
Yaniv Rosner7846e472009-11-05 19:18:07 +02003279 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0);
3280 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1);
3281 } else {
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003282 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, hw_led_mode);
Yaniv Rosner7846e472009-11-05 19:18:07 +02003283 }
3284
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003285 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 + port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003286 /* Set blinking rate to ~15.9Hz */
3287 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003288 LED_BLINK_RATE_VAL);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003289 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003290 port*4, 1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07003291 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003292 EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp & (~EMAC_LED_OVERRIDE)));
Eilon Greenstein345b5d52008-08-13 15:58:12 -07003293
Yaniv Rosner7846e472009-11-05 19:18:07 +02003294 if (CHIP_IS_E1(bp) &&
Eilon Greenstein34f80b02008-06-23 20:33:01 -07003295 ((speed == SPEED_2500) ||
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003296 (speed == SPEED_1000) ||
3297 (speed == SPEED_100) ||
3298 (speed == SPEED_10))) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003299 /*
3300 * On Everest 1 Ax chip versions for speeds less than
3301 * 10G LED scheme is different
3302 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003303 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003304 + port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003305 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003306 port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003307 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_TRAFFIC_P0 +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003308 port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003309 }
3310 break;
3311
3312 default:
3313 rc = -EINVAL;
3314 DP(NETIF_MSG_LINK, "bnx2x_set_led: Invalid led mode %d\n",
3315 mode);
3316 break;
3317 }
3318 return rc;
3319
3320}
3321
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003322/*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003323 * This function comes to reflect the actual link state read DIRECTLY from the
3324 * HW
3325 */
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00003326int bnx2x_test_link(struct link_params *params, struct link_vars *vars,
3327 u8 is_serdes)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003328{
3329 struct bnx2x *bp = params->bp;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003330 u16 gp_status = 0, phy_index = 0;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003331 u8 ext_phy_link_up = 0, serdes_phy_type;
3332 struct link_vars temp_vars;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003333
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003334 CL22_RD_OVER_CL45(bp, &params->phy[INT_PHY],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003335 MDIO_REG_BANK_GP_STATUS,
3336 MDIO_GP_STATUS_TOP_AN_STATUS1,
3337 &gp_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003338 /* link is up only if both local phy and external phy are up */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003339 if (!(gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS))
3340 return -ESRCH;
3341
3342 switch (params->num_phys) {
3343 case 1:
3344 /* No external PHY */
3345 return 0;
3346 case 2:
3347 ext_phy_link_up = params->phy[EXT_PHY1].read_status(
3348 &params->phy[EXT_PHY1],
3349 params, &temp_vars);
3350 break;
3351 case 3: /* Dual Media */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003352 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
3353 phy_index++) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003354 serdes_phy_type = ((params->phy[phy_index].media_type ==
3355 ETH_PHY_SFP_FIBER) ||
3356 (params->phy[phy_index].media_type ==
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00003357 ETH_PHY_XFP_FIBER) ||
3358 (params->phy[phy_index].media_type ==
3359 ETH_PHY_DA_TWINAX));
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003360
3361 if (is_serdes != serdes_phy_type)
3362 continue;
3363 if (params->phy[phy_index].read_status) {
3364 ext_phy_link_up |=
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003365 params->phy[phy_index].read_status(
3366 &params->phy[phy_index],
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003367 params, &temp_vars);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003368 }
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003369 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003370 break;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003371 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003372 if (ext_phy_link_up)
3373 return 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003374 return -ESRCH;
3375}
3376
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00003377static int bnx2x_link_initialize(struct link_params *params,
3378 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003379{
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00003380 int rc = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003381 u8 phy_index, non_ext_phy;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003382 struct bnx2x *bp = params->bp;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003383 /*
3384 * In case of external phy existence, the line speed would be the
3385 * line speed linked up by the external phy. In case it is direct
3386 * only, then the line_speed during initialization will be
3387 * equal to the req_line_speed
3388 */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003389 vars->line_speed = params->phy[INT_PHY].req_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003390
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003391 /*
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003392 * Initialize the internal phy in case this is a direct board
3393 * (no external phys), or this board has external phy which requires
3394 * to first.
3395 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003396
Yaniv Rosnerec146a62011-05-31 21:29:27 +00003397 bnx2x_prepare_xgxs(&params->phy[INT_PHY], params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003398 /* init ext phy and enable link state int */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003399 non_ext_phy = (SINGLE_MEDIA_DIRECT(params) ||
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003400 (params->loopback_mode == LOOPBACK_XGXS));
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003401
3402 if (non_ext_phy ||
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003403 (params->phy[EXT_PHY1].flags & FLAGS_INIT_XGXS_FIRST) ||
Eilon Greenstein8660d8c2009-03-02 08:01:02 +00003404 (params->loopback_mode == LOOPBACK_EXT_PHY)) {
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003405 struct bnx2x_phy *phy = &params->phy[INT_PHY];
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003406 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003407 bnx2x_set_parallel_detection(phy, params);
Yaniv Rosnerec146a62011-05-31 21:29:27 +00003408 if (params->phy[INT_PHY].config_init)
3409 params->phy[INT_PHY].config_init(phy,
3410 params,
3411 vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003412 }
3413
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003414 /* Init external phy*/
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00003415 if (non_ext_phy) {
3416 if (params->phy[INT_PHY].supported &
3417 SUPPORTED_FIBRE)
3418 vars->link_status |= LINK_STATUS_SERDES_LINK;
3419 } else {
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003420 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
3421 phy_index++) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003422 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003423 * No need to initialize second phy in case of first
3424 * phy only selection. In case of second phy, we do
3425 * need to initialize the first phy, since they are
3426 * connected.
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003427 */
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00003428 if (params->phy[phy_index].supported &
3429 SUPPORTED_FIBRE)
3430 vars->link_status |= LINK_STATUS_SERDES_LINK;
3431
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003432 if (phy_index == EXT_PHY2 &&
3433 (bnx2x_phy_selection(params) ==
3434 PORT_HW_CFG_PHY_SELECTION_FIRST_PHY)) {
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00003435 DP(NETIF_MSG_LINK, "Not initializing"
3436 " second phy\n");
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003437 continue;
3438 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003439 params->phy[phy_index].config_init(
3440 &params->phy[phy_index],
3441 params, vars);
3442 }
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00003443 }
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00003444 /* Reset the interrupt indication after phy was initialized */
3445 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 +
3446 params->port*4,
3447 (NIG_STATUS_XGXS0_LINK10G |
3448 NIG_STATUS_XGXS0_LINK_STATUS |
3449 NIG_STATUS_SERDES0_LINK_STATUS |
3450 NIG_MASK_MI_INT));
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00003451 bnx2x_update_mng(params, vars->link_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003452 return rc;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003453}
3454
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003455static void bnx2x_int_link_reset(struct bnx2x_phy *phy,
3456 struct link_params *params)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003457{
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003458 /* reset the SerDes/XGXS */
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003459 REG_WR(params->bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
3460 (0x1ff << (params->port*16)));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003461}
3462
3463static void bnx2x_common_ext_link_reset(struct bnx2x_phy *phy,
3464 struct link_params *params)
3465{
3466 struct bnx2x *bp = params->bp;
3467 u8 gpio_port;
3468 /* HW reset */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00003469 if (CHIP_IS_E2(bp))
3470 gpio_port = BP_PATH(bp);
3471 else
3472 gpio_port = params->port;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003473 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003474 MISC_REGISTERS_GPIO_OUTPUT_LOW,
3475 gpio_port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003476 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003477 MISC_REGISTERS_GPIO_OUTPUT_LOW,
3478 gpio_port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003479 DP(NETIF_MSG_LINK, "reset external PHY\n");
3480}
3481
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00003482static int bnx2x_update_link_down(struct link_params *params,
3483 struct link_vars *vars)
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003484{
3485 struct bnx2x *bp = params->bp;
3486 u8 port = params->port;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00003487
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003488 DP(NETIF_MSG_LINK, "Port %x: Link is down\n", port);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003489 bnx2x_set_led(params, vars, LED_MODE_OFF, 0);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003490
3491 /* indicate no mac active */
3492 vars->mac_type = MAC_TYPE_NONE;
3493
3494 /* update shared memory */
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00003495 vars->link_status &= ~(LINK_STATUS_SPEED_AND_DUPLEX_MASK |
3496 LINK_STATUS_LINK_UP |
3497 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE |
3498 LINK_STATUS_RX_FLOW_CONTROL_FLAG_MASK |
3499 LINK_STATUS_TX_FLOW_CONTROL_FLAG_MASK |
3500 LINK_STATUS_PARALLEL_DETECTION_FLAG_MASK);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003501 vars->line_speed = 0;
3502 bnx2x_update_mng(params, vars->link_status);
3503
3504 /* activate nig drain */
3505 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
3506
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00003507 /* disable emac */
3508 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
3509
3510 msleep(10);
3511
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003512 /* reset BigMac */
3513 bnx2x_bmac_rx_disable(bp, params->port);
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003514 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
3515 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003516 return 0;
3517}
3518
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00003519static int bnx2x_update_link_up(struct link_params *params,
3520 struct link_vars *vars,
3521 u8 link_10g)
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003522{
3523 struct bnx2x *bp = params->bp;
3524 u8 port = params->port;
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00003525 int rc = 0;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00003526
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003527 vars->link_status |= LINK_STATUS_LINK_UP;
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003528
Yaniv Rosner7aa07112010-09-07 11:41:01 +00003529 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
3530 vars->link_status |=
3531 LINK_STATUS_TX_FLOW_CONTROL_ENABLED;
3532
3533 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
3534 vars->link_status |=
3535 LINK_STATUS_RX_FLOW_CONTROL_ENABLED;
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003536
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003537 if (link_10g) {
3538 bnx2x_bmac_enable(params, vars, 0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003539 bnx2x_set_led(params, vars,
3540 LED_MODE_OPER, SPEED_10000);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003541 } else {
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003542 rc = bnx2x_emac_program(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003543
Yaniv Rosner0c786f02009-11-05 19:18:32 +02003544 bnx2x_emac_enable(params, vars, 0);
3545
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003546 /* AN complete? */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003547 if ((vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE)
3548 && (!(vars->phy_flags & PHY_SGMII_FLAG)) &&
3549 SINGLE_MEDIA_DIRECT(params))
3550 bnx2x_set_gmii_tx_driver(params);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003551 }
3552
3553 /* PBF - link up */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00003554 if (!(CHIP_IS_E2(bp)))
3555 rc |= bnx2x_pbf_update(params, vars->flow_ctrl,
3556 vars->line_speed);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003557
3558 /* disable drain */
3559 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 0);
3560
3561 /* update shared memory */
3562 bnx2x_update_mng(params, vars->link_status);
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00003563 msleep(20);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003564 return rc;
3565}
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003566/*
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003567 * The bnx2x_link_update function should be called upon link
3568 * interrupt.
3569 * Link is considered up as follows:
3570 * - DIRECT_SINGLE_MEDIA - Only XGXS link (internal link) needs
3571 * to be up
3572 * - SINGLE_MEDIA - The link between the 577xx and the external
3573 * phy (XGXS) need to up as well as the external link of the
3574 * phy (PHY_EXT1)
3575 * - DUAL_MEDIA - The link between the 577xx and the first
3576 * external phy needs to be up, and at least one of the 2
3577 * external phy link must be up.
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003578 */
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00003579int bnx2x_link_update(struct link_params *params, struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003580{
3581 struct bnx2x *bp = params->bp;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003582 struct link_vars phy_vars[MAX_PHYS];
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003583 u8 port = params->port;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003584 u8 link_10g, phy_index;
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00003585 u8 ext_phy_link_up = 0, cur_link_up;
3586 int rc = 0;
Eilon Greenstein2f904462009-08-12 08:22:16 +00003587 u8 is_mi_int = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003588 u16 ext_phy_line_speed = 0, prev_line_speed = vars->line_speed;
3589 u8 active_external_phy = INT_PHY;
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00003590
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003591 for (phy_index = INT_PHY; phy_index < params->num_phys;
3592 phy_index++) {
3593 phy_vars[phy_index].flow_ctrl = 0;
3594 phy_vars[phy_index].link_status = 0;
3595 phy_vars[phy_index].line_speed = 0;
3596 phy_vars[phy_index].duplex = DUPLEX_FULL;
3597 phy_vars[phy_index].phy_link_up = 0;
3598 phy_vars[phy_index].link_up = 0;
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00003599 phy_vars[phy_index].fault_detected = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003600 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003601
3602 DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n",
Eilon Greenstein2f904462009-08-12 08:22:16 +00003603 port, (vars->phy_flags & PHY_XGXS_FLAG),
3604 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003605
Eilon Greenstein2f904462009-08-12 08:22:16 +00003606 is_mi_int = (u8)(REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003607 port*0x18) > 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003608 DP(NETIF_MSG_LINK, "int_mask 0x%x MI_INT %x, SERDES_LINK %x\n",
Eilon Greenstein2f904462009-08-12 08:22:16 +00003609 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
3610 is_mi_int,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003611 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003612
3613 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
3614 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
3615 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
3616
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00003617 /* disable emac */
3618 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
3619
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003620 /*
3621 * Step 1:
3622 * Check external link change only for external phys, and apply
3623 * priority selection between them in case the link on both phys
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00003624 * is up. Note that instead of the common vars, a temporary
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003625 * vars argument is used since each phy may have different link/
3626 * speed/duplex result
3627 */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003628 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
3629 phy_index++) {
3630 struct bnx2x_phy *phy = &params->phy[phy_index];
3631 if (!phy->read_status)
3632 continue;
3633 /* Read link status and params of this ext phy */
3634 cur_link_up = phy->read_status(phy, params,
3635 &phy_vars[phy_index]);
3636 if (cur_link_up) {
3637 DP(NETIF_MSG_LINK, "phy in index %d link is up\n",
3638 phy_index);
3639 } else {
3640 DP(NETIF_MSG_LINK, "phy in index %d link is down\n",
3641 phy_index);
3642 continue;
3643 }
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003644
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003645 if (!ext_phy_link_up) {
3646 ext_phy_link_up = 1;
3647 active_external_phy = phy_index;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003648 } else {
3649 switch (bnx2x_phy_selection(params)) {
3650 case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT:
3651 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003652 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003653 * In this option, the first PHY makes sure to pass the
3654 * traffic through itself only.
3655 * Its not clear how to reset the link on the second phy
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003656 */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003657 active_external_phy = EXT_PHY1;
3658 break;
3659 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003660 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003661 * In this option, the first PHY makes sure to pass the
3662 * traffic through the second PHY.
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003663 */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003664 active_external_phy = EXT_PHY2;
3665 break;
3666 default:
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003667 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003668 * Link indication on both PHYs with the following cases
3669 * is invalid:
3670 * - FIRST_PHY means that second phy wasn't initialized,
3671 * hence its link is expected to be down
3672 * - SECOND_PHY means that first phy should not be able
3673 * to link up by itself (using configuration)
3674 * - DEFAULT should be overriden during initialiazation
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003675 */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003676 DP(NETIF_MSG_LINK, "Invalid link indication"
3677 "mpc=0x%x. DISABLING LINK !!!\n",
3678 params->multi_phy_config);
3679 ext_phy_link_up = 0;
3680 break;
3681 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003682 }
3683 }
3684 prev_line_speed = vars->line_speed;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003685 /*
3686 * Step 2:
3687 * Read the status of the internal phy. In case of
3688 * DIRECT_SINGLE_MEDIA board, this link is the external link,
3689 * otherwise this is the link between the 577xx and the first
3690 * external phy
3691 */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003692 if (params->phy[INT_PHY].read_status)
3693 params->phy[INT_PHY].read_status(
3694 &params->phy[INT_PHY],
3695 params, vars);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003696 /*
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003697 * The INT_PHY flow control reside in the vars. This include the
3698 * case where the speed or flow control are not set to AUTO.
3699 * Otherwise, the active external phy flow control result is set
3700 * to the vars. The ext_phy_line_speed is needed to check if the
3701 * speed is different between the internal phy and external phy.
3702 * This case may be result of intermediate link speed change.
3703 */
3704 if (active_external_phy > INT_PHY) {
3705 vars->flow_ctrl = phy_vars[active_external_phy].flow_ctrl;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003706 /*
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003707 * Link speed is taken from the XGXS. AN and FC result from
3708 * the external phy.
3709 */
3710 vars->link_status |= phy_vars[active_external_phy].link_status;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003711
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003712 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003713 * if active_external_phy is first PHY and link is up - disable
3714 * disable TX on second external PHY
3715 */
3716 if (active_external_phy == EXT_PHY1) {
3717 if (params->phy[EXT_PHY2].phy_specific_func) {
3718 DP(NETIF_MSG_LINK, "Disabling TX on"
3719 " EXT_PHY2\n");
3720 params->phy[EXT_PHY2].phy_specific_func(
3721 &params->phy[EXT_PHY2],
3722 params, DISABLE_TX);
3723 }
3724 }
3725
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003726 ext_phy_line_speed = phy_vars[active_external_phy].line_speed;
3727 vars->duplex = phy_vars[active_external_phy].duplex;
3728 if (params->phy[active_external_phy].supported &
3729 SUPPORTED_FIBRE)
3730 vars->link_status |= LINK_STATUS_SERDES_LINK;
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00003731 else
3732 vars->link_status &= ~LINK_STATUS_SERDES_LINK;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003733 DP(NETIF_MSG_LINK, "Active external phy selected: %x\n",
3734 active_external_phy);
3735 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003736
3737 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
3738 phy_index++) {
3739 if (params->phy[phy_index].flags &
3740 FLAGS_REARM_LATCH_SIGNAL) {
3741 bnx2x_rearm_latch_signal(bp, port,
3742 phy_index ==
3743 active_external_phy);
3744 break;
3745 }
3746 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003747 DP(NETIF_MSG_LINK, "vars->flow_ctrl = 0x%x, vars->link_status = 0x%x,"
3748 " ext_phy_line_speed = %d\n", vars->flow_ctrl,
3749 vars->link_status, ext_phy_line_speed);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003750 /*
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003751 * Upon link speed change set the NIG into drain mode. Comes to
3752 * deals with possible FIFO glitch due to clk change when speed
3753 * is decreased without link down indicator
3754 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003755
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003756 if (vars->phy_link_up) {
3757 if (!(SINGLE_MEDIA_DIRECT(params)) && ext_phy_link_up &&
3758 (ext_phy_line_speed != vars->line_speed)) {
3759 DP(NETIF_MSG_LINK, "Internal link speed %d is"
3760 " different than the external"
3761 " link speed %d\n", vars->line_speed,
3762 ext_phy_line_speed);
3763 vars->phy_link_up = 0;
3764 } else if (prev_line_speed != vars->line_speed) {
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003765 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4,
3766 0);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003767 msleep(1);
3768 }
3769 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003770
3771 /* anything 10 and over uses the bmac */
3772 link_10g = ((vars->line_speed == SPEED_10000) ||
3773 (vars->line_speed == SPEED_12000) ||
3774 (vars->line_speed == SPEED_12500) ||
3775 (vars->line_speed == SPEED_13000) ||
3776 (vars->line_speed == SPEED_15000) ||
3777 (vars->line_speed == SPEED_16000));
3778
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003779 bnx2x_link_int_ack(params, vars, link_10g);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003780
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003781 /*
3782 * In case external phy link is up, and internal link is down
3783 * (not initialized yet probably after link initialization, it
3784 * needs to be initialized.
3785 * Note that after link down-up as result of cable plug, the xgxs
3786 * link would probably become up again without the need
3787 * initialize it
3788 */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003789 if (!(SINGLE_MEDIA_DIRECT(params))) {
3790 DP(NETIF_MSG_LINK, "ext_phy_link_up = %d, int_link_up = %d,"
3791 " init_preceding = %d\n", ext_phy_link_up,
3792 vars->phy_link_up,
3793 params->phy[EXT_PHY1].flags &
3794 FLAGS_INIT_XGXS_FIRST);
3795 if (!(params->phy[EXT_PHY1].flags &
3796 FLAGS_INIT_XGXS_FIRST)
3797 && ext_phy_link_up && !vars->phy_link_up) {
3798 vars->line_speed = ext_phy_line_speed;
3799 if (vars->line_speed < SPEED_1000)
3800 vars->phy_flags |= PHY_SGMII_FLAG;
3801 else
3802 vars->phy_flags &= ~PHY_SGMII_FLAG;
Yaniv Rosnerec146a62011-05-31 21:29:27 +00003803
3804 if (params->phy[INT_PHY].config_init)
3805 params->phy[INT_PHY].config_init(
3806 &params->phy[INT_PHY], params,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003807 vars);
3808 }
3809 }
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003810 /*
3811 * Link is up only if both local phy and external phy (in case of
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00003812 * non-direct board) are up and no fault detected on active PHY.
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003813 */
3814 vars->link_up = (vars->phy_link_up &&
3815 (ext_phy_link_up ||
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00003816 SINGLE_MEDIA_DIRECT(params)) &&
3817 (phy_vars[active_external_phy].fault_detected == 0));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003818
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003819 if (vars->link_up)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003820 rc = bnx2x_update_link_up(params, vars, link_10g);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003821 else
3822 rc = bnx2x_update_link_down(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003823
3824 return rc;
3825}
3826
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003827
3828/*****************************************************************************/
3829/* External Phy section */
3830/*****************************************************************************/
3831void bnx2x_ext_phy_hw_reset(struct bnx2x *bp, u8 port)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003832{
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003833 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003834 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003835 msleep(1);
3836 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003837 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003838}
3839
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003840static void bnx2x_save_spirom_version(struct bnx2x *bp, u8 port,
3841 u32 spirom_ver, u32 ver_addr)
3842{
3843 DP(NETIF_MSG_LINK, "FW version 0x%x:0x%x for port %d\n",
3844 (u16)(spirom_ver>>16), (u16)spirom_ver, port);
3845
3846 if (ver_addr)
3847 REG_WR(bp, ver_addr, spirom_ver);
3848}
3849
3850static void bnx2x_save_bcm_spirom_ver(struct bnx2x *bp,
3851 struct bnx2x_phy *phy,
3852 u8 port)
3853{
3854 u16 fw_ver1, fw_ver2;
3855
3856 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003857 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003858 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003859 MDIO_PMA_REG_ROM_VER2, &fw_ver2);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003860 bnx2x_save_spirom_version(bp, port, (u32)(fw_ver1<<16 | fw_ver2),
3861 phy->ver_addr);
3862}
3863
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003864static void bnx2x_ext_phy_10G_an_resolve(struct bnx2x *bp,
3865 struct bnx2x_phy *phy,
3866 struct link_vars *vars)
3867{
3868 u16 val;
3869 bnx2x_cl45_read(bp, phy,
3870 MDIO_AN_DEVAD,
3871 MDIO_AN_REG_STATUS, &val);
3872 bnx2x_cl45_read(bp, phy,
3873 MDIO_AN_DEVAD,
3874 MDIO_AN_REG_STATUS, &val);
3875 if (val & (1<<5))
3876 vars->link_status |= LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
3877 if ((val & (1<<0)) == 0)
3878 vars->link_status |= LINK_STATUS_PARALLEL_DETECTION_USED;
3879}
3880
3881/******************************************************************/
3882/* common BCM8073/BCM8727 PHY SECTION */
3883/******************************************************************/
3884static void bnx2x_8073_resolve_fc(struct bnx2x_phy *phy,
3885 struct link_params *params,
3886 struct link_vars *vars)
3887{
3888 struct bnx2x *bp = params->bp;
3889 if (phy->req_line_speed == SPEED_10 ||
3890 phy->req_line_speed == SPEED_100) {
3891 vars->flow_ctrl = phy->req_flow_ctrl;
3892 return;
3893 }
3894
3895 if (bnx2x_ext_phy_resolve_fc(phy, params, vars) &&
3896 (vars->flow_ctrl == BNX2X_FLOW_CTRL_NONE)) {
3897 u16 pause_result;
3898 u16 ld_pause; /* local */
3899 u16 lp_pause; /* link partner */
3900 bnx2x_cl45_read(bp, phy,
3901 MDIO_AN_DEVAD,
3902 MDIO_AN_REG_CL37_FC_LD, &ld_pause);
3903
3904 bnx2x_cl45_read(bp, phy,
3905 MDIO_AN_DEVAD,
3906 MDIO_AN_REG_CL37_FC_LP, &lp_pause);
3907 pause_result = (ld_pause &
3908 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 5;
3909 pause_result |= (lp_pause &
3910 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 7;
3911
3912 bnx2x_pause_resolve(vars, pause_result);
3913 DP(NETIF_MSG_LINK, "Ext PHY CL37 pause result 0x%x\n",
3914 pause_result);
3915 }
3916}
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00003917static int bnx2x_8073_8727_external_rom_boot(struct bnx2x *bp,
3918 struct bnx2x_phy *phy,
3919 u8 port)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003920{
Yaniv Rosner5c99274b2011-01-18 04:33:36 +00003921 u32 count = 0;
3922 u16 fw_ver1, fw_msgout;
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00003923 int rc = 0;
Yaniv Rosner5c99274b2011-01-18 04:33:36 +00003924
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003925 /* Boot port from external ROM */
3926 /* EDC grst */
3927 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003928 MDIO_PMA_DEVAD,
3929 MDIO_PMA_REG_GEN_CTRL,
3930 0x0001);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003931
3932 /* ucode reboot and rst */
3933 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003934 MDIO_PMA_DEVAD,
3935 MDIO_PMA_REG_GEN_CTRL,
3936 0x008c);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003937
3938 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003939 MDIO_PMA_DEVAD,
3940 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003941
3942 /* Reset internal microprocessor */
3943 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003944 MDIO_PMA_DEVAD,
3945 MDIO_PMA_REG_GEN_CTRL,
3946 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003947
3948 /* Release srst bit */
3949 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003950 MDIO_PMA_DEVAD,
3951 MDIO_PMA_REG_GEN_CTRL,
3952 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003953
Yaniv Rosner5c99274b2011-01-18 04:33:36 +00003954 /* Delay 100ms per the PHY specifications */
3955 msleep(100);
3956
3957 /* 8073 sometimes taking longer to download */
3958 do {
3959 count++;
3960 if (count > 300) {
3961 DP(NETIF_MSG_LINK,
3962 "bnx2x_8073_8727_external_rom_boot port %x:"
3963 "Download failed. fw version = 0x%x\n",
3964 port, fw_ver1);
3965 rc = -EINVAL;
3966 break;
3967 }
3968
3969 bnx2x_cl45_read(bp, phy,
3970 MDIO_PMA_DEVAD,
3971 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
3972 bnx2x_cl45_read(bp, phy,
3973 MDIO_PMA_DEVAD,
3974 MDIO_PMA_REG_M8051_MSGOUT_REG, &fw_msgout);
3975
3976 msleep(1);
3977 } while (fw_ver1 == 0 || fw_ver1 == 0x4321 ||
3978 ((fw_msgout & 0xff) != 0x03 && (phy->type ==
3979 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073)));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003980
3981 /* Clear ser_boot_ctl bit */
3982 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003983 MDIO_PMA_DEVAD,
3984 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003985 bnx2x_save_bcm_spirom_ver(bp, phy, port);
Yaniv Rosner5c99274b2011-01-18 04:33:36 +00003986
3987 DP(NETIF_MSG_LINK,
3988 "bnx2x_8073_8727_external_rom_boot port %x:"
3989 "Download complete. fw version = 0x%x\n",
3990 port, fw_ver1);
3991
3992 return rc;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003993}
3994
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003995/******************************************************************/
3996/* BCM8073 PHY SECTION */
3997/******************************************************************/
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00003998static int bnx2x_8073_is_snr_needed(struct bnx2x *bp, struct bnx2x_phy *phy)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003999{
4000 /* This is only required for 8073A1, version 102 only */
4001 u16 val;
4002
4003 /* Read 8073 HW revision*/
4004 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004005 MDIO_PMA_DEVAD,
4006 MDIO_PMA_REG_8073_CHIP_REV, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004007
4008 if (val != 1) {
4009 /* No need to workaround in 8073 A1 */
4010 return 0;
4011 }
4012
4013 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004014 MDIO_PMA_DEVAD,
4015 MDIO_PMA_REG_ROM_VER2, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004016
4017 /* SNR should be applied only for version 0x102 */
4018 if (val != 0x102)
4019 return 0;
4020
4021 return 1;
4022}
4023
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00004024static int bnx2x_8073_xaui_wa(struct bnx2x *bp, struct bnx2x_phy *phy)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004025{
4026 u16 val, cnt, cnt1 ;
4027
4028 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004029 MDIO_PMA_DEVAD,
4030 MDIO_PMA_REG_8073_CHIP_REV, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004031
4032 if (val > 0) {
4033 /* No need to workaround in 8073 A1 */
4034 return 0;
4035 }
4036 /* XAUI workaround in 8073 A0: */
4037
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004038 /*
4039 * After loading the boot ROM and restarting Autoneg, poll
4040 * Dev1, Reg $C820:
4041 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004042
4043 for (cnt = 0; cnt < 1000; cnt++) {
4044 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004045 MDIO_PMA_DEVAD,
4046 MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
4047 &val);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004048 /*
4049 * If bit [14] = 0 or bit [13] = 0, continue on with
4050 * system initialization (XAUI work-around not required, as
4051 * these bits indicate 2.5G or 1G link up).
4052 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004053 if (!(val & (1<<14)) || !(val & (1<<13))) {
4054 DP(NETIF_MSG_LINK, "XAUI work-around not required\n");
4055 return 0;
4056 } else if (!(val & (1<<15))) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004057 DP(NETIF_MSG_LINK, "bit 15 went off\n");
4058 /*
4059 * If bit 15 is 0, then poll Dev1, Reg $C841 until it's
4060 * MSB (bit15) goes to 1 (indicating that the XAUI
4061 * workaround has completed), then continue on with
4062 * system initialization.
4063 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004064 for (cnt1 = 0; cnt1 < 1000; cnt1++) {
4065 bnx2x_cl45_read(bp, phy,
4066 MDIO_PMA_DEVAD,
4067 MDIO_PMA_REG_8073_XAUI_WA, &val);
4068 if (val & (1<<15)) {
4069 DP(NETIF_MSG_LINK,
4070 "XAUI workaround has completed\n");
4071 return 0;
4072 }
4073 msleep(3);
4074 }
4075 break;
4076 }
4077 msleep(3);
4078 }
4079 DP(NETIF_MSG_LINK, "Warning: XAUI work-around timeout !!!\n");
4080 return -EINVAL;
4081}
4082
4083static void bnx2x_807x_force_10G(struct bnx2x *bp, struct bnx2x_phy *phy)
4084{
4085 /* Force KR or KX */
4086 bnx2x_cl45_write(bp, phy,
4087 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x2040);
4088 bnx2x_cl45_write(bp, phy,
4089 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0x000b);
4090 bnx2x_cl45_write(bp, phy,
4091 MDIO_PMA_DEVAD, MDIO_PMA_REG_BCM_CTRL, 0x0000);
4092 bnx2x_cl45_write(bp, phy,
4093 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x0000);
4094}
4095
4096static void bnx2x_8073_set_pause_cl37(struct link_params *params,
4097 struct bnx2x_phy *phy,
4098 struct link_vars *vars)
4099{
4100 u16 cl37_val;
4101 struct bnx2x *bp = params->bp;
4102 bnx2x_cl45_read(bp, phy,
4103 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, &cl37_val);
4104
4105 cl37_val &= ~MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
4106 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
4107 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
4108 if ((vars->ieee_fc &
4109 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) ==
4110 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) {
4111 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC;
4112 }
4113 if ((vars->ieee_fc &
4114 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
4115 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
4116 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
4117 }
4118 if ((vars->ieee_fc &
4119 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
4120 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
4121 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
4122 }
4123 DP(NETIF_MSG_LINK,
4124 "Ext phy AN advertize cl37 0x%x\n", cl37_val);
4125
4126 bnx2x_cl45_write(bp, phy,
4127 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, cl37_val);
4128 msleep(500);
4129}
4130
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00004131static int bnx2x_8073_config_init(struct bnx2x_phy *phy,
4132 struct link_params *params,
4133 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004134{
4135 struct bnx2x *bp = params->bp;
4136 u16 val = 0, tmp1;
4137 u8 gpio_port;
4138 DP(NETIF_MSG_LINK, "Init 8073\n");
4139
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00004140 if (CHIP_IS_E2(bp))
4141 gpio_port = BP_PATH(bp);
4142 else
4143 gpio_port = params->port;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004144 /* Restore normal power mode*/
4145 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004146 MISC_REGISTERS_GPIO_OUTPUT_HIGH, gpio_port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004147
4148 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004149 MISC_REGISTERS_GPIO_OUTPUT_HIGH, gpio_port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004150
4151 /* enable LASI */
4152 bnx2x_cl45_write(bp, phy,
4153 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL, (1<<2));
4154 bnx2x_cl45_write(bp, phy,
4155 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x0004);
4156
4157 bnx2x_8073_set_pause_cl37(params, phy, vars);
4158
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004159 bnx2x_cl45_read(bp, phy,
4160 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &tmp1);
4161
4162 bnx2x_cl45_read(bp, phy,
4163 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &tmp1);
4164
4165 DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1): 0x%x\n", tmp1);
4166
Yaniv Rosner74d7a112011-01-18 04:33:18 +00004167 /* Swap polarity if required - Must be done only in non-1G mode */
4168 if (params->lane_config & PORT_HW_CFG_SWAP_PHY_POLARITY_ENABLED) {
4169 /* Configure the 8073 to swap _P and _N of the KR lines */
4170 DP(NETIF_MSG_LINK, "Swapping polarity for the 8073\n");
4171 /* 10G Rx/Tx and 1G Tx signal polarity swap */
4172 bnx2x_cl45_read(bp, phy,
4173 MDIO_PMA_DEVAD,
4174 MDIO_PMA_REG_8073_OPT_DIGITAL_CTRL, &val);
4175 bnx2x_cl45_write(bp, phy,
4176 MDIO_PMA_DEVAD,
4177 MDIO_PMA_REG_8073_OPT_DIGITAL_CTRL,
4178 (val | (3<<9)));
4179 }
4180
4181
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004182 /* Enable CL37 BAM */
Yaniv Rosner121839b2010-11-01 05:32:38 +00004183 if (REG_RD(bp, params->shmem_base +
4184 offsetof(struct shmem_region, dev_info.
4185 port_hw_config[params->port].default_cfg)) &
4186 PORT_HW_CFG_ENABLE_BAM_ON_KR_ENABLED) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004187
Yaniv Rosner121839b2010-11-01 05:32:38 +00004188 bnx2x_cl45_read(bp, phy,
4189 MDIO_AN_DEVAD,
4190 MDIO_AN_REG_8073_BAM, &val);
4191 bnx2x_cl45_write(bp, phy,
4192 MDIO_AN_DEVAD,
4193 MDIO_AN_REG_8073_BAM, val | 1);
4194 DP(NETIF_MSG_LINK, "Enable CL37 BAM on KR\n");
4195 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004196 if (params->loopback_mode == LOOPBACK_EXT) {
4197 bnx2x_807x_force_10G(bp, phy);
4198 DP(NETIF_MSG_LINK, "Forced speed 10G on 807X\n");
4199 return 0;
4200 } else {
4201 bnx2x_cl45_write(bp, phy,
4202 MDIO_PMA_DEVAD, MDIO_PMA_REG_BCM_CTRL, 0x0002);
4203 }
4204 if (phy->req_line_speed != SPEED_AUTO_NEG) {
4205 if (phy->req_line_speed == SPEED_10000) {
4206 val = (1<<7);
4207 } else if (phy->req_line_speed == SPEED_2500) {
4208 val = (1<<5);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004209 /*
4210 * Note that 2.5G works only when used with 1G
Lucas De Marchi25985ed2011-03-30 22:57:33 -03004211 * advertisement
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004212 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004213 } else
4214 val = (1<<5);
4215 } else {
4216 val = 0;
4217 if (phy->speed_cap_mask &
4218 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
4219 val |= (1<<7);
4220
Lucas De Marchi25985ed2011-03-30 22:57:33 -03004221 /* Note that 2.5G works only when used with 1G advertisement */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004222 if (phy->speed_cap_mask &
4223 (PORT_HW_CFG_SPEED_CAPABILITY_D0_1G |
4224 PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G))
4225 val |= (1<<5);
4226 DP(NETIF_MSG_LINK, "807x autoneg val = 0x%x\n", val);
4227 }
4228
4229 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV, val);
4230 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_8073_2_5G, &tmp1);
4231
4232 if (((phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G) &&
4233 (phy->req_line_speed == SPEED_AUTO_NEG)) ||
4234 (phy->req_line_speed == SPEED_2500)) {
4235 u16 phy_ver;
4236 /* Allow 2.5G for A1 and above */
4237 bnx2x_cl45_read(bp, phy,
4238 MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_CHIP_REV,
4239 &phy_ver);
4240 DP(NETIF_MSG_LINK, "Add 2.5G\n");
4241 if (phy_ver > 0)
4242 tmp1 |= 1;
4243 else
4244 tmp1 &= 0xfffe;
4245 } else {
4246 DP(NETIF_MSG_LINK, "Disable 2.5G\n");
4247 tmp1 &= 0xfffe;
4248 }
4249
4250 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_8073_2_5G, tmp1);
4251 /* Add support for CL37 (passive mode) II */
4252
4253 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, &tmp1);
4254 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD,
4255 (tmp1 | ((phy->req_duplex == DUPLEX_FULL) ?
4256 0x20 : 0x40)));
4257
4258 /* Add support for CL37 (passive mode) III */
4259 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
4260
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004261 /*
4262 * The SNR will improve about 2db by changing BW and FEE main
4263 * tap. Rest commands are executed after link is up
4264 * Change FFE main cursor to 5 in EDC register
4265 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004266 if (bnx2x_8073_is_snr_needed(bp, phy))
4267 bnx2x_cl45_write(bp, phy,
4268 MDIO_PMA_DEVAD, MDIO_PMA_REG_EDC_FFE_MAIN,
4269 0xFB0C);
4270
4271 /* Enable FEC (Forware Error Correction) Request in the AN */
4272 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV2, &tmp1);
4273 tmp1 |= (1<<15);
4274 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV2, tmp1);
4275
4276 bnx2x_ext_phy_set_pause(params, phy, vars);
4277
4278 /* Restart autoneg */
4279 msleep(500);
4280 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
4281 DP(NETIF_MSG_LINK, "807x Autoneg Restart: Advertise 1G=%x, 10G=%x\n",
4282 ((val & (1<<5)) > 0), ((val & (1<<7)) > 0));
4283 return 0;
4284}
4285
4286static u8 bnx2x_8073_read_status(struct bnx2x_phy *phy,
4287 struct link_params *params,
4288 struct link_vars *vars)
4289{
4290 struct bnx2x *bp = params->bp;
4291 u8 link_up = 0;
4292 u16 val1, val2;
4293 u16 link_status = 0;
4294 u16 an1000_status = 0;
4295
4296 bnx2x_cl45_read(bp, phy,
4297 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
4298
4299 DP(NETIF_MSG_LINK, "8703 LASI status 0x%x\n", val1);
4300
4301 /* clear the interrupt LASI status register */
4302 bnx2x_cl45_read(bp, phy,
4303 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val2);
4304 bnx2x_cl45_read(bp, phy,
4305 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val1);
4306 DP(NETIF_MSG_LINK, "807x PCS status 0x%x->0x%x\n", val2, val1);
4307 /* Clear MSG-OUT */
4308 bnx2x_cl45_read(bp, phy,
4309 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &val1);
4310
4311 /* Check the LASI */
4312 bnx2x_cl45_read(bp, phy,
4313 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &val2);
4314
4315 DP(NETIF_MSG_LINK, "KR 0x9003 0x%x\n", val2);
4316
4317 /* Check the link status */
4318 bnx2x_cl45_read(bp, phy,
4319 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val2);
4320 DP(NETIF_MSG_LINK, "KR PCS status 0x%x\n", val2);
4321
4322 bnx2x_cl45_read(bp, phy,
4323 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
4324 bnx2x_cl45_read(bp, phy,
4325 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
4326 link_up = ((val1 & 4) == 4);
4327 DP(NETIF_MSG_LINK, "PMA_REG_STATUS=0x%x\n", val1);
4328
4329 if (link_up &&
4330 ((phy->req_line_speed != SPEED_10000))) {
4331 if (bnx2x_8073_xaui_wa(bp, phy) != 0)
4332 return 0;
4333 }
4334 bnx2x_cl45_read(bp, phy,
4335 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &an1000_status);
4336 bnx2x_cl45_read(bp, phy,
4337 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &an1000_status);
4338
4339 /* Check the link status on 1.1.2 */
4340 bnx2x_cl45_read(bp, phy,
4341 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
4342 bnx2x_cl45_read(bp, phy,
4343 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
4344 DP(NETIF_MSG_LINK, "KR PMA status 0x%x->0x%x,"
4345 "an_link_status=0x%x\n", val2, val1, an1000_status);
4346
4347 link_up = (((val1 & 4) == 4) || (an1000_status & (1<<1)));
4348 if (link_up && bnx2x_8073_is_snr_needed(bp, phy)) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004349 /*
4350 * The SNR will improve about 2dbby changing the BW and FEE main
4351 * tap. The 1st write to change FFE main tap is set before
4352 * restart AN. Change PLL Bandwidth in EDC register
4353 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004354 bnx2x_cl45_write(bp, phy,
4355 MDIO_PMA_DEVAD, MDIO_PMA_REG_PLL_BANDWIDTH,
4356 0x26BC);
4357
4358 /* Change CDR Bandwidth in EDC register */
4359 bnx2x_cl45_write(bp, phy,
4360 MDIO_PMA_DEVAD, MDIO_PMA_REG_CDR_BANDWIDTH,
4361 0x0333);
4362 }
4363 bnx2x_cl45_read(bp, phy,
4364 MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
4365 &link_status);
4366
4367 /* Bits 0..2 --> speed detected, bits 13..15--> link is down */
4368 if ((link_status & (1<<2)) && (!(link_status & (1<<15)))) {
4369 link_up = 1;
4370 vars->line_speed = SPEED_10000;
4371 DP(NETIF_MSG_LINK, "port %x: External link up in 10G\n",
4372 params->port);
4373 } else if ((link_status & (1<<1)) && (!(link_status & (1<<14)))) {
4374 link_up = 1;
4375 vars->line_speed = SPEED_2500;
4376 DP(NETIF_MSG_LINK, "port %x: External link up in 2.5G\n",
4377 params->port);
4378 } else if ((link_status & (1<<0)) && (!(link_status & (1<<13)))) {
4379 link_up = 1;
4380 vars->line_speed = SPEED_1000;
4381 DP(NETIF_MSG_LINK, "port %x: External link up in 1G\n",
4382 params->port);
4383 } else {
4384 link_up = 0;
4385 DP(NETIF_MSG_LINK, "port %x: External link is down\n",
4386 params->port);
4387 }
4388
4389 if (link_up) {
Yaniv Rosner74d7a112011-01-18 04:33:18 +00004390 /* Swap polarity if required */
4391 if (params->lane_config &
4392 PORT_HW_CFG_SWAP_PHY_POLARITY_ENABLED) {
4393 /* Configure the 8073 to swap P and N of the KR lines */
4394 bnx2x_cl45_read(bp, phy,
4395 MDIO_XS_DEVAD,
4396 MDIO_XS_REG_8073_RX_CTRL_PCIE, &val1);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004397 /*
4398 * Set bit 3 to invert Rx in 1G mode and clear this bit
4399 * when it`s in 10G mode.
4400 */
Yaniv Rosner74d7a112011-01-18 04:33:18 +00004401 if (vars->line_speed == SPEED_1000) {
4402 DP(NETIF_MSG_LINK, "Swapping 1G polarity for"
4403 "the 8073\n");
4404 val1 |= (1<<3);
4405 } else
4406 val1 &= ~(1<<3);
4407
4408 bnx2x_cl45_write(bp, phy,
4409 MDIO_XS_DEVAD,
4410 MDIO_XS_REG_8073_RX_CTRL_PCIE,
4411 val1);
4412 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004413 bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
4414 bnx2x_8073_resolve_fc(phy, params, vars);
Yaniv Rosner791f18c2011-01-18 04:33:42 +00004415 vars->duplex = DUPLEX_FULL;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004416 }
4417 return link_up;
4418}
4419
4420static void bnx2x_8073_link_reset(struct bnx2x_phy *phy,
4421 struct link_params *params)
4422{
4423 struct bnx2x *bp = params->bp;
4424 u8 gpio_port;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00004425 if (CHIP_IS_E2(bp))
4426 gpio_port = BP_PATH(bp);
4427 else
4428 gpio_port = params->port;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004429 DP(NETIF_MSG_LINK, "Setting 8073 port %d into low power mode\n",
4430 gpio_port);
4431 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004432 MISC_REGISTERS_GPIO_OUTPUT_LOW,
4433 gpio_port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004434}
4435
4436/******************************************************************/
4437/* BCM8705 PHY SECTION */
4438/******************************************************************/
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00004439static int bnx2x_8705_config_init(struct bnx2x_phy *phy,
4440 struct link_params *params,
4441 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004442{
4443 struct bnx2x *bp = params->bp;
4444 DP(NETIF_MSG_LINK, "init 8705\n");
4445 /* Restore normal power mode*/
4446 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004447 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004448 /* HW reset */
4449 bnx2x_ext_phy_hw_reset(bp, params->port);
4450 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0xa040);
Yaniv Rosner6d870c32011-01-31 04:22:20 +00004451 bnx2x_wait_reset_complete(bp, phy, params);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004452
4453 bnx2x_cl45_write(bp, phy,
4454 MDIO_PMA_DEVAD, MDIO_PMA_REG_MISC_CTRL, 0x8288);
4455 bnx2x_cl45_write(bp, phy,
4456 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, 0x7fbf);
4457 bnx2x_cl45_write(bp, phy,
4458 MDIO_PMA_DEVAD, MDIO_PMA_REG_CMU_PLL_BYPASS, 0x0100);
4459 bnx2x_cl45_write(bp, phy,
4460 MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_CNTL, 0x1);
4461 /* BCM8705 doesn't have microcode, hence the 0 */
4462 bnx2x_save_spirom_version(bp, params->port, params->shmem_base, 0);
4463 return 0;
4464}
4465
4466static u8 bnx2x_8705_read_status(struct bnx2x_phy *phy,
4467 struct link_params *params,
4468 struct link_vars *vars)
4469{
4470 u8 link_up = 0;
4471 u16 val1, rx_sd;
4472 struct bnx2x *bp = params->bp;
4473 DP(NETIF_MSG_LINK, "read status 8705\n");
4474 bnx2x_cl45_read(bp, phy,
4475 MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_STATUS, &val1);
4476 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
4477
4478 bnx2x_cl45_read(bp, phy,
4479 MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_STATUS, &val1);
4480 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
4481
4482 bnx2x_cl45_read(bp, phy,
4483 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD, &rx_sd);
4484
4485 bnx2x_cl45_read(bp, phy,
4486 MDIO_PMA_DEVAD, 0xc809, &val1);
4487 bnx2x_cl45_read(bp, phy,
4488 MDIO_PMA_DEVAD, 0xc809, &val1);
4489
4490 DP(NETIF_MSG_LINK, "8705 1.c809 val=0x%x\n", val1);
4491 link_up = ((rx_sd & 0x1) && (val1 & (1<<9)) && ((val1 & (1<<8)) == 0));
4492 if (link_up) {
4493 vars->line_speed = SPEED_10000;
4494 bnx2x_ext_phy_resolve_fc(phy, params, vars);
4495 }
4496 return link_up;
4497}
4498
4499/******************************************************************/
4500/* SFP+ module Section */
4501/******************************************************************/
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00004502static u8 bnx2x_get_gpio_port(struct link_params *params)
4503{
4504 u8 gpio_port;
4505 u32 swap_val, swap_override;
4506 struct bnx2x *bp = params->bp;
4507 if (CHIP_IS_E2(bp))
4508 gpio_port = BP_PATH(bp);
4509 else
4510 gpio_port = params->port;
4511 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
4512 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
4513 return gpio_port ^ (swap_val && swap_override);
4514}
4515static void bnx2x_sfp_set_transmitter(struct link_params *params,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004516 struct bnx2x_phy *phy,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004517 u8 tx_en)
4518{
4519 u16 val;
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00004520 u8 port = params->port;
4521 struct bnx2x *bp = params->bp;
4522 u32 tx_en_mode;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004523
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004524 /* Disable/Enable transmitter ( TX laser of the SFP+ module.)*/
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00004525 tx_en_mode = REG_RD(bp, params->shmem_base +
4526 offsetof(struct shmem_region,
4527 dev_info.port_hw_config[port].sfp_ctrl)) &
4528 PORT_HW_CFG_TX_LASER_MASK;
4529 DP(NETIF_MSG_LINK, "Setting transmitter tx_en=%x for port %x "
4530 "mode = %x\n", tx_en, port, tx_en_mode);
4531 switch (tx_en_mode) {
4532 case PORT_HW_CFG_TX_LASER_MDIO:
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004533
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00004534 bnx2x_cl45_read(bp, phy,
4535 MDIO_PMA_DEVAD,
4536 MDIO_PMA_REG_PHY_IDENTIFIER,
4537 &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004538
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00004539 if (tx_en)
4540 val &= ~(1<<15);
4541 else
4542 val |= (1<<15);
4543
4544 bnx2x_cl45_write(bp, phy,
4545 MDIO_PMA_DEVAD,
4546 MDIO_PMA_REG_PHY_IDENTIFIER,
4547 val);
4548 break;
4549 case PORT_HW_CFG_TX_LASER_GPIO0:
4550 case PORT_HW_CFG_TX_LASER_GPIO1:
4551 case PORT_HW_CFG_TX_LASER_GPIO2:
4552 case PORT_HW_CFG_TX_LASER_GPIO3:
4553 {
4554 u16 gpio_pin;
4555 u8 gpio_port, gpio_mode;
4556 if (tx_en)
4557 gpio_mode = MISC_REGISTERS_GPIO_OUTPUT_HIGH;
4558 else
4559 gpio_mode = MISC_REGISTERS_GPIO_OUTPUT_LOW;
4560
4561 gpio_pin = tx_en_mode - PORT_HW_CFG_TX_LASER_GPIO0;
4562 gpio_port = bnx2x_get_gpio_port(params);
4563 bnx2x_set_gpio(bp, gpio_pin, gpio_mode, gpio_port);
4564 break;
4565 }
4566 default:
4567 DP(NETIF_MSG_LINK, "Invalid TX_LASER_MDIO 0x%x\n", tx_en_mode);
4568 break;
4569 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004570}
4571
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00004572static int bnx2x_8726_read_sfp_module_eeprom(struct bnx2x_phy *phy,
4573 struct link_params *params,
4574 u16 addr, u8 byte_cnt, u8 *o_buf)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004575{
4576 struct bnx2x *bp = params->bp;
4577 u16 val = 0;
4578 u16 i;
4579 if (byte_cnt > 16) {
4580 DP(NETIF_MSG_LINK, "Reading from eeprom is"
4581 " is limited to 0xf\n");
4582 return -EINVAL;
4583 }
4584 /* Set the read command byte count */
4585 bnx2x_cl45_write(bp, phy,
4586 MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004587 (byte_cnt | 0xa000));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004588
4589 /* Set the read command address */
4590 bnx2x_cl45_write(bp, phy,
4591 MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004592 addr);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004593
4594 /* Activate read command */
4595 bnx2x_cl45_write(bp, phy,
4596 MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004597 0x2c0f);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004598
4599 /* Wait up to 500us for command complete status */
4600 for (i = 0; i < 100; i++) {
4601 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004602 MDIO_PMA_DEVAD,
4603 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004604 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
4605 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
4606 break;
4607 udelay(5);
4608 }
4609
4610 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
4611 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
4612 DP(NETIF_MSG_LINK,
4613 "Got bad status 0x%x when reading from SFP+ EEPROM\n",
4614 (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
4615 return -EINVAL;
4616 }
4617
4618 /* Read the buffer */
4619 for (i = 0; i < byte_cnt; i++) {
4620 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004621 MDIO_PMA_DEVAD,
4622 MDIO_PMA_REG_8726_TWO_WIRE_DATA_BUF + i, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004623 o_buf[i] = (u8)(val & MDIO_PMA_REG_8726_TWO_WIRE_DATA_MASK);
4624 }
4625
4626 for (i = 0; i < 100; i++) {
4627 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004628 MDIO_PMA_DEVAD,
4629 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004630 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
4631 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
Joe Perches6f38ad92010-11-14 17:04:31 +00004632 return 0;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004633 msleep(1);
4634 }
4635 return -EINVAL;
4636}
4637
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00004638static int bnx2x_8727_read_sfp_module_eeprom(struct bnx2x_phy *phy,
4639 struct link_params *params,
4640 u16 addr, u8 byte_cnt, u8 *o_buf)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004641{
4642 struct bnx2x *bp = params->bp;
4643 u16 val, i;
4644
4645 if (byte_cnt > 16) {
4646 DP(NETIF_MSG_LINK, "Reading from eeprom is"
4647 " is limited to 0xf\n");
4648 return -EINVAL;
4649 }
4650
4651 /* Need to read from 1.8000 to clear it */
4652 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004653 MDIO_PMA_DEVAD,
4654 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
4655 &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004656
4657 /* Set the read command byte count */
4658 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004659 MDIO_PMA_DEVAD,
4660 MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
4661 ((byte_cnt < 2) ? 2 : byte_cnt));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004662
4663 /* Set the read command address */
4664 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004665 MDIO_PMA_DEVAD,
4666 MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
4667 addr);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004668 /* Set the destination address */
4669 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004670 MDIO_PMA_DEVAD,
4671 0x8004,
4672 MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004673
4674 /* Activate read command */
4675 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004676 MDIO_PMA_DEVAD,
4677 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
4678 0x8002);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004679 /*
4680 * Wait appropriate time for two-wire command to finish before
4681 * polling the status register
4682 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004683 msleep(1);
4684
4685 /* Wait up to 500us for command complete status */
4686 for (i = 0; i < 100; i++) {
4687 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004688 MDIO_PMA_DEVAD,
4689 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004690 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
4691 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
4692 break;
4693 udelay(5);
4694 }
4695
4696 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
4697 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
4698 DP(NETIF_MSG_LINK,
4699 "Got bad status 0x%x when reading from SFP+ EEPROM\n",
4700 (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
Yaniv Rosner65a001b2011-01-31 04:22:03 +00004701 return -EFAULT;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004702 }
4703
4704 /* Read the buffer */
4705 for (i = 0; i < byte_cnt; i++) {
4706 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004707 MDIO_PMA_DEVAD,
4708 MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF + i, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004709 o_buf[i] = (u8)(val & MDIO_PMA_REG_8727_TWO_WIRE_DATA_MASK);
4710 }
4711
4712 for (i = 0; i < 100; i++) {
4713 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004714 MDIO_PMA_DEVAD,
4715 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004716 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
4717 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
Joe Perches6f38ad92010-11-14 17:04:31 +00004718 return 0;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004719 msleep(1);
4720 }
4721
4722 return -EINVAL;
4723}
4724
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00004725int bnx2x_read_sfp_module_eeprom(struct bnx2x_phy *phy,
4726 struct link_params *params, u16 addr,
4727 u8 byte_cnt, u8 *o_buf)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004728{
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00004729 int rc = -EINVAL;
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00004730 switch (phy->type) {
4731 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
4732 rc = bnx2x_8726_read_sfp_module_eeprom(phy, params, addr,
4733 byte_cnt, o_buf);
4734 break;
4735 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
4736 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722:
4737 rc = bnx2x_8727_read_sfp_module_eeprom(phy, params, addr,
4738 byte_cnt, o_buf);
4739 break;
4740 }
4741 return rc;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004742}
4743
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00004744static int bnx2x_get_edc_mode(struct bnx2x_phy *phy,
4745 struct link_params *params,
4746 u16 *edc_mode)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004747{
4748 struct bnx2x *bp = params->bp;
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00004749 u32 sync_offset = 0, phy_idx, media_types;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004750 u8 val, check_limiting_mode = 0;
4751 *edc_mode = EDC_MODE_LIMITING;
4752
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00004753 phy->media_type = ETH_PHY_UNSPECIFIED;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004754 /* First check for copper cable */
4755 if (bnx2x_read_sfp_module_eeprom(phy,
4756 params,
4757 SFP_EEPROM_CON_TYPE_ADDR,
4758 1,
4759 &val) != 0) {
4760 DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM\n");
4761 return -EINVAL;
4762 }
4763
4764 switch (val) {
4765 case SFP_EEPROM_CON_TYPE_VAL_COPPER:
4766 {
4767 u8 copper_module_type;
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00004768 phy->media_type = ETH_PHY_DA_TWINAX;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004769 /*
4770 * Check if its active cable (includes SFP+ module)
4771 * of passive cable
4772 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004773 if (bnx2x_read_sfp_module_eeprom(phy,
4774 params,
4775 SFP_EEPROM_FC_TX_TECH_ADDR,
4776 1,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00004777 &copper_module_type) != 0) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004778 DP(NETIF_MSG_LINK,
4779 "Failed to read copper-cable-type"
4780 " from SFP+ EEPROM\n");
4781 return -EINVAL;
4782 }
4783
4784 if (copper_module_type &
4785 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE) {
4786 DP(NETIF_MSG_LINK, "Active Copper cable detected\n");
4787 check_limiting_mode = 1;
4788 } else if (copper_module_type &
4789 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE) {
4790 DP(NETIF_MSG_LINK, "Passive Copper"
4791 " cable detected\n");
4792 *edc_mode =
4793 EDC_MODE_PASSIVE_DAC;
4794 } else {
4795 DP(NETIF_MSG_LINK, "Unknown copper-cable-"
4796 "type 0x%x !!!\n", copper_module_type);
4797 return -EINVAL;
4798 }
4799 break;
4800 }
4801 case SFP_EEPROM_CON_TYPE_VAL_LC:
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00004802 phy->media_type = ETH_PHY_SFP_FIBER;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004803 DP(NETIF_MSG_LINK, "Optic module detected\n");
4804 check_limiting_mode = 1;
4805 break;
4806 default:
4807 DP(NETIF_MSG_LINK, "Unable to determine module type 0x%x !!!\n",
4808 val);
4809 return -EINVAL;
4810 }
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00004811 sync_offset = params->shmem_base +
4812 offsetof(struct shmem_region,
4813 dev_info.port_hw_config[params->port].media_type);
4814 media_types = REG_RD(bp, sync_offset);
4815 /* Update media type for non-PMF sync */
4816 for (phy_idx = INT_PHY; phy_idx < MAX_PHYS; phy_idx++) {
4817 if (&(params->phy[phy_idx]) == phy) {
4818 media_types &= ~(PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK <<
4819 (PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT * phy_idx));
4820 media_types |= ((phy->media_type &
4821 PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK) <<
4822 (PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT * phy_idx));
4823 break;
4824 }
4825 }
4826 REG_WR(bp, sync_offset, media_types);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004827 if (check_limiting_mode) {
4828 u8 options[SFP_EEPROM_OPTIONS_SIZE];
4829 if (bnx2x_read_sfp_module_eeprom(phy,
4830 params,
4831 SFP_EEPROM_OPTIONS_ADDR,
4832 SFP_EEPROM_OPTIONS_SIZE,
4833 options) != 0) {
4834 DP(NETIF_MSG_LINK, "Failed to read Option"
4835 " field from module EEPROM\n");
4836 return -EINVAL;
4837 }
4838 if ((options[0] & SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK))
4839 *edc_mode = EDC_MODE_LINEAR;
4840 else
4841 *edc_mode = EDC_MODE_LIMITING;
4842 }
4843 DP(NETIF_MSG_LINK, "EDC mode is set to 0x%x\n", *edc_mode);
4844 return 0;
4845}
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004846/*
4847 * This function read the relevant field from the module (SFP+), and verify it
4848 * is compliant with this board
4849 */
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00004850static int bnx2x_verify_sfp_module(struct bnx2x_phy *phy,
4851 struct link_params *params)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004852{
4853 struct bnx2x *bp = params->bp;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004854 u32 val, cmd;
4855 u32 fw_resp, fw_cmd_param;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004856 char vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE+1];
4857 char vendor_pn[SFP_EEPROM_PART_NO_SIZE+1];
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004858 phy->flags &= ~FLAGS_SFP_NOT_APPROVED;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004859 val = REG_RD(bp, params->shmem_base +
4860 offsetof(struct shmem_region, dev_info.
4861 port_feature_config[params->port].config));
4862 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
4863 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_NO_ENFORCEMENT) {
4864 DP(NETIF_MSG_LINK, "NOT enforcing module verification\n");
4865 return 0;
4866 }
4867
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004868 if (params->feature_config_flags &
4869 FEATURE_CONFIG_BC_SUPPORTS_DUAL_PHY_OPT_MDL_VRFY) {
4870 /* Use specific phy request */
4871 cmd = DRV_MSG_CODE_VRFY_SPECIFIC_PHY_OPT_MDL;
4872 } else if (params->feature_config_flags &
4873 FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY) {
4874 /* Use first phy request only in case of non-dual media*/
4875 if (DUAL_MEDIA(params)) {
4876 DP(NETIF_MSG_LINK, "FW does not support OPT MDL "
4877 "verification\n");
4878 return -EINVAL;
4879 }
4880 cmd = DRV_MSG_CODE_VRFY_FIRST_PHY_OPT_MDL;
4881 } else {
4882 /* No support in OPT MDL detection */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004883 DP(NETIF_MSG_LINK, "FW does not support OPT MDL "
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004884 "verification\n");
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004885 return -EINVAL;
4886 }
Dmitry Kravkov523224a2010-10-06 03:23:26 +00004887
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004888 fw_cmd_param = FW_PARAM_SET(phy->addr, phy->type, phy->mdio_ctrl);
4889 fw_resp = bnx2x_fw_command(bp, cmd, fw_cmd_param);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004890 if (fw_resp == FW_MSG_CODE_VRFY_OPT_MDL_SUCCESS) {
4891 DP(NETIF_MSG_LINK, "Approved module\n");
4892 return 0;
4893 }
4894
4895 /* format the warning message */
4896 if (bnx2x_read_sfp_module_eeprom(phy,
4897 params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004898 SFP_EEPROM_VENDOR_NAME_ADDR,
4899 SFP_EEPROM_VENDOR_NAME_SIZE,
4900 (u8 *)vendor_name))
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004901 vendor_name[0] = '\0';
4902 else
4903 vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE] = '\0';
4904 if (bnx2x_read_sfp_module_eeprom(phy,
4905 params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004906 SFP_EEPROM_PART_NO_ADDR,
4907 SFP_EEPROM_PART_NO_SIZE,
4908 (u8 *)vendor_pn))
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004909 vendor_pn[0] = '\0';
4910 else
4911 vendor_pn[SFP_EEPROM_PART_NO_SIZE] = '\0';
4912
Yaniv Rosner6d870c32011-01-31 04:22:20 +00004913 netdev_err(bp->dev, "Warning: Unqualified SFP+ module detected,"
4914 " Port %d from %s part number %s\n",
4915 params->port, vendor_name, vendor_pn);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004916 phy->flags |= FLAGS_SFP_NOT_APPROVED;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004917 return -EINVAL;
4918}
4919
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00004920static int bnx2x_wait_for_sfp_module_initialized(struct bnx2x_phy *phy,
4921 struct link_params *params)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004922
4923{
4924 u8 val;
4925 struct bnx2x *bp = params->bp;
4926 u16 timeout;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004927 /*
4928 * Initialization time after hot-plug may take up to 300ms for
4929 * some phys type ( e.g. JDSU )
4930 */
4931
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004932 for (timeout = 0; timeout < 60; timeout++) {
4933 if (bnx2x_read_sfp_module_eeprom(phy, params, 1, 1, &val)
4934 == 0) {
4935 DP(NETIF_MSG_LINK, "SFP+ module initialization "
4936 "took %d ms\n", timeout * 5);
4937 return 0;
4938 }
4939 msleep(5);
4940 }
4941 return -EINVAL;
4942}
4943
4944static void bnx2x_8727_power_module(struct bnx2x *bp,
4945 struct bnx2x_phy *phy,
4946 u8 is_power_up) {
4947 /* Make sure GPIOs are not using for LED mode */
4948 u16 val;
4949 /*
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004950 * In the GPIO register, bit 4 is use to determine if the GPIOs are
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004951 * operating as INPUT or as OUTPUT. Bit 1 is for input, and 0 for
4952 * output
4953 * Bits 0-1 determine the gpios value for OUTPUT in case bit 4 val is 0
4954 * Bits 8-9 determine the gpios value for INPUT in case bit 4 val is 1
4955 * where the 1st bit is the over-current(only input), and 2nd bit is
4956 * for power( only output )
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004957 *
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004958 * In case of NOC feature is disabled and power is up, set GPIO control
4959 * as input to enable listening of over-current indication
4960 */
4961 if (phy->flags & FLAGS_NOC)
4962 return;
Yaniv Rosner27d02432011-05-31 21:27:48 +00004963 if (is_power_up)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004964 val = (1<<4);
4965 else
4966 /*
4967 * Set GPIO control to OUTPUT, and set the power bit
4968 * to according to the is_power_up
4969 */
Yaniv Rosner27d02432011-05-31 21:27:48 +00004970 val = (1<<1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004971
4972 bnx2x_cl45_write(bp, phy,
4973 MDIO_PMA_DEVAD,
4974 MDIO_PMA_REG_8727_GPIO_CTRL,
4975 val);
4976}
4977
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00004978static int bnx2x_8726_set_limiting_mode(struct bnx2x *bp,
4979 struct bnx2x_phy *phy,
4980 u16 edc_mode)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004981{
4982 u16 cur_limiting_mode;
4983
4984 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004985 MDIO_PMA_DEVAD,
4986 MDIO_PMA_REG_ROM_VER2,
4987 &cur_limiting_mode);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004988 DP(NETIF_MSG_LINK, "Current Limiting mode is 0x%x\n",
4989 cur_limiting_mode);
4990
4991 if (edc_mode == EDC_MODE_LIMITING) {
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004992 DP(NETIF_MSG_LINK, "Setting LIMITING MODE\n");
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004993 bnx2x_cl45_write(bp, phy,
4994 MDIO_PMA_DEVAD,
4995 MDIO_PMA_REG_ROM_VER2,
4996 EDC_MODE_LIMITING);
4997 } else { /* LRM mode ( default )*/
4998
4999 DP(NETIF_MSG_LINK, "Setting LRM MODE\n");
5000
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005001 /*
5002 * Changing to LRM mode takes quite few seconds. So do it only
5003 * if current mode is limiting (default is LRM)
5004 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005005 if (cur_limiting_mode != EDC_MODE_LIMITING)
5006 return 0;
5007
5008 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005009 MDIO_PMA_DEVAD,
5010 MDIO_PMA_REG_LRM_MODE,
5011 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005012 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005013 MDIO_PMA_DEVAD,
5014 MDIO_PMA_REG_ROM_VER2,
5015 0x128);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005016 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005017 MDIO_PMA_DEVAD,
5018 MDIO_PMA_REG_MISC_CTRL0,
5019 0x4008);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005020 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005021 MDIO_PMA_DEVAD,
5022 MDIO_PMA_REG_LRM_MODE,
5023 0xaaaa);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005024 }
5025 return 0;
5026}
5027
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005028static int bnx2x_8727_set_limiting_mode(struct bnx2x *bp,
5029 struct bnx2x_phy *phy,
5030 u16 edc_mode)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005031{
5032 u16 phy_identifier;
5033 u16 rom_ver2_val;
5034 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005035 MDIO_PMA_DEVAD,
5036 MDIO_PMA_REG_PHY_IDENTIFIER,
5037 &phy_identifier);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005038
5039 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005040 MDIO_PMA_DEVAD,
5041 MDIO_PMA_REG_PHY_IDENTIFIER,
5042 (phy_identifier & ~(1<<9)));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005043
5044 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005045 MDIO_PMA_DEVAD,
5046 MDIO_PMA_REG_ROM_VER2,
5047 &rom_ver2_val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005048 /* Keep the MSB 8-bits, and set the LSB 8-bits with the edc_mode */
5049 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005050 MDIO_PMA_DEVAD,
5051 MDIO_PMA_REG_ROM_VER2,
5052 (rom_ver2_val & 0xff00) | (edc_mode & 0x00ff));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005053
5054 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005055 MDIO_PMA_DEVAD,
5056 MDIO_PMA_REG_PHY_IDENTIFIER,
5057 (phy_identifier | (1<<9)));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005058
5059 return 0;
5060}
5061
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005062static void bnx2x_8727_specific_func(struct bnx2x_phy *phy,
5063 struct link_params *params,
5064 u32 action)
5065{
5066 struct bnx2x *bp = params->bp;
5067
5068 switch (action) {
5069 case DISABLE_TX:
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00005070 bnx2x_sfp_set_transmitter(params, phy, 0);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005071 break;
5072 case ENABLE_TX:
5073 if (!(phy->flags & FLAGS_SFP_NOT_APPROVED))
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00005074 bnx2x_sfp_set_transmitter(params, phy, 1);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005075 break;
5076 default:
5077 DP(NETIF_MSG_LINK, "Function 0x%x not supported by 8727\n",
5078 action);
5079 return;
5080 }
5081}
5082
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00005083static void bnx2x_set_sfp_module_fault_led(struct link_params *params,
5084 u8 gpio_mode)
5085{
5086 struct bnx2x *bp = params->bp;
5087
5088 u32 fault_led_gpio = REG_RD(bp, params->shmem_base +
5089 offsetof(struct shmem_region,
5090 dev_info.port_hw_config[params->port].sfp_ctrl)) &
5091 PORT_HW_CFG_FAULT_MODULE_LED_MASK;
5092 switch (fault_led_gpio) {
5093 case PORT_HW_CFG_FAULT_MODULE_LED_DISABLED:
5094 return;
5095 case PORT_HW_CFG_FAULT_MODULE_LED_GPIO0:
5096 case PORT_HW_CFG_FAULT_MODULE_LED_GPIO1:
5097 case PORT_HW_CFG_FAULT_MODULE_LED_GPIO2:
5098 case PORT_HW_CFG_FAULT_MODULE_LED_GPIO3:
5099 {
5100 u8 gpio_port = bnx2x_get_gpio_port(params);
5101 u16 gpio_pin = fault_led_gpio -
5102 PORT_HW_CFG_FAULT_MODULE_LED_GPIO0;
5103 DP(NETIF_MSG_LINK, "Set fault module-detected led "
5104 "pin %x port %x mode %x\n",
5105 gpio_pin, gpio_port, gpio_mode);
5106 bnx2x_set_gpio(bp, gpio_pin, gpio_mode, gpio_port);
5107 }
5108 break;
5109 default:
5110 DP(NETIF_MSG_LINK, "Error: Invalid fault led mode 0x%x\n",
5111 fault_led_gpio);
5112 }
5113}
5114
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00005115static void bnx2x_power_sfp_module(struct link_params *params,
5116 struct bnx2x_phy *phy,
5117 u8 power)
5118{
5119 struct bnx2x *bp = params->bp;
5120 DP(NETIF_MSG_LINK, "Setting SFP+ power to %x\n", power);
5121
5122 switch (phy->type) {
5123 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
5124 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722:
5125 bnx2x_8727_power_module(params->bp, phy, power);
5126 break;
5127 default:
5128 break;
5129 }
5130}
5131
5132static void bnx2x_set_limiting_mode(struct link_params *params,
5133 struct bnx2x_phy *phy,
5134 u16 edc_mode)
5135{
5136 switch (phy->type) {
5137 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
5138 bnx2x_8726_set_limiting_mode(params->bp, phy, edc_mode);
5139 break;
5140 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
5141 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722:
5142 bnx2x_8727_set_limiting_mode(params->bp, phy, edc_mode);
5143 break;
5144 }
5145}
5146
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005147int bnx2x_sfp_module_detection(struct bnx2x_phy *phy,
5148 struct link_params *params)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005149{
5150 struct bnx2x *bp = params->bp;
5151 u16 edc_mode;
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005152 int rc = 0;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005153
5154 u32 val = REG_RD(bp, params->shmem_base +
5155 offsetof(struct shmem_region, dev_info.
5156 port_feature_config[params->port].config));
5157
5158 DP(NETIF_MSG_LINK, "SFP+ module plugged in/out detected on port %d\n",
5159 params->port);
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00005160 /* Power up module */
5161 bnx2x_power_sfp_module(params, phy, 1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005162 if (bnx2x_get_edc_mode(phy, params, &edc_mode) != 0) {
5163 DP(NETIF_MSG_LINK, "Failed to get valid module type\n");
5164 return -EINVAL;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005165 } else if (bnx2x_verify_sfp_module(phy, params) != 0) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005166 /* check SFP+ module compatibility */
5167 DP(NETIF_MSG_LINK, "Module verification failed!!\n");
5168 rc = -EINVAL;
5169 /* Turn on fault module-detected led */
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00005170 bnx2x_set_sfp_module_fault_led(params,
5171 MISC_REGISTERS_GPIO_HIGH);
5172
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00005173 /* Check if need to power down the SFP+ module */
5174 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
5175 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_POWER_DOWN) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005176 DP(NETIF_MSG_LINK, "Shutdown SFP+ module!!\n");
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00005177 bnx2x_power_sfp_module(params, phy, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005178 return rc;
5179 }
5180 } else {
5181 /* Turn off fault module-detected led */
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00005182 bnx2x_set_sfp_module_fault_led(params, MISC_REGISTERS_GPIO_LOW);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005183 }
5184
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005185 /*
5186 * Check and set limiting mode / LRM mode on 8726. On 8727 it
5187 * is done automatically
5188 */
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00005189 bnx2x_set_limiting_mode(params, phy, edc_mode);
5190
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005191 /*
5192 * Enable transmit for this module if the module is approved, or
5193 * if unapproved modules should also enable the Tx laser
5194 */
5195 if (rc == 0 ||
5196 (val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) !=
5197 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00005198 bnx2x_sfp_set_transmitter(params, phy, 1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005199 else
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00005200 bnx2x_sfp_set_transmitter(params, phy, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005201
5202 return rc;
5203}
5204
5205void bnx2x_handle_module_detect_int(struct link_params *params)
5206{
5207 struct bnx2x *bp = params->bp;
5208 struct bnx2x_phy *phy = &params->phy[EXT_PHY1];
5209 u32 gpio_val;
5210 u8 port = params->port;
5211
5212 /* Set valid module led off */
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00005213 bnx2x_set_sfp_module_fault_led(params, MISC_REGISTERS_GPIO_HIGH);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005214
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005215 /* Get current gpio val reflecting module plugged in / out*/
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005216 gpio_val = bnx2x_get_gpio(bp, MISC_REGISTERS_GPIO_3, port);
5217
5218 /* Call the handling function in case module is detected */
5219 if (gpio_val == 0) {
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00005220 bnx2x_power_sfp_module(params, phy, 1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005221 bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
5222 MISC_REGISTERS_GPIO_INT_OUTPUT_CLR,
5223 port);
5224
5225 if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0)
5226 bnx2x_sfp_module_detection(phy, params);
5227 else
5228 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
5229 } else {
5230 u32 val = REG_RD(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005231 offsetof(struct shmem_region, dev_info.
5232 port_feature_config[params->port].
5233 config));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005234
5235 bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
5236 MISC_REGISTERS_GPIO_INT_OUTPUT_SET,
5237 port);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005238 /*
5239 * Module was plugged out.
5240 * Disable transmit for this module
5241 */
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00005242 phy->media_type = ETH_PHY_NOT_PRESENT;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005243 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
5244 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00005245 bnx2x_sfp_set_transmitter(params, phy, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005246 }
5247}
5248
5249/******************************************************************/
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00005250/* Used by 8706 and 8727 */
5251/******************************************************************/
5252static void bnx2x_sfp_mask_fault(struct bnx2x *bp,
5253 struct bnx2x_phy *phy,
5254 u16 alarm_status_offset,
5255 u16 alarm_ctrl_offset)
5256{
5257 u16 alarm_status, val;
5258 bnx2x_cl45_read(bp, phy,
5259 MDIO_PMA_DEVAD, alarm_status_offset,
5260 &alarm_status);
5261 bnx2x_cl45_read(bp, phy,
5262 MDIO_PMA_DEVAD, alarm_status_offset,
5263 &alarm_status);
5264 /* Mask or enable the fault event. */
5265 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, alarm_ctrl_offset, &val);
5266 if (alarm_status & (1<<0))
5267 val &= ~(1<<0);
5268 else
5269 val |= (1<<0);
5270 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, alarm_ctrl_offset, val);
5271}
5272/******************************************************************/
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005273/* common BCM8706/BCM8726 PHY SECTION */
5274/******************************************************************/
5275static u8 bnx2x_8706_8726_read_status(struct bnx2x_phy *phy,
5276 struct link_params *params,
5277 struct link_vars *vars)
5278{
5279 u8 link_up = 0;
5280 u16 val1, val2, rx_sd, pcs_status;
5281 struct bnx2x *bp = params->bp;
5282 DP(NETIF_MSG_LINK, "XGXS 8706/8726\n");
5283 /* Clear RX Alarm*/
5284 bnx2x_cl45_read(bp, phy,
5285 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &val2);
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00005286
5287 bnx2x_sfp_mask_fault(bp, phy, MDIO_PMA_REG_TX_ALARM,
5288 MDIO_PMA_REG_TX_ALARM_CTRL);
5289
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005290 /* clear LASI indication*/
5291 bnx2x_cl45_read(bp, phy,
5292 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
5293 bnx2x_cl45_read(bp, phy,
5294 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val2);
5295 DP(NETIF_MSG_LINK, "8706/8726 LASI status 0x%x--> 0x%x\n", val1, val2);
5296
5297 bnx2x_cl45_read(bp, phy,
5298 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD, &rx_sd);
5299 bnx2x_cl45_read(bp, phy,
5300 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &pcs_status);
5301 bnx2x_cl45_read(bp, phy,
5302 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &val2);
5303 bnx2x_cl45_read(bp, phy,
5304 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &val2);
5305
5306 DP(NETIF_MSG_LINK, "8706/8726 rx_sd 0x%x pcs_status 0x%x 1Gbps"
5307 " link_status 0x%x\n", rx_sd, pcs_status, val2);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005308 /*
5309 * link is up if both bit 0 of pmd_rx_sd and bit 0 of pcs_status
5310 * are set, or if the autoneg bit 1 is set
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005311 */
5312 link_up = ((rx_sd & pcs_status & 0x1) || (val2 & (1<<1)));
5313 if (link_up) {
5314 if (val2 & (1<<1))
5315 vars->line_speed = SPEED_1000;
5316 else
5317 vars->line_speed = SPEED_10000;
5318 bnx2x_ext_phy_resolve_fc(phy, params, vars);
Yaniv Rosner791f18c2011-01-18 04:33:42 +00005319 vars->duplex = DUPLEX_FULL;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005320 }
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00005321
5322 /* Capture 10G link fault. Read twice to clear stale value. */
5323 if (vars->line_speed == SPEED_10000) {
5324 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
5325 MDIO_PMA_REG_TX_ALARM, &val1);
5326 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
5327 MDIO_PMA_REG_TX_ALARM, &val1);
5328 if (val1 & (1<<0))
5329 vars->fault_detected = 1;
5330 }
5331
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005332 return link_up;
5333}
5334
5335/******************************************************************/
5336/* BCM8706 PHY SECTION */
5337/******************************************************************/
5338static u8 bnx2x_8706_config_init(struct bnx2x_phy *phy,
5339 struct link_params *params,
5340 struct link_vars *vars)
5341{
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00005342 u32 tx_en_mode;
5343 u16 cnt, val, tmp1;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005344 struct bnx2x *bp = params->bp;
5345 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005346 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005347 /* HW reset */
5348 bnx2x_ext_phy_hw_reset(bp, params->port);
5349 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0xa040);
Yaniv Rosner6d870c32011-01-31 04:22:20 +00005350 bnx2x_wait_reset_complete(bp, phy, params);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005351
5352 /* Wait until fw is loaded */
5353 for (cnt = 0; cnt < 100; cnt++) {
5354 bnx2x_cl45_read(bp, phy,
5355 MDIO_PMA_DEVAD, MDIO_PMA_REG_ROM_VER1, &val);
5356 if (val)
5357 break;
5358 msleep(10);
5359 }
5360 DP(NETIF_MSG_LINK, "XGXS 8706 is initialized after %d ms\n", cnt);
5361 if ((params->feature_config_flags &
5362 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
5363 u8 i;
5364 u16 reg;
5365 for (i = 0; i < 4; i++) {
5366 reg = MDIO_XS_8706_REG_BANK_RX0 +
5367 i*(MDIO_XS_8706_REG_BANK_RX1 -
5368 MDIO_XS_8706_REG_BANK_RX0);
5369 bnx2x_cl45_read(bp, phy, MDIO_XS_DEVAD, reg, &val);
5370 /* Clear first 3 bits of the control */
5371 val &= ~0x7;
5372 /* Set control bits according to configuration */
5373 val |= (phy->rx_preemphasis[i] & 0x7);
5374 DP(NETIF_MSG_LINK, "Setting RX Equalizer to BCM8706"
5375 " reg 0x%x <-- val 0x%x\n", reg, val);
5376 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, reg, val);
5377 }
5378 }
5379 /* Force speed */
5380 if (phy->req_line_speed == SPEED_10000) {
5381 DP(NETIF_MSG_LINK, "XGXS 8706 force 10Gbps\n");
5382
5383 bnx2x_cl45_write(bp, phy,
5384 MDIO_PMA_DEVAD,
5385 MDIO_PMA_REG_DIGITAL_CTRL, 0x400);
5386 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00005387 MDIO_PMA_DEVAD, MDIO_PMA_REG_TX_ALARM_CTRL,
5388 0);
5389 /* Arm LASI for link and Tx fault. */
5390 bnx2x_cl45_write(bp, phy,
5391 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 3);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005392 } else {
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005393 /* Force 1Gbps using autoneg with 1G advertisement */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005394
5395 /* Allow CL37 through CL73 */
5396 DP(NETIF_MSG_LINK, "XGXS 8706 AutoNeg\n");
5397 bnx2x_cl45_write(bp, phy,
5398 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_CL73, 0x040c);
5399
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005400 /* Enable Full-Duplex advertisement on CL37 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005401 bnx2x_cl45_write(bp, phy,
5402 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LP, 0x0020);
5403 /* Enable CL37 AN */
5404 bnx2x_cl45_write(bp, phy,
5405 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
5406 /* 1G support */
5407 bnx2x_cl45_write(bp, phy,
5408 MDIO_AN_DEVAD, MDIO_AN_REG_ADV, (1<<5));
5409
5410 /* Enable clause 73 AN */
5411 bnx2x_cl45_write(bp, phy,
5412 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
5413 bnx2x_cl45_write(bp, phy,
5414 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
5415 0x0400);
5416 bnx2x_cl45_write(bp, phy,
5417 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL,
5418 0x0004);
5419 }
5420 bnx2x_save_bcm_spirom_ver(bp, phy, params->port);
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00005421
5422 /*
5423 * If TX Laser is controlled by GPIO_0, do not let PHY go into low
5424 * power mode, if TX Laser is disabled
5425 */
5426
5427 tx_en_mode = REG_RD(bp, params->shmem_base +
5428 offsetof(struct shmem_region,
5429 dev_info.port_hw_config[params->port].sfp_ctrl))
5430 & PORT_HW_CFG_TX_LASER_MASK;
5431
5432 if (tx_en_mode == PORT_HW_CFG_TX_LASER_GPIO0) {
5433 DP(NETIF_MSG_LINK, "Enabling TXONOFF_PWRDN_DIS\n");
5434 bnx2x_cl45_read(bp, phy,
5435 MDIO_PMA_DEVAD, MDIO_PMA_REG_DIGITAL_CTRL, &tmp1);
5436 tmp1 |= 0x1;
5437 bnx2x_cl45_write(bp, phy,
5438 MDIO_PMA_DEVAD, MDIO_PMA_REG_DIGITAL_CTRL, tmp1);
5439 }
5440
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005441 return 0;
5442}
5443
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005444static int bnx2x_8706_read_status(struct bnx2x_phy *phy,
5445 struct link_params *params,
5446 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005447{
5448 return bnx2x_8706_8726_read_status(phy, params, vars);
5449}
5450
5451/******************************************************************/
5452/* BCM8726 PHY SECTION */
5453/******************************************************************/
5454static void bnx2x_8726_config_loopback(struct bnx2x_phy *phy,
5455 struct link_params *params)
5456{
5457 struct bnx2x *bp = params->bp;
5458 DP(NETIF_MSG_LINK, "PMA/PMD ext_phy_loopback: 8726\n");
5459 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x0001);
5460}
5461
5462static void bnx2x_8726_external_rom_boot(struct bnx2x_phy *phy,
5463 struct link_params *params)
5464{
5465 struct bnx2x *bp = params->bp;
5466 /* Need to wait 100ms after reset */
5467 msleep(100);
5468
5469 /* Micro controller re-boot */
5470 bnx2x_cl45_write(bp, phy,
5471 MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, 0x018B);
5472
5473 /* Set soft reset */
5474 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005475 MDIO_PMA_DEVAD,
5476 MDIO_PMA_REG_GEN_CTRL,
5477 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005478
5479 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005480 MDIO_PMA_DEVAD,
5481 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005482
5483 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005484 MDIO_PMA_DEVAD,
5485 MDIO_PMA_REG_GEN_CTRL,
5486 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005487
5488 /* wait for 150ms for microcode load */
5489 msleep(150);
5490
5491 /* Disable serial boot control, tristates pins SS_N, SCK, MOSI, MISO */
5492 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005493 MDIO_PMA_DEVAD,
5494 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005495
5496 msleep(200);
5497 bnx2x_save_bcm_spirom_ver(bp, phy, params->port);
5498}
5499
5500static u8 bnx2x_8726_read_status(struct bnx2x_phy *phy,
5501 struct link_params *params,
5502 struct link_vars *vars)
5503{
5504 struct bnx2x *bp = params->bp;
5505 u16 val1;
5506 u8 link_up = bnx2x_8706_8726_read_status(phy, params, vars);
5507 if (link_up) {
5508 bnx2x_cl45_read(bp, phy,
5509 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER,
5510 &val1);
5511 if (val1 & (1<<15)) {
5512 DP(NETIF_MSG_LINK, "Tx is disabled\n");
5513 link_up = 0;
5514 vars->line_speed = 0;
5515 }
5516 }
5517 return link_up;
5518}
5519
5520
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005521static int bnx2x_8726_config_init(struct bnx2x_phy *phy,
5522 struct link_params *params,
5523 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005524{
5525 struct bnx2x *bp = params->bp;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005526 DP(NETIF_MSG_LINK, "Initializing BCM8726\n");
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005527
5528 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
Yaniv Rosner6d870c32011-01-31 04:22:20 +00005529 bnx2x_wait_reset_complete(bp, phy, params);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005530
5531 bnx2x_8726_external_rom_boot(phy, params);
5532
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005533 /*
5534 * Need to call module detected on initialization since the module
5535 * detection triggered by actual module insertion might occur before
5536 * driver is loaded, and when driver is loaded, it reset all
5537 * registers, including the transmitter
5538 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005539 bnx2x_sfp_module_detection(phy, params);
5540
5541 if (phy->req_line_speed == SPEED_1000) {
5542 DP(NETIF_MSG_LINK, "Setting 1G force\n");
5543 bnx2x_cl45_write(bp, phy,
5544 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x40);
5545 bnx2x_cl45_write(bp, phy,
5546 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0xD);
5547 bnx2x_cl45_write(bp, phy,
5548 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x5);
5549 bnx2x_cl45_write(bp, phy,
5550 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
5551 0x400);
5552 } else if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
5553 (phy->speed_cap_mask &
5554 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G) &&
5555 ((phy->speed_cap_mask &
5556 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) !=
5557 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
5558 DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
5559 /* Set Flow control */
5560 bnx2x_ext_phy_set_pause(params, phy, vars);
5561 bnx2x_cl45_write(bp, phy,
5562 MDIO_AN_DEVAD, MDIO_AN_REG_ADV, 0x20);
5563 bnx2x_cl45_write(bp, phy,
5564 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_CL73, 0x040c);
5565 bnx2x_cl45_write(bp, phy,
5566 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, 0x0020);
5567 bnx2x_cl45_write(bp, phy,
5568 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
5569 bnx2x_cl45_write(bp, phy,
5570 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005571 /*
5572 * Enable RX-ALARM control to receive interrupt for 1G speed
5573 * change
5574 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005575 bnx2x_cl45_write(bp, phy,
5576 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x4);
5577 bnx2x_cl45_write(bp, phy,
5578 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
5579 0x400);
5580
5581 } else { /* Default 10G. Set only LASI control */
5582 bnx2x_cl45_write(bp, phy,
5583 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 1);
5584 }
5585
5586 /* Set TX PreEmphasis if needed */
5587 if ((params->feature_config_flags &
5588 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
5589 DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x,"
5590 "TX_CTRL2 0x%x\n",
5591 phy->tx_preemphasis[0],
5592 phy->tx_preemphasis[1]);
5593 bnx2x_cl45_write(bp, phy,
5594 MDIO_PMA_DEVAD,
5595 MDIO_PMA_REG_8726_TX_CTRL1,
5596 phy->tx_preemphasis[0]);
5597
5598 bnx2x_cl45_write(bp, phy,
5599 MDIO_PMA_DEVAD,
5600 MDIO_PMA_REG_8726_TX_CTRL2,
5601 phy->tx_preemphasis[1]);
5602 }
5603
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005604 return 0;
5605
5606}
5607
5608static void bnx2x_8726_link_reset(struct bnx2x_phy *phy,
5609 struct link_params *params)
5610{
5611 struct bnx2x *bp = params->bp;
5612 DP(NETIF_MSG_LINK, "bnx2x_8726_link_reset port %d\n", params->port);
5613 /* Set serial boot control for external load */
5614 bnx2x_cl45_write(bp, phy,
5615 MDIO_PMA_DEVAD,
5616 MDIO_PMA_REG_GEN_CTRL, 0x0001);
5617}
5618
5619/******************************************************************/
5620/* BCM8727 PHY SECTION */
5621/******************************************************************/
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005622
5623static void bnx2x_8727_set_link_led(struct bnx2x_phy *phy,
5624 struct link_params *params, u8 mode)
5625{
5626 struct bnx2x *bp = params->bp;
5627 u16 led_mode_bitmask = 0;
5628 u16 gpio_pins_bitmask = 0;
5629 u16 val;
5630 /* Only NOC flavor requires to set the LED specifically */
5631 if (!(phy->flags & FLAGS_NOC))
5632 return;
5633 switch (mode) {
5634 case LED_MODE_FRONT_PANEL_OFF:
5635 case LED_MODE_OFF:
5636 led_mode_bitmask = 0;
5637 gpio_pins_bitmask = 0x03;
5638 break;
5639 case LED_MODE_ON:
5640 led_mode_bitmask = 0;
5641 gpio_pins_bitmask = 0x02;
5642 break;
5643 case LED_MODE_OPER:
5644 led_mode_bitmask = 0x60;
5645 gpio_pins_bitmask = 0x11;
5646 break;
5647 }
5648 bnx2x_cl45_read(bp, phy,
5649 MDIO_PMA_DEVAD,
5650 MDIO_PMA_REG_8727_PCS_OPT_CTRL,
5651 &val);
5652 val &= 0xff8f;
5653 val |= led_mode_bitmask;
5654 bnx2x_cl45_write(bp, phy,
5655 MDIO_PMA_DEVAD,
5656 MDIO_PMA_REG_8727_PCS_OPT_CTRL,
5657 val);
5658 bnx2x_cl45_read(bp, phy,
5659 MDIO_PMA_DEVAD,
5660 MDIO_PMA_REG_8727_GPIO_CTRL,
5661 &val);
5662 val &= 0xffe0;
5663 val |= gpio_pins_bitmask;
5664 bnx2x_cl45_write(bp, phy,
5665 MDIO_PMA_DEVAD,
5666 MDIO_PMA_REG_8727_GPIO_CTRL,
5667 val);
5668}
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005669static void bnx2x_8727_hw_reset(struct bnx2x_phy *phy,
5670 struct link_params *params) {
5671 u32 swap_val, swap_override;
5672 u8 port;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005673 /*
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005674 * The PHY reset is controlled by GPIO 1. Fake the port number
5675 * to cancel the swap done in set_gpio()
5676 */
5677 struct bnx2x *bp = params->bp;
5678 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
5679 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
5680 port = (swap_val && swap_override) ^ 1;
5681 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005682 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005683}
5684
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005685static int bnx2x_8727_config_init(struct bnx2x_phy *phy,
5686 struct link_params *params,
5687 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005688{
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00005689 u32 tx_en_mode;
5690 u16 tmp1, val, mod_abs, tmp2;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005691 u16 rx_alarm_ctrl_val;
5692 u16 lasi_ctrl_val;
5693 struct bnx2x *bp = params->bp;
5694 /* Enable PMD link, MOD_ABS_FLT, and 1G link alarm */
5695
Yaniv Rosner6d870c32011-01-31 04:22:20 +00005696 bnx2x_wait_reset_complete(bp, phy, params);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005697 rx_alarm_ctrl_val = (1<<2) | (1<<5) ;
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00005698 /* Should be 0x6 to enable XS on Tx side. */
5699 lasi_ctrl_val = 0x0006;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005700
5701 DP(NETIF_MSG_LINK, "Initializing BCM8727\n");
5702 /* enable LASI */
5703 bnx2x_cl45_write(bp, phy,
5704 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
5705 rx_alarm_ctrl_val);
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00005706 bnx2x_cl45_write(bp, phy,
5707 MDIO_PMA_DEVAD, MDIO_PMA_REG_TX_ALARM_CTRL,
5708 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005709 bnx2x_cl45_write(bp, phy,
5710 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, lasi_ctrl_val);
5711
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005712 /*
5713 * Initially configure MOD_ABS to interrupt when module is
5714 * presence( bit 8)
5715 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005716 bnx2x_cl45_read(bp, phy,
5717 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005718 /*
5719 * Set EDC off by setting OPTXLOS signal input to low (bit 9).
5720 * When the EDC is off it locks onto a reference clock and avoids
5721 * becoming 'lost'
5722 */
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005723 mod_abs &= ~(1<<8);
5724 if (!(phy->flags & FLAGS_NOC))
5725 mod_abs &= ~(1<<9);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005726 bnx2x_cl45_write(bp, phy,
5727 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
5728
5729
5730 /* Make MOD_ABS give interrupt on change */
5731 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL,
5732 &val);
5733 val |= (1<<12);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005734 if (phy->flags & FLAGS_NOC)
5735 val |= (3<<5);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005736
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005737 /*
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005738 * Set 8727 GPIOs to input to allow reading from the 8727 GPIO0
5739 * status which reflect SFP+ module over-current
5740 */
5741 if (!(phy->flags & FLAGS_NOC))
5742 val &= 0xff8f; /* Reset bits 4-6 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005743 bnx2x_cl45_write(bp, phy,
5744 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL, val);
5745
5746 bnx2x_8727_power_module(bp, phy, 1);
5747
5748 bnx2x_cl45_read(bp, phy,
5749 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &tmp1);
5750
5751 bnx2x_cl45_read(bp, phy,
5752 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &tmp1);
5753
5754 /* Set option 1G speed */
5755 if (phy->req_line_speed == SPEED_1000) {
5756 DP(NETIF_MSG_LINK, "Setting 1G force\n");
5757 bnx2x_cl45_write(bp, phy,
5758 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x40);
5759 bnx2x_cl45_write(bp, phy,
5760 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0xD);
5761 bnx2x_cl45_read(bp, phy,
5762 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, &tmp1);
5763 DP(NETIF_MSG_LINK, "1.7 = 0x%x\n", tmp1);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005764 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005765 * Power down the XAUI until link is up in case of dual-media
5766 * and 1G
5767 */
5768 if (DUAL_MEDIA(params)) {
5769 bnx2x_cl45_read(bp, phy,
5770 MDIO_PMA_DEVAD,
5771 MDIO_PMA_REG_8727_PCS_GP, &val);
5772 val |= (3<<10);
5773 bnx2x_cl45_write(bp, phy,
5774 MDIO_PMA_DEVAD,
5775 MDIO_PMA_REG_8727_PCS_GP, val);
5776 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005777 } else if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
5778 ((phy->speed_cap_mask &
5779 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) &&
5780 ((phy->speed_cap_mask &
5781 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) !=
5782 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
5783
5784 DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
5785 bnx2x_cl45_write(bp, phy,
5786 MDIO_AN_DEVAD, MDIO_AN_REG_8727_MISC_CTRL, 0);
5787 bnx2x_cl45_write(bp, phy,
5788 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1300);
5789 } else {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005790 /*
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005791 * Since the 8727 has only single reset pin, need to set the 10G
5792 * registers although it is default
5793 */
5794 bnx2x_cl45_write(bp, phy,
5795 MDIO_AN_DEVAD, MDIO_AN_REG_8727_MISC_CTRL,
5796 0x0020);
5797 bnx2x_cl45_write(bp, phy,
5798 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x0100);
5799 bnx2x_cl45_write(bp, phy,
5800 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x2040);
5801 bnx2x_cl45_write(bp, phy,
5802 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2,
5803 0x0008);
5804 }
5805
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005806 /*
5807 * Set 2-wire transfer rate of SFP+ module EEPROM
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005808 * to 100Khz since some DACs(direct attached cables) do
5809 * not work at 400Khz.
5810 */
5811 bnx2x_cl45_write(bp, phy,
5812 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR,
5813 0xa001);
5814
5815 /* Set TX PreEmphasis if needed */
5816 if ((params->feature_config_flags &
5817 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
5818 DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x, TX_CTRL2 0x%x\n",
5819 phy->tx_preemphasis[0],
5820 phy->tx_preemphasis[1]);
5821 bnx2x_cl45_write(bp, phy,
5822 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TX_CTRL1,
5823 phy->tx_preemphasis[0]);
5824
5825 bnx2x_cl45_write(bp, phy,
5826 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TX_CTRL2,
5827 phy->tx_preemphasis[1]);
5828 }
5829
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00005830 /*
5831 * If TX Laser is controlled by GPIO_0, do not let PHY go into low
5832 * power mode, if TX Laser is disabled
5833 */
5834 tx_en_mode = REG_RD(bp, params->shmem_base +
5835 offsetof(struct shmem_region,
5836 dev_info.port_hw_config[params->port].sfp_ctrl))
5837 & PORT_HW_CFG_TX_LASER_MASK;
5838
5839 if (tx_en_mode == PORT_HW_CFG_TX_LASER_GPIO0) {
5840
5841 DP(NETIF_MSG_LINK, "Enabling TXONOFF_PWRDN_DIS\n");
5842 bnx2x_cl45_read(bp, phy,
5843 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_OPT_CFG_REG, &tmp2);
5844 tmp2 |= 0x1000;
5845 tmp2 &= 0xFFEF;
5846 bnx2x_cl45_write(bp, phy,
5847 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_OPT_CFG_REG, tmp2);
5848 }
5849
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005850 return 0;
5851}
5852
5853static void bnx2x_8727_handle_mod_abs(struct bnx2x_phy *phy,
5854 struct link_params *params)
5855{
5856 struct bnx2x *bp = params->bp;
5857 u16 mod_abs, rx_alarm_status;
5858 u32 val = REG_RD(bp, params->shmem_base +
5859 offsetof(struct shmem_region, dev_info.
5860 port_feature_config[params->port].
5861 config));
5862 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005863 MDIO_PMA_DEVAD,
5864 MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005865 if (mod_abs & (1<<8)) {
5866
5867 /* Module is absent */
5868 DP(NETIF_MSG_LINK, "MOD_ABS indication "
5869 "show module is absent\n");
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00005870 phy->media_type = ETH_PHY_NOT_PRESENT;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005871 /*
5872 * 1. Set mod_abs to detect next module
5873 * presence event
5874 * 2. Set EDC off by setting OPTXLOS signal input to low
5875 * (bit 9).
5876 * When the EDC is off it locks onto a reference clock and
5877 * avoids becoming 'lost'.
5878 */
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005879 mod_abs &= ~(1<<8);
5880 if (!(phy->flags & FLAGS_NOC))
5881 mod_abs &= ~(1<<9);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005882 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005883 MDIO_PMA_DEVAD,
5884 MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005885
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005886 /*
5887 * Clear RX alarm since it stays up as long as
5888 * the mod_abs wasn't changed
5889 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005890 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005891 MDIO_PMA_DEVAD,
5892 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005893
5894 } else {
5895 /* Module is present */
5896 DP(NETIF_MSG_LINK, "MOD_ABS indication "
5897 "show module is present\n");
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005898 /*
5899 * First disable transmitter, and if the module is ok, the
5900 * module_detection will enable it
5901 * 1. Set mod_abs to detect next module absent event ( bit 8)
5902 * 2. Restore the default polarity of the OPRXLOS signal and
5903 * this signal will then correctly indicate the presence or
5904 * absence of the Rx signal. (bit 9)
5905 */
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005906 mod_abs |= (1<<8);
5907 if (!(phy->flags & FLAGS_NOC))
5908 mod_abs |= (1<<9);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005909 bnx2x_cl45_write(bp, phy,
5910 MDIO_PMA_DEVAD,
5911 MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
5912
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005913 /*
5914 * Clear RX alarm since it stays up as long as the mod_abs
5915 * wasn't changed. This is need to be done before calling the
5916 * module detection, otherwise it will clear* the link update
5917 * alarm
5918 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005919 bnx2x_cl45_read(bp, phy,
5920 MDIO_PMA_DEVAD,
5921 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
5922
5923
5924 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
5925 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00005926 bnx2x_sfp_set_transmitter(params, phy, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005927
5928 if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0)
5929 bnx2x_sfp_module_detection(phy, params);
5930 else
5931 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
5932 }
5933
5934 DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n",
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005935 rx_alarm_status);
5936 /* No need to check link status in case of module plugged in/out */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005937}
5938
5939static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy,
5940 struct link_params *params,
5941 struct link_vars *vars)
5942
5943{
5944 struct bnx2x *bp = params->bp;
Yaniv Rosner27d02432011-05-31 21:27:48 +00005945 u8 link_up = 0, oc_port = params->port;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005946 u16 link_status = 0;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005947 u16 rx_alarm_status, lasi_ctrl, val1;
5948
5949 /* If PHY is not initialized, do not check link status */
5950 bnx2x_cl45_read(bp, phy,
5951 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL,
5952 &lasi_ctrl);
5953 if (!lasi_ctrl)
5954 return 0;
5955
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00005956 /* Check the LASI on Rx */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005957 bnx2x_cl45_read(bp, phy,
5958 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM,
5959 &rx_alarm_status);
5960 vars->line_speed = 0;
5961 DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n", rx_alarm_status);
5962
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00005963 bnx2x_sfp_mask_fault(bp, phy, MDIO_PMA_REG_TX_ALARM,
5964 MDIO_PMA_REG_TX_ALARM_CTRL);
5965
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005966 bnx2x_cl45_read(bp, phy,
5967 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
5968
5969 DP(NETIF_MSG_LINK, "8727 LASI status 0x%x\n", val1);
5970
5971 /* Clear MSG-OUT */
5972 bnx2x_cl45_read(bp, phy,
5973 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &val1);
5974
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005975 /*
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005976 * If a module is present and there is need to check
5977 * for over current
5978 */
5979 if (!(phy->flags & FLAGS_NOC) && !(rx_alarm_status & (1<<5))) {
5980 /* Check over-current using 8727 GPIO0 input*/
5981 bnx2x_cl45_read(bp, phy,
5982 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_GPIO_CTRL,
5983 &val1);
5984
5985 if ((val1 & (1<<8)) == 0) {
Yaniv Rosner27d02432011-05-31 21:27:48 +00005986 if (!CHIP_IS_E1x(bp))
5987 oc_port = BP_PATH(bp) + (params->port << 1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005988 DP(NETIF_MSG_LINK, "8727 Power fault has been detected"
Yaniv Rosner27d02432011-05-31 21:27:48 +00005989 " on port %d\n", oc_port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005990 netdev_err(bp->dev, "Error: Power fault on Port %d has"
5991 " been detected and the power to "
5992 "that SFP+ module has been removed"
5993 " to prevent failure of the card."
5994 " Please remove the SFP+ module and"
5995 " restart the system to clear this"
5996 " error.\n",
Yaniv Rosner27d02432011-05-31 21:27:48 +00005997 oc_port);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005998 /* Disable all RX_ALARMs except for mod_abs */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005999 bnx2x_cl45_write(bp, phy,
6000 MDIO_PMA_DEVAD,
6001 MDIO_PMA_REG_RX_ALARM_CTRL, (1<<5));
6002
6003 bnx2x_cl45_read(bp, phy,
6004 MDIO_PMA_DEVAD,
6005 MDIO_PMA_REG_PHY_IDENTIFIER, &val1);
6006 /* Wait for module_absent_event */
6007 val1 |= (1<<8);
6008 bnx2x_cl45_write(bp, phy,
6009 MDIO_PMA_DEVAD,
6010 MDIO_PMA_REG_PHY_IDENTIFIER, val1);
6011 /* Clear RX alarm */
6012 bnx2x_cl45_read(bp, phy,
6013 MDIO_PMA_DEVAD,
6014 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
6015 return 0;
6016 }
6017 } /* Over current check */
6018
6019 /* When module absent bit is set, check module */
6020 if (rx_alarm_status & (1<<5)) {
6021 bnx2x_8727_handle_mod_abs(phy, params);
6022 /* Enable all mod_abs and link detection bits */
6023 bnx2x_cl45_write(bp, phy,
6024 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
6025 ((1<<5) | (1<<2)));
6026 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006027 DP(NETIF_MSG_LINK, "Enabling 8727 TX laser if SFP is approved\n");
6028 bnx2x_8727_specific_func(phy, params, ENABLE_TX);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006029 /* If transmitter is disabled, ignore false link up indication */
6030 bnx2x_cl45_read(bp, phy,
6031 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, &val1);
6032 if (val1 & (1<<15)) {
6033 DP(NETIF_MSG_LINK, "Tx is disabled\n");
6034 return 0;
6035 }
6036
6037 bnx2x_cl45_read(bp, phy,
6038 MDIO_PMA_DEVAD,
6039 MDIO_PMA_REG_8073_SPEED_LINK_STATUS, &link_status);
6040
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006041 /*
6042 * Bits 0..2 --> speed detected,
6043 * Bits 13..15--> link is down
6044 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006045 if ((link_status & (1<<2)) && (!(link_status & (1<<15)))) {
6046 link_up = 1;
6047 vars->line_speed = SPEED_10000;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006048 DP(NETIF_MSG_LINK, "port %x: External link up in 10G\n",
6049 params->port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006050 } else if ((link_status & (1<<0)) && (!(link_status & (1<<13)))) {
6051 link_up = 1;
6052 vars->line_speed = SPEED_1000;
6053 DP(NETIF_MSG_LINK, "port %x: External link up in 1G\n",
6054 params->port);
6055 } else {
6056 link_up = 0;
6057 DP(NETIF_MSG_LINK, "port %x: External link is down\n",
6058 params->port);
6059 }
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00006060
6061 /* Capture 10G link fault. */
6062 if (vars->line_speed == SPEED_10000) {
6063 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
6064 MDIO_PMA_REG_TX_ALARM, &val1);
6065
6066 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
6067 MDIO_PMA_REG_TX_ALARM, &val1);
6068
6069 if (val1 & (1<<0)) {
6070 vars->fault_detected = 1;
6071 }
6072 }
6073
Yaniv Rosner791f18c2011-01-18 04:33:42 +00006074 if (link_up) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006075 bnx2x_ext_phy_resolve_fc(phy, params, vars);
Yaniv Rosner791f18c2011-01-18 04:33:42 +00006076 vars->duplex = DUPLEX_FULL;
6077 DP(NETIF_MSG_LINK, "duplex = 0x%x\n", vars->duplex);
6078 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006079
6080 if ((DUAL_MEDIA(params)) &&
6081 (phy->req_line_speed == SPEED_1000)) {
6082 bnx2x_cl45_read(bp, phy,
6083 MDIO_PMA_DEVAD,
6084 MDIO_PMA_REG_8727_PCS_GP, &val1);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006085 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006086 * In case of dual-media board and 1G, power up the XAUI side,
6087 * otherwise power it down. For 10G it is done automatically
6088 */
6089 if (link_up)
6090 val1 &= ~(3<<10);
6091 else
6092 val1 |= (3<<10);
6093 bnx2x_cl45_write(bp, phy,
6094 MDIO_PMA_DEVAD,
6095 MDIO_PMA_REG_8727_PCS_GP, val1);
6096 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006097 return link_up;
6098}
6099
6100static void bnx2x_8727_link_reset(struct bnx2x_phy *phy,
6101 struct link_params *params)
6102{
6103 struct bnx2x *bp = params->bp;
6104 /* Disable Transmitter */
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00006105 bnx2x_sfp_set_transmitter(params, phy, 0);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006106 /* Clear LASI */
6107 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0);
6108
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006109}
6110
6111/******************************************************************/
6112/* BCM8481/BCM84823/BCM84833 PHY SECTION */
6113/******************************************************************/
6114static void bnx2x_save_848xx_spirom_version(struct bnx2x_phy *phy,
6115 struct link_params *params)
6116{
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006117 u16 val, fw_ver1, fw_ver2, cnt;
6118 u8 port;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006119 struct bnx2x *bp = params->bp;
6120
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006121 port = params->port;
Yaniv Rosnerc87bca12011-01-31 04:22:41 +00006122
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006123 /* For the 32 bits registers in 848xx, access via MDIO2ARM interface.*/
6124 /* (1) set register 0xc200_0014(SPI_BRIDGE_CTRL_2) to 0x03000000 */
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006125 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0014);
6126 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200);
6127 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81B, 0x0000);
6128 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81C, 0x0300);
6129 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x0009);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006130
6131 for (cnt = 0; cnt < 100; cnt++) {
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006132 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006133 if (val & 1)
6134 break;
6135 udelay(5);
6136 }
6137 if (cnt == 100) {
6138 DP(NETIF_MSG_LINK, "Unable to read 848xx phy fw version(1)\n");
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006139 bnx2x_save_spirom_version(bp, port, 0,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006140 phy->ver_addr);
6141 return;
6142 }
6143
6144
6145 /* 2) read register 0xc200_0000 (SPI_FW_STATUS) */
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006146 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0000);
6147 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200);
6148 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x000A);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006149 for (cnt = 0; cnt < 100; cnt++) {
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006150 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006151 if (val & 1)
6152 break;
6153 udelay(5);
6154 }
6155 if (cnt == 100) {
6156 DP(NETIF_MSG_LINK, "Unable to read 848xx phy fw version(2)\n");
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006157 bnx2x_save_spirom_version(bp, port, 0,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006158 phy->ver_addr);
6159 return;
6160 }
6161
6162 /* lower 16 bits of the register SPI_FW_STATUS */
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006163 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81B, &fw_ver1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006164 /* upper 16 bits of register SPI_FW_STATUS */
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006165 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81C, &fw_ver2);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006166
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006167 bnx2x_save_spirom_version(bp, port, (fw_ver2<<16) | fw_ver1,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006168 phy->ver_addr);
6169}
6170
6171static void bnx2x_848xx_set_led(struct bnx2x *bp,
6172 struct bnx2x_phy *phy)
6173{
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006174 u16 val;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006175
6176 /* PHYC_CTL_LED_CTL */
6177 bnx2x_cl45_read(bp, phy,
6178 MDIO_PMA_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006179 MDIO_PMA_REG_8481_LINK_SIGNAL, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006180 val &= 0xFE00;
6181 val |= 0x0092;
6182
6183 bnx2x_cl45_write(bp, phy,
6184 MDIO_PMA_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006185 MDIO_PMA_REG_8481_LINK_SIGNAL, val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006186
6187 bnx2x_cl45_write(bp, phy,
6188 MDIO_PMA_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006189 MDIO_PMA_REG_8481_LED1_MASK,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006190 0x80);
6191
6192 bnx2x_cl45_write(bp, phy,
6193 MDIO_PMA_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006194 MDIO_PMA_REG_8481_LED2_MASK,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006195 0x18);
6196
Yaniv Rosnerf25b3c82011-01-18 04:33:47 +00006197 /* Select activity source by Tx and Rx, as suggested by PHY AE */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006198 bnx2x_cl45_write(bp, phy,
6199 MDIO_PMA_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006200 MDIO_PMA_REG_8481_LED3_MASK,
Yaniv Rosnerf25b3c82011-01-18 04:33:47 +00006201 0x0006);
6202
6203 /* Select the closest activity blink rate to that in 10/100/1000 */
6204 bnx2x_cl45_write(bp, phy,
6205 MDIO_PMA_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006206 MDIO_PMA_REG_8481_LED3_BLINK,
Yaniv Rosnerf25b3c82011-01-18 04:33:47 +00006207 0);
6208
6209 bnx2x_cl45_read(bp, phy,
6210 MDIO_PMA_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006211 MDIO_PMA_REG_84823_CTL_LED_CTL_1, &val);
Yaniv Rosnerf25b3c82011-01-18 04:33:47 +00006212 val |= MDIO_PMA_REG_84823_LED3_STRETCH_EN; /* stretch_en for LED3*/
6213
6214 bnx2x_cl45_write(bp, phy,
6215 MDIO_PMA_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006216 MDIO_PMA_REG_84823_CTL_LED_CTL_1, val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006217
6218 /* 'Interrupt Mask' */
6219 bnx2x_cl45_write(bp, phy,
6220 MDIO_AN_DEVAD,
6221 0xFFFB, 0xFFFD);
6222}
6223
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006224static int bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy,
6225 struct link_params *params,
6226 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006227{
6228 struct bnx2x *bp = params->bp;
6229 u16 autoneg_val, an_1000_val, an_10_100_val;
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006230 u16 tmp_req_line_speed;
6231
6232 tmp_req_line_speed = phy->req_line_speed;
6233 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833)
6234 if (phy->req_line_speed == SPEED_10000)
6235 phy->req_line_speed = SPEED_AUTO_NEG;
6236
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006237 /*
6238 * This phy uses the NIG latch mechanism since link indication
6239 * arrives through its LED4 and not via its LASI signal, so we
6240 * get steady signal instead of clear on read
6241 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006242 bnx2x_bits_en(bp, NIG_REG_LATCH_BC_0 + params->port*4,
6243 1 << NIG_LATCH_BC_ENABLE_MI_INT);
6244
6245 bnx2x_cl45_write(bp, phy,
6246 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x0000);
6247
6248 bnx2x_848xx_set_led(bp, phy);
6249
6250 /* set 1000 speed advertisement */
6251 bnx2x_cl45_read(bp, phy,
6252 MDIO_AN_DEVAD, MDIO_AN_REG_8481_1000T_CTRL,
6253 &an_1000_val);
6254
6255 bnx2x_ext_phy_set_pause(params, phy, vars);
6256 bnx2x_cl45_read(bp, phy,
6257 MDIO_AN_DEVAD,
6258 MDIO_AN_REG_8481_LEGACY_AN_ADV,
6259 &an_10_100_val);
6260 bnx2x_cl45_read(bp, phy,
6261 MDIO_AN_DEVAD, MDIO_AN_REG_8481_LEGACY_MII_CTRL,
6262 &autoneg_val);
6263 /* Disable forced speed */
6264 autoneg_val &= ~((1<<6) | (1<<8) | (1<<9) | (1<<12) | (1<<13));
6265 an_10_100_val &= ~((1<<5) | (1<<6) | (1<<7) | (1<<8));
6266
6267 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
6268 (phy->speed_cap_mask &
6269 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) ||
6270 (phy->req_line_speed == SPEED_1000)) {
6271 an_1000_val |= (1<<8);
6272 autoneg_val |= (1<<9 | 1<<12);
6273 if (phy->req_duplex == DUPLEX_FULL)
6274 an_1000_val |= (1<<9);
6275 DP(NETIF_MSG_LINK, "Advertising 1G\n");
6276 } else
6277 an_1000_val &= ~((1<<8) | (1<<9));
6278
6279 bnx2x_cl45_write(bp, phy,
6280 MDIO_AN_DEVAD, MDIO_AN_REG_8481_1000T_CTRL,
6281 an_1000_val);
6282
6283 /* set 10 speed advertisement */
6284 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
6285 (phy->speed_cap_mask &
6286 (PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL |
6287 PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF)))) {
6288 an_10_100_val |= (1<<7);
6289 /* Enable autoneg and restart autoneg for legacy speeds */
6290 autoneg_val |= (1<<9 | 1<<12);
6291
6292 if (phy->req_duplex == DUPLEX_FULL)
6293 an_10_100_val |= (1<<8);
6294 DP(NETIF_MSG_LINK, "Advertising 100M\n");
6295 }
6296 /* set 10 speed advertisement */
6297 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
6298 (phy->speed_cap_mask &
6299 (PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL |
6300 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF)))) {
6301 an_10_100_val |= (1<<5);
6302 autoneg_val |= (1<<9 | 1<<12);
6303 if (phy->req_duplex == DUPLEX_FULL)
6304 an_10_100_val |= (1<<6);
6305 DP(NETIF_MSG_LINK, "Advertising 10M\n");
6306 }
6307
6308 /* Only 10/100 are allowed to work in FORCE mode */
6309 if (phy->req_line_speed == SPEED_100) {
6310 autoneg_val |= (1<<13);
6311 /* Enabled AUTO-MDIX when autoneg is disabled */
6312 bnx2x_cl45_write(bp, phy,
6313 MDIO_AN_DEVAD, MDIO_AN_REG_8481_AUX_CTRL,
6314 (1<<15 | 1<<9 | 7<<0));
6315 DP(NETIF_MSG_LINK, "Setting 100M force\n");
6316 }
6317 if (phy->req_line_speed == SPEED_10) {
6318 /* Enabled AUTO-MDIX when autoneg is disabled */
6319 bnx2x_cl45_write(bp, phy,
6320 MDIO_AN_DEVAD, MDIO_AN_REG_8481_AUX_CTRL,
6321 (1<<15 | 1<<9 | 7<<0));
6322 DP(NETIF_MSG_LINK, "Setting 10M force\n");
6323 }
6324
6325 bnx2x_cl45_write(bp, phy,
6326 MDIO_AN_DEVAD, MDIO_AN_REG_8481_LEGACY_AN_ADV,
6327 an_10_100_val);
6328
6329 if (phy->req_duplex == DUPLEX_FULL)
6330 autoneg_val |= (1<<8);
6331
6332 bnx2x_cl45_write(bp, phy,
6333 MDIO_AN_DEVAD,
6334 MDIO_AN_REG_8481_LEGACY_MII_CTRL, autoneg_val);
6335
6336 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
6337 (phy->speed_cap_mask &
6338 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) ||
6339 (phy->req_line_speed == SPEED_10000)) {
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00006340 DP(NETIF_MSG_LINK, "Advertising 10G\n");
6341 /* Restart autoneg for 10G*/
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006342
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00006343 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006344 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL,
6345 0x3200);
6346 } else if (phy->req_line_speed != SPEED_10 &&
6347 phy->req_line_speed != SPEED_100) {
6348 bnx2x_cl45_write(bp, phy,
6349 MDIO_AN_DEVAD,
6350 MDIO_AN_REG_8481_10GBASE_T_AN_CTRL,
6351 1);
6352 }
6353 /* Save spirom version */
6354 bnx2x_save_848xx_spirom_version(phy, params);
6355
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006356 phy->req_line_speed = tmp_req_line_speed;
6357
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006358 return 0;
6359}
6360
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006361static int bnx2x_8481_config_init(struct bnx2x_phy *phy,
6362 struct link_params *params,
6363 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006364{
6365 struct bnx2x *bp = params->bp;
6366 /* Restore normal power mode*/
6367 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006368 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006369
6370 /* HW reset */
6371 bnx2x_ext_phy_hw_reset(bp, params->port);
Yaniv Rosner6d870c32011-01-31 04:22:20 +00006372 bnx2x_wait_reset_complete(bp, phy, params);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006373
6374 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
6375 return bnx2x_848xx_cmn_config_init(phy, params, vars);
6376}
6377
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006378
6379#define PHY84833_HDSHK_WAIT 300
6380static int bnx2x_84833_pair_swap_cfg(struct bnx2x_phy *phy,
6381 struct link_params *params,
6382 struct link_vars *vars)
6383{
6384 u32 idx;
6385 u16 val;
6386 u16 data = 0x01b1;
6387 struct bnx2x *bp = params->bp;
6388 /* Do pair swap */
6389
6390
6391 /* Write CMD_OPEN_OVERRIDE to STATUS reg */
6392 bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
6393 MDIO_84833_TOP_CFG_SCRATCH_REG2,
6394 PHY84833_CMD_OPEN_OVERRIDE);
6395 for (idx = 0; idx < PHY84833_HDSHK_WAIT; idx++) {
6396 bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
6397 MDIO_84833_TOP_CFG_SCRATCH_REG2, &val);
6398 if (val == PHY84833_CMD_OPEN_FOR_CMDS)
6399 break;
6400 msleep(1);
6401 }
6402 if (idx >= PHY84833_HDSHK_WAIT) {
6403 DP(NETIF_MSG_LINK, "Pairswap: FW not ready.\n");
6404 return -EINVAL;
6405 }
6406
6407 bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
6408 MDIO_84833_TOP_CFG_SCRATCH_REG4,
6409 data);
6410 /* Issue pair swap command */
6411 bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
6412 MDIO_84833_TOP_CFG_SCRATCH_REG0,
6413 PHY84833_DIAG_CMD_PAIR_SWAP_CHANGE);
6414 for (idx = 0; idx < PHY84833_HDSHK_WAIT; idx++) {
6415 bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
6416 MDIO_84833_TOP_CFG_SCRATCH_REG2, &val);
6417 if ((val == PHY84833_CMD_COMPLETE_PASS) ||
6418 (val == PHY84833_CMD_COMPLETE_ERROR))
6419 break;
6420 msleep(1);
6421 }
6422 if ((idx >= PHY84833_HDSHK_WAIT) ||
6423 (val == PHY84833_CMD_COMPLETE_ERROR)) {
6424 DP(NETIF_MSG_LINK, "Pairswap: override failed.\n");
6425 return -EINVAL;
6426 }
6427 bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
6428 MDIO_84833_TOP_CFG_SCRATCH_REG2,
6429 PHY84833_CMD_CLEAR_COMPLETE);
6430 DP(NETIF_MSG_LINK, "Pairswap OK, val=0x%x\n", data);
6431 return 0;
6432}
6433
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006434static int bnx2x_848x3_config_init(struct bnx2x_phy *phy,
6435 struct link_params *params,
6436 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006437{
6438 struct bnx2x *bp = params->bp;
Yaniv Rosner6a71bbe2010-11-01 05:32:31 +00006439 u8 port, initialize = 1;
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006440 u16 val;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006441 u16 temp;
Yaniv Rosner1bef68e2011-01-31 04:22:46 +00006442 u32 actual_phy_selection, cms_enable;
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006443 int rc = 0;
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006444
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006445 msleep(1);
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006446
6447 if (!(CHIP_IS_E1(bp)))
Yaniv Rosner6a71bbe2010-11-01 05:32:31 +00006448 port = BP_PATH(bp);
6449 else
6450 port = params->port;
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006451
6452 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823) {
6453 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
6454 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
6455 port);
6456 } else {
6457 bnx2x_cl45_write(bp, phy,
6458 MDIO_PMA_DEVAD,
6459 MDIO_PMA_REG_CTRL, 0x8000);
6460 }
6461
Yaniv Rosner6d870c32011-01-31 04:22:20 +00006462 bnx2x_wait_reset_complete(bp, phy, params);
Yaniv Rosner9bffeac2010-11-01 05:32:27 +00006463 /* Wait for GPHY to come out of reset */
6464 msleep(50);
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006465
6466 /* Bring PHY out of super isolate mode */
6467 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) {
6468 bnx2x_cl45_read(bp, phy,
6469 MDIO_CTL_DEVAD,
6470 MDIO_84833_TOP_CFG_XGPHY_STRAP1, &val);
6471 val &= ~MDIO_84833_SUPER_ISOLATE;
6472 bnx2x_cl45_write(bp, phy,
6473 MDIO_CTL_DEVAD,
6474 MDIO_84833_TOP_CFG_XGPHY_STRAP1, val);
6475 bnx2x_wait_reset_complete(bp, phy, params);
6476 }
6477
6478 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833)
6479 bnx2x_84833_pair_swap_cfg(phy, params, vars);
6480
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006481 /*
6482 * BCM84823 requires that XGXS links up first @ 10G for normal behavior
6483 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006484 temp = vars->line_speed;
6485 vars->line_speed = SPEED_10000;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006486 bnx2x_set_autoneg(&params->phy[INT_PHY], params, vars, 0);
6487 bnx2x_program_serdes(&params->phy[INT_PHY], params, vars);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006488 vars->line_speed = temp;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006489
6490 /* Set dual-media configuration according to configuration */
6491
6492 bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006493 MDIO_CTL_REG_84823_MEDIA, &val);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006494 val &= ~(MDIO_CTL_REG_84823_MEDIA_MAC_MASK |
6495 MDIO_CTL_REG_84823_MEDIA_LINE_MASK |
6496 MDIO_CTL_REG_84823_MEDIA_COPPER_CORE_DOWN |
6497 MDIO_CTL_REG_84823_MEDIA_PRIORITY_MASK |
6498 MDIO_CTL_REG_84823_MEDIA_FIBER_1G);
6499 val |= MDIO_CTL_REG_84823_CTRL_MAC_XFI |
6500 MDIO_CTL_REG_84823_MEDIA_LINE_XAUI_L;
6501
6502 actual_phy_selection = bnx2x_phy_selection(params);
6503
6504 switch (actual_phy_selection) {
6505 case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT:
Lucas De Marchi25985ed2011-03-30 22:57:33 -03006506 /* Do nothing. Essentially this is like the priority copper */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006507 break;
6508 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
6509 val |= MDIO_CTL_REG_84823_MEDIA_PRIORITY_COPPER;
6510 break;
6511 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
6512 val |= MDIO_CTL_REG_84823_MEDIA_PRIORITY_FIBER;
6513 break;
6514 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY:
6515 /* Do nothing here. The first PHY won't be initialized at all */
6516 break;
6517 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY:
6518 val |= MDIO_CTL_REG_84823_MEDIA_COPPER_CORE_DOWN;
6519 initialize = 0;
6520 break;
6521 }
6522 if (params->phy[EXT_PHY2].req_line_speed == SPEED_1000)
6523 val |= MDIO_CTL_REG_84823_MEDIA_FIBER_1G;
6524
6525 bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006526 MDIO_CTL_REG_84823_MEDIA, val);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006527 DP(NETIF_MSG_LINK, "Multi_phy config = 0x%x, Media control = 0x%x\n",
6528 params->multi_phy_config, val);
6529
6530 if (initialize)
6531 rc = bnx2x_848xx_cmn_config_init(phy, params, vars);
6532 else
6533 bnx2x_save_848xx_spirom_version(phy, params);
Yaniv Rosner1bef68e2011-01-31 04:22:46 +00006534 cms_enable = REG_RD(bp, params->shmem_base +
6535 offsetof(struct shmem_region,
6536 dev_info.port_hw_config[params->port].default_cfg)) &
6537 PORT_HW_CFG_ENABLE_CMS_MASK;
6538
6539 bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
6540 MDIO_CTL_REG_84823_USER_CTRL_REG, &val);
6541 if (cms_enable)
6542 val |= MDIO_CTL_REG_84823_USER_CTRL_CMS;
6543 else
6544 val &= ~MDIO_CTL_REG_84823_USER_CTRL_CMS;
6545 bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
6546 MDIO_CTL_REG_84823_USER_CTRL_REG, val);
6547
6548
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006549 return rc;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006550}
6551
6552static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006553 struct link_params *params,
6554 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006555{
6556 struct bnx2x *bp = params->bp;
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006557 u16 val, val1, val2;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006558 u8 link_up = 0;
6559
Yaniv Rosnerc87bca12011-01-31 04:22:41 +00006560
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006561 /* Check 10G-BaseT link status */
6562 /* Check PMD signal ok */
6563 bnx2x_cl45_read(bp, phy,
6564 MDIO_AN_DEVAD, 0xFFFA, &val1);
6565 bnx2x_cl45_read(bp, phy,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006566 MDIO_PMA_DEVAD, MDIO_PMA_REG_8481_PMD_SIGNAL,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006567 &val2);
6568 DP(NETIF_MSG_LINK, "BCM848xx: PMD_SIGNAL 1.a811 = 0x%x\n", val2);
6569
6570 /* Check link 10G */
6571 if (val2 & (1<<11)) {
6572 vars->line_speed = SPEED_10000;
Yaniv Rosner791f18c2011-01-18 04:33:42 +00006573 vars->duplex = DUPLEX_FULL;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006574 link_up = 1;
6575 bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
6576 } else { /* Check Legacy speed link */
6577 u16 legacy_status, legacy_speed;
6578
6579 /* Enable expansion register 0x42 (Operation mode status) */
6580 bnx2x_cl45_write(bp, phy,
6581 MDIO_AN_DEVAD,
6582 MDIO_AN_REG_8481_EXPANSION_REG_ACCESS, 0xf42);
6583
6584 /* Get legacy speed operation status */
6585 bnx2x_cl45_read(bp, phy,
6586 MDIO_AN_DEVAD,
6587 MDIO_AN_REG_8481_EXPANSION_REG_RD_RW,
6588 &legacy_status);
6589
6590 DP(NETIF_MSG_LINK, "Legacy speed status"
6591 " = 0x%x\n", legacy_status);
6592 link_up = ((legacy_status & (1<<11)) == (1<<11));
6593 if (link_up) {
6594 legacy_speed = (legacy_status & (3<<9));
6595 if (legacy_speed == (0<<9))
6596 vars->line_speed = SPEED_10;
6597 else if (legacy_speed == (1<<9))
6598 vars->line_speed = SPEED_100;
6599 else if (legacy_speed == (2<<9))
6600 vars->line_speed = SPEED_1000;
6601 else /* Should not happen */
6602 vars->line_speed = 0;
6603
6604 if (legacy_status & (1<<8))
6605 vars->duplex = DUPLEX_FULL;
6606 else
6607 vars->duplex = DUPLEX_HALF;
6608
6609 DP(NETIF_MSG_LINK, "Link is up in %dMbps,"
6610 " is_duplex_full= %d\n", vars->line_speed,
6611 (vars->duplex == DUPLEX_FULL));
6612 /* Check legacy speed AN resolution */
6613 bnx2x_cl45_read(bp, phy,
6614 MDIO_AN_DEVAD,
6615 MDIO_AN_REG_8481_LEGACY_MII_STATUS,
6616 &val);
6617 if (val & (1<<5))
6618 vars->link_status |=
6619 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
6620 bnx2x_cl45_read(bp, phy,
6621 MDIO_AN_DEVAD,
6622 MDIO_AN_REG_8481_LEGACY_AN_EXPANSION,
6623 &val);
6624 if ((val & (1<<0)) == 0)
6625 vars->link_status |=
6626 LINK_STATUS_PARALLEL_DETECTION_USED;
6627 }
6628 }
6629 if (link_up) {
6630 DP(NETIF_MSG_LINK, "BCM84823: link speed is %d\n",
6631 vars->line_speed);
6632 bnx2x_ext_phy_resolve_fc(phy, params, vars);
6633 }
6634
6635 return link_up;
6636}
6637
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006638
6639static int bnx2x_848xx_format_ver(u32 raw_ver, u8 *str, u16 *len)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006640{
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006641 int status = 0;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006642 u32 spirom_ver;
6643 spirom_ver = ((raw_ver & 0xF80) >> 7) << 16 | (raw_ver & 0x7F);
6644 status = bnx2x_format_ver(spirom_ver, str, len);
6645 return status;
6646}
6647
6648static void bnx2x_8481_hw_reset(struct bnx2x_phy *phy,
6649 struct link_params *params)
6650{
6651 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006652 MISC_REGISTERS_GPIO_OUTPUT_LOW, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006653 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006654 MISC_REGISTERS_GPIO_OUTPUT_LOW, 1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006655}
6656
6657static void bnx2x_8481_link_reset(struct bnx2x_phy *phy,
6658 struct link_params *params)
6659{
6660 bnx2x_cl45_write(params->bp, phy,
6661 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x0000);
6662 bnx2x_cl45_write(params->bp, phy,
6663 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1);
6664}
6665
6666static void bnx2x_848x3_link_reset(struct bnx2x_phy *phy,
6667 struct link_params *params)
6668{
6669 struct bnx2x *bp = params->bp;
Yaniv Rosner6a71bbe2010-11-01 05:32:31 +00006670 u8 port;
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006671
6672 if (!(CHIP_IS_E1(bp)))
Yaniv Rosner6a71bbe2010-11-01 05:32:31 +00006673 port = BP_PATH(bp);
6674 else
6675 port = params->port;
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006676
6677 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823) {
6678 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
6679 MISC_REGISTERS_GPIO_OUTPUT_LOW,
6680 port);
6681 } else {
6682 bnx2x_cl45_write(bp, phy,
6683 MDIO_PMA_DEVAD,
6684 MDIO_PMA_REG_CTRL, 0x800);
6685 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006686}
6687
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006688static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy,
6689 struct link_params *params, u8 mode)
6690{
6691 struct bnx2x *bp = params->bp;
6692 u16 val;
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006693 u8 port;
6694
6695 if (!(CHIP_IS_E1(bp)))
6696 port = BP_PATH(bp);
6697 else
6698 port = params->port;
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006699
6700 switch (mode) {
6701 case LED_MODE_OFF:
6702
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006703 DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE OFF\n", port);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006704
6705 if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
6706 SHARED_HW_CFG_LED_EXTPHY1) {
6707
6708 /* Set LED masks */
6709 bnx2x_cl45_write(bp, phy,
6710 MDIO_PMA_DEVAD,
6711 MDIO_PMA_REG_8481_LED1_MASK,
6712 0x0);
6713
6714 bnx2x_cl45_write(bp, phy,
6715 MDIO_PMA_DEVAD,
6716 MDIO_PMA_REG_8481_LED2_MASK,
6717 0x0);
6718
6719 bnx2x_cl45_write(bp, phy,
6720 MDIO_PMA_DEVAD,
6721 MDIO_PMA_REG_8481_LED3_MASK,
6722 0x0);
6723
6724 bnx2x_cl45_write(bp, phy,
6725 MDIO_PMA_DEVAD,
6726 MDIO_PMA_REG_8481_LED5_MASK,
6727 0x0);
6728
6729 } else {
6730 bnx2x_cl45_write(bp, phy,
6731 MDIO_PMA_DEVAD,
6732 MDIO_PMA_REG_8481_LED1_MASK,
6733 0x0);
6734 }
6735 break;
6736 case LED_MODE_FRONT_PANEL_OFF:
6737
6738 DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE FRONT PANEL OFF\n",
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006739 port);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006740
6741 if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
6742 SHARED_HW_CFG_LED_EXTPHY1) {
6743
6744 /* Set LED masks */
6745 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006746 MDIO_PMA_DEVAD,
6747 MDIO_PMA_REG_8481_LED1_MASK,
6748 0x0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006749
6750 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006751 MDIO_PMA_DEVAD,
6752 MDIO_PMA_REG_8481_LED2_MASK,
6753 0x0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006754
6755 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006756 MDIO_PMA_DEVAD,
6757 MDIO_PMA_REG_8481_LED3_MASK,
6758 0x0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006759
6760 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006761 MDIO_PMA_DEVAD,
6762 MDIO_PMA_REG_8481_LED5_MASK,
6763 0x20);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006764
6765 } else {
6766 bnx2x_cl45_write(bp, phy,
6767 MDIO_PMA_DEVAD,
6768 MDIO_PMA_REG_8481_LED1_MASK,
6769 0x0);
6770 }
6771 break;
6772 case LED_MODE_ON:
6773
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006774 DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE ON\n", port);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006775
6776 if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
6777 SHARED_HW_CFG_LED_EXTPHY1) {
6778 /* Set control reg */
6779 bnx2x_cl45_read(bp, phy,
6780 MDIO_PMA_DEVAD,
6781 MDIO_PMA_REG_8481_LINK_SIGNAL,
6782 &val);
6783 val &= 0x8000;
6784 val |= 0x2492;
6785
6786 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006787 MDIO_PMA_DEVAD,
6788 MDIO_PMA_REG_8481_LINK_SIGNAL,
6789 val);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006790
6791 /* Set LED masks */
6792 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006793 MDIO_PMA_DEVAD,
6794 MDIO_PMA_REG_8481_LED1_MASK,
6795 0x0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006796
6797 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006798 MDIO_PMA_DEVAD,
6799 MDIO_PMA_REG_8481_LED2_MASK,
6800 0x20);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006801
6802 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006803 MDIO_PMA_DEVAD,
6804 MDIO_PMA_REG_8481_LED3_MASK,
6805 0x20);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006806
6807 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006808 MDIO_PMA_DEVAD,
6809 MDIO_PMA_REG_8481_LED5_MASK,
6810 0x0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006811 } else {
6812 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006813 MDIO_PMA_DEVAD,
6814 MDIO_PMA_REG_8481_LED1_MASK,
6815 0x20);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006816 }
6817 break;
6818
6819 case LED_MODE_OPER:
6820
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006821 DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE OPER\n", port);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006822
6823 if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
6824 SHARED_HW_CFG_LED_EXTPHY1) {
6825
6826 /* Set control reg */
6827 bnx2x_cl45_read(bp, phy,
6828 MDIO_PMA_DEVAD,
6829 MDIO_PMA_REG_8481_LINK_SIGNAL,
6830 &val);
6831
6832 if (!((val &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006833 MDIO_PMA_REG_8481_LINK_SIGNAL_LED4_ENABLE_MASK)
6834 >> MDIO_PMA_REG_8481_LINK_SIGNAL_LED4_ENABLE_SHIFT)) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006835 DP(NETIF_MSG_LINK, "Setting LINK_SIGNAL\n");
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006836 bnx2x_cl45_write(bp, phy,
6837 MDIO_PMA_DEVAD,
6838 MDIO_PMA_REG_8481_LINK_SIGNAL,
6839 0xa492);
6840 }
6841
6842 /* Set LED masks */
6843 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006844 MDIO_PMA_DEVAD,
6845 MDIO_PMA_REG_8481_LED1_MASK,
6846 0x10);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006847
6848 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006849 MDIO_PMA_DEVAD,
6850 MDIO_PMA_REG_8481_LED2_MASK,
6851 0x80);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006852
6853 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006854 MDIO_PMA_DEVAD,
6855 MDIO_PMA_REG_8481_LED3_MASK,
6856 0x98);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006857
6858 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006859 MDIO_PMA_DEVAD,
6860 MDIO_PMA_REG_8481_LED5_MASK,
6861 0x40);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006862
6863 } else {
6864 bnx2x_cl45_write(bp, phy,
6865 MDIO_PMA_DEVAD,
6866 MDIO_PMA_REG_8481_LED1_MASK,
6867 0x80);
Yaniv Rosner53eda062011-01-30 04:14:55 +00006868
6869 /* Tell LED3 to blink on source */
6870 bnx2x_cl45_read(bp, phy,
6871 MDIO_PMA_DEVAD,
6872 MDIO_PMA_REG_8481_LINK_SIGNAL,
6873 &val);
6874 val &= ~(7<<6);
6875 val |= (1<<6); /* A83B[8:6]= 1 */
6876 bnx2x_cl45_write(bp, phy,
6877 MDIO_PMA_DEVAD,
6878 MDIO_PMA_REG_8481_LINK_SIGNAL,
6879 val);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006880 }
6881 break;
6882 }
6883}
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006884/******************************************************************/
6885/* SFX7101 PHY SECTION */
6886/******************************************************************/
6887static void bnx2x_7101_config_loopback(struct bnx2x_phy *phy,
6888 struct link_params *params)
6889{
6890 struct bnx2x *bp = params->bp;
6891 /* SFX7101_XGXS_TEST1 */
6892 bnx2x_cl45_write(bp, phy,
6893 MDIO_XS_DEVAD, MDIO_XS_SFX7101_XGXS_TEST1, 0x100);
6894}
6895
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006896static int bnx2x_7101_config_init(struct bnx2x_phy *phy,
6897 struct link_params *params,
6898 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006899{
6900 u16 fw_ver1, fw_ver2, val;
6901 struct bnx2x *bp = params->bp;
6902 DP(NETIF_MSG_LINK, "Setting the SFX7101 LASI indication\n");
6903
6904 /* Restore normal power mode*/
6905 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006906 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006907 /* HW reset */
6908 bnx2x_ext_phy_hw_reset(bp, params->port);
Yaniv Rosner6d870c32011-01-31 04:22:20 +00006909 bnx2x_wait_reset_complete(bp, phy, params);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006910
6911 bnx2x_cl45_write(bp, phy,
6912 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x1);
6913 DP(NETIF_MSG_LINK, "Setting the SFX7101 LED to blink on traffic\n");
6914 bnx2x_cl45_write(bp, phy,
6915 MDIO_PMA_DEVAD, MDIO_PMA_REG_7107_LED_CNTL, (1<<3));
6916
6917 bnx2x_ext_phy_set_pause(params, phy, vars);
6918 /* Restart autoneg */
6919 bnx2x_cl45_read(bp, phy,
6920 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, &val);
6921 val |= 0x200;
6922 bnx2x_cl45_write(bp, phy,
6923 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, val);
6924
6925 /* Save spirom version */
6926 bnx2x_cl45_read(bp, phy,
6927 MDIO_PMA_DEVAD, MDIO_PMA_REG_7101_VER1, &fw_ver1);
6928
6929 bnx2x_cl45_read(bp, phy,
6930 MDIO_PMA_DEVAD, MDIO_PMA_REG_7101_VER2, &fw_ver2);
6931 bnx2x_save_spirom_version(bp, params->port,
6932 (u32)(fw_ver1<<16 | fw_ver2), phy->ver_addr);
6933 return 0;
6934}
6935
6936static u8 bnx2x_7101_read_status(struct bnx2x_phy *phy,
6937 struct link_params *params,
6938 struct link_vars *vars)
6939{
6940 struct bnx2x *bp = params->bp;
6941 u8 link_up;
6942 u16 val1, val2;
6943 bnx2x_cl45_read(bp, phy,
6944 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val2);
6945 bnx2x_cl45_read(bp, phy,
6946 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
6947 DP(NETIF_MSG_LINK, "10G-base-T LASI status 0x%x->0x%x\n",
6948 val2, val1);
6949 bnx2x_cl45_read(bp, phy,
6950 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
6951 bnx2x_cl45_read(bp, phy,
6952 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
6953 DP(NETIF_MSG_LINK, "10G-base-T PMA status 0x%x->0x%x\n",
6954 val2, val1);
6955 link_up = ((val1 & 4) == 4);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006956 /* if link is up print the AN outcome of the SFX7101 PHY */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006957 if (link_up) {
6958 bnx2x_cl45_read(bp, phy,
6959 MDIO_AN_DEVAD, MDIO_AN_REG_MASTER_STATUS,
6960 &val2);
6961 vars->line_speed = SPEED_10000;
Yaniv Rosner791f18c2011-01-18 04:33:42 +00006962 vars->duplex = DUPLEX_FULL;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006963 DP(NETIF_MSG_LINK, "SFX7101 AN status 0x%x->Master=%x\n",
6964 val2, (val2 & (1<<14)));
6965 bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
6966 bnx2x_ext_phy_resolve_fc(phy, params, vars);
6967 }
6968 return link_up;
6969}
6970
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006971static int bnx2x_7101_format_ver(u32 spirom_ver, u8 *str, u16 *len)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006972{
6973 if (*len < 5)
6974 return -EINVAL;
6975 str[0] = (spirom_ver & 0xFF);
6976 str[1] = (spirom_ver & 0xFF00) >> 8;
6977 str[2] = (spirom_ver & 0xFF0000) >> 16;
6978 str[3] = (spirom_ver & 0xFF000000) >> 24;
6979 str[4] = '\0';
6980 *len -= 5;
6981 return 0;
6982}
6983
6984void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, struct bnx2x_phy *phy)
6985{
6986 u16 val, cnt;
6987
6988 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006989 MDIO_PMA_DEVAD,
6990 MDIO_PMA_REG_7101_RESET, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006991
6992 for (cnt = 0; cnt < 10; cnt++) {
6993 msleep(50);
6994 /* Writes a self-clearing reset */
6995 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006996 MDIO_PMA_DEVAD,
6997 MDIO_PMA_REG_7101_RESET,
6998 (val | (1<<15)));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006999 /* Wait for clear */
7000 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007001 MDIO_PMA_DEVAD,
7002 MDIO_PMA_REG_7101_RESET, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007003
7004 if ((val & (1<<15)) == 0)
7005 break;
7006 }
7007}
7008
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007009static void bnx2x_7101_hw_reset(struct bnx2x_phy *phy,
7010 struct link_params *params) {
7011 /* Low power mode is controlled by GPIO 2 */
7012 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007013 MISC_REGISTERS_GPIO_OUTPUT_LOW, params->port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007014 /* The PHY reset is controlled by GPIO 1 */
7015 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007016 MISC_REGISTERS_GPIO_OUTPUT_LOW, params->port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007017}
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007018
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00007019static void bnx2x_7101_set_link_led(struct bnx2x_phy *phy,
7020 struct link_params *params, u8 mode)
7021{
7022 u16 val = 0;
7023 struct bnx2x *bp = params->bp;
7024 switch (mode) {
7025 case LED_MODE_FRONT_PANEL_OFF:
7026 case LED_MODE_OFF:
7027 val = 2;
7028 break;
7029 case LED_MODE_ON:
7030 val = 1;
7031 break;
7032 case LED_MODE_OPER:
7033 val = 0;
7034 break;
7035 }
7036 bnx2x_cl45_write(bp, phy,
7037 MDIO_PMA_DEVAD,
7038 MDIO_PMA_REG_7107_LINK_LED_CNTL,
7039 val);
7040}
7041
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007042/******************************************************************/
7043/* STATIC PHY DECLARATION */
7044/******************************************************************/
7045
7046static struct bnx2x_phy phy_null = {
7047 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN,
7048 .addr = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007049 .def_md_devad = 0,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00007050 .flags = FLAGS_INIT_XGXS_FIRST,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007051 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7052 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7053 .mdio_ctrl = 0,
7054 .supported = 0,
7055 .media_type = ETH_PHY_NOT_PRESENT,
7056 .ver_addr = 0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007057 .req_flow_ctrl = 0,
7058 .req_line_speed = 0,
7059 .speed_cap_mask = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007060 .req_duplex = 0,
7061 .rsrv = 0,
7062 .config_init = (config_init_t)NULL,
7063 .read_status = (read_status_t)NULL,
7064 .link_reset = (link_reset_t)NULL,
7065 .config_loopback = (config_loopback_t)NULL,
7066 .format_fw_ver = (format_fw_ver_t)NULL,
7067 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007068 .set_link_led = (set_link_led_t)NULL,
7069 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007070};
7071
7072static struct bnx2x_phy phy_serdes = {
7073 .type = PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT,
7074 .addr = 0xff,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007075 .def_md_devad = 0,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00007076 .flags = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007077 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7078 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7079 .mdio_ctrl = 0,
7080 .supported = (SUPPORTED_10baseT_Half |
7081 SUPPORTED_10baseT_Full |
7082 SUPPORTED_100baseT_Half |
7083 SUPPORTED_100baseT_Full |
7084 SUPPORTED_1000baseT_Full |
7085 SUPPORTED_2500baseX_Full |
7086 SUPPORTED_TP |
7087 SUPPORTED_Autoneg |
7088 SUPPORTED_Pause |
7089 SUPPORTED_Asym_Pause),
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00007090 .media_type = ETH_PHY_BASE_T,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007091 .ver_addr = 0,
7092 .req_flow_ctrl = 0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007093 .req_line_speed = 0,
7094 .speed_cap_mask = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007095 .req_duplex = 0,
7096 .rsrv = 0,
Yaniv Rosnerec146a62011-05-31 21:29:27 +00007097 .config_init = (config_init_t)bnx2x_xgxs_config_init,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007098 .read_status = (read_status_t)bnx2x_link_settings_status,
7099 .link_reset = (link_reset_t)bnx2x_int_link_reset,
7100 .config_loopback = (config_loopback_t)NULL,
7101 .format_fw_ver = (format_fw_ver_t)NULL,
7102 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007103 .set_link_led = (set_link_led_t)NULL,
7104 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007105};
7106
7107static struct bnx2x_phy phy_xgxs = {
7108 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT,
7109 .addr = 0xff,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007110 .def_md_devad = 0,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00007111 .flags = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007112 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7113 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7114 .mdio_ctrl = 0,
7115 .supported = (SUPPORTED_10baseT_Half |
7116 SUPPORTED_10baseT_Full |
7117 SUPPORTED_100baseT_Half |
7118 SUPPORTED_100baseT_Full |
7119 SUPPORTED_1000baseT_Full |
7120 SUPPORTED_2500baseX_Full |
7121 SUPPORTED_10000baseT_Full |
7122 SUPPORTED_FIBRE |
7123 SUPPORTED_Autoneg |
7124 SUPPORTED_Pause |
7125 SUPPORTED_Asym_Pause),
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00007126 .media_type = ETH_PHY_CX4,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007127 .ver_addr = 0,
7128 .req_flow_ctrl = 0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007129 .req_line_speed = 0,
7130 .speed_cap_mask = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007131 .req_duplex = 0,
7132 .rsrv = 0,
Yaniv Rosnerec146a62011-05-31 21:29:27 +00007133 .config_init = (config_init_t)bnx2x_xgxs_config_init,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007134 .read_status = (read_status_t)bnx2x_link_settings_status,
7135 .link_reset = (link_reset_t)bnx2x_int_link_reset,
7136 .config_loopback = (config_loopback_t)bnx2x_set_xgxs_loopback,
7137 .format_fw_ver = (format_fw_ver_t)NULL,
7138 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007139 .set_link_led = (set_link_led_t)NULL,
7140 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007141};
7142
7143static struct bnx2x_phy phy_7101 = {
7144 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
7145 .addr = 0xff,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007146 .def_md_devad = 0,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00007147 .flags = FLAGS_FAN_FAILURE_DET_REQ,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007148 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7149 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7150 .mdio_ctrl = 0,
7151 .supported = (SUPPORTED_10000baseT_Full |
7152 SUPPORTED_TP |
7153 SUPPORTED_Autoneg |
7154 SUPPORTED_Pause |
7155 SUPPORTED_Asym_Pause),
7156 .media_type = ETH_PHY_BASE_T,
7157 .ver_addr = 0,
7158 .req_flow_ctrl = 0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007159 .req_line_speed = 0,
7160 .speed_cap_mask = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007161 .req_duplex = 0,
7162 .rsrv = 0,
7163 .config_init = (config_init_t)bnx2x_7101_config_init,
7164 .read_status = (read_status_t)bnx2x_7101_read_status,
7165 .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
7166 .config_loopback = (config_loopback_t)bnx2x_7101_config_loopback,
7167 .format_fw_ver = (format_fw_ver_t)bnx2x_7101_format_ver,
7168 .hw_reset = (hw_reset_t)bnx2x_7101_hw_reset,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00007169 .set_link_led = (set_link_led_t)bnx2x_7101_set_link_led,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007170 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007171};
7172static struct bnx2x_phy phy_8073 = {
7173 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
7174 .addr = 0xff,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007175 .def_md_devad = 0,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00007176 .flags = FLAGS_HW_LOCK_REQUIRED,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007177 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7178 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7179 .mdio_ctrl = 0,
7180 .supported = (SUPPORTED_10000baseT_Full |
7181 SUPPORTED_2500baseX_Full |
7182 SUPPORTED_1000baseT_Full |
7183 SUPPORTED_FIBRE |
7184 SUPPORTED_Autoneg |
7185 SUPPORTED_Pause |
7186 SUPPORTED_Asym_Pause),
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00007187 .media_type = ETH_PHY_KR,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007188 .ver_addr = 0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007189 .req_flow_ctrl = 0,
7190 .req_line_speed = 0,
7191 .speed_cap_mask = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007192 .req_duplex = 0,
7193 .rsrv = 0,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00007194 .config_init = (config_init_t)bnx2x_8073_config_init,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007195 .read_status = (read_status_t)bnx2x_8073_read_status,
7196 .link_reset = (link_reset_t)bnx2x_8073_link_reset,
7197 .config_loopback = (config_loopback_t)NULL,
7198 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
7199 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007200 .set_link_led = (set_link_led_t)NULL,
7201 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007202};
7203static struct bnx2x_phy phy_8705 = {
7204 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705,
7205 .addr = 0xff,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007206 .def_md_devad = 0,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00007207 .flags = FLAGS_INIT_XGXS_FIRST,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007208 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7209 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7210 .mdio_ctrl = 0,
7211 .supported = (SUPPORTED_10000baseT_Full |
7212 SUPPORTED_FIBRE |
7213 SUPPORTED_Pause |
7214 SUPPORTED_Asym_Pause),
7215 .media_type = ETH_PHY_XFP_FIBER,
7216 .ver_addr = 0,
7217 .req_flow_ctrl = 0,
7218 .req_line_speed = 0,
7219 .speed_cap_mask = 0,
7220 .req_duplex = 0,
7221 .rsrv = 0,
7222 .config_init = (config_init_t)bnx2x_8705_config_init,
7223 .read_status = (read_status_t)bnx2x_8705_read_status,
7224 .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
7225 .config_loopback = (config_loopback_t)NULL,
7226 .format_fw_ver = (format_fw_ver_t)bnx2x_null_format_ver,
7227 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007228 .set_link_led = (set_link_led_t)NULL,
7229 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007230};
7231static struct bnx2x_phy phy_8706 = {
7232 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706,
7233 .addr = 0xff,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007234 .def_md_devad = 0,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00007235 .flags = FLAGS_INIT_XGXS_FIRST,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007236 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7237 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7238 .mdio_ctrl = 0,
7239 .supported = (SUPPORTED_10000baseT_Full |
7240 SUPPORTED_1000baseT_Full |
7241 SUPPORTED_FIBRE |
7242 SUPPORTED_Pause |
7243 SUPPORTED_Asym_Pause),
7244 .media_type = ETH_PHY_SFP_FIBER,
7245 .ver_addr = 0,
7246 .req_flow_ctrl = 0,
7247 .req_line_speed = 0,
7248 .speed_cap_mask = 0,
7249 .req_duplex = 0,
7250 .rsrv = 0,
7251 .config_init = (config_init_t)bnx2x_8706_config_init,
7252 .read_status = (read_status_t)bnx2x_8706_read_status,
7253 .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
7254 .config_loopback = (config_loopback_t)NULL,
7255 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
7256 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007257 .set_link_led = (set_link_led_t)NULL,
7258 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007259};
7260
7261static struct bnx2x_phy phy_8726 = {
7262 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
7263 .addr = 0xff,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00007264 .def_md_devad = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007265 .flags = (FLAGS_HW_LOCK_REQUIRED |
7266 FLAGS_INIT_XGXS_FIRST),
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007267 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7268 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7269 .mdio_ctrl = 0,
7270 .supported = (SUPPORTED_10000baseT_Full |
7271 SUPPORTED_1000baseT_Full |
7272 SUPPORTED_Autoneg |
7273 SUPPORTED_FIBRE |
7274 SUPPORTED_Pause |
7275 SUPPORTED_Asym_Pause),
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00007276 .media_type = ETH_PHY_NOT_PRESENT,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007277 .ver_addr = 0,
7278 .req_flow_ctrl = 0,
7279 .req_line_speed = 0,
7280 .speed_cap_mask = 0,
7281 .req_duplex = 0,
7282 .rsrv = 0,
7283 .config_init = (config_init_t)bnx2x_8726_config_init,
7284 .read_status = (read_status_t)bnx2x_8726_read_status,
7285 .link_reset = (link_reset_t)bnx2x_8726_link_reset,
7286 .config_loopback = (config_loopback_t)bnx2x_8726_config_loopback,
7287 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
7288 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007289 .set_link_led = (set_link_led_t)NULL,
7290 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007291};
7292
7293static struct bnx2x_phy phy_8727 = {
7294 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
7295 .addr = 0xff,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007296 .def_md_devad = 0,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00007297 .flags = FLAGS_FAN_FAILURE_DET_REQ,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007298 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7299 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7300 .mdio_ctrl = 0,
7301 .supported = (SUPPORTED_10000baseT_Full |
7302 SUPPORTED_1000baseT_Full |
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007303 SUPPORTED_FIBRE |
7304 SUPPORTED_Pause |
7305 SUPPORTED_Asym_Pause),
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00007306 .media_type = ETH_PHY_NOT_PRESENT,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007307 .ver_addr = 0,
7308 .req_flow_ctrl = 0,
7309 .req_line_speed = 0,
7310 .speed_cap_mask = 0,
7311 .req_duplex = 0,
7312 .rsrv = 0,
7313 .config_init = (config_init_t)bnx2x_8727_config_init,
7314 .read_status = (read_status_t)bnx2x_8727_read_status,
7315 .link_reset = (link_reset_t)bnx2x_8727_link_reset,
7316 .config_loopback = (config_loopback_t)NULL,
7317 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
7318 .hw_reset = (hw_reset_t)bnx2x_8727_hw_reset,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00007319 .set_link_led = (set_link_led_t)bnx2x_8727_set_link_led,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007320 .phy_specific_func = (phy_specific_func_t)bnx2x_8727_specific_func
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007321};
7322static struct bnx2x_phy phy_8481 = {
7323 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
7324 .addr = 0xff,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00007325 .def_md_devad = 0,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007326 .flags = FLAGS_FAN_FAILURE_DET_REQ |
7327 FLAGS_REARM_LATCH_SIGNAL,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007328 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7329 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7330 .mdio_ctrl = 0,
7331 .supported = (SUPPORTED_10baseT_Half |
7332 SUPPORTED_10baseT_Full |
7333 SUPPORTED_100baseT_Half |
7334 SUPPORTED_100baseT_Full |
7335 SUPPORTED_1000baseT_Full |
7336 SUPPORTED_10000baseT_Full |
7337 SUPPORTED_TP |
7338 SUPPORTED_Autoneg |
7339 SUPPORTED_Pause |
7340 SUPPORTED_Asym_Pause),
7341 .media_type = ETH_PHY_BASE_T,
7342 .ver_addr = 0,
7343 .req_flow_ctrl = 0,
7344 .req_line_speed = 0,
7345 .speed_cap_mask = 0,
7346 .req_duplex = 0,
7347 .rsrv = 0,
7348 .config_init = (config_init_t)bnx2x_8481_config_init,
7349 .read_status = (read_status_t)bnx2x_848xx_read_status,
7350 .link_reset = (link_reset_t)bnx2x_8481_link_reset,
7351 .config_loopback = (config_loopback_t)NULL,
7352 .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver,
7353 .hw_reset = (hw_reset_t)bnx2x_8481_hw_reset,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00007354 .set_link_led = (set_link_led_t)bnx2x_848xx_set_link_led,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007355 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007356};
7357
7358static struct bnx2x_phy phy_84823 = {
7359 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823,
7360 .addr = 0xff,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00007361 .def_md_devad = 0,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007362 .flags = FLAGS_FAN_FAILURE_DET_REQ |
7363 FLAGS_REARM_LATCH_SIGNAL,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007364 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7365 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7366 .mdio_ctrl = 0,
7367 .supported = (SUPPORTED_10baseT_Half |
7368 SUPPORTED_10baseT_Full |
7369 SUPPORTED_100baseT_Half |
7370 SUPPORTED_100baseT_Full |
7371 SUPPORTED_1000baseT_Full |
7372 SUPPORTED_10000baseT_Full |
7373 SUPPORTED_TP |
7374 SUPPORTED_Autoneg |
7375 SUPPORTED_Pause |
7376 SUPPORTED_Asym_Pause),
7377 .media_type = ETH_PHY_BASE_T,
7378 .ver_addr = 0,
7379 .req_flow_ctrl = 0,
7380 .req_line_speed = 0,
7381 .speed_cap_mask = 0,
7382 .req_duplex = 0,
7383 .rsrv = 0,
7384 .config_init = (config_init_t)bnx2x_848x3_config_init,
7385 .read_status = (read_status_t)bnx2x_848xx_read_status,
7386 .link_reset = (link_reset_t)bnx2x_848x3_link_reset,
7387 .config_loopback = (config_loopback_t)NULL,
7388 .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver,
7389 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00007390 .set_link_led = (set_link_led_t)bnx2x_848xx_set_link_led,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007391 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007392};
7393
Yaniv Rosnerc87bca12011-01-31 04:22:41 +00007394static struct bnx2x_phy phy_84833 = {
7395 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833,
7396 .addr = 0xff,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00007397 .def_md_devad = 0,
Yaniv Rosnerc87bca12011-01-31 04:22:41 +00007398 .flags = FLAGS_FAN_FAILURE_DET_REQ |
7399 FLAGS_REARM_LATCH_SIGNAL,
Yaniv Rosnerc87bca12011-01-31 04:22:41 +00007400 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7401 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7402 .mdio_ctrl = 0,
7403 .supported = (SUPPORTED_10baseT_Half |
7404 SUPPORTED_10baseT_Full |
7405 SUPPORTED_100baseT_Half |
7406 SUPPORTED_100baseT_Full |
7407 SUPPORTED_1000baseT_Full |
7408 SUPPORTED_10000baseT_Full |
7409 SUPPORTED_TP |
7410 SUPPORTED_Autoneg |
7411 SUPPORTED_Pause |
7412 SUPPORTED_Asym_Pause),
7413 .media_type = ETH_PHY_BASE_T,
7414 .ver_addr = 0,
7415 .req_flow_ctrl = 0,
7416 .req_line_speed = 0,
7417 .speed_cap_mask = 0,
7418 .req_duplex = 0,
7419 .rsrv = 0,
7420 .config_init = (config_init_t)bnx2x_848x3_config_init,
7421 .read_status = (read_status_t)bnx2x_848xx_read_status,
7422 .link_reset = (link_reset_t)bnx2x_848x3_link_reset,
7423 .config_loopback = (config_loopback_t)NULL,
7424 .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver,
7425 .hw_reset = (hw_reset_t)NULL,
7426 .set_link_led = (set_link_led_t)bnx2x_848xx_set_link_led,
7427 .phy_specific_func = (phy_specific_func_t)NULL
7428};
7429
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007430/*****************************************************************/
7431/* */
7432/* Populate the phy according. Main function: bnx2x_populate_phy */
7433/* */
7434/*****************************************************************/
7435
7436static void bnx2x_populate_preemphasis(struct bnx2x *bp, u32 shmem_base,
7437 struct bnx2x_phy *phy, u8 port,
7438 u8 phy_index)
7439{
7440 /* Get the 4 lanes xgxs config rx and tx */
7441 u32 rx = 0, tx = 0, i;
7442 for (i = 0; i < 2; i++) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007443 /*
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007444 * INT_PHY and EXT_PHY1 share the same value location in the
7445 * shmem. When num_phys is greater than 1, than this value
7446 * applies only to EXT_PHY1
7447 */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007448 if (phy_index == INT_PHY || phy_index == EXT_PHY1) {
7449 rx = REG_RD(bp, shmem_base +
7450 offsetof(struct shmem_region,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007451 dev_info.port_hw_config[port].xgxs_config_rx[i<<1]));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007452
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007453 tx = REG_RD(bp, shmem_base +
7454 offsetof(struct shmem_region,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007455 dev_info.port_hw_config[port].xgxs_config_tx[i<<1]));
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007456 } else {
7457 rx = REG_RD(bp, shmem_base +
7458 offsetof(struct shmem_region,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007459 dev_info.port_hw_config[port].xgxs_config2_rx[i<<1]));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007460
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007461 tx = REG_RD(bp, shmem_base +
7462 offsetof(struct shmem_region,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007463 dev_info.port_hw_config[port].xgxs_config2_rx[i<<1]));
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007464 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007465
7466 phy->rx_preemphasis[i << 1] = ((rx>>16) & 0xffff);
7467 phy->rx_preemphasis[(i << 1) + 1] = (rx & 0xffff);
7468
7469 phy->tx_preemphasis[i << 1] = ((tx>>16) & 0xffff);
7470 phy->tx_preemphasis[(i << 1) + 1] = (tx & 0xffff);
7471 }
7472}
7473
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007474static u32 bnx2x_get_ext_phy_config(struct bnx2x *bp, u32 shmem_base,
7475 u8 phy_index, u8 port)
7476{
7477 u32 ext_phy_config = 0;
7478 switch (phy_index) {
7479 case EXT_PHY1:
7480 ext_phy_config = REG_RD(bp, shmem_base +
7481 offsetof(struct shmem_region,
7482 dev_info.port_hw_config[port].external_phy_config));
7483 break;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007484 case EXT_PHY2:
7485 ext_phy_config = REG_RD(bp, shmem_base +
7486 offsetof(struct shmem_region,
7487 dev_info.port_hw_config[port].external_phy_config2));
7488 break;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007489 default:
7490 DP(NETIF_MSG_LINK, "Invalid phy_index %d\n", phy_index);
7491 return -EINVAL;
7492 }
7493
7494 return ext_phy_config;
7495}
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00007496static int bnx2x_populate_int_phy(struct bnx2x *bp, u32 shmem_base, u8 port,
7497 struct bnx2x_phy *phy)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007498{
7499 u32 phy_addr;
7500 u32 chip_id;
7501 u32 switch_cfg = (REG_RD(bp, shmem_base +
7502 offsetof(struct shmem_region,
7503 dev_info.port_feature_config[port].link_config)) &
7504 PORT_FEATURE_CONNECTED_SWITCH_MASK);
7505 chip_id = REG_RD(bp, MISC_REG_CHIP_NUM) << 16;
7506 switch (switch_cfg) {
7507 case SWITCH_CFG_1G:
7508 phy_addr = REG_RD(bp,
7509 NIG_REG_SERDES0_CTRL_PHY_ADDR +
7510 port * 0x10);
7511 *phy = phy_serdes;
7512 break;
7513 case SWITCH_CFG_10G:
7514 phy_addr = REG_RD(bp,
7515 NIG_REG_XGXS0_CTRL_PHY_ADDR +
7516 port * 0x18);
7517 *phy = phy_xgxs;
7518 break;
7519 default:
7520 DP(NETIF_MSG_LINK, "Invalid switch_cfg\n");
7521 return -EINVAL;
7522 }
7523 phy->addr = (u8)phy_addr;
7524 phy->mdio_ctrl = bnx2x_get_emac_base(bp,
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007525 SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007526 port);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007527 if (CHIP_IS_E2(bp))
7528 phy->def_md_devad = E2_DEFAULT_PHY_DEV_ADDR;
7529 else
7530 phy->def_md_devad = DEFAULT_PHY_DEV_ADDR;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007531
7532 DP(NETIF_MSG_LINK, "Internal phy port=%d, addr=0x%x, mdio_ctl=0x%x\n",
7533 port, phy->addr, phy->mdio_ctrl);
7534
7535 bnx2x_populate_preemphasis(bp, shmem_base, phy, port, INT_PHY);
7536 return 0;
7537}
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007538
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00007539static int bnx2x_populate_ext_phy(struct bnx2x *bp,
7540 u8 phy_index,
7541 u32 shmem_base,
7542 u32 shmem2_base,
7543 u8 port,
7544 struct bnx2x_phy *phy)
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007545{
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007546 u32 ext_phy_config, phy_type, config2;
7547 u32 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007548 ext_phy_config = bnx2x_get_ext_phy_config(bp, shmem_base,
7549 phy_index, port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007550 phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
7551 /* Select the phy type */
7552 switch (phy_type) {
7553 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007554 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_SWAPPED;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007555 *phy = phy_8073;
7556 break;
7557 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
7558 *phy = phy_8705;
7559 break;
7560 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
7561 *phy = phy_8706;
7562 break;
7563 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007564 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007565 *phy = phy_8726;
7566 break;
7567 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
7568 /* BCM8727_NOC => BCM8727 no over current */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007569 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007570 *phy = phy_8727;
7571 phy->flags |= FLAGS_NOC;
7572 break;
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00007573 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722:
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007574 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007575 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007576 *phy = phy_8727;
7577 break;
7578 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
7579 *phy = phy_8481;
7580 break;
7581 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
7582 *phy = phy_84823;
7583 break;
Yaniv Rosnerc87bca12011-01-31 04:22:41 +00007584 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833:
7585 *phy = phy_84833;
7586 break;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007587 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
7588 *phy = phy_7101;
7589 break;
7590 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
7591 *phy = phy_null;
7592 return -EINVAL;
7593 default:
7594 *phy = phy_null;
7595 return 0;
7596 }
7597
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007598 phy->addr = XGXS_EXT_PHY_ADDR(ext_phy_config);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007599 bnx2x_populate_preemphasis(bp, shmem_base, phy, port, phy_index);
Yaniv Rosner62b29a52010-09-07 11:40:58 +00007600
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007601 /*
7602 * The shmem address of the phy version is located on different
7603 * structures. In case this structure is too old, do not set
7604 * the address
7605 */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007606 config2 = REG_RD(bp, shmem_base + offsetof(struct shmem_region,
7607 dev_info.shared_hw_config.config2));
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007608 if (phy_index == EXT_PHY1) {
7609 phy->ver_addr = shmem_base + offsetof(struct shmem_region,
7610 port_mb[port].ext_phy_fw_version);
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007611
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007612 /* Check specific mdc mdio settings */
7613 if (config2 & SHARED_HW_CFG_MDC_MDIO_ACCESS1_MASK)
7614 mdc_mdio_access = config2 &
7615 SHARED_HW_CFG_MDC_MDIO_ACCESS1_MASK;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007616 } else {
7617 u32 size = REG_RD(bp, shmem2_base);
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007618
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007619 if (size >
7620 offsetof(struct shmem2_region, ext_phy_fw_version2)) {
7621 phy->ver_addr = shmem2_base +
7622 offsetof(struct shmem2_region,
7623 ext_phy_fw_version2[port]);
7624 }
7625 /* Check specific mdc mdio settings */
7626 if (config2 & SHARED_HW_CFG_MDC_MDIO_ACCESS2_MASK)
7627 mdc_mdio_access = (config2 &
7628 SHARED_HW_CFG_MDC_MDIO_ACCESS2_MASK) >>
7629 (SHARED_HW_CFG_MDC_MDIO_ACCESS2_SHIFT -
7630 SHARED_HW_CFG_MDC_MDIO_ACCESS1_SHIFT);
7631 }
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007632 phy->mdio_ctrl = bnx2x_get_emac_base(bp, mdc_mdio_access, port);
7633
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007634 /*
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007635 * In case mdc/mdio_access of the external phy is different than the
7636 * mdc/mdio access of the XGXS, a HW lock must be taken in each access
7637 * to prevent one port interfere with another port's CL45 operations.
7638 */
7639 if (mdc_mdio_access != SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH)
7640 phy->flags |= FLAGS_HW_LOCK_REQUIRED;
7641 DP(NETIF_MSG_LINK, "phy_type 0x%x port %d found in index %d\n",
7642 phy_type, port, phy_index);
7643 DP(NETIF_MSG_LINK, " addr=0x%x, mdio_ctl=0x%x\n",
7644 phy->addr, phy->mdio_ctrl);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007645 return 0;
7646}
7647
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00007648static int bnx2x_populate_phy(struct bnx2x *bp, u8 phy_index, u32 shmem_base,
7649 u32 shmem2_base, u8 port, struct bnx2x_phy *phy)
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007650{
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00007651 int status = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007652 phy->type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN;
7653 if (phy_index == INT_PHY)
7654 return bnx2x_populate_int_phy(bp, shmem_base, port, phy);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007655 status = bnx2x_populate_ext_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007656 port, phy);
7657 return status;
7658}
7659
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007660static void bnx2x_phy_def_cfg(struct link_params *params,
7661 struct bnx2x_phy *phy,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007662 u8 phy_index)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007663{
7664 struct bnx2x *bp = params->bp;
7665 u32 link_config;
7666 /* Populate the default phy configuration for MF mode */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007667 if (phy_index == EXT_PHY2) {
7668 link_config = REG_RD(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007669 offsetof(struct shmem_region, dev_info.
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007670 port_feature_config[params->port].link_config2));
7671 phy->speed_cap_mask = REG_RD(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007672 offsetof(struct shmem_region,
7673 dev_info.
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007674 port_hw_config[params->port].speed_capability_mask2));
7675 } else {
7676 link_config = REG_RD(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007677 offsetof(struct shmem_region, dev_info.
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007678 port_feature_config[params->port].link_config));
7679 phy->speed_cap_mask = REG_RD(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007680 offsetof(struct shmem_region,
7681 dev_info.
7682 port_hw_config[params->port].speed_capability_mask));
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007683 }
7684 DP(NETIF_MSG_LINK, "Default config phy idx %x cfg 0x%x speed_cap_mask"
7685 " 0x%x\n", phy_index, link_config, phy->speed_cap_mask);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007686
7687 phy->req_duplex = DUPLEX_FULL;
7688 switch (link_config & PORT_FEATURE_LINK_SPEED_MASK) {
7689 case PORT_FEATURE_LINK_SPEED_10M_HALF:
7690 phy->req_duplex = DUPLEX_HALF;
7691 case PORT_FEATURE_LINK_SPEED_10M_FULL:
7692 phy->req_line_speed = SPEED_10;
7693 break;
7694 case PORT_FEATURE_LINK_SPEED_100M_HALF:
7695 phy->req_duplex = DUPLEX_HALF;
7696 case PORT_FEATURE_LINK_SPEED_100M_FULL:
7697 phy->req_line_speed = SPEED_100;
7698 break;
7699 case PORT_FEATURE_LINK_SPEED_1G:
7700 phy->req_line_speed = SPEED_1000;
7701 break;
7702 case PORT_FEATURE_LINK_SPEED_2_5G:
7703 phy->req_line_speed = SPEED_2500;
7704 break;
7705 case PORT_FEATURE_LINK_SPEED_10G_CX4:
7706 phy->req_line_speed = SPEED_10000;
7707 break;
7708 default:
7709 phy->req_line_speed = SPEED_AUTO_NEG;
7710 break;
7711 }
7712
7713 switch (link_config & PORT_FEATURE_FLOW_CONTROL_MASK) {
7714 case PORT_FEATURE_FLOW_CONTROL_AUTO:
7715 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_AUTO;
7716 break;
7717 case PORT_FEATURE_FLOW_CONTROL_TX:
7718 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_TX;
7719 break;
7720 case PORT_FEATURE_FLOW_CONTROL_RX:
7721 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_RX;
7722 break;
7723 case PORT_FEATURE_FLOW_CONTROL_BOTH:
7724 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_BOTH;
7725 break;
7726 default:
7727 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_NONE;
7728 break;
7729 }
7730}
7731
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007732u32 bnx2x_phy_selection(struct link_params *params)
7733{
7734 u32 phy_config_swapped, prio_cfg;
7735 u32 return_cfg = PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT;
7736
7737 phy_config_swapped = params->multi_phy_config &
7738 PORT_HW_CFG_PHY_SWAPPED_ENABLED;
7739
7740 prio_cfg = params->multi_phy_config &
7741 PORT_HW_CFG_PHY_SELECTION_MASK;
7742
7743 if (phy_config_swapped) {
7744 switch (prio_cfg) {
7745 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
7746 return_cfg = PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY;
7747 break;
7748 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
7749 return_cfg = PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY;
7750 break;
7751 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY:
7752 return_cfg = PORT_HW_CFG_PHY_SELECTION_FIRST_PHY;
7753 break;
7754 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY:
7755 return_cfg = PORT_HW_CFG_PHY_SELECTION_SECOND_PHY;
7756 break;
7757 }
7758 } else
7759 return_cfg = prio_cfg;
7760
7761 return return_cfg;
7762}
7763
7764
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00007765int bnx2x_phy_probe(struct link_params *params)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007766{
7767 u8 phy_index, actual_phy_idx, link_cfg_idx;
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00007768 u32 phy_config_swapped, sync_offset, media_types;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007769 struct bnx2x *bp = params->bp;
7770 struct bnx2x_phy *phy;
7771 params->num_phys = 0;
7772 DP(NETIF_MSG_LINK, "Begin phy probe\n");
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007773 phy_config_swapped = params->multi_phy_config &
7774 PORT_HW_CFG_PHY_SWAPPED_ENABLED;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007775
7776 for (phy_index = INT_PHY; phy_index < MAX_PHYS;
7777 phy_index++) {
7778 link_cfg_idx = LINK_CONFIG_IDX(phy_index);
7779 actual_phy_idx = phy_index;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007780 if (phy_config_swapped) {
7781 if (phy_index == EXT_PHY1)
7782 actual_phy_idx = EXT_PHY2;
7783 else if (phy_index == EXT_PHY2)
7784 actual_phy_idx = EXT_PHY1;
7785 }
7786 DP(NETIF_MSG_LINK, "phy_config_swapped %x, phy_index %x,"
7787 " actual_phy_idx %x\n", phy_config_swapped,
7788 phy_index, actual_phy_idx);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007789 phy = &params->phy[actual_phy_idx];
7790 if (bnx2x_populate_phy(bp, phy_index, params->shmem_base,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007791 params->shmem2_base, params->port,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007792 phy) != 0) {
7793 params->num_phys = 0;
7794 DP(NETIF_MSG_LINK, "phy probe failed in phy index %d\n",
7795 phy_index);
7796 for (phy_index = INT_PHY;
7797 phy_index < MAX_PHYS;
7798 phy_index++)
7799 *phy = phy_null;
7800 return -EINVAL;
7801 }
7802 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)
7803 break;
7804
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00007805 sync_offset = params->shmem_base +
7806 offsetof(struct shmem_region,
7807 dev_info.port_hw_config[params->port].media_type);
7808 media_types = REG_RD(bp, sync_offset);
7809
7810 /*
7811 * Update media type for non-PMF sync only for the first time
7812 * In case the media type changes afterwards, it will be updated
7813 * using the update_status function
7814 */
7815 if ((media_types & (PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK <<
7816 (PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT *
7817 actual_phy_idx))) == 0) {
7818 media_types |= ((phy->media_type &
7819 PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK) <<
7820 (PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT *
7821 actual_phy_idx));
7822 }
7823 REG_WR(bp, sync_offset, media_types);
7824
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007825 bnx2x_phy_def_cfg(params, phy, phy_index);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007826 params->num_phys++;
7827 }
7828
7829 DP(NETIF_MSG_LINK, "End phy probe. #phys found %x\n", params->num_phys);
7830 return 0;
7831}
7832
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00007833void bnx2x_init_bmac_loopback(struct link_params *params,
7834 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007835{
7836 struct bnx2x *bp = params->bp;
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00007837 vars->link_up = 1;
7838 vars->line_speed = SPEED_10000;
7839 vars->duplex = DUPLEX_FULL;
7840 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
7841 vars->mac_type = MAC_TYPE_BMAC;
7842
7843 vars->phy_flags = PHY_XGXS_FLAG;
7844
7845 bnx2x_xgxs_deassert(params);
7846
7847 /* set bmac loopback */
7848 bnx2x_bmac_enable(params, vars, 1);
7849
7850 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
7851}
7852
7853void bnx2x_init_emac_loopback(struct link_params *params,
7854 struct link_vars *vars)
7855{
7856 struct bnx2x *bp = params->bp;
7857 vars->link_up = 1;
7858 vars->line_speed = SPEED_1000;
7859 vars->duplex = DUPLEX_FULL;
7860 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
7861 vars->mac_type = MAC_TYPE_EMAC;
7862
7863 vars->phy_flags = PHY_XGXS_FLAG;
7864
7865 bnx2x_xgxs_deassert(params);
7866 /* set bmac loopback */
7867 bnx2x_emac_enable(params, vars, 1);
7868 bnx2x_emac_program(params, vars);
7869 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
7870}
7871
7872void bnx2x_init_xgxs_loopback(struct link_params *params,
7873 struct link_vars *vars)
7874{
7875 struct bnx2x *bp = params->bp;
7876 vars->link_up = 1;
7877 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
7878 vars->duplex = DUPLEX_FULL;
7879 if (params->req_line_speed[0] == SPEED_1000)
7880 vars->line_speed = SPEED_1000;
7881 else
7882 vars->line_speed = SPEED_10000;
7883
7884
7885 bnx2x_xgxs_deassert(params);
7886 bnx2x_link_initialize(params, vars);
7887
7888 if (params->req_line_speed[0] == SPEED_1000) {
7889 bnx2x_emac_program(params, vars);
7890 bnx2x_emac_enable(params, vars, 0);
7891
7892 } else
7893 bnx2x_bmac_enable(params, vars, 0);
7894
7895
7896 if (params->loopback_mode == LOOPBACK_XGXS) {
7897 /* set 10G XGXS loopback */
7898 params->phy[INT_PHY].config_loopback(
7899 &params->phy[INT_PHY],
7900 params);
7901
7902 } else {
7903 /* set external phy loopback */
7904 u8 phy_index;
7905 for (phy_index = EXT_PHY1;
7906 phy_index < params->num_phys; phy_index++) {
7907 if (params->phy[phy_index].config_loopback)
7908 params->phy[phy_index].config_loopback(
7909 &params->phy[phy_index],
7910 params);
7911 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007912 }
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00007913 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007914
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00007915 bnx2x_set_led(params, vars, LED_MODE_OPER, vars->line_speed);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007916}
7917
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00007918int bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007919{
7920 struct bnx2x *bp = params->bp;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007921 DP(NETIF_MSG_LINK, "Phy Initialization started\n");
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007922 DP(NETIF_MSG_LINK, "(1) req_speed %d, req_flowctrl %d\n",
7923 params->req_line_speed[0], params->req_flow_ctrl[0]);
7924 DP(NETIF_MSG_LINK, "(2) req_speed %d, req_flowctrl %d\n",
7925 params->req_line_speed[1], params->req_flow_ctrl[1]);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007926 vars->link_status = 0;
7927 vars->phy_link_up = 0;
7928 vars->link_up = 0;
7929 vars->line_speed = 0;
7930 vars->duplex = DUPLEX_FULL;
7931 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
7932 vars->mac_type = MAC_TYPE_NONE;
7933 vars->phy_flags = 0;
7934
7935 /* disable attentions */
7936 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4,
7937 (NIG_MASK_XGXS0_LINK_STATUS |
7938 NIG_MASK_XGXS0_LINK10G |
7939 NIG_MASK_SERDES0_LINK_STATUS |
7940 NIG_MASK_MI_INT));
7941
7942 bnx2x_emac_init(params, vars);
7943
7944 if (params->num_phys == 0) {
7945 DP(NETIF_MSG_LINK, "No phy found for initialization !!\n");
7946 return -EINVAL;
7947 }
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00007948 set_phy_vars(params, vars);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007949
7950 DP(NETIF_MSG_LINK, "Num of phys on board: %d\n", params->num_phys);
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00007951 switch (params->loopback_mode) {
7952 case LOOPBACK_BMAC:
7953 bnx2x_init_bmac_loopback(params, vars);
7954 break;
7955 case LOOPBACK_EMAC:
7956 bnx2x_init_emac_loopback(params, vars);
7957 break;
7958 case LOOPBACK_XGXS:
7959 case LOOPBACK_EXT_PHY:
7960 bnx2x_init_xgxs_loopback(params, vars);
7961 break;
7962 default:
7963 /* No loopback */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007964 if (params->switch_cfg == SWITCH_CFG_10G)
7965 bnx2x_xgxs_deassert(params);
7966 else
7967 bnx2x_serdes_deassert(bp, params->port);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00007968
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007969 bnx2x_link_initialize(params, vars);
7970 msleep(30);
7971 bnx2x_link_int_enable(params);
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00007972 break;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007973 }
7974 return 0;
7975}
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00007976
7977int bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
7978 u8 reset_ext_phy)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007979{
7980 struct bnx2x *bp = params->bp;
Yaniv Rosnercf1d9722010-11-01 05:32:34 +00007981 u8 phy_index, port = params->port, clear_latch_ind = 0;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007982 DP(NETIF_MSG_LINK, "Resetting the link of port %d\n", port);
7983 /* disable attentions */
7984 vars->link_status = 0;
7985 bnx2x_update_mng(params, vars->link_status);
7986 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007987 (NIG_MASK_XGXS0_LINK_STATUS |
7988 NIG_MASK_XGXS0_LINK10G |
7989 NIG_MASK_SERDES0_LINK_STATUS |
7990 NIG_MASK_MI_INT));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007991
7992 /* activate nig drain */
7993 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
7994
7995 /* disable nig egress interface */
7996 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
7997 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
7998
7999 /* Stop BigMac rx */
8000 bnx2x_bmac_rx_disable(bp, port);
8001
8002 /* disable emac */
8003 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
8004
8005 msleep(10);
Lucas De Marchi25985ed2011-03-30 22:57:33 -03008006 /* The PHY reset is controlled by GPIO 1
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008007 * Hold it as vars low
8008 */
8009 /* clear link led */
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00008010 bnx2x_set_led(params, vars, LED_MODE_OFF, 0);
8011
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008012 if (reset_ext_phy) {
8013 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
8014 phy_index++) {
8015 if (params->phy[phy_index].link_reset)
8016 params->phy[phy_index].link_reset(
8017 &params->phy[phy_index],
8018 params);
Yaniv Rosnercf1d9722010-11-01 05:32:34 +00008019 if (params->phy[phy_index].flags &
8020 FLAGS_REARM_LATCH_SIGNAL)
8021 clear_latch_ind = 1;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008022 }
8023 }
8024
Yaniv Rosnercf1d9722010-11-01 05:32:34 +00008025 if (clear_latch_ind) {
8026 /* Clear latching indication */
8027 bnx2x_rearm_latch_signal(bp, port, 0);
8028 bnx2x_bits_dis(bp, NIG_REG_LATCH_BC_0 + port*4,
8029 1 << NIG_LATCH_BC_ENABLE_MI_INT);
8030 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008031 if (params->phy[INT_PHY].link_reset)
8032 params->phy[INT_PHY].link_reset(
8033 &params->phy[INT_PHY], params);
8034 /* reset BigMac */
8035 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
8036 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
8037
8038 /* disable nig ingress interface */
8039 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0);
8040 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0);
8041 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
8042 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
8043 vars->link_up = 0;
8044 return 0;
8045}
8046
8047/****************************************************************************/
8048/* Common function */
8049/****************************************************************************/
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00008050static int bnx2x_8073_common_init_phy(struct bnx2x *bp,
8051 u32 shmem_base_path[],
8052 u32 shmem2_base_path[], u8 phy_index,
8053 u32 chip_id)
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008054{
Yaniv Rosnere10bc842010-09-07 11:40:50 +00008055 struct bnx2x_phy phy[PORT_MAX];
8056 struct bnx2x_phy *phy_blk[PORT_MAX];
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008057 u16 val;
Yaniv Rosnerc8e64df2011-01-30 04:15:00 +00008058 s8 port = 0;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00008059 s8 port_of_path = 0;
Yaniv Rosnerc8e64df2011-01-30 04:15:00 +00008060 u32 swap_val, swap_override;
8061 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
8062 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
8063 port ^= (swap_val && swap_override);
8064 bnx2x_ext_phy_hw_reset(bp, port);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008065 /* PART1 - Reset both phys */
8066 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00008067 u32 shmem_base, shmem2_base;
8068 /* In E2, same phy is using for port0 of the two paths */
8069 if (CHIP_IS_E2(bp)) {
8070 shmem_base = shmem_base_path[port];
8071 shmem2_base = shmem2_base_path[port];
8072 port_of_path = 0;
8073 } else {
8074 shmem_base = shmem_base_path[0];
8075 shmem2_base = shmem2_base_path[0];
8076 port_of_path = port;
8077 }
8078
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008079 /* Extract the ext phy address for the port */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008080 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00008081 port_of_path, &phy[port]) !=
Yaniv Rosnere10bc842010-09-07 11:40:50 +00008082 0) {
8083 DP(NETIF_MSG_LINK, "populate_phy failed\n");
8084 return -EINVAL;
8085 }
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008086 /* disable attentions */
Yaniv Rosner6a71bbe2010-11-01 05:32:31 +00008087 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 +
8088 port_of_path*4,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008089 (NIG_MASK_XGXS0_LINK_STATUS |
8090 NIG_MASK_XGXS0_LINK10G |
8091 NIG_MASK_SERDES0_LINK_STATUS |
8092 NIG_MASK_MI_INT));
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008093
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008094 /* Need to take the phy out of low power mode in order
8095 to write to access its registers */
8096 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008097 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
8098 port);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008099
8100 /* Reset the phy */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00008101 bnx2x_cl45_write(bp, &phy[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008102 MDIO_PMA_DEVAD,
8103 MDIO_PMA_REG_CTRL,
8104 1<<15);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008105 }
8106
8107 /* Add delay of 150ms after reset */
8108 msleep(150);
8109
Yaniv Rosnere10bc842010-09-07 11:40:50 +00008110 if (phy[PORT_0].addr & 0x1) {
8111 phy_blk[PORT_0] = &(phy[PORT_1]);
8112 phy_blk[PORT_1] = &(phy[PORT_0]);
8113 } else {
8114 phy_blk[PORT_0] = &(phy[PORT_0]);
8115 phy_blk[PORT_1] = &(phy[PORT_1]);
8116 }
8117
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008118 /* PART2 - Download firmware to both phys */
8119 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00008120 if (CHIP_IS_E2(bp))
8121 port_of_path = 0;
8122 else
8123 port_of_path = port;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008124
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00008125 DP(NETIF_MSG_LINK, "Loading spirom for phy address 0x%x\n",
8126 phy_blk[port]->addr);
Yaniv Rosner5c99274b2011-01-18 04:33:36 +00008127 if (bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port],
8128 port_of_path))
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008129 return -EINVAL;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008130
8131 /* Only set bit 10 = 1 (Tx power down) */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00008132 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008133 MDIO_PMA_DEVAD,
8134 MDIO_PMA_REG_TX_POWER_DOWN, &val);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008135
8136 /* Phase1 of TX_POWER_DOWN reset */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00008137 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008138 MDIO_PMA_DEVAD,
8139 MDIO_PMA_REG_TX_POWER_DOWN,
8140 (val | 1<<10));
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008141 }
8142
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008143 /*
8144 * Toggle Transmitter: Power down and then up with 600ms delay
8145 * between
8146 */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008147 msleep(600);
8148
8149 /* PART3 - complete TX_POWER_DOWN process, and set GPIO2 back to low */
8150 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Eilon Greensteinf5372252009-02-12 08:38:30 +00008151 /* Phase2 of POWER_DOWN_RESET */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008152 /* Release bit 10 (Release Tx power down) */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00008153 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008154 MDIO_PMA_DEVAD,
8155 MDIO_PMA_REG_TX_POWER_DOWN, &val);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008156
Yaniv Rosnere10bc842010-09-07 11:40:50 +00008157 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008158 MDIO_PMA_DEVAD,
8159 MDIO_PMA_REG_TX_POWER_DOWN, (val & (~(1<<10))));
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008160 msleep(15);
8161
8162 /* Read modify write the SPI-ROM version select register */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00008163 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008164 MDIO_PMA_DEVAD,
8165 MDIO_PMA_REG_EDC_FFE_MAIN, &val);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00008166 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008167 MDIO_PMA_DEVAD,
8168 MDIO_PMA_REG_EDC_FFE_MAIN, (val | (1<<12)));
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008169
8170 /* set GPIO2 back to LOW */
8171 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008172 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008173 }
8174 return 0;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008175}
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00008176static int bnx2x_8726_common_init_phy(struct bnx2x *bp,
8177 u32 shmem_base_path[],
8178 u32 shmem2_base_path[], u8 phy_index,
8179 u32 chip_id)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008180{
8181 u32 val;
8182 s8 port;
8183 struct bnx2x_phy phy;
8184 /* Use port1 because of the static port-swap */
8185 /* Enable the module detection interrupt */
8186 val = REG_RD(bp, MISC_REG_GPIO_EVENT_EN);
8187 val |= ((1<<MISC_REGISTERS_GPIO_3)|
8188 (1<<(MISC_REGISTERS_GPIO_3 + MISC_REGISTERS_GPIO_PORT_SHIFT)));
8189 REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val);
8190
Yaniv Rosner650154b2010-11-01 05:32:36 +00008191 bnx2x_ext_phy_hw_reset(bp, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008192 msleep(5);
8193 for (port = 0; port < PORT_MAX; port++) {
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00008194 u32 shmem_base, shmem2_base;
8195
8196 /* In E2, same phy is using for port0 of the two paths */
8197 if (CHIP_IS_E2(bp)) {
8198 shmem_base = shmem_base_path[port];
8199 shmem2_base = shmem2_base_path[port];
8200 } else {
8201 shmem_base = shmem_base_path[0];
8202 shmem2_base = shmem2_base_path[0];
8203 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008204 /* Extract the ext phy address for the port */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008205 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008206 port, &phy) !=
8207 0) {
8208 DP(NETIF_MSG_LINK, "populate phy failed\n");
8209 return -EINVAL;
8210 }
8211
8212 /* Reset phy*/
8213 bnx2x_cl45_write(bp, &phy,
8214 MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, 0x0001);
8215
8216
8217 /* Set fault module detected LED on */
8218 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008219 MISC_REGISTERS_GPIO_HIGH,
8220 port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008221 }
8222
8223 return 0;
8224}
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00008225static void bnx2x_get_ext_phy_reset_gpio(struct bnx2x *bp, u32 shmem_base,
8226 u8 *io_gpio, u8 *io_port)
8227{
8228
8229 u32 phy_gpio_reset = REG_RD(bp, shmem_base +
8230 offsetof(struct shmem_region,
8231 dev_info.port_hw_config[PORT_0].default_cfg));
8232 switch (phy_gpio_reset) {
8233 case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO0_P0:
8234 *io_gpio = 0;
8235 *io_port = 0;
8236 break;
8237 case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO1_P0:
8238 *io_gpio = 1;
8239 *io_port = 0;
8240 break;
8241 case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO2_P0:
8242 *io_gpio = 2;
8243 *io_port = 0;
8244 break;
8245 case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO3_P0:
8246 *io_gpio = 3;
8247 *io_port = 0;
8248 break;
8249 case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO0_P1:
8250 *io_gpio = 0;
8251 *io_port = 1;
8252 break;
8253 case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO1_P1:
8254 *io_gpio = 1;
8255 *io_port = 1;
8256 break;
8257 case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO2_P1:
8258 *io_gpio = 2;
8259 *io_port = 1;
8260 break;
8261 case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO3_P1:
8262 *io_gpio = 3;
8263 *io_port = 1;
8264 break;
8265 default:
8266 /* Don't override the io_gpio and io_port */
8267 break;
8268 }
8269}
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00008270
8271static int bnx2x_8727_common_init_phy(struct bnx2x *bp,
8272 u32 shmem_base_path[],
8273 u32 shmem2_base_path[], u8 phy_index,
8274 u32 chip_id)
Eilon Greenstein4d295db2009-07-21 05:47:47 +00008275{
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00008276 s8 port, reset_gpio;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00008277 u32 swap_val, swap_override;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00008278 struct bnx2x_phy phy[PORT_MAX];
8279 struct bnx2x_phy *phy_blk[PORT_MAX];
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00008280 s8 port_of_path;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008281 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
8282 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00008283
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00008284 reset_gpio = MISC_REGISTERS_GPIO_1;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008285 port = 1;
8286
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00008287 /*
8288 * Retrieve the reset gpio/port which control the reset.
8289 * Default is GPIO1, PORT1
8290 */
8291 bnx2x_get_ext_phy_reset_gpio(bp, shmem_base_path[0],
8292 (u8 *)&reset_gpio, (u8 *)&port);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008293
8294 /* Calculate the port based on port swap */
8295 port ^= (swap_val && swap_override);
8296
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00008297 /* Initiate PHY reset*/
8298 bnx2x_set_gpio(bp, reset_gpio, MISC_REGISTERS_GPIO_OUTPUT_LOW,
8299 port);
8300 msleep(1);
8301 bnx2x_set_gpio(bp, reset_gpio, MISC_REGISTERS_GPIO_OUTPUT_HIGH,
8302 port);
8303
Eilon Greenstein4d295db2009-07-21 05:47:47 +00008304 msleep(5);
8305
8306 /* PART1 - Reset both phys */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008307 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00008308 u32 shmem_base, shmem2_base;
8309
8310 /* In E2, same phy is using for port0 of the two paths */
8311 if (CHIP_IS_E2(bp)) {
8312 shmem_base = shmem_base_path[port];
8313 shmem2_base = shmem2_base_path[port];
8314 port_of_path = 0;
8315 } else {
8316 shmem_base = shmem_base_path[0];
8317 shmem2_base = shmem2_base_path[0];
8318 port_of_path = port;
8319 }
8320
Eilon Greenstein4d295db2009-07-21 05:47:47 +00008321 /* Extract the ext phy address for the port */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008322 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00008323 port_of_path, &phy[port]) !=
Yaniv Rosnere10bc842010-09-07 11:40:50 +00008324 0) {
8325 DP(NETIF_MSG_LINK, "populate phy failed\n");
8326 return -EINVAL;
8327 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00008328 /* disable attentions */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00008329 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 +
8330 port_of_path*4,
8331 (NIG_MASK_XGXS0_LINK_STATUS |
8332 NIG_MASK_XGXS0_LINK10G |
8333 NIG_MASK_SERDES0_LINK_STATUS |
8334 NIG_MASK_MI_INT));
Eilon Greenstein4d295db2009-07-21 05:47:47 +00008335
Eilon Greenstein4d295db2009-07-21 05:47:47 +00008336
8337 /* Reset the phy */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00008338 bnx2x_cl45_write(bp, &phy[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008339 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00008340 }
8341
8342 /* Add delay of 150ms after reset */
8343 msleep(150);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00008344 if (phy[PORT_0].addr & 0x1) {
8345 phy_blk[PORT_0] = &(phy[PORT_1]);
8346 phy_blk[PORT_1] = &(phy[PORT_0]);
8347 } else {
8348 phy_blk[PORT_0] = &(phy[PORT_0]);
8349 phy_blk[PORT_1] = &(phy[PORT_1]);
8350 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00008351 /* PART2 - Download firmware to both phys */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00008352 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008353 if (CHIP_IS_E2(bp))
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00008354 port_of_path = 0;
8355 else
8356 port_of_path = port;
8357 DP(NETIF_MSG_LINK, "Loading spirom for phy address 0x%x\n",
8358 phy_blk[port]->addr);
Yaniv Rosner5c99274b2011-01-18 04:33:36 +00008359 if (bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port],
8360 port_of_path))
Eilon Greenstein4d295db2009-07-21 05:47:47 +00008361 return -EINVAL;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00008362
Yaniv Rosner5c99274b2011-01-18 04:33:36 +00008363 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00008364 return 0;
8365}
8366
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00008367static int bnx2x_ext_phy_common_init(struct bnx2x *bp, u32 shmem_base_path[],
8368 u32 shmem2_base_path[], u8 phy_index,
8369 u32 ext_phy_type, u32 chip_id)
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008370{
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00008371 int rc = 0;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008372
8373 switch (ext_phy_type) {
8374 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00008375 rc = bnx2x_8073_common_init_phy(bp, shmem_base_path,
8376 shmem2_base_path,
8377 phy_index, chip_id);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008378 break;
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00008379 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722:
Eilon Greenstein4d295db2009-07-21 05:47:47 +00008380 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
8381 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00008382 rc = bnx2x_8727_common_init_phy(bp, shmem_base_path,
8383 shmem2_base_path,
8384 phy_index, chip_id);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00008385 break;
8386
Eilon Greenstein589abe32009-02-12 08:36:55 +00008387 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008388 /*
8389 * GPIO1 affects both ports, so there's need to pull
8390 * it for single port alone
8391 */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00008392 rc = bnx2x_8726_common_init_phy(bp, shmem_base_path,
8393 shmem2_base_path,
8394 phy_index, chip_id);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008395 break;
8396 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
8397 rc = -EINVAL;
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02008398 break;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008399 default:
8400 DP(NETIF_MSG_LINK,
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008401 "ext_phy 0x%x common init not required\n",
8402 ext_phy_type);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008403 break;
8404 }
8405
Yaniv Rosner6d870c32011-01-31 04:22:20 +00008406 if (rc != 0)
8407 netdev_err(bp->dev, "Warning: PHY was not initialized,"
8408 " Port %d\n",
8409 0);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008410 return rc;
8411}
8412
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00008413int bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base_path[],
8414 u32 shmem2_base_path[], u32 chip_id)
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008415{
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00008416 int rc = 0;
Yaniv Rosnerb21a3422011-01-18 04:33:24 +00008417 u32 phy_ver;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008418 u8 phy_index;
8419 u32 ext_phy_type, ext_phy_config;
Yaniv Rosnera198c142011-05-31 21:29:42 +00008420 bnx2x_set_mdio_clk(bp, chip_id, PORT_0);
8421 bnx2x_set_mdio_clk(bp, chip_id, PORT_1);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008422 DP(NETIF_MSG_LINK, "Begin common phy init\n");
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00008423
Yaniv Rosnerb21a3422011-01-18 04:33:24 +00008424 /* Check if common init was already done */
8425 phy_ver = REG_RD(bp, shmem_base_path[0] +
8426 offsetof(struct shmem_region,
8427 port_mb[PORT_0].ext_phy_fw_version));
8428 if (phy_ver) {
8429 DP(NETIF_MSG_LINK, "Not doing common init; phy ver is 0x%x\n",
8430 phy_ver);
8431 return 0;
8432 }
8433
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008434 /* Read the ext_phy_type for arbitrary port(0) */
8435 for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
8436 phy_index++) {
8437 ext_phy_config = bnx2x_get_ext_phy_config(bp,
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00008438 shmem_base_path[0],
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008439 phy_index, 0);
8440 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00008441 rc |= bnx2x_ext_phy_common_init(bp, shmem_base_path,
8442 shmem2_base_path,
8443 phy_index, ext_phy_type,
8444 chip_id);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008445 }
8446 return rc;
8447}
8448
8449u8 bnx2x_hw_lock_required(struct bnx2x *bp, u32 shmem_base, u32 shmem2_base)
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00008450{
8451 u8 phy_index;
8452 struct bnx2x_phy phy;
8453 for (phy_index = INT_PHY; phy_index < MAX_PHYS;
8454 phy_index++) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008455 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00008456 0, &phy) != 0) {
8457 DP(NETIF_MSG_LINK, "populate phy failed\n");
8458 return 0;
8459 }
8460
8461 if (phy.flags & FLAGS_HW_LOCK_REQUIRED)
8462 return 1;
8463 }
8464 return 0;
8465}
8466
8467u8 bnx2x_fan_failure_det_req(struct bnx2x *bp,
8468 u32 shmem_base,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008469 u32 shmem2_base,
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00008470 u8 port)
8471{
8472 u8 phy_index, fan_failure_det_req = 0;
8473 struct bnx2x_phy phy;
8474 for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
8475 phy_index++) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008476 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00008477 port, &phy)
8478 != 0) {
8479 DP(NETIF_MSG_LINK, "populate phy failed\n");
8480 return 0;
8481 }
8482 fan_failure_det_req |= (phy.flags &
8483 FLAGS_FAN_FAILURE_DET_REQ);
8484 }
8485 return fan_failure_det_req;
8486}
8487
8488void bnx2x_hw_reset_phy(struct link_params *params)
8489{
8490 u8 phy_index;
8491 for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
8492 phy_index++) {
8493 if (params->phy[phy_index].hw_reset) {
8494 params->phy[phy_index].hw_reset(
8495 &params->phy[phy_index],
8496 params);
8497 params->phy[phy_index] = phy_null;
8498 }
8499 }
8500}
Yaniv Rosner020c7e32011-05-31 21:28:43 +00008501
8502void bnx2x_init_mod_abs_int(struct bnx2x *bp, struct link_vars *vars,
8503 u32 chip_id, u32 shmem_base, u32 shmem2_base,
8504 u8 port)
8505{
8506 u8 gpio_num = 0xff, gpio_port = 0xff, phy_index;
8507 u32 val;
8508 u32 offset, aeu_mask, swap_val, swap_override, sync_offset;
8509
8510 {
8511 struct bnx2x_phy phy;
8512 for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
8513 phy_index++) {
8514 if (bnx2x_populate_phy(bp, phy_index, shmem_base,
8515 shmem2_base, port, &phy)
8516 != 0) {
8517 DP(NETIF_MSG_LINK, "populate phy failed\n");
8518 return;
8519 }
8520 if (phy.type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) {
8521 gpio_num = MISC_REGISTERS_GPIO_3;
8522 gpio_port = port;
8523 break;
8524 }
8525 }
8526 }
8527
8528 if (gpio_num == 0xff)
8529 return;
8530
8531 /* Set GPIO3 to trigger SFP+ module insertion/removal */
8532 bnx2x_set_gpio(bp, gpio_num, MISC_REGISTERS_GPIO_INPUT_HI_Z, gpio_port);
8533
8534 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
8535 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
8536 gpio_port ^= (swap_val && swap_override);
8537
8538 vars->aeu_int_mask = AEU_INPUTS_ATTN_BITS_GPIO0_FUNCTION_0 <<
8539 (gpio_num + (gpio_port << 2));
8540
8541 sync_offset = shmem_base +
8542 offsetof(struct shmem_region,
8543 dev_info.port_hw_config[port].aeu_int_mask);
8544 REG_WR(bp, sync_offset, vars->aeu_int_mask);
8545
8546 DP(NETIF_MSG_LINK, "Setting MOD_ABS (GPIO%d_P%d) AEU to 0x%x\n",
8547 gpio_num, gpio_port, vars->aeu_int_mask);
8548
8549 if (port == 0)
8550 offset = MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0;
8551 else
8552 offset = MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0;
8553
8554 /* Open appropriate AEU for interrupts */
8555 aeu_mask = REG_RD(bp, offset);
8556 aeu_mask |= vars->aeu_int_mask;
8557 REG_WR(bp, offset, aeu_mask);
8558
8559 /* Enable the GPIO to trigger interrupt */
8560 val = REG_RD(bp, MISC_REG_GPIO_EVENT_EN);
8561 val |= 1 << (gpio_num + (gpio_port << 2));
8562 REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val);
8563}