diff options
author | Hariprasad Shenai <hariprasad@chelsio.com> | 2013-12-03 06:35:58 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-12-03 16:55:40 -0500 |
commit | 16e47624e76b43dbef5671af7b9e26589d7018b9 (patch) | |
tree | a96b387a9b7b592e65515d25d293fd52715cb18e | |
parent | 70ee366689bd6d81f7f25553fc81efddc07eb65b (diff) |
cxgb4: Add new scheme to update T4/T5 firmware
Signed-off-by: Hariprasad Shenai <hariprasad@chelsio.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 37 | ||||
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 242 | ||||
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 193 | ||||
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h | 7 |
4 files changed, 289 insertions, 190 deletions
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 9710a16a26e0..6c9308850453 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | |||
@@ -49,13 +49,15 @@ | |||
49 | #include <asm/io.h> | 49 | #include <asm/io.h> |
50 | #include "cxgb4_uld.h" | 50 | #include "cxgb4_uld.h" |
51 | 51 | ||
52 | #define FW_VERSION_MAJOR 1 | 52 | #define T4FW_VERSION_MAJOR 0x01 |
53 | #define FW_VERSION_MINOR 4 | 53 | #define T4FW_VERSION_MINOR 0x06 |
54 | #define FW_VERSION_MICRO 0 | 54 | #define T4FW_VERSION_MICRO 0x18 |
55 | #define T4FW_VERSION_BUILD 0x00 | ||
55 | 56 | ||
56 | #define FW_VERSION_MAJOR_T5 0 | 57 | #define T5FW_VERSION_MAJOR 0x01 |
57 | #define FW_VERSION_MINOR_T5 0 | 58 | #define T5FW_VERSION_MINOR 0x08 |
58 | #define FW_VERSION_MICRO_T5 0 | 59 | #define T5FW_VERSION_MICRO 0x1C |
60 | #define T5FW_VERSION_BUILD 0x00 | ||
59 | 61 | ||
60 | #define CH_WARN(adap, fmt, ...) dev_warn(adap->pdev_dev, fmt, ## __VA_ARGS__) | 62 | #define CH_WARN(adap, fmt, ...) dev_warn(adap->pdev_dev, fmt, ## __VA_ARGS__) |
61 | 63 | ||
@@ -287,6 +289,23 @@ struct adapter_params { | |||
287 | unsigned int ofldq_wr_cred; | 289 | unsigned int ofldq_wr_cred; |
288 | }; | 290 | }; |
289 | 291 | ||
292 | #include "t4fw_api.h" | ||
293 | |||
294 | #define FW_VERSION(chip) ( \ | ||
295 | FW_HDR_FW_VER_MAJOR_GET(chip##FW_VERSION_MAJOR) | \ | ||
296 | FW_HDR_FW_VER_MINOR_GET(chip##FW_VERSION_MINOR) | \ | ||
297 | FW_HDR_FW_VER_MICRO_GET(chip##FW_VERSION_MICRO) | \ | ||
298 | FW_HDR_FW_VER_BUILD_GET(chip##FW_VERSION_BUILD)) | ||
299 | #define FW_INTFVER(chip, intf) (FW_HDR_INTFVER_##intf) | ||
300 | |||
301 | struct fw_info { | ||
302 | u8 chip; | ||
303 | char *fs_name; | ||
304 | char *fw_mod_name; | ||
305 | struct fw_hdr fw_hdr; | ||
306 | }; | ||
307 | |||
308 | |||
290 | struct trace_params { | 309 | struct trace_params { |
291 | u32 data[TRACE_LEN / 4]; | 310 | u32 data[TRACE_LEN / 4]; |
292 | u32 mask[TRACE_LEN / 4]; | 311 | u32 mask[TRACE_LEN / 4]; |
@@ -901,7 +920,11 @@ int get_vpd_params(struct adapter *adapter, struct vpd_params *p); | |||
901 | int t4_load_fw(struct adapter *adapter, const u8 *fw_data, unsigned int size); | 920 | int t4_load_fw(struct adapter *adapter, const u8 *fw_data, unsigned int size); |
902 | unsigned int t4_flash_cfg_addr(struct adapter *adapter); | 921 | unsigned int t4_flash_cfg_addr(struct adapter *adapter); |
903 | int t4_load_cfg(struct adapter *adapter, const u8 *cfg_data, unsigned int size); | 922 | int t4_load_cfg(struct adapter *adapter, const u8 *cfg_data, unsigned int size); |
904 | int t4_check_fw_version(struct adapter *adapter); | 923 | int t4_get_fw_version(struct adapter *adapter, u32 *vers); |
924 | int t4_get_tp_version(struct adapter *adapter, u32 *vers); | ||
925 | int t4_prep_fw(struct adapter *adap, struct fw_info *fw_info, | ||
926 | const u8 *fw_data, unsigned int fw_size, | ||
927 | struct fw_hdr *card_fw, enum dev_state state, int *reset); | ||
905 | int t4_prep_adapter(struct adapter *adapter); | 928 | int t4_prep_adapter(struct adapter *adapter); |
906 | int t4_port_init(struct adapter *adap, int mbox, int pf, int vf); | 929 | int t4_port_init(struct adapter *adap, int mbox, int pf, int vf); |
907 | void t4_fatal_err(struct adapter *adapter); | 930 | void t4_fatal_err(struct adapter *adapter); |
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 35933cd18e0f..d6b12e035a7d 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | |||
@@ -276,9 +276,9 @@ static DEFINE_PCI_DEVICE_TABLE(cxgb4_pci_tbl) = { | |||
276 | { 0, } | 276 | { 0, } |
277 | }; | 277 | }; |
278 | 278 | ||
279 | #define FW_FNAME "cxgb4/t4fw.bin" | 279 | #define FW4_FNAME "cxgb4/t4fw.bin" |
280 | #define FW5_FNAME "cxgb4/t5fw.bin" | 280 | #define FW5_FNAME "cxgb4/t5fw.bin" |
281 | #define FW_CFNAME "cxgb4/t4-config.txt" | 281 | #define FW4_CFNAME "cxgb4/t4-config.txt" |
282 | #define FW5_CFNAME "cxgb4/t5-config.txt" | 282 | #define FW5_CFNAME "cxgb4/t5-config.txt" |
283 | 283 | ||
284 | MODULE_DESCRIPTION(DRV_DESC); | 284 | MODULE_DESCRIPTION(DRV_DESC); |
@@ -286,7 +286,7 @@ MODULE_AUTHOR("Chelsio Communications"); | |||
286 | MODULE_LICENSE("Dual BSD/GPL"); | 286 | MODULE_LICENSE("Dual BSD/GPL"); |
287 | MODULE_VERSION(DRV_VERSION); | 287 | MODULE_VERSION(DRV_VERSION); |
288 | MODULE_DEVICE_TABLE(pci, cxgb4_pci_tbl); | 288 | MODULE_DEVICE_TABLE(pci, cxgb4_pci_tbl); |
289 | MODULE_FIRMWARE(FW_FNAME); | 289 | MODULE_FIRMWARE(FW4_FNAME); |
290 | MODULE_FIRMWARE(FW5_FNAME); | 290 | MODULE_FIRMWARE(FW5_FNAME); |
291 | 291 | ||
292 | /* | 292 | /* |
@@ -1071,72 +1071,6 @@ freeout: t4_free_sge_resources(adap); | |||
1071 | } | 1071 | } |
1072 | 1072 | ||
1073 | /* | 1073 | /* |
1074 | * Returns 0 if new FW was successfully loaded, a positive errno if a load was | ||
1075 | * started but failed, and a negative errno if flash load couldn't start. | ||
1076 | */ | ||
1077 | static int upgrade_fw(struct adapter *adap) | ||
1078 | { | ||
1079 | int ret; | ||
1080 | u32 vers, exp_major; | ||
1081 | const struct fw_hdr *hdr; | ||
1082 | const struct firmware *fw; | ||
1083 | struct device *dev = adap->pdev_dev; | ||
1084 | char *fw_file_name; | ||
1085 | |||
1086 | switch (CHELSIO_CHIP_VERSION(adap->params.chip)) { | ||
1087 | case CHELSIO_T4: | ||
1088 | fw_file_name = FW_FNAME; | ||
1089 | exp_major = FW_VERSION_MAJOR; | ||
1090 | break; | ||
1091 | case CHELSIO_T5: | ||
1092 | fw_file_name = FW5_FNAME; | ||
1093 | exp_major = FW_VERSION_MAJOR_T5; | ||
1094 | break; | ||
1095 | default: | ||
1096 | dev_err(dev, "Unsupported chip type, %x\n", adap->params.chip); | ||
1097 | return -EINVAL; | ||
1098 | } | ||
1099 | |||
1100 | ret = request_firmware(&fw, fw_file_name, dev); | ||
1101 | if (ret < 0) { | ||
1102 | dev_err(dev, "unable to load firmware image %s, error %d\n", | ||
1103 | fw_file_name, ret); | ||
1104 | return ret; | ||
1105 | } | ||
1106 | |||
1107 | hdr = (const struct fw_hdr *)fw->data; | ||
1108 | vers = ntohl(hdr->fw_ver); | ||
1109 | if (FW_HDR_FW_VER_MAJOR_GET(vers) != exp_major) { | ||
1110 | ret = -EINVAL; /* wrong major version, won't do */ | ||
1111 | goto out; | ||
1112 | } | ||
1113 | |||
1114 | /* | ||
1115 | * If the flash FW is unusable or we found something newer, load it. | ||
1116 | */ | ||
1117 | if (FW_HDR_FW_VER_MAJOR_GET(adap->params.fw_vers) != exp_major || | ||
1118 | vers > adap->params.fw_vers) { | ||
1119 | dev_info(dev, "upgrading firmware ...\n"); | ||
1120 | ret = t4_fw_upgrade(adap, adap->mbox, fw->data, fw->size, | ||
1121 | /*force=*/false); | ||
1122 | if (!ret) | ||
1123 | dev_info(dev, | ||
1124 | "firmware upgraded to version %pI4 from %s\n", | ||
1125 | &hdr->fw_ver, fw_file_name); | ||
1126 | else | ||
1127 | dev_err(dev, "firmware upgrade failed! err=%d\n", -ret); | ||
1128 | } else { | ||
1129 | /* | ||
1130 | * Tell our caller that we didn't upgrade the firmware. | ||
1131 | */ | ||
1132 | ret = -EINVAL; | ||
1133 | } | ||
1134 | |||
1135 | out: release_firmware(fw); | ||
1136 | return ret; | ||
1137 | } | ||
1138 | |||
1139 | /* | ||
1140 | * Allocate a chunk of memory using kmalloc or, if that fails, vmalloc. | 1074 | * Allocate a chunk of memory using kmalloc or, if that fails, vmalloc. |
1141 | * The allocated memory is cleared. | 1075 | * The allocated memory is cleared. |
1142 | */ | 1076 | */ |
@@ -4668,8 +4602,10 @@ static int adap_init0_config(struct adapter *adapter, int reset) | |||
4668 | const struct firmware *cf; | 4602 | const struct firmware *cf; |
4669 | unsigned long mtype = 0, maddr = 0; | 4603 | unsigned long mtype = 0, maddr = 0; |
4670 | u32 finiver, finicsum, cfcsum; | 4604 | u32 finiver, finicsum, cfcsum; |
4671 | int ret, using_flash; | 4605 | int ret; |
4606 | int config_issued = 0; | ||
4672 | char *fw_config_file, fw_config_file_path[256]; | 4607 | char *fw_config_file, fw_config_file_path[256]; |
4608 | char *config_name = NULL; | ||
4673 | 4609 | ||
4674 | /* | 4610 | /* |
4675 | * Reset device if necessary. | 4611 | * Reset device if necessary. |
@@ -4688,7 +4624,7 @@ static int adap_init0_config(struct adapter *adapter, int reset) | |||
4688 | */ | 4624 | */ |
4689 | switch (CHELSIO_CHIP_VERSION(adapter->params.chip)) { | 4625 | switch (CHELSIO_CHIP_VERSION(adapter->params.chip)) { |
4690 | case CHELSIO_T4: | 4626 | case CHELSIO_T4: |
4691 | fw_config_file = FW_CFNAME; | 4627 | fw_config_file = FW4_CFNAME; |
4692 | break; | 4628 | break; |
4693 | case CHELSIO_T5: | 4629 | case CHELSIO_T5: |
4694 | fw_config_file = FW5_CFNAME; | 4630 | fw_config_file = FW5_CFNAME; |
@@ -4702,13 +4638,16 @@ static int adap_init0_config(struct adapter *adapter, int reset) | |||
4702 | 4638 | ||
4703 | ret = request_firmware(&cf, fw_config_file, adapter->pdev_dev); | 4639 | ret = request_firmware(&cf, fw_config_file, adapter->pdev_dev); |
4704 | if (ret < 0) { | 4640 | if (ret < 0) { |
4705 | using_flash = 1; | 4641 | config_name = "On FLASH"; |
4706 | mtype = FW_MEMTYPE_CF_FLASH; | 4642 | mtype = FW_MEMTYPE_CF_FLASH; |
4707 | maddr = t4_flash_cfg_addr(adapter); | 4643 | maddr = t4_flash_cfg_addr(adapter); |
4708 | } else { | 4644 | } else { |
4709 | u32 params[7], val[7]; | 4645 | u32 params[7], val[7]; |
4710 | 4646 | ||
4711 | using_flash = 0; | 4647 | sprintf(fw_config_file_path, |
4648 | "/lib/firmware/%s", fw_config_file); | ||
4649 | config_name = fw_config_file_path; | ||
4650 | |||
4712 | if (cf->size >= FLASH_CFG_MAX_SIZE) | 4651 | if (cf->size >= FLASH_CFG_MAX_SIZE) |
4713 | ret = -ENOMEM; | 4652 | ret = -ENOMEM; |
4714 | else { | 4653 | else { |
@@ -4776,6 +4715,26 @@ static int adap_init0_config(struct adapter *adapter, int reset) | |||
4776 | FW_LEN16(caps_cmd)); | 4715 | FW_LEN16(caps_cmd)); |
4777 | ret = t4_wr_mbox(adapter, adapter->mbox, &caps_cmd, sizeof(caps_cmd), | 4716 | ret = t4_wr_mbox(adapter, adapter->mbox, &caps_cmd, sizeof(caps_cmd), |
4778 | &caps_cmd); | 4717 | &caps_cmd); |
4718 | |||
4719 | /* If the CAPS_CONFIG failed with an ENOENT (for a Firmware | ||
4720 | * Configuration File in FLASH), our last gasp effort is to use the | ||
4721 | * Firmware Configuration File which is embedded in the firmware. A | ||
4722 | * very few early versions of the firmware didn't have one embedded | ||
4723 | * but we can ignore those. | ||
4724 | */ | ||
4725 | if (ret == -ENOENT) { | ||
4726 | memset(&caps_cmd, 0, sizeof(caps_cmd)); | ||
4727 | caps_cmd.op_to_write = | ||
4728 | htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) | | ||
4729 | FW_CMD_REQUEST | | ||
4730 | FW_CMD_READ); | ||
4731 | caps_cmd.cfvalid_to_len16 = htonl(FW_LEN16(caps_cmd)); | ||
4732 | ret = t4_wr_mbox(adapter, adapter->mbox, &caps_cmd, | ||
4733 | sizeof(caps_cmd), &caps_cmd); | ||
4734 | config_name = "Firmware Default"; | ||
4735 | } | ||
4736 | |||
4737 | config_issued = 1; | ||
4779 | if (ret < 0) | 4738 | if (ret < 0) |
4780 | goto bye; | 4739 | goto bye; |
4781 | 4740 | ||
@@ -4816,7 +4775,6 @@ static int adap_init0_config(struct adapter *adapter, int reset) | |||
4816 | if (ret < 0) | 4775 | if (ret < 0) |
4817 | goto bye; | 4776 | goto bye; |
4818 | 4777 | ||
4819 | sprintf(fw_config_file_path, "/lib/firmware/%s", fw_config_file); | ||
4820 | /* | 4778 | /* |
4821 | * Return successfully and note that we're operating with parameters | 4779 | * Return successfully and note that we're operating with parameters |
4822 | * not supplied by the driver, rather than from hard-wired | 4780 | * not supplied by the driver, rather than from hard-wired |
@@ -4824,11 +4782,8 @@ static int adap_init0_config(struct adapter *adapter, int reset) | |||
4824 | */ | 4782 | */ |
4825 | adapter->flags |= USING_SOFT_PARAMS; | 4783 | adapter->flags |= USING_SOFT_PARAMS; |
4826 | dev_info(adapter->pdev_dev, "Successfully configured using Firmware "\ | 4784 | dev_info(adapter->pdev_dev, "Successfully configured using Firmware "\ |
4827 | "Configuration File %s, version %#x, computed checksum %#x\n", | 4785 | "Configuration File \"%s\", version %#x, computed checksum %#x\n", |
4828 | (using_flash | 4786 | config_name, finiver, cfcsum); |
4829 | ? "in device FLASH" | ||
4830 | : fw_config_file_path), | ||
4831 | finiver, cfcsum); | ||
4832 | return 0; | 4787 | return 0; |
4833 | 4788 | ||
4834 | /* | 4789 | /* |
@@ -4837,9 +4792,9 @@ static int adap_init0_config(struct adapter *adapter, int reset) | |||
4837 | * want to issue a warning since this is fairly common.) | 4792 | * want to issue a warning since this is fairly common.) |
4838 | */ | 4793 | */ |
4839 | bye: | 4794 | bye: |
4840 | if (ret != -ENOENT) | 4795 | if (config_issued && ret != -ENOENT) |
4841 | dev_warn(adapter->pdev_dev, "Configuration file error %d\n", | 4796 | dev_warn(adapter->pdev_dev, "\"%s\" configuration file error %d\n", |
4842 | -ret); | 4797 | config_name, -ret); |
4843 | return ret; | 4798 | return ret; |
4844 | } | 4799 | } |
4845 | 4800 | ||
@@ -5086,6 +5041,47 @@ bye: | |||
5086 | return ret; | 5041 | return ret; |
5087 | } | 5042 | } |
5088 | 5043 | ||
5044 | static struct fw_info fw_info_array[] = { | ||
5045 | { | ||
5046 | .chip = CHELSIO_T4, | ||
5047 | .fs_name = FW4_CFNAME, | ||
5048 | .fw_mod_name = FW4_FNAME, | ||
5049 | .fw_hdr = { | ||
5050 | .chip = FW_HDR_CHIP_T4, | ||
5051 | .fw_ver = __cpu_to_be32(FW_VERSION(T4)), | ||
5052 | .intfver_nic = FW_INTFVER(T4, NIC), | ||
5053 | .intfver_vnic = FW_INTFVER(T4, VNIC), | ||
5054 | .intfver_ri = FW_INTFVER(T4, RI), | ||
5055 | .intfver_iscsi = FW_INTFVER(T4, ISCSI), | ||
5056 | .intfver_fcoe = FW_INTFVER(T4, FCOE), | ||
5057 | }, | ||
5058 | }, { | ||
5059 | .chip = CHELSIO_T5, | ||
5060 | .fs_name = FW5_CFNAME, | ||
5061 | .fw_mod_name = FW5_FNAME, | ||
5062 | .fw_hdr = { | ||
5063 | .chip = FW_HDR_CHIP_T5, | ||
5064 | .fw_ver = __cpu_to_be32(FW_VERSION(T5)), | ||
5065 | .intfver_nic = FW_INTFVER(T5, NIC), | ||
5066 | .intfver_vnic = FW_INTFVER(T5, VNIC), | ||
5067 | .intfver_ri = FW_INTFVER(T5, RI), | ||
5068 | .intfver_iscsi = FW_INTFVER(T5, ISCSI), | ||
5069 | .intfver_fcoe = FW_INTFVER(T5, FCOE), | ||
5070 | }, | ||
5071 | } | ||
5072 | }; | ||
5073 | |||
5074 | static struct fw_info *find_fw_info(int chip) | ||
5075 | { | ||
5076 | int i; | ||
5077 | |||
5078 | for (i = 0; i < ARRAY_SIZE(fw_info_array); i++) { | ||
5079 | if (fw_info_array[i].chip == chip) | ||
5080 | return &fw_info_array[i]; | ||
5081 | } | ||
5082 | return NULL; | ||
5083 | } | ||
5084 | |||
5089 | /* | 5085 | /* |
5090 | * Phase 0 of initialization: contact FW, obtain config, perform basic init. | 5086 | * Phase 0 of initialization: contact FW, obtain config, perform basic init. |
5091 | */ | 5087 | */ |
@@ -5123,44 +5119,54 @@ static int adap_init0(struct adapter *adap) | |||
5123 | * later reporting and B. to warn if the currently loaded firmware | 5119 | * later reporting and B. to warn if the currently loaded firmware |
5124 | * is excessively mismatched relative to the driver.) | 5120 | * is excessively mismatched relative to the driver.) |
5125 | */ | 5121 | */ |
5126 | ret = t4_check_fw_version(adap); | 5122 | t4_get_fw_version(adap, &adap->params.fw_vers); |
5127 | 5123 | t4_get_tp_version(adap, &adap->params.tp_vers); | |
5128 | /* The error code -EFAULT is returned by t4_check_fw_version() if | ||
5129 | * firmware on adapter < supported firmware. If firmware on adapter | ||
5130 | * is too old (not supported by driver) and we're the MASTER_PF set | ||
5131 | * adapter state to DEV_STATE_UNINIT to force firmware upgrade | ||
5132 | * and reinitialization. | ||
5133 | */ | ||
5134 | if ((adap->flags & MASTER_PF) && ret == -EFAULT) | ||
5135 | state = DEV_STATE_UNINIT; | ||
5136 | if ((adap->flags & MASTER_PF) && state != DEV_STATE_INIT) { | 5124 | if ((adap->flags & MASTER_PF) && state != DEV_STATE_INIT) { |
5137 | if (ret == -EINVAL || ret == -EFAULT || ret > 0) { | 5125 | struct fw_info *fw_info; |
5138 | if (upgrade_fw(adap) >= 0) { | 5126 | struct fw_hdr *card_fw; |
5139 | /* | 5127 | const struct firmware *fw; |
5140 | * Note that the chip was reset as part of the | 5128 | const u8 *fw_data = NULL; |
5141 | * firmware upgrade so we don't reset it again | 5129 | unsigned int fw_size = 0; |
5142 | * below and grab the new firmware version. | 5130 | |
5143 | */ | 5131 | /* This is the firmware whose headers the driver was compiled |
5144 | reset = 0; | 5132 | * against |
5145 | ret = t4_check_fw_version(adap); | 5133 | */ |
5146 | } else | 5134 | fw_info = find_fw_info(CHELSIO_CHIP_VERSION(adap->params.chip)); |
5147 | if (ret == -EFAULT) { | 5135 | if (fw_info == NULL) { |
5148 | /* | 5136 | dev_err(adap->pdev_dev, |
5149 | * Firmware is old but still might | 5137 | "unable to get firmware info for chip %d.\n", |
5150 | * work if we force reinitialization | 5138 | CHELSIO_CHIP_VERSION(adap->params.chip)); |
5151 | * of the adapter. Ignoring FW upgrade | 5139 | return -EINVAL; |
5152 | * failure. | ||
5153 | */ | ||
5154 | dev_warn(adap->pdev_dev, | ||
5155 | "Ignoring firmware upgrade " | ||
5156 | "failure, and forcing driver " | ||
5157 | "to reinitialize the " | ||
5158 | "adapter.\n"); | ||
5159 | ret = 0; | ||
5160 | } | ||
5161 | } | 5140 | } |
5141 | |||
5142 | /* allocate memory to read the header of the firmware on the | ||
5143 | * card | ||
5144 | */ | ||
5145 | card_fw = t4_alloc_mem(sizeof(*card_fw)); | ||
5146 | |||
5147 | /* Get FW from from /lib/firmware/ */ | ||
5148 | ret = request_firmware(&fw, fw_info->fw_mod_name, | ||
5149 | adap->pdev_dev); | ||
5150 | if (ret < 0) { | ||
5151 | dev_err(adap->pdev_dev, | ||
5152 | "unable to load firmware image %s, error %d\n", | ||
5153 | fw_info->fw_mod_name, ret); | ||
5154 | } else { | ||
5155 | fw_data = fw->data; | ||
5156 | fw_size = fw->size; | ||
5157 | } | ||
5158 | |||
5159 | /* upgrade FW logic */ | ||
5160 | ret = t4_prep_fw(adap, fw_info, fw_data, fw_size, card_fw, | ||
5161 | state, &reset); | ||
5162 | |||
5163 | /* Cleaning up */ | ||
5164 | if (fw != NULL) | ||
5165 | release_firmware(fw); | ||
5166 | t4_free_mem(card_fw); | ||
5167 | |||
5162 | if (ret < 0) | 5168 | if (ret < 0) |
5163 | return ret; | 5169 | goto bye; |
5164 | } | 5170 | } |
5165 | 5171 | ||
5166 | /* | 5172 | /* |
@@ -5245,7 +5251,7 @@ static int adap_init0(struct adapter *adap) | |||
5245 | if (ret == -ENOENT) { | 5251 | if (ret == -ENOENT) { |
5246 | dev_info(adap->pdev_dev, | 5252 | dev_info(adap->pdev_dev, |
5247 | "No Configuration File present " | 5253 | "No Configuration File present " |
5248 | "on adapter. Using hard-wired " | 5254 | "on adapter. Using hard-wired " |
5249 | "configuration parameters.\n"); | 5255 | "configuration parameters.\n"); |
5250 | ret = adap_init0_no_config(adap, reset); | 5256 | ret = adap_init0_no_config(adap, reset); |
5251 | } | 5257 | } |
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 83b5e42b66a9..74a6fce5a15a 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | |||
@@ -863,104 +863,169 @@ unlock: | |||
863 | } | 863 | } |
864 | 864 | ||
865 | /** | 865 | /** |
866 | * get_fw_version - read the firmware version | 866 | * t4_get_fw_version - read the firmware version |
867 | * @adapter: the adapter | 867 | * @adapter: the adapter |
868 | * @vers: where to place the version | 868 | * @vers: where to place the version |
869 | * | 869 | * |
870 | * Reads the FW version from flash. | 870 | * Reads the FW version from flash. |
871 | */ | 871 | */ |
872 | static int get_fw_version(struct adapter *adapter, u32 *vers) | 872 | int t4_get_fw_version(struct adapter *adapter, u32 *vers) |
873 | { | 873 | { |
874 | return t4_read_flash(adapter, adapter->params.sf_fw_start + | 874 | return t4_read_flash(adapter, FLASH_FW_START + |
875 | offsetof(struct fw_hdr, fw_ver), 1, vers, 0); | 875 | offsetof(struct fw_hdr, fw_ver), 1, |
876 | vers, 0); | ||
876 | } | 877 | } |
877 | 878 | ||
878 | /** | 879 | /** |
879 | * get_tp_version - read the TP microcode version | 880 | * t4_get_tp_version - read the TP microcode version |
880 | * @adapter: the adapter | 881 | * @adapter: the adapter |
881 | * @vers: where to place the version | 882 | * @vers: where to place the version |
882 | * | 883 | * |
883 | * Reads the TP microcode version from flash. | 884 | * Reads the TP microcode version from flash. |
884 | */ | 885 | */ |
885 | static int get_tp_version(struct adapter *adapter, u32 *vers) | 886 | int t4_get_tp_version(struct adapter *adapter, u32 *vers) |
886 | { | 887 | { |
887 | return t4_read_flash(adapter, adapter->params.sf_fw_start + | 888 | return t4_read_flash(adapter, FLASH_FW_START + |
888 | offsetof(struct fw_hdr, tp_microcode_ver), | 889 | offsetof(struct fw_hdr, tp_microcode_ver), |
889 | 1, vers, 0); | 890 | 1, vers, 0); |
890 | } | 891 | } |
891 | 892 | ||
892 | /** | 893 | /* Is the given firmware API compatible with the one the driver was compiled |
893 | * t4_check_fw_version - check if the FW is compatible with this driver | 894 | * with? |
894 | * @adapter: the adapter | ||
895 | * | ||
896 | * Checks if an adapter's FW is compatible with the driver. Returns 0 | ||
897 | * if there's exact match, a negative error if the version could not be | ||
898 | * read or there's a major version mismatch, and a positive value if the | ||
899 | * expected major version is found but there's a minor version mismatch. | ||
900 | */ | 895 | */ |
901 | int t4_check_fw_version(struct adapter *adapter) | 896 | static int fw_compatible(const struct fw_hdr *hdr1, const struct fw_hdr *hdr2) |
902 | { | 897 | { |
903 | u32 api_vers[2]; | ||
904 | int ret, major, minor, micro; | ||
905 | int exp_major, exp_minor, exp_micro; | ||
906 | 898 | ||
907 | ret = get_fw_version(adapter, &adapter->params.fw_vers); | 899 | /* short circuit if it's the exact same firmware version */ |
908 | if (!ret) | 900 | if (hdr1->chip == hdr2->chip && hdr1->fw_ver == hdr2->fw_ver) |
909 | ret = get_tp_version(adapter, &adapter->params.tp_vers); | 901 | return 1; |
910 | if (!ret) | ||
911 | ret = t4_read_flash(adapter, adapter->params.sf_fw_start + | ||
912 | offsetof(struct fw_hdr, intfver_nic), | ||
913 | 2, api_vers, 1); | ||
914 | if (ret) | ||
915 | return ret; | ||
916 | 902 | ||
917 | major = FW_HDR_FW_VER_MAJOR_GET(adapter->params.fw_vers); | 903 | #define SAME_INTF(x) (hdr1->intfver_##x == hdr2->intfver_##x) |
918 | minor = FW_HDR_FW_VER_MINOR_GET(adapter->params.fw_vers); | 904 | if (hdr1->chip == hdr2->chip && SAME_INTF(nic) && SAME_INTF(vnic) && |
919 | micro = FW_HDR_FW_VER_MICRO_GET(adapter->params.fw_vers); | 905 | SAME_INTF(ri) && SAME_INTF(iscsi) && SAME_INTF(fcoe)) |
906 | return 1; | ||
907 | #undef SAME_INTF | ||
920 | 908 | ||
921 | switch (CHELSIO_CHIP_VERSION(adapter->params.chip)) { | 909 | return 0; |
922 | case CHELSIO_T4: | 910 | } |
923 | exp_major = FW_VERSION_MAJOR; | ||
924 | exp_minor = FW_VERSION_MINOR; | ||
925 | exp_micro = FW_VERSION_MICRO; | ||
926 | break; | ||
927 | case CHELSIO_T5: | ||
928 | exp_major = FW_VERSION_MAJOR_T5; | ||
929 | exp_minor = FW_VERSION_MINOR_T5; | ||
930 | exp_micro = FW_VERSION_MICRO_T5; | ||
931 | break; | ||
932 | default: | ||
933 | dev_err(adapter->pdev_dev, "Unsupported chip type, %x\n", | ||
934 | adapter->params.chip); | ||
935 | return -EINVAL; | ||
936 | } | ||
937 | 911 | ||
938 | memcpy(adapter->params.api_vers, api_vers, | 912 | /* The firmware in the filesystem is usable, but should it be installed? |
939 | sizeof(adapter->params.api_vers)); | 913 | * This routine explains itself in detail if it indicates the filesystem |
914 | * firmware should be installed. | ||
915 | */ | ||
916 | static int should_install_fs_fw(struct adapter *adap, int card_fw_usable, | ||
917 | int k, int c) | ||
918 | { | ||
919 | const char *reason; | ||
940 | 920 | ||
941 | if (major < exp_major || (major == exp_major && minor < exp_minor) || | 921 | if (!card_fw_usable) { |
942 | (major == exp_major && minor == exp_minor && micro < exp_micro)) { | 922 | reason = "incompatible or unusable"; |
943 | dev_err(adapter->pdev_dev, | 923 | goto install; |
944 | "Card has firmware version %u.%u.%u, minimum " | ||
945 | "supported firmware is %u.%u.%u.\n", major, minor, | ||
946 | micro, exp_major, exp_minor, exp_micro); | ||
947 | return -EFAULT; | ||
948 | } | 924 | } |
949 | 925 | ||
950 | if (major != exp_major) { /* major mismatch - fail */ | 926 | if (k > c) { |
951 | dev_err(adapter->pdev_dev, | 927 | reason = "older than the version supported with this driver"; |
952 | "card FW has major version %u, driver wants %u\n", | 928 | goto install; |
953 | major, exp_major); | ||
954 | return -EINVAL; | ||
955 | } | 929 | } |
956 | 930 | ||
957 | if (minor == exp_minor && micro == exp_micro) | 931 | return 0; |
958 | return 0; /* perfect match */ | 932 | |
933 | install: | ||
934 | dev_err(adap->pdev_dev, "firmware on card (%u.%u.%u.%u) is %s, " | ||
935 | "installing firmware %u.%u.%u.%u on card.\n", | ||
936 | FW_HDR_FW_VER_MAJOR_GET(c), FW_HDR_FW_VER_MINOR_GET(c), | ||
937 | FW_HDR_FW_VER_MICRO_GET(c), FW_HDR_FW_VER_BUILD_GET(c), reason, | ||
938 | FW_HDR_FW_VER_MAJOR_GET(k), FW_HDR_FW_VER_MINOR_GET(k), | ||
939 | FW_HDR_FW_VER_MICRO_GET(k), FW_HDR_FW_VER_BUILD_GET(k)); | ||
959 | 940 | ||
960 | /* Minor/micro version mismatch. Report it but often it's OK. */ | ||
961 | return 1; | 941 | return 1; |
962 | } | 942 | } |
963 | 943 | ||
944 | int t4_prep_fw(struct adapter *adap, struct fw_info *fw_info, | ||
945 | const u8 *fw_data, unsigned int fw_size, | ||
946 | struct fw_hdr *card_fw, enum dev_state state, | ||
947 | int *reset) | ||
948 | { | ||
949 | int ret, card_fw_usable, fs_fw_usable; | ||
950 | const struct fw_hdr *fs_fw; | ||
951 | const struct fw_hdr *drv_fw; | ||
952 | |||
953 | drv_fw = &fw_info->fw_hdr; | ||
954 | |||
955 | /* Read the header of the firmware on the card */ | ||
956 | ret = -t4_read_flash(adap, FLASH_FW_START, | ||
957 | sizeof(*card_fw) / sizeof(uint32_t), | ||
958 | (uint32_t *)card_fw, 1); | ||
959 | if (ret == 0) { | ||
960 | card_fw_usable = fw_compatible(drv_fw, (const void *)card_fw); | ||
961 | } else { | ||
962 | dev_err(adap->pdev_dev, | ||
963 | "Unable to read card's firmware header: %d\n", ret); | ||
964 | card_fw_usable = 0; | ||
965 | } | ||
966 | |||
967 | if (fw_data != NULL) { | ||
968 | fs_fw = (const void *)fw_data; | ||
969 | fs_fw_usable = fw_compatible(drv_fw, fs_fw); | ||
970 | } else { | ||
971 | fs_fw = NULL; | ||
972 | fs_fw_usable = 0; | ||
973 | } | ||
974 | |||
975 | if (card_fw_usable && card_fw->fw_ver == drv_fw->fw_ver && | ||
976 | (!fs_fw_usable || fs_fw->fw_ver == drv_fw->fw_ver)) { | ||
977 | /* Common case: the firmware on the card is an exact match and | ||
978 | * the filesystem one is an exact match too, or the filesystem | ||
979 | * one is absent/incompatible. | ||
980 | */ | ||
981 | } else if (fs_fw_usable && state == DEV_STATE_UNINIT && | ||
982 | should_install_fs_fw(adap, card_fw_usable, | ||
983 | be32_to_cpu(fs_fw->fw_ver), | ||
984 | be32_to_cpu(card_fw->fw_ver))) { | ||
985 | ret = -t4_fw_upgrade(adap, adap->mbox, fw_data, | ||
986 | fw_size, 0); | ||
987 | if (ret != 0) { | ||
988 | dev_err(adap->pdev_dev, | ||
989 | "failed to install firmware: %d\n", ret); | ||
990 | goto bye; | ||
991 | } | ||
992 | |||
993 | /* Installed successfully, update the cached header too. */ | ||
994 | memcpy(card_fw, fs_fw, sizeof(*card_fw)); | ||
995 | card_fw_usable = 1; | ||
996 | *reset = 0; /* already reset as part of load_fw */ | ||
997 | } | ||
998 | |||
999 | if (!card_fw_usable) { | ||
1000 | uint32_t d, c, k; | ||
1001 | |||
1002 | d = be32_to_cpu(drv_fw->fw_ver); | ||
1003 | c = be32_to_cpu(card_fw->fw_ver); | ||
1004 | k = fs_fw ? be32_to_cpu(fs_fw->fw_ver) : 0; | ||
1005 | |||
1006 | dev_err(adap->pdev_dev, "Cannot find a usable firmware: " | ||
1007 | "chip state %d, " | ||
1008 | "driver compiled with %d.%d.%d.%d, " | ||
1009 | "card has %d.%d.%d.%d, filesystem has %d.%d.%d.%d\n", | ||
1010 | state, | ||
1011 | FW_HDR_FW_VER_MAJOR_GET(d), FW_HDR_FW_VER_MINOR_GET(d), | ||
1012 | FW_HDR_FW_VER_MICRO_GET(d), FW_HDR_FW_VER_BUILD_GET(d), | ||
1013 | FW_HDR_FW_VER_MAJOR_GET(c), FW_HDR_FW_VER_MINOR_GET(c), | ||
1014 | FW_HDR_FW_VER_MICRO_GET(c), FW_HDR_FW_VER_BUILD_GET(c), | ||
1015 | FW_HDR_FW_VER_MAJOR_GET(k), FW_HDR_FW_VER_MINOR_GET(k), | ||
1016 | FW_HDR_FW_VER_MICRO_GET(k), FW_HDR_FW_VER_BUILD_GET(k)); | ||
1017 | ret = EINVAL; | ||
1018 | goto bye; | ||
1019 | } | ||
1020 | |||
1021 | /* We're using whatever's on the card and it's known to be good. */ | ||
1022 | adap->params.fw_vers = be32_to_cpu(card_fw->fw_ver); | ||
1023 | adap->params.tp_vers = be32_to_cpu(card_fw->tp_microcode_ver); | ||
1024 | |||
1025 | bye: | ||
1026 | return ret; | ||
1027 | } | ||
1028 | |||
964 | /** | 1029 | /** |
965 | * t4_flash_erase_sectors - erase a range of flash sectors | 1030 | * t4_flash_erase_sectors - erase a range of flash sectors |
966 | * @adapter: the adapter | 1031 | * @adapter: the adapter |
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h index 6f77ac487743..74fea74ce0aa 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h | |||
@@ -2157,7 +2157,7 @@ struct fw_debug_cmd { | |||
2157 | 2157 | ||
2158 | struct fw_hdr { | 2158 | struct fw_hdr { |
2159 | u8 ver; | 2159 | u8 ver; |
2160 | u8 reserved1; | 2160 | u8 chip; /* terminator chip type */ |
2161 | __be16 len512; /* bin length in units of 512-bytes */ | 2161 | __be16 len512; /* bin length in units of 512-bytes */ |
2162 | __be32 fw_ver; /* firmware version */ | 2162 | __be32 fw_ver; /* firmware version */ |
2163 | __be32 tp_microcode_ver; | 2163 | __be32 tp_microcode_ver; |
@@ -2176,6 +2176,11 @@ struct fw_hdr { | |||
2176 | __be32 reserved6[23]; | 2176 | __be32 reserved6[23]; |
2177 | }; | 2177 | }; |
2178 | 2178 | ||
2179 | enum fw_hdr_chip { | ||
2180 | FW_HDR_CHIP_T4, | ||
2181 | FW_HDR_CHIP_T5 | ||
2182 | }; | ||
2183 | |||
2179 | #define FW_HDR_FW_VER_MAJOR_GET(x) (((x) >> 24) & 0xff) | 2184 | #define FW_HDR_FW_VER_MAJOR_GET(x) (((x) >> 24) & 0xff) |
2180 | #define FW_HDR_FW_VER_MINOR_GET(x) (((x) >> 16) & 0xff) | 2185 | #define FW_HDR_FW_VER_MINOR_GET(x) (((x) >> 16) & 0xff) |
2181 | #define FW_HDR_FW_VER_MICRO_GET(x) (((x) >> 8) & 0xff) | 2186 | #define FW_HDR_FW_VER_MICRO_GET(x) (((x) >> 8) & 0xff) |