Commit bc765bf3 authored by Shahar Levi's avatar Shahar Levi Committed by Luciano Coelho

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: default avatarShahar Levi <shahar_levi@ti.com>
Reviewed-by: default avatarLuciano Coelho <coelho@ti.com>
Signed-off-by: default avatarLuciano Coelho <coelho@ti.com>
parent 49d750ca
...@@ -243,16 +243,39 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) ...@@ -243,16 +243,39 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
if (wl->nvs == NULL) if (wl->nvs == NULL)
return -ENODEV; return -ENODEV;
if (wl->chip.id == CHIP_ID_1283_PG20) {
struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *)wl->nvs;
if (wl->nvs_len == sizeof(struct wl128x_nvs_file)) {
if (nvs->general_params.dual_mode_select)
wl->enable_11a = true;
} else {
wl1271_error("nvs size is not as expected: %zu != %zu",
wl->nvs_len,
sizeof(struct wl128x_nvs_file));
kfree(wl->nvs);
wl->nvs = NULL;
wl->nvs_len = 0;
return -EILSEQ;
}
/* only the first part of the NVS needs to be uploaded */
nvs_len = sizeof(nvs->nvs);
nvs_ptr = (u8 *)nvs->nvs;
} else {
struct wl1271_nvs_file *nvs =
(struct wl1271_nvs_file *)wl->nvs;
/* /*
* FIXME: the LEGACY NVS image support (NVS's missing the 5GHz band * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz
* configurations) can be removed when those NVS files stop floating * band configurations) can be removed when those NVS files stop
* around. * floating around.
*/ */
if (wl->nvs_len == sizeof(struct wl1271_nvs_file) || if (wl->nvs_len == sizeof(struct wl1271_nvs_file) ||
wl->nvs_len == WL1271_INI_LEGACY_NVS_FILE_SIZE) { wl->nvs_len == WL1271_INI_LEGACY_NVS_FILE_SIZE) {
/* for now 11a is unsupported in AP mode */ /* for now 11a is unsupported in AP mode */
if (wl->bss_type != BSS_TYPE_AP_BSS && if (wl->bss_type != BSS_TYPE_AP_BSS &&
wl->nvs->general_params.dual_mode_select) nvs->general_params.dual_mode_select)
wl->enable_11a = true; wl->enable_11a = true;
} }
...@@ -268,8 +291,9 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) ...@@ -268,8 +291,9 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
} }
/* only the first part of the NVS needs to be uploaded */ /* only the first part of the NVS needs to be uploaded */
nvs_len = sizeof(wl->nvs->nvs); nvs_len = sizeof(nvs->nvs);
nvs_ptr = (u8 *)wl->nvs->nvs; nvs_ptr = (u8 *) nvs->nvs;
}
/* update current MAC address to NVS */ /* update current MAC address to NVS */
nvs_ptr[11] = wl->mac_addr[0]; nvs_ptr[11] = wl->mac_addr[0];
...@@ -319,10 +343,13 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) ...@@ -319,10 +343,13 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
/* /*
* We've reached the first zero length, the first NVS table * We've reached the first zero length, the first NVS table
* is located at an aligned offset which is at least 7 bytes further. * is located at an aligned offset which is at least 7 bytes further.
* NOTE: The wl->nvs->nvs element must be first, in order to
* simplify the casting, we assume it is at the beginning of
* the wl->nvs structure.
*/ */
nvs_ptr = (u8 *)wl->nvs->nvs + nvs_ptr = (u8 *)wl->nvs +
ALIGN(nvs_ptr - (u8 *)wl->nvs->nvs + 7, 4); ALIGN(nvs_ptr - (u8 *)wl->nvs + 7, 4);
nvs_len -= nvs_ptr - (u8 *)wl->nvs->nvs; nvs_len -= nvs_ptr - (u8 *)wl->nvs;
/* Now we must set the partition correctly */ /* Now we must set the partition correctly */
wl1271_set_partition(wl, &part_table[PART_WORK]); wl1271_set_partition(wl, &part_table[PART_WORK]);
......
...@@ -187,8 +187,9 @@ int wl128x_cmd_general_parms(struct wl1271 *wl) ...@@ -187,8 +187,9 @@ int wl128x_cmd_general_parms(struct wl1271 *wl)
int wl1271_cmd_radio_parms(struct wl1271 *wl) int wl1271_cmd_radio_parms(struct wl1271 *wl)
{ {
struct wl1271_nvs_file *nvs = (struct wl1271_nvs_file *)wl->nvs;
struct wl1271_radio_parms_cmd *radio_parms; struct wl1271_radio_parms_cmd *radio_parms;
struct wl1271_ini_general_params *gp = &wl->nvs->general_params; struct wl1271_ini_general_params *gp = &nvs->general_params;
int ret; int ret;
if (!wl->nvs) if (!wl->nvs)
...@@ -201,18 +202,18 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl) ...@@ -201,18 +202,18 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM; radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM;
/* 2.4GHz parameters */ /* 2.4GHz parameters */
memcpy(&radio_parms->static_params_2, &wl->nvs->stat_radio_params_2, memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2,
sizeof(struct wl1271_ini_band_params_2)); sizeof(struct wl1271_ini_band_params_2));
memcpy(&radio_parms->dyn_params_2, memcpy(&radio_parms->dyn_params_2,
&wl->nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params, &nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params,
sizeof(struct wl1271_ini_fem_params_2)); sizeof(struct wl1271_ini_fem_params_2));
/* 5GHz parameters */ /* 5GHz parameters */
memcpy(&radio_parms->static_params_5, memcpy(&radio_parms->static_params_5,
&wl->nvs->stat_radio_params_5, &nvs->stat_radio_params_5,
sizeof(struct wl1271_ini_band_params_5)); sizeof(struct wl1271_ini_band_params_5));
memcpy(&radio_parms->dyn_params_5, memcpy(&radio_parms->dyn_params_5,
&wl->nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params, &nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params,
sizeof(struct wl1271_ini_fem_params_5)); sizeof(struct wl1271_ini_fem_params_5));
wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ", wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ",
......
...@@ -174,7 +174,7 @@ struct wl128x_ini_fem_params_5 { ...@@ -174,7 +174,7 @@ struct wl128x_ini_fem_params_5 {
#define WL1271_INI_LEGACY_NVS_FILE_SIZE 800 #define WL1271_INI_LEGACY_NVS_FILE_SIZE 800
struct wl1271_nvs_file { struct wl1271_nvs_file {
/* NVS section */ /* NVS section - must be first! */
u8 nvs[WL1271_INI_NVS_SECTION_SIZE]; u8 nvs[WL1271_INI_NVS_SECTION_SIZE];
/* INI section */ /* INI section */
...@@ -195,7 +195,7 @@ struct wl1271_nvs_file { ...@@ -195,7 +195,7 @@ struct wl1271_nvs_file {
} __packed; } __packed;
struct wl128x_nvs_file { struct wl128x_nvs_file {
/* NVS section */ /* NVS section - must be first! */
u8 nvs[WL1271_INI_NVS_SECTION_SIZE]; u8 nvs[WL1271_INI_NVS_SECTION_SIZE];
/* INI section */ /* INI section */
......
...@@ -804,6 +804,9 @@ static int wl1271_fetch_firmware(struct wl1271 *wl) ...@@ -804,6 +804,9 @@ static int wl1271_fetch_firmware(struct wl1271 *wl)
break; break;
case BSS_TYPE_IBSS: case BSS_TYPE_IBSS:
case BSS_TYPE_STA_BSS: case BSS_TYPE_STA_BSS:
if (wl->chip.id == CHIP_ID_1283_PG20)
fw_name = WL128X_FW_NAME;
else
fw_name = WL1271_FW_NAME; fw_name = WL1271_FW_NAME;
break; break;
default: default:
...@@ -860,7 +863,7 @@ static int wl1271_fetch_nvs(struct wl1271 *wl) ...@@ -860,7 +863,7 @@ static int wl1271_fetch_nvs(struct wl1271 *wl)
return ret; return ret;
} }
wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL); wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
if (!wl->nvs) { if (!wl->nvs) {
wl1271_error("could not allocate memory for the nvs file"); wl1271_error("could not allocate memory for the nvs file");
...@@ -3289,7 +3292,11 @@ int wl1271_register_hw(struct wl1271 *wl) ...@@ -3289,7 +3292,11 @@ int wl1271_register_hw(struct wl1271 *wl)
ret = wl1271_fetch_nvs(wl); ret = wl1271_fetch_nvs(wl);
if (ret == 0) { if (ret == 0) {
u8 *nvs_ptr = (u8 *)wl->nvs->nvs; /* NOTE: The wl->nvs->nvs element must be first, in
* order to simplify the casting, we assume it is at
* the beginning of the wl->nvs structure.
*/
u8 *nvs_ptr = (u8 *)wl->nvs;
wl->mac_addr[0] = nvs_ptr[11]; wl->mac_addr[0] = nvs_ptr[11];
wl->mac_addr[1] = nvs_ptr[10]; wl->mac_addr[1] = nvs_ptr[10];
......
...@@ -189,7 +189,12 @@ static int wl1271_fetch_firmware(struct wl1271 *wl) ...@@ -189,7 +189,12 @@ static int wl1271_fetch_firmware(struct wl1271 *wl)
const struct firmware *fw; const struct firmware *fw;
int ret; int ret;
ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl)); if (wl->chip.id == CHIP_ID_1283_PG20)
ret = request_firmware(&fw, WL128X_FW_NAME,
wl1271_wl_to_dev(wl));
else
ret = request_firmware(&fw, WL1271_FW_NAME,
wl1271_wl_to_dev(wl));
if (ret < 0) { if (ret < 0) {
wl1271_error("could not get firmware: %d", ret); wl1271_error("could not get firmware: %d", ret);
...@@ -234,7 +239,7 @@ static int wl1271_fetch_nvs(struct wl1271 *wl) ...@@ -234,7 +239,7 @@ static int wl1271_fetch_nvs(struct wl1271 *wl)
return ret; return ret;
} }
wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL); wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
if (!wl->nvs) { if (!wl->nvs) {
wl1271_error("could not allocate memory for the nvs file"); wl1271_error("could not allocate memory for the nvs file");
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "wl12xx.h" #include "wl12xx.h"
#include "acx.h" #include "acx.h"
#include "reg.h"
#define WL1271_TM_MAX_DATA_LENGTH 1024 #define WL1271_TM_MAX_DATA_LENGTH 1024
...@@ -204,7 +205,10 @@ static int wl1271_tm_cmd_nvs_push(struct wl1271 *wl, struct nlattr *tb[]) ...@@ -204,7 +205,10 @@ static int wl1271_tm_cmd_nvs_push(struct wl1271 *wl, struct nlattr *tb[])
kfree(wl->nvs); kfree(wl->nvs);
if (len != sizeof(struct wl1271_nvs_file)) if ((wl->chip.id == CHIP_ID_1283_PG20) &&
(len != sizeof(struct wl128x_nvs_file)))
return -EINVAL;
else if (len != sizeof(struct wl1271_nvs_file))
return -EINVAL; return -EINVAL;
wl->nvs = kzalloc(len, GFP_KERNEL); wl->nvs = kzalloc(len, GFP_KERNEL);
......
...@@ -378,7 +378,7 @@ struct wl1271 { ...@@ -378,7 +378,7 @@ struct wl1271 {
u8 *fw; u8 *fw;
size_t fw_len; size_t fw_len;
u8 fw_bss_type; u8 fw_bss_type;
struct wl1271_nvs_file *nvs; void *nvs;
size_t nvs_len; size_t nvs_len;
s8 hw_pg_ver; s8 hw_pg_ver;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment