diff options
Diffstat (limited to 'drivers/net/sfc/falcon_xmac.c')
-rw-r--r-- | drivers/net/sfc/falcon_xmac.c | 278 |
1 files changed, 134 insertions, 144 deletions
diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c index bec52ca37eee..3da933f8f079 100644 --- a/drivers/net/sfc/falcon_xmac.c +++ b/drivers/net/sfc/falcon_xmac.c @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006-2008 Solarflare Communications Inc. + * Copyright 2006-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published @@ -11,13 +11,12 @@ #include <linux/delay.h> #include "net_driver.h" #include "efx.h" -#include "falcon.h" -#include "falcon_hwdefs.h" -#include "falcon_io.h" +#include "nic.h" +#include "regs.h" +#include "io.h" #include "mac.h" #include "mdio_10g.h" #include "phy.h" -#include "boards.h" #include "workarounds.h" /************************************************************************** @@ -36,43 +35,47 @@ static void falcon_setup_xaui(struct efx_nic *efx) if (efx->phy_type == PHY_TYPE_NONE) return; - falcon_read(efx, &sdctl, XX_SD_CTL_REG); - EFX_SET_OWORD_FIELD(sdctl, XX_HIDRVD, XX_SD_CTL_DRV_DEFAULT); - EFX_SET_OWORD_FIELD(sdctl, XX_LODRVD, XX_SD_CTL_DRV_DEFAULT); - EFX_SET_OWORD_FIELD(sdctl, XX_HIDRVC, XX_SD_CTL_DRV_DEFAULT); - EFX_SET_OWORD_FIELD(sdctl, XX_LODRVC, XX_SD_CTL_DRV_DEFAULT); - EFX_SET_OWORD_FIELD(sdctl, XX_HIDRVB, XX_SD_CTL_DRV_DEFAULT); - EFX_SET_OWORD_FIELD(sdctl, XX_LODRVB, XX_SD_CTL_DRV_DEFAULT); - EFX_SET_OWORD_FIELD(sdctl, XX_HIDRVA, XX_SD_CTL_DRV_DEFAULT); - EFX_SET_OWORD_FIELD(sdctl, XX_LODRVA, XX_SD_CTL_DRV_DEFAULT); - falcon_write(efx, &sdctl, XX_SD_CTL_REG); + efx_reado(efx, &sdctl, FR_AB_XX_SD_CTL); + EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_HIDRVD, FFE_AB_XX_SD_CTL_DRV_DEF); + EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_LODRVD, FFE_AB_XX_SD_CTL_DRV_DEF); + EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_HIDRVC, FFE_AB_XX_SD_CTL_DRV_DEF); + EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_LODRVC, FFE_AB_XX_SD_CTL_DRV_DEF); + EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_HIDRVB, FFE_AB_XX_SD_CTL_DRV_DEF); + EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_LODRVB, FFE_AB_XX_SD_CTL_DRV_DEF); + EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_HIDRVA, FFE_AB_XX_SD_CTL_DRV_DEF); + EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_LODRVA, FFE_AB_XX_SD_CTL_DRV_DEF); + efx_writeo(efx, &sdctl, FR_AB_XX_SD_CTL); EFX_POPULATE_OWORD_8(txdrv, - XX_DEQD, XX_TXDRV_DEQ_DEFAULT, - XX_DEQC, XX_TXDRV_DEQ_DEFAULT, - XX_DEQB, XX_TXDRV_DEQ_DEFAULT, - XX_DEQA, XX_TXDRV_DEQ_DEFAULT, - XX_DTXD, XX_TXDRV_DTX_DEFAULT, - XX_DTXC, XX_TXDRV_DTX_DEFAULT, - XX_DTXB, XX_TXDRV_DTX_DEFAULT, - XX_DTXA, XX_TXDRV_DTX_DEFAULT); - falcon_write(efx, &txdrv, XX_TXDRV_CTL_REG); + FRF_AB_XX_DEQD, FFE_AB_XX_TXDRV_DEQ_DEF, + FRF_AB_XX_DEQC, FFE_AB_XX_TXDRV_DEQ_DEF, + FRF_AB_XX_DEQB, FFE_AB_XX_TXDRV_DEQ_DEF, + FRF_AB_XX_DEQA, FFE_AB_XX_TXDRV_DEQ_DEF, + FRF_AB_XX_DTXD, FFE_AB_XX_TXDRV_DTX_DEF, + FRF_AB_XX_DTXC, FFE_AB_XX_TXDRV_DTX_DEF, + FRF_AB_XX_DTXB, FFE_AB_XX_TXDRV_DTX_DEF, + FRF_AB_XX_DTXA, FFE_AB_XX_TXDRV_DTX_DEF); + efx_writeo(efx, &txdrv, FR_AB_XX_TXDRV_CTL); } int falcon_reset_xaui(struct efx_nic *efx) { + struct falcon_nic_data *nic_data = efx->nic_data; efx_oword_t reg; int count; + /* Don't fetch MAC statistics over an XMAC reset */ + WARN_ON(nic_data->stats_disable_count == 0); + /* Start reset sequence */ - EFX_POPULATE_DWORD_1(reg, XX_RST_XX_EN, 1); - falcon_write(efx, ®, XX_PWR_RST_REG); + EFX_POPULATE_OWORD_1(reg, FRF_AB_XX_RST_XX_EN, 1); + efx_writeo(efx, ®, FR_AB_XX_PWR_RST); /* Wait up to 10 ms for completion, then reinitialise */ for (count = 0; count < 1000; count++) { - falcon_read(efx, ®, XX_PWR_RST_REG); - if (EFX_OWORD_FIELD(reg, XX_RST_XX_EN) == 0 && - EFX_OWORD_FIELD(reg, XX_SD_RST_ACT) == 0) { + efx_reado(efx, ®, FR_AB_XX_PWR_RST); + if (EFX_OWORD_FIELD(reg, FRF_AB_XX_RST_XX_EN) == 0 && + EFX_OWORD_FIELD(reg, FRF_AB_XX_SD_RST_ACT) == 0) { falcon_setup_xaui(efx); return 0; } @@ -86,30 +89,30 @@ static void falcon_mask_status_intr(struct efx_nic *efx, bool enable) { efx_oword_t reg; - if ((falcon_rev(efx) != FALCON_REV_B0) || LOOPBACK_INTERNAL(efx)) + if ((efx_nic_rev(efx) != EFX_REV_FALCON_B0) || LOOPBACK_INTERNAL(efx)) return; /* We expect xgmii faults if the wireside link is up */ - if (!EFX_WORKAROUND_5147(efx) || !efx->link_up) + if (!EFX_WORKAROUND_5147(efx) || !efx->link_state.up) return; /* We can only use this interrupt to signal the negative edge of * xaui_align [we have to poll the positive edge]. */ - if (!efx->mac_up) + if (efx->xmac_poll_required) return; /* Flush the ISR */ if (enable) - falcon_read(efx, ®, XM_MGT_INT_REG_B0); + efx_reado(efx, ®, FR_AB_XM_MGT_INT_MSK); EFX_POPULATE_OWORD_2(reg, - XM_MSK_RMTFLT, !enable, - XM_MSK_LCLFLT, !enable); - falcon_write(efx, ®, XM_MGT_INT_MSK_REG_B0); + FRF_AB_XM_MSK_RMTFLT, !enable, + FRF_AB_XM_MSK_LCLFLT, !enable); + efx_writeo(efx, ®, FR_AB_XM_MGT_INT_MASK); } /* Get status of XAUI link */ -bool falcon_xaui_link_ok(struct efx_nic *efx) +static bool falcon_xaui_link_ok(struct efx_nic *efx) { efx_oword_t reg; bool align_done, link_ok = false; @@ -119,84 +122,79 @@ bool falcon_xaui_link_ok(struct efx_nic *efx) return true; /* Read link status */ - falcon_read(efx, ®, XX_CORE_STAT_REG); + efx_reado(efx, ®, FR_AB_XX_CORE_STAT); - align_done = EFX_OWORD_FIELD(reg, XX_ALIGN_DONE); - sync_status = EFX_OWORD_FIELD(reg, XX_SYNC_STAT); - if (align_done && (sync_status == XX_SYNC_STAT_DECODE_SYNCED)) + align_done = EFX_OWORD_FIELD(reg, FRF_AB_XX_ALIGN_DONE); + sync_status = EFX_OWORD_FIELD(reg, FRF_AB_XX_SYNC_STAT); + if (align_done && (sync_status == FFE_AB_XX_STAT_ALL_LANES)) link_ok = true; /* Clear link status ready for next read */ - EFX_SET_OWORD_FIELD(reg, XX_COMMA_DET, XX_COMMA_DET_RESET); - EFX_SET_OWORD_FIELD(reg, XX_CHARERR, XX_CHARERR_RESET); - EFX_SET_OWORD_FIELD(reg, XX_DISPERR, XX_DISPERR_RESET); - falcon_write(efx, ®, XX_CORE_STAT_REG); + EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_COMMA_DET, FFE_AB_XX_STAT_ALL_LANES); + EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_CHAR_ERR, FFE_AB_XX_STAT_ALL_LANES); + EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_DISPERR, FFE_AB_XX_STAT_ALL_LANES); + efx_writeo(efx, ®, FR_AB_XX_CORE_STAT); /* If the link is up, then check the phy side of the xaui link */ - if (efx->link_up && link_ok) - if (efx->phy_op->mmds & (1 << MDIO_MMD_PHYXS)) + if (efx->link_state.up && link_ok) + if (efx->mdio.mmds & (1 << MDIO_MMD_PHYXS)) link_ok = efx_mdio_phyxgxs_lane_sync(efx); return link_ok; } -static void falcon_reconfigure_xmac_core(struct efx_nic *efx) +void falcon_reconfigure_xmac_core(struct efx_nic *efx) { unsigned int max_frame_len; efx_oword_t reg; - bool rx_fc = !!(efx->link_fc & EFX_FC_RX); + bool rx_fc = !!(efx->link_state.fc & EFX_FC_RX); + bool tx_fc = !!(efx->link_state.fc & EFX_FC_TX); /* Configure MAC - cut-thru mode is hard wired on */ - EFX_POPULATE_DWORD_3(reg, - XM_RX_JUMBO_MODE, 1, - XM_TX_STAT_EN, 1, - XM_RX_STAT_EN, 1); - falcon_write(efx, ®, XM_GLB_CFG_REG); + EFX_POPULATE_OWORD_3(reg, + FRF_AB_XM_RX_JUMBO_MODE, 1, + FRF_AB_XM_TX_STAT_EN, 1, + FRF_AB_XM_RX_STAT_EN, 1); + efx_writeo(efx, ®, FR_AB_XM_GLB_CFG); /* Configure TX */ - EFX_POPULATE_DWORD_6(reg, - XM_TXEN, 1, - XM_TX_PRMBL, 1, - XM_AUTO_PAD, 1, - XM_TXCRC, 1, - XM_FCNTL, 1, - XM_IPG, 0x3); - falcon_write(efx, ®, XM_TX_CFG_REG); + EFX_POPULATE_OWORD_6(reg, + FRF_AB_XM_TXEN, 1, + FRF_AB_XM_TX_PRMBL, 1, + FRF_AB_XM_AUTO_PAD, 1, + FRF_AB_XM_TXCRC, 1, + FRF_AB_XM_FCNTL, tx_fc, + FRF_AB_XM_IPG, 0x3); + efx_writeo(efx, ®, FR_AB_XM_TX_CFG); /* Configure RX */ - EFX_POPULATE_DWORD_5(reg, - XM_RXEN, 1, - XM_AUTO_DEPAD, 0, - XM_ACPT_ALL_MCAST, 1, - XM_ACPT_ALL_UCAST, efx->promiscuous, - XM_PASS_CRC_ERR, 1); - falcon_write(efx, ®, XM_RX_CFG_REG); + EFX_POPULATE_OWORD_5(reg, + FRF_AB_XM_RXEN, 1, + FRF_AB_XM_AUTO_DEPAD, 0, + FRF_AB_XM_ACPT_ALL_MCAST, 1, + FRF_AB_XM_ACPT_ALL_UCAST, efx->promiscuous, + FRF_AB_XM_PASS_CRC_ERR, 1); + efx_writeo(efx, ®, FR_AB_XM_RX_CFG); /* Set frame length */ max_frame_len = EFX_MAX_FRAME_LEN(efx->net_dev->mtu); - EFX_POPULATE_DWORD_1(reg, XM_MAX_RX_FRM_SIZE, max_frame_len); - falcon_write(efx, ®, XM_RX_PARAM_REG); - EFX_POPULATE_DWORD_2(reg, - XM_MAX_TX_FRM_SIZE, max_frame_len, - XM_TX_JUMBO_MODE, 1); - falcon_write(efx, ®, XM_TX_PARAM_REG); - - EFX_POPULATE_DWORD_2(reg, - XM_PAUSE_TIME, 0xfffe, /* MAX PAUSE TIME */ - XM_DIS_FCNTL, !rx_fc); - falcon_write(efx, ®, XM_FC_REG); + EFX_POPULATE_OWORD_1(reg, FRF_AB_XM_MAX_RX_FRM_SIZE, max_frame_len); + efx_writeo(efx, ®, FR_AB_XM_RX_PARAM); + EFX_POPULATE_OWORD_2(reg, + FRF_AB_XM_MAX_TX_FRM_SIZE, max_frame_len, + FRF_AB_XM_TX_JUMBO_MODE, 1); + efx_writeo(efx, ®, FR_AB_XM_TX_PARAM); + + EFX_POPULATE_OWORD_2(reg, + FRF_AB_XM_PAUSE_TIME, 0xfffe, /* MAX PAUSE TIME */ + FRF_AB_XM_DIS_FCNTL, !rx_fc); + efx_writeo(efx, ®, FR_AB_XM_FC); /* Set MAC address */ - EFX_POPULATE_DWORD_4(reg, - XM_ADR_0, efx->net_dev->dev_addr[0], - XM_ADR_1, efx->net_dev->dev_addr[1], - XM_ADR_2, efx->net_dev->dev_addr[2], - XM_ADR_3, efx->net_dev->dev_addr[3]); - falcon_write(efx, ®, XM_ADR_LO_REG); - EFX_POPULATE_DWORD_2(reg, - XM_ADR_4, efx->net_dev->dev_addr[4], - XM_ADR_5, efx->net_dev->dev_addr[5]); - falcon_write(efx, ®, XM_ADR_HI_REG); + memcpy(®, &efx->net_dev->dev_addr[0], 4); + efx_writeo(efx, ®, FR_AB_XM_ADR_LO); + memcpy(®, &efx->net_dev->dev_addr[4], 2); + efx_writeo(efx, ®, FR_AB_XM_ADR_HI); } static void falcon_reconfigure_xgxs_core(struct efx_nic *efx) @@ -212,12 +210,13 @@ static void falcon_reconfigure_xgxs_core(struct efx_nic *efx) bool old_xgmii_loopback, old_xgxs_loopback, old_xaui_loopback; bool reset_xgxs; - falcon_read(efx, ®, XX_CORE_STAT_REG); - old_xgxs_loopback = EFX_OWORD_FIELD(reg, XX_XGXS_LB_EN); - old_xgmii_loopback = EFX_OWORD_FIELD(reg, XX_XGMII_LB_EN); + efx_reado(efx, ®, FR_AB_XX_CORE_STAT); + old_xgxs_loopback = EFX_OWORD_FIELD(reg, FRF_AB_XX_XGXS_LB_EN); + old_xgmii_loopback = + EFX_OWORD_FIELD(reg, FRF_AB_XX_XGMII_LB_EN); - falcon_read(efx, ®, XX_SD_CTL_REG); - old_xaui_loopback = EFX_OWORD_FIELD(reg, XX_LPBKA); + efx_reado(efx, ®, FR_AB_XX_SD_CTL); + old_xaui_loopback = EFX_OWORD_FIELD(reg, FRF_AB_XX_LPBKA); /* The PHY driver may have turned XAUI off */ reset_xgxs = ((xgxs_loopback != old_xgxs_loopback) || @@ -228,45 +227,55 @@ static void falcon_reconfigure_xgxs_core(struct efx_nic *efx) falcon_reset_xaui(efx); } - falcon_read(efx, ®, XX_CORE_STAT_REG); - EFX_SET_OWORD_FIELD(reg, XX_FORCE_SIG, + efx_reado(efx, ®, FR_AB_XX_CORE_STAT); + EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_FORCE_SIG, (xgxs_loopback || xaui_loopback) ? - XX_FORCE_SIG_DECODE_FORCED : 0); - EFX_SET_OWORD_FIELD(reg, XX_XGXS_LB_EN, xgxs_loopback); - EFX_SET_OWORD_FIELD(reg, XX_XGMII_LB_EN, xgmii_loopback); - falcon_write(efx, ®, XX_CORE_STAT_REG); - - falcon_read(efx, ®, XX_SD_CTL_REG); - EFX_SET_OWORD_FIELD(reg, XX_LPBKD, xaui_loopback); - EFX_SET_OWORD_FIELD(reg, XX_LPBKC, xaui_loopback); - EFX_SET_OWORD_FIELD(reg, XX_LPBKB, xaui_loopback); - EFX_SET_OWORD_FIELD(reg, XX_LPBKA, xaui_loopback); - falcon_write(efx, ®, XX_SD_CTL_REG); + FFE_AB_XX_FORCE_SIG_ALL_LANES : 0); + EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_XGXS_LB_EN, xgxs_loopback); + EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_XGMII_LB_EN, xgmii_loopback); + efx_writeo(efx, ®, FR_AB_XX_CORE_STAT); + + efx_reado(efx, ®, FR_AB_XX_SD_CTL); + EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_LPBKD, xaui_loopback); + EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_LPBKC, xaui_loopback); + EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_LPBKB, xaui_loopback); + EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_LPBKA, xaui_loopback); + efx_writeo(efx, ®, FR_AB_XX_SD_CTL); } -/* Try and bring the Falcon side of the Falcon-Phy XAUI link fails - * to come back up. Bash it until it comes back up */ -static void falcon_check_xaui_link_up(struct efx_nic *efx, int tries) +/* Try to bring up the Falcon side of the Falcon-Phy XAUI link */ +static bool falcon_check_xaui_link_up(struct efx_nic *efx, int tries) { - efx->mac_up = falcon_xaui_link_ok(efx); + bool mac_up = falcon_xaui_link_ok(efx); - if ((efx->loopback_mode == LOOPBACK_NETWORK) || + if (LOOPBACK_MASK(efx) & LOOPBACKS_EXTERNAL(efx) & LOOPBACKS_WS || efx_phy_mode_disabled(efx->phy_mode)) /* XAUI link is expected to be down */ - return; + return mac_up; - while (!efx->mac_up && tries) { + falcon_stop_nic_stats(efx); + + while (!mac_up && tries) { EFX_LOG(efx, "bashing xaui\n"); falcon_reset_xaui(efx); udelay(200); - efx->mac_up = falcon_xaui_link_ok(efx); + mac_up = falcon_xaui_link_ok(efx); --tries; } + + falcon_start_nic_stats(efx); + + return mac_up; } -static void falcon_reconfigure_xmac(struct efx_nic *efx) +static bool falcon_xmac_check_fault(struct efx_nic *efx) +{ + return !falcon_check_xaui_link_up(efx, 5); +} + +static int falcon_reconfigure_xmac(struct efx_nic *efx) { falcon_mask_status_intr(efx, false); @@ -275,18 +284,15 @@ static void falcon_reconfigure_xmac(struct efx_nic *efx) falcon_reconfigure_mac_wrapper(efx); - falcon_check_xaui_link_up(efx, 5); + efx->xmac_poll_required = !falcon_check_xaui_link_up(efx, 5); falcon_mask_status_intr(efx, true); + + return 0; } static void falcon_update_stats_xmac(struct efx_nic *efx) { struct efx_mac_stats *mac_stats = &efx->mac_stats; - int rc; - - rc = falcon_dma_stats(efx, XgDmaDone_offset); - if (rc) - return; /* Update MAC stats from DMAed values */ FALCON_STAT(efx, XgRxOctets, rx_bytes); @@ -344,35 +350,19 @@ static void falcon_update_stats_xmac(struct efx_nic *efx) mac_stats->rx_control * 64); } -static void falcon_xmac_irq(struct efx_nic *efx) -{ - /* The XGMII link has a transient fault, which indicates either: - * - there's a transient xgmii fault - * - falcon's end of the xaui link may need a kick - * - the wire-side link may have gone down, but the lasi/poll() - * hasn't noticed yet. - * - * We only want to even bother polling XAUI if we're confident it's - * not (1) or (3). In both cases, the only reliable way to spot this - * is to wait a bit. We do this here by forcing the mac link state - * to down, and waiting for the mac poll to come round and check - */ - efx->mac_up = false; -} - -static void falcon_poll_xmac(struct efx_nic *efx) +void falcon_poll_xmac(struct efx_nic *efx) { - if (!EFX_WORKAROUND_5147(efx) || !efx->link_up || efx->mac_up) + if (!EFX_WORKAROUND_5147(efx) || !efx->link_state.up || + !efx->xmac_poll_required) return; falcon_mask_status_intr(efx, false); - falcon_check_xaui_link_up(efx, 1); + efx->xmac_poll_required = !falcon_check_xaui_link_up(efx, 1); falcon_mask_status_intr(efx, true); } struct efx_mac_operations falcon_xmac_operations = { .reconfigure = falcon_reconfigure_xmac, .update_stats = falcon_update_stats_xmac, - .irq = falcon_xmac_irq, - .poll = falcon_poll_xmac, + .check_fault = falcon_xmac_check_fault, }; |