diff options
-rw-r--r-- | drivers/net/wimax/i2400m/fw.c | 53 | ||||
-rw-r--r-- | drivers/net/wimax/i2400m/i2400m.h | 21 | ||||
-rw-r--r-- | drivers/net/wimax/i2400m/sdio.c | 11 | ||||
-rw-r--r-- | drivers/net/wimax/i2400m/usb.c | 14 |
4 files changed, 64 insertions, 35 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); |
958 | error: | 958 | error: |
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; |
1036 | error_dnload_finalize: | 1036 | error_dnload_finalize: |
1037 | error_dnload_bcf: | 1037 | error_dnload_bcf: |
@@ -1067,28 +1067,41 @@ error_dev_rebooted: | |||
1067 | */ | 1067 | */ |
1068 | int i2400m_dev_bootstrap(struct i2400m *i2400m, enum i2400m_bri flags) | 1068 | int 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); |
1089 | error_fw_bad: | 1102 | error_fw_bad: |
1090 | release_firmware(fw); | 1103 | release_firmware(fw); |
1091 | error_fw_req: | 1104 | error_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 | } |
diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h index f9e55397ee88..ad71ad1086ea 100644 --- a/drivers/net/wimax/i2400m/i2400m.h +++ b/drivers/net/wimax/i2400m/i2400m.h | |||
@@ -156,10 +156,6 @@ enum { | |||
156 | }; | 156 | }; |
157 | 157 | ||
158 | 158 | ||
159 | /* Firmware version we request when pulling the fw image file */ | ||
160 | #define I2400M_FW_VERSION "1.4" | ||
161 | |||
162 | |||
163 | /** | 159 | /** |
164 | * i2400m_reset_type - methods to reset a device | 160 | * i2400m_reset_type - methods to reset a device |
165 | * | 161 | * |
@@ -242,10 +238,14 @@ struct i2400m_reset_ctx; | |||
242 | * The caller to this function will check if the response is a | 238 | * The caller to this function will check if the response is a |
243 | * barker that indicates the device going into reset mode. | 239 | * barker that indicates the device going into reset mode. |
244 | * | 240 | * |
245 | * @bus_fw_name: [fill] name of the firmware image (in most cases, | 241 | * @bus_fw_names: [fill] a NULL-terminated array with the names of the |
246 | * they are all the same for a single release, except that they | 242 | * firmware images to try loading. This is made a list so we can |
247 | * have the type of the bus embedded in the name (eg: | 243 | * support backward compatibility of firmware releases (eg: if we |
248 | * i2400m-fw-X-VERSION.sbcf, where X is the bus name). | 244 | * can't find the default v1.4, we try v1.3). In general, the name |
245 | * should be i2400m-fw-X-VERSION.sbcf, where X is the bus name. | ||
246 | * The list is tried in order and the first one that loads is | ||
247 | * used. The fw loader will set i2400m->fw_name to point to the | ||
248 | * active firmware image. | ||
249 | * | 249 | * |
250 | * @bus_bm_mac_addr_impaired: [fill] Set to true if the device's MAC | 250 | * @bus_bm_mac_addr_impaired: [fill] Set to true if the device's MAC |
251 | * address provided in boot mode is kind of broken and needs to | 251 | * address provided in boot mode is kind of broken and needs to |
@@ -364,6 +364,8 @@ struct i2400m_reset_ctx; | |||
364 | * These have to be in a separate directory, a child of | 364 | * These have to be in a separate directory, a child of |
365 | * (wimax_dev->debugfs_dentry) so they can be removed when the | 365 | * (wimax_dev->debugfs_dentry) so they can be removed when the |
366 | * module unloads, as we don't keep each dentry. | 366 | * module unloads, as we don't keep each dentry. |
367 | * | ||
368 | * @fw_name: name of the firmware image that is currently being used. | ||
367 | */ | 369 | */ |
368 | struct i2400m { | 370 | struct i2400m { |
369 | struct wimax_dev wimax_dev; /* FIRST! See doc */ | 371 | struct wimax_dev wimax_dev; /* FIRST! See doc */ |
@@ -388,7 +390,7 @@ struct i2400m { | |||
388 | size_t, int flags); | 390 | size_t, int flags); |
389 | ssize_t (*bus_bm_wait_for_ack)(struct i2400m *, | 391 | ssize_t (*bus_bm_wait_for_ack)(struct i2400m *, |
390 | struct i2400m_bootrom_header *, size_t); | 392 | struct i2400m_bootrom_header *, size_t); |
391 | const char *bus_fw_name; | 393 | const char **bus_fw_names; |
392 | unsigned bus_bm_mac_addr_impaired:1; | 394 | unsigned bus_bm_mac_addr_impaired:1; |
393 | 395 | ||
394 | spinlock_t tx_lock; /* protect TX state */ | 396 | spinlock_t tx_lock; /* protect TX state */ |
@@ -421,6 +423,7 @@ struct i2400m { | |||
421 | struct sk_buff *wake_tx_skb; | 423 | struct sk_buff *wake_tx_skb; |
422 | 424 | ||
423 | struct dentry *debugfs_dentry; | 425 | struct dentry *debugfs_dentry; |
426 | const char *fw_name; /* name of the current firmware image */ | ||
424 | }; | 427 | }; |
425 | 428 | ||
426 | 429 | ||
diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c index 123a5f8db6ad..5ac5e76701cd 100644 --- a/drivers/net/wimax/i2400m/sdio.c +++ b/drivers/net/wimax/i2400m/sdio.c | |||
@@ -70,8 +70,13 @@ | |||
70 | static int ioe_timeout = 2; | 70 | static int ioe_timeout = 2; |
71 | module_param(ioe_timeout, int, 0); | 71 | module_param(ioe_timeout, int, 0); |
72 | 72 | ||
73 | /* Our firmware file name */ | 73 | /* Our firmware file name list */ |
74 | #define I2400MS_FW_FILE_NAME "i2400m-fw-sdio-" I2400M_FW_VERSION ".sbcf" | 74 | static const char *i2400ms_bus_fw_names[] = { |
75 | #define I2400MS_FW_FILE_NAME "i2400m-fw-sdio-1.3.sbcf" | ||
76 | I2400MS_FW_FILE_NAME, | ||
77 | NULL | ||
78 | }; | ||
79 | |||
75 | 80 | ||
76 | /* | 81 | /* |
77 | * Enable the SDIO function | 82 | * Enable the SDIO function |
@@ -401,7 +406,7 @@ int i2400ms_probe(struct sdio_func *func, | |||
401 | i2400m->bus_reset = i2400ms_bus_reset; | 406 | i2400m->bus_reset = i2400ms_bus_reset; |
402 | i2400m->bus_bm_cmd_send = i2400ms_bus_bm_cmd_send; | 407 | i2400m->bus_bm_cmd_send = i2400ms_bus_bm_cmd_send; |
403 | i2400m->bus_bm_wait_for_ack = i2400ms_bus_bm_wait_for_ack; | 408 | i2400m->bus_bm_wait_for_ack = i2400ms_bus_bm_wait_for_ack; |
404 | i2400m->bus_fw_name = I2400MS_FW_FILE_NAME; | 409 | i2400m->bus_fw_names = i2400ms_bus_fw_names; |
405 | i2400m->bus_bm_mac_addr_impaired = 1; | 410 | i2400m->bus_bm_mac_addr_impaired = 1; |
406 | 411 | ||
407 | result = i2400ms_enable_function(i2400ms->func); | 412 | result = i2400ms_enable_function(i2400ms->func); |
diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c index 7c28610da6f3..ca4151a9e222 100644 --- a/drivers/net/wimax/i2400m/usb.c +++ b/drivers/net/wimax/i2400m/usb.c | |||
@@ -73,7 +73,14 @@ | |||
73 | 73 | ||
74 | 74 | ||
75 | /* Our firmware file name */ | 75 | /* Our firmware file name */ |
76 | #define I2400MU_FW_FILE_NAME "i2400m-fw-usb-" I2400M_FW_VERSION ".sbcf" | 76 | static const char *i2400mu_bus_fw_names[] = { |
77 | #define I2400MU_FW_FILE_NAME_v1_4 "i2400m-fw-usb-1.4.sbcf" | ||
78 | I2400MU_FW_FILE_NAME_v1_4, | ||
79 | #define I2400MU_FW_FILE_NAME_v1_3 "i2400m-fw-usb-1.3.sbcf" | ||
80 | I2400MU_FW_FILE_NAME_v1_3, | ||
81 | NULL, | ||
82 | }; | ||
83 | |||
77 | 84 | ||
78 | static | 85 | static |
79 | int i2400mu_bus_dev_start(struct i2400m *i2400m) | 86 | int i2400mu_bus_dev_start(struct i2400m *i2400m) |
@@ -394,7 +401,7 @@ int i2400mu_probe(struct usb_interface *iface, | |||
394 | i2400m->bus_reset = i2400mu_bus_reset; | 401 | i2400m->bus_reset = i2400mu_bus_reset; |
395 | i2400m->bus_bm_cmd_send = i2400mu_bus_bm_cmd_send; | 402 | i2400m->bus_bm_cmd_send = i2400mu_bus_bm_cmd_send; |
396 | i2400m->bus_bm_wait_for_ack = i2400mu_bus_bm_wait_for_ack; | 403 | i2400m->bus_bm_wait_for_ack = i2400mu_bus_bm_wait_for_ack; |
397 | i2400m->bus_fw_name = I2400MU_FW_FILE_NAME; | 404 | i2400m->bus_fw_names = i2400mu_bus_fw_names; |
398 | i2400m->bus_bm_mac_addr_impaired = 0; | 405 | i2400m->bus_bm_mac_addr_impaired = 0; |
399 | 406 | ||
400 | #ifdef CONFIG_PM | 407 | #ifdef CONFIG_PM |
@@ -594,4 +601,5 @@ module_exit(i2400mu_driver_exit); | |||
594 | MODULE_AUTHOR("Intel Corporation <linux-wimax@intel.com>"); | 601 | MODULE_AUTHOR("Intel Corporation <linux-wimax@intel.com>"); |
595 | MODULE_DESCRIPTION("Intel 2400M WiMAX networking for USB"); | 602 | MODULE_DESCRIPTION("Intel 2400M WiMAX networking for USB"); |
596 | MODULE_LICENSE("GPL"); | 603 | MODULE_LICENSE("GPL"); |
597 | MODULE_FIRMWARE(I2400MU_FW_FILE_NAME); | 604 | MODULE_FIRMWARE(I2400MU_FW_FILE_NAME_v1_4); |
605 | MODULE_FIRMWARE(I2400MU_FW_FILE_NAME_v1_3); | ||