blob: 3b184c2a85535a77c4835a2820de6674187f9224 [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/********************************************************/
Eilon Greenstein3196a882008-08-13 15:58:49 -070031#define ETH_HLEN 14
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000032/* L2 header size + 2*VLANs (8 bytes) + LLC SNAP (8 bytes) */
33#define ETH_OVREHEAD (ETH_HLEN + 8 + 8)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070034#define ETH_MIN_PACKET_SIZE 60
35#define ETH_MAX_PACKET_SIZE 1500
36#define ETH_MAX_JUMBO_PACKET_SIZE 9600
37#define MDIO_ACCESS_TIMEOUT 1000
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000038#define BMAC_CONTROL_RX_ENABLE 2
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000039#define WC_LANE_MAX 4
40#define I2C_SWITCH_WIDTH 2
41#define I2C_BSC0 0
42#define I2C_BSC1 1
43#define I2C_WA_RETRY_CNT 3
44#define MCPR_IMC_COMMAND_READ_OP 1
45#define MCPR_IMC_COMMAND_WRITE_OP 2
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070046
Yaniv Rosner26ffaf32011-10-27 05:09:45 +000047/* LED Blink rate that will achieve ~15.9Hz */
48#define LED_BLINK_RATE_VAL_E3 354
49#define LED_BLINK_RATE_VAL_E1X_E2 480
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070050/***********************************************************/
Eilon Greenstein3196a882008-08-13 15:58:49 -070051/* Shortcut definitions */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070052/***********************************************************/
53
Eilon Greenstein2f904462009-08-12 08:22:16 +000054#define NIG_LATCH_BC_ENABLE_MI_INT 0
55
56#define NIG_STATUS_EMAC0_MI_INT \
57 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_EMAC0_MISC_MI_INT
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070058#define NIG_STATUS_XGXS0_LINK10G \
59 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK10G
60#define NIG_STATUS_XGXS0_LINK_STATUS \
61 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS
62#define NIG_STATUS_XGXS0_LINK_STATUS_SIZE \
63 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS_SIZE
64#define NIG_STATUS_SERDES0_LINK_STATUS \
65 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_SERDES0_LINK_STATUS
66#define NIG_MASK_MI_INT \
67 NIG_MASK_INTERRUPT_PORT0_REG_MASK_EMAC0_MISC_MI_INT
68#define NIG_MASK_XGXS0_LINK10G \
69 NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK10G
70#define NIG_MASK_XGXS0_LINK_STATUS \
71 NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK_STATUS
72#define NIG_MASK_SERDES0_LINK_STATUS \
73 NIG_MASK_INTERRUPT_PORT0_REG_MASK_SERDES0_LINK_STATUS
74
75#define MDIO_AN_CL73_OR_37_COMPLETE \
76 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE | \
77 MDIO_GP_STATUS_TOP_AN_STATUS1_CL37_AUTONEG_COMPLETE)
78
79#define XGXS_RESET_BITS \
80 (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_RSTB_HW | \
81 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_IDDQ | \
82 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN | \
83 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN_SD | \
84 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_TXD_FIFO_RSTB)
85
86#define SERDES_RESET_BITS \
87 (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_RSTB_HW | \
88 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_IDDQ | \
89 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN | \
90 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN_SD)
91
92#define AUTONEG_CL37 SHARED_HW_CFG_AN_ENABLE_CL37
93#define AUTONEG_CL73 SHARED_HW_CFG_AN_ENABLE_CL73
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000094#define AUTONEG_BAM SHARED_HW_CFG_AN_ENABLE_BAM
Eilon Greenstein3196a882008-08-13 15:58:49 -070095#define AUTONEG_PARALLEL \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070096 SHARED_HW_CFG_AN_ENABLE_PARALLEL_DETECTION
Eilon Greenstein3196a882008-08-13 15:58:49 -070097#define AUTONEG_SGMII_FIBER_AUTODET \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070098 SHARED_HW_CFG_AN_EN_SGMII_FIBER_AUTO_DETECT
Eilon Greenstein3196a882008-08-13 15:58:49 -070099#define AUTONEG_REMOTE_PHY SHARED_HW_CFG_AN_ENABLE_REMOTE_PHY
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700100
101#define GP_STATUS_PAUSE_RSOLUTION_TXSIDE \
102 MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_TXSIDE
103#define GP_STATUS_PAUSE_RSOLUTION_RXSIDE \
104 MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_RXSIDE
105#define GP_STATUS_SPEED_MASK \
106 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_MASK
107#define GP_STATUS_10M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10M
108#define GP_STATUS_100M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_100M
109#define GP_STATUS_1G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G
110#define GP_STATUS_2_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_2_5G
111#define GP_STATUS_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_5G
112#define GP_STATUS_6G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_6G
113#define GP_STATUS_10G_HIG \
114 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_HIG
115#define GP_STATUS_10G_CX4 \
116 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_CX4
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700117#define GP_STATUS_1G_KX MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G_KX
118#define GP_STATUS_10G_KX4 \
119 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_KX4
Yaniv Rosner3c9ada22011-06-14 01:34:12 +0000120#define GP_STATUS_10G_KR MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_KR
121#define GP_STATUS_10G_XFI MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_XFI
122#define GP_STATUS_20G_DXGXS MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_20G_DXGXS
123#define GP_STATUS_10G_SFI MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_SFI
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000124#define LINK_10THD LINK_STATUS_SPEED_AND_DUPLEX_10THD
125#define LINK_10TFD LINK_STATUS_SPEED_AND_DUPLEX_10TFD
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700126#define LINK_100TXHD LINK_STATUS_SPEED_AND_DUPLEX_100TXHD
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000127#define LINK_100T4 LINK_STATUS_SPEED_AND_DUPLEX_100T4
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700128#define LINK_100TXFD LINK_STATUS_SPEED_AND_DUPLEX_100TXFD
129#define LINK_1000THD LINK_STATUS_SPEED_AND_DUPLEX_1000THD
130#define LINK_1000TFD LINK_STATUS_SPEED_AND_DUPLEX_1000TFD
131#define LINK_1000XFD LINK_STATUS_SPEED_AND_DUPLEX_1000XFD
132#define LINK_2500THD LINK_STATUS_SPEED_AND_DUPLEX_2500THD
133#define LINK_2500TFD LINK_STATUS_SPEED_AND_DUPLEX_2500TFD
134#define LINK_2500XFD LINK_STATUS_SPEED_AND_DUPLEX_2500XFD
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000135#define LINK_10GTFD LINK_STATUS_SPEED_AND_DUPLEX_10GTFD
136#define LINK_10GXFD LINK_STATUS_SPEED_AND_DUPLEX_10GXFD
Yaniv Rosner3c9ada22011-06-14 01:34:12 +0000137#define LINK_20GTFD LINK_STATUS_SPEED_AND_DUPLEX_20GTFD
138#define LINK_20GXFD LINK_STATUS_SPEED_AND_DUPLEX_20GXFD
Yaniv Rosner6583e332011-06-14 01:34:17 +0000139
140
141
Eilon Greenstein589abe32009-02-12 08:36:55 +0000142/* */
143#define SFP_EEPROM_CON_TYPE_ADDR 0x2
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000144 #define SFP_EEPROM_CON_TYPE_VAL_LC 0x7
Eilon Greenstein589abe32009-02-12 08:36:55 +0000145 #define SFP_EEPROM_CON_TYPE_VAL_COPPER 0x21
146
Eilon Greenstein4d295db2009-07-21 05:47:47 +0000147
148#define SFP_EEPROM_COMP_CODE_ADDR 0x3
149 #define SFP_EEPROM_COMP_CODE_SR_MASK (1<<4)
150 #define SFP_EEPROM_COMP_CODE_LR_MASK (1<<5)
151 #define SFP_EEPROM_COMP_CODE_LRM_MASK (1<<6)
152
Eilon Greenstein589abe32009-02-12 08:36:55 +0000153#define SFP_EEPROM_FC_TX_TECH_ADDR 0x8
154 #define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE 0x4
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000155 #define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE 0x8
Eilon Greenstein4d295db2009-07-21 05:47:47 +0000156
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000157#define SFP_EEPROM_OPTIONS_ADDR 0x40
Eilon Greenstein589abe32009-02-12 08:36:55 +0000158 #define SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK 0x1
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000159#define SFP_EEPROM_OPTIONS_SIZE 2
Eilon Greenstein589abe32009-02-12 08:36:55 +0000160
Yaniv Rosnercd88cce2011-01-31 04:21:34 +0000161#define EDC_MODE_LINEAR 0x0022
162#define EDC_MODE_LIMITING 0x0044
163#define EDC_MODE_PASSIVE_DAC 0x0055
Eilon Greenstein589abe32009-02-12 08:36:55 +0000164
Yaniv Rosner866ceda2011-11-28 00:49:45 +0000165/* BRB default for class 0 E2 */
166#define DEFAULT0_E2_BRB_MAC_PAUSE_XOFF_THR 170
167#define DEFAULT0_E2_BRB_MAC_PAUSE_XON_THR 250
168#define DEFAULT0_E2_BRB_MAC_FULL_XOFF_THR 10
169#define DEFAULT0_E2_BRB_MAC_FULL_XON_THR 50
Eilon Greenstein4d295db2009-07-21 05:47:47 +0000170
Yaniv Rosner9380bb92011-06-14 01:34:07 +0000171/* BRB thresholds for E2*/
172#define PFC_E2_BRB_MAC_PAUSE_XOFF_THR_PAUSE 170
173#define PFC_E2_BRB_MAC_PAUSE_XOFF_THR_NON_PAUSE 0
174
175#define PFC_E2_BRB_MAC_PAUSE_XON_THR_PAUSE 250
176#define PFC_E2_BRB_MAC_PAUSE_XON_THR_NON_PAUSE 0
177
178#define PFC_E2_BRB_MAC_FULL_XOFF_THR_PAUSE 10
179#define PFC_E2_BRB_MAC_FULL_XOFF_THR_NON_PAUSE 90
180
181#define PFC_E2_BRB_MAC_FULL_XON_THR_PAUSE 50
182#define PFC_E2_BRB_MAC_FULL_XON_THR_NON_PAUSE 250
183
Yaniv Rosner866ceda2011-11-28 00:49:45 +0000184/* BRB default for class 0 E3A0 */
185#define DEFAULT0_E3A0_BRB_MAC_PAUSE_XOFF_THR 290
186#define DEFAULT0_E3A0_BRB_MAC_PAUSE_XON_THR 410
187#define DEFAULT0_E3A0_BRB_MAC_FULL_XOFF_THR 10
188#define DEFAULT0_E3A0_BRB_MAC_FULL_XON_THR 50
189
Yaniv Rosner9380bb92011-06-14 01:34:07 +0000190/* BRB thresholds for E3A0 */
191#define PFC_E3A0_BRB_MAC_PAUSE_XOFF_THR_PAUSE 290
192#define PFC_E3A0_BRB_MAC_PAUSE_XOFF_THR_NON_PAUSE 0
193
194#define PFC_E3A0_BRB_MAC_PAUSE_XON_THR_PAUSE 410
195#define PFC_E3A0_BRB_MAC_PAUSE_XON_THR_NON_PAUSE 0
196
197#define PFC_E3A0_BRB_MAC_FULL_XOFF_THR_PAUSE 10
198#define PFC_E3A0_BRB_MAC_FULL_XOFF_THR_NON_PAUSE 170
199
200#define PFC_E3A0_BRB_MAC_FULL_XON_THR_PAUSE 50
201#define PFC_E3A0_BRB_MAC_FULL_XON_THR_NON_PAUSE 410
202
Yaniv Rosner866ceda2011-11-28 00:49:45 +0000203/* BRB default for E3B0 */
204#define DEFAULT0_E3B0_BRB_MAC_PAUSE_XOFF_THR 330
205#define DEFAULT0_E3B0_BRB_MAC_PAUSE_XON_THR 490
206#define DEFAULT0_E3B0_BRB_MAC_FULL_XOFF_THR 15
207#define DEFAULT0_E3B0_BRB_MAC_FULL_XON_THR 55
Yaniv Rosner9380bb92011-06-14 01:34:07 +0000208
209/* BRB thresholds for E3B0 2 port mode*/
210#define PFC_E3B0_2P_BRB_MAC_PAUSE_XOFF_THR_PAUSE 1025
211#define PFC_E3B0_2P_BRB_MAC_PAUSE_XOFF_THR_NON_PAUSE 0
212
213#define PFC_E3B0_2P_BRB_MAC_PAUSE_XON_THR_PAUSE 1025
214#define PFC_E3B0_2P_BRB_MAC_PAUSE_XON_THR_NON_PAUSE 0
215
216#define PFC_E3B0_2P_BRB_MAC_FULL_XOFF_THR_PAUSE 10
217#define PFC_E3B0_2P_BRB_MAC_FULL_XOFF_THR_NON_PAUSE 1025
218
219#define PFC_E3B0_2P_BRB_MAC_FULL_XON_THR_PAUSE 50
220#define PFC_E3B0_2P_BRB_MAC_FULL_XON_THR_NON_PAUSE 1025
221
222/* only for E3B0*/
223#define PFC_E3B0_2P_BRB_FULL_LB_XOFF_THR 1025
224#define PFC_E3B0_2P_BRB_FULL_LB_XON_THR 1025
225
226/* Lossy +Lossless GUARANTIED == GUART */
227#define PFC_E3B0_2P_MIX_PAUSE_LB_GUART 284
228/* Lossless +Lossless*/
229#define PFC_E3B0_2P_PAUSE_LB_GUART 236
230/* Lossy +Lossy*/
231#define PFC_E3B0_2P_NON_PAUSE_LB_GUART 342
232
233/* Lossy +Lossless*/
234#define PFC_E3B0_2P_MIX_PAUSE_MAC_0_CLASS_T_GUART 284
235/* Lossless +Lossless*/
236#define PFC_E3B0_2P_PAUSE_MAC_0_CLASS_T_GUART 236
237/* Lossy +Lossy*/
238#define PFC_E3B0_2P_NON_PAUSE_MAC_0_CLASS_T_GUART 336
239#define PFC_E3B0_2P_BRB_MAC_0_CLASS_T_GUART_HYST 80
240
241#define PFC_E3B0_2P_BRB_MAC_1_CLASS_T_GUART 0
242#define PFC_E3B0_2P_BRB_MAC_1_CLASS_T_GUART_HYST 0
243
244/* BRB thresholds for E3B0 4 port mode */
245#define PFC_E3B0_4P_BRB_MAC_PAUSE_XOFF_THR_PAUSE 304
246#define PFC_E3B0_4P_BRB_MAC_PAUSE_XOFF_THR_NON_PAUSE 0
247
248#define PFC_E3B0_4P_BRB_MAC_PAUSE_XON_THR_PAUSE 384
249#define PFC_E3B0_4P_BRB_MAC_PAUSE_XON_THR_NON_PAUSE 0
250
251#define PFC_E3B0_4P_BRB_MAC_FULL_XOFF_THR_PAUSE 10
252#define PFC_E3B0_4P_BRB_MAC_FULL_XOFF_THR_NON_PAUSE 304
253
254#define PFC_E3B0_4P_BRB_MAC_FULL_XON_THR_PAUSE 50
255#define PFC_E3B0_4P_BRB_MAC_FULL_XON_THR_NON_PAUSE 384
256
Yaniv Rosner9380bb92011-06-14 01:34:07 +0000257/* only for E3B0*/
258#define PFC_E3B0_4P_BRB_FULL_LB_XOFF_THR 304
259#define PFC_E3B0_4P_BRB_FULL_LB_XON_THR 384
Yaniv Rosner2f751a82011-11-28 00:49:52 +0000260#define PFC_E3B0_4P_LB_GUART 120
Yaniv Rosner9380bb92011-06-14 01:34:07 +0000261
262#define PFC_E3B0_4P_BRB_MAC_0_CLASS_T_GUART 120
Yaniv Rosner2f751a82011-11-28 00:49:52 +0000263#define PFC_E3B0_4P_BRB_MAC_0_CLASS_T_GUART_HYST 80
Yaniv Rosner9380bb92011-06-14 01:34:07 +0000264
265#define PFC_E3B0_4P_BRB_MAC_1_CLASS_T_GUART 80
Yaniv Rosner2f751a82011-11-28 00:49:52 +0000266#define PFC_E3B0_4P_BRB_MAC_1_CLASS_T_GUART_HYST 120
Yaniv Rosner9380bb92011-06-14 01:34:07 +0000267
Yaniv Rosner866ceda2011-11-28 00:49:45 +0000268/* Pause defines*/
269#define DEFAULT_E3B0_BRB_FULL_LB_XOFF_THR 330
270#define DEFAULT_E3B0_BRB_FULL_LB_XON_THR 490
271#define DEFAULT_E3B0_LB_GUART 40
272
273#define DEFAULT_E3B0_BRB_MAC_0_CLASS_T_GUART 40
274#define DEFAULT_E3B0_BRB_MAC_0_CLASS_T_GUART_HYST 0
275
276#define DEFAULT_E3B0_BRB_MAC_1_CLASS_T_GUART 40
277#define DEFAULT_E3B0_BRB_MAC_1_CLASS_T_GUART_HYST 0
278
279/* ETS defines*/
Yaniv Rosner9380bb92011-06-14 01:34:07 +0000280#define DCBX_INVALID_COS (0xFF)
281
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000282#define ETS_BW_LIMIT_CREDIT_UPPER_BOUND (0x5000)
283#define ETS_BW_LIMIT_CREDIT_WEIGHT (0x5000)
Yaniv Rosner9380bb92011-06-14 01:34:07 +0000284#define ETS_E3B0_NIG_MIN_W_VAL_UP_TO_10GBPS (1360)
285#define ETS_E3B0_NIG_MIN_W_VAL_20GBPS (2720)
286#define ETS_E3B0_PBF_MIN_W_VAL (10000)
287
288#define MAX_PACKET_SIZE (9700)
Yaniv Rosner3c9ada22011-06-14 01:34:12 +0000289#define WC_UC_TIMEOUT 100
Yaniv Rosnera9077bf2011-10-27 05:09:46 +0000290#define MAX_KR_LINK_RETRY 4
Yaniv Rosner9380bb92011-06-14 01:34:07 +0000291
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700292/**********************************************************/
293/* INTERFACE */
294/**********************************************************/
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000295
Yaniv Rosnercd2be892011-01-31 04:21:45 +0000296#define CL22_WR_OVER_CL45(_bp, _phy, _bank, _addr, _val) \
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000297 bnx2x_cl45_write(_bp, _phy, \
Yaniv Rosner7aa07112010-09-07 11:41:01 +0000298 (_phy)->def_md_devad, \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700299 (_bank + (_addr & 0xf)), \
300 _val)
301
Yaniv Rosnercd2be892011-01-31 04:21:45 +0000302#define CL22_RD_OVER_CL45(_bp, _phy, _bank, _addr, _val) \
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000303 bnx2x_cl45_read(_bp, _phy, \
Yaniv Rosner7aa07112010-09-07 11:41:01 +0000304 (_phy)->def_md_devad, \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700305 (_bank + (_addr & 0xf)), \
306 _val)
307
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700308static u32 bnx2x_bits_en(struct bnx2x *bp, u32 reg, u32 bits)
309{
310 u32 val = REG_RD(bp, reg);
311
312 val |= bits;
313 REG_WR(bp, reg, val);
314 return val;
315}
316
317static u32 bnx2x_bits_dis(struct bnx2x *bp, u32 reg, u32 bits)
318{
319 u32 val = REG_RD(bp, reg);
320
321 val &= ~bits;
322 REG_WR(bp, reg, val);
323 return val;
324}
325
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000326/******************************************************************/
Yaniv Rosner3c9ada22011-06-14 01:34:12 +0000327/* EPIO/GPIO section */
328/******************************************************************/
Yaniv Rosner3deb8162011-06-14 01:34:33 +0000329static void bnx2x_get_epio(struct bnx2x *bp, u32 epio_pin, u32 *en)
330{
331 u32 epio_mask, gp_oenable;
332 *en = 0;
333 /* Sanity check */
334 if (epio_pin > 31) {
335 DP(NETIF_MSG_LINK, "Invalid EPIO pin %d to get\n", epio_pin);
336 return;
337 }
338
339 epio_mask = 1 << epio_pin;
340 /* Set this EPIO to output */
341 gp_oenable = REG_RD(bp, MCP_REG_MCPR_GP_OENABLE);
342 REG_WR(bp, MCP_REG_MCPR_GP_OENABLE, gp_oenable & ~epio_mask);
343
344 *en = (REG_RD(bp, MCP_REG_MCPR_GP_INPUTS) & epio_mask) >> epio_pin;
345}
Yaniv Rosner3c9ada22011-06-14 01:34:12 +0000346static void bnx2x_set_epio(struct bnx2x *bp, u32 epio_pin, u32 en)
347{
348 u32 epio_mask, gp_output, gp_oenable;
349
350 /* Sanity check */
351 if (epio_pin > 31) {
352 DP(NETIF_MSG_LINK, "Invalid EPIO pin %d to set\n", epio_pin);
353 return;
354 }
355 DP(NETIF_MSG_LINK, "Setting EPIO pin %d to %d\n", epio_pin, en);
356 epio_mask = 1 << epio_pin;
357 /* Set this EPIO to output */
358 gp_output = REG_RD(bp, MCP_REG_MCPR_GP_OUTPUTS);
359 if (en)
360 gp_output |= epio_mask;
361 else
362 gp_output &= ~epio_mask;
363
364 REG_WR(bp, MCP_REG_MCPR_GP_OUTPUTS, gp_output);
365
366 /* Set the value for this EPIO */
367 gp_oenable = REG_RD(bp, MCP_REG_MCPR_GP_OENABLE);
368 REG_WR(bp, MCP_REG_MCPR_GP_OENABLE, gp_oenable | epio_mask);
369}
370
371static void bnx2x_set_cfg_pin(struct bnx2x *bp, u32 pin_cfg, u32 val)
372{
373 if (pin_cfg == PIN_CFG_NA)
374 return;
375 if (pin_cfg >= PIN_CFG_EPIO0) {
376 bnx2x_set_epio(bp, pin_cfg - PIN_CFG_EPIO0, val);
377 } else {
378 u8 gpio_num = (pin_cfg - PIN_CFG_GPIO0_P0) & 0x3;
379 u8 gpio_port = (pin_cfg - PIN_CFG_GPIO0_P0) >> 2;
380 bnx2x_set_gpio(bp, gpio_num, (u8)val, gpio_port);
381 }
382}
383
Yaniv Rosner3deb8162011-06-14 01:34:33 +0000384static u32 bnx2x_get_cfg_pin(struct bnx2x *bp, u32 pin_cfg, u32 *val)
385{
386 if (pin_cfg == PIN_CFG_NA)
387 return -EINVAL;
388 if (pin_cfg >= PIN_CFG_EPIO0) {
389 bnx2x_get_epio(bp, pin_cfg - PIN_CFG_EPIO0, val);
390 } else {
391 u8 gpio_num = (pin_cfg - PIN_CFG_GPIO0_P0) & 0x3;
392 u8 gpio_port = (pin_cfg - PIN_CFG_GPIO0_P0) >> 2;
393 *val = bnx2x_get_gpio(bp, gpio_num, gpio_port);
394 }
395 return 0;
396
397}
Yaniv Rosner3c9ada22011-06-14 01:34:12 +0000398/******************************************************************/
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000399/* ETS section */
400/******************************************************************/
Yaniv Rosner6c3218c2011-06-14 01:34:23 +0000401static void bnx2x_ets_e2e3a0_disabled(struct link_params *params)
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000402{
403 /* ETS disabled configuration*/
404 struct bnx2x *bp = params->bp;
405
Yaniv Rosner6c3218c2011-06-14 01:34:23 +0000406 DP(NETIF_MSG_LINK, "ETS E2E3 disabled configuration\n");
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000407
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000408 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000409 * mapping between entry priority to client number (0,1,2 -debug and
410 * management clients, 3 - COS0 client, 4 - COS client)(HIGHEST)
411 * 3bits client num.
412 * PRI4 | PRI3 | PRI2 | PRI1 | PRI0
413 * cos1-100 cos0-011 dbg1-010 dbg0-001 MCP-000
414 */
415
416 REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT, 0x4688);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000417 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000418 * Bitmap of 5bits length. Each bit specifies whether the entry behaves
419 * as strict. Bits 0,1,2 - debug and management entries, 3 -
420 * COS0 entry, 4 - COS1 entry.
421 * COS1 | COS0 | DEBUG1 | DEBUG0 | MGMT
422 * bit4 bit3 bit2 bit1 bit0
423 * MCP and debug are strict
424 */
425
426 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x7);
427 /* defines which entries (clients) are subjected to WFQ arbitration */
428 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ, 0);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000429 /*
430 * For strict priority entries defines the number of consecutive
431 * slots for the highest priority.
432 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000433 REG_WR(bp, NIG_REG_P0_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000434 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000435 * mapping between the CREDIT_WEIGHT registers and actual client
436 * numbers
437 */
438 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP, 0);
439 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_0, 0);
440 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_1, 0);
441
442 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_0, 0);
443 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_1, 0);
444 REG_WR(bp, PBF_REG_HIGH_PRIORITY_COS_NUM, 0);
445 /* ETS mode disable */
446 REG_WR(bp, PBF_REG_ETS_ENABLED, 0);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +0000447 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000448 * If ETS mode is enabled (there is no strict priority) defines a WFQ
449 * weight for COS0/COS1.
450 */
451 REG_WR(bp, PBF_REG_COS0_WEIGHT, 0x2710);
452 REG_WR(bp, PBF_REG_COS1_WEIGHT, 0x2710);
453 /* Upper bound that COS0_WEIGHT can reach in the WFQ arbiter */
454 REG_WR(bp, PBF_REG_COS0_UPPER_BOUND, 0x989680);
455 REG_WR(bp, PBF_REG_COS1_UPPER_BOUND, 0x989680);
456 /* Defines the number of consecutive slots for the strict priority */
457 REG_WR(bp, PBF_REG_NUM_STRICT_ARB_SLOTS, 0);
458}
Yaniv Rosner6c3218c2011-06-14 01:34:23 +0000459/******************************************************************************
460* Description:
461* Getting min_w_val will be set according to line speed .
462*.
463******************************************************************************/
464static u32 bnx2x_ets_get_min_w_val_nig(const struct link_vars *vars)
465{
466 u32 min_w_val = 0;
467 /* Calculate min_w_val.*/
468 if (vars->link_up) {
Yaniv Rosnerde0396f2011-11-28 00:49:53 +0000469 if (vars->line_speed == SPEED_20000)
Yaniv Rosner6c3218c2011-06-14 01:34:23 +0000470 min_w_val = ETS_E3B0_NIG_MIN_W_VAL_20GBPS;
471 else
472 min_w_val = ETS_E3B0_NIG_MIN_W_VAL_UP_TO_10GBPS;
473 } else
474 min_w_val = ETS_E3B0_NIG_MIN_W_VAL_20GBPS;
475 /**
476 * If the link isn't up (static configuration for example ) The
477 * link will be according to 20GBPS.
478 */
479 return min_w_val;
480}
481/******************************************************************************
482* Description:
483* Getting credit upper bound form min_w_val.
484*.
485******************************************************************************/
486static u32 bnx2x_ets_get_credit_upper_bound(const u32 min_w_val)
487{
488 const u32 credit_upper_bound = (u32)MAXVAL((150 * min_w_val),
489 MAX_PACKET_SIZE);
490 return credit_upper_bound;
491}
492/******************************************************************************
493* Description:
494* Set credit upper bound for NIG.
495*.
496******************************************************************************/
497static void bnx2x_ets_e3b0_set_credit_upper_bound_nig(
498 const struct link_params *params,
499 const u32 min_w_val)
500{
501 struct bnx2x *bp = params->bp;
502 const u8 port = params->port;
503 const u32 credit_upper_bound =
504 bnx2x_ets_get_credit_upper_bound(min_w_val);
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +0000505
Yaniv Rosner6c3218c2011-06-14 01:34:23 +0000506 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_UPPER_BOUND_0 :
507 NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_0, credit_upper_bound);
508 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_UPPER_BOUND_1 :
509 NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_1, credit_upper_bound);
510 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_UPPER_BOUND_2 :
511 NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_2, credit_upper_bound);
512 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_UPPER_BOUND_3 :
513 NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_3, credit_upper_bound);
514 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_UPPER_BOUND_4 :
515 NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_4, credit_upper_bound);
516 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_UPPER_BOUND_5 :
517 NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_5, credit_upper_bound);
518
Yaniv Rosnerde0396f2011-11-28 00:49:53 +0000519 if (!port) {
Yaniv Rosner6c3218c2011-06-14 01:34:23 +0000520 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_6,
521 credit_upper_bound);
522 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_7,
523 credit_upper_bound);
524 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_8,
525 credit_upper_bound);
526 }
527}
528/******************************************************************************
529* Description:
530* Will return the NIG ETS registers to init values.Except
531* credit_upper_bound.
532* That isn't used in this configuration (No WFQ is enabled) and will be
533* configured acording to spec
534*.
535******************************************************************************/
536static void bnx2x_ets_e3b0_nig_disabled(const struct link_params *params,
537 const struct link_vars *vars)
538{
539 struct bnx2x *bp = params->bp;
540 const u8 port = params->port;
541 const u32 min_w_val = bnx2x_ets_get_min_w_val_nig(vars);
542 /**
543 * mapping between entry priority to client number (0,1,2 -debug and
544 * management clients, 3 - COS0 client, 4 - COS1, ... 8 -
545 * COS5)(HIGHEST) 4bits client num.TODO_ETS - Should be done by
546 * reset value or init tool
547 */
548 if (port) {
549 REG_WR(bp, NIG_REG_P1_TX_ARB_PRIORITY_CLIENT2_LSB, 0x543210);
550 REG_WR(bp, NIG_REG_P1_TX_ARB_PRIORITY_CLIENT2_MSB, 0x0);
551 } else {
552 REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT2_LSB, 0x76543210);
553 REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT2_MSB, 0x8);
554 }
555 /**
556 * For strict priority entries defines the number of consecutive
557 * slots for the highest priority.
558 */
559 /* TODO_ETS - Should be done by reset value or init tool */
560 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_NUM_STRICT_ARB_SLOTS :
561 NIG_REG_P1_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100);
562 /**
563 * mapping between the CREDIT_WEIGHT registers and actual client
564 * numbers
565 */
566 /* TODO_ETS - Should be done by reset value or init tool */
567 if (port) {
568 /*Port 1 has 6 COS*/
569 REG_WR(bp, NIG_REG_P1_TX_ARB_CLIENT_CREDIT_MAP2_LSB, 0x210543);
570 REG_WR(bp, NIG_REG_P1_TX_ARB_CLIENT_CREDIT_MAP2_MSB, 0x0);
571 } else {
572 /*Port 0 has 9 COS*/
573 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP2_LSB,
574 0x43210876);
575 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP2_MSB, 0x5);
576 }
577
578 /**
579 * Bitmap of 5bits length. Each bit specifies whether the entry behaves
580 * as strict. Bits 0,1,2 - debug and management entries, 3 -
581 * COS0 entry, 4 - COS1 entry.
582 * COS1 | COS0 | DEBUG1 | DEBUG0 | MGMT
583 * bit4 bit3 bit2 bit1 bit0
584 * MCP and debug are strict
585 */
586 if (port)
587 REG_WR(bp, NIG_REG_P1_TX_ARB_CLIENT_IS_STRICT, 0x3f);
588 else
589 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x1ff);
590 /* defines which entries (clients) are subjected to WFQ arbitration */
591 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CLIENT_IS_SUBJECT2WFQ :
592 NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ, 0);
593
594 /**
595 * Please notice the register address are note continuous and a
596 * for here is note appropriate.In 2 port mode port0 only COS0-5
597 * can be used. DEBUG1,DEBUG1,MGMT are never used for WFQ* In 4
598 * port mode port1 only COS0-2 can be used. DEBUG1,DEBUG1,MGMT
599 * are never used for WFQ
600 */
601 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_0 :
602 NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_0, 0x0);
603 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_1 :
604 NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_1, 0x0);
605 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_2 :
606 NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_2, 0x0);
607 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_3 :
608 NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_3, 0x0);
609 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_4 :
610 NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_4, 0x0);
611 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_5 :
612 NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_5, 0x0);
Yaniv Rosnerde0396f2011-11-28 00:49:53 +0000613 if (!port) {
Yaniv Rosner6c3218c2011-06-14 01:34:23 +0000614 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_6, 0x0);
615 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_7, 0x0);
616 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_8, 0x0);
617 }
618
619 bnx2x_ets_e3b0_set_credit_upper_bound_nig(params, min_w_val);
620}
621/******************************************************************************
622* Description:
623* Set credit upper bound for PBF.
624*.
625******************************************************************************/
626static void bnx2x_ets_e3b0_set_credit_upper_bound_pbf(
627 const struct link_params *params,
628 const u32 min_w_val)
629{
630 struct bnx2x *bp = params->bp;
631 const u32 credit_upper_bound =
632 bnx2x_ets_get_credit_upper_bound(min_w_val);
633 const u8 port = params->port;
634 u32 base_upper_bound = 0;
635 u8 max_cos = 0;
636 u8 i = 0;
637 /**
638 * In 2 port mode port0 has COS0-5 that can be used for WFQ.In 4
639 * port mode port1 has COS0-2 that can be used for WFQ.
640 */
Yaniv Rosnerde0396f2011-11-28 00:49:53 +0000641 if (!port) {
Yaniv Rosner6c3218c2011-06-14 01:34:23 +0000642 base_upper_bound = PBF_REG_COS0_UPPER_BOUND_P0;
643 max_cos = DCBX_E3B0_MAX_NUM_COS_PORT0;
644 } else {
645 base_upper_bound = PBF_REG_COS0_UPPER_BOUND_P1;
646 max_cos = DCBX_E3B0_MAX_NUM_COS_PORT1;
647 }
648
649 for (i = 0; i < max_cos; i++)
650 REG_WR(bp, base_upper_bound + (i << 2), credit_upper_bound);
651}
652
653/******************************************************************************
654* Description:
655* Will return the PBF ETS registers to init values.Except
656* credit_upper_bound.
657* That isn't used in this configuration (No WFQ is enabled) and will be
658* configured acording to spec
659*.
660******************************************************************************/
661static void bnx2x_ets_e3b0_pbf_disabled(const struct link_params *params)
662{
663 struct bnx2x *bp = params->bp;
664 const u8 port = params->port;
665 const u32 min_w_val_pbf = ETS_E3B0_PBF_MIN_W_VAL;
666 u8 i = 0;
667 u32 base_weight = 0;
668 u8 max_cos = 0;
669
670 /**
671 * mapping between entry priority to client number 0 - COS0
672 * client, 2 - COS1, ... 5 - COS5)(HIGHEST) 4bits client num.
673 * TODO_ETS - Should be done by reset value or init tool
674 */
675 if (port)
676 /* 0x688 (|011|0 10|00 1|000) */
677 REG_WR(bp, PBF_REG_ETS_ARB_PRIORITY_CLIENT_P1 , 0x688);
678 else
679 /* (10 1|100 |011|0 10|00 1|000) */
680 REG_WR(bp, PBF_REG_ETS_ARB_PRIORITY_CLIENT_P0 , 0x2C688);
681
682 /* TODO_ETS - Should be done by reset value or init tool */
683 if (port)
684 /* 0x688 (|011|0 10|00 1|000)*/
685 REG_WR(bp, PBF_REG_ETS_ARB_CLIENT_CREDIT_MAP_P1, 0x688);
686 else
687 /* 0x2C688 (10 1|100 |011|0 10|00 1|000) */
688 REG_WR(bp, PBF_REG_ETS_ARB_CLIENT_CREDIT_MAP_P0, 0x2C688);
689
690 REG_WR(bp, (port) ? PBF_REG_ETS_ARB_NUM_STRICT_ARB_SLOTS_P1 :
691 PBF_REG_ETS_ARB_NUM_STRICT_ARB_SLOTS_P0 , 0x100);
692
693
694 REG_WR(bp, (port) ? PBF_REG_ETS_ARB_CLIENT_IS_STRICT_P1 :
695 PBF_REG_ETS_ARB_CLIENT_IS_STRICT_P0 , 0);
696
697 REG_WR(bp, (port) ? PBF_REG_ETS_ARB_CLIENT_IS_SUBJECT2WFQ_P1 :
698 PBF_REG_ETS_ARB_CLIENT_IS_SUBJECT2WFQ_P0 , 0);
699 /**
700 * In 2 port mode port0 has COS0-5 that can be used for WFQ.
701 * In 4 port mode port1 has COS0-2 that can be used for WFQ.
702 */
Yaniv Rosnerde0396f2011-11-28 00:49:53 +0000703 if (!port) {
Yaniv Rosner6c3218c2011-06-14 01:34:23 +0000704 base_weight = PBF_REG_COS0_WEIGHT_P0;
705 max_cos = DCBX_E3B0_MAX_NUM_COS_PORT0;
706 } else {
707 base_weight = PBF_REG_COS0_WEIGHT_P1;
708 max_cos = DCBX_E3B0_MAX_NUM_COS_PORT1;
709 }
710
711 for (i = 0; i < max_cos; i++)
712 REG_WR(bp, base_weight + (0x4 * i), 0);
713
714 bnx2x_ets_e3b0_set_credit_upper_bound_pbf(params, min_w_val_pbf);
715}
716/******************************************************************************
717* Description:
718* E3B0 disable will return basicly the values to init values.
719*.
720******************************************************************************/
721static int bnx2x_ets_e3b0_disabled(const struct link_params *params,
722 const struct link_vars *vars)
723{
724 struct bnx2x *bp = params->bp;
725
726 if (!CHIP_IS_E3B0(bp)) {
Joe Perches94f05b02011-08-14 12:16:20 +0000727 DP(NETIF_MSG_LINK,
728 "bnx2x_ets_e3b0_disabled the chip isn't E3B0\n");
Yaniv Rosner6c3218c2011-06-14 01:34:23 +0000729 return -EINVAL;
730 }
731
732 bnx2x_ets_e3b0_nig_disabled(params, vars);
733
734 bnx2x_ets_e3b0_pbf_disabled(params);
735
736 return 0;
737}
738
739/******************************************************************************
740* Description:
741* Disable will return basicly the values to init values.
742*.
743******************************************************************************/
744int bnx2x_ets_disabled(struct link_params *params,
745 struct link_vars *vars)
746{
747 struct bnx2x *bp = params->bp;
748 int bnx2x_status = 0;
749
750 if ((CHIP_IS_E2(bp)) || (CHIP_IS_E3A0(bp)))
751 bnx2x_ets_e2e3a0_disabled(params);
752 else if (CHIP_IS_E3B0(bp))
753 bnx2x_status = bnx2x_ets_e3b0_disabled(params, vars);
754 else {
755 DP(NETIF_MSG_LINK, "bnx2x_ets_disabled - chip not supported\n");
756 return -EINVAL;
757 }
758
759 return bnx2x_status;
760}
761
762/******************************************************************************
763* Description
764* Set the COS mappimg to SP and BW until this point all the COS are not
765* set as SP or BW.
766******************************************************************************/
767static int bnx2x_ets_e3b0_cli_map(const struct link_params *params,
768 const struct bnx2x_ets_params *ets_params,
769 const u8 cos_sp_bitmap,
770 const u8 cos_bw_bitmap)
771{
772 struct bnx2x *bp = params->bp;
773 const u8 port = params->port;
774 const u8 nig_cli_sp_bitmap = 0x7 | (cos_sp_bitmap << 3);
775 const u8 pbf_cli_sp_bitmap = cos_sp_bitmap;
776 const u8 nig_cli_subject2wfq_bitmap = cos_bw_bitmap << 3;
777 const u8 pbf_cli_subject2wfq_bitmap = cos_bw_bitmap;
778
779 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CLIENT_IS_STRICT :
780 NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, nig_cli_sp_bitmap);
781
782 REG_WR(bp, (port) ? PBF_REG_ETS_ARB_CLIENT_IS_STRICT_P1 :
783 PBF_REG_ETS_ARB_CLIENT_IS_STRICT_P0 , pbf_cli_sp_bitmap);
784
785 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CLIENT_IS_SUBJECT2WFQ :
786 NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ,
787 nig_cli_subject2wfq_bitmap);
788
789 REG_WR(bp, (port) ? PBF_REG_ETS_ARB_CLIENT_IS_SUBJECT2WFQ_P1 :
790 PBF_REG_ETS_ARB_CLIENT_IS_SUBJECT2WFQ_P0,
791 pbf_cli_subject2wfq_bitmap);
792
793 return 0;
794}
795
796/******************************************************************************
797* Description:
798* This function is needed because NIG ARB_CREDIT_WEIGHT_X are
799* not continues and ARB_CREDIT_WEIGHT_0 + offset is suitable.
800******************************************************************************/
801static int bnx2x_ets_e3b0_set_cos_bw(struct bnx2x *bp,
802 const u8 cos_entry,
803 const u32 min_w_val_nig,
804 const u32 min_w_val_pbf,
805 const u16 total_bw,
806 const u8 bw,
807 const u8 port)
808{
809 u32 nig_reg_adress_crd_weight = 0;
810 u32 pbf_reg_adress_crd_weight = 0;
David S. Miller8decf862011-09-22 03:23:13 -0400811 /* Calculate and set BW for this COS - use 1 instead of 0 for BW */
812 const u32 cos_bw_nig = ((bw ? bw : 1) * min_w_val_nig) / total_bw;
813 const u32 cos_bw_pbf = ((bw ? bw : 1) * min_w_val_pbf) / total_bw;
Yaniv Rosner6c3218c2011-06-14 01:34:23 +0000814
815 switch (cos_entry) {
816 case 0:
817 nig_reg_adress_crd_weight =
818 (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_0 :
819 NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_0;
820 pbf_reg_adress_crd_weight = (port) ?
821 PBF_REG_COS0_WEIGHT_P1 : PBF_REG_COS0_WEIGHT_P0;
822 break;
823 case 1:
824 nig_reg_adress_crd_weight = (port) ?
825 NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_1 :
826 NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_1;
827 pbf_reg_adress_crd_weight = (port) ?
828 PBF_REG_COS1_WEIGHT_P1 : PBF_REG_COS1_WEIGHT_P0;
829 break;
830 case 2:
831 nig_reg_adress_crd_weight = (port) ?
832 NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_2 :
833 NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_2;
834
835 pbf_reg_adress_crd_weight = (port) ?
836 PBF_REG_COS2_WEIGHT_P1 : PBF_REG_COS2_WEIGHT_P0;
837 break;
838 case 3:
839 if (port)
840 return -EINVAL;
841 nig_reg_adress_crd_weight =
842 NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_3;
843 pbf_reg_adress_crd_weight =
844 PBF_REG_COS3_WEIGHT_P0;
845 break;
846 case 4:
847 if (port)
848 return -EINVAL;
849 nig_reg_adress_crd_weight =
850 NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_4;
851 pbf_reg_adress_crd_weight = PBF_REG_COS4_WEIGHT_P0;
852 break;
853 case 5:
854 if (port)
855 return -EINVAL;
856 nig_reg_adress_crd_weight =
857 NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_5;
858 pbf_reg_adress_crd_weight = PBF_REG_COS5_WEIGHT_P0;
859 break;
860 }
861
862 REG_WR(bp, nig_reg_adress_crd_weight, cos_bw_nig);
863
864 REG_WR(bp, pbf_reg_adress_crd_weight, cos_bw_pbf);
865
866 return 0;
867}
868/******************************************************************************
869* Description:
870* Calculate the total BW.A value of 0 isn't legal.
871*.
872******************************************************************************/
873static int bnx2x_ets_e3b0_get_total_bw(
874 const struct link_params *params,
Yaniv Rosner870516e2011-11-28 00:49:46 +0000875 struct bnx2x_ets_params *ets_params,
Yaniv Rosner6c3218c2011-06-14 01:34:23 +0000876 u16 *total_bw)
877{
878 struct bnx2x *bp = params->bp;
879 u8 cos_idx = 0;
Yaniv Rosner870516e2011-11-28 00:49:46 +0000880 u8 is_bw_cos_exist = 0;
Yaniv Rosner6c3218c2011-06-14 01:34:23 +0000881
882 *total_bw = 0 ;
Yaniv Rosner870516e2011-11-28 00:49:46 +0000883
Yaniv Rosner6c3218c2011-06-14 01:34:23 +0000884 /* Calculate total BW requested */
885 for (cos_idx = 0; cos_idx < ets_params->num_of_cos; cos_idx++) {
Yaniv Rosnerde0396f2011-11-28 00:49:53 +0000886 if (ets_params->cos[cos_idx].state == bnx2x_cos_state_bw) {
Yaniv Rosner870516e2011-11-28 00:49:46 +0000887 is_bw_cos_exist = 1;
888 if (!ets_params->cos[cos_idx].params.bw_params.bw) {
889 DP(NETIF_MSG_LINK, "bnx2x_ets_E3B0_config BW"
890 "was set to 0\n");
891 /*
892 * This is to prevent a state when ramrods
893 * can't be sent
894 */
895 ets_params->cos[cos_idx].params.bw_params.bw
896 = 1;
897 }
David S. Miller8decf862011-09-22 03:23:13 -0400898 *total_bw +=
899 ets_params->cos[cos_idx].params.bw_params.bw;
Yaniv Rosner6c3218c2011-06-14 01:34:23 +0000900 }
Yaniv Rosner6c3218c2011-06-14 01:34:23 +0000901 }
902
David S. Miller8decf862011-09-22 03:23:13 -0400903 /* Check total BW is valid */
Yaniv Rosnerde0396f2011-11-28 00:49:53 +0000904 if ((is_bw_cos_exist == 1) && (*total_bw != 100)) {
905 if (*total_bw == 0) {
Joe Perches94f05b02011-08-14 12:16:20 +0000906 DP(NETIF_MSG_LINK,
Yaniv Rosner2f751a82011-11-28 00:49:52 +0000907 "bnx2x_ets_E3B0_config total BW shouldn't be 0\n");
Yaniv Rosner6c3218c2011-06-14 01:34:23 +0000908 return -EINVAL;
909 }
Joe Perches94f05b02011-08-14 12:16:20 +0000910 DP(NETIF_MSG_LINK,
Yaniv Rosner2f751a82011-11-28 00:49:52 +0000911 "bnx2x_ets_E3B0_config total BW should be 100\n");
912 /*
913 * We can handle a case whre the BW isn't 100 this can happen
914 * if the TC are joined.
915 */
Yaniv Rosner6c3218c2011-06-14 01:34:23 +0000916 }
917 return 0;
918}
919
920/******************************************************************************
921* Description:
922* Invalidate all the sp_pri_to_cos.
923*.
924******************************************************************************/
925static void bnx2x_ets_e3b0_sp_pri_to_cos_init(u8 *sp_pri_to_cos)
926{
927 u8 pri = 0;
928 for (pri = 0; pri < DCBX_MAX_NUM_COS; pri++)
929 sp_pri_to_cos[pri] = DCBX_INVALID_COS;
930}
931/******************************************************************************
932* Description:
933* Calculate and set the SP (ARB_PRIORITY_CLIENT) NIG and PBF registers
934* according to sp_pri_to_cos.
935*.
936******************************************************************************/
937static int bnx2x_ets_e3b0_sp_pri_to_cos_set(const struct link_params *params,
938 u8 *sp_pri_to_cos, const u8 pri,
939 const u8 cos_entry)
940{
941 struct bnx2x *bp = params->bp;
942 const u8 port = params->port;
943 const u8 max_num_of_cos = (port) ? DCBX_E3B0_MAX_NUM_COS_PORT1 :
944 DCBX_E3B0_MAX_NUM_COS_PORT0;
945
Yaniv Rosnerde0396f2011-11-28 00:49:53 +0000946 if (sp_pri_to_cos[pri] != DCBX_INVALID_COS) {
Yaniv Rosner6c3218c2011-06-14 01:34:23 +0000947 DP(NETIF_MSG_LINK, "bnx2x_ets_e3b0_sp_pri_to_cos_set invalid "
Joe Perches94f05b02011-08-14 12:16:20 +0000948 "parameter There can't be two COS's with "
Yaniv Rosner6c3218c2011-06-14 01:34:23 +0000949 "the same strict pri\n");
950 return -EINVAL;
951 }
952
953 if (pri > max_num_of_cos) {
Joe Perches94f05b02011-08-14 12:16:20 +0000954 DP(NETIF_MSG_LINK, "bnx2x_ets_e3b0_sp_pri_to_cos_set invalid "
Yaniv Rosner2f751a82011-11-28 00:49:52 +0000955 "parameter Illegal strict priority\n");
Yaniv Rosner6c3218c2011-06-14 01:34:23 +0000956 return -EINVAL;
957 }
958
959 sp_pri_to_cos[pri] = cos_entry;
960 return 0;
961
962}
963
964/******************************************************************************
965* Description:
966* Returns the correct value according to COS and priority in
967* the sp_pri_cli register.
968*.
969******************************************************************************/
970static u64 bnx2x_e3b0_sp_get_pri_cli_reg(const u8 cos, const u8 cos_offset,
971 const u8 pri_set,
972 const u8 pri_offset,
973 const u8 entry_size)
974{
975 u64 pri_cli_nig = 0;
976 pri_cli_nig = ((u64)(cos + cos_offset)) << (entry_size *
977 (pri_set + pri_offset));
978
979 return pri_cli_nig;
980}
981/******************************************************************************
982* Description:
983* Returns the correct value according to COS and priority in the
984* sp_pri_cli register for NIG.
985*.
986******************************************************************************/
987static u64 bnx2x_e3b0_sp_get_pri_cli_reg_nig(const u8 cos, const u8 pri_set)
988{
989 /* MCP Dbg0 and dbg1 are always with higher strict pri*/
990 const u8 nig_cos_offset = 3;
991 const u8 nig_pri_offset = 3;
992
993 return bnx2x_e3b0_sp_get_pri_cli_reg(cos, nig_cos_offset, pri_set,
994 nig_pri_offset, 4);
995
996}
997/******************************************************************************
998* Description:
999* Returns the correct value according to COS and priority in the
1000* sp_pri_cli register for PBF.
1001*.
1002******************************************************************************/
1003static u64 bnx2x_e3b0_sp_get_pri_cli_reg_pbf(const u8 cos, const u8 pri_set)
1004{
1005 const u8 pbf_cos_offset = 0;
1006 const u8 pbf_pri_offset = 0;
1007
1008 return bnx2x_e3b0_sp_get_pri_cli_reg(cos, pbf_cos_offset, pri_set,
1009 pbf_pri_offset, 3);
1010
1011}
1012
1013/******************************************************************************
1014* Description:
1015* Calculate and set the SP (ARB_PRIORITY_CLIENT) NIG and PBF registers
1016* according to sp_pri_to_cos.(which COS has higher priority)
1017*.
1018******************************************************************************/
1019static int bnx2x_ets_e3b0_sp_set_pri_cli_reg(const struct link_params *params,
1020 u8 *sp_pri_to_cos)
1021{
1022 struct bnx2x *bp = params->bp;
1023 u8 i = 0;
1024 const u8 port = params->port;
1025 /* MCP Dbg0 and dbg1 are always with higher strict pri*/
1026 u64 pri_cli_nig = 0x210;
1027 u32 pri_cli_pbf = 0x0;
1028 u8 pri_set = 0;
1029 u8 pri_bitmask = 0;
1030 const u8 max_num_of_cos = (port) ? DCBX_E3B0_MAX_NUM_COS_PORT1 :
1031 DCBX_E3B0_MAX_NUM_COS_PORT0;
1032
1033 u8 cos_bit_to_set = (1 << max_num_of_cos) - 1;
1034
1035 /* Set all the strict priority first */
1036 for (i = 0; i < max_num_of_cos; i++) {
Yaniv Rosnerde0396f2011-11-28 00:49:53 +00001037 if (sp_pri_to_cos[i] != DCBX_INVALID_COS) {
1038 if (sp_pri_to_cos[i] >= DCBX_MAX_NUM_COS) {
Yaniv Rosner6c3218c2011-06-14 01:34:23 +00001039 DP(NETIF_MSG_LINK,
1040 "bnx2x_ets_e3b0_sp_set_pri_cli_reg "
1041 "invalid cos entry\n");
1042 return -EINVAL;
1043 }
1044
1045 pri_cli_nig |= bnx2x_e3b0_sp_get_pri_cli_reg_nig(
1046 sp_pri_to_cos[i], pri_set);
1047
1048 pri_cli_pbf |= bnx2x_e3b0_sp_get_pri_cli_reg_pbf(
1049 sp_pri_to_cos[i], pri_set);
1050 pri_bitmask = 1 << sp_pri_to_cos[i];
1051 /* COS is used remove it from bitmap.*/
Yaniv Rosnerde0396f2011-11-28 00:49:53 +00001052 if (!(pri_bitmask & cos_bit_to_set)) {
Yaniv Rosner6c3218c2011-06-14 01:34:23 +00001053 DP(NETIF_MSG_LINK,
1054 "bnx2x_ets_e3b0_sp_set_pri_cli_reg "
1055 "invalid There can't be two COS's with"
1056 " the same strict pri\n");
1057 return -EINVAL;
1058 }
1059 cos_bit_to_set &= ~pri_bitmask;
1060 pri_set++;
1061 }
1062 }
1063
1064 /* Set all the Non strict priority i= COS*/
1065 for (i = 0; i < max_num_of_cos; i++) {
1066 pri_bitmask = 1 << i;
1067 /* Check if COS was already used for SP */
1068 if (pri_bitmask & cos_bit_to_set) {
1069 /* COS wasn't used for SP */
1070 pri_cli_nig |= bnx2x_e3b0_sp_get_pri_cli_reg_nig(
1071 i, pri_set);
1072
1073 pri_cli_pbf |= bnx2x_e3b0_sp_get_pri_cli_reg_pbf(
1074 i, pri_set);
1075 /* COS is used remove it from bitmap.*/
1076 cos_bit_to_set &= ~pri_bitmask;
1077 pri_set++;
1078 }
1079 }
1080
1081 if (pri_set != max_num_of_cos) {
1082 DP(NETIF_MSG_LINK, "bnx2x_ets_e3b0_sp_set_pri_cli_reg not all "
1083 "entries were set\n");
1084 return -EINVAL;
1085 }
1086
1087 if (port) {
1088 /* Only 6 usable clients*/
1089 REG_WR(bp, NIG_REG_P1_TX_ARB_PRIORITY_CLIENT2_LSB,
1090 (u32)pri_cli_nig);
1091
1092 REG_WR(bp, PBF_REG_ETS_ARB_PRIORITY_CLIENT_P1 , pri_cli_pbf);
1093 } else {
1094 /* Only 9 usable clients*/
1095 const u32 pri_cli_nig_lsb = (u32) (pri_cli_nig);
1096 const u32 pri_cli_nig_msb = (u32) ((pri_cli_nig >> 32) & 0xF);
1097
1098 REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT2_LSB,
1099 pri_cli_nig_lsb);
1100 REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT2_MSB,
1101 pri_cli_nig_msb);
1102
1103 REG_WR(bp, PBF_REG_ETS_ARB_PRIORITY_CLIENT_P0 , pri_cli_pbf);
1104 }
1105 return 0;
1106}
1107
1108/******************************************************************************
1109* Description:
1110* Configure the COS to ETS according to BW and SP settings.
1111******************************************************************************/
1112int bnx2x_ets_e3b0_config(const struct link_params *params,
1113 const struct link_vars *vars,
Yaniv Rosner870516e2011-11-28 00:49:46 +00001114 struct bnx2x_ets_params *ets_params)
Yaniv Rosner6c3218c2011-06-14 01:34:23 +00001115{
1116 struct bnx2x *bp = params->bp;
1117 int bnx2x_status = 0;
1118 const u8 port = params->port;
1119 u16 total_bw = 0;
1120 const u32 min_w_val_nig = bnx2x_ets_get_min_w_val_nig(vars);
1121 const u32 min_w_val_pbf = ETS_E3B0_PBF_MIN_W_VAL;
1122 u8 cos_bw_bitmap = 0;
1123 u8 cos_sp_bitmap = 0;
1124 u8 sp_pri_to_cos[DCBX_MAX_NUM_COS] = {0};
1125 const u8 max_num_of_cos = (port) ? DCBX_E3B0_MAX_NUM_COS_PORT1 :
1126 DCBX_E3B0_MAX_NUM_COS_PORT0;
1127 u8 cos_entry = 0;
1128
1129 if (!CHIP_IS_E3B0(bp)) {
Joe Perches94f05b02011-08-14 12:16:20 +00001130 DP(NETIF_MSG_LINK,
1131 "bnx2x_ets_e3b0_disabled the chip isn't E3B0\n");
Yaniv Rosner6c3218c2011-06-14 01:34:23 +00001132 return -EINVAL;
1133 }
1134
1135 if ((ets_params->num_of_cos > max_num_of_cos)) {
1136 DP(NETIF_MSG_LINK, "bnx2x_ets_E3B0_config the number of COS "
1137 "isn't supported\n");
1138 return -EINVAL;
1139 }
1140
1141 /* Prepare sp strict priority parameters*/
1142 bnx2x_ets_e3b0_sp_pri_to_cos_init(sp_pri_to_cos);
1143
1144 /* Prepare BW parameters*/
1145 bnx2x_status = bnx2x_ets_e3b0_get_total_bw(params, ets_params,
1146 &total_bw);
Yaniv Rosnerde0396f2011-11-28 00:49:53 +00001147 if (bnx2x_status) {
Joe Perches94f05b02011-08-14 12:16:20 +00001148 DP(NETIF_MSG_LINK,
1149 "bnx2x_ets_E3B0_config get_total_bw failed\n");
Yaniv Rosner6c3218c2011-06-14 01:34:23 +00001150 return -EINVAL;
1151 }
1152
Yaniv Rosner2f751a82011-11-28 00:49:52 +00001153 /*
1154 * Upper bound is set according to current link speed (min_w_val
1155 * should be the same for upper bound and COS credit val).
Yaniv Rosner6c3218c2011-06-14 01:34:23 +00001156 */
1157 bnx2x_ets_e3b0_set_credit_upper_bound_nig(params, min_w_val_nig);
1158 bnx2x_ets_e3b0_set_credit_upper_bound_pbf(params, min_w_val_pbf);
1159
1160
1161 for (cos_entry = 0; cos_entry < ets_params->num_of_cos; cos_entry++) {
1162 if (bnx2x_cos_state_bw == ets_params->cos[cos_entry].state) {
1163 cos_bw_bitmap |= (1 << cos_entry);
Yaniv Rosner2f751a82011-11-28 00:49:52 +00001164 /*
Yaniv Rosner6c3218c2011-06-14 01:34:23 +00001165 * The function also sets the BW in HW(not the mappin
1166 * yet)
1167 */
1168 bnx2x_status = bnx2x_ets_e3b0_set_cos_bw(
1169 bp, cos_entry, min_w_val_nig, min_w_val_pbf,
1170 total_bw,
1171 ets_params->cos[cos_entry].params.bw_params.bw,
1172 port);
1173 } else if (bnx2x_cos_state_strict ==
1174 ets_params->cos[cos_entry].state){
1175 cos_sp_bitmap |= (1 << cos_entry);
1176
1177 bnx2x_status = bnx2x_ets_e3b0_sp_pri_to_cos_set(
1178 params,
1179 sp_pri_to_cos,
1180 ets_params->cos[cos_entry].params.sp_params.pri,
1181 cos_entry);
1182
1183 } else {
Joe Perches94f05b02011-08-14 12:16:20 +00001184 DP(NETIF_MSG_LINK,
1185 "bnx2x_ets_e3b0_config cos state not valid\n");
Yaniv Rosner6c3218c2011-06-14 01:34:23 +00001186 return -EINVAL;
1187 }
Yaniv Rosnerde0396f2011-11-28 00:49:53 +00001188 if (bnx2x_status) {
Joe Perches94f05b02011-08-14 12:16:20 +00001189 DP(NETIF_MSG_LINK,
1190 "bnx2x_ets_e3b0_config set cos bw failed\n");
Yaniv Rosner6c3218c2011-06-14 01:34:23 +00001191 return bnx2x_status;
1192 }
1193 }
1194
1195 /* Set SP register (which COS has higher priority) */
1196 bnx2x_status = bnx2x_ets_e3b0_sp_set_pri_cli_reg(params,
1197 sp_pri_to_cos);
1198
Yaniv Rosnerde0396f2011-11-28 00:49:53 +00001199 if (bnx2x_status) {
Joe Perches94f05b02011-08-14 12:16:20 +00001200 DP(NETIF_MSG_LINK,
1201 "bnx2x_ets_E3B0_config set_pri_cli_reg failed\n");
Yaniv Rosner6c3218c2011-06-14 01:34:23 +00001202 return bnx2x_status;
1203 }
1204
1205 /* Set client mapping of BW and strict */
1206 bnx2x_status = bnx2x_ets_e3b0_cli_map(params, ets_params,
1207 cos_sp_bitmap,
1208 cos_bw_bitmap);
1209
Yaniv Rosnerde0396f2011-11-28 00:49:53 +00001210 if (bnx2x_status) {
Yaniv Rosner6c3218c2011-06-14 01:34:23 +00001211 DP(NETIF_MSG_LINK, "bnx2x_ets_E3B0_config SP failed\n");
1212 return bnx2x_status;
1213 }
1214 return 0;
1215}
Yaniv Rosner65a001b2011-01-31 04:22:03 +00001216static void bnx2x_ets_bw_limit_common(const struct link_params *params)
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001217{
1218 /* ETS disabled configuration */
1219 struct bnx2x *bp = params->bp;
1220 DP(NETIF_MSG_LINK, "ETS enabled BW limit configuration\n");
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001221 /*
1222 * defines which entries (clients) are subjected to WFQ arbitration
1223 * COS0 0x8
1224 * COS1 0x10
1225 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001226 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ, 0x18);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001227 /*
1228 * mapping between the ARB_CREDIT_WEIGHT registers and actual
1229 * client numbers (WEIGHT_0 does not actually have to represent
1230 * client 0)
1231 * PRI4 | PRI3 | PRI2 | PRI1 | PRI0
1232 * cos1-001 cos0-000 dbg1-100 dbg0-011 MCP-010
1233 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001234 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP, 0x111A);
1235
1236 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_0,
1237 ETS_BW_LIMIT_CREDIT_UPPER_BOUND);
1238 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_1,
1239 ETS_BW_LIMIT_CREDIT_UPPER_BOUND);
1240
1241 /* ETS mode enabled*/
1242 REG_WR(bp, PBF_REG_ETS_ENABLED, 1);
1243
1244 /* Defines the number of consecutive slots for the strict priority */
1245 REG_WR(bp, PBF_REG_NUM_STRICT_ARB_SLOTS, 0);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001246 /*
1247 * Bitmap of 5bits length. Each bit specifies whether the entry behaves
1248 * as strict. Bits 0,1,2 - debug and management entries, 3 - COS0
1249 * entry, 4 - COS1 entry.
1250 * COS1 | COS0 | DEBUG21 | DEBUG0 | MGMT
1251 * bit4 bit3 bit2 bit1 bit0
1252 * MCP and debug are strict
1253 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001254 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x7);
1255
1256 /* Upper bound that COS0_WEIGHT can reach in the WFQ arbiter.*/
1257 REG_WR(bp, PBF_REG_COS0_UPPER_BOUND,
1258 ETS_BW_LIMIT_CREDIT_UPPER_BOUND);
1259 REG_WR(bp, PBF_REG_COS1_UPPER_BOUND,
1260 ETS_BW_LIMIT_CREDIT_UPPER_BOUND);
1261}
1262
1263void bnx2x_ets_bw_limit(const struct link_params *params, const u32 cos0_bw,
1264 const u32 cos1_bw)
1265{
1266 /* ETS disabled configuration*/
1267 struct bnx2x *bp = params->bp;
1268 const u32 total_bw = cos0_bw + cos1_bw;
1269 u32 cos0_credit_weight = 0;
1270 u32 cos1_credit_weight = 0;
1271
1272 DP(NETIF_MSG_LINK, "ETS enabled BW limit configuration\n");
1273
Yaniv Rosnerde0396f2011-11-28 00:49:53 +00001274 if ((!total_bw) ||
1275 (!cos0_bw) ||
1276 (!cos1_bw)) {
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001277 DP(NETIF_MSG_LINK, "Total BW can't be zero\n");
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001278 return;
1279 }
1280
1281 cos0_credit_weight = (cos0_bw * ETS_BW_LIMIT_CREDIT_WEIGHT)/
1282 total_bw;
1283 cos1_credit_weight = (cos1_bw * ETS_BW_LIMIT_CREDIT_WEIGHT)/
1284 total_bw;
1285
1286 bnx2x_ets_bw_limit_common(params);
1287
1288 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_0, cos0_credit_weight);
1289 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_1, cos1_credit_weight);
1290
1291 REG_WR(bp, PBF_REG_COS0_WEIGHT, cos0_credit_weight);
1292 REG_WR(bp, PBF_REG_COS1_WEIGHT, cos1_credit_weight);
1293}
1294
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00001295int bnx2x_ets_strict(const struct link_params *params, const u8 strict_cos)
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001296{
1297 /* ETS disabled configuration*/
1298 struct bnx2x *bp = params->bp;
1299 u32 val = 0;
1300
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001301 DP(NETIF_MSG_LINK, "ETS enabled strict configuration\n");
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001302 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001303 * Bitmap of 5bits length. Each bit specifies whether the entry behaves
1304 * as strict. Bits 0,1,2 - debug and management entries,
1305 * 3 - COS0 entry, 4 - COS1 entry.
1306 * COS1 | COS0 | DEBUG21 | DEBUG0 | MGMT
1307 * bit4 bit3 bit2 bit1 bit0
1308 * MCP and debug are strict
1309 */
1310 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x1F);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001311 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001312 * For strict priority entries defines the number of consecutive slots
1313 * for the highest priority.
1314 */
1315 REG_WR(bp, NIG_REG_P0_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100);
1316 /* ETS mode disable */
1317 REG_WR(bp, PBF_REG_ETS_ENABLED, 0);
1318 /* Defines the number of consecutive slots for the strict priority */
1319 REG_WR(bp, PBF_REG_NUM_STRICT_ARB_SLOTS, 0x100);
1320
1321 /* Defines the number of consecutive slots for the strict priority */
1322 REG_WR(bp, PBF_REG_HIGH_PRIORITY_COS_NUM, strict_cos);
1323
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001324 /*
1325 * mapping between entry priority to client number (0,1,2 -debug and
1326 * management clients, 3 - COS0 client, 4 - COS client)(HIGHEST)
1327 * 3bits client num.
1328 * PRI4 | PRI3 | PRI2 | PRI1 | PRI0
1329 * dbg0-010 dbg1-001 cos1-100 cos0-011 MCP-000
1330 * dbg0-010 dbg1-001 cos0-011 cos1-100 MCP-000
1331 */
Yaniv Rosnerde0396f2011-11-28 00:49:53 +00001332 val = (!strict_cos) ? 0x2318 : 0x22E0;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001333 REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT, val);
1334
1335 return 0;
1336}
1337/******************************************************************/
Dmitry Kravkove8920672011-05-04 23:52:40 +00001338/* PFC section */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001339/******************************************************************/
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001340static void bnx2x_update_pfc_xmac(struct link_params *params,
1341 struct link_vars *vars,
1342 u8 is_lb)
1343{
1344 struct bnx2x *bp = params->bp;
1345 u32 xmac_base;
1346 u32 pause_val, pfc0_val, pfc1_val;
1347
1348 /* XMAC base adrr */
1349 xmac_base = (params->port) ? GRCBASE_XMAC1 : GRCBASE_XMAC0;
1350
1351 /* Initialize pause and pfc registers */
1352 pause_val = 0x18000;
1353 pfc0_val = 0xFFFF8000;
1354 pfc1_val = 0x2;
1355
1356 /* No PFC support */
1357 if (!(params->feature_config_flags &
1358 FEATURE_CONFIG_PFC_ENABLED)) {
1359
1360 /*
1361 * RX flow control - Process pause frame in receive direction
1362 */
1363 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
1364 pause_val |= XMAC_PAUSE_CTRL_REG_RX_PAUSE_EN;
1365
1366 /*
1367 * TX flow control - Send pause packet when buffer is full
1368 */
1369 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
1370 pause_val |= XMAC_PAUSE_CTRL_REG_TX_PAUSE_EN;
1371 } else {/* PFC support */
1372 pfc1_val |= XMAC_PFC_CTRL_HI_REG_PFC_REFRESH_EN |
1373 XMAC_PFC_CTRL_HI_REG_PFC_STATS_EN |
1374 XMAC_PFC_CTRL_HI_REG_RX_PFC_EN |
1375 XMAC_PFC_CTRL_HI_REG_TX_PFC_EN;
1376 }
1377
1378 /* Write pause and PFC registers */
1379 REG_WR(bp, xmac_base + XMAC_REG_PAUSE_CTRL, pause_val);
1380 REG_WR(bp, xmac_base + XMAC_REG_PFC_CTRL, pfc0_val);
1381 REG_WR(bp, xmac_base + XMAC_REG_PFC_CTRL_HI, pfc1_val);
1382
Yaniv Rosnerb8d6d082011-07-05 01:06:27 +00001383
1384 /* Set MAC address for source TX Pause/PFC frames */
1385 REG_WR(bp, xmac_base + XMAC_REG_CTRL_SA_LO,
1386 ((params->mac_addr[2] << 24) |
1387 (params->mac_addr[3] << 16) |
1388 (params->mac_addr[4] << 8) |
1389 (params->mac_addr[5])));
1390 REG_WR(bp, xmac_base + XMAC_REG_CTRL_SA_HI,
1391 ((params->mac_addr[0] << 8) |
1392 (params->mac_addr[1])));
1393
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001394 udelay(30);
1395}
1396
1397
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001398static void bnx2x_emac_get_pfc_stat(struct link_params *params,
1399 u32 pfc_frames_sent[2],
1400 u32 pfc_frames_received[2])
1401{
1402 /* Read pfc statistic */
1403 struct bnx2x *bp = params->bp;
1404 u32 emac_base = params->port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
1405 u32 val_xon = 0;
1406 u32 val_xoff = 0;
1407
1408 DP(NETIF_MSG_LINK, "pfc statistic read from EMAC\n");
1409
1410 /* PFC received frames */
1411 val_xoff = REG_RD(bp, emac_base +
1412 EMAC_REG_RX_PFC_STATS_XOFF_RCVD);
1413 val_xoff &= EMAC_REG_RX_PFC_STATS_XOFF_RCVD_COUNT;
1414 val_xon = REG_RD(bp, emac_base + EMAC_REG_RX_PFC_STATS_XON_RCVD);
1415 val_xon &= EMAC_REG_RX_PFC_STATS_XON_RCVD_COUNT;
1416
1417 pfc_frames_received[0] = val_xon + val_xoff;
1418
1419 /* PFC received sent */
1420 val_xoff = REG_RD(bp, emac_base +
1421 EMAC_REG_RX_PFC_STATS_XOFF_SENT);
1422 val_xoff &= EMAC_REG_RX_PFC_STATS_XOFF_SENT_COUNT;
1423 val_xon = REG_RD(bp, emac_base + EMAC_REG_RX_PFC_STATS_XON_SENT);
1424 val_xon &= EMAC_REG_RX_PFC_STATS_XON_SENT_COUNT;
1425
1426 pfc_frames_sent[0] = val_xon + val_xoff;
1427}
1428
Yaniv Rosnerb8d6d082011-07-05 01:06:27 +00001429/* Read pfc statistic*/
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001430void bnx2x_pfc_statistic(struct link_params *params, struct link_vars *vars,
1431 u32 pfc_frames_sent[2],
1432 u32 pfc_frames_received[2])
1433{
1434 /* Read pfc statistic */
1435 struct bnx2x *bp = params->bp;
Yaniv Rosnerb8d6d082011-07-05 01:06:27 +00001436
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001437 DP(NETIF_MSG_LINK, "pfc statistic\n");
1438
1439 if (!vars->link_up)
1440 return;
1441
Yaniv Rosnerde0396f2011-11-28 00:49:53 +00001442 if (vars->mac_type == MAC_TYPE_EMAC) {
Yaniv Rosnerb8d6d082011-07-05 01:06:27 +00001443 DP(NETIF_MSG_LINK, "About to read PFC stats from EMAC\n");
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001444 bnx2x_emac_get_pfc_stat(params, pfc_frames_sent,
1445 pfc_frames_received);
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001446 }
1447}
1448/******************************************************************/
1449/* MAC/PBF section */
1450/******************************************************************/
Yaniv Rosnera198c142011-05-31 21:29:42 +00001451static void bnx2x_set_mdio_clk(struct bnx2x *bp, u32 chip_id, u8 port)
1452{
1453 u32 mode, emac_base;
1454 /**
1455 * Set clause 45 mode, slow down the MDIO clock to 2.5MHz
1456 * (a value of 49==0x31) and make sure that the AUTO poll is off
1457 */
1458
1459 if (CHIP_IS_E2(bp))
1460 emac_base = GRCBASE_EMAC0;
1461 else
1462 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
1463 mode = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
1464 mode &= ~(EMAC_MDIO_MODE_AUTO_POLL |
1465 EMAC_MDIO_MODE_CLOCK_CNT);
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00001466 if (USES_WARPCORE(bp))
1467 mode |= (74L << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT);
1468 else
1469 mode |= (49L << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT);
Yaniv Rosnera198c142011-05-31 21:29:42 +00001470
1471 mode |= (EMAC_MDIO_MODE_CLAUSE_45);
1472 REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE, mode);
1473
1474 udelay(40);
1475}
Yaniv Rosner2f751a82011-11-28 00:49:52 +00001476static u8 bnx2x_is_4_port_mode(struct bnx2x *bp)
1477{
1478 u32 port4mode_ovwr_val;
1479 /* Check 4-port override enabled */
1480 port4mode_ovwr_val = REG_RD(bp, MISC_REG_PORT4MODE_EN_OVWR);
1481 if (port4mode_ovwr_val & (1<<0)) {
1482 /* Return 4-port mode override value */
1483 return ((port4mode_ovwr_val & (1<<1)) == (1<<1));
1484 }
1485 /* Return 4-port mode from input pin */
1486 return (u8)REG_RD(bp, MISC_REG_PORT4MODE_EN);
1487}
Yaniv Rosnera198c142011-05-31 21:29:42 +00001488
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001489static void bnx2x_emac_init(struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001490 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001491{
1492 /* reset and unreset the emac core */
1493 struct bnx2x *bp = params->bp;
1494 u8 port = params->port;
1495 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
1496 u32 val;
1497 u16 timeout;
1498
1499 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001500 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001501 udelay(5);
1502 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001503 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001504
1505 /* init emac - use read-modify-write */
1506 /* self clear reset */
1507 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
Eilon Greenstein3196a882008-08-13 15:58:49 -07001508 EMAC_WR(bp, EMAC_REG_EMAC_MODE, (val | EMAC_MODE_RESET));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001509
1510 timeout = 200;
Eilon Greenstein3196a882008-08-13 15:58:49 -07001511 do {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001512 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
1513 DP(NETIF_MSG_LINK, "EMAC reset reg is %u\n", val);
1514 if (!timeout) {
1515 DP(NETIF_MSG_LINK, "EMAC timeout!\n");
1516 return;
1517 }
1518 timeout--;
Eilon Greenstein3196a882008-08-13 15:58:49 -07001519 } while (val & EMAC_MODE_RESET);
Yaniv Rosnera198c142011-05-31 21:29:42 +00001520 bnx2x_set_mdio_clk(bp, params->chip_id, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001521 /* Set mac address */
1522 val = ((params->mac_addr[0] << 8) |
1523 params->mac_addr[1]);
Eilon Greenstein3196a882008-08-13 15:58:49 -07001524 EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001525
1526 val = ((params->mac_addr[2] << 24) |
1527 (params->mac_addr[3] << 16) |
1528 (params->mac_addr[4] << 8) |
1529 params->mac_addr[5]);
Eilon Greenstein3196a882008-08-13 15:58:49 -07001530 EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH + 4, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001531}
1532
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001533static void bnx2x_set_xumac_nig(struct link_params *params,
1534 u16 tx_pause_en,
1535 u8 enable)
1536{
1537 struct bnx2x *bp = params->bp;
1538
1539 REG_WR(bp, params->port ? NIG_REG_P1_MAC_IN_EN : NIG_REG_P0_MAC_IN_EN,
1540 enable);
1541 REG_WR(bp, params->port ? NIG_REG_P1_MAC_OUT_EN : NIG_REG_P0_MAC_OUT_EN,
1542 enable);
1543 REG_WR(bp, params->port ? NIG_REG_P1_MAC_PAUSE_OUT_EN :
1544 NIG_REG_P0_MAC_PAUSE_OUT_EN, tx_pause_en);
1545}
1546
Yaniv Rosnerce7c0482011-10-27 05:09:47 +00001547static void bnx2x_umac_disable(struct link_params *params)
1548{
1549 u32 umac_base = params->port ? GRCBASE_UMAC1 : GRCBASE_UMAC0;
1550 struct bnx2x *bp = params->bp;
1551 if (!(REG_RD(bp, MISC_REG_RESET_REG_2) &
1552 (MISC_REGISTERS_RESET_REG_2_UMAC0 << params->port)))
1553 return;
1554
1555 /* Disable RX and TX */
1556 REG_WR(bp, umac_base + UMAC_REG_COMMAND_CONFIG, 0);
1557}
1558
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001559static void bnx2x_umac_enable(struct link_params *params,
1560 struct link_vars *vars, u8 lb)
1561{
1562 u32 val;
1563 u32 umac_base = params->port ? GRCBASE_UMAC1 : GRCBASE_UMAC0;
1564 struct bnx2x *bp = params->bp;
1565 /* Reset UMAC */
1566 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
1567 (MISC_REGISTERS_RESET_REG_2_UMAC0 << params->port));
1568 usleep_range(1000, 1000);
1569
1570 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
1571 (MISC_REGISTERS_RESET_REG_2_UMAC0 << params->port));
1572
1573 DP(NETIF_MSG_LINK, "enabling UMAC\n");
1574
1575 /**
1576 * This register determines on which events the MAC will assert
1577 * error on the i/f to the NIG along w/ EOP.
1578 */
1579
1580 /**
1581 * BD REG_WR(bp, NIG_REG_P0_MAC_RSV_ERR_MASK +
1582 * params->port*0x14, 0xfffff.
1583 */
1584 /* This register opens the gate for the UMAC despite its name */
1585 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + params->port*4, 1);
1586
1587 val = UMAC_COMMAND_CONFIG_REG_PROMIS_EN |
1588 UMAC_COMMAND_CONFIG_REG_PAD_EN |
1589 UMAC_COMMAND_CONFIG_REG_SW_RESET |
1590 UMAC_COMMAND_CONFIG_REG_NO_LGTH_CHECK;
1591 switch (vars->line_speed) {
1592 case SPEED_10:
1593 val |= (0<<2);
1594 break;
1595 case SPEED_100:
1596 val |= (1<<2);
1597 break;
1598 case SPEED_1000:
1599 val |= (2<<2);
1600 break;
1601 case SPEED_2500:
1602 val |= (3<<2);
1603 break;
1604 default:
1605 DP(NETIF_MSG_LINK, "Invalid speed for UMAC %d\n",
1606 vars->line_speed);
1607 break;
1608 }
Yaniv Rosner9d5b36b2011-08-02 22:59:10 +00001609 if (!(vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
1610 val |= UMAC_COMMAND_CONFIG_REG_IGNORE_TX_PAUSE;
1611
1612 if (!(vars->flow_ctrl & BNX2X_FLOW_CTRL_RX))
1613 val |= UMAC_COMMAND_CONFIG_REG_PAUSE_IGNORE;
1614
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001615 REG_WR(bp, umac_base + UMAC_REG_COMMAND_CONFIG, val);
1616 udelay(50);
1617
Yaniv Rosnerb8d6d082011-07-05 01:06:27 +00001618 /* Set MAC address for source TX Pause/PFC frames (under SW reset) */
1619 REG_WR(bp, umac_base + UMAC_REG_MAC_ADDR0,
1620 ((params->mac_addr[2] << 24) |
1621 (params->mac_addr[3] << 16) |
1622 (params->mac_addr[4] << 8) |
1623 (params->mac_addr[5])));
1624 REG_WR(bp, umac_base + UMAC_REG_MAC_ADDR1,
1625 ((params->mac_addr[0] << 8) |
1626 (params->mac_addr[1])));
1627
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001628 /* Enable RX and TX */
1629 val &= ~UMAC_COMMAND_CONFIG_REG_PAD_EN;
1630 val |= UMAC_COMMAND_CONFIG_REG_TX_ENA |
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00001631 UMAC_COMMAND_CONFIG_REG_RX_ENA;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001632 REG_WR(bp, umac_base + UMAC_REG_COMMAND_CONFIG, val);
1633 udelay(50);
1634
1635 /* Remove SW Reset */
1636 val &= ~UMAC_COMMAND_CONFIG_REG_SW_RESET;
1637
1638 /* Check loopback mode */
1639 if (lb)
1640 val |= UMAC_COMMAND_CONFIG_REG_LOOP_ENA;
1641 REG_WR(bp, umac_base + UMAC_REG_COMMAND_CONFIG, val);
1642
1643 /*
1644 * Maximum Frame Length (RW). Defines a 14-Bit maximum frame
1645 * length used by the MAC receive logic to check frames.
1646 */
1647 REG_WR(bp, umac_base + UMAC_REG_MAXFR, 0x2710);
1648 bnx2x_set_xumac_nig(params,
1649 ((vars->flow_ctrl & BNX2X_FLOW_CTRL_TX) != 0), 1);
1650 vars->mac_type = MAC_TYPE_UMAC;
1651
1652}
1653
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001654/* Define the XMAC mode */
Yaniv Rosnerce7c0482011-10-27 05:09:47 +00001655static void bnx2x_xmac_init(struct link_params *params, u32 max_speed)
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001656{
Yaniv Rosnerce7c0482011-10-27 05:09:47 +00001657 struct bnx2x *bp = params->bp;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001658 u32 is_port4mode = bnx2x_is_4_port_mode(bp);
1659
Yaniv Rosner2f751a82011-11-28 00:49:52 +00001660 /*
1661 * In 4-port mode, need to set the mode only once, so if XMAC is
1662 * already out of reset, it means the mode has already been set,
1663 * and it must not* reset the XMAC again, since it controls both
1664 * ports of the path
1665 */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001666
Yaniv Rosnerce7c0482011-10-27 05:09:47 +00001667 if ((CHIP_NUM(bp) == CHIP_NUM_57840) &&
1668 (REG_RD(bp, MISC_REG_RESET_REG_2) &
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001669 MISC_REGISTERS_RESET_REG_2_XMAC)) {
Joe Perches94f05b02011-08-14 12:16:20 +00001670 DP(NETIF_MSG_LINK,
1671 "XMAC already out of reset in 4-port mode\n");
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001672 return;
1673 }
1674
1675 /* Hard reset */
1676 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
1677 MISC_REGISTERS_RESET_REG_2_XMAC);
1678 usleep_range(1000, 1000);
1679
1680 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
1681 MISC_REGISTERS_RESET_REG_2_XMAC);
1682 if (is_port4mode) {
1683 DP(NETIF_MSG_LINK, "Init XMAC to 2 ports x 10G per path\n");
1684
1685 /* Set the number of ports on the system side to up to 2 */
1686 REG_WR(bp, MISC_REG_XMAC_CORE_PORT_MODE, 1);
1687
1688 /* Set the number of ports on the Warp Core to 10G */
1689 REG_WR(bp, MISC_REG_XMAC_PHY_PORT_MODE, 3);
1690 } else {
1691 /* Set the number of ports on the system side to 1 */
1692 REG_WR(bp, MISC_REG_XMAC_CORE_PORT_MODE, 0);
1693 if (max_speed == SPEED_10000) {
Joe Perches94f05b02011-08-14 12:16:20 +00001694 DP(NETIF_MSG_LINK,
1695 "Init XMAC to 10G x 1 port per path\n");
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001696 /* Set the number of ports on the Warp Core to 10G */
1697 REG_WR(bp, MISC_REG_XMAC_PHY_PORT_MODE, 3);
1698 } else {
Joe Perches94f05b02011-08-14 12:16:20 +00001699 DP(NETIF_MSG_LINK,
1700 "Init XMAC to 20G x 2 ports per path\n");
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001701 /* Set the number of ports on the Warp Core to 20G */
1702 REG_WR(bp, MISC_REG_XMAC_PHY_PORT_MODE, 1);
1703 }
1704 }
1705 /* Soft reset */
1706 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
1707 MISC_REGISTERS_RESET_REG_2_XMAC_SOFT);
1708 usleep_range(1000, 1000);
1709
1710 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
1711 MISC_REGISTERS_RESET_REG_2_XMAC_SOFT);
1712
1713}
1714
1715static void bnx2x_xmac_disable(struct link_params *params)
1716{
1717 u8 port = params->port;
1718 struct bnx2x *bp = params->bp;
Yaniv Rosnerb5077662011-08-02 22:59:18 +00001719 u32 pfc_ctrl, xmac_base = (port) ? GRCBASE_XMAC1 : GRCBASE_XMAC0;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001720
1721 if (REG_RD(bp, MISC_REG_RESET_REG_2) &
1722 MISC_REGISTERS_RESET_REG_2_XMAC) {
Yaniv Rosnerb5077662011-08-02 22:59:18 +00001723 /*
1724 * Send an indication to change the state in the NIG back to XON
1725 * Clearing this bit enables the next set of this bit to get
1726 * rising edge
1727 */
1728 pfc_ctrl = REG_RD(bp, xmac_base + XMAC_REG_PFC_CTRL_HI);
1729 REG_WR(bp, xmac_base + XMAC_REG_PFC_CTRL_HI,
1730 (pfc_ctrl & ~(1<<1)));
1731 REG_WR(bp, xmac_base + XMAC_REG_PFC_CTRL_HI,
1732 (pfc_ctrl | (1<<1)));
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001733 DP(NETIF_MSG_LINK, "Disable XMAC on port %x\n", port);
1734 REG_WR(bp, xmac_base + XMAC_REG_CTRL, 0);
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001735 }
1736}
1737
1738static int bnx2x_xmac_enable(struct link_params *params,
1739 struct link_vars *vars, u8 lb)
1740{
1741 u32 val, xmac_base;
1742 struct bnx2x *bp = params->bp;
1743 DP(NETIF_MSG_LINK, "enabling XMAC\n");
1744
1745 xmac_base = (params->port) ? GRCBASE_XMAC1 : GRCBASE_XMAC0;
1746
Yaniv Rosnerce7c0482011-10-27 05:09:47 +00001747 bnx2x_xmac_init(params, vars->line_speed);
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001748
1749 /*
1750 * This register determines on which events the MAC will assert
1751 * error on the i/f to the NIG along w/ EOP.
1752 */
1753
1754 /*
1755 * This register tells the NIG whether to send traffic to UMAC
1756 * or XMAC
1757 */
1758 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + params->port*4, 0);
1759
1760 /* Set Max packet size */
1761 REG_WR(bp, xmac_base + XMAC_REG_RX_MAX_SIZE, 0x2710);
1762
1763 /* CRC append for Tx packets */
1764 REG_WR(bp, xmac_base + XMAC_REG_TX_CTRL, 0xC800);
1765
1766 /* update PFC */
1767 bnx2x_update_pfc_xmac(params, vars, 0);
1768
1769 /* Enable TX and RX */
1770 val = XMAC_CTRL_REG_TX_EN | XMAC_CTRL_REG_RX_EN;
1771
1772 /* Check loopback mode */
1773 if (lb)
David S. Miller8decf862011-09-22 03:23:13 -04001774 val |= XMAC_CTRL_REG_LINE_LOCAL_LPBK;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00001775 REG_WR(bp, xmac_base + XMAC_REG_CTRL, val);
1776 bnx2x_set_xumac_nig(params,
1777 ((vars->flow_ctrl & BNX2X_FLOW_CTRL_TX) != 0), 1);
1778
1779 vars->mac_type = MAC_TYPE_XMAC;
1780
1781 return 0;
1782}
Yaniv Rosner2f751a82011-11-28 00:49:52 +00001783
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00001784static int bnx2x_emac_enable(struct link_params *params,
Yaniv Rosner9045f6b2011-05-31 21:28:27 +00001785 struct link_vars *vars, u8 lb)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001786{
1787 struct bnx2x *bp = params->bp;
1788 u8 port = params->port;
1789 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
1790 u32 val;
1791
1792 DP(NETIF_MSG_LINK, "enabling EMAC\n");
1793
Yaniv Rosnerde6f3372011-08-02 22:59:25 +00001794 /* Disable BMAC */
1795 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
1796 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
1797
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001798 /* enable emac and not bmac */
1799 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 1);
1800
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001801 /* ASIC */
1802 if (vars->phy_flags & PHY_XGXS_FLAG) {
1803 u32 ser_lane = ((params->lane_config &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001804 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
1805 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001806
1807 DP(NETIF_MSG_LINK, "XGXS\n");
1808 /* select the master lanes (out of 0-3) */
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001809 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, ser_lane);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001810 /* select XGXS */
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001811 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001812
1813 } else { /* SerDes */
1814 DP(NETIF_MSG_LINK, "SerDes\n");
1815 /* select SerDes */
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001816 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001817 }
1818
Eilon Greenstein811a2f22009-02-12 08:37:04 +00001819 bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001820 EMAC_RX_MODE_RESET);
Eilon Greenstein811a2f22009-02-12 08:37:04 +00001821 bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001822 EMAC_TX_MODE_RESET);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001823
1824 if (CHIP_REV_IS_SLOW(bp)) {
1825 /* config GMII mode */
1826 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001827 EMAC_WR(bp, EMAC_REG_EMAC_MODE, (val | EMAC_MODE_PORT_GMII));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001828 } else { /* ASIC */
1829 /* pause enable/disable */
1830 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
1831 EMAC_RX_MODE_FLOW_EN);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001832
1833 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001834 (EMAC_TX_MODE_EXT_PAUSE_EN |
1835 EMAC_TX_MODE_FLOW_EN));
1836 if (!(params->feature_config_flags &
1837 FEATURE_CONFIG_PFC_ENABLED)) {
1838 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
1839 bnx2x_bits_en(bp, emac_base +
1840 EMAC_REG_EMAC_RX_MODE,
1841 EMAC_RX_MODE_FLOW_EN);
1842
1843 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
1844 bnx2x_bits_en(bp, emac_base +
1845 EMAC_REG_EMAC_TX_MODE,
1846 (EMAC_TX_MODE_EXT_PAUSE_EN |
1847 EMAC_TX_MODE_FLOW_EN));
1848 } else
1849 bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
1850 EMAC_TX_MODE_FLOW_EN);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001851 }
1852
1853 /* KEEP_VLAN_TAG, promiscuous */
1854 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_RX_MODE);
1855 val |= EMAC_RX_MODE_KEEP_VLAN_TAG | EMAC_RX_MODE_PROMISCUOUS;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001856
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00001857 /*
1858 * Setting this bit causes MAC control frames (except for pause
1859 * frames) to be passed on for processing. This setting has no
1860 * affect on the operation of the pause frames. This bit effects
1861 * all packets regardless of RX Parser packet sorting logic.
1862 * Turn the PFC off to make sure we are in Xon state before
1863 * enabling it.
1864 */
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001865 EMAC_WR(bp, EMAC_REG_RX_PFC_MODE, 0);
1866 if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED) {
1867 DP(NETIF_MSG_LINK, "PFC is enabled\n");
1868 /* Enable PFC again */
1869 EMAC_WR(bp, EMAC_REG_RX_PFC_MODE,
1870 EMAC_REG_RX_PFC_MODE_RX_EN |
1871 EMAC_REG_RX_PFC_MODE_TX_EN |
1872 EMAC_REG_RX_PFC_MODE_PRIORITIES);
1873
1874 EMAC_WR(bp, EMAC_REG_RX_PFC_PARAM,
1875 ((0x0101 <<
1876 EMAC_REG_RX_PFC_PARAM_OPCODE_BITSHIFT) |
1877 (0x00ff <<
1878 EMAC_REG_RX_PFC_PARAM_PRIORITY_EN_BITSHIFT)));
1879 val |= EMAC_RX_MODE_KEEP_MAC_CONTROL;
1880 }
Eilon Greenstein3196a882008-08-13 15:58:49 -07001881 EMAC_WR(bp, EMAC_REG_EMAC_RX_MODE, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001882
1883 /* Set Loopback */
1884 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
1885 if (lb)
1886 val |= 0x810;
1887 else
1888 val &= ~0x810;
Eilon Greenstein3196a882008-08-13 15:58:49 -07001889 EMAC_WR(bp, EMAC_REG_EMAC_MODE, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001890
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001891 /* enable emac */
1892 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 1);
1893
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001894 /* enable emac for jumbo packets */
Eilon Greenstein3196a882008-08-13 15:58:49 -07001895 EMAC_WR(bp, EMAC_REG_EMAC_RX_MTU_SIZE,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001896 (EMAC_RX_MTU_SIZE_JUMBO_ENA |
1897 (ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD)));
1898
1899 /* strip CRC */
1900 REG_WR(bp, NIG_REG_NIG_INGRESS_EMAC0_NO_CRC + port*4, 0x1);
1901
1902 /* disable the NIG in/out to the bmac */
1903 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x0);
1904 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, 0x0);
1905 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x0);
1906
1907 /* enable the NIG in/out to the emac */
1908 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x1);
1909 val = 0;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001910 if ((params->feature_config_flags &
1911 FEATURE_CONFIG_PFC_ENABLED) ||
1912 (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001913 val = 1;
1914
1915 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, val);
1916 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x1);
1917
Yaniv Rosner02a23162011-01-31 04:22:53 +00001918 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001919
1920 vars->mac_type = MAC_TYPE_EMAC;
1921 return 0;
1922}
1923
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001924static void bnx2x_update_pfc_bmac1(struct link_params *params,
1925 struct link_vars *vars)
1926{
1927 u32 wb_data[2];
1928 struct bnx2x *bp = params->bp;
1929 u32 bmac_addr = params->port ? NIG_REG_INGRESS_BMAC1_MEM :
1930 NIG_REG_INGRESS_BMAC0_MEM;
1931
1932 u32 val = 0x14;
1933 if ((!(params->feature_config_flags &
1934 FEATURE_CONFIG_PFC_ENABLED)) &&
1935 (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX))
1936 /* Enable BigMAC to react on received Pause packets */
1937 val |= (1<<5);
1938 wb_data[0] = val;
1939 wb_data[1] = 0;
1940 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_CONTROL, wb_data, 2);
1941
1942 /* tx control */
1943 val = 0xc0;
1944 if (!(params->feature_config_flags &
1945 FEATURE_CONFIG_PFC_ENABLED) &&
1946 (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
1947 val |= 0x800000;
1948 wb_data[0] = val;
1949 wb_data[1] = 0;
1950 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_CONTROL, wb_data, 2);
1951}
1952
1953static void bnx2x_update_pfc_bmac2(struct link_params *params,
1954 struct link_vars *vars,
1955 u8 is_lb)
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001956{
1957 /*
1958 * Set rx control: Strip CRC and enable BigMAC to relay
1959 * control packets to the system as well
1960 */
1961 u32 wb_data[2];
1962 struct bnx2x *bp = params->bp;
1963 u32 bmac_addr = params->port ? NIG_REG_INGRESS_BMAC1_MEM :
1964 NIG_REG_INGRESS_BMAC0_MEM;
1965 u32 val = 0x14;
1966
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001967 if ((!(params->feature_config_flags &
1968 FEATURE_CONFIG_PFC_ENABLED)) &&
1969 (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX))
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001970 /* Enable BigMAC to react on received Pause packets */
1971 val |= (1<<5);
1972 wb_data[0] = val;
1973 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00001974 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_CONTROL, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001975 udelay(30);
1976
1977 /* Tx control */
1978 val = 0xc0;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001979 if (!(params->feature_config_flags &
1980 FEATURE_CONFIG_PFC_ENABLED) &&
1981 (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001982 val |= 0x800000;
1983 wb_data[0] = val;
1984 wb_data[1] = 0;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001985 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_CONTROL, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00001986
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00001987 if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED) {
1988 DP(NETIF_MSG_LINK, "PFC is enabled\n");
1989 /* Enable PFC RX & TX & STATS and set 8 COS */
1990 wb_data[0] = 0x0;
1991 wb_data[0] |= (1<<0); /* RX */
1992 wb_data[0] |= (1<<1); /* TX */
1993 wb_data[0] |= (1<<2); /* Force initial Xon */
1994 wb_data[0] |= (1<<3); /* 8 cos */
1995 wb_data[0] |= (1<<5); /* STATS */
1996 wb_data[1] = 0;
1997 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_PFC_CONTROL,
1998 wb_data, 2);
1999 /* Clear the force Xon */
2000 wb_data[0] &= ~(1<<2);
2001 } else {
2002 DP(NETIF_MSG_LINK, "PFC is disabled\n");
2003 /* disable PFC RX & TX & STATS and set 8 COS */
2004 wb_data[0] = 0x8;
2005 wb_data[1] = 0;
2006 }
2007
2008 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_PFC_CONTROL, wb_data, 2);
2009
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002010 /*
2011 * Set Time (based unit is 512 bit time) between automatic
2012 * re-sending of PP packets amd enable automatic re-send of
2013 * Per-Priroity Packet as long as pp_gen is asserted and
2014 * pp_disable is low.
2015 */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002016 val = 0x8000;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002017 if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED)
2018 val |= (1<<16); /* enable automatic re-send */
2019
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002020 wb_data[0] = val;
2021 wb_data[1] = 0;
2022 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_PAUSE_CONTROL,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002023 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002024
2025 /* mac control */
2026 val = 0x3; /* Enable RX and TX */
2027 if (is_lb) {
2028 val |= 0x4; /* Local loopback */
2029 DP(NETIF_MSG_LINK, "enable bmac loopback\n");
2030 }
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002031 /* When PFC enabled, Pass pause frames towards the NIG. */
2032 if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED)
2033 val |= ((1<<6)|(1<<5));
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002034
2035 wb_data[0] = val;
2036 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002037 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_BMAC_CONTROL, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002038}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002039
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002040/* PFC BRB internal port configuration params */
2041struct bnx2x_pfc_brb_threshold_val {
2042 u32 pause_xoff;
2043 u32 pause_xon;
2044 u32 full_xoff;
2045 u32 full_xon;
2046};
2047
2048struct bnx2x_pfc_brb_e3b0_val {
Yaniv Rosner866ceda2011-11-28 00:49:45 +00002049 u32 per_class_guaranty_mode;
2050 u32 lb_guarantied_hyst;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002051 u32 full_lb_xoff_th;
2052 u32 full_lb_xon_threshold;
2053 u32 lb_guarantied;
2054 u32 mac_0_class_t_guarantied;
2055 u32 mac_0_class_t_guarantied_hyst;
2056 u32 mac_1_class_t_guarantied;
2057 u32 mac_1_class_t_guarantied_hyst;
2058};
2059
2060struct bnx2x_pfc_brb_th_val {
2061 struct bnx2x_pfc_brb_threshold_val pauseable_th;
2062 struct bnx2x_pfc_brb_threshold_val non_pauseable_th;
Yaniv Rosner866ceda2011-11-28 00:49:45 +00002063 struct bnx2x_pfc_brb_threshold_val default_class0;
2064 struct bnx2x_pfc_brb_threshold_val default_class1;
2065
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002066};
2067static int bnx2x_pfc_brb_get_config_params(
2068 struct link_params *params,
2069 struct bnx2x_pfc_brb_th_val *config_val)
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002070{
2071 struct bnx2x *bp = params->bp;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002072 DP(NETIF_MSG_LINK, "Setting PFC BRB configuration\n");
Yaniv Rosner866ceda2011-11-28 00:49:45 +00002073
2074 config_val->default_class1.pause_xoff = 0;
2075 config_val->default_class1.pause_xon = 0;
2076 config_val->default_class1.full_xoff = 0;
2077 config_val->default_class1.full_xon = 0;
2078
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002079 if (CHIP_IS_E2(bp)) {
Yaniv Rosner866ceda2011-11-28 00:49:45 +00002080 /* class0 defaults */
2081 config_val->default_class0.pause_xoff =
2082 DEFAULT0_E2_BRB_MAC_PAUSE_XOFF_THR;
2083 config_val->default_class0.pause_xon =
Yaniv Rosner2f751a82011-11-28 00:49:52 +00002084 DEFAULT0_E2_BRB_MAC_PAUSE_XON_THR;
Yaniv Rosner866ceda2011-11-28 00:49:45 +00002085 config_val->default_class0.full_xoff =
Yaniv Rosner2f751a82011-11-28 00:49:52 +00002086 DEFAULT0_E2_BRB_MAC_FULL_XOFF_THR;
Yaniv Rosner866ceda2011-11-28 00:49:45 +00002087 config_val->default_class0.full_xon =
Yaniv Rosner2f751a82011-11-28 00:49:52 +00002088 DEFAULT0_E2_BRB_MAC_FULL_XON_THR;
Yaniv Rosner866ceda2011-11-28 00:49:45 +00002089 /* pause able*/
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002090 config_val->pauseable_th.pause_xoff =
Yaniv Rosner2f751a82011-11-28 00:49:52 +00002091 PFC_E2_BRB_MAC_PAUSE_XOFF_THR_PAUSE;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002092 config_val->pauseable_th.pause_xon =
Yaniv Rosner2f751a82011-11-28 00:49:52 +00002093 PFC_E2_BRB_MAC_PAUSE_XON_THR_PAUSE;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002094 config_val->pauseable_th.full_xoff =
Yaniv Rosner2f751a82011-11-28 00:49:52 +00002095 PFC_E2_BRB_MAC_FULL_XOFF_THR_PAUSE;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002096 config_val->pauseable_th.full_xon =
Yaniv Rosner2f751a82011-11-28 00:49:52 +00002097 PFC_E2_BRB_MAC_FULL_XON_THR_PAUSE;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002098 /* non pause able*/
2099 config_val->non_pauseable_th.pause_xoff =
Yaniv Rosner2f751a82011-11-28 00:49:52 +00002100 PFC_E2_BRB_MAC_PAUSE_XOFF_THR_NON_PAUSE;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002101 config_val->non_pauseable_th.pause_xon =
Yaniv Rosner2f751a82011-11-28 00:49:52 +00002102 PFC_E2_BRB_MAC_PAUSE_XON_THR_NON_PAUSE;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002103 config_val->non_pauseable_th.full_xoff =
Yaniv Rosner2f751a82011-11-28 00:49:52 +00002104 PFC_E2_BRB_MAC_FULL_XOFF_THR_NON_PAUSE;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002105 config_val->non_pauseable_th.full_xon =
Yaniv Rosner2f751a82011-11-28 00:49:52 +00002106 PFC_E2_BRB_MAC_FULL_XON_THR_NON_PAUSE;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002107 } else if (CHIP_IS_E3A0(bp)) {
Yaniv Rosner866ceda2011-11-28 00:49:45 +00002108 /* class0 defaults */
2109 config_val->default_class0.pause_xoff =
2110 DEFAULT0_E3A0_BRB_MAC_PAUSE_XOFF_THR;
2111 config_val->default_class0.pause_xon =
Yaniv Rosner2f751a82011-11-28 00:49:52 +00002112 DEFAULT0_E3A0_BRB_MAC_PAUSE_XON_THR;
Yaniv Rosner866ceda2011-11-28 00:49:45 +00002113 config_val->default_class0.full_xoff =
Yaniv Rosner2f751a82011-11-28 00:49:52 +00002114 DEFAULT0_E3A0_BRB_MAC_FULL_XOFF_THR;
Yaniv Rosner866ceda2011-11-28 00:49:45 +00002115 config_val->default_class0.full_xon =
Yaniv Rosner2f751a82011-11-28 00:49:52 +00002116 DEFAULT0_E3A0_BRB_MAC_FULL_XON_THR;
Yaniv Rosner866ceda2011-11-28 00:49:45 +00002117 /* pause able */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002118 config_val->pauseable_th.pause_xoff =
Yaniv Rosner2f751a82011-11-28 00:49:52 +00002119 PFC_E3A0_BRB_MAC_PAUSE_XOFF_THR_PAUSE;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002120 config_val->pauseable_th.pause_xon =
Yaniv Rosner2f751a82011-11-28 00:49:52 +00002121 PFC_E3A0_BRB_MAC_PAUSE_XON_THR_PAUSE;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002122 config_val->pauseable_th.full_xoff =
Yaniv Rosner2f751a82011-11-28 00:49:52 +00002123 PFC_E3A0_BRB_MAC_FULL_XOFF_THR_PAUSE;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002124 config_val->pauseable_th.full_xon =
Yaniv Rosner2f751a82011-11-28 00:49:52 +00002125 PFC_E3A0_BRB_MAC_FULL_XON_THR_PAUSE;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002126 /* non pause able*/
2127 config_val->non_pauseable_th.pause_xoff =
Yaniv Rosner2f751a82011-11-28 00:49:52 +00002128 PFC_E3A0_BRB_MAC_PAUSE_XOFF_THR_NON_PAUSE;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002129 config_val->non_pauseable_th.pause_xon =
Yaniv Rosner2f751a82011-11-28 00:49:52 +00002130 PFC_E3A0_BRB_MAC_PAUSE_XON_THR_NON_PAUSE;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002131 config_val->non_pauseable_th.full_xoff =
Yaniv Rosner2f751a82011-11-28 00:49:52 +00002132 PFC_E3A0_BRB_MAC_FULL_XOFF_THR_NON_PAUSE;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002133 config_val->non_pauseable_th.full_xon =
Yaniv Rosner2f751a82011-11-28 00:49:52 +00002134 PFC_E3A0_BRB_MAC_FULL_XON_THR_NON_PAUSE;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002135 } else if (CHIP_IS_E3B0(bp)) {
Yaniv Rosner866ceda2011-11-28 00:49:45 +00002136 /* class0 defaults */
2137 config_val->default_class0.pause_xoff =
2138 DEFAULT0_E3B0_BRB_MAC_PAUSE_XOFF_THR;
2139 config_val->default_class0.pause_xon =
2140 DEFAULT0_E3B0_BRB_MAC_PAUSE_XON_THR;
2141 config_val->default_class0.full_xoff =
2142 DEFAULT0_E3B0_BRB_MAC_FULL_XOFF_THR;
2143 config_val->default_class0.full_xon =
2144 DEFAULT0_E3B0_BRB_MAC_FULL_XON_THR;
2145
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002146 if (params->phy[INT_PHY].flags &
Yaniv Rosner2f751a82011-11-28 00:49:52 +00002147 FLAGS_4_PORT_MODE) {
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002148 config_val->pauseable_th.pause_xoff =
Yaniv Rosner866ceda2011-11-28 00:49:45 +00002149 PFC_E3B0_4P_BRB_MAC_PAUSE_XOFF_THR_PAUSE;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002150 config_val->pauseable_th.pause_xon =
Yaniv Rosner866ceda2011-11-28 00:49:45 +00002151 PFC_E3B0_4P_BRB_MAC_PAUSE_XON_THR_PAUSE;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002152 config_val->pauseable_th.full_xoff =
Yaniv Rosner866ceda2011-11-28 00:49:45 +00002153 PFC_E3B0_4P_BRB_MAC_FULL_XOFF_THR_PAUSE;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002154 config_val->pauseable_th.full_xon =
Yaniv Rosner866ceda2011-11-28 00:49:45 +00002155 PFC_E3B0_4P_BRB_MAC_FULL_XON_THR_PAUSE;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002156 /* non pause able*/
2157 config_val->non_pauseable_th.pause_xoff =
Yaniv Rosner866ceda2011-11-28 00:49:45 +00002158 PFC_E3B0_4P_BRB_MAC_PAUSE_XOFF_THR_NON_PAUSE;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002159 config_val->non_pauseable_th.pause_xon =
Yaniv Rosner866ceda2011-11-28 00:49:45 +00002160 PFC_E3B0_4P_BRB_MAC_PAUSE_XON_THR_NON_PAUSE;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002161 config_val->non_pauseable_th.full_xoff =
Yaniv Rosner866ceda2011-11-28 00:49:45 +00002162 PFC_E3B0_4P_BRB_MAC_FULL_XOFF_THR_NON_PAUSE;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002163 config_val->non_pauseable_th.full_xon =
Yaniv Rosner866ceda2011-11-28 00:49:45 +00002164 PFC_E3B0_4P_BRB_MAC_FULL_XON_THR_NON_PAUSE;
2165 } else {
2166 config_val->pauseable_th.pause_xoff =
2167 PFC_E3B0_2P_BRB_MAC_PAUSE_XOFF_THR_PAUSE;
2168 config_val->pauseable_th.pause_xon =
Yaniv Rosner2f751a82011-11-28 00:49:52 +00002169 PFC_E3B0_2P_BRB_MAC_PAUSE_XON_THR_PAUSE;
2170 config_val->pauseable_th.full_xoff =
2171 PFC_E3B0_2P_BRB_MAC_FULL_XOFF_THR_PAUSE;
2172 config_val->pauseable_th.full_xon =
2173 PFC_E3B0_2P_BRB_MAC_FULL_XON_THR_PAUSE;
2174 /* non pause able*/
2175 config_val->non_pauseable_th.pause_xoff =
2176 PFC_E3B0_2P_BRB_MAC_PAUSE_XOFF_THR_NON_PAUSE;
2177 config_val->non_pauseable_th.pause_xon =
2178 PFC_E3B0_2P_BRB_MAC_PAUSE_XON_THR_NON_PAUSE;
2179 config_val->non_pauseable_th.full_xoff =
2180 PFC_E3B0_2P_BRB_MAC_FULL_XOFF_THR_NON_PAUSE;
2181 config_val->non_pauseable_th.full_xon =
2182 PFC_E3B0_2P_BRB_MAC_FULL_XON_THR_NON_PAUSE;
2183 }
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002184 } else
2185 return -EINVAL;
2186
2187 return 0;
2188}
2189
Yaniv Rosner866ceda2011-11-28 00:49:45 +00002190static void bnx2x_pfc_brb_get_e3b0_config_params(
2191 struct link_params *params,
2192 struct bnx2x_pfc_brb_e3b0_val
2193 *e3b0_val,
2194 struct bnx2x_nig_brb_pfc_port_params *pfc_params,
2195 const u8 pfc_enabled)
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002196{
Yaniv Rosner866ceda2011-11-28 00:49:45 +00002197 if (pfc_enabled && pfc_params) {
2198 e3b0_val->per_class_guaranty_mode = 1;
2199 e3b0_val->lb_guarantied_hyst = 80;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002200
Yaniv Rosner866ceda2011-11-28 00:49:45 +00002201 if (params->phy[INT_PHY].flags &
2202 FLAGS_4_PORT_MODE) {
2203 e3b0_val->full_lb_xoff_th =
2204 PFC_E3B0_4P_BRB_FULL_LB_XOFF_THR;
2205 e3b0_val->full_lb_xon_threshold =
2206 PFC_E3B0_4P_BRB_FULL_LB_XON_THR;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002207 e3b0_val->lb_guarantied =
Yaniv Rosner866ceda2011-11-28 00:49:45 +00002208 PFC_E3B0_4P_LB_GUART;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002209 e3b0_val->mac_0_class_t_guarantied =
Yaniv Rosner866ceda2011-11-28 00:49:45 +00002210 PFC_E3B0_4P_BRB_MAC_0_CLASS_T_GUART;
2211 e3b0_val->mac_0_class_t_guarantied_hyst =
2212 PFC_E3B0_4P_BRB_MAC_0_CLASS_T_GUART_HYST;
2213 e3b0_val->mac_1_class_t_guarantied =
2214 PFC_E3B0_4P_BRB_MAC_1_CLASS_T_GUART;
2215 e3b0_val->mac_1_class_t_guarantied_hyst =
2216 PFC_E3B0_4P_BRB_MAC_1_CLASS_T_GUART_HYST;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002217 } else {
Yaniv Rosner866ceda2011-11-28 00:49:45 +00002218 e3b0_val->full_lb_xoff_th =
2219 PFC_E3B0_2P_BRB_FULL_LB_XOFF_THR;
2220 e3b0_val->full_lb_xon_threshold =
2221 PFC_E3B0_2P_BRB_FULL_LB_XON_THR;
2222 e3b0_val->mac_0_class_t_guarantied_hyst =
2223 PFC_E3B0_2P_BRB_MAC_0_CLASS_T_GUART_HYST;
2224 e3b0_val->mac_1_class_t_guarantied =
2225 PFC_E3B0_2P_BRB_MAC_1_CLASS_T_GUART;
2226 e3b0_val->mac_1_class_t_guarantied_hyst =
2227 PFC_E3B0_2P_BRB_MAC_1_CLASS_T_GUART_HYST;
2228
2229 if (pfc_params->cos0_pauseable !=
2230 pfc_params->cos1_pauseable) {
2231 /* nonpauseable= Lossy + pauseable = Lossless*/
2232 e3b0_val->lb_guarantied =
2233 PFC_E3B0_2P_MIX_PAUSE_LB_GUART;
2234 e3b0_val->mac_0_class_t_guarantied =
2235 PFC_E3B0_2P_MIX_PAUSE_MAC_0_CLASS_T_GUART;
2236 } else if (pfc_params->cos0_pauseable) {
2237 /* Lossless +Lossless*/
2238 e3b0_val->lb_guarantied =
2239 PFC_E3B0_2P_PAUSE_LB_GUART;
2240 e3b0_val->mac_0_class_t_guarantied =
2241 PFC_E3B0_2P_PAUSE_MAC_0_CLASS_T_GUART;
2242 } else {
2243 /* Lossy +Lossy*/
2244 e3b0_val->lb_guarantied =
2245 PFC_E3B0_2P_NON_PAUSE_LB_GUART;
2246 e3b0_val->mac_0_class_t_guarantied =
2247 PFC_E3B0_2P_NON_PAUSE_MAC_0_CLASS_T_GUART;
2248 }
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002249 }
Yaniv Rosner866ceda2011-11-28 00:49:45 +00002250 } else {
2251 e3b0_val->per_class_guaranty_mode = 0;
2252 e3b0_val->lb_guarantied_hyst = 0;
2253 e3b0_val->full_lb_xoff_th =
2254 DEFAULT_E3B0_BRB_FULL_LB_XOFF_THR;
2255 e3b0_val->full_lb_xon_threshold =
2256 DEFAULT_E3B0_BRB_FULL_LB_XON_THR;
2257 e3b0_val->lb_guarantied =
2258 DEFAULT_E3B0_LB_GUART;
2259 e3b0_val->mac_0_class_t_guarantied =
2260 DEFAULT_E3B0_BRB_MAC_0_CLASS_T_GUART;
2261 e3b0_val->mac_0_class_t_guarantied_hyst =
2262 DEFAULT_E3B0_BRB_MAC_0_CLASS_T_GUART_HYST;
2263 e3b0_val->mac_1_class_t_guarantied =
2264 DEFAULT_E3B0_BRB_MAC_1_CLASS_T_GUART;
2265 e3b0_val->mac_1_class_t_guarantied_hyst =
2266 DEFAULT_E3B0_BRB_MAC_1_CLASS_T_GUART_HYST;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002267 }
2268}
2269static int bnx2x_update_pfc_brb(struct link_params *params,
2270 struct link_vars *vars,
2271 struct bnx2x_nig_brb_pfc_port_params
2272 *pfc_params)
2273{
2274 struct bnx2x *bp = params->bp;
2275 struct bnx2x_pfc_brb_th_val config_val = { {0} };
2276 struct bnx2x_pfc_brb_threshold_val *reg_th_config =
Yaniv Rosner2f751a82011-11-28 00:49:52 +00002277 &config_val.pauseable_th;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002278 struct bnx2x_pfc_brb_e3b0_val e3b0_val = {0};
Yaniv Rosner866ceda2011-11-28 00:49:45 +00002279 const int set_pfc = params->feature_config_flags &
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002280 FEATURE_CONFIG_PFC_ENABLED;
Yaniv Rosner866ceda2011-11-28 00:49:45 +00002281 const u8 pfc_enabled = (set_pfc && pfc_params);
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002282 int bnx2x_status = 0;
2283 u8 port = params->port;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002284
2285 /* default - pause configuration */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002286 reg_th_config = &config_val.pauseable_th;
2287 bnx2x_status = bnx2x_pfc_brb_get_config_params(params, &config_val);
Yaniv Rosnerde0396f2011-11-28 00:49:53 +00002288 if (bnx2x_status)
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002289 return bnx2x_status;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002290
Yaniv Rosner866ceda2011-11-28 00:49:45 +00002291 if (pfc_enabled) {
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002292 /* First COS */
Yaniv Rosner866ceda2011-11-28 00:49:45 +00002293 if (pfc_params->cos0_pauseable)
2294 reg_th_config = &config_val.pauseable_th;
2295 else
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002296 reg_th_config = &config_val.non_pauseable_th;
Yaniv Rosner866ceda2011-11-28 00:49:45 +00002297 } else
2298 reg_th_config = &config_val.default_class0;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002299 /*
2300 * The number of free blocks below which the pause signal to class 0
2301 * of MAC #n is asserted. n=0,1
2302 */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002303 REG_WR(bp, (port) ? BRB1_REG_PAUSE_0_XOFF_THRESHOLD_1 :
2304 BRB1_REG_PAUSE_0_XOFF_THRESHOLD_0 ,
2305 reg_th_config->pause_xoff);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002306 /*
2307 * The number of free blocks above which the pause signal to class 0
2308 * of MAC #n is de-asserted. n=0,1
2309 */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002310 REG_WR(bp, (port) ? BRB1_REG_PAUSE_0_XON_THRESHOLD_1 :
2311 BRB1_REG_PAUSE_0_XON_THRESHOLD_0 , reg_th_config->pause_xon);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002312 /*
2313 * The number of free blocks below which the full signal to class 0
2314 * of MAC #n is asserted. n=0,1
2315 */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002316 REG_WR(bp, (port) ? BRB1_REG_FULL_0_XOFF_THRESHOLD_1 :
2317 BRB1_REG_FULL_0_XOFF_THRESHOLD_0 , reg_th_config->full_xoff);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002318 /*
2319 * The number of free blocks above which the full signal to class 0
2320 * of MAC #n is de-asserted. n=0,1
2321 */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002322 REG_WR(bp, (port) ? BRB1_REG_FULL_0_XON_THRESHOLD_1 :
2323 BRB1_REG_FULL_0_XON_THRESHOLD_0 , reg_th_config->full_xon);
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002324
Yaniv Rosner866ceda2011-11-28 00:49:45 +00002325 if (pfc_enabled) {
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002326 /* Second COS */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002327 if (pfc_params->cos1_pauseable)
2328 reg_th_config = &config_val.pauseable_th;
2329 else
2330 reg_th_config = &config_val.non_pauseable_th;
Yaniv Rosner866ceda2011-11-28 00:49:45 +00002331 } else
2332 reg_th_config = &config_val.default_class1;
Yaniv Rosner2f751a82011-11-28 00:49:52 +00002333 /*
2334 * The number of free blocks below which the pause signal to
2335 * class 1 of MAC #n is asserted. n=0,1
2336 */
2337 REG_WR(bp, (port) ? BRB1_REG_PAUSE_1_XOFF_THRESHOLD_1 :
2338 BRB1_REG_PAUSE_1_XOFF_THRESHOLD_0,
2339 reg_th_config->pause_xoff);
2340
2341 /*
2342 * The number of free blocks above which the pause signal to
2343 * class 1 of MAC #n is de-asserted. n=0,1
2344 */
2345 REG_WR(bp, (port) ? BRB1_REG_PAUSE_1_XON_THRESHOLD_1 :
2346 BRB1_REG_PAUSE_1_XON_THRESHOLD_0,
2347 reg_th_config->pause_xon);
2348 /*
2349 * The number of free blocks below which the full signal to
2350 * class 1 of MAC #n is asserted. n=0,1
2351 */
2352 REG_WR(bp, (port) ? BRB1_REG_FULL_1_XOFF_THRESHOLD_1 :
2353 BRB1_REG_FULL_1_XOFF_THRESHOLD_0,
2354 reg_th_config->full_xoff);
2355 /*
2356 * The number of free blocks above which the full signal to
2357 * class 1 of MAC #n is de-asserted. n=0,1
2358 */
2359 REG_WR(bp, (port) ? BRB1_REG_FULL_1_XON_THRESHOLD_1 :
2360 BRB1_REG_FULL_1_XON_THRESHOLD_0,
2361 reg_th_config->full_xon);
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002362
Yaniv Rosner866ceda2011-11-28 00:49:45 +00002363 if (CHIP_IS_E3B0(bp)) {
2364 bnx2x_pfc_brb_get_e3b0_config_params(
2365 params,
2366 &e3b0_val,
2367 pfc_params,
2368 pfc_enabled);
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002369
Yaniv Rosner866ceda2011-11-28 00:49:45 +00002370 REG_WR(bp, BRB1_REG_PER_CLASS_GUARANTY_MODE,
2371 e3b0_val.per_class_guaranty_mode);
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002372
Yaniv Rosner2f751a82011-11-28 00:49:52 +00002373 /*
2374 * The hysteresis on the guarantied buffer space for the Lb
2375 * port before signaling XON.
2376 */
Yaniv Rosner866ceda2011-11-28 00:49:45 +00002377 REG_WR(bp, BRB1_REG_LB_GUARANTIED_HYST,
2378 e3b0_val.lb_guarantied_hyst);
Yaniv Rosner2f751a82011-11-28 00:49:52 +00002379
2380 /*
2381 * The number of free blocks below which the full signal to the
2382 * LB port is asserted.
2383 */
Yaniv Rosner866ceda2011-11-28 00:49:45 +00002384 REG_WR(bp, BRB1_REG_FULL_LB_XOFF_THRESHOLD,
Yaniv Rosner2f751a82011-11-28 00:49:52 +00002385 e3b0_val.full_lb_xoff_th);
2386 /*
2387 * The number of free blocks above which the full signal to the
2388 * LB port is de-asserted.
2389 */
2390 REG_WR(bp, BRB1_REG_FULL_LB_XON_THRESHOLD,
2391 e3b0_val.full_lb_xon_threshold);
2392 /*
2393 * The number of blocks guarantied for the MAC #n port. n=0,1
2394 */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002395
Yaniv Rosner2f751a82011-11-28 00:49:52 +00002396 /* The number of blocks guarantied for the LB port.*/
2397 REG_WR(bp, BRB1_REG_LB_GUARANTIED,
2398 e3b0_val.lb_guarantied);
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002399
Yaniv Rosner2f751a82011-11-28 00:49:52 +00002400 /*
2401 * The number of blocks guarantied for the MAC #n port.
2402 */
2403 REG_WR(bp, BRB1_REG_MAC_GUARANTIED_0,
2404 2 * e3b0_val.mac_0_class_t_guarantied);
2405 REG_WR(bp, BRB1_REG_MAC_GUARANTIED_1,
2406 2 * e3b0_val.mac_1_class_t_guarantied);
2407 /*
2408 * The number of blocks guarantied for class #t in MAC0. t=0,1
2409 */
2410 REG_WR(bp, BRB1_REG_MAC_0_CLASS_0_GUARANTIED,
2411 e3b0_val.mac_0_class_t_guarantied);
2412 REG_WR(bp, BRB1_REG_MAC_0_CLASS_1_GUARANTIED,
2413 e3b0_val.mac_0_class_t_guarantied);
2414 /*
2415 * The hysteresis on the guarantied buffer space for class in
2416 * MAC0. t=0,1
2417 */
2418 REG_WR(bp, BRB1_REG_MAC_0_CLASS_0_GUARANTIED_HYST,
2419 e3b0_val.mac_0_class_t_guarantied_hyst);
2420 REG_WR(bp, BRB1_REG_MAC_0_CLASS_1_GUARANTIED_HYST,
2421 e3b0_val.mac_0_class_t_guarantied_hyst);
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002422
Yaniv Rosner2f751a82011-11-28 00:49:52 +00002423 /*
2424 * The number of blocks guarantied for class #t in MAC1.t=0,1
2425 */
2426 REG_WR(bp, BRB1_REG_MAC_1_CLASS_0_GUARANTIED,
2427 e3b0_val.mac_1_class_t_guarantied);
2428 REG_WR(bp, BRB1_REG_MAC_1_CLASS_1_GUARANTIED,
2429 e3b0_val.mac_1_class_t_guarantied);
2430 /*
2431 * The hysteresis on the guarantied buffer space for class #t
2432 * in MAC1. t=0,1
2433 */
2434 REG_WR(bp, BRB1_REG_MAC_1_CLASS_0_GUARANTIED_HYST,
2435 e3b0_val.mac_1_class_t_guarantied_hyst);
2436 REG_WR(bp, BRB1_REG_MAC_1_CLASS_1_GUARANTIED_HYST,
2437 e3b0_val.mac_1_class_t_guarantied_hyst);
2438 }
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002439
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002440 return bnx2x_status;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002441}
2442
Vlad Zolotarov619c5cb2011-06-14 14:33:44 +03002443/******************************************************************************
2444* Description:
2445* This function is needed because NIG ARB_CREDIT_WEIGHT_X are
2446* not continues and ARB_CREDIT_WEIGHT_0 + offset is suitable.
2447******************************************************************************/
2448int bnx2x_pfc_nig_rx_priority_mask(struct bnx2x *bp,
2449 u8 cos_entry,
2450 u32 priority_mask, u8 port)
2451{
2452 u32 nig_reg_rx_priority_mask_add = 0;
2453
2454 switch (cos_entry) {
2455 case 0:
2456 nig_reg_rx_priority_mask_add = (port) ?
2457 NIG_REG_P1_RX_COS0_PRIORITY_MASK :
2458 NIG_REG_P0_RX_COS0_PRIORITY_MASK;
2459 break;
2460 case 1:
2461 nig_reg_rx_priority_mask_add = (port) ?
2462 NIG_REG_P1_RX_COS1_PRIORITY_MASK :
2463 NIG_REG_P0_RX_COS1_PRIORITY_MASK;
2464 break;
2465 case 2:
2466 nig_reg_rx_priority_mask_add = (port) ?
2467 NIG_REG_P1_RX_COS2_PRIORITY_MASK :
2468 NIG_REG_P0_RX_COS2_PRIORITY_MASK;
2469 break;
2470 case 3:
2471 if (port)
2472 return -EINVAL;
2473 nig_reg_rx_priority_mask_add = NIG_REG_P0_RX_COS3_PRIORITY_MASK;
2474 break;
2475 case 4:
2476 if (port)
2477 return -EINVAL;
2478 nig_reg_rx_priority_mask_add = NIG_REG_P0_RX_COS4_PRIORITY_MASK;
2479 break;
2480 case 5:
2481 if (port)
2482 return -EINVAL;
2483 nig_reg_rx_priority_mask_add = NIG_REG_P0_RX_COS5_PRIORITY_MASK;
2484 break;
2485 }
2486
2487 REG_WR(bp, nig_reg_rx_priority_mask_add, priority_mask);
2488
2489 return 0;
2490}
Yaniv Rosnerb8d6d082011-07-05 01:06:27 +00002491static void bnx2x_update_mng(struct link_params *params, u32 link_status)
2492{
2493 struct bnx2x *bp = params->bp;
2494
2495 REG_WR(bp, params->shmem_base +
2496 offsetof(struct shmem_region,
2497 port_mb[params->port].link_status), link_status);
2498}
2499
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002500static void bnx2x_update_pfc_nig(struct link_params *params,
2501 struct link_vars *vars,
2502 struct bnx2x_nig_brb_pfc_port_params *nig_params)
2503{
2504 u32 xcm_mask = 0, ppp_enable = 0, pause_enable = 0, llfc_out_en = 0;
2505 u32 llfc_enable = 0, xcm0_out_en = 0, p0_hwpfc_enable = 0;
2506 u32 pkt_priority_to_cos = 0;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002507 struct bnx2x *bp = params->bp;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002508 u8 port = params->port;
2509
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002510 int set_pfc = params->feature_config_flags &
2511 FEATURE_CONFIG_PFC_ENABLED;
2512 DP(NETIF_MSG_LINK, "updating pfc nig parameters\n");
2513
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002514 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002515 * When NIG_LLH0_XCM_MASK_REG_LLHX_XCM_MASK_BCN bit is set
2516 * MAC control frames (that are not pause packets)
2517 * will be forwarded to the XCM.
2518 */
2519 xcm_mask = REG_RD(bp,
2520 port ? NIG_REG_LLH1_XCM_MASK :
2521 NIG_REG_LLH0_XCM_MASK);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002522 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002523 * nig params will override non PFC params, since it's possible to
2524 * do transition from PFC to SAFC
2525 */
2526 if (set_pfc) {
2527 pause_enable = 0;
2528 llfc_out_en = 0;
2529 llfc_enable = 0;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002530 if (CHIP_IS_E3(bp))
2531 ppp_enable = 0;
2532 else
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002533 ppp_enable = 1;
2534 xcm_mask &= ~(port ? NIG_LLH1_XCM_MASK_REG_LLH1_XCM_MASK_BCN :
2535 NIG_LLH0_XCM_MASK_REG_LLH0_XCM_MASK_BCN);
2536 xcm0_out_en = 0;
2537 p0_hwpfc_enable = 1;
2538 } else {
2539 if (nig_params) {
2540 llfc_out_en = nig_params->llfc_out_en;
2541 llfc_enable = nig_params->llfc_enable;
2542 pause_enable = nig_params->pause_enable;
2543 } else /*defaul non PFC mode - PAUSE */
2544 pause_enable = 1;
2545
2546 xcm_mask |= (port ? NIG_LLH1_XCM_MASK_REG_LLH1_XCM_MASK_BCN :
2547 NIG_LLH0_XCM_MASK_REG_LLH0_XCM_MASK_BCN);
2548 xcm0_out_en = 1;
2549 }
2550
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002551 if (CHIP_IS_E3(bp))
2552 REG_WR(bp, port ? NIG_REG_BRB1_PAUSE_IN_EN :
2553 NIG_REG_BRB0_PAUSE_IN_EN, pause_enable);
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002554 REG_WR(bp, port ? NIG_REG_LLFC_OUT_EN_1 :
2555 NIG_REG_LLFC_OUT_EN_0, llfc_out_en);
2556 REG_WR(bp, port ? NIG_REG_LLFC_ENABLE_1 :
2557 NIG_REG_LLFC_ENABLE_0, llfc_enable);
2558 REG_WR(bp, port ? NIG_REG_PAUSE_ENABLE_1 :
2559 NIG_REG_PAUSE_ENABLE_0, pause_enable);
2560
2561 REG_WR(bp, port ? NIG_REG_PPP_ENABLE_1 :
2562 NIG_REG_PPP_ENABLE_0, ppp_enable);
2563
2564 REG_WR(bp, port ? NIG_REG_LLH1_XCM_MASK :
2565 NIG_REG_LLH0_XCM_MASK, xcm_mask);
2566
2567 REG_WR(bp, NIG_REG_LLFC_EGRESS_SRC_ENABLE_0, 0x7);
2568
2569 /* output enable for RX_XCM # IF */
2570 REG_WR(bp, NIG_REG_XCM0_OUT_EN, xcm0_out_en);
2571
2572 /* HW PFC TX enable */
2573 REG_WR(bp, NIG_REG_P0_HWPFC_ENABLE, p0_hwpfc_enable);
2574
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002575 if (nig_params) {
Vlad Zolotarov619c5cb2011-06-14 14:33:44 +03002576 u8 i = 0;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002577 pkt_priority_to_cos = nig_params->pkt_priority_to_cos;
2578
Vlad Zolotarov619c5cb2011-06-14 14:33:44 +03002579 for (i = 0; i < nig_params->num_of_rx_cos_priority_mask; i++)
2580 bnx2x_pfc_nig_rx_priority_mask(bp, i,
2581 nig_params->rx_cos_priority_mask[i], port);
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002582
2583 REG_WR(bp, port ? NIG_REG_LLFC_HIGH_PRIORITY_CLASSES_1 :
2584 NIG_REG_LLFC_HIGH_PRIORITY_CLASSES_0,
2585 nig_params->llfc_high_priority_classes);
2586
2587 REG_WR(bp, port ? NIG_REG_LLFC_LOW_PRIORITY_CLASSES_1 :
2588 NIG_REG_LLFC_LOW_PRIORITY_CLASSES_0,
2589 nig_params->llfc_low_priority_classes);
2590 }
2591 REG_WR(bp, port ? NIG_REG_P1_PKT_PRIORITY_TO_COS :
2592 NIG_REG_P0_PKT_PRIORITY_TO_COS,
2593 pkt_priority_to_cos);
2594}
2595
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002596int bnx2x_update_pfc(struct link_params *params,
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002597 struct link_vars *vars,
2598 struct bnx2x_nig_brb_pfc_port_params *pfc_params)
2599{
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002600 /*
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002601 * The PFC and pause are orthogonal to one another, meaning when
2602 * PFC is enabled, the pause are disabled, and when PFC is
2603 * disabled, pause are set according to the pause result.
2604 */
2605 u32 val;
2606 struct bnx2x *bp = params->bp;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002607 int bnx2x_status = 0;
2608 u8 bmac_loopback = (params->loopback_mode == LOOPBACK_BMAC);
Yaniv Rosnerb8d6d082011-07-05 01:06:27 +00002609
2610 if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED)
2611 vars->link_status |= LINK_STATUS_PFC_ENABLED;
2612 else
2613 vars->link_status &= ~LINK_STATUS_PFC_ENABLED;
2614
2615 bnx2x_update_mng(params, vars->link_status);
2616
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002617 /* update NIG params */
2618 bnx2x_update_pfc_nig(params, vars, pfc_params);
2619
2620 /* update BRB params */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002621 bnx2x_status = bnx2x_update_pfc_brb(params, vars, pfc_params);
Yaniv Rosnerde0396f2011-11-28 00:49:53 +00002622 if (bnx2x_status)
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002623 return bnx2x_status;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002624
2625 if (!vars->link_up)
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002626 return bnx2x_status;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002627
2628 DP(NETIF_MSG_LINK, "About to update PFC in BMAC\n");
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002629 if (CHIP_IS_E3(bp))
2630 bnx2x_update_pfc_xmac(params, vars, 0);
2631 else {
2632 val = REG_RD(bp, MISC_REG_RESET_REG_2);
2633 if ((val &
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00002634 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << params->port))
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002635 == 0) {
2636 DP(NETIF_MSG_LINK, "About to update PFC in EMAC\n");
2637 bnx2x_emac_enable(params, vars, 0);
2638 return bnx2x_status;
2639 }
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002640 if (CHIP_IS_E2(bp))
2641 bnx2x_update_pfc_bmac2(params, vars, bmac_loopback);
2642 else
2643 bnx2x_update_pfc_bmac1(params, vars);
2644
2645 val = 0;
2646 if ((params->feature_config_flags &
2647 FEATURE_CONFIG_PFC_ENABLED) ||
2648 (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
2649 val = 1;
2650 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + params->port*4, val);
2651 }
2652 return bnx2x_status;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002653}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002654
Yaniv Rosner9380bb92011-06-14 01:34:07 +00002655
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00002656static int bnx2x_bmac1_enable(struct link_params *params,
2657 struct link_vars *vars,
2658 u8 is_lb)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002659{
2660 struct bnx2x *bp = params->bp;
2661 u8 port = params->port;
2662 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
2663 NIG_REG_INGRESS_BMAC0_MEM;
2664 u32 wb_data[2];
2665 u32 val;
2666
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002667 DP(NETIF_MSG_LINK, "Enabling BigMAC1\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002668
2669 /* XGXS control */
2670 wb_data[0] = 0x3c;
2671 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002672 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_XGXS_CONTROL,
2673 wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002674
2675 /* tx MAC SA */
2676 wb_data[0] = ((params->mac_addr[2] << 24) |
2677 (params->mac_addr[3] << 16) |
2678 (params->mac_addr[4] << 8) |
2679 params->mac_addr[5]);
2680 wb_data[1] = ((params->mac_addr[0] << 8) |
2681 params->mac_addr[1]);
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002682 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_SOURCE_ADDR, wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002683
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002684 /* mac control */
2685 val = 0x3;
2686 if (is_lb) {
2687 val |= 0x4;
2688 DP(NETIF_MSG_LINK, "enable bmac loopback\n");
2689 }
2690 wb_data[0] = val;
2691 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002692 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL, wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002693
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002694 /* set rx mtu */
2695 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
2696 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002697 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_MAX_SIZE, wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002698
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002699 bnx2x_update_pfc_bmac1(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002700
2701 /* set tx mtu */
2702 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
2703 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002704 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_MAX_SIZE, wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002705
2706 /* set cnt max size */
2707 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
2708 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002709 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_CNT_MAX_SIZE, wb_data, 2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002710
2711 /* configure safc */
2712 wb_data[0] = 0x1000200;
2713 wb_data[1] = 0;
2714 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_LLFC_MSG_FLDS,
2715 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002716
2717 return 0;
2718}
2719
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00002720static int bnx2x_bmac2_enable(struct link_params *params,
2721 struct link_vars *vars,
2722 u8 is_lb)
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002723{
2724 struct bnx2x *bp = params->bp;
2725 u8 port = params->port;
2726 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
2727 NIG_REG_INGRESS_BMAC0_MEM;
2728 u32 wb_data[2];
2729
2730 DP(NETIF_MSG_LINK, "Enabling BigMAC2\n");
2731
2732 wb_data[0] = 0;
2733 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002734 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_BMAC_CONTROL, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002735 udelay(30);
2736
2737 /* XGXS control: Reset phy HW, MDIO registers, PHY PLL and BMAC */
2738 wb_data[0] = 0x3c;
2739 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002740 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_BMAC_XGXS_CONTROL,
2741 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002742
2743 udelay(30);
2744
2745 /* tx MAC SA */
2746 wb_data[0] = ((params->mac_addr[2] << 24) |
2747 (params->mac_addr[3] << 16) |
2748 (params->mac_addr[4] << 8) |
2749 params->mac_addr[5]);
2750 wb_data[1] = ((params->mac_addr[0] << 8) |
2751 params->mac_addr[1]);
2752 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_SOURCE_ADDR,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002753 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002754
2755 udelay(30);
2756
2757 /* Configure SAFC */
2758 wb_data[0] = 0x1000200;
2759 wb_data[1] = 0;
2760 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_LLFC_MSG_FLDS,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002761 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002762 udelay(30);
2763
2764 /* set rx mtu */
2765 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
2766 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002767 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_MAX_SIZE, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002768 udelay(30);
2769
2770 /* set tx mtu */
2771 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
2772 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002773 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_MAX_SIZE, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002774 udelay(30);
2775 /* set cnt max size */
2776 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD - 2;
2777 wb_data[1] = 0;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002778 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_CNT_MAX_SIZE, wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002779 udelay(30);
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002780 bnx2x_update_pfc_bmac2(params, vars, is_lb);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002781
2782 return 0;
2783}
2784
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00002785static int bnx2x_bmac_enable(struct link_params *params,
2786 struct link_vars *vars,
2787 u8 is_lb)
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002788{
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00002789 int rc = 0;
2790 u8 port = params->port;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002791 struct bnx2x *bp = params->bp;
2792 u32 val;
2793 /* reset and unreset the BigMac */
2794 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002795 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
Yaniv Rosner1d9c05d2010-11-01 05:32:25 +00002796 msleep(1);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002797
2798 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002799 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002800
2801 /* enable access for bmac registers */
2802 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
2803
2804 /* Enable BMAC according to BMAC type*/
2805 if (CHIP_IS_E2(bp))
2806 rc = bnx2x_bmac2_enable(params, vars, is_lb);
2807 else
2808 rc = bnx2x_bmac1_enable(params, vars, is_lb);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002809 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0x1);
2810 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 0x0);
2811 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 0x0);
2812 val = 0;
Vladislav Zolotarovbcab15c2010-12-13 05:44:25 +00002813 if ((params->feature_config_flags &
2814 FEATURE_CONFIG_PFC_ENABLED) ||
2815 (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002816 val = 1;
2817 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, val);
2818 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x0);
2819 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x0);
2820 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, 0x0);
2821 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x1);
2822 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x1);
2823
2824 vars->mac_type = MAC_TYPE_BMAC;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002825 return rc;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002826}
2827
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002828static void bnx2x_bmac_rx_disable(struct bnx2x *bp, u8 port)
2829{
2830 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002831 NIG_REG_INGRESS_BMAC0_MEM;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002832 u32 wb_data[2];
Eilon Greenstein3196a882008-08-13 15:58:49 -07002833 u32 nig_bmac_enable = REG_RD(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002834
2835 /* Only if the bmac is out of reset */
2836 if (REG_RD(bp, MISC_REG_RESET_REG_2) &
2837 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port) &&
2838 nig_bmac_enable) {
2839
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002840 if (CHIP_IS_E2(bp)) {
2841 /* Clear Rx Enable bit in BMAC_CONTROL register */
2842 REG_RD_DMAE(bp, bmac_addr +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002843 BIGMAC2_REGISTER_BMAC_CONTROL,
2844 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002845 wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
2846 REG_WR_DMAE(bp, bmac_addr +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002847 BIGMAC2_REGISTER_BMAC_CONTROL,
2848 wb_data, 2);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00002849 } else {
2850 /* Clear Rx Enable bit in BMAC_CONTROL register */
2851 REG_RD_DMAE(bp, bmac_addr +
2852 BIGMAC_REGISTER_BMAC_CONTROL,
2853 wb_data, 2);
2854 wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
2855 REG_WR_DMAE(bp, bmac_addr +
2856 BIGMAC_REGISTER_BMAC_CONTROL,
2857 wb_data, 2);
2858 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002859 msleep(1);
2860 }
2861}
2862
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00002863static int bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl,
2864 u32 line_speed)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002865{
2866 struct bnx2x *bp = params->bp;
2867 u8 port = params->port;
2868 u32 init_crd, crd;
2869 u32 count = 1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002870
2871 /* disable port */
2872 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x1);
2873
2874 /* wait for init credit */
2875 init_crd = REG_RD(bp, PBF_REG_P0_INIT_CRD + port*4);
2876 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
2877 DP(NETIF_MSG_LINK, "init_crd 0x%x crd 0x%x\n", init_crd, crd);
2878
2879 while ((init_crd != crd) && count) {
2880 msleep(5);
2881
2882 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
2883 count--;
2884 }
2885 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
2886 if (init_crd != crd) {
2887 DP(NETIF_MSG_LINK, "BUG! init_crd 0x%x != crd 0x%x\n",
2888 init_crd, crd);
2889 return -EINVAL;
2890 }
2891
David S. Millerc0700f92008-12-16 23:53:20 -08002892 if (flow_ctrl & BNX2X_FLOW_CTRL_RX ||
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002893 line_speed == SPEED_10 ||
2894 line_speed == SPEED_100 ||
2895 line_speed == SPEED_1000 ||
2896 line_speed == SPEED_2500) {
2897 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002898 /* update threshold */
2899 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, 0);
2900 /* update init credit */
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00002901 init_crd = 778; /* (800-18-4) */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002902
2903 } else {
2904 u32 thresh = (ETH_MAX_JUMBO_PACKET_SIZE +
2905 ETH_OVREHEAD)/16;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002906 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002907 /* update threshold */
2908 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, thresh);
2909 /* update init credit */
2910 switch (line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002911 case SPEED_10000:
2912 init_crd = thresh + 553 - 22;
2913 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002914 default:
2915 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
2916 line_speed);
2917 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002918 }
2919 }
2920 REG_WR(bp, PBF_REG_P0_INIT_CRD + port*4, init_crd);
2921 DP(NETIF_MSG_LINK, "PBF updated to speed %d credit %d\n",
2922 line_speed, init_crd);
2923
2924 /* probe the credit changes */
2925 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x1);
2926 msleep(5);
2927 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x0);
2928
2929 /* enable port */
2930 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x0);
2931 return 0;
2932}
2933
Dmitry Kravkove8920672011-05-04 23:52:40 +00002934/**
2935 * bnx2x_get_emac_base - retrive emac base address
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002936 *
Dmitry Kravkove8920672011-05-04 23:52:40 +00002937 * @bp: driver handle
2938 * @mdc_mdio_access: access type
2939 * @port: port id
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002940 *
2941 * This function selects the MDC/MDIO access (through emac0 or
2942 * emac1) depend on the mdc_mdio_access, port, port swapped. Each
2943 * phy has a default access mode, which could also be overridden
2944 * by nvram configuration. This parameter, whether this is the
2945 * default phy configuration, or the nvram overrun
2946 * configuration, is passed here as mdc_mdio_access and selects
2947 * the emac_base for the CL45 read/writes operations
2948 */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002949static u32 bnx2x_get_emac_base(struct bnx2x *bp,
2950 u32 mdc_mdio_access, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002951{
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002952 u32 emac_base = 0;
2953 switch (mdc_mdio_access) {
2954 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_PHY_TYPE:
2955 break;
2956 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC0:
2957 if (REG_RD(bp, NIG_REG_PORT_SWAP))
2958 emac_base = GRCBASE_EMAC1;
2959 else
2960 emac_base = GRCBASE_EMAC0;
2961 break;
2962 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1:
Eilon Greenstein589abe32009-02-12 08:36:55 +00002963 if (REG_RD(bp, NIG_REG_PORT_SWAP))
2964 emac_base = GRCBASE_EMAC0;
2965 else
2966 emac_base = GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002967 break;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002968 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH:
2969 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
2970 break;
2971 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_SWAPPED:
Eilon Greenstein6378c022008-08-13 15:59:25 -07002972 emac_base = (port) ? GRCBASE_EMAC0 : GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002973 break;
2974 default:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002975 break;
2976 }
2977 return emac_base;
2978
2979}
2980
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00002981/******************************************************************/
Yaniv Rosner6583e332011-06-14 01:34:17 +00002982/* CL22 access functions */
2983/******************************************************************/
2984static int bnx2x_cl22_write(struct bnx2x *bp,
2985 struct bnx2x_phy *phy,
2986 u16 reg, u16 val)
2987{
2988 u32 tmp, mode;
2989 u8 i;
2990 int rc = 0;
2991 /* Switch to CL22 */
2992 mode = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
2993 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE,
2994 mode & ~EMAC_MDIO_MODE_CLAUSE_45);
2995
2996 /* address */
2997 tmp = ((phy->addr << 21) | (reg << 16) | val |
2998 EMAC_MDIO_COMM_COMMAND_WRITE_22 |
2999 EMAC_MDIO_COMM_START_BUSY);
3000 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
3001
3002 for (i = 0; i < 50; i++) {
3003 udelay(10);
3004
3005 tmp = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
3006 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
3007 udelay(5);
3008 break;
3009 }
3010 }
3011 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
3012 DP(NETIF_MSG_LINK, "write phy register failed\n");
3013 rc = -EFAULT;
3014 }
3015 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, mode);
3016 return rc;
3017}
3018
3019static int bnx2x_cl22_read(struct bnx2x *bp,
3020 struct bnx2x_phy *phy,
3021 u16 reg, u16 *ret_val)
3022{
3023 u32 val, mode;
3024 u16 i;
3025 int rc = 0;
3026
3027 /* Switch to CL22 */
3028 mode = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
3029 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE,
3030 mode & ~EMAC_MDIO_MODE_CLAUSE_45);
3031
3032 /* address */
3033 val = ((phy->addr << 21) | (reg << 16) |
3034 EMAC_MDIO_COMM_COMMAND_READ_22 |
3035 EMAC_MDIO_COMM_START_BUSY);
3036 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
3037
3038 for (i = 0; i < 50; i++) {
3039 udelay(10);
3040
3041 val = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
3042 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
3043 *ret_val = (u16)(val & EMAC_MDIO_COMM_DATA);
3044 udelay(5);
3045 break;
3046 }
3047 }
3048 if (val & EMAC_MDIO_COMM_START_BUSY) {
3049 DP(NETIF_MSG_LINK, "read phy register failed\n");
3050
3051 *ret_val = 0;
3052 rc = -EFAULT;
3053 }
3054 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, mode);
3055 return rc;
3056}
3057
3058/******************************************************************/
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003059/* CL45 access functions */
3060/******************************************************************/
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00003061static int bnx2x_cl45_read(struct bnx2x *bp, struct bnx2x_phy *phy,
3062 u8 devad, u16 reg, u16 *ret_val)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003063{
Yaniv Rosnera198c142011-05-31 21:29:42 +00003064 u32 val;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003065 u16 i;
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00003066 int rc = 0;
Yaniv Rosner157fa282011-08-02 22:59:32 +00003067 if (phy->flags & FLAGS_MDC_MDIO_WA_B0)
3068 bnx2x_bits_en(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_STATUS,
3069 EMAC_MDIO_STATUS_10MB);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003070 /* address */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003071 val = ((phy->addr << 21) | (devad << 16) | reg |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003072 EMAC_MDIO_COMM_COMMAND_ADDRESS |
3073 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003074 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003075
3076 for (i = 0; i < 50; i++) {
3077 udelay(10);
3078
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003079 val = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003080 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
3081 udelay(5);
3082 break;
3083 }
3084 }
3085 if (val & EMAC_MDIO_COMM_START_BUSY) {
3086 DP(NETIF_MSG_LINK, "read phy register failed\n");
Yaniv Rosner6d870c32011-01-31 04:22:20 +00003087 netdev_err(bp->dev, "MDC/MDIO access timeout\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003088 *ret_val = 0;
3089 rc = -EFAULT;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003090 } else {
3091 /* data */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003092 val = ((phy->addr << 21) | (devad << 16) |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003093 EMAC_MDIO_COMM_COMMAND_READ_45 |
3094 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003095 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003096
3097 for (i = 0; i < 50; i++) {
3098 udelay(10);
3099
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003100 val = REG_RD(bp, phy->mdio_ctrl +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003101 EMAC_REG_EMAC_MDIO_COMM);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003102 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
3103 *ret_val = (u16)(val & EMAC_MDIO_COMM_DATA);
3104 break;
3105 }
3106 }
3107 if (val & EMAC_MDIO_COMM_START_BUSY) {
3108 DP(NETIF_MSG_LINK, "read phy register failed\n");
Yaniv Rosner6d870c32011-01-31 04:22:20 +00003109 netdev_err(bp->dev, "MDC/MDIO access timeout\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003110 *ret_val = 0;
3111 rc = -EFAULT;
3112 }
3113 }
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00003114 /* Work around for E3 A0 */
3115 if (phy->flags & FLAGS_MDC_MDIO_WA) {
3116 phy->flags ^= FLAGS_DUMMY_READ;
3117 if (phy->flags & FLAGS_DUMMY_READ) {
3118 u16 temp_val;
3119 bnx2x_cl45_read(bp, phy, devad, 0xf, &temp_val);
3120 }
3121 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003122
Yaniv Rosner157fa282011-08-02 22:59:32 +00003123 if (phy->flags & FLAGS_MDC_MDIO_WA_B0)
3124 bnx2x_bits_dis(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_STATUS,
3125 EMAC_MDIO_STATUS_10MB);
Yaniv Rosnera198c142011-05-31 21:29:42 +00003126 return rc;
3127}
3128
3129static int bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy,
3130 u8 devad, u16 reg, u16 val)
3131{
3132 u32 tmp;
3133 u8 i;
3134 int rc = 0;
Yaniv Rosner157fa282011-08-02 22:59:32 +00003135 if (phy->flags & FLAGS_MDC_MDIO_WA_B0)
3136 bnx2x_bits_en(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_STATUS,
3137 EMAC_MDIO_STATUS_10MB);
Yaniv Rosnera198c142011-05-31 21:29:42 +00003138
3139 /* address */
3140
3141 tmp = ((phy->addr << 21) | (devad << 16) | reg |
3142 EMAC_MDIO_COMM_COMMAND_ADDRESS |
3143 EMAC_MDIO_COMM_START_BUSY);
3144 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
3145
3146 for (i = 0; i < 50; i++) {
3147 udelay(10);
3148
3149 tmp = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
3150 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
3151 udelay(5);
3152 break;
3153 }
3154 }
3155 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
3156 DP(NETIF_MSG_LINK, "write phy register failed\n");
3157 netdev_err(bp->dev, "MDC/MDIO access timeout\n");
3158 rc = -EFAULT;
Yaniv Rosnera198c142011-05-31 21:29:42 +00003159 } else {
3160 /* data */
3161 tmp = ((phy->addr << 21) | (devad << 16) | val |
3162 EMAC_MDIO_COMM_COMMAND_WRITE_45 |
3163 EMAC_MDIO_COMM_START_BUSY);
3164 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
3165
3166 for (i = 0; i < 50; i++) {
3167 udelay(10);
3168
3169 tmp = REG_RD(bp, phy->mdio_ctrl +
3170 EMAC_REG_EMAC_MDIO_COMM);
3171 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
3172 udelay(5);
3173 break;
3174 }
3175 }
3176 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
3177 DP(NETIF_MSG_LINK, "write phy register failed\n");
3178 netdev_err(bp->dev, "MDC/MDIO access timeout\n");
3179 rc = -EFAULT;
3180 }
3181 }
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00003182 /* Work around for E3 A0 */
3183 if (phy->flags & FLAGS_MDC_MDIO_WA) {
3184 phy->flags ^= FLAGS_DUMMY_READ;
3185 if (phy->flags & FLAGS_DUMMY_READ) {
3186 u16 temp_val;
3187 bnx2x_cl45_read(bp, phy, devad, 0xf, &temp_val);
3188 }
3189 }
Yaniv Rosner157fa282011-08-02 22:59:32 +00003190 if (phy->flags & FLAGS_MDC_MDIO_WA_B0)
3191 bnx2x_bits_dis(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_STATUS,
3192 EMAC_MDIO_STATUS_10MB);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003193 return rc;
3194}
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00003195/******************************************************************/
3196/* BSC access functions from E3 */
3197/******************************************************************/
3198static void bnx2x_bsc_module_sel(struct link_params *params)
3199{
3200 int idx;
3201 u32 board_cfg, sfp_ctrl;
3202 u32 i2c_pins[I2C_SWITCH_WIDTH], i2c_val[I2C_SWITCH_WIDTH];
3203 struct bnx2x *bp = params->bp;
3204 u8 port = params->port;
3205 /* Read I2C output PINs */
3206 board_cfg = REG_RD(bp, params->shmem_base +
3207 offsetof(struct shmem_region,
3208 dev_info.shared_hw_config.board));
3209 i2c_pins[I2C_BSC0] = board_cfg & SHARED_HW_CFG_E3_I2C_MUX0_MASK;
3210 i2c_pins[I2C_BSC1] = (board_cfg & SHARED_HW_CFG_E3_I2C_MUX1_MASK) >>
3211 SHARED_HW_CFG_E3_I2C_MUX1_SHIFT;
3212
3213 /* Read I2C output value */
3214 sfp_ctrl = REG_RD(bp, params->shmem_base +
3215 offsetof(struct shmem_region,
3216 dev_info.port_hw_config[port].e3_cmn_pin_cfg));
3217 i2c_val[I2C_BSC0] = (sfp_ctrl & PORT_HW_CFG_E3_I2C_MUX0_MASK) > 0;
3218 i2c_val[I2C_BSC1] = (sfp_ctrl & PORT_HW_CFG_E3_I2C_MUX1_MASK) > 0;
3219 DP(NETIF_MSG_LINK, "Setting BSC switch\n");
3220 for (idx = 0; idx < I2C_SWITCH_WIDTH; idx++)
3221 bnx2x_set_cfg_pin(bp, i2c_pins[idx], i2c_val[idx]);
3222}
3223
3224static int bnx2x_bsc_read(struct link_params *params,
3225 struct bnx2x_phy *phy,
3226 u8 sl_devid,
3227 u16 sl_addr,
3228 u8 lc_addr,
3229 u8 xfer_cnt,
3230 u32 *data_array)
3231{
3232 u32 val, i;
3233 int rc = 0;
3234 struct bnx2x *bp = params->bp;
3235
3236 if ((sl_devid != 0xa0) && (sl_devid != 0xa2)) {
3237 DP(NETIF_MSG_LINK, "invalid sl_devid 0x%x\n", sl_devid);
3238 return -EINVAL;
3239 }
3240
3241 if (xfer_cnt > 16) {
3242 DP(NETIF_MSG_LINK, "invalid xfer_cnt %d. Max is 16 bytes\n",
3243 xfer_cnt);
3244 return -EINVAL;
3245 }
3246 bnx2x_bsc_module_sel(params);
3247
3248 xfer_cnt = 16 - lc_addr;
3249
3250 /* enable the engine */
3251 val = REG_RD(bp, MCP_REG_MCPR_IMC_COMMAND);
3252 val |= MCPR_IMC_COMMAND_ENABLE;
3253 REG_WR(bp, MCP_REG_MCPR_IMC_COMMAND, val);
3254
3255 /* program slave device ID */
3256 val = (sl_devid << 16) | sl_addr;
3257 REG_WR(bp, MCP_REG_MCPR_IMC_SLAVE_CONTROL, val);
3258
3259 /* start xfer with 0 byte to update the address pointer ???*/
3260 val = (MCPR_IMC_COMMAND_ENABLE) |
3261 (MCPR_IMC_COMMAND_WRITE_OP <<
3262 MCPR_IMC_COMMAND_OPERATION_BITSHIFT) |
3263 (lc_addr << MCPR_IMC_COMMAND_TRANSFER_ADDRESS_BITSHIFT) | (0);
3264 REG_WR(bp, MCP_REG_MCPR_IMC_COMMAND, val);
3265
3266 /* poll for completion */
3267 i = 0;
3268 val = REG_RD(bp, MCP_REG_MCPR_IMC_COMMAND);
3269 while (((val >> MCPR_IMC_COMMAND_IMC_STATUS_BITSHIFT) & 0x3) != 1) {
3270 udelay(10);
3271 val = REG_RD(bp, MCP_REG_MCPR_IMC_COMMAND);
3272 if (i++ > 1000) {
3273 DP(NETIF_MSG_LINK, "wr 0 byte timed out after %d try\n",
3274 i);
3275 rc = -EFAULT;
3276 break;
3277 }
3278 }
3279 if (rc == -EFAULT)
3280 return rc;
3281
3282 /* start xfer with read op */
3283 val = (MCPR_IMC_COMMAND_ENABLE) |
3284 (MCPR_IMC_COMMAND_READ_OP <<
3285 MCPR_IMC_COMMAND_OPERATION_BITSHIFT) |
3286 (lc_addr << MCPR_IMC_COMMAND_TRANSFER_ADDRESS_BITSHIFT) |
3287 (xfer_cnt);
3288 REG_WR(bp, MCP_REG_MCPR_IMC_COMMAND, val);
3289
3290 /* poll for completion */
3291 i = 0;
3292 val = REG_RD(bp, MCP_REG_MCPR_IMC_COMMAND);
3293 while (((val >> MCPR_IMC_COMMAND_IMC_STATUS_BITSHIFT) & 0x3) != 1) {
3294 udelay(10);
3295 val = REG_RD(bp, MCP_REG_MCPR_IMC_COMMAND);
3296 if (i++ > 1000) {
3297 DP(NETIF_MSG_LINK, "rd op timed out after %d try\n", i);
3298 rc = -EFAULT;
3299 break;
3300 }
3301 }
3302 if (rc == -EFAULT)
3303 return rc;
3304
3305 for (i = (lc_addr >> 2); i < 4; i++) {
3306 data_array[i] = REG_RD(bp, (MCP_REG_MCPR_IMC_DATAREG0 + i*4));
3307#ifdef __BIG_ENDIAN
3308 data_array[i] = ((data_array[i] & 0x000000ff) << 24) |
3309 ((data_array[i] & 0x0000ff00) << 8) |
3310 ((data_array[i] & 0x00ff0000) >> 8) |
3311 ((data_array[i] & 0xff000000) >> 24);
3312#endif
3313 }
3314 return rc;
3315}
3316
3317static void bnx2x_cl45_read_or_write(struct bnx2x *bp, struct bnx2x_phy *phy,
3318 u8 devad, u16 reg, u16 or_val)
3319{
3320 u16 val;
3321 bnx2x_cl45_read(bp, phy, devad, reg, &val);
3322 bnx2x_cl45_write(bp, phy, devad, reg, val | or_val);
3323}
3324
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00003325int bnx2x_phy_read(struct link_params *params, u8 phy_addr,
3326 u8 devad, u16 reg, u16 *ret_val)
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003327{
3328 u8 phy_index;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003329 /*
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003330 * Probe for the phy according to the given phy_addr, and execute
3331 * the read request on it
3332 */
3333 for (phy_index = 0; phy_index < params->num_phys; phy_index++) {
3334 if (params->phy[phy_index].addr == phy_addr) {
3335 return bnx2x_cl45_read(params->bp,
3336 &params->phy[phy_index], devad,
3337 reg, ret_val);
3338 }
3339 }
3340 return -EINVAL;
3341}
3342
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00003343int bnx2x_phy_write(struct link_params *params, u8 phy_addr,
3344 u8 devad, u16 reg, u16 val)
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003345{
3346 u8 phy_index;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00003347 /*
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003348 * Probe for the phy according to the given phy_addr, and execute
3349 * the write request on it
3350 */
3351 for (phy_index = 0; phy_index < params->num_phys; phy_index++) {
3352 if (params->phy[phy_index].addr == phy_addr) {
3353 return bnx2x_cl45_write(params->bp,
3354 &params->phy[phy_index], devad,
3355 reg, val);
3356 }
3357 }
3358 return -EINVAL;
3359}
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00003360static u8 bnx2x_get_warpcore_lane(struct bnx2x_phy *phy,
3361 struct link_params *params)
3362{
3363 u8 lane = 0;
3364 struct bnx2x *bp = params->bp;
3365 u32 path_swap, path_swap_ovr;
3366 u8 path, port;
3367
3368 path = BP_PATH(bp);
3369 port = params->port;
3370
3371 if (bnx2x_is_4_port_mode(bp)) {
3372 u32 port_swap, port_swap_ovr;
3373
3374 /*figure out path swap value */
3375 path_swap_ovr = REG_RD(bp, MISC_REG_FOUR_PORT_PATH_SWAP_OVWR);
3376 if (path_swap_ovr & 0x1)
3377 path_swap = (path_swap_ovr & 0x2);
3378 else
3379 path_swap = REG_RD(bp, MISC_REG_FOUR_PORT_PATH_SWAP);
3380
3381 if (path_swap)
3382 path = path ^ 1;
3383
3384 /*figure out port swap value */
3385 port_swap_ovr = REG_RD(bp, MISC_REG_FOUR_PORT_PORT_SWAP_OVWR);
3386 if (port_swap_ovr & 0x1)
3387 port_swap = (port_swap_ovr & 0x2);
3388 else
3389 port_swap = REG_RD(bp, MISC_REG_FOUR_PORT_PORT_SWAP);
3390
3391 if (port_swap)
3392 port = port ^ 1;
3393
3394 lane = (port<<1) + path;
3395 } else { /* two port mode - no port swap */
3396
3397 /*figure out path swap value */
3398 path_swap_ovr =
3399 REG_RD(bp, MISC_REG_TWO_PORT_PATH_SWAP_OVWR);
3400 if (path_swap_ovr & 0x1) {
3401 path_swap = (path_swap_ovr & 0x2);
3402 } else {
3403 path_swap =
3404 REG_RD(bp, MISC_REG_TWO_PORT_PATH_SWAP);
3405 }
3406 if (path_swap)
3407 path = path ^ 1;
3408
3409 lane = path << 1 ;
3410 }
3411 return lane;
3412}
Yaniv Rosnere10bc842010-09-07 11:40:50 +00003413
Yaniv Rosnerec146a62011-05-31 21:29:27 +00003414static void bnx2x_set_aer_mmd(struct link_params *params,
3415 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003416{
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003417 u32 ser_lane;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00003418 u16 offset, aer_val;
3419 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003420 ser_lane = ((params->lane_config &
3421 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
3422 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
3423
Yaniv Rosnerec146a62011-05-31 21:29:27 +00003424 offset = (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ?
3425 (phy->addr + ser_lane) : 0;
3426
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00003427 if (USES_WARPCORE(bp)) {
3428 aer_val = bnx2x_get_warpcore_lane(phy, params);
3429 /*
3430 * In Dual-lane mode, two lanes are joined together,
3431 * so in order to configure them, the AER broadcast method is
3432 * used here.
3433 * 0x200 is the broadcast address for lanes 0,1
3434 * 0x201 is the broadcast address for lanes 2,3
3435 */
3436 if (phy->flags & FLAGS_WC_DUAL_MODE)
3437 aer_val = (aer_val >> 1) | 0x200;
3438 } else if (CHIP_IS_E2(bp))
Yaniv Rosner82a0d472011-01-18 04:33:52 +00003439 aer_val = 0x3800 + offset - 1;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00003440 else
3441 aer_val = 0x3800 + offset;
Yaniv Rosner2f751a82011-11-28 00:49:52 +00003442
Yaniv Rosnercd2be892011-01-31 04:21:45 +00003443 CL22_WR_OVER_CL45(bp, phy, MDIO_REG_BANK_AER_BLOCK,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003444 MDIO_AER_BLOCK_AER_REG, aer_val);
Yaniv Rosnerec146a62011-05-31 21:29:27 +00003445
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003446}
3447
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003448/******************************************************************/
3449/* Internal phy section */
3450/******************************************************************/
3451
3452static void bnx2x_set_serdes_access(struct bnx2x *bp, u8 port)
3453{
3454 u32 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
3455
3456 /* Set Clause 22 */
3457 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + port*0x10, 1);
3458 REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245f8000);
3459 udelay(500);
3460 REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245d000f);
3461 udelay(500);
3462 /* Set Clause 45 */
3463 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + port*0x10, 0);
3464}
3465
3466static void bnx2x_serdes_deassert(struct bnx2x *bp, u8 port)
3467{
3468 u32 val;
3469
3470 DP(NETIF_MSG_LINK, "bnx2x_serdes_deassert\n");
3471
3472 val = SERDES_RESET_BITS << (port*16);
3473
3474 /* reset and unreset the SerDes/XGXS */
3475 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR, val);
3476 udelay(500);
3477 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET, val);
3478
3479 bnx2x_set_serdes_access(bp, port);
3480
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003481 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_DEVAD + port*0x10,
3482 DEFAULT_PHY_DEV_ADDR);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003483}
3484
3485static void bnx2x_xgxs_deassert(struct link_params *params)
3486{
3487 struct bnx2x *bp = params->bp;
3488 u8 port;
3489 u32 val;
3490 DP(NETIF_MSG_LINK, "bnx2x_xgxs_deassert\n");
3491 port = params->port;
3492
3493 val = XGXS_RESET_BITS << (port*16);
3494
3495 /* reset and unreset the SerDes/XGXS */
3496 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR, val);
3497 udelay(500);
3498 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET, val);
3499
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003500 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_ST + port*0x18, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003501 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00003502 params->phy[INT_PHY].def_md_devad);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003503}
3504
Yaniv Rosner9045f6b2011-05-31 21:28:27 +00003505static void bnx2x_calc_ieee_aneg_adv(struct bnx2x_phy *phy,
3506 struct link_params *params, u16 *ieee_fc)
3507{
3508 struct bnx2x *bp = params->bp;
3509 *ieee_fc = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX;
3510 /**
3511 * resolve pause mode and advertisement Please refer to Table
3512 * 28B-3 of the 802.3ab-1999 spec
3513 */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003514
Yaniv Rosner9045f6b2011-05-31 21:28:27 +00003515 switch (phy->req_flow_ctrl) {
3516 case BNX2X_FLOW_CTRL_AUTO:
3517 if (params->req_fc_auto_adv == BNX2X_FLOW_CTRL_BOTH)
3518 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
3519 else
3520 *ieee_fc |=
3521 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
3522 break;
3523
3524 case BNX2X_FLOW_CTRL_TX:
3525 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
3526 break;
3527
3528 case BNX2X_FLOW_CTRL_RX:
3529 case BNX2X_FLOW_CTRL_BOTH:
3530 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
3531 break;
3532
3533 case BNX2X_FLOW_CTRL_NONE:
3534 default:
3535 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE;
3536 break;
3537 }
3538 DP(NETIF_MSG_LINK, "ieee_fc = 0x%x\n", *ieee_fc);
3539}
3540
3541static void set_phy_vars(struct link_params *params,
3542 struct link_vars *vars)
3543{
3544 struct bnx2x *bp = params->bp;
3545 u8 actual_phy_idx, phy_index, link_cfg_idx;
3546 u8 phy_config_swapped = params->multi_phy_config &
3547 PORT_HW_CFG_PHY_SWAPPED_ENABLED;
3548 for (phy_index = INT_PHY; phy_index < params->num_phys;
3549 phy_index++) {
3550 link_cfg_idx = LINK_CONFIG_IDX(phy_index);
3551 actual_phy_idx = phy_index;
3552 if (phy_config_swapped) {
3553 if (phy_index == EXT_PHY1)
3554 actual_phy_idx = EXT_PHY2;
3555 else if (phy_index == EXT_PHY2)
3556 actual_phy_idx = EXT_PHY1;
3557 }
3558 params->phy[actual_phy_idx].req_flow_ctrl =
3559 params->req_flow_ctrl[link_cfg_idx];
3560
3561 params->phy[actual_phy_idx].req_line_speed =
3562 params->req_line_speed[link_cfg_idx];
3563
3564 params->phy[actual_phy_idx].speed_cap_mask =
3565 params->speed_cap_mask[link_cfg_idx];
3566
3567 params->phy[actual_phy_idx].req_duplex =
3568 params->req_duplex[link_cfg_idx];
3569
3570 if (params->req_line_speed[link_cfg_idx] ==
3571 SPEED_AUTO_NEG)
3572 vars->link_status |= LINK_STATUS_AUTO_NEGOTIATE_ENABLED;
3573
3574 DP(NETIF_MSG_LINK, "req_flow_ctrl %x, req_line_speed %x,"
3575 " speed_cap_mask %x\n",
3576 params->phy[actual_phy_idx].req_flow_ctrl,
3577 params->phy[actual_phy_idx].req_line_speed,
3578 params->phy[actual_phy_idx].speed_cap_mask);
3579 }
3580}
3581
3582static void bnx2x_ext_phy_set_pause(struct link_params *params,
3583 struct bnx2x_phy *phy,
3584 struct link_vars *vars)
3585{
3586 u16 val;
3587 struct bnx2x *bp = params->bp;
3588 /* read modify write pause advertizing */
3589 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV_PAUSE, &val);
3590
3591 val &= ~MDIO_AN_REG_ADV_PAUSE_BOTH;
3592
3593 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
3594 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
3595 if ((vars->ieee_fc &
3596 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
3597 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
3598 val |= MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC;
3599 }
3600 if ((vars->ieee_fc &
3601 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
3602 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
3603 val |= MDIO_AN_REG_ADV_PAUSE_PAUSE;
3604 }
3605 DP(NETIF_MSG_LINK, "Ext phy AN advertize 0x%x\n", val);
3606 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV_PAUSE, val);
3607}
3608
3609static void bnx2x_pause_resolve(struct link_vars *vars, u32 pause_result)
3610{ /* LD LP */
3611 switch (pause_result) { /* ASYM P ASYM P */
3612 case 0xb: /* 1 0 1 1 */
3613 vars->flow_ctrl = BNX2X_FLOW_CTRL_TX;
3614 break;
3615
3616 case 0xe: /* 1 1 1 0 */
3617 vars->flow_ctrl = BNX2X_FLOW_CTRL_RX;
3618 break;
3619
3620 case 0x5: /* 0 1 0 1 */
3621 case 0x7: /* 0 1 1 1 */
3622 case 0xd: /* 1 1 0 1 */
3623 case 0xf: /* 1 1 1 1 */
3624 vars->flow_ctrl = BNX2X_FLOW_CTRL_BOTH;
3625 break;
3626
3627 default:
3628 break;
3629 }
3630 if (pause_result & (1<<0))
3631 vars->link_status |= LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE;
3632 if (pause_result & (1<<1))
3633 vars->link_status |= LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE;
3634}
3635
3636static u8 bnx2x_ext_phy_resolve_fc(struct bnx2x_phy *phy,
3637 struct link_params *params,
3638 struct link_vars *vars)
3639{
3640 struct bnx2x *bp = params->bp;
3641 u16 ld_pause; /* local */
3642 u16 lp_pause; /* link partner */
3643 u16 pause_result;
3644 u8 ret = 0;
3645 /* read twice */
3646
3647 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
3648
3649 if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO)
3650 vars->flow_ctrl = phy->req_flow_ctrl;
3651 else if (phy->req_line_speed != SPEED_AUTO_NEG)
3652 vars->flow_ctrl = params->req_fc_auto_adv;
3653 else if (vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE) {
3654 ret = 1;
Yaniv Rosner52c4d6c2011-07-05 01:06:34 +00003655 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54618SE) {
Yaniv Rosner6583e332011-06-14 01:34:17 +00003656 bnx2x_cl22_read(bp, phy,
3657 0x4, &ld_pause);
3658 bnx2x_cl22_read(bp, phy,
3659 0x5, &lp_pause);
3660 } else {
3661 bnx2x_cl45_read(bp, phy,
3662 MDIO_AN_DEVAD,
3663 MDIO_AN_REG_ADV_PAUSE, &ld_pause);
3664 bnx2x_cl45_read(bp, phy,
3665 MDIO_AN_DEVAD,
3666 MDIO_AN_REG_LP_AUTO_NEG, &lp_pause);
3667 }
Yaniv Rosner9045f6b2011-05-31 21:28:27 +00003668 pause_result = (ld_pause &
3669 MDIO_AN_REG_ADV_PAUSE_MASK) >> 8;
3670 pause_result |= (lp_pause &
3671 MDIO_AN_REG_ADV_PAUSE_MASK) >> 10;
3672 DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x\n",
3673 pause_result);
3674 bnx2x_pause_resolve(vars, pause_result);
3675 }
3676 return ret;
3677}
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00003678/******************************************************************/
3679/* Warpcore section */
3680/******************************************************************/
3681/* The init_internal_warpcore should mirror the xgxs,
3682 * i.e. reset the lane (if needed), set aer for the
3683 * init configuration, and set/clear SGMII flag. Internal
3684 * phy init is done purely in phy_init stage.
3685 */
3686static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy,
3687 struct link_params *params,
3688 struct link_vars *vars) {
Yaniv Rosnera34bc962011-07-05 01:06:41 +00003689 u16 val16 = 0, lane, bam37 = 0;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00003690 struct bnx2x *bp = params->bp;
3691 DP(NETIF_MSG_LINK, "Enable Auto Negotiation for KR\n");
Yaniv Rosnera9077bf2011-10-27 05:09:46 +00003692
3693 /* Disable Autoneg: re-enable it after adv is done. */
3694 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
3695 MDIO_WC_REG_IEEE0BLK_MIICNTL, 0);
3696
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00003697 /* Check adding advertisement for 1G KX */
3698 if (((vars->line_speed == SPEED_AUTO_NEG) &&
3699 (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) ||
3700 (vars->line_speed == SPEED_1000)) {
3701 u16 sd_digital;
3702 val16 |= (1<<5);
3703
3704 /* Enable CL37 1G Parallel Detect */
3705 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3706 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, &sd_digital);
3707 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3708 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2,
3709 (sd_digital | 0x1));
3710
3711 DP(NETIF_MSG_LINK, "Advertize 1G\n");
3712 }
3713 if (((vars->line_speed == SPEED_AUTO_NEG) &&
3714 (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) ||
3715 (vars->line_speed == SPEED_10000)) {
3716 /* Check adding advertisement for 10G KR */
3717 val16 |= (1<<7);
3718 /* Enable 10G Parallel Detect */
3719 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
3720 MDIO_WC_REG_PAR_DET_10G_CTRL, 1);
3721
3722 DP(NETIF_MSG_LINK, "Advertize 10G\n");
3723 }
3724
3725 /* Set Transmit PMD settings */
3726 lane = bnx2x_get_warpcore_lane(phy, params);
3727 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3728 MDIO_WC_REG_TX0_TX_DRIVER + 0x10*lane,
3729 ((0x02 << MDIO_WC_REG_TX0_TX_DRIVER_POST2_COEFF_OFFSET) |
3730 (0x06 << MDIO_WC_REG_TX0_TX_DRIVER_IDRIVER_OFFSET) |
3731 (0x09 << MDIO_WC_REG_TX0_TX_DRIVER_IPRE_DRIVER_OFFSET)));
3732 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3733 MDIO_WC_REG_CL72_USERB0_CL72_OS_DEF_CTRL,
3734 0x03f0);
3735 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3736 MDIO_WC_REG_CL72_USERB0_CL72_2P5_DEF_CTRL,
3737 0x03f0);
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00003738
3739 /* Advertised speeds */
3740 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
3741 MDIO_WC_REG_AN_IEEE1BLK_AN_ADVERTISEMENT1, val16);
3742
David S. Miller8decf862011-09-22 03:23:13 -04003743 /* Advertised and set FEC (Forward Error Correction) */
3744 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
3745 MDIO_WC_REG_AN_IEEE1BLK_AN_ADVERTISEMENT2,
3746 (MDIO_WC_REG_AN_IEEE1BLK_AN_ADV2_FEC_ABILITY |
3747 MDIO_WC_REG_AN_IEEE1BLK_AN_ADV2_FEC_REQ));
3748
Yaniv Rosnera34bc962011-07-05 01:06:41 +00003749 /* Enable CL37 BAM */
3750 if (REG_RD(bp, params->shmem_base +
3751 offsetof(struct shmem_region, dev_info.
3752 port_hw_config[params->port].default_cfg)) &
3753 PORT_HW_CFG_ENABLE_BAM_ON_KR_ENABLED) {
3754 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3755 MDIO_WC_REG_DIGITAL6_MP5_NEXTPAGECTRL, &bam37);
3756 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3757 MDIO_WC_REG_DIGITAL6_MP5_NEXTPAGECTRL, bam37 | 1);
3758 DP(NETIF_MSG_LINK, "Enable CL37 BAM on KR\n");
3759 }
3760
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00003761 /* Advertise pause */
3762 bnx2x_ext_phy_set_pause(params, phy, vars);
3763
Yaniv Rosnera9077bf2011-10-27 05:09:46 +00003764 vars->rx_tx_asic_rst = MAX_KR_LINK_RETRY;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00003765
3766 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3767 MDIO_WC_REG_DIGITAL5_MISC7, &val16);
3768
3769 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3770 MDIO_WC_REG_DIGITAL5_MISC7, val16 | 0x100);
Yaniv Rosnera9077bf2011-10-27 05:09:46 +00003771
3772 /* Over 1G - AN local device user page 1 */
3773 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3774 MDIO_WC_REG_DIGITAL3_UP1, 0x1f);
3775
3776 /* Enable Autoneg */
3777 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
3778 MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x1000);
3779
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00003780}
3781
3782static void bnx2x_warpcore_set_10G_KR(struct bnx2x_phy *phy,
3783 struct link_params *params,
3784 struct link_vars *vars)
3785{
3786 struct bnx2x *bp = params->bp;
3787 u16 val;
3788
3789 /* Disable Autoneg */
3790 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3791 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, 0x7);
3792
3793 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
3794 MDIO_WC_REG_PAR_DET_10G_CTRL, 0);
3795
3796 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3797 MDIO_WC_REG_CL72_USERB0_CL72_MISC1_CONTROL, 0x3f00);
3798
3799 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
3800 MDIO_WC_REG_AN_IEEE1BLK_AN_ADVERTISEMENT1, 0);
3801
3802 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
3803 MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x0);
3804
3805 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3806 MDIO_WC_REG_DIGITAL3_UP1, 0x1);
3807
3808 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3809 MDIO_WC_REG_DIGITAL5_MISC7, 0xa);
3810
3811 /* Disable CL36 PCS Tx */
3812 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3813 MDIO_WC_REG_XGXSBLK1_LANECTRL0, 0x0);
3814
3815 /* Double Wide Single Data Rate @ pll rate */
3816 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3817 MDIO_WC_REG_XGXSBLK1_LANECTRL1, 0xFFFF);
3818
3819 /* Leave cl72 training enable, needed for KR */
3820 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD,
3821 MDIO_WC_REG_PMD_IEEE9BLK_TENGBASE_KR_PMD_CONTROL_REGISTER_150,
3822 0x2);
3823
3824 /* Leave CL72 enabled */
3825 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3826 MDIO_WC_REG_CL72_USERB0_CL72_MISC1_CONTROL,
3827 &val);
3828 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3829 MDIO_WC_REG_CL72_USERB0_CL72_MISC1_CONTROL,
3830 val | 0x3800);
3831
3832 /* Set speed via PMA/PMD register */
3833 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD,
3834 MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x2040);
3835
3836 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD,
3837 MDIO_WC_REG_IEEE0BLK_AUTONEGNP, 0xB);
3838
3839 /*Enable encoded forced speed */
3840 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3841 MDIO_WC_REG_SERDESDIGITAL_MISC2, 0x30);
3842
3843 /* Turn TX scramble payload only the 64/66 scrambler */
3844 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3845 MDIO_WC_REG_TX66_CONTROL, 0x9);
3846
3847 /* Turn RX scramble payload only the 64/66 scrambler */
3848 bnx2x_cl45_read_or_write(bp, phy, MDIO_WC_DEVAD,
3849 MDIO_WC_REG_RX66_CONTROL, 0xF9);
3850
3851 /* set and clear loopback to cause a reset to 64/66 decoder */
3852 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3853 MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x4000);
3854 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3855 MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x0);
3856
3857}
3858
3859static void bnx2x_warpcore_set_10G_XFI(struct bnx2x_phy *phy,
3860 struct link_params *params,
3861 u8 is_xfi)
3862{
3863 struct bnx2x *bp = params->bp;
3864 u16 misc1_val, tap_val, tx_driver_val, lane, val;
3865 /* Hold rxSeqStart */
3866 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3867 MDIO_WC_REG_DSC2B0_DSC_MISC_CTRL0, &val);
3868 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3869 MDIO_WC_REG_DSC2B0_DSC_MISC_CTRL0, (val | 0x8000));
3870
3871 /* Hold tx_fifo_reset */
3872 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3873 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X3, &val);
3874 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3875 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X3, (val | 0x1));
3876
3877 /* Disable CL73 AN */
3878 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0);
3879
3880 /* Disable 100FX Enable and Auto-Detect */
3881 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3882 MDIO_WC_REG_FX100_CTRL1, &val);
3883 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3884 MDIO_WC_REG_FX100_CTRL1, (val & 0xFFFA));
3885
3886 /* Disable 100FX Idle detect */
3887 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3888 MDIO_WC_REG_FX100_CTRL3, &val);
3889 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3890 MDIO_WC_REG_FX100_CTRL3, (val | 0x0080));
3891
3892 /* Set Block address to Remote PHY & Clear forced_speed[5] */
3893 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3894 MDIO_WC_REG_DIGITAL4_MISC3, &val);
3895 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3896 MDIO_WC_REG_DIGITAL4_MISC3, (val & 0xFF7F));
3897
3898 /* Turn off auto-detect & fiber mode */
3899 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3900 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1, &val);
3901 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3902 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1,
3903 (val & 0xFFEE));
3904
3905 /* Set filter_force_link, disable_false_link and parallel_detect */
3906 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3907 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, &val);
3908 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3909 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2,
3910 ((val | 0x0006) & 0xFFFE));
3911
3912 /* Set XFI / SFI */
3913 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3914 MDIO_WC_REG_SERDESDIGITAL_MISC1, &misc1_val);
3915
3916 misc1_val &= ~(0x1f);
3917
3918 if (is_xfi) {
3919 misc1_val |= 0x5;
3920 tap_val = ((0x08 << MDIO_WC_REG_TX_FIR_TAP_POST_TAP_OFFSET) |
3921 (0x37 << MDIO_WC_REG_TX_FIR_TAP_MAIN_TAP_OFFSET) |
3922 (0x00 << MDIO_WC_REG_TX_FIR_TAP_PRE_TAP_OFFSET));
3923 tx_driver_val =
3924 ((0x00 << MDIO_WC_REG_TX0_TX_DRIVER_POST2_COEFF_OFFSET) |
3925 (0x02 << MDIO_WC_REG_TX0_TX_DRIVER_IDRIVER_OFFSET) |
3926 (0x03 << MDIO_WC_REG_TX0_TX_DRIVER_IPRE_DRIVER_OFFSET));
3927
3928 } else {
3929 misc1_val |= 0x9;
3930 tap_val = ((0x12 << MDIO_WC_REG_TX_FIR_TAP_POST_TAP_OFFSET) |
3931 (0x2d << MDIO_WC_REG_TX_FIR_TAP_MAIN_TAP_OFFSET) |
3932 (0x00 << MDIO_WC_REG_TX_FIR_TAP_PRE_TAP_OFFSET));
3933 tx_driver_val =
3934 ((0x02 << MDIO_WC_REG_TX0_TX_DRIVER_POST2_COEFF_OFFSET) |
3935 (0x02 << MDIO_WC_REG_TX0_TX_DRIVER_IDRIVER_OFFSET) |
3936 (0x02 << MDIO_WC_REG_TX0_TX_DRIVER_IPRE_DRIVER_OFFSET));
3937 }
3938 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3939 MDIO_WC_REG_SERDESDIGITAL_MISC1, misc1_val);
3940
3941 /* Set Transmit PMD settings */
3942 lane = bnx2x_get_warpcore_lane(phy, params);
3943 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3944 MDIO_WC_REG_TX_FIR_TAP,
3945 tap_val | MDIO_WC_REG_TX_FIR_TAP_ENABLE);
3946 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3947 MDIO_WC_REG_TX0_TX_DRIVER + 0x10*lane,
3948 tx_driver_val);
3949
3950 /* Enable fiber mode, enable and invert sig_det */
3951 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3952 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1, &val);
3953 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3954 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1, val | 0xd);
3955
3956 /* Set Block address to Remote PHY & Set forced_speed[5], 40bit mode */
3957 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3958 MDIO_WC_REG_DIGITAL4_MISC3, &val);
3959 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3960 MDIO_WC_REG_DIGITAL4_MISC3, val | 0x8080);
3961
3962 /* 10G XFI Full Duplex */
3963 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3964 MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x100);
3965
3966 /* Release tx_fifo_reset */
3967 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3968 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X3, &val);
3969 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3970 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X3, val & 0xFFFE);
3971
3972 /* Release rxSeqStart */
3973 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
3974 MDIO_WC_REG_DSC2B0_DSC_MISC_CTRL0, &val);
3975 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3976 MDIO_WC_REG_DSC2B0_DSC_MISC_CTRL0, (val & 0x7FFF));
3977}
3978
3979static void bnx2x_warpcore_set_20G_KR2(struct bnx2x *bp,
3980 struct bnx2x_phy *phy)
3981{
3982 DP(NETIF_MSG_LINK, "KR2 still not supported !!!\n");
3983}
3984
3985static void bnx2x_warpcore_set_20G_DXGXS(struct bnx2x *bp,
3986 struct bnx2x_phy *phy,
3987 u16 lane)
3988{
3989 /* Rx0 anaRxControl1G */
3990 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3991 MDIO_WC_REG_RX0_ANARXCONTROL1G, 0x90);
3992
3993 /* Rx2 anaRxControl1G */
3994 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3995 MDIO_WC_REG_RX2_ANARXCONTROL1G, 0x90);
3996
3997 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
3998 MDIO_WC_REG_RX66_SCW0, 0xE070);
3999
4000 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4001 MDIO_WC_REG_RX66_SCW1, 0xC0D0);
4002
4003 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4004 MDIO_WC_REG_RX66_SCW2, 0xA0B0);
4005
4006 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4007 MDIO_WC_REG_RX66_SCW3, 0x8090);
4008
4009 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4010 MDIO_WC_REG_RX66_SCW0_MASK, 0xF0F0);
4011
4012 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4013 MDIO_WC_REG_RX66_SCW1_MASK, 0xF0F0);
4014
4015 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4016 MDIO_WC_REG_RX66_SCW2_MASK, 0xF0F0);
4017
4018 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4019 MDIO_WC_REG_RX66_SCW3_MASK, 0xF0F0);
4020
4021 /* Serdes Digital Misc1 */
4022 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4023 MDIO_WC_REG_SERDESDIGITAL_MISC1, 0x6008);
4024
4025 /* Serdes Digital4 Misc3 */
4026 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4027 MDIO_WC_REG_DIGITAL4_MISC3, 0x8088);
4028
4029 /* Set Transmit PMD settings */
4030 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4031 MDIO_WC_REG_TX_FIR_TAP,
4032 ((0x12 << MDIO_WC_REG_TX_FIR_TAP_POST_TAP_OFFSET) |
4033 (0x2d << MDIO_WC_REG_TX_FIR_TAP_MAIN_TAP_OFFSET) |
4034 (0x00 << MDIO_WC_REG_TX_FIR_TAP_PRE_TAP_OFFSET) |
4035 MDIO_WC_REG_TX_FIR_TAP_ENABLE));
4036 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4037 MDIO_WC_REG_TX0_TX_DRIVER + 0x10*lane,
4038 ((0x02 << MDIO_WC_REG_TX0_TX_DRIVER_POST2_COEFF_OFFSET) |
4039 (0x02 << MDIO_WC_REG_TX0_TX_DRIVER_IDRIVER_OFFSET) |
4040 (0x02 << MDIO_WC_REG_TX0_TX_DRIVER_IPRE_DRIVER_OFFSET)));
4041}
4042
4043static void bnx2x_warpcore_set_sgmii_speed(struct bnx2x_phy *phy,
4044 struct link_params *params,
Yaniv Rosner521683d2011-11-28 00:49:48 +00004045 u8 fiber_mode,
4046 u8 always_autoneg)
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004047{
4048 struct bnx2x *bp = params->bp;
4049 u16 val16, digctrl_kx1, digctrl_kx2;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004050
4051 /* Clear XFI clock comp in non-10G single lane mode. */
4052 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
4053 MDIO_WC_REG_RX66_CONTROL, &val16);
4054 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4055 MDIO_WC_REG_RX66_CONTROL, val16 & ~(3<<13));
4056
Yaniv Rosner521683d2011-11-28 00:49:48 +00004057 if (always_autoneg || phy->req_line_speed == SPEED_AUTO_NEG) {
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004058 /* SGMII Autoneg */
4059 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
4060 MDIO_WC_REG_COMBO_IEEE0_MIICTRL, &val16);
4061 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4062 MDIO_WC_REG_COMBO_IEEE0_MIICTRL,
4063 val16 | 0x1000);
4064 DP(NETIF_MSG_LINK, "set SGMII AUTONEG\n");
4065 } else {
4066 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
4067 MDIO_WC_REG_COMBO_IEEE0_MIICTRL, &val16);
Yaniv Rosner521683d2011-11-28 00:49:48 +00004068 val16 &= 0xcebf;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004069 switch (phy->req_line_speed) {
4070 case SPEED_10:
4071 break;
4072 case SPEED_100:
4073 val16 |= 0x2000;
4074 break;
4075 case SPEED_1000:
4076 val16 |= 0x0040;
4077 break;
4078 default:
Joe Perches94f05b02011-08-14 12:16:20 +00004079 DP(NETIF_MSG_LINK,
4080 "Speed not supported: 0x%x\n", phy->req_line_speed);
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004081 return;
4082 }
4083
4084 if (phy->req_duplex == DUPLEX_FULL)
4085 val16 |= 0x0100;
4086
4087 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4088 MDIO_WC_REG_COMBO_IEEE0_MIICTRL, val16);
4089
4090 DP(NETIF_MSG_LINK, "set SGMII force speed %d\n",
4091 phy->req_line_speed);
4092 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
4093 MDIO_WC_REG_COMBO_IEEE0_MIICTRL, &val16);
4094 DP(NETIF_MSG_LINK, " (readback) %x\n", val16);
4095 }
4096
4097 /* SGMII Slave mode and disable signal detect */
4098 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
4099 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1, &digctrl_kx1);
4100 if (fiber_mode)
4101 digctrl_kx1 = 1;
4102 else
4103 digctrl_kx1 &= 0xff4a;
4104
4105 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4106 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1,
4107 digctrl_kx1);
4108
4109 /* Turn off parallel detect */
4110 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
4111 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, &digctrl_kx2);
4112 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4113 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2,
4114 (digctrl_kx2 & ~(1<<2)));
4115
4116 /* Re-enable parallel detect */
4117 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4118 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2,
4119 (digctrl_kx2 | (1<<2)));
4120
4121 /* Enable autodet */
4122 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4123 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1,
4124 (digctrl_kx1 | 0x10));
4125}
4126
4127static void bnx2x_warpcore_reset_lane(struct bnx2x *bp,
4128 struct bnx2x_phy *phy,
4129 u8 reset)
4130{
4131 u16 val;
4132 /* Take lane out of reset after configuration is finished */
4133 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
4134 MDIO_WC_REG_DIGITAL5_MISC6, &val);
4135 if (reset)
4136 val |= 0xC000;
4137 else
4138 val &= 0x3FFF;
4139 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4140 MDIO_WC_REG_DIGITAL5_MISC6, val);
4141 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
4142 MDIO_WC_REG_DIGITAL5_MISC6, &val);
4143}
Yaniv Rosner2f751a82011-11-28 00:49:52 +00004144/* Clear SFI/XFI link settings registers */
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004145static void bnx2x_warpcore_clear_regs(struct bnx2x_phy *phy,
4146 struct link_params *params,
4147 u16 lane)
4148{
4149 struct bnx2x *bp = params->bp;
4150 u16 val16;
4151
4152 /* Set XFI clock comp as default. */
4153 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
4154 MDIO_WC_REG_RX66_CONTROL, &val16);
4155 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4156 MDIO_WC_REG_RX66_CONTROL, val16 | (3<<13));
4157
4158 bnx2x_warpcore_reset_lane(bp, phy, 1);
4159 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0);
4160 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4161 MDIO_WC_REG_FX100_CTRL1, 0x014a);
4162 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4163 MDIO_WC_REG_FX100_CTRL3, 0x0800);
4164 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4165 MDIO_WC_REG_DIGITAL4_MISC3, 0x8008);
4166 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4167 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1, 0x0195);
4168 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4169 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, 0x0007);
4170 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4171 MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X3, 0x0002);
4172 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4173 MDIO_WC_REG_SERDESDIGITAL_MISC1, 0x6000);
4174 lane = bnx2x_get_warpcore_lane(phy, params);
4175 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4176 MDIO_WC_REG_TX_FIR_TAP, 0x0000);
4177 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4178 MDIO_WC_REG_TX0_TX_DRIVER + 0x10*lane, 0x0990);
4179 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4180 MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x2040);
4181 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4182 MDIO_WC_REG_COMBO_IEEE0_MIICTRL, 0x0140);
4183 bnx2x_warpcore_reset_lane(bp, phy, 0);
4184}
4185
4186static int bnx2x_get_mod_abs_int_cfg(struct bnx2x *bp,
4187 u32 chip_id,
4188 u32 shmem_base, u8 port,
4189 u8 *gpio_num, u8 *gpio_port)
4190{
4191 u32 cfg_pin;
4192 *gpio_num = 0;
4193 *gpio_port = 0;
4194 if (CHIP_IS_E3(bp)) {
4195 cfg_pin = (REG_RD(bp, shmem_base +
4196 offsetof(struct shmem_region,
4197 dev_info.port_hw_config[port].e3_sfp_ctrl)) &
4198 PORT_HW_CFG_E3_MOD_ABS_MASK) >>
4199 PORT_HW_CFG_E3_MOD_ABS_SHIFT;
4200
4201 /*
4202 * Should not happen. This function called upon interrupt
4203 * triggered by GPIO ( since EPIO can only generate interrupts
4204 * to MCP).
4205 * So if this function was called and none of the GPIOs was set,
4206 * it means the shit hit the fan.
4207 */
4208 if ((cfg_pin < PIN_CFG_GPIO0_P0) ||
4209 (cfg_pin > PIN_CFG_GPIO3_P1)) {
Joe Perches94f05b02011-08-14 12:16:20 +00004210 DP(NETIF_MSG_LINK,
4211 "ERROR: Invalid cfg pin %x for module detect indication\n",
4212 cfg_pin);
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004213 return -EINVAL;
4214 }
4215
4216 *gpio_num = (cfg_pin - PIN_CFG_GPIO0_P0) & 0x3;
4217 *gpio_port = (cfg_pin - PIN_CFG_GPIO0_P0) >> 2;
4218 } else {
4219 *gpio_num = MISC_REGISTERS_GPIO_3;
4220 *gpio_port = port;
4221 }
4222 DP(NETIF_MSG_LINK, "MOD_ABS int GPIO%d_P%d\n", *gpio_num, *gpio_port);
4223 return 0;
4224}
4225
4226static int bnx2x_is_sfp_module_plugged(struct bnx2x_phy *phy,
4227 struct link_params *params)
4228{
4229 struct bnx2x *bp = params->bp;
4230 u8 gpio_num, gpio_port;
4231 u32 gpio_val;
4232 if (bnx2x_get_mod_abs_int_cfg(bp, params->chip_id,
4233 params->shmem_base, params->port,
4234 &gpio_num, &gpio_port) != 0)
4235 return 0;
4236 gpio_val = bnx2x_get_gpio(bp, gpio_num, gpio_port);
4237
4238 /* Call the handling function in case module is detected */
4239 if (gpio_val == 0)
4240 return 1;
4241 else
4242 return 0;
4243}
Yaniv Rosnera9077bf2011-10-27 05:09:46 +00004244static int bnx2x_warpcore_get_sigdet(struct bnx2x_phy *phy,
4245 struct link_params *params)
4246{
4247 u16 gp2_status_reg0, lane;
4248 struct bnx2x *bp = params->bp;
4249
4250 lane = bnx2x_get_warpcore_lane(phy, params);
4251
4252 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, MDIO_WC_REG_GP2_STATUS_GP_2_0,
4253 &gp2_status_reg0);
4254
4255 return (gp2_status_reg0 >> (8+lane)) & 0x1;
4256}
4257
4258static void bnx2x_warpcore_config_runtime(struct bnx2x_phy *phy,
4259 struct link_params *params,
4260 struct link_vars *vars)
4261{
4262 struct bnx2x *bp = params->bp;
4263 u32 serdes_net_if;
4264 u16 gp_status1 = 0, lnkup = 0, lnkup_kr = 0;
4265 u16 lane = bnx2x_get_warpcore_lane(phy, params);
4266
4267 vars->turn_to_run_wc_rt = vars->turn_to_run_wc_rt ? 0 : 1;
4268
4269 if (!vars->turn_to_run_wc_rt)
4270 return;
4271
4272 /* return if there is no link partner */
4273 if (!(bnx2x_warpcore_get_sigdet(phy, params))) {
4274 DP(NETIF_MSG_LINK, "bnx2x_warpcore_get_sigdet false\n");
4275 return;
4276 }
4277
4278 if (vars->rx_tx_asic_rst) {
4279 serdes_net_if = (REG_RD(bp, params->shmem_base +
4280 offsetof(struct shmem_region, dev_info.
4281 port_hw_config[params->port].default_cfg)) &
4282 PORT_HW_CFG_NET_SERDES_IF_MASK);
4283
4284 switch (serdes_net_if) {
4285 case PORT_HW_CFG_NET_SERDES_IF_KR:
4286 /* Do we get link yet? */
4287 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, 0x81d1,
4288 &gp_status1);
4289 lnkup = (gp_status1 >> (8+lane)) & 0x1;/* 1G */
4290 /*10G KR*/
4291 lnkup_kr = (gp_status1 >> (12+lane)) & 0x1;
4292
4293 DP(NETIF_MSG_LINK,
4294 "gp_status1 0x%x\n", gp_status1);
4295
4296 if (lnkup_kr || lnkup) {
4297 vars->rx_tx_asic_rst = 0;
4298 DP(NETIF_MSG_LINK,
4299 "link up, rx_tx_asic_rst 0x%x\n",
4300 vars->rx_tx_asic_rst);
4301 } else {
4302 /*reset the lane to see if link comes up.*/
4303 bnx2x_warpcore_reset_lane(bp, phy, 1);
4304 bnx2x_warpcore_reset_lane(bp, phy, 0);
4305
4306 /* restart Autoneg */
4307 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
4308 MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x1200);
4309
4310 vars->rx_tx_asic_rst--;
4311 DP(NETIF_MSG_LINK, "0x%x retry left\n",
4312 vars->rx_tx_asic_rst);
4313 }
4314 break;
4315
4316 default:
4317 break;
4318 }
4319
4320 } /*params->rx_tx_asic_rst*/
4321
4322}
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004323
4324static void bnx2x_warpcore_config_init(struct bnx2x_phy *phy,
4325 struct link_params *params,
4326 struct link_vars *vars)
4327{
4328 struct bnx2x *bp = params->bp;
4329 u32 serdes_net_if;
4330 u8 fiber_mode;
4331 u16 lane = bnx2x_get_warpcore_lane(phy, params);
4332 serdes_net_if = (REG_RD(bp, params->shmem_base +
4333 offsetof(struct shmem_region, dev_info.
4334 port_hw_config[params->port].default_cfg)) &
4335 PORT_HW_CFG_NET_SERDES_IF_MASK);
4336 DP(NETIF_MSG_LINK, "Begin Warpcore init, link_speed %d, "
4337 "serdes_net_if = 0x%x\n",
4338 vars->line_speed, serdes_net_if);
4339 bnx2x_set_aer_mmd(params, phy);
4340
4341 vars->phy_flags |= PHY_XGXS_FLAG;
4342 if ((serdes_net_if == PORT_HW_CFG_NET_SERDES_IF_SGMII) ||
4343 (phy->req_line_speed &&
4344 ((phy->req_line_speed == SPEED_100) ||
4345 (phy->req_line_speed == SPEED_10)))) {
4346 vars->phy_flags |= PHY_SGMII_FLAG;
4347 DP(NETIF_MSG_LINK, "Setting SGMII mode\n");
4348 bnx2x_warpcore_clear_regs(phy, params, lane);
Yaniv Rosner521683d2011-11-28 00:49:48 +00004349 bnx2x_warpcore_set_sgmii_speed(phy, params, 0, 1);
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004350 } else {
4351 switch (serdes_net_if) {
4352 case PORT_HW_CFG_NET_SERDES_IF_KR:
4353 /* Enable KR Auto Neg */
4354 if (params->loopback_mode == LOOPBACK_NONE)
4355 bnx2x_warpcore_enable_AN_KR(phy, params, vars);
4356 else {
4357 DP(NETIF_MSG_LINK, "Setting KR 10G-Force\n");
4358 bnx2x_warpcore_set_10G_KR(phy, params, vars);
4359 }
4360 break;
4361
4362 case PORT_HW_CFG_NET_SERDES_IF_XFI:
4363 bnx2x_warpcore_clear_regs(phy, params, lane);
4364 if (vars->line_speed == SPEED_10000) {
4365 DP(NETIF_MSG_LINK, "Setting 10G XFI\n");
4366 bnx2x_warpcore_set_10G_XFI(phy, params, 1);
4367 } else {
4368 if (SINGLE_MEDIA_DIRECT(params)) {
4369 DP(NETIF_MSG_LINK, "1G Fiber\n");
4370 fiber_mode = 1;
4371 } else {
4372 DP(NETIF_MSG_LINK, "10/100/1G SGMII\n");
4373 fiber_mode = 0;
4374 }
4375 bnx2x_warpcore_set_sgmii_speed(phy,
4376 params,
Yaniv Rosner521683d2011-11-28 00:49:48 +00004377 fiber_mode,
4378 0);
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004379 }
4380
4381 break;
4382
4383 case PORT_HW_CFG_NET_SERDES_IF_SFI:
4384
4385 bnx2x_warpcore_clear_regs(phy, params, lane);
4386 if (vars->line_speed == SPEED_10000) {
4387 DP(NETIF_MSG_LINK, "Setting 10G SFI\n");
4388 bnx2x_warpcore_set_10G_XFI(phy, params, 0);
4389 } else if (vars->line_speed == SPEED_1000) {
4390 DP(NETIF_MSG_LINK, "Setting 1G Fiber\n");
Yaniv Rosner521683d2011-11-28 00:49:48 +00004391 bnx2x_warpcore_set_sgmii_speed(
4392 phy, params, 1, 0);
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004393 }
4394 /* Issue Module detection */
4395 if (bnx2x_is_sfp_module_plugged(phy, params))
4396 bnx2x_sfp_module_detection(phy, params);
4397 break;
4398
4399 case PORT_HW_CFG_NET_SERDES_IF_DXGXS:
4400 if (vars->line_speed != SPEED_20000) {
4401 DP(NETIF_MSG_LINK, "Speed not supported yet\n");
4402 return;
4403 }
4404 DP(NETIF_MSG_LINK, "Setting 20G DXGXS\n");
4405 bnx2x_warpcore_set_20G_DXGXS(bp, phy, lane);
4406 /* Issue Module detection */
4407
4408 bnx2x_sfp_module_detection(phy, params);
4409 break;
4410
4411 case PORT_HW_CFG_NET_SERDES_IF_KR2:
4412 if (vars->line_speed != SPEED_20000) {
4413 DP(NETIF_MSG_LINK, "Speed not supported yet\n");
4414 return;
4415 }
4416 DP(NETIF_MSG_LINK, "Setting 20G KR2\n");
4417 bnx2x_warpcore_set_20G_KR2(bp, phy);
4418 break;
4419
4420 default:
Joe Perches94f05b02011-08-14 12:16:20 +00004421 DP(NETIF_MSG_LINK,
4422 "Unsupported Serdes Net Interface 0x%x\n",
4423 serdes_net_if);
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004424 return;
4425 }
4426 }
4427
4428 /* Take lane out of reset after configuration is finished */
4429 bnx2x_warpcore_reset_lane(bp, phy, 0);
4430 DP(NETIF_MSG_LINK, "Exit config init\n");
4431}
4432
4433static void bnx2x_sfp_e3_set_transmitter(struct link_params *params,
4434 struct bnx2x_phy *phy,
4435 u8 tx_en)
4436{
4437 struct bnx2x *bp = params->bp;
4438 u32 cfg_pin;
4439 u8 port = params->port;
4440
4441 cfg_pin = REG_RD(bp, params->shmem_base +
4442 offsetof(struct shmem_region,
4443 dev_info.port_hw_config[port].e3_sfp_ctrl)) &
4444 PORT_HW_CFG_TX_LASER_MASK;
4445 /* Set the !tx_en since this pin is DISABLE_TX_LASER */
4446 DP(NETIF_MSG_LINK, "Setting WC TX to %d\n", tx_en);
4447 /* For 20G, the expected pin to be used is 3 pins after the current */
4448
4449 bnx2x_set_cfg_pin(bp, cfg_pin, tx_en ^ 1);
4450 if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_20G)
4451 bnx2x_set_cfg_pin(bp, cfg_pin + 3, tx_en ^ 1);
4452}
4453
4454static void bnx2x_warpcore_link_reset(struct bnx2x_phy *phy,
4455 struct link_params *params)
4456{
4457 struct bnx2x *bp = params->bp;
4458 u16 val16;
4459 bnx2x_sfp_e3_set_transmitter(params, phy, 0);
4460 bnx2x_set_mdio_clk(bp, params->chip_id, params->port);
4461 bnx2x_set_aer_mmd(params, phy);
4462 /* Global register */
4463 bnx2x_warpcore_reset_lane(bp, phy, 1);
4464
4465 /* Clear loopback settings (if any) */
4466 /* 10G & 20G */
4467 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
4468 MDIO_WC_REG_COMBO_IEEE0_MIICTRL, &val16);
4469 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4470 MDIO_WC_REG_COMBO_IEEE0_MIICTRL, val16 &
4471 0xBFFF);
4472
4473 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
4474 MDIO_WC_REG_IEEE0BLK_MIICNTL, &val16);
4475 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4476 MDIO_WC_REG_IEEE0BLK_MIICNTL, val16 & 0xfffe);
4477
4478 /* Update those 1-copy registers */
4479 CL22_WR_OVER_CL45(bp, phy, MDIO_REG_BANK_AER_BLOCK,
4480 MDIO_AER_BLOCK_AER_REG, 0);
4481 /* Enable 1G MDIO (1-copy) */
4482 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
4483 MDIO_WC_REG_XGXSBLK0_XGXSCONTROL,
4484 &val16);
4485 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4486 MDIO_WC_REG_XGXSBLK0_XGXSCONTROL,
4487 val16 & ~0x10);
4488
4489 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
4490 MDIO_WC_REG_XGXSBLK1_LANECTRL2, &val16);
4491 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4492 MDIO_WC_REG_XGXSBLK1_LANECTRL2,
4493 val16 & 0xff00);
4494
4495}
4496
4497static void bnx2x_set_warpcore_loopback(struct bnx2x_phy *phy,
4498 struct link_params *params)
4499{
4500 struct bnx2x *bp = params->bp;
4501 u16 val16;
4502 u32 lane;
4503 DP(NETIF_MSG_LINK, "Setting Warpcore loopback type %x, speed %d\n",
4504 params->loopback_mode, phy->req_line_speed);
4505
4506 if (phy->req_line_speed < SPEED_10000) {
4507 /* 10/100/1000 */
4508
4509 /* Update those 1-copy registers */
4510 CL22_WR_OVER_CL45(bp, phy, MDIO_REG_BANK_AER_BLOCK,
4511 MDIO_AER_BLOCK_AER_REG, 0);
4512 /* Enable 1G MDIO (1-copy) */
4513 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
4514 MDIO_WC_REG_XGXSBLK0_XGXSCONTROL,
4515 &val16);
4516 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4517 MDIO_WC_REG_XGXSBLK0_XGXSCONTROL,
4518 val16 | 0x10);
4519 /* Set 1G loopback based on lane (1-copy) */
4520 lane = bnx2x_get_warpcore_lane(phy, params);
4521 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
4522 MDIO_WC_REG_XGXSBLK1_LANECTRL2, &val16);
4523 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4524 MDIO_WC_REG_XGXSBLK1_LANECTRL2,
4525 val16 | (1<<lane));
4526
4527 /* Switch back to 4-copy registers */
4528 bnx2x_set_aer_mmd(params, phy);
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004529 } else {
4530 /* 10G & 20G */
4531 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
4532 MDIO_WC_REG_COMBO_IEEE0_MIICTRL, &val16);
4533 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4534 MDIO_WC_REG_COMBO_IEEE0_MIICTRL, val16 |
4535 0x4000);
4536
4537 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
4538 MDIO_WC_REG_IEEE0BLK_MIICNTL, &val16);
4539 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
4540 MDIO_WC_REG_IEEE0BLK_MIICNTL, val16 | 0x1);
4541 }
4542}
4543
4544
Yaniv Rosner2f751a82011-11-28 00:49:52 +00004545void bnx2x_sync_link(struct link_params *params,
4546 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004547{
4548 struct bnx2x *bp = params->bp;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00004549 u8 link_10g_plus;
Yaniv Rosnerde6f3372011-08-02 22:59:25 +00004550 if (vars->link_status & LINK_STATUS_PHYSICAL_LINK_FLAG)
4551 vars->phy_flags |= PHY_PHYSICAL_LINK_FLAG;
Yaniv Rosner2f751a82011-11-28 00:49:52 +00004552 vars->link_up = (vars->link_status & LINK_STATUS_LINK_UP);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004553 if (vars->link_up) {
4554 DP(NETIF_MSG_LINK, "phy link up\n");
4555
4556 vars->phy_link_up = 1;
4557 vars->duplex = DUPLEX_FULL;
4558 switch (vars->link_status &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004559 LINK_STATUS_SPEED_AND_DUPLEX_MASK) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004560 case LINK_10THD:
4561 vars->duplex = DUPLEX_HALF;
4562 /* fall thru */
4563 case LINK_10TFD:
4564 vars->line_speed = SPEED_10;
4565 break;
4566
4567 case LINK_100TXHD:
4568 vars->duplex = DUPLEX_HALF;
4569 /* fall thru */
4570 case LINK_100T4:
4571 case LINK_100TXFD:
4572 vars->line_speed = SPEED_100;
4573 break;
4574
4575 case LINK_1000THD:
4576 vars->duplex = DUPLEX_HALF;
4577 /* fall thru */
4578 case LINK_1000TFD:
4579 vars->line_speed = SPEED_1000;
4580 break;
4581
4582 case LINK_2500THD:
4583 vars->duplex = DUPLEX_HALF;
4584 /* fall thru */
4585 case LINK_2500TFD:
4586 vars->line_speed = SPEED_2500;
4587 break;
4588
4589 case LINK_10GTFD:
4590 vars->line_speed = SPEED_10000;
4591 break;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004592 case LINK_20GTFD:
4593 vars->line_speed = SPEED_20000;
4594 break;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004595 default:
4596 break;
4597 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004598 vars->flow_ctrl = 0;
4599 if (vars->link_status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED)
4600 vars->flow_ctrl |= BNX2X_FLOW_CTRL_TX;
4601
4602 if (vars->link_status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED)
4603 vars->flow_ctrl |= BNX2X_FLOW_CTRL_RX;
4604
4605 if (!vars->flow_ctrl)
4606 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
4607
4608 if (vars->line_speed &&
4609 ((vars->line_speed == SPEED_10) ||
4610 (vars->line_speed == SPEED_100))) {
4611 vars->phy_flags |= PHY_SGMII_FLAG;
4612 } else {
4613 vars->phy_flags &= ~PHY_SGMII_FLAG;
4614 }
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004615 if (vars->line_speed &&
4616 USES_WARPCORE(bp) &&
4617 (vars->line_speed == SPEED_1000))
4618 vars->phy_flags |= PHY_SGMII_FLAG;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004619 /* anything 10 and over uses the bmac */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00004620 link_10g_plus = (vars->line_speed >= SPEED_10000);
4621
4622 if (link_10g_plus) {
4623 if (USES_WARPCORE(bp))
4624 vars->mac_type = MAC_TYPE_XMAC;
4625 else
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004626 vars->mac_type = MAC_TYPE_BMAC;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00004627 } else {
4628 if (USES_WARPCORE(bp))
4629 vars->mac_type = MAC_TYPE_UMAC;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00004630 else
4631 vars->mac_type = MAC_TYPE_EMAC;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00004632 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004633 } else { /* link down */
4634 DP(NETIF_MSG_LINK, "phy link down\n");
4635
4636 vars->phy_link_up = 0;
4637
4638 vars->line_speed = 0;
4639 vars->duplex = DUPLEX_FULL;
4640 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
4641
4642 /* indicate no mac active */
4643 vars->mac_type = MAC_TYPE_NONE;
Yaniv Rosnerde6f3372011-08-02 22:59:25 +00004644 if (vars->link_status & LINK_STATUS_PHYSICAL_LINK_FLAG)
4645 vars->phy_flags |= PHY_HALF_OPEN_CONN_FLAG;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004646 }
Yaniv Rosner2f751a82011-11-28 00:49:52 +00004647}
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004648
Yaniv Rosner2f751a82011-11-28 00:49:52 +00004649void bnx2x_link_status_update(struct link_params *params,
4650 struct link_vars *vars)
4651{
4652 struct bnx2x *bp = params->bp;
4653 u8 port = params->port;
4654 u32 sync_offset, media_types;
4655 /* Update PHY configuration */
4656 set_phy_vars(params, vars);
4657
4658 vars->link_status = REG_RD(bp, params->shmem_base +
4659 offsetof(struct shmem_region,
4660 port_mb[port].link_status));
4661
4662 vars->phy_flags = PHY_XGXS_FLAG;
4663 bnx2x_sync_link(params, vars);
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00004664 /* Sync media type */
4665 sync_offset = params->shmem_base +
4666 offsetof(struct shmem_region,
4667 dev_info.port_hw_config[port].media_type);
4668 media_types = REG_RD(bp, sync_offset);
4669
4670 params->phy[INT_PHY].media_type =
4671 (media_types & PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK) >>
4672 PORT_HW_CFG_MEDIA_TYPE_PHY0_SHIFT;
4673 params->phy[EXT_PHY1].media_type =
4674 (media_types & PORT_HW_CFG_MEDIA_TYPE_PHY1_MASK) >>
4675 PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT;
4676 params->phy[EXT_PHY2].media_type =
4677 (media_types & PORT_HW_CFG_MEDIA_TYPE_PHY2_MASK) >>
4678 PORT_HW_CFG_MEDIA_TYPE_PHY2_SHIFT;
4679 DP(NETIF_MSG_LINK, "media_types = 0x%x\n", media_types);
4680
Yaniv Rosner020c7e32011-05-31 21:28:43 +00004681 /* Sync AEU offset */
4682 sync_offset = params->shmem_base +
4683 offsetof(struct shmem_region,
4684 dev_info.port_hw_config[port].aeu_int_mask);
4685
4686 vars->aeu_int_mask = REG_RD(bp, sync_offset);
4687
Yaniv Rosnerb8d6d082011-07-05 01:06:27 +00004688 /* Sync PFC status */
4689 if (vars->link_status & LINK_STATUS_PFC_ENABLED)
4690 params->feature_config_flags |=
4691 FEATURE_CONFIG_PFC_ENABLED;
4692 else
4693 params->feature_config_flags &=
4694 ~FEATURE_CONFIG_PFC_ENABLED;
4695
Yaniv Rosner020c7e32011-05-31 21:28:43 +00004696 DP(NETIF_MSG_LINK, "link_status 0x%x phy_link_up %x int_mask 0x%x\n",
4697 vars->link_status, vars->phy_link_up, vars->aeu_int_mask);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004698 DP(NETIF_MSG_LINK, "line_speed %x duplex %x flow_ctrl 0x%x\n",
4699 vars->line_speed, vars->duplex, vars->flow_ctrl);
4700}
4701
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004702static void bnx2x_set_master_ln(struct link_params *params,
4703 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004704{
4705 struct bnx2x *bp = params->bp;
4706 u16 new_master_ln, ser_lane;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004707 ser_lane = ((params->lane_config &
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004708 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004709 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004710
4711 /* set the master_ln for AN */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004712 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004713 MDIO_REG_BANK_XGXS_BLOCK2,
4714 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
4715 &new_master_ln);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004716
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004717 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004718 MDIO_REG_BANK_XGXS_BLOCK2 ,
4719 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
4720 (new_master_ln | ser_lane));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004721}
4722
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00004723static int bnx2x_reset_unicore(struct link_params *params,
4724 struct bnx2x_phy *phy,
4725 u8 set_serdes)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004726{
4727 struct bnx2x *bp = params->bp;
4728 u16 mii_control;
4729 u16 i;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004730 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004731 MDIO_REG_BANK_COMBO_IEEE0,
4732 MDIO_COMBO_IEEE0_MII_CONTROL, &mii_control);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004733
4734 /* reset the unicore */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004735 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004736 MDIO_REG_BANK_COMBO_IEEE0,
4737 MDIO_COMBO_IEEE0_MII_CONTROL,
4738 (mii_control |
4739 MDIO_COMBO_IEEO_MII_CONTROL_RESET));
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004740 if (set_serdes)
4741 bnx2x_set_serdes_access(bp, params->port);
Eilon Greensteinc1b73992009-02-12 08:37:07 +00004742
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004743 /* wait for the reset to self clear */
4744 for (i = 0; i < MDIO_ACCESS_TIMEOUT; i++) {
4745 udelay(5);
4746
4747 /* the reset erased the previous bank value */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004748 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004749 MDIO_REG_BANK_COMBO_IEEE0,
4750 MDIO_COMBO_IEEE0_MII_CONTROL,
4751 &mii_control);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004752
4753 if (!(mii_control & MDIO_COMBO_IEEO_MII_CONTROL_RESET)) {
4754 udelay(5);
4755 return 0;
4756 }
4757 }
4758
Yaniv Rosner6d870c32011-01-31 04:22:20 +00004759 netdev_err(bp->dev, "Warning: PHY was not initialized,"
4760 " Port %d\n",
4761 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004762 DP(NETIF_MSG_LINK, "BUG! XGXS is still in reset!\n");
4763 return -EINVAL;
4764
4765}
4766
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004767static void bnx2x_set_swap_lanes(struct link_params *params,
4768 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004769{
4770 struct bnx2x *bp = params->bp;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004771 /*
4772 * Each two bits represents a lane number:
4773 * No swap is 0123 => 0x1b no need to enable the swap
4774 */
Yaniv Rosner2f751a82011-11-28 00:49:52 +00004775 u16 rx_lane_swap, tx_lane_swap;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004776
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004777 rx_lane_swap = ((params->lane_config &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004778 PORT_HW_CFG_LANE_SWAP_CFG_RX_MASK) >>
4779 PORT_HW_CFG_LANE_SWAP_CFG_RX_SHIFT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004780 tx_lane_swap = ((params->lane_config &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004781 PORT_HW_CFG_LANE_SWAP_CFG_TX_MASK) >>
4782 PORT_HW_CFG_LANE_SWAP_CFG_TX_SHIFT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004783
4784 if (rx_lane_swap != 0x1b) {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004785 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004786 MDIO_REG_BANK_XGXS_BLOCK2,
4787 MDIO_XGXS_BLOCK2_RX_LN_SWAP,
4788 (rx_lane_swap |
4789 MDIO_XGXS_BLOCK2_RX_LN_SWAP_ENABLE |
4790 MDIO_XGXS_BLOCK2_RX_LN_SWAP_FORCE_ENABLE));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004791 } else {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004792 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004793 MDIO_REG_BANK_XGXS_BLOCK2,
4794 MDIO_XGXS_BLOCK2_RX_LN_SWAP, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004795 }
4796
4797 if (tx_lane_swap != 0x1b) {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004798 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004799 MDIO_REG_BANK_XGXS_BLOCK2,
4800 MDIO_XGXS_BLOCK2_TX_LN_SWAP,
4801 (tx_lane_swap |
4802 MDIO_XGXS_BLOCK2_TX_LN_SWAP_ENABLE));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004803 } else {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004804 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004805 MDIO_REG_BANK_XGXS_BLOCK2,
4806 MDIO_XGXS_BLOCK2_TX_LN_SWAP, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004807 }
4808}
4809
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004810static void bnx2x_set_parallel_detection(struct bnx2x_phy *phy,
4811 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004812{
4813 struct bnx2x *bp = params->bp;
4814 u16 control2;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004815 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004816 MDIO_REG_BANK_SERDES_DIGITAL,
4817 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
4818 &control2);
Yaniv Rosner7aa07112010-09-07 11:41:01 +00004819 if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
Yaniv Rosner18afb0a2009-11-05 19:18:04 +02004820 control2 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
4821 else
4822 control2 &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00004823 DP(NETIF_MSG_LINK, "phy->speed_cap_mask = 0x%x, control2 = 0x%x\n",
4824 phy->speed_cap_mask, control2);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004825 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004826 MDIO_REG_BANK_SERDES_DIGITAL,
4827 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
4828 control2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004829
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004830 if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00004831 (phy->speed_cap_mask &
Yaniv Rosner18afb0a2009-11-05 19:18:04 +02004832 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004833 DP(NETIF_MSG_LINK, "XGXS\n");
4834
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_10G_PARALLEL_DETECT,
4837 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK,
4838 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004839
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004840 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004841 MDIO_REG_BANK_10G_PARALLEL_DETECT,
4842 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
4843 &control2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004844
4845
4846 control2 |=
4847 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN;
4848
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004849 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004850 MDIO_REG_BANK_10G_PARALLEL_DETECT,
4851 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
4852 control2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004853
4854 /* Disable parallel detection of HiG */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004855 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004856 MDIO_REG_BANK_XGXS_BLOCK2,
4857 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G,
4858 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_CX4_XGXS |
4859 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_HIGIG_XGXS);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004860 }
4861}
4862
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004863static void bnx2x_set_autoneg(struct bnx2x_phy *phy,
4864 struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004865 struct link_vars *vars,
4866 u8 enable_cl73)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004867{
4868 struct bnx2x *bp = params->bp;
4869 u16 reg_val;
4870
4871 /* CL37 Autoneg */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004872 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004873 MDIO_REG_BANK_COMBO_IEEE0,
4874 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004875
4876 /* CL37 Autoneg Enabled */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07004877 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004878 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_AN_EN;
4879 else /* CL37 Autoneg Disabled */
4880 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
4881 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN);
4882
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004883 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004884 MDIO_REG_BANK_COMBO_IEEE0,
4885 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004886
4887 /* Enable/Disable Autodetection */
4888
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004889 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004890 MDIO_REG_BANK_SERDES_DIGITAL,
4891 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, &reg_val);
Eilon Greenstein239d6862009-08-12 08:23:04 +00004892 reg_val &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN |
4893 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT);
4894 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07004895 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004896 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
4897 else
4898 reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
4899
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004900 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004901 MDIO_REG_BANK_SERDES_DIGITAL,
4902 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004903
4904 /* Enable TetonII and BAM autoneg */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004905 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004906 MDIO_REG_BANK_BAM_NEXT_PAGE,
4907 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004908 &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07004909 if (vars->line_speed == SPEED_AUTO_NEG) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004910 /* Enable BAM aneg Mode and TetonII aneg Mode */
4911 reg_val |= (MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
4912 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
4913 } else {
4914 /* TetonII and BAM Autoneg Disabled */
4915 reg_val &= ~(MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
4916 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
4917 }
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004918 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004919 MDIO_REG_BANK_BAM_NEXT_PAGE,
4920 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
4921 reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004922
Eilon Greenstein239d6862009-08-12 08:23:04 +00004923 if (enable_cl73) {
4924 /* Enable Cl73 FSM status bits */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004925 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004926 MDIO_REG_BANK_CL73_USERB0,
4927 MDIO_CL73_USERB0_CL73_UCTRL,
4928 0xe);
Eilon Greenstein239d6862009-08-12 08:23:04 +00004929
4930 /* Enable BAM Station Manager*/
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004931 CL22_WR_OVER_CL45(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00004932 MDIO_REG_BANK_CL73_USERB0,
4933 MDIO_CL73_USERB0_CL73_BAM_CTRL1,
4934 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN |
4935 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_STATION_MNGR_EN |
4936 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN);
4937
Yaniv Rosner7846e472009-11-05 19:18:07 +02004938 /* Advertise CL73 link speeds */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004939 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004940 MDIO_REG_BANK_CL73_IEEEB1,
4941 MDIO_CL73_IEEEB1_AN_ADV2,
4942 &reg_val);
Yaniv Rosner7aa07112010-09-07 11:41:01 +00004943 if (phy->speed_cap_mask &
Yaniv Rosner7846e472009-11-05 19:18:07 +02004944 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
4945 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00004946 if (phy->speed_cap_mask &
Yaniv Rosner7846e472009-11-05 19:18:07 +02004947 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
4948 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX;
Eilon Greenstein239d6862009-08-12 08:23:04 +00004949
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004950 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004951 MDIO_REG_BANK_CL73_IEEEB1,
4952 MDIO_CL73_IEEEB1_AN_ADV2,
4953 reg_val);
Eilon Greenstein239d6862009-08-12 08:23:04 +00004954
Eilon Greenstein239d6862009-08-12 08:23:04 +00004955 /* CL73 Autoneg Enabled */
4956 reg_val = MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN;
4957
4958 } else /* CL73 Autoneg Disabled */
4959 reg_val = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004960
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004961 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004962 MDIO_REG_BANK_CL73_IEEEB0,
4963 MDIO_CL73_IEEEB0_CL73_AN_CONTROL, reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004964}
4965
4966/* program SerDes, forced speed */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00004967static void bnx2x_program_serdes(struct bnx2x_phy *phy,
4968 struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004969 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004970{
4971 struct bnx2x *bp = params->bp;
4972 u16 reg_val;
4973
Eilon Greenstein57937202009-08-12 08:23:53 +00004974 /* program duplex, disable autoneg and sgmii*/
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004975 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004976 MDIO_REG_BANK_COMBO_IEEE0,
4977 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004978 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX |
Eilon Greenstein57937202009-08-12 08:23:53 +00004979 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
4980 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK);
Yaniv Rosner7aa07112010-09-07 11:41:01 +00004981 if (phy->req_duplex == DUPLEX_FULL)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004982 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004983 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004984 MDIO_REG_BANK_COMBO_IEEE0,
4985 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004986
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00004987 /*
4988 * program speed
4989 * - needed only if the speed is greater than 1G (2.5G or 10G)
4990 */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00004991 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00004992 MDIO_REG_BANK_SERDES_DIGITAL,
4993 MDIO_SERDES_DIGITAL_MISC1, &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07004994 /* clearing the speed value before setting the right speed */
4995 DP(NETIF_MSG_LINK, "MDIO_REG_BANK_SERDES_DIGITAL = 0x%x\n", reg_val);
4996
4997 reg_val &= ~(MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_MASK |
4998 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
4999
5000 if (!((vars->line_speed == SPEED_1000) ||
5001 (vars->line_speed == SPEED_100) ||
5002 (vars->line_speed == SPEED_10))) {
5003
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005004 reg_val |= (MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_156_25M |
5005 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07005006 if (vars->line_speed == SPEED_10000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005007 reg_val |=
5008 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_10G_CX4;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07005009 }
5010
Yaniv Rosnercd2be892011-01-31 04:21:45 +00005011 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005012 MDIO_REG_BANK_SERDES_DIGITAL,
5013 MDIO_SERDES_DIGITAL_MISC1, reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07005014
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005015}
5016
Yaniv Rosner9045f6b2011-05-31 21:28:27 +00005017static void bnx2x_set_brcm_cl37_advertisement(struct bnx2x_phy *phy,
5018 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005019{
5020 struct bnx2x *bp = params->bp;
5021 u16 val = 0;
5022
5023 /* configure the 48 bits for BAM AN */
5024
5025 /* set extended capabilities */
Yaniv Rosner7aa07112010-09-07 11:41:01 +00005026 if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005027 val |= MDIO_OVER_1G_UP1_2_5G;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00005028 if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005029 val |= MDIO_OVER_1G_UP1_10G;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00005030 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005031 MDIO_REG_BANK_OVER_1G,
5032 MDIO_OVER_1G_UP1, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005033
Yaniv Rosnercd2be892011-01-31 04:21:45 +00005034 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005035 MDIO_REG_BANK_OVER_1G,
5036 MDIO_OVER_1G_UP3, 0x400);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005037}
5038
Yaniv Rosner9045f6b2011-05-31 21:28:27 +00005039static void bnx2x_set_ieee_aneg_advertisement(struct bnx2x_phy *phy,
5040 struct link_params *params,
5041 u16 ieee_fc)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07005042{
5043 struct bnx2x *bp = params->bp;
Yaniv Rosner7846e472009-11-05 19:18:07 +02005044 u16 val;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07005045 /* for AN, we are always publishing full duplex */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005046
Yaniv Rosnercd2be892011-01-31 04:21:45 +00005047 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005048 MDIO_REG_BANK_COMBO_IEEE0,
5049 MDIO_COMBO_IEEE0_AUTO_NEG_ADV, ieee_fc);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00005050 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005051 MDIO_REG_BANK_CL73_IEEEB1,
5052 MDIO_CL73_IEEEB1_AN_ADV1, &val);
Yaniv Rosner7846e472009-11-05 19:18:07 +02005053 val &= ~MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_BOTH;
5054 val |= ((ieee_fc<<3) & MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00005055 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005056 MDIO_REG_BANK_CL73_IEEEB1,
5057 MDIO_CL73_IEEEB1_AN_ADV1, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005058}
5059
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005060static void bnx2x_restart_autoneg(struct bnx2x_phy *phy,
5061 struct link_params *params,
5062 u8 enable_cl73)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005063{
5064 struct bnx2x *bp = params->bp;
Eilon Greenstein3a36f2e2009-02-12 08:37:09 +00005065 u16 mii_control;
Eilon Greenstein239d6862009-08-12 08:23:04 +00005066
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005067 DP(NETIF_MSG_LINK, "bnx2x_restart_autoneg\n");
Eilon Greenstein3a36f2e2009-02-12 08:37:09 +00005068 /* Enable and restart BAM/CL37 aneg */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005069
Eilon Greenstein239d6862009-08-12 08:23:04 +00005070 if (enable_cl73) {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00005071 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005072 MDIO_REG_BANK_CL73_IEEEB0,
5073 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
5074 &mii_control);
Eilon Greenstein239d6862009-08-12 08:23:04 +00005075
Yaniv Rosnercd2be892011-01-31 04:21:45 +00005076 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005077 MDIO_REG_BANK_CL73_IEEEB0,
5078 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
5079 (mii_control |
5080 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN |
5081 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN));
Eilon Greenstein239d6862009-08-12 08:23:04 +00005082 } else {
5083
Yaniv Rosnercd2be892011-01-31 04:21:45 +00005084 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005085 MDIO_REG_BANK_COMBO_IEEE0,
5086 MDIO_COMBO_IEEE0_MII_CONTROL,
5087 &mii_control);
Eilon Greenstein239d6862009-08-12 08:23:04 +00005088 DP(NETIF_MSG_LINK,
5089 "bnx2x_restart_autoneg mii_control before = 0x%x\n",
5090 mii_control);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00005091 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005092 MDIO_REG_BANK_COMBO_IEEE0,
5093 MDIO_COMBO_IEEE0_MII_CONTROL,
5094 (mii_control |
5095 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
5096 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN));
Eilon Greenstein239d6862009-08-12 08:23:04 +00005097 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005098}
5099
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005100static void bnx2x_initialize_sgmii_process(struct bnx2x_phy *phy,
5101 struct link_params *params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005102 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005103{
5104 struct bnx2x *bp = params->bp;
5105 u16 control1;
5106
5107 /* in SGMII mode, the unicore is always slave */
5108
Yaniv Rosnercd2be892011-01-31 04:21:45 +00005109 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005110 MDIO_REG_BANK_SERDES_DIGITAL,
5111 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
5112 &control1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005113 control1 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT;
5114 /* set sgmii mode (and not fiber) */
5115 control1 &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE |
5116 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET |
5117 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_MSTR_MODE);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00005118 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005119 MDIO_REG_BANK_SERDES_DIGITAL,
5120 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
5121 control1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005122
5123 /* if forced speed */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07005124 if (!(vars->line_speed == SPEED_AUTO_NEG)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005125 /* set speed, disable autoneg */
5126 u16 mii_control;
5127
Yaniv Rosnercd2be892011-01-31 04:21:45 +00005128 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005129 MDIO_REG_BANK_COMBO_IEEE0,
5130 MDIO_COMBO_IEEE0_MII_CONTROL,
5131 &mii_control);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005132 mii_control &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
5133 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK|
5134 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX);
5135
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07005136 switch (vars->line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005137 case SPEED_100:
5138 mii_control |=
5139 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_100;
5140 break;
5141 case SPEED_1000:
5142 mii_control |=
5143 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_1000;
5144 break;
5145 case SPEED_10:
5146 /* there is nothing to set for 10M */
5147 break;
5148 default:
5149 /* invalid speed for SGMII */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07005150 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
5151 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005152 break;
5153 }
5154
5155 /* setting the full duplex */
Yaniv Rosner7aa07112010-09-07 11:41:01 +00005156 if (phy->req_duplex == DUPLEX_FULL)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005157 mii_control |=
5158 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00005159 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005160 MDIO_REG_BANK_COMBO_IEEE0,
5161 MDIO_COMBO_IEEE0_MII_CONTROL,
5162 mii_control);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005163
5164 } else { /* AN mode */
5165 /* enable and restart AN */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005166 bnx2x_restart_autoneg(phy, params, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005167 }
5168}
5169
5170
5171/*
5172 * link management
5173 */
5174
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005175static int bnx2x_direct_parallel_detect_used(struct bnx2x_phy *phy,
5176 struct link_params *params)
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02005177{
5178 struct bnx2x *bp = params->bp;
5179 u16 pd_10g, status2_1000x;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00005180 if (phy->req_line_speed != SPEED_AUTO_NEG)
5181 return 0;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00005182 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005183 MDIO_REG_BANK_SERDES_DIGITAL,
5184 MDIO_SERDES_DIGITAL_A_1000X_STATUS2,
5185 &status2_1000x);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00005186 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005187 MDIO_REG_BANK_SERDES_DIGITAL,
5188 MDIO_SERDES_DIGITAL_A_1000X_STATUS2,
5189 &status2_1000x);
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02005190 if (status2_1000x & MDIO_SERDES_DIGITAL_A_1000X_STATUS2_AN_DISABLED) {
5191 DP(NETIF_MSG_LINK, "1G parallel detect link on port %d\n",
5192 params->port);
5193 return 1;
5194 }
5195
Yaniv Rosnercd2be892011-01-31 04:21:45 +00005196 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005197 MDIO_REG_BANK_10G_PARALLEL_DETECT,
5198 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_STATUS,
5199 &pd_10g);
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02005200
5201 if (pd_10g & MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_STATUS_PD_LINK) {
5202 DP(NETIF_MSG_LINK, "10G parallel detect link on port %d\n",
5203 params->port);
5204 return 1;
5205 }
5206 return 0;
5207}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005208
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005209static void bnx2x_flow_ctrl_resolve(struct bnx2x_phy *phy,
5210 struct link_params *params,
5211 struct link_vars *vars,
5212 u32 gp_status)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005213{
5214 struct bnx2x *bp = params->bp;
Eilon Greenstein3196a882008-08-13 15:58:49 -07005215 u16 ld_pause; /* local driver */
5216 u16 lp_pause; /* link partner */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005217 u16 pause_result;
5218
David S. Millerc0700f92008-12-16 23:53:20 -08005219 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005220
5221 /* resolve from gp_status in case of AN complete and not sgmii */
Yaniv Rosner7aa07112010-09-07 11:41:01 +00005222 if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO)
5223 vars->flow_ctrl = phy->req_flow_ctrl;
5224 else if (phy->req_line_speed != SPEED_AUTO_NEG)
5225 vars->flow_ctrl = params->req_fc_auto_adv;
5226 else if ((gp_status & MDIO_AN_CL73_OR_37_COMPLETE) &&
5227 (!(vars->phy_flags & PHY_SGMII_FLAG))) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005228 if (bnx2x_direct_parallel_detect_used(phy, params)) {
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02005229 vars->flow_ctrl = params->req_fc_auto_adv;
5230 return;
5231 }
Yaniv Rosner7846e472009-11-05 19:18:07 +02005232 if ((gp_status &
5233 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
5234 MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) ==
5235 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
5236 MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) {
5237
Yaniv Rosnercd2be892011-01-31 04:21:45 +00005238 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005239 MDIO_REG_BANK_CL73_IEEEB1,
5240 MDIO_CL73_IEEEB1_AN_ADV1,
5241 &ld_pause);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00005242 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005243 MDIO_REG_BANK_CL73_IEEEB1,
5244 MDIO_CL73_IEEEB1_AN_LP_ADV1,
5245 &lp_pause);
Yaniv Rosner7846e472009-11-05 19:18:07 +02005246 pause_result = (ld_pause &
5247 MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK)
5248 >> 8;
5249 pause_result |= (lp_pause &
5250 MDIO_CL73_IEEEB1_AN_LP_ADV1_PAUSE_MASK)
5251 >> 10;
5252 DP(NETIF_MSG_LINK, "pause_result CL73 0x%x\n",
5253 pause_result);
5254 } else {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00005255 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005256 MDIO_REG_BANK_COMBO_IEEE0,
5257 MDIO_COMBO_IEEE0_AUTO_NEG_ADV,
5258 &ld_pause);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00005259 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005260 MDIO_REG_BANK_COMBO_IEEE0,
5261 MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1,
5262 &lp_pause);
Yaniv Rosner7846e472009-11-05 19:18:07 +02005263 pause_result = (ld_pause &
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005264 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>5;
Yaniv Rosner7846e472009-11-05 19:18:07 +02005265 pause_result |= (lp_pause &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005266 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7;
Yaniv Rosner7846e472009-11-05 19:18:07 +02005267 DP(NETIF_MSG_LINK, "pause_result CL37 0x%x\n",
5268 pause_result);
5269 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005270 bnx2x_pause_resolve(vars, pause_result);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005271 }
5272 DP(NETIF_MSG_LINK, "flow_ctrl 0x%x\n", vars->flow_ctrl);
5273}
5274
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005275static void bnx2x_check_fallback_to_cl37(struct bnx2x_phy *phy,
5276 struct link_params *params)
Eilon Greenstein239d6862009-08-12 08:23:04 +00005277{
5278 struct bnx2x *bp = params->bp;
Yaniv Rosner9045f6b2011-05-31 21:28:27 +00005279 u16 rx_status, ustat_val, cl37_fsm_received;
Eilon Greenstein239d6862009-08-12 08:23:04 +00005280 DP(NETIF_MSG_LINK, "bnx2x_check_fallback_to_cl37\n");
5281 /* Step 1: Make sure signal is detected */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00005282 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005283 MDIO_REG_BANK_RX0,
5284 MDIO_RX0_RX_STATUS,
5285 &rx_status);
Eilon Greenstein239d6862009-08-12 08:23:04 +00005286 if ((rx_status & MDIO_RX0_RX_STATUS_SIGDET) !=
5287 (MDIO_RX0_RX_STATUS_SIGDET)) {
5288 DP(NETIF_MSG_LINK, "Signal is not detected. Restoring CL73."
5289 "rx_status(0x80b0) = 0x%x\n", rx_status);
Yaniv Rosnercd2be892011-01-31 04:21:45 +00005290 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005291 MDIO_REG_BANK_CL73_IEEEB0,
5292 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
5293 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN);
Eilon Greenstein239d6862009-08-12 08:23:04 +00005294 return;
5295 }
5296 /* Step 2: Check CL73 state machine */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00005297 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005298 MDIO_REG_BANK_CL73_USERB0,
5299 MDIO_CL73_USERB0_CL73_USTAT1,
5300 &ustat_val);
Eilon Greenstein239d6862009-08-12 08:23:04 +00005301 if ((ustat_val &
5302 (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK |
5303 MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) !=
5304 (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK |
5305 MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) {
5306 DP(NETIF_MSG_LINK, "CL73 state-machine is not stable. "
5307 "ustat_val(0x8371) = 0x%x\n", ustat_val);
5308 return;
5309 }
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005310 /*
5311 * Step 3: Check CL37 Message Pages received to indicate LP
5312 * supports only CL37
5313 */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00005314 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005315 MDIO_REG_BANK_REMOTE_PHY,
5316 MDIO_REMOTE_PHY_MISC_RX_STATUS,
Yaniv Rosner9045f6b2011-05-31 21:28:27 +00005317 &cl37_fsm_received);
5318 if ((cl37_fsm_received &
Eilon Greenstein239d6862009-08-12 08:23:04 +00005319 (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG |
5320 MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) !=
5321 (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG |
5322 MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) {
5323 DP(NETIF_MSG_LINK, "No CL37 FSM were received. "
5324 "misc_rx_status(0x8330) = 0x%x\n",
Yaniv Rosner9045f6b2011-05-31 21:28:27 +00005325 cl37_fsm_received);
Eilon Greenstein239d6862009-08-12 08:23:04 +00005326 return;
5327 }
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005328 /*
5329 * The combined cl37/cl73 fsm state information indicating that
5330 * we are connected to a device which does not support cl73, but
5331 * does support cl37 BAM. In this case we disable cl73 and
5332 * restart cl37 auto-neg
5333 */
5334
Eilon Greenstein239d6862009-08-12 08:23:04 +00005335 /* Disable CL73 */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00005336 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005337 MDIO_REG_BANK_CL73_IEEEB0,
5338 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
5339 0);
Eilon Greenstein239d6862009-08-12 08:23:04 +00005340 /* Restart CL37 autoneg */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005341 bnx2x_restart_autoneg(phy, params, 0);
Eilon Greenstein239d6862009-08-12 08:23:04 +00005342 DP(NETIF_MSG_LINK, "Disabling CL73, and restarting CL37 autoneg\n");
5343}
Yaniv Rosner7aa07112010-09-07 11:41:01 +00005344
5345static void bnx2x_xgxs_an_resolve(struct bnx2x_phy *phy,
5346 struct link_params *params,
5347 struct link_vars *vars,
5348 u32 gp_status)
5349{
5350 if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE)
5351 vars->link_status |=
5352 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
5353
5354 if (bnx2x_direct_parallel_detect_used(phy, params))
5355 vars->link_status |=
5356 LINK_STATUS_PARALLEL_DETECTION_USED;
5357}
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005358static int bnx2x_get_link_speed_duplex(struct bnx2x_phy *phy,
5359 struct link_params *params,
5360 struct link_vars *vars,
5361 u16 is_link_up,
5362 u16 speed_mask,
5363 u16 is_duplex)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005364{
5365 struct bnx2x *bp = params->bp;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00005366 if (phy->req_line_speed == SPEED_AUTO_NEG)
5367 vars->link_status |= LINK_STATUS_AUTO_NEGOTIATE_ENABLED;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005368 if (is_link_up) {
5369 DP(NETIF_MSG_LINK, "phy link up\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005370
5371 vars->phy_link_up = 1;
5372 vars->link_status |= LINK_STATUS_LINK_UP;
5373
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005374 switch (speed_mask) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005375 case GP_STATUS_10M:
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005376 vars->line_speed = SPEED_10;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005377 if (vars->duplex == DUPLEX_FULL)
5378 vars->link_status |= LINK_10TFD;
5379 else
5380 vars->link_status |= LINK_10THD;
5381 break;
5382
5383 case GP_STATUS_100M:
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005384 vars->line_speed = SPEED_100;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005385 if (vars->duplex == DUPLEX_FULL)
5386 vars->link_status |= LINK_100TXFD;
5387 else
5388 vars->link_status |= LINK_100TXHD;
5389 break;
5390
5391 case GP_STATUS_1G:
5392 case GP_STATUS_1G_KX:
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005393 vars->line_speed = SPEED_1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005394 if (vars->duplex == DUPLEX_FULL)
5395 vars->link_status |= LINK_1000TFD;
5396 else
5397 vars->link_status |= LINK_1000THD;
5398 break;
5399
5400 case GP_STATUS_2_5G:
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005401 vars->line_speed = SPEED_2500;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005402 if (vars->duplex == DUPLEX_FULL)
5403 vars->link_status |= LINK_2500TFD;
5404 else
5405 vars->link_status |= LINK_2500THD;
5406 break;
5407
5408 case GP_STATUS_5G:
5409 case GP_STATUS_6G:
5410 DP(NETIF_MSG_LINK,
5411 "link speed unsupported gp_status 0x%x\n",
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005412 speed_mask);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005413 return -EINVAL;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005414
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005415 case GP_STATUS_10G_KX4:
5416 case GP_STATUS_10G_HIG:
5417 case GP_STATUS_10G_CX4:
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005418 case GP_STATUS_10G_KR:
5419 case GP_STATUS_10G_SFI:
5420 case GP_STATUS_10G_XFI:
5421 vars->line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005422 vars->link_status |= LINK_10GTFD;
5423 break;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005424 case GP_STATUS_20G_DXGXS:
5425 vars->line_speed = SPEED_20000;
5426 vars->link_status |= LINK_20GTFD;
5427 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005428 default:
5429 DP(NETIF_MSG_LINK,
5430 "link speed unsupported gp_status 0x%x\n",
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005431 speed_mask);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005432 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005433 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005434 } else { /* link_down */
5435 DP(NETIF_MSG_LINK, "phy link down\n");
5436
5437 vars->phy_link_up = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005438
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005439 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08005440 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005441 vars->mac_type = MAC_TYPE_NONE;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005442 }
5443 DP(NETIF_MSG_LINK, " phy_link_up %x line_speed %d\n",
5444 vars->phy_link_up, vars->line_speed);
5445 return 0;
5446}
Eilon Greenstein239d6862009-08-12 08:23:04 +00005447
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005448static int bnx2x_link_settings_status(struct bnx2x_phy *phy,
5449 struct link_params *params,
5450 struct link_vars *vars)
5451{
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005452 struct bnx2x *bp = params->bp;
5453
5454 u16 gp_status, duplex = DUPLEX_HALF, link_up = 0, speed_mask;
5455 int rc = 0;
5456
5457 /* Read gp_status */
5458 CL22_RD_OVER_CL45(bp, phy,
5459 MDIO_REG_BANK_GP_STATUS,
5460 MDIO_GP_STATUS_TOP_AN_STATUS1,
5461 &gp_status);
5462 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_DUPLEX_STATUS)
5463 duplex = DUPLEX_FULL;
5464 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS)
5465 link_up = 1;
5466 speed_mask = gp_status & GP_STATUS_SPEED_MASK;
5467 DP(NETIF_MSG_LINK, "gp_status 0x%x, is_link_up %d, speed_mask 0x%x\n",
5468 gp_status, link_up, speed_mask);
5469 rc = bnx2x_get_link_speed_duplex(phy, params, vars, link_up, speed_mask,
5470 duplex);
5471 if (rc == -EINVAL)
5472 return rc;
5473
5474 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) {
5475 if (SINGLE_MEDIA_DIRECT(params)) {
5476 bnx2x_flow_ctrl_resolve(phy, params, vars, gp_status);
5477 if (phy->req_line_speed == SPEED_AUTO_NEG)
5478 bnx2x_xgxs_an_resolve(phy, params, vars,
5479 gp_status);
5480 }
5481 } else { /* link_down */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00005482 if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
5483 SINGLE_MEDIA_DIRECT(params)) {
Eilon Greenstein239d6862009-08-12 08:23:04 +00005484 /* Check signal is detected */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00005485 bnx2x_check_fallback_to_cl37(phy, params);
Eilon Greenstein239d6862009-08-12 08:23:04 +00005486 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005487 }
5488
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005489 DP(NETIF_MSG_LINK, "duplex %x flow_ctrl 0x%x link_status 0x%x\n",
5490 vars->duplex, vars->flow_ctrl, vars->link_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005491 return rc;
5492}
5493
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005494static int bnx2x_warpcore_read_status(struct bnx2x_phy *phy,
5495 struct link_params *params,
5496 struct link_vars *vars)
5497{
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005498 struct bnx2x *bp = params->bp;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005499 u8 lane;
5500 u16 gp_status1, gp_speed, link_up, duplex = DUPLEX_FULL;
5501 int rc = 0;
5502 lane = bnx2x_get_warpcore_lane(phy, params);
5503 /* Read gp_status */
5504 if (phy->req_line_speed > SPEED_10000) {
5505 u16 temp_link_up;
5506 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
5507 1, &temp_link_up);
5508 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
5509 1, &link_up);
5510 DP(NETIF_MSG_LINK, "PCS RX link status = 0x%x-->0x%x\n",
5511 temp_link_up, link_up);
5512 link_up &= (1<<2);
5513 if (link_up)
5514 bnx2x_ext_phy_resolve_fc(phy, params, vars);
5515 } else {
5516 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
5517 MDIO_WC_REG_GP2_STATUS_GP_2_1, &gp_status1);
5518 DP(NETIF_MSG_LINK, "0x81d1 = 0x%x\n", gp_status1);
5519 /* Check for either KR or generic link up. */
5520 gp_status1 = ((gp_status1 >> 8) & 0xf) |
5521 ((gp_status1 >> 12) & 0xf);
5522 link_up = gp_status1 & (1 << lane);
5523 if (link_up && SINGLE_MEDIA_DIRECT(params)) {
5524 u16 pd, gp_status4;
5525 if (phy->req_line_speed == SPEED_AUTO_NEG) {
5526 /* Check Autoneg complete */
5527 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
5528 MDIO_WC_REG_GP2_STATUS_GP_2_4,
5529 &gp_status4);
5530 if (gp_status4 & ((1<<12)<<lane))
5531 vars->link_status |=
5532 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
5533
5534 /* Check parallel detect used */
5535 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
5536 MDIO_WC_REG_PAR_DET_10G_STATUS,
5537 &pd);
5538 if (pd & (1<<15))
5539 vars->link_status |=
5540 LINK_STATUS_PARALLEL_DETECTION_USED;
5541 }
5542 bnx2x_ext_phy_resolve_fc(phy, params, vars);
5543 }
5544 }
5545
5546 if (lane < 2) {
5547 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
5548 MDIO_WC_REG_GP2_STATUS_GP_2_2, &gp_speed);
5549 } else {
5550 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
5551 MDIO_WC_REG_GP2_STATUS_GP_2_3, &gp_speed);
5552 }
5553 DP(NETIF_MSG_LINK, "lane %d gp_speed 0x%x\n", lane, gp_speed);
5554
5555 if ((lane & 1) == 0)
5556 gp_speed <<= 8;
5557 gp_speed &= 0x3f00;
5558
5559
5560 rc = bnx2x_get_link_speed_duplex(phy, params, vars, link_up, gp_speed,
5561 duplex);
5562
5563 DP(NETIF_MSG_LINK, "duplex %x flow_ctrl 0x%x link_status 0x%x\n",
5564 vars->duplex, vars->flow_ctrl, vars->link_status);
5565 return rc;
5566}
Eilon Greensteined8680a2009-02-12 08:37:12 +00005567static void bnx2x_set_gmii_tx_driver(struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005568{
5569 struct bnx2x *bp = params->bp;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005570 struct bnx2x_phy *phy = &params->phy[INT_PHY];
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005571 u16 lp_up2;
5572 u16 tx_driver;
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00005573 u16 bank;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005574
5575 /* read precomp */
Yaniv Rosnercd2be892011-01-31 04:21:45 +00005576 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005577 MDIO_REG_BANK_OVER_1G,
5578 MDIO_OVER_1G_LP_UP2, &lp_up2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005579
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005580 /* bits [10:7] at lp_up2, positioned at [15:12] */
5581 lp_up2 = (((lp_up2 & MDIO_OVER_1G_LP_UP2_PREEMPHASIS_MASK) >>
5582 MDIO_OVER_1G_LP_UP2_PREEMPHASIS_SHIFT) <<
5583 MDIO_TX0_TX_DRIVER_PREEMPHASIS_SHIFT);
5584
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00005585 if (lp_up2 == 0)
5586 return;
5587
5588 for (bank = MDIO_REG_BANK_TX0; bank <= MDIO_REG_BANK_TX3;
5589 bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0)) {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00005590 CL22_RD_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005591 bank,
5592 MDIO_TX0_TX_DRIVER, &tx_driver);
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00005593
5594 /* replace tx_driver bits [15:12] */
5595 if (lp_up2 !=
5596 (tx_driver & MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK)) {
5597 tx_driver &= ~MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK;
5598 tx_driver |= lp_up2;
Yaniv Rosnercd2be892011-01-31 04:21:45 +00005599 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005600 bank,
5601 MDIO_TX0_TX_DRIVER, tx_driver);
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00005602 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005603 }
5604}
5605
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005606static int bnx2x_emac_program(struct link_params *params,
5607 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005608{
5609 struct bnx2x *bp = params->bp;
5610 u8 port = params->port;
5611 u16 mode = 0;
5612
5613 DP(NETIF_MSG_LINK, "setting link speed & duplex\n");
5614 bnx2x_bits_dis(bp, GRCBASE_EMAC0 + port*0x400 +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005615 EMAC_REG_EMAC_MODE,
5616 (EMAC_MODE_25G_MODE |
5617 EMAC_MODE_PORT_MII_10M |
5618 EMAC_MODE_HALF_DUPLEX));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005619 switch (vars->line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005620 case SPEED_10:
5621 mode |= EMAC_MODE_PORT_MII_10M;
5622 break;
5623
5624 case SPEED_100:
5625 mode |= EMAC_MODE_PORT_MII;
5626 break;
5627
5628 case SPEED_1000:
5629 mode |= EMAC_MODE_PORT_GMII;
5630 break;
5631
5632 case SPEED_2500:
5633 mode |= (EMAC_MODE_25G_MODE | EMAC_MODE_PORT_GMII);
5634 break;
5635
5636 default:
5637 /* 10G not valid for EMAC */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005638 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
5639 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005640 return -EINVAL;
5641 }
5642
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005643 if (vars->duplex == DUPLEX_HALF)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005644 mode |= EMAC_MODE_HALF_DUPLEX;
5645 bnx2x_bits_en(bp,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005646 GRCBASE_EMAC0 + port*0x400 + EMAC_REG_EMAC_MODE,
5647 mode);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005648
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005649 bnx2x_set_led(params, vars, LED_MODE_OPER, vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005650 return 0;
5651}
5652
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005653static void bnx2x_set_preemphasis(struct bnx2x_phy *phy,
5654 struct link_params *params)
5655{
5656
5657 u16 bank, i = 0;
5658 struct bnx2x *bp = params->bp;
5659
5660 for (bank = MDIO_REG_BANK_RX0, i = 0; bank <= MDIO_REG_BANK_RX3;
5661 bank += (MDIO_REG_BANK_RX1-MDIO_REG_BANK_RX0), i++) {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00005662 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005663 bank,
5664 MDIO_RX0_RX_EQ_BOOST,
5665 phy->rx_preemphasis[i]);
5666 }
5667
5668 for (bank = MDIO_REG_BANK_TX0, i = 0; bank <= MDIO_REG_BANK_TX3;
5669 bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0), i++) {
Yaniv Rosnercd2be892011-01-31 04:21:45 +00005670 CL22_WR_OVER_CL45(bp, phy,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005671 bank,
5672 MDIO_TX0_TX_DRIVER,
5673 phy->tx_preemphasis[i]);
5674 }
5675}
5676
Yaniv Rosnerec146a62011-05-31 21:29:27 +00005677static void bnx2x_xgxs_config_init(struct bnx2x_phy *phy,
5678 struct link_params *params,
5679 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005680{
5681 struct bnx2x *bp = params->bp;
5682 u8 enable_cl73 = (SINGLE_MEDIA_DIRECT(params) ||
5683 (params->loopback_mode == LOOPBACK_XGXS));
5684 if (!(vars->phy_flags & PHY_SGMII_FLAG)) {
5685 if (SINGLE_MEDIA_DIRECT(params) &&
5686 (params->feature_config_flags &
5687 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED))
5688 bnx2x_set_preemphasis(phy, params);
5689
5690 /* forced speed requested? */
5691 if (vars->line_speed != SPEED_AUTO_NEG ||
5692 (SINGLE_MEDIA_DIRECT(params) &&
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005693 params->loopback_mode == LOOPBACK_EXT)) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005694 DP(NETIF_MSG_LINK, "not SGMII, no AN\n");
5695
5696 /* disable autoneg */
5697 bnx2x_set_autoneg(phy, params, vars, 0);
5698
5699 /* program speed and duplex */
5700 bnx2x_program_serdes(phy, params, vars);
5701
5702 } else { /* AN_mode */
5703 DP(NETIF_MSG_LINK, "not SGMII, AN\n");
5704
5705 /* AN enabled */
Yaniv Rosner9045f6b2011-05-31 21:28:27 +00005706 bnx2x_set_brcm_cl37_advertisement(phy, params);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005707
5708 /* program duplex & pause advertisement (for aneg) */
Yaniv Rosner9045f6b2011-05-31 21:28:27 +00005709 bnx2x_set_ieee_aneg_advertisement(phy, params,
5710 vars->ieee_fc);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005711
5712 /* enable autoneg */
5713 bnx2x_set_autoneg(phy, params, vars, enable_cl73);
5714
5715 /* enable and restart AN */
5716 bnx2x_restart_autoneg(phy, params, enable_cl73);
5717 }
5718
5719 } else { /* SGMII mode */
5720 DP(NETIF_MSG_LINK, "SGMII\n");
5721
5722 bnx2x_initialize_sgmii_process(phy, params, vars);
5723 }
5724}
5725
Yaniv Rosnerec146a62011-05-31 21:29:27 +00005726static int bnx2x_prepare_xgxs(struct bnx2x_phy *phy,
5727 struct link_params *params,
5728 struct link_vars *vars)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005729{
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005730 int rc;
Yaniv Rosnerec146a62011-05-31 21:29:27 +00005731 vars->phy_flags |= PHY_XGXS_FLAG;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005732 if ((phy->req_line_speed &&
5733 ((phy->req_line_speed == SPEED_100) ||
5734 (phy->req_line_speed == SPEED_10))) ||
5735 (!phy->req_line_speed &&
5736 (phy->speed_cap_mask >=
5737 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL) &&
5738 (phy->speed_cap_mask <
Yaniv Rosnerec146a62011-05-31 21:29:27 +00005739 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) ||
5740 (phy->type == PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT_SD))
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005741 vars->phy_flags |= PHY_SGMII_FLAG;
5742 else
5743 vars->phy_flags &= ~PHY_SGMII_FLAG;
5744
5745 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
Yaniv Rosnerec146a62011-05-31 21:29:27 +00005746 bnx2x_set_aer_mmd(params, phy);
5747 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT)
5748 bnx2x_set_master_ln(params, phy);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005749
5750 rc = bnx2x_reset_unicore(params, phy, 0);
5751 /* reset the SerDes and wait for reset bit return low */
5752 if (rc != 0)
5753 return rc;
5754
Yaniv Rosnerec146a62011-05-31 21:29:27 +00005755 bnx2x_set_aer_mmd(params, phy);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005756 /* setting the masterLn_def again after the reset */
Yaniv Rosnerec146a62011-05-31 21:29:27 +00005757 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) {
5758 bnx2x_set_master_ln(params, phy);
5759 bnx2x_set_swap_lanes(params, phy);
5760 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005761
5762 return rc;
5763}
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00005764
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005765static u16 bnx2x_wait_reset_complete(struct bnx2x *bp,
Yaniv Rosner6d870c32011-01-31 04:22:20 +00005766 struct bnx2x_phy *phy,
5767 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005768{
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005769 u16 cnt, ctrl;
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005770 /* Wait for soft reset to get cleared up to 1 sec */
Yaniv Rosner62b29a52010-09-07 11:40:58 +00005771 for (cnt = 0; cnt < 1000; cnt++) {
Yaniv Rosner52c4d6c2011-07-05 01:06:34 +00005772 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54618SE)
Yaniv Rosner6583e332011-06-14 01:34:17 +00005773 bnx2x_cl22_read(bp, phy,
5774 MDIO_PMA_REG_CTRL, &ctrl);
5775 else
5776 bnx2x_cl45_read(bp, phy,
5777 MDIO_PMA_DEVAD,
5778 MDIO_PMA_REG_CTRL, &ctrl);
Yaniv Rosner62b29a52010-09-07 11:40:58 +00005779 if (!(ctrl & (1<<15)))
5780 break;
5781 msleep(1);
5782 }
Yaniv Rosner6d870c32011-01-31 04:22:20 +00005783
5784 if (cnt == 1000)
5785 netdev_err(bp->dev, "Warning: PHY was not initialized,"
5786 " Port %d\n",
5787 params->port);
Yaniv Rosner62b29a52010-09-07 11:40:58 +00005788 DP(NETIF_MSG_LINK, "control reg 0x%x (after %d ms)\n", ctrl, cnt);
5789 return cnt;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005790}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005791
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005792static void bnx2x_link_int_enable(struct link_params *params)
5793{
5794 u8 port = params->port;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005795 u32 mask;
5796 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005797
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005798 /* Setting the status to report on link up for either XGXS or SerDes */
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005799 if (CHIP_IS_E3(bp)) {
5800 mask = NIG_MASK_XGXS0_LINK_STATUS;
5801 if (!(SINGLE_MEDIA_DIRECT(params)))
5802 mask |= NIG_MASK_MI_INT;
5803 } else if (params->switch_cfg == SWITCH_CFG_10G) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005804 mask = (NIG_MASK_XGXS0_LINK10G |
5805 NIG_MASK_XGXS0_LINK_STATUS);
5806 DP(NETIF_MSG_LINK, "enabled XGXS interrupt\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005807 if (!(SINGLE_MEDIA_DIRECT(params)) &&
5808 params->phy[INT_PHY].type !=
5809 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005810 mask |= NIG_MASK_MI_INT;
5811 DP(NETIF_MSG_LINK, "enabled external phy int\n");
5812 }
5813
5814 } else { /* SerDes */
5815 mask = NIG_MASK_SERDES0_LINK_STATUS;
5816 DP(NETIF_MSG_LINK, "enabled SerDes interrupt\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005817 if (!(SINGLE_MEDIA_DIRECT(params)) &&
5818 params->phy[INT_PHY].type !=
5819 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_NOT_CONN) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005820 mask |= NIG_MASK_MI_INT;
5821 DP(NETIF_MSG_LINK, "enabled external phy int\n");
5822 }
5823 }
5824 bnx2x_bits_en(bp,
5825 NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
5826 mask);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005827
5828 DP(NETIF_MSG_LINK, "port %x, is_xgxs %x, int_status 0x%x\n", port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005829 (params->switch_cfg == SWITCH_CFG_10G),
5830 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005831 DP(NETIF_MSG_LINK, " int_mask 0x%x, MI_INT %x, SERDES_LINK %x\n",
5832 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
5833 REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
5834 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS+port*0x3c));
5835 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
5836 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
5837 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
5838}
5839
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005840static void bnx2x_rearm_latch_signal(struct bnx2x *bp, u8 port,
5841 u8 exp_mi_int)
Eilon Greenstein2f904462009-08-12 08:22:16 +00005842{
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005843 u32 latch_status = 0;
5844
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005845 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005846 * Disable the MI INT ( external phy int ) by writing 1 to the
5847 * status register. Link down indication is high-active-signal,
5848 * so in this case we need to write the status to clear the XOR
Eilon Greenstein2f904462009-08-12 08:22:16 +00005849 */
5850 /* Read Latched signals */
5851 latch_status = REG_RD(bp,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005852 NIG_REG_LATCH_STATUS_0 + port*8);
5853 DP(NETIF_MSG_LINK, "latch_status = 0x%x\n", latch_status);
Eilon Greenstein2f904462009-08-12 08:22:16 +00005854 /* Handle only those with latched-signal=up.*/
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005855 if (exp_mi_int)
5856 bnx2x_bits_en(bp,
5857 NIG_REG_STATUS_INTERRUPT_PORT0
5858 + port*4,
5859 NIG_STATUS_EMAC0_MI_INT);
5860 else
5861 bnx2x_bits_dis(bp,
5862 NIG_REG_STATUS_INTERRUPT_PORT0
5863 + port*4,
5864 NIG_STATUS_EMAC0_MI_INT);
5865
Eilon Greenstein2f904462009-08-12 08:22:16 +00005866 if (latch_status & 1) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005867
Eilon Greenstein2f904462009-08-12 08:22:16 +00005868 /* For all latched-signal=up : Re-Arm Latch signals */
5869 REG_WR(bp, NIG_REG_LATCH_STATUS_0 + port*8,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005870 (latch_status & 0xfffe) | (latch_status & 1));
Eilon Greenstein2f904462009-08-12 08:22:16 +00005871 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005872 /* For all latched-signal=up,Write original_signal to status */
Eilon Greenstein2f904462009-08-12 08:22:16 +00005873}
Yaniv Rosnere10bc842010-09-07 11:40:50 +00005874
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005875static void bnx2x_link_int_ack(struct link_params *params,
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005876 struct link_vars *vars, u8 is_10g_plus)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005877{
5878 struct bnx2x *bp = params->bp;
5879 u8 port = params->port;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005880 u32 mask;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00005881 /*
5882 * First reset all status we assume only one line will be
5883 * change at a time
5884 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005885 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005886 (NIG_STATUS_XGXS0_LINK10G |
5887 NIG_STATUS_XGXS0_LINK_STATUS |
5888 NIG_STATUS_SERDES0_LINK_STATUS));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005889 if (vars->phy_link_up) {
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005890 if (USES_WARPCORE(bp))
5891 mask = NIG_STATUS_XGXS0_LINK_STATUS;
5892 else {
5893 if (is_10g_plus)
5894 mask = NIG_STATUS_XGXS0_LINK10G;
5895 else if (params->switch_cfg == SWITCH_CFG_10G) {
5896 /*
5897 * Disable the link interrupt by writing 1 to
5898 * the relevant lane in the status register
5899 */
5900 u32 ser_lane =
5901 ((params->lane_config &
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005902 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
5903 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005904 mask = ((1 << ser_lane) <<
5905 NIG_STATUS_XGXS0_LINK_STATUS_SIZE);
5906 } else
5907 mask = NIG_STATUS_SERDES0_LINK_STATUS;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005908 }
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00005909 DP(NETIF_MSG_LINK, "Ack link up interrupt with mask 0x%x\n",
5910 mask);
5911 bnx2x_bits_en(bp,
5912 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
5913 mask);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005914 }
5915}
5916
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005917static int bnx2x_format_ver(u32 num, u8 *str, u16 *len)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005918{
5919 u8 *str_ptr = str;
5920 u32 mask = 0xf0000000;
5921 u8 shift = 8*4;
5922 u8 digit;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005923 u8 remove_leading_zeros = 1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005924 if (*len < 10) {
Frederik Schwarzer025dfda2008-10-16 19:02:37 +02005925 /* Need more than 10chars for this format */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005926 *str_ptr = '\0';
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005927 (*len)--;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005928 return -EINVAL;
5929 }
5930 while (shift > 0) {
5931
5932 shift -= 4;
5933 digit = ((num & mask) >> shift);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005934 if (digit == 0 && remove_leading_zeros) {
5935 mask = mask >> 4;
5936 continue;
5937 } else if (digit < 0xa)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005938 *str_ptr = digit + '0';
5939 else
5940 *str_ptr = digit - 0xa + 'a';
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005941 remove_leading_zeros = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005942 str_ptr++;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005943 (*len)--;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005944 mask = mask >> 4;
5945 if (shift == 4*4) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005946 *str_ptr = '.';
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005947 str_ptr++;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005948 (*len)--;
5949 remove_leading_zeros = 1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005950 }
5951 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005952 return 0;
5953}
5954
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005955
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005956static int bnx2x_null_format_ver(u32 spirom_ver, u8 *str, u16 *len)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005957{
5958 str[0] = '\0';
5959 (*len)--;
5960 return 0;
5961}
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005962
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005963int bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
5964 u8 *version, u16 len)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005965{
Julia Lawall0376d5b2009-07-19 05:26:35 +00005966 struct bnx2x *bp;
Eilon Greensteina35da8d2009-02-12 08:37:02 +00005967 u32 spirom_ver = 0;
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00005968 int status = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005969 u8 *ver_p = version;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005970 u16 remain_len = len;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005971 if (version == NULL || params == NULL)
5972 return -EINVAL;
Julia Lawall0376d5b2009-07-19 05:26:35 +00005973 bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005974
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005975 /* Extract first external phy*/
5976 version[0] = '\0';
5977 spirom_ver = REG_RD(bp, params->phy[EXT_PHY1].ver_addr);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00005978
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005979 if (params->phy[EXT_PHY1].format_fw_ver) {
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005980 status |= params->phy[EXT_PHY1].format_fw_ver(spirom_ver,
5981 ver_p,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005982 &remain_len);
5983 ver_p += (len - remain_len);
5984 }
5985 if ((params->num_phys == MAX_PHYS) &&
5986 (params->phy[EXT_PHY2].ver_addr != 0)) {
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00005987 spirom_ver = REG_RD(bp, params->phy[EXT_PHY2].ver_addr);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005988 if (params->phy[EXT_PHY2].format_fw_ver) {
5989 *ver_p = '/';
5990 ver_p++;
5991 remain_len--;
5992 status |= params->phy[EXT_PHY2].format_fw_ver(
5993 spirom_ver,
5994 ver_p,
5995 &remain_len);
5996 ver_p = version + (len - remain_len);
5997 }
5998 }
5999 *ver_p = '\0';
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006000 return status;
6001}
6002
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006003static void bnx2x_set_xgxs_loopback(struct bnx2x_phy *phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00006004 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006005{
6006 u8 port = params->port;
6007 struct bnx2x *bp = params->bp;
6008
Yaniv Rosner62b29a52010-09-07 11:40:58 +00006009 if (phy->req_line_speed != SPEED_1000) {
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00006010 u32 md_devad = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006011
6012 DP(NETIF_MSG_LINK, "XGXS 10G loopback enable\n");
6013
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00006014 if (!CHIP_IS_E3(bp)) {
6015 /* change the uni_phy_addr in the nig */
6016 md_devad = REG_RD(bp, (NIG_REG_XGXS0_CTRL_MD_DEVAD +
6017 port*0x18));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006018
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00006019 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
6020 0x5);
6021 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006022
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006023 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006024 5,
6025 (MDIO_REG_BANK_AER_BLOCK +
6026 (MDIO_AER_BLOCK_AER_REG & 0xf)),
6027 0x2800);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006028
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006029 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006030 5,
6031 (MDIO_REG_BANK_CL73_IEEEB0 +
6032 (MDIO_CL73_IEEEB0_CL73_AN_CONTROL & 0xf)),
6033 0x6041);
Eilon Greenstein38582762009-01-14 06:44:16 +00006034 msleep(200);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006035 /* set aer mmd back */
Yaniv Rosnerec146a62011-05-31 21:29:27 +00006036 bnx2x_set_aer_mmd(params, phy);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006037
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00006038 if (!CHIP_IS_E3(bp)) {
6039 /* and md_devad */
6040 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
6041 md_devad);
6042 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006043 } else {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006044 u16 mii_ctrl;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006045 DP(NETIF_MSG_LINK, "XGXS 1G loopback enable\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006046 bnx2x_cl45_read(bp, phy, 5,
6047 (MDIO_REG_BANK_COMBO_IEEE0 +
6048 (MDIO_COMBO_IEEE0_MII_CONTROL & 0xf)),
6049 &mii_ctrl);
6050 bnx2x_cl45_write(bp, phy, 5,
6051 (MDIO_REG_BANK_COMBO_IEEE0 +
6052 (MDIO_COMBO_IEEE0_MII_CONTROL & 0xf)),
6053 mii_ctrl |
6054 MDIO_COMBO_IEEO_MII_CONTROL_LOOPBACK);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006055 }
6056}
6057
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006058int bnx2x_set_led(struct link_params *params,
6059 struct link_vars *vars, u8 mode, u32 speed)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006060{
Yaniv Rosner7846e472009-11-05 19:18:07 +02006061 u8 port = params->port;
6062 u16 hw_led_mode = params->hw_led_mode;
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006063 int rc = 0;
6064 u8 phy_idx;
Eilon Greenstein345b5d52008-08-13 15:58:12 -07006065 u32 tmp;
6066 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Yaniv Rosner7846e472009-11-05 19:18:07 +02006067 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006068 DP(NETIF_MSG_LINK, "bnx2x_set_led: port %x, mode %d\n", port, mode);
6069 DP(NETIF_MSG_LINK, "speed 0x%x, hw_led_mode 0x%x\n",
6070 speed, hw_led_mode);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006071 /* In case */
6072 for (phy_idx = EXT_PHY1; phy_idx < MAX_PHYS; phy_idx++) {
6073 if (params->phy[phy_idx].set_link_led) {
6074 params->phy[phy_idx].set_link_led(
6075 &params->phy[phy_idx], params, mode);
6076 }
6077 }
6078
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006079 switch (mode) {
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006080 case LED_MODE_FRONT_PANEL_OFF:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006081 case LED_MODE_OFF:
6082 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 0);
6083 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006084 SHARED_HW_CFG_LED_MAC1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07006085
6086 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Yaniv Rosner001cea72011-10-27 05:09:48 +00006087 if (params->phy[EXT_PHY1].type ==
6088 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54618SE)
6089 EMAC_WR(bp, EMAC_REG_EMAC_LED, tmp & 0xfff1);
6090 else {
6091 EMAC_WR(bp, EMAC_REG_EMAC_LED,
6092 (tmp | EMAC_LED_OVERRIDE));
6093 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006094 break;
6095
6096 case LED_MODE_OPER:
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006097 /*
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006098 * For all other phys, OPER mode is same as ON, so in case
6099 * link is down, do nothing
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006100 */
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006101 if (!vars->link_up)
6102 break;
6103 case LED_MODE_ON:
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00006104 if (((params->phy[EXT_PHY1].type ==
6105 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) ||
6106 (params->phy[EXT_PHY1].type ==
6107 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722)) &&
Yaniv Rosner1f483532011-01-18 04:33:31 +00006108 CHIP_IS_E2(bp) && params->num_phys == 2) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006109 /*
6110 * This is a work-around for E2+8727 Configurations
6111 */
Yaniv Rosner1f483532011-01-18 04:33:31 +00006112 if (mode == LED_MODE_ON ||
6113 speed == SPEED_10000){
6114 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0);
6115 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1);
6116
6117 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
6118 EMAC_WR(bp, EMAC_REG_EMAC_LED,
6119 (tmp | EMAC_LED_OVERRIDE));
Yaniv Rosner793bd452011-08-02 22:59:40 +00006120 /*
6121 * return here without enabling traffic
David S. Miller8decf862011-09-22 03:23:13 -04006122 * LED blink and setting rate in ON mode.
Yaniv Rosner793bd452011-08-02 22:59:40 +00006123 * In oper mode, enabling LED blink
6124 * and setting rate is needed.
6125 */
6126 if (mode == LED_MODE_ON)
6127 return rc;
Yaniv Rosner1f483532011-01-18 04:33:31 +00006128 }
Yaniv Rosner793bd452011-08-02 22:59:40 +00006129 } else if (SINGLE_MEDIA_DIRECT(params)) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006130 /*
6131 * This is a work-around for HW issue found when link
6132 * is up in CL73
6133 */
David S. Miller8decf862011-09-22 03:23:13 -04006134 if ((!CHIP_IS_E3(bp)) ||
6135 (CHIP_IS_E3(bp) &&
6136 mode == LED_MODE_ON))
6137 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1);
6138
Yaniv Rosner793bd452011-08-02 22:59:40 +00006139 if (CHIP_IS_E1x(bp) ||
6140 CHIP_IS_E2(bp) ||
6141 (mode == LED_MODE_ON))
6142 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0);
6143 else
6144 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
6145 hw_led_mode);
Yaniv Rosner001cea72011-10-27 05:09:48 +00006146 } else if ((params->phy[EXT_PHY1].type ==
6147 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54618SE) &&
6148 (mode != LED_MODE_OPER)) {
6149 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0);
6150 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
6151 EMAC_WR(bp, EMAC_REG_EMAC_LED, tmp | 0x3);
Yaniv Rosner793bd452011-08-02 22:59:40 +00006152 } else
Yaniv Rosner001cea72011-10-27 05:09:48 +00006153 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
6154 hw_led_mode);
Yaniv Rosner7846e472009-11-05 19:18:07 +02006155
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006156 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 + port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006157 /* Set blinking rate to ~15.9Hz */
Yaniv Rosner26ffaf32011-10-27 05:09:45 +00006158 if (CHIP_IS_E3(bp))
6159 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4,
6160 LED_BLINK_RATE_VAL_E3);
6161 else
6162 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4,
6163 LED_BLINK_RATE_VAL_E1X_E2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006164 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006165 port*4, 1);
Yaniv Rosner001cea72011-10-27 05:09:48 +00006166 if ((params->phy[EXT_PHY1].type !=
6167 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54618SE) &&
6168 (mode != LED_MODE_OPER)) {
6169 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
6170 EMAC_WR(bp, EMAC_REG_EMAC_LED,
6171 (tmp & (~EMAC_LED_OVERRIDE)));
6172 }
Eilon Greenstein345b5d52008-08-13 15:58:12 -07006173
Yaniv Rosner7846e472009-11-05 19:18:07 +02006174 if (CHIP_IS_E1(bp) &&
Eilon Greenstein34f80b02008-06-23 20:33:01 -07006175 ((speed == SPEED_2500) ||
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006176 (speed == SPEED_1000) ||
6177 (speed == SPEED_100) ||
6178 (speed == SPEED_10))) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006179 /*
6180 * On Everest 1 Ax chip versions for speeds less than
6181 * 10G LED scheme is different
6182 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006183 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006184 + port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006185 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006186 port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006187 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_TRAFFIC_P0 +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006188 port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006189 }
6190 break;
6191
6192 default:
6193 rc = -EINVAL;
6194 DP(NETIF_MSG_LINK, "bnx2x_set_led: Invalid led mode %d\n",
6195 mode);
6196 break;
6197 }
6198 return rc;
6199
6200}
6201
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006202/*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006203 * This function comes to reflect the actual link state read DIRECTLY from the
6204 * HW
6205 */
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006206int bnx2x_test_link(struct link_params *params, struct link_vars *vars,
6207 u8 is_serdes)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006208{
6209 struct bnx2x *bp = params->bp;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00006210 u16 gp_status = 0, phy_index = 0;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006211 u8 ext_phy_link_up = 0, serdes_phy_type;
6212 struct link_vars temp_vars;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00006213 struct bnx2x_phy *int_phy = &params->phy[INT_PHY];
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006214
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00006215 if (CHIP_IS_E3(bp)) {
6216 u16 link_up;
6217 if (params->req_line_speed[LINK_CONFIG_IDX(INT_PHY)]
6218 > SPEED_10000) {
6219 /* Check 20G link */
6220 bnx2x_cl45_read(bp, int_phy, MDIO_WC_DEVAD,
6221 1, &link_up);
6222 bnx2x_cl45_read(bp, int_phy, MDIO_WC_DEVAD,
6223 1, &link_up);
6224 link_up &= (1<<2);
6225 } else {
6226 /* Check 10G link and below*/
6227 u8 lane = bnx2x_get_warpcore_lane(int_phy, params);
6228 bnx2x_cl45_read(bp, int_phy, MDIO_WC_DEVAD,
6229 MDIO_WC_REG_GP2_STATUS_GP_2_1,
6230 &gp_status);
6231 gp_status = ((gp_status >> 8) & 0xf) |
6232 ((gp_status >> 12) & 0xf);
6233 link_up = gp_status & (1 << lane);
6234 }
6235 if (!link_up)
6236 return -ESRCH;
6237 } else {
6238 CL22_RD_OVER_CL45(bp, int_phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006239 MDIO_REG_BANK_GP_STATUS,
6240 MDIO_GP_STATUS_TOP_AN_STATUS1,
6241 &gp_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006242 /* link is up only if both local phy and external phy are up */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006243 if (!(gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS))
6244 return -ESRCH;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00006245 }
6246 /* In XGXS loopback mode, do not check external PHY */
6247 if (params->loopback_mode == LOOPBACK_XGXS)
6248 return 0;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006249
6250 switch (params->num_phys) {
6251 case 1:
6252 /* No external PHY */
6253 return 0;
6254 case 2:
6255 ext_phy_link_up = params->phy[EXT_PHY1].read_status(
6256 &params->phy[EXT_PHY1],
6257 params, &temp_vars);
6258 break;
6259 case 3: /* Dual Media */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00006260 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
6261 phy_index++) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006262 serdes_phy_type = ((params->phy[phy_index].media_type ==
6263 ETH_PHY_SFP_FIBER) ||
6264 (params->phy[phy_index].media_type ==
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00006265 ETH_PHY_XFP_FIBER) ||
6266 (params->phy[phy_index].media_type ==
6267 ETH_PHY_DA_TWINAX));
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006268
6269 if (is_serdes != serdes_phy_type)
6270 continue;
6271 if (params->phy[phy_index].read_status) {
6272 ext_phy_link_up |=
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00006273 params->phy[phy_index].read_status(
6274 &params->phy[phy_index],
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006275 params, &temp_vars);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006276 }
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00006277 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006278 break;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006279 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006280 if (ext_phy_link_up)
6281 return 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006282 return -ESRCH;
6283}
6284
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006285static int bnx2x_link_initialize(struct link_params *params,
6286 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006287{
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006288 int rc = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006289 u8 phy_index, non_ext_phy;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00006290 struct bnx2x *bp = params->bp;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006291 /*
6292 * In case of external phy existence, the line speed would be the
6293 * line speed linked up by the external phy. In case it is direct
6294 * only, then the line_speed during initialization will be
6295 * equal to the req_line_speed
6296 */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00006297 vars->line_speed = params->phy[INT_PHY].req_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006298
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006299 /*
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00006300 * Initialize the internal phy in case this is a direct board
6301 * (no external phys), or this board has external phy which requires
6302 * to first.
6303 */
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00006304 if (!USES_WARPCORE(bp))
6305 bnx2x_prepare_xgxs(&params->phy[INT_PHY], params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006306 /* init ext phy and enable link state int */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00006307 non_ext_phy = (SINGLE_MEDIA_DIRECT(params) ||
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006308 (params->loopback_mode == LOOPBACK_XGXS));
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006309
6310 if (non_ext_phy ||
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00006311 (params->phy[EXT_PHY1].flags & FLAGS_INIT_XGXS_FIRST) ||
Eilon Greenstein8660d8c2009-03-02 08:01:02 +00006312 (params->loopback_mode == LOOPBACK_EXT_PHY)) {
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00006313 struct bnx2x_phy *phy = &params->phy[INT_PHY];
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00006314 if (vars->line_speed == SPEED_AUTO_NEG &&
6315 (CHIP_IS_E1x(bp) ||
6316 CHIP_IS_E2(bp)))
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00006317 bnx2x_set_parallel_detection(phy, params);
Yaniv Rosnerec146a62011-05-31 21:29:27 +00006318 if (params->phy[INT_PHY].config_init)
6319 params->phy[INT_PHY].config_init(phy,
6320 params,
6321 vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006322 }
6323
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00006324 /* Init external phy*/
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00006325 if (non_ext_phy) {
6326 if (params->phy[INT_PHY].supported &
6327 SUPPORTED_FIBRE)
6328 vars->link_status |= LINK_STATUS_SERDES_LINK;
6329 } else {
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006330 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
6331 phy_index++) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006332 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006333 * No need to initialize second phy in case of first
6334 * phy only selection. In case of second phy, we do
6335 * need to initialize the first phy, since they are
6336 * connected.
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006337 */
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00006338 if (params->phy[phy_index].supported &
6339 SUPPORTED_FIBRE)
6340 vars->link_status |= LINK_STATUS_SERDES_LINK;
6341
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006342 if (phy_index == EXT_PHY2 &&
6343 (bnx2x_phy_selection(params) ==
6344 PORT_HW_CFG_PHY_SELECTION_FIRST_PHY)) {
Joe Perches94f05b02011-08-14 12:16:20 +00006345 DP(NETIF_MSG_LINK,
6346 "Not initializing second phy\n");
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006347 continue;
6348 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006349 params->phy[phy_index].config_init(
6350 &params->phy[phy_index],
6351 params, vars);
6352 }
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00006353 }
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00006354 /* Reset the interrupt indication after phy was initialized */
6355 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 +
6356 params->port*4,
6357 (NIG_STATUS_XGXS0_LINK10G |
6358 NIG_STATUS_XGXS0_LINK_STATUS |
6359 NIG_STATUS_SERDES0_LINK_STATUS |
6360 NIG_MASK_MI_INT));
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00006361 bnx2x_update_mng(params, vars->link_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006362 return rc;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006363}
6364
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006365static void bnx2x_int_link_reset(struct bnx2x_phy *phy,
6366 struct link_params *params)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006367{
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006368 /* reset the SerDes/XGXS */
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006369 REG_WR(params->bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
6370 (0x1ff << (params->port*16)));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006371}
6372
6373static void bnx2x_common_ext_link_reset(struct bnx2x_phy *phy,
6374 struct link_params *params)
6375{
6376 struct bnx2x *bp = params->bp;
6377 u8 gpio_port;
6378 /* HW reset */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00006379 if (CHIP_IS_E2(bp))
6380 gpio_port = BP_PATH(bp);
6381 else
6382 gpio_port = params->port;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006383 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006384 MISC_REGISTERS_GPIO_OUTPUT_LOW,
6385 gpio_port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006386 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006387 MISC_REGISTERS_GPIO_OUTPUT_LOW,
6388 gpio_port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006389 DP(NETIF_MSG_LINK, "reset external PHY\n");
6390}
6391
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006392static int bnx2x_update_link_down(struct link_params *params,
6393 struct link_vars *vars)
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006394{
6395 struct bnx2x *bp = params->bp;
6396 u8 port = params->port;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00006397
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006398 DP(NETIF_MSG_LINK, "Port %x: Link is down\n", port);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006399 bnx2x_set_led(params, vars, LED_MODE_OFF, 0);
Yaniv Rosner3deb8162011-06-14 01:34:33 +00006400 vars->phy_flags &= ~PHY_PHYSICAL_LINK_FLAG;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006401 /* indicate no mac active */
6402 vars->mac_type = MAC_TYPE_NONE;
6403
6404 /* update shared memory */
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00006405 vars->link_status &= ~(LINK_STATUS_SPEED_AND_DUPLEX_MASK |
6406 LINK_STATUS_LINK_UP |
Yaniv Rosnerde6f3372011-08-02 22:59:25 +00006407 LINK_STATUS_PHYSICAL_LINK_FLAG |
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00006408 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE |
6409 LINK_STATUS_RX_FLOW_CONTROL_FLAG_MASK |
6410 LINK_STATUS_TX_FLOW_CONTROL_FLAG_MASK |
6411 LINK_STATUS_PARALLEL_DETECTION_FLAG_MASK);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006412 vars->line_speed = 0;
6413 bnx2x_update_mng(params, vars->link_status);
6414
6415 /* activate nig drain */
6416 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
6417
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00006418 /* disable emac */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00006419 if (!CHIP_IS_E3(bp))
6420 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00006421
6422 msleep(10);
Yaniv Rosner9380bb92011-06-14 01:34:07 +00006423 /* reset BigMac/Xmac */
6424 if (CHIP_IS_E1x(bp) ||
6425 CHIP_IS_E2(bp)) {
6426 bnx2x_bmac_rx_disable(bp, params->port);
6427 REG_WR(bp, GRCBASE_MISC +
6428 MISC_REGISTERS_RESET_REG_2_CLEAR,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006429 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
Yaniv Rosner9380bb92011-06-14 01:34:07 +00006430 }
Yaniv Rosnerce7c0482011-10-27 05:09:47 +00006431 if (CHIP_IS_E3(bp)) {
Yaniv Rosner9380bb92011-06-14 01:34:07 +00006432 bnx2x_xmac_disable(params);
Yaniv Rosnerce7c0482011-10-27 05:09:47 +00006433 bnx2x_umac_disable(params);
6434 }
Yaniv Rosner9380bb92011-06-14 01:34:07 +00006435
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006436 return 0;
6437}
6438
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006439static int bnx2x_update_link_up(struct link_params *params,
6440 struct link_vars *vars,
6441 u8 link_10g)
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006442{
6443 struct bnx2x *bp = params->bp;
6444 u8 port = params->port;
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006445 int rc = 0;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00006446
Yaniv Rosnerde6f3372011-08-02 22:59:25 +00006447 vars->link_status |= (LINK_STATUS_LINK_UP |
6448 LINK_STATUS_PHYSICAL_LINK_FLAG);
Yaniv Rosner3deb8162011-06-14 01:34:33 +00006449 vars->phy_flags |= PHY_PHYSICAL_LINK_FLAG;
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006450
Yaniv Rosner7aa07112010-09-07 11:41:01 +00006451 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
6452 vars->link_status |=
6453 LINK_STATUS_TX_FLOW_CONTROL_ENABLED;
6454
6455 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
6456 vars->link_status |=
6457 LINK_STATUS_RX_FLOW_CONTROL_ENABLED;
Yaniv Rosner9380bb92011-06-14 01:34:07 +00006458 if (USES_WARPCORE(bp)) {
Yaniv Rosner3deb8162011-06-14 01:34:33 +00006459 if (link_10g) {
6460 if (bnx2x_xmac_enable(params, vars, 0) ==
6461 -ESRCH) {
6462 DP(NETIF_MSG_LINK, "Found errors on XMAC\n");
6463 vars->link_up = 0;
6464 vars->phy_flags |= PHY_HALF_OPEN_CONN_FLAG;
6465 vars->link_status &= ~LINK_STATUS_LINK_UP;
6466 }
6467 } else
Yaniv Rosner9380bb92011-06-14 01:34:07 +00006468 bnx2x_umac_enable(params, vars, 0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006469 bnx2x_set_led(params, vars,
Yaniv Rosner9380bb92011-06-14 01:34:07 +00006470 LED_MODE_OPER, vars->line_speed);
6471 }
6472 if ((CHIP_IS_E1x(bp) ||
6473 CHIP_IS_E2(bp))) {
6474 if (link_10g) {
Yaniv Rosner3deb8162011-06-14 01:34:33 +00006475 if (bnx2x_bmac_enable(params, vars, 0) ==
6476 -ESRCH) {
6477 DP(NETIF_MSG_LINK, "Found errors on BMAC\n");
6478 vars->link_up = 0;
6479 vars->phy_flags |= PHY_HALF_OPEN_CONN_FLAG;
6480 vars->link_status &= ~LINK_STATUS_LINK_UP;
6481 }
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006482
Yaniv Rosner9380bb92011-06-14 01:34:07 +00006483 bnx2x_set_led(params, vars,
6484 LED_MODE_OPER, SPEED_10000);
6485 } else {
6486 rc = bnx2x_emac_program(params, vars);
6487 bnx2x_emac_enable(params, vars, 0);
Yaniv Rosner0c786f02009-11-05 19:18:32 +02006488
Yaniv Rosner9380bb92011-06-14 01:34:07 +00006489 /* AN complete? */
6490 if ((vars->link_status &
6491 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE)
6492 && (!(vars->phy_flags & PHY_SGMII_FLAG)) &&
6493 SINGLE_MEDIA_DIRECT(params))
6494 bnx2x_set_gmii_tx_driver(params);
6495 }
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006496 }
6497
6498 /* PBF - link up */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00006499 if (CHIP_IS_E1x(bp))
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00006500 rc |= bnx2x_pbf_update(params, vars->flow_ctrl,
6501 vars->line_speed);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006502
6503 /* disable drain */
6504 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 0);
6505
6506 /* update shared memory */
6507 bnx2x_update_mng(params, vars->link_status);
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00006508 msleep(20);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006509 return rc;
6510}
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006511/*
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006512 * The bnx2x_link_update function should be called upon link
6513 * interrupt.
6514 * Link is considered up as follows:
6515 * - DIRECT_SINGLE_MEDIA - Only XGXS link (internal link) needs
6516 * to be up
6517 * - SINGLE_MEDIA - The link between the 577xx and the external
6518 * phy (XGXS) need to up as well as the external link of the
6519 * phy (PHY_EXT1)
6520 * - DUAL_MEDIA - The link between the 577xx and the first
6521 * external phy needs to be up, and at least one of the 2
6522 * external phy link must be up.
Yaniv Rosner62b29a52010-09-07 11:40:58 +00006523 */
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006524int bnx2x_link_update(struct link_params *params, struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006525{
6526 struct bnx2x *bp = params->bp;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006527 struct link_vars phy_vars[MAX_PHYS];
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006528 u8 port = params->port;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00006529 u8 link_10g_plus, phy_index;
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006530 u8 ext_phy_link_up = 0, cur_link_up;
6531 int rc = 0;
Eilon Greenstein2f904462009-08-12 08:22:16 +00006532 u8 is_mi_int = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006533 u16 ext_phy_line_speed = 0, prev_line_speed = vars->line_speed;
6534 u8 active_external_phy = INT_PHY;
Yaniv Rosner3deb8162011-06-14 01:34:33 +00006535 vars->phy_flags &= ~PHY_HALF_OPEN_CONN_FLAG;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006536 for (phy_index = INT_PHY; phy_index < params->num_phys;
6537 phy_index++) {
6538 phy_vars[phy_index].flow_ctrl = 0;
6539 phy_vars[phy_index].link_status = 0;
6540 phy_vars[phy_index].line_speed = 0;
6541 phy_vars[phy_index].duplex = DUPLEX_FULL;
6542 phy_vars[phy_index].phy_link_up = 0;
6543 phy_vars[phy_index].link_up = 0;
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00006544 phy_vars[phy_index].fault_detected = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006545 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006546
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00006547 if (USES_WARPCORE(bp))
6548 bnx2x_set_aer_mmd(params, &params->phy[INT_PHY]);
6549
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006550 DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n",
Eilon Greenstein2f904462009-08-12 08:22:16 +00006551 port, (vars->phy_flags & PHY_XGXS_FLAG),
6552 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006553
Eilon Greenstein2f904462009-08-12 08:22:16 +00006554 is_mi_int = (u8)(REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006555 port*0x18) > 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006556 DP(NETIF_MSG_LINK, "int_mask 0x%x MI_INT %x, SERDES_LINK %x\n",
Eilon Greenstein2f904462009-08-12 08:22:16 +00006557 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
6558 is_mi_int,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006559 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006560
6561 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
6562 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
6563 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
6564
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00006565 /* disable emac */
Yaniv Rosner9380bb92011-06-14 01:34:07 +00006566 if (!CHIP_IS_E3(bp))
6567 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00006568
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006569 /*
6570 * Step 1:
6571 * Check external link change only for external phys, and apply
6572 * priority selection between them in case the link on both phys
Yaniv Rosner9045f6b2011-05-31 21:28:27 +00006573 * is up. Note that instead of the common vars, a temporary
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006574 * vars argument is used since each phy may have different link/
6575 * speed/duplex result
6576 */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006577 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
6578 phy_index++) {
6579 struct bnx2x_phy *phy = &params->phy[phy_index];
6580 if (!phy->read_status)
6581 continue;
6582 /* Read link status and params of this ext phy */
6583 cur_link_up = phy->read_status(phy, params,
6584 &phy_vars[phy_index]);
6585 if (cur_link_up) {
6586 DP(NETIF_MSG_LINK, "phy in index %d link is up\n",
6587 phy_index);
6588 } else {
6589 DP(NETIF_MSG_LINK, "phy in index %d link is down\n",
6590 phy_index);
6591 continue;
6592 }
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006593
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006594 if (!ext_phy_link_up) {
6595 ext_phy_link_up = 1;
6596 active_external_phy = phy_index;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006597 } else {
6598 switch (bnx2x_phy_selection(params)) {
6599 case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT:
6600 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006601 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006602 * In this option, the first PHY makes sure to pass the
6603 * traffic through itself only.
6604 * Its not clear how to reset the link on the second phy
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006605 */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006606 active_external_phy = EXT_PHY1;
6607 break;
6608 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006609 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006610 * In this option, the first PHY makes sure to pass the
6611 * traffic through the second PHY.
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006612 */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006613 active_external_phy = EXT_PHY2;
6614 break;
6615 default:
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006616 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006617 * Link indication on both PHYs with the following cases
6618 * is invalid:
6619 * - FIRST_PHY means that second phy wasn't initialized,
6620 * hence its link is expected to be down
6621 * - SECOND_PHY means that first phy should not be able
6622 * to link up by itself (using configuration)
6623 * - DEFAULT should be overriden during initialiazation
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006624 */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006625 DP(NETIF_MSG_LINK, "Invalid link indication"
6626 "mpc=0x%x. DISABLING LINK !!!\n",
6627 params->multi_phy_config);
6628 ext_phy_link_up = 0;
6629 break;
6630 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006631 }
6632 }
6633 prev_line_speed = vars->line_speed;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006634 /*
6635 * Step 2:
6636 * Read the status of the internal phy. In case of
6637 * DIRECT_SINGLE_MEDIA board, this link is the external link,
6638 * otherwise this is the link between the 577xx and the first
6639 * external phy
6640 */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006641 if (params->phy[INT_PHY].read_status)
6642 params->phy[INT_PHY].read_status(
6643 &params->phy[INT_PHY],
6644 params, vars);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006645 /*
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006646 * The INT_PHY flow control reside in the vars. This include the
6647 * case where the speed or flow control are not set to AUTO.
6648 * Otherwise, the active external phy flow control result is set
6649 * to the vars. The ext_phy_line_speed is needed to check if the
6650 * speed is different between the internal phy and external phy.
6651 * This case may be result of intermediate link speed change.
6652 */
6653 if (active_external_phy > INT_PHY) {
6654 vars->flow_ctrl = phy_vars[active_external_phy].flow_ctrl;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006655 /*
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006656 * Link speed is taken from the XGXS. AN and FC result from
6657 * the external phy.
6658 */
6659 vars->link_status |= phy_vars[active_external_phy].link_status;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006660
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006661 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006662 * if active_external_phy is first PHY and link is up - disable
6663 * disable TX on second external PHY
6664 */
6665 if (active_external_phy == EXT_PHY1) {
6666 if (params->phy[EXT_PHY2].phy_specific_func) {
Joe Perches94f05b02011-08-14 12:16:20 +00006667 DP(NETIF_MSG_LINK,
6668 "Disabling TX on EXT_PHY2\n");
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006669 params->phy[EXT_PHY2].phy_specific_func(
6670 &params->phy[EXT_PHY2],
6671 params, DISABLE_TX);
6672 }
6673 }
6674
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006675 ext_phy_line_speed = phy_vars[active_external_phy].line_speed;
6676 vars->duplex = phy_vars[active_external_phy].duplex;
6677 if (params->phy[active_external_phy].supported &
6678 SUPPORTED_FIBRE)
6679 vars->link_status |= LINK_STATUS_SERDES_LINK;
Yaniv Rosnerfd36a2e2011-05-31 21:29:05 +00006680 else
6681 vars->link_status &= ~LINK_STATUS_SERDES_LINK;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006682 DP(NETIF_MSG_LINK, "Active external phy selected: %x\n",
6683 active_external_phy);
6684 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006685
6686 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
6687 phy_index++) {
6688 if (params->phy[phy_index].flags &
6689 FLAGS_REARM_LATCH_SIGNAL) {
6690 bnx2x_rearm_latch_signal(bp, port,
6691 phy_index ==
6692 active_external_phy);
6693 break;
6694 }
6695 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006696 DP(NETIF_MSG_LINK, "vars->flow_ctrl = 0x%x, vars->link_status = 0x%x,"
6697 " ext_phy_line_speed = %d\n", vars->flow_ctrl,
6698 vars->link_status, ext_phy_line_speed);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006699 /*
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006700 * Upon link speed change set the NIG into drain mode. Comes to
6701 * deals with possible FIFO glitch due to clk change when speed
6702 * is decreased without link down indicator
6703 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006704
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006705 if (vars->phy_link_up) {
6706 if (!(SINGLE_MEDIA_DIRECT(params)) && ext_phy_link_up &&
6707 (ext_phy_line_speed != vars->line_speed)) {
6708 DP(NETIF_MSG_LINK, "Internal link speed %d is"
6709 " different than the external"
6710 " link speed %d\n", vars->line_speed,
6711 ext_phy_line_speed);
6712 vars->phy_link_up = 0;
6713 } else if (prev_line_speed != vars->line_speed) {
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006714 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4,
6715 0);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006716 msleep(1);
6717 }
6718 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006719
6720 /* anything 10 and over uses the bmac */
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00006721 link_10g_plus = (vars->line_speed >= SPEED_10000);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006722
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00006723 bnx2x_link_int_ack(params, vars, link_10g_plus);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006724
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006725 /*
6726 * In case external phy link is up, and internal link is down
6727 * (not initialized yet probably after link initialization, it
6728 * needs to be initialized.
6729 * Note that after link down-up as result of cable plug, the xgxs
6730 * link would probably become up again without the need
6731 * initialize it
6732 */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006733 if (!(SINGLE_MEDIA_DIRECT(params))) {
6734 DP(NETIF_MSG_LINK, "ext_phy_link_up = %d, int_link_up = %d,"
6735 " init_preceding = %d\n", ext_phy_link_up,
6736 vars->phy_link_up,
6737 params->phy[EXT_PHY1].flags &
6738 FLAGS_INIT_XGXS_FIRST);
6739 if (!(params->phy[EXT_PHY1].flags &
6740 FLAGS_INIT_XGXS_FIRST)
6741 && ext_phy_link_up && !vars->phy_link_up) {
6742 vars->line_speed = ext_phy_line_speed;
6743 if (vars->line_speed < SPEED_1000)
6744 vars->phy_flags |= PHY_SGMII_FLAG;
6745 else
6746 vars->phy_flags &= ~PHY_SGMII_FLAG;
Yaniv Rosnerec146a62011-05-31 21:29:27 +00006747
6748 if (params->phy[INT_PHY].config_init)
6749 params->phy[INT_PHY].config_init(
6750 &params->phy[INT_PHY], params,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006751 vars);
6752 }
6753 }
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006754 /*
6755 * Link is up only if both local phy and external phy (in case of
Yaniv Rosner9045f6b2011-05-31 21:28:27 +00006756 * non-direct board) are up and no fault detected on active PHY.
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006757 */
6758 vars->link_up = (vars->phy_link_up &&
6759 (ext_phy_link_up ||
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00006760 SINGLE_MEDIA_DIRECT(params)) &&
6761 (phy_vars[active_external_phy].fault_detected == 0));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006762
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006763 if (vars->link_up)
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00006764 rc = bnx2x_update_link_up(params, vars, link_10g_plus);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006765 else
6766 rc = bnx2x_update_link_down(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006767
6768 return rc;
6769}
6770
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006771/*****************************************************************************/
6772/* External Phy section */
6773/*****************************************************************************/
6774void bnx2x_ext_phy_hw_reset(struct bnx2x *bp, u8 port)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006775{
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006776 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006777 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006778 msleep(1);
6779 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006780 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006781}
6782
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006783static void bnx2x_save_spirom_version(struct bnx2x *bp, u8 port,
6784 u32 spirom_ver, u32 ver_addr)
6785{
6786 DP(NETIF_MSG_LINK, "FW version 0x%x:0x%x for port %d\n",
6787 (u16)(spirom_ver>>16), (u16)spirom_ver, port);
6788
6789 if (ver_addr)
6790 REG_WR(bp, ver_addr, spirom_ver);
6791}
6792
6793static void bnx2x_save_bcm_spirom_ver(struct bnx2x *bp,
6794 struct bnx2x_phy *phy,
6795 u8 port)
6796{
6797 u16 fw_ver1, fw_ver2;
6798
6799 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006800 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006801 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006802 MDIO_PMA_REG_ROM_VER2, &fw_ver2);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006803 bnx2x_save_spirom_version(bp, port, (u32)(fw_ver1<<16 | fw_ver2),
6804 phy->ver_addr);
6805}
6806
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006807static void bnx2x_ext_phy_10G_an_resolve(struct bnx2x *bp,
6808 struct bnx2x_phy *phy,
6809 struct link_vars *vars)
6810{
6811 u16 val;
6812 bnx2x_cl45_read(bp, phy,
6813 MDIO_AN_DEVAD,
6814 MDIO_AN_REG_STATUS, &val);
6815 bnx2x_cl45_read(bp, phy,
6816 MDIO_AN_DEVAD,
6817 MDIO_AN_REG_STATUS, &val);
6818 if (val & (1<<5))
6819 vars->link_status |= LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
6820 if ((val & (1<<0)) == 0)
6821 vars->link_status |= LINK_STATUS_PARALLEL_DETECTION_USED;
6822}
6823
6824/******************************************************************/
6825/* common BCM8073/BCM8727 PHY SECTION */
6826/******************************************************************/
6827static void bnx2x_8073_resolve_fc(struct bnx2x_phy *phy,
6828 struct link_params *params,
6829 struct link_vars *vars)
6830{
6831 struct bnx2x *bp = params->bp;
6832 if (phy->req_line_speed == SPEED_10 ||
6833 phy->req_line_speed == SPEED_100) {
6834 vars->flow_ctrl = phy->req_flow_ctrl;
6835 return;
6836 }
6837
6838 if (bnx2x_ext_phy_resolve_fc(phy, params, vars) &&
6839 (vars->flow_ctrl == BNX2X_FLOW_CTRL_NONE)) {
6840 u16 pause_result;
6841 u16 ld_pause; /* local */
6842 u16 lp_pause; /* link partner */
6843 bnx2x_cl45_read(bp, phy,
6844 MDIO_AN_DEVAD,
6845 MDIO_AN_REG_CL37_FC_LD, &ld_pause);
6846
6847 bnx2x_cl45_read(bp, phy,
6848 MDIO_AN_DEVAD,
6849 MDIO_AN_REG_CL37_FC_LP, &lp_pause);
6850 pause_result = (ld_pause &
6851 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 5;
6852 pause_result |= (lp_pause &
6853 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 7;
6854
6855 bnx2x_pause_resolve(vars, pause_result);
6856 DP(NETIF_MSG_LINK, "Ext PHY CL37 pause result 0x%x\n",
6857 pause_result);
6858 }
6859}
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006860static int bnx2x_8073_8727_external_rom_boot(struct bnx2x *bp,
6861 struct bnx2x_phy *phy,
6862 u8 port)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006863{
Yaniv Rosner5c99274b2011-01-18 04:33:36 +00006864 u32 count = 0;
6865 u16 fw_ver1, fw_msgout;
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006866 int rc = 0;
Yaniv Rosner5c99274b2011-01-18 04:33:36 +00006867
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006868 /* Boot port from external ROM */
6869 /* EDC grst */
6870 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006871 MDIO_PMA_DEVAD,
6872 MDIO_PMA_REG_GEN_CTRL,
6873 0x0001);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006874
6875 /* ucode reboot and rst */
6876 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006877 MDIO_PMA_DEVAD,
6878 MDIO_PMA_REG_GEN_CTRL,
6879 0x008c);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006880
6881 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006882 MDIO_PMA_DEVAD,
6883 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006884
6885 /* Reset internal microprocessor */
6886 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006887 MDIO_PMA_DEVAD,
6888 MDIO_PMA_REG_GEN_CTRL,
6889 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006890
6891 /* Release srst bit */
6892 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006893 MDIO_PMA_DEVAD,
6894 MDIO_PMA_REG_GEN_CTRL,
6895 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006896
Yaniv Rosner5c99274b2011-01-18 04:33:36 +00006897 /* Delay 100ms per the PHY specifications */
6898 msleep(100);
6899
6900 /* 8073 sometimes taking longer to download */
6901 do {
6902 count++;
6903 if (count > 300) {
6904 DP(NETIF_MSG_LINK,
6905 "bnx2x_8073_8727_external_rom_boot port %x:"
6906 "Download failed. fw version = 0x%x\n",
6907 port, fw_ver1);
6908 rc = -EINVAL;
6909 break;
6910 }
6911
6912 bnx2x_cl45_read(bp, phy,
6913 MDIO_PMA_DEVAD,
6914 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
6915 bnx2x_cl45_read(bp, phy,
6916 MDIO_PMA_DEVAD,
6917 MDIO_PMA_REG_M8051_MSGOUT_REG, &fw_msgout);
6918
6919 msleep(1);
6920 } while (fw_ver1 == 0 || fw_ver1 == 0x4321 ||
6921 ((fw_msgout & 0xff) != 0x03 && (phy->type ==
6922 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073)));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006923
6924 /* Clear ser_boot_ctl bit */
6925 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006926 MDIO_PMA_DEVAD,
6927 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006928 bnx2x_save_bcm_spirom_ver(bp, phy, port);
Yaniv Rosner5c99274b2011-01-18 04:33:36 +00006929
6930 DP(NETIF_MSG_LINK,
6931 "bnx2x_8073_8727_external_rom_boot port %x:"
6932 "Download complete. fw version = 0x%x\n",
6933 port, fw_ver1);
6934
6935 return rc;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006936}
6937
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006938/******************************************************************/
6939/* BCM8073 PHY SECTION */
6940/******************************************************************/
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006941static int bnx2x_8073_is_snr_needed(struct bnx2x *bp, struct bnx2x_phy *phy)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006942{
6943 /* This is only required for 8073A1, version 102 only */
6944 u16 val;
6945
6946 /* Read 8073 HW revision*/
6947 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006948 MDIO_PMA_DEVAD,
6949 MDIO_PMA_REG_8073_CHIP_REV, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006950
6951 if (val != 1) {
6952 /* No need to workaround in 8073 A1 */
6953 return 0;
6954 }
6955
6956 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006957 MDIO_PMA_DEVAD,
6958 MDIO_PMA_REG_ROM_VER2, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006959
6960 /* SNR should be applied only for version 0x102 */
6961 if (val != 0x102)
6962 return 0;
6963
6964 return 1;
6965}
6966
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00006967static int bnx2x_8073_xaui_wa(struct bnx2x *bp, struct bnx2x_phy *phy)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006968{
6969 u16 val, cnt, cnt1 ;
6970
6971 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006972 MDIO_PMA_DEVAD,
6973 MDIO_PMA_REG_8073_CHIP_REV, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006974
6975 if (val > 0) {
6976 /* No need to workaround in 8073 A1 */
6977 return 0;
6978 }
6979 /* XAUI workaround in 8073 A0: */
6980
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006981 /*
6982 * After loading the boot ROM and restarting Autoneg, poll
6983 * Dev1, Reg $C820:
6984 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006985
6986 for (cnt = 0; cnt < 1000; cnt++) {
6987 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00006988 MDIO_PMA_DEVAD,
6989 MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
6990 &val);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00006991 /*
6992 * If bit [14] = 0 or bit [13] = 0, continue on with
6993 * system initialization (XAUI work-around not required, as
6994 * these bits indicate 2.5G or 1G link up).
6995 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006996 if (!(val & (1<<14)) || !(val & (1<<13))) {
6997 DP(NETIF_MSG_LINK, "XAUI work-around not required\n");
6998 return 0;
6999 } else if (!(val & (1<<15))) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007000 DP(NETIF_MSG_LINK, "bit 15 went off\n");
7001 /*
7002 * If bit 15 is 0, then poll Dev1, Reg $C841 until it's
7003 * MSB (bit15) goes to 1 (indicating that the XAUI
7004 * workaround has completed), then continue on with
7005 * system initialization.
7006 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007007 for (cnt1 = 0; cnt1 < 1000; cnt1++) {
7008 bnx2x_cl45_read(bp, phy,
7009 MDIO_PMA_DEVAD,
7010 MDIO_PMA_REG_8073_XAUI_WA, &val);
7011 if (val & (1<<15)) {
7012 DP(NETIF_MSG_LINK,
7013 "XAUI workaround has completed\n");
7014 return 0;
7015 }
7016 msleep(3);
7017 }
7018 break;
7019 }
7020 msleep(3);
7021 }
7022 DP(NETIF_MSG_LINK, "Warning: XAUI work-around timeout !!!\n");
7023 return -EINVAL;
7024}
7025
7026static void bnx2x_807x_force_10G(struct bnx2x *bp, struct bnx2x_phy *phy)
7027{
7028 /* Force KR or KX */
7029 bnx2x_cl45_write(bp, phy,
7030 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x2040);
7031 bnx2x_cl45_write(bp, phy,
7032 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0x000b);
7033 bnx2x_cl45_write(bp, phy,
7034 MDIO_PMA_DEVAD, MDIO_PMA_REG_BCM_CTRL, 0x0000);
7035 bnx2x_cl45_write(bp, phy,
7036 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x0000);
7037}
7038
7039static void bnx2x_8073_set_pause_cl37(struct link_params *params,
7040 struct bnx2x_phy *phy,
7041 struct link_vars *vars)
7042{
7043 u16 cl37_val;
7044 struct bnx2x *bp = params->bp;
7045 bnx2x_cl45_read(bp, phy,
7046 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, &cl37_val);
7047
7048 cl37_val &= ~MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
7049 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
7050 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
7051 if ((vars->ieee_fc &
7052 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) ==
7053 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) {
7054 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC;
7055 }
7056 if ((vars->ieee_fc &
7057 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
7058 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
7059 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
7060 }
7061 if ((vars->ieee_fc &
7062 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
7063 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
7064 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
7065 }
7066 DP(NETIF_MSG_LINK,
7067 "Ext phy AN advertize cl37 0x%x\n", cl37_val);
7068
7069 bnx2x_cl45_write(bp, phy,
7070 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, cl37_val);
7071 msleep(500);
7072}
7073
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00007074static int bnx2x_8073_config_init(struct bnx2x_phy *phy,
7075 struct link_params *params,
7076 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007077{
7078 struct bnx2x *bp = params->bp;
7079 u16 val = 0, tmp1;
7080 u8 gpio_port;
7081 DP(NETIF_MSG_LINK, "Init 8073\n");
7082
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007083 if (CHIP_IS_E2(bp))
7084 gpio_port = BP_PATH(bp);
7085 else
7086 gpio_port = params->port;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007087 /* Restore normal power mode*/
7088 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007089 MISC_REGISTERS_GPIO_OUTPUT_HIGH, gpio_port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007090
7091 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007092 MISC_REGISTERS_GPIO_OUTPUT_HIGH, gpio_port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007093
7094 /* enable LASI */
7095 bnx2x_cl45_write(bp, phy,
Yaniv Rosner60d2fe02011-06-14 01:34:38 +00007096 MDIO_PMA_DEVAD, MDIO_PMA_LASI_RXCTRL, (1<<2));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007097 bnx2x_cl45_write(bp, phy,
Yaniv Rosner60d2fe02011-06-14 01:34:38 +00007098 MDIO_PMA_DEVAD, MDIO_PMA_LASI_CTRL, 0x0004);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007099
7100 bnx2x_8073_set_pause_cl37(params, phy, vars);
7101
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007102 bnx2x_cl45_read(bp, phy,
7103 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &tmp1);
7104
7105 bnx2x_cl45_read(bp, phy,
Yaniv Rosner60d2fe02011-06-14 01:34:38 +00007106 MDIO_PMA_DEVAD, MDIO_PMA_LASI_RXSTAT, &tmp1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007107
7108 DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1): 0x%x\n", tmp1);
7109
Yaniv Rosner74d7a112011-01-18 04:33:18 +00007110 /* Swap polarity if required - Must be done only in non-1G mode */
7111 if (params->lane_config & PORT_HW_CFG_SWAP_PHY_POLARITY_ENABLED) {
7112 /* Configure the 8073 to swap _P and _N of the KR lines */
7113 DP(NETIF_MSG_LINK, "Swapping polarity for the 8073\n");
7114 /* 10G Rx/Tx and 1G Tx signal polarity swap */
7115 bnx2x_cl45_read(bp, phy,
7116 MDIO_PMA_DEVAD,
7117 MDIO_PMA_REG_8073_OPT_DIGITAL_CTRL, &val);
7118 bnx2x_cl45_write(bp, phy,
7119 MDIO_PMA_DEVAD,
7120 MDIO_PMA_REG_8073_OPT_DIGITAL_CTRL,
7121 (val | (3<<9)));
7122 }
7123
7124
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007125 /* Enable CL37 BAM */
Yaniv Rosner121839b2010-11-01 05:32:38 +00007126 if (REG_RD(bp, params->shmem_base +
7127 offsetof(struct shmem_region, dev_info.
7128 port_hw_config[params->port].default_cfg)) &
7129 PORT_HW_CFG_ENABLE_BAM_ON_KR_ENABLED) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007130
Yaniv Rosner121839b2010-11-01 05:32:38 +00007131 bnx2x_cl45_read(bp, phy,
7132 MDIO_AN_DEVAD,
7133 MDIO_AN_REG_8073_BAM, &val);
7134 bnx2x_cl45_write(bp, phy,
7135 MDIO_AN_DEVAD,
7136 MDIO_AN_REG_8073_BAM, val | 1);
7137 DP(NETIF_MSG_LINK, "Enable CL37 BAM on KR\n");
7138 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007139 if (params->loopback_mode == LOOPBACK_EXT) {
7140 bnx2x_807x_force_10G(bp, phy);
7141 DP(NETIF_MSG_LINK, "Forced speed 10G on 807X\n");
7142 return 0;
7143 } else {
7144 bnx2x_cl45_write(bp, phy,
7145 MDIO_PMA_DEVAD, MDIO_PMA_REG_BCM_CTRL, 0x0002);
7146 }
7147 if (phy->req_line_speed != SPEED_AUTO_NEG) {
7148 if (phy->req_line_speed == SPEED_10000) {
7149 val = (1<<7);
7150 } else if (phy->req_line_speed == SPEED_2500) {
7151 val = (1<<5);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007152 /*
7153 * Note that 2.5G works only when used with 1G
Lucas De Marchi25985ed2011-03-30 22:57:33 -03007154 * advertisement
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007155 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007156 } else
7157 val = (1<<5);
7158 } else {
7159 val = 0;
7160 if (phy->speed_cap_mask &
7161 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
7162 val |= (1<<7);
7163
Lucas De Marchi25985ed2011-03-30 22:57:33 -03007164 /* Note that 2.5G works only when used with 1G advertisement */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007165 if (phy->speed_cap_mask &
7166 (PORT_HW_CFG_SPEED_CAPABILITY_D0_1G |
7167 PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G))
7168 val |= (1<<5);
7169 DP(NETIF_MSG_LINK, "807x autoneg val = 0x%x\n", val);
7170 }
7171
7172 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV, val);
7173 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_8073_2_5G, &tmp1);
7174
7175 if (((phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G) &&
7176 (phy->req_line_speed == SPEED_AUTO_NEG)) ||
7177 (phy->req_line_speed == SPEED_2500)) {
7178 u16 phy_ver;
7179 /* Allow 2.5G for A1 and above */
7180 bnx2x_cl45_read(bp, phy,
7181 MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_CHIP_REV,
7182 &phy_ver);
7183 DP(NETIF_MSG_LINK, "Add 2.5G\n");
7184 if (phy_ver > 0)
7185 tmp1 |= 1;
7186 else
7187 tmp1 &= 0xfffe;
7188 } else {
7189 DP(NETIF_MSG_LINK, "Disable 2.5G\n");
7190 tmp1 &= 0xfffe;
7191 }
7192
7193 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_8073_2_5G, tmp1);
7194 /* Add support for CL37 (passive mode) II */
7195
7196 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, &tmp1);
7197 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD,
7198 (tmp1 | ((phy->req_duplex == DUPLEX_FULL) ?
7199 0x20 : 0x40)));
7200
7201 /* Add support for CL37 (passive mode) III */
7202 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
7203
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007204 /*
7205 * The SNR will improve about 2db by changing BW and FEE main
7206 * tap. Rest commands are executed after link is up
7207 * Change FFE main cursor to 5 in EDC register
7208 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007209 if (bnx2x_8073_is_snr_needed(bp, phy))
7210 bnx2x_cl45_write(bp, phy,
7211 MDIO_PMA_DEVAD, MDIO_PMA_REG_EDC_FFE_MAIN,
7212 0xFB0C);
7213
7214 /* Enable FEC (Forware Error Correction) Request in the AN */
7215 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV2, &tmp1);
7216 tmp1 |= (1<<15);
7217 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV2, tmp1);
7218
7219 bnx2x_ext_phy_set_pause(params, phy, vars);
7220
7221 /* Restart autoneg */
7222 msleep(500);
7223 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
7224 DP(NETIF_MSG_LINK, "807x Autoneg Restart: Advertise 1G=%x, 10G=%x\n",
7225 ((val & (1<<5)) > 0), ((val & (1<<7)) > 0));
7226 return 0;
7227}
7228
7229static u8 bnx2x_8073_read_status(struct bnx2x_phy *phy,
7230 struct link_params *params,
7231 struct link_vars *vars)
7232{
7233 struct bnx2x *bp = params->bp;
7234 u8 link_up = 0;
7235 u16 val1, val2;
7236 u16 link_status = 0;
7237 u16 an1000_status = 0;
7238
7239 bnx2x_cl45_read(bp, phy,
Yaniv Rosner60d2fe02011-06-14 01:34:38 +00007240 MDIO_PMA_DEVAD, MDIO_PMA_LASI_STAT, &val1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007241
7242 DP(NETIF_MSG_LINK, "8703 LASI status 0x%x\n", val1);
7243
7244 /* clear the interrupt LASI status register */
7245 bnx2x_cl45_read(bp, phy,
7246 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val2);
7247 bnx2x_cl45_read(bp, phy,
7248 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val1);
7249 DP(NETIF_MSG_LINK, "807x PCS status 0x%x->0x%x\n", val2, val1);
7250 /* Clear MSG-OUT */
7251 bnx2x_cl45_read(bp, phy,
7252 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &val1);
7253
7254 /* Check the LASI */
7255 bnx2x_cl45_read(bp, phy,
Yaniv Rosner60d2fe02011-06-14 01:34:38 +00007256 MDIO_PMA_DEVAD, MDIO_PMA_LASI_RXSTAT, &val2);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007257
7258 DP(NETIF_MSG_LINK, "KR 0x9003 0x%x\n", val2);
7259
7260 /* Check the link status */
7261 bnx2x_cl45_read(bp, phy,
7262 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val2);
7263 DP(NETIF_MSG_LINK, "KR PCS status 0x%x\n", val2);
7264
7265 bnx2x_cl45_read(bp, phy,
7266 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
7267 bnx2x_cl45_read(bp, phy,
7268 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
7269 link_up = ((val1 & 4) == 4);
7270 DP(NETIF_MSG_LINK, "PMA_REG_STATUS=0x%x\n", val1);
7271
7272 if (link_up &&
7273 ((phy->req_line_speed != SPEED_10000))) {
7274 if (bnx2x_8073_xaui_wa(bp, phy) != 0)
7275 return 0;
7276 }
7277 bnx2x_cl45_read(bp, phy,
7278 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &an1000_status);
7279 bnx2x_cl45_read(bp, phy,
7280 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &an1000_status);
7281
7282 /* Check the link status on 1.1.2 */
7283 bnx2x_cl45_read(bp, phy,
7284 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
7285 bnx2x_cl45_read(bp, phy,
7286 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
7287 DP(NETIF_MSG_LINK, "KR PMA status 0x%x->0x%x,"
7288 "an_link_status=0x%x\n", val2, val1, an1000_status);
7289
7290 link_up = (((val1 & 4) == 4) || (an1000_status & (1<<1)));
7291 if (link_up && bnx2x_8073_is_snr_needed(bp, phy)) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007292 /*
7293 * The SNR will improve about 2dbby changing the BW and FEE main
7294 * tap. The 1st write to change FFE main tap is set before
7295 * restart AN. Change PLL Bandwidth in EDC register
7296 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007297 bnx2x_cl45_write(bp, phy,
7298 MDIO_PMA_DEVAD, MDIO_PMA_REG_PLL_BANDWIDTH,
7299 0x26BC);
7300
7301 /* Change CDR Bandwidth in EDC register */
7302 bnx2x_cl45_write(bp, phy,
7303 MDIO_PMA_DEVAD, MDIO_PMA_REG_CDR_BANDWIDTH,
7304 0x0333);
7305 }
7306 bnx2x_cl45_read(bp, phy,
7307 MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
7308 &link_status);
7309
7310 /* Bits 0..2 --> speed detected, bits 13..15--> link is down */
7311 if ((link_status & (1<<2)) && (!(link_status & (1<<15)))) {
7312 link_up = 1;
7313 vars->line_speed = SPEED_10000;
7314 DP(NETIF_MSG_LINK, "port %x: External link up in 10G\n",
7315 params->port);
7316 } else if ((link_status & (1<<1)) && (!(link_status & (1<<14)))) {
7317 link_up = 1;
7318 vars->line_speed = SPEED_2500;
7319 DP(NETIF_MSG_LINK, "port %x: External link up in 2.5G\n",
7320 params->port);
7321 } else if ((link_status & (1<<0)) && (!(link_status & (1<<13)))) {
7322 link_up = 1;
7323 vars->line_speed = SPEED_1000;
7324 DP(NETIF_MSG_LINK, "port %x: External link up in 1G\n",
7325 params->port);
7326 } else {
7327 link_up = 0;
7328 DP(NETIF_MSG_LINK, "port %x: External link is down\n",
7329 params->port);
7330 }
7331
7332 if (link_up) {
Yaniv Rosner74d7a112011-01-18 04:33:18 +00007333 /* Swap polarity if required */
7334 if (params->lane_config &
7335 PORT_HW_CFG_SWAP_PHY_POLARITY_ENABLED) {
7336 /* Configure the 8073 to swap P and N of the KR lines */
7337 bnx2x_cl45_read(bp, phy,
7338 MDIO_XS_DEVAD,
7339 MDIO_XS_REG_8073_RX_CTRL_PCIE, &val1);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007340 /*
7341 * Set bit 3 to invert Rx in 1G mode and clear this bit
7342 * when it`s in 10G mode.
7343 */
Yaniv Rosner74d7a112011-01-18 04:33:18 +00007344 if (vars->line_speed == SPEED_1000) {
7345 DP(NETIF_MSG_LINK, "Swapping 1G polarity for"
7346 "the 8073\n");
7347 val1 |= (1<<3);
7348 } else
7349 val1 &= ~(1<<3);
7350
7351 bnx2x_cl45_write(bp, phy,
7352 MDIO_XS_DEVAD,
7353 MDIO_XS_REG_8073_RX_CTRL_PCIE,
7354 val1);
7355 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007356 bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
7357 bnx2x_8073_resolve_fc(phy, params, vars);
Yaniv Rosner791f18c2011-01-18 04:33:42 +00007358 vars->duplex = DUPLEX_FULL;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007359 }
7360 return link_up;
7361}
7362
7363static void bnx2x_8073_link_reset(struct bnx2x_phy *phy,
7364 struct link_params *params)
7365{
7366 struct bnx2x *bp = params->bp;
7367 u8 gpio_port;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +00007368 if (CHIP_IS_E2(bp))
7369 gpio_port = BP_PATH(bp);
7370 else
7371 gpio_port = params->port;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007372 DP(NETIF_MSG_LINK, "Setting 8073 port %d into low power mode\n",
7373 gpio_port);
7374 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007375 MISC_REGISTERS_GPIO_OUTPUT_LOW,
7376 gpio_port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007377}
7378
7379/******************************************************************/
7380/* BCM8705 PHY SECTION */
7381/******************************************************************/
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00007382static int bnx2x_8705_config_init(struct bnx2x_phy *phy,
7383 struct link_params *params,
7384 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007385{
7386 struct bnx2x *bp = params->bp;
7387 DP(NETIF_MSG_LINK, "init 8705\n");
7388 /* Restore normal power mode*/
7389 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007390 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007391 /* HW reset */
7392 bnx2x_ext_phy_hw_reset(bp, params->port);
7393 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0xa040);
Yaniv Rosner6d870c32011-01-31 04:22:20 +00007394 bnx2x_wait_reset_complete(bp, phy, params);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007395
7396 bnx2x_cl45_write(bp, phy,
7397 MDIO_PMA_DEVAD, MDIO_PMA_REG_MISC_CTRL, 0x8288);
7398 bnx2x_cl45_write(bp, phy,
7399 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, 0x7fbf);
7400 bnx2x_cl45_write(bp, phy,
7401 MDIO_PMA_DEVAD, MDIO_PMA_REG_CMU_PLL_BYPASS, 0x0100);
7402 bnx2x_cl45_write(bp, phy,
7403 MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_CNTL, 0x1);
7404 /* BCM8705 doesn't have microcode, hence the 0 */
7405 bnx2x_save_spirom_version(bp, params->port, params->shmem_base, 0);
7406 return 0;
7407}
7408
7409static u8 bnx2x_8705_read_status(struct bnx2x_phy *phy,
7410 struct link_params *params,
7411 struct link_vars *vars)
7412{
7413 u8 link_up = 0;
7414 u16 val1, rx_sd;
7415 struct bnx2x *bp = params->bp;
7416 DP(NETIF_MSG_LINK, "read status 8705\n");
7417 bnx2x_cl45_read(bp, phy,
7418 MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_STATUS, &val1);
7419 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
7420
7421 bnx2x_cl45_read(bp, phy,
7422 MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_STATUS, &val1);
7423 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
7424
7425 bnx2x_cl45_read(bp, phy,
7426 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD, &rx_sd);
7427
7428 bnx2x_cl45_read(bp, phy,
7429 MDIO_PMA_DEVAD, 0xc809, &val1);
7430 bnx2x_cl45_read(bp, phy,
7431 MDIO_PMA_DEVAD, 0xc809, &val1);
7432
7433 DP(NETIF_MSG_LINK, "8705 1.c809 val=0x%x\n", val1);
7434 link_up = ((rx_sd & 0x1) && (val1 & (1<<9)) && ((val1 & (1<<8)) == 0));
7435 if (link_up) {
7436 vars->line_speed = SPEED_10000;
7437 bnx2x_ext_phy_resolve_fc(phy, params, vars);
7438 }
7439 return link_up;
7440}
7441
7442/******************************************************************/
7443/* SFP+ module Section */
7444/******************************************************************/
Yaniv Rosner85242ee2011-07-05 01:06:53 +00007445static void bnx2x_set_disable_pmd_transmit(struct link_params *params,
7446 struct bnx2x_phy *phy,
7447 u8 pmd_dis)
7448{
7449 struct bnx2x *bp = params->bp;
7450 /*
7451 * Disable transmitter only for bootcodes which can enable it afterwards
7452 * (for D3 link)
7453 */
7454 if (pmd_dis) {
7455 if (params->feature_config_flags &
7456 FEATURE_CONFIG_BC_SUPPORTS_SFP_TX_DISABLED)
7457 DP(NETIF_MSG_LINK, "Disabling PMD transmitter\n");
7458 else {
7459 DP(NETIF_MSG_LINK, "NOT disabling PMD transmitter\n");
7460 return;
7461 }
7462 } else
7463 DP(NETIF_MSG_LINK, "Enabling PMD transmitter\n");
7464 bnx2x_cl45_write(bp, phy,
7465 MDIO_PMA_DEVAD,
7466 MDIO_PMA_REG_TX_DISABLE, pmd_dis);
7467}
7468
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00007469static u8 bnx2x_get_gpio_port(struct link_params *params)
7470{
7471 u8 gpio_port;
7472 u32 swap_val, swap_override;
7473 struct bnx2x *bp = params->bp;
7474 if (CHIP_IS_E2(bp))
7475 gpio_port = BP_PATH(bp);
7476 else
7477 gpio_port = params->port;
7478 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
7479 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
7480 return gpio_port ^ (swap_val && swap_override);
7481}
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00007482
7483static void bnx2x_sfp_e1e2_set_transmitter(struct link_params *params,
7484 struct bnx2x_phy *phy,
7485 u8 tx_en)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007486{
7487 u16 val;
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00007488 u8 port = params->port;
7489 struct bnx2x *bp = params->bp;
7490 u32 tx_en_mode;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007491
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007492 /* Disable/Enable transmitter ( TX laser of the SFP+ module.)*/
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00007493 tx_en_mode = REG_RD(bp, params->shmem_base +
7494 offsetof(struct shmem_region,
7495 dev_info.port_hw_config[port].sfp_ctrl)) &
7496 PORT_HW_CFG_TX_LASER_MASK;
7497 DP(NETIF_MSG_LINK, "Setting transmitter tx_en=%x for port %x "
7498 "mode = %x\n", tx_en, port, tx_en_mode);
7499 switch (tx_en_mode) {
7500 case PORT_HW_CFG_TX_LASER_MDIO:
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007501
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00007502 bnx2x_cl45_read(bp, phy,
7503 MDIO_PMA_DEVAD,
7504 MDIO_PMA_REG_PHY_IDENTIFIER,
7505 &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007506
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00007507 if (tx_en)
7508 val &= ~(1<<15);
7509 else
7510 val |= (1<<15);
7511
7512 bnx2x_cl45_write(bp, phy,
7513 MDIO_PMA_DEVAD,
7514 MDIO_PMA_REG_PHY_IDENTIFIER,
7515 val);
7516 break;
7517 case PORT_HW_CFG_TX_LASER_GPIO0:
7518 case PORT_HW_CFG_TX_LASER_GPIO1:
7519 case PORT_HW_CFG_TX_LASER_GPIO2:
7520 case PORT_HW_CFG_TX_LASER_GPIO3:
7521 {
7522 u16 gpio_pin;
7523 u8 gpio_port, gpio_mode;
7524 if (tx_en)
7525 gpio_mode = MISC_REGISTERS_GPIO_OUTPUT_HIGH;
7526 else
7527 gpio_mode = MISC_REGISTERS_GPIO_OUTPUT_LOW;
7528
7529 gpio_pin = tx_en_mode - PORT_HW_CFG_TX_LASER_GPIO0;
7530 gpio_port = bnx2x_get_gpio_port(params);
7531 bnx2x_set_gpio(bp, gpio_pin, gpio_mode, gpio_port);
7532 break;
7533 }
7534 default:
7535 DP(NETIF_MSG_LINK, "Invalid TX_LASER_MDIO 0x%x\n", tx_en_mode);
7536 break;
7537 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007538}
7539
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00007540static void bnx2x_sfp_set_transmitter(struct link_params *params,
7541 struct bnx2x_phy *phy,
7542 u8 tx_en)
7543{
7544 struct bnx2x *bp = params->bp;
7545 DP(NETIF_MSG_LINK, "Setting SFP+ transmitter to %d\n", tx_en);
7546 if (CHIP_IS_E3(bp))
7547 bnx2x_sfp_e3_set_transmitter(params, phy, tx_en);
7548 else
7549 bnx2x_sfp_e1e2_set_transmitter(params, phy, tx_en);
7550}
7551
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00007552static int bnx2x_8726_read_sfp_module_eeprom(struct bnx2x_phy *phy,
7553 struct link_params *params,
7554 u16 addr, u8 byte_cnt, u8 *o_buf)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007555{
7556 struct bnx2x *bp = params->bp;
7557 u16 val = 0;
7558 u16 i;
7559 if (byte_cnt > 16) {
Joe Perches94f05b02011-08-14 12:16:20 +00007560 DP(NETIF_MSG_LINK,
7561 "Reading from eeprom is limited to 0xf\n");
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007562 return -EINVAL;
7563 }
7564 /* Set the read command byte count */
7565 bnx2x_cl45_write(bp, phy,
7566 MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007567 (byte_cnt | 0xa000));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007568
7569 /* Set the read command address */
7570 bnx2x_cl45_write(bp, phy,
7571 MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007572 addr);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007573
7574 /* Activate read command */
7575 bnx2x_cl45_write(bp, phy,
7576 MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007577 0x2c0f);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007578
7579 /* Wait up to 500us for command complete status */
7580 for (i = 0; i < 100; i++) {
7581 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007582 MDIO_PMA_DEVAD,
7583 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007584 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
7585 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
7586 break;
7587 udelay(5);
7588 }
7589
7590 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
7591 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
7592 DP(NETIF_MSG_LINK,
7593 "Got bad status 0x%x when reading from SFP+ EEPROM\n",
7594 (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
7595 return -EINVAL;
7596 }
7597
7598 /* Read the buffer */
7599 for (i = 0; i < byte_cnt; i++) {
7600 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007601 MDIO_PMA_DEVAD,
7602 MDIO_PMA_REG_8726_TWO_WIRE_DATA_BUF + i, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007603 o_buf[i] = (u8)(val & MDIO_PMA_REG_8726_TWO_WIRE_DATA_MASK);
7604 }
7605
7606 for (i = 0; i < 100; i++) {
7607 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007608 MDIO_PMA_DEVAD,
7609 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007610 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
7611 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
Joe Perches6f38ad92010-11-14 17:04:31 +00007612 return 0;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007613 msleep(1);
7614 }
7615 return -EINVAL;
7616}
7617
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00007618static int bnx2x_warpcore_read_sfp_module_eeprom(struct bnx2x_phy *phy,
7619 struct link_params *params,
7620 u16 addr, u8 byte_cnt,
7621 u8 *o_buf)
7622{
7623 int rc = 0;
7624 u8 i, j = 0, cnt = 0;
7625 u32 data_array[4];
7626 u16 addr32;
7627 struct bnx2x *bp = params->bp;
7628 /*DP(NETIF_MSG_LINK, "bnx2x_direct_read_sfp_module_eeprom:"
7629 " addr %d, cnt %d\n",
7630 addr, byte_cnt);*/
7631 if (byte_cnt > 16) {
Joe Perches94f05b02011-08-14 12:16:20 +00007632 DP(NETIF_MSG_LINK,
7633 "Reading from eeprom is limited to 16 bytes\n");
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00007634 return -EINVAL;
7635 }
7636
7637 /* 4 byte aligned address */
7638 addr32 = addr & (~0x3);
7639 do {
7640 rc = bnx2x_bsc_read(params, phy, 0xa0, addr32, 0, byte_cnt,
7641 data_array);
7642 } while ((rc != 0) && (++cnt < I2C_WA_RETRY_CNT));
7643
7644 if (rc == 0) {
7645 for (i = (addr - addr32); i < byte_cnt + (addr - addr32); i++) {
7646 o_buf[j] = *((u8 *)data_array + i);
7647 j++;
7648 }
7649 }
7650
7651 return rc;
7652}
7653
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00007654static int bnx2x_8727_read_sfp_module_eeprom(struct bnx2x_phy *phy,
7655 struct link_params *params,
7656 u16 addr, u8 byte_cnt, u8 *o_buf)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007657{
7658 struct bnx2x *bp = params->bp;
7659 u16 val, i;
7660
7661 if (byte_cnt > 16) {
Joe Perches94f05b02011-08-14 12:16:20 +00007662 DP(NETIF_MSG_LINK,
7663 "Reading from eeprom is limited to 0xf\n");
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007664 return -EINVAL;
7665 }
7666
7667 /* Need to read from 1.8000 to clear it */
7668 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007669 MDIO_PMA_DEVAD,
7670 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
7671 &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007672
7673 /* Set the read command byte count */
7674 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007675 MDIO_PMA_DEVAD,
7676 MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
7677 ((byte_cnt < 2) ? 2 : byte_cnt));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007678
7679 /* Set the read command address */
7680 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007681 MDIO_PMA_DEVAD,
7682 MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
7683 addr);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007684 /* Set the destination address */
7685 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007686 MDIO_PMA_DEVAD,
7687 0x8004,
7688 MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007689
7690 /* Activate read command */
7691 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007692 MDIO_PMA_DEVAD,
7693 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
7694 0x8002);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007695 /*
7696 * Wait appropriate time for two-wire command to finish before
7697 * polling the status register
7698 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007699 msleep(1);
7700
7701 /* Wait up to 500us for command complete status */
7702 for (i = 0; i < 100; i++) {
7703 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007704 MDIO_PMA_DEVAD,
7705 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007706 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
7707 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
7708 break;
7709 udelay(5);
7710 }
7711
7712 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
7713 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
7714 DP(NETIF_MSG_LINK,
7715 "Got bad status 0x%x when reading from SFP+ EEPROM\n",
7716 (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
Yaniv Rosner65a001b2011-01-31 04:22:03 +00007717 return -EFAULT;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007718 }
7719
7720 /* Read the buffer */
7721 for (i = 0; i < byte_cnt; i++) {
7722 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007723 MDIO_PMA_DEVAD,
7724 MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF + i, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007725 o_buf[i] = (u8)(val & MDIO_PMA_REG_8727_TWO_WIRE_DATA_MASK);
7726 }
7727
7728 for (i = 0; i < 100; i++) {
7729 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007730 MDIO_PMA_DEVAD,
7731 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007732 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
7733 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
Joe Perches6f38ad92010-11-14 17:04:31 +00007734 return 0;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007735 msleep(1);
7736 }
7737
7738 return -EINVAL;
7739}
7740
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00007741int bnx2x_read_sfp_module_eeprom(struct bnx2x_phy *phy,
7742 struct link_params *params, u16 addr,
7743 u8 byte_cnt, u8 *o_buf)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007744{
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00007745 int rc = -EINVAL;
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00007746 switch (phy->type) {
7747 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
7748 rc = bnx2x_8726_read_sfp_module_eeprom(phy, params, addr,
7749 byte_cnt, o_buf);
7750 break;
7751 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
7752 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722:
7753 rc = bnx2x_8727_read_sfp_module_eeprom(phy, params, addr,
7754 byte_cnt, o_buf);
7755 break;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00007756 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
7757 rc = bnx2x_warpcore_read_sfp_module_eeprom(phy, params, addr,
7758 byte_cnt, o_buf);
7759 break;
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00007760 }
7761 return rc;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007762}
7763
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00007764static int bnx2x_get_edc_mode(struct bnx2x_phy *phy,
7765 struct link_params *params,
7766 u16 *edc_mode)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007767{
7768 struct bnx2x *bp = params->bp;
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00007769 u32 sync_offset = 0, phy_idx, media_types;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007770 u8 val, check_limiting_mode = 0;
7771 *edc_mode = EDC_MODE_LIMITING;
7772
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00007773 phy->media_type = ETH_PHY_UNSPECIFIED;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007774 /* First check for copper cable */
7775 if (bnx2x_read_sfp_module_eeprom(phy,
7776 params,
7777 SFP_EEPROM_CON_TYPE_ADDR,
7778 1,
7779 &val) != 0) {
7780 DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM\n");
7781 return -EINVAL;
7782 }
7783
7784 switch (val) {
7785 case SFP_EEPROM_CON_TYPE_VAL_COPPER:
7786 {
7787 u8 copper_module_type;
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00007788 phy->media_type = ETH_PHY_DA_TWINAX;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007789 /*
7790 * Check if its active cable (includes SFP+ module)
7791 * of passive cable
7792 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007793 if (bnx2x_read_sfp_module_eeprom(phy,
7794 params,
7795 SFP_EEPROM_FC_TX_TECH_ADDR,
7796 1,
Yaniv Rosner9045f6b2011-05-31 21:28:27 +00007797 &copper_module_type) != 0) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007798 DP(NETIF_MSG_LINK,
7799 "Failed to read copper-cable-type"
7800 " from SFP+ EEPROM\n");
7801 return -EINVAL;
7802 }
7803
7804 if (copper_module_type &
7805 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE) {
7806 DP(NETIF_MSG_LINK, "Active Copper cable detected\n");
7807 check_limiting_mode = 1;
7808 } else if (copper_module_type &
7809 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE) {
Joe Perches94f05b02011-08-14 12:16:20 +00007810 DP(NETIF_MSG_LINK,
7811 "Passive Copper cable detected\n");
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007812 *edc_mode =
7813 EDC_MODE_PASSIVE_DAC;
7814 } else {
Joe Perches94f05b02011-08-14 12:16:20 +00007815 DP(NETIF_MSG_LINK,
7816 "Unknown copper-cable-type 0x%x !!!\n",
7817 copper_module_type);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007818 return -EINVAL;
7819 }
7820 break;
7821 }
7822 case SFP_EEPROM_CON_TYPE_VAL_LC:
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00007823 phy->media_type = ETH_PHY_SFP_FIBER;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007824 DP(NETIF_MSG_LINK, "Optic module detected\n");
7825 check_limiting_mode = 1;
7826 break;
7827 default:
7828 DP(NETIF_MSG_LINK, "Unable to determine module type 0x%x !!!\n",
7829 val);
7830 return -EINVAL;
7831 }
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00007832 sync_offset = params->shmem_base +
7833 offsetof(struct shmem_region,
7834 dev_info.port_hw_config[params->port].media_type);
7835 media_types = REG_RD(bp, sync_offset);
7836 /* Update media type for non-PMF sync */
7837 for (phy_idx = INT_PHY; phy_idx < MAX_PHYS; phy_idx++) {
7838 if (&(params->phy[phy_idx]) == phy) {
7839 media_types &= ~(PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK <<
7840 (PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT * phy_idx));
7841 media_types |= ((phy->media_type &
7842 PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK) <<
7843 (PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT * phy_idx));
7844 break;
7845 }
7846 }
7847 REG_WR(bp, sync_offset, media_types);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007848 if (check_limiting_mode) {
7849 u8 options[SFP_EEPROM_OPTIONS_SIZE];
7850 if (bnx2x_read_sfp_module_eeprom(phy,
7851 params,
7852 SFP_EEPROM_OPTIONS_ADDR,
7853 SFP_EEPROM_OPTIONS_SIZE,
7854 options) != 0) {
Joe Perches94f05b02011-08-14 12:16:20 +00007855 DP(NETIF_MSG_LINK,
7856 "Failed to read Option field from module EEPROM\n");
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007857 return -EINVAL;
7858 }
7859 if ((options[0] & SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK))
7860 *edc_mode = EDC_MODE_LINEAR;
7861 else
7862 *edc_mode = EDC_MODE_LIMITING;
7863 }
7864 DP(NETIF_MSG_LINK, "EDC mode is set to 0x%x\n", *edc_mode);
7865 return 0;
7866}
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007867/*
7868 * This function read the relevant field from the module (SFP+), and verify it
7869 * is compliant with this board
7870 */
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00007871static int bnx2x_verify_sfp_module(struct bnx2x_phy *phy,
7872 struct link_params *params)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007873{
7874 struct bnx2x *bp = params->bp;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007875 u32 val, cmd;
7876 u32 fw_resp, fw_cmd_param;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007877 char vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE+1];
7878 char vendor_pn[SFP_EEPROM_PART_NO_SIZE+1];
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007879 phy->flags &= ~FLAGS_SFP_NOT_APPROVED;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007880 val = REG_RD(bp, params->shmem_base +
7881 offsetof(struct shmem_region, dev_info.
7882 port_feature_config[params->port].config));
7883 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
7884 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_NO_ENFORCEMENT) {
7885 DP(NETIF_MSG_LINK, "NOT enforcing module verification\n");
7886 return 0;
7887 }
7888
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007889 if (params->feature_config_flags &
7890 FEATURE_CONFIG_BC_SUPPORTS_DUAL_PHY_OPT_MDL_VRFY) {
7891 /* Use specific phy request */
7892 cmd = DRV_MSG_CODE_VRFY_SPECIFIC_PHY_OPT_MDL;
7893 } else if (params->feature_config_flags &
7894 FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY) {
7895 /* Use first phy request only in case of non-dual media*/
7896 if (DUAL_MEDIA(params)) {
Joe Perches94f05b02011-08-14 12:16:20 +00007897 DP(NETIF_MSG_LINK,
7898 "FW does not support OPT MDL verification\n");
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007899 return -EINVAL;
7900 }
7901 cmd = DRV_MSG_CODE_VRFY_FIRST_PHY_OPT_MDL;
7902 } else {
7903 /* No support in OPT MDL detection */
Joe Perches94f05b02011-08-14 12:16:20 +00007904 DP(NETIF_MSG_LINK,
7905 "FW does not support OPT MDL verification\n");
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007906 return -EINVAL;
7907 }
Dmitry Kravkov523224a2010-10-06 03:23:26 +00007908
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007909 fw_cmd_param = FW_PARAM_SET(phy->addr, phy->type, phy->mdio_ctrl);
7910 fw_resp = bnx2x_fw_command(bp, cmd, fw_cmd_param);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007911 if (fw_resp == FW_MSG_CODE_VRFY_OPT_MDL_SUCCESS) {
7912 DP(NETIF_MSG_LINK, "Approved module\n");
7913 return 0;
7914 }
7915
7916 /* format the warning message */
7917 if (bnx2x_read_sfp_module_eeprom(phy,
7918 params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007919 SFP_EEPROM_VENDOR_NAME_ADDR,
7920 SFP_EEPROM_VENDOR_NAME_SIZE,
7921 (u8 *)vendor_name))
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007922 vendor_name[0] = '\0';
7923 else
7924 vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE] = '\0';
7925 if (bnx2x_read_sfp_module_eeprom(phy,
7926 params,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00007927 SFP_EEPROM_PART_NO_ADDR,
7928 SFP_EEPROM_PART_NO_SIZE,
7929 (u8 *)vendor_pn))
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007930 vendor_pn[0] = '\0';
7931 else
7932 vendor_pn[SFP_EEPROM_PART_NO_SIZE] = '\0';
7933
Yaniv Rosner6d870c32011-01-31 04:22:20 +00007934 netdev_err(bp->dev, "Warning: Unqualified SFP+ module detected,"
7935 " Port %d from %s part number %s\n",
7936 params->port, vendor_name, vendor_pn);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007937 phy->flags |= FLAGS_SFP_NOT_APPROVED;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007938 return -EINVAL;
7939}
7940
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00007941static int bnx2x_wait_for_sfp_module_initialized(struct bnx2x_phy *phy,
7942 struct link_params *params)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007943
7944{
7945 u8 val;
7946 struct bnx2x *bp = params->bp;
7947 u16 timeout;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007948 /*
7949 * Initialization time after hot-plug may take up to 300ms for
7950 * some phys type ( e.g. JDSU )
7951 */
7952
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007953 for (timeout = 0; timeout < 60; timeout++) {
7954 if (bnx2x_read_sfp_module_eeprom(phy, params, 1, 1, &val)
7955 == 0) {
Joe Perches94f05b02011-08-14 12:16:20 +00007956 DP(NETIF_MSG_LINK,
7957 "SFP+ module initialization took %d ms\n",
7958 timeout * 5);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007959 return 0;
7960 }
7961 msleep(5);
7962 }
7963 return -EINVAL;
7964}
7965
7966static void bnx2x_8727_power_module(struct bnx2x *bp,
7967 struct bnx2x_phy *phy,
7968 u8 is_power_up) {
7969 /* Make sure GPIOs are not using for LED mode */
7970 u16 val;
7971 /*
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007972 * In the GPIO register, bit 4 is use to determine if the GPIOs are
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007973 * operating as INPUT or as OUTPUT. Bit 1 is for input, and 0 for
7974 * output
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00007975 * Bits 0-1 determine the GPIOs value for OUTPUT in case bit 4 val is 0
7976 * Bits 8-9 determine the GPIOs value for INPUT in case bit 4 val is 1
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007977 * where the 1st bit is the over-current(only input), and 2nd bit is
7978 * for power( only output )
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00007979 *
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007980 * In case of NOC feature is disabled and power is up, set GPIO control
7981 * as input to enable listening of over-current indication
7982 */
7983 if (phy->flags & FLAGS_NOC)
7984 return;
Yaniv Rosner27d02432011-05-31 21:27:48 +00007985 if (is_power_up)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007986 val = (1<<4);
7987 else
7988 /*
7989 * Set GPIO control to OUTPUT, and set the power bit
7990 * to according to the is_power_up
7991 */
Yaniv Rosner27d02432011-05-31 21:27:48 +00007992 val = (1<<1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007993
7994 bnx2x_cl45_write(bp, phy,
7995 MDIO_PMA_DEVAD,
7996 MDIO_PMA_REG_8727_GPIO_CTRL,
7997 val);
7998}
7999
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00008000static int bnx2x_8726_set_limiting_mode(struct bnx2x *bp,
8001 struct bnx2x_phy *phy,
8002 u16 edc_mode)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008003{
8004 u16 cur_limiting_mode;
8005
8006 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008007 MDIO_PMA_DEVAD,
8008 MDIO_PMA_REG_ROM_VER2,
8009 &cur_limiting_mode);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008010 DP(NETIF_MSG_LINK, "Current Limiting mode is 0x%x\n",
8011 cur_limiting_mode);
8012
8013 if (edc_mode == EDC_MODE_LIMITING) {
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008014 DP(NETIF_MSG_LINK, "Setting LIMITING MODE\n");
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008015 bnx2x_cl45_write(bp, phy,
8016 MDIO_PMA_DEVAD,
8017 MDIO_PMA_REG_ROM_VER2,
8018 EDC_MODE_LIMITING);
8019 } else { /* LRM mode ( default )*/
8020
8021 DP(NETIF_MSG_LINK, "Setting LRM MODE\n");
8022
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008023 /*
8024 * Changing to LRM mode takes quite few seconds. So do it only
8025 * if current mode is limiting (default is LRM)
8026 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008027 if (cur_limiting_mode != EDC_MODE_LIMITING)
8028 return 0;
8029
8030 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008031 MDIO_PMA_DEVAD,
8032 MDIO_PMA_REG_LRM_MODE,
8033 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008034 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008035 MDIO_PMA_DEVAD,
8036 MDIO_PMA_REG_ROM_VER2,
8037 0x128);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008038 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008039 MDIO_PMA_DEVAD,
8040 MDIO_PMA_REG_MISC_CTRL0,
8041 0x4008);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008042 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008043 MDIO_PMA_DEVAD,
8044 MDIO_PMA_REG_LRM_MODE,
8045 0xaaaa);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008046 }
8047 return 0;
8048}
8049
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00008050static int bnx2x_8727_set_limiting_mode(struct bnx2x *bp,
8051 struct bnx2x_phy *phy,
8052 u16 edc_mode)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008053{
8054 u16 phy_identifier;
8055 u16 rom_ver2_val;
8056 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008057 MDIO_PMA_DEVAD,
8058 MDIO_PMA_REG_PHY_IDENTIFIER,
8059 &phy_identifier);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008060
8061 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008062 MDIO_PMA_DEVAD,
8063 MDIO_PMA_REG_PHY_IDENTIFIER,
8064 (phy_identifier & ~(1<<9)));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008065
8066 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008067 MDIO_PMA_DEVAD,
8068 MDIO_PMA_REG_ROM_VER2,
8069 &rom_ver2_val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008070 /* Keep the MSB 8-bits, and set the LSB 8-bits with the edc_mode */
8071 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008072 MDIO_PMA_DEVAD,
8073 MDIO_PMA_REG_ROM_VER2,
8074 (rom_ver2_val & 0xff00) | (edc_mode & 0x00ff));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008075
8076 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008077 MDIO_PMA_DEVAD,
8078 MDIO_PMA_REG_PHY_IDENTIFIER,
8079 (phy_identifier | (1<<9)));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008080
8081 return 0;
8082}
8083
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008084static void bnx2x_8727_specific_func(struct bnx2x_phy *phy,
8085 struct link_params *params,
8086 u32 action)
8087{
8088 struct bnx2x *bp = params->bp;
8089
8090 switch (action) {
8091 case DISABLE_TX:
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00008092 bnx2x_sfp_set_transmitter(params, phy, 0);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008093 break;
8094 case ENABLE_TX:
8095 if (!(phy->flags & FLAGS_SFP_NOT_APPROVED))
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00008096 bnx2x_sfp_set_transmitter(params, phy, 1);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008097 break;
8098 default:
8099 DP(NETIF_MSG_LINK, "Function 0x%x not supported by 8727\n",
8100 action);
8101 return;
8102 }
8103}
8104
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00008105static void bnx2x_set_e1e2_module_fault_led(struct link_params *params,
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00008106 u8 gpio_mode)
8107{
8108 struct bnx2x *bp = params->bp;
8109
8110 u32 fault_led_gpio = REG_RD(bp, params->shmem_base +
8111 offsetof(struct shmem_region,
8112 dev_info.port_hw_config[params->port].sfp_ctrl)) &
8113 PORT_HW_CFG_FAULT_MODULE_LED_MASK;
8114 switch (fault_led_gpio) {
8115 case PORT_HW_CFG_FAULT_MODULE_LED_DISABLED:
8116 return;
8117 case PORT_HW_CFG_FAULT_MODULE_LED_GPIO0:
8118 case PORT_HW_CFG_FAULT_MODULE_LED_GPIO1:
8119 case PORT_HW_CFG_FAULT_MODULE_LED_GPIO2:
8120 case PORT_HW_CFG_FAULT_MODULE_LED_GPIO3:
8121 {
8122 u8 gpio_port = bnx2x_get_gpio_port(params);
8123 u16 gpio_pin = fault_led_gpio -
8124 PORT_HW_CFG_FAULT_MODULE_LED_GPIO0;
8125 DP(NETIF_MSG_LINK, "Set fault module-detected led "
8126 "pin %x port %x mode %x\n",
8127 gpio_pin, gpio_port, gpio_mode);
8128 bnx2x_set_gpio(bp, gpio_pin, gpio_mode, gpio_port);
8129 }
8130 break;
8131 default:
8132 DP(NETIF_MSG_LINK, "Error: Invalid fault led mode 0x%x\n",
8133 fault_led_gpio);
8134 }
8135}
8136
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00008137static void bnx2x_set_e3_module_fault_led(struct link_params *params,
8138 u8 gpio_mode)
8139{
8140 u32 pin_cfg;
8141 u8 port = params->port;
8142 struct bnx2x *bp = params->bp;
8143 pin_cfg = (REG_RD(bp, params->shmem_base +
8144 offsetof(struct shmem_region,
8145 dev_info.port_hw_config[port].e3_sfp_ctrl)) &
8146 PORT_HW_CFG_E3_FAULT_MDL_LED_MASK) >>
8147 PORT_HW_CFG_E3_FAULT_MDL_LED_SHIFT;
8148 DP(NETIF_MSG_LINK, "Setting Fault LED to %d using pin cfg %d\n",
8149 gpio_mode, pin_cfg);
8150 bnx2x_set_cfg_pin(bp, pin_cfg, gpio_mode);
8151}
8152
8153static void bnx2x_set_sfp_module_fault_led(struct link_params *params,
8154 u8 gpio_mode)
8155{
8156 struct bnx2x *bp = params->bp;
8157 DP(NETIF_MSG_LINK, "Setting SFP+ module fault LED to %d\n", gpio_mode);
8158 if (CHIP_IS_E3(bp)) {
8159 /*
8160 * Low ==> if SFP+ module is supported otherwise
8161 * High ==> if SFP+ module is not on the approved vendor list
8162 */
8163 bnx2x_set_e3_module_fault_led(params, gpio_mode);
8164 } else
8165 bnx2x_set_e1e2_module_fault_led(params, gpio_mode);
8166}
8167
8168static void bnx2x_warpcore_power_module(struct link_params *params,
8169 struct bnx2x_phy *phy,
8170 u8 power)
8171{
8172 u32 pin_cfg;
8173 struct bnx2x *bp = params->bp;
8174
8175 pin_cfg = (REG_RD(bp, params->shmem_base +
8176 offsetof(struct shmem_region,
8177 dev_info.port_hw_config[params->port].e3_sfp_ctrl)) &
8178 PORT_HW_CFG_E3_PWR_DIS_MASK) >>
8179 PORT_HW_CFG_E3_PWR_DIS_SHIFT;
Yaniv Rosner985848f2011-07-05 01:06:48 +00008180
8181 if (pin_cfg == PIN_CFG_NA)
8182 return;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00008183 DP(NETIF_MSG_LINK, "Setting SFP+ module power to %d using pin cfg %d\n",
8184 power, pin_cfg);
8185 /*
8186 * Low ==> corresponding SFP+ module is powered
8187 * high ==> the SFP+ module is powered down
8188 */
8189 bnx2x_set_cfg_pin(bp, pin_cfg, power ^ 1);
8190}
8191
Yaniv Rosner985848f2011-07-05 01:06:48 +00008192static void bnx2x_warpcore_hw_reset(struct bnx2x_phy *phy,
8193 struct link_params *params)
8194{
Yaniv Rosnerb76070b2011-11-28 00:49:47 +00008195 struct bnx2x *bp = params->bp;
Yaniv Rosner985848f2011-07-05 01:06:48 +00008196 bnx2x_warpcore_power_module(params, phy, 0);
Yaniv Rosnerb76070b2011-11-28 00:49:47 +00008197 /* Put Warpcore in low power mode */
8198 REG_WR(bp, MISC_REG_WC0_RESET, 0x0c0e);
8199
8200 /* Put LCPLL in low power mode */
8201 REG_WR(bp, MISC_REG_LCPLL_E40_PWRDWN, 1);
8202 REG_WR(bp, MISC_REG_LCPLL_E40_RESETB_ANA, 0);
8203 REG_WR(bp, MISC_REG_LCPLL_E40_RESETB_DIG, 0);
Yaniv Rosner985848f2011-07-05 01:06:48 +00008204}
8205
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00008206static void bnx2x_power_sfp_module(struct link_params *params,
8207 struct bnx2x_phy *phy,
8208 u8 power)
8209{
8210 struct bnx2x *bp = params->bp;
8211 DP(NETIF_MSG_LINK, "Setting SFP+ power to %x\n", power);
8212
8213 switch (phy->type) {
8214 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
8215 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722:
8216 bnx2x_8727_power_module(params->bp, phy, power);
8217 break;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00008218 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
8219 bnx2x_warpcore_power_module(params, phy, power);
8220 break;
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00008221 default:
8222 break;
8223 }
8224}
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00008225static void bnx2x_warpcore_set_limiting_mode(struct link_params *params,
8226 struct bnx2x_phy *phy,
8227 u16 edc_mode)
8228{
8229 u16 val = 0;
8230 u16 mode = MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE_DEFAULT;
8231 struct bnx2x *bp = params->bp;
8232
8233 u8 lane = bnx2x_get_warpcore_lane(phy, params);
8234 /* This is a global register which controls all lanes */
8235 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
8236 MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE, &val);
8237 val &= ~(0xf << (lane << 2));
8238
8239 switch (edc_mode) {
8240 case EDC_MODE_LINEAR:
8241 case EDC_MODE_LIMITING:
8242 mode = MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE_DEFAULT;
8243 break;
8244 case EDC_MODE_PASSIVE_DAC:
8245 mode = MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE_SFP_DAC;
8246 break;
8247 default:
8248 break;
8249 }
8250
8251 val |= (mode << (lane << 2));
8252 bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
8253 MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE, val);
8254 /* A must read */
8255 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
8256 MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE, &val);
8257
Yaniv Rosner19af03a2011-08-02 22:59:47 +00008258 /* Restart microcode to re-read the new mode */
8259 bnx2x_warpcore_reset_lane(bp, phy, 1);
8260 bnx2x_warpcore_reset_lane(bp, phy, 0);
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00008261
8262}
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00008263
8264static void bnx2x_set_limiting_mode(struct link_params *params,
8265 struct bnx2x_phy *phy,
8266 u16 edc_mode)
8267{
8268 switch (phy->type) {
8269 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
8270 bnx2x_8726_set_limiting_mode(params->bp, phy, edc_mode);
8271 break;
8272 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
8273 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722:
8274 bnx2x_8727_set_limiting_mode(params->bp, phy, edc_mode);
8275 break;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00008276 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
8277 bnx2x_warpcore_set_limiting_mode(params, phy, edc_mode);
8278 break;
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00008279 }
8280}
8281
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00008282int bnx2x_sfp_module_detection(struct bnx2x_phy *phy,
8283 struct link_params *params)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008284{
8285 struct bnx2x *bp = params->bp;
8286 u16 edc_mode;
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00008287 int rc = 0;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008288
8289 u32 val = REG_RD(bp, params->shmem_base +
8290 offsetof(struct shmem_region, dev_info.
8291 port_feature_config[params->port].config));
8292
8293 DP(NETIF_MSG_LINK, "SFP+ module plugged in/out detected on port %d\n",
8294 params->port);
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00008295 /* Power up module */
8296 bnx2x_power_sfp_module(params, phy, 1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008297 if (bnx2x_get_edc_mode(phy, params, &edc_mode) != 0) {
8298 DP(NETIF_MSG_LINK, "Failed to get valid module type\n");
8299 return -EINVAL;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008300 } else if (bnx2x_verify_sfp_module(phy, params) != 0) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008301 /* check SFP+ module compatibility */
8302 DP(NETIF_MSG_LINK, "Module verification failed!!\n");
8303 rc = -EINVAL;
8304 /* Turn on fault module-detected led */
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00008305 bnx2x_set_sfp_module_fault_led(params,
8306 MISC_REGISTERS_GPIO_HIGH);
8307
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00008308 /* Check if need to power down the SFP+ module */
8309 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
8310 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_POWER_DOWN) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008311 DP(NETIF_MSG_LINK, "Shutdown SFP+ module!!\n");
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00008312 bnx2x_power_sfp_module(params, phy, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008313 return rc;
8314 }
8315 } else {
8316 /* Turn off fault module-detected led */
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00008317 bnx2x_set_sfp_module_fault_led(params, MISC_REGISTERS_GPIO_LOW);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008318 }
8319
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008320 /*
8321 * Check and set limiting mode / LRM mode on 8726. On 8727 it
8322 * is done automatically
8323 */
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00008324 bnx2x_set_limiting_mode(params, phy, edc_mode);
8325
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008326 /*
8327 * Enable transmit for this module if the module is approved, or
8328 * if unapproved modules should also enable the Tx laser
8329 */
8330 if (rc == 0 ||
8331 (val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) !=
8332 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00008333 bnx2x_sfp_set_transmitter(params, phy, 1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008334 else
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00008335 bnx2x_sfp_set_transmitter(params, phy, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008336
8337 return rc;
8338}
8339
8340void bnx2x_handle_module_detect_int(struct link_params *params)
8341{
8342 struct bnx2x *bp = params->bp;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00008343 struct bnx2x_phy *phy;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008344 u32 gpio_val;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00008345 u8 gpio_num, gpio_port;
8346 if (CHIP_IS_E3(bp))
8347 phy = &params->phy[INT_PHY];
8348 else
8349 phy = &params->phy[EXT_PHY1];
8350
8351 if (bnx2x_get_mod_abs_int_cfg(bp, params->chip_id, params->shmem_base,
8352 params->port, &gpio_num, &gpio_port) ==
8353 -EINVAL) {
8354 DP(NETIF_MSG_LINK, "Failed to get MOD_ABS interrupt config\n");
8355 return;
8356 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008357
8358 /* Set valid module led off */
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00008359 bnx2x_set_sfp_module_fault_led(params, MISC_REGISTERS_GPIO_HIGH);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008360
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008361 /* Get current gpio val reflecting module plugged in / out*/
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00008362 gpio_val = bnx2x_get_gpio(bp, gpio_num, gpio_port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008363
8364 /* Call the handling function in case module is detected */
8365 if (gpio_val == 0) {
Yaniv Rosnere4d78f12011-05-31 21:25:55 +00008366 bnx2x_power_sfp_module(params, phy, 1);
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00008367 bnx2x_set_gpio_int(bp, gpio_num,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008368 MISC_REGISTERS_GPIO_INT_OUTPUT_CLR,
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00008369 gpio_port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008370 if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0)
8371 bnx2x_sfp_module_detection(phy, params);
8372 else
8373 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
8374 } else {
8375 u32 val = REG_RD(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008376 offsetof(struct shmem_region, dev_info.
8377 port_feature_config[params->port].
8378 config));
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00008379 bnx2x_set_gpio_int(bp, gpio_num,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008380 MISC_REGISTERS_GPIO_INT_OUTPUT_SET,
Yaniv Rosner3c9ada22011-06-14 01:34:12 +00008381 gpio_port);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008382 /*
8383 * Module was plugged out.
8384 * Disable transmit for this module
8385 */
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00008386 phy->media_type = ETH_PHY_NOT_PRESENT;
Yaniv Rosnerde6f3372011-08-02 22:59:25 +00008387 if (((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
8388 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER) ||
8389 CHIP_IS_E3(bp))
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00008390 bnx2x_sfp_set_transmitter(params, phy, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008391 }
8392}
8393
8394/******************************************************************/
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00008395/* Used by 8706 and 8727 */
8396/******************************************************************/
8397static void bnx2x_sfp_mask_fault(struct bnx2x *bp,
8398 struct bnx2x_phy *phy,
8399 u16 alarm_status_offset,
8400 u16 alarm_ctrl_offset)
8401{
8402 u16 alarm_status, val;
8403 bnx2x_cl45_read(bp, phy,
8404 MDIO_PMA_DEVAD, alarm_status_offset,
8405 &alarm_status);
8406 bnx2x_cl45_read(bp, phy,
8407 MDIO_PMA_DEVAD, alarm_status_offset,
8408 &alarm_status);
8409 /* Mask or enable the fault event. */
8410 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, alarm_ctrl_offset, &val);
8411 if (alarm_status & (1<<0))
8412 val &= ~(1<<0);
8413 else
8414 val |= (1<<0);
8415 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, alarm_ctrl_offset, val);
8416}
8417/******************************************************************/
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008418/* common BCM8706/BCM8726 PHY SECTION */
8419/******************************************************************/
8420static u8 bnx2x_8706_8726_read_status(struct bnx2x_phy *phy,
8421 struct link_params *params,
8422 struct link_vars *vars)
8423{
8424 u8 link_up = 0;
8425 u16 val1, val2, rx_sd, pcs_status;
8426 struct bnx2x *bp = params->bp;
8427 DP(NETIF_MSG_LINK, "XGXS 8706/8726\n");
8428 /* Clear RX Alarm*/
8429 bnx2x_cl45_read(bp, phy,
Yaniv Rosner60d2fe02011-06-14 01:34:38 +00008430 MDIO_PMA_DEVAD, MDIO_PMA_LASI_RXSTAT, &val2);
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00008431
Yaniv Rosner60d2fe02011-06-14 01:34:38 +00008432 bnx2x_sfp_mask_fault(bp, phy, MDIO_PMA_LASI_TXSTAT,
8433 MDIO_PMA_LASI_TXCTRL);
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00008434
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008435 /* clear LASI indication*/
8436 bnx2x_cl45_read(bp, phy,
Yaniv Rosner60d2fe02011-06-14 01:34:38 +00008437 MDIO_PMA_DEVAD, MDIO_PMA_LASI_STAT, &val1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008438 bnx2x_cl45_read(bp, phy,
Yaniv Rosner60d2fe02011-06-14 01:34:38 +00008439 MDIO_PMA_DEVAD, MDIO_PMA_LASI_STAT, &val2);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008440 DP(NETIF_MSG_LINK, "8706/8726 LASI status 0x%x--> 0x%x\n", val1, val2);
8441
8442 bnx2x_cl45_read(bp, phy,
8443 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD, &rx_sd);
8444 bnx2x_cl45_read(bp, phy,
8445 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &pcs_status);
8446 bnx2x_cl45_read(bp, phy,
8447 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &val2);
8448 bnx2x_cl45_read(bp, phy,
8449 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &val2);
8450
8451 DP(NETIF_MSG_LINK, "8706/8726 rx_sd 0x%x pcs_status 0x%x 1Gbps"
8452 " link_status 0x%x\n", rx_sd, pcs_status, val2);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008453 /*
8454 * link is up if both bit 0 of pmd_rx_sd and bit 0 of pcs_status
8455 * are set, or if the autoneg bit 1 is set
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008456 */
8457 link_up = ((rx_sd & pcs_status & 0x1) || (val2 & (1<<1)));
8458 if (link_up) {
8459 if (val2 & (1<<1))
8460 vars->line_speed = SPEED_1000;
8461 else
8462 vars->line_speed = SPEED_10000;
8463 bnx2x_ext_phy_resolve_fc(phy, params, vars);
Yaniv Rosner791f18c2011-01-18 04:33:42 +00008464 vars->duplex = DUPLEX_FULL;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008465 }
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00008466
8467 /* Capture 10G link fault. Read twice to clear stale value. */
8468 if (vars->line_speed == SPEED_10000) {
8469 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
Yaniv Rosner60d2fe02011-06-14 01:34:38 +00008470 MDIO_PMA_LASI_TXSTAT, &val1);
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00008471 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
Yaniv Rosner60d2fe02011-06-14 01:34:38 +00008472 MDIO_PMA_LASI_TXSTAT, &val1);
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00008473 if (val1 & (1<<0))
8474 vars->fault_detected = 1;
8475 }
8476
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008477 return link_up;
8478}
8479
8480/******************************************************************/
8481/* BCM8706 PHY SECTION */
8482/******************************************************************/
8483static u8 bnx2x_8706_config_init(struct bnx2x_phy *phy,
8484 struct link_params *params,
8485 struct link_vars *vars)
8486{
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00008487 u32 tx_en_mode;
8488 u16 cnt, val, tmp1;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008489 struct bnx2x *bp = params->bp;
Yaniv Rosner3deb8162011-06-14 01:34:33 +00008490
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008491 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008492 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008493 /* HW reset */
8494 bnx2x_ext_phy_hw_reset(bp, params->port);
8495 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0xa040);
Yaniv Rosner6d870c32011-01-31 04:22:20 +00008496 bnx2x_wait_reset_complete(bp, phy, params);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008497
8498 /* Wait until fw is loaded */
8499 for (cnt = 0; cnt < 100; cnt++) {
8500 bnx2x_cl45_read(bp, phy,
8501 MDIO_PMA_DEVAD, MDIO_PMA_REG_ROM_VER1, &val);
8502 if (val)
8503 break;
8504 msleep(10);
8505 }
8506 DP(NETIF_MSG_LINK, "XGXS 8706 is initialized after %d ms\n", cnt);
8507 if ((params->feature_config_flags &
8508 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
8509 u8 i;
8510 u16 reg;
8511 for (i = 0; i < 4; i++) {
8512 reg = MDIO_XS_8706_REG_BANK_RX0 +
8513 i*(MDIO_XS_8706_REG_BANK_RX1 -
8514 MDIO_XS_8706_REG_BANK_RX0);
8515 bnx2x_cl45_read(bp, phy, MDIO_XS_DEVAD, reg, &val);
8516 /* Clear first 3 bits of the control */
8517 val &= ~0x7;
8518 /* Set control bits according to configuration */
8519 val |= (phy->rx_preemphasis[i] & 0x7);
8520 DP(NETIF_MSG_LINK, "Setting RX Equalizer to BCM8706"
8521 " reg 0x%x <-- val 0x%x\n", reg, val);
8522 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, reg, val);
8523 }
8524 }
8525 /* Force speed */
8526 if (phy->req_line_speed == SPEED_10000) {
8527 DP(NETIF_MSG_LINK, "XGXS 8706 force 10Gbps\n");
8528
8529 bnx2x_cl45_write(bp, phy,
8530 MDIO_PMA_DEVAD,
8531 MDIO_PMA_REG_DIGITAL_CTRL, 0x400);
8532 bnx2x_cl45_write(bp, phy,
Yaniv Rosner60d2fe02011-06-14 01:34:38 +00008533 MDIO_PMA_DEVAD, MDIO_PMA_LASI_TXCTRL,
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00008534 0);
8535 /* Arm LASI for link and Tx fault. */
8536 bnx2x_cl45_write(bp, phy,
Yaniv Rosner60d2fe02011-06-14 01:34:38 +00008537 MDIO_PMA_DEVAD, MDIO_PMA_LASI_CTRL, 3);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008538 } else {
Lucas De Marchi25985ed2011-03-30 22:57:33 -03008539 /* Force 1Gbps using autoneg with 1G advertisement */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008540
8541 /* Allow CL37 through CL73 */
8542 DP(NETIF_MSG_LINK, "XGXS 8706 AutoNeg\n");
8543 bnx2x_cl45_write(bp, phy,
8544 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_CL73, 0x040c);
8545
Lucas De Marchi25985ed2011-03-30 22:57:33 -03008546 /* Enable Full-Duplex advertisement on CL37 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008547 bnx2x_cl45_write(bp, phy,
8548 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LP, 0x0020);
8549 /* Enable CL37 AN */
8550 bnx2x_cl45_write(bp, phy,
8551 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
8552 /* 1G support */
8553 bnx2x_cl45_write(bp, phy,
8554 MDIO_AN_DEVAD, MDIO_AN_REG_ADV, (1<<5));
8555
8556 /* Enable clause 73 AN */
8557 bnx2x_cl45_write(bp, phy,
8558 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
8559 bnx2x_cl45_write(bp, phy,
Yaniv Rosner60d2fe02011-06-14 01:34:38 +00008560 MDIO_PMA_DEVAD, MDIO_PMA_LASI_RXCTRL,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008561 0x0400);
8562 bnx2x_cl45_write(bp, phy,
Yaniv Rosner60d2fe02011-06-14 01:34:38 +00008563 MDIO_PMA_DEVAD, MDIO_PMA_LASI_CTRL,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008564 0x0004);
8565 }
8566 bnx2x_save_bcm_spirom_ver(bp, phy, params->port);
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00008567
8568 /*
8569 * If TX Laser is controlled by GPIO_0, do not let PHY go into low
8570 * power mode, if TX Laser is disabled
8571 */
8572
8573 tx_en_mode = REG_RD(bp, params->shmem_base +
8574 offsetof(struct shmem_region,
8575 dev_info.port_hw_config[params->port].sfp_ctrl))
8576 & PORT_HW_CFG_TX_LASER_MASK;
8577
8578 if (tx_en_mode == PORT_HW_CFG_TX_LASER_GPIO0) {
8579 DP(NETIF_MSG_LINK, "Enabling TXONOFF_PWRDN_DIS\n");
8580 bnx2x_cl45_read(bp, phy,
8581 MDIO_PMA_DEVAD, MDIO_PMA_REG_DIGITAL_CTRL, &tmp1);
8582 tmp1 |= 0x1;
8583 bnx2x_cl45_write(bp, phy,
8584 MDIO_PMA_DEVAD, MDIO_PMA_REG_DIGITAL_CTRL, tmp1);
8585 }
8586
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008587 return 0;
8588}
8589
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00008590static int bnx2x_8706_read_status(struct bnx2x_phy *phy,
8591 struct link_params *params,
8592 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008593{
8594 return bnx2x_8706_8726_read_status(phy, params, vars);
8595}
8596
8597/******************************************************************/
8598/* BCM8726 PHY SECTION */
8599/******************************************************************/
8600static void bnx2x_8726_config_loopback(struct bnx2x_phy *phy,
8601 struct link_params *params)
8602{
8603 struct bnx2x *bp = params->bp;
8604 DP(NETIF_MSG_LINK, "PMA/PMD ext_phy_loopback: 8726\n");
8605 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x0001);
8606}
8607
8608static void bnx2x_8726_external_rom_boot(struct bnx2x_phy *phy,
8609 struct link_params *params)
8610{
8611 struct bnx2x *bp = params->bp;
8612 /* Need to wait 100ms after reset */
8613 msleep(100);
8614
8615 /* Micro controller re-boot */
8616 bnx2x_cl45_write(bp, phy,
8617 MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, 0x018B);
8618
8619 /* Set soft reset */
8620 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008621 MDIO_PMA_DEVAD,
8622 MDIO_PMA_REG_GEN_CTRL,
8623 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008624
8625 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008626 MDIO_PMA_DEVAD,
8627 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008628
8629 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008630 MDIO_PMA_DEVAD,
8631 MDIO_PMA_REG_GEN_CTRL,
8632 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008633
8634 /* wait for 150ms for microcode load */
8635 msleep(150);
8636
8637 /* Disable serial boot control, tristates pins SS_N, SCK, MOSI, MISO */
8638 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008639 MDIO_PMA_DEVAD,
8640 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008641
8642 msleep(200);
8643 bnx2x_save_bcm_spirom_ver(bp, phy, params->port);
8644}
8645
8646static u8 bnx2x_8726_read_status(struct bnx2x_phy *phy,
8647 struct link_params *params,
8648 struct link_vars *vars)
8649{
8650 struct bnx2x *bp = params->bp;
8651 u16 val1;
8652 u8 link_up = bnx2x_8706_8726_read_status(phy, params, vars);
8653 if (link_up) {
8654 bnx2x_cl45_read(bp, phy,
8655 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER,
8656 &val1);
8657 if (val1 & (1<<15)) {
8658 DP(NETIF_MSG_LINK, "Tx is disabled\n");
8659 link_up = 0;
8660 vars->line_speed = 0;
8661 }
8662 }
8663 return link_up;
8664}
8665
8666
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00008667static int bnx2x_8726_config_init(struct bnx2x_phy *phy,
8668 struct link_params *params,
8669 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008670{
8671 struct bnx2x *bp = params->bp;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008672 DP(NETIF_MSG_LINK, "Initializing BCM8726\n");
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008673
8674 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
Yaniv Rosner6d870c32011-01-31 04:22:20 +00008675 bnx2x_wait_reset_complete(bp, phy, params);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008676
8677 bnx2x_8726_external_rom_boot(phy, params);
8678
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008679 /*
8680 * Need to call module detected on initialization since the module
8681 * detection triggered by actual module insertion might occur before
8682 * driver is loaded, and when driver is loaded, it reset all
8683 * registers, including the transmitter
8684 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008685 bnx2x_sfp_module_detection(phy, params);
8686
8687 if (phy->req_line_speed == SPEED_1000) {
8688 DP(NETIF_MSG_LINK, "Setting 1G force\n");
8689 bnx2x_cl45_write(bp, phy,
8690 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x40);
8691 bnx2x_cl45_write(bp, phy,
8692 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0xD);
8693 bnx2x_cl45_write(bp, phy,
Yaniv Rosner60d2fe02011-06-14 01:34:38 +00008694 MDIO_PMA_DEVAD, MDIO_PMA_LASI_CTRL, 0x5);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008695 bnx2x_cl45_write(bp, phy,
Yaniv Rosner60d2fe02011-06-14 01:34:38 +00008696 MDIO_PMA_DEVAD, MDIO_PMA_LASI_RXCTRL,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008697 0x400);
8698 } else if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
8699 (phy->speed_cap_mask &
8700 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G) &&
8701 ((phy->speed_cap_mask &
8702 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) !=
8703 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
8704 DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
8705 /* Set Flow control */
8706 bnx2x_ext_phy_set_pause(params, phy, vars);
8707 bnx2x_cl45_write(bp, phy,
8708 MDIO_AN_DEVAD, MDIO_AN_REG_ADV, 0x20);
8709 bnx2x_cl45_write(bp, phy,
8710 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_CL73, 0x040c);
8711 bnx2x_cl45_write(bp, phy,
8712 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, 0x0020);
8713 bnx2x_cl45_write(bp, phy,
8714 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
8715 bnx2x_cl45_write(bp, phy,
8716 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008717 /*
8718 * Enable RX-ALARM control to receive interrupt for 1G speed
8719 * change
8720 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008721 bnx2x_cl45_write(bp, phy,
Yaniv Rosner60d2fe02011-06-14 01:34:38 +00008722 MDIO_PMA_DEVAD, MDIO_PMA_LASI_CTRL, 0x4);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008723 bnx2x_cl45_write(bp, phy,
Yaniv Rosner60d2fe02011-06-14 01:34:38 +00008724 MDIO_PMA_DEVAD, MDIO_PMA_LASI_RXCTRL,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008725 0x400);
8726
8727 } else { /* Default 10G. Set only LASI control */
8728 bnx2x_cl45_write(bp, phy,
Yaniv Rosner60d2fe02011-06-14 01:34:38 +00008729 MDIO_PMA_DEVAD, MDIO_PMA_LASI_CTRL, 1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008730 }
8731
8732 /* Set TX PreEmphasis if needed */
8733 if ((params->feature_config_flags &
8734 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
Joe Perches94f05b02011-08-14 12:16:20 +00008735 DP(NETIF_MSG_LINK,
8736 "Setting TX_CTRL1 0x%x, TX_CTRL2 0x%x\n",
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008737 phy->tx_preemphasis[0],
8738 phy->tx_preemphasis[1]);
8739 bnx2x_cl45_write(bp, phy,
8740 MDIO_PMA_DEVAD,
8741 MDIO_PMA_REG_8726_TX_CTRL1,
8742 phy->tx_preemphasis[0]);
8743
8744 bnx2x_cl45_write(bp, phy,
8745 MDIO_PMA_DEVAD,
8746 MDIO_PMA_REG_8726_TX_CTRL2,
8747 phy->tx_preemphasis[1]);
8748 }
8749
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008750 return 0;
8751
8752}
8753
8754static void bnx2x_8726_link_reset(struct bnx2x_phy *phy,
8755 struct link_params *params)
8756{
8757 struct bnx2x *bp = params->bp;
8758 DP(NETIF_MSG_LINK, "bnx2x_8726_link_reset port %d\n", params->port);
8759 /* Set serial boot control for external load */
8760 bnx2x_cl45_write(bp, phy,
8761 MDIO_PMA_DEVAD,
8762 MDIO_PMA_REG_GEN_CTRL, 0x0001);
8763}
8764
8765/******************************************************************/
8766/* BCM8727 PHY SECTION */
8767/******************************************************************/
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00008768
8769static void bnx2x_8727_set_link_led(struct bnx2x_phy *phy,
8770 struct link_params *params, u8 mode)
8771{
8772 struct bnx2x *bp = params->bp;
8773 u16 led_mode_bitmask = 0;
8774 u16 gpio_pins_bitmask = 0;
8775 u16 val;
8776 /* Only NOC flavor requires to set the LED specifically */
8777 if (!(phy->flags & FLAGS_NOC))
8778 return;
8779 switch (mode) {
8780 case LED_MODE_FRONT_PANEL_OFF:
8781 case LED_MODE_OFF:
8782 led_mode_bitmask = 0;
8783 gpio_pins_bitmask = 0x03;
8784 break;
8785 case LED_MODE_ON:
8786 led_mode_bitmask = 0;
8787 gpio_pins_bitmask = 0x02;
8788 break;
8789 case LED_MODE_OPER:
8790 led_mode_bitmask = 0x60;
8791 gpio_pins_bitmask = 0x11;
8792 break;
8793 }
8794 bnx2x_cl45_read(bp, phy,
8795 MDIO_PMA_DEVAD,
8796 MDIO_PMA_REG_8727_PCS_OPT_CTRL,
8797 &val);
8798 val &= 0xff8f;
8799 val |= led_mode_bitmask;
8800 bnx2x_cl45_write(bp, phy,
8801 MDIO_PMA_DEVAD,
8802 MDIO_PMA_REG_8727_PCS_OPT_CTRL,
8803 val);
8804 bnx2x_cl45_read(bp, phy,
8805 MDIO_PMA_DEVAD,
8806 MDIO_PMA_REG_8727_GPIO_CTRL,
8807 &val);
8808 val &= 0xffe0;
8809 val |= gpio_pins_bitmask;
8810 bnx2x_cl45_write(bp, phy,
8811 MDIO_PMA_DEVAD,
8812 MDIO_PMA_REG_8727_GPIO_CTRL,
8813 val);
8814}
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00008815static void bnx2x_8727_hw_reset(struct bnx2x_phy *phy,
8816 struct link_params *params) {
8817 u32 swap_val, swap_override;
8818 u8 port;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008819 /*
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00008820 * The PHY reset is controlled by GPIO 1. Fake the port number
8821 * to cancel the swap done in set_gpio()
8822 */
8823 struct bnx2x *bp = params->bp;
8824 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
8825 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
8826 port = (swap_val && swap_override) ^ 1;
8827 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00008828 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00008829}
8830
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00008831static int bnx2x_8727_config_init(struct bnx2x_phy *phy,
8832 struct link_params *params,
8833 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008834{
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00008835 u32 tx_en_mode;
8836 u16 tmp1, val, mod_abs, tmp2;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008837 u16 rx_alarm_ctrl_val;
8838 u16 lasi_ctrl_val;
8839 struct bnx2x *bp = params->bp;
8840 /* Enable PMD link, MOD_ABS_FLT, and 1G link alarm */
8841
Yaniv Rosner6d870c32011-01-31 04:22:20 +00008842 bnx2x_wait_reset_complete(bp, phy, params);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008843 rx_alarm_ctrl_val = (1<<2) | (1<<5) ;
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00008844 /* Should be 0x6 to enable XS on Tx side. */
8845 lasi_ctrl_val = 0x0006;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008846
8847 DP(NETIF_MSG_LINK, "Initializing BCM8727\n");
8848 /* enable LASI */
8849 bnx2x_cl45_write(bp, phy,
Yaniv Rosner60d2fe02011-06-14 01:34:38 +00008850 MDIO_PMA_DEVAD, MDIO_PMA_LASI_RXCTRL,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008851 rx_alarm_ctrl_val);
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00008852 bnx2x_cl45_write(bp, phy,
Yaniv Rosner60d2fe02011-06-14 01:34:38 +00008853 MDIO_PMA_DEVAD, MDIO_PMA_LASI_TXCTRL,
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00008854 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008855 bnx2x_cl45_write(bp, phy,
Yaniv Rosner60d2fe02011-06-14 01:34:38 +00008856 MDIO_PMA_DEVAD, MDIO_PMA_LASI_CTRL, lasi_ctrl_val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008857
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008858 /*
8859 * Initially configure MOD_ABS to interrupt when module is
8860 * presence( bit 8)
8861 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008862 bnx2x_cl45_read(bp, phy,
8863 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008864 /*
8865 * Set EDC off by setting OPTXLOS signal input to low (bit 9).
8866 * When the EDC is off it locks onto a reference clock and avoids
8867 * becoming 'lost'
8868 */
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00008869 mod_abs &= ~(1<<8);
8870 if (!(phy->flags & FLAGS_NOC))
8871 mod_abs &= ~(1<<9);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008872 bnx2x_cl45_write(bp, phy,
8873 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
8874
8875
Yaniv Rosner85242ee2011-07-05 01:06:53 +00008876 /* Enable/Disable PHY transmitter output */
8877 bnx2x_set_disable_pmd_transmit(params, phy, 0);
8878
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008879 /* Make MOD_ABS give interrupt on change */
8880 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL,
8881 &val);
8882 val |= (1<<12);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00008883 if (phy->flags & FLAGS_NOC)
8884 val |= (3<<5);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008885
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008886 /*
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00008887 * Set 8727 GPIOs to input to allow reading from the 8727 GPIO0
8888 * status which reflect SFP+ module over-current
8889 */
8890 if (!(phy->flags & FLAGS_NOC))
8891 val &= 0xff8f; /* Reset bits 4-6 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008892 bnx2x_cl45_write(bp, phy,
8893 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL, val);
8894
8895 bnx2x_8727_power_module(bp, phy, 1);
8896
8897 bnx2x_cl45_read(bp, phy,
8898 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &tmp1);
8899
8900 bnx2x_cl45_read(bp, phy,
Yaniv Rosner60d2fe02011-06-14 01:34:38 +00008901 MDIO_PMA_DEVAD, MDIO_PMA_LASI_RXSTAT, &tmp1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008902
8903 /* Set option 1G speed */
8904 if (phy->req_line_speed == SPEED_1000) {
8905 DP(NETIF_MSG_LINK, "Setting 1G force\n");
8906 bnx2x_cl45_write(bp, phy,
8907 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x40);
8908 bnx2x_cl45_write(bp, phy,
8909 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0xD);
8910 bnx2x_cl45_read(bp, phy,
8911 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, &tmp1);
8912 DP(NETIF_MSG_LINK, "1.7 = 0x%x\n", tmp1);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008913 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00008914 * Power down the XAUI until link is up in case of dual-media
8915 * and 1G
8916 */
8917 if (DUAL_MEDIA(params)) {
8918 bnx2x_cl45_read(bp, phy,
8919 MDIO_PMA_DEVAD,
8920 MDIO_PMA_REG_8727_PCS_GP, &val);
8921 val |= (3<<10);
8922 bnx2x_cl45_write(bp, phy,
8923 MDIO_PMA_DEVAD,
8924 MDIO_PMA_REG_8727_PCS_GP, val);
8925 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008926 } else if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
8927 ((phy->speed_cap_mask &
8928 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) &&
8929 ((phy->speed_cap_mask &
8930 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) !=
8931 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
8932
8933 DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
8934 bnx2x_cl45_write(bp, phy,
8935 MDIO_AN_DEVAD, MDIO_AN_REG_8727_MISC_CTRL, 0);
8936 bnx2x_cl45_write(bp, phy,
8937 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1300);
8938 } else {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008939 /*
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008940 * Since the 8727 has only single reset pin, need to set the 10G
8941 * registers although it is default
8942 */
8943 bnx2x_cl45_write(bp, phy,
8944 MDIO_AN_DEVAD, MDIO_AN_REG_8727_MISC_CTRL,
8945 0x0020);
8946 bnx2x_cl45_write(bp, phy,
8947 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x0100);
8948 bnx2x_cl45_write(bp, phy,
8949 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x2040);
8950 bnx2x_cl45_write(bp, phy,
8951 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2,
8952 0x0008);
8953 }
8954
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00008955 /*
8956 * Set 2-wire transfer rate of SFP+ module EEPROM
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008957 * to 100Khz since some DACs(direct attached cables) do
8958 * not work at 400Khz.
8959 */
8960 bnx2x_cl45_write(bp, phy,
8961 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR,
8962 0xa001);
8963
8964 /* Set TX PreEmphasis if needed */
8965 if ((params->feature_config_flags &
8966 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
8967 DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x, TX_CTRL2 0x%x\n",
8968 phy->tx_preemphasis[0],
8969 phy->tx_preemphasis[1]);
8970 bnx2x_cl45_write(bp, phy,
8971 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TX_CTRL1,
8972 phy->tx_preemphasis[0]);
8973
8974 bnx2x_cl45_write(bp, phy,
8975 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TX_CTRL2,
8976 phy->tx_preemphasis[1]);
8977 }
8978
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00008979 /*
8980 * If TX Laser is controlled by GPIO_0, do not let PHY go into low
8981 * power mode, if TX Laser is disabled
8982 */
8983 tx_en_mode = REG_RD(bp, params->shmem_base +
8984 offsetof(struct shmem_region,
8985 dev_info.port_hw_config[params->port].sfp_ctrl))
8986 & PORT_HW_CFG_TX_LASER_MASK;
8987
8988 if (tx_en_mode == PORT_HW_CFG_TX_LASER_GPIO0) {
8989
8990 DP(NETIF_MSG_LINK, "Enabling TXONOFF_PWRDN_DIS\n");
8991 bnx2x_cl45_read(bp, phy,
8992 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_OPT_CFG_REG, &tmp2);
8993 tmp2 |= 0x1000;
8994 tmp2 &= 0xFFEF;
8995 bnx2x_cl45_write(bp, phy,
8996 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_OPT_CFG_REG, tmp2);
8997 }
8998
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00008999 return 0;
9000}
9001
9002static void bnx2x_8727_handle_mod_abs(struct bnx2x_phy *phy,
9003 struct link_params *params)
9004{
9005 struct bnx2x *bp = params->bp;
9006 u16 mod_abs, rx_alarm_status;
9007 u32 val = REG_RD(bp, params->shmem_base +
9008 offsetof(struct shmem_region, dev_info.
9009 port_feature_config[params->port].
9010 config));
9011 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00009012 MDIO_PMA_DEVAD,
9013 MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009014 if (mod_abs & (1<<8)) {
9015
9016 /* Module is absent */
Joe Perches94f05b02011-08-14 12:16:20 +00009017 DP(NETIF_MSG_LINK,
9018 "MOD_ABS indication show module is absent\n");
Yaniv Rosner1ac9e422011-05-31 21:26:11 +00009019 phy->media_type = ETH_PHY_NOT_PRESENT;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00009020 /*
9021 * 1. Set mod_abs to detect next module
9022 * presence event
9023 * 2. Set EDC off by setting OPTXLOS signal input to low
9024 * (bit 9).
9025 * When the EDC is off it locks onto a reference clock and
9026 * avoids becoming 'lost'.
9027 */
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00009028 mod_abs &= ~(1<<8);
9029 if (!(phy->flags & FLAGS_NOC))
9030 mod_abs &= ~(1<<9);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009031 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00009032 MDIO_PMA_DEVAD,
9033 MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009034
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00009035 /*
9036 * Clear RX alarm since it stays up as long as
9037 * the mod_abs wasn't changed
9038 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009039 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00009040 MDIO_PMA_DEVAD,
Yaniv Rosner60d2fe02011-06-14 01:34:38 +00009041 MDIO_PMA_LASI_RXSTAT, &rx_alarm_status);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009042
9043 } else {
9044 /* Module is present */
Joe Perches94f05b02011-08-14 12:16:20 +00009045 DP(NETIF_MSG_LINK,
9046 "MOD_ABS indication show module is present\n");
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00009047 /*
9048 * First disable transmitter, and if the module is ok, the
9049 * module_detection will enable it
9050 * 1. Set mod_abs to detect next module absent event ( bit 8)
9051 * 2. Restore the default polarity of the OPRXLOS signal and
9052 * this signal will then correctly indicate the presence or
9053 * absence of the Rx signal. (bit 9)
9054 */
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00009055 mod_abs |= (1<<8);
9056 if (!(phy->flags & FLAGS_NOC))
9057 mod_abs |= (1<<9);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009058 bnx2x_cl45_write(bp, phy,
9059 MDIO_PMA_DEVAD,
9060 MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
9061
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00009062 /*
9063 * Clear RX alarm since it stays up as long as the mod_abs
9064 * wasn't changed. This is need to be done before calling the
9065 * module detection, otherwise it will clear* the link update
9066 * alarm
9067 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009068 bnx2x_cl45_read(bp, phy,
9069 MDIO_PMA_DEVAD,
Yaniv Rosner60d2fe02011-06-14 01:34:38 +00009070 MDIO_PMA_LASI_RXSTAT, &rx_alarm_status);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009071
9072
9073 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
9074 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00009075 bnx2x_sfp_set_transmitter(params, phy, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009076
9077 if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0)
9078 bnx2x_sfp_module_detection(phy, params);
9079 else
9080 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
9081 }
9082
9083 DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n",
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00009084 rx_alarm_status);
9085 /* No need to check link status in case of module plugged in/out */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009086}
9087
9088static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy,
9089 struct link_params *params,
9090 struct link_vars *vars)
9091
9092{
9093 struct bnx2x *bp = params->bp;
Yaniv Rosner27d02432011-05-31 21:27:48 +00009094 u8 link_up = 0, oc_port = params->port;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009095 u16 link_status = 0;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009096 u16 rx_alarm_status, lasi_ctrl, val1;
9097
9098 /* If PHY is not initialized, do not check link status */
9099 bnx2x_cl45_read(bp, phy,
Yaniv Rosner60d2fe02011-06-14 01:34:38 +00009100 MDIO_PMA_DEVAD, MDIO_PMA_LASI_CTRL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009101 &lasi_ctrl);
9102 if (!lasi_ctrl)
9103 return 0;
9104
Yaniv Rosner9045f6b2011-05-31 21:28:27 +00009105 /* Check the LASI on Rx */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009106 bnx2x_cl45_read(bp, phy,
Yaniv Rosner60d2fe02011-06-14 01:34:38 +00009107 MDIO_PMA_DEVAD, MDIO_PMA_LASI_RXSTAT,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009108 &rx_alarm_status);
9109 vars->line_speed = 0;
9110 DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n", rx_alarm_status);
9111
Yaniv Rosner60d2fe02011-06-14 01:34:38 +00009112 bnx2x_sfp_mask_fault(bp, phy, MDIO_PMA_LASI_TXSTAT,
9113 MDIO_PMA_LASI_TXCTRL);
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00009114
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009115 bnx2x_cl45_read(bp, phy,
Yaniv Rosner60d2fe02011-06-14 01:34:38 +00009116 MDIO_PMA_DEVAD, MDIO_PMA_LASI_STAT, &val1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009117
9118 DP(NETIF_MSG_LINK, "8727 LASI status 0x%x\n", val1);
9119
9120 /* Clear MSG-OUT */
9121 bnx2x_cl45_read(bp, phy,
9122 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &val1);
9123
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00009124 /*
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009125 * If a module is present and there is need to check
9126 * for over current
9127 */
9128 if (!(phy->flags & FLAGS_NOC) && !(rx_alarm_status & (1<<5))) {
9129 /* Check over-current using 8727 GPIO0 input*/
9130 bnx2x_cl45_read(bp, phy,
9131 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_GPIO_CTRL,
9132 &val1);
9133
9134 if ((val1 & (1<<8)) == 0) {
Yaniv Rosner27d02432011-05-31 21:27:48 +00009135 if (!CHIP_IS_E1x(bp))
9136 oc_port = BP_PATH(bp) + (params->port << 1);
Joe Perches94f05b02011-08-14 12:16:20 +00009137 DP(NETIF_MSG_LINK,
9138 "8727 Power fault has been detected on port %d\n",
9139 oc_port);
Yaniv Rosner2f751a82011-11-28 00:49:52 +00009140 netdev_err(bp->dev, "Error: Power fault on Port %d has "
9141 "been detected and the power to "
9142 "that SFP+ module has been removed "
9143 "to prevent failure of the card. "
9144 "Please remove the SFP+ module and "
9145 "restart the system to clear this "
9146 "error.\n",
Yaniv Rosner27d02432011-05-31 21:27:48 +00009147 oc_port);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00009148 /* Disable all RX_ALARMs except for mod_abs */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009149 bnx2x_cl45_write(bp, phy,
9150 MDIO_PMA_DEVAD,
Yaniv Rosner60d2fe02011-06-14 01:34:38 +00009151 MDIO_PMA_LASI_RXCTRL, (1<<5));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009152
9153 bnx2x_cl45_read(bp, phy,
9154 MDIO_PMA_DEVAD,
9155 MDIO_PMA_REG_PHY_IDENTIFIER, &val1);
9156 /* Wait for module_absent_event */
9157 val1 |= (1<<8);
9158 bnx2x_cl45_write(bp, phy,
9159 MDIO_PMA_DEVAD,
9160 MDIO_PMA_REG_PHY_IDENTIFIER, val1);
9161 /* Clear RX alarm */
9162 bnx2x_cl45_read(bp, phy,
9163 MDIO_PMA_DEVAD,
Yaniv Rosner60d2fe02011-06-14 01:34:38 +00009164 MDIO_PMA_LASI_RXSTAT, &rx_alarm_status);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009165 return 0;
9166 }
9167 } /* Over current check */
9168
9169 /* When module absent bit is set, check module */
9170 if (rx_alarm_status & (1<<5)) {
9171 bnx2x_8727_handle_mod_abs(phy, params);
9172 /* Enable all mod_abs and link detection bits */
9173 bnx2x_cl45_write(bp, phy,
Yaniv Rosner60d2fe02011-06-14 01:34:38 +00009174 MDIO_PMA_DEVAD, MDIO_PMA_LASI_RXCTRL,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009175 ((1<<5) | (1<<2)));
9176 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009177 DP(NETIF_MSG_LINK, "Enabling 8727 TX laser if SFP is approved\n");
9178 bnx2x_8727_specific_func(phy, params, ENABLE_TX);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009179 /* If transmitter is disabled, ignore false link up indication */
9180 bnx2x_cl45_read(bp, phy,
9181 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, &val1);
9182 if (val1 & (1<<15)) {
9183 DP(NETIF_MSG_LINK, "Tx is disabled\n");
9184 return 0;
9185 }
9186
9187 bnx2x_cl45_read(bp, phy,
9188 MDIO_PMA_DEVAD,
9189 MDIO_PMA_REG_8073_SPEED_LINK_STATUS, &link_status);
9190
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00009191 /*
9192 * Bits 0..2 --> speed detected,
9193 * Bits 13..15--> link is down
9194 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009195 if ((link_status & (1<<2)) && (!(link_status & (1<<15)))) {
9196 link_up = 1;
9197 vars->line_speed = SPEED_10000;
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00009198 DP(NETIF_MSG_LINK, "port %x: External link up in 10G\n",
9199 params->port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009200 } else if ((link_status & (1<<0)) && (!(link_status & (1<<13)))) {
9201 link_up = 1;
9202 vars->line_speed = SPEED_1000;
9203 DP(NETIF_MSG_LINK, "port %x: External link up in 1G\n",
9204 params->port);
9205 } else {
9206 link_up = 0;
9207 DP(NETIF_MSG_LINK, "port %x: External link is down\n",
9208 params->port);
9209 }
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00009210
9211 /* Capture 10G link fault. */
9212 if (vars->line_speed == SPEED_10000) {
9213 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
Yaniv Rosner60d2fe02011-06-14 01:34:38 +00009214 MDIO_PMA_LASI_TXSTAT, &val1);
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00009215
9216 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
Yaniv Rosner60d2fe02011-06-14 01:34:38 +00009217 MDIO_PMA_LASI_TXSTAT, &val1);
Yaniv Rosnerc688fe22011-05-31 21:27:06 +00009218
9219 if (val1 & (1<<0)) {
9220 vars->fault_detected = 1;
9221 }
9222 }
9223
Yaniv Rosner791f18c2011-01-18 04:33:42 +00009224 if (link_up) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009225 bnx2x_ext_phy_resolve_fc(phy, params, vars);
Yaniv Rosner791f18c2011-01-18 04:33:42 +00009226 vars->duplex = DUPLEX_FULL;
9227 DP(NETIF_MSG_LINK, "duplex = 0x%x\n", vars->duplex);
9228 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009229
9230 if ((DUAL_MEDIA(params)) &&
9231 (phy->req_line_speed == SPEED_1000)) {
9232 bnx2x_cl45_read(bp, phy,
9233 MDIO_PMA_DEVAD,
9234 MDIO_PMA_REG_8727_PCS_GP, &val1);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00009235 /*
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009236 * In case of dual-media board and 1G, power up the XAUI side,
9237 * otherwise power it down. For 10G it is done automatically
9238 */
9239 if (link_up)
9240 val1 &= ~(3<<10);
9241 else
9242 val1 |= (3<<10);
9243 bnx2x_cl45_write(bp, phy,
9244 MDIO_PMA_DEVAD,
9245 MDIO_PMA_REG_8727_PCS_GP, val1);
9246 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009247 return link_up;
9248}
9249
9250static void bnx2x_8727_link_reset(struct bnx2x_phy *phy,
9251 struct link_params *params)
9252{
9253 struct bnx2x *bp = params->bp;
Yaniv Rosner85242ee2011-07-05 01:06:53 +00009254
9255 /* Enable/Disable PHY transmitter output */
9256 bnx2x_set_disable_pmd_transmit(params, phy, 1);
9257
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009258 /* Disable Transmitter */
Yaniv Rosnera8db5b42011-01-31 04:22:28 +00009259 bnx2x_sfp_set_transmitter(params, phy, 0);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009260 /* Clear LASI */
Yaniv Rosner60d2fe02011-06-14 01:34:38 +00009261 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_LASI_CTRL, 0);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009262
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009263}
9264
9265/******************************************************************/
9266/* BCM8481/BCM84823/BCM84833 PHY SECTION */
9267/******************************************************************/
9268static void bnx2x_save_848xx_spirom_version(struct bnx2x_phy *phy,
Yaniv Rosner11b2ec62012-01-17 02:33:25 +00009269 struct bnx2x *bp,
9270 u8 port)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009271{
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009272 u16 val, fw_ver1, fw_ver2, cnt;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009273
Yaniv Rosner11b2ec62012-01-17 02:33:25 +00009274 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) {
9275 bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD, 0x400f, &fw_ver1);
9276 bnx2x_save_spirom_version(bp, port,
9277 ((fw_ver1 & 0xf000)>>5) | (fw_ver1 & 0x7f),
9278 phy->ver_addr);
9279 } else {
9280 /* For 32-bit registers in 848xx, access via MDIO2ARM i/f. */
9281 /* (1) set reg 0xc200_0014(SPI_BRIDGE_CTRL_2) to 0x03000000 */
9282 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0014);
9283 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200);
9284 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81B, 0x0000);
9285 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81C, 0x0300);
9286 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x0009);
Yaniv Rosnerc87bca12011-01-31 04:22:41 +00009287
Yaniv Rosner11b2ec62012-01-17 02:33:25 +00009288 for (cnt = 0; cnt < 100; cnt++) {
9289 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val);
9290 if (val & 1)
9291 break;
9292 udelay(5);
9293 }
9294 if (cnt == 100) {
9295 DP(NETIF_MSG_LINK, "Unable to read 848xx "
9296 "phy fw version(1)\n");
9297 bnx2x_save_spirom_version(bp, port, 0,
9298 phy->ver_addr);
9299 return;
9300 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009301
Yaniv Rosner11b2ec62012-01-17 02:33:25 +00009302
9303 /* 2) read register 0xc200_0000 (SPI_FW_STATUS) */
9304 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0000);
9305 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200);
9306 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x000A);
9307 for (cnt = 0; cnt < 100; cnt++) {
9308 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val);
9309 if (val & 1)
9310 break;
9311 udelay(5);
9312 }
9313 if (cnt == 100) {
9314 DP(NETIF_MSG_LINK, "Unable to read 848xx phy fw "
9315 "version(2)\n");
9316 bnx2x_save_spirom_version(bp, port, 0,
9317 phy->ver_addr);
9318 return;
9319 }
9320
9321 /* lower 16 bits of the register SPI_FW_STATUS */
9322 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81B, &fw_ver1);
9323 /* upper 16 bits of register SPI_FW_STATUS */
9324 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81C, &fw_ver2);
9325
9326 bnx2x_save_spirom_version(bp, port, (fw_ver2<<16) | fw_ver1,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009327 phy->ver_addr);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009328 }
9329
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009330}
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009331static void bnx2x_848xx_set_led(struct bnx2x *bp,
9332 struct bnx2x_phy *phy)
9333{
Yaniv Rosner521683d2011-11-28 00:49:48 +00009334 u16 val, offset;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009335
9336 /* PHYC_CTL_LED_CTL */
9337 bnx2x_cl45_read(bp, phy,
9338 MDIO_PMA_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009339 MDIO_PMA_REG_8481_LINK_SIGNAL, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009340 val &= 0xFE00;
9341 val |= 0x0092;
9342
9343 bnx2x_cl45_write(bp, phy,
9344 MDIO_PMA_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009345 MDIO_PMA_REG_8481_LINK_SIGNAL, val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009346
9347 bnx2x_cl45_write(bp, phy,
9348 MDIO_PMA_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009349 MDIO_PMA_REG_8481_LED1_MASK,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009350 0x80);
9351
9352 bnx2x_cl45_write(bp, phy,
9353 MDIO_PMA_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009354 MDIO_PMA_REG_8481_LED2_MASK,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009355 0x18);
9356
Yaniv Rosnerf25b3c82011-01-18 04:33:47 +00009357 /* Select activity source by Tx and Rx, as suggested by PHY AE */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009358 bnx2x_cl45_write(bp, phy,
9359 MDIO_PMA_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009360 MDIO_PMA_REG_8481_LED3_MASK,
Yaniv Rosnerf25b3c82011-01-18 04:33:47 +00009361 0x0006);
9362
9363 /* Select the closest activity blink rate to that in 10/100/1000 */
9364 bnx2x_cl45_write(bp, phy,
9365 MDIO_PMA_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009366 MDIO_PMA_REG_8481_LED3_BLINK,
Yaniv Rosnerf25b3c82011-01-18 04:33:47 +00009367 0);
9368
Yaniv Rosner521683d2011-11-28 00:49:48 +00009369 /* Configure the blink rate to ~15.9 Hz */
Yaniv Rosnerf25b3c82011-01-18 04:33:47 +00009370 bnx2x_cl45_write(bp, phy,
Yaniv Rosner521683d2011-11-28 00:49:48 +00009371 MDIO_PMA_DEVAD,
9372 MDIO_PMA_REG_84823_CTL_SLOW_CLK_CNT_HIGH,
9373 MDIO_PMA_REG_84823_BLINK_RATE_VAL_15P9HZ);
9374
9375 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833)
9376 offset = MDIO_PMA_REG_84833_CTL_LED_CTL_1;
9377 else
9378 offset = MDIO_PMA_REG_84823_CTL_LED_CTL_1;
9379
9380 bnx2x_cl45_read(bp, phy,
9381 MDIO_PMA_DEVAD, offset, &val);
9382 val |= MDIO_PMA_REG_84823_LED3_STRETCH_EN; /* stretch_en for LED3*/
9383 bnx2x_cl45_write(bp, phy,
9384 MDIO_PMA_DEVAD, offset, val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009385
9386 /* 'Interrupt Mask' */
9387 bnx2x_cl45_write(bp, phy,
9388 MDIO_AN_DEVAD,
9389 0xFFFB, 0xFFFD);
9390}
9391
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00009392static int bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy,
9393 struct link_params *params,
9394 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009395{
9396 struct bnx2x *bp = params->bp;
Yaniv Rosner521683d2011-11-28 00:49:48 +00009397 u16 autoneg_val, an_1000_val, an_10_100_val, an_10g_val;
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009398 u16 tmp_req_line_speed;
9399
9400 tmp_req_line_speed = phy->req_line_speed;
Yaniv Rosner11b2ec62012-01-17 02:33:25 +00009401 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) {
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009402 if (phy->req_line_speed == SPEED_10000)
9403 phy->req_line_speed = SPEED_AUTO_NEG;
Yaniv Rosner11b2ec62012-01-17 02:33:25 +00009404 } else {
9405 /* Save spirom version */
9406 bnx2x_save_848xx_spirom_version(phy, bp, params->port);
9407 }
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +00009408 /*
9409 * This phy uses the NIG latch mechanism since link indication
9410 * arrives through its LED4 and not via its LASI signal, so we
9411 * get steady signal instead of clear on read
9412 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009413 bnx2x_bits_en(bp, NIG_REG_LATCH_BC_0 + params->port*4,
9414 1 << NIG_LATCH_BC_ENABLE_MI_INT);
9415
9416 bnx2x_cl45_write(bp, phy,
9417 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x0000);
9418
9419 bnx2x_848xx_set_led(bp, phy);
9420
9421 /* set 1000 speed advertisement */
9422 bnx2x_cl45_read(bp, phy,
9423 MDIO_AN_DEVAD, MDIO_AN_REG_8481_1000T_CTRL,
9424 &an_1000_val);
9425
9426 bnx2x_ext_phy_set_pause(params, phy, vars);
9427 bnx2x_cl45_read(bp, phy,
9428 MDIO_AN_DEVAD,
9429 MDIO_AN_REG_8481_LEGACY_AN_ADV,
9430 &an_10_100_val);
9431 bnx2x_cl45_read(bp, phy,
9432 MDIO_AN_DEVAD, MDIO_AN_REG_8481_LEGACY_MII_CTRL,
9433 &autoneg_val);
9434 /* Disable forced speed */
9435 autoneg_val &= ~((1<<6) | (1<<8) | (1<<9) | (1<<12) | (1<<13));
9436 an_10_100_val &= ~((1<<5) | (1<<6) | (1<<7) | (1<<8));
9437
9438 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
9439 (phy->speed_cap_mask &
9440 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) ||
9441 (phy->req_line_speed == SPEED_1000)) {
9442 an_1000_val |= (1<<8);
9443 autoneg_val |= (1<<9 | 1<<12);
9444 if (phy->req_duplex == DUPLEX_FULL)
9445 an_1000_val |= (1<<9);
9446 DP(NETIF_MSG_LINK, "Advertising 1G\n");
9447 } else
9448 an_1000_val &= ~((1<<8) | (1<<9));
9449
9450 bnx2x_cl45_write(bp, phy,
9451 MDIO_AN_DEVAD, MDIO_AN_REG_8481_1000T_CTRL,
9452 an_1000_val);
9453
Yaniv Rosner0520e632011-07-05 01:06:59 +00009454 /* set 100 speed advertisement */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009455 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
9456 (phy->speed_cap_mask &
Yaniv Rosner0520e632011-07-05 01:06:59 +00009457 (PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL |
9458 PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF)) &&
9459 (phy->supported &
9460 (SUPPORTED_100baseT_Half |
9461 SUPPORTED_100baseT_Full)))) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009462 an_10_100_val |= (1<<7);
9463 /* Enable autoneg and restart autoneg for legacy speeds */
9464 autoneg_val |= (1<<9 | 1<<12);
9465
9466 if (phy->req_duplex == DUPLEX_FULL)
9467 an_10_100_val |= (1<<8);
9468 DP(NETIF_MSG_LINK, "Advertising 100M\n");
9469 }
9470 /* set 10 speed advertisement */
9471 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
Yaniv Rosner0520e632011-07-05 01:06:59 +00009472 (phy->speed_cap_mask &
9473 (PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL |
9474 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF)) &&
9475 (phy->supported &
9476 (SUPPORTED_10baseT_Half |
9477 SUPPORTED_10baseT_Full)))) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009478 an_10_100_val |= (1<<5);
9479 autoneg_val |= (1<<9 | 1<<12);
9480 if (phy->req_duplex == DUPLEX_FULL)
9481 an_10_100_val |= (1<<6);
9482 DP(NETIF_MSG_LINK, "Advertising 10M\n");
9483 }
9484
9485 /* Only 10/100 are allowed to work in FORCE mode */
Yaniv Rosner0520e632011-07-05 01:06:59 +00009486 if ((phy->req_line_speed == SPEED_100) &&
9487 (phy->supported &
9488 (SUPPORTED_100baseT_Half |
9489 SUPPORTED_100baseT_Full))) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009490 autoneg_val |= (1<<13);
9491 /* Enabled AUTO-MDIX when autoneg is disabled */
9492 bnx2x_cl45_write(bp, phy,
9493 MDIO_AN_DEVAD, MDIO_AN_REG_8481_AUX_CTRL,
9494 (1<<15 | 1<<9 | 7<<0));
Yaniv Rosner521683d2011-11-28 00:49:48 +00009495 /* The PHY needs this set even for forced link. */
9496 an_10_100_val |= (1<<8) | (1<<7);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009497 DP(NETIF_MSG_LINK, "Setting 100M force\n");
9498 }
Yaniv Rosner0520e632011-07-05 01:06:59 +00009499 if ((phy->req_line_speed == SPEED_10) &&
9500 (phy->supported &
9501 (SUPPORTED_10baseT_Half |
9502 SUPPORTED_10baseT_Full))) {
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009503 /* Enabled AUTO-MDIX when autoneg is disabled */
9504 bnx2x_cl45_write(bp, phy,
9505 MDIO_AN_DEVAD, MDIO_AN_REG_8481_AUX_CTRL,
9506 (1<<15 | 1<<9 | 7<<0));
9507 DP(NETIF_MSG_LINK, "Setting 10M force\n");
9508 }
9509
9510 bnx2x_cl45_write(bp, phy,
9511 MDIO_AN_DEVAD, MDIO_AN_REG_8481_LEGACY_AN_ADV,
9512 an_10_100_val);
9513
9514 if (phy->req_duplex == DUPLEX_FULL)
9515 autoneg_val |= (1<<8);
9516
Yaniv Rosnerfd38f73e2011-08-02 22:59:53 +00009517 /*
9518 * Always write this if this is not 84833.
9519 * For 84833, write it only when it's a forced speed.
9520 */
9521 if ((phy->type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) ||
9522 ((autoneg_val & (1<<12)) == 0))
9523 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009524 MDIO_AN_DEVAD,
9525 MDIO_AN_REG_8481_LEGACY_MII_CTRL, autoneg_val);
9526
9527 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
9528 (phy->speed_cap_mask &
9529 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) ||
9530 (phy->req_line_speed == SPEED_10000)) {
Yaniv Rosner9045f6b2011-05-31 21:28:27 +00009531 DP(NETIF_MSG_LINK, "Advertising 10G\n");
9532 /* Restart autoneg for 10G*/
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009533
Yaniv Rosner521683d2011-11-28 00:49:48 +00009534 bnx2x_cl45_read(bp, phy,
9535 MDIO_AN_DEVAD,
9536 MDIO_AN_REG_8481_10GBASE_T_AN_CTRL,
9537 &an_10g_val);
Yaniv Rosner9045f6b2011-05-31 21:28:27 +00009538 bnx2x_cl45_write(bp, phy,
Yaniv Rosner521683d2011-11-28 00:49:48 +00009539 MDIO_AN_DEVAD,
9540 MDIO_AN_REG_8481_10GBASE_T_AN_CTRL,
9541 an_10g_val | 0x1000);
9542 bnx2x_cl45_write(bp, phy,
9543 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL,
9544 0x3200);
Yaniv Rosnerfd38f73e2011-08-02 22:59:53 +00009545 } else
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009546 bnx2x_cl45_write(bp, phy,
9547 MDIO_AN_DEVAD,
9548 MDIO_AN_REG_8481_10GBASE_T_AN_CTRL,
9549 1);
Yaniv Rosnerfd38f73e2011-08-02 22:59:53 +00009550
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009551 phy->req_line_speed = tmp_req_line_speed;
9552
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009553 return 0;
9554}
9555
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00009556static int bnx2x_8481_config_init(struct bnx2x_phy *phy,
9557 struct link_params *params,
9558 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009559{
9560 struct bnx2x *bp = params->bp;
9561 /* Restore normal power mode*/
9562 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00009563 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009564
9565 /* HW reset */
9566 bnx2x_ext_phy_hw_reset(bp, params->port);
Yaniv Rosner6d870c32011-01-31 04:22:20 +00009567 bnx2x_wait_reset_complete(bp, phy, params);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009568
9569 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
9570 return bnx2x_848xx_cmn_config_init(phy, params, vars);
9571}
9572
Yaniv Rosner521683d2011-11-28 00:49:48 +00009573#define PHY84833_CMDHDLR_WAIT 300
9574#define PHY84833_CMDHDLR_MAX_ARGS 5
9575static int bnx2x_84833_cmd_hdlr(struct bnx2x_phy *phy,
9576 struct link_params *params,
9577 u16 fw_cmd,
9578 u16 cmd_args[])
9579{
9580 u32 idx;
9581 u16 val;
9582 struct bnx2x *bp = params->bp;
9583 /* Write CMD_OPEN_OVERRIDE to STATUS reg */
9584 bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
9585 MDIO_84833_CMD_HDLR_STATUS,
9586 PHY84833_STATUS_CMD_OPEN_OVERRIDE);
9587 for (idx = 0; idx < PHY84833_CMDHDLR_WAIT; idx++) {
9588 bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
9589 MDIO_84833_CMD_HDLR_STATUS, &val);
9590 if (val == PHY84833_STATUS_CMD_OPEN_FOR_CMDS)
9591 break;
9592 msleep(1);
9593 }
9594 if (idx >= PHY84833_CMDHDLR_WAIT) {
9595 DP(NETIF_MSG_LINK, "FW cmd: FW not ready.\n");
9596 return -EINVAL;
9597 }
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009598
Yaniv Rosner521683d2011-11-28 00:49:48 +00009599 /* Prepare argument(s) and issue command */
9600 for (idx = 0; idx < PHY84833_CMDHDLR_MAX_ARGS; idx++) {
9601 bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
9602 MDIO_84833_CMD_HDLR_DATA1 + idx,
9603 cmd_args[idx]);
9604 }
9605 bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
9606 MDIO_84833_CMD_HDLR_COMMAND, fw_cmd);
9607 for (idx = 0; idx < PHY84833_CMDHDLR_WAIT; idx++) {
9608 bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
9609 MDIO_84833_CMD_HDLR_STATUS, &val);
9610 if ((val == PHY84833_STATUS_CMD_COMPLETE_PASS) ||
9611 (val == PHY84833_STATUS_CMD_COMPLETE_ERROR))
9612 break;
9613 msleep(1);
9614 }
9615 if ((idx >= PHY84833_CMDHDLR_WAIT) ||
9616 (val == PHY84833_STATUS_CMD_COMPLETE_ERROR)) {
9617 DP(NETIF_MSG_LINK, "FW cmd failed.\n");
9618 return -EINVAL;
9619 }
9620 /* Gather returning data */
9621 for (idx = 0; idx < PHY84833_CMDHDLR_MAX_ARGS; idx++) {
9622 bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
9623 MDIO_84833_CMD_HDLR_DATA1 + idx,
9624 &cmd_args[idx]);
9625 }
9626 bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
9627 MDIO_84833_CMD_HDLR_STATUS,
9628 PHY84833_STATUS_CMD_CLEAR_COMPLETE);
9629 return 0;
9630}
9631
9632
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009633static int bnx2x_84833_pair_swap_cfg(struct bnx2x_phy *phy,
9634 struct link_params *params,
9635 struct link_vars *vars)
9636{
Yaniv Rosner0520e632011-07-05 01:06:59 +00009637 u32 pair_swap;
Yaniv Rosner521683d2011-11-28 00:49:48 +00009638 u16 data[PHY84833_CMDHDLR_MAX_ARGS];
9639 int status;
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009640 struct bnx2x *bp = params->bp;
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009641
Yaniv Rosner0520e632011-07-05 01:06:59 +00009642 /* Check for configuration. */
9643 pair_swap = REG_RD(bp, params->shmem_base +
9644 offsetof(struct shmem_region,
9645 dev_info.port_hw_config[params->port].xgbt_phy_cfg)) &
9646 PORT_HW_CFG_RJ45_PAIR_SWAP_MASK;
9647
9648 if (pair_swap == 0)
9649 return 0;
9650
Yaniv Rosner521683d2011-11-28 00:49:48 +00009651 /* Only the second argument is used for this command */
9652 data[1] = (u16)pair_swap;
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009653
Yaniv Rosner521683d2011-11-28 00:49:48 +00009654 status = bnx2x_84833_cmd_hdlr(phy, params,
9655 PHY84833_CMD_SET_PAIR_SWAP, data);
9656 if (status == 0)
9657 DP(NETIF_MSG_LINK, "Pairswap OK, val=0x%x\n", data[1]);
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009658
Yaniv Rosner521683d2011-11-28 00:49:48 +00009659 return status;
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009660}
9661
Yaniv Rosner985848f2011-07-05 01:06:48 +00009662static u8 bnx2x_84833_get_reset_gpios(struct bnx2x *bp,
9663 u32 shmem_base_path[],
9664 u32 chip_id)
Yaniv Rosner0d40f0d2011-06-14 01:34:27 +00009665{
9666 u32 reset_pin[2];
9667 u32 idx;
9668 u8 reset_gpios;
9669 if (CHIP_IS_E3(bp)) {
9670 /* Assume that these will be GPIOs, not EPIOs. */
9671 for (idx = 0; idx < 2; idx++) {
9672 /* Map config param to register bit. */
9673 reset_pin[idx] = REG_RD(bp, shmem_base_path[idx] +
9674 offsetof(struct shmem_region,
9675 dev_info.port_hw_config[0].e3_cmn_pin_cfg));
9676 reset_pin[idx] = (reset_pin[idx] &
9677 PORT_HW_CFG_E3_PHY_RESET_MASK) >>
9678 PORT_HW_CFG_E3_PHY_RESET_SHIFT;
9679 reset_pin[idx] -= PIN_CFG_GPIO0_P0;
9680 reset_pin[idx] = (1 << reset_pin[idx]);
9681 }
9682 reset_gpios = (u8)(reset_pin[0] | reset_pin[1]);
9683 } else {
9684 /* E2, look from diff place of shmem. */
9685 for (idx = 0; idx < 2; idx++) {
9686 reset_pin[idx] = REG_RD(bp, shmem_base_path[idx] +
9687 offsetof(struct shmem_region,
9688 dev_info.port_hw_config[0].default_cfg));
9689 reset_pin[idx] &= PORT_HW_CFG_EXT_PHY_GPIO_RST_MASK;
9690 reset_pin[idx] -= PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO0_P0;
9691 reset_pin[idx] >>= PORT_HW_CFG_EXT_PHY_GPIO_RST_SHIFT;
9692 reset_pin[idx] = (1 << reset_pin[idx]);
9693 }
9694 reset_gpios = (u8)(reset_pin[0] | reset_pin[1]);
9695 }
9696
Yaniv Rosner985848f2011-07-05 01:06:48 +00009697 return reset_gpios;
9698}
9699
9700static int bnx2x_84833_hw_reset_phy(struct bnx2x_phy *phy,
9701 struct link_params *params)
9702{
9703 struct bnx2x *bp = params->bp;
9704 u8 reset_gpios;
9705 u32 other_shmem_base_addr = REG_RD(bp, params->shmem2_base +
9706 offsetof(struct shmem2_region,
9707 other_shmem_base_addr));
9708
9709 u32 shmem_base_path[2];
9710 shmem_base_path[0] = params->shmem_base;
9711 shmem_base_path[1] = other_shmem_base_addr;
9712
9713 reset_gpios = bnx2x_84833_get_reset_gpios(bp, shmem_base_path,
9714 params->chip_id);
9715
9716 bnx2x_set_mult_gpio(bp, reset_gpios, MISC_REGISTERS_GPIO_OUTPUT_LOW);
9717 udelay(10);
9718 DP(NETIF_MSG_LINK, "84833 hw reset on pin values 0x%x\n",
9719 reset_gpios);
9720
9721 return 0;
9722}
9723
Yaniv Rosnera89a1d42011-07-05 01:07:05 +00009724#define PHY84833_CONSTANT_LATENCY 1193
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00009725static int bnx2x_848x3_config_init(struct bnx2x_phy *phy,
9726 struct link_params *params,
9727 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009728{
9729 struct bnx2x *bp = params->bp;
Yaniv Rosner6a71bbe2010-11-01 05:32:31 +00009730 u8 port, initialize = 1;
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009731 u16 val;
Yaniv Rosner521683d2011-11-28 00:49:48 +00009732 u32 actual_phy_selection, cms_enable;
9733 u16 cmd_args[PHY84833_CMDHDLR_MAX_ARGS];
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00009734 int rc = 0;
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00009735
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009736 msleep(1);
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009737
9738 if (!(CHIP_IS_E1(bp)))
Yaniv Rosner6a71bbe2010-11-01 05:32:31 +00009739 port = BP_PATH(bp);
9740 else
9741 port = params->port;
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009742
9743 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823) {
9744 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
9745 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
9746 port);
9747 } else {
Yaniv Rosner985848f2011-07-05 01:06:48 +00009748 /* MDIO reset */
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009749 bnx2x_cl45_write(bp, phy,
9750 MDIO_PMA_DEVAD,
9751 MDIO_PMA_REG_CTRL, 0x8000);
Yaniv Rosner521683d2011-11-28 00:49:48 +00009752 }
9753
9754 bnx2x_wait_reset_complete(bp, phy, params);
9755
9756 /* Wait for GPHY to come out of reset */
9757 msleep(50);
Yaniv Rosner11b2ec62012-01-17 02:33:25 +00009758 if (phy->type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) {
Yaniv Rosner521683d2011-11-28 00:49:48 +00009759 /*
9760 * BCM84823 requires that XGXS links up first @ 10G for normal
9761 * behavior.
9762 */
9763 u16 temp;
9764 temp = vars->line_speed;
9765 vars->line_speed = SPEED_10000;
9766 bnx2x_set_autoneg(&params->phy[INT_PHY], params, vars, 0);
9767 bnx2x_program_serdes(&params->phy[INT_PHY], params, vars);
9768 vars->line_speed = temp;
9769 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009770
9771 bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009772 MDIO_CTL_REG_84823_MEDIA, &val);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009773 val &= ~(MDIO_CTL_REG_84823_MEDIA_MAC_MASK |
9774 MDIO_CTL_REG_84823_MEDIA_LINE_MASK |
9775 MDIO_CTL_REG_84823_MEDIA_COPPER_CORE_DOWN |
9776 MDIO_CTL_REG_84823_MEDIA_PRIORITY_MASK |
9777 MDIO_CTL_REG_84823_MEDIA_FIBER_1G);
Yaniv Rosner0d40f0d2011-06-14 01:34:27 +00009778
9779 if (CHIP_IS_E3(bp)) {
9780 val &= ~(MDIO_CTL_REG_84823_MEDIA_MAC_MASK |
9781 MDIO_CTL_REG_84823_MEDIA_LINE_MASK);
9782 } else {
9783 val |= (MDIO_CTL_REG_84823_CTRL_MAC_XFI |
9784 MDIO_CTL_REG_84823_MEDIA_LINE_XAUI_L);
9785 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009786
9787 actual_phy_selection = bnx2x_phy_selection(params);
9788
9789 switch (actual_phy_selection) {
9790 case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT:
Lucas De Marchi25985ed2011-03-30 22:57:33 -03009791 /* Do nothing. Essentially this is like the priority copper */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009792 break;
9793 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
9794 val |= MDIO_CTL_REG_84823_MEDIA_PRIORITY_COPPER;
9795 break;
9796 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
9797 val |= MDIO_CTL_REG_84823_MEDIA_PRIORITY_FIBER;
9798 break;
9799 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY:
9800 /* Do nothing here. The first PHY won't be initialized at all */
9801 break;
9802 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY:
9803 val |= MDIO_CTL_REG_84823_MEDIA_COPPER_CORE_DOWN;
9804 initialize = 0;
9805 break;
9806 }
9807 if (params->phy[EXT_PHY2].req_line_speed == SPEED_1000)
9808 val |= MDIO_CTL_REG_84823_MEDIA_FIBER_1G;
9809
9810 bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009811 MDIO_CTL_REG_84823_MEDIA, val);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009812 DP(NETIF_MSG_LINK, "Multi_phy config = 0x%x, Media control = 0x%x\n",
9813 params->multi_phy_config, val);
9814
Yaniv Rosner11b2ec62012-01-17 02:33:25 +00009815 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) {
9816 bnx2x_84833_pair_swap_cfg(phy, params, vars);
Yaniv Rosnera89a1d42011-07-05 01:07:05 +00009817
Yaniv Rosner11b2ec62012-01-17 02:33:25 +00009818 /* AutogrEEEn */
9819 if (params->feature_config_flags &
9820 FEATURE_CONFIG_AUTOGREEEN_ENABLED)
9821 cmd_args[0] = 0x2;
9822 else
9823 cmd_args[0] = 0x0;
9824 cmd_args[1] = 0x0;
9825 cmd_args[2] = PHY84833_CONSTANT_LATENCY + 1;
9826 cmd_args[3] = PHY84833_CONSTANT_LATENCY;
9827 rc = bnx2x_84833_cmd_hdlr(phy, params,
9828 PHY84833_CMD_SET_EEE_MODE, cmd_args);
9829 if (rc != 0)
9830 DP(NETIF_MSG_LINK, "Cfg AutogrEEEn failed.\n");
9831 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009832 if (initialize)
9833 rc = bnx2x_848xx_cmn_config_init(phy, params, vars);
9834 else
Yaniv Rosner11b2ec62012-01-17 02:33:25 +00009835 bnx2x_save_848xx_spirom_version(phy, bp, params->port);
Yaniv Rosnera89a1d42011-07-05 01:07:05 +00009836 /* 84833 PHY has a better feature and doesn't need to support this. */
9837 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823) {
9838 cms_enable = REG_RD(bp, params->shmem_base +
Yaniv Rosner1bef68e2011-01-31 04:22:46 +00009839 offsetof(struct shmem_region,
9840 dev_info.port_hw_config[params->port].default_cfg)) &
9841 PORT_HW_CFG_ENABLE_CMS_MASK;
9842
Yaniv Rosnera89a1d42011-07-05 01:07:05 +00009843 bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
9844 MDIO_CTL_REG_84823_USER_CTRL_REG, &val);
9845 if (cms_enable)
9846 val |= MDIO_CTL_REG_84823_USER_CTRL_CMS;
9847 else
9848 val &= ~MDIO_CTL_REG_84823_USER_CTRL_CMS;
9849 bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
9850 MDIO_CTL_REG_84823_USER_CTRL_REG, val);
9851 }
Yaniv Rosner1bef68e2011-01-31 04:22:46 +00009852
Yaniv Rosner11b2ec62012-01-17 02:33:25 +00009853 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) {
9854 /* Bring PHY out of super isolate mode as the final step. */
9855 bnx2x_cl45_read(bp, phy,
9856 MDIO_CTL_DEVAD,
9857 MDIO_84833_TOP_CFG_XGPHY_STRAP1, &val);
9858 val &= ~MDIO_84833_SUPER_ISOLATE;
9859 bnx2x_cl45_write(bp, phy,
9860 MDIO_CTL_DEVAD,
9861 MDIO_84833_TOP_CFG_XGPHY_STRAP1, val);
9862 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00009863 return rc;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009864}
9865
9866static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00009867 struct link_params *params,
9868 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009869{
9870 struct bnx2x *bp = params->bp;
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009871 u16 val, val1, val2;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009872 u8 link_up = 0;
9873
Yaniv Rosnerc87bca12011-01-31 04:22:41 +00009874
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009875 /* Check 10G-BaseT link status */
9876 /* Check PMD signal ok */
9877 bnx2x_cl45_read(bp, phy,
9878 MDIO_AN_DEVAD, 0xFFFA, &val1);
9879 bnx2x_cl45_read(bp, phy,
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009880 MDIO_PMA_DEVAD, MDIO_PMA_REG_8481_PMD_SIGNAL,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009881 &val2);
9882 DP(NETIF_MSG_LINK, "BCM848xx: PMD_SIGNAL 1.a811 = 0x%x\n", val2);
9883
9884 /* Check link 10G */
9885 if (val2 & (1<<11)) {
9886 vars->line_speed = SPEED_10000;
Yaniv Rosner791f18c2011-01-18 04:33:42 +00009887 vars->duplex = DUPLEX_FULL;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009888 link_up = 1;
9889 bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
9890 } else { /* Check Legacy speed link */
9891 u16 legacy_status, legacy_speed;
9892
9893 /* Enable expansion register 0x42 (Operation mode status) */
9894 bnx2x_cl45_write(bp, phy,
9895 MDIO_AN_DEVAD,
9896 MDIO_AN_REG_8481_EXPANSION_REG_ACCESS, 0xf42);
9897
9898 /* Get legacy speed operation status */
9899 bnx2x_cl45_read(bp, phy,
9900 MDIO_AN_DEVAD,
9901 MDIO_AN_REG_8481_EXPANSION_REG_RD_RW,
9902 &legacy_status);
9903
Joe Perches94f05b02011-08-14 12:16:20 +00009904 DP(NETIF_MSG_LINK, "Legacy speed status = 0x%x\n",
9905 legacy_status);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009906 link_up = ((legacy_status & (1<<11)) == (1<<11));
9907 if (link_up) {
9908 legacy_speed = (legacy_status & (3<<9));
9909 if (legacy_speed == (0<<9))
9910 vars->line_speed = SPEED_10;
9911 else if (legacy_speed == (1<<9))
9912 vars->line_speed = SPEED_100;
9913 else if (legacy_speed == (2<<9))
9914 vars->line_speed = SPEED_1000;
9915 else /* Should not happen */
9916 vars->line_speed = 0;
9917
9918 if (legacy_status & (1<<8))
9919 vars->duplex = DUPLEX_FULL;
9920 else
9921 vars->duplex = DUPLEX_HALF;
9922
Joe Perches94f05b02011-08-14 12:16:20 +00009923 DP(NETIF_MSG_LINK,
9924 "Link is up in %dMbps, is_duplex_full= %d\n",
9925 vars->line_speed,
9926 (vars->duplex == DUPLEX_FULL));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009927 /* Check legacy speed AN resolution */
9928 bnx2x_cl45_read(bp, phy,
9929 MDIO_AN_DEVAD,
9930 MDIO_AN_REG_8481_LEGACY_MII_STATUS,
9931 &val);
9932 if (val & (1<<5))
9933 vars->link_status |=
9934 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
9935 bnx2x_cl45_read(bp, phy,
9936 MDIO_AN_DEVAD,
9937 MDIO_AN_REG_8481_LEGACY_AN_EXPANSION,
9938 &val);
9939 if ((val & (1<<0)) == 0)
9940 vars->link_status |=
9941 LINK_STATUS_PARALLEL_DETECTION_USED;
9942 }
9943 }
9944 if (link_up) {
9945 DP(NETIF_MSG_LINK, "BCM84823: link speed is %d\n",
9946 vars->line_speed);
9947 bnx2x_ext_phy_resolve_fc(phy, params, vars);
9948 }
9949
9950 return link_up;
9951}
9952
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00009953
9954static int bnx2x_848xx_format_ver(u32 raw_ver, u8 *str, u16 *len)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009955{
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +00009956 int status = 0;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009957 u32 spirom_ver;
9958 spirom_ver = ((raw_ver & 0xF80) >> 7) << 16 | (raw_ver & 0x7F);
9959 status = bnx2x_format_ver(spirom_ver, str, len);
9960 return status;
9961}
9962
9963static void bnx2x_8481_hw_reset(struct bnx2x_phy *phy,
9964 struct link_params *params)
9965{
9966 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00009967 MISC_REGISTERS_GPIO_OUTPUT_LOW, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009968 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +00009969 MISC_REGISTERS_GPIO_OUTPUT_LOW, 1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00009970}
9971
9972static void bnx2x_8481_link_reset(struct bnx2x_phy *phy,
9973 struct link_params *params)
9974{
9975 bnx2x_cl45_write(params->bp, phy,
9976 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x0000);
9977 bnx2x_cl45_write(params->bp, phy,
9978 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1);
9979}
9980
9981static void bnx2x_848x3_link_reset(struct bnx2x_phy *phy,
9982 struct link_params *params)
9983{
9984 struct bnx2x *bp = params->bp;
Yaniv Rosner6a71bbe2010-11-01 05:32:31 +00009985 u8 port;
Yaniv Rosner0d40f0d2011-06-14 01:34:27 +00009986 u16 val16;
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009987
9988 if (!(CHIP_IS_E1(bp)))
Yaniv Rosner6a71bbe2010-11-01 05:32:31 +00009989 port = BP_PATH(bp);
9990 else
9991 port = params->port;
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +00009992
9993 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823) {
9994 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
9995 MISC_REGISTERS_GPIO_OUTPUT_LOW,
9996 port);
9997 } else {
Yaniv Rosner0d40f0d2011-06-14 01:34:27 +00009998 bnx2x_cl45_read(bp, phy,
9999 MDIO_CTL_DEVAD,
Yaniv Rosner11b2ec62012-01-17 02:33:25 +000010000 MDIO_84833_TOP_CFG_XGPHY_STRAP1, &val16);
10001 val16 |= MDIO_84833_SUPER_ISOLATE;
Yaniv Rosnerfd38f73e2011-08-02 22:59:53 +000010002 bnx2x_cl45_write(bp, phy,
Yaniv Rosner11b2ec62012-01-17 02:33:25 +000010003 MDIO_CTL_DEVAD,
10004 MDIO_84833_TOP_CFG_XGPHY_STRAP1, val16);
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +000010005 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010006}
10007
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +000010008static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy,
10009 struct link_params *params, u8 mode)
10010{
10011 struct bnx2x *bp = params->bp;
10012 u16 val;
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +000010013 u8 port;
10014
10015 if (!(CHIP_IS_E1(bp)))
10016 port = BP_PATH(bp);
10017 else
10018 port = params->port;
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +000010019
10020 switch (mode) {
10021 case LED_MODE_OFF:
10022
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +000010023 DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE OFF\n", port);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +000010024
10025 if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
10026 SHARED_HW_CFG_LED_EXTPHY1) {
10027
10028 /* Set LED masks */
10029 bnx2x_cl45_write(bp, phy,
10030 MDIO_PMA_DEVAD,
10031 MDIO_PMA_REG_8481_LED1_MASK,
10032 0x0);
10033
10034 bnx2x_cl45_write(bp, phy,
10035 MDIO_PMA_DEVAD,
10036 MDIO_PMA_REG_8481_LED2_MASK,
10037 0x0);
10038
10039 bnx2x_cl45_write(bp, phy,
10040 MDIO_PMA_DEVAD,
10041 MDIO_PMA_REG_8481_LED3_MASK,
10042 0x0);
10043
10044 bnx2x_cl45_write(bp, phy,
10045 MDIO_PMA_DEVAD,
10046 MDIO_PMA_REG_8481_LED5_MASK,
10047 0x0);
10048
10049 } else {
10050 bnx2x_cl45_write(bp, phy,
10051 MDIO_PMA_DEVAD,
10052 MDIO_PMA_REG_8481_LED1_MASK,
10053 0x0);
10054 }
10055 break;
10056 case LED_MODE_FRONT_PANEL_OFF:
10057
10058 DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE FRONT PANEL OFF\n",
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +000010059 port);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +000010060
10061 if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
10062 SHARED_HW_CFG_LED_EXTPHY1) {
10063
10064 /* Set LED masks */
10065 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010066 MDIO_PMA_DEVAD,
10067 MDIO_PMA_REG_8481_LED1_MASK,
10068 0x0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +000010069
10070 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010071 MDIO_PMA_DEVAD,
10072 MDIO_PMA_REG_8481_LED2_MASK,
10073 0x0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +000010074
10075 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010076 MDIO_PMA_DEVAD,
10077 MDIO_PMA_REG_8481_LED3_MASK,
10078 0x0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +000010079
10080 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010081 MDIO_PMA_DEVAD,
10082 MDIO_PMA_REG_8481_LED5_MASK,
10083 0x20);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +000010084
10085 } else {
10086 bnx2x_cl45_write(bp, phy,
10087 MDIO_PMA_DEVAD,
10088 MDIO_PMA_REG_8481_LED1_MASK,
10089 0x0);
10090 }
10091 break;
10092 case LED_MODE_ON:
10093
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +000010094 DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE ON\n", port);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +000010095
10096 if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
10097 SHARED_HW_CFG_LED_EXTPHY1) {
10098 /* Set control reg */
10099 bnx2x_cl45_read(bp, phy,
10100 MDIO_PMA_DEVAD,
10101 MDIO_PMA_REG_8481_LINK_SIGNAL,
10102 &val);
10103 val &= 0x8000;
10104 val |= 0x2492;
10105
10106 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010107 MDIO_PMA_DEVAD,
10108 MDIO_PMA_REG_8481_LINK_SIGNAL,
10109 val);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +000010110
10111 /* Set LED masks */
10112 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010113 MDIO_PMA_DEVAD,
10114 MDIO_PMA_REG_8481_LED1_MASK,
10115 0x0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +000010116
10117 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010118 MDIO_PMA_DEVAD,
10119 MDIO_PMA_REG_8481_LED2_MASK,
10120 0x20);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +000010121
10122 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010123 MDIO_PMA_DEVAD,
10124 MDIO_PMA_REG_8481_LED3_MASK,
10125 0x20);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +000010126
10127 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010128 MDIO_PMA_DEVAD,
10129 MDIO_PMA_REG_8481_LED5_MASK,
10130 0x0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +000010131 } else {
10132 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010133 MDIO_PMA_DEVAD,
10134 MDIO_PMA_REG_8481_LED1_MASK,
10135 0x20);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +000010136 }
10137 break;
10138
10139 case LED_MODE_OPER:
10140
Yaniv Rosnerbac27bd2011-05-31 21:28:10 +000010141 DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE OPER\n", port);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +000010142
10143 if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
10144 SHARED_HW_CFG_LED_EXTPHY1) {
10145
10146 /* Set control reg */
10147 bnx2x_cl45_read(bp, phy,
10148 MDIO_PMA_DEVAD,
10149 MDIO_PMA_REG_8481_LINK_SIGNAL,
10150 &val);
10151
10152 if (!((val &
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010153 MDIO_PMA_REG_8481_LINK_SIGNAL_LED4_ENABLE_MASK)
10154 >> MDIO_PMA_REG_8481_LINK_SIGNAL_LED4_ENABLE_SHIFT)) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +000010155 DP(NETIF_MSG_LINK, "Setting LINK_SIGNAL\n");
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +000010156 bnx2x_cl45_write(bp, phy,
10157 MDIO_PMA_DEVAD,
10158 MDIO_PMA_REG_8481_LINK_SIGNAL,
10159 0xa492);
10160 }
10161
10162 /* Set LED masks */
10163 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010164 MDIO_PMA_DEVAD,
10165 MDIO_PMA_REG_8481_LED1_MASK,
10166 0x10);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +000010167
10168 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010169 MDIO_PMA_DEVAD,
10170 MDIO_PMA_REG_8481_LED2_MASK,
10171 0x80);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +000010172
10173 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010174 MDIO_PMA_DEVAD,
10175 MDIO_PMA_REG_8481_LED3_MASK,
10176 0x98);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +000010177
10178 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010179 MDIO_PMA_DEVAD,
10180 MDIO_PMA_REG_8481_LED5_MASK,
10181 0x40);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +000010182
10183 } else {
10184 bnx2x_cl45_write(bp, phy,
10185 MDIO_PMA_DEVAD,
10186 MDIO_PMA_REG_8481_LED1_MASK,
10187 0x80);
Yaniv Rosner53eda062011-01-30 04:14:55 +000010188
10189 /* Tell LED3 to blink on source */
10190 bnx2x_cl45_read(bp, phy,
10191 MDIO_PMA_DEVAD,
10192 MDIO_PMA_REG_8481_LINK_SIGNAL,
10193 &val);
10194 val &= ~(7<<6);
10195 val |= (1<<6); /* A83B[8:6]= 1 */
10196 bnx2x_cl45_write(bp, phy,
10197 MDIO_PMA_DEVAD,
10198 MDIO_PMA_REG_8481_LINK_SIGNAL,
10199 val);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +000010200 }
10201 break;
10202 }
Yaniv Rosner0d40f0d2011-06-14 01:34:27 +000010203
10204 /*
10205 * This is a workaround for E3+84833 until autoneg
10206 * restart is fixed in f/w
10207 */
10208 if (CHIP_IS_E3(bp)) {
10209 bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
10210 MDIO_WC_REG_GP2_STATUS_GP_2_1, &val);
10211 }
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +000010212}
Yaniv Rosner0d40f0d2011-06-14 01:34:27 +000010213
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010214/******************************************************************/
Yaniv Rosner52c4d6c2011-07-05 01:06:34 +000010215/* 54618SE PHY SECTION */
Yaniv Rosner6583e332011-06-14 01:34:17 +000010216/******************************************************************/
Yaniv Rosner52c4d6c2011-07-05 01:06:34 +000010217static int bnx2x_54618se_config_init(struct bnx2x_phy *phy,
Yaniv Rosner6583e332011-06-14 01:34:17 +000010218 struct link_params *params,
10219 struct link_vars *vars)
10220{
10221 struct bnx2x *bp = params->bp;
10222 u8 port;
10223 u16 autoneg_val, an_1000_val, an_10_100_val, fc_val, temp;
10224 u32 cfg_pin;
10225
Yaniv Rosner52c4d6c2011-07-05 01:06:34 +000010226 DP(NETIF_MSG_LINK, "54618SE cfg init\n");
Yaniv Rosner6583e332011-06-14 01:34:17 +000010227 usleep_range(1000, 1000);
10228
Yaniv Rosner2f751a82011-11-28 00:49:52 +000010229 /*
10230 * This works with E3 only, no need to check the chip
10231 * before determining the port.
10232 */
Yaniv Rosner6583e332011-06-14 01:34:17 +000010233 port = params->port;
10234
10235 cfg_pin = (REG_RD(bp, params->shmem_base +
10236 offsetof(struct shmem_region,
10237 dev_info.port_hw_config[port].e3_cmn_pin_cfg)) &
10238 PORT_HW_CFG_E3_PHY_RESET_MASK) >>
10239 PORT_HW_CFG_E3_PHY_RESET_SHIFT;
10240
10241 /* Drive pin high to bring the GPHY out of reset. */
10242 bnx2x_set_cfg_pin(bp, cfg_pin, 1);
10243
10244 /* wait for GPHY to reset */
10245 msleep(50);
10246
10247 /* reset phy */
10248 bnx2x_cl22_write(bp, phy,
10249 MDIO_PMA_REG_CTRL, 0x8000);
10250 bnx2x_wait_reset_complete(bp, phy, params);
10251
10252 /*wait for GPHY to reset */
10253 msleep(50);
10254
10255 /* Configure LED4: set to INTR (0x6). */
10256 /* Accessing shadow register 0xe. */
10257 bnx2x_cl22_write(bp, phy,
10258 MDIO_REG_GPHY_SHADOW,
10259 MDIO_REG_GPHY_SHADOW_LED_SEL2);
10260 bnx2x_cl22_read(bp, phy,
10261 MDIO_REG_GPHY_SHADOW,
10262 &temp);
10263 temp &= ~(0xf << 4);
10264 temp |= (0x6 << 4);
10265 bnx2x_cl22_write(bp, phy,
10266 MDIO_REG_GPHY_SHADOW,
10267 MDIO_REG_GPHY_SHADOW_WR_ENA | temp);
10268 /* Configure INTR based on link status change. */
10269 bnx2x_cl22_write(bp, phy,
10270 MDIO_REG_INTR_MASK,
10271 ~MDIO_REG_INTR_MASK_LINK_STATUS);
10272
10273 /* Flip the signal detect polarity (set 0x1c.0x1e[8]). */
10274 bnx2x_cl22_write(bp, phy,
10275 MDIO_REG_GPHY_SHADOW,
10276 MDIO_REG_GPHY_SHADOW_AUTO_DET_MED);
10277 bnx2x_cl22_read(bp, phy,
10278 MDIO_REG_GPHY_SHADOW,
10279 &temp);
10280 temp |= MDIO_REG_GPHY_SHADOW_INVERT_FIB_SD;
10281 bnx2x_cl22_write(bp, phy,
10282 MDIO_REG_GPHY_SHADOW,
10283 MDIO_REG_GPHY_SHADOW_WR_ENA | temp);
10284
10285 /* Set up fc */
10286 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
10287 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
10288 fc_val = 0;
10289 if ((vars->ieee_fc & MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
10290 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC)
10291 fc_val |= MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC;
10292
10293 if ((vars->ieee_fc & MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
10294 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH)
10295 fc_val |= MDIO_AN_REG_ADV_PAUSE_PAUSE;
10296
10297 /* read all advertisement */
10298 bnx2x_cl22_read(bp, phy,
10299 0x09,
10300 &an_1000_val);
10301
10302 bnx2x_cl22_read(bp, phy,
10303 0x04,
10304 &an_10_100_val);
10305
10306 bnx2x_cl22_read(bp, phy,
10307 MDIO_PMA_REG_CTRL,
10308 &autoneg_val);
10309
10310 /* Disable forced speed */
10311 autoneg_val &= ~((1<<6) | (1<<8) | (1<<9) | (1<<12) | (1<<13));
10312 an_10_100_val &= ~((1<<5) | (1<<6) | (1<<7) | (1<<8) | (1<<10) |
10313 (1<<11));
10314
10315 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
10316 (phy->speed_cap_mask &
10317 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) ||
10318 (phy->req_line_speed == SPEED_1000)) {
10319 an_1000_val |= (1<<8);
10320 autoneg_val |= (1<<9 | 1<<12);
10321 if (phy->req_duplex == DUPLEX_FULL)
10322 an_1000_val |= (1<<9);
10323 DP(NETIF_MSG_LINK, "Advertising 1G\n");
10324 } else
10325 an_1000_val &= ~((1<<8) | (1<<9));
10326
10327 bnx2x_cl22_write(bp, phy,
10328 0x09,
10329 an_1000_val);
10330 bnx2x_cl22_read(bp, phy,
10331 0x09,
10332 &an_1000_val);
10333
10334 /* set 100 speed advertisement */
10335 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
10336 (phy->speed_cap_mask &
10337 (PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL |
10338 PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF)))) {
10339 an_10_100_val |= (1<<7);
10340 /* Enable autoneg and restart autoneg for legacy speeds */
10341 autoneg_val |= (1<<9 | 1<<12);
10342
10343 if (phy->req_duplex == DUPLEX_FULL)
10344 an_10_100_val |= (1<<8);
10345 DP(NETIF_MSG_LINK, "Advertising 100M\n");
10346 }
10347
10348 /* set 10 speed advertisement */
10349 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
10350 (phy->speed_cap_mask &
10351 (PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL |
10352 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF)))) {
10353 an_10_100_val |= (1<<5);
10354 autoneg_val |= (1<<9 | 1<<12);
10355 if (phy->req_duplex == DUPLEX_FULL)
10356 an_10_100_val |= (1<<6);
10357 DP(NETIF_MSG_LINK, "Advertising 10M\n");
10358 }
10359
10360 /* Only 10/100 are allowed to work in FORCE mode */
10361 if (phy->req_line_speed == SPEED_100) {
10362 autoneg_val |= (1<<13);
10363 /* Enabled AUTO-MDIX when autoneg is disabled */
10364 bnx2x_cl22_write(bp, phy,
10365 0x18,
10366 (1<<15 | 1<<9 | 7<<0));
10367 DP(NETIF_MSG_LINK, "Setting 100M force\n");
10368 }
10369 if (phy->req_line_speed == SPEED_10) {
10370 /* Enabled AUTO-MDIX when autoneg is disabled */
10371 bnx2x_cl22_write(bp, phy,
10372 0x18,
10373 (1<<15 | 1<<9 | 7<<0));
10374 DP(NETIF_MSG_LINK, "Setting 10M force\n");
10375 }
10376
Yaniv Rosnera89a1d42011-07-05 01:07:05 +000010377 /* Check if we should turn on Auto-GrEEEn */
10378 bnx2x_cl22_read(bp, phy, MDIO_REG_GPHY_PHYID_LSB, &temp);
10379 if (temp == MDIO_REG_GPHY_ID_54618SE) {
10380 if (params->feature_config_flags &
10381 FEATURE_CONFIG_AUTOGREEEN_ENABLED) {
10382 temp = 6;
10383 DP(NETIF_MSG_LINK, "Enabling Auto-GrEEEn\n");
10384 } else {
10385 temp = 0;
10386 DP(NETIF_MSG_LINK, "Disabling Auto-GrEEEn\n");
10387 }
10388 bnx2x_cl22_write(bp, phy,
10389 MDIO_REG_GPHY_CL45_ADDR_REG, MDIO_AN_DEVAD);
10390 bnx2x_cl22_write(bp, phy,
10391 MDIO_REG_GPHY_CL45_DATA_REG,
10392 MDIO_REG_GPHY_EEE_ADV);
10393 bnx2x_cl22_write(bp, phy,
10394 MDIO_REG_GPHY_CL45_ADDR_REG,
10395 (0x1 << 14) | MDIO_AN_DEVAD);
10396 bnx2x_cl22_write(bp, phy,
10397 MDIO_REG_GPHY_CL45_DATA_REG,
10398 temp);
10399 }
10400
Yaniv Rosner6583e332011-06-14 01:34:17 +000010401 bnx2x_cl22_write(bp, phy,
10402 0x04,
10403 an_10_100_val | fc_val);
10404
10405 if (phy->req_duplex == DUPLEX_FULL)
10406 autoneg_val |= (1<<8);
10407
10408 bnx2x_cl22_write(bp, phy,
10409 MDIO_PMA_REG_CTRL, autoneg_val);
10410
10411 return 0;
10412}
10413
Yaniv Rosner1d125bd2011-11-23 03:54:08 +000010414
10415static void bnx2x_5461x_set_link_led(struct bnx2x_phy *phy,
10416 struct link_params *params, u8 mode)
10417{
10418 struct bnx2x *bp = params->bp;
10419 u16 temp;
10420
10421 bnx2x_cl22_write(bp, phy,
10422 MDIO_REG_GPHY_SHADOW,
10423 MDIO_REG_GPHY_SHADOW_LED_SEL1);
10424 bnx2x_cl22_read(bp, phy,
10425 MDIO_REG_GPHY_SHADOW,
10426 &temp);
10427 temp &= 0xff00;
10428
10429 DP(NETIF_MSG_LINK, "54618x set link led (mode=%x)\n", mode);
10430 switch (mode) {
10431 case LED_MODE_FRONT_PANEL_OFF:
10432 case LED_MODE_OFF:
10433 temp |= 0x00ee;
10434 break;
10435 case LED_MODE_OPER:
10436 temp |= 0x0001;
10437 break;
10438 case LED_MODE_ON:
10439 temp |= 0x00ff;
10440 break;
10441 default:
10442 break;
10443 }
10444 bnx2x_cl22_write(bp, phy,
10445 MDIO_REG_GPHY_SHADOW,
10446 MDIO_REG_GPHY_SHADOW_WR_ENA | temp);
10447 return;
10448}
10449
10450
Yaniv Rosner52c4d6c2011-07-05 01:06:34 +000010451static void bnx2x_54618se_link_reset(struct bnx2x_phy *phy,
10452 struct link_params *params)
Yaniv Rosner6583e332011-06-14 01:34:17 +000010453{
10454 struct bnx2x *bp = params->bp;
10455 u32 cfg_pin;
10456 u8 port;
10457
Yaniv Rosnerd2059a02011-08-02 23:00:00 +000010458 /*
10459 * In case of no EPIO routed to reset the GPHY, put it
10460 * in low power mode.
10461 */
10462 bnx2x_cl22_write(bp, phy, MDIO_PMA_REG_CTRL, 0x800);
10463 /*
10464 * This works with E3 only, no need to check the chip
10465 * before determining the port.
10466 */
Yaniv Rosner6583e332011-06-14 01:34:17 +000010467 port = params->port;
10468 cfg_pin = (REG_RD(bp, params->shmem_base +
10469 offsetof(struct shmem_region,
10470 dev_info.port_hw_config[port].e3_cmn_pin_cfg)) &
10471 PORT_HW_CFG_E3_PHY_RESET_MASK) >>
10472 PORT_HW_CFG_E3_PHY_RESET_SHIFT;
10473
10474 /* Drive pin low to put GPHY in reset. */
10475 bnx2x_set_cfg_pin(bp, cfg_pin, 0);
10476}
10477
Yaniv Rosner52c4d6c2011-07-05 01:06:34 +000010478static u8 bnx2x_54618se_read_status(struct bnx2x_phy *phy,
10479 struct link_params *params,
10480 struct link_vars *vars)
Yaniv Rosner6583e332011-06-14 01:34:17 +000010481{
10482 struct bnx2x *bp = params->bp;
10483 u16 val;
10484 u8 link_up = 0;
10485 u16 legacy_status, legacy_speed;
10486
10487 /* Get speed operation status */
10488 bnx2x_cl22_read(bp, phy,
10489 0x19,
10490 &legacy_status);
Yaniv Rosner52c4d6c2011-07-05 01:06:34 +000010491 DP(NETIF_MSG_LINK, "54618SE read_status: 0x%x\n", legacy_status);
Yaniv Rosner6583e332011-06-14 01:34:17 +000010492
10493 /* Read status to clear the PHY interrupt. */
10494 bnx2x_cl22_read(bp, phy,
10495 MDIO_REG_INTR_STATUS,
10496 &val);
10497
10498 link_up = ((legacy_status & (1<<2)) == (1<<2));
10499
10500 if (link_up) {
10501 legacy_speed = (legacy_status & (7<<8));
10502 if (legacy_speed == (7<<8)) {
10503 vars->line_speed = SPEED_1000;
10504 vars->duplex = DUPLEX_FULL;
10505 } else if (legacy_speed == (6<<8)) {
10506 vars->line_speed = SPEED_1000;
10507 vars->duplex = DUPLEX_HALF;
10508 } else if (legacy_speed == (5<<8)) {
10509 vars->line_speed = SPEED_100;
10510 vars->duplex = DUPLEX_FULL;
10511 }
10512 /* Omitting 100Base-T4 for now */
10513 else if (legacy_speed == (3<<8)) {
10514 vars->line_speed = SPEED_100;
10515 vars->duplex = DUPLEX_HALF;
10516 } else if (legacy_speed == (2<<8)) {
10517 vars->line_speed = SPEED_10;
10518 vars->duplex = DUPLEX_FULL;
10519 } else if (legacy_speed == (1<<8)) {
10520 vars->line_speed = SPEED_10;
10521 vars->duplex = DUPLEX_HALF;
10522 } else /* Should not happen */
10523 vars->line_speed = 0;
10524
Joe Perches94f05b02011-08-14 12:16:20 +000010525 DP(NETIF_MSG_LINK,
10526 "Link is up in %dMbps, is_duplex_full= %d\n",
10527 vars->line_speed,
10528 (vars->duplex == DUPLEX_FULL));
Yaniv Rosner6583e332011-06-14 01:34:17 +000010529
10530 /* Check legacy speed AN resolution */
10531 bnx2x_cl22_read(bp, phy,
10532 0x01,
10533 &val);
10534 if (val & (1<<5))
10535 vars->link_status |=
10536 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
10537 bnx2x_cl22_read(bp, phy,
10538 0x06,
10539 &val);
10540 if ((val & (1<<0)) == 0)
10541 vars->link_status |=
10542 LINK_STATUS_PARALLEL_DETECTION_USED;
10543
Yaniv Rosner52c4d6c2011-07-05 01:06:34 +000010544 DP(NETIF_MSG_LINK, "BCM54618SE: link speed is %d\n",
Yaniv Rosner6583e332011-06-14 01:34:17 +000010545 vars->line_speed);
Yaniv Rosner52c4d6c2011-07-05 01:06:34 +000010546
10547 /* Report whether EEE is resolved. */
10548 bnx2x_cl22_read(bp, phy, MDIO_REG_GPHY_PHYID_LSB, &val);
10549 if (val == MDIO_REG_GPHY_ID_54618SE) {
10550 if (vars->link_status &
10551 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE)
10552 val = 0;
10553 else {
10554 bnx2x_cl22_write(bp, phy,
10555 MDIO_REG_GPHY_CL45_ADDR_REG,
10556 MDIO_AN_DEVAD);
10557 bnx2x_cl22_write(bp, phy,
10558 MDIO_REG_GPHY_CL45_DATA_REG,
10559 MDIO_REG_GPHY_EEE_RESOLVED);
10560 bnx2x_cl22_write(bp, phy,
10561 MDIO_REG_GPHY_CL45_ADDR_REG,
10562 (0x1 << 14) | MDIO_AN_DEVAD);
10563 bnx2x_cl22_read(bp, phy,
10564 MDIO_REG_GPHY_CL45_DATA_REG,
10565 &val);
10566 }
10567 DP(NETIF_MSG_LINK, "EEE resolution: 0x%x\n", val);
10568 }
10569
Yaniv Rosner6583e332011-06-14 01:34:17 +000010570 bnx2x_ext_phy_resolve_fc(phy, params, vars);
10571 }
10572 return link_up;
10573}
10574
Yaniv Rosner52c4d6c2011-07-05 01:06:34 +000010575static void bnx2x_54618se_config_loopback(struct bnx2x_phy *phy,
10576 struct link_params *params)
Yaniv Rosner6583e332011-06-14 01:34:17 +000010577{
10578 struct bnx2x *bp = params->bp;
10579 u16 val;
10580 u32 umac_base = params->port ? GRCBASE_UMAC1 : GRCBASE_UMAC0;
10581
Yaniv Rosner52c4d6c2011-07-05 01:06:34 +000010582 DP(NETIF_MSG_LINK, "2PMA/PMD ext_phy_loopback: 54618se\n");
Yaniv Rosner6583e332011-06-14 01:34:17 +000010583
10584 /* Enable master/slave manual mmode and set to master */
10585 /* mii write 9 [bits set 11 12] */
10586 bnx2x_cl22_write(bp, phy, 0x09, 3<<11);
10587
10588 /* forced 1G and disable autoneg */
10589 /* set val [mii read 0] */
10590 /* set val [expr $val & [bits clear 6 12 13]] */
10591 /* set val [expr $val | [bits set 6 8]] */
10592 /* mii write 0 $val */
10593 bnx2x_cl22_read(bp, phy, 0x00, &val);
10594 val &= ~((1<<6) | (1<<12) | (1<<13));
10595 val |= (1<<6) | (1<<8);
10596 bnx2x_cl22_write(bp, phy, 0x00, val);
10597
10598 /* Set external loopback and Tx using 6dB coding */
10599 /* mii write 0x18 7 */
10600 /* set val [mii read 0x18] */
10601 /* mii write 0x18 [expr $val | [bits set 10 15]] */
10602 bnx2x_cl22_write(bp, phy, 0x18, 7);
10603 bnx2x_cl22_read(bp, phy, 0x18, &val);
10604 bnx2x_cl22_write(bp, phy, 0x18, val | (1<<10) | (1<<15));
10605
10606 /* This register opens the gate for the UMAC despite its name */
10607 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + params->port*4, 1);
10608
10609 /*
10610 * Maximum Frame Length (RW). Defines a 14-Bit maximum frame
10611 * length used by the MAC receive logic to check frames.
10612 */
10613 REG_WR(bp, umac_base + UMAC_REG_MAXFR, 0x2710);
10614}
10615
10616/******************************************************************/
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010617/* SFX7101 PHY SECTION */
10618/******************************************************************/
10619static void bnx2x_7101_config_loopback(struct bnx2x_phy *phy,
10620 struct link_params *params)
10621{
10622 struct bnx2x *bp = params->bp;
10623 /* SFX7101_XGXS_TEST1 */
10624 bnx2x_cl45_write(bp, phy,
10625 MDIO_XS_DEVAD, MDIO_XS_SFX7101_XGXS_TEST1, 0x100);
10626}
10627
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +000010628static int bnx2x_7101_config_init(struct bnx2x_phy *phy,
10629 struct link_params *params,
10630 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010631{
10632 u16 fw_ver1, fw_ver2, val;
10633 struct bnx2x *bp = params->bp;
10634 DP(NETIF_MSG_LINK, "Setting the SFX7101 LASI indication\n");
10635
10636 /* Restore normal power mode*/
10637 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010638 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010639 /* HW reset */
10640 bnx2x_ext_phy_hw_reset(bp, params->port);
Yaniv Rosner6d870c32011-01-31 04:22:20 +000010641 bnx2x_wait_reset_complete(bp, phy, params);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010642
10643 bnx2x_cl45_write(bp, phy,
Yaniv Rosner60d2fe02011-06-14 01:34:38 +000010644 MDIO_PMA_DEVAD, MDIO_PMA_LASI_CTRL, 0x1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010645 DP(NETIF_MSG_LINK, "Setting the SFX7101 LED to blink on traffic\n");
10646 bnx2x_cl45_write(bp, phy,
10647 MDIO_PMA_DEVAD, MDIO_PMA_REG_7107_LED_CNTL, (1<<3));
10648
10649 bnx2x_ext_phy_set_pause(params, phy, vars);
10650 /* Restart autoneg */
10651 bnx2x_cl45_read(bp, phy,
10652 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, &val);
10653 val |= 0x200;
10654 bnx2x_cl45_write(bp, phy,
10655 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, val);
10656
10657 /* Save spirom version */
10658 bnx2x_cl45_read(bp, phy,
10659 MDIO_PMA_DEVAD, MDIO_PMA_REG_7101_VER1, &fw_ver1);
10660
10661 bnx2x_cl45_read(bp, phy,
10662 MDIO_PMA_DEVAD, MDIO_PMA_REG_7101_VER2, &fw_ver2);
10663 bnx2x_save_spirom_version(bp, params->port,
10664 (u32)(fw_ver1<<16 | fw_ver2), phy->ver_addr);
10665 return 0;
10666}
10667
10668static u8 bnx2x_7101_read_status(struct bnx2x_phy *phy,
10669 struct link_params *params,
10670 struct link_vars *vars)
10671{
10672 struct bnx2x *bp = params->bp;
10673 u8 link_up;
10674 u16 val1, val2;
10675 bnx2x_cl45_read(bp, phy,
Yaniv Rosner60d2fe02011-06-14 01:34:38 +000010676 MDIO_PMA_DEVAD, MDIO_PMA_LASI_STAT, &val2);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010677 bnx2x_cl45_read(bp, phy,
Yaniv Rosner60d2fe02011-06-14 01:34:38 +000010678 MDIO_PMA_DEVAD, MDIO_PMA_LASI_STAT, &val1);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010679 DP(NETIF_MSG_LINK, "10G-base-T LASI status 0x%x->0x%x\n",
10680 val2, val1);
10681 bnx2x_cl45_read(bp, phy,
10682 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
10683 bnx2x_cl45_read(bp, phy,
10684 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
10685 DP(NETIF_MSG_LINK, "10G-base-T PMA status 0x%x->0x%x\n",
10686 val2, val1);
10687 link_up = ((val1 & 4) == 4);
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +000010688 /* if link is up print the AN outcome of the SFX7101 PHY */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010689 if (link_up) {
10690 bnx2x_cl45_read(bp, phy,
10691 MDIO_AN_DEVAD, MDIO_AN_REG_MASTER_STATUS,
10692 &val2);
10693 vars->line_speed = SPEED_10000;
Yaniv Rosner791f18c2011-01-18 04:33:42 +000010694 vars->duplex = DUPLEX_FULL;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010695 DP(NETIF_MSG_LINK, "SFX7101 AN status 0x%x->Master=%x\n",
10696 val2, (val2 & (1<<14)));
10697 bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
10698 bnx2x_ext_phy_resolve_fc(phy, params, vars);
10699 }
10700 return link_up;
10701}
10702
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +000010703static int bnx2x_7101_format_ver(u32 spirom_ver, u8 *str, u16 *len)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010704{
10705 if (*len < 5)
10706 return -EINVAL;
10707 str[0] = (spirom_ver & 0xFF);
10708 str[1] = (spirom_ver & 0xFF00) >> 8;
10709 str[2] = (spirom_ver & 0xFF0000) >> 16;
10710 str[3] = (spirom_ver & 0xFF000000) >> 24;
10711 str[4] = '\0';
10712 *len -= 5;
10713 return 0;
10714}
10715
10716void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, struct bnx2x_phy *phy)
10717{
10718 u16 val, cnt;
10719
10720 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010721 MDIO_PMA_DEVAD,
10722 MDIO_PMA_REG_7101_RESET, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010723
10724 for (cnt = 0; cnt < 10; cnt++) {
10725 msleep(50);
10726 /* Writes a self-clearing reset */
10727 bnx2x_cl45_write(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010728 MDIO_PMA_DEVAD,
10729 MDIO_PMA_REG_7101_RESET,
10730 (val | (1<<15)));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010731 /* Wait for clear */
10732 bnx2x_cl45_read(bp, phy,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010733 MDIO_PMA_DEVAD,
10734 MDIO_PMA_REG_7101_RESET, &val);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010735
10736 if ((val & (1<<15)) == 0)
10737 break;
10738 }
10739}
10740
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010741static void bnx2x_7101_hw_reset(struct bnx2x_phy *phy,
10742 struct link_params *params) {
10743 /* Low power mode is controlled by GPIO 2 */
10744 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010745 MISC_REGISTERS_GPIO_OUTPUT_LOW, params->port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010746 /* The PHY reset is controlled by GPIO 1 */
10747 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010748 MISC_REGISTERS_GPIO_OUTPUT_LOW, params->port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010749}
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000010750
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +000010751static void bnx2x_7101_set_link_led(struct bnx2x_phy *phy,
10752 struct link_params *params, u8 mode)
10753{
10754 u16 val = 0;
10755 struct bnx2x *bp = params->bp;
10756 switch (mode) {
10757 case LED_MODE_FRONT_PANEL_OFF:
10758 case LED_MODE_OFF:
10759 val = 2;
10760 break;
10761 case LED_MODE_ON:
10762 val = 1;
10763 break;
10764 case LED_MODE_OPER:
10765 val = 0;
10766 break;
10767 }
10768 bnx2x_cl45_write(bp, phy,
10769 MDIO_PMA_DEVAD,
10770 MDIO_PMA_REG_7107_LINK_LED_CNTL,
10771 val);
10772}
10773
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010774/******************************************************************/
10775/* STATIC PHY DECLARATION */
10776/******************************************************************/
10777
10778static struct bnx2x_phy phy_null = {
10779 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN,
10780 .addr = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010781 .def_md_devad = 0,
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000010782 .flags = FLAGS_INIT_XGXS_FIRST,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010783 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10784 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10785 .mdio_ctrl = 0,
10786 .supported = 0,
10787 .media_type = ETH_PHY_NOT_PRESENT,
10788 .ver_addr = 0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010789 .req_flow_ctrl = 0,
10790 .req_line_speed = 0,
10791 .speed_cap_mask = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010792 .req_duplex = 0,
10793 .rsrv = 0,
10794 .config_init = (config_init_t)NULL,
10795 .read_status = (read_status_t)NULL,
10796 .link_reset = (link_reset_t)NULL,
10797 .config_loopback = (config_loopback_t)NULL,
10798 .format_fw_ver = (format_fw_ver_t)NULL,
10799 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010800 .set_link_led = (set_link_led_t)NULL,
10801 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010802};
10803
10804static struct bnx2x_phy phy_serdes = {
10805 .type = PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT,
10806 .addr = 0xff,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010807 .def_md_devad = 0,
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000010808 .flags = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010809 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10810 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10811 .mdio_ctrl = 0,
10812 .supported = (SUPPORTED_10baseT_Half |
10813 SUPPORTED_10baseT_Full |
10814 SUPPORTED_100baseT_Half |
10815 SUPPORTED_100baseT_Full |
10816 SUPPORTED_1000baseT_Full |
10817 SUPPORTED_2500baseX_Full |
10818 SUPPORTED_TP |
10819 SUPPORTED_Autoneg |
10820 SUPPORTED_Pause |
10821 SUPPORTED_Asym_Pause),
Yaniv Rosner1ac9e422011-05-31 21:26:11 +000010822 .media_type = ETH_PHY_BASE_T,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010823 .ver_addr = 0,
10824 .req_flow_ctrl = 0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010825 .req_line_speed = 0,
10826 .speed_cap_mask = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010827 .req_duplex = 0,
10828 .rsrv = 0,
Yaniv Rosnerec146a62011-05-31 21:29:27 +000010829 .config_init = (config_init_t)bnx2x_xgxs_config_init,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010830 .read_status = (read_status_t)bnx2x_link_settings_status,
10831 .link_reset = (link_reset_t)bnx2x_int_link_reset,
10832 .config_loopback = (config_loopback_t)NULL,
10833 .format_fw_ver = (format_fw_ver_t)NULL,
10834 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010835 .set_link_led = (set_link_led_t)NULL,
10836 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010837};
10838
10839static struct bnx2x_phy phy_xgxs = {
10840 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT,
10841 .addr = 0xff,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010842 .def_md_devad = 0,
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000010843 .flags = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010844 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10845 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10846 .mdio_ctrl = 0,
10847 .supported = (SUPPORTED_10baseT_Half |
10848 SUPPORTED_10baseT_Full |
10849 SUPPORTED_100baseT_Half |
10850 SUPPORTED_100baseT_Full |
10851 SUPPORTED_1000baseT_Full |
10852 SUPPORTED_2500baseX_Full |
10853 SUPPORTED_10000baseT_Full |
10854 SUPPORTED_FIBRE |
10855 SUPPORTED_Autoneg |
10856 SUPPORTED_Pause |
10857 SUPPORTED_Asym_Pause),
Yaniv Rosner1ac9e422011-05-31 21:26:11 +000010858 .media_type = ETH_PHY_CX4,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010859 .ver_addr = 0,
10860 .req_flow_ctrl = 0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010861 .req_line_speed = 0,
10862 .speed_cap_mask = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010863 .req_duplex = 0,
10864 .rsrv = 0,
Yaniv Rosnerec146a62011-05-31 21:29:27 +000010865 .config_init = (config_init_t)bnx2x_xgxs_config_init,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010866 .read_status = (read_status_t)bnx2x_link_settings_status,
10867 .link_reset = (link_reset_t)bnx2x_int_link_reset,
10868 .config_loopback = (config_loopback_t)bnx2x_set_xgxs_loopback,
10869 .format_fw_ver = (format_fw_ver_t)NULL,
10870 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010871 .set_link_led = (set_link_led_t)NULL,
10872 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010873};
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000010874static struct bnx2x_phy phy_warpcore = {
10875 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT,
10876 .addr = 0xff,
10877 .def_md_devad = 0,
David S. Miller8decf862011-09-22 03:23:13 -040010878 .flags = FLAGS_HW_LOCK_REQUIRED,
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000010879 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10880 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10881 .mdio_ctrl = 0,
10882 .supported = (SUPPORTED_10baseT_Half |
10883 SUPPORTED_10baseT_Full |
10884 SUPPORTED_100baseT_Half |
10885 SUPPORTED_100baseT_Full |
10886 SUPPORTED_1000baseT_Full |
10887 SUPPORTED_10000baseT_Full |
10888 SUPPORTED_20000baseKR2_Full |
10889 SUPPORTED_20000baseMLD2_Full |
10890 SUPPORTED_FIBRE |
10891 SUPPORTED_Autoneg |
10892 SUPPORTED_Pause |
10893 SUPPORTED_Asym_Pause),
10894 .media_type = ETH_PHY_UNSPECIFIED,
10895 .ver_addr = 0,
10896 .req_flow_ctrl = 0,
10897 .req_line_speed = 0,
10898 .speed_cap_mask = 0,
10899 /* req_duplex = */0,
10900 /* rsrv = */0,
10901 .config_init = (config_init_t)bnx2x_warpcore_config_init,
10902 .read_status = (read_status_t)bnx2x_warpcore_read_status,
10903 .link_reset = (link_reset_t)bnx2x_warpcore_link_reset,
10904 .config_loopback = (config_loopback_t)bnx2x_set_warpcore_loopback,
10905 .format_fw_ver = (format_fw_ver_t)NULL,
Yaniv Rosner985848f2011-07-05 01:06:48 +000010906 .hw_reset = (hw_reset_t)bnx2x_warpcore_hw_reset,
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000010907 .set_link_led = (set_link_led_t)NULL,
10908 .phy_specific_func = (phy_specific_func_t)NULL
10909};
10910
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010911
10912static struct bnx2x_phy phy_7101 = {
10913 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
10914 .addr = 0xff,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010915 .def_md_devad = 0,
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000010916 .flags = FLAGS_FAN_FAILURE_DET_REQ,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010917 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10918 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10919 .mdio_ctrl = 0,
10920 .supported = (SUPPORTED_10000baseT_Full |
10921 SUPPORTED_TP |
10922 SUPPORTED_Autoneg |
10923 SUPPORTED_Pause |
10924 SUPPORTED_Asym_Pause),
10925 .media_type = ETH_PHY_BASE_T,
10926 .ver_addr = 0,
10927 .req_flow_ctrl = 0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010928 .req_line_speed = 0,
10929 .speed_cap_mask = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010930 .req_duplex = 0,
10931 .rsrv = 0,
10932 .config_init = (config_init_t)bnx2x_7101_config_init,
10933 .read_status = (read_status_t)bnx2x_7101_read_status,
10934 .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
10935 .config_loopback = (config_loopback_t)bnx2x_7101_config_loopback,
10936 .format_fw_ver = (format_fw_ver_t)bnx2x_7101_format_ver,
10937 .hw_reset = (hw_reset_t)bnx2x_7101_hw_reset,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +000010938 .set_link_led = (set_link_led_t)bnx2x_7101_set_link_led,
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010939 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010940};
10941static struct bnx2x_phy phy_8073 = {
10942 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
10943 .addr = 0xff,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010944 .def_md_devad = 0,
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000010945 .flags = FLAGS_HW_LOCK_REQUIRED,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010946 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10947 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10948 .mdio_ctrl = 0,
10949 .supported = (SUPPORTED_10000baseT_Full |
10950 SUPPORTED_2500baseX_Full |
10951 SUPPORTED_1000baseT_Full |
10952 SUPPORTED_FIBRE |
10953 SUPPORTED_Autoneg |
10954 SUPPORTED_Pause |
10955 SUPPORTED_Asym_Pause),
Yaniv Rosner1ac9e422011-05-31 21:26:11 +000010956 .media_type = ETH_PHY_KR,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010957 .ver_addr = 0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000010958 .req_flow_ctrl = 0,
10959 .req_line_speed = 0,
10960 .speed_cap_mask = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010961 .req_duplex = 0,
10962 .rsrv = 0,
Yaniv Rosner62b29a52010-09-07 11:40:58 +000010963 .config_init = (config_init_t)bnx2x_8073_config_init,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010964 .read_status = (read_status_t)bnx2x_8073_read_status,
10965 .link_reset = (link_reset_t)bnx2x_8073_link_reset,
10966 .config_loopback = (config_loopback_t)NULL,
10967 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
10968 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010969 .set_link_led = (set_link_led_t)NULL,
10970 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010971};
10972static struct bnx2x_phy phy_8705 = {
10973 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705,
10974 .addr = 0xff,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010975 .def_md_devad = 0,
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000010976 .flags = FLAGS_INIT_XGXS_FIRST,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010977 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10978 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
10979 .mdio_ctrl = 0,
10980 .supported = (SUPPORTED_10000baseT_Full |
10981 SUPPORTED_FIBRE |
10982 SUPPORTED_Pause |
10983 SUPPORTED_Asym_Pause),
10984 .media_type = ETH_PHY_XFP_FIBER,
10985 .ver_addr = 0,
10986 .req_flow_ctrl = 0,
10987 .req_line_speed = 0,
10988 .speed_cap_mask = 0,
10989 .req_duplex = 0,
10990 .rsrv = 0,
10991 .config_init = (config_init_t)bnx2x_8705_config_init,
10992 .read_status = (read_status_t)bnx2x_8705_read_status,
10993 .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
10994 .config_loopback = (config_loopback_t)NULL,
10995 .format_fw_ver = (format_fw_ver_t)bnx2x_null_format_ver,
10996 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +000010997 .set_link_led = (set_link_led_t)NULL,
10998 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000010999};
11000static struct bnx2x_phy phy_8706 = {
11001 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706,
11002 .addr = 0xff,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011003 .def_md_devad = 0,
David S. Miller8decf862011-09-22 03:23:13 -040011004 .flags = FLAGS_INIT_XGXS_FIRST,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011005 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
11006 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
11007 .mdio_ctrl = 0,
11008 .supported = (SUPPORTED_10000baseT_Full |
11009 SUPPORTED_1000baseT_Full |
11010 SUPPORTED_FIBRE |
11011 SUPPORTED_Pause |
11012 SUPPORTED_Asym_Pause),
11013 .media_type = ETH_PHY_SFP_FIBER,
11014 .ver_addr = 0,
11015 .req_flow_ctrl = 0,
11016 .req_line_speed = 0,
11017 .speed_cap_mask = 0,
11018 .req_duplex = 0,
11019 .rsrv = 0,
11020 .config_init = (config_init_t)bnx2x_8706_config_init,
11021 .read_status = (read_status_t)bnx2x_8706_read_status,
11022 .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
11023 .config_loopback = (config_loopback_t)NULL,
11024 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
11025 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011026 .set_link_led = (set_link_led_t)NULL,
11027 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011028};
11029
11030static struct bnx2x_phy phy_8726 = {
11031 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
11032 .addr = 0xff,
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000011033 .def_md_devad = 0,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011034 .flags = (FLAGS_HW_LOCK_REQUIRED |
David S. Miller8decf862011-09-22 03:23:13 -040011035 FLAGS_INIT_XGXS_FIRST),
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011036 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
11037 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
11038 .mdio_ctrl = 0,
11039 .supported = (SUPPORTED_10000baseT_Full |
11040 SUPPORTED_1000baseT_Full |
11041 SUPPORTED_Autoneg |
11042 SUPPORTED_FIBRE |
11043 SUPPORTED_Pause |
11044 SUPPORTED_Asym_Pause),
Yaniv Rosner1ac9e422011-05-31 21:26:11 +000011045 .media_type = ETH_PHY_NOT_PRESENT,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011046 .ver_addr = 0,
11047 .req_flow_ctrl = 0,
11048 .req_line_speed = 0,
11049 .speed_cap_mask = 0,
11050 .req_duplex = 0,
11051 .rsrv = 0,
11052 .config_init = (config_init_t)bnx2x_8726_config_init,
11053 .read_status = (read_status_t)bnx2x_8726_read_status,
11054 .link_reset = (link_reset_t)bnx2x_8726_link_reset,
11055 .config_loopback = (config_loopback_t)bnx2x_8726_config_loopback,
11056 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
11057 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011058 .set_link_led = (set_link_led_t)NULL,
11059 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011060};
11061
11062static struct bnx2x_phy phy_8727 = {
11063 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
11064 .addr = 0xff,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011065 .def_md_devad = 0,
David S. Miller8decf862011-09-22 03:23:13 -040011066 .flags = FLAGS_FAN_FAILURE_DET_REQ,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011067 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
11068 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
11069 .mdio_ctrl = 0,
11070 .supported = (SUPPORTED_10000baseT_Full |
11071 SUPPORTED_1000baseT_Full |
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011072 SUPPORTED_FIBRE |
11073 SUPPORTED_Pause |
11074 SUPPORTED_Asym_Pause),
Yaniv Rosner1ac9e422011-05-31 21:26:11 +000011075 .media_type = ETH_PHY_NOT_PRESENT,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011076 .ver_addr = 0,
11077 .req_flow_ctrl = 0,
11078 .req_line_speed = 0,
11079 .speed_cap_mask = 0,
11080 .req_duplex = 0,
11081 .rsrv = 0,
11082 .config_init = (config_init_t)bnx2x_8727_config_init,
11083 .read_status = (read_status_t)bnx2x_8727_read_status,
11084 .link_reset = (link_reset_t)bnx2x_8727_link_reset,
11085 .config_loopback = (config_loopback_t)NULL,
11086 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
11087 .hw_reset = (hw_reset_t)bnx2x_8727_hw_reset,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +000011088 .set_link_led = (set_link_led_t)bnx2x_8727_set_link_led,
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011089 .phy_specific_func = (phy_specific_func_t)bnx2x_8727_specific_func
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011090};
11091static struct bnx2x_phy phy_8481 = {
11092 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
11093 .addr = 0xff,
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000011094 .def_md_devad = 0,
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011095 .flags = FLAGS_FAN_FAILURE_DET_REQ |
11096 FLAGS_REARM_LATCH_SIGNAL,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011097 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
11098 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
11099 .mdio_ctrl = 0,
11100 .supported = (SUPPORTED_10baseT_Half |
11101 SUPPORTED_10baseT_Full |
11102 SUPPORTED_100baseT_Half |
11103 SUPPORTED_100baseT_Full |
11104 SUPPORTED_1000baseT_Full |
11105 SUPPORTED_10000baseT_Full |
11106 SUPPORTED_TP |
11107 SUPPORTED_Autoneg |
11108 SUPPORTED_Pause |
11109 SUPPORTED_Asym_Pause),
11110 .media_type = ETH_PHY_BASE_T,
11111 .ver_addr = 0,
11112 .req_flow_ctrl = 0,
11113 .req_line_speed = 0,
11114 .speed_cap_mask = 0,
11115 .req_duplex = 0,
11116 .rsrv = 0,
11117 .config_init = (config_init_t)bnx2x_8481_config_init,
11118 .read_status = (read_status_t)bnx2x_848xx_read_status,
11119 .link_reset = (link_reset_t)bnx2x_8481_link_reset,
11120 .config_loopback = (config_loopback_t)NULL,
11121 .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver,
11122 .hw_reset = (hw_reset_t)bnx2x_8481_hw_reset,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +000011123 .set_link_led = (set_link_led_t)bnx2x_848xx_set_link_led,
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011124 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011125};
11126
11127static struct bnx2x_phy phy_84823 = {
11128 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823,
11129 .addr = 0xff,
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000011130 .def_md_devad = 0,
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011131 .flags = FLAGS_FAN_FAILURE_DET_REQ |
11132 FLAGS_REARM_LATCH_SIGNAL,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011133 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
11134 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
11135 .mdio_ctrl = 0,
11136 .supported = (SUPPORTED_10baseT_Half |
11137 SUPPORTED_10baseT_Full |
11138 SUPPORTED_100baseT_Half |
11139 SUPPORTED_100baseT_Full |
11140 SUPPORTED_1000baseT_Full |
11141 SUPPORTED_10000baseT_Full |
11142 SUPPORTED_TP |
11143 SUPPORTED_Autoneg |
11144 SUPPORTED_Pause |
11145 SUPPORTED_Asym_Pause),
11146 .media_type = ETH_PHY_BASE_T,
11147 .ver_addr = 0,
11148 .req_flow_ctrl = 0,
11149 .req_line_speed = 0,
11150 .speed_cap_mask = 0,
11151 .req_duplex = 0,
11152 .rsrv = 0,
11153 .config_init = (config_init_t)bnx2x_848x3_config_init,
11154 .read_status = (read_status_t)bnx2x_848xx_read_status,
11155 .link_reset = (link_reset_t)bnx2x_848x3_link_reset,
11156 .config_loopback = (config_loopback_t)NULL,
11157 .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver,
11158 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +000011159 .set_link_led = (set_link_led_t)bnx2x_848xx_set_link_led,
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011160 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011161};
11162
Yaniv Rosnerc87bca12011-01-31 04:22:41 +000011163static struct bnx2x_phy phy_84833 = {
11164 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833,
11165 .addr = 0xff,
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000011166 .def_md_devad = 0,
Yaniv Rosnerc87bca12011-01-31 04:22:41 +000011167 .flags = FLAGS_FAN_FAILURE_DET_REQ |
11168 FLAGS_REARM_LATCH_SIGNAL,
Yaniv Rosnerc87bca12011-01-31 04:22:41 +000011169 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
11170 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
11171 .mdio_ctrl = 0,
Yaniv Rosner0520e632011-07-05 01:06:59 +000011172 .supported = (SUPPORTED_100baseT_Half |
Yaniv Rosnerc87bca12011-01-31 04:22:41 +000011173 SUPPORTED_100baseT_Full |
11174 SUPPORTED_1000baseT_Full |
11175 SUPPORTED_10000baseT_Full |
11176 SUPPORTED_TP |
11177 SUPPORTED_Autoneg |
11178 SUPPORTED_Pause |
11179 SUPPORTED_Asym_Pause),
11180 .media_type = ETH_PHY_BASE_T,
11181 .ver_addr = 0,
11182 .req_flow_ctrl = 0,
11183 .req_line_speed = 0,
11184 .speed_cap_mask = 0,
11185 .req_duplex = 0,
11186 .rsrv = 0,
11187 .config_init = (config_init_t)bnx2x_848x3_config_init,
11188 .read_status = (read_status_t)bnx2x_848xx_read_status,
11189 .link_reset = (link_reset_t)bnx2x_848x3_link_reset,
11190 .config_loopback = (config_loopback_t)NULL,
11191 .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver,
Yaniv Rosner985848f2011-07-05 01:06:48 +000011192 .hw_reset = (hw_reset_t)bnx2x_84833_hw_reset_phy,
Yaniv Rosnerc87bca12011-01-31 04:22:41 +000011193 .set_link_led = (set_link_led_t)bnx2x_848xx_set_link_led,
11194 .phy_specific_func = (phy_specific_func_t)NULL
11195};
11196
Yaniv Rosner52c4d6c2011-07-05 01:06:34 +000011197static struct bnx2x_phy phy_54618se = {
11198 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54618SE,
Yaniv Rosner6583e332011-06-14 01:34:17 +000011199 .addr = 0xff,
11200 .def_md_devad = 0,
11201 .flags = FLAGS_INIT_XGXS_FIRST,
11202 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
11203 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
11204 .mdio_ctrl = 0,
11205 .supported = (SUPPORTED_10baseT_Half |
11206 SUPPORTED_10baseT_Full |
11207 SUPPORTED_100baseT_Half |
11208 SUPPORTED_100baseT_Full |
11209 SUPPORTED_1000baseT_Full |
11210 SUPPORTED_TP |
11211 SUPPORTED_Autoneg |
11212 SUPPORTED_Pause |
11213 SUPPORTED_Asym_Pause),
11214 .media_type = ETH_PHY_BASE_T,
11215 .ver_addr = 0,
11216 .req_flow_ctrl = 0,
11217 .req_line_speed = 0,
11218 .speed_cap_mask = 0,
11219 /* req_duplex = */0,
11220 /* rsrv = */0,
Yaniv Rosner52c4d6c2011-07-05 01:06:34 +000011221 .config_init = (config_init_t)bnx2x_54618se_config_init,
11222 .read_status = (read_status_t)bnx2x_54618se_read_status,
11223 .link_reset = (link_reset_t)bnx2x_54618se_link_reset,
11224 .config_loopback = (config_loopback_t)bnx2x_54618se_config_loopback,
Yaniv Rosner6583e332011-06-14 01:34:17 +000011225 .format_fw_ver = (format_fw_ver_t)NULL,
11226 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosner1d125bd2011-11-23 03:54:08 +000011227 .set_link_led = (set_link_led_t)bnx2x_5461x_set_link_led,
Yaniv Rosner6583e332011-06-14 01:34:17 +000011228 .phy_specific_func = (phy_specific_func_t)NULL
11229};
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011230/*****************************************************************/
11231/* */
11232/* Populate the phy according. Main function: bnx2x_populate_phy */
11233/* */
11234/*****************************************************************/
11235
11236static void bnx2x_populate_preemphasis(struct bnx2x *bp, u32 shmem_base,
11237 struct bnx2x_phy *phy, u8 port,
11238 u8 phy_index)
11239{
11240 /* Get the 4 lanes xgxs config rx and tx */
11241 u32 rx = 0, tx = 0, i;
11242 for (i = 0; i < 2; i++) {
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +000011243 /*
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011244 * INT_PHY and EXT_PHY1 share the same value location in the
11245 * shmem. When num_phys is greater than 1, than this value
11246 * applies only to EXT_PHY1
11247 */
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011248 if (phy_index == INT_PHY || phy_index == EXT_PHY1) {
11249 rx = REG_RD(bp, shmem_base +
11250 offsetof(struct shmem_region,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000011251 dev_info.port_hw_config[port].xgxs_config_rx[i<<1]));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011252
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011253 tx = REG_RD(bp, shmem_base +
11254 offsetof(struct shmem_region,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000011255 dev_info.port_hw_config[port].xgxs_config_tx[i<<1]));
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011256 } else {
11257 rx = REG_RD(bp, shmem_base +
11258 offsetof(struct shmem_region,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000011259 dev_info.port_hw_config[port].xgxs_config2_rx[i<<1]));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011260
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011261 tx = REG_RD(bp, shmem_base +
11262 offsetof(struct shmem_region,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000011263 dev_info.port_hw_config[port].xgxs_config2_rx[i<<1]));
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011264 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011265
11266 phy->rx_preemphasis[i << 1] = ((rx>>16) & 0xffff);
11267 phy->rx_preemphasis[(i << 1) + 1] = (rx & 0xffff);
11268
11269 phy->tx_preemphasis[i << 1] = ((tx>>16) & 0xffff);
11270 phy->tx_preemphasis[(i << 1) + 1] = (tx & 0xffff);
11271 }
11272}
11273
Yaniv Rosnere10bc842010-09-07 11:40:50 +000011274static u32 bnx2x_get_ext_phy_config(struct bnx2x *bp, u32 shmem_base,
11275 u8 phy_index, u8 port)
11276{
11277 u32 ext_phy_config = 0;
11278 switch (phy_index) {
11279 case EXT_PHY1:
11280 ext_phy_config = REG_RD(bp, shmem_base +
11281 offsetof(struct shmem_region,
11282 dev_info.port_hw_config[port].external_phy_config));
11283 break;
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011284 case EXT_PHY2:
11285 ext_phy_config = REG_RD(bp, shmem_base +
11286 offsetof(struct shmem_region,
11287 dev_info.port_hw_config[port].external_phy_config2));
11288 break;
Yaniv Rosnere10bc842010-09-07 11:40:50 +000011289 default:
11290 DP(NETIF_MSG_LINK, "Invalid phy_index %d\n", phy_index);
11291 return -EINVAL;
11292 }
11293
11294 return ext_phy_config;
11295}
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +000011296static int bnx2x_populate_int_phy(struct bnx2x *bp, u32 shmem_base, u8 port,
11297 struct bnx2x_phy *phy)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011298{
11299 u32 phy_addr;
11300 u32 chip_id;
11301 u32 switch_cfg = (REG_RD(bp, shmem_base +
11302 offsetof(struct shmem_region,
11303 dev_info.port_feature_config[port].link_config)) &
11304 PORT_FEATURE_CONNECTED_SWITCH_MASK);
Yaniv Rosnerec15b892011-11-28 00:49:49 +000011305 chip_id = (REG_RD(bp, MISC_REG_CHIP_NUM) << 16) |
11306 ((REG_RD(bp, MISC_REG_CHIP_REV) & 0xf) << 12);
11307
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000011308 DP(NETIF_MSG_LINK, ":chip_id = 0x%x\n", chip_id);
11309 if (USES_WARPCORE(bp)) {
11310 u32 serdes_net_if;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011311 phy_addr = REG_RD(bp,
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000011312 MISC_REG_WC0_CTRL_PHY_ADDR);
11313 *phy = phy_warpcore;
11314 if (REG_RD(bp, MISC_REG_PORT4MODE_EN_OVWR) == 0x3)
11315 phy->flags |= FLAGS_4_PORT_MODE;
11316 else
11317 phy->flags &= ~FLAGS_4_PORT_MODE;
11318 /* Check Dual mode */
11319 serdes_net_if = (REG_RD(bp, shmem_base +
11320 offsetof(struct shmem_region, dev_info.
11321 port_hw_config[port].default_cfg)) &
11322 PORT_HW_CFG_NET_SERDES_IF_MASK);
11323 /*
11324 * Set the appropriate supported and flags indications per
11325 * interface type of the chip
11326 */
11327 switch (serdes_net_if) {
11328 case PORT_HW_CFG_NET_SERDES_IF_SGMII:
11329 phy->supported &= (SUPPORTED_10baseT_Half |
11330 SUPPORTED_10baseT_Full |
11331 SUPPORTED_100baseT_Half |
11332 SUPPORTED_100baseT_Full |
11333 SUPPORTED_1000baseT_Full |
11334 SUPPORTED_FIBRE |
11335 SUPPORTED_Autoneg |
11336 SUPPORTED_Pause |
11337 SUPPORTED_Asym_Pause);
11338 phy->media_type = ETH_PHY_BASE_T;
11339 break;
11340 case PORT_HW_CFG_NET_SERDES_IF_XFI:
11341 phy->media_type = ETH_PHY_XFP_FIBER;
11342 break;
11343 case PORT_HW_CFG_NET_SERDES_IF_SFI:
11344 phy->supported &= (SUPPORTED_1000baseT_Full |
11345 SUPPORTED_10000baseT_Full |
11346 SUPPORTED_FIBRE |
11347 SUPPORTED_Pause |
11348 SUPPORTED_Asym_Pause);
11349 phy->media_type = ETH_PHY_SFP_FIBER;
11350 break;
11351 case PORT_HW_CFG_NET_SERDES_IF_KR:
11352 phy->media_type = ETH_PHY_KR;
11353 phy->supported &= (SUPPORTED_1000baseT_Full |
11354 SUPPORTED_10000baseT_Full |
11355 SUPPORTED_FIBRE |
11356 SUPPORTED_Autoneg |
11357 SUPPORTED_Pause |
11358 SUPPORTED_Asym_Pause);
11359 break;
11360 case PORT_HW_CFG_NET_SERDES_IF_DXGXS:
11361 phy->media_type = ETH_PHY_KR;
11362 phy->flags |= FLAGS_WC_DUAL_MODE;
11363 phy->supported &= (SUPPORTED_20000baseMLD2_Full |
11364 SUPPORTED_FIBRE |
11365 SUPPORTED_Pause |
11366 SUPPORTED_Asym_Pause);
11367 break;
11368 case PORT_HW_CFG_NET_SERDES_IF_KR2:
11369 phy->media_type = ETH_PHY_KR;
11370 phy->flags |= FLAGS_WC_DUAL_MODE;
11371 phy->supported &= (SUPPORTED_20000baseKR2_Full |
11372 SUPPORTED_FIBRE |
11373 SUPPORTED_Pause |
11374 SUPPORTED_Asym_Pause);
11375 break;
11376 default:
11377 DP(NETIF_MSG_LINK, "Unknown WC interface type 0x%x\n",
11378 serdes_net_if);
11379 break;
11380 }
11381
11382 /*
11383 * Enable MDC/MDIO work-around for E3 A0 since free running MDC
11384 * was not set as expected. For B0, ECO will be enabled so there
11385 * won't be an issue there
11386 */
11387 if (CHIP_REV(bp) == CHIP_REV_Ax)
11388 phy->flags |= FLAGS_MDC_MDIO_WA;
Yaniv Rosner157fa282011-08-02 22:59:32 +000011389 else
11390 phy->flags |= FLAGS_MDC_MDIO_WA_B0;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000011391 } else {
11392 switch (switch_cfg) {
11393 case SWITCH_CFG_1G:
11394 phy_addr = REG_RD(bp,
11395 NIG_REG_SERDES0_CTRL_PHY_ADDR +
11396 port * 0x10);
11397 *phy = phy_serdes;
11398 break;
11399 case SWITCH_CFG_10G:
11400 phy_addr = REG_RD(bp,
11401 NIG_REG_XGXS0_CTRL_PHY_ADDR +
11402 port * 0x18);
11403 *phy = phy_xgxs;
11404 break;
11405 default:
11406 DP(NETIF_MSG_LINK, "Invalid switch_cfg\n");
11407 return -EINVAL;
11408 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011409 }
11410 phy->addr = (u8)phy_addr;
11411 phy->mdio_ctrl = bnx2x_get_emac_base(bp,
Yaniv Rosnerc18aa152010-09-07 11:41:07 +000011412 SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011413 port);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000011414 if (CHIP_IS_E2(bp))
11415 phy->def_md_devad = E2_DEFAULT_PHY_DEV_ADDR;
11416 else
11417 phy->def_md_devad = DEFAULT_PHY_DEV_ADDR;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011418
11419 DP(NETIF_MSG_LINK, "Internal phy port=%d, addr=0x%x, mdio_ctl=0x%x\n",
11420 port, phy->addr, phy->mdio_ctrl);
11421
11422 bnx2x_populate_preemphasis(bp, shmem_base, phy, port, INT_PHY);
11423 return 0;
11424}
Yaniv Rosnere10bc842010-09-07 11:40:50 +000011425
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +000011426static int bnx2x_populate_ext_phy(struct bnx2x *bp,
11427 u8 phy_index,
11428 u32 shmem_base,
11429 u32 shmem2_base,
11430 u8 port,
11431 struct bnx2x_phy *phy)
Yaniv Rosnere10bc842010-09-07 11:40:50 +000011432{
Yaniv Rosnerc18aa152010-09-07 11:41:07 +000011433 u32 ext_phy_config, phy_type, config2;
11434 u32 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH;
Yaniv Rosnere10bc842010-09-07 11:40:50 +000011435 ext_phy_config = bnx2x_get_ext_phy_config(bp, shmem_base,
11436 phy_index, port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011437 phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
11438 /* Select the phy type */
11439 switch (phy_type) {
11440 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Yaniv Rosnerc18aa152010-09-07 11:41:07 +000011441 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_SWAPPED;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011442 *phy = phy_8073;
11443 break;
11444 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
11445 *phy = phy_8705;
11446 break;
11447 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
11448 *phy = phy_8706;
11449 break;
11450 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
Yaniv Rosnerc18aa152010-09-07 11:41:07 +000011451 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011452 *phy = phy_8726;
11453 break;
11454 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
11455 /* BCM8727_NOC => BCM8727 no over current */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +000011456 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011457 *phy = phy_8727;
11458 phy->flags |= FLAGS_NOC;
11459 break;
Yaniv Rosnere4d78f12011-05-31 21:25:55 +000011460 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722:
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011461 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
Yaniv Rosnerc18aa152010-09-07 11:41:07 +000011462 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011463 *phy = phy_8727;
11464 break;
11465 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
11466 *phy = phy_8481;
11467 break;
11468 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
11469 *phy = phy_84823;
11470 break;
Yaniv Rosnerc87bca12011-01-31 04:22:41 +000011471 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833:
11472 *phy = phy_84833;
11473 break;
Yaniv Rosner3756a892011-08-23 06:33:24 +000011474 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54616:
Yaniv Rosner52c4d6c2011-07-05 01:06:34 +000011475 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54618SE:
11476 *phy = phy_54618se;
Yaniv Rosner6583e332011-06-14 01:34:17 +000011477 break;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011478 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
11479 *phy = phy_7101;
11480 break;
11481 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
11482 *phy = phy_null;
11483 return -EINVAL;
11484 default:
11485 *phy = phy_null;
Yaniv Rosner6db51932011-11-28 00:49:50 +000011486 /* In case external PHY wasn't found */
11487 if ((phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
11488 (phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN))
11489 return -EINVAL;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011490 return 0;
11491 }
11492
Yaniv Rosnere10bc842010-09-07 11:40:50 +000011493 phy->addr = XGXS_EXT_PHY_ADDR(ext_phy_config);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011494 bnx2x_populate_preemphasis(bp, shmem_base, phy, port, phy_index);
Yaniv Rosner62b29a52010-09-07 11:40:58 +000011495
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +000011496 /*
11497 * The shmem address of the phy version is located on different
11498 * structures. In case this structure is too old, do not set
11499 * the address
11500 */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +000011501 config2 = REG_RD(bp, shmem_base + offsetof(struct shmem_region,
11502 dev_info.shared_hw_config.config2));
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011503 if (phy_index == EXT_PHY1) {
11504 phy->ver_addr = shmem_base + offsetof(struct shmem_region,
11505 port_mb[port].ext_phy_fw_version);
Yaniv Rosnerc18aa152010-09-07 11:41:07 +000011506
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000011507 /* Check specific mdc mdio settings */
11508 if (config2 & SHARED_HW_CFG_MDC_MDIO_ACCESS1_MASK)
11509 mdc_mdio_access = config2 &
11510 SHARED_HW_CFG_MDC_MDIO_ACCESS1_MASK;
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011511 } else {
11512 u32 size = REG_RD(bp, shmem2_base);
Yaniv Rosnerc18aa152010-09-07 11:41:07 +000011513
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011514 if (size >
11515 offsetof(struct shmem2_region, ext_phy_fw_version2)) {
11516 phy->ver_addr = shmem2_base +
11517 offsetof(struct shmem2_region,
11518 ext_phy_fw_version2[port]);
11519 }
11520 /* Check specific mdc mdio settings */
11521 if (config2 & SHARED_HW_CFG_MDC_MDIO_ACCESS2_MASK)
11522 mdc_mdio_access = (config2 &
11523 SHARED_HW_CFG_MDC_MDIO_ACCESS2_MASK) >>
11524 (SHARED_HW_CFG_MDC_MDIO_ACCESS2_SHIFT -
11525 SHARED_HW_CFG_MDC_MDIO_ACCESS1_SHIFT);
11526 }
Yaniv Rosnerc18aa152010-09-07 11:41:07 +000011527 phy->mdio_ctrl = bnx2x_get_emac_base(bp, mdc_mdio_access, port);
11528
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +000011529 /*
Yaniv Rosnerc18aa152010-09-07 11:41:07 +000011530 * In case mdc/mdio_access of the external phy is different than the
11531 * mdc/mdio access of the XGXS, a HW lock must be taken in each access
11532 * to prevent one port interfere with another port's CL45 operations.
11533 */
11534 if (mdc_mdio_access != SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH)
11535 phy->flags |= FLAGS_HW_LOCK_REQUIRED;
11536 DP(NETIF_MSG_LINK, "phy_type 0x%x port %d found in index %d\n",
11537 phy_type, port, phy_index);
11538 DP(NETIF_MSG_LINK, " addr=0x%x, mdio_ctl=0x%x\n",
11539 phy->addr, phy->mdio_ctrl);
Yaniv Rosnere10bc842010-09-07 11:40:50 +000011540 return 0;
11541}
11542
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +000011543static int bnx2x_populate_phy(struct bnx2x *bp, u8 phy_index, u32 shmem_base,
11544 u32 shmem2_base, u8 port, struct bnx2x_phy *phy)
Yaniv Rosnere10bc842010-09-07 11:40:50 +000011545{
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +000011546 int status = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011547 phy->type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN;
11548 if (phy_index == INT_PHY)
11549 return bnx2x_populate_int_phy(bp, shmem_base, port, phy);
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011550 status = bnx2x_populate_ext_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnere10bc842010-09-07 11:40:50 +000011551 port, phy);
11552 return status;
11553}
11554
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011555static void bnx2x_phy_def_cfg(struct link_params *params,
11556 struct bnx2x_phy *phy,
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011557 u8 phy_index)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011558{
11559 struct bnx2x *bp = params->bp;
11560 u32 link_config;
11561 /* Populate the default phy configuration for MF mode */
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011562 if (phy_index == EXT_PHY2) {
11563 link_config = REG_RD(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000011564 offsetof(struct shmem_region, dev_info.
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011565 port_feature_config[params->port].link_config2));
11566 phy->speed_cap_mask = REG_RD(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000011567 offsetof(struct shmem_region,
11568 dev_info.
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011569 port_hw_config[params->port].speed_capability_mask2));
11570 } else {
11571 link_config = REG_RD(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000011572 offsetof(struct shmem_region, dev_info.
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011573 port_feature_config[params->port].link_config));
11574 phy->speed_cap_mask = REG_RD(bp, params->shmem_base +
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000011575 offsetof(struct shmem_region,
11576 dev_info.
11577 port_hw_config[params->port].speed_capability_mask));
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011578 }
Joe Perches94f05b02011-08-14 12:16:20 +000011579 DP(NETIF_MSG_LINK,
11580 "Default config phy idx %x cfg 0x%x speed_cap_mask 0x%x\n",
11581 phy_index, link_config, phy->speed_cap_mask);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011582
11583 phy->req_duplex = DUPLEX_FULL;
11584 switch (link_config & PORT_FEATURE_LINK_SPEED_MASK) {
11585 case PORT_FEATURE_LINK_SPEED_10M_HALF:
11586 phy->req_duplex = DUPLEX_HALF;
11587 case PORT_FEATURE_LINK_SPEED_10M_FULL:
11588 phy->req_line_speed = SPEED_10;
11589 break;
11590 case PORT_FEATURE_LINK_SPEED_100M_HALF:
11591 phy->req_duplex = DUPLEX_HALF;
11592 case PORT_FEATURE_LINK_SPEED_100M_FULL:
11593 phy->req_line_speed = SPEED_100;
11594 break;
11595 case PORT_FEATURE_LINK_SPEED_1G:
11596 phy->req_line_speed = SPEED_1000;
11597 break;
11598 case PORT_FEATURE_LINK_SPEED_2_5G:
11599 phy->req_line_speed = SPEED_2500;
11600 break;
11601 case PORT_FEATURE_LINK_SPEED_10G_CX4:
11602 phy->req_line_speed = SPEED_10000;
11603 break;
11604 default:
11605 phy->req_line_speed = SPEED_AUTO_NEG;
11606 break;
11607 }
11608
11609 switch (link_config & PORT_FEATURE_FLOW_CONTROL_MASK) {
11610 case PORT_FEATURE_FLOW_CONTROL_AUTO:
11611 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_AUTO;
11612 break;
11613 case PORT_FEATURE_FLOW_CONTROL_TX:
11614 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_TX;
11615 break;
11616 case PORT_FEATURE_FLOW_CONTROL_RX:
11617 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_RX;
11618 break;
11619 case PORT_FEATURE_FLOW_CONTROL_BOTH:
11620 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_BOTH;
11621 break;
11622 default:
11623 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_NONE;
11624 break;
11625 }
11626}
11627
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011628u32 bnx2x_phy_selection(struct link_params *params)
11629{
11630 u32 phy_config_swapped, prio_cfg;
11631 u32 return_cfg = PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT;
11632
11633 phy_config_swapped = params->multi_phy_config &
11634 PORT_HW_CFG_PHY_SWAPPED_ENABLED;
11635
11636 prio_cfg = params->multi_phy_config &
11637 PORT_HW_CFG_PHY_SELECTION_MASK;
11638
11639 if (phy_config_swapped) {
11640 switch (prio_cfg) {
11641 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
11642 return_cfg = PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY;
11643 break;
11644 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
11645 return_cfg = PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY;
11646 break;
11647 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY:
11648 return_cfg = PORT_HW_CFG_PHY_SELECTION_FIRST_PHY;
11649 break;
11650 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY:
11651 return_cfg = PORT_HW_CFG_PHY_SELECTION_SECOND_PHY;
11652 break;
11653 }
11654 } else
11655 return_cfg = prio_cfg;
11656
11657 return return_cfg;
11658}
11659
11660
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +000011661int bnx2x_phy_probe(struct link_params *params)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011662{
Yaniv Rosner2f751a82011-11-28 00:49:52 +000011663 u8 phy_index, actual_phy_idx;
Yaniv Rosner1ac9e422011-05-31 21:26:11 +000011664 u32 phy_config_swapped, sync_offset, media_types;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011665 struct bnx2x *bp = params->bp;
11666 struct bnx2x_phy *phy;
11667 params->num_phys = 0;
11668 DP(NETIF_MSG_LINK, "Begin phy probe\n");
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011669 phy_config_swapped = params->multi_phy_config &
11670 PORT_HW_CFG_PHY_SWAPPED_ENABLED;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011671
11672 for (phy_index = INT_PHY; phy_index < MAX_PHYS;
11673 phy_index++) {
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011674 actual_phy_idx = phy_index;
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011675 if (phy_config_swapped) {
11676 if (phy_index == EXT_PHY1)
11677 actual_phy_idx = EXT_PHY2;
11678 else if (phy_index == EXT_PHY2)
11679 actual_phy_idx = EXT_PHY1;
11680 }
11681 DP(NETIF_MSG_LINK, "phy_config_swapped %x, phy_index %x,"
11682 " actual_phy_idx %x\n", phy_config_swapped,
11683 phy_index, actual_phy_idx);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011684 phy = &params->phy[actual_phy_idx];
11685 if (bnx2x_populate_phy(bp, phy_index, params->shmem_base,
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011686 params->shmem2_base, params->port,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011687 phy) != 0) {
11688 params->num_phys = 0;
11689 DP(NETIF_MSG_LINK, "phy probe failed in phy index %d\n",
11690 phy_index);
11691 for (phy_index = INT_PHY;
11692 phy_index < MAX_PHYS;
11693 phy_index++)
11694 *phy = phy_null;
11695 return -EINVAL;
11696 }
11697 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)
11698 break;
11699
Yaniv Rosner1ac9e422011-05-31 21:26:11 +000011700 sync_offset = params->shmem_base +
11701 offsetof(struct shmem_region,
11702 dev_info.port_hw_config[params->port].media_type);
11703 media_types = REG_RD(bp, sync_offset);
11704
11705 /*
11706 * Update media type for non-PMF sync only for the first time
11707 * In case the media type changes afterwards, it will be updated
11708 * using the update_status function
11709 */
11710 if ((media_types & (PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK <<
11711 (PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT *
11712 actual_phy_idx))) == 0) {
11713 media_types |= ((phy->media_type &
11714 PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK) <<
11715 (PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT *
11716 actual_phy_idx));
11717 }
11718 REG_WR(bp, sync_offset, media_types);
11719
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011720 bnx2x_phy_def_cfg(params, phy, phy_index);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +000011721 params->num_phys++;
11722 }
11723
11724 DP(NETIF_MSG_LINK, "End phy probe. #phys found %x\n", params->num_phys);
11725 return 0;
11726}
11727
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000011728void bnx2x_init_bmac_loopback(struct link_params *params,
11729 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011730{
11731 struct bnx2x *bp = params->bp;
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000011732 vars->link_up = 1;
11733 vars->line_speed = SPEED_10000;
11734 vars->duplex = DUPLEX_FULL;
11735 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
11736 vars->mac_type = MAC_TYPE_BMAC;
11737
11738 vars->phy_flags = PHY_XGXS_FLAG;
11739
11740 bnx2x_xgxs_deassert(params);
11741
11742 /* set bmac loopback */
11743 bnx2x_bmac_enable(params, vars, 1);
11744
11745 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
11746}
11747
11748void bnx2x_init_emac_loopback(struct link_params *params,
11749 struct link_vars *vars)
11750{
11751 struct bnx2x *bp = params->bp;
11752 vars->link_up = 1;
11753 vars->line_speed = SPEED_1000;
11754 vars->duplex = DUPLEX_FULL;
11755 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
11756 vars->mac_type = MAC_TYPE_EMAC;
11757
11758 vars->phy_flags = PHY_XGXS_FLAG;
11759
11760 bnx2x_xgxs_deassert(params);
11761 /* set bmac loopback */
11762 bnx2x_emac_enable(params, vars, 1);
11763 bnx2x_emac_program(params, vars);
11764 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
11765}
11766
Yaniv Rosner9380bb92011-06-14 01:34:07 +000011767void bnx2x_init_xmac_loopback(struct link_params *params,
11768 struct link_vars *vars)
11769{
11770 struct bnx2x *bp = params->bp;
11771 vars->link_up = 1;
11772 if (!params->req_line_speed[0])
11773 vars->line_speed = SPEED_10000;
11774 else
11775 vars->line_speed = params->req_line_speed[0];
11776 vars->duplex = DUPLEX_FULL;
11777 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
11778 vars->mac_type = MAC_TYPE_XMAC;
11779 vars->phy_flags = PHY_XGXS_FLAG;
11780 /*
11781 * Set WC to loopback mode since link is required to provide clock
11782 * to the XMAC in 20G mode
11783 */
Yaniv Rosnerafad0092011-08-02 23:00:06 +000011784 bnx2x_set_aer_mmd(params, &params->phy[0]);
11785 bnx2x_warpcore_reset_lane(bp, &params->phy[0], 0);
11786 params->phy[INT_PHY].config_loopback(
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000011787 &params->phy[INT_PHY],
11788 params);
Yaniv Rosnerafad0092011-08-02 23:00:06 +000011789
Yaniv Rosner9380bb92011-06-14 01:34:07 +000011790 bnx2x_xmac_enable(params, vars, 1);
11791 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
11792}
11793
11794void bnx2x_init_umac_loopback(struct link_params *params,
11795 struct link_vars *vars)
11796{
11797 struct bnx2x *bp = params->bp;
11798 vars->link_up = 1;
11799 vars->line_speed = SPEED_1000;
11800 vars->duplex = DUPLEX_FULL;
11801 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
11802 vars->mac_type = MAC_TYPE_UMAC;
11803 vars->phy_flags = PHY_XGXS_FLAG;
11804 bnx2x_umac_enable(params, vars, 1);
11805
11806 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
11807}
11808
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000011809void bnx2x_init_xgxs_loopback(struct link_params *params,
11810 struct link_vars *vars)
11811{
11812 struct bnx2x *bp = params->bp;
11813 vars->link_up = 1;
11814 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
11815 vars->duplex = DUPLEX_FULL;
11816 if (params->req_line_speed[0] == SPEED_1000)
11817 vars->line_speed = SPEED_1000;
11818 else
11819 vars->line_speed = SPEED_10000;
11820
Yaniv Rosner9380bb92011-06-14 01:34:07 +000011821 if (!USES_WARPCORE(bp))
11822 bnx2x_xgxs_deassert(params);
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000011823 bnx2x_link_initialize(params, vars);
11824
11825 if (params->req_line_speed[0] == SPEED_1000) {
Yaniv Rosner9380bb92011-06-14 01:34:07 +000011826 if (USES_WARPCORE(bp))
11827 bnx2x_umac_enable(params, vars, 0);
11828 else {
11829 bnx2x_emac_program(params, vars);
11830 bnx2x_emac_enable(params, vars, 0);
11831 }
11832 } else {
11833 if (USES_WARPCORE(bp))
11834 bnx2x_xmac_enable(params, vars, 0);
11835 else
11836 bnx2x_bmac_enable(params, vars, 0);
11837 }
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000011838
11839 if (params->loopback_mode == LOOPBACK_XGXS) {
11840 /* set 10G XGXS loopback */
11841 params->phy[INT_PHY].config_loopback(
11842 &params->phy[INT_PHY],
11843 params);
11844
11845 } else {
11846 /* set external phy loopback */
11847 u8 phy_index;
11848 for (phy_index = EXT_PHY1;
11849 phy_index < params->num_phys; phy_index++) {
11850 if (params->phy[phy_index].config_loopback)
11851 params->phy[phy_index].config_loopback(
11852 &params->phy[phy_index],
11853 params);
11854 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011855 }
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000011856 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011857
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000011858 bnx2x_set_led(params, vars, LED_MODE_OPER, vars->line_speed);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011859}
11860
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +000011861int bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011862{
11863 struct bnx2x *bp = params->bp;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011864 DP(NETIF_MSG_LINK, "Phy Initialization started\n");
Yaniv Rosnera22f0782010-09-07 11:41:20 +000011865 DP(NETIF_MSG_LINK, "(1) req_speed %d, req_flowctrl %d\n",
11866 params->req_line_speed[0], params->req_flow_ctrl[0]);
11867 DP(NETIF_MSG_LINK, "(2) req_speed %d, req_flowctrl %d\n",
11868 params->req_line_speed[1], params->req_flow_ctrl[1]);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011869 vars->link_status = 0;
11870 vars->phy_link_up = 0;
11871 vars->link_up = 0;
11872 vars->line_speed = 0;
11873 vars->duplex = DUPLEX_FULL;
11874 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
11875 vars->mac_type = MAC_TYPE_NONE;
11876 vars->phy_flags = 0;
11877
11878 /* disable attentions */
11879 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4,
11880 (NIG_MASK_XGXS0_LINK_STATUS |
11881 NIG_MASK_XGXS0_LINK10G |
11882 NIG_MASK_SERDES0_LINK_STATUS |
11883 NIG_MASK_MI_INT));
11884
11885 bnx2x_emac_init(params, vars);
11886
11887 if (params->num_phys == 0) {
11888 DP(NETIF_MSG_LINK, "No phy found for initialization !!\n");
11889 return -EINVAL;
11890 }
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000011891 set_phy_vars(params, vars);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011892
11893 DP(NETIF_MSG_LINK, "Num of phys on board: %d\n", params->num_phys);
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000011894 switch (params->loopback_mode) {
11895 case LOOPBACK_BMAC:
11896 bnx2x_init_bmac_loopback(params, vars);
11897 break;
11898 case LOOPBACK_EMAC:
11899 bnx2x_init_emac_loopback(params, vars);
11900 break;
Yaniv Rosner9380bb92011-06-14 01:34:07 +000011901 case LOOPBACK_XMAC:
11902 bnx2x_init_xmac_loopback(params, vars);
11903 break;
11904 case LOOPBACK_UMAC:
11905 bnx2x_init_umac_loopback(params, vars);
11906 break;
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000011907 case LOOPBACK_XGXS:
11908 case LOOPBACK_EXT_PHY:
11909 bnx2x_init_xgxs_loopback(params, vars);
11910 break;
11911 default:
Yaniv Rosner9380bb92011-06-14 01:34:07 +000011912 if (!CHIP_IS_E3(bp)) {
11913 if (params->switch_cfg == SWITCH_CFG_10G)
11914 bnx2x_xgxs_deassert(params);
11915 else
11916 bnx2x_serdes_deassert(bp, params->port);
11917 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011918 bnx2x_link_initialize(params, vars);
11919 msleep(30);
11920 bnx2x_link_int_enable(params);
Yaniv Rosner9045f6b2011-05-31 21:28:27 +000011921 break;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011922 }
11923 return 0;
11924}
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +000011925
11926int bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
11927 u8 reset_ext_phy)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011928{
11929 struct bnx2x *bp = params->bp;
Yaniv Rosnercf1d9722010-11-01 05:32:34 +000011930 u8 phy_index, port = params->port, clear_latch_ind = 0;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011931 DP(NETIF_MSG_LINK, "Resetting the link of port %d\n", port);
11932 /* disable attentions */
11933 vars->link_status = 0;
11934 bnx2x_update_mng(params, vars->link_status);
11935 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000011936 (NIG_MASK_XGXS0_LINK_STATUS |
11937 NIG_MASK_XGXS0_LINK10G |
11938 NIG_MASK_SERDES0_LINK_STATUS |
11939 NIG_MASK_MI_INT));
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011940
11941 /* activate nig drain */
11942 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
11943
11944 /* disable nig egress interface */
Yaniv Rosner9380bb92011-06-14 01:34:07 +000011945 if (!CHIP_IS_E3(bp)) {
11946 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
11947 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
11948 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011949
11950 /* Stop BigMac rx */
Yaniv Rosner9380bb92011-06-14 01:34:07 +000011951 if (!CHIP_IS_E3(bp))
11952 bnx2x_bmac_rx_disable(bp, port);
Yaniv Rosnerce7c0482011-10-27 05:09:47 +000011953 else {
Yaniv Rosner9380bb92011-06-14 01:34:07 +000011954 bnx2x_xmac_disable(params);
Yaniv Rosnerce7c0482011-10-27 05:09:47 +000011955 bnx2x_umac_disable(params);
11956 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011957 /* disable emac */
Yaniv Rosner9380bb92011-06-14 01:34:07 +000011958 if (!CHIP_IS_E3(bp))
11959 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011960
11961 msleep(10);
Lucas De Marchi25985ed2011-03-30 22:57:33 -030011962 /* The PHY reset is controlled by GPIO 1
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011963 * Hold it as vars low
11964 */
11965 /* clear link led */
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +000011966 bnx2x_set_led(params, vars, LED_MODE_OFF, 0);
11967
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011968 if (reset_ext_phy) {
Yaniv Rosner28f48812011-08-02 23:00:12 +000011969 bnx2x_set_mdio_clk(bp, params->chip_id, port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011970 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
11971 phy_index++) {
Yaniv Rosner28f48812011-08-02 23:00:12 +000011972 if (params->phy[phy_index].link_reset) {
11973 bnx2x_set_aer_mmd(params,
11974 &params->phy[phy_index]);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011975 params->phy[phy_index].link_reset(
11976 &params->phy[phy_index],
11977 params);
Yaniv Rosner28f48812011-08-02 23:00:12 +000011978 }
Yaniv Rosnercf1d9722010-11-01 05:32:34 +000011979 if (params->phy[phy_index].flags &
11980 FLAGS_REARM_LATCH_SIGNAL)
11981 clear_latch_ind = 1;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011982 }
11983 }
11984
Yaniv Rosnercf1d9722010-11-01 05:32:34 +000011985 if (clear_latch_ind) {
11986 /* Clear latching indication */
11987 bnx2x_rearm_latch_signal(bp, port, 0);
11988 bnx2x_bits_dis(bp, NIG_REG_LATCH_BC_0 + port*4,
11989 1 << NIG_LATCH_BC_ENABLE_MI_INT);
11990 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011991 if (params->phy[INT_PHY].link_reset)
11992 params->phy[INT_PHY].link_reset(
11993 &params->phy[INT_PHY], params);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000011994
11995 /* disable nig ingress interface */
Yaniv Rosner9380bb92011-06-14 01:34:07 +000011996 if (!CHIP_IS_E3(bp)) {
Yaniv Rosnerce7c0482011-10-27 05:09:47 +000011997 /* reset BigMac */
11998 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
11999 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
Yaniv Rosner9380bb92011-06-14 01:34:07 +000012000 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0);
12001 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0);
Yaniv Rosnerce7c0482011-10-27 05:09:47 +000012002 } else {
12003 u32 xmac_base = (params->port) ? GRCBASE_XMAC1 : GRCBASE_XMAC0;
12004 bnx2x_set_xumac_nig(params, 0, 0);
12005 if (REG_RD(bp, MISC_REG_RESET_REG_2) &
12006 MISC_REGISTERS_RESET_REG_2_XMAC)
12007 REG_WR(bp, xmac_base + XMAC_REG_CTRL,
12008 XMAC_CTRL_REG_SOFT_RESET);
Yaniv Rosner9380bb92011-06-14 01:34:07 +000012009 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000012010 vars->link_up = 0;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000012011 vars->phy_flags = 0;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000012012 return 0;
12013}
12014
12015/****************************************************************************/
12016/* Common function */
12017/****************************************************************************/
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +000012018static int bnx2x_8073_common_init_phy(struct bnx2x *bp,
12019 u32 shmem_base_path[],
12020 u32 shmem2_base_path[], u8 phy_index,
12021 u32 chip_id)
Yaniv Rosner6bbca912008-08-13 15:57:28 -070012022{
Yaniv Rosnere10bc842010-09-07 11:40:50 +000012023 struct bnx2x_phy phy[PORT_MAX];
12024 struct bnx2x_phy *phy_blk[PORT_MAX];
Yaniv Rosner6bbca912008-08-13 15:57:28 -070012025 u16 val;
Yaniv Rosnerc8e64df2011-01-30 04:15:00 +000012026 s8 port = 0;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000012027 s8 port_of_path = 0;
Yaniv Rosnerc8e64df2011-01-30 04:15:00 +000012028 u32 swap_val, swap_override;
12029 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
12030 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
12031 port ^= (swap_val && swap_override);
12032 bnx2x_ext_phy_hw_reset(bp, port);
Yaniv Rosner6bbca912008-08-13 15:57:28 -070012033 /* PART1 - Reset both phys */
12034 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000012035 u32 shmem_base, shmem2_base;
12036 /* In E2, same phy is using for port0 of the two paths */
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000012037 if (CHIP_IS_E1x(bp)) {
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000012038 shmem_base = shmem_base_path[0];
12039 shmem2_base = shmem2_base_path[0];
12040 port_of_path = port;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000012041 } else {
12042 shmem_base = shmem_base_path[port];
12043 shmem2_base = shmem2_base_path[port];
12044 port_of_path = 0;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000012045 }
12046
Yaniv Rosner6bbca912008-08-13 15:57:28 -070012047 /* Extract the ext phy address for the port */
Yaniv Rosnera22f0782010-09-07 11:41:20 +000012048 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000012049 port_of_path, &phy[port]) !=
Yaniv Rosnere10bc842010-09-07 11:40:50 +000012050 0) {
12051 DP(NETIF_MSG_LINK, "populate_phy failed\n");
12052 return -EINVAL;
12053 }
Yaniv Rosner6bbca912008-08-13 15:57:28 -070012054 /* disable attentions */
Yaniv Rosner6a71bbe2010-11-01 05:32:31 +000012055 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 +
12056 port_of_path*4,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000012057 (NIG_MASK_XGXS0_LINK_STATUS |
12058 NIG_MASK_XGXS0_LINK10G |
12059 NIG_MASK_SERDES0_LINK_STATUS |
12060 NIG_MASK_MI_INT));
Yaniv Rosner6bbca912008-08-13 15:57:28 -070012061
Yaniv Rosner6bbca912008-08-13 15:57:28 -070012062 /* Need to take the phy out of low power mode in order
12063 to write to access its registers */
12064 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000012065 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
12066 port);
Yaniv Rosner6bbca912008-08-13 15:57:28 -070012067
12068 /* Reset the phy */
Yaniv Rosnere10bc842010-09-07 11:40:50 +000012069 bnx2x_cl45_write(bp, &phy[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000012070 MDIO_PMA_DEVAD,
12071 MDIO_PMA_REG_CTRL,
12072 1<<15);
Yaniv Rosner6bbca912008-08-13 15:57:28 -070012073 }
12074
12075 /* Add delay of 150ms after reset */
12076 msleep(150);
12077
Yaniv Rosnere10bc842010-09-07 11:40:50 +000012078 if (phy[PORT_0].addr & 0x1) {
12079 phy_blk[PORT_0] = &(phy[PORT_1]);
12080 phy_blk[PORT_1] = &(phy[PORT_0]);
12081 } else {
12082 phy_blk[PORT_0] = &(phy[PORT_0]);
12083 phy_blk[PORT_1] = &(phy[PORT_1]);
12084 }
12085
Yaniv Rosner6bbca912008-08-13 15:57:28 -070012086 /* PART2 - Download firmware to both phys */
12087 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000012088 if (CHIP_IS_E1x(bp))
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000012089 port_of_path = port;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000012090 else
12091 port_of_path = 0;
Yaniv Rosner6bbca912008-08-13 15:57:28 -070012092
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000012093 DP(NETIF_MSG_LINK, "Loading spirom for phy address 0x%x\n",
12094 phy_blk[port]->addr);
Yaniv Rosner5c99274b2011-01-18 04:33:36 +000012095 if (bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port],
12096 port_of_path))
Yaniv Rosner6bbca912008-08-13 15:57:28 -070012097 return -EINVAL;
Yaniv Rosner6bbca912008-08-13 15:57:28 -070012098
12099 /* Only set bit 10 = 1 (Tx power down) */
Yaniv Rosnere10bc842010-09-07 11:40:50 +000012100 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000012101 MDIO_PMA_DEVAD,
12102 MDIO_PMA_REG_TX_POWER_DOWN, &val);
Yaniv Rosner6bbca912008-08-13 15:57:28 -070012103
12104 /* Phase1 of TX_POWER_DOWN reset */
Yaniv Rosnere10bc842010-09-07 11:40:50 +000012105 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000012106 MDIO_PMA_DEVAD,
12107 MDIO_PMA_REG_TX_POWER_DOWN,
12108 (val | 1<<10));
Yaniv Rosner6bbca912008-08-13 15:57:28 -070012109 }
12110
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +000012111 /*
12112 * Toggle Transmitter: Power down and then up with 600ms delay
12113 * between
12114 */
Yaniv Rosner6bbca912008-08-13 15:57:28 -070012115 msleep(600);
12116
12117 /* PART3 - complete TX_POWER_DOWN process, and set GPIO2 back to low */
12118 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Eilon Greensteinf5372252009-02-12 08:38:30 +000012119 /* Phase2 of POWER_DOWN_RESET */
Yaniv Rosner6bbca912008-08-13 15:57:28 -070012120 /* Release bit 10 (Release Tx power down) */
Yaniv Rosnere10bc842010-09-07 11:40:50 +000012121 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000012122 MDIO_PMA_DEVAD,
12123 MDIO_PMA_REG_TX_POWER_DOWN, &val);
Yaniv Rosner6bbca912008-08-13 15:57:28 -070012124
Yaniv Rosnere10bc842010-09-07 11:40:50 +000012125 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000012126 MDIO_PMA_DEVAD,
12127 MDIO_PMA_REG_TX_POWER_DOWN, (val & (~(1<<10))));
Yaniv Rosner6bbca912008-08-13 15:57:28 -070012128 msleep(15);
12129
12130 /* Read modify write the SPI-ROM version select register */
Yaniv Rosnere10bc842010-09-07 11:40:50 +000012131 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000012132 MDIO_PMA_DEVAD,
12133 MDIO_PMA_REG_EDC_FFE_MAIN, &val);
Yaniv Rosnere10bc842010-09-07 11:40:50 +000012134 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000012135 MDIO_PMA_DEVAD,
12136 MDIO_PMA_REG_EDC_FFE_MAIN, (val | (1<<12)));
Yaniv Rosner6bbca912008-08-13 15:57:28 -070012137
12138 /* set GPIO2 back to LOW */
12139 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000012140 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
Yaniv Rosner6bbca912008-08-13 15:57:28 -070012141 }
12142 return 0;
Yaniv Rosner6bbca912008-08-13 15:57:28 -070012143}
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +000012144static int bnx2x_8726_common_init_phy(struct bnx2x *bp,
12145 u32 shmem_base_path[],
12146 u32 shmem2_base_path[], u8 phy_index,
12147 u32 chip_id)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000012148{
12149 u32 val;
12150 s8 port;
12151 struct bnx2x_phy phy;
12152 /* Use port1 because of the static port-swap */
12153 /* Enable the module detection interrupt */
12154 val = REG_RD(bp, MISC_REG_GPIO_EVENT_EN);
12155 val |= ((1<<MISC_REGISTERS_GPIO_3)|
12156 (1<<(MISC_REGISTERS_GPIO_3 + MISC_REGISTERS_GPIO_PORT_SHIFT)));
12157 REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val);
12158
Yaniv Rosner650154b2010-11-01 05:32:36 +000012159 bnx2x_ext_phy_hw_reset(bp, 0);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000012160 msleep(5);
12161 for (port = 0; port < PORT_MAX; port++) {
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000012162 u32 shmem_base, shmem2_base;
12163
12164 /* In E2, same phy is using for port0 of the two paths */
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000012165 if (CHIP_IS_E1x(bp)) {
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000012166 shmem_base = shmem_base_path[0];
12167 shmem2_base = shmem2_base_path[0];
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000012168 } else {
12169 shmem_base = shmem_base_path[port];
12170 shmem2_base = shmem2_base_path[port];
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000012171 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000012172 /* Extract the ext phy address for the port */
Yaniv Rosnera22f0782010-09-07 11:41:20 +000012173 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000012174 port, &phy) !=
12175 0) {
12176 DP(NETIF_MSG_LINK, "populate phy failed\n");
12177 return -EINVAL;
12178 }
12179
12180 /* Reset phy*/
12181 bnx2x_cl45_write(bp, &phy,
12182 MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, 0x0001);
12183
12184
12185 /* Set fault module detected LED on */
12186 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000012187 MISC_REGISTERS_GPIO_HIGH,
12188 port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +000012189 }
12190
12191 return 0;
12192}
Yaniv Rosnera8db5b42011-01-31 04:22:28 +000012193static void bnx2x_get_ext_phy_reset_gpio(struct bnx2x *bp, u32 shmem_base,
12194 u8 *io_gpio, u8 *io_port)
12195{
12196
12197 u32 phy_gpio_reset = REG_RD(bp, shmem_base +
12198 offsetof(struct shmem_region,
12199 dev_info.port_hw_config[PORT_0].default_cfg));
12200 switch (phy_gpio_reset) {
12201 case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO0_P0:
12202 *io_gpio = 0;
12203 *io_port = 0;
12204 break;
12205 case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO1_P0:
12206 *io_gpio = 1;
12207 *io_port = 0;
12208 break;
12209 case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO2_P0:
12210 *io_gpio = 2;
12211 *io_port = 0;
12212 break;
12213 case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO3_P0:
12214 *io_gpio = 3;
12215 *io_port = 0;
12216 break;
12217 case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO0_P1:
12218 *io_gpio = 0;
12219 *io_port = 1;
12220 break;
12221 case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO1_P1:
12222 *io_gpio = 1;
12223 *io_port = 1;
12224 break;
12225 case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO2_P1:
12226 *io_gpio = 2;
12227 *io_port = 1;
12228 break;
12229 case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO3_P1:
12230 *io_gpio = 3;
12231 *io_port = 1;
12232 break;
12233 default:
12234 /* Don't override the io_gpio and io_port */
12235 break;
12236 }
12237}
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +000012238
12239static int bnx2x_8727_common_init_phy(struct bnx2x *bp,
12240 u32 shmem_base_path[],
12241 u32 shmem2_base_path[], u8 phy_index,
12242 u32 chip_id)
Eilon Greenstein4d295db2009-07-21 05:47:47 +000012243{
Yaniv Rosnera8db5b42011-01-31 04:22:28 +000012244 s8 port, reset_gpio;
Eilon Greenstein4d295db2009-07-21 05:47:47 +000012245 u32 swap_val, swap_override;
Yaniv Rosnere10bc842010-09-07 11:40:50 +000012246 struct bnx2x_phy phy[PORT_MAX];
12247 struct bnx2x_phy *phy_blk[PORT_MAX];
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000012248 s8 port_of_path;
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000012249 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
12250 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
Eilon Greenstein4d295db2009-07-21 05:47:47 +000012251
Yaniv Rosnera8db5b42011-01-31 04:22:28 +000012252 reset_gpio = MISC_REGISTERS_GPIO_1;
Yaniv Rosnera22f0782010-09-07 11:41:20 +000012253 port = 1;
12254
Yaniv Rosnera8db5b42011-01-31 04:22:28 +000012255 /*
12256 * Retrieve the reset gpio/port which control the reset.
12257 * Default is GPIO1, PORT1
12258 */
12259 bnx2x_get_ext_phy_reset_gpio(bp, shmem_base_path[0],
12260 (u8 *)&reset_gpio, (u8 *)&port);
Yaniv Rosnera22f0782010-09-07 11:41:20 +000012261
12262 /* Calculate the port based on port swap */
12263 port ^= (swap_val && swap_override);
12264
Yaniv Rosnera8db5b42011-01-31 04:22:28 +000012265 /* Initiate PHY reset*/
12266 bnx2x_set_gpio(bp, reset_gpio, MISC_REGISTERS_GPIO_OUTPUT_LOW,
12267 port);
12268 msleep(1);
12269 bnx2x_set_gpio(bp, reset_gpio, MISC_REGISTERS_GPIO_OUTPUT_HIGH,
12270 port);
12271
Eilon Greenstein4d295db2009-07-21 05:47:47 +000012272 msleep(5);
12273
12274 /* PART1 - Reset both phys */
Yaniv Rosnera22f0782010-09-07 11:41:20 +000012275 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000012276 u32 shmem_base, shmem2_base;
12277
12278 /* In E2, same phy is using for port0 of the two paths */
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000012279 if (CHIP_IS_E1x(bp)) {
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000012280 shmem_base = shmem_base_path[0];
12281 shmem2_base = shmem2_base_path[0];
12282 port_of_path = port;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000012283 } else {
12284 shmem_base = shmem_base_path[port];
12285 shmem2_base = shmem2_base_path[port];
12286 port_of_path = 0;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000012287 }
12288
Eilon Greenstein4d295db2009-07-21 05:47:47 +000012289 /* Extract the ext phy address for the port */
Yaniv Rosnera22f0782010-09-07 11:41:20 +000012290 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000012291 port_of_path, &phy[port]) !=
Yaniv Rosnere10bc842010-09-07 11:40:50 +000012292 0) {
12293 DP(NETIF_MSG_LINK, "populate phy failed\n");
12294 return -EINVAL;
12295 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +000012296 /* disable attentions */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000012297 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 +
12298 port_of_path*4,
12299 (NIG_MASK_XGXS0_LINK_STATUS |
12300 NIG_MASK_XGXS0_LINK10G |
12301 NIG_MASK_SERDES0_LINK_STATUS |
12302 NIG_MASK_MI_INT));
Eilon Greenstein4d295db2009-07-21 05:47:47 +000012303
Eilon Greenstein4d295db2009-07-21 05:47:47 +000012304
12305 /* Reset the phy */
Yaniv Rosnere10bc842010-09-07 11:40:50 +000012306 bnx2x_cl45_write(bp, &phy[port],
Yaniv Rosnercd88cce2011-01-31 04:21:34 +000012307 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
Eilon Greenstein4d295db2009-07-21 05:47:47 +000012308 }
12309
12310 /* Add delay of 150ms after reset */
12311 msleep(150);
Yaniv Rosnere10bc842010-09-07 11:40:50 +000012312 if (phy[PORT_0].addr & 0x1) {
12313 phy_blk[PORT_0] = &(phy[PORT_1]);
12314 phy_blk[PORT_1] = &(phy[PORT_0]);
12315 } else {
12316 phy_blk[PORT_0] = &(phy[PORT_0]);
12317 phy_blk[PORT_1] = &(phy[PORT_1]);
12318 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +000012319 /* PART2 - Download firmware to both phys */
Yaniv Rosnere10bc842010-09-07 11:40:50 +000012320 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000012321 if (CHIP_IS_E1x(bp))
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000012322 port_of_path = port;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000012323 else
12324 port_of_path = 0;
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000012325 DP(NETIF_MSG_LINK, "Loading spirom for phy address 0x%x\n",
12326 phy_blk[port]->addr);
Yaniv Rosner5c99274b2011-01-18 04:33:36 +000012327 if (bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port],
12328 port_of_path))
Eilon Greenstein4d295db2009-07-21 05:47:47 +000012329 return -EINVAL;
Yaniv Rosner85242ee2011-07-05 01:06:53 +000012330 /* Disable PHY transmitter output */
12331 bnx2x_cl45_write(bp, phy_blk[port],
12332 MDIO_PMA_DEVAD,
12333 MDIO_PMA_REG_TX_DISABLE, 1);
Eilon Greenstein4d295db2009-07-21 05:47:47 +000012334
Yaniv Rosner5c99274b2011-01-18 04:33:36 +000012335 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +000012336 return 0;
12337}
12338
Yaniv Rosner521683d2011-11-28 00:49:48 +000012339static int bnx2x_84833_common_init_phy(struct bnx2x *bp,
12340 u32 shmem_base_path[],
12341 u32 shmem2_base_path[],
12342 u8 phy_index,
12343 u32 chip_id)
12344{
12345 u8 reset_gpios;
Yaniv Rosner521683d2011-11-28 00:49:48 +000012346 reset_gpios = bnx2x_84833_get_reset_gpios(bp, shmem_base_path, chip_id);
12347 bnx2x_set_mult_gpio(bp, reset_gpios, MISC_REGISTERS_GPIO_OUTPUT_LOW);
12348 udelay(10);
12349 bnx2x_set_mult_gpio(bp, reset_gpios, MISC_REGISTERS_GPIO_OUTPUT_HIGH);
12350 DP(NETIF_MSG_LINK, "84833 reset pulse on pin values 0x%x\n",
12351 reset_gpios);
Yaniv Rosner521683d2011-11-28 00:49:48 +000012352 return 0;
12353}
12354
Yaniv Rosner11b2ec62012-01-17 02:33:25 +000012355static int bnx2x_84833_pre_init_phy(struct bnx2x *bp,
12356 struct bnx2x_phy *phy)
12357{
12358 u16 val, cnt;
12359 /* Wait for FW completing its initialization. */
12360 for (cnt = 0; cnt < 1500; cnt++) {
12361 bnx2x_cl45_read(bp, phy,
12362 MDIO_PMA_DEVAD,
12363 MDIO_PMA_REG_CTRL, &val);
12364 if (!(val & (1<<15)))
12365 break;
12366 msleep(1);
12367 }
12368 if (cnt >= 1500) {
12369 DP(NETIF_MSG_LINK, "84833 reset timeout\n");
12370 return -EINVAL;
12371 }
12372
12373 /* Put the port in super isolate mode. */
12374 bnx2x_cl45_read(bp, phy,
12375 MDIO_CTL_DEVAD,
12376 MDIO_84833_TOP_CFG_XGPHY_STRAP1, &val);
12377 val |= MDIO_84833_SUPER_ISOLATE;
12378 bnx2x_cl45_write(bp, phy,
12379 MDIO_CTL_DEVAD,
12380 MDIO_84833_TOP_CFG_XGPHY_STRAP1, val);
12381
12382 /* Save spirom version */
12383 bnx2x_save_848xx_spirom_version(phy, bp, PORT_0);
12384 return 0;
12385}
12386
12387int bnx2x_pre_init_phy(struct bnx2x *bp,
12388 u32 shmem_base,
12389 u32 shmem2_base,
12390 u32 chip_id)
12391{
12392 int rc = 0;
12393 struct bnx2x_phy phy;
12394 bnx2x_set_mdio_clk(bp, chip_id, PORT_0);
12395 if (bnx2x_populate_phy(bp, EXT_PHY1, shmem_base, shmem2_base,
12396 PORT_0, &phy)) {
12397 DP(NETIF_MSG_LINK, "populate_phy failed\n");
12398 return -EINVAL;
12399 }
12400 switch (phy.type) {
12401 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833:
12402 rc = bnx2x_84833_pre_init_phy(bp, &phy);
12403 break;
12404 default:
12405 break;
12406 }
12407 return rc;
12408}
Yaniv Rosner521683d2011-11-28 00:49:48 +000012409
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +000012410static int bnx2x_ext_phy_common_init(struct bnx2x *bp, u32 shmem_base_path[],
12411 u32 shmem2_base_path[], u8 phy_index,
12412 u32 ext_phy_type, u32 chip_id)
Yaniv Rosner6bbca912008-08-13 15:57:28 -070012413{
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +000012414 int rc = 0;
Yaniv Rosner6bbca912008-08-13 15:57:28 -070012415
12416 switch (ext_phy_type) {
12417 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000012418 rc = bnx2x_8073_common_init_phy(bp, shmem_base_path,
12419 shmem2_base_path,
12420 phy_index, chip_id);
Yaniv Rosner6bbca912008-08-13 15:57:28 -070012421 break;
Yaniv Rosnere4d78f12011-05-31 21:25:55 +000012422 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722:
Eilon Greenstein4d295db2009-07-21 05:47:47 +000012423 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
12424 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000012425 rc = bnx2x_8727_common_init_phy(bp, shmem_base_path,
12426 shmem2_base_path,
12427 phy_index, chip_id);
Eilon Greenstein4d295db2009-07-21 05:47:47 +000012428 break;
12429
Eilon Greenstein589abe32009-02-12 08:36:55 +000012430 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +000012431 /*
12432 * GPIO1 affects both ports, so there's need to pull
12433 * it for single port alone
12434 */
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000012435 rc = bnx2x_8726_common_init_phy(bp, shmem_base_path,
12436 shmem2_base_path,
12437 phy_index, chip_id);
Yaniv Rosnera22f0782010-09-07 11:41:20 +000012438 break;
Yaniv Rosner0d40f0d2011-06-14 01:34:27 +000012439 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833:
12440 /*
12441 * GPIO3's are linked, and so both need to be toggled
12442 * to obtain required 2us pulse.
12443 */
Yaniv Rosner521683d2011-11-28 00:49:48 +000012444 rc = bnx2x_84833_common_init_phy(bp, shmem_base_path,
12445 shmem2_base_path,
12446 phy_index, chip_id);
Yaniv Rosner0d40f0d2011-06-14 01:34:27 +000012447 break;
Yaniv Rosnera22f0782010-09-07 11:41:20 +000012448 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
12449 rc = -EINVAL;
Yaniv Rosner4f60dab2009-11-05 19:18:23 +020012450 break;
Yaniv Rosner6bbca912008-08-13 15:57:28 -070012451 default:
12452 DP(NETIF_MSG_LINK,
Yaniv Rosner2cf7acf2011-01-31 04:21:55 +000012453 "ext_phy 0x%x common init not required\n",
12454 ext_phy_type);
Yaniv Rosner6bbca912008-08-13 15:57:28 -070012455 break;
12456 }
12457
Yaniv Rosner6d870c32011-01-31 04:22:20 +000012458 if (rc != 0)
12459 netdev_err(bp->dev, "Warning: PHY was not initialized,"
12460 " Port %d\n",
12461 0);
Yaniv Rosner6bbca912008-08-13 15:57:28 -070012462 return rc;
12463}
12464
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +000012465int bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base_path[],
12466 u32 shmem2_base_path[], u32 chip_id)
Yaniv Rosnera22f0782010-09-07 11:41:20 +000012467{
Yaniv Rosnerfcf5b652011-05-31 21:26:28 +000012468 int rc = 0;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000012469 u32 phy_ver, val;
12470 u8 phy_index = 0;
Yaniv Rosnera22f0782010-09-07 11:41:20 +000012471 u32 ext_phy_type, ext_phy_config;
Yaniv Rosnera198c142011-05-31 21:29:42 +000012472 bnx2x_set_mdio_clk(bp, chip_id, PORT_0);
12473 bnx2x_set_mdio_clk(bp, chip_id, PORT_1);
Yaniv Rosnera22f0782010-09-07 11:41:20 +000012474 DP(NETIF_MSG_LINK, "Begin common phy init\n");
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000012475 if (CHIP_IS_E3(bp)) {
12476 /* Enable EPIO */
12477 val = REG_RD(bp, MISC_REG_GEN_PURP_HWG);
12478 REG_WR(bp, MISC_REG_GEN_PURP_HWG, val | 1);
12479 }
Yaniv Rosnerb21a3422011-01-18 04:33:24 +000012480 /* Check if common init was already done */
12481 phy_ver = REG_RD(bp, shmem_base_path[0] +
12482 offsetof(struct shmem_region,
12483 port_mb[PORT_0].ext_phy_fw_version));
12484 if (phy_ver) {
12485 DP(NETIF_MSG_LINK, "Not doing common init; phy ver is 0x%x\n",
12486 phy_ver);
12487 return 0;
12488 }
12489
Yaniv Rosnera22f0782010-09-07 11:41:20 +000012490 /* Read the ext_phy_type for arbitrary port(0) */
12491 for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
12492 phy_index++) {
12493 ext_phy_config = bnx2x_get_ext_phy_config(bp,
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000012494 shmem_base_path[0],
Yaniv Rosnera22f0782010-09-07 11:41:20 +000012495 phy_index, 0);
12496 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
Dmitry Kravkovf2e08992010-10-06 03:28:26 +000012497 rc |= bnx2x_ext_phy_common_init(bp, shmem_base_path,
12498 shmem2_base_path,
12499 phy_index, ext_phy_type,
12500 chip_id);
Yaniv Rosnera22f0782010-09-07 11:41:20 +000012501 }
12502 return rc;
12503}
12504
Yaniv Rosner3deb8162011-06-14 01:34:33 +000012505static void bnx2x_check_over_curr(struct link_params *params,
12506 struct link_vars *vars)
12507{
12508 struct bnx2x *bp = params->bp;
12509 u32 cfg_pin;
12510 u8 port = params->port;
12511 u32 pin_val;
12512
12513 cfg_pin = (REG_RD(bp, params->shmem_base +
12514 offsetof(struct shmem_region,
12515 dev_info.port_hw_config[port].e3_cmn_pin_cfg1)) &
12516 PORT_HW_CFG_E3_OVER_CURRENT_MASK) >>
12517 PORT_HW_CFG_E3_OVER_CURRENT_SHIFT;
12518
12519 /* Ignore check if no external input PIN available */
12520 if (bnx2x_get_cfg_pin(bp, cfg_pin, &pin_val) != 0)
12521 return;
12522
12523 if (!pin_val) {
12524 if ((vars->phy_flags & PHY_OVER_CURRENT_FLAG) == 0) {
12525 netdev_err(bp->dev, "Error: Power fault on Port %d has"
12526 " been detected and the power to "
12527 "that SFP+ module has been removed"
12528 " to prevent failure of the card."
12529 " Please remove the SFP+ module and"
12530 " restart the system to clear this"
12531 " error.\n",
12532 params->port);
12533 vars->phy_flags |= PHY_OVER_CURRENT_FLAG;
12534 }
12535 } else
12536 vars->phy_flags &= ~PHY_OVER_CURRENT_FLAG;
12537}
12538
12539static void bnx2x_analyze_link_error(struct link_params *params,
12540 struct link_vars *vars, u32 lss_status)
12541{
12542 struct bnx2x *bp = params->bp;
12543 /* Compare new value with previous value */
12544 u8 led_mode;
12545 u32 half_open_conn = (vars->phy_flags & PHY_HALF_OPEN_CONN_FLAG) > 0;
12546
Yaniv Rosner3deb8162011-06-14 01:34:33 +000012547 if ((lss_status ^ half_open_conn) == 0)
12548 return;
12549
12550 /* If values differ */
12551 DP(NETIF_MSG_LINK, "Link changed:%x %x->%x\n", vars->link_up,
12552 half_open_conn, lss_status);
12553
12554 /*
12555 * a. Update shmem->link_status accordingly
12556 * b. Update link_vars->link_up
12557 */
12558 if (lss_status) {
Yaniv Rosnerde6f3372011-08-02 22:59:25 +000012559 DP(NETIF_MSG_LINK, "Remote Fault detected !!!\n");
Yaniv Rosner3deb8162011-06-14 01:34:33 +000012560 vars->link_status &= ~LINK_STATUS_LINK_UP;
12561 vars->link_up = 0;
12562 vars->phy_flags |= PHY_HALF_OPEN_CONN_FLAG;
12563 /*
12564 * Set LED mode to off since the PHY doesn't know about these
12565 * errors
12566 */
12567 led_mode = LED_MODE_OFF;
12568 } else {
Yaniv Rosnerde6f3372011-08-02 22:59:25 +000012569 DP(NETIF_MSG_LINK, "Remote Fault cleared\n");
Yaniv Rosner3deb8162011-06-14 01:34:33 +000012570 vars->link_status |= LINK_STATUS_LINK_UP;
12571 vars->link_up = 1;
12572 vars->phy_flags &= ~PHY_HALF_OPEN_CONN_FLAG;
12573 led_mode = LED_MODE_OPER;
12574 }
12575 /* Update the LED according to the link state */
12576 bnx2x_set_led(params, vars, led_mode, SPEED_10000);
12577
12578 /* Update link status in the shared memory */
12579 bnx2x_update_mng(params, vars->link_status);
12580
12581 /* C. Trigger General Attention */
12582 vars->periodic_flags |= PERIODIC_FLAGS_LINK_EVENT;
12583 bnx2x_notify_link_changed(bp);
12584}
12585
Yaniv Rosnerde6f3372011-08-02 22:59:25 +000012586/******************************************************************************
12587* Description:
12588* This function checks for half opened connection change indication.
12589* When such change occurs, it calls the bnx2x_analyze_link_error
12590* to check if Remote Fault is set or cleared. Reception of remote fault
12591* status message in the MAC indicates that the peer's MAC has detected
12592* a fault, for example, due to break in the TX side of fiber.
12593*
12594******************************************************************************/
Yaniv Rosner3deb8162011-06-14 01:34:33 +000012595static void bnx2x_check_half_open_conn(struct link_params *params,
12596 struct link_vars *vars)
12597{
12598 struct bnx2x *bp = params->bp;
12599 u32 lss_status = 0;
12600 u32 mac_base;
12601 /* In case link status is physically up @ 10G do */
12602 if ((vars->phy_flags & PHY_PHYSICAL_LINK_FLAG) == 0)
12603 return;
12604
Yaniv Rosnerde6f3372011-08-02 22:59:25 +000012605 if (CHIP_IS_E3(bp) &&
Yaniv Rosner3deb8162011-06-14 01:34:33 +000012606 (REG_RD(bp, MISC_REG_RESET_REG_2) &
Yaniv Rosnerde6f3372011-08-02 22:59:25 +000012607 (MISC_REGISTERS_RESET_REG_2_XMAC))) {
12608 /* Check E3 XMAC */
12609 /*
12610 * Note that link speed cannot be queried here, since it may be
12611 * zero while link is down. In case UMAC is active, LSS will
12612 * simply not be set
12613 */
12614 mac_base = (params->port) ? GRCBASE_XMAC1 : GRCBASE_XMAC0;
12615
12616 /* Clear stick bits (Requires rising edge) */
12617 REG_WR(bp, mac_base + XMAC_REG_CLEAR_RX_LSS_STATUS, 0);
12618 REG_WR(bp, mac_base + XMAC_REG_CLEAR_RX_LSS_STATUS,
12619 XMAC_CLEAR_RX_LSS_STATUS_REG_CLEAR_LOCAL_FAULT_STATUS |
12620 XMAC_CLEAR_RX_LSS_STATUS_REG_CLEAR_REMOTE_FAULT_STATUS);
12621 if (REG_RD(bp, mac_base + XMAC_REG_RX_LSS_STATUS))
12622 lss_status = 1;
12623
12624 bnx2x_analyze_link_error(params, vars, lss_status);
12625 } else if (REG_RD(bp, MISC_REG_RESET_REG_2) &
12626 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << params->port)) {
Yaniv Rosner3deb8162011-06-14 01:34:33 +000012627 /* Check E1X / E2 BMAC */
12628 u32 lss_status_reg;
12629 u32 wb_data[2];
12630 mac_base = params->port ? NIG_REG_INGRESS_BMAC1_MEM :
12631 NIG_REG_INGRESS_BMAC0_MEM;
12632 /* Read BIGMAC_REGISTER_RX_LSS_STATUS */
12633 if (CHIP_IS_E2(bp))
12634 lss_status_reg = BIGMAC2_REGISTER_RX_LSS_STAT;
12635 else
12636 lss_status_reg = BIGMAC_REGISTER_RX_LSS_STATUS;
12637
12638 REG_RD_DMAE(bp, mac_base + lss_status_reg, wb_data, 2);
12639 lss_status = (wb_data[0] > 0);
12640
12641 bnx2x_analyze_link_error(params, vars, lss_status);
12642 }
12643}
12644
12645void bnx2x_period_func(struct link_params *params, struct link_vars *vars)
12646{
12647 struct bnx2x *bp = params->bp;
Yaniv Rosnerde6f3372011-08-02 22:59:25 +000012648 u16 phy_idx;
Yaniv Rosnerde6f3372011-08-02 22:59:25 +000012649 for (phy_idx = INT_PHY; phy_idx < MAX_PHYS; phy_idx++) {
12650 if (params->phy[phy_idx].flags & FLAGS_TX_ERROR_CHECK) {
12651 bnx2x_set_aer_mmd(params, &params->phy[phy_idx]);
12652 bnx2x_check_half_open_conn(params, vars);
12653 break;
12654 }
12655 }
12656
Yaniv Rosnera9077bf2011-10-27 05:09:46 +000012657 if (CHIP_IS_E3(bp)) {
12658 struct bnx2x_phy *phy = &params->phy[INT_PHY];
12659 bnx2x_set_aer_mmd(params, phy);
Yaniv Rosner3deb8162011-06-14 01:34:33 +000012660 bnx2x_check_over_curr(params, vars);
Yaniv Rosnera9077bf2011-10-27 05:09:46 +000012661 bnx2x_warpcore_config_runtime(phy, params, vars);
12662 }
12663
Yaniv Rosner3deb8162011-06-14 01:34:33 +000012664}
12665
Yaniv Rosnera22f0782010-09-07 11:41:20 +000012666u8 bnx2x_hw_lock_required(struct bnx2x *bp, u32 shmem_base, u32 shmem2_base)
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +000012667{
12668 u8 phy_index;
12669 struct bnx2x_phy phy;
12670 for (phy_index = INT_PHY; phy_index < MAX_PHYS;
12671 phy_index++) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +000012672 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +000012673 0, &phy) != 0) {
12674 DP(NETIF_MSG_LINK, "populate phy failed\n");
12675 return 0;
12676 }
12677
12678 if (phy.flags & FLAGS_HW_LOCK_REQUIRED)
12679 return 1;
12680 }
12681 return 0;
12682}
12683
12684u8 bnx2x_fan_failure_det_req(struct bnx2x *bp,
12685 u32 shmem_base,
Yaniv Rosnera22f0782010-09-07 11:41:20 +000012686 u32 shmem2_base,
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +000012687 u8 port)
12688{
12689 u8 phy_index, fan_failure_det_req = 0;
12690 struct bnx2x_phy phy;
12691 for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
12692 phy_index++) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +000012693 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +000012694 port, &phy)
12695 != 0) {
12696 DP(NETIF_MSG_LINK, "populate phy failed\n");
12697 return 0;
12698 }
12699 fan_failure_det_req |= (phy.flags &
12700 FLAGS_FAN_FAILURE_DET_REQ);
12701 }
12702 return fan_failure_det_req;
12703}
12704
12705void bnx2x_hw_reset_phy(struct link_params *params)
12706{
12707 u8 phy_index;
Yaniv Rosner985848f2011-07-05 01:06:48 +000012708 struct bnx2x *bp = params->bp;
12709 bnx2x_update_mng(params, 0);
12710 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4,
12711 (NIG_MASK_XGXS0_LINK_STATUS |
12712 NIG_MASK_XGXS0_LINK10G |
12713 NIG_MASK_SERDES0_LINK_STATUS |
12714 NIG_MASK_MI_INT));
12715
12716 for (phy_index = INT_PHY; phy_index < MAX_PHYS;
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +000012717 phy_index++) {
12718 if (params->phy[phy_index].hw_reset) {
12719 params->phy[phy_index].hw_reset(
12720 &params->phy[phy_index],
12721 params);
12722 params->phy[phy_index] = phy_null;
12723 }
12724 }
12725}
Yaniv Rosner020c7e32011-05-31 21:28:43 +000012726
12727void bnx2x_init_mod_abs_int(struct bnx2x *bp, struct link_vars *vars,
12728 u32 chip_id, u32 shmem_base, u32 shmem2_base,
12729 u8 port)
12730{
12731 u8 gpio_num = 0xff, gpio_port = 0xff, phy_index;
12732 u32 val;
12733 u32 offset, aeu_mask, swap_val, swap_override, sync_offset;
Yaniv Rosner3c9ada22011-06-14 01:34:12 +000012734 if (CHIP_IS_E3(bp)) {
12735 if (bnx2x_get_mod_abs_int_cfg(bp, chip_id,
12736 shmem_base,
12737 port,
12738 &gpio_num,
12739 &gpio_port) != 0)
12740 return;
12741 } else {
Yaniv Rosner020c7e32011-05-31 21:28:43 +000012742 struct bnx2x_phy phy;
12743 for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
12744 phy_index++) {
12745 if (bnx2x_populate_phy(bp, phy_index, shmem_base,
12746 shmem2_base, port, &phy)
12747 != 0) {
12748 DP(NETIF_MSG_LINK, "populate phy failed\n");
12749 return;
12750 }
12751 if (phy.type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) {
12752 gpio_num = MISC_REGISTERS_GPIO_3;
12753 gpio_port = port;
12754 break;
12755 }
12756 }
12757 }
12758
12759 if (gpio_num == 0xff)
12760 return;
12761
12762 /* Set GPIO3 to trigger SFP+ module insertion/removal */
12763 bnx2x_set_gpio(bp, gpio_num, MISC_REGISTERS_GPIO_INPUT_HI_Z, gpio_port);
12764
12765 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
12766 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
12767 gpio_port ^= (swap_val && swap_override);
12768
12769 vars->aeu_int_mask = AEU_INPUTS_ATTN_BITS_GPIO0_FUNCTION_0 <<
12770 (gpio_num + (gpio_port << 2));
12771
12772 sync_offset = shmem_base +
12773 offsetof(struct shmem_region,
12774 dev_info.port_hw_config[port].aeu_int_mask);
12775 REG_WR(bp, sync_offset, vars->aeu_int_mask);
12776
12777 DP(NETIF_MSG_LINK, "Setting MOD_ABS (GPIO%d_P%d) AEU to 0x%x\n",
12778 gpio_num, gpio_port, vars->aeu_int_mask);
12779
12780 if (port == 0)
12781 offset = MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0;
12782 else
12783 offset = MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0;
12784
12785 /* Open appropriate AEU for interrupts */
12786 aeu_mask = REG_RD(bp, offset);
12787 aeu_mask |= vars->aeu_int_mask;
12788 REG_WR(bp, offset, aeu_mask);
12789
12790 /* Enable the GPIO to trigger interrupt */
12791 val = REG_RD(bp, MISC_REG_GPIO_EVENT_EN);
12792 val |= 1 << (gpio_num + (gpio_port << 2));
12793 REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val);
12794}