aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/wl12xx
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/wl12xx')
-rw-r--r--drivers/net/wireless/wl12xx/Kconfig4
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_main.c4
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_sdio.c41
-rw-r--r--drivers/net/wireless/wl12xx/wl1271.h31
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_cmd.c41
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_cmd.h28
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_event.c10
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_ini.h123
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_main.c95
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_sdio.c2
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_testmode.c11
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_tx.c36
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_tx.h1
13 files changed, 319 insertions, 108 deletions
diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig
index 337fc7bec5a5..2f98058be451 100644
--- a/drivers/net/wireless/wl12xx/Kconfig
+++ b/drivers/net/wireless/wl12xx/Kconfig
@@ -41,7 +41,7 @@ config WL1251_SDIO
41 41
42config WL1271 42config WL1271
43 tristate "TI wl1271 support" 43 tristate "TI wl1271 support"
44 depends on WL12XX && SPI_MASTER && GENERIC_HARDIRQS 44 depends on WL12XX && GENERIC_HARDIRQS
45 depends on INET 45 depends on INET
46 select FW_LOADER 46 select FW_LOADER
47 select CRC7 47 select CRC7
@@ -65,7 +65,7 @@ config WL1271_SPI
65 65
66config WL1271_SDIO 66config WL1271_SDIO
67 tristate "TI wl1271 SDIO support" 67 tristate "TI wl1271 SDIO support"
68 depends on WL1271 && MMC && ARM 68 depends on WL1271 && MMC
69 ---help--- 69 ---help---
70 This module adds support for the SDIO interface of adapters using 70 This module adds support for the SDIO interface of adapters using
71 TI wl1271 chipset. Select this if your platform is using 71 TI wl1271 chipset. Select this if your platform is using
diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c
index 00b24282fc73..c8f268951e10 100644
--- a/drivers/net/wireless/wl12xx/wl1251_main.c
+++ b/drivers/net/wireless/wl12xx/wl1251_main.c
@@ -124,7 +124,7 @@ static int wl1251_fetch_nvs(struct wl1251 *wl)
124 } 124 }
125 125
126 wl->nvs_len = fw->size; 126 wl->nvs_len = fw->size;
127 wl->nvs = kmalloc(wl->nvs_len, GFP_KERNEL); 127 wl->nvs = kmemdup(fw->data, wl->nvs_len, GFP_KERNEL);
128 128
129 if (!wl->nvs) { 129 if (!wl->nvs) {
130 wl1251_error("could not allocate memory for the nvs file"); 130 wl1251_error("could not allocate memory for the nvs file");
@@ -132,8 +132,6 @@ static int wl1251_fetch_nvs(struct wl1251 *wl)
132 goto out; 132 goto out;
133 } 133 }
134 134
135 memcpy(wl->nvs, fw->data, wl->nvs_len);
136
137 ret = 0; 135 ret = 0;
138 136
139out: 137out:
diff --git a/drivers/net/wireless/wl12xx/wl1251_sdio.c b/drivers/net/wireless/wl12xx/wl1251_sdio.c
index d234285c2c81..b901b6135654 100644
--- a/drivers/net/wireless/wl12xx/wl1251_sdio.c
+++ b/drivers/net/wireless/wl12xx/wl1251_sdio.c
@@ -37,11 +37,17 @@
37#define SDIO_DEVICE_ID_TI_WL1251 0x9066 37#define SDIO_DEVICE_ID_TI_WL1251 0x9066
38#endif 38#endif
39 39
40struct wl1251_sdio {
41 struct sdio_func *func;
42 u32 elp_val;
43};
44
40static struct wl12xx_platform_data *wl12xx_board_data; 45static struct wl12xx_platform_data *wl12xx_board_data;
41 46
42static struct sdio_func *wl_to_func(struct wl1251 *wl) 47static struct sdio_func *wl_to_func(struct wl1251 *wl)
43{ 48{
44 return wl->if_priv; 49 struct wl1251_sdio *wl_sdio = wl->if_priv;
50 return wl_sdio->func;
45} 51}
46 52
47static void wl1251_sdio_interrupt(struct sdio_func *func) 53static void wl1251_sdio_interrupt(struct sdio_func *func)
@@ -90,10 +96,17 @@ static void wl1251_sdio_write(struct wl1251 *wl, int addr,
90static void wl1251_sdio_read_elp(struct wl1251 *wl, int addr, u32 *val) 96static void wl1251_sdio_read_elp(struct wl1251 *wl, int addr, u32 *val)
91{ 97{
92 int ret = 0; 98 int ret = 0;
93 struct sdio_func *func = wl_to_func(wl); 99 struct wl1251_sdio *wl_sdio = wl->if_priv;
94 100 struct sdio_func *func = wl_sdio->func;
101
102 /*
103 * The hardware only supports RAW (read after write) access for
104 * reading, regular sdio_readb won't work here (it interprets
105 * the unused bits of CMD52 as write data even if we send read
106 * request).
107 */
95 sdio_claim_host(func); 108 sdio_claim_host(func);
96 *val = sdio_readb(func, addr, &ret); 109 *val = sdio_writeb_readb(func, wl_sdio->elp_val, addr, &ret);
97 sdio_release_host(func); 110 sdio_release_host(func);
98 111
99 if (ret) 112 if (ret)
@@ -103,7 +116,8 @@ static void wl1251_sdio_read_elp(struct wl1251 *wl, int addr, u32 *val)
103static void wl1251_sdio_write_elp(struct wl1251 *wl, int addr, u32 val) 116static void wl1251_sdio_write_elp(struct wl1251 *wl, int addr, u32 val)
104{ 117{
105 int ret = 0; 118 int ret = 0;
106 struct sdio_func *func = wl_to_func(wl); 119 struct wl1251_sdio *wl_sdio = wl->if_priv;
120 struct sdio_func *func = wl_sdio->func;
107 121
108 sdio_claim_host(func); 122 sdio_claim_host(func);
109 sdio_writeb(func, val, addr, &ret); 123 sdio_writeb(func, val, addr, &ret);
@@ -111,6 +125,8 @@ static void wl1251_sdio_write_elp(struct wl1251 *wl, int addr, u32 val)
111 125
112 if (ret) 126 if (ret)
113 wl1251_error("sdio_writeb failed (%d)", ret); 127 wl1251_error("sdio_writeb failed (%d)", ret);
128 else
129 wl_sdio->elp_val = val;
114} 130}
115 131
116static void wl1251_sdio_reset(struct wl1251 *wl) 132static void wl1251_sdio_reset(struct wl1251 *wl)
@@ -197,6 +213,7 @@ static int wl1251_sdio_probe(struct sdio_func *func,
197 int ret; 213 int ret;
198 struct wl1251 *wl; 214 struct wl1251 *wl;
199 struct ieee80211_hw *hw; 215 struct ieee80211_hw *hw;
216 struct wl1251_sdio *wl_sdio;
200 217
201 hw = wl1251_alloc_hw(); 218 hw = wl1251_alloc_hw();
202 if (IS_ERR(hw)) 219 if (IS_ERR(hw))
@@ -204,6 +221,12 @@ static int wl1251_sdio_probe(struct sdio_func *func,
204 221
205 wl = hw->priv; 222 wl = hw->priv;
206 223
224 wl_sdio = kzalloc(sizeof(*wl_sdio), GFP_KERNEL);
225 if (wl_sdio == NULL) {
226 ret = -ENOMEM;
227 goto out_free_hw;
228 }
229
207 sdio_claim_host(func); 230 sdio_claim_host(func);
208 ret = sdio_enable_func(func); 231 ret = sdio_enable_func(func);
209 if (ret) 232 if (ret)
@@ -213,7 +236,8 @@ static int wl1251_sdio_probe(struct sdio_func *func,
213 sdio_release_host(func); 236 sdio_release_host(func);
214 237
215 SET_IEEE80211_DEV(hw, &func->dev); 238 SET_IEEE80211_DEV(hw, &func->dev);
216 wl->if_priv = func; 239 wl_sdio->func = func;
240 wl->if_priv = wl_sdio;
217 wl->if_ops = &wl1251_sdio_ops; 241 wl->if_ops = &wl1251_sdio_ops;
218 wl->set_power = wl1251_sdio_set_power; 242 wl->set_power = wl1251_sdio_set_power;
219 243
@@ -259,15 +283,20 @@ disable:
259 sdio_disable_func(func); 283 sdio_disable_func(func);
260release: 284release:
261 sdio_release_host(func); 285 sdio_release_host(func);
286 kfree(wl_sdio);
287out_free_hw:
288 wl1251_free_hw(wl);
262 return ret; 289 return ret;
263} 290}
264 291
265static void __devexit wl1251_sdio_remove(struct sdio_func *func) 292static void __devexit wl1251_sdio_remove(struct sdio_func *func)
266{ 293{
267 struct wl1251 *wl = sdio_get_drvdata(func); 294 struct wl1251 *wl = sdio_get_drvdata(func);
295 struct wl1251_sdio *wl_sdio = wl->if_priv;
268 296
269 if (wl->irq) 297 if (wl->irq)
270 free_irq(wl->irq, wl); 298 free_irq(wl->irq, wl);
299 kfree(wl_sdio);
271 wl1251_free_hw(wl); 300 wl1251_free_hw(wl);
272 301
273 sdio_claim_host(func); 302 sdio_claim_host(func);
diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h
index 9af14646c278..ec09f0d40ca2 100644
--- a/drivers/net/wireless/wl12xx/wl1271.h
+++ b/drivers/net/wireless/wl12xx/wl1271.h
@@ -33,6 +33,7 @@
33#include <net/mac80211.h> 33#include <net/mac80211.h>
34 34
35#include "wl1271_conf.h" 35#include "wl1271_conf.h"
36#include "wl1271_ini.h"
36 37
37#define DRIVER_NAME "wl1271" 38#define DRIVER_NAME "wl1271"
38#define DRIVER_PREFIX DRIVER_NAME ": " 39#define DRIVER_PREFIX DRIVER_NAME ": "
@@ -116,33 +117,6 @@ enum {
116#define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff)) 117#define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff))
117#define WL1271_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff)) 118#define WL1271_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff))
118 119
119/* NVS data structure */
120#define WL1271_NVS_SECTION_SIZE 468
121
122#define WL1271_NVS_GENERAL_PARAMS_SIZE 57
123#define WL1271_NVS_GENERAL_PARAMS_SIZE_PADDED \
124 (WL1271_NVS_GENERAL_PARAMS_SIZE + 1)
125#define WL1271_NVS_STAT_RADIO_PARAMS_SIZE 17
126#define WL1271_NVS_STAT_RADIO_PARAMS_SIZE_PADDED \
127 (WL1271_NVS_STAT_RADIO_PARAMS_SIZE + 1)
128#define WL1271_NVS_DYN_RADIO_PARAMS_SIZE 65
129#define WL1271_NVS_DYN_RADIO_PARAMS_SIZE_PADDED \
130 (WL1271_NVS_DYN_RADIO_PARAMS_SIZE + 1)
131#define WL1271_NVS_FEM_COUNT 2
132#define WL1271_NVS_INI_SPARE_SIZE 124
133
134struct wl1271_nvs_file {
135 /* NVS section */
136 u8 nvs[WL1271_NVS_SECTION_SIZE];
137
138 /* INI section */
139 u8 general_params[WL1271_NVS_GENERAL_PARAMS_SIZE_PADDED];
140 u8 stat_radio_params[WL1271_NVS_STAT_RADIO_PARAMS_SIZE_PADDED];
141 u8 dyn_radio_params[WL1271_NVS_FEM_COUNT]
142 [WL1271_NVS_DYN_RADIO_PARAMS_SIZE_PADDED];
143 u8 ini_spare[WL1271_NVS_INI_SPARE_SIZE];
144} __packed;
145
146/* 120/*
147 * Enable/disable 802.11a support for WL1273 121 * Enable/disable 802.11a support for WL1273
148 */ 122 */
@@ -325,6 +299,7 @@ struct wl1271_rx_mem_pool_addr {
325}; 299};
326 300
327struct wl1271_scan { 301struct wl1271_scan {
302 struct cfg80211_scan_request *req;
328 u8 state; 303 u8 state;
329 u8 ssid[IW_ESSID_MAX_SIZE+1]; 304 u8 ssid[IW_ESSID_MAX_SIZE+1];
330 size_t ssid_len; 305 size_t ssid_len;
@@ -375,6 +350,7 @@ struct wl1271 {
375#define WL1271_FLAG_IRQ_PENDING (9) 350#define WL1271_FLAG_IRQ_PENDING (9)
376#define WL1271_FLAG_IRQ_RUNNING (10) 351#define WL1271_FLAG_IRQ_RUNNING (10)
377#define WL1271_FLAG_IDLE (11) 352#define WL1271_FLAG_IDLE (11)
353#define WL1271_FLAG_IDLE_REQUESTED (12)
378 unsigned long flags; 354 unsigned long flags;
379 355
380 struct wl1271_partition_set part; 356 struct wl1271_partition_set part;
@@ -421,6 +397,7 @@ struct wl1271 {
421 397
422 /* Pending TX frames */ 398 /* Pending TX frames */
423 struct sk_buff *tx_frames[ACX_TX_DESCRIPTORS]; 399 struct sk_buff *tx_frames[ACX_TX_DESCRIPTORS];
400 int tx_frames_cnt;
424 401
425 /* Security sequence number counters */ 402 /* Security sequence number counters */
426 u8 tx_security_last_seq; 403 u8 tx_security_last_seq;
diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c
index 19393e236e2c..530678e45a13 100644
--- a/drivers/net/wireless/wl12xx/wl1271_cmd.c
+++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c
@@ -212,8 +212,8 @@ int wl1271_cmd_general_parms(struct wl1271 *wl)
212 212
213 gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM; 213 gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM;
214 214
215 memcpy(gen_parms->params, wl->nvs->general_params, 215 memcpy(&gen_parms->general_params, &wl->nvs->general_params,
216 WL1271_NVS_GENERAL_PARAMS_SIZE); 216 sizeof(struct wl1271_ini_general_params));
217 217
218 ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), 0); 218 ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), 0);
219 if (ret < 0) 219 if (ret < 0)
@@ -238,13 +238,20 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
238 238
239 radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM; 239 radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM;
240 240
241 memcpy(radio_parms->stat_radio_params, wl->nvs->stat_radio_params, 241 /* 2.4GHz parameters */
242 WL1271_NVS_STAT_RADIO_PARAMS_SIZE); 242 memcpy(&radio_parms->static_params_2, &wl->nvs->stat_radio_params_2,
243 memcpy(radio_parms->dyn_radio_params, 243 sizeof(struct wl1271_ini_band_params_2));
244 wl->nvs->dyn_radio_params[rparam->fem], 244 memcpy(&radio_parms->dyn_params_2,
245 WL1271_NVS_DYN_RADIO_PARAMS_SIZE); 245 &wl->nvs->dyn_radio_params_2[rparam->fem].params,
246 246 sizeof(struct wl1271_ini_fem_params_2));
247 /* FIXME: current NVS is missing 5GHz parameters */ 247
248 /* 5GHz parameters */
249 memcpy(&radio_parms->static_params_5,
250 &wl->nvs->stat_radio_params_5,
251 sizeof(struct wl1271_ini_band_params_5));
252 memcpy(&radio_parms->dyn_params_5,
253 &wl->nvs->dyn_radio_params_5[rparam->fem].params,
254 sizeof(struct wl1271_ini_fem_params_5));
248 255
249 wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ", 256 wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ",
250 radio_parms, sizeof(*radio_parms)); 257 radio_parms, sizeof(*radio_parms));
@@ -329,12 +336,6 @@ int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type)
329 join->channel = wl->channel; 336 join->channel = wl->channel;
330 join->ssid_len = wl->ssid_len; 337 join->ssid_len = wl->ssid_len;
331 memcpy(join->ssid, wl->ssid, wl->ssid_len); 338 memcpy(join->ssid, wl->ssid, wl->ssid_len);
332 join->ctrl = WL1271_JOIN_CMD_CTRL_TX_FLUSH;
333
334 /* increment the session counter */
335 wl->session_counter++;
336 if (wl->session_counter >= SESSION_COUNTER_MAX)
337 wl->session_counter = 0;
338 339
339 join->ctrl |= wl->session_counter << WL1271_JOIN_CMD_TX_SESSION_OFFSET; 340 join->ctrl |= wl->session_counter << WL1271_JOIN_CMD_TX_SESSION_OFFSET;
340 341
@@ -517,7 +518,7 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send)
517 ps_params->send_null_data = send; 518 ps_params->send_null_data = send;
518 ps_params->retries = 5; 519 ps_params->retries = 5;
519 ps_params->hang_over_period = 1; 520 ps_params->hang_over_period = 1;
520 ps_params->null_data_rate = cpu_to_le32(1); /* 1 Mbps */ 521 ps_params->null_data_rate = cpu_to_le32(wl->basic_rate_set);
521 522
522 ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params, 523 ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params,
523 sizeof(*ps_params), 0); 524 sizeof(*ps_params), 0);
@@ -567,7 +568,7 @@ out:
567} 568}
568 569
569int wl1271_cmd_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, 570int wl1271_cmd_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
570 const u8 *ie, size_t ie_len, u8 active_scan, 571 struct cfg80211_scan_request *req, u8 active_scan,
571 u8 high_prio, u8 band, u8 probe_requests) 572 u8 high_prio, u8 band, u8 probe_requests)
572{ 573{
573 574
@@ -648,7 +649,7 @@ int wl1271_cmd_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
648 } 649 }
649 650
650 ret = wl1271_cmd_build_probe_req(wl, ssid, ssid_len, 651 ret = wl1271_cmd_build_probe_req(wl, ssid, ssid_len,
651 ie, ie_len, ieee_band); 652 req->ie, req->ie_len, ieee_band);
652 if (ret < 0) { 653 if (ret < 0) {
653 wl1271_error("PROBE request template failed"); 654 wl1271_error("PROBE request template failed");
654 goto out; 655 goto out;
@@ -684,7 +685,9 @@ int wl1271_cmd_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
684 memcpy(wl->scan.ssid, ssid, ssid_len); 685 memcpy(wl->scan.ssid, ssid, ssid_len);
685 } else 686 } else
686 wl->scan.ssid_len = 0; 687 wl->scan.ssid_len = 0;
687 } 688 wl->scan.req = req;
689 } else
690 wl->scan.req = NULL;
688 } 691 }
689 692
690 ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params), 0); 693 ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params), 0);
diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.h b/drivers/net/wireless/wl12xx/wl1271_cmd.h
index d88faf9d2642..f5745d829c9b 100644
--- a/drivers/net/wireless/wl12xx/wl1271_cmd.h
+++ b/drivers/net/wireless/wl12xx/wl1271_cmd.h
@@ -42,7 +42,7 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send);
42int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer, 42int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
43 size_t len); 43 size_t len);
44int wl1271_cmd_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, 44int wl1271_cmd_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
45 const u8 *ie, size_t ie_len, u8 active_scan, 45 struct cfg80211_scan_request *req, u8 active_scan,
46 u8 high_prio, u8 band, u8 probe_requests); 46 u8 high_prio, u8 band, u8 probe_requests);
47int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, 47int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
48 void *buf, size_t buf_len, int index, u32 rates); 48 void *buf, size_t buf_len, int index, u32 rates);
@@ -439,24 +439,30 @@ struct wl1271_general_parms_cmd {
439 439
440 struct wl1271_cmd_test_header test; 440 struct wl1271_cmd_test_header test;
441 441
442 u8 params[WL1271_NVS_GENERAL_PARAMS_SIZE]; 442 struct wl1271_ini_general_params general_params;
443 s8 reserved[23];
444} __packed;
445 443
446#define WL1271_STAT_RADIO_PARAMS_5_SIZE 29 444 u8 sr_debug_table[WL1271_INI_MAX_SMART_REFLEX_PARAM];
447#define WL1271_DYN_RADIO_PARAMS_5_SIZE 104 445 u8 sr_sen_n_p;
446 u8 sr_sen_n_p_gain;
447 u8 sr_sen_nrn;
448 u8 sr_sen_prn;
449 u8 padding[3];
450} __packed;
448 451
449struct wl1271_radio_parms_cmd { 452struct wl1271_radio_parms_cmd {
450 struct wl1271_cmd_header header; 453 struct wl1271_cmd_header header;
451 454
452 struct wl1271_cmd_test_header test; 455 struct wl1271_cmd_test_header test;
453 456
454 u8 stat_radio_params[WL1271_NVS_STAT_RADIO_PARAMS_SIZE]; 457 /* Static radio parameters */
455 u8 stat_radio_params_5[WL1271_STAT_RADIO_PARAMS_5_SIZE]; 458 struct wl1271_ini_band_params_2 static_params_2;
459 struct wl1271_ini_band_params_5 static_params_5;
456 460
457 u8 dyn_radio_params[WL1271_NVS_DYN_RADIO_PARAMS_SIZE]; 461 /* Dynamic radio parameters */
458 u8 reserved; 462 struct wl1271_ini_fem_params_2 dyn_params_2;
459 u8 dyn_radio_params_5[WL1271_DYN_RADIO_PARAMS_5_SIZE]; 463 u8 padding2;
464 struct wl1271_ini_fem_params_5 dyn_params_5;
465 u8 padding3[2];
460} __packed; 466} __packed;
461 467
462struct wl1271_cmd_cal_channel_tune { 468struct wl1271_cmd_cal_channel_tune {
diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c
index cf37aa6eb137..ca52cdec7a8f 100644
--- a/drivers/net/wireless/wl12xx/wl1271_event.c
+++ b/drivers/net/wireless/wl12xx/wl1271_event.c
@@ -43,11 +43,11 @@ static int wl1271_event_scan_complete(struct wl1271 *wl,
43 clear_bit(WL1271_FLAG_SCANNING, &wl->flags); 43 clear_bit(WL1271_FLAG_SCANNING, &wl->flags);
44 /* FIXME: ie missing! */ 44 /* FIXME: ie missing! */
45 wl1271_cmd_scan(wl, wl->scan.ssid, wl->scan.ssid_len, 45 wl1271_cmd_scan(wl, wl->scan.ssid, wl->scan.ssid_len,
46 NULL, 0, 46 wl->scan.req,
47 wl->scan.active, 47 wl->scan.active,
48 wl->scan.high_prio, 48 wl->scan.high_prio,
49 WL1271_SCAN_BAND_5_GHZ, 49 WL1271_SCAN_BAND_5_GHZ,
50 wl->scan.probe_requests); 50 wl->scan.probe_requests);
51 } else { 51 } else {
52 mutex_unlock(&wl->mutex); 52 mutex_unlock(&wl->mutex);
53 ieee80211_scan_completed(wl->hw, false); 53 ieee80211_scan_completed(wl->hw, false);
diff --git a/drivers/net/wireless/wl12xx/wl1271_ini.h b/drivers/net/wireless/wl12xx/wl1271_ini.h
new file mode 100644
index 000000000000..2313047d4015
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1271_ini.h
@@ -0,0 +1,123 @@
1/*
2 * This file is part of wl1271
3 *
4 * Copyright (C) 2010 Nokia Corporation
5 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#ifndef __WL1271_INI_H__
25#define __WL1271_INI_H__
26
27#define WL1271_INI_MAX_SMART_REFLEX_PARAM 16
28
29struct wl1271_ini_general_params {
30 u8 ref_clock;
31 u8 settling_time;
32 u8 clk_valid_on_wakeup;
33 u8 dc2dc_mode;
34 u8 dual_mode_select;
35 u8 tx_bip_fem_auto_detect;
36 u8 tx_bip_fem_manufacturer;
37 u8 general_settings;
38 u8 sr_state;
39 u8 srf1[WL1271_INI_MAX_SMART_REFLEX_PARAM];
40 u8 srf2[WL1271_INI_MAX_SMART_REFLEX_PARAM];
41 u8 srf3[WL1271_INI_MAX_SMART_REFLEX_PARAM];
42} __packed;
43
44#define WL1271_INI_RSSI_PROCESS_COMPENS_SIZE 15
45
46struct wl1271_ini_band_params_2 {
47 u8 rx_trace_insertion_loss;
48 u8 tx_trace_loss;
49 u8 rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE];
50} __packed;
51
52#define WL1271_INI_RATE_GROUP_COUNT 6
53#define WL1271_INI_CHANNEL_COUNT_2 14
54
55struct wl1271_ini_fem_params_2 {
56 __le16 tx_bip_ref_pd_voltage;
57 u8 tx_bip_ref_power;
58 u8 tx_bip_ref_offset;
59 u8 tx_per_rate_pwr_limits_normal[WL1271_INI_RATE_GROUP_COUNT];
60 u8 tx_per_rate_pwr_limits_degraded[WL1271_INI_RATE_GROUP_COUNT];
61 u8 tx_per_rate_pwr_limits_extreme[WL1271_INI_RATE_GROUP_COUNT];
62 u8 tx_per_chan_pwr_limits_11b[WL1271_INI_CHANNEL_COUNT_2];
63 u8 tx_per_chan_pwr_limits_ofdm[WL1271_INI_CHANNEL_COUNT_2];
64 u8 tx_pd_vs_rate_offsets[WL1271_INI_RATE_GROUP_COUNT];
65 u8 tx_ibias[WL1271_INI_RATE_GROUP_COUNT];
66 u8 rx_fem_insertion_loss;
67 u8 degraded_low_to_normal_thr;
68 u8 normal_to_degraded_high_thr;
69} __packed;
70
71#define WL1271_INI_CHANNEL_COUNT_5 35
72#define WL1271_INI_SUB_BAND_COUNT_5 7
73
74struct wl1271_ini_band_params_5 {
75 u8 rx_trace_insertion_loss[WL1271_INI_SUB_BAND_COUNT_5];
76 u8 tx_trace_loss[WL1271_INI_SUB_BAND_COUNT_5];
77 u8 rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE];
78} __packed;
79
80struct wl1271_ini_fem_params_5 {
81 __le16 tx_bip_ref_pd_voltage[WL1271_INI_SUB_BAND_COUNT_5];
82 u8 tx_bip_ref_power[WL1271_INI_SUB_BAND_COUNT_5];
83 u8 tx_bip_ref_offset[WL1271_INI_SUB_BAND_COUNT_5];
84 u8 tx_per_rate_pwr_limits_normal[WL1271_INI_RATE_GROUP_COUNT];
85 u8 tx_per_rate_pwr_limits_degraded[WL1271_INI_RATE_GROUP_COUNT];
86 u8 tx_per_rate_pwr_limits_extreme[WL1271_INI_RATE_GROUP_COUNT];
87 u8 tx_per_chan_pwr_limits_ofdm[WL1271_INI_CHANNEL_COUNT_5];
88 u8 tx_pd_vs_rate_offsets[WL1271_INI_RATE_GROUP_COUNT];
89 u8 tx_ibias[WL1271_INI_RATE_GROUP_COUNT];
90 u8 rx_fem_insertion_loss[WL1271_INI_SUB_BAND_COUNT_5];
91 u8 degraded_low_to_normal_thr;
92 u8 normal_to_degraded_high_thr;
93} __packed;
94
95
96/* NVS data structure */
97#define WL1271_INI_NVS_SECTION_SIZE 468
98#define WL1271_INI_FEM_MODULE_COUNT 2
99
100#define WL1271_INI_LEGACY_NVS_FILE_SIZE 800
101
102struct wl1271_nvs_file {
103 /* NVS section */
104 u8 nvs[WL1271_INI_NVS_SECTION_SIZE];
105
106 /* INI section */
107 struct wl1271_ini_general_params general_params;
108 u8 padding1;
109 struct wl1271_ini_band_params_2 stat_radio_params_2;
110 u8 padding2;
111 struct {
112 struct wl1271_ini_fem_params_2 params;
113 u8 padding;
114 } dyn_radio_params_2[WL1271_INI_FEM_MODULE_COUNT];
115 struct wl1271_ini_band_params_5 stat_radio_params_5;
116 u8 padding3;
117 struct {
118 struct wl1271_ini_fem_params_5 params;
119 u8 padding;
120 } dyn_radio_params_5[WL1271_INI_FEM_MODULE_COUNT];
121} __packed;
122
123#endif
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c
index b7d9137851ac..7a14da506d78 100644
--- a/drivers/net/wireless/wl12xx/wl1271_main.c
+++ b/drivers/net/wireless/wl12xx/wl1271_main.c
@@ -566,14 +566,21 @@ static int wl1271_fetch_nvs(struct wl1271 *wl)
566 return ret; 566 return ret;
567 } 567 }
568 568
569 if (fw->size != sizeof(struct wl1271_nvs_file)) { 569 /*
570 * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz band
571 * configurations) can be removed when those NVS files stop floating
572 * around.
573 */
574 if (fw->size != sizeof(struct wl1271_nvs_file) &&
575 (fw->size != WL1271_INI_LEGACY_NVS_FILE_SIZE ||
576 wl1271_11a_enabled())) {
570 wl1271_error("nvs size is not as expected: %zu != %zu", 577 wl1271_error("nvs size is not as expected: %zu != %zu",
571 fw->size, sizeof(struct wl1271_nvs_file)); 578 fw->size, sizeof(struct wl1271_nvs_file));
572 ret = -EILSEQ; 579 ret = -EILSEQ;
573 goto out; 580 goto out;
574 } 581 }
575 582
576 wl->nvs = kmalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL); 583 wl->nvs = kzalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL);
577 584
578 if (!wl->nvs) { 585 if (!wl->nvs) {
579 wl1271_error("could not allocate memory for the nvs file"); 586 wl1271_error("could not allocate memory for the nvs file");
@@ -581,7 +588,7 @@ static int wl1271_fetch_nvs(struct wl1271 *wl)
581 goto out; 588 goto out;
582 } 589 }
583 590
584 memcpy(wl->nvs, fw->data, sizeof(struct wl1271_nvs_file)); 591 memcpy(wl->nvs, fw->data, fw->size);
585 592
586out: 593out:
587 release_firmware(fw); 594 release_firmware(fw);
@@ -1044,7 +1051,7 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1044 mutex_lock(&wl->mutex); 1051 mutex_lock(&wl->mutex);
1045 1052
1046 /* let's notify MAC80211 about the remaining pending TX frames */ 1053 /* let's notify MAC80211 about the remaining pending TX frames */
1047 wl1271_tx_flush(wl); 1054 wl1271_tx_reset(wl);
1048 wl1271_power_off(wl); 1055 wl1271_power_off(wl);
1049 1056
1050 memset(wl->bssid, 0, ETH_ALEN); 1057 memset(wl->bssid, 0, ETH_ALEN);
@@ -1241,6 +1248,42 @@ static u32 wl1271_min_rate_get(struct wl1271 *wl)
1241 return rate; 1248 return rate;
1242} 1249}
1243 1250
1251static int wl1271_handle_idle(struct wl1271 *wl, bool idle)
1252{
1253 int ret;
1254
1255 if (idle) {
1256 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1257 ret = wl1271_unjoin(wl);
1258 if (ret < 0)
1259 goto out;
1260 }
1261 wl->rate_set = wl1271_min_rate_get(wl);
1262 wl->sta_rate_set = 0;
1263 ret = wl1271_acx_rate_policies(wl);
1264 if (ret < 0)
1265 goto out;
1266 ret = wl1271_acx_keep_alive_config(
1267 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1268 ACX_KEEP_ALIVE_TPL_INVALID);
1269 if (ret < 0)
1270 goto out;
1271 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1272 } else {
1273 /* increment the session counter */
1274 wl->session_counter++;
1275 if (wl->session_counter >= SESSION_COUNTER_MAX)
1276 wl->session_counter = 0;
1277 ret = wl1271_dummy_join(wl);
1278 if (ret < 0)
1279 goto out;
1280 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1281 }
1282
1283out:
1284 return ret;
1285}
1286
1244static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) 1287static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1245{ 1288{
1246 struct wl1271 *wl = hw->priv; 1289 struct wl1271 *wl = hw->priv;
@@ -1255,6 +1298,15 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1255 conf->power_level, 1298 conf->power_level,
1256 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use"); 1299 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
1257 1300
1301 /*
1302 * mac80211 will go to idle nearly immediately after transmitting some
1303 * frames, such as the deauth. To make sure those frames reach the air,
1304 * wait here until the TX queue is fully flushed.
1305 */
1306 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1307 (conf->flags & IEEE80211_CONF_IDLE))
1308 wl1271_tx_flush(wl);
1309
1258 mutex_lock(&wl->mutex); 1310 mutex_lock(&wl->mutex);
1259 1311
1260 if (unlikely(wl->state == WL1271_STATE_OFF)) 1312 if (unlikely(wl->state == WL1271_STATE_OFF))
@@ -1295,22 +1347,9 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1295 } 1347 }
1296 1348
1297 if (changed & IEEE80211_CONF_CHANGE_IDLE) { 1349 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
1298 if (conf->flags & IEEE80211_CONF_IDLE && 1350 ret = wl1271_handle_idle(wl, conf->flags & IEEE80211_CONF_IDLE);
1299 test_bit(WL1271_FLAG_JOINED, &wl->flags)) 1351 if (ret < 0)
1300 wl1271_unjoin(wl); 1352 wl1271_warning("idle mode change failed %d", ret);
1301 else if (!(conf->flags & IEEE80211_CONF_IDLE))
1302 wl1271_dummy_join(wl);
1303
1304 if (conf->flags & IEEE80211_CONF_IDLE) {
1305 wl->rate_set = wl1271_min_rate_get(wl);
1306 wl->sta_rate_set = 0;
1307 wl1271_acx_rate_policies(wl);
1308 wl1271_acx_keep_alive_config(
1309 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1310 ACX_KEEP_ALIVE_TPL_INVALID);
1311 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1312 } else
1313 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1314 } 1353 }
1315 1354
1316 if (conf->flags & IEEE80211_CONF_PS && 1355 if (conf->flags & IEEE80211_CONF_PS &&
@@ -1595,13 +1634,11 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
1595 goto out; 1634 goto out;
1596 1635
1597 if (wl1271_11a_enabled()) 1636 if (wl1271_11a_enabled())
1598 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1637 ret = wl1271_cmd_scan(hw->priv, ssid, len, req,
1599 req->ie, req->ie_len, 1, 0, 1638 1, 0, WL1271_SCAN_BAND_DUAL, 3);
1600 WL1271_SCAN_BAND_DUAL, 3);
1601 else 1639 else
1602 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1640 ret = wl1271_cmd_scan(hw->priv, ssid, len, req,
1603 req->ie, req->ie_len, 1, 0, 1641 1, 0, WL1271_SCAN_BAND_2_4_GHZ, 3);
1604 WL1271_SCAN_BAND_2_4_GHZ, 3);
1605 1642
1606 wl1271_ps_elp_sleep(wl); 1643 wl1271_ps_elp_sleep(wl);
1607 1644
@@ -1991,7 +2028,7 @@ static struct ieee80211_channel wl1271_channels[] = {
1991}; 2028};
1992 2029
1993/* mapping to indexes for wl1271_rates */ 2030/* mapping to indexes for wl1271_rates */
1994const static u8 wl1271_rate_to_idx_2ghz[] = { 2031static const u8 wl1271_rate_to_idx_2ghz[] = {
1995 /* MCS rates are used only with 11n */ 2032 /* MCS rates are used only with 11n */
1996 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */ 2033 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
1997 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */ 2034 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
@@ -2103,7 +2140,7 @@ static struct ieee80211_channel wl1271_channels_5ghz[] = {
2103}; 2140};
2104 2141
2105/* mapping to indexes for wl1271_rates_5ghz */ 2142/* mapping to indexes for wl1271_rates_5ghz */
2106const static u8 wl1271_rate_to_idx_5ghz[] = { 2143static const u8 wl1271_rate_to_idx_5ghz[] = {
2107 /* MCS rates are used only with 11n */ 2144 /* MCS rates are used only with 11n */
2108 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */ 2145 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
2109 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */ 2146 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
@@ -2139,7 +2176,7 @@ static struct ieee80211_supported_band wl1271_band_5ghz = {
2139 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz), 2176 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
2140}; 2177};
2141 2178
2142const static u8 *wl1271_band_rate_to_idx[] = { 2179static const u8 *wl1271_band_rate_to_idx[] = {
2143 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz, 2180 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2144 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz 2181 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2145}; 2182};
diff --git a/drivers/net/wireless/wl12xx/wl1271_sdio.c b/drivers/net/wireless/wl12xx/wl1271_sdio.c
index d3d6f302f705..7059b5cccf0f 100644
--- a/drivers/net/wireless/wl12xx/wl1271_sdio.c
+++ b/drivers/net/wireless/wl12xx/wl1271_sdio.c
@@ -28,7 +28,7 @@
28#include <linux/mmc/sdio_func.h> 28#include <linux/mmc/sdio_func.h>
29#include <linux/mmc/sdio_ids.h> 29#include <linux/mmc/sdio_ids.h>
30#include <linux/mmc/card.h> 30#include <linux/mmc/card.h>
31#include <plat/gpio.h> 31#include <linux/gpio.h>
32 32
33#include "wl1271.h" 33#include "wl1271.h"
34#include "wl12xx_80211.h" 34#include "wl12xx_80211.h"
diff --git a/drivers/net/wireless/wl12xx/wl1271_testmode.c b/drivers/net/wireless/wl12xx/wl1271_testmode.c
index 554deb4d024e..6e0952f79e9a 100644
--- a/drivers/net/wireless/wl12xx/wl1271_testmode.c
+++ b/drivers/net/wireless/wl12xx/wl1271_testmode.c
@@ -199,7 +199,14 @@ static int wl1271_tm_cmd_nvs_push(struct wl1271 *wl, struct nlattr *tb[])
199 buf = nla_data(tb[WL1271_TM_ATTR_DATA]); 199 buf = nla_data(tb[WL1271_TM_ATTR_DATA]);
200 len = nla_len(tb[WL1271_TM_ATTR_DATA]); 200 len = nla_len(tb[WL1271_TM_ATTR_DATA]);
201 201
202 if (len != sizeof(struct wl1271_nvs_file)) { 202 /*
203 * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz band
204 * configurations) can be removed when those NVS files stop floating
205 * around.
206 */
207 if (len != sizeof(struct wl1271_nvs_file) &&
208 (len != WL1271_INI_LEGACY_NVS_FILE_SIZE ||
209 wl1271_11a_enabled())) {
203 wl1271_error("nvs size is not as expected: %zu != %zu", 210 wl1271_error("nvs size is not as expected: %zu != %zu",
204 len, sizeof(struct wl1271_nvs_file)); 211 len, sizeof(struct wl1271_nvs_file));
205 return -EMSGSIZE; 212 return -EMSGSIZE;
@@ -209,7 +216,7 @@ static int wl1271_tm_cmd_nvs_push(struct wl1271 *wl, struct nlattr *tb[])
209 216
210 kfree(wl->nvs); 217 kfree(wl->nvs);
211 218
212 wl->nvs = kmalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL); 219 wl->nvs = kzalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL);
213 if (!wl->nvs) { 220 if (!wl->nvs) {
214 wl1271_error("could not allocate memory for the nvs file"); 221 wl1271_error("could not allocate memory for the nvs file");
215 ret = -ENOMEM; 222 ret = -ENOMEM;
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c
index 62db79508ddf..c592cc2e9fe8 100644
--- a/drivers/net/wireless/wl12xx/wl1271_tx.c
+++ b/drivers/net/wireless/wl12xx/wl1271_tx.c
@@ -36,6 +36,7 @@ static int wl1271_tx_id(struct wl1271 *wl, struct sk_buff *skb)
36 for (i = 0; i < ACX_TX_DESCRIPTORS; i++) 36 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
37 if (wl->tx_frames[i] == NULL) { 37 if (wl->tx_frames[i] == NULL) {
38 wl->tx_frames[i] = skb; 38 wl->tx_frames[i] = skb;
39 wl->tx_frames_cnt++;
39 return i; 40 return i;
40 } 41 }
41 42
@@ -73,8 +74,10 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra)
73 wl1271_debug(DEBUG_TX, 74 wl1271_debug(DEBUG_TX,
74 "tx_allocate: size: %d, blocks: %d, id: %d", 75 "tx_allocate: size: %d, blocks: %d, id: %d",
75 total_len, total_blocks, id); 76 total_len, total_blocks, id);
76 } else 77 } else {
77 wl->tx_frames[id] = NULL; 78 wl->tx_frames[id] = NULL;
79 wl->tx_frames_cnt--;
80 }
78 81
79 return ret; 82 return ret;
80} 83}
@@ -358,6 +361,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
358 /* return the packet to the stack */ 361 /* return the packet to the stack */
359 ieee80211_tx_status(wl->hw, skb); 362 ieee80211_tx_status(wl->hw, skb);
360 wl->tx_frames[result->id] = NULL; 363 wl->tx_frames[result->id] = NULL;
364 wl->tx_frames_cnt--;
361} 365}
362 366
363/* Called upon reception of a TX complete interrupt */ 367/* Called upon reception of a TX complete interrupt */
@@ -412,7 +416,7 @@ void wl1271_tx_complete(struct wl1271 *wl)
412} 416}
413 417
414/* caller must hold wl->mutex */ 418/* caller must hold wl->mutex */
415void wl1271_tx_flush(struct wl1271 *wl) 419void wl1271_tx_reset(struct wl1271 *wl)
416{ 420{
417 int i; 421 int i;
418 struct sk_buff *skb; 422 struct sk_buff *skb;
@@ -421,7 +425,7 @@ void wl1271_tx_flush(struct wl1271 *wl)
421/* control->flags = 0; FIXME */ 425/* control->flags = 0; FIXME */
422 426
423 while ((skb = skb_dequeue(&wl->tx_queue))) { 427 while ((skb = skb_dequeue(&wl->tx_queue))) {
424 wl1271_debug(DEBUG_TX, "flushing skb 0x%p", skb); 428 wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb);
425 ieee80211_tx_status(wl->hw, skb); 429 ieee80211_tx_status(wl->hw, skb);
426 } 430 }
427 431
@@ -429,6 +433,32 @@ void wl1271_tx_flush(struct wl1271 *wl)
429 if (wl->tx_frames[i] != NULL) { 433 if (wl->tx_frames[i] != NULL) {
430 skb = wl->tx_frames[i]; 434 skb = wl->tx_frames[i];
431 wl->tx_frames[i] = NULL; 435 wl->tx_frames[i] = NULL;
436 wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb);
432 ieee80211_tx_status(wl->hw, skb); 437 ieee80211_tx_status(wl->hw, skb);
433 } 438 }
439 wl->tx_frames_cnt = 0;
440}
441
442#define WL1271_TX_FLUSH_TIMEOUT 500000
443
444/* caller must *NOT* hold wl->mutex */
445void wl1271_tx_flush(struct wl1271 *wl)
446{
447 unsigned long timeout;
448 timeout = jiffies + usecs_to_jiffies(WL1271_TX_FLUSH_TIMEOUT);
449
450 while (!time_after(jiffies, timeout)) {
451 mutex_lock(&wl->mutex);
452 wl1271_debug(DEBUG_TX, "flushing tx buffer: %d",
453 wl->tx_frames_cnt);
454 if ((wl->tx_frames_cnt == 0) &&
455 skb_queue_empty(&wl->tx_queue)) {
456 mutex_unlock(&wl->mutex);
457 return;
458 }
459 mutex_unlock(&wl->mutex);
460 msleep(1);
461 }
462
463 wl1271_warning("Unable to flush all TX buffers, timed out.");
434} 464}
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.h b/drivers/net/wireless/wl12xx/wl1271_tx.h
index 91d0adb0ea40..48bf92621c03 100644
--- a/drivers/net/wireless/wl12xx/wl1271_tx.h
+++ b/drivers/net/wireless/wl12xx/wl1271_tx.h
@@ -158,6 +158,7 @@ static inline int wl1271_tx_ac_to_tid(int ac)
158 158
159void wl1271_tx_work(struct work_struct *work); 159void wl1271_tx_work(struct work_struct *work);
160void wl1271_tx_complete(struct wl1271 *wl); 160void wl1271_tx_complete(struct wl1271 *wl);
161void wl1271_tx_reset(struct wl1271 *wl);
161void wl1271_tx_flush(struct wl1271 *wl); 162void wl1271_tx_flush(struct wl1271 *wl);
162u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate); 163u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate);
163u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set); 164u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set);