diff options
author | David S. Miller <davem@davemloft.net> | 2010-06-11 14:34:06 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-06-11 14:34:06 -0400 |
commit | 14599f1e341ee219abdd15f4eee5872d6f2d29f1 (patch) | |
tree | 3875181429010e58416ab34e6c06ef42de52e756 /drivers/net/wireless/wl12xx | |
parent | d8d1f30b95a635dbd610dcc5eb641aca8f4768cf (diff) | |
parent | 832c10fd733893f86c63bde1c65b005d5a2fe346 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Conflicts:
drivers/net/wireless/wl12xx/wl1271.h
drivers/net/wireless/wl12xx/wl1271_cmd.h
Diffstat (limited to 'drivers/net/wireless/wl12xx')
-rw-r--r-- | drivers/net/wireless/wl12xx/Kconfig | 4 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1251_main.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1251_sdio.c | 41 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271.h | 31 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_cmd.c | 41 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_cmd.h | 28 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_event.c | 10 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_ini.h | 123 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_main.c | 95 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_sdio.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_testmode.c | 11 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_tx.c | 36 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_tx.h | 1 |
13 files changed, 319 insertions, 108 deletions
diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig index 337fc7bec5a..2f98058be45 100644 --- a/drivers/net/wireless/wl12xx/Kconfig +++ b/drivers/net/wireless/wl12xx/Kconfig | |||
@@ -41,7 +41,7 @@ config WL1251_SDIO | |||
41 | 41 | ||
42 | config WL1271 | 42 | config 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 | ||
66 | config WL1271_SDIO | 66 | config 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 00b24282fc7..c8f268951e1 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 | ||
139 | out: | 137 | out: |
diff --git a/drivers/net/wireless/wl12xx/wl1251_sdio.c b/drivers/net/wireless/wl12xx/wl1251_sdio.c index d234285c2c8..b901b613565 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 | ||
40 | struct wl1251_sdio { | ||
41 | struct sdio_func *func; | ||
42 | u32 elp_val; | ||
43 | }; | ||
44 | |||
40 | static struct wl12xx_platform_data *wl12xx_board_data; | 45 | static struct wl12xx_platform_data *wl12xx_board_data; |
41 | 46 | ||
42 | static struct sdio_func *wl_to_func(struct wl1251 *wl) | 47 | static 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 | ||
47 | static void wl1251_sdio_interrupt(struct sdio_func *func) | 53 | static void wl1251_sdio_interrupt(struct sdio_func *func) |
@@ -90,10 +96,17 @@ static void wl1251_sdio_write(struct wl1251 *wl, int addr, | |||
90 | static void wl1251_sdio_read_elp(struct wl1251 *wl, int addr, u32 *val) | 96 | static 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) | |||
103 | static void wl1251_sdio_write_elp(struct wl1251 *wl, int addr, u32 val) | 116 | static 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 | ||
116 | static void wl1251_sdio_reset(struct wl1251 *wl) | 132 | static 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); |
260 | release: | 284 | release: |
261 | sdio_release_host(func); | 285 | sdio_release_host(func); |
286 | kfree(wl_sdio); | ||
287 | out_free_hw: | ||
288 | wl1251_free_hw(wl); | ||
262 | return ret; | 289 | return ret; |
263 | } | 290 | } |
264 | 291 | ||
265 | static void __devexit wl1251_sdio_remove(struct sdio_func *func) | 292 | static 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 9af14646c27..ec09f0d40ca 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 | |||
134 | struct 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 | ||
327 | struct wl1271_scan { | 301 | struct 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 19393e236e2..530678e45a1 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 | ||
569 | int wl1271_cmd_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, | 570 | int 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 d88faf9d264..f5745d829c9 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); | |||
42 | int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer, | 42 | int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer, |
43 | size_t len); | 43 | size_t len); |
44 | int wl1271_cmd_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, | 44 | int 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); |
47 | int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, | 47 | int 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 | ||
449 | struct wl1271_radio_parms_cmd { | 452 | struct 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 | ||
462 | struct wl1271_cmd_cal_channel_tune { | 468 | struct wl1271_cmd_cal_channel_tune { |
diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c index cf37aa6eb13..ca52cdec7a8 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 00000000000..2313047d401 --- /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 | |||
29 | struct 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 | |||
46 | struct 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 | |||
55 | struct 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 | |||
74 | struct 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 | |||
80 | struct 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 | |||
102 | struct 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 b7d9137851a..7a14da506d7 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 | ||
586 | out: | 593 | out: |
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 | ||
1251 | static 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 | |||
1283 | out: | ||
1284 | return ret; | ||
1285 | } | ||
1286 | |||
1244 | static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) | 1287 | static 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 */ |
1994 | const static u8 wl1271_rate_to_idx_2ghz[] = { | 2031 | static 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 */ |
2106 | const static u8 wl1271_rate_to_idx_5ghz[] = { | 2143 | static 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 | ||
2142 | const static u8 *wl1271_band_rate_to_idx[] = { | 2179 | static 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 d3d6f302f70..7059b5cccf0 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 554deb4d024..6e0952f79e9 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 62db79508dd..c592cc2e9fe 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 */ |
415 | void wl1271_tx_flush(struct wl1271 *wl) | 419 | void 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 */ | ||
445 | void 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 91d0adb0ea4..48bf92621c0 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 | ||
159 | void wl1271_tx_work(struct work_struct *work); | 159 | void wl1271_tx_work(struct work_struct *work); |
160 | void wl1271_tx_complete(struct wl1271 *wl); | 160 | void wl1271_tx_complete(struct wl1271 *wl); |
161 | void wl1271_tx_reset(struct wl1271 *wl); | ||
161 | void wl1271_tx_flush(struct wl1271 *wl); | 162 | void wl1271_tx_flush(struct wl1271 *wl); |
162 | u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate); | 163 | u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate); |
163 | u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set); | 164 | u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set); |