[kernel] r14897 - in dists/trunk/linux-2.6/debian: . patches/bugfix/all patches/series
Ben Hutchings
benh at alioth.debian.org
Thu Jan 7 19:21:55 UTC 2010
Author: benh
Date: Thu Jan 7 19:21:53 2010
New Revision: 14897
Log:
sfc: Apply fixes from 2.6.33-rc3
Added:
dists/trunk/linux-2.6/debian/patches/bugfix/all/sfc-Disable-TX-descriptor-prefetch-watchdog.patch
dists/trunk/linux-2.6/debian/patches/bugfix/all/sfc-Fix-DMA-mapping-cleanup-on-error-in-TSO.patch
dists/trunk/linux-2.6/debian/patches/bugfix/all/sfc-Include-XGXS-in-XMAC-link-status-check.patch
dists/trunk/linux-2.6/debian/patches/bugfix/all/sfc-Move-PHY-software-state-initialisation.patch
dists/trunk/linux-2.6/debian/patches/bugfix/all/sfc-QT2025C-Add-error-message-for-suspected-bad-SFP-cable.patch
dists/trunk/linux-2.6/debian/patches/bugfix/all/sfc-QT2025C-Switch-into-self-configure-mode.patch
dists/trunk/linux-2.6/debian/patches/bugfix/all/sfc-QT2025C-Work-around-PHY-bug.patch
dists/trunk/linux-2.6/debian/patches/bugfix/all/sfc-QT2025C-Work-around-PHY-firmware-initialisation.patch
dists/trunk/linux-2.6/debian/patches/series/5
Modified:
dists/trunk/linux-2.6/debian/changelog
Modified: dists/trunk/linux-2.6/debian/changelog
==============================================================================
--- dists/trunk/linux-2.6/debian/changelog Thu Jan 7 14:30:52 2010 (r14896)
+++ dists/trunk/linux-2.6/debian/changelog Thu Jan 7 19:21:53 2010 (r14897)
@@ -1,3 +1,10 @@
+linux-2.6 (2.6.32-5) UNRELEASED; urgency=low
+
+ [ Ben Hutchings ]
+ * sfc: Apply fixes from 2.6.33-rc3
+
+ -- Ben Hutchings <ben at decadent.org.uk> Thu, 07 Jan 2010 19:19:32 +0000
+
linux-2.6 (2.6.32-4) unstable; urgency=low
[ Ben Hutchings ]
Added: dists/trunk/linux-2.6/debian/patches/bugfix/all/sfc-Disable-TX-descriptor-prefetch-watchdog.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/trunk/linux-2.6/debian/patches/bugfix/all/sfc-Disable-TX-descriptor-prefetch-watchdog.patch Thu Jan 7 19:21:53 2010 (r14897)
@@ -0,0 +1,29 @@
+From 286d47ba90315a871f77351f7f61b7e4a96476a9 Mon Sep 17 00:00:00 2001
+From: Ben Hutchings <bhutchings at solarflare.com>
+Date: Wed, 23 Dec 2009 13:49:13 +0000
+Subject: [PATCH 8/8] sfc: Disable TX descriptor prefetch watchdog
+
+This hardware watchdog can misfire, so it does more harm than good.
+
+Signed-off-by: Ben Hutchings <bhutchings at solarflare.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+---
+ drivers/net/sfc/nic.c | 2 ++
+ 1 files changed, 2 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c
+index a577be2..db44224 100644
+--- a/drivers/net/sfc/nic.c
++++ b/drivers/net/sfc/nic.c
+@@ -1576,6 +1576,8 @@ void efx_nic_init_common(struct efx_nic *efx)
+ EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_SOFT_EVT_EN, 1);
+ /* Prefetch threshold 2 => fetch when descriptor cache half empty */
+ EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_PREF_THRESHOLD, 2);
++ /* Disable hardware watchdog which can misfire */
++ EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_PREF_WD_TMR, 0x3fffff);
+ /* Squash TX of packets of 16 bytes or less */
+ if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0)
+ EFX_SET_OWORD_FIELD(temp, FRF_BZ_TX_FLUSH_MIN_LEN_EN, 1);
+--
+1.6.5.7
+
Added: dists/trunk/linux-2.6/debian/patches/bugfix/all/sfc-Fix-DMA-mapping-cleanup-on-error-in-TSO.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/trunk/linux-2.6/debian/patches/bugfix/all/sfc-Fix-DMA-mapping-cleanup-on-error-in-TSO.patch Thu Jan 7 19:21:53 2010 (r14897)
@@ -0,0 +1,40 @@
+From a7ebd27a13757248863cd61e541af7fa9e7727ee Mon Sep 17 00:00:00 2001
+From: Neil Turton <nturton at solarflare.com>
+Date: Wed, 23 Dec 2009 13:47:13 +0000
+Subject: [PATCH 3/8] sfc: Fix DMA mapping cleanup in case of an error in TSO
+
+We need buffer->len to remain valid to work out the correct address to
+be unmapped. We therefore need to clear buffer->len after the unmap
+operation.
+
+Signed-off-by: Ben Hutchings <bhutchings at solarflare.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+---
+ drivers/net/sfc/tx.c | 4 ++--
+ 1 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c
+index e669f94..a8b70ef 100644
+--- a/drivers/net/sfc/tx.c
++++ b/drivers/net/sfc/tx.c
+@@ -821,8 +821,6 @@ static void efx_enqueue_unwind(struct efx_tx_queue *tx_queue)
+ EFX_TXQ_MASK];
+ efx_tsoh_free(tx_queue, buffer);
+ EFX_BUG_ON_PARANOID(buffer->skb);
+- buffer->len = 0;
+- buffer->continuation = true;
+ if (buffer->unmap_len) {
+ unmap_addr = (buffer->dma_addr + buffer->len -
+ buffer->unmap_len);
+@@ -836,6 +834,8 @@ static void efx_enqueue_unwind(struct efx_tx_queue *tx_queue)
+ PCI_DMA_TODEVICE);
+ buffer->unmap_len = 0;
+ }
++ buffer->len = 0;
++ buffer->continuation = true;
+ }
+ }
+
+--
+1.6.5.7
+
Added: dists/trunk/linux-2.6/debian/patches/bugfix/all/sfc-Include-XGXS-in-XMAC-link-status-check.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/trunk/linux-2.6/debian/patches/bugfix/all/sfc-Include-XGXS-in-XMAC-link-status-check.patch Thu Jan 7 19:21:53 2010 (r14897)
@@ -0,0 +1,121 @@
+From a355020af415947c7dee7e00a91360d11b6a9b47 Mon Sep 17 00:00:00 2001
+From: Ben Hutchings <bhutchings at solarflare.com>
+Date: Wed, 23 Dec 2009 13:46:47 +0000
+Subject: [PATCH 2/8] sfc: Include XGXS in XMAC link status check except in XGMII loopback
+
+The XGXS block may not get a link immediately in XGXS or XAUI loopback
+modes, so we still need to check it. Split falcon_xaui_link_ok() into
+falcon_xgxs_link_ok(), which checks only the Falcon XGXS block, and
+falcon_xmac_link_ok(), which checks one or both sides of the link as
+appropriate. Also rename falcon_check_xaui_link() to
+falcon_xmac_link_ok_retry().
+
+Signed-off-by: Ben Hutchings <bhutchings at solarflare.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+---
+ drivers/net/sfc/falcon_xmac.c | 38 ++++++++++++++++++++++----------------
+ 1 files changed, 22 insertions(+), 16 deletions(-)
+
+diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c
+index 3da933f..8ccab2c 100644
+--- a/drivers/net/sfc/falcon_xmac.c
++++ b/drivers/net/sfc/falcon_xmac.c
+@@ -111,16 +111,12 @@ static void falcon_mask_status_intr(struct efx_nic *efx, bool enable)
+ efx_writeo(efx, ®, FR_AB_XM_MGT_INT_MASK);
+ }
+
+-/* Get status of XAUI link */
+-static bool falcon_xaui_link_ok(struct efx_nic *efx)
++static bool falcon_xgxs_link_ok(struct efx_nic *efx)
+ {
+ efx_oword_t reg;
+ bool align_done, link_ok = false;
+ int sync_status;
+
+- if (LOOPBACK_INTERNAL(efx))
+- return true;
+-
+ /* Read link status */
+ efx_reado(efx, ®, FR_AB_XX_CORE_STAT);
+
+@@ -135,14 +131,24 @@ static bool falcon_xaui_link_ok(struct efx_nic *efx)
+ 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_state.up && link_ok)
+- if (efx->mdio.mmds & (1 << MDIO_MMD_PHYXS))
+- link_ok = efx_mdio_phyxgxs_lane_sync(efx);
+-
+ return link_ok;
+ }
+
++static bool falcon_xmac_link_ok(struct efx_nic *efx)
++{
++ /*
++ * Check MAC's XGXS link status except when using XGMII loopback
++ * which bypasses the XGXS block.
++ * If possible, check PHY's XGXS link status except when using
++ * MAC loopback.
++ */
++ return (efx->loopback_mode == LOOPBACK_XGMII ||
++ falcon_xgxs_link_ok(efx)) &&
++ (!(efx->mdio.mmds & (1 << MDIO_MMD_PHYXS)) ||
++ LOOPBACK_INTERNAL(efx) ||
++ efx_mdio_phyxgxs_lane_sync(efx));
++}
++
+ void falcon_reconfigure_xmac_core(struct efx_nic *efx)
+ {
+ unsigned int max_frame_len;
+@@ -245,9 +251,9 @@ static void falcon_reconfigure_xgxs_core(struct efx_nic *efx)
+
+
+ /* 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)
++static bool falcon_xmac_link_ok_retry(struct efx_nic *efx, int tries)
+ {
+- bool mac_up = falcon_xaui_link_ok(efx);
++ bool mac_up = falcon_xmac_link_ok(efx);
+
+ if (LOOPBACK_MASK(efx) & LOOPBACKS_EXTERNAL(efx) & LOOPBACKS_WS ||
+ efx_phy_mode_disabled(efx->phy_mode))
+@@ -261,7 +267,7 @@ static bool falcon_check_xaui_link_up(struct efx_nic *efx, int tries)
+ falcon_reset_xaui(efx);
+ udelay(200);
+
+- mac_up = falcon_xaui_link_ok(efx);
++ mac_up = falcon_xmac_link_ok(efx);
+ --tries;
+ }
+
+@@ -272,7 +278,7 @@ static bool falcon_check_xaui_link_up(struct efx_nic *efx, int tries)
+
+ static bool falcon_xmac_check_fault(struct efx_nic *efx)
+ {
+- return !falcon_check_xaui_link_up(efx, 5);
++ return !falcon_xmac_link_ok_retry(efx, 5);
+ }
+
+ static int falcon_reconfigure_xmac(struct efx_nic *efx)
+@@ -284,7 +290,7 @@ static int falcon_reconfigure_xmac(struct efx_nic *efx)
+
+ falcon_reconfigure_mac_wrapper(efx);
+
+- efx->xmac_poll_required = !falcon_check_xaui_link_up(efx, 5);
++ efx->xmac_poll_required = !falcon_xmac_link_ok_retry(efx, 5);
+ falcon_mask_status_intr(efx, true);
+
+ return 0;
+@@ -357,7 +363,7 @@ void falcon_poll_xmac(struct efx_nic *efx)
+ return;
+
+ falcon_mask_status_intr(efx, false);
+- efx->xmac_poll_required = !falcon_check_xaui_link_up(efx, 1);
++ efx->xmac_poll_required = !falcon_xmac_link_ok_retry(efx, 1);
+ falcon_mask_status_intr(efx, true);
+ }
+
+--
+1.6.5.7
+
Added: dists/trunk/linux-2.6/debian/patches/bugfix/all/sfc-Move-PHY-software-state-initialisation.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/trunk/linux-2.6/debian/patches/bugfix/all/sfc-Move-PHY-software-state-initialisation.patch Thu Jan 7 19:21:53 2010 (r14897)
@@ -0,0 +1,510 @@
+From ff3b00a0fcaab89ff885e9f0f4ad83c4ced788f4 Mon Sep 17 00:00:00 2001
+From: Steve Hodgson <shodgson at solarflare.com>
+Date: Wed, 23 Dec 2009 13:46:36 +0000
+Subject: [PATCH 1/8] sfc: Move PHY software state initialisation from init() into probe()
+
+This prevents efx->link_advertising from being blatted during
+a reset.
+
+The phy_short_reach sysfs node is now destroyed later in the
+port shutdown process, so check for STATE_RUNNING after
+acquiring the rtnl_lock (just like in set_phy_flash_cfg).
+
+Signed-off-by: Ben Hutchings <bhutchings at solarflare.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+---
+ drivers/net/sfc/efx.c | 6 +-
+ drivers/net/sfc/falcon.c | 1 +
+ drivers/net/sfc/mcdi_phy.c | 93 +++++++++++------------------
+ drivers/net/sfc/net_driver.h | 1 +
+ drivers/net/sfc/qt202x_phy.c | 20 +++---
+ drivers/net/sfc/siena.c | 1 +
+ drivers/net/sfc/tenxpress.c | 138 +++++++++++++++++++++++------------------
+ 7 files changed, 129 insertions(+), 131 deletions(-)
+
+diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
+index f983e3b..103e8b0 100644
+--- a/drivers/net/sfc/efx.c
++++ b/drivers/net/sfc/efx.c
+@@ -741,14 +741,14 @@ static int efx_probe_port(struct efx_nic *efx)
+
+ EFX_LOG(efx, "create port\n");
+
++ if (phy_flash_cfg)
++ efx->phy_mode = PHY_MODE_SPECIAL;
++
+ /* Connect up MAC/PHY operations table */
+ rc = efx->type->probe_port(efx);
+ if (rc)
+ goto err;
+
+- if (phy_flash_cfg)
+- efx->phy_mode = PHY_MODE_SPECIAL;
+-
+ /* Sanity check MAC address */
+ if (is_valid_ether_addr(efx->mac_address)) {
+ memcpy(efx->net_dev->dev_addr, efx->mac_address, ETH_ALEN);
+diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
+index 17afcd2..9d009c4 100644
+--- a/drivers/net/sfc/falcon.c
++++ b/drivers/net/sfc/falcon.c
+@@ -925,6 +925,7 @@ static int falcon_probe_port(struct efx_nic *efx)
+
+ static void falcon_remove_port(struct efx_nic *efx)
+ {
++ efx->phy_op->remove(efx);
+ efx_nic_free_buffer(efx, &efx->stats_buffer);
+ }
+
+diff --git a/drivers/net/sfc/mcdi_phy.c b/drivers/net/sfc/mcdi_phy.c
+index 0e1bcc5..eb694af 100644
+--- a/drivers/net/sfc/mcdi_phy.c
++++ b/drivers/net/sfc/mcdi_phy.c
+@@ -304,31 +304,47 @@ static u32 mcdi_to_ethtool_media(u32 media)
+
+ static int efx_mcdi_phy_probe(struct efx_nic *efx)
+ {
+- struct efx_mcdi_phy_cfg *phy_cfg;
++ struct efx_mcdi_phy_cfg *phy_data;
++ u8 outbuf[MC_CMD_GET_LINK_OUT_LEN];
++ u32 caps;
+ int rc;
+
+- /* TODO: Move phy_data initialisation to
+- * phy_op->probe/remove, rather than init/fini */
+- phy_cfg = kzalloc(sizeof(*phy_cfg), GFP_KERNEL);
+- if (phy_cfg == NULL) {
+- rc = -ENOMEM;
+- goto fail_alloc;
+- }
+- rc = efx_mcdi_get_phy_cfg(efx, phy_cfg);
++ /* Initialise and populate phy_data */
++ phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL);
++ if (phy_data == NULL)
++ return -ENOMEM;
++
++ rc = efx_mcdi_get_phy_cfg(efx, phy_data);
+ if (rc != 0)
+ goto fail;
+
+- efx->phy_type = phy_cfg->type;
++ /* Read initial link advertisement */
++ BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0);
++ rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0,
++ outbuf, sizeof(outbuf), NULL);
++ if (rc)
++ goto fail;
++
++ /* Fill out nic state */
++ efx->phy_data = phy_data;
++ efx->phy_type = phy_data->type;
+
+- efx->mdio_bus = phy_cfg->channel;
+- efx->mdio.prtad = phy_cfg->port;
+- efx->mdio.mmds = phy_cfg->mmd_mask & ~(1 << MC_CMD_MMD_CLAUSE22);
++ efx->mdio_bus = phy_data->channel;
++ efx->mdio.prtad = phy_data->port;
++ efx->mdio.mmds = phy_data->mmd_mask & ~(1 << MC_CMD_MMD_CLAUSE22);
+ efx->mdio.mode_support = 0;
+- if (phy_cfg->mmd_mask & (1 << MC_CMD_MMD_CLAUSE22))
++ if (phy_data->mmd_mask & (1 << MC_CMD_MMD_CLAUSE22))
+ efx->mdio.mode_support |= MDIO_SUPPORTS_C22;
+- if (phy_cfg->mmd_mask & ~(1 << MC_CMD_MMD_CLAUSE22))
++ if (phy_data->mmd_mask & ~(1 << MC_CMD_MMD_CLAUSE22))
+ efx->mdio.mode_support |= MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22;
+
++ caps = MCDI_DWORD(outbuf, GET_LINK_OUT_CAP);
++ if (caps & (1 << MC_CMD_PHY_CAP_AN_LBN))
++ efx->link_advertising =
++ mcdi_to_ethtool_cap(phy_data->media, caps);
++ else
++ phy_data->forced_cap = caps;
++
+ /* Assert that we can map efx -> mcdi loopback modes */
+ BUILD_BUG_ON(LOOPBACK_NONE != MC_CMD_LOOPBACK_NONE);
+ BUILD_BUG_ON(LOOPBACK_DATA != MC_CMD_LOOPBACK_DATA);
+@@ -365,46 +381,6 @@ static int efx_mcdi_phy_probe(struct efx_nic *efx)
+ * but by convention we don't */
+ efx->loopback_modes &= ~(1 << LOOPBACK_NONE);
+
+- kfree(phy_cfg);
+-
+- return 0;
+-
+-fail:
+- kfree(phy_cfg);
+-fail_alloc:
+- return rc;
+-}
+-
+-static int efx_mcdi_phy_init(struct efx_nic *efx)
+-{
+- struct efx_mcdi_phy_cfg *phy_data;
+- u8 outbuf[MC_CMD_GET_LINK_OUT_LEN];
+- u32 caps;
+- int rc;
+-
+- phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL);
+- if (phy_data == NULL)
+- return -ENOMEM;
+-
+- rc = efx_mcdi_get_phy_cfg(efx, phy_data);
+- if (rc != 0)
+- goto fail;
+-
+- efx->phy_data = phy_data;
+-
+- BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0);
+- rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0,
+- outbuf, sizeof(outbuf), NULL);
+- if (rc)
+- goto fail;
+-
+- caps = MCDI_DWORD(outbuf, GET_LINK_OUT_CAP);
+- if (caps & (1 << MC_CMD_PHY_CAP_AN_LBN))
+- efx->link_advertising =
+- mcdi_to_ethtool_cap(phy_data->media, caps);
+- else
+- phy_data->forced_cap = caps;
+-
+ return 0;
+
+ fail:
+@@ -504,7 +480,7 @@ static bool efx_mcdi_phy_poll(struct efx_nic *efx)
+ return !efx_link_state_equal(&efx->link_state, &old_state);
+ }
+
+-static void efx_mcdi_phy_fini(struct efx_nic *efx)
++static void efx_mcdi_phy_remove(struct efx_nic *efx)
+ {
+ struct efx_mcdi_phy_data *phy_data = efx->phy_data;
+
+@@ -586,10 +562,11 @@ static int efx_mcdi_phy_set_settings(struct efx_nic *efx, struct ethtool_cmd *ec
+
+ struct efx_phy_operations efx_mcdi_phy_ops = {
+ .probe = efx_mcdi_phy_probe,
+- .init = efx_mcdi_phy_init,
++ .init = efx_port_dummy_op_int,
+ .reconfigure = efx_mcdi_phy_reconfigure,
+ .poll = efx_mcdi_phy_poll,
+- .fini = efx_mcdi_phy_fini,
++ .fini = efx_port_dummy_op_void,
++ .remove = efx_mcdi_phy_remove,
+ .get_settings = efx_mcdi_phy_get_settings,
+ .set_settings = efx_mcdi_phy_set_settings,
+ .run_tests = NULL,
+diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
+index 34c381f..d5aab5b 100644
+--- a/drivers/net/sfc/net_driver.h
++++ b/drivers/net/sfc/net_driver.h
+@@ -524,6 +524,7 @@ struct efx_phy_operations {
+ int (*probe) (struct efx_nic *efx);
+ int (*init) (struct efx_nic *efx);
+ void (*fini) (struct efx_nic *efx);
++ void (*remove) (struct efx_nic *efx);
+ int (*reconfigure) (struct efx_nic *efx);
+ bool (*poll) (struct efx_nic *efx);
+ void (*get_settings) (struct efx_nic *efx,
+diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c
+index 3800fc7..7450e3a 100644
+--- a/drivers/net/sfc/qt202x_phy.c
++++ b/drivers/net/sfc/qt202x_phy.c
+@@ -137,6 +137,14 @@ static int qt202x_reset_phy(struct efx_nic *efx)
+
+ static int qt202x_phy_probe(struct efx_nic *efx)
+ {
++ struct qt202x_phy_data *phy_data;
++
++ phy_data = kzalloc(sizeof(struct qt202x_phy_data), GFP_KERNEL);
++ if (!phy_data)
++ return -ENOMEM;
++ efx->phy_data = phy_data;
++ phy_data->phy_mode = efx->phy_mode;
++
+ efx->mdio.mmds = QT202X_REQUIRED_DEVS;
+ efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22;
+ efx->loopback_modes = QT202X_LOOPBACKS | FALCON_XMAC_LOOPBACKS;
+@@ -145,7 +153,6 @@ static int qt202x_phy_probe(struct efx_nic *efx)
+
+ static int qt202x_phy_init(struct efx_nic *efx)
+ {
+- struct qt202x_phy_data *phy_data;
+ u32 devid;
+ int rc;
+
+@@ -155,17 +162,11 @@ static int qt202x_phy_init(struct efx_nic *efx)
+ return rc;
+ }
+
+- phy_data = kzalloc(sizeof(struct qt202x_phy_data), GFP_KERNEL);
+- if (!phy_data)
+- return -ENOMEM;
+- efx->phy_data = phy_data;
+-
+ devid = efx_mdio_read_id(efx, MDIO_MMD_PHYXS);
+ EFX_INFO(efx, "PHY ID reg %x (OUI %06x model %02x revision %x)\n",
+ devid, efx_mdio_id_oui(devid), efx_mdio_id_model(devid),
+ efx_mdio_id_rev(devid));
+
+- phy_data->phy_mode = efx->phy_mode;
+ return 0;
+ }
+
+@@ -224,7 +225,7 @@ static void qt202x_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecm
+ mdio45_ethtool_gset(&efx->mdio, ecmd);
+ }
+
+-static void qt202x_phy_fini(struct efx_nic *efx)
++static void qt202x_phy_remove(struct efx_nic *efx)
+ {
+ /* Free the context block */
+ kfree(efx->phy_data);
+@@ -236,7 +237,8 @@ struct efx_phy_operations falcon_qt202x_phy_ops = {
+ .init = qt202x_phy_init,
+ .reconfigure = qt202x_phy_reconfigure,
+ .poll = qt202x_phy_poll,
+- .fini = qt202x_phy_fini,
++ .fini = efx_port_dummy_op_void,
++ .remove = qt202x_phy_remove,
+ .get_settings = qt202x_phy_get_settings,
+ .set_settings = efx_mdio_set_settings,
+ };
+diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c
+index de07a4f..f8c6771 100644
+--- a/drivers/net/sfc/siena.c
++++ b/drivers/net/sfc/siena.c
+@@ -133,6 +133,7 @@ static int siena_probe_port(struct efx_nic *efx)
+
+ void siena_remove_port(struct efx_nic *efx)
+ {
++ efx->phy_op->remove(efx);
+ efx_nic_free_buffer(efx, &efx->stats_buffer);
+ }
+
+diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c
+index ca11572..3009c29 100644
+--- a/drivers/net/sfc/tenxpress.c
++++ b/drivers/net/sfc/tenxpress.c
+@@ -202,10 +202,14 @@ static ssize_t set_phy_short_reach(struct device *dev,
+ int rc;
+
+ rtnl_lock();
+- efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, MDIO_PMA_10GBT_TXPWR,
+- MDIO_PMA_10GBT_TXPWR_SHORT,
+- count != 0 && *buf != '0');
+- rc = efx_reconfigure_port(efx);
++ if (efx->state != STATE_RUNNING) {
++ rc = -EBUSY;
++ } else {
++ efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, MDIO_PMA_10GBT_TXPWR,
++ MDIO_PMA_10GBT_TXPWR_SHORT,
++ count != 0 && *buf != '0');
++ rc = efx_reconfigure_port(efx);
++ }
+ rtnl_unlock();
+
+ return rc < 0 ? rc : (ssize_t)count;
+@@ -298,36 +302,62 @@ static int tenxpress_init(struct efx_nic *efx)
+ return 0;
+ }
+
+-static int sfx7101_phy_probe(struct efx_nic *efx)
++static int tenxpress_phy_probe(struct efx_nic *efx)
+ {
+- efx->mdio.mmds = TENXPRESS_REQUIRED_DEVS;
+- efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22;
+- efx->loopback_modes = SFX7101_LOOPBACKS | FALCON_XMAC_LOOPBACKS;
+- return 0;
+-}
++ struct tenxpress_phy_data *phy_data;
++ int rc;
++
++ /* Allocate phy private storage */
++ phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL);
++ if (!phy_data)
++ return -ENOMEM;
++ efx->phy_data = phy_data;
++ phy_data->phy_mode = efx->phy_mode;
++
++ /* Create any special files */
++ if (efx->phy_type == PHY_TYPE_SFT9001B) {
++ rc = device_create_file(&efx->pci_dev->dev,
++ &dev_attr_phy_short_reach);
++ if (rc)
++ goto fail;
++ }
++
++ if (efx->phy_type == PHY_TYPE_SFX7101) {
++ efx->mdio.mmds = TENXPRESS_REQUIRED_DEVS;
++ efx->mdio.mode_support = MDIO_SUPPORTS_C45;
++
++ efx->loopback_modes = SFX7101_LOOPBACKS | FALCON_XMAC_LOOPBACKS;
++
++ efx->link_advertising = (ADVERTISED_TP | ADVERTISED_Autoneg |
++ ADVERTISED_10000baseT_Full);
++ } else {
++ efx->mdio.mmds = TENXPRESS_REQUIRED_DEVS;
++ efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22;
++
++ efx->loopback_modes = (SFT9001_LOOPBACKS |
++ FALCON_XMAC_LOOPBACKS |
++ FALCON_GMAC_LOOPBACKS);
++
++ efx->link_advertising = (ADVERTISED_TP | ADVERTISED_Autoneg |
++ ADVERTISED_10000baseT_Full |
++ ADVERTISED_1000baseT_Full |
++ ADVERTISED_100baseT_Full);
++ }
+
+-static int sft9001_phy_probe(struct efx_nic *efx)
+-{
+- efx->mdio.mmds = TENXPRESS_REQUIRED_DEVS;
+- efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22;
+- efx->loopback_modes = (SFT9001_LOOPBACKS | FALCON_XMAC_LOOPBACKS |
+- FALCON_GMAC_LOOPBACKS);
+ return 0;
++
++fail:
++ kfree(efx->phy_data);
++ efx->phy_data = NULL;
++ return rc;
+ }
+
+ static int tenxpress_phy_init(struct efx_nic *efx)
+ {
+- struct tenxpress_phy_data *phy_data;
+- int rc = 0;
++ int rc;
+
+ falcon_board(efx)->type->init_phy(efx);
+
+- phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL);
+- if (!phy_data)
+- return -ENOMEM;
+- efx->phy_data = phy_data;
+- phy_data->phy_mode = efx->phy_mode;
+-
+ if (!(efx->phy_mode & PHY_MODE_SPECIAL)) {
+ if (efx->phy_type == PHY_TYPE_SFT9001A) {
+ int reg;
+@@ -341,44 +371,27 @@ static int tenxpress_phy_init(struct efx_nic *efx)
+
+ rc = efx_mdio_wait_reset_mmds(efx, TENXPRESS_REQUIRED_DEVS);
+ if (rc < 0)
+- goto fail;
++ return rc;
+
+ rc = efx_mdio_check_mmds(efx, TENXPRESS_REQUIRED_DEVS, 0);
+ if (rc < 0)
+- goto fail;
++ return rc;
+ }
+
+ rc = tenxpress_init(efx);
+ if (rc < 0)
+- goto fail;
++ return rc;
+
+- /* Initialise advertising flags */
+- efx->link_advertising = (ADVERTISED_TP | ADVERTISED_Autoneg |
+- ADVERTISED_10000baseT_Full);
+- if (efx->phy_type != PHY_TYPE_SFX7101)
+- efx->link_advertising |= (ADVERTISED_1000baseT_Full |
+- ADVERTISED_100baseT_Full);
++ /* Reinitialise flow control settings */
+ efx_link_set_wanted_fc(efx, efx->wanted_fc);
+ efx_mdio_an_reconfigure(efx);
+
+- if (efx->phy_type == PHY_TYPE_SFT9001B) {
+- rc = device_create_file(&efx->pci_dev->dev,
+- &dev_attr_phy_short_reach);
+- if (rc)
+- goto fail;
+- }
+-
+ schedule_timeout_uninterruptible(HZ / 5); /* 200ms */
+
+ /* Let XGXS and SerDes out of reset */
+ falcon_reset_xaui(efx);
+
+ return 0;
+-
+- fail:
+- kfree(efx->phy_data);
+- efx->phy_data = NULL;
+- return rc;
+ }
+
+ /* Perform a "special software reset" on the PHY. The caller is
+@@ -589,25 +602,26 @@ static bool tenxpress_phy_poll(struct efx_nic *efx)
+ return !efx_link_state_equal(&efx->link_state, &old_state);
+ }
+
+-static void tenxpress_phy_fini(struct efx_nic *efx)
++static void sfx7101_phy_fini(struct efx_nic *efx)
+ {
+ int reg;
+
++ /* Power down the LNPGA */
++ reg = (1 << PMA_PMD_LNPGA_POWERDOWN_LBN);
++ efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG, reg);
++
++ /* Waiting here ensures that the board fini, which can turn
++ * off the power to the PHY, won't get run until the LNPGA
++ * powerdown has been given long enough to complete. */
++ schedule_timeout_uninterruptible(LNPGA_PDOWN_WAIT); /* 200 ms */
++}
++
++static void tenxpress_phy_remove(struct efx_nic *efx)
++{
+ if (efx->phy_type == PHY_TYPE_SFT9001B)
+ device_remove_file(&efx->pci_dev->dev,
+ &dev_attr_phy_short_reach);
+
+- if (efx->phy_type == PHY_TYPE_SFX7101) {
+- /* Power down the LNPGA */
+- reg = (1 << PMA_PMD_LNPGA_POWERDOWN_LBN);
+- efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG, reg);
+-
+- /* Waiting here ensures that the board fini, which can turn
+- * off the power to the PHY, won't get run until the LNPGA
+- * powerdown has been given long enough to complete. */
+- schedule_timeout_uninterruptible(LNPGA_PDOWN_WAIT); /* 200 ms */
+- }
+-
+ kfree(efx->phy_data);
+ efx->phy_data = NULL;
+ }
+@@ -819,11 +833,12 @@ static void sft9001_set_npage_adv(struct efx_nic *efx, u32 advertising)
+ }
+
+ struct efx_phy_operations falcon_sfx7101_phy_ops = {
+- .probe = sfx7101_phy_probe,
++ .probe = tenxpress_phy_probe,
+ .init = tenxpress_phy_init,
+ .reconfigure = tenxpress_phy_reconfigure,
+ .poll = tenxpress_phy_poll,
+- .fini = tenxpress_phy_fini,
++ .fini = sfx7101_phy_fini,
++ .remove = tenxpress_phy_remove,
+ .get_settings = tenxpress_get_settings,
+ .set_settings = tenxpress_set_settings,
+ .set_npage_adv = sfx7101_set_npage_adv,
+@@ -832,11 +847,12 @@ struct efx_phy_operations falcon_sfx7101_phy_ops = {
+ };
+
+ struct efx_phy_operations falcon_sft9001_phy_ops = {
+- .probe = sft9001_phy_probe,
++ .probe = tenxpress_phy_probe,
+ .init = tenxpress_phy_init,
+ .reconfigure = tenxpress_phy_reconfigure,
+ .poll = tenxpress_phy_poll,
+- .fini = tenxpress_phy_fini,
++ .fini = efx_port_dummy_op_void,
++ .remove = tenxpress_phy_remove,
+ .get_settings = tenxpress_get_settings,
+ .set_settings = tenxpress_set_settings,
+ .set_npage_adv = sft9001_set_npage_adv,
+--
+1.6.5.7
+
Added: dists/trunk/linux-2.6/debian/patches/bugfix/all/sfc-QT2025C-Add-error-message-for-suspected-bad-SFP-cable.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/trunk/linux-2.6/debian/patches/bugfix/all/sfc-QT2025C-Add-error-message-for-suspected-bad-SFP-cable.patch Thu Jan 7 19:21:53 2010 (r14897)
@@ -0,0 +1,37 @@
+From 50d6ec552bdd4d9227fe9ed2bac819eced3170ac Mon Sep 17 00:00:00 2001
+From: Ben Hutchings <bhutchings at solarflare.com>
+Date: Wed, 23 Dec 2009 13:48:42 +0000
+Subject: [PATCH 7/8] sfc: QT2025C: Add error message for suspected bad SFP+ cables
+
+Some cables have EEPROMs that conflict with the PHY's on-board EEPROM
+so it cannot load firmware.
+
+Signed-off-by: Ben Hutchings <bhutchings at solarflare.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+---
+ drivers/net/sfc/qt202x_phy.c | 8 +++++++-
+ 1 files changed, 7 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c
+index 326ffa4..ff8f0a4 100644
+--- a/drivers/net/sfc/qt202x_phy.c
++++ b/drivers/net/sfc/qt202x_phy.c
+@@ -87,8 +87,14 @@ static int qt2025c_wait_heartbeat(struct efx_nic *efx)
+ old_counter = counter;
+ else if (counter != old_counter)
+ break;
+- if (time_after(jiffies, timeout))
++ if (time_after(jiffies, timeout)) {
++ /* Some cables have EEPROMs that conflict with the
++ * PHY's on-board EEPROM so it cannot load firmware */
++ EFX_ERR(efx, "If an SFP+ direct attach cable is"
++ " connected, please check that it complies"
++ " with the SFP+ specification\n");
+ return -ETIMEDOUT;
++ }
+ msleep(QT2025C_HEARTB_WAIT);
+ }
+
+--
+1.6.5.7
+
Added: dists/trunk/linux-2.6/debian/patches/bugfix/all/sfc-QT2025C-Switch-into-self-configure-mode.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/trunk/linux-2.6/debian/patches/bugfix/all/sfc-QT2025C-Switch-into-self-configure-mode.patch Thu Jan 7 19:21:53 2010 (r14897)
@@ -0,0 +1,185 @@
+From 0d83b2f64c330ee3892cb3117ac5d56e97185ecf Mon Sep 17 00:00:00 2001
+From: Matthew Slattery <mslattery at solarflare.com>
+Date: Wed, 23 Dec 2009 13:48:04 +0000
+Subject: [PATCH 5/8] sfc: QT2025C: Switch into self-configure mode when not in loopback
+
+The PHY boots in a mode which is not necessarily optimal. This change
+switches it to self-configure mode (except when in loopback, which
+won't work in that mode if an SFP+ module is not present) by rebooting
+the PHY's microcontroller, and replicating the sequence of configuration
+writes from the boot EEPROM with the appropriate changes.
+
+Signed-off-by: Ben Hutchings <bhutchings at solarflare.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+---
+ drivers/net/sfc/qt202x_phy.c | 119 ++++++++++++++++++++++++++++++++++++++++++
+ 1 files changed, 119 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c
+index e4590fb..0cd6eed 100644
+--- a/drivers/net/sfc/qt202x_phy.c
++++ b/drivers/net/sfc/qt202x_phy.c
+@@ -33,6 +33,9 @@
+ #define PCS_FW_HEARTBEAT_REG 0xd7ee
+ #define PCS_FW_HEARTB_LBN 0
+ #define PCS_FW_HEARTB_WIDTH 8
++#define PCS_FW_PRODUCT_CODE_1 0xd7f0
++#define PCS_FW_VERSION_1 0xd7f3
++#define PCS_FW_BUILD_1 0xd7f6
+ #define PCS_UC8051_STATUS_REG 0xd7fd
+ #define PCS_UC_STATUS_LBN 0
+ #define PCS_UC_STATUS_WIDTH 8
+@@ -54,6 +57,7 @@ struct qt202x_phy_data {
+ enum efx_phy_mode phy_mode;
+ bool bug17190_in_bad_state;
+ unsigned long bug17190_timer;
++ u32 firmware_ver;
+ };
+
+ #define QT2022C2_MAX_RESET_TIME 500
+@@ -100,6 +104,25 @@ static int qt2025c_wait_reset(struct efx_nic *efx)
+ return 0;
+ }
+
++static void qt2025c_firmware_id(struct efx_nic *efx)
++{
++ struct qt202x_phy_data *phy_data = efx->phy_data;
++ u8 firmware_id[9];
++ size_t i;
++
++ for (i = 0; i < sizeof(firmware_id); i++)
++ firmware_id[i] = efx_mdio_read(efx, MDIO_MMD_PCS,
++ PCS_FW_PRODUCT_CODE_1 + i);
++ EFX_INFO(efx, "QT2025C firmware %xr%d v%d.%d.%d.%d [20%02d-%02d-%02d]\n",
++ (firmware_id[0] << 8) | firmware_id[1], firmware_id[2],
++ firmware_id[3] >> 4, firmware_id[3] & 0xf,
++ firmware_id[4], firmware_id[5],
++ firmware_id[6], firmware_id[7], firmware_id[8]);
++ phy_data->firmware_ver = ((firmware_id[3] & 0xf0) << 20) |
++ ((firmware_id[3] & 0x0f) << 16) |
++ (firmware_id[4] << 8) | firmware_id[5];
++}
++
+ static void qt2025c_bug17190_workaround(struct efx_nic *efx)
+ {
+ struct qt202x_phy_data *phy_data = efx->phy_data;
+@@ -133,6 +156,95 @@ static void qt2025c_bug17190_workaround(struct efx_nic *efx)
+ }
+ }
+
++static int qt2025c_select_phy_mode(struct efx_nic *efx)
++{
++ struct qt202x_phy_data *phy_data = efx->phy_data;
++ struct falcon_board *board = falcon_board(efx);
++ int reg, rc, i;
++ uint16_t phy_op_mode;
++
++ /* Only 2.0.1.0+ PHY firmware supports the more optimal SFP+
++ * Self-Configure mode. Don't attempt any switching if we encounter
++ * older firmware. */
++ if (phy_data->firmware_ver < 0x02000100)
++ return 0;
++
++ /* In general we will get optimal behaviour in "SFP+ Self-Configure"
++ * mode; however, that powers down most of the PHY when no module is
++ * present, so we must use a different mode (any fixed mode will do)
++ * to be sure that loopbacks will work. */
++ phy_op_mode = (efx->loopback_mode == LOOPBACK_NONE) ? 0x0038 : 0x0020;
++
++ /* Only change mode if really necessary */
++ reg = efx_mdio_read(efx, 1, 0xc319);
++ if ((reg & 0x0038) == phy_op_mode)
++ return 0;
++ EFX_LOG(efx, "Switching PHY to mode 0x%04x\n", phy_op_mode);
++
++ /* This sequence replicates the register writes configured in the boot
++ * EEPROM (including the differences between board revisions), except
++ * that the operating mode is changed, and the PHY is prevented from
++ * unnecessarily reloading the main firmware image again. */
++ efx_mdio_write(efx, 1, 0xc300, 0x0000);
++ /* (Note: this portion of the boot EEPROM sequence, which bit-bashes 9
++ * STOPs onto the firmware/module I2C bus to reset it, varies across
++ * board revisions, as the bus is connected to different GPIO/LED
++ * outputs on the PHY.) */
++ if (board->major == 0 && board->minor < 2) {
++ efx_mdio_write(efx, 1, 0xc303, 0x4498);
++ for (i = 0; i < 9; i++) {
++ efx_mdio_write(efx, 1, 0xc303, 0x4488);
++ efx_mdio_write(efx, 1, 0xc303, 0x4480);
++ efx_mdio_write(efx, 1, 0xc303, 0x4490);
++ efx_mdio_write(efx, 1, 0xc303, 0x4498);
++ }
++ } else {
++ efx_mdio_write(efx, 1, 0xc303, 0x0920);
++ efx_mdio_write(efx, 1, 0xd008, 0x0004);
++ for (i = 0; i < 9; i++) {
++ efx_mdio_write(efx, 1, 0xc303, 0x0900);
++ efx_mdio_write(efx, 1, 0xd008, 0x0005);
++ efx_mdio_write(efx, 1, 0xc303, 0x0920);
++ efx_mdio_write(efx, 1, 0xd008, 0x0004);
++ }
++ efx_mdio_write(efx, 1, 0xc303, 0x4900);
++ }
++ efx_mdio_write(efx, 1, 0xc303, 0x4900);
++ efx_mdio_write(efx, 1, 0xc302, 0x0004);
++ efx_mdio_write(efx, 1, 0xc316, 0x0013);
++ efx_mdio_write(efx, 1, 0xc318, 0x0054);
++ efx_mdio_write(efx, 1, 0xc319, phy_op_mode);
++ efx_mdio_write(efx, 1, 0xc31a, 0x0098);
++ efx_mdio_write(efx, 3, 0x0026, 0x0e00);
++ efx_mdio_write(efx, 3, 0x0027, 0x0013);
++ efx_mdio_write(efx, 3, 0x0028, 0xa528);
++ efx_mdio_write(efx, 1, 0xd006, 0x000a);
++ efx_mdio_write(efx, 1, 0xd007, 0x0009);
++ efx_mdio_write(efx, 1, 0xd008, 0x0004);
++ /* This additional write is not present in the boot EEPROM. It
++ * prevents the PHY's internal boot ROM doing another pointless (and
++ * slow) reload of the firmware image (the microcontroller's code
++ * memory is not affected by the microcontroller reset). */
++ efx_mdio_write(efx, 1, 0xc317, 0x00ff);
++ efx_mdio_write(efx, 1, 0xc300, 0x0002);
++ msleep(20);
++
++ /* Restart microcontroller execution from RAM */
++ efx_mdio_write(efx, 3, 0xe854, 0x00c0);
++ efx_mdio_write(efx, 3, 0xe854, 0x0040);
++ msleep(50);
++
++ /* Wait for the microcontroller to be ready again */
++ rc = qt2025c_wait_reset(efx);
++ if (rc < 0) {
++ EFX_ERR(efx, "PHY microcontroller reset during mode switch "
++ "timed out\n");
++ return rc;
++ }
++
++ return 0;
++}
++
+ static int qt202x_reset_phy(struct efx_nic *efx)
+ {
+ int rc;
+@@ -206,6 +318,9 @@ static int qt202x_phy_init(struct efx_nic *efx)
+ devid, efx_mdio_id_oui(devid), efx_mdio_id_model(devid),
+ efx_mdio_id_rev(devid));
+
++ if (efx->phy_type == PHY_TYPE_QT2025C)
++ qt2025c_firmware_id(efx);
++
+ return 0;
+ }
+
+@@ -234,6 +349,10 @@ static int qt202x_phy_reconfigure(struct efx_nic *efx)
+ struct qt202x_phy_data *phy_data = efx->phy_data;
+
+ if (efx->phy_type == PHY_TYPE_QT2025C) {
++ int rc = qt2025c_select_phy_mode(efx);
++ if (rc)
++ return rc;
++
+ /* There are several different register bits which can
+ * disable TX (and save power) on direct-attach cables
+ * or optical transceivers, varying somewhat between
+--
+1.6.5.7
+
Added: dists/trunk/linux-2.6/debian/patches/bugfix/all/sfc-QT2025C-Work-around-PHY-bug.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/trunk/linux-2.6/debian/patches/bugfix/all/sfc-QT2025C-Work-around-PHY-bug.patch Thu Jan 7 19:21:53 2010 (r14897)
@@ -0,0 +1,97 @@
+From 17d6aeafe9d8268612d91edc0102659edb382282 Mon Sep 17 00:00:00 2001
+From: Matthew Slattery <mslattery at solarflare.com>
+Date: Wed, 23 Dec 2009 13:47:37 +0000
+Subject: [PATCH 4/8] sfc: QT2025C: Work around PHY bug
+
+If we see the PHY remaining stuck in a link-down state due to PCS being
+down while PMA/PMD is up, we briefly switch to PMA/PMD loopback and back,
+which usually unsticks it.
+
+Signed-off-by: Ben Hutchings <bhutchings at solarflare.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+---
+ drivers/net/sfc/qt202x_phy.c | 42 ++++++++++++++++++++++++++++++++++++++++++
+ 1 files changed, 42 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c
+index 7450e3a..e4590fb 100644
+--- a/drivers/net/sfc/qt202x_phy.c
++++ b/drivers/net/sfc/qt202x_phy.c
+@@ -52,11 +52,15 @@ void falcon_qt202x_set_led(struct efx_nic *p, int led, int mode)
+
+ struct qt202x_phy_data {
+ enum efx_phy_mode phy_mode;
++ bool bug17190_in_bad_state;
++ unsigned long bug17190_timer;
+ };
+
+ #define QT2022C2_MAX_RESET_TIME 500
+ #define QT2022C2_RESET_WAIT 10
+
++#define BUG17190_INTERVAL (2 * HZ)
++
+ static int qt2025c_wait_reset(struct efx_nic *efx)
+ {
+ unsigned long timeout = jiffies + 10 * HZ;
+@@ -96,6 +100,39 @@ static int qt2025c_wait_reset(struct efx_nic *efx)
+ return 0;
+ }
+
++static void qt2025c_bug17190_workaround(struct efx_nic *efx)
++{
++ struct qt202x_phy_data *phy_data = efx->phy_data;
++
++ /* The PHY can get stuck in a state where it reports PHY_XS and PMA/PMD
++ * layers up, but PCS down (no block_lock). If we notice this state
++ * persisting for a couple of seconds, we switch PMA/PMD loopback
++ * briefly on and then off again, which is normally sufficient to
++ * recover it.
++ */
++ if (efx->link_state.up ||
++ !efx_mdio_links_ok(efx, MDIO_DEVS_PMAPMD | MDIO_DEVS_PHYXS)) {
++ phy_data->bug17190_in_bad_state = false;
++ return;
++ }
++
++ if (!phy_data->bug17190_in_bad_state) {
++ phy_data->bug17190_in_bad_state = true;
++ phy_data->bug17190_timer = jiffies + BUG17190_INTERVAL;
++ return;
++ }
++
++ if (time_after_eq(jiffies, phy_data->bug17190_timer)) {
++ EFX_LOG(efx, "bashing QT2025C PMA/PMD\n");
++ efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, MDIO_CTRL1,
++ MDIO_PMA_CTRL1_LOOPBACK, true);
++ msleep(100);
++ efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, MDIO_CTRL1,
++ MDIO_PMA_CTRL1_LOOPBACK, false);
++ phy_data->bug17190_timer = jiffies + BUG17190_INTERVAL;
++ }
++}
++
+ static int qt202x_reset_phy(struct efx_nic *efx)
+ {
+ int rc;
+@@ -144,6 +181,8 @@ static int qt202x_phy_probe(struct efx_nic *efx)
+ return -ENOMEM;
+ efx->phy_data = phy_data;
+ phy_data->phy_mode = efx->phy_mode;
++ phy_data->bug17190_in_bad_state = false;
++ phy_data->bug17190_timer = 0;
+
+ efx->mdio.mmds = QT202X_REQUIRED_DEVS;
+ efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22;
+@@ -184,6 +223,9 @@ static bool qt202x_phy_poll(struct efx_nic *efx)
+ efx->link_state.fd = true;
+ efx->link_state.fc = efx->wanted_fc;
+
++ if (efx->phy_type == PHY_TYPE_QT2025C)
++ qt2025c_bug17190_workaround(efx);
++
+ return efx->link_state.up != was_up;
+ }
+
+--
+1.6.5.7
+
Added: dists/trunk/linux-2.6/debian/patches/bugfix/all/sfc-QT2025C-Work-around-PHY-firmware-initialisation.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/trunk/linux-2.6/debian/patches/bugfix/all/sfc-QT2025C-Work-around-PHY-firmware-initialisation.patch Thu Jan 7 19:21:53 2010 (r14897)
@@ -0,0 +1,119 @@
+From 1a1284ef97ca79ba747d211b697e996a248a8555 Mon Sep 17 00:00:00 2001
+From: Matthew Slattery <mslattery at solarflare.com>
+Date: Wed, 23 Dec 2009 13:48:32 +0000
+Subject: [PATCH 6/8] sfc: QT2025C: Work around PHY firmware initialisation bug
+
+The PHY's firmware very occasionally appears to lock up very early, but
+with the heartbeat update still running. Rebooting the microcontroller
+core seems to be sufficient to recover.
+
+Signed-off-by: Ben Hutchings <bhutchings at solarflare.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+---
+ drivers/net/sfc/qt202x_phy.c | 59 ++++++++++++++++++++++++++++++++++++-----
+ 1 files changed, 51 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c
+index 0cd6eed..326ffa4 100644
+--- a/drivers/net/sfc/qt202x_phy.c
++++ b/drivers/net/sfc/qt202x_phy.c
+@@ -63,11 +63,16 @@ struct qt202x_phy_data {
+ #define QT2022C2_MAX_RESET_TIME 500
+ #define QT2022C2_RESET_WAIT 10
+
++#define QT2025C_MAX_HEARTB_TIME (5 * HZ)
++#define QT2025C_HEARTB_WAIT 100
++#define QT2025C_MAX_FWSTART_TIME (25 * HZ / 10)
++#define QT2025C_FWSTART_WAIT 100
++
+ #define BUG17190_INTERVAL (2 * HZ)
+
+-static int qt2025c_wait_reset(struct efx_nic *efx)
++static int qt2025c_wait_heartbeat(struct efx_nic *efx)
+ {
+- unsigned long timeout = jiffies + 10 * HZ;
++ unsigned long timeout = jiffies + QT2025C_MAX_HEARTB_TIME;
+ int reg, old_counter = 0;
+
+ /* Wait for firmware heartbeat to start */
+@@ -84,9 +89,17 @@ static int qt2025c_wait_reset(struct efx_nic *efx)
+ break;
+ if (time_after(jiffies, timeout))
+ return -ETIMEDOUT;
+- msleep(10);
++ msleep(QT2025C_HEARTB_WAIT);
+ }
+
++ return 0;
++}
++
++static int qt2025c_wait_fw_status_good(struct efx_nic *efx)
++{
++ unsigned long timeout = jiffies + QT2025C_MAX_FWSTART_TIME;
++ int reg;
++
+ /* Wait for firmware status to look good */
+ for (;;) {
+ reg = efx_mdio_read(efx, MDIO_MMD_PCS, PCS_UC8051_STATUS_REG);
+@@ -98,12 +111,44 @@ static int qt2025c_wait_reset(struct efx_nic *efx)
+ break;
+ if (time_after(jiffies, timeout))
+ return -ETIMEDOUT;
+- msleep(100);
++ msleep(QT2025C_FWSTART_WAIT);
+ }
+
+ return 0;
+ }
+
++static void qt2025c_restart_firmware(struct efx_nic *efx)
++{
++ /* Restart microcontroller execution of firmware from RAM */
++ efx_mdio_write(efx, 3, 0xe854, 0x00c0);
++ efx_mdio_write(efx, 3, 0xe854, 0x0040);
++ msleep(50);
++}
++
++static int qt2025c_wait_reset(struct efx_nic *efx)
++{
++ int rc;
++
++ rc = qt2025c_wait_heartbeat(efx);
++ if (rc != 0)
++ return rc;
++
++ rc = qt2025c_wait_fw_status_good(efx);
++ if (rc == -ETIMEDOUT) {
++ /* Bug 17689: occasionally heartbeat starts but firmware status
++ * code never progresses beyond 0x00. Try again, once, after
++ * restarting execution of the firmware image. */
++ EFX_LOG(efx, "bashing QT2025C microcontroller\n");
++ qt2025c_restart_firmware(efx);
++ rc = qt2025c_wait_heartbeat(efx);
++ if (rc != 0)
++ return rc;
++ rc = qt2025c_wait_fw_status_good(efx);
++ }
++
++ return rc;
++}
++
+ static void qt2025c_firmware_id(struct efx_nic *efx)
+ {
+ struct qt202x_phy_data *phy_data = efx->phy_data;
+@@ -229,10 +274,8 @@ static int qt2025c_select_phy_mode(struct efx_nic *efx)
+ efx_mdio_write(efx, 1, 0xc300, 0x0002);
+ msleep(20);
+
+- /* Restart microcontroller execution from RAM */
+- efx_mdio_write(efx, 3, 0xe854, 0x00c0);
+- efx_mdio_write(efx, 3, 0xe854, 0x0040);
+- msleep(50);
++ /* Restart microcontroller execution of firmware from RAM */
++ qt2025c_restart_firmware(efx);
+
+ /* Wait for the microcontroller to be ready again */
+ rc = qt2025c_wait_reset(efx);
+--
+1.6.5.7
+
Added: dists/trunk/linux-2.6/debian/patches/series/5
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/trunk/linux-2.6/debian/patches/series/5 Thu Jan 7 19:21:53 2010 (r14897)
@@ -0,0 +1,8 @@
++ bugfix/all/sfc-Move-PHY-software-state-initialisation.patch
++ bugfix/all/sfc-Include-XGXS-in-XMAC-link-status-check.patch
++ bugfix/all/sfc-Fix-DMA-mapping-cleanup-on-error-in-TSO.patch
++ bugfix/all/sfc-QT2025C-Work-around-PHY-bug.patch
++ bugfix/all/sfc-QT2025C-Switch-into-self-configure-mode.patch
++ bugfix/all/sfc-QT2025C-Work-around-PHY-firmware-initialisation.patch
++ bugfix/all/sfc-QT2025C-Add-error-message-for-suspected-bad-SFP-cable.patch
++ bugfix/all/sfc-Disable-TX-descriptor-prefetch-watchdog.patch
More information about the Kernel-svn-changes
mailing list