svn commit: r321390 - in head/sys/dev/cxgbe: . common

Navdeep Parhar np at FreeBSD.org
Sun Jul 23 18:10:48 UTC 2017


Author: np
Date: Sun Jul 23 18:10:47 2017
New Revision: 321390
URL: https://svnweb.freebsd.org/changeset/base/321390

Log:
  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

Modified:
  head/sys/dev/cxgbe/common/common.h
  head/sys/dev/cxgbe/common/t4_hw.c
  head/sys/dev/cxgbe/t4_main.c

Modified: head/sys/dev/cxgbe/common/common.h
==============================================================================
--- head/sys/dev/cxgbe/common/common.h	Sun Jul 23 18:00:11 2017	(r321389)
+++ head/sys/dev/cxgbe/common/common.h	Sun Jul 23 18:10:47 2017	(r321390)
@@ -693,6 +693,8 @@ int t4_fw_halt(struct adapter *adap, unsigned int mbox
 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,

Modified: head/sys/dev/cxgbe/common/t4_hw.c
==============================================================================
--- head/sys/dev/cxgbe/common/t4_hw.c	Sun Jul 23 18:00:11 2017	(r321389)
+++ head/sys/dev/cxgbe/common/t4_hw.c	Sun Jul 23 18:10:47 2017	(r321390)
@@ -6745,6 +6745,31 @@ int t4_fw_upgrade(struct adapter *adap, unsigned int m
 	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

Modified: head/sys/dev/cxgbe/t4_main.c
==============================================================================
--- head/sys/dev/cxgbe/t4_main.c	Sun Jul 23 18:00:11 2017	(r321389)
+++ head/sys/dev/cxgbe/t4_main.c	Sun Jul 23 18:10:47 2017	(r321390)
@@ -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,26 +3001,82 @@ prep_firmware(struct adapter *sc)
 	 */
 	default_cfg = firmware_get(fw_info->kld_name);
 
+	/* This is the firmware in the KLD */
+	fw = firmware_get(fw_info->fw_mod_name);
+	if (fw != NULL) {
+		kld_fw = (const void *)fw->data;
+		kld_fw_usable = fw_compatible(drv_fw, kld_fw);
+	} else {
+		kld_fw = NULL;
+		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)
+	if (rc == 0) {
 		card_fw_usable = fw_compatible(drv_fw, (const void*)card_fw);
-	else {
+		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;
 	}
 
-	/* This is the firmware in the KLD */
-	fw = firmware_get(fw_info->fw_mod_name);
-	if (fw != NULL) {
-		kld_fw = (const void *)fw->data;
-		kld_fw_usable = fw_compatible(drv_fw, kld_fw);
-	} else {
-		kld_fw = NULL;
-		kld_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 &&


More information about the svn-src-head mailing list