blob: a5c34880b39eb607d8b771602413e788ec4a0ba2 [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
Yaniv Rosner6583e332011-06-14 01:34:17 +0000137
138
139
Eilon Greenstein589abe32009-02-12 08:36:55 +0000140/* */
141#define SFP_EEPROM_CON_TYPE_ADDR 0x2
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000142 #define SFP_EEPROM_CON_TYPE_VAL_LC 0x7
Eilon Greenstein589abe32009-02-12 08:36:55 +0000143 #define SFP_EEPROM_CON_TYPE_VAL_COPPER 0x21
144
Eilon Greenstein4d295db2009-07-21 05:47:47 +0000145
146#define SFP_EEPROM_COMP_CODE_ADDR 0x3
147 #define SFP_EEPROM_COMP_CODE_SR_MASK (1<<4)
148 #define SFP_EEPROM_COMP_CODE_LR_MASK (1<<5)
149 #define SFP_EEPROM_COMP_CODE_LRM_MASK (1<<6)
150
Eilon Greenstein589abe32009-02-12 08:36:55 +0000151#define SFP_EEPROM_FC_TX_TECH_ADDR 0x8
152 #define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE 0x4
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000153 #define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE 0x8
Eilon Greenstein4d295db2009-07-21 05:47:47 +0000154
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000155#define SFP_EEPROM_OPTIONS_ADDR 0x40
Eilon Greenstein589abe32009-02-12 08:36:55 +0000156 #define SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK 0x1
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000157#define SFP_EEPROM_OPTIONS_SIZE 2
Eilon Greenstein589abe32009-02-12 08:36:55 +0000158
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000159#define EDC_MODE_LINEAR 0x0022
160#define EDC_MODE_LIMITING 0x0044
161#define EDC_MODE_PASSIVE_DAC 0x0055
Eilon Greenstein589abe32009-02-12 08:36:55 +0000162
Eilon Greenstein4d295db2009-07-21 05:47:47 +0000163
Yaniv Rosner9380bb92011-06-14 01:34:07 +0000164/* BRB thresholds for E2*/
165#define PFC_E2_BRB_MAC_PAUSE_XOFF_THR_PAUSE 170
166#define PFC_E2_BRB_MAC_PAUSE_XOFF_THR_NON_PAUSE 0
167
168#define PFC_E2_BRB_MAC_PAUSE_XON_THR_PAUSE 250
169#define PFC_E2_BRB_MAC_PAUSE_XON_THR_NON_PAUSE 0
170
171#define PFC_E2_BRB_MAC_FULL_XOFF_THR_PAUSE 10
172#define PFC_E2_BRB_MAC_FULL_XOFF_THR_NON_PAUSE 90
173
174#define PFC_E2_BRB_MAC_FULL_XON_THR_PAUSE 50
175#define PFC_E2_BRB_MAC_FULL_XON_THR_NON_PAUSE 250
176
177/* BRB thresholds for E3A0 */
178#define PFC_E3A0_BRB_MAC_PAUSE_XOFF_THR_PAUSE 290
179#define PFC_E3A0_BRB_MAC_PAUSE_XOFF_THR_NON_PAUSE 0
180
181#define PFC_E3A0_BRB_MAC_PAUSE_XON_THR_PAUSE 410
182#define PFC_E3A0_BRB_MAC_PAUSE_XON_THR_NON_PAUSE 0
183
184#define PFC_E3A0_BRB_MAC_FULL_XOFF_THR_PAUSE 10
185#define PFC_E3A0_BRB_MAC_FULL_XOFF_THR_NON_PAUSE 170
186
187#define PFC_E3A0_BRB_MAC_FULL_XON_THR_PAUSE 50
188#define PFC_E3A0_BRB_MAC_FULL_XON_THR_NON_PAUSE 410
189
190
191/* BRB thresholds for E3B0 2 port mode*/
192#define PFC_E3B0_2P_BRB_MAC_PAUSE_XOFF_THR_PAUSE 1025
193#define PFC_E3B0_2P_BRB_MAC_PAUSE_XOFF_THR_NON_PAUSE 0
194
195#define PFC_E3B0_2P_BRB_MAC_PAUSE_XON_THR_PAUSE 1025
196#define PFC_E3B0_2P_BRB_MAC_PAUSE_XON_THR_NON_PAUSE 0
197
198#define PFC_E3B0_2P_BRB_MAC_FULL_XOFF_THR_PAUSE 10
199#define PFC_E3B0_2P_BRB_MAC_FULL_XOFF_THR_NON_PAUSE 1025
200
201#define PFC_E3B0_2P_BRB_MAC_FULL_XON_THR_PAUSE 50
202#define PFC_E3B0_2P_BRB_MAC_FULL_XON_THR_NON_PAUSE 1025
203
204/* only for E3B0*/
205#define PFC_E3B0_2P_BRB_FULL_LB_XOFF_THR 1025
206#define PFC_E3B0_2P_BRB_FULL_LB_XON_THR 1025
207
208/* Lossy +Lossless GUARANTIED == GUART */
209#define PFC_E3B0_2P_MIX_PAUSE_LB_GUART 284
210/* Lossless +Lossless*/
211#define PFC_E3B0_2P_PAUSE_LB_GUART 236
212/* Lossy +Lossy*/
213#define PFC_E3B0_2P_NON_PAUSE_LB_GUART 342
214
215/* Lossy +Lossless*/
216#define PFC_E3B0_2P_MIX_PAUSE_MAC_0_CLASS_T_GUART 284
217/* Lossless +Lossless*/
218#define PFC_E3B0_2P_PAUSE_MAC_0_CLASS_T_GUART 236
219/* Lossy +Lossy*/
220#define PFC_E3B0_2P_NON_PAUSE_MAC_0_CLASS_T_GUART 336
221#define PFC_E3B0_2P_BRB_MAC_0_CLASS_T_GUART_HYST 80
222
223#define PFC_E3B0_2P_BRB_MAC_1_CLASS_T_GUART 0
224#define PFC_E3B0_2P_BRB_MAC_1_CLASS_T_GUART_HYST 0
225
226/* BRB thresholds for E3B0 4 port mode */
227#define PFC_E3B0_4P_BRB_MAC_PAUSE_XOFF_THR_PAUSE 304
228#define PFC_E3B0_4P_BRB_MAC_PAUSE_XOFF_THR_NON_PAUSE 0
229
230#define PFC_E3B0_4P_BRB_MAC_PAUSE_XON_THR_PAUSE 384
231#define PFC_E3B0_4P_BRB_MAC_PAUSE_XON_THR_NON_PAUSE 0
232
233#define PFC_E3B0_4P_BRB_MAC_FULL_XOFF_THR_PAUSE 10
234#define PFC_E3B0_4P_BRB_MAC_FULL_XOFF_THR_NON_PAUSE 304
235
236#define PFC_E3B0_4P_BRB_MAC_FULL_XON_THR_PAUSE 50
237#define PFC_E3B0_4P_BRB_MAC_FULL_XON_THR_NON_PAUSE 384
238
239
240/* only for E3B0*/
241#define PFC_E3B0_4P_BRB_FULL_LB_XOFF_THR 304
242#define PFC_E3B0_4P_BRB_FULL_LB_XON_THR 384
243#define PFC_E3B0_4P_LB_GUART 120
244
245#define PFC_E3B0_4P_BRB_MAC_0_CLASS_T_GUART 120
246#define PFC_E3B0_4P_BRB_MAC_0_CLASS_T_GUART_HYST 80
247
248#define PFC_E3B0_4P_BRB_MAC_1_CLASS_T_GUART 80
249#define PFC_E3B0_4P_BRB_MAC_1_CLASS_T_GUART_HYST 120
250
251#define DCBX_INVALID_COS (0xFF)
252
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000253#define ETS_BW_LIMIT_CREDIT_UPPER_BOUND (0x5000)
254#define ETS_BW_LIMIT_CREDIT_WEIGHT (0x5000)
Yaniv Rosner9380bb92011-06-14 01:34:07 +0000255#define ETS_E3B0_NIG_MIN_W_VAL_UP_TO_10GBPS (1360)
256#define ETS_E3B0_NIG_MIN_W_VAL_20GBPS (2720)
257#define ETS_E3B0_PBF_MIN_W_VAL (10000)
258
259#define MAX_PACKET_SIZE (9700)
Yaniv Rosner3c9ada22011-06-14 01:34:12 +0000260#define WC_UC_TIMEOUT 100
Yaniv Rosner9380bb92011-06-14 01:34:07 +0000261
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700262/**********************************************************/
263/* INTERFACE */
264/**********************************************************/
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000265
Yaniv Rosnercd2be892011-01-31 04:21:45 +0000266#define CL22_WR_OVER_CL45(_bp, _phy, _bank, _addr, _val) \
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000267 bnx2x_cl45_write(_bp, _phy, \
Yaniv Rosner7aa07112010-09-07 11:41:01 +0000268 (_phy)->def_md_devad, \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700269 (_bank + (_addr & 0xf)), \
270 _val)
271
Yaniv Rosnercd2be892011-01-31 04:21:45 +0000272#define CL22_RD_OVER_CL45(_bp, _phy, _bank, _addr, _val) \
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000273 bnx2x_cl45_read(_bp, _phy, \
Yaniv Rosner7aa07112010-09-07 11:41:01 +0000274 (_phy)->def_md_devad, \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700275 (_bank + (_addr & 0xf)), \
276 _val)
277
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700278static u32 bnx2x_bits_en(struct bnx2x *bp, u32 reg, u32 bits)
279{
280 u32 val = REG_RD(bp, reg);
281
282 val |= bits;
283 REG_WR(bp, reg, val);
284 return val;
285}
286
287static u32 bnx2x_bits_dis(struct bnx2x *bp, u32 reg, u32 bits)
288{
289 u32 val = REG_RD(bp, reg);
290
291 val &= ~bits;
292 REG_WR(bp, reg, val);
293 return val;
294}
295
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000296/******************************************************************/
Yaniv Rosner3c9ada22011-06-14 01:34:12 +0000297/* EPIO/GPIO section */
298/******************************************************************/
299static void bnx2x_set_epio(struct bnx2x *bp, u32 epio_pin, u32 en)
300{
301 u32 epio_mask, gp_output, gp_oenable;
302
303 /* Sanity check */
304 if (epio_pin > 31) {
305 DP(NETIF_MSG_LINK, "Invalid EPIO pin %d to set\n", epio_pin);
306 return;
307 }
308 DP(NETIF_MSG_LINK, "Setting EPIO pin %d to %d\n", epio_pin, en);
309 epio_mask = 1 << epio_pin;
310 /* Set this EPIO to output */
311 gp_output = REG_RD(bp, MCP_REG_MCPR_GP_OUTPUTS);
312 if (en)
313 gp_output |= epio_mask;
314 else
315 gp_output &= ~epio_mask;
316
317 REG_WR(bp, MCP_REG_MCPR_GP_OUTPUTS, gp_output);
318
319 /* Set the value for this EPIO */
320 gp_oenable = REG_RD(bp, MCP_REG_MCPR_GP_OENABLE);
321 REG_WR(bp, MCP_REG_MCPR_GP_OENABLE, gp_oenable | epio_mask);
322}
323
324static void bnx2x_set_cfg_pin(struct bnx2x *bp, u32 pin_cfg, u32 val)
325{
326 if (pin_cfg == PIN_CFG_NA)
327 return;
328 if (pin_cfg >= PIN_CFG_EPIO0) {
329 bnx2x_set_epio(bp, pin_cfg - PIN_CFG_EPIO0, val);
330 } else {
331 u8 gpio_num = (pin_cfg - PIN_CFG_GPIO0_P0) & 0x3;
332 u8 gpio_port = (pin_cfg - PIN_CFG_GPIO0_P0) >> 2;
333 bnx2x_set_gpio(bp, gpio_num, (u8)val, gpio_port);
334 }
335}
336
337/******************************************************************/
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000338/* ETS section */
339/******************************************************************/
Yaniv Rosner6c3218c2011-06-14 01:34:23 +0000340static void bnx2x_ets_e2e3a0_disabled(struct link_params *params)
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000341{
342 /* ETS disabled configuration*/
343 struct bnx2x *bp = params->bp;
344
Yaniv Rosner6c3218c2011-06-14 01:34:23 +0000345 DP(NETIF_MSG_LINK, "ETS E2E3 disabled configuration\n");
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000346
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000347 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000348 * mapping between entry priority to client number (0,1,2 -debug and
349 * management clients, 3 - COS0 client, 4 - COS client)(HIGHEST)
350 * 3bits client num.
351 * PRI4 | PRI3 | PRI2 | PRI1 | PRI0
352 * cos1-100 cos0-011 dbg1-010 dbg0-001 MCP-000
353 */
354
355 REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT, 0x4688);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000356 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000357 * Bitmap of 5bits length. Each bit specifies whether the entry behaves
358 * as strict. Bits 0,1,2 - debug and management entries, 3 -
359 * COS0 entry, 4 - COS1 entry.
360 * COS1 | COS0 | DEBUG1 | DEBUG0 | MGMT
361 * bit4 bit3 bit2 bit1 bit0
362 * MCP and debug are strict
363 */
364
365 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x7);
366 /* defines which entries (clients) are subjected to WFQ arbitration */
367 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ, 0);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000368 /*
369 * For strict priority entries defines the number of consecutive
370 * slots for the highest priority.
371 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000372 REG_WR(bp, NIG_REG_P0_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000373 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000374 * mapping between the CREDIT_WEIGHT registers and actual client
375 * numbers
376 */
377 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP, 0);
378 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_0, 0);
379 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_1, 0);
380
381 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_0, 0);
382 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_1, 0);
383 REG_WR(bp, PBF_REG_HIGH_PRIORITY_COS_NUM, 0);
384 /* ETS mode disable */
385 REG_WR(bp, PBF_REG_ETS_ENABLED, 0);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000386 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000387 * If ETS mode is enabled (there is no strict priority) defines a WFQ
388 * weight for COS0/COS1.
389 */
390 REG_WR(bp, PBF_REG_COS0_WEIGHT, 0x2710);
391 REG_WR(bp, PBF_REG_COS1_WEIGHT, 0x2710);
392 /* Upper bound that COS0_WEIGHT can reach in the WFQ arbiter */
393 REG_WR(bp, PBF_REG_COS0_UPPER_BOUND, 0x989680);
394 REG_WR(bp, PBF_REG_COS1_UPPER_BOUND, 0x989680);
395 /* Defines the number of consecutive slots for the strict priority */
396 REG_WR(bp, PBF_REG_NUM_STRICT_ARB_SLOTS, 0);
397}
Yaniv Rosner6c3218c2011-06-14 01:34:23 +0000398/******************************************************************************
399* Description:
400* Getting min_w_val will be set according to line speed .
401*.
402******************************************************************************/
403static u32 bnx2x_ets_get_min_w_val_nig(const struct link_vars *vars)
404{
405 u32 min_w_val = 0;
406 /* Calculate min_w_val.*/
407 if (vars->link_up) {
408 if (SPEED_20000 == vars->line_speed)
409 min_w_val = ETS_E3B0_NIG_MIN_W_VAL_20GBPS;
410 else
411 min_w_val = ETS_E3B0_NIG_MIN_W_VAL_UP_TO_10GBPS;
412 } else
413 min_w_val = ETS_E3B0_NIG_MIN_W_VAL_20GBPS;
414 /**
415 * If the link isn't up (static configuration for example ) The
416 * link will be according to 20GBPS.
417 */
418 return min_w_val;
419}
420/******************************************************************************
421* Description:
422* Getting credit upper bound form min_w_val.
423*.
424******************************************************************************/
425static u32 bnx2x_ets_get_credit_upper_bound(const u32 min_w_val)
426{
427 const u32 credit_upper_bound = (u32)MAXVAL((150 * min_w_val),
428 MAX_PACKET_SIZE);
429 return credit_upper_bound;
430}
431/******************************************************************************
432* Description:
433* Set credit upper bound for NIG.
434*.
435******************************************************************************/
436static void bnx2x_ets_e3b0_set_credit_upper_bound_nig(
437 const struct link_params *params,
438 const u32 min_w_val)
439{
440 struct bnx2x *bp = params->bp;
441 const u8 port = params->port;
442 const u32 credit_upper_bound =
443 bnx2x_ets_get_credit_upper_bound(min_w_val);
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000444
Yaniv Rosner6c3218c2011-06-14 01:34:23 +0000445 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_UPPER_BOUND_0 :
446 NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_0, credit_upper_bound);
447 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_UPPER_BOUND_1 :
448 NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_1, credit_upper_bound);
449 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_UPPER_BOUND_2 :
450 NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_2, credit_upper_bound);
451 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_UPPER_BOUND_3 :
452 NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_3, credit_upper_bound);
453 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_UPPER_BOUND_4 :
454 NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_4, credit_upper_bound);
455 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_UPPER_BOUND_5 :
456 NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_5, credit_upper_bound);
457
458 if (0 == port) {
459 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_6,
460 credit_upper_bound);
461 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_7,
462 credit_upper_bound);
463 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_8,
464 credit_upper_bound);
465 }
466}
467/******************************************************************************
468* Description:
469* Will return the NIG ETS registers to init values.Except
470* credit_upper_bound.
471* That isn't used in this configuration (No WFQ is enabled) and will be
472* configured acording to spec
473*.
474******************************************************************************/
475static void bnx2x_ets_e3b0_nig_disabled(const struct link_params *params,
476 const struct link_vars *vars)
477{
478 struct bnx2x *bp = params->bp;
479 const u8 port = params->port;
480 const u32 min_w_val = bnx2x_ets_get_min_w_val_nig(vars);
481 /**
482 * mapping between entry priority to client number (0,1,2 -debug and
483 * management clients, 3 - COS0 client, 4 - COS1, ... 8 -
484 * COS5)(HIGHEST) 4bits client num.TODO_ETS - Should be done by
485 * reset value or init tool
486 */
487 if (port) {
488 REG_WR(bp, NIG_REG_P1_TX_ARB_PRIORITY_CLIENT2_LSB, 0x543210);
489 REG_WR(bp, NIG_REG_P1_TX_ARB_PRIORITY_CLIENT2_MSB, 0x0);
490 } else {
491 REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT2_LSB, 0x76543210);
492 REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT2_MSB, 0x8);
493 }
494 /**
495 * For strict priority entries defines the number of consecutive
496 * slots for the highest priority.
497 */
498 /* TODO_ETS - Should be done by reset value or init tool */
499 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_NUM_STRICT_ARB_SLOTS :
500 NIG_REG_P1_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100);
501 /**
502 * mapping between the CREDIT_WEIGHT registers and actual client
503 * numbers
504 */
505 /* TODO_ETS - Should be done by reset value or init tool */
506 if (port) {
507 /*Port 1 has 6 COS*/
508 REG_WR(bp, NIG_REG_P1_TX_ARB_CLIENT_CREDIT_MAP2_LSB, 0x210543);
509 REG_WR(bp, NIG_REG_P1_TX_ARB_CLIENT_CREDIT_MAP2_MSB, 0x0);
510 } else {
511 /*Port 0 has 9 COS*/
512 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP2_LSB,
513 0x43210876);
514 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP2_MSB, 0x5);
515 }
516
517 /**
518 * Bitmap of 5bits length. Each bit specifies whether the entry behaves
519 * as strict. Bits 0,1,2 - debug and management entries, 3 -
520 * COS0 entry, 4 - COS1 entry.
521 * COS1 | COS0 | DEBUG1 | DEBUG0 | MGMT
522 * bit4 bit3 bit2 bit1 bit0
523 * MCP and debug are strict
524 */
525 if (port)
526 REG_WR(bp, NIG_REG_P1_TX_ARB_CLIENT_IS_STRICT, 0x3f);
527 else
528 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x1ff);
529 /* defines which entries (clients) are subjected to WFQ arbitration */
530 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CLIENT_IS_SUBJECT2WFQ :
531 NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ, 0);
532
533 /**
534 * Please notice the register address are note continuous and a
535 * for here is note appropriate.In 2 port mode port0 only COS0-5
536 * can be used. DEBUG1,DEBUG1,MGMT are never used for WFQ* In 4
537 * port mode port1 only COS0-2 can be used. DEBUG1,DEBUG1,MGMT
538 * are never used for WFQ
539 */
540 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_0 :
541 NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_0, 0x0);
542 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_1 :
543 NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_1, 0x0);
544 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_2 :
545 NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_2, 0x0);
546 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_3 :
547 NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_3, 0x0);
548 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_4 :
549 NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_4, 0x0);
550 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_5 :
551 NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_5, 0x0);
552 if (0 == port) {
553 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_6, 0x0);
554 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_7, 0x0);
555 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_8, 0x0);
556 }
557
558 bnx2x_ets_e3b0_set_credit_upper_bound_nig(params, min_w_val);
559}
560/******************************************************************************
561* Description:
562* Set credit upper bound for PBF.
563*.
564******************************************************************************/
565static void bnx2x_ets_e3b0_set_credit_upper_bound_pbf(
566 const struct link_params *params,
567 const u32 min_w_val)
568{
569 struct bnx2x *bp = params->bp;
570 const u32 credit_upper_bound =
571 bnx2x_ets_get_credit_upper_bound(min_w_val);
572 const u8 port = params->port;
573 u32 base_upper_bound = 0;
574 u8 max_cos = 0;
575 u8 i = 0;
576 /**
577 * In 2 port mode port0 has COS0-5 that can be used for WFQ.In 4
578 * port mode port1 has COS0-2 that can be used for WFQ.
579 */
580 if (0 == port) {
581 base_upper_bound = PBF_REG_COS0_UPPER_BOUND_P0;
582 max_cos = DCBX_E3B0_MAX_NUM_COS_PORT0;
583 } else {
584 base_upper_bound = PBF_REG_COS0_UPPER_BOUND_P1;
585 max_cos = DCBX_E3B0_MAX_NUM_COS_PORT1;
586 }
587
588 for (i = 0; i < max_cos; i++)
589 REG_WR(bp, base_upper_bound + (i << 2), credit_upper_bound);
590}
591
592/******************************************************************************
593* Description:
594* Will return the PBF ETS registers to init values.Except
595* credit_upper_bound.
596* That isn't used in this configuration (No WFQ is enabled) and will be
597* configured acording to spec
598*.
599******************************************************************************/
600static void bnx2x_ets_e3b0_pbf_disabled(const struct link_params *params)
601{
602 struct bnx2x *bp = params->bp;
603 const u8 port = params->port;
604 const u32 min_w_val_pbf = ETS_E3B0_PBF_MIN_W_VAL;
605 u8 i = 0;
606 u32 base_weight = 0;
607 u8 max_cos = 0;
608
609 /**
610 * mapping between entry priority to client number 0 - COS0
611 * client, 2 - COS1, ... 5 - COS5)(HIGHEST) 4bits client num.
612 * TODO_ETS - Should be done by reset value or init tool
613 */
614 if (port)
615 /* 0x688 (|011|0 10|00 1|000) */
616 REG_WR(bp, PBF_REG_ETS_ARB_PRIORITY_CLIENT_P1 , 0x688);
617 else
618 /* (10 1|100 |011|0 10|00 1|000) */
619 REG_WR(bp, PBF_REG_ETS_ARB_PRIORITY_CLIENT_P0 , 0x2C688);
620
621 /* TODO_ETS - Should be done by reset value or init tool */
622 if (port)
623 /* 0x688 (|011|0 10|00 1|000)*/
624 REG_WR(bp, PBF_REG_ETS_ARB_CLIENT_CREDIT_MAP_P1, 0x688);
625 else
626 /* 0x2C688 (10 1|100 |011|0 10|00 1|000) */
627 REG_WR(bp, PBF_REG_ETS_ARB_CLIENT_CREDIT_MAP_P0, 0x2C688);
628
629 REG_WR(bp, (port) ? PBF_REG_ETS_ARB_NUM_STRICT_ARB_SLOTS_P1 :
630 PBF_REG_ETS_ARB_NUM_STRICT_ARB_SLOTS_P0 , 0x100);
631
632
633 REG_WR(bp, (port) ? PBF_REG_ETS_ARB_CLIENT_IS_STRICT_P1 :
634 PBF_REG_ETS_ARB_CLIENT_IS_STRICT_P0 , 0);
635
636 REG_WR(bp, (port) ? PBF_REG_ETS_ARB_CLIENT_IS_SUBJECT2WFQ_P1 :
637 PBF_REG_ETS_ARB_CLIENT_IS_SUBJECT2WFQ_P0 , 0);
638 /**
639 * In 2 port mode port0 has COS0-5 that can be used for WFQ.
640 * In 4 port mode port1 has COS0-2 that can be used for WFQ.
641 */
642 if (0 == port) {
643 base_weight = PBF_REG_COS0_WEIGHT_P0;
644 max_cos = DCBX_E3B0_MAX_NUM_COS_PORT0;
645 } else {
646 base_weight = PBF_REG_COS0_WEIGHT_P1;
647 max_cos = DCBX_E3B0_MAX_NUM_COS_PORT1;
648 }
649
650 for (i = 0; i < max_cos; i++)
651 REG_WR(bp, base_weight + (0x4 * i), 0);
652
653 bnx2x_ets_e3b0_set_credit_upper_bound_pbf(params, min_w_val_pbf);
654}
655/******************************************************************************
656* Description:
657* E3B0 disable will return basicly the values to init values.
658*.
659******************************************************************************/
660static int bnx2x_ets_e3b0_disabled(const struct link_params *params,
661 const struct link_vars *vars)
662{
663 struct bnx2x *bp = params->bp;
664
665 if (!CHIP_IS_E3B0(bp)) {
666 DP(NETIF_MSG_LINK, "bnx2x_ets_e3b0_disabled the chip isn't E3B0"
667 "\n");
668 return -EINVAL;
669 }
670
671 bnx2x_ets_e3b0_nig_disabled(params, vars);
672
673 bnx2x_ets_e3b0_pbf_disabled(params);
674
675 return 0;
676}
677
678/******************************************************************************
679* Description:
680* Disable will return basicly the values to init values.
681*.
682******************************************************************************/
683int bnx2x_ets_disabled(struct link_params *params,
684 struct link_vars *vars)
685{
686 struct bnx2x *bp = params->bp;
687 int bnx2x_status = 0;
688
689 if ((CHIP_IS_E2(bp)) || (CHIP_IS_E3A0(bp)))
690 bnx2x_ets_e2e3a0_disabled(params);
691 else if (CHIP_IS_E3B0(bp))
692 bnx2x_status = bnx2x_ets_e3b0_disabled(params, vars);
693 else {
694 DP(NETIF_MSG_LINK, "bnx2x_ets_disabled - chip not supported\n");
695 return -EINVAL;
696 }
697
698 return bnx2x_status;
699}
700
701/******************************************************************************
702* Description
703* Set the COS mappimg to SP and BW until this point all the COS are not
704* set as SP or BW.
705******************************************************************************/
706static int bnx2x_ets_e3b0_cli_map(const struct link_params *params,
707 const struct bnx2x_ets_params *ets_params,
708 const u8 cos_sp_bitmap,
709 const u8 cos_bw_bitmap)
710{
711 struct bnx2x *bp = params->bp;
712 const u8 port = params->port;
713 const u8 nig_cli_sp_bitmap = 0x7 | (cos_sp_bitmap << 3);
714 const u8 pbf_cli_sp_bitmap = cos_sp_bitmap;
715 const u8 nig_cli_subject2wfq_bitmap = cos_bw_bitmap << 3;
716 const u8 pbf_cli_subject2wfq_bitmap = cos_bw_bitmap;
717
718 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CLIENT_IS_STRICT :
719 NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, nig_cli_sp_bitmap);
720
721 REG_WR(bp, (port) ? PBF_REG_ETS_ARB_CLIENT_IS_STRICT_P1 :
722 PBF_REG_ETS_ARB_CLIENT_IS_STRICT_P0 , pbf_cli_sp_bitmap);
723
724 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CLIENT_IS_SUBJECT2WFQ :
725 NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ,
726 nig_cli_subject2wfq_bitmap);
727
728 REG_WR(bp, (port) ? PBF_REG_ETS_ARB_CLIENT_IS_SUBJECT2WFQ_P1 :
729 PBF_REG_ETS_ARB_CLIENT_IS_SUBJECT2WFQ_P0,
730 pbf_cli_subject2wfq_bitmap);
731
732 return 0;
733}
734
735/******************************************************************************
736* Description:
737* This function is needed because NIG ARB_CREDIT_WEIGHT_X are
738* not continues and ARB_CREDIT_WEIGHT_0 + offset is suitable.
739******************************************************************************/
740static int bnx2x_ets_e3b0_set_cos_bw(struct bnx2x *bp,
741 const u8 cos_entry,
742 const u32 min_w_val_nig,
743 const u32 min_w_val_pbf,
744 const u16 total_bw,
745 const u8 bw,
746 const u8 port)
747{
748 u32 nig_reg_adress_crd_weight = 0;
749 u32 pbf_reg_adress_crd_weight = 0;
750 /* Calculate and set BW for this COS*/
751 const u32 cos_bw_nig = (bw * min_w_val_nig) / total_bw;
752 const u32 cos_bw_pbf = (bw * min_w_val_pbf) / total_bw;
753
754 switch (cos_entry) {
755 case 0:
756 nig_reg_adress_crd_weight =
757 (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_0 :
758 NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_0;
759 pbf_reg_adress_crd_weight = (port) ?
760 PBF_REG_COS0_WEIGHT_P1 : PBF_REG_COS0_WEIGHT_P0;
761 break;
762 case 1:
763 nig_reg_adress_crd_weight = (port) ?
764 NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_1 :
765 NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_1;
766 pbf_reg_adress_crd_weight = (port) ?
767 PBF_REG_COS1_WEIGHT_P1 : PBF_REG_COS1_WEIGHT_P0;
768 break;
769 case 2:
770 nig_reg_adress_crd_weight = (port) ?
771 NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_2 :
772 NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_2;
773
774 pbf_reg_adress_crd_weight = (port) ?
775 PBF_REG_COS2_WEIGHT_P1 : PBF_REG_COS2_WEIGHT_P0;
776 break;
777 case 3:
778 if (port)
779 return -EINVAL;
780 nig_reg_adress_crd_weight =
781 NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_3;
782 pbf_reg_adress_crd_weight =
783 PBF_REG_COS3_WEIGHT_P0;
784 break;
785 case 4:
786 if (port)
787 return -EINVAL;
788 nig_reg_adress_crd_weight =
789 NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_4;
790 pbf_reg_adress_crd_weight = PBF_REG_COS4_WEIGHT_P0;
791 break;
792 case 5:
793 if (port)
794 return -EINVAL;
795 nig_reg_adress_crd_weight =
796 NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_5;
797 pbf_reg_adress_crd_weight = PBF_REG_COS5_WEIGHT_P0;
798 break;
799 }
800
801 REG_WR(bp, nig_reg_adress_crd_weight, cos_bw_nig);
802
803 REG_WR(bp, pbf_reg_adress_crd_weight, cos_bw_pbf);
804
805 return 0;
806}
807/******************************************************************************
808* Description:
809* Calculate the total BW.A value of 0 isn't legal.
810*.
811******************************************************************************/
812static int bnx2x_ets_e3b0_get_total_bw(
813 const struct link_params *params,
814 const struct bnx2x_ets_params *ets_params,
815 u16 *total_bw)
816{
817 struct bnx2x *bp = params->bp;
818 u8 cos_idx = 0;
819
820 *total_bw = 0 ;
821 /* Calculate total BW requested */
822 for (cos_idx = 0; cos_idx < ets_params->num_of_cos; cos_idx++) {
823 if (bnx2x_cos_state_bw == ets_params->cos[cos_idx].state) {
824
825 if (0 == ets_params->cos[cos_idx].params.bw_params.bw) {
826 DP(NETIF_MSG_LINK, "bnx2x_ets_E3B0_config BW"
827 "was set to 0\n");
828 return -EINVAL;
829 }
830 *total_bw +=
831 ets_params->cos[cos_idx].params.bw_params.bw;
832 }
833 }
834
835 /*Check taotl BW is valid */
836 if ((100 != *total_bw) || (0 == *total_bw)) {
837 if (0 == *total_bw) {
838 DP(NETIF_MSG_LINK, "bnx2x_ets_E3B0_config toatl BW"
839 "shouldn't be 0\n");
840 return -EINVAL;
841 }
842 DP(NETIF_MSG_LINK, "bnx2x_ets_E3B0_config toatl BW should be"
843 "100\n");
844 /**
845 * We can handle a case whre the BW isn't 100 this can happen
846 * if the TC are joined.
847 */
848 }
849 return 0;
850}
851
852/******************************************************************************
853* Description:
854* Invalidate all the sp_pri_to_cos.
855*.
856******************************************************************************/
857static void bnx2x_ets_e3b0_sp_pri_to_cos_init(u8 *sp_pri_to_cos)
858{
859 u8 pri = 0;
860 for (pri = 0; pri < DCBX_MAX_NUM_COS; pri++)
861 sp_pri_to_cos[pri] = DCBX_INVALID_COS;
862}
863/******************************************************************************
864* Description:
865* Calculate and set the SP (ARB_PRIORITY_CLIENT) NIG and PBF registers
866* according to sp_pri_to_cos.
867*.
868******************************************************************************/
869static int bnx2x_ets_e3b0_sp_pri_to_cos_set(const struct link_params *params,
870 u8 *sp_pri_to_cos, const u8 pri,
871 const u8 cos_entry)
872{
873 struct bnx2x *bp = params->bp;
874 const u8 port = params->port;
875 const u8 max_num_of_cos = (port) ? DCBX_E3B0_MAX_NUM_COS_PORT1 :
876 DCBX_E3B0_MAX_NUM_COS_PORT0;
877
878 if (DCBX_INVALID_COS != sp_pri_to_cos[pri]) {
879 DP(NETIF_MSG_LINK, "bnx2x_ets_e3b0_sp_pri_to_cos_set invalid "
880 "parameter There can't be two COS's with"
881 "the same strict pri\n");
882 return -EINVAL;
883 }
884
885 if (pri > max_num_of_cos) {
886 DP(NETIF_MSG_LINK, "bnx2x_ets_e3b0_sp_pri_to_cos_set invalid"
887 "parameter Illegal strict priority\n");
888 return -EINVAL;
889 }
890
891 sp_pri_to_cos[pri] = cos_entry;
892 return 0;
893
894}
895
896/******************************************************************************
897* Description:
898* Returns the correct value according to COS and priority in
899* the sp_pri_cli register.
900*.
901******************************************************************************/
902static u64 bnx2x_e3b0_sp_get_pri_cli_reg(const u8 cos, const u8 cos_offset,
903 const u8 pri_set,
904 const u8 pri_offset,
905 const u8 entry_size)
906{
907 u64 pri_cli_nig = 0;
908 pri_cli_nig = ((u64)(cos + cos_offset)) << (entry_size *
909 (pri_set + pri_offset));
910
911 return pri_cli_nig;
912}
913/******************************************************************************
914* Description:
915* Returns the correct value according to COS and priority in the
916* sp_pri_cli register for NIG.
917*.
918******************************************************************************/
919static u64 bnx2x_e3b0_sp_get_pri_cli_reg_nig(const u8 cos, const u8 pri_set)
920{
921 /* MCP Dbg0 and dbg1 are always with higher strict pri*/
922 const u8 nig_cos_offset = 3;
923 const u8 nig_pri_offset = 3;
924
925 return bnx2x_e3b0_sp_get_pri_cli_reg(cos, nig_cos_offset, pri_set,
926 nig_pri_offset, 4);
927
928}
929/******************************************************************************
930* Description:
931* Returns the correct value according to COS and priority in the
932* sp_pri_cli register for PBF.
933*.
934******************************************************************************/
935static u64 bnx2x_e3b0_sp_get_pri_cli_reg_pbf(const u8 cos, const u8 pri_set)
936{
937 const u8 pbf_cos_offset = 0;
938 const u8 pbf_pri_offset = 0;
939
940 return bnx2x_e3b0_sp_get_pri_cli_reg(cos, pbf_cos_offset, pri_set,
941 pbf_pri_offset, 3);
942
943}
944
945/******************************************************************************
946* Description:
947* Calculate and set the SP (ARB_PRIORITY_CLIENT) NIG and PBF registers
948* according to sp_pri_to_cos.(which COS has higher priority)
949*.
950******************************************************************************/
951static int bnx2x_ets_e3b0_sp_set_pri_cli_reg(const struct link_params *params,
952 u8 *sp_pri_to_cos)
953{
954 struct bnx2x *bp = params->bp;
955 u8 i = 0;
956 const u8 port = params->port;
957 /* MCP Dbg0 and dbg1 are always with higher strict pri*/
958 u64 pri_cli_nig = 0x210;
959 u32 pri_cli_pbf = 0x0;
960 u8 pri_set = 0;
961 u8 pri_bitmask = 0;
962 const u8 max_num_of_cos = (port) ? DCBX_E3B0_MAX_NUM_COS_PORT1 :
963 DCBX_E3B0_MAX_NUM_COS_PORT0;
964
965 u8 cos_bit_to_set = (1 << max_num_of_cos) - 1;
966
967 /* Set all the strict priority first */
968 for (i = 0; i < max_num_of_cos; i++) {
969 if (DCBX_INVALID_COS != sp_pri_to_cos[i]) {
970 if (DCBX_MAX_NUM_COS <= sp_pri_to_cos[i]) {
971 DP(NETIF_MSG_LINK,
972 "bnx2x_ets_e3b0_sp_set_pri_cli_reg "
973 "invalid cos entry\n");
974 return -EINVAL;
975 }
976
977 pri_cli_nig |= bnx2x_e3b0_sp_get_pri_cli_reg_nig(
978 sp_pri_to_cos[i], pri_set);
979
980 pri_cli_pbf |= bnx2x_e3b0_sp_get_pri_cli_reg_pbf(
981 sp_pri_to_cos[i], pri_set);
982 pri_bitmask = 1 << sp_pri_to_cos[i];
983 /* COS is used remove it from bitmap.*/
984 if (0 == (pri_bitmask & cos_bit_to_set)) {
985 DP(NETIF_MSG_LINK,
986 "bnx2x_ets_e3b0_sp_set_pri_cli_reg "
987 "invalid There can't be two COS's with"
988 " the same strict pri\n");
989 return -EINVAL;
990 }
991 cos_bit_to_set &= ~pri_bitmask;
992 pri_set++;
993 }
994 }
995
996 /* Set all the Non strict priority i= COS*/
997 for (i = 0; i < max_num_of_cos; i++) {
998 pri_bitmask = 1 << i;
999 /* Check if COS was already used for SP */
1000 if (pri_bitmask & cos_bit_to_set) {
1001 /* COS wasn't used for SP */
1002 pri_cli_nig |= bnx2x_e3b0_sp_get_pri_cli_reg_nig(
1003 i, pri_set);
1004
1005 pri_cli_pbf |= bnx2x_e3b0_sp_get_pri_cli_reg_pbf(
1006 i, pri_set);
1007 /* COS is used remove it from bitmap.*/
1008 cos_bit_to_set &= ~pri_bitmask;
1009 pri_set++;
1010 }
1011 }
1012
1013 if (pri_set != max_num_of_cos) {
1014 DP(NETIF_MSG_LINK, "bnx2x_ets_e3b0_sp_set_pri_cli_reg not all "
1015 "entries were set\n");
1016 return -EINVAL;
1017 }
1018
1019 if (port) {
1020 /* Only 6 usable clients*/
1021 REG_WR(bp, NIG_REG_P1_TX_ARB_PRIORITY_CLIENT2_LSB,
1022 (u32)pri_cli_nig);
1023
1024 REG_WR(bp, PBF_REG_ETS_ARB_PRIORITY_CLIENT_P1 , pri_cli_pbf);
1025 } else {
1026 /* Only 9 usable clients*/
1027 const u32 pri_cli_nig_lsb = (u32) (pri_cli_nig);
1028 const u32 pri_cli_nig_msb = (u32) ((pri_cli_nig >> 32) & 0xF);
1029
1030 REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT2_LSB,
1031 pri_cli_nig_lsb);
1032 REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT2_MSB,
1033 pri_cli_nig_msb);
1034
1035 REG_WR(bp, PBF_REG_ETS_ARB_PRIORITY_CLIENT_P0 , pri_cli_pbf);
1036 }
1037 return 0;
1038}
1039
1040/******************************************************************************
1041* Description:
1042* Configure the COS to ETS according to BW and SP settings.
1043******************************************************************************/
1044int bnx2x_ets_e3b0_config(const struct link_params *params,
1045 const struct link_vars *vars,
1046 const struct bnx2x_ets_params *ets_params)
1047{
1048 struct bnx2x *bp = params->bp;
1049 int bnx2x_status = 0;
1050 const u8 port = params->port;
1051 u16 total_bw = 0;
1052 const u32 min_w_val_nig = bnx2x_ets_get_min_w_val_nig(vars);
1053 const u32 min_w_val_pbf = ETS_E3B0_PBF_MIN_W_VAL;
1054 u8 cos_bw_bitmap = 0;
1055 u8 cos_sp_bitmap = 0;
1056 u8 sp_pri_to_cos[DCBX_MAX_NUM_COS] = {0};
1057 const u8 max_num_of_cos = (port) ? DCBX_E3B0_MAX_NUM_COS_PORT1 :
1058 DCBX_E3B0_MAX_NUM_COS_PORT0;
1059 u8 cos_entry = 0;
1060
1061 if (!CHIP_IS_E3B0(bp)) {
1062 DP(NETIF_MSG_LINK, "bnx2x_ets_e3b0_disabled the chip isn't E3B0"
1063 "\n");
1064 return -EINVAL;
1065 }
1066
1067 if ((ets_params->num_of_cos > max_num_of_cos)) {
1068 DP(NETIF_MSG_LINK, "bnx2x_ets_E3B0_config the number of COS "
1069 "isn't supported\n");
1070 return -EINVAL;
1071 }
1072
1073 /* Prepare sp strict priority parameters*/
1074 bnx2x_ets_e3b0_sp_pri_to_cos_init(sp_pri_to_cos);
1075
1076 /* Prepare BW parameters*/
1077 bnx2x_status = bnx2x_ets_e3b0_get_total_bw(params, ets_params,
1078 &total_bw);
1079 if (0 != bnx2x_status) {
1080 DP(NETIF_MSG_LINK, "bnx2x_ets_E3B0_config get_total_bw failed "
1081 "\n");
1082 return -EINVAL;
1083 }
1084
1085 /**
1086 * Upper bound is set according to current link speed (min_w_val
1087 * should be the same for upper bound and COS credit val).
1088 */
1089 bnx2x_ets_e3b0_set_credit_upper_bound_nig(params, min_w_val_nig);
1090 bnx2x_ets_e3b0_set_credit_upper_bound_pbf(params, min_w_val_pbf);
1091
1092
1093 for (cos_entry = 0; cos_entry < ets_params->num_of_cos; cos_entry++) {
1094 if (bnx2x_cos_state_bw == ets_params->cos[cos_entry].state) {
1095 cos_bw_bitmap |= (1 << cos_entry);
1096 /**
1097 * The function also sets the BW in HW(not the mappin
1098 * yet)
1099 */
1100 bnx2x_status = bnx2x_ets_e3b0_set_cos_bw(
1101 bp, cos_entry, min_w_val_nig, min_w_val_pbf,
1102 total_bw,
1103 ets_params->cos[cos_entry].params.bw_params.bw,
1104 port);
1105 } else if (bnx2x_cos_state_strict ==
1106 ets_params->cos[cos_entry].state){
1107 cos_sp_bitmap |= (1 << cos_entry);
1108
1109 bnx2x_status = bnx2x_ets_e3b0_sp_pri_to_cos_set(
1110 params,
1111 sp_pri_to_cos,
1112 ets_params->cos[cos_entry].params.sp_params.pri,
1113 cos_entry);
1114
1115 } else {
1116 DP(NETIF_MSG_LINK, "bnx2x_ets_e3b0_config cos state not"
1117 " valid\n");
1118 return -EINVAL;
1119 }
1120 if (0 != bnx2x_status) {
1121 DP(NETIF_MSG_LINK, "bnx2x_ets_e3b0_config set cos bw "
1122 "failed\n");
1123 return bnx2x_status;
1124 }
1125 }
1126
1127 /* Set SP register (which COS has higher priority) */
1128 bnx2x_status = bnx2x_ets_e3b0_sp_set_pri_cli_reg(params,
1129 sp_pri_to_cos);
1130
1131 if (0 != bnx2x_status) {
1132 DP(NETIF_MSG_LINK, "bnx2x_ets_E3B0_config set_pri_cli_reg "
1133 "failed\n");
1134 return bnx2x_status;
1135 }
1136
1137 /* Set client mapping of BW and strict */
1138 bnx2x_status = bnx2x_ets_e3b0_cli_map(params, ets_params,
1139 cos_sp_bitmap,
1140 cos_bw_bitmap);
1141
1142 if (0 != bnx2x_status) {
1143 DP(NETIF_MSG_LINK, "bnx2x_ets_E3B0_config SP failed\n");
1144 return bnx2x_status;
1145 }
1146 return 0;
1147}
Yaniv Rosner65a001b2011-01-31 04:22:03 +00001148static void bnx2x_ets_bw_limit_common(const struct link_params *params)
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001149{
1150 /* ETS disabled configuration */
1151 struct bnx2x *bp = params->bp;
1152 DP(NETIF_MSG_LINK, "ETS enabled BW limit configuration\n");
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001153 /*
1154 * defines which entries (clients) are subjected to WFQ arbitration
1155 * COS0 0x8
1156 * COS1 0x10
1157 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001158 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ, 0x18);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001159 /*
1160 * mapping between the ARB_CREDIT_WEIGHT registers and actual
1161 * client numbers (WEIGHT_0 does not actually have to represent
1162 * client 0)
1163 * PRI4 | PRI3 | PRI2 | PRI1 | PRI0
1164 * cos1-001 cos0-000 dbg1-100 dbg0-011 MCP-010
1165 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001166 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP, 0x111A);
1167
1168 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_0,
1169 ETS_BW_LIMIT_CREDIT_UPPER_BOUND);
1170 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_1,
1171 ETS_BW_LIMIT_CREDIT_UPPER_BOUND);
1172
1173 /* ETS mode enabled*/
1174 REG_WR(bp, PBF_REG_ETS_ENABLED, 1);
1175
1176 /* Defines the number of consecutive slots for the strict priority */
1177 REG_WR(bp, PBF_REG_NUM_STRICT_ARB_SLOTS, 0);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001178 /*
1179 * Bitmap of 5bits length. Each bit specifies whether the entry behaves
1180 * as strict. Bits 0,1,2 - debug and management entries, 3 - COS0
1181 * entry, 4 - COS1 entry.
1182 * COS1 | COS0 | DEBUG21 | DEBUG0 | MGMT
1183 * bit4 bit3 bit2 bit1 bit0
1184 * MCP and debug are strict
1185 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001186 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x7);
1187
1188 /* Upper bound that COS0_WEIGHT can reach in the WFQ arbiter.*/
1189 REG_WR(bp, PBF_REG_COS0_UPPER_BOUND,
1190 ETS_BW_LIMIT_CREDIT_UPPER_BOUND);
1191 REG_WR(bp, PBF_REG_COS1_UPPER_BOUND,
1192 ETS_BW_LIMIT_CREDIT_UPPER_BOUND);
1193}
1194
1195void bnx2x_ets_bw_limit(const struct link_params *params, const u32 cos0_bw,
1196 const u32 cos1_bw)
1197{
1198 /* ETS disabled configuration*/
1199 struct bnx2x *bp = params->bp;
1200 const u32 total_bw = cos0_bw + cos1_bw;
1201 u32 cos0_credit_weight = 0;
1202 u32 cos1_credit_weight = 0;
1203
1204 DP(NETIF_MSG_LINK, "ETS enabled BW limit configuration\n");
1205
1206 if ((0 == total_bw) ||
1207 (0 == cos0_bw) ||
1208 (0 == cos1_bw)) {
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001209 DP(NETIF_MSG_LINK, "Total BW can't be zero\n");
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001210 return;
1211 }
1212
1213 cos0_credit_weight = (cos0_bw * ETS_BW_LIMIT_CREDIT_WEIGHT)/
1214 total_bw;
1215 cos1_credit_weight = (cos1_bw * ETS_BW_LIMIT_CREDIT_WEIGHT)/
1216 total_bw;
1217
1218 bnx2x_ets_bw_limit_common(params);
1219
1220 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_0, cos0_credit_weight);
1221 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_1, cos1_credit_weight);
1222
1223 REG_WR(bp, PBF_REG_COS0_WEIGHT, cos0_credit_weight);
1224 REG_WR(bp, PBF_REG_COS1_WEIGHT, cos1_credit_weight);
1225}
1226
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00001227int bnx2x_ets_strict(const struct link_params *params, const u8 strict_cos)
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001228{
1229 /* ETS disabled configuration*/
1230 struct bnx2x *bp = params->bp;
1231 u32 val = 0;
1232
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001233 DP(NETIF_MSG_LINK, "ETS enabled strict configuration\n");
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001234 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001235 * Bitmap of 5bits length. Each bit specifies whether the entry behaves
1236 * as strict. Bits 0,1,2 - debug and management entries,
1237 * 3 - COS0 entry, 4 - COS1 entry.
1238 * COS1 | COS0 | DEBUG21 | DEBUG0 | MGMT
1239 * bit4 bit3 bit2 bit1 bit0
1240 * MCP and debug are strict
1241 */
1242 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x1F);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001243 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001244 * For strict priority entries defines the number of consecutive slots
1245 * for the highest priority.
1246 */
1247 REG_WR(bp, NIG_REG_P0_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100);
1248 /* ETS mode disable */
1249 REG_WR(bp, PBF_REG_ETS_ENABLED, 0);
1250 /* Defines the number of consecutive slots for the strict priority */
1251 REG_WR(bp, PBF_REG_NUM_STRICT_ARB_SLOTS, 0x100);
1252
1253 /* Defines the number of consecutive slots for the strict priority */
1254 REG_WR(bp, PBF_REG_HIGH_PRIORITY_COS_NUM, strict_cos);
1255
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001256 /*
1257 * mapping between entry priority to client number (0,1,2 -debug and
1258 * management clients, 3 - COS0 client, 4 - COS client)(HIGHEST)
1259 * 3bits client num.
1260 * PRI4 | PRI3 | PRI2 | PRI1 | PRI0
1261 * dbg0-010 dbg1-001 cos1-100 cos0-011 MCP-000
1262 * dbg0-010 dbg1-001 cos0-011 cos1-100 MCP-000
1263 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001264 val = (0 == strict_cos) ? 0x2318 : 0x22E0;
1265 REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT, val);
1266
1267 return 0;
1268}
1269/******************************************************************/
Dmitry Kravkove8920672011-05-04 23:52:40 +00001270/* PFC section */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001271/******************************************************************/
1272
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001273static void bnx2x_update_pfc_xmac(struct link_params *params,
1274 struct link_vars *vars,
1275 u8 is_lb)
1276{
1277 struct bnx2x *bp = params->bp;
1278 u32 xmac_base;
1279 u32 pause_val, pfc0_val, pfc1_val;
1280
1281 /* XMAC base adrr */
1282 xmac_base = (params->port) ? GRCBASE_XMAC1 : GRCBASE_XMAC0;
1283
1284 /* Initialize pause and pfc registers */
1285 pause_val = 0x18000;
1286 pfc0_val = 0xFFFF8000;
1287 pfc1_val = 0x2;
1288
1289 /* No PFC support */
1290 if (!(params->feature_config_flags &
1291 FEATURE_CONFIG_PFC_ENABLED)) {
1292
1293 /*
1294 * RX flow control - Process pause frame in receive direction
1295 */
1296 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
1297 pause_val |= XMAC_PAUSE_CTRL_REG_RX_PAUSE_EN;
1298
1299 /*
1300 * TX flow control - Send pause packet when buffer is full
1301 */
1302 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
1303 pause_val |= XMAC_PAUSE_CTRL_REG_TX_PAUSE_EN;
1304 } else {/* PFC support */
1305 pfc1_val |= XMAC_PFC_CTRL_HI_REG_PFC_REFRESH_EN |
1306 XMAC_PFC_CTRL_HI_REG_PFC_STATS_EN |
1307 XMAC_PFC_CTRL_HI_REG_RX_PFC_EN |
1308 XMAC_PFC_CTRL_HI_REG_TX_PFC_EN;
1309 }
1310
1311 /* Write pause and PFC registers */
1312 REG_WR(bp, xmac_base + XMAC_REG_PAUSE_CTRL, pause_val);
1313 REG_WR(bp, xmac_base + XMAC_REG_PFC_CTRL, pfc0_val);
1314 REG_WR(bp, xmac_base + XMAC_REG_PFC_CTRL_HI, pfc1_val);
1315
1316 udelay(30);
1317}
1318
1319
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001320static void bnx2x_bmac2_get_pfc_stat(struct link_params *params,
1321 u32 pfc_frames_sent[2],
1322 u32 pfc_frames_received[2])
1323{
1324 /* Read pfc statistic */
1325 struct bnx2x *bp = params->bp;
1326 u32 bmac_addr = params->port ? NIG_REG_INGRESS_BMAC1_MEM :
1327 NIG_REG_INGRESS_BMAC0_MEM;
1328
1329 DP(NETIF_MSG_LINK, "pfc statistic read from BMAC\n");
1330
1331 REG_RD_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_STAT_GTPP,
1332 pfc_frames_sent, 2);
1333
1334 REG_RD_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_STAT_GRPP,
1335 pfc_frames_received, 2);
1336
1337}
1338static void bnx2x_emac_get_pfc_stat(struct link_params *params,
1339 u32 pfc_frames_sent[2],
1340 u32 pfc_frames_received[2])
1341{
1342 /* Read pfc statistic */
1343 struct bnx2x *bp = params->bp;
1344 u32 emac_base = params->port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
1345 u32 val_xon = 0;
1346 u32 val_xoff = 0;
1347
1348 DP(NETIF_MSG_LINK, "pfc statistic read from EMAC\n");
1349
1350 /* PFC received frames */
1351 val_xoff = REG_RD(bp, emac_base +
1352 EMAC_REG_RX_PFC_STATS_XOFF_RCVD);
1353 val_xoff &= EMAC_REG_RX_PFC_STATS_XOFF_RCVD_COUNT;
1354 val_xon = REG_RD(bp, emac_base + EMAC_REG_RX_PFC_STATS_XON_RCVD);
1355 val_xon &= EMAC_REG_RX_PFC_STATS_XON_RCVD_COUNT;
1356
1357 pfc_frames_received[0] = val_xon + val_xoff;
1358
1359 /* PFC received sent */
1360 val_xoff = REG_RD(bp, emac_base +
1361 EMAC_REG_RX_PFC_STATS_XOFF_SENT);
1362 val_xoff &= EMAC_REG_RX_PFC_STATS_XOFF_SENT_COUNT;
1363 val_xon = REG_RD(bp, emac_base + EMAC_REG_RX_PFC_STATS_XON_SENT);
1364 val_xon &= EMAC_REG_RX_PFC_STATS_XON_SENT_COUNT;
1365
1366 pfc_frames_sent[0] = val_xon + val_xoff;
1367}
1368
1369void bnx2x_pfc_statistic(struct link_params *params, struct link_vars *vars,
1370 u32 pfc_frames_sent[2],
1371 u32 pfc_frames_received[2])
1372{
1373 /* Read pfc statistic */
1374 struct bnx2x *bp = params->bp;
1375 u32 val = 0;
1376 DP(NETIF_MSG_LINK, "pfc statistic\n");
1377
1378 if (!vars->link_up)
1379 return;
1380
1381 val = REG_RD(bp, MISC_REG_RESET_REG_2);
1382 if ((val & (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << params->port))
1383 == 0) {
1384 DP(NETIF_MSG_LINK, "About to read stats from EMAC\n");
1385 bnx2x_emac_get_pfc_stat(params, pfc_frames_sent,
1386 pfc_frames_received);
1387 } else {
1388 DP(NETIF_MSG_LINK, "About to read stats from BMAC\n");
1389 bnx2x_bmac2_get_pfc_stat(params, pfc_frames_sent,
1390 pfc_frames_received);
1391 }
1392}
1393/******************************************************************/
1394/* MAC/PBF section */
1395/******************************************************************/
Yaniv Rosnera198c142011-05-31 21:29:42 +00001396static void bnx2x_set_mdio_clk(struct bnx2x *bp, u32 chip_id, u8 port)
1397{
1398 u32 mode, emac_base;
1399 /**
1400 * Set clause 45 mode, slow down the MDIO clock to 2.5MHz
1401 * (a value of 49==0x31) and make sure that the AUTO poll is off
1402 */
1403
1404 if (CHIP_IS_E2(bp))
1405 emac_base = GRCBASE_EMAC0;
1406 else
1407 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
1408 mode = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
1409 mode &= ~(EMAC_MDIO_MODE_AUTO_POLL |
1410 EMAC_MDIO_MODE_CLOCK_CNT);
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00001411 if (USES_WARPCORE(bp))
1412 mode |= (74L << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT);
1413 else
1414 mode |= (49L << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT);
Yaniv Rosnera198c142011-05-31 21:29:42 +00001415
1416 mode |= (EMAC_MDIO_MODE_CLAUSE_45);
1417 REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE, mode);
1418
1419 udelay(40);
1420}
1421
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001422static void bnx2x_emac_init(struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001423 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001424{
1425 /* reset and unreset the emac core */
1426 struct bnx2x *bp = params->bp;
1427 u8 port = params->port;
1428 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
1429 u32 val;
1430 u16 timeout;
1431
1432 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001433 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001434 udelay(5);
1435 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001436 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001437
1438 /* init emac - use read-modify-write */
1439 /* self clear reset */
1440 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
Eilon Greenstein3196a882008-08-13 15:58:49 -07001441 EMAC_WR(bp, EMAC_REG_EMAC_MODE, (val | EMAC_MODE_RESET));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001442
1443 timeout = 200;
Eilon Greenstein3196a882008-08-13 15:58:49 -07001444 do {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001445 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
1446 DP(NETIF_MSG_LINK, "EMAC reset reg is %u\n", val);
1447 if (!timeout) {
1448 DP(NETIF_MSG_LINK, "EMAC timeout!\n");
1449 return;
1450 }
1451 timeout--;
Eilon Greenstein3196a882008-08-13 15:58:49 -07001452 } while (val & EMAC_MODE_RESET);
Yaniv Rosnera198c142011-05-31 21:29:42 +00001453 bnx2x_set_mdio_clk(bp, params->chip_id, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001454 /* Set mac address */
1455 val = ((params->mac_addr[0] << 8) |
1456 params->mac_addr[1]);
Eilon Greenstein3196a882008-08-13 15:58:49 -07001457 EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001458
1459 val = ((params->mac_addr[2] << 24) |
1460 (params->mac_addr[3] << 16) |
1461 (params->mac_addr[4] << 8) |
1462 params->mac_addr[5]);
Eilon Greenstein3196a882008-08-13 15:58:49 -07001463 EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH + 4, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001464}
1465
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001466static void bnx2x_set_xumac_nig(struct link_params *params,
1467 u16 tx_pause_en,
1468 u8 enable)
1469{
1470 struct bnx2x *bp = params->bp;
1471
1472 REG_WR(bp, params->port ? NIG_REG_P1_MAC_IN_EN : NIG_REG_P0_MAC_IN_EN,
1473 enable);
1474 REG_WR(bp, params->port ? NIG_REG_P1_MAC_OUT_EN : NIG_REG_P0_MAC_OUT_EN,
1475 enable);
1476 REG_WR(bp, params->port ? NIG_REG_P1_MAC_PAUSE_OUT_EN :
1477 NIG_REG_P0_MAC_PAUSE_OUT_EN, tx_pause_en);
1478}
1479
1480static void bnx2x_umac_enable(struct link_params *params,
1481 struct link_vars *vars, u8 lb)
1482{
1483 u32 val;
1484 u32 umac_base = params->port ? GRCBASE_UMAC1 : GRCBASE_UMAC0;
1485 struct bnx2x *bp = params->bp;
1486 /* Reset UMAC */
1487 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
1488 (MISC_REGISTERS_RESET_REG_2_UMAC0 << params->port));
1489 usleep_range(1000, 1000);
1490
1491 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
1492 (MISC_REGISTERS_RESET_REG_2_UMAC0 << params->port));
1493
1494 DP(NETIF_MSG_LINK, "enabling UMAC\n");
1495
1496 /**
1497 * This register determines on which events the MAC will assert
1498 * error on the i/f to the NIG along w/ EOP.
1499 */
1500
1501 /**
1502 * BD REG_WR(bp, NIG_REG_P0_MAC_RSV_ERR_MASK +
1503 * params->port*0x14, 0xfffff.
1504 */
1505 /* This register opens the gate for the UMAC despite its name */
1506 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + params->port*4, 1);
1507
1508 val = UMAC_COMMAND_CONFIG_REG_PROMIS_EN |
1509 UMAC_COMMAND_CONFIG_REG_PAD_EN |
1510 UMAC_COMMAND_CONFIG_REG_SW_RESET |
1511 UMAC_COMMAND_CONFIG_REG_NO_LGTH_CHECK;
1512 switch (vars->line_speed) {
1513 case SPEED_10:
1514 val |= (0<<2);
1515 break;
1516 case SPEED_100:
1517 val |= (1<<2);
1518 break;
1519 case SPEED_1000:
1520 val |= (2<<2);
1521 break;
1522 case SPEED_2500:
1523 val |= (3<<2);
1524 break;
1525 default:
1526 DP(NETIF_MSG_LINK, "Invalid speed for UMAC %d\n",
1527 vars->line_speed);
1528 break;
1529 }
1530 REG_WR(bp, umac_base + UMAC_REG_COMMAND_CONFIG, val);
1531 udelay(50);
1532
1533 /* Enable RX and TX */
1534 val &= ~UMAC_COMMAND_CONFIG_REG_PAD_EN;
1535 val |= UMAC_COMMAND_CONFIG_REG_TX_ENA |
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00001536 UMAC_COMMAND_CONFIG_REG_RX_ENA;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001537 REG_WR(bp, umac_base + UMAC_REG_COMMAND_CONFIG, val);
1538 udelay(50);
1539
1540 /* Remove SW Reset */
1541 val &= ~UMAC_COMMAND_CONFIG_REG_SW_RESET;
1542
1543 /* Check loopback mode */
1544 if (lb)
1545 val |= UMAC_COMMAND_CONFIG_REG_LOOP_ENA;
1546 REG_WR(bp, umac_base + UMAC_REG_COMMAND_CONFIG, val);
1547
1548 /*
1549 * Maximum Frame Length (RW). Defines a 14-Bit maximum frame
1550 * length used by the MAC receive logic to check frames.
1551 */
1552 REG_WR(bp, umac_base + UMAC_REG_MAXFR, 0x2710);
1553 bnx2x_set_xumac_nig(params,
1554 ((vars->flow_ctrl & BNX2X_FLOW_CTRL_TX) != 0), 1);
1555 vars->mac_type = MAC_TYPE_UMAC;
1556
1557}
1558
1559static u8 bnx2x_is_4_port_mode(struct bnx2x *bp)
1560{
1561 u32 port4mode_ovwr_val;
1562 /* Check 4-port override enabled */
1563 port4mode_ovwr_val = REG_RD(bp, MISC_REG_PORT4MODE_EN_OVWR);
1564 if (port4mode_ovwr_val & (1<<0)) {
1565 /* Return 4-port mode override value */
1566 return ((port4mode_ovwr_val & (1<<1)) == (1<<1));
1567 }
1568 /* Return 4-port mode from input pin */
1569 return (u8)REG_RD(bp, MISC_REG_PORT4MODE_EN);
1570}
1571
1572/* Define the XMAC mode */
1573static void bnx2x_xmac_init(struct bnx2x *bp, u32 max_speed)
1574{
1575 u32 is_port4mode = bnx2x_is_4_port_mode(bp);
1576
1577 /**
1578 * In 4-port mode, need to set the mode only once, so if XMAC is
1579 * already out of reset, it means the mode has already been set,
1580 * and it must not* reset the XMAC again, since it controls both
1581 * ports of the path
1582 **/
1583
1584 if (is_port4mode && (REG_RD(bp, MISC_REG_RESET_REG_2) &
1585 MISC_REGISTERS_RESET_REG_2_XMAC)) {
1586 DP(NETIF_MSG_LINK, "XMAC already out of reset"
1587 " in 4-port mode\n");
1588 return;
1589 }
1590
1591 /* Hard reset */
1592 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
1593 MISC_REGISTERS_RESET_REG_2_XMAC);
1594 usleep_range(1000, 1000);
1595
1596 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
1597 MISC_REGISTERS_RESET_REG_2_XMAC);
1598 if (is_port4mode) {
1599 DP(NETIF_MSG_LINK, "Init XMAC to 2 ports x 10G per path\n");
1600
1601 /* Set the number of ports on the system side to up to 2 */
1602 REG_WR(bp, MISC_REG_XMAC_CORE_PORT_MODE, 1);
1603
1604 /* Set the number of ports on the Warp Core to 10G */
1605 REG_WR(bp, MISC_REG_XMAC_PHY_PORT_MODE, 3);
1606 } else {
1607 /* Set the number of ports on the system side to 1 */
1608 REG_WR(bp, MISC_REG_XMAC_CORE_PORT_MODE, 0);
1609 if (max_speed == SPEED_10000) {
1610 DP(NETIF_MSG_LINK, "Init XMAC to 10G x 1"
1611 " port per path\n");
1612 /* Set the number of ports on the Warp Core to 10G */
1613 REG_WR(bp, MISC_REG_XMAC_PHY_PORT_MODE, 3);
1614 } else {
1615 DP(NETIF_MSG_LINK, "Init XMAC to 20G x 2 ports"
1616 " per path\n");
1617 /* Set the number of ports on the Warp Core to 20G */
1618 REG_WR(bp, MISC_REG_XMAC_PHY_PORT_MODE, 1);
1619 }
1620 }
1621 /* Soft reset */
1622 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
1623 MISC_REGISTERS_RESET_REG_2_XMAC_SOFT);
1624 usleep_range(1000, 1000);
1625
1626 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
1627 MISC_REGISTERS_RESET_REG_2_XMAC_SOFT);
1628
1629}
1630
1631static void bnx2x_xmac_disable(struct link_params *params)
1632{
1633 u8 port = params->port;
1634 struct bnx2x *bp = params->bp;
1635 u32 xmac_base = (port) ? GRCBASE_XMAC1 : GRCBASE_XMAC0;
1636
1637 if (REG_RD(bp, MISC_REG_RESET_REG_2) &
1638 MISC_REGISTERS_RESET_REG_2_XMAC) {
1639 DP(NETIF_MSG_LINK, "Disable XMAC on port %x\n", port);
1640 REG_WR(bp, xmac_base + XMAC_REG_CTRL, 0);
1641 usleep_range(1000, 1000);
1642 bnx2x_set_xumac_nig(params, 0, 0);
1643 REG_WR(bp, xmac_base + XMAC_REG_CTRL,
1644 XMAC_CTRL_REG_SOFT_RESET);
1645 }
1646}
1647
1648static int bnx2x_xmac_enable(struct link_params *params,
1649 struct link_vars *vars, u8 lb)
1650{
1651 u32 val, xmac_base;
1652 struct bnx2x *bp = params->bp;
1653 DP(NETIF_MSG_LINK, "enabling XMAC\n");
1654
1655 xmac_base = (params->port) ? GRCBASE_XMAC1 : GRCBASE_XMAC0;
1656
1657 bnx2x_xmac_init(bp, vars->line_speed);
1658
1659 /*
1660 * This register determines on which events the MAC will assert
1661 * error on the i/f to the NIG along w/ EOP.
1662 */
1663
1664 /*
1665 * This register tells the NIG whether to send traffic to UMAC
1666 * or XMAC
1667 */
1668 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + params->port*4, 0);
1669
1670 /* Set Max packet size */
1671 REG_WR(bp, xmac_base + XMAC_REG_RX_MAX_SIZE, 0x2710);
1672
1673 /* CRC append for Tx packets */
1674 REG_WR(bp, xmac_base + XMAC_REG_TX_CTRL, 0xC800);
1675
1676 /* update PFC */
1677 bnx2x_update_pfc_xmac(params, vars, 0);
1678
1679 /* Enable TX and RX */
1680 val = XMAC_CTRL_REG_TX_EN | XMAC_CTRL_REG_RX_EN;
1681
1682 /* Check loopback mode */
1683 if (lb)
1684 val |= XMAC_CTRL_REG_CORE_LOCAL_LPBK;
1685 REG_WR(bp, xmac_base + XMAC_REG_CTRL, val);
1686 bnx2x_set_xumac_nig(params,
1687 ((vars->flow_ctrl & BNX2X_FLOW_CTRL_TX) != 0), 1);
1688
1689 vars->mac_type = MAC_TYPE_XMAC;
1690
1691 return 0;
1692}
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00001693static int bnx2x_emac_enable(struct link_params *params,
Yaniv Rosner9045f6b2011-05-31 21:28:27 +00001694 struct link_vars *vars, u8 lb)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001695{
1696 struct bnx2x *bp = params->bp;
1697 u8 port = params->port;
1698 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
1699 u32 val;
1700
1701 DP(NETIF_MSG_LINK, "enabling EMAC\n");
1702
1703 /* enable emac and not bmac */
1704 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 1);
1705
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001706 /* ASIC */
1707 if (vars->phy_flags & PHY_XGXS_FLAG) {
1708 u32 ser_lane = ((params->lane_config &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001709 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
1710 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001711
1712 DP(NETIF_MSG_LINK, "XGXS\n");
1713 /* select the master lanes (out of 0-3) */
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001714 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, ser_lane);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001715 /* select XGXS */
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001716 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001717
1718 } else { /* SerDes */
1719 DP(NETIF_MSG_LINK, "SerDes\n");
1720 /* select SerDes */
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001721 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001722 }
1723
Eilon Greenstein811a2f22009-02-12 08:37:04 +00001724 bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001725 EMAC_RX_MODE_RESET);
Eilon Greenstein811a2f22009-02-12 08:37:04 +00001726 bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001727 EMAC_TX_MODE_RESET);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001728
1729 if (CHIP_REV_IS_SLOW(bp)) {
1730 /* config GMII mode */
1731 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001732 EMAC_WR(bp, EMAC_REG_EMAC_MODE, (val | EMAC_MODE_PORT_GMII));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001733 } else { /* ASIC */
1734 /* pause enable/disable */
1735 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
1736 EMAC_RX_MODE_FLOW_EN);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001737
1738 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001739 (EMAC_TX_MODE_EXT_PAUSE_EN |
1740 EMAC_TX_MODE_FLOW_EN));
1741 if (!(params->feature_config_flags &
1742 FEATURE_CONFIG_PFC_ENABLED)) {
1743 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
1744 bnx2x_bits_en(bp, emac_base +
1745 EMAC_REG_EMAC_RX_MODE,
1746 EMAC_RX_MODE_FLOW_EN);
1747
1748 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
1749 bnx2x_bits_en(bp, emac_base +
1750 EMAC_REG_EMAC_TX_MODE,
1751 (EMAC_TX_MODE_EXT_PAUSE_EN |
1752 EMAC_TX_MODE_FLOW_EN));
1753 } else
1754 bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
1755 EMAC_TX_MODE_FLOW_EN);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001756 }
1757
1758 /* KEEP_VLAN_TAG, promiscuous */
1759 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_RX_MODE);
1760 val |= EMAC_RX_MODE_KEEP_VLAN_TAG | EMAC_RX_MODE_PROMISCUOUS;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001761
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001762 /*
1763 * Setting this bit causes MAC control frames (except for pause
1764 * frames) to be passed on for processing. This setting has no
1765 * affect on the operation of the pause frames. This bit effects
1766 * all packets regardless of RX Parser packet sorting logic.
1767 * Turn the PFC off to make sure we are in Xon state before
1768 * enabling it.
1769 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001770 EMAC_WR(bp, EMAC_REG_RX_PFC_MODE, 0);
1771 if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED) {
1772 DP(NETIF_MSG_LINK, "PFC is enabled\n");
1773 /* Enable PFC again */
1774 EMAC_WR(bp, EMAC_REG_RX_PFC_MODE,
1775 EMAC_REG_RX_PFC_MODE_RX_EN |
1776 EMAC_REG_RX_PFC_MODE_TX_EN |
1777 EMAC_REG_RX_PFC_MODE_PRIORITIES);
1778
1779 EMAC_WR(bp, EMAC_REG_RX_PFC_PARAM,
1780 ((0x0101 <<
1781 EMAC_REG_RX_PFC_PARAM_OPCODE_BITSHIFT) |
1782 (0x00ff <<
1783 EMAC_REG_RX_PFC_PARAM_PRIORITY_EN_BITSHIFT)));
1784 val |= EMAC_RX_MODE_KEEP_MAC_CONTROL;
1785 }
Eilon Greenstein3196a882008-08-13 15:58:49 -07001786 EMAC_WR(bp, EMAC_REG_EMAC_RX_MODE, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001787
1788 /* Set Loopback */
1789 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
1790 if (lb)
1791 val |= 0x810;
1792 else
1793 val &= ~0x810;
Eilon Greenstein3196a882008-08-13 15:58:49 -07001794 EMAC_WR(bp, EMAC_REG_EMAC_MODE, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001795
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001796 /* enable emac */
1797 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 1);
1798
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001799 /* enable emac for jumbo packets */
Eilon Greenstein3196a882008-08-13 15:58:49 -07001800 EMAC_WR(bp, EMAC_REG_EMAC_RX_MTU_SIZE,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001801 (EMAC_RX_MTU_SIZE_JUMBO_ENA |
1802 (ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD)));
1803
1804 /* strip CRC */
1805 REG_WR(bp, NIG_REG_NIG_INGRESS_EMAC0_NO_CRC + port*4, 0x1);
1806
1807 /* disable the NIG in/out to the bmac */
1808 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x0);
1809 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, 0x0);
1810 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x0);
1811
1812 /* enable the NIG in/out to the emac */
1813 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x1);
1814 val = 0;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001815 if ((params->feature_config_flags &
1816 FEATURE_CONFIG_PFC_ENABLED) ||
1817 (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001818 val = 1;
1819
1820 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, val);
1821 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x1);
1822
Yaniv Rosner02a23162011-01-31 04:22:53 +00001823 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001824
1825 vars->mac_type = MAC_TYPE_EMAC;
1826 return 0;
1827}
1828
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001829static void bnx2x_update_pfc_bmac1(struct link_params *params,
1830 struct link_vars *vars)
1831{
1832 u32 wb_data[2];
1833 struct bnx2x *bp = params->bp;
1834 u32 bmac_addr = params->port ? NIG_REG_INGRESS_BMAC1_MEM :
1835 NIG_REG_INGRESS_BMAC0_MEM;
1836
1837 u32 val = 0x14;
1838 if ((!(params->feature_config_flags &
1839 FEATURE_CONFIG_PFC_ENABLED)) &&
1840 (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX))
1841 /* Enable BigMAC to react on received Pause packets */
1842 val |= (1<<5);
1843 wb_data[0] = val;
1844 wb_data[1] = 0;
1845 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_CONTROL, wb_data, 2);
1846
1847 /* tx control */
1848 val = 0xc0;
1849 if (!(params->feature_config_flags &
1850 FEATURE_CONFIG_PFC_ENABLED) &&
1851 (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
1852 val |= 0x800000;
1853 wb_data[0] = val;
1854 wb_data[1] = 0;
1855 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_CONTROL, wb_data, 2);
1856}
1857
1858static void bnx2x_update_pfc_bmac2(struct link_params *params,
1859 struct link_vars *vars,
1860 u8 is_lb)
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001861{
1862 /*
1863 * Set rx control: Strip CRC and enable BigMAC to relay
1864 * control packets to the system as well
1865 */
1866 u32 wb_data[2];
1867 struct bnx2x *bp = params->bp;
1868 u32 bmac_addr = params->port ? NIG_REG_INGRESS_BMAC1_MEM :
1869 NIG_REG_INGRESS_BMAC0_MEM;
1870 u32 val = 0x14;
1871
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001872 if ((!(params->feature_config_flags &
1873 FEATURE_CONFIG_PFC_ENABLED)) &&
1874 (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX))
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001875 /* Enable BigMAC to react on received Pause packets */
1876 val |= (1<<5);
1877 wb_data[0] = val;
1878 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001879 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_CONTROL, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001880 udelay(30);
1881
1882 /* Tx control */
1883 val = 0xc0;
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))
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001887 val |= 0x800000;
1888 wb_data[0] = val;
1889 wb_data[1] = 0;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001890 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_CONTROL, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001891
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001892 if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED) {
1893 DP(NETIF_MSG_LINK, "PFC is enabled\n");
1894 /* Enable PFC RX & TX & STATS and set 8 COS */
1895 wb_data[0] = 0x0;
1896 wb_data[0] |= (1<<0); /* RX */
1897 wb_data[0] |= (1<<1); /* TX */
1898 wb_data[0] |= (1<<2); /* Force initial Xon */
1899 wb_data[0] |= (1<<3); /* 8 cos */
1900 wb_data[0] |= (1<<5); /* STATS */
1901 wb_data[1] = 0;
1902 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_PFC_CONTROL,
1903 wb_data, 2);
1904 /* Clear the force Xon */
1905 wb_data[0] &= ~(1<<2);
1906 } else {
1907 DP(NETIF_MSG_LINK, "PFC is disabled\n");
1908 /* disable PFC RX & TX & STATS and set 8 COS */
1909 wb_data[0] = 0x8;
1910 wb_data[1] = 0;
1911 }
1912
1913 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_PFC_CONTROL, wb_data, 2);
1914
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001915 /*
1916 * Set Time (based unit is 512 bit time) between automatic
1917 * re-sending of PP packets amd enable automatic re-send of
1918 * Per-Priroity Packet as long as pp_gen is asserted and
1919 * pp_disable is low.
1920 */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001921 val = 0x8000;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001922 if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED)
1923 val |= (1<<16); /* enable automatic re-send */
1924
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001925 wb_data[0] = val;
1926 wb_data[1] = 0;
1927 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_PAUSE_CONTROL,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001928 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001929
1930 /* mac control */
1931 val = 0x3; /* Enable RX and TX */
1932 if (is_lb) {
1933 val |= 0x4; /* Local loopback */
1934 DP(NETIF_MSG_LINK, "enable bmac loopback\n");
1935 }
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001936 /* When PFC enabled, Pass pause frames towards the NIG. */
1937 if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED)
1938 val |= ((1<<6)|(1<<5));
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001939
1940 wb_data[0] = val;
1941 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001942 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_BMAC_CONTROL, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001943}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001944
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001945
1946/* PFC BRB internal port configuration params */
1947struct bnx2x_pfc_brb_threshold_val {
1948 u32 pause_xoff;
1949 u32 pause_xon;
1950 u32 full_xoff;
1951 u32 full_xon;
1952};
1953
1954struct bnx2x_pfc_brb_e3b0_val {
1955 u32 full_lb_xoff_th;
1956 u32 full_lb_xon_threshold;
1957 u32 lb_guarantied;
1958 u32 mac_0_class_t_guarantied;
1959 u32 mac_0_class_t_guarantied_hyst;
1960 u32 mac_1_class_t_guarantied;
1961 u32 mac_1_class_t_guarantied_hyst;
1962};
1963
1964struct bnx2x_pfc_brb_th_val {
1965 struct bnx2x_pfc_brb_threshold_val pauseable_th;
1966 struct bnx2x_pfc_brb_threshold_val non_pauseable_th;
1967};
1968static int bnx2x_pfc_brb_get_config_params(
1969 struct link_params *params,
1970 struct bnx2x_pfc_brb_th_val *config_val)
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001971{
1972 struct bnx2x *bp = params->bp;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001973 DP(NETIF_MSG_LINK, "Setting PFC BRB configuration\n");
1974 if (CHIP_IS_E2(bp)) {
1975 config_val->pauseable_th.pause_xoff =
1976 PFC_E2_BRB_MAC_PAUSE_XOFF_THR_PAUSE;
1977 config_val->pauseable_th.pause_xon =
1978 PFC_E2_BRB_MAC_PAUSE_XON_THR_PAUSE;
1979 config_val->pauseable_th.full_xoff =
1980 PFC_E2_BRB_MAC_FULL_XOFF_THR_PAUSE;
1981 config_val->pauseable_th.full_xon =
1982 PFC_E2_BRB_MAC_FULL_XON_THR_PAUSE;
1983 /* non pause able*/
1984 config_val->non_pauseable_th.pause_xoff =
1985 PFC_E2_BRB_MAC_PAUSE_XOFF_THR_NON_PAUSE;
1986 config_val->non_pauseable_th.pause_xon =
1987 PFC_E2_BRB_MAC_PAUSE_XON_THR_NON_PAUSE;
1988 config_val->non_pauseable_th.full_xoff =
1989 PFC_E2_BRB_MAC_FULL_XOFF_THR_NON_PAUSE;
1990 config_val->non_pauseable_th.full_xon =
1991 PFC_E2_BRB_MAC_FULL_XON_THR_NON_PAUSE;
1992 } else if (CHIP_IS_E3A0(bp)) {
1993 config_val->pauseable_th.pause_xoff =
1994 PFC_E3A0_BRB_MAC_PAUSE_XOFF_THR_PAUSE;
1995 config_val->pauseable_th.pause_xon =
1996 PFC_E3A0_BRB_MAC_PAUSE_XON_THR_PAUSE;
1997 config_val->pauseable_th.full_xoff =
1998 PFC_E3A0_BRB_MAC_FULL_XOFF_THR_PAUSE;
1999 config_val->pauseable_th.full_xon =
2000 PFC_E3A0_BRB_MAC_FULL_XON_THR_PAUSE;
2001 /* non pause able*/
2002 config_val->non_pauseable_th.pause_xoff =
2003 PFC_E3A0_BRB_MAC_PAUSE_XOFF_THR_NON_PAUSE;
2004 config_val->non_pauseable_th.pause_xon =
2005 PFC_E3A0_BRB_MAC_PAUSE_XON_THR_NON_PAUSE;
2006 config_val->non_pauseable_th.full_xoff =
2007 PFC_E3A0_BRB_MAC_FULL_XOFF_THR_NON_PAUSE;
2008 config_val->non_pauseable_th.full_xon =
2009 PFC_E3A0_BRB_MAC_FULL_XON_THR_NON_PAUSE;
2010 } else if (CHIP_IS_E3B0(bp)) {
2011 if (params->phy[INT_PHY].flags &
2012 FLAGS_4_PORT_MODE) {
2013 config_val->pauseable_th.pause_xoff =
2014 PFC_E3B0_4P_BRB_MAC_PAUSE_XOFF_THR_PAUSE;
2015 config_val->pauseable_th.pause_xon =
2016 PFC_E3B0_4P_BRB_MAC_PAUSE_XON_THR_PAUSE;
2017 config_val->pauseable_th.full_xoff =
2018 PFC_E3B0_4P_BRB_MAC_FULL_XOFF_THR_PAUSE;
2019 config_val->pauseable_th.full_xon =
2020 PFC_E3B0_4P_BRB_MAC_FULL_XON_THR_PAUSE;
2021 /* non pause able*/
2022 config_val->non_pauseable_th.pause_xoff =
2023 PFC_E3B0_4P_BRB_MAC_PAUSE_XOFF_THR_NON_PAUSE;
2024 config_val->non_pauseable_th.pause_xon =
2025 PFC_E3B0_4P_BRB_MAC_PAUSE_XON_THR_NON_PAUSE;
2026 config_val->non_pauseable_th.full_xoff =
2027 PFC_E3B0_4P_BRB_MAC_FULL_XOFF_THR_NON_PAUSE;
2028 config_val->non_pauseable_th.full_xon =
2029 PFC_E3B0_4P_BRB_MAC_FULL_XON_THR_NON_PAUSE;
2030 } else {
2031 config_val->pauseable_th.pause_xoff =
2032 PFC_E3B0_2P_BRB_MAC_PAUSE_XOFF_THR_PAUSE;
2033 config_val->pauseable_th.pause_xon =
2034 PFC_E3B0_2P_BRB_MAC_PAUSE_XON_THR_PAUSE;
2035 config_val->pauseable_th.full_xoff =
2036 PFC_E3B0_2P_BRB_MAC_FULL_XOFF_THR_PAUSE;
2037 config_val->pauseable_th.full_xon =
2038 PFC_E3B0_2P_BRB_MAC_FULL_XON_THR_PAUSE;
2039 /* non pause able*/
2040 config_val->non_pauseable_th.pause_xoff =
2041 PFC_E3B0_2P_BRB_MAC_PAUSE_XOFF_THR_NON_PAUSE;
2042 config_val->non_pauseable_th.pause_xon =
2043 PFC_E3B0_2P_BRB_MAC_PAUSE_XON_THR_NON_PAUSE;
2044 config_val->non_pauseable_th.full_xoff =
2045 PFC_E3B0_2P_BRB_MAC_FULL_XOFF_THR_NON_PAUSE;
2046 config_val->non_pauseable_th.full_xon =
2047 PFC_E3B0_2P_BRB_MAC_FULL_XON_THR_NON_PAUSE;
2048 }
2049 } else
2050 return -EINVAL;
2051
2052 return 0;
2053}
2054
2055
2056static void bnx2x_pfc_brb_get_e3b0_config_params(struct link_params *params,
2057 struct bnx2x_pfc_brb_e3b0_val
2058 *e3b0_val,
2059 u32 cos0_pauseable,
2060 u32 cos1_pauseable)
2061{
2062 if (params->phy[INT_PHY].flags & FLAGS_4_PORT_MODE) {
2063 e3b0_val->full_lb_xoff_th =
2064 PFC_E3B0_4P_BRB_FULL_LB_XOFF_THR;
2065 e3b0_val->full_lb_xon_threshold =
2066 PFC_E3B0_4P_BRB_FULL_LB_XON_THR;
2067 e3b0_val->lb_guarantied =
2068 PFC_E3B0_4P_LB_GUART;
2069 e3b0_val->mac_0_class_t_guarantied =
2070 PFC_E3B0_4P_BRB_MAC_0_CLASS_T_GUART;
2071 e3b0_val->mac_0_class_t_guarantied_hyst =
2072 PFC_E3B0_4P_BRB_MAC_0_CLASS_T_GUART_HYST;
2073 e3b0_val->mac_1_class_t_guarantied =
2074 PFC_E3B0_4P_BRB_MAC_1_CLASS_T_GUART;
2075 e3b0_val->mac_1_class_t_guarantied_hyst =
2076 PFC_E3B0_4P_BRB_MAC_1_CLASS_T_GUART_HYST;
2077 } else {
2078 e3b0_val->full_lb_xoff_th =
2079 PFC_E3B0_2P_BRB_FULL_LB_XOFF_THR;
2080 e3b0_val->full_lb_xon_threshold =
2081 PFC_E3B0_2P_BRB_FULL_LB_XON_THR;
2082 e3b0_val->mac_0_class_t_guarantied_hyst =
2083 PFC_E3B0_2P_BRB_MAC_0_CLASS_T_GUART_HYST;
2084 e3b0_val->mac_1_class_t_guarantied =
2085 PFC_E3B0_2P_BRB_MAC_1_CLASS_T_GUART;
2086 e3b0_val->mac_1_class_t_guarantied_hyst =
2087 PFC_E3B0_2P_BRB_MAC_1_CLASS_T_GUART_HYST;
2088
2089 if (cos0_pauseable != cos1_pauseable) {
2090 /* nonpauseable= Lossy + pauseable = Lossless*/
2091 e3b0_val->lb_guarantied =
2092 PFC_E3B0_2P_MIX_PAUSE_LB_GUART;
2093 e3b0_val->mac_0_class_t_guarantied =
2094 PFC_E3B0_2P_MIX_PAUSE_MAC_0_CLASS_T_GUART;
2095 } else if (cos0_pauseable) {
2096 /* Lossless +Lossless*/
2097 e3b0_val->lb_guarantied =
2098 PFC_E3B0_2P_PAUSE_LB_GUART;
2099 e3b0_val->mac_0_class_t_guarantied =
2100 PFC_E3B0_2P_PAUSE_MAC_0_CLASS_T_GUART;
2101 } else {
2102 /* Lossy +Lossy*/
2103 e3b0_val->lb_guarantied =
2104 PFC_E3B0_2P_NON_PAUSE_LB_GUART;
2105 e3b0_val->mac_0_class_t_guarantied =
2106 PFC_E3B0_2P_NON_PAUSE_MAC_0_CLASS_T_GUART;
2107 }
2108 }
2109}
2110static int bnx2x_update_pfc_brb(struct link_params *params,
2111 struct link_vars *vars,
2112 struct bnx2x_nig_brb_pfc_port_params
2113 *pfc_params)
2114{
2115 struct bnx2x *bp = params->bp;
2116 struct bnx2x_pfc_brb_th_val config_val = { {0} };
2117 struct bnx2x_pfc_brb_threshold_val *reg_th_config =
2118 &config_val.pauseable_th;
2119 struct bnx2x_pfc_brb_e3b0_val e3b0_val = {0};
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002120 int set_pfc = params->feature_config_flags &
2121 FEATURE_CONFIG_PFC_ENABLED;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002122 int bnx2x_status = 0;
2123 u8 port = params->port;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002124
2125 /* default - pause configuration */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002126 reg_th_config = &config_val.pauseable_th;
2127 bnx2x_status = bnx2x_pfc_brb_get_config_params(params, &config_val);
2128 if (0 != bnx2x_status)
2129 return bnx2x_status;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002130
2131 if (set_pfc && pfc_params)
2132 /* First COS */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002133 if (!pfc_params->cos0_pauseable)
2134 reg_th_config = &config_val.non_pauseable_th;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002135 /*
2136 * The number of free blocks below which the pause signal to class 0
2137 * of MAC #n is asserted. n=0,1
2138 */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002139 REG_WR(bp, (port) ? BRB1_REG_PAUSE_0_XOFF_THRESHOLD_1 :
2140 BRB1_REG_PAUSE_0_XOFF_THRESHOLD_0 ,
2141 reg_th_config->pause_xoff);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002142 /*
2143 * The number of free blocks above which the pause signal to class 0
2144 * of MAC #n is de-asserted. n=0,1
2145 */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002146 REG_WR(bp, (port) ? BRB1_REG_PAUSE_0_XON_THRESHOLD_1 :
2147 BRB1_REG_PAUSE_0_XON_THRESHOLD_0 , reg_th_config->pause_xon);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002148 /*
2149 * The number of free blocks below which the full signal to class 0
2150 * of MAC #n is asserted. n=0,1
2151 */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002152 REG_WR(bp, (port) ? BRB1_REG_FULL_0_XOFF_THRESHOLD_1 :
2153 BRB1_REG_FULL_0_XOFF_THRESHOLD_0 , reg_th_config->full_xoff);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002154 /*
2155 * The number of free blocks above which the full signal to class 0
2156 * of MAC #n is de-asserted. n=0,1
2157 */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002158 REG_WR(bp, (port) ? BRB1_REG_FULL_0_XON_THRESHOLD_1 :
2159 BRB1_REG_FULL_0_XON_THRESHOLD_0 , reg_th_config->full_xon);
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002160
2161 if (set_pfc && pfc_params) {
2162 /* Second COS */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002163 if (pfc_params->cos1_pauseable)
2164 reg_th_config = &config_val.pauseable_th;
2165 else
2166 reg_th_config = &config_val.non_pauseable_th;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002167 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002168 * The number of free blocks below which the pause signal to
2169 * class 1 of MAC #n is asserted. n=0,1
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002170 **/
2171 REG_WR(bp, (port) ? BRB1_REG_PAUSE_1_XOFF_THRESHOLD_1 :
2172 BRB1_REG_PAUSE_1_XOFF_THRESHOLD_0,
2173 reg_th_config->pause_xoff);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002174 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002175 * The number of free blocks above which the pause signal to
2176 * class 1 of MAC #n is de-asserted. n=0,1
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002177 */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002178 REG_WR(bp, (port) ? BRB1_REG_PAUSE_1_XON_THRESHOLD_1 :
2179 BRB1_REG_PAUSE_1_XON_THRESHOLD_0,
2180 reg_th_config->pause_xon);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002181 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002182 * The number of free blocks below which the full signal to
2183 * class 1 of MAC #n is asserted. n=0,1
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002184 */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002185 REG_WR(bp, (port) ? BRB1_REG_FULL_1_XOFF_THRESHOLD_1 :
2186 BRB1_REG_FULL_1_XOFF_THRESHOLD_0,
2187 reg_th_config->full_xoff);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002188 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002189 * The number of free blocks above which the full signal to
2190 * class 1 of MAC #n is de-asserted. n=0,1
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002191 */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002192 REG_WR(bp, (port) ? BRB1_REG_FULL_1_XON_THRESHOLD_1 :
2193 BRB1_REG_FULL_1_XON_THRESHOLD_0,
2194 reg_th_config->full_xon);
2195
2196
2197 if (CHIP_IS_E3B0(bp)) {
2198 /*Should be done by init tool */
2199 /*
2200 * BRB_empty_for_dup = BRB1_REG_BRB_EMPTY_THRESHOLD
2201 * reset value
2202 * 944
2203 */
2204
2205 /**
2206 * The hysteresis on the guarantied buffer space for the Lb port
2207 * before signaling XON.
2208 **/
2209 REG_WR(bp, BRB1_REG_LB_GUARANTIED_HYST, 80);
2210
2211 bnx2x_pfc_brb_get_e3b0_config_params(
2212 params,
2213 &e3b0_val,
2214 pfc_params->cos0_pauseable,
2215 pfc_params->cos1_pauseable);
2216 /**
2217 * The number of free blocks below which the full signal to the
2218 * LB port is asserted.
2219 */
2220 REG_WR(bp, BRB1_REG_FULL_LB_XOFF_THRESHOLD,
2221 e3b0_val.full_lb_xoff_th);
2222 /**
2223 * The number of free blocks above which the full signal to the
2224 * LB port is de-asserted.
2225 */
2226 REG_WR(bp, BRB1_REG_FULL_LB_XON_THRESHOLD,
2227 e3b0_val.full_lb_xon_threshold);
2228 /**
2229 * The number of blocks guarantied for the MAC #n port. n=0,1
2230 */
2231
2232 /*The number of blocks guarantied for the LB port.*/
2233 REG_WR(bp, BRB1_REG_LB_GUARANTIED,
2234 e3b0_val.lb_guarantied);
2235
2236 /**
2237 * The number of blocks guarantied for the MAC #n port.
2238 */
2239 REG_WR(bp, BRB1_REG_MAC_GUARANTIED_0,
2240 2 * e3b0_val.mac_0_class_t_guarantied);
2241 REG_WR(bp, BRB1_REG_MAC_GUARANTIED_1,
2242 2 * e3b0_val.mac_1_class_t_guarantied);
2243 /**
2244 * The number of blocks guarantied for class #t in MAC0. t=0,1
2245 */
2246 REG_WR(bp, BRB1_REG_MAC_0_CLASS_0_GUARANTIED,
2247 e3b0_val.mac_0_class_t_guarantied);
2248 REG_WR(bp, BRB1_REG_MAC_0_CLASS_1_GUARANTIED,
2249 e3b0_val.mac_0_class_t_guarantied);
2250 /**
2251 * The hysteresis on the guarantied buffer space for class in
2252 * MAC0. t=0,1
2253 */
2254 REG_WR(bp, BRB1_REG_MAC_0_CLASS_0_GUARANTIED_HYST,
2255 e3b0_val.mac_0_class_t_guarantied_hyst);
2256 REG_WR(bp, BRB1_REG_MAC_0_CLASS_1_GUARANTIED_HYST,
2257 e3b0_val.mac_0_class_t_guarantied_hyst);
2258
2259 /**
2260 * The number of blocks guarantied for class #t in MAC1.t=0,1
2261 */
2262 REG_WR(bp, BRB1_REG_MAC_1_CLASS_0_GUARANTIED,
2263 e3b0_val.mac_1_class_t_guarantied);
2264 REG_WR(bp, BRB1_REG_MAC_1_CLASS_1_GUARANTIED,
2265 e3b0_val.mac_1_class_t_guarantied);
2266 /**
2267 * The hysteresis on the guarantied buffer space for class #t
2268 * in MAC1. t=0,1
2269 */
2270 REG_WR(bp, BRB1_REG_MAC_1_CLASS_0_GUARANTIED_HYST,
2271 e3b0_val.mac_1_class_t_guarantied_hyst);
2272 REG_WR(bp, BRB1_REG_MAC_1_CLASS_1_GUARANTIED_HYST,
2273 e3b0_val.mac_1_class_t_guarantied_hyst);
2274
2275 }
2276
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002277 }
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002278
2279 return bnx2x_status;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002280}
2281
Vlad Zolotarov619c5cb2011-06-14 14:33:44 +03002282/******************************************************************************
2283* Description:
2284* This function is needed because NIG ARB_CREDIT_WEIGHT_X are
2285* not continues and ARB_CREDIT_WEIGHT_0 + offset is suitable.
2286******************************************************************************/
2287int bnx2x_pfc_nig_rx_priority_mask(struct bnx2x *bp,
2288 u8 cos_entry,
2289 u32 priority_mask, u8 port)
2290{
2291 u32 nig_reg_rx_priority_mask_add = 0;
2292
2293 switch (cos_entry) {
2294 case 0:
2295 nig_reg_rx_priority_mask_add = (port) ?
2296 NIG_REG_P1_RX_COS0_PRIORITY_MASK :
2297 NIG_REG_P0_RX_COS0_PRIORITY_MASK;
2298 break;
2299 case 1:
2300 nig_reg_rx_priority_mask_add = (port) ?
2301 NIG_REG_P1_RX_COS1_PRIORITY_MASK :
2302 NIG_REG_P0_RX_COS1_PRIORITY_MASK;
2303 break;
2304 case 2:
2305 nig_reg_rx_priority_mask_add = (port) ?
2306 NIG_REG_P1_RX_COS2_PRIORITY_MASK :
2307 NIG_REG_P0_RX_COS2_PRIORITY_MASK;
2308 break;
2309 case 3:
2310 if (port)
2311 return -EINVAL;
2312 nig_reg_rx_priority_mask_add = NIG_REG_P0_RX_COS3_PRIORITY_MASK;
2313 break;
2314 case 4:
2315 if (port)
2316 return -EINVAL;
2317 nig_reg_rx_priority_mask_add = NIG_REG_P0_RX_COS4_PRIORITY_MASK;
2318 break;
2319 case 5:
2320 if (port)
2321 return -EINVAL;
2322 nig_reg_rx_priority_mask_add = NIG_REG_P0_RX_COS5_PRIORITY_MASK;
2323 break;
2324 }
2325
2326 REG_WR(bp, nig_reg_rx_priority_mask_add, priority_mask);
2327
2328 return 0;
2329}
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002330static void bnx2x_update_pfc_nig(struct link_params *params,
2331 struct link_vars *vars,
2332 struct bnx2x_nig_brb_pfc_port_params *nig_params)
2333{
2334 u32 xcm_mask = 0, ppp_enable = 0, pause_enable = 0, llfc_out_en = 0;
2335 u32 llfc_enable = 0, xcm0_out_en = 0, p0_hwpfc_enable = 0;
2336 u32 pkt_priority_to_cos = 0;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002337 struct bnx2x *bp = params->bp;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002338 u8 port = params->port;
2339
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002340 int set_pfc = params->feature_config_flags &
2341 FEATURE_CONFIG_PFC_ENABLED;
2342 DP(NETIF_MSG_LINK, "updating pfc nig parameters\n");
2343
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002344 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002345 * When NIG_LLH0_XCM_MASK_REG_LLHX_XCM_MASK_BCN bit is set
2346 * MAC control frames (that are not pause packets)
2347 * will be forwarded to the XCM.
2348 */
2349 xcm_mask = REG_RD(bp,
2350 port ? NIG_REG_LLH1_XCM_MASK :
2351 NIG_REG_LLH0_XCM_MASK);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002352 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002353 * nig params will override non PFC params, since it's possible to
2354 * do transition from PFC to SAFC
2355 */
2356 if (set_pfc) {
2357 pause_enable = 0;
2358 llfc_out_en = 0;
2359 llfc_enable = 0;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002360 if (CHIP_IS_E3(bp))
2361 ppp_enable = 0;
2362 else
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002363 ppp_enable = 1;
2364 xcm_mask &= ~(port ? NIG_LLH1_XCM_MASK_REG_LLH1_XCM_MASK_BCN :
2365 NIG_LLH0_XCM_MASK_REG_LLH0_XCM_MASK_BCN);
2366 xcm0_out_en = 0;
2367 p0_hwpfc_enable = 1;
2368 } else {
2369 if (nig_params) {
2370 llfc_out_en = nig_params->llfc_out_en;
2371 llfc_enable = nig_params->llfc_enable;
2372 pause_enable = nig_params->pause_enable;
2373 } else /*defaul non PFC mode - PAUSE */
2374 pause_enable = 1;
2375
2376 xcm_mask |= (port ? NIG_LLH1_XCM_MASK_REG_LLH1_XCM_MASK_BCN :
2377 NIG_LLH0_XCM_MASK_REG_LLH0_XCM_MASK_BCN);
2378 xcm0_out_en = 1;
2379 }
2380
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002381 if (CHIP_IS_E3(bp))
2382 REG_WR(bp, port ? NIG_REG_BRB1_PAUSE_IN_EN :
2383 NIG_REG_BRB0_PAUSE_IN_EN, pause_enable);
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002384 REG_WR(bp, port ? NIG_REG_LLFC_OUT_EN_1 :
2385 NIG_REG_LLFC_OUT_EN_0, llfc_out_en);
2386 REG_WR(bp, port ? NIG_REG_LLFC_ENABLE_1 :
2387 NIG_REG_LLFC_ENABLE_0, llfc_enable);
2388 REG_WR(bp, port ? NIG_REG_PAUSE_ENABLE_1 :
2389 NIG_REG_PAUSE_ENABLE_0, pause_enable);
2390
2391 REG_WR(bp, port ? NIG_REG_PPP_ENABLE_1 :
2392 NIG_REG_PPP_ENABLE_0, ppp_enable);
2393
2394 REG_WR(bp, port ? NIG_REG_LLH1_XCM_MASK :
2395 NIG_REG_LLH0_XCM_MASK, xcm_mask);
2396
2397 REG_WR(bp, NIG_REG_LLFC_EGRESS_SRC_ENABLE_0, 0x7);
2398
2399 /* output enable for RX_XCM # IF */
2400 REG_WR(bp, NIG_REG_XCM0_OUT_EN, xcm0_out_en);
2401
2402 /* HW PFC TX enable */
2403 REG_WR(bp, NIG_REG_P0_HWPFC_ENABLE, p0_hwpfc_enable);
2404
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002405 if (nig_params) {
Vlad Zolotarov619c5cb2011-06-14 14:33:44 +03002406 u8 i = 0;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002407 pkt_priority_to_cos = nig_params->pkt_priority_to_cos;
2408
Vlad Zolotarov619c5cb2011-06-14 14:33:44 +03002409 for (i = 0; i < nig_params->num_of_rx_cos_priority_mask; i++)
2410 bnx2x_pfc_nig_rx_priority_mask(bp, i,
2411 nig_params->rx_cos_priority_mask[i], port);
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002412
2413 REG_WR(bp, port ? NIG_REG_LLFC_HIGH_PRIORITY_CLASSES_1 :
2414 NIG_REG_LLFC_HIGH_PRIORITY_CLASSES_0,
2415 nig_params->llfc_high_priority_classes);
2416
2417 REG_WR(bp, port ? NIG_REG_LLFC_LOW_PRIORITY_CLASSES_1 :
2418 NIG_REG_LLFC_LOW_PRIORITY_CLASSES_0,
2419 nig_params->llfc_low_priority_classes);
2420 }
2421 REG_WR(bp, port ? NIG_REG_P1_PKT_PRIORITY_TO_COS :
2422 NIG_REG_P0_PKT_PRIORITY_TO_COS,
2423 pkt_priority_to_cos);
2424}
2425
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002426int bnx2x_update_pfc(struct link_params *params,
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002427 struct link_vars *vars,
2428 struct bnx2x_nig_brb_pfc_port_params *pfc_params)
2429{
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002430 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002431 * The PFC and pause are orthogonal to one another, meaning when
2432 * PFC is enabled, the pause are disabled, and when PFC is
2433 * disabled, pause are set according to the pause result.
2434 */
2435 u32 val;
2436 struct bnx2x *bp = params->bp;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002437 int bnx2x_status = 0;
2438 u8 bmac_loopback = (params->loopback_mode == LOOPBACK_BMAC);
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002439 /* update NIG params */
2440 bnx2x_update_pfc_nig(params, vars, pfc_params);
2441
2442 /* update BRB params */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002443 bnx2x_status = bnx2x_update_pfc_brb(params, vars, pfc_params);
2444 if (0 != bnx2x_status)
2445 return bnx2x_status;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002446
2447 if (!vars->link_up)
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002448 return bnx2x_status;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002449
2450 DP(NETIF_MSG_LINK, "About to update PFC in BMAC\n");
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002451 if (CHIP_IS_E3(bp))
2452 bnx2x_update_pfc_xmac(params, vars, 0);
2453 else {
2454 val = REG_RD(bp, MISC_REG_RESET_REG_2);
2455 if ((val &
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00002456 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << params->port))
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002457 == 0) {
2458 DP(NETIF_MSG_LINK, "About to update PFC in EMAC\n");
2459 bnx2x_emac_enable(params, vars, 0);
2460 return bnx2x_status;
2461 }
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002462
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002463 if (CHIP_IS_E2(bp))
2464 bnx2x_update_pfc_bmac2(params, vars, bmac_loopback);
2465 else
2466 bnx2x_update_pfc_bmac1(params, vars);
2467
2468 val = 0;
2469 if ((params->feature_config_flags &
2470 FEATURE_CONFIG_PFC_ENABLED) ||
2471 (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
2472 val = 1;
2473 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + params->port*4, val);
2474 }
2475 return bnx2x_status;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002476}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002477
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002478
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00002479static int bnx2x_bmac1_enable(struct link_params *params,
2480 struct link_vars *vars,
2481 u8 is_lb)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002482{
2483 struct bnx2x *bp = params->bp;
2484 u8 port = params->port;
2485 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
2486 NIG_REG_INGRESS_BMAC0_MEM;
2487 u32 wb_data[2];
2488 u32 val;
2489
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002490 DP(NETIF_MSG_LINK, "Enabling BigMAC1\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002491
2492 /* XGXS control */
2493 wb_data[0] = 0x3c;
2494 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002495 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_XGXS_CONTROL,
2496 wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002497
2498 /* tx MAC SA */
2499 wb_data[0] = ((params->mac_addr[2] << 24) |
2500 (params->mac_addr[3] << 16) |
2501 (params->mac_addr[4] << 8) |
2502 params->mac_addr[5]);
2503 wb_data[1] = ((params->mac_addr[0] << 8) |
2504 params->mac_addr[1]);
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002505 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_SOURCE_ADDR, wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002506
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002507 /* mac control */
2508 val = 0x3;
2509 if (is_lb) {
2510 val |= 0x4;
2511 DP(NETIF_MSG_LINK, "enable bmac loopback\n");
2512 }
2513 wb_data[0] = val;
2514 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002515 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL, wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002516
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002517 /* set rx mtu */
2518 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
2519 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002520 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_MAX_SIZE, wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002521
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002522 bnx2x_update_pfc_bmac1(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002523
2524 /* set tx mtu */
2525 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
2526 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002527 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_MAX_SIZE, wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002528
2529 /* set cnt max size */
2530 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
2531 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002532 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_CNT_MAX_SIZE, wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002533
2534 /* configure safc */
2535 wb_data[0] = 0x1000200;
2536 wb_data[1] = 0;
2537 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_LLFC_MSG_FLDS,
2538 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002539
2540 return 0;
2541}
2542
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00002543static int bnx2x_bmac2_enable(struct link_params *params,
2544 struct link_vars *vars,
2545 u8 is_lb)
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002546{
2547 struct bnx2x *bp = params->bp;
2548 u8 port = params->port;
2549 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
2550 NIG_REG_INGRESS_BMAC0_MEM;
2551 u32 wb_data[2];
2552
2553 DP(NETIF_MSG_LINK, "Enabling BigMAC2\n");
2554
2555 wb_data[0] = 0;
2556 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002557 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_BMAC_CONTROL, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002558 udelay(30);
2559
2560 /* XGXS control: Reset phy HW, MDIO registers, PHY PLL and BMAC */
2561 wb_data[0] = 0x3c;
2562 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002563 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_BMAC_XGXS_CONTROL,
2564 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002565
2566 udelay(30);
2567
2568 /* tx MAC SA */
2569 wb_data[0] = ((params->mac_addr[2] << 24) |
2570 (params->mac_addr[3] << 16) |
2571 (params->mac_addr[4] << 8) |
2572 params->mac_addr[5]);
2573 wb_data[1] = ((params->mac_addr[0] << 8) |
2574 params->mac_addr[1]);
2575 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_SOURCE_ADDR,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002576 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002577
2578 udelay(30);
2579
2580 /* Configure SAFC */
2581 wb_data[0] = 0x1000200;
2582 wb_data[1] = 0;
2583 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_LLFC_MSG_FLDS,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002584 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002585 udelay(30);
2586
2587 /* set rx mtu */
2588 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
2589 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002590 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_MAX_SIZE, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002591 udelay(30);
2592
2593 /* set tx mtu */
2594 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
2595 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002596 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_MAX_SIZE, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002597 udelay(30);
2598 /* set cnt max size */
2599 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD - 2;
2600 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002601 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_CNT_MAX_SIZE, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002602 udelay(30);
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002603 bnx2x_update_pfc_bmac2(params, vars, is_lb);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002604
2605 return 0;
2606}
2607
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00002608static int bnx2x_bmac_enable(struct link_params *params,
2609 struct link_vars *vars,
2610 u8 is_lb)
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002611{
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00002612 int rc = 0;
2613 u8 port = params->port;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002614 struct bnx2x *bp = params->bp;
2615 u32 val;
2616 /* reset and unreset the BigMac */
2617 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002618 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
Yaniv Rosner1d9c05d2010-11-01 05:32:25 +00002619 msleep(1);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002620
2621 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002622 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002623
2624 /* enable access for bmac registers */
2625 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
2626
2627 /* Enable BMAC according to BMAC type*/
2628 if (CHIP_IS_E2(bp))
2629 rc = bnx2x_bmac2_enable(params, vars, is_lb);
2630 else
2631 rc = bnx2x_bmac1_enable(params, vars, is_lb);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002632 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0x1);
2633 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 0x0);
2634 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 0x0);
2635 val = 0;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002636 if ((params->feature_config_flags &
2637 FEATURE_CONFIG_PFC_ENABLED) ||
2638 (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002639 val = 1;
2640 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, val);
2641 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x0);
2642 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x0);
2643 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, 0x0);
2644 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x1);
2645 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x1);
2646
2647 vars->mac_type = MAC_TYPE_BMAC;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002648 return rc;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002649}
2650
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002651
2652static void bnx2x_update_mng(struct link_params *params, u32 link_status)
2653{
2654 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002655
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002656 REG_WR(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002657 offsetof(struct shmem_region,
2658 port_mb[params->port].link_status), link_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002659}
2660
2661static void bnx2x_bmac_rx_disable(struct bnx2x *bp, u8 port)
2662{
2663 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002664 NIG_REG_INGRESS_BMAC0_MEM;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002665 u32 wb_data[2];
Eilon Greenstein3196a882008-08-13 15:58:49 -07002666 u32 nig_bmac_enable = REG_RD(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002667
2668 /* Only if the bmac is out of reset */
2669 if (REG_RD(bp, MISC_REG_RESET_REG_2) &
2670 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port) &&
2671 nig_bmac_enable) {
2672
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002673 if (CHIP_IS_E2(bp)) {
2674 /* Clear Rx Enable bit in BMAC_CONTROL register */
2675 REG_RD_DMAE(bp, bmac_addr +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002676 BIGMAC2_REGISTER_BMAC_CONTROL,
2677 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002678 wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
2679 REG_WR_DMAE(bp, bmac_addr +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002680 BIGMAC2_REGISTER_BMAC_CONTROL,
2681 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002682 } else {
2683 /* Clear Rx Enable bit in BMAC_CONTROL register */
2684 REG_RD_DMAE(bp, bmac_addr +
2685 BIGMAC_REGISTER_BMAC_CONTROL,
2686 wb_data, 2);
2687 wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
2688 REG_WR_DMAE(bp, bmac_addr +
2689 BIGMAC_REGISTER_BMAC_CONTROL,
2690 wb_data, 2);
2691 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002692 msleep(1);
2693 }
2694}
2695
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00002696static int bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl,
2697 u32 line_speed)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002698{
2699 struct bnx2x *bp = params->bp;
2700 u8 port = params->port;
2701 u32 init_crd, crd;
2702 u32 count = 1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002703
2704 /* disable port */
2705 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x1);
2706
2707 /* wait for init credit */
2708 init_crd = REG_RD(bp, PBF_REG_P0_INIT_CRD + port*4);
2709 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
2710 DP(NETIF_MSG_LINK, "init_crd 0x%x crd 0x%x\n", init_crd, crd);
2711
2712 while ((init_crd != crd) && count) {
2713 msleep(5);
2714
2715 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
2716 count--;
2717 }
2718 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
2719 if (init_crd != crd) {
2720 DP(NETIF_MSG_LINK, "BUG! init_crd 0x%x != crd 0x%x\n",
2721 init_crd, crd);
2722 return -EINVAL;
2723 }
2724
David S. Millerc0700f92008-12-16 23:53:20 -08002725 if (flow_ctrl & BNX2X_FLOW_CTRL_RX ||
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002726 line_speed == SPEED_10 ||
2727 line_speed == SPEED_100 ||
2728 line_speed == SPEED_1000 ||
2729 line_speed == SPEED_2500) {
2730 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002731 /* update threshold */
2732 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, 0);
2733 /* update init credit */
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002734 init_crd = 778; /* (800-18-4) */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002735
2736 } else {
2737 u32 thresh = (ETH_MAX_JUMBO_PACKET_SIZE +
2738 ETH_OVREHEAD)/16;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002739 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002740 /* update threshold */
2741 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, thresh);
2742 /* update init credit */
2743 switch (line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002744 case SPEED_10000:
2745 init_crd = thresh + 553 - 22;
2746 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002747 default:
2748 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
2749 line_speed);
2750 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002751 }
2752 }
2753 REG_WR(bp, PBF_REG_P0_INIT_CRD + port*4, init_crd);
2754 DP(NETIF_MSG_LINK, "PBF updated to speed %d credit %d\n",
2755 line_speed, init_crd);
2756
2757 /* probe the credit changes */
2758 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x1);
2759 msleep(5);
2760 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x0);
2761
2762 /* enable port */
2763 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x0);
2764 return 0;
2765}
2766
Dmitry Kravkove8920672011-05-04 23:52:40 +00002767/**
2768 * bnx2x_get_emac_base - retrive emac base address
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002769 *
Dmitry Kravkove8920672011-05-04 23:52:40 +00002770 * @bp: driver handle
2771 * @mdc_mdio_access: access type
2772 * @port: port id
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002773 *
2774 * This function selects the MDC/MDIO access (through emac0 or
2775 * emac1) depend on the mdc_mdio_access, port, port swapped. Each
2776 * phy has a default access mode, which could also be overridden
2777 * by nvram configuration. This parameter, whether this is the
2778 * default phy configuration, or the nvram overrun
2779 * configuration, is passed here as mdc_mdio_access and selects
2780 * the emac_base for the CL45 read/writes operations
2781 */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002782static u32 bnx2x_get_emac_base(struct bnx2x *bp,
2783 u32 mdc_mdio_access, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002784{
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002785 u32 emac_base = 0;
2786 switch (mdc_mdio_access) {
2787 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_PHY_TYPE:
2788 break;
2789 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC0:
2790 if (REG_RD(bp, NIG_REG_PORT_SWAP))
2791 emac_base = GRCBASE_EMAC1;
2792 else
2793 emac_base = GRCBASE_EMAC0;
2794 break;
2795 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1:
Eilon Greenstein589abe32009-02-12 08:36:55 +00002796 if (REG_RD(bp, NIG_REG_PORT_SWAP))
2797 emac_base = GRCBASE_EMAC0;
2798 else
2799 emac_base = GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002800 break;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002801 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH:
2802 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
2803 break;
2804 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_SWAPPED:
Eilon Greenstein6378c022008-08-13 15:59:25 -07002805 emac_base = (port) ? GRCBASE_EMAC0 : GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002806 break;
2807 default:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002808 break;
2809 }
2810 return emac_base;
2811
2812}
2813
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002814/******************************************************************/
Yaniv Rosner6583e332011-06-14 01:34:17 +00002815/* CL22 access functions */
2816/******************************************************************/
2817static int bnx2x_cl22_write(struct bnx2x *bp,
2818 struct bnx2x_phy *phy,
2819 u16 reg, u16 val)
2820{
2821 u32 tmp, mode;
2822 u8 i;
2823 int rc = 0;
2824 /* Switch to CL22 */
2825 mode = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
2826 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE,
2827 mode & ~EMAC_MDIO_MODE_CLAUSE_45);
2828
2829 /* address */
2830 tmp = ((phy->addr << 21) | (reg << 16) | val |
2831 EMAC_MDIO_COMM_COMMAND_WRITE_22 |
2832 EMAC_MDIO_COMM_START_BUSY);
2833 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
2834
2835 for (i = 0; i < 50; i++) {
2836 udelay(10);
2837
2838 tmp = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
2839 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
2840 udelay(5);
2841 break;
2842 }
2843 }
2844 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
2845 DP(NETIF_MSG_LINK, "write phy register failed\n");
2846 rc = -EFAULT;
2847 }
2848 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, mode);
2849 return rc;
2850}
2851
2852static int bnx2x_cl22_read(struct bnx2x *bp,
2853 struct bnx2x_phy *phy,
2854 u16 reg, u16 *ret_val)
2855{
2856 u32 val, mode;
2857 u16 i;
2858 int rc = 0;
2859
2860 /* Switch to CL22 */
2861 mode = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
2862 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE,
2863 mode & ~EMAC_MDIO_MODE_CLAUSE_45);
2864
2865 /* address */
2866 val = ((phy->addr << 21) | (reg << 16) |
2867 EMAC_MDIO_COMM_COMMAND_READ_22 |
2868 EMAC_MDIO_COMM_START_BUSY);
2869 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
2870
2871 for (i = 0; i < 50; i++) {
2872 udelay(10);
2873
2874 val = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
2875 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
2876 *ret_val = (u16)(val & EMAC_MDIO_COMM_DATA);
2877 udelay(5);
2878 break;
2879 }
2880 }
2881 if (val & EMAC_MDIO_COMM_START_BUSY) {
2882 DP(NETIF_MSG_LINK, "read phy register failed\n");
2883
2884 *ret_val = 0;
2885 rc = -EFAULT;
2886 }
2887 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, mode);
2888 return rc;
2889}
2890
2891/******************************************************************/
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002892/* CL45 access functions */
2893/******************************************************************/
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00002894static int bnx2x_cl45_read(struct bnx2x *bp, struct bnx2x_phy *phy,
2895 u8 devad, u16 reg, u16 *ret_val)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002896{
Yaniv Rosnera198c142011-05-31 21:29:42 +00002897 u32 val;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002898 u16 i;
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00002899 int rc = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002900
2901 /* address */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002902 val = ((phy->addr << 21) | (devad << 16) | reg |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002903 EMAC_MDIO_COMM_COMMAND_ADDRESS |
2904 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002905 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002906
2907 for (i = 0; i < 50; i++) {
2908 udelay(10);
2909
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002910 val = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002911 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
2912 udelay(5);
2913 break;
2914 }
2915 }
2916 if (val & EMAC_MDIO_COMM_START_BUSY) {
2917 DP(NETIF_MSG_LINK, "read phy register failed\n");
Yaniv Rosner6d870c32011-01-31 04:22:20 +00002918 netdev_err(bp->dev, "MDC/MDIO access timeout\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002919 *ret_val = 0;
2920 rc = -EFAULT;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002921 } else {
2922 /* data */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002923 val = ((phy->addr << 21) | (devad << 16) |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002924 EMAC_MDIO_COMM_COMMAND_READ_45 |
2925 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002926 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002927
2928 for (i = 0; i < 50; i++) {
2929 udelay(10);
2930
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002931 val = REG_RD(bp, phy->mdio_ctrl +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002932 EMAC_REG_EMAC_MDIO_COMM);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002933 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
2934 *ret_val = (u16)(val & EMAC_MDIO_COMM_DATA);
2935 break;
2936 }
2937 }
2938 if (val & EMAC_MDIO_COMM_START_BUSY) {
2939 DP(NETIF_MSG_LINK, "read phy register failed\n");
Yaniv Rosner6d870c32011-01-31 04:22:20 +00002940 netdev_err(bp->dev, "MDC/MDIO access timeout\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002941 *ret_val = 0;
2942 rc = -EFAULT;
2943 }
2944 }
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00002945 /* Work around for E3 A0 */
2946 if (phy->flags & FLAGS_MDC_MDIO_WA) {
2947 phy->flags ^= FLAGS_DUMMY_READ;
2948 if (phy->flags & FLAGS_DUMMY_READ) {
2949 u16 temp_val;
2950 bnx2x_cl45_read(bp, phy, devad, 0xf, &temp_val);
2951 }
2952 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002953
Yaniv Rosnera198c142011-05-31 21:29:42 +00002954 return rc;
2955}
2956
2957static int bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy,
2958 u8 devad, u16 reg, u16 val)
2959{
2960 u32 tmp;
2961 u8 i;
2962 int rc = 0;
2963
2964 /* address */
2965
2966 tmp = ((phy->addr << 21) | (devad << 16) | reg |
2967 EMAC_MDIO_COMM_COMMAND_ADDRESS |
2968 EMAC_MDIO_COMM_START_BUSY);
2969 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
2970
2971 for (i = 0; i < 50; i++) {
2972 udelay(10);
2973
2974 tmp = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
2975 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
2976 udelay(5);
2977 break;
2978 }
2979 }
2980 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
2981 DP(NETIF_MSG_LINK, "write phy register failed\n");
2982 netdev_err(bp->dev, "MDC/MDIO access timeout\n");
2983 rc = -EFAULT;
2984
2985 } else {
2986 /* data */
2987 tmp = ((phy->addr << 21) | (devad << 16) | val |
2988 EMAC_MDIO_COMM_COMMAND_WRITE_45 |
2989 EMAC_MDIO_COMM_START_BUSY);
2990 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
2991
2992 for (i = 0; i < 50; i++) {
2993 udelay(10);
2994
2995 tmp = REG_RD(bp, phy->mdio_ctrl +
2996 EMAC_REG_EMAC_MDIO_COMM);
2997 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
2998 udelay(5);
2999 break;
3000 }
3001 }
3002 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
3003 DP(NETIF_MSG_LINK, "write phy register failed\n");
3004 netdev_err(bp->dev, "MDC/MDIO access timeout\n");
3005 rc = -EFAULT;
3006 }
3007 }
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00003008 /* Work around for E3 A0 */
3009 if (phy->flags & FLAGS_MDC_MDIO_WA) {
3010 phy->flags ^= FLAGS_DUMMY_READ;
3011 if (phy->flags & FLAGS_DUMMY_READ) {
3012 u16 temp_val;
3013 bnx2x_cl45_read(bp, phy, devad, 0xf, &temp_val);
3014 }
3015 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003016
3017 return rc;
3018}
3019
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00003020
3021/******************************************************************/
3022/* BSC access functions from E3 */
3023/******************************************************************/
3024static void bnx2x_bsc_module_sel(struct link_params *params)
3025{
3026 int idx;
3027 u32 board_cfg, sfp_ctrl;
3028 u32 i2c_pins[I2C_SWITCH_WIDTH], i2c_val[I2C_SWITCH_WIDTH];
3029 struct bnx2x *bp = params->bp;
3030 u8 port = params->port;
3031 /* Read I2C output PINs */
3032 board_cfg = REG_RD(bp, params->shmem_base +
3033 offsetof(struct shmem_region,
3034 dev_info.shared_hw_config.board));
3035 i2c_pins[I2C_BSC0] = board_cfg & SHARED_HW_CFG_E3_I2C_MUX0_MASK;
3036 i2c_pins[I2C_BSC1] = (board_cfg & SHARED_HW_CFG_E3_I2C_MUX1_MASK) >>
3037 SHARED_HW_CFG_E3_I2C_MUX1_SHIFT;
3038
3039 /* Read I2C output value */
3040 sfp_ctrl = REG_RD(bp, params->shmem_base +
3041 offsetof(struct shmem_region,
3042 dev_info.port_hw_config[port].e3_cmn_pin_cfg));
3043 i2c_val[I2C_BSC0] = (sfp_ctrl & PORT_HW_CFG_E3_I2C_MUX0_MASK) > 0;
3044 i2c_val[I2C_BSC1] = (sfp_ctrl & PORT_HW_CFG_E3_I2C_MUX1_MASK) > 0;
3045 DP(NETIF_MSG_LINK, "Setting BSC switch\n");
3046 for (idx = 0; idx < I2C_SWITCH_WIDTH; idx++)
3047 bnx2x_set_cfg_pin(bp, i2c_pins[idx], i2c_val[idx]);
3048}
3049
3050static int bnx2x_bsc_read(struct link_params *params,
3051 struct bnx2x_phy *phy,
3052 u8 sl_devid,
3053 u16 sl_addr,
3054 u8 lc_addr,
3055 u8 xfer_cnt,
3056 u32 *data_array)
3057{
3058 u32 val, i;
3059 int rc = 0;
3060 struct bnx2x *bp = params->bp;
3061
3062 if ((sl_devid != 0xa0) && (sl_devid != 0xa2)) {
3063 DP(NETIF_MSG_LINK, "invalid sl_devid 0x%x\n", sl_devid);
3064 return -EINVAL;
3065 }
3066
3067 if (xfer_cnt > 16) {
3068 DP(NETIF_MSG_LINK, "invalid xfer_cnt %d. Max is 16 bytes\n",
3069 xfer_cnt);
3070 return -EINVAL;
3071 }
3072 bnx2x_bsc_module_sel(params);
3073
3074 xfer_cnt = 16 - lc_addr;
3075
3076 /* enable the engine */
3077 val = REG_RD(bp, MCP_REG_MCPR_IMC_COMMAND);
3078 val |= MCPR_IMC_COMMAND_ENABLE;
3079 REG_WR(bp, MCP_REG_MCPR_IMC_COMMAND, val);
3080
3081 /* program slave device ID */
3082 val = (sl_devid << 16) | sl_addr;
3083 REG_WR(bp, MCP_REG_MCPR_IMC_SLAVE_CONTROL, val);
3084
3085 /* start xfer with 0 byte to update the address pointer ???*/
3086 val = (MCPR_IMC_COMMAND_ENABLE) |
3087 (MCPR_IMC_COMMAND_WRITE_OP <<
3088 MCPR_IMC_COMMAND_OPERATION_BITSHIFT) |
3089 (lc_addr << MCPR_IMC_COMMAND_TRANSFER_ADDRESS_BITSHIFT) | (0);
3090 REG_WR(bp, MCP_REG_MCPR_IMC_COMMAND, val);
3091
3092 /* poll for completion */
3093 i = 0;
3094 val = REG_RD(bp, MCP_REG_MCPR_IMC_COMMAND);
3095 while (((val >> MCPR_IMC_COMMAND_IMC_STATUS_BITSHIFT) & 0x3) != 1) {
3096 udelay(10);
3097 val = REG_RD(bp, MCP_REG_MCPR_IMC_COMMAND);
3098 if (i++ > 1000) {
3099 DP(NETIF_MSG_LINK, "wr 0 byte timed out after %d try\n",
3100 i);
3101 rc = -EFAULT;
3102 break;
3103 }
3104 }
3105 if (rc == -EFAULT)
3106 return rc;
3107
3108 /* start xfer with read op */
3109 val = (MCPR_IMC_COMMAND_ENABLE) |
3110 (MCPR_IMC_COMMAND_READ_OP <<
3111 MCPR_IMC_COMMAND_OPERATION_BITSHIFT) |
3112 (lc_addr << MCPR_IMC_COMMAND_TRANSFER_ADDRESS_BITSHIFT) |
3113 (xfer_cnt);
3114 REG_WR(bp, MCP_REG_MCPR_IMC_COMMAND, val);
3115
3116 /* poll for completion */
3117 i = 0;
3118 val = REG_RD(bp, MCP_REG_MCPR_IMC_COMMAND);
3119 while (((val >> MCPR_IMC_COMMAND_IMC_STATUS_BITSHIFT) & 0x3) != 1) {
3120 udelay(10);
3121 val = REG_RD(bp, MCP_REG_MCPR_IMC_COMMAND);
3122 if (i++ > 1000) {
3123 DP(NETIF_MSG_LINK, "rd op timed out after %d try\n", i);
3124 rc = -EFAULT;
3125 break;
3126 }
3127 }
3128 if (rc == -EFAULT)
3129 return rc;
3130
3131 for (i = (lc_addr >> 2); i < 4; i++) {
3132 data_array[i] = REG_RD(bp, (MCP_REG_MCPR_IMC_DATAREG0 + i*4));
3133#ifdef __BIG_ENDIAN
3134 data_array[i] = ((data_array[i] & 0x000000ff) << 24) |
3135 ((data_array[i] & 0x0000ff00) << 8) |
3136 ((data_array[i] & 0x00ff0000) >> 8) |
3137 ((data_array[i] & 0xff000000) >> 24);
3138#endif
3139 }
3140 return rc;
3141}
3142
3143static void bnx2x_cl45_read_or_write(struct bnx2x *bp, struct bnx2x_phy *phy,
3144 u8 devad, u16 reg, u16 or_val)
3145{
3146 u16 val;
3147 bnx2x_cl45_read(bp, phy, devad, reg, &val);
3148 bnx2x_cl45_write(bp, phy, devad, reg, val | or_val);
3149}
3150
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00003151int bnx2x_phy_read(struct link_params *params, u8 phy_addr,
3152 u8 devad, u16 reg, u16 *ret_val)
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003153{
3154 u8 phy_index;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003155 /*
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003156 * Probe for the phy according to the given phy_addr, and execute
3157 * the read request on it
3158 */
3159 for (phy_index = 0; phy_index < params->num_phys; phy_index++) {
3160 if (params->phy[phy_index].addr == phy_addr) {
3161 return bnx2x_cl45_read(params->bp,
3162 &params->phy[phy_index], devad,
3163 reg, ret_val);
3164 }
3165 }
3166 return -EINVAL;
3167}
3168
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00003169int bnx2x_phy_write(struct link_params *params, u8 phy_addr,
3170 u8 devad, u16 reg, u16 val)
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003171{
3172 u8 phy_index;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003173 /*
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003174 * Probe for the phy according to the given phy_addr, and execute
3175 * the write request on it
3176 */
3177 for (phy_index = 0; phy_index < params->num_phys; phy_index++) {
3178 if (params->phy[phy_index].addr == phy_addr) {
3179 return bnx2x_cl45_write(params->bp,
3180 &params->phy[phy_index], devad,
3181 reg, val);
3182 }
3183 }
3184 return -EINVAL;
3185}
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00003186static u8 bnx2x_get_warpcore_lane(struct bnx2x_phy *phy,
3187 struct link_params *params)
3188{
3189 u8 lane = 0;
3190 struct bnx2x *bp = params->bp;
3191 u32 path_swap, path_swap_ovr;
3192 u8 path, port;
3193
3194 path = BP_PATH(bp);
3195 port = params->port;
3196
3197 if (bnx2x_is_4_port_mode(bp)) {
3198 u32 port_swap, port_swap_ovr;
3199
3200 /*figure out path swap value */
3201 path_swap_ovr = REG_RD(bp, MISC_REG_FOUR_PORT_PATH_SWAP_OVWR);
3202 if (path_swap_ovr & 0x1)
3203 path_swap = (path_swap_ovr & 0x2);
3204 else
3205 path_swap = REG_RD(bp, MISC_REG_FOUR_PORT_PATH_SWAP);
3206
3207 if (path_swap)
3208 path = path ^ 1;
3209
3210 /*figure out port swap value */
3211 port_swap_ovr = REG_RD(bp, MISC_REG_FOUR_PORT_PORT_SWAP_OVWR);
3212 if (port_swap_ovr & 0x1)
3213 port_swap = (port_swap_ovr & 0x2);
3214 else
3215 port_swap = REG_RD(bp, MISC_REG_FOUR_PORT_PORT_SWAP);
3216
3217 if (port_swap)
3218 port = port ^ 1;
3219
3220 lane = (port<<1) + path;
3221 } else { /* two port mode - no port swap */
3222
3223 /*figure out path swap value */
3224 path_swap_ovr =
3225 REG_RD(bp, MISC_REG_TWO_PORT_PATH_SWAP_OVWR);
3226 if (path_swap_ovr & 0x1) {
3227 path_swap = (path_swap_ovr & 0x2);
3228 } else {
3229 path_swap =
3230 REG_RD(bp, MISC_REG_TWO_PORT_PATH_SWAP);
3231 }
3232 if (path_swap)
3233 path = path ^ 1;
3234
3235 lane = path << 1 ;
3236 }
3237 return lane;
3238}
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003239
Yaniv Rosnerec146a62011-05-31 21:29:27 +00003240static void bnx2x_set_aer_mmd(struct link_params *params,
3241 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003242{
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003243 u32 ser_lane;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00003244 u16 offset, aer_val;
3245 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003246 ser_lane = ((params->lane_config &
3247 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
3248 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
3249
Yaniv Rosnerec146a62011-05-31 21:29:27 +00003250 offset = (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ?
3251 (phy->addr + ser_lane) : 0;
3252
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00003253 if (USES_WARPCORE(bp)) {
3254 aer_val = bnx2x_get_warpcore_lane(phy, params);
3255 /*
3256 * In Dual-lane mode, two lanes are joined together,
3257 * so in order to configure them, the AER broadcast method is
3258 * used here.
3259 * 0x200 is the broadcast address for lanes 0,1
3260 * 0x201 is the broadcast address for lanes 2,3
3261 */
3262 if (phy->flags & FLAGS_WC_DUAL_MODE)
3263 aer_val = (aer_val >> 1) | 0x200;
3264 } else if (CHIP_IS_E2(bp))
Yaniv Rosner82a0d472011-01-18 04:33:52 +00003265 aer_val = 0x3800 + offset - 1;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00003266 else
3267 aer_val = 0x3800 + offset;
Yaniv Rosnerec146a62011-05-31 21:29:27 +00003268 DP(NETIF_MSG_LINK, "Set AER to 0x%x\n", aer_val);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003269 CL22_WR_OVER_CL45(bp, phy, MDIO_REG_BANK_AER_BLOCK,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003270 MDIO_AER_BLOCK_AER_REG, aer_val);
Yaniv Rosnerec146a62011-05-31 21:29:27 +00003271
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003272}
3273
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003274/******************************************************************/
3275/* Internal phy section */
3276/******************************************************************/
3277
3278static void bnx2x_set_serdes_access(struct bnx2x *bp, u8 port)
3279{
3280 u32 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
3281
3282 /* Set Clause 22 */
3283 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + port*0x10, 1);
3284 REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245f8000);
3285 udelay(500);
3286 REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245d000f);
3287 udelay(500);
3288 /* Set Clause 45 */
3289 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + port*0x10, 0);
3290}
3291
3292static void bnx2x_serdes_deassert(struct bnx2x *bp, u8 port)
3293{
3294 u32 val;
3295
3296 DP(NETIF_MSG_LINK, "bnx2x_serdes_deassert\n");
3297
3298 val = SERDES_RESET_BITS << (port*16);
3299
3300 /* reset and unreset the SerDes/XGXS */
3301 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR, val);
3302 udelay(500);
3303 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET, val);
3304
3305 bnx2x_set_serdes_access(bp, port);
3306
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003307 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_DEVAD + port*0x10,
3308 DEFAULT_PHY_DEV_ADDR);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003309}
3310
3311static void bnx2x_xgxs_deassert(struct link_params *params)
3312{
3313 struct bnx2x *bp = params->bp;
3314 u8 port;
3315 u32 val;
3316 DP(NETIF_MSG_LINK, "bnx2x_xgxs_deassert\n");
3317 port = params->port;
3318
3319 val = XGXS_RESET_BITS << (port*16);
3320
3321 /* reset and unreset the SerDes/XGXS */
3322 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR, val);
3323 udelay(500);
3324 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET, val);
3325
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003326 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_ST + port*0x18, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003327 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003328 params->phy[INT_PHY].def_md_devad);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003329}
3330
Yaniv Rosner9045f6b2011-05-31 21:28:27 +00003331static void bnx2x_calc_ieee_aneg_adv(struct bnx2x_phy *phy,
3332 struct link_params *params, u16 *ieee_fc)
3333{
3334 struct bnx2x *bp = params->bp;
3335 *ieee_fc = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX;
3336 /**
3337 * resolve pause mode and advertisement Please refer to Table
3338 * 28B-3 of the 802.3ab-1999 spec
3339 */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003340
Yaniv Rosner9045f6b2011-05-31 21:28:27 +00003341 switch (phy->req_flow_ctrl) {
3342 case BNX2X_FLOW_CTRL_AUTO:
3343 if (params->req_fc_auto_adv == BNX2X_FLOW_CTRL_BOTH)
3344 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
3345 else
3346 *ieee_fc |=
3347 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
3348 break;
3349
3350 case BNX2X_FLOW_CTRL_TX:
3351 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
3352 break;
3353
3354 case BNX2X_FLOW_CTRL_RX:
3355 case BNX2X_FLOW_CTRL_BOTH:
3356 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
3357 break;
3358
3359 case BNX2X_FLOW_CTRL_NONE:
3360 default:
3361 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE;
3362 break;
3363 }
3364 DP(NETIF_MSG_LINK, "ieee_fc = 0x%x\n", *ieee_fc);
3365}
3366
3367static void set_phy_vars(struct link_params *params,
3368 struct link_vars *vars)
3369{
3370 struct bnx2x *bp = params->bp;
3371 u8 actual_phy_idx, phy_index, link_cfg_idx;
3372 u8 phy_config_swapped = params->multi_phy_config &
3373 PORT_HW_CFG_PHY_SWAPPED_ENABLED;
3374 for (phy_index = INT_PHY; phy_index < params->num_phys;
3375 phy_index++) {
3376 link_cfg_idx = LINK_CONFIG_IDX(phy_index);
3377 actual_phy_idx = phy_index;
3378 if (phy_config_swapped) {
3379 if (phy_index == EXT_PHY1)
3380 actual_phy_idx = EXT_PHY2;
3381 else if (phy_index == EXT_PHY2)
3382 actual_phy_idx = EXT_PHY1;
3383 }
3384 params->phy[actual_phy_idx].req_flow_ctrl =
3385 params->req_flow_ctrl[link_cfg_idx];
3386
3387 params->phy[actual_phy_idx].req_line_speed =
3388 params->req_line_speed[link_cfg_idx];
3389
3390 params->phy[actual_phy_idx].speed_cap_mask =
3391 params->speed_cap_mask[link_cfg_idx];
3392
3393 params->phy[actual_phy_idx].req_duplex =
3394 params->req_duplex[link_cfg_idx];
3395
3396 if (params->req_line_speed[link_cfg_idx] ==
3397 SPEED_AUTO_NEG)
3398 vars->link_status |= LINK_STATUS_AUTO_NEGOTIATE_ENABLED;
3399
3400 DP(NETIF_MSG_LINK, "req_flow_ctrl %x, req_line_speed %x,"
3401 " speed_cap_mask %x\n",
3402 params->phy[actual_phy_idx].req_flow_ctrl,
3403 params->phy[actual_phy_idx].req_line_speed,
3404 params->phy[actual_phy_idx].speed_cap_mask);
3405 }
3406}
3407
3408static void bnx2x_ext_phy_set_pause(struct link_params *params,
3409 struct bnx2x_phy *phy,
3410 struct link_vars *vars)
3411{
3412 u16 val;
3413 struct bnx2x *bp = params->bp;
3414 /* read modify write pause advertizing */
3415 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV_PAUSE, &val);
3416
3417 val &= ~MDIO_AN_REG_ADV_PAUSE_BOTH;
3418
3419 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
3420 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
3421 if ((vars->ieee_fc &
3422 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
3423 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
3424 val |= MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC;
3425 }
3426 if ((vars->ieee_fc &
3427 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
3428 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
3429 val |= MDIO_AN_REG_ADV_PAUSE_PAUSE;
3430 }
3431 DP(NETIF_MSG_LINK, "Ext phy AN advertize 0x%x\n", val);
3432 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV_PAUSE, val);
3433}
3434
3435static void bnx2x_pause_resolve(struct link_vars *vars, u32 pause_result)
3436{ /* LD LP */
3437 switch (pause_result) { /* ASYM P ASYM P */
3438 case 0xb: /* 1 0 1 1 */
3439 vars->flow_ctrl = BNX2X_FLOW_CTRL_TX;
3440 break;
3441
3442 case 0xe: /* 1 1 1 0 */
3443 vars->flow_ctrl = BNX2X_FLOW_CTRL_RX;
3444 break;
3445
3446 case 0x5: /* 0 1 0 1 */
3447 case 0x7: /* 0 1 1 1 */
3448 case 0xd: /* 1 1 0 1 */
3449 case 0xf: /* 1 1 1 1 */
3450 vars->flow_ctrl = BNX2X_FLOW_CTRL_BOTH;
3451 break;
3452
3453 default:
3454 break;
3455 }
3456 if (pause_result & (1<<0))
3457 vars->link_status |= LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE;
3458 if (pause_result & (1<<1))
3459 vars->link_status |= LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE;
3460}
3461
3462static u8 bnx2x_ext_phy_resolve_fc(struct bnx2x_phy *phy,
3463 struct link_params *params,
3464 struct link_vars *vars)
3465{
3466 struct bnx2x *bp = params->bp;
3467 u16 ld_pause; /* local */
3468 u16 lp_pause; /* link partner */
3469 u16 pause_result;
3470 u8 ret = 0;
3471 /* read twice */
3472
3473 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
3474
3475 if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO)
3476 vars->flow_ctrl = phy->req_flow_ctrl;
3477 else if (phy->req_line_speed != SPEED_AUTO_NEG)
3478 vars->flow_ctrl = params->req_fc_auto_adv;
3479 else if (vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE) {
3480 ret = 1;
Yaniv Rosner6583e332011-06-14 01:34:17 +00003481 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54616) {
3482 bnx2x_cl22_read(bp, phy,
3483 0x4, &ld_pause);
3484 bnx2x_cl22_read(bp, phy,
3485 0x5, &lp_pause);
3486 } else {
3487 bnx2x_cl45_read(bp, phy,
3488 MDIO_AN_DEVAD,
3489 MDIO_AN_REG_ADV_PAUSE, &ld_pause);
3490 bnx2x_cl45_read(bp, phy,
3491 MDIO_AN_DEVAD,
3492 MDIO_AN_REG_LP_AUTO_NEG, &lp_pause);
3493 }
Yaniv Rosner9045f6b2011-05-31 21:28:27 +00003494 pause_result = (ld_pause &
3495 MDIO_AN_REG_ADV_PAUSE_MASK) >> 8;
3496 pause_result |= (lp_pause &
3497 MDIO_AN_REG_ADV_PAUSE_MASK) >> 10;
3498 DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x\n",
3499 pause_result);
3500 bnx2x_pause_resolve(vars, pause_result);
3501 }
3502 return ret;
3503}
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00003504/******************************************************************/
3505/* Warpcore section */
3506/******************************************************************/
3507/* The init_internal_warpcore should mirror the xgxs,
3508 * i.e. reset the lane (if needed), set aer for the
3509 * init configuration, and set/clear SGMII flag. Internal
3510 * phy init is done purely in phy_init stage.
3511 */
3512static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy,
3513 struct link_params *params,
3514 struct link_vars *vars) {
3515 u16 val16 = 0, lane;
3516 struct bnx2x *bp = params->bp;
3517 DP(NETIF_MSG_LINK, "Enable Auto Negotiation for KR\n");
3518 /* Check adding advertisement for 1G KX */
3519 if (((vars->line_speed == SPEED_AUTO_NEG) &&
3520 (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) ||
3521 (vars->line_speed == SPEED_1000)) {
3522 u16 sd_digital;
3523 val16 |= (1<<5);
3524
3525 /* Enable CL37 1G Parallel Detect */
3526 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3527 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, &sd_digital);
3528 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3529 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2,
3530 (sd_digital | 0x1));
3531
3532 DP(NETIF_MSG_LINK, "Advertize 1G\n");
3533 }
3534 if (((vars->line_speed == SPEED_AUTO_NEG) &&
3535 (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) ||
3536 (vars->line_speed == SPEED_10000)) {
3537 /* Check adding advertisement for 10G KR */
3538 val16 |= (1<<7);
3539 /* Enable 10G Parallel Detect */
3540 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
3541 MDIO_WC_REG_PAR_DET_10G_CTRL, 1);
3542
3543 DP(NETIF_MSG_LINK, "Advertize 10G\n");
3544 }
3545
3546 /* Set Transmit PMD settings */
3547 lane = bnx2x_get_warpcore_lane(phy, params);
3548 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3549 MDIO_WC_REG_TX0_TX_DRIVER + 0x10*lane,
3550 ((0x02 << MDIO_WC_REG_TX0_TX_DRIVER_POST2_COEFF_OFFSET) |
3551 (0x06 << MDIO_WC_REG_TX0_TX_DRIVER_IDRIVER_OFFSET) |
3552 (0x09 << MDIO_WC_REG_TX0_TX_DRIVER_IPRE_DRIVER_OFFSET)));
3553 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3554 MDIO_WC_REG_CL72_USERB0_CL72_OS_DEF_CTRL,
3555 0x03f0);
3556 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3557 MDIO_WC_REG_CL72_USERB0_CL72_2P5_DEF_CTRL,
3558 0x03f0);
3559 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3560 MDIO_WC_REG_CL72_USERB0_CL72_MISC1_CONTROL,
3561 0x383f);
3562
3563 /* Advertised speeds */
3564 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
3565 MDIO_WC_REG_AN_IEEE1BLK_AN_ADVERTISEMENT1, val16);
3566
3567 /* Advertise pause */
3568 bnx2x_ext_phy_set_pause(params, phy, vars);
3569
3570 /* Enable Autoneg */
3571 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
3572 MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x1000);
3573
3574 /* Over 1G - AN local device user page 1 */
3575 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3576 MDIO_WC_REG_DIGITAL3_UP1, 0x1f);
3577
3578 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3579 MDIO_WC_REG_DIGITAL5_MISC7, &val16);
3580
3581 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3582 MDIO_WC_REG_DIGITAL5_MISC7, val16 | 0x100);
3583}
3584
3585static void bnx2x_warpcore_set_10G_KR(struct bnx2x_phy *phy,
3586 struct link_params *params,
3587 struct link_vars *vars)
3588{
3589 struct bnx2x *bp = params->bp;
3590 u16 val;
3591
3592 /* Disable Autoneg */
3593 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3594 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, 0x7);
3595
3596 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
3597 MDIO_WC_REG_PAR_DET_10G_CTRL, 0);
3598
3599 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3600 MDIO_WC_REG_CL72_USERB0_CL72_MISC1_CONTROL, 0x3f00);
3601
3602 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
3603 MDIO_WC_REG_AN_IEEE1BLK_AN_ADVERTISEMENT1, 0);
3604
3605 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
3606 MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x0);
3607
3608 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3609 MDIO_WC_REG_DIGITAL3_UP1, 0x1);
3610
3611 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3612 MDIO_WC_REG_DIGITAL5_MISC7, 0xa);
3613
3614 /* Disable CL36 PCS Tx */
3615 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3616 MDIO_WC_REG_XGXSBLK1_LANECTRL0, 0x0);
3617
3618 /* Double Wide Single Data Rate @ pll rate */
3619 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3620 MDIO_WC_REG_XGXSBLK1_LANECTRL1, 0xFFFF);
3621
3622 /* Leave cl72 training enable, needed for KR */
3623 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD,
3624 MDIO_WC_REG_PMD_IEEE9BLK_TENGBASE_KR_PMD_CONTROL_REGISTER_150,
3625 0x2);
3626
3627 /* Leave CL72 enabled */
3628 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3629 MDIO_WC_REG_CL72_USERB0_CL72_MISC1_CONTROL,
3630 &val);
3631 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3632 MDIO_WC_REG_CL72_USERB0_CL72_MISC1_CONTROL,
3633 val | 0x3800);
3634
3635 /* Set speed via PMA/PMD register */
3636 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD,
3637 MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x2040);
3638
3639 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD,
3640 MDIO_WC_REG_IEEE0BLK_AUTONEGNP, 0xB);
3641
3642 /*Enable encoded forced speed */
3643 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3644 MDIO_WC_REG_SERDESDIGITAL_MISC2, 0x30);
3645
3646 /* Turn TX scramble payload only the 64/66 scrambler */
3647 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3648 MDIO_WC_REG_TX66_CONTROL, 0x9);
3649
3650 /* Turn RX scramble payload only the 64/66 scrambler */
3651 bnx2x_cl45_read_or_write(bp, phy, MDIO_WC_DEVAD,
3652 MDIO_WC_REG_RX66_CONTROL, 0xF9);
3653
3654 /* set and clear loopback to cause a reset to 64/66 decoder */
3655 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3656 MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x4000);
3657 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3658 MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x0);
3659
3660}
3661
3662static void bnx2x_warpcore_set_10G_XFI(struct bnx2x_phy *phy,
3663 struct link_params *params,
3664 u8 is_xfi)
3665{
3666 struct bnx2x *bp = params->bp;
3667 u16 misc1_val, tap_val, tx_driver_val, lane, val;
3668 /* Hold rxSeqStart */
3669 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3670 MDIO_WC_REG_DSC2B0_DSC_MISC_CTRL0, &val);
3671 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3672 MDIO_WC_REG_DSC2B0_DSC_MISC_CTRL0, (val | 0x8000));
3673
3674 /* Hold tx_fifo_reset */
3675 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3676 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X3, &val);
3677 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3678 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X3, (val | 0x1));
3679
3680 /* Disable CL73 AN */
3681 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0);
3682
3683 /* Disable 100FX Enable and Auto-Detect */
3684 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3685 MDIO_WC_REG_FX100_CTRL1, &val);
3686 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3687 MDIO_WC_REG_FX100_CTRL1, (val & 0xFFFA));
3688
3689 /* Disable 100FX Idle detect */
3690 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3691 MDIO_WC_REG_FX100_CTRL3, &val);
3692 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3693 MDIO_WC_REG_FX100_CTRL3, (val | 0x0080));
3694
3695 /* Set Block address to Remote PHY & Clear forced_speed[5] */
3696 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3697 MDIO_WC_REG_DIGITAL4_MISC3, &val);
3698 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3699 MDIO_WC_REG_DIGITAL4_MISC3, (val & 0xFF7F));
3700
3701 /* Turn off auto-detect & fiber mode */
3702 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3703 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1, &val);
3704 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3705 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1,
3706 (val & 0xFFEE));
3707
3708 /* Set filter_force_link, disable_false_link and parallel_detect */
3709 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3710 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, &val);
3711 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3712 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2,
3713 ((val | 0x0006) & 0xFFFE));
3714
3715 /* Set XFI / SFI */
3716 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3717 MDIO_WC_REG_SERDESDIGITAL_MISC1, &misc1_val);
3718
3719 misc1_val &= ~(0x1f);
3720
3721 if (is_xfi) {
3722 misc1_val |= 0x5;
3723 tap_val = ((0x08 << MDIO_WC_REG_TX_FIR_TAP_POST_TAP_OFFSET) |
3724 (0x37 << MDIO_WC_REG_TX_FIR_TAP_MAIN_TAP_OFFSET) |
3725 (0x00 << MDIO_WC_REG_TX_FIR_TAP_PRE_TAP_OFFSET));
3726 tx_driver_val =
3727 ((0x00 << MDIO_WC_REG_TX0_TX_DRIVER_POST2_COEFF_OFFSET) |
3728 (0x02 << MDIO_WC_REG_TX0_TX_DRIVER_IDRIVER_OFFSET) |
3729 (0x03 << MDIO_WC_REG_TX0_TX_DRIVER_IPRE_DRIVER_OFFSET));
3730
3731 } else {
3732 misc1_val |= 0x9;
3733 tap_val = ((0x12 << MDIO_WC_REG_TX_FIR_TAP_POST_TAP_OFFSET) |
3734 (0x2d << MDIO_WC_REG_TX_FIR_TAP_MAIN_TAP_OFFSET) |
3735 (0x00 << MDIO_WC_REG_TX_FIR_TAP_PRE_TAP_OFFSET));
3736 tx_driver_val =
3737 ((0x02 << MDIO_WC_REG_TX0_TX_DRIVER_POST2_COEFF_OFFSET) |
3738 (0x02 << MDIO_WC_REG_TX0_TX_DRIVER_IDRIVER_OFFSET) |
3739 (0x02 << MDIO_WC_REG_TX0_TX_DRIVER_IPRE_DRIVER_OFFSET));
3740 }
3741 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3742 MDIO_WC_REG_SERDESDIGITAL_MISC1, misc1_val);
3743
3744 /* Set Transmit PMD settings */
3745 lane = bnx2x_get_warpcore_lane(phy, params);
3746 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3747 MDIO_WC_REG_TX_FIR_TAP,
3748 tap_val | MDIO_WC_REG_TX_FIR_TAP_ENABLE);
3749 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3750 MDIO_WC_REG_TX0_TX_DRIVER + 0x10*lane,
3751 tx_driver_val);
3752
3753 /* Enable fiber mode, enable and invert sig_det */
3754 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3755 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1, &val);
3756 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3757 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1, val | 0xd);
3758
3759 /* Set Block address to Remote PHY & Set forced_speed[5], 40bit mode */
3760 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3761 MDIO_WC_REG_DIGITAL4_MISC3, &val);
3762 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3763 MDIO_WC_REG_DIGITAL4_MISC3, val | 0x8080);
3764
3765 /* 10G XFI Full Duplex */
3766 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3767 MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x100);
3768
3769 /* Release tx_fifo_reset */
3770 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3771 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X3, &val);
3772 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3773 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X3, val & 0xFFFE);
3774
3775 /* Release rxSeqStart */
3776 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3777 MDIO_WC_REG_DSC2B0_DSC_MISC_CTRL0, &val);
3778 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3779 MDIO_WC_REG_DSC2B0_DSC_MISC_CTRL0, (val & 0x7FFF));
3780}
3781
3782static void bnx2x_warpcore_set_20G_KR2(struct bnx2x *bp,
3783 struct bnx2x_phy *phy)
3784{
3785 DP(NETIF_MSG_LINK, "KR2 still not supported !!!\n");
3786}
3787
3788static void bnx2x_warpcore_set_20G_DXGXS(struct bnx2x *bp,
3789 struct bnx2x_phy *phy,
3790 u16 lane)
3791{
3792 /* Rx0 anaRxControl1G */
3793 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3794 MDIO_WC_REG_RX0_ANARXCONTROL1G, 0x90);
3795
3796 /* Rx2 anaRxControl1G */
3797 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3798 MDIO_WC_REG_RX2_ANARXCONTROL1G, 0x90);
3799
3800 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3801 MDIO_WC_REG_RX66_SCW0, 0xE070);
3802
3803 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3804 MDIO_WC_REG_RX66_SCW1, 0xC0D0);
3805
3806 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3807 MDIO_WC_REG_RX66_SCW2, 0xA0B0);
3808
3809 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3810 MDIO_WC_REG_RX66_SCW3, 0x8090);
3811
3812 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3813 MDIO_WC_REG_RX66_SCW0_MASK, 0xF0F0);
3814
3815 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3816 MDIO_WC_REG_RX66_SCW1_MASK, 0xF0F0);
3817
3818 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3819 MDIO_WC_REG_RX66_SCW2_MASK, 0xF0F0);
3820
3821 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3822 MDIO_WC_REG_RX66_SCW3_MASK, 0xF0F0);
3823
3824 /* Serdes Digital Misc1 */
3825 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3826 MDIO_WC_REG_SERDESDIGITAL_MISC1, 0x6008);
3827
3828 /* Serdes Digital4 Misc3 */
3829 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3830 MDIO_WC_REG_DIGITAL4_MISC3, 0x8088);
3831
3832 /* Set Transmit PMD settings */
3833 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3834 MDIO_WC_REG_TX_FIR_TAP,
3835 ((0x12 << MDIO_WC_REG_TX_FIR_TAP_POST_TAP_OFFSET) |
3836 (0x2d << MDIO_WC_REG_TX_FIR_TAP_MAIN_TAP_OFFSET) |
3837 (0x00 << MDIO_WC_REG_TX_FIR_TAP_PRE_TAP_OFFSET) |
3838 MDIO_WC_REG_TX_FIR_TAP_ENABLE));
3839 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3840 MDIO_WC_REG_TX0_TX_DRIVER + 0x10*lane,
3841 ((0x02 << MDIO_WC_REG_TX0_TX_DRIVER_POST2_COEFF_OFFSET) |
3842 (0x02 << MDIO_WC_REG_TX0_TX_DRIVER_IDRIVER_OFFSET) |
3843 (0x02 << MDIO_WC_REG_TX0_TX_DRIVER_IPRE_DRIVER_OFFSET)));
3844}
3845
3846static void bnx2x_warpcore_set_sgmii_speed(struct bnx2x_phy *phy,
3847 struct link_params *params,
3848 u8 fiber_mode)
3849{
3850 struct bnx2x *bp = params->bp;
3851 u16 val16, digctrl_kx1, digctrl_kx2;
3852 u8 lane;
3853
3854 lane = bnx2x_get_warpcore_lane(phy, params);
3855
3856 /* Clear XFI clock comp in non-10G single lane mode. */
3857 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3858 MDIO_WC_REG_RX66_CONTROL, &val16);
3859 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3860 MDIO_WC_REG_RX66_CONTROL, val16 & ~(3<<13));
3861
3862 if (phy->req_line_speed == SPEED_AUTO_NEG) {
3863 /* SGMII Autoneg */
3864 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3865 MDIO_WC_REG_COMBO_IEEE0_MIICTRL, &val16);
3866 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3867 MDIO_WC_REG_COMBO_IEEE0_MIICTRL,
3868 val16 | 0x1000);
3869 DP(NETIF_MSG_LINK, "set SGMII AUTONEG\n");
3870 } else {
3871 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3872 MDIO_WC_REG_COMBO_IEEE0_MIICTRL, &val16);
3873 val16 &= 0xcfbf;
3874 switch (phy->req_line_speed) {
3875 case SPEED_10:
3876 break;
3877 case SPEED_100:
3878 val16 |= 0x2000;
3879 break;
3880 case SPEED_1000:
3881 val16 |= 0x0040;
3882 break;
3883 default:
3884 DP(NETIF_MSG_LINK, "Speed not supported: 0x%x"
3885 "\n", phy->req_line_speed);
3886 return;
3887 }
3888
3889 if (phy->req_duplex == DUPLEX_FULL)
3890 val16 |= 0x0100;
3891
3892 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3893 MDIO_WC_REG_COMBO_IEEE0_MIICTRL, val16);
3894
3895 DP(NETIF_MSG_LINK, "set SGMII force speed %d\n",
3896 phy->req_line_speed);
3897 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3898 MDIO_WC_REG_COMBO_IEEE0_MIICTRL, &val16);
3899 DP(NETIF_MSG_LINK, " (readback) %x\n", val16);
3900 }
3901
3902 /* SGMII Slave mode and disable signal detect */
3903 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3904 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1, &digctrl_kx1);
3905 if (fiber_mode)
3906 digctrl_kx1 = 1;
3907 else
3908 digctrl_kx1 &= 0xff4a;
3909
3910 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3911 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1,
3912 digctrl_kx1);
3913
3914 /* Turn off parallel detect */
3915 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3916 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, &digctrl_kx2);
3917 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3918 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2,
3919 (digctrl_kx2 & ~(1<<2)));
3920
3921 /* Re-enable parallel detect */
3922 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3923 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2,
3924 (digctrl_kx2 | (1<<2)));
3925
3926 /* Enable autodet */
3927 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3928 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1,
3929 (digctrl_kx1 | 0x10));
3930}
3931
3932static void bnx2x_warpcore_reset_lane(struct bnx2x *bp,
3933 struct bnx2x_phy *phy,
3934 u8 reset)
3935{
3936 u16 val;
3937 /* Take lane out of reset after configuration is finished */
3938 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3939 MDIO_WC_REG_DIGITAL5_MISC6, &val);
3940 if (reset)
3941 val |= 0xC000;
3942 else
3943 val &= 0x3FFF;
3944 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3945 MDIO_WC_REG_DIGITAL5_MISC6, val);
3946 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3947 MDIO_WC_REG_DIGITAL5_MISC6, &val);
3948}
3949
3950
3951 /* Clear SFI/XFI link settings registers */
3952static void bnx2x_warpcore_clear_regs(struct bnx2x_phy *phy,
3953 struct link_params *params,
3954 u16 lane)
3955{
3956 struct bnx2x *bp = params->bp;
3957 u16 val16;
3958
3959 /* Set XFI clock comp as default. */
3960 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3961 MDIO_WC_REG_RX66_CONTROL, &val16);
3962 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3963 MDIO_WC_REG_RX66_CONTROL, val16 | (3<<13));
3964
3965 bnx2x_warpcore_reset_lane(bp, phy, 1);
3966 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0);
3967 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3968 MDIO_WC_REG_FX100_CTRL1, 0x014a);
3969 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3970 MDIO_WC_REG_FX100_CTRL3, 0x0800);
3971 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3972 MDIO_WC_REG_DIGITAL4_MISC3, 0x8008);
3973 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3974 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1, 0x0195);
3975 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3976 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, 0x0007);
3977 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3978 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X3, 0x0002);
3979 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3980 MDIO_WC_REG_SERDESDIGITAL_MISC1, 0x6000);
3981 lane = bnx2x_get_warpcore_lane(phy, params);
3982 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3983 MDIO_WC_REG_TX_FIR_TAP, 0x0000);
3984 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3985 MDIO_WC_REG_TX0_TX_DRIVER + 0x10*lane, 0x0990);
3986 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3987 MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x2040);
3988 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3989 MDIO_WC_REG_COMBO_IEEE0_MIICTRL, 0x0140);
3990 bnx2x_warpcore_reset_lane(bp, phy, 0);
3991}
3992
3993static int bnx2x_get_mod_abs_int_cfg(struct bnx2x *bp,
3994 u32 chip_id,
3995 u32 shmem_base, u8 port,
3996 u8 *gpio_num, u8 *gpio_port)
3997{
3998 u32 cfg_pin;
3999 *gpio_num = 0;
4000 *gpio_port = 0;
4001 if (CHIP_IS_E3(bp)) {
4002 cfg_pin = (REG_RD(bp, shmem_base +
4003 offsetof(struct shmem_region,
4004 dev_info.port_hw_config[port].e3_sfp_ctrl)) &
4005 PORT_HW_CFG_E3_MOD_ABS_MASK) >>
4006 PORT_HW_CFG_E3_MOD_ABS_SHIFT;
4007
4008 /*
4009 * Should not happen. This function called upon interrupt
4010 * triggered by GPIO ( since EPIO can only generate interrupts
4011 * to MCP).
4012 * So if this function was called and none of the GPIOs was set,
4013 * it means the shit hit the fan.
4014 */
4015 if ((cfg_pin < PIN_CFG_GPIO0_P0) ||
4016 (cfg_pin > PIN_CFG_GPIO3_P1)) {
4017 DP(NETIF_MSG_LINK, "ERROR: Invalid cfg pin %x for "
4018 "module detect indication\n",
4019 cfg_pin);
4020 return -EINVAL;
4021 }
4022
4023 *gpio_num = (cfg_pin - PIN_CFG_GPIO0_P0) & 0x3;
4024 *gpio_port = (cfg_pin - PIN_CFG_GPIO0_P0) >> 2;
4025 } else {
4026 *gpio_num = MISC_REGISTERS_GPIO_3;
4027 *gpio_port = port;
4028 }
4029 DP(NETIF_MSG_LINK, "MOD_ABS int GPIO%d_P%d\n", *gpio_num, *gpio_port);
4030 return 0;
4031}
4032
4033static int bnx2x_is_sfp_module_plugged(struct bnx2x_phy *phy,
4034 struct link_params *params)
4035{
4036 struct bnx2x *bp = params->bp;
4037 u8 gpio_num, gpio_port;
4038 u32 gpio_val;
4039 if (bnx2x_get_mod_abs_int_cfg(bp, params->chip_id,
4040 params->shmem_base, params->port,
4041 &gpio_num, &gpio_port) != 0)
4042 return 0;
4043 gpio_val = bnx2x_get_gpio(bp, gpio_num, gpio_port);
4044
4045 /* Call the handling function in case module is detected */
4046 if (gpio_val == 0)
4047 return 1;
4048 else
4049 return 0;
4050}
4051
4052static void bnx2x_warpcore_config_init(struct bnx2x_phy *phy,
4053 struct link_params *params,
4054 struct link_vars *vars)
4055{
4056 struct bnx2x *bp = params->bp;
4057 u32 serdes_net_if;
4058 u8 fiber_mode;
4059 u16 lane = bnx2x_get_warpcore_lane(phy, params);
4060 serdes_net_if = (REG_RD(bp, params->shmem_base +
4061 offsetof(struct shmem_region, dev_info.
4062 port_hw_config[params->port].default_cfg)) &
4063 PORT_HW_CFG_NET_SERDES_IF_MASK);
4064 DP(NETIF_MSG_LINK, "Begin Warpcore init, link_speed %d, "
4065 "serdes_net_if = 0x%x\n",
4066 vars->line_speed, serdes_net_if);
4067 bnx2x_set_aer_mmd(params, phy);
4068
4069 vars->phy_flags |= PHY_XGXS_FLAG;
4070 if ((serdes_net_if == PORT_HW_CFG_NET_SERDES_IF_SGMII) ||
4071 (phy->req_line_speed &&
4072 ((phy->req_line_speed == SPEED_100) ||
4073 (phy->req_line_speed == SPEED_10)))) {
4074 vars->phy_flags |= PHY_SGMII_FLAG;
4075 DP(NETIF_MSG_LINK, "Setting SGMII mode\n");
4076 bnx2x_warpcore_clear_regs(phy, params, lane);
4077 bnx2x_warpcore_set_sgmii_speed(phy, params, 0);
4078 } else {
4079 switch (serdes_net_if) {
4080 case PORT_HW_CFG_NET_SERDES_IF_KR:
4081 /* Enable KR Auto Neg */
4082 if (params->loopback_mode == LOOPBACK_NONE)
4083 bnx2x_warpcore_enable_AN_KR(phy, params, vars);
4084 else {
4085 DP(NETIF_MSG_LINK, "Setting KR 10G-Force\n");
4086 bnx2x_warpcore_set_10G_KR(phy, params, vars);
4087 }
4088 break;
4089
4090 case PORT_HW_CFG_NET_SERDES_IF_XFI:
4091 bnx2x_warpcore_clear_regs(phy, params, lane);
4092 if (vars->line_speed == SPEED_10000) {
4093 DP(NETIF_MSG_LINK, "Setting 10G XFI\n");
4094 bnx2x_warpcore_set_10G_XFI(phy, params, 1);
4095 } else {
4096 if (SINGLE_MEDIA_DIRECT(params)) {
4097 DP(NETIF_MSG_LINK, "1G Fiber\n");
4098 fiber_mode = 1;
4099 } else {
4100 DP(NETIF_MSG_LINK, "10/100/1G SGMII\n");
4101 fiber_mode = 0;
4102 }
4103 bnx2x_warpcore_set_sgmii_speed(phy,
4104 params,
4105 fiber_mode);
4106 }
4107
4108 break;
4109
4110 case PORT_HW_CFG_NET_SERDES_IF_SFI:
4111
4112 bnx2x_warpcore_clear_regs(phy, params, lane);
4113 if (vars->line_speed == SPEED_10000) {
4114 DP(NETIF_MSG_LINK, "Setting 10G SFI\n");
4115 bnx2x_warpcore_set_10G_XFI(phy, params, 0);
4116 } else if (vars->line_speed == SPEED_1000) {
4117 DP(NETIF_MSG_LINK, "Setting 1G Fiber\n");
4118 bnx2x_warpcore_set_sgmii_speed(phy, params, 1);
4119 }
4120 /* Issue Module detection */
4121 if (bnx2x_is_sfp_module_plugged(phy, params))
4122 bnx2x_sfp_module_detection(phy, params);
4123 break;
4124
4125 case PORT_HW_CFG_NET_SERDES_IF_DXGXS:
4126 if (vars->line_speed != SPEED_20000) {
4127 DP(NETIF_MSG_LINK, "Speed not supported yet\n");
4128 return;
4129 }
4130 DP(NETIF_MSG_LINK, "Setting 20G DXGXS\n");
4131 bnx2x_warpcore_set_20G_DXGXS(bp, phy, lane);
4132 /* Issue Module detection */
4133
4134 bnx2x_sfp_module_detection(phy, params);
4135 break;
4136
4137 case PORT_HW_CFG_NET_SERDES_IF_KR2:
4138 if (vars->line_speed != SPEED_20000) {
4139 DP(NETIF_MSG_LINK, "Speed not supported yet\n");
4140 return;
4141 }
4142 DP(NETIF_MSG_LINK, "Setting 20G KR2\n");
4143 bnx2x_warpcore_set_20G_KR2(bp, phy);
4144 break;
4145
4146 default:
4147 DP(NETIF_MSG_LINK, "Unsupported Serdes Net Interface "
4148 "0x%x\n", serdes_net_if);
4149 return;
4150 }
4151 }
4152
4153 /* Take lane out of reset after configuration is finished */
4154 bnx2x_warpcore_reset_lane(bp, phy, 0);
4155 DP(NETIF_MSG_LINK, "Exit config init\n");
4156}
4157
4158static void bnx2x_sfp_e3_set_transmitter(struct link_params *params,
4159 struct bnx2x_phy *phy,
4160 u8 tx_en)
4161{
4162 struct bnx2x *bp = params->bp;
4163 u32 cfg_pin;
4164 u8 port = params->port;
4165
4166 cfg_pin = REG_RD(bp, params->shmem_base +
4167 offsetof(struct shmem_region,
4168 dev_info.port_hw_config[port].e3_sfp_ctrl)) &
4169 PORT_HW_CFG_TX_LASER_MASK;
4170 /* Set the !tx_en since this pin is DISABLE_TX_LASER */
4171 DP(NETIF_MSG_LINK, "Setting WC TX to %d\n", tx_en);
4172 /* For 20G, the expected pin to be used is 3 pins after the current */
4173
4174 bnx2x_set_cfg_pin(bp, cfg_pin, tx_en ^ 1);
4175 if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_20G)
4176 bnx2x_set_cfg_pin(bp, cfg_pin + 3, tx_en ^ 1);
4177}
4178
4179static void bnx2x_warpcore_link_reset(struct bnx2x_phy *phy,
4180 struct link_params *params)
4181{
4182 struct bnx2x *bp = params->bp;
4183 u16 val16;
4184 bnx2x_sfp_e3_set_transmitter(params, phy, 0);
4185 bnx2x_set_mdio_clk(bp, params->chip_id, params->port);
4186 bnx2x_set_aer_mmd(params, phy);
4187 /* Global register */
4188 bnx2x_warpcore_reset_lane(bp, phy, 1);
4189
4190 /* Clear loopback settings (if any) */
4191 /* 10G & 20G */
4192 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
4193 MDIO_WC_REG_COMBO_IEEE0_MIICTRL, &val16);
4194 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4195 MDIO_WC_REG_COMBO_IEEE0_MIICTRL, val16 &
4196 0xBFFF);
4197
4198 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
4199 MDIO_WC_REG_IEEE0BLK_MIICNTL, &val16);
4200 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4201 MDIO_WC_REG_IEEE0BLK_MIICNTL, val16 & 0xfffe);
4202
4203 /* Update those 1-copy registers */
4204 CL22_WR_OVER_CL45(bp, phy, MDIO_REG_BANK_AER_BLOCK,
4205 MDIO_AER_BLOCK_AER_REG, 0);
4206 /* Enable 1G MDIO (1-copy) */
4207 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
4208 MDIO_WC_REG_XGXSBLK0_XGXSCONTROL,
4209 &val16);
4210 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4211 MDIO_WC_REG_XGXSBLK0_XGXSCONTROL,
4212 val16 & ~0x10);
4213
4214 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
4215 MDIO_WC_REG_XGXSBLK1_LANECTRL2, &val16);
4216 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4217 MDIO_WC_REG_XGXSBLK1_LANECTRL2,
4218 val16 & 0xff00);
4219
4220}
4221
4222static void bnx2x_set_warpcore_loopback(struct bnx2x_phy *phy,
4223 struct link_params *params)
4224{
4225 struct bnx2x *bp = params->bp;
4226 u16 val16;
4227 u32 lane;
4228 DP(NETIF_MSG_LINK, "Setting Warpcore loopback type %x, speed %d\n",
4229 params->loopback_mode, phy->req_line_speed);
4230
4231 if (phy->req_line_speed < SPEED_10000) {
4232 /* 10/100/1000 */
4233
4234 /* Update those 1-copy registers */
4235 CL22_WR_OVER_CL45(bp, phy, MDIO_REG_BANK_AER_BLOCK,
4236 MDIO_AER_BLOCK_AER_REG, 0);
4237 /* Enable 1G MDIO (1-copy) */
4238 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
4239 MDIO_WC_REG_XGXSBLK0_XGXSCONTROL,
4240 &val16);
4241 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4242 MDIO_WC_REG_XGXSBLK0_XGXSCONTROL,
4243 val16 | 0x10);
4244 /* Set 1G loopback based on lane (1-copy) */
4245 lane = bnx2x_get_warpcore_lane(phy, params);
4246 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
4247 MDIO_WC_REG_XGXSBLK1_LANECTRL2, &val16);
4248 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4249 MDIO_WC_REG_XGXSBLK1_LANECTRL2,
4250 val16 | (1<<lane));
4251
4252 /* Switch back to 4-copy registers */
4253 bnx2x_set_aer_mmd(params, phy);
4254 /* Global loopback, not recommended. */
4255 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
4256 MDIO_WC_REG_COMBO_IEEE0_MIICTRL, &val16);
4257 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4258 MDIO_WC_REG_COMBO_IEEE0_MIICTRL, val16 |
4259 0x4000);
4260 } else {
4261 /* 10G & 20G */
4262 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
4263 MDIO_WC_REG_COMBO_IEEE0_MIICTRL, &val16);
4264 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4265 MDIO_WC_REG_COMBO_IEEE0_MIICTRL, val16 |
4266 0x4000);
4267
4268 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
4269 MDIO_WC_REG_IEEE0BLK_MIICNTL, &val16);
4270 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4271 MDIO_WC_REG_IEEE0BLK_MIICNTL, val16 | 0x1);
4272 }
4273}
4274
4275
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004276void bnx2x_link_status_update(struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004277 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004278{
4279 struct bnx2x *bp = params->bp;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00004280 u8 link_10g_plus;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004281 u8 port = params->port;
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00004282 u32 sync_offset, media_types;
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00004283 /* Update PHY configuration */
4284 set_phy_vars(params, vars);
4285
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004286 vars->link_status = REG_RD(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004287 offsetof(struct shmem_region,
4288 port_mb[port].link_status));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004289
4290 vars->link_up = (vars->link_status & LINK_STATUS_LINK_UP);
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00004291 vars->phy_flags = PHY_XGXS_FLAG;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004292 if (vars->link_up) {
4293 DP(NETIF_MSG_LINK, "phy link up\n");
4294
4295 vars->phy_link_up = 1;
4296 vars->duplex = DUPLEX_FULL;
4297 switch (vars->link_status &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004298 LINK_STATUS_SPEED_AND_DUPLEX_MASK) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004299 case LINK_10THD:
4300 vars->duplex = DUPLEX_HALF;
4301 /* fall thru */
4302 case LINK_10TFD:
4303 vars->line_speed = SPEED_10;
4304 break;
4305
4306 case LINK_100TXHD:
4307 vars->duplex = DUPLEX_HALF;
4308 /* fall thru */
4309 case LINK_100T4:
4310 case LINK_100TXFD:
4311 vars->line_speed = SPEED_100;
4312 break;
4313
4314 case LINK_1000THD:
4315 vars->duplex = DUPLEX_HALF;
4316 /* fall thru */
4317 case LINK_1000TFD:
4318 vars->line_speed = SPEED_1000;
4319 break;
4320
4321 case LINK_2500THD:
4322 vars->duplex = DUPLEX_HALF;
4323 /* fall thru */
4324 case LINK_2500TFD:
4325 vars->line_speed = SPEED_2500;
4326 break;
4327
4328 case LINK_10GTFD:
4329 vars->line_speed = SPEED_10000;
4330 break;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004331 case LINK_20GTFD:
4332 vars->line_speed = SPEED_20000;
4333 break;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004334 default:
4335 break;
4336 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004337 vars->flow_ctrl = 0;
4338 if (vars->link_status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED)
4339 vars->flow_ctrl |= BNX2X_FLOW_CTRL_TX;
4340
4341 if (vars->link_status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED)
4342 vars->flow_ctrl |= BNX2X_FLOW_CTRL_RX;
4343
4344 if (!vars->flow_ctrl)
4345 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
4346
4347 if (vars->line_speed &&
4348 ((vars->line_speed == SPEED_10) ||
4349 (vars->line_speed == SPEED_100))) {
4350 vars->phy_flags |= PHY_SGMII_FLAG;
4351 } else {
4352 vars->phy_flags &= ~PHY_SGMII_FLAG;
4353 }
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004354 if (vars->line_speed &&
4355 USES_WARPCORE(bp) &&
4356 (vars->line_speed == SPEED_1000))
4357 vars->phy_flags |= PHY_SGMII_FLAG;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004358 /* anything 10 and over uses the bmac */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00004359 link_10g_plus = (vars->line_speed >= SPEED_10000);
4360
4361 if (link_10g_plus) {
4362 if (USES_WARPCORE(bp))
4363 vars->mac_type = MAC_TYPE_XMAC;
4364 else
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004365 vars->mac_type = MAC_TYPE_BMAC;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00004366 } else {
4367 if (USES_WARPCORE(bp))
4368 vars->mac_type = MAC_TYPE_UMAC;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004369 else
4370 vars->mac_type = MAC_TYPE_EMAC;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00004371 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004372 } else { /* link down */
4373 DP(NETIF_MSG_LINK, "phy link down\n");
4374
4375 vars->phy_link_up = 0;
4376
4377 vars->line_speed = 0;
4378 vars->duplex = DUPLEX_FULL;
4379 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
4380
4381 /* indicate no mac active */
4382 vars->mac_type = MAC_TYPE_NONE;
4383 }
4384
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00004385 /* Sync media type */
4386 sync_offset = params->shmem_base +
4387 offsetof(struct shmem_region,
4388 dev_info.port_hw_config[port].media_type);
4389 media_types = REG_RD(bp, sync_offset);
4390
4391 params->phy[INT_PHY].media_type =
4392 (media_types & PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK) >>
4393 PORT_HW_CFG_MEDIA_TYPE_PHY0_SHIFT;
4394 params->phy[EXT_PHY1].media_type =
4395 (media_types & PORT_HW_CFG_MEDIA_TYPE_PHY1_MASK) >>
4396 PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT;
4397 params->phy[EXT_PHY2].media_type =
4398 (media_types & PORT_HW_CFG_MEDIA_TYPE_PHY2_MASK) >>
4399 PORT_HW_CFG_MEDIA_TYPE_PHY2_SHIFT;
4400 DP(NETIF_MSG_LINK, "media_types = 0x%x\n", media_types);
4401
Yaniv Rosner020c7e32011-05-31 21:28:43 +00004402 /* Sync AEU offset */
4403 sync_offset = params->shmem_base +
4404 offsetof(struct shmem_region,
4405 dev_info.port_hw_config[port].aeu_int_mask);
4406
4407 vars->aeu_int_mask = REG_RD(bp, sync_offset);
4408
4409 DP(NETIF_MSG_LINK, "link_status 0x%x phy_link_up %x int_mask 0x%x\n",
4410 vars->link_status, vars->phy_link_up, vars->aeu_int_mask);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004411 DP(NETIF_MSG_LINK, "line_speed %x duplex %x flow_ctrl 0x%x\n",
4412 vars->line_speed, vars->duplex, vars->flow_ctrl);
4413}
4414
4415
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004416static void bnx2x_set_master_ln(struct link_params *params,
4417 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004418{
4419 struct bnx2x *bp = params->bp;
4420 u16 new_master_ln, ser_lane;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004421 ser_lane = ((params->lane_config &
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004422 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004423 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004424
4425 /* set the master_ln for AN */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004426 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004427 MDIO_REG_BANK_XGXS_BLOCK2,
4428 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
4429 &new_master_ln);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004430
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004431 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004432 MDIO_REG_BANK_XGXS_BLOCK2 ,
4433 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
4434 (new_master_ln | ser_lane));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004435}
4436
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00004437static int bnx2x_reset_unicore(struct link_params *params,
4438 struct bnx2x_phy *phy,
4439 u8 set_serdes)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004440{
4441 struct bnx2x *bp = params->bp;
4442 u16 mii_control;
4443 u16 i;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004444 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004445 MDIO_REG_BANK_COMBO_IEEE0,
4446 MDIO_COMBO_IEEE0_MII_CONTROL, &mii_control);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004447
4448 /* reset the unicore */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004449 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004450 MDIO_REG_BANK_COMBO_IEEE0,
4451 MDIO_COMBO_IEEE0_MII_CONTROL,
4452 (mii_control |
4453 MDIO_COMBO_IEEO_MII_CONTROL_RESET));
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004454 if (set_serdes)
4455 bnx2x_set_serdes_access(bp, params->port);
Eilon Greensteinc1b73992009-02-12 08:37:07 +00004456
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004457 /* wait for the reset to self clear */
4458 for (i = 0; i < MDIO_ACCESS_TIMEOUT; i++) {
4459 udelay(5);
4460
4461 /* the reset erased the previous bank value */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004462 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004463 MDIO_REG_BANK_COMBO_IEEE0,
4464 MDIO_COMBO_IEEE0_MII_CONTROL,
4465 &mii_control);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004466
4467 if (!(mii_control & MDIO_COMBO_IEEO_MII_CONTROL_RESET)) {
4468 udelay(5);
4469 return 0;
4470 }
4471 }
4472
Yaniv Rosner6d870c32011-01-31 04:22:20 +00004473 netdev_err(bp->dev, "Warning: PHY was not initialized,"
4474 " Port %d\n",
4475 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004476 DP(NETIF_MSG_LINK, "BUG! XGXS is still in reset!\n");
4477 return -EINVAL;
4478
4479}
4480
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004481static void bnx2x_set_swap_lanes(struct link_params *params,
4482 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004483{
4484 struct bnx2x *bp = params->bp;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004485 /*
4486 * Each two bits represents a lane number:
4487 * No swap is 0123 => 0x1b no need to enable the swap
4488 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004489 u16 ser_lane, rx_lane_swap, tx_lane_swap;
4490
4491 ser_lane = ((params->lane_config &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004492 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
4493 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004494 rx_lane_swap = ((params->lane_config &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004495 PORT_HW_CFG_LANE_SWAP_CFG_RX_MASK) >>
4496 PORT_HW_CFG_LANE_SWAP_CFG_RX_SHIFT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004497 tx_lane_swap = ((params->lane_config &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004498 PORT_HW_CFG_LANE_SWAP_CFG_TX_MASK) >>
4499 PORT_HW_CFG_LANE_SWAP_CFG_TX_SHIFT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004500
4501 if (rx_lane_swap != 0x1b) {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004502 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004503 MDIO_REG_BANK_XGXS_BLOCK2,
4504 MDIO_XGXS_BLOCK2_RX_LN_SWAP,
4505 (rx_lane_swap |
4506 MDIO_XGXS_BLOCK2_RX_LN_SWAP_ENABLE |
4507 MDIO_XGXS_BLOCK2_RX_LN_SWAP_FORCE_ENABLE));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004508 } else {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004509 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004510 MDIO_REG_BANK_XGXS_BLOCK2,
4511 MDIO_XGXS_BLOCK2_RX_LN_SWAP, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004512 }
4513
4514 if (tx_lane_swap != 0x1b) {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004515 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004516 MDIO_REG_BANK_XGXS_BLOCK2,
4517 MDIO_XGXS_BLOCK2_TX_LN_SWAP,
4518 (tx_lane_swap |
4519 MDIO_XGXS_BLOCK2_TX_LN_SWAP_ENABLE));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004520 } else {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004521 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004522 MDIO_REG_BANK_XGXS_BLOCK2,
4523 MDIO_XGXS_BLOCK2_TX_LN_SWAP, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004524 }
4525}
4526
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004527static void bnx2x_set_parallel_detection(struct bnx2x_phy *phy,
4528 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004529{
4530 struct bnx2x *bp = params->bp;
4531 u16 control2;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004532 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004533 MDIO_REG_BANK_SERDES_DIGITAL,
4534 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
4535 &control2);
Yaniv Rosner7aa07112010-09-07 11:41:01 +00004536 if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
Yaniv Rosner18afb0a2009-11-05 19:18:04 +02004537 control2 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
4538 else
4539 control2 &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00004540 DP(NETIF_MSG_LINK, "phy->speed_cap_mask = 0x%x, control2 = 0x%x\n",
4541 phy->speed_cap_mask, control2);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004542 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004543 MDIO_REG_BANK_SERDES_DIGITAL,
4544 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
4545 control2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004546
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004547 if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00004548 (phy->speed_cap_mask &
Yaniv Rosner18afb0a2009-11-05 19:18:04 +02004549 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004550 DP(NETIF_MSG_LINK, "XGXS\n");
4551
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004552 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004553 MDIO_REG_BANK_10G_PARALLEL_DETECT,
4554 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK,
4555 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004556
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004557 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004558 MDIO_REG_BANK_10G_PARALLEL_DETECT,
4559 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
4560 &control2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004561
4562
4563 control2 |=
4564 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN;
4565
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004566 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004567 MDIO_REG_BANK_10G_PARALLEL_DETECT,
4568 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
4569 control2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004570
4571 /* Disable parallel detection of HiG */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004572 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004573 MDIO_REG_BANK_XGXS_BLOCK2,
4574 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G,
4575 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_CX4_XGXS |
4576 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_HIGIG_XGXS);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004577 }
4578}
4579
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004580static void bnx2x_set_autoneg(struct bnx2x_phy *phy,
4581 struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004582 struct link_vars *vars,
4583 u8 enable_cl73)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004584{
4585 struct bnx2x *bp = params->bp;
4586 u16 reg_val;
4587
4588 /* CL37 Autoneg */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004589 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004590 MDIO_REG_BANK_COMBO_IEEE0,
4591 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004592
4593 /* CL37 Autoneg Enabled */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07004594 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004595 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_AN_EN;
4596 else /* CL37 Autoneg Disabled */
4597 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
4598 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN);
4599
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004600 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004601 MDIO_REG_BANK_COMBO_IEEE0,
4602 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004603
4604 /* Enable/Disable Autodetection */
4605
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004606 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004607 MDIO_REG_BANK_SERDES_DIGITAL,
4608 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, &reg_val);
Eilon Greenstein239d6862009-08-12 08:23:04 +00004609 reg_val &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN |
4610 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT);
4611 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07004612 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004613 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
4614 else
4615 reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
4616
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004617 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004618 MDIO_REG_BANK_SERDES_DIGITAL,
4619 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004620
4621 /* Enable TetonII and BAM autoneg */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004622 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004623 MDIO_REG_BANK_BAM_NEXT_PAGE,
4624 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004625 &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07004626 if (vars->line_speed == SPEED_AUTO_NEG) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004627 /* Enable BAM aneg Mode and TetonII aneg Mode */
4628 reg_val |= (MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
4629 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
4630 } else {
4631 /* TetonII and BAM Autoneg Disabled */
4632 reg_val &= ~(MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
4633 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
4634 }
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004635 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004636 MDIO_REG_BANK_BAM_NEXT_PAGE,
4637 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
4638 reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004639
Eilon Greenstein239d6862009-08-12 08:23:04 +00004640 if (enable_cl73) {
4641 /* Enable Cl73 FSM status bits */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004642 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004643 MDIO_REG_BANK_CL73_USERB0,
4644 MDIO_CL73_USERB0_CL73_UCTRL,
4645 0xe);
Eilon Greenstein239d6862009-08-12 08:23:04 +00004646
4647 /* Enable BAM Station Manager*/
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004648 CL22_WR_OVER_CL45(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00004649 MDIO_REG_BANK_CL73_USERB0,
4650 MDIO_CL73_USERB0_CL73_BAM_CTRL1,
4651 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN |
4652 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_STATION_MNGR_EN |
4653 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN);
4654
Yaniv Rosner7846e472009-11-05 19:18:07 +02004655 /* Advertise CL73 link speeds */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004656 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004657 MDIO_REG_BANK_CL73_IEEEB1,
4658 MDIO_CL73_IEEEB1_AN_ADV2,
4659 &reg_val);
Yaniv Rosner7aa07112010-09-07 11:41:01 +00004660 if (phy->speed_cap_mask &
Yaniv Rosner7846e472009-11-05 19:18:07 +02004661 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
4662 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00004663 if (phy->speed_cap_mask &
Yaniv Rosner7846e472009-11-05 19:18:07 +02004664 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
4665 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX;
Eilon Greenstein239d6862009-08-12 08:23:04 +00004666
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004667 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004668 MDIO_REG_BANK_CL73_IEEEB1,
4669 MDIO_CL73_IEEEB1_AN_ADV2,
4670 reg_val);
Eilon Greenstein239d6862009-08-12 08:23:04 +00004671
Eilon Greenstein239d6862009-08-12 08:23:04 +00004672 /* CL73 Autoneg Enabled */
4673 reg_val = MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN;
4674
4675 } else /* CL73 Autoneg Disabled */
4676 reg_val = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004677
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004678 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004679 MDIO_REG_BANK_CL73_IEEEB0,
4680 MDIO_CL73_IEEEB0_CL73_AN_CONTROL, reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004681}
4682
4683/* program SerDes, forced speed */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004684static void bnx2x_program_serdes(struct bnx2x_phy *phy,
4685 struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004686 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004687{
4688 struct bnx2x *bp = params->bp;
4689 u16 reg_val;
4690
Eilon Greenstein57937202009-08-12 08:23:53 +00004691 /* program duplex, disable autoneg and sgmii*/
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004692 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004693 MDIO_REG_BANK_COMBO_IEEE0,
4694 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004695 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX |
Eilon Greenstein57937202009-08-12 08:23:53 +00004696 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
4697 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK);
Yaniv Rosner7aa07112010-09-07 11:41:01 +00004698 if (phy->req_duplex == DUPLEX_FULL)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004699 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004700 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004701 MDIO_REG_BANK_COMBO_IEEE0,
4702 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004703
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004704 /*
4705 * program speed
4706 * - needed only if the speed is greater than 1G (2.5G or 10G)
4707 */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004708 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004709 MDIO_REG_BANK_SERDES_DIGITAL,
4710 MDIO_SERDES_DIGITAL_MISC1, &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07004711 /* clearing the speed value before setting the right speed */
4712 DP(NETIF_MSG_LINK, "MDIO_REG_BANK_SERDES_DIGITAL = 0x%x\n", reg_val);
4713
4714 reg_val &= ~(MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_MASK |
4715 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
4716
4717 if (!((vars->line_speed == SPEED_1000) ||
4718 (vars->line_speed == SPEED_100) ||
4719 (vars->line_speed == SPEED_10))) {
4720
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004721 reg_val |= (MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_156_25M |
4722 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07004723 if (vars->line_speed == SPEED_10000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004724 reg_val |=
4725 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_10G_CX4;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07004726 }
4727
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004728 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004729 MDIO_REG_BANK_SERDES_DIGITAL,
4730 MDIO_SERDES_DIGITAL_MISC1, reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07004731
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004732}
4733
Yaniv Rosner9045f6b2011-05-31 21:28:27 +00004734static void bnx2x_set_brcm_cl37_advertisement(struct bnx2x_phy *phy,
4735 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004736{
4737 struct bnx2x *bp = params->bp;
4738 u16 val = 0;
4739
4740 /* configure the 48 bits for BAM AN */
4741
4742 /* set extended capabilities */
Yaniv Rosner7aa07112010-09-07 11:41:01 +00004743 if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004744 val |= MDIO_OVER_1G_UP1_2_5G;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00004745 if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004746 val |= MDIO_OVER_1G_UP1_10G;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004747 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004748 MDIO_REG_BANK_OVER_1G,
4749 MDIO_OVER_1G_UP1, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004750
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004751 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004752 MDIO_REG_BANK_OVER_1G,
4753 MDIO_OVER_1G_UP3, 0x400);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004754}
4755
Yaniv Rosner9045f6b2011-05-31 21:28:27 +00004756static void bnx2x_set_ieee_aneg_advertisement(struct bnx2x_phy *phy,
4757 struct link_params *params,
4758 u16 ieee_fc)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07004759{
4760 struct bnx2x *bp = params->bp;
Yaniv Rosner7846e472009-11-05 19:18:07 +02004761 u16 val;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07004762 /* for AN, we are always publishing full duplex */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004763
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004764 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004765 MDIO_REG_BANK_COMBO_IEEE0,
4766 MDIO_COMBO_IEEE0_AUTO_NEG_ADV, ieee_fc);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004767 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004768 MDIO_REG_BANK_CL73_IEEEB1,
4769 MDIO_CL73_IEEEB1_AN_ADV1, &val);
Yaniv Rosner7846e472009-11-05 19:18:07 +02004770 val &= ~MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_BOTH;
4771 val |= ((ieee_fc<<3) & MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004772 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004773 MDIO_REG_BANK_CL73_IEEEB1,
4774 MDIO_CL73_IEEEB1_AN_ADV1, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004775}
4776
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004777static void bnx2x_restart_autoneg(struct bnx2x_phy *phy,
4778 struct link_params *params,
4779 u8 enable_cl73)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004780{
4781 struct bnx2x *bp = params->bp;
Eilon Greenstein3a36f2e2009-02-12 08:37:09 +00004782 u16 mii_control;
Eilon Greenstein239d6862009-08-12 08:23:04 +00004783
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004784 DP(NETIF_MSG_LINK, "bnx2x_restart_autoneg\n");
Eilon Greenstein3a36f2e2009-02-12 08:37:09 +00004785 /* Enable and restart BAM/CL37 aneg */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004786
Eilon Greenstein239d6862009-08-12 08:23:04 +00004787 if (enable_cl73) {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004788 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004789 MDIO_REG_BANK_CL73_IEEEB0,
4790 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
4791 &mii_control);
Eilon Greenstein239d6862009-08-12 08:23:04 +00004792
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004793 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004794 MDIO_REG_BANK_CL73_IEEEB0,
4795 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
4796 (mii_control |
4797 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN |
4798 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN));
Eilon Greenstein239d6862009-08-12 08:23:04 +00004799 } else {
4800
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004801 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004802 MDIO_REG_BANK_COMBO_IEEE0,
4803 MDIO_COMBO_IEEE0_MII_CONTROL,
4804 &mii_control);
Eilon Greenstein239d6862009-08-12 08:23:04 +00004805 DP(NETIF_MSG_LINK,
4806 "bnx2x_restart_autoneg mii_control before = 0x%x\n",
4807 mii_control);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004808 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004809 MDIO_REG_BANK_COMBO_IEEE0,
4810 MDIO_COMBO_IEEE0_MII_CONTROL,
4811 (mii_control |
4812 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
4813 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN));
Eilon Greenstein239d6862009-08-12 08:23:04 +00004814 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004815}
4816
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004817static void bnx2x_initialize_sgmii_process(struct bnx2x_phy *phy,
4818 struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004819 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004820{
4821 struct bnx2x *bp = params->bp;
4822 u16 control1;
4823
4824 /* in SGMII mode, the unicore is always slave */
4825
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004826 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004827 MDIO_REG_BANK_SERDES_DIGITAL,
4828 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
4829 &control1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004830 control1 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT;
4831 /* set sgmii mode (and not fiber) */
4832 control1 &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE |
4833 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET |
4834 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_MSTR_MODE);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004835 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004836 MDIO_REG_BANK_SERDES_DIGITAL,
4837 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
4838 control1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004839
4840 /* if forced speed */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07004841 if (!(vars->line_speed == SPEED_AUTO_NEG)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004842 /* set speed, disable autoneg */
4843 u16 mii_control;
4844
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004845 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004846 MDIO_REG_BANK_COMBO_IEEE0,
4847 MDIO_COMBO_IEEE0_MII_CONTROL,
4848 &mii_control);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004849 mii_control &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
4850 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK|
4851 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX);
4852
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07004853 switch (vars->line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004854 case SPEED_100:
4855 mii_control |=
4856 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_100;
4857 break;
4858 case SPEED_1000:
4859 mii_control |=
4860 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_1000;
4861 break;
4862 case SPEED_10:
4863 /* there is nothing to set for 10M */
4864 break;
4865 default:
4866 /* invalid speed for SGMII */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07004867 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
4868 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004869 break;
4870 }
4871
4872 /* setting the full duplex */
Yaniv Rosner7aa07112010-09-07 11:41:01 +00004873 if (phy->req_duplex == DUPLEX_FULL)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004874 mii_control |=
4875 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004876 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004877 MDIO_REG_BANK_COMBO_IEEE0,
4878 MDIO_COMBO_IEEE0_MII_CONTROL,
4879 mii_control);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004880
4881 } else { /* AN mode */
4882 /* enable and restart AN */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004883 bnx2x_restart_autoneg(phy, params, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004884 }
4885}
4886
4887
4888/*
4889 * link management
4890 */
4891
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00004892static int bnx2x_direct_parallel_detect_used(struct bnx2x_phy *phy,
4893 struct link_params *params)
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02004894{
4895 struct bnx2x *bp = params->bp;
4896 u16 pd_10g, status2_1000x;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00004897 if (phy->req_line_speed != SPEED_AUTO_NEG)
4898 return 0;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004899 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004900 MDIO_REG_BANK_SERDES_DIGITAL,
4901 MDIO_SERDES_DIGITAL_A_1000X_STATUS2,
4902 &status2_1000x);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004903 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004904 MDIO_REG_BANK_SERDES_DIGITAL,
4905 MDIO_SERDES_DIGITAL_A_1000X_STATUS2,
4906 &status2_1000x);
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02004907 if (status2_1000x & MDIO_SERDES_DIGITAL_A_1000X_STATUS2_AN_DISABLED) {
4908 DP(NETIF_MSG_LINK, "1G parallel detect link on port %d\n",
4909 params->port);
4910 return 1;
4911 }
4912
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004913 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004914 MDIO_REG_BANK_10G_PARALLEL_DETECT,
4915 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_STATUS,
4916 &pd_10g);
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02004917
4918 if (pd_10g & MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_STATUS_PD_LINK) {
4919 DP(NETIF_MSG_LINK, "10G parallel detect link on port %d\n",
4920 params->port);
4921 return 1;
4922 }
4923 return 0;
4924}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004925
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004926static void bnx2x_flow_ctrl_resolve(struct bnx2x_phy *phy,
4927 struct link_params *params,
4928 struct link_vars *vars,
4929 u32 gp_status)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004930{
4931 struct bnx2x *bp = params->bp;
Eilon Greenstein3196a882008-08-13 15:58:49 -07004932 u16 ld_pause; /* local driver */
4933 u16 lp_pause; /* link partner */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004934 u16 pause_result;
4935
David S. Millerc0700f92008-12-16 23:53:20 -08004936 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004937
4938 /* resolve from gp_status in case of AN complete and not sgmii */
Yaniv Rosner7aa07112010-09-07 11:41:01 +00004939 if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO)
4940 vars->flow_ctrl = phy->req_flow_ctrl;
4941 else if (phy->req_line_speed != SPEED_AUTO_NEG)
4942 vars->flow_ctrl = params->req_fc_auto_adv;
4943 else if ((gp_status & MDIO_AN_CL73_OR_37_COMPLETE) &&
4944 (!(vars->phy_flags & PHY_SGMII_FLAG))) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004945 if (bnx2x_direct_parallel_detect_used(phy, params)) {
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02004946 vars->flow_ctrl = params->req_fc_auto_adv;
4947 return;
4948 }
Yaniv Rosner7846e472009-11-05 19:18:07 +02004949 if ((gp_status &
4950 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
4951 MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) ==
4952 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
4953 MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) {
4954
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004955 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004956 MDIO_REG_BANK_CL73_IEEEB1,
4957 MDIO_CL73_IEEEB1_AN_ADV1,
4958 &ld_pause);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004959 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004960 MDIO_REG_BANK_CL73_IEEEB1,
4961 MDIO_CL73_IEEEB1_AN_LP_ADV1,
4962 &lp_pause);
Yaniv Rosner7846e472009-11-05 19:18:07 +02004963 pause_result = (ld_pause &
4964 MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK)
4965 >> 8;
4966 pause_result |= (lp_pause &
4967 MDIO_CL73_IEEEB1_AN_LP_ADV1_PAUSE_MASK)
4968 >> 10;
4969 DP(NETIF_MSG_LINK, "pause_result CL73 0x%x\n",
4970 pause_result);
4971 } else {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004972 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004973 MDIO_REG_BANK_COMBO_IEEE0,
4974 MDIO_COMBO_IEEE0_AUTO_NEG_ADV,
4975 &ld_pause);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004976 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004977 MDIO_REG_BANK_COMBO_IEEE0,
4978 MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1,
4979 &lp_pause);
Yaniv Rosner7846e472009-11-05 19:18:07 +02004980 pause_result = (ld_pause &
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004981 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>5;
Yaniv Rosner7846e472009-11-05 19:18:07 +02004982 pause_result |= (lp_pause &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004983 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7;
Yaniv Rosner7846e472009-11-05 19:18:07 +02004984 DP(NETIF_MSG_LINK, "pause_result CL37 0x%x\n",
4985 pause_result);
4986 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004987 bnx2x_pause_resolve(vars, pause_result);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004988 }
4989 DP(NETIF_MSG_LINK, "flow_ctrl 0x%x\n", vars->flow_ctrl);
4990}
4991
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004992static void bnx2x_check_fallback_to_cl37(struct bnx2x_phy *phy,
4993 struct link_params *params)
Eilon Greenstein239d6862009-08-12 08:23:04 +00004994{
4995 struct bnx2x *bp = params->bp;
Yaniv Rosner9045f6b2011-05-31 21:28:27 +00004996 u16 rx_status, ustat_val, cl37_fsm_received;
Eilon Greenstein239d6862009-08-12 08:23:04 +00004997 DP(NETIF_MSG_LINK, "bnx2x_check_fallback_to_cl37\n");
4998 /* Step 1: Make sure signal is detected */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004999 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005000 MDIO_REG_BANK_RX0,
5001 MDIO_RX0_RX_STATUS,
5002 &rx_status);
Eilon Greenstein239d6862009-08-12 08:23:04 +00005003 if ((rx_status & MDIO_RX0_RX_STATUS_SIGDET) !=
5004 (MDIO_RX0_RX_STATUS_SIGDET)) {
5005 DP(NETIF_MSG_LINK, "Signal is not detected. Restoring CL73."
5006 "rx_status(0x80b0) = 0x%x\n", rx_status);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00005007 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005008 MDIO_REG_BANK_CL73_IEEEB0,
5009 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
5010 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN);
Eilon Greenstein239d6862009-08-12 08:23:04 +00005011 return;
5012 }
5013 /* Step 2: Check CL73 state machine */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00005014 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005015 MDIO_REG_BANK_CL73_USERB0,
5016 MDIO_CL73_USERB0_CL73_USTAT1,
5017 &ustat_val);
Eilon Greenstein239d6862009-08-12 08:23:04 +00005018 if ((ustat_val &
5019 (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK |
5020 MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) !=
5021 (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK |
5022 MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) {
5023 DP(NETIF_MSG_LINK, "CL73 state-machine is not stable. "
5024 "ustat_val(0x8371) = 0x%x\n", ustat_val);
5025 return;
5026 }
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005027 /*
5028 * Step 3: Check CL37 Message Pages received to indicate LP
5029 * supports only CL37
5030 */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00005031 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005032 MDIO_REG_BANK_REMOTE_PHY,
5033 MDIO_REMOTE_PHY_MISC_RX_STATUS,
Yaniv Rosner9045f6b2011-05-31 21:28:27 +00005034 &cl37_fsm_received);
5035 if ((cl37_fsm_received &
Eilon Greenstein239d6862009-08-12 08:23:04 +00005036 (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG |
5037 MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) !=
5038 (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG |
5039 MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) {
5040 DP(NETIF_MSG_LINK, "No CL37 FSM were received. "
5041 "misc_rx_status(0x8330) = 0x%x\n",
Yaniv Rosner9045f6b2011-05-31 21:28:27 +00005042 cl37_fsm_received);
Eilon Greenstein239d6862009-08-12 08:23:04 +00005043 return;
5044 }
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005045 /*
5046 * The combined cl37/cl73 fsm state information indicating that
5047 * we are connected to a device which does not support cl73, but
5048 * does support cl37 BAM. In this case we disable cl73 and
5049 * restart cl37 auto-neg
5050 */
5051
Eilon Greenstein239d6862009-08-12 08:23:04 +00005052 /* Disable CL73 */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00005053 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005054 MDIO_REG_BANK_CL73_IEEEB0,
5055 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
5056 0);
Eilon Greenstein239d6862009-08-12 08:23:04 +00005057 /* Restart CL37 autoneg */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005058 bnx2x_restart_autoneg(phy, params, 0);
Eilon Greenstein239d6862009-08-12 08:23:04 +00005059 DP(NETIF_MSG_LINK, "Disabling CL73, and restarting CL37 autoneg\n");
5060}
Yaniv Rosner7aa07112010-09-07 11:41:01 +00005061
5062static void bnx2x_xgxs_an_resolve(struct bnx2x_phy *phy,
5063 struct link_params *params,
5064 struct link_vars *vars,
5065 u32 gp_status)
5066{
5067 if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE)
5068 vars->link_status |=
5069 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
5070
5071 if (bnx2x_direct_parallel_detect_used(phy, params))
5072 vars->link_status |=
5073 LINK_STATUS_PARALLEL_DETECTION_USED;
5074}
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005075static int bnx2x_get_link_speed_duplex(struct bnx2x_phy *phy,
5076 struct link_params *params,
5077 struct link_vars *vars,
5078 u16 is_link_up,
5079 u16 speed_mask,
5080 u16 is_duplex)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005081{
5082 struct bnx2x *bp = params->bp;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00005083 if (phy->req_line_speed == SPEED_AUTO_NEG)
5084 vars->link_status |= LINK_STATUS_AUTO_NEGOTIATE_ENABLED;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005085 if (is_link_up) {
5086 DP(NETIF_MSG_LINK, "phy link up\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005087
5088 vars->phy_link_up = 1;
5089 vars->link_status |= LINK_STATUS_LINK_UP;
5090
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005091 switch (speed_mask) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005092 case GP_STATUS_10M:
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005093 vars->line_speed = SPEED_10;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005094 if (vars->duplex == DUPLEX_FULL)
5095 vars->link_status |= LINK_10TFD;
5096 else
5097 vars->link_status |= LINK_10THD;
5098 break;
5099
5100 case GP_STATUS_100M:
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005101 vars->line_speed = SPEED_100;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005102 if (vars->duplex == DUPLEX_FULL)
5103 vars->link_status |= LINK_100TXFD;
5104 else
5105 vars->link_status |= LINK_100TXHD;
5106 break;
5107
5108 case GP_STATUS_1G:
5109 case GP_STATUS_1G_KX:
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005110 vars->line_speed = SPEED_1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005111 if (vars->duplex == DUPLEX_FULL)
5112 vars->link_status |= LINK_1000TFD;
5113 else
5114 vars->link_status |= LINK_1000THD;
5115 break;
5116
5117 case GP_STATUS_2_5G:
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005118 vars->line_speed = SPEED_2500;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005119 if (vars->duplex == DUPLEX_FULL)
5120 vars->link_status |= LINK_2500TFD;
5121 else
5122 vars->link_status |= LINK_2500THD;
5123 break;
5124
5125 case GP_STATUS_5G:
5126 case GP_STATUS_6G:
5127 DP(NETIF_MSG_LINK,
5128 "link speed unsupported gp_status 0x%x\n",
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005129 speed_mask);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005130 return -EINVAL;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005131
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005132 case GP_STATUS_10G_KX4:
5133 case GP_STATUS_10G_HIG:
5134 case GP_STATUS_10G_CX4:
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005135 case GP_STATUS_10G_KR:
5136 case GP_STATUS_10G_SFI:
5137 case GP_STATUS_10G_XFI:
5138 vars->line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005139 vars->link_status |= LINK_10GTFD;
5140 break;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005141 case GP_STATUS_20G_DXGXS:
5142 vars->line_speed = SPEED_20000;
5143 vars->link_status |= LINK_20GTFD;
5144 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005145 default:
5146 DP(NETIF_MSG_LINK,
5147 "link speed unsupported gp_status 0x%x\n",
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005148 speed_mask);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005149 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005150 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005151 } else { /* link_down */
5152 DP(NETIF_MSG_LINK, "phy link down\n");
5153
5154 vars->phy_link_up = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005155
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005156 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08005157 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005158 vars->mac_type = MAC_TYPE_NONE;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005159 }
5160 DP(NETIF_MSG_LINK, " phy_link_up %x line_speed %d\n",
5161 vars->phy_link_up, vars->line_speed);
5162 return 0;
5163}
Eilon Greenstein239d6862009-08-12 08:23:04 +00005164
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005165static int bnx2x_link_settings_status(struct bnx2x_phy *phy,
5166 struct link_params *params,
5167 struct link_vars *vars)
5168{
5169
5170 struct bnx2x *bp = params->bp;
5171
5172 u16 gp_status, duplex = DUPLEX_HALF, link_up = 0, speed_mask;
5173 int rc = 0;
5174
5175 /* Read gp_status */
5176 CL22_RD_OVER_CL45(bp, phy,
5177 MDIO_REG_BANK_GP_STATUS,
5178 MDIO_GP_STATUS_TOP_AN_STATUS1,
5179 &gp_status);
5180 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_DUPLEX_STATUS)
5181 duplex = DUPLEX_FULL;
5182 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS)
5183 link_up = 1;
5184 speed_mask = gp_status & GP_STATUS_SPEED_MASK;
5185 DP(NETIF_MSG_LINK, "gp_status 0x%x, is_link_up %d, speed_mask 0x%x\n",
5186 gp_status, link_up, speed_mask);
5187 rc = bnx2x_get_link_speed_duplex(phy, params, vars, link_up, speed_mask,
5188 duplex);
5189 if (rc == -EINVAL)
5190 return rc;
5191
5192 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) {
5193 if (SINGLE_MEDIA_DIRECT(params)) {
5194 bnx2x_flow_ctrl_resolve(phy, params, vars, gp_status);
5195 if (phy->req_line_speed == SPEED_AUTO_NEG)
5196 bnx2x_xgxs_an_resolve(phy, params, vars,
5197 gp_status);
5198 }
5199 } else { /* link_down */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00005200 if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
5201 SINGLE_MEDIA_DIRECT(params)) {
Eilon Greenstein239d6862009-08-12 08:23:04 +00005202 /* Check signal is detected */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00005203 bnx2x_check_fallback_to_cl37(phy, params);
Eilon Greenstein239d6862009-08-12 08:23:04 +00005204 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005205 }
5206
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005207 DP(NETIF_MSG_LINK, "duplex %x flow_ctrl 0x%x link_status 0x%x\n",
5208 vars->duplex, vars->flow_ctrl, vars->link_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005209 return rc;
5210}
5211
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005212static int bnx2x_warpcore_read_status(struct bnx2x_phy *phy,
5213 struct link_params *params,
5214 struct link_vars *vars)
5215{
5216
5217 struct bnx2x *bp = params->bp;
5218
5219 u8 lane;
5220 u16 gp_status1, gp_speed, link_up, duplex = DUPLEX_FULL;
5221 int rc = 0;
5222 lane = bnx2x_get_warpcore_lane(phy, params);
5223 /* Read gp_status */
5224 if (phy->req_line_speed > SPEED_10000) {
5225 u16 temp_link_up;
5226 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
5227 1, &temp_link_up);
5228 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
5229 1, &link_up);
5230 DP(NETIF_MSG_LINK, "PCS RX link status = 0x%x-->0x%x\n",
5231 temp_link_up, link_up);
5232 link_up &= (1<<2);
5233 if (link_up)
5234 bnx2x_ext_phy_resolve_fc(phy, params, vars);
5235 } else {
5236 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
5237 MDIO_WC_REG_GP2_STATUS_GP_2_1, &gp_status1);
5238 DP(NETIF_MSG_LINK, "0x81d1 = 0x%x\n", gp_status1);
5239 /* Check for either KR or generic link up. */
5240 gp_status1 = ((gp_status1 >> 8) & 0xf) |
5241 ((gp_status1 >> 12) & 0xf);
5242 link_up = gp_status1 & (1 << lane);
5243 if (link_up && SINGLE_MEDIA_DIRECT(params)) {
5244 u16 pd, gp_status4;
5245 if (phy->req_line_speed == SPEED_AUTO_NEG) {
5246 /* Check Autoneg complete */
5247 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
5248 MDIO_WC_REG_GP2_STATUS_GP_2_4,
5249 &gp_status4);
5250 if (gp_status4 & ((1<<12)<<lane))
5251 vars->link_status |=
5252 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
5253
5254 /* Check parallel detect used */
5255 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
5256 MDIO_WC_REG_PAR_DET_10G_STATUS,
5257 &pd);
5258 if (pd & (1<<15))
5259 vars->link_status |=
5260 LINK_STATUS_PARALLEL_DETECTION_USED;
5261 }
5262 bnx2x_ext_phy_resolve_fc(phy, params, vars);
5263 }
5264 }
5265
5266 if (lane < 2) {
5267 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
5268 MDIO_WC_REG_GP2_STATUS_GP_2_2, &gp_speed);
5269 } else {
5270 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
5271 MDIO_WC_REG_GP2_STATUS_GP_2_3, &gp_speed);
5272 }
5273 DP(NETIF_MSG_LINK, "lane %d gp_speed 0x%x\n", lane, gp_speed);
5274
5275 if ((lane & 1) == 0)
5276 gp_speed <<= 8;
5277 gp_speed &= 0x3f00;
5278
5279
5280 rc = bnx2x_get_link_speed_duplex(phy, params, vars, link_up, gp_speed,
5281 duplex);
5282
5283 DP(NETIF_MSG_LINK, "duplex %x flow_ctrl 0x%x link_status 0x%x\n",
5284 vars->duplex, vars->flow_ctrl, vars->link_status);
5285 return rc;
5286}
Eilon Greensteined8680a2009-02-12 08:37:12 +00005287static void bnx2x_set_gmii_tx_driver(struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005288{
5289 struct bnx2x *bp = params->bp;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005290 struct bnx2x_phy *phy = &params->phy[INT_PHY];
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005291 u16 lp_up2;
5292 u16 tx_driver;
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00005293 u16 bank;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005294
5295 /* read precomp */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00005296 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005297 MDIO_REG_BANK_OVER_1G,
5298 MDIO_OVER_1G_LP_UP2, &lp_up2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005299
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005300 /* bits [10:7] at lp_up2, positioned at [15:12] */
5301 lp_up2 = (((lp_up2 & MDIO_OVER_1G_LP_UP2_PREEMPHASIS_MASK) >>
5302 MDIO_OVER_1G_LP_UP2_PREEMPHASIS_SHIFT) <<
5303 MDIO_TX0_TX_DRIVER_PREEMPHASIS_SHIFT);
5304
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00005305 if (lp_up2 == 0)
5306 return;
5307
5308 for (bank = MDIO_REG_BANK_TX0; bank <= MDIO_REG_BANK_TX3;
5309 bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0)) {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00005310 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005311 bank,
5312 MDIO_TX0_TX_DRIVER, &tx_driver);
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00005313
5314 /* replace tx_driver bits [15:12] */
5315 if (lp_up2 !=
5316 (tx_driver & MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK)) {
5317 tx_driver &= ~MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK;
5318 tx_driver |= lp_up2;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00005319 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005320 bank,
5321 MDIO_TX0_TX_DRIVER, tx_driver);
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00005322 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005323 }
5324}
5325
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005326static int bnx2x_emac_program(struct link_params *params,
5327 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005328{
5329 struct bnx2x *bp = params->bp;
5330 u8 port = params->port;
5331 u16 mode = 0;
5332
5333 DP(NETIF_MSG_LINK, "setting link speed & duplex\n");
5334 bnx2x_bits_dis(bp, GRCBASE_EMAC0 + port*0x400 +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005335 EMAC_REG_EMAC_MODE,
5336 (EMAC_MODE_25G_MODE |
5337 EMAC_MODE_PORT_MII_10M |
5338 EMAC_MODE_HALF_DUPLEX));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005339 switch (vars->line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005340 case SPEED_10:
5341 mode |= EMAC_MODE_PORT_MII_10M;
5342 break;
5343
5344 case SPEED_100:
5345 mode |= EMAC_MODE_PORT_MII;
5346 break;
5347
5348 case SPEED_1000:
5349 mode |= EMAC_MODE_PORT_GMII;
5350 break;
5351
5352 case SPEED_2500:
5353 mode |= (EMAC_MODE_25G_MODE | EMAC_MODE_PORT_GMII);
5354 break;
5355
5356 default:
5357 /* 10G not valid for EMAC */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005358 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
5359 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005360 return -EINVAL;
5361 }
5362
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005363 if (vars->duplex == DUPLEX_HALF)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005364 mode |= EMAC_MODE_HALF_DUPLEX;
5365 bnx2x_bits_en(bp,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005366 GRCBASE_EMAC0 + port*0x400 + EMAC_REG_EMAC_MODE,
5367 mode);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005368
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005369 bnx2x_set_led(params, vars, LED_MODE_OPER, vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005370 return 0;
5371}
5372
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005373static void bnx2x_set_preemphasis(struct bnx2x_phy *phy,
5374 struct link_params *params)
5375{
5376
5377 u16 bank, i = 0;
5378 struct bnx2x *bp = params->bp;
5379
5380 for (bank = MDIO_REG_BANK_RX0, i = 0; bank <= MDIO_REG_BANK_RX3;
5381 bank += (MDIO_REG_BANK_RX1-MDIO_REG_BANK_RX0), i++) {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00005382 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005383 bank,
5384 MDIO_RX0_RX_EQ_BOOST,
5385 phy->rx_preemphasis[i]);
5386 }
5387
5388 for (bank = MDIO_REG_BANK_TX0, i = 0; bank <= MDIO_REG_BANK_TX3;
5389 bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0), i++) {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00005390 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005391 bank,
5392 MDIO_TX0_TX_DRIVER,
5393 phy->tx_preemphasis[i]);
5394 }
5395}
5396
Yaniv Rosnerec146a62011-05-31 21:29:27 +00005397static void bnx2x_xgxs_config_init(struct bnx2x_phy *phy,
5398 struct link_params *params,
5399 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005400{
5401 struct bnx2x *bp = params->bp;
5402 u8 enable_cl73 = (SINGLE_MEDIA_DIRECT(params) ||
5403 (params->loopback_mode == LOOPBACK_XGXS));
5404 if (!(vars->phy_flags & PHY_SGMII_FLAG)) {
5405 if (SINGLE_MEDIA_DIRECT(params) &&
5406 (params->feature_config_flags &
5407 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED))
5408 bnx2x_set_preemphasis(phy, params);
5409
5410 /* forced speed requested? */
5411 if (vars->line_speed != SPEED_AUTO_NEG ||
5412 (SINGLE_MEDIA_DIRECT(params) &&
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005413 params->loopback_mode == LOOPBACK_EXT)) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005414 DP(NETIF_MSG_LINK, "not SGMII, no AN\n");
5415
5416 /* disable autoneg */
5417 bnx2x_set_autoneg(phy, params, vars, 0);
5418
5419 /* program speed and duplex */
5420 bnx2x_program_serdes(phy, params, vars);
5421
5422 } else { /* AN_mode */
5423 DP(NETIF_MSG_LINK, "not SGMII, AN\n");
5424
5425 /* AN enabled */
Yaniv Rosner9045f6b2011-05-31 21:28:27 +00005426 bnx2x_set_brcm_cl37_advertisement(phy, params);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005427
5428 /* program duplex & pause advertisement (for aneg) */
Yaniv Rosner9045f6b2011-05-31 21:28:27 +00005429 bnx2x_set_ieee_aneg_advertisement(phy, params,
5430 vars->ieee_fc);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005431
5432 /* enable autoneg */
5433 bnx2x_set_autoneg(phy, params, vars, enable_cl73);
5434
5435 /* enable and restart AN */
5436 bnx2x_restart_autoneg(phy, params, enable_cl73);
5437 }
5438
5439 } else { /* SGMII mode */
5440 DP(NETIF_MSG_LINK, "SGMII\n");
5441
5442 bnx2x_initialize_sgmii_process(phy, params, vars);
5443 }
5444}
5445
Yaniv Rosnerec146a62011-05-31 21:29:27 +00005446static int bnx2x_prepare_xgxs(struct bnx2x_phy *phy,
5447 struct link_params *params,
5448 struct link_vars *vars)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005449{
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005450 int rc;
Yaniv Rosnerec146a62011-05-31 21:29:27 +00005451 vars->phy_flags |= PHY_XGXS_FLAG;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005452 if ((phy->req_line_speed &&
5453 ((phy->req_line_speed == SPEED_100) ||
5454 (phy->req_line_speed == SPEED_10))) ||
5455 (!phy->req_line_speed &&
5456 (phy->speed_cap_mask >=
5457 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL) &&
5458 (phy->speed_cap_mask <
Yaniv Rosnerec146a62011-05-31 21:29:27 +00005459 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) ||
5460 (phy->type == PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT_SD))
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005461 vars->phy_flags |= PHY_SGMII_FLAG;
5462 else
5463 vars->phy_flags &= ~PHY_SGMII_FLAG;
5464
5465 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
Yaniv Rosnerec146a62011-05-31 21:29:27 +00005466 bnx2x_set_aer_mmd(params, phy);
5467 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT)
5468 bnx2x_set_master_ln(params, phy);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005469
5470 rc = bnx2x_reset_unicore(params, phy, 0);
5471 /* reset the SerDes and wait for reset bit return low */
5472 if (rc != 0)
5473 return rc;
5474
Yaniv Rosnerec146a62011-05-31 21:29:27 +00005475 bnx2x_set_aer_mmd(params, phy);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005476 /* setting the masterLn_def again after the reset */
Yaniv Rosnerec146a62011-05-31 21:29:27 +00005477 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) {
5478 bnx2x_set_master_ln(params, phy);
5479 bnx2x_set_swap_lanes(params, phy);
5480 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005481
5482 return rc;
5483}
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00005484
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005485static u16 bnx2x_wait_reset_complete(struct bnx2x *bp,
Yaniv Rosner6d870c32011-01-31 04:22:20 +00005486 struct bnx2x_phy *phy,
5487 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005488{
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005489 u16 cnt, ctrl;
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005490 /* Wait for soft reset to get cleared up to 1 sec */
Yaniv Rosner62b29a52010-09-07 11:40:58 +00005491 for (cnt = 0; cnt < 1000; cnt++) {
Yaniv Rosner6583e332011-06-14 01:34:17 +00005492 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54616)
5493 bnx2x_cl22_read(bp, phy,
5494 MDIO_PMA_REG_CTRL, &ctrl);
5495 else
5496 bnx2x_cl45_read(bp, phy,
5497 MDIO_PMA_DEVAD,
5498 MDIO_PMA_REG_CTRL, &ctrl);
Yaniv Rosner62b29a52010-09-07 11:40:58 +00005499 if (!(ctrl & (1<<15)))
5500 break;
5501 msleep(1);
5502 }
Yaniv Rosner6d870c32011-01-31 04:22:20 +00005503
5504 if (cnt == 1000)
5505 netdev_err(bp->dev, "Warning: PHY was not initialized,"
5506 " Port %d\n",
5507 params->port);
Yaniv Rosner62b29a52010-09-07 11:40:58 +00005508 DP(NETIF_MSG_LINK, "control reg 0x%x (after %d ms)\n", ctrl, cnt);
5509 return cnt;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005510}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005511
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005512static void bnx2x_link_int_enable(struct link_params *params)
5513{
5514 u8 port = params->port;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005515 u32 mask;
5516 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005517
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005518 /* Setting the status to report on link up for either XGXS or SerDes */
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005519 if (CHIP_IS_E3(bp)) {
5520 mask = NIG_MASK_XGXS0_LINK_STATUS;
5521 if (!(SINGLE_MEDIA_DIRECT(params)))
5522 mask |= NIG_MASK_MI_INT;
5523 } else if (params->switch_cfg == SWITCH_CFG_10G) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005524 mask = (NIG_MASK_XGXS0_LINK10G |
5525 NIG_MASK_XGXS0_LINK_STATUS);
5526 DP(NETIF_MSG_LINK, "enabled XGXS interrupt\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005527 if (!(SINGLE_MEDIA_DIRECT(params)) &&
5528 params->phy[INT_PHY].type !=
5529 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005530 mask |= NIG_MASK_MI_INT;
5531 DP(NETIF_MSG_LINK, "enabled external phy int\n");
5532 }
5533
5534 } else { /* SerDes */
5535 mask = NIG_MASK_SERDES0_LINK_STATUS;
5536 DP(NETIF_MSG_LINK, "enabled SerDes interrupt\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005537 if (!(SINGLE_MEDIA_DIRECT(params)) &&
5538 params->phy[INT_PHY].type !=
5539 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_NOT_CONN) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005540 mask |= NIG_MASK_MI_INT;
5541 DP(NETIF_MSG_LINK, "enabled external phy int\n");
5542 }
5543 }
5544 bnx2x_bits_en(bp,
5545 NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
5546 mask);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005547
5548 DP(NETIF_MSG_LINK, "port %x, is_xgxs %x, int_status 0x%x\n", port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005549 (params->switch_cfg == SWITCH_CFG_10G),
5550 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005551 DP(NETIF_MSG_LINK, " int_mask 0x%x, MI_INT %x, SERDES_LINK %x\n",
5552 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
5553 REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
5554 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS+port*0x3c));
5555 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
5556 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
5557 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
5558}
5559
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005560static void bnx2x_rearm_latch_signal(struct bnx2x *bp, u8 port,
5561 u8 exp_mi_int)
Eilon Greenstein2f904462009-08-12 08:22:16 +00005562{
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005563 u32 latch_status = 0;
5564
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005565 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005566 * Disable the MI INT ( external phy int ) by writing 1 to the
5567 * status register. Link down indication is high-active-signal,
5568 * so in this case we need to write the status to clear the XOR
Eilon Greenstein2f904462009-08-12 08:22:16 +00005569 */
5570 /* Read Latched signals */
5571 latch_status = REG_RD(bp,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005572 NIG_REG_LATCH_STATUS_0 + port*8);
5573 DP(NETIF_MSG_LINK, "latch_status = 0x%x\n", latch_status);
Eilon Greenstein2f904462009-08-12 08:22:16 +00005574 /* Handle only those with latched-signal=up.*/
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005575 if (exp_mi_int)
5576 bnx2x_bits_en(bp,
5577 NIG_REG_STATUS_INTERRUPT_PORT0
5578 + port*4,
5579 NIG_STATUS_EMAC0_MI_INT);
5580 else
5581 bnx2x_bits_dis(bp,
5582 NIG_REG_STATUS_INTERRUPT_PORT0
5583 + port*4,
5584 NIG_STATUS_EMAC0_MI_INT);
5585
Eilon Greenstein2f904462009-08-12 08:22:16 +00005586 if (latch_status & 1) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005587
Eilon Greenstein2f904462009-08-12 08:22:16 +00005588 /* For all latched-signal=up : Re-Arm Latch signals */
5589 REG_WR(bp, NIG_REG_LATCH_STATUS_0 + port*8,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005590 (latch_status & 0xfffe) | (latch_status & 1));
Eilon Greenstein2f904462009-08-12 08:22:16 +00005591 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005592 /* For all latched-signal=up,Write original_signal to status */
Eilon Greenstein2f904462009-08-12 08:22:16 +00005593}
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005594
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005595static void bnx2x_link_int_ack(struct link_params *params,
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005596 struct link_vars *vars, u8 is_10g_plus)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005597{
5598 struct bnx2x *bp = params->bp;
5599 u8 port = params->port;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005600 u32 mask;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005601 /*
5602 * First reset all status we assume only one line will be
5603 * change at a time
5604 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005605 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005606 (NIG_STATUS_XGXS0_LINK10G |
5607 NIG_STATUS_XGXS0_LINK_STATUS |
5608 NIG_STATUS_SERDES0_LINK_STATUS));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005609 if (vars->phy_link_up) {
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005610 if (USES_WARPCORE(bp))
5611 mask = NIG_STATUS_XGXS0_LINK_STATUS;
5612 else {
5613 if (is_10g_plus)
5614 mask = NIG_STATUS_XGXS0_LINK10G;
5615 else if (params->switch_cfg == SWITCH_CFG_10G) {
5616 /*
5617 * Disable the link interrupt by writing 1 to
5618 * the relevant lane in the status register
5619 */
5620 u32 ser_lane =
5621 ((params->lane_config &
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005622 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
5623 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005624 mask = ((1 << ser_lane) <<
5625 NIG_STATUS_XGXS0_LINK_STATUS_SIZE);
5626 } else
5627 mask = NIG_STATUS_SERDES0_LINK_STATUS;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005628 }
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005629 DP(NETIF_MSG_LINK, "Ack link up interrupt with mask 0x%x\n",
5630 mask);
5631 bnx2x_bits_en(bp,
5632 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
5633 mask);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005634 }
5635}
5636
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005637static int bnx2x_format_ver(u32 num, u8 *str, u16 *len)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005638{
5639 u8 *str_ptr = str;
5640 u32 mask = 0xf0000000;
5641 u8 shift = 8*4;
5642 u8 digit;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005643 u8 remove_leading_zeros = 1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005644 if (*len < 10) {
Frederik Schwarzer025dfda2008-10-16 19:02:37 +02005645 /* Need more than 10chars for this format */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005646 *str_ptr = '\0';
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005647 (*len)--;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005648 return -EINVAL;
5649 }
5650 while (shift > 0) {
5651
5652 shift -= 4;
5653 digit = ((num & mask) >> shift);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005654 if (digit == 0 && remove_leading_zeros) {
5655 mask = mask >> 4;
5656 continue;
5657 } else if (digit < 0xa)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005658 *str_ptr = digit + '0';
5659 else
5660 *str_ptr = digit - 0xa + 'a';
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005661 remove_leading_zeros = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005662 str_ptr++;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005663 (*len)--;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005664 mask = mask >> 4;
5665 if (shift == 4*4) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005666 *str_ptr = '.';
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005667 str_ptr++;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005668 (*len)--;
5669 remove_leading_zeros = 1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005670 }
5671 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005672 return 0;
5673}
5674
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005675
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005676static int bnx2x_null_format_ver(u32 spirom_ver, u8 *str, u16 *len)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005677{
5678 str[0] = '\0';
5679 (*len)--;
5680 return 0;
5681}
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005682
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005683int bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
5684 u8 *version, u16 len)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005685{
Julia Lawall0376d5b2009-07-19 05:26:35 +00005686 struct bnx2x *bp;
Eilon Greensteina35da8d2009-02-12 08:37:02 +00005687 u32 spirom_ver = 0;
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005688 int status = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005689 u8 *ver_p = version;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005690 u16 remain_len = len;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005691 if (version == NULL || params == NULL)
5692 return -EINVAL;
Julia Lawall0376d5b2009-07-19 05:26:35 +00005693 bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005694
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005695 /* Extract first external phy*/
5696 version[0] = '\0';
5697 spirom_ver = REG_RD(bp, params->phy[EXT_PHY1].ver_addr);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00005698
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005699 if (params->phy[EXT_PHY1].format_fw_ver) {
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005700 status |= params->phy[EXT_PHY1].format_fw_ver(spirom_ver,
5701 ver_p,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005702 &remain_len);
5703 ver_p += (len - remain_len);
5704 }
5705 if ((params->num_phys == MAX_PHYS) &&
5706 (params->phy[EXT_PHY2].ver_addr != 0)) {
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005707 spirom_ver = REG_RD(bp, params->phy[EXT_PHY2].ver_addr);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005708 if (params->phy[EXT_PHY2].format_fw_ver) {
5709 *ver_p = '/';
5710 ver_p++;
5711 remain_len--;
5712 status |= params->phy[EXT_PHY2].format_fw_ver(
5713 spirom_ver,
5714 ver_p,
5715 &remain_len);
5716 ver_p = version + (len - remain_len);
5717 }
5718 }
5719 *ver_p = '\0';
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005720 return status;
5721}
5722
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005723static void bnx2x_set_xgxs_loopback(struct bnx2x_phy *phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00005724 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005725{
5726 u8 port = params->port;
5727 struct bnx2x *bp = params->bp;
5728
Yaniv Rosner62b29a52010-09-07 11:40:58 +00005729 if (phy->req_line_speed != SPEED_1000) {
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005730 u32 md_devad = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005731
5732 DP(NETIF_MSG_LINK, "XGXS 10G loopback enable\n");
5733
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005734 if (!CHIP_IS_E3(bp)) {
5735 /* change the uni_phy_addr in the nig */
5736 md_devad = REG_RD(bp, (NIG_REG_XGXS0_CTRL_MD_DEVAD +
5737 port*0x18));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005738
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005739 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
5740 0x5);
5741 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005742
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005743 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005744 5,
5745 (MDIO_REG_BANK_AER_BLOCK +
5746 (MDIO_AER_BLOCK_AER_REG & 0xf)),
5747 0x2800);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005748
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005749 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005750 5,
5751 (MDIO_REG_BANK_CL73_IEEEB0 +
5752 (MDIO_CL73_IEEEB0_CL73_AN_CONTROL & 0xf)),
5753 0x6041);
Eilon Greenstein38582762009-01-14 06:44:16 +00005754 msleep(200);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005755 /* set aer mmd back */
Yaniv Rosnerec146a62011-05-31 21:29:27 +00005756 bnx2x_set_aer_mmd(params, phy);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005757
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005758 if (!CHIP_IS_E3(bp)) {
5759 /* and md_devad */
5760 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
5761 md_devad);
5762 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005763 } else {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005764 u16 mii_ctrl;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005765 DP(NETIF_MSG_LINK, "XGXS 1G loopback enable\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005766 bnx2x_cl45_read(bp, phy, 5,
5767 (MDIO_REG_BANK_COMBO_IEEE0 +
5768 (MDIO_COMBO_IEEE0_MII_CONTROL & 0xf)),
5769 &mii_ctrl);
5770 bnx2x_cl45_write(bp, phy, 5,
5771 (MDIO_REG_BANK_COMBO_IEEE0 +
5772 (MDIO_COMBO_IEEE0_MII_CONTROL & 0xf)),
5773 mii_ctrl |
5774 MDIO_COMBO_IEEO_MII_CONTROL_LOOPBACK);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005775 }
5776}
5777
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005778int bnx2x_set_led(struct link_params *params,
5779 struct link_vars *vars, u8 mode, u32 speed)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005780{
Yaniv Rosner7846e472009-11-05 19:18:07 +02005781 u8 port = params->port;
5782 u16 hw_led_mode = params->hw_led_mode;
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005783 int rc = 0;
5784 u8 phy_idx;
Eilon Greenstein345b5d52008-08-13 15:58:12 -07005785 u32 tmp;
5786 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Yaniv Rosner7846e472009-11-05 19:18:07 +02005787 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005788 DP(NETIF_MSG_LINK, "bnx2x_set_led: port %x, mode %d\n", port, mode);
5789 DP(NETIF_MSG_LINK, "speed 0x%x, hw_led_mode 0x%x\n",
5790 speed, hw_led_mode);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005791 /* In case */
5792 for (phy_idx = EXT_PHY1; phy_idx < MAX_PHYS; phy_idx++) {
5793 if (params->phy[phy_idx].set_link_led) {
5794 params->phy[phy_idx].set_link_led(
5795 &params->phy[phy_idx], params, mode);
5796 }
5797 }
5798
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005799 switch (mode) {
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005800 case LED_MODE_FRONT_PANEL_OFF:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005801 case LED_MODE_OFF:
5802 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 0);
5803 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005804 SHARED_HW_CFG_LED_MAC1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07005805
5806 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07005807 EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp | EMAC_LED_OVERRIDE));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005808 break;
5809
5810 case LED_MODE_OPER:
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005811 /*
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005812 * For all other phys, OPER mode is same as ON, so in case
5813 * link is down, do nothing
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005814 */
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005815 if (!vars->link_up)
5816 break;
5817 case LED_MODE_ON:
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00005818 if (((params->phy[EXT_PHY1].type ==
5819 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) ||
5820 (params->phy[EXT_PHY1].type ==
5821 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722)) &&
Yaniv Rosner1f483532011-01-18 04:33:31 +00005822 CHIP_IS_E2(bp) && params->num_phys == 2) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005823 /*
5824 * This is a work-around for E2+8727 Configurations
5825 */
Yaniv Rosner1f483532011-01-18 04:33:31 +00005826 if (mode == LED_MODE_ON ||
5827 speed == SPEED_10000){
5828 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0);
5829 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1);
5830
5831 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
5832 EMAC_WR(bp, EMAC_REG_EMAC_LED,
5833 (tmp | EMAC_LED_OVERRIDE));
5834 return rc;
5835 }
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005836 } else if (SINGLE_MEDIA_DIRECT(params) &&
5837 (CHIP_IS_E1x(bp) ||
5838 CHIP_IS_E2(bp))) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005839 /*
5840 * This is a work-around for HW issue found when link
5841 * is up in CL73
5842 */
Yaniv Rosner7846e472009-11-05 19:18:07 +02005843 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0);
5844 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1);
5845 } else {
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005846 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, hw_led_mode);
Yaniv Rosner7846e472009-11-05 19:18:07 +02005847 }
5848
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005849 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 + port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005850 /* Set blinking rate to ~15.9Hz */
5851 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005852 LED_BLINK_RATE_VAL);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005853 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005854 port*4, 1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07005855 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005856 EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp & (~EMAC_LED_OVERRIDE)));
Eilon Greenstein345b5d52008-08-13 15:58:12 -07005857
Yaniv Rosner7846e472009-11-05 19:18:07 +02005858 if (CHIP_IS_E1(bp) &&
Eilon Greenstein34f80b02008-06-23 20:33:01 -07005859 ((speed == SPEED_2500) ||
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005860 (speed == SPEED_1000) ||
5861 (speed == SPEED_100) ||
5862 (speed == SPEED_10))) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005863 /*
5864 * On Everest 1 Ax chip versions for speeds less than
5865 * 10G LED scheme is different
5866 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005867 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005868 + port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005869 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005870 port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005871 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_TRAFFIC_P0 +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005872 port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005873 }
5874 break;
5875
5876 default:
5877 rc = -EINVAL;
5878 DP(NETIF_MSG_LINK, "bnx2x_set_led: Invalid led mode %d\n",
5879 mode);
5880 break;
5881 }
5882 return rc;
5883
5884}
5885
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005886/*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005887 * This function comes to reflect the actual link state read DIRECTLY from the
5888 * HW
5889 */
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005890int bnx2x_test_link(struct link_params *params, struct link_vars *vars,
5891 u8 is_serdes)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005892{
5893 struct bnx2x *bp = params->bp;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00005894 u16 gp_status = 0, phy_index = 0;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005895 u8 ext_phy_link_up = 0, serdes_phy_type;
5896 struct link_vars temp_vars;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005897 struct bnx2x_phy *int_phy = &params->phy[INT_PHY];
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005898
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005899 if (CHIP_IS_E3(bp)) {
5900 u16 link_up;
5901 if (params->req_line_speed[LINK_CONFIG_IDX(INT_PHY)]
5902 > SPEED_10000) {
5903 /* Check 20G link */
5904 bnx2x_cl45_read(bp, int_phy, MDIO_WC_DEVAD,
5905 1, &link_up);
5906 bnx2x_cl45_read(bp, int_phy, MDIO_WC_DEVAD,
5907 1, &link_up);
5908 link_up &= (1<<2);
5909 } else {
5910 /* Check 10G link and below*/
5911 u8 lane = bnx2x_get_warpcore_lane(int_phy, params);
5912 bnx2x_cl45_read(bp, int_phy, MDIO_WC_DEVAD,
5913 MDIO_WC_REG_GP2_STATUS_GP_2_1,
5914 &gp_status);
5915 gp_status = ((gp_status >> 8) & 0xf) |
5916 ((gp_status >> 12) & 0xf);
5917 link_up = gp_status & (1 << lane);
5918 }
5919 if (!link_up)
5920 return -ESRCH;
5921 } else {
5922 CL22_RD_OVER_CL45(bp, int_phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005923 MDIO_REG_BANK_GP_STATUS,
5924 MDIO_GP_STATUS_TOP_AN_STATUS1,
5925 &gp_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005926 /* link is up only if both local phy and external phy are up */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005927 if (!(gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS))
5928 return -ESRCH;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005929 }
5930 /* In XGXS loopback mode, do not check external PHY */
5931 if (params->loopback_mode == LOOPBACK_XGXS)
5932 return 0;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005933
5934 switch (params->num_phys) {
5935 case 1:
5936 /* No external PHY */
5937 return 0;
5938 case 2:
5939 ext_phy_link_up = params->phy[EXT_PHY1].read_status(
5940 &params->phy[EXT_PHY1],
5941 params, &temp_vars);
5942 break;
5943 case 3: /* Dual Media */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00005944 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
5945 phy_index++) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005946 serdes_phy_type = ((params->phy[phy_index].media_type ==
5947 ETH_PHY_SFP_FIBER) ||
5948 (params->phy[phy_index].media_type ==
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00005949 ETH_PHY_XFP_FIBER) ||
5950 (params->phy[phy_index].media_type ==
5951 ETH_PHY_DA_TWINAX));
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005952
5953 if (is_serdes != serdes_phy_type)
5954 continue;
5955 if (params->phy[phy_index].read_status) {
5956 ext_phy_link_up |=
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00005957 params->phy[phy_index].read_status(
5958 &params->phy[phy_index],
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005959 params, &temp_vars);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005960 }
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00005961 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005962 break;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005963 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005964 if (ext_phy_link_up)
5965 return 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005966 return -ESRCH;
5967}
5968
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005969static int bnx2x_link_initialize(struct link_params *params,
5970 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005971{
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005972 int rc = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005973 u8 phy_index, non_ext_phy;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00005974 struct bnx2x *bp = params->bp;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005975 /*
5976 * In case of external phy existence, the line speed would be the
5977 * line speed linked up by the external phy. In case it is direct
5978 * only, then the line_speed during initialization will be
5979 * equal to the req_line_speed
5980 */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00005981 vars->line_speed = params->phy[INT_PHY].req_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005982
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005983 /*
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00005984 * Initialize the internal phy in case this is a direct board
5985 * (no external phys), or this board has external phy which requires
5986 * to first.
5987 */
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005988 if (!USES_WARPCORE(bp))
5989 bnx2x_prepare_xgxs(&params->phy[INT_PHY], params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005990 /* init ext phy and enable link state int */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00005991 non_ext_phy = (SINGLE_MEDIA_DIRECT(params) ||
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005992 (params->loopback_mode == LOOPBACK_XGXS));
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005993
5994 if (non_ext_phy ||
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00005995 (params->phy[EXT_PHY1].flags & FLAGS_INIT_XGXS_FIRST) ||
Eilon Greenstein8660d8c2009-03-02 08:01:02 +00005996 (params->loopback_mode == LOOPBACK_EXT_PHY)) {
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00005997 struct bnx2x_phy *phy = &params->phy[INT_PHY];
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005998 if (vars->line_speed == SPEED_AUTO_NEG &&
5999 (CHIP_IS_E1x(bp) ||
6000 CHIP_IS_E2(bp)))
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00006001 bnx2x_set_parallel_detection(phy, params);
Yaniv Rosnerec146a62011-05-31 21:29:27 +00006002 if (params->phy[INT_PHY].config_init)
6003 params->phy[INT_PHY].config_init(phy,
6004 params,
6005 vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006006 }
6007
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00006008 /* Init external phy*/
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00006009 if (non_ext_phy) {
6010 if (params->phy[INT_PHY].supported &
6011 SUPPORTED_FIBRE)
6012 vars->link_status |= LINK_STATUS_SERDES_LINK;
6013 } else {
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006014 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
6015 phy_index++) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006016 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006017 * No need to initialize second phy in case of first
6018 * phy only selection. In case of second phy, we do
6019 * need to initialize the first phy, since they are
6020 * connected.
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006021 */
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00006022 if (params->phy[phy_index].supported &
6023 SUPPORTED_FIBRE)
6024 vars->link_status |= LINK_STATUS_SERDES_LINK;
6025
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006026 if (phy_index == EXT_PHY2 &&
6027 (bnx2x_phy_selection(params) ==
6028 PORT_HW_CFG_PHY_SELECTION_FIRST_PHY)) {
Yaniv Rosner9045f6b2011-05-31 21:28:27 +00006029 DP(NETIF_MSG_LINK, "Not initializing"
6030 " second phy\n");
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006031 continue;
6032 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006033 params->phy[phy_index].config_init(
6034 &params->phy[phy_index],
6035 params, vars);
6036 }
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00006037 }
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00006038 /* Reset the interrupt indication after phy was initialized */
6039 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 +
6040 params->port*4,
6041 (NIG_STATUS_XGXS0_LINK10G |
6042 NIG_STATUS_XGXS0_LINK_STATUS |
6043 NIG_STATUS_SERDES0_LINK_STATUS |
6044 NIG_MASK_MI_INT));
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00006045 bnx2x_update_mng(params, vars->link_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006046 return rc;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006047}
6048
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006049static void bnx2x_int_link_reset(struct bnx2x_phy *phy,
6050 struct link_params *params)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006051{
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006052 /* reset the SerDes/XGXS */
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006053 REG_WR(params->bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
6054 (0x1ff << (params->port*16)));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006055}
6056
6057static void bnx2x_common_ext_link_reset(struct bnx2x_phy *phy,
6058 struct link_params *params)
6059{
6060 struct bnx2x *bp = params->bp;
6061 u8 gpio_port;
6062 /* HW reset */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00006063 if (CHIP_IS_E2(bp))
6064 gpio_port = BP_PATH(bp);
6065 else
6066 gpio_port = params->port;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006067 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006068 MISC_REGISTERS_GPIO_OUTPUT_LOW,
6069 gpio_port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006070 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006071 MISC_REGISTERS_GPIO_OUTPUT_LOW,
6072 gpio_port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006073 DP(NETIF_MSG_LINK, "reset external PHY\n");
6074}
6075
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006076static int bnx2x_update_link_down(struct link_params *params,
6077 struct link_vars *vars)
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006078{
6079 struct bnx2x *bp = params->bp;
6080 u8 port = params->port;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00006081
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006082 DP(NETIF_MSG_LINK, "Port %x: Link is down\n", port);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006083 bnx2x_set_led(params, vars, LED_MODE_OFF, 0);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006084
6085 /* indicate no mac active */
6086 vars->mac_type = MAC_TYPE_NONE;
6087
6088 /* update shared memory */
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00006089 vars->link_status &= ~(LINK_STATUS_SPEED_AND_DUPLEX_MASK |
6090 LINK_STATUS_LINK_UP |
6091 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE |
6092 LINK_STATUS_RX_FLOW_CONTROL_FLAG_MASK |
6093 LINK_STATUS_TX_FLOW_CONTROL_FLAG_MASK |
6094 LINK_STATUS_PARALLEL_DETECTION_FLAG_MASK);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006095 vars->line_speed = 0;
6096 bnx2x_update_mng(params, vars->link_status);
6097
6098 /* activate nig drain */
6099 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
6100
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00006101 /* disable emac */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00006102 if (!CHIP_IS_E3(bp))
6103 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00006104
6105 msleep(10);
Yaniv Rosner9380bb92011-06-14 01:34:07 +00006106 /* reset BigMac/Xmac */
6107 if (CHIP_IS_E1x(bp) ||
6108 CHIP_IS_E2(bp)) {
6109 bnx2x_bmac_rx_disable(bp, params->port);
6110 REG_WR(bp, GRCBASE_MISC +
6111 MISC_REGISTERS_RESET_REG_2_CLEAR,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006112 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
Yaniv Rosner9380bb92011-06-14 01:34:07 +00006113 }
6114 if (CHIP_IS_E3(bp))
6115 bnx2x_xmac_disable(params);
6116
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006117 return 0;
6118}
6119
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006120static int bnx2x_update_link_up(struct link_params *params,
6121 struct link_vars *vars,
6122 u8 link_10g)
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006123{
6124 struct bnx2x *bp = params->bp;
6125 u8 port = params->port;
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006126 int rc = 0;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00006127
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006128 vars->link_status |= LINK_STATUS_LINK_UP;
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006129
Yaniv Rosner7aa07112010-09-07 11:41:01 +00006130 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
6131 vars->link_status |=
6132 LINK_STATUS_TX_FLOW_CONTROL_ENABLED;
6133
6134 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
6135 vars->link_status |=
6136 LINK_STATUS_RX_FLOW_CONTROL_ENABLED;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00006137 if (USES_WARPCORE(bp)) {
6138 if (link_10g)
6139 bnx2x_xmac_enable(params, vars, 0);
6140 else
6141 bnx2x_umac_enable(params, vars, 0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006142 bnx2x_set_led(params, vars,
Yaniv Rosner9380bb92011-06-14 01:34:07 +00006143 LED_MODE_OPER, vars->line_speed);
6144 }
6145 if ((CHIP_IS_E1x(bp) ||
6146 CHIP_IS_E2(bp))) {
6147 if (link_10g) {
6148 bnx2x_bmac_enable(params, vars, 0);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006149
Yaniv Rosner9380bb92011-06-14 01:34:07 +00006150 bnx2x_set_led(params, vars,
6151 LED_MODE_OPER, SPEED_10000);
6152 } else {
6153 rc = bnx2x_emac_program(params, vars);
6154 bnx2x_emac_enable(params, vars, 0);
Yaniv Rosner0c786f02009-11-05 19:18:32 +02006155
Yaniv Rosner9380bb92011-06-14 01:34:07 +00006156 /* AN complete? */
6157 if ((vars->link_status &
6158 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE)
6159 && (!(vars->phy_flags & PHY_SGMII_FLAG)) &&
6160 SINGLE_MEDIA_DIRECT(params))
6161 bnx2x_set_gmii_tx_driver(params);
6162 }
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006163 }
6164
6165 /* PBF - link up */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00006166 if (CHIP_IS_E1x(bp))
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00006167 rc |= bnx2x_pbf_update(params, vars->flow_ctrl,
6168 vars->line_speed);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006169
6170 /* disable drain */
6171 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 0);
6172
6173 /* update shared memory */
6174 bnx2x_update_mng(params, vars->link_status);
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00006175 msleep(20);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006176 return rc;
6177}
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006178/*
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006179 * The bnx2x_link_update function should be called upon link
6180 * interrupt.
6181 * Link is considered up as follows:
6182 * - DIRECT_SINGLE_MEDIA - Only XGXS link (internal link) needs
6183 * to be up
6184 * - SINGLE_MEDIA - The link between the 577xx and the external
6185 * phy (XGXS) need to up as well as the external link of the
6186 * phy (PHY_EXT1)
6187 * - DUAL_MEDIA - The link between the 577xx and the first
6188 * external phy needs to be up, and at least one of the 2
6189 * external phy link must be up.
Yaniv Rosner62b29a52010-09-07 11:40:58 +00006190 */
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006191int bnx2x_link_update(struct link_params *params, struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006192{
6193 struct bnx2x *bp = params->bp;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006194 struct link_vars phy_vars[MAX_PHYS];
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006195 u8 port = params->port;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00006196 u8 link_10g_plus, phy_index;
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006197 u8 ext_phy_link_up = 0, cur_link_up;
6198 int rc = 0;
Eilon Greenstein2f904462009-08-12 08:22:16 +00006199 u8 is_mi_int = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006200 u16 ext_phy_line_speed = 0, prev_line_speed = vars->line_speed;
6201 u8 active_external_phy = INT_PHY;
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00006202
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006203 for (phy_index = INT_PHY; phy_index < params->num_phys;
6204 phy_index++) {
6205 phy_vars[phy_index].flow_ctrl = 0;
6206 phy_vars[phy_index].link_status = 0;
6207 phy_vars[phy_index].line_speed = 0;
6208 phy_vars[phy_index].duplex = DUPLEX_FULL;
6209 phy_vars[phy_index].phy_link_up = 0;
6210 phy_vars[phy_index].link_up = 0;
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00006211 phy_vars[phy_index].fault_detected = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006212 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006213
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00006214 if (USES_WARPCORE(bp))
6215 bnx2x_set_aer_mmd(params, &params->phy[INT_PHY]);
6216
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006217 DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n",
Eilon Greenstein2f904462009-08-12 08:22:16 +00006218 port, (vars->phy_flags & PHY_XGXS_FLAG),
6219 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006220
Eilon Greenstein2f904462009-08-12 08:22:16 +00006221 is_mi_int = (u8)(REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006222 port*0x18) > 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006223 DP(NETIF_MSG_LINK, "int_mask 0x%x MI_INT %x, SERDES_LINK %x\n",
Eilon Greenstein2f904462009-08-12 08:22:16 +00006224 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
6225 is_mi_int,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006226 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006227
6228 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
6229 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
6230 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
6231
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00006232 /* disable emac */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00006233 if (!CHIP_IS_E3(bp))
6234 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00006235
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006236 /*
6237 * Step 1:
6238 * Check external link change only for external phys, and apply
6239 * priority selection between them in case the link on both phys
Yaniv Rosner9045f6b2011-05-31 21:28:27 +00006240 * is up. Note that instead of the common vars, a temporary
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006241 * vars argument is used since each phy may have different link/
6242 * speed/duplex result
6243 */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006244 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
6245 phy_index++) {
6246 struct bnx2x_phy *phy = &params->phy[phy_index];
6247 if (!phy->read_status)
6248 continue;
6249 /* Read link status and params of this ext phy */
6250 cur_link_up = phy->read_status(phy, params,
6251 &phy_vars[phy_index]);
6252 if (cur_link_up) {
6253 DP(NETIF_MSG_LINK, "phy in index %d link is up\n",
6254 phy_index);
6255 } else {
6256 DP(NETIF_MSG_LINK, "phy in index %d link is down\n",
6257 phy_index);
6258 continue;
6259 }
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006260
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006261 if (!ext_phy_link_up) {
6262 ext_phy_link_up = 1;
6263 active_external_phy = phy_index;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006264 } else {
6265 switch (bnx2x_phy_selection(params)) {
6266 case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT:
6267 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006268 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006269 * In this option, the first PHY makes sure to pass the
6270 * traffic through itself only.
6271 * Its not clear how to reset the link on the second phy
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006272 */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006273 active_external_phy = EXT_PHY1;
6274 break;
6275 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006276 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006277 * In this option, the first PHY makes sure to pass the
6278 * traffic through the second PHY.
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006279 */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006280 active_external_phy = EXT_PHY2;
6281 break;
6282 default:
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006283 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006284 * Link indication on both PHYs with the following cases
6285 * is invalid:
6286 * - FIRST_PHY means that second phy wasn't initialized,
6287 * hence its link is expected to be down
6288 * - SECOND_PHY means that first phy should not be able
6289 * to link up by itself (using configuration)
6290 * - DEFAULT should be overriden during initialiazation
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006291 */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006292 DP(NETIF_MSG_LINK, "Invalid link indication"
6293 "mpc=0x%x. DISABLING LINK !!!\n",
6294 params->multi_phy_config);
6295 ext_phy_link_up = 0;
6296 break;
6297 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006298 }
6299 }
6300 prev_line_speed = vars->line_speed;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006301 /*
6302 * Step 2:
6303 * Read the status of the internal phy. In case of
6304 * DIRECT_SINGLE_MEDIA board, this link is the external link,
6305 * otherwise this is the link between the 577xx and the first
6306 * external phy
6307 */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006308 if (params->phy[INT_PHY].read_status)
6309 params->phy[INT_PHY].read_status(
6310 &params->phy[INT_PHY],
6311 params, vars);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006312 /*
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006313 * The INT_PHY flow control reside in the vars. This include the
6314 * case where the speed or flow control are not set to AUTO.
6315 * Otherwise, the active external phy flow control result is set
6316 * to the vars. The ext_phy_line_speed is needed to check if the
6317 * speed is different between the internal phy and external phy.
6318 * This case may be result of intermediate link speed change.
6319 */
6320 if (active_external_phy > INT_PHY) {
6321 vars->flow_ctrl = phy_vars[active_external_phy].flow_ctrl;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006322 /*
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006323 * Link speed is taken from the XGXS. AN and FC result from
6324 * the external phy.
6325 */
6326 vars->link_status |= phy_vars[active_external_phy].link_status;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006327
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006328 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006329 * if active_external_phy is first PHY and link is up - disable
6330 * disable TX on second external PHY
6331 */
6332 if (active_external_phy == EXT_PHY1) {
6333 if (params->phy[EXT_PHY2].phy_specific_func) {
6334 DP(NETIF_MSG_LINK, "Disabling TX on"
6335 " EXT_PHY2\n");
6336 params->phy[EXT_PHY2].phy_specific_func(
6337 &params->phy[EXT_PHY2],
6338 params, DISABLE_TX);
6339 }
6340 }
6341
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006342 ext_phy_line_speed = phy_vars[active_external_phy].line_speed;
6343 vars->duplex = phy_vars[active_external_phy].duplex;
6344 if (params->phy[active_external_phy].supported &
6345 SUPPORTED_FIBRE)
6346 vars->link_status |= LINK_STATUS_SERDES_LINK;
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00006347 else
6348 vars->link_status &= ~LINK_STATUS_SERDES_LINK;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006349 DP(NETIF_MSG_LINK, "Active external phy selected: %x\n",
6350 active_external_phy);
6351 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006352
6353 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
6354 phy_index++) {
6355 if (params->phy[phy_index].flags &
6356 FLAGS_REARM_LATCH_SIGNAL) {
6357 bnx2x_rearm_latch_signal(bp, port,
6358 phy_index ==
6359 active_external_phy);
6360 break;
6361 }
6362 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006363 DP(NETIF_MSG_LINK, "vars->flow_ctrl = 0x%x, vars->link_status = 0x%x,"
6364 " ext_phy_line_speed = %d\n", vars->flow_ctrl,
6365 vars->link_status, ext_phy_line_speed);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006366 /*
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006367 * Upon link speed change set the NIG into drain mode. Comes to
6368 * deals with possible FIFO glitch due to clk change when speed
6369 * is decreased without link down indicator
6370 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006371
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006372 if (vars->phy_link_up) {
6373 if (!(SINGLE_MEDIA_DIRECT(params)) && ext_phy_link_up &&
6374 (ext_phy_line_speed != vars->line_speed)) {
6375 DP(NETIF_MSG_LINK, "Internal link speed %d is"
6376 " different than the external"
6377 " link speed %d\n", vars->line_speed,
6378 ext_phy_line_speed);
6379 vars->phy_link_up = 0;
6380 } else if (prev_line_speed != vars->line_speed) {
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006381 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4,
6382 0);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006383 msleep(1);
6384 }
6385 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006386
6387 /* anything 10 and over uses the bmac */
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00006388 link_10g_plus = (vars->line_speed >= SPEED_10000);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006389
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00006390 bnx2x_link_int_ack(params, vars, link_10g_plus);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006391
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006392 /*
6393 * In case external phy link is up, and internal link is down
6394 * (not initialized yet probably after link initialization, it
6395 * needs to be initialized.
6396 * Note that after link down-up as result of cable plug, the xgxs
6397 * link would probably become up again without the need
6398 * initialize it
6399 */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006400 if (!(SINGLE_MEDIA_DIRECT(params))) {
6401 DP(NETIF_MSG_LINK, "ext_phy_link_up = %d, int_link_up = %d,"
6402 " init_preceding = %d\n", ext_phy_link_up,
6403 vars->phy_link_up,
6404 params->phy[EXT_PHY1].flags &
6405 FLAGS_INIT_XGXS_FIRST);
6406 if (!(params->phy[EXT_PHY1].flags &
6407 FLAGS_INIT_XGXS_FIRST)
6408 && ext_phy_link_up && !vars->phy_link_up) {
6409 vars->line_speed = ext_phy_line_speed;
6410 if (vars->line_speed < SPEED_1000)
6411 vars->phy_flags |= PHY_SGMII_FLAG;
6412 else
6413 vars->phy_flags &= ~PHY_SGMII_FLAG;
Yaniv Rosnerec146a62011-05-31 21:29:27 +00006414
6415 if (params->phy[INT_PHY].config_init)
6416 params->phy[INT_PHY].config_init(
6417 &params->phy[INT_PHY], params,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006418 vars);
6419 }
6420 }
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006421 /*
6422 * Link is up only if both local phy and external phy (in case of
Yaniv Rosner9045f6b2011-05-31 21:28:27 +00006423 * non-direct board) are up and no fault detected on active PHY.
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006424 */
6425 vars->link_up = (vars->phy_link_up &&
6426 (ext_phy_link_up ||
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00006427 SINGLE_MEDIA_DIRECT(params)) &&
6428 (phy_vars[active_external_phy].fault_detected == 0));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006429
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006430 if (vars->link_up)
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00006431 rc = bnx2x_update_link_up(params, vars, link_10g_plus);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006432 else
6433 rc = bnx2x_update_link_down(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006434
6435 return rc;
6436}
6437
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006438
6439/*****************************************************************************/
6440/* External Phy section */
6441/*****************************************************************************/
6442void bnx2x_ext_phy_hw_reset(struct bnx2x *bp, u8 port)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006443{
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006444 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006445 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006446 msleep(1);
6447 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006448 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006449}
6450
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006451static void bnx2x_save_spirom_version(struct bnx2x *bp, u8 port,
6452 u32 spirom_ver, u32 ver_addr)
6453{
6454 DP(NETIF_MSG_LINK, "FW version 0x%x:0x%x for port %d\n",
6455 (u16)(spirom_ver>>16), (u16)spirom_ver, port);
6456
6457 if (ver_addr)
6458 REG_WR(bp, ver_addr, spirom_ver);
6459}
6460
6461static void bnx2x_save_bcm_spirom_ver(struct bnx2x *bp,
6462 struct bnx2x_phy *phy,
6463 u8 port)
6464{
6465 u16 fw_ver1, fw_ver2;
6466
6467 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006468 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006469 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006470 MDIO_PMA_REG_ROM_VER2, &fw_ver2);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006471 bnx2x_save_spirom_version(bp, port, (u32)(fw_ver1<<16 | fw_ver2),
6472 phy->ver_addr);
6473}
6474
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006475static void bnx2x_ext_phy_10G_an_resolve(struct bnx2x *bp,
6476 struct bnx2x_phy *phy,
6477 struct link_vars *vars)
6478{
6479 u16 val;
6480 bnx2x_cl45_read(bp, phy,
6481 MDIO_AN_DEVAD,
6482 MDIO_AN_REG_STATUS, &val);
6483 bnx2x_cl45_read(bp, phy,
6484 MDIO_AN_DEVAD,
6485 MDIO_AN_REG_STATUS, &val);
6486 if (val & (1<<5))
6487 vars->link_status |= LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
6488 if ((val & (1<<0)) == 0)
6489 vars->link_status |= LINK_STATUS_PARALLEL_DETECTION_USED;
6490}
6491
6492/******************************************************************/
6493/* common BCM8073/BCM8727 PHY SECTION */
6494/******************************************************************/
6495static void bnx2x_8073_resolve_fc(struct bnx2x_phy *phy,
6496 struct link_params *params,
6497 struct link_vars *vars)
6498{
6499 struct bnx2x *bp = params->bp;
6500 if (phy->req_line_speed == SPEED_10 ||
6501 phy->req_line_speed == SPEED_100) {
6502 vars->flow_ctrl = phy->req_flow_ctrl;
6503 return;
6504 }
6505
6506 if (bnx2x_ext_phy_resolve_fc(phy, params, vars) &&
6507 (vars->flow_ctrl == BNX2X_FLOW_CTRL_NONE)) {
6508 u16 pause_result;
6509 u16 ld_pause; /* local */
6510 u16 lp_pause; /* link partner */
6511 bnx2x_cl45_read(bp, phy,
6512 MDIO_AN_DEVAD,
6513 MDIO_AN_REG_CL37_FC_LD, &ld_pause);
6514
6515 bnx2x_cl45_read(bp, phy,
6516 MDIO_AN_DEVAD,
6517 MDIO_AN_REG_CL37_FC_LP, &lp_pause);
6518 pause_result = (ld_pause &
6519 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 5;
6520 pause_result |= (lp_pause &
6521 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 7;
6522
6523 bnx2x_pause_resolve(vars, pause_result);
6524 DP(NETIF_MSG_LINK, "Ext PHY CL37 pause result 0x%x\n",
6525 pause_result);
6526 }
6527}
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006528static int bnx2x_8073_8727_external_rom_boot(struct bnx2x *bp,
6529 struct bnx2x_phy *phy,
6530 u8 port)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006531{
Yaniv Rosner5c99274b2011-01-18 04:33:36 +00006532 u32 count = 0;
6533 u16 fw_ver1, fw_msgout;
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006534 int rc = 0;
Yaniv Rosner5c99274b2011-01-18 04:33:36 +00006535
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006536 /* Boot port from external ROM */
6537 /* EDC grst */
6538 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006539 MDIO_PMA_DEVAD,
6540 MDIO_PMA_REG_GEN_CTRL,
6541 0x0001);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006542
6543 /* ucode reboot and rst */
6544 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006545 MDIO_PMA_DEVAD,
6546 MDIO_PMA_REG_GEN_CTRL,
6547 0x008c);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006548
6549 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006550 MDIO_PMA_DEVAD,
6551 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006552
6553 /* Reset internal microprocessor */
6554 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006555 MDIO_PMA_DEVAD,
6556 MDIO_PMA_REG_GEN_CTRL,
6557 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006558
6559 /* Release srst bit */
6560 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006561 MDIO_PMA_DEVAD,
6562 MDIO_PMA_REG_GEN_CTRL,
6563 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006564
Yaniv Rosner5c99274b2011-01-18 04:33:36 +00006565 /* Delay 100ms per the PHY specifications */
6566 msleep(100);
6567
6568 /* 8073 sometimes taking longer to download */
6569 do {
6570 count++;
6571 if (count > 300) {
6572 DP(NETIF_MSG_LINK,
6573 "bnx2x_8073_8727_external_rom_boot port %x:"
6574 "Download failed. fw version = 0x%x\n",
6575 port, fw_ver1);
6576 rc = -EINVAL;
6577 break;
6578 }
6579
6580 bnx2x_cl45_read(bp, phy,
6581 MDIO_PMA_DEVAD,
6582 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
6583 bnx2x_cl45_read(bp, phy,
6584 MDIO_PMA_DEVAD,
6585 MDIO_PMA_REG_M8051_MSGOUT_REG, &fw_msgout);
6586
6587 msleep(1);
6588 } while (fw_ver1 == 0 || fw_ver1 == 0x4321 ||
6589 ((fw_msgout & 0xff) != 0x03 && (phy->type ==
6590 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073)));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006591
6592 /* Clear ser_boot_ctl bit */
6593 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006594 MDIO_PMA_DEVAD,
6595 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006596 bnx2x_save_bcm_spirom_ver(bp, phy, port);
Yaniv Rosner5c99274b2011-01-18 04:33:36 +00006597
6598 DP(NETIF_MSG_LINK,
6599 "bnx2x_8073_8727_external_rom_boot port %x:"
6600 "Download complete. fw version = 0x%x\n",
6601 port, fw_ver1);
6602
6603 return rc;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006604}
6605
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006606/******************************************************************/
6607/* BCM8073 PHY SECTION */
6608/******************************************************************/
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006609static int bnx2x_8073_is_snr_needed(struct bnx2x *bp, struct bnx2x_phy *phy)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006610{
6611 /* This is only required for 8073A1, version 102 only */
6612 u16 val;
6613
6614 /* Read 8073 HW revision*/
6615 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006616 MDIO_PMA_DEVAD,
6617 MDIO_PMA_REG_8073_CHIP_REV, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006618
6619 if (val != 1) {
6620 /* No need to workaround in 8073 A1 */
6621 return 0;
6622 }
6623
6624 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006625 MDIO_PMA_DEVAD,
6626 MDIO_PMA_REG_ROM_VER2, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006627
6628 /* SNR should be applied only for version 0x102 */
6629 if (val != 0x102)
6630 return 0;
6631
6632 return 1;
6633}
6634
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006635static int bnx2x_8073_xaui_wa(struct bnx2x *bp, struct bnx2x_phy *phy)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006636{
6637 u16 val, cnt, cnt1 ;
6638
6639 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006640 MDIO_PMA_DEVAD,
6641 MDIO_PMA_REG_8073_CHIP_REV, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006642
6643 if (val > 0) {
6644 /* No need to workaround in 8073 A1 */
6645 return 0;
6646 }
6647 /* XAUI workaround in 8073 A0: */
6648
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006649 /*
6650 * After loading the boot ROM and restarting Autoneg, poll
6651 * Dev1, Reg $C820:
6652 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006653
6654 for (cnt = 0; cnt < 1000; cnt++) {
6655 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006656 MDIO_PMA_DEVAD,
6657 MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
6658 &val);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006659 /*
6660 * If bit [14] = 0 or bit [13] = 0, continue on with
6661 * system initialization (XAUI work-around not required, as
6662 * these bits indicate 2.5G or 1G link up).
6663 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006664 if (!(val & (1<<14)) || !(val & (1<<13))) {
6665 DP(NETIF_MSG_LINK, "XAUI work-around not required\n");
6666 return 0;
6667 } else if (!(val & (1<<15))) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006668 DP(NETIF_MSG_LINK, "bit 15 went off\n");
6669 /*
6670 * If bit 15 is 0, then poll Dev1, Reg $C841 until it's
6671 * MSB (bit15) goes to 1 (indicating that the XAUI
6672 * workaround has completed), then continue on with
6673 * system initialization.
6674 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006675 for (cnt1 = 0; cnt1 < 1000; cnt1++) {
6676 bnx2x_cl45_read(bp, phy,
6677 MDIO_PMA_DEVAD,
6678 MDIO_PMA_REG_8073_XAUI_WA, &val);
6679 if (val & (1<<15)) {
6680 DP(NETIF_MSG_LINK,
6681 "XAUI workaround has completed\n");
6682 return 0;
6683 }
6684 msleep(3);
6685 }
6686 break;
6687 }
6688 msleep(3);
6689 }
6690 DP(NETIF_MSG_LINK, "Warning: XAUI work-around timeout !!!\n");
6691 return -EINVAL;
6692}
6693
6694static void bnx2x_807x_force_10G(struct bnx2x *bp, struct bnx2x_phy *phy)
6695{
6696 /* Force KR or KX */
6697 bnx2x_cl45_write(bp, phy,
6698 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x2040);
6699 bnx2x_cl45_write(bp, phy,
6700 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0x000b);
6701 bnx2x_cl45_write(bp, phy,
6702 MDIO_PMA_DEVAD, MDIO_PMA_REG_BCM_CTRL, 0x0000);
6703 bnx2x_cl45_write(bp, phy,
6704 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x0000);
6705}
6706
6707static void bnx2x_8073_set_pause_cl37(struct link_params *params,
6708 struct bnx2x_phy *phy,
6709 struct link_vars *vars)
6710{
6711 u16 cl37_val;
6712 struct bnx2x *bp = params->bp;
6713 bnx2x_cl45_read(bp, phy,
6714 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, &cl37_val);
6715
6716 cl37_val &= ~MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
6717 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
6718 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
6719 if ((vars->ieee_fc &
6720 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) ==
6721 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) {
6722 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC;
6723 }
6724 if ((vars->ieee_fc &
6725 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
6726 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
6727 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
6728 }
6729 if ((vars->ieee_fc &
6730 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
6731 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
6732 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
6733 }
6734 DP(NETIF_MSG_LINK,
6735 "Ext phy AN advertize cl37 0x%x\n", cl37_val);
6736
6737 bnx2x_cl45_write(bp, phy,
6738 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, cl37_val);
6739 msleep(500);
6740}
6741
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006742static int bnx2x_8073_config_init(struct bnx2x_phy *phy,
6743 struct link_params *params,
6744 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006745{
6746 struct bnx2x *bp = params->bp;
6747 u16 val = 0, tmp1;
6748 u8 gpio_port;
6749 DP(NETIF_MSG_LINK, "Init 8073\n");
6750
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00006751 if (CHIP_IS_E2(bp))
6752 gpio_port = BP_PATH(bp);
6753 else
6754 gpio_port = params->port;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006755 /* Restore normal power mode*/
6756 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006757 MISC_REGISTERS_GPIO_OUTPUT_HIGH, gpio_port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006758
6759 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006760 MISC_REGISTERS_GPIO_OUTPUT_HIGH, gpio_port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006761
6762 /* enable LASI */
6763 bnx2x_cl45_write(bp, phy,
6764 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL, (1<<2));
6765 bnx2x_cl45_write(bp, phy,
6766 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x0004);
6767
6768 bnx2x_8073_set_pause_cl37(params, phy, vars);
6769
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006770 bnx2x_cl45_read(bp, phy,
6771 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &tmp1);
6772
6773 bnx2x_cl45_read(bp, phy,
6774 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &tmp1);
6775
6776 DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1): 0x%x\n", tmp1);
6777
Yaniv Rosner74d7a112011-01-18 04:33:18 +00006778 /* Swap polarity if required - Must be done only in non-1G mode */
6779 if (params->lane_config & PORT_HW_CFG_SWAP_PHY_POLARITY_ENABLED) {
6780 /* Configure the 8073 to swap _P and _N of the KR lines */
6781 DP(NETIF_MSG_LINK, "Swapping polarity for the 8073\n");
6782 /* 10G Rx/Tx and 1G Tx signal polarity swap */
6783 bnx2x_cl45_read(bp, phy,
6784 MDIO_PMA_DEVAD,
6785 MDIO_PMA_REG_8073_OPT_DIGITAL_CTRL, &val);
6786 bnx2x_cl45_write(bp, phy,
6787 MDIO_PMA_DEVAD,
6788 MDIO_PMA_REG_8073_OPT_DIGITAL_CTRL,
6789 (val | (3<<9)));
6790 }
6791
6792
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006793 /* Enable CL37 BAM */
Yaniv Rosner121839b2010-11-01 05:32:38 +00006794 if (REG_RD(bp, params->shmem_base +
6795 offsetof(struct shmem_region, dev_info.
6796 port_hw_config[params->port].default_cfg)) &
6797 PORT_HW_CFG_ENABLE_BAM_ON_KR_ENABLED) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006798
Yaniv Rosner121839b2010-11-01 05:32:38 +00006799 bnx2x_cl45_read(bp, phy,
6800 MDIO_AN_DEVAD,
6801 MDIO_AN_REG_8073_BAM, &val);
6802 bnx2x_cl45_write(bp, phy,
6803 MDIO_AN_DEVAD,
6804 MDIO_AN_REG_8073_BAM, val | 1);
6805 DP(NETIF_MSG_LINK, "Enable CL37 BAM on KR\n");
6806 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006807 if (params->loopback_mode == LOOPBACK_EXT) {
6808 bnx2x_807x_force_10G(bp, phy);
6809 DP(NETIF_MSG_LINK, "Forced speed 10G on 807X\n");
6810 return 0;
6811 } else {
6812 bnx2x_cl45_write(bp, phy,
6813 MDIO_PMA_DEVAD, MDIO_PMA_REG_BCM_CTRL, 0x0002);
6814 }
6815 if (phy->req_line_speed != SPEED_AUTO_NEG) {
6816 if (phy->req_line_speed == SPEED_10000) {
6817 val = (1<<7);
6818 } else if (phy->req_line_speed == SPEED_2500) {
6819 val = (1<<5);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006820 /*
6821 * Note that 2.5G works only when used with 1G
Lucas De Marchi25985ed2011-03-30 22:57:33 -03006822 * advertisement
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006823 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006824 } else
6825 val = (1<<5);
6826 } else {
6827 val = 0;
6828 if (phy->speed_cap_mask &
6829 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
6830 val |= (1<<7);
6831
Lucas De Marchi25985ed2011-03-30 22:57:33 -03006832 /* Note that 2.5G works only when used with 1G advertisement */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006833 if (phy->speed_cap_mask &
6834 (PORT_HW_CFG_SPEED_CAPABILITY_D0_1G |
6835 PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G))
6836 val |= (1<<5);
6837 DP(NETIF_MSG_LINK, "807x autoneg val = 0x%x\n", val);
6838 }
6839
6840 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV, val);
6841 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_8073_2_5G, &tmp1);
6842
6843 if (((phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G) &&
6844 (phy->req_line_speed == SPEED_AUTO_NEG)) ||
6845 (phy->req_line_speed == SPEED_2500)) {
6846 u16 phy_ver;
6847 /* Allow 2.5G for A1 and above */
6848 bnx2x_cl45_read(bp, phy,
6849 MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_CHIP_REV,
6850 &phy_ver);
6851 DP(NETIF_MSG_LINK, "Add 2.5G\n");
6852 if (phy_ver > 0)
6853 tmp1 |= 1;
6854 else
6855 tmp1 &= 0xfffe;
6856 } else {
6857 DP(NETIF_MSG_LINK, "Disable 2.5G\n");
6858 tmp1 &= 0xfffe;
6859 }
6860
6861 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_8073_2_5G, tmp1);
6862 /* Add support for CL37 (passive mode) II */
6863
6864 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, &tmp1);
6865 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD,
6866 (tmp1 | ((phy->req_duplex == DUPLEX_FULL) ?
6867 0x20 : 0x40)));
6868
6869 /* Add support for CL37 (passive mode) III */
6870 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
6871
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006872 /*
6873 * The SNR will improve about 2db by changing BW and FEE main
6874 * tap. Rest commands are executed after link is up
6875 * Change FFE main cursor to 5 in EDC register
6876 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006877 if (bnx2x_8073_is_snr_needed(bp, phy))
6878 bnx2x_cl45_write(bp, phy,
6879 MDIO_PMA_DEVAD, MDIO_PMA_REG_EDC_FFE_MAIN,
6880 0xFB0C);
6881
6882 /* Enable FEC (Forware Error Correction) Request in the AN */
6883 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV2, &tmp1);
6884 tmp1 |= (1<<15);
6885 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV2, tmp1);
6886
6887 bnx2x_ext_phy_set_pause(params, phy, vars);
6888
6889 /* Restart autoneg */
6890 msleep(500);
6891 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
6892 DP(NETIF_MSG_LINK, "807x Autoneg Restart: Advertise 1G=%x, 10G=%x\n",
6893 ((val & (1<<5)) > 0), ((val & (1<<7)) > 0));
6894 return 0;
6895}
6896
6897static u8 bnx2x_8073_read_status(struct bnx2x_phy *phy,
6898 struct link_params *params,
6899 struct link_vars *vars)
6900{
6901 struct bnx2x *bp = params->bp;
6902 u8 link_up = 0;
6903 u16 val1, val2;
6904 u16 link_status = 0;
6905 u16 an1000_status = 0;
6906
6907 bnx2x_cl45_read(bp, phy,
6908 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
6909
6910 DP(NETIF_MSG_LINK, "8703 LASI status 0x%x\n", val1);
6911
6912 /* clear the interrupt LASI status register */
6913 bnx2x_cl45_read(bp, phy,
6914 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val2);
6915 bnx2x_cl45_read(bp, phy,
6916 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val1);
6917 DP(NETIF_MSG_LINK, "807x PCS status 0x%x->0x%x\n", val2, val1);
6918 /* Clear MSG-OUT */
6919 bnx2x_cl45_read(bp, phy,
6920 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &val1);
6921
6922 /* Check the LASI */
6923 bnx2x_cl45_read(bp, phy,
6924 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &val2);
6925
6926 DP(NETIF_MSG_LINK, "KR 0x9003 0x%x\n", val2);
6927
6928 /* Check the link status */
6929 bnx2x_cl45_read(bp, phy,
6930 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val2);
6931 DP(NETIF_MSG_LINK, "KR PCS status 0x%x\n", val2);
6932
6933 bnx2x_cl45_read(bp, phy,
6934 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
6935 bnx2x_cl45_read(bp, phy,
6936 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
6937 link_up = ((val1 & 4) == 4);
6938 DP(NETIF_MSG_LINK, "PMA_REG_STATUS=0x%x\n", val1);
6939
6940 if (link_up &&
6941 ((phy->req_line_speed != SPEED_10000))) {
6942 if (bnx2x_8073_xaui_wa(bp, phy) != 0)
6943 return 0;
6944 }
6945 bnx2x_cl45_read(bp, phy,
6946 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &an1000_status);
6947 bnx2x_cl45_read(bp, phy,
6948 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &an1000_status);
6949
6950 /* Check the link status on 1.1.2 */
6951 bnx2x_cl45_read(bp, phy,
6952 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
6953 bnx2x_cl45_read(bp, phy,
6954 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
6955 DP(NETIF_MSG_LINK, "KR PMA status 0x%x->0x%x,"
6956 "an_link_status=0x%x\n", val2, val1, an1000_status);
6957
6958 link_up = (((val1 & 4) == 4) || (an1000_status & (1<<1)));
6959 if (link_up && bnx2x_8073_is_snr_needed(bp, phy)) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006960 /*
6961 * The SNR will improve about 2dbby changing the BW and FEE main
6962 * tap. The 1st write to change FFE main tap is set before
6963 * restart AN. Change PLL Bandwidth in EDC register
6964 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006965 bnx2x_cl45_write(bp, phy,
6966 MDIO_PMA_DEVAD, MDIO_PMA_REG_PLL_BANDWIDTH,
6967 0x26BC);
6968
6969 /* Change CDR Bandwidth in EDC register */
6970 bnx2x_cl45_write(bp, phy,
6971 MDIO_PMA_DEVAD, MDIO_PMA_REG_CDR_BANDWIDTH,
6972 0x0333);
6973 }
6974 bnx2x_cl45_read(bp, phy,
6975 MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
6976 &link_status);
6977
6978 /* Bits 0..2 --> speed detected, bits 13..15--> link is down */
6979 if ((link_status & (1<<2)) && (!(link_status & (1<<15)))) {
6980 link_up = 1;
6981 vars->line_speed = SPEED_10000;
6982 DP(NETIF_MSG_LINK, "port %x: External link up in 10G\n",
6983 params->port);
6984 } else if ((link_status & (1<<1)) && (!(link_status & (1<<14)))) {
6985 link_up = 1;
6986 vars->line_speed = SPEED_2500;
6987 DP(NETIF_MSG_LINK, "port %x: External link up in 2.5G\n",
6988 params->port);
6989 } else if ((link_status & (1<<0)) && (!(link_status & (1<<13)))) {
6990 link_up = 1;
6991 vars->line_speed = SPEED_1000;
6992 DP(NETIF_MSG_LINK, "port %x: External link up in 1G\n",
6993 params->port);
6994 } else {
6995 link_up = 0;
6996 DP(NETIF_MSG_LINK, "port %x: External link is down\n",
6997 params->port);
6998 }
6999
7000 if (link_up) {
Yaniv Rosner74d7a112011-01-18 04:33:18 +00007001 /* Swap polarity if required */
7002 if (params->lane_config &
7003 PORT_HW_CFG_SWAP_PHY_POLARITY_ENABLED) {
7004 /* Configure the 8073 to swap P and N of the KR lines */
7005 bnx2x_cl45_read(bp, phy,
7006 MDIO_XS_DEVAD,
7007 MDIO_XS_REG_8073_RX_CTRL_PCIE, &val1);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007008 /*
7009 * Set bit 3 to invert Rx in 1G mode and clear this bit
7010 * when it`s in 10G mode.
7011 */
Yaniv Rosner74d7a112011-01-18 04:33:18 +00007012 if (vars->line_speed == SPEED_1000) {
7013 DP(NETIF_MSG_LINK, "Swapping 1G polarity for"
7014 "the 8073\n");
7015 val1 |= (1<<3);
7016 } else
7017 val1 &= ~(1<<3);
7018
7019 bnx2x_cl45_write(bp, phy,
7020 MDIO_XS_DEVAD,
7021 MDIO_XS_REG_8073_RX_CTRL_PCIE,
7022 val1);
7023 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007024 bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
7025 bnx2x_8073_resolve_fc(phy, params, vars);
Yaniv Rosner791f18c2011-01-18 04:33:42 +00007026 vars->duplex = DUPLEX_FULL;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007027 }
7028 return link_up;
7029}
7030
7031static void bnx2x_8073_link_reset(struct bnx2x_phy *phy,
7032 struct link_params *params)
7033{
7034 struct bnx2x *bp = params->bp;
7035 u8 gpio_port;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007036 if (CHIP_IS_E2(bp))
7037 gpio_port = BP_PATH(bp);
7038 else
7039 gpio_port = params->port;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007040 DP(NETIF_MSG_LINK, "Setting 8073 port %d into low power mode\n",
7041 gpio_port);
7042 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007043 MISC_REGISTERS_GPIO_OUTPUT_LOW,
7044 gpio_port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007045}
7046
7047/******************************************************************/
7048/* BCM8705 PHY SECTION */
7049/******************************************************************/
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00007050static int bnx2x_8705_config_init(struct bnx2x_phy *phy,
7051 struct link_params *params,
7052 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007053{
7054 struct bnx2x *bp = params->bp;
7055 DP(NETIF_MSG_LINK, "init 8705\n");
7056 /* Restore normal power mode*/
7057 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007058 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007059 /* HW reset */
7060 bnx2x_ext_phy_hw_reset(bp, params->port);
7061 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0xa040);
Yaniv Rosner6d870c32011-01-31 04:22:20 +00007062 bnx2x_wait_reset_complete(bp, phy, params);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007063
7064 bnx2x_cl45_write(bp, phy,
7065 MDIO_PMA_DEVAD, MDIO_PMA_REG_MISC_CTRL, 0x8288);
7066 bnx2x_cl45_write(bp, phy,
7067 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, 0x7fbf);
7068 bnx2x_cl45_write(bp, phy,
7069 MDIO_PMA_DEVAD, MDIO_PMA_REG_CMU_PLL_BYPASS, 0x0100);
7070 bnx2x_cl45_write(bp, phy,
7071 MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_CNTL, 0x1);
7072 /* BCM8705 doesn't have microcode, hence the 0 */
7073 bnx2x_save_spirom_version(bp, params->port, params->shmem_base, 0);
7074 return 0;
7075}
7076
7077static u8 bnx2x_8705_read_status(struct bnx2x_phy *phy,
7078 struct link_params *params,
7079 struct link_vars *vars)
7080{
7081 u8 link_up = 0;
7082 u16 val1, rx_sd;
7083 struct bnx2x *bp = params->bp;
7084 DP(NETIF_MSG_LINK, "read status 8705\n");
7085 bnx2x_cl45_read(bp, phy,
7086 MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_STATUS, &val1);
7087 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
7088
7089 bnx2x_cl45_read(bp, phy,
7090 MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_STATUS, &val1);
7091 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
7092
7093 bnx2x_cl45_read(bp, phy,
7094 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD, &rx_sd);
7095
7096 bnx2x_cl45_read(bp, phy,
7097 MDIO_PMA_DEVAD, 0xc809, &val1);
7098 bnx2x_cl45_read(bp, phy,
7099 MDIO_PMA_DEVAD, 0xc809, &val1);
7100
7101 DP(NETIF_MSG_LINK, "8705 1.c809 val=0x%x\n", val1);
7102 link_up = ((rx_sd & 0x1) && (val1 & (1<<9)) && ((val1 & (1<<8)) == 0));
7103 if (link_up) {
7104 vars->line_speed = SPEED_10000;
7105 bnx2x_ext_phy_resolve_fc(phy, params, vars);
7106 }
7107 return link_up;
7108}
7109
7110/******************************************************************/
7111/* SFP+ module Section */
7112/******************************************************************/
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00007113static u8 bnx2x_get_gpio_port(struct link_params *params)
7114{
7115 u8 gpio_port;
7116 u32 swap_val, swap_override;
7117 struct bnx2x *bp = params->bp;
7118 if (CHIP_IS_E2(bp))
7119 gpio_port = BP_PATH(bp);
7120 else
7121 gpio_port = params->port;
7122 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
7123 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
7124 return gpio_port ^ (swap_val && swap_override);
7125}
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00007126
7127static void bnx2x_sfp_e1e2_set_transmitter(struct link_params *params,
7128 struct bnx2x_phy *phy,
7129 u8 tx_en)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007130{
7131 u16 val;
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00007132 u8 port = params->port;
7133 struct bnx2x *bp = params->bp;
7134 u32 tx_en_mode;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007135
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007136 /* Disable/Enable transmitter ( TX laser of the SFP+ module.)*/
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00007137 tx_en_mode = REG_RD(bp, params->shmem_base +
7138 offsetof(struct shmem_region,
7139 dev_info.port_hw_config[port].sfp_ctrl)) &
7140 PORT_HW_CFG_TX_LASER_MASK;
7141 DP(NETIF_MSG_LINK, "Setting transmitter tx_en=%x for port %x "
7142 "mode = %x\n", tx_en, port, tx_en_mode);
7143 switch (tx_en_mode) {
7144 case PORT_HW_CFG_TX_LASER_MDIO:
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007145
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00007146 bnx2x_cl45_read(bp, phy,
7147 MDIO_PMA_DEVAD,
7148 MDIO_PMA_REG_PHY_IDENTIFIER,
7149 &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007150
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00007151 if (tx_en)
7152 val &= ~(1<<15);
7153 else
7154 val |= (1<<15);
7155
7156 bnx2x_cl45_write(bp, phy,
7157 MDIO_PMA_DEVAD,
7158 MDIO_PMA_REG_PHY_IDENTIFIER,
7159 val);
7160 break;
7161 case PORT_HW_CFG_TX_LASER_GPIO0:
7162 case PORT_HW_CFG_TX_LASER_GPIO1:
7163 case PORT_HW_CFG_TX_LASER_GPIO2:
7164 case PORT_HW_CFG_TX_LASER_GPIO3:
7165 {
7166 u16 gpio_pin;
7167 u8 gpio_port, gpio_mode;
7168 if (tx_en)
7169 gpio_mode = MISC_REGISTERS_GPIO_OUTPUT_HIGH;
7170 else
7171 gpio_mode = MISC_REGISTERS_GPIO_OUTPUT_LOW;
7172
7173 gpio_pin = tx_en_mode - PORT_HW_CFG_TX_LASER_GPIO0;
7174 gpio_port = bnx2x_get_gpio_port(params);
7175 bnx2x_set_gpio(bp, gpio_pin, gpio_mode, gpio_port);
7176 break;
7177 }
7178 default:
7179 DP(NETIF_MSG_LINK, "Invalid TX_LASER_MDIO 0x%x\n", tx_en_mode);
7180 break;
7181 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007182}
7183
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00007184static void bnx2x_sfp_set_transmitter(struct link_params *params,
7185 struct bnx2x_phy *phy,
7186 u8 tx_en)
7187{
7188 struct bnx2x *bp = params->bp;
7189 DP(NETIF_MSG_LINK, "Setting SFP+ transmitter to %d\n", tx_en);
7190 if (CHIP_IS_E3(bp))
7191 bnx2x_sfp_e3_set_transmitter(params, phy, tx_en);
7192 else
7193 bnx2x_sfp_e1e2_set_transmitter(params, phy, tx_en);
7194}
7195
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00007196static int bnx2x_8726_read_sfp_module_eeprom(struct bnx2x_phy *phy,
7197 struct link_params *params,
7198 u16 addr, u8 byte_cnt, u8 *o_buf)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007199{
7200 struct bnx2x *bp = params->bp;
7201 u16 val = 0;
7202 u16 i;
7203 if (byte_cnt > 16) {
7204 DP(NETIF_MSG_LINK, "Reading from eeprom is"
7205 " is limited to 0xf\n");
7206 return -EINVAL;
7207 }
7208 /* Set the read command byte count */
7209 bnx2x_cl45_write(bp, phy,
7210 MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007211 (byte_cnt | 0xa000));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007212
7213 /* Set the read command address */
7214 bnx2x_cl45_write(bp, phy,
7215 MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007216 addr);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007217
7218 /* Activate read command */
7219 bnx2x_cl45_write(bp, phy,
7220 MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007221 0x2c0f);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007222
7223 /* Wait up to 500us for command complete status */
7224 for (i = 0; i < 100; i++) {
7225 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007226 MDIO_PMA_DEVAD,
7227 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007228 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
7229 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
7230 break;
7231 udelay(5);
7232 }
7233
7234 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
7235 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
7236 DP(NETIF_MSG_LINK,
7237 "Got bad status 0x%x when reading from SFP+ EEPROM\n",
7238 (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
7239 return -EINVAL;
7240 }
7241
7242 /* Read the buffer */
7243 for (i = 0; i < byte_cnt; i++) {
7244 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007245 MDIO_PMA_DEVAD,
7246 MDIO_PMA_REG_8726_TWO_WIRE_DATA_BUF + i, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007247 o_buf[i] = (u8)(val & MDIO_PMA_REG_8726_TWO_WIRE_DATA_MASK);
7248 }
7249
7250 for (i = 0; i < 100; i++) {
7251 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007252 MDIO_PMA_DEVAD,
7253 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007254 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
7255 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
Joe Perches6f38ad92010-11-14 17:04:31 +00007256 return 0;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007257 msleep(1);
7258 }
7259 return -EINVAL;
7260}
7261
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00007262static int bnx2x_warpcore_read_sfp_module_eeprom(struct bnx2x_phy *phy,
7263 struct link_params *params,
7264 u16 addr, u8 byte_cnt,
7265 u8 *o_buf)
7266{
7267 int rc = 0;
7268 u8 i, j = 0, cnt = 0;
7269 u32 data_array[4];
7270 u16 addr32;
7271 struct bnx2x *bp = params->bp;
7272 /*DP(NETIF_MSG_LINK, "bnx2x_direct_read_sfp_module_eeprom:"
7273 " addr %d, cnt %d\n",
7274 addr, byte_cnt);*/
7275 if (byte_cnt > 16) {
7276 DP(NETIF_MSG_LINK, "Reading from eeprom is"
7277 " is limited to 16 bytes\n");
7278 return -EINVAL;
7279 }
7280
7281 /* 4 byte aligned address */
7282 addr32 = addr & (~0x3);
7283 do {
7284 rc = bnx2x_bsc_read(params, phy, 0xa0, addr32, 0, byte_cnt,
7285 data_array);
7286 } while ((rc != 0) && (++cnt < I2C_WA_RETRY_CNT));
7287
7288 if (rc == 0) {
7289 for (i = (addr - addr32); i < byte_cnt + (addr - addr32); i++) {
7290 o_buf[j] = *((u8 *)data_array + i);
7291 j++;
7292 }
7293 }
7294
7295 return rc;
7296}
7297
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00007298static int bnx2x_8727_read_sfp_module_eeprom(struct bnx2x_phy *phy,
7299 struct link_params *params,
7300 u16 addr, u8 byte_cnt, u8 *o_buf)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007301{
7302 struct bnx2x *bp = params->bp;
7303 u16 val, i;
7304
7305 if (byte_cnt > 16) {
7306 DP(NETIF_MSG_LINK, "Reading from eeprom is"
7307 " is limited to 0xf\n");
7308 return -EINVAL;
7309 }
7310
7311 /* Need to read from 1.8000 to clear it */
7312 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007313 MDIO_PMA_DEVAD,
7314 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
7315 &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007316
7317 /* Set the read command byte count */
7318 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007319 MDIO_PMA_DEVAD,
7320 MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
7321 ((byte_cnt < 2) ? 2 : byte_cnt));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007322
7323 /* Set the read command address */
7324 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007325 MDIO_PMA_DEVAD,
7326 MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
7327 addr);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007328 /* Set the destination address */
7329 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007330 MDIO_PMA_DEVAD,
7331 0x8004,
7332 MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007333
7334 /* Activate read command */
7335 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007336 MDIO_PMA_DEVAD,
7337 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
7338 0x8002);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007339 /*
7340 * Wait appropriate time for two-wire command to finish before
7341 * polling the status register
7342 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007343 msleep(1);
7344
7345 /* Wait up to 500us for command complete status */
7346 for (i = 0; i < 100; i++) {
7347 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007348 MDIO_PMA_DEVAD,
7349 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007350 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
7351 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
7352 break;
7353 udelay(5);
7354 }
7355
7356 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
7357 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
7358 DP(NETIF_MSG_LINK,
7359 "Got bad status 0x%x when reading from SFP+ EEPROM\n",
7360 (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
Yaniv Rosner65a001b2011-01-31 04:22:03 +00007361 return -EFAULT;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007362 }
7363
7364 /* Read the buffer */
7365 for (i = 0; i < byte_cnt; i++) {
7366 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007367 MDIO_PMA_DEVAD,
7368 MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF + i, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007369 o_buf[i] = (u8)(val & MDIO_PMA_REG_8727_TWO_WIRE_DATA_MASK);
7370 }
7371
7372 for (i = 0; i < 100; i++) {
7373 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007374 MDIO_PMA_DEVAD,
7375 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007376 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
7377 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
Joe Perches6f38ad92010-11-14 17:04:31 +00007378 return 0;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007379 msleep(1);
7380 }
7381
7382 return -EINVAL;
7383}
7384
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00007385int bnx2x_read_sfp_module_eeprom(struct bnx2x_phy *phy,
7386 struct link_params *params, u16 addr,
7387 u8 byte_cnt, u8 *o_buf)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007388{
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00007389 int rc = -EINVAL;
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00007390 switch (phy->type) {
7391 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
7392 rc = bnx2x_8726_read_sfp_module_eeprom(phy, params, addr,
7393 byte_cnt, o_buf);
7394 break;
7395 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
7396 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722:
7397 rc = bnx2x_8727_read_sfp_module_eeprom(phy, params, addr,
7398 byte_cnt, o_buf);
7399 break;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00007400 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
7401 rc = bnx2x_warpcore_read_sfp_module_eeprom(phy, params, addr,
7402 byte_cnt, o_buf);
7403 break;
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00007404 }
7405 return rc;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007406}
7407
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00007408static int bnx2x_get_edc_mode(struct bnx2x_phy *phy,
7409 struct link_params *params,
7410 u16 *edc_mode)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007411{
7412 struct bnx2x *bp = params->bp;
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00007413 u32 sync_offset = 0, phy_idx, media_types;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007414 u8 val, check_limiting_mode = 0;
7415 *edc_mode = EDC_MODE_LIMITING;
7416
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00007417 phy->media_type = ETH_PHY_UNSPECIFIED;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007418 /* First check for copper cable */
7419 if (bnx2x_read_sfp_module_eeprom(phy,
7420 params,
7421 SFP_EEPROM_CON_TYPE_ADDR,
7422 1,
7423 &val) != 0) {
7424 DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM\n");
7425 return -EINVAL;
7426 }
7427
7428 switch (val) {
7429 case SFP_EEPROM_CON_TYPE_VAL_COPPER:
7430 {
7431 u8 copper_module_type;
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00007432 phy->media_type = ETH_PHY_DA_TWINAX;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007433 /*
7434 * Check if its active cable (includes SFP+ module)
7435 * of passive cable
7436 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007437 if (bnx2x_read_sfp_module_eeprom(phy,
7438 params,
7439 SFP_EEPROM_FC_TX_TECH_ADDR,
7440 1,
Yaniv Rosner9045f6b2011-05-31 21:28:27 +00007441 &copper_module_type) != 0) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007442 DP(NETIF_MSG_LINK,
7443 "Failed to read copper-cable-type"
7444 " from SFP+ EEPROM\n");
7445 return -EINVAL;
7446 }
7447
7448 if (copper_module_type &
7449 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE) {
7450 DP(NETIF_MSG_LINK, "Active Copper cable detected\n");
7451 check_limiting_mode = 1;
7452 } else if (copper_module_type &
7453 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE) {
7454 DP(NETIF_MSG_LINK, "Passive Copper"
7455 " cable detected\n");
7456 *edc_mode =
7457 EDC_MODE_PASSIVE_DAC;
7458 } else {
7459 DP(NETIF_MSG_LINK, "Unknown copper-cable-"
7460 "type 0x%x !!!\n", copper_module_type);
7461 return -EINVAL;
7462 }
7463 break;
7464 }
7465 case SFP_EEPROM_CON_TYPE_VAL_LC:
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00007466 phy->media_type = ETH_PHY_SFP_FIBER;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007467 DP(NETIF_MSG_LINK, "Optic module detected\n");
7468 check_limiting_mode = 1;
7469 break;
7470 default:
7471 DP(NETIF_MSG_LINK, "Unable to determine module type 0x%x !!!\n",
7472 val);
7473 return -EINVAL;
7474 }
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00007475 sync_offset = params->shmem_base +
7476 offsetof(struct shmem_region,
7477 dev_info.port_hw_config[params->port].media_type);
7478 media_types = REG_RD(bp, sync_offset);
7479 /* Update media type for non-PMF sync */
7480 for (phy_idx = INT_PHY; phy_idx < MAX_PHYS; phy_idx++) {
7481 if (&(params->phy[phy_idx]) == phy) {
7482 media_types &= ~(PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK <<
7483 (PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT * phy_idx));
7484 media_types |= ((phy->media_type &
7485 PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK) <<
7486 (PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT * phy_idx));
7487 break;
7488 }
7489 }
7490 REG_WR(bp, sync_offset, media_types);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007491 if (check_limiting_mode) {
7492 u8 options[SFP_EEPROM_OPTIONS_SIZE];
7493 if (bnx2x_read_sfp_module_eeprom(phy,
7494 params,
7495 SFP_EEPROM_OPTIONS_ADDR,
7496 SFP_EEPROM_OPTIONS_SIZE,
7497 options) != 0) {
7498 DP(NETIF_MSG_LINK, "Failed to read Option"
7499 " field from module EEPROM\n");
7500 return -EINVAL;
7501 }
7502 if ((options[0] & SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK))
7503 *edc_mode = EDC_MODE_LINEAR;
7504 else
7505 *edc_mode = EDC_MODE_LIMITING;
7506 }
7507 DP(NETIF_MSG_LINK, "EDC mode is set to 0x%x\n", *edc_mode);
7508 return 0;
7509}
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007510/*
7511 * This function read the relevant field from the module (SFP+), and verify it
7512 * is compliant with this board
7513 */
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00007514static int bnx2x_verify_sfp_module(struct bnx2x_phy *phy,
7515 struct link_params *params)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007516{
7517 struct bnx2x *bp = params->bp;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007518 u32 val, cmd;
7519 u32 fw_resp, fw_cmd_param;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007520 char vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE+1];
7521 char vendor_pn[SFP_EEPROM_PART_NO_SIZE+1];
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007522 phy->flags &= ~FLAGS_SFP_NOT_APPROVED;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007523 val = REG_RD(bp, params->shmem_base +
7524 offsetof(struct shmem_region, dev_info.
7525 port_feature_config[params->port].config));
7526 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
7527 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_NO_ENFORCEMENT) {
7528 DP(NETIF_MSG_LINK, "NOT enforcing module verification\n");
7529 return 0;
7530 }
7531
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007532 if (params->feature_config_flags &
7533 FEATURE_CONFIG_BC_SUPPORTS_DUAL_PHY_OPT_MDL_VRFY) {
7534 /* Use specific phy request */
7535 cmd = DRV_MSG_CODE_VRFY_SPECIFIC_PHY_OPT_MDL;
7536 } else if (params->feature_config_flags &
7537 FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY) {
7538 /* Use first phy request only in case of non-dual media*/
7539 if (DUAL_MEDIA(params)) {
7540 DP(NETIF_MSG_LINK, "FW does not support OPT MDL "
7541 "verification\n");
7542 return -EINVAL;
7543 }
7544 cmd = DRV_MSG_CODE_VRFY_FIRST_PHY_OPT_MDL;
7545 } else {
7546 /* No support in OPT MDL detection */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007547 DP(NETIF_MSG_LINK, "FW does not support OPT MDL "
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007548 "verification\n");
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007549 return -EINVAL;
7550 }
Dmitry Kravkov523224a2010-10-06 03:23:26 +00007551
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007552 fw_cmd_param = FW_PARAM_SET(phy->addr, phy->type, phy->mdio_ctrl);
7553 fw_resp = bnx2x_fw_command(bp, cmd, fw_cmd_param);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007554 if (fw_resp == FW_MSG_CODE_VRFY_OPT_MDL_SUCCESS) {
7555 DP(NETIF_MSG_LINK, "Approved module\n");
7556 return 0;
7557 }
7558
7559 /* format the warning message */
7560 if (bnx2x_read_sfp_module_eeprom(phy,
7561 params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007562 SFP_EEPROM_VENDOR_NAME_ADDR,
7563 SFP_EEPROM_VENDOR_NAME_SIZE,
7564 (u8 *)vendor_name))
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007565 vendor_name[0] = '\0';
7566 else
7567 vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE] = '\0';
7568 if (bnx2x_read_sfp_module_eeprom(phy,
7569 params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007570 SFP_EEPROM_PART_NO_ADDR,
7571 SFP_EEPROM_PART_NO_SIZE,
7572 (u8 *)vendor_pn))
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007573 vendor_pn[0] = '\0';
7574 else
7575 vendor_pn[SFP_EEPROM_PART_NO_SIZE] = '\0';
7576
Yaniv Rosner6d870c32011-01-31 04:22:20 +00007577 netdev_err(bp->dev, "Warning: Unqualified SFP+ module detected,"
7578 " Port %d from %s part number %s\n",
7579 params->port, vendor_name, vendor_pn);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007580 phy->flags |= FLAGS_SFP_NOT_APPROVED;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007581 return -EINVAL;
7582}
7583
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00007584static int bnx2x_wait_for_sfp_module_initialized(struct bnx2x_phy *phy,
7585 struct link_params *params)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007586
7587{
7588 u8 val;
7589 struct bnx2x *bp = params->bp;
7590 u16 timeout;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007591 /*
7592 * Initialization time after hot-plug may take up to 300ms for
7593 * some phys type ( e.g. JDSU )
7594 */
7595
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007596 for (timeout = 0; timeout < 60; timeout++) {
7597 if (bnx2x_read_sfp_module_eeprom(phy, params, 1, 1, &val)
7598 == 0) {
7599 DP(NETIF_MSG_LINK, "SFP+ module initialization "
7600 "took %d ms\n", timeout * 5);
7601 return 0;
7602 }
7603 msleep(5);
7604 }
7605 return -EINVAL;
7606}
7607
7608static void bnx2x_8727_power_module(struct bnx2x *bp,
7609 struct bnx2x_phy *phy,
7610 u8 is_power_up) {
7611 /* Make sure GPIOs are not using for LED mode */
7612 u16 val;
7613 /*
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007614 * In the GPIO register, bit 4 is use to determine if the GPIOs are
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007615 * operating as INPUT or as OUTPUT. Bit 1 is for input, and 0 for
7616 * output
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00007617 * Bits 0-1 determine the GPIOs value for OUTPUT in case bit 4 val is 0
7618 * Bits 8-9 determine the GPIOs value for INPUT in case bit 4 val is 1
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007619 * where the 1st bit is the over-current(only input), and 2nd bit is
7620 * for power( only output )
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007621 *
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007622 * In case of NOC feature is disabled and power is up, set GPIO control
7623 * as input to enable listening of over-current indication
7624 */
7625 if (phy->flags & FLAGS_NOC)
7626 return;
Yaniv Rosner27d02432011-05-31 21:27:48 +00007627 if (is_power_up)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007628 val = (1<<4);
7629 else
7630 /*
7631 * Set GPIO control to OUTPUT, and set the power bit
7632 * to according to the is_power_up
7633 */
Yaniv Rosner27d02432011-05-31 21:27:48 +00007634 val = (1<<1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007635
7636 bnx2x_cl45_write(bp, phy,
7637 MDIO_PMA_DEVAD,
7638 MDIO_PMA_REG_8727_GPIO_CTRL,
7639 val);
7640}
7641
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00007642static int bnx2x_8726_set_limiting_mode(struct bnx2x *bp,
7643 struct bnx2x_phy *phy,
7644 u16 edc_mode)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007645{
7646 u16 cur_limiting_mode;
7647
7648 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007649 MDIO_PMA_DEVAD,
7650 MDIO_PMA_REG_ROM_VER2,
7651 &cur_limiting_mode);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007652 DP(NETIF_MSG_LINK, "Current Limiting mode is 0x%x\n",
7653 cur_limiting_mode);
7654
7655 if (edc_mode == EDC_MODE_LIMITING) {
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007656 DP(NETIF_MSG_LINK, "Setting LIMITING MODE\n");
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007657 bnx2x_cl45_write(bp, phy,
7658 MDIO_PMA_DEVAD,
7659 MDIO_PMA_REG_ROM_VER2,
7660 EDC_MODE_LIMITING);
7661 } else { /* LRM mode ( default )*/
7662
7663 DP(NETIF_MSG_LINK, "Setting LRM MODE\n");
7664
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007665 /*
7666 * Changing to LRM mode takes quite few seconds. So do it only
7667 * if current mode is limiting (default is LRM)
7668 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007669 if (cur_limiting_mode != EDC_MODE_LIMITING)
7670 return 0;
7671
7672 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007673 MDIO_PMA_DEVAD,
7674 MDIO_PMA_REG_LRM_MODE,
7675 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007676 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007677 MDIO_PMA_DEVAD,
7678 MDIO_PMA_REG_ROM_VER2,
7679 0x128);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007680 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007681 MDIO_PMA_DEVAD,
7682 MDIO_PMA_REG_MISC_CTRL0,
7683 0x4008);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007684 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007685 MDIO_PMA_DEVAD,
7686 MDIO_PMA_REG_LRM_MODE,
7687 0xaaaa);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007688 }
7689 return 0;
7690}
7691
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00007692static int bnx2x_8727_set_limiting_mode(struct bnx2x *bp,
7693 struct bnx2x_phy *phy,
7694 u16 edc_mode)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007695{
7696 u16 phy_identifier;
7697 u16 rom_ver2_val;
7698 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007699 MDIO_PMA_DEVAD,
7700 MDIO_PMA_REG_PHY_IDENTIFIER,
7701 &phy_identifier);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007702
7703 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007704 MDIO_PMA_DEVAD,
7705 MDIO_PMA_REG_PHY_IDENTIFIER,
7706 (phy_identifier & ~(1<<9)));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007707
7708 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007709 MDIO_PMA_DEVAD,
7710 MDIO_PMA_REG_ROM_VER2,
7711 &rom_ver2_val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007712 /* Keep the MSB 8-bits, and set the LSB 8-bits with the edc_mode */
7713 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007714 MDIO_PMA_DEVAD,
7715 MDIO_PMA_REG_ROM_VER2,
7716 (rom_ver2_val & 0xff00) | (edc_mode & 0x00ff));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007717
7718 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007719 MDIO_PMA_DEVAD,
7720 MDIO_PMA_REG_PHY_IDENTIFIER,
7721 (phy_identifier | (1<<9)));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007722
7723 return 0;
7724}
7725
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007726static void bnx2x_8727_specific_func(struct bnx2x_phy *phy,
7727 struct link_params *params,
7728 u32 action)
7729{
7730 struct bnx2x *bp = params->bp;
7731
7732 switch (action) {
7733 case DISABLE_TX:
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00007734 bnx2x_sfp_set_transmitter(params, phy, 0);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007735 break;
7736 case ENABLE_TX:
7737 if (!(phy->flags & FLAGS_SFP_NOT_APPROVED))
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00007738 bnx2x_sfp_set_transmitter(params, phy, 1);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007739 break;
7740 default:
7741 DP(NETIF_MSG_LINK, "Function 0x%x not supported by 8727\n",
7742 action);
7743 return;
7744 }
7745}
7746
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00007747static void bnx2x_set_e1e2_module_fault_led(struct link_params *params,
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00007748 u8 gpio_mode)
7749{
7750 struct bnx2x *bp = params->bp;
7751
7752 u32 fault_led_gpio = REG_RD(bp, params->shmem_base +
7753 offsetof(struct shmem_region,
7754 dev_info.port_hw_config[params->port].sfp_ctrl)) &
7755 PORT_HW_CFG_FAULT_MODULE_LED_MASK;
7756 switch (fault_led_gpio) {
7757 case PORT_HW_CFG_FAULT_MODULE_LED_DISABLED:
7758 return;
7759 case PORT_HW_CFG_FAULT_MODULE_LED_GPIO0:
7760 case PORT_HW_CFG_FAULT_MODULE_LED_GPIO1:
7761 case PORT_HW_CFG_FAULT_MODULE_LED_GPIO2:
7762 case PORT_HW_CFG_FAULT_MODULE_LED_GPIO3:
7763 {
7764 u8 gpio_port = bnx2x_get_gpio_port(params);
7765 u16 gpio_pin = fault_led_gpio -
7766 PORT_HW_CFG_FAULT_MODULE_LED_GPIO0;
7767 DP(NETIF_MSG_LINK, "Set fault module-detected led "
7768 "pin %x port %x mode %x\n",
7769 gpio_pin, gpio_port, gpio_mode);
7770 bnx2x_set_gpio(bp, gpio_pin, gpio_mode, gpio_port);
7771 }
7772 break;
7773 default:
7774 DP(NETIF_MSG_LINK, "Error: Invalid fault led mode 0x%x\n",
7775 fault_led_gpio);
7776 }
7777}
7778
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00007779static void bnx2x_set_e3_module_fault_led(struct link_params *params,
7780 u8 gpio_mode)
7781{
7782 u32 pin_cfg;
7783 u8 port = params->port;
7784 struct bnx2x *bp = params->bp;
7785 pin_cfg = (REG_RD(bp, params->shmem_base +
7786 offsetof(struct shmem_region,
7787 dev_info.port_hw_config[port].e3_sfp_ctrl)) &
7788 PORT_HW_CFG_E3_FAULT_MDL_LED_MASK) >>
7789 PORT_HW_CFG_E3_FAULT_MDL_LED_SHIFT;
7790 DP(NETIF_MSG_LINK, "Setting Fault LED to %d using pin cfg %d\n",
7791 gpio_mode, pin_cfg);
7792 bnx2x_set_cfg_pin(bp, pin_cfg, gpio_mode);
7793}
7794
7795static void bnx2x_set_sfp_module_fault_led(struct link_params *params,
7796 u8 gpio_mode)
7797{
7798 struct bnx2x *bp = params->bp;
7799 DP(NETIF_MSG_LINK, "Setting SFP+ module fault LED to %d\n", gpio_mode);
7800 if (CHIP_IS_E3(bp)) {
7801 /*
7802 * Low ==> if SFP+ module is supported otherwise
7803 * High ==> if SFP+ module is not on the approved vendor list
7804 */
7805 bnx2x_set_e3_module_fault_led(params, gpio_mode);
7806 } else
7807 bnx2x_set_e1e2_module_fault_led(params, gpio_mode);
7808}
7809
7810static void bnx2x_warpcore_power_module(struct link_params *params,
7811 struct bnx2x_phy *phy,
7812 u8 power)
7813{
7814 u32 pin_cfg;
7815 struct bnx2x *bp = params->bp;
7816
7817 pin_cfg = (REG_RD(bp, params->shmem_base +
7818 offsetof(struct shmem_region,
7819 dev_info.port_hw_config[params->port].e3_sfp_ctrl)) &
7820 PORT_HW_CFG_E3_PWR_DIS_MASK) >>
7821 PORT_HW_CFG_E3_PWR_DIS_SHIFT;
7822 DP(NETIF_MSG_LINK, "Setting SFP+ module power to %d using pin cfg %d\n",
7823 power, pin_cfg);
7824 /*
7825 * Low ==> corresponding SFP+ module is powered
7826 * high ==> the SFP+ module is powered down
7827 */
7828 bnx2x_set_cfg_pin(bp, pin_cfg, power ^ 1);
7829}
7830
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00007831static void bnx2x_power_sfp_module(struct link_params *params,
7832 struct bnx2x_phy *phy,
7833 u8 power)
7834{
7835 struct bnx2x *bp = params->bp;
7836 DP(NETIF_MSG_LINK, "Setting SFP+ power to %x\n", power);
7837
7838 switch (phy->type) {
7839 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
7840 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722:
7841 bnx2x_8727_power_module(params->bp, phy, power);
7842 break;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00007843 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
7844 bnx2x_warpcore_power_module(params, phy, power);
7845 break;
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00007846 default:
7847 break;
7848 }
7849}
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00007850static void bnx2x_warpcore_set_limiting_mode(struct link_params *params,
7851 struct bnx2x_phy *phy,
7852 u16 edc_mode)
7853{
7854 u16 val = 0;
7855 u16 mode = MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE_DEFAULT;
7856 struct bnx2x *bp = params->bp;
7857
7858 u8 lane = bnx2x_get_warpcore_lane(phy, params);
7859 /* This is a global register which controls all lanes */
7860 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
7861 MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE, &val);
7862 val &= ~(0xf << (lane << 2));
7863
7864 switch (edc_mode) {
7865 case EDC_MODE_LINEAR:
7866 case EDC_MODE_LIMITING:
7867 mode = MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE_DEFAULT;
7868 break;
7869 case EDC_MODE_PASSIVE_DAC:
7870 mode = MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE_SFP_DAC;
7871 break;
7872 default:
7873 break;
7874 }
7875
7876 val |= (mode << (lane << 2));
7877 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
7878 MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE, val);
7879 /* A must read */
7880 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
7881 MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE, &val);
7882
7883
7884}
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00007885
7886static void bnx2x_set_limiting_mode(struct link_params *params,
7887 struct bnx2x_phy *phy,
7888 u16 edc_mode)
7889{
7890 switch (phy->type) {
7891 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
7892 bnx2x_8726_set_limiting_mode(params->bp, phy, edc_mode);
7893 break;
7894 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
7895 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722:
7896 bnx2x_8727_set_limiting_mode(params->bp, phy, edc_mode);
7897 break;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00007898 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
7899 bnx2x_warpcore_set_limiting_mode(params, phy, edc_mode);
7900 break;
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00007901 }
7902}
7903
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00007904int bnx2x_sfp_module_detection(struct bnx2x_phy *phy,
7905 struct link_params *params)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007906{
7907 struct bnx2x *bp = params->bp;
7908 u16 edc_mode;
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00007909 int rc = 0;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007910
7911 u32 val = REG_RD(bp, params->shmem_base +
7912 offsetof(struct shmem_region, dev_info.
7913 port_feature_config[params->port].config));
7914
7915 DP(NETIF_MSG_LINK, "SFP+ module plugged in/out detected on port %d\n",
7916 params->port);
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00007917 /* Power up module */
7918 bnx2x_power_sfp_module(params, phy, 1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007919 if (bnx2x_get_edc_mode(phy, params, &edc_mode) != 0) {
7920 DP(NETIF_MSG_LINK, "Failed to get valid module type\n");
7921 return -EINVAL;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007922 } else if (bnx2x_verify_sfp_module(phy, params) != 0) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007923 /* check SFP+ module compatibility */
7924 DP(NETIF_MSG_LINK, "Module verification failed!!\n");
7925 rc = -EINVAL;
7926 /* Turn on fault module-detected led */
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00007927 bnx2x_set_sfp_module_fault_led(params,
7928 MISC_REGISTERS_GPIO_HIGH);
7929
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00007930 /* Check if need to power down the SFP+ module */
7931 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
7932 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_POWER_DOWN) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007933 DP(NETIF_MSG_LINK, "Shutdown SFP+ module!!\n");
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00007934 bnx2x_power_sfp_module(params, phy, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007935 return rc;
7936 }
7937 } else {
7938 /* Turn off fault module-detected led */
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00007939 bnx2x_set_sfp_module_fault_led(params, MISC_REGISTERS_GPIO_LOW);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007940 }
7941
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007942 /*
7943 * Check and set limiting mode / LRM mode on 8726. On 8727 it
7944 * is done automatically
7945 */
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00007946 bnx2x_set_limiting_mode(params, phy, edc_mode);
7947
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007948 /*
7949 * Enable transmit for this module if the module is approved, or
7950 * if unapproved modules should also enable the Tx laser
7951 */
7952 if (rc == 0 ||
7953 (val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) !=
7954 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00007955 bnx2x_sfp_set_transmitter(params, phy, 1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007956 else
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00007957 bnx2x_sfp_set_transmitter(params, phy, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007958
7959 return rc;
7960}
7961
7962void bnx2x_handle_module_detect_int(struct link_params *params)
7963{
7964 struct bnx2x *bp = params->bp;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00007965 struct bnx2x_phy *phy;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007966 u32 gpio_val;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00007967 u8 gpio_num, gpio_port;
7968 if (CHIP_IS_E3(bp))
7969 phy = &params->phy[INT_PHY];
7970 else
7971 phy = &params->phy[EXT_PHY1];
7972
7973 if (bnx2x_get_mod_abs_int_cfg(bp, params->chip_id, params->shmem_base,
7974 params->port, &gpio_num, &gpio_port) ==
7975 -EINVAL) {
7976 DP(NETIF_MSG_LINK, "Failed to get MOD_ABS interrupt config\n");
7977 return;
7978 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007979
7980 /* Set valid module led off */
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00007981 bnx2x_set_sfp_module_fault_led(params, MISC_REGISTERS_GPIO_HIGH);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007982
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007983 /* Get current gpio val reflecting module plugged in / out*/
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00007984 gpio_val = bnx2x_get_gpio(bp, gpio_num, gpio_port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007985
7986 /* Call the handling function in case module is detected */
7987 if (gpio_val == 0) {
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00007988 bnx2x_power_sfp_module(params, phy, 1);
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00007989 bnx2x_set_gpio_int(bp, gpio_num,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007990 MISC_REGISTERS_GPIO_INT_OUTPUT_CLR,
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00007991 gpio_port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007992 if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0)
7993 bnx2x_sfp_module_detection(phy, params);
7994 else
7995 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
7996 } else {
7997 u32 val = REG_RD(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007998 offsetof(struct shmem_region, dev_info.
7999 port_feature_config[params->port].
8000 config));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008001
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00008002 bnx2x_set_gpio_int(bp, gpio_num,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008003 MISC_REGISTERS_GPIO_INT_OUTPUT_SET,
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00008004 gpio_port);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008005 /*
8006 * Module was plugged out.
8007 * Disable transmit for this module
8008 */
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00008009 phy->media_type = ETH_PHY_NOT_PRESENT;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008010 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
8011 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00008012 bnx2x_sfp_set_transmitter(params, phy, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008013 }
8014}
8015
8016/******************************************************************/
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00008017/* Used by 8706 and 8727 */
8018/******************************************************************/
8019static void bnx2x_sfp_mask_fault(struct bnx2x *bp,
8020 struct bnx2x_phy *phy,
8021 u16 alarm_status_offset,
8022 u16 alarm_ctrl_offset)
8023{
8024 u16 alarm_status, val;
8025 bnx2x_cl45_read(bp, phy,
8026 MDIO_PMA_DEVAD, alarm_status_offset,
8027 &alarm_status);
8028 bnx2x_cl45_read(bp, phy,
8029 MDIO_PMA_DEVAD, alarm_status_offset,
8030 &alarm_status);
8031 /* Mask or enable the fault event. */
8032 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, alarm_ctrl_offset, &val);
8033 if (alarm_status & (1<<0))
8034 val &= ~(1<<0);
8035 else
8036 val |= (1<<0);
8037 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, alarm_ctrl_offset, val);
8038}
8039/******************************************************************/
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008040/* common BCM8706/BCM8726 PHY SECTION */
8041/******************************************************************/
8042static u8 bnx2x_8706_8726_read_status(struct bnx2x_phy *phy,
8043 struct link_params *params,
8044 struct link_vars *vars)
8045{
8046 u8 link_up = 0;
8047 u16 val1, val2, rx_sd, pcs_status;
8048 struct bnx2x *bp = params->bp;
8049 DP(NETIF_MSG_LINK, "XGXS 8706/8726\n");
8050 /* Clear RX Alarm*/
8051 bnx2x_cl45_read(bp, phy,
8052 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &val2);
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00008053
8054 bnx2x_sfp_mask_fault(bp, phy, MDIO_PMA_REG_TX_ALARM,
8055 MDIO_PMA_REG_TX_ALARM_CTRL);
8056
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008057 /* clear LASI indication*/
8058 bnx2x_cl45_read(bp, phy,
8059 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
8060 bnx2x_cl45_read(bp, phy,
8061 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val2);
8062 DP(NETIF_MSG_LINK, "8706/8726 LASI status 0x%x--> 0x%x\n", val1, val2);
8063
8064 bnx2x_cl45_read(bp, phy,
8065 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD, &rx_sd);
8066 bnx2x_cl45_read(bp, phy,
8067 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &pcs_status);
8068 bnx2x_cl45_read(bp, phy,
8069 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &val2);
8070 bnx2x_cl45_read(bp, phy,
8071 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &val2);
8072
8073 DP(NETIF_MSG_LINK, "8706/8726 rx_sd 0x%x pcs_status 0x%x 1Gbps"
8074 " link_status 0x%x\n", rx_sd, pcs_status, val2);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008075 /*
8076 * link is up if both bit 0 of pmd_rx_sd and bit 0 of pcs_status
8077 * are set, or if the autoneg bit 1 is set
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008078 */
8079 link_up = ((rx_sd & pcs_status & 0x1) || (val2 & (1<<1)));
8080 if (link_up) {
8081 if (val2 & (1<<1))
8082 vars->line_speed = SPEED_1000;
8083 else
8084 vars->line_speed = SPEED_10000;
8085 bnx2x_ext_phy_resolve_fc(phy, params, vars);
Yaniv Rosner791f18c2011-01-18 04:33:42 +00008086 vars->duplex = DUPLEX_FULL;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008087 }
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00008088
8089 /* Capture 10G link fault. Read twice to clear stale value. */
8090 if (vars->line_speed == SPEED_10000) {
8091 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
8092 MDIO_PMA_REG_TX_ALARM, &val1);
8093 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
8094 MDIO_PMA_REG_TX_ALARM, &val1);
8095 if (val1 & (1<<0))
8096 vars->fault_detected = 1;
8097 }
8098
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008099 return link_up;
8100}
8101
8102/******************************************************************/
8103/* BCM8706 PHY SECTION */
8104/******************************************************************/
8105static u8 bnx2x_8706_config_init(struct bnx2x_phy *phy,
8106 struct link_params *params,
8107 struct link_vars *vars)
8108{
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00008109 u32 tx_en_mode;
8110 u16 cnt, val, tmp1;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008111 struct bnx2x *bp = params->bp;
8112 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008113 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008114 /* HW reset */
8115 bnx2x_ext_phy_hw_reset(bp, params->port);
8116 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0xa040);
Yaniv Rosner6d870c32011-01-31 04:22:20 +00008117 bnx2x_wait_reset_complete(bp, phy, params);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008118
8119 /* Wait until fw is loaded */
8120 for (cnt = 0; cnt < 100; cnt++) {
8121 bnx2x_cl45_read(bp, phy,
8122 MDIO_PMA_DEVAD, MDIO_PMA_REG_ROM_VER1, &val);
8123 if (val)
8124 break;
8125 msleep(10);
8126 }
8127 DP(NETIF_MSG_LINK, "XGXS 8706 is initialized after %d ms\n", cnt);
8128 if ((params->feature_config_flags &
8129 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
8130 u8 i;
8131 u16 reg;
8132 for (i = 0; i < 4; i++) {
8133 reg = MDIO_XS_8706_REG_BANK_RX0 +
8134 i*(MDIO_XS_8706_REG_BANK_RX1 -
8135 MDIO_XS_8706_REG_BANK_RX0);
8136 bnx2x_cl45_read(bp, phy, MDIO_XS_DEVAD, reg, &val);
8137 /* Clear first 3 bits of the control */
8138 val &= ~0x7;
8139 /* Set control bits according to configuration */
8140 val |= (phy->rx_preemphasis[i] & 0x7);
8141 DP(NETIF_MSG_LINK, "Setting RX Equalizer to BCM8706"
8142 " reg 0x%x <-- val 0x%x\n", reg, val);
8143 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, reg, val);
8144 }
8145 }
8146 /* Force speed */
8147 if (phy->req_line_speed == SPEED_10000) {
8148 DP(NETIF_MSG_LINK, "XGXS 8706 force 10Gbps\n");
8149
8150 bnx2x_cl45_write(bp, phy,
8151 MDIO_PMA_DEVAD,
8152 MDIO_PMA_REG_DIGITAL_CTRL, 0x400);
8153 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00008154 MDIO_PMA_DEVAD, MDIO_PMA_REG_TX_ALARM_CTRL,
8155 0);
8156 /* Arm LASI for link and Tx fault. */
8157 bnx2x_cl45_write(bp, phy,
8158 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 3);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008159 } else {
Lucas De Marchi25985ed2011-03-30 22:57:33 -03008160 /* Force 1Gbps using autoneg with 1G advertisement */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008161
8162 /* Allow CL37 through CL73 */
8163 DP(NETIF_MSG_LINK, "XGXS 8706 AutoNeg\n");
8164 bnx2x_cl45_write(bp, phy,
8165 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_CL73, 0x040c);
8166
Lucas De Marchi25985ed2011-03-30 22:57:33 -03008167 /* Enable Full-Duplex advertisement on CL37 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008168 bnx2x_cl45_write(bp, phy,
8169 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LP, 0x0020);
8170 /* Enable CL37 AN */
8171 bnx2x_cl45_write(bp, phy,
8172 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
8173 /* 1G support */
8174 bnx2x_cl45_write(bp, phy,
8175 MDIO_AN_DEVAD, MDIO_AN_REG_ADV, (1<<5));
8176
8177 /* Enable clause 73 AN */
8178 bnx2x_cl45_write(bp, phy,
8179 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
8180 bnx2x_cl45_write(bp, phy,
8181 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
8182 0x0400);
8183 bnx2x_cl45_write(bp, phy,
8184 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL,
8185 0x0004);
8186 }
8187 bnx2x_save_bcm_spirom_ver(bp, phy, params->port);
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00008188
8189 /*
8190 * If TX Laser is controlled by GPIO_0, do not let PHY go into low
8191 * power mode, if TX Laser is disabled
8192 */
8193
8194 tx_en_mode = REG_RD(bp, params->shmem_base +
8195 offsetof(struct shmem_region,
8196 dev_info.port_hw_config[params->port].sfp_ctrl))
8197 & PORT_HW_CFG_TX_LASER_MASK;
8198
8199 if (tx_en_mode == PORT_HW_CFG_TX_LASER_GPIO0) {
8200 DP(NETIF_MSG_LINK, "Enabling TXONOFF_PWRDN_DIS\n");
8201 bnx2x_cl45_read(bp, phy,
8202 MDIO_PMA_DEVAD, MDIO_PMA_REG_DIGITAL_CTRL, &tmp1);
8203 tmp1 |= 0x1;
8204 bnx2x_cl45_write(bp, phy,
8205 MDIO_PMA_DEVAD, MDIO_PMA_REG_DIGITAL_CTRL, tmp1);
8206 }
8207
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008208 return 0;
8209}
8210
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00008211static int bnx2x_8706_read_status(struct bnx2x_phy *phy,
8212 struct link_params *params,
8213 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008214{
8215 return bnx2x_8706_8726_read_status(phy, params, vars);
8216}
8217
8218/******************************************************************/
8219/* BCM8726 PHY SECTION */
8220/******************************************************************/
8221static void bnx2x_8726_config_loopback(struct bnx2x_phy *phy,
8222 struct link_params *params)
8223{
8224 struct bnx2x *bp = params->bp;
8225 DP(NETIF_MSG_LINK, "PMA/PMD ext_phy_loopback: 8726\n");
8226 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x0001);
8227}
8228
8229static void bnx2x_8726_external_rom_boot(struct bnx2x_phy *phy,
8230 struct link_params *params)
8231{
8232 struct bnx2x *bp = params->bp;
8233 /* Need to wait 100ms after reset */
8234 msleep(100);
8235
8236 /* Micro controller re-boot */
8237 bnx2x_cl45_write(bp, phy,
8238 MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, 0x018B);
8239
8240 /* Set soft reset */
8241 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008242 MDIO_PMA_DEVAD,
8243 MDIO_PMA_REG_GEN_CTRL,
8244 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008245
8246 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008247 MDIO_PMA_DEVAD,
8248 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008249
8250 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008251 MDIO_PMA_DEVAD,
8252 MDIO_PMA_REG_GEN_CTRL,
8253 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008254
8255 /* wait for 150ms for microcode load */
8256 msleep(150);
8257
8258 /* Disable serial boot control, tristates pins SS_N, SCK, MOSI, MISO */
8259 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008260 MDIO_PMA_DEVAD,
8261 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008262
8263 msleep(200);
8264 bnx2x_save_bcm_spirom_ver(bp, phy, params->port);
8265}
8266
8267static u8 bnx2x_8726_read_status(struct bnx2x_phy *phy,
8268 struct link_params *params,
8269 struct link_vars *vars)
8270{
8271 struct bnx2x *bp = params->bp;
8272 u16 val1;
8273 u8 link_up = bnx2x_8706_8726_read_status(phy, params, vars);
8274 if (link_up) {
8275 bnx2x_cl45_read(bp, phy,
8276 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER,
8277 &val1);
8278 if (val1 & (1<<15)) {
8279 DP(NETIF_MSG_LINK, "Tx is disabled\n");
8280 link_up = 0;
8281 vars->line_speed = 0;
8282 }
8283 }
8284 return link_up;
8285}
8286
8287
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00008288static int bnx2x_8726_config_init(struct bnx2x_phy *phy,
8289 struct link_params *params,
8290 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008291{
8292 struct bnx2x *bp = params->bp;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008293 DP(NETIF_MSG_LINK, "Initializing BCM8726\n");
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008294
8295 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
Yaniv Rosner6d870c32011-01-31 04:22:20 +00008296 bnx2x_wait_reset_complete(bp, phy, params);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008297
8298 bnx2x_8726_external_rom_boot(phy, params);
8299
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008300 /*
8301 * Need to call module detected on initialization since the module
8302 * detection triggered by actual module insertion might occur before
8303 * driver is loaded, and when driver is loaded, it reset all
8304 * registers, including the transmitter
8305 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008306 bnx2x_sfp_module_detection(phy, params);
8307
8308 if (phy->req_line_speed == SPEED_1000) {
8309 DP(NETIF_MSG_LINK, "Setting 1G force\n");
8310 bnx2x_cl45_write(bp, phy,
8311 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x40);
8312 bnx2x_cl45_write(bp, phy,
8313 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0xD);
8314 bnx2x_cl45_write(bp, phy,
8315 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x5);
8316 bnx2x_cl45_write(bp, phy,
8317 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
8318 0x400);
8319 } else if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
8320 (phy->speed_cap_mask &
8321 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G) &&
8322 ((phy->speed_cap_mask &
8323 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) !=
8324 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
8325 DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
8326 /* Set Flow control */
8327 bnx2x_ext_phy_set_pause(params, phy, vars);
8328 bnx2x_cl45_write(bp, phy,
8329 MDIO_AN_DEVAD, MDIO_AN_REG_ADV, 0x20);
8330 bnx2x_cl45_write(bp, phy,
8331 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_CL73, 0x040c);
8332 bnx2x_cl45_write(bp, phy,
8333 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, 0x0020);
8334 bnx2x_cl45_write(bp, phy,
8335 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
8336 bnx2x_cl45_write(bp, phy,
8337 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008338 /*
8339 * Enable RX-ALARM control to receive interrupt for 1G speed
8340 * change
8341 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008342 bnx2x_cl45_write(bp, phy,
8343 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x4);
8344 bnx2x_cl45_write(bp, phy,
8345 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
8346 0x400);
8347
8348 } else { /* Default 10G. Set only LASI control */
8349 bnx2x_cl45_write(bp, phy,
8350 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 1);
8351 }
8352
8353 /* Set TX PreEmphasis if needed */
8354 if ((params->feature_config_flags &
8355 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
8356 DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x,"
8357 "TX_CTRL2 0x%x\n",
8358 phy->tx_preemphasis[0],
8359 phy->tx_preemphasis[1]);
8360 bnx2x_cl45_write(bp, phy,
8361 MDIO_PMA_DEVAD,
8362 MDIO_PMA_REG_8726_TX_CTRL1,
8363 phy->tx_preemphasis[0]);
8364
8365 bnx2x_cl45_write(bp, phy,
8366 MDIO_PMA_DEVAD,
8367 MDIO_PMA_REG_8726_TX_CTRL2,
8368 phy->tx_preemphasis[1]);
8369 }
8370
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008371 return 0;
8372
8373}
8374
8375static void bnx2x_8726_link_reset(struct bnx2x_phy *phy,
8376 struct link_params *params)
8377{
8378 struct bnx2x *bp = params->bp;
8379 DP(NETIF_MSG_LINK, "bnx2x_8726_link_reset port %d\n", params->port);
8380 /* Set serial boot control for external load */
8381 bnx2x_cl45_write(bp, phy,
8382 MDIO_PMA_DEVAD,
8383 MDIO_PMA_REG_GEN_CTRL, 0x0001);
8384}
8385
8386/******************************************************************/
8387/* BCM8727 PHY SECTION */
8388/******************************************************************/
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00008389
8390static void bnx2x_8727_set_link_led(struct bnx2x_phy *phy,
8391 struct link_params *params, u8 mode)
8392{
8393 struct bnx2x *bp = params->bp;
8394 u16 led_mode_bitmask = 0;
8395 u16 gpio_pins_bitmask = 0;
8396 u16 val;
8397 /* Only NOC flavor requires to set the LED specifically */
8398 if (!(phy->flags & FLAGS_NOC))
8399 return;
8400 switch (mode) {
8401 case LED_MODE_FRONT_PANEL_OFF:
8402 case LED_MODE_OFF:
8403 led_mode_bitmask = 0;
8404 gpio_pins_bitmask = 0x03;
8405 break;
8406 case LED_MODE_ON:
8407 led_mode_bitmask = 0;
8408 gpio_pins_bitmask = 0x02;
8409 break;
8410 case LED_MODE_OPER:
8411 led_mode_bitmask = 0x60;
8412 gpio_pins_bitmask = 0x11;
8413 break;
8414 }
8415 bnx2x_cl45_read(bp, phy,
8416 MDIO_PMA_DEVAD,
8417 MDIO_PMA_REG_8727_PCS_OPT_CTRL,
8418 &val);
8419 val &= 0xff8f;
8420 val |= led_mode_bitmask;
8421 bnx2x_cl45_write(bp, phy,
8422 MDIO_PMA_DEVAD,
8423 MDIO_PMA_REG_8727_PCS_OPT_CTRL,
8424 val);
8425 bnx2x_cl45_read(bp, phy,
8426 MDIO_PMA_DEVAD,
8427 MDIO_PMA_REG_8727_GPIO_CTRL,
8428 &val);
8429 val &= 0xffe0;
8430 val |= gpio_pins_bitmask;
8431 bnx2x_cl45_write(bp, phy,
8432 MDIO_PMA_DEVAD,
8433 MDIO_PMA_REG_8727_GPIO_CTRL,
8434 val);
8435}
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00008436static void bnx2x_8727_hw_reset(struct bnx2x_phy *phy,
8437 struct link_params *params) {
8438 u32 swap_val, swap_override;
8439 u8 port;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008440 /*
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00008441 * The PHY reset is controlled by GPIO 1. Fake the port number
8442 * to cancel the swap done in set_gpio()
8443 */
8444 struct bnx2x *bp = params->bp;
8445 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
8446 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
8447 port = (swap_val && swap_override) ^ 1;
8448 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008449 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00008450}
8451
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00008452static int bnx2x_8727_config_init(struct bnx2x_phy *phy,
8453 struct link_params *params,
8454 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008455{
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00008456 u32 tx_en_mode;
8457 u16 tmp1, val, mod_abs, tmp2;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008458 u16 rx_alarm_ctrl_val;
8459 u16 lasi_ctrl_val;
8460 struct bnx2x *bp = params->bp;
8461 /* Enable PMD link, MOD_ABS_FLT, and 1G link alarm */
8462
Yaniv Rosner6d870c32011-01-31 04:22:20 +00008463 bnx2x_wait_reset_complete(bp, phy, params);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008464 rx_alarm_ctrl_val = (1<<2) | (1<<5) ;
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00008465 /* Should be 0x6 to enable XS on Tx side. */
8466 lasi_ctrl_val = 0x0006;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008467
8468 DP(NETIF_MSG_LINK, "Initializing BCM8727\n");
8469 /* enable LASI */
8470 bnx2x_cl45_write(bp, phy,
8471 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
8472 rx_alarm_ctrl_val);
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00008473 bnx2x_cl45_write(bp, phy,
8474 MDIO_PMA_DEVAD, MDIO_PMA_REG_TX_ALARM_CTRL,
8475 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008476 bnx2x_cl45_write(bp, phy,
8477 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, lasi_ctrl_val);
8478
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008479 /*
8480 * Initially configure MOD_ABS to interrupt when module is
8481 * presence( bit 8)
8482 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008483 bnx2x_cl45_read(bp, phy,
8484 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008485 /*
8486 * Set EDC off by setting OPTXLOS signal input to low (bit 9).
8487 * When the EDC is off it locks onto a reference clock and avoids
8488 * becoming 'lost'
8489 */
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00008490 mod_abs &= ~(1<<8);
8491 if (!(phy->flags & FLAGS_NOC))
8492 mod_abs &= ~(1<<9);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008493 bnx2x_cl45_write(bp, phy,
8494 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
8495
8496
8497 /* Make MOD_ABS give interrupt on change */
8498 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL,
8499 &val);
8500 val |= (1<<12);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00008501 if (phy->flags & FLAGS_NOC)
8502 val |= (3<<5);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008503
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008504 /*
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00008505 * Set 8727 GPIOs to input to allow reading from the 8727 GPIO0
8506 * status which reflect SFP+ module over-current
8507 */
8508 if (!(phy->flags & FLAGS_NOC))
8509 val &= 0xff8f; /* Reset bits 4-6 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008510 bnx2x_cl45_write(bp, phy,
8511 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL, val);
8512
8513 bnx2x_8727_power_module(bp, phy, 1);
8514
8515 bnx2x_cl45_read(bp, phy,
8516 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &tmp1);
8517
8518 bnx2x_cl45_read(bp, phy,
8519 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &tmp1);
8520
8521 /* Set option 1G speed */
8522 if (phy->req_line_speed == SPEED_1000) {
8523 DP(NETIF_MSG_LINK, "Setting 1G force\n");
8524 bnx2x_cl45_write(bp, phy,
8525 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x40);
8526 bnx2x_cl45_write(bp, phy,
8527 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0xD);
8528 bnx2x_cl45_read(bp, phy,
8529 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, &tmp1);
8530 DP(NETIF_MSG_LINK, "1.7 = 0x%x\n", tmp1);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008531 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008532 * Power down the XAUI until link is up in case of dual-media
8533 * and 1G
8534 */
8535 if (DUAL_MEDIA(params)) {
8536 bnx2x_cl45_read(bp, phy,
8537 MDIO_PMA_DEVAD,
8538 MDIO_PMA_REG_8727_PCS_GP, &val);
8539 val |= (3<<10);
8540 bnx2x_cl45_write(bp, phy,
8541 MDIO_PMA_DEVAD,
8542 MDIO_PMA_REG_8727_PCS_GP, val);
8543 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008544 } else if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
8545 ((phy->speed_cap_mask &
8546 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) &&
8547 ((phy->speed_cap_mask &
8548 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) !=
8549 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
8550
8551 DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
8552 bnx2x_cl45_write(bp, phy,
8553 MDIO_AN_DEVAD, MDIO_AN_REG_8727_MISC_CTRL, 0);
8554 bnx2x_cl45_write(bp, phy,
8555 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1300);
8556 } else {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008557 /*
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008558 * Since the 8727 has only single reset pin, need to set the 10G
8559 * registers although it is default
8560 */
8561 bnx2x_cl45_write(bp, phy,
8562 MDIO_AN_DEVAD, MDIO_AN_REG_8727_MISC_CTRL,
8563 0x0020);
8564 bnx2x_cl45_write(bp, phy,
8565 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x0100);
8566 bnx2x_cl45_write(bp, phy,
8567 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x2040);
8568 bnx2x_cl45_write(bp, phy,
8569 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2,
8570 0x0008);
8571 }
8572
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008573 /*
8574 * Set 2-wire transfer rate of SFP+ module EEPROM
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008575 * to 100Khz since some DACs(direct attached cables) do
8576 * not work at 400Khz.
8577 */
8578 bnx2x_cl45_write(bp, phy,
8579 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR,
8580 0xa001);
8581
8582 /* Set TX PreEmphasis if needed */
8583 if ((params->feature_config_flags &
8584 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
8585 DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x, TX_CTRL2 0x%x\n",
8586 phy->tx_preemphasis[0],
8587 phy->tx_preemphasis[1]);
8588 bnx2x_cl45_write(bp, phy,
8589 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TX_CTRL1,
8590 phy->tx_preemphasis[0]);
8591
8592 bnx2x_cl45_write(bp, phy,
8593 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TX_CTRL2,
8594 phy->tx_preemphasis[1]);
8595 }
8596
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00008597 /*
8598 * If TX Laser is controlled by GPIO_0, do not let PHY go into low
8599 * power mode, if TX Laser is disabled
8600 */
8601 tx_en_mode = REG_RD(bp, params->shmem_base +
8602 offsetof(struct shmem_region,
8603 dev_info.port_hw_config[params->port].sfp_ctrl))
8604 & PORT_HW_CFG_TX_LASER_MASK;
8605
8606 if (tx_en_mode == PORT_HW_CFG_TX_LASER_GPIO0) {
8607
8608 DP(NETIF_MSG_LINK, "Enabling TXONOFF_PWRDN_DIS\n");
8609 bnx2x_cl45_read(bp, phy,
8610 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_OPT_CFG_REG, &tmp2);
8611 tmp2 |= 0x1000;
8612 tmp2 &= 0xFFEF;
8613 bnx2x_cl45_write(bp, phy,
8614 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_OPT_CFG_REG, tmp2);
8615 }
8616
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008617 return 0;
8618}
8619
8620static void bnx2x_8727_handle_mod_abs(struct bnx2x_phy *phy,
8621 struct link_params *params)
8622{
8623 struct bnx2x *bp = params->bp;
8624 u16 mod_abs, rx_alarm_status;
8625 u32 val = REG_RD(bp, params->shmem_base +
8626 offsetof(struct shmem_region, dev_info.
8627 port_feature_config[params->port].
8628 config));
8629 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008630 MDIO_PMA_DEVAD,
8631 MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008632 if (mod_abs & (1<<8)) {
8633
8634 /* Module is absent */
8635 DP(NETIF_MSG_LINK, "MOD_ABS indication "
8636 "show module is absent\n");
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00008637 phy->media_type = ETH_PHY_NOT_PRESENT;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008638 /*
8639 * 1. Set mod_abs to detect next module
8640 * presence event
8641 * 2. Set EDC off by setting OPTXLOS signal input to low
8642 * (bit 9).
8643 * When the EDC is off it locks onto a reference clock and
8644 * avoids becoming 'lost'.
8645 */
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00008646 mod_abs &= ~(1<<8);
8647 if (!(phy->flags & FLAGS_NOC))
8648 mod_abs &= ~(1<<9);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008649 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008650 MDIO_PMA_DEVAD,
8651 MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008652
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008653 /*
8654 * Clear RX alarm since it stays up as long as
8655 * the mod_abs wasn't changed
8656 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008657 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008658 MDIO_PMA_DEVAD,
8659 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008660
8661 } else {
8662 /* Module is present */
8663 DP(NETIF_MSG_LINK, "MOD_ABS indication "
8664 "show module is present\n");
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008665 /*
8666 * First disable transmitter, and if the module is ok, the
8667 * module_detection will enable it
8668 * 1. Set mod_abs to detect next module absent event ( bit 8)
8669 * 2. Restore the default polarity of the OPRXLOS signal and
8670 * this signal will then correctly indicate the presence or
8671 * absence of the Rx signal. (bit 9)
8672 */
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00008673 mod_abs |= (1<<8);
8674 if (!(phy->flags & FLAGS_NOC))
8675 mod_abs |= (1<<9);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008676 bnx2x_cl45_write(bp, phy,
8677 MDIO_PMA_DEVAD,
8678 MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
8679
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008680 /*
8681 * Clear RX alarm since it stays up as long as the mod_abs
8682 * wasn't changed. This is need to be done before calling the
8683 * module detection, otherwise it will clear* the link update
8684 * alarm
8685 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008686 bnx2x_cl45_read(bp, phy,
8687 MDIO_PMA_DEVAD,
8688 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
8689
8690
8691 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
8692 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00008693 bnx2x_sfp_set_transmitter(params, phy, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008694
8695 if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0)
8696 bnx2x_sfp_module_detection(phy, params);
8697 else
8698 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
8699 }
8700
8701 DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n",
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008702 rx_alarm_status);
8703 /* No need to check link status in case of module plugged in/out */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008704}
8705
8706static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy,
8707 struct link_params *params,
8708 struct link_vars *vars)
8709
8710{
8711 struct bnx2x *bp = params->bp;
Yaniv Rosner27d02432011-05-31 21:27:48 +00008712 u8 link_up = 0, oc_port = params->port;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008713 u16 link_status = 0;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008714 u16 rx_alarm_status, lasi_ctrl, val1;
8715
8716 /* If PHY is not initialized, do not check link status */
8717 bnx2x_cl45_read(bp, phy,
8718 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL,
8719 &lasi_ctrl);
8720 if (!lasi_ctrl)
8721 return 0;
8722
Yaniv Rosner9045f6b2011-05-31 21:28:27 +00008723 /* Check the LASI on Rx */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008724 bnx2x_cl45_read(bp, phy,
8725 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM,
8726 &rx_alarm_status);
8727 vars->line_speed = 0;
8728 DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n", rx_alarm_status);
8729
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00008730 bnx2x_sfp_mask_fault(bp, phy, MDIO_PMA_REG_TX_ALARM,
8731 MDIO_PMA_REG_TX_ALARM_CTRL);
8732
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008733 bnx2x_cl45_read(bp, phy,
8734 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
8735
8736 DP(NETIF_MSG_LINK, "8727 LASI status 0x%x\n", val1);
8737
8738 /* Clear MSG-OUT */
8739 bnx2x_cl45_read(bp, phy,
8740 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &val1);
8741
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008742 /*
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008743 * If a module is present and there is need to check
8744 * for over current
8745 */
8746 if (!(phy->flags & FLAGS_NOC) && !(rx_alarm_status & (1<<5))) {
8747 /* Check over-current using 8727 GPIO0 input*/
8748 bnx2x_cl45_read(bp, phy,
8749 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_GPIO_CTRL,
8750 &val1);
8751
8752 if ((val1 & (1<<8)) == 0) {
Yaniv Rosner27d02432011-05-31 21:27:48 +00008753 if (!CHIP_IS_E1x(bp))
8754 oc_port = BP_PATH(bp) + (params->port << 1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008755 DP(NETIF_MSG_LINK, "8727 Power fault has been detected"
Yaniv Rosner27d02432011-05-31 21:27:48 +00008756 " on port %d\n", oc_port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008757 netdev_err(bp->dev, "Error: Power fault on Port %d has"
8758 " been detected and the power to "
8759 "that SFP+ module has been removed"
8760 " to prevent failure of the card."
8761 " Please remove the SFP+ module and"
8762 " restart the system to clear this"
8763 " error.\n",
Yaniv Rosner27d02432011-05-31 21:27:48 +00008764 oc_port);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008765 /* Disable all RX_ALARMs except for mod_abs */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008766 bnx2x_cl45_write(bp, phy,
8767 MDIO_PMA_DEVAD,
8768 MDIO_PMA_REG_RX_ALARM_CTRL, (1<<5));
8769
8770 bnx2x_cl45_read(bp, phy,
8771 MDIO_PMA_DEVAD,
8772 MDIO_PMA_REG_PHY_IDENTIFIER, &val1);
8773 /* Wait for module_absent_event */
8774 val1 |= (1<<8);
8775 bnx2x_cl45_write(bp, phy,
8776 MDIO_PMA_DEVAD,
8777 MDIO_PMA_REG_PHY_IDENTIFIER, val1);
8778 /* Clear RX alarm */
8779 bnx2x_cl45_read(bp, phy,
8780 MDIO_PMA_DEVAD,
8781 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
8782 return 0;
8783 }
8784 } /* Over current check */
8785
8786 /* When module absent bit is set, check module */
8787 if (rx_alarm_status & (1<<5)) {
8788 bnx2x_8727_handle_mod_abs(phy, params);
8789 /* Enable all mod_abs and link detection bits */
8790 bnx2x_cl45_write(bp, phy,
8791 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
8792 ((1<<5) | (1<<2)));
8793 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008794 DP(NETIF_MSG_LINK, "Enabling 8727 TX laser if SFP is approved\n");
8795 bnx2x_8727_specific_func(phy, params, ENABLE_TX);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008796 /* If transmitter is disabled, ignore false link up indication */
8797 bnx2x_cl45_read(bp, phy,
8798 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, &val1);
8799 if (val1 & (1<<15)) {
8800 DP(NETIF_MSG_LINK, "Tx is disabled\n");
8801 return 0;
8802 }
8803
8804 bnx2x_cl45_read(bp, phy,
8805 MDIO_PMA_DEVAD,
8806 MDIO_PMA_REG_8073_SPEED_LINK_STATUS, &link_status);
8807
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008808 /*
8809 * Bits 0..2 --> speed detected,
8810 * Bits 13..15--> link is down
8811 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008812 if ((link_status & (1<<2)) && (!(link_status & (1<<15)))) {
8813 link_up = 1;
8814 vars->line_speed = SPEED_10000;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008815 DP(NETIF_MSG_LINK, "port %x: External link up in 10G\n",
8816 params->port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008817 } else if ((link_status & (1<<0)) && (!(link_status & (1<<13)))) {
8818 link_up = 1;
8819 vars->line_speed = SPEED_1000;
8820 DP(NETIF_MSG_LINK, "port %x: External link up in 1G\n",
8821 params->port);
8822 } else {
8823 link_up = 0;
8824 DP(NETIF_MSG_LINK, "port %x: External link is down\n",
8825 params->port);
8826 }
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00008827
8828 /* Capture 10G link fault. */
8829 if (vars->line_speed == SPEED_10000) {
8830 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
8831 MDIO_PMA_REG_TX_ALARM, &val1);
8832
8833 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
8834 MDIO_PMA_REG_TX_ALARM, &val1);
8835
8836 if (val1 & (1<<0)) {
8837 vars->fault_detected = 1;
8838 }
8839 }
8840
Yaniv Rosner791f18c2011-01-18 04:33:42 +00008841 if (link_up) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008842 bnx2x_ext_phy_resolve_fc(phy, params, vars);
Yaniv Rosner791f18c2011-01-18 04:33:42 +00008843 vars->duplex = DUPLEX_FULL;
8844 DP(NETIF_MSG_LINK, "duplex = 0x%x\n", vars->duplex);
8845 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008846
8847 if ((DUAL_MEDIA(params)) &&
8848 (phy->req_line_speed == SPEED_1000)) {
8849 bnx2x_cl45_read(bp, phy,
8850 MDIO_PMA_DEVAD,
8851 MDIO_PMA_REG_8727_PCS_GP, &val1);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008852 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008853 * In case of dual-media board and 1G, power up the XAUI side,
8854 * otherwise power it down. For 10G it is done automatically
8855 */
8856 if (link_up)
8857 val1 &= ~(3<<10);
8858 else
8859 val1 |= (3<<10);
8860 bnx2x_cl45_write(bp, phy,
8861 MDIO_PMA_DEVAD,
8862 MDIO_PMA_REG_8727_PCS_GP, val1);
8863 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008864 return link_up;
8865}
8866
8867static void bnx2x_8727_link_reset(struct bnx2x_phy *phy,
8868 struct link_params *params)
8869{
8870 struct bnx2x *bp = params->bp;
8871 /* Disable Transmitter */
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00008872 bnx2x_sfp_set_transmitter(params, phy, 0);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008873 /* Clear LASI */
8874 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0);
8875
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008876}
8877
8878/******************************************************************/
8879/* BCM8481/BCM84823/BCM84833 PHY SECTION */
8880/******************************************************************/
8881static void bnx2x_save_848xx_spirom_version(struct bnx2x_phy *phy,
8882 struct link_params *params)
8883{
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008884 u16 val, fw_ver1, fw_ver2, cnt;
8885 u8 port;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008886 struct bnx2x *bp = params->bp;
8887
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008888 port = params->port;
Yaniv Rosnerc87bca12011-01-31 04:22:41 +00008889
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008890 /* For the 32 bits registers in 848xx, access via MDIO2ARM interface.*/
8891 /* (1) set register 0xc200_0014(SPI_BRIDGE_CTRL_2) to 0x03000000 */
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008892 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0014);
8893 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200);
8894 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81B, 0x0000);
8895 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81C, 0x0300);
8896 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x0009);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008897
8898 for (cnt = 0; cnt < 100; cnt++) {
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008899 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008900 if (val & 1)
8901 break;
8902 udelay(5);
8903 }
8904 if (cnt == 100) {
8905 DP(NETIF_MSG_LINK, "Unable to read 848xx phy fw version(1)\n");
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008906 bnx2x_save_spirom_version(bp, port, 0,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008907 phy->ver_addr);
8908 return;
8909 }
8910
8911
8912 /* 2) read register 0xc200_0000 (SPI_FW_STATUS) */
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008913 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0000);
8914 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200);
8915 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x000A);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008916 for (cnt = 0; cnt < 100; cnt++) {
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008917 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008918 if (val & 1)
8919 break;
8920 udelay(5);
8921 }
8922 if (cnt == 100) {
8923 DP(NETIF_MSG_LINK, "Unable to read 848xx phy fw version(2)\n");
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008924 bnx2x_save_spirom_version(bp, port, 0,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008925 phy->ver_addr);
8926 return;
8927 }
8928
8929 /* lower 16 bits of the register SPI_FW_STATUS */
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008930 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81B, &fw_ver1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008931 /* upper 16 bits of register SPI_FW_STATUS */
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008932 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81C, &fw_ver2);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008933
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008934 bnx2x_save_spirom_version(bp, port, (fw_ver2<<16) | fw_ver1,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008935 phy->ver_addr);
8936}
8937
8938static void bnx2x_848xx_set_led(struct bnx2x *bp,
8939 struct bnx2x_phy *phy)
8940{
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008941 u16 val;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008942
8943 /* PHYC_CTL_LED_CTL */
8944 bnx2x_cl45_read(bp, phy,
8945 MDIO_PMA_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008946 MDIO_PMA_REG_8481_LINK_SIGNAL, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008947 val &= 0xFE00;
8948 val |= 0x0092;
8949
8950 bnx2x_cl45_write(bp, phy,
8951 MDIO_PMA_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008952 MDIO_PMA_REG_8481_LINK_SIGNAL, val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008953
8954 bnx2x_cl45_write(bp, phy,
8955 MDIO_PMA_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008956 MDIO_PMA_REG_8481_LED1_MASK,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008957 0x80);
8958
8959 bnx2x_cl45_write(bp, phy,
8960 MDIO_PMA_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008961 MDIO_PMA_REG_8481_LED2_MASK,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008962 0x18);
8963
Yaniv Rosnerf25b3c82011-01-18 04:33:47 +00008964 /* Select activity source by Tx and Rx, as suggested by PHY AE */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008965 bnx2x_cl45_write(bp, phy,
8966 MDIO_PMA_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008967 MDIO_PMA_REG_8481_LED3_MASK,
Yaniv Rosnerf25b3c82011-01-18 04:33:47 +00008968 0x0006);
8969
8970 /* Select the closest activity blink rate to that in 10/100/1000 */
8971 bnx2x_cl45_write(bp, phy,
8972 MDIO_PMA_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008973 MDIO_PMA_REG_8481_LED3_BLINK,
Yaniv Rosnerf25b3c82011-01-18 04:33:47 +00008974 0);
8975
8976 bnx2x_cl45_read(bp, phy,
8977 MDIO_PMA_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008978 MDIO_PMA_REG_84823_CTL_LED_CTL_1, &val);
Yaniv Rosnerf25b3c82011-01-18 04:33:47 +00008979 val |= MDIO_PMA_REG_84823_LED3_STRETCH_EN; /* stretch_en for LED3*/
8980
8981 bnx2x_cl45_write(bp, phy,
8982 MDIO_PMA_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008983 MDIO_PMA_REG_84823_CTL_LED_CTL_1, val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008984
8985 /* 'Interrupt Mask' */
8986 bnx2x_cl45_write(bp, phy,
8987 MDIO_AN_DEVAD,
8988 0xFFFB, 0xFFFD);
8989}
8990
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00008991static int bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy,
8992 struct link_params *params,
8993 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008994{
8995 struct bnx2x *bp = params->bp;
8996 u16 autoneg_val, an_1000_val, an_10_100_val;
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00008997 u16 tmp_req_line_speed;
8998
8999 tmp_req_line_speed = phy->req_line_speed;
9000 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833)
9001 if (phy->req_line_speed == SPEED_10000)
9002 phy->req_line_speed = SPEED_AUTO_NEG;
9003
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00009004 /*
9005 * This phy uses the NIG latch mechanism since link indication
9006 * arrives through its LED4 and not via its LASI signal, so we
9007 * get steady signal instead of clear on read
9008 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009009 bnx2x_bits_en(bp, NIG_REG_LATCH_BC_0 + params->port*4,
9010 1 << NIG_LATCH_BC_ENABLE_MI_INT);
9011
9012 bnx2x_cl45_write(bp, phy,
9013 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x0000);
9014
9015 bnx2x_848xx_set_led(bp, phy);
9016
9017 /* set 1000 speed advertisement */
9018 bnx2x_cl45_read(bp, phy,
9019 MDIO_AN_DEVAD, MDIO_AN_REG_8481_1000T_CTRL,
9020 &an_1000_val);
9021
9022 bnx2x_ext_phy_set_pause(params, phy, vars);
9023 bnx2x_cl45_read(bp, phy,
9024 MDIO_AN_DEVAD,
9025 MDIO_AN_REG_8481_LEGACY_AN_ADV,
9026 &an_10_100_val);
9027 bnx2x_cl45_read(bp, phy,
9028 MDIO_AN_DEVAD, MDIO_AN_REG_8481_LEGACY_MII_CTRL,
9029 &autoneg_val);
9030 /* Disable forced speed */
9031 autoneg_val &= ~((1<<6) | (1<<8) | (1<<9) | (1<<12) | (1<<13));
9032 an_10_100_val &= ~((1<<5) | (1<<6) | (1<<7) | (1<<8));
9033
9034 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
9035 (phy->speed_cap_mask &
9036 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) ||
9037 (phy->req_line_speed == SPEED_1000)) {
9038 an_1000_val |= (1<<8);
9039 autoneg_val |= (1<<9 | 1<<12);
9040 if (phy->req_duplex == DUPLEX_FULL)
9041 an_1000_val |= (1<<9);
9042 DP(NETIF_MSG_LINK, "Advertising 1G\n");
9043 } else
9044 an_1000_val &= ~((1<<8) | (1<<9));
9045
9046 bnx2x_cl45_write(bp, phy,
9047 MDIO_AN_DEVAD, MDIO_AN_REG_8481_1000T_CTRL,
9048 an_1000_val);
9049
9050 /* set 10 speed advertisement */
9051 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
9052 (phy->speed_cap_mask &
9053 (PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL |
9054 PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF)))) {
9055 an_10_100_val |= (1<<7);
9056 /* Enable autoneg and restart autoneg for legacy speeds */
9057 autoneg_val |= (1<<9 | 1<<12);
9058
9059 if (phy->req_duplex == DUPLEX_FULL)
9060 an_10_100_val |= (1<<8);
9061 DP(NETIF_MSG_LINK, "Advertising 100M\n");
9062 }
9063 /* set 10 speed advertisement */
9064 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
9065 (phy->speed_cap_mask &
9066 (PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL |
9067 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF)))) {
9068 an_10_100_val |= (1<<5);
9069 autoneg_val |= (1<<9 | 1<<12);
9070 if (phy->req_duplex == DUPLEX_FULL)
9071 an_10_100_val |= (1<<6);
9072 DP(NETIF_MSG_LINK, "Advertising 10M\n");
9073 }
9074
9075 /* Only 10/100 are allowed to work in FORCE mode */
9076 if (phy->req_line_speed == SPEED_100) {
9077 autoneg_val |= (1<<13);
9078 /* Enabled AUTO-MDIX when autoneg is disabled */
9079 bnx2x_cl45_write(bp, phy,
9080 MDIO_AN_DEVAD, MDIO_AN_REG_8481_AUX_CTRL,
9081 (1<<15 | 1<<9 | 7<<0));
9082 DP(NETIF_MSG_LINK, "Setting 100M force\n");
9083 }
9084 if (phy->req_line_speed == SPEED_10) {
9085 /* Enabled AUTO-MDIX when autoneg is disabled */
9086 bnx2x_cl45_write(bp, phy,
9087 MDIO_AN_DEVAD, MDIO_AN_REG_8481_AUX_CTRL,
9088 (1<<15 | 1<<9 | 7<<0));
9089 DP(NETIF_MSG_LINK, "Setting 10M force\n");
9090 }
9091
9092 bnx2x_cl45_write(bp, phy,
9093 MDIO_AN_DEVAD, MDIO_AN_REG_8481_LEGACY_AN_ADV,
9094 an_10_100_val);
9095
9096 if (phy->req_duplex == DUPLEX_FULL)
9097 autoneg_val |= (1<<8);
9098
9099 bnx2x_cl45_write(bp, phy,
9100 MDIO_AN_DEVAD,
9101 MDIO_AN_REG_8481_LEGACY_MII_CTRL, autoneg_val);
9102
9103 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
9104 (phy->speed_cap_mask &
9105 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) ||
9106 (phy->req_line_speed == SPEED_10000)) {
Yaniv Rosner9045f6b2011-05-31 21:28:27 +00009107 DP(NETIF_MSG_LINK, "Advertising 10G\n");
9108 /* Restart autoneg for 10G*/
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009109
Yaniv Rosner9045f6b2011-05-31 21:28:27 +00009110 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009111 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL,
9112 0x3200);
9113 } else if (phy->req_line_speed != SPEED_10 &&
9114 phy->req_line_speed != SPEED_100) {
9115 bnx2x_cl45_write(bp, phy,
9116 MDIO_AN_DEVAD,
9117 MDIO_AN_REG_8481_10GBASE_T_AN_CTRL,
9118 1);
9119 }
9120 /* Save spirom version */
9121 bnx2x_save_848xx_spirom_version(phy, params);
9122
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009123 phy->req_line_speed = tmp_req_line_speed;
9124
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009125 return 0;
9126}
9127
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00009128static int bnx2x_8481_config_init(struct bnx2x_phy *phy,
9129 struct link_params *params,
9130 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009131{
9132 struct bnx2x *bp = params->bp;
9133 /* Restore normal power mode*/
9134 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00009135 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009136
9137 /* HW reset */
9138 bnx2x_ext_phy_hw_reset(bp, params->port);
Yaniv Rosner6d870c32011-01-31 04:22:20 +00009139 bnx2x_wait_reset_complete(bp, phy, params);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009140
9141 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
9142 return bnx2x_848xx_cmn_config_init(phy, params, vars);
9143}
9144
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009145
9146#define PHY84833_HDSHK_WAIT 300
9147static int bnx2x_84833_pair_swap_cfg(struct bnx2x_phy *phy,
9148 struct link_params *params,
9149 struct link_vars *vars)
9150{
9151 u32 idx;
9152 u16 val;
9153 u16 data = 0x01b1;
9154 struct bnx2x *bp = params->bp;
9155 /* Do pair swap */
9156
9157
9158 /* Write CMD_OPEN_OVERRIDE to STATUS reg */
9159 bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
9160 MDIO_84833_TOP_CFG_SCRATCH_REG2,
9161 PHY84833_CMD_OPEN_OVERRIDE);
9162 for (idx = 0; idx < PHY84833_HDSHK_WAIT; idx++) {
9163 bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
9164 MDIO_84833_TOP_CFG_SCRATCH_REG2, &val);
9165 if (val == PHY84833_CMD_OPEN_FOR_CMDS)
9166 break;
9167 msleep(1);
9168 }
9169 if (idx >= PHY84833_HDSHK_WAIT) {
9170 DP(NETIF_MSG_LINK, "Pairswap: FW not ready.\n");
9171 return -EINVAL;
9172 }
9173
9174 bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
9175 MDIO_84833_TOP_CFG_SCRATCH_REG4,
9176 data);
9177 /* Issue pair swap command */
9178 bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
9179 MDIO_84833_TOP_CFG_SCRATCH_REG0,
9180 PHY84833_DIAG_CMD_PAIR_SWAP_CHANGE);
9181 for (idx = 0; idx < PHY84833_HDSHK_WAIT; idx++) {
9182 bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
9183 MDIO_84833_TOP_CFG_SCRATCH_REG2, &val);
9184 if ((val == PHY84833_CMD_COMPLETE_PASS) ||
9185 (val == PHY84833_CMD_COMPLETE_ERROR))
9186 break;
9187 msleep(1);
9188 }
9189 if ((idx >= PHY84833_HDSHK_WAIT) ||
9190 (val == PHY84833_CMD_COMPLETE_ERROR)) {
9191 DP(NETIF_MSG_LINK, "Pairswap: override failed.\n");
9192 return -EINVAL;
9193 }
9194 bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
9195 MDIO_84833_TOP_CFG_SCRATCH_REG2,
9196 PHY84833_CMD_CLEAR_COMPLETE);
9197 DP(NETIF_MSG_LINK, "Pairswap OK, val=0x%x\n", data);
9198 return 0;
9199}
9200
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00009201static int bnx2x_848x3_config_init(struct bnx2x_phy *phy,
9202 struct link_params *params,
9203 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009204{
9205 struct bnx2x *bp = params->bp;
Yaniv Rosner6a71bbe2010-11-01 05:32:31 +00009206 u8 port, initialize = 1;
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009207 u16 val;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009208 u16 temp;
Yaniv Rosner1bef68e2011-01-31 04:22:46 +00009209 u32 actual_phy_selection, cms_enable;
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00009210 int rc = 0;
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00009211
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009212 msleep(1);
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009213
9214 if (!(CHIP_IS_E1(bp)))
Yaniv Rosner6a71bbe2010-11-01 05:32:31 +00009215 port = BP_PATH(bp);
9216 else
9217 port = params->port;
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009218
9219 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823) {
9220 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
9221 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
9222 port);
9223 } else {
9224 bnx2x_cl45_write(bp, phy,
9225 MDIO_PMA_DEVAD,
9226 MDIO_PMA_REG_CTRL, 0x8000);
9227 }
9228
Yaniv Rosner6d870c32011-01-31 04:22:20 +00009229 bnx2x_wait_reset_complete(bp, phy, params);
Yaniv Rosner9bffeac2010-11-01 05:32:27 +00009230 /* Wait for GPHY to come out of reset */
9231 msleep(50);
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009232
9233 /* Bring PHY out of super isolate mode */
9234 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) {
9235 bnx2x_cl45_read(bp, phy,
9236 MDIO_CTL_DEVAD,
9237 MDIO_84833_TOP_CFG_XGPHY_STRAP1, &val);
9238 val &= ~MDIO_84833_SUPER_ISOLATE;
9239 bnx2x_cl45_write(bp, phy,
9240 MDIO_CTL_DEVAD,
9241 MDIO_84833_TOP_CFG_XGPHY_STRAP1, val);
9242 bnx2x_wait_reset_complete(bp, phy, params);
9243 }
9244
9245 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833)
9246 bnx2x_84833_pair_swap_cfg(phy, params, vars);
9247
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00009248 /*
9249 * BCM84823 requires that XGXS links up first @ 10G for normal behavior
9250 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009251 temp = vars->line_speed;
9252 vars->line_speed = SPEED_10000;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009253 bnx2x_set_autoneg(&params->phy[INT_PHY], params, vars, 0);
9254 bnx2x_program_serdes(&params->phy[INT_PHY], params, vars);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009255 vars->line_speed = temp;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009256
9257 /* Set dual-media configuration according to configuration */
9258
9259 bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009260 MDIO_CTL_REG_84823_MEDIA, &val);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009261 val &= ~(MDIO_CTL_REG_84823_MEDIA_MAC_MASK |
9262 MDIO_CTL_REG_84823_MEDIA_LINE_MASK |
9263 MDIO_CTL_REG_84823_MEDIA_COPPER_CORE_DOWN |
9264 MDIO_CTL_REG_84823_MEDIA_PRIORITY_MASK |
9265 MDIO_CTL_REG_84823_MEDIA_FIBER_1G);
9266 val |= MDIO_CTL_REG_84823_CTRL_MAC_XFI |
9267 MDIO_CTL_REG_84823_MEDIA_LINE_XAUI_L;
9268
9269 actual_phy_selection = bnx2x_phy_selection(params);
9270
9271 switch (actual_phy_selection) {
9272 case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT:
Lucas De Marchi25985ed2011-03-30 22:57:33 -03009273 /* Do nothing. Essentially this is like the priority copper */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009274 break;
9275 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
9276 val |= MDIO_CTL_REG_84823_MEDIA_PRIORITY_COPPER;
9277 break;
9278 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
9279 val |= MDIO_CTL_REG_84823_MEDIA_PRIORITY_FIBER;
9280 break;
9281 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY:
9282 /* Do nothing here. The first PHY won't be initialized at all */
9283 break;
9284 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY:
9285 val |= MDIO_CTL_REG_84823_MEDIA_COPPER_CORE_DOWN;
9286 initialize = 0;
9287 break;
9288 }
9289 if (params->phy[EXT_PHY2].req_line_speed == SPEED_1000)
9290 val |= MDIO_CTL_REG_84823_MEDIA_FIBER_1G;
9291
9292 bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009293 MDIO_CTL_REG_84823_MEDIA, val);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009294 DP(NETIF_MSG_LINK, "Multi_phy config = 0x%x, Media control = 0x%x\n",
9295 params->multi_phy_config, val);
9296
9297 if (initialize)
9298 rc = bnx2x_848xx_cmn_config_init(phy, params, vars);
9299 else
9300 bnx2x_save_848xx_spirom_version(phy, params);
Yaniv Rosner1bef68e2011-01-31 04:22:46 +00009301 cms_enable = REG_RD(bp, params->shmem_base +
9302 offsetof(struct shmem_region,
9303 dev_info.port_hw_config[params->port].default_cfg)) &
9304 PORT_HW_CFG_ENABLE_CMS_MASK;
9305
9306 bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
9307 MDIO_CTL_REG_84823_USER_CTRL_REG, &val);
9308 if (cms_enable)
9309 val |= MDIO_CTL_REG_84823_USER_CTRL_CMS;
9310 else
9311 val &= ~MDIO_CTL_REG_84823_USER_CTRL_CMS;
9312 bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
9313 MDIO_CTL_REG_84823_USER_CTRL_REG, val);
9314
9315
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009316 return rc;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009317}
9318
9319static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00009320 struct link_params *params,
9321 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009322{
9323 struct bnx2x *bp = params->bp;
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009324 u16 val, val1, val2;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009325 u8 link_up = 0;
9326
Yaniv Rosnerc87bca12011-01-31 04:22:41 +00009327
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009328 /* Check 10G-BaseT link status */
9329 /* Check PMD signal ok */
9330 bnx2x_cl45_read(bp, phy,
9331 MDIO_AN_DEVAD, 0xFFFA, &val1);
9332 bnx2x_cl45_read(bp, phy,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009333 MDIO_PMA_DEVAD, MDIO_PMA_REG_8481_PMD_SIGNAL,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009334 &val2);
9335 DP(NETIF_MSG_LINK, "BCM848xx: PMD_SIGNAL 1.a811 = 0x%x\n", val2);
9336
9337 /* Check link 10G */
9338 if (val2 & (1<<11)) {
9339 vars->line_speed = SPEED_10000;
Yaniv Rosner791f18c2011-01-18 04:33:42 +00009340 vars->duplex = DUPLEX_FULL;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009341 link_up = 1;
9342 bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
9343 } else { /* Check Legacy speed link */
9344 u16 legacy_status, legacy_speed;
9345
9346 /* Enable expansion register 0x42 (Operation mode status) */
9347 bnx2x_cl45_write(bp, phy,
9348 MDIO_AN_DEVAD,
9349 MDIO_AN_REG_8481_EXPANSION_REG_ACCESS, 0xf42);
9350
9351 /* Get legacy speed operation status */
9352 bnx2x_cl45_read(bp, phy,
9353 MDIO_AN_DEVAD,
9354 MDIO_AN_REG_8481_EXPANSION_REG_RD_RW,
9355 &legacy_status);
9356
9357 DP(NETIF_MSG_LINK, "Legacy speed status"
9358 " = 0x%x\n", legacy_status);
9359 link_up = ((legacy_status & (1<<11)) == (1<<11));
9360 if (link_up) {
9361 legacy_speed = (legacy_status & (3<<9));
9362 if (legacy_speed == (0<<9))
9363 vars->line_speed = SPEED_10;
9364 else if (legacy_speed == (1<<9))
9365 vars->line_speed = SPEED_100;
9366 else if (legacy_speed == (2<<9))
9367 vars->line_speed = SPEED_1000;
9368 else /* Should not happen */
9369 vars->line_speed = 0;
9370
9371 if (legacy_status & (1<<8))
9372 vars->duplex = DUPLEX_FULL;
9373 else
9374 vars->duplex = DUPLEX_HALF;
9375
9376 DP(NETIF_MSG_LINK, "Link is up in %dMbps,"
9377 " is_duplex_full= %d\n", vars->line_speed,
9378 (vars->duplex == DUPLEX_FULL));
9379 /* Check legacy speed AN resolution */
9380 bnx2x_cl45_read(bp, phy,
9381 MDIO_AN_DEVAD,
9382 MDIO_AN_REG_8481_LEGACY_MII_STATUS,
9383 &val);
9384 if (val & (1<<5))
9385 vars->link_status |=
9386 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
9387 bnx2x_cl45_read(bp, phy,
9388 MDIO_AN_DEVAD,
9389 MDIO_AN_REG_8481_LEGACY_AN_EXPANSION,
9390 &val);
9391 if ((val & (1<<0)) == 0)
9392 vars->link_status |=
9393 LINK_STATUS_PARALLEL_DETECTION_USED;
9394 }
9395 }
9396 if (link_up) {
9397 DP(NETIF_MSG_LINK, "BCM84823: link speed is %d\n",
9398 vars->line_speed);
9399 bnx2x_ext_phy_resolve_fc(phy, params, vars);
9400 }
9401
9402 return link_up;
9403}
9404
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00009405
9406static int bnx2x_848xx_format_ver(u32 raw_ver, u8 *str, u16 *len)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009407{
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00009408 int status = 0;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009409 u32 spirom_ver;
9410 spirom_ver = ((raw_ver & 0xF80) >> 7) << 16 | (raw_ver & 0x7F);
9411 status = bnx2x_format_ver(spirom_ver, str, len);
9412 return status;
9413}
9414
9415static void bnx2x_8481_hw_reset(struct bnx2x_phy *phy,
9416 struct link_params *params)
9417{
9418 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00009419 MISC_REGISTERS_GPIO_OUTPUT_LOW, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009420 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00009421 MISC_REGISTERS_GPIO_OUTPUT_LOW, 1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009422}
9423
9424static void bnx2x_8481_link_reset(struct bnx2x_phy *phy,
9425 struct link_params *params)
9426{
9427 bnx2x_cl45_write(params->bp, phy,
9428 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x0000);
9429 bnx2x_cl45_write(params->bp, phy,
9430 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1);
9431}
9432
9433static void bnx2x_848x3_link_reset(struct bnx2x_phy *phy,
9434 struct link_params *params)
9435{
9436 struct bnx2x *bp = params->bp;
Yaniv Rosner6a71bbe2010-11-01 05:32:31 +00009437 u8 port;
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009438
9439 if (!(CHIP_IS_E1(bp)))
Yaniv Rosner6a71bbe2010-11-01 05:32:31 +00009440 port = BP_PATH(bp);
9441 else
9442 port = params->port;
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009443
9444 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823) {
9445 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
9446 MISC_REGISTERS_GPIO_OUTPUT_LOW,
9447 port);
9448 } else {
9449 bnx2x_cl45_write(bp, phy,
9450 MDIO_PMA_DEVAD,
9451 MDIO_PMA_REG_CTRL, 0x800);
9452 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009453}
9454
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00009455static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy,
9456 struct link_params *params, u8 mode)
9457{
9458 struct bnx2x *bp = params->bp;
9459 u16 val;
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009460 u8 port;
9461
9462 if (!(CHIP_IS_E1(bp)))
9463 port = BP_PATH(bp);
9464 else
9465 port = params->port;
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00009466
9467 switch (mode) {
9468 case LED_MODE_OFF:
9469
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009470 DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE OFF\n", port);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00009471
9472 if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
9473 SHARED_HW_CFG_LED_EXTPHY1) {
9474
9475 /* Set LED masks */
9476 bnx2x_cl45_write(bp, phy,
9477 MDIO_PMA_DEVAD,
9478 MDIO_PMA_REG_8481_LED1_MASK,
9479 0x0);
9480
9481 bnx2x_cl45_write(bp, phy,
9482 MDIO_PMA_DEVAD,
9483 MDIO_PMA_REG_8481_LED2_MASK,
9484 0x0);
9485
9486 bnx2x_cl45_write(bp, phy,
9487 MDIO_PMA_DEVAD,
9488 MDIO_PMA_REG_8481_LED3_MASK,
9489 0x0);
9490
9491 bnx2x_cl45_write(bp, phy,
9492 MDIO_PMA_DEVAD,
9493 MDIO_PMA_REG_8481_LED5_MASK,
9494 0x0);
9495
9496 } else {
9497 bnx2x_cl45_write(bp, phy,
9498 MDIO_PMA_DEVAD,
9499 MDIO_PMA_REG_8481_LED1_MASK,
9500 0x0);
9501 }
9502 break;
9503 case LED_MODE_FRONT_PANEL_OFF:
9504
9505 DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE FRONT PANEL OFF\n",
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009506 port);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00009507
9508 if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
9509 SHARED_HW_CFG_LED_EXTPHY1) {
9510
9511 /* Set LED masks */
9512 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00009513 MDIO_PMA_DEVAD,
9514 MDIO_PMA_REG_8481_LED1_MASK,
9515 0x0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00009516
9517 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00009518 MDIO_PMA_DEVAD,
9519 MDIO_PMA_REG_8481_LED2_MASK,
9520 0x0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00009521
9522 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00009523 MDIO_PMA_DEVAD,
9524 MDIO_PMA_REG_8481_LED3_MASK,
9525 0x0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00009526
9527 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00009528 MDIO_PMA_DEVAD,
9529 MDIO_PMA_REG_8481_LED5_MASK,
9530 0x20);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00009531
9532 } else {
9533 bnx2x_cl45_write(bp, phy,
9534 MDIO_PMA_DEVAD,
9535 MDIO_PMA_REG_8481_LED1_MASK,
9536 0x0);
9537 }
9538 break;
9539 case LED_MODE_ON:
9540
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009541 DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE ON\n", port);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00009542
9543 if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
9544 SHARED_HW_CFG_LED_EXTPHY1) {
9545 /* Set control reg */
9546 bnx2x_cl45_read(bp, phy,
9547 MDIO_PMA_DEVAD,
9548 MDIO_PMA_REG_8481_LINK_SIGNAL,
9549 &val);
9550 val &= 0x8000;
9551 val |= 0x2492;
9552
9553 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00009554 MDIO_PMA_DEVAD,
9555 MDIO_PMA_REG_8481_LINK_SIGNAL,
9556 val);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00009557
9558 /* Set LED masks */
9559 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00009560 MDIO_PMA_DEVAD,
9561 MDIO_PMA_REG_8481_LED1_MASK,
9562 0x0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00009563
9564 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00009565 MDIO_PMA_DEVAD,
9566 MDIO_PMA_REG_8481_LED2_MASK,
9567 0x20);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00009568
9569 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00009570 MDIO_PMA_DEVAD,
9571 MDIO_PMA_REG_8481_LED3_MASK,
9572 0x20);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00009573
9574 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00009575 MDIO_PMA_DEVAD,
9576 MDIO_PMA_REG_8481_LED5_MASK,
9577 0x0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00009578 } else {
9579 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00009580 MDIO_PMA_DEVAD,
9581 MDIO_PMA_REG_8481_LED1_MASK,
9582 0x20);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00009583 }
9584 break;
9585
9586 case LED_MODE_OPER:
9587
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009588 DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE OPER\n", port);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00009589
9590 if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
9591 SHARED_HW_CFG_LED_EXTPHY1) {
9592
9593 /* Set control reg */
9594 bnx2x_cl45_read(bp, phy,
9595 MDIO_PMA_DEVAD,
9596 MDIO_PMA_REG_8481_LINK_SIGNAL,
9597 &val);
9598
9599 if (!((val &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00009600 MDIO_PMA_REG_8481_LINK_SIGNAL_LED4_ENABLE_MASK)
9601 >> MDIO_PMA_REG_8481_LINK_SIGNAL_LED4_ENABLE_SHIFT)) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00009602 DP(NETIF_MSG_LINK, "Setting LINK_SIGNAL\n");
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00009603 bnx2x_cl45_write(bp, phy,
9604 MDIO_PMA_DEVAD,
9605 MDIO_PMA_REG_8481_LINK_SIGNAL,
9606 0xa492);
9607 }
9608
9609 /* Set LED masks */
9610 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00009611 MDIO_PMA_DEVAD,
9612 MDIO_PMA_REG_8481_LED1_MASK,
9613 0x10);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00009614
9615 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00009616 MDIO_PMA_DEVAD,
9617 MDIO_PMA_REG_8481_LED2_MASK,
9618 0x80);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00009619
9620 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00009621 MDIO_PMA_DEVAD,
9622 MDIO_PMA_REG_8481_LED3_MASK,
9623 0x98);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00009624
9625 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00009626 MDIO_PMA_DEVAD,
9627 MDIO_PMA_REG_8481_LED5_MASK,
9628 0x40);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00009629
9630 } else {
9631 bnx2x_cl45_write(bp, phy,
9632 MDIO_PMA_DEVAD,
9633 MDIO_PMA_REG_8481_LED1_MASK,
9634 0x80);
Yaniv Rosner53eda062011-01-30 04:14:55 +00009635
9636 /* Tell LED3 to blink on source */
9637 bnx2x_cl45_read(bp, phy,
9638 MDIO_PMA_DEVAD,
9639 MDIO_PMA_REG_8481_LINK_SIGNAL,
9640 &val);
9641 val &= ~(7<<6);
9642 val |= (1<<6); /* A83B[8:6]= 1 */
9643 bnx2x_cl45_write(bp, phy,
9644 MDIO_PMA_DEVAD,
9645 MDIO_PMA_REG_8481_LINK_SIGNAL,
9646 val);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00009647 }
9648 break;
9649 }
9650}
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009651/******************************************************************/
Yaniv Rosner6583e332011-06-14 01:34:17 +00009652/* 54616S PHY SECTION */
9653/******************************************************************/
9654static int bnx2x_54616s_config_init(struct bnx2x_phy *phy,
9655 struct link_params *params,
9656 struct link_vars *vars)
9657{
9658 struct bnx2x *bp = params->bp;
9659 u8 port;
9660 u16 autoneg_val, an_1000_val, an_10_100_val, fc_val, temp;
9661 u32 cfg_pin;
9662
9663 DP(NETIF_MSG_LINK, "54616S cfg init\n");
9664 usleep_range(1000, 1000);
9665
9666 /* This works with E3 only, no need to check the chip
9667 before determining the port. */
9668 port = params->port;
9669
9670 cfg_pin = (REG_RD(bp, params->shmem_base +
9671 offsetof(struct shmem_region,
9672 dev_info.port_hw_config[port].e3_cmn_pin_cfg)) &
9673 PORT_HW_CFG_E3_PHY_RESET_MASK) >>
9674 PORT_HW_CFG_E3_PHY_RESET_SHIFT;
9675
9676 /* Drive pin high to bring the GPHY out of reset. */
9677 bnx2x_set_cfg_pin(bp, cfg_pin, 1);
9678
9679 /* wait for GPHY to reset */
9680 msleep(50);
9681
9682 /* reset phy */
9683 bnx2x_cl22_write(bp, phy,
9684 MDIO_PMA_REG_CTRL, 0x8000);
9685 bnx2x_wait_reset_complete(bp, phy, params);
9686
9687 /*wait for GPHY to reset */
9688 msleep(50);
9689
9690 /* Configure LED4: set to INTR (0x6). */
9691 /* Accessing shadow register 0xe. */
9692 bnx2x_cl22_write(bp, phy,
9693 MDIO_REG_GPHY_SHADOW,
9694 MDIO_REG_GPHY_SHADOW_LED_SEL2);
9695 bnx2x_cl22_read(bp, phy,
9696 MDIO_REG_GPHY_SHADOW,
9697 &temp);
9698 temp &= ~(0xf << 4);
9699 temp |= (0x6 << 4);
9700 bnx2x_cl22_write(bp, phy,
9701 MDIO_REG_GPHY_SHADOW,
9702 MDIO_REG_GPHY_SHADOW_WR_ENA | temp);
9703 /* Configure INTR based on link status change. */
9704 bnx2x_cl22_write(bp, phy,
9705 MDIO_REG_INTR_MASK,
9706 ~MDIO_REG_INTR_MASK_LINK_STATUS);
9707
9708 /* Flip the signal detect polarity (set 0x1c.0x1e[8]). */
9709 bnx2x_cl22_write(bp, phy,
9710 MDIO_REG_GPHY_SHADOW,
9711 MDIO_REG_GPHY_SHADOW_AUTO_DET_MED);
9712 bnx2x_cl22_read(bp, phy,
9713 MDIO_REG_GPHY_SHADOW,
9714 &temp);
9715 temp |= MDIO_REG_GPHY_SHADOW_INVERT_FIB_SD;
9716 bnx2x_cl22_write(bp, phy,
9717 MDIO_REG_GPHY_SHADOW,
9718 MDIO_REG_GPHY_SHADOW_WR_ENA | temp);
9719
9720 /* Set up fc */
9721 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
9722 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
9723 fc_val = 0;
9724 if ((vars->ieee_fc & MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
9725 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC)
9726 fc_val |= MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC;
9727
9728 if ((vars->ieee_fc & MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
9729 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH)
9730 fc_val |= MDIO_AN_REG_ADV_PAUSE_PAUSE;
9731
9732 /* read all advertisement */
9733 bnx2x_cl22_read(bp, phy,
9734 0x09,
9735 &an_1000_val);
9736
9737 bnx2x_cl22_read(bp, phy,
9738 0x04,
9739 &an_10_100_val);
9740
9741 bnx2x_cl22_read(bp, phy,
9742 MDIO_PMA_REG_CTRL,
9743 &autoneg_val);
9744
9745 /* Disable forced speed */
9746 autoneg_val &= ~((1<<6) | (1<<8) | (1<<9) | (1<<12) | (1<<13));
9747 an_10_100_val &= ~((1<<5) | (1<<6) | (1<<7) | (1<<8) | (1<<10) |
9748 (1<<11));
9749
9750 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
9751 (phy->speed_cap_mask &
9752 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) ||
9753 (phy->req_line_speed == SPEED_1000)) {
9754 an_1000_val |= (1<<8);
9755 autoneg_val |= (1<<9 | 1<<12);
9756 if (phy->req_duplex == DUPLEX_FULL)
9757 an_1000_val |= (1<<9);
9758 DP(NETIF_MSG_LINK, "Advertising 1G\n");
9759 } else
9760 an_1000_val &= ~((1<<8) | (1<<9));
9761
9762 bnx2x_cl22_write(bp, phy,
9763 0x09,
9764 an_1000_val);
9765 bnx2x_cl22_read(bp, phy,
9766 0x09,
9767 &an_1000_val);
9768
9769 /* set 100 speed advertisement */
9770 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
9771 (phy->speed_cap_mask &
9772 (PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL |
9773 PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF)))) {
9774 an_10_100_val |= (1<<7);
9775 /* Enable autoneg and restart autoneg for legacy speeds */
9776 autoneg_val |= (1<<9 | 1<<12);
9777
9778 if (phy->req_duplex == DUPLEX_FULL)
9779 an_10_100_val |= (1<<8);
9780 DP(NETIF_MSG_LINK, "Advertising 100M\n");
9781 }
9782
9783 /* set 10 speed advertisement */
9784 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
9785 (phy->speed_cap_mask &
9786 (PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL |
9787 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF)))) {
9788 an_10_100_val |= (1<<5);
9789 autoneg_val |= (1<<9 | 1<<12);
9790 if (phy->req_duplex == DUPLEX_FULL)
9791 an_10_100_val |= (1<<6);
9792 DP(NETIF_MSG_LINK, "Advertising 10M\n");
9793 }
9794
9795 /* Only 10/100 are allowed to work in FORCE mode */
9796 if (phy->req_line_speed == SPEED_100) {
9797 autoneg_val |= (1<<13);
9798 /* Enabled AUTO-MDIX when autoneg is disabled */
9799 bnx2x_cl22_write(bp, phy,
9800 0x18,
9801 (1<<15 | 1<<9 | 7<<0));
9802 DP(NETIF_MSG_LINK, "Setting 100M force\n");
9803 }
9804 if (phy->req_line_speed == SPEED_10) {
9805 /* Enabled AUTO-MDIX when autoneg is disabled */
9806 bnx2x_cl22_write(bp, phy,
9807 0x18,
9808 (1<<15 | 1<<9 | 7<<0));
9809 DP(NETIF_MSG_LINK, "Setting 10M force\n");
9810 }
9811
9812 bnx2x_cl22_write(bp, phy,
9813 0x04,
9814 an_10_100_val | fc_val);
9815
9816 if (phy->req_duplex == DUPLEX_FULL)
9817 autoneg_val |= (1<<8);
9818
9819 bnx2x_cl22_write(bp, phy,
9820 MDIO_PMA_REG_CTRL, autoneg_val);
9821
9822 return 0;
9823}
9824
9825static void bnx2x_54616s_set_link_led(struct bnx2x_phy *phy,
9826 struct link_params *params, u8 mode)
9827{
9828 struct bnx2x *bp = params->bp;
9829 DP(NETIF_MSG_LINK, "54616S set link led (mode=%x)\n", mode);
9830 switch (mode) {
9831 case LED_MODE_FRONT_PANEL_OFF:
9832 case LED_MODE_OFF:
9833 case LED_MODE_OPER:
9834 case LED_MODE_ON:
9835 default:
9836 break;
9837 }
9838 return;
9839}
9840
9841static void bnx2x_54616s_link_reset(struct bnx2x_phy *phy,
9842 struct link_params *params)
9843{
9844 struct bnx2x *bp = params->bp;
9845 u32 cfg_pin;
9846 u8 port;
9847
9848 /* This works with E3 only, no need to check the chip
9849 before determining the port. */
9850 port = params->port;
9851 cfg_pin = (REG_RD(bp, params->shmem_base +
9852 offsetof(struct shmem_region,
9853 dev_info.port_hw_config[port].e3_cmn_pin_cfg)) &
9854 PORT_HW_CFG_E3_PHY_RESET_MASK) >>
9855 PORT_HW_CFG_E3_PHY_RESET_SHIFT;
9856
9857 /* Drive pin low to put GPHY in reset. */
9858 bnx2x_set_cfg_pin(bp, cfg_pin, 0);
9859}
9860
9861static u8 bnx2x_54616s_read_status(struct bnx2x_phy *phy,
9862 struct link_params *params,
9863 struct link_vars *vars)
9864{
9865 struct bnx2x *bp = params->bp;
9866 u16 val;
9867 u8 link_up = 0;
9868 u16 legacy_status, legacy_speed;
9869
9870 /* Get speed operation status */
9871 bnx2x_cl22_read(bp, phy,
9872 0x19,
9873 &legacy_status);
9874 DP(NETIF_MSG_LINK, "54616S read_status: 0x%x\n", legacy_status);
9875
9876 /* Read status to clear the PHY interrupt. */
9877 bnx2x_cl22_read(bp, phy,
9878 MDIO_REG_INTR_STATUS,
9879 &val);
9880
9881 link_up = ((legacy_status & (1<<2)) == (1<<2));
9882
9883 if (link_up) {
9884 legacy_speed = (legacy_status & (7<<8));
9885 if (legacy_speed == (7<<8)) {
9886 vars->line_speed = SPEED_1000;
9887 vars->duplex = DUPLEX_FULL;
9888 } else if (legacy_speed == (6<<8)) {
9889 vars->line_speed = SPEED_1000;
9890 vars->duplex = DUPLEX_HALF;
9891 } else if (legacy_speed == (5<<8)) {
9892 vars->line_speed = SPEED_100;
9893 vars->duplex = DUPLEX_FULL;
9894 }
9895 /* Omitting 100Base-T4 for now */
9896 else if (legacy_speed == (3<<8)) {
9897 vars->line_speed = SPEED_100;
9898 vars->duplex = DUPLEX_HALF;
9899 } else if (legacy_speed == (2<<8)) {
9900 vars->line_speed = SPEED_10;
9901 vars->duplex = DUPLEX_FULL;
9902 } else if (legacy_speed == (1<<8)) {
9903 vars->line_speed = SPEED_10;
9904 vars->duplex = DUPLEX_HALF;
9905 } else /* Should not happen */
9906 vars->line_speed = 0;
9907
9908 DP(NETIF_MSG_LINK, "Link is up in %dMbps,"
9909 " is_duplex_full= %d\n", vars->line_speed,
9910 (vars->duplex == DUPLEX_FULL));
9911
9912 /* Check legacy speed AN resolution */
9913 bnx2x_cl22_read(bp, phy,
9914 0x01,
9915 &val);
9916 if (val & (1<<5))
9917 vars->link_status |=
9918 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
9919 bnx2x_cl22_read(bp, phy,
9920 0x06,
9921 &val);
9922 if ((val & (1<<0)) == 0)
9923 vars->link_status |=
9924 LINK_STATUS_PARALLEL_DETECTION_USED;
9925
9926 DP(NETIF_MSG_LINK, "BCM54616S: link speed is %d\n",
9927 vars->line_speed);
9928 bnx2x_ext_phy_resolve_fc(phy, params, vars);
9929 }
9930 return link_up;
9931}
9932
9933static void bnx2x_54616s_config_loopback(struct bnx2x_phy *phy,
9934 struct link_params *params)
9935{
9936 struct bnx2x *bp = params->bp;
9937 u16 val;
9938 u32 umac_base = params->port ? GRCBASE_UMAC1 : GRCBASE_UMAC0;
9939
9940 DP(NETIF_MSG_LINK, "2PMA/PMD ext_phy_loopback: 54616s\n");
9941
9942 /* Enable master/slave manual mmode and set to master */
9943 /* mii write 9 [bits set 11 12] */
9944 bnx2x_cl22_write(bp, phy, 0x09, 3<<11);
9945
9946 /* forced 1G and disable autoneg */
9947 /* set val [mii read 0] */
9948 /* set val [expr $val & [bits clear 6 12 13]] */
9949 /* set val [expr $val | [bits set 6 8]] */
9950 /* mii write 0 $val */
9951 bnx2x_cl22_read(bp, phy, 0x00, &val);
9952 val &= ~((1<<6) | (1<<12) | (1<<13));
9953 val |= (1<<6) | (1<<8);
9954 bnx2x_cl22_write(bp, phy, 0x00, val);
9955
9956 /* Set external loopback and Tx using 6dB coding */
9957 /* mii write 0x18 7 */
9958 /* set val [mii read 0x18] */
9959 /* mii write 0x18 [expr $val | [bits set 10 15]] */
9960 bnx2x_cl22_write(bp, phy, 0x18, 7);
9961 bnx2x_cl22_read(bp, phy, 0x18, &val);
9962 bnx2x_cl22_write(bp, phy, 0x18, val | (1<<10) | (1<<15));
9963
9964 /* This register opens the gate for the UMAC despite its name */
9965 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + params->port*4, 1);
9966
9967 /*
9968 * Maximum Frame Length (RW). Defines a 14-Bit maximum frame
9969 * length used by the MAC receive logic to check frames.
9970 */
9971 REG_WR(bp, umac_base + UMAC_REG_MAXFR, 0x2710);
9972}
9973
9974/******************************************************************/
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009975/* SFX7101 PHY SECTION */
9976/******************************************************************/
9977static void bnx2x_7101_config_loopback(struct bnx2x_phy *phy,
9978 struct link_params *params)
9979{
9980 struct bnx2x *bp = params->bp;
9981 /* SFX7101_XGXS_TEST1 */
9982 bnx2x_cl45_write(bp, phy,
9983 MDIO_XS_DEVAD, MDIO_XS_SFX7101_XGXS_TEST1, 0x100);
9984}
9985
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00009986static int bnx2x_7101_config_init(struct bnx2x_phy *phy,
9987 struct link_params *params,
9988 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009989{
9990 u16 fw_ver1, fw_ver2, val;
9991 struct bnx2x *bp = params->bp;
9992 DP(NETIF_MSG_LINK, "Setting the SFX7101 LASI indication\n");
9993
9994 /* Restore normal power mode*/
9995 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00009996 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009997 /* HW reset */
9998 bnx2x_ext_phy_hw_reset(bp, params->port);
Yaniv Rosner6d870c32011-01-31 04:22:20 +00009999 bnx2x_wait_reset_complete(bp, phy, params);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010000
10001 bnx2x_cl45_write(bp, phy,
10002 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x1);
10003 DP(NETIF_MSG_LINK, "Setting the SFX7101 LED to blink on traffic\n");
10004 bnx2x_cl45_write(bp, phy,
10005 MDIO_PMA_DEVAD, MDIO_PMA_REG_7107_LED_CNTL, (1<<3));
10006
10007 bnx2x_ext_phy_set_pause(params, phy, vars);
10008 /* Restart autoneg */
10009 bnx2x_cl45_read(bp, phy,
10010 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, &val);
10011 val |= 0x200;
10012 bnx2x_cl45_write(bp, phy,
10013 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, val);
10014
10015 /* Save spirom version */
10016 bnx2x_cl45_read(bp, phy,
10017 MDIO_PMA_DEVAD, MDIO_PMA_REG_7101_VER1, &fw_ver1);
10018
10019 bnx2x_cl45_read(bp, phy,
10020 MDIO_PMA_DEVAD, MDIO_PMA_REG_7101_VER2, &fw_ver2);
10021 bnx2x_save_spirom_version(bp, params->port,
10022 (u32)(fw_ver1<<16 | fw_ver2), phy->ver_addr);
10023 return 0;
10024}
10025
10026static u8 bnx2x_7101_read_status(struct bnx2x_phy *phy,
10027 struct link_params *params,
10028 struct link_vars *vars)
10029{
10030 struct bnx2x *bp = params->bp;
10031 u8 link_up;
10032 u16 val1, val2;
10033 bnx2x_cl45_read(bp, phy,
10034 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val2);
10035 bnx2x_cl45_read(bp, phy,
10036 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
10037 DP(NETIF_MSG_LINK, "10G-base-T LASI status 0x%x->0x%x\n",
10038 val2, val1);
10039 bnx2x_cl45_read(bp, phy,
10040 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
10041 bnx2x_cl45_read(bp, phy,
10042 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
10043 DP(NETIF_MSG_LINK, "10G-base-T PMA status 0x%x->0x%x\n",
10044 val2, val1);
10045 link_up = ((val1 & 4) == 4);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +000010046 /* if link is up print the AN outcome of the SFX7101 PHY */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010047 if (link_up) {
10048 bnx2x_cl45_read(bp, phy,
10049 MDIO_AN_DEVAD, MDIO_AN_REG_MASTER_STATUS,
10050 &val2);
10051 vars->line_speed = SPEED_10000;
Yaniv Rosner791f18c2011-01-18 04:33:42 +000010052 vars->duplex = DUPLEX_FULL;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010053 DP(NETIF_MSG_LINK, "SFX7101 AN status 0x%x->Master=%x\n",
10054 val2, (val2 & (1<<14)));
10055 bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
10056 bnx2x_ext_phy_resolve_fc(phy, params, vars);
10057 }
10058 return link_up;
10059}
10060
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +000010061static int bnx2x_7101_format_ver(u32 spirom_ver, u8 *str, u16 *len)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010062{
10063 if (*len < 5)
10064 return -EINVAL;
10065 str[0] = (spirom_ver & 0xFF);
10066 str[1] = (spirom_ver & 0xFF00) >> 8;
10067 str[2] = (spirom_ver & 0xFF0000) >> 16;
10068 str[3] = (spirom_ver & 0xFF000000) >> 24;
10069 str[4] = '\0';
10070 *len -= 5;
10071 return 0;
10072}
10073
10074void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, struct bnx2x_phy *phy)
10075{
10076 u16 val, cnt;
10077
10078 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010079 MDIO_PMA_DEVAD,
10080 MDIO_PMA_REG_7101_RESET, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010081
10082 for (cnt = 0; cnt < 10; cnt++) {
10083 msleep(50);
10084 /* Writes a self-clearing reset */
10085 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010086 MDIO_PMA_DEVAD,
10087 MDIO_PMA_REG_7101_RESET,
10088 (val | (1<<15)));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010089 /* Wait for clear */
10090 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010091 MDIO_PMA_DEVAD,
10092 MDIO_PMA_REG_7101_RESET, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010093
10094 if ((val & (1<<15)) == 0)
10095 break;
10096 }
10097}
10098
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010099static void bnx2x_7101_hw_reset(struct bnx2x_phy *phy,
10100 struct link_params *params) {
10101 /* Low power mode is controlled by GPIO 2 */
10102 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010103 MISC_REGISTERS_GPIO_OUTPUT_LOW, params->port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010104 /* The PHY reset is controlled by GPIO 1 */
10105 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010106 MISC_REGISTERS_GPIO_OUTPUT_LOW, params->port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010107}
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010108
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +000010109static void bnx2x_7101_set_link_led(struct bnx2x_phy *phy,
10110 struct link_params *params, u8 mode)
10111{
10112 u16 val = 0;
10113 struct bnx2x *bp = params->bp;
10114 switch (mode) {
10115 case LED_MODE_FRONT_PANEL_OFF:
10116 case LED_MODE_OFF:
10117 val = 2;
10118 break;
10119 case LED_MODE_ON:
10120 val = 1;
10121 break;
10122 case LED_MODE_OPER:
10123 val = 0;
10124 break;
10125 }
10126 bnx2x_cl45_write(bp, phy,
10127 MDIO_PMA_DEVAD,
10128 MDIO_PMA_REG_7107_LINK_LED_CNTL,
10129 val);
10130}
10131
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010132/******************************************************************/
10133/* STATIC PHY DECLARATION */
10134/******************************************************************/
10135
10136static struct bnx2x_phy phy_null = {
10137 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN,
10138 .addr = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010139 .def_md_devad = 0,
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000010140 .flags = FLAGS_INIT_XGXS_FIRST,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010141 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10142 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10143 .mdio_ctrl = 0,
10144 .supported = 0,
10145 .media_type = ETH_PHY_NOT_PRESENT,
10146 .ver_addr = 0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010147 .req_flow_ctrl = 0,
10148 .req_line_speed = 0,
10149 .speed_cap_mask = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010150 .req_duplex = 0,
10151 .rsrv = 0,
10152 .config_init = (config_init_t)NULL,
10153 .read_status = (read_status_t)NULL,
10154 .link_reset = (link_reset_t)NULL,
10155 .config_loopback = (config_loopback_t)NULL,
10156 .format_fw_ver = (format_fw_ver_t)NULL,
10157 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010158 .set_link_led = (set_link_led_t)NULL,
10159 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010160};
10161
10162static struct bnx2x_phy phy_serdes = {
10163 .type = PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT,
10164 .addr = 0xff,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010165 .def_md_devad = 0,
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000010166 .flags = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010167 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10168 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10169 .mdio_ctrl = 0,
10170 .supported = (SUPPORTED_10baseT_Half |
10171 SUPPORTED_10baseT_Full |
10172 SUPPORTED_100baseT_Half |
10173 SUPPORTED_100baseT_Full |
10174 SUPPORTED_1000baseT_Full |
10175 SUPPORTED_2500baseX_Full |
10176 SUPPORTED_TP |
10177 SUPPORTED_Autoneg |
10178 SUPPORTED_Pause |
10179 SUPPORTED_Asym_Pause),
Yaniv Rosner1ac9e422011-05-31 21:26:11 +000010180 .media_type = ETH_PHY_BASE_T,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010181 .ver_addr = 0,
10182 .req_flow_ctrl = 0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010183 .req_line_speed = 0,
10184 .speed_cap_mask = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010185 .req_duplex = 0,
10186 .rsrv = 0,
Yaniv Rosnerec146a62011-05-31 21:29:27 +000010187 .config_init = (config_init_t)bnx2x_xgxs_config_init,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010188 .read_status = (read_status_t)bnx2x_link_settings_status,
10189 .link_reset = (link_reset_t)bnx2x_int_link_reset,
10190 .config_loopback = (config_loopback_t)NULL,
10191 .format_fw_ver = (format_fw_ver_t)NULL,
10192 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010193 .set_link_led = (set_link_led_t)NULL,
10194 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010195};
10196
10197static struct bnx2x_phy phy_xgxs = {
10198 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT,
10199 .addr = 0xff,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010200 .def_md_devad = 0,
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000010201 .flags = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010202 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10203 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10204 .mdio_ctrl = 0,
10205 .supported = (SUPPORTED_10baseT_Half |
10206 SUPPORTED_10baseT_Full |
10207 SUPPORTED_100baseT_Half |
10208 SUPPORTED_100baseT_Full |
10209 SUPPORTED_1000baseT_Full |
10210 SUPPORTED_2500baseX_Full |
10211 SUPPORTED_10000baseT_Full |
10212 SUPPORTED_FIBRE |
10213 SUPPORTED_Autoneg |
10214 SUPPORTED_Pause |
10215 SUPPORTED_Asym_Pause),
Yaniv Rosner1ac9e422011-05-31 21:26:11 +000010216 .media_type = ETH_PHY_CX4,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010217 .ver_addr = 0,
10218 .req_flow_ctrl = 0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010219 .req_line_speed = 0,
10220 .speed_cap_mask = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010221 .req_duplex = 0,
10222 .rsrv = 0,
Yaniv Rosnerec146a62011-05-31 21:29:27 +000010223 .config_init = (config_init_t)bnx2x_xgxs_config_init,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010224 .read_status = (read_status_t)bnx2x_link_settings_status,
10225 .link_reset = (link_reset_t)bnx2x_int_link_reset,
10226 .config_loopback = (config_loopback_t)bnx2x_set_xgxs_loopback,
10227 .format_fw_ver = (format_fw_ver_t)NULL,
10228 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010229 .set_link_led = (set_link_led_t)NULL,
10230 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010231};
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000010232static struct bnx2x_phy phy_warpcore = {
10233 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT,
10234 .addr = 0xff,
10235 .def_md_devad = 0,
10236 .flags = FLAGS_HW_LOCK_REQUIRED,
10237 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10238 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10239 .mdio_ctrl = 0,
10240 .supported = (SUPPORTED_10baseT_Half |
10241 SUPPORTED_10baseT_Full |
10242 SUPPORTED_100baseT_Half |
10243 SUPPORTED_100baseT_Full |
10244 SUPPORTED_1000baseT_Full |
10245 SUPPORTED_10000baseT_Full |
10246 SUPPORTED_20000baseKR2_Full |
10247 SUPPORTED_20000baseMLD2_Full |
10248 SUPPORTED_FIBRE |
10249 SUPPORTED_Autoneg |
10250 SUPPORTED_Pause |
10251 SUPPORTED_Asym_Pause),
10252 .media_type = ETH_PHY_UNSPECIFIED,
10253 .ver_addr = 0,
10254 .req_flow_ctrl = 0,
10255 .req_line_speed = 0,
10256 .speed_cap_mask = 0,
10257 /* req_duplex = */0,
10258 /* rsrv = */0,
10259 .config_init = (config_init_t)bnx2x_warpcore_config_init,
10260 .read_status = (read_status_t)bnx2x_warpcore_read_status,
10261 .link_reset = (link_reset_t)bnx2x_warpcore_link_reset,
10262 .config_loopback = (config_loopback_t)bnx2x_set_warpcore_loopback,
10263 .format_fw_ver = (format_fw_ver_t)NULL,
10264 .hw_reset = (hw_reset_t)NULL,
10265 .set_link_led = (set_link_led_t)NULL,
10266 .phy_specific_func = (phy_specific_func_t)NULL
10267};
10268
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010269
10270static struct bnx2x_phy phy_7101 = {
10271 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
10272 .addr = 0xff,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010273 .def_md_devad = 0,
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000010274 .flags = FLAGS_FAN_FAILURE_DET_REQ,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010275 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10276 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10277 .mdio_ctrl = 0,
10278 .supported = (SUPPORTED_10000baseT_Full |
10279 SUPPORTED_TP |
10280 SUPPORTED_Autoneg |
10281 SUPPORTED_Pause |
10282 SUPPORTED_Asym_Pause),
10283 .media_type = ETH_PHY_BASE_T,
10284 .ver_addr = 0,
10285 .req_flow_ctrl = 0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010286 .req_line_speed = 0,
10287 .speed_cap_mask = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010288 .req_duplex = 0,
10289 .rsrv = 0,
10290 .config_init = (config_init_t)bnx2x_7101_config_init,
10291 .read_status = (read_status_t)bnx2x_7101_read_status,
10292 .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
10293 .config_loopback = (config_loopback_t)bnx2x_7101_config_loopback,
10294 .format_fw_ver = (format_fw_ver_t)bnx2x_7101_format_ver,
10295 .hw_reset = (hw_reset_t)bnx2x_7101_hw_reset,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +000010296 .set_link_led = (set_link_led_t)bnx2x_7101_set_link_led,
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010297 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010298};
10299static struct bnx2x_phy phy_8073 = {
10300 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
10301 .addr = 0xff,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010302 .def_md_devad = 0,
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000010303 .flags = FLAGS_HW_LOCK_REQUIRED,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010304 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10305 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10306 .mdio_ctrl = 0,
10307 .supported = (SUPPORTED_10000baseT_Full |
10308 SUPPORTED_2500baseX_Full |
10309 SUPPORTED_1000baseT_Full |
10310 SUPPORTED_FIBRE |
10311 SUPPORTED_Autoneg |
10312 SUPPORTED_Pause |
10313 SUPPORTED_Asym_Pause),
Yaniv Rosner1ac9e422011-05-31 21:26:11 +000010314 .media_type = ETH_PHY_KR,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010315 .ver_addr = 0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010316 .req_flow_ctrl = 0,
10317 .req_line_speed = 0,
10318 .speed_cap_mask = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010319 .req_duplex = 0,
10320 .rsrv = 0,
Yaniv Rosner62b29a52010-09-07 11:40:58 +000010321 .config_init = (config_init_t)bnx2x_8073_config_init,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010322 .read_status = (read_status_t)bnx2x_8073_read_status,
10323 .link_reset = (link_reset_t)bnx2x_8073_link_reset,
10324 .config_loopback = (config_loopback_t)NULL,
10325 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
10326 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010327 .set_link_led = (set_link_led_t)NULL,
10328 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010329};
10330static struct bnx2x_phy phy_8705 = {
10331 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705,
10332 .addr = 0xff,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010333 .def_md_devad = 0,
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000010334 .flags = FLAGS_INIT_XGXS_FIRST,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010335 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10336 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10337 .mdio_ctrl = 0,
10338 .supported = (SUPPORTED_10000baseT_Full |
10339 SUPPORTED_FIBRE |
10340 SUPPORTED_Pause |
10341 SUPPORTED_Asym_Pause),
10342 .media_type = ETH_PHY_XFP_FIBER,
10343 .ver_addr = 0,
10344 .req_flow_ctrl = 0,
10345 .req_line_speed = 0,
10346 .speed_cap_mask = 0,
10347 .req_duplex = 0,
10348 .rsrv = 0,
10349 .config_init = (config_init_t)bnx2x_8705_config_init,
10350 .read_status = (read_status_t)bnx2x_8705_read_status,
10351 .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
10352 .config_loopback = (config_loopback_t)NULL,
10353 .format_fw_ver = (format_fw_ver_t)bnx2x_null_format_ver,
10354 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010355 .set_link_led = (set_link_led_t)NULL,
10356 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010357};
10358static struct bnx2x_phy phy_8706 = {
10359 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706,
10360 .addr = 0xff,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010361 .def_md_devad = 0,
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000010362 .flags = FLAGS_INIT_XGXS_FIRST,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010363 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10364 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10365 .mdio_ctrl = 0,
10366 .supported = (SUPPORTED_10000baseT_Full |
10367 SUPPORTED_1000baseT_Full |
10368 SUPPORTED_FIBRE |
10369 SUPPORTED_Pause |
10370 SUPPORTED_Asym_Pause),
10371 .media_type = ETH_PHY_SFP_FIBER,
10372 .ver_addr = 0,
10373 .req_flow_ctrl = 0,
10374 .req_line_speed = 0,
10375 .speed_cap_mask = 0,
10376 .req_duplex = 0,
10377 .rsrv = 0,
10378 .config_init = (config_init_t)bnx2x_8706_config_init,
10379 .read_status = (read_status_t)bnx2x_8706_read_status,
10380 .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
10381 .config_loopback = (config_loopback_t)NULL,
10382 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
10383 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010384 .set_link_led = (set_link_led_t)NULL,
10385 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010386};
10387
10388static struct bnx2x_phy phy_8726 = {
10389 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
10390 .addr = 0xff,
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000010391 .def_md_devad = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010392 .flags = (FLAGS_HW_LOCK_REQUIRED |
10393 FLAGS_INIT_XGXS_FIRST),
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010394 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10395 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10396 .mdio_ctrl = 0,
10397 .supported = (SUPPORTED_10000baseT_Full |
10398 SUPPORTED_1000baseT_Full |
10399 SUPPORTED_Autoneg |
10400 SUPPORTED_FIBRE |
10401 SUPPORTED_Pause |
10402 SUPPORTED_Asym_Pause),
Yaniv Rosner1ac9e422011-05-31 21:26:11 +000010403 .media_type = ETH_PHY_NOT_PRESENT,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010404 .ver_addr = 0,
10405 .req_flow_ctrl = 0,
10406 .req_line_speed = 0,
10407 .speed_cap_mask = 0,
10408 .req_duplex = 0,
10409 .rsrv = 0,
10410 .config_init = (config_init_t)bnx2x_8726_config_init,
10411 .read_status = (read_status_t)bnx2x_8726_read_status,
10412 .link_reset = (link_reset_t)bnx2x_8726_link_reset,
10413 .config_loopback = (config_loopback_t)bnx2x_8726_config_loopback,
10414 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
10415 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010416 .set_link_led = (set_link_led_t)NULL,
10417 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010418};
10419
10420static struct bnx2x_phy phy_8727 = {
10421 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
10422 .addr = 0xff,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010423 .def_md_devad = 0,
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000010424 .flags = FLAGS_FAN_FAILURE_DET_REQ,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010425 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10426 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10427 .mdio_ctrl = 0,
10428 .supported = (SUPPORTED_10000baseT_Full |
10429 SUPPORTED_1000baseT_Full |
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010430 SUPPORTED_FIBRE |
10431 SUPPORTED_Pause |
10432 SUPPORTED_Asym_Pause),
Yaniv Rosner1ac9e422011-05-31 21:26:11 +000010433 .media_type = ETH_PHY_NOT_PRESENT,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010434 .ver_addr = 0,
10435 .req_flow_ctrl = 0,
10436 .req_line_speed = 0,
10437 .speed_cap_mask = 0,
10438 .req_duplex = 0,
10439 .rsrv = 0,
10440 .config_init = (config_init_t)bnx2x_8727_config_init,
10441 .read_status = (read_status_t)bnx2x_8727_read_status,
10442 .link_reset = (link_reset_t)bnx2x_8727_link_reset,
10443 .config_loopback = (config_loopback_t)NULL,
10444 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
10445 .hw_reset = (hw_reset_t)bnx2x_8727_hw_reset,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +000010446 .set_link_led = (set_link_led_t)bnx2x_8727_set_link_led,
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010447 .phy_specific_func = (phy_specific_func_t)bnx2x_8727_specific_func
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010448};
10449static struct bnx2x_phy phy_8481 = {
10450 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
10451 .addr = 0xff,
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000010452 .def_md_devad = 0,
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010453 .flags = FLAGS_FAN_FAILURE_DET_REQ |
10454 FLAGS_REARM_LATCH_SIGNAL,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010455 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10456 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10457 .mdio_ctrl = 0,
10458 .supported = (SUPPORTED_10baseT_Half |
10459 SUPPORTED_10baseT_Full |
10460 SUPPORTED_100baseT_Half |
10461 SUPPORTED_100baseT_Full |
10462 SUPPORTED_1000baseT_Full |
10463 SUPPORTED_10000baseT_Full |
10464 SUPPORTED_TP |
10465 SUPPORTED_Autoneg |
10466 SUPPORTED_Pause |
10467 SUPPORTED_Asym_Pause),
10468 .media_type = ETH_PHY_BASE_T,
10469 .ver_addr = 0,
10470 .req_flow_ctrl = 0,
10471 .req_line_speed = 0,
10472 .speed_cap_mask = 0,
10473 .req_duplex = 0,
10474 .rsrv = 0,
10475 .config_init = (config_init_t)bnx2x_8481_config_init,
10476 .read_status = (read_status_t)bnx2x_848xx_read_status,
10477 .link_reset = (link_reset_t)bnx2x_8481_link_reset,
10478 .config_loopback = (config_loopback_t)NULL,
10479 .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver,
10480 .hw_reset = (hw_reset_t)bnx2x_8481_hw_reset,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +000010481 .set_link_led = (set_link_led_t)bnx2x_848xx_set_link_led,
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010482 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010483};
10484
10485static struct bnx2x_phy phy_84823 = {
10486 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823,
10487 .addr = 0xff,
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000010488 .def_md_devad = 0,
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010489 .flags = FLAGS_FAN_FAILURE_DET_REQ |
10490 FLAGS_REARM_LATCH_SIGNAL,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010491 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10492 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10493 .mdio_ctrl = 0,
10494 .supported = (SUPPORTED_10baseT_Half |
10495 SUPPORTED_10baseT_Full |
10496 SUPPORTED_100baseT_Half |
10497 SUPPORTED_100baseT_Full |
10498 SUPPORTED_1000baseT_Full |
10499 SUPPORTED_10000baseT_Full |
10500 SUPPORTED_TP |
10501 SUPPORTED_Autoneg |
10502 SUPPORTED_Pause |
10503 SUPPORTED_Asym_Pause),
10504 .media_type = ETH_PHY_BASE_T,
10505 .ver_addr = 0,
10506 .req_flow_ctrl = 0,
10507 .req_line_speed = 0,
10508 .speed_cap_mask = 0,
10509 .req_duplex = 0,
10510 .rsrv = 0,
10511 .config_init = (config_init_t)bnx2x_848x3_config_init,
10512 .read_status = (read_status_t)bnx2x_848xx_read_status,
10513 .link_reset = (link_reset_t)bnx2x_848x3_link_reset,
10514 .config_loopback = (config_loopback_t)NULL,
10515 .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver,
10516 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +000010517 .set_link_led = (set_link_led_t)bnx2x_848xx_set_link_led,
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010518 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010519};
10520
Yaniv Rosnerc87bca12011-01-31 04:22:41 +000010521static struct bnx2x_phy phy_84833 = {
10522 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833,
10523 .addr = 0xff,
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000010524 .def_md_devad = 0,
Yaniv Rosnerc87bca12011-01-31 04:22:41 +000010525 .flags = FLAGS_FAN_FAILURE_DET_REQ |
10526 FLAGS_REARM_LATCH_SIGNAL,
Yaniv Rosnerc87bca12011-01-31 04:22:41 +000010527 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10528 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10529 .mdio_ctrl = 0,
10530 .supported = (SUPPORTED_10baseT_Half |
10531 SUPPORTED_10baseT_Full |
10532 SUPPORTED_100baseT_Half |
10533 SUPPORTED_100baseT_Full |
10534 SUPPORTED_1000baseT_Full |
10535 SUPPORTED_10000baseT_Full |
10536 SUPPORTED_TP |
10537 SUPPORTED_Autoneg |
10538 SUPPORTED_Pause |
10539 SUPPORTED_Asym_Pause),
10540 .media_type = ETH_PHY_BASE_T,
10541 .ver_addr = 0,
10542 .req_flow_ctrl = 0,
10543 .req_line_speed = 0,
10544 .speed_cap_mask = 0,
10545 .req_duplex = 0,
10546 .rsrv = 0,
10547 .config_init = (config_init_t)bnx2x_848x3_config_init,
10548 .read_status = (read_status_t)bnx2x_848xx_read_status,
10549 .link_reset = (link_reset_t)bnx2x_848x3_link_reset,
10550 .config_loopback = (config_loopback_t)NULL,
10551 .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver,
10552 .hw_reset = (hw_reset_t)NULL,
10553 .set_link_led = (set_link_led_t)bnx2x_848xx_set_link_led,
10554 .phy_specific_func = (phy_specific_func_t)NULL
10555};
10556
Yaniv Rosner6583e332011-06-14 01:34:17 +000010557static struct bnx2x_phy phy_54616s = {
10558 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54616,
10559 .addr = 0xff,
10560 .def_md_devad = 0,
10561 .flags = FLAGS_INIT_XGXS_FIRST,
10562 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10563 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10564 .mdio_ctrl = 0,
10565 .supported = (SUPPORTED_10baseT_Half |
10566 SUPPORTED_10baseT_Full |
10567 SUPPORTED_100baseT_Half |
10568 SUPPORTED_100baseT_Full |
10569 SUPPORTED_1000baseT_Full |
10570 SUPPORTED_TP |
10571 SUPPORTED_Autoneg |
10572 SUPPORTED_Pause |
10573 SUPPORTED_Asym_Pause),
10574 .media_type = ETH_PHY_BASE_T,
10575 .ver_addr = 0,
10576 .req_flow_ctrl = 0,
10577 .req_line_speed = 0,
10578 .speed_cap_mask = 0,
10579 /* req_duplex = */0,
10580 /* rsrv = */0,
10581 .config_init = (config_init_t)bnx2x_54616s_config_init,
10582 .read_status = (read_status_t)bnx2x_54616s_read_status,
10583 .link_reset = (link_reset_t)bnx2x_54616s_link_reset,
10584 .config_loopback = (config_loopback_t)bnx2x_54616s_config_loopback,
10585 .format_fw_ver = (format_fw_ver_t)NULL,
10586 .hw_reset = (hw_reset_t)NULL,
10587 .set_link_led = (set_link_led_t)bnx2x_54616s_set_link_led,
10588 .phy_specific_func = (phy_specific_func_t)NULL
10589};
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010590/*****************************************************************/
10591/* */
10592/* Populate the phy according. Main function: bnx2x_populate_phy */
10593/* */
10594/*****************************************************************/
10595
10596static void bnx2x_populate_preemphasis(struct bnx2x *bp, u32 shmem_base,
10597 struct bnx2x_phy *phy, u8 port,
10598 u8 phy_index)
10599{
10600 /* Get the 4 lanes xgxs config rx and tx */
10601 u32 rx = 0, tx = 0, i;
10602 for (i = 0; i < 2; i++) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +000010603 /*
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010604 * INT_PHY and EXT_PHY1 share the same value location in the
10605 * shmem. When num_phys is greater than 1, than this value
10606 * applies only to EXT_PHY1
10607 */
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010608 if (phy_index == INT_PHY || phy_index == EXT_PHY1) {
10609 rx = REG_RD(bp, shmem_base +
10610 offsetof(struct shmem_region,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010611 dev_info.port_hw_config[port].xgxs_config_rx[i<<1]));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010612
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010613 tx = REG_RD(bp, shmem_base +
10614 offsetof(struct shmem_region,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010615 dev_info.port_hw_config[port].xgxs_config_tx[i<<1]));
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010616 } else {
10617 rx = REG_RD(bp, shmem_base +
10618 offsetof(struct shmem_region,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010619 dev_info.port_hw_config[port].xgxs_config2_rx[i<<1]));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010620
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010621 tx = REG_RD(bp, shmem_base +
10622 offsetof(struct shmem_region,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010623 dev_info.port_hw_config[port].xgxs_config2_rx[i<<1]));
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010624 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010625
10626 phy->rx_preemphasis[i << 1] = ((rx>>16) & 0xffff);
10627 phy->rx_preemphasis[(i << 1) + 1] = (rx & 0xffff);
10628
10629 phy->tx_preemphasis[i << 1] = ((tx>>16) & 0xffff);
10630 phy->tx_preemphasis[(i << 1) + 1] = (tx & 0xffff);
10631 }
10632}
10633
Yaniv Rosnere10bc842010-09-07 11:40:50 +000010634static u32 bnx2x_get_ext_phy_config(struct bnx2x *bp, u32 shmem_base,
10635 u8 phy_index, u8 port)
10636{
10637 u32 ext_phy_config = 0;
10638 switch (phy_index) {
10639 case EXT_PHY1:
10640 ext_phy_config = REG_RD(bp, shmem_base +
10641 offsetof(struct shmem_region,
10642 dev_info.port_hw_config[port].external_phy_config));
10643 break;
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010644 case EXT_PHY2:
10645 ext_phy_config = REG_RD(bp, shmem_base +
10646 offsetof(struct shmem_region,
10647 dev_info.port_hw_config[port].external_phy_config2));
10648 break;
Yaniv Rosnere10bc842010-09-07 11:40:50 +000010649 default:
10650 DP(NETIF_MSG_LINK, "Invalid phy_index %d\n", phy_index);
10651 return -EINVAL;
10652 }
10653
10654 return ext_phy_config;
10655}
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +000010656static int bnx2x_populate_int_phy(struct bnx2x *bp, u32 shmem_base, u8 port,
10657 struct bnx2x_phy *phy)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010658{
10659 u32 phy_addr;
10660 u32 chip_id;
10661 u32 switch_cfg = (REG_RD(bp, shmem_base +
10662 offsetof(struct shmem_region,
10663 dev_info.port_feature_config[port].link_config)) &
10664 PORT_FEATURE_CONNECTED_SWITCH_MASK);
10665 chip_id = REG_RD(bp, MISC_REG_CHIP_NUM) << 16;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000010666 DP(NETIF_MSG_LINK, ":chip_id = 0x%x\n", chip_id);
10667 if (USES_WARPCORE(bp)) {
10668 u32 serdes_net_if;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010669 phy_addr = REG_RD(bp,
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000010670 MISC_REG_WC0_CTRL_PHY_ADDR);
10671 *phy = phy_warpcore;
10672 if (REG_RD(bp, MISC_REG_PORT4MODE_EN_OVWR) == 0x3)
10673 phy->flags |= FLAGS_4_PORT_MODE;
10674 else
10675 phy->flags &= ~FLAGS_4_PORT_MODE;
10676 /* Check Dual mode */
10677 serdes_net_if = (REG_RD(bp, shmem_base +
10678 offsetof(struct shmem_region, dev_info.
10679 port_hw_config[port].default_cfg)) &
10680 PORT_HW_CFG_NET_SERDES_IF_MASK);
10681 /*
10682 * Set the appropriate supported and flags indications per
10683 * interface type of the chip
10684 */
10685 switch (serdes_net_if) {
10686 case PORT_HW_CFG_NET_SERDES_IF_SGMII:
10687 phy->supported &= (SUPPORTED_10baseT_Half |
10688 SUPPORTED_10baseT_Full |
10689 SUPPORTED_100baseT_Half |
10690 SUPPORTED_100baseT_Full |
10691 SUPPORTED_1000baseT_Full |
10692 SUPPORTED_FIBRE |
10693 SUPPORTED_Autoneg |
10694 SUPPORTED_Pause |
10695 SUPPORTED_Asym_Pause);
10696 phy->media_type = ETH_PHY_BASE_T;
10697 break;
10698 case PORT_HW_CFG_NET_SERDES_IF_XFI:
10699 phy->media_type = ETH_PHY_XFP_FIBER;
10700 break;
10701 case PORT_HW_CFG_NET_SERDES_IF_SFI:
10702 phy->supported &= (SUPPORTED_1000baseT_Full |
10703 SUPPORTED_10000baseT_Full |
10704 SUPPORTED_FIBRE |
10705 SUPPORTED_Pause |
10706 SUPPORTED_Asym_Pause);
10707 phy->media_type = ETH_PHY_SFP_FIBER;
10708 break;
10709 case PORT_HW_CFG_NET_SERDES_IF_KR:
10710 phy->media_type = ETH_PHY_KR;
10711 phy->supported &= (SUPPORTED_1000baseT_Full |
10712 SUPPORTED_10000baseT_Full |
10713 SUPPORTED_FIBRE |
10714 SUPPORTED_Autoneg |
10715 SUPPORTED_Pause |
10716 SUPPORTED_Asym_Pause);
10717 break;
10718 case PORT_HW_CFG_NET_SERDES_IF_DXGXS:
10719 phy->media_type = ETH_PHY_KR;
10720 phy->flags |= FLAGS_WC_DUAL_MODE;
10721 phy->supported &= (SUPPORTED_20000baseMLD2_Full |
10722 SUPPORTED_FIBRE |
10723 SUPPORTED_Pause |
10724 SUPPORTED_Asym_Pause);
10725 break;
10726 case PORT_HW_CFG_NET_SERDES_IF_KR2:
10727 phy->media_type = ETH_PHY_KR;
10728 phy->flags |= FLAGS_WC_DUAL_MODE;
10729 phy->supported &= (SUPPORTED_20000baseKR2_Full |
10730 SUPPORTED_FIBRE |
10731 SUPPORTED_Pause |
10732 SUPPORTED_Asym_Pause);
10733 break;
10734 default:
10735 DP(NETIF_MSG_LINK, "Unknown WC interface type 0x%x\n",
10736 serdes_net_if);
10737 break;
10738 }
10739
10740 /*
10741 * Enable MDC/MDIO work-around for E3 A0 since free running MDC
10742 * was not set as expected. For B0, ECO will be enabled so there
10743 * won't be an issue there
10744 */
10745 if (CHIP_REV(bp) == CHIP_REV_Ax)
10746 phy->flags |= FLAGS_MDC_MDIO_WA;
10747 } else {
10748 switch (switch_cfg) {
10749 case SWITCH_CFG_1G:
10750 phy_addr = REG_RD(bp,
10751 NIG_REG_SERDES0_CTRL_PHY_ADDR +
10752 port * 0x10);
10753 *phy = phy_serdes;
10754 break;
10755 case SWITCH_CFG_10G:
10756 phy_addr = REG_RD(bp,
10757 NIG_REG_XGXS0_CTRL_PHY_ADDR +
10758 port * 0x18);
10759 *phy = phy_xgxs;
10760 break;
10761 default:
10762 DP(NETIF_MSG_LINK, "Invalid switch_cfg\n");
10763 return -EINVAL;
10764 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010765 }
10766 phy->addr = (u8)phy_addr;
10767 phy->mdio_ctrl = bnx2x_get_emac_base(bp,
Yaniv Rosnerc18aa152010-09-07 11:41:07 +000010768 SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010769 port);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000010770 if (CHIP_IS_E2(bp))
10771 phy->def_md_devad = E2_DEFAULT_PHY_DEV_ADDR;
10772 else
10773 phy->def_md_devad = DEFAULT_PHY_DEV_ADDR;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010774
10775 DP(NETIF_MSG_LINK, "Internal phy port=%d, addr=0x%x, mdio_ctl=0x%x\n",
10776 port, phy->addr, phy->mdio_ctrl);
10777
10778 bnx2x_populate_preemphasis(bp, shmem_base, phy, port, INT_PHY);
10779 return 0;
10780}
Yaniv Rosnere10bc842010-09-07 11:40:50 +000010781
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +000010782static int bnx2x_populate_ext_phy(struct bnx2x *bp,
10783 u8 phy_index,
10784 u32 shmem_base,
10785 u32 shmem2_base,
10786 u8 port,
10787 struct bnx2x_phy *phy)
Yaniv Rosnere10bc842010-09-07 11:40:50 +000010788{
Yaniv Rosnerc18aa152010-09-07 11:41:07 +000010789 u32 ext_phy_config, phy_type, config2;
10790 u32 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH;
Yaniv Rosnere10bc842010-09-07 11:40:50 +000010791 ext_phy_config = bnx2x_get_ext_phy_config(bp, shmem_base,
10792 phy_index, port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010793 phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
10794 /* Select the phy type */
10795 switch (phy_type) {
10796 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Yaniv Rosnerc18aa152010-09-07 11:41:07 +000010797 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_SWAPPED;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010798 *phy = phy_8073;
10799 break;
10800 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
10801 *phy = phy_8705;
10802 break;
10803 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
10804 *phy = phy_8706;
10805 break;
10806 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
Yaniv Rosnerc18aa152010-09-07 11:41:07 +000010807 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010808 *phy = phy_8726;
10809 break;
10810 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
10811 /* BCM8727_NOC => BCM8727 no over current */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +000010812 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010813 *phy = phy_8727;
10814 phy->flags |= FLAGS_NOC;
10815 break;
Yaniv Rosnere4d78f12011-05-31 21:25:55 +000010816 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722:
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010817 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
Yaniv Rosnerc18aa152010-09-07 11:41:07 +000010818 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010819 *phy = phy_8727;
10820 break;
10821 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
10822 *phy = phy_8481;
10823 break;
10824 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
10825 *phy = phy_84823;
10826 break;
Yaniv Rosnerc87bca12011-01-31 04:22:41 +000010827 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833:
10828 *phy = phy_84833;
10829 break;
Yaniv Rosner6583e332011-06-14 01:34:17 +000010830 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54616:
10831 *phy = phy_54616s;
10832 break;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010833 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
10834 *phy = phy_7101;
10835 break;
10836 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
10837 *phy = phy_null;
10838 return -EINVAL;
10839 default:
10840 *phy = phy_null;
10841 return 0;
10842 }
10843
Yaniv Rosnere10bc842010-09-07 11:40:50 +000010844 phy->addr = XGXS_EXT_PHY_ADDR(ext_phy_config);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010845 bnx2x_populate_preemphasis(bp, shmem_base, phy, port, phy_index);
Yaniv Rosner62b29a52010-09-07 11:40:58 +000010846
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +000010847 /*
10848 * The shmem address of the phy version is located on different
10849 * structures. In case this structure is too old, do not set
10850 * the address
10851 */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +000010852 config2 = REG_RD(bp, shmem_base + offsetof(struct shmem_region,
10853 dev_info.shared_hw_config.config2));
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010854 if (phy_index == EXT_PHY1) {
10855 phy->ver_addr = shmem_base + offsetof(struct shmem_region,
10856 port_mb[port].ext_phy_fw_version);
Yaniv Rosnerc18aa152010-09-07 11:41:07 +000010857
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010858 /* Check specific mdc mdio settings */
10859 if (config2 & SHARED_HW_CFG_MDC_MDIO_ACCESS1_MASK)
10860 mdc_mdio_access = config2 &
10861 SHARED_HW_CFG_MDC_MDIO_ACCESS1_MASK;
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010862 } else {
10863 u32 size = REG_RD(bp, shmem2_base);
Yaniv Rosnerc18aa152010-09-07 11:41:07 +000010864
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010865 if (size >
10866 offsetof(struct shmem2_region, ext_phy_fw_version2)) {
10867 phy->ver_addr = shmem2_base +
10868 offsetof(struct shmem2_region,
10869 ext_phy_fw_version2[port]);
10870 }
10871 /* Check specific mdc mdio settings */
10872 if (config2 & SHARED_HW_CFG_MDC_MDIO_ACCESS2_MASK)
10873 mdc_mdio_access = (config2 &
10874 SHARED_HW_CFG_MDC_MDIO_ACCESS2_MASK) >>
10875 (SHARED_HW_CFG_MDC_MDIO_ACCESS2_SHIFT -
10876 SHARED_HW_CFG_MDC_MDIO_ACCESS1_SHIFT);
10877 }
Yaniv Rosnerc18aa152010-09-07 11:41:07 +000010878 phy->mdio_ctrl = bnx2x_get_emac_base(bp, mdc_mdio_access, port);
10879
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +000010880 /*
Yaniv Rosnerc18aa152010-09-07 11:41:07 +000010881 * In case mdc/mdio_access of the external phy is different than the
10882 * mdc/mdio access of the XGXS, a HW lock must be taken in each access
10883 * to prevent one port interfere with another port's CL45 operations.
10884 */
10885 if (mdc_mdio_access != SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH)
10886 phy->flags |= FLAGS_HW_LOCK_REQUIRED;
10887 DP(NETIF_MSG_LINK, "phy_type 0x%x port %d found in index %d\n",
10888 phy_type, port, phy_index);
10889 DP(NETIF_MSG_LINK, " addr=0x%x, mdio_ctl=0x%x\n",
10890 phy->addr, phy->mdio_ctrl);
Yaniv Rosnere10bc842010-09-07 11:40:50 +000010891 return 0;
10892}
10893
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +000010894static int bnx2x_populate_phy(struct bnx2x *bp, u8 phy_index, u32 shmem_base,
10895 u32 shmem2_base, u8 port, struct bnx2x_phy *phy)
Yaniv Rosnere10bc842010-09-07 11:40:50 +000010896{
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +000010897 int status = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010898 phy->type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN;
10899 if (phy_index == INT_PHY)
10900 return bnx2x_populate_int_phy(bp, shmem_base, port, phy);
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010901 status = bnx2x_populate_ext_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnere10bc842010-09-07 11:40:50 +000010902 port, phy);
10903 return status;
10904}
10905
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010906static void bnx2x_phy_def_cfg(struct link_params *params,
10907 struct bnx2x_phy *phy,
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010908 u8 phy_index)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010909{
10910 struct bnx2x *bp = params->bp;
10911 u32 link_config;
10912 /* Populate the default phy configuration for MF mode */
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010913 if (phy_index == EXT_PHY2) {
10914 link_config = REG_RD(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010915 offsetof(struct shmem_region, dev_info.
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010916 port_feature_config[params->port].link_config2));
10917 phy->speed_cap_mask = REG_RD(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010918 offsetof(struct shmem_region,
10919 dev_info.
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010920 port_hw_config[params->port].speed_capability_mask2));
10921 } else {
10922 link_config = REG_RD(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010923 offsetof(struct shmem_region, dev_info.
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010924 port_feature_config[params->port].link_config));
10925 phy->speed_cap_mask = REG_RD(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010926 offsetof(struct shmem_region,
10927 dev_info.
10928 port_hw_config[params->port].speed_capability_mask));
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010929 }
10930 DP(NETIF_MSG_LINK, "Default config phy idx %x cfg 0x%x speed_cap_mask"
10931 " 0x%x\n", phy_index, link_config, phy->speed_cap_mask);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010932
10933 phy->req_duplex = DUPLEX_FULL;
10934 switch (link_config & PORT_FEATURE_LINK_SPEED_MASK) {
10935 case PORT_FEATURE_LINK_SPEED_10M_HALF:
10936 phy->req_duplex = DUPLEX_HALF;
10937 case PORT_FEATURE_LINK_SPEED_10M_FULL:
10938 phy->req_line_speed = SPEED_10;
10939 break;
10940 case PORT_FEATURE_LINK_SPEED_100M_HALF:
10941 phy->req_duplex = DUPLEX_HALF;
10942 case PORT_FEATURE_LINK_SPEED_100M_FULL:
10943 phy->req_line_speed = SPEED_100;
10944 break;
10945 case PORT_FEATURE_LINK_SPEED_1G:
10946 phy->req_line_speed = SPEED_1000;
10947 break;
10948 case PORT_FEATURE_LINK_SPEED_2_5G:
10949 phy->req_line_speed = SPEED_2500;
10950 break;
10951 case PORT_FEATURE_LINK_SPEED_10G_CX4:
10952 phy->req_line_speed = SPEED_10000;
10953 break;
10954 default:
10955 phy->req_line_speed = SPEED_AUTO_NEG;
10956 break;
10957 }
10958
10959 switch (link_config & PORT_FEATURE_FLOW_CONTROL_MASK) {
10960 case PORT_FEATURE_FLOW_CONTROL_AUTO:
10961 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_AUTO;
10962 break;
10963 case PORT_FEATURE_FLOW_CONTROL_TX:
10964 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_TX;
10965 break;
10966 case PORT_FEATURE_FLOW_CONTROL_RX:
10967 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_RX;
10968 break;
10969 case PORT_FEATURE_FLOW_CONTROL_BOTH:
10970 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_BOTH;
10971 break;
10972 default:
10973 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_NONE;
10974 break;
10975 }
10976}
10977
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010978u32 bnx2x_phy_selection(struct link_params *params)
10979{
10980 u32 phy_config_swapped, prio_cfg;
10981 u32 return_cfg = PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT;
10982
10983 phy_config_swapped = params->multi_phy_config &
10984 PORT_HW_CFG_PHY_SWAPPED_ENABLED;
10985
10986 prio_cfg = params->multi_phy_config &
10987 PORT_HW_CFG_PHY_SELECTION_MASK;
10988
10989 if (phy_config_swapped) {
10990 switch (prio_cfg) {
10991 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
10992 return_cfg = PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY;
10993 break;
10994 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
10995 return_cfg = PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY;
10996 break;
10997 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY:
10998 return_cfg = PORT_HW_CFG_PHY_SELECTION_FIRST_PHY;
10999 break;
11000 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY:
11001 return_cfg = PORT_HW_CFG_PHY_SELECTION_SECOND_PHY;
11002 break;
11003 }
11004 } else
11005 return_cfg = prio_cfg;
11006
11007 return return_cfg;
11008}
11009
11010
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +000011011int bnx2x_phy_probe(struct link_params *params)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011012{
11013 u8 phy_index, actual_phy_idx, link_cfg_idx;
Yaniv Rosner1ac9e422011-05-31 21:26:11 +000011014 u32 phy_config_swapped, sync_offset, media_types;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011015 struct bnx2x *bp = params->bp;
11016 struct bnx2x_phy *phy;
11017 params->num_phys = 0;
11018 DP(NETIF_MSG_LINK, "Begin phy probe\n");
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011019 phy_config_swapped = params->multi_phy_config &
11020 PORT_HW_CFG_PHY_SWAPPED_ENABLED;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011021
11022 for (phy_index = INT_PHY; phy_index < MAX_PHYS;
11023 phy_index++) {
11024 link_cfg_idx = LINK_CONFIG_IDX(phy_index);
11025 actual_phy_idx = phy_index;
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011026 if (phy_config_swapped) {
11027 if (phy_index == EXT_PHY1)
11028 actual_phy_idx = EXT_PHY2;
11029 else if (phy_index == EXT_PHY2)
11030 actual_phy_idx = EXT_PHY1;
11031 }
11032 DP(NETIF_MSG_LINK, "phy_config_swapped %x, phy_index %x,"
11033 " actual_phy_idx %x\n", phy_config_swapped,
11034 phy_index, actual_phy_idx);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011035 phy = &params->phy[actual_phy_idx];
11036 if (bnx2x_populate_phy(bp, phy_index, params->shmem_base,
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011037 params->shmem2_base, params->port,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011038 phy) != 0) {
11039 params->num_phys = 0;
11040 DP(NETIF_MSG_LINK, "phy probe failed in phy index %d\n",
11041 phy_index);
11042 for (phy_index = INT_PHY;
11043 phy_index < MAX_PHYS;
11044 phy_index++)
11045 *phy = phy_null;
11046 return -EINVAL;
11047 }
11048 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)
11049 break;
11050
Yaniv Rosner1ac9e422011-05-31 21:26:11 +000011051 sync_offset = params->shmem_base +
11052 offsetof(struct shmem_region,
11053 dev_info.port_hw_config[params->port].media_type);
11054 media_types = REG_RD(bp, sync_offset);
11055
11056 /*
11057 * Update media type for non-PMF sync only for the first time
11058 * In case the media type changes afterwards, it will be updated
11059 * using the update_status function
11060 */
11061 if ((media_types & (PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK <<
11062 (PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT *
11063 actual_phy_idx))) == 0) {
11064 media_types |= ((phy->media_type &
11065 PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK) <<
11066 (PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT *
11067 actual_phy_idx));
11068 }
11069 REG_WR(bp, sync_offset, media_types);
11070
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011071 bnx2x_phy_def_cfg(params, phy, phy_index);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011072 params->num_phys++;
11073 }
11074
11075 DP(NETIF_MSG_LINK, "End phy probe. #phys found %x\n", params->num_phys);
11076 return 0;
11077}
11078
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000011079void bnx2x_init_bmac_loopback(struct link_params *params,
11080 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011081{
11082 struct bnx2x *bp = params->bp;
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000011083 vars->link_up = 1;
11084 vars->line_speed = SPEED_10000;
11085 vars->duplex = DUPLEX_FULL;
11086 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
11087 vars->mac_type = MAC_TYPE_BMAC;
11088
11089 vars->phy_flags = PHY_XGXS_FLAG;
11090
11091 bnx2x_xgxs_deassert(params);
11092
11093 /* set bmac loopback */
11094 bnx2x_bmac_enable(params, vars, 1);
11095
11096 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
11097}
11098
11099void bnx2x_init_emac_loopback(struct link_params *params,
11100 struct link_vars *vars)
11101{
11102 struct bnx2x *bp = params->bp;
11103 vars->link_up = 1;
11104 vars->line_speed = SPEED_1000;
11105 vars->duplex = DUPLEX_FULL;
11106 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
11107 vars->mac_type = MAC_TYPE_EMAC;
11108
11109 vars->phy_flags = PHY_XGXS_FLAG;
11110
11111 bnx2x_xgxs_deassert(params);
11112 /* set bmac loopback */
11113 bnx2x_emac_enable(params, vars, 1);
11114 bnx2x_emac_program(params, vars);
11115 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
11116}
11117
Yaniv Rosner9380bb92011-06-14 01:34:07 +000011118void bnx2x_init_xmac_loopback(struct link_params *params,
11119 struct link_vars *vars)
11120{
11121 struct bnx2x *bp = params->bp;
11122 vars->link_up = 1;
11123 if (!params->req_line_speed[0])
11124 vars->line_speed = SPEED_10000;
11125 else
11126 vars->line_speed = params->req_line_speed[0];
11127 vars->duplex = DUPLEX_FULL;
11128 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
11129 vars->mac_type = MAC_TYPE_XMAC;
11130 vars->phy_flags = PHY_XGXS_FLAG;
11131 /*
11132 * Set WC to loopback mode since link is required to provide clock
11133 * to the XMAC in 20G mode
11134 */
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000011135 if (vars->line_speed == SPEED_20000) {
11136 bnx2x_set_aer_mmd(params, &params->phy[0]);
11137 bnx2x_warpcore_reset_lane(bp, &params->phy[0], 0);
11138 params->phy[INT_PHY].config_loopback(
11139 &params->phy[INT_PHY],
11140 params);
11141 }
Yaniv Rosner9380bb92011-06-14 01:34:07 +000011142 bnx2x_xmac_enable(params, vars, 1);
11143 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
11144}
11145
11146void bnx2x_init_umac_loopback(struct link_params *params,
11147 struct link_vars *vars)
11148{
11149 struct bnx2x *bp = params->bp;
11150 vars->link_up = 1;
11151 vars->line_speed = SPEED_1000;
11152 vars->duplex = DUPLEX_FULL;
11153 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
11154 vars->mac_type = MAC_TYPE_UMAC;
11155 vars->phy_flags = PHY_XGXS_FLAG;
11156 bnx2x_umac_enable(params, vars, 1);
11157
11158 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
11159}
11160
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000011161void bnx2x_init_xgxs_loopback(struct link_params *params,
11162 struct link_vars *vars)
11163{
11164 struct bnx2x *bp = params->bp;
11165 vars->link_up = 1;
11166 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
11167 vars->duplex = DUPLEX_FULL;
11168 if (params->req_line_speed[0] == SPEED_1000)
11169 vars->line_speed = SPEED_1000;
11170 else
11171 vars->line_speed = SPEED_10000;
11172
Yaniv Rosner9380bb92011-06-14 01:34:07 +000011173 if (!USES_WARPCORE(bp))
11174 bnx2x_xgxs_deassert(params);
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000011175 bnx2x_link_initialize(params, vars);
11176
11177 if (params->req_line_speed[0] == SPEED_1000) {
Yaniv Rosner9380bb92011-06-14 01:34:07 +000011178 if (USES_WARPCORE(bp))
11179 bnx2x_umac_enable(params, vars, 0);
11180 else {
11181 bnx2x_emac_program(params, vars);
11182 bnx2x_emac_enable(params, vars, 0);
11183 }
11184 } else {
11185 if (USES_WARPCORE(bp))
11186 bnx2x_xmac_enable(params, vars, 0);
11187 else
11188 bnx2x_bmac_enable(params, vars, 0);
11189 }
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000011190
11191 if (params->loopback_mode == LOOPBACK_XGXS) {
11192 /* set 10G XGXS loopback */
11193 params->phy[INT_PHY].config_loopback(
11194 &params->phy[INT_PHY],
11195 params);
11196
11197 } else {
11198 /* set external phy loopback */
11199 u8 phy_index;
11200 for (phy_index = EXT_PHY1;
11201 phy_index < params->num_phys; phy_index++) {
11202 if (params->phy[phy_index].config_loopback)
11203 params->phy[phy_index].config_loopback(
11204 &params->phy[phy_index],
11205 params);
11206 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011207 }
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000011208 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011209
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000011210 bnx2x_set_led(params, vars, LED_MODE_OPER, vars->line_speed);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011211}
11212
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +000011213int bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011214{
11215 struct bnx2x *bp = params->bp;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011216 DP(NETIF_MSG_LINK, "Phy Initialization started\n");
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011217 DP(NETIF_MSG_LINK, "(1) req_speed %d, req_flowctrl %d\n",
11218 params->req_line_speed[0], params->req_flow_ctrl[0]);
11219 DP(NETIF_MSG_LINK, "(2) req_speed %d, req_flowctrl %d\n",
11220 params->req_line_speed[1], params->req_flow_ctrl[1]);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011221 vars->link_status = 0;
11222 vars->phy_link_up = 0;
11223 vars->link_up = 0;
11224 vars->line_speed = 0;
11225 vars->duplex = DUPLEX_FULL;
11226 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
11227 vars->mac_type = MAC_TYPE_NONE;
11228 vars->phy_flags = 0;
11229
11230 /* disable attentions */
11231 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4,
11232 (NIG_MASK_XGXS0_LINK_STATUS |
11233 NIG_MASK_XGXS0_LINK10G |
11234 NIG_MASK_SERDES0_LINK_STATUS |
11235 NIG_MASK_MI_INT));
11236
11237 bnx2x_emac_init(params, vars);
11238
11239 if (params->num_phys == 0) {
11240 DP(NETIF_MSG_LINK, "No phy found for initialization !!\n");
11241 return -EINVAL;
11242 }
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000011243 set_phy_vars(params, vars);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011244
11245 DP(NETIF_MSG_LINK, "Num of phys on board: %d\n", params->num_phys);
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000011246 switch (params->loopback_mode) {
11247 case LOOPBACK_BMAC:
11248 bnx2x_init_bmac_loopback(params, vars);
11249 break;
11250 case LOOPBACK_EMAC:
11251 bnx2x_init_emac_loopback(params, vars);
11252 break;
Yaniv Rosner9380bb92011-06-14 01:34:07 +000011253 case LOOPBACK_XMAC:
11254 bnx2x_init_xmac_loopback(params, vars);
11255 break;
11256 case LOOPBACK_UMAC:
11257 bnx2x_init_umac_loopback(params, vars);
11258 break;
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000011259 case LOOPBACK_XGXS:
11260 case LOOPBACK_EXT_PHY:
11261 bnx2x_init_xgxs_loopback(params, vars);
11262 break;
11263 default:
Yaniv Rosner9380bb92011-06-14 01:34:07 +000011264 if (!CHIP_IS_E3(bp)) {
11265 if (params->switch_cfg == SWITCH_CFG_10G)
11266 bnx2x_xgxs_deassert(params);
11267 else
11268 bnx2x_serdes_deassert(bp, params->port);
11269 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011270 bnx2x_link_initialize(params, vars);
11271 msleep(30);
11272 bnx2x_link_int_enable(params);
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000011273 break;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011274 }
11275 return 0;
11276}
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +000011277
11278int bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
11279 u8 reset_ext_phy)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011280{
11281 struct bnx2x *bp = params->bp;
Yaniv Rosnercf1d9722010-11-01 05:32:34 +000011282 u8 phy_index, port = params->port, clear_latch_ind = 0;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011283 DP(NETIF_MSG_LINK, "Resetting the link of port %d\n", port);
11284 /* disable attentions */
11285 vars->link_status = 0;
11286 bnx2x_update_mng(params, vars->link_status);
11287 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000011288 (NIG_MASK_XGXS0_LINK_STATUS |
11289 NIG_MASK_XGXS0_LINK10G |
11290 NIG_MASK_SERDES0_LINK_STATUS |
11291 NIG_MASK_MI_INT));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011292
11293 /* activate nig drain */
11294 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
11295
11296 /* disable nig egress interface */
Yaniv Rosner9380bb92011-06-14 01:34:07 +000011297 if (!CHIP_IS_E3(bp)) {
11298 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
11299 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
11300 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011301
11302 /* Stop BigMac rx */
Yaniv Rosner9380bb92011-06-14 01:34:07 +000011303 if (!CHIP_IS_E3(bp))
11304 bnx2x_bmac_rx_disable(bp, port);
11305 else
11306 bnx2x_xmac_disable(params);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011307 /* disable emac */
Yaniv Rosner9380bb92011-06-14 01:34:07 +000011308 if (!CHIP_IS_E3(bp))
11309 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011310
11311 msleep(10);
Lucas De Marchi25985ed2011-03-30 22:57:33 -030011312 /* The PHY reset is controlled by GPIO 1
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011313 * Hold it as vars low
11314 */
11315 /* clear link led */
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +000011316 bnx2x_set_led(params, vars, LED_MODE_OFF, 0);
11317
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011318 if (reset_ext_phy) {
11319 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
11320 phy_index++) {
11321 if (params->phy[phy_index].link_reset)
11322 params->phy[phy_index].link_reset(
11323 &params->phy[phy_index],
11324 params);
Yaniv Rosnercf1d9722010-11-01 05:32:34 +000011325 if (params->phy[phy_index].flags &
11326 FLAGS_REARM_LATCH_SIGNAL)
11327 clear_latch_ind = 1;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011328 }
11329 }
11330
Yaniv Rosnercf1d9722010-11-01 05:32:34 +000011331 if (clear_latch_ind) {
11332 /* Clear latching indication */
11333 bnx2x_rearm_latch_signal(bp, port, 0);
11334 bnx2x_bits_dis(bp, NIG_REG_LATCH_BC_0 + port*4,
11335 1 << NIG_LATCH_BC_ENABLE_MI_INT);
11336 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011337 if (params->phy[INT_PHY].link_reset)
11338 params->phy[INT_PHY].link_reset(
11339 &params->phy[INT_PHY], params);
11340 /* reset BigMac */
11341 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
11342 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
11343
11344 /* disable nig ingress interface */
Yaniv Rosner9380bb92011-06-14 01:34:07 +000011345 if (!CHIP_IS_E3(bp)) {
11346 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0);
11347 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0);
11348 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011349 vars->link_up = 0;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000011350 vars->phy_flags = 0;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011351 return 0;
11352}
11353
11354/****************************************************************************/
11355/* Common function */
11356/****************************************************************************/
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +000011357static int bnx2x_8073_common_init_phy(struct bnx2x *bp,
11358 u32 shmem_base_path[],
11359 u32 shmem2_base_path[], u8 phy_index,
11360 u32 chip_id)
Yaniv Rosner6bbca912008-08-13 15:57:28 -070011361{
Yaniv Rosnere10bc842010-09-07 11:40:50 +000011362 struct bnx2x_phy phy[PORT_MAX];
11363 struct bnx2x_phy *phy_blk[PORT_MAX];
Yaniv Rosner6bbca912008-08-13 15:57:28 -070011364 u16 val;
Yaniv Rosnerc8e64df2011-01-30 04:15:00 +000011365 s8 port = 0;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000011366 s8 port_of_path = 0;
Yaniv Rosnerc8e64df2011-01-30 04:15:00 +000011367 u32 swap_val, swap_override;
11368 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
11369 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
11370 port ^= (swap_val && swap_override);
11371 bnx2x_ext_phy_hw_reset(bp, port);
Yaniv Rosner6bbca912008-08-13 15:57:28 -070011372 /* PART1 - Reset both phys */
11373 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000011374 u32 shmem_base, shmem2_base;
11375 /* In E2, same phy is using for port0 of the two paths */
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000011376 if (CHIP_IS_E1x(bp)) {
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000011377 shmem_base = shmem_base_path[0];
11378 shmem2_base = shmem2_base_path[0];
11379 port_of_path = port;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000011380 } else {
11381 shmem_base = shmem_base_path[port];
11382 shmem2_base = shmem2_base_path[port];
11383 port_of_path = 0;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000011384 }
11385
Yaniv Rosner6bbca912008-08-13 15:57:28 -070011386 /* Extract the ext phy address for the port */
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011387 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000011388 port_of_path, &phy[port]) !=
Yaniv Rosnere10bc842010-09-07 11:40:50 +000011389 0) {
11390 DP(NETIF_MSG_LINK, "populate_phy failed\n");
11391 return -EINVAL;
11392 }
Yaniv Rosner6bbca912008-08-13 15:57:28 -070011393 /* disable attentions */
Yaniv Rosner6a71bbe2010-11-01 05:32:31 +000011394 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 +
11395 port_of_path*4,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000011396 (NIG_MASK_XGXS0_LINK_STATUS |
11397 NIG_MASK_XGXS0_LINK10G |
11398 NIG_MASK_SERDES0_LINK_STATUS |
11399 NIG_MASK_MI_INT));
Yaniv Rosner6bbca912008-08-13 15:57:28 -070011400
Yaniv Rosner6bbca912008-08-13 15:57:28 -070011401 /* Need to take the phy out of low power mode in order
11402 to write to access its registers */
11403 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000011404 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
11405 port);
Yaniv Rosner6bbca912008-08-13 15:57:28 -070011406
11407 /* Reset the phy */
Yaniv Rosnere10bc842010-09-07 11:40:50 +000011408 bnx2x_cl45_write(bp, &phy[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000011409 MDIO_PMA_DEVAD,
11410 MDIO_PMA_REG_CTRL,
11411 1<<15);
Yaniv Rosner6bbca912008-08-13 15:57:28 -070011412 }
11413
11414 /* Add delay of 150ms after reset */
11415 msleep(150);
11416
Yaniv Rosnere10bc842010-09-07 11:40:50 +000011417 if (phy[PORT_0].addr & 0x1) {
11418 phy_blk[PORT_0] = &(phy[PORT_1]);
11419 phy_blk[PORT_1] = &(phy[PORT_0]);
11420 } else {
11421 phy_blk[PORT_0] = &(phy[PORT_0]);
11422 phy_blk[PORT_1] = &(phy[PORT_1]);
11423 }
11424
Yaniv Rosner6bbca912008-08-13 15:57:28 -070011425 /* PART2 - Download firmware to both phys */
11426 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000011427 if (CHIP_IS_E1x(bp))
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000011428 port_of_path = port;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000011429 else
11430 port_of_path = 0;
Yaniv Rosner6bbca912008-08-13 15:57:28 -070011431
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000011432 DP(NETIF_MSG_LINK, "Loading spirom for phy address 0x%x\n",
11433 phy_blk[port]->addr);
Yaniv Rosner5c99274b2011-01-18 04:33:36 +000011434 if (bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port],
11435 port_of_path))
Yaniv Rosner6bbca912008-08-13 15:57:28 -070011436 return -EINVAL;
Yaniv Rosner6bbca912008-08-13 15:57:28 -070011437
11438 /* Only set bit 10 = 1 (Tx power down) */
Yaniv Rosnere10bc842010-09-07 11:40:50 +000011439 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000011440 MDIO_PMA_DEVAD,
11441 MDIO_PMA_REG_TX_POWER_DOWN, &val);
Yaniv Rosner6bbca912008-08-13 15:57:28 -070011442
11443 /* Phase1 of TX_POWER_DOWN reset */
Yaniv Rosnere10bc842010-09-07 11:40:50 +000011444 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000011445 MDIO_PMA_DEVAD,
11446 MDIO_PMA_REG_TX_POWER_DOWN,
11447 (val | 1<<10));
Yaniv Rosner6bbca912008-08-13 15:57:28 -070011448 }
11449
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +000011450 /*
11451 * Toggle Transmitter: Power down and then up with 600ms delay
11452 * between
11453 */
Yaniv Rosner6bbca912008-08-13 15:57:28 -070011454 msleep(600);
11455
11456 /* PART3 - complete TX_POWER_DOWN process, and set GPIO2 back to low */
11457 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Eilon Greensteinf5372252009-02-12 08:38:30 +000011458 /* Phase2 of POWER_DOWN_RESET */
Yaniv Rosner6bbca912008-08-13 15:57:28 -070011459 /* Release bit 10 (Release Tx power down) */
Yaniv Rosnere10bc842010-09-07 11:40:50 +000011460 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000011461 MDIO_PMA_DEVAD,
11462 MDIO_PMA_REG_TX_POWER_DOWN, &val);
Yaniv Rosner6bbca912008-08-13 15:57:28 -070011463
Yaniv Rosnere10bc842010-09-07 11:40:50 +000011464 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000011465 MDIO_PMA_DEVAD,
11466 MDIO_PMA_REG_TX_POWER_DOWN, (val & (~(1<<10))));
Yaniv Rosner6bbca912008-08-13 15:57:28 -070011467 msleep(15);
11468
11469 /* Read modify write the SPI-ROM version select register */
Yaniv Rosnere10bc842010-09-07 11:40:50 +000011470 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000011471 MDIO_PMA_DEVAD,
11472 MDIO_PMA_REG_EDC_FFE_MAIN, &val);
Yaniv Rosnere10bc842010-09-07 11:40:50 +000011473 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000011474 MDIO_PMA_DEVAD,
11475 MDIO_PMA_REG_EDC_FFE_MAIN, (val | (1<<12)));
Yaniv Rosner6bbca912008-08-13 15:57:28 -070011476
11477 /* set GPIO2 back to LOW */
11478 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000011479 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
Yaniv Rosner6bbca912008-08-13 15:57:28 -070011480 }
11481 return 0;
Yaniv Rosner6bbca912008-08-13 15:57:28 -070011482}
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +000011483static int bnx2x_8726_common_init_phy(struct bnx2x *bp,
11484 u32 shmem_base_path[],
11485 u32 shmem2_base_path[], u8 phy_index,
11486 u32 chip_id)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011487{
11488 u32 val;
11489 s8 port;
11490 struct bnx2x_phy phy;
11491 /* Use port1 because of the static port-swap */
11492 /* Enable the module detection interrupt */
11493 val = REG_RD(bp, MISC_REG_GPIO_EVENT_EN);
11494 val |= ((1<<MISC_REGISTERS_GPIO_3)|
11495 (1<<(MISC_REGISTERS_GPIO_3 + MISC_REGISTERS_GPIO_PORT_SHIFT)));
11496 REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val);
11497
Yaniv Rosner650154b2010-11-01 05:32:36 +000011498 bnx2x_ext_phy_hw_reset(bp, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011499 msleep(5);
11500 for (port = 0; port < PORT_MAX; port++) {
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000011501 u32 shmem_base, shmem2_base;
11502
11503 /* In E2, same phy is using for port0 of the two paths */
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000011504 if (CHIP_IS_E1x(bp)) {
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000011505 shmem_base = shmem_base_path[0];
11506 shmem2_base = shmem2_base_path[0];
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000011507 } else {
11508 shmem_base = shmem_base_path[port];
11509 shmem2_base = shmem2_base_path[port];
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000011510 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011511 /* Extract the ext phy address for the port */
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011512 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011513 port, &phy) !=
11514 0) {
11515 DP(NETIF_MSG_LINK, "populate phy failed\n");
11516 return -EINVAL;
11517 }
11518
11519 /* Reset phy*/
11520 bnx2x_cl45_write(bp, &phy,
11521 MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, 0x0001);
11522
11523
11524 /* Set fault module detected LED on */
11525 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000011526 MISC_REGISTERS_GPIO_HIGH,
11527 port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011528 }
11529
11530 return 0;
11531}
Yaniv Rosnera8db5b42011-01-31 04:22:28 +000011532static void bnx2x_get_ext_phy_reset_gpio(struct bnx2x *bp, u32 shmem_base,
11533 u8 *io_gpio, u8 *io_port)
11534{
11535
11536 u32 phy_gpio_reset = REG_RD(bp, shmem_base +
11537 offsetof(struct shmem_region,
11538 dev_info.port_hw_config[PORT_0].default_cfg));
11539 switch (phy_gpio_reset) {
11540 case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO0_P0:
11541 *io_gpio = 0;
11542 *io_port = 0;
11543 break;
11544 case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO1_P0:
11545 *io_gpio = 1;
11546 *io_port = 0;
11547 break;
11548 case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO2_P0:
11549 *io_gpio = 2;
11550 *io_port = 0;
11551 break;
11552 case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO3_P0:
11553 *io_gpio = 3;
11554 *io_port = 0;
11555 break;
11556 case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO0_P1:
11557 *io_gpio = 0;
11558 *io_port = 1;
11559 break;
11560 case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO1_P1:
11561 *io_gpio = 1;
11562 *io_port = 1;
11563 break;
11564 case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO2_P1:
11565 *io_gpio = 2;
11566 *io_port = 1;
11567 break;
11568 case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO3_P1:
11569 *io_gpio = 3;
11570 *io_port = 1;
11571 break;
11572 default:
11573 /* Don't override the io_gpio and io_port */
11574 break;
11575 }
11576}
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +000011577
11578static int bnx2x_8727_common_init_phy(struct bnx2x *bp,
11579 u32 shmem_base_path[],
11580 u32 shmem2_base_path[], u8 phy_index,
11581 u32 chip_id)
Eilon Greenstein4d295db2009-07-21 05:47:47 +000011582{
Yaniv Rosnera8db5b42011-01-31 04:22:28 +000011583 s8 port, reset_gpio;
Eilon Greenstein4d295db2009-07-21 05:47:47 +000011584 u32 swap_val, swap_override;
Yaniv Rosnere10bc842010-09-07 11:40:50 +000011585 struct bnx2x_phy phy[PORT_MAX];
11586 struct bnx2x_phy *phy_blk[PORT_MAX];
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000011587 s8 port_of_path;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000011588 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
11589 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
Eilon Greenstein4d295db2009-07-21 05:47:47 +000011590
Yaniv Rosnera8db5b42011-01-31 04:22:28 +000011591 reset_gpio = MISC_REGISTERS_GPIO_1;
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011592 port = 1;
11593
Yaniv Rosnera8db5b42011-01-31 04:22:28 +000011594 /*
11595 * Retrieve the reset gpio/port which control the reset.
11596 * Default is GPIO1, PORT1
11597 */
11598 bnx2x_get_ext_phy_reset_gpio(bp, shmem_base_path[0],
11599 (u8 *)&reset_gpio, (u8 *)&port);
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011600
11601 /* Calculate the port based on port swap */
11602 port ^= (swap_val && swap_override);
11603
Yaniv Rosnera8db5b42011-01-31 04:22:28 +000011604 /* Initiate PHY reset*/
11605 bnx2x_set_gpio(bp, reset_gpio, MISC_REGISTERS_GPIO_OUTPUT_LOW,
11606 port);
11607 msleep(1);
11608 bnx2x_set_gpio(bp, reset_gpio, MISC_REGISTERS_GPIO_OUTPUT_HIGH,
11609 port);
11610
Eilon Greenstein4d295db2009-07-21 05:47:47 +000011611 msleep(5);
11612
11613 /* PART1 - Reset both phys */
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011614 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000011615 u32 shmem_base, shmem2_base;
11616
11617 /* In E2, same phy is using for port0 of the two paths */
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000011618 if (CHIP_IS_E1x(bp)) {
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000011619 shmem_base = shmem_base_path[0];
11620 shmem2_base = shmem2_base_path[0];
11621 port_of_path = port;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000011622 } else {
11623 shmem_base = shmem_base_path[port];
11624 shmem2_base = shmem2_base_path[port];
11625 port_of_path = 0;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000011626 }
11627
Eilon Greenstein4d295db2009-07-21 05:47:47 +000011628 /* Extract the ext phy address for the port */
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011629 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000011630 port_of_path, &phy[port]) !=
Yaniv Rosnere10bc842010-09-07 11:40:50 +000011631 0) {
11632 DP(NETIF_MSG_LINK, "populate phy failed\n");
11633 return -EINVAL;
11634 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +000011635 /* disable attentions */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000011636 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 +
11637 port_of_path*4,
11638 (NIG_MASK_XGXS0_LINK_STATUS |
11639 NIG_MASK_XGXS0_LINK10G |
11640 NIG_MASK_SERDES0_LINK_STATUS |
11641 NIG_MASK_MI_INT));
Eilon Greenstein4d295db2009-07-21 05:47:47 +000011642
Eilon Greenstein4d295db2009-07-21 05:47:47 +000011643
11644 /* Reset the phy */
Yaniv Rosnere10bc842010-09-07 11:40:50 +000011645 bnx2x_cl45_write(bp, &phy[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000011646 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
Eilon Greenstein4d295db2009-07-21 05:47:47 +000011647 }
11648
11649 /* Add delay of 150ms after reset */
11650 msleep(150);
Yaniv Rosnere10bc842010-09-07 11:40:50 +000011651 if (phy[PORT_0].addr & 0x1) {
11652 phy_blk[PORT_0] = &(phy[PORT_1]);
11653 phy_blk[PORT_1] = &(phy[PORT_0]);
11654 } else {
11655 phy_blk[PORT_0] = &(phy[PORT_0]);
11656 phy_blk[PORT_1] = &(phy[PORT_1]);
11657 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +000011658 /* PART2 - Download firmware to both phys */
Yaniv Rosnere10bc842010-09-07 11:40:50 +000011659 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000011660 if (CHIP_IS_E1x(bp))
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000011661 port_of_path = port;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000011662 else
11663 port_of_path = 0;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000011664 DP(NETIF_MSG_LINK, "Loading spirom for phy address 0x%x\n",
11665 phy_blk[port]->addr);
Yaniv Rosner5c99274b2011-01-18 04:33:36 +000011666 if (bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port],
11667 port_of_path))
Eilon Greenstein4d295db2009-07-21 05:47:47 +000011668 return -EINVAL;
Eilon Greenstein4d295db2009-07-21 05:47:47 +000011669
Yaniv Rosner5c99274b2011-01-18 04:33:36 +000011670 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +000011671 return 0;
11672}
11673
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +000011674static int bnx2x_ext_phy_common_init(struct bnx2x *bp, u32 shmem_base_path[],
11675 u32 shmem2_base_path[], u8 phy_index,
11676 u32 ext_phy_type, u32 chip_id)
Yaniv Rosner6bbca912008-08-13 15:57:28 -070011677{
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +000011678 int rc = 0;
Yaniv Rosner6bbca912008-08-13 15:57:28 -070011679
11680 switch (ext_phy_type) {
11681 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000011682 rc = bnx2x_8073_common_init_phy(bp, shmem_base_path,
11683 shmem2_base_path,
11684 phy_index, chip_id);
Yaniv Rosner6bbca912008-08-13 15:57:28 -070011685 break;
Yaniv Rosnere4d78f12011-05-31 21:25:55 +000011686 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722:
Eilon Greenstein4d295db2009-07-21 05:47:47 +000011687 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
11688 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000011689 rc = bnx2x_8727_common_init_phy(bp, shmem_base_path,
11690 shmem2_base_path,
11691 phy_index, chip_id);
Eilon Greenstein4d295db2009-07-21 05:47:47 +000011692 break;
11693
Eilon Greenstein589abe32009-02-12 08:36:55 +000011694 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +000011695 /*
11696 * GPIO1 affects both ports, so there's need to pull
11697 * it for single port alone
11698 */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000011699 rc = bnx2x_8726_common_init_phy(bp, shmem_base_path,
11700 shmem2_base_path,
11701 phy_index, chip_id);
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011702 break;
11703 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
11704 rc = -EINVAL;
Yaniv Rosner4f60dab2009-11-05 19:18:23 +020011705 break;
Yaniv Rosner6bbca912008-08-13 15:57:28 -070011706 default:
11707 DP(NETIF_MSG_LINK,
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +000011708 "ext_phy 0x%x common init not required\n",
11709 ext_phy_type);
Yaniv Rosner6bbca912008-08-13 15:57:28 -070011710 break;
11711 }
11712
Yaniv Rosner6d870c32011-01-31 04:22:20 +000011713 if (rc != 0)
11714 netdev_err(bp->dev, "Warning: PHY was not initialized,"
11715 " Port %d\n",
11716 0);
Yaniv Rosner6bbca912008-08-13 15:57:28 -070011717 return rc;
11718}
11719
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +000011720int bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base_path[],
11721 u32 shmem2_base_path[], u32 chip_id)
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011722{
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +000011723 int rc = 0;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000011724 u32 phy_ver, val;
11725 u8 phy_index = 0;
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011726 u32 ext_phy_type, ext_phy_config;
Yaniv Rosnera198c142011-05-31 21:29:42 +000011727 bnx2x_set_mdio_clk(bp, chip_id, PORT_0);
11728 bnx2x_set_mdio_clk(bp, chip_id, PORT_1);
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011729 DP(NETIF_MSG_LINK, "Begin common phy init\n");
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000011730 if (CHIP_IS_E3(bp)) {
11731 /* Enable EPIO */
11732 val = REG_RD(bp, MISC_REG_GEN_PURP_HWG);
11733 REG_WR(bp, MISC_REG_GEN_PURP_HWG, val | 1);
11734 }
Yaniv Rosnerb21a3422011-01-18 04:33:24 +000011735 /* Check if common init was already done */
11736 phy_ver = REG_RD(bp, shmem_base_path[0] +
11737 offsetof(struct shmem_region,
11738 port_mb[PORT_0].ext_phy_fw_version));
11739 if (phy_ver) {
11740 DP(NETIF_MSG_LINK, "Not doing common init; phy ver is 0x%x\n",
11741 phy_ver);
11742 return 0;
11743 }
11744
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011745 /* Read the ext_phy_type for arbitrary port(0) */
11746 for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
11747 phy_index++) {
11748 ext_phy_config = bnx2x_get_ext_phy_config(bp,
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000011749 shmem_base_path[0],
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011750 phy_index, 0);
11751 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000011752 rc |= bnx2x_ext_phy_common_init(bp, shmem_base_path,
11753 shmem2_base_path,
11754 phy_index, ext_phy_type,
11755 chip_id);
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011756 }
11757 return rc;
11758}
11759
11760u8 bnx2x_hw_lock_required(struct bnx2x *bp, u32 shmem_base, u32 shmem2_base)
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +000011761{
11762 u8 phy_index;
11763 struct bnx2x_phy phy;
11764 for (phy_index = INT_PHY; phy_index < MAX_PHYS;
11765 phy_index++) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011766 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +000011767 0, &phy) != 0) {
11768 DP(NETIF_MSG_LINK, "populate phy failed\n");
11769 return 0;
11770 }
11771
11772 if (phy.flags & FLAGS_HW_LOCK_REQUIRED)
11773 return 1;
11774 }
11775 return 0;
11776}
11777
11778u8 bnx2x_fan_failure_det_req(struct bnx2x *bp,
11779 u32 shmem_base,
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011780 u32 shmem2_base,
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +000011781 u8 port)
11782{
11783 u8 phy_index, fan_failure_det_req = 0;
11784 struct bnx2x_phy phy;
11785 for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
11786 phy_index++) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011787 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +000011788 port, &phy)
11789 != 0) {
11790 DP(NETIF_MSG_LINK, "populate phy failed\n");
11791 return 0;
11792 }
11793 fan_failure_det_req |= (phy.flags &
11794 FLAGS_FAN_FAILURE_DET_REQ);
11795 }
11796 return fan_failure_det_req;
11797}
11798
11799void bnx2x_hw_reset_phy(struct link_params *params)
11800{
11801 u8 phy_index;
11802 for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
11803 phy_index++) {
11804 if (params->phy[phy_index].hw_reset) {
11805 params->phy[phy_index].hw_reset(
11806 &params->phy[phy_index],
11807 params);
11808 params->phy[phy_index] = phy_null;
11809 }
11810 }
11811}
Yaniv Rosner020c7e32011-05-31 21:28:43 +000011812
11813void bnx2x_init_mod_abs_int(struct bnx2x *bp, struct link_vars *vars,
11814 u32 chip_id, u32 shmem_base, u32 shmem2_base,
11815 u8 port)
11816{
11817 u8 gpio_num = 0xff, gpio_port = 0xff, phy_index;
11818 u32 val;
11819 u32 offset, aeu_mask, swap_val, swap_override, sync_offset;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000011820 if (CHIP_IS_E3(bp)) {
11821 if (bnx2x_get_mod_abs_int_cfg(bp, chip_id,
11822 shmem_base,
11823 port,
11824 &gpio_num,
11825 &gpio_port) != 0)
11826 return;
11827 } else {
Yaniv Rosner020c7e32011-05-31 21:28:43 +000011828 struct bnx2x_phy phy;
11829 for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
11830 phy_index++) {
11831 if (bnx2x_populate_phy(bp, phy_index, shmem_base,
11832 shmem2_base, port, &phy)
11833 != 0) {
11834 DP(NETIF_MSG_LINK, "populate phy failed\n");
11835 return;
11836 }
11837 if (phy.type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) {
11838 gpio_num = MISC_REGISTERS_GPIO_3;
11839 gpio_port = port;
11840 break;
11841 }
11842 }
11843 }
11844
11845 if (gpio_num == 0xff)
11846 return;
11847
11848 /* Set GPIO3 to trigger SFP+ module insertion/removal */
11849 bnx2x_set_gpio(bp, gpio_num, MISC_REGISTERS_GPIO_INPUT_HI_Z, gpio_port);
11850
11851 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
11852 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
11853 gpio_port ^= (swap_val && swap_override);
11854
11855 vars->aeu_int_mask = AEU_INPUTS_ATTN_BITS_GPIO0_FUNCTION_0 <<
11856 (gpio_num + (gpio_port << 2));
11857
11858 sync_offset = shmem_base +
11859 offsetof(struct shmem_region,
11860 dev_info.port_hw_config[port].aeu_int_mask);
11861 REG_WR(bp, sync_offset, vars->aeu_int_mask);
11862
11863 DP(NETIF_MSG_LINK, "Setting MOD_ABS (GPIO%d_P%d) AEU to 0x%x\n",
11864 gpio_num, gpio_port, vars->aeu_int_mask);
11865
11866 if (port == 0)
11867 offset = MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0;
11868 else
11869 offset = MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0;
11870
11871 /* Open appropriate AEU for interrupts */
11872 aeu_mask = REG_RD(bp, offset);
11873 aeu_mask |= vars->aeu_int_mask;
11874 REG_WR(bp, offset, aeu_mask);
11875
11876 /* Enable the GPIO to trigger interrupt */
11877 val = REG_RD(bp, MISC_REG_GPIO_EVENT_EN);
11878 val |= 1 << (gpio_num + (gpio_port << 2));
11879 REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val);
11880}