#define DRV_MODULE_NAME "bnx2"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "1.5.10"
-#define DRV_MODULE_RELDATE "May 1, 2007"
+#define DRV_MODULE_VERSION "1.5.11"
+#define DRV_MODULE_RELDATE "June 4, 2007"
#define RUN_AT(x) (jiffies + (x))
{
u32 fw_link_status = 0;
+ if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
+ return;
+
if (bp->link_up) {
u32 bmsr;
return 0;
}
+ if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
+ return 0;
+
link_up = bp->link_up;
bnx2_enable_bmsr1(bp);
return adv;
}
+static int bnx2_fw_sync(struct bnx2 *, u32, int);
+
+static int
+bnx2_setup_remote_phy(struct bnx2 *bp, u8 port)
+{
+ u32 speed_arg = 0, pause_adv;
+
+ pause_adv = bnx2_phy_get_pause_adv(bp);
+
+ if (bp->autoneg & AUTONEG_SPEED) {
+ speed_arg |= BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG;
+ if (bp->advertising & ADVERTISED_10baseT_Half)
+ speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10HALF;
+ if (bp->advertising & ADVERTISED_10baseT_Full)
+ speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10FULL;
+ if (bp->advertising & ADVERTISED_100baseT_Half)
+ speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100HALF;
+ if (bp->advertising & ADVERTISED_100baseT_Full)
+ speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100FULL;
+ if (bp->advertising & ADVERTISED_1000baseT_Full)
+ speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_1GFULL;
+ if (bp->advertising & ADVERTISED_2500baseX_Full)
+ speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_2G5FULL;
+ } else {
+ if (bp->req_line_speed == SPEED_2500)
+ speed_arg = BNX2_NETLINK_SET_LINK_SPEED_2G5FULL;
+ else if (bp->req_line_speed == SPEED_1000)
+ speed_arg = BNX2_NETLINK_SET_LINK_SPEED_1GFULL;
+ else if (bp->req_line_speed == SPEED_100) {
+ if (bp->req_duplex == DUPLEX_FULL)
+ speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100FULL;
+ else
+ speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100HALF;
+ } else if (bp->req_line_speed == SPEED_10) {
+ if (bp->req_duplex == DUPLEX_FULL)
+ speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10FULL;
+ else
+ speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10HALF;
+ }
+ }
+
+ if (pause_adv & (ADVERTISE_1000XPAUSE | ADVERTISE_PAUSE_CAP))
+ speed_arg |= BNX2_NETLINK_SET_LINK_FC_SYM_PAUSE;
+ if (pause_adv & (ADVERTISE_1000XPSE_ASYM | ADVERTISE_1000XPSE_ASYM))
+ speed_arg |= BNX2_NETLINK_SET_LINK_FC_ASYM_PAUSE;
+
+ if (port == PORT_TP)
+ speed_arg |= BNX2_NETLINK_SET_LINK_PHY_APP_REMOTE |
+ BNX2_NETLINK_SET_LINK_ETH_AT_WIRESPEED;
+
+ REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_MB_ARG0, speed_arg);
+
+ spin_unlock_bh(&bp->phy_lock);
+ bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_CMD_SET_LINK, 0);
+ spin_lock_bh(&bp->phy_lock);
+
+ return 0;
+}
+
static int
-bnx2_setup_serdes_phy(struct bnx2 *bp)
+bnx2_setup_serdes_phy(struct bnx2 *bp, u8 port)
{
u32 adv, bmcr;
u32 new_adv = 0;
+ if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
+ return (bnx2_setup_remote_phy(bp, port));
+
if (!(bp->autoneg & AUTONEG_SPEED)) {
u32 new_bmcr;
int force_link_down = 0;
}
#define ETHTOOL_ALL_FIBRE_SPEED \
- (ADVERTISED_1000baseT_Full)
+ (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) ? \
+ (ADVERTISED_2500baseX_Full | ADVERTISED_1000baseT_Full) :\
+ (ADVERTISED_1000baseT_Full)
#define ETHTOOL_ALL_COPPER_SPEED \
(ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \
#define PHY_ALL_1000_SPEED (ADVERTISE_1000HALF | ADVERTISE_1000FULL)
+static void
+bnx2_set_default_remote_link(struct bnx2 *bp)
+{
+ u32 link;
+
+ if (bp->phy_port == PORT_TP)
+ link = REG_RD_IND(bp, bp->shmem_base + BNX2_RPHY_COPPER_LINK);
+ else
+ link = REG_RD_IND(bp, bp->shmem_base + BNX2_RPHY_SERDES_LINK);
+
+ if (link & BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG) {
+ bp->req_line_speed = 0;
+ bp->autoneg |= AUTONEG_SPEED;
+ bp->advertising = ADVERTISED_Autoneg;
+ if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF)
+ bp->advertising |= ADVERTISED_10baseT_Half;
+ if (link & BNX2_NETLINK_SET_LINK_SPEED_10FULL)
+ bp->advertising |= ADVERTISED_10baseT_Full;
+ if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF)
+ bp->advertising |= ADVERTISED_100baseT_Half;
+ if (link & BNX2_NETLINK_SET_LINK_SPEED_100FULL)
+ bp->advertising |= ADVERTISED_100baseT_Full;
+ if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL)
+ bp->advertising |= ADVERTISED_1000baseT_Full;
+ if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL)
+ bp->advertising |= ADVERTISED_2500baseX_Full;
+ } else {
+ bp->autoneg = 0;
+ bp->advertising = 0;
+ bp->req_duplex = DUPLEX_FULL;
+ if (link & BNX2_NETLINK_SET_LINK_SPEED_10) {
+ bp->req_line_speed = SPEED_10;
+ if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF)
+ bp->req_duplex = DUPLEX_HALF;
+ }
+ if (link & BNX2_NETLINK_SET_LINK_SPEED_100) {
+ bp->req_line_speed = SPEED_100;
+ if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF)
+ bp->req_duplex = DUPLEX_HALF;
+ }
+ if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL)
+ bp->req_line_speed = SPEED_1000;
+ if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL)
+ bp->req_line_speed = SPEED_2500;
+ }
+}
+
+static void
+bnx2_set_default_link(struct bnx2 *bp)
+{
+ if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
+ return bnx2_set_default_remote_link(bp);
+
+ bp->autoneg = AUTONEG_SPEED | AUTONEG_FLOW_CTRL;
+ bp->req_line_speed = 0;
+ if (bp->phy_flags & PHY_SERDES_FLAG) {
+ u32 reg;
+
+ bp->advertising = ETHTOOL_ALL_FIBRE_SPEED | ADVERTISED_Autoneg;
+
+ reg = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_CONFIG);
+ reg &= BNX2_PORT_HW_CFG_CFG_DFLT_LINK_MASK;
+ if (reg == BNX2_PORT_HW_CFG_CFG_DFLT_LINK_1G) {
+ bp->autoneg = 0;
+ bp->req_line_speed = bp->line_speed = SPEED_1000;
+ bp->req_duplex = DUPLEX_FULL;
+ }
+ } else
+ bp->advertising = ETHTOOL_ALL_COPPER_SPEED | ADVERTISED_Autoneg;
+}
+
+static void
+bnx2_remote_phy_event(struct bnx2 *bp)
+{
+ u32 msg;
+ u8 link_up = bp->link_up;
+ u8 old_port;
+
+ msg = REG_RD_IND(bp, bp->shmem_base + BNX2_LINK_STATUS);
+
+ if ((msg & BNX2_LINK_STATUS_LINK_UP) == BNX2_LINK_STATUS_LINK_DOWN)
+ bp->link_up = 0;
+ else {
+ u32 speed;
+
+ bp->link_up = 1;
+ speed = msg & BNX2_LINK_STATUS_SPEED_MASK;
+ bp->duplex = DUPLEX_FULL;
+ switch (speed) {
+ case BNX2_LINK_STATUS_10HALF:
+ bp->duplex = DUPLEX_HALF;
+ case BNX2_LINK_STATUS_10FULL:
+ bp->line_speed = SPEED_10;
+ break;
+ case BNX2_LINK_STATUS_100HALF:
+ bp->duplex = DUPLEX_HALF;
+ case BNX2_LINK_STATUS_100BASE_T4:
+ case BNX2_LINK_STATUS_100FULL:
+ bp->line_speed = SPEED_100;
+ break;
+ case BNX2_LINK_STATUS_1000HALF:
+ bp->duplex = DUPLEX_HALF;
+ case BNX2_LINK_STATUS_1000FULL:
+ bp->line_speed = SPEED_1000;
+ break;
+ case BNX2_LINK_STATUS_2500HALF:
+ bp->duplex = DUPLEX_HALF;
+ case BNX2_LINK_STATUS_2500FULL:
+ bp->line_speed = SPEED_2500;
+ break;
+ default:
+ bp->line_speed = 0;
+ break;
+ }
+
+ spin_lock(&bp->phy_lock);
+ bp->flow_ctrl = 0;
+ if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) !=
+ (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) {
+ if (bp->duplex == DUPLEX_FULL)
+ bp->flow_ctrl = bp->req_flow_ctrl;
+ } else {
+ if (msg & BNX2_LINK_STATUS_TX_FC_ENABLED)
+ bp->flow_ctrl |= FLOW_CTRL_TX;
+ if (msg & BNX2_LINK_STATUS_RX_FC_ENABLED)
+ bp->flow_ctrl |= FLOW_CTRL_RX;
+ }
+
+ old_port = bp->phy_port;
+ if (msg & BNX2_LINK_STATUS_SERDES_LINK)
+ bp->phy_port = PORT_FIBRE;
+ else
+ bp->phy_port = PORT_TP;
+
+ if (old_port != bp->phy_port)
+ bnx2_set_default_link(bp);
+
+ spin_unlock(&bp->phy_lock);
+ }
+ if (bp->link_up != link_up)
+ bnx2_report_link(bp);
+
+ bnx2_set_mac_link(bp);
+}
+
+static int
+bnx2_set_remote_link(struct bnx2 *bp)
+{
+ u32 evt_code;
+
+ evt_code = REG_RD_IND(bp, bp->shmem_base + BNX2_FW_EVT_CODE_MB);
+ switch (evt_code) {
+ case BNX2_FW_EVT_CODE_LINK_EVENT:
+ bnx2_remote_phy_event(bp);
+ break;
+ case BNX2_FW_EVT_CODE_SW_TIMER_EXPIRATION_EVENT:
+ default:
+ break;
+ }
+ return 0;
+}
+
static int
bnx2_setup_copper_phy(struct bnx2 *bp)
{
}
static int
-bnx2_setup_phy(struct bnx2 *bp)
+bnx2_setup_phy(struct bnx2 *bp, u8 port)
{
if (bp->loopback == MAC_LOOPBACK)
return 0;
if (bp->phy_flags & PHY_SERDES_FLAG) {
- return (bnx2_setup_serdes_phy(bp));
+ return (bnx2_setup_serdes_phy(bp, port));
}
else {
return (bnx2_setup_copper_phy(bp));
REG_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
+ if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
+ goto setup_phy;
+
bnx2_read_phy(bp, MII_PHYSID1, &val);
bp->phy_id = val << 16;
bnx2_read_phy(bp, MII_PHYSID2, &val);
rc = bnx2_init_copper_phy(bp);
}
- bnx2_setup_phy(bp);
+setup_phy:
+ if (!rc)
+ rc = bnx2_setup_phy(bp, bp->phy_port);
return rc;
}
val = BNX2_CTX_COMMAND_ENABLED | BNX2_CTX_COMMAND_MEM_INIT | (1 << 12);
val |= (BCM_PAGE_BITS - 8) << 16;
REG_WR(bp, BNX2_CTX_COMMAND, val);
+ for (i = 0; i < 10; i++) {
+ val = REG_RD(bp, BNX2_CTX_COMMAND);
+ if (!(val & BNX2_CTX_COMMAND_MEM_INIT))
+ break;
+ udelay(2);
+ }
+ if (val & BNX2_CTX_COMMAND_MEM_INIT)
+ return -EBUSY;
+
for (i = 0; i < bp->ctx_pages; i++) {
int j;
vcid = 96;
while (vcid) {
u32 vcid_addr, pcid_addr, offset;
+ int i;
vcid--;
pcid_addr = vcid_addr;
}
- REG_WR(bp, BNX2_CTX_VIRT_ADDR, 0x00);
- REG_WR(bp, BNX2_CTX_PAGE_TBL, pcid_addr);
+ for (i = 0; i < (CTX_SIZE / PHY_CTX_SIZE); i++) {
+ vcid_addr += (i << PHY_CTX_SHIFT);
+ pcid_addr += (i << PHY_CTX_SHIFT);
- /* Zero out the context. */
- for (offset = 0; offset < PHY_CTX_SIZE; offset += 4) {
- CTX_WR(bp, 0x00, offset, 0);
- }
+ REG_WR(bp, BNX2_CTX_VIRT_ADDR, 0x00);
+ REG_WR(bp, BNX2_CTX_PAGE_TBL, pcid_addr);
+
+ /* Zero out the context. */
+ for (offset = 0; offset < PHY_CTX_SIZE; offset += 4)
+ CTX_WR(bp, 0x00, offset, 0);
- REG_WR(bp, BNX2_CTX_VIRT_ADDR, vcid_addr);
- REG_WR(bp, BNX2_CTX_PAGE_TBL, pcid_addr);
+ REG_WR(bp, BNX2_CTX_VIRT_ADDR, vcid_addr);
+ REG_WR(bp, BNX2_CTX_PAGE_TBL, pcid_addr);
+ }
}
}
bnx2_set_link(bp);
spin_unlock(&bp->phy_lock);
}
+ if (bnx2_phy_event_is_set(bp, STATUS_ATTN_BITS_TIMER_ABORT))
+ bnx2_set_remote_link(bp);
+
}
static void
return IRQ_HANDLED;
}
-#define STATUS_ATTN_EVENTS STATUS_ATTN_BITS_LINK_STATE
+#define STATUS_ATTN_EVENTS (STATUS_ATTN_BITS_LINK_STATE | \
+ STATUS_ATTN_BITS_TIMER_ABORT)
static inline int
bnx2_has_work(struct bnx2 *bp)
return rc;
}
+static void
+bnx2_init_remote_phy(struct bnx2 *bp)
+{
+ u32 val;
+
+ bp->phy_flags &= ~REMOTE_PHY_CAP_FLAG;
+ if (!(bp->phy_flags & PHY_SERDES_FLAG))
+ return;
+
+ val = REG_RD_IND(bp, bp->shmem_base + BNX2_FW_CAP_MB);
+ if ((val & BNX2_FW_CAP_SIGNATURE_MASK) != BNX2_FW_CAP_SIGNATURE)
+ return;
+
+ if (val & BNX2_FW_CAP_REMOTE_PHY_CAPABLE) {
+ if (netif_running(bp->dev)) {
+ val = BNX2_DRV_ACK_CAP_SIGNATURE |
+ BNX2_FW_CAP_REMOTE_PHY_CAPABLE;
+ REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_ACK_CAP_MB,
+ val);
+ }
+ bp->phy_flags |= REMOTE_PHY_CAP_FLAG;
+
+ val = REG_RD_IND(bp, bp->shmem_base + BNX2_LINK_STATUS);
+ if (val & BNX2_LINK_STATUS_SERDES_LINK)
+ bp->phy_port = PORT_FIBRE;
+ else
+ bp->phy_port = PORT_TP;
+ }
+}
+
static int
bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
{
if (rc)
return rc;
+ spin_lock_bh(&bp->phy_lock);
+ bnx2_init_remote_phy(bp);
+ if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
+ bnx2_set_default_remote_link(bp);
+ spin_unlock_bh(&bp->phy_lock);
+
if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
/* Adjust the voltage regular to two steps lower. The default
* of this register is 0x0000000e. */
/* Initialize context mapping and zero out the quick contexts. The
* context block must have already been enabled. */
- if (CHIP_NUM(bp) == CHIP_NUM_5709)
- bnx2_init_5709_context(bp);
- else
+ if (CHIP_NUM(bp) == CHIP_NUM_5709) {
+ rc = bnx2_init_5709_context(bp);
+ if (rc)
+ return rc;
+ } else
bnx2_init_context(bp);
if ((rc = bnx2_init_cpus(bp)) != 0)
REG_WR(bp, BNX2_HC_CMD_TICKS,
(bp->cmd_ticks_int << 16) | bp->cmd_ticks);
- REG_WR(bp, BNX2_HC_STATS_TICKS, bp->stats_ticks & 0xffff00);
+ if (CHIP_NUM(bp) == CHIP_NUM_5708)
+ REG_WR(bp, BNX2_HC_STATS_TICKS, 0);
+ else
+ REG_WR(bp, BNX2_HC_STATS_TICKS, bp->stats_ticks & 0xffff00);
REG_WR(bp, BNX2_HC_STAT_COLLECT_TICKS, 0xbb8); /* 3ms */
if (CHIP_ID(bp) == CHIP_ID_5706_A1)
/* Initialize the receive filter. */
bnx2_set_rx_mode(bp->dev);
+ if (CHIP_NUM(bp) == CHIP_NUM_5709) {
+ val = REG_RD(bp, BNX2_MISC_NEW_CORE_CTL);
+ val |= BNX2_MISC_NEW_CORE_CTL_DMA_ENABLE;
+ REG_WR(bp, BNX2_MISC_NEW_CORE_CTL, val);
+ }
rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT2 | BNX2_DRV_MSG_CODE_RESET,
0);
spin_lock_bh(&bp->phy_lock);
bnx2_init_phy(bp);
- spin_unlock_bh(&bp->phy_lock);
bnx2_set_link(bp);
+ spin_unlock_bh(&bp->phy_lock);
return 0;
}
static void
bnx2_5708_serdes_timer(struct bnx2 *bp)
{
+ if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
+ return;
+
if ((bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) == 0) {
bp->serdes_an_pending = 0;
return;
bp->stats_blk->stat_FwRxDrop = REG_RD_IND(bp, BNX2_FW_RX_DROP_COUNT);
+ /* workaround occasional corrupted counters */
+ if (CHIP_NUM(bp) == CHIP_NUM_5708 && bp->stats_ticks)
+ REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd |
+ BNX2_HC_COMMAND_STATS_NOW);
+
if (bp->phy_flags & PHY_SERDES_FLAG) {
if (CHIP_NUM(bp) == CHIP_NUM_5706)
bnx2_5706_serdes_timer(bp);
bnx2_netif_start(bp);
}
-
-/* Called with rtnl_lock */
-static void
-bnx2_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid)
-{
- struct bnx2 *bp = netdev_priv(dev);
-
- bnx2_netif_stop(bp);
- vlan_group_set_device(bp->vlgrp, vid, NULL);
- bnx2_set_rx_mode(dev);
-
- bnx2_netif_start(bp);
-}
#endif
/* Called with netif_tx_lock.
bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct bnx2 *bp = netdev_priv(dev);
+ int support_serdes = 0, support_copper = 0;
cmd->supported = SUPPORTED_Autoneg;
- if (bp->phy_flags & PHY_SERDES_FLAG) {
+ if (bp->phy_flags & REMOTE_PHY_CAP_FLAG) {
+ support_serdes = 1;
+ support_copper = 1;
+ } else if (bp->phy_port == PORT_FIBRE)
+ support_serdes = 1;
+ else
+ support_copper = 1;
+
+ if (support_serdes) {
cmd->supported |= SUPPORTED_1000baseT_Full |
SUPPORTED_FIBRE;
if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG)
cmd->supported |= SUPPORTED_2500baseX_Full;
- cmd->port = PORT_FIBRE;
}
- else {
+ if (support_copper) {
cmd->supported |= SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half |
SUPPORTED_1000baseT_Full |
SUPPORTED_TP;
- cmd->port = PORT_TP;
}
+ spin_lock_bh(&bp->phy_lock);
+ cmd->port = bp->phy_port;
cmd->advertising = bp->advertising;
if (bp->autoneg & AUTONEG_SPEED) {
cmd->speed = -1;
cmd->duplex = -1;
}
+ spin_unlock_bh(&bp->phy_lock);
cmd->transceiver = XCVR_INTERNAL;
cmd->phy_address = bp->phy_addr;
u8 req_duplex = bp->req_duplex;
u16 req_line_speed = bp->req_line_speed;
u32 advertising = bp->advertising;
+ int err = -EINVAL;
+
+ spin_lock_bh(&bp->phy_lock);
+
+ if (cmd->port != PORT_TP && cmd->port != PORT_FIBRE)
+ goto err_out_unlock;
+
+ if (cmd->port != bp->phy_port && !(bp->phy_flags & REMOTE_PHY_CAP_FLAG))
+ goto err_out_unlock;
if (cmd->autoneg == AUTONEG_ENABLE) {
autoneg |= AUTONEG_SPEED;
(cmd->advertising == ADVERTISED_100baseT_Half) ||
(cmd->advertising == ADVERTISED_100baseT_Full)) {
- if (bp->phy_flags & PHY_SERDES_FLAG)
- return -EINVAL;
+ if (cmd->port == PORT_FIBRE)
+ goto err_out_unlock;
advertising = cmd->advertising;
} else if (cmd->advertising == ADVERTISED_2500baseX_Full) {
- if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))
- return -EINVAL;
- } else if (cmd->advertising == ADVERTISED_1000baseT_Full) {
+ if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) ||
+ (cmd->port == PORT_TP))
+ goto err_out_unlock;
+ } else if (cmd->advertising == ADVERTISED_1000baseT_Full)
advertising = cmd->advertising;
- }
- else if (cmd->advertising == ADVERTISED_1000baseT_Half) {
- return -EINVAL;
- }
+ else if (cmd->advertising == ADVERTISED_1000baseT_Half)
+ goto err_out_unlock;
else {
- if (bp->phy_flags & PHY_SERDES_FLAG) {
+ if (cmd->port == PORT_FIBRE)
advertising = ETHTOOL_ALL_FIBRE_SPEED;
- }
- else {
+ else
advertising = ETHTOOL_ALL_COPPER_SPEED;
- }
}
advertising |= ADVERTISED_Autoneg;
}
else {
- if (bp->phy_flags & PHY_SERDES_FLAG) {
+ if (cmd->port == PORT_FIBRE) {
if ((cmd->speed != SPEED_1000 &&
cmd->speed != SPEED_2500) ||
(cmd->duplex != DUPLEX_FULL))
- return -EINVAL;
+ goto err_out_unlock;
if (cmd->speed == SPEED_2500 &&
!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))
- return -EINVAL;
- }
- else if (cmd->speed == SPEED_1000) {
- return -EINVAL;
+ goto err_out_unlock;
}
+ else if (cmd->speed == SPEED_1000 || cmd->speed == SPEED_2500)
+ goto err_out_unlock;
+
autoneg &= ~AUTONEG_SPEED;
req_line_speed = cmd->speed;
req_duplex = cmd->duplex;
bp->req_line_speed = req_line_speed;
bp->req_duplex = req_duplex;
- spin_lock_bh(&bp->phy_lock);
-
- bnx2_setup_phy(bp);
+ err = bnx2_setup_phy(bp, cmd->port);
+err_out_unlock:
spin_unlock_bh(&bp->phy_lock);
- return 0;
+ return err;
}
static void
spin_lock_bh(&bp->phy_lock);
+ if (bp->phy_flags & REMOTE_PHY_CAP_FLAG) {
+ int rc;
+
+ rc = bnx2_setup_remote_phy(bp, bp->phy_port);
+ spin_unlock_bh(&bp->phy_lock);
+ return rc;
+ }
+
/* Force a link down visible on the other side */
if (bp->phy_flags & PHY_SERDES_FLAG) {
bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
0xff;
bp->stats_ticks = coal->stats_block_coalesce_usecs;
+ if (CHIP_NUM(bp) == CHIP_NUM_5708) {
+ if (bp->stats_ticks != 0 && bp->stats_ticks != USEC_PER_SEC)
+ bp->stats_ticks = USEC_PER_SEC;
+ }
if (bp->stats_ticks > 0xffff00) bp->stats_ticks = 0xffff00;
bp->stats_ticks &= 0xffff00;
spin_lock_bh(&bp->phy_lock);
- bnx2_setup_phy(bp);
+ bnx2_setup_phy(bp, bp->phy_port);
spin_unlock_bh(&bp->phy_lock);
case SIOCGMIIREG: {
u32 mii_regval;
+ if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
+ return -EOPNOTSUPP;
+
if (!netif_running(dev))
return -EAGAIN;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
+ if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
+ return -EOPNOTSUPP;
+
if (!netif_running(dev))
return -EAGAIN;
else if (CHIP_BOND_ID(bp) & CHIP_BOND_ID_SERDES_BIT)
bp->phy_flags |= PHY_SERDES_FLAG;
+ bp->phy_port = PORT_TP;
if (bp->phy_flags & PHY_SERDES_FLAG) {
+ bp->phy_port = PORT_FIBRE;
bp->flags |= NO_WOL_FLAG;
if (CHIP_NUM(bp) != CHIP_NUM_5706) {
bp->phy_addr = 2;
if (reg & BNX2_SHARED_HW_CFG_PHY_2_5G)
bp->phy_flags |= PHY_2_5G_CAPABLE_FLAG;
}
+ bnx2_init_remote_phy(bp);
+
} else if (CHIP_NUM(bp) == CHIP_NUM_5706 ||
CHIP_NUM(bp) == CHIP_NUM_5708)
bp->phy_flags |= PHY_CRC_FIX_FLAG;
}
}
- bp->autoneg = AUTONEG_SPEED | AUTONEG_FLOW_CTRL;
- bp->req_line_speed = 0;
- if (bp->phy_flags & PHY_SERDES_FLAG) {
- bp->advertising = ETHTOOL_ALL_FIBRE_SPEED | ADVERTISED_Autoneg;
-
- reg = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_CONFIG);
- reg &= BNX2_PORT_HW_CFG_CFG_DFLT_LINK_MASK;
- if (reg == BNX2_PORT_HW_CFG_CFG_DFLT_LINK_1G) {
- bp->autoneg = 0;
- bp->req_line_speed = bp->line_speed = SPEED_1000;
- bp->req_duplex = DUPLEX_FULL;
- }
- }
- else {
- bp->advertising = ETHTOOL_ALL_COPPER_SPEED | ADVERTISED_Autoneg;
- }
-
+ bnx2_set_default_link(bp);
bp->req_flow_ctrl = FLOW_CTRL_RX | FLOW_CTRL_TX;
init_timer(&bp->timer);
dev->watchdog_timeo = TX_TIMEOUT;
#ifdef BCM_VLAN
dev->vlan_rx_register = bnx2_vlan_rx_register;
- dev->vlan_rx_kill_vid = bnx2_vlan_rx_kill_vid;
#endif
dev->poll = bnx2_poll;
dev->ethtool_ops = &bnx2_ethtool_ops;
memcpy(dev->perm_addr, bp->mac_addr, 6);
bp->name = board_info[ent->driver_data].name;
+ dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
if (CHIP_NUM(bp) == CHIP_NUM_5709)
- dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
- else
- dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
+ dev->features |= NETIF_F_IPV6_CSUM;
+
#ifdef BCM_VLAN
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
#endif