blob: b777d2c9633f7ae95862e38f58d8b1cb77b39bde [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 Rosner3c9ada22011-06-14 01:34:12 +000040#define WC_LANE_MAX 4
41#define I2C_SWITCH_WIDTH 2
42#define I2C_BSC0 0
43#define I2C_BSC1 1
44#define I2C_WA_RETRY_CNT 3
45#define MCPR_IMC_COMMAND_READ_OP 1
46#define MCPR_IMC_COMMAND_WRITE_OP 2
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070047
48/***********************************************************/
Eilon Greenstein3196a882008-08-13 15:58:49 -070049/* Shortcut definitions */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070050/***********************************************************/
51
Eilon Greenstein2f904462009-08-12 08:22:16 +000052#define NIG_LATCH_BC_ENABLE_MI_INT 0
53
54#define NIG_STATUS_EMAC0_MI_INT \
55 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_EMAC0_MISC_MI_INT
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070056#define NIG_STATUS_XGXS0_LINK10G \
57 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK10G
58#define NIG_STATUS_XGXS0_LINK_STATUS \
59 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS
60#define NIG_STATUS_XGXS0_LINK_STATUS_SIZE \
61 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS_SIZE
62#define NIG_STATUS_SERDES0_LINK_STATUS \
63 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_SERDES0_LINK_STATUS
64#define NIG_MASK_MI_INT \
65 NIG_MASK_INTERRUPT_PORT0_REG_MASK_EMAC0_MISC_MI_INT
66#define NIG_MASK_XGXS0_LINK10G \
67 NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK10G
68#define NIG_MASK_XGXS0_LINK_STATUS \
69 NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK_STATUS
70#define NIG_MASK_SERDES0_LINK_STATUS \
71 NIG_MASK_INTERRUPT_PORT0_REG_MASK_SERDES0_LINK_STATUS
72
73#define MDIO_AN_CL73_OR_37_COMPLETE \
74 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE | \
75 MDIO_GP_STATUS_TOP_AN_STATUS1_CL37_AUTONEG_COMPLETE)
76
77#define XGXS_RESET_BITS \
78 (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_RSTB_HW | \
79 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_IDDQ | \
80 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN | \
81 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN_SD | \
82 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_TXD_FIFO_RSTB)
83
84#define SERDES_RESET_BITS \
85 (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_RSTB_HW | \
86 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_IDDQ | \
87 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN | \
88 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN_SD)
89
90#define AUTONEG_CL37 SHARED_HW_CFG_AN_ENABLE_CL37
91#define AUTONEG_CL73 SHARED_HW_CFG_AN_ENABLE_CL73
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000092#define AUTONEG_BAM SHARED_HW_CFG_AN_ENABLE_BAM
Eilon Greenstein3196a882008-08-13 15:58:49 -070093#define AUTONEG_PARALLEL \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070094 SHARED_HW_CFG_AN_ENABLE_PARALLEL_DETECTION
Eilon Greenstein3196a882008-08-13 15:58:49 -070095#define AUTONEG_SGMII_FIBER_AUTODET \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070096 SHARED_HW_CFG_AN_EN_SGMII_FIBER_AUTO_DETECT
Eilon Greenstein3196a882008-08-13 15:58:49 -070097#define AUTONEG_REMOTE_PHY SHARED_HW_CFG_AN_ENABLE_REMOTE_PHY
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070098
99#define GP_STATUS_PAUSE_RSOLUTION_TXSIDE \
100 MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_TXSIDE
101#define GP_STATUS_PAUSE_RSOLUTION_RXSIDE \
102 MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_RXSIDE
103#define GP_STATUS_SPEED_MASK \
104 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_MASK
105#define GP_STATUS_10M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10M
106#define GP_STATUS_100M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_100M
107#define GP_STATUS_1G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G
108#define GP_STATUS_2_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_2_5G
109#define GP_STATUS_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_5G
110#define GP_STATUS_6G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_6G
111#define GP_STATUS_10G_HIG \
112 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_HIG
113#define GP_STATUS_10G_CX4 \
114 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_CX4
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700115#define GP_STATUS_1G_KX MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G_KX
116#define GP_STATUS_10G_KX4 \
117 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_KX4
Yaniv Rosner3c9ada22011-06-14 01:34:12 +0000118#define GP_STATUS_10G_KR MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_KR
119#define GP_STATUS_10G_XFI MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_XFI
120#define GP_STATUS_20G_DXGXS MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_20G_DXGXS
121#define GP_STATUS_10G_SFI MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_SFI
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000122#define LINK_10THD LINK_STATUS_SPEED_AND_DUPLEX_10THD
123#define LINK_10TFD LINK_STATUS_SPEED_AND_DUPLEX_10TFD
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700124#define LINK_100TXHD LINK_STATUS_SPEED_AND_DUPLEX_100TXHD
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000125#define LINK_100T4 LINK_STATUS_SPEED_AND_DUPLEX_100T4
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700126#define LINK_100TXFD LINK_STATUS_SPEED_AND_DUPLEX_100TXFD
127#define LINK_1000THD LINK_STATUS_SPEED_AND_DUPLEX_1000THD
128#define LINK_1000TFD LINK_STATUS_SPEED_AND_DUPLEX_1000TFD
129#define LINK_1000XFD LINK_STATUS_SPEED_AND_DUPLEX_1000XFD
130#define LINK_2500THD LINK_STATUS_SPEED_AND_DUPLEX_2500THD
131#define LINK_2500TFD LINK_STATUS_SPEED_AND_DUPLEX_2500TFD
132#define LINK_2500XFD LINK_STATUS_SPEED_AND_DUPLEX_2500XFD
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000133#define LINK_10GTFD LINK_STATUS_SPEED_AND_DUPLEX_10GTFD
134#define LINK_10GXFD LINK_STATUS_SPEED_AND_DUPLEX_10GXFD
Yaniv Rosner3c9ada22011-06-14 01:34:12 +0000135#define LINK_20GTFD LINK_STATUS_SPEED_AND_DUPLEX_20GTFD
136#define LINK_20GXFD LINK_STATUS_SPEED_AND_DUPLEX_20GXFD
Eilon Greenstein589abe32009-02-12 08:36:55 +0000137/* */
138#define SFP_EEPROM_CON_TYPE_ADDR 0x2
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000139 #define SFP_EEPROM_CON_TYPE_VAL_LC 0x7
Eilon Greenstein589abe32009-02-12 08:36:55 +0000140 #define SFP_EEPROM_CON_TYPE_VAL_COPPER 0x21
141
Eilon Greenstein4d295db2009-07-21 05:47:47 +0000142
143#define SFP_EEPROM_COMP_CODE_ADDR 0x3
144 #define SFP_EEPROM_COMP_CODE_SR_MASK (1<<4)
145 #define SFP_EEPROM_COMP_CODE_LR_MASK (1<<5)
146 #define SFP_EEPROM_COMP_CODE_LRM_MASK (1<<6)
147
Eilon Greenstein589abe32009-02-12 08:36:55 +0000148#define SFP_EEPROM_FC_TX_TECH_ADDR 0x8
149 #define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE 0x4
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000150 #define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE 0x8
Eilon Greenstein4d295db2009-07-21 05:47:47 +0000151
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000152#define SFP_EEPROM_OPTIONS_ADDR 0x40
Eilon Greenstein589abe32009-02-12 08:36:55 +0000153 #define SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK 0x1
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000154#define SFP_EEPROM_OPTIONS_SIZE 2
Eilon Greenstein589abe32009-02-12 08:36:55 +0000155
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000156#define EDC_MODE_LINEAR 0x0022
157#define EDC_MODE_LIMITING 0x0044
158#define EDC_MODE_PASSIVE_DAC 0x0055
Eilon Greenstein589abe32009-02-12 08:36:55 +0000159
Eilon Greenstein4d295db2009-07-21 05:47:47 +0000160
Yaniv Rosner9380bb92011-06-14 01:34:07 +0000161/* BRB thresholds for E2*/
162#define PFC_E2_BRB_MAC_PAUSE_XOFF_THR_PAUSE 170
163#define PFC_E2_BRB_MAC_PAUSE_XOFF_THR_NON_PAUSE 0
164
165#define PFC_E2_BRB_MAC_PAUSE_XON_THR_PAUSE 250
166#define PFC_E2_BRB_MAC_PAUSE_XON_THR_NON_PAUSE 0
167
168#define PFC_E2_BRB_MAC_FULL_XOFF_THR_PAUSE 10
169#define PFC_E2_BRB_MAC_FULL_XOFF_THR_NON_PAUSE 90
170
171#define PFC_E2_BRB_MAC_FULL_XON_THR_PAUSE 50
172#define PFC_E2_BRB_MAC_FULL_XON_THR_NON_PAUSE 250
173
174/* BRB thresholds for E3A0 */
175#define PFC_E3A0_BRB_MAC_PAUSE_XOFF_THR_PAUSE 290
176#define PFC_E3A0_BRB_MAC_PAUSE_XOFF_THR_NON_PAUSE 0
177
178#define PFC_E3A0_BRB_MAC_PAUSE_XON_THR_PAUSE 410
179#define PFC_E3A0_BRB_MAC_PAUSE_XON_THR_NON_PAUSE 0
180
181#define PFC_E3A0_BRB_MAC_FULL_XOFF_THR_PAUSE 10
182#define PFC_E3A0_BRB_MAC_FULL_XOFF_THR_NON_PAUSE 170
183
184#define PFC_E3A0_BRB_MAC_FULL_XON_THR_PAUSE 50
185#define PFC_E3A0_BRB_MAC_FULL_XON_THR_NON_PAUSE 410
186
187
188/* BRB thresholds for E3B0 2 port mode*/
189#define PFC_E3B0_2P_BRB_MAC_PAUSE_XOFF_THR_PAUSE 1025
190#define PFC_E3B0_2P_BRB_MAC_PAUSE_XOFF_THR_NON_PAUSE 0
191
192#define PFC_E3B0_2P_BRB_MAC_PAUSE_XON_THR_PAUSE 1025
193#define PFC_E3B0_2P_BRB_MAC_PAUSE_XON_THR_NON_PAUSE 0
194
195#define PFC_E3B0_2P_BRB_MAC_FULL_XOFF_THR_PAUSE 10
196#define PFC_E3B0_2P_BRB_MAC_FULL_XOFF_THR_NON_PAUSE 1025
197
198#define PFC_E3B0_2P_BRB_MAC_FULL_XON_THR_PAUSE 50
199#define PFC_E3B0_2P_BRB_MAC_FULL_XON_THR_NON_PAUSE 1025
200
201/* only for E3B0*/
202#define PFC_E3B0_2P_BRB_FULL_LB_XOFF_THR 1025
203#define PFC_E3B0_2P_BRB_FULL_LB_XON_THR 1025
204
205/* Lossy +Lossless GUARANTIED == GUART */
206#define PFC_E3B0_2P_MIX_PAUSE_LB_GUART 284
207/* Lossless +Lossless*/
208#define PFC_E3B0_2P_PAUSE_LB_GUART 236
209/* Lossy +Lossy*/
210#define PFC_E3B0_2P_NON_PAUSE_LB_GUART 342
211
212/* Lossy +Lossless*/
213#define PFC_E3B0_2P_MIX_PAUSE_MAC_0_CLASS_T_GUART 284
214/* Lossless +Lossless*/
215#define PFC_E3B0_2P_PAUSE_MAC_0_CLASS_T_GUART 236
216/* Lossy +Lossy*/
217#define PFC_E3B0_2P_NON_PAUSE_MAC_0_CLASS_T_GUART 336
218#define PFC_E3B0_2P_BRB_MAC_0_CLASS_T_GUART_HYST 80
219
220#define PFC_E3B0_2P_BRB_MAC_1_CLASS_T_GUART 0
221#define PFC_E3B0_2P_BRB_MAC_1_CLASS_T_GUART_HYST 0
222
223/* BRB thresholds for E3B0 4 port mode */
224#define PFC_E3B0_4P_BRB_MAC_PAUSE_XOFF_THR_PAUSE 304
225#define PFC_E3B0_4P_BRB_MAC_PAUSE_XOFF_THR_NON_PAUSE 0
226
227#define PFC_E3B0_4P_BRB_MAC_PAUSE_XON_THR_PAUSE 384
228#define PFC_E3B0_4P_BRB_MAC_PAUSE_XON_THR_NON_PAUSE 0
229
230#define PFC_E3B0_4P_BRB_MAC_FULL_XOFF_THR_PAUSE 10
231#define PFC_E3B0_4P_BRB_MAC_FULL_XOFF_THR_NON_PAUSE 304
232
233#define PFC_E3B0_4P_BRB_MAC_FULL_XON_THR_PAUSE 50
234#define PFC_E3B0_4P_BRB_MAC_FULL_XON_THR_NON_PAUSE 384
235
236
237/* only for E3B0*/
238#define PFC_E3B0_4P_BRB_FULL_LB_XOFF_THR 304
239#define PFC_E3B0_4P_BRB_FULL_LB_XON_THR 384
240#define PFC_E3B0_4P_LB_GUART 120
241
242#define PFC_E3B0_4P_BRB_MAC_0_CLASS_T_GUART 120
243#define PFC_E3B0_4P_BRB_MAC_0_CLASS_T_GUART_HYST 80
244
245#define PFC_E3B0_4P_BRB_MAC_1_CLASS_T_GUART 80
246#define PFC_E3B0_4P_BRB_MAC_1_CLASS_T_GUART_HYST 120
247
248#define DCBX_INVALID_COS (0xFF)
249
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000250#define ETS_BW_LIMIT_CREDIT_UPPER_BOUND (0x5000)
251#define ETS_BW_LIMIT_CREDIT_WEIGHT (0x5000)
Yaniv Rosner9380bb92011-06-14 01:34:07 +0000252#define ETS_E3B0_NIG_MIN_W_VAL_UP_TO_10GBPS (1360)
253#define ETS_E3B0_NIG_MIN_W_VAL_20GBPS (2720)
254#define ETS_E3B0_PBF_MIN_W_VAL (10000)
255
256#define MAX_PACKET_SIZE (9700)
Yaniv Rosner3c9ada22011-06-14 01:34:12 +0000257#define WC_UC_TIMEOUT 100
Yaniv Rosner9380bb92011-06-14 01:34:07 +0000258
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700259/**********************************************************/
260/* INTERFACE */
261/**********************************************************/
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000262
Yaniv Rosnercd2be892011-01-31 04:21:45 +0000263#define CL22_WR_OVER_CL45(_bp, _phy, _bank, _addr, _val) \
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000264 bnx2x_cl45_write(_bp, _phy, \
Yaniv Rosner7aa07112010-09-07 11:41:01 +0000265 (_phy)->def_md_devad, \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700266 (_bank + (_addr & 0xf)), \
267 _val)
268
Yaniv Rosnercd2be892011-01-31 04:21:45 +0000269#define CL22_RD_OVER_CL45(_bp, _phy, _bank, _addr, _val) \
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000270 bnx2x_cl45_read(_bp, _phy, \
Yaniv Rosner7aa07112010-09-07 11:41:01 +0000271 (_phy)->def_md_devad, \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700272 (_bank + (_addr & 0xf)), \
273 _val)
274
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700275static u32 bnx2x_bits_en(struct bnx2x *bp, u32 reg, u32 bits)
276{
277 u32 val = REG_RD(bp, reg);
278
279 val |= bits;
280 REG_WR(bp, reg, val);
281 return val;
282}
283
284static u32 bnx2x_bits_dis(struct bnx2x *bp, u32 reg, u32 bits)
285{
286 u32 val = REG_RD(bp, reg);
287
288 val &= ~bits;
289 REG_WR(bp, reg, val);
290 return val;
291}
292
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000293/******************************************************************/
Yaniv Rosner3c9ada22011-06-14 01:34:12 +0000294/* EPIO/GPIO section */
295/******************************************************************/
296static void bnx2x_set_epio(struct bnx2x *bp, u32 epio_pin, u32 en)
297{
298 u32 epio_mask, gp_output, gp_oenable;
299
300 /* Sanity check */
301 if (epio_pin > 31) {
302 DP(NETIF_MSG_LINK, "Invalid EPIO pin %d to set\n", epio_pin);
303 return;
304 }
305 DP(NETIF_MSG_LINK, "Setting EPIO pin %d to %d\n", epio_pin, en);
306 epio_mask = 1 << epio_pin;
307 /* Set this EPIO to output */
308 gp_output = REG_RD(bp, MCP_REG_MCPR_GP_OUTPUTS);
309 if (en)
310 gp_output |= epio_mask;
311 else
312 gp_output &= ~epio_mask;
313
314 REG_WR(bp, MCP_REG_MCPR_GP_OUTPUTS, gp_output);
315
316 /* Set the value for this EPIO */
317 gp_oenable = REG_RD(bp, MCP_REG_MCPR_GP_OENABLE);
318 REG_WR(bp, MCP_REG_MCPR_GP_OENABLE, gp_oenable | epio_mask);
319}
320
321static void bnx2x_set_cfg_pin(struct bnx2x *bp, u32 pin_cfg, u32 val)
322{
323 if (pin_cfg == PIN_CFG_NA)
324 return;
325 if (pin_cfg >= PIN_CFG_EPIO0) {
326 bnx2x_set_epio(bp, pin_cfg - PIN_CFG_EPIO0, val);
327 } else {
328 u8 gpio_num = (pin_cfg - PIN_CFG_GPIO0_P0) & 0x3;
329 u8 gpio_port = (pin_cfg - PIN_CFG_GPIO0_P0) >> 2;
330 bnx2x_set_gpio(bp, gpio_num, (u8)val, gpio_port);
331 }
332}
333
334/******************************************************************/
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000335/* ETS section */
336/******************************************************************/
337void bnx2x_ets_disabled(struct link_params *params)
338{
339 /* ETS disabled configuration*/
340 struct bnx2x *bp = params->bp;
341
342 DP(NETIF_MSG_LINK, "ETS disabled configuration\n");
343
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000344 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000345 * mapping between entry priority to client number (0,1,2 -debug and
346 * management clients, 3 - COS0 client, 4 - COS client)(HIGHEST)
347 * 3bits client num.
348 * PRI4 | PRI3 | PRI2 | PRI1 | PRI0
349 * cos1-100 cos0-011 dbg1-010 dbg0-001 MCP-000
350 */
351
352 REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT, 0x4688);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000353 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000354 * Bitmap of 5bits length. Each bit specifies whether the entry behaves
355 * as strict. Bits 0,1,2 - debug and management entries, 3 -
356 * COS0 entry, 4 - COS1 entry.
357 * COS1 | COS0 | DEBUG1 | DEBUG0 | MGMT
358 * bit4 bit3 bit2 bit1 bit0
359 * MCP and debug are strict
360 */
361
362 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x7);
363 /* defines which entries (clients) are subjected to WFQ arbitration */
364 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ, 0);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000365 /*
366 * For strict priority entries defines the number of consecutive
367 * slots for the highest priority.
368 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000369 REG_WR(bp, NIG_REG_P0_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000370 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000371 * mapping between the CREDIT_WEIGHT registers and actual client
372 * numbers
373 */
374 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP, 0);
375 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_0, 0);
376 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_1, 0);
377
378 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_0, 0);
379 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_1, 0);
380 REG_WR(bp, PBF_REG_HIGH_PRIORITY_COS_NUM, 0);
381 /* ETS mode disable */
382 REG_WR(bp, PBF_REG_ETS_ENABLED, 0);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000383 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000384 * If ETS mode is enabled (there is no strict priority) defines a WFQ
385 * weight for COS0/COS1.
386 */
387 REG_WR(bp, PBF_REG_COS0_WEIGHT, 0x2710);
388 REG_WR(bp, PBF_REG_COS1_WEIGHT, 0x2710);
389 /* Upper bound that COS0_WEIGHT can reach in the WFQ arbiter */
390 REG_WR(bp, PBF_REG_COS0_UPPER_BOUND, 0x989680);
391 REG_WR(bp, PBF_REG_COS1_UPPER_BOUND, 0x989680);
392 /* Defines the number of consecutive slots for the strict priority */
393 REG_WR(bp, PBF_REG_NUM_STRICT_ARB_SLOTS, 0);
394}
395
Yaniv Rosner65a001b2011-01-31 04:22:03 +0000396static void bnx2x_ets_bw_limit_common(const struct link_params *params)
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000397{
398 /* ETS disabled configuration */
399 struct bnx2x *bp = params->bp;
400 DP(NETIF_MSG_LINK, "ETS enabled BW limit configuration\n");
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000401 /*
402 * defines which entries (clients) are subjected to WFQ arbitration
403 * COS0 0x8
404 * COS1 0x10
405 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000406 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ, 0x18);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000407 /*
408 * mapping between the ARB_CREDIT_WEIGHT registers and actual
409 * client numbers (WEIGHT_0 does not actually have to represent
410 * client 0)
411 * PRI4 | PRI3 | PRI2 | PRI1 | PRI0
412 * cos1-001 cos0-000 dbg1-100 dbg0-011 MCP-010
413 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000414 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP, 0x111A);
415
416 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_0,
417 ETS_BW_LIMIT_CREDIT_UPPER_BOUND);
418 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_1,
419 ETS_BW_LIMIT_CREDIT_UPPER_BOUND);
420
421 /* ETS mode enabled*/
422 REG_WR(bp, PBF_REG_ETS_ENABLED, 1);
423
424 /* Defines the number of consecutive slots for the strict priority */
425 REG_WR(bp, PBF_REG_NUM_STRICT_ARB_SLOTS, 0);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000426 /*
427 * Bitmap of 5bits length. Each bit specifies whether the entry behaves
428 * as strict. Bits 0,1,2 - debug and management entries, 3 - COS0
429 * entry, 4 - COS1 entry.
430 * COS1 | COS0 | DEBUG21 | DEBUG0 | MGMT
431 * bit4 bit3 bit2 bit1 bit0
432 * MCP and debug are strict
433 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000434 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x7);
435
436 /* Upper bound that COS0_WEIGHT can reach in the WFQ arbiter.*/
437 REG_WR(bp, PBF_REG_COS0_UPPER_BOUND,
438 ETS_BW_LIMIT_CREDIT_UPPER_BOUND);
439 REG_WR(bp, PBF_REG_COS1_UPPER_BOUND,
440 ETS_BW_LIMIT_CREDIT_UPPER_BOUND);
441}
442
443void bnx2x_ets_bw_limit(const struct link_params *params, const u32 cos0_bw,
444 const u32 cos1_bw)
445{
446 /* ETS disabled configuration*/
447 struct bnx2x *bp = params->bp;
448 const u32 total_bw = cos0_bw + cos1_bw;
449 u32 cos0_credit_weight = 0;
450 u32 cos1_credit_weight = 0;
451
452 DP(NETIF_MSG_LINK, "ETS enabled BW limit configuration\n");
453
454 if ((0 == total_bw) ||
455 (0 == cos0_bw) ||
456 (0 == cos1_bw)) {
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000457 DP(NETIF_MSG_LINK, "Total BW can't be zero\n");
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000458 return;
459 }
460
461 cos0_credit_weight = (cos0_bw * ETS_BW_LIMIT_CREDIT_WEIGHT)/
462 total_bw;
463 cos1_credit_weight = (cos1_bw * ETS_BW_LIMIT_CREDIT_WEIGHT)/
464 total_bw;
465
466 bnx2x_ets_bw_limit_common(params);
467
468 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_0, cos0_credit_weight);
469 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_1, cos1_credit_weight);
470
471 REG_WR(bp, PBF_REG_COS0_WEIGHT, cos0_credit_weight);
472 REG_WR(bp, PBF_REG_COS1_WEIGHT, cos1_credit_weight);
473}
474
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +0000475int bnx2x_ets_strict(const struct link_params *params, const u8 strict_cos)
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000476{
477 /* ETS disabled configuration*/
478 struct bnx2x *bp = params->bp;
479 u32 val = 0;
480
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000481 DP(NETIF_MSG_LINK, "ETS enabled strict configuration\n");
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000482 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000483 * Bitmap of 5bits length. Each bit specifies whether the entry behaves
484 * as strict. Bits 0,1,2 - debug and management entries,
485 * 3 - COS0 entry, 4 - COS1 entry.
486 * COS1 | COS0 | DEBUG21 | DEBUG0 | MGMT
487 * bit4 bit3 bit2 bit1 bit0
488 * MCP and debug are strict
489 */
490 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x1F);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000491 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000492 * For strict priority entries defines the number of consecutive slots
493 * for the highest priority.
494 */
495 REG_WR(bp, NIG_REG_P0_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100);
496 /* ETS mode disable */
497 REG_WR(bp, PBF_REG_ETS_ENABLED, 0);
498 /* Defines the number of consecutive slots for the strict priority */
499 REG_WR(bp, PBF_REG_NUM_STRICT_ARB_SLOTS, 0x100);
500
501 /* Defines the number of consecutive slots for the strict priority */
502 REG_WR(bp, PBF_REG_HIGH_PRIORITY_COS_NUM, strict_cos);
503
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000504 /*
505 * mapping between entry priority to client number (0,1,2 -debug and
506 * management clients, 3 - COS0 client, 4 - COS client)(HIGHEST)
507 * 3bits client num.
508 * PRI4 | PRI3 | PRI2 | PRI1 | PRI0
509 * dbg0-010 dbg1-001 cos1-100 cos0-011 MCP-000
510 * dbg0-010 dbg1-001 cos0-011 cos1-100 MCP-000
511 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000512 val = (0 == strict_cos) ? 0x2318 : 0x22E0;
513 REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT, val);
514
515 return 0;
516}
517/******************************************************************/
Dmitry Kravkove8920672011-05-04 23:52:40 +0000518/* PFC section */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000519/******************************************************************/
520
Yaniv Rosner9380bb92011-06-14 01:34:07 +0000521static void bnx2x_update_pfc_xmac(struct link_params *params,
522 struct link_vars *vars,
523 u8 is_lb)
524{
525 struct bnx2x *bp = params->bp;
526 u32 xmac_base;
527 u32 pause_val, pfc0_val, pfc1_val;
528
529 /* XMAC base adrr */
530 xmac_base = (params->port) ? GRCBASE_XMAC1 : GRCBASE_XMAC0;
531
532 /* Initialize pause and pfc registers */
533 pause_val = 0x18000;
534 pfc0_val = 0xFFFF8000;
535 pfc1_val = 0x2;
536
537 /* No PFC support */
538 if (!(params->feature_config_flags &
539 FEATURE_CONFIG_PFC_ENABLED)) {
540
541 /*
542 * RX flow control - Process pause frame in receive direction
543 */
544 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
545 pause_val |= XMAC_PAUSE_CTRL_REG_RX_PAUSE_EN;
546
547 /*
548 * TX flow control - Send pause packet when buffer is full
549 */
550 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
551 pause_val |= XMAC_PAUSE_CTRL_REG_TX_PAUSE_EN;
552 } else {/* PFC support */
553 pfc1_val |= XMAC_PFC_CTRL_HI_REG_PFC_REFRESH_EN |
554 XMAC_PFC_CTRL_HI_REG_PFC_STATS_EN |
555 XMAC_PFC_CTRL_HI_REG_RX_PFC_EN |
556 XMAC_PFC_CTRL_HI_REG_TX_PFC_EN;
557 }
558
559 /* Write pause and PFC registers */
560 REG_WR(bp, xmac_base + XMAC_REG_PAUSE_CTRL, pause_val);
561 REG_WR(bp, xmac_base + XMAC_REG_PFC_CTRL, pfc0_val);
562 REG_WR(bp, xmac_base + XMAC_REG_PFC_CTRL_HI, pfc1_val);
563
564 udelay(30);
565}
566
567
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000568static void bnx2x_bmac2_get_pfc_stat(struct link_params *params,
569 u32 pfc_frames_sent[2],
570 u32 pfc_frames_received[2])
571{
572 /* Read pfc statistic */
573 struct bnx2x *bp = params->bp;
574 u32 bmac_addr = params->port ? NIG_REG_INGRESS_BMAC1_MEM :
575 NIG_REG_INGRESS_BMAC0_MEM;
576
577 DP(NETIF_MSG_LINK, "pfc statistic read from BMAC\n");
578
579 REG_RD_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_STAT_GTPP,
580 pfc_frames_sent, 2);
581
582 REG_RD_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_STAT_GRPP,
583 pfc_frames_received, 2);
584
585}
586static void bnx2x_emac_get_pfc_stat(struct link_params *params,
587 u32 pfc_frames_sent[2],
588 u32 pfc_frames_received[2])
589{
590 /* Read pfc statistic */
591 struct bnx2x *bp = params->bp;
592 u32 emac_base = params->port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
593 u32 val_xon = 0;
594 u32 val_xoff = 0;
595
596 DP(NETIF_MSG_LINK, "pfc statistic read from EMAC\n");
597
598 /* PFC received frames */
599 val_xoff = REG_RD(bp, emac_base +
600 EMAC_REG_RX_PFC_STATS_XOFF_RCVD);
601 val_xoff &= EMAC_REG_RX_PFC_STATS_XOFF_RCVD_COUNT;
602 val_xon = REG_RD(bp, emac_base + EMAC_REG_RX_PFC_STATS_XON_RCVD);
603 val_xon &= EMAC_REG_RX_PFC_STATS_XON_RCVD_COUNT;
604
605 pfc_frames_received[0] = val_xon + val_xoff;
606
607 /* PFC received sent */
608 val_xoff = REG_RD(bp, emac_base +
609 EMAC_REG_RX_PFC_STATS_XOFF_SENT);
610 val_xoff &= EMAC_REG_RX_PFC_STATS_XOFF_SENT_COUNT;
611 val_xon = REG_RD(bp, emac_base + EMAC_REG_RX_PFC_STATS_XON_SENT);
612 val_xon &= EMAC_REG_RX_PFC_STATS_XON_SENT_COUNT;
613
614 pfc_frames_sent[0] = val_xon + val_xoff;
615}
616
617void bnx2x_pfc_statistic(struct link_params *params, struct link_vars *vars,
618 u32 pfc_frames_sent[2],
619 u32 pfc_frames_received[2])
620{
621 /* Read pfc statistic */
622 struct bnx2x *bp = params->bp;
623 u32 val = 0;
624 DP(NETIF_MSG_LINK, "pfc statistic\n");
625
626 if (!vars->link_up)
627 return;
628
629 val = REG_RD(bp, MISC_REG_RESET_REG_2);
630 if ((val & (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << params->port))
631 == 0) {
632 DP(NETIF_MSG_LINK, "About to read stats from EMAC\n");
633 bnx2x_emac_get_pfc_stat(params, pfc_frames_sent,
634 pfc_frames_received);
635 } else {
636 DP(NETIF_MSG_LINK, "About to read stats from BMAC\n");
637 bnx2x_bmac2_get_pfc_stat(params, pfc_frames_sent,
638 pfc_frames_received);
639 }
640}
641/******************************************************************/
642/* MAC/PBF section */
643/******************************************************************/
Yaniv Rosnera198c142011-05-31 21:29:42 +0000644static void bnx2x_set_mdio_clk(struct bnx2x *bp, u32 chip_id, u8 port)
645{
646 u32 mode, emac_base;
647 /**
648 * Set clause 45 mode, slow down the MDIO clock to 2.5MHz
649 * (a value of 49==0x31) and make sure that the AUTO poll is off
650 */
651
652 if (CHIP_IS_E2(bp))
653 emac_base = GRCBASE_EMAC0;
654 else
655 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
656 mode = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
657 mode &= ~(EMAC_MDIO_MODE_AUTO_POLL |
658 EMAC_MDIO_MODE_CLOCK_CNT);
Yaniv Rosner3c9ada22011-06-14 01:34:12 +0000659 if (USES_WARPCORE(bp))
660 mode |= (74L << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT);
661 else
662 mode |= (49L << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT);
Yaniv Rosnera198c142011-05-31 21:29:42 +0000663
664 mode |= (EMAC_MDIO_MODE_CLAUSE_45);
665 REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE, mode);
666
667 udelay(40);
668}
669
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700670static void bnx2x_emac_init(struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000671 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700672{
673 /* reset and unreset the emac core */
674 struct bnx2x *bp = params->bp;
675 u8 port = params->port;
676 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
677 u32 val;
678 u16 timeout;
679
680 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000681 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700682 udelay(5);
683 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000684 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700685
686 /* init emac - use read-modify-write */
687 /* self clear reset */
688 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700689 EMAC_WR(bp, EMAC_REG_EMAC_MODE, (val | EMAC_MODE_RESET));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700690
691 timeout = 200;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700692 do {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700693 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
694 DP(NETIF_MSG_LINK, "EMAC reset reg is %u\n", val);
695 if (!timeout) {
696 DP(NETIF_MSG_LINK, "EMAC timeout!\n");
697 return;
698 }
699 timeout--;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700700 } while (val & EMAC_MODE_RESET);
Yaniv Rosnera198c142011-05-31 21:29:42 +0000701 bnx2x_set_mdio_clk(bp, params->chip_id, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700702 /* Set mac address */
703 val = ((params->mac_addr[0] << 8) |
704 params->mac_addr[1]);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700705 EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700706
707 val = ((params->mac_addr[2] << 24) |
708 (params->mac_addr[3] << 16) |
709 (params->mac_addr[4] << 8) |
710 params->mac_addr[5]);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700711 EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH + 4, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700712}
713
Yaniv Rosner9380bb92011-06-14 01:34:07 +0000714static void bnx2x_set_xumac_nig(struct link_params *params,
715 u16 tx_pause_en,
716 u8 enable)
717{
718 struct bnx2x *bp = params->bp;
719
720 REG_WR(bp, params->port ? NIG_REG_P1_MAC_IN_EN : NIG_REG_P0_MAC_IN_EN,
721 enable);
722 REG_WR(bp, params->port ? NIG_REG_P1_MAC_OUT_EN : NIG_REG_P0_MAC_OUT_EN,
723 enable);
724 REG_WR(bp, params->port ? NIG_REG_P1_MAC_PAUSE_OUT_EN :
725 NIG_REG_P0_MAC_PAUSE_OUT_EN, tx_pause_en);
726}
727
728static void bnx2x_umac_enable(struct link_params *params,
729 struct link_vars *vars, u8 lb)
730{
731 u32 val;
732 u32 umac_base = params->port ? GRCBASE_UMAC1 : GRCBASE_UMAC0;
733 struct bnx2x *bp = params->bp;
734 /* Reset UMAC */
735 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
736 (MISC_REGISTERS_RESET_REG_2_UMAC0 << params->port));
737 usleep_range(1000, 1000);
738
739 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
740 (MISC_REGISTERS_RESET_REG_2_UMAC0 << params->port));
741
742 DP(NETIF_MSG_LINK, "enabling UMAC\n");
743
744 /**
745 * This register determines on which events the MAC will assert
746 * error on the i/f to the NIG along w/ EOP.
747 */
748
749 /**
750 * BD REG_WR(bp, NIG_REG_P0_MAC_RSV_ERR_MASK +
751 * params->port*0x14, 0xfffff.
752 */
753 /* This register opens the gate for the UMAC despite its name */
754 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + params->port*4, 1);
755
756 val = UMAC_COMMAND_CONFIG_REG_PROMIS_EN |
757 UMAC_COMMAND_CONFIG_REG_PAD_EN |
758 UMAC_COMMAND_CONFIG_REG_SW_RESET |
759 UMAC_COMMAND_CONFIG_REG_NO_LGTH_CHECK;
760 switch (vars->line_speed) {
761 case SPEED_10:
762 val |= (0<<2);
763 break;
764 case SPEED_100:
765 val |= (1<<2);
766 break;
767 case SPEED_1000:
768 val |= (2<<2);
769 break;
770 case SPEED_2500:
771 val |= (3<<2);
772 break;
773 default:
774 DP(NETIF_MSG_LINK, "Invalid speed for UMAC %d\n",
775 vars->line_speed);
776 break;
777 }
778 REG_WR(bp, umac_base + UMAC_REG_COMMAND_CONFIG, val);
779 udelay(50);
780
781 /* Enable RX and TX */
782 val &= ~UMAC_COMMAND_CONFIG_REG_PAD_EN;
783 val |= UMAC_COMMAND_CONFIG_REG_TX_ENA |
Yaniv Rosner3c9ada22011-06-14 01:34:12 +0000784 UMAC_COMMAND_CONFIG_REG_RX_ENA;
Yaniv Rosner9380bb92011-06-14 01:34:07 +0000785 REG_WR(bp, umac_base + UMAC_REG_COMMAND_CONFIG, val);
786 udelay(50);
787
788 /* Remove SW Reset */
789 val &= ~UMAC_COMMAND_CONFIG_REG_SW_RESET;
790
791 /* Check loopback mode */
792 if (lb)
793 val |= UMAC_COMMAND_CONFIG_REG_LOOP_ENA;
794 REG_WR(bp, umac_base + UMAC_REG_COMMAND_CONFIG, val);
795
796 /*
797 * Maximum Frame Length (RW). Defines a 14-Bit maximum frame
798 * length used by the MAC receive logic to check frames.
799 */
800 REG_WR(bp, umac_base + UMAC_REG_MAXFR, 0x2710);
801 bnx2x_set_xumac_nig(params,
802 ((vars->flow_ctrl & BNX2X_FLOW_CTRL_TX) != 0), 1);
803 vars->mac_type = MAC_TYPE_UMAC;
804
805}
806
807static u8 bnx2x_is_4_port_mode(struct bnx2x *bp)
808{
809 u32 port4mode_ovwr_val;
810 /* Check 4-port override enabled */
811 port4mode_ovwr_val = REG_RD(bp, MISC_REG_PORT4MODE_EN_OVWR);
812 if (port4mode_ovwr_val & (1<<0)) {
813 /* Return 4-port mode override value */
814 return ((port4mode_ovwr_val & (1<<1)) == (1<<1));
815 }
816 /* Return 4-port mode from input pin */
817 return (u8)REG_RD(bp, MISC_REG_PORT4MODE_EN);
818}
819
820/* Define the XMAC mode */
821static void bnx2x_xmac_init(struct bnx2x *bp, u32 max_speed)
822{
823 u32 is_port4mode = bnx2x_is_4_port_mode(bp);
824
825 /**
826 * In 4-port mode, need to set the mode only once, so if XMAC is
827 * already out of reset, it means the mode has already been set,
828 * and it must not* reset the XMAC again, since it controls both
829 * ports of the path
830 **/
831
832 if (is_port4mode && (REG_RD(bp, MISC_REG_RESET_REG_2) &
833 MISC_REGISTERS_RESET_REG_2_XMAC)) {
834 DP(NETIF_MSG_LINK, "XMAC already out of reset"
835 " in 4-port mode\n");
836 return;
837 }
838
839 /* Hard reset */
840 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
841 MISC_REGISTERS_RESET_REG_2_XMAC);
842 usleep_range(1000, 1000);
843
844 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
845 MISC_REGISTERS_RESET_REG_2_XMAC);
846 if (is_port4mode) {
847 DP(NETIF_MSG_LINK, "Init XMAC to 2 ports x 10G per path\n");
848
849 /* Set the number of ports on the system side to up to 2 */
850 REG_WR(bp, MISC_REG_XMAC_CORE_PORT_MODE, 1);
851
852 /* Set the number of ports on the Warp Core to 10G */
853 REG_WR(bp, MISC_REG_XMAC_PHY_PORT_MODE, 3);
854 } else {
855 /* Set the number of ports on the system side to 1 */
856 REG_WR(bp, MISC_REG_XMAC_CORE_PORT_MODE, 0);
857 if (max_speed == SPEED_10000) {
858 DP(NETIF_MSG_LINK, "Init XMAC to 10G x 1"
859 " port per path\n");
860 /* Set the number of ports on the Warp Core to 10G */
861 REG_WR(bp, MISC_REG_XMAC_PHY_PORT_MODE, 3);
862 } else {
863 DP(NETIF_MSG_LINK, "Init XMAC to 20G x 2 ports"
864 " per path\n");
865 /* Set the number of ports on the Warp Core to 20G */
866 REG_WR(bp, MISC_REG_XMAC_PHY_PORT_MODE, 1);
867 }
868 }
869 /* Soft reset */
870 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
871 MISC_REGISTERS_RESET_REG_2_XMAC_SOFT);
872 usleep_range(1000, 1000);
873
874 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
875 MISC_REGISTERS_RESET_REG_2_XMAC_SOFT);
876
877}
878
879static void bnx2x_xmac_disable(struct link_params *params)
880{
881 u8 port = params->port;
882 struct bnx2x *bp = params->bp;
883 u32 xmac_base = (port) ? GRCBASE_XMAC1 : GRCBASE_XMAC0;
884
885 if (REG_RD(bp, MISC_REG_RESET_REG_2) &
886 MISC_REGISTERS_RESET_REG_2_XMAC) {
887 DP(NETIF_MSG_LINK, "Disable XMAC on port %x\n", port);
888 REG_WR(bp, xmac_base + XMAC_REG_CTRL, 0);
889 usleep_range(1000, 1000);
890 bnx2x_set_xumac_nig(params, 0, 0);
891 REG_WR(bp, xmac_base + XMAC_REG_CTRL,
892 XMAC_CTRL_REG_SOFT_RESET);
893 }
894}
895
896static int bnx2x_xmac_enable(struct link_params *params,
897 struct link_vars *vars, u8 lb)
898{
899 u32 val, xmac_base;
900 struct bnx2x *bp = params->bp;
901 DP(NETIF_MSG_LINK, "enabling XMAC\n");
902
903 xmac_base = (params->port) ? GRCBASE_XMAC1 : GRCBASE_XMAC0;
904
905 bnx2x_xmac_init(bp, vars->line_speed);
906
907 /*
908 * This register determines on which events the MAC will assert
909 * error on the i/f to the NIG along w/ EOP.
910 */
911
912 /*
913 * This register tells the NIG whether to send traffic to UMAC
914 * or XMAC
915 */
916 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + params->port*4, 0);
917
918 /* Set Max packet size */
919 REG_WR(bp, xmac_base + XMAC_REG_RX_MAX_SIZE, 0x2710);
920
921 /* CRC append for Tx packets */
922 REG_WR(bp, xmac_base + XMAC_REG_TX_CTRL, 0xC800);
923
924 /* update PFC */
925 bnx2x_update_pfc_xmac(params, vars, 0);
926
927 /* Enable TX and RX */
928 val = XMAC_CTRL_REG_TX_EN | XMAC_CTRL_REG_RX_EN;
929
930 /* Check loopback mode */
931 if (lb)
932 val |= XMAC_CTRL_REG_CORE_LOCAL_LPBK;
933 REG_WR(bp, xmac_base + XMAC_REG_CTRL, val);
934 bnx2x_set_xumac_nig(params,
935 ((vars->flow_ctrl & BNX2X_FLOW_CTRL_TX) != 0), 1);
936
937 vars->mac_type = MAC_TYPE_XMAC;
938
939 return 0;
940}
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +0000941static int bnx2x_emac_enable(struct link_params *params,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +0000942 struct link_vars *vars, u8 lb)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700943{
944 struct bnx2x *bp = params->bp;
945 u8 port = params->port;
946 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
947 u32 val;
948
949 DP(NETIF_MSG_LINK, "enabling EMAC\n");
950
951 /* enable emac and not bmac */
952 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 1);
953
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700954 /* ASIC */
955 if (vars->phy_flags & PHY_XGXS_FLAG) {
956 u32 ser_lane = ((params->lane_config &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000957 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
958 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700959
960 DP(NETIF_MSG_LINK, "XGXS\n");
961 /* select the master lanes (out of 0-3) */
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000962 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, ser_lane);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700963 /* select XGXS */
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000964 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700965
966 } else { /* SerDes */
967 DP(NETIF_MSG_LINK, "SerDes\n");
968 /* select SerDes */
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000969 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700970 }
971
Eilon Greenstein811a2f22009-02-12 08:37:04 +0000972 bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000973 EMAC_RX_MODE_RESET);
Eilon Greenstein811a2f22009-02-12 08:37:04 +0000974 bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000975 EMAC_TX_MODE_RESET);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700976
977 if (CHIP_REV_IS_SLOW(bp)) {
978 /* config GMII mode */
979 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000980 EMAC_WR(bp, EMAC_REG_EMAC_MODE, (val | EMAC_MODE_PORT_GMII));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700981 } else { /* ASIC */
982 /* pause enable/disable */
983 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
984 EMAC_RX_MODE_FLOW_EN);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700985
986 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000987 (EMAC_TX_MODE_EXT_PAUSE_EN |
988 EMAC_TX_MODE_FLOW_EN));
989 if (!(params->feature_config_flags &
990 FEATURE_CONFIG_PFC_ENABLED)) {
991 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
992 bnx2x_bits_en(bp, emac_base +
993 EMAC_REG_EMAC_RX_MODE,
994 EMAC_RX_MODE_FLOW_EN);
995
996 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
997 bnx2x_bits_en(bp, emac_base +
998 EMAC_REG_EMAC_TX_MODE,
999 (EMAC_TX_MODE_EXT_PAUSE_EN |
1000 EMAC_TX_MODE_FLOW_EN));
1001 } else
1002 bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
1003 EMAC_TX_MODE_FLOW_EN);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001004 }
1005
1006 /* KEEP_VLAN_TAG, promiscuous */
1007 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_RX_MODE);
1008 val |= EMAC_RX_MODE_KEEP_VLAN_TAG | EMAC_RX_MODE_PROMISCUOUS;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001009
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001010 /*
1011 * Setting this bit causes MAC control frames (except for pause
1012 * frames) to be passed on for processing. This setting has no
1013 * affect on the operation of the pause frames. This bit effects
1014 * all packets regardless of RX Parser packet sorting logic.
1015 * Turn the PFC off to make sure we are in Xon state before
1016 * enabling it.
1017 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001018 EMAC_WR(bp, EMAC_REG_RX_PFC_MODE, 0);
1019 if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED) {
1020 DP(NETIF_MSG_LINK, "PFC is enabled\n");
1021 /* Enable PFC again */
1022 EMAC_WR(bp, EMAC_REG_RX_PFC_MODE,
1023 EMAC_REG_RX_PFC_MODE_RX_EN |
1024 EMAC_REG_RX_PFC_MODE_TX_EN |
1025 EMAC_REG_RX_PFC_MODE_PRIORITIES);
1026
1027 EMAC_WR(bp, EMAC_REG_RX_PFC_PARAM,
1028 ((0x0101 <<
1029 EMAC_REG_RX_PFC_PARAM_OPCODE_BITSHIFT) |
1030 (0x00ff <<
1031 EMAC_REG_RX_PFC_PARAM_PRIORITY_EN_BITSHIFT)));
1032 val |= EMAC_RX_MODE_KEEP_MAC_CONTROL;
1033 }
Eilon Greenstein3196a882008-08-13 15:58:49 -07001034 EMAC_WR(bp, EMAC_REG_EMAC_RX_MODE, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001035
1036 /* Set Loopback */
1037 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
1038 if (lb)
1039 val |= 0x810;
1040 else
1041 val &= ~0x810;
Eilon Greenstein3196a882008-08-13 15:58:49 -07001042 EMAC_WR(bp, EMAC_REG_EMAC_MODE, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001043
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001044 /* enable emac */
1045 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 1);
1046
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001047 /* enable emac for jumbo packets */
Eilon Greenstein3196a882008-08-13 15:58:49 -07001048 EMAC_WR(bp, EMAC_REG_EMAC_RX_MTU_SIZE,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001049 (EMAC_RX_MTU_SIZE_JUMBO_ENA |
1050 (ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD)));
1051
1052 /* strip CRC */
1053 REG_WR(bp, NIG_REG_NIG_INGRESS_EMAC0_NO_CRC + port*4, 0x1);
1054
1055 /* disable the NIG in/out to the bmac */
1056 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x0);
1057 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, 0x0);
1058 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x0);
1059
1060 /* enable the NIG in/out to the emac */
1061 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x1);
1062 val = 0;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001063 if ((params->feature_config_flags &
1064 FEATURE_CONFIG_PFC_ENABLED) ||
1065 (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001066 val = 1;
1067
1068 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, val);
1069 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x1);
1070
Yaniv Rosner02a23162011-01-31 04:22:53 +00001071 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001072
1073 vars->mac_type = MAC_TYPE_EMAC;
1074 return 0;
1075}
1076
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001077static void bnx2x_update_pfc_bmac1(struct link_params *params,
1078 struct link_vars *vars)
1079{
1080 u32 wb_data[2];
1081 struct bnx2x *bp = params->bp;
1082 u32 bmac_addr = params->port ? NIG_REG_INGRESS_BMAC1_MEM :
1083 NIG_REG_INGRESS_BMAC0_MEM;
1084
1085 u32 val = 0x14;
1086 if ((!(params->feature_config_flags &
1087 FEATURE_CONFIG_PFC_ENABLED)) &&
1088 (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX))
1089 /* Enable BigMAC to react on received Pause packets */
1090 val |= (1<<5);
1091 wb_data[0] = val;
1092 wb_data[1] = 0;
1093 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_CONTROL, wb_data, 2);
1094
1095 /* tx control */
1096 val = 0xc0;
1097 if (!(params->feature_config_flags &
1098 FEATURE_CONFIG_PFC_ENABLED) &&
1099 (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
1100 val |= 0x800000;
1101 wb_data[0] = val;
1102 wb_data[1] = 0;
1103 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_CONTROL, wb_data, 2);
1104}
1105
1106static void bnx2x_update_pfc_bmac2(struct link_params *params,
1107 struct link_vars *vars,
1108 u8 is_lb)
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001109{
1110 /*
1111 * Set rx control: Strip CRC and enable BigMAC to relay
1112 * control packets to the system as well
1113 */
1114 u32 wb_data[2];
1115 struct bnx2x *bp = params->bp;
1116 u32 bmac_addr = params->port ? NIG_REG_INGRESS_BMAC1_MEM :
1117 NIG_REG_INGRESS_BMAC0_MEM;
1118 u32 val = 0x14;
1119
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001120 if ((!(params->feature_config_flags &
1121 FEATURE_CONFIG_PFC_ENABLED)) &&
1122 (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX))
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001123 /* Enable BigMAC to react on received Pause packets */
1124 val |= (1<<5);
1125 wb_data[0] = val;
1126 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001127 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_CONTROL, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001128 udelay(30);
1129
1130 /* Tx control */
1131 val = 0xc0;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001132 if (!(params->feature_config_flags &
1133 FEATURE_CONFIG_PFC_ENABLED) &&
1134 (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001135 val |= 0x800000;
1136 wb_data[0] = val;
1137 wb_data[1] = 0;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001138 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_CONTROL, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001139
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001140 if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED) {
1141 DP(NETIF_MSG_LINK, "PFC is enabled\n");
1142 /* Enable PFC RX & TX & STATS and set 8 COS */
1143 wb_data[0] = 0x0;
1144 wb_data[0] |= (1<<0); /* RX */
1145 wb_data[0] |= (1<<1); /* TX */
1146 wb_data[0] |= (1<<2); /* Force initial Xon */
1147 wb_data[0] |= (1<<3); /* 8 cos */
1148 wb_data[0] |= (1<<5); /* STATS */
1149 wb_data[1] = 0;
1150 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_PFC_CONTROL,
1151 wb_data, 2);
1152 /* Clear the force Xon */
1153 wb_data[0] &= ~(1<<2);
1154 } else {
1155 DP(NETIF_MSG_LINK, "PFC is disabled\n");
1156 /* disable PFC RX & TX & STATS and set 8 COS */
1157 wb_data[0] = 0x8;
1158 wb_data[1] = 0;
1159 }
1160
1161 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_PFC_CONTROL, wb_data, 2);
1162
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001163 /*
1164 * Set Time (based unit is 512 bit time) between automatic
1165 * re-sending of PP packets amd enable automatic re-send of
1166 * Per-Priroity Packet as long as pp_gen is asserted and
1167 * pp_disable is low.
1168 */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001169 val = 0x8000;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001170 if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED)
1171 val |= (1<<16); /* enable automatic re-send */
1172
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001173 wb_data[0] = val;
1174 wb_data[1] = 0;
1175 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_PAUSE_CONTROL,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001176 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001177
1178 /* mac control */
1179 val = 0x3; /* Enable RX and TX */
1180 if (is_lb) {
1181 val |= 0x4; /* Local loopback */
1182 DP(NETIF_MSG_LINK, "enable bmac loopback\n");
1183 }
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001184 /* When PFC enabled, Pass pause frames towards the NIG. */
1185 if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED)
1186 val |= ((1<<6)|(1<<5));
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001187
1188 wb_data[0] = val;
1189 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001190 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_BMAC_CONTROL, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001191}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001192
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001193
1194/* PFC BRB internal port configuration params */
1195struct bnx2x_pfc_brb_threshold_val {
1196 u32 pause_xoff;
1197 u32 pause_xon;
1198 u32 full_xoff;
1199 u32 full_xon;
1200};
1201
1202struct bnx2x_pfc_brb_e3b0_val {
1203 u32 full_lb_xoff_th;
1204 u32 full_lb_xon_threshold;
1205 u32 lb_guarantied;
1206 u32 mac_0_class_t_guarantied;
1207 u32 mac_0_class_t_guarantied_hyst;
1208 u32 mac_1_class_t_guarantied;
1209 u32 mac_1_class_t_guarantied_hyst;
1210};
1211
1212struct bnx2x_pfc_brb_th_val {
1213 struct bnx2x_pfc_brb_threshold_val pauseable_th;
1214 struct bnx2x_pfc_brb_threshold_val non_pauseable_th;
1215};
1216static int bnx2x_pfc_brb_get_config_params(
1217 struct link_params *params,
1218 struct bnx2x_pfc_brb_th_val *config_val)
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001219{
1220 struct bnx2x *bp = params->bp;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001221 DP(NETIF_MSG_LINK, "Setting PFC BRB configuration\n");
1222 if (CHIP_IS_E2(bp)) {
1223 config_val->pauseable_th.pause_xoff =
1224 PFC_E2_BRB_MAC_PAUSE_XOFF_THR_PAUSE;
1225 config_val->pauseable_th.pause_xon =
1226 PFC_E2_BRB_MAC_PAUSE_XON_THR_PAUSE;
1227 config_val->pauseable_th.full_xoff =
1228 PFC_E2_BRB_MAC_FULL_XOFF_THR_PAUSE;
1229 config_val->pauseable_th.full_xon =
1230 PFC_E2_BRB_MAC_FULL_XON_THR_PAUSE;
1231 /* non pause able*/
1232 config_val->non_pauseable_th.pause_xoff =
1233 PFC_E2_BRB_MAC_PAUSE_XOFF_THR_NON_PAUSE;
1234 config_val->non_pauseable_th.pause_xon =
1235 PFC_E2_BRB_MAC_PAUSE_XON_THR_NON_PAUSE;
1236 config_val->non_pauseable_th.full_xoff =
1237 PFC_E2_BRB_MAC_FULL_XOFF_THR_NON_PAUSE;
1238 config_val->non_pauseable_th.full_xon =
1239 PFC_E2_BRB_MAC_FULL_XON_THR_NON_PAUSE;
1240 } else if (CHIP_IS_E3A0(bp)) {
1241 config_val->pauseable_th.pause_xoff =
1242 PFC_E3A0_BRB_MAC_PAUSE_XOFF_THR_PAUSE;
1243 config_val->pauseable_th.pause_xon =
1244 PFC_E3A0_BRB_MAC_PAUSE_XON_THR_PAUSE;
1245 config_val->pauseable_th.full_xoff =
1246 PFC_E3A0_BRB_MAC_FULL_XOFF_THR_PAUSE;
1247 config_val->pauseable_th.full_xon =
1248 PFC_E3A0_BRB_MAC_FULL_XON_THR_PAUSE;
1249 /* non pause able*/
1250 config_val->non_pauseable_th.pause_xoff =
1251 PFC_E3A0_BRB_MAC_PAUSE_XOFF_THR_NON_PAUSE;
1252 config_val->non_pauseable_th.pause_xon =
1253 PFC_E3A0_BRB_MAC_PAUSE_XON_THR_NON_PAUSE;
1254 config_val->non_pauseable_th.full_xoff =
1255 PFC_E3A0_BRB_MAC_FULL_XOFF_THR_NON_PAUSE;
1256 config_val->non_pauseable_th.full_xon =
1257 PFC_E3A0_BRB_MAC_FULL_XON_THR_NON_PAUSE;
1258 } else if (CHIP_IS_E3B0(bp)) {
1259 if (params->phy[INT_PHY].flags &
1260 FLAGS_4_PORT_MODE) {
1261 config_val->pauseable_th.pause_xoff =
1262 PFC_E3B0_4P_BRB_MAC_PAUSE_XOFF_THR_PAUSE;
1263 config_val->pauseable_th.pause_xon =
1264 PFC_E3B0_4P_BRB_MAC_PAUSE_XON_THR_PAUSE;
1265 config_val->pauseable_th.full_xoff =
1266 PFC_E3B0_4P_BRB_MAC_FULL_XOFF_THR_PAUSE;
1267 config_val->pauseable_th.full_xon =
1268 PFC_E3B0_4P_BRB_MAC_FULL_XON_THR_PAUSE;
1269 /* non pause able*/
1270 config_val->non_pauseable_th.pause_xoff =
1271 PFC_E3B0_4P_BRB_MAC_PAUSE_XOFF_THR_NON_PAUSE;
1272 config_val->non_pauseable_th.pause_xon =
1273 PFC_E3B0_4P_BRB_MAC_PAUSE_XON_THR_NON_PAUSE;
1274 config_val->non_pauseable_th.full_xoff =
1275 PFC_E3B0_4P_BRB_MAC_FULL_XOFF_THR_NON_PAUSE;
1276 config_val->non_pauseable_th.full_xon =
1277 PFC_E3B0_4P_BRB_MAC_FULL_XON_THR_NON_PAUSE;
1278 } else {
1279 config_val->pauseable_th.pause_xoff =
1280 PFC_E3B0_2P_BRB_MAC_PAUSE_XOFF_THR_PAUSE;
1281 config_val->pauseable_th.pause_xon =
1282 PFC_E3B0_2P_BRB_MAC_PAUSE_XON_THR_PAUSE;
1283 config_val->pauseable_th.full_xoff =
1284 PFC_E3B0_2P_BRB_MAC_FULL_XOFF_THR_PAUSE;
1285 config_val->pauseable_th.full_xon =
1286 PFC_E3B0_2P_BRB_MAC_FULL_XON_THR_PAUSE;
1287 /* non pause able*/
1288 config_val->non_pauseable_th.pause_xoff =
1289 PFC_E3B0_2P_BRB_MAC_PAUSE_XOFF_THR_NON_PAUSE;
1290 config_val->non_pauseable_th.pause_xon =
1291 PFC_E3B0_2P_BRB_MAC_PAUSE_XON_THR_NON_PAUSE;
1292 config_val->non_pauseable_th.full_xoff =
1293 PFC_E3B0_2P_BRB_MAC_FULL_XOFF_THR_NON_PAUSE;
1294 config_val->non_pauseable_th.full_xon =
1295 PFC_E3B0_2P_BRB_MAC_FULL_XON_THR_NON_PAUSE;
1296 }
1297 } else
1298 return -EINVAL;
1299
1300 return 0;
1301}
1302
1303
1304static void bnx2x_pfc_brb_get_e3b0_config_params(struct link_params *params,
1305 struct bnx2x_pfc_brb_e3b0_val
1306 *e3b0_val,
1307 u32 cos0_pauseable,
1308 u32 cos1_pauseable)
1309{
1310 if (params->phy[INT_PHY].flags & FLAGS_4_PORT_MODE) {
1311 e3b0_val->full_lb_xoff_th =
1312 PFC_E3B0_4P_BRB_FULL_LB_XOFF_THR;
1313 e3b0_val->full_lb_xon_threshold =
1314 PFC_E3B0_4P_BRB_FULL_LB_XON_THR;
1315 e3b0_val->lb_guarantied =
1316 PFC_E3B0_4P_LB_GUART;
1317 e3b0_val->mac_0_class_t_guarantied =
1318 PFC_E3B0_4P_BRB_MAC_0_CLASS_T_GUART;
1319 e3b0_val->mac_0_class_t_guarantied_hyst =
1320 PFC_E3B0_4P_BRB_MAC_0_CLASS_T_GUART_HYST;
1321 e3b0_val->mac_1_class_t_guarantied =
1322 PFC_E3B0_4P_BRB_MAC_1_CLASS_T_GUART;
1323 e3b0_val->mac_1_class_t_guarantied_hyst =
1324 PFC_E3B0_4P_BRB_MAC_1_CLASS_T_GUART_HYST;
1325 } else {
1326 e3b0_val->full_lb_xoff_th =
1327 PFC_E3B0_2P_BRB_FULL_LB_XOFF_THR;
1328 e3b0_val->full_lb_xon_threshold =
1329 PFC_E3B0_2P_BRB_FULL_LB_XON_THR;
1330 e3b0_val->mac_0_class_t_guarantied_hyst =
1331 PFC_E3B0_2P_BRB_MAC_0_CLASS_T_GUART_HYST;
1332 e3b0_val->mac_1_class_t_guarantied =
1333 PFC_E3B0_2P_BRB_MAC_1_CLASS_T_GUART;
1334 e3b0_val->mac_1_class_t_guarantied_hyst =
1335 PFC_E3B0_2P_BRB_MAC_1_CLASS_T_GUART_HYST;
1336
1337 if (cos0_pauseable != cos1_pauseable) {
1338 /* nonpauseable= Lossy + pauseable = Lossless*/
1339 e3b0_val->lb_guarantied =
1340 PFC_E3B0_2P_MIX_PAUSE_LB_GUART;
1341 e3b0_val->mac_0_class_t_guarantied =
1342 PFC_E3B0_2P_MIX_PAUSE_MAC_0_CLASS_T_GUART;
1343 } else if (cos0_pauseable) {
1344 /* Lossless +Lossless*/
1345 e3b0_val->lb_guarantied =
1346 PFC_E3B0_2P_PAUSE_LB_GUART;
1347 e3b0_val->mac_0_class_t_guarantied =
1348 PFC_E3B0_2P_PAUSE_MAC_0_CLASS_T_GUART;
1349 } else {
1350 /* Lossy +Lossy*/
1351 e3b0_val->lb_guarantied =
1352 PFC_E3B0_2P_NON_PAUSE_LB_GUART;
1353 e3b0_val->mac_0_class_t_guarantied =
1354 PFC_E3B0_2P_NON_PAUSE_MAC_0_CLASS_T_GUART;
1355 }
1356 }
1357}
1358static int bnx2x_update_pfc_brb(struct link_params *params,
1359 struct link_vars *vars,
1360 struct bnx2x_nig_brb_pfc_port_params
1361 *pfc_params)
1362{
1363 struct bnx2x *bp = params->bp;
1364 struct bnx2x_pfc_brb_th_val config_val = { {0} };
1365 struct bnx2x_pfc_brb_threshold_val *reg_th_config =
1366 &config_val.pauseable_th;
1367 struct bnx2x_pfc_brb_e3b0_val e3b0_val = {0};
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001368 int set_pfc = params->feature_config_flags &
1369 FEATURE_CONFIG_PFC_ENABLED;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001370 int bnx2x_status = 0;
1371 u8 port = params->port;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001372
1373 /* default - pause configuration */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001374 reg_th_config = &config_val.pauseable_th;
1375 bnx2x_status = bnx2x_pfc_brb_get_config_params(params, &config_val);
1376 if (0 != bnx2x_status)
1377 return bnx2x_status;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001378
1379 if (set_pfc && pfc_params)
1380 /* First COS */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001381 if (!pfc_params->cos0_pauseable)
1382 reg_th_config = &config_val.non_pauseable_th;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001383 /*
1384 * The number of free blocks below which the pause signal to class 0
1385 * of MAC #n is asserted. n=0,1
1386 */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001387 REG_WR(bp, (port) ? BRB1_REG_PAUSE_0_XOFF_THRESHOLD_1 :
1388 BRB1_REG_PAUSE_0_XOFF_THRESHOLD_0 ,
1389 reg_th_config->pause_xoff);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001390 /*
1391 * The number of free blocks above which the pause signal to class 0
1392 * of MAC #n is de-asserted. n=0,1
1393 */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001394 REG_WR(bp, (port) ? BRB1_REG_PAUSE_0_XON_THRESHOLD_1 :
1395 BRB1_REG_PAUSE_0_XON_THRESHOLD_0 , reg_th_config->pause_xon);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001396 /*
1397 * The number of free blocks below which the full signal to class 0
1398 * of MAC #n is asserted. n=0,1
1399 */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001400 REG_WR(bp, (port) ? BRB1_REG_FULL_0_XOFF_THRESHOLD_1 :
1401 BRB1_REG_FULL_0_XOFF_THRESHOLD_0 , reg_th_config->full_xoff);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001402 /*
1403 * The number of free blocks above which the full signal to class 0
1404 * of MAC #n is de-asserted. n=0,1
1405 */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001406 REG_WR(bp, (port) ? BRB1_REG_FULL_0_XON_THRESHOLD_1 :
1407 BRB1_REG_FULL_0_XON_THRESHOLD_0 , reg_th_config->full_xon);
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001408
1409 if (set_pfc && pfc_params) {
1410 /* Second COS */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001411 if (pfc_params->cos1_pauseable)
1412 reg_th_config = &config_val.pauseable_th;
1413 else
1414 reg_th_config = &config_val.non_pauseable_th;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001415 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001416 * The number of free blocks below which the pause signal to
1417 * class 1 of MAC #n is asserted. n=0,1
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001418 **/
1419 REG_WR(bp, (port) ? BRB1_REG_PAUSE_1_XOFF_THRESHOLD_1 :
1420 BRB1_REG_PAUSE_1_XOFF_THRESHOLD_0,
1421 reg_th_config->pause_xoff);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001422 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001423 * The number of free blocks above which the pause signal to
1424 * class 1 of MAC #n is de-asserted. n=0,1
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001425 */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001426 REG_WR(bp, (port) ? BRB1_REG_PAUSE_1_XON_THRESHOLD_1 :
1427 BRB1_REG_PAUSE_1_XON_THRESHOLD_0,
1428 reg_th_config->pause_xon);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001429 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001430 * The number of free blocks below which the full signal to
1431 * class 1 of MAC #n is asserted. n=0,1
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001432 */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001433 REG_WR(bp, (port) ? BRB1_REG_FULL_1_XOFF_THRESHOLD_1 :
1434 BRB1_REG_FULL_1_XOFF_THRESHOLD_0,
1435 reg_th_config->full_xoff);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001436 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001437 * The number of free blocks above which the full signal to
1438 * class 1 of MAC #n is de-asserted. n=0,1
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001439 */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001440 REG_WR(bp, (port) ? BRB1_REG_FULL_1_XON_THRESHOLD_1 :
1441 BRB1_REG_FULL_1_XON_THRESHOLD_0,
1442 reg_th_config->full_xon);
1443
1444
1445 if (CHIP_IS_E3B0(bp)) {
1446 /*Should be done by init tool */
1447 /*
1448 * BRB_empty_for_dup = BRB1_REG_BRB_EMPTY_THRESHOLD
1449 * reset value
1450 * 944
1451 */
1452
1453 /**
1454 * The hysteresis on the guarantied buffer space for the Lb port
1455 * before signaling XON.
1456 **/
1457 REG_WR(bp, BRB1_REG_LB_GUARANTIED_HYST, 80);
1458
1459 bnx2x_pfc_brb_get_e3b0_config_params(
1460 params,
1461 &e3b0_val,
1462 pfc_params->cos0_pauseable,
1463 pfc_params->cos1_pauseable);
1464 /**
1465 * The number of free blocks below which the full signal to the
1466 * LB port is asserted.
1467 */
1468 REG_WR(bp, BRB1_REG_FULL_LB_XOFF_THRESHOLD,
1469 e3b0_val.full_lb_xoff_th);
1470 /**
1471 * The number of free blocks above which the full signal to the
1472 * LB port is de-asserted.
1473 */
1474 REG_WR(bp, BRB1_REG_FULL_LB_XON_THRESHOLD,
1475 e3b0_val.full_lb_xon_threshold);
1476 /**
1477 * The number of blocks guarantied for the MAC #n port. n=0,1
1478 */
1479
1480 /*The number of blocks guarantied for the LB port.*/
1481 REG_WR(bp, BRB1_REG_LB_GUARANTIED,
1482 e3b0_val.lb_guarantied);
1483
1484 /**
1485 * The number of blocks guarantied for the MAC #n port.
1486 */
1487 REG_WR(bp, BRB1_REG_MAC_GUARANTIED_0,
1488 2 * e3b0_val.mac_0_class_t_guarantied);
1489 REG_WR(bp, BRB1_REG_MAC_GUARANTIED_1,
1490 2 * e3b0_val.mac_1_class_t_guarantied);
1491 /**
1492 * The number of blocks guarantied for class #t in MAC0. t=0,1
1493 */
1494 REG_WR(bp, BRB1_REG_MAC_0_CLASS_0_GUARANTIED,
1495 e3b0_val.mac_0_class_t_guarantied);
1496 REG_WR(bp, BRB1_REG_MAC_0_CLASS_1_GUARANTIED,
1497 e3b0_val.mac_0_class_t_guarantied);
1498 /**
1499 * The hysteresis on the guarantied buffer space for class in
1500 * MAC0. t=0,1
1501 */
1502 REG_WR(bp, BRB1_REG_MAC_0_CLASS_0_GUARANTIED_HYST,
1503 e3b0_val.mac_0_class_t_guarantied_hyst);
1504 REG_WR(bp, BRB1_REG_MAC_0_CLASS_1_GUARANTIED_HYST,
1505 e3b0_val.mac_0_class_t_guarantied_hyst);
1506
1507 /**
1508 * The number of blocks guarantied for class #t in MAC1.t=0,1
1509 */
1510 REG_WR(bp, BRB1_REG_MAC_1_CLASS_0_GUARANTIED,
1511 e3b0_val.mac_1_class_t_guarantied);
1512 REG_WR(bp, BRB1_REG_MAC_1_CLASS_1_GUARANTIED,
1513 e3b0_val.mac_1_class_t_guarantied);
1514 /**
1515 * The hysteresis on the guarantied buffer space for class #t
1516 * in MAC1. t=0,1
1517 */
1518 REG_WR(bp, BRB1_REG_MAC_1_CLASS_0_GUARANTIED_HYST,
1519 e3b0_val.mac_1_class_t_guarantied_hyst);
1520 REG_WR(bp, BRB1_REG_MAC_1_CLASS_1_GUARANTIED_HYST,
1521 e3b0_val.mac_1_class_t_guarantied_hyst);
1522
1523 }
1524
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001525 }
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001526
1527 return bnx2x_status;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001528}
1529
Vlad Zolotarov619c5cb2011-06-14 14:33:44 +03001530/******************************************************************************
1531* Description:
1532* This function is needed because NIG ARB_CREDIT_WEIGHT_X are
1533* not continues and ARB_CREDIT_WEIGHT_0 + offset is suitable.
1534******************************************************************************/
1535int bnx2x_pfc_nig_rx_priority_mask(struct bnx2x *bp,
1536 u8 cos_entry,
1537 u32 priority_mask, u8 port)
1538{
1539 u32 nig_reg_rx_priority_mask_add = 0;
1540
1541 switch (cos_entry) {
1542 case 0:
1543 nig_reg_rx_priority_mask_add = (port) ?
1544 NIG_REG_P1_RX_COS0_PRIORITY_MASK :
1545 NIG_REG_P0_RX_COS0_PRIORITY_MASK;
1546 break;
1547 case 1:
1548 nig_reg_rx_priority_mask_add = (port) ?
1549 NIG_REG_P1_RX_COS1_PRIORITY_MASK :
1550 NIG_REG_P0_RX_COS1_PRIORITY_MASK;
1551 break;
1552 case 2:
1553 nig_reg_rx_priority_mask_add = (port) ?
1554 NIG_REG_P1_RX_COS2_PRIORITY_MASK :
1555 NIG_REG_P0_RX_COS2_PRIORITY_MASK;
1556 break;
1557 case 3:
1558 if (port)
1559 return -EINVAL;
1560 nig_reg_rx_priority_mask_add = NIG_REG_P0_RX_COS3_PRIORITY_MASK;
1561 break;
1562 case 4:
1563 if (port)
1564 return -EINVAL;
1565 nig_reg_rx_priority_mask_add = NIG_REG_P0_RX_COS4_PRIORITY_MASK;
1566 break;
1567 case 5:
1568 if (port)
1569 return -EINVAL;
1570 nig_reg_rx_priority_mask_add = NIG_REG_P0_RX_COS5_PRIORITY_MASK;
1571 break;
1572 }
1573
1574 REG_WR(bp, nig_reg_rx_priority_mask_add, priority_mask);
1575
1576 return 0;
1577}
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001578static void bnx2x_update_pfc_nig(struct link_params *params,
1579 struct link_vars *vars,
1580 struct bnx2x_nig_brb_pfc_port_params *nig_params)
1581{
1582 u32 xcm_mask = 0, ppp_enable = 0, pause_enable = 0, llfc_out_en = 0;
1583 u32 llfc_enable = 0, xcm0_out_en = 0, p0_hwpfc_enable = 0;
1584 u32 pkt_priority_to_cos = 0;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001585 struct bnx2x *bp = params->bp;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001586 u8 port = params->port;
1587
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001588 int set_pfc = params->feature_config_flags &
1589 FEATURE_CONFIG_PFC_ENABLED;
1590 DP(NETIF_MSG_LINK, "updating pfc nig parameters\n");
1591
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001592 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001593 * When NIG_LLH0_XCM_MASK_REG_LLHX_XCM_MASK_BCN bit is set
1594 * MAC control frames (that are not pause packets)
1595 * will be forwarded to the XCM.
1596 */
1597 xcm_mask = REG_RD(bp,
1598 port ? NIG_REG_LLH1_XCM_MASK :
1599 NIG_REG_LLH0_XCM_MASK);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001600 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001601 * nig params will override non PFC params, since it's possible to
1602 * do transition from PFC to SAFC
1603 */
1604 if (set_pfc) {
1605 pause_enable = 0;
1606 llfc_out_en = 0;
1607 llfc_enable = 0;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001608 if (CHIP_IS_E3(bp))
1609 ppp_enable = 0;
1610 else
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001611 ppp_enable = 1;
1612 xcm_mask &= ~(port ? NIG_LLH1_XCM_MASK_REG_LLH1_XCM_MASK_BCN :
1613 NIG_LLH0_XCM_MASK_REG_LLH0_XCM_MASK_BCN);
1614 xcm0_out_en = 0;
1615 p0_hwpfc_enable = 1;
1616 } else {
1617 if (nig_params) {
1618 llfc_out_en = nig_params->llfc_out_en;
1619 llfc_enable = nig_params->llfc_enable;
1620 pause_enable = nig_params->pause_enable;
1621 } else /*defaul non PFC mode - PAUSE */
1622 pause_enable = 1;
1623
1624 xcm_mask |= (port ? NIG_LLH1_XCM_MASK_REG_LLH1_XCM_MASK_BCN :
1625 NIG_LLH0_XCM_MASK_REG_LLH0_XCM_MASK_BCN);
1626 xcm0_out_en = 1;
1627 }
1628
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001629 if (CHIP_IS_E3(bp))
1630 REG_WR(bp, port ? NIG_REG_BRB1_PAUSE_IN_EN :
1631 NIG_REG_BRB0_PAUSE_IN_EN, pause_enable);
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001632 REG_WR(bp, port ? NIG_REG_LLFC_OUT_EN_1 :
1633 NIG_REG_LLFC_OUT_EN_0, llfc_out_en);
1634 REG_WR(bp, port ? NIG_REG_LLFC_ENABLE_1 :
1635 NIG_REG_LLFC_ENABLE_0, llfc_enable);
1636 REG_WR(bp, port ? NIG_REG_PAUSE_ENABLE_1 :
1637 NIG_REG_PAUSE_ENABLE_0, pause_enable);
1638
1639 REG_WR(bp, port ? NIG_REG_PPP_ENABLE_1 :
1640 NIG_REG_PPP_ENABLE_0, ppp_enable);
1641
1642 REG_WR(bp, port ? NIG_REG_LLH1_XCM_MASK :
1643 NIG_REG_LLH0_XCM_MASK, xcm_mask);
1644
1645 REG_WR(bp, NIG_REG_LLFC_EGRESS_SRC_ENABLE_0, 0x7);
1646
1647 /* output enable for RX_XCM # IF */
1648 REG_WR(bp, NIG_REG_XCM0_OUT_EN, xcm0_out_en);
1649
1650 /* HW PFC TX enable */
1651 REG_WR(bp, NIG_REG_P0_HWPFC_ENABLE, p0_hwpfc_enable);
1652
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001653 if (nig_params) {
Vlad Zolotarov619c5cb2011-06-14 14:33:44 +03001654 u8 i = 0;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001655 pkt_priority_to_cos = nig_params->pkt_priority_to_cos;
1656
Vlad Zolotarov619c5cb2011-06-14 14:33:44 +03001657 for (i = 0; i < nig_params->num_of_rx_cos_priority_mask; i++)
1658 bnx2x_pfc_nig_rx_priority_mask(bp, i,
1659 nig_params->rx_cos_priority_mask[i], port);
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001660
1661 REG_WR(bp, port ? NIG_REG_LLFC_HIGH_PRIORITY_CLASSES_1 :
1662 NIG_REG_LLFC_HIGH_PRIORITY_CLASSES_0,
1663 nig_params->llfc_high_priority_classes);
1664
1665 REG_WR(bp, port ? NIG_REG_LLFC_LOW_PRIORITY_CLASSES_1 :
1666 NIG_REG_LLFC_LOW_PRIORITY_CLASSES_0,
1667 nig_params->llfc_low_priority_classes);
1668 }
1669 REG_WR(bp, port ? NIG_REG_P1_PKT_PRIORITY_TO_COS :
1670 NIG_REG_P0_PKT_PRIORITY_TO_COS,
1671 pkt_priority_to_cos);
1672}
1673
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001674int bnx2x_update_pfc(struct link_params *params,
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001675 struct link_vars *vars,
1676 struct bnx2x_nig_brb_pfc_port_params *pfc_params)
1677{
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001678 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001679 * The PFC and pause are orthogonal to one another, meaning when
1680 * PFC is enabled, the pause are disabled, and when PFC is
1681 * disabled, pause are set according to the pause result.
1682 */
1683 u32 val;
1684 struct bnx2x *bp = params->bp;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001685 int bnx2x_status = 0;
1686 u8 bmac_loopback = (params->loopback_mode == LOOPBACK_BMAC);
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001687 /* update NIG params */
1688 bnx2x_update_pfc_nig(params, vars, pfc_params);
1689
1690 /* update BRB params */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001691 bnx2x_status = bnx2x_update_pfc_brb(params, vars, pfc_params);
1692 if (0 != bnx2x_status)
1693 return bnx2x_status;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001694
1695 if (!vars->link_up)
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001696 return bnx2x_status;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001697
1698 DP(NETIF_MSG_LINK, "About to update PFC in BMAC\n");
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001699 if (CHIP_IS_E3(bp))
1700 bnx2x_update_pfc_xmac(params, vars, 0);
1701 else {
1702 val = REG_RD(bp, MISC_REG_RESET_REG_2);
1703 if ((val &
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00001704 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << params->port))
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001705 == 0) {
1706 DP(NETIF_MSG_LINK, "About to update PFC in EMAC\n");
1707 bnx2x_emac_enable(params, vars, 0);
1708 return bnx2x_status;
1709 }
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001710
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001711 if (CHIP_IS_E2(bp))
1712 bnx2x_update_pfc_bmac2(params, vars, bmac_loopback);
1713 else
1714 bnx2x_update_pfc_bmac1(params, vars);
1715
1716 val = 0;
1717 if ((params->feature_config_flags &
1718 FEATURE_CONFIG_PFC_ENABLED) ||
1719 (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
1720 val = 1;
1721 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + params->port*4, val);
1722 }
1723 return bnx2x_status;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001724}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001725
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001726
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00001727static int bnx2x_bmac1_enable(struct link_params *params,
1728 struct link_vars *vars,
1729 u8 is_lb)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001730{
1731 struct bnx2x *bp = params->bp;
1732 u8 port = params->port;
1733 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
1734 NIG_REG_INGRESS_BMAC0_MEM;
1735 u32 wb_data[2];
1736 u32 val;
1737
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001738 DP(NETIF_MSG_LINK, "Enabling BigMAC1\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001739
1740 /* XGXS control */
1741 wb_data[0] = 0x3c;
1742 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001743 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_XGXS_CONTROL,
1744 wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001745
1746 /* tx MAC SA */
1747 wb_data[0] = ((params->mac_addr[2] << 24) |
1748 (params->mac_addr[3] << 16) |
1749 (params->mac_addr[4] << 8) |
1750 params->mac_addr[5]);
1751 wb_data[1] = ((params->mac_addr[0] << 8) |
1752 params->mac_addr[1]);
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001753 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_SOURCE_ADDR, wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001754
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001755 /* mac control */
1756 val = 0x3;
1757 if (is_lb) {
1758 val |= 0x4;
1759 DP(NETIF_MSG_LINK, "enable bmac loopback\n");
1760 }
1761 wb_data[0] = val;
1762 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001763 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL, wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001764
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001765 /* set rx mtu */
1766 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
1767 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001768 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_MAX_SIZE, wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001769
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001770 bnx2x_update_pfc_bmac1(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001771
1772 /* set tx mtu */
1773 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
1774 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001775 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_MAX_SIZE, wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001776
1777 /* set cnt max size */
1778 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
1779 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001780 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_CNT_MAX_SIZE, wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001781
1782 /* configure safc */
1783 wb_data[0] = 0x1000200;
1784 wb_data[1] = 0;
1785 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_LLFC_MSG_FLDS,
1786 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001787
1788 return 0;
1789}
1790
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00001791static int bnx2x_bmac2_enable(struct link_params *params,
1792 struct link_vars *vars,
1793 u8 is_lb)
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001794{
1795 struct bnx2x *bp = params->bp;
1796 u8 port = params->port;
1797 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
1798 NIG_REG_INGRESS_BMAC0_MEM;
1799 u32 wb_data[2];
1800
1801 DP(NETIF_MSG_LINK, "Enabling BigMAC2\n");
1802
1803 wb_data[0] = 0;
1804 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001805 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_BMAC_CONTROL, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001806 udelay(30);
1807
1808 /* XGXS control: Reset phy HW, MDIO registers, PHY PLL and BMAC */
1809 wb_data[0] = 0x3c;
1810 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001811 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_BMAC_XGXS_CONTROL,
1812 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001813
1814 udelay(30);
1815
1816 /* tx MAC SA */
1817 wb_data[0] = ((params->mac_addr[2] << 24) |
1818 (params->mac_addr[3] << 16) |
1819 (params->mac_addr[4] << 8) |
1820 params->mac_addr[5]);
1821 wb_data[1] = ((params->mac_addr[0] << 8) |
1822 params->mac_addr[1]);
1823 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_SOURCE_ADDR,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001824 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001825
1826 udelay(30);
1827
1828 /* Configure SAFC */
1829 wb_data[0] = 0x1000200;
1830 wb_data[1] = 0;
1831 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_LLFC_MSG_FLDS,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001832 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001833 udelay(30);
1834
1835 /* set rx mtu */
1836 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
1837 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001838 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_MAX_SIZE, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001839 udelay(30);
1840
1841 /* set tx mtu */
1842 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
1843 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001844 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_MAX_SIZE, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001845 udelay(30);
1846 /* set cnt max size */
1847 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD - 2;
1848 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001849 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_CNT_MAX_SIZE, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001850 udelay(30);
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001851 bnx2x_update_pfc_bmac2(params, vars, is_lb);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001852
1853 return 0;
1854}
1855
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00001856static int bnx2x_bmac_enable(struct link_params *params,
1857 struct link_vars *vars,
1858 u8 is_lb)
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001859{
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00001860 int rc = 0;
1861 u8 port = params->port;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001862 struct bnx2x *bp = params->bp;
1863 u32 val;
1864 /* reset and unreset the BigMac */
1865 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001866 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
Yaniv Rosner1d9c05d2010-11-01 05:32:25 +00001867 msleep(1);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001868
1869 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001870 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001871
1872 /* enable access for bmac registers */
1873 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
1874
1875 /* Enable BMAC according to BMAC type*/
1876 if (CHIP_IS_E2(bp))
1877 rc = bnx2x_bmac2_enable(params, vars, is_lb);
1878 else
1879 rc = bnx2x_bmac1_enable(params, vars, is_lb);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001880 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0x1);
1881 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 0x0);
1882 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 0x0);
1883 val = 0;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001884 if ((params->feature_config_flags &
1885 FEATURE_CONFIG_PFC_ENABLED) ||
1886 (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001887 val = 1;
1888 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, val);
1889 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x0);
1890 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x0);
1891 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, 0x0);
1892 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x1);
1893 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x1);
1894
1895 vars->mac_type = MAC_TYPE_BMAC;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001896 return rc;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001897}
1898
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001899
1900static void bnx2x_update_mng(struct link_params *params, u32 link_status)
1901{
1902 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00001903
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001904 REG_WR(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001905 offsetof(struct shmem_region,
1906 port_mb[params->port].link_status), link_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001907}
1908
1909static void bnx2x_bmac_rx_disable(struct bnx2x *bp, u8 port)
1910{
1911 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001912 NIG_REG_INGRESS_BMAC0_MEM;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001913 u32 wb_data[2];
Eilon Greenstein3196a882008-08-13 15:58:49 -07001914 u32 nig_bmac_enable = REG_RD(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001915
1916 /* Only if the bmac is out of reset */
1917 if (REG_RD(bp, MISC_REG_RESET_REG_2) &
1918 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port) &&
1919 nig_bmac_enable) {
1920
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001921 if (CHIP_IS_E2(bp)) {
1922 /* Clear Rx Enable bit in BMAC_CONTROL register */
1923 REG_RD_DMAE(bp, bmac_addr +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001924 BIGMAC2_REGISTER_BMAC_CONTROL,
1925 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001926 wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
1927 REG_WR_DMAE(bp, bmac_addr +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001928 BIGMAC2_REGISTER_BMAC_CONTROL,
1929 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001930 } else {
1931 /* Clear Rx Enable bit in BMAC_CONTROL register */
1932 REG_RD_DMAE(bp, bmac_addr +
1933 BIGMAC_REGISTER_BMAC_CONTROL,
1934 wb_data, 2);
1935 wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
1936 REG_WR_DMAE(bp, bmac_addr +
1937 BIGMAC_REGISTER_BMAC_CONTROL,
1938 wb_data, 2);
1939 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001940 msleep(1);
1941 }
1942}
1943
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00001944static int bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl,
1945 u32 line_speed)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001946{
1947 struct bnx2x *bp = params->bp;
1948 u8 port = params->port;
1949 u32 init_crd, crd;
1950 u32 count = 1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001951
1952 /* disable port */
1953 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x1);
1954
1955 /* wait for init credit */
1956 init_crd = REG_RD(bp, PBF_REG_P0_INIT_CRD + port*4);
1957 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
1958 DP(NETIF_MSG_LINK, "init_crd 0x%x crd 0x%x\n", init_crd, crd);
1959
1960 while ((init_crd != crd) && count) {
1961 msleep(5);
1962
1963 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
1964 count--;
1965 }
1966 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
1967 if (init_crd != crd) {
1968 DP(NETIF_MSG_LINK, "BUG! init_crd 0x%x != crd 0x%x\n",
1969 init_crd, crd);
1970 return -EINVAL;
1971 }
1972
David S. Millerc0700f92008-12-16 23:53:20 -08001973 if (flow_ctrl & BNX2X_FLOW_CTRL_RX ||
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001974 line_speed == SPEED_10 ||
1975 line_speed == SPEED_100 ||
1976 line_speed == SPEED_1000 ||
1977 line_speed == SPEED_2500) {
1978 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001979 /* update threshold */
1980 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, 0);
1981 /* update init credit */
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001982 init_crd = 778; /* (800-18-4) */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001983
1984 } else {
1985 u32 thresh = (ETH_MAX_JUMBO_PACKET_SIZE +
1986 ETH_OVREHEAD)/16;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001987 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001988 /* update threshold */
1989 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, thresh);
1990 /* update init credit */
1991 switch (line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001992 case SPEED_10000:
1993 init_crd = thresh + 553 - 22;
1994 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001995 default:
1996 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
1997 line_speed);
1998 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001999 }
2000 }
2001 REG_WR(bp, PBF_REG_P0_INIT_CRD + port*4, init_crd);
2002 DP(NETIF_MSG_LINK, "PBF updated to speed %d credit %d\n",
2003 line_speed, init_crd);
2004
2005 /* probe the credit changes */
2006 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x1);
2007 msleep(5);
2008 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x0);
2009
2010 /* enable port */
2011 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x0);
2012 return 0;
2013}
2014
Dmitry Kravkove8920672011-05-04 23:52:40 +00002015/**
2016 * bnx2x_get_emac_base - retrive emac base address
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002017 *
Dmitry Kravkove8920672011-05-04 23:52:40 +00002018 * @bp: driver handle
2019 * @mdc_mdio_access: access type
2020 * @port: port id
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002021 *
2022 * This function selects the MDC/MDIO access (through emac0 or
2023 * emac1) depend on the mdc_mdio_access, port, port swapped. Each
2024 * phy has a default access mode, which could also be overridden
2025 * by nvram configuration. This parameter, whether this is the
2026 * default phy configuration, or the nvram overrun
2027 * configuration, is passed here as mdc_mdio_access and selects
2028 * the emac_base for the CL45 read/writes operations
2029 */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002030static u32 bnx2x_get_emac_base(struct bnx2x *bp,
2031 u32 mdc_mdio_access, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002032{
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002033 u32 emac_base = 0;
2034 switch (mdc_mdio_access) {
2035 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_PHY_TYPE:
2036 break;
2037 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC0:
2038 if (REG_RD(bp, NIG_REG_PORT_SWAP))
2039 emac_base = GRCBASE_EMAC1;
2040 else
2041 emac_base = GRCBASE_EMAC0;
2042 break;
2043 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1:
Eilon Greenstein589abe32009-02-12 08:36:55 +00002044 if (REG_RD(bp, NIG_REG_PORT_SWAP))
2045 emac_base = GRCBASE_EMAC0;
2046 else
2047 emac_base = GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002048 break;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002049 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH:
2050 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
2051 break;
2052 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_SWAPPED:
Eilon Greenstein6378c022008-08-13 15:59:25 -07002053 emac_base = (port) ? GRCBASE_EMAC0 : GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002054 break;
2055 default:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002056 break;
2057 }
2058 return emac_base;
2059
2060}
2061
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002062/******************************************************************/
2063/* CL45 access functions */
2064/******************************************************************/
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00002065static int bnx2x_cl45_read(struct bnx2x *bp, struct bnx2x_phy *phy,
2066 u8 devad, u16 reg, u16 *ret_val)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002067{
Yaniv Rosnera198c142011-05-31 21:29:42 +00002068 u32 val;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002069 u16 i;
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00002070 int rc = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002071
2072 /* address */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002073 val = ((phy->addr << 21) | (devad << 16) | reg |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002074 EMAC_MDIO_COMM_COMMAND_ADDRESS |
2075 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002076 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002077
2078 for (i = 0; i < 50; i++) {
2079 udelay(10);
2080
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002081 val = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002082 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
2083 udelay(5);
2084 break;
2085 }
2086 }
2087 if (val & EMAC_MDIO_COMM_START_BUSY) {
2088 DP(NETIF_MSG_LINK, "read phy register failed\n");
Yaniv Rosner6d870c32011-01-31 04:22:20 +00002089 netdev_err(bp->dev, "MDC/MDIO access timeout\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002090 *ret_val = 0;
2091 rc = -EFAULT;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002092 } else {
2093 /* data */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002094 val = ((phy->addr << 21) | (devad << 16) |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002095 EMAC_MDIO_COMM_COMMAND_READ_45 |
2096 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002097 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002098
2099 for (i = 0; i < 50; i++) {
2100 udelay(10);
2101
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002102 val = REG_RD(bp, phy->mdio_ctrl +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002103 EMAC_REG_EMAC_MDIO_COMM);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002104 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
2105 *ret_val = (u16)(val & EMAC_MDIO_COMM_DATA);
2106 break;
2107 }
2108 }
2109 if (val & EMAC_MDIO_COMM_START_BUSY) {
2110 DP(NETIF_MSG_LINK, "read phy register failed\n");
Yaniv Rosner6d870c32011-01-31 04:22:20 +00002111 netdev_err(bp->dev, "MDC/MDIO access timeout\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002112 *ret_val = 0;
2113 rc = -EFAULT;
2114 }
2115 }
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00002116 /* Work around for E3 A0 */
2117 if (phy->flags & FLAGS_MDC_MDIO_WA) {
2118 phy->flags ^= FLAGS_DUMMY_READ;
2119 if (phy->flags & FLAGS_DUMMY_READ) {
2120 u16 temp_val;
2121 bnx2x_cl45_read(bp, phy, devad, 0xf, &temp_val);
2122 }
2123 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002124
Yaniv Rosnera198c142011-05-31 21:29:42 +00002125 return rc;
2126}
2127
2128static int bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy,
2129 u8 devad, u16 reg, u16 val)
2130{
2131 u32 tmp;
2132 u8 i;
2133 int rc = 0;
2134
2135 /* address */
2136
2137 tmp = ((phy->addr << 21) | (devad << 16) | reg |
2138 EMAC_MDIO_COMM_COMMAND_ADDRESS |
2139 EMAC_MDIO_COMM_START_BUSY);
2140 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
2141
2142 for (i = 0; i < 50; i++) {
2143 udelay(10);
2144
2145 tmp = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
2146 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
2147 udelay(5);
2148 break;
2149 }
2150 }
2151 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
2152 DP(NETIF_MSG_LINK, "write phy register failed\n");
2153 netdev_err(bp->dev, "MDC/MDIO access timeout\n");
2154 rc = -EFAULT;
2155
2156 } else {
2157 /* data */
2158 tmp = ((phy->addr << 21) | (devad << 16) | val |
2159 EMAC_MDIO_COMM_COMMAND_WRITE_45 |
2160 EMAC_MDIO_COMM_START_BUSY);
2161 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
2162
2163 for (i = 0; i < 50; i++) {
2164 udelay(10);
2165
2166 tmp = REG_RD(bp, phy->mdio_ctrl +
2167 EMAC_REG_EMAC_MDIO_COMM);
2168 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
2169 udelay(5);
2170 break;
2171 }
2172 }
2173 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
2174 DP(NETIF_MSG_LINK, "write phy register failed\n");
2175 netdev_err(bp->dev, "MDC/MDIO access timeout\n");
2176 rc = -EFAULT;
2177 }
2178 }
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00002179 /* Work around for E3 A0 */
2180 if (phy->flags & FLAGS_MDC_MDIO_WA) {
2181 phy->flags ^= FLAGS_DUMMY_READ;
2182 if (phy->flags & FLAGS_DUMMY_READ) {
2183 u16 temp_val;
2184 bnx2x_cl45_read(bp, phy, devad, 0xf, &temp_val);
2185 }
2186 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002187
2188 return rc;
2189}
2190
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00002191
2192/******************************************************************/
2193/* BSC access functions from E3 */
2194/******************************************************************/
2195static void bnx2x_bsc_module_sel(struct link_params *params)
2196{
2197 int idx;
2198 u32 board_cfg, sfp_ctrl;
2199 u32 i2c_pins[I2C_SWITCH_WIDTH], i2c_val[I2C_SWITCH_WIDTH];
2200 struct bnx2x *bp = params->bp;
2201 u8 port = params->port;
2202 /* Read I2C output PINs */
2203 board_cfg = REG_RD(bp, params->shmem_base +
2204 offsetof(struct shmem_region,
2205 dev_info.shared_hw_config.board));
2206 i2c_pins[I2C_BSC0] = board_cfg & SHARED_HW_CFG_E3_I2C_MUX0_MASK;
2207 i2c_pins[I2C_BSC1] = (board_cfg & SHARED_HW_CFG_E3_I2C_MUX1_MASK) >>
2208 SHARED_HW_CFG_E3_I2C_MUX1_SHIFT;
2209
2210 /* Read I2C output value */
2211 sfp_ctrl = REG_RD(bp, params->shmem_base +
2212 offsetof(struct shmem_region,
2213 dev_info.port_hw_config[port].e3_cmn_pin_cfg));
2214 i2c_val[I2C_BSC0] = (sfp_ctrl & PORT_HW_CFG_E3_I2C_MUX0_MASK) > 0;
2215 i2c_val[I2C_BSC1] = (sfp_ctrl & PORT_HW_CFG_E3_I2C_MUX1_MASK) > 0;
2216 DP(NETIF_MSG_LINK, "Setting BSC switch\n");
2217 for (idx = 0; idx < I2C_SWITCH_WIDTH; idx++)
2218 bnx2x_set_cfg_pin(bp, i2c_pins[idx], i2c_val[idx]);
2219}
2220
2221static int bnx2x_bsc_read(struct link_params *params,
2222 struct bnx2x_phy *phy,
2223 u8 sl_devid,
2224 u16 sl_addr,
2225 u8 lc_addr,
2226 u8 xfer_cnt,
2227 u32 *data_array)
2228{
2229 u32 val, i;
2230 int rc = 0;
2231 struct bnx2x *bp = params->bp;
2232
2233 if ((sl_devid != 0xa0) && (sl_devid != 0xa2)) {
2234 DP(NETIF_MSG_LINK, "invalid sl_devid 0x%x\n", sl_devid);
2235 return -EINVAL;
2236 }
2237
2238 if (xfer_cnt > 16) {
2239 DP(NETIF_MSG_LINK, "invalid xfer_cnt %d. Max is 16 bytes\n",
2240 xfer_cnt);
2241 return -EINVAL;
2242 }
2243 bnx2x_bsc_module_sel(params);
2244
2245 xfer_cnt = 16 - lc_addr;
2246
2247 /* enable the engine */
2248 val = REG_RD(bp, MCP_REG_MCPR_IMC_COMMAND);
2249 val |= MCPR_IMC_COMMAND_ENABLE;
2250 REG_WR(bp, MCP_REG_MCPR_IMC_COMMAND, val);
2251
2252 /* program slave device ID */
2253 val = (sl_devid << 16) | sl_addr;
2254 REG_WR(bp, MCP_REG_MCPR_IMC_SLAVE_CONTROL, val);
2255
2256 /* start xfer with 0 byte to update the address pointer ???*/
2257 val = (MCPR_IMC_COMMAND_ENABLE) |
2258 (MCPR_IMC_COMMAND_WRITE_OP <<
2259 MCPR_IMC_COMMAND_OPERATION_BITSHIFT) |
2260 (lc_addr << MCPR_IMC_COMMAND_TRANSFER_ADDRESS_BITSHIFT) | (0);
2261 REG_WR(bp, MCP_REG_MCPR_IMC_COMMAND, val);
2262
2263 /* poll for completion */
2264 i = 0;
2265 val = REG_RD(bp, MCP_REG_MCPR_IMC_COMMAND);
2266 while (((val >> MCPR_IMC_COMMAND_IMC_STATUS_BITSHIFT) & 0x3) != 1) {
2267 udelay(10);
2268 val = REG_RD(bp, MCP_REG_MCPR_IMC_COMMAND);
2269 if (i++ > 1000) {
2270 DP(NETIF_MSG_LINK, "wr 0 byte timed out after %d try\n",
2271 i);
2272 rc = -EFAULT;
2273 break;
2274 }
2275 }
2276 if (rc == -EFAULT)
2277 return rc;
2278
2279 /* start xfer with read op */
2280 val = (MCPR_IMC_COMMAND_ENABLE) |
2281 (MCPR_IMC_COMMAND_READ_OP <<
2282 MCPR_IMC_COMMAND_OPERATION_BITSHIFT) |
2283 (lc_addr << MCPR_IMC_COMMAND_TRANSFER_ADDRESS_BITSHIFT) |
2284 (xfer_cnt);
2285 REG_WR(bp, MCP_REG_MCPR_IMC_COMMAND, val);
2286
2287 /* poll for completion */
2288 i = 0;
2289 val = REG_RD(bp, MCP_REG_MCPR_IMC_COMMAND);
2290 while (((val >> MCPR_IMC_COMMAND_IMC_STATUS_BITSHIFT) & 0x3) != 1) {
2291 udelay(10);
2292 val = REG_RD(bp, MCP_REG_MCPR_IMC_COMMAND);
2293 if (i++ > 1000) {
2294 DP(NETIF_MSG_LINK, "rd op timed out after %d try\n", i);
2295 rc = -EFAULT;
2296 break;
2297 }
2298 }
2299 if (rc == -EFAULT)
2300 return rc;
2301
2302 for (i = (lc_addr >> 2); i < 4; i++) {
2303 data_array[i] = REG_RD(bp, (MCP_REG_MCPR_IMC_DATAREG0 + i*4));
2304#ifdef __BIG_ENDIAN
2305 data_array[i] = ((data_array[i] & 0x000000ff) << 24) |
2306 ((data_array[i] & 0x0000ff00) << 8) |
2307 ((data_array[i] & 0x00ff0000) >> 8) |
2308 ((data_array[i] & 0xff000000) >> 24);
2309#endif
2310 }
2311 return rc;
2312}
2313
2314static void bnx2x_cl45_read_or_write(struct bnx2x *bp, struct bnx2x_phy *phy,
2315 u8 devad, u16 reg, u16 or_val)
2316{
2317 u16 val;
2318 bnx2x_cl45_read(bp, phy, devad, reg, &val);
2319 bnx2x_cl45_write(bp, phy, devad, reg, val | or_val);
2320}
2321
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00002322int bnx2x_phy_read(struct link_params *params, u8 phy_addr,
2323 u8 devad, u16 reg, u16 *ret_val)
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002324{
2325 u8 phy_index;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002326 /*
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002327 * Probe for the phy according to the given phy_addr, and execute
2328 * the read request on it
2329 */
2330 for (phy_index = 0; phy_index < params->num_phys; phy_index++) {
2331 if (params->phy[phy_index].addr == phy_addr) {
2332 return bnx2x_cl45_read(params->bp,
2333 &params->phy[phy_index], devad,
2334 reg, ret_val);
2335 }
2336 }
2337 return -EINVAL;
2338}
2339
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00002340int bnx2x_phy_write(struct link_params *params, u8 phy_addr,
2341 u8 devad, u16 reg, u16 val)
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002342{
2343 u8 phy_index;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002344 /*
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002345 * Probe for the phy according to the given phy_addr, and execute
2346 * the write request on it
2347 */
2348 for (phy_index = 0; phy_index < params->num_phys; phy_index++) {
2349 if (params->phy[phy_index].addr == phy_addr) {
2350 return bnx2x_cl45_write(params->bp,
2351 &params->phy[phy_index], devad,
2352 reg, val);
2353 }
2354 }
2355 return -EINVAL;
2356}
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00002357static u8 bnx2x_get_warpcore_lane(struct bnx2x_phy *phy,
2358 struct link_params *params)
2359{
2360 u8 lane = 0;
2361 struct bnx2x *bp = params->bp;
2362 u32 path_swap, path_swap_ovr;
2363 u8 path, port;
2364
2365 path = BP_PATH(bp);
2366 port = params->port;
2367
2368 if (bnx2x_is_4_port_mode(bp)) {
2369 u32 port_swap, port_swap_ovr;
2370
2371 /*figure out path swap value */
2372 path_swap_ovr = REG_RD(bp, MISC_REG_FOUR_PORT_PATH_SWAP_OVWR);
2373 if (path_swap_ovr & 0x1)
2374 path_swap = (path_swap_ovr & 0x2);
2375 else
2376 path_swap = REG_RD(bp, MISC_REG_FOUR_PORT_PATH_SWAP);
2377
2378 if (path_swap)
2379 path = path ^ 1;
2380
2381 /*figure out port swap value */
2382 port_swap_ovr = REG_RD(bp, MISC_REG_FOUR_PORT_PORT_SWAP_OVWR);
2383 if (port_swap_ovr & 0x1)
2384 port_swap = (port_swap_ovr & 0x2);
2385 else
2386 port_swap = REG_RD(bp, MISC_REG_FOUR_PORT_PORT_SWAP);
2387
2388 if (port_swap)
2389 port = port ^ 1;
2390
2391 lane = (port<<1) + path;
2392 } else { /* two port mode - no port swap */
2393
2394 /*figure out path swap value */
2395 path_swap_ovr =
2396 REG_RD(bp, MISC_REG_TWO_PORT_PATH_SWAP_OVWR);
2397 if (path_swap_ovr & 0x1) {
2398 path_swap = (path_swap_ovr & 0x2);
2399 } else {
2400 path_swap =
2401 REG_RD(bp, MISC_REG_TWO_PORT_PATH_SWAP);
2402 }
2403 if (path_swap)
2404 path = path ^ 1;
2405
2406 lane = path << 1 ;
2407 }
2408 return lane;
2409}
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002410
Yaniv Rosnerec146a62011-05-31 21:29:27 +00002411static void bnx2x_set_aer_mmd(struct link_params *params,
2412 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002413{
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002414 u32 ser_lane;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002415 u16 offset, aer_val;
2416 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002417 ser_lane = ((params->lane_config &
2418 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
2419 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
2420
Yaniv Rosnerec146a62011-05-31 21:29:27 +00002421 offset = (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ?
2422 (phy->addr + ser_lane) : 0;
2423
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00002424 if (USES_WARPCORE(bp)) {
2425 aer_val = bnx2x_get_warpcore_lane(phy, params);
2426 /*
2427 * In Dual-lane mode, two lanes are joined together,
2428 * so in order to configure them, the AER broadcast method is
2429 * used here.
2430 * 0x200 is the broadcast address for lanes 0,1
2431 * 0x201 is the broadcast address for lanes 2,3
2432 */
2433 if (phy->flags & FLAGS_WC_DUAL_MODE)
2434 aer_val = (aer_val >> 1) | 0x200;
2435 } else if (CHIP_IS_E2(bp))
Yaniv Rosner82a0d472011-01-18 04:33:52 +00002436 aer_val = 0x3800 + offset - 1;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002437 else
2438 aer_val = 0x3800 + offset;
Yaniv Rosnerec146a62011-05-31 21:29:27 +00002439 DP(NETIF_MSG_LINK, "Set AER to 0x%x\n", aer_val);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00002440 CL22_WR_OVER_CL45(bp, phy, MDIO_REG_BANK_AER_BLOCK,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002441 MDIO_AER_BLOCK_AER_REG, aer_val);
Yaniv Rosnerec146a62011-05-31 21:29:27 +00002442
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002443}
2444
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002445/******************************************************************/
2446/* Internal phy section */
2447/******************************************************************/
2448
2449static void bnx2x_set_serdes_access(struct bnx2x *bp, u8 port)
2450{
2451 u32 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
2452
2453 /* Set Clause 22 */
2454 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + port*0x10, 1);
2455 REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245f8000);
2456 udelay(500);
2457 REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245d000f);
2458 udelay(500);
2459 /* Set Clause 45 */
2460 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + port*0x10, 0);
2461}
2462
2463static void bnx2x_serdes_deassert(struct bnx2x *bp, u8 port)
2464{
2465 u32 val;
2466
2467 DP(NETIF_MSG_LINK, "bnx2x_serdes_deassert\n");
2468
2469 val = SERDES_RESET_BITS << (port*16);
2470
2471 /* reset and unreset the SerDes/XGXS */
2472 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR, val);
2473 udelay(500);
2474 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET, val);
2475
2476 bnx2x_set_serdes_access(bp, port);
2477
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002478 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_DEVAD + port*0x10,
2479 DEFAULT_PHY_DEV_ADDR);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002480}
2481
2482static void bnx2x_xgxs_deassert(struct link_params *params)
2483{
2484 struct bnx2x *bp = params->bp;
2485 u8 port;
2486 u32 val;
2487 DP(NETIF_MSG_LINK, "bnx2x_xgxs_deassert\n");
2488 port = params->port;
2489
2490 val = XGXS_RESET_BITS << (port*16);
2491
2492 /* reset and unreset the SerDes/XGXS */
2493 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR, val);
2494 udelay(500);
2495 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET, val);
2496
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002497 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_ST + port*0x18, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002498 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002499 params->phy[INT_PHY].def_md_devad);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002500}
2501
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00002502static void bnx2x_calc_ieee_aneg_adv(struct bnx2x_phy *phy,
2503 struct link_params *params, u16 *ieee_fc)
2504{
2505 struct bnx2x *bp = params->bp;
2506 *ieee_fc = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX;
2507 /**
2508 * resolve pause mode and advertisement Please refer to Table
2509 * 28B-3 of the 802.3ab-1999 spec
2510 */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002511
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00002512 switch (phy->req_flow_ctrl) {
2513 case BNX2X_FLOW_CTRL_AUTO:
2514 if (params->req_fc_auto_adv == BNX2X_FLOW_CTRL_BOTH)
2515 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
2516 else
2517 *ieee_fc |=
2518 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
2519 break;
2520
2521 case BNX2X_FLOW_CTRL_TX:
2522 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
2523 break;
2524
2525 case BNX2X_FLOW_CTRL_RX:
2526 case BNX2X_FLOW_CTRL_BOTH:
2527 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
2528 break;
2529
2530 case BNX2X_FLOW_CTRL_NONE:
2531 default:
2532 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE;
2533 break;
2534 }
2535 DP(NETIF_MSG_LINK, "ieee_fc = 0x%x\n", *ieee_fc);
2536}
2537
2538static void set_phy_vars(struct link_params *params,
2539 struct link_vars *vars)
2540{
2541 struct bnx2x *bp = params->bp;
2542 u8 actual_phy_idx, phy_index, link_cfg_idx;
2543 u8 phy_config_swapped = params->multi_phy_config &
2544 PORT_HW_CFG_PHY_SWAPPED_ENABLED;
2545 for (phy_index = INT_PHY; phy_index < params->num_phys;
2546 phy_index++) {
2547 link_cfg_idx = LINK_CONFIG_IDX(phy_index);
2548 actual_phy_idx = phy_index;
2549 if (phy_config_swapped) {
2550 if (phy_index == EXT_PHY1)
2551 actual_phy_idx = EXT_PHY2;
2552 else if (phy_index == EXT_PHY2)
2553 actual_phy_idx = EXT_PHY1;
2554 }
2555 params->phy[actual_phy_idx].req_flow_ctrl =
2556 params->req_flow_ctrl[link_cfg_idx];
2557
2558 params->phy[actual_phy_idx].req_line_speed =
2559 params->req_line_speed[link_cfg_idx];
2560
2561 params->phy[actual_phy_idx].speed_cap_mask =
2562 params->speed_cap_mask[link_cfg_idx];
2563
2564 params->phy[actual_phy_idx].req_duplex =
2565 params->req_duplex[link_cfg_idx];
2566
2567 if (params->req_line_speed[link_cfg_idx] ==
2568 SPEED_AUTO_NEG)
2569 vars->link_status |= LINK_STATUS_AUTO_NEGOTIATE_ENABLED;
2570
2571 DP(NETIF_MSG_LINK, "req_flow_ctrl %x, req_line_speed %x,"
2572 " speed_cap_mask %x\n",
2573 params->phy[actual_phy_idx].req_flow_ctrl,
2574 params->phy[actual_phy_idx].req_line_speed,
2575 params->phy[actual_phy_idx].speed_cap_mask);
2576 }
2577}
2578
2579static void bnx2x_ext_phy_set_pause(struct link_params *params,
2580 struct bnx2x_phy *phy,
2581 struct link_vars *vars)
2582{
2583 u16 val;
2584 struct bnx2x *bp = params->bp;
2585 /* read modify write pause advertizing */
2586 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV_PAUSE, &val);
2587
2588 val &= ~MDIO_AN_REG_ADV_PAUSE_BOTH;
2589
2590 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
2591 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
2592 if ((vars->ieee_fc &
2593 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
2594 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
2595 val |= MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC;
2596 }
2597 if ((vars->ieee_fc &
2598 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
2599 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
2600 val |= MDIO_AN_REG_ADV_PAUSE_PAUSE;
2601 }
2602 DP(NETIF_MSG_LINK, "Ext phy AN advertize 0x%x\n", val);
2603 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV_PAUSE, val);
2604}
2605
2606static void bnx2x_pause_resolve(struct link_vars *vars, u32 pause_result)
2607{ /* LD LP */
2608 switch (pause_result) { /* ASYM P ASYM P */
2609 case 0xb: /* 1 0 1 1 */
2610 vars->flow_ctrl = BNX2X_FLOW_CTRL_TX;
2611 break;
2612
2613 case 0xe: /* 1 1 1 0 */
2614 vars->flow_ctrl = BNX2X_FLOW_CTRL_RX;
2615 break;
2616
2617 case 0x5: /* 0 1 0 1 */
2618 case 0x7: /* 0 1 1 1 */
2619 case 0xd: /* 1 1 0 1 */
2620 case 0xf: /* 1 1 1 1 */
2621 vars->flow_ctrl = BNX2X_FLOW_CTRL_BOTH;
2622 break;
2623
2624 default:
2625 break;
2626 }
2627 if (pause_result & (1<<0))
2628 vars->link_status |= LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE;
2629 if (pause_result & (1<<1))
2630 vars->link_status |= LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE;
2631}
2632
2633static u8 bnx2x_ext_phy_resolve_fc(struct bnx2x_phy *phy,
2634 struct link_params *params,
2635 struct link_vars *vars)
2636{
2637 struct bnx2x *bp = params->bp;
2638 u16 ld_pause; /* local */
2639 u16 lp_pause; /* link partner */
2640 u16 pause_result;
2641 u8 ret = 0;
2642 /* read twice */
2643
2644 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
2645
2646 if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO)
2647 vars->flow_ctrl = phy->req_flow_ctrl;
2648 else if (phy->req_line_speed != SPEED_AUTO_NEG)
2649 vars->flow_ctrl = params->req_fc_auto_adv;
2650 else if (vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE) {
2651 ret = 1;
2652 bnx2x_cl45_read(bp, phy,
2653 MDIO_AN_DEVAD,
2654 MDIO_AN_REG_ADV_PAUSE, &ld_pause);
2655 bnx2x_cl45_read(bp, phy,
2656 MDIO_AN_DEVAD,
2657 MDIO_AN_REG_LP_AUTO_NEG, &lp_pause);
2658 pause_result = (ld_pause &
2659 MDIO_AN_REG_ADV_PAUSE_MASK) >> 8;
2660 pause_result |= (lp_pause &
2661 MDIO_AN_REG_ADV_PAUSE_MASK) >> 10;
2662 DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x\n",
2663 pause_result);
2664 bnx2x_pause_resolve(vars, pause_result);
2665 }
2666 return ret;
2667}
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00002668/******************************************************************/
2669/* Warpcore section */
2670/******************************************************************/
2671/* The init_internal_warpcore should mirror the xgxs,
2672 * i.e. reset the lane (if needed), set aer for the
2673 * init configuration, and set/clear SGMII flag. Internal
2674 * phy init is done purely in phy_init stage.
2675 */
2676static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy,
2677 struct link_params *params,
2678 struct link_vars *vars) {
2679 u16 val16 = 0, lane;
2680 struct bnx2x *bp = params->bp;
2681 DP(NETIF_MSG_LINK, "Enable Auto Negotiation for KR\n");
2682 /* Check adding advertisement for 1G KX */
2683 if (((vars->line_speed == SPEED_AUTO_NEG) &&
2684 (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) ||
2685 (vars->line_speed == SPEED_1000)) {
2686 u16 sd_digital;
2687 val16 |= (1<<5);
2688
2689 /* Enable CL37 1G Parallel Detect */
2690 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
2691 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, &sd_digital);
2692 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2693 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2,
2694 (sd_digital | 0x1));
2695
2696 DP(NETIF_MSG_LINK, "Advertize 1G\n");
2697 }
2698 if (((vars->line_speed == SPEED_AUTO_NEG) &&
2699 (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) ||
2700 (vars->line_speed == SPEED_10000)) {
2701 /* Check adding advertisement for 10G KR */
2702 val16 |= (1<<7);
2703 /* Enable 10G Parallel Detect */
2704 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
2705 MDIO_WC_REG_PAR_DET_10G_CTRL, 1);
2706
2707 DP(NETIF_MSG_LINK, "Advertize 10G\n");
2708 }
2709
2710 /* Set Transmit PMD settings */
2711 lane = bnx2x_get_warpcore_lane(phy, params);
2712 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2713 MDIO_WC_REG_TX0_TX_DRIVER + 0x10*lane,
2714 ((0x02 << MDIO_WC_REG_TX0_TX_DRIVER_POST2_COEFF_OFFSET) |
2715 (0x06 << MDIO_WC_REG_TX0_TX_DRIVER_IDRIVER_OFFSET) |
2716 (0x09 << MDIO_WC_REG_TX0_TX_DRIVER_IPRE_DRIVER_OFFSET)));
2717 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2718 MDIO_WC_REG_CL72_USERB0_CL72_OS_DEF_CTRL,
2719 0x03f0);
2720 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2721 MDIO_WC_REG_CL72_USERB0_CL72_2P5_DEF_CTRL,
2722 0x03f0);
2723 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2724 MDIO_WC_REG_CL72_USERB0_CL72_MISC1_CONTROL,
2725 0x383f);
2726
2727 /* Advertised speeds */
2728 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
2729 MDIO_WC_REG_AN_IEEE1BLK_AN_ADVERTISEMENT1, val16);
2730
2731 /* Advertise pause */
2732 bnx2x_ext_phy_set_pause(params, phy, vars);
2733
2734 /* Enable Autoneg */
2735 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
2736 MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x1000);
2737
2738 /* Over 1G - AN local device user page 1 */
2739 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2740 MDIO_WC_REG_DIGITAL3_UP1, 0x1f);
2741
2742 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
2743 MDIO_WC_REG_DIGITAL5_MISC7, &val16);
2744
2745 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2746 MDIO_WC_REG_DIGITAL5_MISC7, val16 | 0x100);
2747}
2748
2749static void bnx2x_warpcore_set_10G_KR(struct bnx2x_phy *phy,
2750 struct link_params *params,
2751 struct link_vars *vars)
2752{
2753 struct bnx2x *bp = params->bp;
2754 u16 val;
2755
2756 /* Disable Autoneg */
2757 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2758 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, 0x7);
2759
2760 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
2761 MDIO_WC_REG_PAR_DET_10G_CTRL, 0);
2762
2763 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2764 MDIO_WC_REG_CL72_USERB0_CL72_MISC1_CONTROL, 0x3f00);
2765
2766 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
2767 MDIO_WC_REG_AN_IEEE1BLK_AN_ADVERTISEMENT1, 0);
2768
2769 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
2770 MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x0);
2771
2772 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2773 MDIO_WC_REG_DIGITAL3_UP1, 0x1);
2774
2775 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2776 MDIO_WC_REG_DIGITAL5_MISC7, 0xa);
2777
2778 /* Disable CL36 PCS Tx */
2779 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2780 MDIO_WC_REG_XGXSBLK1_LANECTRL0, 0x0);
2781
2782 /* Double Wide Single Data Rate @ pll rate */
2783 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2784 MDIO_WC_REG_XGXSBLK1_LANECTRL1, 0xFFFF);
2785
2786 /* Leave cl72 training enable, needed for KR */
2787 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD,
2788 MDIO_WC_REG_PMD_IEEE9BLK_TENGBASE_KR_PMD_CONTROL_REGISTER_150,
2789 0x2);
2790
2791 /* Leave CL72 enabled */
2792 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
2793 MDIO_WC_REG_CL72_USERB0_CL72_MISC1_CONTROL,
2794 &val);
2795 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2796 MDIO_WC_REG_CL72_USERB0_CL72_MISC1_CONTROL,
2797 val | 0x3800);
2798
2799 /* Set speed via PMA/PMD register */
2800 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD,
2801 MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x2040);
2802
2803 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD,
2804 MDIO_WC_REG_IEEE0BLK_AUTONEGNP, 0xB);
2805
2806 /*Enable encoded forced speed */
2807 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2808 MDIO_WC_REG_SERDESDIGITAL_MISC2, 0x30);
2809
2810 /* Turn TX scramble payload only the 64/66 scrambler */
2811 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2812 MDIO_WC_REG_TX66_CONTROL, 0x9);
2813
2814 /* Turn RX scramble payload only the 64/66 scrambler */
2815 bnx2x_cl45_read_or_write(bp, phy, MDIO_WC_DEVAD,
2816 MDIO_WC_REG_RX66_CONTROL, 0xF9);
2817
2818 /* set and clear loopback to cause a reset to 64/66 decoder */
2819 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2820 MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x4000);
2821 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2822 MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x0);
2823
2824}
2825
2826static void bnx2x_warpcore_set_10G_XFI(struct bnx2x_phy *phy,
2827 struct link_params *params,
2828 u8 is_xfi)
2829{
2830 struct bnx2x *bp = params->bp;
2831 u16 misc1_val, tap_val, tx_driver_val, lane, val;
2832 /* Hold rxSeqStart */
2833 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
2834 MDIO_WC_REG_DSC2B0_DSC_MISC_CTRL0, &val);
2835 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2836 MDIO_WC_REG_DSC2B0_DSC_MISC_CTRL0, (val | 0x8000));
2837
2838 /* Hold tx_fifo_reset */
2839 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
2840 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X3, &val);
2841 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2842 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X3, (val | 0x1));
2843
2844 /* Disable CL73 AN */
2845 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0);
2846
2847 /* Disable 100FX Enable and Auto-Detect */
2848 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
2849 MDIO_WC_REG_FX100_CTRL1, &val);
2850 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2851 MDIO_WC_REG_FX100_CTRL1, (val & 0xFFFA));
2852
2853 /* Disable 100FX Idle detect */
2854 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
2855 MDIO_WC_REG_FX100_CTRL3, &val);
2856 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2857 MDIO_WC_REG_FX100_CTRL3, (val | 0x0080));
2858
2859 /* Set Block address to Remote PHY & Clear forced_speed[5] */
2860 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
2861 MDIO_WC_REG_DIGITAL4_MISC3, &val);
2862 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2863 MDIO_WC_REG_DIGITAL4_MISC3, (val & 0xFF7F));
2864
2865 /* Turn off auto-detect & fiber mode */
2866 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
2867 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1, &val);
2868 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2869 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1,
2870 (val & 0xFFEE));
2871
2872 /* Set filter_force_link, disable_false_link and parallel_detect */
2873 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
2874 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, &val);
2875 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2876 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2,
2877 ((val | 0x0006) & 0xFFFE));
2878
2879 /* Set XFI / SFI */
2880 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
2881 MDIO_WC_REG_SERDESDIGITAL_MISC1, &misc1_val);
2882
2883 misc1_val &= ~(0x1f);
2884
2885 if (is_xfi) {
2886 misc1_val |= 0x5;
2887 tap_val = ((0x08 << MDIO_WC_REG_TX_FIR_TAP_POST_TAP_OFFSET) |
2888 (0x37 << MDIO_WC_REG_TX_FIR_TAP_MAIN_TAP_OFFSET) |
2889 (0x00 << MDIO_WC_REG_TX_FIR_TAP_PRE_TAP_OFFSET));
2890 tx_driver_val =
2891 ((0x00 << MDIO_WC_REG_TX0_TX_DRIVER_POST2_COEFF_OFFSET) |
2892 (0x02 << MDIO_WC_REG_TX0_TX_DRIVER_IDRIVER_OFFSET) |
2893 (0x03 << MDIO_WC_REG_TX0_TX_DRIVER_IPRE_DRIVER_OFFSET));
2894
2895 } else {
2896 misc1_val |= 0x9;
2897 tap_val = ((0x12 << MDIO_WC_REG_TX_FIR_TAP_POST_TAP_OFFSET) |
2898 (0x2d << MDIO_WC_REG_TX_FIR_TAP_MAIN_TAP_OFFSET) |
2899 (0x00 << MDIO_WC_REG_TX_FIR_TAP_PRE_TAP_OFFSET));
2900 tx_driver_val =
2901 ((0x02 << MDIO_WC_REG_TX0_TX_DRIVER_POST2_COEFF_OFFSET) |
2902 (0x02 << MDIO_WC_REG_TX0_TX_DRIVER_IDRIVER_OFFSET) |
2903 (0x02 << MDIO_WC_REG_TX0_TX_DRIVER_IPRE_DRIVER_OFFSET));
2904 }
2905 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2906 MDIO_WC_REG_SERDESDIGITAL_MISC1, misc1_val);
2907
2908 /* Set Transmit PMD settings */
2909 lane = bnx2x_get_warpcore_lane(phy, params);
2910 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2911 MDIO_WC_REG_TX_FIR_TAP,
2912 tap_val | MDIO_WC_REG_TX_FIR_TAP_ENABLE);
2913 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2914 MDIO_WC_REG_TX0_TX_DRIVER + 0x10*lane,
2915 tx_driver_val);
2916
2917 /* Enable fiber mode, enable and invert sig_det */
2918 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
2919 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1, &val);
2920 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2921 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1, val | 0xd);
2922
2923 /* Set Block address to Remote PHY & Set forced_speed[5], 40bit mode */
2924 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
2925 MDIO_WC_REG_DIGITAL4_MISC3, &val);
2926 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2927 MDIO_WC_REG_DIGITAL4_MISC3, val | 0x8080);
2928
2929 /* 10G XFI Full Duplex */
2930 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2931 MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x100);
2932
2933 /* Release tx_fifo_reset */
2934 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
2935 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X3, &val);
2936 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2937 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X3, val & 0xFFFE);
2938
2939 /* Release rxSeqStart */
2940 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
2941 MDIO_WC_REG_DSC2B0_DSC_MISC_CTRL0, &val);
2942 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2943 MDIO_WC_REG_DSC2B0_DSC_MISC_CTRL0, (val & 0x7FFF));
2944}
2945
2946static void bnx2x_warpcore_set_20G_KR2(struct bnx2x *bp,
2947 struct bnx2x_phy *phy)
2948{
2949 DP(NETIF_MSG_LINK, "KR2 still not supported !!!\n");
2950}
2951
2952static void bnx2x_warpcore_set_20G_DXGXS(struct bnx2x *bp,
2953 struct bnx2x_phy *phy,
2954 u16 lane)
2955{
2956 /* Rx0 anaRxControl1G */
2957 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2958 MDIO_WC_REG_RX0_ANARXCONTROL1G, 0x90);
2959
2960 /* Rx2 anaRxControl1G */
2961 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2962 MDIO_WC_REG_RX2_ANARXCONTROL1G, 0x90);
2963
2964 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2965 MDIO_WC_REG_RX66_SCW0, 0xE070);
2966
2967 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2968 MDIO_WC_REG_RX66_SCW1, 0xC0D0);
2969
2970 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2971 MDIO_WC_REG_RX66_SCW2, 0xA0B0);
2972
2973 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2974 MDIO_WC_REG_RX66_SCW3, 0x8090);
2975
2976 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2977 MDIO_WC_REG_RX66_SCW0_MASK, 0xF0F0);
2978
2979 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2980 MDIO_WC_REG_RX66_SCW1_MASK, 0xF0F0);
2981
2982 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2983 MDIO_WC_REG_RX66_SCW2_MASK, 0xF0F0);
2984
2985 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2986 MDIO_WC_REG_RX66_SCW3_MASK, 0xF0F0);
2987
2988 /* Serdes Digital Misc1 */
2989 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2990 MDIO_WC_REG_SERDESDIGITAL_MISC1, 0x6008);
2991
2992 /* Serdes Digital4 Misc3 */
2993 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2994 MDIO_WC_REG_DIGITAL4_MISC3, 0x8088);
2995
2996 /* Set Transmit PMD settings */
2997 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
2998 MDIO_WC_REG_TX_FIR_TAP,
2999 ((0x12 << MDIO_WC_REG_TX_FIR_TAP_POST_TAP_OFFSET) |
3000 (0x2d << MDIO_WC_REG_TX_FIR_TAP_MAIN_TAP_OFFSET) |
3001 (0x00 << MDIO_WC_REG_TX_FIR_TAP_PRE_TAP_OFFSET) |
3002 MDIO_WC_REG_TX_FIR_TAP_ENABLE));
3003 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3004 MDIO_WC_REG_TX0_TX_DRIVER + 0x10*lane,
3005 ((0x02 << MDIO_WC_REG_TX0_TX_DRIVER_POST2_COEFF_OFFSET) |
3006 (0x02 << MDIO_WC_REG_TX0_TX_DRIVER_IDRIVER_OFFSET) |
3007 (0x02 << MDIO_WC_REG_TX0_TX_DRIVER_IPRE_DRIVER_OFFSET)));
3008}
3009
3010static void bnx2x_warpcore_set_sgmii_speed(struct bnx2x_phy *phy,
3011 struct link_params *params,
3012 u8 fiber_mode)
3013{
3014 struct bnx2x *bp = params->bp;
3015 u16 val16, digctrl_kx1, digctrl_kx2;
3016 u8 lane;
3017
3018 lane = bnx2x_get_warpcore_lane(phy, params);
3019
3020 /* Clear XFI clock comp in non-10G single lane mode. */
3021 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3022 MDIO_WC_REG_RX66_CONTROL, &val16);
3023 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3024 MDIO_WC_REG_RX66_CONTROL, val16 & ~(3<<13));
3025
3026 if (phy->req_line_speed == SPEED_AUTO_NEG) {
3027 /* SGMII Autoneg */
3028 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3029 MDIO_WC_REG_COMBO_IEEE0_MIICTRL, &val16);
3030 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3031 MDIO_WC_REG_COMBO_IEEE0_MIICTRL,
3032 val16 | 0x1000);
3033 DP(NETIF_MSG_LINK, "set SGMII AUTONEG\n");
3034 } else {
3035 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3036 MDIO_WC_REG_COMBO_IEEE0_MIICTRL, &val16);
3037 val16 &= 0xcfbf;
3038 switch (phy->req_line_speed) {
3039 case SPEED_10:
3040 break;
3041 case SPEED_100:
3042 val16 |= 0x2000;
3043 break;
3044 case SPEED_1000:
3045 val16 |= 0x0040;
3046 break;
3047 default:
3048 DP(NETIF_MSG_LINK, "Speed not supported: 0x%x"
3049 "\n", phy->req_line_speed);
3050 return;
3051 }
3052
3053 if (phy->req_duplex == DUPLEX_FULL)
3054 val16 |= 0x0100;
3055
3056 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3057 MDIO_WC_REG_COMBO_IEEE0_MIICTRL, val16);
3058
3059 DP(NETIF_MSG_LINK, "set SGMII force speed %d\n",
3060 phy->req_line_speed);
3061 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3062 MDIO_WC_REG_COMBO_IEEE0_MIICTRL, &val16);
3063 DP(NETIF_MSG_LINK, " (readback) %x\n", val16);
3064 }
3065
3066 /* SGMII Slave mode and disable signal detect */
3067 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3068 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1, &digctrl_kx1);
3069 if (fiber_mode)
3070 digctrl_kx1 = 1;
3071 else
3072 digctrl_kx1 &= 0xff4a;
3073
3074 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3075 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1,
3076 digctrl_kx1);
3077
3078 /* Turn off parallel detect */
3079 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3080 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, &digctrl_kx2);
3081 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3082 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2,
3083 (digctrl_kx2 & ~(1<<2)));
3084
3085 /* Re-enable parallel detect */
3086 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3087 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2,
3088 (digctrl_kx2 | (1<<2)));
3089
3090 /* Enable autodet */
3091 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3092 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1,
3093 (digctrl_kx1 | 0x10));
3094}
3095
3096static void bnx2x_warpcore_reset_lane(struct bnx2x *bp,
3097 struct bnx2x_phy *phy,
3098 u8 reset)
3099{
3100 u16 val;
3101 /* Take lane out of reset after configuration is finished */
3102 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3103 MDIO_WC_REG_DIGITAL5_MISC6, &val);
3104 if (reset)
3105 val |= 0xC000;
3106 else
3107 val &= 0x3FFF;
3108 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3109 MDIO_WC_REG_DIGITAL5_MISC6, val);
3110 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3111 MDIO_WC_REG_DIGITAL5_MISC6, &val);
3112}
3113
3114
3115 /* Clear SFI/XFI link settings registers */
3116static void bnx2x_warpcore_clear_regs(struct bnx2x_phy *phy,
3117 struct link_params *params,
3118 u16 lane)
3119{
3120 struct bnx2x *bp = params->bp;
3121 u16 val16;
3122
3123 /* Set XFI clock comp as default. */
3124 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3125 MDIO_WC_REG_RX66_CONTROL, &val16);
3126 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3127 MDIO_WC_REG_RX66_CONTROL, val16 | (3<<13));
3128
3129 bnx2x_warpcore_reset_lane(bp, phy, 1);
3130 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0);
3131 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3132 MDIO_WC_REG_FX100_CTRL1, 0x014a);
3133 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3134 MDIO_WC_REG_FX100_CTRL3, 0x0800);
3135 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3136 MDIO_WC_REG_DIGITAL4_MISC3, 0x8008);
3137 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3138 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1, 0x0195);
3139 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3140 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, 0x0007);
3141 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3142 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X3, 0x0002);
3143 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3144 MDIO_WC_REG_SERDESDIGITAL_MISC1, 0x6000);
3145 lane = bnx2x_get_warpcore_lane(phy, params);
3146 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3147 MDIO_WC_REG_TX_FIR_TAP, 0x0000);
3148 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3149 MDIO_WC_REG_TX0_TX_DRIVER + 0x10*lane, 0x0990);
3150 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3151 MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x2040);
3152 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3153 MDIO_WC_REG_COMBO_IEEE0_MIICTRL, 0x0140);
3154 bnx2x_warpcore_reset_lane(bp, phy, 0);
3155}
3156
3157static int bnx2x_get_mod_abs_int_cfg(struct bnx2x *bp,
3158 u32 chip_id,
3159 u32 shmem_base, u8 port,
3160 u8 *gpio_num, u8 *gpio_port)
3161{
3162 u32 cfg_pin;
3163 *gpio_num = 0;
3164 *gpio_port = 0;
3165 if (CHIP_IS_E3(bp)) {
3166 cfg_pin = (REG_RD(bp, shmem_base +
3167 offsetof(struct shmem_region,
3168 dev_info.port_hw_config[port].e3_sfp_ctrl)) &
3169 PORT_HW_CFG_E3_MOD_ABS_MASK) >>
3170 PORT_HW_CFG_E3_MOD_ABS_SHIFT;
3171
3172 /*
3173 * Should not happen. This function called upon interrupt
3174 * triggered by GPIO ( since EPIO can only generate interrupts
3175 * to MCP).
3176 * So if this function was called and none of the GPIOs was set,
3177 * it means the shit hit the fan.
3178 */
3179 if ((cfg_pin < PIN_CFG_GPIO0_P0) ||
3180 (cfg_pin > PIN_CFG_GPIO3_P1)) {
3181 DP(NETIF_MSG_LINK, "ERROR: Invalid cfg pin %x for "
3182 "module detect indication\n",
3183 cfg_pin);
3184 return -EINVAL;
3185 }
3186
3187 *gpio_num = (cfg_pin - PIN_CFG_GPIO0_P0) & 0x3;
3188 *gpio_port = (cfg_pin - PIN_CFG_GPIO0_P0) >> 2;
3189 } else {
3190 *gpio_num = MISC_REGISTERS_GPIO_3;
3191 *gpio_port = port;
3192 }
3193 DP(NETIF_MSG_LINK, "MOD_ABS int GPIO%d_P%d\n", *gpio_num, *gpio_port);
3194 return 0;
3195}
3196
3197static int bnx2x_is_sfp_module_plugged(struct bnx2x_phy *phy,
3198 struct link_params *params)
3199{
3200 struct bnx2x *bp = params->bp;
3201 u8 gpio_num, gpio_port;
3202 u32 gpio_val;
3203 if (bnx2x_get_mod_abs_int_cfg(bp, params->chip_id,
3204 params->shmem_base, params->port,
3205 &gpio_num, &gpio_port) != 0)
3206 return 0;
3207 gpio_val = bnx2x_get_gpio(bp, gpio_num, gpio_port);
3208
3209 /* Call the handling function in case module is detected */
3210 if (gpio_val == 0)
3211 return 1;
3212 else
3213 return 0;
3214}
3215
3216static void bnx2x_warpcore_config_init(struct bnx2x_phy *phy,
3217 struct link_params *params,
3218 struct link_vars *vars)
3219{
3220 struct bnx2x *bp = params->bp;
3221 u32 serdes_net_if;
3222 u8 fiber_mode;
3223 u16 lane = bnx2x_get_warpcore_lane(phy, params);
3224 serdes_net_if = (REG_RD(bp, params->shmem_base +
3225 offsetof(struct shmem_region, dev_info.
3226 port_hw_config[params->port].default_cfg)) &
3227 PORT_HW_CFG_NET_SERDES_IF_MASK);
3228 DP(NETIF_MSG_LINK, "Begin Warpcore init, link_speed %d, "
3229 "serdes_net_if = 0x%x\n",
3230 vars->line_speed, serdes_net_if);
3231 bnx2x_set_aer_mmd(params, phy);
3232
3233 vars->phy_flags |= PHY_XGXS_FLAG;
3234 if ((serdes_net_if == PORT_HW_CFG_NET_SERDES_IF_SGMII) ||
3235 (phy->req_line_speed &&
3236 ((phy->req_line_speed == SPEED_100) ||
3237 (phy->req_line_speed == SPEED_10)))) {
3238 vars->phy_flags |= PHY_SGMII_FLAG;
3239 DP(NETIF_MSG_LINK, "Setting SGMII mode\n");
3240 bnx2x_warpcore_clear_regs(phy, params, lane);
3241 bnx2x_warpcore_set_sgmii_speed(phy, params, 0);
3242 } else {
3243 switch (serdes_net_if) {
3244 case PORT_HW_CFG_NET_SERDES_IF_KR:
3245 /* Enable KR Auto Neg */
3246 if (params->loopback_mode == LOOPBACK_NONE)
3247 bnx2x_warpcore_enable_AN_KR(phy, params, vars);
3248 else {
3249 DP(NETIF_MSG_LINK, "Setting KR 10G-Force\n");
3250 bnx2x_warpcore_set_10G_KR(phy, params, vars);
3251 }
3252 break;
3253
3254 case PORT_HW_CFG_NET_SERDES_IF_XFI:
3255 bnx2x_warpcore_clear_regs(phy, params, lane);
3256 if (vars->line_speed == SPEED_10000) {
3257 DP(NETIF_MSG_LINK, "Setting 10G XFI\n");
3258 bnx2x_warpcore_set_10G_XFI(phy, params, 1);
3259 } else {
3260 if (SINGLE_MEDIA_DIRECT(params)) {
3261 DP(NETIF_MSG_LINK, "1G Fiber\n");
3262 fiber_mode = 1;
3263 } else {
3264 DP(NETIF_MSG_LINK, "10/100/1G SGMII\n");
3265 fiber_mode = 0;
3266 }
3267 bnx2x_warpcore_set_sgmii_speed(phy,
3268 params,
3269 fiber_mode);
3270 }
3271
3272 break;
3273
3274 case PORT_HW_CFG_NET_SERDES_IF_SFI:
3275
3276 bnx2x_warpcore_clear_regs(phy, params, lane);
3277 if (vars->line_speed == SPEED_10000) {
3278 DP(NETIF_MSG_LINK, "Setting 10G SFI\n");
3279 bnx2x_warpcore_set_10G_XFI(phy, params, 0);
3280 } else if (vars->line_speed == SPEED_1000) {
3281 DP(NETIF_MSG_LINK, "Setting 1G Fiber\n");
3282 bnx2x_warpcore_set_sgmii_speed(phy, params, 1);
3283 }
3284 /* Issue Module detection */
3285 if (bnx2x_is_sfp_module_plugged(phy, params))
3286 bnx2x_sfp_module_detection(phy, params);
3287 break;
3288
3289 case PORT_HW_CFG_NET_SERDES_IF_DXGXS:
3290 if (vars->line_speed != SPEED_20000) {
3291 DP(NETIF_MSG_LINK, "Speed not supported yet\n");
3292 return;
3293 }
3294 DP(NETIF_MSG_LINK, "Setting 20G DXGXS\n");
3295 bnx2x_warpcore_set_20G_DXGXS(bp, phy, lane);
3296 /* Issue Module detection */
3297
3298 bnx2x_sfp_module_detection(phy, params);
3299 break;
3300
3301 case PORT_HW_CFG_NET_SERDES_IF_KR2:
3302 if (vars->line_speed != SPEED_20000) {
3303 DP(NETIF_MSG_LINK, "Speed not supported yet\n");
3304 return;
3305 }
3306 DP(NETIF_MSG_LINK, "Setting 20G KR2\n");
3307 bnx2x_warpcore_set_20G_KR2(bp, phy);
3308 break;
3309
3310 default:
3311 DP(NETIF_MSG_LINK, "Unsupported Serdes Net Interface "
3312 "0x%x\n", serdes_net_if);
3313 return;
3314 }
3315 }
3316
3317 /* Take lane out of reset after configuration is finished */
3318 bnx2x_warpcore_reset_lane(bp, phy, 0);
3319 DP(NETIF_MSG_LINK, "Exit config init\n");
3320}
3321
3322static void bnx2x_sfp_e3_set_transmitter(struct link_params *params,
3323 struct bnx2x_phy *phy,
3324 u8 tx_en)
3325{
3326 struct bnx2x *bp = params->bp;
3327 u32 cfg_pin;
3328 u8 port = params->port;
3329
3330 cfg_pin = REG_RD(bp, params->shmem_base +
3331 offsetof(struct shmem_region,
3332 dev_info.port_hw_config[port].e3_sfp_ctrl)) &
3333 PORT_HW_CFG_TX_LASER_MASK;
3334 /* Set the !tx_en since this pin is DISABLE_TX_LASER */
3335 DP(NETIF_MSG_LINK, "Setting WC TX to %d\n", tx_en);
3336 /* For 20G, the expected pin to be used is 3 pins after the current */
3337
3338 bnx2x_set_cfg_pin(bp, cfg_pin, tx_en ^ 1);
3339 if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_20G)
3340 bnx2x_set_cfg_pin(bp, cfg_pin + 3, tx_en ^ 1);
3341}
3342
3343static void bnx2x_warpcore_link_reset(struct bnx2x_phy *phy,
3344 struct link_params *params)
3345{
3346 struct bnx2x *bp = params->bp;
3347 u16 val16;
3348 bnx2x_sfp_e3_set_transmitter(params, phy, 0);
3349 bnx2x_set_mdio_clk(bp, params->chip_id, params->port);
3350 bnx2x_set_aer_mmd(params, phy);
3351 /* Global register */
3352 bnx2x_warpcore_reset_lane(bp, phy, 1);
3353
3354 /* Clear loopback settings (if any) */
3355 /* 10G & 20G */
3356 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3357 MDIO_WC_REG_COMBO_IEEE0_MIICTRL, &val16);
3358 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3359 MDIO_WC_REG_COMBO_IEEE0_MIICTRL, val16 &
3360 0xBFFF);
3361
3362 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3363 MDIO_WC_REG_IEEE0BLK_MIICNTL, &val16);
3364 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3365 MDIO_WC_REG_IEEE0BLK_MIICNTL, val16 & 0xfffe);
3366
3367 /* Update those 1-copy registers */
3368 CL22_WR_OVER_CL45(bp, phy, MDIO_REG_BANK_AER_BLOCK,
3369 MDIO_AER_BLOCK_AER_REG, 0);
3370 /* Enable 1G MDIO (1-copy) */
3371 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3372 MDIO_WC_REG_XGXSBLK0_XGXSCONTROL,
3373 &val16);
3374 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3375 MDIO_WC_REG_XGXSBLK0_XGXSCONTROL,
3376 val16 & ~0x10);
3377
3378 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3379 MDIO_WC_REG_XGXSBLK1_LANECTRL2, &val16);
3380 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3381 MDIO_WC_REG_XGXSBLK1_LANECTRL2,
3382 val16 & 0xff00);
3383
3384}
3385
3386static void bnx2x_set_warpcore_loopback(struct bnx2x_phy *phy,
3387 struct link_params *params)
3388{
3389 struct bnx2x *bp = params->bp;
3390 u16 val16;
3391 u32 lane;
3392 DP(NETIF_MSG_LINK, "Setting Warpcore loopback type %x, speed %d\n",
3393 params->loopback_mode, phy->req_line_speed);
3394
3395 if (phy->req_line_speed < SPEED_10000) {
3396 /* 10/100/1000 */
3397
3398 /* Update those 1-copy registers */
3399 CL22_WR_OVER_CL45(bp, phy, MDIO_REG_BANK_AER_BLOCK,
3400 MDIO_AER_BLOCK_AER_REG, 0);
3401 /* Enable 1G MDIO (1-copy) */
3402 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3403 MDIO_WC_REG_XGXSBLK0_XGXSCONTROL,
3404 &val16);
3405 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3406 MDIO_WC_REG_XGXSBLK0_XGXSCONTROL,
3407 val16 | 0x10);
3408 /* Set 1G loopback based on lane (1-copy) */
3409 lane = bnx2x_get_warpcore_lane(phy, params);
3410 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3411 MDIO_WC_REG_XGXSBLK1_LANECTRL2, &val16);
3412 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3413 MDIO_WC_REG_XGXSBLK1_LANECTRL2,
3414 val16 | (1<<lane));
3415
3416 /* Switch back to 4-copy registers */
3417 bnx2x_set_aer_mmd(params, phy);
3418 /* Global loopback, not recommended. */
3419 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3420 MDIO_WC_REG_COMBO_IEEE0_MIICTRL, &val16);
3421 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3422 MDIO_WC_REG_COMBO_IEEE0_MIICTRL, val16 |
3423 0x4000);
3424 } else {
3425 /* 10G & 20G */
3426 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3427 MDIO_WC_REG_COMBO_IEEE0_MIICTRL, &val16);
3428 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3429 MDIO_WC_REG_COMBO_IEEE0_MIICTRL, val16 |
3430 0x4000);
3431
3432 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3433 MDIO_WC_REG_IEEE0BLK_MIICNTL, &val16);
3434 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3435 MDIO_WC_REG_IEEE0BLK_MIICNTL, val16 | 0x1);
3436 }
3437}
3438
3439
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003440void bnx2x_link_status_update(struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003441 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003442{
3443 struct bnx2x *bp = params->bp;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00003444 u8 link_10g_plus;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003445 u8 port = params->port;
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00003446 u32 sync_offset, media_types;
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00003447 /* Update PHY configuration */
3448 set_phy_vars(params, vars);
3449
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003450 vars->link_status = REG_RD(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003451 offsetof(struct shmem_region,
3452 port_mb[port].link_status));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003453
3454 vars->link_up = (vars->link_status & LINK_STATUS_LINK_UP);
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00003455 vars->phy_flags = PHY_XGXS_FLAG;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003456 if (vars->link_up) {
3457 DP(NETIF_MSG_LINK, "phy link up\n");
3458
3459 vars->phy_link_up = 1;
3460 vars->duplex = DUPLEX_FULL;
3461 switch (vars->link_status &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003462 LINK_STATUS_SPEED_AND_DUPLEX_MASK) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003463 case LINK_10THD:
3464 vars->duplex = DUPLEX_HALF;
3465 /* fall thru */
3466 case LINK_10TFD:
3467 vars->line_speed = SPEED_10;
3468 break;
3469
3470 case LINK_100TXHD:
3471 vars->duplex = DUPLEX_HALF;
3472 /* fall thru */
3473 case LINK_100T4:
3474 case LINK_100TXFD:
3475 vars->line_speed = SPEED_100;
3476 break;
3477
3478 case LINK_1000THD:
3479 vars->duplex = DUPLEX_HALF;
3480 /* fall thru */
3481 case LINK_1000TFD:
3482 vars->line_speed = SPEED_1000;
3483 break;
3484
3485 case LINK_2500THD:
3486 vars->duplex = DUPLEX_HALF;
3487 /* fall thru */
3488 case LINK_2500TFD:
3489 vars->line_speed = SPEED_2500;
3490 break;
3491
3492 case LINK_10GTFD:
3493 vars->line_speed = SPEED_10000;
3494 break;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00003495 case LINK_20GTFD:
3496 vars->line_speed = SPEED_20000;
3497 break;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003498 default:
3499 break;
3500 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003501 vars->flow_ctrl = 0;
3502 if (vars->link_status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED)
3503 vars->flow_ctrl |= BNX2X_FLOW_CTRL_TX;
3504
3505 if (vars->link_status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED)
3506 vars->flow_ctrl |= BNX2X_FLOW_CTRL_RX;
3507
3508 if (!vars->flow_ctrl)
3509 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
3510
3511 if (vars->line_speed &&
3512 ((vars->line_speed == SPEED_10) ||
3513 (vars->line_speed == SPEED_100))) {
3514 vars->phy_flags |= PHY_SGMII_FLAG;
3515 } else {
3516 vars->phy_flags &= ~PHY_SGMII_FLAG;
3517 }
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00003518 if (vars->line_speed &&
3519 USES_WARPCORE(bp) &&
3520 (vars->line_speed == SPEED_1000))
3521 vars->phy_flags |= PHY_SGMII_FLAG;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003522 /* anything 10 and over uses the bmac */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00003523 link_10g_plus = (vars->line_speed >= SPEED_10000);
3524
3525 if (link_10g_plus) {
3526 if (USES_WARPCORE(bp))
3527 vars->mac_type = MAC_TYPE_XMAC;
3528 else
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00003529 vars->mac_type = MAC_TYPE_BMAC;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00003530 } else {
3531 if (USES_WARPCORE(bp))
3532 vars->mac_type = MAC_TYPE_UMAC;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00003533 else
3534 vars->mac_type = MAC_TYPE_EMAC;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00003535 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003536 } else { /* link down */
3537 DP(NETIF_MSG_LINK, "phy link down\n");
3538
3539 vars->phy_link_up = 0;
3540
3541 vars->line_speed = 0;
3542 vars->duplex = DUPLEX_FULL;
3543 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
3544
3545 /* indicate no mac active */
3546 vars->mac_type = MAC_TYPE_NONE;
3547 }
3548
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00003549 /* Sync media type */
3550 sync_offset = params->shmem_base +
3551 offsetof(struct shmem_region,
3552 dev_info.port_hw_config[port].media_type);
3553 media_types = REG_RD(bp, sync_offset);
3554
3555 params->phy[INT_PHY].media_type =
3556 (media_types & PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK) >>
3557 PORT_HW_CFG_MEDIA_TYPE_PHY0_SHIFT;
3558 params->phy[EXT_PHY1].media_type =
3559 (media_types & PORT_HW_CFG_MEDIA_TYPE_PHY1_MASK) >>
3560 PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT;
3561 params->phy[EXT_PHY2].media_type =
3562 (media_types & PORT_HW_CFG_MEDIA_TYPE_PHY2_MASK) >>
3563 PORT_HW_CFG_MEDIA_TYPE_PHY2_SHIFT;
3564 DP(NETIF_MSG_LINK, "media_types = 0x%x\n", media_types);
3565
Yaniv Rosner020c7e32011-05-31 21:28:43 +00003566 /* Sync AEU offset */
3567 sync_offset = params->shmem_base +
3568 offsetof(struct shmem_region,
3569 dev_info.port_hw_config[port].aeu_int_mask);
3570
3571 vars->aeu_int_mask = REG_RD(bp, sync_offset);
3572
3573 DP(NETIF_MSG_LINK, "link_status 0x%x phy_link_up %x int_mask 0x%x\n",
3574 vars->link_status, vars->phy_link_up, vars->aeu_int_mask);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003575 DP(NETIF_MSG_LINK, "line_speed %x duplex %x flow_ctrl 0x%x\n",
3576 vars->line_speed, vars->duplex, vars->flow_ctrl);
3577}
3578
3579
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003580static void bnx2x_set_master_ln(struct link_params *params,
3581 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003582{
3583 struct bnx2x *bp = params->bp;
3584 u16 new_master_ln, ser_lane;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003585 ser_lane = ((params->lane_config &
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003586 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003587 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003588
3589 /* set the master_ln for AN */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003590 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003591 MDIO_REG_BANK_XGXS_BLOCK2,
3592 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
3593 &new_master_ln);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003594
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003595 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003596 MDIO_REG_BANK_XGXS_BLOCK2 ,
3597 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
3598 (new_master_ln | ser_lane));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003599}
3600
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00003601static int bnx2x_reset_unicore(struct link_params *params,
3602 struct bnx2x_phy *phy,
3603 u8 set_serdes)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003604{
3605 struct bnx2x *bp = params->bp;
3606 u16 mii_control;
3607 u16 i;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003608 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003609 MDIO_REG_BANK_COMBO_IEEE0,
3610 MDIO_COMBO_IEEE0_MII_CONTROL, &mii_control);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003611
3612 /* reset the unicore */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003613 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003614 MDIO_REG_BANK_COMBO_IEEE0,
3615 MDIO_COMBO_IEEE0_MII_CONTROL,
3616 (mii_control |
3617 MDIO_COMBO_IEEO_MII_CONTROL_RESET));
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003618 if (set_serdes)
3619 bnx2x_set_serdes_access(bp, params->port);
Eilon Greensteinc1b73992009-02-12 08:37:07 +00003620
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003621 /* wait for the reset to self clear */
3622 for (i = 0; i < MDIO_ACCESS_TIMEOUT; i++) {
3623 udelay(5);
3624
3625 /* the reset erased the previous bank value */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003626 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003627 MDIO_REG_BANK_COMBO_IEEE0,
3628 MDIO_COMBO_IEEE0_MII_CONTROL,
3629 &mii_control);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003630
3631 if (!(mii_control & MDIO_COMBO_IEEO_MII_CONTROL_RESET)) {
3632 udelay(5);
3633 return 0;
3634 }
3635 }
3636
Yaniv Rosner6d870c32011-01-31 04:22:20 +00003637 netdev_err(bp->dev, "Warning: PHY was not initialized,"
3638 " Port %d\n",
3639 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003640 DP(NETIF_MSG_LINK, "BUG! XGXS is still in reset!\n");
3641 return -EINVAL;
3642
3643}
3644
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003645static void bnx2x_set_swap_lanes(struct link_params *params,
3646 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003647{
3648 struct bnx2x *bp = params->bp;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003649 /*
3650 * Each two bits represents a lane number:
3651 * No swap is 0123 => 0x1b no need to enable the swap
3652 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003653 u16 ser_lane, rx_lane_swap, tx_lane_swap;
3654
3655 ser_lane = ((params->lane_config &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003656 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
3657 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003658 rx_lane_swap = ((params->lane_config &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003659 PORT_HW_CFG_LANE_SWAP_CFG_RX_MASK) >>
3660 PORT_HW_CFG_LANE_SWAP_CFG_RX_SHIFT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003661 tx_lane_swap = ((params->lane_config &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003662 PORT_HW_CFG_LANE_SWAP_CFG_TX_MASK) >>
3663 PORT_HW_CFG_LANE_SWAP_CFG_TX_SHIFT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003664
3665 if (rx_lane_swap != 0x1b) {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003666 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003667 MDIO_REG_BANK_XGXS_BLOCK2,
3668 MDIO_XGXS_BLOCK2_RX_LN_SWAP,
3669 (rx_lane_swap |
3670 MDIO_XGXS_BLOCK2_RX_LN_SWAP_ENABLE |
3671 MDIO_XGXS_BLOCK2_RX_LN_SWAP_FORCE_ENABLE));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003672 } else {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003673 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003674 MDIO_REG_BANK_XGXS_BLOCK2,
3675 MDIO_XGXS_BLOCK2_RX_LN_SWAP, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003676 }
3677
3678 if (tx_lane_swap != 0x1b) {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003679 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003680 MDIO_REG_BANK_XGXS_BLOCK2,
3681 MDIO_XGXS_BLOCK2_TX_LN_SWAP,
3682 (tx_lane_swap |
3683 MDIO_XGXS_BLOCK2_TX_LN_SWAP_ENABLE));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003684 } else {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003685 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003686 MDIO_REG_BANK_XGXS_BLOCK2,
3687 MDIO_XGXS_BLOCK2_TX_LN_SWAP, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003688 }
3689}
3690
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003691static void bnx2x_set_parallel_detection(struct bnx2x_phy *phy,
3692 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003693{
3694 struct bnx2x *bp = params->bp;
3695 u16 control2;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003696 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003697 MDIO_REG_BANK_SERDES_DIGITAL,
3698 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
3699 &control2);
Yaniv Rosner7aa07112010-09-07 11:41:01 +00003700 if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
Yaniv Rosner18afb0a2009-11-05 19:18:04 +02003701 control2 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
3702 else
3703 control2 &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00003704 DP(NETIF_MSG_LINK, "phy->speed_cap_mask = 0x%x, control2 = 0x%x\n",
3705 phy->speed_cap_mask, control2);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003706 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003707 MDIO_REG_BANK_SERDES_DIGITAL,
3708 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
3709 control2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003710
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003711 if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00003712 (phy->speed_cap_mask &
Yaniv Rosner18afb0a2009-11-05 19:18:04 +02003713 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003714 DP(NETIF_MSG_LINK, "XGXS\n");
3715
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003716 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003717 MDIO_REG_BANK_10G_PARALLEL_DETECT,
3718 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK,
3719 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003720
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003721 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003722 MDIO_REG_BANK_10G_PARALLEL_DETECT,
3723 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
3724 &control2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003725
3726
3727 control2 |=
3728 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN;
3729
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003730 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003731 MDIO_REG_BANK_10G_PARALLEL_DETECT,
3732 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
3733 control2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003734
3735 /* Disable parallel detection of HiG */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003736 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003737 MDIO_REG_BANK_XGXS_BLOCK2,
3738 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G,
3739 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_CX4_XGXS |
3740 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_HIGIG_XGXS);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003741 }
3742}
3743
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003744static void bnx2x_set_autoneg(struct bnx2x_phy *phy,
3745 struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003746 struct link_vars *vars,
3747 u8 enable_cl73)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003748{
3749 struct bnx2x *bp = params->bp;
3750 u16 reg_val;
3751
3752 /* CL37 Autoneg */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003753 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003754 MDIO_REG_BANK_COMBO_IEEE0,
3755 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003756
3757 /* CL37 Autoneg Enabled */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003758 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003759 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_AN_EN;
3760 else /* CL37 Autoneg Disabled */
3761 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
3762 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN);
3763
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003764 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003765 MDIO_REG_BANK_COMBO_IEEE0,
3766 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003767
3768 /* Enable/Disable Autodetection */
3769
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003770 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003771 MDIO_REG_BANK_SERDES_DIGITAL,
3772 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, &reg_val);
Eilon Greenstein239d6862009-08-12 08:23:04 +00003773 reg_val &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN |
3774 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT);
3775 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003776 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003777 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
3778 else
3779 reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
3780
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003781 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003782 MDIO_REG_BANK_SERDES_DIGITAL,
3783 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003784
3785 /* Enable TetonII and BAM autoneg */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003786 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003787 MDIO_REG_BANK_BAM_NEXT_PAGE,
3788 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003789 &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003790 if (vars->line_speed == SPEED_AUTO_NEG) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003791 /* Enable BAM aneg Mode and TetonII aneg Mode */
3792 reg_val |= (MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
3793 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
3794 } else {
3795 /* TetonII and BAM Autoneg Disabled */
3796 reg_val &= ~(MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
3797 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
3798 }
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003799 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003800 MDIO_REG_BANK_BAM_NEXT_PAGE,
3801 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
3802 reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003803
Eilon Greenstein239d6862009-08-12 08:23:04 +00003804 if (enable_cl73) {
3805 /* Enable Cl73 FSM status bits */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003806 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003807 MDIO_REG_BANK_CL73_USERB0,
3808 MDIO_CL73_USERB0_CL73_UCTRL,
3809 0xe);
Eilon Greenstein239d6862009-08-12 08:23:04 +00003810
3811 /* Enable BAM Station Manager*/
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003812 CL22_WR_OVER_CL45(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00003813 MDIO_REG_BANK_CL73_USERB0,
3814 MDIO_CL73_USERB0_CL73_BAM_CTRL1,
3815 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN |
3816 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_STATION_MNGR_EN |
3817 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN);
3818
Yaniv Rosner7846e472009-11-05 19:18:07 +02003819 /* Advertise CL73 link speeds */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003820 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003821 MDIO_REG_BANK_CL73_IEEEB1,
3822 MDIO_CL73_IEEEB1_AN_ADV2,
3823 &reg_val);
Yaniv Rosner7aa07112010-09-07 11:41:01 +00003824 if (phy->speed_cap_mask &
Yaniv Rosner7846e472009-11-05 19:18:07 +02003825 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
3826 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00003827 if (phy->speed_cap_mask &
Yaniv Rosner7846e472009-11-05 19:18:07 +02003828 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
3829 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX;
Eilon Greenstein239d6862009-08-12 08:23:04 +00003830
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003831 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003832 MDIO_REG_BANK_CL73_IEEEB1,
3833 MDIO_CL73_IEEEB1_AN_ADV2,
3834 reg_val);
Eilon Greenstein239d6862009-08-12 08:23:04 +00003835
Eilon Greenstein239d6862009-08-12 08:23:04 +00003836 /* CL73 Autoneg Enabled */
3837 reg_val = MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN;
3838
3839 } else /* CL73 Autoneg Disabled */
3840 reg_val = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003841
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003842 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003843 MDIO_REG_BANK_CL73_IEEEB0,
3844 MDIO_CL73_IEEEB0_CL73_AN_CONTROL, reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003845}
3846
3847/* program SerDes, forced speed */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003848static void bnx2x_program_serdes(struct bnx2x_phy *phy,
3849 struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003850 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003851{
3852 struct bnx2x *bp = params->bp;
3853 u16 reg_val;
3854
Eilon Greenstein57937202009-08-12 08:23:53 +00003855 /* program duplex, disable autoneg and sgmii*/
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003856 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003857 MDIO_REG_BANK_COMBO_IEEE0,
3858 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003859 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX |
Eilon Greenstein57937202009-08-12 08:23:53 +00003860 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
3861 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK);
Yaniv Rosner7aa07112010-09-07 11:41:01 +00003862 if (phy->req_duplex == DUPLEX_FULL)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003863 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003864 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003865 MDIO_REG_BANK_COMBO_IEEE0,
3866 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003867
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003868 /*
3869 * program speed
3870 * - needed only if the speed is greater than 1G (2.5G or 10G)
3871 */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003872 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003873 MDIO_REG_BANK_SERDES_DIGITAL,
3874 MDIO_SERDES_DIGITAL_MISC1, &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003875 /* clearing the speed value before setting the right speed */
3876 DP(NETIF_MSG_LINK, "MDIO_REG_BANK_SERDES_DIGITAL = 0x%x\n", reg_val);
3877
3878 reg_val &= ~(MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_MASK |
3879 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
3880
3881 if (!((vars->line_speed == SPEED_1000) ||
3882 (vars->line_speed == SPEED_100) ||
3883 (vars->line_speed == SPEED_10))) {
3884
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003885 reg_val |= (MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_156_25M |
3886 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003887 if (vars->line_speed == SPEED_10000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003888 reg_val |=
3889 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_10G_CX4;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003890 }
3891
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003892 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003893 MDIO_REG_BANK_SERDES_DIGITAL,
3894 MDIO_SERDES_DIGITAL_MISC1, reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003895
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003896}
3897
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00003898static void bnx2x_set_brcm_cl37_advertisement(struct bnx2x_phy *phy,
3899 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003900{
3901 struct bnx2x *bp = params->bp;
3902 u16 val = 0;
3903
3904 /* configure the 48 bits for BAM AN */
3905
3906 /* set extended capabilities */
Yaniv Rosner7aa07112010-09-07 11:41:01 +00003907 if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003908 val |= MDIO_OVER_1G_UP1_2_5G;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00003909 if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003910 val |= MDIO_OVER_1G_UP1_10G;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003911 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003912 MDIO_REG_BANK_OVER_1G,
3913 MDIO_OVER_1G_UP1, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003914
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003915 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003916 MDIO_REG_BANK_OVER_1G,
3917 MDIO_OVER_1G_UP3, 0x400);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003918}
3919
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00003920static void bnx2x_set_ieee_aneg_advertisement(struct bnx2x_phy *phy,
3921 struct link_params *params,
3922 u16 ieee_fc)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003923{
3924 struct bnx2x *bp = params->bp;
Yaniv Rosner7846e472009-11-05 19:18:07 +02003925 u16 val;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003926 /* for AN, we are always publishing full duplex */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003927
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003928 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003929 MDIO_REG_BANK_COMBO_IEEE0,
3930 MDIO_COMBO_IEEE0_AUTO_NEG_ADV, ieee_fc);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003931 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003932 MDIO_REG_BANK_CL73_IEEEB1,
3933 MDIO_CL73_IEEEB1_AN_ADV1, &val);
Yaniv Rosner7846e472009-11-05 19:18:07 +02003934 val &= ~MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_BOTH;
3935 val |= ((ieee_fc<<3) & MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003936 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003937 MDIO_REG_BANK_CL73_IEEEB1,
3938 MDIO_CL73_IEEEB1_AN_ADV1, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003939}
3940
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003941static void bnx2x_restart_autoneg(struct bnx2x_phy *phy,
3942 struct link_params *params,
3943 u8 enable_cl73)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003944{
3945 struct bnx2x *bp = params->bp;
Eilon Greenstein3a36f2e2009-02-12 08:37:09 +00003946 u16 mii_control;
Eilon Greenstein239d6862009-08-12 08:23:04 +00003947
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003948 DP(NETIF_MSG_LINK, "bnx2x_restart_autoneg\n");
Eilon Greenstein3a36f2e2009-02-12 08:37:09 +00003949 /* Enable and restart BAM/CL37 aneg */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003950
Eilon Greenstein239d6862009-08-12 08:23:04 +00003951 if (enable_cl73) {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003952 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003953 MDIO_REG_BANK_CL73_IEEEB0,
3954 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
3955 &mii_control);
Eilon Greenstein239d6862009-08-12 08:23:04 +00003956
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003957 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003958 MDIO_REG_BANK_CL73_IEEEB0,
3959 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
3960 (mii_control |
3961 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN |
3962 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN));
Eilon Greenstein239d6862009-08-12 08:23:04 +00003963 } else {
3964
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003965 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003966 MDIO_REG_BANK_COMBO_IEEE0,
3967 MDIO_COMBO_IEEE0_MII_CONTROL,
3968 &mii_control);
Eilon Greenstein239d6862009-08-12 08:23:04 +00003969 DP(NETIF_MSG_LINK,
3970 "bnx2x_restart_autoneg mii_control before = 0x%x\n",
3971 mii_control);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003972 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003973 MDIO_REG_BANK_COMBO_IEEE0,
3974 MDIO_COMBO_IEEE0_MII_CONTROL,
3975 (mii_control |
3976 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
3977 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN));
Eilon Greenstein239d6862009-08-12 08:23:04 +00003978 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003979}
3980
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003981static void bnx2x_initialize_sgmii_process(struct bnx2x_phy *phy,
3982 struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003983 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003984{
3985 struct bnx2x *bp = params->bp;
3986 u16 control1;
3987
3988 /* in SGMII mode, the unicore is always slave */
3989
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003990 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003991 MDIO_REG_BANK_SERDES_DIGITAL,
3992 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
3993 &control1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003994 control1 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT;
3995 /* set sgmii mode (and not fiber) */
3996 control1 &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE |
3997 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET |
3998 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_MSTR_MODE);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003999 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004000 MDIO_REG_BANK_SERDES_DIGITAL,
4001 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
4002 control1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004003
4004 /* if forced speed */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07004005 if (!(vars->line_speed == SPEED_AUTO_NEG)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004006 /* set speed, disable autoneg */
4007 u16 mii_control;
4008
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004009 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004010 MDIO_REG_BANK_COMBO_IEEE0,
4011 MDIO_COMBO_IEEE0_MII_CONTROL,
4012 &mii_control);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004013 mii_control &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
4014 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK|
4015 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX);
4016
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07004017 switch (vars->line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004018 case SPEED_100:
4019 mii_control |=
4020 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_100;
4021 break;
4022 case SPEED_1000:
4023 mii_control |=
4024 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_1000;
4025 break;
4026 case SPEED_10:
4027 /* there is nothing to set for 10M */
4028 break;
4029 default:
4030 /* invalid speed for SGMII */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07004031 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
4032 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004033 break;
4034 }
4035
4036 /* setting the full duplex */
Yaniv Rosner7aa07112010-09-07 11:41:01 +00004037 if (phy->req_duplex == DUPLEX_FULL)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004038 mii_control |=
4039 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004040 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004041 MDIO_REG_BANK_COMBO_IEEE0,
4042 MDIO_COMBO_IEEE0_MII_CONTROL,
4043 mii_control);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004044
4045 } else { /* AN mode */
4046 /* enable and restart AN */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004047 bnx2x_restart_autoneg(phy, params, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004048 }
4049}
4050
4051
4052/*
4053 * link management
4054 */
4055
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00004056static int bnx2x_direct_parallel_detect_used(struct bnx2x_phy *phy,
4057 struct link_params *params)
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02004058{
4059 struct bnx2x *bp = params->bp;
4060 u16 pd_10g, status2_1000x;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00004061 if (phy->req_line_speed != SPEED_AUTO_NEG)
4062 return 0;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004063 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004064 MDIO_REG_BANK_SERDES_DIGITAL,
4065 MDIO_SERDES_DIGITAL_A_1000X_STATUS2,
4066 &status2_1000x);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004067 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004068 MDIO_REG_BANK_SERDES_DIGITAL,
4069 MDIO_SERDES_DIGITAL_A_1000X_STATUS2,
4070 &status2_1000x);
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02004071 if (status2_1000x & MDIO_SERDES_DIGITAL_A_1000X_STATUS2_AN_DISABLED) {
4072 DP(NETIF_MSG_LINK, "1G parallel detect link on port %d\n",
4073 params->port);
4074 return 1;
4075 }
4076
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004077 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004078 MDIO_REG_BANK_10G_PARALLEL_DETECT,
4079 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_STATUS,
4080 &pd_10g);
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02004081
4082 if (pd_10g & MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_STATUS_PD_LINK) {
4083 DP(NETIF_MSG_LINK, "10G parallel detect link on port %d\n",
4084 params->port);
4085 return 1;
4086 }
4087 return 0;
4088}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004089
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004090static void bnx2x_flow_ctrl_resolve(struct bnx2x_phy *phy,
4091 struct link_params *params,
4092 struct link_vars *vars,
4093 u32 gp_status)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004094{
4095 struct bnx2x *bp = params->bp;
Eilon Greenstein3196a882008-08-13 15:58:49 -07004096 u16 ld_pause; /* local driver */
4097 u16 lp_pause; /* link partner */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004098 u16 pause_result;
4099
David S. Millerc0700f92008-12-16 23:53:20 -08004100 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004101
4102 /* resolve from gp_status in case of AN complete and not sgmii */
Yaniv Rosner7aa07112010-09-07 11:41:01 +00004103 if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO)
4104 vars->flow_ctrl = phy->req_flow_ctrl;
4105 else if (phy->req_line_speed != SPEED_AUTO_NEG)
4106 vars->flow_ctrl = params->req_fc_auto_adv;
4107 else if ((gp_status & MDIO_AN_CL73_OR_37_COMPLETE) &&
4108 (!(vars->phy_flags & PHY_SGMII_FLAG))) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004109 if (bnx2x_direct_parallel_detect_used(phy, params)) {
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02004110 vars->flow_ctrl = params->req_fc_auto_adv;
4111 return;
4112 }
Yaniv Rosner7846e472009-11-05 19:18:07 +02004113 if ((gp_status &
4114 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
4115 MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) ==
4116 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
4117 MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) {
4118
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004119 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004120 MDIO_REG_BANK_CL73_IEEEB1,
4121 MDIO_CL73_IEEEB1_AN_ADV1,
4122 &ld_pause);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004123 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004124 MDIO_REG_BANK_CL73_IEEEB1,
4125 MDIO_CL73_IEEEB1_AN_LP_ADV1,
4126 &lp_pause);
Yaniv Rosner7846e472009-11-05 19:18:07 +02004127 pause_result = (ld_pause &
4128 MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK)
4129 >> 8;
4130 pause_result |= (lp_pause &
4131 MDIO_CL73_IEEEB1_AN_LP_ADV1_PAUSE_MASK)
4132 >> 10;
4133 DP(NETIF_MSG_LINK, "pause_result CL73 0x%x\n",
4134 pause_result);
4135 } else {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004136 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004137 MDIO_REG_BANK_COMBO_IEEE0,
4138 MDIO_COMBO_IEEE0_AUTO_NEG_ADV,
4139 &ld_pause);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004140 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004141 MDIO_REG_BANK_COMBO_IEEE0,
4142 MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1,
4143 &lp_pause);
Yaniv Rosner7846e472009-11-05 19:18:07 +02004144 pause_result = (ld_pause &
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004145 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>5;
Yaniv Rosner7846e472009-11-05 19:18:07 +02004146 pause_result |= (lp_pause &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004147 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7;
Yaniv Rosner7846e472009-11-05 19:18:07 +02004148 DP(NETIF_MSG_LINK, "pause_result CL37 0x%x\n",
4149 pause_result);
4150 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004151 bnx2x_pause_resolve(vars, pause_result);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004152 }
4153 DP(NETIF_MSG_LINK, "flow_ctrl 0x%x\n", vars->flow_ctrl);
4154}
4155
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004156static void bnx2x_check_fallback_to_cl37(struct bnx2x_phy *phy,
4157 struct link_params *params)
Eilon Greenstein239d6862009-08-12 08:23:04 +00004158{
4159 struct bnx2x *bp = params->bp;
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00004160 u16 rx_status, ustat_val, cl37_fsm_received;
Eilon Greenstein239d6862009-08-12 08:23:04 +00004161 DP(NETIF_MSG_LINK, "bnx2x_check_fallback_to_cl37\n");
4162 /* Step 1: Make sure signal is detected */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004163 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004164 MDIO_REG_BANK_RX0,
4165 MDIO_RX0_RX_STATUS,
4166 &rx_status);
Eilon Greenstein239d6862009-08-12 08:23:04 +00004167 if ((rx_status & MDIO_RX0_RX_STATUS_SIGDET) !=
4168 (MDIO_RX0_RX_STATUS_SIGDET)) {
4169 DP(NETIF_MSG_LINK, "Signal is not detected. Restoring CL73."
4170 "rx_status(0x80b0) = 0x%x\n", rx_status);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004171 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004172 MDIO_REG_BANK_CL73_IEEEB0,
4173 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
4174 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN);
Eilon Greenstein239d6862009-08-12 08:23:04 +00004175 return;
4176 }
4177 /* Step 2: Check CL73 state machine */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004178 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004179 MDIO_REG_BANK_CL73_USERB0,
4180 MDIO_CL73_USERB0_CL73_USTAT1,
4181 &ustat_val);
Eilon Greenstein239d6862009-08-12 08:23:04 +00004182 if ((ustat_val &
4183 (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK |
4184 MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) !=
4185 (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK |
4186 MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) {
4187 DP(NETIF_MSG_LINK, "CL73 state-machine is not stable. "
4188 "ustat_val(0x8371) = 0x%x\n", ustat_val);
4189 return;
4190 }
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004191 /*
4192 * Step 3: Check CL37 Message Pages received to indicate LP
4193 * supports only CL37
4194 */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004195 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004196 MDIO_REG_BANK_REMOTE_PHY,
4197 MDIO_REMOTE_PHY_MISC_RX_STATUS,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00004198 &cl37_fsm_received);
4199 if ((cl37_fsm_received &
Eilon Greenstein239d6862009-08-12 08:23:04 +00004200 (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG |
4201 MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) !=
4202 (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG |
4203 MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) {
4204 DP(NETIF_MSG_LINK, "No CL37 FSM were received. "
4205 "misc_rx_status(0x8330) = 0x%x\n",
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00004206 cl37_fsm_received);
Eilon Greenstein239d6862009-08-12 08:23:04 +00004207 return;
4208 }
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004209 /*
4210 * The combined cl37/cl73 fsm state information indicating that
4211 * we are connected to a device which does not support cl73, but
4212 * does support cl37 BAM. In this case we disable cl73 and
4213 * restart cl37 auto-neg
4214 */
4215
Eilon Greenstein239d6862009-08-12 08:23:04 +00004216 /* Disable CL73 */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004217 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004218 MDIO_REG_BANK_CL73_IEEEB0,
4219 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
4220 0);
Eilon Greenstein239d6862009-08-12 08:23:04 +00004221 /* Restart CL37 autoneg */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004222 bnx2x_restart_autoneg(phy, params, 0);
Eilon Greenstein239d6862009-08-12 08:23:04 +00004223 DP(NETIF_MSG_LINK, "Disabling CL73, and restarting CL37 autoneg\n");
4224}
Yaniv Rosner7aa07112010-09-07 11:41:01 +00004225
4226static void bnx2x_xgxs_an_resolve(struct bnx2x_phy *phy,
4227 struct link_params *params,
4228 struct link_vars *vars,
4229 u32 gp_status)
4230{
4231 if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE)
4232 vars->link_status |=
4233 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
4234
4235 if (bnx2x_direct_parallel_detect_used(phy, params))
4236 vars->link_status |=
4237 LINK_STATUS_PARALLEL_DETECTION_USED;
4238}
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004239static int bnx2x_get_link_speed_duplex(struct bnx2x_phy *phy,
4240 struct link_params *params,
4241 struct link_vars *vars,
4242 u16 is_link_up,
4243 u16 speed_mask,
4244 u16 is_duplex)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004245{
4246 struct bnx2x *bp = params->bp;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00004247 if (phy->req_line_speed == SPEED_AUTO_NEG)
4248 vars->link_status |= LINK_STATUS_AUTO_NEGOTIATE_ENABLED;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004249 if (is_link_up) {
4250 DP(NETIF_MSG_LINK, "phy link up\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004251
4252 vars->phy_link_up = 1;
4253 vars->link_status |= LINK_STATUS_LINK_UP;
4254
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004255 switch (speed_mask) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004256 case GP_STATUS_10M:
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004257 vars->line_speed = SPEED_10;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004258 if (vars->duplex == DUPLEX_FULL)
4259 vars->link_status |= LINK_10TFD;
4260 else
4261 vars->link_status |= LINK_10THD;
4262 break;
4263
4264 case GP_STATUS_100M:
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004265 vars->line_speed = SPEED_100;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004266 if (vars->duplex == DUPLEX_FULL)
4267 vars->link_status |= LINK_100TXFD;
4268 else
4269 vars->link_status |= LINK_100TXHD;
4270 break;
4271
4272 case GP_STATUS_1G:
4273 case GP_STATUS_1G_KX:
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004274 vars->line_speed = SPEED_1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004275 if (vars->duplex == DUPLEX_FULL)
4276 vars->link_status |= LINK_1000TFD;
4277 else
4278 vars->link_status |= LINK_1000THD;
4279 break;
4280
4281 case GP_STATUS_2_5G:
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004282 vars->line_speed = SPEED_2500;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004283 if (vars->duplex == DUPLEX_FULL)
4284 vars->link_status |= LINK_2500TFD;
4285 else
4286 vars->link_status |= LINK_2500THD;
4287 break;
4288
4289 case GP_STATUS_5G:
4290 case GP_STATUS_6G:
4291 DP(NETIF_MSG_LINK,
4292 "link speed unsupported gp_status 0x%x\n",
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004293 speed_mask);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004294 return -EINVAL;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00004295
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004296 case GP_STATUS_10G_KX4:
4297 case GP_STATUS_10G_HIG:
4298 case GP_STATUS_10G_CX4:
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004299 case GP_STATUS_10G_KR:
4300 case GP_STATUS_10G_SFI:
4301 case GP_STATUS_10G_XFI:
4302 vars->line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004303 vars->link_status |= LINK_10GTFD;
4304 break;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004305 case GP_STATUS_20G_DXGXS:
4306 vars->line_speed = SPEED_20000;
4307 vars->link_status |= LINK_20GTFD;
4308 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004309 default:
4310 DP(NETIF_MSG_LINK,
4311 "link speed unsupported gp_status 0x%x\n",
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004312 speed_mask);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00004313 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004314 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004315 } else { /* link_down */
4316 DP(NETIF_MSG_LINK, "phy link down\n");
4317
4318 vars->phy_link_up = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004319
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004320 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08004321 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004322 vars->mac_type = MAC_TYPE_NONE;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004323 }
4324 DP(NETIF_MSG_LINK, " phy_link_up %x line_speed %d\n",
4325 vars->phy_link_up, vars->line_speed);
4326 return 0;
4327}
Eilon Greenstein239d6862009-08-12 08:23:04 +00004328
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004329static int bnx2x_link_settings_status(struct bnx2x_phy *phy,
4330 struct link_params *params,
4331 struct link_vars *vars)
4332{
4333
4334 struct bnx2x *bp = params->bp;
4335
4336 u16 gp_status, duplex = DUPLEX_HALF, link_up = 0, speed_mask;
4337 int rc = 0;
4338
4339 /* Read gp_status */
4340 CL22_RD_OVER_CL45(bp, phy,
4341 MDIO_REG_BANK_GP_STATUS,
4342 MDIO_GP_STATUS_TOP_AN_STATUS1,
4343 &gp_status);
4344 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_DUPLEX_STATUS)
4345 duplex = DUPLEX_FULL;
4346 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS)
4347 link_up = 1;
4348 speed_mask = gp_status & GP_STATUS_SPEED_MASK;
4349 DP(NETIF_MSG_LINK, "gp_status 0x%x, is_link_up %d, speed_mask 0x%x\n",
4350 gp_status, link_up, speed_mask);
4351 rc = bnx2x_get_link_speed_duplex(phy, params, vars, link_up, speed_mask,
4352 duplex);
4353 if (rc == -EINVAL)
4354 return rc;
4355
4356 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) {
4357 if (SINGLE_MEDIA_DIRECT(params)) {
4358 bnx2x_flow_ctrl_resolve(phy, params, vars, gp_status);
4359 if (phy->req_line_speed == SPEED_AUTO_NEG)
4360 bnx2x_xgxs_an_resolve(phy, params, vars,
4361 gp_status);
4362 }
4363 } else { /* link_down */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00004364 if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
4365 SINGLE_MEDIA_DIRECT(params)) {
Eilon Greenstein239d6862009-08-12 08:23:04 +00004366 /* Check signal is detected */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00004367 bnx2x_check_fallback_to_cl37(phy, params);
Eilon Greenstein239d6862009-08-12 08:23:04 +00004368 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004369 }
4370
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004371 DP(NETIF_MSG_LINK, "duplex %x flow_ctrl 0x%x link_status 0x%x\n",
4372 vars->duplex, vars->flow_ctrl, vars->link_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004373 return rc;
4374}
4375
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004376static int bnx2x_warpcore_read_status(struct bnx2x_phy *phy,
4377 struct link_params *params,
4378 struct link_vars *vars)
4379{
4380
4381 struct bnx2x *bp = params->bp;
4382
4383 u8 lane;
4384 u16 gp_status1, gp_speed, link_up, duplex = DUPLEX_FULL;
4385 int rc = 0;
4386 lane = bnx2x_get_warpcore_lane(phy, params);
4387 /* Read gp_status */
4388 if (phy->req_line_speed > SPEED_10000) {
4389 u16 temp_link_up;
4390 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
4391 1, &temp_link_up);
4392 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
4393 1, &link_up);
4394 DP(NETIF_MSG_LINK, "PCS RX link status = 0x%x-->0x%x\n",
4395 temp_link_up, link_up);
4396 link_up &= (1<<2);
4397 if (link_up)
4398 bnx2x_ext_phy_resolve_fc(phy, params, vars);
4399 } else {
4400 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
4401 MDIO_WC_REG_GP2_STATUS_GP_2_1, &gp_status1);
4402 DP(NETIF_MSG_LINK, "0x81d1 = 0x%x\n", gp_status1);
4403 /* Check for either KR or generic link up. */
4404 gp_status1 = ((gp_status1 >> 8) & 0xf) |
4405 ((gp_status1 >> 12) & 0xf);
4406 link_up = gp_status1 & (1 << lane);
4407 if (link_up && SINGLE_MEDIA_DIRECT(params)) {
4408 u16 pd, gp_status4;
4409 if (phy->req_line_speed == SPEED_AUTO_NEG) {
4410 /* Check Autoneg complete */
4411 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
4412 MDIO_WC_REG_GP2_STATUS_GP_2_4,
4413 &gp_status4);
4414 if (gp_status4 & ((1<<12)<<lane))
4415 vars->link_status |=
4416 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
4417
4418 /* Check parallel detect used */
4419 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
4420 MDIO_WC_REG_PAR_DET_10G_STATUS,
4421 &pd);
4422 if (pd & (1<<15))
4423 vars->link_status |=
4424 LINK_STATUS_PARALLEL_DETECTION_USED;
4425 }
4426 bnx2x_ext_phy_resolve_fc(phy, params, vars);
4427 }
4428 }
4429
4430 if (lane < 2) {
4431 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
4432 MDIO_WC_REG_GP2_STATUS_GP_2_2, &gp_speed);
4433 } else {
4434 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
4435 MDIO_WC_REG_GP2_STATUS_GP_2_3, &gp_speed);
4436 }
4437 DP(NETIF_MSG_LINK, "lane %d gp_speed 0x%x\n", lane, gp_speed);
4438
4439 if ((lane & 1) == 0)
4440 gp_speed <<= 8;
4441 gp_speed &= 0x3f00;
4442
4443
4444 rc = bnx2x_get_link_speed_duplex(phy, params, vars, link_up, gp_speed,
4445 duplex);
4446
4447 DP(NETIF_MSG_LINK, "duplex %x flow_ctrl 0x%x link_status 0x%x\n",
4448 vars->duplex, vars->flow_ctrl, vars->link_status);
4449 return rc;
4450}
Eilon Greensteined8680a2009-02-12 08:37:12 +00004451static void bnx2x_set_gmii_tx_driver(struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004452{
4453 struct bnx2x *bp = params->bp;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004454 struct bnx2x_phy *phy = &params->phy[INT_PHY];
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004455 u16 lp_up2;
4456 u16 tx_driver;
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00004457 u16 bank;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004458
4459 /* read precomp */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004460 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004461 MDIO_REG_BANK_OVER_1G,
4462 MDIO_OVER_1G_LP_UP2, &lp_up2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004463
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004464 /* bits [10:7] at lp_up2, positioned at [15:12] */
4465 lp_up2 = (((lp_up2 & MDIO_OVER_1G_LP_UP2_PREEMPHASIS_MASK) >>
4466 MDIO_OVER_1G_LP_UP2_PREEMPHASIS_SHIFT) <<
4467 MDIO_TX0_TX_DRIVER_PREEMPHASIS_SHIFT);
4468
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00004469 if (lp_up2 == 0)
4470 return;
4471
4472 for (bank = MDIO_REG_BANK_TX0; bank <= MDIO_REG_BANK_TX3;
4473 bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0)) {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004474 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004475 bank,
4476 MDIO_TX0_TX_DRIVER, &tx_driver);
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00004477
4478 /* replace tx_driver bits [15:12] */
4479 if (lp_up2 !=
4480 (tx_driver & MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK)) {
4481 tx_driver &= ~MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK;
4482 tx_driver |= lp_up2;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004483 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004484 bank,
4485 MDIO_TX0_TX_DRIVER, tx_driver);
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00004486 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004487 }
4488}
4489
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00004490static int bnx2x_emac_program(struct link_params *params,
4491 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004492{
4493 struct bnx2x *bp = params->bp;
4494 u8 port = params->port;
4495 u16 mode = 0;
4496
4497 DP(NETIF_MSG_LINK, "setting link speed & duplex\n");
4498 bnx2x_bits_dis(bp, GRCBASE_EMAC0 + port*0x400 +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004499 EMAC_REG_EMAC_MODE,
4500 (EMAC_MODE_25G_MODE |
4501 EMAC_MODE_PORT_MII_10M |
4502 EMAC_MODE_HALF_DUPLEX));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004503 switch (vars->line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004504 case SPEED_10:
4505 mode |= EMAC_MODE_PORT_MII_10M;
4506 break;
4507
4508 case SPEED_100:
4509 mode |= EMAC_MODE_PORT_MII;
4510 break;
4511
4512 case SPEED_1000:
4513 mode |= EMAC_MODE_PORT_GMII;
4514 break;
4515
4516 case SPEED_2500:
4517 mode |= (EMAC_MODE_25G_MODE | EMAC_MODE_PORT_GMII);
4518 break;
4519
4520 default:
4521 /* 10G not valid for EMAC */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004522 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
4523 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004524 return -EINVAL;
4525 }
4526
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004527 if (vars->duplex == DUPLEX_HALF)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004528 mode |= EMAC_MODE_HALF_DUPLEX;
4529 bnx2x_bits_en(bp,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004530 GRCBASE_EMAC0 + port*0x400 + EMAC_REG_EMAC_MODE,
4531 mode);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004532
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00004533 bnx2x_set_led(params, vars, LED_MODE_OPER, vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004534 return 0;
4535}
4536
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004537static void bnx2x_set_preemphasis(struct bnx2x_phy *phy,
4538 struct link_params *params)
4539{
4540
4541 u16 bank, i = 0;
4542 struct bnx2x *bp = params->bp;
4543
4544 for (bank = MDIO_REG_BANK_RX0, i = 0; bank <= MDIO_REG_BANK_RX3;
4545 bank += (MDIO_REG_BANK_RX1-MDIO_REG_BANK_RX0), i++) {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004546 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004547 bank,
4548 MDIO_RX0_RX_EQ_BOOST,
4549 phy->rx_preemphasis[i]);
4550 }
4551
4552 for (bank = MDIO_REG_BANK_TX0, i = 0; bank <= MDIO_REG_BANK_TX3;
4553 bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0), i++) {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004554 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004555 bank,
4556 MDIO_TX0_TX_DRIVER,
4557 phy->tx_preemphasis[i]);
4558 }
4559}
4560
Yaniv Rosnerec146a62011-05-31 21:29:27 +00004561static void bnx2x_xgxs_config_init(struct bnx2x_phy *phy,
4562 struct link_params *params,
4563 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004564{
4565 struct bnx2x *bp = params->bp;
4566 u8 enable_cl73 = (SINGLE_MEDIA_DIRECT(params) ||
4567 (params->loopback_mode == LOOPBACK_XGXS));
4568 if (!(vars->phy_flags & PHY_SGMII_FLAG)) {
4569 if (SINGLE_MEDIA_DIRECT(params) &&
4570 (params->feature_config_flags &
4571 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED))
4572 bnx2x_set_preemphasis(phy, params);
4573
4574 /* forced speed requested? */
4575 if (vars->line_speed != SPEED_AUTO_NEG ||
4576 (SINGLE_MEDIA_DIRECT(params) &&
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004577 params->loopback_mode == LOOPBACK_EXT)) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004578 DP(NETIF_MSG_LINK, "not SGMII, no AN\n");
4579
4580 /* disable autoneg */
4581 bnx2x_set_autoneg(phy, params, vars, 0);
4582
4583 /* program speed and duplex */
4584 bnx2x_program_serdes(phy, params, vars);
4585
4586 } else { /* AN_mode */
4587 DP(NETIF_MSG_LINK, "not SGMII, AN\n");
4588
4589 /* AN enabled */
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00004590 bnx2x_set_brcm_cl37_advertisement(phy, params);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004591
4592 /* program duplex & pause advertisement (for aneg) */
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00004593 bnx2x_set_ieee_aneg_advertisement(phy, params,
4594 vars->ieee_fc);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004595
4596 /* enable autoneg */
4597 bnx2x_set_autoneg(phy, params, vars, enable_cl73);
4598
4599 /* enable and restart AN */
4600 bnx2x_restart_autoneg(phy, params, enable_cl73);
4601 }
4602
4603 } else { /* SGMII mode */
4604 DP(NETIF_MSG_LINK, "SGMII\n");
4605
4606 bnx2x_initialize_sgmii_process(phy, params, vars);
4607 }
4608}
4609
Yaniv Rosnerec146a62011-05-31 21:29:27 +00004610static int bnx2x_prepare_xgxs(struct bnx2x_phy *phy,
4611 struct link_params *params,
4612 struct link_vars *vars)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004613{
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00004614 int rc;
Yaniv Rosnerec146a62011-05-31 21:29:27 +00004615 vars->phy_flags |= PHY_XGXS_FLAG;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004616 if ((phy->req_line_speed &&
4617 ((phy->req_line_speed == SPEED_100) ||
4618 (phy->req_line_speed == SPEED_10))) ||
4619 (!phy->req_line_speed &&
4620 (phy->speed_cap_mask >=
4621 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL) &&
4622 (phy->speed_cap_mask <
Yaniv Rosnerec146a62011-05-31 21:29:27 +00004623 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) ||
4624 (phy->type == PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT_SD))
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004625 vars->phy_flags |= PHY_SGMII_FLAG;
4626 else
4627 vars->phy_flags &= ~PHY_SGMII_FLAG;
4628
4629 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
Yaniv Rosnerec146a62011-05-31 21:29:27 +00004630 bnx2x_set_aer_mmd(params, phy);
4631 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT)
4632 bnx2x_set_master_ln(params, phy);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004633
4634 rc = bnx2x_reset_unicore(params, phy, 0);
4635 /* reset the SerDes and wait for reset bit return low */
4636 if (rc != 0)
4637 return rc;
4638
Yaniv Rosnerec146a62011-05-31 21:29:27 +00004639 bnx2x_set_aer_mmd(params, phy);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004640 /* setting the masterLn_def again after the reset */
Yaniv Rosnerec146a62011-05-31 21:29:27 +00004641 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) {
4642 bnx2x_set_master_ln(params, phy);
4643 bnx2x_set_swap_lanes(params, phy);
4644 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004645
4646 return rc;
4647}
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00004648
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004649static u16 bnx2x_wait_reset_complete(struct bnx2x *bp,
Yaniv Rosner6d870c32011-01-31 04:22:20 +00004650 struct bnx2x_phy *phy,
4651 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004652{
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004653 u16 cnt, ctrl;
Lucas De Marchi25985ed2011-03-30 22:57:33 -03004654 /* Wait for soft reset to get cleared up to 1 sec */
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004655 for (cnt = 0; cnt < 1000; cnt++) {
4656 bnx2x_cl45_read(bp, phy,
4657 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, &ctrl);
4658 if (!(ctrl & (1<<15)))
4659 break;
4660 msleep(1);
4661 }
Yaniv Rosner6d870c32011-01-31 04:22:20 +00004662
4663 if (cnt == 1000)
4664 netdev_err(bp->dev, "Warning: PHY was not initialized,"
4665 " Port %d\n",
4666 params->port);
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004667 DP(NETIF_MSG_LINK, "control reg 0x%x (after %d ms)\n", ctrl, cnt);
4668 return cnt;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004669}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004670
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004671static void bnx2x_link_int_enable(struct link_params *params)
4672{
4673 u8 port = params->port;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004674 u32 mask;
4675 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00004676
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004677 /* Setting the status to report on link up for either XGXS or SerDes */
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004678 if (CHIP_IS_E3(bp)) {
4679 mask = NIG_MASK_XGXS0_LINK_STATUS;
4680 if (!(SINGLE_MEDIA_DIRECT(params)))
4681 mask |= NIG_MASK_MI_INT;
4682 } else if (params->switch_cfg == SWITCH_CFG_10G) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004683 mask = (NIG_MASK_XGXS0_LINK10G |
4684 NIG_MASK_XGXS0_LINK_STATUS);
4685 DP(NETIF_MSG_LINK, "enabled XGXS interrupt\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004686 if (!(SINGLE_MEDIA_DIRECT(params)) &&
4687 params->phy[INT_PHY].type !=
4688 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004689 mask |= NIG_MASK_MI_INT;
4690 DP(NETIF_MSG_LINK, "enabled external phy int\n");
4691 }
4692
4693 } else { /* SerDes */
4694 mask = NIG_MASK_SERDES0_LINK_STATUS;
4695 DP(NETIF_MSG_LINK, "enabled SerDes interrupt\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004696 if (!(SINGLE_MEDIA_DIRECT(params)) &&
4697 params->phy[INT_PHY].type !=
4698 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_NOT_CONN) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004699 mask |= NIG_MASK_MI_INT;
4700 DP(NETIF_MSG_LINK, "enabled external phy int\n");
4701 }
4702 }
4703 bnx2x_bits_en(bp,
4704 NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
4705 mask);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00004706
4707 DP(NETIF_MSG_LINK, "port %x, is_xgxs %x, int_status 0x%x\n", port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004708 (params->switch_cfg == SWITCH_CFG_10G),
4709 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004710 DP(NETIF_MSG_LINK, " int_mask 0x%x, MI_INT %x, SERDES_LINK %x\n",
4711 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
4712 REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
4713 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS+port*0x3c));
4714 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
4715 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
4716 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
4717}
4718
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004719static void bnx2x_rearm_latch_signal(struct bnx2x *bp, u8 port,
4720 u8 exp_mi_int)
Eilon Greenstein2f904462009-08-12 08:22:16 +00004721{
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004722 u32 latch_status = 0;
4723
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004724 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004725 * Disable the MI INT ( external phy int ) by writing 1 to the
4726 * status register. Link down indication is high-active-signal,
4727 * so in this case we need to write the status to clear the XOR
Eilon Greenstein2f904462009-08-12 08:22:16 +00004728 */
4729 /* Read Latched signals */
4730 latch_status = REG_RD(bp,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004731 NIG_REG_LATCH_STATUS_0 + port*8);
4732 DP(NETIF_MSG_LINK, "latch_status = 0x%x\n", latch_status);
Eilon Greenstein2f904462009-08-12 08:22:16 +00004733 /* Handle only those with latched-signal=up.*/
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004734 if (exp_mi_int)
4735 bnx2x_bits_en(bp,
4736 NIG_REG_STATUS_INTERRUPT_PORT0
4737 + port*4,
4738 NIG_STATUS_EMAC0_MI_INT);
4739 else
4740 bnx2x_bits_dis(bp,
4741 NIG_REG_STATUS_INTERRUPT_PORT0
4742 + port*4,
4743 NIG_STATUS_EMAC0_MI_INT);
4744
Eilon Greenstein2f904462009-08-12 08:22:16 +00004745 if (latch_status & 1) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004746
Eilon Greenstein2f904462009-08-12 08:22:16 +00004747 /* For all latched-signal=up : Re-Arm Latch signals */
4748 REG_WR(bp, NIG_REG_LATCH_STATUS_0 + port*8,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004749 (latch_status & 0xfffe) | (latch_status & 1));
Eilon Greenstein2f904462009-08-12 08:22:16 +00004750 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004751 /* For all latched-signal=up,Write original_signal to status */
Eilon Greenstein2f904462009-08-12 08:22:16 +00004752}
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004753
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004754static void bnx2x_link_int_ack(struct link_params *params,
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004755 struct link_vars *vars, u8 is_10g_plus)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004756{
4757 struct bnx2x *bp = params->bp;
4758 u8 port = params->port;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004759 u32 mask;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004760 /*
4761 * First reset all status we assume only one line will be
4762 * change at a time
4763 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004764 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004765 (NIG_STATUS_XGXS0_LINK10G |
4766 NIG_STATUS_XGXS0_LINK_STATUS |
4767 NIG_STATUS_SERDES0_LINK_STATUS));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004768 if (vars->phy_link_up) {
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004769 if (USES_WARPCORE(bp))
4770 mask = NIG_STATUS_XGXS0_LINK_STATUS;
4771 else {
4772 if (is_10g_plus)
4773 mask = NIG_STATUS_XGXS0_LINK10G;
4774 else if (params->switch_cfg == SWITCH_CFG_10G) {
4775 /*
4776 * Disable the link interrupt by writing 1 to
4777 * the relevant lane in the status register
4778 */
4779 u32 ser_lane =
4780 ((params->lane_config &
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004781 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
4782 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004783 mask = ((1 << ser_lane) <<
4784 NIG_STATUS_XGXS0_LINK_STATUS_SIZE);
4785 } else
4786 mask = NIG_STATUS_SERDES0_LINK_STATUS;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004787 }
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004788 DP(NETIF_MSG_LINK, "Ack link up interrupt with mask 0x%x\n",
4789 mask);
4790 bnx2x_bits_en(bp,
4791 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
4792 mask);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004793 }
4794}
4795
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00004796static int bnx2x_format_ver(u32 num, u8 *str, u16 *len)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004797{
4798 u8 *str_ptr = str;
4799 u32 mask = 0xf0000000;
4800 u8 shift = 8*4;
4801 u8 digit;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004802 u8 remove_leading_zeros = 1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004803 if (*len < 10) {
Frederik Schwarzer025dfda2008-10-16 19:02:37 +02004804 /* Need more than 10chars for this format */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004805 *str_ptr = '\0';
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004806 (*len)--;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004807 return -EINVAL;
4808 }
4809 while (shift > 0) {
4810
4811 shift -= 4;
4812 digit = ((num & mask) >> shift);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004813 if (digit == 0 && remove_leading_zeros) {
4814 mask = mask >> 4;
4815 continue;
4816 } else if (digit < 0xa)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004817 *str_ptr = digit + '0';
4818 else
4819 *str_ptr = digit - 0xa + 'a';
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004820 remove_leading_zeros = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004821 str_ptr++;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004822 (*len)--;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004823 mask = mask >> 4;
4824 if (shift == 4*4) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004825 *str_ptr = '.';
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004826 str_ptr++;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004827 (*len)--;
4828 remove_leading_zeros = 1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004829 }
4830 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004831 return 0;
4832}
4833
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004834
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00004835static int bnx2x_null_format_ver(u32 spirom_ver, u8 *str, u16 *len)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004836{
4837 str[0] = '\0';
4838 (*len)--;
4839 return 0;
4840}
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004841
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00004842int bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
4843 u8 *version, u16 len)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004844{
Julia Lawall0376d5b2009-07-19 05:26:35 +00004845 struct bnx2x *bp;
Eilon Greensteina35da8d2009-02-12 08:37:02 +00004846 u32 spirom_ver = 0;
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00004847 int status = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004848 u8 *ver_p = version;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004849 u16 remain_len = len;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004850 if (version == NULL || params == NULL)
4851 return -EINVAL;
Julia Lawall0376d5b2009-07-19 05:26:35 +00004852 bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004853
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004854 /* Extract first external phy*/
4855 version[0] = '\0';
4856 spirom_ver = REG_RD(bp, params->phy[EXT_PHY1].ver_addr);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00004857
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004858 if (params->phy[EXT_PHY1].format_fw_ver) {
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004859 status |= params->phy[EXT_PHY1].format_fw_ver(spirom_ver,
4860 ver_p,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004861 &remain_len);
4862 ver_p += (len - remain_len);
4863 }
4864 if ((params->num_phys == MAX_PHYS) &&
4865 (params->phy[EXT_PHY2].ver_addr != 0)) {
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004866 spirom_ver = REG_RD(bp, params->phy[EXT_PHY2].ver_addr);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004867 if (params->phy[EXT_PHY2].format_fw_ver) {
4868 *ver_p = '/';
4869 ver_p++;
4870 remain_len--;
4871 status |= params->phy[EXT_PHY2].format_fw_ver(
4872 spirom_ver,
4873 ver_p,
4874 &remain_len);
4875 ver_p = version + (len - remain_len);
4876 }
4877 }
4878 *ver_p = '\0';
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004879 return status;
4880}
4881
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004882static void bnx2x_set_xgxs_loopback(struct bnx2x_phy *phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004883 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004884{
4885 u8 port = params->port;
4886 struct bnx2x *bp = params->bp;
4887
Yaniv Rosner62b29a52010-09-07 11:40:58 +00004888 if (phy->req_line_speed != SPEED_1000) {
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004889 u32 md_devad = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004890
4891 DP(NETIF_MSG_LINK, "XGXS 10G loopback enable\n");
4892
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004893 if (!CHIP_IS_E3(bp)) {
4894 /* change the uni_phy_addr in the nig */
4895 md_devad = REG_RD(bp, (NIG_REG_XGXS0_CTRL_MD_DEVAD +
4896 port*0x18));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004897
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004898 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
4899 0x5);
4900 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004901
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004902 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004903 5,
4904 (MDIO_REG_BANK_AER_BLOCK +
4905 (MDIO_AER_BLOCK_AER_REG & 0xf)),
4906 0x2800);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004907
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004908 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004909 5,
4910 (MDIO_REG_BANK_CL73_IEEEB0 +
4911 (MDIO_CL73_IEEEB0_CL73_AN_CONTROL & 0xf)),
4912 0x6041);
Eilon Greenstein38582762009-01-14 06:44:16 +00004913 msleep(200);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004914 /* set aer mmd back */
Yaniv Rosnerec146a62011-05-31 21:29:27 +00004915 bnx2x_set_aer_mmd(params, phy);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004916
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004917 if (!CHIP_IS_E3(bp)) {
4918 /* and md_devad */
4919 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
4920 md_devad);
4921 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004922 } else {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004923 u16 mii_ctrl;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004924 DP(NETIF_MSG_LINK, "XGXS 1G loopback enable\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004925 bnx2x_cl45_read(bp, phy, 5,
4926 (MDIO_REG_BANK_COMBO_IEEE0 +
4927 (MDIO_COMBO_IEEE0_MII_CONTROL & 0xf)),
4928 &mii_ctrl);
4929 bnx2x_cl45_write(bp, phy, 5,
4930 (MDIO_REG_BANK_COMBO_IEEE0 +
4931 (MDIO_COMBO_IEEE0_MII_CONTROL & 0xf)),
4932 mii_ctrl |
4933 MDIO_COMBO_IEEO_MII_CONTROL_LOOPBACK);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004934 }
4935}
4936
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00004937int bnx2x_set_led(struct link_params *params,
4938 struct link_vars *vars, u8 mode, u32 speed)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004939{
Yaniv Rosner7846e472009-11-05 19:18:07 +02004940 u8 port = params->port;
4941 u16 hw_led_mode = params->hw_led_mode;
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00004942 int rc = 0;
4943 u8 phy_idx;
Eilon Greenstein345b5d52008-08-13 15:58:12 -07004944 u32 tmp;
4945 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Yaniv Rosner7846e472009-11-05 19:18:07 +02004946 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004947 DP(NETIF_MSG_LINK, "bnx2x_set_led: port %x, mode %d\n", port, mode);
4948 DP(NETIF_MSG_LINK, "speed 0x%x, hw_led_mode 0x%x\n",
4949 speed, hw_led_mode);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00004950 /* In case */
4951 for (phy_idx = EXT_PHY1; phy_idx < MAX_PHYS; phy_idx++) {
4952 if (params->phy[phy_idx].set_link_led) {
4953 params->phy[phy_idx].set_link_led(
4954 &params->phy[phy_idx], params, mode);
4955 }
4956 }
4957
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004958 switch (mode) {
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00004959 case LED_MODE_FRONT_PANEL_OFF:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004960 case LED_MODE_OFF:
4961 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 0);
4962 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004963 SHARED_HW_CFG_LED_MAC1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07004964
4965 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07004966 EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp | EMAC_LED_OVERRIDE));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004967 break;
4968
4969 case LED_MODE_OPER:
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004970 /*
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00004971 * For all other phys, OPER mode is same as ON, so in case
4972 * link is down, do nothing
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004973 */
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00004974 if (!vars->link_up)
4975 break;
4976 case LED_MODE_ON:
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00004977 if (((params->phy[EXT_PHY1].type ==
4978 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) ||
4979 (params->phy[EXT_PHY1].type ==
4980 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722)) &&
Yaniv Rosner1f483532011-01-18 04:33:31 +00004981 CHIP_IS_E2(bp) && params->num_phys == 2) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004982 /*
4983 * This is a work-around for E2+8727 Configurations
4984 */
Yaniv Rosner1f483532011-01-18 04:33:31 +00004985 if (mode == LED_MODE_ON ||
4986 speed == SPEED_10000){
4987 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0);
4988 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1);
4989
4990 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
4991 EMAC_WR(bp, EMAC_REG_EMAC_LED,
4992 (tmp | EMAC_LED_OVERRIDE));
4993 return rc;
4994 }
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004995 } else if (SINGLE_MEDIA_DIRECT(params) &&
4996 (CHIP_IS_E1x(bp) ||
4997 CHIP_IS_E2(bp))) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004998 /*
4999 * This is a work-around for HW issue found when link
5000 * is up in CL73
5001 */
Yaniv Rosner7846e472009-11-05 19:18:07 +02005002 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0);
5003 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1);
5004 } else {
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005005 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, hw_led_mode);
Yaniv Rosner7846e472009-11-05 19:18:07 +02005006 }
5007
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005008 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 + port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005009 /* Set blinking rate to ~15.9Hz */
5010 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005011 LED_BLINK_RATE_VAL);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005012 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005013 port*4, 1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07005014 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005015 EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp & (~EMAC_LED_OVERRIDE)));
Eilon Greenstein345b5d52008-08-13 15:58:12 -07005016
Yaniv Rosner7846e472009-11-05 19:18:07 +02005017 if (CHIP_IS_E1(bp) &&
Eilon Greenstein34f80b02008-06-23 20:33:01 -07005018 ((speed == SPEED_2500) ||
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005019 (speed == SPEED_1000) ||
5020 (speed == SPEED_100) ||
5021 (speed == SPEED_10))) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005022 /*
5023 * On Everest 1 Ax chip versions for speeds less than
5024 * 10G LED scheme is different
5025 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005026 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005027 + port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005028 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005029 port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005030 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_TRAFFIC_P0 +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005031 port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005032 }
5033 break;
5034
5035 default:
5036 rc = -EINVAL;
5037 DP(NETIF_MSG_LINK, "bnx2x_set_led: Invalid led mode %d\n",
5038 mode);
5039 break;
5040 }
5041 return rc;
5042
5043}
5044
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005045/*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005046 * This function comes to reflect the actual link state read DIRECTLY from the
5047 * HW
5048 */
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005049int bnx2x_test_link(struct link_params *params, struct link_vars *vars,
5050 u8 is_serdes)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005051{
5052 struct bnx2x *bp = params->bp;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00005053 u16 gp_status = 0, phy_index = 0;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005054 u8 ext_phy_link_up = 0, serdes_phy_type;
5055 struct link_vars temp_vars;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005056 struct bnx2x_phy *int_phy = &params->phy[INT_PHY];
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005057
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005058 if (CHIP_IS_E3(bp)) {
5059 u16 link_up;
5060 if (params->req_line_speed[LINK_CONFIG_IDX(INT_PHY)]
5061 > SPEED_10000) {
5062 /* Check 20G link */
5063 bnx2x_cl45_read(bp, int_phy, MDIO_WC_DEVAD,
5064 1, &link_up);
5065 bnx2x_cl45_read(bp, int_phy, MDIO_WC_DEVAD,
5066 1, &link_up);
5067 link_up &= (1<<2);
5068 } else {
5069 /* Check 10G link and below*/
5070 u8 lane = bnx2x_get_warpcore_lane(int_phy, params);
5071 bnx2x_cl45_read(bp, int_phy, MDIO_WC_DEVAD,
5072 MDIO_WC_REG_GP2_STATUS_GP_2_1,
5073 &gp_status);
5074 gp_status = ((gp_status >> 8) & 0xf) |
5075 ((gp_status >> 12) & 0xf);
5076 link_up = gp_status & (1 << lane);
5077 }
5078 if (!link_up)
5079 return -ESRCH;
5080 } else {
5081 CL22_RD_OVER_CL45(bp, int_phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005082 MDIO_REG_BANK_GP_STATUS,
5083 MDIO_GP_STATUS_TOP_AN_STATUS1,
5084 &gp_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005085 /* link is up only if both local phy and external phy are up */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005086 if (!(gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS))
5087 return -ESRCH;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005088 }
5089 /* In XGXS loopback mode, do not check external PHY */
5090 if (params->loopback_mode == LOOPBACK_XGXS)
5091 return 0;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005092
5093 switch (params->num_phys) {
5094 case 1:
5095 /* No external PHY */
5096 return 0;
5097 case 2:
5098 ext_phy_link_up = params->phy[EXT_PHY1].read_status(
5099 &params->phy[EXT_PHY1],
5100 params, &temp_vars);
5101 break;
5102 case 3: /* Dual Media */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00005103 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
5104 phy_index++) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005105 serdes_phy_type = ((params->phy[phy_index].media_type ==
5106 ETH_PHY_SFP_FIBER) ||
5107 (params->phy[phy_index].media_type ==
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00005108 ETH_PHY_XFP_FIBER) ||
5109 (params->phy[phy_index].media_type ==
5110 ETH_PHY_DA_TWINAX));
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005111
5112 if (is_serdes != serdes_phy_type)
5113 continue;
5114 if (params->phy[phy_index].read_status) {
5115 ext_phy_link_up |=
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00005116 params->phy[phy_index].read_status(
5117 &params->phy[phy_index],
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005118 params, &temp_vars);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005119 }
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00005120 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005121 break;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005122 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005123 if (ext_phy_link_up)
5124 return 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005125 return -ESRCH;
5126}
5127
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005128static int bnx2x_link_initialize(struct link_params *params,
5129 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005130{
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005131 int rc = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005132 u8 phy_index, non_ext_phy;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00005133 struct bnx2x *bp = params->bp;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005134 /*
5135 * In case of external phy existence, the line speed would be the
5136 * line speed linked up by the external phy. In case it is direct
5137 * only, then the line_speed during initialization will be
5138 * equal to the req_line_speed
5139 */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00005140 vars->line_speed = params->phy[INT_PHY].req_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005141
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005142 /*
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00005143 * Initialize the internal phy in case this is a direct board
5144 * (no external phys), or this board has external phy which requires
5145 * to first.
5146 */
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005147 if (!USES_WARPCORE(bp))
5148 bnx2x_prepare_xgxs(&params->phy[INT_PHY], params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005149 /* init ext phy and enable link state int */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00005150 non_ext_phy = (SINGLE_MEDIA_DIRECT(params) ||
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005151 (params->loopback_mode == LOOPBACK_XGXS));
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005152
5153 if (non_ext_phy ||
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00005154 (params->phy[EXT_PHY1].flags & FLAGS_INIT_XGXS_FIRST) ||
Eilon Greenstein8660d8c2009-03-02 08:01:02 +00005155 (params->loopback_mode == LOOPBACK_EXT_PHY)) {
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00005156 struct bnx2x_phy *phy = &params->phy[INT_PHY];
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005157 if (vars->line_speed == SPEED_AUTO_NEG &&
5158 (CHIP_IS_E1x(bp) ||
5159 CHIP_IS_E2(bp)))
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00005160 bnx2x_set_parallel_detection(phy, params);
Yaniv Rosnerec146a62011-05-31 21:29:27 +00005161 if (params->phy[INT_PHY].config_init)
5162 params->phy[INT_PHY].config_init(phy,
5163 params,
5164 vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005165 }
5166
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00005167 /* Init external phy*/
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00005168 if (non_ext_phy) {
5169 if (params->phy[INT_PHY].supported &
5170 SUPPORTED_FIBRE)
5171 vars->link_status |= LINK_STATUS_SERDES_LINK;
5172 } else {
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005173 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
5174 phy_index++) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005175 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005176 * No need to initialize second phy in case of first
5177 * phy only selection. In case of second phy, we do
5178 * need to initialize the first phy, since they are
5179 * connected.
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005180 */
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00005181 if (params->phy[phy_index].supported &
5182 SUPPORTED_FIBRE)
5183 vars->link_status |= LINK_STATUS_SERDES_LINK;
5184
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005185 if (phy_index == EXT_PHY2 &&
5186 (bnx2x_phy_selection(params) ==
5187 PORT_HW_CFG_PHY_SELECTION_FIRST_PHY)) {
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00005188 DP(NETIF_MSG_LINK, "Not initializing"
5189 " second phy\n");
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005190 continue;
5191 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005192 params->phy[phy_index].config_init(
5193 &params->phy[phy_index],
5194 params, vars);
5195 }
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00005196 }
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00005197 /* Reset the interrupt indication after phy was initialized */
5198 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 +
5199 params->port*4,
5200 (NIG_STATUS_XGXS0_LINK10G |
5201 NIG_STATUS_XGXS0_LINK_STATUS |
5202 NIG_STATUS_SERDES0_LINK_STATUS |
5203 NIG_MASK_MI_INT));
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00005204 bnx2x_update_mng(params, vars->link_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005205 return rc;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005206}
5207
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005208static void bnx2x_int_link_reset(struct bnx2x_phy *phy,
5209 struct link_params *params)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005210{
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005211 /* reset the SerDes/XGXS */
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005212 REG_WR(params->bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
5213 (0x1ff << (params->port*16)));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005214}
5215
5216static void bnx2x_common_ext_link_reset(struct bnx2x_phy *phy,
5217 struct link_params *params)
5218{
5219 struct bnx2x *bp = params->bp;
5220 u8 gpio_port;
5221 /* HW reset */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00005222 if (CHIP_IS_E2(bp))
5223 gpio_port = BP_PATH(bp);
5224 else
5225 gpio_port = params->port;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005226 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005227 MISC_REGISTERS_GPIO_OUTPUT_LOW,
5228 gpio_port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005229 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005230 MISC_REGISTERS_GPIO_OUTPUT_LOW,
5231 gpio_port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005232 DP(NETIF_MSG_LINK, "reset external PHY\n");
5233}
5234
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005235static int bnx2x_update_link_down(struct link_params *params,
5236 struct link_vars *vars)
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005237{
5238 struct bnx2x *bp = params->bp;
5239 u8 port = params->port;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005240
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005241 DP(NETIF_MSG_LINK, "Port %x: Link is down\n", port);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005242 bnx2x_set_led(params, vars, LED_MODE_OFF, 0);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005243
5244 /* indicate no mac active */
5245 vars->mac_type = MAC_TYPE_NONE;
5246
5247 /* update shared memory */
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00005248 vars->link_status &= ~(LINK_STATUS_SPEED_AND_DUPLEX_MASK |
5249 LINK_STATUS_LINK_UP |
5250 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE |
5251 LINK_STATUS_RX_FLOW_CONTROL_FLAG_MASK |
5252 LINK_STATUS_TX_FLOW_CONTROL_FLAG_MASK |
5253 LINK_STATUS_PARALLEL_DETECTION_FLAG_MASK);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005254 vars->line_speed = 0;
5255 bnx2x_update_mng(params, vars->link_status);
5256
5257 /* activate nig drain */
5258 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
5259
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00005260 /* disable emac */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00005261 if (!CHIP_IS_E3(bp))
5262 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00005263
5264 msleep(10);
Yaniv Rosner9380bb92011-06-14 01:34:07 +00005265 /* reset BigMac/Xmac */
5266 if (CHIP_IS_E1x(bp) ||
5267 CHIP_IS_E2(bp)) {
5268 bnx2x_bmac_rx_disable(bp, params->port);
5269 REG_WR(bp, GRCBASE_MISC +
5270 MISC_REGISTERS_RESET_REG_2_CLEAR,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005271 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
Yaniv Rosner9380bb92011-06-14 01:34:07 +00005272 }
5273 if (CHIP_IS_E3(bp))
5274 bnx2x_xmac_disable(params);
5275
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005276 return 0;
5277}
5278
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005279static int bnx2x_update_link_up(struct link_params *params,
5280 struct link_vars *vars,
5281 u8 link_10g)
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005282{
5283 struct bnx2x *bp = params->bp;
5284 u8 port = params->port;
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005285 int rc = 0;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005286
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005287 vars->link_status |= LINK_STATUS_LINK_UP;
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005288
Yaniv Rosner7aa07112010-09-07 11:41:01 +00005289 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
5290 vars->link_status |=
5291 LINK_STATUS_TX_FLOW_CONTROL_ENABLED;
5292
5293 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
5294 vars->link_status |=
5295 LINK_STATUS_RX_FLOW_CONTROL_ENABLED;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00005296 if (USES_WARPCORE(bp)) {
5297 if (link_10g)
5298 bnx2x_xmac_enable(params, vars, 0);
5299 else
5300 bnx2x_umac_enable(params, vars, 0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005301 bnx2x_set_led(params, vars,
Yaniv Rosner9380bb92011-06-14 01:34:07 +00005302 LED_MODE_OPER, vars->line_speed);
5303 }
5304 if ((CHIP_IS_E1x(bp) ||
5305 CHIP_IS_E2(bp))) {
5306 if (link_10g) {
5307 bnx2x_bmac_enable(params, vars, 0);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005308
Yaniv Rosner9380bb92011-06-14 01:34:07 +00005309 bnx2x_set_led(params, vars,
5310 LED_MODE_OPER, SPEED_10000);
5311 } else {
5312 rc = bnx2x_emac_program(params, vars);
5313 bnx2x_emac_enable(params, vars, 0);
Yaniv Rosner0c786f02009-11-05 19:18:32 +02005314
Yaniv Rosner9380bb92011-06-14 01:34:07 +00005315 /* AN complete? */
5316 if ((vars->link_status &
5317 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE)
5318 && (!(vars->phy_flags & PHY_SGMII_FLAG)) &&
5319 SINGLE_MEDIA_DIRECT(params))
5320 bnx2x_set_gmii_tx_driver(params);
5321 }
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005322 }
5323
5324 /* PBF - link up */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00005325 if (CHIP_IS_E1x(bp))
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00005326 rc |= bnx2x_pbf_update(params, vars->flow_ctrl,
5327 vars->line_speed);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005328
5329 /* disable drain */
5330 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 0);
5331
5332 /* update shared memory */
5333 bnx2x_update_mng(params, vars->link_status);
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00005334 msleep(20);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005335 return rc;
5336}
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005337/*
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005338 * The bnx2x_link_update function should be called upon link
5339 * interrupt.
5340 * Link is considered up as follows:
5341 * - DIRECT_SINGLE_MEDIA - Only XGXS link (internal link) needs
5342 * to be up
5343 * - SINGLE_MEDIA - The link between the 577xx and the external
5344 * phy (XGXS) need to up as well as the external link of the
5345 * phy (PHY_EXT1)
5346 * - DUAL_MEDIA - The link between the 577xx and the first
5347 * external phy needs to be up, and at least one of the 2
5348 * external phy link must be up.
Yaniv Rosner62b29a52010-09-07 11:40:58 +00005349 */
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005350int bnx2x_link_update(struct link_params *params, struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005351{
5352 struct bnx2x *bp = params->bp;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005353 struct link_vars phy_vars[MAX_PHYS];
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005354 u8 port = params->port;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005355 u8 link_10g_plus, phy_index;
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005356 u8 ext_phy_link_up = 0, cur_link_up;
5357 int rc = 0;
Eilon Greenstein2f904462009-08-12 08:22:16 +00005358 u8 is_mi_int = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005359 u16 ext_phy_line_speed = 0, prev_line_speed = vars->line_speed;
5360 u8 active_external_phy = INT_PHY;
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00005361
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005362 for (phy_index = INT_PHY; phy_index < params->num_phys;
5363 phy_index++) {
5364 phy_vars[phy_index].flow_ctrl = 0;
5365 phy_vars[phy_index].link_status = 0;
5366 phy_vars[phy_index].line_speed = 0;
5367 phy_vars[phy_index].duplex = DUPLEX_FULL;
5368 phy_vars[phy_index].phy_link_up = 0;
5369 phy_vars[phy_index].link_up = 0;
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00005370 phy_vars[phy_index].fault_detected = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005371 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005372
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005373 if (USES_WARPCORE(bp))
5374 bnx2x_set_aer_mmd(params, &params->phy[INT_PHY]);
5375
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005376 DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n",
Eilon Greenstein2f904462009-08-12 08:22:16 +00005377 port, (vars->phy_flags & PHY_XGXS_FLAG),
5378 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005379
Eilon Greenstein2f904462009-08-12 08:22:16 +00005380 is_mi_int = (u8)(REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005381 port*0x18) > 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005382 DP(NETIF_MSG_LINK, "int_mask 0x%x MI_INT %x, SERDES_LINK %x\n",
Eilon Greenstein2f904462009-08-12 08:22:16 +00005383 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
5384 is_mi_int,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005385 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005386
5387 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
5388 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
5389 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
5390
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00005391 /* disable emac */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00005392 if (!CHIP_IS_E3(bp))
5393 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00005394
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005395 /*
5396 * Step 1:
5397 * Check external link change only for external phys, and apply
5398 * priority selection between them in case the link on both phys
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00005399 * is up. Note that instead of the common vars, a temporary
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005400 * vars argument is used since each phy may have different link/
5401 * speed/duplex result
5402 */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005403 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
5404 phy_index++) {
5405 struct bnx2x_phy *phy = &params->phy[phy_index];
5406 if (!phy->read_status)
5407 continue;
5408 /* Read link status and params of this ext phy */
5409 cur_link_up = phy->read_status(phy, params,
5410 &phy_vars[phy_index]);
5411 if (cur_link_up) {
5412 DP(NETIF_MSG_LINK, "phy in index %d link is up\n",
5413 phy_index);
5414 } else {
5415 DP(NETIF_MSG_LINK, "phy in index %d link is down\n",
5416 phy_index);
5417 continue;
5418 }
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005419
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005420 if (!ext_phy_link_up) {
5421 ext_phy_link_up = 1;
5422 active_external_phy = phy_index;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005423 } else {
5424 switch (bnx2x_phy_selection(params)) {
5425 case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT:
5426 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005427 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005428 * In this option, the first PHY makes sure to pass the
5429 * traffic through itself only.
5430 * Its not clear how to reset the link on the second phy
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005431 */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005432 active_external_phy = EXT_PHY1;
5433 break;
5434 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005435 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005436 * In this option, the first PHY makes sure to pass the
5437 * traffic through the second PHY.
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005438 */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005439 active_external_phy = EXT_PHY2;
5440 break;
5441 default:
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005442 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005443 * Link indication on both PHYs with the following cases
5444 * is invalid:
5445 * - FIRST_PHY means that second phy wasn't initialized,
5446 * hence its link is expected to be down
5447 * - SECOND_PHY means that first phy should not be able
5448 * to link up by itself (using configuration)
5449 * - DEFAULT should be overriden during initialiazation
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005450 */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005451 DP(NETIF_MSG_LINK, "Invalid link indication"
5452 "mpc=0x%x. DISABLING LINK !!!\n",
5453 params->multi_phy_config);
5454 ext_phy_link_up = 0;
5455 break;
5456 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005457 }
5458 }
5459 prev_line_speed = vars->line_speed;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005460 /*
5461 * Step 2:
5462 * Read the status of the internal phy. In case of
5463 * DIRECT_SINGLE_MEDIA board, this link is the external link,
5464 * otherwise this is the link between the 577xx and the first
5465 * external phy
5466 */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005467 if (params->phy[INT_PHY].read_status)
5468 params->phy[INT_PHY].read_status(
5469 &params->phy[INT_PHY],
5470 params, vars);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005471 /*
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005472 * The INT_PHY flow control reside in the vars. This include the
5473 * case where the speed or flow control are not set to AUTO.
5474 * Otherwise, the active external phy flow control result is set
5475 * to the vars. The ext_phy_line_speed is needed to check if the
5476 * speed is different between the internal phy and external phy.
5477 * This case may be result of intermediate link speed change.
5478 */
5479 if (active_external_phy > INT_PHY) {
5480 vars->flow_ctrl = phy_vars[active_external_phy].flow_ctrl;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005481 /*
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005482 * Link speed is taken from the XGXS. AN and FC result from
5483 * the external phy.
5484 */
5485 vars->link_status |= phy_vars[active_external_phy].link_status;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005486
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005487 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005488 * if active_external_phy is first PHY and link is up - disable
5489 * disable TX on second external PHY
5490 */
5491 if (active_external_phy == EXT_PHY1) {
5492 if (params->phy[EXT_PHY2].phy_specific_func) {
5493 DP(NETIF_MSG_LINK, "Disabling TX on"
5494 " EXT_PHY2\n");
5495 params->phy[EXT_PHY2].phy_specific_func(
5496 &params->phy[EXT_PHY2],
5497 params, DISABLE_TX);
5498 }
5499 }
5500
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005501 ext_phy_line_speed = phy_vars[active_external_phy].line_speed;
5502 vars->duplex = phy_vars[active_external_phy].duplex;
5503 if (params->phy[active_external_phy].supported &
5504 SUPPORTED_FIBRE)
5505 vars->link_status |= LINK_STATUS_SERDES_LINK;
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00005506 else
5507 vars->link_status &= ~LINK_STATUS_SERDES_LINK;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005508 DP(NETIF_MSG_LINK, "Active external phy selected: %x\n",
5509 active_external_phy);
5510 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005511
5512 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
5513 phy_index++) {
5514 if (params->phy[phy_index].flags &
5515 FLAGS_REARM_LATCH_SIGNAL) {
5516 bnx2x_rearm_latch_signal(bp, port,
5517 phy_index ==
5518 active_external_phy);
5519 break;
5520 }
5521 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005522 DP(NETIF_MSG_LINK, "vars->flow_ctrl = 0x%x, vars->link_status = 0x%x,"
5523 " ext_phy_line_speed = %d\n", vars->flow_ctrl,
5524 vars->link_status, ext_phy_line_speed);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005525 /*
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005526 * Upon link speed change set the NIG into drain mode. Comes to
5527 * deals with possible FIFO glitch due to clk change when speed
5528 * is decreased without link down indicator
5529 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005530
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005531 if (vars->phy_link_up) {
5532 if (!(SINGLE_MEDIA_DIRECT(params)) && ext_phy_link_up &&
5533 (ext_phy_line_speed != vars->line_speed)) {
5534 DP(NETIF_MSG_LINK, "Internal link speed %d is"
5535 " different than the external"
5536 " link speed %d\n", vars->line_speed,
5537 ext_phy_line_speed);
5538 vars->phy_link_up = 0;
5539 } else if (prev_line_speed != vars->line_speed) {
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005540 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4,
5541 0);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005542 msleep(1);
5543 }
5544 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005545
5546 /* anything 10 and over uses the bmac */
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005547 link_10g_plus = (vars->line_speed >= SPEED_10000);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005548
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005549 bnx2x_link_int_ack(params, vars, link_10g_plus);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005550
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005551 /*
5552 * In case external phy link is up, and internal link is down
5553 * (not initialized yet probably after link initialization, it
5554 * needs to be initialized.
5555 * Note that after link down-up as result of cable plug, the xgxs
5556 * link would probably become up again without the need
5557 * initialize it
5558 */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005559 if (!(SINGLE_MEDIA_DIRECT(params))) {
5560 DP(NETIF_MSG_LINK, "ext_phy_link_up = %d, int_link_up = %d,"
5561 " init_preceding = %d\n", ext_phy_link_up,
5562 vars->phy_link_up,
5563 params->phy[EXT_PHY1].flags &
5564 FLAGS_INIT_XGXS_FIRST);
5565 if (!(params->phy[EXT_PHY1].flags &
5566 FLAGS_INIT_XGXS_FIRST)
5567 && ext_phy_link_up && !vars->phy_link_up) {
5568 vars->line_speed = ext_phy_line_speed;
5569 if (vars->line_speed < SPEED_1000)
5570 vars->phy_flags |= PHY_SGMII_FLAG;
5571 else
5572 vars->phy_flags &= ~PHY_SGMII_FLAG;
Yaniv Rosnerec146a62011-05-31 21:29:27 +00005573
5574 if (params->phy[INT_PHY].config_init)
5575 params->phy[INT_PHY].config_init(
5576 &params->phy[INT_PHY], params,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005577 vars);
5578 }
5579 }
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005580 /*
5581 * Link is up only if both local phy and external phy (in case of
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00005582 * non-direct board) are up and no fault detected on active PHY.
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005583 */
5584 vars->link_up = (vars->phy_link_up &&
5585 (ext_phy_link_up ||
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00005586 SINGLE_MEDIA_DIRECT(params)) &&
5587 (phy_vars[active_external_phy].fault_detected == 0));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005588
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005589 if (vars->link_up)
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005590 rc = bnx2x_update_link_up(params, vars, link_10g_plus);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005591 else
5592 rc = bnx2x_update_link_down(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005593
5594 return rc;
5595}
5596
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005597
5598/*****************************************************************************/
5599/* External Phy section */
5600/*****************************************************************************/
5601void bnx2x_ext_phy_hw_reset(struct bnx2x *bp, u8 port)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005602{
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005603 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005604 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005605 msleep(1);
5606 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005607 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005608}
5609
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005610static void bnx2x_save_spirom_version(struct bnx2x *bp, u8 port,
5611 u32 spirom_ver, u32 ver_addr)
5612{
5613 DP(NETIF_MSG_LINK, "FW version 0x%x:0x%x for port %d\n",
5614 (u16)(spirom_ver>>16), (u16)spirom_ver, port);
5615
5616 if (ver_addr)
5617 REG_WR(bp, ver_addr, spirom_ver);
5618}
5619
5620static void bnx2x_save_bcm_spirom_ver(struct bnx2x *bp,
5621 struct bnx2x_phy *phy,
5622 u8 port)
5623{
5624 u16 fw_ver1, fw_ver2;
5625
5626 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005627 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005628 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005629 MDIO_PMA_REG_ROM_VER2, &fw_ver2);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005630 bnx2x_save_spirom_version(bp, port, (u32)(fw_ver1<<16 | fw_ver2),
5631 phy->ver_addr);
5632}
5633
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005634static void bnx2x_ext_phy_10G_an_resolve(struct bnx2x *bp,
5635 struct bnx2x_phy *phy,
5636 struct link_vars *vars)
5637{
5638 u16 val;
5639 bnx2x_cl45_read(bp, phy,
5640 MDIO_AN_DEVAD,
5641 MDIO_AN_REG_STATUS, &val);
5642 bnx2x_cl45_read(bp, phy,
5643 MDIO_AN_DEVAD,
5644 MDIO_AN_REG_STATUS, &val);
5645 if (val & (1<<5))
5646 vars->link_status |= LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
5647 if ((val & (1<<0)) == 0)
5648 vars->link_status |= LINK_STATUS_PARALLEL_DETECTION_USED;
5649}
5650
5651/******************************************************************/
5652/* common BCM8073/BCM8727 PHY SECTION */
5653/******************************************************************/
5654static void bnx2x_8073_resolve_fc(struct bnx2x_phy *phy,
5655 struct link_params *params,
5656 struct link_vars *vars)
5657{
5658 struct bnx2x *bp = params->bp;
5659 if (phy->req_line_speed == SPEED_10 ||
5660 phy->req_line_speed == SPEED_100) {
5661 vars->flow_ctrl = phy->req_flow_ctrl;
5662 return;
5663 }
5664
5665 if (bnx2x_ext_phy_resolve_fc(phy, params, vars) &&
5666 (vars->flow_ctrl == BNX2X_FLOW_CTRL_NONE)) {
5667 u16 pause_result;
5668 u16 ld_pause; /* local */
5669 u16 lp_pause; /* link partner */
5670 bnx2x_cl45_read(bp, phy,
5671 MDIO_AN_DEVAD,
5672 MDIO_AN_REG_CL37_FC_LD, &ld_pause);
5673
5674 bnx2x_cl45_read(bp, phy,
5675 MDIO_AN_DEVAD,
5676 MDIO_AN_REG_CL37_FC_LP, &lp_pause);
5677 pause_result = (ld_pause &
5678 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 5;
5679 pause_result |= (lp_pause &
5680 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 7;
5681
5682 bnx2x_pause_resolve(vars, pause_result);
5683 DP(NETIF_MSG_LINK, "Ext PHY CL37 pause result 0x%x\n",
5684 pause_result);
5685 }
5686}
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005687static int bnx2x_8073_8727_external_rom_boot(struct bnx2x *bp,
5688 struct bnx2x_phy *phy,
5689 u8 port)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005690{
Yaniv Rosner5c99274b2011-01-18 04:33:36 +00005691 u32 count = 0;
5692 u16 fw_ver1, fw_msgout;
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005693 int rc = 0;
Yaniv Rosner5c99274b2011-01-18 04:33:36 +00005694
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005695 /* Boot port from external ROM */
5696 /* EDC grst */
5697 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005698 MDIO_PMA_DEVAD,
5699 MDIO_PMA_REG_GEN_CTRL,
5700 0x0001);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005701
5702 /* ucode reboot and rst */
5703 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005704 MDIO_PMA_DEVAD,
5705 MDIO_PMA_REG_GEN_CTRL,
5706 0x008c);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005707
5708 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005709 MDIO_PMA_DEVAD,
5710 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005711
5712 /* Reset internal microprocessor */
5713 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005714 MDIO_PMA_DEVAD,
5715 MDIO_PMA_REG_GEN_CTRL,
5716 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005717
5718 /* Release srst bit */
5719 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005720 MDIO_PMA_DEVAD,
5721 MDIO_PMA_REG_GEN_CTRL,
5722 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005723
Yaniv Rosner5c99274b2011-01-18 04:33:36 +00005724 /* Delay 100ms per the PHY specifications */
5725 msleep(100);
5726
5727 /* 8073 sometimes taking longer to download */
5728 do {
5729 count++;
5730 if (count > 300) {
5731 DP(NETIF_MSG_LINK,
5732 "bnx2x_8073_8727_external_rom_boot port %x:"
5733 "Download failed. fw version = 0x%x\n",
5734 port, fw_ver1);
5735 rc = -EINVAL;
5736 break;
5737 }
5738
5739 bnx2x_cl45_read(bp, phy,
5740 MDIO_PMA_DEVAD,
5741 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
5742 bnx2x_cl45_read(bp, phy,
5743 MDIO_PMA_DEVAD,
5744 MDIO_PMA_REG_M8051_MSGOUT_REG, &fw_msgout);
5745
5746 msleep(1);
5747 } while (fw_ver1 == 0 || fw_ver1 == 0x4321 ||
5748 ((fw_msgout & 0xff) != 0x03 && (phy->type ==
5749 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073)));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005750
5751 /* Clear ser_boot_ctl bit */
5752 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005753 MDIO_PMA_DEVAD,
5754 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005755 bnx2x_save_bcm_spirom_ver(bp, phy, port);
Yaniv Rosner5c99274b2011-01-18 04:33:36 +00005756
5757 DP(NETIF_MSG_LINK,
5758 "bnx2x_8073_8727_external_rom_boot port %x:"
5759 "Download complete. fw version = 0x%x\n",
5760 port, fw_ver1);
5761
5762 return rc;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005763}
5764
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005765/******************************************************************/
5766/* BCM8073 PHY SECTION */
5767/******************************************************************/
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005768static int bnx2x_8073_is_snr_needed(struct bnx2x *bp, struct bnx2x_phy *phy)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005769{
5770 /* This is only required for 8073A1, version 102 only */
5771 u16 val;
5772
5773 /* Read 8073 HW revision*/
5774 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005775 MDIO_PMA_DEVAD,
5776 MDIO_PMA_REG_8073_CHIP_REV, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005777
5778 if (val != 1) {
5779 /* No need to workaround in 8073 A1 */
5780 return 0;
5781 }
5782
5783 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005784 MDIO_PMA_DEVAD,
5785 MDIO_PMA_REG_ROM_VER2, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005786
5787 /* SNR should be applied only for version 0x102 */
5788 if (val != 0x102)
5789 return 0;
5790
5791 return 1;
5792}
5793
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005794static int bnx2x_8073_xaui_wa(struct bnx2x *bp, struct bnx2x_phy *phy)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005795{
5796 u16 val, cnt, cnt1 ;
5797
5798 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005799 MDIO_PMA_DEVAD,
5800 MDIO_PMA_REG_8073_CHIP_REV, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005801
5802 if (val > 0) {
5803 /* No need to workaround in 8073 A1 */
5804 return 0;
5805 }
5806 /* XAUI workaround in 8073 A0: */
5807
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005808 /*
5809 * After loading the boot ROM and restarting Autoneg, poll
5810 * Dev1, Reg $C820:
5811 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005812
5813 for (cnt = 0; cnt < 1000; cnt++) {
5814 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005815 MDIO_PMA_DEVAD,
5816 MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
5817 &val);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005818 /*
5819 * If bit [14] = 0 or bit [13] = 0, continue on with
5820 * system initialization (XAUI work-around not required, as
5821 * these bits indicate 2.5G or 1G link up).
5822 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005823 if (!(val & (1<<14)) || !(val & (1<<13))) {
5824 DP(NETIF_MSG_LINK, "XAUI work-around not required\n");
5825 return 0;
5826 } else if (!(val & (1<<15))) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005827 DP(NETIF_MSG_LINK, "bit 15 went off\n");
5828 /*
5829 * If bit 15 is 0, then poll Dev1, Reg $C841 until it's
5830 * MSB (bit15) goes to 1 (indicating that the XAUI
5831 * workaround has completed), then continue on with
5832 * system initialization.
5833 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005834 for (cnt1 = 0; cnt1 < 1000; cnt1++) {
5835 bnx2x_cl45_read(bp, phy,
5836 MDIO_PMA_DEVAD,
5837 MDIO_PMA_REG_8073_XAUI_WA, &val);
5838 if (val & (1<<15)) {
5839 DP(NETIF_MSG_LINK,
5840 "XAUI workaround has completed\n");
5841 return 0;
5842 }
5843 msleep(3);
5844 }
5845 break;
5846 }
5847 msleep(3);
5848 }
5849 DP(NETIF_MSG_LINK, "Warning: XAUI work-around timeout !!!\n");
5850 return -EINVAL;
5851}
5852
5853static void bnx2x_807x_force_10G(struct bnx2x *bp, struct bnx2x_phy *phy)
5854{
5855 /* Force KR or KX */
5856 bnx2x_cl45_write(bp, phy,
5857 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x2040);
5858 bnx2x_cl45_write(bp, phy,
5859 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0x000b);
5860 bnx2x_cl45_write(bp, phy,
5861 MDIO_PMA_DEVAD, MDIO_PMA_REG_BCM_CTRL, 0x0000);
5862 bnx2x_cl45_write(bp, phy,
5863 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x0000);
5864}
5865
5866static void bnx2x_8073_set_pause_cl37(struct link_params *params,
5867 struct bnx2x_phy *phy,
5868 struct link_vars *vars)
5869{
5870 u16 cl37_val;
5871 struct bnx2x *bp = params->bp;
5872 bnx2x_cl45_read(bp, phy,
5873 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, &cl37_val);
5874
5875 cl37_val &= ~MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
5876 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
5877 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
5878 if ((vars->ieee_fc &
5879 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) ==
5880 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) {
5881 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC;
5882 }
5883 if ((vars->ieee_fc &
5884 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
5885 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
5886 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
5887 }
5888 if ((vars->ieee_fc &
5889 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
5890 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
5891 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
5892 }
5893 DP(NETIF_MSG_LINK,
5894 "Ext phy AN advertize cl37 0x%x\n", cl37_val);
5895
5896 bnx2x_cl45_write(bp, phy,
5897 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, cl37_val);
5898 msleep(500);
5899}
5900
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005901static int bnx2x_8073_config_init(struct bnx2x_phy *phy,
5902 struct link_params *params,
5903 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005904{
5905 struct bnx2x *bp = params->bp;
5906 u16 val = 0, tmp1;
5907 u8 gpio_port;
5908 DP(NETIF_MSG_LINK, "Init 8073\n");
5909
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00005910 if (CHIP_IS_E2(bp))
5911 gpio_port = BP_PATH(bp);
5912 else
5913 gpio_port = params->port;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005914 /* Restore normal power mode*/
5915 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005916 MISC_REGISTERS_GPIO_OUTPUT_HIGH, gpio_port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005917
5918 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005919 MISC_REGISTERS_GPIO_OUTPUT_HIGH, gpio_port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005920
5921 /* enable LASI */
5922 bnx2x_cl45_write(bp, phy,
5923 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL, (1<<2));
5924 bnx2x_cl45_write(bp, phy,
5925 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x0004);
5926
5927 bnx2x_8073_set_pause_cl37(params, phy, vars);
5928
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005929 bnx2x_cl45_read(bp, phy,
5930 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &tmp1);
5931
5932 bnx2x_cl45_read(bp, phy,
5933 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &tmp1);
5934
5935 DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1): 0x%x\n", tmp1);
5936
Yaniv Rosner74d7a112011-01-18 04:33:18 +00005937 /* Swap polarity if required - Must be done only in non-1G mode */
5938 if (params->lane_config & PORT_HW_CFG_SWAP_PHY_POLARITY_ENABLED) {
5939 /* Configure the 8073 to swap _P and _N of the KR lines */
5940 DP(NETIF_MSG_LINK, "Swapping polarity for the 8073\n");
5941 /* 10G Rx/Tx and 1G Tx signal polarity swap */
5942 bnx2x_cl45_read(bp, phy,
5943 MDIO_PMA_DEVAD,
5944 MDIO_PMA_REG_8073_OPT_DIGITAL_CTRL, &val);
5945 bnx2x_cl45_write(bp, phy,
5946 MDIO_PMA_DEVAD,
5947 MDIO_PMA_REG_8073_OPT_DIGITAL_CTRL,
5948 (val | (3<<9)));
5949 }
5950
5951
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005952 /* Enable CL37 BAM */
Yaniv Rosner121839b2010-11-01 05:32:38 +00005953 if (REG_RD(bp, params->shmem_base +
5954 offsetof(struct shmem_region, dev_info.
5955 port_hw_config[params->port].default_cfg)) &
5956 PORT_HW_CFG_ENABLE_BAM_ON_KR_ENABLED) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005957
Yaniv Rosner121839b2010-11-01 05:32:38 +00005958 bnx2x_cl45_read(bp, phy,
5959 MDIO_AN_DEVAD,
5960 MDIO_AN_REG_8073_BAM, &val);
5961 bnx2x_cl45_write(bp, phy,
5962 MDIO_AN_DEVAD,
5963 MDIO_AN_REG_8073_BAM, val | 1);
5964 DP(NETIF_MSG_LINK, "Enable CL37 BAM on KR\n");
5965 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005966 if (params->loopback_mode == LOOPBACK_EXT) {
5967 bnx2x_807x_force_10G(bp, phy);
5968 DP(NETIF_MSG_LINK, "Forced speed 10G on 807X\n");
5969 return 0;
5970 } else {
5971 bnx2x_cl45_write(bp, phy,
5972 MDIO_PMA_DEVAD, MDIO_PMA_REG_BCM_CTRL, 0x0002);
5973 }
5974 if (phy->req_line_speed != SPEED_AUTO_NEG) {
5975 if (phy->req_line_speed == SPEED_10000) {
5976 val = (1<<7);
5977 } else if (phy->req_line_speed == SPEED_2500) {
5978 val = (1<<5);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005979 /*
5980 * Note that 2.5G works only when used with 1G
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005981 * advertisement
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005982 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005983 } else
5984 val = (1<<5);
5985 } else {
5986 val = 0;
5987 if (phy->speed_cap_mask &
5988 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
5989 val |= (1<<7);
5990
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005991 /* Note that 2.5G works only when used with 1G advertisement */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005992 if (phy->speed_cap_mask &
5993 (PORT_HW_CFG_SPEED_CAPABILITY_D0_1G |
5994 PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G))
5995 val |= (1<<5);
5996 DP(NETIF_MSG_LINK, "807x autoneg val = 0x%x\n", val);
5997 }
5998
5999 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV, val);
6000 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_8073_2_5G, &tmp1);
6001
6002 if (((phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G) &&
6003 (phy->req_line_speed == SPEED_AUTO_NEG)) ||
6004 (phy->req_line_speed == SPEED_2500)) {
6005 u16 phy_ver;
6006 /* Allow 2.5G for A1 and above */
6007 bnx2x_cl45_read(bp, phy,
6008 MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_CHIP_REV,
6009 &phy_ver);
6010 DP(NETIF_MSG_LINK, "Add 2.5G\n");
6011 if (phy_ver > 0)
6012 tmp1 |= 1;
6013 else
6014 tmp1 &= 0xfffe;
6015 } else {
6016 DP(NETIF_MSG_LINK, "Disable 2.5G\n");
6017 tmp1 &= 0xfffe;
6018 }
6019
6020 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_8073_2_5G, tmp1);
6021 /* Add support for CL37 (passive mode) II */
6022
6023 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, &tmp1);
6024 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD,
6025 (tmp1 | ((phy->req_duplex == DUPLEX_FULL) ?
6026 0x20 : 0x40)));
6027
6028 /* Add support for CL37 (passive mode) III */
6029 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
6030
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006031 /*
6032 * The SNR will improve about 2db by changing BW and FEE main
6033 * tap. Rest commands are executed after link is up
6034 * Change FFE main cursor to 5 in EDC register
6035 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006036 if (bnx2x_8073_is_snr_needed(bp, phy))
6037 bnx2x_cl45_write(bp, phy,
6038 MDIO_PMA_DEVAD, MDIO_PMA_REG_EDC_FFE_MAIN,
6039 0xFB0C);
6040
6041 /* Enable FEC (Forware Error Correction) Request in the AN */
6042 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV2, &tmp1);
6043 tmp1 |= (1<<15);
6044 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV2, tmp1);
6045
6046 bnx2x_ext_phy_set_pause(params, phy, vars);
6047
6048 /* Restart autoneg */
6049 msleep(500);
6050 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
6051 DP(NETIF_MSG_LINK, "807x Autoneg Restart: Advertise 1G=%x, 10G=%x\n",
6052 ((val & (1<<5)) > 0), ((val & (1<<7)) > 0));
6053 return 0;
6054}
6055
6056static u8 bnx2x_8073_read_status(struct bnx2x_phy *phy,
6057 struct link_params *params,
6058 struct link_vars *vars)
6059{
6060 struct bnx2x *bp = params->bp;
6061 u8 link_up = 0;
6062 u16 val1, val2;
6063 u16 link_status = 0;
6064 u16 an1000_status = 0;
6065
6066 bnx2x_cl45_read(bp, phy,
6067 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
6068
6069 DP(NETIF_MSG_LINK, "8703 LASI status 0x%x\n", val1);
6070
6071 /* clear the interrupt LASI status register */
6072 bnx2x_cl45_read(bp, phy,
6073 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val2);
6074 bnx2x_cl45_read(bp, phy,
6075 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val1);
6076 DP(NETIF_MSG_LINK, "807x PCS status 0x%x->0x%x\n", val2, val1);
6077 /* Clear MSG-OUT */
6078 bnx2x_cl45_read(bp, phy,
6079 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &val1);
6080
6081 /* Check the LASI */
6082 bnx2x_cl45_read(bp, phy,
6083 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &val2);
6084
6085 DP(NETIF_MSG_LINK, "KR 0x9003 0x%x\n", val2);
6086
6087 /* Check the link status */
6088 bnx2x_cl45_read(bp, phy,
6089 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val2);
6090 DP(NETIF_MSG_LINK, "KR PCS status 0x%x\n", val2);
6091
6092 bnx2x_cl45_read(bp, phy,
6093 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
6094 bnx2x_cl45_read(bp, phy,
6095 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
6096 link_up = ((val1 & 4) == 4);
6097 DP(NETIF_MSG_LINK, "PMA_REG_STATUS=0x%x\n", val1);
6098
6099 if (link_up &&
6100 ((phy->req_line_speed != SPEED_10000))) {
6101 if (bnx2x_8073_xaui_wa(bp, phy) != 0)
6102 return 0;
6103 }
6104 bnx2x_cl45_read(bp, phy,
6105 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &an1000_status);
6106 bnx2x_cl45_read(bp, phy,
6107 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &an1000_status);
6108
6109 /* Check the link status on 1.1.2 */
6110 bnx2x_cl45_read(bp, phy,
6111 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
6112 bnx2x_cl45_read(bp, phy,
6113 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
6114 DP(NETIF_MSG_LINK, "KR PMA status 0x%x->0x%x,"
6115 "an_link_status=0x%x\n", val2, val1, an1000_status);
6116
6117 link_up = (((val1 & 4) == 4) || (an1000_status & (1<<1)));
6118 if (link_up && bnx2x_8073_is_snr_needed(bp, phy)) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006119 /*
6120 * The SNR will improve about 2dbby changing the BW and FEE main
6121 * tap. The 1st write to change FFE main tap is set before
6122 * restart AN. Change PLL Bandwidth in EDC register
6123 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006124 bnx2x_cl45_write(bp, phy,
6125 MDIO_PMA_DEVAD, MDIO_PMA_REG_PLL_BANDWIDTH,
6126 0x26BC);
6127
6128 /* Change CDR Bandwidth in EDC register */
6129 bnx2x_cl45_write(bp, phy,
6130 MDIO_PMA_DEVAD, MDIO_PMA_REG_CDR_BANDWIDTH,
6131 0x0333);
6132 }
6133 bnx2x_cl45_read(bp, phy,
6134 MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
6135 &link_status);
6136
6137 /* Bits 0..2 --> speed detected, bits 13..15--> link is down */
6138 if ((link_status & (1<<2)) && (!(link_status & (1<<15)))) {
6139 link_up = 1;
6140 vars->line_speed = SPEED_10000;
6141 DP(NETIF_MSG_LINK, "port %x: External link up in 10G\n",
6142 params->port);
6143 } else if ((link_status & (1<<1)) && (!(link_status & (1<<14)))) {
6144 link_up = 1;
6145 vars->line_speed = SPEED_2500;
6146 DP(NETIF_MSG_LINK, "port %x: External link up in 2.5G\n",
6147 params->port);
6148 } else if ((link_status & (1<<0)) && (!(link_status & (1<<13)))) {
6149 link_up = 1;
6150 vars->line_speed = SPEED_1000;
6151 DP(NETIF_MSG_LINK, "port %x: External link up in 1G\n",
6152 params->port);
6153 } else {
6154 link_up = 0;
6155 DP(NETIF_MSG_LINK, "port %x: External link is down\n",
6156 params->port);
6157 }
6158
6159 if (link_up) {
Yaniv Rosner74d7a112011-01-18 04:33:18 +00006160 /* Swap polarity if required */
6161 if (params->lane_config &
6162 PORT_HW_CFG_SWAP_PHY_POLARITY_ENABLED) {
6163 /* Configure the 8073 to swap P and N of the KR lines */
6164 bnx2x_cl45_read(bp, phy,
6165 MDIO_XS_DEVAD,
6166 MDIO_XS_REG_8073_RX_CTRL_PCIE, &val1);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006167 /*
6168 * Set bit 3 to invert Rx in 1G mode and clear this bit
6169 * when it`s in 10G mode.
6170 */
Yaniv Rosner74d7a112011-01-18 04:33:18 +00006171 if (vars->line_speed == SPEED_1000) {
6172 DP(NETIF_MSG_LINK, "Swapping 1G polarity for"
6173 "the 8073\n");
6174 val1 |= (1<<3);
6175 } else
6176 val1 &= ~(1<<3);
6177
6178 bnx2x_cl45_write(bp, phy,
6179 MDIO_XS_DEVAD,
6180 MDIO_XS_REG_8073_RX_CTRL_PCIE,
6181 val1);
6182 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006183 bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
6184 bnx2x_8073_resolve_fc(phy, params, vars);
Yaniv Rosner791f18c2011-01-18 04:33:42 +00006185 vars->duplex = DUPLEX_FULL;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006186 }
6187 return link_up;
6188}
6189
6190static void bnx2x_8073_link_reset(struct bnx2x_phy *phy,
6191 struct link_params *params)
6192{
6193 struct bnx2x *bp = params->bp;
6194 u8 gpio_port;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00006195 if (CHIP_IS_E2(bp))
6196 gpio_port = BP_PATH(bp);
6197 else
6198 gpio_port = params->port;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006199 DP(NETIF_MSG_LINK, "Setting 8073 port %d into low power mode\n",
6200 gpio_port);
6201 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006202 MISC_REGISTERS_GPIO_OUTPUT_LOW,
6203 gpio_port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006204}
6205
6206/******************************************************************/
6207/* BCM8705 PHY SECTION */
6208/******************************************************************/
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006209static int bnx2x_8705_config_init(struct bnx2x_phy *phy,
6210 struct link_params *params,
6211 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006212{
6213 struct bnx2x *bp = params->bp;
6214 DP(NETIF_MSG_LINK, "init 8705\n");
6215 /* Restore normal power mode*/
6216 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006217 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006218 /* HW reset */
6219 bnx2x_ext_phy_hw_reset(bp, params->port);
6220 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0xa040);
Yaniv Rosner6d870c32011-01-31 04:22:20 +00006221 bnx2x_wait_reset_complete(bp, phy, params);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006222
6223 bnx2x_cl45_write(bp, phy,
6224 MDIO_PMA_DEVAD, MDIO_PMA_REG_MISC_CTRL, 0x8288);
6225 bnx2x_cl45_write(bp, phy,
6226 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, 0x7fbf);
6227 bnx2x_cl45_write(bp, phy,
6228 MDIO_PMA_DEVAD, MDIO_PMA_REG_CMU_PLL_BYPASS, 0x0100);
6229 bnx2x_cl45_write(bp, phy,
6230 MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_CNTL, 0x1);
6231 /* BCM8705 doesn't have microcode, hence the 0 */
6232 bnx2x_save_spirom_version(bp, params->port, params->shmem_base, 0);
6233 return 0;
6234}
6235
6236static u8 bnx2x_8705_read_status(struct bnx2x_phy *phy,
6237 struct link_params *params,
6238 struct link_vars *vars)
6239{
6240 u8 link_up = 0;
6241 u16 val1, rx_sd;
6242 struct bnx2x *bp = params->bp;
6243 DP(NETIF_MSG_LINK, "read status 8705\n");
6244 bnx2x_cl45_read(bp, phy,
6245 MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_STATUS, &val1);
6246 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
6247
6248 bnx2x_cl45_read(bp, phy,
6249 MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_STATUS, &val1);
6250 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
6251
6252 bnx2x_cl45_read(bp, phy,
6253 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD, &rx_sd);
6254
6255 bnx2x_cl45_read(bp, phy,
6256 MDIO_PMA_DEVAD, 0xc809, &val1);
6257 bnx2x_cl45_read(bp, phy,
6258 MDIO_PMA_DEVAD, 0xc809, &val1);
6259
6260 DP(NETIF_MSG_LINK, "8705 1.c809 val=0x%x\n", val1);
6261 link_up = ((rx_sd & 0x1) && (val1 & (1<<9)) && ((val1 & (1<<8)) == 0));
6262 if (link_up) {
6263 vars->line_speed = SPEED_10000;
6264 bnx2x_ext_phy_resolve_fc(phy, params, vars);
6265 }
6266 return link_up;
6267}
6268
6269/******************************************************************/
6270/* SFP+ module Section */
6271/******************************************************************/
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00006272static u8 bnx2x_get_gpio_port(struct link_params *params)
6273{
6274 u8 gpio_port;
6275 u32 swap_val, swap_override;
6276 struct bnx2x *bp = params->bp;
6277 if (CHIP_IS_E2(bp))
6278 gpio_port = BP_PATH(bp);
6279 else
6280 gpio_port = params->port;
6281 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
6282 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
6283 return gpio_port ^ (swap_val && swap_override);
6284}
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00006285
6286static void bnx2x_sfp_e1e2_set_transmitter(struct link_params *params,
6287 struct bnx2x_phy *phy,
6288 u8 tx_en)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006289{
6290 u16 val;
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00006291 u8 port = params->port;
6292 struct bnx2x *bp = params->bp;
6293 u32 tx_en_mode;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006294
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006295 /* Disable/Enable transmitter ( TX laser of the SFP+ module.)*/
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00006296 tx_en_mode = REG_RD(bp, params->shmem_base +
6297 offsetof(struct shmem_region,
6298 dev_info.port_hw_config[port].sfp_ctrl)) &
6299 PORT_HW_CFG_TX_LASER_MASK;
6300 DP(NETIF_MSG_LINK, "Setting transmitter tx_en=%x for port %x "
6301 "mode = %x\n", tx_en, port, tx_en_mode);
6302 switch (tx_en_mode) {
6303 case PORT_HW_CFG_TX_LASER_MDIO:
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006304
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00006305 bnx2x_cl45_read(bp, phy,
6306 MDIO_PMA_DEVAD,
6307 MDIO_PMA_REG_PHY_IDENTIFIER,
6308 &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006309
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00006310 if (tx_en)
6311 val &= ~(1<<15);
6312 else
6313 val |= (1<<15);
6314
6315 bnx2x_cl45_write(bp, phy,
6316 MDIO_PMA_DEVAD,
6317 MDIO_PMA_REG_PHY_IDENTIFIER,
6318 val);
6319 break;
6320 case PORT_HW_CFG_TX_LASER_GPIO0:
6321 case PORT_HW_CFG_TX_LASER_GPIO1:
6322 case PORT_HW_CFG_TX_LASER_GPIO2:
6323 case PORT_HW_CFG_TX_LASER_GPIO3:
6324 {
6325 u16 gpio_pin;
6326 u8 gpio_port, gpio_mode;
6327 if (tx_en)
6328 gpio_mode = MISC_REGISTERS_GPIO_OUTPUT_HIGH;
6329 else
6330 gpio_mode = MISC_REGISTERS_GPIO_OUTPUT_LOW;
6331
6332 gpio_pin = tx_en_mode - PORT_HW_CFG_TX_LASER_GPIO0;
6333 gpio_port = bnx2x_get_gpio_port(params);
6334 bnx2x_set_gpio(bp, gpio_pin, gpio_mode, gpio_port);
6335 break;
6336 }
6337 default:
6338 DP(NETIF_MSG_LINK, "Invalid TX_LASER_MDIO 0x%x\n", tx_en_mode);
6339 break;
6340 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006341}
6342
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00006343static void bnx2x_sfp_set_transmitter(struct link_params *params,
6344 struct bnx2x_phy *phy,
6345 u8 tx_en)
6346{
6347 struct bnx2x *bp = params->bp;
6348 DP(NETIF_MSG_LINK, "Setting SFP+ transmitter to %d\n", tx_en);
6349 if (CHIP_IS_E3(bp))
6350 bnx2x_sfp_e3_set_transmitter(params, phy, tx_en);
6351 else
6352 bnx2x_sfp_e1e2_set_transmitter(params, phy, tx_en);
6353}
6354
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006355static int bnx2x_8726_read_sfp_module_eeprom(struct bnx2x_phy *phy,
6356 struct link_params *params,
6357 u16 addr, u8 byte_cnt, u8 *o_buf)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006358{
6359 struct bnx2x *bp = params->bp;
6360 u16 val = 0;
6361 u16 i;
6362 if (byte_cnt > 16) {
6363 DP(NETIF_MSG_LINK, "Reading from eeprom is"
6364 " is limited to 0xf\n");
6365 return -EINVAL;
6366 }
6367 /* Set the read command byte count */
6368 bnx2x_cl45_write(bp, phy,
6369 MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006370 (byte_cnt | 0xa000));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006371
6372 /* Set the read command address */
6373 bnx2x_cl45_write(bp, phy,
6374 MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006375 addr);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006376
6377 /* Activate read command */
6378 bnx2x_cl45_write(bp, phy,
6379 MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006380 0x2c0f);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006381
6382 /* Wait up to 500us for command complete status */
6383 for (i = 0; i < 100; i++) {
6384 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006385 MDIO_PMA_DEVAD,
6386 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006387 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
6388 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
6389 break;
6390 udelay(5);
6391 }
6392
6393 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
6394 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
6395 DP(NETIF_MSG_LINK,
6396 "Got bad status 0x%x when reading from SFP+ EEPROM\n",
6397 (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
6398 return -EINVAL;
6399 }
6400
6401 /* Read the buffer */
6402 for (i = 0; i < byte_cnt; i++) {
6403 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006404 MDIO_PMA_DEVAD,
6405 MDIO_PMA_REG_8726_TWO_WIRE_DATA_BUF + i, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006406 o_buf[i] = (u8)(val & MDIO_PMA_REG_8726_TWO_WIRE_DATA_MASK);
6407 }
6408
6409 for (i = 0; i < 100; i++) {
6410 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006411 MDIO_PMA_DEVAD,
6412 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006413 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
6414 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
Joe Perches6f38ad92010-11-14 17:04:31 +00006415 return 0;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006416 msleep(1);
6417 }
6418 return -EINVAL;
6419}
6420
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00006421static int bnx2x_warpcore_read_sfp_module_eeprom(struct bnx2x_phy *phy,
6422 struct link_params *params,
6423 u16 addr, u8 byte_cnt,
6424 u8 *o_buf)
6425{
6426 int rc = 0;
6427 u8 i, j = 0, cnt = 0;
6428 u32 data_array[4];
6429 u16 addr32;
6430 struct bnx2x *bp = params->bp;
6431 /*DP(NETIF_MSG_LINK, "bnx2x_direct_read_sfp_module_eeprom:"
6432 " addr %d, cnt %d\n",
6433 addr, byte_cnt);*/
6434 if (byte_cnt > 16) {
6435 DP(NETIF_MSG_LINK, "Reading from eeprom is"
6436 " is limited to 16 bytes\n");
6437 return -EINVAL;
6438 }
6439
6440 /* 4 byte aligned address */
6441 addr32 = addr & (~0x3);
6442 do {
6443 rc = bnx2x_bsc_read(params, phy, 0xa0, addr32, 0, byte_cnt,
6444 data_array);
6445 } while ((rc != 0) && (++cnt < I2C_WA_RETRY_CNT));
6446
6447 if (rc == 0) {
6448 for (i = (addr - addr32); i < byte_cnt + (addr - addr32); i++) {
6449 o_buf[j] = *((u8 *)data_array + i);
6450 j++;
6451 }
6452 }
6453
6454 return rc;
6455}
6456
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006457static int bnx2x_8727_read_sfp_module_eeprom(struct bnx2x_phy *phy,
6458 struct link_params *params,
6459 u16 addr, u8 byte_cnt, u8 *o_buf)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006460{
6461 struct bnx2x *bp = params->bp;
6462 u16 val, i;
6463
6464 if (byte_cnt > 16) {
6465 DP(NETIF_MSG_LINK, "Reading from eeprom is"
6466 " is limited to 0xf\n");
6467 return -EINVAL;
6468 }
6469
6470 /* Need to read from 1.8000 to clear it */
6471 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006472 MDIO_PMA_DEVAD,
6473 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
6474 &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006475
6476 /* Set the read command byte count */
6477 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006478 MDIO_PMA_DEVAD,
6479 MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
6480 ((byte_cnt < 2) ? 2 : byte_cnt));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006481
6482 /* Set the read command address */
6483 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006484 MDIO_PMA_DEVAD,
6485 MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
6486 addr);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006487 /* Set the destination address */
6488 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006489 MDIO_PMA_DEVAD,
6490 0x8004,
6491 MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006492
6493 /* Activate read command */
6494 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006495 MDIO_PMA_DEVAD,
6496 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
6497 0x8002);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006498 /*
6499 * Wait appropriate time for two-wire command to finish before
6500 * polling the status register
6501 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006502 msleep(1);
6503
6504 /* Wait up to 500us for command complete status */
6505 for (i = 0; i < 100; i++) {
6506 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006507 MDIO_PMA_DEVAD,
6508 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006509 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
6510 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
6511 break;
6512 udelay(5);
6513 }
6514
6515 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
6516 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
6517 DP(NETIF_MSG_LINK,
6518 "Got bad status 0x%x when reading from SFP+ EEPROM\n",
6519 (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
Yaniv Rosner65a001b2011-01-31 04:22:03 +00006520 return -EFAULT;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006521 }
6522
6523 /* Read the buffer */
6524 for (i = 0; i < byte_cnt; i++) {
6525 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006526 MDIO_PMA_DEVAD,
6527 MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF + i, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006528 o_buf[i] = (u8)(val & MDIO_PMA_REG_8727_TWO_WIRE_DATA_MASK);
6529 }
6530
6531 for (i = 0; i < 100; i++) {
6532 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006533 MDIO_PMA_DEVAD,
6534 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006535 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
6536 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
Joe Perches6f38ad92010-11-14 17:04:31 +00006537 return 0;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006538 msleep(1);
6539 }
6540
6541 return -EINVAL;
6542}
6543
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006544int bnx2x_read_sfp_module_eeprom(struct bnx2x_phy *phy,
6545 struct link_params *params, u16 addr,
6546 u8 byte_cnt, u8 *o_buf)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006547{
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006548 int rc = -EINVAL;
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00006549 switch (phy->type) {
6550 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
6551 rc = bnx2x_8726_read_sfp_module_eeprom(phy, params, addr,
6552 byte_cnt, o_buf);
6553 break;
6554 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
6555 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722:
6556 rc = bnx2x_8727_read_sfp_module_eeprom(phy, params, addr,
6557 byte_cnt, o_buf);
6558 break;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00006559 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
6560 rc = bnx2x_warpcore_read_sfp_module_eeprom(phy, params, addr,
6561 byte_cnt, o_buf);
6562 break;
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00006563 }
6564 return rc;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006565}
6566
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006567static int bnx2x_get_edc_mode(struct bnx2x_phy *phy,
6568 struct link_params *params,
6569 u16 *edc_mode)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006570{
6571 struct bnx2x *bp = params->bp;
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00006572 u32 sync_offset = 0, phy_idx, media_types;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006573 u8 val, check_limiting_mode = 0;
6574 *edc_mode = EDC_MODE_LIMITING;
6575
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00006576 phy->media_type = ETH_PHY_UNSPECIFIED;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006577 /* First check for copper cable */
6578 if (bnx2x_read_sfp_module_eeprom(phy,
6579 params,
6580 SFP_EEPROM_CON_TYPE_ADDR,
6581 1,
6582 &val) != 0) {
6583 DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM\n");
6584 return -EINVAL;
6585 }
6586
6587 switch (val) {
6588 case SFP_EEPROM_CON_TYPE_VAL_COPPER:
6589 {
6590 u8 copper_module_type;
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00006591 phy->media_type = ETH_PHY_DA_TWINAX;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006592 /*
6593 * Check if its active cable (includes SFP+ module)
6594 * of passive cable
6595 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006596 if (bnx2x_read_sfp_module_eeprom(phy,
6597 params,
6598 SFP_EEPROM_FC_TX_TECH_ADDR,
6599 1,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00006600 &copper_module_type) != 0) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006601 DP(NETIF_MSG_LINK,
6602 "Failed to read copper-cable-type"
6603 " from SFP+ EEPROM\n");
6604 return -EINVAL;
6605 }
6606
6607 if (copper_module_type &
6608 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE) {
6609 DP(NETIF_MSG_LINK, "Active Copper cable detected\n");
6610 check_limiting_mode = 1;
6611 } else if (copper_module_type &
6612 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE) {
6613 DP(NETIF_MSG_LINK, "Passive Copper"
6614 " cable detected\n");
6615 *edc_mode =
6616 EDC_MODE_PASSIVE_DAC;
6617 } else {
6618 DP(NETIF_MSG_LINK, "Unknown copper-cable-"
6619 "type 0x%x !!!\n", copper_module_type);
6620 return -EINVAL;
6621 }
6622 break;
6623 }
6624 case SFP_EEPROM_CON_TYPE_VAL_LC:
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00006625 phy->media_type = ETH_PHY_SFP_FIBER;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006626 DP(NETIF_MSG_LINK, "Optic module detected\n");
6627 check_limiting_mode = 1;
6628 break;
6629 default:
6630 DP(NETIF_MSG_LINK, "Unable to determine module type 0x%x !!!\n",
6631 val);
6632 return -EINVAL;
6633 }
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00006634 sync_offset = params->shmem_base +
6635 offsetof(struct shmem_region,
6636 dev_info.port_hw_config[params->port].media_type);
6637 media_types = REG_RD(bp, sync_offset);
6638 /* Update media type for non-PMF sync */
6639 for (phy_idx = INT_PHY; phy_idx < MAX_PHYS; phy_idx++) {
6640 if (&(params->phy[phy_idx]) == phy) {
6641 media_types &= ~(PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK <<
6642 (PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT * phy_idx));
6643 media_types |= ((phy->media_type &
6644 PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK) <<
6645 (PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT * phy_idx));
6646 break;
6647 }
6648 }
6649 REG_WR(bp, sync_offset, media_types);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006650 if (check_limiting_mode) {
6651 u8 options[SFP_EEPROM_OPTIONS_SIZE];
6652 if (bnx2x_read_sfp_module_eeprom(phy,
6653 params,
6654 SFP_EEPROM_OPTIONS_ADDR,
6655 SFP_EEPROM_OPTIONS_SIZE,
6656 options) != 0) {
6657 DP(NETIF_MSG_LINK, "Failed to read Option"
6658 " field from module EEPROM\n");
6659 return -EINVAL;
6660 }
6661 if ((options[0] & SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK))
6662 *edc_mode = EDC_MODE_LINEAR;
6663 else
6664 *edc_mode = EDC_MODE_LIMITING;
6665 }
6666 DP(NETIF_MSG_LINK, "EDC mode is set to 0x%x\n", *edc_mode);
6667 return 0;
6668}
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006669/*
6670 * This function read the relevant field from the module (SFP+), and verify it
6671 * is compliant with this board
6672 */
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006673static int bnx2x_verify_sfp_module(struct bnx2x_phy *phy,
6674 struct link_params *params)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006675{
6676 struct bnx2x *bp = params->bp;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006677 u32 val, cmd;
6678 u32 fw_resp, fw_cmd_param;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006679 char vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE+1];
6680 char vendor_pn[SFP_EEPROM_PART_NO_SIZE+1];
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006681 phy->flags &= ~FLAGS_SFP_NOT_APPROVED;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006682 val = REG_RD(bp, params->shmem_base +
6683 offsetof(struct shmem_region, dev_info.
6684 port_feature_config[params->port].config));
6685 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
6686 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_NO_ENFORCEMENT) {
6687 DP(NETIF_MSG_LINK, "NOT enforcing module verification\n");
6688 return 0;
6689 }
6690
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006691 if (params->feature_config_flags &
6692 FEATURE_CONFIG_BC_SUPPORTS_DUAL_PHY_OPT_MDL_VRFY) {
6693 /* Use specific phy request */
6694 cmd = DRV_MSG_CODE_VRFY_SPECIFIC_PHY_OPT_MDL;
6695 } else if (params->feature_config_flags &
6696 FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY) {
6697 /* Use first phy request only in case of non-dual media*/
6698 if (DUAL_MEDIA(params)) {
6699 DP(NETIF_MSG_LINK, "FW does not support OPT MDL "
6700 "verification\n");
6701 return -EINVAL;
6702 }
6703 cmd = DRV_MSG_CODE_VRFY_FIRST_PHY_OPT_MDL;
6704 } else {
6705 /* No support in OPT MDL detection */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006706 DP(NETIF_MSG_LINK, "FW does not support OPT MDL "
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006707 "verification\n");
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006708 return -EINVAL;
6709 }
Dmitry Kravkov523224a2010-10-06 03:23:26 +00006710
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006711 fw_cmd_param = FW_PARAM_SET(phy->addr, phy->type, phy->mdio_ctrl);
6712 fw_resp = bnx2x_fw_command(bp, cmd, fw_cmd_param);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006713 if (fw_resp == FW_MSG_CODE_VRFY_OPT_MDL_SUCCESS) {
6714 DP(NETIF_MSG_LINK, "Approved module\n");
6715 return 0;
6716 }
6717
6718 /* format the warning message */
6719 if (bnx2x_read_sfp_module_eeprom(phy,
6720 params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006721 SFP_EEPROM_VENDOR_NAME_ADDR,
6722 SFP_EEPROM_VENDOR_NAME_SIZE,
6723 (u8 *)vendor_name))
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006724 vendor_name[0] = '\0';
6725 else
6726 vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE] = '\0';
6727 if (bnx2x_read_sfp_module_eeprom(phy,
6728 params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006729 SFP_EEPROM_PART_NO_ADDR,
6730 SFP_EEPROM_PART_NO_SIZE,
6731 (u8 *)vendor_pn))
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006732 vendor_pn[0] = '\0';
6733 else
6734 vendor_pn[SFP_EEPROM_PART_NO_SIZE] = '\0';
6735
Yaniv Rosner6d870c32011-01-31 04:22:20 +00006736 netdev_err(bp->dev, "Warning: Unqualified SFP+ module detected,"
6737 " Port %d from %s part number %s\n",
6738 params->port, vendor_name, vendor_pn);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006739 phy->flags |= FLAGS_SFP_NOT_APPROVED;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006740 return -EINVAL;
6741}
6742
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006743static int bnx2x_wait_for_sfp_module_initialized(struct bnx2x_phy *phy,
6744 struct link_params *params)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006745
6746{
6747 u8 val;
6748 struct bnx2x *bp = params->bp;
6749 u16 timeout;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006750 /*
6751 * Initialization time after hot-plug may take up to 300ms for
6752 * some phys type ( e.g. JDSU )
6753 */
6754
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006755 for (timeout = 0; timeout < 60; timeout++) {
6756 if (bnx2x_read_sfp_module_eeprom(phy, params, 1, 1, &val)
6757 == 0) {
6758 DP(NETIF_MSG_LINK, "SFP+ module initialization "
6759 "took %d ms\n", timeout * 5);
6760 return 0;
6761 }
6762 msleep(5);
6763 }
6764 return -EINVAL;
6765}
6766
6767static void bnx2x_8727_power_module(struct bnx2x *bp,
6768 struct bnx2x_phy *phy,
6769 u8 is_power_up) {
6770 /* Make sure GPIOs are not using for LED mode */
6771 u16 val;
6772 /*
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006773 * In the GPIO register, bit 4 is use to determine if the GPIOs are
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006774 * operating as INPUT or as OUTPUT. Bit 1 is for input, and 0 for
6775 * output
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00006776 * Bits 0-1 determine the GPIOs value for OUTPUT in case bit 4 val is 0
6777 * Bits 8-9 determine the GPIOs value for INPUT in case bit 4 val is 1
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006778 * where the 1st bit is the over-current(only input), and 2nd bit is
6779 * for power( only output )
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006780 *
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006781 * In case of NOC feature is disabled and power is up, set GPIO control
6782 * as input to enable listening of over-current indication
6783 */
6784 if (phy->flags & FLAGS_NOC)
6785 return;
Yaniv Rosner27d02432011-05-31 21:27:48 +00006786 if (is_power_up)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006787 val = (1<<4);
6788 else
6789 /*
6790 * Set GPIO control to OUTPUT, and set the power bit
6791 * to according to the is_power_up
6792 */
Yaniv Rosner27d02432011-05-31 21:27:48 +00006793 val = (1<<1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006794
6795 bnx2x_cl45_write(bp, phy,
6796 MDIO_PMA_DEVAD,
6797 MDIO_PMA_REG_8727_GPIO_CTRL,
6798 val);
6799}
6800
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006801static int bnx2x_8726_set_limiting_mode(struct bnx2x *bp,
6802 struct bnx2x_phy *phy,
6803 u16 edc_mode)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006804{
6805 u16 cur_limiting_mode;
6806
6807 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006808 MDIO_PMA_DEVAD,
6809 MDIO_PMA_REG_ROM_VER2,
6810 &cur_limiting_mode);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006811 DP(NETIF_MSG_LINK, "Current Limiting mode is 0x%x\n",
6812 cur_limiting_mode);
6813
6814 if (edc_mode == EDC_MODE_LIMITING) {
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006815 DP(NETIF_MSG_LINK, "Setting LIMITING MODE\n");
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006816 bnx2x_cl45_write(bp, phy,
6817 MDIO_PMA_DEVAD,
6818 MDIO_PMA_REG_ROM_VER2,
6819 EDC_MODE_LIMITING);
6820 } else { /* LRM mode ( default )*/
6821
6822 DP(NETIF_MSG_LINK, "Setting LRM MODE\n");
6823
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006824 /*
6825 * Changing to LRM mode takes quite few seconds. So do it only
6826 * if current mode is limiting (default is LRM)
6827 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006828 if (cur_limiting_mode != EDC_MODE_LIMITING)
6829 return 0;
6830
6831 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006832 MDIO_PMA_DEVAD,
6833 MDIO_PMA_REG_LRM_MODE,
6834 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006835 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006836 MDIO_PMA_DEVAD,
6837 MDIO_PMA_REG_ROM_VER2,
6838 0x128);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006839 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006840 MDIO_PMA_DEVAD,
6841 MDIO_PMA_REG_MISC_CTRL0,
6842 0x4008);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006843 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006844 MDIO_PMA_DEVAD,
6845 MDIO_PMA_REG_LRM_MODE,
6846 0xaaaa);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006847 }
6848 return 0;
6849}
6850
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006851static int bnx2x_8727_set_limiting_mode(struct bnx2x *bp,
6852 struct bnx2x_phy *phy,
6853 u16 edc_mode)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006854{
6855 u16 phy_identifier;
6856 u16 rom_ver2_val;
6857 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006858 MDIO_PMA_DEVAD,
6859 MDIO_PMA_REG_PHY_IDENTIFIER,
6860 &phy_identifier);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006861
6862 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006863 MDIO_PMA_DEVAD,
6864 MDIO_PMA_REG_PHY_IDENTIFIER,
6865 (phy_identifier & ~(1<<9)));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006866
6867 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006868 MDIO_PMA_DEVAD,
6869 MDIO_PMA_REG_ROM_VER2,
6870 &rom_ver2_val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006871 /* Keep the MSB 8-bits, and set the LSB 8-bits with the edc_mode */
6872 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006873 MDIO_PMA_DEVAD,
6874 MDIO_PMA_REG_ROM_VER2,
6875 (rom_ver2_val & 0xff00) | (edc_mode & 0x00ff));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006876
6877 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006878 MDIO_PMA_DEVAD,
6879 MDIO_PMA_REG_PHY_IDENTIFIER,
6880 (phy_identifier | (1<<9)));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006881
6882 return 0;
6883}
6884
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006885static void bnx2x_8727_specific_func(struct bnx2x_phy *phy,
6886 struct link_params *params,
6887 u32 action)
6888{
6889 struct bnx2x *bp = params->bp;
6890
6891 switch (action) {
6892 case DISABLE_TX:
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00006893 bnx2x_sfp_set_transmitter(params, phy, 0);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006894 break;
6895 case ENABLE_TX:
6896 if (!(phy->flags & FLAGS_SFP_NOT_APPROVED))
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00006897 bnx2x_sfp_set_transmitter(params, phy, 1);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006898 break;
6899 default:
6900 DP(NETIF_MSG_LINK, "Function 0x%x not supported by 8727\n",
6901 action);
6902 return;
6903 }
6904}
6905
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00006906static void bnx2x_set_e1e2_module_fault_led(struct link_params *params,
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00006907 u8 gpio_mode)
6908{
6909 struct bnx2x *bp = params->bp;
6910
6911 u32 fault_led_gpio = REG_RD(bp, params->shmem_base +
6912 offsetof(struct shmem_region,
6913 dev_info.port_hw_config[params->port].sfp_ctrl)) &
6914 PORT_HW_CFG_FAULT_MODULE_LED_MASK;
6915 switch (fault_led_gpio) {
6916 case PORT_HW_CFG_FAULT_MODULE_LED_DISABLED:
6917 return;
6918 case PORT_HW_CFG_FAULT_MODULE_LED_GPIO0:
6919 case PORT_HW_CFG_FAULT_MODULE_LED_GPIO1:
6920 case PORT_HW_CFG_FAULT_MODULE_LED_GPIO2:
6921 case PORT_HW_CFG_FAULT_MODULE_LED_GPIO3:
6922 {
6923 u8 gpio_port = bnx2x_get_gpio_port(params);
6924 u16 gpio_pin = fault_led_gpio -
6925 PORT_HW_CFG_FAULT_MODULE_LED_GPIO0;
6926 DP(NETIF_MSG_LINK, "Set fault module-detected led "
6927 "pin %x port %x mode %x\n",
6928 gpio_pin, gpio_port, gpio_mode);
6929 bnx2x_set_gpio(bp, gpio_pin, gpio_mode, gpio_port);
6930 }
6931 break;
6932 default:
6933 DP(NETIF_MSG_LINK, "Error: Invalid fault led mode 0x%x\n",
6934 fault_led_gpio);
6935 }
6936}
6937
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00006938static void bnx2x_set_e3_module_fault_led(struct link_params *params,
6939 u8 gpio_mode)
6940{
6941 u32 pin_cfg;
6942 u8 port = params->port;
6943 struct bnx2x *bp = params->bp;
6944 pin_cfg = (REG_RD(bp, params->shmem_base +
6945 offsetof(struct shmem_region,
6946 dev_info.port_hw_config[port].e3_sfp_ctrl)) &
6947 PORT_HW_CFG_E3_FAULT_MDL_LED_MASK) >>
6948 PORT_HW_CFG_E3_FAULT_MDL_LED_SHIFT;
6949 DP(NETIF_MSG_LINK, "Setting Fault LED to %d using pin cfg %d\n",
6950 gpio_mode, pin_cfg);
6951 bnx2x_set_cfg_pin(bp, pin_cfg, gpio_mode);
6952}
6953
6954static void bnx2x_set_sfp_module_fault_led(struct link_params *params,
6955 u8 gpio_mode)
6956{
6957 struct bnx2x *bp = params->bp;
6958 DP(NETIF_MSG_LINK, "Setting SFP+ module fault LED to %d\n", gpio_mode);
6959 if (CHIP_IS_E3(bp)) {
6960 /*
6961 * Low ==> if SFP+ module is supported otherwise
6962 * High ==> if SFP+ module is not on the approved vendor list
6963 */
6964 bnx2x_set_e3_module_fault_led(params, gpio_mode);
6965 } else
6966 bnx2x_set_e1e2_module_fault_led(params, gpio_mode);
6967}
6968
6969static void bnx2x_warpcore_power_module(struct link_params *params,
6970 struct bnx2x_phy *phy,
6971 u8 power)
6972{
6973 u32 pin_cfg;
6974 struct bnx2x *bp = params->bp;
6975
6976 pin_cfg = (REG_RD(bp, params->shmem_base +
6977 offsetof(struct shmem_region,
6978 dev_info.port_hw_config[params->port].e3_sfp_ctrl)) &
6979 PORT_HW_CFG_E3_PWR_DIS_MASK) >>
6980 PORT_HW_CFG_E3_PWR_DIS_SHIFT;
6981 DP(NETIF_MSG_LINK, "Setting SFP+ module power to %d using pin cfg %d\n",
6982 power, pin_cfg);
6983 /*
6984 * Low ==> corresponding SFP+ module is powered
6985 * high ==> the SFP+ module is powered down
6986 */
6987 bnx2x_set_cfg_pin(bp, pin_cfg, power ^ 1);
6988}
6989
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00006990static void bnx2x_power_sfp_module(struct link_params *params,
6991 struct bnx2x_phy *phy,
6992 u8 power)
6993{
6994 struct bnx2x *bp = params->bp;
6995 DP(NETIF_MSG_LINK, "Setting SFP+ power to %x\n", power);
6996
6997 switch (phy->type) {
6998 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
6999 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722:
7000 bnx2x_8727_power_module(params->bp, phy, power);
7001 break;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00007002 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
7003 bnx2x_warpcore_power_module(params, phy, power);
7004 break;
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00007005 default:
7006 break;
7007 }
7008}
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00007009static void bnx2x_warpcore_set_limiting_mode(struct link_params *params,
7010 struct bnx2x_phy *phy,
7011 u16 edc_mode)
7012{
7013 u16 val = 0;
7014 u16 mode = MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE_DEFAULT;
7015 struct bnx2x *bp = params->bp;
7016
7017 u8 lane = bnx2x_get_warpcore_lane(phy, params);
7018 /* This is a global register which controls all lanes */
7019 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
7020 MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE, &val);
7021 val &= ~(0xf << (lane << 2));
7022
7023 switch (edc_mode) {
7024 case EDC_MODE_LINEAR:
7025 case EDC_MODE_LIMITING:
7026 mode = MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE_DEFAULT;
7027 break;
7028 case EDC_MODE_PASSIVE_DAC:
7029 mode = MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE_SFP_DAC;
7030 break;
7031 default:
7032 break;
7033 }
7034
7035 val |= (mode << (lane << 2));
7036 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
7037 MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE, val);
7038 /* A must read */
7039 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
7040 MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE, &val);
7041
7042
7043}
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00007044
7045static void bnx2x_set_limiting_mode(struct link_params *params,
7046 struct bnx2x_phy *phy,
7047 u16 edc_mode)
7048{
7049 switch (phy->type) {
7050 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
7051 bnx2x_8726_set_limiting_mode(params->bp, phy, edc_mode);
7052 break;
7053 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
7054 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722:
7055 bnx2x_8727_set_limiting_mode(params->bp, phy, edc_mode);
7056 break;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00007057 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
7058 bnx2x_warpcore_set_limiting_mode(params, phy, edc_mode);
7059 break;
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00007060 }
7061}
7062
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00007063int bnx2x_sfp_module_detection(struct bnx2x_phy *phy,
7064 struct link_params *params)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007065{
7066 struct bnx2x *bp = params->bp;
7067 u16 edc_mode;
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00007068 int rc = 0;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007069
7070 u32 val = REG_RD(bp, params->shmem_base +
7071 offsetof(struct shmem_region, dev_info.
7072 port_feature_config[params->port].config));
7073
7074 DP(NETIF_MSG_LINK, "SFP+ module plugged in/out detected on port %d\n",
7075 params->port);
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00007076 /* Power up module */
7077 bnx2x_power_sfp_module(params, phy, 1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007078 if (bnx2x_get_edc_mode(phy, params, &edc_mode) != 0) {
7079 DP(NETIF_MSG_LINK, "Failed to get valid module type\n");
7080 return -EINVAL;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007081 } else if (bnx2x_verify_sfp_module(phy, params) != 0) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007082 /* check SFP+ module compatibility */
7083 DP(NETIF_MSG_LINK, "Module verification failed!!\n");
7084 rc = -EINVAL;
7085 /* Turn on fault module-detected led */
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00007086 bnx2x_set_sfp_module_fault_led(params,
7087 MISC_REGISTERS_GPIO_HIGH);
7088
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00007089 /* Check if need to power down the SFP+ module */
7090 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
7091 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_POWER_DOWN) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007092 DP(NETIF_MSG_LINK, "Shutdown SFP+ module!!\n");
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00007093 bnx2x_power_sfp_module(params, phy, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007094 return rc;
7095 }
7096 } else {
7097 /* Turn off fault module-detected led */
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00007098 bnx2x_set_sfp_module_fault_led(params, MISC_REGISTERS_GPIO_LOW);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007099 }
7100
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007101 /*
7102 * Check and set limiting mode / LRM mode on 8726. On 8727 it
7103 * is done automatically
7104 */
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00007105 bnx2x_set_limiting_mode(params, phy, edc_mode);
7106
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007107 /*
7108 * Enable transmit for this module if the module is approved, or
7109 * if unapproved modules should also enable the Tx laser
7110 */
7111 if (rc == 0 ||
7112 (val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) !=
7113 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00007114 bnx2x_sfp_set_transmitter(params, phy, 1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007115 else
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00007116 bnx2x_sfp_set_transmitter(params, phy, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007117
7118 return rc;
7119}
7120
7121void bnx2x_handle_module_detect_int(struct link_params *params)
7122{
7123 struct bnx2x *bp = params->bp;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00007124 struct bnx2x_phy *phy;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007125 u32 gpio_val;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00007126 u8 gpio_num, gpio_port;
7127 if (CHIP_IS_E3(bp))
7128 phy = &params->phy[INT_PHY];
7129 else
7130 phy = &params->phy[EXT_PHY1];
7131
7132 if (bnx2x_get_mod_abs_int_cfg(bp, params->chip_id, params->shmem_base,
7133 params->port, &gpio_num, &gpio_port) ==
7134 -EINVAL) {
7135 DP(NETIF_MSG_LINK, "Failed to get MOD_ABS interrupt config\n");
7136 return;
7137 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007138
7139 /* Set valid module led off */
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00007140 bnx2x_set_sfp_module_fault_led(params, MISC_REGISTERS_GPIO_HIGH);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007141
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007142 /* Get current gpio val reflecting module plugged in / out*/
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00007143 gpio_val = bnx2x_get_gpio(bp, gpio_num, gpio_port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007144
7145 /* Call the handling function in case module is detected */
7146 if (gpio_val == 0) {
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00007147 bnx2x_power_sfp_module(params, phy, 1);
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00007148 bnx2x_set_gpio_int(bp, gpio_num,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007149 MISC_REGISTERS_GPIO_INT_OUTPUT_CLR,
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00007150 gpio_port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007151 if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0)
7152 bnx2x_sfp_module_detection(phy, params);
7153 else
7154 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
7155 } else {
7156 u32 val = REG_RD(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007157 offsetof(struct shmem_region, dev_info.
7158 port_feature_config[params->port].
7159 config));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007160
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00007161 bnx2x_set_gpio_int(bp, gpio_num,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007162 MISC_REGISTERS_GPIO_INT_OUTPUT_SET,
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00007163 gpio_port);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007164 /*
7165 * Module was plugged out.
7166 * Disable transmit for this module
7167 */
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00007168 phy->media_type = ETH_PHY_NOT_PRESENT;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007169 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
7170 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00007171 bnx2x_sfp_set_transmitter(params, phy, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007172 }
7173}
7174
7175/******************************************************************/
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00007176/* Used by 8706 and 8727 */
7177/******************************************************************/
7178static void bnx2x_sfp_mask_fault(struct bnx2x *bp,
7179 struct bnx2x_phy *phy,
7180 u16 alarm_status_offset,
7181 u16 alarm_ctrl_offset)
7182{
7183 u16 alarm_status, val;
7184 bnx2x_cl45_read(bp, phy,
7185 MDIO_PMA_DEVAD, alarm_status_offset,
7186 &alarm_status);
7187 bnx2x_cl45_read(bp, phy,
7188 MDIO_PMA_DEVAD, alarm_status_offset,
7189 &alarm_status);
7190 /* Mask or enable the fault event. */
7191 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, alarm_ctrl_offset, &val);
7192 if (alarm_status & (1<<0))
7193 val &= ~(1<<0);
7194 else
7195 val |= (1<<0);
7196 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, alarm_ctrl_offset, val);
7197}
7198/******************************************************************/
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007199/* common BCM8706/BCM8726 PHY SECTION */
7200/******************************************************************/
7201static u8 bnx2x_8706_8726_read_status(struct bnx2x_phy *phy,
7202 struct link_params *params,
7203 struct link_vars *vars)
7204{
7205 u8 link_up = 0;
7206 u16 val1, val2, rx_sd, pcs_status;
7207 struct bnx2x *bp = params->bp;
7208 DP(NETIF_MSG_LINK, "XGXS 8706/8726\n");
7209 /* Clear RX Alarm*/
7210 bnx2x_cl45_read(bp, phy,
7211 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &val2);
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00007212
7213 bnx2x_sfp_mask_fault(bp, phy, MDIO_PMA_REG_TX_ALARM,
7214 MDIO_PMA_REG_TX_ALARM_CTRL);
7215
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007216 /* clear LASI indication*/
7217 bnx2x_cl45_read(bp, phy,
7218 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
7219 bnx2x_cl45_read(bp, phy,
7220 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val2);
7221 DP(NETIF_MSG_LINK, "8706/8726 LASI status 0x%x--> 0x%x\n", val1, val2);
7222
7223 bnx2x_cl45_read(bp, phy,
7224 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD, &rx_sd);
7225 bnx2x_cl45_read(bp, phy,
7226 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &pcs_status);
7227 bnx2x_cl45_read(bp, phy,
7228 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &val2);
7229 bnx2x_cl45_read(bp, phy,
7230 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &val2);
7231
7232 DP(NETIF_MSG_LINK, "8706/8726 rx_sd 0x%x pcs_status 0x%x 1Gbps"
7233 " link_status 0x%x\n", rx_sd, pcs_status, val2);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007234 /*
7235 * link is up if both bit 0 of pmd_rx_sd and bit 0 of pcs_status
7236 * are set, or if the autoneg bit 1 is set
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007237 */
7238 link_up = ((rx_sd & pcs_status & 0x1) || (val2 & (1<<1)));
7239 if (link_up) {
7240 if (val2 & (1<<1))
7241 vars->line_speed = SPEED_1000;
7242 else
7243 vars->line_speed = SPEED_10000;
7244 bnx2x_ext_phy_resolve_fc(phy, params, vars);
Yaniv Rosner791f18c2011-01-18 04:33:42 +00007245 vars->duplex = DUPLEX_FULL;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007246 }
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00007247
7248 /* Capture 10G link fault. Read twice to clear stale value. */
7249 if (vars->line_speed == SPEED_10000) {
7250 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
7251 MDIO_PMA_REG_TX_ALARM, &val1);
7252 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
7253 MDIO_PMA_REG_TX_ALARM, &val1);
7254 if (val1 & (1<<0))
7255 vars->fault_detected = 1;
7256 }
7257
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007258 return link_up;
7259}
7260
7261/******************************************************************/
7262/* BCM8706 PHY SECTION */
7263/******************************************************************/
7264static u8 bnx2x_8706_config_init(struct bnx2x_phy *phy,
7265 struct link_params *params,
7266 struct link_vars *vars)
7267{
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00007268 u32 tx_en_mode;
7269 u16 cnt, val, tmp1;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007270 struct bnx2x *bp = params->bp;
7271 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007272 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007273 /* HW reset */
7274 bnx2x_ext_phy_hw_reset(bp, params->port);
7275 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0xa040);
Yaniv Rosner6d870c32011-01-31 04:22:20 +00007276 bnx2x_wait_reset_complete(bp, phy, params);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007277
7278 /* Wait until fw is loaded */
7279 for (cnt = 0; cnt < 100; cnt++) {
7280 bnx2x_cl45_read(bp, phy,
7281 MDIO_PMA_DEVAD, MDIO_PMA_REG_ROM_VER1, &val);
7282 if (val)
7283 break;
7284 msleep(10);
7285 }
7286 DP(NETIF_MSG_LINK, "XGXS 8706 is initialized after %d ms\n", cnt);
7287 if ((params->feature_config_flags &
7288 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
7289 u8 i;
7290 u16 reg;
7291 for (i = 0; i < 4; i++) {
7292 reg = MDIO_XS_8706_REG_BANK_RX0 +
7293 i*(MDIO_XS_8706_REG_BANK_RX1 -
7294 MDIO_XS_8706_REG_BANK_RX0);
7295 bnx2x_cl45_read(bp, phy, MDIO_XS_DEVAD, reg, &val);
7296 /* Clear first 3 bits of the control */
7297 val &= ~0x7;
7298 /* Set control bits according to configuration */
7299 val |= (phy->rx_preemphasis[i] & 0x7);
7300 DP(NETIF_MSG_LINK, "Setting RX Equalizer to BCM8706"
7301 " reg 0x%x <-- val 0x%x\n", reg, val);
7302 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, reg, val);
7303 }
7304 }
7305 /* Force speed */
7306 if (phy->req_line_speed == SPEED_10000) {
7307 DP(NETIF_MSG_LINK, "XGXS 8706 force 10Gbps\n");
7308
7309 bnx2x_cl45_write(bp, phy,
7310 MDIO_PMA_DEVAD,
7311 MDIO_PMA_REG_DIGITAL_CTRL, 0x400);
7312 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00007313 MDIO_PMA_DEVAD, MDIO_PMA_REG_TX_ALARM_CTRL,
7314 0);
7315 /* Arm LASI for link and Tx fault. */
7316 bnx2x_cl45_write(bp, phy,
7317 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 3);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007318 } else {
Lucas De Marchi25985ed2011-03-30 22:57:33 -03007319 /* Force 1Gbps using autoneg with 1G advertisement */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007320
7321 /* Allow CL37 through CL73 */
7322 DP(NETIF_MSG_LINK, "XGXS 8706 AutoNeg\n");
7323 bnx2x_cl45_write(bp, phy,
7324 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_CL73, 0x040c);
7325
Lucas De Marchi25985ed2011-03-30 22:57:33 -03007326 /* Enable Full-Duplex advertisement on CL37 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007327 bnx2x_cl45_write(bp, phy,
7328 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LP, 0x0020);
7329 /* Enable CL37 AN */
7330 bnx2x_cl45_write(bp, phy,
7331 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
7332 /* 1G support */
7333 bnx2x_cl45_write(bp, phy,
7334 MDIO_AN_DEVAD, MDIO_AN_REG_ADV, (1<<5));
7335
7336 /* Enable clause 73 AN */
7337 bnx2x_cl45_write(bp, phy,
7338 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
7339 bnx2x_cl45_write(bp, phy,
7340 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
7341 0x0400);
7342 bnx2x_cl45_write(bp, phy,
7343 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL,
7344 0x0004);
7345 }
7346 bnx2x_save_bcm_spirom_ver(bp, phy, params->port);
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00007347
7348 /*
7349 * If TX Laser is controlled by GPIO_0, do not let PHY go into low
7350 * power mode, if TX Laser is disabled
7351 */
7352
7353 tx_en_mode = REG_RD(bp, params->shmem_base +
7354 offsetof(struct shmem_region,
7355 dev_info.port_hw_config[params->port].sfp_ctrl))
7356 & PORT_HW_CFG_TX_LASER_MASK;
7357
7358 if (tx_en_mode == PORT_HW_CFG_TX_LASER_GPIO0) {
7359 DP(NETIF_MSG_LINK, "Enabling TXONOFF_PWRDN_DIS\n");
7360 bnx2x_cl45_read(bp, phy,
7361 MDIO_PMA_DEVAD, MDIO_PMA_REG_DIGITAL_CTRL, &tmp1);
7362 tmp1 |= 0x1;
7363 bnx2x_cl45_write(bp, phy,
7364 MDIO_PMA_DEVAD, MDIO_PMA_REG_DIGITAL_CTRL, tmp1);
7365 }
7366
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007367 return 0;
7368}
7369
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00007370static int bnx2x_8706_read_status(struct bnx2x_phy *phy,
7371 struct link_params *params,
7372 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007373{
7374 return bnx2x_8706_8726_read_status(phy, params, vars);
7375}
7376
7377/******************************************************************/
7378/* BCM8726 PHY SECTION */
7379/******************************************************************/
7380static void bnx2x_8726_config_loopback(struct bnx2x_phy *phy,
7381 struct link_params *params)
7382{
7383 struct bnx2x *bp = params->bp;
7384 DP(NETIF_MSG_LINK, "PMA/PMD ext_phy_loopback: 8726\n");
7385 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x0001);
7386}
7387
7388static void bnx2x_8726_external_rom_boot(struct bnx2x_phy *phy,
7389 struct link_params *params)
7390{
7391 struct bnx2x *bp = params->bp;
7392 /* Need to wait 100ms after reset */
7393 msleep(100);
7394
7395 /* Micro controller re-boot */
7396 bnx2x_cl45_write(bp, phy,
7397 MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, 0x018B);
7398
7399 /* Set soft reset */
7400 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007401 MDIO_PMA_DEVAD,
7402 MDIO_PMA_REG_GEN_CTRL,
7403 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007404
7405 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007406 MDIO_PMA_DEVAD,
7407 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007408
7409 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007410 MDIO_PMA_DEVAD,
7411 MDIO_PMA_REG_GEN_CTRL,
7412 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007413
7414 /* wait for 150ms for microcode load */
7415 msleep(150);
7416
7417 /* Disable serial boot control, tristates pins SS_N, SCK, MOSI, MISO */
7418 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007419 MDIO_PMA_DEVAD,
7420 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007421
7422 msleep(200);
7423 bnx2x_save_bcm_spirom_ver(bp, phy, params->port);
7424}
7425
7426static u8 bnx2x_8726_read_status(struct bnx2x_phy *phy,
7427 struct link_params *params,
7428 struct link_vars *vars)
7429{
7430 struct bnx2x *bp = params->bp;
7431 u16 val1;
7432 u8 link_up = bnx2x_8706_8726_read_status(phy, params, vars);
7433 if (link_up) {
7434 bnx2x_cl45_read(bp, phy,
7435 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER,
7436 &val1);
7437 if (val1 & (1<<15)) {
7438 DP(NETIF_MSG_LINK, "Tx is disabled\n");
7439 link_up = 0;
7440 vars->line_speed = 0;
7441 }
7442 }
7443 return link_up;
7444}
7445
7446
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00007447static int bnx2x_8726_config_init(struct bnx2x_phy *phy,
7448 struct link_params *params,
7449 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007450{
7451 struct bnx2x *bp = params->bp;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007452 DP(NETIF_MSG_LINK, "Initializing BCM8726\n");
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007453
7454 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
Yaniv Rosner6d870c32011-01-31 04:22:20 +00007455 bnx2x_wait_reset_complete(bp, phy, params);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007456
7457 bnx2x_8726_external_rom_boot(phy, params);
7458
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007459 /*
7460 * Need to call module detected on initialization since the module
7461 * detection triggered by actual module insertion might occur before
7462 * driver is loaded, and when driver is loaded, it reset all
7463 * registers, including the transmitter
7464 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007465 bnx2x_sfp_module_detection(phy, params);
7466
7467 if (phy->req_line_speed == SPEED_1000) {
7468 DP(NETIF_MSG_LINK, "Setting 1G force\n");
7469 bnx2x_cl45_write(bp, phy,
7470 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x40);
7471 bnx2x_cl45_write(bp, phy,
7472 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0xD);
7473 bnx2x_cl45_write(bp, phy,
7474 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x5);
7475 bnx2x_cl45_write(bp, phy,
7476 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
7477 0x400);
7478 } else if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
7479 (phy->speed_cap_mask &
7480 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G) &&
7481 ((phy->speed_cap_mask &
7482 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) !=
7483 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
7484 DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
7485 /* Set Flow control */
7486 bnx2x_ext_phy_set_pause(params, phy, vars);
7487 bnx2x_cl45_write(bp, phy,
7488 MDIO_AN_DEVAD, MDIO_AN_REG_ADV, 0x20);
7489 bnx2x_cl45_write(bp, phy,
7490 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_CL73, 0x040c);
7491 bnx2x_cl45_write(bp, phy,
7492 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, 0x0020);
7493 bnx2x_cl45_write(bp, phy,
7494 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
7495 bnx2x_cl45_write(bp, phy,
7496 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007497 /*
7498 * Enable RX-ALARM control to receive interrupt for 1G speed
7499 * change
7500 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007501 bnx2x_cl45_write(bp, phy,
7502 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x4);
7503 bnx2x_cl45_write(bp, phy,
7504 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
7505 0x400);
7506
7507 } else { /* Default 10G. Set only LASI control */
7508 bnx2x_cl45_write(bp, phy,
7509 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 1);
7510 }
7511
7512 /* Set TX PreEmphasis if needed */
7513 if ((params->feature_config_flags &
7514 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
7515 DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x,"
7516 "TX_CTRL2 0x%x\n",
7517 phy->tx_preemphasis[0],
7518 phy->tx_preemphasis[1]);
7519 bnx2x_cl45_write(bp, phy,
7520 MDIO_PMA_DEVAD,
7521 MDIO_PMA_REG_8726_TX_CTRL1,
7522 phy->tx_preemphasis[0]);
7523
7524 bnx2x_cl45_write(bp, phy,
7525 MDIO_PMA_DEVAD,
7526 MDIO_PMA_REG_8726_TX_CTRL2,
7527 phy->tx_preemphasis[1]);
7528 }
7529
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007530 return 0;
7531
7532}
7533
7534static void bnx2x_8726_link_reset(struct bnx2x_phy *phy,
7535 struct link_params *params)
7536{
7537 struct bnx2x *bp = params->bp;
7538 DP(NETIF_MSG_LINK, "bnx2x_8726_link_reset port %d\n", params->port);
7539 /* Set serial boot control for external load */
7540 bnx2x_cl45_write(bp, phy,
7541 MDIO_PMA_DEVAD,
7542 MDIO_PMA_REG_GEN_CTRL, 0x0001);
7543}
7544
7545/******************************************************************/
7546/* BCM8727 PHY SECTION */
7547/******************************************************************/
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00007548
7549static void bnx2x_8727_set_link_led(struct bnx2x_phy *phy,
7550 struct link_params *params, u8 mode)
7551{
7552 struct bnx2x *bp = params->bp;
7553 u16 led_mode_bitmask = 0;
7554 u16 gpio_pins_bitmask = 0;
7555 u16 val;
7556 /* Only NOC flavor requires to set the LED specifically */
7557 if (!(phy->flags & FLAGS_NOC))
7558 return;
7559 switch (mode) {
7560 case LED_MODE_FRONT_PANEL_OFF:
7561 case LED_MODE_OFF:
7562 led_mode_bitmask = 0;
7563 gpio_pins_bitmask = 0x03;
7564 break;
7565 case LED_MODE_ON:
7566 led_mode_bitmask = 0;
7567 gpio_pins_bitmask = 0x02;
7568 break;
7569 case LED_MODE_OPER:
7570 led_mode_bitmask = 0x60;
7571 gpio_pins_bitmask = 0x11;
7572 break;
7573 }
7574 bnx2x_cl45_read(bp, phy,
7575 MDIO_PMA_DEVAD,
7576 MDIO_PMA_REG_8727_PCS_OPT_CTRL,
7577 &val);
7578 val &= 0xff8f;
7579 val |= led_mode_bitmask;
7580 bnx2x_cl45_write(bp, phy,
7581 MDIO_PMA_DEVAD,
7582 MDIO_PMA_REG_8727_PCS_OPT_CTRL,
7583 val);
7584 bnx2x_cl45_read(bp, phy,
7585 MDIO_PMA_DEVAD,
7586 MDIO_PMA_REG_8727_GPIO_CTRL,
7587 &val);
7588 val &= 0xffe0;
7589 val |= gpio_pins_bitmask;
7590 bnx2x_cl45_write(bp, phy,
7591 MDIO_PMA_DEVAD,
7592 MDIO_PMA_REG_8727_GPIO_CTRL,
7593 val);
7594}
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007595static void bnx2x_8727_hw_reset(struct bnx2x_phy *phy,
7596 struct link_params *params) {
7597 u32 swap_val, swap_override;
7598 u8 port;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007599 /*
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007600 * The PHY reset is controlled by GPIO 1. Fake the port number
7601 * to cancel the swap done in set_gpio()
7602 */
7603 struct bnx2x *bp = params->bp;
7604 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
7605 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
7606 port = (swap_val && swap_override) ^ 1;
7607 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007608 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00007609}
7610
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00007611static int bnx2x_8727_config_init(struct bnx2x_phy *phy,
7612 struct link_params *params,
7613 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007614{
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00007615 u32 tx_en_mode;
7616 u16 tmp1, val, mod_abs, tmp2;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007617 u16 rx_alarm_ctrl_val;
7618 u16 lasi_ctrl_val;
7619 struct bnx2x *bp = params->bp;
7620 /* Enable PMD link, MOD_ABS_FLT, and 1G link alarm */
7621
Yaniv Rosner6d870c32011-01-31 04:22:20 +00007622 bnx2x_wait_reset_complete(bp, phy, params);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007623 rx_alarm_ctrl_val = (1<<2) | (1<<5) ;
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00007624 /* Should be 0x6 to enable XS on Tx side. */
7625 lasi_ctrl_val = 0x0006;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007626
7627 DP(NETIF_MSG_LINK, "Initializing BCM8727\n");
7628 /* enable LASI */
7629 bnx2x_cl45_write(bp, phy,
7630 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
7631 rx_alarm_ctrl_val);
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00007632 bnx2x_cl45_write(bp, phy,
7633 MDIO_PMA_DEVAD, MDIO_PMA_REG_TX_ALARM_CTRL,
7634 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007635 bnx2x_cl45_write(bp, phy,
7636 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, lasi_ctrl_val);
7637
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007638 /*
7639 * Initially configure MOD_ABS to interrupt when module is
7640 * presence( bit 8)
7641 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007642 bnx2x_cl45_read(bp, phy,
7643 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007644 /*
7645 * Set EDC off by setting OPTXLOS signal input to low (bit 9).
7646 * When the EDC is off it locks onto a reference clock and avoids
7647 * becoming 'lost'
7648 */
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00007649 mod_abs &= ~(1<<8);
7650 if (!(phy->flags & FLAGS_NOC))
7651 mod_abs &= ~(1<<9);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007652 bnx2x_cl45_write(bp, phy,
7653 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
7654
7655
7656 /* Make MOD_ABS give interrupt on change */
7657 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL,
7658 &val);
7659 val |= (1<<12);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00007660 if (phy->flags & FLAGS_NOC)
7661 val |= (3<<5);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007662
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007663 /*
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00007664 * Set 8727 GPIOs to input to allow reading from the 8727 GPIO0
7665 * status which reflect SFP+ module over-current
7666 */
7667 if (!(phy->flags & FLAGS_NOC))
7668 val &= 0xff8f; /* Reset bits 4-6 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007669 bnx2x_cl45_write(bp, phy,
7670 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL, val);
7671
7672 bnx2x_8727_power_module(bp, phy, 1);
7673
7674 bnx2x_cl45_read(bp, phy,
7675 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &tmp1);
7676
7677 bnx2x_cl45_read(bp, phy,
7678 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &tmp1);
7679
7680 /* Set option 1G speed */
7681 if (phy->req_line_speed == SPEED_1000) {
7682 DP(NETIF_MSG_LINK, "Setting 1G force\n");
7683 bnx2x_cl45_write(bp, phy,
7684 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x40);
7685 bnx2x_cl45_write(bp, phy,
7686 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0xD);
7687 bnx2x_cl45_read(bp, phy,
7688 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, &tmp1);
7689 DP(NETIF_MSG_LINK, "1.7 = 0x%x\n", tmp1);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007690 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007691 * Power down the XAUI until link is up in case of dual-media
7692 * and 1G
7693 */
7694 if (DUAL_MEDIA(params)) {
7695 bnx2x_cl45_read(bp, phy,
7696 MDIO_PMA_DEVAD,
7697 MDIO_PMA_REG_8727_PCS_GP, &val);
7698 val |= (3<<10);
7699 bnx2x_cl45_write(bp, phy,
7700 MDIO_PMA_DEVAD,
7701 MDIO_PMA_REG_8727_PCS_GP, val);
7702 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007703 } else if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
7704 ((phy->speed_cap_mask &
7705 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) &&
7706 ((phy->speed_cap_mask &
7707 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) !=
7708 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
7709
7710 DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
7711 bnx2x_cl45_write(bp, phy,
7712 MDIO_AN_DEVAD, MDIO_AN_REG_8727_MISC_CTRL, 0);
7713 bnx2x_cl45_write(bp, phy,
7714 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1300);
7715 } else {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007716 /*
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007717 * Since the 8727 has only single reset pin, need to set the 10G
7718 * registers although it is default
7719 */
7720 bnx2x_cl45_write(bp, phy,
7721 MDIO_AN_DEVAD, MDIO_AN_REG_8727_MISC_CTRL,
7722 0x0020);
7723 bnx2x_cl45_write(bp, phy,
7724 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x0100);
7725 bnx2x_cl45_write(bp, phy,
7726 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x2040);
7727 bnx2x_cl45_write(bp, phy,
7728 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2,
7729 0x0008);
7730 }
7731
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007732 /*
7733 * Set 2-wire transfer rate of SFP+ module EEPROM
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007734 * to 100Khz since some DACs(direct attached cables) do
7735 * not work at 400Khz.
7736 */
7737 bnx2x_cl45_write(bp, phy,
7738 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR,
7739 0xa001);
7740
7741 /* Set TX PreEmphasis if needed */
7742 if ((params->feature_config_flags &
7743 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
7744 DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x, TX_CTRL2 0x%x\n",
7745 phy->tx_preemphasis[0],
7746 phy->tx_preemphasis[1]);
7747 bnx2x_cl45_write(bp, phy,
7748 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TX_CTRL1,
7749 phy->tx_preemphasis[0]);
7750
7751 bnx2x_cl45_write(bp, phy,
7752 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TX_CTRL2,
7753 phy->tx_preemphasis[1]);
7754 }
7755
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00007756 /*
7757 * If TX Laser is controlled by GPIO_0, do not let PHY go into low
7758 * power mode, if TX Laser is disabled
7759 */
7760 tx_en_mode = REG_RD(bp, params->shmem_base +
7761 offsetof(struct shmem_region,
7762 dev_info.port_hw_config[params->port].sfp_ctrl))
7763 & PORT_HW_CFG_TX_LASER_MASK;
7764
7765 if (tx_en_mode == PORT_HW_CFG_TX_LASER_GPIO0) {
7766
7767 DP(NETIF_MSG_LINK, "Enabling TXONOFF_PWRDN_DIS\n");
7768 bnx2x_cl45_read(bp, phy,
7769 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_OPT_CFG_REG, &tmp2);
7770 tmp2 |= 0x1000;
7771 tmp2 &= 0xFFEF;
7772 bnx2x_cl45_write(bp, phy,
7773 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_OPT_CFG_REG, tmp2);
7774 }
7775
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007776 return 0;
7777}
7778
7779static void bnx2x_8727_handle_mod_abs(struct bnx2x_phy *phy,
7780 struct link_params *params)
7781{
7782 struct bnx2x *bp = params->bp;
7783 u16 mod_abs, rx_alarm_status;
7784 u32 val = REG_RD(bp, params->shmem_base +
7785 offsetof(struct shmem_region, dev_info.
7786 port_feature_config[params->port].
7787 config));
7788 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007789 MDIO_PMA_DEVAD,
7790 MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007791 if (mod_abs & (1<<8)) {
7792
7793 /* Module is absent */
7794 DP(NETIF_MSG_LINK, "MOD_ABS indication "
7795 "show module is absent\n");
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00007796 phy->media_type = ETH_PHY_NOT_PRESENT;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007797 /*
7798 * 1. Set mod_abs to detect next module
7799 * presence event
7800 * 2. Set EDC off by setting OPTXLOS signal input to low
7801 * (bit 9).
7802 * When the EDC is off it locks onto a reference clock and
7803 * avoids becoming 'lost'.
7804 */
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00007805 mod_abs &= ~(1<<8);
7806 if (!(phy->flags & FLAGS_NOC))
7807 mod_abs &= ~(1<<9);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007808 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007809 MDIO_PMA_DEVAD,
7810 MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007811
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007812 /*
7813 * Clear RX alarm since it stays up as long as
7814 * the mod_abs wasn't changed
7815 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007816 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007817 MDIO_PMA_DEVAD,
7818 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007819
7820 } else {
7821 /* Module is present */
7822 DP(NETIF_MSG_LINK, "MOD_ABS indication "
7823 "show module is present\n");
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007824 /*
7825 * First disable transmitter, and if the module is ok, the
7826 * module_detection will enable it
7827 * 1. Set mod_abs to detect next module absent event ( bit 8)
7828 * 2. Restore the default polarity of the OPRXLOS signal and
7829 * this signal will then correctly indicate the presence or
7830 * absence of the Rx signal. (bit 9)
7831 */
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00007832 mod_abs |= (1<<8);
7833 if (!(phy->flags & FLAGS_NOC))
7834 mod_abs |= (1<<9);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007835 bnx2x_cl45_write(bp, phy,
7836 MDIO_PMA_DEVAD,
7837 MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
7838
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007839 /*
7840 * Clear RX alarm since it stays up as long as the mod_abs
7841 * wasn't changed. This is need to be done before calling the
7842 * module detection, otherwise it will clear* the link update
7843 * alarm
7844 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007845 bnx2x_cl45_read(bp, phy,
7846 MDIO_PMA_DEVAD,
7847 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
7848
7849
7850 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
7851 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00007852 bnx2x_sfp_set_transmitter(params, phy, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007853
7854 if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0)
7855 bnx2x_sfp_module_detection(phy, params);
7856 else
7857 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
7858 }
7859
7860 DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n",
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007861 rx_alarm_status);
7862 /* No need to check link status in case of module plugged in/out */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007863}
7864
7865static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy,
7866 struct link_params *params,
7867 struct link_vars *vars)
7868
7869{
7870 struct bnx2x *bp = params->bp;
Yaniv Rosner27d02432011-05-31 21:27:48 +00007871 u8 link_up = 0, oc_port = params->port;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007872 u16 link_status = 0;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007873 u16 rx_alarm_status, lasi_ctrl, val1;
7874
7875 /* If PHY is not initialized, do not check link status */
7876 bnx2x_cl45_read(bp, phy,
7877 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL,
7878 &lasi_ctrl);
7879 if (!lasi_ctrl)
7880 return 0;
7881
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00007882 /* Check the LASI on Rx */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007883 bnx2x_cl45_read(bp, phy,
7884 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM,
7885 &rx_alarm_status);
7886 vars->line_speed = 0;
7887 DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n", rx_alarm_status);
7888
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00007889 bnx2x_sfp_mask_fault(bp, phy, MDIO_PMA_REG_TX_ALARM,
7890 MDIO_PMA_REG_TX_ALARM_CTRL);
7891
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007892 bnx2x_cl45_read(bp, phy,
7893 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
7894
7895 DP(NETIF_MSG_LINK, "8727 LASI status 0x%x\n", val1);
7896
7897 /* Clear MSG-OUT */
7898 bnx2x_cl45_read(bp, phy,
7899 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &val1);
7900
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007901 /*
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007902 * If a module is present and there is need to check
7903 * for over current
7904 */
7905 if (!(phy->flags & FLAGS_NOC) && !(rx_alarm_status & (1<<5))) {
7906 /* Check over-current using 8727 GPIO0 input*/
7907 bnx2x_cl45_read(bp, phy,
7908 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_GPIO_CTRL,
7909 &val1);
7910
7911 if ((val1 & (1<<8)) == 0) {
Yaniv Rosner27d02432011-05-31 21:27:48 +00007912 if (!CHIP_IS_E1x(bp))
7913 oc_port = BP_PATH(bp) + (params->port << 1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007914 DP(NETIF_MSG_LINK, "8727 Power fault has been detected"
Yaniv Rosner27d02432011-05-31 21:27:48 +00007915 " on port %d\n", oc_port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007916 netdev_err(bp->dev, "Error: Power fault on Port %d has"
7917 " been detected and the power to "
7918 "that SFP+ module has been removed"
7919 " to prevent failure of the card."
7920 " Please remove the SFP+ module and"
7921 " restart the system to clear this"
7922 " error.\n",
Yaniv Rosner27d02432011-05-31 21:27:48 +00007923 oc_port);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007924 /* Disable all RX_ALARMs except for mod_abs */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007925 bnx2x_cl45_write(bp, phy,
7926 MDIO_PMA_DEVAD,
7927 MDIO_PMA_REG_RX_ALARM_CTRL, (1<<5));
7928
7929 bnx2x_cl45_read(bp, phy,
7930 MDIO_PMA_DEVAD,
7931 MDIO_PMA_REG_PHY_IDENTIFIER, &val1);
7932 /* Wait for module_absent_event */
7933 val1 |= (1<<8);
7934 bnx2x_cl45_write(bp, phy,
7935 MDIO_PMA_DEVAD,
7936 MDIO_PMA_REG_PHY_IDENTIFIER, val1);
7937 /* Clear RX alarm */
7938 bnx2x_cl45_read(bp, phy,
7939 MDIO_PMA_DEVAD,
7940 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
7941 return 0;
7942 }
7943 } /* Over current check */
7944
7945 /* When module absent bit is set, check module */
7946 if (rx_alarm_status & (1<<5)) {
7947 bnx2x_8727_handle_mod_abs(phy, params);
7948 /* Enable all mod_abs and link detection bits */
7949 bnx2x_cl45_write(bp, phy,
7950 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
7951 ((1<<5) | (1<<2)));
7952 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007953 DP(NETIF_MSG_LINK, "Enabling 8727 TX laser if SFP is approved\n");
7954 bnx2x_8727_specific_func(phy, params, ENABLE_TX);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007955 /* If transmitter is disabled, ignore false link up indication */
7956 bnx2x_cl45_read(bp, phy,
7957 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, &val1);
7958 if (val1 & (1<<15)) {
7959 DP(NETIF_MSG_LINK, "Tx is disabled\n");
7960 return 0;
7961 }
7962
7963 bnx2x_cl45_read(bp, phy,
7964 MDIO_PMA_DEVAD,
7965 MDIO_PMA_REG_8073_SPEED_LINK_STATUS, &link_status);
7966
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007967 /*
7968 * Bits 0..2 --> speed detected,
7969 * Bits 13..15--> link is down
7970 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007971 if ((link_status & (1<<2)) && (!(link_status & (1<<15)))) {
7972 link_up = 1;
7973 vars->line_speed = SPEED_10000;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007974 DP(NETIF_MSG_LINK, "port %x: External link up in 10G\n",
7975 params->port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007976 } else if ((link_status & (1<<0)) && (!(link_status & (1<<13)))) {
7977 link_up = 1;
7978 vars->line_speed = SPEED_1000;
7979 DP(NETIF_MSG_LINK, "port %x: External link up in 1G\n",
7980 params->port);
7981 } else {
7982 link_up = 0;
7983 DP(NETIF_MSG_LINK, "port %x: External link is down\n",
7984 params->port);
7985 }
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00007986
7987 /* Capture 10G link fault. */
7988 if (vars->line_speed == SPEED_10000) {
7989 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
7990 MDIO_PMA_REG_TX_ALARM, &val1);
7991
7992 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
7993 MDIO_PMA_REG_TX_ALARM, &val1);
7994
7995 if (val1 & (1<<0)) {
7996 vars->fault_detected = 1;
7997 }
7998 }
7999
Yaniv Rosner791f18c2011-01-18 04:33:42 +00008000 if (link_up) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008001 bnx2x_ext_phy_resolve_fc(phy, params, vars);
Yaniv Rosner791f18c2011-01-18 04:33:42 +00008002 vars->duplex = DUPLEX_FULL;
8003 DP(NETIF_MSG_LINK, "duplex = 0x%x\n", vars->duplex);
8004 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008005
8006 if ((DUAL_MEDIA(params)) &&
8007 (phy->req_line_speed == SPEED_1000)) {
8008 bnx2x_cl45_read(bp, phy,
8009 MDIO_PMA_DEVAD,
8010 MDIO_PMA_REG_8727_PCS_GP, &val1);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008011 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008012 * In case of dual-media board and 1G, power up the XAUI side,
8013 * otherwise power it down. For 10G it is done automatically
8014 */
8015 if (link_up)
8016 val1 &= ~(3<<10);
8017 else
8018 val1 |= (3<<10);
8019 bnx2x_cl45_write(bp, phy,
8020 MDIO_PMA_DEVAD,
8021 MDIO_PMA_REG_8727_PCS_GP, val1);
8022 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008023 return link_up;
8024}
8025
8026static void bnx2x_8727_link_reset(struct bnx2x_phy *phy,
8027 struct link_params *params)
8028{
8029 struct bnx2x *bp = params->bp;
8030 /* Disable Transmitter */
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00008031 bnx2x_sfp_set_transmitter(params, phy, 0);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008032 /* Clear LASI */
8033 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0);
8034
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008035}
8036
8037/******************************************************************/
8038/* BCM8481/BCM84823/BCM84833 PHY SECTION */
8039/******************************************************************/
8040static void bnx2x_save_848xx_spirom_version(struct bnx2x_phy *phy,
8041 struct link_params *params)
8042{
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008043 u16 val, fw_ver1, fw_ver2, cnt;
8044 u8 port;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008045 struct bnx2x *bp = params->bp;
8046
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008047 port = params->port;
Yaniv Rosnerc87bca12011-01-31 04:22:41 +00008048
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008049 /* For the 32 bits registers in 848xx, access via MDIO2ARM interface.*/
8050 /* (1) set register 0xc200_0014(SPI_BRIDGE_CTRL_2) to 0x03000000 */
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008051 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0014);
8052 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200);
8053 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81B, 0x0000);
8054 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81C, 0x0300);
8055 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x0009);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008056
8057 for (cnt = 0; cnt < 100; cnt++) {
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008058 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008059 if (val & 1)
8060 break;
8061 udelay(5);
8062 }
8063 if (cnt == 100) {
8064 DP(NETIF_MSG_LINK, "Unable to read 848xx phy fw version(1)\n");
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008065 bnx2x_save_spirom_version(bp, port, 0,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008066 phy->ver_addr);
8067 return;
8068 }
8069
8070
8071 /* 2) read register 0xc200_0000 (SPI_FW_STATUS) */
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008072 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0000);
8073 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200);
8074 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x000A);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008075 for (cnt = 0; cnt < 100; cnt++) {
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008076 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008077 if (val & 1)
8078 break;
8079 udelay(5);
8080 }
8081 if (cnt == 100) {
8082 DP(NETIF_MSG_LINK, "Unable to read 848xx phy fw version(2)\n");
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008083 bnx2x_save_spirom_version(bp, port, 0,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008084 phy->ver_addr);
8085 return;
8086 }
8087
8088 /* lower 16 bits of the register SPI_FW_STATUS */
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008089 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81B, &fw_ver1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008090 /* upper 16 bits of register SPI_FW_STATUS */
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008091 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81C, &fw_ver2);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008092
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008093 bnx2x_save_spirom_version(bp, port, (fw_ver2<<16) | fw_ver1,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008094 phy->ver_addr);
8095}
8096
8097static void bnx2x_848xx_set_led(struct bnx2x *bp,
8098 struct bnx2x_phy *phy)
8099{
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008100 u16 val;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008101
8102 /* PHYC_CTL_LED_CTL */
8103 bnx2x_cl45_read(bp, phy,
8104 MDIO_PMA_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008105 MDIO_PMA_REG_8481_LINK_SIGNAL, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008106 val &= 0xFE00;
8107 val |= 0x0092;
8108
8109 bnx2x_cl45_write(bp, phy,
8110 MDIO_PMA_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008111 MDIO_PMA_REG_8481_LINK_SIGNAL, val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008112
8113 bnx2x_cl45_write(bp, phy,
8114 MDIO_PMA_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008115 MDIO_PMA_REG_8481_LED1_MASK,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008116 0x80);
8117
8118 bnx2x_cl45_write(bp, phy,
8119 MDIO_PMA_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008120 MDIO_PMA_REG_8481_LED2_MASK,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008121 0x18);
8122
Yaniv Rosnerf25b3c82011-01-18 04:33:47 +00008123 /* Select activity source by Tx and Rx, as suggested by PHY AE */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008124 bnx2x_cl45_write(bp, phy,
8125 MDIO_PMA_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008126 MDIO_PMA_REG_8481_LED3_MASK,
Yaniv Rosnerf25b3c82011-01-18 04:33:47 +00008127 0x0006);
8128
8129 /* Select the closest activity blink rate to that in 10/100/1000 */
8130 bnx2x_cl45_write(bp, phy,
8131 MDIO_PMA_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008132 MDIO_PMA_REG_8481_LED3_BLINK,
Yaniv Rosnerf25b3c82011-01-18 04:33:47 +00008133 0);
8134
8135 bnx2x_cl45_read(bp, phy,
8136 MDIO_PMA_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008137 MDIO_PMA_REG_84823_CTL_LED_CTL_1, &val);
Yaniv Rosnerf25b3c82011-01-18 04:33:47 +00008138 val |= MDIO_PMA_REG_84823_LED3_STRETCH_EN; /* stretch_en for LED3*/
8139
8140 bnx2x_cl45_write(bp, phy,
8141 MDIO_PMA_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008142 MDIO_PMA_REG_84823_CTL_LED_CTL_1, val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008143
8144 /* 'Interrupt Mask' */
8145 bnx2x_cl45_write(bp, phy,
8146 MDIO_AN_DEVAD,
8147 0xFFFB, 0xFFFD);
8148}
8149
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00008150static int bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy,
8151 struct link_params *params,
8152 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008153{
8154 struct bnx2x *bp = params->bp;
8155 u16 autoneg_val, an_1000_val, an_10_100_val;
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008156 u16 tmp_req_line_speed;
8157
8158 tmp_req_line_speed = phy->req_line_speed;
8159 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833)
8160 if (phy->req_line_speed == SPEED_10000)
8161 phy->req_line_speed = SPEED_AUTO_NEG;
8162
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008163 /*
8164 * This phy uses the NIG latch mechanism since link indication
8165 * arrives through its LED4 and not via its LASI signal, so we
8166 * get steady signal instead of clear on read
8167 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008168 bnx2x_bits_en(bp, NIG_REG_LATCH_BC_0 + params->port*4,
8169 1 << NIG_LATCH_BC_ENABLE_MI_INT);
8170
8171 bnx2x_cl45_write(bp, phy,
8172 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x0000);
8173
8174 bnx2x_848xx_set_led(bp, phy);
8175
8176 /* set 1000 speed advertisement */
8177 bnx2x_cl45_read(bp, phy,
8178 MDIO_AN_DEVAD, MDIO_AN_REG_8481_1000T_CTRL,
8179 &an_1000_val);
8180
8181 bnx2x_ext_phy_set_pause(params, phy, vars);
8182 bnx2x_cl45_read(bp, phy,
8183 MDIO_AN_DEVAD,
8184 MDIO_AN_REG_8481_LEGACY_AN_ADV,
8185 &an_10_100_val);
8186 bnx2x_cl45_read(bp, phy,
8187 MDIO_AN_DEVAD, MDIO_AN_REG_8481_LEGACY_MII_CTRL,
8188 &autoneg_val);
8189 /* Disable forced speed */
8190 autoneg_val &= ~((1<<6) | (1<<8) | (1<<9) | (1<<12) | (1<<13));
8191 an_10_100_val &= ~((1<<5) | (1<<6) | (1<<7) | (1<<8));
8192
8193 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
8194 (phy->speed_cap_mask &
8195 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) ||
8196 (phy->req_line_speed == SPEED_1000)) {
8197 an_1000_val |= (1<<8);
8198 autoneg_val |= (1<<9 | 1<<12);
8199 if (phy->req_duplex == DUPLEX_FULL)
8200 an_1000_val |= (1<<9);
8201 DP(NETIF_MSG_LINK, "Advertising 1G\n");
8202 } else
8203 an_1000_val &= ~((1<<8) | (1<<9));
8204
8205 bnx2x_cl45_write(bp, phy,
8206 MDIO_AN_DEVAD, MDIO_AN_REG_8481_1000T_CTRL,
8207 an_1000_val);
8208
8209 /* set 10 speed advertisement */
8210 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
8211 (phy->speed_cap_mask &
8212 (PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL |
8213 PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF)))) {
8214 an_10_100_val |= (1<<7);
8215 /* Enable autoneg and restart autoneg for legacy speeds */
8216 autoneg_val |= (1<<9 | 1<<12);
8217
8218 if (phy->req_duplex == DUPLEX_FULL)
8219 an_10_100_val |= (1<<8);
8220 DP(NETIF_MSG_LINK, "Advertising 100M\n");
8221 }
8222 /* set 10 speed advertisement */
8223 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
8224 (phy->speed_cap_mask &
8225 (PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL |
8226 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF)))) {
8227 an_10_100_val |= (1<<5);
8228 autoneg_val |= (1<<9 | 1<<12);
8229 if (phy->req_duplex == DUPLEX_FULL)
8230 an_10_100_val |= (1<<6);
8231 DP(NETIF_MSG_LINK, "Advertising 10M\n");
8232 }
8233
8234 /* Only 10/100 are allowed to work in FORCE mode */
8235 if (phy->req_line_speed == SPEED_100) {
8236 autoneg_val |= (1<<13);
8237 /* Enabled AUTO-MDIX when autoneg is disabled */
8238 bnx2x_cl45_write(bp, phy,
8239 MDIO_AN_DEVAD, MDIO_AN_REG_8481_AUX_CTRL,
8240 (1<<15 | 1<<9 | 7<<0));
8241 DP(NETIF_MSG_LINK, "Setting 100M force\n");
8242 }
8243 if (phy->req_line_speed == SPEED_10) {
8244 /* Enabled AUTO-MDIX when autoneg is disabled */
8245 bnx2x_cl45_write(bp, phy,
8246 MDIO_AN_DEVAD, MDIO_AN_REG_8481_AUX_CTRL,
8247 (1<<15 | 1<<9 | 7<<0));
8248 DP(NETIF_MSG_LINK, "Setting 10M force\n");
8249 }
8250
8251 bnx2x_cl45_write(bp, phy,
8252 MDIO_AN_DEVAD, MDIO_AN_REG_8481_LEGACY_AN_ADV,
8253 an_10_100_val);
8254
8255 if (phy->req_duplex == DUPLEX_FULL)
8256 autoneg_val |= (1<<8);
8257
8258 bnx2x_cl45_write(bp, phy,
8259 MDIO_AN_DEVAD,
8260 MDIO_AN_REG_8481_LEGACY_MII_CTRL, autoneg_val);
8261
8262 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
8263 (phy->speed_cap_mask &
8264 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) ||
8265 (phy->req_line_speed == SPEED_10000)) {
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00008266 DP(NETIF_MSG_LINK, "Advertising 10G\n");
8267 /* Restart autoneg for 10G*/
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008268
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00008269 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008270 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL,
8271 0x3200);
8272 } else if (phy->req_line_speed != SPEED_10 &&
8273 phy->req_line_speed != SPEED_100) {
8274 bnx2x_cl45_write(bp, phy,
8275 MDIO_AN_DEVAD,
8276 MDIO_AN_REG_8481_10GBASE_T_AN_CTRL,
8277 1);
8278 }
8279 /* Save spirom version */
8280 bnx2x_save_848xx_spirom_version(phy, params);
8281
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008282 phy->req_line_speed = tmp_req_line_speed;
8283
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008284 return 0;
8285}
8286
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00008287static int bnx2x_8481_config_init(struct bnx2x_phy *phy,
8288 struct link_params *params,
8289 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008290{
8291 struct bnx2x *bp = params->bp;
8292 /* Restore normal power mode*/
8293 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008294 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008295
8296 /* HW reset */
8297 bnx2x_ext_phy_hw_reset(bp, params->port);
Yaniv Rosner6d870c32011-01-31 04:22:20 +00008298 bnx2x_wait_reset_complete(bp, phy, params);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008299
8300 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
8301 return bnx2x_848xx_cmn_config_init(phy, params, vars);
8302}
8303
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008304
8305#define PHY84833_HDSHK_WAIT 300
8306static int bnx2x_84833_pair_swap_cfg(struct bnx2x_phy *phy,
8307 struct link_params *params,
8308 struct link_vars *vars)
8309{
8310 u32 idx;
8311 u16 val;
8312 u16 data = 0x01b1;
8313 struct bnx2x *bp = params->bp;
8314 /* Do pair swap */
8315
8316
8317 /* Write CMD_OPEN_OVERRIDE to STATUS reg */
8318 bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
8319 MDIO_84833_TOP_CFG_SCRATCH_REG2,
8320 PHY84833_CMD_OPEN_OVERRIDE);
8321 for (idx = 0; idx < PHY84833_HDSHK_WAIT; idx++) {
8322 bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
8323 MDIO_84833_TOP_CFG_SCRATCH_REG2, &val);
8324 if (val == PHY84833_CMD_OPEN_FOR_CMDS)
8325 break;
8326 msleep(1);
8327 }
8328 if (idx >= PHY84833_HDSHK_WAIT) {
8329 DP(NETIF_MSG_LINK, "Pairswap: FW not ready.\n");
8330 return -EINVAL;
8331 }
8332
8333 bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
8334 MDIO_84833_TOP_CFG_SCRATCH_REG4,
8335 data);
8336 /* Issue pair swap command */
8337 bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
8338 MDIO_84833_TOP_CFG_SCRATCH_REG0,
8339 PHY84833_DIAG_CMD_PAIR_SWAP_CHANGE);
8340 for (idx = 0; idx < PHY84833_HDSHK_WAIT; idx++) {
8341 bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
8342 MDIO_84833_TOP_CFG_SCRATCH_REG2, &val);
8343 if ((val == PHY84833_CMD_COMPLETE_PASS) ||
8344 (val == PHY84833_CMD_COMPLETE_ERROR))
8345 break;
8346 msleep(1);
8347 }
8348 if ((idx >= PHY84833_HDSHK_WAIT) ||
8349 (val == PHY84833_CMD_COMPLETE_ERROR)) {
8350 DP(NETIF_MSG_LINK, "Pairswap: override failed.\n");
8351 return -EINVAL;
8352 }
8353 bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
8354 MDIO_84833_TOP_CFG_SCRATCH_REG2,
8355 PHY84833_CMD_CLEAR_COMPLETE);
8356 DP(NETIF_MSG_LINK, "Pairswap OK, val=0x%x\n", data);
8357 return 0;
8358}
8359
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00008360static int bnx2x_848x3_config_init(struct bnx2x_phy *phy,
8361 struct link_params *params,
8362 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008363{
8364 struct bnx2x *bp = params->bp;
Yaniv Rosner6a71bbe2010-11-01 05:32:31 +00008365 u8 port, initialize = 1;
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008366 u16 val;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008367 u16 temp;
Yaniv Rosner1bef68e2011-01-31 04:22:46 +00008368 u32 actual_phy_selection, cms_enable;
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00008369 int rc = 0;
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00008370
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008371 msleep(1);
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008372
8373 if (!(CHIP_IS_E1(bp)))
Yaniv Rosner6a71bbe2010-11-01 05:32:31 +00008374 port = BP_PATH(bp);
8375 else
8376 port = params->port;
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008377
8378 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823) {
8379 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
8380 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
8381 port);
8382 } else {
8383 bnx2x_cl45_write(bp, phy,
8384 MDIO_PMA_DEVAD,
8385 MDIO_PMA_REG_CTRL, 0x8000);
8386 }
8387
Yaniv Rosner6d870c32011-01-31 04:22:20 +00008388 bnx2x_wait_reset_complete(bp, phy, params);
Yaniv Rosner9bffeac2010-11-01 05:32:27 +00008389 /* Wait for GPHY to come out of reset */
8390 msleep(50);
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008391
8392 /* Bring PHY out of super isolate mode */
8393 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) {
8394 bnx2x_cl45_read(bp, phy,
8395 MDIO_CTL_DEVAD,
8396 MDIO_84833_TOP_CFG_XGPHY_STRAP1, &val);
8397 val &= ~MDIO_84833_SUPER_ISOLATE;
8398 bnx2x_cl45_write(bp, phy,
8399 MDIO_CTL_DEVAD,
8400 MDIO_84833_TOP_CFG_XGPHY_STRAP1, val);
8401 bnx2x_wait_reset_complete(bp, phy, params);
8402 }
8403
8404 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833)
8405 bnx2x_84833_pair_swap_cfg(phy, params, vars);
8406
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008407 /*
8408 * BCM84823 requires that XGXS links up first @ 10G for normal behavior
8409 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008410 temp = vars->line_speed;
8411 vars->line_speed = SPEED_10000;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008412 bnx2x_set_autoneg(&params->phy[INT_PHY], params, vars, 0);
8413 bnx2x_program_serdes(&params->phy[INT_PHY], params, vars);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008414 vars->line_speed = temp;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008415
8416 /* Set dual-media configuration according to configuration */
8417
8418 bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008419 MDIO_CTL_REG_84823_MEDIA, &val);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008420 val &= ~(MDIO_CTL_REG_84823_MEDIA_MAC_MASK |
8421 MDIO_CTL_REG_84823_MEDIA_LINE_MASK |
8422 MDIO_CTL_REG_84823_MEDIA_COPPER_CORE_DOWN |
8423 MDIO_CTL_REG_84823_MEDIA_PRIORITY_MASK |
8424 MDIO_CTL_REG_84823_MEDIA_FIBER_1G);
8425 val |= MDIO_CTL_REG_84823_CTRL_MAC_XFI |
8426 MDIO_CTL_REG_84823_MEDIA_LINE_XAUI_L;
8427
8428 actual_phy_selection = bnx2x_phy_selection(params);
8429
8430 switch (actual_phy_selection) {
8431 case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT:
Lucas De Marchi25985ed2011-03-30 22:57:33 -03008432 /* Do nothing. Essentially this is like the priority copper */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008433 break;
8434 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
8435 val |= MDIO_CTL_REG_84823_MEDIA_PRIORITY_COPPER;
8436 break;
8437 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
8438 val |= MDIO_CTL_REG_84823_MEDIA_PRIORITY_FIBER;
8439 break;
8440 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY:
8441 /* Do nothing here. The first PHY won't be initialized at all */
8442 break;
8443 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY:
8444 val |= MDIO_CTL_REG_84823_MEDIA_COPPER_CORE_DOWN;
8445 initialize = 0;
8446 break;
8447 }
8448 if (params->phy[EXT_PHY2].req_line_speed == SPEED_1000)
8449 val |= MDIO_CTL_REG_84823_MEDIA_FIBER_1G;
8450
8451 bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008452 MDIO_CTL_REG_84823_MEDIA, val);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008453 DP(NETIF_MSG_LINK, "Multi_phy config = 0x%x, Media control = 0x%x\n",
8454 params->multi_phy_config, val);
8455
8456 if (initialize)
8457 rc = bnx2x_848xx_cmn_config_init(phy, params, vars);
8458 else
8459 bnx2x_save_848xx_spirom_version(phy, params);
Yaniv Rosner1bef68e2011-01-31 04:22:46 +00008460 cms_enable = REG_RD(bp, params->shmem_base +
8461 offsetof(struct shmem_region,
8462 dev_info.port_hw_config[params->port].default_cfg)) &
8463 PORT_HW_CFG_ENABLE_CMS_MASK;
8464
8465 bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
8466 MDIO_CTL_REG_84823_USER_CTRL_REG, &val);
8467 if (cms_enable)
8468 val |= MDIO_CTL_REG_84823_USER_CTRL_CMS;
8469 else
8470 val &= ~MDIO_CTL_REG_84823_USER_CTRL_CMS;
8471 bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
8472 MDIO_CTL_REG_84823_USER_CTRL_REG, val);
8473
8474
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008475 return rc;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008476}
8477
8478static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008479 struct link_params *params,
8480 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008481{
8482 struct bnx2x *bp = params->bp;
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008483 u16 val, val1, val2;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008484 u8 link_up = 0;
8485
Yaniv Rosnerc87bca12011-01-31 04:22:41 +00008486
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008487 /* Check 10G-BaseT link status */
8488 /* Check PMD signal ok */
8489 bnx2x_cl45_read(bp, phy,
8490 MDIO_AN_DEVAD, 0xFFFA, &val1);
8491 bnx2x_cl45_read(bp, phy,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008492 MDIO_PMA_DEVAD, MDIO_PMA_REG_8481_PMD_SIGNAL,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008493 &val2);
8494 DP(NETIF_MSG_LINK, "BCM848xx: PMD_SIGNAL 1.a811 = 0x%x\n", val2);
8495
8496 /* Check link 10G */
8497 if (val2 & (1<<11)) {
8498 vars->line_speed = SPEED_10000;
Yaniv Rosner791f18c2011-01-18 04:33:42 +00008499 vars->duplex = DUPLEX_FULL;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008500 link_up = 1;
8501 bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
8502 } else { /* Check Legacy speed link */
8503 u16 legacy_status, legacy_speed;
8504
8505 /* Enable expansion register 0x42 (Operation mode status) */
8506 bnx2x_cl45_write(bp, phy,
8507 MDIO_AN_DEVAD,
8508 MDIO_AN_REG_8481_EXPANSION_REG_ACCESS, 0xf42);
8509
8510 /* Get legacy speed operation status */
8511 bnx2x_cl45_read(bp, phy,
8512 MDIO_AN_DEVAD,
8513 MDIO_AN_REG_8481_EXPANSION_REG_RD_RW,
8514 &legacy_status);
8515
8516 DP(NETIF_MSG_LINK, "Legacy speed status"
8517 " = 0x%x\n", legacy_status);
8518 link_up = ((legacy_status & (1<<11)) == (1<<11));
8519 if (link_up) {
8520 legacy_speed = (legacy_status & (3<<9));
8521 if (legacy_speed == (0<<9))
8522 vars->line_speed = SPEED_10;
8523 else if (legacy_speed == (1<<9))
8524 vars->line_speed = SPEED_100;
8525 else if (legacy_speed == (2<<9))
8526 vars->line_speed = SPEED_1000;
8527 else /* Should not happen */
8528 vars->line_speed = 0;
8529
8530 if (legacy_status & (1<<8))
8531 vars->duplex = DUPLEX_FULL;
8532 else
8533 vars->duplex = DUPLEX_HALF;
8534
8535 DP(NETIF_MSG_LINK, "Link is up in %dMbps,"
8536 " is_duplex_full= %d\n", vars->line_speed,
8537 (vars->duplex == DUPLEX_FULL));
8538 /* Check legacy speed AN resolution */
8539 bnx2x_cl45_read(bp, phy,
8540 MDIO_AN_DEVAD,
8541 MDIO_AN_REG_8481_LEGACY_MII_STATUS,
8542 &val);
8543 if (val & (1<<5))
8544 vars->link_status |=
8545 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
8546 bnx2x_cl45_read(bp, phy,
8547 MDIO_AN_DEVAD,
8548 MDIO_AN_REG_8481_LEGACY_AN_EXPANSION,
8549 &val);
8550 if ((val & (1<<0)) == 0)
8551 vars->link_status |=
8552 LINK_STATUS_PARALLEL_DETECTION_USED;
8553 }
8554 }
8555 if (link_up) {
8556 DP(NETIF_MSG_LINK, "BCM84823: link speed is %d\n",
8557 vars->line_speed);
8558 bnx2x_ext_phy_resolve_fc(phy, params, vars);
8559 }
8560
8561 return link_up;
8562}
8563
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00008564
8565static int bnx2x_848xx_format_ver(u32 raw_ver, u8 *str, u16 *len)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008566{
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00008567 int status = 0;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008568 u32 spirom_ver;
8569 spirom_ver = ((raw_ver & 0xF80) >> 7) << 16 | (raw_ver & 0x7F);
8570 status = bnx2x_format_ver(spirom_ver, str, len);
8571 return status;
8572}
8573
8574static void bnx2x_8481_hw_reset(struct bnx2x_phy *phy,
8575 struct link_params *params)
8576{
8577 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008578 MISC_REGISTERS_GPIO_OUTPUT_LOW, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008579 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008580 MISC_REGISTERS_GPIO_OUTPUT_LOW, 1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008581}
8582
8583static void bnx2x_8481_link_reset(struct bnx2x_phy *phy,
8584 struct link_params *params)
8585{
8586 bnx2x_cl45_write(params->bp, phy,
8587 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x0000);
8588 bnx2x_cl45_write(params->bp, phy,
8589 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1);
8590}
8591
8592static void bnx2x_848x3_link_reset(struct bnx2x_phy *phy,
8593 struct link_params *params)
8594{
8595 struct bnx2x *bp = params->bp;
Yaniv Rosner6a71bbe2010-11-01 05:32:31 +00008596 u8 port;
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008597
8598 if (!(CHIP_IS_E1(bp)))
Yaniv Rosner6a71bbe2010-11-01 05:32:31 +00008599 port = BP_PATH(bp);
8600 else
8601 port = params->port;
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008602
8603 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823) {
8604 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
8605 MISC_REGISTERS_GPIO_OUTPUT_LOW,
8606 port);
8607 } else {
8608 bnx2x_cl45_write(bp, phy,
8609 MDIO_PMA_DEVAD,
8610 MDIO_PMA_REG_CTRL, 0x800);
8611 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008612}
8613
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00008614static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy,
8615 struct link_params *params, u8 mode)
8616{
8617 struct bnx2x *bp = params->bp;
8618 u16 val;
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008619 u8 port;
8620
8621 if (!(CHIP_IS_E1(bp)))
8622 port = BP_PATH(bp);
8623 else
8624 port = params->port;
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00008625
8626 switch (mode) {
8627 case LED_MODE_OFF:
8628
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008629 DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE OFF\n", port);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00008630
8631 if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
8632 SHARED_HW_CFG_LED_EXTPHY1) {
8633
8634 /* Set LED masks */
8635 bnx2x_cl45_write(bp, phy,
8636 MDIO_PMA_DEVAD,
8637 MDIO_PMA_REG_8481_LED1_MASK,
8638 0x0);
8639
8640 bnx2x_cl45_write(bp, phy,
8641 MDIO_PMA_DEVAD,
8642 MDIO_PMA_REG_8481_LED2_MASK,
8643 0x0);
8644
8645 bnx2x_cl45_write(bp, phy,
8646 MDIO_PMA_DEVAD,
8647 MDIO_PMA_REG_8481_LED3_MASK,
8648 0x0);
8649
8650 bnx2x_cl45_write(bp, phy,
8651 MDIO_PMA_DEVAD,
8652 MDIO_PMA_REG_8481_LED5_MASK,
8653 0x0);
8654
8655 } else {
8656 bnx2x_cl45_write(bp, phy,
8657 MDIO_PMA_DEVAD,
8658 MDIO_PMA_REG_8481_LED1_MASK,
8659 0x0);
8660 }
8661 break;
8662 case LED_MODE_FRONT_PANEL_OFF:
8663
8664 DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE FRONT PANEL OFF\n",
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008665 port);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00008666
8667 if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
8668 SHARED_HW_CFG_LED_EXTPHY1) {
8669
8670 /* Set LED masks */
8671 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008672 MDIO_PMA_DEVAD,
8673 MDIO_PMA_REG_8481_LED1_MASK,
8674 0x0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00008675
8676 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008677 MDIO_PMA_DEVAD,
8678 MDIO_PMA_REG_8481_LED2_MASK,
8679 0x0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00008680
8681 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008682 MDIO_PMA_DEVAD,
8683 MDIO_PMA_REG_8481_LED3_MASK,
8684 0x0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00008685
8686 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008687 MDIO_PMA_DEVAD,
8688 MDIO_PMA_REG_8481_LED5_MASK,
8689 0x20);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00008690
8691 } else {
8692 bnx2x_cl45_write(bp, phy,
8693 MDIO_PMA_DEVAD,
8694 MDIO_PMA_REG_8481_LED1_MASK,
8695 0x0);
8696 }
8697 break;
8698 case LED_MODE_ON:
8699
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008700 DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE ON\n", port);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00008701
8702 if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
8703 SHARED_HW_CFG_LED_EXTPHY1) {
8704 /* Set control reg */
8705 bnx2x_cl45_read(bp, phy,
8706 MDIO_PMA_DEVAD,
8707 MDIO_PMA_REG_8481_LINK_SIGNAL,
8708 &val);
8709 val &= 0x8000;
8710 val |= 0x2492;
8711
8712 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008713 MDIO_PMA_DEVAD,
8714 MDIO_PMA_REG_8481_LINK_SIGNAL,
8715 val);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00008716
8717 /* Set LED masks */
8718 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008719 MDIO_PMA_DEVAD,
8720 MDIO_PMA_REG_8481_LED1_MASK,
8721 0x0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00008722
8723 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008724 MDIO_PMA_DEVAD,
8725 MDIO_PMA_REG_8481_LED2_MASK,
8726 0x20);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00008727
8728 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008729 MDIO_PMA_DEVAD,
8730 MDIO_PMA_REG_8481_LED3_MASK,
8731 0x20);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00008732
8733 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008734 MDIO_PMA_DEVAD,
8735 MDIO_PMA_REG_8481_LED5_MASK,
8736 0x0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00008737 } else {
8738 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008739 MDIO_PMA_DEVAD,
8740 MDIO_PMA_REG_8481_LED1_MASK,
8741 0x20);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00008742 }
8743 break;
8744
8745 case LED_MODE_OPER:
8746
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008747 DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE OPER\n", port);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00008748
8749 if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
8750 SHARED_HW_CFG_LED_EXTPHY1) {
8751
8752 /* Set control reg */
8753 bnx2x_cl45_read(bp, phy,
8754 MDIO_PMA_DEVAD,
8755 MDIO_PMA_REG_8481_LINK_SIGNAL,
8756 &val);
8757
8758 if (!((val &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008759 MDIO_PMA_REG_8481_LINK_SIGNAL_LED4_ENABLE_MASK)
8760 >> MDIO_PMA_REG_8481_LINK_SIGNAL_LED4_ENABLE_SHIFT)) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008761 DP(NETIF_MSG_LINK, "Setting LINK_SIGNAL\n");
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00008762 bnx2x_cl45_write(bp, phy,
8763 MDIO_PMA_DEVAD,
8764 MDIO_PMA_REG_8481_LINK_SIGNAL,
8765 0xa492);
8766 }
8767
8768 /* Set LED masks */
8769 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008770 MDIO_PMA_DEVAD,
8771 MDIO_PMA_REG_8481_LED1_MASK,
8772 0x10);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00008773
8774 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008775 MDIO_PMA_DEVAD,
8776 MDIO_PMA_REG_8481_LED2_MASK,
8777 0x80);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00008778
8779 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008780 MDIO_PMA_DEVAD,
8781 MDIO_PMA_REG_8481_LED3_MASK,
8782 0x98);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00008783
8784 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008785 MDIO_PMA_DEVAD,
8786 MDIO_PMA_REG_8481_LED5_MASK,
8787 0x40);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00008788
8789 } else {
8790 bnx2x_cl45_write(bp, phy,
8791 MDIO_PMA_DEVAD,
8792 MDIO_PMA_REG_8481_LED1_MASK,
8793 0x80);
Yaniv Rosner53eda062011-01-30 04:14:55 +00008794
8795 /* Tell LED3 to blink on source */
8796 bnx2x_cl45_read(bp, phy,
8797 MDIO_PMA_DEVAD,
8798 MDIO_PMA_REG_8481_LINK_SIGNAL,
8799 &val);
8800 val &= ~(7<<6);
8801 val |= (1<<6); /* A83B[8:6]= 1 */
8802 bnx2x_cl45_write(bp, phy,
8803 MDIO_PMA_DEVAD,
8804 MDIO_PMA_REG_8481_LINK_SIGNAL,
8805 val);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00008806 }
8807 break;
8808 }
8809}
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008810/******************************************************************/
8811/* SFX7101 PHY SECTION */
8812/******************************************************************/
8813static void bnx2x_7101_config_loopback(struct bnx2x_phy *phy,
8814 struct link_params *params)
8815{
8816 struct bnx2x *bp = params->bp;
8817 /* SFX7101_XGXS_TEST1 */
8818 bnx2x_cl45_write(bp, phy,
8819 MDIO_XS_DEVAD, MDIO_XS_SFX7101_XGXS_TEST1, 0x100);
8820}
8821
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00008822static int bnx2x_7101_config_init(struct bnx2x_phy *phy,
8823 struct link_params *params,
8824 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008825{
8826 u16 fw_ver1, fw_ver2, val;
8827 struct bnx2x *bp = params->bp;
8828 DP(NETIF_MSG_LINK, "Setting the SFX7101 LASI indication\n");
8829
8830 /* Restore normal power mode*/
8831 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008832 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008833 /* HW reset */
8834 bnx2x_ext_phy_hw_reset(bp, params->port);
Yaniv Rosner6d870c32011-01-31 04:22:20 +00008835 bnx2x_wait_reset_complete(bp, phy, params);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008836
8837 bnx2x_cl45_write(bp, phy,
8838 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x1);
8839 DP(NETIF_MSG_LINK, "Setting the SFX7101 LED to blink on traffic\n");
8840 bnx2x_cl45_write(bp, phy,
8841 MDIO_PMA_DEVAD, MDIO_PMA_REG_7107_LED_CNTL, (1<<3));
8842
8843 bnx2x_ext_phy_set_pause(params, phy, vars);
8844 /* Restart autoneg */
8845 bnx2x_cl45_read(bp, phy,
8846 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, &val);
8847 val |= 0x200;
8848 bnx2x_cl45_write(bp, phy,
8849 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, val);
8850
8851 /* Save spirom version */
8852 bnx2x_cl45_read(bp, phy,
8853 MDIO_PMA_DEVAD, MDIO_PMA_REG_7101_VER1, &fw_ver1);
8854
8855 bnx2x_cl45_read(bp, phy,
8856 MDIO_PMA_DEVAD, MDIO_PMA_REG_7101_VER2, &fw_ver2);
8857 bnx2x_save_spirom_version(bp, params->port,
8858 (u32)(fw_ver1<<16 | fw_ver2), phy->ver_addr);
8859 return 0;
8860}
8861
8862static u8 bnx2x_7101_read_status(struct bnx2x_phy *phy,
8863 struct link_params *params,
8864 struct link_vars *vars)
8865{
8866 struct bnx2x *bp = params->bp;
8867 u8 link_up;
8868 u16 val1, val2;
8869 bnx2x_cl45_read(bp, phy,
8870 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val2);
8871 bnx2x_cl45_read(bp, phy,
8872 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
8873 DP(NETIF_MSG_LINK, "10G-base-T LASI status 0x%x->0x%x\n",
8874 val2, val1);
8875 bnx2x_cl45_read(bp, phy,
8876 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
8877 bnx2x_cl45_read(bp, phy,
8878 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
8879 DP(NETIF_MSG_LINK, "10G-base-T PMA status 0x%x->0x%x\n",
8880 val2, val1);
8881 link_up = ((val1 & 4) == 4);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008882 /* if link is up print the AN outcome of the SFX7101 PHY */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008883 if (link_up) {
8884 bnx2x_cl45_read(bp, phy,
8885 MDIO_AN_DEVAD, MDIO_AN_REG_MASTER_STATUS,
8886 &val2);
8887 vars->line_speed = SPEED_10000;
Yaniv Rosner791f18c2011-01-18 04:33:42 +00008888 vars->duplex = DUPLEX_FULL;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008889 DP(NETIF_MSG_LINK, "SFX7101 AN status 0x%x->Master=%x\n",
8890 val2, (val2 & (1<<14)));
8891 bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
8892 bnx2x_ext_phy_resolve_fc(phy, params, vars);
8893 }
8894 return link_up;
8895}
8896
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00008897static int bnx2x_7101_format_ver(u32 spirom_ver, u8 *str, u16 *len)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008898{
8899 if (*len < 5)
8900 return -EINVAL;
8901 str[0] = (spirom_ver & 0xFF);
8902 str[1] = (spirom_ver & 0xFF00) >> 8;
8903 str[2] = (spirom_ver & 0xFF0000) >> 16;
8904 str[3] = (spirom_ver & 0xFF000000) >> 24;
8905 str[4] = '\0';
8906 *len -= 5;
8907 return 0;
8908}
8909
8910void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, struct bnx2x_phy *phy)
8911{
8912 u16 val, cnt;
8913
8914 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008915 MDIO_PMA_DEVAD,
8916 MDIO_PMA_REG_7101_RESET, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008917
8918 for (cnt = 0; cnt < 10; cnt++) {
8919 msleep(50);
8920 /* Writes a self-clearing reset */
8921 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008922 MDIO_PMA_DEVAD,
8923 MDIO_PMA_REG_7101_RESET,
8924 (val | (1<<15)));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008925 /* Wait for clear */
8926 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008927 MDIO_PMA_DEVAD,
8928 MDIO_PMA_REG_7101_RESET, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008929
8930 if ((val & (1<<15)) == 0)
8931 break;
8932 }
8933}
8934
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00008935static void bnx2x_7101_hw_reset(struct bnx2x_phy *phy,
8936 struct link_params *params) {
8937 /* Low power mode is controlled by GPIO 2 */
8938 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008939 MISC_REGISTERS_GPIO_OUTPUT_LOW, params->port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00008940 /* The PHY reset is controlled by GPIO 1 */
8941 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008942 MISC_REGISTERS_GPIO_OUTPUT_LOW, params->port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00008943}
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008944
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00008945static void bnx2x_7101_set_link_led(struct bnx2x_phy *phy,
8946 struct link_params *params, u8 mode)
8947{
8948 u16 val = 0;
8949 struct bnx2x *bp = params->bp;
8950 switch (mode) {
8951 case LED_MODE_FRONT_PANEL_OFF:
8952 case LED_MODE_OFF:
8953 val = 2;
8954 break;
8955 case LED_MODE_ON:
8956 val = 1;
8957 break;
8958 case LED_MODE_OPER:
8959 val = 0;
8960 break;
8961 }
8962 bnx2x_cl45_write(bp, phy,
8963 MDIO_PMA_DEVAD,
8964 MDIO_PMA_REG_7107_LINK_LED_CNTL,
8965 val);
8966}
8967
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00008968/******************************************************************/
8969/* STATIC PHY DECLARATION */
8970/******************************************************************/
8971
8972static struct bnx2x_phy phy_null = {
8973 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN,
8974 .addr = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00008975 .def_md_devad = 0,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00008976 .flags = FLAGS_INIT_XGXS_FIRST,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00008977 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
8978 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
8979 .mdio_ctrl = 0,
8980 .supported = 0,
8981 .media_type = ETH_PHY_NOT_PRESENT,
8982 .ver_addr = 0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008983 .req_flow_ctrl = 0,
8984 .req_line_speed = 0,
8985 .speed_cap_mask = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00008986 .req_duplex = 0,
8987 .rsrv = 0,
8988 .config_init = (config_init_t)NULL,
8989 .read_status = (read_status_t)NULL,
8990 .link_reset = (link_reset_t)NULL,
8991 .config_loopback = (config_loopback_t)NULL,
8992 .format_fw_ver = (format_fw_ver_t)NULL,
8993 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008994 .set_link_led = (set_link_led_t)NULL,
8995 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00008996};
8997
8998static struct bnx2x_phy phy_serdes = {
8999 .type = PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT,
9000 .addr = 0xff,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009001 .def_md_devad = 0,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00009002 .flags = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009003 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
9004 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
9005 .mdio_ctrl = 0,
9006 .supported = (SUPPORTED_10baseT_Half |
9007 SUPPORTED_10baseT_Full |
9008 SUPPORTED_100baseT_Half |
9009 SUPPORTED_100baseT_Full |
9010 SUPPORTED_1000baseT_Full |
9011 SUPPORTED_2500baseX_Full |
9012 SUPPORTED_TP |
9013 SUPPORTED_Autoneg |
9014 SUPPORTED_Pause |
9015 SUPPORTED_Asym_Pause),
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00009016 .media_type = ETH_PHY_BASE_T,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009017 .ver_addr = 0,
9018 .req_flow_ctrl = 0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00009019 .req_line_speed = 0,
9020 .speed_cap_mask = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009021 .req_duplex = 0,
9022 .rsrv = 0,
Yaniv Rosnerec146a62011-05-31 21:29:27 +00009023 .config_init = (config_init_t)bnx2x_xgxs_config_init,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009024 .read_status = (read_status_t)bnx2x_link_settings_status,
9025 .link_reset = (link_reset_t)bnx2x_int_link_reset,
9026 .config_loopback = (config_loopback_t)NULL,
9027 .format_fw_ver = (format_fw_ver_t)NULL,
9028 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009029 .set_link_led = (set_link_led_t)NULL,
9030 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009031};
9032
9033static struct bnx2x_phy phy_xgxs = {
9034 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT,
9035 .addr = 0xff,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009036 .def_md_devad = 0,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00009037 .flags = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009038 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
9039 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
9040 .mdio_ctrl = 0,
9041 .supported = (SUPPORTED_10baseT_Half |
9042 SUPPORTED_10baseT_Full |
9043 SUPPORTED_100baseT_Half |
9044 SUPPORTED_100baseT_Full |
9045 SUPPORTED_1000baseT_Full |
9046 SUPPORTED_2500baseX_Full |
9047 SUPPORTED_10000baseT_Full |
9048 SUPPORTED_FIBRE |
9049 SUPPORTED_Autoneg |
9050 SUPPORTED_Pause |
9051 SUPPORTED_Asym_Pause),
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00009052 .media_type = ETH_PHY_CX4,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009053 .ver_addr = 0,
9054 .req_flow_ctrl = 0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00009055 .req_line_speed = 0,
9056 .speed_cap_mask = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009057 .req_duplex = 0,
9058 .rsrv = 0,
Yaniv Rosnerec146a62011-05-31 21:29:27 +00009059 .config_init = (config_init_t)bnx2x_xgxs_config_init,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009060 .read_status = (read_status_t)bnx2x_link_settings_status,
9061 .link_reset = (link_reset_t)bnx2x_int_link_reset,
9062 .config_loopback = (config_loopback_t)bnx2x_set_xgxs_loopback,
9063 .format_fw_ver = (format_fw_ver_t)NULL,
9064 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009065 .set_link_led = (set_link_led_t)NULL,
9066 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009067};
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00009068static struct bnx2x_phy phy_warpcore = {
9069 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT,
9070 .addr = 0xff,
9071 .def_md_devad = 0,
9072 .flags = FLAGS_HW_LOCK_REQUIRED,
9073 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
9074 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
9075 .mdio_ctrl = 0,
9076 .supported = (SUPPORTED_10baseT_Half |
9077 SUPPORTED_10baseT_Full |
9078 SUPPORTED_100baseT_Half |
9079 SUPPORTED_100baseT_Full |
9080 SUPPORTED_1000baseT_Full |
9081 SUPPORTED_10000baseT_Full |
9082 SUPPORTED_20000baseKR2_Full |
9083 SUPPORTED_20000baseMLD2_Full |
9084 SUPPORTED_FIBRE |
9085 SUPPORTED_Autoneg |
9086 SUPPORTED_Pause |
9087 SUPPORTED_Asym_Pause),
9088 .media_type = ETH_PHY_UNSPECIFIED,
9089 .ver_addr = 0,
9090 .req_flow_ctrl = 0,
9091 .req_line_speed = 0,
9092 .speed_cap_mask = 0,
9093 /* req_duplex = */0,
9094 /* rsrv = */0,
9095 .config_init = (config_init_t)bnx2x_warpcore_config_init,
9096 .read_status = (read_status_t)bnx2x_warpcore_read_status,
9097 .link_reset = (link_reset_t)bnx2x_warpcore_link_reset,
9098 .config_loopback = (config_loopback_t)bnx2x_set_warpcore_loopback,
9099 .format_fw_ver = (format_fw_ver_t)NULL,
9100 .hw_reset = (hw_reset_t)NULL,
9101 .set_link_led = (set_link_led_t)NULL,
9102 .phy_specific_func = (phy_specific_func_t)NULL
9103};
9104
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009105
9106static struct bnx2x_phy phy_7101 = {
9107 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
9108 .addr = 0xff,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009109 .def_md_devad = 0,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00009110 .flags = FLAGS_FAN_FAILURE_DET_REQ,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009111 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
9112 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
9113 .mdio_ctrl = 0,
9114 .supported = (SUPPORTED_10000baseT_Full |
9115 SUPPORTED_TP |
9116 SUPPORTED_Autoneg |
9117 SUPPORTED_Pause |
9118 SUPPORTED_Asym_Pause),
9119 .media_type = ETH_PHY_BASE_T,
9120 .ver_addr = 0,
9121 .req_flow_ctrl = 0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00009122 .req_line_speed = 0,
9123 .speed_cap_mask = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009124 .req_duplex = 0,
9125 .rsrv = 0,
9126 .config_init = (config_init_t)bnx2x_7101_config_init,
9127 .read_status = (read_status_t)bnx2x_7101_read_status,
9128 .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
9129 .config_loopback = (config_loopback_t)bnx2x_7101_config_loopback,
9130 .format_fw_ver = (format_fw_ver_t)bnx2x_7101_format_ver,
9131 .hw_reset = (hw_reset_t)bnx2x_7101_hw_reset,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00009132 .set_link_led = (set_link_led_t)bnx2x_7101_set_link_led,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009133 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009134};
9135static struct bnx2x_phy phy_8073 = {
9136 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
9137 .addr = 0xff,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009138 .def_md_devad = 0,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00009139 .flags = FLAGS_HW_LOCK_REQUIRED,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009140 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
9141 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
9142 .mdio_ctrl = 0,
9143 .supported = (SUPPORTED_10000baseT_Full |
9144 SUPPORTED_2500baseX_Full |
9145 SUPPORTED_1000baseT_Full |
9146 SUPPORTED_FIBRE |
9147 SUPPORTED_Autoneg |
9148 SUPPORTED_Pause |
9149 SUPPORTED_Asym_Pause),
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00009150 .media_type = ETH_PHY_KR,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009151 .ver_addr = 0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00009152 .req_flow_ctrl = 0,
9153 .req_line_speed = 0,
9154 .speed_cap_mask = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009155 .req_duplex = 0,
9156 .rsrv = 0,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00009157 .config_init = (config_init_t)bnx2x_8073_config_init,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009158 .read_status = (read_status_t)bnx2x_8073_read_status,
9159 .link_reset = (link_reset_t)bnx2x_8073_link_reset,
9160 .config_loopback = (config_loopback_t)NULL,
9161 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
9162 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009163 .set_link_led = (set_link_led_t)NULL,
9164 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009165};
9166static struct bnx2x_phy phy_8705 = {
9167 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705,
9168 .addr = 0xff,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009169 .def_md_devad = 0,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00009170 .flags = FLAGS_INIT_XGXS_FIRST,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009171 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
9172 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
9173 .mdio_ctrl = 0,
9174 .supported = (SUPPORTED_10000baseT_Full |
9175 SUPPORTED_FIBRE |
9176 SUPPORTED_Pause |
9177 SUPPORTED_Asym_Pause),
9178 .media_type = ETH_PHY_XFP_FIBER,
9179 .ver_addr = 0,
9180 .req_flow_ctrl = 0,
9181 .req_line_speed = 0,
9182 .speed_cap_mask = 0,
9183 .req_duplex = 0,
9184 .rsrv = 0,
9185 .config_init = (config_init_t)bnx2x_8705_config_init,
9186 .read_status = (read_status_t)bnx2x_8705_read_status,
9187 .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
9188 .config_loopback = (config_loopback_t)NULL,
9189 .format_fw_ver = (format_fw_ver_t)bnx2x_null_format_ver,
9190 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009191 .set_link_led = (set_link_led_t)NULL,
9192 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009193};
9194static struct bnx2x_phy phy_8706 = {
9195 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706,
9196 .addr = 0xff,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009197 .def_md_devad = 0,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00009198 .flags = FLAGS_INIT_XGXS_FIRST,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009199 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
9200 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
9201 .mdio_ctrl = 0,
9202 .supported = (SUPPORTED_10000baseT_Full |
9203 SUPPORTED_1000baseT_Full |
9204 SUPPORTED_FIBRE |
9205 SUPPORTED_Pause |
9206 SUPPORTED_Asym_Pause),
9207 .media_type = ETH_PHY_SFP_FIBER,
9208 .ver_addr = 0,
9209 .req_flow_ctrl = 0,
9210 .req_line_speed = 0,
9211 .speed_cap_mask = 0,
9212 .req_duplex = 0,
9213 .rsrv = 0,
9214 .config_init = (config_init_t)bnx2x_8706_config_init,
9215 .read_status = (read_status_t)bnx2x_8706_read_status,
9216 .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
9217 .config_loopback = (config_loopback_t)NULL,
9218 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
9219 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009220 .set_link_led = (set_link_led_t)NULL,
9221 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009222};
9223
9224static struct bnx2x_phy phy_8726 = {
9225 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
9226 .addr = 0xff,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00009227 .def_md_devad = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009228 .flags = (FLAGS_HW_LOCK_REQUIRED |
9229 FLAGS_INIT_XGXS_FIRST),
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009230 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
9231 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
9232 .mdio_ctrl = 0,
9233 .supported = (SUPPORTED_10000baseT_Full |
9234 SUPPORTED_1000baseT_Full |
9235 SUPPORTED_Autoneg |
9236 SUPPORTED_FIBRE |
9237 SUPPORTED_Pause |
9238 SUPPORTED_Asym_Pause),
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00009239 .media_type = ETH_PHY_NOT_PRESENT,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009240 .ver_addr = 0,
9241 .req_flow_ctrl = 0,
9242 .req_line_speed = 0,
9243 .speed_cap_mask = 0,
9244 .req_duplex = 0,
9245 .rsrv = 0,
9246 .config_init = (config_init_t)bnx2x_8726_config_init,
9247 .read_status = (read_status_t)bnx2x_8726_read_status,
9248 .link_reset = (link_reset_t)bnx2x_8726_link_reset,
9249 .config_loopback = (config_loopback_t)bnx2x_8726_config_loopback,
9250 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
9251 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009252 .set_link_led = (set_link_led_t)NULL,
9253 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009254};
9255
9256static struct bnx2x_phy phy_8727 = {
9257 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
9258 .addr = 0xff,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009259 .def_md_devad = 0,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00009260 .flags = FLAGS_FAN_FAILURE_DET_REQ,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009261 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
9262 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
9263 .mdio_ctrl = 0,
9264 .supported = (SUPPORTED_10000baseT_Full |
9265 SUPPORTED_1000baseT_Full |
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009266 SUPPORTED_FIBRE |
9267 SUPPORTED_Pause |
9268 SUPPORTED_Asym_Pause),
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00009269 .media_type = ETH_PHY_NOT_PRESENT,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009270 .ver_addr = 0,
9271 .req_flow_ctrl = 0,
9272 .req_line_speed = 0,
9273 .speed_cap_mask = 0,
9274 .req_duplex = 0,
9275 .rsrv = 0,
9276 .config_init = (config_init_t)bnx2x_8727_config_init,
9277 .read_status = (read_status_t)bnx2x_8727_read_status,
9278 .link_reset = (link_reset_t)bnx2x_8727_link_reset,
9279 .config_loopback = (config_loopback_t)NULL,
9280 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
9281 .hw_reset = (hw_reset_t)bnx2x_8727_hw_reset,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00009282 .set_link_led = (set_link_led_t)bnx2x_8727_set_link_led,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009283 .phy_specific_func = (phy_specific_func_t)bnx2x_8727_specific_func
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009284};
9285static struct bnx2x_phy phy_8481 = {
9286 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
9287 .addr = 0xff,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00009288 .def_md_devad = 0,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009289 .flags = FLAGS_FAN_FAILURE_DET_REQ |
9290 FLAGS_REARM_LATCH_SIGNAL,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009291 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
9292 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
9293 .mdio_ctrl = 0,
9294 .supported = (SUPPORTED_10baseT_Half |
9295 SUPPORTED_10baseT_Full |
9296 SUPPORTED_100baseT_Half |
9297 SUPPORTED_100baseT_Full |
9298 SUPPORTED_1000baseT_Full |
9299 SUPPORTED_10000baseT_Full |
9300 SUPPORTED_TP |
9301 SUPPORTED_Autoneg |
9302 SUPPORTED_Pause |
9303 SUPPORTED_Asym_Pause),
9304 .media_type = ETH_PHY_BASE_T,
9305 .ver_addr = 0,
9306 .req_flow_ctrl = 0,
9307 .req_line_speed = 0,
9308 .speed_cap_mask = 0,
9309 .req_duplex = 0,
9310 .rsrv = 0,
9311 .config_init = (config_init_t)bnx2x_8481_config_init,
9312 .read_status = (read_status_t)bnx2x_848xx_read_status,
9313 .link_reset = (link_reset_t)bnx2x_8481_link_reset,
9314 .config_loopback = (config_loopback_t)NULL,
9315 .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver,
9316 .hw_reset = (hw_reset_t)bnx2x_8481_hw_reset,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00009317 .set_link_led = (set_link_led_t)bnx2x_848xx_set_link_led,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009318 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009319};
9320
9321static struct bnx2x_phy phy_84823 = {
9322 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823,
9323 .addr = 0xff,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00009324 .def_md_devad = 0,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009325 .flags = FLAGS_FAN_FAILURE_DET_REQ |
9326 FLAGS_REARM_LATCH_SIGNAL,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009327 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
9328 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
9329 .mdio_ctrl = 0,
9330 .supported = (SUPPORTED_10baseT_Half |
9331 SUPPORTED_10baseT_Full |
9332 SUPPORTED_100baseT_Half |
9333 SUPPORTED_100baseT_Full |
9334 SUPPORTED_1000baseT_Full |
9335 SUPPORTED_10000baseT_Full |
9336 SUPPORTED_TP |
9337 SUPPORTED_Autoneg |
9338 SUPPORTED_Pause |
9339 SUPPORTED_Asym_Pause),
9340 .media_type = ETH_PHY_BASE_T,
9341 .ver_addr = 0,
9342 .req_flow_ctrl = 0,
9343 .req_line_speed = 0,
9344 .speed_cap_mask = 0,
9345 .req_duplex = 0,
9346 .rsrv = 0,
9347 .config_init = (config_init_t)bnx2x_848x3_config_init,
9348 .read_status = (read_status_t)bnx2x_848xx_read_status,
9349 .link_reset = (link_reset_t)bnx2x_848x3_link_reset,
9350 .config_loopback = (config_loopback_t)NULL,
9351 .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver,
9352 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00009353 .set_link_led = (set_link_led_t)bnx2x_848xx_set_link_led,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009354 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009355};
9356
Yaniv Rosnerc87bca12011-01-31 04:22:41 +00009357static struct bnx2x_phy phy_84833 = {
9358 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833,
9359 .addr = 0xff,
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00009360 .def_md_devad = 0,
Yaniv Rosnerc87bca12011-01-31 04:22:41 +00009361 .flags = FLAGS_FAN_FAILURE_DET_REQ |
9362 FLAGS_REARM_LATCH_SIGNAL,
Yaniv Rosnerc87bca12011-01-31 04:22:41 +00009363 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
9364 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
9365 .mdio_ctrl = 0,
9366 .supported = (SUPPORTED_10baseT_Half |
9367 SUPPORTED_10baseT_Full |
9368 SUPPORTED_100baseT_Half |
9369 SUPPORTED_100baseT_Full |
9370 SUPPORTED_1000baseT_Full |
9371 SUPPORTED_10000baseT_Full |
9372 SUPPORTED_TP |
9373 SUPPORTED_Autoneg |
9374 SUPPORTED_Pause |
9375 SUPPORTED_Asym_Pause),
9376 .media_type = ETH_PHY_BASE_T,
9377 .ver_addr = 0,
9378 .req_flow_ctrl = 0,
9379 .req_line_speed = 0,
9380 .speed_cap_mask = 0,
9381 .req_duplex = 0,
9382 .rsrv = 0,
9383 .config_init = (config_init_t)bnx2x_848x3_config_init,
9384 .read_status = (read_status_t)bnx2x_848xx_read_status,
9385 .link_reset = (link_reset_t)bnx2x_848x3_link_reset,
9386 .config_loopback = (config_loopback_t)NULL,
9387 .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver,
9388 .hw_reset = (hw_reset_t)NULL,
9389 .set_link_led = (set_link_led_t)bnx2x_848xx_set_link_led,
9390 .phy_specific_func = (phy_specific_func_t)NULL
9391};
9392
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009393/*****************************************************************/
9394/* */
9395/* Populate the phy according. Main function: bnx2x_populate_phy */
9396/* */
9397/*****************************************************************/
9398
9399static void bnx2x_populate_preemphasis(struct bnx2x *bp, u32 shmem_base,
9400 struct bnx2x_phy *phy, u8 port,
9401 u8 phy_index)
9402{
9403 /* Get the 4 lanes xgxs config rx and tx */
9404 u32 rx = 0, tx = 0, i;
9405 for (i = 0; i < 2; i++) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00009406 /*
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009407 * INT_PHY and EXT_PHY1 share the same value location in the
9408 * shmem. When num_phys is greater than 1, than this value
9409 * applies only to EXT_PHY1
9410 */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009411 if (phy_index == INT_PHY || phy_index == EXT_PHY1) {
9412 rx = REG_RD(bp, shmem_base +
9413 offsetof(struct shmem_region,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00009414 dev_info.port_hw_config[port].xgxs_config_rx[i<<1]));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009415
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009416 tx = REG_RD(bp, shmem_base +
9417 offsetof(struct shmem_region,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00009418 dev_info.port_hw_config[port].xgxs_config_tx[i<<1]));
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009419 } else {
9420 rx = REG_RD(bp, shmem_base +
9421 offsetof(struct shmem_region,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00009422 dev_info.port_hw_config[port].xgxs_config2_rx[i<<1]));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009423
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009424 tx = REG_RD(bp, shmem_base +
9425 offsetof(struct shmem_region,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00009426 dev_info.port_hw_config[port].xgxs_config2_rx[i<<1]));
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009427 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009428
9429 phy->rx_preemphasis[i << 1] = ((rx>>16) & 0xffff);
9430 phy->rx_preemphasis[(i << 1) + 1] = (rx & 0xffff);
9431
9432 phy->tx_preemphasis[i << 1] = ((tx>>16) & 0xffff);
9433 phy->tx_preemphasis[(i << 1) + 1] = (tx & 0xffff);
9434 }
9435}
9436
Yaniv Rosnere10bc842010-09-07 11:40:50 +00009437static u32 bnx2x_get_ext_phy_config(struct bnx2x *bp, u32 shmem_base,
9438 u8 phy_index, u8 port)
9439{
9440 u32 ext_phy_config = 0;
9441 switch (phy_index) {
9442 case EXT_PHY1:
9443 ext_phy_config = REG_RD(bp, shmem_base +
9444 offsetof(struct shmem_region,
9445 dev_info.port_hw_config[port].external_phy_config));
9446 break;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009447 case EXT_PHY2:
9448 ext_phy_config = REG_RD(bp, shmem_base +
9449 offsetof(struct shmem_region,
9450 dev_info.port_hw_config[port].external_phy_config2));
9451 break;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00009452 default:
9453 DP(NETIF_MSG_LINK, "Invalid phy_index %d\n", phy_index);
9454 return -EINVAL;
9455 }
9456
9457 return ext_phy_config;
9458}
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00009459static int bnx2x_populate_int_phy(struct bnx2x *bp, u32 shmem_base, u8 port,
9460 struct bnx2x_phy *phy)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009461{
9462 u32 phy_addr;
9463 u32 chip_id;
9464 u32 switch_cfg = (REG_RD(bp, shmem_base +
9465 offsetof(struct shmem_region,
9466 dev_info.port_feature_config[port].link_config)) &
9467 PORT_FEATURE_CONNECTED_SWITCH_MASK);
9468 chip_id = REG_RD(bp, MISC_REG_CHIP_NUM) << 16;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00009469 DP(NETIF_MSG_LINK, ":chip_id = 0x%x\n", chip_id);
9470 if (USES_WARPCORE(bp)) {
9471 u32 serdes_net_if;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009472 phy_addr = REG_RD(bp,
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00009473 MISC_REG_WC0_CTRL_PHY_ADDR);
9474 *phy = phy_warpcore;
9475 if (REG_RD(bp, MISC_REG_PORT4MODE_EN_OVWR) == 0x3)
9476 phy->flags |= FLAGS_4_PORT_MODE;
9477 else
9478 phy->flags &= ~FLAGS_4_PORT_MODE;
9479 /* Check Dual mode */
9480 serdes_net_if = (REG_RD(bp, shmem_base +
9481 offsetof(struct shmem_region, dev_info.
9482 port_hw_config[port].default_cfg)) &
9483 PORT_HW_CFG_NET_SERDES_IF_MASK);
9484 /*
9485 * Set the appropriate supported and flags indications per
9486 * interface type of the chip
9487 */
9488 switch (serdes_net_if) {
9489 case PORT_HW_CFG_NET_SERDES_IF_SGMII:
9490 phy->supported &= (SUPPORTED_10baseT_Half |
9491 SUPPORTED_10baseT_Full |
9492 SUPPORTED_100baseT_Half |
9493 SUPPORTED_100baseT_Full |
9494 SUPPORTED_1000baseT_Full |
9495 SUPPORTED_FIBRE |
9496 SUPPORTED_Autoneg |
9497 SUPPORTED_Pause |
9498 SUPPORTED_Asym_Pause);
9499 phy->media_type = ETH_PHY_BASE_T;
9500 break;
9501 case PORT_HW_CFG_NET_SERDES_IF_XFI:
9502 phy->media_type = ETH_PHY_XFP_FIBER;
9503 break;
9504 case PORT_HW_CFG_NET_SERDES_IF_SFI:
9505 phy->supported &= (SUPPORTED_1000baseT_Full |
9506 SUPPORTED_10000baseT_Full |
9507 SUPPORTED_FIBRE |
9508 SUPPORTED_Pause |
9509 SUPPORTED_Asym_Pause);
9510 phy->media_type = ETH_PHY_SFP_FIBER;
9511 break;
9512 case PORT_HW_CFG_NET_SERDES_IF_KR:
9513 phy->media_type = ETH_PHY_KR;
9514 phy->supported &= (SUPPORTED_1000baseT_Full |
9515 SUPPORTED_10000baseT_Full |
9516 SUPPORTED_FIBRE |
9517 SUPPORTED_Autoneg |
9518 SUPPORTED_Pause |
9519 SUPPORTED_Asym_Pause);
9520 break;
9521 case PORT_HW_CFG_NET_SERDES_IF_DXGXS:
9522 phy->media_type = ETH_PHY_KR;
9523 phy->flags |= FLAGS_WC_DUAL_MODE;
9524 phy->supported &= (SUPPORTED_20000baseMLD2_Full |
9525 SUPPORTED_FIBRE |
9526 SUPPORTED_Pause |
9527 SUPPORTED_Asym_Pause);
9528 break;
9529 case PORT_HW_CFG_NET_SERDES_IF_KR2:
9530 phy->media_type = ETH_PHY_KR;
9531 phy->flags |= FLAGS_WC_DUAL_MODE;
9532 phy->supported &= (SUPPORTED_20000baseKR2_Full |
9533 SUPPORTED_FIBRE |
9534 SUPPORTED_Pause |
9535 SUPPORTED_Asym_Pause);
9536 break;
9537 default:
9538 DP(NETIF_MSG_LINK, "Unknown WC interface type 0x%x\n",
9539 serdes_net_if);
9540 break;
9541 }
9542
9543 /*
9544 * Enable MDC/MDIO work-around for E3 A0 since free running MDC
9545 * was not set as expected. For B0, ECO will be enabled so there
9546 * won't be an issue there
9547 */
9548 if (CHIP_REV(bp) == CHIP_REV_Ax)
9549 phy->flags |= FLAGS_MDC_MDIO_WA;
9550 } else {
9551 switch (switch_cfg) {
9552 case SWITCH_CFG_1G:
9553 phy_addr = REG_RD(bp,
9554 NIG_REG_SERDES0_CTRL_PHY_ADDR +
9555 port * 0x10);
9556 *phy = phy_serdes;
9557 break;
9558 case SWITCH_CFG_10G:
9559 phy_addr = REG_RD(bp,
9560 NIG_REG_XGXS0_CTRL_PHY_ADDR +
9561 port * 0x18);
9562 *phy = phy_xgxs;
9563 break;
9564 default:
9565 DP(NETIF_MSG_LINK, "Invalid switch_cfg\n");
9566 return -EINVAL;
9567 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009568 }
9569 phy->addr = (u8)phy_addr;
9570 phy->mdio_ctrl = bnx2x_get_emac_base(bp,
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00009571 SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009572 port);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00009573 if (CHIP_IS_E2(bp))
9574 phy->def_md_devad = E2_DEFAULT_PHY_DEV_ADDR;
9575 else
9576 phy->def_md_devad = DEFAULT_PHY_DEV_ADDR;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009577
9578 DP(NETIF_MSG_LINK, "Internal phy port=%d, addr=0x%x, mdio_ctl=0x%x\n",
9579 port, phy->addr, phy->mdio_ctrl);
9580
9581 bnx2x_populate_preemphasis(bp, shmem_base, phy, port, INT_PHY);
9582 return 0;
9583}
Yaniv Rosnere10bc842010-09-07 11:40:50 +00009584
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00009585static int bnx2x_populate_ext_phy(struct bnx2x *bp,
9586 u8 phy_index,
9587 u32 shmem_base,
9588 u32 shmem2_base,
9589 u8 port,
9590 struct bnx2x_phy *phy)
Yaniv Rosnere10bc842010-09-07 11:40:50 +00009591{
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00009592 u32 ext_phy_config, phy_type, config2;
9593 u32 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00009594 ext_phy_config = bnx2x_get_ext_phy_config(bp, shmem_base,
9595 phy_index, port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009596 phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
9597 /* Select the phy type */
9598 switch (phy_type) {
9599 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00009600 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_SWAPPED;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009601 *phy = phy_8073;
9602 break;
9603 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
9604 *phy = phy_8705;
9605 break;
9606 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
9607 *phy = phy_8706;
9608 break;
9609 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00009610 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009611 *phy = phy_8726;
9612 break;
9613 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
9614 /* BCM8727_NOC => BCM8727 no over current */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00009615 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009616 *phy = phy_8727;
9617 phy->flags |= FLAGS_NOC;
9618 break;
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00009619 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722:
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009620 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00009621 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009622 *phy = phy_8727;
9623 break;
9624 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
9625 *phy = phy_8481;
9626 break;
9627 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
9628 *phy = phy_84823;
9629 break;
Yaniv Rosnerc87bca12011-01-31 04:22:41 +00009630 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833:
9631 *phy = phy_84833;
9632 break;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009633 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
9634 *phy = phy_7101;
9635 break;
9636 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
9637 *phy = phy_null;
9638 return -EINVAL;
9639 default:
9640 *phy = phy_null;
9641 return 0;
9642 }
9643
Yaniv Rosnere10bc842010-09-07 11:40:50 +00009644 phy->addr = XGXS_EXT_PHY_ADDR(ext_phy_config);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009645 bnx2x_populate_preemphasis(bp, shmem_base, phy, port, phy_index);
Yaniv Rosner62b29a52010-09-07 11:40:58 +00009646
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00009647 /*
9648 * The shmem address of the phy version is located on different
9649 * structures. In case this structure is too old, do not set
9650 * the address
9651 */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00009652 config2 = REG_RD(bp, shmem_base + offsetof(struct shmem_region,
9653 dev_info.shared_hw_config.config2));
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009654 if (phy_index == EXT_PHY1) {
9655 phy->ver_addr = shmem_base + offsetof(struct shmem_region,
9656 port_mb[port].ext_phy_fw_version);
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00009657
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00009658 /* Check specific mdc mdio settings */
9659 if (config2 & SHARED_HW_CFG_MDC_MDIO_ACCESS1_MASK)
9660 mdc_mdio_access = config2 &
9661 SHARED_HW_CFG_MDC_MDIO_ACCESS1_MASK;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009662 } else {
9663 u32 size = REG_RD(bp, shmem2_base);
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00009664
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009665 if (size >
9666 offsetof(struct shmem2_region, ext_phy_fw_version2)) {
9667 phy->ver_addr = shmem2_base +
9668 offsetof(struct shmem2_region,
9669 ext_phy_fw_version2[port]);
9670 }
9671 /* Check specific mdc mdio settings */
9672 if (config2 & SHARED_HW_CFG_MDC_MDIO_ACCESS2_MASK)
9673 mdc_mdio_access = (config2 &
9674 SHARED_HW_CFG_MDC_MDIO_ACCESS2_MASK) >>
9675 (SHARED_HW_CFG_MDC_MDIO_ACCESS2_SHIFT -
9676 SHARED_HW_CFG_MDC_MDIO_ACCESS1_SHIFT);
9677 }
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00009678 phy->mdio_ctrl = bnx2x_get_emac_base(bp, mdc_mdio_access, port);
9679
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00009680 /*
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00009681 * In case mdc/mdio_access of the external phy is different than the
9682 * mdc/mdio access of the XGXS, a HW lock must be taken in each access
9683 * to prevent one port interfere with another port's CL45 operations.
9684 */
9685 if (mdc_mdio_access != SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH)
9686 phy->flags |= FLAGS_HW_LOCK_REQUIRED;
9687 DP(NETIF_MSG_LINK, "phy_type 0x%x port %d found in index %d\n",
9688 phy_type, port, phy_index);
9689 DP(NETIF_MSG_LINK, " addr=0x%x, mdio_ctl=0x%x\n",
9690 phy->addr, phy->mdio_ctrl);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00009691 return 0;
9692}
9693
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00009694static int bnx2x_populate_phy(struct bnx2x *bp, u8 phy_index, u32 shmem_base,
9695 u32 shmem2_base, u8 port, struct bnx2x_phy *phy)
Yaniv Rosnere10bc842010-09-07 11:40:50 +00009696{
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00009697 int status = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009698 phy->type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN;
9699 if (phy_index == INT_PHY)
9700 return bnx2x_populate_int_phy(bp, shmem_base, port, phy);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009701 status = bnx2x_populate_ext_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnere10bc842010-09-07 11:40:50 +00009702 port, phy);
9703 return status;
9704}
9705
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009706static void bnx2x_phy_def_cfg(struct link_params *params,
9707 struct bnx2x_phy *phy,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009708 u8 phy_index)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009709{
9710 struct bnx2x *bp = params->bp;
9711 u32 link_config;
9712 /* Populate the default phy configuration for MF mode */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009713 if (phy_index == EXT_PHY2) {
9714 link_config = REG_RD(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00009715 offsetof(struct shmem_region, dev_info.
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009716 port_feature_config[params->port].link_config2));
9717 phy->speed_cap_mask = REG_RD(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00009718 offsetof(struct shmem_region,
9719 dev_info.
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009720 port_hw_config[params->port].speed_capability_mask2));
9721 } else {
9722 link_config = REG_RD(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00009723 offsetof(struct shmem_region, dev_info.
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009724 port_feature_config[params->port].link_config));
9725 phy->speed_cap_mask = REG_RD(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00009726 offsetof(struct shmem_region,
9727 dev_info.
9728 port_hw_config[params->port].speed_capability_mask));
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009729 }
9730 DP(NETIF_MSG_LINK, "Default config phy idx %x cfg 0x%x speed_cap_mask"
9731 " 0x%x\n", phy_index, link_config, phy->speed_cap_mask);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009732
9733 phy->req_duplex = DUPLEX_FULL;
9734 switch (link_config & PORT_FEATURE_LINK_SPEED_MASK) {
9735 case PORT_FEATURE_LINK_SPEED_10M_HALF:
9736 phy->req_duplex = DUPLEX_HALF;
9737 case PORT_FEATURE_LINK_SPEED_10M_FULL:
9738 phy->req_line_speed = SPEED_10;
9739 break;
9740 case PORT_FEATURE_LINK_SPEED_100M_HALF:
9741 phy->req_duplex = DUPLEX_HALF;
9742 case PORT_FEATURE_LINK_SPEED_100M_FULL:
9743 phy->req_line_speed = SPEED_100;
9744 break;
9745 case PORT_FEATURE_LINK_SPEED_1G:
9746 phy->req_line_speed = SPEED_1000;
9747 break;
9748 case PORT_FEATURE_LINK_SPEED_2_5G:
9749 phy->req_line_speed = SPEED_2500;
9750 break;
9751 case PORT_FEATURE_LINK_SPEED_10G_CX4:
9752 phy->req_line_speed = SPEED_10000;
9753 break;
9754 default:
9755 phy->req_line_speed = SPEED_AUTO_NEG;
9756 break;
9757 }
9758
9759 switch (link_config & PORT_FEATURE_FLOW_CONTROL_MASK) {
9760 case PORT_FEATURE_FLOW_CONTROL_AUTO:
9761 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_AUTO;
9762 break;
9763 case PORT_FEATURE_FLOW_CONTROL_TX:
9764 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_TX;
9765 break;
9766 case PORT_FEATURE_FLOW_CONTROL_RX:
9767 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_RX;
9768 break;
9769 case PORT_FEATURE_FLOW_CONTROL_BOTH:
9770 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_BOTH;
9771 break;
9772 default:
9773 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_NONE;
9774 break;
9775 }
9776}
9777
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009778u32 bnx2x_phy_selection(struct link_params *params)
9779{
9780 u32 phy_config_swapped, prio_cfg;
9781 u32 return_cfg = PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT;
9782
9783 phy_config_swapped = params->multi_phy_config &
9784 PORT_HW_CFG_PHY_SWAPPED_ENABLED;
9785
9786 prio_cfg = params->multi_phy_config &
9787 PORT_HW_CFG_PHY_SELECTION_MASK;
9788
9789 if (phy_config_swapped) {
9790 switch (prio_cfg) {
9791 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
9792 return_cfg = PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY;
9793 break;
9794 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
9795 return_cfg = PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY;
9796 break;
9797 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY:
9798 return_cfg = PORT_HW_CFG_PHY_SELECTION_FIRST_PHY;
9799 break;
9800 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY:
9801 return_cfg = PORT_HW_CFG_PHY_SELECTION_SECOND_PHY;
9802 break;
9803 }
9804 } else
9805 return_cfg = prio_cfg;
9806
9807 return return_cfg;
9808}
9809
9810
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00009811int bnx2x_phy_probe(struct link_params *params)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009812{
9813 u8 phy_index, actual_phy_idx, link_cfg_idx;
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00009814 u32 phy_config_swapped, sync_offset, media_types;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009815 struct bnx2x *bp = params->bp;
9816 struct bnx2x_phy *phy;
9817 params->num_phys = 0;
9818 DP(NETIF_MSG_LINK, "Begin phy probe\n");
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009819 phy_config_swapped = params->multi_phy_config &
9820 PORT_HW_CFG_PHY_SWAPPED_ENABLED;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009821
9822 for (phy_index = INT_PHY; phy_index < MAX_PHYS;
9823 phy_index++) {
9824 link_cfg_idx = LINK_CONFIG_IDX(phy_index);
9825 actual_phy_idx = phy_index;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009826 if (phy_config_swapped) {
9827 if (phy_index == EXT_PHY1)
9828 actual_phy_idx = EXT_PHY2;
9829 else if (phy_index == EXT_PHY2)
9830 actual_phy_idx = EXT_PHY1;
9831 }
9832 DP(NETIF_MSG_LINK, "phy_config_swapped %x, phy_index %x,"
9833 " actual_phy_idx %x\n", phy_config_swapped,
9834 phy_index, actual_phy_idx);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009835 phy = &params->phy[actual_phy_idx];
9836 if (bnx2x_populate_phy(bp, phy_index, params->shmem_base,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009837 params->shmem2_base, params->port,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009838 phy) != 0) {
9839 params->num_phys = 0;
9840 DP(NETIF_MSG_LINK, "phy probe failed in phy index %d\n",
9841 phy_index);
9842 for (phy_index = INT_PHY;
9843 phy_index < MAX_PHYS;
9844 phy_index++)
9845 *phy = phy_null;
9846 return -EINVAL;
9847 }
9848 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)
9849 break;
9850
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00009851 sync_offset = params->shmem_base +
9852 offsetof(struct shmem_region,
9853 dev_info.port_hw_config[params->port].media_type);
9854 media_types = REG_RD(bp, sync_offset);
9855
9856 /*
9857 * Update media type for non-PMF sync only for the first time
9858 * In case the media type changes afterwards, it will be updated
9859 * using the update_status function
9860 */
9861 if ((media_types & (PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK <<
9862 (PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT *
9863 actual_phy_idx))) == 0) {
9864 media_types |= ((phy->media_type &
9865 PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK) <<
9866 (PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT *
9867 actual_phy_idx));
9868 }
9869 REG_WR(bp, sync_offset, media_types);
9870
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009871 bnx2x_phy_def_cfg(params, phy, phy_index);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00009872 params->num_phys++;
9873 }
9874
9875 DP(NETIF_MSG_LINK, "End phy probe. #phys found %x\n", params->num_phys);
9876 return 0;
9877}
9878
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00009879void bnx2x_init_bmac_loopback(struct link_params *params,
9880 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009881{
9882 struct bnx2x *bp = params->bp;
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00009883 vars->link_up = 1;
9884 vars->line_speed = SPEED_10000;
9885 vars->duplex = DUPLEX_FULL;
9886 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
9887 vars->mac_type = MAC_TYPE_BMAC;
9888
9889 vars->phy_flags = PHY_XGXS_FLAG;
9890
9891 bnx2x_xgxs_deassert(params);
9892
9893 /* set bmac loopback */
9894 bnx2x_bmac_enable(params, vars, 1);
9895
9896 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
9897}
9898
9899void bnx2x_init_emac_loopback(struct link_params *params,
9900 struct link_vars *vars)
9901{
9902 struct bnx2x *bp = params->bp;
9903 vars->link_up = 1;
9904 vars->line_speed = SPEED_1000;
9905 vars->duplex = DUPLEX_FULL;
9906 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
9907 vars->mac_type = MAC_TYPE_EMAC;
9908
9909 vars->phy_flags = PHY_XGXS_FLAG;
9910
9911 bnx2x_xgxs_deassert(params);
9912 /* set bmac loopback */
9913 bnx2x_emac_enable(params, vars, 1);
9914 bnx2x_emac_program(params, vars);
9915 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
9916}
9917
Yaniv Rosner9380bb92011-06-14 01:34:07 +00009918void bnx2x_init_xmac_loopback(struct link_params *params,
9919 struct link_vars *vars)
9920{
9921 struct bnx2x *bp = params->bp;
9922 vars->link_up = 1;
9923 if (!params->req_line_speed[0])
9924 vars->line_speed = SPEED_10000;
9925 else
9926 vars->line_speed = params->req_line_speed[0];
9927 vars->duplex = DUPLEX_FULL;
9928 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
9929 vars->mac_type = MAC_TYPE_XMAC;
9930 vars->phy_flags = PHY_XGXS_FLAG;
9931 /*
9932 * Set WC to loopback mode since link is required to provide clock
9933 * to the XMAC in 20G mode
9934 */
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00009935 if (vars->line_speed == SPEED_20000) {
9936 bnx2x_set_aer_mmd(params, &params->phy[0]);
9937 bnx2x_warpcore_reset_lane(bp, &params->phy[0], 0);
9938 params->phy[INT_PHY].config_loopback(
9939 &params->phy[INT_PHY],
9940 params);
9941 }
Yaniv Rosner9380bb92011-06-14 01:34:07 +00009942 bnx2x_xmac_enable(params, vars, 1);
9943 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
9944}
9945
9946void bnx2x_init_umac_loopback(struct link_params *params,
9947 struct link_vars *vars)
9948{
9949 struct bnx2x *bp = params->bp;
9950 vars->link_up = 1;
9951 vars->line_speed = SPEED_1000;
9952 vars->duplex = DUPLEX_FULL;
9953 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
9954 vars->mac_type = MAC_TYPE_UMAC;
9955 vars->phy_flags = PHY_XGXS_FLAG;
9956 bnx2x_umac_enable(params, vars, 1);
9957
9958 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
9959}
9960
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00009961void bnx2x_init_xgxs_loopback(struct link_params *params,
9962 struct link_vars *vars)
9963{
9964 struct bnx2x *bp = params->bp;
9965 vars->link_up = 1;
9966 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
9967 vars->duplex = DUPLEX_FULL;
9968 if (params->req_line_speed[0] == SPEED_1000)
9969 vars->line_speed = SPEED_1000;
9970 else
9971 vars->line_speed = SPEED_10000;
9972
Yaniv Rosner9380bb92011-06-14 01:34:07 +00009973 if (!USES_WARPCORE(bp))
9974 bnx2x_xgxs_deassert(params);
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00009975 bnx2x_link_initialize(params, vars);
9976
9977 if (params->req_line_speed[0] == SPEED_1000) {
Yaniv Rosner9380bb92011-06-14 01:34:07 +00009978 if (USES_WARPCORE(bp))
9979 bnx2x_umac_enable(params, vars, 0);
9980 else {
9981 bnx2x_emac_program(params, vars);
9982 bnx2x_emac_enable(params, vars, 0);
9983 }
9984 } else {
9985 if (USES_WARPCORE(bp))
9986 bnx2x_xmac_enable(params, vars, 0);
9987 else
9988 bnx2x_bmac_enable(params, vars, 0);
9989 }
Yaniv Rosner9045f6b42011-05-31 21:28:27 +00009990
9991 if (params->loopback_mode == LOOPBACK_XGXS) {
9992 /* set 10G XGXS loopback */
9993 params->phy[INT_PHY].config_loopback(
9994 &params->phy[INT_PHY],
9995 params);
9996
9997 } else {
9998 /* set external phy loopback */
9999 u8 phy_index;
10000 for (phy_index = EXT_PHY1;
10001 phy_index < params->num_phys; phy_index++) {
10002 if (params->phy[phy_index].config_loopback)
10003 params->phy[phy_index].config_loopback(
10004 &params->phy[phy_index],
10005 params);
10006 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010007 }
Yaniv Rosner9045f6b42011-05-31 21:28:27 +000010008 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010009
Yaniv Rosner9045f6b42011-05-31 21:28:27 +000010010 bnx2x_set_led(params, vars, LED_MODE_OPER, vars->line_speed);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010011}
10012
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +000010013int bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010014{
10015 struct bnx2x *bp = params->bp;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010016 DP(NETIF_MSG_LINK, "Phy Initialization started\n");
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010017 DP(NETIF_MSG_LINK, "(1) req_speed %d, req_flowctrl %d\n",
10018 params->req_line_speed[0], params->req_flow_ctrl[0]);
10019 DP(NETIF_MSG_LINK, "(2) req_speed %d, req_flowctrl %d\n",
10020 params->req_line_speed[1], params->req_flow_ctrl[1]);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010021 vars->link_status = 0;
10022 vars->phy_link_up = 0;
10023 vars->link_up = 0;
10024 vars->line_speed = 0;
10025 vars->duplex = DUPLEX_FULL;
10026 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
10027 vars->mac_type = MAC_TYPE_NONE;
10028 vars->phy_flags = 0;
10029
10030 /* disable attentions */
10031 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4,
10032 (NIG_MASK_XGXS0_LINK_STATUS |
10033 NIG_MASK_XGXS0_LINK10G |
10034 NIG_MASK_SERDES0_LINK_STATUS |
10035 NIG_MASK_MI_INT));
10036
10037 bnx2x_emac_init(params, vars);
10038
10039 if (params->num_phys == 0) {
10040 DP(NETIF_MSG_LINK, "No phy found for initialization !!\n");
10041 return -EINVAL;
10042 }
Yaniv Rosner9045f6b42011-05-31 21:28:27 +000010043 set_phy_vars(params, vars);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010044
10045 DP(NETIF_MSG_LINK, "Num of phys on board: %d\n", params->num_phys);
Yaniv Rosner9045f6b42011-05-31 21:28:27 +000010046 switch (params->loopback_mode) {
10047 case LOOPBACK_BMAC:
10048 bnx2x_init_bmac_loopback(params, vars);
10049 break;
10050 case LOOPBACK_EMAC:
10051 bnx2x_init_emac_loopback(params, vars);
10052 break;
Yaniv Rosner9380bb92011-06-14 01:34:07 +000010053 case LOOPBACK_XMAC:
10054 bnx2x_init_xmac_loopback(params, vars);
10055 break;
10056 case LOOPBACK_UMAC:
10057 bnx2x_init_umac_loopback(params, vars);
10058 break;
Yaniv Rosner9045f6b42011-05-31 21:28:27 +000010059 case LOOPBACK_XGXS:
10060 case LOOPBACK_EXT_PHY:
10061 bnx2x_init_xgxs_loopback(params, vars);
10062 break;
10063 default:
Yaniv Rosner9380bb92011-06-14 01:34:07 +000010064 if (!CHIP_IS_E3(bp)) {
10065 if (params->switch_cfg == SWITCH_CFG_10G)
10066 bnx2x_xgxs_deassert(params);
10067 else
10068 bnx2x_serdes_deassert(bp, params->port);
10069 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010070 bnx2x_link_initialize(params, vars);
10071 msleep(30);
10072 bnx2x_link_int_enable(params);
Yaniv Rosner9045f6b42011-05-31 21:28:27 +000010073 break;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010074 }
10075 return 0;
10076}
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +000010077
10078int bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
10079 u8 reset_ext_phy)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010080{
10081 struct bnx2x *bp = params->bp;
Yaniv Rosnercf1d9722010-11-01 05:32:34 +000010082 u8 phy_index, port = params->port, clear_latch_ind = 0;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010083 DP(NETIF_MSG_LINK, "Resetting the link of port %d\n", port);
10084 /* disable attentions */
10085 vars->link_status = 0;
10086 bnx2x_update_mng(params, vars->link_status);
10087 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010088 (NIG_MASK_XGXS0_LINK_STATUS |
10089 NIG_MASK_XGXS0_LINK10G |
10090 NIG_MASK_SERDES0_LINK_STATUS |
10091 NIG_MASK_MI_INT));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010092
10093 /* activate nig drain */
10094 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
10095
10096 /* disable nig egress interface */
Yaniv Rosner9380bb92011-06-14 01:34:07 +000010097 if (!CHIP_IS_E3(bp)) {
10098 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
10099 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
10100 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010101
10102 /* Stop BigMac rx */
Yaniv Rosner9380bb92011-06-14 01:34:07 +000010103 if (!CHIP_IS_E3(bp))
10104 bnx2x_bmac_rx_disable(bp, port);
10105 else
10106 bnx2x_xmac_disable(params);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010107 /* disable emac */
Yaniv Rosner9380bb92011-06-14 01:34:07 +000010108 if (!CHIP_IS_E3(bp))
10109 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010110
10111 msleep(10);
Lucas De Marchi25985ed2011-03-30 22:57:33 -030010112 /* The PHY reset is controlled by GPIO 1
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010113 * Hold it as vars low
10114 */
10115 /* clear link led */
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +000010116 bnx2x_set_led(params, vars, LED_MODE_OFF, 0);
10117
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010118 if (reset_ext_phy) {
10119 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
10120 phy_index++) {
10121 if (params->phy[phy_index].link_reset)
10122 params->phy[phy_index].link_reset(
10123 &params->phy[phy_index],
10124 params);
Yaniv Rosnercf1d9722010-11-01 05:32:34 +000010125 if (params->phy[phy_index].flags &
10126 FLAGS_REARM_LATCH_SIGNAL)
10127 clear_latch_ind = 1;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010128 }
10129 }
10130
Yaniv Rosnercf1d9722010-11-01 05:32:34 +000010131 if (clear_latch_ind) {
10132 /* Clear latching indication */
10133 bnx2x_rearm_latch_signal(bp, port, 0);
10134 bnx2x_bits_dis(bp, NIG_REG_LATCH_BC_0 + port*4,
10135 1 << NIG_LATCH_BC_ENABLE_MI_INT);
10136 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010137 if (params->phy[INT_PHY].link_reset)
10138 params->phy[INT_PHY].link_reset(
10139 &params->phy[INT_PHY], params);
10140 /* reset BigMac */
10141 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
10142 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
10143
10144 /* disable nig ingress interface */
Yaniv Rosner9380bb92011-06-14 01:34:07 +000010145 if (!CHIP_IS_E3(bp)) {
10146 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0);
10147 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0);
10148 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010149 vars->link_up = 0;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000010150 vars->phy_flags = 0;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010151 return 0;
10152}
10153
10154/****************************************************************************/
10155/* Common function */
10156/****************************************************************************/
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +000010157static int bnx2x_8073_common_init_phy(struct bnx2x *bp,
10158 u32 shmem_base_path[],
10159 u32 shmem2_base_path[], u8 phy_index,
10160 u32 chip_id)
Yaniv Rosner6bbca912008-08-13 15:57:28 -070010161{
Yaniv Rosnere10bc842010-09-07 11:40:50 +000010162 struct bnx2x_phy phy[PORT_MAX];
10163 struct bnx2x_phy *phy_blk[PORT_MAX];
Yaniv Rosner6bbca912008-08-13 15:57:28 -070010164 u16 val;
Yaniv Rosnerc8e64df2011-01-30 04:15:00 +000010165 s8 port = 0;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000010166 s8 port_of_path = 0;
Yaniv Rosnerc8e64df2011-01-30 04:15:00 +000010167 u32 swap_val, swap_override;
10168 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
10169 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
10170 port ^= (swap_val && swap_override);
10171 bnx2x_ext_phy_hw_reset(bp, port);
Yaniv Rosner6bbca912008-08-13 15:57:28 -070010172 /* PART1 - Reset both phys */
10173 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000010174 u32 shmem_base, shmem2_base;
10175 /* In E2, same phy is using for port0 of the two paths */
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000010176 if (CHIP_IS_E1x(bp)) {
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000010177 shmem_base = shmem_base_path[0];
10178 shmem2_base = shmem2_base_path[0];
10179 port_of_path = port;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000010180 } else {
10181 shmem_base = shmem_base_path[port];
10182 shmem2_base = shmem2_base_path[port];
10183 port_of_path = 0;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000010184 }
10185
Yaniv Rosner6bbca912008-08-13 15:57:28 -070010186 /* Extract the ext phy address for the port */
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010187 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000010188 port_of_path, &phy[port]) !=
Yaniv Rosnere10bc842010-09-07 11:40:50 +000010189 0) {
10190 DP(NETIF_MSG_LINK, "populate_phy failed\n");
10191 return -EINVAL;
10192 }
Yaniv Rosner6bbca912008-08-13 15:57:28 -070010193 /* disable attentions */
Yaniv Rosner6a71bbe2010-11-01 05:32:31 +000010194 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 +
10195 port_of_path*4,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010196 (NIG_MASK_XGXS0_LINK_STATUS |
10197 NIG_MASK_XGXS0_LINK10G |
10198 NIG_MASK_SERDES0_LINK_STATUS |
10199 NIG_MASK_MI_INT));
Yaniv Rosner6bbca912008-08-13 15:57:28 -070010200
Yaniv Rosner6bbca912008-08-13 15:57:28 -070010201 /* Need to take the phy out of low power mode in order
10202 to write to access its registers */
10203 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010204 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
10205 port);
Yaniv Rosner6bbca912008-08-13 15:57:28 -070010206
10207 /* Reset the phy */
Yaniv Rosnere10bc842010-09-07 11:40:50 +000010208 bnx2x_cl45_write(bp, &phy[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010209 MDIO_PMA_DEVAD,
10210 MDIO_PMA_REG_CTRL,
10211 1<<15);
Yaniv Rosner6bbca912008-08-13 15:57:28 -070010212 }
10213
10214 /* Add delay of 150ms after reset */
10215 msleep(150);
10216
Yaniv Rosnere10bc842010-09-07 11:40:50 +000010217 if (phy[PORT_0].addr & 0x1) {
10218 phy_blk[PORT_0] = &(phy[PORT_1]);
10219 phy_blk[PORT_1] = &(phy[PORT_0]);
10220 } else {
10221 phy_blk[PORT_0] = &(phy[PORT_0]);
10222 phy_blk[PORT_1] = &(phy[PORT_1]);
10223 }
10224
Yaniv Rosner6bbca912008-08-13 15:57:28 -070010225 /* PART2 - Download firmware to both phys */
10226 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000010227 if (CHIP_IS_E1x(bp))
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000010228 port_of_path = port;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000010229 else
10230 port_of_path = 0;
Yaniv Rosner6bbca912008-08-13 15:57:28 -070010231
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000010232 DP(NETIF_MSG_LINK, "Loading spirom for phy address 0x%x\n",
10233 phy_blk[port]->addr);
Yaniv Rosner5c99274b2011-01-18 04:33:36 +000010234 if (bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port],
10235 port_of_path))
Yaniv Rosner6bbca912008-08-13 15:57:28 -070010236 return -EINVAL;
Yaniv Rosner6bbca912008-08-13 15:57:28 -070010237
10238 /* Only set bit 10 = 1 (Tx power down) */
Yaniv Rosnere10bc842010-09-07 11:40:50 +000010239 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010240 MDIO_PMA_DEVAD,
10241 MDIO_PMA_REG_TX_POWER_DOWN, &val);
Yaniv Rosner6bbca912008-08-13 15:57:28 -070010242
10243 /* Phase1 of TX_POWER_DOWN reset */
Yaniv Rosnere10bc842010-09-07 11:40:50 +000010244 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010245 MDIO_PMA_DEVAD,
10246 MDIO_PMA_REG_TX_POWER_DOWN,
10247 (val | 1<<10));
Yaniv Rosner6bbca912008-08-13 15:57:28 -070010248 }
10249
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +000010250 /*
10251 * Toggle Transmitter: Power down and then up with 600ms delay
10252 * between
10253 */
Yaniv Rosner6bbca912008-08-13 15:57:28 -070010254 msleep(600);
10255
10256 /* PART3 - complete TX_POWER_DOWN process, and set GPIO2 back to low */
10257 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Eilon Greensteinf5372252009-02-12 08:38:30 +000010258 /* Phase2 of POWER_DOWN_RESET */
Yaniv Rosner6bbca912008-08-13 15:57:28 -070010259 /* Release bit 10 (Release Tx power down) */
Yaniv Rosnere10bc842010-09-07 11:40:50 +000010260 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010261 MDIO_PMA_DEVAD,
10262 MDIO_PMA_REG_TX_POWER_DOWN, &val);
Yaniv Rosner6bbca912008-08-13 15:57:28 -070010263
Yaniv Rosnere10bc842010-09-07 11:40:50 +000010264 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010265 MDIO_PMA_DEVAD,
10266 MDIO_PMA_REG_TX_POWER_DOWN, (val & (~(1<<10))));
Yaniv Rosner6bbca912008-08-13 15:57:28 -070010267 msleep(15);
10268
10269 /* Read modify write the SPI-ROM version select register */
Yaniv Rosnere10bc842010-09-07 11:40:50 +000010270 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010271 MDIO_PMA_DEVAD,
10272 MDIO_PMA_REG_EDC_FFE_MAIN, &val);
Yaniv Rosnere10bc842010-09-07 11:40:50 +000010273 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010274 MDIO_PMA_DEVAD,
10275 MDIO_PMA_REG_EDC_FFE_MAIN, (val | (1<<12)));
Yaniv Rosner6bbca912008-08-13 15:57:28 -070010276
10277 /* set GPIO2 back to LOW */
10278 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010279 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
Yaniv Rosner6bbca912008-08-13 15:57:28 -070010280 }
10281 return 0;
Yaniv Rosner6bbca912008-08-13 15:57:28 -070010282}
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +000010283static int bnx2x_8726_common_init_phy(struct bnx2x *bp,
10284 u32 shmem_base_path[],
10285 u32 shmem2_base_path[], u8 phy_index,
10286 u32 chip_id)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010287{
10288 u32 val;
10289 s8 port;
10290 struct bnx2x_phy phy;
10291 /* Use port1 because of the static port-swap */
10292 /* Enable the module detection interrupt */
10293 val = REG_RD(bp, MISC_REG_GPIO_EVENT_EN);
10294 val |= ((1<<MISC_REGISTERS_GPIO_3)|
10295 (1<<(MISC_REGISTERS_GPIO_3 + MISC_REGISTERS_GPIO_PORT_SHIFT)));
10296 REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val);
10297
Yaniv Rosner650154b2010-11-01 05:32:36 +000010298 bnx2x_ext_phy_hw_reset(bp, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010299 msleep(5);
10300 for (port = 0; port < PORT_MAX; port++) {
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000010301 u32 shmem_base, shmem2_base;
10302
10303 /* In E2, same phy is using for port0 of the two paths */
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000010304 if (CHIP_IS_E1x(bp)) {
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000010305 shmem_base = shmem_base_path[0];
10306 shmem2_base = shmem2_base_path[0];
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000010307 } else {
10308 shmem_base = shmem_base_path[port];
10309 shmem2_base = shmem2_base_path[port];
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000010310 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010311 /* Extract the ext phy address for the port */
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010312 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010313 port, &phy) !=
10314 0) {
10315 DP(NETIF_MSG_LINK, "populate phy failed\n");
10316 return -EINVAL;
10317 }
10318
10319 /* Reset phy*/
10320 bnx2x_cl45_write(bp, &phy,
10321 MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, 0x0001);
10322
10323
10324 /* Set fault module detected LED on */
10325 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010326 MISC_REGISTERS_GPIO_HIGH,
10327 port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010328 }
10329
10330 return 0;
10331}
Yaniv Rosnera8db5b42011-01-31 04:22:28 +000010332static void bnx2x_get_ext_phy_reset_gpio(struct bnx2x *bp, u32 shmem_base,
10333 u8 *io_gpio, u8 *io_port)
10334{
10335
10336 u32 phy_gpio_reset = REG_RD(bp, shmem_base +
10337 offsetof(struct shmem_region,
10338 dev_info.port_hw_config[PORT_0].default_cfg));
10339 switch (phy_gpio_reset) {
10340 case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO0_P0:
10341 *io_gpio = 0;
10342 *io_port = 0;
10343 break;
10344 case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO1_P0:
10345 *io_gpio = 1;
10346 *io_port = 0;
10347 break;
10348 case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO2_P0:
10349 *io_gpio = 2;
10350 *io_port = 0;
10351 break;
10352 case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO3_P0:
10353 *io_gpio = 3;
10354 *io_port = 0;
10355 break;
10356 case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO0_P1:
10357 *io_gpio = 0;
10358 *io_port = 1;
10359 break;
10360 case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO1_P1:
10361 *io_gpio = 1;
10362 *io_port = 1;
10363 break;
10364 case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO2_P1:
10365 *io_gpio = 2;
10366 *io_port = 1;
10367 break;
10368 case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO3_P1:
10369 *io_gpio = 3;
10370 *io_port = 1;
10371 break;
10372 default:
10373 /* Don't override the io_gpio and io_port */
10374 break;
10375 }
10376}
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +000010377
10378static int bnx2x_8727_common_init_phy(struct bnx2x *bp,
10379 u32 shmem_base_path[],
10380 u32 shmem2_base_path[], u8 phy_index,
10381 u32 chip_id)
Eilon Greenstein4d295db2009-07-21 05:47:47 +000010382{
Yaniv Rosnera8db5b42011-01-31 04:22:28 +000010383 s8 port, reset_gpio;
Eilon Greenstein4d295db2009-07-21 05:47:47 +000010384 u32 swap_val, swap_override;
Yaniv Rosnere10bc842010-09-07 11:40:50 +000010385 struct bnx2x_phy phy[PORT_MAX];
10386 struct bnx2x_phy *phy_blk[PORT_MAX];
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000010387 s8 port_of_path;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010388 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
10389 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
Eilon Greenstein4d295db2009-07-21 05:47:47 +000010390
Yaniv Rosnera8db5b42011-01-31 04:22:28 +000010391 reset_gpio = MISC_REGISTERS_GPIO_1;
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010392 port = 1;
10393
Yaniv Rosnera8db5b42011-01-31 04:22:28 +000010394 /*
10395 * Retrieve the reset gpio/port which control the reset.
10396 * Default is GPIO1, PORT1
10397 */
10398 bnx2x_get_ext_phy_reset_gpio(bp, shmem_base_path[0],
10399 (u8 *)&reset_gpio, (u8 *)&port);
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010400
10401 /* Calculate the port based on port swap */
10402 port ^= (swap_val && swap_override);
10403
Yaniv Rosnera8db5b42011-01-31 04:22:28 +000010404 /* Initiate PHY reset*/
10405 bnx2x_set_gpio(bp, reset_gpio, MISC_REGISTERS_GPIO_OUTPUT_LOW,
10406 port);
10407 msleep(1);
10408 bnx2x_set_gpio(bp, reset_gpio, MISC_REGISTERS_GPIO_OUTPUT_HIGH,
10409 port);
10410
Eilon Greenstein4d295db2009-07-21 05:47:47 +000010411 msleep(5);
10412
10413 /* PART1 - Reset both phys */
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010414 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000010415 u32 shmem_base, shmem2_base;
10416
10417 /* In E2, same phy is using for port0 of the two paths */
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000010418 if (CHIP_IS_E1x(bp)) {
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000010419 shmem_base = shmem_base_path[0];
10420 shmem2_base = shmem2_base_path[0];
10421 port_of_path = port;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000010422 } else {
10423 shmem_base = shmem_base_path[port];
10424 shmem2_base = shmem2_base_path[port];
10425 port_of_path = 0;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000010426 }
10427
Eilon Greenstein4d295db2009-07-21 05:47:47 +000010428 /* Extract the ext phy address for the port */
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010429 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000010430 port_of_path, &phy[port]) !=
Yaniv Rosnere10bc842010-09-07 11:40:50 +000010431 0) {
10432 DP(NETIF_MSG_LINK, "populate phy failed\n");
10433 return -EINVAL;
10434 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +000010435 /* disable attentions */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000010436 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 +
10437 port_of_path*4,
10438 (NIG_MASK_XGXS0_LINK_STATUS |
10439 NIG_MASK_XGXS0_LINK10G |
10440 NIG_MASK_SERDES0_LINK_STATUS |
10441 NIG_MASK_MI_INT));
Eilon Greenstein4d295db2009-07-21 05:47:47 +000010442
Eilon Greenstein4d295db2009-07-21 05:47:47 +000010443
10444 /* Reset the phy */
Yaniv Rosnere10bc842010-09-07 11:40:50 +000010445 bnx2x_cl45_write(bp, &phy[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010446 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
Eilon Greenstein4d295db2009-07-21 05:47:47 +000010447 }
10448
10449 /* Add delay of 150ms after reset */
10450 msleep(150);
Yaniv Rosnere10bc842010-09-07 11:40:50 +000010451 if (phy[PORT_0].addr & 0x1) {
10452 phy_blk[PORT_0] = &(phy[PORT_1]);
10453 phy_blk[PORT_1] = &(phy[PORT_0]);
10454 } else {
10455 phy_blk[PORT_0] = &(phy[PORT_0]);
10456 phy_blk[PORT_1] = &(phy[PORT_1]);
10457 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +000010458 /* PART2 - Download firmware to both phys */
Yaniv Rosnere10bc842010-09-07 11:40:50 +000010459 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000010460 if (CHIP_IS_E1x(bp))
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000010461 port_of_path = port;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000010462 else
10463 port_of_path = 0;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000010464 DP(NETIF_MSG_LINK, "Loading spirom for phy address 0x%x\n",
10465 phy_blk[port]->addr);
Yaniv Rosner5c99274b2011-01-18 04:33:36 +000010466 if (bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port],
10467 port_of_path))
Eilon Greenstein4d295db2009-07-21 05:47:47 +000010468 return -EINVAL;
Eilon Greenstein4d295db2009-07-21 05:47:47 +000010469
Yaniv Rosner5c99274b2011-01-18 04:33:36 +000010470 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +000010471 return 0;
10472}
10473
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +000010474static int bnx2x_ext_phy_common_init(struct bnx2x *bp, u32 shmem_base_path[],
10475 u32 shmem2_base_path[], u8 phy_index,
10476 u32 ext_phy_type, u32 chip_id)
Yaniv Rosner6bbca912008-08-13 15:57:28 -070010477{
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +000010478 int rc = 0;
Yaniv Rosner6bbca912008-08-13 15:57:28 -070010479
10480 switch (ext_phy_type) {
10481 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000010482 rc = bnx2x_8073_common_init_phy(bp, shmem_base_path,
10483 shmem2_base_path,
10484 phy_index, chip_id);
Yaniv Rosner6bbca912008-08-13 15:57:28 -070010485 break;
Yaniv Rosnere4d78f12011-05-31 21:25:55 +000010486 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722:
Eilon Greenstein4d295db2009-07-21 05:47:47 +000010487 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
10488 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000010489 rc = bnx2x_8727_common_init_phy(bp, shmem_base_path,
10490 shmem2_base_path,
10491 phy_index, chip_id);
Eilon Greenstein4d295db2009-07-21 05:47:47 +000010492 break;
10493
Eilon Greenstein589abe32009-02-12 08:36:55 +000010494 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +000010495 /*
10496 * GPIO1 affects both ports, so there's need to pull
10497 * it for single port alone
10498 */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000010499 rc = bnx2x_8726_common_init_phy(bp, shmem_base_path,
10500 shmem2_base_path,
10501 phy_index, chip_id);
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010502 break;
10503 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
10504 rc = -EINVAL;
Yaniv Rosner4f60dab2009-11-05 19:18:23 +020010505 break;
Yaniv Rosner6bbca912008-08-13 15:57:28 -070010506 default:
10507 DP(NETIF_MSG_LINK,
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +000010508 "ext_phy 0x%x common init not required\n",
10509 ext_phy_type);
Yaniv Rosner6bbca912008-08-13 15:57:28 -070010510 break;
10511 }
10512
Yaniv Rosner6d870c32011-01-31 04:22:20 +000010513 if (rc != 0)
10514 netdev_err(bp->dev, "Warning: PHY was not initialized,"
10515 " Port %d\n",
10516 0);
Yaniv Rosner6bbca912008-08-13 15:57:28 -070010517 return rc;
10518}
10519
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +000010520int bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base_path[],
10521 u32 shmem2_base_path[], u32 chip_id)
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010522{
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +000010523 int rc = 0;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000010524 u32 phy_ver, val;
10525 u8 phy_index = 0;
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010526 u32 ext_phy_type, ext_phy_config;
Yaniv Rosnera198c142011-05-31 21:29:42 +000010527 bnx2x_set_mdio_clk(bp, chip_id, PORT_0);
10528 bnx2x_set_mdio_clk(bp, chip_id, PORT_1);
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010529 DP(NETIF_MSG_LINK, "Begin common phy init\n");
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000010530 if (CHIP_IS_E3(bp)) {
10531 /* Enable EPIO */
10532 val = REG_RD(bp, MISC_REG_GEN_PURP_HWG);
10533 REG_WR(bp, MISC_REG_GEN_PURP_HWG, val | 1);
10534 }
Yaniv Rosnerb21a3422011-01-18 04:33:24 +000010535 /* Check if common init was already done */
10536 phy_ver = REG_RD(bp, shmem_base_path[0] +
10537 offsetof(struct shmem_region,
10538 port_mb[PORT_0].ext_phy_fw_version));
10539 if (phy_ver) {
10540 DP(NETIF_MSG_LINK, "Not doing common init; phy ver is 0x%x\n",
10541 phy_ver);
10542 return 0;
10543 }
10544
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010545 /* Read the ext_phy_type for arbitrary port(0) */
10546 for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
10547 phy_index++) {
10548 ext_phy_config = bnx2x_get_ext_phy_config(bp,
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000010549 shmem_base_path[0],
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010550 phy_index, 0);
10551 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000010552 rc |= bnx2x_ext_phy_common_init(bp, shmem_base_path,
10553 shmem2_base_path,
10554 phy_index, ext_phy_type,
10555 chip_id);
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010556 }
10557 return rc;
10558}
10559
10560u8 bnx2x_hw_lock_required(struct bnx2x *bp, u32 shmem_base, u32 shmem2_base)
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +000010561{
10562 u8 phy_index;
10563 struct bnx2x_phy phy;
10564 for (phy_index = INT_PHY; phy_index < MAX_PHYS;
10565 phy_index++) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010566 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +000010567 0, &phy) != 0) {
10568 DP(NETIF_MSG_LINK, "populate phy failed\n");
10569 return 0;
10570 }
10571
10572 if (phy.flags & FLAGS_HW_LOCK_REQUIRED)
10573 return 1;
10574 }
10575 return 0;
10576}
10577
10578u8 bnx2x_fan_failure_det_req(struct bnx2x *bp,
10579 u32 shmem_base,
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010580 u32 shmem2_base,
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +000010581 u8 port)
10582{
10583 u8 phy_index, fan_failure_det_req = 0;
10584 struct bnx2x_phy phy;
10585 for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
10586 phy_index++) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010587 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +000010588 port, &phy)
10589 != 0) {
10590 DP(NETIF_MSG_LINK, "populate phy failed\n");
10591 return 0;
10592 }
10593 fan_failure_det_req |= (phy.flags &
10594 FLAGS_FAN_FAILURE_DET_REQ);
10595 }
10596 return fan_failure_det_req;
10597}
10598
10599void bnx2x_hw_reset_phy(struct link_params *params)
10600{
10601 u8 phy_index;
10602 for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
10603 phy_index++) {
10604 if (params->phy[phy_index].hw_reset) {
10605 params->phy[phy_index].hw_reset(
10606 &params->phy[phy_index],
10607 params);
10608 params->phy[phy_index] = phy_null;
10609 }
10610 }
10611}
Yaniv Rosner020c7e32011-05-31 21:28:43 +000010612
10613void bnx2x_init_mod_abs_int(struct bnx2x *bp, struct link_vars *vars,
10614 u32 chip_id, u32 shmem_base, u32 shmem2_base,
10615 u8 port)
10616{
10617 u8 gpio_num = 0xff, gpio_port = 0xff, phy_index;
10618 u32 val;
10619 u32 offset, aeu_mask, swap_val, swap_override, sync_offset;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000010620 if (CHIP_IS_E3(bp)) {
10621 if (bnx2x_get_mod_abs_int_cfg(bp, chip_id,
10622 shmem_base,
10623 port,
10624 &gpio_num,
10625 &gpio_port) != 0)
10626 return;
10627 } else {
Yaniv Rosner020c7e32011-05-31 21:28:43 +000010628 struct bnx2x_phy phy;
10629 for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
10630 phy_index++) {
10631 if (bnx2x_populate_phy(bp, phy_index, shmem_base,
10632 shmem2_base, port, &phy)
10633 != 0) {
10634 DP(NETIF_MSG_LINK, "populate phy failed\n");
10635 return;
10636 }
10637 if (phy.type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) {
10638 gpio_num = MISC_REGISTERS_GPIO_3;
10639 gpio_port = port;
10640 break;
10641 }
10642 }
10643 }
10644
10645 if (gpio_num == 0xff)
10646 return;
10647
10648 /* Set GPIO3 to trigger SFP+ module insertion/removal */
10649 bnx2x_set_gpio(bp, gpio_num, MISC_REGISTERS_GPIO_INPUT_HI_Z, gpio_port);
10650
10651 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
10652 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
10653 gpio_port ^= (swap_val && swap_override);
10654
10655 vars->aeu_int_mask = AEU_INPUTS_ATTN_BITS_GPIO0_FUNCTION_0 <<
10656 (gpio_num + (gpio_port << 2));
10657
10658 sync_offset = shmem_base +
10659 offsetof(struct shmem_region,
10660 dev_info.port_hw_config[port].aeu_int_mask);
10661 REG_WR(bp, sync_offset, vars->aeu_int_mask);
10662
10663 DP(NETIF_MSG_LINK, "Setting MOD_ABS (GPIO%d_P%d) AEU to 0x%x\n",
10664 gpio_num, gpio_port, vars->aeu_int_mask);
10665
10666 if (port == 0)
10667 offset = MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0;
10668 else
10669 offset = MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0;
10670
10671 /* Open appropriate AEU for interrupts */
10672 aeu_mask = REG_RD(bp, offset);
10673 aeu_mask |= vars->aeu_int_mask;
10674 REG_WR(bp, offset, aeu_mask);
10675
10676 /* Enable the GPIO to trigger interrupt */
10677 val = REG_RD(bp, MISC_REG_GPIO_EVENT_EN);
10678 val |= 1 << (gpio_num + (gpio_port << 2));
10679 REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val);
10680}