From 70824840b09935e8df8cc9123f1c09400e00b7b5 Mon Sep 17 00:00:00 2001 From: Ben Hutchings 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 . --- 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