summaryrefslogtreecommitdiffstats
path: root/drivers/net/bnx2x_link.c
diff options
context:
space:
mode:
authorYaniv Rosner <yanivr@broadcom.com>2008-06-23 20:27:26 -0700
committerDavid S. Miller <davem@davemloft.net>2008-06-23 20:27:26 -0700
commitea4e040abc72f2dbbfdd8d04e271a18593ba72c7 (patch)
treedb16da50c6ff7a1a60480824c6ef06174b8fcdb1 /drivers/net/bnx2x_link.c
parent23bd462b6dd8b9d6ee2540a491e432c09dfcff4a (diff)
bnx2x: Adding bnx2x_link
This patch is int the new bnx2x_link files (C and H). The files are still not used in this patch, only in the next one so the patch will be small enough for the mailing list. Signed-off-by: Yaniv Rosner <yanivr@broadcom.com> Signed-off-by: Eilong Greenstein <eilong@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/bnx2x_link.c')
-rw-r--r--drivers/net/bnx2x_link.c4518
1 files changed, 4518 insertions, 0 deletions
diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c
new file mode 100644
index 000000000000..22586ebd7b1e
--- /dev/null
+++ b/drivers/net/bnx2x_link.c
@@ -0,0 +1,4518 @@
+/* Copyright 2008 Broadcom Corporation
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2, available
+ * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL").
+ *
+ * Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a
+ * license other than the GPL, without Broadcom's express prior written
+ * consent.
+ *
+ * Written by Yaniv Rosner
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/delay.h>
+#include <linux/ethtool.h>
+#include <linux/mutex.h>
+#include <linux/version.h>
+
+#include "bnx2x_reg.h"
+#include "bnx2x_fw_defs.h"
+#include "bnx2x_hsi.h"
+#include "bnx2x_link.h"
+#include "bnx2x.h"
+
+/********************************************************/
+#define SUPPORT_CL73 0 /* Currently no */
+#define ETH_HLEN 14
+#define ETH_OVREHEAD (ETH_HLEN + 8)/* 8 for CRC + VLAN*/
+#define ETH_MIN_PACKET_SIZE 60
+#define ETH_MAX_PACKET_SIZE 1500
+#define ETH_MAX_JUMBO_PACKET_SIZE 9600
+#define MDIO_ACCESS_TIMEOUT 1000
+#define BMAC_CONTROL_RX_ENABLE 2
+#define MAX_MTU_SIZE 5000
+
+/***********************************************************/
+/* Shortcut definitions */
+/***********************************************************/
+
+#define NIG_STATUS_XGXS0_LINK10G \
+ NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK10G
+#define NIG_STATUS_XGXS0_LINK_STATUS \
+ NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS
+#define NIG_STATUS_XGXS0_LINK_STATUS_SIZE \
+ NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS_SIZE
+#define NIG_STATUS_SERDES0_LINK_STATUS \
+ NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_SERDES0_LINK_STATUS
+#define NIG_MASK_MI_INT \
+ NIG_MASK_INTERRUPT_PORT0_REG_MASK_EMAC0_MISC_MI_INT
+#define NIG_MASK_XGXS0_LINK10G \
+ NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK10G
+#define NIG_MASK_XGXS0_LINK_STATUS \
+ NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK_STATUS
+#define NIG_MASK_SERDES0_LINK_STATUS \
+ NIG_MASK_INTERRUPT_PORT0_REG_MASK_SERDES0_LINK_STATUS
+
+#define MDIO_AN_CL73_OR_37_COMPLETE \
+ (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE | \
+ MDIO_GP_STATUS_TOP_AN_STATUS1_CL37_AUTONEG_COMPLETE)
+
+#define XGXS_RESET_BITS \
+ (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_RSTB_HW | \
+ MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_IDDQ | \
+ MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN | \
+ MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN_SD | \
+ MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_TXD_FIFO_RSTB)
+
+#define SERDES_RESET_BITS \
+ (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_RSTB_HW | \
+ MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_IDDQ | \
+ MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN | \
+ MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN_SD)
+
+#define AUTONEG_CL37 SHARED_HW_CFG_AN_ENABLE_CL37
+#define AUTONEG_CL73 SHARED_HW_CFG_AN_ENABLE_CL73
+#define AUTONEG_BAM SHARED_HW_CFG_AN_ENABLE_BAM
+#define AUTONEG_PARALLEL \
+ SHARED_HW_CFG_AN_ENABLE_PARALLEL_DETECTION
+#define AUTONEG_SGMII_FIBER_AUTODET \
+ SHARED_HW_CFG_AN_EN_SGMII_FIBER_AUTO_DETECT
+#define AUTONEG_REMOTE_PHY SHARED_HW_CFG_AN_ENABLE_REMOTE_PHY
+
+#define GP_STATUS_PAUSE_RSOLUTION_TXSIDE \
+ MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_TXSIDE
+#define GP_STATUS_PAUSE_RSOLUTION_RXSIDE \
+ MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_RXSIDE
+#define GP_STATUS_SPEED_MASK \
+ MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_MASK
+#define GP_STATUS_10M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10M
+#define GP_STATUS_100M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_100M
+#define GP_STATUS_1G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G
+#define GP_STATUS_2_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_2_5G
+#define GP_STATUS_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_5G
+#define GP_STATUS_6G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_6G
+#define GP_STATUS_10G_HIG \
+ MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_HIG
+#define GP_STATUS_10G_CX4 \
+ MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_CX4
+#define GP_STATUS_12G_HIG \
+ MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12G_HIG
+#define GP_STATUS_12_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12_5G
+#define GP_STATUS_13G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_13G
+#define GP_STATUS_15G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_15G
+#define GP_STATUS_16G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_16G
+#define GP_STATUS_1G_KX MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G_KX
+#define GP_STATUS_10G_KX4 \
+ MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_KX4
+
+#define LINK_10THD LINK_STATUS_SPEED_AND_DUPLEX_10THD
+#define LINK_10TFD LINK_STATUS_SPEED_AND_DUPLEX_10TFD
+#define LINK_100TXHD LINK_STATUS_SPEED_AND_DUPLEX_100TXHD
+#define LINK_100T4 LINK_STATUS_SPEED_AND_DUPLEX_100T4
+#define LINK_100TXFD LINK_STATUS_SPEED_AND_DUPLEX_100TXFD
+#define LINK_1000THD LINK_STATUS_SPEED_AND_DUPLEX_1000THD
+#define LINK_1000TFD LINK_STATUS_SPEED_AND_DUPLEX_1000TFD
+#define LINK_1000XFD LINK_STATUS_SPEED_AND_DUPLEX_1000XFD
+#define LINK_2500THD LINK_STATUS_SPEED_AND_DUPLEX_2500THD
+#define LINK_2500TFD LINK_STATUS_SPEED_AND_DUPLEX_2500TFD
+#define LINK_2500XFD LINK_STATUS_SPEED_AND_DUPLEX_2500XFD
+#define LINK_10GTFD LINK_STATUS_SPEED_AND_DUPLEX_10GTFD
+#define LINK_10GXFD LINK_STATUS_SPEED_AND_DUPLEX_10GXFD
+#define LINK_12GTFD LINK_STATUS_SPEED_AND_DUPLEX_12GTFD
+#define LINK_12GXFD LINK_STATUS_SPEED_AND_DUPLEX_12GXFD
+#define LINK_12_5GTFD LINK_STATUS_SPEED_AND_DUPLEX_12_5GTFD
+#define LINK_12_5GXFD LINK_STATUS_SPEED_AND_DUPLEX_12_5GXFD
+#define LINK_13GTFD LINK_STATUS_SPEED_AND_DUPLEX_13GTFD
+#define LINK_13GXFD LINK_STATUS_SPEED_AND_DUPLEX_13GXFD
+#define LINK_15GTFD LINK_STATUS_SPEED_AND_DUPLEX_15GTFD
+#define LINK_15GXFD LINK_STATUS_SPEED_AND_DUPLEX_15GXFD
+#define LINK_16GTFD LINK_STATUS_SPEED_AND_DUPLEX_16GTFD
+#define LINK_16GXFD LINK_STATUS_SPEED_AND_DUPLEX_16GXFD
+
+#define PHY_XGXS_FLAG 0x1
+#define PHY_SGMII_FLAG 0x2
+#define PHY_SERDES_FLAG 0x4
+
+/**********************************************************/
+/* INTERFACE */
+/**********************************************************/
+#define CL45_WR_OVER_CL22(_bp, _port, _phy_addr, _bank, _addr, _val) \
+ bnx2x_cl45_write(_bp, _port, 0, _phy_addr, \
+ DEFAULT_PHY_DEV_ADDR, \
+ (_bank + (_addr & 0xf)), \
+ _val)
+
+#define CL45_RD_OVER_CL22(_bp, _port, _phy_addr, _bank, _addr, _val) \
+ bnx2x_cl45_read(_bp, _port, 0, _phy_addr, \
+ DEFAULT_PHY_DEV_ADDR, \
+ (_bank + (_addr & 0xf)), \
+ _val)
+
+static void bnx2x_set_phy_mdio(struct link_params *params)
+{
+ struct bnx2x *bp = params->bp;
+ REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_ST +
+ params->port*0x18, 0);
+ REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + params->port*0x18,
+ DEFAULT_PHY_DEV_ADDR);
+}
+
+static u32 bnx2x_bits_en(struct bnx2x *bp, u32 reg, u32 bits)
+{
+ u32 val = REG_RD(bp, reg);
+
+ val |= bits;
+ REG_WR(bp, reg, val);
+ return val;
+}
+
+static u32 bnx2x_bits_dis(struct bnx2x *bp, u32 reg, u32 bits)
+{
+ u32 val = REG_RD(bp, reg);
+
+ val &= ~bits;
+ REG_WR(bp, reg, val);
+ return val;
+}
+
+static void bnx2x_emac_init(struct link_params *params,
+ struct link_vars *vars)
+{
+ /* reset and unreset the emac core */
+ struct bnx2x *bp = params->bp;
+ u8 port = params->port;
+ u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
+ u32 val;
+ u16 timeout;
+
+ REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
+ (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
+ udelay(5);
+ REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
+ (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
+
+ /* init emac - use read-modify-write */
+ /* self clear reset */
+ val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
+ EMAC_WR(EMAC_REG_EMAC_MODE, (val | EMAC_MODE_RESET));
+
+ timeout = 200;
+ do
+ {
+ val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
+ DP(NETIF_MSG_LINK, "EMAC reset reg is %u\n", val);
+ if (!timeout) {
+ DP(NETIF_MSG_LINK, "EMAC timeout!\n");
+ return;
+ }
+ timeout--;
+ }while (val & EMAC_MODE_RESET);
+
+ /* Set mac address */
+ val = ((params->mac_addr[0] << 8) |
+ params->mac_addr[1]);
+ EMAC_WR(EMAC_REG_EMAC_MAC_MATCH, val);
+
+ val = ((params->mac_addr[2] << 24) |
+ (params->mac_addr[3] << 16) |
+ (params->mac_addr[4] << 8) |
+ params->mac_addr[5]);
+ EMAC_WR(EMAC_REG_EMAC_MAC_MATCH + 4, val);
+}
+
+static u8 bnx2x_emac_enable(struct link_params *params,
+ struct link_vars *vars, u8 lb)
+{
+ struct bnx2x *bp = params->bp;
+ u8 port = params->port;
+ u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
+ u32 val;
+
+ DP(NETIF_MSG_LINK, "enabling EMAC\n");
+
+ /* enable emac and not bmac */
+ REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 1);
+
+ /* for paladium */
+ if (CHIP_REV_IS_EMUL(bp)) {
+ /* Use lane 1 (of lanes 0-3) */
+ REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1);
+ REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
+ port*4, 1);
+ }
+ /* for fpga */
+ else
+
+ if (CHIP_REV_IS_FPGA(bp)) {
+ /* Use lane 1 (of lanes 0-3) */
+ DP(NETIF_MSG_LINK, "bnx2x_emac_enable: Setting FPGA\n");
+
+ REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1);
+ REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4,
+ 0);
+ } else
+ /* ASIC */
+ if (vars->phy_flags & PHY_XGXS_FLAG) {
+ u32 ser_lane = ((params->lane_config &
+ PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
+ PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
+
+ DP(NETIF_MSG_LINK, "XGXS\n");
+ /* select the master lanes (out of 0-3) */
+ REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 +
+ port*4, ser_lane);
+ /* select XGXS */
+ REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
+ port*4, 1);
+
+ } else { /* SerDes */
+ DP(NETIF_MSG_LINK, "SerDes\n");
+ /* select SerDes */
+ REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
+ port*4, 0);
+ }
+
+ /* enable emac */
+ REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 1);
+
+ if (CHIP_REV_IS_SLOW(bp)) {
+ /* config GMII mode */
+ val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
+ EMAC_WR(EMAC_REG_EMAC_MODE,
+ (val | EMAC_MODE_PORT_GMII));
+ } else { /* ASIC */
+ /* pause enable/disable */
+ bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
+ EMAC_RX_MODE_FLOW_EN);
+ if (vars->flow_ctrl & FLOW_CTRL_RX)
+ bnx2x_bits_en(bp, emac_base +
+ EMAC_REG_EMAC_RX_MODE,
+ EMAC_RX_MODE_FLOW_EN);
+
+ bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
+ EMAC_TX_MODE_EXT_PAUSE_EN);
+ if (vars->flow_ctrl & FLOW_CTRL_TX)
+ bnx2x_bits_en(bp, emac_base +
+ EMAC_REG_EMAC_TX_MODE,
+ EMAC_TX_MODE_EXT_PAUSE_EN);
+ }
+
+ /* KEEP_VLAN_TAG, promiscuous */
+ val = REG_RD(bp, emac_base + EMAC_REG_EMAC_RX_MODE);
+ val |= EMAC_RX_MODE_KEEP_VLAN_TAG | EMAC_RX_MODE_PROMISCUOUS;
+ EMAC_WR(EMAC_REG_EMAC_RX_MODE, val);
+
+ /* Set Loopback */
+ val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
+ if (lb)
+ val |= 0x810;
+ else
+ val &= ~0x810;
+ EMAC_WR(EMAC_REG_EMAC_MODE, val);
+
+ /* enable emac for jumbo packets */
+ EMAC_WR(EMAC_REG_EMAC_RX_MTU_SIZE,
+ (EMAC_RX_MTU_SIZE_JUMBO_ENA |
+ (ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD)));
+
+ /* strip CRC */
+ REG_WR(bp, NIG_REG_NIG_INGRESS_EMAC0_NO_CRC + port*4, 0x1);
+
+ /* disable the NIG in/out to the bmac */
+ REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x0);
+ REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, 0x0);
+ REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x0);
+
+ /* enable the NIG in/out to the emac */
+ REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x1);
+ val = 0;
+ if (vars->flow_ctrl & FLOW_CTRL_TX)
+ val = 1;
+
+ REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, val);
+ REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x1);
+
+ if (CHIP_REV_IS_EMUL(bp)) {
+ /* take the BigMac out of reset */
+ REG_WR(bp,
+ GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
+ (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
+
+ /* enable access for bmac registers */
+ REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
+ }
+
+ vars->mac_type = MAC_TYPE_EMAC;
+ return 0;
+}
+
+
+
+static u8 bnx2x_bmac_enable(struct link_params *params, struct link_vars *vars,
+ u8 is_lb)
+{
+ struct bnx2x *bp = params->bp;
+ u8 port = params->port;
+ u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
+ NIG_REG_INGRESS_BMAC0_MEM;
+ u32 wb_data[2];
+ u32 val;
+
+ DP(NETIF_MSG_LINK, "Enabling BigMAC\n");
+ /* reset and unreset the BigMac */
+ REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
+ (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
+ msleep(1);
+
+ REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
+ (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
+
+ /* enable access for bmac registers */
+ REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
+
+ /* XGXS control */
+ wb_data[0] = 0x3c;
+ wb_data[1] = 0;
+ REG_WR_DMAE(bp, bmac_addr +
+ BIGMAC_REGISTER_BMAC_XGXS_CONTROL,
+ wb_data, 2);
+
+ /* tx MAC SA */
+ wb_data[0] = ((params->mac_addr[2] << 24) |
+ (params->mac_addr[3] << 16) |
+ (params->mac_addr[4] << 8) |
+ params->mac_addr[5]);
+ wb_data[1] = ((params->mac_addr[0] << 8) |
+ params->mac_addr[1]);
+ REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_SOURCE_ADDR,
+ wb_data, 2);
+
+ /* tx control */
+ val = 0xc0;
+ if (vars->flow_ctrl & FLOW_CTRL_TX)
+ val |= 0x800000;
+ wb_data[0] = val;
+ wb_data[1] = 0;
+ REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_CONTROL,
+ wb_data, 2);
+
+ /* mac control */
+ val = 0x3;
+ if (is_lb) {
+ val |= 0x4;
+ DP(NETIF_MSG_LINK, "enable bmac loopback\n");
+ }
+ wb_data[0] = val;
+ wb_data[1] = 0;
+ REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
+ wb_data, 2);
+
+
+ /* set rx mtu */
+ wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
+ wb_data[1] = 0;
+ REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_MAX_SIZE,
+ wb_data, 2);
+
+ /* rx control set to don't strip crc */
+ val = 0x14;
+ if (vars->flow_ctrl & FLOW_CTRL_RX)
+ val |= 0x20;
+ wb_data[0] = val;
+ wb_data[1] = 0;
+ REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_CONTROL,
+ wb_data, 2);
+
+ /* set tx mtu */
+ wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
+ wb_data[1] = 0;
+ REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_MAX_SIZE,
+ wb_data, 2);
+
+ /* set cnt max size */
+ wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
+ wb_data[1] = 0;
+ REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_CNT_MAX_SIZE,
+ wb_data, 2);
+
+ /* configure safc */
+ wb_data[0] = 0x1000200;
+ wb_data[1] = 0;
+ REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_LLFC_MSG_FLDS,
+ wb_data, 2);
+ /* fix for emulation */
+ if (CHIP_REV_IS_EMUL(bp)) {
+ wb_data[0] = 0xf000;
+ wb_data[1] = 0;
+ REG_WR_DMAE(bp,
+ bmac_addr + BIGMAC_REGISTER_TX_PAUSE_THRESHOLD,
+ wb_data, 2);
+ }
+
+ REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0x1);
+ REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 0x0);
+ REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 0x0);
+ val = 0;
+ if (vars->flow_ctrl & FLOW_CTRL_TX)
+ val = 1;
+ REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, val);
+ REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x0);
+ REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x0);
+ REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, 0x0);
+ REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x1);
+ REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x1);
+
+ vars->mac_type = MAC_TYPE_BMAC;
+ return 0;
+}
+
+static void bnx2x_phy_deassert(struct link_params *params, u8 phy_flags)
+{
+ struct bnx2x *bp = params->bp;
+ u32 val;
+
+ if (phy_flags & PHY_XGXS_FLAG) {
+ DP(NETIF_MSG_LINK, "bnx2x_phy_deassert:XGXS\n");
+ val = XGXS_RESET_BITS;
+
+ } else { /* SerDes */
+ DP(NETIF_MSG_LINK, "bnx2x_phy_deassert:SerDes\n");
+ val = SERDES_RESET_BITS;
+ }
+
+ val = val << (params->port*16);
+
+ /* reset and unreset the SerDes/XGXS */
+ REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
+ val);
+ udelay(500);
+ REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET,
+ val);
+ bnx2x_set_phy_mdio(params);
+}
+
+void bnx2x_link_status_update(struct link_params *params,
+ struct link_vars *vars)
+{
+ struct bnx2x *bp = params->bp;
+ u8 link_10g;
+ u8 port = params->port;
+
+ if (params->switch_cfg == SWITCH_CFG_1G)
+ vars->phy_flags = PHY_SERDES_FLAG;
+ else
+ vars->phy_flags = PHY_XGXS_FLAG;
+ vars->link_status = REG_RD(bp, params->shmem_base +
+ offsetof(struct shmem_region,
+ port_mb[port].link_status));
+
+ vars->link_up = (vars->link_status & LINK_STATUS_LINK_UP);
+
+ if (vars->link_up) {
+ DP(NETIF_MSG_LINK, "phy link up\n");
+
+ vars->phy_link_up = 1;
+ vars->duplex = DUPLEX_FULL;
+ switch (vars->link_status &
+ LINK_STATUS_SPEED_AND_DUPLEX_MASK) {
+ case LINK_10THD:
+ vars->duplex = DUPLEX_HALF;
+ /* fall thru */
+ case LINK_10TFD:
+ vars->line_speed = SPEED_10;
+ break;
+
+ case LINK_100TXHD:
+ vars->duplex = DUPLEX_HALF;
+ /* fall thru */
+ case LINK_100T4:
+ case LINK_100TXFD:
+ vars->line_speed = SPEED_100;
+ break;
+
+ case LINK_1000THD:
+ vars->duplex = DUPLEX_HALF;
+ /* fall thru */
+ case LINK_1000TFD:
+ vars->line_speed = SPEED_1000;
+ break;
+
+ case LINK_2500THD:
+ vars->duplex = DUPLEX_HALF;
+ /* fall thru */
+ case LINK_2500TFD:
+ vars->line_speed = SPEED_2500;
+ break;
+
+ case LINK_10GTFD:
+ vars->line_speed = SPEED_10000;
+ break;
+
+ case LINK_12GTFD:
+ vars->line_speed = SPEED_12000;
+ break;
+
+ case LINK_12_5GTFD:
+ vars->line_speed = SPEED_12500;
+ break;
+
+ case LINK_13GTFD:
+ vars->line_speed = SPEED_13000;
+ break;
+
+ case LINK_15GTFD:
+ vars->line_speed = SPEED_15000;
+ break;
+
+ case LINK_16GTFD:
+ vars->line_speed = SPEED_16000;
+ break;
+
+ default:
+ break;
+ }
+
+ if (vars->link_status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED)
+ vars->flow_ctrl |= FLOW_CTRL_TX;
+ else
+ vars->flow_ctrl &= ~FLOW_CTRL_TX;
+
+ if (vars->link_status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED)
+ vars->flow_ctrl |= FLOW_CTRL_RX;
+ else
+ vars->flow_ctrl &= ~FLOW_CTRL_RX;
+
+ if (vars->phy_flags & PHY_XGXS_FLAG) {
+ if (params->req_line_speed &&
+ ((params->req_line_speed == SPEED_10) ||
+ (params->req_line_speed == SPEED_100))) {
+ vars->phy_flags |= PHY_SGMII_FLAG;
+ } else {
+ vars->phy_flags &= ~PHY_SGMII_FLAG;
+ }
+ }
+
+ /* anything 10 and over uses the bmac */
+ link_10g = ((vars->line_speed == SPEED_10000) ||
+ (vars->line_speed == SPEED_12000) ||
+ (vars->line_speed == SPEED_12500) ||
+ (vars->line_speed == SPEED_13000) ||
+ (vars->line_speed == SPEED_15000) ||
+ (vars->line_speed == SPEED_16000));
+ if (link_10g)
+ vars->mac_type = MAC_TYPE_BMAC;
+ else
+ vars->mac_type = MAC_TYPE_EMAC;
+
+ } else { /* link down */
+ DP(NETIF_MSG_LINK, "phy link down\n");
+
+ vars->phy_link_up = 0;
+
+ vars->line_speed = 0;
+ vars->duplex = DUPLEX_FULL;
+ vars->flow_ctrl = FLOW_CTRL_NONE;
+
+ /* indicate no mac active */
+ vars->mac_type = MAC_TYPE_NONE;
+ }
+
+ DP(NETIF_MSG_LINK, "link_status 0x%x phy_link_up %x\n",
+ vars->link_status, vars->phy_link_up);
+ DP(NETIF_MSG_LINK, "line_speed %x duplex %x flow_ctrl 0x%x\n",
+ vars->line_speed, vars->duplex, vars->flow_ctrl);
+}
+
+static void bnx2x_update_mng(struct link_params *params, u32 link_status)
+{
+ struct bnx2x *bp = params->bp;
+ REG_WR(bp, params->shmem_base +
+ offsetof(struct shmem_region,
+ port_mb[params->port].link_status),
+ link_status);
+}
+
+static void bnx2x_bmac_rx_disable(struct bnx2x *bp, u8 port)
+{
+ u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
+ NIG_REG_INGRESS_BMAC0_MEM;
+ u32 wb_data[2];
+ u32 nig_bmac_enable = REG_RD(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4);
+
+ /* Only if the bmac is out of reset */
+ if (REG_RD(bp, MISC_REG_RESET_REG_2) &
+ (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port) &&
+ nig_bmac_enable) {
+
+ /* Clear Rx Enable bit in BMAC_CONTROL register */
+ REG_RD_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
+ wb_data, 2);
+ wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
+ REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
+ wb_data, 2);
+
+ msleep(1);
+ }
+}
+
+static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl,
+ u32 line_speed)
+{
+ struct bnx2x *bp = params->bp;
+ u8 port = params->port;
+ u32 init_crd, crd;
+ u32 count = 1000;
+ u32 pause = 0;
+
+ /* disable port */
+ REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x1);
+
+ /* wait for init credit */
+ init_crd = REG_RD(bp, PBF_REG_P0_INIT_CRD + port*4);
+ crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
+ DP(NETIF_MSG_LINK, "init_crd 0x%x crd 0x%x\n", init_crd, crd);
+
+ while ((init_crd != crd) && count) {
+ msleep(5);
+
+ crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
+ count--;
+ }
+ crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
+ if (init_crd != crd) {
+ DP(NETIF_MSG_LINK, "BUG! init_crd 0x%x != crd 0x%x\n",
+ init_crd, crd);
+ return -EINVAL;
+ }
+
+ if (flow_ctrl & FLOW_CTRL_RX)
+ pause = 1;
+ REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, pause);
+ if (pause) {
+ /* update threshold */
+ REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, 0);
+ /* update init credit */
+ init_crd = 778; /* (800-18-4) */
+
+ } else {
+ u32 thresh = (ETH_MAX_JUMBO_PACKET_SIZE +
+ ETH_OVREHEAD)/16;
+
+ /* update threshold */
+ REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, thresh);
+ /* update init credit */
+ switch (line_speed) {
+ case SPEED_10:
+ case SPEED_100:
+ case SPEED_1000:
+ init_crd = thresh + 55 - 22;
+ break;
+
+ case SPEED_2500:
+ init_crd = thresh + 138 - 22;
+ break;
+
+ case SPEED_10000:
+ init_crd = thresh + 553 - 22;
+ break;
+
+ case SPEED_12000:
+ init_crd = thresh + 664 - 22;
+ break;
+
+ case SPEED_13000:
+ init_crd = thresh + 742 - 22;
+ break;
+
+ case SPEED_16000:
+ init_crd = thresh + 778 - 22;
+ break;
+ default:
+ DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
+ line_speed);
+ return -EINVAL;
+ break;
+ }
+ }
+ REG_WR(bp, PBF_REG_P0_INIT_CRD + port*4, init_crd);
+ DP(NETIF_MSG_LINK, "PBF updated to speed %d credit %d\n",
+ line_speed, init_crd);
+
+ /* probe the credit changes */
+ REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x1);
+ msleep(5);
+ REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x0);
+
+ /* enable port */
+ REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x0);
+ return 0;
+}
+
+static u32 bnx2x_get_emac_base(u32 ext_phy_type, u8 port)
+{
+ u32 emac_base;
+ switch (ext_phy_type) {
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
+ emac_base = GRCBASE_EMAC0;
+ break;
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
+ emac_base = (port) ? GRCBASE_EMAC0: GRCBASE_EMAC1;
+ break;
+ default:
+ emac_base = (port) ? GRCBASE_EMAC1: GRCBASE_EMAC0;
+ break;
+ }
+ return emac_base;
+
+}
+
+u8 bnx2x_cl45_write(struct bnx2x *bp, u8 port, u32 ext_phy_type,
+ u8 phy_addr, u8 devad, u16 reg, u16 val)
+{
+ u32 tmp, saved_mode;
+ u8 i, rc = 0;
+ u32 mdio_ctrl = bnx2x_get_emac_base(ext_phy_type, port);
+
+ /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
+ * (a value of 49==0x31) and make sure that the AUTO poll is off
+ */
+ saved_mode = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
+ tmp = saved_mode & ~(EMAC_MDIO_MODE_AUTO_POLL |
+ EMAC_MDIO_MODE_CLOCK_CNT);
+ tmp |= (EMAC_MDIO_MODE_CLAUSE_45 |
+ (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
+ REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, tmp);
+ REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
+ udelay(40);
+
+ /* address */
+
+ tmp = ((phy_addr << 21) | (devad << 16) | reg |
+ EMAC_MDIO_COMM_COMMAND_ADDRESS |
+ EMAC_MDIO_COMM_START_BUSY);
+ REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
+
+ for (i = 0; i < 50; i++) {
+ udelay(10);
+
+ tmp = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
+ if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
+ udelay(5);
+ break;
+ }
+ }
+ if (tmp & EMAC_MDIO_COMM_START_BUSY) {
+ DP(NETIF_MSG_LINK, "write phy register failed\n");
+ rc = -EFAULT;
+ } else {
+ /* data */
+ tmp = ((phy_addr << 21) | (devad << 16) | val |
+ EMAC_MDIO_COMM_COMMAND_WRITE_45 |
+ EMAC_MDIO_COMM_START_BUSY);
+ REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
+
+ for (i = 0; i < 50; i++) {
+ udelay(10);
+
+ tmp = REG_RD(bp, mdio_ctrl +
+ EMAC_REG_EMAC_MDIO_COMM);
+ if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
+ udelay(5);
+ break;
+ }
+ }
+ if (tmp & EMAC_MDIO_COMM_START_BUSY) {
+ DP(NETIF_MSG_LINK, "write phy register failed\n");
+ rc = -EFAULT;
+ }
+ }
+
+ /* Restore the saved mode */
+ REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
+
+ return rc;
+}
+
+u8 bnx2x_cl45_read(struct bnx2x *bp, u8 port, u32 ext_phy_type,
+ u8 phy_addr, u8 devad, u16 reg, u16 *ret_val)
+{
+ u32 val, saved_mode;
+ u16 i;
+ u8 rc = 0;
+
+ u32 mdio_ctrl = bnx2x_get_emac_base(ext_phy_type, port);
+ /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
+ * (a value of 49==0x31) and make sure that the AUTO poll is off
+ */
+ saved_mode = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
+ val = saved_mode & ((EMAC_MDIO_MODE_AUTO_POLL |
+ EMAC_MDIO_MODE_CLOCK_CNT));
+ val |= (EMAC_MDIO_MODE_CLAUSE_45 |
+ (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
+ REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, val);
+ REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
+ udelay(40);
+
+ /* address */
+ val = ((phy_addr << 21) | (devad << 16) | reg |
+ EMAC_MDIO_COMM_COMMAND_ADDRESS |
+ EMAC_MDIO_COMM_START_BUSY);
+ REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
+
+ for (i = 0; i < 50; i++) {
+ udelay(10);
+
+ val = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
+ if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
+ udelay(5);
+ break;
+ }
+ }
+ if (val & EMAC_MDIO_COMM_START_BUSY) {
+ DP(NETIF_MSG_LINK, "read phy register failed\n");
+
+ *ret_val = 0;
+ rc = -EFAULT;
+
+ } else {
+ /* data */
+ val = ((phy_addr << 21) | (devad << 16) |
+ EMAC_MDIO_COMM_COMMAND_READ_45 |
+ EMAC_MDIO_COMM_START_BUSY);
+ REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
+
+ for (i = 0; i < 50; i++) {
+ udelay(10);
+
+ val = REG_RD(bp, mdio_ctrl +
+ EMAC_REG_EMAC_MDIO_COMM);
+ if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
+ *ret_val = (u16)(val & EMAC_MDIO_COMM_DATA);
+ break;
+ }
+ }
+ if (val & EMAC_MDIO_COMM_START_BUSY) {
+ DP(NETIF_MSG_LINK, "read phy register failed\n");
+
+ *ret_val = 0;
+ rc = -EFAULT;
+ }
+ }
+
+ /* Restore the saved mode */
+ REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
+
+ return rc;
+}
+
+static void bnx2x_set_aer_mmd(struct link_params *params,
+ struct link_vars *vars)
+{
+ struct bnx2x *bp = params->bp;
+ u32 ser_lane;
+ u16 offset;
+
+ ser_lane = ((params->lane_config &
+ PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
+ PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
+
+ offset = (vars->phy_flags & PHY_XGXS_FLAG) ?
+ (params->phy_addr + ser_lane) : 0;
+
+ CL45_WR_OVER_CL22(bp, params->port,
+ params->phy_addr,
+ MDIO_REG_BANK_AER_BLOCK,
+ MDIO_AER_BLOCK_AER_REG, 0x3800 + offset);
+}
+
+static void bnx2x_set_master_ln(struct link_params *params)
+{
+ struct bnx2x *bp = params->bp;
+ u16 new_master_ln, ser_lane;
+ ser_lane = ((params->lane_config &
+ PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
+ PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
+
+ /* set the master_ln for AN */
+ CL45_RD_OVER_CL22(bp, params->port,
+ params->phy_addr,
+ MDIO_REG_BANK_XGXS_BLOCK2,
+ MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
+ &new_master_ln);
+
+ CL45_WR_OVER_CL22(bp, params->port,
+ params->phy_addr,
+ MDIO_REG_BANK_XGXS_BLOCK2 ,
+ MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
+ (new_master_ln | ser_lane));
+}
+
+static u8 bnx2x_reset_unicore(struct link_params *params)
+{
+ struct bnx2x *bp = params->bp;
+ u16 mii_control;
+ u16 i;
+
+ CL45_RD_OVER_CL22(bp, params->port,
+ params->phy_addr,
+ MDIO_REG_BANK_COMBO_IEEE0,
+ MDIO_COMBO_IEEE0_MII_CONTROL, &mii_control);
+
+ /* reset the unicore */
+ CL45_WR_OVER_CL22(bp, params->port,
+ params->phy_addr,
+ MDIO_REG_BANK_COMBO_IEEE0,
+ MDIO_COMBO_IEEE0_MII_CONTROL,
+ (mii_control |
+ MDIO_COMBO_IEEO_MII_CONTROL_RESET));
+
+ /* wait for the reset to self clear */
+ for (i = 0; i < MDIO_ACCESS_TIMEOUT; i++) {
+ udelay(5);
+
+ /* the reset erased the previous bank value */
+ CL45_RD_OVER_CL22(bp, params->port,
+ params->phy_addr,
+ MDIO_REG_BANK_COMBO_IEEE0,
+ MDIO_COMBO_IEEE0_MII_CONTROL,
+ &mii_control);
+
+ if (!(mii_control & MDIO_COMBO_IEEO_MII_CONTROL_RESET)) {
+ udelay(5);
+ return 0;
+ }
+ }
+
+ DP(NETIF_MSG_LINK, "BUG! XGXS is still in reset!\n");
+ return -EINVAL;
+
+}
+
+static void bnx2x_set_swap_lanes(struct link_params *params)
+{
+ struct bnx2x *bp = params->bp;
+ /* Each two bits represents a lane number:
+ No swap is 0123 => 0x1b no need to enable the swap */
+ u16 ser_lane, rx_lane_swap, tx_lane_swap;
+
+ ser_lane = ((params->lane_config &
+ PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
+ PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
+ rx_lane_swap = ((params->lane_config &
+ PORT_HW_CFG_LANE_SWAP_CFG_RX_MASK) >>
+ PORT_HW_CFG_LANE_SWAP_CFG_RX_SHIFT);
+ tx_lane_swap = ((params->lane_config &
+ PORT_HW_CFG_LANE_SWAP_CFG_TX_MASK) >>
+ PORT_HW_CFG_LANE_SWAP_CFG_TX_SHIFT);
+
+ if (rx_lane_swap != 0x1b) {
+ CL45_WR_OVER_CL22(bp, params->port,
+ params->phy_addr,
+ MDIO_REG_BANK_XGXS_BLOCK2,
+ MDIO_XGXS_BLOCK2_RX_LN_SWAP,
+ (rx_lane_swap |
+ MDIO_XGXS_BLOCK2_RX_LN_SWAP_ENABLE |
+ MDIO_XGXS_BLOCK2_RX_LN_SWAP_FORCE_ENABLE));
+ } else {
+ CL45_WR_OVER_CL22(bp, params->port,
+ params->phy_addr,
+ MDIO_REG_BANK_XGXS_BLOCK2,
+ MDIO_XGXS_BLOCK2_RX_LN_SWAP, 0);
+ }
+
+ if (tx_lane_swap != 0x1b) {
+ CL45_WR_OVER_CL22(bp, params->port,
+ params->phy_addr,
+ MDIO_REG_BANK_XGXS_BLOCK2,
+ MDIO_XGXS_BLOCK2_TX_LN_SWAP,
+ (tx_lane_swap |
+ MDIO_XGXS_BLOCK2_TX_LN_SWAP_ENABLE));
+ } else {
+ CL45_WR_OVER_CL22(bp, params->port,
+ params->phy_addr,
+ MDIO_REG_BANK_XGXS_BLOCK2,
+ MDIO_XGXS_BLOCK2_TX_LN_SWAP, 0);
+ }
+}
+
+static void bnx2x_set_parallel_detection(struct link_params *params,
+ u8 phy_flags)
+{
+ struct bnx2x *bp = params->bp;
+ u16 control2;
+
+ CL45_RD_OVER_CL22(bp, params->port,
+ params->phy_addr,
+ MDIO_REG_BANK_SERDES_DIGITAL,
+ MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
+ &control2);
+
+
+ control2 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
+
+
+ CL45_WR_OVER_CL22(bp, params->port,
+ params->phy_addr,
+ MDIO_REG_BANK_SERDES_DIGITAL,
+ MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
+ control2);
+
+ if (phy_flags & PHY_XGXS_FLAG) {
+ DP(NETIF_MSG_LINK, "XGXS\n");
+
+ CL45_WR_OVER_CL22(bp, params->port,
+ params->phy_addr,
+ MDIO_REG_BANK_10G_PARALLEL_DETECT,
+ MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK,
+ MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT);
+
+ CL45_RD_OVER_CL22(bp, params->port,
+ params->phy_addr,
+ MDIO_REG_BANK_10G_PARALLEL_DETECT,
+ MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
+ &control2);
+
+
+ control2 |=
+ MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN;
+
+ CL45_WR_OVER_CL22(bp, params->port,
+ params->phy_addr,
+ MDIO_REG_BANK_10G_PARALLEL_DETECT,
+ MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
+ control2);
+
+ /* Disable parallel detection of HiG */
+ CL45_WR_OVER_CL22(bp, params->port,
+ params->phy_addr,
+ MDIO_REG_BANK_XGXS_BLOCK2,
+ MDIO_XGXS_BLOCK2_UNICORE_MODE_10G,
+ MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_CX4_XGXS |
+ MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_HIGIG_XGXS);
+ }
+}
+
+static void bnx2x_set_autoneg(struct link_params *params,
+ struct link_vars *vars)
+{
+ struct bnx2x *bp = params->bp;
+ u16 reg_val;
+
+ /* CL37 Autoneg */
+
+ CL45_RD_OVER_CL22(bp, params->port,
+ params->phy_addr,
+ MDIO_REG_BANK_COMBO_IEEE0,
+ MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
+
+ /* CL37 Autoneg Enabled */
+ if (params->req_line_speed == SPEED_AUTO_NEG)
+