aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wimax/i2400m/fw.c
diff options
context:
space:
mode:
authorInaky Perez-Gonzalez <inaky@linux.intel.com>2009-02-28 18:42:47 -0500
committerDavid S. Miller <davem@davemloft.net>2009-03-02 06:10:23 -0500
commit1039abbc5b1bfa943b6daabbe9de1499037a90c0 (patch)
tree7c8e18a228750d59fba2941cca87850fb603af6c /drivers/net/wimax/i2400m/fw.c
parent86739fb96e8c8269fc5b3d300c959bede272a6f6 (diff)
wimax/i2400m: add the ability to fallback to other firmware files if the default is not there
In order to support backwards compatibility with older firmwares when a driver is updated by a new kernel release, the i2400m bus drivers can declare a list of firmware files they can work with (in general these will be each a different version). The firmware loader will try them in sequence until one loads. Thus, if a user doesn't have the latest and greatest firmware that a newly installed kernel would require, the driver would fall back to the firmware from a previous release. To support this, the i2400m->bus_fw_name is changed to be a NULL terminated array firmware file names (and renamed to bus_fw_names) and we add a new entry (i2400m->fw_name) that points to the name of the firmware being currently used. All code that needs to print the firmware file name uses i2400m->fw_name instead of the old i2400m->bus_fw_name. The code in i2400m_dev_bootstrap() that loads the firmware is changed with an iterator over the firmware file name list that tries to load each form user space, using the first one that succeeds in request_firmware() (and thus stopping the iteration). The USB and SDIO bus drivers are updated to take advantage of this and reflect which firmwares they support. Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/wimax/i2400m/fw.c')
-rw-r--r--drivers/net/wimax/i2400m/fw.c53
1 files changed, 33 insertions, 20 deletions
diff --git a/drivers/net/wimax/i2400m/fw.c b/drivers/net/wimax/i2400m/fw.c
index ecd0cfaefdcc..675c6ce810c0 100644
--- a/drivers/net/wimax/i2400m/fw.c
+++ b/drivers/net/wimax/i2400m/fw.c
@@ -483,7 +483,7 @@ ssize_t i2400m_dnload_bcf(struct i2400m *i2400m,
483 if (offset + section_size > bcf_len) { 483 if (offset + section_size > bcf_len) {
484 dev_err(dev, "fw %s: bad section #%zu, " 484 dev_err(dev, "fw %s: bad section #%zu, "
485 "end (@%zu) beyond EOF (@%zu)\n", 485 "end (@%zu) beyond EOF (@%zu)\n",
486 i2400m->bus_fw_name, section, 486 i2400m->fw_name, section,
487 offset + section_size, bcf_len); 487 offset + section_size, bcf_len);
488 ret = -EINVAL; 488 ret = -EINVAL;
489 goto error_section_beyond_eof; 489 goto error_section_beyond_eof;
@@ -493,7 +493,7 @@ ssize_t i2400m_dnload_bcf(struct i2400m *i2400m,
493 &ack, sizeof(ack), I2400M_BM_CMD_RAW); 493 &ack, sizeof(ack), I2400M_BM_CMD_RAW);
494 if (ret < 0) { 494 if (ret < 0) {
495 dev_err(dev, "fw %s: section #%zu (@%zu %zu B) " 495 dev_err(dev, "fw %s: section #%zu (@%zu %zu B) "
496 "failed %d\n", i2400m->bus_fw_name, section, 496 "failed %d\n", i2400m->fw_name, section,
497 offset, sizeof(*bh) + data_size, (int) ret); 497 offset, sizeof(*bh) + data_size, (int) ret);
498 goto error_send; 498 goto error_send;
499 } 499 }
@@ -874,7 +874,7 @@ int i2400m_dnload_init(struct i2400m *i2400m, const struct i2400m_bcf_hdr *bcf)
874 if (result < 0) 874 if (result < 0)
875 dev_err(dev, "fw %s: non-signed download " 875 dev_err(dev, "fw %s: non-signed download "
876 "initialization failed: %d\n", 876 "initialization failed: %d\n",
877 i2400m->bus_fw_name, result); 877 i2400m->fw_name, result);
878 } else if (i2400m->sboot == 0 878 } else if (i2400m->sboot == 0
879 && (module_id & I2400M_BCF_MOD_ID_POKES)) { 879 && (module_id & I2400M_BCF_MOD_ID_POKES)) {
880 /* non-signed boot process with pokes, nothing to do */ 880 /* non-signed boot process with pokes, nothing to do */
@@ -886,7 +886,7 @@ int i2400m_dnload_init(struct i2400m *i2400m, const struct i2400m_bcf_hdr *bcf)
886 if (result < 0) 886 if (result < 0)
887 dev_err(dev, "fw %s: signed boot download " 887 dev_err(dev, "fw %s: signed boot download "
888 "initialization failed: %d\n", 888 "initialization failed: %d\n",
889 i2400m->bus_fw_name, result); 889 i2400m->fw_name, result);
890 } 890 }
891 return result; 891 return result;
892} 892}
@@ -915,7 +915,7 @@ int i2400m_fw_check(struct i2400m *i2400m,
915 if (bcf_size < sizeof(*bcf)) { /* big enough header? */ 915 if (bcf_size < sizeof(*bcf)) { /* big enough header? */
916 dev_err(dev, "firmware %s too short: " 916 dev_err(dev, "firmware %s too short: "
917 "%zu B vs %zu (at least) expected\n", 917 "%zu B vs %zu (at least) expected\n",
918 i2400m->bus_fw_name, bcf_size, sizeof(*bcf)); 918 i2400m->fw_name, bcf_size, sizeof(*bcf));
919 goto error; 919 goto error;
920 } 920 }
921 921
@@ -931,7 +931,7 @@ int i2400m_fw_check(struct i2400m *i2400m,
931 if (bcf_size != size) { /* annoyingly paranoid */ 931 if (bcf_size != size) { /* annoyingly paranoid */
932 dev_err(dev, "firmware %s: bad size, got " 932 dev_err(dev, "firmware %s: bad size, got "
933 "%zu B vs %u expected\n", 933 "%zu B vs %u expected\n",
934 i2400m->bus_fw_name, bcf_size, size); 934 i2400m->fw_name, bcf_size, size);
935 goto error; 935 goto error;
936 } 936 }
937 937
@@ -943,7 +943,7 @@ int i2400m_fw_check(struct i2400m *i2400m,
943 943
944 if (module_type != 6) { /* built for the right hardware? */ 944 if (module_type != 6) { /* built for the right hardware? */
945 dev_err(dev, "bad fw %s: unexpected module type 0x%x; " 945 dev_err(dev, "bad fw %s: unexpected module type 0x%x; "
946 "aborting\n", i2400m->bus_fw_name, module_type); 946 "aborting\n", i2400m->fw_name, module_type);
947 goto error; 947 goto error;
948 } 948 }
949 949
@@ -951,10 +951,10 @@ int i2400m_fw_check(struct i2400m *i2400m,
951 result = 0; 951 result = 0;
952 if (module_vendor != 0x8086) 952 if (module_vendor != 0x8086)
953 dev_err(dev, "bad fw %s? unexpected vendor 0x%04x\n", 953 dev_err(dev, "bad fw %s? unexpected vendor 0x%04x\n",
954 i2400m->bus_fw_name, module_vendor); 954 i2400m->fw_name, module_vendor);
955 if (date < 0x20080300) 955 if (date < 0x20080300)
956 dev_err(dev, "bad fw %s? build date too old %08x\n", 956 dev_err(dev, "bad fw %s? build date too old %08x\n",
957 i2400m->bus_fw_name, date); 957 i2400m->fw_name, date);
958error: 958error:
959 return result; 959 return result;
960} 960}
@@ -1016,7 +1016,7 @@ hw_reboot:
1016 goto error_dev_rebooted; 1016 goto error_dev_rebooted;
1017 if (ret < 0) { 1017 if (ret < 0) {
1018 dev_err(dev, "fw %s: download failed: %d\n", 1018 dev_err(dev, "fw %s: download failed: %d\n",
1019 i2400m->bus_fw_name, ret); 1019 i2400m->fw_name, ret);
1020 goto error_dnload_bcf; 1020 goto error_dnload_bcf;
1021 } 1021 }
1022 1022
@@ -1026,12 +1026,12 @@ hw_reboot:
1026 if (ret < 0) { 1026 if (ret < 0) {
1027 dev_err(dev, "fw %s: " 1027 dev_err(dev, "fw %s: "
1028 "download finalization failed: %d\n", 1028 "download finalization failed: %d\n",
1029 i2400m->bus_fw_name, ret); 1029 i2400m->fw_name, ret);
1030 goto error_dnload_finalize; 1030 goto error_dnload_finalize;
1031 } 1031 }
1032 1032
1033 d_printf(2, dev, "fw %s successfully uploaded\n", 1033 d_printf(2, dev, "fw %s successfully uploaded\n",
1034 i2400m->bus_fw_name); 1034 i2400m->fw_name);
1035 i2400m->boot_mode = 0; 1035 i2400m->boot_mode = 0;
1036error_dnload_finalize: 1036error_dnload_finalize:
1037error_dnload_bcf: 1037error_dnload_bcf:
@@ -1067,28 +1067,41 @@ error_dev_rebooted:
1067 */ 1067 */
1068int i2400m_dev_bootstrap(struct i2400m *i2400m, enum i2400m_bri flags) 1068int i2400m_dev_bootstrap(struct i2400m *i2400m, enum i2400m_bri flags)
1069{ 1069{
1070 int ret = 0; 1070 int ret = 0, itr = 0;
1071 struct device *dev = i2400m_dev(i2400m); 1071 struct device *dev = i2400m_dev(i2400m);
1072 const struct firmware *fw; 1072 const struct firmware *fw;
1073 const struct i2400m_bcf_hdr *bcf; /* Firmware data */ 1073 const struct i2400m_bcf_hdr *bcf; /* Firmware data */
1074 const char *fw_name;
1074 1075
1075 d_fnstart(5, dev, "(i2400m %p)\n", i2400m); 1076 d_fnstart(5, dev, "(i2400m %p)\n", i2400m);
1077
1076 /* Load firmware files to memory. */ 1078 /* Load firmware files to memory. */
1077 ret = request_firmware(&fw, i2400m->bus_fw_name, dev); 1079 itr = 0;
1078 if (ret) { 1080 while(1) {
1079 dev_err(dev, "fw %s: request failed: %d\n", 1081 fw_name = i2400m->bus_fw_names[itr];
1080 i2400m->bus_fw_name, ret); 1082 if (fw_name == NULL) {
1081 goto error_fw_req; 1083 dev_err(dev, "Could not find a usable firmware image\n");
1084 ret = -ENOENT;
1085 goto error_no_fw;
1086 }
1087 ret = request_firmware(&fw, fw_name, dev);
1088 if (ret == 0)
1089 break; /* got it */
1090 if (ret < 0)
1091 dev_err(dev, "fw %s: cannot load file: %d\n",
1092 fw_name, ret);
1093 itr++;
1082 } 1094 }
1083 bcf = (void *) fw->data;
1084 1095
1096 bcf = (void *) fw->data;
1097 i2400m->fw_name = fw_name;
1085 ret = i2400m_fw_check(i2400m, bcf, fw->size); 1098 ret = i2400m_fw_check(i2400m, bcf, fw->size);
1086 if (ret < 0) 1099 if (ret < 0)
1087 goto error_fw_bad; 1100 goto error_fw_bad;
1088 ret = i2400m_fw_dnload(i2400m, bcf, fw->size, flags); 1101 ret = i2400m_fw_dnload(i2400m, bcf, fw->size, flags);
1089error_fw_bad: 1102error_fw_bad:
1090 release_firmware(fw); 1103 release_firmware(fw);
1091error_fw_req: 1104error_no_fw:
1092 d_fnend(5, dev, "(i2400m %p) = %d\n", i2400m, ret); 1105 d_fnend(5, dev, "(i2400m %p) = %d\n", i2400m, ret);
1093 return ret; 1106 return ret;
1094} 1107}