blob: 347f3239ad1f50aac6e5f6ff56c1da872635c11d [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"
Vlad Zolotarov619c5cb2011-06-14 14:33:44 +030028#include "bnx2x_cmn.h"
29
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070030
31/********************************************************/
Eilon Greenstein3196a882008-08-13 15:58:49 -070032#define ETH_HLEN 14
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000033/* L2 header size + 2*VLANs (8 bytes) + LLC SNAP (8 bytes) */
34#define ETH_OVREHEAD (ETH_HLEN + 8 + 8)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070035#define ETH_MIN_PACKET_SIZE 60
36#define ETH_MAX_PACKET_SIZE 1500
37#define ETH_MAX_JUMBO_PACKET_SIZE 9600
38#define MDIO_ACCESS_TIMEOUT 1000
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000039#define BMAC_CONTROL_RX_ENABLE 2
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070040
41/***********************************************************/
Eilon Greenstein3196a882008-08-13 15:58:49 -070042/* Shortcut definitions */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070043/***********************************************************/
44
Eilon Greenstein2f904462009-08-12 08:22:16 +000045#define NIG_LATCH_BC_ENABLE_MI_INT 0
46
47#define NIG_STATUS_EMAC0_MI_INT \
48 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_EMAC0_MISC_MI_INT
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070049#define NIG_STATUS_XGXS0_LINK10G \
50 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK10G
51#define NIG_STATUS_XGXS0_LINK_STATUS \
52 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS
53#define NIG_STATUS_XGXS0_LINK_STATUS_SIZE \
54 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS_SIZE
55#define NIG_STATUS_SERDES0_LINK_STATUS \
56 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_SERDES0_LINK_STATUS
57#define NIG_MASK_MI_INT \
58 NIG_MASK_INTERRUPT_PORT0_REG_MASK_EMAC0_MISC_MI_INT
59#define NIG_MASK_XGXS0_LINK10G \
60 NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK10G
61#define NIG_MASK_XGXS0_LINK_STATUS \
62 NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK_STATUS
63#define NIG_MASK_SERDES0_LINK_STATUS \
64 NIG_MASK_INTERRUPT_PORT0_REG_MASK_SERDES0_LINK_STATUS
65
66#define MDIO_AN_CL73_OR_37_COMPLETE \
67 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE | \
68 MDIO_GP_STATUS_TOP_AN_STATUS1_CL37_AUTONEG_COMPLETE)
69
70#define XGXS_RESET_BITS \
71 (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_RSTB_HW | \
72 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_IDDQ | \
73 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN | \
74 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN_SD | \
75 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_TXD_FIFO_RSTB)
76
77#define SERDES_RESET_BITS \
78 (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_RSTB_HW | \
79 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_IDDQ | \
80 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN | \
81 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN_SD)
82
83#define AUTONEG_CL37 SHARED_HW_CFG_AN_ENABLE_CL37
84#define AUTONEG_CL73 SHARED_HW_CFG_AN_ENABLE_CL73
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000085#define AUTONEG_BAM SHARED_HW_CFG_AN_ENABLE_BAM
Eilon Greenstein3196a882008-08-13 15:58:49 -070086#define AUTONEG_PARALLEL \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070087 SHARED_HW_CFG_AN_ENABLE_PARALLEL_DETECTION
Eilon Greenstein3196a882008-08-13 15:58:49 -070088#define AUTONEG_SGMII_FIBER_AUTODET \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070089 SHARED_HW_CFG_AN_EN_SGMII_FIBER_AUTO_DETECT
Eilon Greenstein3196a882008-08-13 15:58:49 -070090#define AUTONEG_REMOTE_PHY SHARED_HW_CFG_AN_ENABLE_REMOTE_PHY
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070091
92#define GP_STATUS_PAUSE_RSOLUTION_TXSIDE \
93 MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_TXSIDE
94#define GP_STATUS_PAUSE_RSOLUTION_RXSIDE \
95 MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_RXSIDE
96#define GP_STATUS_SPEED_MASK \
97 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_MASK
98#define GP_STATUS_10M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10M
99#define GP_STATUS_100M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_100M
100#define GP_STATUS_1G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G
101#define GP_STATUS_2_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_2_5G
102#define GP_STATUS_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_5G
103#define GP_STATUS_6G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_6G
104#define GP_STATUS_10G_HIG \
105 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_HIG
106#define GP_STATUS_10G_CX4 \
107 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_CX4
108#define GP_STATUS_12G_HIG \
109 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12G_HIG
110#define GP_STATUS_12_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12_5G
111#define GP_STATUS_13G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_13G
112#define GP_STATUS_15G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_15G
113#define GP_STATUS_16G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_16G
114#define GP_STATUS_1G_KX MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G_KX
115#define GP_STATUS_10G_KX4 \
116 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_KX4
117
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000118#define LINK_10THD LINK_STATUS_SPEED_AND_DUPLEX_10THD
119#define LINK_10TFD LINK_STATUS_SPEED_AND_DUPLEX_10TFD
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700120#define LINK_100TXHD LINK_STATUS_SPEED_AND_DUPLEX_100TXHD
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000121#define LINK_100T4 LINK_STATUS_SPEED_AND_DUPLEX_100T4
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700122#define LINK_100TXFD LINK_STATUS_SPEED_AND_DUPLEX_100TXFD
123#define LINK_1000THD LINK_STATUS_SPEED_AND_DUPLEX_1000THD
124#define LINK_1000TFD LINK_STATUS_SPEED_AND_DUPLEX_1000TFD
125#define LINK_1000XFD LINK_STATUS_SPEED_AND_DUPLEX_1000XFD
126#define LINK_2500THD LINK_STATUS_SPEED_AND_DUPLEX_2500THD
127#define LINK_2500TFD LINK_STATUS_SPEED_AND_DUPLEX_2500TFD
128#define LINK_2500XFD LINK_STATUS_SPEED_AND_DUPLEX_2500XFD
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000129#define LINK_10GTFD LINK_STATUS_SPEED_AND_DUPLEX_10GTFD
130#define LINK_10GXFD LINK_STATUS_SPEED_AND_DUPLEX_10GXFD
131#define LINK_12GTFD LINK_STATUS_SPEED_AND_DUPLEX_12GTFD
132#define LINK_12GXFD LINK_STATUS_SPEED_AND_DUPLEX_12GXFD
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700133#define LINK_12_5GTFD LINK_STATUS_SPEED_AND_DUPLEX_12_5GTFD
134#define LINK_12_5GXFD LINK_STATUS_SPEED_AND_DUPLEX_12_5GXFD
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000135#define LINK_13GTFD LINK_STATUS_SPEED_AND_DUPLEX_13GTFD
136#define LINK_13GXFD LINK_STATUS_SPEED_AND_DUPLEX_13GXFD
137#define LINK_15GTFD LINK_STATUS_SPEED_AND_DUPLEX_15GTFD
138#define LINK_15GXFD LINK_STATUS_SPEED_AND_DUPLEX_15GXFD
139#define LINK_16GTFD LINK_STATUS_SPEED_AND_DUPLEX_16GTFD
140#define LINK_16GXFD LINK_STATUS_SPEED_AND_DUPLEX_16GXFD
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700141
142#define PHY_XGXS_FLAG 0x1
143#define PHY_SGMII_FLAG 0x2
144#define PHY_SERDES_FLAG 0x4
145
Eilon Greenstein589abe32009-02-12 08:36:55 +0000146/* */
147#define SFP_EEPROM_CON_TYPE_ADDR 0x2
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000148 #define SFP_EEPROM_CON_TYPE_VAL_LC 0x7
Eilon Greenstein589abe32009-02-12 08:36:55 +0000149 #define SFP_EEPROM_CON_TYPE_VAL_COPPER 0x21
150
Eilon Greenstein4d295db2009-07-21 05:47:47 +0000151
152#define SFP_EEPROM_COMP_CODE_ADDR 0x3
153 #define SFP_EEPROM_COMP_CODE_SR_MASK (1<<4)
154 #define SFP_EEPROM_COMP_CODE_LR_MASK (1<<5)
155 #define SFP_EEPROM_COMP_CODE_LRM_MASK (1<<6)
156
Eilon Greenstein589abe32009-02-12 08:36:55 +0000157#define SFP_EEPROM_FC_TX_TECH_ADDR 0x8
158 #define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE 0x4
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000159 #define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE 0x8
Eilon Greenstein4d295db2009-07-21 05:47:47 +0000160
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000161#define SFP_EEPROM_OPTIONS_ADDR 0x40
Eilon Greenstein589abe32009-02-12 08:36:55 +0000162 #define SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK 0x1
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000163#define SFP_EEPROM_OPTIONS_SIZE 2
Eilon Greenstein589abe32009-02-12 08:36:55 +0000164
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000165#define EDC_MODE_LINEAR 0x0022
166#define EDC_MODE_LIMITING 0x0044
167#define EDC_MODE_PASSIVE_DAC 0x0055
Eilon Greenstein589abe32009-02-12 08:36:55 +0000168
Eilon Greenstein4d295db2009-07-21 05:47:47 +0000169
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000170#define ETS_BW_LIMIT_CREDIT_UPPER_BOUND (0x5000)
171#define ETS_BW_LIMIT_CREDIT_WEIGHT (0x5000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700172/**********************************************************/
173/* INTERFACE */
174/**********************************************************/
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000175
Yaniv Rosnercd2be892011-01-31 04:21:45 +0000176#define CL22_WR_OVER_CL45(_bp, _phy, _bank, _addr, _val) \
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000177 bnx2x_cl45_write(_bp, _phy, \
Yaniv Rosner7aa07112010-09-07 11:41:01 +0000178 (_phy)->def_md_devad, \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700179 (_bank + (_addr & 0xf)), \
180 _val)
181
Yaniv Rosnercd2be892011-01-31 04:21:45 +0000182#define CL22_RD_OVER_CL45(_bp, _phy, _bank, _addr, _val) \
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000183 bnx2x_cl45_read(_bp, _phy, \
Yaniv Rosner7aa07112010-09-07 11:41:01 +0000184 (_phy)->def_md_devad, \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700185 (_bank + (_addr & 0xf)), \
186 _val)
187
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700188static u32 bnx2x_bits_en(struct bnx2x *bp, u32 reg, u32 bits)
189{
190 u32 val = REG_RD(bp, reg);
191
192 val |= bits;
193 REG_WR(bp, reg, val);
194 return val;
195}
196
197static u32 bnx2x_bits_dis(struct bnx2x *bp, u32 reg, u32 bits)
198{
199 u32 val = REG_RD(bp, reg);
200
201 val &= ~bits;
202 REG_WR(bp, reg, val);
203 return val;
204}
205
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000206/******************************************************************/
207/* ETS section */
208/******************************************************************/
209void bnx2x_ets_disabled(struct link_params *params)
210{
211 /* ETS disabled configuration*/
212 struct bnx2x *bp = params->bp;
213
214 DP(NETIF_MSG_LINK, "ETS disabled configuration\n");
215
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000216 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000217 * mapping between entry priority to client number (0,1,2 -debug and
218 * management clients, 3 - COS0 client, 4 - COS client)(HIGHEST)
219 * 3bits client num.
220 * PRI4 | PRI3 | PRI2 | PRI1 | PRI0
221 * cos1-100 cos0-011 dbg1-010 dbg0-001 MCP-000
222 */
223
224 REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT, 0x4688);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000225 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000226 * Bitmap of 5bits length. Each bit specifies whether the entry behaves
227 * as strict. Bits 0,1,2 - debug and management entries, 3 -
228 * COS0 entry, 4 - COS1 entry.
229 * COS1 | COS0 | DEBUG1 | DEBUG0 | MGMT
230 * bit4 bit3 bit2 bit1 bit0
231 * MCP and debug are strict
232 */
233
234 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x7);
235 /* defines which entries (clients) are subjected to WFQ arbitration */
236 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ, 0);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000237 /*
238 * For strict priority entries defines the number of consecutive
239 * slots for the highest priority.
240 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000241 REG_WR(bp, NIG_REG_P0_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000242 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000243 * mapping between the CREDIT_WEIGHT registers and actual client
244 * numbers
245 */
246 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP, 0);
247 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_0, 0);
248 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_1, 0);
249
250 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_0, 0);
251 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_1, 0);
252 REG_WR(bp, PBF_REG_HIGH_PRIORITY_COS_NUM, 0);
253 /* ETS mode disable */
254 REG_WR(bp, PBF_REG_ETS_ENABLED, 0);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000255 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000256 * If ETS mode is enabled (there is no strict priority) defines a WFQ
257 * weight for COS0/COS1.
258 */
259 REG_WR(bp, PBF_REG_COS0_WEIGHT, 0x2710);
260 REG_WR(bp, PBF_REG_COS1_WEIGHT, 0x2710);
261 /* Upper bound that COS0_WEIGHT can reach in the WFQ arbiter */
262 REG_WR(bp, PBF_REG_COS0_UPPER_BOUND, 0x989680);
263 REG_WR(bp, PBF_REG_COS1_UPPER_BOUND, 0x989680);
264 /* Defines the number of consecutive slots for the strict priority */
265 REG_WR(bp, PBF_REG_NUM_STRICT_ARB_SLOTS, 0);
266}
267
Yaniv Rosner65a001b2011-01-31 04:22:03 +0000268static void bnx2x_ets_bw_limit_common(const struct link_params *params)
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000269{
270 /* ETS disabled configuration */
271 struct bnx2x *bp = params->bp;
272 DP(NETIF_MSG_LINK, "ETS enabled BW limit configuration\n");
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000273 /*
274 * defines which entries (clients) are subjected to WFQ arbitration
275 * COS0 0x8
276 * COS1 0x10
277 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000278 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ, 0x18);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000279 /*
280 * mapping between the ARB_CREDIT_WEIGHT registers and actual
281 * client numbers (WEIGHT_0 does not actually have to represent
282 * client 0)
283 * PRI4 | PRI3 | PRI2 | PRI1 | PRI0
284 * cos1-001 cos0-000 dbg1-100 dbg0-011 MCP-010
285 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000286 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP, 0x111A);
287
288 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_0,
289 ETS_BW_LIMIT_CREDIT_UPPER_BOUND);
290 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_1,
291 ETS_BW_LIMIT_CREDIT_UPPER_BOUND);
292
293 /* ETS mode enabled*/
294 REG_WR(bp, PBF_REG_ETS_ENABLED, 1);
295
296 /* Defines the number of consecutive slots for the strict priority */
297 REG_WR(bp, PBF_REG_NUM_STRICT_ARB_SLOTS, 0);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000298 /*
299 * Bitmap of 5bits length. Each bit specifies whether the entry behaves
300 * as strict. Bits 0,1,2 - debug and management entries, 3 - COS0
301 * entry, 4 - COS1 entry.
302 * COS1 | COS0 | DEBUG21 | DEBUG0 | MGMT
303 * bit4 bit3 bit2 bit1 bit0
304 * MCP and debug are strict
305 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000306 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x7);
307
308 /* Upper bound that COS0_WEIGHT can reach in the WFQ arbiter.*/
309 REG_WR(bp, PBF_REG_COS0_UPPER_BOUND,
310 ETS_BW_LIMIT_CREDIT_UPPER_BOUND);
311 REG_WR(bp, PBF_REG_COS1_UPPER_BOUND,
312 ETS_BW_LIMIT_CREDIT_UPPER_BOUND);
313}
314
315void bnx2x_ets_bw_limit(const struct link_params *params, const u32 cos0_bw,
316 const u32 cos1_bw)
317{
318 /* ETS disabled configuration*/
319 struct bnx2x *bp = params->bp;
320 const u32 total_bw = cos0_bw + cos1_bw;
321 u32 cos0_credit_weight = 0;
322 u32 cos1_credit_weight = 0;
323
324 DP(NETIF_MSG_LINK, "ETS enabled BW limit configuration\n");
325
326 if ((0 == total_bw) ||
327 (0 == cos0_bw) ||
328 (0 == cos1_bw)) {
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000329 DP(NETIF_MSG_LINK, "Total BW can't be zero\n");
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000330 return;
331 }
332
333 cos0_credit_weight = (cos0_bw * ETS_BW_LIMIT_CREDIT_WEIGHT)/
334 total_bw;
335 cos1_credit_weight = (cos1_bw * ETS_BW_LIMIT_CREDIT_WEIGHT)/
336 total_bw;
337
338 bnx2x_ets_bw_limit_common(params);
339
340 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_0, cos0_credit_weight);
341 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_1, cos1_credit_weight);
342
343 REG_WR(bp, PBF_REG_COS0_WEIGHT, cos0_credit_weight);
344 REG_WR(bp, PBF_REG_COS1_WEIGHT, cos1_credit_weight);
345}
346
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +0000347int bnx2x_ets_strict(const struct link_params *params, const u8 strict_cos)
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000348{
349 /* ETS disabled configuration*/
350 struct bnx2x *bp = params->bp;
351 u32 val = 0;
352
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000353 DP(NETIF_MSG_LINK, "ETS enabled strict configuration\n");
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000354 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000355 * Bitmap of 5bits length. Each bit specifies whether the entry behaves
356 * as strict. Bits 0,1,2 - debug and management entries,
357 * 3 - COS0 entry, 4 - COS1 entry.
358 * COS1 | COS0 | DEBUG21 | DEBUG0 | MGMT
359 * bit4 bit3 bit2 bit1 bit0
360 * MCP and debug are strict
361 */
362 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x1F);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000363 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000364 * For strict priority entries defines the number of consecutive slots
365 * for the highest priority.
366 */
367 REG_WR(bp, NIG_REG_P0_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100);
368 /* ETS mode disable */
369 REG_WR(bp, PBF_REG_ETS_ENABLED, 0);
370 /* Defines the number of consecutive slots for the strict priority */
371 REG_WR(bp, PBF_REG_NUM_STRICT_ARB_SLOTS, 0x100);
372
373 /* Defines the number of consecutive slots for the strict priority */
374 REG_WR(bp, PBF_REG_HIGH_PRIORITY_COS_NUM, strict_cos);
375
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000376 /*
377 * mapping between entry priority to client number (0,1,2 -debug and
378 * management clients, 3 - COS0 client, 4 - COS client)(HIGHEST)
379 * 3bits client num.
380 * PRI4 | PRI3 | PRI2 | PRI1 | PRI0
381 * dbg0-010 dbg1-001 cos1-100 cos0-011 MCP-000
382 * dbg0-010 dbg1-001 cos0-011 cos1-100 MCP-000
383 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000384 val = (0 == strict_cos) ? 0x2318 : 0x22E0;
385 REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT, val);
386
387 return 0;
388}
389/******************************************************************/
Dmitry Kravkove8920672011-05-04 23:52:40 +0000390/* PFC section */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000391/******************************************************************/
392
393static void bnx2x_bmac2_get_pfc_stat(struct link_params *params,
394 u32 pfc_frames_sent[2],
395 u32 pfc_frames_received[2])
396{
397 /* Read pfc statistic */
398 struct bnx2x *bp = params->bp;
399 u32 bmac_addr = params->port ? NIG_REG_INGRESS_BMAC1_MEM :
400 NIG_REG_INGRESS_BMAC0_MEM;
401
402 DP(NETIF_MSG_LINK, "pfc statistic read from BMAC\n");
403
404 REG_RD_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_STAT_GTPP,
405 pfc_frames_sent, 2);
406
407 REG_RD_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_STAT_GRPP,
408 pfc_frames_received, 2);
409
410}
411static void bnx2x_emac_get_pfc_stat(struct link_params *params,
412 u32 pfc_frames_sent[2],
413 u32 pfc_frames_received[2])
414{
415 /* Read pfc statistic */
416 struct bnx2x *bp = params->bp;
417 u32 emac_base = params->port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
418 u32 val_xon = 0;
419 u32 val_xoff = 0;
420
421 DP(NETIF_MSG_LINK, "pfc statistic read from EMAC\n");
422
423 /* PFC received frames */
424 val_xoff = REG_RD(bp, emac_base +
425 EMAC_REG_RX_PFC_STATS_XOFF_RCVD);
426 val_xoff &= EMAC_REG_RX_PFC_STATS_XOFF_RCVD_COUNT;
427 val_xon = REG_RD(bp, emac_base + EMAC_REG_RX_PFC_STATS_XON_RCVD);
428 val_xon &= EMAC_REG_RX_PFC_STATS_XON_RCVD_COUNT;
429
430 pfc_frames_received[0] = val_xon + val_xoff;
431
432 /* PFC received sent */
433 val_xoff = REG_RD(bp, emac_base +
434 EMAC_REG_RX_PFC_STATS_XOFF_SENT);
435 val_xoff &= EMAC_REG_RX_PFC_STATS_XOFF_SENT_COUNT;
436 val_xon = REG_RD(bp, emac_base + EMAC_REG_RX_PFC_STATS_XON_SENT);
437 val_xon &= EMAC_REG_RX_PFC_STATS_XON_SENT_COUNT;
438
439 pfc_frames_sent[0] = val_xon + val_xoff;
440}
441
442void bnx2x_pfc_statistic(struct link_params *params, struct link_vars *vars,
443 u32 pfc_frames_sent[2],
444 u32 pfc_frames_received[2])
445{
446 /* Read pfc statistic */
447 struct bnx2x *bp = params->bp;
448 u32 val = 0;
449 DP(NETIF_MSG_LINK, "pfc statistic\n");
450
451 if (!vars->link_up)
452 return;
453
454 val = REG_RD(bp, MISC_REG_RESET_REG_2);
455 if ((val & (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << params->port))
456 == 0) {
457 DP(NETIF_MSG_LINK, "About to read stats from EMAC\n");
458 bnx2x_emac_get_pfc_stat(params, pfc_frames_sent,
459 pfc_frames_received);
460 } else {
461 DP(NETIF_MSG_LINK, "About to read stats from BMAC\n");
462 bnx2x_bmac2_get_pfc_stat(params, pfc_frames_sent,
463 pfc_frames_received);
464 }
465}
466/******************************************************************/
467/* MAC/PBF section */
468/******************************************************************/
Yaniv Rosnera198c142011-05-31 21:29:42 +0000469static void bnx2x_set_mdio_clk(struct bnx2x *bp, u32 chip_id, u8 port)
470{
471 u32 mode, emac_base;
472 /**
473 * Set clause 45 mode, slow down the MDIO clock to 2.5MHz
474 * (a value of 49==0x31) and make sure that the AUTO poll is off
475 */
476
477 if (CHIP_IS_E2(bp))
478 emac_base = GRCBASE_EMAC0;
479 else
480 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
481 mode = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
482 mode &= ~(EMAC_MDIO_MODE_AUTO_POLL |
483 EMAC_MDIO_MODE_CLOCK_CNT);
484 mode |= (49L << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT);
485
486 mode |= (EMAC_MDIO_MODE_CLAUSE_45);
487 REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE, mode);
488
489 udelay(40);
490}
491
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700492static void bnx2x_emac_init(struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000493 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700494{
495 /* reset and unreset the emac core */
496 struct bnx2x *bp = params->bp;
497 u8 port = params->port;
498 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
499 u32 val;
500 u16 timeout;
501
502 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000503 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700504 udelay(5);
505 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000506 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700507
508 /* init emac - use read-modify-write */
509 /* self clear reset */
510 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700511 EMAC_WR(bp, EMAC_REG_EMAC_MODE, (val | EMAC_MODE_RESET));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700512
513 timeout = 200;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700514 do {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700515 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
516 DP(NETIF_MSG_LINK, "EMAC reset reg is %u\n", val);
517 if (!timeout) {
518 DP(NETIF_MSG_LINK, "EMAC timeout!\n");
519 return;
520 }
521 timeout--;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700522 } while (val & EMAC_MODE_RESET);
Yaniv Rosnera198c142011-05-31 21:29:42 +0000523 bnx2x_set_mdio_clk(bp, params->chip_id, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700524 /* Set mac address */
525 val = ((params->mac_addr[0] << 8) |
526 params->mac_addr[1]);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700527 EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700528
529 val = ((params->mac_addr[2] << 24) |
530 (params->mac_addr[3] << 16) |
531 (params->mac_addr[4] << 8) |
532 params->mac_addr[5]);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700533 EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH + 4, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700534}
535
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +0000536static int bnx2x_emac_enable(struct link_params *params,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +0000537 struct link_vars *vars, u8 lb)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700538{
539 struct bnx2x *bp = params->bp;
540 u8 port = params->port;
541 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
542 u32 val;
543
544 DP(NETIF_MSG_LINK, "enabling EMAC\n");
545
546 /* enable emac and not bmac */
547 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 1);
548
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700549 /* ASIC */
550 if (vars->phy_flags & PHY_XGXS_FLAG) {
551 u32 ser_lane = ((params->lane_config &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000552 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
553 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700554
555 DP(NETIF_MSG_LINK, "XGXS\n");
556 /* select the master lanes (out of 0-3) */
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000557 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, ser_lane);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700558 /* select XGXS */
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000559 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700560
561 } else { /* SerDes */
562 DP(NETIF_MSG_LINK, "SerDes\n");
563 /* select SerDes */
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000564 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700565 }
566
Eilon Greenstein811a2f22009-02-12 08:37:04 +0000567 bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000568 EMAC_RX_MODE_RESET);
Eilon Greenstein811a2f22009-02-12 08:37:04 +0000569 bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000570 EMAC_TX_MODE_RESET);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700571
572 if (CHIP_REV_IS_SLOW(bp)) {
573 /* config GMII mode */
574 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000575 EMAC_WR(bp, EMAC_REG_EMAC_MODE, (val | EMAC_MODE_PORT_GMII));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700576 } else { /* ASIC */
577 /* pause enable/disable */
578 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
579 EMAC_RX_MODE_FLOW_EN);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700580
581 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000582 (EMAC_TX_MODE_EXT_PAUSE_EN |
583 EMAC_TX_MODE_FLOW_EN));
584 if (!(params->feature_config_flags &
585 FEATURE_CONFIG_PFC_ENABLED)) {
586 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
587 bnx2x_bits_en(bp, emac_base +
588 EMAC_REG_EMAC_RX_MODE,
589 EMAC_RX_MODE_FLOW_EN);
590
591 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
592 bnx2x_bits_en(bp, emac_base +
593 EMAC_REG_EMAC_TX_MODE,
594 (EMAC_TX_MODE_EXT_PAUSE_EN |
595 EMAC_TX_MODE_FLOW_EN));
596 } else
597 bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
598 EMAC_TX_MODE_FLOW_EN);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700599 }
600
601 /* KEEP_VLAN_TAG, promiscuous */
602 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_RX_MODE);
603 val |= EMAC_RX_MODE_KEEP_VLAN_TAG | EMAC_RX_MODE_PROMISCUOUS;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000604
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000605 /*
606 * Setting this bit causes MAC control frames (except for pause
607 * frames) to be passed on for processing. This setting has no
608 * affect on the operation of the pause frames. This bit effects
609 * all packets regardless of RX Parser packet sorting logic.
610 * Turn the PFC off to make sure we are in Xon state before
611 * enabling it.
612 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000613 EMAC_WR(bp, EMAC_REG_RX_PFC_MODE, 0);
614 if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED) {
615 DP(NETIF_MSG_LINK, "PFC is enabled\n");
616 /* Enable PFC again */
617 EMAC_WR(bp, EMAC_REG_RX_PFC_MODE,
618 EMAC_REG_RX_PFC_MODE_RX_EN |
619 EMAC_REG_RX_PFC_MODE_TX_EN |
620 EMAC_REG_RX_PFC_MODE_PRIORITIES);
621
622 EMAC_WR(bp, EMAC_REG_RX_PFC_PARAM,
623 ((0x0101 <<
624 EMAC_REG_RX_PFC_PARAM_OPCODE_BITSHIFT) |
625 (0x00ff <<
626 EMAC_REG_RX_PFC_PARAM_PRIORITY_EN_BITSHIFT)));
627 val |= EMAC_RX_MODE_KEEP_MAC_CONTROL;
628 }
Eilon Greenstein3196a882008-08-13 15:58:49 -0700629 EMAC_WR(bp, EMAC_REG_EMAC_RX_MODE, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700630
631 /* Set Loopback */
632 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
633 if (lb)
634 val |= 0x810;
635 else
636 val &= ~0x810;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700637 EMAC_WR(bp, EMAC_REG_EMAC_MODE, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700638
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +0000639 /* enable emac */
640 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 1);
641
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700642 /* enable emac for jumbo packets */
Eilon Greenstein3196a882008-08-13 15:58:49 -0700643 EMAC_WR(bp, EMAC_REG_EMAC_RX_MTU_SIZE,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700644 (EMAC_RX_MTU_SIZE_JUMBO_ENA |
645 (ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD)));
646
647 /* strip CRC */
648 REG_WR(bp, NIG_REG_NIG_INGRESS_EMAC0_NO_CRC + port*4, 0x1);
649
650 /* disable the NIG in/out to the bmac */
651 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x0);
652 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, 0x0);
653 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x0);
654
655 /* enable the NIG in/out to the emac */
656 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x1);
657 val = 0;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000658 if ((params->feature_config_flags &
659 FEATURE_CONFIG_PFC_ENABLED) ||
660 (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700661 val = 1;
662
663 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, val);
664 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x1);
665
Yaniv Rosner02a23162011-01-31 04:22:53 +0000666 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700667
668 vars->mac_type = MAC_TYPE_EMAC;
669 return 0;
670}
671
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000672static void bnx2x_update_pfc_bmac1(struct link_params *params,
673 struct link_vars *vars)
674{
675 u32 wb_data[2];
676 struct bnx2x *bp = params->bp;
677 u32 bmac_addr = params->port ? NIG_REG_INGRESS_BMAC1_MEM :
678 NIG_REG_INGRESS_BMAC0_MEM;
679
680 u32 val = 0x14;
681 if ((!(params->feature_config_flags &
682 FEATURE_CONFIG_PFC_ENABLED)) &&
683 (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX))
684 /* Enable BigMAC to react on received Pause packets */
685 val |= (1<<5);
686 wb_data[0] = val;
687 wb_data[1] = 0;
688 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_CONTROL, wb_data, 2);
689
690 /* tx control */
691 val = 0xc0;
692 if (!(params->feature_config_flags &
693 FEATURE_CONFIG_PFC_ENABLED) &&
694 (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
695 val |= 0x800000;
696 wb_data[0] = val;
697 wb_data[1] = 0;
698 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_CONTROL, wb_data, 2);
699}
700
701static void bnx2x_update_pfc_bmac2(struct link_params *params,
702 struct link_vars *vars,
703 u8 is_lb)
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000704{
705 /*
706 * Set rx control: Strip CRC and enable BigMAC to relay
707 * control packets to the system as well
708 */
709 u32 wb_data[2];
710 struct bnx2x *bp = params->bp;
711 u32 bmac_addr = params->port ? NIG_REG_INGRESS_BMAC1_MEM :
712 NIG_REG_INGRESS_BMAC0_MEM;
713 u32 val = 0x14;
714
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000715 if ((!(params->feature_config_flags &
716 FEATURE_CONFIG_PFC_ENABLED)) &&
717 (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX))
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000718 /* Enable BigMAC to react on received Pause packets */
719 val |= (1<<5);
720 wb_data[0] = val;
721 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000722 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_CONTROL, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000723 udelay(30);
724
725 /* Tx control */
726 val = 0xc0;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000727 if (!(params->feature_config_flags &
728 FEATURE_CONFIG_PFC_ENABLED) &&
729 (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000730 val |= 0x800000;
731 wb_data[0] = val;
732 wb_data[1] = 0;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000733 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_CONTROL, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000734
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000735 if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED) {
736 DP(NETIF_MSG_LINK, "PFC is enabled\n");
737 /* Enable PFC RX & TX & STATS and set 8 COS */
738 wb_data[0] = 0x0;
739 wb_data[0] |= (1<<0); /* RX */
740 wb_data[0] |= (1<<1); /* TX */
741 wb_data[0] |= (1<<2); /* Force initial Xon */
742 wb_data[0] |= (1<<3); /* 8 cos */
743 wb_data[0] |= (1<<5); /* STATS */
744 wb_data[1] = 0;
745 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_PFC_CONTROL,
746 wb_data, 2);
747 /* Clear the force Xon */
748 wb_data[0] &= ~(1<<2);
749 } else {
750 DP(NETIF_MSG_LINK, "PFC is disabled\n");
751 /* disable PFC RX & TX & STATS and set 8 COS */
752 wb_data[0] = 0x8;
753 wb_data[1] = 0;
754 }
755
756 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_PFC_CONTROL, wb_data, 2);
757
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000758 /*
759 * Set Time (based unit is 512 bit time) between automatic
760 * re-sending of PP packets amd enable automatic re-send of
761 * Per-Priroity Packet as long as pp_gen is asserted and
762 * pp_disable is low.
763 */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000764 val = 0x8000;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000765 if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED)
766 val |= (1<<16); /* enable automatic re-send */
767
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000768 wb_data[0] = val;
769 wb_data[1] = 0;
770 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_PAUSE_CONTROL,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000771 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000772
773 /* mac control */
774 val = 0x3; /* Enable RX and TX */
775 if (is_lb) {
776 val |= 0x4; /* Local loopback */
777 DP(NETIF_MSG_LINK, "enable bmac loopback\n");
778 }
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000779 /* When PFC enabled, Pass pause frames towards the NIG. */
780 if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED)
781 val |= ((1<<6)|(1<<5));
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000782
783 wb_data[0] = val;
784 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000785 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_BMAC_CONTROL, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +0000786}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700787
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000788static void bnx2x_update_pfc_brb(struct link_params *params,
789 struct link_vars *vars,
790 struct bnx2x_nig_brb_pfc_port_params *pfc_params)
791{
792 struct bnx2x *bp = params->bp;
793 int set_pfc = params->feature_config_flags &
794 FEATURE_CONFIG_PFC_ENABLED;
795
796 /* default - pause configuration */
797 u32 pause_xoff_th = PFC_BRB_MAC_PAUSE_XOFF_THRESHOLD_PAUSEABLE;
798 u32 pause_xon_th = PFC_BRB_MAC_PAUSE_XON_THRESHOLD_PAUSEABLE;
799 u32 full_xoff_th = PFC_BRB_MAC_FULL_XOFF_THRESHOLD_PAUSEABLE;
800 u32 full_xon_th = PFC_BRB_MAC_FULL_XON_THRESHOLD_PAUSEABLE;
801
802 if (set_pfc && pfc_params)
803 /* First COS */
804 if (!pfc_params->cos0_pauseable) {
805 pause_xoff_th =
806 PFC_BRB_MAC_PAUSE_XOFF_THRESHOLD_NON_PAUSEABLE;
807 pause_xon_th =
808 PFC_BRB_MAC_PAUSE_XON_THRESHOLD_NON_PAUSEABLE;
809 full_xoff_th =
810 PFC_BRB_MAC_FULL_XOFF_THRESHOLD_NON_PAUSEABLE;
811 full_xon_th =
812 PFC_BRB_MAC_FULL_XON_THRESHOLD_NON_PAUSEABLE;
813 }
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000814 /*
815 * The number of free blocks below which the pause signal to class 0
816 * of MAC #n is asserted. n=0,1
817 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000818 REG_WR(bp, BRB1_REG_PAUSE_0_XOFF_THRESHOLD_0 , pause_xoff_th);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000819 /*
820 * The number of free blocks above which the pause signal to class 0
821 * of MAC #n is de-asserted. n=0,1
822 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000823 REG_WR(bp, BRB1_REG_PAUSE_0_XON_THRESHOLD_0 , pause_xon_th);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000824 /*
825 * The number of free blocks below which the full signal to class 0
826 * of MAC #n is asserted. n=0,1
827 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000828 REG_WR(bp, BRB1_REG_FULL_0_XOFF_THRESHOLD_0 , full_xoff_th);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000829 /*
830 * The number of free blocks above which the full signal to class 0
831 * of MAC #n is de-asserted. n=0,1
832 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000833 REG_WR(bp, BRB1_REG_FULL_0_XON_THRESHOLD_0 , full_xon_th);
834
835 if (set_pfc && pfc_params) {
836 /* Second COS */
837 if (pfc_params->cos1_pauseable) {
838 pause_xoff_th =
839 PFC_BRB_MAC_PAUSE_XOFF_THRESHOLD_PAUSEABLE;
840 pause_xon_th =
841 PFC_BRB_MAC_PAUSE_XON_THRESHOLD_PAUSEABLE;
842 full_xoff_th =
843 PFC_BRB_MAC_FULL_XOFF_THRESHOLD_PAUSEABLE;
844 full_xon_th =
845 PFC_BRB_MAC_FULL_XON_THRESHOLD_PAUSEABLE;
846 } else {
847 pause_xoff_th =
848 PFC_BRB_MAC_PAUSE_XOFF_THRESHOLD_NON_PAUSEABLE;
849 pause_xon_th =
850 PFC_BRB_MAC_PAUSE_XON_THRESHOLD_NON_PAUSEABLE;
851 full_xoff_th =
852 PFC_BRB_MAC_FULL_XOFF_THRESHOLD_NON_PAUSEABLE;
853 full_xon_th =
854 PFC_BRB_MAC_FULL_XON_THRESHOLD_NON_PAUSEABLE;
855 }
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000856 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000857 * The number of free blocks below which the pause signal to
858 * class 1 of MAC #n is asserted. n=0,1
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000859 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000860 REG_WR(bp, BRB1_REG_PAUSE_1_XOFF_THRESHOLD_0, pause_xoff_th);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000861 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000862 * The number of free blocks above which the pause signal to
863 * class 1 of MAC #n is de-asserted. n=0,1
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000864 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000865 REG_WR(bp, BRB1_REG_PAUSE_1_XON_THRESHOLD_0, pause_xon_th);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000866 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000867 * The number of free blocks below which the full signal to
868 * class 1 of MAC #n is asserted. n=0,1
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000869 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000870 REG_WR(bp, BRB1_REG_FULL_1_XOFF_THRESHOLD_0, full_xoff_th);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000871 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000872 * The number of free blocks above which the full signal to
873 * class 1 of MAC #n is de-asserted. n=0,1
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000874 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000875 REG_WR(bp, BRB1_REG_FULL_1_XON_THRESHOLD_0, full_xon_th);
876 }
877}
878
Vlad Zolotarov619c5cb2011-06-14 14:33:44 +0300879/******************************************************************************
880* Description:
881* This function is needed because NIG ARB_CREDIT_WEIGHT_X are
882* not continues and ARB_CREDIT_WEIGHT_0 + offset is suitable.
883******************************************************************************/
884int bnx2x_pfc_nig_rx_priority_mask(struct bnx2x *bp,
885 u8 cos_entry,
886 u32 priority_mask, u8 port)
887{
888 u32 nig_reg_rx_priority_mask_add = 0;
889
890 switch (cos_entry) {
891 case 0:
892 nig_reg_rx_priority_mask_add = (port) ?
893 NIG_REG_P1_RX_COS0_PRIORITY_MASK :
894 NIG_REG_P0_RX_COS0_PRIORITY_MASK;
895 break;
896 case 1:
897 nig_reg_rx_priority_mask_add = (port) ?
898 NIG_REG_P1_RX_COS1_PRIORITY_MASK :
899 NIG_REG_P0_RX_COS1_PRIORITY_MASK;
900 break;
901 case 2:
902 nig_reg_rx_priority_mask_add = (port) ?
903 NIG_REG_P1_RX_COS2_PRIORITY_MASK :
904 NIG_REG_P0_RX_COS2_PRIORITY_MASK;
905 break;
906 case 3:
907 if (port)
908 return -EINVAL;
909 nig_reg_rx_priority_mask_add = NIG_REG_P0_RX_COS3_PRIORITY_MASK;
910 break;
911 case 4:
912 if (port)
913 return -EINVAL;
914 nig_reg_rx_priority_mask_add = NIG_REG_P0_RX_COS4_PRIORITY_MASK;
915 break;
916 case 5:
917 if (port)
918 return -EINVAL;
919 nig_reg_rx_priority_mask_add = NIG_REG_P0_RX_COS5_PRIORITY_MASK;
920 break;
921 }
922
923 REG_WR(bp, nig_reg_rx_priority_mask_add, priority_mask);
924
925 return 0;
926}
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000927static void bnx2x_update_pfc_nig(struct link_params *params,
928 struct link_vars *vars,
929 struct bnx2x_nig_brb_pfc_port_params *nig_params)
930{
931 u32 xcm_mask = 0, ppp_enable = 0, pause_enable = 0, llfc_out_en = 0;
932 u32 llfc_enable = 0, xcm0_out_en = 0, p0_hwpfc_enable = 0;
933 u32 pkt_priority_to_cos = 0;
934 u32 val;
935 struct bnx2x *bp = params->bp;
936 int port = params->port;
937 int set_pfc = params->feature_config_flags &
938 FEATURE_CONFIG_PFC_ENABLED;
939 DP(NETIF_MSG_LINK, "updating pfc nig parameters\n");
940
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000941 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000942 * When NIG_LLH0_XCM_MASK_REG_LLHX_XCM_MASK_BCN bit is set
943 * MAC control frames (that are not pause packets)
944 * will be forwarded to the XCM.
945 */
946 xcm_mask = REG_RD(bp,
947 port ? NIG_REG_LLH1_XCM_MASK :
948 NIG_REG_LLH0_XCM_MASK);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000949 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000950 * nig params will override non PFC params, since it's possible to
951 * do transition from PFC to SAFC
952 */
953 if (set_pfc) {
954 pause_enable = 0;
955 llfc_out_en = 0;
956 llfc_enable = 0;
957 ppp_enable = 1;
958 xcm_mask &= ~(port ? NIG_LLH1_XCM_MASK_REG_LLH1_XCM_MASK_BCN :
959 NIG_LLH0_XCM_MASK_REG_LLH0_XCM_MASK_BCN);
960 xcm0_out_en = 0;
961 p0_hwpfc_enable = 1;
962 } else {
963 if (nig_params) {
964 llfc_out_en = nig_params->llfc_out_en;
965 llfc_enable = nig_params->llfc_enable;
966 pause_enable = nig_params->pause_enable;
967 } else /*defaul non PFC mode - PAUSE */
968 pause_enable = 1;
969
970 xcm_mask |= (port ? NIG_LLH1_XCM_MASK_REG_LLH1_XCM_MASK_BCN :
971 NIG_LLH0_XCM_MASK_REG_LLH0_XCM_MASK_BCN);
972 xcm0_out_en = 1;
973 }
974
975 REG_WR(bp, port ? NIG_REG_LLFC_OUT_EN_1 :
976 NIG_REG_LLFC_OUT_EN_0, llfc_out_en);
977 REG_WR(bp, port ? NIG_REG_LLFC_ENABLE_1 :
978 NIG_REG_LLFC_ENABLE_0, llfc_enable);
979 REG_WR(bp, port ? NIG_REG_PAUSE_ENABLE_1 :
980 NIG_REG_PAUSE_ENABLE_0, pause_enable);
981
982 REG_WR(bp, port ? NIG_REG_PPP_ENABLE_1 :
983 NIG_REG_PPP_ENABLE_0, ppp_enable);
984
985 REG_WR(bp, port ? NIG_REG_LLH1_XCM_MASK :
986 NIG_REG_LLH0_XCM_MASK, xcm_mask);
987
988 REG_WR(bp, NIG_REG_LLFC_EGRESS_SRC_ENABLE_0, 0x7);
989
990 /* output enable for RX_XCM # IF */
991 REG_WR(bp, NIG_REG_XCM0_OUT_EN, xcm0_out_en);
992
993 /* HW PFC TX enable */
994 REG_WR(bp, NIG_REG_P0_HWPFC_ENABLE, p0_hwpfc_enable);
995
996 /* 0x2 = BMAC, 0x1= EMAC */
997 switch (vars->mac_type) {
998 case MAC_TYPE_EMAC:
999 val = 1;
1000 break;
1001 case MAC_TYPE_BMAC:
1002 val = 0;
1003 break;
1004 default:
1005 val = 0;
1006 break;
1007 }
1008 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT, val);
1009
1010 if (nig_params) {
Vlad Zolotarov619c5cb2011-06-14 14:33:44 +03001011 u8 i = 0;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001012 pkt_priority_to_cos = nig_params->pkt_priority_to_cos;
1013
Vlad Zolotarov619c5cb2011-06-14 14:33:44 +03001014 for (i = 0; i < nig_params->num_of_rx_cos_priority_mask; i++)
1015 bnx2x_pfc_nig_rx_priority_mask(bp, i,
1016 nig_params->rx_cos_priority_mask[i], port);
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001017
1018 REG_WR(bp, port ? NIG_REG_LLFC_HIGH_PRIORITY_CLASSES_1 :
1019 NIG_REG_LLFC_HIGH_PRIORITY_CLASSES_0,
1020 nig_params->llfc_high_priority_classes);
1021
1022 REG_WR(bp, port ? NIG_REG_LLFC_LOW_PRIORITY_CLASSES_1 :
1023 NIG_REG_LLFC_LOW_PRIORITY_CLASSES_0,
1024 nig_params->llfc_low_priority_classes);
1025 }
1026 REG_WR(bp, port ? NIG_REG_P1_PKT_PRIORITY_TO_COS :
1027 NIG_REG_P0_PKT_PRIORITY_TO_COS,
1028 pkt_priority_to_cos);
1029}
1030
1031
1032void bnx2x_update_pfc(struct link_params *params,
1033 struct link_vars *vars,
1034 struct bnx2x_nig_brb_pfc_port_params *pfc_params)
1035{
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001036 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001037 * The PFC and pause are orthogonal to one another, meaning when
1038 * PFC is enabled, the pause are disabled, and when PFC is
1039 * disabled, pause are set according to the pause result.
1040 */
1041 u32 val;
1042 struct bnx2x *bp = params->bp;
1043
1044 /* update NIG params */
1045 bnx2x_update_pfc_nig(params, vars, pfc_params);
1046
1047 /* update BRB params */
1048 bnx2x_update_pfc_brb(params, vars, pfc_params);
1049
1050 if (!vars->link_up)
1051 return;
1052
1053 val = REG_RD(bp, MISC_REG_RESET_REG_2);
1054 if ((val & (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << params->port))
1055 == 0) {
1056 DP(NETIF_MSG_LINK, "About to update PFC in EMAC\n");
1057 bnx2x_emac_enable(params, vars, 0);
1058 return;
1059 }
1060
1061 DP(NETIF_MSG_LINK, "About to update PFC in BMAC\n");
1062 if (CHIP_IS_E2(bp))
1063 bnx2x_update_pfc_bmac2(params, vars, 0);
1064 else
1065 bnx2x_update_pfc_bmac1(params, vars);
1066
1067 val = 0;
1068 if ((params->feature_config_flags &
1069 FEATURE_CONFIG_PFC_ENABLED) ||
1070 (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
1071 val = 1;
1072 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + params->port*4, val);
1073}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001074
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00001075static int bnx2x_bmac1_enable(struct link_params *params,
1076 struct link_vars *vars,
1077 u8 is_lb)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001078{
1079 struct bnx2x *bp = params->bp;
1080 u8 port = params->port;
1081 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
1082 NIG_REG_INGRESS_BMAC0_MEM;
1083 u32 wb_data[2];
1084 u32 val;
1085
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001086 DP(NETIF_MSG_LINK, "Enabling BigMAC1\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001087
1088 /* XGXS control */
1089 wb_data[0] = 0x3c;
1090 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001091 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_XGXS_CONTROL,
1092 wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001093
1094 /* tx MAC SA */
1095 wb_data[0] = ((params->mac_addr[2] << 24) |
1096 (params->mac_addr[3] << 16) |
1097 (params->mac_addr[4] << 8) |
1098 params->mac_addr[5]);
1099 wb_data[1] = ((params->mac_addr[0] << 8) |
1100 params->mac_addr[1]);
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001101 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_SOURCE_ADDR, wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001102
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001103 /* mac control */
1104 val = 0x3;
1105 if (is_lb) {
1106 val |= 0x4;
1107 DP(NETIF_MSG_LINK, "enable bmac loopback\n");
1108 }
1109 wb_data[0] = val;
1110 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001111 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL, wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001112
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001113 /* set rx mtu */
1114 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
1115 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001116 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_MAX_SIZE, wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001117
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001118 bnx2x_update_pfc_bmac1(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001119
1120 /* set tx mtu */
1121 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
1122 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001123 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_MAX_SIZE, wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001124
1125 /* set cnt max size */
1126 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
1127 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001128 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_CNT_MAX_SIZE, wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001129
1130 /* configure safc */
1131 wb_data[0] = 0x1000200;
1132 wb_data[1] = 0;
1133 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_LLFC_MSG_FLDS,
1134 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001135
1136 return 0;
1137}
1138
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00001139static int bnx2x_bmac2_enable(struct link_params *params,
1140 struct link_vars *vars,
1141 u8 is_lb)
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001142{
1143 struct bnx2x *bp = params->bp;
1144 u8 port = params->port;
1145 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
1146 NIG_REG_INGRESS_BMAC0_MEM;
1147 u32 wb_data[2];
1148
1149 DP(NETIF_MSG_LINK, "Enabling BigMAC2\n");
1150
1151 wb_data[0] = 0;
1152 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001153 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_BMAC_CONTROL, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001154 udelay(30);
1155
1156 /* XGXS control: Reset phy HW, MDIO registers, PHY PLL and BMAC */
1157 wb_data[0] = 0x3c;
1158 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001159 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_BMAC_XGXS_CONTROL,
1160 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001161
1162 udelay(30);
1163
1164 /* tx MAC SA */
1165 wb_data[0] = ((params->mac_addr[2] << 24) |
1166 (params->mac_addr[3] << 16) |
1167 (params->mac_addr[4] << 8) |
1168 params->mac_addr[5]);
1169 wb_data[1] = ((params->mac_addr[0] << 8) |
1170 params->mac_addr[1]);
1171 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_SOURCE_ADDR,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001172 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001173
1174 udelay(30);
1175
1176 /* Configure SAFC */
1177 wb_data[0] = 0x1000200;
1178 wb_data[1] = 0;
1179 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_LLFC_MSG_FLDS,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001180 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001181 udelay(30);
1182
1183 /* set rx mtu */
1184 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
1185 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001186 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_MAX_SIZE, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001187 udelay(30);
1188
1189 /* set tx mtu */
1190 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
1191 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001192 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_MAX_SIZE, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001193 udelay(30);
1194 /* set cnt max size */
1195 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD - 2;
1196 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001197 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_CNT_MAX_SIZE, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001198 udelay(30);
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001199 bnx2x_update_pfc_bmac2(params, vars, is_lb);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001200
1201 return 0;
1202}
1203
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00001204static int bnx2x_bmac_enable(struct link_params *params,
1205 struct link_vars *vars,
1206 u8 is_lb)
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001207{
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00001208 int rc = 0;
1209 u8 port = params->port;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001210 struct bnx2x *bp = params->bp;
1211 u32 val;
1212 /* reset and unreset the BigMac */
1213 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001214 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
Yaniv Rosner1d9c05d2010-11-01 05:32:25 +00001215 msleep(1);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001216
1217 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001218 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001219
1220 /* enable access for bmac registers */
1221 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
1222
1223 /* Enable BMAC according to BMAC type*/
1224 if (CHIP_IS_E2(bp))
1225 rc = bnx2x_bmac2_enable(params, vars, is_lb);
1226 else
1227 rc = bnx2x_bmac1_enable(params, vars, is_lb);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001228 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0x1);
1229 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 0x0);
1230 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 0x0);
1231 val = 0;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001232 if ((params->feature_config_flags &
1233 FEATURE_CONFIG_PFC_ENABLED) ||
1234 (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001235 val = 1;
1236 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, val);
1237 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x0);
1238 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x0);
1239 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, 0x0);
1240 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x1);
1241 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x1);
1242
1243 vars->mac_type = MAC_TYPE_BMAC;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001244 return rc;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001245}
1246
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001247
1248static void bnx2x_update_mng(struct link_params *params, u32 link_status)
1249{
1250 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00001251
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001252 REG_WR(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001253 offsetof(struct shmem_region,
1254 port_mb[params->port].link_status), link_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001255}
1256
1257static void bnx2x_bmac_rx_disable(struct bnx2x *bp, u8 port)
1258{
1259 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001260 NIG_REG_INGRESS_BMAC0_MEM;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001261 u32 wb_data[2];
Eilon Greenstein3196a882008-08-13 15:58:49 -07001262 u32 nig_bmac_enable = REG_RD(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001263
1264 /* Only if the bmac is out of reset */
1265 if (REG_RD(bp, MISC_REG_RESET_REG_2) &
1266 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port) &&
1267 nig_bmac_enable) {
1268
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001269 if (CHIP_IS_E2(bp)) {
1270 /* Clear Rx Enable bit in BMAC_CONTROL register */
1271 REG_RD_DMAE(bp, bmac_addr +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001272 BIGMAC2_REGISTER_BMAC_CONTROL,
1273 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001274 wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
1275 REG_WR_DMAE(bp, bmac_addr +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001276 BIGMAC2_REGISTER_BMAC_CONTROL,
1277 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001278 } else {
1279 /* Clear Rx Enable bit in BMAC_CONTROL register */
1280 REG_RD_DMAE(bp, bmac_addr +
1281 BIGMAC_REGISTER_BMAC_CONTROL,
1282 wb_data, 2);
1283 wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
1284 REG_WR_DMAE(bp, bmac_addr +
1285 BIGMAC_REGISTER_BMAC_CONTROL,
1286 wb_data, 2);
1287 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001288 msleep(1);
1289 }
1290}
1291
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00001292static int bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl,
1293 u32 line_speed)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001294{
1295 struct bnx2x *bp = params->bp;
1296 u8 port = params->port;
1297 u32 init_crd, crd;
1298 u32 count = 1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001299
1300 /* disable port */
1301 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x1);
1302
1303 /* wait for init credit */
1304 init_crd = REG_RD(bp, PBF_REG_P0_INIT_CRD + port*4);
1305 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
1306 DP(NETIF_MSG_LINK, "init_crd 0x%x crd 0x%x\n", init_crd, crd);
1307
1308 while ((init_crd != crd) && count) {
1309 msleep(5);
1310
1311 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
1312 count--;
1313 }
1314 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
1315 if (init_crd != crd) {
1316 DP(NETIF_MSG_LINK, "BUG! init_crd 0x%x != crd 0x%x\n",
1317 init_crd, crd);
1318 return -EINVAL;
1319 }
1320
David S. Millerc0700f92008-12-16 23:53:20 -08001321 if (flow_ctrl & BNX2X_FLOW_CTRL_RX ||
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001322 line_speed == SPEED_10 ||
1323 line_speed == SPEED_100 ||
1324 line_speed == SPEED_1000 ||
1325 line_speed == SPEED_2500) {
1326 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001327 /* update threshold */
1328 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, 0);
1329 /* update init credit */
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001330 init_crd = 778; /* (800-18-4) */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001331
1332 } else {
1333 u32 thresh = (ETH_MAX_JUMBO_PACKET_SIZE +
1334 ETH_OVREHEAD)/16;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001335 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001336 /* update threshold */
1337 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, thresh);
1338 /* update init credit */
1339 switch (line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001340 case SPEED_10000:
1341 init_crd = thresh + 553 - 22;
1342 break;
1343
1344 case SPEED_12000:
1345 init_crd = thresh + 664 - 22;
1346 break;
1347
1348 case SPEED_13000:
1349 init_crd = thresh + 742 - 22;
1350 break;
1351
1352 case SPEED_16000:
1353 init_crd = thresh + 778 - 22;
1354 break;
1355 default:
1356 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
1357 line_speed);
1358 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001359 }
1360 }
1361 REG_WR(bp, PBF_REG_P0_INIT_CRD + port*4, init_crd);
1362 DP(NETIF_MSG_LINK, "PBF updated to speed %d credit %d\n",
1363 line_speed, init_crd);
1364
1365 /* probe the credit changes */
1366 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x1);
1367 msleep(5);
1368 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x0);
1369
1370 /* enable port */
1371 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x0);
1372 return 0;
1373}
1374
Dmitry Kravkove8920672011-05-04 23:52:40 +00001375/**
1376 * bnx2x_get_emac_base - retrive emac base address
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001377 *
Dmitry Kravkove8920672011-05-04 23:52:40 +00001378 * @bp: driver handle
1379 * @mdc_mdio_access: access type
1380 * @port: port id
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001381 *
1382 * This function selects the MDC/MDIO access (through emac0 or
1383 * emac1) depend on the mdc_mdio_access, port, port swapped. Each
1384 * phy has a default access mode, which could also be overridden
1385 * by nvram configuration. This parameter, whether this is the
1386 * default phy configuration, or the nvram overrun
1387 * configuration, is passed here as mdc_mdio_access and selects
1388 * the emac_base for the CL45 read/writes operations
1389 */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00001390static u32 bnx2x_get_emac_base(struct bnx2x *bp,
1391 u32 mdc_mdio_access, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001392{
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00001393 u32 emac_base = 0;
1394 switch (mdc_mdio_access) {
1395 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_PHY_TYPE:
1396 break;
1397 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC0:
1398 if (REG_RD(bp, NIG_REG_PORT_SWAP))
1399 emac_base = GRCBASE_EMAC1;
1400 else
1401 emac_base = GRCBASE_EMAC0;
1402 break;
1403 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1:
Eilon Greenstein589abe32009-02-12 08:36:55 +00001404 if (REG_RD(bp, NIG_REG_PORT_SWAP))
1405 emac_base = GRCBASE_EMAC0;
1406 else
1407 emac_base = GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001408 break;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00001409 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH:
1410 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
1411 break;
1412 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_SWAPPED:
Eilon Greenstein6378c022008-08-13 15:59:25 -07001413 emac_base = (port) ? GRCBASE_EMAC0 : GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001414 break;
1415 default:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001416 break;
1417 }
1418 return emac_base;
1419
1420}
1421
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001422/******************************************************************/
1423/* CL45 access functions */
1424/******************************************************************/
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00001425static int bnx2x_cl45_read(struct bnx2x *bp, struct bnx2x_phy *phy,
1426 u8 devad, u16 reg, u16 *ret_val)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001427{
Yaniv Rosnera198c142011-05-31 21:29:42 +00001428 u32 val;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001429 u16 i;
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00001430 int rc = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001431
1432 /* address */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001433 val = ((phy->addr << 21) | (devad << 16) | reg |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001434 EMAC_MDIO_COMM_COMMAND_ADDRESS |
1435 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001436 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001437
1438 for (i = 0; i < 50; i++) {
1439 udelay(10);
1440
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001441 val = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001442 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
1443 udelay(5);
1444 break;
1445 }
1446 }
1447 if (val & EMAC_MDIO_COMM_START_BUSY) {
1448 DP(NETIF_MSG_LINK, "read phy register failed\n");
Yaniv Rosner6d870c32011-01-31 04:22:20 +00001449 netdev_err(bp->dev, "MDC/MDIO access timeout\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001450 *ret_val = 0;
1451 rc = -EFAULT;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001452 } else {
1453 /* data */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001454 val = ((phy->addr << 21) | (devad << 16) |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001455 EMAC_MDIO_COMM_COMMAND_READ_45 |
1456 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001457 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001458
1459 for (i = 0; i < 50; i++) {
1460 udelay(10);
1461
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001462 val = REG_RD(bp, phy->mdio_ctrl +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001463 EMAC_REG_EMAC_MDIO_COMM);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001464 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
1465 *ret_val = (u16)(val & EMAC_MDIO_COMM_DATA);
1466 break;
1467 }
1468 }
1469 if (val & EMAC_MDIO_COMM_START_BUSY) {
1470 DP(NETIF_MSG_LINK, "read phy register failed\n");
Yaniv Rosner6d870c32011-01-31 04:22:20 +00001471 netdev_err(bp->dev, "MDC/MDIO access timeout\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001472 *ret_val = 0;
1473 rc = -EFAULT;
1474 }
1475 }
1476
Yaniv Rosnera198c142011-05-31 21:29:42 +00001477 return rc;
1478}
1479
1480static int bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy,
1481 u8 devad, u16 reg, u16 val)
1482{
1483 u32 tmp;
1484 u8 i;
1485 int rc = 0;
1486
1487 /* address */
1488
1489 tmp = ((phy->addr << 21) | (devad << 16) | reg |
1490 EMAC_MDIO_COMM_COMMAND_ADDRESS |
1491 EMAC_MDIO_COMM_START_BUSY);
1492 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
1493
1494 for (i = 0; i < 50; i++) {
1495 udelay(10);
1496
1497 tmp = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
1498 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
1499 udelay(5);
1500 break;
1501 }
1502 }
1503 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
1504 DP(NETIF_MSG_LINK, "write phy register failed\n");
1505 netdev_err(bp->dev, "MDC/MDIO access timeout\n");
1506 rc = -EFAULT;
1507
1508 } else {
1509 /* data */
1510 tmp = ((phy->addr << 21) | (devad << 16) | val |
1511 EMAC_MDIO_COMM_COMMAND_WRITE_45 |
1512 EMAC_MDIO_COMM_START_BUSY);
1513 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
1514
1515 for (i = 0; i < 50; i++) {
1516 udelay(10);
1517
1518 tmp = REG_RD(bp, phy->mdio_ctrl +
1519 EMAC_REG_EMAC_MDIO_COMM);
1520 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
1521 udelay(5);
1522 break;
1523 }
1524 }
1525 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
1526 DP(NETIF_MSG_LINK, "write phy register failed\n");
1527 netdev_err(bp->dev, "MDC/MDIO access timeout\n");
1528 rc = -EFAULT;
1529 }
1530 }
1531
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001532
1533 return rc;
1534}
1535
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00001536int bnx2x_phy_read(struct link_params *params, u8 phy_addr,
1537 u8 devad, u16 reg, u16 *ret_val)
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001538{
1539 u8 phy_index;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001540 /*
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001541 * Probe for the phy according to the given phy_addr, and execute
1542 * the read request on it
1543 */
1544 for (phy_index = 0; phy_index < params->num_phys; phy_index++) {
1545 if (params->phy[phy_index].addr == phy_addr) {
1546 return bnx2x_cl45_read(params->bp,
1547 &params->phy[phy_index], devad,
1548 reg, ret_val);
1549 }
1550 }
1551 return -EINVAL;
1552}
1553
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00001554int bnx2x_phy_write(struct link_params *params, u8 phy_addr,
1555 u8 devad, u16 reg, u16 val)
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001556{
1557 u8 phy_index;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001558 /*
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001559 * Probe for the phy according to the given phy_addr, and execute
1560 * the write request on it
1561 */
1562 for (phy_index = 0; phy_index < params->num_phys; phy_index++) {
1563 if (params->phy[phy_index].addr == phy_addr) {
1564 return bnx2x_cl45_write(params->bp,
1565 &params->phy[phy_index], devad,
1566 reg, val);
1567 }
1568 }
1569 return -EINVAL;
1570}
1571
Yaniv Rosnerec146a62011-05-31 21:29:27 +00001572static void bnx2x_set_aer_mmd(struct link_params *params,
1573 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001574{
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001575 u32 ser_lane;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001576 u16 offset, aer_val;
1577 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001578 ser_lane = ((params->lane_config &
1579 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
1580 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
1581
Yaniv Rosnerec146a62011-05-31 21:29:27 +00001582 offset = (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ?
1583 (phy->addr + ser_lane) : 0;
1584
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001585 if (CHIP_IS_E2(bp))
Yaniv Rosner82a0d472011-01-18 04:33:52 +00001586 aer_val = 0x3800 + offset - 1;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001587 else
1588 aer_val = 0x3800 + offset;
Yaniv Rosnerec146a62011-05-31 21:29:27 +00001589 DP(NETIF_MSG_LINK, "Set AER to 0x%x\n", aer_val);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001590 CL22_WR_OVER_CL45(bp, phy, MDIO_REG_BANK_AER_BLOCK,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001591 MDIO_AER_BLOCK_AER_REG, aer_val);
Yaniv Rosnerec146a62011-05-31 21:29:27 +00001592
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001593}
1594
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001595/******************************************************************/
1596/* Internal phy section */
1597/******************************************************************/
1598
1599static void bnx2x_set_serdes_access(struct bnx2x *bp, u8 port)
1600{
1601 u32 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
1602
1603 /* Set Clause 22 */
1604 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + port*0x10, 1);
1605 REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245f8000);
1606 udelay(500);
1607 REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245d000f);
1608 udelay(500);
1609 /* Set Clause 45 */
1610 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + port*0x10, 0);
1611}
1612
1613static void bnx2x_serdes_deassert(struct bnx2x *bp, u8 port)
1614{
1615 u32 val;
1616
1617 DP(NETIF_MSG_LINK, "bnx2x_serdes_deassert\n");
1618
1619 val = SERDES_RESET_BITS << (port*16);
1620
1621 /* reset and unreset the SerDes/XGXS */
1622 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR, val);
1623 udelay(500);
1624 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET, val);
1625
1626 bnx2x_set_serdes_access(bp, port);
1627
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001628 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_DEVAD + port*0x10,
1629 DEFAULT_PHY_DEV_ADDR);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001630}
1631
1632static void bnx2x_xgxs_deassert(struct link_params *params)
1633{
1634 struct bnx2x *bp = params->bp;
1635 u8 port;
1636 u32 val;
1637 DP(NETIF_MSG_LINK, "bnx2x_xgxs_deassert\n");
1638 port = params->port;
1639
1640 val = XGXS_RESET_BITS << (port*16);
1641
1642 /* reset and unreset the SerDes/XGXS */
1643 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR, val);
1644 udelay(500);
1645 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET, val);
1646
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001647 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_ST + port*0x18, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001648 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001649 params->phy[INT_PHY].def_md_devad);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001650}
1651
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00001652static void bnx2x_calc_ieee_aneg_adv(struct bnx2x_phy *phy,
1653 struct link_params *params, u16 *ieee_fc)
1654{
1655 struct bnx2x *bp = params->bp;
1656 *ieee_fc = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX;
1657 /**
1658 * resolve pause mode and advertisement Please refer to Table
1659 * 28B-3 of the 802.3ab-1999 spec
1660 */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00001661
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00001662 switch (phy->req_flow_ctrl) {
1663 case BNX2X_FLOW_CTRL_AUTO:
1664 if (params->req_fc_auto_adv == BNX2X_FLOW_CTRL_BOTH)
1665 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
1666 else
1667 *ieee_fc |=
1668 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
1669 break;
1670
1671 case BNX2X_FLOW_CTRL_TX:
1672 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
1673 break;
1674
1675 case BNX2X_FLOW_CTRL_RX:
1676 case BNX2X_FLOW_CTRL_BOTH:
1677 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
1678 break;
1679
1680 case BNX2X_FLOW_CTRL_NONE:
1681 default:
1682 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE;
1683 break;
1684 }
1685 DP(NETIF_MSG_LINK, "ieee_fc = 0x%x\n", *ieee_fc);
1686}
1687
1688static void set_phy_vars(struct link_params *params,
1689 struct link_vars *vars)
1690{
1691 struct bnx2x *bp = params->bp;
1692 u8 actual_phy_idx, phy_index, link_cfg_idx;
1693 u8 phy_config_swapped = params->multi_phy_config &
1694 PORT_HW_CFG_PHY_SWAPPED_ENABLED;
1695 for (phy_index = INT_PHY; phy_index < params->num_phys;
1696 phy_index++) {
1697 link_cfg_idx = LINK_CONFIG_IDX(phy_index);
1698 actual_phy_idx = phy_index;
1699 if (phy_config_swapped) {
1700 if (phy_index == EXT_PHY1)
1701 actual_phy_idx = EXT_PHY2;
1702 else if (phy_index == EXT_PHY2)
1703 actual_phy_idx = EXT_PHY1;
1704 }
1705 params->phy[actual_phy_idx].req_flow_ctrl =
1706 params->req_flow_ctrl[link_cfg_idx];
1707
1708 params->phy[actual_phy_idx].req_line_speed =
1709 params->req_line_speed[link_cfg_idx];
1710
1711 params->phy[actual_phy_idx].speed_cap_mask =
1712 params->speed_cap_mask[link_cfg_idx];
1713
1714 params->phy[actual_phy_idx].req_duplex =
1715 params->req_duplex[link_cfg_idx];
1716
1717 if (params->req_line_speed[link_cfg_idx] ==
1718 SPEED_AUTO_NEG)
1719 vars->link_status |= LINK_STATUS_AUTO_NEGOTIATE_ENABLED;
1720
1721 DP(NETIF_MSG_LINK, "req_flow_ctrl %x, req_line_speed %x,"
1722 " speed_cap_mask %x\n",
1723 params->phy[actual_phy_idx].req_flow_ctrl,
1724 params->phy[actual_phy_idx].req_line_speed,
1725 params->phy[actual_phy_idx].speed_cap_mask);
1726 }
1727}
1728
1729static void bnx2x_ext_phy_set_pause(struct link_params *params,
1730 struct bnx2x_phy *phy,
1731 struct link_vars *vars)
1732{
1733 u16 val;
1734 struct bnx2x *bp = params->bp;
1735 /* read modify write pause advertizing */
1736 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV_PAUSE, &val);
1737
1738 val &= ~MDIO_AN_REG_ADV_PAUSE_BOTH;
1739
1740 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
1741 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
1742 if ((vars->ieee_fc &
1743 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
1744 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
1745 val |= MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC;
1746 }
1747 if ((vars->ieee_fc &
1748 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
1749 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
1750 val |= MDIO_AN_REG_ADV_PAUSE_PAUSE;
1751 }
1752 DP(NETIF_MSG_LINK, "Ext phy AN advertize 0x%x\n", val);
1753 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV_PAUSE, val);
1754}
1755
1756static void bnx2x_pause_resolve(struct link_vars *vars, u32 pause_result)
1757{ /* LD LP */
1758 switch (pause_result) { /* ASYM P ASYM P */
1759 case 0xb: /* 1 0 1 1 */
1760 vars->flow_ctrl = BNX2X_FLOW_CTRL_TX;
1761 break;
1762
1763 case 0xe: /* 1 1 1 0 */
1764 vars->flow_ctrl = BNX2X_FLOW_CTRL_RX;
1765 break;
1766
1767 case 0x5: /* 0 1 0 1 */
1768 case 0x7: /* 0 1 1 1 */
1769 case 0xd: /* 1 1 0 1 */
1770 case 0xf: /* 1 1 1 1 */
1771 vars->flow_ctrl = BNX2X_FLOW_CTRL_BOTH;
1772 break;
1773
1774 default:
1775 break;
1776 }
1777 if (pause_result & (1<<0))
1778 vars->link_status |= LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE;
1779 if (pause_result & (1<<1))
1780 vars->link_status |= LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE;
1781}
1782
1783static u8 bnx2x_ext_phy_resolve_fc(struct bnx2x_phy *phy,
1784 struct link_params *params,
1785 struct link_vars *vars)
1786{
1787 struct bnx2x *bp = params->bp;
1788 u16 ld_pause; /* local */
1789 u16 lp_pause; /* link partner */
1790 u16 pause_result;
1791 u8 ret = 0;
1792 /* read twice */
1793
1794 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
1795
1796 if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO)
1797 vars->flow_ctrl = phy->req_flow_ctrl;
1798 else if (phy->req_line_speed != SPEED_AUTO_NEG)
1799 vars->flow_ctrl = params->req_fc_auto_adv;
1800 else if (vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE) {
1801 ret = 1;
1802 bnx2x_cl45_read(bp, phy,
1803 MDIO_AN_DEVAD,
1804 MDIO_AN_REG_ADV_PAUSE, &ld_pause);
1805 bnx2x_cl45_read(bp, phy,
1806 MDIO_AN_DEVAD,
1807 MDIO_AN_REG_LP_AUTO_NEG, &lp_pause);
1808 pause_result = (ld_pause &
1809 MDIO_AN_REG_ADV_PAUSE_MASK) >> 8;
1810 pause_result |= (lp_pause &
1811 MDIO_AN_REG_ADV_PAUSE_MASK) >> 10;
1812 DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x\n",
1813 pause_result);
1814 bnx2x_pause_resolve(vars, pause_result);
1815 }
1816 return ret;
1817}
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001818void bnx2x_link_status_update(struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001819 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001820{
1821 struct bnx2x *bp = params->bp;
1822 u8 link_10g;
1823 u8 port = params->port;
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00001824 u32 sync_offset, media_types;
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00001825 /* Update PHY configuration */
1826 set_phy_vars(params, vars);
1827
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001828 vars->link_status = REG_RD(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001829 offsetof(struct shmem_region,
1830 port_mb[port].link_status));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001831
1832 vars->link_up = (vars->link_status & LINK_STATUS_LINK_UP);
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00001833 vars->phy_flags = PHY_XGXS_FLAG;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001834 if (vars->link_up) {
1835 DP(NETIF_MSG_LINK, "phy link up\n");
1836
1837 vars->phy_link_up = 1;
1838 vars->duplex = DUPLEX_FULL;
1839 switch (vars->link_status &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001840 LINK_STATUS_SPEED_AND_DUPLEX_MASK) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001841 case LINK_10THD:
1842 vars->duplex = DUPLEX_HALF;
1843 /* fall thru */
1844 case LINK_10TFD:
1845 vars->line_speed = SPEED_10;
1846 break;
1847
1848 case LINK_100TXHD:
1849 vars->duplex = DUPLEX_HALF;
1850 /* fall thru */
1851 case LINK_100T4:
1852 case LINK_100TXFD:
1853 vars->line_speed = SPEED_100;
1854 break;
1855
1856 case LINK_1000THD:
1857 vars->duplex = DUPLEX_HALF;
1858 /* fall thru */
1859 case LINK_1000TFD:
1860 vars->line_speed = SPEED_1000;
1861 break;
1862
1863 case LINK_2500THD:
1864 vars->duplex = DUPLEX_HALF;
1865 /* fall thru */
1866 case LINK_2500TFD:
1867 vars->line_speed = SPEED_2500;
1868 break;
1869
1870 case LINK_10GTFD:
1871 vars->line_speed = SPEED_10000;
1872 break;
1873
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001874 default:
1875 break;
1876 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001877 vars->flow_ctrl = 0;
1878 if (vars->link_status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED)
1879 vars->flow_ctrl |= BNX2X_FLOW_CTRL_TX;
1880
1881 if (vars->link_status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED)
1882 vars->flow_ctrl |= BNX2X_FLOW_CTRL_RX;
1883
1884 if (!vars->flow_ctrl)
1885 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
1886
1887 if (vars->line_speed &&
1888 ((vars->line_speed == SPEED_10) ||
1889 (vars->line_speed == SPEED_100))) {
1890 vars->phy_flags |= PHY_SGMII_FLAG;
1891 } else {
1892 vars->phy_flags &= ~PHY_SGMII_FLAG;
1893 }
1894
1895 /* anything 10 and over uses the bmac */
1896 link_10g = ((vars->line_speed == SPEED_10000) ||
1897 (vars->line_speed == SPEED_12000) ||
1898 (vars->line_speed == SPEED_12500) ||
1899 (vars->line_speed == SPEED_13000) ||
1900 (vars->line_speed == SPEED_15000) ||
1901 (vars->line_speed == SPEED_16000));
1902 if (link_10g)
1903 vars->mac_type = MAC_TYPE_BMAC;
1904 else
1905 vars->mac_type = MAC_TYPE_EMAC;
1906
1907 } else { /* link down */
1908 DP(NETIF_MSG_LINK, "phy link down\n");
1909
1910 vars->phy_link_up = 0;
1911
1912 vars->line_speed = 0;
1913 vars->duplex = DUPLEX_FULL;
1914 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
1915
1916 /* indicate no mac active */
1917 vars->mac_type = MAC_TYPE_NONE;
1918 }
1919
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00001920 /* Sync media type */
1921 sync_offset = params->shmem_base +
1922 offsetof(struct shmem_region,
1923 dev_info.port_hw_config[port].media_type);
1924 media_types = REG_RD(bp, sync_offset);
1925
1926 params->phy[INT_PHY].media_type =
1927 (media_types & PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK) >>
1928 PORT_HW_CFG_MEDIA_TYPE_PHY0_SHIFT;
1929 params->phy[EXT_PHY1].media_type =
1930 (media_types & PORT_HW_CFG_MEDIA_TYPE_PHY1_MASK) >>
1931 PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT;
1932 params->phy[EXT_PHY2].media_type =
1933 (media_types & PORT_HW_CFG_MEDIA_TYPE_PHY2_MASK) >>
1934 PORT_HW_CFG_MEDIA_TYPE_PHY2_SHIFT;
1935 DP(NETIF_MSG_LINK, "media_types = 0x%x\n", media_types);
1936
Yaniv Rosner020c7e32011-05-31 21:28:43 +00001937 /* Sync AEU offset */
1938 sync_offset = params->shmem_base +
1939 offsetof(struct shmem_region,
1940 dev_info.port_hw_config[port].aeu_int_mask);
1941
1942 vars->aeu_int_mask = REG_RD(bp, sync_offset);
1943
1944 DP(NETIF_MSG_LINK, "link_status 0x%x phy_link_up %x int_mask 0x%x\n",
1945 vars->link_status, vars->phy_link_up, vars->aeu_int_mask);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001946 DP(NETIF_MSG_LINK, "line_speed %x duplex %x flow_ctrl 0x%x\n",
1947 vars->line_speed, vars->duplex, vars->flow_ctrl);
1948}
1949
1950
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001951static void bnx2x_set_master_ln(struct link_params *params,
1952 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001953{
1954 struct bnx2x *bp = params->bp;
1955 u16 new_master_ln, ser_lane;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001956 ser_lane = ((params->lane_config &
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001957 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001958 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001959
1960 /* set the master_ln for AN */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001961 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001962 MDIO_REG_BANK_XGXS_BLOCK2,
1963 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
1964 &new_master_ln);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001965
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001966 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001967 MDIO_REG_BANK_XGXS_BLOCK2 ,
1968 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
1969 (new_master_ln | ser_lane));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001970}
1971
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00001972static int bnx2x_reset_unicore(struct link_params *params,
1973 struct bnx2x_phy *phy,
1974 u8 set_serdes)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001975{
1976 struct bnx2x *bp = params->bp;
1977 u16 mii_control;
1978 u16 i;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001979 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001980 MDIO_REG_BANK_COMBO_IEEE0,
1981 MDIO_COMBO_IEEE0_MII_CONTROL, &mii_control);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001982
1983 /* reset the unicore */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001984 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001985 MDIO_REG_BANK_COMBO_IEEE0,
1986 MDIO_COMBO_IEEE0_MII_CONTROL,
1987 (mii_control |
1988 MDIO_COMBO_IEEO_MII_CONTROL_RESET));
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001989 if (set_serdes)
1990 bnx2x_set_serdes_access(bp, params->port);
Eilon Greensteinc1b73992009-02-12 08:37:07 +00001991
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001992 /* wait for the reset to self clear */
1993 for (i = 0; i < MDIO_ACCESS_TIMEOUT; i++) {
1994 udelay(5);
1995
1996 /* the reset erased the previous bank value */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00001997 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001998 MDIO_REG_BANK_COMBO_IEEE0,
1999 MDIO_COMBO_IEEE0_MII_CONTROL,
2000 &mii_control);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002001
2002 if (!(mii_control & MDIO_COMBO_IEEO_MII_CONTROL_RESET)) {
2003 udelay(5);
2004 return 0;
2005 }
2006 }
2007
Yaniv Rosner6d870c32011-01-31 04:22:20 +00002008 netdev_err(bp->dev, "Warning: PHY was not initialized,"
2009 " Port %d\n",
2010 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002011 DP(NETIF_MSG_LINK, "BUG! XGXS is still in reset!\n");
2012 return -EINVAL;
2013
2014}
2015
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002016static void bnx2x_set_swap_lanes(struct link_params *params,
2017 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002018{
2019 struct bnx2x *bp = params->bp;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002020 /*
2021 * Each two bits represents a lane number:
2022 * No swap is 0123 => 0x1b no need to enable the swap
2023 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002024 u16 ser_lane, rx_lane_swap, tx_lane_swap;
2025
2026 ser_lane = ((params->lane_config &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002027 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
2028 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002029 rx_lane_swap = ((params->lane_config &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002030 PORT_HW_CFG_LANE_SWAP_CFG_RX_MASK) >>
2031 PORT_HW_CFG_LANE_SWAP_CFG_RX_SHIFT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002032 tx_lane_swap = ((params->lane_config &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002033 PORT_HW_CFG_LANE_SWAP_CFG_TX_MASK) >>
2034 PORT_HW_CFG_LANE_SWAP_CFG_TX_SHIFT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002035
2036 if (rx_lane_swap != 0x1b) {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002037 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002038 MDIO_REG_BANK_XGXS_BLOCK2,
2039 MDIO_XGXS_BLOCK2_RX_LN_SWAP,
2040 (rx_lane_swap |
2041 MDIO_XGXS_BLOCK2_RX_LN_SWAP_ENABLE |
2042 MDIO_XGXS_BLOCK2_RX_LN_SWAP_FORCE_ENABLE));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002043 } else {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002044 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002045 MDIO_REG_BANK_XGXS_BLOCK2,
2046 MDIO_XGXS_BLOCK2_RX_LN_SWAP, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002047 }
2048
2049 if (tx_lane_swap != 0x1b) {
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_XGXS_BLOCK2,
2052 MDIO_XGXS_BLOCK2_TX_LN_SWAP,
2053 (tx_lane_swap |
2054 MDIO_XGXS_BLOCK2_TX_LN_SWAP_ENABLE));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002055 } else {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002056 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002057 MDIO_REG_BANK_XGXS_BLOCK2,
2058 MDIO_XGXS_BLOCK2_TX_LN_SWAP, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002059 }
2060}
2061
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002062static void bnx2x_set_parallel_detection(struct bnx2x_phy *phy,
2063 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002064{
2065 struct bnx2x *bp = params->bp;
2066 u16 control2;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002067 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002068 MDIO_REG_BANK_SERDES_DIGITAL,
2069 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
2070 &control2);
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002071 if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
Yaniv Rosner18afb0a2009-11-05 19:18:04 +02002072 control2 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
2073 else
2074 control2 &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002075 DP(NETIF_MSG_LINK, "phy->speed_cap_mask = 0x%x, control2 = 0x%x\n",
2076 phy->speed_cap_mask, control2);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002077 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002078 MDIO_REG_BANK_SERDES_DIGITAL,
2079 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
2080 control2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002081
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002082 if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002083 (phy->speed_cap_mask &
Yaniv Rosner18afb0a2009-11-05 19:18:04 +02002084 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002085 DP(NETIF_MSG_LINK, "XGXS\n");
2086
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002087 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002088 MDIO_REG_BANK_10G_PARALLEL_DETECT,
2089 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK,
2090 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002091
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002092 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002093 MDIO_REG_BANK_10G_PARALLEL_DETECT,
2094 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
2095 &control2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002096
2097
2098 control2 |=
2099 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN;
2100
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002101 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002102 MDIO_REG_BANK_10G_PARALLEL_DETECT,
2103 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
2104 control2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002105
2106 /* Disable parallel detection of HiG */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002107 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002108 MDIO_REG_BANK_XGXS_BLOCK2,
2109 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G,
2110 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_CX4_XGXS |
2111 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_HIGIG_XGXS);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002112 }
2113}
2114
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002115static void bnx2x_set_autoneg(struct bnx2x_phy *phy,
2116 struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002117 struct link_vars *vars,
2118 u8 enable_cl73)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002119{
2120 struct bnx2x *bp = params->bp;
2121 u16 reg_val;
2122
2123 /* CL37 Autoneg */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002124 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002125 MDIO_REG_BANK_COMBO_IEEE0,
2126 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002127
2128 /* CL37 Autoneg Enabled */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002129 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002130 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_AN_EN;
2131 else /* CL37 Autoneg Disabled */
2132 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
2133 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN);
2134
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002135 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002136 MDIO_REG_BANK_COMBO_IEEE0,
2137 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002138
2139 /* Enable/Disable Autodetection */
2140
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002141 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002142 MDIO_REG_BANK_SERDES_DIGITAL,
2143 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, &reg_val);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002144 reg_val &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN |
2145 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT);
2146 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002147 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002148 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
2149 else
2150 reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
2151
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002152 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002153 MDIO_REG_BANK_SERDES_DIGITAL,
2154 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002155
2156 /* Enable TetonII and BAM autoneg */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002157 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002158 MDIO_REG_BANK_BAM_NEXT_PAGE,
2159 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002160 &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002161 if (vars->line_speed == SPEED_AUTO_NEG) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002162 /* Enable BAM aneg Mode and TetonII aneg Mode */
2163 reg_val |= (MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
2164 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
2165 } else {
2166 /* TetonII and BAM Autoneg Disabled */
2167 reg_val &= ~(MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
2168 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
2169 }
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002170 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002171 MDIO_REG_BANK_BAM_NEXT_PAGE,
2172 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
2173 reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002174
Eilon Greenstein239d6862009-08-12 08:23:04 +00002175 if (enable_cl73) {
2176 /* Enable Cl73 FSM status bits */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002177 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002178 MDIO_REG_BANK_CL73_USERB0,
2179 MDIO_CL73_USERB0_CL73_UCTRL,
2180 0xe);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002181
2182 /* Enable BAM Station Manager*/
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002183 CL22_WR_OVER_CL45(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00002184 MDIO_REG_BANK_CL73_USERB0,
2185 MDIO_CL73_USERB0_CL73_BAM_CTRL1,
2186 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN |
2187 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_STATION_MNGR_EN |
2188 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN);
2189
Yaniv Rosner7846e472009-11-05 19:18:07 +02002190 /* Advertise CL73 link speeds */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002191 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002192 MDIO_REG_BANK_CL73_IEEEB1,
2193 MDIO_CL73_IEEEB1_AN_ADV2,
2194 &reg_val);
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002195 if (phy->speed_cap_mask &
Yaniv Rosner7846e472009-11-05 19:18:07 +02002196 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
2197 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002198 if (phy->speed_cap_mask &
Yaniv Rosner7846e472009-11-05 19:18:07 +02002199 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
2200 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX;
Eilon Greenstein239d6862009-08-12 08:23:04 +00002201
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002202 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002203 MDIO_REG_BANK_CL73_IEEEB1,
2204 MDIO_CL73_IEEEB1_AN_ADV2,
2205 reg_val);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002206
Eilon Greenstein239d6862009-08-12 08:23:04 +00002207 /* CL73 Autoneg Enabled */
2208 reg_val = MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN;
2209
2210 } else /* CL73 Autoneg Disabled */
2211 reg_val = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002212
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002213 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002214 MDIO_REG_BANK_CL73_IEEEB0,
2215 MDIO_CL73_IEEEB0_CL73_AN_CONTROL, reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002216}
2217
2218/* program SerDes, forced speed */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002219static void bnx2x_program_serdes(struct bnx2x_phy *phy,
2220 struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002221 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002222{
2223 struct bnx2x *bp = params->bp;
2224 u16 reg_val;
2225
Eilon Greenstein57937202009-08-12 08:23:53 +00002226 /* program duplex, disable autoneg and sgmii*/
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002227 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002228 MDIO_REG_BANK_COMBO_IEEE0,
2229 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002230 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX |
Eilon Greenstein57937202009-08-12 08:23:53 +00002231 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
2232 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK);
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002233 if (phy->req_duplex == DUPLEX_FULL)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002234 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002235 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002236 MDIO_REG_BANK_COMBO_IEEE0,
2237 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002238
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002239 /*
2240 * program speed
2241 * - needed only if the speed is greater than 1G (2.5G or 10G)
2242 */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002243 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002244 MDIO_REG_BANK_SERDES_DIGITAL,
2245 MDIO_SERDES_DIGITAL_MISC1, &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002246 /* clearing the speed value before setting the right speed */
2247 DP(NETIF_MSG_LINK, "MDIO_REG_BANK_SERDES_DIGITAL = 0x%x\n", reg_val);
2248
2249 reg_val &= ~(MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_MASK |
2250 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
2251
2252 if (!((vars->line_speed == SPEED_1000) ||
2253 (vars->line_speed == SPEED_100) ||
2254 (vars->line_speed == SPEED_10))) {
2255
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002256 reg_val |= (MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_156_25M |
2257 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002258 if (vars->line_speed == SPEED_10000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002259 reg_val |=
2260 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_10G_CX4;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002261 if (vars->line_speed == SPEED_13000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002262 reg_val |=
2263 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_13G;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002264 }
2265
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002266 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002267 MDIO_REG_BANK_SERDES_DIGITAL,
2268 MDIO_SERDES_DIGITAL_MISC1, reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002269
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002270}
2271
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00002272static void bnx2x_set_brcm_cl37_advertisement(struct bnx2x_phy *phy,
2273 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002274{
2275 struct bnx2x *bp = params->bp;
2276 u16 val = 0;
2277
2278 /* configure the 48 bits for BAM AN */
2279
2280 /* set extended capabilities */
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002281 if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002282 val |= MDIO_OVER_1G_UP1_2_5G;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002283 if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002284 val |= MDIO_OVER_1G_UP1_10G;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002285 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002286 MDIO_REG_BANK_OVER_1G,
2287 MDIO_OVER_1G_UP1, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002288
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002289 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002290 MDIO_REG_BANK_OVER_1G,
2291 MDIO_OVER_1G_UP3, 0x400);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002292}
2293
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00002294static void bnx2x_set_ieee_aneg_advertisement(struct bnx2x_phy *phy,
2295 struct link_params *params,
2296 u16 ieee_fc)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002297{
2298 struct bnx2x *bp = params->bp;
Yaniv Rosner7846e472009-11-05 19:18:07 +02002299 u16 val;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002300 /* for AN, we are always publishing full duplex */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002301
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002302 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002303 MDIO_REG_BANK_COMBO_IEEE0,
2304 MDIO_COMBO_IEEE0_AUTO_NEG_ADV, ieee_fc);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002305 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002306 MDIO_REG_BANK_CL73_IEEEB1,
2307 MDIO_CL73_IEEEB1_AN_ADV1, &val);
Yaniv Rosner7846e472009-11-05 19:18:07 +02002308 val &= ~MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_BOTH;
2309 val |= ((ieee_fc<<3) & MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002310 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002311 MDIO_REG_BANK_CL73_IEEEB1,
2312 MDIO_CL73_IEEEB1_AN_ADV1, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002313}
2314
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002315static void bnx2x_restart_autoneg(struct bnx2x_phy *phy,
2316 struct link_params *params,
2317 u8 enable_cl73)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002318{
2319 struct bnx2x *bp = params->bp;
Eilon Greenstein3a36f2e2009-02-12 08:37:09 +00002320 u16 mii_control;
Eilon Greenstein239d6862009-08-12 08:23:04 +00002321
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002322 DP(NETIF_MSG_LINK, "bnx2x_restart_autoneg\n");
Eilon Greenstein3a36f2e2009-02-12 08:37:09 +00002323 /* Enable and restart BAM/CL37 aneg */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002324
Eilon Greenstein239d6862009-08-12 08:23:04 +00002325 if (enable_cl73) {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002326 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002327 MDIO_REG_BANK_CL73_IEEEB0,
2328 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
2329 &mii_control);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002330
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002331 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002332 MDIO_REG_BANK_CL73_IEEEB0,
2333 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
2334 (mii_control |
2335 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN |
2336 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN));
Eilon Greenstein239d6862009-08-12 08:23:04 +00002337 } else {
2338
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002339 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002340 MDIO_REG_BANK_COMBO_IEEE0,
2341 MDIO_COMBO_IEEE0_MII_CONTROL,
2342 &mii_control);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002343 DP(NETIF_MSG_LINK,
2344 "bnx2x_restart_autoneg mii_control before = 0x%x\n",
2345 mii_control);
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_COMBO_IEEE0,
2348 MDIO_COMBO_IEEE0_MII_CONTROL,
2349 (mii_control |
2350 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
2351 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN));
Eilon Greenstein239d6862009-08-12 08:23:04 +00002352 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002353}
2354
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002355static void bnx2x_initialize_sgmii_process(struct bnx2x_phy *phy,
2356 struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002357 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002358{
2359 struct bnx2x *bp = params->bp;
2360 u16 control1;
2361
2362 /* in SGMII mode, the unicore is always slave */
2363
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002364 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002365 MDIO_REG_BANK_SERDES_DIGITAL,
2366 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
2367 &control1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002368 control1 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT;
2369 /* set sgmii mode (and not fiber) */
2370 control1 &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE |
2371 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET |
2372 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_MSTR_MODE);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002373 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002374 MDIO_REG_BANK_SERDES_DIGITAL,
2375 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
2376 control1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002377
2378 /* if forced speed */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002379 if (!(vars->line_speed == SPEED_AUTO_NEG)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002380 /* set speed, disable autoneg */
2381 u16 mii_control;
2382
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002383 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002384 MDIO_REG_BANK_COMBO_IEEE0,
2385 MDIO_COMBO_IEEE0_MII_CONTROL,
2386 &mii_control);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002387 mii_control &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
2388 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK|
2389 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX);
2390
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002391 switch (vars->line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002392 case SPEED_100:
2393 mii_control |=
2394 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_100;
2395 break;
2396 case SPEED_1000:
2397 mii_control |=
2398 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_1000;
2399 break;
2400 case SPEED_10:
2401 /* there is nothing to set for 10M */
2402 break;
2403 default:
2404 /* invalid speed for SGMII */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002405 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
2406 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002407 break;
2408 }
2409
2410 /* setting the full duplex */
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002411 if (phy->req_duplex == DUPLEX_FULL)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002412 mii_control |=
2413 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002414 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002415 MDIO_REG_BANK_COMBO_IEEE0,
2416 MDIO_COMBO_IEEE0_MII_CONTROL,
2417 mii_control);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002418
2419 } else { /* AN mode */
2420 /* enable and restart AN */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002421 bnx2x_restart_autoneg(phy, params, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002422 }
2423}
2424
2425
2426/*
2427 * link management
2428 */
2429
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00002430static int bnx2x_direct_parallel_detect_used(struct bnx2x_phy *phy,
2431 struct link_params *params)
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02002432{
2433 struct bnx2x *bp = params->bp;
2434 u16 pd_10g, status2_1000x;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002435 if (phy->req_line_speed != SPEED_AUTO_NEG)
2436 return 0;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002437 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002438 MDIO_REG_BANK_SERDES_DIGITAL,
2439 MDIO_SERDES_DIGITAL_A_1000X_STATUS2,
2440 &status2_1000x);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002441 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002442 MDIO_REG_BANK_SERDES_DIGITAL,
2443 MDIO_SERDES_DIGITAL_A_1000X_STATUS2,
2444 &status2_1000x);
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02002445 if (status2_1000x & MDIO_SERDES_DIGITAL_A_1000X_STATUS2_AN_DISABLED) {
2446 DP(NETIF_MSG_LINK, "1G parallel detect link on port %d\n",
2447 params->port);
2448 return 1;
2449 }
2450
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002451 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002452 MDIO_REG_BANK_10G_PARALLEL_DETECT,
2453 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_STATUS,
2454 &pd_10g);
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02002455
2456 if (pd_10g & MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_STATUS_PD_LINK) {
2457 DP(NETIF_MSG_LINK, "10G parallel detect link on port %d\n",
2458 params->port);
2459 return 1;
2460 }
2461 return 0;
2462}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002463
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002464static void bnx2x_flow_ctrl_resolve(struct bnx2x_phy *phy,
2465 struct link_params *params,
2466 struct link_vars *vars,
2467 u32 gp_status)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002468{
2469 struct bnx2x *bp = params->bp;
Eilon Greenstein3196a882008-08-13 15:58:49 -07002470 u16 ld_pause; /* local driver */
2471 u16 lp_pause; /* link partner */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002472 u16 pause_result;
2473
David S. Millerc0700f92008-12-16 23:53:20 -08002474 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002475
2476 /* resolve from gp_status in case of AN complete and not sgmii */
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002477 if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO)
2478 vars->flow_ctrl = phy->req_flow_ctrl;
2479 else if (phy->req_line_speed != SPEED_AUTO_NEG)
2480 vars->flow_ctrl = params->req_fc_auto_adv;
2481 else if ((gp_status & MDIO_AN_CL73_OR_37_COMPLETE) &&
2482 (!(vars->phy_flags & PHY_SGMII_FLAG))) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002483 if (bnx2x_direct_parallel_detect_used(phy, params)) {
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02002484 vars->flow_ctrl = params->req_fc_auto_adv;
2485 return;
2486 }
Yaniv Rosner7846e472009-11-05 19:18:07 +02002487 if ((gp_status &
2488 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
2489 MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) ==
2490 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
2491 MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) {
2492
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002493 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002494 MDIO_REG_BANK_CL73_IEEEB1,
2495 MDIO_CL73_IEEEB1_AN_ADV1,
2496 &ld_pause);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002497 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002498 MDIO_REG_BANK_CL73_IEEEB1,
2499 MDIO_CL73_IEEEB1_AN_LP_ADV1,
2500 &lp_pause);
Yaniv Rosner7846e472009-11-05 19:18:07 +02002501 pause_result = (ld_pause &
2502 MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK)
2503 >> 8;
2504 pause_result |= (lp_pause &
2505 MDIO_CL73_IEEEB1_AN_LP_ADV1_PAUSE_MASK)
2506 >> 10;
2507 DP(NETIF_MSG_LINK, "pause_result CL73 0x%x\n",
2508 pause_result);
2509 } else {
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_COMBO_IEEE0,
2512 MDIO_COMBO_IEEE0_AUTO_NEG_ADV,
2513 &ld_pause);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002514 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002515 MDIO_REG_BANK_COMBO_IEEE0,
2516 MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1,
2517 &lp_pause);
Yaniv Rosner7846e472009-11-05 19:18:07 +02002518 pause_result = (ld_pause &
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002519 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>5;
Yaniv Rosner7846e472009-11-05 19:18:07 +02002520 pause_result |= (lp_pause &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002521 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7;
Yaniv Rosner7846e472009-11-05 19:18:07 +02002522 DP(NETIF_MSG_LINK, "pause_result CL37 0x%x\n",
2523 pause_result);
2524 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002525 bnx2x_pause_resolve(vars, pause_result);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002526 }
2527 DP(NETIF_MSG_LINK, "flow_ctrl 0x%x\n", vars->flow_ctrl);
2528}
2529
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002530static void bnx2x_check_fallback_to_cl37(struct bnx2x_phy *phy,
2531 struct link_params *params)
Eilon Greenstein239d6862009-08-12 08:23:04 +00002532{
2533 struct bnx2x *bp = params->bp;
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00002534 u16 rx_status, ustat_val, cl37_fsm_received;
Eilon Greenstein239d6862009-08-12 08:23:04 +00002535 DP(NETIF_MSG_LINK, "bnx2x_check_fallback_to_cl37\n");
2536 /* Step 1: Make sure signal is detected */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002537 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002538 MDIO_REG_BANK_RX0,
2539 MDIO_RX0_RX_STATUS,
2540 &rx_status);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002541 if ((rx_status & MDIO_RX0_RX_STATUS_SIGDET) !=
2542 (MDIO_RX0_RX_STATUS_SIGDET)) {
2543 DP(NETIF_MSG_LINK, "Signal is not detected. Restoring CL73."
2544 "rx_status(0x80b0) = 0x%x\n", rx_status);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002545 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002546 MDIO_REG_BANK_CL73_IEEEB0,
2547 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
2548 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002549 return;
2550 }
2551 /* Step 2: Check CL73 state machine */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002552 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002553 MDIO_REG_BANK_CL73_USERB0,
2554 MDIO_CL73_USERB0_CL73_USTAT1,
2555 &ustat_val);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002556 if ((ustat_val &
2557 (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK |
2558 MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) !=
2559 (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK |
2560 MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) {
2561 DP(NETIF_MSG_LINK, "CL73 state-machine is not stable. "
2562 "ustat_val(0x8371) = 0x%x\n", ustat_val);
2563 return;
2564 }
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002565 /*
2566 * Step 3: Check CL37 Message Pages received to indicate LP
2567 * supports only CL37
2568 */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002569 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002570 MDIO_REG_BANK_REMOTE_PHY,
2571 MDIO_REMOTE_PHY_MISC_RX_STATUS,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00002572 &cl37_fsm_received);
2573 if ((cl37_fsm_received &
Eilon Greenstein239d6862009-08-12 08:23:04 +00002574 (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG |
2575 MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) !=
2576 (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG |
2577 MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) {
2578 DP(NETIF_MSG_LINK, "No CL37 FSM were received. "
2579 "misc_rx_status(0x8330) = 0x%x\n",
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00002580 cl37_fsm_received);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002581 return;
2582 }
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002583 /*
2584 * The combined cl37/cl73 fsm state information indicating that
2585 * we are connected to a device which does not support cl73, but
2586 * does support cl37 BAM. In this case we disable cl73 and
2587 * restart cl37 auto-neg
2588 */
2589
Eilon Greenstein239d6862009-08-12 08:23:04 +00002590 /* Disable CL73 */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002591 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002592 MDIO_REG_BANK_CL73_IEEEB0,
2593 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
2594 0);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002595 /* Restart CL37 autoneg */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002596 bnx2x_restart_autoneg(phy, params, 0);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002597 DP(NETIF_MSG_LINK, "Disabling CL73, and restarting CL37 autoneg\n");
2598}
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002599
2600static void bnx2x_xgxs_an_resolve(struct bnx2x_phy *phy,
2601 struct link_params *params,
2602 struct link_vars *vars,
2603 u32 gp_status)
2604{
2605 if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE)
2606 vars->link_status |=
2607 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
2608
2609 if (bnx2x_direct_parallel_detect_used(phy, params))
2610 vars->link_status |=
2611 LINK_STATUS_PARALLEL_DETECTION_USED;
2612}
2613
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00002614static int bnx2x_link_settings_status(struct bnx2x_phy *phy,
2615 struct link_params *params,
2616 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002617{
2618 struct bnx2x *bp = params->bp;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002619 u16 new_line_speed, gp_status;
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00002620 int rc = 0;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002621
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002622 /* Read gp_status */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002623 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002624 MDIO_REG_BANK_GP_STATUS,
2625 MDIO_GP_STATUS_TOP_AN_STATUS1,
2626 &gp_status);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00002627
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002628 if (phy->req_line_speed == SPEED_AUTO_NEG)
2629 vars->link_status |= LINK_STATUS_AUTO_NEGOTIATE_ENABLED;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002630 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) {
2631 DP(NETIF_MSG_LINK, "phy link up gp_status=0x%x\n",
2632 gp_status);
2633
2634 vars->phy_link_up = 1;
2635 vars->link_status |= LINK_STATUS_LINK_UP;
2636
2637 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_DUPLEX_STATUS)
2638 vars->duplex = DUPLEX_FULL;
2639 else
2640 vars->duplex = DUPLEX_HALF;
2641
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002642 if (SINGLE_MEDIA_DIRECT(params)) {
2643 bnx2x_flow_ctrl_resolve(phy, params, vars, gp_status);
2644 if (phy->req_line_speed == SPEED_AUTO_NEG)
2645 bnx2x_xgxs_an_resolve(phy, params, vars,
2646 gp_status);
2647 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002648
2649 switch (gp_status & GP_STATUS_SPEED_MASK) {
2650 case GP_STATUS_10M:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002651 new_line_speed = SPEED_10;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002652 if (vars->duplex == DUPLEX_FULL)
2653 vars->link_status |= LINK_10TFD;
2654 else
2655 vars->link_status |= LINK_10THD;
2656 break;
2657
2658 case GP_STATUS_100M:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002659 new_line_speed = SPEED_100;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002660 if (vars->duplex == DUPLEX_FULL)
2661 vars->link_status |= LINK_100TXFD;
2662 else
2663 vars->link_status |= LINK_100TXHD;
2664 break;
2665
2666 case GP_STATUS_1G:
2667 case GP_STATUS_1G_KX:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002668 new_line_speed = SPEED_1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002669 if (vars->duplex == DUPLEX_FULL)
2670 vars->link_status |= LINK_1000TFD;
2671 else
2672 vars->link_status |= LINK_1000THD;
2673 break;
2674
2675 case GP_STATUS_2_5G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002676 new_line_speed = SPEED_2500;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002677 if (vars->duplex == DUPLEX_FULL)
2678 vars->link_status |= LINK_2500TFD;
2679 else
2680 vars->link_status |= LINK_2500THD;
2681 break;
2682
2683 case GP_STATUS_5G:
2684 case GP_STATUS_6G:
2685 DP(NETIF_MSG_LINK,
2686 "link speed unsupported gp_status 0x%x\n",
2687 gp_status);
2688 return -EINVAL;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002689
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002690 case GP_STATUS_10G_KX4:
2691 case GP_STATUS_10G_HIG:
2692 case GP_STATUS_10G_CX4:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002693 new_line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002694 vars->link_status |= LINK_10GTFD;
2695 break;
2696
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002697 default:
2698 DP(NETIF_MSG_LINK,
2699 "link speed unsupported gp_status 0x%x\n",
2700 gp_status);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002701 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002702 }
2703
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002704 vars->line_speed = new_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002705
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002706 } else { /* link_down */
2707 DP(NETIF_MSG_LINK, "phy link down\n");
2708
2709 vars->phy_link_up = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002710
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002711 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08002712 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002713 vars->mac_type = MAC_TYPE_NONE;
Eilon Greenstein239d6862009-08-12 08:23:04 +00002714
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002715 if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
2716 SINGLE_MEDIA_DIRECT(params)) {
Eilon Greenstein239d6862009-08-12 08:23:04 +00002717 /* Check signal is detected */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002718 bnx2x_check_fallback_to_cl37(phy, params);
Eilon Greenstein239d6862009-08-12 08:23:04 +00002719 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002720 }
2721
Frans Pop2381a552010-03-24 07:57:36 +00002722 DP(NETIF_MSG_LINK, "gp_status 0x%x phy_link_up %x line_speed %x\n",
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002723 gp_status, vars->phy_link_up, vars->line_speed);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002724 DP(NETIF_MSG_LINK, "duplex %x flow_ctrl 0x%x link_status 0x%x\n",
2725 vars->duplex, vars->flow_ctrl, vars->link_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002726 return rc;
2727}
2728
Eilon Greensteined8680a2009-02-12 08:37:12 +00002729static void bnx2x_set_gmii_tx_driver(struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002730{
2731 struct bnx2x *bp = params->bp;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002732 struct bnx2x_phy *phy = &params->phy[INT_PHY];
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002733 u16 lp_up2;
2734 u16 tx_driver;
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00002735 u16 bank;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002736
2737 /* read precomp */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002738 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002739 MDIO_REG_BANK_OVER_1G,
2740 MDIO_OVER_1G_LP_UP2, &lp_up2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002741
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002742 /* bits [10:7] at lp_up2, positioned at [15:12] */
2743 lp_up2 = (((lp_up2 & MDIO_OVER_1G_LP_UP2_PREEMPHASIS_MASK) >>
2744 MDIO_OVER_1G_LP_UP2_PREEMPHASIS_SHIFT) <<
2745 MDIO_TX0_TX_DRIVER_PREEMPHASIS_SHIFT);
2746
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00002747 if (lp_up2 == 0)
2748 return;
2749
2750 for (bank = MDIO_REG_BANK_TX0; bank <= MDIO_REG_BANK_TX3;
2751 bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0)) {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002752 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002753 bank,
2754 MDIO_TX0_TX_DRIVER, &tx_driver);
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00002755
2756 /* replace tx_driver bits [15:12] */
2757 if (lp_up2 !=
2758 (tx_driver & MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK)) {
2759 tx_driver &= ~MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK;
2760 tx_driver |= lp_up2;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002761 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002762 bank,
2763 MDIO_TX0_TX_DRIVER, tx_driver);
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00002764 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002765 }
2766}
2767
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00002768static int bnx2x_emac_program(struct link_params *params,
2769 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002770{
2771 struct bnx2x *bp = params->bp;
2772 u8 port = params->port;
2773 u16 mode = 0;
2774
2775 DP(NETIF_MSG_LINK, "setting link speed & duplex\n");
2776 bnx2x_bits_dis(bp, GRCBASE_EMAC0 + port*0x400 +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002777 EMAC_REG_EMAC_MODE,
2778 (EMAC_MODE_25G_MODE |
2779 EMAC_MODE_PORT_MII_10M |
2780 EMAC_MODE_HALF_DUPLEX));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002781 switch (vars->line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002782 case SPEED_10:
2783 mode |= EMAC_MODE_PORT_MII_10M;
2784 break;
2785
2786 case SPEED_100:
2787 mode |= EMAC_MODE_PORT_MII;
2788 break;
2789
2790 case SPEED_1000:
2791 mode |= EMAC_MODE_PORT_GMII;
2792 break;
2793
2794 case SPEED_2500:
2795 mode |= (EMAC_MODE_25G_MODE | EMAC_MODE_PORT_GMII);
2796 break;
2797
2798 default:
2799 /* 10G not valid for EMAC */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002800 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
2801 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002802 return -EINVAL;
2803 }
2804
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002805 if (vars->duplex == DUPLEX_HALF)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002806 mode |= EMAC_MODE_HALF_DUPLEX;
2807 bnx2x_bits_en(bp,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002808 GRCBASE_EMAC0 + port*0x400 + EMAC_REG_EMAC_MODE,
2809 mode);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002810
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00002811 bnx2x_set_led(params, vars, LED_MODE_OPER, vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002812 return 0;
2813}
2814
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002815static void bnx2x_set_preemphasis(struct bnx2x_phy *phy,
2816 struct link_params *params)
2817{
2818
2819 u16 bank, i = 0;
2820 struct bnx2x *bp = params->bp;
2821
2822 for (bank = MDIO_REG_BANK_RX0, i = 0; bank <= MDIO_REG_BANK_RX3;
2823 bank += (MDIO_REG_BANK_RX1-MDIO_REG_BANK_RX0), i++) {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002824 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002825 bank,
2826 MDIO_RX0_RX_EQ_BOOST,
2827 phy->rx_preemphasis[i]);
2828 }
2829
2830 for (bank = MDIO_REG_BANK_TX0, i = 0; bank <= MDIO_REG_BANK_TX3;
2831 bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0), i++) {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002832 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002833 bank,
2834 MDIO_TX0_TX_DRIVER,
2835 phy->tx_preemphasis[i]);
2836 }
2837}
2838
Yaniv Rosnerec146a62011-05-31 21:29:27 +00002839static void bnx2x_xgxs_config_init(struct bnx2x_phy *phy,
2840 struct link_params *params,
2841 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002842{
2843 struct bnx2x *bp = params->bp;
2844 u8 enable_cl73 = (SINGLE_MEDIA_DIRECT(params) ||
2845 (params->loopback_mode == LOOPBACK_XGXS));
2846 if (!(vars->phy_flags & PHY_SGMII_FLAG)) {
2847 if (SINGLE_MEDIA_DIRECT(params) &&
2848 (params->feature_config_flags &
2849 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED))
2850 bnx2x_set_preemphasis(phy, params);
2851
2852 /* forced speed requested? */
2853 if (vars->line_speed != SPEED_AUTO_NEG ||
2854 (SINGLE_MEDIA_DIRECT(params) &&
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002855 params->loopback_mode == LOOPBACK_EXT)) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002856 DP(NETIF_MSG_LINK, "not SGMII, no AN\n");
2857
2858 /* disable autoneg */
2859 bnx2x_set_autoneg(phy, params, vars, 0);
2860
2861 /* program speed and duplex */
2862 bnx2x_program_serdes(phy, params, vars);
2863
2864 } else { /* AN_mode */
2865 DP(NETIF_MSG_LINK, "not SGMII, AN\n");
2866
2867 /* AN enabled */
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00002868 bnx2x_set_brcm_cl37_advertisement(phy, params);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002869
2870 /* program duplex & pause advertisement (for aneg) */
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00002871 bnx2x_set_ieee_aneg_advertisement(phy, params,
2872 vars->ieee_fc);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002873
2874 /* enable autoneg */
2875 bnx2x_set_autoneg(phy, params, vars, enable_cl73);
2876
2877 /* enable and restart AN */
2878 bnx2x_restart_autoneg(phy, params, enable_cl73);
2879 }
2880
2881 } else { /* SGMII mode */
2882 DP(NETIF_MSG_LINK, "SGMII\n");
2883
2884 bnx2x_initialize_sgmii_process(phy, params, vars);
2885 }
2886}
2887
Yaniv Rosnerec146a62011-05-31 21:29:27 +00002888static int bnx2x_prepare_xgxs(struct bnx2x_phy *phy,
2889 struct link_params *params,
2890 struct link_vars *vars)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002891{
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00002892 int rc;
Yaniv Rosnerec146a62011-05-31 21:29:27 +00002893 vars->phy_flags |= PHY_XGXS_FLAG;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002894 if ((phy->req_line_speed &&
2895 ((phy->req_line_speed == SPEED_100) ||
2896 (phy->req_line_speed == SPEED_10))) ||
2897 (!phy->req_line_speed &&
2898 (phy->speed_cap_mask >=
2899 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL) &&
2900 (phy->speed_cap_mask <
Yaniv Rosnerec146a62011-05-31 21:29:27 +00002901 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) ||
2902 (phy->type == PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT_SD))
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002903 vars->phy_flags |= PHY_SGMII_FLAG;
2904 else
2905 vars->phy_flags &= ~PHY_SGMII_FLAG;
2906
2907 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
Yaniv Rosnerec146a62011-05-31 21:29:27 +00002908 bnx2x_set_aer_mmd(params, phy);
2909 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT)
2910 bnx2x_set_master_ln(params, phy);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002911
2912 rc = bnx2x_reset_unicore(params, phy, 0);
2913 /* reset the SerDes and wait for reset bit return low */
2914 if (rc != 0)
2915 return rc;
2916
Yaniv Rosnerec146a62011-05-31 21:29:27 +00002917 bnx2x_set_aer_mmd(params, phy);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002918 /* setting the masterLn_def again after the reset */
Yaniv Rosnerec146a62011-05-31 21:29:27 +00002919 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) {
2920 bnx2x_set_master_ln(params, phy);
2921 bnx2x_set_swap_lanes(params, phy);
2922 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002923
2924 return rc;
2925}
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002926
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002927static u16 bnx2x_wait_reset_complete(struct bnx2x *bp,
Yaniv Rosner6d870c32011-01-31 04:22:20 +00002928 struct bnx2x_phy *phy,
2929 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002930{
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002931 u16 cnt, ctrl;
Lucas De Marchi25985ed2011-03-30 22:57:33 -03002932 /* Wait for soft reset to get cleared up to 1 sec */
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002933 for (cnt = 0; cnt < 1000; cnt++) {
2934 bnx2x_cl45_read(bp, phy,
2935 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, &ctrl);
2936 if (!(ctrl & (1<<15)))
2937 break;
2938 msleep(1);
2939 }
Yaniv Rosner6d870c32011-01-31 04:22:20 +00002940
2941 if (cnt == 1000)
2942 netdev_err(bp->dev, "Warning: PHY was not initialized,"
2943 " Port %d\n",
2944 params->port);
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002945 DP(NETIF_MSG_LINK, "control reg 0x%x (after %d ms)\n", ctrl, cnt);
2946 return cnt;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002947}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002948
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002949static void bnx2x_link_int_enable(struct link_params *params)
2950{
2951 u8 port = params->port;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002952 u32 mask;
2953 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002954
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002955 /* Setting the status to report on link up for either XGXS or SerDes */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002956 if (params->switch_cfg == SWITCH_CFG_10G) {
2957 mask = (NIG_MASK_XGXS0_LINK10G |
2958 NIG_MASK_XGXS0_LINK_STATUS);
2959 DP(NETIF_MSG_LINK, "enabled XGXS interrupt\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002960 if (!(SINGLE_MEDIA_DIRECT(params)) &&
2961 params->phy[INT_PHY].type !=
2962 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002963 mask |= NIG_MASK_MI_INT;
2964 DP(NETIF_MSG_LINK, "enabled external phy int\n");
2965 }
2966
2967 } else { /* SerDes */
2968 mask = NIG_MASK_SERDES0_LINK_STATUS;
2969 DP(NETIF_MSG_LINK, "enabled SerDes interrupt\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002970 if (!(SINGLE_MEDIA_DIRECT(params)) &&
2971 params->phy[INT_PHY].type !=
2972 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_NOT_CONN) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002973 mask |= NIG_MASK_MI_INT;
2974 DP(NETIF_MSG_LINK, "enabled external phy int\n");
2975 }
2976 }
2977 bnx2x_bits_en(bp,
2978 NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
2979 mask);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002980
2981 DP(NETIF_MSG_LINK, "port %x, is_xgxs %x, int_status 0x%x\n", port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002982 (params->switch_cfg == SWITCH_CFG_10G),
2983 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002984 DP(NETIF_MSG_LINK, " int_mask 0x%x, MI_INT %x, SERDES_LINK %x\n",
2985 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
2986 REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
2987 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS+port*0x3c));
2988 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
2989 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
2990 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
2991}
2992
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002993static void bnx2x_rearm_latch_signal(struct bnx2x *bp, u8 port,
2994 u8 exp_mi_int)
Eilon Greenstein2f904462009-08-12 08:22:16 +00002995{
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002996 u32 latch_status = 0;
2997
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002998 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002999 * Disable the MI INT ( external phy int ) by writing 1 to the
3000 * status register. Link down indication is high-active-signal,
3001 * so in this case we need to write the status to clear the XOR
Eilon Greenstein2f904462009-08-12 08:22:16 +00003002 */
3003 /* Read Latched signals */
3004 latch_status = REG_RD(bp,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003005 NIG_REG_LATCH_STATUS_0 + port*8);
3006 DP(NETIF_MSG_LINK, "latch_status = 0x%x\n", latch_status);
Eilon Greenstein2f904462009-08-12 08:22:16 +00003007 /* Handle only those with latched-signal=up.*/
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003008 if (exp_mi_int)
3009 bnx2x_bits_en(bp,
3010 NIG_REG_STATUS_INTERRUPT_PORT0
3011 + port*4,
3012 NIG_STATUS_EMAC0_MI_INT);
3013 else
3014 bnx2x_bits_dis(bp,
3015 NIG_REG_STATUS_INTERRUPT_PORT0
3016 + port*4,
3017 NIG_STATUS_EMAC0_MI_INT);
3018
Eilon Greenstein2f904462009-08-12 08:22:16 +00003019 if (latch_status & 1) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003020
Eilon Greenstein2f904462009-08-12 08:22:16 +00003021 /* For all latched-signal=up : Re-Arm Latch signals */
3022 REG_WR(bp, NIG_REG_LATCH_STATUS_0 + port*8,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003023 (latch_status & 0xfffe) | (latch_status & 1));
Eilon Greenstein2f904462009-08-12 08:22:16 +00003024 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003025 /* For all latched-signal=up,Write original_signal to status */
Eilon Greenstein2f904462009-08-12 08:22:16 +00003026}
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003027
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003028static void bnx2x_link_int_ack(struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003029 struct link_vars *vars, u8 is_10g)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003030{
3031 struct bnx2x *bp = params->bp;
3032 u8 port = params->port;
3033
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003034 /*
3035 * First reset all status we assume only one line will be
3036 * change at a time
3037 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003038 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003039 (NIG_STATUS_XGXS0_LINK10G |
3040 NIG_STATUS_XGXS0_LINK_STATUS |
3041 NIG_STATUS_SERDES0_LINK_STATUS));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003042 if (vars->phy_link_up) {
3043 if (is_10g) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003044 /*
3045 * Disable the 10G link interrupt by writing 1 to the
3046 * status register
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003047 */
3048 DP(NETIF_MSG_LINK, "10G XGXS phy link up\n");
3049 bnx2x_bits_en(bp,
3050 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
3051 NIG_STATUS_XGXS0_LINK10G);
3052
3053 } else if (params->switch_cfg == SWITCH_CFG_10G) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003054 /*
3055 * Disable the link interrupt by writing 1 to the
3056 * relevant lane in the status register
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003057 */
3058 u32 ser_lane = ((params->lane_config &
3059 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
3060 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
3061
Eilon Greenstein2f904462009-08-12 08:22:16 +00003062 DP(NETIF_MSG_LINK, "%d speed XGXS phy link up\n",
3063 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003064 bnx2x_bits_en(bp,
3065 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
3066 ((1 << ser_lane) <<
3067 NIG_STATUS_XGXS0_LINK_STATUS_SIZE));
3068
3069 } else { /* SerDes */
3070 DP(NETIF_MSG_LINK, "SerDes phy link up\n");
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003071 /*
3072 * Disable the link interrupt by writing 1 to the status
3073 * register
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003074 */
3075 bnx2x_bits_en(bp,
3076 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
3077 NIG_STATUS_SERDES0_LINK_STATUS);
3078 }
3079
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003080 }
3081}
3082
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00003083static int bnx2x_format_ver(u32 num, u8 *str, u16 *len)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003084{
3085 u8 *str_ptr = str;
3086 u32 mask = 0xf0000000;
3087 u8 shift = 8*4;
3088 u8 digit;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003089 u8 remove_leading_zeros = 1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003090 if (*len < 10) {
Frederik Schwarzer025dfda2008-10-16 19:02:37 +02003091 /* Need more than 10chars for this format */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003092 *str_ptr = '\0';
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003093 (*len)--;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003094 return -EINVAL;
3095 }
3096 while (shift > 0) {
3097
3098 shift -= 4;
3099 digit = ((num & mask) >> shift);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003100 if (digit == 0 && remove_leading_zeros) {
3101 mask = mask >> 4;
3102 continue;
3103 } else if (digit < 0xa)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003104 *str_ptr = digit + '0';
3105 else
3106 *str_ptr = digit - 0xa + 'a';
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003107 remove_leading_zeros = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003108 str_ptr++;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003109 (*len)--;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003110 mask = mask >> 4;
3111 if (shift == 4*4) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003112 *str_ptr = '.';
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003113 str_ptr++;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003114 (*len)--;
3115 remove_leading_zeros = 1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003116 }
3117 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003118 return 0;
3119}
3120
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003121
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00003122static int bnx2x_null_format_ver(u32 spirom_ver, u8 *str, u16 *len)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003123{
3124 str[0] = '\0';
3125 (*len)--;
3126 return 0;
3127}
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003128
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00003129int bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
3130 u8 *version, u16 len)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003131{
Julia Lawall0376d5b2009-07-19 05:26:35 +00003132 struct bnx2x *bp;
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003133 u32 spirom_ver = 0;
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00003134 int status = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003135 u8 *ver_p = version;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003136 u16 remain_len = len;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003137 if (version == NULL || params == NULL)
3138 return -EINVAL;
Julia Lawall0376d5b2009-07-19 05:26:35 +00003139 bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003140
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003141 /* Extract first external phy*/
3142 version[0] = '\0';
3143 spirom_ver = REG_RD(bp, params->phy[EXT_PHY1].ver_addr);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003144
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003145 if (params->phy[EXT_PHY1].format_fw_ver) {
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003146 status |= params->phy[EXT_PHY1].format_fw_ver(spirom_ver,
3147 ver_p,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003148 &remain_len);
3149 ver_p += (len - remain_len);
3150 }
3151 if ((params->num_phys == MAX_PHYS) &&
3152 (params->phy[EXT_PHY2].ver_addr != 0)) {
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003153 spirom_ver = REG_RD(bp, params->phy[EXT_PHY2].ver_addr);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003154 if (params->phy[EXT_PHY2].format_fw_ver) {
3155 *ver_p = '/';
3156 ver_p++;
3157 remain_len--;
3158 status |= params->phy[EXT_PHY2].format_fw_ver(
3159 spirom_ver,
3160 ver_p,
3161 &remain_len);
3162 ver_p = version + (len - remain_len);
3163 }
3164 }
3165 *ver_p = '\0';
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003166 return status;
3167}
3168
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003169static void bnx2x_set_xgxs_loopback(struct bnx2x_phy *phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003170 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003171{
3172 u8 port = params->port;
3173 struct bnx2x *bp = params->bp;
3174
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003175 if (phy->req_line_speed != SPEED_1000) {
Eilon Greenstein6378c022008-08-13 15:59:25 -07003176 u32 md_devad;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003177
3178 DP(NETIF_MSG_LINK, "XGXS 10G loopback enable\n");
3179
3180 /* change the uni_phy_addr in the nig */
3181 md_devad = REG_RD(bp, (NIG_REG_XGXS0_CTRL_MD_DEVAD +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003182 port*0x18));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003183
3184 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, 0x5);
3185
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003186 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003187 5,
3188 (MDIO_REG_BANK_AER_BLOCK +
3189 (MDIO_AER_BLOCK_AER_REG & 0xf)),
3190 0x2800);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003191
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003192 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003193 5,
3194 (MDIO_REG_BANK_CL73_IEEEB0 +
3195 (MDIO_CL73_IEEEB0_CL73_AN_CONTROL & 0xf)),
3196 0x6041);
Eilon Greenstein38582762009-01-14 06:44:16 +00003197 msleep(200);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003198 /* set aer mmd back */
Yaniv Rosnerec146a62011-05-31 21:29:27 +00003199 bnx2x_set_aer_mmd(params, phy);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003200
3201 /* and md_devad */
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003202 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, md_devad);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003203 } else {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003204 u16 mii_ctrl;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003205 DP(NETIF_MSG_LINK, "XGXS 1G loopback enable\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003206 bnx2x_cl45_read(bp, phy, 5,
3207 (MDIO_REG_BANK_COMBO_IEEE0 +
3208 (MDIO_COMBO_IEEE0_MII_CONTROL & 0xf)),
3209 &mii_ctrl);
3210 bnx2x_cl45_write(bp, phy, 5,
3211 (MDIO_REG_BANK_COMBO_IEEE0 +
3212 (MDIO_COMBO_IEEE0_MII_CONTROL & 0xf)),
3213 mii_ctrl |
3214 MDIO_COMBO_IEEO_MII_CONTROL_LOOPBACK);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003215 }
3216}
3217
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00003218int bnx2x_set_led(struct link_params *params,
3219 struct link_vars *vars, u8 mode, u32 speed)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003220{
Yaniv Rosner7846e472009-11-05 19:18:07 +02003221 u8 port = params->port;
3222 u16 hw_led_mode = params->hw_led_mode;
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00003223 int rc = 0;
3224 u8 phy_idx;
Eilon Greenstein345b5d52008-08-13 15:58:12 -07003225 u32 tmp;
3226 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Yaniv Rosner7846e472009-11-05 19:18:07 +02003227 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003228 DP(NETIF_MSG_LINK, "bnx2x_set_led: port %x, mode %d\n", port, mode);
3229 DP(NETIF_MSG_LINK, "speed 0x%x, hw_led_mode 0x%x\n",
3230 speed, hw_led_mode);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003231 /* In case */
3232 for (phy_idx = EXT_PHY1; phy_idx < MAX_PHYS; phy_idx++) {
3233 if (params->phy[phy_idx].set_link_led) {
3234 params->phy[phy_idx].set_link_led(
3235 &params->phy[phy_idx], params, mode);
3236 }
3237 }
3238
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003239 switch (mode) {
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003240 case LED_MODE_FRONT_PANEL_OFF:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003241 case LED_MODE_OFF:
3242 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 0);
3243 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003244 SHARED_HW_CFG_LED_MAC1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07003245
3246 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07003247 EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp | EMAC_LED_OVERRIDE));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003248 break;
3249
3250 case LED_MODE_OPER:
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003251 /*
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003252 * For all other phys, OPER mode is same as ON, so in case
3253 * link is down, do nothing
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003254 */
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003255 if (!vars->link_up)
3256 break;
3257 case LED_MODE_ON:
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00003258 if (((params->phy[EXT_PHY1].type ==
3259 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) ||
3260 (params->phy[EXT_PHY1].type ==
3261 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722)) &&
Yaniv Rosner1f483532011-01-18 04:33:31 +00003262 CHIP_IS_E2(bp) && params->num_phys == 2) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003263 /*
3264 * This is a work-around for E2+8727 Configurations
3265 */
Yaniv Rosner1f483532011-01-18 04:33:31 +00003266 if (mode == LED_MODE_ON ||
3267 speed == SPEED_10000){
3268 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0);
3269 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1);
3270
3271 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
3272 EMAC_WR(bp, EMAC_REG_EMAC_LED,
3273 (tmp | EMAC_LED_OVERRIDE));
3274 return rc;
3275 }
3276 } else if (SINGLE_MEDIA_DIRECT(params)) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003277 /*
3278 * This is a work-around for HW issue found when link
3279 * is up in CL73
3280 */
Yaniv Rosner7846e472009-11-05 19:18:07 +02003281 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0);
3282 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1);
3283 } else {
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003284 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, hw_led_mode);
Yaniv Rosner7846e472009-11-05 19:18:07 +02003285 }
3286
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003287 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 + port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003288 /* Set blinking rate to ~15.9Hz */
3289 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003290 LED_BLINK_RATE_VAL);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003291 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003292 port*4, 1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07003293 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003294 EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp & (~EMAC_LED_OVERRIDE)));
Eilon Greenstein345b5d52008-08-13 15:58:12 -07003295
Yaniv Rosner7846e472009-11-05 19:18:07 +02003296 if (CHIP_IS_E1(bp) &&
Eilon Greenstein34f80b02008-06-23 20:33:01 -07003297 ((speed == SPEED_2500) ||
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003298 (speed == SPEED_1000) ||
3299 (speed == SPEED_100) ||
3300 (speed == SPEED_10))) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003301 /*
3302 * On Everest 1 Ax chip versions for speeds less than
3303 * 10G LED scheme is different
3304 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003305 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003306 + port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003307 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003308 port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003309 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_TRAFFIC_P0 +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003310 port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003311 }
3312 break;
3313
3314 default:
3315 rc = -EINVAL;
3316 DP(NETIF_MSG_LINK, "bnx2x_set_led: Invalid led mode %d\n",
3317 mode);
3318 break;
3319 }
3320 return rc;
3321
3322}
3323
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003324/*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003325 * This function comes to reflect the actual link state read DIRECTLY from the
3326 * HW
3327 */
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00003328int bnx2x_test_link(struct link_params *params, struct link_vars *vars,
3329 u8 is_serdes)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003330{
3331 struct bnx2x *bp = params->bp;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003332 u16 gp_status = 0, phy_index = 0;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003333 u8 ext_phy_link_up = 0, serdes_phy_type;
3334 struct link_vars temp_vars;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003335
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003336 CL22_RD_OVER_CL45(bp, &params->phy[INT_PHY],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003337 MDIO_REG_BANK_GP_STATUS,
3338 MDIO_GP_STATUS_TOP_AN_STATUS1,
3339 &gp_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003340 /* link is up only if both local phy and external phy are up */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003341 if (!(gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS))
3342 return -ESRCH;
3343
3344 switch (params->num_phys) {
3345 case 1:
3346 /* No external PHY */
3347 return 0;
3348 case 2:
3349 ext_phy_link_up = params->phy[EXT_PHY1].read_status(
3350 &params->phy[EXT_PHY1],
3351 params, &temp_vars);
3352 break;
3353 case 3: /* Dual Media */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003354 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
3355 phy_index++) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003356 serdes_phy_type = ((params->phy[phy_index].media_type ==
3357 ETH_PHY_SFP_FIBER) ||
3358 (params->phy[phy_index].media_type ==
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00003359 ETH_PHY_XFP_FIBER) ||
3360 (params->phy[phy_index].media_type ==
3361 ETH_PHY_DA_TWINAX));
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003362
3363 if (is_serdes != serdes_phy_type)
3364 continue;
3365 if (params->phy[phy_index].read_status) {
3366 ext_phy_link_up |=
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003367 params->phy[phy_index].read_status(
3368 &params->phy[phy_index],
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003369 params, &temp_vars);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003370 }
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003371 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003372 break;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003373 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003374 if (ext_phy_link_up)
3375 return 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003376 return -ESRCH;
3377}
3378
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00003379static int bnx2x_link_initialize(struct link_params *params,
3380 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003381{
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00003382 int rc = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003383 u8 phy_index, non_ext_phy;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003384 struct bnx2x *bp = params->bp;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003385 /*
3386 * In case of external phy existence, the line speed would be the
3387 * line speed linked up by the external phy. In case it is direct
3388 * only, then the line_speed during initialization will be
3389 * equal to the req_line_speed
3390 */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003391 vars->line_speed = params->phy[INT_PHY].req_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003392
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003393 /*
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003394 * Initialize the internal phy in case this is a direct board
3395 * (no external phys), or this board has external phy which requires
3396 * to first.
3397 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003398
Yaniv Rosnerec146a62011-05-31 21:29:27 +00003399 bnx2x_prepare_xgxs(&params->phy[INT_PHY], params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003400 /* init ext phy and enable link state int */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003401 non_ext_phy = (SINGLE_MEDIA_DIRECT(params) ||
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003402 (params->loopback_mode == LOOPBACK_XGXS));
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003403
3404 if (non_ext_phy ||
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003405 (params->phy[EXT_PHY1].flags & FLAGS_INIT_XGXS_FIRST) ||
Eilon Greenstein8660d8c2009-03-02 08:01:02 +00003406 (params->loopback_mode == LOOPBACK_EXT_PHY)) {
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003407 struct bnx2x_phy *phy = &params->phy[INT_PHY];
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003408 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003409 bnx2x_set_parallel_detection(phy, params);
Yaniv Rosnerec146a62011-05-31 21:29:27 +00003410 if (params->phy[INT_PHY].config_init)
3411 params->phy[INT_PHY].config_init(phy,
3412 params,
3413 vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003414 }
3415
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003416 /* Init external phy*/
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00003417 if (non_ext_phy) {
3418 if (params->phy[INT_PHY].supported &
3419 SUPPORTED_FIBRE)
3420 vars->link_status |= LINK_STATUS_SERDES_LINK;
3421 } else {
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003422 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
3423 phy_index++) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003424 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003425 * No need to initialize second phy in case of first
3426 * phy only selection. In case of second phy, we do
3427 * need to initialize the first phy, since they are
3428 * connected.
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003429 */
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00003430 if (params->phy[phy_index].supported &
3431 SUPPORTED_FIBRE)
3432 vars->link_status |= LINK_STATUS_SERDES_LINK;
3433
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003434 if (phy_index == EXT_PHY2 &&
3435 (bnx2x_phy_selection(params) ==
3436 PORT_HW_CFG_PHY_SELECTION_FIRST_PHY)) {
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00003437 DP(NETIF_MSG_LINK, "Not initializing"
3438 " second phy\n");
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003439 continue;
3440 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003441 params->phy[phy_index].config_init(
3442 &params->phy[phy_index],
3443 params, vars);
3444 }
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00003445 }
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00003446 /* Reset the interrupt indication after phy was initialized */
3447 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 +
3448 params->port*4,
3449 (NIG_STATUS_XGXS0_LINK10G |
3450 NIG_STATUS_XGXS0_LINK_STATUS |
3451 NIG_STATUS_SERDES0_LINK_STATUS |
3452 NIG_MASK_MI_INT));
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00003453 bnx2x_update_mng(params, vars->link_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003454 return rc;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003455}
3456
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003457static void bnx2x_int_link_reset(struct bnx2x_phy *phy,
3458 struct link_params *params)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003459{
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003460 /* reset the SerDes/XGXS */
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003461 REG_WR(params->bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
3462 (0x1ff << (params->port*16)));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003463}
3464
3465static void bnx2x_common_ext_link_reset(struct bnx2x_phy *phy,
3466 struct link_params *params)
3467{
3468 struct bnx2x *bp = params->bp;
3469 u8 gpio_port;
3470 /* HW reset */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00003471 if (CHIP_IS_E2(bp))
3472 gpio_port = BP_PATH(bp);
3473 else
3474 gpio_port = params->port;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003475 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003476 MISC_REGISTERS_GPIO_OUTPUT_LOW,
3477 gpio_port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003478 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003479 MISC_REGISTERS_GPIO_OUTPUT_LOW,
3480 gpio_port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003481 DP(NETIF_MSG_LINK, "reset external PHY\n");
3482}
3483
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00003484static int bnx2x_update_link_down(struct link_params *params,
3485 struct link_vars *vars)
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003486{
3487 struct bnx2x *bp = params->bp;
3488 u8 port = params->port;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00003489
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003490 DP(NETIF_MSG_LINK, "Port %x: Link is down\n", port);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003491 bnx2x_set_led(params, vars, LED_MODE_OFF, 0);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003492
3493 /* indicate no mac active */
3494 vars->mac_type = MAC_TYPE_NONE;
3495
3496 /* update shared memory */
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00003497 vars->link_status &= ~(LINK_STATUS_SPEED_AND_DUPLEX_MASK |
3498 LINK_STATUS_LINK_UP |
3499 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE |
3500 LINK_STATUS_RX_FLOW_CONTROL_FLAG_MASK |
3501 LINK_STATUS_TX_FLOW_CONTROL_FLAG_MASK |
3502 LINK_STATUS_PARALLEL_DETECTION_FLAG_MASK);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003503 vars->line_speed = 0;
3504 bnx2x_update_mng(params, vars->link_status);
3505
3506 /* activate nig drain */
3507 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
3508
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00003509 /* disable emac */
3510 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
3511
3512 msleep(10);
3513
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003514 /* reset BigMac */
3515 bnx2x_bmac_rx_disable(bp, params->port);
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003516 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
3517 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003518 return 0;
3519}
3520
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00003521static int bnx2x_update_link_up(struct link_params *params,
3522 struct link_vars *vars,
3523 u8 link_10g)
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003524{
3525 struct bnx2x *bp = params->bp;
3526 u8 port = params->port;
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00003527 int rc = 0;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00003528
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003529 vars->link_status |= LINK_STATUS_LINK_UP;
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003530
Yaniv Rosner7aa07112010-09-07 11:41:01 +00003531 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
3532 vars->link_status |=
3533 LINK_STATUS_TX_FLOW_CONTROL_ENABLED;
3534
3535 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
3536 vars->link_status |=
3537 LINK_STATUS_RX_FLOW_CONTROL_ENABLED;
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003538
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003539 if (link_10g) {
3540 bnx2x_bmac_enable(params, vars, 0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00003541 bnx2x_set_led(params, vars,
3542 LED_MODE_OPER, SPEED_10000);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003543 } else {
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003544 rc = bnx2x_emac_program(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003545
Yaniv Rosner0c786f02009-11-05 19:18:32 +02003546 bnx2x_emac_enable(params, vars, 0);
3547
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003548 /* AN complete? */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003549 if ((vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE)
3550 && (!(vars->phy_flags & PHY_SGMII_FLAG)) &&
3551 SINGLE_MEDIA_DIRECT(params))
3552 bnx2x_set_gmii_tx_driver(params);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003553 }
3554
3555 /* PBF - link up */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00003556 if (!(CHIP_IS_E2(bp)))
3557 rc |= bnx2x_pbf_update(params, vars->flow_ctrl,
3558 vars->line_speed);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003559
3560 /* disable drain */
3561 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 0);
3562
3563 /* update shared memory */
3564 bnx2x_update_mng(params, vars->link_status);
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00003565 msleep(20);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003566 return rc;
3567}
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003568/*
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003569 * The bnx2x_link_update function should be called upon link
3570 * interrupt.
3571 * Link is considered up as follows:
3572 * - DIRECT_SINGLE_MEDIA - Only XGXS link (internal link) needs
3573 * to be up
3574 * - SINGLE_MEDIA - The link between the 577xx and the external
3575 * phy (XGXS) need to up as well as the external link of the
3576 * phy (PHY_EXT1)
3577 * - DUAL_MEDIA - The link between the 577xx and the first
3578 * external phy needs to be up, and at least one of the 2
3579 * external phy link must be up.
Yaniv Rosner62b29a52010-09-07 11:40:58 +00003580 */
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00003581int bnx2x_link_update(struct link_params *params, struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003582{
3583 struct bnx2x *bp = params->bp;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003584 struct link_vars phy_vars[MAX_PHYS];
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003585 u8 port = params->port;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003586 u8 link_10g, phy_index;
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00003587 u8 ext_phy_link_up = 0, cur_link_up;
3588 int rc = 0;
Eilon Greenstein2f904462009-08-12 08:22:16 +00003589 u8 is_mi_int = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003590 u16 ext_phy_line_speed = 0, prev_line_speed = vars->line_speed;
3591 u8 active_external_phy = INT_PHY;
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00003592
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003593 for (phy_index = INT_PHY; phy_index < params->num_phys;
3594 phy_index++) {
3595 phy_vars[phy_index].flow_ctrl = 0;
3596 phy_vars[phy_index].link_status = 0;
3597 phy_vars[phy_index].line_speed = 0;
3598 phy_vars[phy_index].duplex = DUPLEX_FULL;
3599 phy_vars[phy_index].phy_link_up = 0;
3600 phy_vars[phy_index].link_up = 0;
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00003601 phy_vars[phy_index].fault_detected = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003602 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003603
3604 DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n",
Eilon Greenstein2f904462009-08-12 08:22:16 +00003605 port, (vars->phy_flags & PHY_XGXS_FLAG),
3606 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003607
Eilon Greenstein2f904462009-08-12 08:22:16 +00003608 is_mi_int = (u8)(REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003609 port*0x18) > 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003610 DP(NETIF_MSG_LINK, "int_mask 0x%x MI_INT %x, SERDES_LINK %x\n",
Eilon Greenstein2f904462009-08-12 08:22:16 +00003611 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
3612 is_mi_int,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003613 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003614
3615 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
3616 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
3617 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
3618
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00003619 /* disable emac */
3620 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
3621
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003622 /*
3623 * Step 1:
3624 * Check external link change only for external phys, and apply
3625 * priority selection between them in case the link on both phys
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00003626 * is up. Note that instead of the common vars, a temporary
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003627 * vars argument is used since each phy may have different link/
3628 * speed/duplex result
3629 */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003630 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
3631 phy_index++) {
3632 struct bnx2x_phy *phy = &params->phy[phy_index];
3633 if (!phy->read_status)
3634 continue;
3635 /* Read link status and params of this ext phy */
3636 cur_link_up = phy->read_status(phy, params,
3637 &phy_vars[phy_index]);
3638 if (cur_link_up) {
3639 DP(NETIF_MSG_LINK, "phy in index %d link is up\n",
3640 phy_index);
3641 } else {
3642 DP(NETIF_MSG_LINK, "phy in index %d link is down\n",
3643 phy_index);
3644 continue;
3645 }
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003646
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003647 if (!ext_phy_link_up) {
3648 ext_phy_link_up = 1;
3649 active_external_phy = phy_index;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003650 } else {
3651 switch (bnx2x_phy_selection(params)) {
3652 case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT:
3653 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003654 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003655 * In this option, the first PHY makes sure to pass the
3656 * traffic through itself only.
3657 * Its not clear how to reset the link on the second phy
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003658 */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003659 active_external_phy = EXT_PHY1;
3660 break;
3661 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003662 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003663 * In this option, the first PHY makes sure to pass the
3664 * traffic through the second PHY.
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003665 */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003666 active_external_phy = EXT_PHY2;
3667 break;
3668 default:
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003669 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003670 * Link indication on both PHYs with the following cases
3671 * is invalid:
3672 * - FIRST_PHY means that second phy wasn't initialized,
3673 * hence its link is expected to be down
3674 * - SECOND_PHY means that first phy should not be able
3675 * to link up by itself (using configuration)
3676 * - DEFAULT should be overriden during initialiazation
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003677 */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003678 DP(NETIF_MSG_LINK, "Invalid link indication"
3679 "mpc=0x%x. DISABLING LINK !!!\n",
3680 params->multi_phy_config);
3681 ext_phy_link_up = 0;
3682 break;
3683 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003684 }
3685 }
3686 prev_line_speed = vars->line_speed;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003687 /*
3688 * Step 2:
3689 * Read the status of the internal phy. In case of
3690 * DIRECT_SINGLE_MEDIA board, this link is the external link,
3691 * otherwise this is the link between the 577xx and the first
3692 * external phy
3693 */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003694 if (params->phy[INT_PHY].read_status)
3695 params->phy[INT_PHY].read_status(
3696 &params->phy[INT_PHY],
3697 params, vars);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003698 /*
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003699 * The INT_PHY flow control reside in the vars. This include the
3700 * case where the speed or flow control are not set to AUTO.
3701 * Otherwise, the active external phy flow control result is set
3702 * to the vars. The ext_phy_line_speed is needed to check if the
3703 * speed is different between the internal phy and external phy.
3704 * This case may be result of intermediate link speed change.
3705 */
3706 if (active_external_phy > INT_PHY) {
3707 vars->flow_ctrl = phy_vars[active_external_phy].flow_ctrl;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003708 /*
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003709 * Link speed is taken from the XGXS. AN and FC result from
3710 * the external phy.
3711 */
3712 vars->link_status |= phy_vars[active_external_phy].link_status;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003713
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003714 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003715 * if active_external_phy is first PHY and link is up - disable
3716 * disable TX on second external PHY
3717 */
3718 if (active_external_phy == EXT_PHY1) {
3719 if (params->phy[EXT_PHY2].phy_specific_func) {
3720 DP(NETIF_MSG_LINK, "Disabling TX on"
3721 " EXT_PHY2\n");
3722 params->phy[EXT_PHY2].phy_specific_func(
3723 &params->phy[EXT_PHY2],
3724 params, DISABLE_TX);
3725 }
3726 }
3727
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003728 ext_phy_line_speed = phy_vars[active_external_phy].line_speed;
3729 vars->duplex = phy_vars[active_external_phy].duplex;
3730 if (params->phy[active_external_phy].supported &
3731 SUPPORTED_FIBRE)
3732 vars->link_status |= LINK_STATUS_SERDES_LINK;
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00003733 else
3734 vars->link_status &= ~LINK_STATUS_SERDES_LINK;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003735 DP(NETIF_MSG_LINK, "Active external phy selected: %x\n",
3736 active_external_phy);
3737 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003738
3739 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
3740 phy_index++) {
3741 if (params->phy[phy_index].flags &
3742 FLAGS_REARM_LATCH_SIGNAL) {
3743 bnx2x_rearm_latch_signal(bp, port,
3744 phy_index ==
3745 active_external_phy);
3746 break;
3747 }
3748 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003749 DP(NETIF_MSG_LINK, "vars->flow_ctrl = 0x%x, vars->link_status = 0x%x,"
3750 " ext_phy_line_speed = %d\n", vars->flow_ctrl,
3751 vars->link_status, ext_phy_line_speed);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003752 /*
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003753 * Upon link speed change set the NIG into drain mode. Comes to
3754 * deals with possible FIFO glitch due to clk change when speed
3755 * is decreased without link down indicator
3756 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003757
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003758 if (vars->phy_link_up) {
3759 if (!(SINGLE_MEDIA_DIRECT(params)) && ext_phy_link_up &&
3760 (ext_phy_line_speed != vars->line_speed)) {
3761 DP(NETIF_MSG_LINK, "Internal link speed %d is"
3762 " different than the external"
3763 " link speed %d\n", vars->line_speed,
3764 ext_phy_line_speed);
3765 vars->phy_link_up = 0;
3766 } else if (prev_line_speed != vars->line_speed) {
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003767 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4,
3768 0);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003769 msleep(1);
3770 }
3771 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003772
3773 /* anything 10 and over uses the bmac */
3774 link_10g = ((vars->line_speed == SPEED_10000) ||
3775 (vars->line_speed == SPEED_12000) ||
3776 (vars->line_speed == SPEED_12500) ||
3777 (vars->line_speed == SPEED_13000) ||
3778 (vars->line_speed == SPEED_15000) ||
3779 (vars->line_speed == SPEED_16000));
3780
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003781 bnx2x_link_int_ack(params, vars, link_10g);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003782
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003783 /*
3784 * In case external phy link is up, and internal link is down
3785 * (not initialized yet probably after link initialization, it
3786 * needs to be initialized.
3787 * Note that after link down-up as result of cable plug, the xgxs
3788 * link would probably become up again without the need
3789 * initialize it
3790 */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003791 if (!(SINGLE_MEDIA_DIRECT(params))) {
3792 DP(NETIF_MSG_LINK, "ext_phy_link_up = %d, int_link_up = %d,"
3793 " init_preceding = %d\n", ext_phy_link_up,
3794 vars->phy_link_up,
3795 params->phy[EXT_PHY1].flags &
3796 FLAGS_INIT_XGXS_FIRST);
3797 if (!(params->phy[EXT_PHY1].flags &
3798 FLAGS_INIT_XGXS_FIRST)
3799 && ext_phy_link_up && !vars->phy_link_up) {
3800 vars->line_speed = ext_phy_line_speed;
3801 if (vars->line_speed < SPEED_1000)
3802 vars->phy_flags |= PHY_SGMII_FLAG;
3803 else
3804 vars->phy_flags &= ~PHY_SGMII_FLAG;
Yaniv Rosnerec146a62011-05-31 21:29:27 +00003805
3806 if (params->phy[INT_PHY].config_init)
3807 params->phy[INT_PHY].config_init(
3808 &params->phy[INT_PHY], params,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003809 vars);
3810 }
3811 }
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003812 /*
3813 * Link is up only if both local phy and external phy (in case of
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00003814 * non-direct board) are up and no fault detected on active PHY.
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003815 */
3816 vars->link_up = (vars->phy_link_up &&
3817 (ext_phy_link_up ||
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00003818 SINGLE_MEDIA_DIRECT(params)) &&
3819 (phy_vars[active_external_phy].fault_detected == 0));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003820
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003821 if (vars->link_up)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003822 rc = bnx2x_update_link_up(params, vars, link_10g);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003823 else
3824 rc = bnx2x_update_link_down(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003825
3826 return rc;
3827}
3828
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003829
3830/*****************************************************************************/
3831/* External Phy section */
3832/*****************************************************************************/
3833void bnx2x_ext_phy_hw_reset(struct bnx2x *bp, u8 port)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003834{
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003835 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003836 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003837 msleep(1);
3838 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003839 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003840}
3841
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003842static void bnx2x_save_spirom_version(struct bnx2x *bp, u8 port,
3843 u32 spirom_ver, u32 ver_addr)
3844{
3845 DP(NETIF_MSG_LINK, "FW version 0x%x:0x%x for port %d\n",
3846 (u16)(spirom_ver>>16), (u16)spirom_ver, port);
3847
3848 if (ver_addr)
3849 REG_WR(bp, ver_addr, spirom_ver);
3850}
3851
3852static void bnx2x_save_bcm_spirom_ver(struct bnx2x *bp,
3853 struct bnx2x_phy *phy,
3854 u8 port)
3855{
3856 u16 fw_ver1, fw_ver2;
3857
3858 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003859 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003860 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003861 MDIO_PMA_REG_ROM_VER2, &fw_ver2);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003862 bnx2x_save_spirom_version(bp, port, (u32)(fw_ver1<<16 | fw_ver2),
3863 phy->ver_addr);
3864}
3865
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003866static void bnx2x_ext_phy_10G_an_resolve(struct bnx2x *bp,
3867 struct bnx2x_phy *phy,
3868 struct link_vars *vars)
3869{
3870 u16 val;
3871 bnx2x_cl45_read(bp, phy,
3872 MDIO_AN_DEVAD,
3873 MDIO_AN_REG_STATUS, &val);
3874 bnx2x_cl45_read(bp, phy,
3875 MDIO_AN_DEVAD,
3876 MDIO_AN_REG_STATUS, &val);
3877 if (val & (1<<5))
3878 vars->link_status |= LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
3879 if ((val & (1<<0)) == 0)
3880 vars->link_status |= LINK_STATUS_PARALLEL_DETECTION_USED;
3881}
3882
3883/******************************************************************/
3884/* common BCM8073/BCM8727 PHY SECTION */
3885/******************************************************************/
3886static void bnx2x_8073_resolve_fc(struct bnx2x_phy *phy,
3887 struct link_params *params,
3888 struct link_vars *vars)
3889{
3890 struct bnx2x *bp = params->bp;
3891 if (phy->req_line_speed == SPEED_10 ||
3892 phy->req_line_speed == SPEED_100) {
3893 vars->flow_ctrl = phy->req_flow_ctrl;
3894 return;
3895 }
3896
3897 if (bnx2x_ext_phy_resolve_fc(phy, params, vars) &&
3898 (vars->flow_ctrl == BNX2X_FLOW_CTRL_NONE)) {
3899 u16 pause_result;
3900 u16 ld_pause; /* local */
3901 u16 lp_pause; /* link partner */
3902 bnx2x_cl45_read(bp, phy,
3903 MDIO_AN_DEVAD,
3904 MDIO_AN_REG_CL37_FC_LD, &ld_pause);
3905
3906 bnx2x_cl45_read(bp, phy,
3907 MDIO_AN_DEVAD,
3908 MDIO_AN_REG_CL37_FC_LP, &lp_pause);
3909 pause_result = (ld_pause &
3910 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 5;
3911 pause_result |= (lp_pause &
3912 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 7;
3913
3914 bnx2x_pause_resolve(vars, pause_result);
3915 DP(NETIF_MSG_LINK, "Ext PHY CL37 pause result 0x%x\n",
3916 pause_result);
3917 }
3918}
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00003919static int bnx2x_8073_8727_external_rom_boot(struct bnx2x *bp,
3920 struct bnx2x_phy *phy,
3921 u8 port)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003922{
Yaniv Rosner5c99274b2011-01-18 04:33:36 +00003923 u32 count = 0;
3924 u16 fw_ver1, fw_msgout;
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00003925 int rc = 0;
Yaniv Rosner5c99274b2011-01-18 04:33:36 +00003926
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003927 /* Boot port from external ROM */
3928 /* EDC grst */
3929 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003930 MDIO_PMA_DEVAD,
3931 MDIO_PMA_REG_GEN_CTRL,
3932 0x0001);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003933
3934 /* ucode reboot and rst */
3935 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003936 MDIO_PMA_DEVAD,
3937 MDIO_PMA_REG_GEN_CTRL,
3938 0x008c);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003939
3940 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003941 MDIO_PMA_DEVAD,
3942 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003943
3944 /* Reset internal microprocessor */
3945 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003946 MDIO_PMA_DEVAD,
3947 MDIO_PMA_REG_GEN_CTRL,
3948 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003949
3950 /* Release srst bit */
3951 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003952 MDIO_PMA_DEVAD,
3953 MDIO_PMA_REG_GEN_CTRL,
3954 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003955
Yaniv Rosner5c99274b2011-01-18 04:33:36 +00003956 /* Delay 100ms per the PHY specifications */
3957 msleep(100);
3958
3959 /* 8073 sometimes taking longer to download */
3960 do {
3961 count++;
3962 if (count > 300) {
3963 DP(NETIF_MSG_LINK,
3964 "bnx2x_8073_8727_external_rom_boot port %x:"
3965 "Download failed. fw version = 0x%x\n",
3966 port, fw_ver1);
3967 rc = -EINVAL;
3968 break;
3969 }
3970
3971 bnx2x_cl45_read(bp, phy,
3972 MDIO_PMA_DEVAD,
3973 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
3974 bnx2x_cl45_read(bp, phy,
3975 MDIO_PMA_DEVAD,
3976 MDIO_PMA_REG_M8051_MSGOUT_REG, &fw_msgout);
3977
3978 msleep(1);
3979 } while (fw_ver1 == 0 || fw_ver1 == 0x4321 ||
3980 ((fw_msgout & 0xff) != 0x03 && (phy->type ==
3981 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073)));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003982
3983 /* Clear ser_boot_ctl bit */
3984 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003985 MDIO_PMA_DEVAD,
3986 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003987 bnx2x_save_bcm_spirom_ver(bp, phy, port);
Yaniv Rosner5c99274b2011-01-18 04:33:36 +00003988
3989 DP(NETIF_MSG_LINK,
3990 "bnx2x_8073_8727_external_rom_boot port %x:"
3991 "Download complete. fw version = 0x%x\n",
3992 port, fw_ver1);
3993
3994 return rc;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003995}
3996
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003997/******************************************************************/
3998/* BCM8073 PHY SECTION */
3999/******************************************************************/
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00004000static int bnx2x_8073_is_snr_needed(struct bnx2x *bp, struct bnx2x_phy *phy)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004001{
4002 /* This is only required for 8073A1, version 102 only */
4003 u16 val;
4004
4005 /* Read 8073 HW revision*/
4006 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004007 MDIO_PMA_DEVAD,
4008 MDIO_PMA_REG_8073_CHIP_REV, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004009
4010 if (val != 1) {
4011 /* No need to workaround in 8073 A1 */
4012 return 0;
4013 }
4014
4015 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004016 MDIO_PMA_DEVAD,
4017 MDIO_PMA_REG_ROM_VER2, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004018
4019 /* SNR should be applied only for version 0x102 */
4020 if (val != 0x102)
4021 return 0;
4022
4023 return 1;
4024}
4025
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00004026static int bnx2x_8073_xaui_wa(struct bnx2x *bp, struct bnx2x_phy *phy)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004027{
4028 u16 val, cnt, cnt1 ;
4029
4030 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004031 MDIO_PMA_DEVAD,
4032 MDIO_PMA_REG_8073_CHIP_REV, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004033
4034 if (val > 0) {
4035 /* No need to workaround in 8073 A1 */
4036 return 0;
4037 }
4038 /* XAUI workaround in 8073 A0: */
4039
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004040 /*
4041 * After loading the boot ROM and restarting Autoneg, poll
4042 * Dev1, Reg $C820:
4043 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004044
4045 for (cnt = 0; cnt < 1000; cnt++) {
4046 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004047 MDIO_PMA_DEVAD,
4048 MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
4049 &val);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004050 /*
4051 * If bit [14] = 0 or bit [13] = 0, continue on with
4052 * system initialization (XAUI work-around not required, as
4053 * these bits indicate 2.5G or 1G link up).
4054 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004055 if (!(val & (1<<14)) || !(val & (1<<13))) {
4056 DP(NETIF_MSG_LINK, "XAUI work-around not required\n");
4057 return 0;
4058 } else if (!(val & (1<<15))) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004059 DP(NETIF_MSG_LINK, "bit 15 went off\n");
4060 /*
4061 * If bit 15 is 0, then poll Dev1, Reg $C841 until it's
4062 * MSB (bit15) goes to 1 (indicating that the XAUI
4063 * workaround has completed), then continue on with
4064 * system initialization.
4065 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004066 for (cnt1 = 0; cnt1 < 1000; cnt1++) {
4067 bnx2x_cl45_read(bp, phy,
4068 MDIO_PMA_DEVAD,
4069 MDIO_PMA_REG_8073_XAUI_WA, &val);
4070 if (val & (1<<15)) {
4071 DP(NETIF_MSG_LINK,
4072 "XAUI workaround has completed\n");
4073 return 0;
4074 }
4075 msleep(3);
4076 }
4077 break;
4078 }
4079 msleep(3);
4080 }
4081 DP(NETIF_MSG_LINK, "Warning: XAUI work-around timeout !!!\n");
4082 return -EINVAL;
4083}
4084
4085static void bnx2x_807x_force_10G(struct bnx2x *bp, struct bnx2x_phy *phy)
4086{
4087 /* Force KR or KX */
4088 bnx2x_cl45_write(bp, phy,
4089 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x2040);
4090 bnx2x_cl45_write(bp, phy,
4091 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0x000b);
4092 bnx2x_cl45_write(bp, phy,
4093 MDIO_PMA_DEVAD, MDIO_PMA_REG_BCM_CTRL, 0x0000);
4094 bnx2x_cl45_write(bp, phy,
4095 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x0000);
4096}
4097
4098static void bnx2x_8073_set_pause_cl37(struct link_params *params,
4099 struct bnx2x_phy *phy,
4100 struct link_vars *vars)
4101{
4102 u16 cl37_val;
4103 struct bnx2x *bp = params->bp;
4104 bnx2x_cl45_read(bp, phy,
4105 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, &cl37_val);
4106
4107 cl37_val &= ~MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
4108 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
4109 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
4110 if ((vars->ieee_fc &
4111 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) ==
4112 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) {
4113 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC;
4114 }
4115 if ((vars->ieee_fc &
4116 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
4117 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
4118 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
4119 }
4120 if ((vars->ieee_fc &
4121 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
4122 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
4123 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
4124 }
4125 DP(NETIF_MSG_LINK,
4126 "Ext phy AN advertize cl37 0x%x\n", cl37_val);
4127
4128 bnx2x_cl45_write(bp, phy,
4129 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, cl37_val);
4130 msleep(500);
4131}
4132
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00004133static int bnx2x_8073_config_init(struct bnx2x_phy *phy,
4134 struct link_params *params,
4135 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004136{
4137 struct bnx2x *bp = params->bp;
4138 u16 val = 0, tmp1;
4139 u8 gpio_port;
4140 DP(NETIF_MSG_LINK, "Init 8073\n");
4141
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00004142 if (CHIP_IS_E2(bp))
4143 gpio_port = BP_PATH(bp);
4144 else
4145 gpio_port = params->port;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004146 /* Restore normal power mode*/
4147 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004148 MISC_REGISTERS_GPIO_OUTPUT_HIGH, gpio_port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004149
4150 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004151 MISC_REGISTERS_GPIO_OUTPUT_HIGH, gpio_port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004152
4153 /* enable LASI */
4154 bnx2x_cl45_write(bp, phy,
4155 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL, (1<<2));
4156 bnx2x_cl45_write(bp, phy,
4157 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x0004);
4158
4159 bnx2x_8073_set_pause_cl37(params, phy, vars);
4160
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004161 bnx2x_cl45_read(bp, phy,
4162 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &tmp1);
4163
4164 bnx2x_cl45_read(bp, phy,
4165 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &tmp1);
4166
4167 DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1): 0x%x\n", tmp1);
4168
Yaniv Rosner74d7a112011-01-18 04:33:18 +00004169 /* Swap polarity if required - Must be done only in non-1G mode */
4170 if (params->lane_config & PORT_HW_CFG_SWAP_PHY_POLARITY_ENABLED) {
4171 /* Configure the 8073 to swap _P and _N of the KR lines */
4172 DP(NETIF_MSG_LINK, "Swapping polarity for the 8073\n");
4173 /* 10G Rx/Tx and 1G Tx signal polarity swap */
4174 bnx2x_cl45_read(bp, phy,
4175 MDIO_PMA_DEVAD,
4176 MDIO_PMA_REG_8073_OPT_DIGITAL_CTRL, &val);
4177 bnx2x_cl45_write(bp, phy,
4178 MDIO_PMA_DEVAD,
4179 MDIO_PMA_REG_8073_OPT_DIGITAL_CTRL,
4180 (val | (3<<9)));
4181 }
4182
4183
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004184 /* Enable CL37 BAM */
Yaniv Rosner121839b2010-11-01 05:32:38 +00004185 if (REG_RD(bp, params->shmem_base +
4186 offsetof(struct shmem_region, dev_info.
4187 port_hw_config[params->port].default_cfg)) &
4188 PORT_HW_CFG_ENABLE_BAM_ON_KR_ENABLED) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004189
Yaniv Rosner121839b2010-11-01 05:32:38 +00004190 bnx2x_cl45_read(bp, phy,
4191 MDIO_AN_DEVAD,
4192 MDIO_AN_REG_8073_BAM, &val);
4193 bnx2x_cl45_write(bp, phy,
4194 MDIO_AN_DEVAD,
4195 MDIO_AN_REG_8073_BAM, val | 1);
4196 DP(NETIF_MSG_LINK, "Enable CL37 BAM on KR\n");
4197 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004198 if (params->loopback_mode == LOOPBACK_EXT) {
4199 bnx2x_807x_force_10G(bp, phy);
4200 DP(NETIF_MSG_LINK, "Forced speed 10G on 807X\n");
4201 return 0;
4202 } else {
4203 bnx2x_cl45_write(bp, phy,
4204 MDIO_PMA_DEVAD, MDIO_PMA_REG_BCM_CTRL, 0x0002);
4205 }
4206 if (phy->req_line_speed != SPEED_AUTO_NEG) {
4207 if (phy->req_line_speed == SPEED_10000) {
4208 val = (1<<7);
4209 } else if (phy->req_line_speed == SPEED_2500) {
4210 val = (1<<5);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004211 /*
4212 * Note that 2.5G works only when used with 1G
Lucas De Marchi25985ed2011-03-30 22:57:33 -03004213 * advertisement
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004214 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004215 } else
4216 val = (1<<5);
4217 } else {
4218 val = 0;
4219 if (phy->speed_cap_mask &
4220 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
4221 val |= (1<<7);
4222
Lucas De Marchi25985ed2011-03-30 22:57:33 -03004223 /* Note that 2.5G works only when used with 1G advertisement */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004224 if (phy->speed_cap_mask &
4225 (PORT_HW_CFG_SPEED_CAPABILITY_D0_1G |
4226 PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G))
4227 val |= (1<<5);
4228 DP(NETIF_MSG_LINK, "807x autoneg val = 0x%x\n", val);
4229 }
4230
4231 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV, val);
4232 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_8073_2_5G, &tmp1);
4233
4234 if (((phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G) &&
4235 (phy->req_line_speed == SPEED_AUTO_NEG)) ||
4236 (phy->req_line_speed == SPEED_2500)) {
4237 u16 phy_ver;
4238 /* Allow 2.5G for A1 and above */
4239 bnx2x_cl45_read(bp, phy,
4240 MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_CHIP_REV,
4241 &phy_ver);
4242 DP(NETIF_MSG_LINK, "Add 2.5G\n");
4243 if (phy_ver > 0)
4244 tmp1 |= 1;
4245 else
4246 tmp1 &= 0xfffe;
4247 } else {
4248 DP(NETIF_MSG_LINK, "Disable 2.5G\n");
4249 tmp1 &= 0xfffe;
4250 }
4251
4252 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_8073_2_5G, tmp1);
4253 /* Add support for CL37 (passive mode) II */
4254
4255 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, &tmp1);
4256 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD,
4257 (tmp1 | ((phy->req_duplex == DUPLEX_FULL) ?
4258 0x20 : 0x40)));
4259
4260 /* Add support for CL37 (passive mode) III */
4261 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
4262
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004263 /*
4264 * The SNR will improve about 2db by changing BW and FEE main
4265 * tap. Rest commands are executed after link is up
4266 * Change FFE main cursor to 5 in EDC register
4267 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004268 if (bnx2x_8073_is_snr_needed(bp, phy))
4269 bnx2x_cl45_write(bp, phy,
4270 MDIO_PMA_DEVAD, MDIO_PMA_REG_EDC_FFE_MAIN,
4271 0xFB0C);
4272
4273 /* Enable FEC (Forware Error Correction) Request in the AN */
4274 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV2, &tmp1);
4275 tmp1 |= (1<<15);
4276 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV2, tmp1);
4277
4278 bnx2x_ext_phy_set_pause(params, phy, vars);
4279
4280 /* Restart autoneg */
4281 msleep(500);
4282 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
4283 DP(NETIF_MSG_LINK, "807x Autoneg Restart: Advertise 1G=%x, 10G=%x\n",
4284 ((val & (1<<5)) > 0), ((val & (1<<7)) > 0));
4285 return 0;
4286}
4287
4288static u8 bnx2x_8073_read_status(struct bnx2x_phy *phy,
4289 struct link_params *params,
4290 struct link_vars *vars)
4291{
4292 struct bnx2x *bp = params->bp;
4293 u8 link_up = 0;
4294 u16 val1, val2;
4295 u16 link_status = 0;
4296 u16 an1000_status = 0;
4297
4298 bnx2x_cl45_read(bp, phy,
4299 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
4300
4301 DP(NETIF_MSG_LINK, "8703 LASI status 0x%x\n", val1);
4302
4303 /* clear the interrupt LASI status register */
4304 bnx2x_cl45_read(bp, phy,
4305 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val2);
4306 bnx2x_cl45_read(bp, phy,
4307 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val1);
4308 DP(NETIF_MSG_LINK, "807x PCS status 0x%x->0x%x\n", val2, val1);
4309 /* Clear MSG-OUT */
4310 bnx2x_cl45_read(bp, phy,
4311 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &val1);
4312
4313 /* Check the LASI */
4314 bnx2x_cl45_read(bp, phy,
4315 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &val2);
4316
4317 DP(NETIF_MSG_LINK, "KR 0x9003 0x%x\n", val2);
4318
4319 /* Check the link status */
4320 bnx2x_cl45_read(bp, phy,
4321 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val2);
4322 DP(NETIF_MSG_LINK, "KR PCS status 0x%x\n", val2);
4323
4324 bnx2x_cl45_read(bp, phy,
4325 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
4326 bnx2x_cl45_read(bp, phy,
4327 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
4328 link_up = ((val1 & 4) == 4);
4329 DP(NETIF_MSG_LINK, "PMA_REG_STATUS=0x%x\n", val1);
4330
4331 if (link_up &&
4332 ((phy->req_line_speed != SPEED_10000))) {
4333 if (bnx2x_8073_xaui_wa(bp, phy) != 0)
4334 return 0;
4335 }
4336 bnx2x_cl45_read(bp, phy,
4337 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &an1000_status);
4338 bnx2x_cl45_read(bp, phy,
4339 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &an1000_status);
4340
4341 /* Check the link status on 1.1.2 */
4342 bnx2x_cl45_read(bp, phy,
4343 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
4344 bnx2x_cl45_read(bp, phy,
4345 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
4346 DP(NETIF_MSG_LINK, "KR PMA status 0x%x->0x%x,"
4347 "an_link_status=0x%x\n", val2, val1, an1000_status);
4348
4349 link_up = (((val1 & 4) == 4) || (an1000_status & (1<<1)));
4350 if (link_up && bnx2x_8073_is_snr_needed(bp, phy)) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004351 /*
4352 * The SNR will improve about 2dbby changing the BW and FEE main
4353 * tap. The 1st write to change FFE main tap is set before
4354 * restart AN. Change PLL Bandwidth in EDC register
4355 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004356 bnx2x_cl45_write(bp, phy,
4357 MDIO_PMA_DEVAD, MDIO_PMA_REG_PLL_BANDWIDTH,
4358 0x26BC);
4359
4360 /* Change CDR Bandwidth in EDC register */
4361 bnx2x_cl45_write(bp, phy,
4362 MDIO_PMA_DEVAD, MDIO_PMA_REG_CDR_BANDWIDTH,
4363 0x0333);
4364 }
4365 bnx2x_cl45_read(bp, phy,
4366 MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
4367 &link_status);
4368
4369 /* Bits 0..2 --> speed detected, bits 13..15--> link is down */
4370 if ((link_status & (1<<2)) && (!(link_status & (1<<15)))) {
4371 link_up = 1;
4372 vars->line_speed = SPEED_10000;
4373 DP(NETIF_MSG_LINK, "port %x: External link up in 10G\n",
4374 params->port);
4375 } else if ((link_status & (1<<1)) && (!(link_status & (1<<14)))) {
4376 link_up = 1;
4377 vars->line_speed = SPEED_2500;
4378 DP(NETIF_MSG_LINK, "port %x: External link up in 2.5G\n",
4379 params->port);
4380 } else if ((link_status & (1<<0)) && (!(link_status & (1<<13)))) {
4381 link_up = 1;
4382 vars->line_speed = SPEED_1000;
4383 DP(NETIF_MSG_LINK, "port %x: External link up in 1G\n",
4384 params->port);
4385 } else {
4386 link_up = 0;
4387 DP(NETIF_MSG_LINK, "port %x: External link is down\n",
4388 params->port);
4389 }
4390
4391 if (link_up) {
Yaniv Rosner74d7a112011-01-18 04:33:18 +00004392 /* Swap polarity if required */
4393 if (params->lane_config &
4394 PORT_HW_CFG_SWAP_PHY_POLARITY_ENABLED) {
4395 /* Configure the 8073 to swap P and N of the KR lines */
4396 bnx2x_cl45_read(bp, phy,
4397 MDIO_XS_DEVAD,
4398 MDIO_XS_REG_8073_RX_CTRL_PCIE, &val1);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004399 /*
4400 * Set bit 3 to invert Rx in 1G mode and clear this bit
4401 * when it`s in 10G mode.
4402 */
Yaniv Rosner74d7a112011-01-18 04:33:18 +00004403 if (vars->line_speed == SPEED_1000) {
4404 DP(NETIF_MSG_LINK, "Swapping 1G polarity for"
4405 "the 8073\n");
4406 val1 |= (1<<3);
4407 } else
4408 val1 &= ~(1<<3);
4409
4410 bnx2x_cl45_write(bp, phy,
4411 MDIO_XS_DEVAD,
4412 MDIO_XS_REG_8073_RX_CTRL_PCIE,
4413 val1);
4414 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004415 bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
4416 bnx2x_8073_resolve_fc(phy, params, vars);
Yaniv Rosner791f18c2011-01-18 04:33:42 +00004417 vars->duplex = DUPLEX_FULL;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004418 }
4419 return link_up;
4420}
4421
4422static void bnx2x_8073_link_reset(struct bnx2x_phy *phy,
4423 struct link_params *params)
4424{
4425 struct bnx2x *bp = params->bp;
4426 u8 gpio_port;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00004427 if (CHIP_IS_E2(bp))
4428 gpio_port = BP_PATH(bp);
4429 else
4430 gpio_port = params->port;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004431 DP(NETIF_MSG_LINK, "Setting 8073 port %d into low power mode\n",
4432 gpio_port);
4433 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004434 MISC_REGISTERS_GPIO_OUTPUT_LOW,
4435 gpio_port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004436}
4437
4438/******************************************************************/
4439/* BCM8705 PHY SECTION */
4440/******************************************************************/
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00004441static int bnx2x_8705_config_init(struct bnx2x_phy *phy,
4442 struct link_params *params,
4443 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004444{
4445 struct bnx2x *bp = params->bp;
4446 DP(NETIF_MSG_LINK, "init 8705\n");
4447 /* Restore normal power mode*/
4448 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004449 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004450 /* HW reset */
4451 bnx2x_ext_phy_hw_reset(bp, params->port);
4452 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0xa040);
Yaniv Rosner6d870c32011-01-31 04:22:20 +00004453 bnx2x_wait_reset_complete(bp, phy, params);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004454
4455 bnx2x_cl45_write(bp, phy,
4456 MDIO_PMA_DEVAD, MDIO_PMA_REG_MISC_CTRL, 0x8288);
4457 bnx2x_cl45_write(bp, phy,
4458 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, 0x7fbf);
4459 bnx2x_cl45_write(bp, phy,
4460 MDIO_PMA_DEVAD, MDIO_PMA_REG_CMU_PLL_BYPASS, 0x0100);
4461 bnx2x_cl45_write(bp, phy,
4462 MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_CNTL, 0x1);
4463 /* BCM8705 doesn't have microcode, hence the 0 */
4464 bnx2x_save_spirom_version(bp, params->port, params->shmem_base, 0);
4465 return 0;
4466}
4467
4468static u8 bnx2x_8705_read_status(struct bnx2x_phy *phy,
4469 struct link_params *params,
4470 struct link_vars *vars)
4471{
4472 u8 link_up = 0;
4473 u16 val1, rx_sd;
4474 struct bnx2x *bp = params->bp;
4475 DP(NETIF_MSG_LINK, "read status 8705\n");
4476 bnx2x_cl45_read(bp, phy,
4477 MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_STATUS, &val1);
4478 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
4479
4480 bnx2x_cl45_read(bp, phy,
4481 MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_STATUS, &val1);
4482 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
4483
4484 bnx2x_cl45_read(bp, phy,
4485 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD, &rx_sd);
4486
4487 bnx2x_cl45_read(bp, phy,
4488 MDIO_PMA_DEVAD, 0xc809, &val1);
4489 bnx2x_cl45_read(bp, phy,
4490 MDIO_PMA_DEVAD, 0xc809, &val1);
4491
4492 DP(NETIF_MSG_LINK, "8705 1.c809 val=0x%x\n", val1);
4493 link_up = ((rx_sd & 0x1) && (val1 & (1<<9)) && ((val1 & (1<<8)) == 0));
4494 if (link_up) {
4495 vars->line_speed = SPEED_10000;
4496 bnx2x_ext_phy_resolve_fc(phy, params, vars);
4497 }
4498 return link_up;
4499}
4500
4501/******************************************************************/
4502/* SFP+ module Section */
4503/******************************************************************/
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00004504static u8 bnx2x_get_gpio_port(struct link_params *params)
4505{
4506 u8 gpio_port;
4507 u32 swap_val, swap_override;
4508 struct bnx2x *bp = params->bp;
4509 if (CHIP_IS_E2(bp))
4510 gpio_port = BP_PATH(bp);
4511 else
4512 gpio_port = params->port;
4513 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
4514 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
4515 return gpio_port ^ (swap_val && swap_override);
4516}
4517static void bnx2x_sfp_set_transmitter(struct link_params *params,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004518 struct bnx2x_phy *phy,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004519 u8 tx_en)
4520{
4521 u16 val;
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00004522 u8 port = params->port;
4523 struct bnx2x *bp = params->bp;
4524 u32 tx_en_mode;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004525
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004526 /* Disable/Enable transmitter ( TX laser of the SFP+ module.)*/
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00004527 tx_en_mode = REG_RD(bp, params->shmem_base +
4528 offsetof(struct shmem_region,
4529 dev_info.port_hw_config[port].sfp_ctrl)) &
4530 PORT_HW_CFG_TX_LASER_MASK;
4531 DP(NETIF_MSG_LINK, "Setting transmitter tx_en=%x for port %x "
4532 "mode = %x\n", tx_en, port, tx_en_mode);
4533 switch (tx_en_mode) {
4534 case PORT_HW_CFG_TX_LASER_MDIO:
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004535
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00004536 bnx2x_cl45_read(bp, phy,
4537 MDIO_PMA_DEVAD,
4538 MDIO_PMA_REG_PHY_IDENTIFIER,
4539 &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004540
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00004541 if (tx_en)
4542 val &= ~(1<<15);
4543 else
4544 val |= (1<<15);
4545
4546 bnx2x_cl45_write(bp, phy,
4547 MDIO_PMA_DEVAD,
4548 MDIO_PMA_REG_PHY_IDENTIFIER,
4549 val);
4550 break;
4551 case PORT_HW_CFG_TX_LASER_GPIO0:
4552 case PORT_HW_CFG_TX_LASER_GPIO1:
4553 case PORT_HW_CFG_TX_LASER_GPIO2:
4554 case PORT_HW_CFG_TX_LASER_GPIO3:
4555 {
4556 u16 gpio_pin;
4557 u8 gpio_port, gpio_mode;
4558 if (tx_en)
4559 gpio_mode = MISC_REGISTERS_GPIO_OUTPUT_HIGH;
4560 else
4561 gpio_mode = MISC_REGISTERS_GPIO_OUTPUT_LOW;
4562
4563 gpio_pin = tx_en_mode - PORT_HW_CFG_TX_LASER_GPIO0;
4564 gpio_port = bnx2x_get_gpio_port(params);
4565 bnx2x_set_gpio(bp, gpio_pin, gpio_mode, gpio_port);
4566 break;
4567 }
4568 default:
4569 DP(NETIF_MSG_LINK, "Invalid TX_LASER_MDIO 0x%x\n", tx_en_mode);
4570 break;
4571 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004572}
4573
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00004574static int bnx2x_8726_read_sfp_module_eeprom(struct bnx2x_phy *phy,
4575 struct link_params *params,
4576 u16 addr, u8 byte_cnt, u8 *o_buf)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004577{
4578 struct bnx2x *bp = params->bp;
4579 u16 val = 0;
4580 u16 i;
4581 if (byte_cnt > 16) {
4582 DP(NETIF_MSG_LINK, "Reading from eeprom is"
4583 " is limited to 0xf\n");
4584 return -EINVAL;
4585 }
4586 /* Set the read command byte count */
4587 bnx2x_cl45_write(bp, phy,
4588 MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004589 (byte_cnt | 0xa000));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004590
4591 /* Set the read command address */
4592 bnx2x_cl45_write(bp, phy,
4593 MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004594 addr);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004595
4596 /* Activate read command */
4597 bnx2x_cl45_write(bp, phy,
4598 MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004599 0x2c0f);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004600
4601 /* Wait up to 500us for command complete status */
4602 for (i = 0; i < 100; i++) {
4603 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004604 MDIO_PMA_DEVAD,
4605 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004606 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
4607 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
4608 break;
4609 udelay(5);
4610 }
4611
4612 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
4613 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
4614 DP(NETIF_MSG_LINK,
4615 "Got bad status 0x%x when reading from SFP+ EEPROM\n",
4616 (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
4617 return -EINVAL;
4618 }
4619
4620 /* Read the buffer */
4621 for (i = 0; i < byte_cnt; i++) {
4622 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004623 MDIO_PMA_DEVAD,
4624 MDIO_PMA_REG_8726_TWO_WIRE_DATA_BUF + i, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004625 o_buf[i] = (u8)(val & MDIO_PMA_REG_8726_TWO_WIRE_DATA_MASK);
4626 }
4627
4628 for (i = 0; i < 100; i++) {
4629 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004630 MDIO_PMA_DEVAD,
4631 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004632 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
4633 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
Joe Perches6f38ad92010-11-14 17:04:31 +00004634 return 0;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004635 msleep(1);
4636 }
4637 return -EINVAL;
4638}
4639
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00004640static int bnx2x_8727_read_sfp_module_eeprom(struct bnx2x_phy *phy,
4641 struct link_params *params,
4642 u16 addr, u8 byte_cnt, u8 *o_buf)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004643{
4644 struct bnx2x *bp = params->bp;
4645 u16 val, i;
4646
4647 if (byte_cnt > 16) {
4648 DP(NETIF_MSG_LINK, "Reading from eeprom is"
4649 " is limited to 0xf\n");
4650 return -EINVAL;
4651 }
4652
4653 /* Need to read from 1.8000 to clear it */
4654 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004655 MDIO_PMA_DEVAD,
4656 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
4657 &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004658
4659 /* Set the read command byte count */
4660 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004661 MDIO_PMA_DEVAD,
4662 MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
4663 ((byte_cnt < 2) ? 2 : byte_cnt));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004664
4665 /* Set the read command address */
4666 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004667 MDIO_PMA_DEVAD,
4668 MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
4669 addr);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004670 /* Set the destination address */
4671 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004672 MDIO_PMA_DEVAD,
4673 0x8004,
4674 MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004675
4676 /* Activate read command */
4677 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004678 MDIO_PMA_DEVAD,
4679 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
4680 0x8002);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004681 /*
4682 * Wait appropriate time for two-wire command to finish before
4683 * polling the status register
4684 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004685 msleep(1);
4686
4687 /* Wait up to 500us for command complete status */
4688 for (i = 0; i < 100; i++) {
4689 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004690 MDIO_PMA_DEVAD,
4691 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004692 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
4693 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
4694 break;
4695 udelay(5);
4696 }
4697
4698 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
4699 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
4700 DP(NETIF_MSG_LINK,
4701 "Got bad status 0x%x when reading from SFP+ EEPROM\n",
4702 (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
Yaniv Rosner65a001b2011-01-31 04:22:03 +00004703 return -EFAULT;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004704 }
4705
4706 /* Read the buffer */
4707 for (i = 0; i < byte_cnt; i++) {
4708 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004709 MDIO_PMA_DEVAD,
4710 MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF + i, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004711 o_buf[i] = (u8)(val & MDIO_PMA_REG_8727_TWO_WIRE_DATA_MASK);
4712 }
4713
4714 for (i = 0; i < 100; i++) {
4715 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004716 MDIO_PMA_DEVAD,
4717 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004718 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
4719 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
Joe Perches6f38ad92010-11-14 17:04:31 +00004720 return 0;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004721 msleep(1);
4722 }
4723
4724 return -EINVAL;
4725}
4726
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00004727int bnx2x_read_sfp_module_eeprom(struct bnx2x_phy *phy,
4728 struct link_params *params, u16 addr,
4729 u8 byte_cnt, u8 *o_buf)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004730{
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00004731 int rc = -EINVAL;
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00004732 switch (phy->type) {
4733 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
4734 rc = bnx2x_8726_read_sfp_module_eeprom(phy, params, addr,
4735 byte_cnt, o_buf);
4736 break;
4737 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
4738 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722:
4739 rc = bnx2x_8727_read_sfp_module_eeprom(phy, params, addr,
4740 byte_cnt, o_buf);
4741 break;
4742 }
4743 return rc;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004744}
4745
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00004746static int bnx2x_get_edc_mode(struct bnx2x_phy *phy,
4747 struct link_params *params,
4748 u16 *edc_mode)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004749{
4750 struct bnx2x *bp = params->bp;
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00004751 u32 sync_offset = 0, phy_idx, media_types;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004752 u8 val, check_limiting_mode = 0;
4753 *edc_mode = EDC_MODE_LIMITING;
4754
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00004755 phy->media_type = ETH_PHY_UNSPECIFIED;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004756 /* First check for copper cable */
4757 if (bnx2x_read_sfp_module_eeprom(phy,
4758 params,
4759 SFP_EEPROM_CON_TYPE_ADDR,
4760 1,
4761 &val) != 0) {
4762 DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM\n");
4763 return -EINVAL;
4764 }
4765
4766 switch (val) {
4767 case SFP_EEPROM_CON_TYPE_VAL_COPPER:
4768 {
4769 u8 copper_module_type;
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00004770 phy->media_type = ETH_PHY_DA_TWINAX;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004771 /*
4772 * Check if its active cable (includes SFP+ module)
4773 * of passive cable
4774 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004775 if (bnx2x_read_sfp_module_eeprom(phy,
4776 params,
4777 SFP_EEPROM_FC_TX_TECH_ADDR,
4778 1,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00004779 &copper_module_type) != 0) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004780 DP(NETIF_MSG_LINK,
4781 "Failed to read copper-cable-type"
4782 " from SFP+ EEPROM\n");
4783 return -EINVAL;
4784 }
4785
4786 if (copper_module_type &
4787 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE) {
4788 DP(NETIF_MSG_LINK, "Active Copper cable detected\n");
4789 check_limiting_mode = 1;
4790 } else if (copper_module_type &
4791 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE) {
4792 DP(NETIF_MSG_LINK, "Passive Copper"
4793 " cable detected\n");
4794 *edc_mode =
4795 EDC_MODE_PASSIVE_DAC;
4796 } else {
4797 DP(NETIF_MSG_LINK, "Unknown copper-cable-"
4798 "type 0x%x !!!\n", copper_module_type);
4799 return -EINVAL;
4800 }
4801 break;
4802 }
4803 case SFP_EEPROM_CON_TYPE_VAL_LC:
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00004804 phy->media_type = ETH_PHY_SFP_FIBER;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004805 DP(NETIF_MSG_LINK, "Optic module detected\n");
4806 check_limiting_mode = 1;
4807 break;
4808 default:
4809 DP(NETIF_MSG_LINK, "Unable to determine module type 0x%x !!!\n",
4810 val);
4811 return -EINVAL;
4812 }
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00004813 sync_offset = params->shmem_base +
4814 offsetof(struct shmem_region,
4815 dev_info.port_hw_config[params->port].media_type);
4816 media_types = REG_RD(bp, sync_offset);
4817 /* Update media type for non-PMF sync */
4818 for (phy_idx = INT_PHY; phy_idx < MAX_PHYS; phy_idx++) {
4819 if (&(params->phy[phy_idx]) == phy) {
4820 media_types &= ~(PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK <<
4821 (PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT * phy_idx));
4822 media_types |= ((phy->media_type &
4823 PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK) <<
4824 (PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT * phy_idx));
4825 break;
4826 }
4827 }
4828 REG_WR(bp, sync_offset, media_types);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004829 if (check_limiting_mode) {
4830 u8 options[SFP_EEPROM_OPTIONS_SIZE];
4831 if (bnx2x_read_sfp_module_eeprom(phy,
4832 params,
4833 SFP_EEPROM_OPTIONS_ADDR,
4834 SFP_EEPROM_OPTIONS_SIZE,
4835 options) != 0) {
4836 DP(NETIF_MSG_LINK, "Failed to read Option"
4837 " field from module EEPROM\n");
4838 return -EINVAL;
4839 }
4840 if ((options[0] & SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK))
4841 *edc_mode = EDC_MODE_LINEAR;
4842 else
4843 *edc_mode = EDC_MODE_LIMITING;
4844 }
4845 DP(NETIF_MSG_LINK, "EDC mode is set to 0x%x\n", *edc_mode);
4846 return 0;
4847}
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004848/*
4849 * This function read the relevant field from the module (SFP+), and verify it
4850 * is compliant with this board
4851 */
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00004852static int bnx2x_verify_sfp_module(struct bnx2x_phy *phy,
4853 struct link_params *params)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004854{
4855 struct bnx2x *bp = params->bp;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004856 u32 val, cmd;
4857 u32 fw_resp, fw_cmd_param;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004858 char vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE+1];
4859 char vendor_pn[SFP_EEPROM_PART_NO_SIZE+1];
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004860 phy->flags &= ~FLAGS_SFP_NOT_APPROVED;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004861 val = REG_RD(bp, params->shmem_base +
4862 offsetof(struct shmem_region, dev_info.
4863 port_feature_config[params->port].config));
4864 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
4865 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_NO_ENFORCEMENT) {
4866 DP(NETIF_MSG_LINK, "NOT enforcing module verification\n");
4867 return 0;
4868 }
4869
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004870 if (params->feature_config_flags &
4871 FEATURE_CONFIG_BC_SUPPORTS_DUAL_PHY_OPT_MDL_VRFY) {
4872 /* Use specific phy request */
4873 cmd = DRV_MSG_CODE_VRFY_SPECIFIC_PHY_OPT_MDL;
4874 } else if (params->feature_config_flags &
4875 FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY) {
4876 /* Use first phy request only in case of non-dual media*/
4877 if (DUAL_MEDIA(params)) {
4878 DP(NETIF_MSG_LINK, "FW does not support OPT MDL "
4879 "verification\n");
4880 return -EINVAL;
4881 }
4882 cmd = DRV_MSG_CODE_VRFY_FIRST_PHY_OPT_MDL;
4883 } else {
4884 /* No support in OPT MDL detection */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004885 DP(NETIF_MSG_LINK, "FW does not support OPT MDL "
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004886 "verification\n");
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004887 return -EINVAL;
4888 }
Dmitry Kravkov523224a2010-10-06 03:23:26 +00004889
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004890 fw_cmd_param = FW_PARAM_SET(phy->addr, phy->type, phy->mdio_ctrl);
4891 fw_resp = bnx2x_fw_command(bp, cmd, fw_cmd_param);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004892 if (fw_resp == FW_MSG_CODE_VRFY_OPT_MDL_SUCCESS) {
4893 DP(NETIF_MSG_LINK, "Approved module\n");
4894 return 0;
4895 }
4896
4897 /* format the warning message */
4898 if (bnx2x_read_sfp_module_eeprom(phy,
4899 params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004900 SFP_EEPROM_VENDOR_NAME_ADDR,
4901 SFP_EEPROM_VENDOR_NAME_SIZE,
4902 (u8 *)vendor_name))
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004903 vendor_name[0] = '\0';
4904 else
4905 vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE] = '\0';
4906 if (bnx2x_read_sfp_module_eeprom(phy,
4907 params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004908 SFP_EEPROM_PART_NO_ADDR,
4909 SFP_EEPROM_PART_NO_SIZE,
4910 (u8 *)vendor_pn))
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004911 vendor_pn[0] = '\0';
4912 else
4913 vendor_pn[SFP_EEPROM_PART_NO_SIZE] = '\0';
4914
Yaniv Rosner6d870c32011-01-31 04:22:20 +00004915 netdev_err(bp->dev, "Warning: Unqualified SFP+ module detected,"
4916 " Port %d from %s part number %s\n",
4917 params->port, vendor_name, vendor_pn);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004918 phy->flags |= FLAGS_SFP_NOT_APPROVED;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004919 return -EINVAL;
4920}
4921
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00004922static int bnx2x_wait_for_sfp_module_initialized(struct bnx2x_phy *phy,
4923 struct link_params *params)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004924
4925{
4926 u8 val;
4927 struct bnx2x *bp = params->bp;
4928 u16 timeout;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004929 /*
4930 * Initialization time after hot-plug may take up to 300ms for
4931 * some phys type ( e.g. JDSU )
4932 */
4933
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004934 for (timeout = 0; timeout < 60; timeout++) {
4935 if (bnx2x_read_sfp_module_eeprom(phy, params, 1, 1, &val)
4936 == 0) {
4937 DP(NETIF_MSG_LINK, "SFP+ module initialization "
4938 "took %d ms\n", timeout * 5);
4939 return 0;
4940 }
4941 msleep(5);
4942 }
4943 return -EINVAL;
4944}
4945
4946static void bnx2x_8727_power_module(struct bnx2x *bp,
4947 struct bnx2x_phy *phy,
4948 u8 is_power_up) {
4949 /* Make sure GPIOs are not using for LED mode */
4950 u16 val;
4951 /*
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004952 * In the GPIO register, bit 4 is use to determine if the GPIOs are
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004953 * operating as INPUT or as OUTPUT. Bit 1 is for input, and 0 for
4954 * output
4955 * Bits 0-1 determine the gpios value for OUTPUT in case bit 4 val is 0
4956 * Bits 8-9 determine the gpios value for INPUT in case bit 4 val is 1
4957 * where the 1st bit is the over-current(only input), and 2nd bit is
4958 * for power( only output )
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004959 *
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004960 * In case of NOC feature is disabled and power is up, set GPIO control
4961 * as input to enable listening of over-current indication
4962 */
4963 if (phy->flags & FLAGS_NOC)
4964 return;
Yaniv Rosner27d02432011-05-31 21:27:48 +00004965 if (is_power_up)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004966 val = (1<<4);
4967 else
4968 /*
4969 * Set GPIO control to OUTPUT, and set the power bit
4970 * to according to the is_power_up
4971 */
Yaniv Rosner27d02432011-05-31 21:27:48 +00004972 val = (1<<1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004973
4974 bnx2x_cl45_write(bp, phy,
4975 MDIO_PMA_DEVAD,
4976 MDIO_PMA_REG_8727_GPIO_CTRL,
4977 val);
4978}
4979
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00004980static int bnx2x_8726_set_limiting_mode(struct bnx2x *bp,
4981 struct bnx2x_phy *phy,
4982 u16 edc_mode)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004983{
4984 u16 cur_limiting_mode;
4985
4986 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004987 MDIO_PMA_DEVAD,
4988 MDIO_PMA_REG_ROM_VER2,
4989 &cur_limiting_mode);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004990 DP(NETIF_MSG_LINK, "Current Limiting mode is 0x%x\n",
4991 cur_limiting_mode);
4992
4993 if (edc_mode == EDC_MODE_LIMITING) {
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004994 DP(NETIF_MSG_LINK, "Setting LIMITING MODE\n");
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004995 bnx2x_cl45_write(bp, phy,
4996 MDIO_PMA_DEVAD,
4997 MDIO_PMA_REG_ROM_VER2,
4998 EDC_MODE_LIMITING);
4999 } else { /* LRM mode ( default )*/
5000
5001 DP(NETIF_MSG_LINK, "Setting LRM MODE\n");
5002
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005003 /*
5004 * Changing to LRM mode takes quite few seconds. So do it only
5005 * if current mode is limiting (default is LRM)
5006 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005007 if (cur_limiting_mode != EDC_MODE_LIMITING)
5008 return 0;
5009
5010 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005011 MDIO_PMA_DEVAD,
5012 MDIO_PMA_REG_LRM_MODE,
5013 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005014 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005015 MDIO_PMA_DEVAD,
5016 MDIO_PMA_REG_ROM_VER2,
5017 0x128);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005018 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005019 MDIO_PMA_DEVAD,
5020 MDIO_PMA_REG_MISC_CTRL0,
5021 0x4008);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005022 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005023 MDIO_PMA_DEVAD,
5024 MDIO_PMA_REG_LRM_MODE,
5025 0xaaaa);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005026 }
5027 return 0;
5028}
5029
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005030static int bnx2x_8727_set_limiting_mode(struct bnx2x *bp,
5031 struct bnx2x_phy *phy,
5032 u16 edc_mode)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005033{
5034 u16 phy_identifier;
5035 u16 rom_ver2_val;
5036 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005037 MDIO_PMA_DEVAD,
5038 MDIO_PMA_REG_PHY_IDENTIFIER,
5039 &phy_identifier);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005040
5041 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005042 MDIO_PMA_DEVAD,
5043 MDIO_PMA_REG_PHY_IDENTIFIER,
5044 (phy_identifier & ~(1<<9)));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005045
5046 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005047 MDIO_PMA_DEVAD,
5048 MDIO_PMA_REG_ROM_VER2,
5049 &rom_ver2_val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005050 /* Keep the MSB 8-bits, and set the LSB 8-bits with the edc_mode */
5051 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005052 MDIO_PMA_DEVAD,
5053 MDIO_PMA_REG_ROM_VER2,
5054 (rom_ver2_val & 0xff00) | (edc_mode & 0x00ff));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005055
5056 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005057 MDIO_PMA_DEVAD,
5058 MDIO_PMA_REG_PHY_IDENTIFIER,
5059 (phy_identifier | (1<<9)));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005060
5061 return 0;
5062}
5063
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005064static void bnx2x_8727_specific_func(struct bnx2x_phy *phy,
5065 struct link_params *params,
5066 u32 action)
5067{
5068 struct bnx2x *bp = params->bp;
5069
5070 switch (action) {
5071 case DISABLE_TX:
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00005072 bnx2x_sfp_set_transmitter(params, phy, 0);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005073 break;
5074 case ENABLE_TX:
5075 if (!(phy->flags & FLAGS_SFP_NOT_APPROVED))
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00005076 bnx2x_sfp_set_transmitter(params, phy, 1);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005077 break;
5078 default:
5079 DP(NETIF_MSG_LINK, "Function 0x%x not supported by 8727\n",
5080 action);
5081 return;
5082 }
5083}
5084
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00005085static void bnx2x_set_sfp_module_fault_led(struct link_params *params,
5086 u8 gpio_mode)
5087{
5088 struct bnx2x *bp = params->bp;
5089
5090 u32 fault_led_gpio = REG_RD(bp, params->shmem_base +
5091 offsetof(struct shmem_region,
5092 dev_info.port_hw_config[params->port].sfp_ctrl)) &
5093 PORT_HW_CFG_FAULT_MODULE_LED_MASK;
5094 switch (fault_led_gpio) {
5095 case PORT_HW_CFG_FAULT_MODULE_LED_DISABLED:
5096 return;
5097 case PORT_HW_CFG_FAULT_MODULE_LED_GPIO0:
5098 case PORT_HW_CFG_FAULT_MODULE_LED_GPIO1:
5099 case PORT_HW_CFG_FAULT_MODULE_LED_GPIO2:
5100 case PORT_HW_CFG_FAULT_MODULE_LED_GPIO3:
5101 {
5102 u8 gpio_port = bnx2x_get_gpio_port(params);
5103 u16 gpio_pin = fault_led_gpio -
5104 PORT_HW_CFG_FAULT_MODULE_LED_GPIO0;
5105 DP(NETIF_MSG_LINK, "Set fault module-detected led "
5106 "pin %x port %x mode %x\n",
5107 gpio_pin, gpio_port, gpio_mode);
5108 bnx2x_set_gpio(bp, gpio_pin, gpio_mode, gpio_port);
5109 }
5110 break;
5111 default:
5112 DP(NETIF_MSG_LINK, "Error: Invalid fault led mode 0x%x\n",
5113 fault_led_gpio);
5114 }
5115}
5116
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00005117static void bnx2x_power_sfp_module(struct link_params *params,
5118 struct bnx2x_phy *phy,
5119 u8 power)
5120{
5121 struct bnx2x *bp = params->bp;
5122 DP(NETIF_MSG_LINK, "Setting SFP+ power to %x\n", power);
5123
5124 switch (phy->type) {
5125 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
5126 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722:
5127 bnx2x_8727_power_module(params->bp, phy, power);
5128 break;
5129 default:
5130 break;
5131 }
5132}
5133
5134static void bnx2x_set_limiting_mode(struct link_params *params,
5135 struct bnx2x_phy *phy,
5136 u16 edc_mode)
5137{
5138 switch (phy->type) {
5139 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
5140 bnx2x_8726_set_limiting_mode(params->bp, phy, edc_mode);
5141 break;
5142 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
5143 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722:
5144 bnx2x_8727_set_limiting_mode(params->bp, phy, edc_mode);
5145 break;
5146 }
5147}
5148
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005149int bnx2x_sfp_module_detection(struct bnx2x_phy *phy,
5150 struct link_params *params)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005151{
5152 struct bnx2x *bp = params->bp;
5153 u16 edc_mode;
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005154 int rc = 0;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005155
5156 u32 val = REG_RD(bp, params->shmem_base +
5157 offsetof(struct shmem_region, dev_info.
5158 port_feature_config[params->port].config));
5159
5160 DP(NETIF_MSG_LINK, "SFP+ module plugged in/out detected on port %d\n",
5161 params->port);
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00005162 /* Power up module */
5163 bnx2x_power_sfp_module(params, phy, 1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005164 if (bnx2x_get_edc_mode(phy, params, &edc_mode) != 0) {
5165 DP(NETIF_MSG_LINK, "Failed to get valid module type\n");
5166 return -EINVAL;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005167 } else if (bnx2x_verify_sfp_module(phy, params) != 0) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005168 /* check SFP+ module compatibility */
5169 DP(NETIF_MSG_LINK, "Module verification failed!!\n");
5170 rc = -EINVAL;
5171 /* Turn on fault module-detected led */
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00005172 bnx2x_set_sfp_module_fault_led(params,
5173 MISC_REGISTERS_GPIO_HIGH);
5174
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00005175 /* Check if need to power down the SFP+ module */
5176 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
5177 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_POWER_DOWN) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005178 DP(NETIF_MSG_LINK, "Shutdown SFP+ module!!\n");
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00005179 bnx2x_power_sfp_module(params, phy, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005180 return rc;
5181 }
5182 } else {
5183 /* Turn off fault module-detected led */
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00005184 bnx2x_set_sfp_module_fault_led(params, MISC_REGISTERS_GPIO_LOW);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005185 }
5186
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005187 /*
5188 * Check and set limiting mode / LRM mode on 8726. On 8727 it
5189 * is done automatically
5190 */
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00005191 bnx2x_set_limiting_mode(params, phy, edc_mode);
5192
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005193 /*
5194 * Enable transmit for this module if the module is approved, or
5195 * if unapproved modules should also enable the Tx laser
5196 */
5197 if (rc == 0 ||
5198 (val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) !=
5199 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00005200 bnx2x_sfp_set_transmitter(params, phy, 1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005201 else
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00005202 bnx2x_sfp_set_transmitter(params, phy, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005203
5204 return rc;
5205}
5206
5207void bnx2x_handle_module_detect_int(struct link_params *params)
5208{
5209 struct bnx2x *bp = params->bp;
5210 struct bnx2x_phy *phy = &params->phy[EXT_PHY1];
5211 u32 gpio_val;
5212 u8 port = params->port;
5213
5214 /* Set valid module led off */
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00005215 bnx2x_set_sfp_module_fault_led(params, MISC_REGISTERS_GPIO_HIGH);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005216
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005217 /* Get current gpio val reflecting module plugged in / out*/
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005218 gpio_val = bnx2x_get_gpio(bp, MISC_REGISTERS_GPIO_3, port);
5219
5220 /* Call the handling function in case module is detected */
5221 if (gpio_val == 0) {
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00005222 bnx2x_power_sfp_module(params, phy, 1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005223 bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
5224 MISC_REGISTERS_GPIO_INT_OUTPUT_CLR,
5225 port);
5226
5227 if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0)
5228 bnx2x_sfp_module_detection(phy, params);
5229 else
5230 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
5231 } else {
5232 u32 val = REG_RD(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005233 offsetof(struct shmem_region, dev_info.
5234 port_feature_config[params->port].
5235 config));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005236
5237 bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
5238 MISC_REGISTERS_GPIO_INT_OUTPUT_SET,
5239 port);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005240 /*
5241 * Module was plugged out.
5242 * Disable transmit for this module
5243 */
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00005244 phy->media_type = ETH_PHY_NOT_PRESENT;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005245 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
5246 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00005247 bnx2x_sfp_set_transmitter(params, phy, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005248 }
5249}
5250
5251/******************************************************************/
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00005252/* Used by 8706 and 8727 */
5253/******************************************************************/
5254static void bnx2x_sfp_mask_fault(struct bnx2x *bp,
5255 struct bnx2x_phy *phy,
5256 u16 alarm_status_offset,
5257 u16 alarm_ctrl_offset)
5258{
5259 u16 alarm_status, val;
5260 bnx2x_cl45_read(bp, phy,
5261 MDIO_PMA_DEVAD, alarm_status_offset,
5262 &alarm_status);
5263 bnx2x_cl45_read(bp, phy,
5264 MDIO_PMA_DEVAD, alarm_status_offset,
5265 &alarm_status);
5266 /* Mask or enable the fault event. */
5267 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, alarm_ctrl_offset, &val);
5268 if (alarm_status & (1<<0))
5269 val &= ~(1<<0);
5270 else
5271 val |= (1<<0);
5272 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, alarm_ctrl_offset, val);
5273}
5274/******************************************************************/
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005275/* common BCM8706/BCM8726 PHY SECTION */
5276/******************************************************************/
5277static u8 bnx2x_8706_8726_read_status(struct bnx2x_phy *phy,
5278 struct link_params *params,
5279 struct link_vars *vars)
5280{
5281 u8 link_up = 0;
5282 u16 val1, val2, rx_sd, pcs_status;
5283 struct bnx2x *bp = params->bp;
5284 DP(NETIF_MSG_LINK, "XGXS 8706/8726\n");
5285 /* Clear RX Alarm*/
5286 bnx2x_cl45_read(bp, phy,
5287 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &val2);
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00005288
5289 bnx2x_sfp_mask_fault(bp, phy, MDIO_PMA_REG_TX_ALARM,
5290 MDIO_PMA_REG_TX_ALARM_CTRL);
5291
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005292 /* clear LASI indication*/
5293 bnx2x_cl45_read(bp, phy,
5294 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
5295 bnx2x_cl45_read(bp, phy,
5296 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val2);
5297 DP(NETIF_MSG_LINK, "8706/8726 LASI status 0x%x--> 0x%x\n", val1, val2);
5298
5299 bnx2x_cl45_read(bp, phy,
5300 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD, &rx_sd);
5301 bnx2x_cl45_read(bp, phy,
5302 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &pcs_status);
5303 bnx2x_cl45_read(bp, phy,
5304 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &val2);
5305 bnx2x_cl45_read(bp, phy,
5306 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &val2);
5307
5308 DP(NETIF_MSG_LINK, "8706/8726 rx_sd 0x%x pcs_status 0x%x 1Gbps"
5309 " link_status 0x%x\n", rx_sd, pcs_status, val2);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005310 /*
5311 * link is up if both bit 0 of pmd_rx_sd and bit 0 of pcs_status
5312 * are set, or if the autoneg bit 1 is set
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005313 */
5314 link_up = ((rx_sd & pcs_status & 0x1) || (val2 & (1<<1)));
5315 if (link_up) {
5316 if (val2 & (1<<1))
5317 vars->line_speed = SPEED_1000;
5318 else
5319 vars->line_speed = SPEED_10000;
5320 bnx2x_ext_phy_resolve_fc(phy, params, vars);
Yaniv Rosner791f18c2011-01-18 04:33:42 +00005321 vars->duplex = DUPLEX_FULL;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005322 }
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00005323
5324 /* Capture 10G link fault. Read twice to clear stale value. */
5325 if (vars->line_speed == SPEED_10000) {
5326 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
5327 MDIO_PMA_REG_TX_ALARM, &val1);
5328 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
5329 MDIO_PMA_REG_TX_ALARM, &val1);
5330 if (val1 & (1<<0))
5331 vars->fault_detected = 1;
5332 }
5333
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005334 return link_up;
5335}
5336
5337/******************************************************************/
5338/* BCM8706 PHY SECTION */
5339/******************************************************************/
5340static u8 bnx2x_8706_config_init(struct bnx2x_phy *phy,
5341 struct link_params *params,
5342 struct link_vars *vars)
5343{
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00005344 u32 tx_en_mode;
5345 u16 cnt, val, tmp1;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005346 struct bnx2x *bp = params->bp;
5347 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005348 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005349 /* HW reset */
5350 bnx2x_ext_phy_hw_reset(bp, params->port);
5351 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0xa040);
Yaniv Rosner6d870c32011-01-31 04:22:20 +00005352 bnx2x_wait_reset_complete(bp, phy, params);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005353
5354 /* Wait until fw is loaded */
5355 for (cnt = 0; cnt < 100; cnt++) {
5356 bnx2x_cl45_read(bp, phy,
5357 MDIO_PMA_DEVAD, MDIO_PMA_REG_ROM_VER1, &val);
5358 if (val)
5359 break;
5360 msleep(10);
5361 }
5362 DP(NETIF_MSG_LINK, "XGXS 8706 is initialized after %d ms\n", cnt);
5363 if ((params->feature_config_flags &
5364 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
5365 u8 i;
5366 u16 reg;
5367 for (i = 0; i < 4; i++) {
5368 reg = MDIO_XS_8706_REG_BANK_RX0 +
5369 i*(MDIO_XS_8706_REG_BANK_RX1 -
5370 MDIO_XS_8706_REG_BANK_RX0);
5371 bnx2x_cl45_read(bp, phy, MDIO_XS_DEVAD, reg, &val);
5372 /* Clear first 3 bits of the control */
5373 val &= ~0x7;
5374 /* Set control bits according to configuration */
5375 val |= (phy->rx_preemphasis[i] & 0x7);
5376 DP(NETIF_MSG_LINK, "Setting RX Equalizer to BCM8706"
5377 " reg 0x%x <-- val 0x%x\n", reg, val);
5378 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, reg, val);
5379 }
5380 }
5381 /* Force speed */
5382 if (phy->req_line_speed == SPEED_10000) {
5383 DP(NETIF_MSG_LINK, "XGXS 8706 force 10Gbps\n");
5384
5385 bnx2x_cl45_write(bp, phy,
5386 MDIO_PMA_DEVAD,
5387 MDIO_PMA_REG_DIGITAL_CTRL, 0x400);
5388 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00005389 MDIO_PMA_DEVAD, MDIO_PMA_REG_TX_ALARM_CTRL,
5390 0);
5391 /* Arm LASI for link and Tx fault. */
5392 bnx2x_cl45_write(bp, phy,
5393 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 3);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005394 } else {
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005395 /* Force 1Gbps using autoneg with 1G advertisement */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005396
5397 /* Allow CL37 through CL73 */
5398 DP(NETIF_MSG_LINK, "XGXS 8706 AutoNeg\n");
5399 bnx2x_cl45_write(bp, phy,
5400 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_CL73, 0x040c);
5401
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005402 /* Enable Full-Duplex advertisement on CL37 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005403 bnx2x_cl45_write(bp, phy,
5404 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LP, 0x0020);
5405 /* Enable CL37 AN */
5406 bnx2x_cl45_write(bp, phy,
5407 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
5408 /* 1G support */
5409 bnx2x_cl45_write(bp, phy,
5410 MDIO_AN_DEVAD, MDIO_AN_REG_ADV, (1<<5));
5411
5412 /* Enable clause 73 AN */
5413 bnx2x_cl45_write(bp, phy,
5414 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
5415 bnx2x_cl45_write(bp, phy,
5416 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
5417 0x0400);
5418 bnx2x_cl45_write(bp, phy,
5419 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL,
5420 0x0004);
5421 }
5422 bnx2x_save_bcm_spirom_ver(bp, phy, params->port);
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00005423
5424 /*
5425 * If TX Laser is controlled by GPIO_0, do not let PHY go into low
5426 * power mode, if TX Laser is disabled
5427 */
5428
5429 tx_en_mode = REG_RD(bp, params->shmem_base +
5430 offsetof(struct shmem_region,
5431 dev_info.port_hw_config[params->port].sfp_ctrl))
5432 & PORT_HW_CFG_TX_LASER_MASK;
5433
5434 if (tx_en_mode == PORT_HW_CFG_TX_LASER_GPIO0) {
5435 DP(NETIF_MSG_LINK, "Enabling TXONOFF_PWRDN_DIS\n");
5436 bnx2x_cl45_read(bp, phy,
5437 MDIO_PMA_DEVAD, MDIO_PMA_REG_DIGITAL_CTRL, &tmp1);
5438 tmp1 |= 0x1;
5439 bnx2x_cl45_write(bp, phy,
5440 MDIO_PMA_DEVAD, MDIO_PMA_REG_DIGITAL_CTRL, tmp1);
5441 }
5442
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005443 return 0;
5444}
5445
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005446static int bnx2x_8706_read_status(struct bnx2x_phy *phy,
5447 struct link_params *params,
5448 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005449{
5450 return bnx2x_8706_8726_read_status(phy, params, vars);
5451}
5452
5453/******************************************************************/
5454/* BCM8726 PHY SECTION */
5455/******************************************************************/
5456static void bnx2x_8726_config_loopback(struct bnx2x_phy *phy,
5457 struct link_params *params)
5458{
5459 struct bnx2x *bp = params->bp;
5460 DP(NETIF_MSG_LINK, "PMA/PMD ext_phy_loopback: 8726\n");
5461 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x0001);
5462}
5463
5464static void bnx2x_8726_external_rom_boot(struct bnx2x_phy *phy,
5465 struct link_params *params)
5466{
5467 struct bnx2x *bp = params->bp;
5468 /* Need to wait 100ms after reset */
5469 msleep(100);
5470
5471 /* Micro controller re-boot */
5472 bnx2x_cl45_write(bp, phy,
5473 MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, 0x018B);
5474
5475 /* Set soft reset */
5476 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005477 MDIO_PMA_DEVAD,
5478 MDIO_PMA_REG_GEN_CTRL,
5479 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005480
5481 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005482 MDIO_PMA_DEVAD,
5483 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005484
5485 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005486 MDIO_PMA_DEVAD,
5487 MDIO_PMA_REG_GEN_CTRL,
5488 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005489
5490 /* wait for 150ms for microcode load */
5491 msleep(150);
5492
5493 /* Disable serial boot control, tristates pins SS_N, SCK, MOSI, MISO */
5494 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005495 MDIO_PMA_DEVAD,
5496 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005497
5498 msleep(200);
5499 bnx2x_save_bcm_spirom_ver(bp, phy, params->port);
5500}
5501
5502static u8 bnx2x_8726_read_status(struct bnx2x_phy *phy,
5503 struct link_params *params,
5504 struct link_vars *vars)
5505{
5506 struct bnx2x *bp = params->bp;
5507 u16 val1;
5508 u8 link_up = bnx2x_8706_8726_read_status(phy, params, vars);
5509 if (link_up) {
5510 bnx2x_cl45_read(bp, phy,
5511 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER,
5512 &val1);
5513 if (val1 & (1<<15)) {
5514 DP(NETIF_MSG_LINK, "Tx is disabled\n");
5515 link_up = 0;
5516 vars->line_speed = 0;
5517 }
5518 }
5519 return link_up;
5520}
5521
5522
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005523static int bnx2x_8726_config_init(struct bnx2x_phy *phy,
5524 struct link_params *params,
5525 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005526{
5527 struct bnx2x *bp = params->bp;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005528 DP(NETIF_MSG_LINK, "Initializing BCM8726\n");
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005529
5530 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
Yaniv Rosner6d870c32011-01-31 04:22:20 +00005531 bnx2x_wait_reset_complete(bp, phy, params);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005532
5533 bnx2x_8726_external_rom_boot(phy, params);
5534
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005535 /*
5536 * Need to call module detected on initialization since the module
5537 * detection triggered by actual module insertion might occur before
5538 * driver is loaded, and when driver is loaded, it reset all
5539 * registers, including the transmitter
5540 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005541 bnx2x_sfp_module_detection(phy, params);
5542
5543 if (phy->req_line_speed == SPEED_1000) {
5544 DP(NETIF_MSG_LINK, "Setting 1G force\n");
5545 bnx2x_cl45_write(bp, phy,
5546 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x40);
5547 bnx2x_cl45_write(bp, phy,
5548 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0xD);
5549 bnx2x_cl45_write(bp, phy,
5550 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x5);
5551 bnx2x_cl45_write(bp, phy,
5552 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
5553 0x400);
5554 } else if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
5555 (phy->speed_cap_mask &
5556 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G) &&
5557 ((phy->speed_cap_mask &
5558 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) !=
5559 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
5560 DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
5561 /* Set Flow control */
5562 bnx2x_ext_phy_set_pause(params, phy, vars);
5563 bnx2x_cl45_write(bp, phy,
5564 MDIO_AN_DEVAD, MDIO_AN_REG_ADV, 0x20);
5565 bnx2x_cl45_write(bp, phy,
5566 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_CL73, 0x040c);
5567 bnx2x_cl45_write(bp, phy,
5568 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, 0x0020);
5569 bnx2x_cl45_write(bp, phy,
5570 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
5571 bnx2x_cl45_write(bp, phy,
5572 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005573 /*
5574 * Enable RX-ALARM control to receive interrupt for 1G speed
5575 * change
5576 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005577 bnx2x_cl45_write(bp, phy,
5578 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x4);
5579 bnx2x_cl45_write(bp, phy,
5580 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
5581 0x400);
5582
5583 } else { /* Default 10G. Set only LASI control */
5584 bnx2x_cl45_write(bp, phy,
5585 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 1);
5586 }
5587
5588 /* Set TX PreEmphasis if needed */
5589 if ((params->feature_config_flags &
5590 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
5591 DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x,"
5592 "TX_CTRL2 0x%x\n",
5593 phy->tx_preemphasis[0],
5594 phy->tx_preemphasis[1]);
5595 bnx2x_cl45_write(bp, phy,
5596 MDIO_PMA_DEVAD,
5597 MDIO_PMA_REG_8726_TX_CTRL1,
5598 phy->tx_preemphasis[0]);
5599
5600 bnx2x_cl45_write(bp, phy,
5601 MDIO_PMA_DEVAD,
5602 MDIO_PMA_REG_8726_TX_CTRL2,
5603 phy->tx_preemphasis[1]);
5604 }
5605
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005606 return 0;
5607
5608}
5609
5610static void bnx2x_8726_link_reset(struct bnx2x_phy *phy,
5611 struct link_params *params)
5612{
5613 struct bnx2x *bp = params->bp;
5614 DP(NETIF_MSG_LINK, "bnx2x_8726_link_reset port %d\n", params->port);
5615 /* Set serial boot control for external load */
5616 bnx2x_cl45_write(bp, phy,
5617 MDIO_PMA_DEVAD,
5618 MDIO_PMA_REG_GEN_CTRL, 0x0001);
5619}
5620
5621/******************************************************************/
5622/* BCM8727 PHY SECTION */
5623/******************************************************************/
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005624
5625static void bnx2x_8727_set_link_led(struct bnx2x_phy *phy,
5626 struct link_params *params, u8 mode)
5627{
5628 struct bnx2x *bp = params->bp;
5629 u16 led_mode_bitmask = 0;
5630 u16 gpio_pins_bitmask = 0;
5631 u16 val;
5632 /* Only NOC flavor requires to set the LED specifically */
5633 if (!(phy->flags & FLAGS_NOC))
5634 return;
5635 switch (mode) {
5636 case LED_MODE_FRONT_PANEL_OFF:
5637 case LED_MODE_OFF:
5638 led_mode_bitmask = 0;
5639 gpio_pins_bitmask = 0x03;
5640 break;
5641 case LED_MODE_ON:
5642 led_mode_bitmask = 0;
5643 gpio_pins_bitmask = 0x02;
5644 break;
5645 case LED_MODE_OPER:
5646 led_mode_bitmask = 0x60;
5647 gpio_pins_bitmask = 0x11;
5648 break;
5649 }
5650 bnx2x_cl45_read(bp, phy,
5651 MDIO_PMA_DEVAD,
5652 MDIO_PMA_REG_8727_PCS_OPT_CTRL,
5653 &val);
5654 val &= 0xff8f;
5655 val |= led_mode_bitmask;
5656 bnx2x_cl45_write(bp, phy,
5657 MDIO_PMA_DEVAD,
5658 MDIO_PMA_REG_8727_PCS_OPT_CTRL,
5659 val);
5660 bnx2x_cl45_read(bp, phy,
5661 MDIO_PMA_DEVAD,
5662 MDIO_PMA_REG_8727_GPIO_CTRL,
5663 &val);
5664 val &= 0xffe0;
5665 val |= gpio_pins_bitmask;
5666 bnx2x_cl45_write(bp, phy,
5667 MDIO_PMA_DEVAD,
5668 MDIO_PMA_REG_8727_GPIO_CTRL,
5669 val);
5670}
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005671static void bnx2x_8727_hw_reset(struct bnx2x_phy *phy,
5672 struct link_params *params) {
5673 u32 swap_val, swap_override;
5674 u8 port;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005675 /*
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005676 * The PHY reset is controlled by GPIO 1. Fake the port number
5677 * to cancel the swap done in set_gpio()
5678 */
5679 struct bnx2x *bp = params->bp;
5680 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
5681 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
5682 port = (swap_val && swap_override) ^ 1;
5683 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005684 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005685}
5686
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005687static int bnx2x_8727_config_init(struct bnx2x_phy *phy,
5688 struct link_params *params,
5689 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005690{
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00005691 u32 tx_en_mode;
5692 u16 tmp1, val, mod_abs, tmp2;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005693 u16 rx_alarm_ctrl_val;
5694 u16 lasi_ctrl_val;
5695 struct bnx2x *bp = params->bp;
5696 /* Enable PMD link, MOD_ABS_FLT, and 1G link alarm */
5697
Yaniv Rosner6d870c32011-01-31 04:22:20 +00005698 bnx2x_wait_reset_complete(bp, phy, params);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005699 rx_alarm_ctrl_val = (1<<2) | (1<<5) ;
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00005700 /* Should be 0x6 to enable XS on Tx side. */
5701 lasi_ctrl_val = 0x0006;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005702
5703 DP(NETIF_MSG_LINK, "Initializing BCM8727\n");
5704 /* enable LASI */
5705 bnx2x_cl45_write(bp, phy,
5706 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
5707 rx_alarm_ctrl_val);
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00005708 bnx2x_cl45_write(bp, phy,
5709 MDIO_PMA_DEVAD, MDIO_PMA_REG_TX_ALARM_CTRL,
5710 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005711 bnx2x_cl45_write(bp, phy,
5712 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, lasi_ctrl_val);
5713
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005714 /*
5715 * Initially configure MOD_ABS to interrupt when module is
5716 * presence( bit 8)
5717 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005718 bnx2x_cl45_read(bp, phy,
5719 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005720 /*
5721 * Set EDC off by setting OPTXLOS signal input to low (bit 9).
5722 * When the EDC is off it locks onto a reference clock and avoids
5723 * becoming 'lost'
5724 */
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005725 mod_abs &= ~(1<<8);
5726 if (!(phy->flags & FLAGS_NOC))
5727 mod_abs &= ~(1<<9);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005728 bnx2x_cl45_write(bp, phy,
5729 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
5730
5731
5732 /* Make MOD_ABS give interrupt on change */
5733 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL,
5734 &val);
5735 val |= (1<<12);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005736 if (phy->flags & FLAGS_NOC)
5737 val |= (3<<5);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005738
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005739 /*
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005740 * Set 8727 GPIOs to input to allow reading from the 8727 GPIO0
5741 * status which reflect SFP+ module over-current
5742 */
5743 if (!(phy->flags & FLAGS_NOC))
5744 val &= 0xff8f; /* Reset bits 4-6 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005745 bnx2x_cl45_write(bp, phy,
5746 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL, val);
5747
5748 bnx2x_8727_power_module(bp, phy, 1);
5749
5750 bnx2x_cl45_read(bp, phy,
5751 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &tmp1);
5752
5753 bnx2x_cl45_read(bp, phy,
5754 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &tmp1);
5755
5756 /* Set option 1G speed */
5757 if (phy->req_line_speed == SPEED_1000) {
5758 DP(NETIF_MSG_LINK, "Setting 1G force\n");
5759 bnx2x_cl45_write(bp, phy,
5760 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x40);
5761 bnx2x_cl45_write(bp, phy,
5762 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0xD);
5763 bnx2x_cl45_read(bp, phy,
5764 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, &tmp1);
5765 DP(NETIF_MSG_LINK, "1.7 = 0x%x\n", tmp1);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005766 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005767 * Power down the XAUI until link is up in case of dual-media
5768 * and 1G
5769 */
5770 if (DUAL_MEDIA(params)) {
5771 bnx2x_cl45_read(bp, phy,
5772 MDIO_PMA_DEVAD,
5773 MDIO_PMA_REG_8727_PCS_GP, &val);
5774 val |= (3<<10);
5775 bnx2x_cl45_write(bp, phy,
5776 MDIO_PMA_DEVAD,
5777 MDIO_PMA_REG_8727_PCS_GP, val);
5778 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005779 } else if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
5780 ((phy->speed_cap_mask &
5781 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) &&
5782 ((phy->speed_cap_mask &
5783 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) !=
5784 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
5785
5786 DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
5787 bnx2x_cl45_write(bp, phy,
5788 MDIO_AN_DEVAD, MDIO_AN_REG_8727_MISC_CTRL, 0);
5789 bnx2x_cl45_write(bp, phy,
5790 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1300);
5791 } else {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005792 /*
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005793 * Since the 8727 has only single reset pin, need to set the 10G
5794 * registers although it is default
5795 */
5796 bnx2x_cl45_write(bp, phy,
5797 MDIO_AN_DEVAD, MDIO_AN_REG_8727_MISC_CTRL,
5798 0x0020);
5799 bnx2x_cl45_write(bp, phy,
5800 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x0100);
5801 bnx2x_cl45_write(bp, phy,
5802 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x2040);
5803 bnx2x_cl45_write(bp, phy,
5804 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2,
5805 0x0008);
5806 }
5807
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005808 /*
5809 * Set 2-wire transfer rate of SFP+ module EEPROM
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005810 * to 100Khz since some DACs(direct attached cables) do
5811 * not work at 400Khz.
5812 */
5813 bnx2x_cl45_write(bp, phy,
5814 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR,
5815 0xa001);
5816
5817 /* Set TX PreEmphasis if needed */
5818 if ((params->feature_config_flags &
5819 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
5820 DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x, TX_CTRL2 0x%x\n",
5821 phy->tx_preemphasis[0],
5822 phy->tx_preemphasis[1]);
5823 bnx2x_cl45_write(bp, phy,
5824 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TX_CTRL1,
5825 phy->tx_preemphasis[0]);
5826
5827 bnx2x_cl45_write(bp, phy,
5828 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TX_CTRL2,
5829 phy->tx_preemphasis[1]);
5830 }
5831
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00005832 /*
5833 * If TX Laser is controlled by GPIO_0, do not let PHY go into low
5834 * power mode, if TX Laser is disabled
5835 */
5836 tx_en_mode = REG_RD(bp, params->shmem_base +
5837 offsetof(struct shmem_region,
5838 dev_info.port_hw_config[params->port].sfp_ctrl))
5839 & PORT_HW_CFG_TX_LASER_MASK;
5840
5841 if (tx_en_mode == PORT_HW_CFG_TX_LASER_GPIO0) {
5842
5843 DP(NETIF_MSG_LINK, "Enabling TXONOFF_PWRDN_DIS\n");
5844 bnx2x_cl45_read(bp, phy,
5845 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_OPT_CFG_REG, &tmp2);
5846 tmp2 |= 0x1000;
5847 tmp2 &= 0xFFEF;
5848 bnx2x_cl45_write(bp, phy,
5849 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_OPT_CFG_REG, tmp2);
5850 }
5851
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005852 return 0;
5853}
5854
5855static void bnx2x_8727_handle_mod_abs(struct bnx2x_phy *phy,
5856 struct link_params *params)
5857{
5858 struct bnx2x *bp = params->bp;
5859 u16 mod_abs, rx_alarm_status;
5860 u32 val = REG_RD(bp, params->shmem_base +
5861 offsetof(struct shmem_region, dev_info.
5862 port_feature_config[params->port].
5863 config));
5864 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005865 MDIO_PMA_DEVAD,
5866 MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005867 if (mod_abs & (1<<8)) {
5868
5869 /* Module is absent */
5870 DP(NETIF_MSG_LINK, "MOD_ABS indication "
5871 "show module is absent\n");
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00005872 phy->media_type = ETH_PHY_NOT_PRESENT;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005873 /*
5874 * 1. Set mod_abs to detect next module
5875 * presence event
5876 * 2. Set EDC off by setting OPTXLOS signal input to low
5877 * (bit 9).
5878 * When the EDC is off it locks onto a reference clock and
5879 * avoids becoming 'lost'.
5880 */
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005881 mod_abs &= ~(1<<8);
5882 if (!(phy->flags & FLAGS_NOC))
5883 mod_abs &= ~(1<<9);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005884 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005885 MDIO_PMA_DEVAD,
5886 MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005887
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005888 /*
5889 * Clear RX alarm since it stays up as long as
5890 * the mod_abs wasn't changed
5891 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005892 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005893 MDIO_PMA_DEVAD,
5894 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005895
5896 } else {
5897 /* Module is present */
5898 DP(NETIF_MSG_LINK, "MOD_ABS indication "
5899 "show module is present\n");
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005900 /*
5901 * First disable transmitter, and if the module is ok, the
5902 * module_detection will enable it
5903 * 1. Set mod_abs to detect next module absent event ( bit 8)
5904 * 2. Restore the default polarity of the OPRXLOS signal and
5905 * this signal will then correctly indicate the presence or
5906 * absence of the Rx signal. (bit 9)
5907 */
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005908 mod_abs |= (1<<8);
5909 if (!(phy->flags & FLAGS_NOC))
5910 mod_abs |= (1<<9);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005911 bnx2x_cl45_write(bp, phy,
5912 MDIO_PMA_DEVAD,
5913 MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
5914
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005915 /*
5916 * Clear RX alarm since it stays up as long as the mod_abs
5917 * wasn't changed. This is need to be done before calling the
5918 * module detection, otherwise it will clear* the link update
5919 * alarm
5920 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005921 bnx2x_cl45_read(bp, phy,
5922 MDIO_PMA_DEVAD,
5923 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
5924
5925
5926 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
5927 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00005928 bnx2x_sfp_set_transmitter(params, phy, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005929
5930 if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0)
5931 bnx2x_sfp_module_detection(phy, params);
5932 else
5933 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
5934 }
5935
5936 DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n",
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005937 rx_alarm_status);
5938 /* No need to check link status in case of module plugged in/out */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005939}
5940
5941static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy,
5942 struct link_params *params,
5943 struct link_vars *vars)
5944
5945{
5946 struct bnx2x *bp = params->bp;
Yaniv Rosner27d02432011-05-31 21:27:48 +00005947 u8 link_up = 0, oc_port = params->port;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005948 u16 link_status = 0;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005949 u16 rx_alarm_status, lasi_ctrl, val1;
5950
5951 /* If PHY is not initialized, do not check link status */
5952 bnx2x_cl45_read(bp, phy,
5953 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL,
5954 &lasi_ctrl);
5955 if (!lasi_ctrl)
5956 return 0;
5957
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00005958 /* Check the LASI on Rx */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005959 bnx2x_cl45_read(bp, phy,
5960 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM,
5961 &rx_alarm_status);
5962 vars->line_speed = 0;
5963 DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n", rx_alarm_status);
5964
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00005965 bnx2x_sfp_mask_fault(bp, phy, MDIO_PMA_REG_TX_ALARM,
5966 MDIO_PMA_REG_TX_ALARM_CTRL);
5967
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005968 bnx2x_cl45_read(bp, phy,
5969 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
5970
5971 DP(NETIF_MSG_LINK, "8727 LASI status 0x%x\n", val1);
5972
5973 /* Clear MSG-OUT */
5974 bnx2x_cl45_read(bp, phy,
5975 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &val1);
5976
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005977 /*
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005978 * If a module is present and there is need to check
5979 * for over current
5980 */
5981 if (!(phy->flags & FLAGS_NOC) && !(rx_alarm_status & (1<<5))) {
5982 /* Check over-current using 8727 GPIO0 input*/
5983 bnx2x_cl45_read(bp, phy,
5984 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_GPIO_CTRL,
5985 &val1);
5986
5987 if ((val1 & (1<<8)) == 0) {
Yaniv Rosner27d02432011-05-31 21:27:48 +00005988 if (!CHIP_IS_E1x(bp))
5989 oc_port = BP_PATH(bp) + (params->port << 1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005990 DP(NETIF_MSG_LINK, "8727 Power fault has been detected"
Yaniv Rosner27d02432011-05-31 21:27:48 +00005991 " on port %d\n", oc_port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005992 netdev_err(bp->dev, "Error: Power fault on Port %d has"
5993 " been detected and the power to "
5994 "that SFP+ module has been removed"
5995 " to prevent failure of the card."
5996 " Please remove the SFP+ module and"
5997 " restart the system to clear this"
5998 " error.\n",
Yaniv Rosner27d02432011-05-31 21:27:48 +00005999 oc_port);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006000 /* Disable all RX_ALARMs except for mod_abs */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006001 bnx2x_cl45_write(bp, phy,
6002 MDIO_PMA_DEVAD,
6003 MDIO_PMA_REG_RX_ALARM_CTRL, (1<<5));
6004
6005 bnx2x_cl45_read(bp, phy,
6006 MDIO_PMA_DEVAD,
6007 MDIO_PMA_REG_PHY_IDENTIFIER, &val1);
6008 /* Wait for module_absent_event */
6009 val1 |= (1<<8);
6010 bnx2x_cl45_write(bp, phy,
6011 MDIO_PMA_DEVAD,
6012 MDIO_PMA_REG_PHY_IDENTIFIER, val1);
6013 /* Clear RX alarm */
6014 bnx2x_cl45_read(bp, phy,
6015 MDIO_PMA_DEVAD,
6016 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
6017 return 0;
6018 }
6019 } /* Over current check */
6020
6021 /* When module absent bit is set, check module */
6022 if (rx_alarm_status & (1<<5)) {
6023 bnx2x_8727_handle_mod_abs(phy, params);
6024 /* Enable all mod_abs and link detection bits */
6025 bnx2x_cl45_write(bp, phy,
6026 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
6027 ((1<<5) | (1<<2)));
6028 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006029 DP(NETIF_MSG_LINK, "Enabling 8727 TX laser if SFP is approved\n");
6030 bnx2x_8727_specific_func(phy, params, ENABLE_TX);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006031 /* If transmitter is disabled, ignore false link up indication */
6032 bnx2x_cl45_read(bp, phy,
6033 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, &val1);
6034 if (val1 & (1<<15)) {
6035 DP(NETIF_MSG_LINK, "Tx is disabled\n");
6036 return 0;
6037 }
6038
6039 bnx2x_cl45_read(bp, phy,
6040 MDIO_PMA_DEVAD,
6041 MDIO_PMA_REG_8073_SPEED_LINK_STATUS, &link_status);
6042
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006043 /*
6044 * Bits 0..2 --> speed detected,
6045 * Bits 13..15--> link is down
6046 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006047 if ((link_status & (1<<2)) && (!(link_status & (1<<15)))) {
6048 link_up = 1;
6049 vars->line_speed = SPEED_10000;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006050 DP(NETIF_MSG_LINK, "port %x: External link up in 10G\n",
6051 params->port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006052 } else if ((link_status & (1<<0)) && (!(link_status & (1<<13)))) {
6053 link_up = 1;
6054 vars->line_speed = SPEED_1000;
6055 DP(NETIF_MSG_LINK, "port %x: External link up in 1G\n",
6056 params->port);
6057 } else {
6058 link_up = 0;
6059 DP(NETIF_MSG_LINK, "port %x: External link is down\n",
6060 params->port);
6061 }
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00006062
6063 /* Capture 10G link fault. */
6064 if (vars->line_speed == SPEED_10000) {
6065 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
6066 MDIO_PMA_REG_TX_ALARM, &val1);
6067
6068 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
6069 MDIO_PMA_REG_TX_ALARM, &val1);
6070
6071 if (val1 & (1<<0)) {
6072 vars->fault_detected = 1;
6073 }
6074 }
6075
Yaniv Rosner791f18c2011-01-18 04:33:42 +00006076 if (link_up) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006077 bnx2x_ext_phy_resolve_fc(phy, params, vars);
Yaniv Rosner791f18c2011-01-18 04:33:42 +00006078 vars->duplex = DUPLEX_FULL;
6079 DP(NETIF_MSG_LINK, "duplex = 0x%x\n", vars->duplex);
6080 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006081
6082 if ((DUAL_MEDIA(params)) &&
6083 (phy->req_line_speed == SPEED_1000)) {
6084 bnx2x_cl45_read(bp, phy,
6085 MDIO_PMA_DEVAD,
6086 MDIO_PMA_REG_8727_PCS_GP, &val1);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006087 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006088 * In case of dual-media board and 1G, power up the XAUI side,
6089 * otherwise power it down. For 10G it is done automatically
6090 */
6091 if (link_up)
6092 val1 &= ~(3<<10);
6093 else
6094 val1 |= (3<<10);
6095 bnx2x_cl45_write(bp, phy,
6096 MDIO_PMA_DEVAD,
6097 MDIO_PMA_REG_8727_PCS_GP, val1);
6098 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006099 return link_up;
6100}
6101
6102static void bnx2x_8727_link_reset(struct bnx2x_phy *phy,
6103 struct link_params *params)
6104{
6105 struct bnx2x *bp = params->bp;
6106 /* Disable Transmitter */
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00006107 bnx2x_sfp_set_transmitter(params, phy, 0);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006108 /* Clear LASI */
6109 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0);
6110
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006111}
6112
6113/******************************************************************/
6114/* BCM8481/BCM84823/BCM84833 PHY SECTION */
6115/******************************************************************/
6116static void bnx2x_save_848xx_spirom_version(struct bnx2x_phy *phy,
6117 struct link_params *params)
6118{
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006119 u16 val, fw_ver1, fw_ver2, cnt;
6120 u8 port;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006121 struct bnx2x *bp = params->bp;
6122
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006123 port = params->port;
Yaniv Rosnerc87bca12011-01-31 04:22:41 +00006124
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006125 /* For the 32 bits registers in 848xx, access via MDIO2ARM interface.*/
6126 /* (1) set register 0xc200_0014(SPI_BRIDGE_CTRL_2) to 0x03000000 */
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006127 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0014);
6128 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200);
6129 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81B, 0x0000);
6130 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81C, 0x0300);
6131 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x0009);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006132
6133 for (cnt = 0; cnt < 100; cnt++) {
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006134 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006135 if (val & 1)
6136 break;
6137 udelay(5);
6138 }
6139 if (cnt == 100) {
6140 DP(NETIF_MSG_LINK, "Unable to read 848xx phy fw version(1)\n");
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006141 bnx2x_save_spirom_version(bp, port, 0,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006142 phy->ver_addr);
6143 return;
6144 }
6145
6146
6147 /* 2) read register 0xc200_0000 (SPI_FW_STATUS) */
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006148 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0000);
6149 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200);
6150 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x000A);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006151 for (cnt = 0; cnt < 100; cnt++) {
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006152 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006153 if (val & 1)
6154 break;
6155 udelay(5);
6156 }
6157 if (cnt == 100) {
6158 DP(NETIF_MSG_LINK, "Unable to read 848xx phy fw version(2)\n");
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006159 bnx2x_save_spirom_version(bp, port, 0,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006160 phy->ver_addr);
6161 return;
6162 }
6163
6164 /* lower 16 bits of the register SPI_FW_STATUS */
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006165 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81B, &fw_ver1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006166 /* upper 16 bits of register SPI_FW_STATUS */
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006167 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81C, &fw_ver2);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006168
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006169 bnx2x_save_spirom_version(bp, port, (fw_ver2<<16) | fw_ver1,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006170 phy->ver_addr);
6171}
6172
6173static void bnx2x_848xx_set_led(struct bnx2x *bp,
6174 struct bnx2x_phy *phy)
6175{
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006176 u16 val;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006177
6178 /* PHYC_CTL_LED_CTL */
6179 bnx2x_cl45_read(bp, phy,
6180 MDIO_PMA_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006181 MDIO_PMA_REG_8481_LINK_SIGNAL, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006182 val &= 0xFE00;
6183 val |= 0x0092;
6184
6185 bnx2x_cl45_write(bp, phy,
6186 MDIO_PMA_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006187 MDIO_PMA_REG_8481_LINK_SIGNAL, val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006188
6189 bnx2x_cl45_write(bp, phy,
6190 MDIO_PMA_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006191 MDIO_PMA_REG_8481_LED1_MASK,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006192 0x80);
6193
6194 bnx2x_cl45_write(bp, phy,
6195 MDIO_PMA_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006196 MDIO_PMA_REG_8481_LED2_MASK,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006197 0x18);
6198
Yaniv Rosnerf25b3c82011-01-18 04:33:47 +00006199 /* Select activity source by Tx and Rx, as suggested by PHY AE */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006200 bnx2x_cl45_write(bp, phy,
6201 MDIO_PMA_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006202 MDIO_PMA_REG_8481_LED3_MASK,
Yaniv Rosnerf25b3c82011-01-18 04:33:47 +00006203 0x0006);
6204
6205 /* Select the closest activity blink rate to that in 10/100/1000 */
6206 bnx2x_cl45_write(bp, phy,
6207 MDIO_PMA_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006208 MDIO_PMA_REG_8481_LED3_BLINK,
Yaniv Rosnerf25b3c82011-01-18 04:33:47 +00006209 0);
6210
6211 bnx2x_cl45_read(bp, phy,
6212 MDIO_PMA_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006213 MDIO_PMA_REG_84823_CTL_LED_CTL_1, &val);
Yaniv Rosnerf25b3c82011-01-18 04:33:47 +00006214 val |= MDIO_PMA_REG_84823_LED3_STRETCH_EN; /* stretch_en for LED3*/
6215
6216 bnx2x_cl45_write(bp, phy,
6217 MDIO_PMA_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006218 MDIO_PMA_REG_84823_CTL_LED_CTL_1, val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006219
6220 /* 'Interrupt Mask' */
6221 bnx2x_cl45_write(bp, phy,
6222 MDIO_AN_DEVAD,
6223 0xFFFB, 0xFFFD);
6224}
6225
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006226static int bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy,
6227 struct link_params *params,
6228 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006229{
6230 struct bnx2x *bp = params->bp;
6231 u16 autoneg_val, an_1000_val, an_10_100_val;
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006232 u16 tmp_req_line_speed;
6233
6234 tmp_req_line_speed = phy->req_line_speed;
6235 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833)
6236 if (phy->req_line_speed == SPEED_10000)
6237 phy->req_line_speed = SPEED_AUTO_NEG;
6238
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006239 /*
6240 * This phy uses the NIG latch mechanism since link indication
6241 * arrives through its LED4 and not via its LASI signal, so we
6242 * get steady signal instead of clear on read
6243 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006244 bnx2x_bits_en(bp, NIG_REG_LATCH_BC_0 + params->port*4,
6245 1 << NIG_LATCH_BC_ENABLE_MI_INT);
6246
6247 bnx2x_cl45_write(bp, phy,
6248 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x0000);
6249
6250 bnx2x_848xx_set_led(bp, phy);
6251
6252 /* set 1000 speed advertisement */
6253 bnx2x_cl45_read(bp, phy,
6254 MDIO_AN_DEVAD, MDIO_AN_REG_8481_1000T_CTRL,
6255 &an_1000_val);
6256
6257 bnx2x_ext_phy_set_pause(params, phy, vars);
6258 bnx2x_cl45_read(bp, phy,
6259 MDIO_AN_DEVAD,
6260 MDIO_AN_REG_8481_LEGACY_AN_ADV,
6261 &an_10_100_val);
6262 bnx2x_cl45_read(bp, phy,
6263 MDIO_AN_DEVAD, MDIO_AN_REG_8481_LEGACY_MII_CTRL,
6264 &autoneg_val);
6265 /* Disable forced speed */
6266 autoneg_val &= ~((1<<6) | (1<<8) | (1<<9) | (1<<12) | (1<<13));
6267 an_10_100_val &= ~((1<<5) | (1<<6) | (1<<7) | (1<<8));
6268
6269 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
6270 (phy->speed_cap_mask &
6271 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) ||
6272 (phy->req_line_speed == SPEED_1000)) {
6273 an_1000_val |= (1<<8);
6274 autoneg_val |= (1<<9 | 1<<12);
6275 if (phy->req_duplex == DUPLEX_FULL)
6276 an_1000_val |= (1<<9);
6277 DP(NETIF_MSG_LINK, "Advertising 1G\n");
6278 } else
6279 an_1000_val &= ~((1<<8) | (1<<9));
6280
6281 bnx2x_cl45_write(bp, phy,
6282 MDIO_AN_DEVAD, MDIO_AN_REG_8481_1000T_CTRL,
6283 an_1000_val);
6284
6285 /* set 10 speed advertisement */
6286 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
6287 (phy->speed_cap_mask &
6288 (PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL |
6289 PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF)))) {
6290 an_10_100_val |= (1<<7);
6291 /* Enable autoneg and restart autoneg for legacy speeds */
6292 autoneg_val |= (1<<9 | 1<<12);
6293
6294 if (phy->req_duplex == DUPLEX_FULL)
6295 an_10_100_val |= (1<<8);
6296 DP(NETIF_MSG_LINK, "Advertising 100M\n");
6297 }
6298 /* set 10 speed advertisement */
6299 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
6300 (phy->speed_cap_mask &
6301 (PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL |
6302 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF)))) {
6303 an_10_100_val |= (1<<5);
6304 autoneg_val |= (1<<9 | 1<<12);
6305 if (phy->req_duplex == DUPLEX_FULL)
6306 an_10_100_val |= (1<<6);
6307 DP(NETIF_MSG_LINK, "Advertising 10M\n");
6308 }
6309
6310 /* Only 10/100 are allowed to work in FORCE mode */
6311 if (phy->req_line_speed == SPEED_100) {
6312 autoneg_val |= (1<<13);
6313 /* Enabled AUTO-MDIX when autoneg is disabled */
6314 bnx2x_cl45_write(bp, phy,
6315 MDIO_AN_DEVAD, MDIO_AN_REG_8481_AUX_CTRL,
6316 (1<<15 | 1<<9 | 7<<0));
6317 DP(NETIF_MSG_LINK, "Setting 100M force\n");
6318 }
6319 if (phy->req_line_speed == SPEED_10) {
6320 /* Enabled AUTO-MDIX when autoneg is disabled */
6321 bnx2x_cl45_write(bp, phy,
6322 MDIO_AN_DEVAD, MDIO_AN_REG_8481_AUX_CTRL,
6323 (1<<15 | 1<<9 | 7<<0));
6324 DP(NETIF_MSG_LINK, "Setting 10M force\n");
6325 }
6326
6327 bnx2x_cl45_write(bp, phy,
6328 MDIO_AN_DEVAD, MDIO_AN_REG_8481_LEGACY_AN_ADV,
6329 an_10_100_val);
6330
6331 if (phy->req_duplex == DUPLEX_FULL)
6332 autoneg_val |= (1<<8);
6333
6334 bnx2x_cl45_write(bp, phy,
6335 MDIO_AN_DEVAD,
6336 MDIO_AN_REG_8481_LEGACY_MII_CTRL, autoneg_val);
6337
6338 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
6339 (phy->speed_cap_mask &
6340 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) ||
6341 (phy->req_line_speed == SPEED_10000)) {
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00006342 DP(NETIF_MSG_LINK, "Advertising 10G\n");
6343 /* Restart autoneg for 10G*/
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006344
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00006345 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006346 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL,
6347 0x3200);
6348 } else if (phy->req_line_speed != SPEED_10 &&
6349 phy->req_line_speed != SPEED_100) {
6350 bnx2x_cl45_write(bp, phy,
6351 MDIO_AN_DEVAD,
6352 MDIO_AN_REG_8481_10GBASE_T_AN_CTRL,
6353 1);
6354 }
6355 /* Save spirom version */
6356 bnx2x_save_848xx_spirom_version(phy, params);
6357
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006358 phy->req_line_speed = tmp_req_line_speed;
6359
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006360 return 0;
6361}
6362
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006363static int bnx2x_8481_config_init(struct bnx2x_phy *phy,
6364 struct link_params *params,
6365 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006366{
6367 struct bnx2x *bp = params->bp;
6368 /* Restore normal power mode*/
6369 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006370 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006371
6372 /* HW reset */
6373 bnx2x_ext_phy_hw_reset(bp, params->port);
Yaniv Rosner6d870c32011-01-31 04:22:20 +00006374 bnx2x_wait_reset_complete(bp, phy, params);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006375
6376 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
6377 return bnx2x_848xx_cmn_config_init(phy, params, vars);
6378}
6379
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006380
6381#define PHY84833_HDSHK_WAIT 300
6382static int bnx2x_84833_pair_swap_cfg(struct bnx2x_phy *phy,
6383 struct link_params *params,
6384 struct link_vars *vars)
6385{
6386 u32 idx;
6387 u16 val;
6388 u16 data = 0x01b1;
6389 struct bnx2x *bp = params->bp;
6390 /* Do pair swap */
6391
6392
6393 /* Write CMD_OPEN_OVERRIDE to STATUS reg */
6394 bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
6395 MDIO_84833_TOP_CFG_SCRATCH_REG2,
6396 PHY84833_CMD_OPEN_OVERRIDE);
6397 for (idx = 0; idx < PHY84833_HDSHK_WAIT; idx++) {
6398 bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
6399 MDIO_84833_TOP_CFG_SCRATCH_REG2, &val);
6400 if (val == PHY84833_CMD_OPEN_FOR_CMDS)
6401 break;
6402 msleep(1);
6403 }
6404 if (idx >= PHY84833_HDSHK_WAIT) {
6405 DP(NETIF_MSG_LINK, "Pairswap: FW not ready.\n");
6406 return -EINVAL;
6407 }
6408
6409 bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
6410 MDIO_84833_TOP_CFG_SCRATCH_REG4,
6411 data);
6412 /* Issue pair swap command */
6413 bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
6414 MDIO_84833_TOP_CFG_SCRATCH_REG0,
6415 PHY84833_DIAG_CMD_PAIR_SWAP_CHANGE);
6416 for (idx = 0; idx < PHY84833_HDSHK_WAIT; idx++) {
6417 bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
6418 MDIO_84833_TOP_CFG_SCRATCH_REG2, &val);
6419 if ((val == PHY84833_CMD_COMPLETE_PASS) ||
6420 (val == PHY84833_CMD_COMPLETE_ERROR))
6421 break;
6422 msleep(1);
6423 }
6424 if ((idx >= PHY84833_HDSHK_WAIT) ||
6425 (val == PHY84833_CMD_COMPLETE_ERROR)) {
6426 DP(NETIF_MSG_LINK, "Pairswap: override failed.\n");
6427 return -EINVAL;
6428 }
6429 bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
6430 MDIO_84833_TOP_CFG_SCRATCH_REG2,
6431 PHY84833_CMD_CLEAR_COMPLETE);
6432 DP(NETIF_MSG_LINK, "Pairswap OK, val=0x%x\n", data);
6433 return 0;
6434}
6435
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006436static int bnx2x_848x3_config_init(struct bnx2x_phy *phy,
6437 struct link_params *params,
6438 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006439{
6440 struct bnx2x *bp = params->bp;
Yaniv Rosner6a71bbe2010-11-01 05:32:31 +00006441 u8 port, initialize = 1;
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006442 u16 val;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006443 u16 temp;
Yaniv Rosner1bef68e2011-01-31 04:22:46 +00006444 u32 actual_phy_selection, cms_enable;
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006445 int rc = 0;
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006446
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006447 msleep(1);
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006448
6449 if (!(CHIP_IS_E1(bp)))
Yaniv Rosner6a71bbe2010-11-01 05:32:31 +00006450 port = BP_PATH(bp);
6451 else
6452 port = params->port;
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006453
6454 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823) {
6455 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
6456 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
6457 port);
6458 } else {
6459 bnx2x_cl45_write(bp, phy,
6460 MDIO_PMA_DEVAD,
6461 MDIO_PMA_REG_CTRL, 0x8000);
6462 }
6463
Yaniv Rosner6d870c32011-01-31 04:22:20 +00006464 bnx2x_wait_reset_complete(bp, phy, params);
Yaniv Rosner9bffeac2010-11-01 05:32:27 +00006465 /* Wait for GPHY to come out of reset */
6466 msleep(50);
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006467
6468 /* Bring PHY out of super isolate mode */
6469 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) {
6470 bnx2x_cl45_read(bp, phy,
6471 MDIO_CTL_DEVAD,
6472 MDIO_84833_TOP_CFG_XGPHY_STRAP1, &val);
6473 val &= ~MDIO_84833_SUPER_ISOLATE;
6474 bnx2x_cl45_write(bp, phy,
6475 MDIO_CTL_DEVAD,
6476 MDIO_84833_TOP_CFG_XGPHY_STRAP1, val);
6477 bnx2x_wait_reset_complete(bp, phy, params);
6478 }
6479
6480 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833)
6481 bnx2x_84833_pair_swap_cfg(phy, params, vars);
6482
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006483 /*
6484 * BCM84823 requires that XGXS links up first @ 10G for normal behavior
6485 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006486 temp = vars->line_speed;
6487 vars->line_speed = SPEED_10000;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006488 bnx2x_set_autoneg(&params->phy[INT_PHY], params, vars, 0);
6489 bnx2x_program_serdes(&params->phy[INT_PHY], params, vars);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006490 vars->line_speed = temp;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006491
6492 /* Set dual-media configuration according to configuration */
6493
6494 bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006495 MDIO_CTL_REG_84823_MEDIA, &val);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006496 val &= ~(MDIO_CTL_REG_84823_MEDIA_MAC_MASK |
6497 MDIO_CTL_REG_84823_MEDIA_LINE_MASK |
6498 MDIO_CTL_REG_84823_MEDIA_COPPER_CORE_DOWN |
6499 MDIO_CTL_REG_84823_MEDIA_PRIORITY_MASK |
6500 MDIO_CTL_REG_84823_MEDIA_FIBER_1G);
6501 val |= MDIO_CTL_REG_84823_CTRL_MAC_XFI |
6502 MDIO_CTL_REG_84823_MEDIA_LINE_XAUI_L;
6503
6504 actual_phy_selection = bnx2x_phy_selection(params);
6505
6506 switch (actual_phy_selection) {
6507 case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT:
Lucas De Marchi25985ed2011-03-30 22:57:33 -03006508 /* Do nothing. Essentially this is like the priority copper */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006509 break;
6510 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
6511 val |= MDIO_CTL_REG_84823_MEDIA_PRIORITY_COPPER;
6512 break;
6513 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
6514 val |= MDIO_CTL_REG_84823_MEDIA_PRIORITY_FIBER;
6515 break;
6516 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY:
6517 /* Do nothing here. The first PHY won't be initialized at all */
6518 break;
6519 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY:
6520 val |= MDIO_CTL_REG_84823_MEDIA_COPPER_CORE_DOWN;
6521 initialize = 0;
6522 break;
6523 }
6524 if (params->phy[EXT_PHY2].req_line_speed == SPEED_1000)
6525 val |= MDIO_CTL_REG_84823_MEDIA_FIBER_1G;
6526
6527 bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006528 MDIO_CTL_REG_84823_MEDIA, val);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006529 DP(NETIF_MSG_LINK, "Multi_phy config = 0x%x, Media control = 0x%x\n",
6530 params->multi_phy_config, val);
6531
6532 if (initialize)
6533 rc = bnx2x_848xx_cmn_config_init(phy, params, vars);
6534 else
6535 bnx2x_save_848xx_spirom_version(phy, params);
Yaniv Rosner1bef68e2011-01-31 04:22:46 +00006536 cms_enable = REG_RD(bp, params->shmem_base +
6537 offsetof(struct shmem_region,
6538 dev_info.port_hw_config[params->port].default_cfg)) &
6539 PORT_HW_CFG_ENABLE_CMS_MASK;
6540
6541 bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
6542 MDIO_CTL_REG_84823_USER_CTRL_REG, &val);
6543 if (cms_enable)
6544 val |= MDIO_CTL_REG_84823_USER_CTRL_CMS;
6545 else
6546 val &= ~MDIO_CTL_REG_84823_USER_CTRL_CMS;
6547 bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
6548 MDIO_CTL_REG_84823_USER_CTRL_REG, val);
6549
6550
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006551 return rc;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006552}
6553
6554static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006555 struct link_params *params,
6556 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006557{
6558 struct bnx2x *bp = params->bp;
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006559 u16 val, val1, val2;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006560 u8 link_up = 0;
6561
Yaniv Rosnerc87bca12011-01-31 04:22:41 +00006562
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006563 /* Check 10G-BaseT link status */
6564 /* Check PMD signal ok */
6565 bnx2x_cl45_read(bp, phy,
6566 MDIO_AN_DEVAD, 0xFFFA, &val1);
6567 bnx2x_cl45_read(bp, phy,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006568 MDIO_PMA_DEVAD, MDIO_PMA_REG_8481_PMD_SIGNAL,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006569 &val2);
6570 DP(NETIF_MSG_LINK, "BCM848xx: PMD_SIGNAL 1.a811 = 0x%x\n", val2);
6571
6572 /* Check link 10G */
6573 if (val2 & (1<<11)) {
6574 vars->line_speed = SPEED_10000;
Yaniv Rosner791f18c2011-01-18 04:33:42 +00006575 vars->duplex = DUPLEX_FULL;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006576 link_up = 1;
6577 bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
6578 } else { /* Check Legacy speed link */
6579 u16 legacy_status, legacy_speed;
6580
6581 /* Enable expansion register 0x42 (Operation mode status) */
6582 bnx2x_cl45_write(bp, phy,
6583 MDIO_AN_DEVAD,
6584 MDIO_AN_REG_8481_EXPANSION_REG_ACCESS, 0xf42);
6585
6586 /* Get legacy speed operation status */
6587 bnx2x_cl45_read(bp, phy,
6588 MDIO_AN_DEVAD,
6589 MDIO_AN_REG_8481_EXPANSION_REG_RD_RW,
6590 &legacy_status);
6591
6592 DP(NETIF_MSG_LINK, "Legacy speed status"
6593 " = 0x%x\n", legacy_status);
6594 link_up = ((legacy_status & (1<<11)) == (1<<11));
6595 if (link_up) {
6596 legacy_speed = (legacy_status & (3<<9));
6597 if (legacy_speed == (0<<9))
6598 vars->line_speed = SPEED_10;
6599 else if (legacy_speed == (1<<9))
6600 vars->line_speed = SPEED_100;
6601 else if (legacy_speed == (2<<9))
6602 vars->line_speed = SPEED_1000;
6603 else /* Should not happen */
6604 vars->line_speed = 0;
6605
6606 if (legacy_status & (1<<8))
6607 vars->duplex = DUPLEX_FULL;
6608 else
6609 vars->duplex = DUPLEX_HALF;
6610
6611 DP(NETIF_MSG_LINK, "Link is up in %dMbps,"
6612 " is_duplex_full= %d\n", vars->line_speed,
6613 (vars->duplex == DUPLEX_FULL));
6614 /* Check legacy speed AN resolution */
6615 bnx2x_cl45_read(bp, phy,
6616 MDIO_AN_DEVAD,
6617 MDIO_AN_REG_8481_LEGACY_MII_STATUS,
6618 &val);
6619 if (val & (1<<5))
6620 vars->link_status |=
6621 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
6622 bnx2x_cl45_read(bp, phy,
6623 MDIO_AN_DEVAD,
6624 MDIO_AN_REG_8481_LEGACY_AN_EXPANSION,
6625 &val);
6626 if ((val & (1<<0)) == 0)
6627 vars->link_status |=
6628 LINK_STATUS_PARALLEL_DETECTION_USED;
6629 }
6630 }
6631 if (link_up) {
6632 DP(NETIF_MSG_LINK, "BCM84823: link speed is %d\n",
6633 vars->line_speed);
6634 bnx2x_ext_phy_resolve_fc(phy, params, vars);
6635 }
6636
6637 return link_up;
6638}
6639
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006640
6641static int bnx2x_848xx_format_ver(u32 raw_ver, u8 *str, u16 *len)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006642{
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006643 int status = 0;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006644 u32 spirom_ver;
6645 spirom_ver = ((raw_ver & 0xF80) >> 7) << 16 | (raw_ver & 0x7F);
6646 status = bnx2x_format_ver(spirom_ver, str, len);
6647 return status;
6648}
6649
6650static void bnx2x_8481_hw_reset(struct bnx2x_phy *phy,
6651 struct link_params *params)
6652{
6653 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006654 MISC_REGISTERS_GPIO_OUTPUT_LOW, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006655 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006656 MISC_REGISTERS_GPIO_OUTPUT_LOW, 1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006657}
6658
6659static void bnx2x_8481_link_reset(struct bnx2x_phy *phy,
6660 struct link_params *params)
6661{
6662 bnx2x_cl45_write(params->bp, phy,
6663 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x0000);
6664 bnx2x_cl45_write(params->bp, phy,
6665 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1);
6666}
6667
6668static void bnx2x_848x3_link_reset(struct bnx2x_phy *phy,
6669 struct link_params *params)
6670{
6671 struct bnx2x *bp = params->bp;
Yaniv Rosner6a71bbe2010-11-01 05:32:31 +00006672 u8 port;
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006673
6674 if (!(CHIP_IS_E1(bp)))
Yaniv Rosner6a71bbe2010-11-01 05:32:31 +00006675 port = BP_PATH(bp);
6676 else
6677 port = params->port;
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006678
6679 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823) {
6680 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
6681 MISC_REGISTERS_GPIO_OUTPUT_LOW,
6682 port);
6683 } else {
6684 bnx2x_cl45_write(bp, phy,
6685 MDIO_PMA_DEVAD,
6686 MDIO_PMA_REG_CTRL, 0x800);
6687 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006688}
6689
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006690static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy,
6691 struct link_params *params, u8 mode)
6692{
6693 struct bnx2x *bp = params->bp;
6694 u16 val;
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006695 u8 port;
6696
6697 if (!(CHIP_IS_E1(bp)))
6698 port = BP_PATH(bp);
6699 else
6700 port = params->port;
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006701
6702 switch (mode) {
6703 case LED_MODE_OFF:
6704
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006705 DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE OFF\n", port);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006706
6707 if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
6708 SHARED_HW_CFG_LED_EXTPHY1) {
6709
6710 /* Set LED masks */
6711 bnx2x_cl45_write(bp, phy,
6712 MDIO_PMA_DEVAD,
6713 MDIO_PMA_REG_8481_LED1_MASK,
6714 0x0);
6715
6716 bnx2x_cl45_write(bp, phy,
6717 MDIO_PMA_DEVAD,
6718 MDIO_PMA_REG_8481_LED2_MASK,
6719 0x0);
6720
6721 bnx2x_cl45_write(bp, phy,
6722 MDIO_PMA_DEVAD,
6723 MDIO_PMA_REG_8481_LED3_MASK,
6724 0x0);
6725
6726 bnx2x_cl45_write(bp, phy,
6727 MDIO_PMA_DEVAD,
6728 MDIO_PMA_REG_8481_LED5_MASK,
6729 0x0);
6730
6731 } else {
6732 bnx2x_cl45_write(bp, phy,
6733 MDIO_PMA_DEVAD,
6734 MDIO_PMA_REG_8481_LED1_MASK,
6735 0x0);
6736 }
6737 break;
6738 case LED_MODE_FRONT_PANEL_OFF:
6739
6740 DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE FRONT PANEL OFF\n",
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006741 port);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006742
6743 if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
6744 SHARED_HW_CFG_LED_EXTPHY1) {
6745
6746 /* Set LED masks */
6747 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006748 MDIO_PMA_DEVAD,
6749 MDIO_PMA_REG_8481_LED1_MASK,
6750 0x0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006751
6752 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006753 MDIO_PMA_DEVAD,
6754 MDIO_PMA_REG_8481_LED2_MASK,
6755 0x0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006756
6757 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006758 MDIO_PMA_DEVAD,
6759 MDIO_PMA_REG_8481_LED3_MASK,
6760 0x0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006761
6762 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006763 MDIO_PMA_DEVAD,
6764 MDIO_PMA_REG_8481_LED5_MASK,
6765 0x20);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006766
6767 } else {
6768 bnx2x_cl45_write(bp, phy,
6769 MDIO_PMA_DEVAD,
6770 MDIO_PMA_REG_8481_LED1_MASK,
6771 0x0);
6772 }
6773 break;
6774 case LED_MODE_ON:
6775
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006776 DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE ON\n", port);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006777
6778 if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
6779 SHARED_HW_CFG_LED_EXTPHY1) {
6780 /* Set control reg */
6781 bnx2x_cl45_read(bp, phy,
6782 MDIO_PMA_DEVAD,
6783 MDIO_PMA_REG_8481_LINK_SIGNAL,
6784 &val);
6785 val &= 0x8000;
6786 val |= 0x2492;
6787
6788 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006789 MDIO_PMA_DEVAD,
6790 MDIO_PMA_REG_8481_LINK_SIGNAL,
6791 val);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006792
6793 /* Set LED masks */
6794 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006795 MDIO_PMA_DEVAD,
6796 MDIO_PMA_REG_8481_LED1_MASK,
6797 0x0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006798
6799 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006800 MDIO_PMA_DEVAD,
6801 MDIO_PMA_REG_8481_LED2_MASK,
6802 0x20);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006803
6804 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006805 MDIO_PMA_DEVAD,
6806 MDIO_PMA_REG_8481_LED3_MASK,
6807 0x20);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006808
6809 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006810 MDIO_PMA_DEVAD,
6811 MDIO_PMA_REG_8481_LED5_MASK,
6812 0x0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006813 } else {
6814 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006815 MDIO_PMA_DEVAD,
6816 MDIO_PMA_REG_8481_LED1_MASK,
6817 0x20);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006818 }
6819 break;
6820
6821 case LED_MODE_OPER:
6822
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00006823 DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE OPER\n", port);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006824
6825 if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
6826 SHARED_HW_CFG_LED_EXTPHY1) {
6827
6828 /* Set control reg */
6829 bnx2x_cl45_read(bp, phy,
6830 MDIO_PMA_DEVAD,
6831 MDIO_PMA_REG_8481_LINK_SIGNAL,
6832 &val);
6833
6834 if (!((val &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006835 MDIO_PMA_REG_8481_LINK_SIGNAL_LED4_ENABLE_MASK)
6836 >> MDIO_PMA_REG_8481_LINK_SIGNAL_LED4_ENABLE_SHIFT)) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006837 DP(NETIF_MSG_LINK, "Setting LINK_SIGNAL\n");
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006838 bnx2x_cl45_write(bp, phy,
6839 MDIO_PMA_DEVAD,
6840 MDIO_PMA_REG_8481_LINK_SIGNAL,
6841 0xa492);
6842 }
6843
6844 /* Set LED masks */
6845 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006846 MDIO_PMA_DEVAD,
6847 MDIO_PMA_REG_8481_LED1_MASK,
6848 0x10);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006849
6850 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006851 MDIO_PMA_DEVAD,
6852 MDIO_PMA_REG_8481_LED2_MASK,
6853 0x80);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006854
6855 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006856 MDIO_PMA_DEVAD,
6857 MDIO_PMA_REG_8481_LED3_MASK,
6858 0x98);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006859
6860 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006861 MDIO_PMA_DEVAD,
6862 MDIO_PMA_REG_8481_LED5_MASK,
6863 0x40);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006864
6865 } else {
6866 bnx2x_cl45_write(bp, phy,
6867 MDIO_PMA_DEVAD,
6868 MDIO_PMA_REG_8481_LED1_MASK,
6869 0x80);
Yaniv Rosner53eda062011-01-30 04:14:55 +00006870
6871 /* Tell LED3 to blink on source */
6872 bnx2x_cl45_read(bp, phy,
6873 MDIO_PMA_DEVAD,
6874 MDIO_PMA_REG_8481_LINK_SIGNAL,
6875 &val);
6876 val &= ~(7<<6);
6877 val |= (1<<6); /* A83B[8:6]= 1 */
6878 bnx2x_cl45_write(bp, phy,
6879 MDIO_PMA_DEVAD,
6880 MDIO_PMA_REG_8481_LINK_SIGNAL,
6881 val);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006882 }
6883 break;
6884 }
6885}
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006886/******************************************************************/
6887/* SFX7101 PHY SECTION */
6888/******************************************************************/
6889static void bnx2x_7101_config_loopback(struct bnx2x_phy *phy,
6890 struct link_params *params)
6891{
6892 struct bnx2x *bp = params->bp;
6893 /* SFX7101_XGXS_TEST1 */
6894 bnx2x_cl45_write(bp, phy,
6895 MDIO_XS_DEVAD, MDIO_XS_SFX7101_XGXS_TEST1, 0x100);
6896}
6897
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006898static int bnx2x_7101_config_init(struct bnx2x_phy *phy,
6899 struct link_params *params,
6900 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006901{
6902 u16 fw_ver1, fw_ver2, val;
6903 struct bnx2x *bp = params->bp;
6904 DP(NETIF_MSG_LINK, "Setting the SFX7101 LASI indication\n");
6905
6906 /* Restore normal power mode*/
6907 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006908 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006909 /* HW reset */
6910 bnx2x_ext_phy_hw_reset(bp, params->port);
Yaniv Rosner6d870c32011-01-31 04:22:20 +00006911 bnx2x_wait_reset_complete(bp, phy, params);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006912
6913 bnx2x_cl45_write(bp, phy,
6914 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x1);
6915 DP(NETIF_MSG_LINK, "Setting the SFX7101 LED to blink on traffic\n");
6916 bnx2x_cl45_write(bp, phy,
6917 MDIO_PMA_DEVAD, MDIO_PMA_REG_7107_LED_CNTL, (1<<3));
6918
6919 bnx2x_ext_phy_set_pause(params, phy, vars);
6920 /* Restart autoneg */
6921 bnx2x_cl45_read(bp, phy,
6922 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, &val);
6923 val |= 0x200;
6924 bnx2x_cl45_write(bp, phy,
6925 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, val);
6926
6927 /* Save spirom version */
6928 bnx2x_cl45_read(bp, phy,
6929 MDIO_PMA_DEVAD, MDIO_PMA_REG_7101_VER1, &fw_ver1);
6930
6931 bnx2x_cl45_read(bp, phy,
6932 MDIO_PMA_DEVAD, MDIO_PMA_REG_7101_VER2, &fw_ver2);
6933 bnx2x_save_spirom_version(bp, params->port,
6934 (u32)(fw_ver1<<16 | fw_ver2), phy->ver_addr);
6935 return 0;
6936}
6937
6938static u8 bnx2x_7101_read_status(struct bnx2x_phy *phy,
6939 struct link_params *params,
6940 struct link_vars *vars)
6941{
6942 struct bnx2x *bp = params->bp;
6943 u8 link_up;
6944 u16 val1, val2;
6945 bnx2x_cl45_read(bp, phy,
6946 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val2);
6947 bnx2x_cl45_read(bp, phy,
6948 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
6949 DP(NETIF_MSG_LINK, "10G-base-T LASI status 0x%x->0x%x\n",
6950 val2, val1);
6951 bnx2x_cl45_read(bp, phy,
6952 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
6953 bnx2x_cl45_read(bp, phy,
6954 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
6955 DP(NETIF_MSG_LINK, "10G-base-T PMA status 0x%x->0x%x\n",
6956 val2, val1);
6957 link_up = ((val1 & 4) == 4);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006958 /* if link is up print the AN outcome of the SFX7101 PHY */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006959 if (link_up) {
6960 bnx2x_cl45_read(bp, phy,
6961 MDIO_AN_DEVAD, MDIO_AN_REG_MASTER_STATUS,
6962 &val2);
6963 vars->line_speed = SPEED_10000;
Yaniv Rosner791f18c2011-01-18 04:33:42 +00006964 vars->duplex = DUPLEX_FULL;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006965 DP(NETIF_MSG_LINK, "SFX7101 AN status 0x%x->Master=%x\n",
6966 val2, (val2 & (1<<14)));
6967 bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
6968 bnx2x_ext_phy_resolve_fc(phy, params, vars);
6969 }
6970 return link_up;
6971}
6972
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006973static int bnx2x_7101_format_ver(u32 spirom_ver, u8 *str, u16 *len)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006974{
6975 if (*len < 5)
6976 return -EINVAL;
6977 str[0] = (spirom_ver & 0xFF);
6978 str[1] = (spirom_ver & 0xFF00) >> 8;
6979 str[2] = (spirom_ver & 0xFF0000) >> 16;
6980 str[3] = (spirom_ver & 0xFF000000) >> 24;
6981 str[4] = '\0';
6982 *len -= 5;
6983 return 0;
6984}
6985
6986void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, struct bnx2x_phy *phy)
6987{
6988 u16 val, cnt;
6989
6990 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006991 MDIO_PMA_DEVAD,
6992 MDIO_PMA_REG_7101_RESET, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006993
6994 for (cnt = 0; cnt < 10; cnt++) {
6995 msleep(50);
6996 /* Writes a self-clearing reset */
6997 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006998 MDIO_PMA_DEVAD,
6999 MDIO_PMA_REG_7101_RESET,
7000 (val | (1<<15)));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007001 /* Wait for clear */
7002 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007003 MDIO_PMA_DEVAD,
7004 MDIO_PMA_REG_7101_RESET, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007005
7006 if ((val & (1<<15)) == 0)
7007 break;
7008 }
7009}
7010
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007011static void bnx2x_7101_hw_reset(struct bnx2x_phy *phy,
7012 struct link_params *params) {
7013 /* Low power mode is controlled by GPIO 2 */
7014 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007015 MISC_REGISTERS_GPIO_OUTPUT_LOW, params->port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007016 /* The PHY reset is controlled by GPIO 1 */
7017 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007018 MISC_REGISTERS_GPIO_OUTPUT_LOW, params->port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007019}
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007020
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00007021static void bnx2x_7101_set_link_led(struct bnx2x_phy *phy,
7022 struct link_params *params, u8 mode)
7023{
7024 u16 val = 0;
7025 struct bnx2x *bp = params->bp;
7026 switch (mode) {
7027 case LED_MODE_FRONT_PANEL_OFF:
7028 case LED_MODE_OFF:
7029 val = 2;
7030 break;
7031 case LED_MODE_ON:
7032 val = 1;
7033 break;
7034 case LED_MODE_OPER:
7035 val = 0;
7036 break;
7037 }
7038 bnx2x_cl45_write(bp, phy,
7039 MDIO_PMA_DEVAD,
7040 MDIO_PMA_REG_7107_LINK_LED_CNTL,
7041 val);
7042}
7043
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007044/******************************************************************/
7045/* STATIC PHY DECLARATION */
7046/******************************************************************/
7047
7048static struct bnx2x_phy phy_null = {
7049 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN,
7050 .addr = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007051 .def_md_devad = 0,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00007052 .flags = FLAGS_INIT_XGXS_FIRST,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007053 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7054 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7055 .mdio_ctrl = 0,
7056 .supported = 0,
7057 .media_type = ETH_PHY_NOT_PRESENT,
7058 .ver_addr = 0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007059 .req_flow_ctrl = 0,
7060 .req_line_speed = 0,
7061 .speed_cap_mask = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007062 .req_duplex = 0,
7063 .rsrv = 0,
7064 .config_init = (config_init_t)NULL,
7065 .read_status = (read_status_t)NULL,
7066 .link_reset = (link_reset_t)NULL,
7067 .config_loopback = (config_loopback_t)NULL,
7068 .format_fw_ver = (format_fw_ver_t)NULL,
7069 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007070 .set_link_led = (set_link_led_t)NULL,
7071 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007072};
7073
7074static struct bnx2x_phy phy_serdes = {
7075 .type = PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT,
7076 .addr = 0xff,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007077 .def_md_devad = 0,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00007078 .flags = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007079 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7080 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7081 .mdio_ctrl = 0,
7082 .supported = (SUPPORTED_10baseT_Half |
7083 SUPPORTED_10baseT_Full |
7084 SUPPORTED_100baseT_Half |
7085 SUPPORTED_100baseT_Full |
7086 SUPPORTED_1000baseT_Full |
7087 SUPPORTED_2500baseX_Full |
7088 SUPPORTED_TP |
7089 SUPPORTED_Autoneg |
7090 SUPPORTED_Pause |
7091 SUPPORTED_Asym_Pause),
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00007092 .media_type = ETH_PHY_BASE_T,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007093 .ver_addr = 0,
7094 .req_flow_ctrl = 0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007095 .req_line_speed = 0,
7096 .speed_cap_mask = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007097 .req_duplex = 0,
7098 .rsrv = 0,
Yaniv Rosnerec146a62011-05-31 21:29:27 +00007099 .config_init = (config_init_t)bnx2x_xgxs_config_init,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007100 .read_status = (read_status_t)bnx2x_link_settings_status,
7101 .link_reset = (link_reset_t)bnx2x_int_link_reset,
7102 .config_loopback = (config_loopback_t)NULL,
7103 .format_fw_ver = (format_fw_ver_t)NULL,
7104 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007105 .set_link_led = (set_link_led_t)NULL,
7106 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007107};
7108
7109static struct bnx2x_phy phy_xgxs = {
7110 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT,
7111 .addr = 0xff,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007112 .def_md_devad = 0,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00007113 .flags = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007114 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7115 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7116 .mdio_ctrl = 0,
7117 .supported = (SUPPORTED_10baseT_Half |
7118 SUPPORTED_10baseT_Full |
7119 SUPPORTED_100baseT_Half |
7120 SUPPORTED_100baseT_Full |
7121 SUPPORTED_1000baseT_Full |
7122 SUPPORTED_2500baseX_Full |
7123 SUPPORTED_10000baseT_Full |
7124 SUPPORTED_FIBRE |
7125 SUPPORTED_Autoneg |
7126 SUPPORTED_Pause |
7127 SUPPORTED_Asym_Pause),
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00007128 .media_type = ETH_PHY_CX4,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007129 .ver_addr = 0,
7130 .req_flow_ctrl = 0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007131 .req_line_speed = 0,
7132 .speed_cap_mask = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007133 .req_duplex = 0,
7134 .rsrv = 0,
Yaniv Rosnerec146a62011-05-31 21:29:27 +00007135 .config_init = (config_init_t)bnx2x_xgxs_config_init,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007136 .read_status = (read_status_t)bnx2x_link_settings_status,
7137 .link_reset = (link_reset_t)bnx2x_int_link_reset,
7138 .config_loopback = (config_loopback_t)bnx2x_set_xgxs_loopback,
7139 .format_fw_ver = (format_fw_ver_t)NULL,
7140 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007141 .set_link_led = (set_link_led_t)NULL,
7142 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007143};
7144
7145static struct bnx2x_phy phy_7101 = {
7146 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
7147 .addr = 0xff,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007148 .def_md_devad = 0,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00007149 .flags = FLAGS_FAN_FAILURE_DET_REQ,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007150 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7151 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7152 .mdio_ctrl = 0,
7153 .supported = (SUPPORTED_10000baseT_Full |
7154 SUPPORTED_TP |
7155 SUPPORTED_Autoneg |
7156 SUPPORTED_Pause |
7157 SUPPORTED_Asym_Pause),
7158 .media_type = ETH_PHY_BASE_T,
7159 .ver_addr = 0,
7160 .req_flow_ctrl = 0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007161 .req_line_speed = 0,
7162 .speed_cap_mask = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007163 .req_duplex = 0,
7164 .rsrv = 0,
7165 .config_init = (config_init_t)bnx2x_7101_config_init,
7166 .read_status = (read_status_t)bnx2x_7101_read_status,
7167 .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
7168 .config_loopback = (config_loopback_t)bnx2x_7101_config_loopback,
7169 .format_fw_ver = (format_fw_ver_t)bnx2x_7101_format_ver,
7170 .hw_reset = (hw_reset_t)bnx2x_7101_hw_reset,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00007171 .set_link_led = (set_link_led_t)bnx2x_7101_set_link_led,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007172 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007173};
7174static struct bnx2x_phy phy_8073 = {
7175 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
7176 .addr = 0xff,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007177 .def_md_devad = 0,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00007178 .flags = FLAGS_HW_LOCK_REQUIRED,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007179 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7180 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7181 .mdio_ctrl = 0,
7182 .supported = (SUPPORTED_10000baseT_Full |
7183 SUPPORTED_2500baseX_Full |
7184 SUPPORTED_1000baseT_Full |
7185 SUPPORTED_FIBRE |
7186 SUPPORTED_Autoneg |
7187 SUPPORTED_Pause |
7188 SUPPORTED_Asym_Pause),
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00007189 .media_type = ETH_PHY_KR,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007190 .ver_addr = 0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007191 .req_flow_ctrl = 0,
7192 .req_line_speed = 0,
7193 .speed_cap_mask = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007194 .req_duplex = 0,
7195 .rsrv = 0,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00007196 .config_init = (config_init_t)bnx2x_8073_config_init,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007197 .read_status = (read_status_t)bnx2x_8073_read_status,
7198 .link_reset = (link_reset_t)bnx2x_8073_link_reset,
7199 .config_loopback = (config_loopback_t)NULL,
7200 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
7201 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007202 .set_link_led = (set_link_led_t)NULL,
7203 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007204};
7205static struct bnx2x_phy phy_8705 = {
7206 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705,
7207 .addr = 0xff,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007208 .def_md_devad = 0,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00007209 .flags = FLAGS_INIT_XGXS_FIRST,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007210 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7211 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7212 .mdio_ctrl = 0,
7213 .supported = (SUPPORTED_10000baseT_Full |
7214 SUPPORTED_FIBRE |
7215 SUPPORTED_Pause |
7216 SUPPORTED_Asym_Pause),
7217 .media_type = ETH_PHY_XFP_FIBER,
7218 .ver_addr = 0,
7219 .req_flow_ctrl = 0,
7220 .req_line_speed = 0,
7221 .speed_cap_mask = 0,
7222 .req_duplex = 0,
7223 .rsrv = 0,
7224 .config_init = (config_init_t)bnx2x_8705_config_init,
7225 .read_status = (read_status_t)bnx2x_8705_read_status,
7226 .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
7227 .config_loopback = (config_loopback_t)NULL,
7228 .format_fw_ver = (format_fw_ver_t)bnx2x_null_format_ver,
7229 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007230 .set_link_led = (set_link_led_t)NULL,
7231 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007232};
7233static struct bnx2x_phy phy_8706 = {
7234 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706,
7235 .addr = 0xff,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007236 .def_md_devad = 0,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00007237 .flags = FLAGS_INIT_XGXS_FIRST,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007238 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7239 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7240 .mdio_ctrl = 0,
7241 .supported = (SUPPORTED_10000baseT_Full |
7242 SUPPORTED_1000baseT_Full |
7243 SUPPORTED_FIBRE |
7244 SUPPORTED_Pause |
7245 SUPPORTED_Asym_Pause),
7246 .media_type = ETH_PHY_SFP_FIBER,
7247 .ver_addr = 0,
7248 .req_flow_ctrl = 0,
7249 .req_line_speed = 0,
7250 .speed_cap_mask = 0,
7251 .req_duplex = 0,
7252 .rsrv = 0,
7253 .config_init = (config_init_t)bnx2x_8706_config_init,
7254 .read_status = (read_status_t)bnx2x_8706_read_status,
7255 .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
7256 .config_loopback = (config_loopback_t)NULL,
7257 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
7258 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007259 .set_link_led = (set_link_led_t)NULL,
7260 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007261};
7262
7263static struct bnx2x_phy phy_8726 = {
7264 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
7265 .addr = 0xff,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00007266 .def_md_devad = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007267 .flags = (FLAGS_HW_LOCK_REQUIRED |
7268 FLAGS_INIT_XGXS_FIRST),
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007269 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7270 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7271 .mdio_ctrl = 0,
7272 .supported = (SUPPORTED_10000baseT_Full |
7273 SUPPORTED_1000baseT_Full |
7274 SUPPORTED_Autoneg |
7275 SUPPORTED_FIBRE |
7276 SUPPORTED_Pause |
7277 SUPPORTED_Asym_Pause),
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00007278 .media_type = ETH_PHY_NOT_PRESENT,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007279 .ver_addr = 0,
7280 .req_flow_ctrl = 0,
7281 .req_line_speed = 0,
7282 .speed_cap_mask = 0,
7283 .req_duplex = 0,
7284 .rsrv = 0,
7285 .config_init = (config_init_t)bnx2x_8726_config_init,
7286 .read_status = (read_status_t)bnx2x_8726_read_status,
7287 .link_reset = (link_reset_t)bnx2x_8726_link_reset,
7288 .config_loopback = (config_loopback_t)bnx2x_8726_config_loopback,
7289 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
7290 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007291 .set_link_led = (set_link_led_t)NULL,
7292 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007293};
7294
7295static struct bnx2x_phy phy_8727 = {
7296 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
7297 .addr = 0xff,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007298 .def_md_devad = 0,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00007299 .flags = FLAGS_FAN_FAILURE_DET_REQ,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007300 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7301 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7302 .mdio_ctrl = 0,
7303 .supported = (SUPPORTED_10000baseT_Full |
7304 SUPPORTED_1000baseT_Full |
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007305 SUPPORTED_FIBRE |
7306 SUPPORTED_Pause |
7307 SUPPORTED_Asym_Pause),
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00007308 .media_type = ETH_PHY_NOT_PRESENT,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007309 .ver_addr = 0,
7310 .req_flow_ctrl = 0,
7311 .req_line_speed = 0,
7312 .speed_cap_mask = 0,
7313 .req_duplex = 0,
7314 .rsrv = 0,
7315 .config_init = (config_init_t)bnx2x_8727_config_init,
7316 .read_status = (read_status_t)bnx2x_8727_read_status,
7317 .link_reset = (link_reset_t)bnx2x_8727_link_reset,
7318 .config_loopback = (config_loopback_t)NULL,
7319 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
7320 .hw_reset = (hw_reset_t)bnx2x_8727_hw_reset,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00007321 .set_link_led = (set_link_led_t)bnx2x_8727_set_link_led,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007322 .phy_specific_func = (phy_specific_func_t)bnx2x_8727_specific_func
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007323};
7324static struct bnx2x_phy phy_8481 = {
7325 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
7326 .addr = 0xff,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00007327 .def_md_devad = 0,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007328 .flags = FLAGS_FAN_FAILURE_DET_REQ |
7329 FLAGS_REARM_LATCH_SIGNAL,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007330 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7331 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7332 .mdio_ctrl = 0,
7333 .supported = (SUPPORTED_10baseT_Half |
7334 SUPPORTED_10baseT_Full |
7335 SUPPORTED_100baseT_Half |
7336 SUPPORTED_100baseT_Full |
7337 SUPPORTED_1000baseT_Full |
7338 SUPPORTED_10000baseT_Full |
7339 SUPPORTED_TP |
7340 SUPPORTED_Autoneg |
7341 SUPPORTED_Pause |
7342 SUPPORTED_Asym_Pause),
7343 .media_type = ETH_PHY_BASE_T,
7344 .ver_addr = 0,
7345 .req_flow_ctrl = 0,
7346 .req_line_speed = 0,
7347 .speed_cap_mask = 0,
7348 .req_duplex = 0,
7349 .rsrv = 0,
7350 .config_init = (config_init_t)bnx2x_8481_config_init,
7351 .read_status = (read_status_t)bnx2x_848xx_read_status,
7352 .link_reset = (link_reset_t)bnx2x_8481_link_reset,
7353 .config_loopback = (config_loopback_t)NULL,
7354 .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver,
7355 .hw_reset = (hw_reset_t)bnx2x_8481_hw_reset,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00007356 .set_link_led = (set_link_led_t)bnx2x_848xx_set_link_led,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007357 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007358};
7359
7360static struct bnx2x_phy phy_84823 = {
7361 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823,
7362 .addr = 0xff,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00007363 .def_md_devad = 0,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007364 .flags = FLAGS_FAN_FAILURE_DET_REQ |
7365 FLAGS_REARM_LATCH_SIGNAL,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007366 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7367 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7368 .mdio_ctrl = 0,
7369 .supported = (SUPPORTED_10baseT_Half |
7370 SUPPORTED_10baseT_Full |
7371 SUPPORTED_100baseT_Half |
7372 SUPPORTED_100baseT_Full |
7373 SUPPORTED_1000baseT_Full |
7374 SUPPORTED_10000baseT_Full |
7375 SUPPORTED_TP |
7376 SUPPORTED_Autoneg |
7377 SUPPORTED_Pause |
7378 SUPPORTED_Asym_Pause),
7379 .media_type = ETH_PHY_BASE_T,
7380 .ver_addr = 0,
7381 .req_flow_ctrl = 0,
7382 .req_line_speed = 0,
7383 .speed_cap_mask = 0,
7384 .req_duplex = 0,
7385 .rsrv = 0,
7386 .config_init = (config_init_t)bnx2x_848x3_config_init,
7387 .read_status = (read_status_t)bnx2x_848xx_read_status,
7388 .link_reset = (link_reset_t)bnx2x_848x3_link_reset,
7389 .config_loopback = (config_loopback_t)NULL,
7390 .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver,
7391 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00007392 .set_link_led = (set_link_led_t)bnx2x_848xx_set_link_led,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007393 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007394};
7395
Yaniv Rosnerc87bca12011-01-31 04:22:41 +00007396static struct bnx2x_phy phy_84833 = {
7397 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833,
7398 .addr = 0xff,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00007399 .def_md_devad = 0,
Yaniv Rosnerc87bca12011-01-31 04:22:41 +00007400 .flags = FLAGS_FAN_FAILURE_DET_REQ |
7401 FLAGS_REARM_LATCH_SIGNAL,
Yaniv Rosnerc87bca12011-01-31 04:22:41 +00007402 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7403 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
7404 .mdio_ctrl = 0,
7405 .supported = (SUPPORTED_10baseT_Half |
7406 SUPPORTED_10baseT_Full |
7407 SUPPORTED_100baseT_Half |
7408 SUPPORTED_100baseT_Full |
7409 SUPPORTED_1000baseT_Full |
7410 SUPPORTED_10000baseT_Full |
7411 SUPPORTED_TP |
7412 SUPPORTED_Autoneg |
7413 SUPPORTED_Pause |
7414 SUPPORTED_Asym_Pause),
7415 .media_type = ETH_PHY_BASE_T,
7416 .ver_addr = 0,
7417 .req_flow_ctrl = 0,
7418 .req_line_speed = 0,
7419 .speed_cap_mask = 0,
7420 .req_duplex = 0,
7421 .rsrv = 0,
7422 .config_init = (config_init_t)bnx2x_848x3_config_init,
7423 .read_status = (read_status_t)bnx2x_848xx_read_status,
7424 .link_reset = (link_reset_t)bnx2x_848x3_link_reset,
7425 .config_loopback = (config_loopback_t)NULL,
7426 .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver,
7427 .hw_reset = (hw_reset_t)NULL,
7428 .set_link_led = (set_link_led_t)bnx2x_848xx_set_link_led,
7429 .phy_specific_func = (phy_specific_func_t)NULL
7430};
7431
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007432/*****************************************************************/
7433/* */
7434/* Populate the phy according. Main function: bnx2x_populate_phy */
7435/* */
7436/*****************************************************************/
7437
7438static void bnx2x_populate_preemphasis(struct bnx2x *bp, u32 shmem_base,
7439 struct bnx2x_phy *phy, u8 port,
7440 u8 phy_index)
7441{
7442 /* Get the 4 lanes xgxs config rx and tx */
7443 u32 rx = 0, tx = 0, i;
7444 for (i = 0; i < 2; i++) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007445 /*
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007446 * INT_PHY and EXT_PHY1 share the same value location in the
7447 * shmem. When num_phys is greater than 1, than this value
7448 * applies only to EXT_PHY1
7449 */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007450 if (phy_index == INT_PHY || phy_index == EXT_PHY1) {
7451 rx = REG_RD(bp, shmem_base +
7452 offsetof(struct shmem_region,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007453 dev_info.port_hw_config[port].xgxs_config_rx[i<<1]));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007454
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007455 tx = REG_RD(bp, shmem_base +
7456 offsetof(struct shmem_region,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007457 dev_info.port_hw_config[port].xgxs_config_tx[i<<1]));
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007458 } else {
7459 rx = REG_RD(bp, shmem_base +
7460 offsetof(struct shmem_region,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007461 dev_info.port_hw_config[port].xgxs_config2_rx[i<<1]));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007462
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007463 tx = REG_RD(bp, shmem_base +
7464 offsetof(struct shmem_region,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007465 dev_info.port_hw_config[port].xgxs_config2_rx[i<<1]));
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007466 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007467
7468 phy->rx_preemphasis[i << 1] = ((rx>>16) & 0xffff);
7469 phy->rx_preemphasis[(i << 1) + 1] = (rx & 0xffff);
7470
7471 phy->tx_preemphasis[i << 1] = ((tx>>16) & 0xffff);
7472 phy->tx_preemphasis[(i << 1) + 1] = (tx & 0xffff);
7473 }
7474}
7475
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007476static u32 bnx2x_get_ext_phy_config(struct bnx2x *bp, u32 shmem_base,
7477 u8 phy_index, u8 port)
7478{
7479 u32 ext_phy_config = 0;
7480 switch (phy_index) {
7481 case EXT_PHY1:
7482 ext_phy_config = REG_RD(bp, shmem_base +
7483 offsetof(struct shmem_region,
7484 dev_info.port_hw_config[port].external_phy_config));
7485 break;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007486 case EXT_PHY2:
7487 ext_phy_config = REG_RD(bp, shmem_base +
7488 offsetof(struct shmem_region,
7489 dev_info.port_hw_config[port].external_phy_config2));
7490 break;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007491 default:
7492 DP(NETIF_MSG_LINK, "Invalid phy_index %d\n", phy_index);
7493 return -EINVAL;
7494 }
7495
7496 return ext_phy_config;
7497}
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00007498static int bnx2x_populate_int_phy(struct bnx2x *bp, u32 shmem_base, u8 port,
7499 struct bnx2x_phy *phy)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007500{
7501 u32 phy_addr;
7502 u32 chip_id;
7503 u32 switch_cfg = (REG_RD(bp, shmem_base +
7504 offsetof(struct shmem_region,
7505 dev_info.port_feature_config[port].link_config)) &
7506 PORT_FEATURE_CONNECTED_SWITCH_MASK);
7507 chip_id = REG_RD(bp, MISC_REG_CHIP_NUM) << 16;
7508 switch (switch_cfg) {
7509 case SWITCH_CFG_1G:
7510 phy_addr = REG_RD(bp,
7511 NIG_REG_SERDES0_CTRL_PHY_ADDR +
7512 port * 0x10);
7513 *phy = phy_serdes;
7514 break;
7515 case SWITCH_CFG_10G:
7516 phy_addr = REG_RD(bp,
7517 NIG_REG_XGXS0_CTRL_PHY_ADDR +
7518 port * 0x18);
7519 *phy = phy_xgxs;
7520 break;
7521 default:
7522 DP(NETIF_MSG_LINK, "Invalid switch_cfg\n");
7523 return -EINVAL;
7524 }
7525 phy->addr = (u8)phy_addr;
7526 phy->mdio_ctrl = bnx2x_get_emac_base(bp,
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007527 SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007528 port);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007529 if (CHIP_IS_E2(bp))
7530 phy->def_md_devad = E2_DEFAULT_PHY_DEV_ADDR;
7531 else
7532 phy->def_md_devad = DEFAULT_PHY_DEV_ADDR;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007533
7534 DP(NETIF_MSG_LINK, "Internal phy port=%d, addr=0x%x, mdio_ctl=0x%x\n",
7535 port, phy->addr, phy->mdio_ctrl);
7536
7537 bnx2x_populate_preemphasis(bp, shmem_base, phy, port, INT_PHY);
7538 return 0;
7539}
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007540
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00007541static int bnx2x_populate_ext_phy(struct bnx2x *bp,
7542 u8 phy_index,
7543 u32 shmem_base,
7544 u32 shmem2_base,
7545 u8 port,
7546 struct bnx2x_phy *phy)
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007547{
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007548 u32 ext_phy_config, phy_type, config2;
7549 u32 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007550 ext_phy_config = bnx2x_get_ext_phy_config(bp, shmem_base,
7551 phy_index, port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007552 phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
7553 /* Select the phy type */
7554 switch (phy_type) {
7555 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007556 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_SWAPPED;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007557 *phy = phy_8073;
7558 break;
7559 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
7560 *phy = phy_8705;
7561 break;
7562 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
7563 *phy = phy_8706;
7564 break;
7565 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007566 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007567 *phy = phy_8726;
7568 break;
7569 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
7570 /* BCM8727_NOC => BCM8727 no over current */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007571 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007572 *phy = phy_8727;
7573 phy->flags |= FLAGS_NOC;
7574 break;
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00007575 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722:
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007576 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007577 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007578 *phy = phy_8727;
7579 break;
7580 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
7581 *phy = phy_8481;
7582 break;
7583 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
7584 *phy = phy_84823;
7585 break;
Yaniv Rosnerc87bca12011-01-31 04:22:41 +00007586 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833:
7587 *phy = phy_84833;
7588 break;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007589 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
7590 *phy = phy_7101;
7591 break;
7592 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
7593 *phy = phy_null;
7594 return -EINVAL;
7595 default:
7596 *phy = phy_null;
7597 return 0;
7598 }
7599
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007600 phy->addr = XGXS_EXT_PHY_ADDR(ext_phy_config);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007601 bnx2x_populate_preemphasis(bp, shmem_base, phy, port, phy_index);
Yaniv Rosner62b29a52010-09-07 11:40:58 +00007602
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007603 /*
7604 * The shmem address of the phy version is located on different
7605 * structures. In case this structure is too old, do not set
7606 * the address
7607 */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007608 config2 = REG_RD(bp, shmem_base + offsetof(struct shmem_region,
7609 dev_info.shared_hw_config.config2));
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007610 if (phy_index == EXT_PHY1) {
7611 phy->ver_addr = shmem_base + offsetof(struct shmem_region,
7612 port_mb[port].ext_phy_fw_version);
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007613
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007614 /* Check specific mdc mdio settings */
7615 if (config2 & SHARED_HW_CFG_MDC_MDIO_ACCESS1_MASK)
7616 mdc_mdio_access = config2 &
7617 SHARED_HW_CFG_MDC_MDIO_ACCESS1_MASK;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007618 } else {
7619 u32 size = REG_RD(bp, shmem2_base);
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007620
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007621 if (size >
7622 offsetof(struct shmem2_region, ext_phy_fw_version2)) {
7623 phy->ver_addr = shmem2_base +
7624 offsetof(struct shmem2_region,
7625 ext_phy_fw_version2[port]);
7626 }
7627 /* Check specific mdc mdio settings */
7628 if (config2 & SHARED_HW_CFG_MDC_MDIO_ACCESS2_MASK)
7629 mdc_mdio_access = (config2 &
7630 SHARED_HW_CFG_MDC_MDIO_ACCESS2_MASK) >>
7631 (SHARED_HW_CFG_MDC_MDIO_ACCESS2_SHIFT -
7632 SHARED_HW_CFG_MDC_MDIO_ACCESS1_SHIFT);
7633 }
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007634 phy->mdio_ctrl = bnx2x_get_emac_base(bp, mdc_mdio_access, port);
7635
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007636 /*
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007637 * In case mdc/mdio_access of the external phy is different than the
7638 * mdc/mdio access of the XGXS, a HW lock must be taken in each access
7639 * to prevent one port interfere with another port's CL45 operations.
7640 */
7641 if (mdc_mdio_access != SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH)
7642 phy->flags |= FLAGS_HW_LOCK_REQUIRED;
7643 DP(NETIF_MSG_LINK, "phy_type 0x%x port %d found in index %d\n",
7644 phy_type, port, phy_index);
7645 DP(NETIF_MSG_LINK, " addr=0x%x, mdio_ctl=0x%x\n",
7646 phy->addr, phy->mdio_ctrl);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007647 return 0;
7648}
7649
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00007650static int bnx2x_populate_phy(struct bnx2x *bp, u8 phy_index, u32 shmem_base,
7651 u32 shmem2_base, u8 port, struct bnx2x_phy *phy)
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007652{
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00007653 int status = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007654 phy->type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN;
7655 if (phy_index == INT_PHY)
7656 return bnx2x_populate_int_phy(bp, shmem_base, port, phy);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007657 status = bnx2x_populate_ext_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007658 port, phy);
7659 return status;
7660}
7661
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007662static void bnx2x_phy_def_cfg(struct link_params *params,
7663 struct bnx2x_phy *phy,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007664 u8 phy_index)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007665{
7666 struct bnx2x *bp = params->bp;
7667 u32 link_config;
7668 /* Populate the default phy configuration for MF mode */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007669 if (phy_index == EXT_PHY2) {
7670 link_config = REG_RD(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007671 offsetof(struct shmem_region, dev_info.
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007672 port_feature_config[params->port].link_config2));
7673 phy->speed_cap_mask = REG_RD(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007674 offsetof(struct shmem_region,
7675 dev_info.
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007676 port_hw_config[params->port].speed_capability_mask2));
7677 } else {
7678 link_config = REG_RD(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007679 offsetof(struct shmem_region, dev_info.
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007680 port_feature_config[params->port].link_config));
7681 phy->speed_cap_mask = REG_RD(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007682 offsetof(struct shmem_region,
7683 dev_info.
7684 port_hw_config[params->port].speed_capability_mask));
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007685 }
7686 DP(NETIF_MSG_LINK, "Default config phy idx %x cfg 0x%x speed_cap_mask"
7687 " 0x%x\n", phy_index, link_config, phy->speed_cap_mask);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007688
7689 phy->req_duplex = DUPLEX_FULL;
7690 switch (link_config & PORT_FEATURE_LINK_SPEED_MASK) {
7691 case PORT_FEATURE_LINK_SPEED_10M_HALF:
7692 phy->req_duplex = DUPLEX_HALF;
7693 case PORT_FEATURE_LINK_SPEED_10M_FULL:
7694 phy->req_line_speed = SPEED_10;
7695 break;
7696 case PORT_FEATURE_LINK_SPEED_100M_HALF:
7697 phy->req_duplex = DUPLEX_HALF;
7698 case PORT_FEATURE_LINK_SPEED_100M_FULL:
7699 phy->req_line_speed = SPEED_100;
7700 break;
7701 case PORT_FEATURE_LINK_SPEED_1G:
7702 phy->req_line_speed = SPEED_1000;
7703 break;
7704 case PORT_FEATURE_LINK_SPEED_2_5G:
7705 phy->req_line_speed = SPEED_2500;
7706 break;
7707 case PORT_FEATURE_LINK_SPEED_10G_CX4:
7708 phy->req_line_speed = SPEED_10000;
7709 break;
7710 default:
7711 phy->req_line_speed = SPEED_AUTO_NEG;
7712 break;
7713 }
7714
7715 switch (link_config & PORT_FEATURE_FLOW_CONTROL_MASK) {
7716 case PORT_FEATURE_FLOW_CONTROL_AUTO:
7717 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_AUTO;
7718 break;
7719 case PORT_FEATURE_FLOW_CONTROL_TX:
7720 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_TX;
7721 break;
7722 case PORT_FEATURE_FLOW_CONTROL_RX:
7723 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_RX;
7724 break;
7725 case PORT_FEATURE_FLOW_CONTROL_BOTH:
7726 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_BOTH;
7727 break;
7728 default:
7729 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_NONE;
7730 break;
7731 }
7732}
7733
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007734u32 bnx2x_phy_selection(struct link_params *params)
7735{
7736 u32 phy_config_swapped, prio_cfg;
7737 u32 return_cfg = PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT;
7738
7739 phy_config_swapped = params->multi_phy_config &
7740 PORT_HW_CFG_PHY_SWAPPED_ENABLED;
7741
7742 prio_cfg = params->multi_phy_config &
7743 PORT_HW_CFG_PHY_SELECTION_MASK;
7744
7745 if (phy_config_swapped) {
7746 switch (prio_cfg) {
7747 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
7748 return_cfg = PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY;
7749 break;
7750 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
7751 return_cfg = PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY;
7752 break;
7753 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY:
7754 return_cfg = PORT_HW_CFG_PHY_SELECTION_FIRST_PHY;
7755 break;
7756 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY:
7757 return_cfg = PORT_HW_CFG_PHY_SELECTION_SECOND_PHY;
7758 break;
7759 }
7760 } else
7761 return_cfg = prio_cfg;
7762
7763 return return_cfg;
7764}
7765
7766
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00007767int bnx2x_phy_probe(struct link_params *params)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007768{
7769 u8 phy_index, actual_phy_idx, link_cfg_idx;
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00007770 u32 phy_config_swapped, sync_offset, media_types;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007771 struct bnx2x *bp = params->bp;
7772 struct bnx2x_phy *phy;
7773 params->num_phys = 0;
7774 DP(NETIF_MSG_LINK, "Begin phy probe\n");
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007775 phy_config_swapped = params->multi_phy_config &
7776 PORT_HW_CFG_PHY_SWAPPED_ENABLED;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007777
7778 for (phy_index = INT_PHY; phy_index < MAX_PHYS;
7779 phy_index++) {
7780 link_cfg_idx = LINK_CONFIG_IDX(phy_index);
7781 actual_phy_idx = phy_index;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007782 if (phy_config_swapped) {
7783 if (phy_index == EXT_PHY1)
7784 actual_phy_idx = EXT_PHY2;
7785 else if (phy_index == EXT_PHY2)
7786 actual_phy_idx = EXT_PHY1;
7787 }
7788 DP(NETIF_MSG_LINK, "phy_config_swapped %x, phy_index %x,"
7789 " actual_phy_idx %x\n", phy_config_swapped,
7790 phy_index, actual_phy_idx);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007791 phy = &params->phy[actual_phy_idx];
7792 if (bnx2x_populate_phy(bp, phy_index, params->shmem_base,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007793 params->shmem2_base, params->port,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007794 phy) != 0) {
7795 params->num_phys = 0;
7796 DP(NETIF_MSG_LINK, "phy probe failed in phy index %d\n",
7797 phy_index);
7798 for (phy_index = INT_PHY;
7799 phy_index < MAX_PHYS;
7800 phy_index++)
7801 *phy = phy_null;
7802 return -EINVAL;
7803 }
7804 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)
7805 break;
7806
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00007807 sync_offset = params->shmem_base +
7808 offsetof(struct shmem_region,
7809 dev_info.port_hw_config[params->port].media_type);
7810 media_types = REG_RD(bp, sync_offset);
7811
7812 /*
7813 * Update media type for non-PMF sync only for the first time
7814 * In case the media type changes afterwards, it will be updated
7815 * using the update_status function
7816 */
7817 if ((media_types & (PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK <<
7818 (PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT *
7819 actual_phy_idx))) == 0) {
7820 media_types |= ((phy->media_type &
7821 PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK) <<
7822 (PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT *
7823 actual_phy_idx));
7824 }
7825 REG_WR(bp, sync_offset, media_types);
7826
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007827 bnx2x_phy_def_cfg(params, phy, phy_index);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007828 params->num_phys++;
7829 }
7830
7831 DP(NETIF_MSG_LINK, "End phy probe. #phys found %x\n", params->num_phys);
7832 return 0;
7833}
7834
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00007835void bnx2x_init_bmac_loopback(struct link_params *params,
7836 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007837{
7838 struct bnx2x *bp = params->bp;
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00007839 vars->link_up = 1;
7840 vars->line_speed = SPEED_10000;
7841 vars->duplex = DUPLEX_FULL;
7842 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
7843 vars->mac_type = MAC_TYPE_BMAC;
7844
7845 vars->phy_flags = PHY_XGXS_FLAG;
7846
7847 bnx2x_xgxs_deassert(params);
7848
7849 /* set bmac loopback */
7850 bnx2x_bmac_enable(params, vars, 1);
7851
7852 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
7853}
7854
7855void bnx2x_init_emac_loopback(struct link_params *params,
7856 struct link_vars *vars)
7857{
7858 struct bnx2x *bp = params->bp;
7859 vars->link_up = 1;
7860 vars->line_speed = SPEED_1000;
7861 vars->duplex = DUPLEX_FULL;
7862 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
7863 vars->mac_type = MAC_TYPE_EMAC;
7864
7865 vars->phy_flags = PHY_XGXS_FLAG;
7866
7867 bnx2x_xgxs_deassert(params);
7868 /* set bmac loopback */
7869 bnx2x_emac_enable(params, vars, 1);
7870 bnx2x_emac_program(params, vars);
7871 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
7872}
7873
7874void bnx2x_init_xgxs_loopback(struct link_params *params,
7875 struct link_vars *vars)
7876{
7877 struct bnx2x *bp = params->bp;
7878 vars->link_up = 1;
7879 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
7880 vars->duplex = DUPLEX_FULL;
7881 if (params->req_line_speed[0] == SPEED_1000)
7882 vars->line_speed = SPEED_1000;
7883 else
7884 vars->line_speed = SPEED_10000;
7885
7886
7887 bnx2x_xgxs_deassert(params);
7888 bnx2x_link_initialize(params, vars);
7889
7890 if (params->req_line_speed[0] == SPEED_1000) {
7891 bnx2x_emac_program(params, vars);
7892 bnx2x_emac_enable(params, vars, 0);
7893
7894 } else
7895 bnx2x_bmac_enable(params, vars, 0);
7896
7897
7898 if (params->loopback_mode == LOOPBACK_XGXS) {
7899 /* set 10G XGXS loopback */
7900 params->phy[INT_PHY].config_loopback(
7901 &params->phy[INT_PHY],
7902 params);
7903
7904 } else {
7905 /* set external phy loopback */
7906 u8 phy_index;
7907 for (phy_index = EXT_PHY1;
7908 phy_index < params->num_phys; phy_index++) {
7909 if (params->phy[phy_index].config_loopback)
7910 params->phy[phy_index].config_loopback(
7911 &params->phy[phy_index],
7912 params);
7913 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007914 }
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00007915 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007916
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00007917 bnx2x_set_led(params, vars, LED_MODE_OPER, vars->line_speed);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007918}
7919
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00007920int bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007921{
7922 struct bnx2x *bp = params->bp;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007923 DP(NETIF_MSG_LINK, "Phy Initialization started\n");
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007924 DP(NETIF_MSG_LINK, "(1) req_speed %d, req_flowctrl %d\n",
7925 params->req_line_speed[0], params->req_flow_ctrl[0]);
7926 DP(NETIF_MSG_LINK, "(2) req_speed %d, req_flowctrl %d\n",
7927 params->req_line_speed[1], params->req_flow_ctrl[1]);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007928 vars->link_status = 0;
7929 vars->phy_link_up = 0;
7930 vars->link_up = 0;
7931 vars->line_speed = 0;
7932 vars->duplex = DUPLEX_FULL;
7933 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
7934 vars->mac_type = MAC_TYPE_NONE;
7935 vars->phy_flags = 0;
7936
7937 /* disable attentions */
7938 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4,
7939 (NIG_MASK_XGXS0_LINK_STATUS |
7940 NIG_MASK_XGXS0_LINK10G |
7941 NIG_MASK_SERDES0_LINK_STATUS |
7942 NIG_MASK_MI_INT));
7943
7944 bnx2x_emac_init(params, vars);
7945
7946 if (params->num_phys == 0) {
7947 DP(NETIF_MSG_LINK, "No phy found for initialization !!\n");
7948 return -EINVAL;
7949 }
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00007950 set_phy_vars(params, vars);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007951
7952 DP(NETIF_MSG_LINK, "Num of phys on board: %d\n", params->num_phys);
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00007953 switch (params->loopback_mode) {
7954 case LOOPBACK_BMAC:
7955 bnx2x_init_bmac_loopback(params, vars);
7956 break;
7957 case LOOPBACK_EMAC:
7958 bnx2x_init_emac_loopback(params, vars);
7959 break;
7960 case LOOPBACK_XGXS:
7961 case LOOPBACK_EXT_PHY:
7962 bnx2x_init_xgxs_loopback(params, vars);
7963 break;
7964 default:
7965 /* No loopback */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007966 if (params->switch_cfg == SWITCH_CFG_10G)
7967 bnx2x_xgxs_deassert(params);
7968 else
7969 bnx2x_serdes_deassert(bp, params->port);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00007970
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007971 bnx2x_link_initialize(params, vars);
7972 msleep(30);
7973 bnx2x_link_int_enable(params);
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00007974 break;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007975 }
7976 return 0;
7977}
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00007978
7979int bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
7980 u8 reset_ext_phy)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007981{
7982 struct bnx2x *bp = params->bp;
Yaniv Rosnercf1d9722010-11-01 05:32:34 +00007983 u8 phy_index, port = params->port, clear_latch_ind = 0;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007984 DP(NETIF_MSG_LINK, "Resetting the link of port %d\n", port);
7985 /* disable attentions */
7986 vars->link_status = 0;
7987 bnx2x_update_mng(params, vars->link_status);
7988 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007989 (NIG_MASK_XGXS0_LINK_STATUS |
7990 NIG_MASK_XGXS0_LINK10G |
7991 NIG_MASK_SERDES0_LINK_STATUS |
7992 NIG_MASK_MI_INT));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007993
7994 /* activate nig drain */
7995 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
7996
7997 /* disable nig egress interface */
7998 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
7999 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
8000
8001 /* Stop BigMac rx */
8002 bnx2x_bmac_rx_disable(bp, port);
8003
8004 /* disable emac */
8005 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
8006
8007 msleep(10);
Lucas De Marchi25985ed2011-03-30 22:57:33 -03008008 /* The PHY reset is controlled by GPIO 1
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008009 * Hold it as vars low
8010 */
8011 /* clear link led */
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00008012 bnx2x_set_led(params, vars, LED_MODE_OFF, 0);
8013
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008014 if (reset_ext_phy) {
8015 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
8016 phy_index++) {
8017 if (params->phy[phy_index].link_reset)
8018 params->phy[phy_index].link_reset(
8019 &params->phy[phy_index],
8020 params);
Yaniv Rosnercf1d9722010-11-01 05:32:34 +00008021 if (params->phy[phy_index].flags &
8022 FLAGS_REARM_LATCH_SIGNAL)
8023 clear_latch_ind = 1;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008024 }
8025 }
8026
Yaniv Rosnercf1d9722010-11-01 05:32:34 +00008027 if (clear_latch_ind) {
8028 /* Clear latching indication */
8029 bnx2x_rearm_latch_signal(bp, port, 0);
8030 bnx2x_bits_dis(bp, NIG_REG_LATCH_BC_0 + port*4,
8031 1 << NIG_LATCH_BC_ENABLE_MI_INT);
8032 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008033 if (params->phy[INT_PHY].link_reset)
8034 params->phy[INT_PHY].link_reset(
8035 &params->phy[INT_PHY], params);
8036 /* reset BigMac */
8037 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
8038 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
8039
8040 /* disable nig ingress interface */
8041 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0);
8042 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0);
8043 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
8044 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
8045 vars->link_up = 0;
8046 return 0;
8047}
8048
8049/****************************************************************************/
8050/* Common function */
8051/****************************************************************************/
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00008052static int bnx2x_8073_common_init_phy(struct bnx2x *bp,
8053 u32 shmem_base_path[],
8054 u32 shmem2_base_path[], u8 phy_index,
8055 u32 chip_id)
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008056{
Yaniv Rosnere10bc842010-09-07 11:40:50 +00008057 struct bnx2x_phy phy[PORT_MAX];
8058 struct bnx2x_phy *phy_blk[PORT_MAX];
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008059 u16 val;
Yaniv Rosnerc8e64df2011-01-30 04:15:00 +00008060 s8 port = 0;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00008061 s8 port_of_path = 0;
Yaniv Rosnerc8e64df2011-01-30 04:15:00 +00008062 u32 swap_val, swap_override;
8063 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
8064 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
8065 port ^= (swap_val && swap_override);
8066 bnx2x_ext_phy_hw_reset(bp, port);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008067 /* PART1 - Reset both phys */
8068 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00008069 u32 shmem_base, shmem2_base;
8070 /* In E2, same phy is using for port0 of the two paths */
8071 if (CHIP_IS_E2(bp)) {
8072 shmem_base = shmem_base_path[port];
8073 shmem2_base = shmem2_base_path[port];
8074 port_of_path = 0;
8075 } else {
8076 shmem_base = shmem_base_path[0];
8077 shmem2_base = shmem2_base_path[0];
8078 port_of_path = port;
8079 }
8080
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008081 /* Extract the ext phy address for the port */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008082 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00008083 port_of_path, &phy[port]) !=
Yaniv Rosnere10bc842010-09-07 11:40:50 +00008084 0) {
8085 DP(NETIF_MSG_LINK, "populate_phy failed\n");
8086 return -EINVAL;
8087 }
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008088 /* disable attentions */
Yaniv Rosner6a71bbe2010-11-01 05:32:31 +00008089 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 +
8090 port_of_path*4,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008091 (NIG_MASK_XGXS0_LINK_STATUS |
8092 NIG_MASK_XGXS0_LINK10G |
8093 NIG_MASK_SERDES0_LINK_STATUS |
8094 NIG_MASK_MI_INT));
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008095
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008096 /* Need to take the phy out of low power mode in order
8097 to write to access its registers */
8098 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008099 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
8100 port);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008101
8102 /* Reset the phy */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00008103 bnx2x_cl45_write(bp, &phy[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008104 MDIO_PMA_DEVAD,
8105 MDIO_PMA_REG_CTRL,
8106 1<<15);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008107 }
8108
8109 /* Add delay of 150ms after reset */
8110 msleep(150);
8111
Yaniv Rosnere10bc842010-09-07 11:40:50 +00008112 if (phy[PORT_0].addr & 0x1) {
8113 phy_blk[PORT_0] = &(phy[PORT_1]);
8114 phy_blk[PORT_1] = &(phy[PORT_0]);
8115 } else {
8116 phy_blk[PORT_0] = &(phy[PORT_0]);
8117 phy_blk[PORT_1] = &(phy[PORT_1]);
8118 }
8119
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008120 /* PART2 - Download firmware to both phys */
8121 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00008122 if (CHIP_IS_E2(bp))
8123 port_of_path = 0;
8124 else
8125 port_of_path = port;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008126
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00008127 DP(NETIF_MSG_LINK, "Loading spirom for phy address 0x%x\n",
8128 phy_blk[port]->addr);
Yaniv Rosner5c99274b2011-01-18 04:33:36 +00008129 if (bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port],
8130 port_of_path))
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008131 return -EINVAL;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008132
8133 /* Only set bit 10 = 1 (Tx power down) */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00008134 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008135 MDIO_PMA_DEVAD,
8136 MDIO_PMA_REG_TX_POWER_DOWN, &val);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008137
8138 /* Phase1 of TX_POWER_DOWN reset */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00008139 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008140 MDIO_PMA_DEVAD,
8141 MDIO_PMA_REG_TX_POWER_DOWN,
8142 (val | 1<<10));
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008143 }
8144
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008145 /*
8146 * Toggle Transmitter: Power down and then up with 600ms delay
8147 * between
8148 */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008149 msleep(600);
8150
8151 /* PART3 - complete TX_POWER_DOWN process, and set GPIO2 back to low */
8152 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Eilon Greensteinf5372252009-02-12 08:38:30 +00008153 /* Phase2 of POWER_DOWN_RESET */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008154 /* Release bit 10 (Release Tx power down) */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00008155 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008156 MDIO_PMA_DEVAD,
8157 MDIO_PMA_REG_TX_POWER_DOWN, &val);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008158
Yaniv Rosnere10bc842010-09-07 11:40:50 +00008159 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008160 MDIO_PMA_DEVAD,
8161 MDIO_PMA_REG_TX_POWER_DOWN, (val & (~(1<<10))));
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008162 msleep(15);
8163
8164 /* Read modify write the SPI-ROM version select register */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00008165 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008166 MDIO_PMA_DEVAD,
8167 MDIO_PMA_REG_EDC_FFE_MAIN, &val);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00008168 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008169 MDIO_PMA_DEVAD,
8170 MDIO_PMA_REG_EDC_FFE_MAIN, (val | (1<<12)));
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008171
8172 /* set GPIO2 back to LOW */
8173 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008174 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008175 }
8176 return 0;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008177}
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00008178static int bnx2x_8726_common_init_phy(struct bnx2x *bp,
8179 u32 shmem_base_path[],
8180 u32 shmem2_base_path[], u8 phy_index,
8181 u32 chip_id)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008182{
8183 u32 val;
8184 s8 port;
8185 struct bnx2x_phy phy;
8186 /* Use port1 because of the static port-swap */
8187 /* Enable the module detection interrupt */
8188 val = REG_RD(bp, MISC_REG_GPIO_EVENT_EN);
8189 val |= ((1<<MISC_REGISTERS_GPIO_3)|
8190 (1<<(MISC_REGISTERS_GPIO_3 + MISC_REGISTERS_GPIO_PORT_SHIFT)));
8191 REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val);
8192
Yaniv Rosner650154b2010-11-01 05:32:36 +00008193 bnx2x_ext_phy_hw_reset(bp, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008194 msleep(5);
8195 for (port = 0; port < PORT_MAX; port++) {
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00008196 u32 shmem_base, shmem2_base;
8197
8198 /* In E2, same phy is using for port0 of the two paths */
8199 if (CHIP_IS_E2(bp)) {
8200 shmem_base = shmem_base_path[port];
8201 shmem2_base = shmem2_base_path[port];
8202 } else {
8203 shmem_base = shmem_base_path[0];
8204 shmem2_base = shmem2_base_path[0];
8205 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008206 /* Extract the ext phy address for the port */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008207 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008208 port, &phy) !=
8209 0) {
8210 DP(NETIF_MSG_LINK, "populate phy failed\n");
8211 return -EINVAL;
8212 }
8213
8214 /* Reset phy*/
8215 bnx2x_cl45_write(bp, &phy,
8216 MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, 0x0001);
8217
8218
8219 /* Set fault module detected LED on */
8220 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008221 MISC_REGISTERS_GPIO_HIGH,
8222 port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008223 }
8224
8225 return 0;
8226}
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00008227static void bnx2x_get_ext_phy_reset_gpio(struct bnx2x *bp, u32 shmem_base,
8228 u8 *io_gpio, u8 *io_port)
8229{
8230
8231 u32 phy_gpio_reset = REG_RD(bp, shmem_base +
8232 offsetof(struct shmem_region,
8233 dev_info.port_hw_config[PORT_0].default_cfg));
8234 switch (phy_gpio_reset) {
8235 case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO0_P0:
8236 *io_gpio = 0;
8237 *io_port = 0;
8238 break;
8239 case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO1_P0:
8240 *io_gpio = 1;
8241 *io_port = 0;
8242 break;
8243 case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO2_P0:
8244 *io_gpio = 2;
8245 *io_port = 0;
8246 break;
8247 case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO3_P0:
8248 *io_gpio = 3;
8249 *io_port = 0;
8250 break;
8251 case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO0_P1:
8252 *io_gpio = 0;
8253 *io_port = 1;
8254 break;
8255 case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO1_P1:
8256 *io_gpio = 1;
8257 *io_port = 1;
8258 break;
8259 case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO2_P1:
8260 *io_gpio = 2;
8261 *io_port = 1;
8262 break;
8263 case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO3_P1:
8264 *io_gpio = 3;
8265 *io_port = 1;
8266 break;
8267 default:
8268 /* Don't override the io_gpio and io_port */
8269 break;
8270 }
8271}
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00008272
8273static int bnx2x_8727_common_init_phy(struct bnx2x *bp,
8274 u32 shmem_base_path[],
8275 u32 shmem2_base_path[], u8 phy_index,
8276 u32 chip_id)
Eilon Greenstein4d295db2009-07-21 05:47:47 +00008277{
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00008278 s8 port, reset_gpio;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00008279 u32 swap_val, swap_override;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00008280 struct bnx2x_phy phy[PORT_MAX];
8281 struct bnx2x_phy *phy_blk[PORT_MAX];
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00008282 s8 port_of_path;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008283 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
8284 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00008285
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00008286 reset_gpio = MISC_REGISTERS_GPIO_1;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008287 port = 1;
8288
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00008289 /*
8290 * Retrieve the reset gpio/port which control the reset.
8291 * Default is GPIO1, PORT1
8292 */
8293 bnx2x_get_ext_phy_reset_gpio(bp, shmem_base_path[0],
8294 (u8 *)&reset_gpio, (u8 *)&port);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008295
8296 /* Calculate the port based on port swap */
8297 port ^= (swap_val && swap_override);
8298
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00008299 /* Initiate PHY reset*/
8300 bnx2x_set_gpio(bp, reset_gpio, MISC_REGISTERS_GPIO_OUTPUT_LOW,
8301 port);
8302 msleep(1);
8303 bnx2x_set_gpio(bp, reset_gpio, MISC_REGISTERS_GPIO_OUTPUT_HIGH,
8304 port);
8305
Eilon Greenstein4d295db2009-07-21 05:47:47 +00008306 msleep(5);
8307
8308 /* PART1 - Reset both phys */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008309 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00008310 u32 shmem_base, shmem2_base;
8311
8312 /* In E2, same phy is using for port0 of the two paths */
8313 if (CHIP_IS_E2(bp)) {
8314 shmem_base = shmem_base_path[port];
8315 shmem2_base = shmem2_base_path[port];
8316 port_of_path = 0;
8317 } else {
8318 shmem_base = shmem_base_path[0];
8319 shmem2_base = shmem2_base_path[0];
8320 port_of_path = port;
8321 }
8322
Eilon Greenstein4d295db2009-07-21 05:47:47 +00008323 /* Extract the ext phy address for the port */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008324 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00008325 port_of_path, &phy[port]) !=
Yaniv Rosnere10bc842010-09-07 11:40:50 +00008326 0) {
8327 DP(NETIF_MSG_LINK, "populate phy failed\n");
8328 return -EINVAL;
8329 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00008330 /* disable attentions */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00008331 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 +
8332 port_of_path*4,
8333 (NIG_MASK_XGXS0_LINK_STATUS |
8334 NIG_MASK_XGXS0_LINK10G |
8335 NIG_MASK_SERDES0_LINK_STATUS |
8336 NIG_MASK_MI_INT));
Eilon Greenstein4d295db2009-07-21 05:47:47 +00008337
Eilon Greenstein4d295db2009-07-21 05:47:47 +00008338
8339 /* Reset the phy */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00008340 bnx2x_cl45_write(bp, &phy[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008341 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00008342 }
8343
8344 /* Add delay of 150ms after reset */
8345 msleep(150);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00008346 if (phy[PORT_0].addr & 0x1) {
8347 phy_blk[PORT_0] = &(phy[PORT_1]);
8348 phy_blk[PORT_1] = &(phy[PORT_0]);
8349 } else {
8350 phy_blk[PORT_0] = &(phy[PORT_0]);
8351 phy_blk[PORT_1] = &(phy[PORT_1]);
8352 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00008353 /* PART2 - Download firmware to both phys */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00008354 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008355 if (CHIP_IS_E2(bp))
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00008356 port_of_path = 0;
8357 else
8358 port_of_path = port;
8359 DP(NETIF_MSG_LINK, "Loading spirom for phy address 0x%x\n",
8360 phy_blk[port]->addr);
Yaniv Rosner5c99274b2011-01-18 04:33:36 +00008361 if (bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port],
8362 port_of_path))
Eilon Greenstein4d295db2009-07-21 05:47:47 +00008363 return -EINVAL;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00008364
Yaniv Rosner5c99274b2011-01-18 04:33:36 +00008365 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00008366 return 0;
8367}
8368
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00008369static int bnx2x_ext_phy_common_init(struct bnx2x *bp, u32 shmem_base_path[],
8370 u32 shmem2_base_path[], u8 phy_index,
8371 u32 ext_phy_type, u32 chip_id)
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008372{
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00008373 int rc = 0;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008374
8375 switch (ext_phy_type) {
8376 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00008377 rc = bnx2x_8073_common_init_phy(bp, shmem_base_path,
8378 shmem2_base_path,
8379 phy_index, chip_id);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008380 break;
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00008381 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722:
Eilon Greenstein4d295db2009-07-21 05:47:47 +00008382 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
8383 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00008384 rc = bnx2x_8727_common_init_phy(bp, shmem_base_path,
8385 shmem2_base_path,
8386 phy_index, chip_id);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00008387 break;
8388
Eilon Greenstein589abe32009-02-12 08:36:55 +00008389 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008390 /*
8391 * GPIO1 affects both ports, so there's need to pull
8392 * it for single port alone
8393 */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00008394 rc = bnx2x_8726_common_init_phy(bp, shmem_base_path,
8395 shmem2_base_path,
8396 phy_index, chip_id);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008397 break;
8398 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
8399 rc = -EINVAL;
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02008400 break;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008401 default:
8402 DP(NETIF_MSG_LINK,
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008403 "ext_phy 0x%x common init not required\n",
8404 ext_phy_type);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008405 break;
8406 }
8407
Yaniv Rosner6d870c32011-01-31 04:22:20 +00008408 if (rc != 0)
8409 netdev_err(bp->dev, "Warning: PHY was not initialized,"
8410 " Port %d\n",
8411 0);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07008412 return rc;
8413}
8414
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00008415int bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base_path[],
8416 u32 shmem2_base_path[], u32 chip_id)
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008417{
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00008418 int rc = 0;
Yaniv Rosnerb21a3422011-01-18 04:33:24 +00008419 u32 phy_ver;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008420 u8 phy_index;
8421 u32 ext_phy_type, ext_phy_config;
Yaniv Rosnera198c142011-05-31 21:29:42 +00008422 bnx2x_set_mdio_clk(bp, chip_id, PORT_0);
8423 bnx2x_set_mdio_clk(bp, chip_id, PORT_1);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008424 DP(NETIF_MSG_LINK, "Begin common phy init\n");
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00008425
Yaniv Rosnerb21a3422011-01-18 04:33:24 +00008426 /* Check if common init was already done */
8427 phy_ver = REG_RD(bp, shmem_base_path[0] +
8428 offsetof(struct shmem_region,
8429 port_mb[PORT_0].ext_phy_fw_version));
8430 if (phy_ver) {
8431 DP(NETIF_MSG_LINK, "Not doing common init; phy ver is 0x%x\n",
8432 phy_ver);
8433 return 0;
8434 }
8435
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008436 /* Read the ext_phy_type for arbitrary port(0) */
8437 for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
8438 phy_index++) {
8439 ext_phy_config = bnx2x_get_ext_phy_config(bp,
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00008440 shmem_base_path[0],
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008441 phy_index, 0);
8442 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00008443 rc |= bnx2x_ext_phy_common_init(bp, shmem_base_path,
8444 shmem2_base_path,
8445 phy_index, ext_phy_type,
8446 chip_id);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008447 }
8448 return rc;
8449}
8450
8451u8 bnx2x_hw_lock_required(struct bnx2x *bp, u32 shmem_base, u32 shmem2_base)
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00008452{
8453 u8 phy_index;
8454 struct bnx2x_phy phy;
8455 for (phy_index = INT_PHY; phy_index < MAX_PHYS;
8456 phy_index++) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008457 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00008458 0, &phy) != 0) {
8459 DP(NETIF_MSG_LINK, "populate phy failed\n");
8460 return 0;
8461 }
8462
8463 if (phy.flags & FLAGS_HW_LOCK_REQUIRED)
8464 return 1;
8465 }
8466 return 0;
8467}
8468
8469u8 bnx2x_fan_failure_det_req(struct bnx2x *bp,
8470 u32 shmem_base,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008471 u32 shmem2_base,
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00008472 u8 port)
8473{
8474 u8 phy_index, fan_failure_det_req = 0;
8475 struct bnx2x_phy phy;
8476 for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
8477 phy_index++) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008478 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00008479 port, &phy)
8480 != 0) {
8481 DP(NETIF_MSG_LINK, "populate phy failed\n");
8482 return 0;
8483 }
8484 fan_failure_det_req |= (phy.flags &
8485 FLAGS_FAN_FAILURE_DET_REQ);
8486 }
8487 return fan_failure_det_req;
8488}
8489
8490void bnx2x_hw_reset_phy(struct link_params *params)
8491{
8492 u8 phy_index;
8493 for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
8494 phy_index++) {
8495 if (params->phy[phy_index].hw_reset) {
8496 params->phy[phy_index].hw_reset(
8497 &params->phy[phy_index],
8498 params);
8499 params->phy[phy_index] = phy_null;
8500 }
8501 }
8502}
Yaniv Rosner020c7e32011-05-31 21:28:43 +00008503
8504void bnx2x_init_mod_abs_int(struct bnx2x *bp, struct link_vars *vars,
8505 u32 chip_id, u32 shmem_base, u32 shmem2_base,
8506 u8 port)
8507{
8508 u8 gpio_num = 0xff, gpio_port = 0xff, phy_index;
8509 u32 val;
8510 u32 offset, aeu_mask, swap_val, swap_override, sync_offset;
8511
8512 {
8513 struct bnx2x_phy phy;
8514 for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
8515 phy_index++) {
8516 if (bnx2x_populate_phy(bp, phy_index, shmem_base,
8517 shmem2_base, port, &phy)
8518 != 0) {
8519 DP(NETIF_MSG_LINK, "populate phy failed\n");
8520 return;
8521 }
8522 if (phy.type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) {
8523 gpio_num = MISC_REGISTERS_GPIO_3;
8524 gpio_port = port;
8525 break;
8526 }
8527 }
8528 }
8529
8530 if (gpio_num == 0xff)
8531 return;
8532
8533 /* Set GPIO3 to trigger SFP+ module insertion/removal */
8534 bnx2x_set_gpio(bp, gpio_num, MISC_REGISTERS_GPIO_INPUT_HI_Z, gpio_port);
8535
8536 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
8537 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
8538 gpio_port ^= (swap_val && swap_override);
8539
8540 vars->aeu_int_mask = AEU_INPUTS_ATTN_BITS_GPIO0_FUNCTION_0 <<
8541 (gpio_num + (gpio_port << 2));
8542
8543 sync_offset = shmem_base +
8544 offsetof(struct shmem_region,
8545 dev_info.port_hw_config[port].aeu_int_mask);
8546 REG_WR(bp, sync_offset, vars->aeu_int_mask);
8547
8548 DP(NETIF_MSG_LINK, "Setting MOD_ABS (GPIO%d_P%d) AEU to 0x%x\n",
8549 gpio_num, gpio_port, vars->aeu_int_mask);
8550
8551 if (port == 0)
8552 offset = MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0;
8553 else
8554 offset = MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0;
8555
8556 /* Open appropriate AEU for interrupts */
8557 aeu_mask = REG_RD(bp, offset);
8558 aeu_mask |= vars->aeu_int_mask;
8559 REG_WR(bp, offset, aeu_mask);
8560
8561 /* Enable the GPIO to trigger interrupt */
8562 val = REG_RD(bp, MISC_REG_GPIO_EVENT_EN);
8563 val |= 1 << (gpio_num + (gpio_port << 2));
8564 REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val);
8565}