blob: 36fa356c74fab3a52c8a09af3fdb78efe1394f31 [file] [log] [blame]
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001/* Copyright 2008 Broadcom Corporation
2 *
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
17#include <linux/kernel.h>
18#include <linux/errno.h>
19#include <linux/pci.h>
20#include <linux/netdevice.h>
21#include <linux/delay.h>
22#include <linux/ethtool.h>
23#include <linux/mutex.h>
24#include <linux/version.h>
25
26#include "bnx2x_reg.h"
27#include "bnx2x_fw_defs.h"
28#include "bnx2x_hsi.h"
29#include "bnx2x_link.h"
30#include "bnx2x.h"
31
32/********************************************************/
33#define SUPPORT_CL73 0 /* Currently no */
34#define ETH_HLEN 14
35#define ETH_OVREHEAD (ETH_HLEN + 8)/* 8 for CRC + VLAN*/
36#define ETH_MIN_PACKET_SIZE 60
37#define ETH_MAX_PACKET_SIZE 1500
38#define ETH_MAX_JUMBO_PACKET_SIZE 9600
39#define MDIO_ACCESS_TIMEOUT 1000
40#define BMAC_CONTROL_RX_ENABLE 2
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070041
42/***********************************************************/
43/* Shortcut definitions */
44/***********************************************************/
45
46#define NIG_STATUS_XGXS0_LINK10G \
47 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK10G
48#define NIG_STATUS_XGXS0_LINK_STATUS \
49 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS
50#define NIG_STATUS_XGXS0_LINK_STATUS_SIZE \
51 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS_SIZE
52#define NIG_STATUS_SERDES0_LINK_STATUS \
53 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_SERDES0_LINK_STATUS
54#define NIG_MASK_MI_INT \
55 NIG_MASK_INTERRUPT_PORT0_REG_MASK_EMAC0_MISC_MI_INT
56#define NIG_MASK_XGXS0_LINK10G \
57 NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK10G
58#define NIG_MASK_XGXS0_LINK_STATUS \
59 NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK_STATUS
60#define NIG_MASK_SERDES0_LINK_STATUS \
61 NIG_MASK_INTERRUPT_PORT0_REG_MASK_SERDES0_LINK_STATUS
62
63#define MDIO_AN_CL73_OR_37_COMPLETE \
64 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE | \
65 MDIO_GP_STATUS_TOP_AN_STATUS1_CL37_AUTONEG_COMPLETE)
66
67#define XGXS_RESET_BITS \
68 (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_RSTB_HW | \
69 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_IDDQ | \
70 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN | \
71 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN_SD | \
72 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_TXD_FIFO_RSTB)
73
74#define SERDES_RESET_BITS \
75 (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_RSTB_HW | \
76 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_IDDQ | \
77 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN | \
78 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN_SD)
79
80#define AUTONEG_CL37 SHARED_HW_CFG_AN_ENABLE_CL37
81#define AUTONEG_CL73 SHARED_HW_CFG_AN_ENABLE_CL73
82#define AUTONEG_BAM SHARED_HW_CFG_AN_ENABLE_BAM
83#define AUTONEG_PARALLEL \
84 SHARED_HW_CFG_AN_ENABLE_PARALLEL_DETECTION
85#define AUTONEG_SGMII_FIBER_AUTODET \
86 SHARED_HW_CFG_AN_EN_SGMII_FIBER_AUTO_DETECT
87#define AUTONEG_REMOTE_PHY SHARED_HW_CFG_AN_ENABLE_REMOTE_PHY
88
89#define GP_STATUS_PAUSE_RSOLUTION_TXSIDE \
90 MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_TXSIDE
91#define GP_STATUS_PAUSE_RSOLUTION_RXSIDE \
92 MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_RXSIDE
93#define GP_STATUS_SPEED_MASK \
94 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_MASK
95#define GP_STATUS_10M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10M
96#define GP_STATUS_100M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_100M
97#define GP_STATUS_1G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G
98#define GP_STATUS_2_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_2_5G
99#define GP_STATUS_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_5G
100#define GP_STATUS_6G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_6G
101#define GP_STATUS_10G_HIG \
102 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_HIG
103#define GP_STATUS_10G_CX4 \
104 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_CX4
105#define GP_STATUS_12G_HIG \
106 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12G_HIG
107#define GP_STATUS_12_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12_5G
108#define GP_STATUS_13G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_13G
109#define GP_STATUS_15G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_15G
110#define GP_STATUS_16G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_16G
111#define GP_STATUS_1G_KX MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G_KX
112#define GP_STATUS_10G_KX4 \
113 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_KX4
114
115#define LINK_10THD LINK_STATUS_SPEED_AND_DUPLEX_10THD
116#define LINK_10TFD LINK_STATUS_SPEED_AND_DUPLEX_10TFD
117#define LINK_100TXHD LINK_STATUS_SPEED_AND_DUPLEX_100TXHD
118#define LINK_100T4 LINK_STATUS_SPEED_AND_DUPLEX_100T4
119#define LINK_100TXFD LINK_STATUS_SPEED_AND_DUPLEX_100TXFD
120#define LINK_1000THD LINK_STATUS_SPEED_AND_DUPLEX_1000THD
121#define LINK_1000TFD LINK_STATUS_SPEED_AND_DUPLEX_1000TFD
122#define LINK_1000XFD LINK_STATUS_SPEED_AND_DUPLEX_1000XFD
123#define LINK_2500THD LINK_STATUS_SPEED_AND_DUPLEX_2500THD
124#define LINK_2500TFD LINK_STATUS_SPEED_AND_DUPLEX_2500TFD
125#define LINK_2500XFD LINK_STATUS_SPEED_AND_DUPLEX_2500XFD
126#define LINK_10GTFD LINK_STATUS_SPEED_AND_DUPLEX_10GTFD
127#define LINK_10GXFD LINK_STATUS_SPEED_AND_DUPLEX_10GXFD
128#define LINK_12GTFD LINK_STATUS_SPEED_AND_DUPLEX_12GTFD
129#define LINK_12GXFD LINK_STATUS_SPEED_AND_DUPLEX_12GXFD
130#define LINK_12_5GTFD LINK_STATUS_SPEED_AND_DUPLEX_12_5GTFD
131#define LINK_12_5GXFD LINK_STATUS_SPEED_AND_DUPLEX_12_5GXFD
132#define LINK_13GTFD LINK_STATUS_SPEED_AND_DUPLEX_13GTFD
133#define LINK_13GXFD LINK_STATUS_SPEED_AND_DUPLEX_13GXFD
134#define LINK_15GTFD LINK_STATUS_SPEED_AND_DUPLEX_15GTFD
135#define LINK_15GXFD LINK_STATUS_SPEED_AND_DUPLEX_15GXFD
136#define LINK_16GTFD LINK_STATUS_SPEED_AND_DUPLEX_16GTFD
137#define LINK_16GXFD LINK_STATUS_SPEED_AND_DUPLEX_16GXFD
138
139#define PHY_XGXS_FLAG 0x1
140#define PHY_SGMII_FLAG 0x2
141#define PHY_SERDES_FLAG 0x4
142
143/**********************************************************/
144/* INTERFACE */
145/**********************************************************/
146#define CL45_WR_OVER_CL22(_bp, _port, _phy_addr, _bank, _addr, _val) \
147 bnx2x_cl45_write(_bp, _port, 0, _phy_addr, \
148 DEFAULT_PHY_DEV_ADDR, \
149 (_bank + (_addr & 0xf)), \
150 _val)
151
152#define CL45_RD_OVER_CL22(_bp, _port, _phy_addr, _bank, _addr, _val) \
153 bnx2x_cl45_read(_bp, _port, 0, _phy_addr, \
154 DEFAULT_PHY_DEV_ADDR, \
155 (_bank + (_addr & 0xf)), \
156 _val)
157
158static void bnx2x_set_phy_mdio(struct link_params *params)
159{
160 struct bnx2x *bp = params->bp;
161 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_ST +
162 params->port*0x18, 0);
163 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + params->port*0x18,
164 DEFAULT_PHY_DEV_ADDR);
165}
166
167static u32 bnx2x_bits_en(struct bnx2x *bp, u32 reg, u32 bits)
168{
169 u32 val = REG_RD(bp, reg);
170
171 val |= bits;
172 REG_WR(bp, reg, val);
173 return val;
174}
175
176static u32 bnx2x_bits_dis(struct bnx2x *bp, u32 reg, u32 bits)
177{
178 u32 val = REG_RD(bp, reg);
179
180 val &= ~bits;
181 REG_WR(bp, reg, val);
182 return val;
183}
184
185static void bnx2x_emac_init(struct link_params *params,
186 struct link_vars *vars)
187{
188 /* reset and unreset the emac core */
189 struct bnx2x *bp = params->bp;
190 u8 port = params->port;
191 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
192 u32 val;
193 u16 timeout;
194
195 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
196 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
197 udelay(5);
198 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
199 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
200
201 /* init emac - use read-modify-write */
202 /* self clear reset */
203 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
204 EMAC_WR(EMAC_REG_EMAC_MODE, (val | EMAC_MODE_RESET));
205
206 timeout = 200;
207 do
208 {
209 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
210 DP(NETIF_MSG_LINK, "EMAC reset reg is %u\n", val);
211 if (!timeout) {
212 DP(NETIF_MSG_LINK, "EMAC timeout!\n");
213 return;
214 }
215 timeout--;
216 }while (val & EMAC_MODE_RESET);
217
218 /* Set mac address */
219 val = ((params->mac_addr[0] << 8) |
220 params->mac_addr[1]);
221 EMAC_WR(EMAC_REG_EMAC_MAC_MATCH, val);
222
223 val = ((params->mac_addr[2] << 24) |
224 (params->mac_addr[3] << 16) |
225 (params->mac_addr[4] << 8) |
226 params->mac_addr[5]);
227 EMAC_WR(EMAC_REG_EMAC_MAC_MATCH + 4, val);
228}
229
230static u8 bnx2x_emac_enable(struct link_params *params,
231 struct link_vars *vars, u8 lb)
232{
233 struct bnx2x *bp = params->bp;
234 u8 port = params->port;
235 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
236 u32 val;
237
238 DP(NETIF_MSG_LINK, "enabling EMAC\n");
239
240 /* enable emac and not bmac */
241 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 1);
242
243 /* for paladium */
244 if (CHIP_REV_IS_EMUL(bp)) {
245 /* Use lane 1 (of lanes 0-3) */
246 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1);
247 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
248 port*4, 1);
249 }
250 /* for fpga */
251 else
252
253 if (CHIP_REV_IS_FPGA(bp)) {
254 /* Use lane 1 (of lanes 0-3) */
255 DP(NETIF_MSG_LINK, "bnx2x_emac_enable: Setting FPGA\n");
256
257 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1);
258 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4,
259 0);
260 } else
261 /* ASIC */
262 if (vars->phy_flags & PHY_XGXS_FLAG) {
263 u32 ser_lane = ((params->lane_config &
264 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
265 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
266
267 DP(NETIF_MSG_LINK, "XGXS\n");
268 /* select the master lanes (out of 0-3) */
269 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 +
270 port*4, ser_lane);
271 /* select XGXS */
272 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
273 port*4, 1);
274
275 } else { /* SerDes */
276 DP(NETIF_MSG_LINK, "SerDes\n");
277 /* select SerDes */
278 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
279 port*4, 0);
280 }
281
282 /* enable emac */
283 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 1);
284
285 if (CHIP_REV_IS_SLOW(bp)) {
286 /* config GMII mode */
287 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
288 EMAC_WR(EMAC_REG_EMAC_MODE,
289 (val | EMAC_MODE_PORT_GMII));
290 } else { /* ASIC */
291 /* pause enable/disable */
292 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
293 EMAC_RX_MODE_FLOW_EN);
294 if (vars->flow_ctrl & FLOW_CTRL_RX)
295 bnx2x_bits_en(bp, emac_base +
296 EMAC_REG_EMAC_RX_MODE,
297 EMAC_RX_MODE_FLOW_EN);
298
299 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700300 (EMAC_TX_MODE_EXT_PAUSE_EN |
301 EMAC_TX_MODE_FLOW_EN));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700302 if (vars->flow_ctrl & FLOW_CTRL_TX)
303 bnx2x_bits_en(bp, emac_base +
304 EMAC_REG_EMAC_TX_MODE,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700305 (EMAC_TX_MODE_EXT_PAUSE_EN |
306 EMAC_TX_MODE_FLOW_EN));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700307 }
308
309 /* KEEP_VLAN_TAG, promiscuous */
310 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_RX_MODE);
311 val |= EMAC_RX_MODE_KEEP_VLAN_TAG | EMAC_RX_MODE_PROMISCUOUS;
312 EMAC_WR(EMAC_REG_EMAC_RX_MODE, val);
313
314 /* Set Loopback */
315 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
316 if (lb)
317 val |= 0x810;
318 else
319 val &= ~0x810;
320 EMAC_WR(EMAC_REG_EMAC_MODE, val);
321
322 /* enable emac for jumbo packets */
323 EMAC_WR(EMAC_REG_EMAC_RX_MTU_SIZE,
324 (EMAC_RX_MTU_SIZE_JUMBO_ENA |
325 (ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD)));
326
327 /* strip CRC */
328 REG_WR(bp, NIG_REG_NIG_INGRESS_EMAC0_NO_CRC + port*4, 0x1);
329
330 /* disable the NIG in/out to the bmac */
331 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x0);
332 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, 0x0);
333 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x0);
334
335 /* enable the NIG in/out to the emac */
336 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x1);
337 val = 0;
338 if (vars->flow_ctrl & FLOW_CTRL_TX)
339 val = 1;
340
341 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, val);
342 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x1);
343
344 if (CHIP_REV_IS_EMUL(bp)) {
345 /* take the BigMac out of reset */
346 REG_WR(bp,
347 GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
348 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
349
350 /* enable access for bmac registers */
351 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
352 }
353
354 vars->mac_type = MAC_TYPE_EMAC;
355 return 0;
356}
357
358
359
360static u8 bnx2x_bmac_enable(struct link_params *params, struct link_vars *vars,
361 u8 is_lb)
362{
363 struct bnx2x *bp = params->bp;
364 u8 port = params->port;
365 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
366 NIG_REG_INGRESS_BMAC0_MEM;
367 u32 wb_data[2];
368 u32 val;
369
370 DP(NETIF_MSG_LINK, "Enabling BigMAC\n");
371 /* reset and unreset the BigMac */
372 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
373 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
374 msleep(1);
375
376 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
377 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
378
379 /* enable access for bmac registers */
380 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
381
382 /* XGXS control */
383 wb_data[0] = 0x3c;
384 wb_data[1] = 0;
385 REG_WR_DMAE(bp, bmac_addr +
386 BIGMAC_REGISTER_BMAC_XGXS_CONTROL,
387 wb_data, 2);
388
389 /* tx MAC SA */
390 wb_data[0] = ((params->mac_addr[2] << 24) |
391 (params->mac_addr[3] << 16) |
392 (params->mac_addr[4] << 8) |
393 params->mac_addr[5]);
394 wb_data[1] = ((params->mac_addr[0] << 8) |
395 params->mac_addr[1]);
396 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_SOURCE_ADDR,
397 wb_data, 2);
398
399 /* tx control */
400 val = 0xc0;
401 if (vars->flow_ctrl & FLOW_CTRL_TX)
402 val |= 0x800000;
403 wb_data[0] = val;
404 wb_data[1] = 0;
405 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_CONTROL,
406 wb_data, 2);
407
408 /* mac control */
409 val = 0x3;
410 if (is_lb) {
411 val |= 0x4;
412 DP(NETIF_MSG_LINK, "enable bmac loopback\n");
413 }
414 wb_data[0] = val;
415 wb_data[1] = 0;
416 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
417 wb_data, 2);
418
419
420 /* set rx mtu */
421 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
422 wb_data[1] = 0;
423 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_MAX_SIZE,
424 wb_data, 2);
425
426 /* rx control set to don't strip crc */
427 val = 0x14;
428 if (vars->flow_ctrl & FLOW_CTRL_RX)
429 val |= 0x20;
430 wb_data[0] = val;
431 wb_data[1] = 0;
432 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_CONTROL,
433 wb_data, 2);
434
435 /* set tx mtu */
436 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
437 wb_data[1] = 0;
438 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_MAX_SIZE,
439 wb_data, 2);
440
441 /* set cnt max size */
442 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
443 wb_data[1] = 0;
444 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_CNT_MAX_SIZE,
445 wb_data, 2);
446
447 /* configure safc */
448 wb_data[0] = 0x1000200;
449 wb_data[1] = 0;
450 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_LLFC_MSG_FLDS,
451 wb_data, 2);
452 /* fix for emulation */
453 if (CHIP_REV_IS_EMUL(bp)) {
454 wb_data[0] = 0xf000;
455 wb_data[1] = 0;
456 REG_WR_DMAE(bp,
457 bmac_addr + BIGMAC_REGISTER_TX_PAUSE_THRESHOLD,
458 wb_data, 2);
459 }
460
461 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0x1);
462 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 0x0);
463 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 0x0);
464 val = 0;
465 if (vars->flow_ctrl & FLOW_CTRL_TX)
466 val = 1;
467 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, val);
468 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x0);
469 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x0);
470 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, 0x0);
471 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x1);
472 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x1);
473
474 vars->mac_type = MAC_TYPE_BMAC;
475 return 0;
476}
477
478static void bnx2x_phy_deassert(struct link_params *params, u8 phy_flags)
479{
480 struct bnx2x *bp = params->bp;
481 u32 val;
482
483 if (phy_flags & PHY_XGXS_FLAG) {
484 DP(NETIF_MSG_LINK, "bnx2x_phy_deassert:XGXS\n");
485 val = XGXS_RESET_BITS;
486
487 } else { /* SerDes */
488 DP(NETIF_MSG_LINK, "bnx2x_phy_deassert:SerDes\n");
489 val = SERDES_RESET_BITS;
490 }
491
492 val = val << (params->port*16);
493
494 /* reset and unreset the SerDes/XGXS */
495 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
496 val);
497 udelay(500);
498 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET,
499 val);
500 bnx2x_set_phy_mdio(params);
501}
502
503void bnx2x_link_status_update(struct link_params *params,
504 struct link_vars *vars)
505{
506 struct bnx2x *bp = params->bp;
507 u8 link_10g;
508 u8 port = params->port;
509
510 if (params->switch_cfg == SWITCH_CFG_1G)
511 vars->phy_flags = PHY_SERDES_FLAG;
512 else
513 vars->phy_flags = PHY_XGXS_FLAG;
514 vars->link_status = REG_RD(bp, params->shmem_base +
515 offsetof(struct shmem_region,
516 port_mb[port].link_status));
517
518 vars->link_up = (vars->link_status & LINK_STATUS_LINK_UP);
519
520 if (vars->link_up) {
521 DP(NETIF_MSG_LINK, "phy link up\n");
522
523 vars->phy_link_up = 1;
524 vars->duplex = DUPLEX_FULL;
525 switch (vars->link_status &
526 LINK_STATUS_SPEED_AND_DUPLEX_MASK) {
527 case LINK_10THD:
528 vars->duplex = DUPLEX_HALF;
529 /* fall thru */
530 case LINK_10TFD:
531 vars->line_speed = SPEED_10;
532 break;
533
534 case LINK_100TXHD:
535 vars->duplex = DUPLEX_HALF;
536 /* fall thru */
537 case LINK_100T4:
538 case LINK_100TXFD:
539 vars->line_speed = SPEED_100;
540 break;
541
542 case LINK_1000THD:
543 vars->duplex = DUPLEX_HALF;
544 /* fall thru */
545 case LINK_1000TFD:
546 vars->line_speed = SPEED_1000;
547 break;
548
549 case LINK_2500THD:
550 vars->duplex = DUPLEX_HALF;
551 /* fall thru */
552 case LINK_2500TFD:
553 vars->line_speed = SPEED_2500;
554 break;
555
556 case LINK_10GTFD:
557 vars->line_speed = SPEED_10000;
558 break;
559
560 case LINK_12GTFD:
561 vars->line_speed = SPEED_12000;
562 break;
563
564 case LINK_12_5GTFD:
565 vars->line_speed = SPEED_12500;
566 break;
567
568 case LINK_13GTFD:
569 vars->line_speed = SPEED_13000;
570 break;
571
572 case LINK_15GTFD:
573 vars->line_speed = SPEED_15000;
574 break;
575
576 case LINK_16GTFD:
577 vars->line_speed = SPEED_16000;
578 break;
579
580 default:
581 break;
582 }
583
584 if (vars->link_status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED)
585 vars->flow_ctrl |= FLOW_CTRL_TX;
586 else
587 vars->flow_ctrl &= ~FLOW_CTRL_TX;
588
589 if (vars->link_status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED)
590 vars->flow_ctrl |= FLOW_CTRL_RX;
591 else
592 vars->flow_ctrl &= ~FLOW_CTRL_RX;
593
594 if (vars->phy_flags & PHY_XGXS_FLAG) {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700595 if (vars->line_speed &&
596 ((vars->line_speed == SPEED_10) ||
597 (vars->line_speed == SPEED_100))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700598 vars->phy_flags |= PHY_SGMII_FLAG;
599 } else {
600 vars->phy_flags &= ~PHY_SGMII_FLAG;
601 }
602 }
603
604 /* anything 10 and over uses the bmac */
605 link_10g = ((vars->line_speed == SPEED_10000) ||
606 (vars->line_speed == SPEED_12000) ||
607 (vars->line_speed == SPEED_12500) ||
608 (vars->line_speed == SPEED_13000) ||
609 (vars->line_speed == SPEED_15000) ||
610 (vars->line_speed == SPEED_16000));
611 if (link_10g)
612 vars->mac_type = MAC_TYPE_BMAC;
613 else
614 vars->mac_type = MAC_TYPE_EMAC;
615
616 } else { /* link down */
617 DP(NETIF_MSG_LINK, "phy link down\n");
618
619 vars->phy_link_up = 0;
620
621 vars->line_speed = 0;
622 vars->duplex = DUPLEX_FULL;
623 vars->flow_ctrl = FLOW_CTRL_NONE;
624
625 /* indicate no mac active */
626 vars->mac_type = MAC_TYPE_NONE;
627 }
628
629 DP(NETIF_MSG_LINK, "link_status 0x%x phy_link_up %x\n",
630 vars->link_status, vars->phy_link_up);
631 DP(NETIF_MSG_LINK, "line_speed %x duplex %x flow_ctrl 0x%x\n",
632 vars->line_speed, vars->duplex, vars->flow_ctrl);
633}
634
635static void bnx2x_update_mng(struct link_params *params, u32 link_status)
636{
637 struct bnx2x *bp = params->bp;
638 REG_WR(bp, params->shmem_base +
639 offsetof(struct shmem_region,
640 port_mb[params->port].link_status),
641 link_status);
642}
643
644static void bnx2x_bmac_rx_disable(struct bnx2x *bp, u8 port)
645{
646 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
647 NIG_REG_INGRESS_BMAC0_MEM;
648 u32 wb_data[2];
649 u32 nig_bmac_enable = REG_RD(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4);
650
651 /* Only if the bmac is out of reset */
652 if (REG_RD(bp, MISC_REG_RESET_REG_2) &
653 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port) &&
654 nig_bmac_enable) {
655
656 /* Clear Rx Enable bit in BMAC_CONTROL register */
657 REG_RD_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
658 wb_data, 2);
659 wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
660 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
661 wb_data, 2);
662
663 msleep(1);
664 }
665}
666
667static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl,
668 u32 line_speed)
669{
670 struct bnx2x *bp = params->bp;
671 u8 port = params->port;
672 u32 init_crd, crd;
673 u32 count = 1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700674
675 /* disable port */
676 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x1);
677
678 /* wait for init credit */
679 init_crd = REG_RD(bp, PBF_REG_P0_INIT_CRD + port*4);
680 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
681 DP(NETIF_MSG_LINK, "init_crd 0x%x crd 0x%x\n", init_crd, crd);
682
683 while ((init_crd != crd) && count) {
684 msleep(5);
685
686 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
687 count--;
688 }
689 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
690 if (init_crd != crd) {
691 DP(NETIF_MSG_LINK, "BUG! init_crd 0x%x != crd 0x%x\n",
692 init_crd, crd);
693 return -EINVAL;
694 }
695
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700696 if (flow_ctrl & FLOW_CTRL_RX ||
697 line_speed == SPEED_10 ||
698 line_speed == SPEED_100 ||
699 line_speed == SPEED_1000 ||
700 line_speed == SPEED_2500) {
701 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700702 /* update threshold */
703 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, 0);
704 /* update init credit */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700705 init_crd = 778; /* (800-18-4) */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700706
707 } else {
708 u32 thresh = (ETH_MAX_JUMBO_PACKET_SIZE +
709 ETH_OVREHEAD)/16;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700710 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700711 /* update threshold */
712 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, thresh);
713 /* update init credit */
714 switch (line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700715 case SPEED_10000:
716 init_crd = thresh + 553 - 22;
717 break;
718
719 case SPEED_12000:
720 init_crd = thresh + 664 - 22;
721 break;
722
723 case SPEED_13000:
724 init_crd = thresh + 742 - 22;
725 break;
726
727 case SPEED_16000:
728 init_crd = thresh + 778 - 22;
729 break;
730 default:
731 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
732 line_speed);
733 return -EINVAL;
734 break;
735 }
736 }
737 REG_WR(bp, PBF_REG_P0_INIT_CRD + port*4, init_crd);
738 DP(NETIF_MSG_LINK, "PBF updated to speed %d credit %d\n",
739 line_speed, init_crd);
740
741 /* probe the credit changes */
742 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x1);
743 msleep(5);
744 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x0);
745
746 /* enable port */
747 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x0);
748 return 0;
749}
750
751static u32 bnx2x_get_emac_base(u32 ext_phy_type, u8 port)
752{
753 u32 emac_base;
754 switch (ext_phy_type) {
755 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
756 emac_base = GRCBASE_EMAC0;
757 break;
758 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
759 emac_base = (port) ? GRCBASE_EMAC0: GRCBASE_EMAC1;
760 break;
761 default:
762 emac_base = (port) ? GRCBASE_EMAC1: GRCBASE_EMAC0;
763 break;
764 }
765 return emac_base;
766
767}
768
769u8 bnx2x_cl45_write(struct bnx2x *bp, u8 port, u32 ext_phy_type,
770 u8 phy_addr, u8 devad, u16 reg, u16 val)
771{
772 u32 tmp, saved_mode;
773 u8 i, rc = 0;
774 u32 mdio_ctrl = bnx2x_get_emac_base(ext_phy_type, port);
775
776 /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
777 * (a value of 49==0x31) and make sure that the AUTO poll is off
778 */
779 saved_mode = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
780 tmp = saved_mode & ~(EMAC_MDIO_MODE_AUTO_POLL |
781 EMAC_MDIO_MODE_CLOCK_CNT);
782 tmp |= (EMAC_MDIO_MODE_CLAUSE_45 |
783 (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
784 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, tmp);
785 REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
786 udelay(40);
787
788 /* address */
789
790 tmp = ((phy_addr << 21) | (devad << 16) | reg |
791 EMAC_MDIO_COMM_COMMAND_ADDRESS |
792 EMAC_MDIO_COMM_START_BUSY);
793 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
794
795 for (i = 0; i < 50; i++) {
796 udelay(10);
797
798 tmp = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
799 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
800 udelay(5);
801 break;
802 }
803 }
804 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
805 DP(NETIF_MSG_LINK, "write phy register failed\n");
806 rc = -EFAULT;
807 } else {
808 /* data */
809 tmp = ((phy_addr << 21) | (devad << 16) | val |
810 EMAC_MDIO_COMM_COMMAND_WRITE_45 |
811 EMAC_MDIO_COMM_START_BUSY);
812 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
813
814 for (i = 0; i < 50; i++) {
815 udelay(10);
816
817 tmp = REG_RD(bp, mdio_ctrl +
818 EMAC_REG_EMAC_MDIO_COMM);
819 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
820 udelay(5);
821 break;
822 }
823 }
824 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
825 DP(NETIF_MSG_LINK, "write phy register failed\n");
826 rc = -EFAULT;
827 }
828 }
829
830 /* Restore the saved mode */
831 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
832
833 return rc;
834}
835
836u8 bnx2x_cl45_read(struct bnx2x *bp, u8 port, u32 ext_phy_type,
837 u8 phy_addr, u8 devad, u16 reg, u16 *ret_val)
838{
839 u32 val, saved_mode;
840 u16 i;
841 u8 rc = 0;
842
843 u32 mdio_ctrl = bnx2x_get_emac_base(ext_phy_type, port);
844 /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
845 * (a value of 49==0x31) and make sure that the AUTO poll is off
846 */
847 saved_mode = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
848 val = saved_mode & ((EMAC_MDIO_MODE_AUTO_POLL |
849 EMAC_MDIO_MODE_CLOCK_CNT));
850 val |= (EMAC_MDIO_MODE_CLAUSE_45 |
851 (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
852 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, val);
853 REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
854 udelay(40);
855
856 /* address */
857 val = ((phy_addr << 21) | (devad << 16) | reg |
858 EMAC_MDIO_COMM_COMMAND_ADDRESS |
859 EMAC_MDIO_COMM_START_BUSY);
860 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
861
862 for (i = 0; i < 50; i++) {
863 udelay(10);
864
865 val = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
866 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
867 udelay(5);
868 break;
869 }
870 }
871 if (val & EMAC_MDIO_COMM_START_BUSY) {
872 DP(NETIF_MSG_LINK, "read phy register failed\n");
873
874 *ret_val = 0;
875 rc = -EFAULT;
876
877 } else {
878 /* data */
879 val = ((phy_addr << 21) | (devad << 16) |
880 EMAC_MDIO_COMM_COMMAND_READ_45 |
881 EMAC_MDIO_COMM_START_BUSY);
882 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
883
884 for (i = 0; i < 50; i++) {
885 udelay(10);
886
887 val = REG_RD(bp, mdio_ctrl +
888 EMAC_REG_EMAC_MDIO_COMM);
889 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
890 *ret_val = (u16)(val & EMAC_MDIO_COMM_DATA);
891 break;
892 }
893 }
894 if (val & EMAC_MDIO_COMM_START_BUSY) {
895 DP(NETIF_MSG_LINK, "read phy register failed\n");
896
897 *ret_val = 0;
898 rc = -EFAULT;
899 }
900 }
901
902 /* Restore the saved mode */
903 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
904
905 return rc;
906}
907
908static void bnx2x_set_aer_mmd(struct link_params *params,
909 struct link_vars *vars)
910{
911 struct bnx2x *bp = params->bp;
912 u32 ser_lane;
913 u16 offset;
914
915 ser_lane = ((params->lane_config &
916 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
917 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
918
919 offset = (vars->phy_flags & PHY_XGXS_FLAG) ?
920 (params->phy_addr + ser_lane) : 0;
921
922 CL45_WR_OVER_CL22(bp, params->port,
923 params->phy_addr,
924 MDIO_REG_BANK_AER_BLOCK,
925 MDIO_AER_BLOCK_AER_REG, 0x3800 + offset);
926}
927
928static void bnx2x_set_master_ln(struct link_params *params)
929{
930 struct bnx2x *bp = params->bp;
931 u16 new_master_ln, ser_lane;
932 ser_lane = ((params->lane_config &
933 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
934 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
935
936 /* set the master_ln for AN */
937 CL45_RD_OVER_CL22(bp, params->port,
938 params->phy_addr,
939 MDIO_REG_BANK_XGXS_BLOCK2,
940 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
941 &new_master_ln);
942
943 CL45_WR_OVER_CL22(bp, params->port,
944 params->phy_addr,
945 MDIO_REG_BANK_XGXS_BLOCK2 ,
946 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
947 (new_master_ln | ser_lane));
948}
949
950static u8 bnx2x_reset_unicore(struct link_params *params)
951{
952 struct bnx2x *bp = params->bp;
953 u16 mii_control;
954 u16 i;
955
956 CL45_RD_OVER_CL22(bp, params->port,
957 params->phy_addr,
958 MDIO_REG_BANK_COMBO_IEEE0,
959 MDIO_COMBO_IEEE0_MII_CONTROL, &mii_control);
960
961 /* reset the unicore */
962 CL45_WR_OVER_CL22(bp, params->port,
963 params->phy_addr,
964 MDIO_REG_BANK_COMBO_IEEE0,
965 MDIO_COMBO_IEEE0_MII_CONTROL,
966 (mii_control |
967 MDIO_COMBO_IEEO_MII_CONTROL_RESET));
968
969 /* wait for the reset to self clear */
970 for (i = 0; i < MDIO_ACCESS_TIMEOUT; i++) {
971 udelay(5);
972
973 /* the reset erased the previous bank value */
974 CL45_RD_OVER_CL22(bp, params->port,
975 params->phy_addr,
976 MDIO_REG_BANK_COMBO_IEEE0,
977 MDIO_COMBO_IEEE0_MII_CONTROL,
978 &mii_control);
979
980 if (!(mii_control & MDIO_COMBO_IEEO_MII_CONTROL_RESET)) {
981 udelay(5);
982 return 0;
983 }
984 }
985
986 DP(NETIF_MSG_LINK, "BUG! XGXS is still in reset!\n");
987 return -EINVAL;
988
989}
990
991static void bnx2x_set_swap_lanes(struct link_params *params)
992{
993 struct bnx2x *bp = params->bp;
994 /* Each two bits represents a lane number:
995 No swap is 0123 => 0x1b no need to enable the swap */
996 u16 ser_lane, rx_lane_swap, tx_lane_swap;
997
998 ser_lane = ((params->lane_config &
999 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
1000 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
1001 rx_lane_swap = ((params->lane_config &
1002 PORT_HW_CFG_LANE_SWAP_CFG_RX_MASK) >>
1003 PORT_HW_CFG_LANE_SWAP_CFG_RX_SHIFT);
1004 tx_lane_swap = ((params->lane_config &
1005 PORT_HW_CFG_LANE_SWAP_CFG_TX_MASK) >>
1006 PORT_HW_CFG_LANE_SWAP_CFG_TX_SHIFT);
1007
1008 if (rx_lane_swap != 0x1b) {
1009 CL45_WR_OVER_CL22(bp, params->port,
1010 params->phy_addr,
1011 MDIO_REG_BANK_XGXS_BLOCK2,
1012 MDIO_XGXS_BLOCK2_RX_LN_SWAP,
1013 (rx_lane_swap |
1014 MDIO_XGXS_BLOCK2_RX_LN_SWAP_ENABLE |
1015 MDIO_XGXS_BLOCK2_RX_LN_SWAP_FORCE_ENABLE));
1016 } else {
1017 CL45_WR_OVER_CL22(bp, params->port,
1018 params->phy_addr,
1019 MDIO_REG_BANK_XGXS_BLOCK2,
1020 MDIO_XGXS_BLOCK2_RX_LN_SWAP, 0);
1021 }
1022
1023 if (tx_lane_swap != 0x1b) {
1024 CL45_WR_OVER_CL22(bp, params->port,
1025 params->phy_addr,
1026 MDIO_REG_BANK_XGXS_BLOCK2,
1027 MDIO_XGXS_BLOCK2_TX_LN_SWAP,
1028 (tx_lane_swap |
1029 MDIO_XGXS_BLOCK2_TX_LN_SWAP_ENABLE));
1030 } else {
1031 CL45_WR_OVER_CL22(bp, params->port,
1032 params->phy_addr,
1033 MDIO_REG_BANK_XGXS_BLOCK2,
1034 MDIO_XGXS_BLOCK2_TX_LN_SWAP, 0);
1035 }
1036}
1037
1038static void bnx2x_set_parallel_detection(struct link_params *params,
1039 u8 phy_flags)
1040{
1041 struct bnx2x *bp = params->bp;
1042 u16 control2;
1043
1044 CL45_RD_OVER_CL22(bp, params->port,
1045 params->phy_addr,
1046 MDIO_REG_BANK_SERDES_DIGITAL,
1047 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
1048 &control2);
1049
1050
1051 control2 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
1052
1053
1054 CL45_WR_OVER_CL22(bp, params->port,
1055 params->phy_addr,
1056 MDIO_REG_BANK_SERDES_DIGITAL,
1057 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
1058 control2);
1059
1060 if (phy_flags & PHY_XGXS_FLAG) {
1061 DP(NETIF_MSG_LINK, "XGXS\n");
1062
1063 CL45_WR_OVER_CL22(bp, params->port,
1064 params->phy_addr,
1065 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1066 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK,
1067 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT);
1068
1069 CL45_RD_OVER_CL22(bp, params->port,
1070 params->phy_addr,
1071 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1072 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
1073 &control2);
1074
1075
1076 control2 |=
1077 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN;
1078
1079 CL45_WR_OVER_CL22(bp, params->port,
1080 params->phy_addr,
1081 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1082 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
1083 control2);
1084
1085 /* Disable parallel detection of HiG */
1086 CL45_WR_OVER_CL22(bp, params->port,
1087 params->phy_addr,
1088 MDIO_REG_BANK_XGXS_BLOCK2,
1089 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G,
1090 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_CX4_XGXS |
1091 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_HIGIG_XGXS);
1092 }
1093}
1094
1095static void bnx2x_set_autoneg(struct link_params *params,
1096 struct link_vars *vars)
1097{
1098 struct bnx2x *bp = params->bp;
1099 u16 reg_val;
1100
1101 /* CL37 Autoneg */
1102
1103 CL45_RD_OVER_CL22(bp, params->port,
1104 params->phy_addr,
1105 MDIO_REG_BANK_COMBO_IEEE0,
1106 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
1107
1108 /* CL37 Autoneg Enabled */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001109 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001110 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_AN_EN;
1111 else /* CL37 Autoneg Disabled */
1112 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1113 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN);
1114
1115 CL45_WR_OVER_CL22(bp, params->port,
1116 params->phy_addr,
1117 MDIO_REG_BANK_COMBO_IEEE0,
1118 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
1119
1120 /* Enable/Disable Autodetection */
1121
1122 CL45_RD_OVER_CL22(bp, params->port,
1123 params->phy_addr,
1124 MDIO_REG_BANK_SERDES_DIGITAL,
1125 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, &reg_val);
1126 reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001127 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001128 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
1129 else
1130 reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
1131
1132 CL45_WR_OVER_CL22(bp, params->port,
1133 params->phy_addr,
1134 MDIO_REG_BANK_SERDES_DIGITAL,
1135 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, reg_val);
1136
1137 /* Enable TetonII and BAM autoneg */
1138 CL45_RD_OVER_CL22(bp, params->port,
1139 params->phy_addr,
1140 MDIO_REG_BANK_BAM_NEXT_PAGE,
1141 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
1142 &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001143 if (vars->line_speed == SPEED_AUTO_NEG) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001144 /* Enable BAM aneg Mode and TetonII aneg Mode */
1145 reg_val |= (MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
1146 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
1147 } else {
1148 /* TetonII and BAM Autoneg Disabled */
1149 reg_val &= ~(MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
1150 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
1151 }
1152 CL45_WR_OVER_CL22(bp, params->port,
1153 params->phy_addr,
1154 MDIO_REG_BANK_BAM_NEXT_PAGE,
1155 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
1156 reg_val);
1157
1158 /* Enable Clause 73 Aneg */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001159 if ((vars->line_speed == SPEED_AUTO_NEG) &&
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001160 (SUPPORT_CL73)) {
1161 /* Enable BAM Station Manager */
1162
1163 CL45_WR_OVER_CL22(bp, params->port,
1164 params->phy_addr,
1165 MDIO_REG_BANK_CL73_USERB0,
1166 MDIO_CL73_USERB0_CL73_BAM_CTRL1,
1167 (MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN |
1168 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_STATION_MNGR_EN |
1169 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN));
1170
1171 /* Merge CL73 and CL37 aneg resolution */
1172 CL45_RD_OVER_CL22(bp, params->port,
1173 params->phy_addr,
1174 MDIO_REG_BANK_CL73_USERB0,
1175 MDIO_CL73_USERB0_CL73_BAM_CTRL3,
1176 &reg_val);
1177
1178 CL45_WR_OVER_CL22(bp, params->port,
1179 params->phy_addr,
1180 MDIO_REG_BANK_CL73_USERB0,
1181 MDIO_CL73_USERB0_CL73_BAM_CTRL3,
1182 (reg_val |
1183 MDIO_CL73_USERB0_CL73_BAM_CTRL3_USE_CL73_HCD_MR));
1184
1185 /* Set the CL73 AN speed */
1186
1187 CL45_RD_OVER_CL22(bp, params->port,
1188 params->phy_addr,
1189 MDIO_REG_BANK_CL73_IEEEB1,
1190 MDIO_CL73_IEEEB1_AN_ADV2, &reg_val);
1191 /* In the SerDes we support only the 1G.
1192 In the XGXS we support the 10G KX4
1193 but we currently do not support the KR */
1194 if (vars->phy_flags & PHY_XGXS_FLAG) {
1195 DP(NETIF_MSG_LINK, "XGXS\n");
1196 /* 10G KX4 */
1197 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4;
1198 } else {
1199 DP(NETIF_MSG_LINK, "SerDes\n");
1200 /* 1000M KX */
1201 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX;
1202 }
1203 CL45_WR_OVER_CL22(bp, params->port,
1204 params->phy_addr,
1205 MDIO_REG_BANK_CL73_IEEEB1,
1206 MDIO_CL73_IEEEB1_AN_ADV2, reg_val);
1207
1208 /* CL73 Autoneg Enabled */
1209 reg_val = MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN;
1210 } else {
1211 /* CL73 Autoneg Disabled */
1212 reg_val = 0;
1213 }
1214 CL45_WR_OVER_CL22(bp, params->port,
1215 params->phy_addr,
1216 MDIO_REG_BANK_CL73_IEEEB0,
1217 MDIO_CL73_IEEEB0_CL73_AN_CONTROL, reg_val);
1218}
1219
1220/* program SerDes, forced speed */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001221static void bnx2x_program_serdes(struct link_params *params,
1222 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001223{
1224 struct bnx2x *bp = params->bp;
1225 u16 reg_val;
1226
1227 /* program duplex, disable autoneg */
1228
1229 CL45_RD_OVER_CL22(bp, params->port,
1230 params->phy_addr,
1231 MDIO_REG_BANK_COMBO_IEEE0,
1232 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
1233 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX |
1234 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN);
1235 if (params->req_duplex == DUPLEX_FULL)
1236 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
1237 CL45_WR_OVER_CL22(bp, params->port,
1238 params->phy_addr,
1239 MDIO_REG_BANK_COMBO_IEEE0,
1240 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
1241
1242 /* program speed
1243 - needed only if the speed is greater than 1G (2.5G or 10G) */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001244 CL45_RD_OVER_CL22(bp, params->port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001245 params->phy_addr,
1246 MDIO_REG_BANK_SERDES_DIGITAL,
1247 MDIO_SERDES_DIGITAL_MISC1, &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001248 /* clearing the speed value before setting the right speed */
1249 DP(NETIF_MSG_LINK, "MDIO_REG_BANK_SERDES_DIGITAL = 0x%x\n", reg_val);
1250
1251 reg_val &= ~(MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_MASK |
1252 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
1253
1254 if (!((vars->line_speed == SPEED_1000) ||
1255 (vars->line_speed == SPEED_100) ||
1256 (vars->line_speed == SPEED_10))) {
1257
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001258 reg_val |= (MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_156_25M |
1259 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001260 if (vars->line_speed == SPEED_10000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001261 reg_val |=
1262 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_10G_CX4;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001263 if (vars->line_speed == SPEED_13000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001264 reg_val |=
1265 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_13G;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001266 }
1267
1268 CL45_WR_OVER_CL22(bp, params->port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001269 params->phy_addr,
1270 MDIO_REG_BANK_SERDES_DIGITAL,
1271 MDIO_SERDES_DIGITAL_MISC1, reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001272
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001273}
1274
1275static void bnx2x_set_brcm_cl37_advertisment(struct link_params *params)
1276{
1277 struct bnx2x *bp = params->bp;
1278 u16 val = 0;
1279
1280 /* configure the 48 bits for BAM AN */
1281
1282 /* set extended capabilities */
1283 if (params->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G)
1284 val |= MDIO_OVER_1G_UP1_2_5G;
1285 if (params->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
1286 val |= MDIO_OVER_1G_UP1_10G;
1287 CL45_WR_OVER_CL22(bp, params->port,
1288 params->phy_addr,
1289 MDIO_REG_BANK_OVER_1G,
1290 MDIO_OVER_1G_UP1, val);
1291
1292 CL45_WR_OVER_CL22(bp, params->port,
1293 params->phy_addr,
1294 MDIO_REG_BANK_OVER_1G,
1295 MDIO_OVER_1G_UP3, 0);
1296}
1297
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001298static void bnx2x_calc_ieee_aneg_adv(struct link_params *params, u32 *ieee_fc)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001299{
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001300 *ieee_fc = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001301 /* resolve pause mode and advertisement
1302 * Please refer to Table 28B-3 of the 802.3ab-1999 spec */
1303
1304 switch (params->req_flow_ctrl) {
1305 case FLOW_CTRL_AUTO:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001306 if (params->req_fc_auto_adv == FLOW_CTRL_BOTH) {
1307 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001308 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
1309 } else {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001310 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001311 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
1312 }
1313 break;
1314 case FLOW_CTRL_TX:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001315 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001316 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
1317 break;
1318
1319 case FLOW_CTRL_RX:
1320 case FLOW_CTRL_BOTH:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001321 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001322 break;
1323
1324 case FLOW_CTRL_NONE:
1325 default:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001326 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001327 break;
1328 }
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001329}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001330
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001331static void bnx2x_set_ieee_aneg_advertisment(struct link_params *params,
1332 u32 ieee_fc)
1333{
1334 struct bnx2x *bp = params->bp;
1335 /* for AN, we are always publishing full duplex */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001336
1337 CL45_WR_OVER_CL22(bp, params->port,
1338 params->phy_addr,
1339 MDIO_REG_BANK_COMBO_IEEE0,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001340 MDIO_COMBO_IEEE0_AUTO_NEG_ADV, (u16)ieee_fc);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001341}
1342
1343static void bnx2x_restart_autoneg(struct link_params *params)
1344{
1345 struct bnx2x *bp = params->bp;
1346 DP(NETIF_MSG_LINK, "bnx2x_restart_autoneg\n");
1347 if (SUPPORT_CL73) {
1348 /* enable and restart clause 73 aneg */
1349 u16 an_ctrl;
1350
1351 CL45_RD_OVER_CL22(bp, params->port,
1352 params->phy_addr,
1353 MDIO_REG_BANK_CL73_IEEEB0,
1354 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1355 &an_ctrl);
1356 CL45_WR_OVER_CL22(bp, params->port,
1357 params->phy_addr,
1358 MDIO_REG_BANK_CL73_IEEEB0,
1359 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1360 (an_ctrl |
1361 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN |
1362 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN));
1363
1364 } else {
1365 /* Enable and restart BAM/CL37 aneg */
1366 u16 mii_control;
1367
1368 CL45_RD_OVER_CL22(bp, params->port,
1369 params->phy_addr,
1370 MDIO_REG_BANK_COMBO_IEEE0,
1371 MDIO_COMBO_IEEE0_MII_CONTROL,
1372 &mii_control);
1373 DP(NETIF_MSG_LINK,
1374 "bnx2x_restart_autoneg mii_control before = 0x%x\n",
1375 mii_control);
1376 CL45_WR_OVER_CL22(bp, params->port,
1377 params->phy_addr,
1378 MDIO_REG_BANK_COMBO_IEEE0,
1379 MDIO_COMBO_IEEE0_MII_CONTROL,
1380 (mii_control |
1381 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1382 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN));
1383 }
1384}
1385
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001386static void bnx2x_initialize_sgmii_process(struct link_params *params,
1387 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001388{
1389 struct bnx2x *bp = params->bp;
1390 u16 control1;
1391
1392 /* in SGMII mode, the unicore is always slave */
1393
1394 CL45_RD_OVER_CL22(bp, params->port,
1395 params->phy_addr,
1396 MDIO_REG_BANK_SERDES_DIGITAL,
1397 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
1398 &control1);
1399 control1 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT;
1400 /* set sgmii mode (and not fiber) */
1401 control1 &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE |
1402 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET |
1403 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_MSTR_MODE);
1404 CL45_WR_OVER_CL22(bp, params->port,
1405 params->phy_addr,
1406 MDIO_REG_BANK_SERDES_DIGITAL,
1407 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
1408 control1);
1409
1410 /* if forced speed */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001411 if (!(vars->line_speed == SPEED_AUTO_NEG)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001412 /* set speed, disable autoneg */
1413 u16 mii_control;
1414
1415 CL45_RD_OVER_CL22(bp, params->port,
1416 params->phy_addr,
1417 MDIO_REG_BANK_COMBO_IEEE0,
1418 MDIO_COMBO_IEEE0_MII_CONTROL,
1419 &mii_control);
1420 mii_control &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1421 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK|
1422 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX);
1423
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001424 switch (vars->line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001425 case SPEED_100:
1426 mii_control |=
1427 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_100;
1428 break;
1429 case SPEED_1000:
1430 mii_control |=
1431 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_1000;
1432 break;
1433 case SPEED_10:
1434 /* there is nothing to set for 10M */
1435 break;
1436 default:
1437 /* invalid speed for SGMII */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001438 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
1439 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001440 break;
1441 }
1442
1443 /* setting the full duplex */
1444 if (params->req_duplex == DUPLEX_FULL)
1445 mii_control |=
1446 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
1447 CL45_WR_OVER_CL22(bp, params->port,
1448 params->phy_addr,
1449 MDIO_REG_BANK_COMBO_IEEE0,
1450 MDIO_COMBO_IEEE0_MII_CONTROL,
1451 mii_control);
1452
1453 } else { /* AN mode */
1454 /* enable and restart AN */
1455 bnx2x_restart_autoneg(params);
1456 }
1457}
1458
1459
1460/*
1461 * link management
1462 */
1463
1464static void bnx2x_pause_resolve(struct link_vars *vars, u32 pause_result)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001465{ /* LD LP */
1466 switch (pause_result) { /* ASYM P ASYM P */
1467 case 0xb: /* 1 0 1 1 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001468 vars->flow_ctrl = FLOW_CTRL_TX;
1469 break;
1470
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001471 case 0xe: /* 1 1 1 0 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001472 vars->flow_ctrl = FLOW_CTRL_RX;
1473 break;
1474
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001475 case 0x5: /* 0 1 0 1 */
1476 case 0x7: /* 0 1 1 1 */
1477 case 0xd: /* 1 1 0 1 */
1478 case 0xf: /* 1 1 1 1 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001479 vars->flow_ctrl = FLOW_CTRL_BOTH;
1480 break;
1481
1482 default:
1483 break;
1484 }
1485}
1486
1487static u8 bnx2x_ext_phy_resove_fc(struct link_params *params,
1488 struct link_vars *vars)
1489{
1490 struct bnx2x *bp = params->bp;
1491 u8 ext_phy_addr;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001492 u16 ld_pause; /* local */
1493 u16 lp_pause; /* link partner */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001494 u16 an_complete; /* AN complete */
1495 u16 pause_result;
1496 u8 ret = 0;
1497 u32 ext_phy_type;
1498 u8 port = params->port;
1499 ext_phy_addr = ((params->ext_phy_config &
1500 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
1501 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
1502
1503 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
1504 /* read twice */
1505
1506 bnx2x_cl45_read(bp, port,
1507 ext_phy_type,
1508 ext_phy_addr,
1509 MDIO_AN_DEVAD,
1510 MDIO_AN_REG_STATUS, &an_complete);
1511 bnx2x_cl45_read(bp, port,
1512 ext_phy_type,
1513 ext_phy_addr,
1514 MDIO_AN_DEVAD,
1515 MDIO_AN_REG_STATUS, &an_complete);
1516
1517 if (an_complete & MDIO_AN_REG_STATUS_AN_COMPLETE) {
1518 ret = 1;
1519 bnx2x_cl45_read(bp, port,
1520 ext_phy_type,
1521 ext_phy_addr,
1522 MDIO_AN_DEVAD,
1523 MDIO_AN_REG_ADV_PAUSE, &ld_pause);
1524 bnx2x_cl45_read(bp, port,
1525 ext_phy_type,
1526 ext_phy_addr,
1527 MDIO_AN_DEVAD,
1528 MDIO_AN_REG_LP_AUTO_NEG, &lp_pause);
1529 pause_result = (ld_pause &
1530 MDIO_AN_REG_ADV_PAUSE_MASK) >> 8;
1531 pause_result |= (lp_pause &
1532 MDIO_AN_REG_ADV_PAUSE_MASK) >> 10;
1533 DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x \n",
1534 pause_result);
1535 bnx2x_pause_resolve(vars, pause_result);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001536 if (vars->flow_ctrl == FLOW_CTRL_NONE &&
1537 ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
1538 bnx2x_cl45_read(bp, port,
1539 ext_phy_type,
1540 ext_phy_addr,
1541 MDIO_AN_DEVAD,
1542 MDIO_AN_REG_CL37_FC_LD, &ld_pause);
1543
1544 bnx2x_cl45_read(bp, port,
1545 ext_phy_type,
1546 ext_phy_addr,
1547 MDIO_AN_DEVAD,
1548 MDIO_AN_REG_CL37_FC_LP, &lp_pause);
1549 pause_result = (ld_pause &
1550 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 5;
1551 pause_result |= (lp_pause &
1552 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 7;
1553
1554 bnx2x_pause_resolve(vars, pause_result);
1555 DP(NETIF_MSG_LINK, "Ext PHY CL37 pause result 0x%x \n",
1556 pause_result);
1557 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001558 }
1559 return ret;
1560}
1561
1562
1563static void bnx2x_flow_ctrl_resolve(struct link_params *params,
1564 struct link_vars *vars,
1565 u32 gp_status)
1566{
1567 struct bnx2x *bp = params->bp;
1568 u16 ld_pause; /* local driver */
1569 u16 lp_pause; /* link partner */
1570 u16 pause_result;
1571
1572 vars->flow_ctrl = FLOW_CTRL_NONE;
1573
1574 /* resolve from gp_status in case of AN complete and not sgmii */
1575 if ((params->req_flow_ctrl == FLOW_CTRL_AUTO) &&
1576 (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) &&
1577 (!(vars->phy_flags & PHY_SGMII_FLAG)) &&
1578 (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
1579 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT)) {
1580 CL45_RD_OVER_CL22(bp, params->port,
1581 params->phy_addr,
1582 MDIO_REG_BANK_COMBO_IEEE0,
1583 MDIO_COMBO_IEEE0_AUTO_NEG_ADV,
1584 &ld_pause);
1585 CL45_RD_OVER_CL22(bp, params->port,
1586 params->phy_addr,
1587 MDIO_REG_BANK_COMBO_IEEE0,
1588 MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1,
1589 &lp_pause);
1590 pause_result = (ld_pause &
1591 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>5;
1592 pause_result |= (lp_pause &
1593 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7;
1594 DP(NETIF_MSG_LINK, "pause_result 0x%x\n", pause_result);
1595 bnx2x_pause_resolve(vars, pause_result);
1596 } else if ((params->req_flow_ctrl == FLOW_CTRL_AUTO) &&
1597 (bnx2x_ext_phy_resove_fc(params, vars))) {
1598 return;
1599 } else {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001600 if (params->req_flow_ctrl == FLOW_CTRL_AUTO)
1601 vars->flow_ctrl = params->req_fc_auto_adv;
1602 else
1603 vars->flow_ctrl = params->req_flow_ctrl;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001604 }
1605 DP(NETIF_MSG_LINK, "flow_ctrl 0x%x\n", vars->flow_ctrl);
1606}
1607
1608
1609static u8 bnx2x_link_settings_status(struct link_params *params,
1610 struct link_vars *vars,
1611 u32 gp_status)
1612{
1613 struct bnx2x *bp = params->bp;
1614 u8 rc = 0;
1615 vars->link_status = 0;
1616
1617 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) {
1618 DP(NETIF_MSG_LINK, "phy link up gp_status=0x%x\n",
1619 gp_status);
1620
1621 vars->phy_link_up = 1;
1622 vars->link_status |= LINK_STATUS_LINK_UP;
1623
1624 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_DUPLEX_STATUS)
1625 vars->duplex = DUPLEX_FULL;
1626 else
1627 vars->duplex = DUPLEX_HALF;
1628
1629 bnx2x_flow_ctrl_resolve(params, vars, gp_status);
1630
1631 switch (gp_status & GP_STATUS_SPEED_MASK) {
1632 case GP_STATUS_10M:
1633 vars->line_speed = SPEED_10;
1634 if (vars->duplex == DUPLEX_FULL)
1635 vars->link_status |= LINK_10TFD;
1636 else
1637 vars->link_status |= LINK_10THD;
1638 break;
1639
1640 case GP_STATUS_100M:
1641 vars->line_speed = SPEED_100;
1642 if (vars->duplex == DUPLEX_FULL)
1643 vars->link_status |= LINK_100TXFD;
1644 else
1645 vars->link_status |= LINK_100TXHD;
1646 break;
1647
1648 case GP_STATUS_1G:
1649 case GP_STATUS_1G_KX:
1650 vars->line_speed = SPEED_1000;
1651 if (vars->duplex == DUPLEX_FULL)
1652 vars->link_status |= LINK_1000TFD;
1653 else
1654 vars->link_status |= LINK_1000THD;
1655 break;
1656
1657 case GP_STATUS_2_5G:
1658 vars->line_speed = SPEED_2500;
1659 if (vars->duplex == DUPLEX_FULL)
1660 vars->link_status |= LINK_2500TFD;
1661 else
1662 vars->link_status |= LINK_2500THD;
1663 break;
1664
1665 case GP_STATUS_5G:
1666 case GP_STATUS_6G:
1667 DP(NETIF_MSG_LINK,
1668 "link speed unsupported gp_status 0x%x\n",
1669 gp_status);
1670 return -EINVAL;
1671 break;
1672 case GP_STATUS_10G_KX4:
1673 case GP_STATUS_10G_HIG:
1674 case GP_STATUS_10G_CX4:
1675 vars->line_speed = SPEED_10000;
1676 vars->link_status |= LINK_10GTFD;
1677 break;
1678
1679 case GP_STATUS_12G_HIG:
1680 vars->line_speed = SPEED_12000;
1681 vars->link_status |= LINK_12GTFD;
1682 break;
1683
1684 case GP_STATUS_12_5G:
1685 vars->line_speed = SPEED_12500;
1686 vars->link_status |= LINK_12_5GTFD;
1687 break;
1688
1689 case GP_STATUS_13G:
1690 vars->line_speed = SPEED_13000;
1691 vars->link_status |= LINK_13GTFD;
1692 break;
1693
1694 case GP_STATUS_15G:
1695 vars->line_speed = SPEED_15000;
1696 vars->link_status |= LINK_15GTFD;
1697 break;
1698
1699 case GP_STATUS_16G:
1700 vars->line_speed = SPEED_16000;
1701 vars->link_status |= LINK_16GTFD;
1702 break;
1703
1704 default:
1705 DP(NETIF_MSG_LINK,
1706 "link speed unsupported gp_status 0x%x\n",
1707 gp_status);
1708 return -EINVAL;
1709 break;
1710 }
1711
1712 vars->link_status |= LINK_STATUS_SERDES_LINK;
1713
Yaniv Rosner57963ed2008-08-13 15:55:28 -07001714 if ((params->req_line_speed == SPEED_AUTO_NEG) &&
1715 ((XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
1716 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ||
1717 (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
1718 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001719 vars->autoneg = AUTO_NEG_ENABLED;
1720
1721 if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) {
1722 vars->autoneg |= AUTO_NEG_COMPLETE;
1723 vars->link_status |=
1724 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
1725 }
1726
1727 vars->autoneg |= AUTO_NEG_PARALLEL_DETECTION_USED;
1728 vars->link_status |=
1729 LINK_STATUS_PARALLEL_DETECTION_USED;
1730
1731 }
1732 if (vars->flow_ctrl & FLOW_CTRL_TX)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001733 vars->link_status |=
1734 LINK_STATUS_TX_FLOW_CONTROL_ENABLED;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001735
1736 if (vars->flow_ctrl & FLOW_CTRL_RX)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001737 vars->link_status |=
1738 LINK_STATUS_RX_FLOW_CONTROL_ENABLED;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001739
1740 } else { /* link_down */
1741 DP(NETIF_MSG_LINK, "phy link down\n");
1742
1743 vars->phy_link_up = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07001744
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001745 vars->duplex = DUPLEX_FULL;
1746 vars->flow_ctrl = FLOW_CTRL_NONE;
1747 vars->autoneg = AUTO_NEG_DISABLED;
1748 vars->mac_type = MAC_TYPE_NONE;
1749 }
1750
1751 DP(NETIF_MSG_LINK, "gp_status 0x%x phy_link_up %x line_speed %x \n",
1752 gp_status, vars->phy_link_up, vars->line_speed);
1753 DP(NETIF_MSG_LINK, "duplex %x flow_ctrl 0x%x"
1754 " autoneg 0x%x\n",
1755 vars->duplex,
1756 vars->flow_ctrl, vars->autoneg);
1757 DP(NETIF_MSG_LINK, "link_status 0x%x\n", vars->link_status);
1758
1759 return rc;
1760}
1761
1762static void bnx2x_set_sgmii_tx_driver(struct link_params *params)
1763{
1764 struct bnx2x *bp = params->bp;
1765 u16 lp_up2;
1766 u16 tx_driver;
1767
1768 /* read precomp */
1769
1770 CL45_RD_OVER_CL22(bp, params->port,
1771 params->phy_addr,
1772 MDIO_REG_BANK_OVER_1G,
1773 MDIO_OVER_1G_LP_UP2, &lp_up2);
1774
1775 CL45_RD_OVER_CL22(bp, params->port,
1776 params->phy_addr,
1777 MDIO_REG_BANK_TX0,
1778 MDIO_TX0_TX_DRIVER, &tx_driver);
1779
1780 /* bits [10:7] at lp_up2, positioned at [15:12] */
1781 lp_up2 = (((lp_up2 & MDIO_OVER_1G_LP_UP2_PREEMPHASIS_MASK) >>
1782 MDIO_OVER_1G_LP_UP2_PREEMPHASIS_SHIFT) <<
1783 MDIO_TX0_TX_DRIVER_PREEMPHASIS_SHIFT);
1784
1785 if ((lp_up2 != 0) &&
1786 (lp_up2 != (tx_driver & MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK))) {
1787 /* replace tx_driver bits [15:12] */
1788 tx_driver &= ~MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK;
1789 tx_driver |= lp_up2;
1790 CL45_WR_OVER_CL22(bp, params->port,
1791 params->phy_addr,
1792 MDIO_REG_BANK_TX0,
1793 MDIO_TX0_TX_DRIVER, tx_driver);
1794 }
1795}
1796
1797static u8 bnx2x_emac_program(struct link_params *params,
1798 u32 line_speed, u32 duplex)
1799{
1800 struct bnx2x *bp = params->bp;
1801 u8 port = params->port;
1802 u16 mode = 0;
1803
1804 DP(NETIF_MSG_LINK, "setting link speed & duplex\n");
1805 bnx2x_bits_dis(bp, GRCBASE_EMAC0 + port*0x400 +
1806 EMAC_REG_EMAC_MODE,
1807 (EMAC_MODE_25G_MODE |
1808 EMAC_MODE_PORT_MII_10M |
1809 EMAC_MODE_HALF_DUPLEX));
1810 switch (line_speed) {
1811 case SPEED_10:
1812 mode |= EMAC_MODE_PORT_MII_10M;
1813 break;
1814
1815 case SPEED_100:
1816 mode |= EMAC_MODE_PORT_MII;
1817 break;
1818
1819 case SPEED_1000:
1820 mode |= EMAC_MODE_PORT_GMII;
1821 break;
1822
1823 case SPEED_2500:
1824 mode |= (EMAC_MODE_25G_MODE | EMAC_MODE_PORT_GMII);
1825 break;
1826
1827 default:
1828 /* 10G not valid for EMAC */
1829 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n", line_speed);
1830 return -EINVAL;
1831 }
1832
1833 if (duplex == DUPLEX_HALF)
1834 mode |= EMAC_MODE_HALF_DUPLEX;
1835 bnx2x_bits_en(bp,
1836 GRCBASE_EMAC0 + port*0x400 + EMAC_REG_EMAC_MODE,
1837 mode);
1838
1839 bnx2x_set_led(bp, params->port, LED_MODE_OPER,
1840 line_speed, params->hw_led_mode, params->chip_id);
1841 return 0;
1842}
1843
1844/*****************************************************************************/
1845/* External Phy section */
1846/*****************************************************************************/
1847static void bnx2x_hw_reset(struct bnx2x *bp)
1848{
1849 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
1850 MISC_REGISTERS_GPIO_OUTPUT_LOW);
1851 msleep(1);
1852 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
1853 MISC_REGISTERS_GPIO_OUTPUT_HIGH);
1854}
1855
1856static void bnx2x_ext_phy_reset(struct link_params *params,
1857 struct link_vars *vars)
1858{
1859 struct bnx2x *bp = params->bp;
1860 u32 ext_phy_type;
1861 u8 ext_phy_addr = ((params->ext_phy_config &
1862 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
1863 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
1864 DP(NETIF_MSG_LINK, "Port %x: bnx2x_ext_phy_reset\n", params->port);
1865 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
1866 /* The PHY reset is controled by GPIO 1
1867 * Give it 1ms of reset pulse
1868 */
1869 if (vars->phy_flags & PHY_XGXS_FLAG) {
1870
1871 switch (ext_phy_type) {
1872 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
1873 DP(NETIF_MSG_LINK, "XGXS Direct\n");
1874 break;
1875
1876 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
1877 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
1878 DP(NETIF_MSG_LINK, "XGXS 8705/8706\n");
1879
1880 /* Restore normal power mode*/
1881 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
1882 MISC_REGISTERS_GPIO_OUTPUT_HIGH);
1883
1884 /* HW reset */
1885 bnx2x_hw_reset(bp);
1886
1887 bnx2x_cl45_write(bp, params->port,
1888 ext_phy_type,
1889 ext_phy_addr,
1890 MDIO_PMA_DEVAD,
1891 MDIO_PMA_REG_CTRL, 0xa040);
1892 break;
1893 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
1894 /* Unset Low Power Mode and SW reset */
1895 /* Restore normal power mode*/
1896 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
1897 MISC_REGISTERS_GPIO_OUTPUT_HIGH);
1898
1899 DP(NETIF_MSG_LINK, "XGXS 8072\n");
1900 bnx2x_cl45_write(bp, params->port,
1901 ext_phy_type,
1902 ext_phy_addr,
1903 MDIO_PMA_DEVAD,
1904 MDIO_PMA_REG_CTRL,
1905 1<<15);
1906 break;
1907 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
1908 {
1909 u16 emac_base;
1910 emac_base = (params->port) ? GRCBASE_EMAC0 :
1911 GRCBASE_EMAC1;
1912
1913 /* Restore normal power mode*/
1914 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
1915 MISC_REGISTERS_GPIO_OUTPUT_HIGH);
1916
1917 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
1918 MISC_REGISTERS_GPIO_OUTPUT_HIGH);
1919
1920 DP(NETIF_MSG_LINK, "XGXS 8073\n");
1921 bnx2x_cl45_write(bp,
1922 params->port,
1923 ext_phy_type,
1924 ext_phy_addr,
1925 MDIO_PMA_DEVAD,
1926 MDIO_PMA_REG_CTRL,
1927 1<<15);
1928 }
1929 break;
1930
1931 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
1932 DP(NETIF_MSG_LINK, "XGXS SFX7101\n");
1933
1934 /* Restore normal power mode*/
1935 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
1936 MISC_REGISTERS_GPIO_OUTPUT_HIGH);
1937
1938 /* HW reset */
1939 bnx2x_hw_reset(bp);
1940
1941 break;
1942
1943 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
1944 DP(NETIF_MSG_LINK, "XGXS PHY Failure detected\n");
1945 break;
1946
1947 default:
1948 DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
1949 params->ext_phy_config);
1950 break;
1951 }
1952
1953 } else { /* SerDes */
1954 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
1955 switch (ext_phy_type) {
1956 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
1957 DP(NETIF_MSG_LINK, "SerDes Direct\n");
1958 break;
1959
1960 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
1961 DP(NETIF_MSG_LINK, "SerDes 5482\n");
1962 bnx2x_hw_reset(bp);
1963 break;
1964
1965 default:
1966 DP(NETIF_MSG_LINK,
1967 "BAD SerDes ext_phy_config 0x%x\n",
1968 params->ext_phy_config);
1969 break;
1970 }
1971 }
1972}
1973
1974static void bnx2x_bcm8072_external_rom_boot(struct link_params *params)
1975{
1976 struct bnx2x *bp = params->bp;
1977 u8 port = params->port;
1978 u8 ext_phy_addr = ((params->ext_phy_config &
1979 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
1980 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
1981 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
1982 u16 fw_ver1, fw_ver2;
1983
1984 /* Need to wait 200ms after reset */
1985 msleep(200);
1986 /* Boot port from external ROM
1987 * Set ser_boot_ctl bit in the MISC_CTRL1 register
1988 */
1989 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
1990 MDIO_PMA_DEVAD,
1991 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
1992
1993 /* Reset internal microprocessor */
1994 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
1995 MDIO_PMA_DEVAD,
1996 MDIO_PMA_REG_GEN_CTRL,
1997 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
1998 /* set micro reset = 0 */
1999 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2000 MDIO_PMA_DEVAD,
2001 MDIO_PMA_REG_GEN_CTRL,
2002 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
2003 /* Reset internal microprocessor */
2004 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2005 MDIO_PMA_DEVAD,
2006 MDIO_PMA_REG_GEN_CTRL,
2007 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2008 /* wait for 100ms for code download via SPI port */
2009 msleep(100);
2010
2011 /* Clear ser_boot_ctl bit */
2012 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2013 MDIO_PMA_DEVAD,
2014 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
2015 /* Wait 100ms */
2016 msleep(100);
2017
2018 /* Print the PHY FW version */
2019 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
2020 MDIO_PMA_DEVAD,
2021 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
2022 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
2023 MDIO_PMA_DEVAD,
2024 MDIO_PMA_REG_ROM_VER2, &fw_ver2);
2025 DP(NETIF_MSG_LINK, "8072 FW version 0x%x:0x%x\n", fw_ver1, fw_ver2);
2026}
2027
2028static u8 bnx2x_8073_is_snr_needed(struct link_params *params)
2029{
2030 /* This is only required for 8073A1, version 102 only */
2031
2032 struct bnx2x *bp = params->bp;
2033 u8 ext_phy_addr = ((params->ext_phy_config &
2034 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2035 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2036 u16 val;
2037
2038 /* Read 8073 HW revision*/
2039 bnx2x_cl45_read(bp, params->port,
2040 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2041 ext_phy_addr,
2042 MDIO_PMA_DEVAD,
2043 0xc801, &val);
2044
2045 if (val != 1) {
2046 /* No need to workaround in 8073 A1 */
2047 return 0;
2048 }
2049
2050 bnx2x_cl45_read(bp, params->port,
2051 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2052 ext_phy_addr,
2053 MDIO_PMA_DEVAD,
2054 MDIO_PMA_REG_ROM_VER2, &val);
2055
2056 /* SNR should be applied only for version 0x102 */
2057 if (val != 0x102)
2058 return 0;
2059
2060 return 1;
2061}
2062
2063static u8 bnx2x_bcm8073_xaui_wa(struct link_params *params)
2064{
2065 struct bnx2x *bp = params->bp;
2066 u8 ext_phy_addr = ((params->ext_phy_config &
2067 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2068 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2069 u16 val, cnt, cnt1 ;
2070
2071 bnx2x_cl45_read(bp, params->port,
2072 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2073 ext_phy_addr,
2074 MDIO_PMA_DEVAD,
2075 0xc801, &val);
2076
2077 if (val > 0) {
2078 /* No need to workaround in 8073 A1 */
2079 return 0;
2080 }
2081 /* XAUI workaround in 8073 A0: */
2082
2083 /* After loading the boot ROM and restarting Autoneg,
2084 poll Dev1, Reg $C820: */
2085
2086 for (cnt = 0; cnt < 1000; cnt++) {
2087 bnx2x_cl45_read(bp, params->port,
2088 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2089 ext_phy_addr,
2090 MDIO_PMA_DEVAD,
2091 0xc820, &val);
2092 /* If bit [14] = 0 or bit [13] = 0, continue on with
2093 system initialization (XAUI work-around not required,
2094 as these bits indicate 2.5G or 1G link up). */
2095 if (!(val & (1<<14)) || !(val & (1<<13))) {
2096 DP(NETIF_MSG_LINK, "XAUI work-around not required\n");
2097 return 0;
2098 } else if (!(val & (1<<15))) {
2099 DP(NETIF_MSG_LINK, "clc bit 15 went off\n");
2100 /* If bit 15 is 0, then poll Dev1, Reg $C841 until
2101 it's MSB (bit 15) goes to 1 (indicating that the
2102 XAUI workaround has completed),
2103 then continue on with system initialization.*/
2104 for (cnt1 = 0; cnt1 < 1000; cnt1++) {
2105 bnx2x_cl45_read(bp, params->port,
2106 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2107 ext_phy_addr,
2108 MDIO_PMA_DEVAD,
2109 0xc841, &val);
2110 if (val & (1<<15)) {
2111 DP(NETIF_MSG_LINK,
2112 "XAUI workaround has completed\n");
2113 return 0;
2114 }
2115 msleep(3);
2116 }
2117 break;
2118 }
2119 msleep(3);
2120 }
2121 DP(NETIF_MSG_LINK, "Warning: XAUI work-around timeout !!!\n");
2122 return -EINVAL;
2123
2124}
2125
2126static void bnx2x_bcm8073_external_rom_boot(struct link_params *params)
2127{
2128 struct bnx2x *bp = params->bp;
2129 u8 port = params->port;
2130 u8 ext_phy_addr = ((params->ext_phy_config &
2131 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2132 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2133 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2134 u16 fw_ver1, fw_ver2, val;
2135 /* Need to wait 100ms after reset */
2136 msleep(100);
2137 /* Boot port from external ROM */
2138 /* EDC grst */
2139 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2140 MDIO_PMA_DEVAD,
2141 MDIO_PMA_REG_GEN_CTRL,
2142 0x0001);
2143
2144 /* ucode reboot and rst */
2145 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2146 MDIO_PMA_DEVAD,
2147 MDIO_PMA_REG_GEN_CTRL,
2148 0x008c);
2149
2150 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2151 MDIO_PMA_DEVAD,
2152 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
2153
2154 /* Reset internal microprocessor */
2155 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2156 MDIO_PMA_DEVAD,
2157 MDIO_PMA_REG_GEN_CTRL,
2158 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
2159
2160 /* Release srst bit */
2161 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2162 MDIO_PMA_DEVAD,
2163 MDIO_PMA_REG_GEN_CTRL,
2164 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2165
2166 /* wait for 100ms for code download via SPI port */
2167 msleep(100);
2168
2169 /* Clear ser_boot_ctl bit */
2170 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2171 MDIO_PMA_DEVAD,
2172 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
2173
2174 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
2175 MDIO_PMA_DEVAD,
2176 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
2177 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
2178 MDIO_PMA_DEVAD,
2179 MDIO_PMA_REG_ROM_VER2, &fw_ver2);
2180 DP(NETIF_MSG_LINK, "8073 FW version 0x%x:0x%x\n", fw_ver1, fw_ver2);
2181
2182 /* Only set bit 10 = 1 (Tx power down) */
2183 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
2184 MDIO_PMA_DEVAD,
2185 MDIO_PMA_REG_TX_POWER_DOWN, &val);
2186
2187 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2188 MDIO_PMA_DEVAD,
2189 MDIO_PMA_REG_TX_POWER_DOWN, (val | 1<<10));
2190
2191 msleep(600);
2192 /* Release bit 10 (Release Tx power down) */
2193 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2194 MDIO_PMA_DEVAD,
2195 MDIO_PMA_REG_TX_POWER_DOWN, (val & (~(1<<10))));
2196
2197}
2198
2199static void bnx2x_bcm8073_set_xaui_low_power_mode(struct link_params *params)
2200{
2201 struct bnx2x *bp = params->bp;
2202 u8 port = params->port;
2203 u16 val;
2204 u8 ext_phy_addr = ((params->ext_phy_config &
2205 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2206 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2207 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2208
2209 bnx2x_cl45_read(bp, params->port,
2210 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2211 ext_phy_addr,
2212 MDIO_PMA_DEVAD,
2213 0xc801, &val);
2214
2215 if (val == 0) {
2216 /* Mustn't set low power mode in 8073 A0 */
2217 return;
2218 }
2219
2220 /* Disable PLL sequencer (use read-modify-write to clear bit 13) */
2221 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
2222 MDIO_XS_DEVAD,
2223 MDIO_XS_PLL_SEQUENCER, &val);
2224 val &= ~(1<<13);
2225 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2226 MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
2227
2228 /* PLL controls */
2229 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2230 MDIO_XS_DEVAD, 0x805E, 0x1077);
2231 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2232 MDIO_XS_DEVAD, 0x805D, 0x0000);
2233 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2234 MDIO_XS_DEVAD, 0x805C, 0x030B);
2235 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2236 MDIO_XS_DEVAD, 0x805B, 0x1240);
2237 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2238 MDIO_XS_DEVAD, 0x805A, 0x2490);
2239
2240 /* Tx Controls */
2241 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2242 MDIO_XS_DEVAD, 0x80A7, 0x0C74);
2243 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2244 MDIO_XS_DEVAD, 0x80A6, 0x9041);
2245 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2246 MDIO_XS_DEVAD, 0x80A5, 0x4640);
2247
2248 /* Rx Controls */
2249 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2250 MDIO_XS_DEVAD, 0x80FE, 0x01C4);
2251 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2252 MDIO_XS_DEVAD, 0x80FD, 0x9249);
2253 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2254 MDIO_XS_DEVAD, 0x80FC, 0x2015);
2255
2256 /* Enable PLL sequencer (use read-modify-write to set bit 13) */
2257 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
2258 MDIO_XS_DEVAD,
2259 MDIO_XS_PLL_SEQUENCER, &val);
2260 val |= (1<<13);
2261 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2262 MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
2263}
2264static void bnx2x_bcm807x_force_10G(struct link_params *params)
2265{
2266 struct bnx2x *bp = params->bp;
2267 u8 port = params->port;
2268 u8 ext_phy_addr = ((params->ext_phy_config &
2269 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2270 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2271 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2272
2273 /* Force KR or KX */
2274 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2275 MDIO_PMA_DEVAD,
2276 MDIO_PMA_REG_CTRL,
2277 0x2040);
2278 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2279 MDIO_PMA_DEVAD,
2280 MDIO_PMA_REG_10G_CTRL2,
2281 0x000b);
2282 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2283 MDIO_PMA_DEVAD,
2284 MDIO_PMA_REG_BCM_CTRL,
2285 0x0000);
2286 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2287 MDIO_AN_DEVAD,
2288 MDIO_AN_REG_CTRL,
2289 0x0000);
2290}
2291
2292static void bnx2x_ext_phy_set_pause(struct link_params *params,
2293 struct link_vars *vars)
2294{
2295 struct bnx2x *bp = params->bp;
2296 u16 val;
2297 u8 ext_phy_addr = ((params->ext_phy_config &
2298 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2299 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2300 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2301
2302 /* read modify write pause advertizing */
2303 bnx2x_cl45_read(bp, params->port,
2304 ext_phy_type,
2305 ext_phy_addr,
2306 MDIO_AN_DEVAD,
2307 MDIO_AN_REG_ADV_PAUSE, &val);
2308
2309 val &= ~MDIO_AN_REG_ADV_PAUSE_BOTH;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002310
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002311 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
2312
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002313 if ((vars->ieee_fc &
2314 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002315 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
2316 val |= MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC;
2317 }
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002318 if ((vars->ieee_fc &
2319 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002320 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
2321 val |=
2322 MDIO_AN_REG_ADV_PAUSE_PAUSE;
2323 }
2324 DP(NETIF_MSG_LINK,
2325 "Ext phy AN advertize 0x%x\n", val);
2326 bnx2x_cl45_write(bp, params->port,
2327 ext_phy_type,
2328 ext_phy_addr,
2329 MDIO_AN_DEVAD,
2330 MDIO_AN_REG_ADV_PAUSE, val);
2331}
2332
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002333
2334static void bnx2x_init_internal_phy(struct link_params *params,
2335 struct link_vars *vars)
2336{
2337 struct bnx2x *bp = params->bp;
2338 u8 port = params->port;
2339 if (!(vars->phy_flags & PHY_SGMII_FLAG)) {
2340 u16 bank, rx_eq;
2341
2342 rx_eq = ((params->serdes_config &
2343 PORT_HW_CFG_SERDES_RX_DRV_EQUALIZER_MASK) >>
2344 PORT_HW_CFG_SERDES_RX_DRV_EQUALIZER_SHIFT);
2345
2346 DP(NETIF_MSG_LINK, "setting rx eq to 0x%x\n", rx_eq);
2347 for (bank = MDIO_REG_BANK_RX0; bank <= MDIO_REG_BANK_RX_ALL;
2348 bank += (MDIO_REG_BANK_RX1-MDIO_REG_BANK_RX0)) {
2349 CL45_WR_OVER_CL22(bp, port,
2350 params->phy_addr,
2351 bank ,
2352 MDIO_RX0_RX_EQ_BOOST,
2353 ((rx_eq &
2354 MDIO_RX0_RX_EQ_BOOST_EQUALIZER_CTRL_MASK) |
2355 MDIO_RX0_RX_EQ_BOOST_OFFSET_CTRL));
2356 }
2357
2358 /* forced speed requested? */
2359 if (vars->line_speed != SPEED_AUTO_NEG) {
2360 DP(NETIF_MSG_LINK, "not SGMII, no AN\n");
2361
2362 /* disable autoneg */
2363 bnx2x_set_autoneg(params, vars);
2364
2365 /* program speed and duplex */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002366 bnx2x_program_serdes(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002367
2368 } else { /* AN_mode */
2369 DP(NETIF_MSG_LINK, "not SGMII, AN\n");
2370
2371 /* AN enabled */
2372 bnx2x_set_brcm_cl37_advertisment(params);
2373
2374 /* program duplex & pause advertisement (for aneg) */
2375 bnx2x_set_ieee_aneg_advertisment(params,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002376 vars->ieee_fc);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002377
2378 /* enable autoneg */
2379 bnx2x_set_autoneg(params, vars);
2380
2381 /* enable and restart AN */
2382 bnx2x_restart_autoneg(params);
2383 }
2384
2385 } else { /* SGMII mode */
2386 DP(NETIF_MSG_LINK, "SGMII\n");
2387
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002388 bnx2x_initialize_sgmii_process(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002389 }
2390}
2391
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002392static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
2393{
2394 struct bnx2x *bp = params->bp;
2395 u32 ext_phy_type;
2396 u8 ext_phy_addr;
2397 u16 cnt;
2398 u16 ctrl = 0;
2399 u16 val = 0;
2400 u8 rc = 0;
2401 if (vars->phy_flags & PHY_XGXS_FLAG) {
2402 ext_phy_addr = ((params->ext_phy_config &
2403 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2404 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2405
2406 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2407 /* Make sure that the soft reset is off (expect for the 8072:
2408 * due to the lock, it will be done inside the specific
2409 * handling)
2410 */
2411 if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
2412 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
2413 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN) &&
2414 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) &&
2415 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073)) {
2416 /* Wait for soft reset to get cleared upto 1 sec */
2417 for (cnt = 0; cnt < 1000; cnt++) {
2418 bnx2x_cl45_read(bp, params->port,
2419 ext_phy_type,
2420 ext_phy_addr,
2421 MDIO_PMA_DEVAD,
2422 MDIO_PMA_REG_CTRL, &ctrl);
2423 if (!(ctrl & (1<<15)))
2424 break;
2425 msleep(1);
2426 }
2427 DP(NETIF_MSG_LINK, "control reg 0x%x (after %d ms)\n",
2428 ctrl, cnt);
2429 }
2430
2431 switch (ext_phy_type) {
2432 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002433 break;
2434
2435 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
2436 DP(NETIF_MSG_LINK, "XGXS 8705\n");
2437
2438 bnx2x_cl45_write(bp, params->port,
2439 ext_phy_type,
2440 ext_phy_addr,
2441 MDIO_PMA_DEVAD,
2442 MDIO_PMA_REG_MISC_CTRL,
2443 0x8288);
2444 bnx2x_cl45_write(bp, params->port,
2445 ext_phy_type,
2446 ext_phy_addr,
2447 MDIO_PMA_DEVAD,
2448 MDIO_PMA_REG_PHY_IDENTIFIER,
2449 0x7fbf);
2450 bnx2x_cl45_write(bp, params->port,
2451 ext_phy_type,
2452 ext_phy_addr,
2453 MDIO_PMA_DEVAD,
2454 MDIO_PMA_REG_CMU_PLL_BYPASS,
2455 0x0100);
2456 bnx2x_cl45_write(bp, params->port,
2457 ext_phy_type,
2458 ext_phy_addr,
2459 MDIO_WIS_DEVAD,
2460 MDIO_WIS_REG_LASI_CNTL, 0x1);
2461 break;
2462
2463 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
2464 DP(NETIF_MSG_LINK, "XGXS 8706\n");
2465
2466 msleep(10);
2467 /* Force speed */
2468 /* First enable LASI */
2469 bnx2x_cl45_write(bp, params->port,
2470 ext_phy_type,
2471 ext_phy_addr,
2472 MDIO_PMA_DEVAD,
2473 MDIO_PMA_REG_RX_ALARM_CTRL,
2474 0x0400);
2475 bnx2x_cl45_write(bp, params->port,
2476 ext_phy_type,
2477 ext_phy_addr,
2478 MDIO_PMA_DEVAD,
2479 MDIO_PMA_REG_LASI_CTRL, 0x0004);
2480
2481 if (params->req_line_speed == SPEED_10000) {
2482 DP(NETIF_MSG_LINK, "XGXS 8706 force 10Gbps\n");
2483
2484 bnx2x_cl45_write(bp, params->port,
2485 ext_phy_type,
2486 ext_phy_addr,
2487 MDIO_PMA_DEVAD,
2488 MDIO_PMA_REG_DIGITAL_CTRL,
2489 0x400);
2490 } else {
2491 /* Force 1Gbps using autoneg with 1G
2492 advertisment */
2493
2494 /* Allow CL37 through CL73 */
2495 DP(NETIF_MSG_LINK, "XGXS 8706 AutoNeg\n");
2496 bnx2x_cl45_write(bp, params->port,
2497 ext_phy_type,
2498 ext_phy_addr,
2499 MDIO_AN_DEVAD,
2500 MDIO_AN_REG_CL37_CL73,
2501 0x040c);
2502
2503 /* Enable Full-Duplex advertisment on CL37 */
2504 bnx2x_cl45_write(bp, params->port,
2505 ext_phy_type,
2506 ext_phy_addr,
2507 MDIO_AN_DEVAD,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002508 MDIO_AN_REG_CL37_FC_LP,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002509 0x0020);
2510 /* Enable CL37 AN */
2511 bnx2x_cl45_write(bp, params->port,
2512 ext_phy_type,
2513 ext_phy_addr,
2514 MDIO_AN_DEVAD,
2515 MDIO_AN_REG_CL37_AN,
2516 0x1000);
2517 /* 1G support */
2518 bnx2x_cl45_write(bp, params->port,
2519 ext_phy_type,
2520 ext_phy_addr,
2521 MDIO_AN_DEVAD,
2522 MDIO_AN_REG_ADV, (1<<5));
2523
2524 /* Enable clause 73 AN */
2525 bnx2x_cl45_write(bp, params->port,
2526 ext_phy_type,
2527 ext_phy_addr,
2528 MDIO_AN_DEVAD,
2529 MDIO_AN_REG_CTRL,
2530 0x1200);
2531
2532 }
2533
2534 break;
2535
2536 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
2537 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
2538 {
2539 u16 tmp1;
2540 u16 rx_alarm_ctrl_val;
2541 u16 lasi_ctrl_val;
2542 if (ext_phy_type ==
2543 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) {
2544 rx_alarm_ctrl_val = 0x400;
2545 lasi_ctrl_val = 0x0004;
2546 } else {
2547 /* In 8073, port1 is directed through emac0 and
2548 * port0 is directed through emac1
2549 */
2550 rx_alarm_ctrl_val = (1<<2);
2551 /*lasi_ctrl_val = 0x0005;*/
2552 lasi_ctrl_val = 0x0004;
2553 }
2554
2555 /* Wait for soft reset to get cleared upto 1 sec */
2556 for (cnt = 0; cnt < 1000; cnt++) {
2557 bnx2x_cl45_read(bp, params->port,
2558 ext_phy_type,
2559 ext_phy_addr,
2560 MDIO_PMA_DEVAD,
2561 MDIO_PMA_REG_CTRL,
2562 &ctrl);
2563 if (!(ctrl & (1<<15)))
2564 break;
2565 msleep(1);
2566 }
2567 DP(NETIF_MSG_LINK,
2568 "807x control reg 0x%x (after %d ms)\n",
2569 ctrl, cnt);
2570
2571 if (ext_phy_type ==
2572 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072){
2573 bnx2x_bcm8072_external_rom_boot(params);
2574 } else {
2575 bnx2x_bcm8073_external_rom_boot(params);
2576 /* In case of 8073 with long xaui lines,
2577 don't set the 8073 xaui low power*/
2578 bnx2x_bcm8073_set_xaui_low_power_mode(params);
2579 }
2580
2581 /* enable LASI */
2582 bnx2x_cl45_write(bp, params->port,
2583 ext_phy_type,
2584 ext_phy_addr,
2585 MDIO_PMA_DEVAD,
2586 MDIO_PMA_REG_RX_ALARM_CTRL,
2587 rx_alarm_ctrl_val);
2588
2589 bnx2x_cl45_write(bp, params->port,
2590 ext_phy_type,
2591 ext_phy_addr,
2592 MDIO_PMA_DEVAD,
2593 MDIO_PMA_REG_LASI_CTRL,
2594 lasi_ctrl_val);
2595
2596 bnx2x_cl45_read(bp, params->port,
2597 ext_phy_type,
2598 ext_phy_addr,
2599 MDIO_PMA_DEVAD,
2600 MDIO_PMA_REG_RX_ALARM, &tmp1);
2601
2602 DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1):"
2603 "0x%x\n", tmp1);
2604
2605 /* If this is forced speed, set to KR or KX
2606 * (all other are not supported)
2607 */
2608 if (!(params->req_line_speed == SPEED_AUTO_NEG)) {
2609 if (params->req_line_speed == SPEED_10000) {
2610 bnx2x_bcm807x_force_10G(params);
2611 DP(NETIF_MSG_LINK,
2612 "Forced speed 10G on 807X\n");
2613 break;
2614 } else if (params->req_line_speed ==
2615 SPEED_2500) {
2616 val = (1<<5);
2617 /* Note that 2.5G works only
2618 when used with 1G advertisment */
2619 } else
2620 val = (1<<5);
2621 } else {
2622
2623 val = 0;
2624 if (params->speed_cap_mask &
2625 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
2626 val |= (1<<7);
2627
2628 if (params->speed_cap_mask &
2629 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
2630 val |= (1<<5);
2631 DP(NETIF_MSG_LINK, "807x autoneg val = 0x%x\n", val);
2632 /*val = ((1<<5)|(1<<7));*/
2633 }
2634
2635 bnx2x_cl45_write(bp, params->port,
2636 ext_phy_type,
2637 ext_phy_addr,
2638 MDIO_AN_DEVAD,
2639 MDIO_AN_REG_ADV, val);
2640
2641 if (ext_phy_type ==
2642 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
2643 /* Disable 2.5Ghz */
2644 bnx2x_cl45_read(bp, params->port,
2645 ext_phy_type,
2646 ext_phy_addr,
2647 MDIO_AN_DEVAD,
2648 0x8329, &tmp1);
2649/* SUPPORT_SPEED_CAPABILITY
2650 (Due to the nature of the link order, its not
2651 possible to enable 2.5G within the autoneg
2652 capabilities)
2653 if (params->speed_cap_mask &
2654 PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G)
2655*/
2656 if (params->req_line_speed == SPEED_2500) {
2657 u16 phy_ver;
2658 /* Allow 2.5G for A1 and above */
2659 bnx2x_cl45_read(bp, params->port,
2660 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2661 ext_phy_addr,
2662 MDIO_PMA_DEVAD,
2663 0xc801, &phy_ver);
2664
2665 if (phy_ver > 0)
2666 tmp1 |= 1;
2667 else
2668 tmp1 &= 0xfffe;
2669 }
2670 else
2671 tmp1 &= 0xfffe;
2672
2673 bnx2x_cl45_write(bp, params->port,
2674 ext_phy_type,
2675 ext_phy_addr,
2676 MDIO_AN_DEVAD,
2677 0x8329, tmp1);
2678 }
2679 /* Add support for CL37 (passive mode) I */
2680 bnx2x_cl45_write(bp, params->port,
2681 ext_phy_type,
2682 ext_phy_addr,
2683 MDIO_AN_DEVAD,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002684 MDIO_AN_REG_CL37_FC_LD, 0x040c);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002685 /* Add support for CL37 (passive mode) II */
2686 bnx2x_cl45_write(bp, params->port,
2687 ext_phy_type,
2688 ext_phy_addr,
2689 MDIO_AN_DEVAD,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002690 MDIO_AN_REG_CL37_FC_LD, 0x20);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002691 /* Add support for CL37 (passive mode) III */
2692 bnx2x_cl45_write(bp, params->port,
2693 ext_phy_type,
2694 ext_phy_addr,
2695 MDIO_AN_DEVAD,
2696 MDIO_AN_REG_CL37_AN, 0x1000);
2697 /* Restart autoneg */
2698 msleep(500);
2699
2700 if (ext_phy_type ==
2701 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
2702
2703 /* The SNR will improve about 2db by changing the
2704 BW and FEE main tap. Rest commands are executed
2705 after link is up*/
2706 /* Change FFE main cursor to 5 in EDC register */
2707 if (bnx2x_8073_is_snr_needed(params))
2708 bnx2x_cl45_write(bp, params->port,
2709 ext_phy_type,
2710 ext_phy_addr,
2711 MDIO_PMA_DEVAD,
2712 MDIO_PMA_REG_EDC_FFE_MAIN,
2713 0xFB0C);
2714
2715 /* Enable FEC (Forware Error Correction)
2716 Request in the AN */
2717 bnx2x_cl45_read(bp, params->port,
2718 ext_phy_type,
2719 ext_phy_addr,
2720 MDIO_AN_DEVAD,
2721 MDIO_AN_REG_ADV2, &tmp1);
2722
2723 tmp1 |= (1<<15);
2724
2725 bnx2x_cl45_write(bp, params->port,
2726 ext_phy_type,
2727 ext_phy_addr,
2728 MDIO_AN_DEVAD,
2729 MDIO_AN_REG_ADV2, tmp1);
2730 }
2731
2732 bnx2x_ext_phy_set_pause(params, vars);
2733
2734 bnx2x_cl45_write(bp, params->port,
2735 ext_phy_type,
2736 ext_phy_addr,
2737 MDIO_AN_DEVAD,
2738 MDIO_AN_REG_CTRL, 0x1200);
2739 DP(NETIF_MSG_LINK, "807x Autoneg Restart: "
2740 "Advertise 1G=%x, 10G=%x\n",
2741 ((val & (1<<5)) > 0),
2742 ((val & (1<<7)) > 0));
2743 break;
2744 }
2745 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
2746 DP(NETIF_MSG_LINK,
2747 "Setting the SFX7101 LASI indication\n");
2748
2749 bnx2x_cl45_write(bp, params->port,
2750 ext_phy_type,
2751 ext_phy_addr,
2752 MDIO_PMA_DEVAD,
2753 MDIO_PMA_REG_LASI_CTRL, 0x1);
2754 DP(NETIF_MSG_LINK,
2755 "Setting the SFX7101 LED to blink on traffic\n");
2756 bnx2x_cl45_write(bp, params->port,
2757 ext_phy_type,
2758 ext_phy_addr,
2759 MDIO_PMA_DEVAD,
2760 MDIO_PMA_REG_7107_LED_CNTL, (1<<3));
2761
2762 bnx2x_ext_phy_set_pause(params, vars);
2763 /* Restart autoneg */
2764 bnx2x_cl45_read(bp, params->port,
2765 ext_phy_type,
2766 ext_phy_addr,
2767 MDIO_AN_DEVAD,
2768 MDIO_AN_REG_CTRL, &val);
2769 val |= 0x200;
2770 bnx2x_cl45_write(bp, params->port,
2771 ext_phy_type,
2772 ext_phy_addr,
2773 MDIO_AN_DEVAD,
2774 MDIO_AN_REG_CTRL, val);
2775 break;
2776 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
2777 DP(NETIF_MSG_LINK,
2778 "XGXS PHY Failure detected 0x%x\n",
2779 params->ext_phy_config);
2780 rc = -EINVAL;
2781 break;
2782 default:
2783 DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
2784 params->ext_phy_config);
2785 rc = -EINVAL;
2786 break;
2787 }
2788
2789 } else { /* SerDes */
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002790
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002791 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
2792 switch (ext_phy_type) {
2793 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
2794 DP(NETIF_MSG_LINK, "SerDes Direct\n");
2795 break;
2796
2797 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
2798 DP(NETIF_MSG_LINK, "SerDes 5482\n");
2799 break;
2800
2801 default:
2802 DP(NETIF_MSG_LINK, "BAD SerDes ext_phy_config 0x%x\n",
2803 params->ext_phy_config);
2804 break;
2805 }
2806 }
2807 return rc;
2808}
2809
2810
2811static u8 bnx2x_ext_phy_is_link_up(struct link_params *params,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002812 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002813{
2814 struct bnx2x *bp = params->bp;
2815 u32 ext_phy_type;
2816 u8 ext_phy_addr;
2817 u16 val1 = 0, val2;
2818 u16 rx_sd, pcs_status;
2819 u8 ext_phy_link_up = 0;
2820 u8 port = params->port;
2821 if (vars->phy_flags & PHY_XGXS_FLAG) {
2822 ext_phy_addr = ((params->ext_phy_config &
2823 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2824 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2825
2826 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2827 switch (ext_phy_type) {
2828 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
2829 DP(NETIF_MSG_LINK, "XGXS Direct\n");
2830 ext_phy_link_up = 1;
2831 break;
2832
2833 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
2834 DP(NETIF_MSG_LINK, "XGXS 8705\n");
2835 bnx2x_cl45_read(bp, params->port, ext_phy_type,
2836 ext_phy_addr,
2837 MDIO_WIS_DEVAD,
2838 MDIO_WIS_REG_LASI_STATUS, &val1);
2839 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
2840
2841 bnx2x_cl45_read(bp, params->port, ext_phy_type,
2842 ext_phy_addr,
2843 MDIO_WIS_DEVAD,
2844 MDIO_WIS_REG_LASI_STATUS, &val1);
2845 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
2846
2847 bnx2x_cl45_read(bp, params->port, ext_phy_type,
2848 ext_phy_addr,
2849 MDIO_PMA_DEVAD,
2850 MDIO_PMA_REG_RX_SD, &rx_sd);
2851 DP(NETIF_MSG_LINK, "8705 rx_sd 0x%x\n", rx_sd);
2852 ext_phy_link_up = (rx_sd & 0x1);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002853 if (ext_phy_link_up)
2854 vars->line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002855 break;
2856
2857 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
2858 DP(NETIF_MSG_LINK, "XGXS 8706\n");
2859 bnx2x_cl45_read(bp, params->port, ext_phy_type,
2860 ext_phy_addr,
2861 MDIO_PMA_DEVAD,
2862 MDIO_PMA_REG_LASI_STATUS, &val1);
2863 DP(NETIF_MSG_LINK, "8706 LASI status 0x%x\n", val1);
2864
2865 bnx2x_cl45_read(bp, params->port, ext_phy_type,
2866 ext_phy_addr,
2867 MDIO_PMA_DEVAD,
2868 MDIO_PMA_REG_LASI_STATUS, &val1);
2869 DP(NETIF_MSG_LINK, "8706 LASI status 0x%x\n", val1);
2870
2871 bnx2x_cl45_read(bp, params->port, ext_phy_type,
2872 ext_phy_addr,
2873 MDIO_PMA_DEVAD,
2874 MDIO_PMA_REG_RX_SD, &rx_sd);
2875 bnx2x_cl45_read(bp, params->port, ext_phy_type,
2876 ext_phy_addr,
2877 MDIO_PCS_DEVAD,
2878 MDIO_PCS_REG_STATUS, &pcs_status);
2879
2880 bnx2x_cl45_read(bp, params->port, ext_phy_type,
2881 ext_phy_addr,
2882 MDIO_AN_DEVAD,
2883 MDIO_AN_REG_LINK_STATUS, &val2);
2884 bnx2x_cl45_read(bp, params->port, ext_phy_type,
2885 ext_phy_addr,
2886 MDIO_AN_DEVAD,
2887 MDIO_AN_REG_LINK_STATUS, &val2);
2888
2889 DP(NETIF_MSG_LINK, "8706 rx_sd 0x%x"
2890 " pcs_status 0x%x 1Gbps link_status 0x%x\n",
2891 rx_sd, pcs_status, val2);
2892 /* link is up if both bit 0 of pmd_rx_sd and
2893 * bit 0 of pcs_status are set, or if the autoneg bit
2894 1 is set
2895 */
2896 ext_phy_link_up = ((rx_sd & pcs_status & 0x1) ||
2897 (val2 & (1<<1)));
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002898 if (ext_phy_link_up) {
2899 if (val2 & (1<<1))
2900 vars->line_speed = SPEED_1000;
2901 else
2902 vars->line_speed = SPEED_10000;
2903 }
2904
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002905 /* clear LASI indication*/
2906 bnx2x_cl45_read(bp, params->port, ext_phy_type,
2907 ext_phy_addr,
2908 MDIO_PMA_DEVAD,
2909 MDIO_PMA_REG_RX_ALARM, &val2);
2910 break;
2911
2912 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
2913 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
2914 {
2915 if (ext_phy_type ==
2916 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) {
2917 bnx2x_cl45_read(bp, params->port,
2918 ext_phy_type,
2919 ext_phy_addr,
2920 MDIO_PCS_DEVAD,
2921 MDIO_PCS_REG_LASI_STATUS, &val1);
2922 bnx2x_cl45_read(bp, params->port,
2923 ext_phy_type,
2924 ext_phy_addr,
2925 MDIO_PCS_DEVAD,
2926 MDIO_PCS_REG_LASI_STATUS, &val2);
2927 DP(NETIF_MSG_LINK,
2928 "870x LASI status 0x%x->0x%x\n",
2929 val1, val2);
2930
2931 } else {
2932 /* In 8073, port1 is directed through emac0 and
2933 * port0 is directed through emac1
2934 */
2935 bnx2x_cl45_read(bp, params->port,
2936 ext_phy_type,
2937 ext_phy_addr,
2938 MDIO_PMA_DEVAD,
2939 MDIO_PMA_REG_LASI_STATUS, &val1);
2940
2941 bnx2x_cl45_read(bp, params->port,
2942 ext_phy_type,
2943 ext_phy_addr,
2944 MDIO_PMA_DEVAD,
2945 MDIO_PMA_REG_LASI_STATUS, &val2);
2946 DP(NETIF_MSG_LINK,
2947 "8703 LASI status 0x%x->0x%x\n",
2948 val1, val2);
2949 }
2950
2951 /* clear the interrupt LASI status register */
2952 bnx2x_cl45_read(bp, params->port,
2953 ext_phy_type,
2954 ext_phy_addr,
2955 MDIO_PCS_DEVAD,
2956 MDIO_PCS_REG_STATUS, &val2);
2957 bnx2x_cl45_read(bp, params->port,
2958 ext_phy_type,
2959 ext_phy_addr,
2960 MDIO_PCS_DEVAD,
2961 MDIO_PCS_REG_STATUS, &val1);
2962 DP(NETIF_MSG_LINK, "807x PCS status 0x%x->0x%x\n",
2963 val2, val1);
2964 /* Check the LASI */
2965 bnx2x_cl45_read(bp, params->port,
2966 ext_phy_type,
2967 ext_phy_addr,
2968 MDIO_PMA_DEVAD,
2969 MDIO_PMA_REG_RX_ALARM, &val2);
2970 bnx2x_cl45_read(bp, params->port,
2971 ext_phy_type,
2972 ext_phy_addr,
2973 MDIO_PMA_DEVAD,
2974 MDIO_PMA_REG_RX_ALARM,
2975 &val1);
2976 DP(NETIF_MSG_LINK, "KR 0x9003 0x%x->0x%x\n",
2977 val2, val1);
2978 /* Check the link status */
2979 bnx2x_cl45_read(bp, params->port,
2980 ext_phy_type,
2981 ext_phy_addr,
2982 MDIO_PCS_DEVAD,
2983 MDIO_PCS_REG_STATUS, &val2);
2984 DP(NETIF_MSG_LINK, "KR PCS status 0x%x\n", val2);
2985
2986 bnx2x_cl45_read(bp, params->port,
2987 ext_phy_type,
2988 ext_phy_addr,
2989 MDIO_PMA_DEVAD,
2990 MDIO_PMA_REG_STATUS, &val2);
2991 bnx2x_cl45_read(bp, params->port,
2992 ext_phy_type,
2993 ext_phy_addr,
2994 MDIO_PMA_DEVAD,
2995 MDIO_PMA_REG_STATUS, &val1);
2996 ext_phy_link_up = ((val1 & 4) == 4);
2997 DP(NETIF_MSG_LINK, "PMA_REG_STATUS=0x%x\n", val1);
2998 if (ext_phy_type ==
2999 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
3000 u16 an1000_status = 0;
3001 if (ext_phy_link_up &&
3002 (
3003 (params->req_line_speed != SPEED_10000)
3004 )) {
3005 if (bnx2x_bcm8073_xaui_wa(params)
3006 != 0) {
3007 ext_phy_link_up = 0;
3008 break;
3009 }
3010 bnx2x_cl45_read(bp, params->port,
3011 ext_phy_type,
3012 ext_phy_addr,
3013 MDIO_XS_DEVAD,
3014 0x8304,
3015 &an1000_status);
3016 bnx2x_cl45_read(bp, params->port,
3017 ext_phy_type,
3018 ext_phy_addr,
3019 MDIO_XS_DEVAD,
3020 0x8304,
3021 &an1000_status);
3022 }
3023 /* Check the link status on 1.1.2 */
3024 bnx2x_cl45_read(bp, params->port,
3025 ext_phy_type,
3026 ext_phy_addr,
3027 MDIO_PMA_DEVAD,
3028 MDIO_PMA_REG_STATUS, &val2);
3029 bnx2x_cl45_read(bp, params->port,
3030 ext_phy_type,
3031 ext_phy_addr,
3032 MDIO_PMA_DEVAD,
3033 MDIO_PMA_REG_STATUS, &val1);
3034 DP(NETIF_MSG_LINK, "KR PMA status 0x%x->0x%x,"
3035 "an_link_status=0x%x\n",
3036 val2, val1, an1000_status);
3037
3038 ext_phy_link_up = (((val1 & 4) == 4) ||
3039 (an1000_status & (1<<1)));
3040 if (ext_phy_link_up &&
3041 bnx2x_8073_is_snr_needed(params)) {
3042 /* The SNR will improve about 2dbby
3043 changing the BW and FEE main tap.*/
3044
3045 /* The 1st write to change FFE main
3046 tap is set before restart AN */
3047 /* Change PLL Bandwidth in EDC
3048 register */
3049 bnx2x_cl45_write(bp, port, ext_phy_type,
3050 ext_phy_addr,
3051 MDIO_PMA_DEVAD,
3052 MDIO_PMA_REG_PLL_BANDWIDTH,
3053 0x26BC);
3054
3055 /* Change CDR Bandwidth in EDC
3056 register */
3057 bnx2x_cl45_write(bp, port, ext_phy_type,
3058 ext_phy_addr,
3059 MDIO_PMA_DEVAD,
3060 MDIO_PMA_REG_CDR_BANDWIDTH,
3061 0x0333);
3062
3063 }
3064 }
3065 break;
3066 }
3067 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
3068 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3069 ext_phy_addr,
3070 MDIO_PMA_DEVAD,
3071 MDIO_PMA_REG_LASI_STATUS, &val2);
3072 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3073 ext_phy_addr,
3074 MDIO_PMA_DEVAD,
3075 MDIO_PMA_REG_LASI_STATUS, &val1);
3076 DP(NETIF_MSG_LINK,
3077 "10G-base-T LASI status 0x%x->0x%x\n",
3078 val2, val1);
3079 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3080 ext_phy_addr,
3081 MDIO_PMA_DEVAD,
3082 MDIO_PMA_REG_STATUS, &val2);
3083 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3084 ext_phy_addr,
3085 MDIO_PMA_DEVAD,
3086 MDIO_PMA_REG_STATUS, &val1);
3087 DP(NETIF_MSG_LINK,
3088 "10G-base-T PMA status 0x%x->0x%x\n",
3089 val2, val1);
3090 ext_phy_link_up = ((val1 & 4) == 4);
3091 /* if link is up
3092 * print the AN outcome of the SFX7101 PHY
3093 */
3094 if (ext_phy_link_up) {
3095 bnx2x_cl45_read(bp, params->port,
3096 ext_phy_type,
3097 ext_phy_addr,
3098 MDIO_AN_DEVAD,
3099 MDIO_AN_REG_MASTER_STATUS,
3100 &val2);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003101 vars->line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003102 DP(NETIF_MSG_LINK,
3103 "SFX7101 AN status 0x%x->Master=%x\n",
3104 val2,
3105 (val2 & (1<<14)));
3106 }
3107 break;
3108
3109 default:
3110 DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
3111 params->ext_phy_config);
3112 ext_phy_link_up = 0;
3113 break;
3114 }
3115
3116 } else { /* SerDes */
3117 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
3118 switch (ext_phy_type) {
3119 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
3120 DP(NETIF_MSG_LINK, "SerDes Direct\n");
3121 ext_phy_link_up = 1;
3122 break;
3123
3124 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
3125 DP(NETIF_MSG_LINK, "SerDes 5482\n");
3126 ext_phy_link_up = 1;
3127 break;
3128
3129 default:
3130 DP(NETIF_MSG_LINK,
3131 "BAD SerDes ext_phy_config 0x%x\n",
3132 params->ext_phy_config);
3133 ext_phy_link_up = 0;
3134 break;
3135 }
3136 }
3137
3138 return ext_phy_link_up;
3139}
3140
3141static void bnx2x_link_int_enable(struct link_params *params)
3142{
3143 u8 port = params->port;
3144 u32 ext_phy_type;
3145 u32 mask;
3146 struct bnx2x *bp = params->bp;
3147 /* setting the status to report on link up
3148 for either XGXS or SerDes */
3149
3150 if (params->switch_cfg == SWITCH_CFG_10G) {
3151 mask = (NIG_MASK_XGXS0_LINK10G |
3152 NIG_MASK_XGXS0_LINK_STATUS);
3153 DP(NETIF_MSG_LINK, "enabled XGXS interrupt\n");
3154 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3155 if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
3156 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
3157 (ext_phy_type !=
3158 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)) {
3159 mask |= NIG_MASK_MI_INT;
3160 DP(NETIF_MSG_LINK, "enabled external phy int\n");
3161 }
3162
3163 } else { /* SerDes */
3164 mask = NIG_MASK_SERDES0_LINK_STATUS;
3165 DP(NETIF_MSG_LINK, "enabled SerDes interrupt\n");
3166 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
3167 if ((ext_phy_type !=
3168 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT) &&
3169 (ext_phy_type !=
3170 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_NOT_CONN)) {
3171 mask |= NIG_MASK_MI_INT;
3172 DP(NETIF_MSG_LINK, "enabled external phy int\n");
3173 }
3174 }
3175 bnx2x_bits_en(bp,
3176 NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
3177 mask);
3178 DP(NETIF_MSG_LINK, "port %x, is_xgxs=%x, int_status 0x%x\n", port,
3179 (params->switch_cfg == SWITCH_CFG_10G),
3180 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
3181
3182 DP(NETIF_MSG_LINK, " int_mask 0x%x, MI_INT %x, SERDES_LINK %x\n",
3183 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
3184 REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
3185 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS+port*0x3c));
3186 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
3187 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
3188 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
3189}
3190
3191
3192/*
3193 * link management
3194 */
3195static void bnx2x_link_int_ack(struct link_params *params,
3196 struct link_vars *vars, u16 is_10g)
3197{
3198 struct bnx2x *bp = params->bp;
3199 u8 port = params->port;
3200
3201 /* first reset all status
3202 * we assume only one line will be change at a time */
3203 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
3204 (NIG_STATUS_XGXS0_LINK10G |
3205 NIG_STATUS_XGXS0_LINK_STATUS |
3206 NIG_STATUS_SERDES0_LINK_STATUS));
3207 if (vars->phy_link_up) {
3208 if (is_10g) {
3209 /* Disable the 10G link interrupt
3210 * by writing 1 to the status register
3211 */
3212 DP(NETIF_MSG_LINK, "10G XGXS phy link up\n");
3213 bnx2x_bits_en(bp,
3214 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
3215 NIG_STATUS_XGXS0_LINK10G);
3216
3217 } else if (params->switch_cfg == SWITCH_CFG_10G) {
3218 /* Disable the link interrupt
3219 * by writing 1 to the relevant lane
3220 * in the status register
3221 */
3222 u32 ser_lane = ((params->lane_config &
3223 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
3224 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
3225
3226 DP(NETIF_MSG_LINK, "1G XGXS phy link up\n");
3227 bnx2x_bits_en(bp,
3228 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
3229 ((1 << ser_lane) <<
3230 NIG_STATUS_XGXS0_LINK_STATUS_SIZE));
3231
3232 } else { /* SerDes */
3233 DP(NETIF_MSG_LINK, "SerDes phy link up\n");
3234 /* Disable the link interrupt
3235 * by writing 1 to the status register
3236 */
3237 bnx2x_bits_en(bp,
3238 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
3239 NIG_STATUS_SERDES0_LINK_STATUS);
3240 }
3241
3242 } else { /* link_down */
3243 }
3244}
3245
3246static u8 bnx2x_format_ver(u32 num, u8 *str, u16 len)
3247{
3248 u8 *str_ptr = str;
3249 u32 mask = 0xf0000000;
3250 u8 shift = 8*4;
3251 u8 digit;
3252 if (len < 10) {
3253 /* Need more then 10chars for this format */
3254 *str_ptr = '\0';
3255 return -EINVAL;
3256 }
3257 while (shift > 0) {
3258
3259 shift -= 4;
3260 digit = ((num & mask) >> shift);
3261 if (digit < 0xa)
3262 *str_ptr = digit + '0';
3263 else
3264 *str_ptr = digit - 0xa + 'a';
3265 str_ptr++;
3266 mask = mask >> 4;
3267 if (shift == 4*4) {
3268 *str_ptr = ':';
3269 str_ptr++;
3270 }
3271 }
3272 *str_ptr = '\0';
3273 return 0;
3274}
3275
3276
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003277static void bnx2x_turn_on_ef(struct bnx2x *bp, u8 port, u8 ext_phy_addr,
3278 u32 ext_phy_type)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003279{
3280 u32 cnt = 0;
3281 u16 ctrl = 0;
3282 /* Enable EMAC0 in to enable MDIO */
3283 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
3284 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
3285 msleep(5);
3286
3287 /* take ext phy out of reset */
3288 bnx2x_set_gpio(bp,
3289 MISC_REGISTERS_GPIO_2,
3290 MISC_REGISTERS_GPIO_HIGH);
3291
3292 bnx2x_set_gpio(bp,
3293 MISC_REGISTERS_GPIO_1,
3294 MISC_REGISTERS_GPIO_HIGH);
3295
3296 /* wait for 5ms */
3297 msleep(5);
3298
3299 for (cnt = 0; cnt < 1000; cnt++) {
3300 msleep(1);
3301 bnx2x_cl45_read(bp, port,
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003302 ext_phy_type,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003303 ext_phy_addr,
3304 MDIO_PMA_DEVAD,
3305 MDIO_PMA_REG_CTRL,
3306 &ctrl);
3307 if (!(ctrl & (1<<15))) {
3308 DP(NETIF_MSG_LINK, "Reset completed\n\n");
3309 break;
3310 }
3311 }
3312}
3313
3314static void bnx2x_turn_off_sf(struct bnx2x *bp)
3315{
3316 /* put sf to reset */
3317 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1, MISC_REGISTERS_GPIO_LOW);
3318 bnx2x_set_gpio(bp,
3319 MISC_REGISTERS_GPIO_2,
3320 MISC_REGISTERS_GPIO_LOW);
3321}
3322
3323u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
3324 u8 *version, u16 len)
3325{
3326 struct bnx2x *bp = params->bp;
3327 u32 ext_phy_type = 0;
3328 u16 val = 0;
3329 u8 ext_phy_addr = 0 ;
3330 u8 status = 0 ;
3331 u32 ver_num;
3332
3333 if (version == NULL || params == NULL)
3334 return -EINVAL;
3335
3336 /* reset the returned value to zero */
3337 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3338 ext_phy_addr = ((params->ext_phy_config &
3339 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
3340 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
3341
3342 switch (ext_phy_type) {
3343 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
3344
3345 if (len < 5)
3346 return -EINVAL;
3347
3348 /* Take ext phy out of reset */
3349 if (!driver_loaded)
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003350 bnx2x_turn_on_ef(bp, params->port, ext_phy_addr,
3351 ext_phy_type);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003352
3353 /* wait for 1ms */
3354 msleep(1);
3355
3356 bnx2x_cl45_read(bp, params->port,
3357 ext_phy_type,
3358 ext_phy_addr,
3359 MDIO_PMA_DEVAD,
3360 MDIO_PMA_REG_7101_VER1, &val);
3361 version[2] = (val & 0xFF);
3362 version[3] = ((val & 0xFF00)>>8);
3363
3364 bnx2x_cl45_read(bp, params->port,
3365 ext_phy_type,
3366 ext_phy_addr,
3367 MDIO_PMA_DEVAD, MDIO_PMA_REG_7101_VER2,
3368 &val);
3369 version[0] = (val & 0xFF);
3370 version[1] = ((val & 0xFF00)>>8);
3371 version[4] = '\0';
3372
3373 if (!driver_loaded)
3374 bnx2x_turn_off_sf(bp);
3375 break;
3376 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
3377 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
3378 {
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003379 /* Take ext phy out of reset */
3380 if (!driver_loaded)
3381 bnx2x_turn_on_ef(bp, params->port, ext_phy_addr,
3382 ext_phy_type);
3383
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003384 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3385 ext_phy_addr,
3386 MDIO_PMA_DEVAD,
3387 MDIO_PMA_REG_ROM_VER1, &val);
3388 ver_num = val<<16;
3389 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3390 ext_phy_addr,
3391 MDIO_PMA_DEVAD,
3392 MDIO_PMA_REG_ROM_VER2, &val);
3393 ver_num |= val;
3394 status = bnx2x_format_ver(ver_num, version, len);
3395 break;
3396 }
3397 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
3398 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
3399
3400 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3401 ext_phy_addr,
3402 MDIO_PMA_DEVAD,
3403 MDIO_PMA_REG_ROM_VER1, &val);
3404 ver_num = val<<16;
3405 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3406 ext_phy_addr,
3407 MDIO_PMA_DEVAD,
3408 MDIO_PMA_REG_ROM_VER2, &val);
3409 ver_num |= val;
3410 status = bnx2x_format_ver(ver_num, version, len);
3411 break;
3412
3413 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
3414 break;
3415
3416 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
3417 DP(NETIF_MSG_LINK, "bnx2x_get_ext_phy_fw_version:"
3418 " type is FAILURE!\n");
3419 status = -EINVAL;
3420 break;
3421
3422 default:
3423 break;
3424 }
3425 return status;
3426}
3427
3428static void bnx2x_set_xgxs_loopback(struct link_params *params,
3429 struct link_vars *vars,
3430 u8 is_10g)
3431{
3432 u8 port = params->port;
3433 struct bnx2x *bp = params->bp;
3434
3435 if (is_10g) {
3436 u32 md_devad;
3437
3438 DP(NETIF_MSG_LINK, "XGXS 10G loopback enable\n");
3439
3440 /* change the uni_phy_addr in the nig */
3441 md_devad = REG_RD(bp, (NIG_REG_XGXS0_CTRL_MD_DEVAD +
3442 port*0x18));
3443
3444 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, 0x5);
3445
3446 bnx2x_cl45_write(bp, port, 0,
3447 params->phy_addr,
3448 5,
3449 (MDIO_REG_BANK_AER_BLOCK +
3450 (MDIO_AER_BLOCK_AER_REG & 0xf)),
3451 0x2800);
3452
3453 bnx2x_cl45_write(bp, port, 0,
3454 params->phy_addr,
3455 5,
3456 (MDIO_REG_BANK_CL73_IEEEB0 +
3457 (MDIO_CL73_IEEEB0_CL73_AN_CONTROL & 0xf)),
3458 0x6041);
3459
3460 /* set aer mmd back */
3461 bnx2x_set_aer_mmd(params, vars);
3462
3463 /* and md_devad */
3464 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
3465 md_devad);
3466
3467 } else {
3468 u16 mii_control;
3469
3470 DP(NETIF_MSG_LINK, "XGXS 1G loopback enable\n");
3471
3472 CL45_RD_OVER_CL22(bp, port,
3473 params->phy_addr,
3474 MDIO_REG_BANK_COMBO_IEEE0,
3475 MDIO_COMBO_IEEE0_MII_CONTROL,
3476 &mii_control);
3477
3478 CL45_WR_OVER_CL22(bp, port,
3479 params->phy_addr,
3480 MDIO_REG_BANK_COMBO_IEEE0,
3481 MDIO_COMBO_IEEE0_MII_CONTROL,
3482 (mii_control |
3483 MDIO_COMBO_IEEO_MII_CONTROL_LOOPBACK));
3484 }
3485}
3486
3487
3488static void bnx2x_ext_phy_loopback(struct link_params *params)
3489{
3490 struct bnx2x *bp = params->bp;
3491 u8 ext_phy_addr;
3492 u32 ext_phy_type;
3493
3494 if (params->switch_cfg == SWITCH_CFG_10G) {
3495 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3496 /* CL37 Autoneg Enabled */
3497 ext_phy_addr = ((params->ext_phy_config &
3498 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
3499 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
3500 switch (ext_phy_type) {
3501 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
3502 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN:
3503 DP(NETIF_MSG_LINK,
3504 "ext_phy_loopback: We should not get here\n");
3505 break;
3506 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
3507 DP(NETIF_MSG_LINK, "ext_phy_loopback: 8705\n");
3508 break;
3509 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
3510 DP(NETIF_MSG_LINK, "ext_phy_loopback: 8706\n");
3511 break;
3512 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
3513 /* SFX7101_XGXS_TEST1 */
3514 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3515 ext_phy_addr,
3516 MDIO_XS_DEVAD,
3517 MDIO_XS_SFX7101_XGXS_TEST1,
3518 0x100);
3519 DP(NETIF_MSG_LINK,
3520 "ext_phy_loopback: set ext phy loopback\n");
3521 break;
3522 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
3523
3524 break;
3525 } /* switch external PHY type */
3526 } else {
3527 /* serdes */
3528 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
3529 ext_phy_addr = (params->ext_phy_config &
3530 PORT_HW_CFG_SERDES_EXT_PHY_ADDR_MASK)
3531 >> PORT_HW_CFG_SERDES_EXT_PHY_ADDR_SHIFT;
3532 }
3533}
3534
3535
3536/*
3537 *------------------------------------------------------------------------
3538 * bnx2x_override_led_value -
3539 *
3540 * Override the led value of the requsted led
3541 *
3542 *------------------------------------------------------------------------
3543 */
3544u8 bnx2x_override_led_value(struct bnx2x *bp, u8 port,
3545 u32 led_idx, u32 value)
3546{
3547 u32 reg_val;
3548
3549 /* If port 0 then use EMAC0, else use EMAC1*/
3550 u32 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
3551
3552 DP(NETIF_MSG_LINK,
3553 "bnx2x_override_led_value() port %x led_idx %d value %d\n",
3554 port, led_idx, value);
3555
3556 switch (led_idx) {
3557 case 0: /* 10MB led */
3558 /* Read the current value of the LED register in
3559 the EMAC block */
3560 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
3561 /* Set the OVERRIDE bit to 1 */
3562 reg_val |= EMAC_LED_OVERRIDE;
3563 /* If value is 1, set the 10M_OVERRIDE bit,
3564 otherwise reset it.*/
3565 reg_val = (value == 1) ? (reg_val | EMAC_LED_10MB_OVERRIDE) :
3566 (reg_val & ~EMAC_LED_10MB_OVERRIDE);
3567 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
3568 break;
3569 case 1: /*100MB led */
3570 /*Read the current value of the LED register in
3571 the EMAC block */
3572 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
3573 /* Set the OVERRIDE bit to 1 */
3574 reg_val |= EMAC_LED_OVERRIDE;
3575 /* If value is 1, set the 100M_OVERRIDE bit,
3576 otherwise reset it.*/
3577 reg_val = (value == 1) ? (reg_val | EMAC_LED_100MB_OVERRIDE) :
3578 (reg_val & ~EMAC_LED_100MB_OVERRIDE);
3579 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
3580 break;
3581 case 2: /* 1000MB led */
3582 /* Read the current value of the LED register in the
3583 EMAC block */
3584 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
3585 /* Set the OVERRIDE bit to 1 */
3586 reg_val |= EMAC_LED_OVERRIDE;
3587 /* If value is 1, set the 1000M_OVERRIDE bit, otherwise
3588 reset it. */
3589 reg_val = (value == 1) ? (reg_val | EMAC_LED_1000MB_OVERRIDE) :
3590 (reg_val & ~EMAC_LED_1000MB_OVERRIDE);
3591 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
3592 break;
3593 case 3: /* 2500MB led */
3594 /* Read the current value of the LED register in the
3595 EMAC block*/
3596 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
3597 /* Set the OVERRIDE bit to 1 */
3598 reg_val |= EMAC_LED_OVERRIDE;
3599 /* If value is 1, set the 2500M_OVERRIDE bit, otherwise
3600 reset it.*/
3601 reg_val = (value == 1) ? (reg_val | EMAC_LED_2500MB_OVERRIDE) :
3602 (reg_val & ~EMAC_LED_2500MB_OVERRIDE);
3603 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
3604 break;
3605 case 4: /*10G led */
3606 if (port == 0) {
3607 REG_WR(bp, NIG_REG_LED_10G_P0,
3608 value);
3609 } else {
3610 REG_WR(bp, NIG_REG_LED_10G_P1,
3611 value);
3612 }
3613 break;
3614 case 5: /* TRAFFIC led */
3615 /* Find if the traffic control is via BMAC or EMAC */
3616 if (port == 0)
3617 reg_val = REG_RD(bp, NIG_REG_NIG_EMAC0_EN);
3618 else
3619 reg_val = REG_RD(bp, NIG_REG_NIG_EMAC1_EN);
3620
3621 /* Override the traffic led in the EMAC:*/
3622 if (reg_val == 1) {
3623 /* Read the current value of the LED register in
3624 the EMAC block */
3625 reg_val = REG_RD(bp, emac_base +
3626 EMAC_REG_EMAC_LED);
3627 /* Set the TRAFFIC_OVERRIDE bit to 1 */
3628 reg_val |= EMAC_LED_OVERRIDE;
3629 /* If value is 1, set the TRAFFIC bit, otherwise
3630 reset it.*/
3631 reg_val = (value == 1) ? (reg_val | EMAC_LED_TRAFFIC) :
3632 (reg_val & ~EMAC_LED_TRAFFIC);
3633 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
3634 } else { /* Override the traffic led in the BMAC: */
3635 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
3636 + port*4, 1);
3637 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 + port*4,
3638 value);
3639 }
3640 break;
3641 default:
3642 DP(NETIF_MSG_LINK,
3643 "bnx2x_override_led_value() unknown led index %d "
3644 "(should be 0-5)\n", led_idx);
3645 return -EINVAL;
3646 }
3647
3648 return 0;
3649}
3650
3651
3652u8 bnx2x_set_led(struct bnx2x *bp, u8 port, u8 mode, u32 speed,
3653 u16 hw_led_mode, u32 chip_id)
3654{
3655 u8 rc = 0;
3656 DP(NETIF_MSG_LINK, "bnx2x_set_led: port %x, mode %d\n", port, mode);
3657 DP(NETIF_MSG_LINK, "speed 0x%x, hw_led_mode 0x%x\n",
3658 speed, hw_led_mode);
3659 switch (mode) {
3660 case LED_MODE_OFF:
3661 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 0);
3662 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
3663 SHARED_HW_CFG_LED_MAC1);
3664 break;
3665
3666 case LED_MODE_OPER:
3667 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, hw_led_mode);
3668 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 +
3669 port*4, 0);
3670 /* Set blinking rate to ~15.9Hz */
3671 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4,
3672 LED_BLINK_RATE_VAL);
3673 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 +
3674 port*4, 1);
Eilon Greenstein34f80b02008-06-23 20:33:01 -07003675 if (!CHIP_IS_E1H(bp) &&
3676 ((speed == SPEED_2500) ||
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003677 (speed == SPEED_1000) ||
3678 (speed == SPEED_100) ||
3679 (speed == SPEED_10))) {
3680 /* On Everest 1 Ax chip versions for speeds less than
3681 10G LED scheme is different */
3682 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
3683 + port*4, 1);
3684 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 +
3685 port*4, 0);
3686 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_TRAFFIC_P0 +
3687 port*4, 1);
3688 }
3689 break;
3690
3691 default:
3692 rc = -EINVAL;
3693 DP(NETIF_MSG_LINK, "bnx2x_set_led: Invalid led mode %d\n",
3694 mode);
3695 break;
3696 }
3697 return rc;
3698
3699}
3700
3701u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars)
3702{
3703 struct bnx2x *bp = params->bp;
3704 u16 gp_status = 0;
3705
3706 CL45_RD_OVER_CL22(bp, params->port,
3707 params->phy_addr,
3708 MDIO_REG_BANK_GP_STATUS,
3709 MDIO_GP_STATUS_TOP_AN_STATUS1,
3710 &gp_status);
3711 /* link is up only if both local phy and external phy are up */
3712 if ((gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) &&
3713 bnx2x_ext_phy_is_link_up(params, vars))
3714 return 0;
3715
3716 return -ESRCH;
3717}
3718
3719static u8 bnx2x_link_initialize(struct link_params *params,
3720 struct link_vars *vars)
3721{
3722 struct bnx2x *bp = params->bp;
3723 u8 port = params->port;
3724 u8 rc = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003725 u8 non_ext_phy;
3726 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003727 /* Activate the external PHY */
3728 bnx2x_ext_phy_reset(params, vars);
3729
3730 bnx2x_set_aer_mmd(params, vars);
3731
3732 if (vars->phy_flags & PHY_XGXS_FLAG)
3733 bnx2x_set_master_ln(params);
3734
3735 rc = bnx2x_reset_unicore(params);
3736 /* reset the SerDes and wait for reset bit return low */
3737 if (rc != 0)
3738 return rc;
3739
3740 bnx2x_set_aer_mmd(params, vars);
3741
3742 /* setting the masterLn_def again after the reset */
3743 if (vars->phy_flags & PHY_XGXS_FLAG) {
3744 bnx2x_set_master_ln(params);
3745 bnx2x_set_swap_lanes(params);
3746 }
3747
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003748 if (vars->phy_flags & PHY_XGXS_FLAG) {
3749 if (params->req_line_speed &&
3750 ((params->req_line_speed == SPEED_100) ||
3751 (params->req_line_speed == SPEED_10))) {
3752 vars->phy_flags |= PHY_SGMII_FLAG;
3753 } else {
3754 vars->phy_flags &= ~PHY_SGMII_FLAG;
3755 }
3756 }
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003757 /* In case of external phy existance, the line speed would be the
3758 line speed linked up by the external phy. In case it is direct only,
3759 then the line_speed during initialization will be equal to the
3760 req_line_speed*/
3761 vars->line_speed = params->req_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003762
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003763 bnx2x_calc_ieee_aneg_adv(params, &vars->ieee_fc);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003764
3765 /* init ext phy and enable link state int */
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003766 non_ext_phy = ((ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ||
3767 (params->loopback_mode == LOOPBACK_XGXS_10) ||
3768 (params->loopback_mode == LOOPBACK_EXT_PHY));
3769
3770 if (non_ext_phy ||
3771 (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705)) {
3772 if (params->req_line_speed == SPEED_AUTO_NEG)
3773 bnx2x_set_parallel_detection(params, vars->phy_flags);
3774 bnx2x_init_internal_phy(params, vars);
3775 }
3776
3777 if (!non_ext_phy)
3778 rc |= bnx2x_ext_phy_init(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003779
3780 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003781 (NIG_STATUS_XGXS0_LINK10G |
3782 NIG_STATUS_XGXS0_LINK_STATUS |
3783 NIG_STATUS_SERDES0_LINK_STATUS));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003784
3785 return rc;
3786
3787}
3788
3789
3790u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
3791{
3792 struct bnx2x *bp = params->bp;
3793
3794 u32 val;
3795 DP(NETIF_MSG_LINK, "Phy Initialization started\n");
3796 DP(NETIF_MSG_LINK, "req_speed = %d, req_flowctrl=%d\n",
3797 params->req_line_speed, params->req_flow_ctrl);
3798 vars->link_status = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003799 vars->phy_link_up = 0;
3800 vars->link_up = 0;
3801 vars->line_speed = 0;
3802 vars->duplex = DUPLEX_FULL;
3803 vars->flow_ctrl = FLOW_CTRL_NONE;
3804 vars->mac_type = MAC_TYPE_NONE;
3805
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003806 if (params->switch_cfg == SWITCH_CFG_1G)
3807 vars->phy_flags = PHY_SERDES_FLAG;
3808 else
3809 vars->phy_flags = PHY_XGXS_FLAG;
3810
3811 /* disable attentions */
3812 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4,
3813 (NIG_MASK_XGXS0_LINK_STATUS |
3814 NIG_MASK_XGXS0_LINK10G |
3815 NIG_MASK_SERDES0_LINK_STATUS |
3816 NIG_MASK_MI_INT));
3817
3818 bnx2x_emac_init(params, vars);
3819
3820 if (CHIP_REV_IS_FPGA(bp)) {
3821 vars->link_up = 1;
3822 vars->line_speed = SPEED_10000;
3823 vars->duplex = DUPLEX_FULL;
3824 vars->flow_ctrl = FLOW_CTRL_NONE;
3825 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
Eilon Greenstein34f80b02008-06-23 20:33:01 -07003826 /* enable on E1.5 FPGA */
3827 if (CHIP_IS_E1H(bp)) {
3828 vars->flow_ctrl |=
3829 (FLOW_CTRL_TX | FLOW_CTRL_RX);
3830 vars->link_status |=
3831 (LINK_STATUS_TX_FLOW_CONTROL_ENABLED |
3832 LINK_STATUS_RX_FLOW_CONTROL_ENABLED);
3833 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003834
3835 bnx2x_emac_enable(params, vars, 0);
3836 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
3837 /* disable drain */
3838 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
3839 + params->port*4, 0);
3840
3841 /* update shared memory */
3842 bnx2x_update_mng(params, vars->link_status);
3843
3844 return 0;
3845
3846 } else
3847 if (CHIP_REV_IS_EMUL(bp)) {
3848
3849 vars->link_up = 1;
3850 vars->line_speed = SPEED_10000;
3851 vars->duplex = DUPLEX_FULL;
3852 vars->flow_ctrl = FLOW_CTRL_NONE;
3853 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
3854
3855 bnx2x_bmac_enable(params, vars, 0);
3856
3857 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
3858 /* Disable drain */
3859 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
3860 + params->port*4, 0);
3861
3862 /* update shared memory */
3863 bnx2x_update_mng(params, vars->link_status);
3864
3865 return 0;
3866
3867 } else
3868 if (params->loopback_mode == LOOPBACK_BMAC) {
3869 vars->link_up = 1;
3870 vars->line_speed = SPEED_10000;
3871 vars->duplex = DUPLEX_FULL;
3872 vars->flow_ctrl = FLOW_CTRL_NONE;
3873 vars->mac_type = MAC_TYPE_BMAC;
3874
3875 vars->phy_flags = PHY_XGXS_FLAG;
3876
3877 bnx2x_phy_deassert(params, vars->phy_flags);
3878 /* set bmac loopback */
3879 bnx2x_bmac_enable(params, vars, 1);
3880
3881 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
3882 params->port*4, 0);
3883 } else if (params->loopback_mode == LOOPBACK_EMAC) {
3884 vars->link_up = 1;
3885 vars->line_speed = SPEED_1000;
3886 vars->duplex = DUPLEX_FULL;
3887 vars->flow_ctrl = FLOW_CTRL_NONE;
3888 vars->mac_type = MAC_TYPE_EMAC;
3889
3890 vars->phy_flags = PHY_XGXS_FLAG;
3891
3892 bnx2x_phy_deassert(params, vars->phy_flags);
3893 /* set bmac loopback */
3894 bnx2x_emac_enable(params, vars, 1);
3895 bnx2x_emac_program(params, vars->line_speed,
3896 vars->duplex);
3897 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
3898 params->port*4, 0);
3899 } else if ((params->loopback_mode == LOOPBACK_XGXS_10) ||
3900 (params->loopback_mode == LOOPBACK_EXT_PHY)) {
3901 vars->link_up = 1;
3902 vars->line_speed = SPEED_10000;
3903 vars->duplex = DUPLEX_FULL;
3904 vars->flow_ctrl = FLOW_CTRL_NONE;
3905
3906 vars->phy_flags = PHY_XGXS_FLAG;
3907
3908 val = REG_RD(bp,
3909 NIG_REG_XGXS0_CTRL_PHY_ADDR+
3910 params->port*0x18);
3911 params->phy_addr = (u8)val;
3912
3913 bnx2x_phy_deassert(params, vars->phy_flags);
3914 bnx2x_link_initialize(params, vars);
3915
3916 vars->mac_type = MAC_TYPE_BMAC;
3917
3918 bnx2x_bmac_enable(params, vars, 0);
3919
3920 if (params->loopback_mode == LOOPBACK_XGXS_10) {
3921 /* set 10G XGXS loopback */
3922 bnx2x_set_xgxs_loopback(params, vars, 1);
3923 } else {
3924 /* set external phy loopback */
3925 bnx2x_ext_phy_loopback(params);
3926 }
3927 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
3928 params->port*4, 0);
3929 } else
3930 /* No loopback */
3931 {
3932
3933 bnx2x_phy_deassert(params, vars->phy_flags);
3934 switch (params->switch_cfg) {
3935 case SWITCH_CFG_1G:
3936 vars->phy_flags |= PHY_SERDES_FLAG;
3937 if ((params->ext_phy_config &
3938 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_MASK) ==
3939 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482) {
3940 vars->phy_flags |=
3941 PHY_SGMII_FLAG;
3942 }
3943
3944 val = REG_RD(bp,
3945 NIG_REG_SERDES0_CTRL_PHY_ADDR+
3946 params->port*0x10);
3947
3948 params->phy_addr = (u8)val;
3949
3950 break;
3951 case SWITCH_CFG_10G:
3952 vars->phy_flags |= PHY_XGXS_FLAG;
3953 val = REG_RD(bp,
3954 NIG_REG_XGXS0_CTRL_PHY_ADDR+
3955 params->port*0x18);
3956 params->phy_addr = (u8)val;
3957
3958 break;
3959 default:
3960 DP(NETIF_MSG_LINK, "Invalid switch_cfg\n");
3961 return -EINVAL;
3962 break;
3963 }
3964
3965 bnx2x_link_initialize(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003966 msleep(30);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003967 bnx2x_link_int_enable(params);
3968 }
3969 return 0;
3970}
3971
3972u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars)
3973{
3974
3975 struct bnx2x *bp = params->bp;
3976 u32 ext_phy_config = params->ext_phy_config;
3977 u16 hw_led_mode = params->hw_led_mode;
3978 u32 chip_id = params->chip_id;
3979 u8 port = params->port;
3980 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
3981 /* disable attentions */
3982
3983 vars->link_status = 0;
3984 bnx2x_update_mng(params, vars->link_status);
3985 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
3986 (NIG_MASK_XGXS0_LINK_STATUS |
3987 NIG_MASK_XGXS0_LINK10G |
3988 NIG_MASK_SERDES0_LINK_STATUS |
3989 NIG_MASK_MI_INT));
3990
3991 /* activate nig drain */
3992 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
3993
3994 /* disable nig egress interface */
3995 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
3996 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
3997
3998 /* Stop BigMac rx */
3999 bnx2x_bmac_rx_disable(bp, port);
4000
4001 /* disable emac */
4002 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
4003
4004 msleep(10);
4005 /* The PHY reset is controled by GPIO 1
4006 * Hold it as vars low
4007 */
4008 /* clear link led */
4009 bnx2x_set_led(bp, port, LED_MODE_OFF, 0, hw_led_mode, chip_id);
4010 if (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) {
4011 if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) &&
4012 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073)) {
4013 /* HW reset */
4014
4015 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
4016 MISC_REGISTERS_GPIO_OUTPUT_LOW);
4017
4018 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
4019 MISC_REGISTERS_GPIO_OUTPUT_LOW);
4020
4021 DP(NETIF_MSG_LINK, "reset external PHY\n");
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004022 } else if (ext_phy_type ==
4023 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
4024 DP(NETIF_MSG_LINK, "Setting 8073 port %d into "
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004025 "low power mode\n",
4026 port);
4027 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
4028 MISC_REGISTERS_GPIO_OUTPUT_LOW);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004029 }
4030 }
4031 /* reset the SerDes/XGXS */
4032 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
4033 (0x1ff << (port*16)));
4034
4035 /* reset BigMac */
4036 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
4037 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
4038
4039 /* disable nig ingress interface */
4040 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0);
4041 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0);
4042 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
4043 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
4044 vars->link_up = 0;
4045 return 0;
4046}
4047
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004048static u8 bnx2x_update_link_down(struct link_params *params,
4049 struct link_vars *vars)
4050{
4051 struct bnx2x *bp = params->bp;
4052 u8 port = params->port;
4053 DP(NETIF_MSG_LINK, "Port %x: Link is down\n", port);
4054 bnx2x_set_led(bp, port, LED_MODE_OFF,
4055 0, params->hw_led_mode,
4056 params->chip_id);
4057
4058 /* indicate no mac active */
4059 vars->mac_type = MAC_TYPE_NONE;
4060
4061 /* update shared memory */
4062 vars->link_status = 0;
4063 vars->line_speed = 0;
4064 bnx2x_update_mng(params, vars->link_status);
4065
4066 /* activate nig drain */
4067 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
4068
4069 /* reset BigMac */
4070 bnx2x_bmac_rx_disable(bp, params->port);
4071 REG_WR(bp, GRCBASE_MISC +
4072 MISC_REGISTERS_RESET_REG_2_CLEAR,
4073 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
4074 return 0;
4075}
4076
4077static u8 bnx2x_update_link_up(struct link_params *params,
4078 struct link_vars *vars,
4079 u8 link_10g, u32 gp_status)
4080{
4081 struct bnx2x *bp = params->bp;
4082 u8 port = params->port;
4083 u8 rc = 0;
4084 vars->link_status |= LINK_STATUS_LINK_UP;
4085 if (link_10g) {
4086 bnx2x_bmac_enable(params, vars, 0);
4087 bnx2x_set_led(bp, port, LED_MODE_OPER,
4088 SPEED_10000, params->hw_led_mode,
4089 params->chip_id);
4090
4091 } else {
4092 bnx2x_emac_enable(params, vars, 0);
4093 rc = bnx2x_emac_program(params, vars->line_speed,
4094 vars->duplex);
4095
4096 /* AN complete? */
4097 if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) {
4098 if (!(vars->phy_flags &
4099 PHY_SGMII_FLAG))
4100 bnx2x_set_sgmii_tx_driver(params);
4101 }
4102 }
4103
4104 /* PBF - link up */
4105 rc |= bnx2x_pbf_update(params, vars->flow_ctrl,
4106 vars->line_speed);
4107
4108 /* disable drain */
4109 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 0);
4110
4111 /* update shared memory */
4112 bnx2x_update_mng(params, vars->link_status);
4113 return rc;
4114}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004115/* This function should called upon link interrupt */
4116/* In case vars->link_up, driver needs to
4117 1. Update the pbf
4118 2. Disable drain
4119 3. Update the shared memory
4120 4. Indicate link up
4121 5. Set LEDs
4122 Otherwise,
4123 1. Update shared memory
4124 2. Reset BigMac
4125 3. Report link down
4126 4. Unset LEDs
4127*/
4128u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars)
4129{
4130 struct bnx2x *bp = params->bp;
4131 u8 port = params->port;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004132 u16 gp_status;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004133 u8 link_10g;
4134 u8 ext_phy_link_up, rc = 0;
4135 u32 ext_phy_type;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004136
4137 DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n",
4138 port,
4139 (vars->phy_flags & PHY_XGXS_FLAG),
4140 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
4141
4142 DP(NETIF_MSG_LINK, "int_mask 0x%x MI_INT %x, SERDES_LINK %x\n",
4143 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
4144 REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
4145 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c));
4146
4147 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
4148 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
4149 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
4150
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004151 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004152
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004153 /* Check external link change only for non-direct */
4154 ext_phy_link_up = bnx2x_ext_phy_is_link_up(params, vars);
4155
4156 /* Read gp_status */
4157 CL45_RD_OVER_CL22(bp, port, params->phy_addr,
4158 MDIO_REG_BANK_GP_STATUS,
4159 MDIO_GP_STATUS_TOP_AN_STATUS1,
4160 &gp_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004161
4162 rc = bnx2x_link_settings_status(params, vars, gp_status);
4163 if (rc != 0)
4164 return rc;
4165
4166 /* anything 10 and over uses the bmac */
4167 link_10g = ((vars->line_speed == SPEED_10000) ||
4168 (vars->line_speed == SPEED_12000) ||
4169 (vars->line_speed == SPEED_12500) ||
4170 (vars->line_speed == SPEED_13000) ||
4171 (vars->line_speed == SPEED_15000) ||
4172 (vars->line_speed == SPEED_16000));
4173
4174 bnx2x_link_int_ack(params, vars, link_10g);
4175
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004176 /* In case external phy link is up, and internal link is down
4177 ( not initialized yet probably after link initialization, it needs
4178 to be initialized.
4179 Note that after link down-up as result of cable plug,
4180 the xgxs link would probably become up again without the need to
4181 initialize it*/
4182
4183 if ((ext_phy_type != PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT) &&
4184 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) &&
4185 (ext_phy_link_up && !vars->phy_link_up))
4186 bnx2x_init_internal_phy(params, vars);
4187
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004188 /* link is up only if both local phy and external phy are up */
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004189 vars->link_up = (ext_phy_link_up && vars->phy_link_up);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004190
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004191 if (vars->link_up)
4192 rc = bnx2x_update_link_up(params, vars, link_10g, gp_status);
4193 else
4194 rc = bnx2x_update_link_down(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004195
4196 return rc;
4197}
4198
4199static void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, u8 port, u8 phy_addr)
4200{
4201 u16 val, cnt;
4202
4203 bnx2x_cl45_read(bp, port,
4204 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4205 phy_addr,
4206 MDIO_PMA_DEVAD,
4207 MDIO_PMA_REG_7101_RESET, &val);
4208
4209 for (cnt = 0; cnt < 10; cnt++) {
4210 msleep(50);
4211 /* Writes a self-clearing reset */
4212 bnx2x_cl45_write(bp, port,
4213 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4214 phy_addr,
4215 MDIO_PMA_DEVAD,
4216 MDIO_PMA_REG_7101_RESET,
4217 (val | (1<<15)));
4218 /* Wait for clear */
4219 bnx2x_cl45_read(bp, port,
4220 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4221 phy_addr,
4222 MDIO_PMA_DEVAD,
4223 MDIO_PMA_REG_7101_RESET, &val);
4224
4225 if ((val & (1<<15)) == 0)
4226 break;
4227 }
4228}
4229#define RESERVED_SIZE 256
4230/* max application is 160K bytes - data at end of RAM */
4231#define MAX_APP_SIZE 160*1024 - RESERVED_SIZE
4232
4233/* Header is 14 bytes */
4234#define HEADER_SIZE 14
4235#define DATA_OFFSET HEADER_SIZE
4236
4237#define SPI_START_TRANSFER(bp, port, ext_phy_addr) \
4238 bnx2x_cl45_write(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, \
4239 ext_phy_addr, \
4240 MDIO_PCS_DEVAD, \
4241 MDIO_PCS_REG_7101_SPI_CTRL_ADDR, 1)
4242
4243/* Programs an image to DSP's flash via the SPI port*/
4244static u8 bnx2x_sfx7101_flash_download(struct bnx2x *bp, u8 port,
4245 u8 ext_phy_addr,
4246 char data[], u32 size)
4247{
4248 const u16 num_trans = size/4; /* 4 bytes can be sent at a time */
4249 /* Doesn't include last trans!*/
4250 const u16 last_trans_size = size%4; /* Num bytes on last trans */
4251 u16 trans_cnt, byte_cnt;
4252 u32 data_index;
4253 u16 tmp;
4254 u16 code_started = 0;
4255 u16 image_revision1, image_revision2;
4256 u16 cnt;
4257
4258 DP(NETIF_MSG_LINK, "bnx2x_sfx7101_flash_download file_size=%d\n", size);
4259 /* Going to flash*/
4260 if ((size-HEADER_SIZE) > MAX_APP_SIZE) {
4261 /* This very often will be the case, because the image is built
4262 with 160Kbytes size whereas the total image size must actually
4263 be 160Kbytes-RESERVED_SIZE */
4264 DP(NETIF_MSG_LINK, "Warning, file size was %d bytes "
4265 "truncated to %d bytes\n", size, MAX_APP_SIZE);
4266 size = MAX_APP_SIZE+HEADER_SIZE;
4267 }
4268 DP(NETIF_MSG_LINK, "File version is %c%c\n", data[0x14e], data[0x14f]);
4269 DP(NETIF_MSG_LINK, " %c%c\n", data[0x150], data[0x151]);
4270 /* Put the DSP in download mode by setting FLASH_CFG[2] to 1
4271 and issuing a reset.*/
4272
4273 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
4274 MISC_REGISTERS_GPIO_HIGH);
4275
4276 bnx2x_sfx7101_sp_sw_reset(bp, port, ext_phy_addr);
4277
4278 /* wait 0.5 sec */
4279 for (cnt = 0; cnt < 100; cnt++)
4280 msleep(5);
4281
4282 /* Make sure we can access the DSP
4283 And it's in the correct mode (waiting for download) */
4284
4285 bnx2x_cl45_read(bp, port,
4286 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4287 ext_phy_addr,
4288 MDIO_PCS_DEVAD,
4289 MDIO_PCS_REG_7101_DSP_ACCESS, &tmp);
4290
4291 if (tmp != 0x000A) {
4292 DP(NETIF_MSG_LINK, "DSP is not in waiting on download mode. "
4293 "Expected 0x000A, read 0x%04X\n", tmp);
4294 DP(NETIF_MSG_LINK, "Download failed\n");
4295 return -EINVAL;
4296 }
4297
4298 /* Mux the SPI interface away from the internal processor */
4299 bnx2x_cl45_write(bp, port,
4300 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4301 ext_phy_addr,
4302 MDIO_PCS_DEVAD,
4303 MDIO_PCS_REG_7101_SPI_MUX, 1);
4304
4305 /* Reset the SPI port */
4306 bnx2x_cl45_write(bp, port,
4307 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4308 ext_phy_addr,
4309 MDIO_PCS_DEVAD,
4310 MDIO_PCS_REG_7101_SPI_CTRL_ADDR, 0);
4311 bnx2x_cl45_write(bp, port,
4312 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4313 ext_phy_addr,
4314 MDIO_PCS_DEVAD,
4315 MDIO_PCS_REG_7101_SPI_CTRL_ADDR,
4316 (1<<MDIO_PCS_REG_7101_SPI_RESET_BIT));
4317 bnx2x_cl45_write(bp, port,
4318 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4319 ext_phy_addr,
4320 MDIO_PCS_DEVAD,
4321 MDIO_PCS_REG_7101_SPI_CTRL_ADDR, 0);
4322
4323 /* Erase the flash */
4324 bnx2x_cl45_write(bp, port,
4325 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4326 ext_phy_addr,
4327 MDIO_PCS_DEVAD,
4328 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4329 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_WRITE_ENABLE_CMD);
4330
4331 bnx2x_cl45_write(bp, port,
4332 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4333 ext_phy_addr,
4334 MDIO_PCS_DEVAD,
4335 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
4336 1);
4337
4338 SPI_START_TRANSFER(bp, port, ext_phy_addr);
4339 bnx2x_cl45_write(bp, port,
4340 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4341 ext_phy_addr,
4342 MDIO_PCS_DEVAD,
4343 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4344 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_BULK_ERASE_CMD);
4345
4346 bnx2x_cl45_write(bp, port,
4347 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4348 ext_phy_addr,
4349 MDIO_PCS_DEVAD,
4350 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
4351 1);
4352 SPI_START_TRANSFER(bp, port, ext_phy_addr);
4353
4354 /* Wait 10 seconds, the maximum time for the erase to complete */
4355 DP(NETIF_MSG_LINK, "Erasing flash, this takes 10 seconds...\n");
4356 for (cnt = 0; cnt < 1000; cnt++)
4357 msleep(10);
4358
4359 DP(NETIF_MSG_LINK, "Downloading flash, please wait...\n");
4360 data_index = 0;
4361 for (trans_cnt = 0; trans_cnt < num_trans; trans_cnt++) {
4362 bnx2x_cl45_write(bp, port,
4363 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4364 ext_phy_addr,
4365 MDIO_PCS_DEVAD,
4366 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4367 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_WRITE_ENABLE_CMD);
4368
4369 bnx2x_cl45_write(bp, port,
4370 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4371 ext_phy_addr,
4372 MDIO_PCS_DEVAD,
4373 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
4374 1);
4375 SPI_START_TRANSFER(bp, port, ext_phy_addr);
4376
4377 bnx2x_cl45_write(bp, port,
4378 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4379 ext_phy_addr,
4380 MDIO_PCS_DEVAD,
4381 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4382 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_PAGE_PROGRAM_CMD);
4383
4384 /* Bits 23-16 of address */
4385 bnx2x_cl45_write(bp, port,
4386 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4387 ext_phy_addr,
4388 MDIO_PCS_DEVAD,
4389 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4390 (data_index>>16));
4391 /* Bits 15-8 of address */
4392 bnx2x_cl45_write(bp, port,
4393 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4394 ext_phy_addr,
4395 MDIO_PCS_DEVAD,
4396 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4397 (data_index>>8));
4398
4399 /* Bits 7-0 of address */
4400 bnx2x_cl45_write(bp, port,
4401 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4402 ext_phy_addr,
4403 MDIO_PCS_DEVAD,
4404 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4405 ((u16)data_index));
4406
4407 byte_cnt = 0;
4408 while (byte_cnt < 4 && data_index < size) {
4409 bnx2x_cl45_write(bp, port,
4410 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4411 ext_phy_addr,
4412 MDIO_PCS_DEVAD,
4413 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4414 data[data_index++]);
4415 byte_cnt++;
4416 }
4417
4418 bnx2x_cl45_write(bp, port,
4419 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4420 ext_phy_addr,
4421 MDIO_PCS_DEVAD,
4422 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
4423 byte_cnt+4);
4424
4425 SPI_START_TRANSFER(bp, port, ext_phy_addr);
4426 msleep(5); /* Wait 5 ms minimum between transs */
4427
4428 /* Let the user know something's going on.*/
4429 /* a pacifier ever 4K */
4430 if ((data_index % 1023) == 0)
4431 DP(NETIF_MSG_LINK, "Download %d%%\n", data_index/size);
4432 }
4433
4434 DP(NETIF_MSG_LINK, "\n");
4435 /* Transfer the last block if there is data remaining */
4436 if (last_trans_size) {
4437 bnx2x_cl45_write(bp, port,
4438 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4439 ext_phy_addr,
4440 MDIO_PCS_DEVAD,
4441 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4442 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_WRITE_ENABLE_CMD);
4443
4444 bnx2x_cl45_write(bp, port,
4445 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4446 ext_phy_addr,
4447 MDIO_PCS_DEVAD,
4448 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
4449 1);
4450
4451 SPI_START_TRANSFER(bp, port, ext_phy_addr);
4452
4453 bnx2x_cl45_write(bp, port,
4454 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4455 ext_phy_addr,
4456 MDIO_PCS_DEVAD,
4457 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4458 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_PAGE_PROGRAM_CMD);
4459
4460 /* Bits 23-16 of address */
4461 bnx2x_cl45_write(bp, port,
4462 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4463 ext_phy_addr,
4464 MDIO_PCS_DEVAD,
4465 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4466 (data_index>>16));
4467 /* Bits 15-8 of address */
4468 bnx2x_cl45_write(bp, port,
4469 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4470 ext_phy_addr,
4471 MDIO_PCS_DEVAD,
4472 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4473 (data_index>>8));
4474
4475 /* Bits 7-0 of address */
4476 bnx2x_cl45_write(bp, port,
4477 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4478 ext_phy_addr,
4479 MDIO_PCS_DEVAD,
4480 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4481 ((u16)data_index));
4482
4483 byte_cnt = 0;
4484 while (byte_cnt < last_trans_size && data_index < size) {
4485 /* Bits 7-0 of address */
4486 bnx2x_cl45_write(bp, port,
4487 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4488 ext_phy_addr,
4489 MDIO_PCS_DEVAD,
4490 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4491 data[data_index++]);
4492 byte_cnt++;
4493 }
4494
4495 bnx2x_cl45_write(bp, port,
4496 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4497 ext_phy_addr,
4498 MDIO_PCS_DEVAD,
4499 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
4500 byte_cnt+4);
4501
4502 SPI_START_TRANSFER(bp, port, ext_phy_addr);
4503 }
4504
4505 /* DSP Remove Download Mode */
4506 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0, MISC_REGISTERS_GPIO_LOW);
4507
4508 bnx2x_sfx7101_sp_sw_reset(bp, port, ext_phy_addr);
4509
4510 /* wait 0.5 sec to allow it to run */
4511 for (cnt = 0; cnt < 100; cnt++)
4512 msleep(5);
4513
4514 bnx2x_hw_reset(bp);
4515
4516 for (cnt = 0; cnt < 100; cnt++)
4517 msleep(5);
4518
4519 /* Check that the code is started. In case the download
4520 checksum failed, the code won't be started. */
4521 bnx2x_cl45_read(bp, port,
4522 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4523 ext_phy_addr,
4524 MDIO_PCS_DEVAD,
4525 MDIO_PCS_REG_7101_DSP_ACCESS,
4526 &tmp);
4527
4528 code_started = (tmp & (1<<4));
4529 if (!code_started) {
4530 DP(NETIF_MSG_LINK, "Download failed. Please check file.\n");
4531 return -EINVAL;
4532 }
4533
4534 /* Verify that the file revision is now equal to the image
4535 revision within the DSP */
4536 bnx2x_cl45_read(bp, port,
4537 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4538 ext_phy_addr,
4539 MDIO_PMA_DEVAD,
4540 MDIO_PMA_REG_7101_VER1,
4541 &image_revision1);
4542
4543 bnx2x_cl45_read(bp, port,
4544 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4545 ext_phy_addr,
4546 MDIO_PMA_DEVAD,
4547 MDIO_PMA_REG_7101_VER2,
4548 &image_revision2);
4549
4550 if (data[0x14e] != (image_revision2&0xFF) ||
4551 data[0x14f] != ((image_revision2&0xFF00)>>8) ||
4552 data[0x150] != (image_revision1&0xFF) ||
4553 data[0x151] != ((image_revision1&0xFF00)>>8)) {
4554 DP(NETIF_MSG_LINK, "Download failed.\n");
4555 return -EINVAL;
4556 }
4557 DP(NETIF_MSG_LINK, "Download %d%%\n", data_index/size);
4558 return 0;
4559}
4560
4561u8 bnx2x_flash_download(struct bnx2x *bp, u8 port, u32 ext_phy_config,
4562 u8 driver_loaded, char data[], u32 size)
4563{
4564 u8 rc = 0;
4565 u32 ext_phy_type;
4566 u8 ext_phy_addr;
4567 ext_phy_addr = ((ext_phy_config &
4568 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
4569 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
4570
4571 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
4572
4573 switch (ext_phy_type) {
4574 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
4575 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
4576 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
4577 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
4578 DP(NETIF_MSG_LINK,
4579 "Flash download not supported for this ext phy\n");
4580 rc = -EINVAL;
4581 break;
4582 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
4583 /* Take ext phy out of reset */
4584 if (!driver_loaded)
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004585 bnx2x_turn_on_ef(bp, port, ext_phy_addr, ext_phy_type);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004586 rc = bnx2x_sfx7101_flash_download(bp, port, ext_phy_addr,
4587 data, size);
4588 if (!driver_loaded)
4589 bnx2x_turn_off_sf(bp);
4590 break;
4591 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
4592 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
4593 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN:
4594 default:
4595 DP(NETIF_MSG_LINK, "Invalid ext phy type\n");
4596 rc = -EINVAL;
4597 break;
4598 }
4599 return rc;
4600}
4601