diff options
| author | Shahar Levi <shahar_levi@ti.com> | 2011-03-06 09:32:10 -0500 |
|---|---|---|
| committer | Luciano Coelho <coelho@ti.com> | 2011-04-19 09:48:10 -0400 |
| commit | bc765bf3b9a095b3e41c8cda80643901884c3dd4 (patch) | |
| tree | debb36120cb682b9fb848f0876454547f285495f | |
| parent | 49d750ca14cd49e76ab039b33b5a621e0a92b9fd (diff) | |
wl12xx: 1281/1283 support - Loading FW & NVS
Take care of FW & NVS with the auto-detection between wl127x and
wl128x.
[Moved some common code outside if statements and added notes about
NVS structure assumptions; Fixed a bug when checking the nvs size: if
the size was incorrect, the local nvs variable was set to NULL, it
should be wl->nvs instead. -- Luca]
[Merged with potential buffer overflow fix -- Luca]
Signed-off-by: Shahar Levi <shahar_levi@ti.com>
Reviewed-by: Luciano Coelho <coelho@ti.com>
Signed-off-by: Luciano Coelho <coelho@ti.com>
| -rw-r--r-- | drivers/net/wireless/wl12xx/boot.c | 83 | ||||
| -rw-r--r-- | drivers/net/wireless/wl12xx/cmd.c | 11 | ||||
| -rw-r--r-- | drivers/net/wireless/wl12xx/ini.h | 4 | ||||
| -rw-r--r-- | drivers/net/wireless/wl12xx/main.c | 13 | ||||
| -rw-r--r-- | drivers/net/wireless/wl12xx/sdio_test.c | 9 | ||||
| -rw-r--r-- | drivers/net/wireless/wl12xx/testmode.c | 6 | ||||
| -rw-r--r-- | drivers/net/wireless/wl12xx/wl12xx.h | 2 |
7 files changed, 86 insertions, 42 deletions
diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c index 69fe8703be42..38f3e8ba2628 100644 --- a/drivers/net/wireless/wl12xx/boot.c +++ b/drivers/net/wireless/wl12xx/boot.c | |||
| @@ -243,33 +243,57 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) | |||
| 243 | if (wl->nvs == NULL) | 243 | if (wl->nvs == NULL) |
| 244 | return -ENODEV; | 244 | return -ENODEV; |
| 245 | 245 | ||
| 246 | /* | 246 | if (wl->chip.id == CHIP_ID_1283_PG20) { |
| 247 | * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz band | 247 | struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *)wl->nvs; |
| 248 | * configurations) can be removed when those NVS files stop floating | 248 | |
| 249 | * around. | 249 | if (wl->nvs_len == sizeof(struct wl128x_nvs_file)) { |
| 250 | */ | 250 | if (nvs->general_params.dual_mode_select) |
| 251 | if (wl->nvs_len == sizeof(struct wl1271_nvs_file) || | 251 | wl->enable_11a = true; |
| 252 | wl->nvs_len == WL1271_INI_LEGACY_NVS_FILE_SIZE) { | 252 | } else { |
| 253 | /* for now 11a is unsupported in AP mode */ | 253 | wl1271_error("nvs size is not as expected: %zu != %zu", |
| 254 | if (wl->bss_type != BSS_TYPE_AP_BSS && | 254 | wl->nvs_len, |
| 255 | wl->nvs->general_params.dual_mode_select) | 255 | sizeof(struct wl128x_nvs_file)); |
| 256 | wl->enable_11a = true; | 256 | kfree(wl->nvs); |
| 257 | } | 257 | wl->nvs = NULL; |
| 258 | wl->nvs_len = 0; | ||
| 259 | return -EILSEQ; | ||
| 260 | } | ||
| 258 | 261 | ||
| 259 | if (wl->nvs_len != sizeof(struct wl1271_nvs_file) && | 262 | /* only the first part of the NVS needs to be uploaded */ |
| 260 | (wl->nvs_len != WL1271_INI_LEGACY_NVS_FILE_SIZE || | 263 | nvs_len = sizeof(nvs->nvs); |
| 261 | wl->enable_11a)) { | 264 | nvs_ptr = (u8 *)nvs->nvs; |
| 262 | wl1271_error("nvs size is not as expected: %zu != %zu", | ||
| 263 | wl->nvs_len, sizeof(struct wl1271_nvs_file)); | ||
| 264 | kfree(wl->nvs); | ||
| 265 | wl->nvs = NULL; | ||
| 266 | wl->nvs_len = 0; | ||
| 267 | return -EILSEQ; | ||
| 268 | } | ||
| 269 | 265 | ||
| 270 | /* only the first part of the NVS needs to be uploaded */ | 266 | } else { |
| 271 | nvs_len = sizeof(wl->nvs->nvs); | 267 | struct wl1271_nvs_file *nvs = |
| 272 | nvs_ptr = (u8 *)wl->nvs->nvs; | 268 | (struct wl1271_nvs_file *)wl->nvs; |
| 269 | /* | ||
| 270 | * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz | ||
| 271 | * band configurations) can be removed when those NVS files stop | ||
| 272 | * floating around. | ||
| 273 | */ | ||
| 274 | if (wl->nvs_len == sizeof(struct wl1271_nvs_file) || | ||
| 275 | wl->nvs_len == WL1271_INI_LEGACY_NVS_FILE_SIZE) { | ||
| 276 | /* for now 11a is unsupported in AP mode */ | ||
| 277 | if (wl->bss_type != BSS_TYPE_AP_BSS && | ||
| 278 | nvs->general_params.dual_mode_select) | ||
| 279 | wl->enable_11a = true; | ||
| 280 | } | ||
| 281 | |||
| 282 | if (wl->nvs_len != sizeof(struct wl1271_nvs_file) && | ||
| 283 | (wl->nvs_len != WL1271_INI_LEGACY_NVS_FILE_SIZE || | ||
| 284 | wl->enable_11a)) { | ||
| 285 | wl1271_error("nvs size is not as expected: %zu != %zu", | ||
| 286 | wl->nvs_len, sizeof(struct wl1271_nvs_file)); | ||
| 287 | kfree(wl->nvs); | ||
| 288 | wl->nvs = NULL; | ||
| 289 | wl->nvs_len = 0; | ||
| 290 | return -EILSEQ; | ||
| 291 | } | ||
| 292 | |||
| 293 | /* only the first part of the NVS needs to be uploaded */ | ||
| 294 | nvs_len = sizeof(nvs->nvs); | ||
| 295 | nvs_ptr = (u8 *) nvs->nvs; | ||
| 296 | } | ||
| 273 | 297 | ||
| 274 | /* update current MAC address to NVS */ | 298 | /* update current MAC address to NVS */ |
| 275 | nvs_ptr[11] = wl->mac_addr[0]; | 299 | nvs_ptr[11] = wl->mac_addr[0]; |
| @@ -319,10 +343,13 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) | |||
| 319 | /* | 343 | /* |
| 320 | * We've reached the first zero length, the first NVS table | 344 | * We've reached the first zero length, the first NVS table |
| 321 | * is located at an aligned offset which is at least 7 bytes further. | 345 | * is located at an aligned offset which is at least 7 bytes further. |
| 346 | * NOTE: The wl->nvs->nvs element must be first, in order to | ||
| 347 | * simplify the casting, we assume it is at the beginning of | ||
| 348 | * the wl->nvs structure. | ||
| 322 | */ | 349 | */ |
| 323 | nvs_ptr = (u8 *)wl->nvs->nvs + | 350 | nvs_ptr = (u8 *)wl->nvs + |
| 324 | ALIGN(nvs_ptr - (u8 *)wl->nvs->nvs + 7, 4); | 351 | ALIGN(nvs_ptr - (u8 *)wl->nvs + 7, 4); |
| 325 | nvs_len -= nvs_ptr - (u8 *)wl->nvs->nvs; | 352 | nvs_len -= nvs_ptr - (u8 *)wl->nvs; |
| 326 | 353 | ||
| 327 | /* Now we must set the partition correctly */ | 354 | /* Now we must set the partition correctly */ |
| 328 | wl1271_set_partition(wl, &part_table[PART_WORK]); | 355 | wl1271_set_partition(wl, &part_table[PART_WORK]); |
diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index 37eb9f366942..246804428517 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c | |||
| @@ -187,8 +187,9 @@ out: | |||
| 187 | 187 | ||
| 188 | int wl1271_cmd_radio_parms(struct wl1271 *wl) | 188 | int wl1271_cmd_radio_parms(struct wl1271 *wl) |
| 189 | { | 189 | { |
| 190 | struct wl1271_nvs_file *nvs = (struct wl1271_nvs_file *)wl->nvs; | ||
| 190 | struct wl1271_radio_parms_cmd *radio_parms; | 191 | struct wl1271_radio_parms_cmd *radio_parms; |
| 191 | struct wl1271_ini_general_params *gp = &wl->nvs->general_params; | 192 | struct wl1271_ini_general_params *gp = &nvs->general_params; |
| 192 | int ret; | 193 | int ret; |
| 193 | 194 | ||
| 194 | if (!wl->nvs) | 195 | if (!wl->nvs) |
| @@ -201,18 +202,18 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl) | |||
| 201 | radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM; | 202 | radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM; |
| 202 | 203 | ||
| 203 | /* 2.4GHz parameters */ | 204 | /* 2.4GHz parameters */ |
| 204 | memcpy(&radio_parms->static_params_2, &wl->nvs->stat_radio_params_2, | 205 | memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2, |
| 205 | sizeof(struct wl1271_ini_band_params_2)); | 206 | sizeof(struct wl1271_ini_band_params_2)); |
| 206 | memcpy(&radio_parms->dyn_params_2, | 207 | memcpy(&radio_parms->dyn_params_2, |
| 207 | &wl->nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params, | 208 | &nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params, |
| 208 | sizeof(struct wl1271_ini_fem_params_2)); | 209 | sizeof(struct wl1271_ini_fem_params_2)); |
| 209 | 210 | ||
| 210 | /* 5GHz parameters */ | 211 | /* 5GHz parameters */ |
| 211 | memcpy(&radio_parms->static_params_5, | 212 | memcpy(&radio_parms->static_params_5, |
| 212 | &wl->nvs->stat_radio_params_5, | 213 | &nvs->stat_radio_params_5, |
| 213 | sizeof(struct wl1271_ini_band_params_5)); | 214 | sizeof(struct wl1271_ini_band_params_5)); |
| 214 | memcpy(&radio_parms->dyn_params_5, | 215 | memcpy(&radio_parms->dyn_params_5, |
| 215 | &wl->nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params, | 216 | &nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params, |
| 216 | sizeof(struct wl1271_ini_fem_params_5)); | 217 | sizeof(struct wl1271_ini_fem_params_5)); |
| 217 | 218 | ||
| 218 | wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ", | 219 | wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ", |
diff --git a/drivers/net/wireless/wl12xx/ini.h b/drivers/net/wireless/wl12xx/ini.h index 30efcd6643b1..1420c842b8f1 100644 --- a/drivers/net/wireless/wl12xx/ini.h +++ b/drivers/net/wireless/wl12xx/ini.h | |||
| @@ -174,7 +174,7 @@ struct wl128x_ini_fem_params_5 { | |||
| 174 | #define WL1271_INI_LEGACY_NVS_FILE_SIZE 800 | 174 | #define WL1271_INI_LEGACY_NVS_FILE_SIZE 800 |
| 175 | 175 | ||
| 176 | struct wl1271_nvs_file { | 176 | struct wl1271_nvs_file { |
| 177 | /* NVS section */ | 177 | /* NVS section - must be first! */ |
| 178 | u8 nvs[WL1271_INI_NVS_SECTION_SIZE]; | 178 | u8 nvs[WL1271_INI_NVS_SECTION_SIZE]; |
| 179 | 179 | ||
| 180 | /* INI section */ | 180 | /* INI section */ |
| @@ -195,7 +195,7 @@ struct wl1271_nvs_file { | |||
| 195 | } __packed; | 195 | } __packed; |
| 196 | 196 | ||
| 197 | struct wl128x_nvs_file { | 197 | struct wl128x_nvs_file { |
| 198 | /* NVS section */ | 198 | /* NVS section - must be first! */ |
| 199 | u8 nvs[WL1271_INI_NVS_SECTION_SIZE]; | 199 | u8 nvs[WL1271_INI_NVS_SECTION_SIZE]; |
| 200 | 200 | ||
| 201 | /* INI section */ | 201 | /* INI section */ |
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index e1fd005dd048..fe0cf47a656c 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c | |||
| @@ -804,7 +804,10 @@ static int wl1271_fetch_firmware(struct wl1271 *wl) | |||
| 804 | break; | 804 | break; |
| 805 | case BSS_TYPE_IBSS: | 805 | case BSS_TYPE_IBSS: |
| 806 | case BSS_TYPE_STA_BSS: | 806 | case BSS_TYPE_STA_BSS: |
| 807 | fw_name = WL1271_FW_NAME; | 807 | if (wl->chip.id == CHIP_ID_1283_PG20) |
| 808 | fw_name = WL128X_FW_NAME; | ||
| 809 | else | ||
| 810 | fw_name = WL1271_FW_NAME; | ||
| 808 | break; | 811 | break; |
| 809 | default: | 812 | default: |
| 810 | wl1271_error("no compatible firmware for bss_type %d", | 813 | wl1271_error("no compatible firmware for bss_type %d", |
| @@ -860,7 +863,7 @@ static int wl1271_fetch_nvs(struct wl1271 *wl) | |||
| 860 | return ret; | 863 | return ret; |
| 861 | } | 864 | } |
| 862 | 865 | ||
| 863 | wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL); | 866 | wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL); |
| 864 | 867 | ||
| 865 | if (!wl->nvs) { | 868 | if (!wl->nvs) { |
| 866 | wl1271_error("could not allocate memory for the nvs file"); | 869 | wl1271_error("could not allocate memory for the nvs file"); |
| @@ -3289,7 +3292,11 @@ int wl1271_register_hw(struct wl1271 *wl) | |||
| 3289 | 3292 | ||
| 3290 | ret = wl1271_fetch_nvs(wl); | 3293 | ret = wl1271_fetch_nvs(wl); |
| 3291 | if (ret == 0) { | 3294 | if (ret == 0) { |
| 3292 | u8 *nvs_ptr = (u8 *)wl->nvs->nvs; | 3295 | /* NOTE: The wl->nvs->nvs element must be first, in |
| 3296 | * order to simplify the casting, we assume it is at | ||
| 3297 | * the beginning of the wl->nvs structure. | ||
| 3298 | */ | ||
| 3299 | u8 *nvs_ptr = (u8 *)wl->nvs; | ||
| 3293 | 3300 | ||
| 3294 | wl->mac_addr[0] = nvs_ptr[11]; | 3301 | wl->mac_addr[0] = nvs_ptr[11]; |
| 3295 | wl->mac_addr[1] = nvs_ptr[10]; | 3302 | wl->mac_addr[1] = nvs_ptr[10]; |
diff --git a/drivers/net/wireless/wl12xx/sdio_test.c b/drivers/net/wireless/wl12xx/sdio_test.c index 01adf1b1003b..e6e2ad63a1c1 100644 --- a/drivers/net/wireless/wl12xx/sdio_test.c +++ b/drivers/net/wireless/wl12xx/sdio_test.c | |||
| @@ -189,7 +189,12 @@ static int wl1271_fetch_firmware(struct wl1271 *wl) | |||
| 189 | const struct firmware *fw; | 189 | const struct firmware *fw; |
| 190 | int ret; | 190 | int ret; |
| 191 | 191 | ||
| 192 | ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl)); | 192 | if (wl->chip.id == CHIP_ID_1283_PG20) |
| 193 | ret = request_firmware(&fw, WL128X_FW_NAME, | ||
| 194 | wl1271_wl_to_dev(wl)); | ||
| 195 | else | ||
| 196 | ret = request_firmware(&fw, WL1271_FW_NAME, | ||
| 197 | wl1271_wl_to_dev(wl)); | ||
| 193 | 198 | ||
| 194 | if (ret < 0) { | 199 | if (ret < 0) { |
| 195 | wl1271_error("could not get firmware: %d", ret); | 200 | wl1271_error("could not get firmware: %d", ret); |
| @@ -234,7 +239,7 @@ static int wl1271_fetch_nvs(struct wl1271 *wl) | |||
| 234 | return ret; | 239 | return ret; |
| 235 | } | 240 | } |
| 236 | 241 | ||
| 237 | wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL); | 242 | wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL); |
| 238 | 243 | ||
| 239 | if (!wl->nvs) { | 244 | if (!wl->nvs) { |
| 240 | wl1271_error("could not allocate memory for the nvs file"); | 245 | wl1271_error("could not allocate memory for the nvs file"); |
diff --git a/drivers/net/wireless/wl12xx/testmode.c b/drivers/net/wireless/wl12xx/testmode.c index 6ec06a4a4c6d..da351d7cd1f2 100644 --- a/drivers/net/wireless/wl12xx/testmode.c +++ b/drivers/net/wireless/wl12xx/testmode.c | |||
| @@ -27,6 +27,7 @@ | |||
| 27 | 27 | ||
| 28 | #include "wl12xx.h" | 28 | #include "wl12xx.h" |
| 29 | #include "acx.h" | 29 | #include "acx.h" |
| 30 | #include "reg.h" | ||
| 30 | 31 | ||
| 31 | #define WL1271_TM_MAX_DATA_LENGTH 1024 | 32 | #define WL1271_TM_MAX_DATA_LENGTH 1024 |
| 32 | 33 | ||
| @@ -204,7 +205,10 @@ static int wl1271_tm_cmd_nvs_push(struct wl1271 *wl, struct nlattr *tb[]) | |||
| 204 | 205 | ||
| 205 | kfree(wl->nvs); | 206 | kfree(wl->nvs); |
| 206 | 207 | ||
| 207 | if (len != sizeof(struct wl1271_nvs_file)) | 208 | if ((wl->chip.id == CHIP_ID_1283_PG20) && |
| 209 | (len != sizeof(struct wl128x_nvs_file))) | ||
| 210 | return -EINVAL; | ||
| 211 | else if (len != sizeof(struct wl1271_nvs_file)) | ||
| 208 | return -EINVAL; | 212 | return -EINVAL; |
| 209 | 213 | ||
| 210 | wl->nvs = kzalloc(len, GFP_KERNEL); | 214 | wl->nvs = kzalloc(len, GFP_KERNEL); |
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 959b338d0af4..e59f5392e909 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h | |||
| @@ -378,7 +378,7 @@ struct wl1271 { | |||
| 378 | u8 *fw; | 378 | u8 *fw; |
| 379 | size_t fw_len; | 379 | size_t fw_len; |
| 380 | u8 fw_bss_type; | 380 | u8 fw_bss_type; |
| 381 | struct wl1271_nvs_file *nvs; | 381 | void *nvs; |
| 382 | size_t nvs_len; | 382 | size_t nvs_len; |
| 383 | 383 | ||
| 384 | s8 hw_pg_ver; | 384 | s8 hw_pg_ver; |
