[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, &reg, 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, &reg, 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, &reg, 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