From 98d227f3e81c2fdbd0369a080d3f7ca4b9cb0283 Mon Sep 17 00:00:00 2001 From: Navdeep Parhar Date: Sun, 23 Jul 2017 18:10:47 +0000 Subject: [PATCH] cxgbe(4): Install the firmware bundled with the driver to the card if it doesn't seem to have one. This lets the driver recover automatically from incomplete firmware upgrades (panic, reboot, power loss, etc. in the middle of an upgrade). MFC after: 2 weeks Sponsored by: Chelsio Communications --- sys/dev/cxgbe/common/common.h | 2 + sys/dev/cxgbe/common/t4_hw.c | 25 +++++++++ sys/dev/cxgbe/t4_main.c | 103 +++++++++++++++++++++++----------- 3 files changed, 96 insertions(+), 34 deletions(-) diff --git a/sys/dev/cxgbe/common/common.h b/sys/dev/cxgbe/common/common.h index c90e9956fed..292343ce4c8 100644 --- a/sys/dev/cxgbe/common/common.h +++ b/sys/dev/cxgbe/common/common.h @@ -693,6 +693,8 @@ int t4_fw_halt(struct adapter *adap, unsigned int mbox, int force); int t4_fw_restart(struct adapter *adap, unsigned int mbox, int reset); int t4_fw_upgrade(struct adapter *adap, unsigned int mbox, const u8 *fw_data, unsigned int size, int force); +int t4_fw_forceinstall(struct adapter *adap, const u8 *fw_data, + unsigned int size); int t4_fw_initialize(struct adapter *adap, unsigned int mbox); int t4_query_params(struct adapter *adap, unsigned int mbox, unsigned int pf, unsigned int vf, unsigned int nparams, const u32 *params, diff --git a/sys/dev/cxgbe/common/t4_hw.c b/sys/dev/cxgbe/common/t4_hw.c index 85ca854f6f5..e29f23b1606 100644 --- a/sys/dev/cxgbe/common/t4_hw.c +++ b/sys/dev/cxgbe/common/t4_hw.c @@ -6745,6 +6745,31 @@ int t4_fw_upgrade(struct adapter *adap, unsigned int mbox, return t4_fw_restart(adap, mbox, reset); } +/* + * Card doesn't have a firmware, install one. + */ +int t4_fw_forceinstall(struct adapter *adap, const u8 *fw_data, + unsigned int size) +{ + const struct fw_hdr *fw_hdr = (const struct fw_hdr *)fw_data; + unsigned int bootstrap = + be32_to_cpu(fw_hdr->magic) == FW_HDR_MAGIC_BOOTSTRAP; + int ret; + + if (!t4_fw_matches_chip(adap, fw_hdr) || bootstrap) + return -EINVAL; + + t4_set_reg_field(adap, A_CIM_BOOT_CFG, F_UPCRST, F_UPCRST); + t4_write_reg(adap, A_PCIE_FW, 0); /* Clobber internal state */ + ret = t4_load_fw(adap, fw_data, size); + if (ret < 0) + return ret; + t4_write_reg(adap, A_PL_RST, F_PIORST | F_PIORSTMODE); + msleep(1000); + + return (0); +} + /** * t4_fw_initialize - ask FW to initialize the device * @adap: the adapter diff --git a/sys/dev/cxgbe/t4_main.c b/sys/dev/cxgbe/t4_main.c index c0cec806893..919034bcc59 100644 --- a/sys/dev/cxgbe/t4_main.c +++ b/sys/dev/cxgbe/t4_main.c @@ -2968,6 +2968,7 @@ install: return (1); } + /* * Establish contact with the firmware and determine if we are the master driver * or not, and whether we are responsible for chip initialization. @@ -2984,28 +2985,6 @@ prep_firmware(struct adapter *sc) const struct fw_hdr *drv_fw; /* fw header the driver was compiled against */ - /* Contact firmware. */ - rc = t4_fw_hello(sc, sc->mbox, sc->mbox, MASTER_MAY, &state); - if (rc < 0 || state == DEV_STATE_ERR) { - rc = -rc; - device_printf(sc->dev, - "failed to connect to the firmware: %d, %d.\n", rc, state); - return (rc); - } - pf = rc; - if (pf == sc->mbox) - sc->flags |= MASTER_PF; - else if (state == DEV_STATE_UNINIT) { - /* - * We didn't get to be the master so we definitely won't be - * configuring the chip. It's a bug if someone else hasn't - * configured it already. - */ - device_printf(sc->dev, "couldn't be master(%d), " - "device not already initialized either(%d).\n", rc, state); - return (EDOOFUS); - } - /* This is the firmware whose headers the driver was compiled against */ fw_info = find_fw_info(chip_id(sc)); if (fw_info == NULL) { @@ -3022,18 +3001,6 @@ prep_firmware(struct adapter *sc) */ default_cfg = firmware_get(fw_info->kld_name); - /* Read the header of the firmware on the card */ - card_fw = malloc(sizeof(*card_fw), M_CXGBE, M_ZERO | M_WAITOK); - rc = -t4_read_flash(sc, FLASH_FW_START, - sizeof (*card_fw) / sizeof (uint32_t), (uint32_t *)card_fw, 1); - if (rc == 0) - card_fw_usable = fw_compatible(drv_fw, (const void*)card_fw); - else { - device_printf(sc->dev, - "Unable to read card's firmware header: %d\n", rc); - card_fw_usable = 0; - } - /* This is the firmware in the KLD */ fw = firmware_get(fw_info->fw_mod_name); if (fw != NULL) { @@ -3044,6 +3011,74 @@ prep_firmware(struct adapter *sc) kld_fw_usable = 0; } + /* Read the header of the firmware on the card */ + card_fw = malloc(sizeof(*card_fw), M_CXGBE, M_ZERO | M_WAITOK); + rc = -t4_read_flash(sc, FLASH_FW_START, + sizeof (*card_fw) / sizeof (uint32_t), (uint32_t *)card_fw, 1); + if (rc == 0) { + card_fw_usable = fw_compatible(drv_fw, (const void*)card_fw); + if (card_fw->fw_ver == be32toh(0xffffffff)) { + uint32_t d = be32toh(kld_fw->fw_ver); + + if (!kld_fw_usable) { + device_printf(sc->dev, + "no firmware on the card and no usable " + "firmware bundled with the driver.\n"); + rc = EIO; + goto done; + } else if (t4_fw_install == 0) { + device_printf(sc->dev, + "no firmware on the card and the driver " + "is prohibited from installing new " + "firmware.\n"); + rc = EIO; + goto done; + } + + device_printf(sc->dev, "no firmware on the card, " + "installing firmware %d.%d.%d.%d\n", + G_FW_HDR_FW_VER_MAJOR(d), G_FW_HDR_FW_VER_MINOR(d), + G_FW_HDR_FW_VER_MICRO(d), G_FW_HDR_FW_VER_BUILD(d)); + rc = t4_fw_forceinstall(sc, fw->data, fw->datasize); + if (rc < 0) { + rc = -rc; + device_printf(sc->dev, + "firmware install failed: %d.\n", rc); + goto done; + } + memcpy(card_fw, kld_fw, sizeof(*card_fw)); + card_fw_usable = 1; + need_fw_reset = 0; + } + } else { + device_printf(sc->dev, + "Unable to read card's firmware header: %d\n", rc); + card_fw_usable = 0; + } + + /* Contact firmware. */ + rc = t4_fw_hello(sc, sc->mbox, sc->mbox, MASTER_MAY, &state); + if (rc < 0 || state == DEV_STATE_ERR) { + rc = -rc; + device_printf(sc->dev, + "failed to connect to the firmware: %d, %d.\n", rc, state); + goto done; + } + pf = rc; + if (pf == sc->mbox) + sc->flags |= MASTER_PF; + else if (state == DEV_STATE_UNINIT) { + /* + * We didn't get to be the master so we definitely won't be + * configuring the chip. It's a bug if someone else hasn't + * configured it already. + */ + device_printf(sc->dev, "couldn't be master(%d), " + "device not already initialized either(%d).\n", rc, state); + rc = EPROTO; + goto done; + } + if (card_fw_usable && card_fw->fw_ver == drv_fw->fw_ver && (!kld_fw_usable || kld_fw->fw_ver == drv_fw->fw_ver)) { /*