aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShahar Levi <shahar_levi@ti.com>2011-03-06 09:32:10 -0500
committerLuciano Coelho <coelho@ti.com>2011-04-19 09:48:10 -0400
commitbc765bf3b9a095b3e41c8cda80643901884c3dd4 (patch)
treedebb36120cb682b9fb848f0876454547f285495f
parent49d750ca14cd49e76ab039b33b5a621e0a92b9fd (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.c83
-rw-r--r--drivers/net/wireless/wl12xx/cmd.c11
-rw-r--r--drivers/net/wireless/wl12xx/ini.h4
-rw-r--r--drivers/net/wireless/wl12xx/main.c13
-rw-r--r--drivers/net/wireless/wl12xx/sdio_test.c9
-rw-r--r--drivers/net/wireless/wl12xx/testmode.c6
-rw-r--r--drivers/net/wireless/wl12xx/wl12xx.h2
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
188int wl1271_cmd_radio_parms(struct wl1271 *wl) 188int 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
176struct wl1271_nvs_file { 176struct 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
197struct wl128x_nvs_file { 197struct 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;