be2net: bug fix for flashing the BladeEngine3 ASIC

Now flashing both BE2 and BE3 devices is supported.

From: Naresh G <nareshg@serverengines.com>
Signed-off-by: Ajit Khaparde <ajitk@serverengines.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c
index 0779f6b..9906148 100644
--- a/drivers/net/benet/be_main.c
+++ b/drivers/net/benet/be_main.c
@@ -1798,15 +1798,19 @@
 				"H DIRECTORY *** "};
 
 static bool be_flash_redboot(struct be_adapter *adapter,
-			const u8 *p)
+			const u8 *p, u32 img_start, int image_size,
+			int hdr_size)
 {
 	u32 crc_offset;
 	u8 flashed_crc[4];
 	int status;
-	crc_offset = FLASH_REDBOOT_START + FLASH_REDBOOT_IMAGE_MAX_SIZE - 4
-			+ sizeof(struct flash_file_hdr) - 32*1024;
+
+	crc_offset = hdr_size + img_start + image_size - 4;
+
 	p += crc_offset;
-	status = be_cmd_get_flash_crc(adapter, flashed_crc);
+
+	status = be_cmd_get_flash_crc(adapter, flashed_crc,
+			(img_start + image_size - 4));
 	if (status) {
 		dev_err(&adapter->pdev->dev,
 		"could not get crc from flash, not flashing redboot\n");
@@ -1818,102 +1822,124 @@
 		return false;
 	else
 		return true;
-
 }
 
-static int be_flash_image(struct be_adapter *adapter,
+static int be_flash_data(struct be_adapter *adapter,
 			const struct firmware *fw,
-			struct be_dma_mem *flash_cmd, u32 flash_type)
+			struct be_dma_mem *flash_cmd, int num_of_images)
+
 {
-	int status;
-	u32 flash_op, image_offset = 0, total_bytes, image_size = 0;
+	int status = 0, i, filehdr_size = 0;
+	u32 total_bytes = 0, flash_op;
 	int num_bytes;
 	const u8 *p = fw->data;
 	struct be_cmd_write_flashrom *req = flash_cmd->va;
+	struct flash_comp *pflashcomp;
 
-	switch (flash_type) {
-	case FLASHROM_TYPE_ISCSI_ACTIVE:
-		image_offset = FLASH_iSCSI_PRIMARY_IMAGE_START;
-		image_size = FLASH_IMAGE_MAX_SIZE;
-		break;
-	case FLASHROM_TYPE_ISCSI_BACKUP:
-		image_offset = FLASH_iSCSI_BACKUP_IMAGE_START;
-		image_size = FLASH_IMAGE_MAX_SIZE;
-		break;
-	case FLASHROM_TYPE_FCOE_FW_ACTIVE:
-		image_offset = FLASH_FCoE_PRIMARY_IMAGE_START;
-		image_size = FLASH_IMAGE_MAX_SIZE;
-		break;
-	case FLASHROM_TYPE_FCOE_FW_BACKUP:
-		image_offset = FLASH_FCoE_BACKUP_IMAGE_START;
-		image_size = FLASH_IMAGE_MAX_SIZE;
-		break;
-	case FLASHROM_TYPE_BIOS:
-		image_offset = FLASH_iSCSI_BIOS_START;
-		image_size = FLASH_BIOS_IMAGE_MAX_SIZE;
-		break;
-	case FLASHROM_TYPE_FCOE_BIOS:
-		image_offset = FLASH_FCoE_BIOS_START;
-		image_size = FLASH_BIOS_IMAGE_MAX_SIZE;
-		break;
-	case FLASHROM_TYPE_PXE_BIOS:
-		image_offset = FLASH_PXE_BIOS_START;
-		image_size = FLASH_BIOS_IMAGE_MAX_SIZE;
-		break;
-	case FLASHROM_TYPE_REDBOOT:
-		if (!be_flash_redboot(adapter, fw->data))
-			return 0;
-		image_offset = FLASH_REDBOOT_ISM_START;
-		image_size = FLASH_REDBOOT_IMAGE_MAX_SIZE;
-		break;
-	default:
-		return 0;
+	struct flash_comp gen3_flash_types[8] = {
+		{ FLASH_iSCSI_PRIMARY_IMAGE_START_g3, IMG_TYPE_ISCSI_ACTIVE,
+			FLASH_IMAGE_MAX_SIZE_g3},
+		{ FLASH_REDBOOT_START_g3, IMG_TYPE_REDBOOT,
+			FLASH_REDBOOT_IMAGE_MAX_SIZE_g3},
+		{ FLASH_iSCSI_BIOS_START_g3, IMG_TYPE_BIOS,
+			FLASH_BIOS_IMAGE_MAX_SIZE_g3},
+		{ FLASH_PXE_BIOS_START_g3, IMG_TYPE_PXE_BIOS,
+			FLASH_BIOS_IMAGE_MAX_SIZE_g3},
+		{ FLASH_FCoE_BIOS_START_g3, IMG_TYPE_FCOE_BIOS,
+			FLASH_BIOS_IMAGE_MAX_SIZE_g3},
+		{ FLASH_iSCSI_BACKUP_IMAGE_START_g3, IMG_TYPE_ISCSI_BACKUP,
+			FLASH_IMAGE_MAX_SIZE_g3},
+		{ FLASH_FCoE_PRIMARY_IMAGE_START_g3, IMG_TYPE_FCOE_FW_ACTIVE,
+			FLASH_IMAGE_MAX_SIZE_g3},
+		{ FLASH_FCoE_BACKUP_IMAGE_START_g3, IMG_TYPE_FCOE_FW_BACKUP,
+			FLASH_IMAGE_MAX_SIZE_g3}
+	};
+	struct flash_comp gen2_flash_types[8] = {
+		{ FLASH_iSCSI_PRIMARY_IMAGE_START_g2, IMG_TYPE_ISCSI_ACTIVE,
+			FLASH_IMAGE_MAX_SIZE_g2},
+		{ FLASH_REDBOOT_START_g2, IMG_TYPE_REDBOOT,
+			FLASH_REDBOOT_IMAGE_MAX_SIZE_g2},
+		{ FLASH_iSCSI_BIOS_START_g2, IMG_TYPE_BIOS,
+			FLASH_BIOS_IMAGE_MAX_SIZE_g2},
+		{ FLASH_PXE_BIOS_START_g2, IMG_TYPE_PXE_BIOS,
+			FLASH_BIOS_IMAGE_MAX_SIZE_g2},
+		{ FLASH_FCoE_BIOS_START_g2, IMG_TYPE_FCOE_BIOS,
+			FLASH_BIOS_IMAGE_MAX_SIZE_g2},
+		{ FLASH_iSCSI_BACKUP_IMAGE_START_g2, IMG_TYPE_ISCSI_BACKUP,
+			FLASH_IMAGE_MAX_SIZE_g2},
+		{ FLASH_FCoE_PRIMARY_IMAGE_START_g2, IMG_TYPE_FCOE_FW_ACTIVE,
+			FLASH_IMAGE_MAX_SIZE_g2},
+		{ FLASH_FCoE_BACKUP_IMAGE_START_g2, IMG_TYPE_FCOE_FW_BACKUP,
+			 FLASH_IMAGE_MAX_SIZE_g2}
+	};
+
+	if (adapter->generation == BE_GEN3) {
+		pflashcomp = gen3_flash_types;
+		filehdr_size = sizeof(struct flash_file_hdr_g3);
+	} else {
+		pflashcomp = gen2_flash_types;
+		filehdr_size = sizeof(struct flash_file_hdr_g2);
 	}
-
-	p += sizeof(struct flash_file_hdr) + image_offset;
-	if (p + image_size > fw->data + fw->size)
+	for (i = 0; i < 8; i++) {
+		if ((pflashcomp[i].optype == IMG_TYPE_REDBOOT) &&
+			(!be_flash_redboot(adapter, fw->data,
+			 pflashcomp[i].offset, pflashcomp[i].size,
+			 filehdr_size)))
+			continue;
+		p = fw->data;
+		p += filehdr_size + pflashcomp[i].offset
+			+ (num_of_images * sizeof(struct image_hdr));
+	if (p + pflashcomp[i].size > fw->data + fw->size)
 		return -1;
+	total_bytes = pflashcomp[i].size;
+		while (total_bytes) {
+			if (total_bytes > 32*1024)
+				num_bytes = 32*1024;
+			else
+				num_bytes = total_bytes;
+			total_bytes -= num_bytes;
 
-	total_bytes = image_size;
-
-	while (total_bytes) {
-		if (total_bytes > 32*1024)
-			num_bytes = 32*1024;
-		else
-			num_bytes = total_bytes;
-		total_bytes -= num_bytes;
-
-		if (!total_bytes)
-			flash_op = FLASHROM_OPER_FLASH;
-		else
-			flash_op = FLASHROM_OPER_SAVE;
-		memcpy(req->params.data_buf, p, num_bytes);
-		p += num_bytes;
-		status = be_cmd_write_flashrom(adapter, flash_cmd,
-				flash_type, flash_op, num_bytes);
-		if (status) {
-			dev_err(&adapter->pdev->dev,
-			"cmd to write to flash rom failed. type/op %d/%d\n",
-			flash_type, flash_op);
-			return -1;
+			if (!total_bytes)
+				flash_op = FLASHROM_OPER_FLASH;
+			else
+				flash_op = FLASHROM_OPER_SAVE;
+			memcpy(req->params.data_buf, p, num_bytes);
+			p += num_bytes;
+			status = be_cmd_write_flashrom(adapter, flash_cmd,
+				pflashcomp[i].optype, flash_op, num_bytes);
+			if (status) {
+				dev_err(&adapter->pdev->dev,
+					"cmd to write to flash rom failed.\n");
+				return -1;
+			}
+			yield();
 		}
-		yield();
 	}
-
 	return 0;
 }
 
+static int get_ufigen_type(struct flash_file_hdr_g2 *fhdr)
+{
+	if (fhdr == NULL)
+		return 0;
+	if (fhdr->build[0] == '3')
+		return BE_GEN3;
+	else if (fhdr->build[0] == '2')
+		return BE_GEN2;
+	else
+		return 0;
+}
+
 int be_load_fw(struct be_adapter *adapter, u8 *func)
 {
 	char fw_file[ETHTOOL_FLASH_MAX_FILENAME];
 	const struct firmware *fw;
-	struct flash_file_hdr *fhdr;
-	struct flash_section_info *fsec = NULL;
+	struct flash_file_hdr_g2 *fhdr;
+	struct flash_file_hdr_g3 *fhdr3;
+	struct image_hdr *img_hdr_ptr = NULL;
 	struct be_dma_mem flash_cmd;
-	int status;
+	int status, i = 0;
 	const u8 *p;
-	bool entry_found = false;
-	int flash_type;
 	char fw_ver[FW_VER_LEN];
 	char fw_cfg;
 
@@ -1931,34 +1957,9 @@
 		goto fw_exit;
 
 	p = fw->data;
-	fhdr = (struct flash_file_hdr *) p;
-	if (memcmp(fhdr->sign, FW_FILE_HDR_SIGN, strlen(FW_FILE_HDR_SIGN))) {
-		dev_err(&adapter->pdev->dev,
-			"Firmware(%s) load error (signature did not match)\n",
-				fw_file);
-		status = -1;
-		goto fw_exit;
-	}
-
+	fhdr = (struct flash_file_hdr_g2 *) p;
 	dev_info(&adapter->pdev->dev, "Flashing firmware file %s\n", fw_file);
 
-	p += sizeof(struct flash_file_hdr);
-	while (p < (fw->data + fw->size)) {
-		fsec = (struct flash_section_info *)p;
-		if (!memcmp(flash_cookie, fsec->cookie, sizeof(flash_cookie))) {
-			entry_found = true;
-			break;
-		}
-		p += 32;
-	}
-
-	if (!entry_found) {
-		status = -1;
-		dev_err(&adapter->pdev->dev,
-			"Flash cookie not found in firmware image\n");
-		goto fw_exit;
-	}
-
 	flash_cmd.size = sizeof(struct be_cmd_write_flashrom) + 32*1024;
 	flash_cmd.va = pci_alloc_consistent(adapter->pdev, flash_cmd.size,
 					&flash_cmd.dma);
@@ -1969,12 +1970,26 @@
 		goto fw_exit;
 	}
 
-	for (flash_type = FLASHROM_TYPE_ISCSI_ACTIVE;
-		flash_type <= FLASHROM_TYPE_FCOE_FW_BACKUP; flash_type++) {
-		status = be_flash_image(adapter, fw, &flash_cmd,
-				flash_type);
-		if (status)
-			break;
+	if ((adapter->generation == BE_GEN3) &&
+			(get_ufigen_type(fhdr) == BE_GEN3)) {
+		fhdr3 = (struct flash_file_hdr_g3 *) fw->data;
+		for (i = 0; i < fhdr3->num_imgs; i++) {
+			img_hdr_ptr = (struct image_hdr *) (fw->data +
+					(sizeof(struct flash_file_hdr_g3) +
+					i * sizeof(struct image_hdr)));
+			if (img_hdr_ptr->imageid == 1) {
+				status = be_flash_data(adapter, fw,
+						&flash_cmd, fhdr3->num_imgs);
+			}
+
+		}
+	} else if ((adapter->generation == BE_GEN2) &&
+			(get_ufigen_type(fhdr) == BE_GEN2)) {
+		status = be_flash_data(adapter, fw, &flash_cmd, 0);
+	} else {
+		dev_err(&adapter->pdev->dev,
+			"UFI and Interface are not compatible for flashing\n");
+		status = -1;
 	}
 
 	pci_free_consistent(adapter->pdev, flash_cmd.size, flash_cmd.va,