214 lines
6.1 KiB
Diff
214 lines
6.1 KiB
Diff
From 70824840b09935e8df8cc9123f1c09400e00b7b5 Mon Sep 17 00:00:00 2001
|
|
From: Ben Hutchings <ben@decadent.org.uk>
|
|
Date: Thu, 9 Jul 2009 00:25:04 +0100
|
|
Subject: [PATCH 3/3] cxgb3: Use request_firmware() for EDC PHY code
|
|
|
|
Adapted from work by Divy Le Ray <divy@chelsio.com>.
|
|
---
|
|
drivers/net/Kconfig | 1 -
|
|
drivers/net/cxgb3/adapter.h | 2 +
|
|
drivers/net/cxgb3/ael1002.c | 40 +++++++++++++++++------
|
|
drivers/net/cxgb3/common.h | 10 ++++++
|
|
drivers/net/cxgb3/cxgb3_main.c | 69 ++++++++++++++++++++++++++++++++++++++++
|
|
5 files changed, 111 insertions(+), 11 deletions(-)
|
|
|
|
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
|
|
index 183479d..c155bd3 100644
|
|
--- a/drivers/net/Kconfig
|
|
+++ b/drivers/net/Kconfig
|
|
@@ -2511,7 +2511,6 @@ config CHELSIO_T3_DEPENDS
|
|
|
|
config CHELSIO_T3
|
|
tristate "Chelsio Communications T3 10Gb Ethernet support"
|
|
- depends on BROKEN
|
|
depends on CHELSIO_T3_DEPENDS
|
|
select FW_LOADER
|
|
select MDIO
|
|
diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h
|
|
index 1694fad..9241c88 100644
|
|
--- a/drivers/net/cxgb3/adapter.h
|
|
+++ b/drivers/net/cxgb3/adapter.h
|
|
@@ -312,4 +312,6 @@ int t3_get_desc(const struct sge_qset *qs, unsigned int qnum, unsigned int idx,
|
|
unsigned char *data);
|
|
irqreturn_t t3_sge_intr_msix(int irq, void *cookie);
|
|
|
|
+int t3_get_edc_fw(struct cphy *phy, int edc_idx, int size);
|
|
+
|
|
#endif /* __T3_ADAPTER_H__ */
|
|
diff --git a/drivers/net/cxgb3/ael1002.c b/drivers/net/cxgb3/ael1002.c
|
|
index 7b0d445..5a4ff80 100644
|
|
--- a/drivers/net/cxgb3/ael1002.c
|
|
+++ b/drivers/net/cxgb3/ael1002.c
|
|
@@ -312,9 +312,16 @@ static int ael2005_setup_sr_edc(struct cphy *phy)
|
|
|
|
msleep(50);
|
|
|
|
- for (i = 0; i < ARRAY_SIZE(sr_edc) && !err; i += 2)
|
|
- err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, sr_edc[i],
|
|
- sr_edc[i + 1]);
|
|
+ if (phy->priv != edc_sr)
|
|
+ err = t3_get_edc_fw(phy, EDC_OPT_AEL2005,
|
|
+ EDC_OPT_AEL2005_SIZE);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ for (i = 0; i < EDC_OPT_AEL2005_SIZE / sizeof(u16) && !err; i += 2)
|
|
+ err = t3_mdio_write(phy, MDIO_MMD_PMAPMD,
|
|
+ phy->phy_cache[i],
|
|
+ phy->phy_cache[i + 1]);
|
|
if (!err)
|
|
phy->priv = edc_sr;
|
|
return err;
|
|
@@ -341,9 +348,16 @@ static int ael2005_setup_twinax_edc(struct cphy *phy, int modtype)
|
|
|
|
msleep(50);
|
|
|
|
- for (i = 0; i < ARRAY_SIZE(twinax_edc) && !err; i += 2)
|
|
- err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, twinax_edc[i],
|
|
- twinax_edc[i + 1]);
|
|
+ if (phy->priv != edc_twinax)
|
|
+ err = t3_get_edc_fw(phy, EDC_TWX_AEL2005,
|
|
+ EDC_TWX_AEL2005_SIZE);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ for (i = 0; i < EDC_TWX_AEL2005_SIZE / sizeof(u16) && !err; i += 2)
|
|
+ err = t3_mdio_write(phy, MDIO_MMD_PMAPMD,
|
|
+ phy->phy_cache[i],
|
|
+ phy->phy_cache[i + 1]);
|
|
if (!err)
|
|
phy->priv = edc_twinax;
|
|
return err;
|
|
@@ -573,10 +587,16 @@ static int ael2020_setup_twinax_edc(struct cphy *phy, int modtype)
|
|
if (err)
|
|
return err;
|
|
|
|
- /* write TWINAX EDC firmware into PHY */
|
|
- for (i = 0; i < ARRAY_SIZE(twinax_edc) && !err; i += 2)
|
|
- err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, twinax_edc[i],
|
|
- twinax_edc[i + 1]);
|
|
+ if (phy->priv != edc_twinax)
|
|
+ err = t3_get_edc_fw(phy, EDC_TWX_AEL2020,
|
|
+ EDC_TWX_AEL2020_SIZE);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ for (i = 0; i < EDC_TWX_AEL2020_SIZE / sizeof(u16) && !err; i += 2)
|
|
+ err = t3_mdio_write(phy, MDIO_MMD_PMAPMD,
|
|
+ phy->phy_cache[i],
|
|
+ phy->phy_cache[i + 1]);
|
|
/* activate uC */
|
|
err = set_phy_regs(phy, uCactivate);
|
|
if (!err)
|
|
diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h
|
|
index d21b705..1b2c305 100644
|
|
--- a/drivers/net/cxgb3/common.h
|
|
+++ b/drivers/net/cxgb3/common.h
|
|
@@ -566,6 +566,15 @@ struct cphy_ops {
|
|
|
|
u32 mmds;
|
|
};
|
|
+enum {
|
|
+ EDC_OPT_AEL2005 = 0,
|
|
+ EDC_OPT_AEL2005_SIZE = 1084,
|
|
+ EDC_TWX_AEL2005 = 1,
|
|
+ EDC_TWX_AEL2005_SIZE = 1464,
|
|
+ EDC_TWX_AEL2020 = 2,
|
|
+ EDC_TWX_AEL2020_SIZE = 1628,
|
|
+ EDC_MAX_SIZE = EDC_TWX_AEL2020_SIZE, /* Max cache size */
|
|
+};
|
|
|
|
/* A PHY instance */
|
|
struct cphy {
|
|
@@ -577,6 +586,7 @@ struct cphy {
|
|
unsigned long fifo_errors; /* FIFO over/under-flows */
|
|
const struct cphy_ops *ops; /* PHY operations */
|
|
struct mdio_if_info mdio;
|
|
+ u16 phy_cache[EDC_MAX_SIZE]; /* EDC cache */
|
|
};
|
|
|
|
/* Convenience MDIO read/write wrappers */
|
|
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c
|
|
index 538dda4..27e7ef5 100644
|
|
--- a/drivers/net/cxgb3/cxgb3_main.c
|
|
+++ b/drivers/net/cxgb3/cxgb3_main.c
|
|
@@ -964,6 +964,75 @@ static int bind_qsets(struct adapter *adap)
|
|
|
|
#define FW_FNAME "cxgb3/t3fw-%d.%d.%d.bin"
|
|
#define TPSRAM_NAME "cxgb3/t3%c_psram-%d.%d.%d.bin"
|
|
+#define AEL2005_OPT_EDC_NAME "cxgb3/ael2005_opt_edc.bin"
|
|
+#define AEL2005_TWX_EDC_NAME "cxgb3/ael2005_twx_edc.bin"
|
|
+#define AEL2020_TWX_EDC_NAME "cxgb3/ael2020_twx_edc.bin"
|
|
+
|
|
+static inline const char *get_edc_fw_name(int edc_idx)
|
|
+{
|
|
+ const char *fw_name = NULL;
|
|
+
|
|
+ switch (edc_idx) {
|
|
+ case EDC_OPT_AEL2005:
|
|
+ fw_name = AEL2005_OPT_EDC_NAME;
|
|
+ break;
|
|
+ case EDC_TWX_AEL2005:
|
|
+ fw_name = AEL2005_TWX_EDC_NAME;
|
|
+ break;
|
|
+ case EDC_TWX_AEL2020:
|
|
+ fw_name = AEL2020_TWX_EDC_NAME;
|
|
+ break;
|
|
+ }
|
|
+ return fw_name;
|
|
+}
|
|
+
|
|
+int t3_get_edc_fw(struct cphy *phy, int edc_idx, int size)
|
|
+{
|
|
+ struct adapter *adapter = phy->adapter;
|
|
+ const struct firmware *fw;
|
|
+ char buf[64];
|
|
+ u32 csum;
|
|
+ const __be32 *p;
|
|
+ u16 *cache = phy->phy_cache;
|
|
+ int i, ret;
|
|
+
|
|
+ snprintf(buf, sizeof(buf), get_edc_fw_name(edc_idx));
|
|
+
|
|
+ ret = request_firmware(&fw, buf, &adapter->pdev->dev);
|
|
+ if (ret < 0) {
|
|
+ dev_err(&adapter->pdev->dev,
|
|
+ "could not upgrade firmware: unable to load %s\n",
|
|
+ buf);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ /* check size, take checksum in account */
|
|
+ if (fw->size > size + 4) {
|
|
+ CH_ERR(adapter, "firmware image too large %u, expected %d\n",
|
|
+ (unsigned int)fw->size, size + 4);
|
|
+ ret = -EINVAL;
|
|
+ }
|
|
+
|
|
+ /* compute checksum */
|
|
+ p = (const __be32 *)fw->data;
|
|
+ for (csum = 0, i = 0; i < fw->size / sizeof(csum); i++)
|
|
+ csum += ntohl(p[i]);
|
|
+
|
|
+ if (csum != 0xffffffff) {
|
|
+ CH_ERR(adapter, "corrupted firmware image, checksum %u\n",
|
|
+ csum);
|
|
+ ret = -EINVAL;
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < size / 4 ; i++) {
|
|
+ *cache++ = (be32_to_cpu(p[i]) & 0xffff0000) >> 16;
|
|
+ *cache++ = be32_to_cpu(p[i]) & 0xffff;
|
|
+ }
|
|
+
|
|
+ release_firmware(fw);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
|
|
static int upgrade_fw(struct adapter *adap)
|
|
{
|
|
--
|
|
1.6.3.3
|
|
|