diff options
author | Luciano Coelho <coelho@ti.com> | 2011-11-20 14:40:41 -0500 |
---|---|---|
committer | Luciano Coelho <coelho@ti.com> | 2012-04-12 01:43:55 -0400 |
commit | 90921014608d91a03766d0025fa32662dc7c5062 (patch) | |
tree | adba69dd7be20600cdec0cc856263dc2ca3bfdb1 /drivers/net/wireless/ti | |
parent | 16f3eb530fb5e7eacbdaaf09c66edc273087a21d (diff) |
wireless/wl12xx/wl1251: move TI WLAN modules to a common ti subdirectory
Move wl12xx and wl1251 modules into a new drivers/net/wireless/ti
directory. Add a TI WLAN Kconfig option and Makefile to support this
change.
Signed-off-by: Luciano Coelho <coelho@ti.com>
Cc: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ti')
67 files changed, 33334 insertions, 0 deletions
diff --git a/drivers/net/wireless/ti/Kconfig b/drivers/net/wireless/ti/Kconfig new file mode 100644 index 000000000000..75722d81188c --- /dev/null +++ b/drivers/net/wireless/ti/Kconfig | |||
@@ -0,0 +1,11 @@ | |||
1 | menuconfig WL_TI | ||
2 | bool "TI Wireless LAN support" | ||
3 | ---help--- | ||
4 | This section contains support for all the wireless drivers | ||
5 | for Texas Instruments WLAN chips, such as wl1251 and the wl12xx | ||
6 | family. | ||
7 | |||
8 | if WL_TI | ||
9 | source "drivers/net/wireless/ti/wl1251/Kconfig" | ||
10 | source "drivers/net/wireless/ti/wl12xx/Kconfig" | ||
11 | endif # WL_TI | ||
diff --git a/drivers/net/wireless/ti/Makefile b/drivers/net/wireless/ti/Makefile new file mode 100644 index 000000000000..db2cb03f6f98 --- /dev/null +++ b/drivers/net/wireless/ti/Makefile | |||
@@ -0,0 +1,3 @@ | |||
1 | obj-$(CONFIG_WL12XX) += wl12xx/ | ||
2 | obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx/ | ||
3 | obj-$(CONFIG_WL1251) += wl1251/ | ||
diff --git a/drivers/net/wireless/ti/wl1251/Kconfig b/drivers/net/wireless/ti/wl1251/Kconfig new file mode 100644 index 000000000000..1fb65849414f --- /dev/null +++ b/drivers/net/wireless/ti/wl1251/Kconfig | |||
@@ -0,0 +1,33 @@ | |||
1 | menuconfig WL1251 | ||
2 | tristate "TI wl1251 driver support" | ||
3 | depends on MAC80211 && EXPERIMENTAL && GENERIC_HARDIRQS | ||
4 | select FW_LOADER | ||
5 | select CRC7 | ||
6 | ---help--- | ||
7 | This will enable TI wl1251 driver support. The drivers make | ||
8 | use of the mac80211 stack. | ||
9 | |||
10 | If you choose to build a module, it'll be called wl1251. Say | ||
11 | N if unsure. | ||
12 | |||
13 | config WL1251_SPI | ||
14 | tristate "TI wl1251 SPI support" | ||
15 | depends on WL1251 && SPI_MASTER | ||
16 | ---help--- | ||
17 | This module adds support for the SPI interface of adapters using | ||
18 | TI wl1251 chipset. Select this if your platform is using | ||
19 | the SPI bus. | ||
20 | |||
21 | If you choose to build a module, it'll be called wl1251_spi. | ||
22 | Say N if unsure. | ||
23 | |||
24 | config WL1251_SDIO | ||
25 | tristate "TI wl1251 SDIO support" | ||
26 | depends on WL1251 && MMC | ||
27 | ---help--- | ||
28 | This module adds support for the SDIO interface of adapters using | ||
29 | TI wl1251 chipset. Select this if your platform is using | ||
30 | the SDIO bus. | ||
31 | |||
32 | If you choose to build a module, it'll be called | ||
33 | wl1251_sdio. Say N if unsure. | ||
diff --git a/drivers/net/wireless/ti/wl1251/Makefile b/drivers/net/wireless/ti/wl1251/Makefile new file mode 100644 index 000000000000..a5c6328b5f72 --- /dev/null +++ b/drivers/net/wireless/ti/wl1251/Makefile | |||
@@ -0,0 +1,10 @@ | |||
1 | wl1251-objs = main.o event.o tx.o rx.o ps.o cmd.o \ | ||
2 | acx.o boot.o init.o debugfs.o io.o | ||
3 | wl1251_spi-objs += spi.o | ||
4 | wl1251_sdio-objs += sdio.o | ||
5 | |||
6 | obj-$(CONFIG_WL1251) += wl1251.o | ||
7 | obj-$(CONFIG_WL1251_SPI) += wl1251_spi.o | ||
8 | obj-$(CONFIG_WL1251_SDIO) += wl1251_sdio.o | ||
9 | |||
10 | ccflags-y += -D__CHECK_ENDIAN__ | ||
diff --git a/drivers/net/wireless/ti/wl1251/acx.c b/drivers/net/wireless/ti/wl1251/acx.c new file mode 100644 index 000000000000..ad87a1ac6462 --- /dev/null +++ b/drivers/net/wireless/ti/wl1251/acx.c | |||
@@ -0,0 +1,1097 @@ | |||
1 | #include "acx.h" | ||
2 | |||
3 | #include <linux/module.h> | ||
4 | #include <linux/slab.h> | ||
5 | #include <linux/crc7.h> | ||
6 | |||
7 | #include "wl1251.h" | ||
8 | #include "reg.h" | ||
9 | #include "cmd.h" | ||
10 | #include "ps.h" | ||
11 | |||
12 | int wl1251_acx_frame_rates(struct wl1251 *wl, u8 ctrl_rate, u8 ctrl_mod, | ||
13 | u8 mgt_rate, u8 mgt_mod) | ||
14 | { | ||
15 | struct acx_fw_gen_frame_rates *rates; | ||
16 | int ret; | ||
17 | |||
18 | wl1251_debug(DEBUG_ACX, "acx frame rates"); | ||
19 | |||
20 | rates = kzalloc(sizeof(*rates), GFP_KERNEL); | ||
21 | if (!rates) { | ||
22 | ret = -ENOMEM; | ||
23 | goto out; | ||
24 | } | ||
25 | |||
26 | rates->tx_ctrl_frame_rate = ctrl_rate; | ||
27 | rates->tx_ctrl_frame_mod = ctrl_mod; | ||
28 | rates->tx_mgt_frame_rate = mgt_rate; | ||
29 | rates->tx_mgt_frame_mod = mgt_mod; | ||
30 | |||
31 | ret = wl1251_cmd_configure(wl, ACX_FW_GEN_FRAME_RATES, | ||
32 | rates, sizeof(*rates)); | ||
33 | if (ret < 0) { | ||
34 | wl1251_error("Failed to set FW rates and modulation"); | ||
35 | goto out; | ||
36 | } | ||
37 | |||
38 | out: | ||
39 | kfree(rates); | ||
40 | return ret; | ||
41 | } | ||
42 | |||
43 | |||
44 | int wl1251_acx_station_id(struct wl1251 *wl) | ||
45 | { | ||
46 | struct acx_dot11_station_id *mac; | ||
47 | int ret, i; | ||
48 | |||
49 | wl1251_debug(DEBUG_ACX, "acx dot11_station_id"); | ||
50 | |||
51 | mac = kzalloc(sizeof(*mac), GFP_KERNEL); | ||
52 | if (!mac) { | ||
53 | ret = -ENOMEM; | ||
54 | goto out; | ||
55 | } | ||
56 | |||
57 | for (i = 0; i < ETH_ALEN; i++) | ||
58 | mac->mac[i] = wl->mac_addr[ETH_ALEN - 1 - i]; | ||
59 | |||
60 | ret = wl1251_cmd_configure(wl, DOT11_STATION_ID, mac, sizeof(*mac)); | ||
61 | if (ret < 0) | ||
62 | goto out; | ||
63 | |||
64 | out: | ||
65 | kfree(mac); | ||
66 | return ret; | ||
67 | } | ||
68 | |||
69 | int wl1251_acx_default_key(struct wl1251 *wl, u8 key_id) | ||
70 | { | ||
71 | struct acx_dot11_default_key *default_key; | ||
72 | int ret; | ||
73 | |||
74 | wl1251_debug(DEBUG_ACX, "acx dot11_default_key (%d)", key_id); | ||
75 | |||
76 | default_key = kzalloc(sizeof(*default_key), GFP_KERNEL); | ||
77 | if (!default_key) { | ||
78 | ret = -ENOMEM; | ||
79 | goto out; | ||
80 | } | ||
81 | |||
82 | default_key->id = key_id; | ||
83 | |||
84 | ret = wl1251_cmd_configure(wl, DOT11_DEFAULT_KEY, | ||
85 | default_key, sizeof(*default_key)); | ||
86 | if (ret < 0) { | ||
87 | wl1251_error("Couldn't set default key"); | ||
88 | goto out; | ||
89 | } | ||
90 | |||
91 | wl->default_key = key_id; | ||
92 | |||
93 | out: | ||
94 | kfree(default_key); | ||
95 | return ret; | ||
96 | } | ||
97 | |||
98 | int wl1251_acx_wake_up_conditions(struct wl1251 *wl, u8 wake_up_event, | ||
99 | u8 listen_interval) | ||
100 | { | ||
101 | struct acx_wake_up_condition *wake_up; | ||
102 | int ret; | ||
103 | |||
104 | wl1251_debug(DEBUG_ACX, "acx wake up conditions"); | ||
105 | |||
106 | wake_up = kzalloc(sizeof(*wake_up), GFP_KERNEL); | ||
107 | if (!wake_up) { | ||
108 | ret = -ENOMEM; | ||
109 | goto out; | ||
110 | } | ||
111 | |||
112 | wake_up->wake_up_event = wake_up_event; | ||
113 | wake_up->listen_interval = listen_interval; | ||
114 | |||
115 | ret = wl1251_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS, | ||
116 | wake_up, sizeof(*wake_up)); | ||
117 | if (ret < 0) { | ||
118 | wl1251_warning("could not set wake up conditions: %d", ret); | ||
119 | goto out; | ||
120 | } | ||
121 | |||
122 | out: | ||
123 | kfree(wake_up); | ||
124 | return ret; | ||
125 | } | ||
126 | |||
127 | int wl1251_acx_sleep_auth(struct wl1251 *wl, u8 sleep_auth) | ||
128 | { | ||
129 | struct acx_sleep_auth *auth; | ||
130 | int ret; | ||
131 | |||
132 | wl1251_debug(DEBUG_ACX, "acx sleep auth"); | ||
133 | |||
134 | auth = kzalloc(sizeof(*auth), GFP_KERNEL); | ||
135 | if (!auth) { | ||
136 | ret = -ENOMEM; | ||
137 | goto out; | ||
138 | } | ||
139 | |||
140 | auth->sleep_auth = sleep_auth; | ||
141 | |||
142 | ret = wl1251_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth)); | ||
143 | |||
144 | out: | ||
145 | kfree(auth); | ||
146 | return ret; | ||
147 | } | ||
148 | |||
149 | int wl1251_acx_fw_version(struct wl1251 *wl, char *buf, size_t len) | ||
150 | { | ||
151 | struct acx_revision *rev; | ||
152 | int ret; | ||
153 | |||
154 | wl1251_debug(DEBUG_ACX, "acx fw rev"); | ||
155 | |||
156 | rev = kzalloc(sizeof(*rev), GFP_KERNEL); | ||
157 | if (!rev) { | ||
158 | ret = -ENOMEM; | ||
159 | goto out; | ||
160 | } | ||
161 | |||
162 | ret = wl1251_cmd_interrogate(wl, ACX_FW_REV, rev, sizeof(*rev)); | ||
163 | if (ret < 0) { | ||
164 | wl1251_warning("ACX_FW_REV interrogate failed"); | ||
165 | goto out; | ||
166 | } | ||
167 | |||
168 | /* be careful with the buffer sizes */ | ||
169 | strncpy(buf, rev->fw_version, min(len, sizeof(rev->fw_version))); | ||
170 | |||
171 | /* | ||
172 | * if the firmware version string is exactly | ||
173 | * sizeof(rev->fw_version) long or fw_len is less than | ||
174 | * sizeof(rev->fw_version) it won't be null terminated | ||
175 | */ | ||
176 | buf[min(len, sizeof(rev->fw_version)) - 1] = '\0'; | ||
177 | |||
178 | out: | ||
179 | kfree(rev); | ||
180 | return ret; | ||
181 | } | ||
182 | |||
183 | int wl1251_acx_tx_power(struct wl1251 *wl, int power) | ||
184 | { | ||
185 | struct acx_current_tx_power *acx; | ||
186 | int ret; | ||
187 | |||
188 | wl1251_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr"); | ||
189 | |||
190 | if (power < 0 || power > 25) | ||
191 | return -EINVAL; | ||
192 | |||
193 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
194 | if (!acx) { | ||
195 | ret = -ENOMEM; | ||
196 | goto out; | ||
197 | } | ||
198 | |||
199 | acx->current_tx_power = power * 10; | ||
200 | |||
201 | ret = wl1251_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx)); | ||
202 | if (ret < 0) { | ||
203 | wl1251_warning("configure of tx power failed: %d", ret); | ||
204 | goto out; | ||
205 | } | ||
206 | |||
207 | out: | ||
208 | kfree(acx); | ||
209 | return ret; | ||
210 | } | ||
211 | |||
212 | int wl1251_acx_feature_cfg(struct wl1251 *wl) | ||
213 | { | ||
214 | struct acx_feature_config *feature; | ||
215 | int ret; | ||
216 | |||
217 | wl1251_debug(DEBUG_ACX, "acx feature cfg"); | ||
218 | |||
219 | feature = kzalloc(sizeof(*feature), GFP_KERNEL); | ||
220 | if (!feature) { | ||
221 | ret = -ENOMEM; | ||
222 | goto out; | ||
223 | } | ||
224 | |||
225 | /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */ | ||
226 | feature->data_flow_options = 0; | ||
227 | feature->options = 0; | ||
228 | |||
229 | ret = wl1251_cmd_configure(wl, ACX_FEATURE_CFG, | ||
230 | feature, sizeof(*feature)); | ||
231 | if (ret < 0) { | ||
232 | wl1251_error("Couldn't set HW encryption"); | ||
233 | goto out; | ||
234 | } | ||
235 | |||
236 | out: | ||
237 | kfree(feature); | ||
238 | return ret; | ||
239 | } | ||
240 | |||
241 | int wl1251_acx_mem_map(struct wl1251 *wl, struct acx_header *mem_map, | ||
242 | size_t len) | ||
243 | { | ||
244 | int ret; | ||
245 | |||
246 | wl1251_debug(DEBUG_ACX, "acx mem map"); | ||
247 | |||
248 | ret = wl1251_cmd_interrogate(wl, ACX_MEM_MAP, mem_map, len); | ||
249 | if (ret < 0) | ||
250 | return ret; | ||
251 | |||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | int wl1251_acx_data_path_params(struct wl1251 *wl, | ||
256 | struct acx_data_path_params_resp *resp) | ||
257 | { | ||
258 | struct acx_data_path_params *params; | ||
259 | int ret; | ||
260 | |||
261 | wl1251_debug(DEBUG_ACX, "acx data path params"); | ||
262 | |||
263 | params = kzalloc(sizeof(*params), GFP_KERNEL); | ||
264 | if (!params) { | ||
265 | ret = -ENOMEM; | ||
266 | goto out; | ||
267 | } | ||
268 | |||
269 | params->rx_packet_ring_chunk_size = DP_RX_PACKET_RING_CHUNK_SIZE; | ||
270 | params->tx_packet_ring_chunk_size = DP_TX_PACKET_RING_CHUNK_SIZE; | ||
271 | |||
272 | params->rx_packet_ring_chunk_num = DP_RX_PACKET_RING_CHUNK_NUM; | ||
273 | params->tx_packet_ring_chunk_num = DP_TX_PACKET_RING_CHUNK_NUM; | ||
274 | |||
275 | params->tx_complete_threshold = 1; | ||
276 | |||
277 | params->tx_complete_ring_depth = FW_TX_CMPLT_BLOCK_SIZE; | ||
278 | |||
279 | params->tx_complete_timeout = DP_TX_COMPLETE_TIME_OUT; | ||
280 | |||
281 | ret = wl1251_cmd_configure(wl, ACX_DATA_PATH_PARAMS, | ||
282 | params, sizeof(*params)); | ||
283 | if (ret < 0) | ||
284 | goto out; | ||
285 | |||
286 | /* FIXME: shouldn't this be ACX_DATA_PATH_RESP_PARAMS? */ | ||
287 | ret = wl1251_cmd_interrogate(wl, ACX_DATA_PATH_PARAMS, | ||
288 | resp, sizeof(*resp)); | ||
289 | |||
290 | if (ret < 0) { | ||
291 | wl1251_warning("failed to read data path parameters: %d", ret); | ||
292 | goto out; | ||
293 | } else if (resp->header.cmd.status != CMD_STATUS_SUCCESS) { | ||
294 | wl1251_warning("data path parameter acx status failed"); | ||
295 | ret = -EIO; | ||
296 | goto out; | ||
297 | } | ||
298 | |||
299 | out: | ||
300 | kfree(params); | ||
301 | return ret; | ||
302 | } | ||
303 | |||
304 | int wl1251_acx_rx_msdu_life_time(struct wl1251 *wl, u32 life_time) | ||
305 | { | ||
306 | struct acx_rx_msdu_lifetime *acx; | ||
307 | int ret; | ||
308 | |||
309 | wl1251_debug(DEBUG_ACX, "acx rx msdu life time"); | ||
310 | |||
311 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
312 | if (!acx) { | ||
313 | ret = -ENOMEM; | ||
314 | goto out; | ||
315 | } | ||
316 | |||
317 | acx->lifetime = life_time; | ||
318 | ret = wl1251_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME, | ||
319 | acx, sizeof(*acx)); | ||
320 | if (ret < 0) { | ||
321 | wl1251_warning("failed to set rx msdu life time: %d", ret); | ||
322 | goto out; | ||
323 | } | ||
324 | |||
325 | out: | ||
326 | kfree(acx); | ||
327 | return ret; | ||
328 | } | ||
329 | |||
330 | int wl1251_acx_rx_config(struct wl1251 *wl, u32 config, u32 filter) | ||
331 | { | ||
332 | struct acx_rx_config *rx_config; | ||
333 | int ret; | ||
334 | |||
335 | wl1251_debug(DEBUG_ACX, "acx rx config"); | ||
336 | |||
337 | rx_config = kzalloc(sizeof(*rx_config), GFP_KERNEL); | ||
338 | if (!rx_config) { | ||
339 | ret = -ENOMEM; | ||
340 | goto out; | ||
341 | } | ||
342 | |||
343 | rx_config->config_options = config; | ||
344 | rx_config->filter_options = filter; | ||
345 | |||
346 | ret = wl1251_cmd_configure(wl, ACX_RX_CFG, | ||
347 | rx_config, sizeof(*rx_config)); | ||
348 | if (ret < 0) { | ||
349 | wl1251_warning("failed to set rx config: %d", ret); | ||
350 | goto out; | ||
351 | } | ||
352 | |||
353 | out: | ||
354 | kfree(rx_config); | ||
355 | return ret; | ||
356 | } | ||
357 | |||
358 | int wl1251_acx_pd_threshold(struct wl1251 *wl) | ||
359 | { | ||
360 | struct acx_packet_detection *pd; | ||
361 | int ret; | ||
362 | |||
363 | wl1251_debug(DEBUG_ACX, "acx data pd threshold"); | ||
364 | |||
365 | pd = kzalloc(sizeof(*pd), GFP_KERNEL); | ||
366 | if (!pd) { | ||
367 | ret = -ENOMEM; | ||
368 | goto out; | ||
369 | } | ||
370 | |||
371 | /* FIXME: threshold value not set */ | ||
372 | |||
373 | ret = wl1251_cmd_configure(wl, ACX_PD_THRESHOLD, pd, sizeof(*pd)); | ||
374 | if (ret < 0) { | ||
375 | wl1251_warning("failed to set pd threshold: %d", ret); | ||
376 | goto out; | ||
377 | } | ||
378 | |||
379 | out: | ||
380 | kfree(pd); | ||
381 | return ret; | ||
382 | } | ||
383 | |||
384 | int wl1251_acx_slot(struct wl1251 *wl, enum acx_slot_type slot_time) | ||
385 | { | ||
386 | struct acx_slot *slot; | ||
387 | int ret; | ||
388 | |||
389 | wl1251_debug(DEBUG_ACX, "acx slot"); | ||
390 | |||
391 | slot = kzalloc(sizeof(*slot), GFP_KERNEL); | ||
392 | if (!slot) { | ||
393 | ret = -ENOMEM; | ||
394 | goto out; | ||
395 | } | ||
396 | |||
397 | slot->wone_index = STATION_WONE_INDEX; | ||
398 | slot->slot_time = slot_time; | ||
399 | |||
400 | ret = wl1251_cmd_configure(wl, ACX_SLOT, slot, sizeof(*slot)); | ||
401 | if (ret < 0) { | ||
402 | wl1251_warning("failed to set slot time: %d", ret); | ||
403 | goto out; | ||
404 | } | ||
405 | |||
406 | out: | ||
407 | kfree(slot); | ||
408 | return ret; | ||
409 | } | ||
410 | |||
411 | int wl1251_acx_group_address_tbl(struct wl1251 *wl) | ||
412 | { | ||
413 | struct acx_dot11_grp_addr_tbl *acx; | ||
414 | int ret; | ||
415 | |||
416 | wl1251_debug(DEBUG_ACX, "acx group address tbl"); | ||
417 | |||
418 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
419 | if (!acx) { | ||
420 | ret = -ENOMEM; | ||
421 | goto out; | ||
422 | } | ||
423 | |||
424 | /* MAC filtering */ | ||
425 | acx->enabled = 0; | ||
426 | acx->num_groups = 0; | ||
427 | memset(acx->mac_table, 0, ADDRESS_GROUP_MAX_LEN); | ||
428 | |||
429 | ret = wl1251_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL, | ||
430 | acx, sizeof(*acx)); | ||
431 | if (ret < 0) { | ||
432 | wl1251_warning("failed to set group addr table: %d", ret); | ||
433 | goto out; | ||
434 | } | ||
435 | |||
436 | out: | ||
437 | kfree(acx); | ||
438 | return ret; | ||
439 | } | ||
440 | |||
441 | int wl1251_acx_service_period_timeout(struct wl1251 *wl) | ||
442 | { | ||
443 | struct acx_rx_timeout *rx_timeout; | ||
444 | int ret; | ||
445 | |||
446 | rx_timeout = kzalloc(sizeof(*rx_timeout), GFP_KERNEL); | ||
447 | if (!rx_timeout) { | ||
448 | ret = -ENOMEM; | ||
449 | goto out; | ||
450 | } | ||
451 | |||
452 | wl1251_debug(DEBUG_ACX, "acx service period timeout"); | ||
453 | |||
454 | rx_timeout->ps_poll_timeout = RX_TIMEOUT_PS_POLL_DEF; | ||
455 | rx_timeout->upsd_timeout = RX_TIMEOUT_UPSD_DEF; | ||
456 | |||
457 | ret = wl1251_cmd_configure(wl, ACX_SERVICE_PERIOD_TIMEOUT, | ||
458 | rx_timeout, sizeof(*rx_timeout)); | ||
459 | if (ret < 0) { | ||
460 | wl1251_warning("failed to set service period timeout: %d", | ||
461 | ret); | ||
462 | goto out; | ||
463 | } | ||
464 | |||
465 | out: | ||
466 | kfree(rx_timeout); | ||
467 | return ret; | ||
468 | } | ||
469 | |||
470 | int wl1251_acx_rts_threshold(struct wl1251 *wl, u16 rts_threshold) | ||
471 | { | ||
472 | struct acx_rts_threshold *rts; | ||
473 | int ret; | ||
474 | |||
475 | wl1251_debug(DEBUG_ACX, "acx rts threshold"); | ||
476 | |||
477 | rts = kzalloc(sizeof(*rts), GFP_KERNEL); | ||
478 | if (!rts) { | ||
479 | ret = -ENOMEM; | ||
480 | goto out; | ||
481 | } | ||
482 | |||
483 | rts->threshold = rts_threshold; | ||
484 | |||
485 | ret = wl1251_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts)); | ||
486 | if (ret < 0) { | ||
487 | wl1251_warning("failed to set rts threshold: %d", ret); | ||
488 | goto out; | ||
489 | } | ||
490 | |||
491 | out: | ||
492 | kfree(rts); | ||
493 | return ret; | ||
494 | } | ||
495 | |||
496 | int wl1251_acx_beacon_filter_opt(struct wl1251 *wl, bool enable_filter) | ||
497 | { | ||
498 | struct acx_beacon_filter_option *beacon_filter; | ||
499 | int ret; | ||
500 | |||
501 | wl1251_debug(DEBUG_ACX, "acx beacon filter opt"); | ||
502 | |||
503 | beacon_filter = kzalloc(sizeof(*beacon_filter), GFP_KERNEL); | ||
504 | if (!beacon_filter) { | ||
505 | ret = -ENOMEM; | ||
506 | goto out; | ||
507 | } | ||
508 | |||
509 | beacon_filter->enable = enable_filter; | ||
510 | beacon_filter->max_num_beacons = 0; | ||
511 | |||
512 | ret = wl1251_cmd_configure(wl, ACX_BEACON_FILTER_OPT, | ||
513 | beacon_filter, sizeof(*beacon_filter)); | ||
514 | if (ret < 0) { | ||
515 | wl1251_warning("failed to set beacon filter opt: %d", ret); | ||
516 | goto out; | ||
517 | } | ||
518 | |||
519 | out: | ||
520 | kfree(beacon_filter); | ||
521 | return ret; | ||
522 | } | ||
523 | |||
524 | int wl1251_acx_beacon_filter_table(struct wl1251 *wl) | ||
525 | { | ||
526 | struct acx_beacon_filter_ie_table *ie_table; | ||
527 | int idx = 0; | ||
528 | int ret; | ||
529 | |||
530 | wl1251_debug(DEBUG_ACX, "acx beacon filter table"); | ||
531 | |||
532 | ie_table = kzalloc(sizeof(*ie_table), GFP_KERNEL); | ||
533 | if (!ie_table) { | ||
534 | ret = -ENOMEM; | ||
535 | goto out; | ||
536 | } | ||
537 | |||
538 | /* configure default beacon pass-through rules */ | ||
539 | ie_table->num_ie = 1; | ||
540 | ie_table->table[idx++] = BEACON_FILTER_IE_ID_CHANNEL_SWITCH_ANN; | ||
541 | ie_table->table[idx++] = BEACON_RULE_PASS_ON_APPEARANCE; | ||
542 | |||
543 | ret = wl1251_cmd_configure(wl, ACX_BEACON_FILTER_TABLE, | ||
544 | ie_table, sizeof(*ie_table)); | ||
545 | if (ret < 0) { | ||
546 | wl1251_warning("failed to set beacon filter table: %d", ret); | ||
547 | goto out; | ||
548 | } | ||
549 | |||
550 | out: | ||
551 | kfree(ie_table); | ||
552 | return ret; | ||
553 | } | ||
554 | |||
555 | int wl1251_acx_conn_monit_params(struct wl1251 *wl) | ||
556 | { | ||
557 | struct acx_conn_monit_params *acx; | ||
558 | int ret; | ||
559 | |||
560 | wl1251_debug(DEBUG_ACX, "acx connection monitor parameters"); | ||
561 | |||
562 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
563 | if (!acx) { | ||
564 | ret = -ENOMEM; | ||
565 | goto out; | ||
566 | } | ||
567 | |||
568 | acx->synch_fail_thold = SYNCH_FAIL_DEFAULT_THRESHOLD; | ||
569 | acx->bss_lose_timeout = NO_BEACON_DEFAULT_TIMEOUT; | ||
570 | |||
571 | ret = wl1251_cmd_configure(wl, ACX_CONN_MONIT_PARAMS, | ||
572 | acx, sizeof(*acx)); | ||
573 | if (ret < 0) { | ||
574 | wl1251_warning("failed to set connection monitor " | ||
575 | "parameters: %d", ret); | ||
576 | goto out; | ||
577 | } | ||
578 | |||
579 | out: | ||
580 | kfree(acx); | ||
581 | return ret; | ||
582 | } | ||
583 | |||
584 | int wl1251_acx_sg_enable(struct wl1251 *wl) | ||
585 | { | ||
586 | struct acx_bt_wlan_coex *pta; | ||
587 | int ret; | ||
588 | |||
589 | wl1251_debug(DEBUG_ACX, "acx sg enable"); | ||
590 | |||
591 | pta = kzalloc(sizeof(*pta), GFP_KERNEL); | ||
592 | if (!pta) { | ||
593 | ret = -ENOMEM; | ||
594 | goto out; | ||
595 | } | ||
596 | |||
597 | pta->enable = SG_ENABLE; | ||
598 | |||
599 | ret = wl1251_cmd_configure(wl, ACX_SG_ENABLE, pta, sizeof(*pta)); | ||
600 | if (ret < 0) { | ||
601 | wl1251_warning("failed to set softgemini enable: %d", ret); | ||
602 | goto out; | ||
603 | } | ||
604 | |||
605 | out: | ||
606 | kfree(pta); | ||
607 | return ret; | ||
608 | } | ||
609 | |||
610 | int wl1251_acx_sg_cfg(struct wl1251 *wl) | ||
611 | { | ||
612 | struct acx_bt_wlan_coex_param *param; | ||
613 | int ret; | ||
614 | |||
615 | wl1251_debug(DEBUG_ACX, "acx sg cfg"); | ||
616 | |||
617 | param = kzalloc(sizeof(*param), GFP_KERNEL); | ||
618 | if (!param) { | ||
619 | ret = -ENOMEM; | ||
620 | goto out; | ||
621 | } | ||
622 | |||
623 | /* BT-WLAN coext parameters */ | ||
624 | param->min_rate = RATE_INDEX_24MBPS; | ||
625 | param->bt_hp_max_time = PTA_BT_HP_MAXTIME_DEF; | ||
626 | param->wlan_hp_max_time = PTA_WLAN_HP_MAX_TIME_DEF; | ||
627 | param->sense_disable_timer = PTA_SENSE_DISABLE_TIMER_DEF; | ||
628 | param->rx_time_bt_hp = PTA_PROTECTIVE_RX_TIME_DEF; | ||
629 | param->tx_time_bt_hp = PTA_PROTECTIVE_TX_TIME_DEF; | ||
630 | param->rx_time_bt_hp_fast = PTA_PROTECTIVE_RX_TIME_FAST_DEF; | ||
631 | param->tx_time_bt_hp_fast = PTA_PROTECTIVE_TX_TIME_FAST_DEF; | ||
632 | param->wlan_cycle_fast = PTA_CYCLE_TIME_FAST_DEF; | ||
633 | param->bt_anti_starvation_period = PTA_ANTI_STARVE_PERIOD_DEF; | ||
634 | param->next_bt_lp_packet = PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF; | ||
635 | param->wake_up_beacon = PTA_TIME_BEFORE_BEACON_DEF; | ||
636 | param->hp_dm_max_guard_time = PTA_HPDM_MAX_TIME_DEF; | ||
637 | param->next_wlan_packet = PTA_TIME_OUT_NEXT_WLAN_DEF; | ||
638 | param->antenna_type = PTA_ANTENNA_TYPE_DEF; | ||
639 | param->signal_type = PTA_SIGNALING_TYPE_DEF; | ||
640 | param->afh_leverage_on = PTA_AFH_LEVERAGE_ON_DEF; | ||
641 | param->quiet_cycle_num = PTA_NUMBER_QUIET_CYCLE_DEF; | ||
642 | param->max_cts = PTA_MAX_NUM_CTS_DEF; | ||
643 | param->wlan_packets_num = PTA_NUMBER_OF_WLAN_PACKETS_DEF; | ||
644 | param->bt_packets_num = PTA_NUMBER_OF_BT_PACKETS_DEF; | ||
645 | param->missed_rx_avalanche = PTA_RX_FOR_AVALANCHE_DEF; | ||
646 | param->wlan_elp_hp = PTA_ELP_HP_DEF; | ||
647 | param->bt_anti_starvation_cycles = PTA_ANTI_STARVE_NUM_CYCLE_DEF; | ||
648 | param->ack_mode_dual_ant = PTA_ACK_MODE_DEF; | ||
649 | param->pa_sd_enable = PTA_ALLOW_PA_SD_DEF; | ||
650 | param->pta_auto_mode_enable = PTA_AUTO_MODE_NO_CTS_DEF; | ||
651 | param->bt_hp_respected_num = PTA_BT_HP_RESPECTED_DEF; | ||
652 | |||
653 | ret = wl1251_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param)); | ||
654 | if (ret < 0) { | ||
655 | wl1251_warning("failed to set sg config: %d", ret); | ||
656 | goto out; | ||
657 | } | ||
658 | |||
659 | out: | ||
660 | kfree(param); | ||
661 | return ret; | ||
662 | } | ||
663 | |||
664 | int wl1251_acx_cca_threshold(struct wl1251 *wl) | ||
665 | { | ||
666 | struct acx_energy_detection *detection; | ||
667 | int ret; | ||
668 | |||
669 | wl1251_debug(DEBUG_ACX, "acx cca threshold"); | ||
670 | |||
671 | detection = kzalloc(sizeof(*detection), GFP_KERNEL); | ||
672 | if (!detection) { | ||
673 | ret = -ENOMEM; | ||
674 | goto out; | ||
675 | } | ||
676 | |||
677 | detection->rx_cca_threshold = CCA_THRSH_DISABLE_ENERGY_D; | ||
678 | detection->tx_energy_detection = 0; | ||
679 | |||
680 | ret = wl1251_cmd_configure(wl, ACX_CCA_THRESHOLD, | ||
681 | detection, sizeof(*detection)); | ||
682 | if (ret < 0) | ||
683 | wl1251_warning("failed to set cca threshold: %d", ret); | ||
684 | |||
685 | out: | ||
686 | kfree(detection); | ||
687 | return ret; | ||
688 | } | ||
689 | |||
690 | int wl1251_acx_bcn_dtim_options(struct wl1251 *wl) | ||
691 | { | ||
692 | struct acx_beacon_broadcast *bb; | ||
693 | int ret; | ||
694 | |||
695 | wl1251_debug(DEBUG_ACX, "acx bcn dtim options"); | ||
696 | |||
697 | bb = kzalloc(sizeof(*bb), GFP_KERNEL); | ||
698 | if (!bb) { | ||
699 | ret = -ENOMEM; | ||
700 | goto out; | ||
701 | } | ||
702 | |||
703 | bb->beacon_rx_timeout = BCN_RX_TIMEOUT_DEF_VALUE; | ||
704 | bb->broadcast_timeout = BROADCAST_RX_TIMEOUT_DEF_VALUE; | ||
705 | bb->rx_broadcast_in_ps = RX_BROADCAST_IN_PS_DEF_VALUE; | ||
706 | bb->ps_poll_threshold = CONSECUTIVE_PS_POLL_FAILURE_DEF; | ||
707 | |||
708 | ret = wl1251_cmd_configure(wl, ACX_BCN_DTIM_OPTIONS, bb, sizeof(*bb)); | ||
709 | if (ret < 0) { | ||
710 | wl1251_warning("failed to set rx config: %d", ret); | ||
711 | goto out; | ||
712 | } | ||
713 | |||
714 | out: | ||
715 | kfree(bb); | ||
716 | return ret; | ||
717 | } | ||
718 | |||
719 | int wl1251_acx_aid(struct wl1251 *wl, u16 aid) | ||
720 | { | ||
721 | struct acx_aid *acx_aid; | ||
722 | int ret; | ||
723 | |||
724 | wl1251_debug(DEBUG_ACX, "acx aid"); | ||
725 | |||
726 | acx_aid = kzalloc(sizeof(*acx_aid), GFP_KERNEL); | ||
727 | if (!acx_aid) { | ||
728 | ret = -ENOMEM; | ||
729 | goto out; | ||
730 | } | ||
731 | |||
732 | acx_aid->aid = aid; | ||
733 | |||
734 | ret = wl1251_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid)); | ||
735 | if (ret < 0) { | ||
736 | wl1251_warning("failed to set aid: %d", ret); | ||
737 | goto out; | ||
738 | } | ||
739 | |||
740 | out: | ||
741 | kfree(acx_aid); | ||
742 | return ret; | ||
743 | } | ||
744 | |||
745 | int wl1251_acx_event_mbox_mask(struct wl1251 *wl, u32 event_mask) | ||
746 | { | ||
747 | struct acx_event_mask *mask; | ||
748 | int ret; | ||
749 | |||
750 | wl1251_debug(DEBUG_ACX, "acx event mbox mask"); | ||
751 | |||
752 | mask = kzalloc(sizeof(*mask), GFP_KERNEL); | ||
753 | if (!mask) { | ||
754 | ret = -ENOMEM; | ||
755 | goto out; | ||
756 | } | ||
757 | |||
758 | /* high event mask is unused */ | ||
759 | mask->high_event_mask = 0xffffffff; | ||
760 | |||
761 | mask->event_mask = event_mask; | ||
762 | |||
763 | ret = wl1251_cmd_configure(wl, ACX_EVENT_MBOX_MASK, | ||
764 | mask, sizeof(*mask)); | ||
765 | if (ret < 0) { | ||
766 | wl1251_warning("failed to set acx_event_mbox_mask: %d", ret); | ||
767 | goto out; | ||
768 | } | ||
769 | |||
770 | out: | ||
771 | kfree(mask); | ||
772 | return ret; | ||
773 | } | ||
774 | |||
775 | int wl1251_acx_low_rssi(struct wl1251 *wl, s8 threshold, u8 weight, | ||
776 | u8 depth, enum wl1251_acx_low_rssi_type type) | ||
777 | { | ||
778 | struct acx_low_rssi *rssi; | ||
779 | int ret; | ||
780 | |||
781 | wl1251_debug(DEBUG_ACX, "acx low rssi"); | ||
782 | |||
783 | rssi = kzalloc(sizeof(*rssi), GFP_KERNEL); | ||
784 | if (!rssi) | ||
785 | return -ENOMEM; | ||
786 | |||
787 | rssi->threshold = threshold; | ||
788 | rssi->weight = weight; | ||
789 | rssi->depth = depth; | ||
790 | rssi->type = type; | ||
791 | |||
792 | ret = wl1251_cmd_configure(wl, ACX_LOW_RSSI, rssi, sizeof(*rssi)); | ||
793 | if (ret < 0) | ||
794 | wl1251_warning("failed to set low rssi threshold: %d", ret); | ||
795 | |||
796 | kfree(rssi); | ||
797 | return ret; | ||
798 | } | ||
799 | |||
800 | int wl1251_acx_set_preamble(struct wl1251 *wl, enum acx_preamble_type preamble) | ||
801 | { | ||
802 | struct acx_preamble *acx; | ||
803 | int ret; | ||
804 | |||
805 | wl1251_debug(DEBUG_ACX, "acx_set_preamble"); | ||
806 | |||
807 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
808 | if (!acx) { | ||
809 | ret = -ENOMEM; | ||
810 | goto out; | ||
811 | } | ||
812 | |||
813 | acx->preamble = preamble; | ||
814 | |||
815 | ret = wl1251_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx)); | ||
816 | if (ret < 0) { | ||
817 | wl1251_warning("Setting of preamble failed: %d", ret); | ||
818 | goto out; | ||
819 | } | ||
820 | |||
821 | out: | ||
822 | kfree(acx); | ||
823 | return ret; | ||
824 | } | ||
825 | |||
826 | int wl1251_acx_cts_protect(struct wl1251 *wl, | ||
827 | enum acx_ctsprotect_type ctsprotect) | ||
828 | { | ||
829 | struct acx_ctsprotect *acx; | ||
830 | int ret; | ||
831 | |||
832 | wl1251_debug(DEBUG_ACX, "acx_set_ctsprotect"); | ||
833 | |||
834 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
835 | if (!acx) { | ||
836 | ret = -ENOMEM; | ||
837 | goto out; | ||
838 | } | ||
839 | |||
840 | acx->ctsprotect = ctsprotect; | ||
841 | |||
842 | ret = wl1251_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx)); | ||
843 | if (ret < 0) { | ||
844 | wl1251_warning("Setting of ctsprotect failed: %d", ret); | ||
845 | goto out; | ||
846 | } | ||
847 | |||
848 | out: | ||
849 | kfree(acx); | ||
850 | return ret; | ||
851 | } | ||
852 | |||
853 | int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime) | ||
854 | { | ||
855 | struct acx_tsf_info *tsf_info; | ||
856 | int ret; | ||
857 | |||
858 | tsf_info = kzalloc(sizeof(*tsf_info), GFP_KERNEL); | ||
859 | if (!tsf_info) { | ||
860 | ret = -ENOMEM; | ||
861 | goto out; | ||
862 | } | ||
863 | |||
864 | ret = wl1251_cmd_interrogate(wl, ACX_TSF_INFO, | ||
865 | tsf_info, sizeof(*tsf_info)); | ||
866 | if (ret < 0) { | ||
867 | wl1251_warning("ACX_FW_REV interrogate failed"); | ||
868 | goto out; | ||
869 | } | ||
870 | |||
871 | *mactime = tsf_info->current_tsf_lsb | | ||
872 | (tsf_info->current_tsf_msb << 31); | ||
873 | |||
874 | out: | ||
875 | kfree(tsf_info); | ||
876 | return ret; | ||
877 | } | ||
878 | |||
879 | int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats) | ||
880 | { | ||
881 | int ret; | ||
882 | |||
883 | wl1251_debug(DEBUG_ACX, "acx statistics"); | ||
884 | |||
885 | ret = wl1251_cmd_interrogate(wl, ACX_STATISTICS, stats, | ||
886 | sizeof(*stats)); | ||
887 | if (ret < 0) { | ||
888 | wl1251_warning("acx statistics failed: %d", ret); | ||
889 | return -ENOMEM; | ||
890 | } | ||
891 | |||
892 | return 0; | ||
893 | } | ||
894 | |||
895 | int wl1251_acx_rate_policies(struct wl1251 *wl) | ||
896 | { | ||
897 | struct acx_rate_policy *acx; | ||
898 | int ret = 0; | ||
899 | |||
900 | wl1251_debug(DEBUG_ACX, "acx rate policies"); | ||
901 | |||
902 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
903 | |||
904 | if (!acx) { | ||
905 | ret = -ENOMEM; | ||
906 | goto out; | ||
907 | } | ||
908 | |||
909 | /* configure one default (one-size-fits-all) rate class */ | ||
910 | acx->rate_class_cnt = 1; | ||
911 | acx->rate_class[0].enabled_rates = ACX_RATE_MASK_UNSPECIFIED; | ||
912 | acx->rate_class[0].short_retry_limit = ACX_RATE_RETRY_LIMIT; | ||
913 | acx->rate_class[0].long_retry_limit = ACX_RATE_RETRY_LIMIT; | ||
914 | acx->rate_class[0].aflags = 0; | ||
915 | |||
916 | ret = wl1251_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); | ||
917 | if (ret < 0) { | ||
918 | wl1251_warning("Setting of rate policies failed: %d", ret); | ||
919 | goto out; | ||
920 | } | ||
921 | |||
922 | out: | ||
923 | kfree(acx); | ||
924 | return ret; | ||
925 | } | ||
926 | |||
927 | int wl1251_acx_mem_cfg(struct wl1251 *wl) | ||
928 | { | ||
929 | struct wl1251_acx_config_memory *mem_conf; | ||
930 | int ret, i; | ||
931 | |||
932 | wl1251_debug(DEBUG_ACX, "acx mem cfg"); | ||
933 | |||
934 | mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL); | ||
935 | if (!mem_conf) { | ||
936 | ret = -ENOMEM; | ||
937 | goto out; | ||
938 | } | ||
939 | |||
940 | /* memory config */ | ||
941 | mem_conf->mem_config.num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS); | ||
942 | mem_conf->mem_config.rx_mem_block_num = 35; | ||
943 | mem_conf->mem_config.tx_min_mem_block_num = 64; | ||
944 | mem_conf->mem_config.num_tx_queues = MAX_TX_QUEUES; | ||
945 | mem_conf->mem_config.host_if_options = HOSTIF_PKT_RING; | ||
946 | mem_conf->mem_config.num_ssid_profiles = 1; | ||
947 | mem_conf->mem_config.debug_buffer_size = | ||
948 | cpu_to_le16(TRACE_BUFFER_MAX_SIZE); | ||
949 | |||
950 | /* RX queue config */ | ||
951 | mem_conf->rx_queue_config.dma_address = 0; | ||
952 | mem_conf->rx_queue_config.num_descs = ACX_RX_DESC_DEF; | ||
953 | mem_conf->rx_queue_config.priority = DEFAULT_RXQ_PRIORITY; | ||
954 | mem_conf->rx_queue_config.type = DEFAULT_RXQ_TYPE; | ||
955 | |||
956 | /* TX queue config */ | ||
957 | for (i = 0; i < MAX_TX_QUEUES; i++) { | ||
958 | mem_conf->tx_queue_config[i].num_descs = ACX_TX_DESC_DEF; | ||
959 | mem_conf->tx_queue_config[i].attributes = i; | ||
960 | } | ||
961 | |||
962 | ret = wl1251_cmd_configure(wl, ACX_MEM_CFG, mem_conf, | ||
963 | sizeof(*mem_conf)); | ||
964 | if (ret < 0) { | ||
965 | wl1251_warning("wl1251 mem config failed: %d", ret); | ||
966 | goto out; | ||
967 | } | ||
968 | |||
969 | out: | ||
970 | kfree(mem_conf); | ||
971 | return ret; | ||
972 | } | ||
973 | |||
974 | int wl1251_acx_wr_tbtt_and_dtim(struct wl1251 *wl, u16 tbtt, u8 dtim) | ||
975 | { | ||
976 | struct wl1251_acx_wr_tbtt_and_dtim *acx; | ||
977 | int ret; | ||
978 | |||
979 | wl1251_debug(DEBUG_ACX, "acx tbtt and dtim"); | ||
980 | |||
981 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
982 | if (!acx) { | ||
983 | ret = -ENOMEM; | ||
984 | goto out; | ||
985 | } | ||
986 | |||
987 | acx->tbtt = tbtt; | ||
988 | acx->dtim = dtim; | ||
989 | |||
990 | ret = wl1251_cmd_configure(wl, ACX_WR_TBTT_AND_DTIM, | ||
991 | acx, sizeof(*acx)); | ||
992 | if (ret < 0) { | ||
993 | wl1251_warning("failed to set tbtt and dtim: %d", ret); | ||
994 | goto out; | ||
995 | } | ||
996 | |||
997 | out: | ||
998 | kfree(acx); | ||
999 | return ret; | ||
1000 | } | ||
1001 | |||
1002 | int wl1251_acx_bet_enable(struct wl1251 *wl, enum wl1251_acx_bet_mode mode, | ||
1003 | u8 max_consecutive) | ||
1004 | { | ||
1005 | struct wl1251_acx_bet_enable *acx; | ||
1006 | int ret; | ||
1007 | |||
1008 | wl1251_debug(DEBUG_ACX, "acx bet enable"); | ||
1009 | |||
1010 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
1011 | if (!acx) { | ||
1012 | ret = -ENOMEM; | ||
1013 | goto out; | ||
1014 | } | ||
1015 | |||
1016 | acx->enable = mode; | ||
1017 | acx->max_consecutive = max_consecutive; | ||
1018 | |||
1019 | ret = wl1251_cmd_configure(wl, ACX_BET_ENABLE, acx, sizeof(*acx)); | ||
1020 | if (ret < 0) { | ||
1021 | wl1251_warning("wl1251 acx bet enable failed: %d", ret); | ||
1022 | goto out; | ||
1023 | } | ||
1024 | |||
1025 | out: | ||
1026 | kfree(acx); | ||
1027 | return ret; | ||
1028 | } | ||
1029 | |||
1030 | int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max, | ||
1031 | u8 aifs, u16 txop) | ||
1032 | { | ||
1033 | struct wl1251_acx_ac_cfg *acx; | ||
1034 | int ret = 0; | ||
1035 | |||
1036 | wl1251_debug(DEBUG_ACX, "acx ac cfg %d cw_ming %d cw_max %d " | ||
1037 | "aifs %d txop %d", ac, cw_min, cw_max, aifs, txop); | ||
1038 | |||
1039 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
1040 | |||
1041 | if (!acx) { | ||
1042 | ret = -ENOMEM; | ||
1043 | goto out; | ||
1044 | } | ||
1045 | |||
1046 | acx->ac = ac; | ||
1047 | acx->cw_min = cw_min; | ||
1048 | acx->cw_max = cw_max; | ||
1049 | acx->aifsn = aifs; | ||
1050 | acx->txop_limit = txop; | ||
1051 | |||
1052 | ret = wl1251_cmd_configure(wl, ACX_AC_CFG, acx, sizeof(*acx)); | ||
1053 | if (ret < 0) { | ||
1054 | wl1251_warning("acx ac cfg failed: %d", ret); | ||
1055 | goto out; | ||
1056 | } | ||
1057 | |||
1058 | out: | ||
1059 | kfree(acx); | ||
1060 | return ret; | ||
1061 | } | ||
1062 | |||
1063 | int wl1251_acx_tid_cfg(struct wl1251 *wl, u8 queue, | ||
1064 | enum wl1251_acx_channel_type type, | ||
1065 | u8 tsid, enum wl1251_acx_ps_scheme ps_scheme, | ||
1066 | enum wl1251_acx_ack_policy ack_policy) | ||
1067 | { | ||
1068 | struct wl1251_acx_tid_cfg *acx; | ||
1069 | int ret = 0; | ||
1070 | |||
1071 | wl1251_debug(DEBUG_ACX, "acx tid cfg %d type %d tsid %d " | ||
1072 | "ps_scheme %d ack_policy %d", queue, type, tsid, | ||
1073 | ps_scheme, ack_policy); | ||
1074 | |||
1075 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
1076 | |||
1077 | if (!acx) { | ||
1078 | ret = -ENOMEM; | ||
1079 | goto out; | ||
1080 | } | ||
1081 | |||
1082 | acx->queue = queue; | ||
1083 | acx->type = type; | ||
1084 | acx->tsid = tsid; | ||
1085 | acx->ps_scheme = ps_scheme; | ||
1086 | acx->ack_policy = ack_policy; | ||
1087 | |||
1088 | ret = wl1251_cmd_configure(wl, ACX_TID_CFG, acx, sizeof(*acx)); | ||
1089 | if (ret < 0) { | ||
1090 | wl1251_warning("acx tid cfg failed: %d", ret); | ||
1091 | goto out; | ||
1092 | } | ||
1093 | |||
1094 | out: | ||
1095 | kfree(acx); | ||
1096 | return ret; | ||
1097 | } | ||
diff --git a/drivers/net/wireless/ti/wl1251/acx.h b/drivers/net/wireless/ti/wl1251/acx.h new file mode 100644 index 000000000000..c2ba100f9b1a --- /dev/null +++ b/drivers/net/wireless/ti/wl1251/acx.h | |||
@@ -0,0 +1,1483 @@ | |||
1 | /* | ||
2 | * This file is part of wl1251 | ||
3 | * | ||
4 | * Copyright (c) 1998-2007 Texas Instruments Incorporated | ||
5 | * Copyright (C) 2008 Nokia Corporation | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * version 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
19 | * 02110-1301 USA | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #ifndef __WL1251_ACX_H__ | ||
24 | #define __WL1251_ACX_H__ | ||
25 | |||
26 | #include "wl1251.h" | ||
27 | #include "cmd.h" | ||
28 | |||
29 | /* Target's information element */ | ||
30 | struct acx_header { | ||
31 | struct wl1251_cmd_header cmd; | ||
32 | |||
33 | /* acx (or information element) header */ | ||
34 | u16 id; | ||
35 | |||
36 | /* payload length (not including headers */ | ||
37 | u16 len; | ||
38 | } __packed; | ||
39 | |||
40 | struct acx_error_counter { | ||
41 | struct acx_header header; | ||
42 | |||
43 | /* The number of PLCP errors since the last time this */ | ||
44 | /* information element was interrogated. This field is */ | ||
45 | /* automatically cleared when it is interrogated.*/ | ||
46 | u32 PLCP_error; | ||
47 | |||
48 | /* The number of FCS errors since the last time this */ | ||
49 | /* information element was interrogated. This field is */ | ||
50 | /* automatically cleared when it is interrogated.*/ | ||
51 | u32 FCS_error; | ||
52 | |||
53 | /* The number of MPDUs without PLCP header errors received*/ | ||
54 | /* since the last time this information element was interrogated. */ | ||
55 | /* This field is automatically cleared when it is interrogated.*/ | ||
56 | u32 valid_frame; | ||
57 | |||
58 | /* the number of missed sequence numbers in the squentially */ | ||
59 | /* values of frames seq numbers */ | ||
60 | u32 seq_num_miss; | ||
61 | } __packed; | ||
62 | |||
63 | struct acx_revision { | ||
64 | struct acx_header header; | ||
65 | |||
66 | /* | ||
67 | * The WiLink firmware version, an ASCII string x.x.x.x, | ||
68 | * that uniquely identifies the current firmware. | ||
69 | * The left most digit is incremented each time a | ||
70 | * significant change is made to the firmware, such as | ||
71 | * code redesign or new platform support. | ||
72 | * The second digit is incremented when major enhancements | ||
73 | * are added or major fixes are made. | ||
74 | * The third digit is incremented for each GA release. | ||
75 | * The fourth digit is incremented for each build. | ||
76 | * The first two digits identify a firmware release version, | ||
77 | * in other words, a unique set of features. | ||
78 | * The first three digits identify a GA release. | ||
79 | */ | ||
80 | char fw_version[20]; | ||
81 | |||
82 | /* | ||
83 | * This 4 byte field specifies the WiLink hardware version. | ||
84 | * bits 0 - 15: Reserved. | ||
85 | * bits 16 - 23: Version ID - The WiLink version ID | ||
86 | * (1 = first spin, 2 = second spin, and so on). | ||
87 | * bits 24 - 31: Chip ID - The WiLink chip ID. | ||
88 | */ | ||
89 | u32 hw_version; | ||
90 | } __packed; | ||
91 | |||
92 | enum wl1251_psm_mode { | ||
93 | /* Active mode */ | ||
94 | WL1251_PSM_CAM = 0, | ||
95 | |||
96 | /* Power save mode */ | ||
97 | WL1251_PSM_PS = 1, | ||
98 | |||
99 | /* Extreme low power */ | ||
100 | WL1251_PSM_ELP = 2, | ||
101 | }; | ||
102 | |||
103 | struct acx_sleep_auth { | ||
104 | struct acx_header header; | ||
105 | |||
106 | /* The sleep level authorization of the device. */ | ||
107 | /* 0 - Always active*/ | ||
108 | /* 1 - Power down mode: light / fast sleep*/ | ||
109 | /* 2 - ELP mode: Deep / Max sleep*/ | ||
110 | u8 sleep_auth; | ||
111 | u8 padding[3]; | ||
112 | } __packed; | ||
113 | |||
114 | enum { | ||
115 | HOSTIF_PCI_MASTER_HOST_INDIRECT, | ||
116 | HOSTIF_PCI_MASTER_HOST_DIRECT, | ||
117 | HOSTIF_SLAVE, | ||
118 | HOSTIF_PKT_RING, | ||
119 | HOSTIF_DONTCARE = 0xFF | ||
120 | }; | ||
121 | |||
122 | #define DEFAULT_UCAST_PRIORITY 0 | ||
123 | #define DEFAULT_RX_Q_PRIORITY 0 | ||
124 | #define DEFAULT_NUM_STATIONS 1 | ||
125 | #define DEFAULT_RXQ_PRIORITY 0 /* low 0 .. 15 high */ | ||
126 | #define DEFAULT_RXQ_TYPE 0x07 /* All frames, Data/Ctrl/Mgmt */ | ||
127 | #define TRACE_BUFFER_MAX_SIZE 256 | ||
128 | |||
129 | #define DP_RX_PACKET_RING_CHUNK_SIZE 1600 | ||
130 | #define DP_TX_PACKET_RING_CHUNK_SIZE 1600 | ||
131 | #define DP_RX_PACKET_RING_CHUNK_NUM 2 | ||
132 | #define DP_TX_PACKET_RING_CHUNK_NUM 2 | ||
133 | #define DP_TX_COMPLETE_TIME_OUT 20 | ||
134 | #define FW_TX_CMPLT_BLOCK_SIZE 16 | ||
135 | |||
136 | struct acx_data_path_params { | ||
137 | struct acx_header header; | ||
138 | |||
139 | u16 rx_packet_ring_chunk_size; | ||
140 | u16 tx_packet_ring_chunk_size; | ||
141 | |||
142 | u8 rx_packet_ring_chunk_num; | ||
143 | u8 tx_packet_ring_chunk_num; | ||
144 | |||
145 | /* | ||
146 | * Maximum number of packets that can be gathered | ||
147 | * in the TX complete ring before an interrupt | ||
148 | * is generated. | ||
149 | */ | ||
150 | u8 tx_complete_threshold; | ||
151 | |||
152 | /* Number of pending TX complete entries in cyclic ring.*/ | ||
153 | u8 tx_complete_ring_depth; | ||
154 | |||
155 | /* | ||
156 | * Max num microseconds since a packet enters the TX | ||
157 | * complete ring until an interrupt is generated. | ||
158 | */ | ||
159 | u32 tx_complete_timeout; | ||
160 | } __packed; | ||
161 | |||
162 | |||
163 | struct acx_data_path_params_resp { | ||
164 | struct acx_header header; | ||
165 | |||
166 | u16 rx_packet_ring_chunk_size; | ||
167 | u16 tx_packet_ring_chunk_size; | ||
168 | |||
169 | u8 rx_packet_ring_chunk_num; | ||
170 | u8 tx_packet_ring_chunk_num; | ||
171 | |||
172 | u8 pad[2]; | ||
173 | |||
174 | u32 rx_packet_ring_addr; | ||
175 | u32 tx_packet_ring_addr; | ||
176 | |||
177 | u32 rx_control_addr; | ||
178 | u32 tx_control_addr; | ||
179 | |||
180 | u32 tx_complete_addr; | ||
181 | } __packed; | ||
182 | |||
183 | #define TX_MSDU_LIFETIME_MIN 0 | ||
184 | #define TX_MSDU_LIFETIME_MAX 3000 | ||
185 | #define TX_MSDU_LIFETIME_DEF 512 | ||
186 | #define RX_MSDU_LIFETIME_MIN 0 | ||
187 | #define RX_MSDU_LIFETIME_MAX 0xFFFFFFFF | ||
188 | #define RX_MSDU_LIFETIME_DEF 512000 | ||
189 | |||
190 | struct acx_rx_msdu_lifetime { | ||
191 | struct acx_header header; | ||
192 | |||
193 | /* | ||
194 | * The maximum amount of time, in TU, before the | ||
195 | * firmware discards the MSDU. | ||
196 | */ | ||
197 | u32 lifetime; | ||
198 | } __packed; | ||
199 | |||
200 | /* | ||
201 | * RX Config Options Table | ||
202 | * Bit Definition | ||
203 | * === ========== | ||
204 | * 31:14 Reserved | ||
205 | * 13 Copy RX Status - when set, write three receive status words | ||
206 | * to top of rx'd MPDUs. | ||
207 | * When cleared, do not write three status words (added rev 1.5) | ||
208 | * 12 Reserved | ||
209 | * 11 RX Complete upon FCS error - when set, give rx complete | ||
210 | * interrupt for FCS errors, after the rx filtering, e.g. unicast | ||
211 | * frames not to us with FCS error will not generate an interrupt. | ||
212 | * 10 SSID Filter Enable - When set, the WiLink discards all beacon, | ||
213 | * probe request, and probe response frames with an SSID that does | ||
214 | * not match the SSID specified by the host in the START/JOIN | ||
215 | * command. | ||
216 | * When clear, the WiLink receives frames with any SSID. | ||
217 | * 9 Broadcast Filter Enable - When set, the WiLink discards all | ||
218 | * broadcast frames. When clear, the WiLink receives all received | ||
219 | * broadcast frames. | ||
220 | * 8:6 Reserved | ||
221 | * 5 BSSID Filter Enable - When set, the WiLink discards any frames | ||
222 | * with a BSSID that does not match the BSSID specified by the | ||
223 | * host. | ||
224 | * When clear, the WiLink receives frames from any BSSID. | ||
225 | * 4 MAC Addr Filter - When set, the WiLink discards any frames | ||
226 | * with a destination address that does not match the MAC address | ||
227 | * of the adaptor. | ||
228 | * When clear, the WiLink receives frames destined to any MAC | ||
229 | * address. | ||
230 | * 3 Promiscuous - When set, the WiLink receives all valid frames | ||
231 | * (i.e., all frames that pass the FCS check). | ||
232 | * When clear, only frames that pass the other filters specified | ||
233 | * are received. | ||
234 | * 2 FCS - When set, the WiLink includes the FCS with the received | ||
235 | * frame. | ||
236 | * When cleared, the FCS is discarded. | ||
237 | * 1 PLCP header - When set, write all data from baseband to frame | ||
238 | * buffer including PHY header. | ||
239 | * 0 Reserved - Always equal to 0. | ||
240 | * | ||
241 | * RX Filter Options Table | ||
242 | * Bit Definition | ||
243 | * === ========== | ||
244 | * 31:12 Reserved - Always equal to 0. | ||
245 | * 11 Association - When set, the WiLink receives all association | ||
246 | * related frames (association request/response, reassocation | ||
247 | * request/response, and disassociation). When clear, these frames | ||
248 | * are discarded. | ||
249 | * 10 Auth/De auth - When set, the WiLink receives all authentication | ||
250 | * and de-authentication frames. When clear, these frames are | ||
251 | * discarded. | ||
252 | * 9 Beacon - When set, the WiLink receives all beacon frames. | ||
253 | * When clear, these frames are discarded. | ||
254 | * 8 Contention Free - When set, the WiLink receives all contention | ||
255 | * free frames. | ||
256 | * When clear, these frames are discarded. | ||
257 | * 7 Control - When set, the WiLink receives all control frames. | ||
258 | * When clear, these frames are discarded. | ||
259 | * 6 Data - When set, the WiLink receives all data frames. | ||
260 | * When clear, these frames are discarded. | ||
261 | * 5 FCS Error - When set, the WiLink receives frames that have FCS | ||
262 | * errors. | ||
263 | * When clear, these frames are discarded. | ||
264 | * 4 Management - When set, the WiLink receives all management | ||
265 | * frames. | ||
266 | * When clear, these frames are discarded. | ||
267 | * 3 Probe Request - When set, the WiLink receives all probe request | ||
268 | * frames. | ||
269 | * When clear, these frames are discarded. | ||
270 | * 2 Probe Response - When set, the WiLink receives all probe | ||
271 | * response frames. | ||
272 | * When clear, these frames are discarded. | ||
273 | * 1 RTS/CTS/ACK - When set, the WiLink receives all RTS, CTS and ACK | ||
274 | * frames. | ||
275 | * When clear, these frames are discarded. | ||
276 | * 0 Rsvd Type/Sub Type - When set, the WiLink receives all frames | ||
277 | * that have reserved frame types and sub types as defined by the | ||
278 | * 802.11 specification. | ||
279 | * When clear, these frames are discarded. | ||
280 | */ | ||
281 | struct acx_rx_config { | ||
282 | struct acx_header header; | ||
283 | |||
284 | u32 config_options; | ||
285 | u32 filter_options; | ||
286 | } __packed; | ||
287 | |||
288 | enum { | ||
289 | QOS_AC_BE = 0, | ||
290 | QOS_AC_BK, | ||
291 | QOS_AC_VI, | ||
292 | QOS_AC_VO, | ||
293 | QOS_HIGHEST_AC_INDEX = QOS_AC_VO, | ||
294 | }; | ||
295 | |||
296 | #define MAX_NUM_OF_AC (QOS_HIGHEST_AC_INDEX+1) | ||
297 | #define FIRST_AC_INDEX QOS_AC_BE | ||
298 | #define MAX_NUM_OF_802_1d_TAGS 8 | ||
299 | #define AC_PARAMS_MAX_TSID 15 | ||
300 | #define MAX_APSD_CONF 0xffff | ||
301 | |||
302 | #define QOS_TX_HIGH_MIN (0) | ||
303 | #define QOS_TX_HIGH_MAX (100) | ||
304 | |||
305 | #define QOS_TX_HIGH_BK_DEF (25) | ||
306 | #define QOS_TX_HIGH_BE_DEF (35) | ||
307 | #define QOS_TX_HIGH_VI_DEF (35) | ||
308 | #define QOS_TX_HIGH_VO_DEF (35) | ||
309 | |||
310 | #define QOS_TX_LOW_BK_DEF (15) | ||
311 | #define QOS_TX_LOW_BE_DEF (25) | ||
312 | #define QOS_TX_LOW_VI_DEF (25) | ||
313 | #define QOS_TX_LOW_VO_DEF (25) | ||
314 | |||
315 | struct acx_tx_queue_qos_config { | ||
316 | struct acx_header header; | ||
317 | |||
318 | u8 qid; | ||
319 | u8 pad[3]; | ||
320 | |||
321 | /* Max number of blocks allowd in the queue */ | ||
322 | u16 high_threshold; | ||
323 | |||
324 | /* Lowest memory blocks guaranteed for this queue */ | ||
325 | u16 low_threshold; | ||
326 | } __packed; | ||
327 | |||
328 | struct acx_packet_detection { | ||
329 | struct acx_header header; | ||
330 | |||
331 | u32 threshold; | ||
332 | } __packed; | ||
333 | |||
334 | |||
335 | enum acx_slot_type { | ||
336 | SLOT_TIME_LONG = 0, | ||
337 | SLOT_TIME_SHORT = 1, | ||
338 | DEFAULT_SLOT_TIME = SLOT_TIME_SHORT, | ||
339 | MAX_SLOT_TIMES = 0xFF | ||
340 | }; | ||
341 | |||
342 | #define STATION_WONE_INDEX 0 | ||
343 | |||
344 | struct acx_slot { | ||
345 | struct acx_header header; | ||
346 | |||
347 | u8 wone_index; /* Reserved */ | ||
348 | u8 slot_time; | ||
349 | u8 reserved[6]; | ||
350 | } __packed; | ||
351 | |||
352 | |||
353 | #define ADDRESS_GROUP_MAX (8) | ||
354 | #define ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ADDRESS_GROUP_MAX) | ||
355 | |||
356 | struct acx_dot11_grp_addr_tbl { | ||
357 | struct acx_header header; | ||
358 | |||
359 | u8 enabled; | ||
360 | u8 num_groups; | ||
361 | u8 pad[2]; | ||
362 | u8 mac_table[ADDRESS_GROUP_MAX_LEN]; | ||
363 | } __packed; | ||
364 | |||
365 | |||
366 | #define RX_TIMEOUT_PS_POLL_MIN 0 | ||
367 | #define RX_TIMEOUT_PS_POLL_MAX (200000) | ||
368 | #define RX_TIMEOUT_PS_POLL_DEF (15) | ||
369 | #define RX_TIMEOUT_UPSD_MIN 0 | ||
370 | #define RX_TIMEOUT_UPSD_MAX (200000) | ||
371 | #define RX_TIMEOUT_UPSD_DEF (15) | ||
372 | |||
373 | struct acx_rx_timeout { | ||
374 | struct acx_header header; | ||
375 | |||
376 | /* | ||
377 | * The longest time the STA will wait to receive | ||
378 | * traffic from the AP after a PS-poll has been | ||
379 | * transmitted. | ||
380 | */ | ||
381 | u16 ps_poll_timeout; | ||
382 | |||
383 | /* | ||
384 | * The longest time the STA will wait to receive | ||
385 | * traffic from the AP after a frame has been sent | ||
386 | * from an UPSD enabled queue. | ||
387 | */ | ||
388 | u16 upsd_timeout; | ||
389 | } __packed; | ||
390 | |||
391 | #define RTS_THRESHOLD_MIN 0 | ||
392 | #define RTS_THRESHOLD_MAX 4096 | ||
393 | #define RTS_THRESHOLD_DEF 2347 | ||
394 | |||
395 | struct acx_rts_threshold { | ||
396 | struct acx_header header; | ||
397 | |||
398 | u16 threshold; | ||
399 | u8 pad[2]; | ||
400 | } __packed; | ||
401 | |||
402 | enum wl1251_acx_low_rssi_type { | ||
403 | /* | ||
404 | * The event is a "Level" indication which keeps triggering | ||
405 | * as long as the average RSSI is below the threshold. | ||
406 | */ | ||
407 | WL1251_ACX_LOW_RSSI_TYPE_LEVEL = 0, | ||
408 | |||
409 | /* | ||
410 | * The event is an "Edge" indication which triggers | ||
411 | * only when the RSSI threshold is crossed from above. | ||
412 | */ | ||
413 | WL1251_ACX_LOW_RSSI_TYPE_EDGE = 1, | ||
414 | }; | ||
415 | |||
416 | struct acx_low_rssi { | ||
417 | struct acx_header header; | ||
418 | |||
419 | /* | ||
420 | * The threshold (in dBm) below (or above after low rssi | ||
421 | * indication) which the firmware generates an interrupt to the | ||
422 | * host. This parameter is signed. | ||
423 | */ | ||
424 | s8 threshold; | ||
425 | |||
426 | /* | ||
427 | * The weight of the current RSSI sample, before adding the new | ||
428 | * sample, that is used to calculate the average RSSI. | ||
429 | */ | ||
430 | u8 weight; | ||
431 | |||
432 | /* | ||
433 | * The number of Beacons/Probe response frames that will be | ||
434 | * received before issuing the Low or Regained RSSI event. | ||
435 | */ | ||
436 | u8 depth; | ||
437 | |||
438 | /* | ||
439 | * Configures how the Low RSSI Event is triggered. Refer to | ||
440 | * enum wl1251_acx_low_rssi_type for more. | ||
441 | */ | ||
442 | u8 type; | ||
443 | } __packed; | ||
444 | |||
445 | struct acx_beacon_filter_option { | ||
446 | struct acx_header header; | ||
447 | |||
448 | u8 enable; | ||
449 | |||
450 | /* | ||
451 | * The number of beacons without the unicast TIM | ||
452 | * bit set that the firmware buffers before | ||
453 | * signaling the host about ready frames. | ||
454 | * When set to 0 and the filter is enabled, beacons | ||
455 | * without the unicast TIM bit set are dropped. | ||
456 | */ | ||
457 | u8 max_num_beacons; | ||
458 | u8 pad[2]; | ||
459 | } __packed; | ||
460 | |||
461 | /* | ||
462 | * ACXBeaconFilterEntry (not 221) | ||
463 | * Byte Offset Size (Bytes) Definition | ||
464 | * =========== ============ ========== | ||
465 | * 0 1 IE identifier | ||
466 | * 1 1 Treatment bit mask | ||
467 | * | ||
468 | * ACXBeaconFilterEntry (221) | ||
469 | * Byte Offset Size (Bytes) Definition | ||
470 | * =========== ============ ========== | ||
471 | * 0 1 IE identifier | ||
472 | * 1 1 Treatment bit mask | ||
473 | * 2 3 OUI | ||
474 | * 5 1 Type | ||
475 | * 6 2 Version | ||
476 | * | ||
477 | * | ||
478 | * Treatment bit mask - The information element handling: | ||
479 | * bit 0 - The information element is compared and transferred | ||
480 | * in case of change. | ||
481 | * bit 1 - The information element is transferred to the host | ||
482 | * with each appearance or disappearance. | ||
483 | * Note that both bits can be set at the same time. | ||
484 | */ | ||
485 | #define BEACON_FILTER_TABLE_MAX_IE_NUM (32) | ||
486 | #define BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM (6) | ||
487 | #define BEACON_FILTER_TABLE_IE_ENTRY_SIZE (2) | ||
488 | #define BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE (6) | ||
489 | #define BEACON_FILTER_TABLE_MAX_SIZE ((BEACON_FILTER_TABLE_MAX_IE_NUM * \ | ||
490 | BEACON_FILTER_TABLE_IE_ENTRY_SIZE) + \ | ||
491 | (BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM * \ | ||
492 | BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE)) | ||
493 | |||
494 | #define BEACON_RULE_PASS_ON_CHANGE BIT(0) | ||
495 | #define BEACON_RULE_PASS_ON_APPEARANCE BIT(1) | ||
496 | |||
497 | #define BEACON_FILTER_IE_ID_CHANNEL_SWITCH_ANN (37) | ||
498 | |||
499 | struct acx_beacon_filter_ie_table { | ||
500 | struct acx_header header; | ||
501 | |||
502 | u8 num_ie; | ||
503 | u8 pad[3]; | ||
504 | u8 table[BEACON_FILTER_TABLE_MAX_SIZE]; | ||
505 | } __packed; | ||
506 | |||
507 | #define SYNCH_FAIL_DEFAULT_THRESHOLD 10 /* number of beacons */ | ||
508 | #define NO_BEACON_DEFAULT_TIMEOUT (500) /* in microseconds */ | ||
509 | |||
510 | struct acx_conn_monit_params { | ||
511 | struct acx_header header; | ||
512 | |||
513 | u32 synch_fail_thold; /* number of beacons missed */ | ||
514 | u32 bss_lose_timeout; /* number of TU's from synch fail */ | ||
515 | } __packed; | ||
516 | |||
517 | enum { | ||
518 | SG_ENABLE = 0, | ||
519 | SG_DISABLE, | ||
520 | SG_SENSE_NO_ACTIVITY, | ||
521 | SG_SENSE_ACTIVE | ||
522 | }; | ||
523 | |||
524 | struct acx_bt_wlan_coex { | ||
525 | struct acx_header header; | ||
526 | |||
527 | /* | ||
528 | * 0 -> PTA enabled | ||
529 | * 1 -> PTA disabled | ||
530 | * 2 -> sense no active mode, i.e. | ||
531 | * an interrupt is sent upon | ||
532 | * BT activity. | ||
533 | * 3 -> PTA is switched on in response | ||
534 | * to the interrupt sending. | ||
535 | */ | ||
536 | u8 enable; | ||
537 | u8 pad[3]; | ||
538 | } __packed; | ||
539 | |||
540 | #define PTA_ANTENNA_TYPE_DEF (0) | ||
541 | #define PTA_BT_HP_MAXTIME_DEF (2000) | ||
542 | #define PTA_WLAN_HP_MAX_TIME_DEF (5000) | ||
543 | #define PTA_SENSE_DISABLE_TIMER_DEF (1350) | ||
544 | #define PTA_PROTECTIVE_RX_TIME_DEF (1500) | ||
545 | #define PTA_PROTECTIVE_TX_TIME_DEF (1500) | ||
546 | #define PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF (3000) | ||
547 | #define PTA_SIGNALING_TYPE_DEF (1) | ||
548 | #define PTA_AFH_LEVERAGE_ON_DEF (0) | ||
549 | #define PTA_NUMBER_QUIET_CYCLE_DEF (0) | ||
550 | #define PTA_MAX_NUM_CTS_DEF (3) | ||
551 | #define PTA_NUMBER_OF_WLAN_PACKETS_DEF (2) | ||
552 | #define PTA_NUMBER_OF_BT_PACKETS_DEF (2) | ||
553 | #define PTA_PROTECTIVE_RX_TIME_FAST_DEF (1500) | ||
554 | #define PTA_PROTECTIVE_TX_TIME_FAST_DEF (3000) | ||
555 | #define PTA_CYCLE_TIME_FAST_DEF (8700) | ||
556 | #define PTA_RX_FOR_AVALANCHE_DEF (5) | ||
557 | #define PTA_ELP_HP_DEF (0) | ||
558 | #define PTA_ANTI_STARVE_PERIOD_DEF (500) | ||
559 | #define PTA_ANTI_STARVE_NUM_CYCLE_DEF (4) | ||
560 | #define PTA_ALLOW_PA_SD_DEF (1) | ||
561 | #define PTA_TIME_BEFORE_BEACON_DEF (6300) | ||
562 | #define PTA_HPDM_MAX_TIME_DEF (1600) | ||
563 | #define PTA_TIME_OUT_NEXT_WLAN_DEF (2550) | ||
564 | #define PTA_AUTO_MODE_NO_CTS_DEF (0) | ||
565 | #define PTA_BT_HP_RESPECTED_DEF (3) | ||
566 | #define PTA_WLAN_RX_MIN_RATE_DEF (24) | ||
567 | #define PTA_ACK_MODE_DEF (1) | ||
568 | |||
569 | struct acx_bt_wlan_coex_param { | ||
570 | struct acx_header header; | ||
571 | |||
572 | /* | ||
573 | * The minimum rate of a received WLAN packet in the STA, | ||
574 | * during protective mode, of which a new BT-HP request | ||
575 | * during this Rx will always be respected and gain the antenna. | ||
576 | */ | ||
577 | u32 min_rate; | ||
578 | |||
579 | /* Max time the BT HP will be respected. */ | ||
580 | u16 bt_hp_max_time; | ||
581 | |||
582 | /* Max time the WLAN HP will be respected. */ | ||
583 | u16 wlan_hp_max_time; | ||
584 | |||
585 | /* | ||
586 | * The time between the last BT activity | ||
587 | * and the moment when the sense mode returns | ||
588 | * to SENSE_INACTIVE. | ||
589 | */ | ||
590 | u16 sense_disable_timer; | ||
591 | |||
592 | /* Time before the next BT HP instance */ | ||
593 | u16 rx_time_bt_hp; | ||
594 | u16 tx_time_bt_hp; | ||
595 | |||
596 | /* range: 10-20000 default: 1500 */ | ||
597 | u16 rx_time_bt_hp_fast; | ||
598 | u16 tx_time_bt_hp_fast; | ||
599 | |||
600 | /* range: 2000-65535 default: 8700 */ | ||
601 | u16 wlan_cycle_fast; | ||
602 | |||
603 | /* range: 0 - 15000 (Msec) default: 1000 */ | ||
604 | u16 bt_anti_starvation_period; | ||
605 | |||
606 | /* range 400-10000(Usec) default: 3000 */ | ||
607 | u16 next_bt_lp_packet; | ||
608 | |||
609 | /* Deafult: worst case for BT DH5 traffic */ | ||
610 | u16 wake_up_beacon; | ||
611 | |||
612 | /* range: 0-50000(Usec) default: 1050 */ | ||
613 | u16 hp_dm_max_guard_time; | ||
614 | |||
615 | /* | ||
616 | * This is to prevent both BT & WLAN antenna | ||
617 | * starvation. | ||
618 | * Range: 100-50000(Usec) default:2550 | ||
619 | */ | ||
620 | u16 next_wlan_packet; | ||
621 | |||
622 | /* 0 -> shared antenna */ | ||
623 | u8 antenna_type; | ||
624 | |||
625 | /* | ||
626 | * 0 -> TI legacy | ||
627 | * 1 -> Palau | ||
628 | */ | ||
629 | u8 signal_type; | ||
630 | |||
631 | /* | ||
632 | * BT AFH status | ||
633 | * 0 -> no AFH | ||
634 | * 1 -> from dedicated GPIO | ||
635 | * 2 -> AFH on (from host) | ||
636 | */ | ||
637 | u8 afh_leverage_on; | ||
638 | |||
639 | /* | ||
640 | * The number of cycles during which no | ||
641 | * TX will be sent after 1 cycle of RX | ||
642 | * transaction in protective mode | ||
643 | */ | ||
644 | u8 quiet_cycle_num; | ||
645 | |||
646 | /* | ||
647 | * The maximum number of CTSs that will | ||
648 | * be sent for receiving RX packet in | ||
649 | * protective mode | ||
650 | */ | ||
651 | u8 max_cts; | ||
652 | |||
653 | /* | ||
654 | * The number of WLAN packets | ||
655 | * transferred in common mode before | ||
656 | * switching to BT. | ||
657 | */ | ||
658 | u8 wlan_packets_num; | ||
659 | |||
660 | /* | ||
661 | * The number of BT packets | ||
662 | * transferred in common mode before | ||
663 | * switching to WLAN. | ||
664 | */ | ||
665 | u8 bt_packets_num; | ||
666 | |||
667 | /* range: 1-255 default: 5 */ | ||
668 | u8 missed_rx_avalanche; | ||
669 | |||
670 | /* range: 0-1 default: 1 */ | ||
671 | u8 wlan_elp_hp; | ||
672 | |||
673 | /* range: 0 - 15 default: 4 */ | ||
674 | u8 bt_anti_starvation_cycles; | ||
675 | |||
676 | u8 ack_mode_dual_ant; | ||
677 | |||
678 | /* | ||
679 | * Allow PA_SD assertion/de-assertion | ||
680 | * during enabled BT activity. | ||
681 | */ | ||
682 | u8 pa_sd_enable; | ||
683 | |||
684 | /* | ||
685 | * Enable/Disable PTA in auto mode: | ||
686 | * Support Both Active & P.S modes | ||
687 | */ | ||
688 | u8 pta_auto_mode_enable; | ||
689 | |||
690 | /* range: 0 - 20 default: 1 */ | ||
691 | u8 bt_hp_respected_num; | ||
692 | } __packed; | ||
693 | |||
694 | #define CCA_THRSH_ENABLE_ENERGY_D 0x140A | ||
695 | #define CCA_THRSH_DISABLE_ENERGY_D 0xFFEF | ||
696 | |||
697 | struct acx_energy_detection { | ||
698 | struct acx_header header; | ||
699 | |||
700 | /* The RX Clear Channel Assessment threshold in the PHY */ | ||
701 | u16 rx_cca_threshold; | ||
702 | u8 tx_energy_detection; | ||
703 | u8 pad; | ||
704 | } __packed; | ||
705 | |||
706 | #define BCN_RX_TIMEOUT_DEF_VALUE 10000 | ||
707 | #define BROADCAST_RX_TIMEOUT_DEF_VALUE 20000 | ||
708 | #define RX_BROADCAST_IN_PS_DEF_VALUE 1 | ||
709 | #define CONSECUTIVE_PS_POLL_FAILURE_DEF 4 | ||
710 | |||
711 | struct acx_beacon_broadcast { | ||
712 | struct acx_header header; | ||
713 | |||
714 | u16 beacon_rx_timeout; | ||
715 | u16 broadcast_timeout; | ||
716 | |||
717 | /* Enables receiving of broadcast packets in PS mode */ | ||
718 | u8 rx_broadcast_in_ps; | ||
719 | |||
720 | /* Consecutive PS Poll failures before updating the host */ | ||
721 | u8 ps_poll_threshold; | ||
722 | u8 pad[2]; | ||
723 | } __packed; | ||
724 | |||
725 | struct acx_event_mask { | ||
726 | struct acx_header header; | ||
727 | |||
728 | u32 event_mask; | ||
729 | u32 high_event_mask; /* Unused */ | ||
730 | } __packed; | ||
731 | |||
732 | #define CFG_RX_FCS BIT(2) | ||
733 | #define CFG_RX_ALL_GOOD BIT(3) | ||
734 | #define CFG_UNI_FILTER_EN BIT(4) | ||
735 | #define CFG_BSSID_FILTER_EN BIT(5) | ||
736 | #define CFG_MC_FILTER_EN BIT(6) | ||
737 | #define CFG_MC_ADDR0_EN BIT(7) | ||
738 | #define CFG_MC_ADDR1_EN BIT(8) | ||
739 | #define CFG_BC_REJECT_EN BIT(9) | ||
740 | #define CFG_SSID_FILTER_EN BIT(10) | ||
741 | #define CFG_RX_INT_FCS_ERROR BIT(11) | ||
742 | #define CFG_RX_INT_ENCRYPTED BIT(12) | ||
743 | #define CFG_RX_WR_RX_STATUS BIT(13) | ||
744 | #define CFG_RX_FILTER_NULTI BIT(14) | ||
745 | #define CFG_RX_RESERVE BIT(15) | ||
746 | #define CFG_RX_TIMESTAMP_TSF BIT(16) | ||
747 | |||
748 | #define CFG_RX_RSV_EN BIT(0) | ||
749 | #define CFG_RX_RCTS_ACK BIT(1) | ||
750 | #define CFG_RX_PRSP_EN BIT(2) | ||
751 | #define CFG_RX_PREQ_EN BIT(3) | ||
752 | #define CFG_RX_MGMT_EN BIT(4) | ||
753 | #define CFG_RX_FCS_ERROR BIT(5) | ||
754 | #define CFG_RX_DATA_EN BIT(6) | ||
755 | #define CFG_RX_CTL_EN BIT(7) | ||
756 | #define CFG_RX_CF_EN BIT(8) | ||
757 | #define CFG_RX_BCN_EN BIT(9) | ||
758 | #define CFG_RX_AUTH_EN BIT(10) | ||
759 | #define CFG_RX_ASSOC_EN BIT(11) | ||
760 | |||
761 | #define SCAN_PASSIVE BIT(0) | ||
762 | #define SCAN_5GHZ_BAND BIT(1) | ||
763 | #define SCAN_TRIGGERED BIT(2) | ||
764 | #define SCAN_PRIORITY_HIGH BIT(3) | ||
765 | |||
766 | struct acx_fw_gen_frame_rates { | ||
767 | struct acx_header header; | ||
768 | |||
769 | u8 tx_ctrl_frame_rate; /* RATE_* */ | ||
770 | u8 tx_ctrl_frame_mod; /* CCK_* or PBCC_* */ | ||
771 | u8 tx_mgt_frame_rate; | ||
772 | u8 tx_mgt_frame_mod; | ||
773 | } __packed; | ||
774 | |||
775 | /* STA MAC */ | ||
776 | struct acx_dot11_station_id { | ||
777 | struct acx_header header; | ||
778 | |||
779 | u8 mac[ETH_ALEN]; | ||
780 | u8 pad[2]; | ||
781 | } __packed; | ||
782 | |||
783 | struct acx_feature_config { | ||
784 | struct acx_header header; | ||
785 | |||
786 | u32 options; | ||
787 | u32 data_flow_options; | ||
788 | } __packed; | ||
789 | |||
790 | struct acx_current_tx_power { | ||
791 | struct acx_header header; | ||
792 | |||
793 | u8 current_tx_power; | ||
794 | u8 padding[3]; | ||
795 | } __packed; | ||
796 | |||
797 | struct acx_dot11_default_key { | ||
798 | struct acx_header header; | ||
799 | |||
800 | u8 id; | ||
801 | u8 pad[3]; | ||
802 | } __packed; | ||
803 | |||
804 | struct acx_tsf_info { | ||
805 | struct acx_header header; | ||
806 | |||
807 | u32 current_tsf_msb; | ||
808 | u32 current_tsf_lsb; | ||
809 | u32 last_TBTT_msb; | ||
810 | u32 last_TBTT_lsb; | ||
811 | u8 last_dtim_count; | ||
812 | u8 pad[3]; | ||
813 | } __packed; | ||
814 | |||
815 | enum acx_wake_up_event { | ||
816 | WAKE_UP_EVENT_BEACON_BITMAP = 0x01, /* Wake on every Beacon*/ | ||
817 | WAKE_UP_EVENT_DTIM_BITMAP = 0x02, /* Wake on every DTIM*/ | ||
818 | WAKE_UP_EVENT_N_DTIM_BITMAP = 0x04, /* Wake on every Nth DTIM */ | ||
819 | WAKE_UP_EVENT_N_BEACONS_BITMAP = 0x08, /* Wake on every Nth Beacon */ | ||
820 | WAKE_UP_EVENT_BITS_MASK = 0x0F | ||
821 | }; | ||
822 | |||
823 | struct acx_wake_up_condition { | ||
824 | struct acx_header header; | ||
825 | |||
826 | u8 wake_up_event; /* Only one bit can be set */ | ||
827 | u8 listen_interval; | ||
828 | u8 pad[2]; | ||
829 | } __packed; | ||
830 | |||
831 | struct acx_aid { | ||
832 | struct acx_header header; | ||
833 | |||
834 | /* | ||
835 | * To be set when associated with an AP. | ||
836 | */ | ||
837 | u16 aid; | ||
838 | u8 pad[2]; | ||
839 | } __packed; | ||
840 | |||
841 | enum acx_preamble_type { | ||
842 | ACX_PREAMBLE_LONG = 0, | ||
843 | ACX_PREAMBLE_SHORT = 1 | ||
844 | }; | ||
845 | |||
846 | struct acx_preamble { | ||
847 | struct acx_header header; | ||
848 | |||
849 | /* | ||
850 | * When set, the WiLink transmits the frames with a short preamble and | ||
851 | * when cleared, the WiLink transmits the frames with a long preamble. | ||
852 | */ | ||
853 | u8 preamble; | ||
854 | u8 padding[3]; | ||
855 | } __packed; | ||
856 | |||
857 | enum acx_ctsprotect_type { | ||
858 | CTSPROTECT_DISABLE = 0, | ||
859 | CTSPROTECT_ENABLE = 1 | ||
860 | }; | ||
861 | |||
862 | struct acx_ctsprotect { | ||
863 | struct acx_header header; | ||
864 | u8 ctsprotect; | ||
865 | u8 padding[3]; | ||
866 | } __packed; | ||
867 | |||
868 | struct acx_tx_statistics { | ||
869 | u32 internal_desc_overflow; | ||
870 | } __packed; | ||
871 | |||
872 | struct acx_rx_statistics { | ||
873 | u32 out_of_mem; | ||
874 | u32 hdr_overflow; | ||
875 | u32 hw_stuck; | ||
876 | u32 dropped; | ||
877 | u32 fcs_err; | ||
878 | u32 xfr_hint_trig; | ||
879 | u32 path_reset; | ||
880 | u32 reset_counter; | ||
881 | } __packed; | ||
882 | |||
883 | struct acx_dma_statistics { | ||
884 | u32 rx_requested; | ||
885 | u32 rx_errors; | ||
886 | u32 tx_requested; | ||
887 | u32 tx_errors; | ||
888 | } __packed; | ||
889 | |||
890 | struct acx_isr_statistics { | ||
891 | /* host command complete */ | ||
892 | u32 cmd_cmplt; | ||
893 | |||
894 | /* fiqisr() */ | ||
895 | u32 fiqs; | ||
896 | |||
897 | /* (INT_STS_ND & INT_TRIG_RX_HEADER) */ | ||
898 | u32 rx_headers; | ||
899 | |||
900 | /* (INT_STS_ND & INT_TRIG_RX_CMPLT) */ | ||
901 | u32 rx_completes; | ||
902 | |||
903 | /* (INT_STS_ND & INT_TRIG_NO_RX_BUF) */ | ||
904 | u32 rx_mem_overflow; | ||
905 | |||
906 | /* (INT_STS_ND & INT_TRIG_S_RX_RDY) */ | ||
907 | u32 rx_rdys; | ||
908 | |||
909 | /* irqisr() */ | ||
910 | u32 irqs; | ||
911 | |||
912 | /* (INT_STS_ND & INT_TRIG_TX_PROC) */ | ||
913 | u32 tx_procs; | ||
914 | |||
915 | /* (INT_STS_ND & INT_TRIG_DECRYPT_DONE) */ | ||
916 | u32 decrypt_done; | ||
917 | |||
918 | /* (INT_STS_ND & INT_TRIG_DMA0) */ | ||
919 | u32 dma0_done; | ||
920 | |||
921 | /* (INT_STS_ND & INT_TRIG_DMA1) */ | ||
922 | u32 dma1_done; | ||
923 | |||
924 | /* (INT_STS_ND & INT_TRIG_TX_EXC_CMPLT) */ | ||
925 | u32 tx_exch_complete; | ||
926 | |||
927 | /* (INT_STS_ND & INT_TRIG_COMMAND) */ | ||
928 | u32 commands; | ||
929 | |||
930 | /* (INT_STS_ND & INT_TRIG_RX_PROC) */ | ||
931 | u32 rx_procs; | ||
932 | |||
933 | /* (INT_STS_ND & INT_TRIG_PM_802) */ | ||
934 | u32 hw_pm_mode_changes; | ||
935 | |||
936 | /* (INT_STS_ND & INT_TRIG_ACKNOWLEDGE) */ | ||
937 | u32 host_acknowledges; | ||
938 | |||
939 | /* (INT_STS_ND & INT_TRIG_PM_PCI) */ | ||
940 | u32 pci_pm; | ||
941 | |||
942 | /* (INT_STS_ND & INT_TRIG_ACM_WAKEUP) */ | ||
943 | u32 wakeups; | ||
944 | |||
945 | /* (INT_STS_ND & INT_TRIG_LOW_RSSI) */ | ||
946 | u32 low_rssi; | ||
947 | } __packed; | ||
948 | |||
949 | struct acx_wep_statistics { | ||
950 | /* WEP address keys configured */ | ||
951 | u32 addr_key_count; | ||
952 | |||
953 | /* default keys configured */ | ||
954 | u32 default_key_count; | ||
955 | |||
956 | u32 reserved; | ||
957 | |||
958 | /* number of times that WEP key not found on lookup */ | ||
959 | u32 key_not_found; | ||
960 | |||
961 | /* number of times that WEP key decryption failed */ | ||
962 | u32 decrypt_fail; | ||
963 | |||
964 | /* WEP packets decrypted */ | ||
965 | u32 packets; | ||
966 | |||
967 | /* WEP decrypt interrupts */ | ||
968 | u32 interrupt; | ||
969 | } __packed; | ||
970 | |||
971 | #define ACX_MISSED_BEACONS_SPREAD 10 | ||
972 | |||
973 | struct acx_pwr_statistics { | ||
974 | /* the amount of enters into power save mode (both PD & ELP) */ | ||
975 | u32 ps_enter; | ||
976 | |||
977 | /* the amount of enters into ELP mode */ | ||
978 | u32 elp_enter; | ||
979 | |||
980 | /* the amount of missing beacon interrupts to the host */ | ||
981 | u32 missing_bcns; | ||
982 | |||
983 | /* the amount of wake on host-access times */ | ||
984 | u32 wake_on_host; | ||
985 | |||
986 | /* the amount of wake on timer-expire */ | ||
987 | u32 wake_on_timer_exp; | ||
988 | |||
989 | /* the number of packets that were transmitted with PS bit set */ | ||
990 | u32 tx_with_ps; | ||
991 | |||
992 | /* the number of packets that were transmitted with PS bit clear */ | ||
993 | u32 tx_without_ps; | ||
994 | |||
995 | /* the number of received beacons */ | ||
996 | u32 rcvd_beacons; | ||
997 | |||
998 | /* the number of entering into PowerOn (power save off) */ | ||
999 | u32 power_save_off; | ||
1000 | |||
1001 | /* the number of entries into power save mode */ | ||
1002 | u16 enable_ps; | ||
1003 | |||
1004 | /* | ||
1005 | * the number of exits from power save, not including failed PS | ||
1006 | * transitions | ||
1007 | */ | ||
1008 | u16 disable_ps; | ||
1009 | |||
1010 | /* | ||
1011 | * the number of times the TSF counter was adjusted because | ||
1012 | * of drift | ||
1013 | */ | ||
1014 | u32 fix_tsf_ps; | ||
1015 | |||
1016 | /* Gives statistics about the spread continuous missed beacons. | ||
1017 | * The 16 LSB are dedicated for the PS mode. | ||
1018 | * The 16 MSB are dedicated for the PS mode. | ||
1019 | * cont_miss_bcns_spread[0] - single missed beacon. | ||
1020 | * cont_miss_bcns_spread[1] - two continuous missed beacons. | ||
1021 | * cont_miss_bcns_spread[2] - three continuous missed beacons. | ||
1022 | * ... | ||
1023 | * cont_miss_bcns_spread[9] - ten and more continuous missed beacons. | ||
1024 | */ | ||
1025 | u32 cont_miss_bcns_spread[ACX_MISSED_BEACONS_SPREAD]; | ||
1026 | |||
1027 | /* the number of beacons in awake mode */ | ||
1028 | u32 rcvd_awake_beacons; | ||
1029 | } __packed; | ||
1030 | |||
1031 | struct acx_mic_statistics { | ||
1032 | u32 rx_pkts; | ||
1033 | u32 calc_failure; | ||
1034 | } __packed; | ||
1035 | |||
1036 | struct acx_aes_statistics { | ||
1037 | u32 encrypt_fail; | ||
1038 | u32 decrypt_fail; | ||
1039 | u32 encrypt_packets; | ||
1040 | u32 decrypt_packets; | ||
1041 | u32 encrypt_interrupt; | ||
1042 | u32 decrypt_interrupt; | ||
1043 | } __packed; | ||
1044 | |||
1045 | struct acx_event_statistics { | ||
1046 | u32 heart_beat; | ||
1047 | u32 calibration; | ||
1048 | u32 rx_mismatch; | ||
1049 | u32 rx_mem_empty; | ||
1050 | u32 rx_pool; | ||
1051 | u32 oom_late; | ||
1052 | u32 phy_transmit_error; | ||
1053 | u32 tx_stuck; | ||
1054 | } __packed; | ||
1055 | |||
1056 | struct acx_ps_statistics { | ||
1057 | u32 pspoll_timeouts; | ||
1058 | u32 upsd_timeouts; | ||
1059 | u32 upsd_max_sptime; | ||
1060 | u32 upsd_max_apturn; | ||
1061 | u32 pspoll_max_apturn; | ||
1062 | u32 pspoll_utilization; | ||
1063 | u32 upsd_utilization; | ||
1064 | } __packed; | ||
1065 | |||
1066 | struct acx_rxpipe_statistics { | ||
1067 | u32 rx_prep_beacon_drop; | ||
1068 | u32 descr_host_int_trig_rx_data; | ||
1069 | u32 beacon_buffer_thres_host_int_trig_rx_data; | ||
1070 | u32 missed_beacon_host_int_trig_rx_data; | ||
1071 | u32 tx_xfr_host_int_trig_rx_data; | ||
1072 | } __packed; | ||
1073 | |||
1074 | struct acx_statistics { | ||
1075 | struct acx_header header; | ||
1076 | |||
1077 | struct acx_tx_statistics tx; | ||
1078 | struct acx_rx_statistics rx; | ||
1079 | struct acx_dma_statistics dma; | ||
1080 | struct acx_isr_statistics isr; | ||
1081 | struct acx_wep_statistics wep; | ||
1082 | struct acx_pwr_statistics pwr; | ||
1083 | struct acx_aes_statistics aes; | ||
1084 | struct acx_mic_statistics mic; | ||
1085 | struct acx_event_statistics event; | ||
1086 | struct acx_ps_statistics ps; | ||
1087 | struct acx_rxpipe_statistics rxpipe; | ||
1088 | } __packed; | ||
1089 | |||
1090 | #define ACX_MAX_RATE_CLASSES 8 | ||
1091 | #define ACX_RATE_MASK_UNSPECIFIED 0 | ||
1092 | #define ACX_RATE_RETRY_LIMIT 10 | ||
1093 | |||
1094 | struct acx_rate_class { | ||
1095 | u32 enabled_rates; | ||
1096 | u8 short_retry_limit; | ||
1097 | u8 long_retry_limit; | ||
1098 | u8 aflags; | ||
1099 | u8 reserved; | ||
1100 | } __packed; | ||
1101 | |||
1102 | struct acx_rate_policy { | ||
1103 | struct acx_header header; | ||
1104 | |||
1105 | u32 rate_class_cnt; | ||
1106 | struct acx_rate_class rate_class[ACX_MAX_RATE_CLASSES]; | ||
1107 | } __packed; | ||
1108 | |||
1109 | struct wl1251_acx_memory { | ||
1110 | __le16 num_stations; /* number of STAs to be supported. */ | ||
1111 | u16 reserved_1; | ||
1112 | |||
1113 | /* | ||
1114 | * Nmber of memory buffers for the RX mem pool. | ||
1115 | * The actual number may be less if there are | ||
1116 | * not enough blocks left for the minimum num | ||
1117 | * of TX ones. | ||
1118 | */ | ||
1119 | u8 rx_mem_block_num; | ||
1120 | u8 reserved_2; | ||
1121 | u8 num_tx_queues; /* From 1 to 16 */ | ||
1122 | u8 host_if_options; /* HOST_IF* */ | ||
1123 | u8 tx_min_mem_block_num; | ||
1124 | u8 num_ssid_profiles; | ||
1125 | __le16 debug_buffer_size; | ||
1126 | } __packed; | ||
1127 | |||
1128 | |||
1129 | #define ACX_RX_DESC_MIN 1 | ||
1130 | #define ACX_RX_DESC_MAX 127 | ||
1131 | #define ACX_RX_DESC_DEF 32 | ||
1132 | struct wl1251_acx_rx_queue_config { | ||
1133 | u8 num_descs; | ||
1134 | u8 pad; | ||
1135 | u8 type; | ||
1136 | u8 priority; | ||
1137 | __le32 dma_address; | ||
1138 | } __packed; | ||
1139 | |||
1140 | #define ACX_TX_DESC_MIN 1 | ||
1141 | #define ACX_TX_DESC_MAX 127 | ||
1142 | #define ACX_TX_DESC_DEF 16 | ||
1143 | struct wl1251_acx_tx_queue_config { | ||
1144 | u8 num_descs; | ||
1145 | u8 pad[2]; | ||
1146 | u8 attributes; | ||
1147 | } __packed; | ||
1148 | |||
1149 | #define MAX_TX_QUEUE_CONFIGS 5 | ||
1150 | #define MAX_TX_QUEUES 4 | ||
1151 | struct wl1251_acx_config_memory { | ||
1152 | struct acx_header header; | ||
1153 | |||
1154 | struct wl1251_acx_memory mem_config; | ||
1155 | struct wl1251_acx_rx_queue_config rx_queue_config; | ||
1156 | struct wl1251_acx_tx_queue_config tx_queue_config[MAX_TX_QUEUE_CONFIGS]; | ||
1157 | } __packed; | ||
1158 | |||
1159 | struct wl1251_acx_mem_map { | ||
1160 | struct acx_header header; | ||
1161 | |||
1162 | void *code_start; | ||
1163 | void *code_end; | ||
1164 | |||
1165 | void *wep_defkey_start; | ||
1166 | void *wep_defkey_end; | ||
1167 | |||
1168 | void *sta_table_start; | ||
1169 | void *sta_table_end; | ||
1170 | |||
1171 | void *packet_template_start; | ||
1172 | void *packet_template_end; | ||
1173 | |||
1174 | void *queue_memory_start; | ||
1175 | void *queue_memory_end; | ||
1176 | |||
1177 | void *packet_memory_pool_start; | ||
1178 | void *packet_memory_pool_end; | ||
1179 | |||
1180 | void *debug_buffer1_start; | ||
1181 | void *debug_buffer1_end; | ||
1182 | |||
1183 | void *debug_buffer2_start; | ||
1184 | void *debug_buffer2_end; | ||
1185 | |||
1186 | /* Number of blocks FW allocated for TX packets */ | ||
1187 | u32 num_tx_mem_blocks; | ||
1188 | |||
1189 | /* Number of blocks FW allocated for RX packets */ | ||
1190 | u32 num_rx_mem_blocks; | ||
1191 | } __packed; | ||
1192 | |||
1193 | |||
1194 | struct wl1251_acx_wr_tbtt_and_dtim { | ||
1195 | |||
1196 | struct acx_header header; | ||
1197 | |||
1198 | /* Time in TUs between two consecutive beacons */ | ||
1199 | u16 tbtt; | ||
1200 | |||
1201 | /* | ||
1202 | * DTIM period | ||
1203 | * For BSS: Number of TBTTs in a DTIM period (range: 1-10) | ||
1204 | * For IBSS: value shall be set to 1 | ||
1205 | */ | ||
1206 | u8 dtim; | ||
1207 | u8 padding; | ||
1208 | } __packed; | ||
1209 | |||
1210 | enum wl1251_acx_bet_mode { | ||
1211 | WL1251_ACX_BET_DISABLE = 0, | ||
1212 | WL1251_ACX_BET_ENABLE = 1, | ||
1213 | }; | ||
1214 | |||
1215 | struct wl1251_acx_bet_enable { | ||
1216 | struct acx_header header; | ||
1217 | |||
1218 | /* | ||
1219 | * Specifies if beacon early termination procedure is enabled or | ||
1220 | * disabled, see enum wl1251_acx_bet_mode. | ||
1221 | */ | ||
1222 | u8 enable; | ||
1223 | |||
1224 | /* | ||
1225 | * Specifies the maximum number of consecutive beacons that may be | ||
1226 | * early terminated. After this number is reached at least one full | ||
1227 | * beacon must be correctly received in FW before beacon ET | ||
1228 | * resumes. Range 0 - 255. | ||
1229 | */ | ||
1230 | u8 max_consecutive; | ||
1231 | |||
1232 | u8 padding[2]; | ||
1233 | } __packed; | ||
1234 | |||
1235 | struct wl1251_acx_ac_cfg { | ||
1236 | struct acx_header header; | ||
1237 | |||
1238 | /* | ||
1239 | * Access Category - The TX queue's access category | ||
1240 | * (refer to AccessCategory_enum) | ||
1241 | */ | ||
1242 | u8 ac; | ||
1243 | |||
1244 | /* | ||
1245 | * The contention window minimum size (in slots) for | ||
1246 | * the access class. | ||
1247 | */ | ||
1248 | u8 cw_min; | ||
1249 | |||
1250 | /* | ||
1251 | * The contention window maximum size (in slots) for | ||
1252 | * the access class. | ||
1253 | */ | ||
1254 | u16 cw_max; | ||
1255 | |||
1256 | /* The AIF value (in slots) for the access class. */ | ||
1257 | u8 aifsn; | ||
1258 | |||
1259 | u8 reserved; | ||
1260 | |||
1261 | /* The TX Op Limit (in microseconds) for the access class. */ | ||
1262 | u16 txop_limit; | ||
1263 | } __packed; | ||
1264 | |||
1265 | |||
1266 | enum wl1251_acx_channel_type { | ||
1267 | CHANNEL_TYPE_DCF = 0, | ||
1268 | CHANNEL_TYPE_EDCF = 1, | ||
1269 | CHANNEL_TYPE_HCCA = 2, | ||
1270 | }; | ||
1271 | |||
1272 | enum wl1251_acx_ps_scheme { | ||
1273 | /* regular ps: simple sending of packets */ | ||
1274 | WL1251_ACX_PS_SCHEME_LEGACY = 0, | ||
1275 | |||
1276 | /* sending a packet triggers a unscheduled apsd downstream */ | ||
1277 | WL1251_ACX_PS_SCHEME_UPSD_TRIGGER = 1, | ||
1278 | |||
1279 | /* a pspoll packet will be sent before every data packet */ | ||
1280 | WL1251_ACX_PS_SCHEME_LEGACY_PSPOLL = 2, | ||
1281 | |||
1282 | /* scheduled apsd mode */ | ||
1283 | WL1251_ACX_PS_SCHEME_SAPSD = 3, | ||
1284 | }; | ||
1285 | |||
1286 | enum wl1251_acx_ack_policy { | ||
1287 | WL1251_ACX_ACK_POLICY_LEGACY = 0, | ||
1288 | WL1251_ACX_ACK_POLICY_NO_ACK = 1, | ||
1289 | WL1251_ACX_ACK_POLICY_BLOCK = 2, | ||
1290 | }; | ||
1291 | |||
1292 | struct wl1251_acx_tid_cfg { | ||
1293 | struct acx_header header; | ||
1294 | |||
1295 | /* tx queue id number (0-7) */ | ||
1296 | u8 queue; | ||
1297 | |||
1298 | /* channel access type for the queue, enum wl1251_acx_channel_type */ | ||
1299 | u8 type; | ||
1300 | |||
1301 | /* EDCA: ac index (0-3), HCCA: traffic stream id (8-15) */ | ||
1302 | u8 tsid; | ||
1303 | |||
1304 | /* ps scheme of the specified queue, enum wl1251_acx_ps_scheme */ | ||
1305 | u8 ps_scheme; | ||
1306 | |||
1307 | /* the tx queue ack policy, enum wl1251_acx_ack_policy */ | ||
1308 | u8 ack_policy; | ||
1309 | |||
1310 | u8 padding[3]; | ||
1311 | |||
1312 | /* not supported */ | ||
1313 | u32 apsdconf[2]; | ||
1314 | } __packed; | ||
1315 | |||
1316 | /************************************************************************* | ||
1317 | |||
1318 | Host Interrupt Register (WiLink -> Host) | ||
1319 | |||
1320 | **************************************************************************/ | ||
1321 | |||
1322 | /* RX packet is ready in Xfer buffer #0 */ | ||
1323 | #define WL1251_ACX_INTR_RX0_DATA BIT(0) | ||
1324 | |||
1325 | /* TX result(s) are in the TX complete buffer */ | ||
1326 | #define WL1251_ACX_INTR_TX_RESULT BIT(1) | ||
1327 | |||
1328 | /* OBSOLETE */ | ||
1329 | #define WL1251_ACX_INTR_TX_XFR BIT(2) | ||
1330 | |||
1331 | /* RX packet is ready in Xfer buffer #1 */ | ||
1332 | #define WL1251_ACX_INTR_RX1_DATA BIT(3) | ||
1333 | |||
1334 | /* Event was entered to Event MBOX #A */ | ||
1335 | #define WL1251_ACX_INTR_EVENT_A BIT(4) | ||
1336 | |||
1337 | /* Event was entered to Event MBOX #B */ | ||
1338 | #define WL1251_ACX_INTR_EVENT_B BIT(5) | ||
1339 | |||
1340 | /* OBSOLETE */ | ||
1341 | #define WL1251_ACX_INTR_WAKE_ON_HOST BIT(6) | ||
1342 | |||
1343 | /* Trace message on MBOX #A */ | ||
1344 | #define WL1251_ACX_INTR_TRACE_A BIT(7) | ||
1345 | |||
1346 | /* Trace message on MBOX #B */ | ||
1347 | #define WL1251_ACX_INTR_TRACE_B BIT(8) | ||
1348 | |||
1349 | /* Command processing completion */ | ||
1350 | #define WL1251_ACX_INTR_CMD_COMPLETE BIT(9) | ||
1351 | |||
1352 | /* Init sequence is done */ | ||
1353 | #define WL1251_ACX_INTR_INIT_COMPLETE BIT(14) | ||
1354 | |||
1355 | #define WL1251_ACX_INTR_ALL 0xFFFFFFFF | ||
1356 | |||
1357 | enum { | ||
1358 | ACX_WAKE_UP_CONDITIONS = 0x0002, | ||
1359 | ACX_MEM_CFG = 0x0003, | ||
1360 | ACX_SLOT = 0x0004, | ||
1361 | ACX_QUEUE_HEAD = 0x0005, /* for MASTER mode only */ | ||
1362 | ACX_AC_CFG = 0x0007, | ||
1363 | ACX_MEM_MAP = 0x0008, | ||
1364 | ACX_AID = 0x000A, | ||
1365 | ACX_RADIO_PARAM = 0x000B, /* Not used */ | ||
1366 | ACX_CFG = 0x000C, /* Not used */ | ||
1367 | ACX_FW_REV = 0x000D, | ||
1368 | ACX_MEDIUM_USAGE = 0x000F, | ||
1369 | ACX_RX_CFG = 0x0010, | ||
1370 | ACX_TX_QUEUE_CFG = 0x0011, /* FIXME: only used by wl1251 */ | ||
1371 | ACX_BSS_IN_PS = 0x0012, /* for AP only */ | ||
1372 | ACX_STATISTICS = 0x0013, /* Debug API */ | ||
1373 | ACX_FEATURE_CFG = 0x0015, | ||
1374 | ACX_MISC_CFG = 0x0017, /* Not used */ | ||
1375 | ACX_TID_CFG = 0x001A, | ||
1376 | ACX_BEACON_FILTER_OPT = 0x001F, | ||
1377 | ACX_LOW_RSSI = 0x0020, | ||
1378 | ACX_NOISE_HIST = 0x0021, | ||
1379 | ACX_HDK_VERSION = 0x0022, /* ??? */ | ||
1380 | ACX_PD_THRESHOLD = 0x0023, | ||
1381 | ACX_DATA_PATH_PARAMS = 0x0024, /* WO */ | ||
1382 | ACX_DATA_PATH_RESP_PARAMS = 0x0024, /* RO */ | ||
1383 | ACX_CCA_THRESHOLD = 0x0025, | ||
1384 | ACX_EVENT_MBOX_MASK = 0x0026, | ||
1385 | #ifdef FW_RUNNING_AS_AP | ||
1386 | ACX_DTIM_PERIOD = 0x0027, /* for AP only */ | ||
1387 | #else | ||
1388 | ACX_WR_TBTT_AND_DTIM = 0x0027, /* STA only */ | ||
1389 | #endif | ||
1390 | ACX_ACI_OPTION_CFG = 0x0029, /* OBSOLETE (for 1251)*/ | ||
1391 | ACX_GPIO_CFG = 0x002A, /* Not used */ | ||
1392 | ACX_GPIO_SET = 0x002B, /* Not used */ | ||
1393 | ACX_PM_CFG = 0x002C, /* To Be Documented */ | ||
1394 | ACX_CONN_MONIT_PARAMS = 0x002D, | ||
1395 | ACX_AVERAGE_RSSI = 0x002E, /* Not used */ | ||
1396 | ACX_CONS_TX_FAILURE = 0x002F, | ||
1397 | ACX_BCN_DTIM_OPTIONS = 0x0031, | ||
1398 | ACX_SG_ENABLE = 0x0032, | ||
1399 | ACX_SG_CFG = 0x0033, | ||
1400 | ACX_ANTENNA_DIVERSITY_CFG = 0x0035, /* To Be Documented */ | ||
1401 | ACX_LOW_SNR = 0x0037, /* To Be Documented */ | ||
1402 | ACX_BEACON_FILTER_TABLE = 0x0038, | ||
1403 | ACX_ARP_IP_FILTER = 0x0039, | ||
1404 | ACX_ROAMING_STATISTICS_TBL = 0x003B, | ||
1405 | ACX_RATE_POLICY = 0x003D, | ||
1406 | ACX_CTS_PROTECTION = 0x003E, | ||
1407 | ACX_SLEEP_AUTH = 0x003F, | ||
1408 | ACX_PREAMBLE_TYPE = 0x0040, | ||
1409 | ACX_ERROR_CNT = 0x0041, | ||
1410 | ACX_FW_GEN_FRAME_RATES = 0x0042, | ||
1411 | ACX_IBSS_FILTER = 0x0044, | ||
1412 | ACX_SERVICE_PERIOD_TIMEOUT = 0x0045, | ||
1413 | ACX_TSF_INFO = 0x0046, | ||
1414 | ACX_CONFIG_PS_WMM = 0x0049, | ||
1415 | ACX_ENABLE_RX_DATA_FILTER = 0x004A, | ||
1416 | ACX_SET_RX_DATA_FILTER = 0x004B, | ||
1417 | ACX_GET_DATA_FILTER_STATISTICS = 0x004C, | ||
1418 | ACX_POWER_LEVEL_TABLE = 0x004D, | ||
1419 | ACX_BET_ENABLE = 0x0050, | ||
1420 | DOT11_STATION_ID = 0x1001, | ||
1421 | DOT11_RX_MSDU_LIFE_TIME = 0x1004, | ||
1422 | DOT11_CUR_TX_PWR = 0x100D, | ||
1423 | DOT11_DEFAULT_KEY = 0x1010, | ||
1424 | DOT11_RX_DOT11_MODE = 0x1012, | ||
1425 | DOT11_RTS_THRESHOLD = 0x1013, | ||
1426 | DOT11_GROUP_ADDRESS_TBL = 0x1014, | ||
1427 | |||
1428 | MAX_DOT11_IE = DOT11_GROUP_ADDRESS_TBL, | ||
1429 | |||
1430 | MAX_IE = 0xFFFF | ||
1431 | }; | ||
1432 | |||
1433 | |||
1434 | int wl1251_acx_frame_rates(struct wl1251 *wl, u8 ctrl_rate, u8 ctrl_mod, | ||
1435 | u8 mgt_rate, u8 mgt_mod); | ||
1436 | int wl1251_acx_station_id(struct wl1251 *wl); | ||
1437 | int wl1251_acx_default_key(struct wl1251 *wl, u8 key_id); | ||
1438 | int wl1251_acx_wake_up_conditions(struct wl1251 *wl, u8 wake_up_event, | ||
1439 | u8 listen_interval); | ||
1440 | int wl1251_acx_sleep_auth(struct wl1251 *wl, u8 sleep_auth); | ||
1441 | int wl1251_acx_fw_version(struct wl1251 *wl, char *buf, size_t len); | ||
1442 | int wl1251_acx_tx_power(struct wl1251 *wl, int power); | ||
1443 | int wl1251_acx_feature_cfg(struct wl1251 *wl); | ||
1444 | int wl1251_acx_mem_map(struct wl1251 *wl, | ||
1445 | struct acx_header *mem_map, size_t len); | ||
1446 | int wl1251_acx_data_path_params(struct wl1251 *wl, | ||
1447 | struct acx_data_path_params_resp *data_path); | ||
1448 | int wl1251_acx_rx_msdu_life_time(struct wl1251 *wl, u32 life_time); | ||
1449 | int wl1251_acx_rx_config(struct wl1251 *wl, u32 config, u32 filter); | ||
1450 | int wl1251_acx_pd_threshold(struct wl1251 *wl); | ||
1451 | int wl1251_acx_slot(struct wl1251 *wl, enum acx_slot_type slot_time); | ||
1452 | int wl1251_acx_group_address_tbl(struct wl1251 *wl); | ||
1453 | int wl1251_acx_service_period_timeout(struct wl1251 *wl); | ||
1454 | int wl1251_acx_rts_threshold(struct wl1251 *wl, u16 rts_threshold); | ||
1455 | int wl1251_acx_beacon_filter_opt(struct wl1251 *wl, bool enable_filter); | ||
1456 | int wl1251_acx_beacon_filter_table(struct wl1251 *wl); | ||
1457 | int wl1251_acx_conn_monit_params(struct wl1251 *wl); | ||
1458 | int wl1251_acx_sg_enable(struct wl1251 *wl); | ||
1459 | int wl1251_acx_sg_cfg(struct wl1251 *wl); | ||
1460 | int wl1251_acx_cca_threshold(struct wl1251 *wl); | ||
1461 | int wl1251_acx_bcn_dtim_options(struct wl1251 *wl); | ||
1462 | int wl1251_acx_aid(struct wl1251 *wl, u16 aid); | ||
1463 | int wl1251_acx_event_mbox_mask(struct wl1251 *wl, u32 event_mask); | ||
1464 | int wl1251_acx_low_rssi(struct wl1251 *wl, s8 threshold, u8 weight, | ||
1465 | u8 depth, enum wl1251_acx_low_rssi_type type); | ||
1466 | int wl1251_acx_set_preamble(struct wl1251 *wl, enum acx_preamble_type preamble); | ||
1467 | int wl1251_acx_cts_protect(struct wl1251 *wl, | ||
1468 | enum acx_ctsprotect_type ctsprotect); | ||
1469 | int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats); | ||
1470 | int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime); | ||
1471 | int wl1251_acx_rate_policies(struct wl1251 *wl); | ||
1472 | int wl1251_acx_mem_cfg(struct wl1251 *wl); | ||
1473 | int wl1251_acx_wr_tbtt_and_dtim(struct wl1251 *wl, u16 tbtt, u8 dtim); | ||
1474 | int wl1251_acx_bet_enable(struct wl1251 *wl, enum wl1251_acx_bet_mode mode, | ||
1475 | u8 max_consecutive); | ||
1476 | int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max, | ||
1477 | u8 aifs, u16 txop); | ||
1478 | int wl1251_acx_tid_cfg(struct wl1251 *wl, u8 queue, | ||
1479 | enum wl1251_acx_channel_type type, | ||
1480 | u8 tsid, enum wl1251_acx_ps_scheme ps_scheme, | ||
1481 | enum wl1251_acx_ack_policy ack_policy); | ||
1482 | |||
1483 | #endif /* __WL1251_ACX_H__ */ | ||
diff --git a/drivers/net/wireless/ti/wl1251/boot.c b/drivers/net/wireless/ti/wl1251/boot.c new file mode 100644 index 000000000000..a2e5241382da --- /dev/null +++ b/drivers/net/wireless/ti/wl1251/boot.c | |||
@@ -0,0 +1,554 @@ | |||
1 | /* | ||
2 | * This file is part of wl1251 | ||
3 | * | ||
4 | * Copyright (C) 2008 Nokia Corporation | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * version 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
18 | * 02110-1301 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include <linux/slab.h> | ||
23 | |||
24 | #include "reg.h" | ||
25 | #include "boot.h" | ||
26 | #include "io.h" | ||
27 | #include "spi.h" | ||
28 | #include "event.h" | ||
29 | #include "acx.h" | ||
30 | |||
31 | void wl1251_boot_target_enable_interrupts(struct wl1251 *wl) | ||
32 | { | ||
33 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); | ||
34 | wl1251_reg_write32(wl, HI_CFG, HI_CFG_DEF_VAL); | ||
35 | } | ||
36 | |||
37 | int wl1251_boot_soft_reset(struct wl1251 *wl) | ||
38 | { | ||
39 | unsigned long timeout; | ||
40 | u32 boot_data; | ||
41 | |||
42 | /* perform soft reset */ | ||
43 | wl1251_reg_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT); | ||
44 | |||
45 | /* SOFT_RESET is self clearing */ | ||
46 | timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME); | ||
47 | while (1) { | ||
48 | boot_data = wl1251_reg_read32(wl, ACX_REG_SLV_SOFT_RESET); | ||
49 | wl1251_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data); | ||
50 | if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0) | ||
51 | break; | ||
52 | |||
53 | if (time_after(jiffies, timeout)) { | ||
54 | /* 1.2 check pWhalBus->uSelfClearTime if the | ||
55 | * timeout was reached */ | ||
56 | wl1251_error("soft reset timeout"); | ||
57 | return -1; | ||
58 | } | ||
59 | |||
60 | udelay(SOFT_RESET_STALL_TIME); | ||
61 | } | ||
62 | |||
63 | /* disable Rx/Tx */ | ||
64 | wl1251_reg_write32(wl, ENABLE, 0x0); | ||
65 | |||
66 | /* disable auto calibration on start*/ | ||
67 | wl1251_reg_write32(wl, SPARE_A2, 0xffff); | ||
68 | |||
69 | return 0; | ||
70 | } | ||
71 | |||
72 | int wl1251_boot_init_seq(struct wl1251 *wl) | ||
73 | { | ||
74 | u32 scr_pad6, init_data, tmp, elp_cmd, ref_freq; | ||
75 | |||
76 | /* | ||
77 | * col #1: INTEGER_DIVIDER | ||
78 | * col #2: FRACTIONAL_DIVIDER | ||
79 | * col #3: ATTN_BB | ||
80 | * col #4: ALPHA_BB | ||
81 | * col #5: STOP_TIME_BB | ||
82 | * col #6: BB_PLL_LOOP_FILTER | ||
83 | */ | ||
84 | static const u32 LUT[REF_FREQ_NUM][LUT_PARAM_NUM] = { | ||
85 | |||
86 | { 83, 87381, 0xB, 5, 0xF00, 3}, /* REF_FREQ_19_2*/ | ||
87 | { 61, 141154, 0xB, 5, 0x1450, 2}, /* REF_FREQ_26_0*/ | ||
88 | { 41, 174763, 0xC, 6, 0x2D00, 1}, /* REF_FREQ_38_4*/ | ||
89 | { 40, 0, 0xC, 6, 0x2EE0, 1}, /* REF_FREQ_40_0*/ | ||
90 | { 47, 162280, 0xC, 6, 0x2760, 1} /* REF_FREQ_33_6 */ | ||
91 | }; | ||
92 | |||
93 | /* read NVS params */ | ||
94 | scr_pad6 = wl1251_reg_read32(wl, SCR_PAD6); | ||
95 | wl1251_debug(DEBUG_BOOT, "scr_pad6 0x%x", scr_pad6); | ||
96 | |||
97 | /* read ELP_CMD */ | ||
98 | elp_cmd = wl1251_reg_read32(wl, ELP_CMD); | ||
99 | wl1251_debug(DEBUG_BOOT, "elp_cmd 0x%x", elp_cmd); | ||
100 | |||
101 | /* set the BB calibration time to be 300 usec (PLL_CAL_TIME) */ | ||
102 | ref_freq = scr_pad6 & 0x000000FF; | ||
103 | wl1251_debug(DEBUG_BOOT, "ref_freq 0x%x", ref_freq); | ||
104 | |||
105 | wl1251_reg_write32(wl, PLL_CAL_TIME, 0x9); | ||
106 | |||
107 | /* | ||
108 | * PG 1.2: set the clock buffer time to be 210 usec (CLK_BUF_TIME) | ||
109 | */ | ||
110 | wl1251_reg_write32(wl, CLK_BUF_TIME, 0x6); | ||
111 | |||
112 | /* | ||
113 | * set the clock detect feature to work in the restart wu procedure | ||
114 | * (ELP_CFG_MODE[14]) and Select the clock source type | ||
115 | * (ELP_CFG_MODE[13:12]) | ||
116 | */ | ||
117 | tmp = ((scr_pad6 & 0x0000FF00) << 4) | 0x00004000; | ||
118 | wl1251_reg_write32(wl, ELP_CFG_MODE, tmp); | ||
119 | |||
120 | /* PG 1.2: enable the BB PLL fix. Enable the PLL_LIMP_CLK_EN_CMD */ | ||
121 | elp_cmd |= 0x00000040; | ||
122 | wl1251_reg_write32(wl, ELP_CMD, elp_cmd); | ||
123 | |||
124 | /* PG 1.2: Set the BB PLL stable time to be 1000usec | ||
125 | * (PLL_STABLE_TIME) */ | ||
126 | wl1251_reg_write32(wl, CFG_PLL_SYNC_CNT, 0x20); | ||
127 | |||
128 | /* PG 1.2: read clock request time */ | ||
129 | init_data = wl1251_reg_read32(wl, CLK_REQ_TIME); | ||
130 | |||
131 | /* | ||
132 | * PG 1.2: set the clock request time to be ref_clk_settling_time - | ||
133 | * 1ms = 4ms | ||
134 | */ | ||
135 | if (init_data > 0x21) | ||
136 | tmp = init_data - 0x21; | ||
137 | else | ||
138 | tmp = 0; | ||
139 | wl1251_reg_write32(wl, CLK_REQ_TIME, tmp); | ||
140 | |||
141 | /* set BB PLL configurations in RF AFE */ | ||
142 | wl1251_reg_write32(wl, 0x003058cc, 0x4B5); | ||
143 | |||
144 | /* set RF_AFE_REG_5 */ | ||
145 | wl1251_reg_write32(wl, 0x003058d4, 0x50); | ||
146 | |||
147 | /* set RF_AFE_CTRL_REG_2 */ | ||
148 | wl1251_reg_write32(wl, 0x00305948, 0x11c001); | ||
149 | |||
150 | /* | ||
151 | * change RF PLL and BB PLL divider for VCO clock and adjust VCO | ||
152 | * bais current(RF_AFE_REG_13) | ||
153 | */ | ||
154 | wl1251_reg_write32(wl, 0x003058f4, 0x1e); | ||
155 | |||
156 | /* set BB PLL configurations */ | ||
157 | tmp = LUT[ref_freq][LUT_PARAM_INTEGER_DIVIDER] | 0x00017000; | ||
158 | wl1251_reg_write32(wl, 0x00305840, tmp); | ||
159 | |||
160 | /* set fractional divider according to Appendix C-BB PLL | ||
161 | * Calculations | ||
162 | */ | ||
163 | tmp = LUT[ref_freq][LUT_PARAM_FRACTIONAL_DIVIDER]; | ||
164 | wl1251_reg_write32(wl, 0x00305844, tmp); | ||
165 | |||
166 | /* set the initial data for the sigma delta */ | ||
167 | wl1251_reg_write32(wl, 0x00305848, 0x3039); | ||
168 | |||
169 | /* | ||
170 | * set the accumulator attenuation value, calibration loop1 | ||
171 | * (alpha), calibration loop2 (beta), calibration loop3 (gamma) and | ||
172 | * the VCO gain | ||
173 | */ | ||
174 | tmp = (LUT[ref_freq][LUT_PARAM_ATTN_BB] << 16) | | ||
175 | (LUT[ref_freq][LUT_PARAM_ALPHA_BB] << 12) | 0x1; | ||
176 | wl1251_reg_write32(wl, 0x00305854, tmp); | ||
177 | |||
178 | /* | ||
179 | * set the calibration stop time after holdoff time expires and set | ||
180 | * settling time HOLD_OFF_TIME_BB | ||
181 | */ | ||
182 | tmp = LUT[ref_freq][LUT_PARAM_STOP_TIME_BB] | 0x000A0000; | ||
183 | wl1251_reg_write32(wl, 0x00305858, tmp); | ||
184 | |||
185 | /* | ||
186 | * set BB PLL Loop filter capacitor3- BB_C3[2:0] and set BB PLL | ||
187 | * constant leakage current to linearize PFD to 0uA - | ||
188 | * BB_ILOOPF[7:3] | ||
189 | */ | ||
190 | tmp = LUT[ref_freq][LUT_PARAM_BB_PLL_LOOP_FILTER] | 0x00000030; | ||
191 | wl1251_reg_write32(wl, 0x003058f8, tmp); | ||
192 | |||
193 | /* | ||
194 | * set regulator output voltage for n divider to | ||
195 | * 1.35-BB_REFDIV[1:0], set charge pump current- BB_CPGAIN[4:2], | ||
196 | * set BB PLL Loop filter capacitor2- BB_C2[7:5], set gain of BB | ||
197 | * PLL auto-call to normal mode- BB_CALGAIN_3DB[8] | ||
198 | */ | ||
199 | wl1251_reg_write32(wl, 0x003058f0, 0x29); | ||
200 | |||
201 | /* enable restart wakeup sequence (ELP_CMD[0]) */ | ||
202 | wl1251_reg_write32(wl, ELP_CMD, elp_cmd | 0x1); | ||
203 | |||
204 | /* restart sequence completed */ | ||
205 | udelay(2000); | ||
206 | |||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | static void wl1251_boot_set_ecpu_ctrl(struct wl1251 *wl, u32 flag) | ||
211 | { | ||
212 | u32 cpu_ctrl; | ||
213 | |||
214 | /* 10.5.0 run the firmware (I) */ | ||
215 | cpu_ctrl = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL); | ||
216 | |||
217 | /* 10.5.1 run the firmware (II) */ | ||
218 | cpu_ctrl &= ~flag; | ||
219 | wl1251_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); | ||
220 | } | ||
221 | |||
222 | int wl1251_boot_run_firmware(struct wl1251 *wl) | ||
223 | { | ||
224 | int loop, ret; | ||
225 | u32 chip_id, acx_intr; | ||
226 | |||
227 | wl1251_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); | ||
228 | |||
229 | chip_id = wl1251_reg_read32(wl, CHIP_ID_B); | ||
230 | |||
231 | wl1251_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); | ||
232 | |||
233 | if (chip_id != wl->chip_id) { | ||
234 | wl1251_error("chip id doesn't match after firmware boot"); | ||
235 | return -EIO; | ||
236 | } | ||
237 | |||
238 | /* wait for init to complete */ | ||
239 | loop = 0; | ||
240 | while (loop++ < INIT_LOOP) { | ||
241 | udelay(INIT_LOOP_DELAY); | ||
242 | acx_intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); | ||
243 | |||
244 | if (acx_intr == 0xffffffff) { | ||
245 | wl1251_error("error reading hardware complete " | ||
246 | "init indication"); | ||
247 | return -EIO; | ||
248 | } | ||
249 | /* check that ACX_INTR_INIT_COMPLETE is enabled */ | ||
250 | else if (acx_intr & WL1251_ACX_INTR_INIT_COMPLETE) { | ||
251 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK, | ||
252 | WL1251_ACX_INTR_INIT_COMPLETE); | ||
253 | break; | ||
254 | } | ||
255 | } | ||
256 | |||
257 | if (loop > INIT_LOOP) { | ||
258 | wl1251_error("timeout waiting for the hardware to " | ||
259 | "complete initialization"); | ||
260 | return -EIO; | ||
261 | } | ||
262 | |||
263 | /* get hardware config command mail box */ | ||
264 | wl->cmd_box_addr = wl1251_reg_read32(wl, REG_COMMAND_MAILBOX_PTR); | ||
265 | |||
266 | /* get hardware config event mail box */ | ||
267 | wl->event_box_addr = wl1251_reg_read32(wl, REG_EVENT_MAILBOX_PTR); | ||
268 | |||
269 | /* set the working partition to its "running" mode offset */ | ||
270 | wl1251_set_partition(wl, WL1251_PART_WORK_MEM_START, | ||
271 | WL1251_PART_WORK_MEM_SIZE, | ||
272 | WL1251_PART_WORK_REG_START, | ||
273 | WL1251_PART_WORK_REG_SIZE); | ||
274 | |||
275 | wl1251_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x", | ||
276 | wl->cmd_box_addr, wl->event_box_addr); | ||
277 | |||
278 | wl1251_acx_fw_version(wl, wl->fw_ver, sizeof(wl->fw_ver)); | ||
279 | |||
280 | /* | ||
281 | * in case of full asynchronous mode the firmware event must be | ||
282 | * ready to receive event from the command mailbox | ||
283 | */ | ||
284 | |||
285 | /* enable gpio interrupts */ | ||
286 | wl1251_enable_interrupts(wl); | ||
287 | |||
288 | /* Enable target's interrupts */ | ||
289 | wl->intr_mask = WL1251_ACX_INTR_RX0_DATA | | ||
290 | WL1251_ACX_INTR_RX1_DATA | | ||
291 | WL1251_ACX_INTR_TX_RESULT | | ||
292 | WL1251_ACX_INTR_EVENT_A | | ||
293 | WL1251_ACX_INTR_EVENT_B | | ||
294 | WL1251_ACX_INTR_INIT_COMPLETE; | ||
295 | wl1251_boot_target_enable_interrupts(wl); | ||
296 | |||
297 | wl->event_mask = SCAN_COMPLETE_EVENT_ID | BSS_LOSE_EVENT_ID | | ||
298 | SYNCHRONIZATION_TIMEOUT_EVENT_ID | | ||
299 | ROAMING_TRIGGER_LOW_RSSI_EVENT_ID | | ||
300 | ROAMING_TRIGGER_REGAINED_RSSI_EVENT_ID | | ||
301 | REGAINED_BSS_EVENT_ID | BT_PTA_SENSE_EVENT_ID | | ||
302 | BT_PTA_PREDICTION_EVENT_ID | JOIN_EVENT_COMPLETE_ID; | ||
303 | |||
304 | ret = wl1251_event_unmask(wl); | ||
305 | if (ret < 0) { | ||
306 | wl1251_error("EVENT mask setting failed"); | ||
307 | return ret; | ||
308 | } | ||
309 | |||
310 | wl1251_event_mbox_config(wl); | ||
311 | |||
312 | /* firmware startup completed */ | ||
313 | return 0; | ||
314 | } | ||
315 | |||
316 | static int wl1251_boot_upload_firmware(struct wl1251 *wl) | ||
317 | { | ||
318 | int addr, chunk_num, partition_limit; | ||
319 | size_t fw_data_len, len; | ||
320 | u8 *p, *buf; | ||
321 | |||
322 | /* whal_FwCtrl_LoadFwImageSm() */ | ||
323 | |||
324 | wl1251_debug(DEBUG_BOOT, "chip id before fw upload: 0x%x", | ||
325 | wl1251_reg_read32(wl, CHIP_ID_B)); | ||
326 | |||
327 | /* 10.0 check firmware length and set partition */ | ||
328 | fw_data_len = (wl->fw[4] << 24) | (wl->fw[5] << 16) | | ||
329 | (wl->fw[6] << 8) | (wl->fw[7]); | ||
330 | |||
331 | wl1251_debug(DEBUG_BOOT, "fw_data_len %zu chunk_size %d", fw_data_len, | ||
332 | CHUNK_SIZE); | ||
333 | |||
334 | if ((fw_data_len % 4) != 0) { | ||
335 | wl1251_error("firmware length not multiple of four"); | ||
336 | return -EIO; | ||
337 | } | ||
338 | |||
339 | buf = kmalloc(CHUNK_SIZE, GFP_KERNEL); | ||
340 | if (!buf) { | ||
341 | wl1251_error("allocation for firmware upload chunk failed"); | ||
342 | return -ENOMEM; | ||
343 | } | ||
344 | |||
345 | wl1251_set_partition(wl, WL1251_PART_DOWN_MEM_START, | ||
346 | WL1251_PART_DOWN_MEM_SIZE, | ||
347 | WL1251_PART_DOWN_REG_START, | ||
348 | WL1251_PART_DOWN_REG_SIZE); | ||
349 | |||
350 | /* 10.1 set partition limit and chunk num */ | ||
351 | chunk_num = 0; | ||
352 | partition_limit = WL1251_PART_DOWN_MEM_SIZE; | ||
353 | |||
354 | while (chunk_num < fw_data_len / CHUNK_SIZE) { | ||
355 | /* 10.2 update partition, if needed */ | ||
356 | addr = WL1251_PART_DOWN_MEM_START + | ||
357 | (chunk_num + 2) * CHUNK_SIZE; | ||
358 | if (addr > partition_limit) { | ||
359 | addr = WL1251_PART_DOWN_MEM_START + | ||
360 | chunk_num * CHUNK_SIZE; | ||
361 | partition_limit = chunk_num * CHUNK_SIZE + | ||
362 | WL1251_PART_DOWN_MEM_SIZE; | ||
363 | wl1251_set_partition(wl, | ||
364 | addr, | ||
365 | WL1251_PART_DOWN_MEM_SIZE, | ||
366 | WL1251_PART_DOWN_REG_START, | ||
367 | WL1251_PART_DOWN_REG_SIZE); | ||
368 | } | ||
369 | |||
370 | /* 10.3 upload the chunk */ | ||
371 | addr = WL1251_PART_DOWN_MEM_START + chunk_num * CHUNK_SIZE; | ||
372 | p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; | ||
373 | wl1251_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", | ||
374 | p, addr); | ||
375 | |||
376 | /* need to copy the chunk for dma */ | ||
377 | len = CHUNK_SIZE; | ||
378 | memcpy(buf, p, len); | ||
379 | wl1251_mem_write(wl, addr, buf, len); | ||
380 | |||
381 | chunk_num++; | ||
382 | } | ||
383 | |||
384 | /* 10.4 upload the last chunk */ | ||
385 | addr = WL1251_PART_DOWN_MEM_START + chunk_num * CHUNK_SIZE; | ||
386 | p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; | ||
387 | |||
388 | /* need to copy the chunk for dma */ | ||
389 | len = fw_data_len % CHUNK_SIZE; | ||
390 | memcpy(buf, p, len); | ||
391 | |||
392 | wl1251_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x", | ||
393 | len, p, addr); | ||
394 | wl1251_mem_write(wl, addr, buf, len); | ||
395 | |||
396 | kfree(buf); | ||
397 | |||
398 | return 0; | ||
399 | } | ||
400 | |||
401 | static int wl1251_boot_upload_nvs(struct wl1251 *wl) | ||
402 | { | ||
403 | size_t nvs_len, nvs_bytes_written, burst_len; | ||
404 | int nvs_start, i; | ||
405 | u32 dest_addr, val; | ||
406 | u8 *nvs_ptr, *nvs; | ||
407 | |||
408 | nvs = wl->nvs; | ||
409 | if (nvs == NULL) | ||
410 | return -ENODEV; | ||
411 | |||
412 | nvs_ptr = nvs; | ||
413 | |||
414 | nvs_len = wl->nvs_len; | ||
415 | nvs_start = wl->fw_len; | ||
416 | |||
417 | /* | ||
418 | * Layout before the actual NVS tables: | ||
419 | * 1 byte : burst length. | ||
420 | * 2 bytes: destination address. | ||
421 | * n bytes: data to burst copy. | ||
422 | * | ||
423 | * This is ended by a 0 length, then the NVS tables. | ||
424 | */ | ||
425 | |||
426 | while (nvs_ptr[0]) { | ||
427 | burst_len = nvs_ptr[0]; | ||
428 | dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8)); | ||
429 | |||
430 | /* We move our pointer to the data */ | ||
431 | nvs_ptr += 3; | ||
432 | |||
433 | for (i = 0; i < burst_len; i++) { | ||
434 | val = (nvs_ptr[0] | (nvs_ptr[1] << 8) | ||
435 | | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); | ||
436 | |||
437 | wl1251_debug(DEBUG_BOOT, | ||
438 | "nvs burst write 0x%x: 0x%x", | ||
439 | dest_addr, val); | ||
440 | wl1251_mem_write32(wl, dest_addr, val); | ||
441 | |||
442 | nvs_ptr += 4; | ||
443 | dest_addr += 4; | ||
444 | } | ||
445 | } | ||
446 | |||
447 | /* | ||
448 | * We've reached the first zero length, the first NVS table | ||
449 | * is 7 bytes further. | ||
450 | */ | ||
451 | nvs_ptr += 7; | ||
452 | nvs_len -= nvs_ptr - nvs; | ||
453 | nvs_len = ALIGN(nvs_len, 4); | ||
454 | |||
455 | /* Now we must set the partition correctly */ | ||
456 | wl1251_set_partition(wl, nvs_start, | ||
457 | WL1251_PART_DOWN_MEM_SIZE, | ||
458 | WL1251_PART_DOWN_REG_START, | ||
459 | WL1251_PART_DOWN_REG_SIZE); | ||
460 | |||
461 | /* And finally we upload the NVS tables */ | ||
462 | nvs_bytes_written = 0; | ||
463 | while (nvs_bytes_written < nvs_len) { | ||
464 | val = (nvs_ptr[0] | (nvs_ptr[1] << 8) | ||
465 | | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); | ||
466 | |||
467 | wl1251_debug(DEBUG_BOOT, | ||
468 | "nvs write table 0x%x: 0x%x", | ||
469 | nvs_start, val); | ||
470 | wl1251_mem_write32(wl, nvs_start, val); | ||
471 | |||
472 | nvs_ptr += 4; | ||
473 | nvs_bytes_written += 4; | ||
474 | nvs_start += 4; | ||
475 | } | ||
476 | |||
477 | return 0; | ||
478 | } | ||
479 | |||
480 | int wl1251_boot(struct wl1251 *wl) | ||
481 | { | ||
482 | int ret = 0, minor_minor_e2_ver; | ||
483 | u32 tmp, boot_data; | ||
484 | |||
485 | /* halt embedded ARM CPU while loading firmware */ | ||
486 | wl1251_reg_write32(wl, ACX_REG_ECPU_CONTROL, ECPU_CONTROL_HALT); | ||
487 | |||
488 | ret = wl1251_boot_soft_reset(wl); | ||
489 | if (ret < 0) | ||
490 | goto out; | ||
491 | |||
492 | /* 2. start processing NVS file */ | ||
493 | if (wl->use_eeprom) { | ||
494 | wl1251_reg_write32(wl, ACX_REG_EE_START, START_EEPROM_MGR); | ||
495 | /* Wait for EEPROM NVS burst read to complete */ | ||
496 | msleep(40); | ||
497 | wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, USE_EEPROM); | ||
498 | } else { | ||
499 | ret = wl1251_boot_upload_nvs(wl); | ||
500 | if (ret < 0) | ||
501 | goto out; | ||
502 | |||
503 | /* write firmware's last address (ie. it's length) to | ||
504 | * ACX_EEPROMLESS_IND_REG */ | ||
505 | wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len); | ||
506 | } | ||
507 | |||
508 | /* 6. read the EEPROM parameters */ | ||
509 | tmp = wl1251_reg_read32(wl, SCR_PAD2); | ||
510 | |||
511 | /* 7. read bootdata */ | ||
512 | wl->boot_attr.radio_type = (tmp & 0x0000FF00) >> 8; | ||
513 | wl->boot_attr.major = (tmp & 0x00FF0000) >> 16; | ||
514 | tmp = wl1251_reg_read32(wl, SCR_PAD3); | ||
515 | |||
516 | /* 8. check bootdata and call restart sequence */ | ||
517 | wl->boot_attr.minor = (tmp & 0x00FF0000) >> 16; | ||
518 | minor_minor_e2_ver = (tmp & 0xFF000000) >> 24; | ||
519 | |||
520 | wl1251_debug(DEBUG_BOOT, "radioType 0x%x majorE2Ver 0x%x " | ||
521 | "minorE2Ver 0x%x minor_minor_e2_ver 0x%x", | ||
522 | wl->boot_attr.radio_type, wl->boot_attr.major, | ||
523 | wl->boot_attr.minor, minor_minor_e2_ver); | ||
524 | |||
525 | ret = wl1251_boot_init_seq(wl); | ||
526 | if (ret < 0) | ||
527 | goto out; | ||
528 | |||
529 | /* 9. NVS processing done */ | ||
530 | boot_data = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL); | ||
531 | |||
532 | wl1251_debug(DEBUG_BOOT, "halt boot_data 0x%x", boot_data); | ||
533 | |||
534 | /* 10. check that ECPU_CONTROL_HALT bits are set in | ||
535 | * pWhalBus->uBootData and start uploading firmware | ||
536 | */ | ||
537 | if ((boot_data & ECPU_CONTROL_HALT) == 0) { | ||
538 | wl1251_error("boot failed, ECPU_CONTROL_HALT not set"); | ||
539 | ret = -EIO; | ||
540 | goto out; | ||
541 | } | ||
542 | |||
543 | ret = wl1251_boot_upload_firmware(wl); | ||
544 | if (ret < 0) | ||
545 | goto out; | ||
546 | |||
547 | /* 10.5 start firmware */ | ||
548 | ret = wl1251_boot_run_firmware(wl); | ||
549 | if (ret < 0) | ||
550 | goto out; | ||
551 | |||
552 | out: | ||
553 | return ret; | ||
554 | } | ||
diff --git a/drivers/net/wireless/ti/wl1251/boot.h b/drivers/net/wireless/ti/wl1251/boot.h new file mode 100644 index 000000000000..7661bc5e4662 --- /dev/null +++ b/drivers/net/wireless/ti/wl1251/boot.h | |||
@@ -0,0 +1,39 @@ | |||
1 | /* | ||
2 | * This file is part of wl1251 | ||
3 | * | ||
4 | * Copyright (C) 2008 Nokia Corporation | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * version 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
18 | * 02110-1301 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifndef __BOOT_H__ | ||
23 | #define __BOOT_H__ | ||
24 | |||
25 | #include "wl1251.h" | ||
26 | |||
27 | int wl1251_boot_soft_reset(struct wl1251 *wl); | ||
28 | int wl1251_boot_init_seq(struct wl1251 *wl); | ||
29 | int wl1251_boot_run_firmware(struct wl1251 *wl); | ||
30 | void wl1251_boot_target_enable_interrupts(struct wl1251 *wl); | ||
31 | int wl1251_boot(struct wl1251 *wl); | ||
32 | |||
33 | /* number of times we try to read the INIT interrupt */ | ||
34 | #define INIT_LOOP 20000 | ||
35 | |||
36 | /* delay between retries */ | ||
37 | #define INIT_LOOP_DELAY 50 | ||
38 | |||
39 | #endif | ||
diff --git a/drivers/net/wireless/ti/wl1251/cmd.c b/drivers/net/wireless/ti/wl1251/cmd.c new file mode 100644 index 000000000000..d14d69d733a0 --- /dev/null +++ b/drivers/net/wireless/ti/wl1251/cmd.c | |||
@@ -0,0 +1,496 @@ | |||
1 | #include "cmd.h" | ||
2 | |||
3 | #include <linux/module.h> | ||
4 | #include <linux/slab.h> | ||
5 | #include <linux/crc7.h> | ||
6 | |||
7 | #include "wl1251.h" | ||
8 | #include "reg.h" | ||
9 | #include "io.h" | ||
10 | #include "ps.h" | ||
11 | #include "acx.h" | ||
12 | |||
13 | /** | ||
14 | * send command to firmware | ||
15 | * | ||
16 | * @wl: wl struct | ||
17 | * @id: command id | ||
18 | * @buf: buffer containing the command, must work with dma | ||
19 | * @len: length of the buffer | ||
20 | */ | ||
21 | int wl1251_cmd_send(struct wl1251 *wl, u16 id, void *buf, size_t len) | ||
22 | { | ||
23 | struct wl1251_cmd_header *cmd; | ||
24 | unsigned long timeout; | ||
25 | u32 intr; | ||
26 | int ret = 0; | ||
27 | |||
28 | cmd = buf; | ||
29 | cmd->id = id; | ||
30 | cmd->status = 0; | ||
31 | |||
32 | WARN_ON(len % 4 != 0); | ||
33 | |||
34 | wl1251_mem_write(wl, wl->cmd_box_addr, buf, len); | ||
35 | |||
36 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); | ||
37 | |||
38 | timeout = jiffies + msecs_to_jiffies(WL1251_COMMAND_TIMEOUT); | ||
39 | |||
40 | intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); | ||
41 | while (!(intr & WL1251_ACX_INTR_CMD_COMPLETE)) { | ||
42 | if (time_after(jiffies, timeout)) { | ||
43 | wl1251_error("command complete timeout"); | ||
44 | ret = -ETIMEDOUT; | ||
45 | goto out; | ||
46 | } | ||
47 | |||
48 | msleep(1); | ||
49 | |||
50 | intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); | ||
51 | } | ||
52 | |||
53 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK, | ||
54 | WL1251_ACX_INTR_CMD_COMPLETE); | ||
55 | |||
56 | out: | ||
57 | return ret; | ||
58 | } | ||
59 | |||
60 | /** | ||
61 | * send test command to firmware | ||
62 | * | ||
63 | * @wl: wl struct | ||
64 | * @buf: buffer containing the command, with all headers, must work with dma | ||
65 | * @len: length of the buffer | ||
66 | * @answer: is answer needed | ||
67 | */ | ||
68 | int wl1251_cmd_test(struct wl1251 *wl, void *buf, size_t buf_len, u8 answer) | ||
69 | { | ||
70 | int ret; | ||
71 | |||
72 | wl1251_debug(DEBUG_CMD, "cmd test"); | ||
73 | |||
74 | ret = wl1251_cmd_send(wl, CMD_TEST, buf, buf_len); | ||
75 | |||
76 | if (ret < 0) { | ||
77 | wl1251_warning("TEST command failed"); | ||
78 | return ret; | ||
79 | } | ||
80 | |||
81 | if (answer) { | ||
82 | struct wl1251_command *cmd_answer; | ||
83 | |||
84 | /* | ||
85 | * The test command got in, we can read the answer. | ||
86 | * The answer would be a wl1251_command, where the | ||
87 | * parameter array contains the actual answer. | ||
88 | */ | ||
89 | wl1251_mem_read(wl, wl->cmd_box_addr, buf, buf_len); | ||
90 | |||
91 | cmd_answer = buf; | ||
92 | |||
93 | if (cmd_answer->header.status != CMD_STATUS_SUCCESS) | ||
94 | wl1251_error("TEST command answer error: %d", | ||
95 | cmd_answer->header.status); | ||
96 | } | ||
97 | |||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | /** | ||
102 | * read acx from firmware | ||
103 | * | ||
104 | * @wl: wl struct | ||
105 | * @id: acx id | ||
106 | * @buf: buffer for the response, including all headers, must work with dma | ||
107 | * @len: length of buf | ||
108 | */ | ||
109 | int wl1251_cmd_interrogate(struct wl1251 *wl, u16 id, void *buf, size_t len) | ||
110 | { | ||
111 | struct acx_header *acx = buf; | ||
112 | int ret; | ||
113 | |||
114 | wl1251_debug(DEBUG_CMD, "cmd interrogate"); | ||
115 | |||
116 | acx->id = id; | ||
117 | |||
118 | /* payload length, does not include any headers */ | ||
119 | acx->len = len - sizeof(*acx); | ||
120 | |||
121 | ret = wl1251_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx)); | ||
122 | if (ret < 0) { | ||
123 | wl1251_error("INTERROGATE command failed"); | ||
124 | goto out; | ||
125 | } | ||
126 | |||
127 | /* the interrogate command got in, we can read the answer */ | ||
128 | wl1251_mem_read(wl, wl->cmd_box_addr, buf, len); | ||
129 | |||
130 | acx = buf; | ||
131 | if (acx->cmd.status != CMD_STATUS_SUCCESS) | ||
132 | wl1251_error("INTERROGATE command error: %d", | ||
133 | acx->cmd.status); | ||
134 | |||
135 | out: | ||
136 | return ret; | ||
137 | } | ||
138 | |||
139 | /** | ||
140 | * write acx value to firmware | ||
141 | * | ||
142 | * @wl: wl struct | ||
143 | * @id: acx id | ||
144 | * @buf: buffer containing acx, including all headers, must work with dma | ||
145 | * @len: length of buf | ||
146 | */ | ||
147 | int wl1251_cmd_configure(struct wl1251 *wl, u16 id, void *buf, size_t len) | ||
148 | { | ||
149 | struct acx_header *acx = buf; | ||
150 | int ret; | ||
151 | |||
152 | wl1251_debug(DEBUG_CMD, "cmd configure"); | ||
153 | |||
154 | acx->id = id; | ||
155 | |||
156 | /* payload length, does not include any headers */ | ||
157 | acx->len = len - sizeof(*acx); | ||
158 | |||
159 | ret = wl1251_cmd_send(wl, CMD_CONFIGURE, acx, len); | ||
160 | if (ret < 0) { | ||
161 | wl1251_warning("CONFIGURE command NOK"); | ||
162 | return ret; | ||
163 | } | ||
164 | |||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity, | ||
169 | void *bitmap, u16 bitmap_len, u8 bitmap_control) | ||
170 | { | ||
171 | struct wl1251_cmd_vbm_update *vbm; | ||
172 | int ret; | ||
173 | |||
174 | wl1251_debug(DEBUG_CMD, "cmd vbm"); | ||
175 | |||
176 | vbm = kzalloc(sizeof(*vbm), GFP_KERNEL); | ||
177 | if (!vbm) { | ||
178 | ret = -ENOMEM; | ||
179 | goto out; | ||
180 | } | ||
181 | |||
182 | /* Count and period will be filled by the target */ | ||
183 | vbm->tim.bitmap_ctrl = bitmap_control; | ||
184 | if (bitmap_len > PARTIAL_VBM_MAX) { | ||
185 | wl1251_warning("cmd vbm len is %d B, truncating to %d", | ||
186 | bitmap_len, PARTIAL_VBM_MAX); | ||
187 | bitmap_len = PARTIAL_VBM_MAX; | ||
188 | } | ||
189 | memcpy(vbm->tim.pvb_field, bitmap, bitmap_len); | ||
190 | vbm->tim.identity = identity; | ||
191 | vbm->tim.length = bitmap_len + 3; | ||
192 | |||
193 | vbm->len = cpu_to_le16(bitmap_len + 5); | ||
194 | |||
195 | ret = wl1251_cmd_send(wl, CMD_VBM, vbm, sizeof(*vbm)); | ||
196 | if (ret < 0) { | ||
197 | wl1251_error("VBM command failed"); | ||
198 | goto out; | ||
199 | } | ||
200 | |||
201 | out: | ||
202 | kfree(vbm); | ||
203 | return ret; | ||
204 | } | ||
205 | |||
206 | int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable) | ||
207 | { | ||
208 | struct cmd_enabledisable_path *cmd; | ||
209 | int ret; | ||
210 | u16 cmd_rx, cmd_tx; | ||
211 | |||
212 | wl1251_debug(DEBUG_CMD, "cmd data path"); | ||
213 | |||
214 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
215 | if (!cmd) { | ||
216 | ret = -ENOMEM; | ||
217 | goto out; | ||
218 | } | ||
219 | |||
220 | cmd->channel = channel; | ||
221 | |||
222 | if (enable) { | ||
223 | cmd_rx = CMD_ENABLE_RX; | ||
224 | cmd_tx = CMD_ENABLE_TX; | ||
225 | } else { | ||
226 | cmd_rx = CMD_DISABLE_RX; | ||
227 | cmd_tx = CMD_DISABLE_TX; | ||
228 | } | ||
229 | |||
230 | ret = wl1251_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd)); | ||
231 | if (ret < 0) { | ||
232 | wl1251_error("rx %s cmd for channel %d failed", | ||
233 | enable ? "start" : "stop", channel); | ||
234 | goto out; | ||
235 | } | ||
236 | |||
237 | wl1251_debug(DEBUG_BOOT, "rx %s cmd channel %d", | ||
238 | enable ? "start" : "stop", channel); | ||
239 | |||
240 | ret = wl1251_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd)); | ||
241 | if (ret < 0) { | ||
242 | wl1251_error("tx %s cmd for channel %d failed", | ||
243 | enable ? "start" : "stop", channel); | ||
244 | goto out; | ||
245 | } | ||
246 | |||
247 | wl1251_debug(DEBUG_BOOT, "tx %s cmd channel %d", | ||
248 | enable ? "start" : "stop", channel); | ||
249 | |||
250 | out: | ||
251 | kfree(cmd); | ||
252 | return ret; | ||
253 | } | ||
254 | |||
255 | int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 channel, | ||
256 | u16 beacon_interval, u8 dtim_interval) | ||
257 | { | ||
258 | struct cmd_join *join; | ||
259 | int ret, i; | ||
260 | u8 *bssid; | ||
261 | |||
262 | join = kzalloc(sizeof(*join), GFP_KERNEL); | ||
263 | if (!join) { | ||
264 | ret = -ENOMEM; | ||
265 | goto out; | ||
266 | } | ||
267 | |||
268 | wl1251_debug(DEBUG_CMD, "cmd join%s ch %d %d/%d", | ||
269 | bss_type == BSS_TYPE_IBSS ? " ibss" : "", | ||
270 | channel, beacon_interval, dtim_interval); | ||
271 | |||
272 | /* Reverse order BSSID */ | ||
273 | bssid = (u8 *) &join->bssid_lsb; | ||
274 | for (i = 0; i < ETH_ALEN; i++) | ||
275 | bssid[i] = wl->bssid[ETH_ALEN - i - 1]; | ||
276 | |||
277 | join->rx_config_options = wl->rx_config; | ||
278 | join->rx_filter_options = wl->rx_filter; | ||
279 | |||
280 | /* | ||
281 | * FIXME: disable temporarily all filters because after commit | ||
282 | * 9cef8737 "mac80211: fix managed mode BSSID handling" broke | ||
283 | * association. The filter logic needs to be implemented properly | ||
284 | * and once that is done, this hack can be removed. | ||
285 | */ | ||
286 | join->rx_config_options = 0; | ||
287 | join->rx_filter_options = WL1251_DEFAULT_RX_FILTER; | ||
288 | |||
289 | join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS | | ||
290 | RATE_MASK_5_5MBPS | RATE_MASK_11MBPS; | ||
291 | |||
292 | join->beacon_interval = beacon_interval; | ||
293 | join->dtim_interval = dtim_interval; | ||
294 | join->bss_type = bss_type; | ||
295 | join->channel = channel; | ||
296 | join->ctrl = JOIN_CMD_CTRL_TX_FLUSH; | ||
297 | |||
298 | ret = wl1251_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join)); | ||
299 | if (ret < 0) { | ||
300 | wl1251_error("failed to initiate cmd join"); | ||
301 | goto out; | ||
302 | } | ||
303 | |||
304 | out: | ||
305 | kfree(join); | ||
306 | return ret; | ||
307 | } | ||
308 | |||
309 | int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode) | ||
310 | { | ||
311 | struct wl1251_cmd_ps_params *ps_params = NULL; | ||
312 | int ret = 0; | ||
313 | |||
314 | wl1251_debug(DEBUG_CMD, "cmd set ps mode"); | ||
315 | |||
316 | ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL); | ||
317 | if (!ps_params) { | ||
318 | ret = -ENOMEM; | ||
319 | goto out; | ||
320 | } | ||
321 | |||
322 | ps_params->ps_mode = ps_mode; | ||
323 | ps_params->send_null_data = 1; | ||
324 | ps_params->retries = 5; | ||
325 | ps_params->hang_over_period = 128; | ||
326 | ps_params->null_data_rate = 1; /* 1 Mbps */ | ||
327 | |||
328 | ret = wl1251_cmd_send(wl, CMD_SET_PS_MODE, ps_params, | ||
329 | sizeof(*ps_params)); | ||
330 | if (ret < 0) { | ||
331 | wl1251_error("cmd set_ps_mode failed"); | ||
332 | goto out; | ||
333 | } | ||
334 | |||
335 | out: | ||
336 | kfree(ps_params); | ||
337 | return ret; | ||
338 | } | ||
339 | |||
340 | int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer, | ||
341 | size_t len) | ||
342 | { | ||
343 | struct cmd_read_write_memory *cmd; | ||
344 | int ret = 0; | ||
345 | |||
346 | wl1251_debug(DEBUG_CMD, "cmd read memory"); | ||
347 | |||
348 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
349 | if (!cmd) { | ||
350 | ret = -ENOMEM; | ||
351 | goto out; | ||
352 | } | ||
353 | |||
354 | WARN_ON(len > MAX_READ_SIZE); | ||
355 | len = min_t(size_t, len, MAX_READ_SIZE); | ||
356 | |||
357 | cmd->addr = addr; | ||
358 | cmd->size = len; | ||
359 | |||
360 | ret = wl1251_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd)); | ||
361 | if (ret < 0) { | ||
362 | wl1251_error("read memory command failed: %d", ret); | ||
363 | goto out; | ||
364 | } | ||
365 | |||
366 | /* the read command got in, we can now read the answer */ | ||
367 | wl1251_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd)); | ||
368 | |||
369 | if (cmd->header.status != CMD_STATUS_SUCCESS) | ||
370 | wl1251_error("error in read command result: %d", | ||
371 | cmd->header.status); | ||
372 | |||
373 | memcpy(answer, cmd->value, len); | ||
374 | |||
375 | out: | ||
376 | kfree(cmd); | ||
377 | return ret; | ||
378 | } | ||
379 | |||
380 | int wl1251_cmd_template_set(struct wl1251 *wl, u16 cmd_id, | ||
381 | void *buf, size_t buf_len) | ||
382 | { | ||
383 | struct wl1251_cmd_packet_template *cmd; | ||
384 | size_t cmd_len; | ||
385 | int ret = 0; | ||
386 | |||
387 | wl1251_debug(DEBUG_CMD, "cmd template %d", cmd_id); | ||
388 | |||
389 | WARN_ON(buf_len > WL1251_MAX_TEMPLATE_SIZE); | ||
390 | buf_len = min_t(size_t, buf_len, WL1251_MAX_TEMPLATE_SIZE); | ||
391 | cmd_len = ALIGN(sizeof(*cmd) + buf_len, 4); | ||
392 | |||
393 | cmd = kzalloc(cmd_len, GFP_KERNEL); | ||
394 | if (!cmd) { | ||
395 | ret = -ENOMEM; | ||
396 | goto out; | ||
397 | } | ||
398 | |||
399 | cmd->size = cpu_to_le16(buf_len); | ||
400 | |||
401 | if (buf) | ||
402 | memcpy(cmd->data, buf, buf_len); | ||
403 | |||
404 | ret = wl1251_cmd_send(wl, cmd_id, cmd, cmd_len); | ||
405 | if (ret < 0) { | ||
406 | wl1251_warning("cmd set_template failed: %d", ret); | ||
407 | goto out; | ||
408 | } | ||
409 | |||
410 | out: | ||
411 | kfree(cmd); | ||
412 | return ret; | ||
413 | } | ||
414 | |||
415 | int wl1251_cmd_scan(struct wl1251 *wl, u8 *ssid, size_t ssid_len, | ||
416 | struct ieee80211_channel *channels[], | ||
417 | unsigned int n_channels, unsigned int n_probes) | ||
418 | { | ||
419 | struct wl1251_cmd_scan *cmd; | ||
420 | int i, ret = 0; | ||
421 | |||
422 | wl1251_debug(DEBUG_CMD, "cmd scan"); | ||
423 | |||
424 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
425 | if (!cmd) | ||
426 | return -ENOMEM; | ||
427 | |||
428 | cmd->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD); | ||
429 | cmd->params.rx_filter_options = cpu_to_le32(CFG_RX_PRSP_EN | | ||
430 | CFG_RX_MGMT_EN | | ||
431 | CFG_RX_BCN_EN); | ||
432 | cmd->params.scan_options = 0; | ||
433 | cmd->params.num_channels = n_channels; | ||
434 | cmd->params.num_probe_requests = n_probes; | ||
435 | cmd->params.tx_rate = cpu_to_le16(1 << 1); /* 2 Mbps */ | ||
436 | cmd->params.tid_trigger = 0; | ||
437 | |||
438 | for (i = 0; i < n_channels; i++) { | ||
439 | cmd->channels[i].min_duration = | ||
440 | cpu_to_le32(WL1251_SCAN_MIN_DURATION); | ||
441 | cmd->channels[i].max_duration = | ||
442 | cpu_to_le32(WL1251_SCAN_MAX_DURATION); | ||
443 | memset(&cmd->channels[i].bssid_lsb, 0xff, 4); | ||
444 | memset(&cmd->channels[i].bssid_msb, 0xff, 2); | ||
445 | cmd->channels[i].early_termination = 0; | ||
446 | cmd->channels[i].tx_power_att = 0; | ||
447 | cmd->channels[i].channel = channels[i]->hw_value; | ||
448 | } | ||
449 | |||
450 | cmd->params.ssid_len = ssid_len; | ||
451 | if (ssid) | ||
452 | memcpy(cmd->params.ssid, ssid, ssid_len); | ||
453 | |||
454 | ret = wl1251_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd)); | ||
455 | if (ret < 0) { | ||
456 | wl1251_error("cmd scan failed: %d", ret); | ||
457 | goto out; | ||
458 | } | ||
459 | |||
460 | wl1251_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd)); | ||
461 | |||
462 | if (cmd->header.status != CMD_STATUS_SUCCESS) { | ||
463 | wl1251_error("cmd scan status wasn't success: %d", | ||
464 | cmd->header.status); | ||
465 | ret = -EIO; | ||
466 | goto out; | ||
467 | } | ||
468 | |||
469 | out: | ||
470 | kfree(cmd); | ||
471 | return ret; | ||
472 | } | ||
473 | |||
474 | int wl1251_cmd_trigger_scan_to(struct wl1251 *wl, u32 timeout) | ||
475 | { | ||
476 | struct wl1251_cmd_trigger_scan_to *cmd; | ||
477 | int ret; | ||
478 | |||
479 | wl1251_debug(DEBUG_CMD, "cmd trigger scan to"); | ||
480 | |||
481 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
482 | if (!cmd) | ||
483 | return -ENOMEM; | ||
484 | |||
485 | cmd->timeout = timeout; | ||
486 | |||
487 | ret = wl1251_cmd_send(wl, CMD_TRIGGER_SCAN_TO, cmd, sizeof(*cmd)); | ||
488 | if (ret < 0) { | ||
489 | wl1251_error("cmd trigger scan to failed: %d", ret); | ||
490 | goto out; | ||
491 | } | ||
492 | |||
493 | out: | ||
494 | kfree(cmd); | ||
495 | return ret; | ||
496 | } | ||
diff --git a/drivers/net/wireless/ti/wl1251/cmd.h b/drivers/net/wireless/ti/wl1251/cmd.h new file mode 100644 index 000000000000..ee4f2b391822 --- /dev/null +++ b/drivers/net/wireless/ti/wl1251/cmd.h | |||
@@ -0,0 +1,415 @@ | |||
1 | /* | ||
2 | * This file is part of wl1251 | ||
3 | * | ||
4 | * Copyright (c) 1998-2007 Texas Instruments Incorporated | ||
5 | * Copyright (C) 2008 Nokia Corporation | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * version 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
19 | * 02110-1301 USA | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #ifndef __WL1251_CMD_H__ | ||
24 | #define __WL1251_CMD_H__ | ||
25 | |||
26 | #include "wl1251.h" | ||
27 | |||
28 | #include <net/cfg80211.h> | ||
29 | |||
30 | struct acx_header; | ||
31 | |||
32 | int wl1251_cmd_send(struct wl1251 *wl, u16 type, void *buf, size_t buf_len); | ||
33 | int wl1251_cmd_test(struct wl1251 *wl, void *buf, size_t buf_len, u8 answer); | ||
34 | int wl1251_cmd_interrogate(struct wl1251 *wl, u16 id, void *buf, size_t len); | ||
35 | int wl1251_cmd_configure(struct wl1251 *wl, u16 id, void *buf, size_t len); | ||
36 | int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity, | ||
37 | void *bitmap, u16 bitmap_len, u8 bitmap_control); | ||
38 | int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable); | ||
39 | int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 channel, | ||
40 | u16 beacon_interval, u8 dtim_interval); | ||
41 | int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode); | ||
42 | int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer, | ||
43 | size_t len); | ||
44 | int wl1251_cmd_template_set(struct wl1251 *wl, u16 cmd_id, | ||
45 | void *buf, size_t buf_len); | ||
46 | int wl1251_cmd_scan(struct wl1251 *wl, u8 *ssid, size_t ssid_len, | ||
47 | struct ieee80211_channel *channels[], | ||
48 | unsigned int n_channels, unsigned int n_probes); | ||
49 | int wl1251_cmd_trigger_scan_to(struct wl1251 *wl, u32 timeout); | ||
50 | |||
51 | /* unit ms */ | ||
52 | #define WL1251_COMMAND_TIMEOUT 2000 | ||
53 | |||
54 | enum wl1251_commands { | ||
55 | CMD_RESET = 0, | ||
56 | CMD_INTERROGATE = 1, /*use this to read information elements*/ | ||
57 | CMD_CONFIGURE = 2, /*use this to write information elements*/ | ||
58 | CMD_ENABLE_RX = 3, | ||
59 | CMD_ENABLE_TX = 4, | ||
60 | CMD_DISABLE_RX = 5, | ||
61 | CMD_DISABLE_TX = 6, | ||
62 | CMD_SCAN = 8, | ||
63 | CMD_STOP_SCAN = 9, | ||
64 | CMD_VBM = 10, | ||
65 | CMD_START_JOIN = 11, | ||
66 | CMD_SET_KEYS = 12, | ||
67 | CMD_READ_MEMORY = 13, | ||
68 | CMD_WRITE_MEMORY = 14, | ||
69 | CMD_BEACON = 19, | ||
70 | CMD_PROBE_RESP = 20, | ||
71 | CMD_NULL_DATA = 21, | ||
72 | CMD_PROBE_REQ = 22, | ||
73 | CMD_TEST = 23, | ||
74 | CMD_RADIO_CALIBRATE = 25, /* OBSOLETE */ | ||
75 | CMD_ENABLE_RX_PATH = 27, /* OBSOLETE */ | ||
76 | CMD_NOISE_HIST = 28, | ||
77 | CMD_RX_RESET = 29, | ||
78 | CMD_PS_POLL = 30, | ||
79 | CMD_QOS_NULL_DATA = 31, | ||
80 | CMD_LNA_CONTROL = 32, | ||
81 | CMD_SET_BCN_MODE = 33, | ||
82 | CMD_MEASUREMENT = 34, | ||
83 | CMD_STOP_MEASUREMENT = 35, | ||
84 | CMD_DISCONNECT = 36, | ||
85 | CMD_SET_PS_MODE = 37, | ||
86 | CMD_CHANNEL_SWITCH = 38, | ||
87 | CMD_STOP_CHANNEL_SWICTH = 39, | ||
88 | CMD_AP_DISCOVERY = 40, | ||
89 | CMD_STOP_AP_DISCOVERY = 41, | ||
90 | CMD_SPS_SCAN = 42, | ||
91 | CMD_STOP_SPS_SCAN = 43, | ||
92 | CMD_HEALTH_CHECK = 45, | ||
93 | CMD_DEBUG = 46, | ||
94 | CMD_TRIGGER_SCAN_TO = 47, | ||
95 | |||
96 | NUM_COMMANDS, | ||
97 | MAX_COMMAND_ID = 0xFFFF, | ||
98 | }; | ||
99 | |||
100 | #define MAX_CMD_PARAMS 572 | ||
101 | |||
102 | struct wl1251_cmd_header { | ||
103 | u16 id; | ||
104 | u16 status; | ||
105 | /* payload */ | ||
106 | u8 data[0]; | ||
107 | } __packed; | ||
108 | |||
109 | struct wl1251_command { | ||
110 | struct wl1251_cmd_header header; | ||
111 | u8 parameters[MAX_CMD_PARAMS]; | ||
112 | } __packed; | ||
113 | |||
114 | enum { | ||
115 | CMD_MAILBOX_IDLE = 0, | ||
116 | CMD_STATUS_SUCCESS = 1, | ||
117 | CMD_STATUS_UNKNOWN_CMD = 2, | ||
118 | CMD_STATUS_UNKNOWN_IE = 3, | ||
119 | CMD_STATUS_REJECT_MEAS_SG_ACTIVE = 11, | ||
120 | CMD_STATUS_RX_BUSY = 13, | ||
121 | CMD_STATUS_INVALID_PARAM = 14, | ||
122 | CMD_STATUS_TEMPLATE_TOO_LARGE = 15, | ||
123 | CMD_STATUS_OUT_OF_MEMORY = 16, | ||
124 | CMD_STATUS_STA_TABLE_FULL = 17, | ||
125 | CMD_STATUS_RADIO_ERROR = 18, | ||
126 | CMD_STATUS_WRONG_NESTING = 19, | ||
127 | CMD_STATUS_TIMEOUT = 21, /* Driver internal use.*/ | ||
128 | CMD_STATUS_FW_RESET = 22, /* Driver internal use.*/ | ||
129 | MAX_COMMAND_STATUS = 0xff | ||
130 | }; | ||
131 | |||
132 | |||
133 | /* | ||
134 | * CMD_READ_MEMORY | ||
135 | * | ||
136 | * The host issues this command to read the WiLink device memory/registers. | ||
137 | * | ||
138 | * Note: The Base Band address has special handling (16 bits registers and | ||
139 | * addresses). For more information, see the hardware specification. | ||
140 | */ | ||
141 | /* | ||
142 | * CMD_WRITE_MEMORY | ||
143 | * | ||
144 | * The host issues this command to write the WiLink device memory/registers. | ||
145 | * | ||
146 | * The Base Band address has special handling (16 bits registers and | ||
147 | * addresses). For more information, see the hardware specification. | ||
148 | */ | ||
149 | #define MAX_READ_SIZE 256 | ||
150 | |||
151 | struct cmd_read_write_memory { | ||
152 | struct wl1251_cmd_header header; | ||
153 | |||
154 | /* The address of the memory to read from or write to.*/ | ||
155 | u32 addr; | ||
156 | |||
157 | /* The amount of data in bytes to read from or write to the WiLink | ||
158 | * device.*/ | ||
159 | u32 size; | ||
160 | |||
161 | /* The actual value read from or written to the Wilink. The source | ||
162 | of this field is the Host in WRITE command or the Wilink in READ | ||
163 | command. */ | ||
164 | u8 value[MAX_READ_SIZE]; | ||
165 | } __packed; | ||
166 | |||
167 | #define CMDMBOX_HEADER_LEN 4 | ||
168 | #define CMDMBOX_INFO_ELEM_HEADER_LEN 4 | ||
169 | |||
170 | #define WL1251_SCAN_MIN_DURATION 30000 | ||
171 | #define WL1251_SCAN_MAX_DURATION 60000 | ||
172 | |||
173 | #define WL1251_SCAN_NUM_PROBES 3 | ||
174 | |||
175 | struct wl1251_scan_parameters { | ||
176 | __le32 rx_config_options; | ||
177 | __le32 rx_filter_options; | ||
178 | |||
179 | /* | ||
180 | * Scan options: | ||
181 | * bit 0: When this bit is set, passive scan. | ||
182 | * bit 1: Band, when this bit is set we scan | ||
183 | * in the 5Ghz band. | ||
184 | * bit 2: voice mode, 0 for normal scan. | ||
185 | * bit 3: scan priority, 1 for high priority. | ||
186 | */ | ||
187 | __le16 scan_options; | ||
188 | |||
189 | /* Number of channels to scan */ | ||
190 | u8 num_channels; | ||
191 | |||
192 | /* Number opf probe requests to send, per channel */ | ||
193 | u8 num_probe_requests; | ||
194 | |||
195 | /* Rate and modulation for probe requests */ | ||
196 | __le16 tx_rate; | ||
197 | |||
198 | u8 tid_trigger; | ||
199 | u8 ssid_len; | ||
200 | u8 ssid[32]; | ||
201 | |||
202 | } __packed; | ||
203 | |||
204 | struct wl1251_scan_ch_parameters { | ||
205 | __le32 min_duration; /* in TU */ | ||
206 | __le32 max_duration; /* in TU */ | ||
207 | u32 bssid_lsb; | ||
208 | u16 bssid_msb; | ||
209 | |||
210 | /* | ||
211 | * bits 0-3: Early termination count. | ||
212 | * bits 4-5: Early termination condition. | ||
213 | */ | ||
214 | u8 early_termination; | ||
215 | |||
216 | u8 tx_power_att; | ||
217 | u8 channel; | ||
218 | u8 pad[3]; | ||
219 | } __packed; | ||
220 | |||
221 | /* SCAN parameters */ | ||
222 | #define SCAN_MAX_NUM_OF_CHANNELS 16 | ||
223 | |||
224 | struct wl1251_cmd_scan { | ||
225 | struct wl1251_cmd_header header; | ||
226 | |||
227 | struct wl1251_scan_parameters params; | ||
228 | struct wl1251_scan_ch_parameters channels[SCAN_MAX_NUM_OF_CHANNELS]; | ||
229 | } __packed; | ||
230 | |||
231 | enum { | ||
232 | BSS_TYPE_IBSS = 0, | ||
233 | BSS_TYPE_STA_BSS = 2, | ||
234 | BSS_TYPE_AP_BSS = 3, | ||
235 | MAX_BSS_TYPE = 0xFF | ||
236 | }; | ||
237 | |||
238 | #define JOIN_CMD_CTRL_TX_FLUSH 0x80 /* Firmware flushes all Tx */ | ||
239 | #define JOIN_CMD_CTRL_EARLY_WAKEUP_ENABLE 0x01 /* Early wakeup time */ | ||
240 | |||
241 | |||
242 | struct cmd_join { | ||
243 | struct wl1251_cmd_header header; | ||
244 | |||
245 | u32 bssid_lsb; | ||
246 | u16 bssid_msb; | ||
247 | u16 beacon_interval; /* in TBTTs */ | ||
248 | u32 rx_config_options; | ||
249 | u32 rx_filter_options; | ||
250 | |||
251 | /* | ||
252 | * The target uses this field to determine the rate at | ||
253 | * which to transmit control frame responses (such as | ||
254 | * ACK or CTS frames). | ||
255 | */ | ||
256 | u16 basic_rate_set; | ||
257 | u8 dtim_interval; | ||
258 | u8 tx_ctrl_frame_rate; /* OBSOLETE */ | ||
259 | u8 tx_ctrl_frame_mod; /* OBSOLETE */ | ||
260 | /* | ||
261 | * bits 0-2: This bitwise field specifies the type | ||
262 | * of BSS to start or join (BSS_TYPE_*). | ||
263 | * bit 4: Band - The radio band in which to join | ||
264 | * or start. | ||
265 | * 0 - 2.4GHz band | ||
266 | * 1 - 5GHz band | ||
267 | * bits 3, 5-7: Reserved | ||
268 | */ | ||
269 | u8 bss_type; | ||
270 | u8 channel; | ||
271 | u8 ssid_len; | ||
272 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | ||
273 | u8 ctrl; /* JOIN_CMD_CTRL_* */ | ||
274 | u8 tx_mgt_frame_rate; /* OBSOLETE */ | ||
275 | u8 tx_mgt_frame_mod; /* OBSOLETE */ | ||
276 | u8 reserved; | ||
277 | } __packed; | ||
278 | |||
279 | struct cmd_enabledisable_path { | ||
280 | struct wl1251_cmd_header header; | ||
281 | |||
282 | u8 channel; | ||
283 | u8 padding[3]; | ||
284 | } __packed; | ||
285 | |||
286 | #define WL1251_MAX_TEMPLATE_SIZE 300 | ||
287 | |||
288 | struct wl1251_cmd_packet_template { | ||
289 | struct wl1251_cmd_header header; | ||
290 | |||
291 | __le16 size; | ||
292 | u8 data[0]; | ||
293 | } __packed; | ||
294 | |||
295 | #define TIM_ELE_ID 5 | ||
296 | #define PARTIAL_VBM_MAX 251 | ||
297 | |||
298 | struct wl1251_tim { | ||
299 | u8 identity; | ||
300 | u8 length; | ||
301 | u8 dtim_count; | ||
302 | u8 dtim_period; | ||
303 | u8 bitmap_ctrl; | ||
304 | u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */ | ||
305 | } __packed; | ||
306 | |||
307 | /* Virtual Bit Map update */ | ||
308 | struct wl1251_cmd_vbm_update { | ||
309 | struct wl1251_cmd_header header; | ||
310 | __le16 len; | ||
311 | u8 padding[2]; | ||
312 | struct wl1251_tim tim; | ||
313 | } __packed; | ||
314 | |||
315 | enum wl1251_cmd_ps_mode { | ||
316 | CHIP_ACTIVE_MODE, | ||
317 | CHIP_POWER_SAVE_MODE | ||
318 | }; | ||
319 | |||
320 | struct wl1251_cmd_ps_params { | ||
321 | struct wl1251_cmd_header header; | ||
322 | |||
323 | u8 ps_mode; /* STATION_* */ | ||
324 | u8 send_null_data; /* Do we have to send NULL data packet ? */ | ||
325 | u8 retries; /* Number of retires for the initial NULL data packet */ | ||
326 | |||
327 | /* | ||
328 | * TUs during which the target stays awake after switching | ||
329 | * to power save mode. | ||
330 | */ | ||
331 | u8 hang_over_period; | ||
332 | u16 null_data_rate; | ||
333 | u8 pad[2]; | ||
334 | } __packed; | ||
335 | |||
336 | struct wl1251_cmd_trigger_scan_to { | ||
337 | struct wl1251_cmd_header header; | ||
338 | |||
339 | u32 timeout; | ||
340 | } __packed; | ||
341 | |||
342 | /* HW encryption keys */ | ||
343 | #define NUM_ACCESS_CATEGORIES_COPY 4 | ||
344 | #define MAX_KEY_SIZE 32 | ||
345 | |||
346 | /* When set, disable HW encryption */ | ||
347 | #define DF_ENCRYPTION_DISABLE 0x01 | ||
348 | /* When set, disable HW decryption */ | ||
349 | #define DF_SNIFF_MODE_ENABLE 0x80 | ||
350 | |||
351 | enum wl1251_cmd_key_action { | ||
352 | KEY_ADD_OR_REPLACE = 1, | ||
353 | KEY_REMOVE = 2, | ||
354 | KEY_SET_ID = 3, | ||
355 | MAX_KEY_ACTION = 0xffff, | ||
356 | }; | ||
357 | |||
358 | enum wl1251_cmd_key_type { | ||
359 | KEY_WEP_DEFAULT = 0, | ||
360 | KEY_WEP_ADDR = 1, | ||
361 | KEY_AES_GROUP = 4, | ||
362 | KEY_AES_PAIRWISE = 5, | ||
363 | KEY_WEP_GROUP = 6, | ||
364 | KEY_TKIP_MIC_GROUP = 10, | ||
365 | KEY_TKIP_MIC_PAIRWISE = 11, | ||
366 | }; | ||
367 | |||
368 | /* | ||
369 | * | ||
370 | * key_type_e key size key format | ||
371 | * ---------- --------- ---------- | ||
372 | * 0x00 5, 13, 29 Key data | ||
373 | * 0x01 5, 13, 29 Key data | ||
374 | * 0x04 16 16 bytes of key data | ||
375 | * 0x05 16 16 bytes of key data | ||
376 | * 0x0a 32 16 bytes of TKIP key data | ||
377 | * 8 bytes of RX MIC key data | ||
378 | * 8 bytes of TX MIC key data | ||
379 | * 0x0b 32 16 bytes of TKIP key data | ||
380 | * 8 bytes of RX MIC key data | ||
381 | * 8 bytes of TX MIC key data | ||
382 | * | ||
383 | */ | ||
384 | |||
385 | struct wl1251_cmd_set_keys { | ||
386 | struct wl1251_cmd_header header; | ||
387 | |||
388 | /* Ignored for default WEP key */ | ||
389 | u8 addr[ETH_ALEN]; | ||
390 | |||
391 | /* key_action_e */ | ||
392 | u16 key_action; | ||
393 | |||
394 | u16 reserved_1; | ||
395 | |||
396 | /* key size in bytes */ | ||
397 | u8 key_size; | ||
398 | |||
399 | /* key_type_e */ | ||
400 | u8 key_type; | ||
401 | u8 ssid_profile; | ||
402 | |||
403 | /* | ||
404 | * TKIP, AES: frame's key id field. | ||
405 | * For WEP default key: key id; | ||
406 | */ | ||
407 | u8 id; | ||
408 | u8 reserved_2[6]; | ||
409 | u8 key[MAX_KEY_SIZE]; | ||
410 | u16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY]; | ||
411 | u32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY]; | ||
412 | } __packed; | ||
413 | |||
414 | |||
415 | #endif /* __WL1251_CMD_H__ */ | ||
diff --git a/drivers/net/wireless/ti/wl1251/debugfs.c b/drivers/net/wireless/ti/wl1251/debugfs.c new file mode 100644 index 000000000000..6c274007d200 --- /dev/null +++ b/drivers/net/wireless/ti/wl1251/debugfs.c | |||
@@ -0,0 +1,545 @@ | |||
1 | /* | ||
2 | * This file is part of wl1251 | ||
3 | * | ||
4 | * Copyright (C) 2009 Nokia Corporation | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * version 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
18 | * 02110-1301 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include "debugfs.h" | ||
23 | |||
24 | #include <linux/skbuff.h> | ||
25 | #include <linux/slab.h> | ||
26 | |||
27 | #include "wl1251.h" | ||
28 | #include "acx.h" | ||
29 | #include "ps.h" | ||
30 | |||
31 | /* ms */ | ||
32 | #define WL1251_DEBUGFS_STATS_LIFETIME 1000 | ||
33 | |||
34 | /* debugfs macros idea from mac80211 */ | ||
35 | |||
36 | #define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...) \ | ||
37 | static ssize_t name## _read(struct file *file, char __user *userbuf, \ | ||
38 | size_t count, loff_t *ppos) \ | ||
39 | { \ | ||
40 | struct wl1251 *wl = file->private_data; \ | ||
41 | char buf[buflen]; \ | ||
42 | int res; \ | ||
43 | \ | ||
44 | res = scnprintf(buf, buflen, fmt "\n", ##value); \ | ||
45 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ | ||
46 | } \ | ||
47 | \ | ||
48 | static const struct file_operations name## _ops = { \ | ||
49 | .read = name## _read, \ | ||
50 | .open = wl1251_open_file_generic, \ | ||
51 | .llseek = generic_file_llseek, \ | ||
52 | }; | ||
53 | |||
54 | #define DEBUGFS_ADD(name, parent) \ | ||
55 | wl->debugfs.name = debugfs_create_file(#name, 0400, parent, \ | ||
56 | wl, &name## _ops); \ | ||
57 | if (IS_ERR(wl->debugfs.name)) { \ | ||
58 | ret = PTR_ERR(wl->debugfs.name); \ | ||
59 | wl->debugfs.name = NULL; \ | ||
60 | goto out; \ | ||
61 | } | ||
62 | |||
63 | #define DEBUGFS_DEL(name) \ | ||
64 | do { \ | ||
65 | debugfs_remove(wl->debugfs.name); \ | ||
66 | wl->debugfs.name = NULL; \ | ||
67 | } while (0) | ||
68 | |||
69 | #define DEBUGFS_FWSTATS_FILE(sub, name, buflen, fmt) \ | ||
70 | static ssize_t sub## _ ##name## _read(struct file *file, \ | ||
71 | char __user *userbuf, \ | ||
72 | size_t count, loff_t *ppos) \ | ||
73 | { \ | ||
74 | struct wl1251 *wl = file->private_data; \ | ||
75 | char buf[buflen]; \ | ||
76 | int res; \ | ||
77 | \ | ||
78 | wl1251_debugfs_update_stats(wl); \ | ||
79 | \ | ||
80 | res = scnprintf(buf, buflen, fmt "\n", \ | ||
81 | wl->stats.fw_stats->sub.name); \ | ||
82 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ | ||
83 | } \ | ||
84 | \ | ||
85 | static const struct file_operations sub## _ ##name## _ops = { \ | ||
86 | .read = sub## _ ##name## _read, \ | ||
87 | .open = wl1251_open_file_generic, \ | ||
88 | .llseek = generic_file_llseek, \ | ||
89 | }; | ||
90 | |||
91 | #define DEBUGFS_FWSTATS_ADD(sub, name) \ | ||
92 | DEBUGFS_ADD(sub## _ ##name, wl->debugfs.fw_statistics) | ||
93 | |||
94 | #define DEBUGFS_FWSTATS_DEL(sub, name) \ | ||
95 | DEBUGFS_DEL(sub## _ ##name) | ||
96 | |||
97 | static void wl1251_debugfs_update_stats(struct wl1251 *wl) | ||
98 | { | ||
99 | int ret; | ||
100 | |||
101 | mutex_lock(&wl->mutex); | ||
102 | |||
103 | ret = wl1251_ps_elp_wakeup(wl); | ||
104 | if (ret < 0) | ||
105 | goto out; | ||
106 | |||
107 | if (wl->state == WL1251_STATE_ON && | ||
108 | time_after(jiffies, wl->stats.fw_stats_update + | ||
109 | msecs_to_jiffies(WL1251_DEBUGFS_STATS_LIFETIME))) { | ||
110 | wl1251_acx_statistics(wl, wl->stats.fw_stats); | ||
111 | wl->stats.fw_stats_update = jiffies; | ||
112 | } | ||
113 | |||
114 | wl1251_ps_elp_sleep(wl); | ||
115 | |||
116 | out: | ||
117 | mutex_unlock(&wl->mutex); | ||
118 | } | ||
119 | |||
120 | static int wl1251_open_file_generic(struct inode *inode, struct file *file) | ||
121 | { | ||
122 | file->private_data = inode->i_private; | ||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | DEBUGFS_FWSTATS_FILE(tx, internal_desc_overflow, 20, "%u"); | ||
127 | |||
128 | DEBUGFS_FWSTATS_FILE(rx, out_of_mem, 20, "%u"); | ||
129 | DEBUGFS_FWSTATS_FILE(rx, hdr_overflow, 20, "%u"); | ||
130 | DEBUGFS_FWSTATS_FILE(rx, hw_stuck, 20, "%u"); | ||
131 | DEBUGFS_FWSTATS_FILE(rx, dropped, 20, "%u"); | ||
132 | DEBUGFS_FWSTATS_FILE(rx, fcs_err, 20, "%u"); | ||
133 | DEBUGFS_FWSTATS_FILE(rx, xfr_hint_trig, 20, "%u"); | ||
134 | DEBUGFS_FWSTATS_FILE(rx, path_reset, 20, "%u"); | ||
135 | DEBUGFS_FWSTATS_FILE(rx, reset_counter, 20, "%u"); | ||
136 | |||
137 | DEBUGFS_FWSTATS_FILE(dma, rx_requested, 20, "%u"); | ||
138 | DEBUGFS_FWSTATS_FILE(dma, rx_errors, 20, "%u"); | ||
139 | DEBUGFS_FWSTATS_FILE(dma, tx_requested, 20, "%u"); | ||
140 | DEBUGFS_FWSTATS_FILE(dma, tx_errors, 20, "%u"); | ||
141 | |||
142 | DEBUGFS_FWSTATS_FILE(isr, cmd_cmplt, 20, "%u"); | ||
143 | DEBUGFS_FWSTATS_FILE(isr, fiqs, 20, "%u"); | ||
144 | DEBUGFS_FWSTATS_FILE(isr, rx_headers, 20, "%u"); | ||
145 | DEBUGFS_FWSTATS_FILE(isr, rx_mem_overflow, 20, "%u"); | ||
146 | DEBUGFS_FWSTATS_FILE(isr, rx_rdys, 20, "%u"); | ||
147 | DEBUGFS_FWSTATS_FILE(isr, irqs, 20, "%u"); | ||
148 | DEBUGFS_FWSTATS_FILE(isr, tx_procs, 20, "%u"); | ||
149 | DEBUGFS_FWSTATS_FILE(isr, decrypt_done, 20, "%u"); | ||
150 | DEBUGFS_FWSTATS_FILE(isr, dma0_done, 20, "%u"); | ||
151 | DEBUGFS_FWSTATS_FILE(isr, dma1_done, 20, "%u"); | ||
152 | DEBUGFS_FWSTATS_FILE(isr, tx_exch_complete, 20, "%u"); | ||
153 | DEBUGFS_FWSTATS_FILE(isr, commands, 20, "%u"); | ||
154 | DEBUGFS_FWSTATS_FILE(isr, rx_procs, 20, "%u"); | ||
155 | DEBUGFS_FWSTATS_FILE(isr, hw_pm_mode_changes, 20, "%u"); | ||
156 | DEBUGFS_FWSTATS_FILE(isr, host_acknowledges, 20, "%u"); | ||
157 | DEBUGFS_FWSTATS_FILE(isr, pci_pm, 20, "%u"); | ||
158 | DEBUGFS_FWSTATS_FILE(isr, wakeups, 20, "%u"); | ||
159 | DEBUGFS_FWSTATS_FILE(isr, low_rssi, 20, "%u"); | ||
160 | |||
161 | DEBUGFS_FWSTATS_FILE(wep, addr_key_count, 20, "%u"); | ||
162 | DEBUGFS_FWSTATS_FILE(wep, default_key_count, 20, "%u"); | ||
163 | /* skipping wep.reserved */ | ||
164 | DEBUGFS_FWSTATS_FILE(wep, key_not_found, 20, "%u"); | ||
165 | DEBUGFS_FWSTATS_FILE(wep, decrypt_fail, 20, "%u"); | ||
166 | DEBUGFS_FWSTATS_FILE(wep, packets, 20, "%u"); | ||
167 | DEBUGFS_FWSTATS_FILE(wep, interrupt, 20, "%u"); | ||
168 | |||
169 | DEBUGFS_FWSTATS_FILE(pwr, ps_enter, 20, "%u"); | ||
170 | DEBUGFS_FWSTATS_FILE(pwr, elp_enter, 20, "%u"); | ||
171 | DEBUGFS_FWSTATS_FILE(pwr, missing_bcns, 20, "%u"); | ||
172 | DEBUGFS_FWSTATS_FILE(pwr, wake_on_host, 20, "%u"); | ||
173 | DEBUGFS_FWSTATS_FILE(pwr, wake_on_timer_exp, 20, "%u"); | ||
174 | DEBUGFS_FWSTATS_FILE(pwr, tx_with_ps, 20, "%u"); | ||
175 | DEBUGFS_FWSTATS_FILE(pwr, tx_without_ps, 20, "%u"); | ||
176 | DEBUGFS_FWSTATS_FILE(pwr, rcvd_beacons, 20, "%u"); | ||
177 | DEBUGFS_FWSTATS_FILE(pwr, power_save_off, 20, "%u"); | ||
178 | DEBUGFS_FWSTATS_FILE(pwr, enable_ps, 20, "%u"); | ||
179 | DEBUGFS_FWSTATS_FILE(pwr, disable_ps, 20, "%u"); | ||
180 | DEBUGFS_FWSTATS_FILE(pwr, fix_tsf_ps, 20, "%u"); | ||
181 | /* skipping cont_miss_bcns_spread for now */ | ||
182 | DEBUGFS_FWSTATS_FILE(pwr, rcvd_awake_beacons, 20, "%u"); | ||
183 | |||
184 | DEBUGFS_FWSTATS_FILE(mic, rx_pkts, 20, "%u"); | ||
185 | DEBUGFS_FWSTATS_FILE(mic, calc_failure, 20, "%u"); | ||
186 | |||
187 | DEBUGFS_FWSTATS_FILE(aes, encrypt_fail, 20, "%u"); | ||
188 | DEBUGFS_FWSTATS_FILE(aes, decrypt_fail, 20, "%u"); | ||
189 | DEBUGFS_FWSTATS_FILE(aes, encrypt_packets, 20, "%u"); | ||
190 | DEBUGFS_FWSTATS_FILE(aes, decrypt_packets, 20, "%u"); | ||
191 | DEBUGFS_FWSTATS_FILE(aes, encrypt_interrupt, 20, "%u"); | ||
192 | DEBUGFS_FWSTATS_FILE(aes, decrypt_interrupt, 20, "%u"); | ||
193 | |||
194 | DEBUGFS_FWSTATS_FILE(event, heart_beat, 20, "%u"); | ||
195 | DEBUGFS_FWSTATS_FILE(event, calibration, 20, "%u"); | ||
196 | DEBUGFS_FWSTATS_FILE(event, rx_mismatch, 20, "%u"); | ||
197 | DEBUGFS_FWSTATS_FILE(event, rx_mem_empty, 20, "%u"); | ||
198 | DEBUGFS_FWSTATS_FILE(event, rx_pool, 20, "%u"); | ||
199 | DEBUGFS_FWSTATS_FILE(event, oom_late, 20, "%u"); | ||
200 | DEBUGFS_FWSTATS_FILE(event, phy_transmit_error, 20, "%u"); | ||
201 | DEBUGFS_FWSTATS_FILE(event, tx_stuck, 20, "%u"); | ||
202 | |||
203 | DEBUGFS_FWSTATS_FILE(ps, pspoll_timeouts, 20, "%u"); | ||
204 | DEBUGFS_FWSTATS_FILE(ps, upsd_timeouts, 20, "%u"); | ||
205 | DEBUGFS_FWSTATS_FILE(ps, upsd_max_sptime, 20, "%u"); | ||
206 | DEBUGFS_FWSTATS_FILE(ps, upsd_max_apturn, 20, "%u"); | ||
207 | DEBUGFS_FWSTATS_FILE(ps, pspoll_max_apturn, 20, "%u"); | ||
208 | DEBUGFS_FWSTATS_FILE(ps, pspoll_utilization, 20, "%u"); | ||
209 | DEBUGFS_FWSTATS_FILE(ps, upsd_utilization, 20, "%u"); | ||
210 | |||
211 | DEBUGFS_FWSTATS_FILE(rxpipe, rx_prep_beacon_drop, 20, "%u"); | ||
212 | DEBUGFS_FWSTATS_FILE(rxpipe, descr_host_int_trig_rx_data, 20, "%u"); | ||
213 | DEBUGFS_FWSTATS_FILE(rxpipe, beacon_buffer_thres_host_int_trig_rx_data, | ||
214 | 20, "%u"); | ||
215 | DEBUGFS_FWSTATS_FILE(rxpipe, missed_beacon_host_int_trig_rx_data, 20, "%u"); | ||
216 | DEBUGFS_FWSTATS_FILE(rxpipe, tx_xfr_host_int_trig_rx_data, 20, "%u"); | ||
217 | |||
218 | DEBUGFS_READONLY_FILE(retry_count, 20, "%u", wl->stats.retry_count); | ||
219 | DEBUGFS_READONLY_FILE(excessive_retries, 20, "%u", | ||
220 | wl->stats.excessive_retries); | ||
221 | |||
222 | static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf, | ||
223 | size_t count, loff_t *ppos) | ||
224 | { | ||
225 | struct wl1251 *wl = file->private_data; | ||
226 | u32 queue_len; | ||
227 | char buf[20]; | ||
228 | int res; | ||
229 | |||
230 | queue_len = skb_queue_len(&wl->tx_queue); | ||
231 | |||
232 | res = scnprintf(buf, sizeof(buf), "%u\n", queue_len); | ||
233 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); | ||
234 | } | ||
235 | |||
236 | static const struct file_operations tx_queue_len_ops = { | ||
237 | .read = tx_queue_len_read, | ||
238 | .open = wl1251_open_file_generic, | ||
239 | .llseek = generic_file_llseek, | ||
240 | }; | ||
241 | |||
242 | static ssize_t tx_queue_status_read(struct file *file, char __user *userbuf, | ||
243 | size_t count, loff_t *ppos) | ||
244 | { | ||
245 | struct wl1251 *wl = file->private_data; | ||
246 | char buf[3], status; | ||
247 | int len; | ||
248 | |||
249 | if (wl->tx_queue_stopped) | ||
250 | status = 's'; | ||
251 | else | ||
252 | status = 'r'; | ||
253 | |||
254 | len = scnprintf(buf, sizeof(buf), "%c\n", status); | ||
255 | return simple_read_from_buffer(userbuf, count, ppos, buf, len); | ||
256 | } | ||
257 | |||
258 | static const struct file_operations tx_queue_status_ops = { | ||
259 | .read = tx_queue_status_read, | ||
260 | .open = wl1251_open_file_generic, | ||
261 | .llseek = generic_file_llseek, | ||
262 | }; | ||
263 | |||
264 | static void wl1251_debugfs_delete_files(struct wl1251 *wl) | ||
265 | { | ||
266 | DEBUGFS_FWSTATS_DEL(tx, internal_desc_overflow); | ||
267 | |||
268 | DEBUGFS_FWSTATS_DEL(rx, out_of_mem); | ||
269 | DEBUGFS_FWSTATS_DEL(rx, hdr_overflow); | ||
270 | DEBUGFS_FWSTATS_DEL(rx, hw_stuck); | ||
271 | DEBUGFS_FWSTATS_DEL(rx, dropped); | ||
272 | DEBUGFS_FWSTATS_DEL(rx, fcs_err); | ||
273 | DEBUGFS_FWSTATS_DEL(rx, xfr_hint_trig); | ||
274 | DEBUGFS_FWSTATS_DEL(rx, path_reset); | ||
275 | DEBUGFS_FWSTATS_DEL(rx, reset_counter); | ||
276 | |||
277 | DEBUGFS_FWSTATS_DEL(dma, rx_requested); | ||
278 | DEBUGFS_FWSTATS_DEL(dma, rx_errors); | ||
279 | DEBUGFS_FWSTATS_DEL(dma, tx_requested); | ||
280 | DEBUGFS_FWSTATS_DEL(dma, tx_errors); | ||
281 | |||
282 | DEBUGFS_FWSTATS_DEL(isr, cmd_cmplt); | ||
283 | DEBUGFS_FWSTATS_DEL(isr, fiqs); | ||
284 | DEBUGFS_FWSTATS_DEL(isr, rx_headers); | ||
285 | DEBUGFS_FWSTATS_DEL(isr, rx_mem_overflow); | ||
286 | DEBUGFS_FWSTATS_DEL(isr, rx_rdys); | ||
287 | DEBUGFS_FWSTATS_DEL(isr, irqs); | ||
288 | DEBUGFS_FWSTATS_DEL(isr, tx_procs); | ||
289 | DEBUGFS_FWSTATS_DEL(isr, decrypt_done); | ||
290 | DEBUGFS_FWSTATS_DEL(isr, dma0_done); | ||
291 | DEBUGFS_FWSTATS_DEL(isr, dma1_done); | ||
292 | DEBUGFS_FWSTATS_DEL(isr, tx_exch_complete); | ||
293 | DEBUGFS_FWSTATS_DEL(isr, commands); | ||
294 | DEBUGFS_FWSTATS_DEL(isr, rx_procs); | ||
295 | DEBUGFS_FWSTATS_DEL(isr, hw_pm_mode_changes); | ||
296 | DEBUGFS_FWSTATS_DEL(isr, host_acknowledges); | ||
297 | DEBUGFS_FWSTATS_DEL(isr, pci_pm); | ||
298 | DEBUGFS_FWSTATS_DEL(isr, wakeups); | ||
299 | DEBUGFS_FWSTATS_DEL(isr, low_rssi); | ||
300 | |||
301 | DEBUGFS_FWSTATS_DEL(wep, addr_key_count); | ||
302 | DEBUGFS_FWSTATS_DEL(wep, default_key_count); | ||
303 | /* skipping wep.reserved */ | ||
304 | DEBUGFS_FWSTATS_DEL(wep, key_not_found); | ||
305 | DEBUGFS_FWSTATS_DEL(wep, decrypt_fail); | ||
306 | DEBUGFS_FWSTATS_DEL(wep, packets); | ||
307 | DEBUGFS_FWSTATS_DEL(wep, interrupt); | ||
308 | |||
309 | DEBUGFS_FWSTATS_DEL(pwr, ps_enter); | ||
310 | DEBUGFS_FWSTATS_DEL(pwr, elp_enter); | ||
311 | DEBUGFS_FWSTATS_DEL(pwr, missing_bcns); | ||
312 | DEBUGFS_FWSTATS_DEL(pwr, wake_on_host); | ||
313 | DEBUGFS_FWSTATS_DEL(pwr, wake_on_timer_exp); | ||
314 | DEBUGFS_FWSTATS_DEL(pwr, tx_with_ps); | ||
315 | DEBUGFS_FWSTATS_DEL(pwr, tx_without_ps); | ||
316 | DEBUGFS_FWSTATS_DEL(pwr, rcvd_beacons); | ||
317 | DEBUGFS_FWSTATS_DEL(pwr, power_save_off); | ||
318 | DEBUGFS_FWSTATS_DEL(pwr, enable_ps); | ||
319 | DEBUGFS_FWSTATS_DEL(pwr, disable_ps); | ||
320 | DEBUGFS_FWSTATS_DEL(pwr, fix_tsf_ps); | ||
321 | /* skipping cont_miss_bcns_spread for now */ | ||
322 | DEBUGFS_FWSTATS_DEL(pwr, rcvd_awake_beacons); | ||
323 | |||
324 | DEBUGFS_FWSTATS_DEL(mic, rx_pkts); | ||
325 | DEBUGFS_FWSTATS_DEL(mic, calc_failure); | ||
326 | |||
327 | DEBUGFS_FWSTATS_DEL(aes, encrypt_fail); | ||
328 | DEBUGFS_FWSTATS_DEL(aes, decrypt_fail); | ||
329 | DEBUGFS_FWSTATS_DEL(aes, encrypt_packets); | ||
330 | DEBUGFS_FWSTATS_DEL(aes, decrypt_packets); | ||
331 | DEBUGFS_FWSTATS_DEL(aes, encrypt_interrupt); | ||
332 | DEBUGFS_FWSTATS_DEL(aes, decrypt_interrupt); | ||
333 | |||
334 | DEBUGFS_FWSTATS_DEL(event, heart_beat); | ||
335 | DEBUGFS_FWSTATS_DEL(event, calibration); | ||
336 | DEBUGFS_FWSTATS_DEL(event, rx_mismatch); | ||
337 | DEBUGFS_FWSTATS_DEL(event, rx_mem_empty); | ||
338 | DEBUGFS_FWSTATS_DEL(event, rx_pool); | ||
339 | DEBUGFS_FWSTATS_DEL(event, oom_late); | ||
340 | DEBUGFS_FWSTATS_DEL(event, phy_transmit_error); | ||
341 | DEBUGFS_FWSTATS_DEL(event, tx_stuck); | ||
342 | |||
343 | DEBUGFS_FWSTATS_DEL(ps, pspoll_timeouts); | ||
344 | DEBUGFS_FWSTATS_DEL(ps, upsd_timeouts); | ||
345 | DEBUGFS_FWSTATS_DEL(ps, upsd_max_sptime); | ||
346 | DEBUGFS_FWSTATS_DEL(ps, upsd_max_apturn); | ||
347 | DEBUGFS_FWSTATS_DEL(ps, pspoll_max_apturn); | ||
348 | DEBUGFS_FWSTATS_DEL(ps, pspoll_utilization); | ||
349 | DEBUGFS_FWSTATS_DEL(ps, upsd_utilization); | ||
350 | |||
351 | DEBUGFS_FWSTATS_DEL(rxpipe, rx_prep_beacon_drop); | ||
352 | DEBUGFS_FWSTATS_DEL(rxpipe, descr_host_int_trig_rx_data); | ||
353 | DEBUGFS_FWSTATS_DEL(rxpipe, beacon_buffer_thres_host_int_trig_rx_data); | ||
354 | DEBUGFS_FWSTATS_DEL(rxpipe, missed_beacon_host_int_trig_rx_data); | ||
355 | DEBUGFS_FWSTATS_DEL(rxpipe, tx_xfr_host_int_trig_rx_data); | ||
356 | |||
357 | DEBUGFS_DEL(tx_queue_len); | ||
358 | DEBUGFS_DEL(tx_queue_status); | ||
359 | DEBUGFS_DEL(retry_count); | ||
360 | DEBUGFS_DEL(excessive_retries); | ||
361 | } | ||
362 | |||
363 | static int wl1251_debugfs_add_files(struct wl1251 *wl) | ||
364 | { | ||
365 | int ret = 0; | ||
366 | |||
367 | DEBUGFS_FWSTATS_ADD(tx, internal_desc_overflow); | ||
368 | |||
369 | DEBUGFS_FWSTATS_ADD(rx, out_of_mem); | ||
370 | DEBUGFS_FWSTATS_ADD(rx, hdr_overflow); | ||
371 | DEBUGFS_FWSTATS_ADD(rx, hw_stuck); | ||
372 | DEBUGFS_FWSTATS_ADD(rx, dropped); | ||
373 | DEBUGFS_FWSTATS_ADD(rx, fcs_err); | ||
374 | DEBUGFS_FWSTATS_ADD(rx, xfr_hint_trig); | ||
375 | DEBUGFS_FWSTATS_ADD(rx, path_reset); | ||
376 | DEBUGFS_FWSTATS_ADD(rx, reset_counter); | ||
377 | |||
378 | DEBUGFS_FWSTATS_ADD(dma, rx_requested); | ||
379 | DEBUGFS_FWSTATS_ADD(dma, rx_errors); | ||
380 | DEBUGFS_FWSTATS_ADD(dma, tx_requested); | ||
381 | DEBUGFS_FWSTATS_ADD(dma, tx_errors); | ||
382 | |||
383 | DEBUGFS_FWSTATS_ADD(isr, cmd_cmplt); | ||
384 | DEBUGFS_FWSTATS_ADD(isr, fiqs); | ||
385 | DEBUGFS_FWSTATS_ADD(isr, rx_headers); | ||
386 | DEBUGFS_FWSTATS_ADD(isr, rx_mem_overflow); | ||
387 | DEBUGFS_FWSTATS_ADD(isr, rx_rdys); | ||
388 | DEBUGFS_FWSTATS_ADD(isr, irqs); | ||
389 | DEBUGFS_FWSTATS_ADD(isr, tx_procs); | ||
390 | DEBUGFS_FWSTATS_ADD(isr, decrypt_done); | ||
391 | DEBUGFS_FWSTATS_ADD(isr, dma0_done); | ||
392 | DEBUGFS_FWSTATS_ADD(isr, dma1_done); | ||
393 | DEBUGFS_FWSTATS_ADD(isr, tx_exch_complete); | ||
394 | DEBUGFS_FWSTATS_ADD(isr, commands); | ||
395 | DEBUGFS_FWSTATS_ADD(isr, rx_procs); | ||
396 | DEBUGFS_FWSTATS_ADD(isr, hw_pm_mode_changes); | ||
397 | DEBUGFS_FWSTATS_ADD(isr, host_acknowledges); | ||
398 | DEBUGFS_FWSTATS_ADD(isr, pci_pm); | ||
399 | DEBUGFS_FWSTATS_ADD(isr, wakeups); | ||
400 | DEBUGFS_FWSTATS_ADD(isr, low_rssi); | ||
401 | |||
402 | DEBUGFS_FWSTATS_ADD(wep, addr_key_count); | ||
403 | DEBUGFS_FWSTATS_ADD(wep, default_key_count); | ||
404 | /* skipping wep.reserved */ | ||
405 | DEBUGFS_FWSTATS_ADD(wep, key_not_found); | ||
406 | DEBUGFS_FWSTATS_ADD(wep, decrypt_fail); | ||
407 | DEBUGFS_FWSTATS_ADD(wep, packets); | ||
408 | DEBUGFS_FWSTATS_ADD(wep, interrupt); | ||
409 | |||
410 | DEBUGFS_FWSTATS_ADD(pwr, ps_enter); | ||
411 | DEBUGFS_FWSTATS_ADD(pwr, elp_enter); | ||
412 | DEBUGFS_FWSTATS_ADD(pwr, missing_bcns); | ||
413 | DEBUGFS_FWSTATS_ADD(pwr, wake_on_host); | ||
414 | DEBUGFS_FWSTATS_ADD(pwr, wake_on_timer_exp); | ||
415 | DEBUGFS_FWSTATS_ADD(pwr, tx_with_ps); | ||
416 | DEBUGFS_FWSTATS_ADD(pwr, tx_without_ps); | ||
417 | DEBUGFS_FWSTATS_ADD(pwr, rcvd_beacons); | ||
418 | DEBUGFS_FWSTATS_ADD(pwr, power_save_off); | ||
419 | DEBUGFS_FWSTATS_ADD(pwr, enable_ps); | ||
420 | DEBUGFS_FWSTATS_ADD(pwr, disable_ps); | ||
421 | DEBUGFS_FWSTATS_ADD(pwr, fix_tsf_ps); | ||
422 | /* skipping cont_miss_bcns_spread for now */ | ||
423 | DEBUGFS_FWSTATS_ADD(pwr, rcvd_awake_beacons); | ||
424 | |||
425 | DEBUGFS_FWSTATS_ADD(mic, rx_pkts); | ||
426 | DEBUGFS_FWSTATS_ADD(mic, calc_failure); | ||
427 | |||
428 | DEBUGFS_FWSTATS_ADD(aes, encrypt_fail); | ||
429 | DEBUGFS_FWSTATS_ADD(aes, decrypt_fail); | ||
430 | DEBUGFS_FWSTATS_ADD(aes, encrypt_packets); | ||
431 | DEBUGFS_FWSTATS_ADD(aes, decrypt_packets); | ||
432 | DEBUGFS_FWSTATS_ADD(aes, encrypt_interrupt); | ||
433 | DEBUGFS_FWSTATS_ADD(aes, decrypt_interrupt); | ||
434 | |||
435 | DEBUGFS_FWSTATS_ADD(event, heart_beat); | ||
436 | DEBUGFS_FWSTATS_ADD(event, calibration); | ||
437 | DEBUGFS_FWSTATS_ADD(event, rx_mismatch); | ||
438 | DEBUGFS_FWSTATS_ADD(event, rx_mem_empty); | ||
439 | DEBUGFS_FWSTATS_ADD(event, rx_pool); | ||
440 | DEBUGFS_FWSTATS_ADD(event, oom_late); | ||
441 | DEBUGFS_FWSTATS_ADD(event, phy_transmit_error); | ||
442 | DEBUGFS_FWSTATS_ADD(event, tx_stuck); | ||
443 | |||
444 | DEBUGFS_FWSTATS_ADD(ps, pspoll_timeouts); | ||
445 | DEBUGFS_FWSTATS_ADD(ps, upsd_timeouts); | ||
446 | DEBUGFS_FWSTATS_ADD(ps, upsd_max_sptime); | ||
447 | DEBUGFS_FWSTATS_ADD(ps, upsd_max_apturn); | ||
448 | DEBUGFS_FWSTATS_ADD(ps, pspoll_max_apturn); | ||
449 | DEBUGFS_FWSTATS_ADD(ps, pspoll_utilization); | ||
450 | DEBUGFS_FWSTATS_ADD(ps, upsd_utilization); | ||
451 | |||
452 | DEBUGFS_FWSTATS_ADD(rxpipe, rx_prep_beacon_drop); | ||
453 | DEBUGFS_FWSTATS_ADD(rxpipe, descr_host_int_trig_rx_data); | ||
454 | DEBUGFS_FWSTATS_ADD(rxpipe, beacon_buffer_thres_host_int_trig_rx_data); | ||
455 | DEBUGFS_FWSTATS_ADD(rxpipe, missed_beacon_host_int_trig_rx_data); | ||
456 | DEBUGFS_FWSTATS_ADD(rxpipe, tx_xfr_host_int_trig_rx_data); | ||
457 | |||
458 | DEBUGFS_ADD(tx_queue_len, wl->debugfs.rootdir); | ||
459 | DEBUGFS_ADD(tx_queue_status, wl->debugfs.rootdir); | ||
460 | DEBUGFS_ADD(retry_count, wl->debugfs.rootdir); | ||
461 | DEBUGFS_ADD(excessive_retries, wl->debugfs.rootdir); | ||
462 | |||
463 | out: | ||
464 | if (ret < 0) | ||
465 | wl1251_debugfs_delete_files(wl); | ||
466 | |||
467 | return ret; | ||
468 | } | ||
469 | |||
470 | void wl1251_debugfs_reset(struct wl1251 *wl) | ||
471 | { | ||
472 | if (wl->stats.fw_stats != NULL) | ||
473 | memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats)); | ||
474 | wl->stats.retry_count = 0; | ||
475 | wl->stats.excessive_retries = 0; | ||
476 | } | ||
477 | |||
478 | int wl1251_debugfs_init(struct wl1251 *wl) | ||
479 | { | ||
480 | int ret; | ||
481 | |||
482 | wl->debugfs.rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL); | ||
483 | |||
484 | if (IS_ERR(wl->debugfs.rootdir)) { | ||
485 | ret = PTR_ERR(wl->debugfs.rootdir); | ||
486 | wl->debugfs.rootdir = NULL; | ||
487 | goto err; | ||
488 | } | ||
489 | |||
490 | wl->debugfs.fw_statistics = debugfs_create_dir("fw-statistics", | ||
491 | wl->debugfs.rootdir); | ||
492 | |||
493 | if (IS_ERR(wl->debugfs.fw_statistics)) { | ||
494 | ret = PTR_ERR(wl->debugfs.fw_statistics); | ||
495 | wl->debugfs.fw_statistics = NULL; | ||
496 | goto err_root; | ||
497 | } | ||
498 | |||
499 | wl->stats.fw_stats = kzalloc(sizeof(*wl->stats.fw_stats), | ||
500 | GFP_KERNEL); | ||
501 | |||
502 | if (!wl->stats.fw_stats) { | ||
503 | ret = -ENOMEM; | ||
504 | goto err_fw; | ||
505 | } | ||
506 | |||
507 | wl->stats.fw_stats_update = jiffies; | ||
508 | |||
509 | ret = wl1251_debugfs_add_files(wl); | ||
510 | |||
511 | if (ret < 0) | ||
512 | goto err_file; | ||
513 | |||
514 | return 0; | ||
515 | |||
516 | err_file: | ||
517 | kfree(wl->stats.fw_stats); | ||
518 | wl->stats.fw_stats = NULL; | ||
519 | |||
520 | err_fw: | ||
521 | debugfs_remove(wl->debugfs.fw_statistics); | ||
522 | wl->debugfs.fw_statistics = NULL; | ||
523 | |||
524 | err_root: | ||
525 | debugfs_remove(wl->debugfs.rootdir); | ||
526 | wl->debugfs.rootdir = NULL; | ||
527 | |||
528 | err: | ||
529 | return ret; | ||
530 | } | ||
531 | |||
532 | void wl1251_debugfs_exit(struct wl1251 *wl) | ||
533 | { | ||
534 | wl1251_debugfs_delete_files(wl); | ||
535 | |||
536 | kfree(wl->stats.fw_stats); | ||
537 | wl->stats.fw_stats = NULL; | ||
538 | |||
539 | debugfs_remove(wl->debugfs.fw_statistics); | ||
540 | wl->debugfs.fw_statistics = NULL; | ||
541 | |||
542 | debugfs_remove(wl->debugfs.rootdir); | ||
543 | wl->debugfs.rootdir = NULL; | ||
544 | |||
545 | } | ||
diff --git a/drivers/net/wireless/ti/wl1251/debugfs.h b/drivers/net/wireless/ti/wl1251/debugfs.h new file mode 100644 index 000000000000..b3417c02a218 --- /dev/null +++ b/drivers/net/wireless/ti/wl1251/debugfs.h | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * This file is part of wl1251 | ||
3 | * | ||
4 | * Copyright (C) 2009 Nokia Corporation | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * version 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
18 | * 02110-1301 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifndef WL1251_DEBUGFS_H | ||
23 | #define WL1251_DEBUGFS_H | ||
24 | |||
25 | #include "wl1251.h" | ||
26 | |||
27 | int wl1251_debugfs_init(struct wl1251 *wl); | ||
28 | void wl1251_debugfs_exit(struct wl1251 *wl); | ||
29 | void wl1251_debugfs_reset(struct wl1251 *wl); | ||
30 | |||
31 | #endif /* WL1251_DEBUGFS_H */ | ||
diff --git a/drivers/net/wireless/ti/wl1251/event.c b/drivers/net/wireless/ti/wl1251/event.c new file mode 100644 index 000000000000..9f15ccaf8f05 --- /dev/null +++ b/drivers/net/wireless/ti/wl1251/event.c | |||
@@ -0,0 +1,188 @@ | |||
1 | /* | ||
2 | * This file is part of wl1251 | ||
3 | * | ||
4 | * Copyright (c) 1998-2007 Texas Instruments Incorporated | ||
5 | * Copyright (C) 2008 Nokia Corporation | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * version 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
19 | * 02110-1301 USA | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #include "wl1251.h" | ||
24 | #include "reg.h" | ||
25 | #include "io.h" | ||
26 | #include "event.h" | ||
27 | #include "ps.h" | ||
28 | |||
29 | static int wl1251_event_scan_complete(struct wl1251 *wl, | ||
30 | struct event_mailbox *mbox) | ||
31 | { | ||
32 | wl1251_debug(DEBUG_EVENT, "status: 0x%x, channels: %d", | ||
33 | mbox->scheduled_scan_status, | ||
34 | mbox->scheduled_scan_channels); | ||
35 | |||
36 | if (wl->scanning) { | ||
37 | ieee80211_scan_completed(wl->hw, false); | ||
38 | wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan completed"); | ||
39 | wl->scanning = false; | ||
40 | } | ||
41 | |||
42 | return 0; | ||
43 | } | ||
44 | |||
45 | static void wl1251_event_mbox_dump(struct event_mailbox *mbox) | ||
46 | { | ||
47 | wl1251_debug(DEBUG_EVENT, "MBOX DUMP:"); | ||
48 | wl1251_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector); | ||
49 | wl1251_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask); | ||
50 | } | ||
51 | |||
52 | static int wl1251_event_process(struct wl1251 *wl, struct event_mailbox *mbox) | ||
53 | { | ||
54 | int ret; | ||
55 | u32 vector; | ||
56 | |||
57 | wl1251_event_mbox_dump(mbox); | ||
58 | |||
59 | vector = mbox->events_vector & ~(mbox->events_mask); | ||
60 | wl1251_debug(DEBUG_EVENT, "vector: 0x%x", vector); | ||
61 | |||
62 | if (vector & SCAN_COMPLETE_EVENT_ID) { | ||
63 | ret = wl1251_event_scan_complete(wl, mbox); | ||
64 | if (ret < 0) | ||
65 | return ret; | ||
66 | } | ||
67 | |||
68 | if (vector & BSS_LOSE_EVENT_ID) { | ||
69 | wl1251_debug(DEBUG_EVENT, "BSS_LOSE_EVENT"); | ||
70 | |||
71 | if (wl->psm_requested && | ||
72 | wl->station_mode != STATION_ACTIVE_MODE) { | ||
73 | ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE); | ||
74 | if (ret < 0) | ||
75 | return ret; | ||
76 | } | ||
77 | } | ||
78 | |||
79 | if (vector & SYNCHRONIZATION_TIMEOUT_EVENT_ID && | ||
80 | wl->station_mode != STATION_ACTIVE_MODE) { | ||
81 | wl1251_debug(DEBUG_EVENT, "SYNCHRONIZATION_TIMEOUT_EVENT"); | ||
82 | |||
83 | /* indicate to the stack, that beacons have been lost */ | ||
84 | ieee80211_beacon_loss(wl->vif); | ||
85 | } | ||
86 | |||
87 | if (vector & REGAINED_BSS_EVENT_ID) { | ||
88 | if (wl->psm_requested) { | ||
89 | ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE); | ||
90 | if (ret < 0) | ||
91 | return ret; | ||
92 | } | ||
93 | } | ||
94 | |||
95 | if (wl->vif && wl->rssi_thold) { | ||
96 | if (vector & ROAMING_TRIGGER_LOW_RSSI_EVENT_ID) { | ||
97 | wl1251_debug(DEBUG_EVENT, | ||
98 | "ROAMING_TRIGGER_LOW_RSSI_EVENT"); | ||
99 | ieee80211_cqm_rssi_notify(wl->vif, | ||
100 | NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW, | ||
101 | GFP_KERNEL); | ||
102 | } | ||
103 | |||
104 | if (vector & ROAMING_TRIGGER_REGAINED_RSSI_EVENT_ID) { | ||
105 | wl1251_debug(DEBUG_EVENT, | ||
106 | "ROAMING_TRIGGER_REGAINED_RSSI_EVENT"); | ||
107 | ieee80211_cqm_rssi_notify(wl->vif, | ||
108 | NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH, | ||
109 | GFP_KERNEL); | ||
110 | } | ||
111 | } | ||
112 | |||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | /* | ||
117 | * Poll the mailbox event field until any of the bits in the mask is set or a | ||
118 | * timeout occurs (WL1251_EVENT_TIMEOUT in msecs) | ||
119 | */ | ||
120 | int wl1251_event_wait(struct wl1251 *wl, u32 mask, int timeout_ms) | ||
121 | { | ||
122 | u32 events_vector, event; | ||
123 | unsigned long timeout; | ||
124 | |||
125 | timeout = jiffies + msecs_to_jiffies(timeout_ms); | ||
126 | |||
127 | do { | ||
128 | if (time_after(jiffies, timeout)) | ||
129 | return -ETIMEDOUT; | ||
130 | |||
131 | msleep(1); | ||
132 | |||
133 | /* read from both event fields */ | ||
134 | wl1251_mem_read(wl, wl->mbox_ptr[0], &events_vector, | ||
135 | sizeof(events_vector)); | ||
136 | event = events_vector & mask; | ||
137 | wl1251_mem_read(wl, wl->mbox_ptr[1], &events_vector, | ||
138 | sizeof(events_vector)); | ||
139 | event |= events_vector & mask; | ||
140 | } while (!event); | ||
141 | |||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | int wl1251_event_unmask(struct wl1251 *wl) | ||
146 | { | ||
147 | int ret; | ||
148 | |||
149 | ret = wl1251_acx_event_mbox_mask(wl, ~(wl->event_mask)); | ||
150 | if (ret < 0) | ||
151 | return ret; | ||
152 | |||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | void wl1251_event_mbox_config(struct wl1251 *wl) | ||
157 | { | ||
158 | wl->mbox_ptr[0] = wl1251_reg_read32(wl, REG_EVENT_MAILBOX_PTR); | ||
159 | wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox); | ||
160 | |||
161 | wl1251_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x", | ||
162 | wl->mbox_ptr[0], wl->mbox_ptr[1]); | ||
163 | } | ||
164 | |||
165 | int wl1251_event_handle(struct wl1251 *wl, u8 mbox_num) | ||
166 | { | ||
167 | struct event_mailbox mbox; | ||
168 | int ret; | ||
169 | |||
170 | wl1251_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num); | ||
171 | |||
172 | if (mbox_num > 1) | ||
173 | return -EINVAL; | ||
174 | |||
175 | /* first we read the mbox descriptor */ | ||
176 | wl1251_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox, | ||
177 | sizeof(struct event_mailbox)); | ||
178 | |||
179 | /* process the descriptor */ | ||
180 | ret = wl1251_event_process(wl, &mbox); | ||
181 | if (ret < 0) | ||
182 | return ret; | ||
183 | |||
184 | /* then we let the firmware know it can go on...*/ | ||
185 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK); | ||
186 | |||
187 | return 0; | ||
188 | } | ||
diff --git a/drivers/net/wireless/ti/wl1251/event.h b/drivers/net/wireless/ti/wl1251/event.h new file mode 100644 index 000000000000..30eb5d150bf7 --- /dev/null +++ b/drivers/net/wireless/ti/wl1251/event.h | |||
@@ -0,0 +1,120 @@ | |||
1 | /* | ||
2 | * This file is part of wl1251 | ||
3 | * | ||
4 | * Copyright (c) 1998-2007 Texas Instruments Incorporated | ||
5 | * Copyright (C) 2008 Nokia Corporation | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * version 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
19 | * 02110-1301 USA | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #ifndef __WL1251_EVENT_H__ | ||
24 | #define __WL1251_EVENT_H__ | ||
25 | |||
26 | /* | ||
27 | * Mbox events | ||
28 | * | ||
29 | * The event mechanism is based on a pair of event buffers (buffers A and | ||
30 | * B) at fixed locations in the target's memory. The host processes one | ||
31 | * buffer while the other buffer continues to collect events. If the host | ||
32 | * is not processing events, an interrupt is issued to signal that a buffer | ||
33 | * is ready. Once the host is done with processing events from one buffer, | ||
34 | * it signals the target (with an ACK interrupt) that the event buffer is | ||
35 | * free. | ||
36 | */ | ||
37 | |||
38 | enum { | ||
39 | RESERVED1_EVENT_ID = BIT(0), | ||
40 | RESERVED2_EVENT_ID = BIT(1), | ||
41 | MEASUREMENT_START_EVENT_ID = BIT(2), | ||
42 | SCAN_COMPLETE_EVENT_ID = BIT(3), | ||
43 | CALIBRATION_COMPLETE_EVENT_ID = BIT(4), | ||
44 | ROAMING_TRIGGER_LOW_RSSI_EVENT_ID = BIT(5), | ||
45 | PS_REPORT_EVENT_ID = BIT(6), | ||
46 | SYNCHRONIZATION_TIMEOUT_EVENT_ID = BIT(7), | ||
47 | HEALTH_REPORT_EVENT_ID = BIT(8), | ||
48 | ACI_DETECTION_EVENT_ID = BIT(9), | ||
49 | DEBUG_REPORT_EVENT_ID = BIT(10), | ||
50 | MAC_STATUS_EVENT_ID = BIT(11), | ||
51 | DISCONNECT_EVENT_COMPLETE_ID = BIT(12), | ||
52 | JOIN_EVENT_COMPLETE_ID = BIT(13), | ||
53 | CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(14), | ||
54 | BSS_LOSE_EVENT_ID = BIT(15), | ||
55 | ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID = BIT(16), | ||
56 | MEASUREMENT_COMPLETE_EVENT_ID = BIT(17), | ||
57 | AP_DISCOVERY_COMPLETE_EVENT_ID = BIT(18), | ||
58 | SCHEDULED_SCAN_COMPLETE_EVENT_ID = BIT(19), | ||
59 | PSPOLL_DELIVERY_FAILURE_EVENT_ID = BIT(20), | ||
60 | RESET_BSS_EVENT_ID = BIT(21), | ||
61 | REGAINED_BSS_EVENT_ID = BIT(22), | ||
62 | ROAMING_TRIGGER_REGAINED_RSSI_EVENT_ID = BIT(23), | ||
63 | ROAMING_TRIGGER_LOW_SNR_EVENT_ID = BIT(24), | ||
64 | ROAMING_TRIGGER_REGAINED_SNR_EVENT_ID = BIT(25), | ||
65 | |||
66 | DBG_EVENT_ID = BIT(26), | ||
67 | BT_PTA_SENSE_EVENT_ID = BIT(27), | ||
68 | BT_PTA_PREDICTION_EVENT_ID = BIT(28), | ||
69 | BT_PTA_AVALANCHE_EVENT_ID = BIT(29), | ||
70 | |||
71 | PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(30), | ||
72 | |||
73 | EVENT_MBOX_ALL_EVENT_ID = 0x7fffffff, | ||
74 | }; | ||
75 | |||
76 | struct event_debug_report { | ||
77 | u8 debug_event_id; | ||
78 | u8 num_params; | ||
79 | u16 pad; | ||
80 | u32 report_1; | ||
81 | u32 report_2; | ||
82 | u32 report_3; | ||
83 | } __packed; | ||
84 | |||
85 | struct event_mailbox { | ||
86 | u32 events_vector; | ||
87 | u32 events_mask; | ||
88 | u32 reserved_1; | ||
89 | u32 reserved_2; | ||
90 | |||
91 | char average_rssi_level; | ||
92 | u8 ps_status; | ||
93 | u8 channel_switch_status; | ||
94 | u8 scheduled_scan_status; | ||
95 | |||
96 | /* Channels scanned by the scheduled scan */ | ||
97 | u16 scheduled_scan_channels; | ||
98 | |||
99 | /* If bit 0 is set -> target's fatal error */ | ||
100 | u16 health_report; | ||
101 | u16 bad_fft_counter; | ||
102 | u8 bt_pta_sense_info; | ||
103 | u8 bt_pta_protective_info; | ||
104 | u32 reserved; | ||
105 | u32 debug_report[2]; | ||
106 | |||
107 | /* Number of FCS errors since last event */ | ||
108 | u32 fcs_err_counter; | ||
109 | |||
110 | struct event_debug_report report; | ||
111 | u8 average_snr_level; | ||
112 | u8 padding[19]; | ||
113 | } __packed; | ||
114 | |||
115 | int wl1251_event_unmask(struct wl1251 *wl); | ||
116 | void wl1251_event_mbox_config(struct wl1251 *wl); | ||
117 | int wl1251_event_handle(struct wl1251 *wl, u8 mbox); | ||
118 | int wl1251_event_wait(struct wl1251 *wl, u32 mask, int timeout_ms); | ||
119 | |||
120 | #endif | ||
diff --git a/drivers/net/wireless/ti/wl1251/init.c b/drivers/net/wireless/ti/wl1251/init.c new file mode 100644 index 000000000000..89b43d35473c --- /dev/null +++ b/drivers/net/wireless/ti/wl1251/init.c | |||
@@ -0,0 +1,423 @@ | |||
1 | /* | ||
2 | * This file is part of wl1251 | ||
3 | * | ||
4 | * Copyright (C) 2009 Nokia Corporation | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * version 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
18 | * 02110-1301 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/slab.h> | ||
25 | |||
26 | #include "init.h" | ||
27 | #include "wl12xx_80211.h" | ||
28 | #include "acx.h" | ||
29 | #include "cmd.h" | ||
30 | #include "reg.h" | ||
31 | |||
32 | int wl1251_hw_init_hwenc_config(struct wl1251 *wl) | ||
33 | { | ||
34 | int ret; | ||
35 | |||
36 | ret = wl1251_acx_feature_cfg(wl); | ||
37 | if (ret < 0) { | ||
38 | wl1251_warning("couldn't set feature config"); | ||
39 | return ret; | ||
40 | } | ||
41 | |||
42 | ret = wl1251_acx_default_key(wl, wl->default_key); | ||
43 | if (ret < 0) { | ||
44 | wl1251_warning("couldn't set default key"); | ||
45 | return ret; | ||
46 | } | ||
47 | |||
48 | return 0; | ||
49 | } | ||
50 | |||
51 | int wl1251_hw_init_templates_config(struct wl1251 *wl) | ||
52 | { | ||
53 | int ret; | ||
54 | u8 partial_vbm[PARTIAL_VBM_MAX]; | ||
55 | |||
56 | /* send empty templates for fw memory reservation */ | ||
57 | ret = wl1251_cmd_template_set(wl, CMD_PROBE_REQ, NULL, | ||
58 | sizeof(struct wl12xx_probe_req_template)); | ||
59 | if (ret < 0) | ||
60 | return ret; | ||
61 | |||
62 | ret = wl1251_cmd_template_set(wl, CMD_NULL_DATA, NULL, | ||
63 | sizeof(struct wl12xx_null_data_template)); | ||
64 | if (ret < 0) | ||
65 | return ret; | ||
66 | |||
67 | ret = wl1251_cmd_template_set(wl, CMD_PS_POLL, NULL, | ||
68 | sizeof(struct wl12xx_ps_poll_template)); | ||
69 | if (ret < 0) | ||
70 | return ret; | ||
71 | |||
72 | ret = wl1251_cmd_template_set(wl, CMD_QOS_NULL_DATA, NULL, | ||
73 | sizeof | ||
74 | (struct wl12xx_qos_null_data_template)); | ||
75 | if (ret < 0) | ||
76 | return ret; | ||
77 | |||
78 | ret = wl1251_cmd_template_set(wl, CMD_PROBE_RESP, NULL, | ||
79 | sizeof | ||
80 | (struct wl12xx_probe_resp_template)); | ||
81 | if (ret < 0) | ||
82 | return ret; | ||
83 | |||
84 | ret = wl1251_cmd_template_set(wl, CMD_BEACON, NULL, | ||
85 | sizeof | ||
86 | (struct wl12xx_beacon_template)); | ||
87 | if (ret < 0) | ||
88 | return ret; | ||
89 | |||
90 | /* tim templates, first reserve space then allocate an empty one */ | ||
91 | memset(partial_vbm, 0, PARTIAL_VBM_MAX); | ||
92 | ret = wl1251_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, PARTIAL_VBM_MAX, 0); | ||
93 | if (ret < 0) | ||
94 | return ret; | ||
95 | |||
96 | ret = wl1251_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, 1, 0); | ||
97 | if (ret < 0) | ||
98 | return ret; | ||
99 | |||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | int wl1251_hw_init_rx_config(struct wl1251 *wl, u32 config, u32 filter) | ||
104 | { | ||
105 | int ret; | ||
106 | |||
107 | ret = wl1251_acx_rx_msdu_life_time(wl, RX_MSDU_LIFETIME_DEF); | ||
108 | if (ret < 0) | ||
109 | return ret; | ||
110 | |||
111 | ret = wl1251_acx_rx_config(wl, config, filter); | ||
112 | if (ret < 0) | ||
113 | return ret; | ||
114 | |||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | int wl1251_hw_init_phy_config(struct wl1251 *wl) | ||
119 | { | ||
120 | int ret; | ||
121 | |||
122 | ret = wl1251_acx_pd_threshold(wl); | ||
123 | if (ret < 0) | ||
124 | return ret; | ||
125 | |||
126 | ret = wl1251_acx_slot(wl, DEFAULT_SLOT_TIME); | ||
127 | if (ret < 0) | ||
128 | return ret; | ||
129 | |||
130 | ret = wl1251_acx_group_address_tbl(wl); | ||
131 | if (ret < 0) | ||
132 | return ret; | ||
133 | |||
134 | ret = wl1251_acx_service_period_timeout(wl); | ||
135 | if (ret < 0) | ||
136 | return ret; | ||
137 | |||
138 | ret = wl1251_acx_rts_threshold(wl, RTS_THRESHOLD_DEF); | ||
139 | if (ret < 0) | ||
140 | return ret; | ||
141 | |||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | int wl1251_hw_init_beacon_filter(struct wl1251 *wl) | ||
146 | { | ||
147 | int ret; | ||
148 | |||
149 | /* disable beacon filtering at this stage */ | ||
150 | ret = wl1251_acx_beacon_filter_opt(wl, false); | ||
151 | if (ret < 0) | ||
152 | return ret; | ||
153 | |||
154 | ret = wl1251_acx_beacon_filter_table(wl); | ||
155 | if (ret < 0) | ||
156 | return ret; | ||
157 | |||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | int wl1251_hw_init_pta(struct wl1251 *wl) | ||
162 | { | ||
163 | int ret; | ||
164 | |||
165 | ret = wl1251_acx_sg_enable(wl); | ||
166 | if (ret < 0) | ||
167 | return ret; | ||
168 | |||
169 | ret = wl1251_acx_sg_cfg(wl); | ||
170 | if (ret < 0) | ||
171 | return ret; | ||
172 | |||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | int wl1251_hw_init_energy_detection(struct wl1251 *wl) | ||
177 | { | ||
178 | int ret; | ||
179 | |||
180 | ret = wl1251_acx_cca_threshold(wl); | ||
181 | if (ret < 0) | ||
182 | return ret; | ||
183 | |||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | int wl1251_hw_init_beacon_broadcast(struct wl1251 *wl) | ||
188 | { | ||
189 | int ret; | ||
190 | |||
191 | ret = wl1251_acx_bcn_dtim_options(wl); | ||
192 | if (ret < 0) | ||
193 | return ret; | ||
194 | |||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | int wl1251_hw_init_power_auth(struct wl1251 *wl) | ||
199 | { | ||
200 | return wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM); | ||
201 | } | ||
202 | |||
203 | int wl1251_hw_init_mem_config(struct wl1251 *wl) | ||
204 | { | ||
205 | int ret; | ||
206 | |||
207 | ret = wl1251_acx_mem_cfg(wl); | ||
208 | if (ret < 0) | ||
209 | return ret; | ||
210 | |||
211 | wl->target_mem_map = kzalloc(sizeof(struct wl1251_acx_mem_map), | ||
212 | GFP_KERNEL); | ||
213 | if (!wl->target_mem_map) { | ||
214 | wl1251_error("couldn't allocate target memory map"); | ||
215 | return -ENOMEM; | ||
216 | } | ||
217 | |||
218 | /* we now ask for the firmware built memory map */ | ||
219 | ret = wl1251_acx_mem_map(wl, wl->target_mem_map, | ||
220 | sizeof(struct wl1251_acx_mem_map)); | ||
221 | if (ret < 0) { | ||
222 | wl1251_error("couldn't retrieve firmware memory map"); | ||
223 | kfree(wl->target_mem_map); | ||
224 | wl->target_mem_map = NULL; | ||
225 | return ret; | ||
226 | } | ||
227 | |||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | static int wl1251_hw_init_txq_fill(u8 qid, | ||
232 | struct acx_tx_queue_qos_config *config, | ||
233 | u32 num_blocks) | ||
234 | { | ||
235 | config->qid = qid; | ||
236 | |||
237 | switch (qid) { | ||
238 | case QOS_AC_BE: | ||
239 | config->high_threshold = | ||
240 | (QOS_TX_HIGH_BE_DEF * num_blocks) / 100; | ||
241 | config->low_threshold = | ||
242 | (QOS_TX_LOW_BE_DEF * num_blocks) / 100; | ||
243 | break; | ||
244 | case QOS_AC_BK: | ||
245 | config->high_threshold = | ||
246 | (QOS_TX_HIGH_BK_DEF * num_blocks) / 100; | ||
247 | config->low_threshold = | ||
248 | (QOS_TX_LOW_BK_DEF * num_blocks) / 100; | ||
249 | break; | ||
250 | case QOS_AC_VI: | ||
251 | config->high_threshold = | ||
252 | (QOS_TX_HIGH_VI_DEF * num_blocks) / 100; | ||
253 | config->low_threshold = | ||
254 | (QOS_TX_LOW_VI_DEF * num_blocks) / 100; | ||
255 | break; | ||
256 | case QOS_AC_VO: | ||
257 | config->high_threshold = | ||
258 | (QOS_TX_HIGH_VO_DEF * num_blocks) / 100; | ||
259 | config->low_threshold = | ||
260 | (QOS_TX_LOW_VO_DEF * num_blocks) / 100; | ||
261 | break; | ||
262 | default: | ||
263 | wl1251_error("Invalid TX queue id: %d", qid); | ||
264 | return -EINVAL; | ||
265 | } | ||
266 | |||
267 | return 0; | ||
268 | } | ||
269 | |||
270 | static int wl1251_hw_init_tx_queue_config(struct wl1251 *wl) | ||
271 | { | ||
272 | struct acx_tx_queue_qos_config *config; | ||
273 | struct wl1251_acx_mem_map *wl_mem_map = wl->target_mem_map; | ||
274 | int ret, i; | ||
275 | |||
276 | wl1251_debug(DEBUG_ACX, "acx tx queue config"); | ||
277 | |||
278 | config = kzalloc(sizeof(*config), GFP_KERNEL); | ||
279 | if (!config) { | ||
280 | ret = -ENOMEM; | ||
281 | goto out; | ||
282 | } | ||
283 | |||
284 | for (i = 0; i < MAX_NUM_OF_AC; i++) { | ||
285 | ret = wl1251_hw_init_txq_fill(i, config, | ||
286 | wl_mem_map->num_tx_mem_blocks); | ||
287 | if (ret < 0) | ||
288 | goto out; | ||
289 | |||
290 | ret = wl1251_cmd_configure(wl, ACX_TX_QUEUE_CFG, | ||
291 | config, sizeof(*config)); | ||
292 | if (ret < 0) | ||
293 | goto out; | ||
294 | } | ||
295 | |||
296 | wl1251_acx_ac_cfg(wl, AC_BE, CWMIN_BE, CWMAX_BE, AIFS_DIFS, TXOP_BE); | ||
297 | wl1251_acx_ac_cfg(wl, AC_BK, CWMIN_BK, CWMAX_BK, AIFS_DIFS, TXOP_BK); | ||
298 | wl1251_acx_ac_cfg(wl, AC_VI, CWMIN_VI, CWMAX_VI, AIFS_DIFS, TXOP_VI); | ||
299 | wl1251_acx_ac_cfg(wl, AC_VO, CWMIN_VO, CWMAX_VO, AIFS_DIFS, TXOP_VO); | ||
300 | |||
301 | out: | ||
302 | kfree(config); | ||
303 | return ret; | ||
304 | } | ||
305 | |||
306 | static int wl1251_hw_init_data_path_config(struct wl1251 *wl) | ||
307 | { | ||
308 | int ret; | ||
309 | |||
310 | /* asking for the data path parameters */ | ||
311 | wl->data_path = kzalloc(sizeof(struct acx_data_path_params_resp), | ||
312 | GFP_KERNEL); | ||
313 | if (!wl->data_path) { | ||
314 | wl1251_error("Couldnt allocate data path parameters"); | ||
315 | return -ENOMEM; | ||
316 | } | ||
317 | |||
318 | ret = wl1251_acx_data_path_params(wl, wl->data_path); | ||
319 | if (ret < 0) { | ||
320 | kfree(wl->data_path); | ||
321 | wl->data_path = NULL; | ||
322 | return ret; | ||
323 | } | ||
324 | |||
325 | return 0; | ||
326 | } | ||
327 | |||
328 | |||
329 | int wl1251_hw_init(struct wl1251 *wl) | ||
330 | { | ||
331 | struct wl1251_acx_mem_map *wl_mem_map; | ||
332 | int ret; | ||
333 | |||
334 | ret = wl1251_hw_init_hwenc_config(wl); | ||
335 | if (ret < 0) | ||
336 | return ret; | ||
337 | |||
338 | /* Template settings */ | ||
339 | ret = wl1251_hw_init_templates_config(wl); | ||
340 | if (ret < 0) | ||
341 | return ret; | ||
342 | |||
343 | /* Default memory configuration */ | ||
344 | ret = wl1251_hw_init_mem_config(wl); | ||
345 | if (ret < 0) | ||
346 | return ret; | ||
347 | |||
348 | /* Default data path configuration */ | ||
349 | ret = wl1251_hw_init_data_path_config(wl); | ||
350 | if (ret < 0) | ||
351 | goto out_free_memmap; | ||
352 | |||
353 | /* RX config */ | ||
354 | ret = wl1251_hw_init_rx_config(wl, | ||
355 | RX_CFG_PROMISCUOUS | RX_CFG_TSF, | ||
356 | RX_FILTER_OPTION_DEF); | ||
357 | /* RX_CONFIG_OPTION_ANY_DST_ANY_BSS, | ||
358 | RX_FILTER_OPTION_FILTER_ALL); */ | ||
359 | if (ret < 0) | ||
360 | goto out_free_data_path; | ||
361 | |||
362 | /* TX queues config */ | ||
363 | ret = wl1251_hw_init_tx_queue_config(wl); | ||
364 | if (ret < 0) | ||
365 | goto out_free_data_path; | ||
366 | |||
367 | /* PHY layer config */ | ||
368 | ret = wl1251_hw_init_phy_config(wl); | ||
369 | if (ret < 0) | ||
370 | goto out_free_data_path; | ||
371 | |||
372 | /* Initialize connection monitoring thresholds */ | ||
373 | ret = wl1251_acx_conn_monit_params(wl); | ||
374 | if (ret < 0) | ||
375 | goto out_free_data_path; | ||
376 | |||
377 | /* Beacon filtering */ | ||
378 | ret = wl1251_hw_init_beacon_filter(wl); | ||
379 | if (ret < 0) | ||
380 | goto out_free_data_path; | ||
381 | |||
382 | /* Bluetooth WLAN coexistence */ | ||
383 | ret = wl1251_hw_init_pta(wl); | ||
384 | if (ret < 0) | ||
385 | goto out_free_data_path; | ||
386 | |||
387 | /* Energy detection */ | ||
388 | ret = wl1251_hw_init_energy_detection(wl); | ||
389 | if (ret < 0) | ||
390 | goto out_free_data_path; | ||
391 | |||
392 | /* Beacons and boradcast settings */ | ||
393 | ret = wl1251_hw_init_beacon_broadcast(wl); | ||
394 | if (ret < 0) | ||
395 | goto out_free_data_path; | ||
396 | |||
397 | /* Enable data path */ | ||
398 | ret = wl1251_cmd_data_path(wl, wl->channel, 1); | ||
399 | if (ret < 0) | ||
400 | goto out_free_data_path; | ||
401 | |||
402 | /* Default power state */ | ||
403 | ret = wl1251_hw_init_power_auth(wl); | ||
404 | if (ret < 0) | ||
405 | goto out_free_data_path; | ||
406 | |||
407 | wl_mem_map = wl->target_mem_map; | ||
408 | wl1251_info("%d tx blocks at 0x%x, %d rx blocks at 0x%x", | ||
409 | wl_mem_map->num_tx_mem_blocks, | ||
410 | wl->data_path->tx_control_addr, | ||
411 | wl_mem_map->num_rx_mem_blocks, | ||
412 | wl->data_path->rx_control_addr); | ||
413 | |||
414 | return 0; | ||
415 | |||
416 | out_free_data_path: | ||
417 | kfree(wl->data_path); | ||
418 | |||
419 | out_free_memmap: | ||
420 | kfree(wl->target_mem_map); | ||
421 | |||
422 | return ret; | ||
423 | } | ||
diff --git a/drivers/net/wireless/ti/wl1251/init.h b/drivers/net/wireless/ti/wl1251/init.h new file mode 100644 index 000000000000..543f17582ead --- /dev/null +++ b/drivers/net/wireless/ti/wl1251/init.h | |||
@@ -0,0 +1,86 @@ | |||
1 | /* | ||
2 | * This file is part of wl1251 | ||
3 | * | ||
4 | * Copyright (C) 2009 Nokia Corporation | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * version 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
18 | * 02110-1301 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifndef __WL1251_INIT_H__ | ||
23 | #define __WL1251_INIT_H__ | ||
24 | |||
25 | #include "wl1251.h" | ||
26 | |||
27 | enum { | ||
28 | /* best effort/legacy */ | ||
29 | AC_BE = 0, | ||
30 | |||
31 | /* background */ | ||
32 | AC_BK = 1, | ||
33 | |||
34 | /* video */ | ||
35 | AC_VI = 2, | ||
36 | |||
37 | /* voice */ | ||
38 | AC_VO = 3, | ||
39 | |||
40 | /* broadcast dummy access category */ | ||
41 | AC_BCAST = 4, | ||
42 | |||
43 | NUM_ACCESS_CATEGORIES = 4 | ||
44 | }; | ||
45 | |||
46 | /* following are defult values for the IE fields*/ | ||
47 | #define CWMIN_BK 15 | ||
48 | #define CWMIN_BE 15 | ||
49 | #define CWMIN_VI 7 | ||
50 | #define CWMIN_VO 3 | ||
51 | #define CWMAX_BK 1023 | ||
52 | #define CWMAX_BE 63 | ||
53 | #define CWMAX_VI 15 | ||
54 | #define CWMAX_VO 7 | ||
55 | |||
56 | /* slot number setting to start transmission at PIFS interval */ | ||
57 | #define AIFS_PIFS 1 | ||
58 | |||
59 | /* | ||
60 | * slot number setting to start transmission at DIFS interval - normal DCF | ||
61 | * access | ||
62 | */ | ||
63 | #define AIFS_DIFS 2 | ||
64 | |||
65 | #define AIFSN_BK 7 | ||
66 | #define AIFSN_BE 3 | ||
67 | #define AIFSN_VI AIFS_PIFS | ||
68 | #define AIFSN_VO AIFS_PIFS | ||
69 | #define TXOP_BK 0 | ||
70 | #define TXOP_BE 0 | ||
71 | #define TXOP_VI 3008 | ||
72 | #define TXOP_VO 1504 | ||
73 | |||
74 | int wl1251_hw_init_hwenc_config(struct wl1251 *wl); | ||
75 | int wl1251_hw_init_templates_config(struct wl1251 *wl); | ||
76 | int wl1251_hw_init_rx_config(struct wl1251 *wl, u32 config, u32 filter); | ||
77 | int wl1251_hw_init_phy_config(struct wl1251 *wl); | ||
78 | int wl1251_hw_init_beacon_filter(struct wl1251 *wl); | ||
79 | int wl1251_hw_init_pta(struct wl1251 *wl); | ||
80 | int wl1251_hw_init_energy_detection(struct wl1251 *wl); | ||
81 | int wl1251_hw_init_beacon_broadcast(struct wl1251 *wl); | ||
82 | int wl1251_hw_init_power_auth(struct wl1251 *wl); | ||
83 | int wl1251_hw_init_mem_config(struct wl1251 *wl); | ||
84 | int wl1251_hw_init(struct wl1251 *wl); | ||
85 | |||
86 | #endif | ||
diff --git a/drivers/net/wireless/ti/wl1251/io.c b/drivers/net/wireless/ti/wl1251/io.c new file mode 100644 index 000000000000..cdcadbf6ac2c --- /dev/null +++ b/drivers/net/wireless/ti/wl1251/io.c | |||
@@ -0,0 +1,194 @@ | |||
1 | /* | ||
2 | * This file is part of wl12xx | ||
3 | * | ||
4 | * Copyright (C) 2008 Nokia Corporation | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * version 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
18 | * 02110-1301 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include "wl1251.h" | ||
23 | #include "reg.h" | ||
24 | #include "io.h" | ||
25 | |||
26 | /* FIXME: this is static data nowadays and the table can be removed */ | ||
27 | static enum wl12xx_acx_int_reg wl1251_io_reg_table[ACX_REG_TABLE_LEN] = { | ||
28 | [ACX_REG_INTERRUPT_TRIG] = (REGISTERS_BASE + 0x0474), | ||
29 | [ACX_REG_INTERRUPT_TRIG_H] = (REGISTERS_BASE + 0x0478), | ||
30 | [ACX_REG_INTERRUPT_MASK] = (REGISTERS_BASE + 0x0494), | ||
31 | [ACX_REG_HINT_MASK_SET] = (REGISTERS_BASE + 0x0498), | ||
32 | [ACX_REG_HINT_MASK_CLR] = (REGISTERS_BASE + 0x049C), | ||
33 | [ACX_REG_INTERRUPT_NO_CLEAR] = (REGISTERS_BASE + 0x04B0), | ||
34 | [ACX_REG_INTERRUPT_CLEAR] = (REGISTERS_BASE + 0x04A4), | ||
35 | [ACX_REG_INTERRUPT_ACK] = (REGISTERS_BASE + 0x04A8), | ||
36 | [ACX_REG_SLV_SOFT_RESET] = (REGISTERS_BASE + 0x0000), | ||
37 | [ACX_REG_EE_START] = (REGISTERS_BASE + 0x080C), | ||
38 | [ACX_REG_ECPU_CONTROL] = (REGISTERS_BASE + 0x0804) | ||
39 | }; | ||
40 | |||
41 | static int wl1251_translate_reg_addr(struct wl1251 *wl, int addr) | ||
42 | { | ||
43 | /* If the address is lower than REGISTERS_BASE, it means that this is | ||
44 | * a chip-specific register address, so look it up in the registers | ||
45 | * table */ | ||
46 | if (addr < REGISTERS_BASE) { | ||
47 | /* Make sure we don't go over the table */ | ||
48 | if (addr >= ACX_REG_TABLE_LEN) { | ||
49 | wl1251_error("address out of range (%d)", addr); | ||
50 | return -EINVAL; | ||
51 | } | ||
52 | addr = wl1251_io_reg_table[addr]; | ||
53 | } | ||
54 | |||
55 | return addr - wl->physical_reg_addr + wl->virtual_reg_addr; | ||
56 | } | ||
57 | |||
58 | static int wl1251_translate_mem_addr(struct wl1251 *wl, int addr) | ||
59 | { | ||
60 | return addr - wl->physical_mem_addr + wl->virtual_mem_addr; | ||
61 | } | ||
62 | |||
63 | void wl1251_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len) | ||
64 | { | ||
65 | int physical; | ||
66 | |||
67 | physical = wl1251_translate_mem_addr(wl, addr); | ||
68 | |||
69 | wl->if_ops->read(wl, physical, buf, len); | ||
70 | } | ||
71 | |||
72 | void wl1251_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len) | ||
73 | { | ||
74 | int physical; | ||
75 | |||
76 | physical = wl1251_translate_mem_addr(wl, addr); | ||
77 | |||
78 | wl->if_ops->write(wl, physical, buf, len); | ||
79 | } | ||
80 | |||
81 | u32 wl1251_mem_read32(struct wl1251 *wl, int addr) | ||
82 | { | ||
83 | return wl1251_read32(wl, wl1251_translate_mem_addr(wl, addr)); | ||
84 | } | ||
85 | |||
86 | void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val) | ||
87 | { | ||
88 | wl1251_write32(wl, wl1251_translate_mem_addr(wl, addr), val); | ||
89 | } | ||
90 | |||
91 | u32 wl1251_reg_read32(struct wl1251 *wl, int addr) | ||
92 | { | ||
93 | return wl1251_read32(wl, wl1251_translate_reg_addr(wl, addr)); | ||
94 | } | ||
95 | |||
96 | void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val) | ||
97 | { | ||
98 | wl1251_write32(wl, wl1251_translate_reg_addr(wl, addr), val); | ||
99 | } | ||
100 | |||
101 | /* Set the partitions to access the chip addresses. | ||
102 | * | ||
103 | * There are two VIRTUAL partitions (the memory partition and the | ||
104 | * registers partition), which are mapped to two different areas of the | ||
105 | * PHYSICAL (hardware) memory. This function also makes other checks to | ||
106 | * ensure that the partitions are not overlapping. In the diagram below, the | ||
107 | * memory partition comes before the register partition, but the opposite is | ||
108 | * also supported. | ||
109 | * | ||
110 | * PHYSICAL address | ||
111 | * space | ||
112 | * | ||
113 | * | | | ||
114 | * ...+----+--> mem_start | ||
115 | * VIRTUAL address ... | | | ||
116 | * space ... | | [PART_0] | ||
117 | * ... | | | ||
118 | * 0x00000000 <--+----+... ...+----+--> mem_start + mem_size | ||
119 | * | | ... | | | ||
120 | * |MEM | ... | | | ||
121 | * | | ... | | | ||
122 | * part_size <--+----+... | | {unused area) | ||
123 | * | | ... | | | ||
124 | * |REG | ... | | | ||
125 | * part_size | | ... | | | ||
126 | * + <--+----+... ...+----+--> reg_start | ||
127 | * reg_size ... | | | ||
128 | * ... | | [PART_1] | ||
129 | * ... | | | ||
130 | * ...+----+--> reg_start + reg_size | ||
131 | * | | | ||
132 | * | ||
133 | */ | ||
134 | void wl1251_set_partition(struct wl1251 *wl, | ||
135 | u32 mem_start, u32 mem_size, | ||
136 | u32 reg_start, u32 reg_size) | ||
137 | { | ||
138 | struct wl1251_partition partition[2]; | ||
139 | |||
140 | wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | ||
141 | mem_start, mem_size); | ||
142 | wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | ||
143 | reg_start, reg_size); | ||
144 | |||
145 | /* Make sure that the two partitions together don't exceed the | ||
146 | * address range */ | ||
147 | if ((mem_size + reg_size) > HW_ACCESS_MEMORY_MAX_RANGE) { | ||
148 | wl1251_debug(DEBUG_SPI, "Total size exceeds maximum virtual" | ||
149 | " address range. Truncating partition[0]."); | ||
150 | mem_size = HW_ACCESS_MEMORY_MAX_RANGE - reg_size; | ||
151 | wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | ||
152 | mem_start, mem_size); | ||
153 | wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | ||
154 | reg_start, reg_size); | ||
155 | } | ||
156 | |||
157 | if ((mem_start < reg_start) && | ||
158 | ((mem_start + mem_size) > reg_start)) { | ||
159 | /* Guarantee that the memory partition doesn't overlap the | ||
160 | * registers partition */ | ||
161 | wl1251_debug(DEBUG_SPI, "End of partition[0] is " | ||
162 | "overlapping partition[1]. Adjusted."); | ||
163 | mem_size = reg_start - mem_start; | ||
164 | wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | ||
165 | mem_start, mem_size); | ||
166 | wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | ||
167 | reg_start, reg_size); | ||
168 | } else if ((reg_start < mem_start) && | ||
169 | ((reg_start + reg_size) > mem_start)) { | ||
170 | /* Guarantee that the register partition doesn't overlap the | ||
171 | * memory partition */ | ||
172 | wl1251_debug(DEBUG_SPI, "End of partition[1] is" | ||
173 | " overlapping partition[0]. Adjusted."); | ||
174 | reg_size = mem_start - reg_start; | ||
175 | wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | ||
176 | mem_start, mem_size); | ||
177 | wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | ||
178 | reg_start, reg_size); | ||
179 | } | ||
180 | |||
181 | partition[0].start = mem_start; | ||
182 | partition[0].size = mem_size; | ||
183 | partition[1].start = reg_start; | ||
184 | partition[1].size = reg_size; | ||
185 | |||
186 | wl->physical_mem_addr = mem_start; | ||
187 | wl->physical_reg_addr = reg_start; | ||
188 | |||
189 | wl->virtual_mem_addr = 0; | ||
190 | wl->virtual_reg_addr = mem_size; | ||
191 | |||
192 | wl->if_ops->write(wl, HW_ACCESS_PART0_SIZE_ADDR, partition, | ||
193 | sizeof(partition)); | ||
194 | } | ||
diff --git a/drivers/net/wireless/ti/wl1251/io.h b/drivers/net/wireless/ti/wl1251/io.h new file mode 100644 index 000000000000..d382877c34cc --- /dev/null +++ b/drivers/net/wireless/ti/wl1251/io.h | |||
@@ -0,0 +1,83 @@ | |||
1 | /* | ||
2 | * This file is part of wl12xx | ||
3 | * | ||
4 | * Copyright (C) 2008 Nokia Corporation | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * version 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
18 | * 02110-1301 USA | ||
19 | * | ||
20 | */ | ||
21 | #ifndef __WL1251_IO_H__ | ||
22 | #define __WL1251_IO_H__ | ||
23 | |||
24 | #include "wl1251.h" | ||
25 | |||
26 | #define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0 | ||
27 | |||
28 | #define HW_ACCESS_PART0_SIZE_ADDR 0x1FFC0 | ||
29 | #define HW_ACCESS_PART0_START_ADDR 0x1FFC4 | ||
30 | #define HW_ACCESS_PART1_SIZE_ADDR 0x1FFC8 | ||
31 | #define HW_ACCESS_PART1_START_ADDR 0x1FFCC | ||
32 | |||
33 | #define HW_ACCESS_REGISTER_SIZE 4 | ||
34 | |||
35 | #define HW_ACCESS_PRAM_MAX_RANGE 0x3c000 | ||
36 | |||
37 | static inline u32 wl1251_read32(struct wl1251 *wl, int addr) | ||
38 | { | ||
39 | wl->if_ops->read(wl, addr, &wl->buffer_32, sizeof(wl->buffer_32)); | ||
40 | |||
41 | return le32_to_cpu(wl->buffer_32); | ||
42 | } | ||
43 | |||
44 | static inline void wl1251_write32(struct wl1251 *wl, int addr, u32 val) | ||
45 | { | ||
46 | wl->buffer_32 = cpu_to_le32(val); | ||
47 | wl->if_ops->write(wl, addr, &wl->buffer_32, sizeof(wl->buffer_32)); | ||
48 | } | ||
49 | |||
50 | static inline u32 wl1251_read_elp(struct wl1251 *wl, int addr) | ||
51 | { | ||
52 | u32 response; | ||
53 | |||
54 | if (wl->if_ops->read_elp) | ||
55 | wl->if_ops->read_elp(wl, addr, &response); | ||
56 | else | ||
57 | wl->if_ops->read(wl, addr, &response, sizeof(u32)); | ||
58 | |||
59 | return response; | ||
60 | } | ||
61 | |||
62 | static inline void wl1251_write_elp(struct wl1251 *wl, int addr, u32 val) | ||
63 | { | ||
64 | if (wl->if_ops->write_elp) | ||
65 | wl->if_ops->write_elp(wl, addr, val); | ||
66 | else | ||
67 | wl->if_ops->write(wl, addr, &val, sizeof(u32)); | ||
68 | } | ||
69 | |||
70 | /* Memory target IO, address is translated to partition 0 */ | ||
71 | void wl1251_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len); | ||
72 | void wl1251_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len); | ||
73 | u32 wl1251_mem_read32(struct wl1251 *wl, int addr); | ||
74 | void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val); | ||
75 | /* Registers IO */ | ||
76 | u32 wl1251_reg_read32(struct wl1251 *wl, int addr); | ||
77 | void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val); | ||
78 | |||
79 | void wl1251_set_partition(struct wl1251 *wl, | ||
80 | u32 part_start, u32 part_size, | ||
81 | u32 reg_start, u32 reg_size); | ||
82 | |||
83 | #endif | ||
diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c new file mode 100644 index 000000000000..41302c7b1ad0 --- /dev/null +++ b/drivers/net/wireless/ti/wl1251/main.c | |||
@@ -0,0 +1,1471 @@ | |||
1 | /* | ||
2 | * This file is part of wl1251 | ||
3 | * | ||
4 | * Copyright (C) 2008-2009 Nokia Corporation | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * version 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
18 | * 02110-1301 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/firmware.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/irq.h> | ||
27 | #include <linux/crc32.h> | ||
28 | #include <linux/etherdevice.h> | ||
29 | #include <linux/vmalloc.h> | ||
30 | #include <linux/slab.h> | ||
31 | |||
32 | #include "wl1251.h" | ||
33 | #include "wl12xx_80211.h" | ||
34 | #include "reg.h" | ||
35 | #include "io.h" | ||
36 | #include "cmd.h" | ||
37 | #include "event.h" | ||
38 | #include "tx.h" | ||
39 | #include "rx.h" | ||
40 | #include "ps.h" | ||
41 | #include "init.h" | ||
42 | #include "debugfs.h" | ||
43 | #include "boot.h" | ||
44 | |||
45 | void wl1251_enable_interrupts(struct wl1251 *wl) | ||
46 | { | ||
47 | wl->if_ops->enable_irq(wl); | ||
48 | } | ||
49 | |||
50 | void wl1251_disable_interrupts(struct wl1251 *wl) | ||
51 | { | ||
52 | wl->if_ops->disable_irq(wl); | ||
53 | } | ||
54 | |||
55 | static int wl1251_power_off(struct wl1251 *wl) | ||
56 | { | ||
57 | return wl->if_ops->power(wl, false); | ||
58 | } | ||
59 | |||
60 | static int wl1251_power_on(struct wl1251 *wl) | ||
61 | { | ||
62 | return wl->if_ops->power(wl, true); | ||
63 | } | ||
64 | |||
65 | static int wl1251_fetch_firmware(struct wl1251 *wl) | ||
66 | { | ||
67 | const struct firmware *fw; | ||
68 | struct device *dev = wiphy_dev(wl->hw->wiphy); | ||
69 | int ret; | ||
70 | |||
71 | ret = request_firmware(&fw, WL1251_FW_NAME, dev); | ||
72 | |||
73 | if (ret < 0) { | ||
74 | wl1251_error("could not get firmware: %d", ret); | ||
75 | return ret; | ||
76 | } | ||
77 | |||
78 | if (fw->size % 4) { | ||
79 | wl1251_error("firmware size is not multiple of 32 bits: %zu", | ||
80 | fw->size); | ||
81 | ret = -EILSEQ; | ||
82 | goto out; | ||
83 | } | ||
84 | |||
85 | wl->fw_len = fw->size; | ||
86 | wl->fw = vmalloc(wl->fw_len); | ||
87 | |||
88 | if (!wl->fw) { | ||
89 | wl1251_error("could not allocate memory for the firmware"); | ||
90 | ret = -ENOMEM; | ||
91 | goto out; | ||
92 | } | ||
93 | |||
94 | memcpy(wl->fw, fw->data, wl->fw_len); | ||
95 | |||
96 | ret = 0; | ||
97 | |||
98 | out: | ||
99 | release_firmware(fw); | ||
100 | |||
101 | return ret; | ||
102 | } | ||
103 | |||
104 | static int wl1251_fetch_nvs(struct wl1251 *wl) | ||
105 | { | ||
106 | const struct firmware *fw; | ||
107 | struct device *dev = wiphy_dev(wl->hw->wiphy); | ||
108 | int ret; | ||
109 | |||
110 | ret = request_firmware(&fw, WL1251_NVS_NAME, dev); | ||
111 | |||
112 | if (ret < 0) { | ||
113 | wl1251_error("could not get nvs file: %d", ret); | ||
114 | return ret; | ||
115 | } | ||
116 | |||
117 | if (fw->size % 4) { | ||
118 | wl1251_error("nvs size is not multiple of 32 bits: %zu", | ||
119 | fw->size); | ||
120 | ret = -EILSEQ; | ||
121 | goto out; | ||
122 | } | ||
123 | |||
124 | wl->nvs_len = fw->size; | ||
125 | wl->nvs = kmemdup(fw->data, wl->nvs_len, GFP_KERNEL); | ||
126 | |||
127 | if (!wl->nvs) { | ||
128 | wl1251_error("could not allocate memory for the nvs file"); | ||
129 | ret = -ENOMEM; | ||
130 | goto out; | ||
131 | } | ||
132 | |||
133 | ret = 0; | ||
134 | |||
135 | out: | ||
136 | release_firmware(fw); | ||
137 | |||
138 | return ret; | ||
139 | } | ||
140 | |||
141 | static void wl1251_fw_wakeup(struct wl1251 *wl) | ||
142 | { | ||
143 | u32 elp_reg; | ||
144 | |||
145 | elp_reg = ELPCTRL_WAKE_UP; | ||
146 | wl1251_write_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg); | ||
147 | elp_reg = wl1251_read_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); | ||
148 | |||
149 | if (!(elp_reg & ELPCTRL_WLAN_READY)) | ||
150 | wl1251_warning("WLAN not ready"); | ||
151 | } | ||
152 | |||
153 | static int wl1251_chip_wakeup(struct wl1251 *wl) | ||
154 | { | ||
155 | int ret; | ||
156 | |||
157 | ret = wl1251_power_on(wl); | ||
158 | if (ret < 0) | ||
159 | return ret; | ||
160 | |||
161 | msleep(WL1251_POWER_ON_SLEEP); | ||
162 | wl->if_ops->reset(wl); | ||
163 | |||
164 | /* We don't need a real memory partition here, because we only want | ||
165 | * to use the registers at this point. */ | ||
166 | wl1251_set_partition(wl, | ||
167 | 0x00000000, | ||
168 | 0x00000000, | ||
169 | REGISTERS_BASE, | ||
170 | REGISTERS_DOWN_SIZE); | ||
171 | |||
172 | /* ELP module wake up */ | ||
173 | wl1251_fw_wakeup(wl); | ||
174 | |||
175 | /* whal_FwCtrl_BootSm() */ | ||
176 | |||
177 | /* 0. read chip id from CHIP_ID */ | ||
178 | wl->chip_id = wl1251_reg_read32(wl, CHIP_ID_B); | ||
179 | |||
180 | /* 1. check if chip id is valid */ | ||
181 | |||
182 | switch (wl->chip_id) { | ||
183 | case CHIP_ID_1251_PG12: | ||
184 | wl1251_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG12)", | ||
185 | wl->chip_id); | ||
186 | break; | ||
187 | case CHIP_ID_1251_PG11: | ||
188 | wl1251_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG11)", | ||
189 | wl->chip_id); | ||
190 | break; | ||
191 | case CHIP_ID_1251_PG10: | ||
192 | default: | ||
193 | wl1251_error("unsupported chip id: 0x%x", wl->chip_id); | ||
194 | ret = -ENODEV; | ||
195 | goto out; | ||
196 | } | ||
197 | |||
198 | if (wl->fw == NULL) { | ||
199 | ret = wl1251_fetch_firmware(wl); | ||
200 | if (ret < 0) | ||
201 | goto out; | ||
202 | } | ||
203 | |||
204 | if (wl->nvs == NULL && !wl->use_eeprom) { | ||
205 | /* No NVS from netlink, try to get it from the filesystem */ | ||
206 | ret = wl1251_fetch_nvs(wl); | ||
207 | if (ret < 0) | ||
208 | goto out; | ||
209 | } | ||
210 | |||
211 | out: | ||
212 | return ret; | ||
213 | } | ||
214 | |||
215 | #define WL1251_IRQ_LOOP_COUNT 10 | ||
216 | static void wl1251_irq_work(struct work_struct *work) | ||
217 | { | ||
218 | u32 intr, ctr = WL1251_IRQ_LOOP_COUNT; | ||
219 | struct wl1251 *wl = | ||
220 | container_of(work, struct wl1251, irq_work); | ||
221 | int ret; | ||
222 | |||
223 | mutex_lock(&wl->mutex); | ||
224 | |||
225 | wl1251_debug(DEBUG_IRQ, "IRQ work"); | ||
226 | |||
227 | if (wl->state == WL1251_STATE_OFF) | ||
228 | goto out; | ||
229 | |||
230 | ret = wl1251_ps_elp_wakeup(wl); | ||
231 | if (ret < 0) | ||
232 | goto out; | ||
233 | |||
234 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1251_ACX_INTR_ALL); | ||
235 | |||
236 | intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); | ||
237 | wl1251_debug(DEBUG_IRQ, "intr: 0x%x", intr); | ||
238 | |||
239 | do { | ||
240 | if (wl->data_path) { | ||
241 | wl->rx_counter = wl1251_mem_read32( | ||
242 | wl, wl->data_path->rx_control_addr); | ||
243 | |||
244 | /* We handle a frmware bug here */ | ||
245 | switch ((wl->rx_counter - wl->rx_handled) & 0xf) { | ||
246 | case 0: | ||
247 | wl1251_debug(DEBUG_IRQ, | ||
248 | "RX: FW and host in sync"); | ||
249 | intr &= ~WL1251_ACX_INTR_RX0_DATA; | ||
250 | intr &= ~WL1251_ACX_INTR_RX1_DATA; | ||
251 | break; | ||
252 | case 1: | ||
253 | wl1251_debug(DEBUG_IRQ, "RX: FW +1"); | ||
254 | intr |= WL1251_ACX_INTR_RX0_DATA; | ||
255 | intr &= ~WL1251_ACX_INTR_RX1_DATA; | ||
256 | break; | ||
257 | case 2: | ||
258 | wl1251_debug(DEBUG_IRQ, "RX: FW +2"); | ||
259 | intr |= WL1251_ACX_INTR_RX0_DATA; | ||
260 | intr |= WL1251_ACX_INTR_RX1_DATA; | ||
261 | break; | ||
262 | default: | ||
263 | wl1251_warning( | ||
264 | "RX: FW and host out of sync: %d", | ||
265 | wl->rx_counter - wl->rx_handled); | ||
266 | break; | ||
267 | } | ||
268 | |||
269 | wl->rx_handled = wl->rx_counter; | ||
270 | |||
271 | wl1251_debug(DEBUG_IRQ, "RX counter: %d", | ||
272 | wl->rx_counter); | ||
273 | } | ||
274 | |||
275 | intr &= wl->intr_mask; | ||
276 | |||
277 | if (intr == 0) { | ||
278 | wl1251_debug(DEBUG_IRQ, "INTR is 0"); | ||
279 | goto out_sleep; | ||
280 | } | ||
281 | |||
282 | if (intr & WL1251_ACX_INTR_RX0_DATA) { | ||
283 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA"); | ||
284 | wl1251_rx(wl); | ||
285 | } | ||
286 | |||
287 | if (intr & WL1251_ACX_INTR_RX1_DATA) { | ||
288 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA"); | ||
289 | wl1251_rx(wl); | ||
290 | } | ||
291 | |||
292 | if (intr & WL1251_ACX_INTR_TX_RESULT) { | ||
293 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT"); | ||
294 | wl1251_tx_complete(wl); | ||
295 | } | ||
296 | |||
297 | if (intr & WL1251_ACX_INTR_EVENT_A) { | ||
298 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT_A"); | ||
299 | wl1251_event_handle(wl, 0); | ||
300 | } | ||
301 | |||
302 | if (intr & WL1251_ACX_INTR_EVENT_B) { | ||
303 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT_B"); | ||
304 | wl1251_event_handle(wl, 1); | ||
305 | } | ||
306 | |||
307 | if (intr & WL1251_ACX_INTR_INIT_COMPLETE) | ||
308 | wl1251_debug(DEBUG_IRQ, | ||
309 | "WL1251_ACX_INTR_INIT_COMPLETE"); | ||
310 | |||
311 | if (--ctr == 0) | ||
312 | break; | ||
313 | |||
314 | intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); | ||
315 | } while (intr); | ||
316 | |||
317 | out_sleep: | ||
318 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); | ||
319 | wl1251_ps_elp_sleep(wl); | ||
320 | |||
321 | out: | ||
322 | mutex_unlock(&wl->mutex); | ||
323 | } | ||
324 | |||
325 | static int wl1251_join(struct wl1251 *wl, u8 bss_type, u8 channel, | ||
326 | u16 beacon_interval, u8 dtim_period) | ||
327 | { | ||
328 | int ret; | ||
329 | |||
330 | ret = wl1251_acx_frame_rates(wl, DEFAULT_HW_GEN_TX_RATE, | ||
331 | DEFAULT_HW_GEN_MODULATION_TYPE, | ||
332 | wl->tx_mgmt_frm_rate, | ||
333 | wl->tx_mgmt_frm_mod); | ||
334 | if (ret < 0) | ||
335 | goto out; | ||
336 | |||
337 | |||
338 | ret = wl1251_cmd_join(wl, bss_type, channel, beacon_interval, | ||
339 | dtim_period); | ||
340 | if (ret < 0) | ||
341 | goto out; | ||
342 | |||
343 | ret = wl1251_event_wait(wl, JOIN_EVENT_COMPLETE_ID, 100); | ||
344 | if (ret < 0) | ||
345 | wl1251_warning("join timeout"); | ||
346 | |||
347 | out: | ||
348 | return ret; | ||
349 | } | ||
350 | |||
351 | static void wl1251_filter_work(struct work_struct *work) | ||
352 | { | ||
353 | struct wl1251 *wl = | ||
354 | container_of(work, struct wl1251, filter_work); | ||
355 | int ret; | ||
356 | |||
357 | mutex_lock(&wl->mutex); | ||
358 | |||
359 | if (wl->state == WL1251_STATE_OFF) | ||
360 | goto out; | ||
361 | |||
362 | ret = wl1251_ps_elp_wakeup(wl); | ||
363 | if (ret < 0) | ||
364 | goto out; | ||
365 | |||
366 | ret = wl1251_join(wl, wl->bss_type, wl->channel, wl->beacon_int, | ||
367 | wl->dtim_period); | ||
368 | if (ret < 0) | ||
369 | goto out_sleep; | ||
370 | |||
371 | out_sleep: | ||
372 | wl1251_ps_elp_sleep(wl); | ||
373 | |||
374 | out: | ||
375 | mutex_unlock(&wl->mutex); | ||
376 | } | ||
377 | |||
378 | static void wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | ||
379 | { | ||
380 | struct wl1251 *wl = hw->priv; | ||
381 | unsigned long flags; | ||
382 | |||
383 | skb_queue_tail(&wl->tx_queue, skb); | ||
384 | |||
385 | /* | ||
386 | * The chip specific setup must run before the first TX packet - | ||
387 | * before that, the tx_work will not be initialized! | ||
388 | */ | ||
389 | |||
390 | ieee80211_queue_work(wl->hw, &wl->tx_work); | ||
391 | |||
392 | /* | ||
393 | * The workqueue is slow to process the tx_queue and we need stop | ||
394 | * the queue here, otherwise the queue will get too long. | ||
395 | */ | ||
396 | if (skb_queue_len(&wl->tx_queue) >= WL1251_TX_QUEUE_HIGH_WATERMARK) { | ||
397 | wl1251_debug(DEBUG_TX, "op_tx: tx_queue full, stop queues"); | ||
398 | |||
399 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
400 | ieee80211_stop_queues(wl->hw); | ||
401 | wl->tx_queue_stopped = true; | ||
402 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
403 | } | ||
404 | } | ||
405 | |||
406 | static int wl1251_op_start(struct ieee80211_hw *hw) | ||
407 | { | ||
408 | struct wl1251 *wl = hw->priv; | ||
409 | struct wiphy *wiphy = hw->wiphy; | ||
410 | int ret = 0; | ||
411 | |||
412 | wl1251_debug(DEBUG_MAC80211, "mac80211 start"); | ||
413 | |||
414 | mutex_lock(&wl->mutex); | ||
415 | |||
416 | if (wl->state != WL1251_STATE_OFF) { | ||
417 | wl1251_error("cannot start because not in off state: %d", | ||
418 | wl->state); | ||
419 | ret = -EBUSY; | ||
420 | goto out; | ||
421 | } | ||
422 | |||
423 | ret = wl1251_chip_wakeup(wl); | ||
424 | if (ret < 0) | ||
425 | goto out; | ||
426 | |||
427 | ret = wl1251_boot(wl); | ||
428 | if (ret < 0) | ||
429 | goto out; | ||
430 | |||
431 | ret = wl1251_hw_init(wl); | ||
432 | if (ret < 0) | ||
433 | goto out; | ||
434 | |||
435 | ret = wl1251_acx_station_id(wl); | ||
436 | if (ret < 0) | ||
437 | goto out; | ||
438 | |||
439 | wl->state = WL1251_STATE_ON; | ||
440 | |||
441 | wl1251_info("firmware booted (%s)", wl->fw_ver); | ||
442 | |||
443 | /* update hw/fw version info in wiphy struct */ | ||
444 | wiphy->hw_version = wl->chip_id; | ||
445 | strncpy(wiphy->fw_version, wl->fw_ver, sizeof(wiphy->fw_version)); | ||
446 | |||
447 | out: | ||
448 | if (ret < 0) | ||
449 | wl1251_power_off(wl); | ||
450 | |||
451 | mutex_unlock(&wl->mutex); | ||
452 | |||
453 | return ret; | ||
454 | } | ||
455 | |||
456 | static void wl1251_op_stop(struct ieee80211_hw *hw) | ||
457 | { | ||
458 | struct wl1251 *wl = hw->priv; | ||
459 | |||
460 | wl1251_info("down"); | ||
461 | |||
462 | wl1251_debug(DEBUG_MAC80211, "mac80211 stop"); | ||
463 | |||
464 | mutex_lock(&wl->mutex); | ||
465 | |||
466 | WARN_ON(wl->state != WL1251_STATE_ON); | ||
467 | |||
468 | if (wl->scanning) { | ||
469 | ieee80211_scan_completed(wl->hw, true); | ||
470 | wl->scanning = false; | ||
471 | } | ||
472 | |||
473 | wl->state = WL1251_STATE_OFF; | ||
474 | |||
475 | wl1251_disable_interrupts(wl); | ||
476 | |||
477 | mutex_unlock(&wl->mutex); | ||
478 | |||
479 | cancel_work_sync(&wl->irq_work); | ||
480 | cancel_work_sync(&wl->tx_work); | ||
481 | cancel_work_sync(&wl->filter_work); | ||
482 | |||
483 | mutex_lock(&wl->mutex); | ||
484 | |||
485 | /* let's notify MAC80211 about the remaining pending TX frames */ | ||
486 | wl1251_tx_flush(wl); | ||
487 | wl1251_power_off(wl); | ||
488 | |||
489 | memset(wl->bssid, 0, ETH_ALEN); | ||
490 | wl->listen_int = 1; | ||
491 | wl->bss_type = MAX_BSS_TYPE; | ||
492 | |||
493 | wl->data_in_count = 0; | ||
494 | wl->rx_counter = 0; | ||
495 | wl->rx_handled = 0; | ||
496 | wl->rx_current_buffer = 0; | ||
497 | wl->rx_last_id = 0; | ||
498 | wl->next_tx_complete = 0; | ||
499 | wl->elp = false; | ||
500 | wl->station_mode = STATION_ACTIVE_MODE; | ||
501 | wl->tx_queue_stopped = false; | ||
502 | wl->power_level = WL1251_DEFAULT_POWER_LEVEL; | ||
503 | wl->rssi_thold = 0; | ||
504 | wl->channel = WL1251_DEFAULT_CHANNEL; | ||
505 | |||
506 | wl1251_debugfs_reset(wl); | ||
507 | |||
508 | mutex_unlock(&wl->mutex); | ||
509 | } | ||
510 | |||
511 | static int wl1251_op_add_interface(struct ieee80211_hw *hw, | ||
512 | struct ieee80211_vif *vif) | ||
513 | { | ||
514 | struct wl1251 *wl = hw->priv; | ||
515 | int ret = 0; | ||
516 | |||
517 | vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | | ||
518 | IEEE80211_VIF_SUPPORTS_CQM_RSSI; | ||
519 | |||
520 | wl1251_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", | ||
521 | vif->type, vif->addr); | ||
522 | |||
523 | mutex_lock(&wl->mutex); | ||
524 | if (wl->vif) { | ||
525 | ret = -EBUSY; | ||
526 | goto out; | ||
527 | } | ||
528 | |||
529 | wl->vif = vif; | ||
530 | |||
531 | switch (vif->type) { | ||
532 | case NL80211_IFTYPE_STATION: | ||
533 | wl->bss_type = BSS_TYPE_STA_BSS; | ||
534 | break; | ||
535 | case NL80211_IFTYPE_ADHOC: | ||
536 | wl->bss_type = BSS_TYPE_IBSS; | ||
537 | break; | ||
538 | default: | ||
539 | ret = -EOPNOTSUPP; | ||
540 | goto out; | ||
541 | } | ||
542 | |||
543 | if (memcmp(wl->mac_addr, vif->addr, ETH_ALEN)) { | ||
544 | memcpy(wl->mac_addr, vif->addr, ETH_ALEN); | ||
545 | SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); | ||
546 | ret = wl1251_acx_station_id(wl); | ||
547 | if (ret < 0) | ||
548 | goto out; | ||
549 | } | ||
550 | |||
551 | out: | ||
552 | mutex_unlock(&wl->mutex); | ||
553 | return ret; | ||
554 | } | ||
555 | |||
556 | static void wl1251_op_remove_interface(struct ieee80211_hw *hw, | ||
557 | struct ieee80211_vif *vif) | ||
558 | { | ||
559 | struct wl1251 *wl = hw->priv; | ||
560 | |||
561 | mutex_lock(&wl->mutex); | ||
562 | wl1251_debug(DEBUG_MAC80211, "mac80211 remove interface"); | ||
563 | wl->vif = NULL; | ||
564 | mutex_unlock(&wl->mutex); | ||
565 | } | ||
566 | |||
567 | static int wl1251_build_qos_null_data(struct wl1251 *wl) | ||
568 | { | ||
569 | struct ieee80211_qos_hdr template; | ||
570 | |||
571 | memset(&template, 0, sizeof(template)); | ||
572 | |||
573 | memcpy(template.addr1, wl->bssid, ETH_ALEN); | ||
574 | memcpy(template.addr2, wl->mac_addr, ETH_ALEN); | ||
575 | memcpy(template.addr3, wl->bssid, ETH_ALEN); | ||
576 | |||
577 | template.frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | | ||
578 | IEEE80211_STYPE_QOS_NULLFUNC | | ||
579 | IEEE80211_FCTL_TODS); | ||
580 | |||
581 | /* FIXME: not sure what priority to use here */ | ||
582 | template.qos_ctrl = cpu_to_le16(0); | ||
583 | |||
584 | return wl1251_cmd_template_set(wl, CMD_QOS_NULL_DATA, &template, | ||
585 | sizeof(template)); | ||
586 | } | ||
587 | |||
588 | static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) | ||
589 | { | ||
590 | struct wl1251 *wl = hw->priv; | ||
591 | struct ieee80211_conf *conf = &hw->conf; | ||
592 | int channel, ret = 0; | ||
593 | |||
594 | channel = ieee80211_frequency_to_channel(conf->channel->center_freq); | ||
595 | |||
596 | wl1251_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d", | ||
597 | channel, | ||
598 | conf->flags & IEEE80211_CONF_PS ? "on" : "off", | ||
599 | conf->power_level); | ||
600 | |||
601 | mutex_lock(&wl->mutex); | ||
602 | |||
603 | ret = wl1251_ps_elp_wakeup(wl); | ||
604 | if (ret < 0) | ||
605 | goto out; | ||
606 | |||
607 | if (channel != wl->channel) { | ||
608 | wl->channel = channel; | ||
609 | |||
610 | ret = wl1251_join(wl, wl->bss_type, wl->channel, | ||
611 | wl->beacon_int, wl->dtim_period); | ||
612 | if (ret < 0) | ||
613 | goto out_sleep; | ||
614 | } | ||
615 | |||
616 | if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) { | ||
617 | wl1251_debug(DEBUG_PSM, "psm enabled"); | ||
618 | |||
619 | wl->psm_requested = true; | ||
620 | |||
621 | wl->dtim_period = conf->ps_dtim_period; | ||
622 | |||
623 | ret = wl1251_acx_wr_tbtt_and_dtim(wl, wl->beacon_int, | ||
624 | wl->dtim_period); | ||
625 | |||
626 | /* | ||
627 | * mac80211 enables PSM only if we're already associated. | ||
628 | */ | ||
629 | ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE); | ||
630 | if (ret < 0) | ||
631 | goto out_sleep; | ||
632 | } else if (!(conf->flags & IEEE80211_CONF_PS) && | ||
633 | wl->psm_requested) { | ||
634 | wl1251_debug(DEBUG_PSM, "psm disabled"); | ||
635 | |||
636 | wl->psm_requested = false; | ||
637 | |||
638 | if (wl->station_mode != STATION_ACTIVE_MODE) { | ||
639 | ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE); | ||
640 | if (ret < 0) | ||
641 | goto out_sleep; | ||
642 | } | ||
643 | } | ||
644 | |||
645 | if (changed & IEEE80211_CONF_CHANGE_IDLE) { | ||
646 | if (conf->flags & IEEE80211_CONF_IDLE) { | ||
647 | ret = wl1251_ps_set_mode(wl, STATION_IDLE); | ||
648 | if (ret < 0) | ||
649 | goto out_sleep; | ||
650 | } else { | ||
651 | ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE); | ||
652 | if (ret < 0) | ||
653 | goto out_sleep; | ||
654 | ret = wl1251_join(wl, wl->bss_type, wl->channel, | ||
655 | wl->beacon_int, wl->dtim_period); | ||
656 | if (ret < 0) | ||
657 | goto out_sleep; | ||
658 | } | ||
659 | } | ||
660 | |||
661 | if (conf->power_level != wl->power_level) { | ||
662 | ret = wl1251_acx_tx_power(wl, conf->power_level); | ||
663 | if (ret < 0) | ||
664 | goto out_sleep; | ||
665 | |||
666 | wl->power_level = conf->power_level; | ||
667 | } | ||
668 | |||
669 | out_sleep: | ||
670 | wl1251_ps_elp_sleep(wl); | ||
671 | |||
672 | out: | ||
673 | mutex_unlock(&wl->mutex); | ||
674 | |||
675 | return ret; | ||
676 | } | ||
677 | |||
678 | #define WL1251_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \ | ||
679 | FIF_ALLMULTI | \ | ||
680 | FIF_FCSFAIL | \ | ||
681 | FIF_BCN_PRBRESP_PROMISC | \ | ||
682 | FIF_CONTROL | \ | ||
683 | FIF_OTHER_BSS) | ||
684 | |||
685 | static void wl1251_op_configure_filter(struct ieee80211_hw *hw, | ||
686 | unsigned int changed, | ||
687 | unsigned int *total,u64 multicast) | ||
688 | { | ||
689 | struct wl1251 *wl = hw->priv; | ||
690 | |||
691 | wl1251_debug(DEBUG_MAC80211, "mac80211 configure filter"); | ||
692 | |||
693 | *total &= WL1251_SUPPORTED_FILTERS; | ||
694 | changed &= WL1251_SUPPORTED_FILTERS; | ||
695 | |||
696 | if (changed == 0) | ||
697 | /* no filters which we support changed */ | ||
698 | return; | ||
699 | |||
700 | /* FIXME: wl->rx_config and wl->rx_filter are not protected */ | ||
701 | |||
702 | wl->rx_config = WL1251_DEFAULT_RX_CONFIG; | ||
703 | wl->rx_filter = WL1251_DEFAULT_RX_FILTER; | ||
704 | |||
705 | if (*total & FIF_PROMISC_IN_BSS) { | ||
706 | wl->rx_config |= CFG_BSSID_FILTER_EN; | ||
707 | wl->rx_config |= CFG_RX_ALL_GOOD; | ||
708 | } | ||
709 | if (*total & FIF_ALLMULTI) | ||
710 | /* | ||
711 | * CFG_MC_FILTER_EN in rx_config needs to be 0 to receive | ||
712 | * all multicast frames | ||
713 | */ | ||
714 | wl->rx_config &= ~CFG_MC_FILTER_EN; | ||
715 | if (*total & FIF_FCSFAIL) | ||
716 | wl->rx_filter |= CFG_RX_FCS_ERROR; | ||
717 | if (*total & FIF_BCN_PRBRESP_PROMISC) { | ||
718 | wl->rx_config &= ~CFG_BSSID_FILTER_EN; | ||
719 | wl->rx_config &= ~CFG_SSID_FILTER_EN; | ||
720 | } | ||
721 | if (*total & FIF_CONTROL) | ||
722 | wl->rx_filter |= CFG_RX_CTL_EN; | ||
723 | if (*total & FIF_OTHER_BSS) | ||
724 | wl->rx_filter &= ~CFG_BSSID_FILTER_EN; | ||
725 | |||
726 | /* | ||
727 | * FIXME: workqueues need to be properly cancelled on stop(), for | ||
728 | * now let's just disable changing the filter settings. They will | ||
729 | * be updated any on config(). | ||
730 | */ | ||
731 | /* schedule_work(&wl->filter_work); */ | ||
732 | } | ||
733 | |||
734 | /* HW encryption */ | ||
735 | static int wl1251_set_key_type(struct wl1251 *wl, | ||
736 | struct wl1251_cmd_set_keys *key, | ||
737 | enum set_key_cmd cmd, | ||
738 | struct ieee80211_key_conf *mac80211_key, | ||
739 | const u8 *addr) | ||
740 | { | ||
741 | switch (mac80211_key->cipher) { | ||
742 | case WLAN_CIPHER_SUITE_WEP40: | ||
743 | case WLAN_CIPHER_SUITE_WEP104: | ||
744 | if (is_broadcast_ether_addr(addr)) | ||
745 | key->key_type = KEY_WEP_DEFAULT; | ||
746 | else | ||
747 | key->key_type = KEY_WEP_ADDR; | ||
748 | |||
749 | mac80211_key->hw_key_idx = mac80211_key->keyidx; | ||
750 | break; | ||
751 | case WLAN_CIPHER_SUITE_TKIP: | ||
752 | if (is_broadcast_ether_addr(addr)) | ||
753 | key->key_type = KEY_TKIP_MIC_GROUP; | ||
754 | else | ||
755 | key->key_type = KEY_TKIP_MIC_PAIRWISE; | ||
756 | |||
757 | mac80211_key->hw_key_idx = mac80211_key->keyidx; | ||
758 | break; | ||
759 | case WLAN_CIPHER_SUITE_CCMP: | ||
760 | if (is_broadcast_ether_addr(addr)) | ||
761 | key->key_type = KEY_AES_GROUP; | ||
762 | else | ||
763 | key->key_type = KEY_AES_PAIRWISE; | ||
764 | mac80211_key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; | ||
765 | break; | ||
766 | default: | ||
767 | wl1251_error("Unknown key cipher 0x%x", mac80211_key->cipher); | ||
768 | return -EOPNOTSUPP; | ||
769 | } | ||
770 | |||
771 | return 0; | ||
772 | } | ||
773 | |||
774 | static int wl1251_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | ||
775 | struct ieee80211_vif *vif, | ||
776 | struct ieee80211_sta *sta, | ||
777 | struct ieee80211_key_conf *key) | ||
778 | { | ||
779 | struct wl1251 *wl = hw->priv; | ||
780 | struct wl1251_cmd_set_keys *wl_cmd; | ||
781 | const u8 *addr; | ||
782 | int ret; | ||
783 | |||
784 | static const u8 bcast_addr[ETH_ALEN] = | ||
785 | { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; | ||
786 | |||
787 | wl1251_debug(DEBUG_MAC80211, "mac80211 set key"); | ||
788 | |||
789 | wl_cmd = kzalloc(sizeof(*wl_cmd), GFP_KERNEL); | ||
790 | if (!wl_cmd) { | ||
791 | ret = -ENOMEM; | ||
792 | goto out; | ||
793 | } | ||
794 | |||
795 | addr = sta ? sta->addr : bcast_addr; | ||
796 | |||
797 | wl1251_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd); | ||
798 | wl1251_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN); | ||
799 | wl1251_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x", | ||
800 | key->cipher, key->keyidx, key->keylen, key->flags); | ||
801 | wl1251_dump(DEBUG_CRYPT, "KEY: ", key->key, key->keylen); | ||
802 | |||
803 | if (is_zero_ether_addr(addr)) { | ||
804 | /* We dont support TX only encryption */ | ||
805 | ret = -EOPNOTSUPP; | ||
806 | goto out; | ||
807 | } | ||
808 | |||
809 | mutex_lock(&wl->mutex); | ||
810 | |||
811 | ret = wl1251_ps_elp_wakeup(wl); | ||
812 | if (ret < 0) | ||
813 | goto out_unlock; | ||
814 | |||
815 | switch (cmd) { | ||
816 | case SET_KEY: | ||
817 | wl_cmd->key_action = KEY_ADD_OR_REPLACE; | ||
818 | break; | ||
819 | case DISABLE_KEY: | ||
820 | wl_cmd->key_action = KEY_REMOVE; | ||
821 | break; | ||
822 | default: | ||
823 | wl1251_error("Unsupported key cmd 0x%x", cmd); | ||
824 | break; | ||
825 | } | ||
826 | |||
827 | ret = wl1251_set_key_type(wl, wl_cmd, cmd, key, addr); | ||
828 | if (ret < 0) { | ||
829 | wl1251_error("Set KEY type failed"); | ||
830 | goto out_sleep; | ||
831 | } | ||
832 | |||
833 | if (wl_cmd->key_type != KEY_WEP_DEFAULT) | ||
834 | memcpy(wl_cmd->addr, addr, ETH_ALEN); | ||
835 | |||
836 | if ((wl_cmd->key_type == KEY_TKIP_MIC_GROUP) || | ||
837 | (wl_cmd->key_type == KEY_TKIP_MIC_PAIRWISE)) { | ||
838 | /* | ||
839 | * We get the key in the following form: | ||
840 | * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes) | ||
841 | * but the target is expecting: | ||
842 | * TKIP - RX MIC - TX MIC | ||
843 | */ | ||
844 | memcpy(wl_cmd->key, key->key, 16); | ||
845 | memcpy(wl_cmd->key + 16, key->key + 24, 8); | ||
846 | memcpy(wl_cmd->key + 24, key->key + 16, 8); | ||
847 | |||
848 | } else { | ||
849 | memcpy(wl_cmd->key, key->key, key->keylen); | ||
850 | } | ||
851 | wl_cmd->key_size = key->keylen; | ||
852 | |||
853 | wl_cmd->id = key->keyidx; | ||
854 | wl_cmd->ssid_profile = 0; | ||
855 | |||
856 | wl1251_dump(DEBUG_CRYPT, "TARGET KEY: ", wl_cmd, sizeof(*wl_cmd)); | ||
857 | |||
858 | ret = wl1251_cmd_send(wl, CMD_SET_KEYS, wl_cmd, sizeof(*wl_cmd)); | ||
859 | if (ret < 0) { | ||
860 | wl1251_warning("could not set keys"); | ||
861 | goto out_sleep; | ||
862 | } | ||
863 | |||
864 | out_sleep: | ||
865 | wl1251_ps_elp_sleep(wl); | ||
866 | |||
867 | out_unlock: | ||
868 | mutex_unlock(&wl->mutex); | ||
869 | |||
870 | out: | ||
871 | kfree(wl_cmd); | ||
872 | |||
873 | return ret; | ||
874 | } | ||
875 | |||
876 | static int wl1251_op_hw_scan(struct ieee80211_hw *hw, | ||
877 | struct ieee80211_vif *vif, | ||
878 | struct cfg80211_scan_request *req) | ||
879 | { | ||
880 | struct wl1251 *wl = hw->priv; | ||
881 | struct sk_buff *skb; | ||
882 | size_t ssid_len = 0; | ||
883 | u8 *ssid = NULL; | ||
884 | int ret; | ||
885 | |||
886 | wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan"); | ||
887 | |||
888 | if (req->n_ssids) { | ||
889 | ssid = req->ssids[0].ssid; | ||
890 | ssid_len = req->ssids[0].ssid_len; | ||
891 | } | ||
892 | |||
893 | mutex_lock(&wl->mutex); | ||
894 | |||
895 | if (wl->scanning) { | ||
896 | wl1251_debug(DEBUG_SCAN, "scan already in progress"); | ||
897 | ret = -EINVAL; | ||
898 | goto out; | ||
899 | } | ||
900 | |||
901 | ret = wl1251_ps_elp_wakeup(wl); | ||
902 | if (ret < 0) | ||
903 | goto out; | ||
904 | |||
905 | skb = ieee80211_probereq_get(wl->hw, wl->vif, ssid, ssid_len, | ||
906 | req->ie, req->ie_len); | ||
907 | if (!skb) { | ||
908 | ret = -ENOMEM; | ||
909 | goto out; | ||
910 | } | ||
911 | |||
912 | ret = wl1251_cmd_template_set(wl, CMD_PROBE_REQ, skb->data, | ||
913 | skb->len); | ||
914 | dev_kfree_skb(skb); | ||
915 | if (ret < 0) | ||
916 | goto out_sleep; | ||
917 | |||
918 | ret = wl1251_cmd_trigger_scan_to(wl, 0); | ||
919 | if (ret < 0) | ||
920 | goto out_sleep; | ||
921 | |||
922 | wl->scanning = true; | ||
923 | |||
924 | ret = wl1251_cmd_scan(wl, ssid, ssid_len, req->channels, | ||
925 | req->n_channels, WL1251_SCAN_NUM_PROBES); | ||
926 | if (ret < 0) { | ||
927 | wl->scanning = false; | ||
928 | goto out_sleep; | ||
929 | } | ||
930 | |||
931 | out_sleep: | ||
932 | wl1251_ps_elp_sleep(wl); | ||
933 | |||
934 | out: | ||
935 | mutex_unlock(&wl->mutex); | ||
936 | |||
937 | return ret; | ||
938 | } | ||
939 | |||
940 | static int wl1251_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) | ||
941 | { | ||
942 | struct wl1251 *wl = hw->priv; | ||
943 | int ret; | ||
944 | |||
945 | mutex_lock(&wl->mutex); | ||
946 | |||
947 | ret = wl1251_ps_elp_wakeup(wl); | ||
948 | if (ret < 0) | ||
949 | goto out; | ||
950 | |||
951 | ret = wl1251_acx_rts_threshold(wl, (u16) value); | ||
952 | if (ret < 0) | ||
953 | wl1251_warning("wl1251_op_set_rts_threshold failed: %d", ret); | ||
954 | |||
955 | wl1251_ps_elp_sleep(wl); | ||
956 | |||
957 | out: | ||
958 | mutex_unlock(&wl->mutex); | ||
959 | |||
960 | return ret; | ||
961 | } | ||
962 | |||
963 | static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, | ||
964 | struct ieee80211_vif *vif, | ||
965 | struct ieee80211_bss_conf *bss_conf, | ||
966 | u32 changed) | ||
967 | { | ||
968 | struct wl1251 *wl = hw->priv; | ||
969 | struct sk_buff *beacon, *skb; | ||
970 | int ret; | ||
971 | |||
972 | wl1251_debug(DEBUG_MAC80211, "mac80211 bss info changed"); | ||
973 | |||
974 | mutex_lock(&wl->mutex); | ||
975 | |||
976 | ret = wl1251_ps_elp_wakeup(wl); | ||
977 | if (ret < 0) | ||
978 | goto out; | ||
979 | |||
980 | if (changed & BSS_CHANGED_CQM) { | ||
981 | ret = wl1251_acx_low_rssi(wl, bss_conf->cqm_rssi_thold, | ||
982 | WL1251_DEFAULT_LOW_RSSI_WEIGHT, | ||
983 | WL1251_DEFAULT_LOW_RSSI_DEPTH, | ||
984 | WL1251_ACX_LOW_RSSI_TYPE_EDGE); | ||
985 | if (ret < 0) | ||
986 | goto out; | ||
987 | wl->rssi_thold = bss_conf->cqm_rssi_thold; | ||
988 | } | ||
989 | |||
990 | if (changed & BSS_CHANGED_BSSID) { | ||
991 | memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN); | ||
992 | |||
993 | skb = ieee80211_nullfunc_get(wl->hw, wl->vif); | ||
994 | if (!skb) | ||
995 | goto out_sleep; | ||
996 | |||
997 | ret = wl1251_cmd_template_set(wl, CMD_NULL_DATA, | ||
998 | skb->data, skb->len); | ||
999 | dev_kfree_skb(skb); | ||
1000 | if (ret < 0) | ||
1001 | goto out_sleep; | ||
1002 | |||
1003 | ret = wl1251_build_qos_null_data(wl); | ||
1004 | if (ret < 0) | ||
1005 | goto out; | ||
1006 | |||
1007 | if (wl->bss_type != BSS_TYPE_IBSS) { | ||
1008 | ret = wl1251_join(wl, wl->bss_type, wl->channel, | ||
1009 | wl->beacon_int, wl->dtim_period); | ||
1010 | if (ret < 0) | ||
1011 | goto out_sleep; | ||
1012 | } | ||
1013 | } | ||
1014 | |||
1015 | if (changed & BSS_CHANGED_ASSOC) { | ||
1016 | if (bss_conf->assoc) { | ||
1017 | wl->beacon_int = bss_conf->beacon_int; | ||
1018 | |||
1019 | skb = ieee80211_pspoll_get(wl->hw, wl->vif); | ||
1020 | if (!skb) | ||
1021 | goto out_sleep; | ||
1022 | |||
1023 | ret = wl1251_cmd_template_set(wl, CMD_PS_POLL, | ||
1024 | skb->data, | ||
1025 | skb->len); | ||
1026 | dev_kfree_skb(skb); | ||
1027 | if (ret < 0) | ||
1028 | goto out_sleep; | ||
1029 | |||
1030 | ret = wl1251_acx_aid(wl, bss_conf->aid); | ||
1031 | if (ret < 0) | ||
1032 | goto out_sleep; | ||
1033 | } else { | ||
1034 | /* use defaults when not associated */ | ||
1035 | wl->beacon_int = WL1251_DEFAULT_BEACON_INT; | ||
1036 | wl->dtim_period = WL1251_DEFAULT_DTIM_PERIOD; | ||
1037 | } | ||
1038 | } | ||
1039 | if (changed & BSS_CHANGED_ERP_SLOT) { | ||
1040 | if (bss_conf->use_short_slot) | ||
1041 | ret = wl1251_acx_slot(wl, SLOT_TIME_SHORT); | ||
1042 | else | ||
1043 | ret = wl1251_acx_slot(wl, SLOT_TIME_LONG); | ||
1044 | if (ret < 0) { | ||
1045 | wl1251_warning("Set slot time failed %d", ret); | ||
1046 | goto out_sleep; | ||
1047 | } | ||
1048 | } | ||
1049 | |||
1050 | if (changed & BSS_CHANGED_ERP_PREAMBLE) { | ||
1051 | if (bss_conf->use_short_preamble) | ||
1052 | wl1251_acx_set_preamble(wl, ACX_PREAMBLE_SHORT); | ||
1053 | else | ||
1054 | wl1251_acx_set_preamble(wl, ACX_PREAMBLE_LONG); | ||
1055 | } | ||
1056 | |||
1057 | if (changed & BSS_CHANGED_ERP_CTS_PROT) { | ||
1058 | if (bss_conf->use_cts_prot) | ||
1059 | ret = wl1251_acx_cts_protect(wl, CTSPROTECT_ENABLE); | ||
1060 | else | ||
1061 | ret = wl1251_acx_cts_protect(wl, CTSPROTECT_DISABLE); | ||
1062 | if (ret < 0) { | ||
1063 | wl1251_warning("Set ctsprotect failed %d", ret); | ||
1064 | goto out_sleep; | ||
1065 | } | ||
1066 | } | ||
1067 | |||
1068 | if (changed & BSS_CHANGED_BEACON) { | ||
1069 | beacon = ieee80211_beacon_get(hw, vif); | ||
1070 | if (!beacon) | ||
1071 | goto out_sleep; | ||
1072 | |||
1073 | ret = wl1251_cmd_template_set(wl, CMD_BEACON, beacon->data, | ||
1074 | beacon->len); | ||
1075 | |||
1076 | if (ret < 0) { | ||
1077 | dev_kfree_skb(beacon); | ||
1078 | goto out_sleep; | ||
1079 | } | ||
1080 | |||
1081 | ret = wl1251_cmd_template_set(wl, CMD_PROBE_RESP, beacon->data, | ||
1082 | beacon->len); | ||
1083 | |||
1084 | dev_kfree_skb(beacon); | ||
1085 | |||
1086 | if (ret < 0) | ||
1087 | goto out_sleep; | ||
1088 | |||
1089 | ret = wl1251_join(wl, wl->bss_type, wl->beacon_int, | ||
1090 | wl->channel, wl->dtim_period); | ||
1091 | |||
1092 | if (ret < 0) | ||
1093 | goto out_sleep; | ||
1094 | } | ||
1095 | |||
1096 | out_sleep: | ||
1097 | wl1251_ps_elp_sleep(wl); | ||
1098 | |||
1099 | out: | ||
1100 | mutex_unlock(&wl->mutex); | ||
1101 | } | ||
1102 | |||
1103 | |||
1104 | /* can't be const, mac80211 writes to this */ | ||
1105 | static struct ieee80211_rate wl1251_rates[] = { | ||
1106 | { .bitrate = 10, | ||
1107 | .hw_value = 0x1, | ||
1108 | .hw_value_short = 0x1, }, | ||
1109 | { .bitrate = 20, | ||
1110 | .hw_value = 0x2, | ||
1111 | .hw_value_short = 0x2, | ||
1112 | .flags = IEEE80211_RATE_SHORT_PREAMBLE }, | ||
1113 | { .bitrate = 55, | ||
1114 | .hw_value = 0x4, | ||
1115 | .hw_value_short = 0x4, | ||
1116 | .flags = IEEE80211_RATE_SHORT_PREAMBLE }, | ||
1117 | { .bitrate = 110, | ||
1118 | .hw_value = 0x20, | ||
1119 | .hw_value_short = 0x20, | ||
1120 | .flags = IEEE80211_RATE_SHORT_PREAMBLE }, | ||
1121 | { .bitrate = 60, | ||
1122 | .hw_value = 0x8, | ||
1123 | .hw_value_short = 0x8, }, | ||
1124 | { .bitrate = 90, | ||
1125 | .hw_value = 0x10, | ||
1126 | .hw_value_short = 0x10, }, | ||
1127 | { .bitrate = 120, | ||
1128 | .hw_value = 0x40, | ||
1129 | .hw_value_short = 0x40, }, | ||
1130 | { .bitrate = 180, | ||
1131 | .hw_value = 0x80, | ||
1132 | .hw_value_short = 0x80, }, | ||
1133 | { .bitrate = 240, | ||
1134 | .hw_value = 0x200, | ||
1135 | .hw_value_short = 0x200, }, | ||
1136 | { .bitrate = 360, | ||
1137 | .hw_value = 0x400, | ||
1138 | .hw_value_short = 0x400, }, | ||
1139 | { .bitrate = 480, | ||
1140 | .hw_value = 0x800, | ||
1141 | .hw_value_short = 0x800, }, | ||
1142 | { .bitrate = 540, | ||
1143 | .hw_value = 0x1000, | ||
1144 | .hw_value_short = 0x1000, }, | ||
1145 | }; | ||
1146 | |||
1147 | /* can't be const, mac80211 writes to this */ | ||
1148 | static struct ieee80211_channel wl1251_channels[] = { | ||
1149 | { .hw_value = 1, .center_freq = 2412}, | ||
1150 | { .hw_value = 2, .center_freq = 2417}, | ||
1151 | { .hw_value = 3, .center_freq = 2422}, | ||
1152 | { .hw_value = 4, .center_freq = 2427}, | ||
1153 | { .hw_value = 5, .center_freq = 2432}, | ||
1154 | { .hw_value = 6, .center_freq = 2437}, | ||
1155 | { .hw_value = 7, .center_freq = 2442}, | ||
1156 | { .hw_value = 8, .center_freq = 2447}, | ||
1157 | { .hw_value = 9, .center_freq = 2452}, | ||
1158 | { .hw_value = 10, .center_freq = 2457}, | ||
1159 | { .hw_value = 11, .center_freq = 2462}, | ||
1160 | { .hw_value = 12, .center_freq = 2467}, | ||
1161 | { .hw_value = 13, .center_freq = 2472}, | ||
1162 | }; | ||
1163 | |||
1164 | static int wl1251_op_conf_tx(struct ieee80211_hw *hw, | ||
1165 | struct ieee80211_vif *vif, u16 queue, | ||
1166 | const struct ieee80211_tx_queue_params *params) | ||
1167 | { | ||
1168 | enum wl1251_acx_ps_scheme ps_scheme; | ||
1169 | struct wl1251 *wl = hw->priv; | ||
1170 | int ret; | ||
1171 | |||
1172 | mutex_lock(&wl->mutex); | ||
1173 | |||
1174 | wl1251_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue); | ||
1175 | |||
1176 | ret = wl1251_ps_elp_wakeup(wl); | ||
1177 | if (ret < 0) | ||
1178 | goto out; | ||
1179 | |||
1180 | /* mac80211 uses units of 32 usec */ | ||
1181 | ret = wl1251_acx_ac_cfg(wl, wl1251_tx_get_queue(queue), | ||
1182 | params->cw_min, params->cw_max, | ||
1183 | params->aifs, params->txop * 32); | ||
1184 | if (ret < 0) | ||
1185 | goto out_sleep; | ||
1186 | |||
1187 | if (params->uapsd) | ||
1188 | ps_scheme = WL1251_ACX_PS_SCHEME_UPSD_TRIGGER; | ||
1189 | else | ||
1190 | ps_scheme = WL1251_ACX_PS_SCHEME_LEGACY; | ||
1191 | |||
1192 | ret = wl1251_acx_tid_cfg(wl, wl1251_tx_get_queue(queue), | ||
1193 | CHANNEL_TYPE_EDCF, | ||
1194 | wl1251_tx_get_queue(queue), ps_scheme, | ||
1195 | WL1251_ACX_ACK_POLICY_LEGACY); | ||
1196 | if (ret < 0) | ||
1197 | goto out_sleep; | ||
1198 | |||
1199 | out_sleep: | ||
1200 | wl1251_ps_elp_sleep(wl); | ||
1201 | |||
1202 | out: | ||
1203 | mutex_unlock(&wl->mutex); | ||
1204 | |||
1205 | return ret; | ||
1206 | } | ||
1207 | |||
1208 | static int wl1251_op_get_survey(struct ieee80211_hw *hw, int idx, | ||
1209 | struct survey_info *survey) | ||
1210 | { | ||
1211 | struct wl1251 *wl = hw->priv; | ||
1212 | struct ieee80211_conf *conf = &hw->conf; | ||
1213 | |||
1214 | if (idx != 0) | ||
1215 | return -ENOENT; | ||
1216 | |||
1217 | survey->channel = conf->channel; | ||
1218 | survey->filled = SURVEY_INFO_NOISE_DBM; | ||
1219 | survey->noise = wl->noise; | ||
1220 | |||
1221 | return 0; | ||
1222 | } | ||
1223 | |||
1224 | /* can't be const, mac80211 writes to this */ | ||
1225 | static struct ieee80211_supported_band wl1251_band_2ghz = { | ||
1226 | .channels = wl1251_channels, | ||
1227 | .n_channels = ARRAY_SIZE(wl1251_channels), | ||
1228 | .bitrates = wl1251_rates, | ||
1229 | .n_bitrates = ARRAY_SIZE(wl1251_rates), | ||
1230 | }; | ||
1231 | |||
1232 | static const struct ieee80211_ops wl1251_ops = { | ||
1233 | .start = wl1251_op_start, | ||
1234 | .stop = wl1251_op_stop, | ||
1235 | .add_interface = wl1251_op_add_interface, | ||
1236 | .remove_interface = wl1251_op_remove_interface, | ||
1237 | .config = wl1251_op_config, | ||
1238 | .configure_filter = wl1251_op_configure_filter, | ||
1239 | .tx = wl1251_op_tx, | ||
1240 | .set_key = wl1251_op_set_key, | ||
1241 | .hw_scan = wl1251_op_hw_scan, | ||
1242 | .bss_info_changed = wl1251_op_bss_info_changed, | ||
1243 | .set_rts_threshold = wl1251_op_set_rts_threshold, | ||
1244 | .conf_tx = wl1251_op_conf_tx, | ||
1245 | .get_survey = wl1251_op_get_survey, | ||
1246 | }; | ||
1247 | |||
1248 | static int wl1251_read_eeprom_byte(struct wl1251 *wl, off_t offset, u8 *data) | ||
1249 | { | ||
1250 | unsigned long timeout; | ||
1251 | |||
1252 | wl1251_reg_write32(wl, EE_ADDR, offset); | ||
1253 | wl1251_reg_write32(wl, EE_CTL, EE_CTL_READ); | ||
1254 | |||
1255 | /* EE_CTL_READ clears when data is ready */ | ||
1256 | timeout = jiffies + msecs_to_jiffies(100); | ||
1257 | while (1) { | ||
1258 | if (!(wl1251_reg_read32(wl, EE_CTL) & EE_CTL_READ)) | ||
1259 | break; | ||
1260 | |||
1261 | if (time_after(jiffies, timeout)) | ||
1262 | return -ETIMEDOUT; | ||
1263 | |||
1264 | msleep(1); | ||
1265 | } | ||
1266 | |||
1267 | *data = wl1251_reg_read32(wl, EE_DATA); | ||
1268 | return 0; | ||
1269 | } | ||
1270 | |||
1271 | static int wl1251_read_eeprom(struct wl1251 *wl, off_t offset, | ||
1272 | u8 *data, size_t len) | ||
1273 | { | ||
1274 | size_t i; | ||
1275 | int ret; | ||
1276 | |||
1277 | wl1251_reg_write32(wl, EE_START, 0); | ||
1278 | |||
1279 | for (i = 0; i < len; i++) { | ||
1280 | ret = wl1251_read_eeprom_byte(wl, offset + i, &data[i]); | ||
1281 | if (ret < 0) | ||
1282 | return ret; | ||
1283 | } | ||
1284 | |||
1285 | return 0; | ||
1286 | } | ||
1287 | |||
1288 | static int wl1251_read_eeprom_mac(struct wl1251 *wl) | ||
1289 | { | ||
1290 | u8 mac[ETH_ALEN]; | ||
1291 | int i, ret; | ||
1292 | |||
1293 | wl1251_set_partition(wl, 0, 0, REGISTERS_BASE, REGISTERS_DOWN_SIZE); | ||
1294 | |||
1295 | ret = wl1251_read_eeprom(wl, 0x1c, mac, sizeof(mac)); | ||
1296 | if (ret < 0) { | ||
1297 | wl1251_warning("failed to read MAC address from EEPROM"); | ||
1298 | return ret; | ||
1299 | } | ||
1300 | |||
1301 | /* MAC is stored in reverse order */ | ||
1302 | for (i = 0; i < ETH_ALEN; i++) | ||
1303 | wl->mac_addr[i] = mac[ETH_ALEN - i - 1]; | ||
1304 | |||
1305 | return 0; | ||
1306 | } | ||
1307 | |||
1308 | static int wl1251_register_hw(struct wl1251 *wl) | ||
1309 | { | ||
1310 | int ret; | ||
1311 | |||
1312 | if (wl->mac80211_registered) | ||
1313 | return 0; | ||
1314 | |||
1315 | SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); | ||
1316 | |||
1317 | ret = ieee80211_register_hw(wl->hw); | ||
1318 | if (ret < 0) { | ||
1319 | wl1251_error("unable to register mac80211 hw: %d", ret); | ||
1320 | return ret; | ||
1321 | } | ||
1322 | |||
1323 | wl->mac80211_registered = true; | ||
1324 | |||
1325 | wl1251_notice("loaded"); | ||
1326 | |||
1327 | return 0; | ||
1328 | } | ||
1329 | |||
1330 | int wl1251_init_ieee80211(struct wl1251 *wl) | ||
1331 | { | ||
1332 | int ret; | ||
1333 | |||
1334 | /* The tx descriptor buffer and the TKIP space */ | ||
1335 | wl->hw->extra_tx_headroom = sizeof(struct tx_double_buffer_desc) | ||
1336 | + WL1251_TKIP_IV_SPACE; | ||
1337 | |||
1338 | /* unit us */ | ||
1339 | /* FIXME: find a proper value */ | ||
1340 | wl->hw->channel_change_time = 10000; | ||
1341 | |||
1342 | wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | | ||
1343 | IEEE80211_HW_SUPPORTS_PS | | ||
1344 | IEEE80211_HW_SUPPORTS_UAPSD; | ||
1345 | |||
1346 | wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | | ||
1347 | BIT(NL80211_IFTYPE_ADHOC); | ||
1348 | wl->hw->wiphy->max_scan_ssids = 1; | ||
1349 | wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1251_band_2ghz; | ||
1350 | |||
1351 | wl->hw->queues = 4; | ||
1352 | |||
1353 | if (wl->use_eeprom) | ||
1354 | wl1251_read_eeprom_mac(wl); | ||
1355 | |||
1356 | ret = wl1251_register_hw(wl); | ||
1357 | if (ret) | ||
1358 | goto out; | ||
1359 | |||
1360 | wl1251_debugfs_init(wl); | ||
1361 | wl1251_notice("initialized"); | ||
1362 | |||
1363 | ret = 0; | ||
1364 | |||
1365 | out: | ||
1366 | return ret; | ||
1367 | } | ||
1368 | EXPORT_SYMBOL_GPL(wl1251_init_ieee80211); | ||
1369 | |||
1370 | struct ieee80211_hw *wl1251_alloc_hw(void) | ||
1371 | { | ||
1372 | struct ieee80211_hw *hw; | ||
1373 | struct wl1251 *wl; | ||
1374 | int i; | ||
1375 | static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf}; | ||
1376 | |||
1377 | hw = ieee80211_alloc_hw(sizeof(*wl), &wl1251_ops); | ||
1378 | if (!hw) { | ||
1379 | wl1251_error("could not alloc ieee80211_hw"); | ||
1380 | return ERR_PTR(-ENOMEM); | ||
1381 | } | ||
1382 | |||
1383 | wl = hw->priv; | ||
1384 | memset(wl, 0, sizeof(*wl)); | ||
1385 | |||
1386 | wl->hw = hw; | ||
1387 | |||
1388 | wl->data_in_count = 0; | ||
1389 | |||
1390 | skb_queue_head_init(&wl->tx_queue); | ||
1391 | |||
1392 | INIT_WORK(&wl->filter_work, wl1251_filter_work); | ||
1393 | INIT_DELAYED_WORK(&wl->elp_work, wl1251_elp_work); | ||
1394 | wl->channel = WL1251_DEFAULT_CHANNEL; | ||
1395 | wl->scanning = false; | ||
1396 | wl->default_key = 0; | ||
1397 | wl->listen_int = 1; | ||
1398 | wl->rx_counter = 0; | ||
1399 | wl->rx_handled = 0; | ||
1400 | wl->rx_current_buffer = 0; | ||
1401 | wl->rx_last_id = 0; | ||
1402 | wl->rx_config = WL1251_DEFAULT_RX_CONFIG; | ||
1403 | wl->rx_filter = WL1251_DEFAULT_RX_FILTER; | ||
1404 | wl->elp = false; | ||
1405 | wl->station_mode = STATION_ACTIVE_MODE; | ||
1406 | wl->psm_requested = false; | ||
1407 | wl->tx_queue_stopped = false; | ||
1408 | wl->power_level = WL1251_DEFAULT_POWER_LEVEL; | ||
1409 | wl->rssi_thold = 0; | ||
1410 | wl->beacon_int = WL1251_DEFAULT_BEACON_INT; | ||
1411 | wl->dtim_period = WL1251_DEFAULT_DTIM_PERIOD; | ||
1412 | wl->vif = NULL; | ||
1413 | |||
1414 | for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) | ||
1415 | wl->tx_frames[i] = NULL; | ||
1416 | |||
1417 | wl->next_tx_complete = 0; | ||
1418 | |||
1419 | INIT_WORK(&wl->irq_work, wl1251_irq_work); | ||
1420 | INIT_WORK(&wl->tx_work, wl1251_tx_work); | ||
1421 | |||
1422 | /* | ||
1423 | * In case our MAC address is not correctly set, | ||
1424 | * we use a random but Nokia MAC. | ||
1425 | */ | ||
1426 | memcpy(wl->mac_addr, nokia_oui, 3); | ||
1427 | get_random_bytes(wl->mac_addr + 3, 3); | ||
1428 | |||
1429 | wl->state = WL1251_STATE_OFF; | ||
1430 | mutex_init(&wl->mutex); | ||
1431 | |||
1432 | wl->tx_mgmt_frm_rate = DEFAULT_HW_GEN_TX_RATE; | ||
1433 | wl->tx_mgmt_frm_mod = DEFAULT_HW_GEN_MODULATION_TYPE; | ||
1434 | |||
1435 | wl->rx_descriptor = kmalloc(sizeof(*wl->rx_descriptor), GFP_KERNEL); | ||
1436 | if (!wl->rx_descriptor) { | ||
1437 | wl1251_error("could not allocate memory for rx descriptor"); | ||
1438 | ieee80211_free_hw(hw); | ||
1439 | return ERR_PTR(-ENOMEM); | ||
1440 | } | ||
1441 | |||
1442 | return hw; | ||
1443 | } | ||
1444 | EXPORT_SYMBOL_GPL(wl1251_alloc_hw); | ||
1445 | |||
1446 | int wl1251_free_hw(struct wl1251 *wl) | ||
1447 | { | ||
1448 | ieee80211_unregister_hw(wl->hw); | ||
1449 | |||
1450 | wl1251_debugfs_exit(wl); | ||
1451 | |||
1452 | kfree(wl->target_mem_map); | ||
1453 | kfree(wl->data_path); | ||
1454 | vfree(wl->fw); | ||
1455 | wl->fw = NULL; | ||
1456 | kfree(wl->nvs); | ||
1457 | wl->nvs = NULL; | ||
1458 | |||
1459 | kfree(wl->rx_descriptor); | ||
1460 | wl->rx_descriptor = NULL; | ||
1461 | |||
1462 | ieee80211_free_hw(wl->hw); | ||
1463 | |||
1464 | return 0; | ||
1465 | } | ||
1466 | EXPORT_SYMBOL_GPL(wl1251_free_hw); | ||
1467 | |||
1468 | MODULE_DESCRIPTION("TI wl1251 Wireles LAN Driver Core"); | ||
1469 | MODULE_LICENSE("GPL"); | ||
1470 | MODULE_AUTHOR("Kalle Valo <kvalo@adurom.com>"); | ||
1471 | MODULE_FIRMWARE(WL1251_FW_NAME); | ||
diff --git a/drivers/net/wireless/ti/wl1251/ps.c b/drivers/net/wireless/ti/wl1251/ps.c new file mode 100644 index 000000000000..db719f7d2692 --- /dev/null +++ b/drivers/net/wireless/ti/wl1251/ps.c | |||
@@ -0,0 +1,185 @@ | |||
1 | /* | ||
2 | * This file is part of wl1251 | ||
3 | * | ||
4 | * Copyright (C) 2008 Nokia Corporation | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * version 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
18 | * 02110-1301 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include "reg.h" | ||
23 | #include "ps.h" | ||
24 | #include "cmd.h" | ||
25 | #include "io.h" | ||
26 | |||
27 | /* in ms */ | ||
28 | #define WL1251_WAKEUP_TIMEOUT 100 | ||
29 | |||
30 | void wl1251_elp_work(struct work_struct *work) | ||
31 | { | ||
32 | struct delayed_work *dwork; | ||
33 | struct wl1251 *wl; | ||
34 | |||
35 | dwork = container_of(work, struct delayed_work, work); | ||
36 | wl = container_of(dwork, struct wl1251, elp_work); | ||
37 | |||
38 | wl1251_debug(DEBUG_PSM, "elp work"); | ||
39 | |||
40 | mutex_lock(&wl->mutex); | ||
41 | |||
42 | if (wl->elp || wl->station_mode == STATION_ACTIVE_MODE) | ||
43 | goto out; | ||
44 | |||
45 | wl1251_debug(DEBUG_PSM, "chip to elp"); | ||
46 | wl1251_write_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); | ||
47 | wl->elp = true; | ||
48 | |||
49 | out: | ||
50 | mutex_unlock(&wl->mutex); | ||
51 | } | ||
52 | |||
53 | #define ELP_ENTRY_DELAY 5 | ||
54 | |||
55 | /* Routines to toggle sleep mode while in ELP */ | ||
56 | void wl1251_ps_elp_sleep(struct wl1251 *wl) | ||
57 | { | ||
58 | unsigned long delay; | ||
59 | |||
60 | if (wl->station_mode != STATION_ACTIVE_MODE) { | ||
61 | delay = msecs_to_jiffies(ELP_ENTRY_DELAY); | ||
62 | ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, delay); | ||
63 | } | ||
64 | } | ||
65 | |||
66 | int wl1251_ps_elp_wakeup(struct wl1251 *wl) | ||
67 | { | ||
68 | unsigned long timeout, start; | ||
69 | u32 elp_reg; | ||
70 | |||
71 | if (delayed_work_pending(&wl->elp_work)) | ||
72 | cancel_delayed_work(&wl->elp_work); | ||
73 | |||
74 | if (!wl->elp) | ||
75 | return 0; | ||
76 | |||
77 | wl1251_debug(DEBUG_PSM, "waking up chip from elp"); | ||
78 | |||
79 | start = jiffies; | ||
80 | timeout = jiffies + msecs_to_jiffies(WL1251_WAKEUP_TIMEOUT); | ||
81 | |||
82 | wl1251_write_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP); | ||
83 | |||
84 | elp_reg = wl1251_read_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); | ||
85 | |||
86 | /* | ||
87 | * FIXME: we should wait for irq from chip but, as a temporary | ||
88 | * solution to simplify locking, let's poll instead | ||
89 | */ | ||
90 | while (!(elp_reg & ELPCTRL_WLAN_READY)) { | ||
91 | if (time_after(jiffies, timeout)) { | ||
92 | wl1251_error("elp wakeup timeout"); | ||
93 | return -ETIMEDOUT; | ||
94 | } | ||
95 | msleep(1); | ||
96 | elp_reg = wl1251_read_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); | ||
97 | } | ||
98 | |||
99 | wl1251_debug(DEBUG_PSM, "wakeup time: %u ms", | ||
100 | jiffies_to_msecs(jiffies - start)); | ||
101 | |||
102 | wl->elp = false; | ||
103 | |||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_station_mode mode) | ||
108 | { | ||
109 | int ret; | ||
110 | |||
111 | switch (mode) { | ||
112 | case STATION_POWER_SAVE_MODE: | ||
113 | wl1251_debug(DEBUG_PSM, "entering psm"); | ||
114 | |||
115 | /* enable beacon filtering */ | ||
116 | ret = wl1251_acx_beacon_filter_opt(wl, true); | ||
117 | if (ret < 0) | ||
118 | return ret; | ||
119 | |||
120 | ret = wl1251_acx_wake_up_conditions(wl, | ||
121 | WAKE_UP_EVENT_DTIM_BITMAP, | ||
122 | wl->listen_int); | ||
123 | if (ret < 0) | ||
124 | return ret; | ||
125 | |||
126 | ret = wl1251_acx_bet_enable(wl, WL1251_ACX_BET_ENABLE, | ||
127 | WL1251_DEFAULT_BET_CONSECUTIVE); | ||
128 | if (ret < 0) | ||
129 | return ret; | ||
130 | |||
131 | ret = wl1251_cmd_ps_mode(wl, CHIP_POWER_SAVE_MODE); | ||
132 | if (ret < 0) | ||
133 | return ret; | ||
134 | |||
135 | ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_ELP); | ||
136 | if (ret < 0) | ||
137 | return ret; | ||
138 | break; | ||
139 | case STATION_IDLE: | ||
140 | wl1251_debug(DEBUG_PSM, "entering idle"); | ||
141 | |||
142 | ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_ELP); | ||
143 | if (ret < 0) | ||
144 | return ret; | ||
145 | |||
146 | ret = wl1251_cmd_template_set(wl, CMD_DISCONNECT, NULL, 0); | ||
147 | if (ret < 0) | ||
148 | return ret; | ||
149 | break; | ||
150 | case STATION_ACTIVE_MODE: | ||
151 | default: | ||
152 | wl1251_debug(DEBUG_PSM, "leaving psm"); | ||
153 | |||
154 | ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM); | ||
155 | if (ret < 0) | ||
156 | return ret; | ||
157 | |||
158 | /* disable BET */ | ||
159 | ret = wl1251_acx_bet_enable(wl, WL1251_ACX_BET_DISABLE, | ||
160 | WL1251_DEFAULT_BET_CONSECUTIVE); | ||
161 | if (ret < 0) | ||
162 | return ret; | ||
163 | |||
164 | /* disable beacon filtering */ | ||
165 | ret = wl1251_acx_beacon_filter_opt(wl, false); | ||
166 | if (ret < 0) | ||
167 | return ret; | ||
168 | |||
169 | ret = wl1251_acx_wake_up_conditions(wl, | ||
170 | WAKE_UP_EVENT_DTIM_BITMAP, | ||
171 | wl->listen_int); | ||
172 | if (ret < 0) | ||
173 | return ret; | ||
174 | |||
175 | ret = wl1251_cmd_ps_mode(wl, CHIP_ACTIVE_MODE); | ||
176 | if (ret < 0) | ||
177 | return ret; | ||
178 | |||
179 | break; | ||
180 | } | ||
181 | wl->station_mode = mode; | ||
182 | |||
183 | return ret; | ||
184 | } | ||
185 | |||
diff --git a/drivers/net/wireless/ti/wl1251/ps.h b/drivers/net/wireless/ti/wl1251/ps.h new file mode 100644 index 000000000000..75efad246d67 --- /dev/null +++ b/drivers/net/wireless/ti/wl1251/ps.h | |||
@@ -0,0 +1,35 @@ | |||
1 | /* | ||
2 | * This file is part of wl1251 | ||
3 | * | ||
4 | * Copyright (c) 1998-2007 Texas Instruments Incorporated | ||
5 | * Copyright (C) 2008 Nokia Corporation | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * version 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
19 | * 02110-1301 USA | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #ifndef __WL1251_PS_H__ | ||
24 | #define __WL1251_PS_H__ | ||
25 | |||
26 | #include "wl1251.h" | ||
27 | #include "acx.h" | ||
28 | |||
29 | int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_station_mode mode); | ||
30 | void wl1251_ps_elp_sleep(struct wl1251 *wl); | ||
31 | int wl1251_ps_elp_wakeup(struct wl1251 *wl); | ||
32 | void wl1251_elp_work(struct work_struct *work); | ||
33 | |||
34 | |||
35 | #endif /* __WL1251_PS_H__ */ | ||
diff --git a/drivers/net/wireless/ti/wl1251/reg.h b/drivers/net/wireless/ti/wl1251/reg.h new file mode 100644 index 000000000000..a5809019c5c1 --- /dev/null +++ b/drivers/net/wireless/ti/wl1251/reg.h | |||
@@ -0,0 +1,655 @@ | |||
1 | /* | ||
2 | * This file is part of wl12xx | ||
3 | * | ||
4 | * Copyright (c) 1998-2007 Texas Instruments Incorporated | ||
5 | * Copyright (C) 2008 Nokia Corporation | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * version 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
19 | * 02110-1301 USA | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #ifndef __REG_H__ | ||
24 | #define __REG_H__ | ||
25 | |||
26 | #include <linux/bitops.h> | ||
27 | |||
28 | #define REGISTERS_BASE 0x00300000 | ||
29 | #define DRPW_BASE 0x00310000 | ||
30 | |||
31 | #define REGISTERS_DOWN_SIZE 0x00008800 | ||
32 | #define REGISTERS_WORK_SIZE 0x0000b000 | ||
33 | |||
34 | #define HW_ACCESS_ELP_CTRL_REG_ADDR 0x1FFFC | ||
35 | |||
36 | /* ELP register commands */ | ||
37 | #define ELPCTRL_WAKE_UP 0x1 | ||
38 | #define ELPCTRL_WAKE_UP_WLAN_READY 0x5 | ||
39 | #define ELPCTRL_SLEEP 0x0 | ||
40 | /* ELP WLAN_READY bit */ | ||
41 | #define ELPCTRL_WLAN_READY 0x2 | ||
42 | |||
43 | /* Device Configuration registers*/ | ||
44 | #define SOR_CFG (REGISTERS_BASE + 0x0800) | ||
45 | #define ECPU_CTRL (REGISTERS_BASE + 0x0804) | ||
46 | #define HI_CFG (REGISTERS_BASE + 0x0808) | ||
47 | |||
48 | /* EEPROM registers */ | ||
49 | #define EE_START (REGISTERS_BASE + 0x080C) | ||
50 | #define EE_CTL (REGISTERS_BASE + 0x2000) | ||
51 | #define EE_DATA (REGISTERS_BASE + 0x2004) | ||
52 | #define EE_ADDR (REGISTERS_BASE + 0x2008) | ||
53 | |||
54 | #define EE_CTL_READ 2 | ||
55 | |||
56 | #define CHIP_ID_B (REGISTERS_BASE + 0x5674) | ||
57 | |||
58 | #define CHIP_ID_1251_PG10 (0x7010101) | ||
59 | #define CHIP_ID_1251_PG11 (0x7020101) | ||
60 | #define CHIP_ID_1251_PG12 (0x7030101) | ||
61 | |||
62 | #define ENABLE (REGISTERS_BASE + 0x5450) | ||
63 | |||
64 | /* Power Management registers */ | ||
65 | #define ELP_CFG_MODE (REGISTERS_BASE + 0x5804) | ||
66 | #define ELP_CMD (REGISTERS_BASE + 0x5808) | ||
67 | #define PLL_CAL_TIME (REGISTERS_BASE + 0x5810) | ||
68 | #define CLK_REQ_TIME (REGISTERS_BASE + 0x5814) | ||
69 | #define CLK_BUF_TIME (REGISTERS_BASE + 0x5818) | ||
70 | |||
71 | #define CFG_PLL_SYNC_CNT (REGISTERS_BASE + 0x5820) | ||
72 | |||
73 | /* Scratch Pad registers*/ | ||
74 | #define SCR_PAD0 (REGISTERS_BASE + 0x5608) | ||
75 | #define SCR_PAD1 (REGISTERS_BASE + 0x560C) | ||
76 | #define SCR_PAD2 (REGISTERS_BASE + 0x5610) | ||
77 | #define SCR_PAD3 (REGISTERS_BASE + 0x5614) | ||
78 | #define SCR_PAD4 (REGISTERS_BASE + 0x5618) | ||
79 | #define SCR_PAD4_SET (REGISTERS_BASE + 0x561C) | ||
80 | #define SCR_PAD4_CLR (REGISTERS_BASE + 0x5620) | ||
81 | #define SCR_PAD5 (REGISTERS_BASE + 0x5624) | ||
82 | #define SCR_PAD5_SET (REGISTERS_BASE + 0x5628) | ||
83 | #define SCR_PAD5_CLR (REGISTERS_BASE + 0x562C) | ||
84 | #define SCR_PAD6 (REGISTERS_BASE + 0x5630) | ||
85 | #define SCR_PAD7 (REGISTERS_BASE + 0x5634) | ||
86 | #define SCR_PAD8 (REGISTERS_BASE + 0x5638) | ||
87 | #define SCR_PAD9 (REGISTERS_BASE + 0x563C) | ||
88 | |||
89 | /* Spare registers*/ | ||
90 | #define SPARE_A1 (REGISTERS_BASE + 0x0994) | ||
91 | #define SPARE_A2 (REGISTERS_BASE + 0x0998) | ||
92 | #define SPARE_A3 (REGISTERS_BASE + 0x099C) | ||
93 | #define SPARE_A4 (REGISTERS_BASE + 0x09A0) | ||
94 | #define SPARE_A5 (REGISTERS_BASE + 0x09A4) | ||
95 | #define SPARE_A6 (REGISTERS_BASE + 0x09A8) | ||
96 | #define SPARE_A7 (REGISTERS_BASE + 0x09AC) | ||
97 | #define SPARE_A8 (REGISTERS_BASE + 0x09B0) | ||
98 | #define SPARE_B1 (REGISTERS_BASE + 0x5420) | ||
99 | #define SPARE_B2 (REGISTERS_BASE + 0x5424) | ||
100 | #define SPARE_B3 (REGISTERS_BASE + 0x5428) | ||
101 | #define SPARE_B4 (REGISTERS_BASE + 0x542C) | ||
102 | #define SPARE_B5 (REGISTERS_BASE + 0x5430) | ||
103 | #define SPARE_B6 (REGISTERS_BASE + 0x5434) | ||
104 | #define SPARE_B7 (REGISTERS_BASE + 0x5438) | ||
105 | #define SPARE_B8 (REGISTERS_BASE + 0x543C) | ||
106 | |||
107 | enum wl12xx_acx_int_reg { | ||
108 | ACX_REG_INTERRUPT_TRIG, | ||
109 | ACX_REG_INTERRUPT_TRIG_H, | ||
110 | |||
111 | /*============================================= | ||
112 | Host Interrupt Mask Register - 32bit (RW) | ||
113 | ------------------------------------------ | ||
114 | Setting a bit in this register masks the | ||
115 | corresponding interrupt to the host. | ||
116 | 0 - RX0 - Rx first dubble buffer Data Interrupt | ||
117 | 1 - TXD - Tx Data Interrupt | ||
118 | 2 - TXXFR - Tx Transfer Interrupt | ||
119 | 3 - RX1 - Rx second dubble buffer Data Interrupt | ||
120 | 4 - RXXFR - Rx Transfer Interrupt | ||
121 | 5 - EVENT_A - Event Mailbox interrupt | ||
122 | 6 - EVENT_B - Event Mailbox interrupt | ||
123 | 7 - WNONHST - Wake On Host Interrupt | ||
124 | 8 - TRACE_A - Debug Trace interrupt | ||
125 | 9 - TRACE_B - Debug Trace interrupt | ||
126 | 10 - CDCMP - Command Complete Interrupt | ||
127 | 11 - | ||
128 | 12 - | ||
129 | 13 - | ||
130 | 14 - ICOMP - Initialization Complete Interrupt | ||
131 | 16 - SG SE - Soft Gemini - Sense enable interrupt | ||
132 | 17 - SG SD - Soft Gemini - Sense disable interrupt | ||
133 | 18 - - | ||
134 | 19 - - | ||
135 | 20 - - | ||
136 | 21- - | ||
137 | Default: 0x0001 | ||
138 | *==============================================*/ | ||
139 | ACX_REG_INTERRUPT_MASK, | ||
140 | |||
141 | /*============================================= | ||
142 | Host Interrupt Mask Set 16bit, (Write only) | ||
143 | ------------------------------------------ | ||
144 | Setting a bit in this register sets | ||
145 | the corresponding bin in ACX_HINT_MASK register | ||
146 | without effecting the mask | ||
147 | state of other bits (0 = no effect). | ||
148 | ==============================================*/ | ||
149 | ACX_REG_HINT_MASK_SET, | ||
150 | |||
151 | /*============================================= | ||
152 | Host Interrupt Mask Clear 16bit,(Write only) | ||
153 | ------------------------------------------ | ||
154 | Setting a bit in this register clears | ||
155 | the corresponding bin in ACX_HINT_MASK register | ||
156 | without effecting the mask | ||
157 | state of other bits (0 = no effect). | ||
158 | =============================================*/ | ||
159 | ACX_REG_HINT_MASK_CLR, | ||
160 | |||
161 | /*============================================= | ||
162 | Host Interrupt Status Nondestructive Read | ||
163 | 16bit,(Read only) | ||
164 | ------------------------------------------ | ||
165 | The host can read this register to determine | ||
166 | which interrupts are active. | ||
167 | Reading this register doesn't | ||
168 | effect its content. | ||
169 | =============================================*/ | ||
170 | ACX_REG_INTERRUPT_NO_CLEAR, | ||
171 | |||
172 | /*============================================= | ||
173 | Host Interrupt Status Clear on Read Register | ||
174 | 16bit,(Read only) | ||
175 | ------------------------------------------ | ||
176 | The host can read this register to determine | ||
177 | which interrupts are active. | ||
178 | Reading this register clears it, | ||
179 | thus making all interrupts inactive. | ||
180 | ==============================================*/ | ||
181 | ACX_REG_INTERRUPT_CLEAR, | ||
182 | |||
183 | /*============================================= | ||
184 | Host Interrupt Acknowledge Register | ||
185 | 16bit,(Write only) | ||
186 | ------------------------------------------ | ||
187 | The host can set individual bits in this | ||
188 | register to clear (acknowledge) the corresp. | ||
189 | interrupt status bits in the HINT_STS_CLR and | ||
190 | HINT_STS_ND registers, thus making the | ||
191 | assotiated interrupt inactive. (0-no effect) | ||
192 | ==============================================*/ | ||
193 | ACX_REG_INTERRUPT_ACK, | ||
194 | |||
195 | /*=============================================== | ||
196 | Host Software Reset - 32bit RW | ||
197 | ------------------------------------------ | ||
198 | [31:1] Reserved | ||
199 | 0 SOFT_RESET Soft Reset - When this bit is set, | ||
200 | it holds the Wlan hardware in a soft reset state. | ||
201 | This reset disables all MAC and baseband processor | ||
202 | clocks except the CardBus/PCI interface clock. | ||
203 | It also initializes all MAC state machines except | ||
204 | the host interface. It does not reload the | ||
205 | contents of the EEPROM. When this bit is cleared | ||
206 | (not self-clearing), the Wlan hardware | ||
207 | exits the software reset state. | ||
208 | ===============================================*/ | ||
209 | ACX_REG_SLV_SOFT_RESET, | ||
210 | |||
211 | /*=============================================== | ||
212 | EEPROM Burst Read Start - 32bit RW | ||
213 | ------------------------------------------ | ||
214 | [31:1] Reserved | ||
215 | 0 ACX_EE_START - EEPROM Burst Read Start 0 | ||
216 | Setting this bit starts a burst read from | ||
217 | the external EEPROM. | ||
218 | If this bit is set (after reset) before an EEPROM read/write, | ||
219 | the burst read starts at EEPROM address 0. | ||
220 | Otherwise, it starts at the address | ||
221 | following the address of the previous access. | ||
222 | TheWlan hardware hardware clears this bit automatically. | ||
223 | |||
224 | Default: 0x00000000 | ||
225 | *================================================*/ | ||
226 | ACX_REG_EE_START, | ||
227 | |||
228 | /* Embedded ARM CPU Control */ | ||
229 | |||
230 | /*=============================================== | ||
231 | Halt eCPU - 32bit RW | ||
232 | ------------------------------------------ | ||
233 | 0 HALT_ECPU Halt Embedded CPU - This bit is the | ||
234 | compliment of bit 1 (MDATA2) in the SOR_CFG register. | ||
235 | During a hardware reset, this bit holds | ||
236 | the inverse of MDATA2. | ||
237 | When downloading firmware from the host, | ||
238 | set this bit (pull down MDATA2). | ||
239 | The host clears this bit after downloading the firmware into | ||
240 | zero-wait-state SSRAM. | ||
241 | When loading firmware from Flash, clear this bit (pull up MDATA2) | ||
242 | so that the eCPU can run the bootloader code in Flash | ||
243 | HALT_ECPU eCPU State | ||
244 | -------------------- | ||
245 | 1 halt eCPU | ||
246 | 0 enable eCPU | ||
247 | ===============================================*/ | ||
248 | ACX_REG_ECPU_CONTROL, | ||
249 | |||
250 | ACX_REG_TABLE_LEN | ||
251 | }; | ||
252 | |||
253 | #define ACX_SLV_SOFT_RESET_BIT BIT(0) | ||
254 | #define ACX_REG_EEPROM_START_BIT BIT(0) | ||
255 | |||
256 | /* Command/Information Mailbox Pointers */ | ||
257 | |||
258 | /*=============================================== | ||
259 | Command Mailbox Pointer - 32bit RW | ||
260 | ------------------------------------------ | ||
261 | This register holds the start address of | ||
262 | the command mailbox located in the Wlan hardware memory. | ||
263 | The host must read this pointer after a reset to | ||
264 | find the location of the command mailbox. | ||
265 | The Wlan hardware initializes the command mailbox | ||
266 | pointer with the default address of the command mailbox. | ||
267 | The command mailbox pointer is not valid until after | ||
268 | the host receives the Init Complete interrupt from | ||
269 | the Wlan hardware. | ||
270 | ===============================================*/ | ||
271 | #define REG_COMMAND_MAILBOX_PTR (SCR_PAD0) | ||
272 | |||
273 | /*=============================================== | ||
274 | Information Mailbox Pointer - 32bit RW | ||
275 | ------------------------------------------ | ||
276 | This register holds the start address of | ||
277 | the information mailbox located in the Wlan hardware memory. | ||
278 | The host must read this pointer after a reset to find | ||
279 | the location of the information mailbox. | ||
280 | The Wlan hardware initializes the information mailbox pointer | ||
281 | with the default address of the information mailbox. | ||
282 | The information mailbox pointer is not valid | ||
283 | until after the host receives the Init Complete interrupt from | ||
284 | the Wlan hardware. | ||
285 | ===============================================*/ | ||
286 | #define REG_EVENT_MAILBOX_PTR (SCR_PAD1) | ||
287 | |||
288 | |||
289 | /* Misc */ | ||
290 | |||
291 | #define REG_ENABLE_TX_RX (ENABLE) | ||
292 | /* | ||
293 | * Rx configuration (filter) information element | ||
294 | * --------------------------------------------- | ||
295 | */ | ||
296 | #define REG_RX_CONFIG (RX_CFG) | ||
297 | #define REG_RX_FILTER (RX_FILTER_CFG) | ||
298 | |||
299 | |||
300 | #define RX_CFG_ENABLE_PHY_HEADER_PLCP 0x0002 | ||
301 | |||
302 | /* promiscuous - receives all valid frames */ | ||
303 | #define RX_CFG_PROMISCUOUS 0x0008 | ||
304 | |||
305 | /* receives frames from any BSSID */ | ||
306 | #define RX_CFG_BSSID 0x0020 | ||
307 | |||
308 | /* receives frames destined to any MAC address */ | ||
309 | #define RX_CFG_MAC 0x0010 | ||
310 | |||
311 | #define RX_CFG_ENABLE_ONLY_MY_DEST_MAC 0x0010 | ||
312 | #define RX_CFG_ENABLE_ANY_DEST_MAC 0x0000 | ||
313 | #define RX_CFG_ENABLE_ONLY_MY_BSSID 0x0020 | ||
314 | #define RX_CFG_ENABLE_ANY_BSSID 0x0000 | ||
315 | |||
316 | /* discards all broadcast frames */ | ||
317 | #define RX_CFG_DISABLE_BCAST 0x0200 | ||
318 | |||
319 | #define RX_CFG_ENABLE_ONLY_MY_SSID 0x0400 | ||
320 | #define RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR 0x0800 | ||
321 | #define RX_CFG_COPY_RX_STATUS 0x2000 | ||
322 | #define RX_CFG_TSF 0x10000 | ||
323 | |||
324 | #define RX_CONFIG_OPTION_ANY_DST_MY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \ | ||
325 | RX_CFG_ENABLE_ONLY_MY_BSSID) | ||
326 | |||
327 | #define RX_CONFIG_OPTION_MY_DST_ANY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\ | ||
328 | | RX_CFG_ENABLE_ANY_BSSID) | ||
329 | |||
330 | #define RX_CONFIG_OPTION_ANY_DST_ANY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \ | ||
331 | RX_CFG_ENABLE_ANY_BSSID) | ||
332 | |||
333 | #define RX_CONFIG_OPTION_MY_DST_MY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\ | ||
334 | | RX_CFG_ENABLE_ONLY_MY_BSSID) | ||
335 | |||
336 | #define RX_CONFIG_OPTION_FOR_SCAN (RX_CFG_ENABLE_PHY_HEADER_PLCP \ | ||
337 | | RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR \ | ||
338 | | RX_CFG_COPY_RX_STATUS | RX_CFG_TSF) | ||
339 | |||
340 | #define RX_CONFIG_OPTION_FOR_MEASUREMENT (RX_CFG_ENABLE_ANY_DEST_MAC) | ||
341 | |||
342 | #define RX_CONFIG_OPTION_FOR_JOIN (RX_CFG_ENABLE_ONLY_MY_BSSID | \ | ||
343 | RX_CFG_ENABLE_ONLY_MY_DEST_MAC) | ||
344 | |||
345 | #define RX_CONFIG_OPTION_FOR_IBSS_JOIN (RX_CFG_ENABLE_ONLY_MY_SSID | \ | ||
346 | RX_CFG_ENABLE_ONLY_MY_DEST_MAC) | ||
347 | |||
348 | #define RX_FILTER_OPTION_DEF (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\ | ||
349 | | CFG_RX_CTL_EN | CFG_RX_BCN_EN\ | ||
350 | | CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN) | ||
351 | |||
352 | #define RX_FILTER_OPTION_FILTER_ALL 0 | ||
353 | |||
354 | #define RX_FILTER_OPTION_DEF_PRSP_BCN (CFG_RX_PRSP_EN | CFG_RX_MGMT_EN\ | ||
355 | | CFG_RX_RCTS_ACK | CFG_RX_BCN_EN) | ||
356 | |||
357 | #define RX_FILTER_OPTION_JOIN (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\ | ||
358 | | CFG_RX_BCN_EN | CFG_RX_AUTH_EN\ | ||
359 | | CFG_RX_ASSOC_EN | CFG_RX_RCTS_ACK\ | ||
360 | | CFG_RX_PRSP_EN) | ||
361 | |||
362 | |||
363 | /*=============================================== | ||
364 | EEPROM Read/Write Request 32bit RW | ||
365 | ------------------------------------------ | ||
366 | 1 EE_READ - EEPROM Read Request 1 - Setting this bit | ||
367 | loads a single byte of data into the EE_DATA | ||
368 | register from the EEPROM location specified in | ||
369 | the EE_ADDR register. | ||
370 | The Wlan hardware hardware clears this bit automatically. | ||
371 | EE_DATA is valid when this bit is cleared. | ||
372 | |||
373 | 0 EE_WRITE - EEPROM Write Request - Setting this bit | ||
374 | writes a single byte of data from the EE_DATA register into the | ||
375 | EEPROM location specified in the EE_ADDR register. | ||
376 | The Wlan hardware hardware clears this bit automatically. | ||
377 | *===============================================*/ | ||
378 | #define EE_CTL (REGISTERS_BASE + 0x2000) | ||
379 | #define ACX_EE_CTL_REG EE_CTL | ||
380 | #define EE_WRITE 0x00000001ul | ||
381 | #define EE_READ 0x00000002ul | ||
382 | |||
383 | /*=============================================== | ||
384 | EEPROM Address - 32bit RW | ||
385 | ------------------------------------------ | ||
386 | This register specifies the address | ||
387 | within the EEPROM from/to which to read/write data. | ||
388 | ===============================================*/ | ||
389 | #define EE_ADDR (REGISTERS_BASE + 0x2008) | ||
390 | #define ACX_EE_ADDR_REG EE_ADDR | ||
391 | |||
392 | /*=============================================== | ||
393 | EEPROM Data - 32bit RW | ||
394 | ------------------------------------------ | ||
395 | This register either holds the read 8 bits of | ||
396 | data from the EEPROM or the write data | ||
397 | to be written to the EEPROM. | ||
398 | ===============================================*/ | ||
399 | #define EE_DATA (REGISTERS_BASE + 0x2004) | ||
400 | #define ACX_EE_DATA_REG EE_DATA | ||
401 | |||
402 | #define EEPROM_ACCESS_TO 10000 /* timeout counter */ | ||
403 | #define START_EEPROM_MGR 0x00000001 | ||
404 | |||
405 | /*=============================================== | ||
406 | EEPROM Base Address - 32bit RW | ||
407 | ------------------------------------------ | ||
408 | This register holds the upper nine bits | ||
409 | [23:15] of the 24-bit Wlan hardware memory | ||
410 | address for burst reads from EEPROM accesses. | ||
411 | The EEPROM provides the lower 15 bits of this address. | ||
412 | The MSB of the address from the EEPROM is ignored. | ||
413 | ===============================================*/ | ||
414 | #define ACX_EE_CFG EE_CFG | ||
415 | |||
416 | /*=============================================== | ||
417 | GPIO Output Values -32bit, RW | ||
418 | ------------------------------------------ | ||
419 | [31:16] Reserved | ||
420 | [15: 0] Specify the output values (at the output driver inputs) for | ||
421 | GPIO[15:0], respectively. | ||
422 | ===============================================*/ | ||
423 | #define ACX_GPIO_OUT_REG GPIO_OUT | ||
424 | #define ACX_MAX_GPIO_LINES 15 | ||
425 | |||
426 | /*=============================================== | ||
427 | Contention window -32bit, RW | ||
428 | ------------------------------------------ | ||
429 | [31:26] Reserved | ||
430 | [25:16] Max (0x3ff) | ||
431 | [15:07] Reserved | ||
432 | [06:00] Current contention window value - default is 0x1F | ||
433 | ===============================================*/ | ||
434 | #define ACX_CONT_WIND_CFG_REG CONT_WIND_CFG | ||
435 | #define ACX_CONT_WIND_MIN_MASK 0x0000007f | ||
436 | #define ACX_CONT_WIND_MAX 0x03ff0000 | ||
437 | |||
438 | /*=============================================== | ||
439 | HI_CFG Interface Configuration Register Values | ||
440 | ------------------------------------------ | ||
441 | ===============================================*/ | ||
442 | #define HI_CFG_UART_ENABLE 0x00000004 | ||
443 | #define HI_CFG_RST232_ENABLE 0x00000008 | ||
444 | #define HI_CFG_CLOCK_REQ_SELECT 0x00000010 | ||
445 | #define HI_CFG_HOST_INT_ENABLE 0x00000020 | ||
446 | #define HI_CFG_VLYNQ_OUTPUT_ENABLE 0x00000040 | ||
447 | #define HI_CFG_HOST_INT_ACTIVE_LOW 0x00000080 | ||
448 | #define HI_CFG_UART_TX_OUT_GPIO_15 0x00000100 | ||
449 | #define HI_CFG_UART_TX_OUT_GPIO_14 0x00000200 | ||
450 | #define HI_CFG_UART_TX_OUT_GPIO_7 0x00000400 | ||
451 | |||
452 | /* | ||
453 | * NOTE: USE_ACTIVE_HIGH compilation flag should be defined in makefile | ||
454 | * for platforms using active high interrupt level | ||
455 | */ | ||
456 | #ifdef USE_ACTIVE_HIGH | ||
457 | #define HI_CFG_DEF_VAL \ | ||
458 | (HI_CFG_UART_ENABLE | \ | ||
459 | HI_CFG_RST232_ENABLE | \ | ||
460 | HI_CFG_CLOCK_REQ_SELECT | \ | ||
461 | HI_CFG_HOST_INT_ENABLE) | ||
462 | #else | ||
463 | #define HI_CFG_DEF_VAL \ | ||
464 | (HI_CFG_UART_ENABLE | \ | ||
465 | HI_CFG_RST232_ENABLE | \ | ||
466 | HI_CFG_CLOCK_REQ_SELECT | \ | ||
467 | HI_CFG_HOST_INT_ENABLE) | ||
468 | |||
469 | #endif | ||
470 | |||
471 | #define REF_FREQ_19_2 0 | ||
472 | #define REF_FREQ_26_0 1 | ||
473 | #define REF_FREQ_38_4 2 | ||
474 | #define REF_FREQ_40_0 3 | ||
475 | #define REF_FREQ_33_6 4 | ||
476 | #define REF_FREQ_NUM 5 | ||
477 | |||
478 | #define LUT_PARAM_INTEGER_DIVIDER 0 | ||
479 | #define LUT_PARAM_FRACTIONAL_DIVIDER 1 | ||
480 | #define LUT_PARAM_ATTN_BB 2 | ||
481 | #define LUT_PARAM_ALPHA_BB 3 | ||
482 | #define LUT_PARAM_STOP_TIME_BB 4 | ||
483 | #define LUT_PARAM_BB_PLL_LOOP_FILTER 5 | ||
484 | #define LUT_PARAM_NUM 6 | ||
485 | |||
486 | #define ACX_EEPROMLESS_IND_REG (SCR_PAD4) | ||
487 | #define USE_EEPROM 0 | ||
488 | #define SOFT_RESET_MAX_TIME 1000000 | ||
489 | #define SOFT_RESET_STALL_TIME 1000 | ||
490 | #define NVS_DATA_BUNDARY_ALIGNMENT 4 | ||
491 | |||
492 | |||
493 | /* Firmware image load chunk size */ | ||
494 | #define CHUNK_SIZE 512 | ||
495 | |||
496 | /* Firmware image header size */ | ||
497 | #define FW_HDR_SIZE 8 | ||
498 | |||
499 | #define ECPU_CONTROL_HALT 0x00000101 | ||
500 | |||
501 | |||
502 | /****************************************************************************** | ||
503 | |||
504 | CHANNELS, BAND & REG DOMAINS definitions | ||
505 | |||
506 | ******************************************************************************/ | ||
507 | |||
508 | |||
509 | enum { | ||
510 | RADIO_BAND_2_4GHZ = 0, /* 2.4 Ghz band */ | ||
511 | RADIO_BAND_5GHZ = 1, /* 5 Ghz band */ | ||
512 | RADIO_BAND_JAPAN_4_9_GHZ = 2, | ||
513 | DEFAULT_BAND = RADIO_BAND_2_4GHZ, | ||
514 | INVALID_BAND = 0xFE, | ||
515 | MAX_RADIO_BANDS = 0xFF | ||
516 | }; | ||
517 | |||
518 | enum { | ||
519 | NO_RATE = 0, | ||
520 | RATE_1MBPS = 0x0A, | ||
521 | RATE_2MBPS = 0x14, | ||
522 | RATE_5_5MBPS = 0x37, | ||
523 | RATE_6MBPS = 0x0B, | ||
524 | RATE_9MBPS = 0x0F, | ||
525 | RATE_11MBPS = 0x6E, | ||
526 | RATE_12MBPS = 0x0A, | ||
527 | RATE_18MBPS = 0x0E, | ||
528 | RATE_22MBPS = 0xDC, | ||
529 | RATE_24MBPS = 0x09, | ||
530 | RATE_36MBPS = 0x0D, | ||
531 | RATE_48MBPS = 0x08, | ||
532 | RATE_54MBPS = 0x0C | ||
533 | }; | ||
534 | |||
535 | enum { | ||
536 | RATE_INDEX_1MBPS = 0, | ||
537 | RATE_INDEX_2MBPS = 1, | ||
538 | RATE_INDEX_5_5MBPS = 2, | ||
539 | RATE_INDEX_6MBPS = 3, | ||
540 | RATE_INDEX_9MBPS = 4, | ||
541 | RATE_INDEX_11MBPS = 5, | ||
542 | RATE_INDEX_12MBPS = 6, | ||
543 | RATE_INDEX_18MBPS = 7, | ||
544 | RATE_INDEX_22MBPS = 8, | ||
545 | RATE_INDEX_24MBPS = 9, | ||
546 | RATE_INDEX_36MBPS = 10, | ||
547 | RATE_INDEX_48MBPS = 11, | ||
548 | RATE_INDEX_54MBPS = 12, | ||
549 | RATE_INDEX_MAX = RATE_INDEX_54MBPS, | ||
550 | MAX_RATE_INDEX, | ||
551 | INVALID_RATE_INDEX = MAX_RATE_INDEX, | ||
552 | RATE_INDEX_ENUM_MAX_SIZE = 0x7FFFFFFF | ||
553 | }; | ||
554 | |||
555 | enum { | ||
556 | RATE_MASK_1MBPS = 0x1, | ||
557 | RATE_MASK_2MBPS = 0x2, | ||
558 | RATE_MASK_5_5MBPS = 0x4, | ||
559 | RATE_MASK_11MBPS = 0x20, | ||
560 | }; | ||
561 | |||
562 | #define SHORT_PREAMBLE_BIT BIT(0) /* CCK or Barker depending on the rate */ | ||
563 | #define OFDM_RATE_BIT BIT(6) | ||
564 | #define PBCC_RATE_BIT BIT(7) | ||
565 | |||
566 | enum { | ||
567 | CCK_LONG = 0, | ||
568 | CCK_SHORT = SHORT_PREAMBLE_BIT, | ||
569 | PBCC_LONG = PBCC_RATE_BIT, | ||
570 | PBCC_SHORT = PBCC_RATE_BIT | SHORT_PREAMBLE_BIT, | ||
571 | OFDM = OFDM_RATE_BIT | ||
572 | }; | ||
573 | |||
574 | /****************************************************************************** | ||
575 | |||
576 | Transmit-Descriptor RATE-SET field definitions... | ||
577 | |||
578 | Define a new "Rate-Set" for TX path that incorporates the | ||
579 | Rate & Modulation info into a single 16-bit field. | ||
580 | |||
581 | TxdRateSet_t: | ||
582 | b15 - Indicates Preamble type (1=SHORT, 0=LONG). | ||
583 | Notes: | ||
584 | Must be LONG (0) for 1Mbps rate. | ||
585 | Does not apply (set to 0) for RevG-OFDM rates. | ||
586 | b14 - Indicates PBCC encoding (1=PBCC, 0=not). | ||
587 | Notes: | ||
588 | Does not apply (set to 0) for rates 1 and 2 Mbps. | ||
589 | Does not apply (set to 0) for RevG-OFDM rates. | ||
590 | b13 - Unused (set to 0). | ||
591 | b12-b0 - Supported Rate indicator bits as defined below. | ||
592 | |||
593 | ******************************************************************************/ | ||
594 | |||
595 | |||
596 | /************************************************************************* | ||
597 | |||
598 | Interrupt Trigger Register (Host -> WiLink) | ||
599 | |||
600 | **************************************************************************/ | ||
601 | |||
602 | /* Hardware to Embedded CPU Interrupts - first 32-bit register set */ | ||
603 | |||
604 | /* | ||
605 | * Host Command Interrupt. Setting this bit masks | ||
606 | * the interrupt that the host issues to inform | ||
607 | * the FW that it has sent a command | ||
608 | * to the Wlan hardware Command Mailbox. | ||
609 | */ | ||
610 | #define INTR_TRIG_CMD BIT(0) | ||
611 | |||
612 | /* | ||
613 | * Host Event Acknowlegde Interrupt. The host | ||
614 | * sets this bit to acknowledge that it received | ||
615 | * the unsolicited information from the event | ||
616 | * mailbox. | ||
617 | */ | ||
618 | #define INTR_TRIG_EVENT_ACK BIT(1) | ||
619 | |||
620 | /* | ||
621 | * The host sets this bit to inform the Wlan | ||
622 | * FW that a TX packet is in the XFER | ||
623 | * Buffer #0. | ||
624 | */ | ||
625 | #define INTR_TRIG_TX_PROC0 BIT(2) | ||
626 | |||
627 | /* | ||
628 | * The host sets this bit to inform the FW | ||
629 | * that it read a packet from RX XFER | ||
630 | * Buffer #0. | ||
631 | */ | ||
632 | #define INTR_TRIG_RX_PROC0 BIT(3) | ||
633 | |||
634 | #define INTR_TRIG_DEBUG_ACK BIT(4) | ||
635 | |||
636 | #define INTR_TRIG_STATE_CHANGED BIT(5) | ||
637 | |||
638 | |||
639 | /* Hardware to Embedded CPU Interrupts - second 32-bit register set */ | ||
640 | |||
641 | /* | ||
642 | * The host sets this bit to inform the FW | ||
643 | * that it read a packet from RX XFER | ||
644 | * Buffer #1. | ||
645 | */ | ||
646 | #define INTR_TRIG_RX_PROC1 BIT(17) | ||
647 | |||
648 | /* | ||
649 | * The host sets this bit to inform the Wlan | ||
650 | * hardware that a TX packet is in the XFER | ||
651 | * Buffer #1. | ||
652 | */ | ||
653 | #define INTR_TRIG_TX_PROC1 BIT(18) | ||
654 | |||
655 | #endif | ||
diff --git a/drivers/net/wireless/ti/wl1251/rx.c b/drivers/net/wireless/ti/wl1251/rx.c new file mode 100644 index 000000000000..6af35265c900 --- /dev/null +++ b/drivers/net/wireless/ti/wl1251/rx.c | |||
@@ -0,0 +1,235 @@ | |||
1 | /* | ||
2 | * This file is part of wl1251 | ||
3 | * | ||
4 | * Copyright (c) 1998-2007 Texas Instruments Incorporated | ||
5 | * Copyright (C) 2008 Nokia Corporation | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * version 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
19 | * 02110-1301 USA | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #include <linux/skbuff.h> | ||
24 | #include <linux/gfp.h> | ||
25 | #include <net/mac80211.h> | ||
26 | |||
27 | #include "wl1251.h" | ||
28 | #include "reg.h" | ||
29 | #include "io.h" | ||
30 | #include "rx.h" | ||
31 | #include "cmd.h" | ||
32 | #include "acx.h" | ||
33 | |||
34 | static void wl1251_rx_header(struct wl1251 *wl, | ||
35 | struct wl1251_rx_descriptor *desc) | ||
36 | { | ||
37 | u32 rx_packet_ring_addr; | ||
38 | |||
39 | rx_packet_ring_addr = wl->data_path->rx_packet_ring_addr; | ||
40 | if (wl->rx_current_buffer) | ||
41 | rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size; | ||
42 | |||
43 | wl1251_mem_read(wl, rx_packet_ring_addr, desc, sizeof(*desc)); | ||
44 | } | ||
45 | |||
46 | static void wl1251_rx_status(struct wl1251 *wl, | ||
47 | struct wl1251_rx_descriptor *desc, | ||
48 | struct ieee80211_rx_status *status, | ||
49 | u8 beacon) | ||
50 | { | ||
51 | u64 mactime; | ||
52 | int ret; | ||
53 | |||
54 | memset(status, 0, sizeof(struct ieee80211_rx_status)); | ||
55 | |||
56 | status->band = IEEE80211_BAND_2GHZ; | ||
57 | status->mactime = desc->timestamp; | ||
58 | |||
59 | /* | ||
60 | * The rx status timestamp is a 32 bits value while the TSF is a | ||
61 | * 64 bits one. | ||
62 | * For IBSS merging, TSF is mandatory, so we have to get it | ||
63 | * somehow, so we ask for ACX_TSF_INFO. | ||
64 | * That could be moved to the get_tsf() hook, but unfortunately, | ||
65 | * this one must be atomic, while our SPI routines can sleep. | ||
66 | */ | ||
67 | if ((wl->bss_type == BSS_TYPE_IBSS) && beacon) { | ||
68 | ret = wl1251_acx_tsf_info(wl, &mactime); | ||
69 | if (ret == 0) | ||
70 | status->mactime = mactime; | ||
71 | } | ||
72 | |||
73 | status->signal = desc->rssi; | ||
74 | |||
75 | /* | ||
76 | * FIXME: guessing that snr needs to be divided by two, otherwise | ||
77 | * the values don't make any sense | ||
78 | */ | ||
79 | wl->noise = desc->rssi - desc->snr / 2; | ||
80 | |||
81 | status->freq = ieee80211_channel_to_frequency(desc->channel, | ||
82 | status->band); | ||
83 | |||
84 | status->flag |= RX_FLAG_MACTIME_MPDU; | ||
85 | |||
86 | if (desc->flags & RX_DESC_ENCRYPTION_MASK) { | ||
87 | status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED; | ||
88 | |||
89 | if (likely(!(desc->flags & RX_DESC_DECRYPT_FAIL))) | ||
90 | status->flag |= RX_FLAG_DECRYPTED; | ||
91 | |||
92 | if (unlikely(desc->flags & RX_DESC_MIC_FAIL)) | ||
93 | status->flag |= RX_FLAG_MMIC_ERROR; | ||
94 | } | ||
95 | |||
96 | if (unlikely(!(desc->flags & RX_DESC_VALID_FCS))) | ||
97 | status->flag |= RX_FLAG_FAILED_FCS_CRC; | ||
98 | |||
99 | switch (desc->rate) { | ||
100 | /* skip 1 and 12 Mbps because they have same value 0x0a */ | ||
101 | case RATE_2MBPS: | ||
102 | status->rate_idx = 1; | ||
103 | break; | ||
104 | case RATE_5_5MBPS: | ||
105 | status->rate_idx = 2; | ||
106 | break; | ||
107 | case RATE_11MBPS: | ||
108 | status->rate_idx = 3; | ||
109 | break; | ||
110 | case RATE_6MBPS: | ||
111 | status->rate_idx = 4; | ||
112 | break; | ||
113 | case RATE_9MBPS: | ||
114 | status->rate_idx = 5; | ||
115 | break; | ||
116 | case RATE_18MBPS: | ||
117 | status->rate_idx = 7; | ||
118 | break; | ||
119 | case RATE_24MBPS: | ||
120 | status->rate_idx = 8; | ||
121 | break; | ||
122 | case RATE_36MBPS: | ||
123 | status->rate_idx = 9; | ||
124 | break; | ||
125 | case RATE_48MBPS: | ||
126 | status->rate_idx = 10; | ||
127 | break; | ||
128 | case RATE_54MBPS: | ||
129 | status->rate_idx = 11; | ||
130 | break; | ||
131 | } | ||
132 | |||
133 | /* for 1 and 12 Mbps we have to check the modulation */ | ||
134 | if (desc->rate == RATE_1MBPS) { | ||
135 | if (!(desc->mod_pre & OFDM_RATE_BIT)) | ||
136 | /* CCK -> RATE_1MBPS */ | ||
137 | status->rate_idx = 0; | ||
138 | else | ||
139 | /* OFDM -> RATE_12MBPS */ | ||
140 | status->rate_idx = 6; | ||
141 | } | ||
142 | |||
143 | if (desc->mod_pre & SHORT_PREAMBLE_BIT) | ||
144 | status->flag |= RX_FLAG_SHORTPRE; | ||
145 | } | ||
146 | |||
147 | static void wl1251_rx_body(struct wl1251 *wl, | ||
148 | struct wl1251_rx_descriptor *desc) | ||
149 | { | ||
150 | struct sk_buff *skb; | ||
151 | struct ieee80211_rx_status status; | ||
152 | u8 *rx_buffer, beacon = 0; | ||
153 | u16 length, *fc; | ||
154 | u32 curr_id, last_id_inc, rx_packet_ring_addr; | ||
155 | |||
156 | length = WL1251_RX_ALIGN(desc->length - PLCP_HEADER_LENGTH); | ||
157 | curr_id = (desc->flags & RX_DESC_SEQNUM_MASK) >> RX_DESC_PACKETID_SHIFT; | ||
158 | last_id_inc = (wl->rx_last_id + 1) % (RX_MAX_PACKET_ID + 1); | ||
159 | |||
160 | if (last_id_inc != curr_id) { | ||
161 | wl1251_warning("curr ID:%d, last ID inc:%d", | ||
162 | curr_id, last_id_inc); | ||
163 | wl->rx_last_id = curr_id; | ||
164 | } else { | ||
165 | wl->rx_last_id = last_id_inc; | ||
166 | } | ||
167 | |||
168 | rx_packet_ring_addr = wl->data_path->rx_packet_ring_addr + | ||
169 | sizeof(struct wl1251_rx_descriptor) + 20; | ||
170 | if (wl->rx_current_buffer) | ||
171 | rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size; | ||
172 | |||
173 | skb = __dev_alloc_skb(length, GFP_KERNEL); | ||
174 | if (!skb) { | ||
175 | wl1251_error("Couldn't allocate RX frame"); | ||
176 | return; | ||
177 | } | ||
178 | |||
179 | rx_buffer = skb_put(skb, length); | ||
180 | wl1251_mem_read(wl, rx_packet_ring_addr, rx_buffer, length); | ||
181 | |||
182 | /* The actual length doesn't include the target's alignment */ | ||
183 | skb->len = desc->length - PLCP_HEADER_LENGTH; | ||
184 | |||
185 | fc = (u16 *)skb->data; | ||
186 | |||
187 | if ((*fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) | ||
188 | beacon = 1; | ||
189 | |||
190 | wl1251_rx_status(wl, desc, &status, beacon); | ||
191 | |||
192 | wl1251_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len, | ||
193 | beacon ? "beacon" : ""); | ||
194 | |||
195 | memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); | ||
196 | ieee80211_rx_ni(wl->hw, skb); | ||
197 | } | ||
198 | |||
199 | static void wl1251_rx_ack(struct wl1251 *wl) | ||
200 | { | ||
201 | u32 data, addr; | ||
202 | |||
203 | if (wl->rx_current_buffer) { | ||
204 | addr = ACX_REG_INTERRUPT_TRIG_H; | ||
205 | data = INTR_TRIG_RX_PROC1; | ||
206 | } else { | ||
207 | addr = ACX_REG_INTERRUPT_TRIG; | ||
208 | data = INTR_TRIG_RX_PROC0; | ||
209 | } | ||
210 | |||
211 | wl1251_reg_write32(wl, addr, data); | ||
212 | |||
213 | /* Toggle buffer ring */ | ||
214 | wl->rx_current_buffer = !wl->rx_current_buffer; | ||
215 | } | ||
216 | |||
217 | |||
218 | void wl1251_rx(struct wl1251 *wl) | ||
219 | { | ||
220 | struct wl1251_rx_descriptor *rx_desc; | ||
221 | |||
222 | if (wl->state != WL1251_STATE_ON) | ||
223 | return; | ||
224 | |||
225 | rx_desc = wl->rx_descriptor; | ||
226 | |||
227 | /* We first read the frame's header */ | ||
228 | wl1251_rx_header(wl, rx_desc); | ||
229 | |||
230 | /* Now we can read the body */ | ||
231 | wl1251_rx_body(wl, rx_desc); | ||
232 | |||
233 | /* Finally, we need to ACK the RX */ | ||
234 | wl1251_rx_ack(wl); | ||
235 | } | ||
diff --git a/drivers/net/wireless/ti/wl1251/rx.h b/drivers/net/wireless/ti/wl1251/rx.h new file mode 100644 index 000000000000..4448f635a4d8 --- /dev/null +++ b/drivers/net/wireless/ti/wl1251/rx.h | |||
@@ -0,0 +1,122 @@ | |||
1 | /* | ||
2 | * This file is part of wl1251 | ||
3 | * | ||
4 | * Copyright (c) 1998-2007 Texas Instruments Incorporated | ||
5 | * Copyright (C) 2008 Nokia Corporation | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * version 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
19 | * 02110-1301 USA | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #ifndef __WL1251_RX_H__ | ||
24 | #define __WL1251_RX_H__ | ||
25 | |||
26 | #include <linux/bitops.h> | ||
27 | |||
28 | #include "wl1251.h" | ||
29 | |||
30 | /* | ||
31 | * RX PATH | ||
32 | * | ||
33 | * The Rx path uses a double buffer and an rx_contro structure, each located | ||
34 | * at a fixed address in the device memory. The host keeps track of which | ||
35 | * buffer is available and alternates between them on a per packet basis. | ||
36 | * The size of each of the two buffers is large enough to hold the longest | ||
37 | * 802.3 packet. | ||
38 | * The RX path goes like that: | ||
39 | * 1) The target generates an interrupt each time a new packet is received. | ||
40 | * There are 2 RX interrupts, one for each buffer. | ||
41 | * 2) The host reads the received packet from one of the double buffers. | ||
42 | * 3) The host triggers a target interrupt. | ||
43 | * 4) The target prepares the next RX packet. | ||
44 | */ | ||
45 | |||
46 | #define WL1251_RX_MAX_RSSI -30 | ||
47 | #define WL1251_RX_MIN_RSSI -95 | ||
48 | |||
49 | #define WL1251_RX_ALIGN_TO 4 | ||
50 | #define WL1251_RX_ALIGN(len) (((len) + WL1251_RX_ALIGN_TO - 1) & \ | ||
51 | ~(WL1251_RX_ALIGN_TO - 1)) | ||
52 | |||
53 | #define SHORT_PREAMBLE_BIT BIT(0) | ||
54 | #define OFDM_RATE_BIT BIT(6) | ||
55 | #define PBCC_RATE_BIT BIT(7) | ||
56 | |||
57 | #define PLCP_HEADER_LENGTH 8 | ||
58 | #define RX_DESC_PACKETID_SHIFT 11 | ||
59 | #define RX_MAX_PACKET_ID 3 | ||
60 | |||
61 | #define RX_DESC_VALID_FCS 0x0001 | ||
62 | #define RX_DESC_MATCH_RXADDR1 0x0002 | ||
63 | #define RX_DESC_MCAST 0x0004 | ||
64 | #define RX_DESC_STAINTIM 0x0008 | ||
65 | #define RX_DESC_VIRTUAL_BM 0x0010 | ||
66 | #define RX_DESC_BCAST 0x0020 | ||
67 | #define RX_DESC_MATCH_SSID 0x0040 | ||
68 | #define RX_DESC_MATCH_BSSID 0x0080 | ||
69 | #define RX_DESC_ENCRYPTION_MASK 0x0300 | ||
70 | #define RX_DESC_MEASURMENT 0x0400 | ||
71 | #define RX_DESC_SEQNUM_MASK 0x1800 | ||
72 | #define RX_DESC_MIC_FAIL 0x2000 | ||
73 | #define RX_DESC_DECRYPT_FAIL 0x4000 | ||
74 | |||
75 | struct wl1251_rx_descriptor { | ||
76 | u32 timestamp; /* In microseconds */ | ||
77 | u16 length; /* Paylod length, including headers */ | ||
78 | u16 flags; | ||
79 | |||
80 | /* | ||
81 | * 0 - 802.11 | ||
82 | * 1 - 802.3 | ||
83 | * 2 - IP | ||
84 | * 3 - Raw Codec | ||
85 | */ | ||
86 | u8 type; | ||
87 | |||
88 | /* | ||
89 | * Received Rate: | ||
90 | * 0x0A - 1MBPS | ||
91 | * 0x14 - 2MBPS | ||
92 | * 0x37 - 5_5MBPS | ||
93 | * 0x0B - 6MBPS | ||
94 | * 0x0F - 9MBPS | ||
95 | * 0x6E - 11MBPS | ||
96 | * 0x0A - 12MBPS | ||
97 | * 0x0E - 18MBPS | ||
98 | * 0xDC - 22MBPS | ||
99 | * 0x09 - 24MBPS | ||
100 | * 0x0D - 36MBPS | ||
101 | * 0x08 - 48MBPS | ||
102 | * 0x0C - 54MBPS | ||
103 | */ | ||
104 | u8 rate; | ||
105 | |||
106 | u8 mod_pre; /* Modulation and preamble */ | ||
107 | u8 channel; | ||
108 | |||
109 | /* | ||
110 | * 0 - 2.4 Ghz | ||
111 | * 1 - 5 Ghz | ||
112 | */ | ||
113 | u8 band; | ||
114 | |||
115 | s8 rssi; /* in dB */ | ||
116 | u8 rcpi; /* in dB */ | ||
117 | u8 snr; /* in dB */ | ||
118 | } __packed; | ||
119 | |||
120 | void wl1251_rx(struct wl1251 *wl); | ||
121 | |||
122 | #endif | ||
diff --git a/drivers/net/wireless/ti/wl1251/sdio.c b/drivers/net/wireless/ti/wl1251/sdio.c new file mode 100644 index 000000000000..f78694295c39 --- /dev/null +++ b/drivers/net/wireless/ti/wl1251/sdio.c | |||
@@ -0,0 +1,374 @@ | |||
1 | /* | ||
2 | * wl12xx SDIO routines | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, but | ||
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
11 | * General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program; if not, write to the Free Software | ||
15 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
16 | * 02110-1301 USA | ||
17 | * | ||
18 | * Copyright (C) 2005 Texas Instruments Incorporated | ||
19 | * Copyright (C) 2008 Google Inc | ||
20 | * Copyright (C) 2009 Bob Copeland (me@bobcopeland.com) | ||
21 | */ | ||
22 | #include <linux/interrupt.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/mod_devicetable.h> | ||
25 | #include <linux/mmc/sdio_func.h> | ||
26 | #include <linux/mmc/sdio_ids.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | #include <linux/wl12xx.h> | ||
29 | #include <linux/irq.h> | ||
30 | #include <linux/pm_runtime.h> | ||
31 | |||
32 | #include "wl1251.h" | ||
33 | |||
34 | #ifndef SDIO_VENDOR_ID_TI | ||
35 | #define SDIO_VENDOR_ID_TI 0x104c | ||
36 | #endif | ||
37 | |||
38 | #ifndef SDIO_DEVICE_ID_TI_WL1251 | ||
39 | #define SDIO_DEVICE_ID_TI_WL1251 0x9066 | ||
40 | #endif | ||
41 | |||
42 | struct wl1251_sdio { | ||
43 | struct sdio_func *func; | ||
44 | u32 elp_val; | ||
45 | }; | ||
46 | |||
47 | static struct sdio_func *wl_to_func(struct wl1251 *wl) | ||
48 | { | ||
49 | struct wl1251_sdio *wl_sdio = wl->if_priv; | ||
50 | return wl_sdio->func; | ||
51 | } | ||
52 | |||
53 | static void wl1251_sdio_interrupt(struct sdio_func *func) | ||
54 | { | ||
55 | struct wl1251 *wl = sdio_get_drvdata(func); | ||
56 | |||
57 | wl1251_debug(DEBUG_IRQ, "IRQ"); | ||
58 | |||
59 | /* FIXME should be synchronous for sdio */ | ||
60 | ieee80211_queue_work(wl->hw, &wl->irq_work); | ||
61 | } | ||
62 | |||
63 | static const struct sdio_device_id wl1251_devices[] = { | ||
64 | { SDIO_DEVICE(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1251) }, | ||
65 | {} | ||
66 | }; | ||
67 | MODULE_DEVICE_TABLE(sdio, wl1251_devices); | ||
68 | |||
69 | |||
70 | static void wl1251_sdio_read(struct wl1251 *wl, int addr, | ||
71 | void *buf, size_t len) | ||
72 | { | ||
73 | int ret; | ||
74 | struct sdio_func *func = wl_to_func(wl); | ||
75 | |||
76 | sdio_claim_host(func); | ||
77 | ret = sdio_memcpy_fromio(func, buf, addr, len); | ||
78 | if (ret) | ||
79 | wl1251_error("sdio read failed (%d)", ret); | ||
80 | sdio_release_host(func); | ||
81 | } | ||
82 | |||
83 | static void wl1251_sdio_write(struct wl1251 *wl, int addr, | ||
84 | void *buf, size_t len) | ||
85 | { | ||
86 | int ret; | ||
87 | struct sdio_func *func = wl_to_func(wl); | ||
88 | |||
89 | sdio_claim_host(func); | ||
90 | ret = sdio_memcpy_toio(func, addr, buf, len); | ||
91 | if (ret) | ||
92 | wl1251_error("sdio write failed (%d)", ret); | ||
93 | sdio_release_host(func); | ||
94 | } | ||
95 | |||
96 | static void wl1251_sdio_read_elp(struct wl1251 *wl, int addr, u32 *val) | ||
97 | { | ||
98 | int ret = 0; | ||
99 | struct wl1251_sdio *wl_sdio = wl->if_priv; | ||
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 | */ | ||
108 | sdio_claim_host(func); | ||
109 | *val = sdio_writeb_readb(func, wl_sdio->elp_val, addr, &ret); | ||
110 | sdio_release_host(func); | ||
111 | |||
112 | if (ret) | ||
113 | wl1251_error("sdio_readb failed (%d)", ret); | ||
114 | } | ||
115 | |||
116 | static void wl1251_sdio_write_elp(struct wl1251 *wl, int addr, u32 val) | ||
117 | { | ||
118 | int ret = 0; | ||
119 | struct wl1251_sdio *wl_sdio = wl->if_priv; | ||
120 | struct sdio_func *func = wl_sdio->func; | ||
121 | |||
122 | sdio_claim_host(func); | ||
123 | sdio_writeb(func, val, addr, &ret); | ||
124 | sdio_release_host(func); | ||
125 | |||
126 | if (ret) | ||
127 | wl1251_error("sdio_writeb failed (%d)", ret); | ||
128 | else | ||
129 | wl_sdio->elp_val = val; | ||
130 | } | ||
131 | |||
132 | static void wl1251_sdio_reset(struct wl1251 *wl) | ||
133 | { | ||
134 | } | ||
135 | |||
136 | static void wl1251_sdio_enable_irq(struct wl1251 *wl) | ||
137 | { | ||
138 | struct sdio_func *func = wl_to_func(wl); | ||
139 | |||
140 | sdio_claim_host(func); | ||
141 | sdio_claim_irq(func, wl1251_sdio_interrupt); | ||
142 | sdio_release_host(func); | ||
143 | } | ||
144 | |||
145 | static void wl1251_sdio_disable_irq(struct wl1251 *wl) | ||
146 | { | ||
147 | struct sdio_func *func = wl_to_func(wl); | ||
148 | |||
149 | sdio_claim_host(func); | ||
150 | sdio_release_irq(func); | ||
151 | sdio_release_host(func); | ||
152 | } | ||
153 | |||
154 | /* Interrupts when using dedicated WLAN_IRQ pin */ | ||
155 | static irqreturn_t wl1251_line_irq(int irq, void *cookie) | ||
156 | { | ||
157 | struct wl1251 *wl = cookie; | ||
158 | |||
159 | ieee80211_queue_work(wl->hw, &wl->irq_work); | ||
160 | |||
161 | return IRQ_HANDLED; | ||
162 | } | ||
163 | |||
164 | static void wl1251_enable_line_irq(struct wl1251 *wl) | ||
165 | { | ||
166 | return enable_irq(wl->irq); | ||
167 | } | ||
168 | |||
169 | static void wl1251_disable_line_irq(struct wl1251 *wl) | ||
170 | { | ||
171 | return disable_irq(wl->irq); | ||
172 | } | ||
173 | |||
174 | static int wl1251_sdio_set_power(struct wl1251 *wl, bool enable) | ||
175 | { | ||
176 | struct sdio_func *func = wl_to_func(wl); | ||
177 | int ret; | ||
178 | |||
179 | if (enable) { | ||
180 | /* | ||
181 | * Power is controlled by runtime PM, but we still call board | ||
182 | * callback in case it wants to do any additional setup, | ||
183 | * for example enabling clock buffer for the module. | ||
184 | */ | ||
185 | if (wl->set_power) | ||
186 | wl->set_power(true); | ||
187 | |||
188 | ret = pm_runtime_get_sync(&func->dev); | ||
189 | if (ret < 0) | ||
190 | goto out; | ||
191 | |||
192 | sdio_claim_host(func); | ||
193 | sdio_enable_func(func); | ||
194 | sdio_release_host(func); | ||
195 | } else { | ||
196 | sdio_claim_host(func); | ||
197 | sdio_disable_func(func); | ||
198 | sdio_release_host(func); | ||
199 | |||
200 | ret = pm_runtime_put_sync(&func->dev); | ||
201 | if (ret < 0) | ||
202 | goto out; | ||
203 | |||
204 | if (wl->set_power) | ||
205 | wl->set_power(false); | ||
206 | } | ||
207 | |||
208 | out: | ||
209 | return ret; | ||
210 | } | ||
211 | |||
212 | static struct wl1251_if_operations wl1251_sdio_ops = { | ||
213 | .read = wl1251_sdio_read, | ||
214 | .write = wl1251_sdio_write, | ||
215 | .write_elp = wl1251_sdio_write_elp, | ||
216 | .read_elp = wl1251_sdio_read_elp, | ||
217 | .reset = wl1251_sdio_reset, | ||
218 | .power = wl1251_sdio_set_power, | ||
219 | }; | ||
220 | |||
221 | static int wl1251_sdio_probe(struct sdio_func *func, | ||
222 | const struct sdio_device_id *id) | ||
223 | { | ||
224 | int ret; | ||
225 | struct wl1251 *wl; | ||
226 | struct ieee80211_hw *hw; | ||
227 | struct wl1251_sdio *wl_sdio; | ||
228 | const struct wl12xx_platform_data *wl12xx_board_data; | ||
229 | |||
230 | hw = wl1251_alloc_hw(); | ||
231 | if (IS_ERR(hw)) | ||
232 | return PTR_ERR(hw); | ||
233 | |||
234 | wl = hw->priv; | ||
235 | |||
236 | wl_sdio = kzalloc(sizeof(*wl_sdio), GFP_KERNEL); | ||
237 | if (wl_sdio == NULL) { | ||
238 | ret = -ENOMEM; | ||
239 | goto out_free_hw; | ||
240 | } | ||
241 | |||
242 | sdio_claim_host(func); | ||
243 | ret = sdio_enable_func(func); | ||
244 | if (ret) | ||
245 | goto release; | ||
246 | |||
247 | sdio_set_block_size(func, 512); | ||
248 | sdio_release_host(func); | ||
249 | |||
250 | SET_IEEE80211_DEV(hw, &func->dev); | ||
251 | wl_sdio->func = func; | ||
252 | wl->if_priv = wl_sdio; | ||
253 | wl->if_ops = &wl1251_sdio_ops; | ||
254 | |||
255 | wl12xx_board_data = wl12xx_get_platform_data(); | ||
256 | if (!IS_ERR(wl12xx_board_data)) { | ||
257 | wl->set_power = wl12xx_board_data->set_power; | ||
258 | wl->irq = wl12xx_board_data->irq; | ||
259 | wl->use_eeprom = wl12xx_board_data->use_eeprom; | ||
260 | } | ||
261 | |||
262 | if (wl->irq) { | ||
263 | ret = request_irq(wl->irq, wl1251_line_irq, 0, "wl1251", wl); | ||
264 | if (ret < 0) { | ||
265 | wl1251_error("request_irq() failed: %d", ret); | ||
266 | goto disable; | ||
267 | } | ||
268 | |||
269 | irq_set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); | ||
270 | disable_irq(wl->irq); | ||
271 | |||
272 | wl1251_sdio_ops.enable_irq = wl1251_enable_line_irq; | ||
273 | wl1251_sdio_ops.disable_irq = wl1251_disable_line_irq; | ||
274 | |||
275 | wl1251_info("using dedicated interrupt line"); | ||
276 | } else { | ||
277 | wl1251_sdio_ops.enable_irq = wl1251_sdio_enable_irq; | ||
278 | wl1251_sdio_ops.disable_irq = wl1251_sdio_disable_irq; | ||
279 | |||
280 | wl1251_info("using SDIO interrupt"); | ||
281 | } | ||
282 | |||
283 | ret = wl1251_init_ieee80211(wl); | ||
284 | if (ret) | ||
285 | goto out_free_irq; | ||
286 | |||
287 | sdio_set_drvdata(func, wl); | ||
288 | |||
289 | /* Tell PM core that we don't need the card to be powered now */ | ||
290 | pm_runtime_put_noidle(&func->dev); | ||
291 | |||
292 | return ret; | ||
293 | |||
294 | out_free_irq: | ||
295 | if (wl->irq) | ||
296 | free_irq(wl->irq, wl); | ||
297 | disable: | ||
298 | sdio_claim_host(func); | ||
299 | sdio_disable_func(func); | ||
300 | release: | ||
301 | sdio_release_host(func); | ||
302 | kfree(wl_sdio); | ||
303 | out_free_hw: | ||
304 | wl1251_free_hw(wl); | ||
305 | return ret; | ||
306 | } | ||
307 | |||
308 | static void __devexit wl1251_sdio_remove(struct sdio_func *func) | ||
309 | { | ||
310 | struct wl1251 *wl = sdio_get_drvdata(func); | ||
311 | struct wl1251_sdio *wl_sdio = wl->if_priv; | ||
312 | |||
313 | /* Undo decrement done above in wl1251_probe */ | ||
314 | pm_runtime_get_noresume(&func->dev); | ||
315 | |||
316 | if (wl->irq) | ||
317 | free_irq(wl->irq, wl); | ||
318 | kfree(wl_sdio); | ||
319 | wl1251_free_hw(wl); | ||
320 | |||
321 | sdio_claim_host(func); | ||
322 | sdio_release_irq(func); | ||
323 | sdio_disable_func(func); | ||
324 | sdio_release_host(func); | ||
325 | } | ||
326 | |||
327 | static int wl1251_suspend(struct device *dev) | ||
328 | { | ||
329 | /* | ||
330 | * Tell MMC/SDIO core it's OK to power down the card | ||
331 | * (if it isn't already), but not to remove it completely. | ||
332 | */ | ||
333 | return 0; | ||
334 | } | ||
335 | |||
336 | static int wl1251_resume(struct device *dev) | ||
337 | { | ||
338 | return 0; | ||
339 | } | ||
340 | |||
341 | static const struct dev_pm_ops wl1251_sdio_pm_ops = { | ||
342 | .suspend = wl1251_suspend, | ||
343 | .resume = wl1251_resume, | ||
344 | }; | ||
345 | |||
346 | static struct sdio_driver wl1251_sdio_driver = { | ||
347 | .name = "wl1251_sdio", | ||
348 | .id_table = wl1251_devices, | ||
349 | .probe = wl1251_sdio_probe, | ||
350 | .remove = __devexit_p(wl1251_sdio_remove), | ||
351 | .drv.pm = &wl1251_sdio_pm_ops, | ||
352 | }; | ||
353 | |||
354 | static int __init wl1251_sdio_init(void) | ||
355 | { | ||
356 | int err; | ||
357 | |||
358 | err = sdio_register_driver(&wl1251_sdio_driver); | ||
359 | if (err) | ||
360 | wl1251_error("failed to register sdio driver: %d", err); | ||
361 | return err; | ||
362 | } | ||
363 | |||
364 | static void __exit wl1251_sdio_exit(void) | ||
365 | { | ||
366 | sdio_unregister_driver(&wl1251_sdio_driver); | ||
367 | wl1251_notice("unloaded"); | ||
368 | } | ||
369 | |||
370 | module_init(wl1251_sdio_init); | ||
371 | module_exit(wl1251_sdio_exit); | ||
372 | |||
373 | MODULE_LICENSE("GPL"); | ||
374 | MODULE_AUTHOR("Kalle Valo <kvalo@adurom.com>"); | ||
diff --git a/drivers/net/wireless/ti/wl1251/spi.c b/drivers/net/wireless/ti/wl1251/spi.c new file mode 100644 index 000000000000..6248c354fc5c --- /dev/null +++ b/drivers/net/wireless/ti/wl1251/spi.c | |||
@@ -0,0 +1,355 @@ | |||
1 | /* | ||
2 | * This file is part of wl1251 | ||
3 | * | ||
4 | * Copyright (C) 2008 Nokia Corporation | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * version 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
18 | * 02110-1301 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include <linux/interrupt.h> | ||
23 | #include <linux/irq.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/crc7.h> | ||
27 | #include <linux/spi/spi.h> | ||
28 | #include <linux/wl12xx.h> | ||
29 | |||
30 | #include "wl1251.h" | ||
31 | #include "reg.h" | ||
32 | #include "spi.h" | ||
33 | |||
34 | static irqreturn_t wl1251_irq(int irq, void *cookie) | ||
35 | { | ||
36 | struct wl1251 *wl; | ||
37 | |||
38 | wl1251_debug(DEBUG_IRQ, "IRQ"); | ||
39 | |||
40 | wl = cookie; | ||
41 | |||
42 | ieee80211_queue_work(wl->hw, &wl->irq_work); | ||
43 | |||
44 | return IRQ_HANDLED; | ||
45 | } | ||
46 | |||
47 | static struct spi_device *wl_to_spi(struct wl1251 *wl) | ||
48 | { | ||
49 | return wl->if_priv; | ||
50 | } | ||
51 | |||
52 | static void wl1251_spi_reset(struct wl1251 *wl) | ||
53 | { | ||
54 | u8 *cmd; | ||
55 | struct spi_transfer t; | ||
56 | struct spi_message m; | ||
57 | |||
58 | cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); | ||
59 | if (!cmd) { | ||
60 | wl1251_error("could not allocate cmd for spi reset"); | ||
61 | return; | ||
62 | } | ||
63 | |||
64 | memset(&t, 0, sizeof(t)); | ||
65 | spi_message_init(&m); | ||
66 | |||
67 | memset(cmd, 0xff, WSPI_INIT_CMD_LEN); | ||
68 | |||
69 | t.tx_buf = cmd; | ||
70 | t.len = WSPI_INIT_CMD_LEN; | ||
71 | spi_message_add_tail(&t, &m); | ||
72 | |||
73 | spi_sync(wl_to_spi(wl), &m); | ||
74 | |||
75 | wl1251_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); | ||
76 | } | ||
77 | |||
78 | static void wl1251_spi_wake(struct wl1251 *wl) | ||
79 | { | ||
80 | u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd; | ||
81 | struct spi_transfer t; | ||
82 | struct spi_message m; | ||
83 | |||
84 | cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); | ||
85 | if (!cmd) { | ||
86 | wl1251_error("could not allocate cmd for spi init"); | ||
87 | return; | ||
88 | } | ||
89 | |||
90 | memset(crc, 0, sizeof(crc)); | ||
91 | memset(&t, 0, sizeof(t)); | ||
92 | spi_message_init(&m); | ||
93 | |||
94 | /* | ||
95 | * Set WSPI_INIT_COMMAND | ||
96 | * the data is being send from the MSB to LSB | ||
97 | */ | ||
98 | cmd[2] = 0xff; | ||
99 | cmd[3] = 0xff; | ||
100 | cmd[1] = WSPI_INIT_CMD_START | WSPI_INIT_CMD_TX; | ||
101 | cmd[0] = 0; | ||
102 | cmd[7] = 0; | ||
103 | cmd[6] |= HW_ACCESS_WSPI_INIT_CMD_MASK << 3; | ||
104 | cmd[6] |= HW_ACCESS_WSPI_FIXED_BUSY_LEN & WSPI_INIT_CMD_FIXEDBUSY_LEN; | ||
105 | |||
106 | if (HW_ACCESS_WSPI_FIXED_BUSY_LEN == 0) | ||
107 | cmd[5] |= WSPI_INIT_CMD_DIS_FIXEDBUSY; | ||
108 | else | ||
109 | cmd[5] |= WSPI_INIT_CMD_EN_FIXEDBUSY; | ||
110 | |||
111 | cmd[5] |= WSPI_INIT_CMD_IOD | WSPI_INIT_CMD_IP | WSPI_INIT_CMD_CS | ||
112 | | WSPI_INIT_CMD_WSPI | WSPI_INIT_CMD_WS; | ||
113 | |||
114 | crc[0] = cmd[1]; | ||
115 | crc[1] = cmd[0]; | ||
116 | crc[2] = cmd[7]; | ||
117 | crc[3] = cmd[6]; | ||
118 | crc[4] = cmd[5]; | ||
119 | |||
120 | cmd[4] |= crc7(0, crc, WSPI_INIT_CMD_CRC_LEN) << 1; | ||
121 | cmd[4] |= WSPI_INIT_CMD_END; | ||
122 | |||
123 | t.tx_buf = cmd; | ||
124 | t.len = WSPI_INIT_CMD_LEN; | ||
125 | spi_message_add_tail(&t, &m); | ||
126 | |||
127 | spi_sync(wl_to_spi(wl), &m); | ||
128 | |||
129 | wl1251_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN); | ||
130 | } | ||
131 | |||
132 | static void wl1251_spi_reset_wake(struct wl1251 *wl) | ||
133 | { | ||
134 | wl1251_spi_reset(wl); | ||
135 | wl1251_spi_wake(wl); | ||
136 | } | ||
137 | |||
138 | static void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, | ||
139 | size_t len) | ||
140 | { | ||
141 | struct spi_transfer t[3]; | ||
142 | struct spi_message m; | ||
143 | u8 *busy_buf; | ||
144 | u32 *cmd; | ||
145 | |||
146 | cmd = &wl->buffer_cmd; | ||
147 | busy_buf = wl->buffer_busyword; | ||
148 | |||
149 | *cmd = 0; | ||
150 | *cmd |= WSPI_CMD_READ; | ||
151 | *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; | ||
152 | *cmd |= addr & WSPI_CMD_BYTE_ADDR; | ||
153 | |||
154 | spi_message_init(&m); | ||
155 | memset(t, 0, sizeof(t)); | ||
156 | |||
157 | t[0].tx_buf = cmd; | ||
158 | t[0].len = 4; | ||
159 | spi_message_add_tail(&t[0], &m); | ||
160 | |||
161 | /* Busy and non busy words read */ | ||
162 | t[1].rx_buf = busy_buf; | ||
163 | t[1].len = WL1251_BUSY_WORD_LEN; | ||
164 | spi_message_add_tail(&t[1], &m); | ||
165 | |||
166 | t[2].rx_buf = buf; | ||
167 | t[2].len = len; | ||
168 | spi_message_add_tail(&t[2], &m); | ||
169 | |||
170 | spi_sync(wl_to_spi(wl), &m); | ||
171 | |||
172 | /* FIXME: check busy words */ | ||
173 | |||
174 | wl1251_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd)); | ||
175 | wl1251_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); | ||
176 | } | ||
177 | |||
178 | static void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, | ||
179 | size_t len) | ||
180 | { | ||
181 | struct spi_transfer t[2]; | ||
182 | struct spi_message m; | ||
183 | u32 *cmd; | ||
184 | |||
185 | cmd = &wl->buffer_cmd; | ||
186 | |||
187 | *cmd = 0; | ||
188 | *cmd |= WSPI_CMD_WRITE; | ||
189 | *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; | ||
190 | *cmd |= addr & WSPI_CMD_BYTE_ADDR; | ||
191 | |||
192 | spi_message_init(&m); | ||
193 | memset(t, 0, sizeof(t)); | ||
194 | |||
195 | t[0].tx_buf = cmd; | ||
196 | t[0].len = sizeof(*cmd); | ||
197 | spi_message_add_tail(&t[0], &m); | ||
198 | |||
199 | t[1].tx_buf = buf; | ||
200 | t[1].len = len; | ||
201 | spi_message_add_tail(&t[1], &m); | ||
202 | |||
203 | spi_sync(wl_to_spi(wl), &m); | ||
204 | |||
205 | wl1251_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); | ||
206 | wl1251_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); | ||
207 | } | ||
208 | |||
209 | static void wl1251_spi_enable_irq(struct wl1251 *wl) | ||
210 | { | ||
211 | return enable_irq(wl->irq); | ||
212 | } | ||
213 | |||
214 | static void wl1251_spi_disable_irq(struct wl1251 *wl) | ||
215 | { | ||
216 | return disable_irq(wl->irq); | ||
217 | } | ||
218 | |||
219 | static int wl1251_spi_set_power(struct wl1251 *wl, bool enable) | ||
220 | { | ||
221 | if (wl->set_power) | ||
222 | wl->set_power(enable); | ||
223 | |||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | static const struct wl1251_if_operations wl1251_spi_ops = { | ||
228 | .read = wl1251_spi_read, | ||
229 | .write = wl1251_spi_write, | ||
230 | .reset = wl1251_spi_reset_wake, | ||
231 | .enable_irq = wl1251_spi_enable_irq, | ||
232 | .disable_irq = wl1251_spi_disable_irq, | ||
233 | .power = wl1251_spi_set_power, | ||
234 | }; | ||
235 | |||
236 | static int __devinit wl1251_spi_probe(struct spi_device *spi) | ||
237 | { | ||
238 | struct wl12xx_platform_data *pdata; | ||
239 | struct ieee80211_hw *hw; | ||
240 | struct wl1251 *wl; | ||
241 | int ret; | ||
242 | |||
243 | pdata = spi->dev.platform_data; | ||
244 | if (!pdata) { | ||
245 | wl1251_error("no platform data"); | ||
246 | return -ENODEV; | ||
247 | } | ||
248 | |||
249 | hw = wl1251_alloc_hw(); | ||
250 | if (IS_ERR(hw)) | ||
251 | return PTR_ERR(hw); | ||
252 | |||
253 | wl = hw->priv; | ||
254 | |||
255 | SET_IEEE80211_DEV(hw, &spi->dev); | ||
256 | dev_set_drvdata(&spi->dev, wl); | ||
257 | wl->if_priv = spi; | ||
258 | wl->if_ops = &wl1251_spi_ops; | ||
259 | |||
260 | /* This is the only SPI value that we need to set here, the rest | ||
261 | * comes from the board-peripherals file */ | ||
262 | spi->bits_per_word = 32; | ||
263 | |||
264 | ret = spi_setup(spi); | ||
265 | if (ret < 0) { | ||
266 | wl1251_error("spi_setup failed"); | ||
267 | goto out_free; | ||
268 | } | ||
269 | |||
270 | wl->set_power = pdata->set_power; | ||
271 | if (!wl->set_power) { | ||
272 | wl1251_error("set power function missing in platform data"); | ||
273 | return -ENODEV; | ||
274 | } | ||
275 | |||
276 | wl->irq = spi->irq; | ||
277 | if (wl->irq < 0) { | ||
278 | wl1251_error("irq missing in platform data"); | ||
279 | return -ENODEV; | ||
280 | } | ||
281 | |||
282 | wl->use_eeprom = pdata->use_eeprom; | ||
283 | |||
284 | ret = request_irq(wl->irq, wl1251_irq, 0, DRIVER_NAME, wl); | ||
285 | if (ret < 0) { | ||
286 | wl1251_error("request_irq() failed: %d", ret); | ||
287 | goto out_free; | ||
288 | } | ||
289 | |||
290 | irq_set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); | ||
291 | |||
292 | disable_irq(wl->irq); | ||
293 | |||
294 | ret = wl1251_init_ieee80211(wl); | ||
295 | if (ret) | ||
296 | goto out_irq; | ||
297 | |||
298 | return 0; | ||
299 | |||
300 | out_irq: | ||
301 | free_irq(wl->irq, wl); | ||
302 | |||
303 | out_free: | ||
304 | ieee80211_free_hw(hw); | ||
305 | |||
306 | return ret; | ||
307 | } | ||
308 | |||
309 | static int __devexit wl1251_spi_remove(struct spi_device *spi) | ||
310 | { | ||
311 | struct wl1251 *wl = dev_get_drvdata(&spi->dev); | ||
312 | |||
313 | free_irq(wl->irq, wl); | ||
314 | wl1251_free_hw(wl); | ||
315 | |||
316 | return 0; | ||
317 | } | ||
318 | |||
319 | static struct spi_driver wl1251_spi_driver = { | ||
320 | .driver = { | ||
321 | .name = DRIVER_NAME, | ||
322 | .owner = THIS_MODULE, | ||
323 | }, | ||
324 | |||
325 | .probe = wl1251_spi_probe, | ||
326 | .remove = __devexit_p(wl1251_spi_remove), | ||
327 | }; | ||
328 | |||
329 | static int __init wl1251_spi_init(void) | ||
330 | { | ||
331 | int ret; | ||
332 | |||
333 | ret = spi_register_driver(&wl1251_spi_driver); | ||
334 | if (ret < 0) { | ||
335 | wl1251_error("failed to register spi driver: %d", ret); | ||
336 | goto out; | ||
337 | } | ||
338 | |||
339 | out: | ||
340 | return ret; | ||
341 | } | ||
342 | |||
343 | static void __exit wl1251_spi_exit(void) | ||
344 | { | ||
345 | spi_unregister_driver(&wl1251_spi_driver); | ||
346 | |||
347 | wl1251_notice("unloaded"); | ||
348 | } | ||
349 | |||
350 | module_init(wl1251_spi_init); | ||
351 | module_exit(wl1251_spi_exit); | ||
352 | |||
353 | MODULE_LICENSE("GPL"); | ||
354 | MODULE_AUTHOR("Kalle Valo <kvalo@adurom.com>"); | ||
355 | MODULE_ALIAS("spi:wl1251"); | ||
diff --git a/drivers/net/wireless/ti/wl1251/spi.h b/drivers/net/wireless/ti/wl1251/spi.h new file mode 100644 index 000000000000..16d506955cc0 --- /dev/null +++ b/drivers/net/wireless/ti/wl1251/spi.h | |||
@@ -0,0 +1,59 @@ | |||
1 | /* | ||
2 | * This file is part of wl1251 | ||
3 | * | ||
4 | * Copyright (c) 1998-2007 Texas Instruments Incorporated | ||
5 | * Copyright (C) 2008 Nokia Corporation | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * version 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
19 | * 02110-1301 USA | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #ifndef __WL1251_SPI_H__ | ||
24 | #define __WL1251_SPI_H__ | ||
25 | |||
26 | #include "cmd.h" | ||
27 | #include "acx.h" | ||
28 | #include "reg.h" | ||
29 | |||
30 | #define WSPI_CMD_READ 0x40000000 | ||
31 | #define WSPI_CMD_WRITE 0x00000000 | ||
32 | #define WSPI_CMD_FIXED 0x20000000 | ||
33 | #define WSPI_CMD_BYTE_LENGTH 0x1FFE0000 | ||
34 | #define WSPI_CMD_BYTE_LENGTH_OFFSET 17 | ||
35 | #define WSPI_CMD_BYTE_ADDR 0x0001FFFF | ||
36 | |||
37 | #define WSPI_INIT_CMD_CRC_LEN 5 | ||
38 | |||
39 | #define WSPI_INIT_CMD_START 0x00 | ||
40 | #define WSPI_INIT_CMD_TX 0x40 | ||
41 | /* the extra bypass bit is sampled by the TNET as '1' */ | ||
42 | #define WSPI_INIT_CMD_BYPASS_BIT 0x80 | ||
43 | #define WSPI_INIT_CMD_FIXEDBUSY_LEN 0x07 | ||
44 | #define WSPI_INIT_CMD_EN_FIXEDBUSY 0x80 | ||
45 | #define WSPI_INIT_CMD_DIS_FIXEDBUSY 0x00 | ||
46 | #define WSPI_INIT_CMD_IOD 0x40 | ||
47 | #define WSPI_INIT_CMD_IP 0x20 | ||
48 | #define WSPI_INIT_CMD_CS 0x10 | ||
49 | #define WSPI_INIT_CMD_WS 0x08 | ||
50 | #define WSPI_INIT_CMD_WSPI 0x01 | ||
51 | #define WSPI_INIT_CMD_END 0x01 | ||
52 | |||
53 | #define WSPI_INIT_CMD_LEN 8 | ||
54 | |||
55 | #define HW_ACCESS_WSPI_FIXED_BUSY_LEN \ | ||
56 | ((WL1251_BUSY_WORD_LEN - 4) / sizeof(u32)) | ||
57 | #define HW_ACCESS_WSPI_INIT_CMD_MASK 0 | ||
58 | |||
59 | #endif /* __WL1251_SPI_H__ */ | ||
diff --git a/drivers/net/wireless/ti/wl1251/tx.c b/drivers/net/wireless/ti/wl1251/tx.c new file mode 100644 index 000000000000..28121c590a2b --- /dev/null +++ b/drivers/net/wireless/ti/wl1251/tx.c | |||
@@ -0,0 +1,560 @@ | |||
1 | /* | ||
2 | * This file is part of wl1251 | ||
3 | * | ||
4 | * Copyright (c) 1998-2007 Texas Instruments Incorporated | ||
5 | * Copyright (C) 2008 Nokia Corporation | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * version 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
19 | * 02110-1301 USA | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/module.h> | ||
25 | |||
26 | #include "wl1251.h" | ||
27 | #include "reg.h" | ||
28 | #include "tx.h" | ||
29 | #include "ps.h" | ||
30 | #include "io.h" | ||
31 | |||
32 | static bool wl1251_tx_double_buffer_busy(struct wl1251 *wl, u32 data_out_count) | ||
33 | { | ||
34 | int used, data_in_count; | ||
35 | |||
36 | data_in_count = wl->data_in_count; | ||
37 | |||
38 | if (data_in_count < data_out_count) | ||
39 | /* data_in_count has wrapped */ | ||
40 | data_in_count += TX_STATUS_DATA_OUT_COUNT_MASK + 1; | ||
41 | |||
42 | used = data_in_count - data_out_count; | ||
43 | |||
44 | WARN_ON(used < 0); | ||
45 | WARN_ON(used > DP_TX_PACKET_RING_CHUNK_NUM); | ||
46 | |||
47 | if (used >= DP_TX_PACKET_RING_CHUNK_NUM) | ||
48 | return true; | ||
49 | else | ||
50 | return false; | ||
51 | } | ||
52 | |||
53 | static int wl1251_tx_path_status(struct wl1251 *wl) | ||
54 | { | ||
55 | u32 status, addr, data_out_count; | ||
56 | bool busy; | ||
57 | |||
58 | addr = wl->data_path->tx_control_addr; | ||
59 | status = wl1251_mem_read32(wl, addr); | ||
60 | data_out_count = status & TX_STATUS_DATA_OUT_COUNT_MASK; | ||
61 | busy = wl1251_tx_double_buffer_busy(wl, data_out_count); | ||
62 | |||
63 | if (busy) | ||
64 | return -EBUSY; | ||
65 | |||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | static int wl1251_tx_id(struct wl1251 *wl, struct sk_buff *skb) | ||
70 | { | ||
71 | int i; | ||
72 | |||
73 | for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) | ||
74 | if (wl->tx_frames[i] == NULL) { | ||
75 | wl->tx_frames[i] = skb; | ||
76 | return i; | ||
77 | } | ||
78 | |||
79 | return -EBUSY; | ||
80 | } | ||
81 | |||
82 | static void wl1251_tx_control(struct tx_double_buffer_desc *tx_hdr, | ||
83 | struct ieee80211_tx_info *control, u16 fc) | ||
84 | { | ||
85 | *(u16 *)&tx_hdr->control = 0; | ||
86 | |||
87 | tx_hdr->control.rate_policy = 0; | ||
88 | |||
89 | /* 802.11 packets */ | ||
90 | tx_hdr->control.packet_type = 0; | ||
91 | |||
92 | if (control->flags & IEEE80211_TX_CTL_NO_ACK) | ||
93 | tx_hdr->control.ack_policy = 1; | ||
94 | |||
95 | tx_hdr->control.tx_complete = 1; | ||
96 | |||
97 | if ((fc & IEEE80211_FTYPE_DATA) && | ||
98 | ((fc & IEEE80211_STYPE_QOS_DATA) || | ||
99 | (fc & IEEE80211_STYPE_QOS_NULLFUNC))) | ||
100 | tx_hdr->control.qos = 1; | ||
101 | } | ||
102 | |||
103 | /* RSN + MIC = 8 + 8 = 16 bytes (worst case - AES). */ | ||
104 | #define MAX_MSDU_SECURITY_LENGTH 16 | ||
105 | #define MAX_MPDU_SECURITY_LENGTH 16 | ||
106 | #define WLAN_QOS_HDR_LEN 26 | ||
107 | #define MAX_MPDU_HEADER_AND_SECURITY (MAX_MPDU_SECURITY_LENGTH + \ | ||
108 | WLAN_QOS_HDR_LEN) | ||
109 | #define HW_BLOCK_SIZE 252 | ||
110 | static void wl1251_tx_frag_block_num(struct tx_double_buffer_desc *tx_hdr) | ||
111 | { | ||
112 | u16 payload_len, frag_threshold, mem_blocks; | ||
113 | u16 num_mpdus, mem_blocks_per_frag; | ||
114 | |||
115 | frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD; | ||
116 | tx_hdr->frag_threshold = cpu_to_le16(frag_threshold); | ||
117 | |||
118 | payload_len = le16_to_cpu(tx_hdr->length) + MAX_MSDU_SECURITY_LENGTH; | ||
119 | |||
120 | if (payload_len > frag_threshold) { | ||
121 | mem_blocks_per_frag = | ||
122 | ((frag_threshold + MAX_MPDU_HEADER_AND_SECURITY) / | ||
123 | HW_BLOCK_SIZE) + 1; | ||
124 | num_mpdus = payload_len / frag_threshold; | ||
125 | mem_blocks = num_mpdus * mem_blocks_per_frag; | ||
126 | payload_len -= num_mpdus * frag_threshold; | ||
127 | num_mpdus++; | ||
128 | |||
129 | } else { | ||
130 | mem_blocks_per_frag = 0; | ||
131 | mem_blocks = 0; | ||
132 | num_mpdus = 1; | ||
133 | } | ||
134 | |||
135 | mem_blocks += (payload_len / HW_BLOCK_SIZE) + 1; | ||
136 | |||
137 | if (num_mpdus > 1) | ||
138 | mem_blocks += min(num_mpdus, mem_blocks_per_frag); | ||
139 | |||
140 | tx_hdr->num_mem_blocks = mem_blocks; | ||
141 | } | ||
142 | |||
143 | static int wl1251_tx_fill_hdr(struct wl1251 *wl, struct sk_buff *skb, | ||
144 | struct ieee80211_tx_info *control) | ||
145 | { | ||
146 | struct tx_double_buffer_desc *tx_hdr; | ||
147 | struct ieee80211_rate *rate; | ||
148 | int id; | ||
149 | u16 fc; | ||
150 | |||
151 | if (!skb) | ||
152 | return -EINVAL; | ||
153 | |||
154 | id = wl1251_tx_id(wl, skb); | ||
155 | if (id < 0) | ||
156 | return id; | ||
157 | |||
158 | fc = *(u16 *)skb->data; | ||
159 | tx_hdr = (struct tx_double_buffer_desc *) skb_push(skb, | ||
160 | sizeof(*tx_hdr)); | ||
161 | |||
162 | tx_hdr->length = cpu_to_le16(skb->len - sizeof(*tx_hdr)); | ||
163 | rate = ieee80211_get_tx_rate(wl->hw, control); | ||
164 | tx_hdr->rate = cpu_to_le16(rate->hw_value); | ||
165 | tx_hdr->expiry_time = cpu_to_le32(1 << 16); | ||
166 | tx_hdr->id = id; | ||
167 | |||
168 | tx_hdr->xmit_queue = wl1251_tx_get_queue(skb_get_queue_mapping(skb)); | ||
169 | |||
170 | wl1251_tx_control(tx_hdr, control, fc); | ||
171 | wl1251_tx_frag_block_num(tx_hdr); | ||
172 | |||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | /* We copy the packet to the target */ | ||
177 | static int wl1251_tx_send_packet(struct wl1251 *wl, struct sk_buff *skb, | ||
178 | struct ieee80211_tx_info *control) | ||
179 | { | ||
180 | struct tx_double_buffer_desc *tx_hdr; | ||
181 | int len; | ||
182 | u32 addr; | ||
183 | |||
184 | if (!skb) | ||
185 | return -EINVAL; | ||
186 | |||
187 | tx_hdr = (struct tx_double_buffer_desc *) skb->data; | ||
188 | |||
189 | if (control->control.hw_key && | ||
190 | control->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) { | ||
191 | int hdrlen; | ||
192 | __le16 fc; | ||
193 | u16 length; | ||
194 | u8 *pos; | ||
195 | |||
196 | fc = *(__le16 *)(skb->data + sizeof(*tx_hdr)); | ||
197 | length = le16_to_cpu(tx_hdr->length) + WL1251_TKIP_IV_SPACE; | ||
198 | tx_hdr->length = cpu_to_le16(length); | ||
199 | |||
200 | hdrlen = ieee80211_hdrlen(fc); | ||
201 | |||
202 | pos = skb_push(skb, WL1251_TKIP_IV_SPACE); | ||
203 | memmove(pos, pos + WL1251_TKIP_IV_SPACE, | ||
204 | sizeof(*tx_hdr) + hdrlen); | ||
205 | } | ||
206 | |||
207 | /* Revisit. This is a workaround for getting non-aligned packets. | ||
208 | This happens at least with EAPOL packets from the user space. | ||
209 | Our DMA requires packets to be aligned on a 4-byte boundary. | ||
210 | */ | ||
211 | if (unlikely((long)skb->data & 0x03)) { | ||
212 | int offset = (4 - (long)skb->data) & 0x03; | ||
213 | wl1251_debug(DEBUG_TX, "skb offset %d", offset); | ||
214 | |||
215 | /* check whether the current skb can be used */ | ||
216 | if (skb_cloned(skb) || (skb_tailroom(skb) < offset)) { | ||
217 | struct sk_buff *newskb = skb_copy_expand(skb, 0, 3, | ||
218 | GFP_KERNEL); | ||
219 | |||
220 | if (unlikely(newskb == NULL)) { | ||
221 | wl1251_error("Can't allocate skb!"); | ||
222 | return -EINVAL; | ||
223 | } | ||
224 | |||
225 | tx_hdr = (struct tx_double_buffer_desc *) newskb->data; | ||
226 | |||
227 | dev_kfree_skb_any(skb); | ||
228 | wl->tx_frames[tx_hdr->id] = skb = newskb; | ||
229 | |||
230 | offset = (4 - (long)skb->data) & 0x03; | ||
231 | wl1251_debug(DEBUG_TX, "new skb offset %d", offset); | ||
232 | } | ||
233 | |||
234 | /* align the buffer on a 4-byte boundary */ | ||
235 | if (offset) { | ||
236 | unsigned char *src = skb->data; | ||
237 | skb_reserve(skb, offset); | ||
238 | memmove(skb->data, src, skb->len); | ||
239 | tx_hdr = (struct tx_double_buffer_desc *) skb->data; | ||
240 | } | ||
241 | } | ||
242 | |||
243 | /* Our skb->data at this point includes the HW header */ | ||
244 | len = WL1251_TX_ALIGN(skb->len); | ||
245 | |||
246 | if (wl->data_in_count & 0x1) | ||
247 | addr = wl->data_path->tx_packet_ring_addr + | ||
248 | wl->data_path->tx_packet_ring_chunk_size; | ||
249 | else | ||
250 | addr = wl->data_path->tx_packet_ring_addr; | ||
251 | |||
252 | wl1251_mem_write(wl, addr, skb->data, len); | ||
253 | |||
254 | wl1251_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x " | ||
255 | "queue %d", tx_hdr->id, skb, tx_hdr->length, | ||
256 | tx_hdr->rate, tx_hdr->xmit_queue); | ||
257 | |||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | static void wl1251_tx_trigger(struct wl1251 *wl) | ||
262 | { | ||
263 | u32 data, addr; | ||
264 | |||
265 | if (wl->data_in_count & 0x1) { | ||
266 | addr = ACX_REG_INTERRUPT_TRIG_H; | ||
267 | data = INTR_TRIG_TX_PROC1; | ||
268 | } else { | ||
269 | addr = ACX_REG_INTERRUPT_TRIG; | ||
270 | data = INTR_TRIG_TX_PROC0; | ||
271 | } | ||
272 | |||
273 | wl1251_reg_write32(wl, addr, data); | ||
274 | |||
275 | /* Bumping data in */ | ||
276 | wl->data_in_count = (wl->data_in_count + 1) & | ||
277 | TX_STATUS_DATA_OUT_COUNT_MASK; | ||
278 | } | ||
279 | |||
280 | /* caller must hold wl->mutex */ | ||
281 | static int wl1251_tx_frame(struct wl1251 *wl, struct sk_buff *skb) | ||
282 | { | ||
283 | struct ieee80211_tx_info *info; | ||
284 | int ret = 0; | ||
285 | u8 idx; | ||
286 | |||
287 | info = IEEE80211_SKB_CB(skb); | ||
288 | |||
289 | if (info->control.hw_key) { | ||
290 | idx = info->control.hw_key->hw_key_idx; | ||
291 | if (unlikely(wl->default_key != idx)) { | ||
292 | ret = wl1251_acx_default_key(wl, idx); | ||
293 | if (ret < 0) | ||
294 | return ret; | ||
295 | } | ||
296 | } | ||
297 | |||
298 | ret = wl1251_tx_path_status(wl); | ||
299 | if (ret < 0) | ||
300 | return ret; | ||
301 | |||
302 | ret = wl1251_tx_fill_hdr(wl, skb, info); | ||
303 | if (ret < 0) | ||
304 | return ret; | ||
305 | |||
306 | ret = wl1251_tx_send_packet(wl, skb, info); | ||
307 | if (ret < 0) | ||
308 | return ret; | ||
309 | |||
310 | wl1251_tx_trigger(wl); | ||
311 | |||
312 | return ret; | ||
313 | } | ||
314 | |||
315 | void wl1251_tx_work(struct work_struct *work) | ||
316 | { | ||
317 | struct wl1251 *wl = container_of(work, struct wl1251, tx_work); | ||
318 | struct sk_buff *skb; | ||
319 | bool woken_up = false; | ||
320 | int ret; | ||
321 | |||
322 | mutex_lock(&wl->mutex); | ||
323 | |||
324 | if (unlikely(wl->state == WL1251_STATE_OFF)) | ||
325 | goto out; | ||
326 | |||
327 | while ((skb = skb_dequeue(&wl->tx_queue))) { | ||
328 | if (!woken_up) { | ||
329 | ret = wl1251_ps_elp_wakeup(wl); | ||
330 | if (ret < 0) | ||
331 | goto out; | ||
332 | woken_up = true; | ||
333 | } | ||
334 | |||
335 | ret = wl1251_tx_frame(wl, skb); | ||
336 | if (ret == -EBUSY) { | ||
337 | skb_queue_head(&wl->tx_queue, skb); | ||
338 | goto out; | ||
339 | } else if (ret < 0) { | ||
340 | dev_kfree_skb(skb); | ||
341 | goto out; | ||
342 | } | ||
343 | } | ||
344 | |||
345 | out: | ||
346 | if (woken_up) | ||
347 | wl1251_ps_elp_sleep(wl); | ||
348 | |||
349 | mutex_unlock(&wl->mutex); | ||
350 | } | ||
351 | |||
352 | static const char *wl1251_tx_parse_status(u8 status) | ||
353 | { | ||
354 | /* 8 bit status field, one character per bit plus null */ | ||
355 | static char buf[9]; | ||
356 | int i = 0; | ||
357 | |||
358 | memset(buf, 0, sizeof(buf)); | ||
359 | |||
360 | if (status & TX_DMA_ERROR) | ||
361 | buf[i++] = 'm'; | ||
362 | if (status & TX_DISABLED) | ||
363 | buf[i++] = 'd'; | ||
364 | if (status & TX_RETRY_EXCEEDED) | ||
365 | buf[i++] = 'r'; | ||
366 | if (status & TX_TIMEOUT) | ||
367 | buf[i++] = 't'; | ||
368 | if (status & TX_KEY_NOT_FOUND) | ||
369 | buf[i++] = 'k'; | ||
370 | if (status & TX_ENCRYPT_FAIL) | ||
371 | buf[i++] = 'e'; | ||
372 | if (status & TX_UNAVAILABLE_PRIORITY) | ||
373 | buf[i++] = 'p'; | ||
374 | |||
375 | /* bit 0 is unused apparently */ | ||
376 | |||
377 | return buf; | ||
378 | } | ||
379 | |||
380 | static void wl1251_tx_packet_cb(struct wl1251 *wl, | ||
381 | struct tx_result *result) | ||
382 | { | ||
383 | struct ieee80211_tx_info *info; | ||
384 | struct sk_buff *skb; | ||
385 | int hdrlen; | ||
386 | u8 *frame; | ||
387 | |||
388 | skb = wl->tx_frames[result->id]; | ||
389 | if (skb == NULL) { | ||
390 | wl1251_error("SKB for packet %d is NULL", result->id); | ||
391 | return; | ||
392 | } | ||
393 | |||
394 | info = IEEE80211_SKB_CB(skb); | ||
395 | |||
396 | if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && | ||
397 | (result->status == TX_SUCCESS)) | ||
398 | info->flags |= IEEE80211_TX_STAT_ACK; | ||
399 | |||
400 | info->status.rates[0].count = result->ack_failures + 1; | ||
401 | wl->stats.retry_count += result->ack_failures; | ||
402 | |||
403 | /* | ||
404 | * We have to remove our private TX header before pushing | ||
405 | * the skb back to mac80211. | ||
406 | */ | ||
407 | frame = skb_pull(skb, sizeof(struct tx_double_buffer_desc)); | ||
408 | if (info->control.hw_key && | ||
409 | info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) { | ||
410 | hdrlen = ieee80211_get_hdrlen_from_skb(skb); | ||
411 | memmove(frame + WL1251_TKIP_IV_SPACE, frame, hdrlen); | ||
412 | skb_pull(skb, WL1251_TKIP_IV_SPACE); | ||
413 | } | ||
414 | |||
415 | wl1251_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x" | ||
416 | " status 0x%x (%s)", | ||
417 | result->id, skb, result->ack_failures, result->rate, | ||
418 | result->status, wl1251_tx_parse_status(result->status)); | ||
419 | |||
420 | |||
421 | ieee80211_tx_status(wl->hw, skb); | ||
422 | |||
423 | wl->tx_frames[result->id] = NULL; | ||
424 | } | ||
425 | |||
426 | /* Called upon reception of a TX complete interrupt */ | ||
427 | void wl1251_tx_complete(struct wl1251 *wl) | ||
428 | { | ||
429 | int i, result_index, num_complete = 0, queue_len; | ||
430 | struct tx_result result[FW_TX_CMPLT_BLOCK_SIZE], *result_ptr; | ||
431 | unsigned long flags; | ||
432 | |||
433 | if (unlikely(wl->state != WL1251_STATE_ON)) | ||
434 | return; | ||
435 | |||
436 | /* First we read the result */ | ||
437 | wl1251_mem_read(wl, wl->data_path->tx_complete_addr, | ||
438 | result, sizeof(result)); | ||
439 | |||
440 | result_index = wl->next_tx_complete; | ||
441 | |||
442 | for (i = 0; i < ARRAY_SIZE(result); i++) { | ||
443 | result_ptr = &result[result_index]; | ||
444 | |||
445 | if (result_ptr->done_1 == 1 && | ||
446 | result_ptr->done_2 == 1) { | ||
447 | wl1251_tx_packet_cb(wl, result_ptr); | ||
448 | |||
449 | result_ptr->done_1 = 0; | ||
450 | result_ptr->done_2 = 0; | ||
451 | |||
452 | result_index = (result_index + 1) & | ||
453 | (FW_TX_CMPLT_BLOCK_SIZE - 1); | ||
454 | num_complete++; | ||
455 | } else { | ||
456 | break; | ||
457 | } | ||
458 | } | ||
459 | |||
460 | queue_len = skb_queue_len(&wl->tx_queue); | ||
461 | |||
462 | if ((num_complete > 0) && (queue_len > 0)) { | ||
463 | /* firmware buffer has space, reschedule tx_work */ | ||
464 | wl1251_debug(DEBUG_TX, "tx_complete: reschedule tx_work"); | ||
465 | ieee80211_queue_work(wl->hw, &wl->tx_work); | ||
466 | } | ||
467 | |||
468 | if (wl->tx_queue_stopped && | ||
469 | queue_len <= WL1251_TX_QUEUE_LOW_WATERMARK) { | ||
470 | /* tx_queue has space, restart queues */ | ||
471 | wl1251_debug(DEBUG_TX, "tx_complete: waking queues"); | ||
472 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
473 | ieee80211_wake_queues(wl->hw); | ||
474 | wl->tx_queue_stopped = false; | ||
475 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
476 | } | ||
477 | |||
478 | /* Every completed frame needs to be acknowledged */ | ||
479 | if (num_complete) { | ||
480 | /* | ||
481 | * If we've wrapped, we have to clear | ||
482 | * the results in 2 steps. | ||
483 | */ | ||
484 | if (result_index > wl->next_tx_complete) { | ||
485 | /* Only 1 write is needed */ | ||
486 | wl1251_mem_write(wl, | ||
487 | wl->data_path->tx_complete_addr + | ||
488 | (wl->next_tx_complete * | ||
489 | sizeof(struct tx_result)), | ||
490 | &result[wl->next_tx_complete], | ||
491 | num_complete * | ||
492 | sizeof(struct tx_result)); | ||
493 | |||
494 | |||
495 | } else if (result_index < wl->next_tx_complete) { | ||
496 | /* 2 writes are needed */ | ||
497 | wl1251_mem_write(wl, | ||
498 | wl->data_path->tx_complete_addr + | ||
499 | (wl->next_tx_complete * | ||
500 | sizeof(struct tx_result)), | ||
501 | &result[wl->next_tx_complete], | ||
502 | (FW_TX_CMPLT_BLOCK_SIZE - | ||
503 | wl->next_tx_complete) * | ||
504 | sizeof(struct tx_result)); | ||
505 | |||
506 | wl1251_mem_write(wl, | ||
507 | wl->data_path->tx_complete_addr, | ||
508 | result, | ||
509 | (num_complete - | ||
510 | FW_TX_CMPLT_BLOCK_SIZE + | ||
511 | wl->next_tx_complete) * | ||
512 | sizeof(struct tx_result)); | ||
513 | |||
514 | } else { | ||
515 | /* We have to write the whole array */ | ||
516 | wl1251_mem_write(wl, | ||
517 | wl->data_path->tx_complete_addr, | ||
518 | result, | ||
519 | FW_TX_CMPLT_BLOCK_SIZE * | ||
520 | sizeof(struct tx_result)); | ||
521 | } | ||
522 | |||
523 | } | ||
524 | |||
525 | wl->next_tx_complete = result_index; | ||
526 | } | ||
527 | |||
528 | /* caller must hold wl->mutex */ | ||
529 | void wl1251_tx_flush(struct wl1251 *wl) | ||
530 | { | ||
531 | int i; | ||
532 | struct sk_buff *skb; | ||
533 | struct ieee80211_tx_info *info; | ||
534 | |||
535 | /* TX failure */ | ||
536 | /* control->flags = 0; FIXME */ | ||
537 | |||
538 | while ((skb = skb_dequeue(&wl->tx_queue))) { | ||
539 | info = IEEE80211_SKB_CB(skb); | ||
540 | |||
541 | wl1251_debug(DEBUG_TX, "flushing skb 0x%p", skb); | ||
542 | |||
543 | if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) | ||
544 | continue; | ||
545 | |||
546 | ieee80211_tx_status(wl->hw, skb); | ||
547 | } | ||
548 | |||
549 | for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) | ||
550 | if (wl->tx_frames[i] != NULL) { | ||
551 | skb = wl->tx_frames[i]; | ||
552 | info = IEEE80211_SKB_CB(skb); | ||
553 | |||
554 | if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) | ||
555 | continue; | ||
556 | |||
557 | ieee80211_tx_status(wl->hw, skb); | ||
558 | wl->tx_frames[i] = NULL; | ||
559 | } | ||
560 | } | ||
diff --git a/drivers/net/wireless/ti/wl1251/tx.h b/drivers/net/wireless/ti/wl1251/tx.h new file mode 100644 index 000000000000..81338d39b43e --- /dev/null +++ b/drivers/net/wireless/ti/wl1251/tx.h | |||
@@ -0,0 +1,231 @@ | |||
1 | /* | ||
2 | * This file is part of wl1251 | ||
3 | * | ||
4 | * Copyright (c) 1998-2007 Texas Instruments Incorporated | ||
5 | * Copyright (C) 2008 Nokia Corporation | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * version 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
19 | * 02110-1301 USA | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #ifndef __WL1251_TX_H__ | ||
24 | #define __WL1251_TX_H__ | ||
25 | |||
26 | #include <linux/bitops.h> | ||
27 | #include "acx.h" | ||
28 | |||
29 | /* | ||
30 | * | ||
31 | * TX PATH | ||
32 | * | ||
33 | * The Tx path uses a double buffer and a tx_control structure, each located | ||
34 | * at a fixed address in the device's memory. On startup, the host retrieves | ||
35 | * the pointers to these addresses. A double buffer allows for continuous data | ||
36 | * flow towards the device. The host keeps track of which buffer is available | ||
37 | * and alternates between these two buffers on a per packet basis. | ||
38 | * | ||
39 | * The size of each of the two buffers is large enough to hold the longest | ||
40 | * 802.3 packet - maximum size Ethernet packet + header + descriptor. | ||
41 | * TX complete indication will be received a-synchronously in a TX done cyclic | ||
42 | * buffer which is composed of 16 tx_result descriptors structures and is used | ||
43 | * in a cyclic manner. | ||
44 | * | ||
45 | * The TX (HOST) procedure is as follows: | ||
46 | * 1. Read the Tx path status, that will give the data_out_count. | ||
47 | * 2. goto 1, if not possible. | ||
48 | * i.e. if data_in_count - data_out_count >= HwBuffer size (2 for double | ||
49 | * buffer). | ||
50 | * 3. Copy the packet (preceded by double_buffer_desc), if possible. | ||
51 | * i.e. if data_in_count - data_out_count < HwBuffer size (2 for double | ||
52 | * buffer). | ||
53 | * 4. increment data_in_count. | ||
54 | * 5. Inform the firmware by generating a firmware internal interrupt. | ||
55 | * 6. FW will increment data_out_count after it reads the buffer. | ||
56 | * | ||
57 | * The TX Complete procedure: | ||
58 | * 1. To get a TX complete indication the host enables the tx_complete flag in | ||
59 | * the TX descriptor Structure. | ||
60 | * 2. For each packet with a Tx Complete field set, the firmware adds the | ||
61 | * transmit results to the cyclic buffer (txDoneRing) and sets both done_1 | ||
62 | * and done_2 to 1 to indicate driver ownership. | ||
63 | * 3. The firmware sends a Tx Complete interrupt to the host to trigger the | ||
64 | * host to process the new data. Note: interrupt will be send per packet if | ||
65 | * TX complete indication was requested in tx_control or per crossing | ||
66 | * aggregation threshold. | ||
67 | * 4. After receiving the Tx Complete interrupt, the host reads the | ||
68 | * TxDescriptorDone information in a cyclic manner and clears both done_1 | ||
69 | * and done_2 fields. | ||
70 | * | ||
71 | */ | ||
72 | |||
73 | #define TX_COMPLETE_REQUIRED_BIT 0x80 | ||
74 | #define TX_STATUS_DATA_OUT_COUNT_MASK 0xf | ||
75 | |||
76 | #define WL1251_TX_ALIGN_TO 4 | ||
77 | #define WL1251_TX_ALIGN(len) (((len) + WL1251_TX_ALIGN_TO - 1) & \ | ||
78 | ~(WL1251_TX_ALIGN_TO - 1)) | ||
79 | #define WL1251_TKIP_IV_SPACE 4 | ||
80 | |||
81 | struct tx_control { | ||
82 | /* Rate Policy (class) index */ | ||
83 | unsigned rate_policy:3; | ||
84 | |||
85 | /* When set, no ack policy is expected */ | ||
86 | unsigned ack_policy:1; | ||
87 | |||
88 | /* | ||
89 | * Packet type: | ||
90 | * 0 -> 802.11 | ||
91 | * 1 -> 802.3 | ||
92 | * 2 -> IP | ||
93 | * 3 -> raw codec | ||
94 | */ | ||
95 | unsigned packet_type:2; | ||
96 | |||
97 | /* If set, this is a QoS-Null or QoS-Data frame */ | ||
98 | unsigned qos:1; | ||
99 | |||
100 | /* | ||
101 | * If set, the target triggers the tx complete INT | ||
102 | * upon frame sending completion. | ||
103 | */ | ||
104 | unsigned tx_complete:1; | ||
105 | |||
106 | /* 2 bytes padding before packet header */ | ||
107 | unsigned xfer_pad:1; | ||
108 | |||
109 | unsigned reserved:7; | ||
110 | } __packed; | ||
111 | |||
112 | |||
113 | struct tx_double_buffer_desc { | ||
114 | /* Length of payload, including headers. */ | ||
115 | __le16 length; | ||
116 | |||
117 | /* | ||
118 | * A bit mask that specifies the initial rate to be used | ||
119 | * Possible values are: | ||
120 | * 0x0001 - 1Mbits | ||
121 | * 0x0002 - 2Mbits | ||
122 | * 0x0004 - 5.5Mbits | ||
123 | * 0x0008 - 6Mbits | ||
124 | * 0x0010 - 9Mbits | ||
125 | * 0x0020 - 11Mbits | ||
126 | * 0x0040 - 12Mbits | ||
127 | * 0x0080 - 18Mbits | ||
128 | * 0x0100 - 22Mbits | ||
129 | * 0x0200 - 24Mbits | ||
130 | * 0x0400 - 36Mbits | ||
131 | * 0x0800 - 48Mbits | ||
132 | * 0x1000 - 54Mbits | ||
133 | */ | ||
134 | __le16 rate; | ||
135 | |||
136 | /* Time in us that a packet can spend in the target */ | ||
137 | __le32 expiry_time; | ||
138 | |||
139 | /* index of the TX queue used for this packet */ | ||
140 | u8 xmit_queue; | ||
141 | |||
142 | /* Used to identify a packet */ | ||
143 | u8 id; | ||
144 | |||
145 | struct tx_control control; | ||
146 | |||
147 | /* | ||
148 | * The FW should cut the packet into fragments | ||
149 | * of this size. | ||
150 | */ | ||
151 | __le16 frag_threshold; | ||
152 | |||
153 | /* Numbers of HW queue blocks to be allocated */ | ||
154 | u8 num_mem_blocks; | ||
155 | |||
156 | u8 reserved; | ||
157 | } __packed; | ||
158 | |||
159 | enum { | ||
160 | TX_SUCCESS = 0, | ||
161 | TX_DMA_ERROR = BIT(7), | ||
162 | TX_DISABLED = BIT(6), | ||
163 | TX_RETRY_EXCEEDED = BIT(5), | ||
164 | TX_TIMEOUT = BIT(4), | ||
165 | TX_KEY_NOT_FOUND = BIT(3), | ||
166 | TX_ENCRYPT_FAIL = BIT(2), | ||
167 | TX_UNAVAILABLE_PRIORITY = BIT(1), | ||
168 | }; | ||
169 | |||
170 | struct tx_result { | ||
171 | /* | ||
172 | * Ownership synchronization between the host and | ||
173 | * the firmware. If done_1 and done_2 are cleared, | ||
174 | * owned by the FW (no info ready). | ||
175 | */ | ||
176 | u8 done_1; | ||
177 | |||
178 | /* same as double_buffer_desc->id */ | ||
179 | u8 id; | ||
180 | |||
181 | /* | ||
182 | * Total air access duration consumed by this | ||
183 | * packet, including all retries and overheads. | ||
184 | */ | ||
185 | u16 medium_usage; | ||
186 | |||
187 | /* Total media delay (from 1st EDCA AIFS counter until TX Complete). */ | ||
188 | u32 medium_delay; | ||
189 | |||
190 | /* Time between host xfer and tx complete */ | ||
191 | u32 fw_hnadling_time; | ||
192 | |||
193 | /* The LS-byte of the last TKIP sequence number. */ | ||
194 | u8 lsb_seq_num; | ||
195 | |||
196 | /* Retry count */ | ||
197 | u8 ack_failures; | ||
198 | |||
199 | /* At which rate we got a ACK */ | ||
200 | u16 rate; | ||
201 | |||
202 | u16 reserved; | ||
203 | |||
204 | /* TX_* */ | ||
205 | u8 status; | ||
206 | |||
207 | /* See done_1 */ | ||
208 | u8 done_2; | ||
209 | } __packed; | ||
210 | |||
211 | static inline int wl1251_tx_get_queue(int queue) | ||
212 | { | ||
213 | switch (queue) { | ||
214 | case 0: | ||
215 | return QOS_AC_VO; | ||
216 | case 1: | ||
217 | return QOS_AC_VI; | ||
218 | case 2: | ||
219 | return QOS_AC_BE; | ||
220 | case 3: | ||
221 | return QOS_AC_BK; | ||
222 | default: | ||
223 | return QOS_AC_BE; | ||
224 | } | ||
225 | } | ||
226 | |||
227 | void wl1251_tx_work(struct work_struct *work); | ||
228 | void wl1251_tx_complete(struct wl1251 *wl); | ||
229 | void wl1251_tx_flush(struct wl1251 *wl); | ||
230 | |||
231 | #endif | ||
diff --git a/drivers/net/wireless/ti/wl1251/wl1251.h b/drivers/net/wireless/ti/wl1251/wl1251.h new file mode 100644 index 000000000000..9d8f5816c6f9 --- /dev/null +++ b/drivers/net/wireless/ti/wl1251/wl1251.h | |||
@@ -0,0 +1,446 @@ | |||
1 | /* | ||
2 | * This file is part of wl1251 | ||
3 | * | ||
4 | * Copyright (c) 1998-2007 Texas Instruments Incorporated | ||
5 | * Copyright (C) 2008-2009 Nokia Corporation | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * version 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
19 | * 02110-1301 USA | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #ifndef __WL1251_H__ | ||
24 | #define __WL1251_H__ | ||
25 | |||
26 | #include <linux/mutex.h> | ||
27 | #include <linux/list.h> | ||
28 | #include <linux/bitops.h> | ||
29 | #include <net/mac80211.h> | ||
30 | |||
31 | #define DRIVER_NAME "wl1251" | ||
32 | #define DRIVER_PREFIX DRIVER_NAME ": " | ||
33 | |||
34 | enum { | ||
35 | DEBUG_NONE = 0, | ||
36 | DEBUG_IRQ = BIT(0), | ||
37 | DEBUG_SPI = BIT(1), | ||
38 | DEBUG_BOOT = BIT(2), | ||
39 | DEBUG_MAILBOX = BIT(3), | ||
40 | DEBUG_NETLINK = BIT(4), | ||
41 | DEBUG_EVENT = BIT(5), | ||
42 | DEBUG_TX = BIT(6), | ||
43 | DEBUG_RX = BIT(7), | ||
44 | DEBUG_SCAN = BIT(8), | ||
45 | DEBUG_CRYPT = BIT(9), | ||
46 | DEBUG_PSM = BIT(10), | ||
47 | DEBUG_MAC80211 = BIT(11), | ||
48 | DEBUG_CMD = BIT(12), | ||
49 | DEBUG_ACX = BIT(13), | ||
50 | DEBUG_ALL = ~0, | ||
51 | }; | ||
52 | |||
53 | #define DEBUG_LEVEL (DEBUG_NONE) | ||
54 | |||
55 | #define DEBUG_DUMP_LIMIT 1024 | ||
56 | |||
57 | #define wl1251_error(fmt, arg...) \ | ||
58 | printk(KERN_ERR DRIVER_PREFIX "ERROR " fmt "\n", ##arg) | ||
59 | |||
60 | #define wl1251_warning(fmt, arg...) \ | ||
61 | printk(KERN_WARNING DRIVER_PREFIX "WARNING " fmt "\n", ##arg) | ||
62 | |||
63 | #define wl1251_notice(fmt, arg...) \ | ||
64 | printk(KERN_INFO DRIVER_PREFIX fmt "\n", ##arg) | ||
65 | |||
66 | #define wl1251_info(fmt, arg...) \ | ||
67 | printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg) | ||
68 | |||
69 | #define wl1251_debug(level, fmt, arg...) \ | ||
70 | do { \ | ||
71 | if (level & DEBUG_LEVEL) \ | ||
72 | printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg); \ | ||
73 | } while (0) | ||
74 | |||
75 | #define wl1251_dump(level, prefix, buf, len) \ | ||
76 | do { \ | ||
77 | if (level & DEBUG_LEVEL) \ | ||
78 | print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ | ||
79 | DUMP_PREFIX_OFFSET, 16, 1, \ | ||
80 | buf, \ | ||
81 | min_t(size_t, len, DEBUG_DUMP_LIMIT), \ | ||
82 | 0); \ | ||
83 | } while (0) | ||
84 | |||
85 | #define wl1251_dump_ascii(level, prefix, buf, len) \ | ||
86 | do { \ | ||
87 | if (level & DEBUG_LEVEL) \ | ||
88 | print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ | ||
89 | DUMP_PREFIX_OFFSET, 16, 1, \ | ||
90 | buf, \ | ||
91 | min_t(size_t, len, DEBUG_DUMP_LIMIT), \ | ||
92 | true); \ | ||
93 | } while (0) | ||
94 | |||
95 | #define WL1251_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \ | ||
96 | CFG_BSSID_FILTER_EN) | ||
97 | |||
98 | #define WL1251_DEFAULT_RX_FILTER (CFG_RX_PRSP_EN | \ | ||
99 | CFG_RX_MGMT_EN | \ | ||
100 | CFG_RX_DATA_EN | \ | ||
101 | CFG_RX_CTL_EN | \ | ||
102 | CFG_RX_BCN_EN | \ | ||
103 | CFG_RX_AUTH_EN | \ | ||
104 | CFG_RX_ASSOC_EN) | ||
105 | |||
106 | #define WL1251_BUSY_WORD_LEN 8 | ||
107 | |||
108 | struct boot_attr { | ||
109 | u32 radio_type; | ||
110 | u8 mac_clock; | ||
111 | u8 arm_clock; | ||
112 | int firmware_debug; | ||
113 | u32 minor; | ||
114 | u32 major; | ||
115 | u32 bugfix; | ||
116 | }; | ||
117 | |||
118 | enum wl1251_state { | ||
119 | WL1251_STATE_OFF, | ||
120 | WL1251_STATE_ON, | ||
121 | WL1251_STATE_PLT, | ||
122 | }; | ||
123 | |||
124 | enum wl1251_partition_type { | ||
125 | PART_DOWN, | ||
126 | PART_WORK, | ||
127 | PART_DRPW, | ||
128 | |||
129 | PART_TABLE_LEN | ||
130 | }; | ||
131 | |||
132 | enum wl1251_station_mode { | ||
133 | STATION_ACTIVE_MODE, | ||
134 | STATION_POWER_SAVE_MODE, | ||
135 | STATION_IDLE, | ||
136 | }; | ||
137 | |||
138 | struct wl1251_partition { | ||
139 | u32 size; | ||
140 | u32 start; | ||
141 | }; | ||
142 | |||
143 | struct wl1251_partition_set { | ||
144 | struct wl1251_partition mem; | ||
145 | struct wl1251_partition reg; | ||
146 | }; | ||
147 | |||
148 | struct wl1251; | ||
149 | |||
150 | struct wl1251_stats { | ||
151 | struct acx_statistics *fw_stats; | ||
152 | unsigned long fw_stats_update; | ||
153 | |||
154 | unsigned int retry_count; | ||
155 | unsigned int excessive_retries; | ||
156 | }; | ||
157 | |||
158 | struct wl1251_debugfs { | ||
159 | struct dentry *rootdir; | ||
160 | struct dentry *fw_statistics; | ||
161 | |||
162 | struct dentry *tx_internal_desc_overflow; | ||
163 | |||
164 | struct dentry *rx_out_of_mem; | ||
165 | struct dentry *rx_hdr_overflow; | ||
166 | struct dentry *rx_hw_stuck; | ||
167 | struct dentry *rx_dropped; | ||
168 | struct dentry *rx_fcs_err; | ||
169 | struct dentry *rx_xfr_hint_trig; | ||
170 | struct dentry *rx_path_reset; | ||
171 | struct dentry *rx_reset_counter; | ||
172 | |||
173 | struct dentry *dma_rx_requested; | ||
174 | struct dentry *dma_rx_errors; | ||
175 | struct dentry *dma_tx_requested; | ||
176 | struct dentry *dma_tx_errors; | ||
177 | |||
178 | struct dentry *isr_cmd_cmplt; | ||
179 | struct dentry *isr_fiqs; | ||
180 | struct dentry *isr_rx_headers; | ||
181 | struct dentry *isr_rx_mem_overflow; | ||
182 | struct dentry *isr_rx_rdys; | ||
183 | struct dentry *isr_irqs; | ||
184 | struct dentry *isr_tx_procs; | ||
185 | struct dentry *isr_decrypt_done; | ||
186 | struct dentry *isr_dma0_done; | ||
187 | struct dentry *isr_dma1_done; | ||
188 | struct dentry *isr_tx_exch_complete; | ||
189 | struct dentry *isr_commands; | ||
190 | struct dentry *isr_rx_procs; | ||
191 | struct dentry *isr_hw_pm_mode_changes; | ||
192 | struct dentry *isr_host_acknowledges; | ||
193 | struct dentry *isr_pci_pm; | ||
194 | struct dentry *isr_wakeups; | ||
195 | struct dentry *isr_low_rssi; | ||
196 | |||
197 | struct dentry *wep_addr_key_count; | ||
198 | struct dentry *wep_default_key_count; | ||
199 | /* skipping wep.reserved */ | ||
200 | struct dentry *wep_key_not_found; | ||
201 | struct dentry *wep_decrypt_fail; | ||
202 | struct dentry *wep_packets; | ||
203 | struct dentry *wep_interrupt; | ||
204 | |||
205 | struct dentry *pwr_ps_enter; | ||
206 | struct dentry *pwr_elp_enter; | ||
207 | struct dentry *pwr_missing_bcns; | ||
208 | struct dentry *pwr_wake_on_host; | ||
209 | struct dentry *pwr_wake_on_timer_exp; | ||
210 | struct dentry *pwr_tx_with_ps; | ||
211 | struct dentry *pwr_tx_without_ps; | ||
212 | struct dentry *pwr_rcvd_beacons; | ||
213 | struct dentry *pwr_power_save_off; | ||
214 | struct dentry *pwr_enable_ps; | ||
215 | struct dentry *pwr_disable_ps; | ||
216 | struct dentry *pwr_fix_tsf_ps; | ||
217 | /* skipping cont_miss_bcns_spread for now */ | ||
218 | struct dentry *pwr_rcvd_awake_beacons; | ||
219 | |||
220 | struct dentry *mic_rx_pkts; | ||
221 | struct dentry *mic_calc_failure; | ||
222 | |||
223 | struct dentry *aes_encrypt_fail; | ||
224 | struct dentry *aes_decrypt_fail; | ||
225 | struct dentry *aes_encrypt_packets; | ||
226 | struct dentry *aes_decrypt_packets; | ||
227 | struct dentry *aes_encrypt_interrupt; | ||
228 | struct dentry *aes_decrypt_interrupt; | ||
229 | |||
230 | struct dentry *event_heart_beat; | ||
231 | struct dentry *event_calibration; | ||
232 | struct dentry *event_rx_mismatch; | ||
233 | struct dentry *event_rx_mem_empty; | ||
234 | struct dentry *event_rx_pool; | ||
235 | struct dentry *event_oom_late; | ||
236 | struct dentry *event_phy_transmit_error; | ||
237 | struct dentry *event_tx_stuck; | ||
238 | |||
239 | struct dentry *ps_pspoll_timeouts; | ||
240 | struct dentry *ps_upsd_timeouts; | ||
241 | struct dentry *ps_upsd_max_sptime; | ||
242 | struct dentry *ps_upsd_max_apturn; | ||
243 | struct dentry *ps_pspoll_max_apturn; | ||
244 | struct dentry *ps_pspoll_utilization; | ||
245 | struct dentry *ps_upsd_utilization; | ||
246 | |||
247 | struct dentry *rxpipe_rx_prep_beacon_drop; | ||
248 | struct dentry *rxpipe_descr_host_int_trig_rx_data; | ||
249 | struct dentry *rxpipe_beacon_buffer_thres_host_int_trig_rx_data; | ||
250 | struct dentry *rxpipe_missed_beacon_host_int_trig_rx_data; | ||
251 | struct dentry *rxpipe_tx_xfr_host_int_trig_rx_data; | ||
252 | |||
253 | struct dentry *tx_queue_len; | ||
254 | struct dentry *tx_queue_status; | ||
255 | |||
256 | struct dentry *retry_count; | ||
257 | struct dentry *excessive_retries; | ||
258 | }; | ||
259 | |||
260 | struct wl1251_if_operations { | ||
261 | void (*read)(struct wl1251 *wl, int addr, void *buf, size_t len); | ||
262 | void (*write)(struct wl1251 *wl, int addr, void *buf, size_t len); | ||
263 | void (*read_elp)(struct wl1251 *wl, int addr, u32 *val); | ||
264 | void (*write_elp)(struct wl1251 *wl, int addr, u32 val); | ||
265 | int (*power)(struct wl1251 *wl, bool enable); | ||
266 | void (*reset)(struct wl1251 *wl); | ||
267 | void (*enable_irq)(struct wl1251 *wl); | ||
268 | void (*disable_irq)(struct wl1251 *wl); | ||
269 | }; | ||
270 | |||
271 | struct wl1251 { | ||
272 | struct ieee80211_hw *hw; | ||
273 | bool mac80211_registered; | ||
274 | |||
275 | void *if_priv; | ||
276 | const struct wl1251_if_operations *if_ops; | ||
277 | |||
278 | void (*set_power)(bool enable); | ||
279 | int irq; | ||
280 | bool use_eeprom; | ||
281 | |||
282 | spinlock_t wl_lock; | ||
283 | |||
284 | enum wl1251_state state; | ||
285 | struct mutex mutex; | ||
286 | |||
287 | int physical_mem_addr; | ||
288 | int physical_reg_addr; | ||
289 | int virtual_mem_addr; | ||
290 | int virtual_reg_addr; | ||
291 | |||
292 | int cmd_box_addr; | ||
293 | int event_box_addr; | ||
294 | struct boot_attr boot_attr; | ||
295 | |||
296 | u8 *fw; | ||
297 | size_t fw_len; | ||
298 | u8 *nvs; | ||
299 | size_t nvs_len; | ||
300 | |||
301 | u8 bssid[ETH_ALEN]; | ||
302 | u8 mac_addr[ETH_ALEN]; | ||
303 | u8 bss_type; | ||
304 | u8 listen_int; | ||
305 | int channel; | ||
306 | |||
307 | void *target_mem_map; | ||
308 | struct acx_data_path_params_resp *data_path; | ||
309 | |||
310 | /* Number of TX packets transferred to the FW, modulo 16 */ | ||
311 | u32 data_in_count; | ||
312 | |||
313 | /* Frames scheduled for transmission, not handled yet */ | ||
314 | struct sk_buff_head tx_queue; | ||
315 | bool tx_queue_stopped; | ||
316 | |||
317 | struct work_struct tx_work; | ||
318 | struct work_struct filter_work; | ||
319 | |||
320 | /* Pending TX frames */ | ||
321 | struct sk_buff *tx_frames[16]; | ||
322 | |||
323 | /* | ||
324 | * Index pointing to the next TX complete entry | ||
325 | * in the cyclic XT complete array we get from | ||
326 | * the FW. | ||
327 | */ | ||
328 | u32 next_tx_complete; | ||
329 | |||
330 | /* FW Rx counter */ | ||
331 | u32 rx_counter; | ||
332 | |||
333 | /* Rx frames handled */ | ||
334 | u32 rx_handled; | ||
335 | |||
336 | /* Current double buffer */ | ||
337 | u32 rx_current_buffer; | ||
338 | u32 rx_last_id; | ||
339 | |||
340 | /* The target interrupt mask */ | ||
341 | u32 intr_mask; | ||
342 | struct work_struct irq_work; | ||
343 | |||
344 | /* The mbox event mask */ | ||
345 | u32 event_mask; | ||
346 | |||
347 | /* Mailbox pointers */ | ||
348 | u32 mbox_ptr[2]; | ||
349 | |||
350 | /* Are we currently scanning */ | ||
351 | bool scanning; | ||
352 | |||
353 | /* Default key (for WEP) */ | ||
354 | u32 default_key; | ||
355 | |||
356 | unsigned int tx_mgmt_frm_rate; | ||
357 | unsigned int tx_mgmt_frm_mod; | ||
358 | |||
359 | unsigned int rx_config; | ||
360 | unsigned int rx_filter; | ||
361 | |||
362 | /* is firmware in elp mode */ | ||
363 | bool elp; | ||
364 | |||
365 | struct delayed_work elp_work; | ||
366 | |||
367 | enum wl1251_station_mode station_mode; | ||
368 | |||
369 | /* PSM mode requested */ | ||
370 | bool psm_requested; | ||
371 | |||
372 | u16 beacon_int; | ||
373 | u8 dtim_period; | ||
374 | |||
375 | /* in dBm */ | ||
376 | int power_level; | ||
377 | |||
378 | int rssi_thold; | ||
379 | |||
380 | struct wl1251_stats stats; | ||
381 | struct wl1251_debugfs debugfs; | ||
382 | |||
383 | __le32 buffer_32; | ||
384 | u32 buffer_cmd; | ||
385 | u8 buffer_busyword[WL1251_BUSY_WORD_LEN]; | ||
386 | struct wl1251_rx_descriptor *rx_descriptor; | ||
387 | |||
388 | struct ieee80211_vif *vif; | ||
389 | |||
390 | u32 chip_id; | ||
391 | char fw_ver[21]; | ||
392 | |||
393 | /* Most recently reported noise in dBm */ | ||
394 | s8 noise; | ||
395 | }; | ||
396 | |||
397 | int wl1251_plt_start(struct wl1251 *wl); | ||
398 | int wl1251_plt_stop(struct wl1251 *wl); | ||
399 | |||
400 | struct ieee80211_hw *wl1251_alloc_hw(void); | ||
401 | int wl1251_free_hw(struct wl1251 *wl); | ||
402 | int wl1251_init_ieee80211(struct wl1251 *wl); | ||
403 | void wl1251_enable_interrupts(struct wl1251 *wl); | ||
404 | void wl1251_disable_interrupts(struct wl1251 *wl); | ||
405 | |||
406 | #define DEFAULT_HW_GEN_MODULATION_TYPE CCK_LONG /* Long Preamble */ | ||
407 | #define DEFAULT_HW_GEN_TX_RATE RATE_2MBPS | ||
408 | #define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */ | ||
409 | |||
410 | #define WL1251_DEFAULT_POWER_LEVEL 20 | ||
411 | |||
412 | #define WL1251_TX_QUEUE_LOW_WATERMARK 10 | ||
413 | #define WL1251_TX_QUEUE_HIGH_WATERMARK 25 | ||
414 | |||
415 | #define WL1251_DEFAULT_BEACON_INT 100 | ||
416 | #define WL1251_DEFAULT_DTIM_PERIOD 1 | ||
417 | |||
418 | #define WL1251_DEFAULT_CHANNEL 0 | ||
419 | |||
420 | #define WL1251_DEFAULT_BET_CONSECUTIVE 10 | ||
421 | |||
422 | #define CHIP_ID_1251_PG10 (0x7010101) | ||
423 | #define CHIP_ID_1251_PG11 (0x7020101) | ||
424 | #define CHIP_ID_1251_PG12 (0x7030101) | ||
425 | #define CHIP_ID_1271_PG10 (0x4030101) | ||
426 | #define CHIP_ID_1271_PG20 (0x4030111) | ||
427 | |||
428 | #define WL1251_FW_NAME "wl1251-fw.bin" | ||
429 | #define WL1251_NVS_NAME "wl1251-nvs.bin" | ||
430 | |||
431 | #define WL1251_POWER_ON_SLEEP 10 /* in milliseconds */ | ||
432 | |||
433 | #define WL1251_PART_DOWN_MEM_START 0x0 | ||
434 | #define WL1251_PART_DOWN_MEM_SIZE 0x16800 | ||
435 | #define WL1251_PART_DOWN_REG_START REGISTERS_BASE | ||
436 | #define WL1251_PART_DOWN_REG_SIZE REGISTERS_DOWN_SIZE | ||
437 | |||
438 | #define WL1251_PART_WORK_MEM_START 0x28000 | ||
439 | #define WL1251_PART_WORK_MEM_SIZE 0x14000 | ||
440 | #define WL1251_PART_WORK_REG_START REGISTERS_BASE | ||
441 | #define WL1251_PART_WORK_REG_SIZE REGISTERS_WORK_SIZE | ||
442 | |||
443 | #define WL1251_DEFAULT_LOW_RSSI_WEIGHT 10 | ||
444 | #define WL1251_DEFAULT_LOW_RSSI_DEPTH 10 | ||
445 | |||
446 | #endif | ||
diff --git a/drivers/net/wireless/ti/wl1251/wl12xx_80211.h b/drivers/net/wireless/ti/wl1251/wl12xx_80211.h new file mode 100644 index 000000000000..04ed51495772 --- /dev/null +++ b/drivers/net/wireless/ti/wl1251/wl12xx_80211.h | |||
@@ -0,0 +1,155 @@ | |||
1 | #ifndef __WL12XX_80211_H__ | ||
2 | #define __WL12XX_80211_H__ | ||
3 | |||
4 | #include <linux/if_ether.h> /* ETH_ALEN */ | ||
5 | |||
6 | /* RATES */ | ||
7 | #define IEEE80211_CCK_RATE_1MB 0x02 | ||
8 | #define IEEE80211_CCK_RATE_2MB 0x04 | ||
9 | #define IEEE80211_CCK_RATE_5MB 0x0B | ||
10 | #define IEEE80211_CCK_RATE_11MB 0x16 | ||
11 | #define IEEE80211_OFDM_RATE_6MB 0x0C | ||
12 | #define IEEE80211_OFDM_RATE_9MB 0x12 | ||
13 | #define IEEE80211_OFDM_RATE_12MB 0x18 | ||
14 | #define IEEE80211_OFDM_RATE_18MB 0x24 | ||
15 | #define IEEE80211_OFDM_RATE_24MB 0x30 | ||
16 | #define IEEE80211_OFDM_RATE_36MB 0x48 | ||
17 | #define IEEE80211_OFDM_RATE_48MB 0x60 | ||
18 | #define IEEE80211_OFDM_RATE_54MB 0x6C | ||
19 | #define IEEE80211_BASIC_RATE_MASK 0x80 | ||
20 | |||
21 | #define IEEE80211_CCK_RATE_1MB_MASK (1<<0) | ||
22 | #define IEEE80211_CCK_RATE_2MB_MASK (1<<1) | ||
23 | #define IEEE80211_CCK_RATE_5MB_MASK (1<<2) | ||
24 | #define IEEE80211_CCK_RATE_11MB_MASK (1<<3) | ||
25 | #define IEEE80211_OFDM_RATE_6MB_MASK (1<<4) | ||
26 | #define IEEE80211_OFDM_RATE_9MB_MASK (1<<5) | ||
27 | #define IEEE80211_OFDM_RATE_12MB_MASK (1<<6) | ||
28 | #define IEEE80211_OFDM_RATE_18MB_MASK (1<<7) | ||
29 | #define IEEE80211_OFDM_RATE_24MB_MASK (1<<8) | ||
30 | #define IEEE80211_OFDM_RATE_36MB_MASK (1<<9) | ||
31 | #define IEEE80211_OFDM_RATE_48MB_MASK (1<<10) | ||
32 | #define IEEE80211_OFDM_RATE_54MB_MASK (1<<11) | ||
33 | |||
34 | #define IEEE80211_CCK_RATES_MASK 0x0000000F | ||
35 | #define IEEE80211_CCK_BASIC_RATES_MASK (IEEE80211_CCK_RATE_1MB_MASK | \ | ||
36 | IEEE80211_CCK_RATE_2MB_MASK) | ||
37 | #define IEEE80211_CCK_DEFAULT_RATES_MASK (IEEE80211_CCK_BASIC_RATES_MASK | \ | ||
38 | IEEE80211_CCK_RATE_5MB_MASK | \ | ||
39 | IEEE80211_CCK_RATE_11MB_MASK) | ||
40 | |||
41 | #define IEEE80211_OFDM_RATES_MASK 0x00000FF0 | ||
42 | #define IEEE80211_OFDM_BASIC_RATES_MASK (IEEE80211_OFDM_RATE_6MB_MASK | \ | ||
43 | IEEE80211_OFDM_RATE_12MB_MASK | \ | ||
44 | IEEE80211_OFDM_RATE_24MB_MASK) | ||
45 | #define IEEE80211_OFDM_DEFAULT_RATES_MASK (IEEE80211_OFDM_BASIC_RATES_MASK | \ | ||
46 | IEEE80211_OFDM_RATE_9MB_MASK | \ | ||
47 | IEEE80211_OFDM_RATE_18MB_MASK | \ | ||
48 | IEEE80211_OFDM_RATE_36MB_MASK | \ | ||
49 | IEEE80211_OFDM_RATE_48MB_MASK | \ | ||
50 | IEEE80211_OFDM_RATE_54MB_MASK) | ||
51 | #define IEEE80211_DEFAULT_RATES_MASK (IEEE80211_OFDM_DEFAULT_RATES_MASK | \ | ||
52 | IEEE80211_CCK_DEFAULT_RATES_MASK) | ||
53 | |||
54 | |||
55 | /* This really should be 8, but not for our firmware */ | ||
56 | #define MAX_SUPPORTED_RATES 32 | ||
57 | #define MAX_COUNTRY_TRIPLETS 32 | ||
58 | |||
59 | /* Headers */ | ||
60 | struct ieee80211_header { | ||
61 | __le16 frame_ctl; | ||
62 | __le16 duration_id; | ||
63 | u8 da[ETH_ALEN]; | ||
64 | u8 sa[ETH_ALEN]; | ||
65 | u8 bssid[ETH_ALEN]; | ||
66 | __le16 seq_ctl; | ||
67 | u8 payload[0]; | ||
68 | } __packed; | ||
69 | |||
70 | struct wl12xx_ie_header { | ||
71 | u8 id; | ||
72 | u8 len; | ||
73 | } __packed; | ||
74 | |||
75 | /* IEs */ | ||
76 | |||
77 | struct wl12xx_ie_ssid { | ||
78 | struct wl12xx_ie_header header; | ||
79 | char ssid[IEEE80211_MAX_SSID_LEN]; | ||
80 | } __packed; | ||
81 | |||
82 | struct wl12xx_ie_rates { | ||
83 | struct wl12xx_ie_header header; | ||
84 | u8 rates[MAX_SUPPORTED_RATES]; | ||
85 | } __packed; | ||
86 | |||
87 | struct wl12xx_ie_ds_params { | ||
88 | struct wl12xx_ie_header header; | ||
89 | u8 channel; | ||
90 | } __packed; | ||
91 | |||
92 | struct country_triplet { | ||
93 | u8 channel; | ||
94 | u8 num_channels; | ||
95 | u8 max_tx_power; | ||
96 | } __packed; | ||
97 | |||
98 | struct wl12xx_ie_country { | ||
99 | struct wl12xx_ie_header header; | ||
100 | u8 country_string[IEEE80211_COUNTRY_STRING_LEN]; | ||
101 | struct country_triplet triplets[MAX_COUNTRY_TRIPLETS]; | ||
102 | } __packed; | ||
103 | |||
104 | |||
105 | /* Templates */ | ||
106 | |||
107 | struct wl12xx_beacon_template { | ||
108 | struct ieee80211_header header; | ||
109 | __le32 time_stamp[2]; | ||
110 | __le16 beacon_interval; | ||
111 | __le16 capability; | ||
112 | struct wl12xx_ie_ssid ssid; | ||
113 | struct wl12xx_ie_rates rates; | ||
114 | struct wl12xx_ie_rates ext_rates; | ||
115 | struct wl12xx_ie_ds_params ds_params; | ||
116 | struct wl12xx_ie_country country; | ||
117 | } __packed; | ||
118 | |||
119 | struct wl12xx_null_data_template { | ||
120 | struct ieee80211_header header; | ||
121 | } __packed; | ||
122 | |||
123 | struct wl12xx_ps_poll_template { | ||
124 | __le16 fc; | ||
125 | __le16 aid; | ||
126 | u8 bssid[ETH_ALEN]; | ||
127 | u8 ta[ETH_ALEN]; | ||
128 | } __packed; | ||
129 | |||
130 | struct wl12xx_qos_null_data_template { | ||
131 | struct ieee80211_header header; | ||
132 | __le16 qos_ctl; | ||
133 | } __packed; | ||
134 | |||
135 | struct wl12xx_probe_req_template { | ||
136 | struct ieee80211_header header; | ||
137 | struct wl12xx_ie_ssid ssid; | ||
138 | struct wl12xx_ie_rates rates; | ||
139 | struct wl12xx_ie_rates ext_rates; | ||
140 | } __packed; | ||
141 | |||
142 | |||
143 | struct wl12xx_probe_resp_template { | ||
144 | struct ieee80211_header header; | ||
145 | __le32 time_stamp[2]; | ||
146 | __le16 beacon_interval; | ||
147 | __le16 capability; | ||
148 | struct wl12xx_ie_ssid ssid; | ||
149 | struct wl12xx_ie_rates rates; | ||
150 | struct wl12xx_ie_rates ext_rates; | ||
151 | struct wl12xx_ie_ds_params ds_params; | ||
152 | struct wl12xx_ie_country country; | ||
153 | } __packed; | ||
154 | |||
155 | #endif | ||
diff --git a/drivers/net/wireless/ti/wl12xx/Kconfig b/drivers/net/wireless/ti/wl12xx/Kconfig new file mode 100644 index 000000000000..af08c8609c63 --- /dev/null +++ b/drivers/net/wireless/ti/wl12xx/Kconfig | |||
@@ -0,0 +1,48 @@ | |||
1 | menuconfig WL12XX_MENU | ||
2 | tristate "TI wl12xx driver support" | ||
3 | depends on MAC80211 && EXPERIMENTAL | ||
4 | ---help--- | ||
5 | This will enable TI wl12xx driver support for the following chips: | ||
6 | wl1271, wl1273, wl1281 and wl1283. | ||
7 | The drivers make use of the mac80211 stack. | ||
8 | |||
9 | config WL12XX | ||
10 | tristate "TI wl12xx support" | ||
11 | depends on WL12XX_MENU && GENERIC_HARDIRQS | ||
12 | depends on INET | ||
13 | select FW_LOADER | ||
14 | ---help--- | ||
15 | This module adds support for wireless adapters based on TI wl1271 and | ||
16 | TI wl1273 chipsets. This module does *not* include support for wl1251. | ||
17 | For wl1251 support, use the separate homonymous driver instead. | ||
18 | |||
19 | If you choose to build a module, it will be called wl12xx. Say N if | ||
20 | unsure. | ||
21 | |||
22 | config WL12XX_SPI | ||
23 | tristate "TI wl12xx SPI support" | ||
24 | depends on WL12XX && SPI_MASTER | ||
25 | select CRC7 | ||
26 | ---help--- | ||
27 | This module adds support for the SPI interface of adapters using | ||
28 | TI wl12xx chipsets. Select this if your platform is using | ||
29 | the SPI bus. | ||
30 | |||
31 | If you choose to build a module, it'll be called wl12xx_spi. | ||
32 | Say N if unsure. | ||
33 | |||
34 | config WL12XX_SDIO | ||
35 | tristate "TI wl12xx SDIO support" | ||
36 | depends on WL12XX && MMC | ||
37 | ---help--- | ||
38 | This module adds support for the SDIO interface of adapters using | ||
39 | TI wl12xx chipsets. Select this if your platform is using | ||
40 | the SDIO bus. | ||
41 | |||
42 | If you choose to build a module, it'll be called wl12xx_sdio. | ||
43 | Say N if unsure. | ||
44 | |||
45 | config WL12XX_PLATFORM_DATA | ||
46 | bool | ||
47 | depends on WL12XX_SDIO != n || WL1251_SDIO != n | ||
48 | default y | ||
diff --git a/drivers/net/wireless/ti/wl12xx/Makefile b/drivers/net/wireless/ti/wl12xx/Makefile new file mode 100644 index 000000000000..98f289c907a9 --- /dev/null +++ b/drivers/net/wireless/ti/wl12xx/Makefile | |||
@@ -0,0 +1,15 @@ | |||
1 | wl12xx-objs = main.o cmd.o io.o event.o tx.o rx.o ps.o acx.o \ | ||
2 | boot.o init.o debugfs.o scan.o | ||
3 | |||
4 | wl12xx_spi-objs = spi.o | ||
5 | wl12xx_sdio-objs = sdio.o | ||
6 | |||
7 | wl12xx-$(CONFIG_NL80211_TESTMODE) += testmode.o | ||
8 | obj-$(CONFIG_WL12XX) += wl12xx.o | ||
9 | obj-$(CONFIG_WL12XX_SPI) += wl12xx_spi.o | ||
10 | obj-$(CONFIG_WL12XX_SDIO) += wl12xx_sdio.o | ||
11 | |||
12 | # small builtin driver bit | ||
13 | obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx_platform_data.o | ||
14 | |||
15 | ccflags-y += -D__CHECK_ENDIAN__ | ||
diff --git a/drivers/net/wireless/ti/wl12xx/acx.c b/drivers/net/wireless/ti/wl12xx/acx.c new file mode 100644 index 000000000000..bc96db0683a5 --- /dev/null +++ b/drivers/net/wireless/ti/wl12xx/acx.c | |||
@@ -0,0 +1,1742 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2008-2009 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 | #include "acx.h" | ||
25 | |||
26 | #include <linux/module.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | #include <linux/spi/spi.h> | ||
29 | #include <linux/slab.h> | ||
30 | |||
31 | #include "wl12xx.h" | ||
32 | #include "debug.h" | ||
33 | #include "wl12xx_80211.h" | ||
34 | #include "reg.h" | ||
35 | #include "ps.h" | ||
36 | |||
37 | int wl1271_acx_wake_up_conditions(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
38 | u8 wake_up_event, u8 listen_interval) | ||
39 | { | ||
40 | struct acx_wake_up_condition *wake_up; | ||
41 | int ret; | ||
42 | |||
43 | wl1271_debug(DEBUG_ACX, "acx wake up conditions (wake_up_event %d listen_interval %d)", | ||
44 | wake_up_event, listen_interval); | ||
45 | |||
46 | wake_up = kzalloc(sizeof(*wake_up), GFP_KERNEL); | ||
47 | if (!wake_up) { | ||
48 | ret = -ENOMEM; | ||
49 | goto out; | ||
50 | } | ||
51 | |||
52 | wake_up->role_id = wlvif->role_id; | ||
53 | wake_up->wake_up_event = wake_up_event; | ||
54 | wake_up->listen_interval = listen_interval; | ||
55 | |||
56 | ret = wl1271_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS, | ||
57 | wake_up, sizeof(*wake_up)); | ||
58 | if (ret < 0) { | ||
59 | wl1271_warning("could not set wake up conditions: %d", ret); | ||
60 | goto out; | ||
61 | } | ||
62 | |||
63 | out: | ||
64 | kfree(wake_up); | ||
65 | return ret; | ||
66 | } | ||
67 | |||
68 | int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth) | ||
69 | { | ||
70 | struct acx_sleep_auth *auth; | ||
71 | int ret; | ||
72 | |||
73 | wl1271_debug(DEBUG_ACX, "acx sleep auth"); | ||
74 | |||
75 | auth = kzalloc(sizeof(*auth), GFP_KERNEL); | ||
76 | if (!auth) { | ||
77 | ret = -ENOMEM; | ||
78 | goto out; | ||
79 | } | ||
80 | |||
81 | auth->sleep_auth = sleep_auth; | ||
82 | |||
83 | ret = wl1271_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth)); | ||
84 | |||
85 | out: | ||
86 | kfree(auth); | ||
87 | return ret; | ||
88 | } | ||
89 | |||
90 | int wl1271_acx_tx_power(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
91 | int power) | ||
92 | { | ||
93 | struct acx_current_tx_power *acx; | ||
94 | int ret; | ||
95 | |||
96 | wl1271_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr %d", power); | ||
97 | |||
98 | if (power < 0 || power > 25) | ||
99 | return -EINVAL; | ||
100 | |||
101 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
102 | if (!acx) { | ||
103 | ret = -ENOMEM; | ||
104 | goto out; | ||
105 | } | ||
106 | |||
107 | acx->role_id = wlvif->role_id; | ||
108 | acx->current_tx_power = power * 10; | ||
109 | |||
110 | ret = wl1271_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx)); | ||
111 | if (ret < 0) { | ||
112 | wl1271_warning("configure of tx power failed: %d", ret); | ||
113 | goto out; | ||
114 | } | ||
115 | |||
116 | out: | ||
117 | kfree(acx); | ||
118 | return ret; | ||
119 | } | ||
120 | |||
121 | int wl1271_acx_feature_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif) | ||
122 | { | ||
123 | struct acx_feature_config *feature; | ||
124 | int ret; | ||
125 | |||
126 | wl1271_debug(DEBUG_ACX, "acx feature cfg"); | ||
127 | |||
128 | feature = kzalloc(sizeof(*feature), GFP_KERNEL); | ||
129 | if (!feature) { | ||
130 | ret = -ENOMEM; | ||
131 | goto out; | ||
132 | } | ||
133 | |||
134 | /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */ | ||
135 | feature->role_id = wlvif->role_id; | ||
136 | feature->data_flow_options = 0; | ||
137 | feature->options = 0; | ||
138 | |||
139 | ret = wl1271_cmd_configure(wl, ACX_FEATURE_CFG, | ||
140 | feature, sizeof(*feature)); | ||
141 | if (ret < 0) { | ||
142 | wl1271_error("Couldnt set HW encryption"); | ||
143 | goto out; | ||
144 | } | ||
145 | |||
146 | out: | ||
147 | kfree(feature); | ||
148 | return ret; | ||
149 | } | ||
150 | |||
151 | int wl1271_acx_mem_map(struct wl1271 *wl, struct acx_header *mem_map, | ||
152 | size_t len) | ||
153 | { | ||
154 | int ret; | ||
155 | |||
156 | wl1271_debug(DEBUG_ACX, "acx mem map"); | ||
157 | |||
158 | ret = wl1271_cmd_interrogate(wl, ACX_MEM_MAP, mem_map, len); | ||
159 | if (ret < 0) | ||
160 | return ret; | ||
161 | |||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl) | ||
166 | { | ||
167 | struct acx_rx_msdu_lifetime *acx; | ||
168 | int ret; | ||
169 | |||
170 | wl1271_debug(DEBUG_ACX, "acx rx msdu life time"); | ||
171 | |||
172 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
173 | if (!acx) { | ||
174 | ret = -ENOMEM; | ||
175 | goto out; | ||
176 | } | ||
177 | |||
178 | acx->lifetime = cpu_to_le32(wl->conf.rx.rx_msdu_life_time); | ||
179 | ret = wl1271_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME, | ||
180 | acx, sizeof(*acx)); | ||
181 | if (ret < 0) { | ||
182 | wl1271_warning("failed to set rx msdu life time: %d", ret); | ||
183 | goto out; | ||
184 | } | ||
185 | |||
186 | out: | ||
187 | kfree(acx); | ||
188 | return ret; | ||
189 | } | ||
190 | |||
191 | int wl1271_acx_slot(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
192 | enum acx_slot_type slot_time) | ||
193 | { | ||
194 | struct acx_slot *slot; | ||
195 | int ret; | ||
196 | |||
197 | wl1271_debug(DEBUG_ACX, "acx slot"); | ||
198 | |||
199 | slot = kzalloc(sizeof(*slot), GFP_KERNEL); | ||
200 | if (!slot) { | ||
201 | ret = -ENOMEM; | ||
202 | goto out; | ||
203 | } | ||
204 | |||
205 | slot->role_id = wlvif->role_id; | ||
206 | slot->wone_index = STATION_WONE_INDEX; | ||
207 | slot->slot_time = slot_time; | ||
208 | |||
209 | ret = wl1271_cmd_configure(wl, ACX_SLOT, slot, sizeof(*slot)); | ||
210 | if (ret < 0) { | ||
211 | wl1271_warning("failed to set slot time: %d", ret); | ||
212 | goto out; | ||
213 | } | ||
214 | |||
215 | out: | ||
216 | kfree(slot); | ||
217 | return ret; | ||
218 | } | ||
219 | |||
220 | int wl1271_acx_group_address_tbl(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
221 | bool enable, void *mc_list, u32 mc_list_len) | ||
222 | { | ||
223 | struct acx_dot11_grp_addr_tbl *acx; | ||
224 | int ret; | ||
225 | |||
226 | wl1271_debug(DEBUG_ACX, "acx group address tbl"); | ||
227 | |||
228 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
229 | if (!acx) { | ||
230 | ret = -ENOMEM; | ||
231 | goto out; | ||
232 | } | ||
233 | |||
234 | /* MAC filtering */ | ||
235 | acx->role_id = wlvif->role_id; | ||
236 | acx->enabled = enable; | ||
237 | acx->num_groups = mc_list_len; | ||
238 | memcpy(acx->mac_table, mc_list, mc_list_len * ETH_ALEN); | ||
239 | |||
240 | ret = wl1271_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL, | ||
241 | acx, sizeof(*acx)); | ||
242 | if (ret < 0) { | ||
243 | wl1271_warning("failed to set group addr table: %d", ret); | ||
244 | goto out; | ||
245 | } | ||
246 | |||
247 | out: | ||
248 | kfree(acx); | ||
249 | return ret; | ||
250 | } | ||
251 | |||
252 | int wl1271_acx_service_period_timeout(struct wl1271 *wl, | ||
253 | struct wl12xx_vif *wlvif) | ||
254 | { | ||
255 | struct acx_rx_timeout *rx_timeout; | ||
256 | int ret; | ||
257 | |||
258 | rx_timeout = kzalloc(sizeof(*rx_timeout), GFP_KERNEL); | ||
259 | if (!rx_timeout) { | ||
260 | ret = -ENOMEM; | ||
261 | goto out; | ||
262 | } | ||
263 | |||
264 | wl1271_debug(DEBUG_ACX, "acx service period timeout"); | ||
265 | |||
266 | rx_timeout->role_id = wlvif->role_id; | ||
267 | rx_timeout->ps_poll_timeout = cpu_to_le16(wl->conf.rx.ps_poll_timeout); | ||
268 | rx_timeout->upsd_timeout = cpu_to_le16(wl->conf.rx.upsd_timeout); | ||
269 | |||
270 | ret = wl1271_cmd_configure(wl, ACX_SERVICE_PERIOD_TIMEOUT, | ||
271 | rx_timeout, sizeof(*rx_timeout)); | ||
272 | if (ret < 0) { | ||
273 | wl1271_warning("failed to set service period timeout: %d", | ||
274 | ret); | ||
275 | goto out; | ||
276 | } | ||
277 | |||
278 | out: | ||
279 | kfree(rx_timeout); | ||
280 | return ret; | ||
281 | } | ||
282 | |||
283 | int wl1271_acx_rts_threshold(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
284 | u32 rts_threshold) | ||
285 | { | ||
286 | struct acx_rts_threshold *rts; | ||
287 | int ret; | ||
288 | |||
289 | /* | ||
290 | * If the RTS threshold is not configured or out of range, use the | ||
291 | * default value. | ||
292 | */ | ||
293 | if (rts_threshold > IEEE80211_MAX_RTS_THRESHOLD) | ||
294 | rts_threshold = wl->conf.rx.rts_threshold; | ||
295 | |||
296 | wl1271_debug(DEBUG_ACX, "acx rts threshold: %d", rts_threshold); | ||
297 | |||
298 | rts = kzalloc(sizeof(*rts), GFP_KERNEL); | ||
299 | if (!rts) { | ||
300 | ret = -ENOMEM; | ||
301 | goto out; | ||
302 | } | ||
303 | |||
304 | rts->role_id = wlvif->role_id; | ||
305 | rts->threshold = cpu_to_le16((u16)rts_threshold); | ||
306 | |||
307 | ret = wl1271_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts)); | ||
308 | if (ret < 0) { | ||
309 | wl1271_warning("failed to set rts threshold: %d", ret); | ||
310 | goto out; | ||
311 | } | ||
312 | |||
313 | out: | ||
314 | kfree(rts); | ||
315 | return ret; | ||
316 | } | ||
317 | |||
318 | int wl1271_acx_dco_itrim_params(struct wl1271 *wl) | ||
319 | { | ||
320 | struct acx_dco_itrim_params *dco; | ||
321 | struct conf_itrim_settings *c = &wl->conf.itrim; | ||
322 | int ret; | ||
323 | |||
324 | wl1271_debug(DEBUG_ACX, "acx dco itrim parameters"); | ||
325 | |||
326 | dco = kzalloc(sizeof(*dco), GFP_KERNEL); | ||
327 | if (!dco) { | ||
328 | ret = -ENOMEM; | ||
329 | goto out; | ||
330 | } | ||
331 | |||
332 | dco->enable = c->enable; | ||
333 | dco->timeout = cpu_to_le32(c->timeout); | ||
334 | |||
335 | ret = wl1271_cmd_configure(wl, ACX_SET_DCO_ITRIM_PARAMS, | ||
336 | dco, sizeof(*dco)); | ||
337 | if (ret < 0) { | ||
338 | wl1271_warning("failed to set dco itrim parameters: %d", ret); | ||
339 | goto out; | ||
340 | } | ||
341 | |||
342 | out: | ||
343 | kfree(dco); | ||
344 | return ret; | ||
345 | } | ||
346 | |||
347 | int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
348 | bool enable_filter) | ||
349 | { | ||
350 | struct acx_beacon_filter_option *beacon_filter = NULL; | ||
351 | int ret = 0; | ||
352 | |||
353 | wl1271_debug(DEBUG_ACX, "acx beacon filter opt"); | ||
354 | |||
355 | if (enable_filter && | ||
356 | wl->conf.conn.bcn_filt_mode == CONF_BCN_FILT_MODE_DISABLED) | ||
357 | goto out; | ||
358 | |||
359 | beacon_filter = kzalloc(sizeof(*beacon_filter), GFP_KERNEL); | ||
360 | if (!beacon_filter) { | ||
361 | ret = -ENOMEM; | ||
362 | goto out; | ||
363 | } | ||
364 | |||
365 | beacon_filter->role_id = wlvif->role_id; | ||
366 | beacon_filter->enable = enable_filter; | ||
367 | |||
368 | /* | ||
369 | * When set to zero, and the filter is enabled, beacons | ||
370 | * without the unicast TIM bit set are dropped. | ||
371 | */ | ||
372 | beacon_filter->max_num_beacons = 0; | ||
373 | |||
374 | ret = wl1271_cmd_configure(wl, ACX_BEACON_FILTER_OPT, | ||
375 | beacon_filter, sizeof(*beacon_filter)); | ||
376 | if (ret < 0) { | ||
377 | wl1271_warning("failed to set beacon filter opt: %d", ret); | ||
378 | goto out; | ||
379 | } | ||
380 | |||
381 | out: | ||
382 | kfree(beacon_filter); | ||
383 | return ret; | ||
384 | } | ||
385 | |||
386 | int wl1271_acx_beacon_filter_table(struct wl1271 *wl, | ||
387 | struct wl12xx_vif *wlvif) | ||
388 | { | ||
389 | struct acx_beacon_filter_ie_table *ie_table; | ||
390 | int i, idx = 0; | ||
391 | int ret; | ||
392 | bool vendor_spec = false; | ||
393 | |||
394 | wl1271_debug(DEBUG_ACX, "acx beacon filter table"); | ||
395 | |||
396 | ie_table = kzalloc(sizeof(*ie_table), GFP_KERNEL); | ||
397 | if (!ie_table) { | ||
398 | ret = -ENOMEM; | ||
399 | goto out; | ||
400 | } | ||
401 | |||
402 | /* configure default beacon pass-through rules */ | ||
403 | ie_table->role_id = wlvif->role_id; | ||
404 | ie_table->num_ie = 0; | ||
405 | for (i = 0; i < wl->conf.conn.bcn_filt_ie_count; i++) { | ||
406 | struct conf_bcn_filt_rule *r = &(wl->conf.conn.bcn_filt_ie[i]); | ||
407 | ie_table->table[idx++] = r->ie; | ||
408 | ie_table->table[idx++] = r->rule; | ||
409 | |||
410 | if (r->ie == WLAN_EID_VENDOR_SPECIFIC) { | ||
411 | /* only one vendor specific ie allowed */ | ||
412 | if (vendor_spec) | ||
413 | continue; | ||
414 | |||
415 | /* for vendor specific rules configure the | ||
416 | additional fields */ | ||
417 | memcpy(&(ie_table->table[idx]), r->oui, | ||
418 | CONF_BCN_IE_OUI_LEN); | ||
419 | idx += CONF_BCN_IE_OUI_LEN; | ||
420 | ie_table->table[idx++] = r->type; | ||
421 | memcpy(&(ie_table->table[idx]), r->version, | ||
422 | CONF_BCN_IE_VER_LEN); | ||
423 | idx += CONF_BCN_IE_VER_LEN; | ||
424 | vendor_spec = true; | ||
425 | } | ||
426 | |||
427 | ie_table->num_ie++; | ||
428 | } | ||
429 | |||
430 | ret = wl1271_cmd_configure(wl, ACX_BEACON_FILTER_TABLE, | ||
431 | ie_table, sizeof(*ie_table)); | ||
432 | if (ret < 0) { | ||
433 | wl1271_warning("failed to set beacon filter table: %d", ret); | ||
434 | goto out; | ||
435 | } | ||
436 | |||
437 | out: | ||
438 | kfree(ie_table); | ||
439 | return ret; | ||
440 | } | ||
441 | |||
442 | #define ACX_CONN_MONIT_DISABLE_VALUE 0xffffffff | ||
443 | |||
444 | int wl1271_acx_conn_monit_params(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
445 | bool enable) | ||
446 | { | ||
447 | struct acx_conn_monit_params *acx; | ||
448 | u32 threshold = ACX_CONN_MONIT_DISABLE_VALUE; | ||
449 | u32 timeout = ACX_CONN_MONIT_DISABLE_VALUE; | ||
450 | int ret; | ||
451 | |||
452 | wl1271_debug(DEBUG_ACX, "acx connection monitor parameters: %s", | ||
453 | enable ? "enabled" : "disabled"); | ||
454 | |||
455 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
456 | if (!acx) { | ||
457 | ret = -ENOMEM; | ||
458 | goto out; | ||
459 | } | ||
460 | |||
461 | if (enable) { | ||
462 | threshold = wl->conf.conn.synch_fail_thold; | ||
463 | timeout = wl->conf.conn.bss_lose_timeout; | ||
464 | } | ||
465 | |||
466 | acx->role_id = wlvif->role_id; | ||
467 | acx->synch_fail_thold = cpu_to_le32(threshold); | ||
468 | acx->bss_lose_timeout = cpu_to_le32(timeout); | ||
469 | |||
470 | ret = wl1271_cmd_configure(wl, ACX_CONN_MONIT_PARAMS, | ||
471 | acx, sizeof(*acx)); | ||
472 | if (ret < 0) { | ||
473 | wl1271_warning("failed to set connection monitor " | ||
474 | "parameters: %d", ret); | ||
475 | goto out; | ||
476 | } | ||
477 | |||
478 | out: | ||
479 | kfree(acx); | ||
480 | return ret; | ||
481 | } | ||
482 | |||
483 | |||
484 | int wl1271_acx_sg_enable(struct wl1271 *wl, bool enable) | ||
485 | { | ||
486 | struct acx_bt_wlan_coex *pta; | ||
487 | int ret; | ||
488 | |||
489 | wl1271_debug(DEBUG_ACX, "acx sg enable"); | ||
490 | |||
491 | pta = kzalloc(sizeof(*pta), GFP_KERNEL); | ||
492 | if (!pta) { | ||
493 | ret = -ENOMEM; | ||
494 | goto out; | ||
495 | } | ||
496 | |||
497 | if (enable) | ||
498 | pta->enable = wl->conf.sg.state; | ||
499 | else | ||
500 | pta->enable = CONF_SG_DISABLE; | ||
501 | |||
502 | ret = wl1271_cmd_configure(wl, ACX_SG_ENABLE, pta, sizeof(*pta)); | ||
503 | if (ret < 0) { | ||
504 | wl1271_warning("failed to set softgemini enable: %d", ret); | ||
505 | goto out; | ||
506 | } | ||
507 | |||
508 | out: | ||
509 | kfree(pta); | ||
510 | return ret; | ||
511 | } | ||
512 | |||
513 | int wl12xx_acx_sg_cfg(struct wl1271 *wl) | ||
514 | { | ||
515 | struct acx_bt_wlan_coex_param *param; | ||
516 | struct conf_sg_settings *c = &wl->conf.sg; | ||
517 | int i, ret; | ||
518 | |||
519 | wl1271_debug(DEBUG_ACX, "acx sg cfg"); | ||
520 | |||
521 | param = kzalloc(sizeof(*param), GFP_KERNEL); | ||
522 | if (!param) { | ||
523 | ret = -ENOMEM; | ||
524 | goto out; | ||
525 | } | ||
526 | |||
527 | /* BT-WLAN coext parameters */ | ||
528 | for (i = 0; i < CONF_SG_PARAMS_MAX; i++) | ||
529 | param->params[i] = cpu_to_le32(c->params[i]); | ||
530 | param->param_idx = CONF_SG_PARAMS_ALL; | ||
531 | |||
532 | ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param)); | ||
533 | if (ret < 0) { | ||
534 | wl1271_warning("failed to set sg config: %d", ret); | ||
535 | goto out; | ||
536 | } | ||
537 | |||
538 | out: | ||
539 | kfree(param); | ||
540 | return ret; | ||
541 | } | ||
542 | |||
543 | int wl1271_acx_cca_threshold(struct wl1271 *wl) | ||
544 | { | ||
545 | struct acx_energy_detection *detection; | ||
546 | int ret; | ||
547 | |||
548 | wl1271_debug(DEBUG_ACX, "acx cca threshold"); | ||
549 | |||
550 | detection = kzalloc(sizeof(*detection), GFP_KERNEL); | ||
551 | if (!detection) { | ||
552 | ret = -ENOMEM; | ||
553 | goto out; | ||
554 | } | ||
555 | |||
556 | detection->rx_cca_threshold = cpu_to_le16(wl->conf.rx.rx_cca_threshold); | ||
557 | detection->tx_energy_detection = wl->conf.tx.tx_energy_detection; | ||
558 | |||
559 | ret = wl1271_cmd_configure(wl, ACX_CCA_THRESHOLD, | ||
560 | detection, sizeof(*detection)); | ||
561 | if (ret < 0) | ||
562 | wl1271_warning("failed to set cca threshold: %d", ret); | ||
563 | |||
564 | out: | ||
565 | kfree(detection); | ||
566 | return ret; | ||
567 | } | ||
568 | |||
569 | int wl1271_acx_bcn_dtim_options(struct wl1271 *wl, struct wl12xx_vif *wlvif) | ||
570 | { | ||
571 | struct acx_beacon_broadcast *bb; | ||
572 | int ret; | ||
573 | |||
574 | wl1271_debug(DEBUG_ACX, "acx bcn dtim options"); | ||
575 | |||
576 | bb = kzalloc(sizeof(*bb), GFP_KERNEL); | ||
577 | if (!bb) { | ||
578 | ret = -ENOMEM; | ||
579 | goto out; | ||
580 | } | ||
581 | |||
582 | bb->role_id = wlvif->role_id; | ||
583 | bb->beacon_rx_timeout = cpu_to_le16(wl->conf.conn.beacon_rx_timeout); | ||
584 | bb->broadcast_timeout = cpu_to_le16(wl->conf.conn.broadcast_timeout); | ||
585 | bb->rx_broadcast_in_ps = wl->conf.conn.rx_broadcast_in_ps; | ||
586 | bb->ps_poll_threshold = wl->conf.conn.ps_poll_threshold; | ||
587 | |||
588 | ret = wl1271_cmd_configure(wl, ACX_BCN_DTIM_OPTIONS, bb, sizeof(*bb)); | ||
589 | if (ret < 0) { | ||
590 | wl1271_warning("failed to set rx config: %d", ret); | ||
591 | goto out; | ||
592 | } | ||
593 | |||
594 | out: | ||
595 | kfree(bb); | ||
596 | return ret; | ||
597 | } | ||
598 | |||
599 | int wl1271_acx_aid(struct wl1271 *wl, struct wl12xx_vif *wlvif, u16 aid) | ||
600 | { | ||
601 | struct acx_aid *acx_aid; | ||
602 | int ret; | ||
603 | |||
604 | wl1271_debug(DEBUG_ACX, "acx aid"); | ||
605 | |||
606 | acx_aid = kzalloc(sizeof(*acx_aid), GFP_KERNEL); | ||
607 | if (!acx_aid) { | ||
608 | ret = -ENOMEM; | ||
609 | goto out; | ||
610 | } | ||
611 | |||
612 | acx_aid->role_id = wlvif->role_id; | ||
613 | acx_aid->aid = cpu_to_le16(aid); | ||
614 | |||
615 | ret = wl1271_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid)); | ||
616 | if (ret < 0) { | ||
617 | wl1271_warning("failed to set aid: %d", ret); | ||
618 | goto out; | ||
619 | } | ||
620 | |||
621 | out: | ||
622 | kfree(acx_aid); | ||
623 | return ret; | ||
624 | } | ||
625 | |||
626 | int wl1271_acx_event_mbox_mask(struct wl1271 *wl, u32 event_mask) | ||
627 | { | ||
628 | struct acx_event_mask *mask; | ||
629 | int ret; | ||
630 | |||
631 | wl1271_debug(DEBUG_ACX, "acx event mbox mask"); | ||
632 | |||
633 | mask = kzalloc(sizeof(*mask), GFP_KERNEL); | ||
634 | if (!mask) { | ||
635 | ret = -ENOMEM; | ||
636 | goto out; | ||
637 | } | ||
638 | |||
639 | /* high event mask is unused */ | ||
640 | mask->high_event_mask = cpu_to_le32(0xffffffff); | ||
641 | mask->event_mask = cpu_to_le32(event_mask); | ||
642 | |||
643 | ret = wl1271_cmd_configure(wl, ACX_EVENT_MBOX_MASK, | ||
644 | mask, sizeof(*mask)); | ||
645 | if (ret < 0) { | ||
646 | wl1271_warning("failed to set acx_event_mbox_mask: %d", ret); | ||
647 | goto out; | ||
648 | } | ||
649 | |||
650 | out: | ||
651 | kfree(mask); | ||
652 | return ret; | ||
653 | } | ||
654 | |||
655 | int wl1271_acx_set_preamble(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
656 | enum acx_preamble_type preamble) | ||
657 | { | ||
658 | struct acx_preamble *acx; | ||
659 | int ret; | ||
660 | |||
661 | wl1271_debug(DEBUG_ACX, "acx_set_preamble"); | ||
662 | |||
663 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
664 | if (!acx) { | ||
665 | ret = -ENOMEM; | ||
666 | goto out; | ||
667 | } | ||
668 | |||
669 | acx->role_id = wlvif->role_id; | ||
670 | acx->preamble = preamble; | ||
671 | |||
672 | ret = wl1271_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx)); | ||
673 | if (ret < 0) { | ||
674 | wl1271_warning("Setting of preamble failed: %d", ret); | ||
675 | goto out; | ||
676 | } | ||
677 | |||
678 | out: | ||
679 | kfree(acx); | ||
680 | return ret; | ||
681 | } | ||
682 | |||
683 | int wl1271_acx_cts_protect(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
684 | enum acx_ctsprotect_type ctsprotect) | ||
685 | { | ||
686 | struct acx_ctsprotect *acx; | ||
687 | int ret; | ||
688 | |||
689 | wl1271_debug(DEBUG_ACX, "acx_set_ctsprotect"); | ||
690 | |||
691 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
692 | if (!acx) { | ||
693 | ret = -ENOMEM; | ||
694 | goto out; | ||
695 | } | ||
696 | |||
697 | acx->role_id = wlvif->role_id; | ||
698 | acx->ctsprotect = ctsprotect; | ||
699 | |||
700 | ret = wl1271_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx)); | ||
701 | if (ret < 0) { | ||
702 | wl1271_warning("Setting of ctsprotect failed: %d", ret); | ||
703 | goto out; | ||
704 | } | ||
705 | |||
706 | out: | ||
707 | kfree(acx); | ||
708 | return ret; | ||
709 | } | ||
710 | |||
711 | int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats) | ||
712 | { | ||
713 | int ret; | ||
714 | |||
715 | wl1271_debug(DEBUG_ACX, "acx statistics"); | ||
716 | |||
717 | ret = wl1271_cmd_interrogate(wl, ACX_STATISTICS, stats, | ||
718 | sizeof(*stats)); | ||
719 | if (ret < 0) { | ||
720 | wl1271_warning("acx statistics failed: %d", ret); | ||
721 | return -ENOMEM; | ||
722 | } | ||
723 | |||
724 | return 0; | ||
725 | } | ||
726 | |||
727 | int wl1271_acx_sta_rate_policies(struct wl1271 *wl, struct wl12xx_vif *wlvif) | ||
728 | { | ||
729 | struct acx_rate_policy *acx; | ||
730 | struct conf_tx_rate_class *c = &wl->conf.tx.sta_rc_conf; | ||
731 | int ret = 0; | ||
732 | |||
733 | wl1271_debug(DEBUG_ACX, "acx rate policies"); | ||
734 | |||
735 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
736 | |||
737 | if (!acx) { | ||
738 | ret = -ENOMEM; | ||
739 | goto out; | ||
740 | } | ||
741 | |||
742 | wl1271_debug(DEBUG_ACX, "basic_rate: 0x%x, full_rate: 0x%x", | ||
743 | wlvif->basic_rate, wlvif->rate_set); | ||
744 | |||
745 | /* configure one basic rate class */ | ||
746 | acx->rate_policy_idx = cpu_to_le32(wlvif->sta.basic_rate_idx); | ||
747 | acx->rate_policy.enabled_rates = cpu_to_le32(wlvif->basic_rate); | ||
748 | acx->rate_policy.short_retry_limit = c->short_retry_limit; | ||
749 | acx->rate_policy.long_retry_limit = c->long_retry_limit; | ||
750 | acx->rate_policy.aflags = c->aflags; | ||
751 | |||
752 | ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); | ||
753 | if (ret < 0) { | ||
754 | wl1271_warning("Setting of rate policies failed: %d", ret); | ||
755 | goto out; | ||
756 | } | ||
757 | |||
758 | /* configure one AP supported rate class */ | ||
759 | acx->rate_policy_idx = cpu_to_le32(wlvif->sta.ap_rate_idx); | ||
760 | acx->rate_policy.enabled_rates = cpu_to_le32(wlvif->rate_set); | ||
761 | acx->rate_policy.short_retry_limit = c->short_retry_limit; | ||
762 | acx->rate_policy.long_retry_limit = c->long_retry_limit; | ||
763 | acx->rate_policy.aflags = c->aflags; | ||
764 | |||
765 | ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); | ||
766 | if (ret < 0) { | ||
767 | wl1271_warning("Setting of rate policies failed: %d", ret); | ||
768 | goto out; | ||
769 | } | ||
770 | |||
771 | /* | ||
772 | * configure one rate class for basic p2p operations. | ||
773 | * (p2p packets should always go out with OFDM rates, even | ||
774 | * if we are currently connected to 11b AP) | ||
775 | */ | ||
776 | acx->rate_policy_idx = cpu_to_le32(wlvif->sta.p2p_rate_idx); | ||
777 | acx->rate_policy.enabled_rates = | ||
778 | cpu_to_le32(CONF_TX_RATE_MASK_BASIC_P2P); | ||
779 | acx->rate_policy.short_retry_limit = c->short_retry_limit; | ||
780 | acx->rate_policy.long_retry_limit = c->long_retry_limit; | ||
781 | acx->rate_policy.aflags = c->aflags; | ||
782 | |||
783 | ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); | ||
784 | if (ret < 0) { | ||
785 | wl1271_warning("Setting of rate policies failed: %d", ret); | ||
786 | goto out; | ||
787 | } | ||
788 | |||
789 | out: | ||
790 | kfree(acx); | ||
791 | return ret; | ||
792 | } | ||
793 | |||
794 | int wl1271_acx_ap_rate_policy(struct wl1271 *wl, struct conf_tx_rate_class *c, | ||
795 | u8 idx) | ||
796 | { | ||
797 | struct acx_rate_policy *acx; | ||
798 | int ret = 0; | ||
799 | |||
800 | wl1271_debug(DEBUG_ACX, "acx ap rate policy %d rates 0x%x", | ||
801 | idx, c->enabled_rates); | ||
802 | |||
803 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
804 | if (!acx) { | ||
805 | ret = -ENOMEM; | ||
806 | goto out; | ||
807 | } | ||
808 | |||
809 | acx->rate_policy.enabled_rates = cpu_to_le32(c->enabled_rates); | ||
810 | acx->rate_policy.short_retry_limit = c->short_retry_limit; | ||
811 | acx->rate_policy.long_retry_limit = c->long_retry_limit; | ||
812 | acx->rate_policy.aflags = c->aflags; | ||
813 | |||
814 | acx->rate_policy_idx = cpu_to_le32(idx); | ||
815 | |||
816 | ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); | ||
817 | if (ret < 0) { | ||
818 | wl1271_warning("Setting of ap rate policy failed: %d", ret); | ||
819 | goto out; | ||
820 | } | ||
821 | |||
822 | out: | ||
823 | kfree(acx); | ||
824 | return ret; | ||
825 | } | ||
826 | |||
827 | int wl1271_acx_ac_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
828 | u8 ac, u8 cw_min, u16 cw_max, u8 aifsn, u16 txop) | ||
829 | { | ||
830 | struct acx_ac_cfg *acx; | ||
831 | int ret = 0; | ||
832 | |||
833 | wl1271_debug(DEBUG_ACX, "acx ac cfg %d cw_ming %d cw_max %d " | ||
834 | "aifs %d txop %d", ac, cw_min, cw_max, aifsn, txop); | ||
835 | |||
836 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
837 | |||
838 | if (!acx) { | ||
839 | ret = -ENOMEM; | ||
840 | goto out; | ||
841 | } | ||
842 | |||
843 | acx->role_id = wlvif->role_id; | ||
844 | acx->ac = ac; | ||
845 | acx->cw_min = cw_min; | ||
846 | acx->cw_max = cpu_to_le16(cw_max); | ||
847 | acx->aifsn = aifsn; | ||
848 | acx->tx_op_limit = cpu_to_le16(txop); | ||
849 | |||
850 | ret = wl1271_cmd_configure(wl, ACX_AC_CFG, acx, sizeof(*acx)); | ||
851 | if (ret < 0) { | ||
852 | wl1271_warning("acx ac cfg failed: %d", ret); | ||
853 | goto out; | ||
854 | } | ||
855 | |||
856 | out: | ||
857 | kfree(acx); | ||
858 | return ret; | ||
859 | } | ||
860 | |||
861 | int wl1271_acx_tid_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
862 | u8 queue_id, u8 channel_type, | ||
863 | u8 tsid, u8 ps_scheme, u8 ack_policy, | ||
864 | u32 apsd_conf0, u32 apsd_conf1) | ||
865 | { | ||
866 | struct acx_tid_config *acx; | ||
867 | int ret = 0; | ||
868 | |||
869 | wl1271_debug(DEBUG_ACX, "acx tid config"); | ||
870 | |||
871 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
872 | |||
873 | if (!acx) { | ||
874 | ret = -ENOMEM; | ||
875 | goto out; | ||
876 | } | ||
877 | |||
878 | acx->role_id = wlvif->role_id; | ||
879 | acx->queue_id = queue_id; | ||
880 | acx->channel_type = channel_type; | ||
881 | acx->tsid = tsid; | ||
882 | acx->ps_scheme = ps_scheme; | ||
883 | acx->ack_policy = ack_policy; | ||
884 | acx->apsd_conf[0] = cpu_to_le32(apsd_conf0); | ||
885 | acx->apsd_conf[1] = cpu_to_le32(apsd_conf1); | ||
886 | |||
887 | ret = wl1271_cmd_configure(wl, ACX_TID_CFG, acx, sizeof(*acx)); | ||
888 | if (ret < 0) { | ||
889 | wl1271_warning("Setting of tid config failed: %d", ret); | ||
890 | goto out; | ||
891 | } | ||
892 | |||
893 | out: | ||
894 | kfree(acx); | ||
895 | return ret; | ||
896 | } | ||
897 | |||
898 | int wl1271_acx_frag_threshold(struct wl1271 *wl, u32 frag_threshold) | ||
899 | { | ||
900 | struct acx_frag_threshold *acx; | ||
901 | int ret = 0; | ||
902 | |||
903 | /* | ||
904 | * If the fragmentation is not configured or out of range, use the | ||
905 | * default value. | ||
906 | */ | ||
907 | if (frag_threshold > IEEE80211_MAX_FRAG_THRESHOLD) | ||
908 | frag_threshold = wl->conf.tx.frag_threshold; | ||
909 | |||
910 | wl1271_debug(DEBUG_ACX, "acx frag threshold: %d", frag_threshold); | ||
911 | |||
912 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
913 | |||
914 | if (!acx) { | ||
915 | ret = -ENOMEM; | ||
916 | goto out; | ||
917 | } | ||
918 | |||
919 | acx->frag_threshold = cpu_to_le16((u16)frag_threshold); | ||
920 | ret = wl1271_cmd_configure(wl, ACX_FRAG_CFG, acx, sizeof(*acx)); | ||
921 | if (ret < 0) { | ||
922 | wl1271_warning("Setting of frag threshold failed: %d", ret); | ||
923 | goto out; | ||
924 | } | ||
925 | |||
926 | out: | ||
927 | kfree(acx); | ||
928 | return ret; | ||
929 | } | ||
930 | |||
931 | int wl1271_acx_tx_config_options(struct wl1271 *wl) | ||
932 | { | ||
933 | struct acx_tx_config_options *acx; | ||
934 | int ret = 0; | ||
935 | |||
936 | wl1271_debug(DEBUG_ACX, "acx tx config options"); | ||
937 | |||
938 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
939 | |||
940 | if (!acx) { | ||
941 | ret = -ENOMEM; | ||
942 | goto out; | ||
943 | } | ||
944 | |||
945 | acx->tx_compl_timeout = cpu_to_le16(wl->conf.tx.tx_compl_timeout); | ||
946 | acx->tx_compl_threshold = cpu_to_le16(wl->conf.tx.tx_compl_threshold); | ||
947 | ret = wl1271_cmd_configure(wl, ACX_TX_CONFIG_OPT, acx, sizeof(*acx)); | ||
948 | if (ret < 0) { | ||
949 | wl1271_warning("Setting of tx options failed: %d", ret); | ||
950 | goto out; | ||
951 | } | ||
952 | |||
953 | out: | ||
954 | kfree(acx); | ||
955 | return ret; | ||
956 | } | ||
957 | |||
958 | int wl12xx_acx_mem_cfg(struct wl1271 *wl) | ||
959 | { | ||
960 | struct wl12xx_acx_config_memory *mem_conf; | ||
961 | struct conf_memory_settings *mem; | ||
962 | int ret; | ||
963 | |||
964 | wl1271_debug(DEBUG_ACX, "wl1271 mem cfg"); | ||
965 | |||
966 | mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL); | ||
967 | if (!mem_conf) { | ||
968 | ret = -ENOMEM; | ||
969 | goto out; | ||
970 | } | ||
971 | |||
972 | if (wl->chip.id == CHIP_ID_1283_PG20) | ||
973 | mem = &wl->conf.mem_wl128x; | ||
974 | else | ||
975 | mem = &wl->conf.mem_wl127x; | ||
976 | |||
977 | /* memory config */ | ||
978 | mem_conf->num_stations = mem->num_stations; | ||
979 | mem_conf->rx_mem_block_num = mem->rx_block_num; | ||
980 | mem_conf->tx_min_mem_block_num = mem->tx_min_block_num; | ||
981 | mem_conf->num_ssid_profiles = mem->ssid_profiles; | ||
982 | mem_conf->total_tx_descriptors = cpu_to_le32(ACX_TX_DESCRIPTORS); | ||
983 | mem_conf->dyn_mem_enable = mem->dynamic_memory; | ||
984 | mem_conf->tx_free_req = mem->min_req_tx_blocks; | ||
985 | mem_conf->rx_free_req = mem->min_req_rx_blocks; | ||
986 | mem_conf->tx_min = mem->tx_min; | ||
987 | mem_conf->fwlog_blocks = wl->conf.fwlog.mem_blocks; | ||
988 | |||
989 | ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf, | ||
990 | sizeof(*mem_conf)); | ||
991 | if (ret < 0) { | ||
992 | wl1271_warning("wl1271 mem config failed: %d", ret); | ||
993 | goto out; | ||
994 | } | ||
995 | |||
996 | out: | ||
997 | kfree(mem_conf); | ||
998 | return ret; | ||
999 | } | ||
1000 | |||
1001 | int wl1271_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap) | ||
1002 | { | ||
1003 | struct wl1271_acx_host_config_bitmap *bitmap_conf; | ||
1004 | int ret; | ||
1005 | |||
1006 | bitmap_conf = kzalloc(sizeof(*bitmap_conf), GFP_KERNEL); | ||
1007 | if (!bitmap_conf) { | ||
1008 | ret = -ENOMEM; | ||
1009 | goto out; | ||
1010 | } | ||
1011 | |||
1012 | bitmap_conf->host_cfg_bitmap = cpu_to_le32(host_cfg_bitmap); | ||
1013 | |||
1014 | ret = wl1271_cmd_configure(wl, ACX_HOST_IF_CFG_BITMAP, | ||
1015 | bitmap_conf, sizeof(*bitmap_conf)); | ||
1016 | if (ret < 0) { | ||
1017 | wl1271_warning("wl1271 bitmap config opt failed: %d", ret); | ||
1018 | goto out; | ||
1019 | } | ||
1020 | |||
1021 | out: | ||
1022 | kfree(bitmap_conf); | ||
1023 | |||
1024 | return ret; | ||
1025 | } | ||
1026 | |||
1027 | int wl1271_acx_init_mem_config(struct wl1271 *wl) | ||
1028 | { | ||
1029 | int ret; | ||
1030 | |||
1031 | wl->target_mem_map = kzalloc(sizeof(struct wl1271_acx_mem_map), | ||
1032 | GFP_KERNEL); | ||
1033 | if (!wl->target_mem_map) { | ||
1034 | wl1271_error("couldn't allocate target memory map"); | ||
1035 | return -ENOMEM; | ||
1036 | } | ||
1037 | |||
1038 | /* we now ask for the firmware built memory map */ | ||
1039 | ret = wl1271_acx_mem_map(wl, (void *)wl->target_mem_map, | ||
1040 | sizeof(struct wl1271_acx_mem_map)); | ||
1041 | if (ret < 0) { | ||
1042 | wl1271_error("couldn't retrieve firmware memory map"); | ||
1043 | kfree(wl->target_mem_map); | ||
1044 | wl->target_mem_map = NULL; | ||
1045 | return ret; | ||
1046 | } | ||
1047 | |||
1048 | /* initialize TX block book keeping */ | ||
1049 | wl->tx_blocks_available = | ||
1050 | le32_to_cpu(wl->target_mem_map->num_tx_mem_blocks); | ||
1051 | wl1271_debug(DEBUG_TX, "available tx blocks: %d", | ||
1052 | wl->tx_blocks_available); | ||
1053 | |||
1054 | return 0; | ||
1055 | } | ||
1056 | |||
1057 | int wl1271_acx_init_rx_interrupt(struct wl1271 *wl) | ||
1058 | { | ||
1059 | struct wl1271_acx_rx_config_opt *rx_conf; | ||
1060 | int ret; | ||
1061 | |||
1062 | wl1271_debug(DEBUG_ACX, "wl1271 rx interrupt config"); | ||
1063 | |||
1064 | rx_conf = kzalloc(sizeof(*rx_conf), GFP_KERNEL); | ||
1065 | if (!rx_conf) { | ||
1066 | ret = -ENOMEM; | ||
1067 | goto out; | ||
1068 | } | ||
1069 | |||
1070 | rx_conf->threshold = cpu_to_le16(wl->conf.rx.irq_pkt_threshold); | ||
1071 | rx_conf->timeout = cpu_to_le16(wl->conf.rx.irq_timeout); | ||
1072 | rx_conf->mblk_threshold = cpu_to_le16(wl->conf.rx.irq_blk_threshold); | ||
1073 | rx_conf->queue_type = wl->conf.rx.queue_type; | ||
1074 | |||
1075 | ret = wl1271_cmd_configure(wl, ACX_RX_CONFIG_OPT, rx_conf, | ||
1076 | sizeof(*rx_conf)); | ||
1077 | if (ret < 0) { | ||
1078 | wl1271_warning("wl1271 rx config opt failed: %d", ret); | ||
1079 | goto out; | ||
1080 | } | ||
1081 | |||
1082 | out: | ||
1083 | kfree(rx_conf); | ||
1084 | return ret; | ||
1085 | } | ||
1086 | |||
1087 | int wl1271_acx_bet_enable(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
1088 | bool enable) | ||
1089 | { | ||
1090 | struct wl1271_acx_bet_enable *acx = NULL; | ||
1091 | int ret = 0; | ||
1092 | |||
1093 | wl1271_debug(DEBUG_ACX, "acx bet enable"); | ||
1094 | |||
1095 | if (enable && wl->conf.conn.bet_enable == CONF_BET_MODE_DISABLE) | ||
1096 | goto out; | ||
1097 | |||
1098 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
1099 | if (!acx) { | ||
1100 | ret = -ENOMEM; | ||
1101 | goto out; | ||
1102 | } | ||
1103 | |||
1104 | acx->role_id = wlvif->role_id; | ||
1105 | acx->enable = enable ? CONF_BET_MODE_ENABLE : CONF_BET_MODE_DISABLE; | ||
1106 | acx->max_consecutive = wl->conf.conn.bet_max_consecutive; | ||
1107 | |||
1108 | ret = wl1271_cmd_configure(wl, ACX_BET_ENABLE, acx, sizeof(*acx)); | ||
1109 | if (ret < 0) { | ||
1110 | wl1271_warning("acx bet enable failed: %d", ret); | ||
1111 | goto out; | ||
1112 | } | ||
1113 | |||
1114 | out: | ||
1115 | kfree(acx); | ||
1116 | return ret; | ||
1117 | } | ||
1118 | |||
1119 | int wl1271_acx_arp_ip_filter(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
1120 | u8 enable, __be32 address) | ||
1121 | { | ||
1122 | struct wl1271_acx_arp_filter *acx; | ||
1123 | int ret; | ||
1124 | |||
1125 | wl1271_debug(DEBUG_ACX, "acx arp ip filter, enable: %d", enable); | ||
1126 | |||
1127 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
1128 | if (!acx) { | ||
1129 | ret = -ENOMEM; | ||
1130 | goto out; | ||
1131 | } | ||
1132 | |||
1133 | acx->role_id = wlvif->role_id; | ||
1134 | acx->version = ACX_IPV4_VERSION; | ||
1135 | acx->enable = enable; | ||
1136 | |||
1137 | if (enable) | ||
1138 | memcpy(acx->address, &address, ACX_IPV4_ADDR_SIZE); | ||
1139 | |||
1140 | ret = wl1271_cmd_configure(wl, ACX_ARP_IP_FILTER, | ||
1141 | acx, sizeof(*acx)); | ||
1142 | if (ret < 0) { | ||
1143 | wl1271_warning("failed to set arp ip filter: %d", ret); | ||
1144 | goto out; | ||
1145 | } | ||
1146 | |||
1147 | out: | ||
1148 | kfree(acx); | ||
1149 | return ret; | ||
1150 | } | ||
1151 | |||
1152 | int wl1271_acx_pm_config(struct wl1271 *wl) | ||
1153 | { | ||
1154 | struct wl1271_acx_pm_config *acx = NULL; | ||
1155 | struct conf_pm_config_settings *c = &wl->conf.pm_config; | ||
1156 | int ret = 0; | ||
1157 | |||
1158 | wl1271_debug(DEBUG_ACX, "acx pm config"); | ||
1159 | |||
1160 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
1161 | if (!acx) { | ||
1162 | ret = -ENOMEM; | ||
1163 | goto out; | ||
1164 | } | ||
1165 | |||
1166 | acx->host_clk_settling_time = cpu_to_le32(c->host_clk_settling_time); | ||
1167 | acx->host_fast_wakeup_support = c->host_fast_wakeup_support; | ||
1168 | |||
1169 | ret = wl1271_cmd_configure(wl, ACX_PM_CONFIG, acx, sizeof(*acx)); | ||
1170 | if (ret < 0) { | ||
1171 | wl1271_warning("acx pm config failed: %d", ret); | ||
1172 | goto out; | ||
1173 | } | ||
1174 | |||
1175 | out: | ||
1176 | kfree(acx); | ||
1177 | return ret; | ||
1178 | } | ||
1179 | |||
1180 | int wl1271_acx_keep_alive_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
1181 | bool enable) | ||
1182 | { | ||
1183 | struct wl1271_acx_keep_alive_mode *acx = NULL; | ||
1184 | int ret = 0; | ||
1185 | |||
1186 | wl1271_debug(DEBUG_ACX, "acx keep alive mode: %d", enable); | ||
1187 | |||
1188 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
1189 | if (!acx) { | ||
1190 | ret = -ENOMEM; | ||
1191 | goto out; | ||
1192 | } | ||
1193 | |||
1194 | acx->role_id = wlvif->role_id; | ||
1195 | acx->enabled = enable; | ||
1196 | |||
1197 | ret = wl1271_cmd_configure(wl, ACX_KEEP_ALIVE_MODE, acx, sizeof(*acx)); | ||
1198 | if (ret < 0) { | ||
1199 | wl1271_warning("acx keep alive mode failed: %d", ret); | ||
1200 | goto out; | ||
1201 | } | ||
1202 | |||
1203 | out: | ||
1204 | kfree(acx); | ||
1205 | return ret; | ||
1206 | } | ||
1207 | |||
1208 | int wl1271_acx_keep_alive_config(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
1209 | u8 index, u8 tpl_valid) | ||
1210 | { | ||
1211 | struct wl1271_acx_keep_alive_config *acx = NULL; | ||
1212 | int ret = 0; | ||
1213 | |||
1214 | wl1271_debug(DEBUG_ACX, "acx keep alive config"); | ||
1215 | |||
1216 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
1217 | if (!acx) { | ||
1218 | ret = -ENOMEM; | ||
1219 | goto out; | ||
1220 | } | ||
1221 | |||
1222 | acx->role_id = wlvif->role_id; | ||
1223 | acx->period = cpu_to_le32(wl->conf.conn.keep_alive_interval); | ||
1224 | acx->index = index; | ||
1225 | acx->tpl_validation = tpl_valid; | ||
1226 | acx->trigger = ACX_KEEP_ALIVE_NO_TX; | ||
1227 | |||
1228 | ret = wl1271_cmd_configure(wl, ACX_SET_KEEP_ALIVE_CONFIG, | ||
1229 | acx, sizeof(*acx)); | ||
1230 | if (ret < 0) { | ||
1231 | wl1271_warning("acx keep alive config failed: %d", ret); | ||
1232 | goto out; | ||
1233 | } | ||
1234 | |||
1235 | out: | ||
1236 | kfree(acx); | ||
1237 | return ret; | ||
1238 | } | ||
1239 | |||
1240 | int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
1241 | bool enable, s16 thold, u8 hyst) | ||
1242 | { | ||
1243 | struct wl1271_acx_rssi_snr_trigger *acx = NULL; | ||
1244 | int ret = 0; | ||
1245 | |||
1246 | wl1271_debug(DEBUG_ACX, "acx rssi snr trigger"); | ||
1247 | |||
1248 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
1249 | if (!acx) { | ||
1250 | ret = -ENOMEM; | ||
1251 | goto out; | ||
1252 | } | ||
1253 | |||
1254 | wlvif->last_rssi_event = -1; | ||
1255 | |||
1256 | acx->role_id = wlvif->role_id; | ||
1257 | acx->pacing = cpu_to_le16(wl->conf.roam_trigger.trigger_pacing); | ||
1258 | acx->metric = WL1271_ACX_TRIG_METRIC_RSSI_BEACON; | ||
1259 | acx->type = WL1271_ACX_TRIG_TYPE_EDGE; | ||
1260 | if (enable) | ||
1261 | acx->enable = WL1271_ACX_TRIG_ENABLE; | ||
1262 | else | ||
1263 | acx->enable = WL1271_ACX_TRIG_DISABLE; | ||
1264 | |||
1265 | acx->index = WL1271_ACX_TRIG_IDX_RSSI; | ||
1266 | acx->dir = WL1271_ACX_TRIG_DIR_BIDIR; | ||
1267 | acx->threshold = cpu_to_le16(thold); | ||
1268 | acx->hysteresis = hyst; | ||
1269 | |||
1270 | ret = wl1271_cmd_configure(wl, ACX_RSSI_SNR_TRIGGER, acx, sizeof(*acx)); | ||
1271 | if (ret < 0) { | ||
1272 | wl1271_warning("acx rssi snr trigger setting failed: %d", ret); | ||
1273 | goto out; | ||
1274 | } | ||
1275 | |||
1276 | out: | ||
1277 | kfree(acx); | ||
1278 | return ret; | ||
1279 | } | ||
1280 | |||
1281 | int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl, | ||
1282 | struct wl12xx_vif *wlvif) | ||
1283 | { | ||
1284 | struct wl1271_acx_rssi_snr_avg_weights *acx = NULL; | ||
1285 | struct conf_roam_trigger_settings *c = &wl->conf.roam_trigger; | ||
1286 | int ret = 0; | ||
1287 | |||
1288 | wl1271_debug(DEBUG_ACX, "acx rssi snr avg weights"); | ||
1289 | |||
1290 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
1291 | if (!acx) { | ||
1292 | ret = -ENOMEM; | ||
1293 | goto out; | ||
1294 | } | ||
1295 | |||
1296 | acx->role_id = wlvif->role_id; | ||
1297 | acx->rssi_beacon = c->avg_weight_rssi_beacon; | ||
1298 | acx->rssi_data = c->avg_weight_rssi_data; | ||
1299 | acx->snr_beacon = c->avg_weight_snr_beacon; | ||
1300 | acx->snr_data = c->avg_weight_snr_data; | ||
1301 | |||
1302 | ret = wl1271_cmd_configure(wl, ACX_RSSI_SNR_WEIGHTS, acx, sizeof(*acx)); | ||
1303 | if (ret < 0) { | ||
1304 | wl1271_warning("acx rssi snr trigger weights failed: %d", ret); | ||
1305 | goto out; | ||
1306 | } | ||
1307 | |||
1308 | out: | ||
1309 | kfree(acx); | ||
1310 | return ret; | ||
1311 | } | ||
1312 | |||
1313 | int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, | ||
1314 | struct ieee80211_sta_ht_cap *ht_cap, | ||
1315 | bool allow_ht_operation, u8 hlid) | ||
1316 | { | ||
1317 | struct wl1271_acx_ht_capabilities *acx; | ||
1318 | int ret = 0; | ||
1319 | u32 ht_capabilites = 0; | ||
1320 | |||
1321 | wl1271_debug(DEBUG_ACX, "acx ht capabilities setting " | ||
1322 | "sta supp: %d sta cap: %d", ht_cap->ht_supported, | ||
1323 | ht_cap->cap); | ||
1324 | |||
1325 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
1326 | if (!acx) { | ||
1327 | ret = -ENOMEM; | ||
1328 | goto out; | ||
1329 | } | ||
1330 | |||
1331 | if (allow_ht_operation && ht_cap->ht_supported) { | ||
1332 | /* no need to translate capabilities - use the spec values */ | ||
1333 | ht_capabilites = ht_cap->cap; | ||
1334 | |||
1335 | /* | ||
1336 | * this bit is not employed by the spec but only by FW to | ||
1337 | * indicate peer HT support | ||
1338 | */ | ||
1339 | ht_capabilites |= WL12XX_HT_CAP_HT_OPERATION; | ||
1340 | |||
1341 | /* get data from A-MPDU parameters field */ | ||
1342 | acx->ampdu_max_length = ht_cap->ampdu_factor; | ||
1343 | acx->ampdu_min_spacing = ht_cap->ampdu_density; | ||
1344 | } | ||
1345 | |||
1346 | acx->hlid = hlid; | ||
1347 | acx->ht_capabilites = cpu_to_le32(ht_capabilites); | ||
1348 | |||
1349 | ret = wl1271_cmd_configure(wl, ACX_PEER_HT_CAP, acx, sizeof(*acx)); | ||
1350 | if (ret < 0) { | ||
1351 | wl1271_warning("acx ht capabilities setting failed: %d", ret); | ||
1352 | goto out; | ||
1353 | } | ||
1354 | |||
1355 | out: | ||
1356 | kfree(acx); | ||
1357 | return ret; | ||
1358 | } | ||
1359 | |||
1360 | int wl1271_acx_set_ht_information(struct wl1271 *wl, | ||
1361 | struct wl12xx_vif *wlvif, | ||
1362 | u16 ht_operation_mode) | ||
1363 | { | ||
1364 | struct wl1271_acx_ht_information *acx; | ||
1365 | int ret = 0; | ||
1366 | |||
1367 | wl1271_debug(DEBUG_ACX, "acx ht information setting"); | ||
1368 | |||
1369 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
1370 | if (!acx) { | ||
1371 | ret = -ENOMEM; | ||
1372 | goto out; | ||
1373 | } | ||
1374 | |||
1375 | acx->role_id = wlvif->role_id; | ||
1376 | acx->ht_protection = | ||
1377 | (u8)(ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION); | ||
1378 | acx->rifs_mode = 0; | ||
1379 | acx->gf_protection = | ||
1380 | !!(ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); | ||
1381 | acx->ht_tx_burst_limit = 0; | ||
1382 | acx->dual_cts_protection = 0; | ||
1383 | |||
1384 | ret = wl1271_cmd_configure(wl, ACX_HT_BSS_OPERATION, acx, sizeof(*acx)); | ||
1385 | |||
1386 | if (ret < 0) { | ||
1387 | wl1271_warning("acx ht information setting failed: %d", ret); | ||
1388 | goto out; | ||
1389 | } | ||
1390 | |||
1391 | out: | ||
1392 | kfree(acx); | ||
1393 | return ret; | ||
1394 | } | ||
1395 | |||
1396 | /* Configure BA session initiator/receiver parameters setting in the FW. */ | ||
1397 | int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl, | ||
1398 | struct wl12xx_vif *wlvif) | ||
1399 | { | ||
1400 | struct wl1271_acx_ba_initiator_policy *acx; | ||
1401 | int ret; | ||
1402 | |||
1403 | wl1271_debug(DEBUG_ACX, "acx ba initiator policy"); | ||
1404 | |||
1405 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
1406 | if (!acx) { | ||
1407 | ret = -ENOMEM; | ||
1408 | goto out; | ||
1409 | } | ||
1410 | |||
1411 | /* set for the current role */ | ||
1412 | acx->role_id = wlvif->role_id; | ||
1413 | acx->tid_bitmap = wl->conf.ht.tx_ba_tid_bitmap; | ||
1414 | acx->win_size = wl->conf.ht.tx_ba_win_size; | ||
1415 | acx->inactivity_timeout = wl->conf.ht.inactivity_timeout; | ||
1416 | |||
1417 | ret = wl1271_cmd_configure(wl, | ||
1418 | ACX_BA_SESSION_INIT_POLICY, | ||
1419 | acx, | ||
1420 | sizeof(*acx)); | ||
1421 | if (ret < 0) { | ||
1422 | wl1271_warning("acx ba initiator policy failed: %d", ret); | ||
1423 | goto out; | ||
1424 | } | ||
1425 | |||
1426 | out: | ||
1427 | kfree(acx); | ||
1428 | return ret; | ||
1429 | } | ||
1430 | |||
1431 | /* setup BA session receiver setting in the FW. */ | ||
1432 | int wl12xx_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, | ||
1433 | u16 ssn, bool enable, u8 peer_hlid) | ||
1434 | { | ||
1435 | struct wl1271_acx_ba_receiver_setup *acx; | ||
1436 | int ret; | ||
1437 | |||
1438 | wl1271_debug(DEBUG_ACX, "acx ba receiver session setting"); | ||
1439 | |||
1440 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
1441 | if (!acx) { | ||
1442 | ret = -ENOMEM; | ||
1443 | goto out; | ||
1444 | } | ||
1445 | |||
1446 | acx->hlid = peer_hlid; | ||
1447 | acx->tid = tid_index; | ||
1448 | acx->enable = enable; | ||
1449 | acx->win_size = wl->conf.ht.rx_ba_win_size; | ||
1450 | acx->ssn = ssn; | ||
1451 | |||
1452 | ret = wl1271_cmd_configure(wl, ACX_BA_SESSION_RX_SETUP, acx, | ||
1453 | sizeof(*acx)); | ||
1454 | if (ret < 0) { | ||
1455 | wl1271_warning("acx ba receiver session failed: %d", ret); | ||
1456 | goto out; | ||
1457 | } | ||
1458 | |||
1459 | out: | ||
1460 | kfree(acx); | ||
1461 | return ret; | ||
1462 | } | ||
1463 | |||
1464 | int wl12xx_acx_tsf_info(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
1465 | u64 *mactime) | ||
1466 | { | ||
1467 | struct wl12xx_acx_fw_tsf_information *tsf_info; | ||
1468 | int ret; | ||
1469 | |||
1470 | tsf_info = kzalloc(sizeof(*tsf_info), GFP_KERNEL); | ||
1471 | if (!tsf_info) { | ||
1472 | ret = -ENOMEM; | ||
1473 | goto out; | ||
1474 | } | ||
1475 | |||
1476 | tsf_info->role_id = wlvif->role_id; | ||
1477 | |||
1478 | ret = wl1271_cmd_interrogate(wl, ACX_TSF_INFO, | ||
1479 | tsf_info, sizeof(*tsf_info)); | ||
1480 | if (ret < 0) { | ||
1481 | wl1271_warning("acx tsf info interrogate failed"); | ||
1482 | goto out; | ||
1483 | } | ||
1484 | |||
1485 | *mactime = le32_to_cpu(tsf_info->current_tsf_low) | | ||
1486 | ((u64) le32_to_cpu(tsf_info->current_tsf_high) << 32); | ||
1487 | |||
1488 | out: | ||
1489 | kfree(tsf_info); | ||
1490 | return ret; | ||
1491 | } | ||
1492 | |||
1493 | int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
1494 | bool enable) | ||
1495 | { | ||
1496 | struct wl1271_acx_ps_rx_streaming *rx_streaming; | ||
1497 | u32 conf_queues, enable_queues; | ||
1498 | int i, ret = 0; | ||
1499 | |||
1500 | wl1271_debug(DEBUG_ACX, "acx ps rx streaming"); | ||
1501 | |||
1502 | rx_streaming = kzalloc(sizeof(*rx_streaming), GFP_KERNEL); | ||
1503 | if (!rx_streaming) { | ||
1504 | ret = -ENOMEM; | ||
1505 | goto out; | ||
1506 | } | ||
1507 | |||
1508 | conf_queues = wl->conf.rx_streaming.queues; | ||
1509 | if (enable) | ||
1510 | enable_queues = conf_queues; | ||
1511 | else | ||
1512 | enable_queues = 0; | ||
1513 | |||
1514 | for (i = 0; i < 8; i++) { | ||
1515 | /* | ||
1516 | * Skip non-changed queues, to avoid redundant acxs. | ||
1517 | * this check assumes conf.rx_streaming.queues can't | ||
1518 | * be changed while rx_streaming is enabled. | ||
1519 | */ | ||
1520 | if (!(conf_queues & BIT(i))) | ||
1521 | continue; | ||
1522 | |||
1523 | rx_streaming->role_id = wlvif->role_id; | ||
1524 | rx_streaming->tid = i; | ||
1525 | rx_streaming->enable = enable_queues & BIT(i); | ||
1526 | rx_streaming->period = wl->conf.rx_streaming.interval; | ||
1527 | rx_streaming->timeout = wl->conf.rx_streaming.interval; | ||
1528 | |||
1529 | ret = wl1271_cmd_configure(wl, ACX_PS_RX_STREAMING, | ||
1530 | rx_streaming, | ||
1531 | sizeof(*rx_streaming)); | ||
1532 | if (ret < 0) { | ||
1533 | wl1271_warning("acx ps rx streaming failed: %d", ret); | ||
1534 | goto out; | ||
1535 | } | ||
1536 | } | ||
1537 | out: | ||
1538 | kfree(rx_streaming); | ||
1539 | return ret; | ||
1540 | } | ||
1541 | |||
1542 | int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl, struct wl12xx_vif *wlvif) | ||
1543 | { | ||
1544 | struct wl1271_acx_ap_max_tx_retry *acx = NULL; | ||
1545 | int ret; | ||
1546 | |||
1547 | wl1271_debug(DEBUG_ACX, "acx ap max tx retry"); | ||
1548 | |||
1549 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
1550 | if (!acx) | ||
1551 | return -ENOMEM; | ||
1552 | |||
1553 | acx->role_id = wlvif->role_id; | ||
1554 | acx->max_tx_retry = cpu_to_le16(wl->conf.tx.max_tx_retries); | ||
1555 | |||
1556 | ret = wl1271_cmd_configure(wl, ACX_MAX_TX_FAILURE, acx, sizeof(*acx)); | ||
1557 | if (ret < 0) { | ||
1558 | wl1271_warning("acx ap max tx retry failed: %d", ret); | ||
1559 | goto out; | ||
1560 | } | ||
1561 | |||
1562 | out: | ||
1563 | kfree(acx); | ||
1564 | return ret; | ||
1565 | } | ||
1566 | |||
1567 | int wl12xx_acx_config_ps(struct wl1271 *wl, struct wl12xx_vif *wlvif) | ||
1568 | { | ||
1569 | struct wl1271_acx_config_ps *config_ps; | ||
1570 | int ret; | ||
1571 | |||
1572 | wl1271_debug(DEBUG_ACX, "acx config ps"); | ||
1573 | |||
1574 | config_ps = kzalloc(sizeof(*config_ps), GFP_KERNEL); | ||
1575 | if (!config_ps) { | ||
1576 | ret = -ENOMEM; | ||
1577 | goto out; | ||
1578 | } | ||
1579 | |||
1580 | config_ps->exit_retries = wl->conf.conn.psm_exit_retries; | ||
1581 | config_ps->enter_retries = wl->conf.conn.psm_entry_retries; | ||
1582 | config_ps->null_data_rate = cpu_to_le32(wlvif->basic_rate); | ||
1583 | |||
1584 | ret = wl1271_cmd_configure(wl, ACX_CONFIG_PS, config_ps, | ||
1585 | sizeof(*config_ps)); | ||
1586 | |||
1587 | if (ret < 0) { | ||
1588 | wl1271_warning("acx config ps failed: %d", ret); | ||
1589 | goto out; | ||
1590 | } | ||
1591 | |||
1592 | out: | ||
1593 | kfree(config_ps); | ||
1594 | return ret; | ||
1595 | } | ||
1596 | |||
1597 | int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr) | ||
1598 | { | ||
1599 | struct wl1271_acx_inconnection_sta *acx = NULL; | ||
1600 | int ret; | ||
1601 | |||
1602 | wl1271_debug(DEBUG_ACX, "acx set inconnaction sta %pM", addr); | ||
1603 | |||
1604 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
1605 | if (!acx) | ||
1606 | return -ENOMEM; | ||
1607 | |||
1608 | memcpy(acx->addr, addr, ETH_ALEN); | ||
1609 | |||
1610 | ret = wl1271_cmd_configure(wl, ACX_UPDATE_INCONNECTION_STA_LIST, | ||
1611 | acx, sizeof(*acx)); | ||
1612 | if (ret < 0) { | ||
1613 | wl1271_warning("acx set inconnaction sta failed: %d", ret); | ||
1614 | goto out; | ||
1615 | } | ||
1616 | |||
1617 | out: | ||
1618 | kfree(acx); | ||
1619 | return ret; | ||
1620 | } | ||
1621 | |||
1622 | int wl1271_acx_fm_coex(struct wl1271 *wl) | ||
1623 | { | ||
1624 | struct wl1271_acx_fm_coex *acx; | ||
1625 | int ret; | ||
1626 | |||
1627 | wl1271_debug(DEBUG_ACX, "acx fm coex setting"); | ||
1628 | |||
1629 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
1630 | if (!acx) { | ||
1631 | ret = -ENOMEM; | ||
1632 | goto out; | ||
1633 | } | ||
1634 | |||
1635 | acx->enable = wl->conf.fm_coex.enable; | ||
1636 | acx->swallow_period = wl->conf.fm_coex.swallow_period; | ||
1637 | acx->n_divider_fref_set_1 = wl->conf.fm_coex.n_divider_fref_set_1; | ||
1638 | acx->n_divider_fref_set_2 = wl->conf.fm_coex.n_divider_fref_set_2; | ||
1639 | acx->m_divider_fref_set_1 = | ||
1640 | cpu_to_le16(wl->conf.fm_coex.m_divider_fref_set_1); | ||
1641 | acx->m_divider_fref_set_2 = | ||
1642 | cpu_to_le16(wl->conf.fm_coex.m_divider_fref_set_2); | ||
1643 | acx->coex_pll_stabilization_time = | ||
1644 | cpu_to_le32(wl->conf.fm_coex.coex_pll_stabilization_time); | ||
1645 | acx->ldo_stabilization_time = | ||
1646 | cpu_to_le16(wl->conf.fm_coex.ldo_stabilization_time); | ||
1647 | acx->fm_disturbed_band_margin = | ||
1648 | wl->conf.fm_coex.fm_disturbed_band_margin; | ||
1649 | acx->swallow_clk_diff = wl->conf.fm_coex.swallow_clk_diff; | ||
1650 | |||
1651 | ret = wl1271_cmd_configure(wl, ACX_FM_COEX_CFG, acx, sizeof(*acx)); | ||
1652 | if (ret < 0) { | ||
1653 | wl1271_warning("acx fm coex setting failed: %d", ret); | ||
1654 | goto out; | ||
1655 | } | ||
1656 | |||
1657 | out: | ||
1658 | kfree(acx); | ||
1659 | return ret; | ||
1660 | } | ||
1661 | |||
1662 | int wl12xx_acx_set_rate_mgmt_params(struct wl1271 *wl) | ||
1663 | { | ||
1664 | struct wl12xx_acx_set_rate_mgmt_params *acx = NULL; | ||
1665 | struct conf_rate_policy_settings *conf = &wl->conf.rate; | ||
1666 | int ret; | ||
1667 | |||
1668 | wl1271_debug(DEBUG_ACX, "acx set rate mgmt params"); | ||
1669 | |||
1670 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
1671 | if (!acx) | ||
1672 | return -ENOMEM; | ||
1673 | |||
1674 | acx->index = ACX_RATE_MGMT_ALL_PARAMS; | ||
1675 | acx->rate_retry_score = cpu_to_le16(conf->rate_retry_score); | ||
1676 | acx->per_add = cpu_to_le16(conf->per_add); | ||
1677 | acx->per_th1 = cpu_to_le16(conf->per_th1); | ||
1678 | acx->per_th2 = cpu_to_le16(conf->per_th2); | ||
1679 | acx->max_per = cpu_to_le16(conf->max_per); | ||
1680 | acx->inverse_curiosity_factor = conf->inverse_curiosity_factor; | ||
1681 | acx->tx_fail_low_th = conf->tx_fail_low_th; | ||
1682 | acx->tx_fail_high_th = conf->tx_fail_high_th; | ||
1683 | acx->per_alpha_shift = conf->per_alpha_shift; | ||
1684 | acx->per_add_shift = conf->per_add_shift; | ||
1685 | acx->per_beta1_shift = conf->per_beta1_shift; | ||
1686 | acx->per_beta2_shift = conf->per_beta2_shift; | ||
1687 | acx->rate_check_up = conf->rate_check_up; | ||
1688 | acx->rate_check_down = conf->rate_check_down; | ||
1689 | memcpy(acx->rate_retry_policy, conf->rate_retry_policy, | ||
1690 | sizeof(acx->rate_retry_policy)); | ||
1691 | |||
1692 | ret = wl1271_cmd_configure(wl, ACX_SET_RATE_MGMT_PARAMS, | ||
1693 | acx, sizeof(*acx)); | ||
1694 | if (ret < 0) { | ||
1695 | wl1271_warning("acx set rate mgmt params failed: %d", ret); | ||
1696 | goto out; | ||
1697 | } | ||
1698 | |||
1699 | out: | ||
1700 | kfree(acx); | ||
1701 | return ret; | ||
1702 | } | ||
1703 | |||
1704 | int wl12xx_acx_config_hangover(struct wl1271 *wl) | ||
1705 | { | ||
1706 | struct wl12xx_acx_config_hangover *acx; | ||
1707 | struct conf_hangover_settings *conf = &wl->conf.hangover; | ||
1708 | int ret; | ||
1709 | |||
1710 | wl1271_debug(DEBUG_ACX, "acx config hangover"); | ||
1711 | |||
1712 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
1713 | if (!acx) { | ||
1714 | ret = -ENOMEM; | ||
1715 | goto out; | ||
1716 | } | ||
1717 | |||
1718 | acx->recover_time = cpu_to_le32(conf->recover_time); | ||
1719 | acx->hangover_period = conf->hangover_period; | ||
1720 | acx->dynamic_mode = conf->dynamic_mode; | ||
1721 | acx->early_termination_mode = conf->early_termination_mode; | ||
1722 | acx->max_period = conf->max_period; | ||
1723 | acx->min_period = conf->min_period; | ||
1724 | acx->increase_delta = conf->increase_delta; | ||
1725 | acx->decrease_delta = conf->decrease_delta; | ||
1726 | acx->quiet_time = conf->quiet_time; | ||
1727 | acx->increase_time = conf->increase_time; | ||
1728 | acx->window_size = acx->window_size; | ||
1729 | |||
1730 | ret = wl1271_cmd_configure(wl, ACX_CONFIG_HANGOVER, acx, | ||
1731 | sizeof(*acx)); | ||
1732 | |||
1733 | if (ret < 0) { | ||
1734 | wl1271_warning("acx config hangover failed: %d", ret); | ||
1735 | goto out; | ||
1736 | } | ||
1737 | |||
1738 | out: | ||
1739 | kfree(acx); | ||
1740 | return ret; | ||
1741 | |||
1742 | } | ||
diff --git a/drivers/net/wireless/ti/wl12xx/acx.h b/drivers/net/wireless/ti/wl12xx/acx.h new file mode 100644 index 000000000000..a28fc044034c --- /dev/null +++ b/drivers/net/wireless/ti/wl12xx/acx.h | |||
@@ -0,0 +1,1314 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. | ||
5 | * Copyright (C) 2008-2010 Nokia Corporation | ||
6 | * | ||
7 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef __ACX_H__ | ||
26 | #define __ACX_H__ | ||
27 | |||
28 | #include "wl12xx.h" | ||
29 | #include "cmd.h" | ||
30 | |||
31 | /************************************************************************* | ||
32 | |||
33 | Host Interrupt Register (WiLink -> Host) | ||
34 | |||
35 | **************************************************************************/ | ||
36 | /* HW Initiated interrupt Watchdog timer expiration */ | ||
37 | #define WL1271_ACX_INTR_WATCHDOG BIT(0) | ||
38 | /* Init sequence is done (masked interrupt, detection through polling only ) */ | ||
39 | #define WL1271_ACX_INTR_INIT_COMPLETE BIT(1) | ||
40 | /* Event was entered to Event MBOX #A*/ | ||
41 | #define WL1271_ACX_INTR_EVENT_A BIT(2) | ||
42 | /* Event was entered to Event MBOX #B*/ | ||
43 | #define WL1271_ACX_INTR_EVENT_B BIT(3) | ||
44 | /* Command processing completion*/ | ||
45 | #define WL1271_ACX_INTR_CMD_COMPLETE BIT(4) | ||
46 | /* Signaling the host on HW wakeup */ | ||
47 | #define WL1271_ACX_INTR_HW_AVAILABLE BIT(5) | ||
48 | /* The MISC bit is used for aggregation of RX, TxComplete and TX rate update */ | ||
49 | #define WL1271_ACX_INTR_DATA BIT(6) | ||
50 | /* Trace message on MBOX #A */ | ||
51 | #define WL1271_ACX_INTR_TRACE_A BIT(7) | ||
52 | /* Trace message on MBOX #B */ | ||
53 | #define WL1271_ACX_INTR_TRACE_B BIT(8) | ||
54 | |||
55 | #define WL1271_ACX_INTR_ALL 0xFFFFFFFF | ||
56 | #define WL1271_ACX_ALL_EVENTS_VECTOR (WL1271_ACX_INTR_WATCHDOG | \ | ||
57 | WL1271_ACX_INTR_INIT_COMPLETE | \ | ||
58 | WL1271_ACX_INTR_EVENT_A | \ | ||
59 | WL1271_ACX_INTR_EVENT_B | \ | ||
60 | WL1271_ACX_INTR_CMD_COMPLETE | \ | ||
61 | WL1271_ACX_INTR_HW_AVAILABLE | \ | ||
62 | WL1271_ACX_INTR_DATA) | ||
63 | |||
64 | #define WL1271_INTR_MASK (WL1271_ACX_INTR_WATCHDOG | \ | ||
65 | WL1271_ACX_INTR_EVENT_A | \ | ||
66 | WL1271_ACX_INTR_EVENT_B | \ | ||
67 | WL1271_ACX_INTR_HW_AVAILABLE | \ | ||
68 | WL1271_ACX_INTR_DATA) | ||
69 | |||
70 | /* Target's information element */ | ||
71 | struct acx_header { | ||
72 | struct wl1271_cmd_header cmd; | ||
73 | |||
74 | /* acx (or information element) header */ | ||
75 | __le16 id; | ||
76 | |||
77 | /* payload length (not including headers */ | ||
78 | __le16 len; | ||
79 | } __packed; | ||
80 | |||
81 | struct acx_error_counter { | ||
82 | struct acx_header header; | ||
83 | |||
84 | /* The number of PLCP errors since the last time this */ | ||
85 | /* information element was interrogated. This field is */ | ||
86 | /* automatically cleared when it is interrogated.*/ | ||
87 | __le32 PLCP_error; | ||
88 | |||
89 | /* The number of FCS errors since the last time this */ | ||
90 | /* information element was interrogated. This field is */ | ||
91 | /* automatically cleared when it is interrogated.*/ | ||
92 | __le32 FCS_error; | ||
93 | |||
94 | /* The number of MPDUs without PLCP header errors received*/ | ||
95 | /* since the last time this information element was interrogated. */ | ||
96 | /* This field is automatically cleared when it is interrogated.*/ | ||
97 | __le32 valid_frame; | ||
98 | |||
99 | /* the number of missed sequence numbers in the squentially */ | ||
100 | /* values of frames seq numbers */ | ||
101 | __le32 seq_num_miss; | ||
102 | } __packed; | ||
103 | |||
104 | enum wl12xx_role { | ||
105 | WL1271_ROLE_STA = 0, | ||
106 | WL1271_ROLE_IBSS, | ||
107 | WL1271_ROLE_AP, | ||
108 | WL1271_ROLE_DEVICE, | ||
109 | WL1271_ROLE_P2P_CL, | ||
110 | WL1271_ROLE_P2P_GO, | ||
111 | |||
112 | WL12XX_INVALID_ROLE_TYPE = 0xff | ||
113 | }; | ||
114 | |||
115 | enum wl1271_psm_mode { | ||
116 | /* Active mode */ | ||
117 | WL1271_PSM_CAM = 0, | ||
118 | |||
119 | /* Power save mode */ | ||
120 | WL1271_PSM_PS = 1, | ||
121 | |||
122 | /* Extreme low power */ | ||
123 | WL1271_PSM_ELP = 2, | ||
124 | }; | ||
125 | |||
126 | struct acx_sleep_auth { | ||
127 | struct acx_header header; | ||
128 | |||
129 | /* The sleep level authorization of the device. */ | ||
130 | /* 0 - Always active*/ | ||
131 | /* 1 - Power down mode: light / fast sleep*/ | ||
132 | /* 2 - ELP mode: Deep / Max sleep*/ | ||
133 | u8 sleep_auth; | ||
134 | u8 padding[3]; | ||
135 | } __packed; | ||
136 | |||
137 | enum { | ||
138 | HOSTIF_PCI_MASTER_HOST_INDIRECT, | ||
139 | HOSTIF_PCI_MASTER_HOST_DIRECT, | ||
140 | HOSTIF_SLAVE, | ||
141 | HOSTIF_PKT_RING, | ||
142 | HOSTIF_DONTCARE = 0xFF | ||
143 | }; | ||
144 | |||
145 | #define DEFAULT_UCAST_PRIORITY 0 | ||
146 | #define DEFAULT_RX_Q_PRIORITY 0 | ||
147 | #define DEFAULT_RXQ_PRIORITY 0 /* low 0 .. 15 high */ | ||
148 | #define DEFAULT_RXQ_TYPE 0x07 /* All frames, Data/Ctrl/Mgmt */ | ||
149 | #define TRACE_BUFFER_MAX_SIZE 256 | ||
150 | |||
151 | #define DP_RX_PACKET_RING_CHUNK_SIZE 1600 | ||
152 | #define DP_TX_PACKET_RING_CHUNK_SIZE 1600 | ||
153 | #define DP_RX_PACKET_RING_CHUNK_NUM 2 | ||
154 | #define DP_TX_PACKET_RING_CHUNK_NUM 2 | ||
155 | #define DP_TX_COMPLETE_TIME_OUT 20 | ||
156 | |||
157 | #define TX_MSDU_LIFETIME_MIN 0 | ||
158 | #define TX_MSDU_LIFETIME_MAX 3000 | ||
159 | #define TX_MSDU_LIFETIME_DEF 512 | ||
160 | #define RX_MSDU_LIFETIME_MIN 0 | ||
161 | #define RX_MSDU_LIFETIME_MAX 0xFFFFFFFF | ||
162 | #define RX_MSDU_LIFETIME_DEF 512000 | ||
163 | |||
164 | struct acx_rx_msdu_lifetime { | ||
165 | struct acx_header header; | ||
166 | |||
167 | /* | ||
168 | * The maximum amount of time, in TU, before the | ||
169 | * firmware discards the MSDU. | ||
170 | */ | ||
171 | __le32 lifetime; | ||
172 | } __packed; | ||
173 | |||
174 | enum acx_slot_type { | ||
175 | SLOT_TIME_LONG = 0, | ||
176 | SLOT_TIME_SHORT = 1, | ||
177 | DEFAULT_SLOT_TIME = SLOT_TIME_SHORT, | ||
178 | MAX_SLOT_TIMES = 0xFF | ||
179 | }; | ||
180 | |||
181 | #define STATION_WONE_INDEX 0 | ||
182 | |||
183 | struct acx_slot { | ||
184 | struct acx_header header; | ||
185 | |||
186 | u8 role_id; | ||
187 | u8 wone_index; /* Reserved */ | ||
188 | u8 slot_time; | ||
189 | u8 reserved[5]; | ||
190 | } __packed; | ||
191 | |||
192 | |||
193 | #define ACX_MC_ADDRESS_GROUP_MAX (8) | ||
194 | #define ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ACX_MC_ADDRESS_GROUP_MAX) | ||
195 | |||
196 | struct acx_dot11_grp_addr_tbl { | ||
197 | struct acx_header header; | ||
198 | |||
199 | u8 role_id; | ||
200 | u8 enabled; | ||
201 | u8 num_groups; | ||
202 | u8 pad[1]; | ||
203 | u8 mac_table[ADDRESS_GROUP_MAX_LEN]; | ||
204 | } __packed; | ||
205 | |||
206 | struct acx_rx_timeout { | ||
207 | struct acx_header header; | ||
208 | |||
209 | u8 role_id; | ||
210 | u8 reserved; | ||
211 | __le16 ps_poll_timeout; | ||
212 | __le16 upsd_timeout; | ||
213 | u8 padding[2]; | ||
214 | } __packed; | ||
215 | |||
216 | struct acx_rts_threshold { | ||
217 | struct acx_header header; | ||
218 | |||
219 | u8 role_id; | ||
220 | u8 reserved; | ||
221 | __le16 threshold; | ||
222 | } __packed; | ||
223 | |||
224 | struct acx_beacon_filter_option { | ||
225 | struct acx_header header; | ||
226 | |||
227 | u8 role_id; | ||
228 | u8 enable; | ||
229 | /* | ||
230 | * The number of beacons without the unicast TIM | ||
231 | * bit set that the firmware buffers before | ||
232 | * signaling the host about ready frames. | ||
233 | * When set to 0 and the filter is enabled, beacons | ||
234 | * without the unicast TIM bit set are dropped. | ||
235 | */ | ||
236 | u8 max_num_beacons; | ||
237 | u8 pad[1]; | ||
238 | } __packed; | ||
239 | |||
240 | /* | ||
241 | * ACXBeaconFilterEntry (not 221) | ||
242 | * Byte Offset Size (Bytes) Definition | ||
243 | * =========== ============ ========== | ||
244 | * 0 1 IE identifier | ||
245 | * 1 1 Treatment bit mask | ||
246 | * | ||
247 | * ACXBeaconFilterEntry (221) | ||
248 | * Byte Offset Size (Bytes) Definition | ||
249 | * =========== ============ ========== | ||
250 | * 0 1 IE identifier | ||
251 | * 1 1 Treatment bit mask | ||
252 | * 2 3 OUI | ||
253 | * 5 1 Type | ||
254 | * 6 2 Version | ||
255 | * | ||
256 | * | ||
257 | * Treatment bit mask - The information element handling: | ||
258 | * bit 0 - The information element is compared and transferred | ||
259 | * in case of change. | ||
260 | * bit 1 - The information element is transferred to the host | ||
261 | * with each appearance or disappearance. | ||
262 | * Note that both bits can be set at the same time. | ||
263 | */ | ||
264 | #define BEACON_FILTER_TABLE_MAX_IE_NUM (32) | ||
265 | #define BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM (6) | ||
266 | #define BEACON_FILTER_TABLE_IE_ENTRY_SIZE (2) | ||
267 | #define BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE (6) | ||
268 | #define BEACON_FILTER_TABLE_MAX_SIZE ((BEACON_FILTER_TABLE_MAX_IE_NUM * \ | ||
269 | BEACON_FILTER_TABLE_IE_ENTRY_SIZE) + \ | ||
270 | (BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM * \ | ||
271 | BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE)) | ||
272 | |||
273 | struct acx_beacon_filter_ie_table { | ||
274 | struct acx_header header; | ||
275 | |||
276 | u8 role_id; | ||
277 | u8 num_ie; | ||
278 | u8 pad[2]; | ||
279 | u8 table[BEACON_FILTER_TABLE_MAX_SIZE]; | ||
280 | } __packed; | ||
281 | |||
282 | struct acx_conn_monit_params { | ||
283 | struct acx_header header; | ||
284 | |||
285 | u8 role_id; | ||
286 | u8 padding[3]; | ||
287 | __le32 synch_fail_thold; /* number of beacons missed */ | ||
288 | __le32 bss_lose_timeout; /* number of TU's from synch fail */ | ||
289 | } __packed; | ||
290 | |||
291 | struct acx_bt_wlan_coex { | ||
292 | struct acx_header header; | ||
293 | |||
294 | u8 enable; | ||
295 | u8 pad[3]; | ||
296 | } __packed; | ||
297 | |||
298 | struct acx_bt_wlan_coex_param { | ||
299 | struct acx_header header; | ||
300 | |||
301 | __le32 params[CONF_SG_PARAMS_MAX]; | ||
302 | u8 param_idx; | ||
303 | u8 padding[3]; | ||
304 | } __packed; | ||
305 | |||
306 | struct acx_dco_itrim_params { | ||
307 | struct acx_header header; | ||
308 | |||
309 | u8 enable; | ||
310 | u8 padding[3]; | ||
311 | __le32 timeout; | ||
312 | } __packed; | ||
313 | |||
314 | struct acx_energy_detection { | ||
315 | struct acx_header header; | ||
316 | |||
317 | /* The RX Clear Channel Assessment threshold in the PHY */ | ||
318 | __le16 rx_cca_threshold; | ||
319 | u8 tx_energy_detection; | ||
320 | u8 pad; | ||
321 | } __packed; | ||
322 | |||
323 | struct acx_beacon_broadcast { | ||
324 | struct acx_header header; | ||
325 | |||
326 | u8 role_id; | ||
327 | /* Enables receiving of broadcast packets in PS mode */ | ||
328 | u8 rx_broadcast_in_ps; | ||
329 | |||
330 | __le16 beacon_rx_timeout; | ||
331 | __le16 broadcast_timeout; | ||
332 | |||
333 | /* Consecutive PS Poll failures before updating the host */ | ||
334 | u8 ps_poll_threshold; | ||
335 | u8 pad[1]; | ||
336 | } __packed; | ||
337 | |||
338 | struct acx_event_mask { | ||
339 | struct acx_header header; | ||
340 | |||
341 | __le32 event_mask; | ||
342 | __le32 high_event_mask; /* Unused */ | ||
343 | } __packed; | ||
344 | |||
345 | #define SCAN_PASSIVE BIT(0) | ||
346 | #define SCAN_5GHZ_BAND BIT(1) | ||
347 | #define SCAN_TRIGGERED BIT(2) | ||
348 | #define SCAN_PRIORITY_HIGH BIT(3) | ||
349 | |||
350 | /* When set, disable HW encryption */ | ||
351 | #define DF_ENCRYPTION_DISABLE 0x01 | ||
352 | #define DF_SNIFF_MODE_ENABLE 0x80 | ||
353 | |||
354 | struct acx_feature_config { | ||
355 | struct acx_header header; | ||
356 | |||
357 | u8 role_id; | ||
358 | u8 padding[3]; | ||
359 | __le32 options; | ||
360 | __le32 data_flow_options; | ||
361 | } __packed; | ||
362 | |||
363 | struct acx_current_tx_power { | ||
364 | struct acx_header header; | ||
365 | |||
366 | u8 role_id; | ||
367 | u8 current_tx_power; | ||
368 | u8 padding[2]; | ||
369 | } __packed; | ||
370 | |||
371 | struct acx_wake_up_condition { | ||
372 | struct acx_header header; | ||
373 | |||
374 | u8 role_id; | ||
375 | u8 wake_up_event; /* Only one bit can be set */ | ||
376 | u8 listen_interval; | ||
377 | u8 pad[1]; | ||
378 | } __packed; | ||
379 | |||
380 | struct acx_aid { | ||
381 | struct acx_header header; | ||
382 | |||
383 | /* | ||
384 | * To be set when associated with an AP. | ||
385 | */ | ||
386 | u8 role_id; | ||
387 | u8 reserved; | ||
388 | __le16 aid; | ||
389 | } __packed; | ||
390 | |||
391 | enum acx_preamble_type { | ||
392 | ACX_PREAMBLE_LONG = 0, | ||
393 | ACX_PREAMBLE_SHORT = 1 | ||
394 | }; | ||
395 | |||
396 | struct acx_preamble { | ||
397 | struct acx_header header; | ||
398 | |||
399 | /* | ||
400 | * When set, the WiLink transmits the frames with a short preamble and | ||
401 | * when cleared, the WiLink transmits the frames with a long preamble. | ||
402 | */ | ||
403 | u8 role_id; | ||
404 | u8 preamble; | ||
405 | u8 padding[2]; | ||
406 | } __packed; | ||
407 | |||
408 | enum acx_ctsprotect_type { | ||
409 | CTSPROTECT_DISABLE = 0, | ||
410 | CTSPROTECT_ENABLE = 1 | ||
411 | }; | ||
412 | |||
413 | struct acx_ctsprotect { | ||
414 | struct acx_header header; | ||
415 | u8 role_id; | ||
416 | u8 ctsprotect; | ||
417 | u8 padding[2]; | ||
418 | } __packed; | ||
419 | |||
420 | struct acx_tx_statistics { | ||
421 | __le32 internal_desc_overflow; | ||
422 | } __packed; | ||
423 | |||
424 | struct acx_rx_statistics { | ||
425 | __le32 out_of_mem; | ||
426 | __le32 hdr_overflow; | ||
427 | __le32 hw_stuck; | ||
428 | __le32 dropped; | ||
429 | __le32 fcs_err; | ||
430 | __le32 xfr_hint_trig; | ||
431 | __le32 path_reset; | ||
432 | __le32 reset_counter; | ||
433 | } __packed; | ||
434 | |||
435 | struct acx_dma_statistics { | ||
436 | __le32 rx_requested; | ||
437 | __le32 rx_errors; | ||
438 | __le32 tx_requested; | ||
439 | __le32 tx_errors; | ||
440 | } __packed; | ||
441 | |||
442 | struct acx_isr_statistics { | ||
443 | /* host command complete */ | ||
444 | __le32 cmd_cmplt; | ||
445 | |||
446 | /* fiqisr() */ | ||
447 | __le32 fiqs; | ||
448 | |||
449 | /* (INT_STS_ND & INT_TRIG_RX_HEADER) */ | ||
450 | __le32 rx_headers; | ||
451 | |||
452 | /* (INT_STS_ND & INT_TRIG_RX_CMPLT) */ | ||
453 | __le32 rx_completes; | ||
454 | |||
455 | /* (INT_STS_ND & INT_TRIG_NO_RX_BUF) */ | ||
456 | __le32 rx_mem_overflow; | ||
457 | |||
458 | /* (INT_STS_ND & INT_TRIG_S_RX_RDY) */ | ||
459 | __le32 rx_rdys; | ||
460 | |||
461 | /* irqisr() */ | ||
462 | __le32 irqs; | ||
463 | |||
464 | /* (INT_STS_ND & INT_TRIG_TX_PROC) */ | ||
465 | __le32 tx_procs; | ||
466 | |||
467 | /* (INT_STS_ND & INT_TRIG_DECRYPT_DONE) */ | ||
468 | __le32 decrypt_done; | ||
469 | |||
470 | /* (INT_STS_ND & INT_TRIG_DMA0) */ | ||
471 | __le32 dma0_done; | ||
472 | |||
473 | /* (INT_STS_ND & INT_TRIG_DMA1) */ | ||
474 | __le32 dma1_done; | ||
475 | |||
476 | /* (INT_STS_ND & INT_TRIG_TX_EXC_CMPLT) */ | ||
477 | __le32 tx_exch_complete; | ||
478 | |||
479 | /* (INT_STS_ND & INT_TRIG_COMMAND) */ | ||
480 | __le32 commands; | ||
481 | |||
482 | /* (INT_STS_ND & INT_TRIG_RX_PROC) */ | ||
483 | __le32 rx_procs; | ||
484 | |||
485 | /* (INT_STS_ND & INT_TRIG_PM_802) */ | ||
486 | __le32 hw_pm_mode_changes; | ||
487 | |||
488 | /* (INT_STS_ND & INT_TRIG_ACKNOWLEDGE) */ | ||
489 | __le32 host_acknowledges; | ||
490 | |||
491 | /* (INT_STS_ND & INT_TRIG_PM_PCI) */ | ||
492 | __le32 pci_pm; | ||
493 | |||
494 | /* (INT_STS_ND & INT_TRIG_ACM_WAKEUP) */ | ||
495 | __le32 wakeups; | ||
496 | |||
497 | /* (INT_STS_ND & INT_TRIG_LOW_RSSI) */ | ||
498 | __le32 low_rssi; | ||
499 | } __packed; | ||
500 | |||
501 | struct acx_wep_statistics { | ||
502 | /* WEP address keys configured */ | ||
503 | __le32 addr_key_count; | ||
504 | |||
505 | /* default keys configured */ | ||
506 | __le32 default_key_count; | ||
507 | |||
508 | __le32 reserved; | ||
509 | |||
510 | /* number of times that WEP key not found on lookup */ | ||
511 | __le32 key_not_found; | ||
512 | |||
513 | /* number of times that WEP key decryption failed */ | ||
514 | __le32 decrypt_fail; | ||
515 | |||
516 | /* WEP packets decrypted */ | ||
517 | __le32 packets; | ||
518 | |||
519 | /* WEP decrypt interrupts */ | ||
520 | __le32 interrupt; | ||
521 | } __packed; | ||
522 | |||
523 | #define ACX_MISSED_BEACONS_SPREAD 10 | ||
524 | |||
525 | struct acx_pwr_statistics { | ||
526 | /* the amount of enters into power save mode (both PD & ELP) */ | ||
527 | __le32 ps_enter; | ||
528 | |||
529 | /* the amount of enters into ELP mode */ | ||
530 | __le32 elp_enter; | ||
531 | |||
532 | /* the amount of missing beacon interrupts to the host */ | ||
533 | __le32 missing_bcns; | ||
534 | |||
535 | /* the amount of wake on host-access times */ | ||
536 | __le32 wake_on_host; | ||
537 | |||
538 | /* the amount of wake on timer-expire */ | ||
539 | __le32 wake_on_timer_exp; | ||
540 | |||
541 | /* the number of packets that were transmitted with PS bit set */ | ||
542 | __le32 tx_with_ps; | ||
543 | |||
544 | /* the number of packets that were transmitted with PS bit clear */ | ||
545 | __le32 tx_without_ps; | ||
546 | |||
547 | /* the number of received beacons */ | ||
548 | __le32 rcvd_beacons; | ||
549 | |||
550 | /* the number of entering into PowerOn (power save off) */ | ||
551 | __le32 power_save_off; | ||
552 | |||
553 | /* the number of entries into power save mode */ | ||
554 | __le16 enable_ps; | ||
555 | |||
556 | /* | ||
557 | * the number of exits from power save, not including failed PS | ||
558 | * transitions | ||
559 | */ | ||
560 | __le16 disable_ps; | ||
561 | |||
562 | /* | ||
563 | * the number of times the TSF counter was adjusted because | ||
564 | * of drift | ||
565 | */ | ||
566 | __le32 fix_tsf_ps; | ||
567 | |||
568 | /* Gives statistics about the spread continuous missed beacons. | ||
569 | * The 16 LSB are dedicated for the PS mode. | ||
570 | * The 16 MSB are dedicated for the PS mode. | ||
571 | * cont_miss_bcns_spread[0] - single missed beacon. | ||
572 | * cont_miss_bcns_spread[1] - two continuous missed beacons. | ||
573 | * cont_miss_bcns_spread[2] - three continuous missed beacons. | ||
574 | * ... | ||
575 | * cont_miss_bcns_spread[9] - ten and more continuous missed beacons. | ||
576 | */ | ||
577 | __le32 cont_miss_bcns_spread[ACX_MISSED_BEACONS_SPREAD]; | ||
578 | |||
579 | /* the number of beacons in awake mode */ | ||
580 | __le32 rcvd_awake_beacons; | ||
581 | } __packed; | ||
582 | |||
583 | struct acx_mic_statistics { | ||
584 | __le32 rx_pkts; | ||
585 | __le32 calc_failure; | ||
586 | } __packed; | ||
587 | |||
588 | struct acx_aes_statistics { | ||
589 | __le32 encrypt_fail; | ||
590 | __le32 decrypt_fail; | ||
591 | __le32 encrypt_packets; | ||
592 | __le32 decrypt_packets; | ||
593 | __le32 encrypt_interrupt; | ||
594 | __le32 decrypt_interrupt; | ||
595 | } __packed; | ||
596 | |||
597 | struct acx_event_statistics { | ||
598 | __le32 heart_beat; | ||
599 | __le32 calibration; | ||
600 | __le32 rx_mismatch; | ||
601 | __le32 rx_mem_empty; | ||
602 | __le32 rx_pool; | ||
603 | __le32 oom_late; | ||
604 | __le32 phy_transmit_error; | ||
605 | __le32 tx_stuck; | ||
606 | } __packed; | ||
607 | |||
608 | struct acx_ps_statistics { | ||
609 | __le32 pspoll_timeouts; | ||
610 | __le32 upsd_timeouts; | ||
611 | __le32 upsd_max_sptime; | ||
612 | __le32 upsd_max_apturn; | ||
613 | __le32 pspoll_max_apturn; | ||
614 | __le32 pspoll_utilization; | ||
615 | __le32 upsd_utilization; | ||
616 | } __packed; | ||
617 | |||
618 | struct acx_rxpipe_statistics { | ||
619 | __le32 rx_prep_beacon_drop; | ||
620 | __le32 descr_host_int_trig_rx_data; | ||
621 | __le32 beacon_buffer_thres_host_int_trig_rx_data; | ||
622 | __le32 missed_beacon_host_int_trig_rx_data; | ||
623 | __le32 tx_xfr_host_int_trig_rx_data; | ||
624 | } __packed; | ||
625 | |||
626 | struct acx_statistics { | ||
627 | struct acx_header header; | ||
628 | |||
629 | struct acx_tx_statistics tx; | ||
630 | struct acx_rx_statistics rx; | ||
631 | struct acx_dma_statistics dma; | ||
632 | struct acx_isr_statistics isr; | ||
633 | struct acx_wep_statistics wep; | ||
634 | struct acx_pwr_statistics pwr; | ||
635 | struct acx_aes_statistics aes; | ||
636 | struct acx_mic_statistics mic; | ||
637 | struct acx_event_statistics event; | ||
638 | struct acx_ps_statistics ps; | ||
639 | struct acx_rxpipe_statistics rxpipe; | ||
640 | } __packed; | ||
641 | |||
642 | struct acx_rate_class { | ||
643 | __le32 enabled_rates; | ||
644 | u8 short_retry_limit; | ||
645 | u8 long_retry_limit; | ||
646 | u8 aflags; | ||
647 | u8 reserved; | ||
648 | }; | ||
649 | |||
650 | struct acx_rate_policy { | ||
651 | struct acx_header header; | ||
652 | |||
653 | __le32 rate_policy_idx; | ||
654 | struct acx_rate_class rate_policy; | ||
655 | } __packed; | ||
656 | |||
657 | struct acx_ac_cfg { | ||
658 | struct acx_header header; | ||
659 | u8 role_id; | ||
660 | u8 ac; | ||
661 | u8 aifsn; | ||
662 | u8 cw_min; | ||
663 | __le16 cw_max; | ||
664 | __le16 tx_op_limit; | ||
665 | } __packed; | ||
666 | |||
667 | struct acx_tid_config { | ||
668 | struct acx_header header; | ||
669 | u8 role_id; | ||
670 | u8 queue_id; | ||
671 | u8 channel_type; | ||
672 | u8 tsid; | ||
673 | u8 ps_scheme; | ||
674 | u8 ack_policy; | ||
675 | u8 padding[2]; | ||
676 | __le32 apsd_conf[2]; | ||
677 | } __packed; | ||
678 | |||
679 | struct acx_frag_threshold { | ||
680 | struct acx_header header; | ||
681 | __le16 frag_threshold; | ||
682 | u8 padding[2]; | ||
683 | } __packed; | ||
684 | |||
685 | struct acx_tx_config_options { | ||
686 | struct acx_header header; | ||
687 | __le16 tx_compl_timeout; /* msec */ | ||
688 | __le16 tx_compl_threshold; /* number of packets */ | ||
689 | } __packed; | ||
690 | |||
691 | struct wl12xx_acx_config_memory { | ||
692 | struct acx_header header; | ||
693 | |||
694 | u8 rx_mem_block_num; | ||
695 | u8 tx_min_mem_block_num; | ||
696 | u8 num_stations; | ||
697 | u8 num_ssid_profiles; | ||
698 | __le32 total_tx_descriptors; | ||
699 | u8 dyn_mem_enable; | ||
700 | u8 tx_free_req; | ||
701 | u8 rx_free_req; | ||
702 | u8 tx_min; | ||
703 | u8 fwlog_blocks; | ||
704 | u8 padding[3]; | ||
705 | } __packed; | ||
706 | |||
707 | struct wl1271_acx_mem_map { | ||
708 | struct acx_header header; | ||
709 | |||
710 | __le32 code_start; | ||
711 | __le32 code_end; | ||
712 | |||
713 | __le32 wep_defkey_start; | ||
714 | __le32 wep_defkey_end; | ||
715 | |||
716 | __le32 sta_table_start; | ||
717 | __le32 sta_table_end; | ||
718 | |||
719 | __le32 packet_template_start; | ||
720 | __le32 packet_template_end; | ||
721 | |||
722 | /* Address of the TX result interface (control block) */ | ||
723 | __le32 tx_result; | ||
724 | __le32 tx_result_queue_start; | ||
725 | |||
726 | __le32 queue_memory_start; | ||
727 | __le32 queue_memory_end; | ||
728 | |||
729 | __le32 packet_memory_pool_start; | ||
730 | __le32 packet_memory_pool_end; | ||
731 | |||
732 | __le32 debug_buffer1_start; | ||
733 | __le32 debug_buffer1_end; | ||
734 | |||
735 | __le32 debug_buffer2_start; | ||
736 | __le32 debug_buffer2_end; | ||
737 | |||
738 | /* Number of blocks FW allocated for TX packets */ | ||
739 | __le32 num_tx_mem_blocks; | ||
740 | |||
741 | /* Number of blocks FW allocated for RX packets */ | ||
742 | __le32 num_rx_mem_blocks; | ||
743 | |||
744 | /* the following 4 fields are valid in SLAVE mode only */ | ||
745 | u8 *tx_cbuf; | ||
746 | u8 *rx_cbuf; | ||
747 | __le32 rx_ctrl; | ||
748 | __le32 tx_ctrl; | ||
749 | } __packed; | ||
750 | |||
751 | struct wl1271_acx_rx_config_opt { | ||
752 | struct acx_header header; | ||
753 | |||
754 | __le16 mblk_threshold; | ||
755 | __le16 threshold; | ||
756 | __le16 timeout; | ||
757 | u8 queue_type; | ||
758 | u8 reserved; | ||
759 | } __packed; | ||
760 | |||
761 | |||
762 | struct wl1271_acx_bet_enable { | ||
763 | struct acx_header header; | ||
764 | |||
765 | u8 role_id; | ||
766 | u8 enable; | ||
767 | u8 max_consecutive; | ||
768 | u8 padding[1]; | ||
769 | } __packed; | ||
770 | |||
771 | #define ACX_IPV4_VERSION 4 | ||
772 | #define ACX_IPV6_VERSION 6 | ||
773 | #define ACX_IPV4_ADDR_SIZE 4 | ||
774 | |||
775 | /* bitmap of enabled arp_filter features */ | ||
776 | #define ACX_ARP_FILTER_ARP_FILTERING BIT(0) | ||
777 | #define ACX_ARP_FILTER_AUTO_ARP BIT(1) | ||
778 | |||
779 | struct wl1271_acx_arp_filter { | ||
780 | struct acx_header header; | ||
781 | u8 role_id; | ||
782 | u8 version; /* ACX_IPV4_VERSION, ACX_IPV6_VERSION */ | ||
783 | u8 enable; /* bitmap of enabled ARP filtering features */ | ||
784 | u8 padding[1]; | ||
785 | u8 address[16]; /* The configured device IP address - all ARP | ||
786 | requests directed to this IP address will pass | ||
787 | through. For IPv4, the first four bytes are | ||
788 | used. */ | ||
789 | } __packed; | ||
790 | |||
791 | struct wl1271_acx_pm_config { | ||
792 | struct acx_header header; | ||
793 | |||
794 | __le32 host_clk_settling_time; | ||
795 | u8 host_fast_wakeup_support; | ||
796 | u8 padding[3]; | ||
797 | } __packed; | ||
798 | |||
799 | struct wl1271_acx_keep_alive_mode { | ||
800 | struct acx_header header; | ||
801 | |||
802 | u8 role_id; | ||
803 | u8 enabled; | ||
804 | u8 padding[2]; | ||
805 | } __packed; | ||
806 | |||
807 | enum { | ||
808 | ACX_KEEP_ALIVE_NO_TX = 0, | ||
809 | ACX_KEEP_ALIVE_PERIOD_ONLY | ||
810 | }; | ||
811 | |||
812 | enum { | ||
813 | ACX_KEEP_ALIVE_TPL_INVALID = 0, | ||
814 | ACX_KEEP_ALIVE_TPL_VALID | ||
815 | }; | ||
816 | |||
817 | struct wl1271_acx_keep_alive_config { | ||
818 | struct acx_header header; | ||
819 | |||
820 | u8 role_id; | ||
821 | u8 index; | ||
822 | u8 tpl_validation; | ||
823 | u8 trigger; | ||
824 | __le32 period; | ||
825 | } __packed; | ||
826 | |||
827 | #define HOST_IF_CFG_RX_FIFO_ENABLE BIT(0) | ||
828 | #define HOST_IF_CFG_TX_EXTRA_BLKS_SWAP BIT(1) | ||
829 | #define HOST_IF_CFG_TX_PAD_TO_SDIO_BLK BIT(3) | ||
830 | |||
831 | struct wl1271_acx_host_config_bitmap { | ||
832 | struct acx_header header; | ||
833 | |||
834 | __le32 host_cfg_bitmap; | ||
835 | } __packed; | ||
836 | |||
837 | enum { | ||
838 | WL1271_ACX_TRIG_TYPE_LEVEL = 0, | ||
839 | WL1271_ACX_TRIG_TYPE_EDGE, | ||
840 | }; | ||
841 | |||
842 | enum { | ||
843 | WL1271_ACX_TRIG_DIR_LOW = 0, | ||
844 | WL1271_ACX_TRIG_DIR_HIGH, | ||
845 | WL1271_ACX_TRIG_DIR_BIDIR, | ||
846 | }; | ||
847 | |||
848 | enum { | ||
849 | WL1271_ACX_TRIG_ENABLE = 1, | ||
850 | WL1271_ACX_TRIG_DISABLE, | ||
851 | }; | ||
852 | |||
853 | enum { | ||
854 | WL1271_ACX_TRIG_METRIC_RSSI_BEACON = 0, | ||
855 | WL1271_ACX_TRIG_METRIC_RSSI_DATA, | ||
856 | WL1271_ACX_TRIG_METRIC_SNR_BEACON, | ||
857 | WL1271_ACX_TRIG_METRIC_SNR_DATA, | ||
858 | }; | ||
859 | |||
860 | enum { | ||
861 | WL1271_ACX_TRIG_IDX_RSSI = 0, | ||
862 | WL1271_ACX_TRIG_COUNT = 8, | ||
863 | }; | ||
864 | |||
865 | struct wl1271_acx_rssi_snr_trigger { | ||
866 | struct acx_header header; | ||
867 | |||
868 | u8 role_id; | ||
869 | u8 metric; | ||
870 | u8 type; | ||
871 | u8 dir; | ||
872 | __le16 threshold; | ||
873 | __le16 pacing; /* 0 - 60000 ms */ | ||
874 | u8 hysteresis; | ||
875 | u8 index; | ||
876 | u8 enable; | ||
877 | u8 padding[1]; | ||
878 | }; | ||
879 | |||
880 | struct wl1271_acx_rssi_snr_avg_weights { | ||
881 | struct acx_header header; | ||
882 | |||
883 | u8 role_id; | ||
884 | u8 padding[3]; | ||
885 | u8 rssi_beacon; | ||
886 | u8 rssi_data; | ||
887 | u8 snr_beacon; | ||
888 | u8 snr_data; | ||
889 | }; | ||
890 | |||
891 | |||
892 | /* special capability bit (not employed by the 802.11n spec) */ | ||
893 | #define WL12XX_HT_CAP_HT_OPERATION BIT(16) | ||
894 | |||
895 | /* | ||
896 | * ACX_PEER_HT_CAP | ||
897 | * Configure HT capabilities - declare the capabilities of the peer | ||
898 | * we are connected to. | ||
899 | */ | ||
900 | struct wl1271_acx_ht_capabilities { | ||
901 | struct acx_header header; | ||
902 | |||
903 | /* bitmask of capability bits supported by the peer */ | ||
904 | __le32 ht_capabilites; | ||
905 | |||
906 | /* Indicates to which link these capabilities apply. */ | ||
907 | u8 hlid; | ||
908 | |||
909 | /* | ||
910 | * This the maximum A-MPDU length supported by the AP. The FW may not | ||
911 | * exceed this length when sending A-MPDUs | ||
912 | */ | ||
913 | u8 ampdu_max_length; | ||
914 | |||
915 | /* This is the minimal spacing required when sending A-MPDUs to the AP*/ | ||
916 | u8 ampdu_min_spacing; | ||
917 | |||
918 | u8 padding; | ||
919 | } __packed; | ||
920 | |||
921 | /* | ||
922 | * ACX_HT_BSS_OPERATION | ||
923 | * Configure HT capabilities - AP rules for behavior in the BSS. | ||
924 | */ | ||
925 | struct wl1271_acx_ht_information { | ||
926 | struct acx_header header; | ||
927 | |||
928 | u8 role_id; | ||
929 | |||
930 | /* Values: 0 - RIFS not allowed, 1 - RIFS allowed */ | ||
931 | u8 rifs_mode; | ||
932 | |||
933 | /* Values: 0 - 3 like in spec */ | ||
934 | u8 ht_protection; | ||
935 | |||
936 | /* Values: 0 - GF protection not required, 1 - GF protection required */ | ||
937 | u8 gf_protection; | ||
938 | |||
939 | /*Values: 0 - TX Burst limit not required, 1 - TX Burst Limit required*/ | ||
940 | u8 ht_tx_burst_limit; | ||
941 | |||
942 | /* | ||
943 | * Values: 0 - Dual CTS protection not required, | ||
944 | * 1 - Dual CTS Protection required | ||
945 | * Note: When this value is set to 1 FW will protect all TXOP with RTS | ||
946 | * frame and will not use CTS-to-self regardless of the value of the | ||
947 | * ACX_CTS_PROTECTION information element | ||
948 | */ | ||
949 | u8 dual_cts_protection; | ||
950 | |||
951 | u8 padding[2]; | ||
952 | } __packed; | ||
953 | |||
954 | #define RX_BA_MAX_SESSIONS 2 | ||
955 | |||
956 | struct wl1271_acx_ba_initiator_policy { | ||
957 | struct acx_header header; | ||
958 | |||
959 | /* Specifies role Id, Range 0-7, 0xFF means ANY role. */ | ||
960 | u8 role_id; | ||
961 | |||
962 | /* | ||
963 | * Per TID setting for allowing TX BA. Set a bit to 1 to allow | ||
964 | * TX BA sessions for the corresponding TID. | ||
965 | */ | ||
966 | u8 tid_bitmap; | ||
967 | |||
968 | /* Windows size in number of packets */ | ||
969 | u8 win_size; | ||
970 | |||
971 | u8 padding1[1]; | ||
972 | |||
973 | /* As initiator inactivity timeout in time units(TU) of 1024us */ | ||
974 | u16 inactivity_timeout; | ||
975 | |||
976 | u8 padding[2]; | ||
977 | } __packed; | ||
978 | |||
979 | struct wl1271_acx_ba_receiver_setup { | ||
980 | struct acx_header header; | ||
981 | |||
982 | /* Specifies link id, range 0-31 */ | ||
983 | u8 hlid; | ||
984 | |||
985 | u8 tid; | ||
986 | |||
987 | u8 enable; | ||
988 | |||
989 | /* Windows size in number of packets */ | ||
990 | u8 win_size; | ||
991 | |||
992 | /* BA session starting sequence number. RANGE 0-FFF */ | ||
993 | u16 ssn; | ||
994 | |||
995 | u8 padding[2]; | ||
996 | } __packed; | ||
997 | |||
998 | struct wl12xx_acx_fw_tsf_information { | ||
999 | struct acx_header header; | ||
1000 | |||
1001 | u8 role_id; | ||
1002 | u8 padding1[3]; | ||
1003 | __le32 current_tsf_high; | ||
1004 | __le32 current_tsf_low; | ||
1005 | __le32 last_bttt_high; | ||
1006 | __le32 last_tbtt_low; | ||
1007 | u8 last_dtim_count; | ||
1008 | u8 padding2[3]; | ||
1009 | } __packed; | ||
1010 | |||
1011 | struct wl1271_acx_ps_rx_streaming { | ||
1012 | struct acx_header header; | ||
1013 | |||
1014 | u8 role_id; | ||
1015 | u8 tid; | ||
1016 | u8 enable; | ||
1017 | |||
1018 | /* interval between triggers (10-100 msec) */ | ||
1019 | u8 period; | ||
1020 | |||
1021 | /* timeout before first trigger (0-200 msec) */ | ||
1022 | u8 timeout; | ||
1023 | u8 padding[3]; | ||
1024 | } __packed; | ||
1025 | |||
1026 | struct wl1271_acx_ap_max_tx_retry { | ||
1027 | struct acx_header header; | ||
1028 | |||
1029 | u8 role_id; | ||
1030 | u8 padding_1; | ||
1031 | |||
1032 | /* | ||
1033 | * the number of frames transmission failures before | ||
1034 | * issuing the aging event. | ||
1035 | */ | ||
1036 | __le16 max_tx_retry; | ||
1037 | } __packed; | ||
1038 | |||
1039 | struct wl1271_acx_config_ps { | ||
1040 | struct acx_header header; | ||
1041 | |||
1042 | u8 exit_retries; | ||
1043 | u8 enter_retries; | ||
1044 | u8 padding[2]; | ||
1045 | __le32 null_data_rate; | ||
1046 | } __packed; | ||
1047 | |||
1048 | struct wl1271_acx_inconnection_sta { | ||
1049 | struct acx_header header; | ||
1050 | |||
1051 | u8 addr[ETH_ALEN]; | ||
1052 | u8 padding1[2]; | ||
1053 | } __packed; | ||
1054 | |||
1055 | /* | ||
1056 | * ACX_FM_COEX_CFG | ||
1057 | * set the FM co-existence parameters. | ||
1058 | */ | ||
1059 | struct wl1271_acx_fm_coex { | ||
1060 | struct acx_header header; | ||
1061 | /* enable(1) / disable(0) the FM Coex feature */ | ||
1062 | u8 enable; | ||
1063 | /* | ||
1064 | * Swallow period used in COEX PLL swallowing mechanism. | ||
1065 | * 0xFF = use FW default | ||
1066 | */ | ||
1067 | u8 swallow_period; | ||
1068 | /* | ||
1069 | * The N divider used in COEX PLL swallowing mechanism for Fref of | ||
1070 | * 38.4/19.2 Mhz. 0xFF = use FW default | ||
1071 | */ | ||
1072 | u8 n_divider_fref_set_1; | ||
1073 | /* | ||
1074 | * The N divider used in COEX PLL swallowing mechanism for Fref of | ||
1075 | * 26/52 Mhz. 0xFF = use FW default | ||
1076 | */ | ||
1077 | u8 n_divider_fref_set_2; | ||
1078 | /* | ||
1079 | * The M divider used in COEX PLL swallowing mechanism for Fref of | ||
1080 | * 38.4/19.2 Mhz. 0xFFFF = use FW default | ||
1081 | */ | ||
1082 | __le16 m_divider_fref_set_1; | ||
1083 | /* | ||
1084 | * The M divider used in COEX PLL swallowing mechanism for Fref of | ||
1085 | * 26/52 Mhz. 0xFFFF = use FW default | ||
1086 | */ | ||
1087 | __le16 m_divider_fref_set_2; | ||
1088 | /* | ||
1089 | * The time duration in uSec required for COEX PLL to stabilize. | ||
1090 | * 0xFFFFFFFF = use FW default | ||
1091 | */ | ||
1092 | __le32 coex_pll_stabilization_time; | ||
1093 | /* | ||
1094 | * The time duration in uSec required for LDO to stabilize. | ||
1095 | * 0xFFFFFFFF = use FW default | ||
1096 | */ | ||
1097 | __le16 ldo_stabilization_time; | ||
1098 | /* | ||
1099 | * The disturbed frequency band margin around the disturbed frequency | ||
1100 | * center (single sided). | ||
1101 | * For example, if 2 is configured, the following channels will be | ||
1102 | * considered disturbed channel: | ||
1103 | * 80 +- 0.1 MHz, 91 +- 0.1 MHz, 98 +- 0.1 MHz, 102 +- 0.1 MH | ||
1104 | * 0xFF = use FW default | ||
1105 | */ | ||
1106 | u8 fm_disturbed_band_margin; | ||
1107 | /* | ||
1108 | * The swallow clock difference of the swallowing mechanism. | ||
1109 | * 0xFF = use FW default | ||
1110 | */ | ||
1111 | u8 swallow_clk_diff; | ||
1112 | } __packed; | ||
1113 | |||
1114 | #define ACX_RATE_MGMT_ALL_PARAMS 0xff | ||
1115 | struct wl12xx_acx_set_rate_mgmt_params { | ||
1116 | struct acx_header header; | ||
1117 | |||
1118 | u8 index; /* 0xff to configure all params */ | ||
1119 | u8 padding1; | ||
1120 | __le16 rate_retry_score; | ||
1121 | __le16 per_add; | ||
1122 | __le16 per_th1; | ||
1123 | __le16 per_th2; | ||
1124 | __le16 max_per; | ||
1125 | u8 inverse_curiosity_factor; | ||
1126 | u8 tx_fail_low_th; | ||
1127 | u8 tx_fail_high_th; | ||
1128 | u8 per_alpha_shift; | ||
1129 | u8 per_add_shift; | ||
1130 | u8 per_beta1_shift; | ||
1131 | u8 per_beta2_shift; | ||
1132 | u8 rate_check_up; | ||
1133 | u8 rate_check_down; | ||
1134 | u8 rate_retry_policy[ACX_RATE_MGMT_NUM_OF_RATES]; | ||
1135 | u8 padding2[2]; | ||
1136 | } __packed; | ||
1137 | |||
1138 | struct wl12xx_acx_config_hangover { | ||
1139 | struct acx_header header; | ||
1140 | |||
1141 | __le32 recover_time; | ||
1142 | u8 hangover_period; | ||
1143 | u8 dynamic_mode; | ||
1144 | u8 early_termination_mode; | ||
1145 | u8 max_period; | ||
1146 | u8 min_period; | ||
1147 | u8 increase_delta; | ||
1148 | u8 decrease_delta; | ||
1149 | u8 quiet_time; | ||
1150 | u8 increase_time; | ||
1151 | u8 window_size; | ||
1152 | u8 padding[2]; | ||
1153 | } __packed; | ||
1154 | |||
1155 | enum { | ||
1156 | ACX_WAKE_UP_CONDITIONS = 0x0000, | ||
1157 | ACX_MEM_CFG = 0x0001, | ||
1158 | ACX_SLOT = 0x0002, | ||
1159 | ACX_AC_CFG = 0x0003, | ||
1160 | ACX_MEM_MAP = 0x0004, | ||
1161 | ACX_AID = 0x0005, | ||
1162 | ACX_MEDIUM_USAGE = 0x0006, | ||
1163 | ACX_STATISTICS = 0x0007, | ||
1164 | ACX_PWR_CONSUMPTION_STATISTICS = 0x0008, | ||
1165 | ACX_TID_CFG = 0x0009, | ||
1166 | ACX_PS_RX_STREAMING = 0x000A, | ||
1167 | ACX_BEACON_FILTER_OPT = 0x000B, | ||
1168 | ACX_NOISE_HIST = 0x000C, | ||
1169 | ACX_HDK_VERSION = 0x000D, | ||
1170 | ACX_PD_THRESHOLD = 0x000E, | ||
1171 | ACX_TX_CONFIG_OPT = 0x000F, | ||
1172 | ACX_CCA_THRESHOLD = 0x0010, | ||
1173 | ACX_EVENT_MBOX_MASK = 0x0011, | ||
1174 | ACX_CONN_MONIT_PARAMS = 0x0012, | ||
1175 | ACX_DISABLE_BROADCASTS = 0x0013, | ||
1176 | ACX_BCN_DTIM_OPTIONS = 0x0014, | ||
1177 | ACX_SG_ENABLE = 0x0015, | ||
1178 | ACX_SG_CFG = 0x0016, | ||
1179 | ACX_FM_COEX_CFG = 0x0017, | ||
1180 | ACX_BEACON_FILTER_TABLE = 0x0018, | ||
1181 | ACX_ARP_IP_FILTER = 0x0019, | ||
1182 | ACX_ROAMING_STATISTICS_TBL = 0x001A, | ||
1183 | ACX_RATE_POLICY = 0x001B, | ||
1184 | ACX_CTS_PROTECTION = 0x001C, | ||
1185 | ACX_SLEEP_AUTH = 0x001D, | ||
1186 | ACX_PREAMBLE_TYPE = 0x001E, | ||
1187 | ACX_ERROR_CNT = 0x001F, | ||
1188 | ACX_IBSS_FILTER = 0x0020, | ||
1189 | ACX_SERVICE_PERIOD_TIMEOUT = 0x0021, | ||
1190 | ACX_TSF_INFO = 0x0022, | ||
1191 | ACX_CONFIG_PS_WMM = 0x0023, | ||
1192 | ACX_ENABLE_RX_DATA_FILTER = 0x0024, | ||
1193 | ACX_SET_RX_DATA_FILTER = 0x0025, | ||
1194 | ACX_GET_DATA_FILTER_STATISTICS = 0x0026, | ||
1195 | ACX_RX_CONFIG_OPT = 0x0027, | ||
1196 | ACX_FRAG_CFG = 0x0028, | ||
1197 | ACX_BET_ENABLE = 0x0029, | ||
1198 | ACX_RSSI_SNR_TRIGGER = 0x002A, | ||
1199 | ACX_RSSI_SNR_WEIGHTS = 0x002B, | ||
1200 | ACX_KEEP_ALIVE_MODE = 0x002C, | ||
1201 | ACX_SET_KEEP_ALIVE_CONFIG = 0x002D, | ||
1202 | ACX_BA_SESSION_INIT_POLICY = 0x002E, | ||
1203 | ACX_BA_SESSION_RX_SETUP = 0x002F, | ||
1204 | ACX_PEER_HT_CAP = 0x0030, | ||
1205 | ACX_HT_BSS_OPERATION = 0x0031, | ||
1206 | ACX_COEX_ACTIVITY = 0x0032, | ||
1207 | ACX_BURST_MODE = 0x0033, | ||
1208 | ACX_SET_RATE_MGMT_PARAMS = 0x0034, | ||
1209 | ACX_GET_RATE_MGMT_PARAMS = 0x0035, | ||
1210 | ACX_SET_RATE_ADAPT_PARAMS = 0x0036, | ||
1211 | ACX_SET_DCO_ITRIM_PARAMS = 0x0037, | ||
1212 | ACX_GEN_FW_CMD = 0x0038, | ||
1213 | ACX_HOST_IF_CFG_BITMAP = 0x0039, | ||
1214 | ACX_MAX_TX_FAILURE = 0x003A, | ||
1215 | ACX_UPDATE_INCONNECTION_STA_LIST = 0x003B, | ||
1216 | DOT11_RX_MSDU_LIFE_TIME = 0x003C, | ||
1217 | DOT11_CUR_TX_PWR = 0x003D, | ||
1218 | DOT11_RTS_THRESHOLD = 0x003E, | ||
1219 | DOT11_GROUP_ADDRESS_TBL = 0x003F, | ||
1220 | ACX_PM_CONFIG = 0x0040, | ||
1221 | ACX_CONFIG_PS = 0x0041, | ||
1222 | ACX_CONFIG_HANGOVER = 0x0042, | ||
1223 | ACX_FEATURE_CFG = 0x0043, | ||
1224 | ACX_PROTECTION_CFG = 0x0044, | ||
1225 | }; | ||
1226 | |||
1227 | |||
1228 | int wl1271_acx_wake_up_conditions(struct wl1271 *wl, | ||
1229 | struct wl12xx_vif *wlvif, | ||
1230 | u8 wake_up_event, u8 listen_interval); | ||
1231 | int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth); | ||
1232 | int wl1271_acx_tx_power(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
1233 | int power); | ||
1234 | int wl1271_acx_feature_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif); | ||
1235 | int wl1271_acx_mem_map(struct wl1271 *wl, | ||
1236 | struct acx_header *mem_map, size_t len); | ||
1237 | int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl); | ||
1238 | int wl1271_acx_slot(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
1239 | enum acx_slot_type slot_time); | ||
1240 | int wl1271_acx_group_address_tbl(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
1241 | bool enable, void *mc_list, u32 mc_list_len); | ||
1242 | int wl1271_acx_service_period_timeout(struct wl1271 *wl, | ||
1243 | struct wl12xx_vif *wlvif); | ||
1244 | int wl1271_acx_rts_threshold(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
1245 | u32 rts_threshold); | ||
1246 | int wl1271_acx_dco_itrim_params(struct wl1271 *wl); | ||
1247 | int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
1248 | bool enable_filter); | ||
1249 | int wl1271_acx_beacon_filter_table(struct wl1271 *wl, | ||
1250 | struct wl12xx_vif *wlvif); | ||
1251 | int wl1271_acx_conn_monit_params(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
1252 | bool enable); | ||
1253 | int wl1271_acx_sg_enable(struct wl1271 *wl, bool enable); | ||
1254 | int wl12xx_acx_sg_cfg(struct wl1271 *wl); | ||
1255 | int wl1271_acx_cca_threshold(struct wl1271 *wl); | ||
1256 | int wl1271_acx_bcn_dtim_options(struct wl1271 *wl, struct wl12xx_vif *wlvif); | ||
1257 | int wl1271_acx_aid(struct wl1271 *wl, struct wl12xx_vif *wlvif, u16 aid); | ||
1258 | int wl1271_acx_event_mbox_mask(struct wl1271 *wl, u32 event_mask); | ||
1259 | int wl1271_acx_set_preamble(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
1260 | enum acx_preamble_type preamble); | ||
1261 | int wl1271_acx_cts_protect(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
1262 | enum acx_ctsprotect_type ctsprotect); | ||
1263 | int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats); | ||
1264 | int wl1271_acx_sta_rate_policies(struct wl1271 *wl, struct wl12xx_vif *wlvif); | ||
1265 | int wl1271_acx_ap_rate_policy(struct wl1271 *wl, struct conf_tx_rate_class *c, | ||
1266 | u8 idx); | ||
1267 | int wl1271_acx_ac_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
1268 | u8 ac, u8 cw_min, u16 cw_max, u8 aifsn, u16 txop); | ||
1269 | int wl1271_acx_tid_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
1270 | u8 queue_id, u8 channel_type, | ||
1271 | u8 tsid, u8 ps_scheme, u8 ack_policy, | ||
1272 | u32 apsd_conf0, u32 apsd_conf1); | ||
1273 | int wl1271_acx_frag_threshold(struct wl1271 *wl, u32 frag_threshold); | ||
1274 | int wl1271_acx_tx_config_options(struct wl1271 *wl); | ||
1275 | int wl12xx_acx_mem_cfg(struct wl1271 *wl); | ||
1276 | int wl1271_acx_init_mem_config(struct wl1271 *wl); | ||
1277 | int wl1271_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap); | ||
1278 | int wl1271_acx_init_rx_interrupt(struct wl1271 *wl); | ||
1279 | int wl1271_acx_smart_reflex(struct wl1271 *wl); | ||
1280 | int wl1271_acx_bet_enable(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
1281 | bool enable); | ||
1282 | int wl1271_acx_arp_ip_filter(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
1283 | u8 enable, __be32 address); | ||
1284 | int wl1271_acx_pm_config(struct wl1271 *wl); | ||
1285 | int wl1271_acx_keep_alive_mode(struct wl1271 *wl, struct wl12xx_vif *vif, | ||
1286 | bool enable); | ||
1287 | int wl1271_acx_keep_alive_config(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
1288 | u8 index, u8 tpl_valid); | ||
1289 | int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
1290 | bool enable, s16 thold, u8 hyst); | ||
1291 | int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl, | ||
1292 | struct wl12xx_vif *wlvif); | ||
1293 | int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, | ||
1294 | struct ieee80211_sta_ht_cap *ht_cap, | ||
1295 | bool allow_ht_operation, u8 hlid); | ||
1296 | int wl1271_acx_set_ht_information(struct wl1271 *wl, | ||
1297 | struct wl12xx_vif *wlvif, | ||
1298 | u16 ht_operation_mode); | ||
1299 | int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl, | ||
1300 | struct wl12xx_vif *wlvif); | ||
1301 | int wl12xx_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, | ||
1302 | u16 ssn, bool enable, u8 peer_hlid); | ||
1303 | int wl12xx_acx_tsf_info(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
1304 | u64 *mactime); | ||
1305 | int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
1306 | bool enable); | ||
1307 | int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl, struct wl12xx_vif *wlvif); | ||
1308 | int wl12xx_acx_config_ps(struct wl1271 *wl, struct wl12xx_vif *wlvif); | ||
1309 | int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr); | ||
1310 | int wl1271_acx_fm_coex(struct wl1271 *wl); | ||
1311 | int wl12xx_acx_set_rate_mgmt_params(struct wl1271 *wl); | ||
1312 | int wl12xx_acx_config_hangover(struct wl1271 *wl); | ||
1313 | |||
1314 | #endif /* __WL1271_ACX_H__ */ | ||
diff --git a/drivers/net/wireless/ti/wl12xx/boot.c b/drivers/net/wireless/ti/wl12xx/boot.c new file mode 100644 index 000000000000..88d60c40b7e3 --- /dev/null +++ b/drivers/net/wireless/ti/wl12xx/boot.c | |||
@@ -0,0 +1,794 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2008-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 | #include <linux/slab.h> | ||
25 | #include <linux/wl12xx.h> | ||
26 | #include <linux/export.h> | ||
27 | |||
28 | #include "debug.h" | ||
29 | #include "acx.h" | ||
30 | #include "reg.h" | ||
31 | #include "boot.h" | ||
32 | #include "io.h" | ||
33 | #include "event.h" | ||
34 | #include "rx.h" | ||
35 | |||
36 | static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag) | ||
37 | { | ||
38 | u32 cpu_ctrl; | ||
39 | |||
40 | /* 10.5.0 run the firmware (I) */ | ||
41 | cpu_ctrl = wl1271_read32(wl, ACX_REG_ECPU_CONTROL); | ||
42 | |||
43 | /* 10.5.1 run the firmware (II) */ | ||
44 | cpu_ctrl |= flag; | ||
45 | wl1271_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); | ||
46 | } | ||
47 | |||
48 | static unsigned int wl12xx_get_fw_ver_quirks(struct wl1271 *wl) | ||
49 | { | ||
50 | unsigned int quirks = 0; | ||
51 | unsigned int *fw_ver = wl->chip.fw_ver; | ||
52 | |||
53 | /* Only new station firmwares support routing fw logs to the host */ | ||
54 | if ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) && | ||
55 | (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_FWLOG_STA_MIN)) | ||
56 | quirks |= WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED; | ||
57 | |||
58 | /* This feature is not yet supported for AP mode */ | ||
59 | if (fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP) | ||
60 | quirks |= WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED; | ||
61 | |||
62 | return quirks; | ||
63 | } | ||
64 | |||
65 | static void wl1271_parse_fw_ver(struct wl1271 *wl) | ||
66 | { | ||
67 | int ret; | ||
68 | |||
69 | ret = sscanf(wl->chip.fw_ver_str + 4, "%u.%u.%u.%u.%u", | ||
70 | &wl->chip.fw_ver[0], &wl->chip.fw_ver[1], | ||
71 | &wl->chip.fw_ver[2], &wl->chip.fw_ver[3], | ||
72 | &wl->chip.fw_ver[4]); | ||
73 | |||
74 | if (ret != 5) { | ||
75 | wl1271_warning("fw version incorrect value"); | ||
76 | memset(wl->chip.fw_ver, 0, sizeof(wl->chip.fw_ver)); | ||
77 | return; | ||
78 | } | ||
79 | |||
80 | /* Check if any quirks are needed with older fw versions */ | ||
81 | wl->quirks |= wl12xx_get_fw_ver_quirks(wl); | ||
82 | } | ||
83 | |||
84 | static void wl1271_boot_fw_version(struct wl1271 *wl) | ||
85 | { | ||
86 | struct wl1271_static_data *static_data; | ||
87 | |||
88 | static_data = kmalloc(sizeof(*static_data), GFP_DMA); | ||
89 | if (!static_data) { | ||
90 | __WARN(); | ||
91 | return; | ||
92 | } | ||
93 | |||
94 | wl1271_read(wl, wl->cmd_box_addr, static_data, sizeof(*static_data), | ||
95 | false); | ||
96 | |||
97 | strncpy(wl->chip.fw_ver_str, static_data->fw_version, | ||
98 | sizeof(wl->chip.fw_ver_str)); | ||
99 | |||
100 | kfree(static_data); | ||
101 | |||
102 | /* make sure the string is NULL-terminated */ | ||
103 | wl->chip.fw_ver_str[sizeof(wl->chip.fw_ver_str) - 1] = '\0'; | ||
104 | |||
105 | wl1271_parse_fw_ver(wl); | ||
106 | } | ||
107 | |||
108 | static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, | ||
109 | size_t fw_data_len, u32 dest) | ||
110 | { | ||
111 | struct wl1271_partition_set partition; | ||
112 | int addr, chunk_num, partition_limit; | ||
113 | u8 *p, *chunk; | ||
114 | |||
115 | /* whal_FwCtrl_LoadFwImageSm() */ | ||
116 | |||
117 | wl1271_debug(DEBUG_BOOT, "starting firmware upload"); | ||
118 | |||
119 | wl1271_debug(DEBUG_BOOT, "fw_data_len %zd chunk_size %d", | ||
120 | fw_data_len, CHUNK_SIZE); | ||
121 | |||
122 | if ((fw_data_len % 4) != 0) { | ||
123 | wl1271_error("firmware length not multiple of four"); | ||
124 | return -EIO; | ||
125 | } | ||
126 | |||
127 | chunk = kmalloc(CHUNK_SIZE, GFP_KERNEL); | ||
128 | if (!chunk) { | ||
129 | wl1271_error("allocation for firmware upload chunk failed"); | ||
130 | return -ENOMEM; | ||
131 | } | ||
132 | |||
133 | memcpy(&partition, &wl12xx_part_table[PART_DOWN], sizeof(partition)); | ||
134 | partition.mem.start = dest; | ||
135 | wl1271_set_partition(wl, &partition); | ||
136 | |||
137 | /* 10.1 set partition limit and chunk num */ | ||
138 | chunk_num = 0; | ||
139 | partition_limit = wl12xx_part_table[PART_DOWN].mem.size; | ||
140 | |||
141 | while (chunk_num < fw_data_len / CHUNK_SIZE) { | ||
142 | /* 10.2 update partition, if needed */ | ||
143 | addr = dest + (chunk_num + 2) * CHUNK_SIZE; | ||
144 | if (addr > partition_limit) { | ||
145 | addr = dest + chunk_num * CHUNK_SIZE; | ||
146 | partition_limit = chunk_num * CHUNK_SIZE + | ||
147 | wl12xx_part_table[PART_DOWN].mem.size; | ||
148 | partition.mem.start = addr; | ||
149 | wl1271_set_partition(wl, &partition); | ||
150 | } | ||
151 | |||
152 | /* 10.3 upload the chunk */ | ||
153 | addr = dest + chunk_num * CHUNK_SIZE; | ||
154 | p = buf + chunk_num * CHUNK_SIZE; | ||
155 | memcpy(chunk, p, CHUNK_SIZE); | ||
156 | wl1271_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", | ||
157 | p, addr); | ||
158 | wl1271_write(wl, addr, chunk, CHUNK_SIZE, false); | ||
159 | |||
160 | chunk_num++; | ||
161 | } | ||
162 | |||
163 | /* 10.4 upload the last chunk */ | ||
164 | addr = dest + chunk_num * CHUNK_SIZE; | ||
165 | p = buf + chunk_num * CHUNK_SIZE; | ||
166 | memcpy(chunk, p, fw_data_len % CHUNK_SIZE); | ||
167 | wl1271_debug(DEBUG_BOOT, "uploading fw last chunk (%zd B) 0x%p to 0x%x", | ||
168 | fw_data_len % CHUNK_SIZE, p, addr); | ||
169 | wl1271_write(wl, addr, chunk, fw_data_len % CHUNK_SIZE, false); | ||
170 | |||
171 | kfree(chunk); | ||
172 | return 0; | ||
173 | } | ||
174 | |||
175 | static int wl1271_boot_upload_firmware(struct wl1271 *wl) | ||
176 | { | ||
177 | u32 chunks, addr, len; | ||
178 | int ret = 0; | ||
179 | u8 *fw; | ||
180 | |||
181 | fw = wl->fw; | ||
182 | chunks = be32_to_cpup((__be32 *) fw); | ||
183 | fw += sizeof(u32); | ||
184 | |||
185 | wl1271_debug(DEBUG_BOOT, "firmware chunks to be uploaded: %u", chunks); | ||
186 | |||
187 | while (chunks--) { | ||
188 | addr = be32_to_cpup((__be32 *) fw); | ||
189 | fw += sizeof(u32); | ||
190 | len = be32_to_cpup((__be32 *) fw); | ||
191 | fw += sizeof(u32); | ||
192 | |||
193 | if (len > 300000) { | ||
194 | wl1271_info("firmware chunk too long: %u", len); | ||
195 | return -EINVAL; | ||
196 | } | ||
197 | wl1271_debug(DEBUG_BOOT, "chunk %d addr 0x%x len %u", | ||
198 | chunks, addr, len); | ||
199 | ret = wl1271_boot_upload_firmware_chunk(wl, fw, len, addr); | ||
200 | if (ret != 0) | ||
201 | break; | ||
202 | fw += len; | ||
203 | } | ||
204 | |||
205 | return ret; | ||
206 | } | ||
207 | |||
208 | static int wl1271_boot_upload_nvs(struct wl1271 *wl) | ||
209 | { | ||
210 | size_t nvs_len, burst_len; | ||
211 | int i; | ||
212 | u32 dest_addr, val; | ||
213 | u8 *nvs_ptr, *nvs_aligned; | ||
214 | |||
215 | if (wl->nvs == NULL) | ||
216 | return -ENODEV; | ||
217 | |||
218 | if (wl->chip.id == CHIP_ID_1283_PG20) { | ||
219 | struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *)wl->nvs; | ||
220 | |||
221 | if (wl->nvs_len == sizeof(struct wl128x_nvs_file)) { | ||
222 | if (nvs->general_params.dual_mode_select) | ||
223 | wl->enable_11a = true; | ||
224 | } else { | ||
225 | wl1271_error("nvs size is not as expected: %zu != %zu", | ||
226 | wl->nvs_len, | ||
227 | sizeof(struct wl128x_nvs_file)); | ||
228 | kfree(wl->nvs); | ||
229 | wl->nvs = NULL; | ||
230 | wl->nvs_len = 0; | ||
231 | return -EILSEQ; | ||
232 | } | ||
233 | |||
234 | /* only the first part of the NVS needs to be uploaded */ | ||
235 | nvs_len = sizeof(nvs->nvs); | ||
236 | nvs_ptr = (u8 *)nvs->nvs; | ||
237 | |||
238 | } else { | ||
239 | struct wl1271_nvs_file *nvs = | ||
240 | (struct wl1271_nvs_file *)wl->nvs; | ||
241 | /* | ||
242 | * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz | ||
243 | * band configurations) can be removed when those NVS files stop | ||
244 | * floating around. | ||
245 | */ | ||
246 | if (wl->nvs_len == sizeof(struct wl1271_nvs_file) || | ||
247 | wl->nvs_len == WL1271_INI_LEGACY_NVS_FILE_SIZE) { | ||
248 | if (nvs->general_params.dual_mode_select) | ||
249 | wl->enable_11a = true; | ||
250 | } | ||
251 | |||
252 | if (wl->nvs_len != sizeof(struct wl1271_nvs_file) && | ||
253 | (wl->nvs_len != WL1271_INI_LEGACY_NVS_FILE_SIZE || | ||
254 | wl->enable_11a)) { | ||
255 | wl1271_error("nvs size is not as expected: %zu != %zu", | ||
256 | wl->nvs_len, sizeof(struct wl1271_nvs_file)); | ||
257 | kfree(wl->nvs); | ||
258 | wl->nvs = NULL; | ||
259 | wl->nvs_len = 0; | ||
260 | return -EILSEQ; | ||
261 | } | ||
262 | |||
263 | /* only the first part of the NVS needs to be uploaded */ | ||
264 | nvs_len = sizeof(nvs->nvs); | ||
265 | nvs_ptr = (u8 *) nvs->nvs; | ||
266 | } | ||
267 | |||
268 | /* update current MAC address to NVS */ | ||
269 | nvs_ptr[11] = wl->addresses[0].addr[0]; | ||
270 | nvs_ptr[10] = wl->addresses[0].addr[1]; | ||
271 | nvs_ptr[6] = wl->addresses[0].addr[2]; | ||
272 | nvs_ptr[5] = wl->addresses[0].addr[3]; | ||
273 | nvs_ptr[4] = wl->addresses[0].addr[4]; | ||
274 | nvs_ptr[3] = wl->addresses[0].addr[5]; | ||
275 | |||
276 | /* | ||
277 | * Layout before the actual NVS tables: | ||
278 | * 1 byte : burst length. | ||
279 | * 2 bytes: destination address. | ||
280 | * n bytes: data to burst copy. | ||
281 | * | ||
282 | * This is ended by a 0 length, then the NVS tables. | ||
283 | */ | ||
284 | |||
285 | /* FIXME: Do we need to check here whether the LSB is 1? */ | ||
286 | while (nvs_ptr[0]) { | ||
287 | burst_len = nvs_ptr[0]; | ||
288 | dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8)); | ||
289 | |||
290 | /* | ||
291 | * Due to our new wl1271_translate_reg_addr function, | ||
292 | * we need to add the REGISTER_BASE to the destination | ||
293 | */ | ||
294 | dest_addr += REGISTERS_BASE; | ||
295 | |||
296 | /* We move our pointer to the data */ | ||
297 | nvs_ptr += 3; | ||
298 | |||
299 | for (i = 0; i < burst_len; i++) { | ||
300 | if (nvs_ptr + 3 >= (u8 *) wl->nvs + nvs_len) | ||
301 | goto out_badnvs; | ||
302 | |||
303 | val = (nvs_ptr[0] | (nvs_ptr[1] << 8) | ||
304 | | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); | ||
305 | |||
306 | wl1271_debug(DEBUG_BOOT, | ||
307 | "nvs burst write 0x%x: 0x%x", | ||
308 | dest_addr, val); | ||
309 | wl1271_write32(wl, dest_addr, val); | ||
310 | |||
311 | nvs_ptr += 4; | ||
312 | dest_addr += 4; | ||
313 | } | ||
314 | |||
315 | if (nvs_ptr >= (u8 *) wl->nvs + nvs_len) | ||
316 | goto out_badnvs; | ||
317 | } | ||
318 | |||
319 | /* | ||
320 | * 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. | ||
322 | * NOTE: The wl->nvs->nvs element must be first, in order to | ||
323 | * simplify the casting, we assume it is at the beginning of | ||
324 | * the wl->nvs structure. | ||
325 | */ | ||
326 | nvs_ptr = (u8 *)wl->nvs + | ||
327 | ALIGN(nvs_ptr - (u8 *)wl->nvs + 7, 4); | ||
328 | |||
329 | if (nvs_ptr >= (u8 *) wl->nvs + nvs_len) | ||
330 | goto out_badnvs; | ||
331 | |||
332 | nvs_len -= nvs_ptr - (u8 *)wl->nvs; | ||
333 | |||
334 | /* Now we must set the partition correctly */ | ||
335 | wl1271_set_partition(wl, &wl12xx_part_table[PART_WORK]); | ||
336 | |||
337 | /* Copy the NVS tables to a new block to ensure alignment */ | ||
338 | nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL); | ||
339 | if (!nvs_aligned) | ||
340 | return -ENOMEM; | ||
341 | |||
342 | /* And finally we upload the NVS tables */ | ||
343 | wl1271_write(wl, CMD_MBOX_ADDRESS, nvs_aligned, nvs_len, false); | ||
344 | |||
345 | kfree(nvs_aligned); | ||
346 | return 0; | ||
347 | |||
348 | out_badnvs: | ||
349 | wl1271_error("nvs data is malformed"); | ||
350 | return -EILSEQ; | ||
351 | } | ||
352 | |||
353 | static void wl1271_boot_enable_interrupts(struct wl1271 *wl) | ||
354 | { | ||
355 | wl1271_enable_interrupts(wl); | ||
356 | wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, | ||
357 | WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK)); | ||
358 | wl1271_write32(wl, HI_CFG, HI_CFG_DEF_VAL); | ||
359 | } | ||
360 | |||
361 | static int wl1271_boot_soft_reset(struct wl1271 *wl) | ||
362 | { | ||
363 | unsigned long timeout; | ||
364 | u32 boot_data; | ||
365 | |||
366 | /* perform soft reset */ | ||
367 | wl1271_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT); | ||
368 | |||
369 | /* SOFT_RESET is self clearing */ | ||
370 | timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME); | ||
371 | while (1) { | ||
372 | boot_data = wl1271_read32(wl, ACX_REG_SLV_SOFT_RESET); | ||
373 | wl1271_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data); | ||
374 | if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0) | ||
375 | break; | ||
376 | |||
377 | if (time_after(jiffies, timeout)) { | ||
378 | /* 1.2 check pWhalBus->uSelfClearTime if the | ||
379 | * timeout was reached */ | ||
380 | wl1271_error("soft reset timeout"); | ||
381 | return -1; | ||
382 | } | ||
383 | |||
384 | udelay(SOFT_RESET_STALL_TIME); | ||
385 | } | ||
386 | |||
387 | /* disable Rx/Tx */ | ||
388 | wl1271_write32(wl, ENABLE, 0x0); | ||
389 | |||
390 | /* disable auto calibration on start*/ | ||
391 | wl1271_write32(wl, SPARE_A2, 0xffff); | ||
392 | |||
393 | return 0; | ||
394 | } | ||
395 | |||
396 | static int wl1271_boot_run_firmware(struct wl1271 *wl) | ||
397 | { | ||
398 | int loop, ret; | ||
399 | u32 chip_id, intr; | ||
400 | |||
401 | wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); | ||
402 | |||
403 | chip_id = wl1271_read32(wl, CHIP_ID_B); | ||
404 | |||
405 | wl1271_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); | ||
406 | |||
407 | if (chip_id != wl->chip.id) { | ||
408 | wl1271_error("chip id doesn't match after firmware boot"); | ||
409 | return -EIO; | ||
410 | } | ||
411 | |||
412 | /* wait for init to complete */ | ||
413 | loop = 0; | ||
414 | while (loop++ < INIT_LOOP) { | ||
415 | udelay(INIT_LOOP_DELAY); | ||
416 | intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); | ||
417 | |||
418 | if (intr == 0xffffffff) { | ||
419 | wl1271_error("error reading hardware complete " | ||
420 | "init indication"); | ||
421 | return -EIO; | ||
422 | } | ||
423 | /* check that ACX_INTR_INIT_COMPLETE is enabled */ | ||
424 | else if (intr & WL1271_ACX_INTR_INIT_COMPLETE) { | ||
425 | wl1271_write32(wl, ACX_REG_INTERRUPT_ACK, | ||
426 | WL1271_ACX_INTR_INIT_COMPLETE); | ||
427 | break; | ||
428 | } | ||
429 | } | ||
430 | |||
431 | if (loop > INIT_LOOP) { | ||
432 | wl1271_error("timeout waiting for the hardware to " | ||
433 | "complete initialization"); | ||
434 | return -EIO; | ||
435 | } | ||
436 | |||
437 | /* get hardware config command mail box */ | ||
438 | wl->cmd_box_addr = wl1271_read32(wl, REG_COMMAND_MAILBOX_PTR); | ||
439 | |||
440 | /* get hardware config event mail box */ | ||
441 | wl->event_box_addr = wl1271_read32(wl, REG_EVENT_MAILBOX_PTR); | ||
442 | |||
443 | /* set the working partition to its "running" mode offset */ | ||
444 | wl1271_set_partition(wl, &wl12xx_part_table[PART_WORK]); | ||
445 | |||
446 | wl1271_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x", | ||
447 | wl->cmd_box_addr, wl->event_box_addr); | ||
448 | |||
449 | wl1271_boot_fw_version(wl); | ||
450 | |||
451 | /* | ||
452 | * in case of full asynchronous mode the firmware event must be | ||
453 | * ready to receive event from the command mailbox | ||
454 | */ | ||
455 | |||
456 | /* unmask required mbox events */ | ||
457 | wl->event_mask = BSS_LOSE_EVENT_ID | | ||
458 | SCAN_COMPLETE_EVENT_ID | | ||
459 | ROLE_STOP_COMPLETE_EVENT_ID | | ||
460 | RSSI_SNR_TRIGGER_0_EVENT_ID | | ||
461 | PSPOLL_DELIVERY_FAILURE_EVENT_ID | | ||
462 | SOFT_GEMINI_SENSE_EVENT_ID | | ||
463 | PERIODIC_SCAN_REPORT_EVENT_ID | | ||
464 | PERIODIC_SCAN_COMPLETE_EVENT_ID | | ||
465 | DUMMY_PACKET_EVENT_ID | | ||
466 | PEER_REMOVE_COMPLETE_EVENT_ID | | ||
467 | BA_SESSION_RX_CONSTRAINT_EVENT_ID | | ||
468 | REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID | | ||
469 | INACTIVE_STA_EVENT_ID | | ||
470 | MAX_TX_RETRY_EVENT_ID | | ||
471 | CHANNEL_SWITCH_COMPLETE_EVENT_ID; | ||
472 | |||
473 | ret = wl1271_event_unmask(wl); | ||
474 | if (ret < 0) { | ||
475 | wl1271_error("EVENT mask setting failed"); | ||
476 | return ret; | ||
477 | } | ||
478 | |||
479 | wl1271_event_mbox_config(wl); | ||
480 | |||
481 | /* firmware startup completed */ | ||
482 | return 0; | ||
483 | } | ||
484 | |||
485 | static int wl1271_boot_write_irq_polarity(struct wl1271 *wl) | ||
486 | { | ||
487 | u32 polarity; | ||
488 | |||
489 | polarity = wl1271_top_reg_read(wl, OCP_REG_POLARITY); | ||
490 | |||
491 | /* We use HIGH polarity, so unset the LOW bit */ | ||
492 | polarity &= ~POLARITY_LOW; | ||
493 | wl1271_top_reg_write(wl, OCP_REG_POLARITY, polarity); | ||
494 | |||
495 | return 0; | ||
496 | } | ||
497 | |||
498 | static int wl128x_switch_tcxo_to_fref(struct wl1271 *wl) | ||
499 | { | ||
500 | u16 spare_reg; | ||
501 | |||
502 | /* Mask bits [2] & [8:4] in the sys_clk_cfg register */ | ||
503 | spare_reg = wl1271_top_reg_read(wl, WL_SPARE_REG); | ||
504 | if (spare_reg == 0xFFFF) | ||
505 | return -EFAULT; | ||
506 | spare_reg |= (BIT(3) | BIT(5) | BIT(6)); | ||
507 | wl1271_top_reg_write(wl, WL_SPARE_REG, spare_reg); | ||
508 | |||
509 | /* Enable FREF_CLK_REQ & mux MCS and coex PLLs to FREF */ | ||
510 | wl1271_top_reg_write(wl, SYS_CLK_CFG_REG, | ||
511 | WL_CLK_REQ_TYPE_PG2 | MCS_PLL_CLK_SEL_FREF); | ||
512 | |||
513 | /* Delay execution for 15msec, to let the HW settle */ | ||
514 | mdelay(15); | ||
515 | |||
516 | return 0; | ||
517 | } | ||
518 | |||
519 | static bool wl128x_is_tcxo_valid(struct wl1271 *wl) | ||
520 | { | ||
521 | u16 tcxo_detection; | ||
522 | |||
523 | tcxo_detection = wl1271_top_reg_read(wl, TCXO_CLK_DETECT_REG); | ||
524 | if (tcxo_detection & TCXO_DET_FAILED) | ||
525 | return false; | ||
526 | |||
527 | return true; | ||
528 | } | ||
529 | |||
530 | static bool wl128x_is_fref_valid(struct wl1271 *wl) | ||
531 | { | ||
532 | u16 fref_detection; | ||
533 | |||
534 | fref_detection = wl1271_top_reg_read(wl, FREF_CLK_DETECT_REG); | ||
535 | if (fref_detection & FREF_CLK_DETECT_FAIL) | ||
536 | return false; | ||
537 | |||
538 | return true; | ||
539 | } | ||
540 | |||
541 | static int wl128x_manually_configure_mcs_pll(struct wl1271 *wl) | ||
542 | { | ||
543 | wl1271_top_reg_write(wl, MCS_PLL_M_REG, MCS_PLL_M_REG_VAL); | ||
544 | wl1271_top_reg_write(wl, MCS_PLL_N_REG, MCS_PLL_N_REG_VAL); | ||
545 | wl1271_top_reg_write(wl, MCS_PLL_CONFIG_REG, MCS_PLL_CONFIG_REG_VAL); | ||
546 | |||
547 | return 0; | ||
548 | } | ||
549 | |||
550 | static int wl128x_configure_mcs_pll(struct wl1271 *wl, int clk) | ||
551 | { | ||
552 | u16 spare_reg; | ||
553 | u16 pll_config; | ||
554 | u8 input_freq; | ||
555 | |||
556 | /* Mask bits [3:1] in the sys_clk_cfg register */ | ||
557 | spare_reg = wl1271_top_reg_read(wl, WL_SPARE_REG); | ||
558 | if (spare_reg == 0xFFFF) | ||
559 | return -EFAULT; | ||
560 | spare_reg |= BIT(2); | ||
561 | wl1271_top_reg_write(wl, WL_SPARE_REG, spare_reg); | ||
562 | |||
563 | /* Handle special cases of the TCXO clock */ | ||
564 | if (wl->tcxo_clock == WL12XX_TCXOCLOCK_16_8 || | ||
565 | wl->tcxo_clock == WL12XX_TCXOCLOCK_33_6) | ||
566 | return wl128x_manually_configure_mcs_pll(wl); | ||
567 | |||
568 | /* Set the input frequency according to the selected clock source */ | ||
569 | input_freq = (clk & 1) + 1; | ||
570 | |||
571 | pll_config = wl1271_top_reg_read(wl, MCS_PLL_CONFIG_REG); | ||
572 | if (pll_config == 0xFFFF) | ||
573 | return -EFAULT; | ||
574 | pll_config |= (input_freq << MCS_SEL_IN_FREQ_SHIFT); | ||
575 | pll_config |= MCS_PLL_ENABLE_HP; | ||
576 | wl1271_top_reg_write(wl, MCS_PLL_CONFIG_REG, pll_config); | ||
577 | |||
578 | return 0; | ||
579 | } | ||
580 | |||
581 | /* | ||
582 | * WL128x has two clocks input - TCXO and FREF. | ||
583 | * TCXO is the main clock of the device, while FREF is used to sync | ||
584 | * between the GPS and the cellular modem. | ||
585 | * In cases where TCXO is 32.736MHz or 16.368MHz, the FREF will be used | ||
586 | * as the WLAN/BT main clock. | ||
587 | */ | ||
588 | static int wl128x_boot_clk(struct wl1271 *wl, int *selected_clock) | ||
589 | { | ||
590 | u16 sys_clk_cfg; | ||
591 | |||
592 | /* For XTAL-only modes, FREF will be used after switching from TCXO */ | ||
593 | if (wl->ref_clock == WL12XX_REFCLOCK_26_XTAL || | ||
594 | wl->ref_clock == WL12XX_REFCLOCK_38_XTAL) { | ||
595 | if (!wl128x_switch_tcxo_to_fref(wl)) | ||
596 | return -EINVAL; | ||
597 | goto fref_clk; | ||
598 | } | ||
599 | |||
600 | /* Query the HW, to determine which clock source we should use */ | ||
601 | sys_clk_cfg = wl1271_top_reg_read(wl, SYS_CLK_CFG_REG); | ||
602 | if (sys_clk_cfg == 0xFFFF) | ||
603 | return -EINVAL; | ||
604 | if (sys_clk_cfg & PRCM_CM_EN_MUX_WLAN_FREF) | ||
605 | goto fref_clk; | ||
606 | |||
607 | /* If TCXO is either 32.736MHz or 16.368MHz, switch to FREF */ | ||
608 | if (wl->tcxo_clock == WL12XX_TCXOCLOCK_16_368 || | ||
609 | wl->tcxo_clock == WL12XX_TCXOCLOCK_32_736) { | ||
610 | if (!wl128x_switch_tcxo_to_fref(wl)) | ||
611 | return -EINVAL; | ||
612 | goto fref_clk; | ||
613 | } | ||
614 | |||
615 | /* TCXO clock is selected */ | ||
616 | if (!wl128x_is_tcxo_valid(wl)) | ||
617 | return -EINVAL; | ||
618 | *selected_clock = wl->tcxo_clock; | ||
619 | goto config_mcs_pll; | ||
620 | |||
621 | fref_clk: | ||
622 | /* FREF clock is selected */ | ||
623 | if (!wl128x_is_fref_valid(wl)) | ||
624 | return -EINVAL; | ||
625 | *selected_clock = wl->ref_clock; | ||
626 | |||
627 | config_mcs_pll: | ||
628 | return wl128x_configure_mcs_pll(wl, *selected_clock); | ||
629 | } | ||
630 | |||
631 | static int wl127x_boot_clk(struct wl1271 *wl) | ||
632 | { | ||
633 | u32 pause; | ||
634 | u32 clk; | ||
635 | |||
636 | if (WL127X_PG_GET_MAJOR(wl->hw_pg_ver) < 3) | ||
637 | wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION; | ||
638 | |||
639 | if (wl->ref_clock == CONF_REF_CLK_19_2_E || | ||
640 | wl->ref_clock == CONF_REF_CLK_38_4_E || | ||
641 | wl->ref_clock == CONF_REF_CLK_38_4_M_XTAL) | ||
642 | /* ref clk: 19.2/38.4/38.4-XTAL */ | ||
643 | clk = 0x3; | ||
644 | else if (wl->ref_clock == CONF_REF_CLK_26_E || | ||
645 | wl->ref_clock == CONF_REF_CLK_52_E) | ||
646 | /* ref clk: 26/52 */ | ||
647 | clk = 0x5; | ||
648 | else | ||
649 | return -EINVAL; | ||
650 | |||
651 | if (wl->ref_clock != CONF_REF_CLK_19_2_E) { | ||
652 | u16 val; | ||
653 | /* Set clock type (open drain) */ | ||
654 | val = wl1271_top_reg_read(wl, OCP_REG_CLK_TYPE); | ||
655 | val &= FREF_CLK_TYPE_BITS; | ||
656 | wl1271_top_reg_write(wl, OCP_REG_CLK_TYPE, val); | ||
657 | |||
658 | /* Set clock pull mode (no pull) */ | ||
659 | val = wl1271_top_reg_read(wl, OCP_REG_CLK_PULL); | ||
660 | val |= NO_PULL; | ||
661 | wl1271_top_reg_write(wl, OCP_REG_CLK_PULL, val); | ||
662 | } else { | ||
663 | u16 val; | ||
664 | /* Set clock polarity */ | ||
665 | val = wl1271_top_reg_read(wl, OCP_REG_CLK_POLARITY); | ||
666 | val &= FREF_CLK_POLARITY_BITS; | ||
667 | val |= CLK_REQ_OUTN_SEL; | ||
668 | wl1271_top_reg_write(wl, OCP_REG_CLK_POLARITY, val); | ||
669 | } | ||
670 | |||
671 | wl1271_write32(wl, PLL_PARAMETERS, clk); | ||
672 | |||
673 | pause = wl1271_read32(wl, PLL_PARAMETERS); | ||
674 | |||
675 | wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause); | ||
676 | |||
677 | pause &= ~(WU_COUNTER_PAUSE_VAL); | ||
678 | pause |= WU_COUNTER_PAUSE_VAL; | ||
679 | wl1271_write32(wl, WU_COUNTER_PAUSE, pause); | ||
680 | |||
681 | return 0; | ||
682 | } | ||
683 | |||
684 | /* uploads NVS and firmware */ | ||
685 | int wl1271_load_firmware(struct wl1271 *wl) | ||
686 | { | ||
687 | int ret = 0; | ||
688 | u32 tmp, clk; | ||
689 | int selected_clock = -1; | ||
690 | |||
691 | if (wl->chip.id == CHIP_ID_1283_PG20) { | ||
692 | ret = wl128x_boot_clk(wl, &selected_clock); | ||
693 | if (ret < 0) | ||
694 | goto out; | ||
695 | } else { | ||
696 | ret = wl127x_boot_clk(wl); | ||
697 | if (ret < 0) | ||
698 | goto out; | ||
699 | } | ||
700 | |||
701 | /* Continue the ELP wake up sequence */ | ||
702 | wl1271_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL); | ||
703 | udelay(500); | ||
704 | |||
705 | wl1271_set_partition(wl, &wl12xx_part_table[PART_DRPW]); | ||
706 | |||
707 | /* Read-modify-write DRPW_SCRATCH_START register (see next state) | ||
708 | to be used by DRPw FW. The RTRIM value will be added by the FW | ||
709 | before taking DRPw out of reset */ | ||
710 | |||
711 | wl1271_debug(DEBUG_BOOT, "DRPW_SCRATCH_START %08x", DRPW_SCRATCH_START); | ||
712 | clk = wl1271_read32(wl, DRPW_SCRATCH_START); | ||
713 | |||
714 | wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk); | ||
715 | |||
716 | if (wl->chip.id == CHIP_ID_1283_PG20) { | ||
717 | clk |= ((selected_clock & 0x3) << 1) << 4; | ||
718 | } else { | ||
719 | clk |= (wl->ref_clock << 1) << 4; | ||
720 | } | ||
721 | |||
722 | wl1271_write32(wl, DRPW_SCRATCH_START, clk); | ||
723 | |||
724 | wl1271_set_partition(wl, &wl12xx_part_table[PART_WORK]); | ||
725 | |||
726 | /* Disable interrupts */ | ||
727 | wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL); | ||
728 | |||
729 | ret = wl1271_boot_soft_reset(wl); | ||
730 | if (ret < 0) | ||
731 | goto out; | ||
732 | |||
733 | /* 2. start processing NVS file */ | ||
734 | ret = wl1271_boot_upload_nvs(wl); | ||
735 | if (ret < 0) | ||
736 | goto out; | ||
737 | |||
738 | /* write firmware's last address (ie. it's length) to | ||
739 | * ACX_EEPROMLESS_IND_REG */ | ||
740 | wl1271_debug(DEBUG_BOOT, "ACX_EEPROMLESS_IND_REG"); | ||
741 | |||
742 | wl1271_write32(wl, ACX_EEPROMLESS_IND_REG, ACX_EEPROMLESS_IND_REG); | ||
743 | |||
744 | tmp = wl1271_read32(wl, CHIP_ID_B); | ||
745 | |||
746 | wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp); | ||
747 | |||
748 | /* 6. read the EEPROM parameters */ | ||
749 | tmp = wl1271_read32(wl, SCR_PAD2); | ||
750 | |||
751 | /* WL1271: The reference driver skips steps 7 to 10 (jumps directly | ||
752 | * to upload_fw) */ | ||
753 | |||
754 | if (wl->chip.id == CHIP_ID_1283_PG20) | ||
755 | wl1271_top_reg_write(wl, SDIO_IO_DS, wl->conf.hci_io_ds); | ||
756 | |||
757 | ret = wl1271_boot_upload_firmware(wl); | ||
758 | if (ret < 0) | ||
759 | goto out; | ||
760 | |||
761 | out: | ||
762 | return ret; | ||
763 | } | ||
764 | EXPORT_SYMBOL_GPL(wl1271_load_firmware); | ||
765 | |||
766 | int wl1271_boot(struct wl1271 *wl) | ||
767 | { | ||
768 | int ret; | ||
769 | |||
770 | /* upload NVS and firmware */ | ||
771 | ret = wl1271_load_firmware(wl); | ||
772 | if (ret) | ||
773 | return ret; | ||
774 | |||
775 | /* 10.5 start firmware */ | ||
776 | ret = wl1271_boot_run_firmware(wl); | ||
777 | if (ret < 0) | ||
778 | goto out; | ||
779 | |||
780 | ret = wl1271_boot_write_irq_polarity(wl); | ||
781 | if (ret < 0) | ||
782 | goto out; | ||
783 | |||
784 | wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, | ||
785 | WL1271_ACX_ALL_EVENTS_VECTOR); | ||
786 | |||
787 | /* Enable firmware interrupts now */ | ||
788 | wl1271_boot_enable_interrupts(wl); | ||
789 | |||
790 | wl1271_event_mbox_config(wl); | ||
791 | |||
792 | out: | ||
793 | return ret; | ||
794 | } | ||
diff --git a/drivers/net/wireless/ti/wl12xx/boot.h b/drivers/net/wireless/ti/wl12xx/boot.h new file mode 100644 index 000000000000..c3adc09f403d --- /dev/null +++ b/drivers/net/wireless/ti/wl12xx/boot.h | |||
@@ -0,0 +1,120 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2008-2009 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 __BOOT_H__ | ||
25 | #define __BOOT_H__ | ||
26 | |||
27 | #include "wl12xx.h" | ||
28 | |||
29 | int wl1271_boot(struct wl1271 *wl); | ||
30 | int wl1271_load_firmware(struct wl1271 *wl); | ||
31 | |||
32 | #define WL1271_NO_SUBBANDS 8 | ||
33 | #define WL1271_NO_POWER_LEVELS 4 | ||
34 | #define WL1271_FW_VERSION_MAX_LEN 20 | ||
35 | |||
36 | struct wl1271_static_data { | ||
37 | u8 mac_address[ETH_ALEN]; | ||
38 | u8 padding[2]; | ||
39 | u8 fw_version[WL1271_FW_VERSION_MAX_LEN]; | ||
40 | u32 hw_version; | ||
41 | u8 tx_power_table[WL1271_NO_SUBBANDS][WL1271_NO_POWER_LEVELS]; | ||
42 | }; | ||
43 | |||
44 | /* number of times we try to read the INIT interrupt */ | ||
45 | #define INIT_LOOP 20000 | ||
46 | |||
47 | /* delay between retries */ | ||
48 | #define INIT_LOOP_DELAY 50 | ||
49 | |||
50 | #define WU_COUNTER_PAUSE_VAL 0x3FF | ||
51 | #define WELP_ARM_COMMAND_VAL 0x4 | ||
52 | |||
53 | #define OCP_REG_POLARITY 0x0064 | ||
54 | #define OCP_REG_CLK_TYPE 0x0448 | ||
55 | #define OCP_REG_CLK_POLARITY 0x0cb2 | ||
56 | #define OCP_REG_CLK_PULL 0x0cb4 | ||
57 | |||
58 | #define CMD_MBOX_ADDRESS 0x407B4 | ||
59 | |||
60 | #define POLARITY_LOW BIT(1) | ||
61 | #define NO_PULL (BIT(14) | BIT(15)) | ||
62 | |||
63 | #define FREF_CLK_TYPE_BITS 0xfffffe7f | ||
64 | #define CLK_REQ_PRCM 0x100 | ||
65 | #define FREF_CLK_POLARITY_BITS 0xfffff8ff | ||
66 | #define CLK_REQ_OUTN_SEL 0x700 | ||
67 | |||
68 | /* PLL configuration algorithm for wl128x */ | ||
69 | #define SYS_CLK_CFG_REG 0x2200 | ||
70 | /* Bit[0] - 0-TCXO, 1-FREF */ | ||
71 | #define MCS_PLL_CLK_SEL_FREF BIT(0) | ||
72 | /* Bit[3:2] - 01-TCXO, 10-FREF */ | ||
73 | #define WL_CLK_REQ_TYPE_FREF BIT(3) | ||
74 | #define WL_CLK_REQ_TYPE_PG2 (BIT(3) | BIT(2)) | ||
75 | /* Bit[4] - 0-TCXO, 1-FREF */ | ||
76 | #define PRCM_CM_EN_MUX_WLAN_FREF BIT(4) | ||
77 | |||
78 | #define TCXO_ILOAD_INT_REG 0x2264 | ||
79 | #define TCXO_CLK_DETECT_REG 0x2266 | ||
80 | |||
81 | #define TCXO_DET_FAILED BIT(4) | ||
82 | |||
83 | #define FREF_ILOAD_INT_REG 0x2084 | ||
84 | #define FREF_CLK_DETECT_REG 0x2086 | ||
85 | #define FREF_CLK_DETECT_FAIL BIT(4) | ||
86 | |||
87 | /* Use this reg for masking during driver access */ | ||
88 | #define WL_SPARE_REG 0x2320 | ||
89 | #define WL_SPARE_VAL BIT(2) | ||
90 | /* Bit[6:5:3] - mask wl write SYS_CLK_CFG[8:5:2:4] */ | ||
91 | #define WL_SPARE_MASK_8526 (BIT(6) | BIT(5) | BIT(3)) | ||
92 | |||
93 | #define PLL_LOCK_COUNTERS_REG 0xD8C | ||
94 | #define PLL_LOCK_COUNTERS_COEX 0x0F | ||
95 | #define PLL_LOCK_COUNTERS_MCS 0xF0 | ||
96 | #define MCS_PLL_OVERRIDE_REG 0xD90 | ||
97 | #define MCS_PLL_CONFIG_REG 0xD92 | ||
98 | #define MCS_SEL_IN_FREQ_MASK 0x0070 | ||
99 | #define MCS_SEL_IN_FREQ_SHIFT 4 | ||
100 | #define MCS_PLL_CONFIG_REG_VAL 0x73 | ||
101 | #define MCS_PLL_ENABLE_HP (BIT(0) | BIT(1)) | ||
102 | |||
103 | #define MCS_PLL_M_REG 0xD94 | ||
104 | #define MCS_PLL_N_REG 0xD96 | ||
105 | #define MCS_PLL_M_REG_VAL 0xC8 | ||
106 | #define MCS_PLL_N_REG_VAL 0x07 | ||
107 | |||
108 | #define SDIO_IO_DS 0xd14 | ||
109 | |||
110 | /* SDIO/wSPI DS configuration values */ | ||
111 | enum { | ||
112 | HCI_IO_DS_8MA = 0, | ||
113 | HCI_IO_DS_4MA = 1, /* default */ | ||
114 | HCI_IO_DS_6MA = 2, | ||
115 | HCI_IO_DS_2MA = 3, | ||
116 | }; | ||
117 | |||
118 | /* end PLL configuration algorithm for wl128x */ | ||
119 | |||
120 | #endif | ||
diff --git a/drivers/net/wireless/ti/wl12xx/cmd.c b/drivers/net/wireless/ti/wl12xx/cmd.c new file mode 100644 index 000000000000..82cb90a4a99c --- /dev/null +++ b/drivers/net/wireless/ti/wl12xx/cmd.c | |||
@@ -0,0 +1,1950 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2009-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 | #include <linux/module.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/spi/spi.h> | ||
27 | #include <linux/etherdevice.h> | ||
28 | #include <linux/ieee80211.h> | ||
29 | #include <linux/slab.h> | ||
30 | |||
31 | #include "wl12xx.h" | ||
32 | #include "debug.h" | ||
33 | #include "reg.h" | ||
34 | #include "io.h" | ||
35 | #include "acx.h" | ||
36 | #include "wl12xx_80211.h" | ||
37 | #include "cmd.h" | ||
38 | #include "event.h" | ||
39 | #include "tx.h" | ||
40 | |||
41 | #define WL1271_CMD_FAST_POLL_COUNT 50 | ||
42 | |||
43 | /* | ||
44 | * send command to firmware | ||
45 | * | ||
46 | * @wl: wl struct | ||
47 | * @id: command id | ||
48 | * @buf: buffer containing the command, must work with dma | ||
49 | * @len: length of the buffer | ||
50 | */ | ||
51 | int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, | ||
52 | size_t res_len) | ||
53 | { | ||
54 | struct wl1271_cmd_header *cmd; | ||
55 | unsigned long timeout; | ||
56 | u32 intr; | ||
57 | int ret = 0; | ||
58 | u16 status; | ||
59 | u16 poll_count = 0; | ||
60 | |||
61 | cmd = buf; | ||
62 | cmd->id = cpu_to_le16(id); | ||
63 | cmd->status = 0; | ||
64 | |||
65 | WARN_ON(len % 4 != 0); | ||
66 | WARN_ON(test_bit(WL1271_FLAG_IN_ELP, &wl->flags)); | ||
67 | |||
68 | wl1271_write(wl, wl->cmd_box_addr, buf, len, false); | ||
69 | |||
70 | wl1271_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); | ||
71 | |||
72 | timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT); | ||
73 | |||
74 | intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); | ||
75 | while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) { | ||
76 | if (time_after(jiffies, timeout)) { | ||
77 | wl1271_error("command complete timeout"); | ||
78 | ret = -ETIMEDOUT; | ||
79 | goto fail; | ||
80 | } | ||
81 | |||
82 | poll_count++; | ||
83 | if (poll_count < WL1271_CMD_FAST_POLL_COUNT) | ||
84 | udelay(10); | ||
85 | else | ||
86 | msleep(1); | ||
87 | |||
88 | intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); | ||
89 | } | ||
90 | |||
91 | /* read back the status code of the command */ | ||
92 | if (res_len == 0) | ||
93 | res_len = sizeof(struct wl1271_cmd_header); | ||
94 | wl1271_read(wl, wl->cmd_box_addr, cmd, res_len, false); | ||
95 | |||
96 | status = le16_to_cpu(cmd->status); | ||
97 | if (status != CMD_STATUS_SUCCESS) { | ||
98 | wl1271_error("command execute failure %d", status); | ||
99 | ret = -EIO; | ||
100 | goto fail; | ||
101 | } | ||
102 | |||
103 | wl1271_write32(wl, ACX_REG_INTERRUPT_ACK, | ||
104 | WL1271_ACX_INTR_CMD_COMPLETE); | ||
105 | return 0; | ||
106 | |||
107 | fail: | ||
108 | WARN_ON(1); | ||
109 | wl12xx_queue_recovery_work(wl); | ||
110 | return ret; | ||
111 | } | ||
112 | |||
113 | int wl1271_cmd_general_parms(struct wl1271 *wl) | ||
114 | { | ||
115 | struct wl1271_general_parms_cmd *gen_parms; | ||
116 | struct wl1271_ini_general_params *gp = | ||
117 | &((struct wl1271_nvs_file *)wl->nvs)->general_params; | ||
118 | bool answer = false; | ||
119 | int ret; | ||
120 | |||
121 | if (!wl->nvs) | ||
122 | return -ENODEV; | ||
123 | |||
124 | if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) { | ||
125 | wl1271_warning("FEM index from INI out of bounds"); | ||
126 | return -EINVAL; | ||
127 | } | ||
128 | |||
129 | gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL); | ||
130 | if (!gen_parms) | ||
131 | return -ENOMEM; | ||
132 | |||
133 | gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM; | ||
134 | |||
135 | memcpy(&gen_parms->general_params, gp, sizeof(*gp)); | ||
136 | |||
137 | if (gp->tx_bip_fem_auto_detect) | ||
138 | answer = true; | ||
139 | |||
140 | /* Override the REF CLK from the NVS with the one from platform data */ | ||
141 | gen_parms->general_params.ref_clock = wl->ref_clock; | ||
142 | |||
143 | ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer); | ||
144 | if (ret < 0) { | ||
145 | wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed"); | ||
146 | goto out; | ||
147 | } | ||
148 | |||
149 | gp->tx_bip_fem_manufacturer = | ||
150 | gen_parms->general_params.tx_bip_fem_manufacturer; | ||
151 | |||
152 | if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) { | ||
153 | wl1271_warning("FEM index from FW out of bounds"); | ||
154 | ret = -EINVAL; | ||
155 | goto out; | ||
156 | } | ||
157 | |||
158 | wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n", | ||
159 | answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer); | ||
160 | |||
161 | out: | ||
162 | kfree(gen_parms); | ||
163 | return ret; | ||
164 | } | ||
165 | |||
166 | int wl128x_cmd_general_parms(struct wl1271 *wl) | ||
167 | { | ||
168 | struct wl128x_general_parms_cmd *gen_parms; | ||
169 | struct wl128x_ini_general_params *gp = | ||
170 | &((struct wl128x_nvs_file *)wl->nvs)->general_params; | ||
171 | bool answer = false; | ||
172 | int ret; | ||
173 | |||
174 | if (!wl->nvs) | ||
175 | return -ENODEV; | ||
176 | |||
177 | if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) { | ||
178 | wl1271_warning("FEM index from ini out of bounds"); | ||
179 | return -EINVAL; | ||
180 | } | ||
181 | |||
182 | gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL); | ||
183 | if (!gen_parms) | ||
184 | return -ENOMEM; | ||
185 | |||
186 | gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM; | ||
187 | |||
188 | memcpy(&gen_parms->general_params, gp, sizeof(*gp)); | ||
189 | |||
190 | if (gp->tx_bip_fem_auto_detect) | ||
191 | answer = true; | ||
192 | |||
193 | /* Replace REF and TCXO CLKs with the ones from platform data */ | ||
194 | gen_parms->general_params.ref_clock = wl->ref_clock; | ||
195 | gen_parms->general_params.tcxo_ref_clock = wl->tcxo_clock; | ||
196 | |||
197 | ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer); | ||
198 | if (ret < 0) { | ||
199 | wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed"); | ||
200 | goto out; | ||
201 | } | ||
202 | |||
203 | gp->tx_bip_fem_manufacturer = | ||
204 | gen_parms->general_params.tx_bip_fem_manufacturer; | ||
205 | |||
206 | if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) { | ||
207 | wl1271_warning("FEM index from FW out of bounds"); | ||
208 | ret = -EINVAL; | ||
209 | goto out; | ||
210 | } | ||
211 | |||
212 | wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n", | ||
213 | answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer); | ||
214 | |||
215 | out: | ||
216 | kfree(gen_parms); | ||
217 | return ret; | ||
218 | } | ||
219 | |||
220 | int wl1271_cmd_radio_parms(struct wl1271 *wl) | ||
221 | { | ||
222 | struct wl1271_nvs_file *nvs = (struct wl1271_nvs_file *)wl->nvs; | ||
223 | struct wl1271_radio_parms_cmd *radio_parms; | ||
224 | struct wl1271_ini_general_params *gp = &nvs->general_params; | ||
225 | int ret; | ||
226 | |||
227 | if (!wl->nvs) | ||
228 | return -ENODEV; | ||
229 | |||
230 | radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL); | ||
231 | if (!radio_parms) | ||
232 | return -ENOMEM; | ||
233 | |||
234 | radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM; | ||
235 | |||
236 | /* 2.4GHz parameters */ | ||
237 | memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2, | ||
238 | sizeof(struct wl1271_ini_band_params_2)); | ||
239 | memcpy(&radio_parms->dyn_params_2, | ||
240 | &nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params, | ||
241 | sizeof(struct wl1271_ini_fem_params_2)); | ||
242 | |||
243 | /* 5GHz parameters */ | ||
244 | memcpy(&radio_parms->static_params_5, | ||
245 | &nvs->stat_radio_params_5, | ||
246 | sizeof(struct wl1271_ini_band_params_5)); | ||
247 | memcpy(&radio_parms->dyn_params_5, | ||
248 | &nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params, | ||
249 | sizeof(struct wl1271_ini_fem_params_5)); | ||
250 | |||
251 | wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ", | ||
252 | radio_parms, sizeof(*radio_parms)); | ||
253 | |||
254 | ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0); | ||
255 | if (ret < 0) | ||
256 | wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed"); | ||
257 | |||
258 | kfree(radio_parms); | ||
259 | return ret; | ||
260 | } | ||
261 | |||
262 | int wl128x_cmd_radio_parms(struct wl1271 *wl) | ||
263 | { | ||
264 | struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *)wl->nvs; | ||
265 | struct wl128x_radio_parms_cmd *radio_parms; | ||
266 | struct wl128x_ini_general_params *gp = &nvs->general_params; | ||
267 | int ret; | ||
268 | |||
269 | if (!wl->nvs) | ||
270 | return -ENODEV; | ||
271 | |||
272 | radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL); | ||
273 | if (!radio_parms) | ||
274 | return -ENOMEM; | ||
275 | |||
276 | radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM; | ||
277 | |||
278 | /* 2.4GHz parameters */ | ||
279 | memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2, | ||
280 | sizeof(struct wl128x_ini_band_params_2)); | ||
281 | memcpy(&radio_parms->dyn_params_2, | ||
282 | &nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params, | ||
283 | sizeof(struct wl128x_ini_fem_params_2)); | ||
284 | |||
285 | /* 5GHz parameters */ | ||
286 | memcpy(&radio_parms->static_params_5, | ||
287 | &nvs->stat_radio_params_5, | ||
288 | sizeof(struct wl128x_ini_band_params_5)); | ||
289 | memcpy(&radio_parms->dyn_params_5, | ||
290 | &nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params, | ||
291 | sizeof(struct wl128x_ini_fem_params_5)); | ||
292 | |||
293 | radio_parms->fem_vendor_and_options = nvs->fem_vendor_and_options; | ||
294 | |||
295 | wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ", | ||
296 | radio_parms, sizeof(*radio_parms)); | ||
297 | |||
298 | ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0); | ||
299 | if (ret < 0) | ||
300 | wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed"); | ||
301 | |||
302 | kfree(radio_parms); | ||
303 | return ret; | ||
304 | } | ||
305 | |||
306 | int wl1271_cmd_ext_radio_parms(struct wl1271 *wl) | ||
307 | { | ||
308 | struct wl1271_ext_radio_parms_cmd *ext_radio_parms; | ||
309 | struct conf_rf_settings *rf = &wl->conf.rf; | ||
310 | int ret; | ||
311 | |||
312 | if (!wl->nvs) | ||
313 | return -ENODEV; | ||
314 | |||
315 | ext_radio_parms = kzalloc(sizeof(*ext_radio_parms), GFP_KERNEL); | ||
316 | if (!ext_radio_parms) | ||
317 | return -ENOMEM; | ||
318 | |||
319 | ext_radio_parms->test.id = TEST_CMD_INI_FILE_RF_EXTENDED_PARAM; | ||
320 | |||
321 | memcpy(ext_radio_parms->tx_per_channel_power_compensation_2, | ||
322 | rf->tx_per_channel_power_compensation_2, | ||
323 | CONF_TX_PWR_COMPENSATION_LEN_2); | ||
324 | memcpy(ext_radio_parms->tx_per_channel_power_compensation_5, | ||
325 | rf->tx_per_channel_power_compensation_5, | ||
326 | CONF_TX_PWR_COMPENSATION_LEN_5); | ||
327 | |||
328 | wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_EXT_RADIO_PARAM: ", | ||
329 | ext_radio_parms, sizeof(*ext_radio_parms)); | ||
330 | |||
331 | ret = wl1271_cmd_test(wl, ext_radio_parms, sizeof(*ext_radio_parms), 0); | ||
332 | if (ret < 0) | ||
333 | wl1271_warning("TEST_CMD_INI_FILE_RF_EXTENDED_PARAM failed"); | ||
334 | |||
335 | kfree(ext_radio_parms); | ||
336 | return ret; | ||
337 | } | ||
338 | |||
339 | /* | ||
340 | * Poll the mailbox event field until any of the bits in the mask is set or a | ||
341 | * timeout occurs (WL1271_EVENT_TIMEOUT in msecs) | ||
342 | */ | ||
343 | static int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl, u32 mask) | ||
344 | { | ||
345 | u32 *events_vector; | ||
346 | u32 event; | ||
347 | unsigned long timeout; | ||
348 | int ret = 0; | ||
349 | |||
350 | events_vector = kmalloc(sizeof(*events_vector), GFP_DMA); | ||
351 | |||
352 | timeout = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT); | ||
353 | |||
354 | do { | ||
355 | if (time_after(jiffies, timeout)) { | ||
356 | wl1271_debug(DEBUG_CMD, "timeout waiting for event %d", | ||
357 | (int)mask); | ||
358 | ret = -ETIMEDOUT; | ||
359 | goto out; | ||
360 | } | ||
361 | |||
362 | msleep(1); | ||
363 | |||
364 | /* read from both event fields */ | ||
365 | wl1271_read(wl, wl->mbox_ptr[0], events_vector, | ||
366 | sizeof(*events_vector), false); | ||
367 | event = *events_vector & mask; | ||
368 | wl1271_read(wl, wl->mbox_ptr[1], events_vector, | ||
369 | sizeof(*events_vector), false); | ||
370 | event |= *events_vector & mask; | ||
371 | } while (!event); | ||
372 | |||
373 | out: | ||
374 | kfree(events_vector); | ||
375 | return ret; | ||
376 | } | ||
377 | |||
378 | static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask) | ||
379 | { | ||
380 | int ret; | ||
381 | |||
382 | ret = wl1271_cmd_wait_for_event_or_timeout(wl, mask); | ||
383 | if (ret != 0) { | ||
384 | wl12xx_queue_recovery_work(wl); | ||
385 | return ret; | ||
386 | } | ||
387 | |||
388 | return 0; | ||
389 | } | ||
390 | |||
391 | int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 *addr, u8 role_type, | ||
392 | u8 *role_id) | ||
393 | { | ||
394 | struct wl12xx_cmd_role_enable *cmd; | ||
395 | int ret; | ||
396 | |||
397 | wl1271_debug(DEBUG_CMD, "cmd role enable"); | ||
398 | |||
399 | if (WARN_ON(*role_id != WL12XX_INVALID_ROLE_ID)) | ||
400 | return -EBUSY; | ||
401 | |||
402 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
403 | if (!cmd) { | ||
404 | ret = -ENOMEM; | ||
405 | goto out; | ||
406 | } | ||
407 | |||
408 | /* get role id */ | ||
409 | cmd->role_id = find_first_zero_bit(wl->roles_map, WL12XX_MAX_ROLES); | ||
410 | if (cmd->role_id >= WL12XX_MAX_ROLES) { | ||
411 | ret = -EBUSY; | ||
412 | goto out_free; | ||
413 | } | ||
414 | |||
415 | memcpy(cmd->mac_address, addr, ETH_ALEN); | ||
416 | cmd->role_type = role_type; | ||
417 | |||
418 | ret = wl1271_cmd_send(wl, CMD_ROLE_ENABLE, cmd, sizeof(*cmd), 0); | ||
419 | if (ret < 0) { | ||
420 | wl1271_error("failed to initiate cmd role enable"); | ||
421 | goto out_free; | ||
422 | } | ||
423 | |||
424 | __set_bit(cmd->role_id, wl->roles_map); | ||
425 | *role_id = cmd->role_id; | ||
426 | |||
427 | out_free: | ||
428 | kfree(cmd); | ||
429 | |||
430 | out: | ||
431 | return ret; | ||
432 | } | ||
433 | |||
434 | int wl12xx_cmd_role_disable(struct wl1271 *wl, u8 *role_id) | ||
435 | { | ||
436 | struct wl12xx_cmd_role_disable *cmd; | ||
437 | int ret; | ||
438 | |||
439 | wl1271_debug(DEBUG_CMD, "cmd role disable"); | ||
440 | |||
441 | if (WARN_ON(*role_id == WL12XX_INVALID_ROLE_ID)) | ||
442 | return -ENOENT; | ||
443 | |||
444 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
445 | if (!cmd) { | ||
446 | ret = -ENOMEM; | ||
447 | goto out; | ||
448 | } | ||
449 | cmd->role_id = *role_id; | ||
450 | |||
451 | ret = wl1271_cmd_send(wl, CMD_ROLE_DISABLE, cmd, sizeof(*cmd), 0); | ||
452 | if (ret < 0) { | ||
453 | wl1271_error("failed to initiate cmd role disable"); | ||
454 | goto out_free; | ||
455 | } | ||
456 | |||
457 | __clear_bit(*role_id, wl->roles_map); | ||
458 | *role_id = WL12XX_INVALID_ROLE_ID; | ||
459 | |||
460 | out_free: | ||
461 | kfree(cmd); | ||
462 | |||
463 | out: | ||
464 | return ret; | ||
465 | } | ||
466 | |||
467 | int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid) | ||
468 | { | ||
469 | unsigned long flags; | ||
470 | u8 link = find_first_zero_bit(wl->links_map, WL12XX_MAX_LINKS); | ||
471 | if (link >= WL12XX_MAX_LINKS) | ||
472 | return -EBUSY; | ||
473 | |||
474 | /* these bits are used by op_tx */ | ||
475 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
476 | __set_bit(link, wl->links_map); | ||
477 | __set_bit(link, wlvif->links_map); | ||
478 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
479 | *hlid = link; | ||
480 | return 0; | ||
481 | } | ||
482 | |||
483 | void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid) | ||
484 | { | ||
485 | unsigned long flags; | ||
486 | |||
487 | if (*hlid == WL12XX_INVALID_LINK_ID) | ||
488 | return; | ||
489 | |||
490 | /* these bits are used by op_tx */ | ||
491 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
492 | __clear_bit(*hlid, wl->links_map); | ||
493 | __clear_bit(*hlid, wlvif->links_map); | ||
494 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
495 | |||
496 | /* | ||
497 | * At this point op_tx() will not add more packets to the queues. We | ||
498 | * can purge them. | ||
499 | */ | ||
500 | wl1271_tx_reset_link_queues(wl, *hlid); | ||
501 | |||
502 | *hlid = WL12XX_INVALID_LINK_ID; | ||
503 | } | ||
504 | |||
505 | static int wl12xx_get_new_session_id(struct wl1271 *wl, | ||
506 | struct wl12xx_vif *wlvif) | ||
507 | { | ||
508 | if (wlvif->session_counter >= SESSION_COUNTER_MAX) | ||
509 | wlvif->session_counter = 0; | ||
510 | |||
511 | wlvif->session_counter++; | ||
512 | |||
513 | return wlvif->session_counter; | ||
514 | } | ||
515 | |||
516 | static int wl12xx_cmd_role_start_dev(struct wl1271 *wl, | ||
517 | struct wl12xx_vif *wlvif) | ||
518 | { | ||
519 | struct wl12xx_cmd_role_start *cmd; | ||
520 | int ret; | ||
521 | |||
522 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
523 | if (!cmd) { | ||
524 | ret = -ENOMEM; | ||
525 | goto out; | ||
526 | } | ||
527 | |||
528 | wl1271_debug(DEBUG_CMD, "cmd role start dev %d", wlvif->dev_role_id); | ||
529 | |||
530 | cmd->role_id = wlvif->dev_role_id; | ||
531 | if (wlvif->band == IEEE80211_BAND_5GHZ) | ||
532 | cmd->band = WL12XX_BAND_5GHZ; | ||
533 | cmd->channel = wlvif->channel; | ||
534 | |||
535 | if (wlvif->dev_hlid == WL12XX_INVALID_LINK_ID) { | ||
536 | ret = wl12xx_allocate_link(wl, wlvif, &wlvif->dev_hlid); | ||
537 | if (ret) | ||
538 | goto out_free; | ||
539 | } | ||
540 | cmd->device.hlid = wlvif->dev_hlid; | ||
541 | cmd->device.session = wl12xx_get_new_session_id(wl, wlvif); | ||
542 | |||
543 | wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d", | ||
544 | cmd->role_id, cmd->device.hlid, cmd->device.session); | ||
545 | |||
546 | ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0); | ||
547 | if (ret < 0) { | ||
548 | wl1271_error("failed to initiate cmd role enable"); | ||
549 | goto err_hlid; | ||
550 | } | ||
551 | |||
552 | goto out_free; | ||
553 | |||
554 | err_hlid: | ||
555 | /* clear links on error */ | ||
556 | wl12xx_free_link(wl, wlvif, &wlvif->dev_hlid); | ||
557 | |||
558 | out_free: | ||
559 | kfree(cmd); | ||
560 | |||
561 | out: | ||
562 | return ret; | ||
563 | } | ||
564 | |||
565 | static int wl12xx_cmd_role_stop_dev(struct wl1271 *wl, | ||
566 | struct wl12xx_vif *wlvif) | ||
567 | { | ||
568 | struct wl12xx_cmd_role_stop *cmd; | ||
569 | int ret; | ||
570 | |||
571 | if (WARN_ON(wlvif->dev_hlid == WL12XX_INVALID_LINK_ID)) | ||
572 | return -EINVAL; | ||
573 | |||
574 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
575 | if (!cmd) { | ||
576 | ret = -ENOMEM; | ||
577 | goto out; | ||
578 | } | ||
579 | |||
580 | wl1271_debug(DEBUG_CMD, "cmd role stop dev"); | ||
581 | |||
582 | cmd->role_id = wlvif->dev_role_id; | ||
583 | cmd->disc_type = DISCONNECT_IMMEDIATE; | ||
584 | cmd->reason = cpu_to_le16(WLAN_REASON_UNSPECIFIED); | ||
585 | |||
586 | ret = wl1271_cmd_send(wl, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0); | ||
587 | if (ret < 0) { | ||
588 | wl1271_error("failed to initiate cmd role stop"); | ||
589 | goto out_free; | ||
590 | } | ||
591 | |||
592 | ret = wl1271_cmd_wait_for_event(wl, ROLE_STOP_COMPLETE_EVENT_ID); | ||
593 | if (ret < 0) { | ||
594 | wl1271_error("cmd role stop dev event completion error"); | ||
595 | goto out_free; | ||
596 | } | ||
597 | |||
598 | wl12xx_free_link(wl, wlvif, &wlvif->dev_hlid); | ||
599 | |||
600 | out_free: | ||
601 | kfree(cmd); | ||
602 | |||
603 | out: | ||
604 | return ret; | ||
605 | } | ||
606 | |||
607 | int wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif) | ||
608 | { | ||
609 | struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); | ||
610 | struct wl12xx_cmd_role_start *cmd; | ||
611 | int ret; | ||
612 | |||
613 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
614 | if (!cmd) { | ||
615 | ret = -ENOMEM; | ||
616 | goto out; | ||
617 | } | ||
618 | |||
619 | wl1271_debug(DEBUG_CMD, "cmd role start sta %d", wlvif->role_id); | ||
620 | |||
621 | cmd->role_id = wlvif->role_id; | ||
622 | if (wlvif->band == IEEE80211_BAND_5GHZ) | ||
623 | cmd->band = WL12XX_BAND_5GHZ; | ||
624 | cmd->channel = wlvif->channel; | ||
625 | cmd->sta.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set); | ||
626 | cmd->sta.beacon_interval = cpu_to_le16(wlvif->beacon_int); | ||
627 | cmd->sta.ssid_type = WL12XX_SSID_TYPE_ANY; | ||
628 | cmd->sta.ssid_len = wlvif->ssid_len; | ||
629 | memcpy(cmd->sta.ssid, wlvif->ssid, wlvif->ssid_len); | ||
630 | memcpy(cmd->sta.bssid, vif->bss_conf.bssid, ETH_ALEN); | ||
631 | cmd->sta.local_rates = cpu_to_le32(wlvif->rate_set); | ||
632 | |||
633 | if (wlvif->sta.hlid == WL12XX_INVALID_LINK_ID) { | ||
634 | ret = wl12xx_allocate_link(wl, wlvif, &wlvif->sta.hlid); | ||
635 | if (ret) | ||
636 | goto out_free; | ||
637 | } | ||
638 | cmd->sta.hlid = wlvif->sta.hlid; | ||
639 | cmd->sta.session = wl12xx_get_new_session_id(wl, wlvif); | ||
640 | cmd->sta.remote_rates = cpu_to_le32(wlvif->rate_set); | ||
641 | |||
642 | wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d " | ||
643 | "basic_rate_set: 0x%x, remote_rates: 0x%x", | ||
644 | wlvif->role_id, cmd->sta.hlid, cmd->sta.session, | ||
645 | wlvif->basic_rate_set, wlvif->rate_set); | ||
646 | |||
647 | ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0); | ||
648 | if (ret < 0) { | ||
649 | wl1271_error("failed to initiate cmd role start sta"); | ||
650 | goto err_hlid; | ||
651 | } | ||
652 | |||
653 | goto out_free; | ||
654 | |||
655 | err_hlid: | ||
656 | /* clear links on error. */ | ||
657 | wl12xx_free_link(wl, wlvif, &wlvif->sta.hlid); | ||
658 | |||
659 | out_free: | ||
660 | kfree(cmd); | ||
661 | |||
662 | out: | ||
663 | return ret; | ||
664 | } | ||
665 | |||
666 | /* use this function to stop ibss as well */ | ||
667 | int wl12xx_cmd_role_stop_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif) | ||
668 | { | ||
669 | struct wl12xx_cmd_role_stop *cmd; | ||
670 | int ret; | ||
671 | |||
672 | if (WARN_ON(wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)) | ||
673 | return -EINVAL; | ||
674 | |||
675 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
676 | if (!cmd) { | ||
677 | ret = -ENOMEM; | ||
678 | goto out; | ||
679 | } | ||
680 | |||
681 | wl1271_debug(DEBUG_CMD, "cmd role stop sta %d", wlvif->role_id); | ||
682 | |||
683 | cmd->role_id = wlvif->role_id; | ||
684 | cmd->disc_type = DISCONNECT_IMMEDIATE; | ||
685 | cmd->reason = cpu_to_le16(WLAN_REASON_UNSPECIFIED); | ||
686 | |||
687 | ret = wl1271_cmd_send(wl, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0); | ||
688 | if (ret < 0) { | ||
689 | wl1271_error("failed to initiate cmd role stop sta"); | ||
690 | goto out_free; | ||
691 | } | ||
692 | |||
693 | wl12xx_free_link(wl, wlvif, &wlvif->sta.hlid); | ||
694 | |||
695 | out_free: | ||
696 | kfree(cmd); | ||
697 | |||
698 | out: | ||
699 | return ret; | ||
700 | } | ||
701 | |||
702 | int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif) | ||
703 | { | ||
704 | struct wl12xx_cmd_role_start *cmd; | ||
705 | struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); | ||
706 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; | ||
707 | int ret; | ||
708 | |||
709 | wl1271_debug(DEBUG_CMD, "cmd role start ap %d", wlvif->role_id); | ||
710 | |||
711 | /* trying to use hidden SSID with an old hostapd version */ | ||
712 | if (wlvif->ssid_len == 0 && !bss_conf->hidden_ssid) { | ||
713 | wl1271_error("got a null SSID from beacon/bss"); | ||
714 | ret = -EINVAL; | ||
715 | goto out; | ||
716 | } | ||
717 | |||
718 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
719 | if (!cmd) { | ||
720 | ret = -ENOMEM; | ||
721 | goto out; | ||
722 | } | ||
723 | |||
724 | ret = wl12xx_allocate_link(wl, wlvif, &wlvif->ap.global_hlid); | ||
725 | if (ret < 0) | ||
726 | goto out_free; | ||
727 | |||
728 | ret = wl12xx_allocate_link(wl, wlvif, &wlvif->ap.bcast_hlid); | ||
729 | if (ret < 0) | ||
730 | goto out_free_global; | ||
731 | |||
732 | cmd->role_id = wlvif->role_id; | ||
733 | cmd->ap.aging_period = cpu_to_le16(wl->conf.tx.ap_aging_period); | ||
734 | cmd->ap.bss_index = WL1271_AP_BSS_INDEX; | ||
735 | cmd->ap.global_hlid = wlvif->ap.global_hlid; | ||
736 | cmd->ap.broadcast_hlid = wlvif->ap.bcast_hlid; | ||
737 | cmd->ap.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set); | ||
738 | cmd->ap.beacon_interval = cpu_to_le16(wlvif->beacon_int); | ||
739 | cmd->ap.dtim_interval = bss_conf->dtim_period; | ||
740 | cmd->ap.beacon_expiry = WL1271_AP_DEF_BEACON_EXP; | ||
741 | /* FIXME: Change when adding DFS */ | ||
742 | cmd->ap.reset_tsf = 1; /* By default reset AP TSF */ | ||
743 | cmd->channel = wlvif->channel; | ||
744 | |||
745 | if (!bss_conf->hidden_ssid) { | ||
746 | /* take the SSID from the beacon for backward compatibility */ | ||
747 | cmd->ap.ssid_type = WL12XX_SSID_TYPE_PUBLIC; | ||
748 | cmd->ap.ssid_len = wlvif->ssid_len; | ||
749 | memcpy(cmd->ap.ssid, wlvif->ssid, wlvif->ssid_len); | ||
750 | } else { | ||
751 | cmd->ap.ssid_type = WL12XX_SSID_TYPE_HIDDEN; | ||
752 | cmd->ap.ssid_len = bss_conf->ssid_len; | ||
753 | memcpy(cmd->ap.ssid, bss_conf->ssid, bss_conf->ssid_len); | ||
754 | } | ||
755 | |||
756 | cmd->ap.local_rates = cpu_to_le32(0xffffffff); | ||
757 | |||
758 | switch (wlvif->band) { | ||
759 | case IEEE80211_BAND_2GHZ: | ||
760 | cmd->band = RADIO_BAND_2_4GHZ; | ||
761 | break; | ||
762 | case IEEE80211_BAND_5GHZ: | ||
763 | cmd->band = RADIO_BAND_5GHZ; | ||
764 | break; | ||
765 | default: | ||
766 | wl1271_warning("ap start - unknown band: %d", (int)wlvif->band); | ||
767 | cmd->band = RADIO_BAND_2_4GHZ; | ||
768 | break; | ||
769 | } | ||
770 | |||
771 | ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0); | ||
772 | if (ret < 0) { | ||
773 | wl1271_error("failed to initiate cmd role start ap"); | ||
774 | goto out_free_bcast; | ||
775 | } | ||
776 | |||
777 | goto out_free; | ||
778 | |||
779 | out_free_bcast: | ||
780 | wl12xx_free_link(wl, wlvif, &wlvif->ap.bcast_hlid); | ||
781 | |||
782 | out_free_global: | ||
783 | wl12xx_free_link(wl, wlvif, &wlvif->ap.global_hlid); | ||
784 | |||
785 | out_free: | ||
786 | kfree(cmd); | ||
787 | |||
788 | out: | ||
789 | return ret; | ||
790 | } | ||
791 | |||
792 | int wl12xx_cmd_role_stop_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif) | ||
793 | { | ||
794 | struct wl12xx_cmd_role_stop *cmd; | ||
795 | int ret; | ||
796 | |||
797 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
798 | if (!cmd) { | ||
799 | ret = -ENOMEM; | ||
800 | goto out; | ||
801 | } | ||
802 | |||
803 | wl1271_debug(DEBUG_CMD, "cmd role stop ap %d", wlvif->role_id); | ||
804 | |||
805 | cmd->role_id = wlvif->role_id; | ||
806 | |||
807 | ret = wl1271_cmd_send(wl, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0); | ||
808 | if (ret < 0) { | ||
809 | wl1271_error("failed to initiate cmd role stop ap"); | ||
810 | goto out_free; | ||
811 | } | ||
812 | |||
813 | wl12xx_free_link(wl, wlvif, &wlvif->ap.bcast_hlid); | ||
814 | wl12xx_free_link(wl, wlvif, &wlvif->ap.global_hlid); | ||
815 | |||
816 | out_free: | ||
817 | kfree(cmd); | ||
818 | |||
819 | out: | ||
820 | return ret; | ||
821 | } | ||
822 | |||
823 | int wl12xx_cmd_role_start_ibss(struct wl1271 *wl, struct wl12xx_vif *wlvif) | ||
824 | { | ||
825 | struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); | ||
826 | struct wl12xx_cmd_role_start *cmd; | ||
827 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; | ||
828 | int ret; | ||
829 | |||
830 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
831 | if (!cmd) { | ||
832 | ret = -ENOMEM; | ||
833 | goto out; | ||
834 | } | ||
835 | |||
836 | wl1271_debug(DEBUG_CMD, "cmd role start ibss %d", wlvif->role_id); | ||
837 | |||
838 | cmd->role_id = wlvif->role_id; | ||
839 | if (wlvif->band == IEEE80211_BAND_5GHZ) | ||
840 | cmd->band = WL12XX_BAND_5GHZ; | ||
841 | cmd->channel = wlvif->channel; | ||
842 | cmd->ibss.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set); | ||
843 | cmd->ibss.beacon_interval = cpu_to_le16(wlvif->beacon_int); | ||
844 | cmd->ibss.dtim_interval = bss_conf->dtim_period; | ||
845 | cmd->ibss.ssid_type = WL12XX_SSID_TYPE_ANY; | ||
846 | cmd->ibss.ssid_len = wlvif->ssid_len; | ||
847 | memcpy(cmd->ibss.ssid, wlvif->ssid, wlvif->ssid_len); | ||
848 | memcpy(cmd->ibss.bssid, vif->bss_conf.bssid, ETH_ALEN); | ||
849 | cmd->sta.local_rates = cpu_to_le32(wlvif->rate_set); | ||
850 | |||
851 | if (wlvif->sta.hlid == WL12XX_INVALID_LINK_ID) { | ||
852 | ret = wl12xx_allocate_link(wl, wlvif, &wlvif->sta.hlid); | ||
853 | if (ret) | ||
854 | goto out_free; | ||
855 | } | ||
856 | cmd->ibss.hlid = wlvif->sta.hlid; | ||
857 | cmd->ibss.remote_rates = cpu_to_le32(wlvif->rate_set); | ||
858 | |||
859 | wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d " | ||
860 | "basic_rate_set: 0x%x, remote_rates: 0x%x", | ||
861 | wlvif->role_id, cmd->sta.hlid, cmd->sta.session, | ||
862 | wlvif->basic_rate_set, wlvif->rate_set); | ||
863 | |||
864 | wl1271_debug(DEBUG_CMD, "vif->bss_conf.bssid = %pM", | ||
865 | vif->bss_conf.bssid); | ||
866 | |||
867 | ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0); | ||
868 | if (ret < 0) { | ||
869 | wl1271_error("failed to initiate cmd role enable"); | ||
870 | goto err_hlid; | ||
871 | } | ||
872 | |||
873 | goto out_free; | ||
874 | |||
875 | err_hlid: | ||
876 | /* clear links on error. */ | ||
877 | wl12xx_free_link(wl, wlvif, &wlvif->sta.hlid); | ||
878 | |||
879 | out_free: | ||
880 | kfree(cmd); | ||
881 | |||
882 | out: | ||
883 | return ret; | ||
884 | } | ||
885 | |||
886 | |||
887 | /** | ||
888 | * send test command to firmware | ||
889 | * | ||
890 | * @wl: wl struct | ||
891 | * @buf: buffer containing the command, with all headers, must work with dma | ||
892 | * @len: length of the buffer | ||
893 | * @answer: is answer needed | ||
894 | */ | ||
895 | int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer) | ||
896 | { | ||
897 | int ret; | ||
898 | size_t res_len = 0; | ||
899 | |||
900 | wl1271_debug(DEBUG_CMD, "cmd test"); | ||
901 | |||
902 | if (answer) | ||
903 | res_len = buf_len; | ||
904 | |||
905 | ret = wl1271_cmd_send(wl, CMD_TEST, buf, buf_len, res_len); | ||
906 | |||
907 | if (ret < 0) { | ||
908 | wl1271_warning("TEST command failed"); | ||
909 | return ret; | ||
910 | } | ||
911 | |||
912 | return ret; | ||
913 | } | ||
914 | |||
915 | /** | ||
916 | * read acx from firmware | ||
917 | * | ||
918 | * @wl: wl struct | ||
919 | * @id: acx id | ||
920 | * @buf: buffer for the response, including all headers, must work with dma | ||
921 | * @len: length of buf | ||
922 | */ | ||
923 | int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len) | ||
924 | { | ||
925 | struct acx_header *acx = buf; | ||
926 | int ret; | ||
927 | |||
928 | wl1271_debug(DEBUG_CMD, "cmd interrogate"); | ||
929 | |||
930 | acx->id = cpu_to_le16(id); | ||
931 | |||
932 | /* payload length, does not include any headers */ | ||
933 | acx->len = cpu_to_le16(len - sizeof(*acx)); | ||
934 | |||
935 | ret = wl1271_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx), len); | ||
936 | if (ret < 0) | ||
937 | wl1271_error("INTERROGATE command failed"); | ||
938 | |||
939 | return ret; | ||
940 | } | ||
941 | |||
942 | /** | ||
943 | * write acx value to firmware | ||
944 | * | ||
945 | * @wl: wl struct | ||
946 | * @id: acx id | ||
947 | * @buf: buffer containing acx, including all headers, must work with dma | ||
948 | * @len: length of buf | ||
949 | */ | ||
950 | int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len) | ||
951 | { | ||
952 | struct acx_header *acx = buf; | ||
953 | int ret; | ||
954 | |||
955 | wl1271_debug(DEBUG_CMD, "cmd configure (%d)", id); | ||
956 | |||
957 | acx->id = cpu_to_le16(id); | ||
958 | |||
959 | /* payload length, does not include any headers */ | ||
960 | acx->len = cpu_to_le16(len - sizeof(*acx)); | ||
961 | |||
962 | ret = wl1271_cmd_send(wl, CMD_CONFIGURE, acx, len, 0); | ||
963 | if (ret < 0) { | ||
964 | wl1271_warning("CONFIGURE command NOK"); | ||
965 | return ret; | ||
966 | } | ||
967 | |||
968 | return 0; | ||
969 | } | ||
970 | |||
971 | int wl1271_cmd_data_path(struct wl1271 *wl, bool enable) | ||
972 | { | ||
973 | struct cmd_enabledisable_path *cmd; | ||
974 | int ret; | ||
975 | u16 cmd_rx, cmd_tx; | ||
976 | |||
977 | wl1271_debug(DEBUG_CMD, "cmd data path"); | ||
978 | |||
979 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
980 | if (!cmd) { | ||
981 | ret = -ENOMEM; | ||
982 | goto out; | ||
983 | } | ||
984 | |||
985 | /* the channel here is only used for calibration, so hardcoded to 1 */ | ||
986 | cmd->channel = 1; | ||
987 | |||
988 | if (enable) { | ||
989 | cmd_rx = CMD_ENABLE_RX; | ||
990 | cmd_tx = CMD_ENABLE_TX; | ||
991 | } else { | ||
992 | cmd_rx = CMD_DISABLE_RX; | ||
993 | cmd_tx = CMD_DISABLE_TX; | ||
994 | } | ||
995 | |||
996 | ret = wl1271_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd), 0); | ||
997 | if (ret < 0) { | ||
998 | wl1271_error("rx %s cmd for channel %d failed", | ||
999 | enable ? "start" : "stop", cmd->channel); | ||
1000 | goto out; | ||
1001 | } | ||
1002 | |||
1003 | wl1271_debug(DEBUG_BOOT, "rx %s cmd channel %d", | ||
1004 | enable ? "start" : "stop", cmd->channel); | ||
1005 | |||
1006 | ret = wl1271_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd), 0); | ||
1007 | if (ret < 0) { | ||
1008 | wl1271_error("tx %s cmd for channel %d failed", | ||
1009 | enable ? "start" : "stop", cmd->channel); | ||
1010 | goto out; | ||
1011 | } | ||
1012 | |||
1013 | wl1271_debug(DEBUG_BOOT, "tx %s cmd channel %d", | ||
1014 | enable ? "start" : "stop", cmd->channel); | ||
1015 | |||
1016 | out: | ||
1017 | kfree(cmd); | ||
1018 | return ret; | ||
1019 | } | ||
1020 | |||
1021 | int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
1022 | u8 ps_mode, u16 auto_ps_timeout) | ||
1023 | { | ||
1024 | struct wl1271_cmd_ps_params *ps_params = NULL; | ||
1025 | int ret = 0; | ||
1026 | |||
1027 | wl1271_debug(DEBUG_CMD, "cmd set ps mode"); | ||
1028 | |||
1029 | ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL); | ||
1030 | if (!ps_params) { | ||
1031 | ret = -ENOMEM; | ||
1032 | goto out; | ||
1033 | } | ||
1034 | |||
1035 | ps_params->role_id = wlvif->role_id; | ||
1036 | ps_params->ps_mode = ps_mode; | ||
1037 | ps_params->auto_ps_timeout = auto_ps_timeout; | ||
1038 | |||
1039 | ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params, | ||
1040 | sizeof(*ps_params), 0); | ||
1041 | if (ret < 0) { | ||
1042 | wl1271_error("cmd set_ps_mode failed"); | ||
1043 | goto out; | ||
1044 | } | ||
1045 | |||
1046 | out: | ||
1047 | kfree(ps_params); | ||
1048 | return ret; | ||
1049 | } | ||
1050 | |||
1051 | int wl1271_cmd_template_set(struct wl1271 *wl, u8 role_id, | ||
1052 | u16 template_id, void *buf, size_t buf_len, | ||
1053 | int index, u32 rates) | ||
1054 | { | ||
1055 | struct wl1271_cmd_template_set *cmd; | ||
1056 | int ret = 0; | ||
1057 | |||
1058 | wl1271_debug(DEBUG_CMD, "cmd template_set %d (role %d)", | ||
1059 | template_id, role_id); | ||
1060 | |||
1061 | WARN_ON(buf_len > WL1271_CMD_TEMPL_MAX_SIZE); | ||
1062 | buf_len = min_t(size_t, buf_len, WL1271_CMD_TEMPL_MAX_SIZE); | ||
1063 | |||
1064 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
1065 | if (!cmd) { | ||
1066 | ret = -ENOMEM; | ||
1067 | goto out; | ||
1068 | } | ||
1069 | |||
1070 | /* during initialization wlvif is NULL */ | ||
1071 | cmd->role_id = role_id; | ||
1072 | cmd->len = cpu_to_le16(buf_len); | ||
1073 | cmd->template_type = template_id; | ||
1074 | cmd->enabled_rates = cpu_to_le32(rates); | ||
1075 | cmd->short_retry_limit = wl->conf.tx.tmpl_short_retry_limit; | ||
1076 | cmd->long_retry_limit = wl->conf.tx.tmpl_long_retry_limit; | ||
1077 | cmd->index = index; | ||
1078 | |||
1079 | if (buf) | ||
1080 | memcpy(cmd->template_data, buf, buf_len); | ||
1081 | |||
1082 | ret = wl1271_cmd_send(wl, CMD_SET_TEMPLATE, cmd, sizeof(*cmd), 0); | ||
1083 | if (ret < 0) { | ||
1084 | wl1271_warning("cmd set_template failed: %d", ret); | ||
1085 | goto out_free; | ||
1086 | } | ||
1087 | |||
1088 | out_free: | ||
1089 | kfree(cmd); | ||
1090 | |||
1091 | out: | ||
1092 | return ret; | ||
1093 | } | ||
1094 | |||
1095 | int wl12xx_cmd_build_null_data(struct wl1271 *wl, struct wl12xx_vif *wlvif) | ||
1096 | { | ||
1097 | struct sk_buff *skb = NULL; | ||
1098 | int size; | ||
1099 | void *ptr; | ||
1100 | int ret = -ENOMEM; | ||
1101 | |||
1102 | |||
1103 | if (wlvif->bss_type == BSS_TYPE_IBSS) { | ||
1104 | size = sizeof(struct wl12xx_null_data_template); | ||
1105 | ptr = NULL; | ||
1106 | } else { | ||
1107 | skb = ieee80211_nullfunc_get(wl->hw, | ||
1108 | wl12xx_wlvif_to_vif(wlvif)); | ||
1109 | if (!skb) | ||
1110 | goto out; | ||
1111 | size = skb->len; | ||
1112 | ptr = skb->data; | ||
1113 | } | ||
1114 | |||
1115 | ret = wl1271_cmd_template_set(wl, wlvif->role_id, | ||
1116 | CMD_TEMPL_NULL_DATA, ptr, size, 0, | ||
1117 | wlvif->basic_rate); | ||
1118 | |||
1119 | out: | ||
1120 | dev_kfree_skb(skb); | ||
1121 | if (ret) | ||
1122 | wl1271_warning("cmd buld null data failed %d", ret); | ||
1123 | |||
1124 | return ret; | ||
1125 | |||
1126 | } | ||
1127 | |||
1128 | int wl12xx_cmd_build_klv_null_data(struct wl1271 *wl, | ||
1129 | struct wl12xx_vif *wlvif) | ||
1130 | { | ||
1131 | struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); | ||
1132 | struct sk_buff *skb = NULL; | ||
1133 | int ret = -ENOMEM; | ||
1134 | |||
1135 | skb = ieee80211_nullfunc_get(wl->hw, vif); | ||
1136 | if (!skb) | ||
1137 | goto out; | ||
1138 | |||
1139 | ret = wl1271_cmd_template_set(wl, wlvif->role_id, CMD_TEMPL_KLV, | ||
1140 | skb->data, skb->len, | ||
1141 | CMD_TEMPL_KLV_IDX_NULL_DATA, | ||
1142 | wlvif->basic_rate); | ||
1143 | |||
1144 | out: | ||
1145 | dev_kfree_skb(skb); | ||
1146 | if (ret) | ||
1147 | wl1271_warning("cmd build klv null data failed %d", ret); | ||
1148 | |||
1149 | return ret; | ||
1150 | |||
1151 | } | ||
1152 | |||
1153 | int wl1271_cmd_build_ps_poll(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
1154 | u16 aid) | ||
1155 | { | ||
1156 | struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); | ||
1157 | struct sk_buff *skb; | ||
1158 | int ret = 0; | ||
1159 | |||
1160 | skb = ieee80211_pspoll_get(wl->hw, vif); | ||
1161 | if (!skb) | ||
1162 | goto out; | ||
1163 | |||
1164 | ret = wl1271_cmd_template_set(wl, wlvif->role_id, | ||
1165 | CMD_TEMPL_PS_POLL, skb->data, | ||
1166 | skb->len, 0, wlvif->basic_rate_set); | ||
1167 | |||
1168 | out: | ||
1169 | dev_kfree_skb(skb); | ||
1170 | return ret; | ||
1171 | } | ||
1172 | |||
1173 | int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
1174 | u8 role_id, u8 band, | ||
1175 | const u8 *ssid, size_t ssid_len, | ||
1176 | const u8 *ie, size_t ie_len) | ||
1177 | { | ||
1178 | struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); | ||
1179 | struct sk_buff *skb; | ||
1180 | int ret; | ||
1181 | u32 rate; | ||
1182 | |||
1183 | skb = ieee80211_probereq_get(wl->hw, vif, ssid, ssid_len, | ||
1184 | ie, ie_len); | ||
1185 | if (!skb) { | ||
1186 | ret = -ENOMEM; | ||
1187 | goto out; | ||
1188 | } | ||
1189 | |||
1190 | wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", skb->data, skb->len); | ||
1191 | |||
1192 | rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]); | ||
1193 | if (band == IEEE80211_BAND_2GHZ) | ||
1194 | ret = wl1271_cmd_template_set(wl, role_id, | ||
1195 | CMD_TEMPL_CFG_PROBE_REQ_2_4, | ||
1196 | skb->data, skb->len, 0, rate); | ||
1197 | else | ||
1198 | ret = wl1271_cmd_template_set(wl, role_id, | ||
1199 | CMD_TEMPL_CFG_PROBE_REQ_5, | ||
1200 | skb->data, skb->len, 0, rate); | ||
1201 | |||
1202 | out: | ||
1203 | dev_kfree_skb(skb); | ||
1204 | return ret; | ||
1205 | } | ||
1206 | |||
1207 | struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, | ||
1208 | struct wl12xx_vif *wlvif, | ||
1209 | struct sk_buff *skb) | ||
1210 | { | ||
1211 | struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); | ||
1212 | int ret; | ||
1213 | u32 rate; | ||
1214 | |||
1215 | if (!skb) | ||
1216 | skb = ieee80211_ap_probereq_get(wl->hw, vif); | ||
1217 | if (!skb) | ||
1218 | goto out; | ||
1219 | |||
1220 | wl1271_dump(DEBUG_SCAN, "AP PROBE REQ: ", skb->data, skb->len); | ||
1221 | |||
1222 | rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[wlvif->band]); | ||
1223 | if (wlvif->band == IEEE80211_BAND_2GHZ) | ||
1224 | ret = wl1271_cmd_template_set(wl, wlvif->role_id, | ||
1225 | CMD_TEMPL_CFG_PROBE_REQ_2_4, | ||
1226 | skb->data, skb->len, 0, rate); | ||
1227 | else | ||
1228 | ret = wl1271_cmd_template_set(wl, wlvif->role_id, | ||
1229 | CMD_TEMPL_CFG_PROBE_REQ_5, | ||
1230 | skb->data, skb->len, 0, rate); | ||
1231 | |||
1232 | if (ret < 0) | ||
1233 | wl1271_error("Unable to set ap probe request template."); | ||
1234 | |||
1235 | out: | ||
1236 | return skb; | ||
1237 | } | ||
1238 | |||
1239 | int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif) | ||
1240 | { | ||
1241 | int ret, extra; | ||
1242 | u16 fc; | ||
1243 | struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); | ||
1244 | struct sk_buff *skb; | ||
1245 | struct wl12xx_arp_rsp_template *tmpl; | ||
1246 | struct ieee80211_hdr_3addr *hdr; | ||
1247 | struct arphdr *arp_hdr; | ||
1248 | |||
1249 | skb = dev_alloc_skb(sizeof(*hdr) + sizeof(__le16) + sizeof(*tmpl) + | ||
1250 | WL1271_EXTRA_SPACE_MAX); | ||
1251 | if (!skb) { | ||
1252 | wl1271_error("failed to allocate buffer for arp rsp template"); | ||
1253 | return -ENOMEM; | ||
1254 | } | ||
1255 | |||
1256 | skb_reserve(skb, sizeof(*hdr) + WL1271_EXTRA_SPACE_MAX); | ||
1257 | |||
1258 | tmpl = (struct wl12xx_arp_rsp_template *)skb_put(skb, sizeof(*tmpl)); | ||
1259 | memset(tmpl, 0, sizeof(tmpl)); | ||
1260 | |||
1261 | /* llc layer */ | ||
1262 | memcpy(tmpl->llc_hdr, rfc1042_header, sizeof(rfc1042_header)); | ||
1263 | tmpl->llc_type = cpu_to_be16(ETH_P_ARP); | ||
1264 | |||
1265 | /* arp header */ | ||
1266 | arp_hdr = &tmpl->arp_hdr; | ||
1267 | arp_hdr->ar_hrd = cpu_to_be16(ARPHRD_ETHER); | ||
1268 | arp_hdr->ar_pro = cpu_to_be16(ETH_P_IP); | ||
1269 | arp_hdr->ar_hln = ETH_ALEN; | ||
1270 | arp_hdr->ar_pln = 4; | ||
1271 | arp_hdr->ar_op = cpu_to_be16(ARPOP_REPLY); | ||
1272 | |||
1273 | /* arp payload */ | ||
1274 | memcpy(tmpl->sender_hw, vif->addr, ETH_ALEN); | ||
1275 | tmpl->sender_ip = wlvif->ip_addr; | ||
1276 | |||
1277 | /* encryption space */ | ||
1278 | switch (wlvif->encryption_type) { | ||
1279 | case KEY_TKIP: | ||
1280 | extra = WL1271_EXTRA_SPACE_TKIP; | ||
1281 | break; | ||
1282 | case KEY_AES: | ||
1283 | extra = WL1271_EXTRA_SPACE_AES; | ||
1284 | break; | ||
1285 | case KEY_NONE: | ||
1286 | case KEY_WEP: | ||
1287 | case KEY_GEM: | ||
1288 | extra = 0; | ||
1289 | break; | ||
1290 | default: | ||
1291 | wl1271_warning("Unknown encryption type: %d", | ||
1292 | wlvif->encryption_type); | ||
1293 | ret = -EINVAL; | ||
1294 | goto out; | ||
1295 | } | ||
1296 | |||
1297 | if (extra) { | ||
1298 | u8 *space = skb_push(skb, extra); | ||
1299 | memset(space, 0, extra); | ||
1300 | } | ||
1301 | |||
1302 | /* QoS header - BE */ | ||
1303 | if (wlvif->sta.qos) | ||
1304 | memset(skb_push(skb, sizeof(__le16)), 0, sizeof(__le16)); | ||
1305 | |||
1306 | /* mac80211 header */ | ||
1307 | hdr = (struct ieee80211_hdr_3addr *)skb_push(skb, sizeof(*hdr)); | ||
1308 | memset(hdr, 0, sizeof(hdr)); | ||
1309 | fc = IEEE80211_FTYPE_DATA | IEEE80211_FCTL_TODS; | ||
1310 | if (wlvif->sta.qos) | ||
1311 | fc |= IEEE80211_STYPE_QOS_DATA; | ||
1312 | else | ||
1313 | fc |= IEEE80211_STYPE_DATA; | ||
1314 | if (wlvif->encryption_type != KEY_NONE) | ||
1315 | fc |= IEEE80211_FCTL_PROTECTED; | ||
1316 | |||
1317 | hdr->frame_control = cpu_to_le16(fc); | ||
1318 | memcpy(hdr->addr1, vif->bss_conf.bssid, ETH_ALEN); | ||
1319 | memcpy(hdr->addr2, vif->addr, ETH_ALEN); | ||
1320 | memset(hdr->addr3, 0xff, ETH_ALEN); | ||
1321 | |||
1322 | ret = wl1271_cmd_template_set(wl, wlvif->role_id, CMD_TEMPL_ARP_RSP, | ||
1323 | skb->data, skb->len, 0, | ||
1324 | wlvif->basic_rate); | ||
1325 | out: | ||
1326 | dev_kfree_skb(skb); | ||
1327 | return ret; | ||
1328 | } | ||
1329 | |||
1330 | int wl1271_build_qos_null_data(struct wl1271 *wl, struct ieee80211_vif *vif) | ||
1331 | { | ||
1332 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | ||
1333 | struct ieee80211_qos_hdr template; | ||
1334 | |||
1335 | memset(&template, 0, sizeof(template)); | ||
1336 | |||
1337 | memcpy(template.addr1, vif->bss_conf.bssid, ETH_ALEN); | ||
1338 | memcpy(template.addr2, vif->addr, ETH_ALEN); | ||
1339 | memcpy(template.addr3, vif->bss_conf.bssid, ETH_ALEN); | ||
1340 | |||
1341 | template.frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | | ||
1342 | IEEE80211_STYPE_QOS_NULLFUNC | | ||
1343 | IEEE80211_FCTL_TODS); | ||
1344 | |||
1345 | /* FIXME: not sure what priority to use here */ | ||
1346 | template.qos_ctrl = cpu_to_le16(0); | ||
1347 | |||
1348 | return wl1271_cmd_template_set(wl, wlvif->role_id, | ||
1349 | CMD_TEMPL_QOS_NULL_DATA, &template, | ||
1350 | sizeof(template), 0, | ||
1351 | wlvif->basic_rate); | ||
1352 | } | ||
1353 | |||
1354 | int wl12xx_cmd_set_default_wep_key(struct wl1271 *wl, u8 id, u8 hlid) | ||
1355 | { | ||
1356 | struct wl1271_cmd_set_keys *cmd; | ||
1357 | int ret = 0; | ||
1358 | |||
1359 | wl1271_debug(DEBUG_CMD, "cmd set_default_wep_key %d", id); | ||
1360 | |||
1361 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
1362 | if (!cmd) { | ||
1363 | ret = -ENOMEM; | ||
1364 | goto out; | ||
1365 | } | ||
1366 | |||
1367 | cmd->hlid = hlid; | ||
1368 | cmd->key_id = id; | ||
1369 | cmd->lid_key_type = WEP_DEFAULT_LID_TYPE; | ||
1370 | cmd->key_action = cpu_to_le16(KEY_SET_ID); | ||
1371 | cmd->key_type = KEY_WEP; | ||
1372 | |||
1373 | ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0); | ||
1374 | if (ret < 0) { | ||
1375 | wl1271_warning("cmd set_default_wep_key failed: %d", ret); | ||
1376 | goto out; | ||
1377 | } | ||
1378 | |||
1379 | out: | ||
1380 | kfree(cmd); | ||
1381 | |||
1382 | return ret; | ||
1383 | } | ||
1384 | |||
1385 | int wl1271_cmd_set_sta_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
1386 | u16 action, u8 id, u8 key_type, | ||
1387 | u8 key_size, const u8 *key, const u8 *addr, | ||
1388 | u32 tx_seq_32, u16 tx_seq_16) | ||
1389 | { | ||
1390 | struct wl1271_cmd_set_keys *cmd; | ||
1391 | int ret = 0; | ||
1392 | |||
1393 | /* hlid might have already been deleted */ | ||
1394 | if (wlvif->sta.hlid == WL12XX_INVALID_LINK_ID) | ||
1395 | return 0; | ||
1396 | |||
1397 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
1398 | if (!cmd) { | ||
1399 | ret = -ENOMEM; | ||
1400 | goto out; | ||
1401 | } | ||
1402 | |||
1403 | cmd->hlid = wlvif->sta.hlid; | ||
1404 | |||
1405 | if (key_type == KEY_WEP) | ||
1406 | cmd->lid_key_type = WEP_DEFAULT_LID_TYPE; | ||
1407 | else if (is_broadcast_ether_addr(addr)) | ||
1408 | cmd->lid_key_type = BROADCAST_LID_TYPE; | ||
1409 | else | ||
1410 | cmd->lid_key_type = UNICAST_LID_TYPE; | ||
1411 | |||
1412 | cmd->key_action = cpu_to_le16(action); | ||
1413 | cmd->key_size = key_size; | ||
1414 | cmd->key_type = key_type; | ||
1415 | |||
1416 | cmd->ac_seq_num16[0] = cpu_to_le16(tx_seq_16); | ||
1417 | cmd->ac_seq_num32[0] = cpu_to_le32(tx_seq_32); | ||
1418 | |||
1419 | cmd->key_id = id; | ||
1420 | |||
1421 | if (key_type == KEY_TKIP) { | ||
1422 | /* | ||
1423 | * We get the key in the following form: | ||
1424 | * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes) | ||
1425 | * but the target is expecting: | ||
1426 | * TKIP - RX MIC - TX MIC | ||
1427 | */ | ||
1428 | memcpy(cmd->key, key, 16); | ||
1429 | memcpy(cmd->key + 16, key + 24, 8); | ||
1430 | memcpy(cmd->key + 24, key + 16, 8); | ||
1431 | |||
1432 | } else { | ||
1433 | memcpy(cmd->key, key, key_size); | ||
1434 | } | ||
1435 | |||
1436 | wl1271_dump(DEBUG_CRYPT, "TARGET KEY: ", cmd, sizeof(*cmd)); | ||
1437 | |||
1438 | ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0); | ||
1439 | if (ret < 0) { | ||
1440 | wl1271_warning("could not set keys"); | ||
1441 | goto out; | ||
1442 | } | ||
1443 | |||
1444 | out: | ||
1445 | kfree(cmd); | ||
1446 | |||
1447 | return ret; | ||
1448 | } | ||
1449 | |||
1450 | /* | ||
1451 | * TODO: merge with sta/ibss into 1 set_key function. | ||
1452 | * note there are slight diffs | ||
1453 | */ | ||
1454 | int wl1271_cmd_set_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
1455 | u16 action, u8 id, u8 key_type, | ||
1456 | u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32, | ||
1457 | u16 tx_seq_16) | ||
1458 | { | ||
1459 | struct wl1271_cmd_set_keys *cmd; | ||
1460 | int ret = 0; | ||
1461 | u8 lid_type; | ||
1462 | |||
1463 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
1464 | if (!cmd) | ||
1465 | return -ENOMEM; | ||
1466 | |||
1467 | if (hlid == wlvif->ap.bcast_hlid) { | ||
1468 | if (key_type == KEY_WEP) | ||
1469 | lid_type = WEP_DEFAULT_LID_TYPE; | ||
1470 | else | ||
1471 | lid_type = BROADCAST_LID_TYPE; | ||
1472 | } else { | ||
1473 | lid_type = UNICAST_LID_TYPE; | ||
1474 | } | ||
1475 | |||
1476 | wl1271_debug(DEBUG_CRYPT, "ap key action: %d id: %d lid: %d type: %d" | ||
1477 | " hlid: %d", (int)action, (int)id, (int)lid_type, | ||
1478 | (int)key_type, (int)hlid); | ||
1479 | |||
1480 | cmd->lid_key_type = lid_type; | ||
1481 | cmd->hlid = hlid; | ||
1482 | cmd->key_action = cpu_to_le16(action); | ||
1483 | cmd->key_size = key_size; | ||
1484 | cmd->key_type = key_type; | ||
1485 | cmd->key_id = id; | ||
1486 | cmd->ac_seq_num16[0] = cpu_to_le16(tx_seq_16); | ||
1487 | cmd->ac_seq_num32[0] = cpu_to_le32(tx_seq_32); | ||
1488 | |||
1489 | if (key_type == KEY_TKIP) { | ||
1490 | /* | ||
1491 | * We get the key in the following form: | ||
1492 | * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes) | ||
1493 | * but the target is expecting: | ||
1494 | * TKIP - RX MIC - TX MIC | ||
1495 | */ | ||
1496 | memcpy(cmd->key, key, 16); | ||
1497 | memcpy(cmd->key + 16, key + 24, 8); | ||
1498 | memcpy(cmd->key + 24, key + 16, 8); | ||
1499 | } else { | ||
1500 | memcpy(cmd->key, key, key_size); | ||
1501 | } | ||
1502 | |||
1503 | wl1271_dump(DEBUG_CRYPT, "TARGET AP KEY: ", cmd, sizeof(*cmd)); | ||
1504 | |||
1505 | ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0); | ||
1506 | if (ret < 0) { | ||
1507 | wl1271_warning("could not set ap keys"); | ||
1508 | goto out; | ||
1509 | } | ||
1510 | |||
1511 | out: | ||
1512 | kfree(cmd); | ||
1513 | return ret; | ||
1514 | } | ||
1515 | |||
1516 | int wl12xx_cmd_set_peer_state(struct wl1271 *wl, u8 hlid) | ||
1517 | { | ||
1518 | struct wl12xx_cmd_set_peer_state *cmd; | ||
1519 | int ret = 0; | ||
1520 | |||
1521 | wl1271_debug(DEBUG_CMD, "cmd set peer state (hlid=%d)", hlid); | ||
1522 | |||
1523 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
1524 | if (!cmd) { | ||
1525 | ret = -ENOMEM; | ||
1526 | goto out; | ||
1527 | } | ||
1528 | |||
1529 | cmd->hlid = hlid; | ||
1530 | cmd->state = WL1271_CMD_STA_STATE_CONNECTED; | ||
1531 | |||
1532 | ret = wl1271_cmd_send(wl, CMD_SET_PEER_STATE, cmd, sizeof(*cmd), 0); | ||
1533 | if (ret < 0) { | ||
1534 | wl1271_error("failed to send set peer state command"); | ||
1535 | goto out_free; | ||
1536 | } | ||
1537 | |||
1538 | out_free: | ||
1539 | kfree(cmd); | ||
1540 | |||
1541 | out: | ||
1542 | return ret; | ||
1543 | } | ||
1544 | |||
1545 | int wl12xx_cmd_add_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
1546 | struct ieee80211_sta *sta, u8 hlid) | ||
1547 | { | ||
1548 | struct wl12xx_cmd_add_peer *cmd; | ||
1549 | int i, ret; | ||
1550 | u32 sta_rates; | ||
1551 | |||
1552 | wl1271_debug(DEBUG_CMD, "cmd add peer %d", (int)hlid); | ||
1553 | |||
1554 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
1555 | if (!cmd) { | ||
1556 | ret = -ENOMEM; | ||
1557 | goto out; | ||
1558 | } | ||
1559 | |||
1560 | memcpy(cmd->addr, sta->addr, ETH_ALEN); | ||
1561 | cmd->bss_index = WL1271_AP_BSS_INDEX; | ||
1562 | cmd->aid = sta->aid; | ||
1563 | cmd->hlid = hlid; | ||
1564 | cmd->sp_len = sta->max_sp; | ||
1565 | cmd->wmm = sta->wme ? 1 : 0; | ||
1566 | |||
1567 | for (i = 0; i < NUM_ACCESS_CATEGORIES_COPY; i++) | ||
1568 | if (sta->wme && (sta->uapsd_queues & BIT(i))) | ||
1569 | cmd->psd_type[i] = WL1271_PSD_UPSD_TRIGGER; | ||
1570 | else | ||
1571 | cmd->psd_type[i] = WL1271_PSD_LEGACY; | ||
1572 | |||
1573 | sta_rates = sta->supp_rates[wlvif->band]; | ||
1574 | if (sta->ht_cap.ht_supported) | ||
1575 | sta_rates |= sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET; | ||
1576 | |||
1577 | cmd->supported_rates = | ||
1578 | cpu_to_le32(wl1271_tx_enabled_rates_get(wl, sta_rates, | ||
1579 | wlvif->band)); | ||
1580 | |||
1581 | wl1271_debug(DEBUG_CMD, "new peer rates=0x%x queues=0x%x", | ||
1582 | cmd->supported_rates, sta->uapsd_queues); | ||
1583 | |||
1584 | ret = wl1271_cmd_send(wl, CMD_ADD_PEER, cmd, sizeof(*cmd), 0); | ||
1585 | if (ret < 0) { | ||
1586 | wl1271_error("failed to initiate cmd add peer"); | ||
1587 | goto out_free; | ||
1588 | } | ||
1589 | |||
1590 | out_free: | ||
1591 | kfree(cmd); | ||
1592 | |||
1593 | out: | ||
1594 | return ret; | ||
1595 | } | ||
1596 | |||
1597 | int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid) | ||
1598 | { | ||
1599 | struct wl12xx_cmd_remove_peer *cmd; | ||
1600 | int ret; | ||
1601 | |||
1602 | wl1271_debug(DEBUG_CMD, "cmd remove peer %d", (int)hlid); | ||
1603 | |||
1604 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
1605 | if (!cmd) { | ||
1606 | ret = -ENOMEM; | ||
1607 | goto out; | ||
1608 | } | ||
1609 | |||
1610 | cmd->hlid = hlid; | ||
1611 | /* We never send a deauth, mac80211 is in charge of this */ | ||
1612 | cmd->reason_opcode = 0; | ||
1613 | cmd->send_deauth_flag = 0; | ||
1614 | |||
1615 | ret = wl1271_cmd_send(wl, CMD_REMOVE_PEER, cmd, sizeof(*cmd), 0); | ||
1616 | if (ret < 0) { | ||
1617 | wl1271_error("failed to initiate cmd remove peer"); | ||
1618 | goto out_free; | ||
1619 | } | ||
1620 | |||
1621 | /* | ||
1622 | * We are ok with a timeout here. The event is sometimes not sent | ||
1623 | * due to a firmware bug. | ||
1624 | */ | ||
1625 | wl1271_cmd_wait_for_event_or_timeout(wl, | ||
1626 | PEER_REMOVE_COMPLETE_EVENT_ID); | ||
1627 | |||
1628 | out_free: | ||
1629 | kfree(cmd); | ||
1630 | |||
1631 | out: | ||
1632 | return ret; | ||
1633 | } | ||
1634 | |||
1635 | int wl12xx_cmd_config_fwlog(struct wl1271 *wl) | ||
1636 | { | ||
1637 | struct wl12xx_cmd_config_fwlog *cmd; | ||
1638 | int ret = 0; | ||
1639 | |||
1640 | wl1271_debug(DEBUG_CMD, "cmd config firmware logger"); | ||
1641 | |||
1642 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
1643 | if (!cmd) { | ||
1644 | ret = -ENOMEM; | ||
1645 | goto out; | ||
1646 | } | ||
1647 | |||
1648 | cmd->logger_mode = wl->conf.fwlog.mode; | ||
1649 | cmd->log_severity = wl->conf.fwlog.severity; | ||
1650 | cmd->timestamp = wl->conf.fwlog.timestamp; | ||
1651 | cmd->output = wl->conf.fwlog.output; | ||
1652 | cmd->threshold = wl->conf.fwlog.threshold; | ||
1653 | |||
1654 | ret = wl1271_cmd_send(wl, CMD_CONFIG_FWLOGGER, cmd, sizeof(*cmd), 0); | ||
1655 | if (ret < 0) { | ||
1656 | wl1271_error("failed to send config firmware logger command"); | ||
1657 | goto out_free; | ||
1658 | } | ||
1659 | |||
1660 | out_free: | ||
1661 | kfree(cmd); | ||
1662 | |||
1663 | out: | ||
1664 | return ret; | ||
1665 | } | ||
1666 | |||
1667 | int wl12xx_cmd_start_fwlog(struct wl1271 *wl) | ||
1668 | { | ||
1669 | struct wl12xx_cmd_start_fwlog *cmd; | ||
1670 | int ret = 0; | ||
1671 | |||
1672 | wl1271_debug(DEBUG_CMD, "cmd start firmware logger"); | ||
1673 | |||
1674 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
1675 | if (!cmd) { | ||
1676 | ret = -ENOMEM; | ||
1677 | goto out; | ||
1678 | } | ||
1679 | |||
1680 | ret = wl1271_cmd_send(wl, CMD_START_FWLOGGER, cmd, sizeof(*cmd), 0); | ||
1681 | if (ret < 0) { | ||
1682 | wl1271_error("failed to send start firmware logger command"); | ||
1683 | goto out_free; | ||
1684 | } | ||
1685 | |||
1686 | out_free: | ||
1687 | kfree(cmd); | ||
1688 | |||
1689 | out: | ||
1690 | return ret; | ||
1691 | } | ||
1692 | |||
1693 | int wl12xx_cmd_stop_fwlog(struct wl1271 *wl) | ||
1694 | { | ||
1695 | struct wl12xx_cmd_stop_fwlog *cmd; | ||
1696 | int ret = 0; | ||
1697 | |||
1698 | wl1271_debug(DEBUG_CMD, "cmd stop firmware logger"); | ||
1699 | |||
1700 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
1701 | if (!cmd) { | ||
1702 | ret = -ENOMEM; | ||
1703 | goto out; | ||
1704 | } | ||
1705 | |||
1706 | ret = wl1271_cmd_send(wl, CMD_STOP_FWLOGGER, cmd, sizeof(*cmd), 0); | ||
1707 | if (ret < 0) { | ||
1708 | wl1271_error("failed to send stop firmware logger command"); | ||
1709 | goto out_free; | ||
1710 | } | ||
1711 | |||
1712 | out_free: | ||
1713 | kfree(cmd); | ||
1714 | |||
1715 | out: | ||
1716 | return ret; | ||
1717 | } | ||
1718 | |||
1719 | static int wl12xx_cmd_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
1720 | u8 role_id) | ||
1721 | { | ||
1722 | struct wl12xx_cmd_roc *cmd; | ||
1723 | int ret = 0; | ||
1724 | |||
1725 | wl1271_debug(DEBUG_CMD, "cmd roc %d (%d)", wlvif->channel, role_id); | ||
1726 | |||
1727 | if (WARN_ON(role_id == WL12XX_INVALID_ROLE_ID)) | ||
1728 | return -EINVAL; | ||
1729 | |||
1730 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
1731 | if (!cmd) { | ||
1732 | ret = -ENOMEM; | ||
1733 | goto out; | ||
1734 | } | ||
1735 | |||
1736 | cmd->role_id = role_id; | ||
1737 | cmd->channel = wlvif->channel; | ||
1738 | switch (wlvif->band) { | ||
1739 | case IEEE80211_BAND_2GHZ: | ||
1740 | cmd->band = RADIO_BAND_2_4GHZ; | ||
1741 | break; | ||
1742 | case IEEE80211_BAND_5GHZ: | ||
1743 | cmd->band = RADIO_BAND_5GHZ; | ||
1744 | break; | ||
1745 | default: | ||
1746 | wl1271_error("roc - unknown band: %d", (int)wlvif->band); | ||
1747 | ret = -EINVAL; | ||
1748 | goto out_free; | ||
1749 | } | ||
1750 | |||
1751 | |||
1752 | ret = wl1271_cmd_send(wl, CMD_REMAIN_ON_CHANNEL, cmd, sizeof(*cmd), 0); | ||
1753 | if (ret < 0) { | ||
1754 | wl1271_error("failed to send ROC command"); | ||
1755 | goto out_free; | ||
1756 | } | ||
1757 | |||
1758 | out_free: | ||
1759 | kfree(cmd); | ||
1760 | |||
1761 | out: | ||
1762 | return ret; | ||
1763 | } | ||
1764 | |||
1765 | static int wl12xx_cmd_croc(struct wl1271 *wl, u8 role_id) | ||
1766 | { | ||
1767 | struct wl12xx_cmd_croc *cmd; | ||
1768 | int ret = 0; | ||
1769 | |||
1770 | wl1271_debug(DEBUG_CMD, "cmd croc (%d)", role_id); | ||
1771 | |||
1772 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
1773 | if (!cmd) { | ||
1774 | ret = -ENOMEM; | ||
1775 | goto out; | ||
1776 | } | ||
1777 | cmd->role_id = role_id; | ||
1778 | |||
1779 | ret = wl1271_cmd_send(wl, CMD_CANCEL_REMAIN_ON_CHANNEL, cmd, | ||
1780 | sizeof(*cmd), 0); | ||
1781 | if (ret < 0) { | ||
1782 | wl1271_error("failed to send ROC command"); | ||
1783 | goto out_free; | ||
1784 | } | ||
1785 | |||
1786 | out_free: | ||
1787 | kfree(cmd); | ||
1788 | |||
1789 | out: | ||
1790 | return ret; | ||
1791 | } | ||
1792 | |||
1793 | int wl12xx_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id) | ||
1794 | { | ||
1795 | int ret = 0; | ||
1796 | |||
1797 | if (WARN_ON(test_bit(role_id, wl->roc_map))) | ||
1798 | return 0; | ||
1799 | |||
1800 | ret = wl12xx_cmd_roc(wl, wlvif, role_id); | ||
1801 | if (ret < 0) | ||
1802 | goto out; | ||
1803 | |||
1804 | ret = wl1271_cmd_wait_for_event(wl, | ||
1805 | REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID); | ||
1806 | if (ret < 0) { | ||
1807 | wl1271_error("cmd roc event completion error"); | ||
1808 | goto out; | ||
1809 | } | ||
1810 | |||
1811 | __set_bit(role_id, wl->roc_map); | ||
1812 | out: | ||
1813 | return ret; | ||
1814 | } | ||
1815 | |||
1816 | int wl12xx_croc(struct wl1271 *wl, u8 role_id) | ||
1817 | { | ||
1818 | int ret = 0; | ||
1819 | |||
1820 | if (WARN_ON(!test_bit(role_id, wl->roc_map))) | ||
1821 | return 0; | ||
1822 | |||
1823 | ret = wl12xx_cmd_croc(wl, role_id); | ||
1824 | if (ret < 0) | ||
1825 | goto out; | ||
1826 | |||
1827 | __clear_bit(role_id, wl->roc_map); | ||
1828 | |||
1829 | /* | ||
1830 | * Rearm the tx watchdog when removing the last ROC. This prevents | ||
1831 | * recoveries due to just finished ROCs - when Tx hasn't yet had | ||
1832 | * a chance to get out. | ||
1833 | */ | ||
1834 | if (find_first_bit(wl->roc_map, WL12XX_MAX_ROLES) >= WL12XX_MAX_ROLES) | ||
1835 | wl12xx_rearm_tx_watchdog_locked(wl); | ||
1836 | out: | ||
1837 | return ret; | ||
1838 | } | ||
1839 | |||
1840 | int wl12xx_cmd_channel_switch(struct wl1271 *wl, | ||
1841 | struct wl12xx_vif *wlvif, | ||
1842 | struct ieee80211_channel_switch *ch_switch) | ||
1843 | { | ||
1844 | struct wl12xx_cmd_channel_switch *cmd; | ||
1845 | int ret; | ||
1846 | |||
1847 | wl1271_debug(DEBUG_ACX, "cmd channel switch"); | ||
1848 | |||
1849 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
1850 | if (!cmd) { | ||
1851 | ret = -ENOMEM; | ||
1852 | goto out; | ||
1853 | } | ||
1854 | |||
1855 | cmd->role_id = wlvif->role_id; | ||
1856 | cmd->channel = ch_switch->channel->hw_value; | ||
1857 | cmd->switch_time = ch_switch->count; | ||
1858 | cmd->stop_tx = ch_switch->block_tx; | ||
1859 | |||
1860 | /* FIXME: control from mac80211 in the future */ | ||
1861 | cmd->post_switch_tx_disable = 0; /* Enable TX on the target channel */ | ||
1862 | |||
1863 | ret = wl1271_cmd_send(wl, CMD_CHANNEL_SWITCH, cmd, sizeof(*cmd), 0); | ||
1864 | if (ret < 0) { | ||
1865 | wl1271_error("failed to send channel switch command"); | ||
1866 | goto out_free; | ||
1867 | } | ||
1868 | |||
1869 | out_free: | ||
1870 | kfree(cmd); | ||
1871 | |||
1872 | out: | ||
1873 | return ret; | ||
1874 | } | ||
1875 | |||
1876 | int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl) | ||
1877 | { | ||
1878 | struct wl12xx_cmd_stop_channel_switch *cmd; | ||
1879 | int ret; | ||
1880 | |||
1881 | wl1271_debug(DEBUG_ACX, "cmd stop channel switch"); | ||
1882 | |||
1883 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
1884 | if (!cmd) { | ||
1885 | ret = -ENOMEM; | ||
1886 | goto out; | ||
1887 | } | ||
1888 | |||
1889 | ret = wl1271_cmd_send(wl, CMD_STOP_CHANNEL_SWICTH, cmd, sizeof(*cmd), 0); | ||
1890 | if (ret < 0) { | ||
1891 | wl1271_error("failed to stop channel switch command"); | ||
1892 | goto out_free; | ||
1893 | } | ||
1894 | |||
1895 | out_free: | ||
1896 | kfree(cmd); | ||
1897 | |||
1898 | out: | ||
1899 | return ret; | ||
1900 | } | ||
1901 | |||
1902 | /* start dev role and roc on its channel */ | ||
1903 | int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif) | ||
1904 | { | ||
1905 | int ret; | ||
1906 | |||
1907 | if (WARN_ON(!(wlvif->bss_type == BSS_TYPE_STA_BSS || | ||
1908 | wlvif->bss_type == BSS_TYPE_IBSS))) | ||
1909 | return -EINVAL; | ||
1910 | |||
1911 | ret = wl12xx_cmd_role_start_dev(wl, wlvif); | ||
1912 | if (ret < 0) | ||
1913 | goto out; | ||
1914 | |||
1915 | ret = wl12xx_roc(wl, wlvif, wlvif->dev_role_id); | ||
1916 | if (ret < 0) | ||
1917 | goto out_stop; | ||
1918 | |||
1919 | return 0; | ||
1920 | |||
1921 | out_stop: | ||
1922 | wl12xx_cmd_role_stop_dev(wl, wlvif); | ||
1923 | out: | ||
1924 | return ret; | ||
1925 | } | ||
1926 | |||
1927 | /* croc dev hlid, and stop the role */ | ||
1928 | int wl12xx_stop_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif) | ||
1929 | { | ||
1930 | int ret; | ||
1931 | |||
1932 | if (WARN_ON(!(wlvif->bss_type == BSS_TYPE_STA_BSS || | ||
1933 | wlvif->bss_type == BSS_TYPE_IBSS))) | ||
1934 | return -EINVAL; | ||
1935 | |||
1936 | /* flush all pending packets */ | ||
1937 | wl1271_tx_work_locked(wl); | ||
1938 | |||
1939 | if (test_bit(wlvif->dev_role_id, wl->roc_map)) { | ||
1940 | ret = wl12xx_croc(wl, wlvif->dev_role_id); | ||
1941 | if (ret < 0) | ||
1942 | goto out; | ||
1943 | } | ||
1944 | |||
1945 | ret = wl12xx_cmd_role_stop_dev(wl, wlvif); | ||
1946 | if (ret < 0) | ||
1947 | goto out; | ||
1948 | out: | ||
1949 | return ret; | ||
1950 | } | ||
diff --git a/drivers/net/wireless/ti/wl12xx/cmd.h b/drivers/net/wireless/ti/wl12xx/cmd.h new file mode 100644 index 000000000000..de217d92516b --- /dev/null +++ b/drivers/net/wireless/ti/wl12xx/cmd.h | |||
@@ -0,0 +1,728 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. | ||
5 | * Copyright (C) 2009 Nokia Corporation | ||
6 | * | ||
7 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef __CMD_H__ | ||
26 | #define __CMD_H__ | ||
27 | |||
28 | #include "wl12xx.h" | ||
29 | |||
30 | struct acx_header; | ||
31 | |||
32 | int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, | ||
33 | size_t res_len); | ||
34 | int wl1271_cmd_general_parms(struct wl1271 *wl); | ||
35 | int wl128x_cmd_general_parms(struct wl1271 *wl); | ||
36 | int wl1271_cmd_radio_parms(struct wl1271 *wl); | ||
37 | int wl128x_cmd_radio_parms(struct wl1271 *wl); | ||
38 | int wl1271_cmd_ext_radio_parms(struct wl1271 *wl); | ||
39 | int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 *addr, u8 role_type, | ||
40 | u8 *role_id); | ||
41 | int wl12xx_cmd_role_disable(struct wl1271 *wl, u8 *role_id); | ||
42 | int wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif); | ||
43 | int wl12xx_cmd_role_stop_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif); | ||
44 | int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif); | ||
45 | int wl12xx_cmd_role_stop_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif); | ||
46 | int wl12xx_cmd_role_start_ibss(struct wl1271 *wl, struct wl12xx_vif *wlvif); | ||
47 | int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif); | ||
48 | int wl12xx_stop_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif); | ||
49 | int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer); | ||
50 | int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len); | ||
51 | int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len); | ||
52 | int wl1271_cmd_data_path(struct wl1271 *wl, bool enable); | ||
53 | int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
54 | u8 ps_mode, u16 auto_ps_timeout); | ||
55 | int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer, | ||
56 | size_t len); | ||
57 | int wl1271_cmd_template_set(struct wl1271 *wl, u8 role_id, | ||
58 | u16 template_id, void *buf, size_t buf_len, | ||
59 | int index, u32 rates); | ||
60 | int wl12xx_cmd_build_null_data(struct wl1271 *wl, struct wl12xx_vif *wlvif); | ||
61 | int wl1271_cmd_build_ps_poll(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
62 | u16 aid); | ||
63 | int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
64 | u8 role_id, u8 band, | ||
65 | const u8 *ssid, size_t ssid_len, | ||
66 | const u8 *ie, size_t ie_len); | ||
67 | struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, | ||
68 | struct wl12xx_vif *wlvif, | ||
69 | struct sk_buff *skb); | ||
70 | int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif); | ||
71 | int wl1271_build_qos_null_data(struct wl1271 *wl, struct ieee80211_vif *vif); | ||
72 | int wl12xx_cmd_build_klv_null_data(struct wl1271 *wl, | ||
73 | struct wl12xx_vif *wlvif); | ||
74 | int wl12xx_cmd_set_default_wep_key(struct wl1271 *wl, u8 id, u8 hlid); | ||
75 | int wl1271_cmd_set_sta_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
76 | u16 action, u8 id, u8 key_type, | ||
77 | u8 key_size, const u8 *key, const u8 *addr, | ||
78 | u32 tx_seq_32, u16 tx_seq_16); | ||
79 | int wl1271_cmd_set_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
80 | u16 action, u8 id, u8 key_type, | ||
81 | u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32, | ||
82 | u16 tx_seq_16); | ||
83 | int wl12xx_cmd_set_peer_state(struct wl1271 *wl, u8 hlid); | ||
84 | int wl12xx_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id); | ||
85 | int wl12xx_croc(struct wl1271 *wl, u8 role_id); | ||
86 | int wl12xx_cmd_add_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
87 | struct ieee80211_sta *sta, u8 hlid); | ||
88 | int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid); | ||
89 | int wl12xx_cmd_config_fwlog(struct wl1271 *wl); | ||
90 | int wl12xx_cmd_start_fwlog(struct wl1271 *wl); | ||
91 | int wl12xx_cmd_stop_fwlog(struct wl1271 *wl); | ||
92 | int wl12xx_cmd_channel_switch(struct wl1271 *wl, | ||
93 | struct wl12xx_vif *wlvif, | ||
94 | struct ieee80211_channel_switch *ch_switch); | ||
95 | int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl); | ||
96 | int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
97 | u8 *hlid); | ||
98 | void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid); | ||
99 | |||
100 | enum wl1271_commands { | ||
101 | CMD_INTERROGATE = 1, /* use this to read information elements */ | ||
102 | CMD_CONFIGURE = 2, /* use this to write information elements */ | ||
103 | CMD_ENABLE_RX = 3, | ||
104 | CMD_ENABLE_TX = 4, | ||
105 | CMD_DISABLE_RX = 5, | ||
106 | CMD_DISABLE_TX = 6, | ||
107 | CMD_SCAN = 7, | ||
108 | CMD_STOP_SCAN = 8, | ||
109 | CMD_SET_KEYS = 9, | ||
110 | CMD_READ_MEMORY = 10, | ||
111 | CMD_WRITE_MEMORY = 11, | ||
112 | CMD_SET_TEMPLATE = 12, | ||
113 | CMD_TEST = 13, | ||
114 | CMD_NOISE_HIST = 14, | ||
115 | CMD_QUIET_ELEMENT_SET_STATE = 15, | ||
116 | CMD_SET_BCN_MODE = 16, | ||
117 | |||
118 | CMD_MEASUREMENT = 17, | ||
119 | CMD_STOP_MEASUREMENT = 18, | ||
120 | CMD_SET_PS_MODE = 19, | ||
121 | CMD_CHANNEL_SWITCH = 20, | ||
122 | CMD_STOP_CHANNEL_SWICTH = 21, | ||
123 | CMD_AP_DISCOVERY = 22, | ||
124 | CMD_STOP_AP_DISCOVERY = 23, | ||
125 | CMD_HEALTH_CHECK = 24, | ||
126 | CMD_DEBUG = 25, | ||
127 | CMD_TRIGGER_SCAN_TO = 26, | ||
128 | CMD_CONNECTION_SCAN_CFG = 27, | ||
129 | CMD_CONNECTION_SCAN_SSID_CFG = 28, | ||
130 | CMD_START_PERIODIC_SCAN = 29, | ||
131 | CMD_STOP_PERIODIC_SCAN = 30, | ||
132 | CMD_SET_PEER_STATE = 31, | ||
133 | CMD_REMAIN_ON_CHANNEL = 32, | ||
134 | CMD_CANCEL_REMAIN_ON_CHANNEL = 33, | ||
135 | CMD_CONFIG_FWLOGGER = 34, | ||
136 | CMD_START_FWLOGGER = 35, | ||
137 | CMD_STOP_FWLOGGER = 36, | ||
138 | |||
139 | /* Access point commands */ | ||
140 | CMD_ADD_PEER = 37, | ||
141 | CMD_REMOVE_PEER = 38, | ||
142 | |||
143 | /* Role API */ | ||
144 | CMD_ROLE_ENABLE = 39, | ||
145 | CMD_ROLE_DISABLE = 40, | ||
146 | CMD_ROLE_START = 41, | ||
147 | CMD_ROLE_STOP = 42, | ||
148 | |||
149 | /* DFS */ | ||
150 | CMD_START_RADAR_DETECTION = 43, | ||
151 | CMD_STOP_RADAR_DETECTION = 44, | ||
152 | |||
153 | /* WIFI Direct */ | ||
154 | CMD_WFD_START_DISCOVERY = 45, | ||
155 | CMD_WFD_STOP_DISCOVERY = 46, | ||
156 | CMD_WFD_ATTRIBUTE_CONFIG = 47, | ||
157 | CMD_NOP = 48, | ||
158 | CMD_LAST_COMMAND, | ||
159 | |||
160 | MAX_COMMAND_ID = 0xFFFF, | ||
161 | }; | ||
162 | |||
163 | #define MAX_CMD_PARAMS 572 | ||
164 | |||
165 | enum { | ||
166 | CMD_TEMPL_KLV_IDX_NULL_DATA = 0, | ||
167 | CMD_TEMPL_KLV_IDX_MAX = 4 | ||
168 | }; | ||
169 | |||
170 | enum cmd_templ { | ||
171 | CMD_TEMPL_NULL_DATA = 0, | ||
172 | CMD_TEMPL_BEACON, | ||
173 | CMD_TEMPL_CFG_PROBE_REQ_2_4, | ||
174 | CMD_TEMPL_CFG_PROBE_REQ_5, | ||
175 | CMD_TEMPL_PROBE_RESPONSE, | ||
176 | CMD_TEMPL_QOS_NULL_DATA, | ||
177 | CMD_TEMPL_PS_POLL, | ||
178 | CMD_TEMPL_KLV, | ||
179 | CMD_TEMPL_DISCONNECT, | ||
180 | CMD_TEMPL_PROBE_REQ_2_4, /* for firmware internal use only */ | ||
181 | CMD_TEMPL_PROBE_REQ_5, /* for firmware internal use only */ | ||
182 | CMD_TEMPL_BAR, /* for firmware internal use only */ | ||
183 | CMD_TEMPL_CTS, /* | ||
184 | * For CTS-to-self (FastCTS) mechanism | ||
185 | * for BT/WLAN coexistence (SoftGemini). */ | ||
186 | CMD_TEMPL_AP_BEACON, | ||
187 | CMD_TEMPL_AP_PROBE_RESPONSE, | ||
188 | CMD_TEMPL_ARP_RSP, | ||
189 | CMD_TEMPL_DEAUTH_AP, | ||
190 | CMD_TEMPL_TEMPORARY, | ||
191 | CMD_TEMPL_LINK_MEASUREMENT_REPORT, | ||
192 | |||
193 | CMD_TEMPL_MAX = 0xff | ||
194 | }; | ||
195 | |||
196 | /* unit ms */ | ||
197 | #define WL1271_COMMAND_TIMEOUT 2000 | ||
198 | #define WL1271_CMD_TEMPL_DFLT_SIZE 252 | ||
199 | #define WL1271_CMD_TEMPL_MAX_SIZE 512 | ||
200 | #define WL1271_EVENT_TIMEOUT 750 | ||
201 | |||
202 | struct wl1271_cmd_header { | ||
203 | __le16 id; | ||
204 | __le16 status; | ||
205 | /* payload */ | ||
206 | u8 data[0]; | ||
207 | } __packed; | ||
208 | |||
209 | #define WL1271_CMD_MAX_PARAMS 572 | ||
210 | |||
211 | struct wl1271_command { | ||
212 | struct wl1271_cmd_header header; | ||
213 | u8 parameters[WL1271_CMD_MAX_PARAMS]; | ||
214 | } __packed; | ||
215 | |||
216 | enum { | ||
217 | CMD_MAILBOX_IDLE = 0, | ||
218 | CMD_STATUS_SUCCESS = 1, | ||
219 | CMD_STATUS_UNKNOWN_CMD = 2, | ||
220 | CMD_STATUS_UNKNOWN_IE = 3, | ||
221 | CMD_STATUS_REJECT_MEAS_SG_ACTIVE = 11, | ||
222 | CMD_STATUS_RX_BUSY = 13, | ||
223 | CMD_STATUS_INVALID_PARAM = 14, | ||
224 | CMD_STATUS_TEMPLATE_TOO_LARGE = 15, | ||
225 | CMD_STATUS_OUT_OF_MEMORY = 16, | ||
226 | CMD_STATUS_STA_TABLE_FULL = 17, | ||
227 | CMD_STATUS_RADIO_ERROR = 18, | ||
228 | CMD_STATUS_WRONG_NESTING = 19, | ||
229 | CMD_STATUS_TIMEOUT = 21, /* Driver internal use.*/ | ||
230 | CMD_STATUS_FW_RESET = 22, /* Driver internal use.*/ | ||
231 | CMD_STATUS_TEMPLATE_OOM = 23, | ||
232 | CMD_STATUS_NO_RX_BA_SESSION = 24, | ||
233 | MAX_COMMAND_STATUS = 0xff | ||
234 | }; | ||
235 | |||
236 | #define CMDMBOX_HEADER_LEN 4 | ||
237 | #define CMDMBOX_INFO_ELEM_HEADER_LEN 4 | ||
238 | |||
239 | enum { | ||
240 | BSS_TYPE_IBSS = 0, | ||
241 | BSS_TYPE_STA_BSS = 2, | ||
242 | BSS_TYPE_AP_BSS = 3, | ||
243 | MAX_BSS_TYPE = 0xFF | ||
244 | }; | ||
245 | |||
246 | #define WL1271_JOIN_CMD_CTRL_TX_FLUSH 0x80 /* Firmware flushes all Tx */ | ||
247 | #define WL1271_JOIN_CMD_TX_SESSION_OFFSET 1 | ||
248 | #define WL1271_JOIN_CMD_BSS_TYPE_5GHZ 0x10 | ||
249 | |||
250 | struct wl12xx_cmd_role_enable { | ||
251 | struct wl1271_cmd_header header; | ||
252 | |||
253 | u8 role_id; | ||
254 | u8 role_type; | ||
255 | u8 mac_address[ETH_ALEN]; | ||
256 | } __packed; | ||
257 | |||
258 | struct wl12xx_cmd_role_disable { | ||
259 | struct wl1271_cmd_header header; | ||
260 | |||
261 | u8 role_id; | ||
262 | u8 padding[3]; | ||
263 | } __packed; | ||
264 | |||
265 | enum wl12xx_band { | ||
266 | WL12XX_BAND_2_4GHZ = 0, | ||
267 | WL12XX_BAND_5GHZ = 1, | ||
268 | WL12XX_BAND_JAPAN_4_9_GHZ = 2, | ||
269 | WL12XX_BAND_DEFAULT = WL12XX_BAND_2_4GHZ, | ||
270 | WL12XX_BAND_INVALID = 0x7E, | ||
271 | WL12XX_BAND_MAX_RADIO = 0x7F, | ||
272 | }; | ||
273 | |||
274 | struct wl12xx_cmd_role_start { | ||
275 | struct wl1271_cmd_header header; | ||
276 | |||
277 | u8 role_id; | ||
278 | u8 band; | ||
279 | u8 channel; | ||
280 | u8 padding; | ||
281 | |||
282 | union { | ||
283 | struct { | ||
284 | u8 hlid; | ||
285 | u8 session; | ||
286 | u8 padding_1[54]; | ||
287 | } __packed device; | ||
288 | /* sta & p2p_cli use the same struct */ | ||
289 | struct { | ||
290 | u8 bssid[ETH_ALEN]; | ||
291 | u8 hlid; /* data hlid */ | ||
292 | u8 session; | ||
293 | __le32 remote_rates; /* remote supported rates */ | ||
294 | |||
295 | /* | ||
296 | * The target uses this field to determine the rate at | ||
297 | * which to transmit control frame responses (such as | ||
298 | * ACK or CTS frames). | ||
299 | */ | ||
300 | __le32 basic_rate_set; | ||
301 | __le32 local_rates; /* local supported rates */ | ||
302 | |||
303 | u8 ssid_type; | ||
304 | u8 ssid_len; | ||
305 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | ||
306 | |||
307 | __le16 beacon_interval; /* in TBTTs */ | ||
308 | } __packed sta; | ||
309 | struct { | ||
310 | u8 bssid[ETH_ALEN]; | ||
311 | u8 hlid; /* data hlid */ | ||
312 | u8 dtim_interval; | ||
313 | __le32 remote_rates; /* remote supported rates */ | ||
314 | |||
315 | __le32 basic_rate_set; | ||
316 | __le32 local_rates; /* local supported rates */ | ||
317 | |||
318 | u8 ssid_type; | ||
319 | u8 ssid_len; | ||
320 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | ||
321 | |||
322 | __le16 beacon_interval; /* in TBTTs */ | ||
323 | |||
324 | u8 padding_1[4]; | ||
325 | } __packed ibss; | ||
326 | /* ap & p2p_go use the same struct */ | ||
327 | struct { | ||
328 | __le16 aging_period; /* in secs */ | ||
329 | u8 beacon_expiry; /* in ms */ | ||
330 | u8 bss_index; | ||
331 | /* The host link id for the AP's global queue */ | ||
332 | u8 global_hlid; | ||
333 | /* The host link id for the AP's broadcast queue */ | ||
334 | u8 broadcast_hlid; | ||
335 | |||
336 | __le16 beacon_interval; /* in TBTTs */ | ||
337 | |||
338 | __le32 basic_rate_set; | ||
339 | __le32 local_rates; /* local supported rates */ | ||
340 | |||
341 | u8 dtim_interval; | ||
342 | |||
343 | u8 ssid_type; | ||
344 | u8 ssid_len; | ||
345 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | ||
346 | |||
347 | u8 reset_tsf; | ||
348 | |||
349 | u8 padding_1[4]; | ||
350 | } __packed ap; | ||
351 | }; | ||
352 | } __packed; | ||
353 | |||
354 | struct wl12xx_cmd_role_stop { | ||
355 | struct wl1271_cmd_header header; | ||
356 | |||
357 | u8 role_id; | ||
358 | u8 disc_type; /* only STA and P2P_CLI */ | ||
359 | __le16 reason; /* only STA and P2P_CLI */ | ||
360 | } __packed; | ||
361 | |||
362 | struct cmd_enabledisable_path { | ||
363 | struct wl1271_cmd_header header; | ||
364 | |||
365 | u8 channel; | ||
366 | u8 padding[3]; | ||
367 | } __packed; | ||
368 | |||
369 | #define WL1271_RATE_AUTOMATIC 0 | ||
370 | |||
371 | struct wl1271_cmd_template_set { | ||
372 | struct wl1271_cmd_header header; | ||
373 | |||
374 | u8 role_id; | ||
375 | u8 template_type; | ||
376 | __le16 len; | ||
377 | u8 index; /* relevant only for KLV_TEMPLATE type */ | ||
378 | u8 padding[3]; | ||
379 | |||
380 | __le32 enabled_rates; | ||
381 | u8 short_retry_limit; | ||
382 | u8 long_retry_limit; | ||
383 | u8 aflags; | ||
384 | u8 reserved; | ||
385 | |||
386 | u8 template_data[WL1271_CMD_TEMPL_MAX_SIZE]; | ||
387 | } __packed; | ||
388 | |||
389 | #define TIM_ELE_ID 5 | ||
390 | #define PARTIAL_VBM_MAX 251 | ||
391 | |||
392 | struct wl1271_tim { | ||
393 | u8 identity; | ||
394 | u8 length; | ||
395 | u8 dtim_count; | ||
396 | u8 dtim_period; | ||
397 | u8 bitmap_ctrl; | ||
398 | u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */ | ||
399 | } __packed; | ||
400 | |||
401 | enum wl1271_cmd_ps_mode { | ||
402 | STATION_AUTO_PS_MODE, /* Dynamic Power Save */ | ||
403 | STATION_ACTIVE_MODE, | ||
404 | STATION_POWER_SAVE_MODE | ||
405 | }; | ||
406 | |||
407 | struct wl1271_cmd_ps_params { | ||
408 | struct wl1271_cmd_header header; | ||
409 | |||
410 | u8 role_id; | ||
411 | u8 ps_mode; /* STATION_* */ | ||
412 | u16 auto_ps_timeout; | ||
413 | } __packed; | ||
414 | |||
415 | /* HW encryption keys */ | ||
416 | #define NUM_ACCESS_CATEGORIES_COPY 4 | ||
417 | |||
418 | enum wl1271_cmd_key_action { | ||
419 | KEY_ADD_OR_REPLACE = 1, | ||
420 | KEY_REMOVE = 2, | ||
421 | KEY_SET_ID = 3, | ||
422 | MAX_KEY_ACTION = 0xffff, | ||
423 | }; | ||
424 | |||
425 | enum wl1271_cmd_lid_key_type { | ||
426 | UNICAST_LID_TYPE = 0, | ||
427 | BROADCAST_LID_TYPE = 1, | ||
428 | WEP_DEFAULT_LID_TYPE = 2 | ||
429 | }; | ||
430 | |||
431 | enum wl1271_cmd_key_type { | ||
432 | KEY_NONE = 0, | ||
433 | KEY_WEP = 1, | ||
434 | KEY_TKIP = 2, | ||
435 | KEY_AES = 3, | ||
436 | KEY_GEM = 4, | ||
437 | }; | ||
438 | |||
439 | struct wl1271_cmd_set_keys { | ||
440 | struct wl1271_cmd_header header; | ||
441 | |||
442 | /* | ||
443 | * Indicates whether the HLID is a unicast key set | ||
444 | * or broadcast key set. A special value 0xFF is | ||
445 | * used to indicate that the HLID is on WEP-default | ||
446 | * (multi-hlids). of type wl1271_cmd_lid_key_type. | ||
447 | */ | ||
448 | u8 hlid; | ||
449 | |||
450 | /* | ||
451 | * In WEP-default network (hlid == 0xFF) used to | ||
452 | * indicate which network STA/IBSS/AP role should be | ||
453 | * changed | ||
454 | */ | ||
455 | u8 lid_key_type; | ||
456 | |||
457 | /* | ||
458 | * Key ID - For TKIP and AES key types, this field | ||
459 | * indicates the value that should be inserted into | ||
460 | * the KeyID field of frames transmitted using this | ||
461 | * key entry. For broadcast keys the index use as a | ||
462 | * marker for TX/RX key. | ||
463 | * For WEP default network (HLID=0xFF), this field | ||
464 | * indicates the ID of the key to add or remove. | ||
465 | */ | ||
466 | u8 key_id; | ||
467 | u8 reserved_1; | ||
468 | |||
469 | /* key_action_e */ | ||
470 | __le16 key_action; | ||
471 | |||
472 | /* key size in bytes */ | ||
473 | u8 key_size; | ||
474 | |||
475 | /* key_type_e */ | ||
476 | u8 key_type; | ||
477 | |||
478 | /* This field holds the security key data to add to the STA table */ | ||
479 | u8 key[MAX_KEY_SIZE]; | ||
480 | __le16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY]; | ||
481 | __le32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY]; | ||
482 | } __packed; | ||
483 | |||
484 | struct wl1271_cmd_test_header { | ||
485 | u8 id; | ||
486 | u8 padding[3]; | ||
487 | } __packed; | ||
488 | |||
489 | enum wl1271_channel_tune_bands { | ||
490 | WL1271_CHANNEL_TUNE_BAND_2_4, | ||
491 | WL1271_CHANNEL_TUNE_BAND_5, | ||
492 | WL1271_CHANNEL_TUNE_BAND_4_9 | ||
493 | }; | ||
494 | |||
495 | #define WL1271_PD_REFERENCE_POINT_BAND_B_G 0 | ||
496 | |||
497 | #define TEST_CMD_INI_FILE_RADIO_PARAM 0x19 | ||
498 | #define TEST_CMD_INI_FILE_GENERAL_PARAM 0x1E | ||
499 | #define TEST_CMD_INI_FILE_RF_EXTENDED_PARAM 0x26 | ||
500 | |||
501 | struct wl1271_general_parms_cmd { | ||
502 | struct wl1271_cmd_header header; | ||
503 | |||
504 | struct wl1271_cmd_test_header test; | ||
505 | |||
506 | struct wl1271_ini_general_params general_params; | ||
507 | |||
508 | u8 sr_debug_table[WL1271_INI_MAX_SMART_REFLEX_PARAM]; | ||
509 | u8 sr_sen_n_p; | ||
510 | u8 sr_sen_n_p_gain; | ||
511 | u8 sr_sen_nrn; | ||
512 | u8 sr_sen_prn; | ||
513 | u8 padding[3]; | ||
514 | } __packed; | ||
515 | |||
516 | struct wl128x_general_parms_cmd { | ||
517 | struct wl1271_cmd_header header; | ||
518 | |||
519 | struct wl1271_cmd_test_header test; | ||
520 | |||
521 | struct wl128x_ini_general_params general_params; | ||
522 | |||
523 | u8 sr_debug_table[WL1271_INI_MAX_SMART_REFLEX_PARAM]; | ||
524 | u8 sr_sen_n_p; | ||
525 | u8 sr_sen_n_p_gain; | ||
526 | u8 sr_sen_nrn; | ||
527 | u8 sr_sen_prn; | ||
528 | u8 padding[3]; | ||
529 | } __packed; | ||
530 | |||
531 | struct wl1271_radio_parms_cmd { | ||
532 | struct wl1271_cmd_header header; | ||
533 | |||
534 | struct wl1271_cmd_test_header test; | ||
535 | |||
536 | /* Static radio parameters */ | ||
537 | struct wl1271_ini_band_params_2 static_params_2; | ||
538 | struct wl1271_ini_band_params_5 static_params_5; | ||
539 | |||
540 | /* Dynamic radio parameters */ | ||
541 | struct wl1271_ini_fem_params_2 dyn_params_2; | ||
542 | u8 padding2; | ||
543 | struct wl1271_ini_fem_params_5 dyn_params_5; | ||
544 | u8 padding3[2]; | ||
545 | } __packed; | ||
546 | |||
547 | struct wl128x_radio_parms_cmd { | ||
548 | struct wl1271_cmd_header header; | ||
549 | |||
550 | struct wl1271_cmd_test_header test; | ||
551 | |||
552 | /* Static radio parameters */ | ||
553 | struct wl128x_ini_band_params_2 static_params_2; | ||
554 | struct wl128x_ini_band_params_5 static_params_5; | ||
555 | |||
556 | u8 fem_vendor_and_options; | ||
557 | |||
558 | /* Dynamic radio parameters */ | ||
559 | struct wl128x_ini_fem_params_2 dyn_params_2; | ||
560 | u8 padding2; | ||
561 | struct wl128x_ini_fem_params_5 dyn_params_5; | ||
562 | } __packed; | ||
563 | |||
564 | struct wl1271_ext_radio_parms_cmd { | ||
565 | struct wl1271_cmd_header header; | ||
566 | |||
567 | struct wl1271_cmd_test_header test; | ||
568 | |||
569 | u8 tx_per_channel_power_compensation_2[CONF_TX_PWR_COMPENSATION_LEN_2]; | ||
570 | u8 tx_per_channel_power_compensation_5[CONF_TX_PWR_COMPENSATION_LEN_5]; | ||
571 | u8 padding[3]; | ||
572 | } __packed; | ||
573 | |||
574 | /* | ||
575 | * There are three types of disconnections: | ||
576 | * | ||
577 | * DISCONNECT_IMMEDIATE: the fw doesn't send any frames | ||
578 | * DISCONNECT_DEAUTH: the fw generates a DEAUTH request with the reason | ||
579 | * we have passed | ||
580 | * DISCONNECT_DISASSOC: the fw generates a DESASSOC request with the reason | ||
581 | * we have passed | ||
582 | */ | ||
583 | enum wl1271_disconnect_type { | ||
584 | DISCONNECT_IMMEDIATE, | ||
585 | DISCONNECT_DEAUTH, | ||
586 | DISCONNECT_DISASSOC | ||
587 | }; | ||
588 | |||
589 | #define WL1271_CMD_STA_STATE_CONNECTED 1 | ||
590 | |||
591 | struct wl12xx_cmd_set_peer_state { | ||
592 | struct wl1271_cmd_header header; | ||
593 | |||
594 | u8 hlid; | ||
595 | u8 state; | ||
596 | u8 padding[2]; | ||
597 | } __packed; | ||
598 | |||
599 | struct wl12xx_cmd_roc { | ||
600 | struct wl1271_cmd_header header; | ||
601 | |||
602 | u8 role_id; | ||
603 | u8 channel; | ||
604 | u8 band; | ||
605 | u8 padding; | ||
606 | }; | ||
607 | |||
608 | struct wl12xx_cmd_croc { | ||
609 | struct wl1271_cmd_header header; | ||
610 | |||
611 | u8 role_id; | ||
612 | u8 padding[3]; | ||
613 | }; | ||
614 | |||
615 | enum wl12xx_ssid_type { | ||
616 | WL12XX_SSID_TYPE_PUBLIC = 0, | ||
617 | WL12XX_SSID_TYPE_HIDDEN = 1, | ||
618 | WL12XX_SSID_TYPE_ANY = 2, | ||
619 | }; | ||
620 | |||
621 | enum wl1271_psd_type { | ||
622 | WL1271_PSD_LEGACY = 0, | ||
623 | WL1271_PSD_UPSD_TRIGGER = 1, | ||
624 | WL1271_PSD_LEGACY_PSPOLL = 2, | ||
625 | WL1271_PSD_SAPSD = 3 | ||
626 | }; | ||
627 | |||
628 | struct wl12xx_cmd_add_peer { | ||
629 | struct wl1271_cmd_header header; | ||
630 | |||
631 | u8 addr[ETH_ALEN]; | ||
632 | u8 hlid; | ||
633 | u8 aid; | ||
634 | u8 psd_type[NUM_ACCESS_CATEGORIES_COPY]; | ||
635 | __le32 supported_rates; | ||
636 | u8 bss_index; | ||
637 | u8 sp_len; | ||
638 | u8 wmm; | ||
639 | u8 padding1; | ||
640 | } __packed; | ||
641 | |||
642 | struct wl12xx_cmd_remove_peer { | ||
643 | struct wl1271_cmd_header header; | ||
644 | |||
645 | u8 hlid; | ||
646 | u8 reason_opcode; | ||
647 | u8 send_deauth_flag; | ||
648 | u8 padding1; | ||
649 | } __packed; | ||
650 | |||
651 | /* | ||
652 | * Continuous mode - packets are transferred to the host periodically | ||
653 | * via the data path. | ||
654 | * On demand - Log messages are stored in a cyclic buffer in the | ||
655 | * firmware, and only transferred to the host when explicitly requested | ||
656 | */ | ||
657 | enum wl12xx_fwlogger_log_mode { | ||
658 | WL12XX_FWLOG_CONTINUOUS, | ||
659 | WL12XX_FWLOG_ON_DEMAND | ||
660 | }; | ||
661 | |||
662 | /* Include/exclude timestamps from the log messages */ | ||
663 | enum wl12xx_fwlogger_timestamp { | ||
664 | WL12XX_FWLOG_TIMESTAMP_DISABLED, | ||
665 | WL12XX_FWLOG_TIMESTAMP_ENABLED | ||
666 | }; | ||
667 | |||
668 | /* | ||
669 | * Logs can be routed to the debug pinouts (where available), to the host bus | ||
670 | * (SDIO/SPI), or dropped | ||
671 | */ | ||
672 | enum wl12xx_fwlogger_output { | ||
673 | WL12XX_FWLOG_OUTPUT_NONE, | ||
674 | WL12XX_FWLOG_OUTPUT_DBG_PINS, | ||
675 | WL12XX_FWLOG_OUTPUT_HOST, | ||
676 | }; | ||
677 | |||
678 | struct wl12xx_cmd_config_fwlog { | ||
679 | struct wl1271_cmd_header header; | ||
680 | |||
681 | /* See enum wl12xx_fwlogger_log_mode */ | ||
682 | u8 logger_mode; | ||
683 | |||
684 | /* Minimum log level threshold */ | ||
685 | u8 log_severity; | ||
686 | |||
687 | /* Include/exclude timestamps from the log messages */ | ||
688 | u8 timestamp; | ||
689 | |||
690 | /* See enum wl1271_fwlogger_output */ | ||
691 | u8 output; | ||
692 | |||
693 | /* Regulates the frequency of log messages */ | ||
694 | u8 threshold; | ||
695 | |||
696 | u8 padding[3]; | ||
697 | } __packed; | ||
698 | |||
699 | struct wl12xx_cmd_start_fwlog { | ||
700 | struct wl1271_cmd_header header; | ||
701 | } __packed; | ||
702 | |||
703 | struct wl12xx_cmd_stop_fwlog { | ||
704 | struct wl1271_cmd_header header; | ||
705 | } __packed; | ||
706 | |||
707 | struct wl12xx_cmd_channel_switch { | ||
708 | struct wl1271_cmd_header header; | ||
709 | |||
710 | u8 role_id; | ||
711 | |||
712 | /* The new serving channel */ | ||
713 | u8 channel; | ||
714 | /* Relative time of the serving channel switch in TBTT units */ | ||
715 | u8 switch_time; | ||
716 | /* Stop the role TX, should expect it after radar detection */ | ||
717 | u8 stop_tx; | ||
718 | /* The target channel tx status 1-stopped 0-open*/ | ||
719 | u8 post_switch_tx_disable; | ||
720 | |||
721 | u8 padding[3]; | ||
722 | } __packed; | ||
723 | |||
724 | struct wl12xx_cmd_stop_channel_switch { | ||
725 | struct wl1271_cmd_header header; | ||
726 | } __packed; | ||
727 | |||
728 | #endif /* __WL1271_CMD_H__ */ | ||
diff --git a/drivers/net/wireless/ti/wl12xx/conf.h b/drivers/net/wireless/ti/wl12xx/conf.h new file mode 100644 index 000000000000..5d2a9e004c72 --- /dev/null +++ b/drivers/net/wireless/ti/wl12xx/conf.h | |||
@@ -0,0 +1,1326 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2009 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 __CONF_H__ | ||
25 | #define __CONF_H__ | ||
26 | |||
27 | enum { | ||
28 | CONF_HW_BIT_RATE_1MBPS = BIT(0), | ||
29 | CONF_HW_BIT_RATE_2MBPS = BIT(1), | ||
30 | CONF_HW_BIT_RATE_5_5MBPS = BIT(2), | ||
31 | CONF_HW_BIT_RATE_6MBPS = BIT(3), | ||
32 | CONF_HW_BIT_RATE_9MBPS = BIT(4), | ||
33 | CONF_HW_BIT_RATE_11MBPS = BIT(5), | ||
34 | CONF_HW_BIT_RATE_12MBPS = BIT(6), | ||
35 | CONF_HW_BIT_RATE_18MBPS = BIT(7), | ||
36 | CONF_HW_BIT_RATE_22MBPS = BIT(8), | ||
37 | CONF_HW_BIT_RATE_24MBPS = BIT(9), | ||
38 | CONF_HW_BIT_RATE_36MBPS = BIT(10), | ||
39 | CONF_HW_BIT_RATE_48MBPS = BIT(11), | ||
40 | CONF_HW_BIT_RATE_54MBPS = BIT(12), | ||
41 | CONF_HW_BIT_RATE_MCS_0 = BIT(13), | ||
42 | CONF_HW_BIT_RATE_MCS_1 = BIT(14), | ||
43 | CONF_HW_BIT_RATE_MCS_2 = BIT(15), | ||
44 | CONF_HW_BIT_RATE_MCS_3 = BIT(16), | ||
45 | CONF_HW_BIT_RATE_MCS_4 = BIT(17), | ||
46 | CONF_HW_BIT_RATE_MCS_5 = BIT(18), | ||
47 | CONF_HW_BIT_RATE_MCS_6 = BIT(19), | ||
48 | CONF_HW_BIT_RATE_MCS_7 = BIT(20) | ||
49 | }; | ||
50 | |||
51 | enum { | ||
52 | CONF_HW_RATE_INDEX_1MBPS = 0, | ||
53 | CONF_HW_RATE_INDEX_2MBPS = 1, | ||
54 | CONF_HW_RATE_INDEX_5_5MBPS = 2, | ||
55 | CONF_HW_RATE_INDEX_6MBPS = 3, | ||
56 | CONF_HW_RATE_INDEX_9MBPS = 4, | ||
57 | CONF_HW_RATE_INDEX_11MBPS = 5, | ||
58 | CONF_HW_RATE_INDEX_12MBPS = 6, | ||
59 | CONF_HW_RATE_INDEX_18MBPS = 7, | ||
60 | CONF_HW_RATE_INDEX_22MBPS = 8, | ||
61 | CONF_HW_RATE_INDEX_24MBPS = 9, | ||
62 | CONF_HW_RATE_INDEX_36MBPS = 10, | ||
63 | CONF_HW_RATE_INDEX_48MBPS = 11, | ||
64 | CONF_HW_RATE_INDEX_54MBPS = 12, | ||
65 | CONF_HW_RATE_INDEX_MAX = CONF_HW_RATE_INDEX_54MBPS, | ||
66 | }; | ||
67 | |||
68 | enum { | ||
69 | CONF_HW_RXTX_RATE_MCS7_SGI = 0, | ||
70 | CONF_HW_RXTX_RATE_MCS7, | ||
71 | CONF_HW_RXTX_RATE_MCS6, | ||
72 | CONF_HW_RXTX_RATE_MCS5, | ||
73 | CONF_HW_RXTX_RATE_MCS4, | ||
74 | CONF_HW_RXTX_RATE_MCS3, | ||
75 | CONF_HW_RXTX_RATE_MCS2, | ||
76 | CONF_HW_RXTX_RATE_MCS1, | ||
77 | CONF_HW_RXTX_RATE_MCS0, | ||
78 | CONF_HW_RXTX_RATE_54, | ||
79 | CONF_HW_RXTX_RATE_48, | ||
80 | CONF_HW_RXTX_RATE_36, | ||
81 | CONF_HW_RXTX_RATE_24, | ||
82 | CONF_HW_RXTX_RATE_22, | ||
83 | CONF_HW_RXTX_RATE_18, | ||
84 | CONF_HW_RXTX_RATE_12, | ||
85 | CONF_HW_RXTX_RATE_11, | ||
86 | CONF_HW_RXTX_RATE_9, | ||
87 | CONF_HW_RXTX_RATE_6, | ||
88 | CONF_HW_RXTX_RATE_5_5, | ||
89 | CONF_HW_RXTX_RATE_2, | ||
90 | CONF_HW_RXTX_RATE_1, | ||
91 | CONF_HW_RXTX_RATE_MAX, | ||
92 | CONF_HW_RXTX_RATE_UNSUPPORTED = 0xff | ||
93 | }; | ||
94 | |||
95 | /* Rates between and including these are MCS rates */ | ||
96 | #define CONF_HW_RXTX_RATE_MCS_MIN CONF_HW_RXTX_RATE_MCS7_SGI | ||
97 | #define CONF_HW_RXTX_RATE_MCS_MAX CONF_HW_RXTX_RATE_MCS0 | ||
98 | |||
99 | enum { | ||
100 | CONF_SG_DISABLE = 0, | ||
101 | CONF_SG_PROTECTIVE, | ||
102 | CONF_SG_OPPORTUNISTIC | ||
103 | }; | ||
104 | |||
105 | enum { | ||
106 | /* | ||
107 | * Configure the min and max time BT gains the antenna | ||
108 | * in WLAN / BT master basic rate | ||
109 | * | ||
110 | * Range: 0 - 255 (ms) | ||
111 | */ | ||
112 | CONF_SG_ACL_BT_MASTER_MIN_BR = 0, | ||
113 | CONF_SG_ACL_BT_MASTER_MAX_BR, | ||
114 | |||
115 | /* | ||
116 | * Configure the min and max time BT gains the antenna | ||
117 | * in WLAN / BT slave basic rate | ||
118 | * | ||
119 | * Range: 0 - 255 (ms) | ||
120 | */ | ||
121 | CONF_SG_ACL_BT_SLAVE_MIN_BR, | ||
122 | CONF_SG_ACL_BT_SLAVE_MAX_BR, | ||
123 | |||
124 | /* | ||
125 | * Configure the min and max time BT gains the antenna | ||
126 | * in WLAN / BT master EDR | ||
127 | * | ||
128 | * Range: 0 - 255 (ms) | ||
129 | */ | ||
130 | CONF_SG_ACL_BT_MASTER_MIN_EDR, | ||
131 | CONF_SG_ACL_BT_MASTER_MAX_EDR, | ||
132 | |||
133 | /* | ||
134 | * Configure the min and max time BT gains the antenna | ||
135 | * in WLAN / BT slave EDR | ||
136 | * | ||
137 | * Range: 0 - 255 (ms) | ||
138 | */ | ||
139 | CONF_SG_ACL_BT_SLAVE_MIN_EDR, | ||
140 | CONF_SG_ACL_BT_SLAVE_MAX_EDR, | ||
141 | |||
142 | /* | ||
143 | * The maximum time WLAN can gain the antenna | ||
144 | * in WLAN PSM / BT master/slave BR | ||
145 | * | ||
146 | * Range: 0 - 255 (ms) | ||
147 | */ | ||
148 | CONF_SG_ACL_WLAN_PS_MASTER_BR, | ||
149 | CONF_SG_ACL_WLAN_PS_SLAVE_BR, | ||
150 | |||
151 | /* | ||
152 | * The maximum time WLAN can gain the antenna | ||
153 | * in WLAN PSM / BT master/slave EDR | ||
154 | * | ||
155 | * Range: 0 - 255 (ms) | ||
156 | */ | ||
157 | CONF_SG_ACL_WLAN_PS_MASTER_EDR, | ||
158 | CONF_SG_ACL_WLAN_PS_SLAVE_EDR, | ||
159 | |||
160 | /* TODO: explain these values */ | ||
161 | CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR, | ||
162 | CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR, | ||
163 | CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR, | ||
164 | CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR, | ||
165 | CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR, | ||
166 | CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR, | ||
167 | CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR, | ||
168 | CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR, | ||
169 | |||
170 | CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR, | ||
171 | CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR, | ||
172 | CONF_SG_ACL_PASSIVE_SCAN_BT_BR, | ||
173 | CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR, | ||
174 | CONF_SG_ACL_PASSIVE_SCAN_BT_EDR, | ||
175 | CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR, | ||
176 | |||
177 | /* | ||
178 | * Compensation percentage of probe requests when scan initiated | ||
179 | * during BT voice/ACL link. | ||
180 | * | ||
181 | * Range: 0 - 255 (%) | ||
182 | */ | ||
183 | CONF_SG_AUTO_SCAN_PROBE_REQ, | ||
184 | |||
185 | /* | ||
186 | * Compensation percentage of probe requests when active scan initiated | ||
187 | * during BT voice | ||
188 | * | ||
189 | * Range: 0 - 255 (%) | ||
190 | */ | ||
191 | CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3, | ||
192 | |||
193 | /* | ||
194 | * Compensation percentage of WLAN active scan window if initiated | ||
195 | * during BT A2DP | ||
196 | * | ||
197 | * Range: 0 - 1000 (%) | ||
198 | */ | ||
199 | CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP, | ||
200 | |||
201 | /* | ||
202 | * Compensation percentage of WLAN passive scan window if initiated | ||
203 | * during BT A2DP BR | ||
204 | * | ||
205 | * Range: 0 - 1000 (%) | ||
206 | */ | ||
207 | CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR, | ||
208 | |||
209 | /* | ||
210 | * Compensation percentage of WLAN passive scan window if initiated | ||
211 | * during BT A2DP EDR | ||
212 | * | ||
213 | * Range: 0 - 1000 (%) | ||
214 | */ | ||
215 | CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR, | ||
216 | |||
217 | /* | ||
218 | * Compensation percentage of WLAN passive scan window if initiated | ||
219 | * during BT voice | ||
220 | * | ||
221 | * Range: 0 - 1000 (%) | ||
222 | */ | ||
223 | CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3, | ||
224 | |||
225 | /* TODO: explain these values */ | ||
226 | CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN, | ||
227 | CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN, | ||
228 | CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN, | ||
229 | |||
230 | /* | ||
231 | * Defines whether the SG will force WLAN host to enter/exit PSM | ||
232 | * | ||
233 | * Range: 1 - SG can force, 0 - host handles PSM | ||
234 | */ | ||
235 | CONF_SG_STA_FORCE_PS_IN_BT_SCO, | ||
236 | |||
237 | /* | ||
238 | * Defines antenna configuration (single/dual antenna) | ||
239 | * | ||
240 | * Range: 0 - single antenna, 1 - dual antenna | ||
241 | */ | ||
242 | CONF_SG_ANTENNA_CONFIGURATION, | ||
243 | |||
244 | /* | ||
245 | * The threshold (percent) of max consecutive beacon misses before | ||
246 | * increasing priority of beacon reception. | ||
247 | * | ||
248 | * Range: 0 - 100 (%) | ||
249 | */ | ||
250 | CONF_SG_BEACON_MISS_PERCENT, | ||
251 | |||
252 | /* | ||
253 | * Protection time of the DHCP procedure. | ||
254 | * | ||
255 | * Range: 0 - 100000 (ms) | ||
256 | */ | ||
257 | CONF_SG_DHCP_TIME, | ||
258 | |||
259 | /* | ||
260 | * RX guard time before the beginning of a new BT voice frame during | ||
261 | * which no new WLAN trigger frame is transmitted. | ||
262 | * | ||
263 | * Range: 0 - 100000 (us) | ||
264 | */ | ||
265 | CONF_SG_RXT, | ||
266 | |||
267 | /* | ||
268 | * TX guard time before the beginning of a new BT voice frame during | ||
269 | * which no new WLAN frame is transmitted. | ||
270 | * | ||
271 | * Range: 0 - 100000 (us) | ||
272 | */ | ||
273 | |||
274 | CONF_SG_TXT, | ||
275 | |||
276 | /* | ||
277 | * Enable adaptive RXT/TXT algorithm. If disabled, the host values | ||
278 | * will be utilized. | ||
279 | * | ||
280 | * Range: 0 - disable, 1 - enable | ||
281 | */ | ||
282 | CONF_SG_ADAPTIVE_RXT_TXT, | ||
283 | |||
284 | /* TODO: explain this value */ | ||
285 | CONF_SG_GENERAL_USAGE_BIT_MAP, | ||
286 | |||
287 | /* | ||
288 | * Number of consecutive BT voice frames not interrupted by WLAN | ||
289 | * | ||
290 | * Range: 0 - 100 | ||
291 | */ | ||
292 | CONF_SG_HV3_MAX_SERVED, | ||
293 | |||
294 | /* | ||
295 | * The used WLAN legacy service period during active BT ACL link | ||
296 | * | ||
297 | * Range: 0 - 255 (ms) | ||
298 | */ | ||
299 | CONF_SG_PS_POLL_TIMEOUT, | ||
300 | |||
301 | /* | ||
302 | * The used WLAN UPSD service period during active BT ACL link | ||
303 | * | ||
304 | * Range: 0 - 255 (ms) | ||
305 | */ | ||
306 | CONF_SG_UPSD_TIMEOUT, | ||
307 | |||
308 | CONF_SG_CONSECUTIVE_CTS_THRESHOLD, | ||
309 | CONF_SG_STA_RX_WINDOW_AFTER_DTIM, | ||
310 | CONF_SG_STA_CONNECTION_PROTECTION_TIME, | ||
311 | |||
312 | /* AP params */ | ||
313 | CONF_AP_BEACON_MISS_TX, | ||
314 | CONF_AP_RX_WINDOW_AFTER_BEACON, | ||
315 | CONF_AP_BEACON_WINDOW_INTERVAL, | ||
316 | CONF_AP_CONNECTION_PROTECTION_TIME, | ||
317 | CONF_AP_BT_ACL_VAL_BT_SERVE_TIME, | ||
318 | CONF_AP_BT_ACL_VAL_WL_SERVE_TIME, | ||
319 | |||
320 | /* CTS Diluting params */ | ||
321 | CONF_SG_CTS_DILUTED_BAD_RX_PACKETS_TH, | ||
322 | CONF_SG_CTS_CHOP_IN_DUAL_ANT_SCO_MASTER, | ||
323 | |||
324 | CONF_SG_TEMP_PARAM_1, | ||
325 | CONF_SG_TEMP_PARAM_2, | ||
326 | CONF_SG_TEMP_PARAM_3, | ||
327 | CONF_SG_TEMP_PARAM_4, | ||
328 | CONF_SG_TEMP_PARAM_5, | ||
329 | CONF_SG_TEMP_PARAM_6, | ||
330 | CONF_SG_TEMP_PARAM_7, | ||
331 | CONF_SG_TEMP_PARAM_8, | ||
332 | CONF_SG_TEMP_PARAM_9, | ||
333 | CONF_SG_TEMP_PARAM_10, | ||
334 | |||
335 | CONF_SG_PARAMS_MAX, | ||
336 | CONF_SG_PARAMS_ALL = 0xff | ||
337 | }; | ||
338 | |||
339 | struct conf_sg_settings { | ||
340 | u32 params[CONF_SG_PARAMS_MAX]; | ||
341 | u8 state; | ||
342 | }; | ||
343 | |||
344 | enum conf_rx_queue_type { | ||
345 | CONF_RX_QUEUE_TYPE_LOW_PRIORITY, /* All except the high priority */ | ||
346 | CONF_RX_QUEUE_TYPE_HIGH_PRIORITY, /* Management and voice packets */ | ||
347 | }; | ||
348 | |||
349 | struct conf_rx_settings { | ||
350 | /* | ||
351 | * The maximum amount of time, in TU, before the | ||
352 | * firmware discards the MSDU. | ||
353 | * | ||
354 | * Range: 0 - 0xFFFFFFFF | ||
355 | */ | ||
356 | u32 rx_msdu_life_time; | ||
357 | |||
358 | /* | ||
359 | * Packet detection threshold in the PHY. | ||
360 | * | ||
361 | * FIXME: details unknown. | ||
362 | */ | ||
363 | u32 packet_detection_threshold; | ||
364 | |||
365 | /* | ||
366 | * The longest time the STA will wait to receive traffic from the AP | ||
367 | * after a PS-poll has been transmitted. | ||
368 | * | ||
369 | * Range: 0 - 200000 | ||
370 | */ | ||
371 | u16 ps_poll_timeout; | ||
372 | /* | ||
373 | * The longest time the STA will wait to receive traffic from the AP | ||
374 | * after a frame has been sent from an UPSD enabled queue. | ||
375 | * | ||
376 | * Range: 0 - 200000 | ||
377 | */ | ||
378 | u16 upsd_timeout; | ||
379 | |||
380 | /* | ||
381 | * The number of octets in an MPDU, below which an RTS/CTS | ||
382 | * handshake is not performed. | ||
383 | * | ||
384 | * Range: 0 - 4096 | ||
385 | */ | ||
386 | u16 rts_threshold; | ||
387 | |||
388 | /* | ||
389 | * The RX Clear Channel Assessment threshold in the PHY | ||
390 | * (the energy threshold). | ||
391 | * | ||
392 | * Range: ENABLE_ENERGY_D == 0x140A | ||
393 | * DISABLE_ENERGY_D == 0xFFEF | ||
394 | */ | ||
395 | u16 rx_cca_threshold; | ||
396 | |||
397 | /* | ||
398 | * Occupied Rx mem-blocks number which requires interrupting the host | ||
399 | * (0 = no buffering, 0xffff = disabled). | ||
400 | * | ||
401 | * Range: u16 | ||
402 | */ | ||
403 | u16 irq_blk_threshold; | ||
404 | |||
405 | /* | ||
406 | * Rx packets number which requires interrupting the host | ||
407 | * (0 = no buffering). | ||
408 | * | ||
409 | * Range: u16 | ||
410 | */ | ||
411 | u16 irq_pkt_threshold; | ||
412 | |||
413 | /* | ||
414 | * Max time in msec the FW may delay RX-Complete interrupt. | ||
415 | * | ||
416 | * Range: 1 - 100 | ||
417 | */ | ||
418 | u16 irq_timeout; | ||
419 | |||
420 | /* | ||
421 | * The RX queue type. | ||
422 | * | ||
423 | * Range: RX_QUEUE_TYPE_RX_LOW_PRIORITY, RX_QUEUE_TYPE_RX_HIGH_PRIORITY, | ||
424 | */ | ||
425 | u8 queue_type; | ||
426 | }; | ||
427 | |||
428 | #define CONF_TX_MAX_RATE_CLASSES 10 | ||
429 | |||
430 | #define CONF_TX_RATE_MASK_UNSPECIFIED 0 | ||
431 | #define CONF_TX_RATE_MASK_BASIC (CONF_HW_BIT_RATE_1MBPS | \ | ||
432 | CONF_HW_BIT_RATE_2MBPS) | ||
433 | #define CONF_TX_RATE_RETRY_LIMIT 10 | ||
434 | |||
435 | /* basic rates for p2p operations (probe req/resp, etc.) */ | ||
436 | #define CONF_TX_RATE_MASK_BASIC_P2P (CONF_HW_BIT_RATE_6MBPS | \ | ||
437 | CONF_HW_BIT_RATE_12MBPS | CONF_HW_BIT_RATE_24MBPS) | ||
438 | |||
439 | /* | ||
440 | * Rates supported for data packets when operating as AP. Note the absence | ||
441 | * of the 22Mbps rate. There is a FW limitation on 12 rates so we must drop | ||
442 | * one. The rate dropped is not mandatory under any operating mode. | ||
443 | */ | ||
444 | #define CONF_TX_AP_ENABLED_RATES (CONF_HW_BIT_RATE_1MBPS | \ | ||
445 | CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS | \ | ||
446 | CONF_HW_BIT_RATE_6MBPS | CONF_HW_BIT_RATE_9MBPS | \ | ||
447 | CONF_HW_BIT_RATE_11MBPS | CONF_HW_BIT_RATE_12MBPS | \ | ||
448 | CONF_HW_BIT_RATE_18MBPS | CONF_HW_BIT_RATE_24MBPS | \ | ||
449 | CONF_HW_BIT_RATE_36MBPS | CONF_HW_BIT_RATE_48MBPS | \ | ||
450 | CONF_HW_BIT_RATE_54MBPS) | ||
451 | |||
452 | #define CONF_TX_CCK_RATES (CONF_HW_BIT_RATE_1MBPS | \ | ||
453 | CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS | \ | ||
454 | CONF_HW_BIT_RATE_11MBPS) | ||
455 | |||
456 | #define CONF_TX_OFDM_RATES (CONF_HW_BIT_RATE_6MBPS | \ | ||
457 | CONF_HW_BIT_RATE_12MBPS | CONF_HW_BIT_RATE_24MBPS | \ | ||
458 | CONF_HW_BIT_RATE_36MBPS | CONF_HW_BIT_RATE_48MBPS | \ | ||
459 | CONF_HW_BIT_RATE_54MBPS) | ||
460 | |||
461 | #define CONF_TX_MCS_RATES (CONF_HW_BIT_RATE_MCS_0 | \ | ||
462 | CONF_HW_BIT_RATE_MCS_1 | CONF_HW_BIT_RATE_MCS_2 | \ | ||
463 | CONF_HW_BIT_RATE_MCS_3 | CONF_HW_BIT_RATE_MCS_4 | \ | ||
464 | CONF_HW_BIT_RATE_MCS_5 | CONF_HW_BIT_RATE_MCS_6 | \ | ||
465 | CONF_HW_BIT_RATE_MCS_7) | ||
466 | |||
467 | /* | ||
468 | * Default rates for management traffic when operating in AP mode. This | ||
469 | * should be configured according to the basic rate set of the AP | ||
470 | */ | ||
471 | #define CONF_TX_AP_DEFAULT_MGMT_RATES (CONF_HW_BIT_RATE_1MBPS | \ | ||
472 | CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS) | ||
473 | |||
474 | /* default rates for working as IBSS (11b and OFDM) */ | ||
475 | #define CONF_TX_IBSS_DEFAULT_RATES (CONF_HW_BIT_RATE_1MBPS | \ | ||
476 | CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS | \ | ||
477 | CONF_HW_BIT_RATE_11MBPS | CONF_TX_OFDM_RATES); | ||
478 | |||
479 | struct conf_tx_rate_class { | ||
480 | |||
481 | /* | ||
482 | * The rates enabled for this rate class. | ||
483 | * | ||
484 | * Range: CONF_HW_BIT_RATE_* bit mask | ||
485 | */ | ||
486 | u32 enabled_rates; | ||
487 | |||
488 | /* | ||
489 | * The dot11 short retry limit used for TX retries. | ||
490 | * | ||
491 | * Range: u8 | ||
492 | */ | ||
493 | u8 short_retry_limit; | ||
494 | |||
495 | /* | ||
496 | * The dot11 long retry limit used for TX retries. | ||
497 | * | ||
498 | * Range: u8 | ||
499 | */ | ||
500 | u8 long_retry_limit; | ||
501 | |||
502 | /* | ||
503 | * Flags controlling the attributes of TX transmission. | ||
504 | * | ||
505 | * Range: bit 0: Truncate - when set, FW attempts to send a frame stop | ||
506 | * when the total valid per-rate attempts have | ||
507 | * been exhausted; otherwise transmissions | ||
508 | * will continue at the lowest available rate | ||
509 | * until the appropriate one of the | ||
510 | * short_retry_limit, long_retry_limit, | ||
511 | * dot11_max_transmit_msdu_life_time, or | ||
512 | * max_tx_life_time, is exhausted. | ||
513 | * 1: Preamble Override - indicates if the preamble type | ||
514 | * should be used in TX. | ||
515 | * 2: Preamble Type - the type of the preamble to be used by | ||
516 | * the policy (0 - long preamble, 1 - short preamble. | ||
517 | */ | ||
518 | u8 aflags; | ||
519 | }; | ||
520 | |||
521 | #define CONF_TX_MAX_AC_COUNT 4 | ||
522 | |||
523 | /* Slot number setting to start transmission at PIFS interval */ | ||
524 | #define CONF_TX_AIFS_PIFS 1 | ||
525 | /* Slot number setting to start transmission at DIFS interval normal | ||
526 | * DCF access */ | ||
527 | #define CONF_TX_AIFS_DIFS 2 | ||
528 | |||
529 | |||
530 | enum conf_tx_ac { | ||
531 | CONF_TX_AC_BE = 0, /* best effort / legacy */ | ||
532 | CONF_TX_AC_BK = 1, /* background */ | ||
533 | CONF_TX_AC_VI = 2, /* video */ | ||
534 | CONF_TX_AC_VO = 3, /* voice */ | ||
535 | CONF_TX_AC_CTS2SELF = 4, /* fictitious AC, follows AC_VO */ | ||
536 | CONF_TX_AC_ANY_TID = 0x1f | ||
537 | }; | ||
538 | |||
539 | struct conf_tx_ac_category { | ||
540 | /* | ||
541 | * The AC class identifier. | ||
542 | * | ||
543 | * Range: enum conf_tx_ac | ||
544 | */ | ||
545 | u8 ac; | ||
546 | |||
547 | /* | ||
548 | * The contention window minimum size (in slots) for the access | ||
549 | * class. | ||
550 | * | ||
551 | * Range: u8 | ||
552 | */ | ||
553 | u8 cw_min; | ||
554 | |||
555 | /* | ||
556 | * The contention window maximum size (in slots) for the access | ||
557 | * class. | ||
558 | * | ||
559 | * Range: u8 | ||
560 | */ | ||
561 | u16 cw_max; | ||
562 | |||
563 | /* | ||
564 | * The AIF value (in slots) for the access class. | ||
565 | * | ||
566 | * Range: u8 | ||
567 | */ | ||
568 | u8 aifsn; | ||
569 | |||
570 | /* | ||
571 | * The TX Op Limit (in microseconds) for the access class. | ||
572 | * | ||
573 | * Range: u16 | ||
574 | */ | ||
575 | u16 tx_op_limit; | ||
576 | }; | ||
577 | |||
578 | #define CONF_TX_MAX_TID_COUNT 8 | ||
579 | |||
580 | /* Allow TX BA on all TIDs but 6,7. These are currently reserved in the FW */ | ||
581 | #define CONF_TX_BA_ENABLED_TID_BITMAP 0x3F | ||
582 | |||
583 | enum { | ||
584 | CONF_CHANNEL_TYPE_DCF = 0, /* DC/LEGACY*/ | ||
585 | CONF_CHANNEL_TYPE_EDCF = 1, /* EDCA*/ | ||
586 | CONF_CHANNEL_TYPE_HCCA = 2, /* HCCA*/ | ||
587 | }; | ||
588 | |||
589 | enum { | ||
590 | CONF_PS_SCHEME_LEGACY = 0, | ||
591 | CONF_PS_SCHEME_UPSD_TRIGGER = 1, | ||
592 | CONF_PS_SCHEME_LEGACY_PSPOLL = 2, | ||
593 | CONF_PS_SCHEME_SAPSD = 3, | ||
594 | }; | ||
595 | |||
596 | enum { | ||
597 | CONF_ACK_POLICY_LEGACY = 0, | ||
598 | CONF_ACK_POLICY_NO_ACK = 1, | ||
599 | CONF_ACK_POLICY_BLOCK = 2, | ||
600 | }; | ||
601 | |||
602 | |||
603 | struct conf_tx_tid { | ||
604 | u8 queue_id; | ||
605 | u8 channel_type; | ||
606 | u8 tsid; | ||
607 | u8 ps_scheme; | ||
608 | u8 ack_policy; | ||
609 | u32 apsd_conf[2]; | ||
610 | }; | ||
611 | |||
612 | struct conf_tx_settings { | ||
613 | /* | ||
614 | * The TX ED value for TELEC Enable/Disable. | ||
615 | * | ||
616 | * Range: 0, 1 | ||
617 | */ | ||
618 | u8 tx_energy_detection; | ||
619 | |||
620 | /* | ||
621 | * Configuration for rate classes for TX (currently only one | ||
622 | * rate class supported). Used in non-AP mode. | ||
623 | */ | ||
624 | struct conf_tx_rate_class sta_rc_conf; | ||
625 | |||
626 | /* | ||
627 | * Configuration for access categories for TX rate control. | ||
628 | */ | ||
629 | u8 ac_conf_count; | ||
630 | struct conf_tx_ac_category ac_conf[CONF_TX_MAX_AC_COUNT]; | ||
631 | |||
632 | /* | ||
633 | * AP-mode - allow this number of TX retries to a station before an | ||
634 | * event is triggered from FW. | ||
635 | * In AP-mode the hlids of unreachable stations are given in the | ||
636 | * "sta_tx_retry_exceeded" member in the event mailbox. | ||
637 | */ | ||
638 | u8 max_tx_retries; | ||
639 | |||
640 | /* | ||
641 | * AP-mode - after this number of seconds a connected station is | ||
642 | * considered inactive. | ||
643 | */ | ||
644 | u16 ap_aging_period; | ||
645 | |||
646 | /* | ||
647 | * Configuration for TID parameters. | ||
648 | */ | ||
649 | u8 tid_conf_count; | ||
650 | struct conf_tx_tid tid_conf[CONF_TX_MAX_TID_COUNT]; | ||
651 | |||
652 | /* | ||
653 | * The TX fragmentation threshold. | ||
654 | * | ||
655 | * Range: u16 | ||
656 | */ | ||
657 | u16 frag_threshold; | ||
658 | |||
659 | /* | ||
660 | * Max time in msec the FW may delay frame TX-Complete interrupt. | ||
661 | * | ||
662 | * Range: u16 | ||
663 | */ | ||
664 | u16 tx_compl_timeout; | ||
665 | |||
666 | /* | ||
667 | * Completed TX packet count which requires to issue the TX-Complete | ||
668 | * interrupt. | ||
669 | * | ||
670 | * Range: u16 | ||
671 | */ | ||
672 | u16 tx_compl_threshold; | ||
673 | |||
674 | /* | ||
675 | * The rate used for control messages and scanning on the 2.4GHz band | ||
676 | * | ||
677 | * Range: CONF_HW_BIT_RATE_* bit mask | ||
678 | */ | ||
679 | u32 basic_rate; | ||
680 | |||
681 | /* | ||
682 | * The rate used for control messages and scanning on the 5GHz band | ||
683 | * | ||
684 | * Range: CONF_HW_BIT_RATE_* bit mask | ||
685 | */ | ||
686 | u32 basic_rate_5; | ||
687 | |||
688 | /* | ||
689 | * TX retry limits for templates | ||
690 | */ | ||
691 | u8 tmpl_short_retry_limit; | ||
692 | u8 tmpl_long_retry_limit; | ||
693 | |||
694 | /* Time in ms for Tx watchdog timer to expire */ | ||
695 | u32 tx_watchdog_timeout; | ||
696 | }; | ||
697 | |||
698 | enum { | ||
699 | CONF_WAKE_UP_EVENT_BEACON = 0x01, /* Wake on every Beacon*/ | ||
700 | CONF_WAKE_UP_EVENT_DTIM = 0x02, /* Wake on every DTIM*/ | ||
701 | CONF_WAKE_UP_EVENT_N_DTIM = 0x04, /* Wake every Nth DTIM */ | ||
702 | CONF_WAKE_UP_EVENT_N_BEACONS = 0x08, /* Wake every Nth beacon */ | ||
703 | CONF_WAKE_UP_EVENT_BITS_MASK = 0x0F | ||
704 | }; | ||
705 | |||
706 | #define CONF_MAX_BCN_FILT_IE_COUNT 32 | ||
707 | |||
708 | #define CONF_BCN_RULE_PASS_ON_CHANGE BIT(0) | ||
709 | #define CONF_BCN_RULE_PASS_ON_APPEARANCE BIT(1) | ||
710 | |||
711 | #define CONF_BCN_IE_OUI_LEN 3 | ||
712 | #define CONF_BCN_IE_VER_LEN 2 | ||
713 | |||
714 | struct conf_bcn_filt_rule { | ||
715 | /* | ||
716 | * IE number to which to associate a rule. | ||
717 | * | ||
718 | * Range: u8 | ||
719 | */ | ||
720 | u8 ie; | ||
721 | |||
722 | /* | ||
723 | * Rule to associate with the specific ie. | ||
724 | * | ||
725 | * Range: CONF_BCN_RULE_PASS_ON_* | ||
726 | */ | ||
727 | u8 rule; | ||
728 | |||
729 | /* | ||
730 | * OUI for the vendor specifie IE (221) | ||
731 | */ | ||
732 | u8 oui[CONF_BCN_IE_OUI_LEN]; | ||
733 | |||
734 | /* | ||
735 | * Type for the vendor specifie IE (221) | ||
736 | */ | ||
737 | u8 type; | ||
738 | |||
739 | /* | ||
740 | * Version for the vendor specifie IE (221) | ||
741 | */ | ||
742 | u8 version[CONF_BCN_IE_VER_LEN]; | ||
743 | }; | ||
744 | |||
745 | #define CONF_MAX_RSSI_SNR_TRIGGERS 8 | ||
746 | |||
747 | enum { | ||
748 | CONF_TRIG_METRIC_RSSI_BEACON = 0, | ||
749 | CONF_TRIG_METRIC_RSSI_DATA, | ||
750 | CONF_TRIG_METRIC_SNR_BEACON, | ||
751 | CONF_TRIG_METRIC_SNR_DATA | ||
752 | }; | ||
753 | |||
754 | enum { | ||
755 | CONF_TRIG_EVENT_TYPE_LEVEL = 0, | ||
756 | CONF_TRIG_EVENT_TYPE_EDGE | ||
757 | }; | ||
758 | |||
759 | enum { | ||
760 | CONF_TRIG_EVENT_DIR_LOW = 0, | ||
761 | CONF_TRIG_EVENT_DIR_HIGH, | ||
762 | CONF_TRIG_EVENT_DIR_BIDIR | ||
763 | }; | ||
764 | |||
765 | struct conf_sig_weights { | ||
766 | |||
767 | /* | ||
768 | * RSSI from beacons average weight. | ||
769 | * | ||
770 | * Range: u8 | ||
771 | */ | ||
772 | u8 rssi_bcn_avg_weight; | ||
773 | |||
774 | /* | ||
775 | * RSSI from data average weight. | ||
776 | * | ||
777 | * Range: u8 | ||
778 | */ | ||
779 | u8 rssi_pkt_avg_weight; | ||
780 | |||
781 | /* | ||
782 | * SNR from beacons average weight. | ||
783 | * | ||
784 | * Range: u8 | ||
785 | */ | ||
786 | u8 snr_bcn_avg_weight; | ||
787 | |||
788 | /* | ||
789 | * SNR from data average weight. | ||
790 | * | ||
791 | * Range: u8 | ||
792 | */ | ||
793 | u8 snr_pkt_avg_weight; | ||
794 | }; | ||
795 | |||
796 | enum conf_bcn_filt_mode { | ||
797 | CONF_BCN_FILT_MODE_DISABLED = 0, | ||
798 | CONF_BCN_FILT_MODE_ENABLED = 1 | ||
799 | }; | ||
800 | |||
801 | enum conf_bet_mode { | ||
802 | CONF_BET_MODE_DISABLE = 0, | ||
803 | CONF_BET_MODE_ENABLE = 1, | ||
804 | }; | ||
805 | |||
806 | struct conf_conn_settings { | ||
807 | /* | ||
808 | * Firmware wakeup conditions configuration. The host may set only | ||
809 | * one bit. | ||
810 | * | ||
811 | * Range: CONF_WAKE_UP_EVENT_* | ||
812 | */ | ||
813 | u8 wake_up_event; | ||
814 | |||
815 | /* | ||
816 | * Listen interval for beacons or Dtims. | ||
817 | * | ||
818 | * Range: 0 for beacon and Dtim wakeup | ||
819 | * 1-10 for x Dtims | ||
820 | * 1-255 for x beacons | ||
821 | */ | ||
822 | u8 listen_interval; | ||
823 | |||
824 | /* | ||
825 | * Firmware wakeup conditions during suspend | ||
826 | * Range: CONF_WAKE_UP_EVENT_* | ||
827 | */ | ||
828 | u8 suspend_wake_up_event; | ||
829 | |||
830 | /* | ||
831 | * Listen interval during suspend. | ||
832 | * Currently will be in DTIMs (1-10) | ||
833 | * | ||
834 | */ | ||
835 | u8 suspend_listen_interval; | ||
836 | |||
837 | /* | ||
838 | * Enable or disable the beacon filtering. | ||
839 | * | ||
840 | * Range: CONF_BCN_FILT_MODE_* | ||
841 | */ | ||
842 | enum conf_bcn_filt_mode bcn_filt_mode; | ||
843 | |||
844 | /* | ||
845 | * Configure Beacon filter pass-thru rules. | ||
846 | */ | ||
847 | u8 bcn_filt_ie_count; | ||
848 | struct conf_bcn_filt_rule bcn_filt_ie[CONF_MAX_BCN_FILT_IE_COUNT]; | ||
849 | |||
850 | /* | ||
851 | * The number of consecutive beacons to lose, before the firmware | ||
852 | * becomes out of synch. | ||
853 | * | ||
854 | * Range: u32 | ||
855 | */ | ||
856 | u32 synch_fail_thold; | ||
857 | |||
858 | /* | ||
859 | * After out-of-synch, the number of TU's to wait without a further | ||
860 | * received beacon (or probe response) before issuing the BSS_EVENT_LOSE | ||
861 | * event. | ||
862 | * | ||
863 | * Range: u32 | ||
864 | */ | ||
865 | u32 bss_lose_timeout; | ||
866 | |||
867 | /* | ||
868 | * Beacon receive timeout. | ||
869 | * | ||
870 | * Range: u32 | ||
871 | */ | ||
872 | u32 beacon_rx_timeout; | ||
873 | |||
874 | /* | ||
875 | * Broadcast receive timeout. | ||
876 | * | ||
877 | * Range: u32 | ||
878 | */ | ||
879 | u32 broadcast_timeout; | ||
880 | |||
881 | /* | ||
882 | * Enable/disable reception of broadcast packets in power save mode | ||
883 | * | ||
884 | * Range: 1 - enable, 0 - disable | ||
885 | */ | ||
886 | u8 rx_broadcast_in_ps; | ||
887 | |||
888 | /* | ||
889 | * Consecutive PS Poll failures before sending event to driver | ||
890 | * | ||
891 | * Range: u8 | ||
892 | */ | ||
893 | u8 ps_poll_threshold; | ||
894 | |||
895 | /* | ||
896 | * Configuration of signal average weights. | ||
897 | */ | ||
898 | struct conf_sig_weights sig_weights; | ||
899 | |||
900 | /* | ||
901 | * Specifies if beacon early termination procedure is enabled or | ||
902 | * disabled. | ||
903 | * | ||
904 | * Range: CONF_BET_MODE_* | ||
905 | */ | ||
906 | u8 bet_enable; | ||
907 | |||
908 | /* | ||
909 | * Specifies the maximum number of consecutive beacons that may be | ||
910 | * early terminated. After this number is reached at least one full | ||
911 | * beacon must be correctly received in FW before beacon ET | ||
912 | * resumes. | ||
913 | * | ||
914 | * Range 0 - 255 | ||
915 | */ | ||
916 | u8 bet_max_consecutive; | ||
917 | |||
918 | /* | ||
919 | * Specifies the maximum number of times to try PSM entry if it fails | ||
920 | * (if sending the appropriate null-func message fails.) | ||
921 | * | ||
922 | * Range 0 - 255 | ||
923 | */ | ||
924 | u8 psm_entry_retries; | ||
925 | |||
926 | /* | ||
927 | * Specifies the maximum number of times to try PSM exit if it fails | ||
928 | * (if sending the appropriate null-func message fails.) | ||
929 | * | ||
930 | * Range 0 - 255 | ||
931 | */ | ||
932 | u8 psm_exit_retries; | ||
933 | |||
934 | /* | ||
935 | * Specifies the maximum number of times to try transmit the PSM entry | ||
936 | * null-func frame for each PSM entry attempt | ||
937 | * | ||
938 | * Range 0 - 255 | ||
939 | */ | ||
940 | u8 psm_entry_nullfunc_retries; | ||
941 | |||
942 | /* | ||
943 | * Specifies the dynamic PS timeout in ms that will be used | ||
944 | * by the FW when in AUTO_PS mode | ||
945 | */ | ||
946 | u16 dynamic_ps_timeout; | ||
947 | |||
948 | /* | ||
949 | * Specifies whether dynamic PS should be disabled and PSM forced. | ||
950 | * This is required for certain WiFi certification tests. | ||
951 | */ | ||
952 | u8 forced_ps; | ||
953 | |||
954 | /* | ||
955 | * | ||
956 | * Specifies the interval of the connection keep-alive null-func | ||
957 | * frame in ms. | ||
958 | * | ||
959 | * Range: 1000 - 3600000 | ||
960 | */ | ||
961 | u32 keep_alive_interval; | ||
962 | |||
963 | /* | ||
964 | * Maximum listen interval supported by the driver in units of beacons. | ||
965 | * | ||
966 | * Range: u16 | ||
967 | */ | ||
968 | u8 max_listen_interval; | ||
969 | }; | ||
970 | |||
971 | enum { | ||
972 | CONF_REF_CLK_19_2_E, | ||
973 | CONF_REF_CLK_26_E, | ||
974 | CONF_REF_CLK_38_4_E, | ||
975 | CONF_REF_CLK_52_E, | ||
976 | CONF_REF_CLK_38_4_M_XTAL, | ||
977 | CONF_REF_CLK_26_M_XTAL, | ||
978 | }; | ||
979 | |||
980 | enum single_dual_band_enum { | ||
981 | CONF_SINGLE_BAND, | ||
982 | CONF_DUAL_BAND | ||
983 | }; | ||
984 | |||
985 | #define CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE 15 | ||
986 | #define CONF_NUMBER_OF_SUB_BANDS_5 7 | ||
987 | #define CONF_NUMBER_OF_RATE_GROUPS 6 | ||
988 | #define CONF_NUMBER_OF_CHANNELS_2_4 14 | ||
989 | #define CONF_NUMBER_OF_CHANNELS_5 35 | ||
990 | |||
991 | struct conf_itrim_settings { | ||
992 | /* enable dco itrim */ | ||
993 | u8 enable; | ||
994 | |||
995 | /* moderation timeout in microsecs from the last TX */ | ||
996 | u32 timeout; | ||
997 | }; | ||
998 | |||
999 | struct conf_pm_config_settings { | ||
1000 | /* | ||
1001 | * Host clock settling time | ||
1002 | * | ||
1003 | * Range: 0 - 30000 us | ||
1004 | */ | ||
1005 | u32 host_clk_settling_time; | ||
1006 | |||
1007 | /* | ||
1008 | * Host fast wakeup support | ||
1009 | * | ||
1010 | * Range: true, false | ||
1011 | */ | ||
1012 | bool host_fast_wakeup_support; | ||
1013 | }; | ||
1014 | |||
1015 | struct conf_roam_trigger_settings { | ||
1016 | /* | ||
1017 | * The minimum interval between two trigger events. | ||
1018 | * | ||
1019 | * Range: 0 - 60000 ms | ||
1020 | */ | ||
1021 | u16 trigger_pacing; | ||
1022 | |||
1023 | /* | ||
1024 | * The weight for rssi/beacon average calculation | ||
1025 | * | ||
1026 | * Range: 0 - 255 | ||
1027 | */ | ||
1028 | u8 avg_weight_rssi_beacon; | ||
1029 | |||
1030 | /* | ||
1031 | * The weight for rssi/data frame average calculation | ||
1032 | * | ||
1033 | * Range: 0 - 255 | ||
1034 | */ | ||
1035 | u8 avg_weight_rssi_data; | ||
1036 | |||
1037 | /* | ||
1038 | * The weight for snr/beacon average calculation | ||
1039 | * | ||
1040 | * Range: 0 - 255 | ||
1041 | */ | ||
1042 | u8 avg_weight_snr_beacon; | ||
1043 | |||
1044 | /* | ||
1045 | * The weight for snr/data frame average calculation | ||
1046 | * | ||
1047 | * Range: 0 - 255 | ||
1048 | */ | ||
1049 | u8 avg_weight_snr_data; | ||
1050 | }; | ||
1051 | |||
1052 | struct conf_scan_settings { | ||
1053 | /* | ||
1054 | * The minimum time to wait on each channel for active scans | ||
1055 | * | ||
1056 | * Range: u32 tu/1000 | ||
1057 | */ | ||
1058 | u32 min_dwell_time_active; | ||
1059 | |||
1060 | /* | ||
1061 | * The maximum time to wait on each channel for active scans | ||
1062 | * | ||
1063 | * Range: u32 tu/1000 | ||
1064 | */ | ||
1065 | u32 max_dwell_time_active; | ||
1066 | |||
1067 | /* | ||
1068 | * The minimum time to wait on each channel for passive scans | ||
1069 | * | ||
1070 | * Range: u32 tu/1000 | ||
1071 | */ | ||
1072 | u32 min_dwell_time_passive; | ||
1073 | |||
1074 | /* | ||
1075 | * The maximum time to wait on each channel for passive scans | ||
1076 | * | ||
1077 | * Range: u32 tu/1000 | ||
1078 | */ | ||
1079 | u32 max_dwell_time_passive; | ||
1080 | |||
1081 | /* | ||
1082 | * Number of probe requests to transmit on each active scan channel | ||
1083 | * | ||
1084 | * Range: u8 | ||
1085 | */ | ||
1086 | u16 num_probe_reqs; | ||
1087 | |||
1088 | /* | ||
1089 | * Scan trigger (split scan) timeout. The FW will split the scan | ||
1090 | * operation into slices of the given time and allow the FW to schedule | ||
1091 | * other tasks in between. | ||
1092 | * | ||
1093 | * Range: u32 Microsecs | ||
1094 | */ | ||
1095 | u32 split_scan_timeout; | ||
1096 | }; | ||
1097 | |||
1098 | struct conf_sched_scan_settings { | ||
1099 | /* | ||
1100 | * The base time to wait on the channel for active scans (in TU/1000). | ||
1101 | * The minimum dwell time is calculated according to this: | ||
1102 | * min_dwell_time = base + num_of_probes_to_be_sent * delta_per_probe | ||
1103 | * The maximum dwell time is calculated according to this: | ||
1104 | * max_dwell_time = min_dwell_time + max_dwell_time_delta | ||
1105 | */ | ||
1106 | u32 base_dwell_time; | ||
1107 | |||
1108 | /* The delta between the min dwell time and max dwell time for | ||
1109 | * active scans (in TU/1000s). The max dwell time is used by the FW once | ||
1110 | * traffic is detected on the channel. | ||
1111 | */ | ||
1112 | u32 max_dwell_time_delta; | ||
1113 | |||
1114 | /* Delta added to min dwell time per each probe in 2.4 GHz (TU/1000) */ | ||
1115 | u32 dwell_time_delta_per_probe; | ||
1116 | |||
1117 | /* Delta added to min dwell time per each probe in 5 GHz (TU/1000) */ | ||
1118 | u32 dwell_time_delta_per_probe_5; | ||
1119 | |||
1120 | /* time to wait on the channel for passive scans (in TU/1000) */ | ||
1121 | u32 dwell_time_passive; | ||
1122 | |||
1123 | /* time to wait on the channel for DFS scans (in TU/1000) */ | ||
1124 | u32 dwell_time_dfs; | ||
1125 | |||
1126 | /* number of probe requests to send on each channel in active scans */ | ||
1127 | u8 num_probe_reqs; | ||
1128 | |||
1129 | /* RSSI threshold to be used for filtering */ | ||
1130 | s8 rssi_threshold; | ||
1131 | |||
1132 | /* SNR threshold to be used for filtering */ | ||
1133 | s8 snr_threshold; | ||
1134 | }; | ||
1135 | |||
1136 | /* these are number of channels on the band divided by two, rounded up */ | ||
1137 | #define CONF_TX_PWR_COMPENSATION_LEN_2 7 | ||
1138 | #define CONF_TX_PWR_COMPENSATION_LEN_5 18 | ||
1139 | |||
1140 | struct conf_rf_settings { | ||
1141 | /* | ||
1142 | * Per channel power compensation for 2.4GHz | ||
1143 | * | ||
1144 | * Range: s8 | ||
1145 | */ | ||
1146 | u8 tx_per_channel_power_compensation_2[CONF_TX_PWR_COMPENSATION_LEN_2]; | ||
1147 | |||
1148 | /* | ||
1149 | * Per channel power compensation for 5GHz | ||
1150 | * | ||
1151 | * Range: s8 | ||
1152 | */ | ||
1153 | u8 tx_per_channel_power_compensation_5[CONF_TX_PWR_COMPENSATION_LEN_5]; | ||
1154 | }; | ||
1155 | |||
1156 | struct conf_ht_setting { | ||
1157 | u8 rx_ba_win_size; | ||
1158 | u8 tx_ba_win_size; | ||
1159 | u16 inactivity_timeout; | ||
1160 | |||
1161 | /* bitmap of enabled TIDs for TX BA sessions */ | ||
1162 | u8 tx_ba_tid_bitmap; | ||
1163 | }; | ||
1164 | |||
1165 | struct conf_memory_settings { | ||
1166 | /* Number of stations supported in IBSS mode */ | ||
1167 | u8 num_stations; | ||
1168 | |||
1169 | /* Number of ssid profiles used in IBSS mode */ | ||
1170 | u8 ssid_profiles; | ||
1171 | |||
1172 | /* Number of memory buffers allocated to rx pool */ | ||
1173 | u8 rx_block_num; | ||
1174 | |||
1175 | /* Minimum number of blocks allocated to tx pool */ | ||
1176 | u8 tx_min_block_num; | ||
1177 | |||
1178 | /* Disable/Enable dynamic memory */ | ||
1179 | u8 dynamic_memory; | ||
1180 | |||
1181 | /* | ||
1182 | * Minimum required free tx memory blocks in order to assure optimum | ||
1183 | * performance | ||
1184 | * | ||
1185 | * Range: 0-120 | ||
1186 | */ | ||
1187 | u8 min_req_tx_blocks; | ||
1188 | |||
1189 | /* | ||
1190 | * Minimum required free rx memory blocks in order to assure optimum | ||
1191 | * performance | ||
1192 | * | ||
1193 | * Range: 0-120 | ||
1194 | */ | ||
1195 | u8 min_req_rx_blocks; | ||
1196 | |||
1197 | /* | ||
1198 | * Minimum number of mem blocks (free+used) guaranteed for TX | ||
1199 | * | ||
1200 | * Range: 0-120 | ||
1201 | */ | ||
1202 | u8 tx_min; | ||
1203 | }; | ||
1204 | |||
1205 | struct conf_fm_coex { | ||
1206 | u8 enable; | ||
1207 | u8 swallow_period; | ||
1208 | u8 n_divider_fref_set_1; | ||
1209 | u8 n_divider_fref_set_2; | ||
1210 | u16 m_divider_fref_set_1; | ||
1211 | u16 m_divider_fref_set_2; | ||
1212 | u32 coex_pll_stabilization_time; | ||
1213 | u16 ldo_stabilization_time; | ||
1214 | u8 fm_disturbed_band_margin; | ||
1215 | u8 swallow_clk_diff; | ||
1216 | }; | ||
1217 | |||
1218 | struct conf_rx_streaming_settings { | ||
1219 | /* | ||
1220 | * RX Streaming duration (in msec) from last tx/rx | ||
1221 | * | ||
1222 | * Range: u32 | ||
1223 | */ | ||
1224 | u32 duration; | ||
1225 | |||
1226 | /* | ||
1227 | * Bitmap of tids to be polled during RX streaming. | ||
1228 | * (Note: it doesn't look like it really matters) | ||
1229 | * | ||
1230 | * Range: 0x1-0xff | ||
1231 | */ | ||
1232 | u8 queues; | ||
1233 | |||
1234 | /* | ||
1235 | * RX Streaming interval. | ||
1236 | * (Note:this value is also used as the rx streaming timeout) | ||
1237 | * Range: 0 (disabled), 10 - 100 | ||
1238 | */ | ||
1239 | u8 interval; | ||
1240 | |||
1241 | /* | ||
1242 | * enable rx streaming also when there is no coex activity | ||
1243 | */ | ||
1244 | u8 always; | ||
1245 | }; | ||
1246 | |||
1247 | struct conf_fwlog { | ||
1248 | /* Continuous or on-demand */ | ||
1249 | u8 mode; | ||
1250 | |||
1251 | /* | ||
1252 | * Number of memory blocks dedicated for the FW logger | ||
1253 | * | ||
1254 | * Range: 1-3, or 0 to disable the FW logger | ||
1255 | */ | ||
1256 | u8 mem_blocks; | ||
1257 | |||
1258 | /* Minimum log level threshold */ | ||
1259 | u8 severity; | ||
1260 | |||
1261 | /* Include/exclude timestamps from the log messages */ | ||
1262 | u8 timestamp; | ||
1263 | |||
1264 | /* See enum wl1271_fwlogger_output */ | ||
1265 | u8 output; | ||
1266 | |||
1267 | /* Regulates the frequency of log messages */ | ||
1268 | u8 threshold; | ||
1269 | }; | ||
1270 | |||
1271 | #define ACX_RATE_MGMT_NUM_OF_RATES 13 | ||
1272 | struct conf_rate_policy_settings { | ||
1273 | u16 rate_retry_score; | ||
1274 | u16 per_add; | ||
1275 | u16 per_th1; | ||
1276 | u16 per_th2; | ||
1277 | u16 max_per; | ||
1278 | u8 inverse_curiosity_factor; | ||
1279 | u8 tx_fail_low_th; | ||
1280 | u8 tx_fail_high_th; | ||
1281 | u8 per_alpha_shift; | ||
1282 | u8 per_add_shift; | ||
1283 | u8 per_beta1_shift; | ||
1284 | u8 per_beta2_shift; | ||
1285 | u8 rate_check_up; | ||
1286 | u8 rate_check_down; | ||
1287 | u8 rate_retry_policy[ACX_RATE_MGMT_NUM_OF_RATES]; | ||
1288 | }; | ||
1289 | |||
1290 | struct conf_hangover_settings { | ||
1291 | u32 recover_time; | ||
1292 | u8 hangover_period; | ||
1293 | u8 dynamic_mode; | ||
1294 | u8 early_termination_mode; | ||
1295 | u8 max_period; | ||
1296 | u8 min_period; | ||
1297 | u8 increase_delta; | ||
1298 | u8 decrease_delta; | ||
1299 | u8 quiet_time; | ||
1300 | u8 increase_time; | ||
1301 | u8 window_size; | ||
1302 | }; | ||
1303 | |||
1304 | struct conf_drv_settings { | ||
1305 | struct conf_sg_settings sg; | ||
1306 | struct conf_rx_settings rx; | ||
1307 | struct conf_tx_settings tx; | ||
1308 | struct conf_conn_settings conn; | ||
1309 | struct conf_itrim_settings itrim; | ||
1310 | struct conf_pm_config_settings pm_config; | ||
1311 | struct conf_roam_trigger_settings roam_trigger; | ||
1312 | struct conf_scan_settings scan; | ||
1313 | struct conf_sched_scan_settings sched_scan; | ||
1314 | struct conf_rf_settings rf; | ||
1315 | struct conf_ht_setting ht; | ||
1316 | struct conf_memory_settings mem_wl127x; | ||
1317 | struct conf_memory_settings mem_wl128x; | ||
1318 | struct conf_fm_coex fm_coex; | ||
1319 | struct conf_rx_streaming_settings rx_streaming; | ||
1320 | struct conf_fwlog fwlog; | ||
1321 | struct conf_rate_policy_settings rate; | ||
1322 | struct conf_hangover_settings hangover; | ||
1323 | u8 hci_io_ds; | ||
1324 | }; | ||
1325 | |||
1326 | #endif | ||
diff --git a/drivers/net/wireless/ti/wl12xx/debug.h b/drivers/net/wireless/ti/wl12xx/debug.h new file mode 100644 index 000000000000..ec0fdc25b280 --- /dev/null +++ b/drivers/net/wireless/ti/wl12xx/debug.h | |||
@@ -0,0 +1,102 @@ | |||
1 | /* | ||
2 | * This file is part of wl12xx | ||
3 | * | ||
4 | * Copyright (C) 2011 Texas Instruments. All rights reserved. | ||
5 | * Copyright (C) 2008-2009 Nokia Corporation | ||
6 | * | ||
7 | * Contact: Luciano Coelho <coelho@ti.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef __DEBUG_H__ | ||
26 | #define __DEBUG_H__ | ||
27 | |||
28 | #include <linux/bitops.h> | ||
29 | #include <linux/printk.h> | ||
30 | |||
31 | #define DRIVER_NAME "wl12xx" | ||
32 | #define DRIVER_PREFIX DRIVER_NAME ": " | ||
33 | |||
34 | enum { | ||
35 | DEBUG_NONE = 0, | ||
36 | DEBUG_IRQ = BIT(0), | ||
37 | DEBUG_SPI = BIT(1), | ||
38 | DEBUG_BOOT = BIT(2), | ||
39 | DEBUG_MAILBOX = BIT(3), | ||
40 | DEBUG_TESTMODE = BIT(4), | ||
41 | DEBUG_EVENT = BIT(5), | ||
42 | DEBUG_TX = BIT(6), | ||
43 | DEBUG_RX = BIT(7), | ||
44 | DEBUG_SCAN = BIT(8), | ||
45 | DEBUG_CRYPT = BIT(9), | ||
46 | DEBUG_PSM = BIT(10), | ||
47 | DEBUG_MAC80211 = BIT(11), | ||
48 | DEBUG_CMD = BIT(12), | ||
49 | DEBUG_ACX = BIT(13), | ||
50 | DEBUG_SDIO = BIT(14), | ||
51 | DEBUG_FILTERS = BIT(15), | ||
52 | DEBUG_ADHOC = BIT(16), | ||
53 | DEBUG_AP = BIT(17), | ||
54 | DEBUG_PROBE = BIT(18), | ||
55 | DEBUG_MASTER = (DEBUG_ADHOC | DEBUG_AP), | ||
56 | DEBUG_ALL = ~0, | ||
57 | }; | ||
58 | |||
59 | extern u32 wl12xx_debug_level; | ||
60 | |||
61 | #define DEBUG_DUMP_LIMIT 1024 | ||
62 | |||
63 | #define wl1271_error(fmt, arg...) \ | ||
64 | pr_err(DRIVER_PREFIX "ERROR " fmt "\n", ##arg) | ||
65 | |||
66 | #define wl1271_warning(fmt, arg...) \ | ||
67 | pr_warning(DRIVER_PREFIX "WARNING " fmt "\n", ##arg) | ||
68 | |||
69 | #define wl1271_notice(fmt, arg...) \ | ||
70 | pr_info(DRIVER_PREFIX fmt "\n", ##arg) | ||
71 | |||
72 | #define wl1271_info(fmt, arg...) \ | ||
73 | pr_info(DRIVER_PREFIX fmt "\n", ##arg) | ||
74 | |||
75 | #define wl1271_debug(level, fmt, arg...) \ | ||
76 | do { \ | ||
77 | if (level & wl12xx_debug_level) \ | ||
78 | pr_debug(DRIVER_PREFIX fmt "\n", ##arg); \ | ||
79 | } while (0) | ||
80 | |||
81 | /* TODO: use pr_debug_hex_dump when it becomes available */ | ||
82 | #define wl1271_dump(level, prefix, buf, len) \ | ||
83 | do { \ | ||
84 | if (level & wl12xx_debug_level) \ | ||
85 | print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ | ||
86 | DUMP_PREFIX_OFFSET, 16, 1, \ | ||
87 | buf, \ | ||
88 | min_t(size_t, len, DEBUG_DUMP_LIMIT), \ | ||
89 | 0); \ | ||
90 | } while (0) | ||
91 | |||
92 | #define wl1271_dump_ascii(level, prefix, buf, len) \ | ||
93 | do { \ | ||
94 | if (level & wl12xx_debug_level) \ | ||
95 | print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ | ||
96 | DUMP_PREFIX_OFFSET, 16, 1, \ | ||
97 | buf, \ | ||
98 | min_t(size_t, len, DEBUG_DUMP_LIMIT), \ | ||
99 | true); \ | ||
100 | } while (0) | ||
101 | |||
102 | #endif /* __DEBUG_H__ */ | ||
diff --git a/drivers/net/wireless/ti/wl12xx/debugfs.c b/drivers/net/wireless/ti/wl12xx/debugfs.c new file mode 100644 index 000000000000..e1cf72765965 --- /dev/null +++ b/drivers/net/wireless/ti/wl12xx/debugfs.c | |||
@@ -0,0 +1,1203 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2009 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 | #include "debugfs.h" | ||
25 | |||
26 | #include <linux/skbuff.h> | ||
27 | #include <linux/slab.h> | ||
28 | |||
29 | #include "wl12xx.h" | ||
30 | #include "debug.h" | ||
31 | #include "acx.h" | ||
32 | #include "ps.h" | ||
33 | #include "io.h" | ||
34 | #include "tx.h" | ||
35 | |||
36 | /* ms */ | ||
37 | #define WL1271_DEBUGFS_STATS_LIFETIME 1000 | ||
38 | |||
39 | /* debugfs macros idea from mac80211 */ | ||
40 | #define DEBUGFS_FORMAT_BUFFER_SIZE 100 | ||
41 | static int wl1271_format_buffer(char __user *userbuf, size_t count, | ||
42 | loff_t *ppos, char *fmt, ...) | ||
43 | { | ||
44 | va_list args; | ||
45 | char buf[DEBUGFS_FORMAT_BUFFER_SIZE]; | ||
46 | int res; | ||
47 | |||
48 | va_start(args, fmt); | ||
49 | res = vscnprintf(buf, sizeof(buf), fmt, args); | ||
50 | va_end(args); | ||
51 | |||
52 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); | ||
53 | } | ||
54 | |||
55 | #define DEBUGFS_READONLY_FILE(name, fmt, value...) \ | ||
56 | static ssize_t name## _read(struct file *file, char __user *userbuf, \ | ||
57 | size_t count, loff_t *ppos) \ | ||
58 | { \ | ||
59 | struct wl1271 *wl = file->private_data; \ | ||
60 | return wl1271_format_buffer(userbuf, count, ppos, \ | ||
61 | fmt "\n", ##value); \ | ||
62 | } \ | ||
63 | \ | ||
64 | static const struct file_operations name## _ops = { \ | ||
65 | .read = name## _read, \ | ||
66 | .open = wl1271_open_file_generic, \ | ||
67 | .llseek = generic_file_llseek, \ | ||
68 | }; | ||
69 | |||
70 | #define DEBUGFS_ADD(name, parent) \ | ||
71 | entry = debugfs_create_file(#name, 0400, parent, \ | ||
72 | wl, &name## _ops); \ | ||
73 | if (!entry || IS_ERR(entry)) \ | ||
74 | goto err; \ | ||
75 | |||
76 | #define DEBUGFS_ADD_PREFIX(prefix, name, parent) \ | ||
77 | do { \ | ||
78 | entry = debugfs_create_file(#name, 0400, parent, \ | ||
79 | wl, &prefix## _## name## _ops); \ | ||
80 | if (!entry || IS_ERR(entry)) \ | ||
81 | goto err; \ | ||
82 | } while (0); | ||
83 | |||
84 | #define DEBUGFS_FWSTATS_FILE(sub, name, fmt) \ | ||
85 | static ssize_t sub## _ ##name## _read(struct file *file, \ | ||
86 | char __user *userbuf, \ | ||
87 | size_t count, loff_t *ppos) \ | ||
88 | { \ | ||
89 | struct wl1271 *wl = file->private_data; \ | ||
90 | \ | ||
91 | wl1271_debugfs_update_stats(wl); \ | ||
92 | \ | ||
93 | return wl1271_format_buffer(userbuf, count, ppos, fmt "\n", \ | ||
94 | wl->stats.fw_stats->sub.name); \ | ||
95 | } \ | ||
96 | \ | ||
97 | static const struct file_operations sub## _ ##name## _ops = { \ | ||
98 | .read = sub## _ ##name## _read, \ | ||
99 | .open = wl1271_open_file_generic, \ | ||
100 | .llseek = generic_file_llseek, \ | ||
101 | }; | ||
102 | |||
103 | #define DEBUGFS_FWSTATS_ADD(sub, name) \ | ||
104 | DEBUGFS_ADD(sub## _ ##name, stats) | ||
105 | |||
106 | static void wl1271_debugfs_update_stats(struct wl1271 *wl) | ||
107 | { | ||
108 | int ret; | ||
109 | |||
110 | mutex_lock(&wl->mutex); | ||
111 | |||
112 | ret = wl1271_ps_elp_wakeup(wl); | ||
113 | if (ret < 0) | ||
114 | goto out; | ||
115 | |||
116 | if (wl->state == WL1271_STATE_ON && !wl->plt && | ||
117 | time_after(jiffies, wl->stats.fw_stats_update + | ||
118 | msecs_to_jiffies(WL1271_DEBUGFS_STATS_LIFETIME))) { | ||
119 | wl1271_acx_statistics(wl, wl->stats.fw_stats); | ||
120 | wl->stats.fw_stats_update = jiffies; | ||
121 | } | ||
122 | |||
123 | wl1271_ps_elp_sleep(wl); | ||
124 | |||
125 | out: | ||
126 | mutex_unlock(&wl->mutex); | ||
127 | } | ||
128 | |||
129 | static int wl1271_open_file_generic(struct inode *inode, struct file *file) | ||
130 | { | ||
131 | file->private_data = inode->i_private; | ||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | DEBUGFS_FWSTATS_FILE(tx, internal_desc_overflow, "%u"); | ||
136 | |||
137 | DEBUGFS_FWSTATS_FILE(rx, out_of_mem, "%u"); | ||
138 | DEBUGFS_FWSTATS_FILE(rx, hdr_overflow, "%u"); | ||
139 | DEBUGFS_FWSTATS_FILE(rx, hw_stuck, "%u"); | ||
140 | DEBUGFS_FWSTATS_FILE(rx, dropped, "%u"); | ||
141 | DEBUGFS_FWSTATS_FILE(rx, fcs_err, "%u"); | ||
142 | DEBUGFS_FWSTATS_FILE(rx, xfr_hint_trig, "%u"); | ||
143 | DEBUGFS_FWSTATS_FILE(rx, path_reset, "%u"); | ||
144 | DEBUGFS_FWSTATS_FILE(rx, reset_counter, "%u"); | ||
145 | |||
146 | DEBUGFS_FWSTATS_FILE(dma, rx_requested, "%u"); | ||
147 | DEBUGFS_FWSTATS_FILE(dma, rx_errors, "%u"); | ||
148 | DEBUGFS_FWSTATS_FILE(dma, tx_requested, "%u"); | ||
149 | DEBUGFS_FWSTATS_FILE(dma, tx_errors, "%u"); | ||
150 | |||
151 | DEBUGFS_FWSTATS_FILE(isr, cmd_cmplt, "%u"); | ||
152 | DEBUGFS_FWSTATS_FILE(isr, fiqs, "%u"); | ||
153 | DEBUGFS_FWSTATS_FILE(isr, rx_headers, "%u"); | ||
154 | DEBUGFS_FWSTATS_FILE(isr, rx_mem_overflow, "%u"); | ||
155 | DEBUGFS_FWSTATS_FILE(isr, rx_rdys, "%u"); | ||
156 | DEBUGFS_FWSTATS_FILE(isr, irqs, "%u"); | ||
157 | DEBUGFS_FWSTATS_FILE(isr, tx_procs, "%u"); | ||
158 | DEBUGFS_FWSTATS_FILE(isr, decrypt_done, "%u"); | ||
159 | DEBUGFS_FWSTATS_FILE(isr, dma0_done, "%u"); | ||
160 | DEBUGFS_FWSTATS_FILE(isr, dma1_done, "%u"); | ||
161 | DEBUGFS_FWSTATS_FILE(isr, tx_exch_complete, "%u"); | ||
162 | DEBUGFS_FWSTATS_FILE(isr, commands, "%u"); | ||
163 | DEBUGFS_FWSTATS_FILE(isr, rx_procs, "%u"); | ||
164 | DEBUGFS_FWSTATS_FILE(isr, hw_pm_mode_changes, "%u"); | ||
165 | DEBUGFS_FWSTATS_FILE(isr, host_acknowledges, "%u"); | ||
166 | DEBUGFS_FWSTATS_FILE(isr, pci_pm, "%u"); | ||
167 | DEBUGFS_FWSTATS_FILE(isr, wakeups, "%u"); | ||
168 | DEBUGFS_FWSTATS_FILE(isr, low_rssi, "%u"); | ||
169 | |||
170 | DEBUGFS_FWSTATS_FILE(wep, addr_key_count, "%u"); | ||
171 | DEBUGFS_FWSTATS_FILE(wep, default_key_count, "%u"); | ||
172 | /* skipping wep.reserved */ | ||
173 | DEBUGFS_FWSTATS_FILE(wep, key_not_found, "%u"); | ||
174 | DEBUGFS_FWSTATS_FILE(wep, decrypt_fail, "%u"); | ||
175 | DEBUGFS_FWSTATS_FILE(wep, packets, "%u"); | ||
176 | DEBUGFS_FWSTATS_FILE(wep, interrupt, "%u"); | ||
177 | |||
178 | DEBUGFS_FWSTATS_FILE(pwr, ps_enter, "%u"); | ||
179 | DEBUGFS_FWSTATS_FILE(pwr, elp_enter, "%u"); | ||
180 | DEBUGFS_FWSTATS_FILE(pwr, missing_bcns, "%u"); | ||
181 | DEBUGFS_FWSTATS_FILE(pwr, wake_on_host, "%u"); | ||
182 | DEBUGFS_FWSTATS_FILE(pwr, wake_on_timer_exp, "%u"); | ||
183 | DEBUGFS_FWSTATS_FILE(pwr, tx_with_ps, "%u"); | ||
184 | DEBUGFS_FWSTATS_FILE(pwr, tx_without_ps, "%u"); | ||
185 | DEBUGFS_FWSTATS_FILE(pwr, rcvd_beacons, "%u"); | ||
186 | DEBUGFS_FWSTATS_FILE(pwr, power_save_off, "%u"); | ||
187 | DEBUGFS_FWSTATS_FILE(pwr, enable_ps, "%u"); | ||
188 | DEBUGFS_FWSTATS_FILE(pwr, disable_ps, "%u"); | ||
189 | DEBUGFS_FWSTATS_FILE(pwr, fix_tsf_ps, "%u"); | ||
190 | /* skipping cont_miss_bcns_spread for now */ | ||
191 | DEBUGFS_FWSTATS_FILE(pwr, rcvd_awake_beacons, "%u"); | ||
192 | |||
193 | DEBUGFS_FWSTATS_FILE(mic, rx_pkts, "%u"); | ||
194 | DEBUGFS_FWSTATS_FILE(mic, calc_failure, "%u"); | ||
195 | |||
196 | DEBUGFS_FWSTATS_FILE(aes, encrypt_fail, "%u"); | ||
197 | DEBUGFS_FWSTATS_FILE(aes, decrypt_fail, "%u"); | ||
198 | DEBUGFS_FWSTATS_FILE(aes, encrypt_packets, "%u"); | ||
199 | DEBUGFS_FWSTATS_FILE(aes, decrypt_packets, "%u"); | ||
200 | DEBUGFS_FWSTATS_FILE(aes, encrypt_interrupt, "%u"); | ||
201 | DEBUGFS_FWSTATS_FILE(aes, decrypt_interrupt, "%u"); | ||
202 | |||
203 | DEBUGFS_FWSTATS_FILE(event, heart_beat, "%u"); | ||
204 | DEBUGFS_FWSTATS_FILE(event, calibration, "%u"); | ||
205 | DEBUGFS_FWSTATS_FILE(event, rx_mismatch, "%u"); | ||
206 | DEBUGFS_FWSTATS_FILE(event, rx_mem_empty, "%u"); | ||
207 | DEBUGFS_FWSTATS_FILE(event, rx_pool, "%u"); | ||
208 | DEBUGFS_FWSTATS_FILE(event, oom_late, "%u"); | ||
209 | DEBUGFS_FWSTATS_FILE(event, phy_transmit_error, "%u"); | ||
210 | DEBUGFS_FWSTATS_FILE(event, tx_stuck, "%u"); | ||
211 | |||
212 | DEBUGFS_FWSTATS_FILE(ps, pspoll_timeouts, "%u"); | ||
213 | DEBUGFS_FWSTATS_FILE(ps, upsd_timeouts, "%u"); | ||
214 | DEBUGFS_FWSTATS_FILE(ps, upsd_max_sptime, "%u"); | ||
215 | DEBUGFS_FWSTATS_FILE(ps, upsd_max_apturn, "%u"); | ||
216 | DEBUGFS_FWSTATS_FILE(ps, pspoll_max_apturn, "%u"); | ||
217 | DEBUGFS_FWSTATS_FILE(ps, pspoll_utilization, "%u"); | ||
218 | DEBUGFS_FWSTATS_FILE(ps, upsd_utilization, "%u"); | ||
219 | |||
220 | DEBUGFS_FWSTATS_FILE(rxpipe, rx_prep_beacon_drop, "%u"); | ||
221 | DEBUGFS_FWSTATS_FILE(rxpipe, descr_host_int_trig_rx_data, "%u"); | ||
222 | DEBUGFS_FWSTATS_FILE(rxpipe, beacon_buffer_thres_host_int_trig_rx_data, "%u"); | ||
223 | DEBUGFS_FWSTATS_FILE(rxpipe, missed_beacon_host_int_trig_rx_data, "%u"); | ||
224 | DEBUGFS_FWSTATS_FILE(rxpipe, tx_xfr_host_int_trig_rx_data, "%u"); | ||
225 | |||
226 | DEBUGFS_READONLY_FILE(retry_count, "%u", wl->stats.retry_count); | ||
227 | DEBUGFS_READONLY_FILE(excessive_retries, "%u", | ||
228 | wl->stats.excessive_retries); | ||
229 | |||
230 | static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf, | ||
231 | size_t count, loff_t *ppos) | ||
232 | { | ||
233 | struct wl1271 *wl = file->private_data; | ||
234 | u32 queue_len; | ||
235 | char buf[20]; | ||
236 | int res; | ||
237 | |||
238 | queue_len = wl1271_tx_total_queue_count(wl); | ||
239 | |||
240 | res = scnprintf(buf, sizeof(buf), "%u\n", queue_len); | ||
241 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); | ||
242 | } | ||
243 | |||
244 | static const struct file_operations tx_queue_len_ops = { | ||
245 | .read = tx_queue_len_read, | ||
246 | .open = wl1271_open_file_generic, | ||
247 | .llseek = default_llseek, | ||
248 | }; | ||
249 | |||
250 | static ssize_t gpio_power_read(struct file *file, char __user *user_buf, | ||
251 | size_t count, loff_t *ppos) | ||
252 | { | ||
253 | struct wl1271 *wl = file->private_data; | ||
254 | bool state = test_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); | ||
255 | |||
256 | int res; | ||
257 | char buf[10]; | ||
258 | |||
259 | res = scnprintf(buf, sizeof(buf), "%d\n", state); | ||
260 | |||
261 | return simple_read_from_buffer(user_buf, count, ppos, buf, res); | ||
262 | } | ||
263 | |||
264 | static ssize_t gpio_power_write(struct file *file, | ||
265 | const char __user *user_buf, | ||
266 | size_t count, loff_t *ppos) | ||
267 | { | ||
268 | struct wl1271 *wl = file->private_data; | ||
269 | unsigned long value; | ||
270 | int ret; | ||
271 | |||
272 | ret = kstrtoul_from_user(user_buf, count, 10, &value); | ||
273 | if (ret < 0) { | ||
274 | wl1271_warning("illegal value in gpio_power"); | ||
275 | return -EINVAL; | ||
276 | } | ||
277 | |||
278 | mutex_lock(&wl->mutex); | ||
279 | |||
280 | if (value) | ||
281 | wl1271_power_on(wl); | ||
282 | else | ||
283 | wl1271_power_off(wl); | ||
284 | |||
285 | mutex_unlock(&wl->mutex); | ||
286 | return count; | ||
287 | } | ||
288 | |||
289 | static const struct file_operations gpio_power_ops = { | ||
290 | .read = gpio_power_read, | ||
291 | .write = gpio_power_write, | ||
292 | .open = wl1271_open_file_generic, | ||
293 | .llseek = default_llseek, | ||
294 | }; | ||
295 | |||
296 | static ssize_t start_recovery_write(struct file *file, | ||
297 | const char __user *user_buf, | ||
298 | size_t count, loff_t *ppos) | ||
299 | { | ||
300 | struct wl1271 *wl = file->private_data; | ||
301 | |||
302 | mutex_lock(&wl->mutex); | ||
303 | wl12xx_queue_recovery_work(wl); | ||
304 | mutex_unlock(&wl->mutex); | ||
305 | |||
306 | return count; | ||
307 | } | ||
308 | |||
309 | static const struct file_operations start_recovery_ops = { | ||
310 | .write = start_recovery_write, | ||
311 | .open = wl1271_open_file_generic, | ||
312 | .llseek = default_llseek, | ||
313 | }; | ||
314 | |||
315 | static ssize_t dynamic_ps_timeout_read(struct file *file, char __user *user_buf, | ||
316 | size_t count, loff_t *ppos) | ||
317 | { | ||
318 | struct wl1271 *wl = file->private_data; | ||
319 | |||
320 | return wl1271_format_buffer(user_buf, count, | ||
321 | ppos, "%d\n", | ||
322 | wl->conf.conn.dynamic_ps_timeout); | ||
323 | } | ||
324 | |||
325 | static ssize_t dynamic_ps_timeout_write(struct file *file, | ||
326 | const char __user *user_buf, | ||
327 | size_t count, loff_t *ppos) | ||
328 | { | ||
329 | struct wl1271 *wl = file->private_data; | ||
330 | struct wl12xx_vif *wlvif; | ||
331 | unsigned long value; | ||
332 | int ret; | ||
333 | |||
334 | ret = kstrtoul_from_user(user_buf, count, 10, &value); | ||
335 | if (ret < 0) { | ||
336 | wl1271_warning("illegal value in dynamic_ps"); | ||
337 | return -EINVAL; | ||
338 | } | ||
339 | |||
340 | if (value < 1 || value > 65535) { | ||
341 | wl1271_warning("dyanmic_ps_timeout is not in valid range"); | ||
342 | return -ERANGE; | ||
343 | } | ||
344 | |||
345 | mutex_lock(&wl->mutex); | ||
346 | |||
347 | wl->conf.conn.dynamic_ps_timeout = value; | ||
348 | |||
349 | if (wl->state == WL1271_STATE_OFF) | ||
350 | goto out; | ||
351 | |||
352 | ret = wl1271_ps_elp_wakeup(wl); | ||
353 | if (ret < 0) | ||
354 | goto out; | ||
355 | |||
356 | /* In case we're already in PSM, trigger it again to set new timeout | ||
357 | * immediately without waiting for re-association | ||
358 | */ | ||
359 | |||
360 | wl12xx_for_each_wlvif_sta(wl, wlvif) { | ||
361 | if (test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) | ||
362 | wl1271_ps_set_mode(wl, wlvif, STATION_AUTO_PS_MODE); | ||
363 | } | ||
364 | |||
365 | wl1271_ps_elp_sleep(wl); | ||
366 | |||
367 | out: | ||
368 | mutex_unlock(&wl->mutex); | ||
369 | return count; | ||
370 | } | ||
371 | |||
372 | static const struct file_operations dynamic_ps_timeout_ops = { | ||
373 | .read = dynamic_ps_timeout_read, | ||
374 | .write = dynamic_ps_timeout_write, | ||
375 | .open = wl1271_open_file_generic, | ||
376 | .llseek = default_llseek, | ||
377 | }; | ||
378 | |||
379 | static ssize_t forced_ps_read(struct file *file, char __user *user_buf, | ||
380 | size_t count, loff_t *ppos) | ||
381 | { | ||
382 | struct wl1271 *wl = file->private_data; | ||
383 | |||
384 | return wl1271_format_buffer(user_buf, count, | ||
385 | ppos, "%d\n", | ||
386 | wl->conf.conn.forced_ps); | ||
387 | } | ||
388 | |||
389 | static ssize_t forced_ps_write(struct file *file, | ||
390 | const char __user *user_buf, | ||
391 | size_t count, loff_t *ppos) | ||
392 | { | ||
393 | struct wl1271 *wl = file->private_data; | ||
394 | struct wl12xx_vif *wlvif; | ||
395 | unsigned long value; | ||
396 | int ret, ps_mode; | ||
397 | |||
398 | ret = kstrtoul_from_user(user_buf, count, 10, &value); | ||
399 | if (ret < 0) { | ||
400 | wl1271_warning("illegal value in forced_ps"); | ||
401 | return -EINVAL; | ||
402 | } | ||
403 | |||
404 | if (value != 1 && value != 0) { | ||
405 | wl1271_warning("forced_ps should be either 0 or 1"); | ||
406 | return -ERANGE; | ||
407 | } | ||
408 | |||
409 | mutex_lock(&wl->mutex); | ||
410 | |||
411 | if (wl->conf.conn.forced_ps == value) | ||
412 | goto out; | ||
413 | |||
414 | wl->conf.conn.forced_ps = value; | ||
415 | |||
416 | if (wl->state == WL1271_STATE_OFF) | ||
417 | goto out; | ||
418 | |||
419 | ret = wl1271_ps_elp_wakeup(wl); | ||
420 | if (ret < 0) | ||
421 | goto out; | ||
422 | |||
423 | /* In case we're already in PSM, trigger it again to switch mode | ||
424 | * immediately without waiting for re-association | ||
425 | */ | ||
426 | |||
427 | ps_mode = value ? STATION_POWER_SAVE_MODE : STATION_AUTO_PS_MODE; | ||
428 | |||
429 | wl12xx_for_each_wlvif_sta(wl, wlvif) { | ||
430 | if (test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) | ||
431 | wl1271_ps_set_mode(wl, wlvif, ps_mode); | ||
432 | } | ||
433 | |||
434 | wl1271_ps_elp_sleep(wl); | ||
435 | |||
436 | out: | ||
437 | mutex_unlock(&wl->mutex); | ||
438 | return count; | ||
439 | } | ||
440 | |||
441 | static const struct file_operations forced_ps_ops = { | ||
442 | .read = forced_ps_read, | ||
443 | .write = forced_ps_write, | ||
444 | .open = wl1271_open_file_generic, | ||
445 | .llseek = default_llseek, | ||
446 | }; | ||
447 | |||
448 | static ssize_t split_scan_timeout_read(struct file *file, char __user *user_buf, | ||
449 | size_t count, loff_t *ppos) | ||
450 | { | ||
451 | struct wl1271 *wl = file->private_data; | ||
452 | |||
453 | return wl1271_format_buffer(user_buf, count, | ||
454 | ppos, "%d\n", | ||
455 | wl->conf.scan.split_scan_timeout / 1000); | ||
456 | } | ||
457 | |||
458 | static ssize_t split_scan_timeout_write(struct file *file, | ||
459 | const char __user *user_buf, | ||
460 | size_t count, loff_t *ppos) | ||
461 | { | ||
462 | struct wl1271 *wl = file->private_data; | ||
463 | unsigned long value; | ||
464 | int ret; | ||
465 | |||
466 | ret = kstrtoul_from_user(user_buf, count, 10, &value); | ||
467 | if (ret < 0) { | ||
468 | wl1271_warning("illegal value in split_scan_timeout"); | ||
469 | return -EINVAL; | ||
470 | } | ||
471 | |||
472 | if (value == 0) | ||
473 | wl1271_info("split scan will be disabled"); | ||
474 | |||
475 | mutex_lock(&wl->mutex); | ||
476 | |||
477 | wl->conf.scan.split_scan_timeout = value * 1000; | ||
478 | |||
479 | mutex_unlock(&wl->mutex); | ||
480 | return count; | ||
481 | } | ||
482 | |||
483 | static const struct file_operations split_scan_timeout_ops = { | ||
484 | .read = split_scan_timeout_read, | ||
485 | .write = split_scan_timeout_write, | ||
486 | .open = wl1271_open_file_generic, | ||
487 | .llseek = default_llseek, | ||
488 | }; | ||
489 | |||
490 | static ssize_t driver_state_read(struct file *file, char __user *user_buf, | ||
491 | size_t count, loff_t *ppos) | ||
492 | { | ||
493 | struct wl1271 *wl = file->private_data; | ||
494 | int res = 0; | ||
495 | ssize_t ret; | ||
496 | char *buf; | ||
497 | |||
498 | #define DRIVER_STATE_BUF_LEN 1024 | ||
499 | |||
500 | buf = kmalloc(DRIVER_STATE_BUF_LEN, GFP_KERNEL); | ||
501 | if (!buf) | ||
502 | return -ENOMEM; | ||
503 | |||
504 | mutex_lock(&wl->mutex); | ||
505 | |||
506 | #define DRIVER_STATE_PRINT(x, fmt) \ | ||
507 | (res += scnprintf(buf + res, DRIVER_STATE_BUF_LEN - res,\ | ||
508 | #x " = " fmt "\n", wl->x)) | ||
509 | |||
510 | #define DRIVER_STATE_PRINT_LONG(x) DRIVER_STATE_PRINT(x, "%ld") | ||
511 | #define DRIVER_STATE_PRINT_INT(x) DRIVER_STATE_PRINT(x, "%d") | ||
512 | #define DRIVER_STATE_PRINT_STR(x) DRIVER_STATE_PRINT(x, "%s") | ||
513 | #define DRIVER_STATE_PRINT_LHEX(x) DRIVER_STATE_PRINT(x, "0x%lx") | ||
514 | #define DRIVER_STATE_PRINT_HEX(x) DRIVER_STATE_PRINT(x, "0x%x") | ||
515 | |||
516 | DRIVER_STATE_PRINT_INT(tx_blocks_available); | ||
517 | DRIVER_STATE_PRINT_INT(tx_allocated_blocks); | ||
518 | DRIVER_STATE_PRINT_INT(tx_allocated_pkts[0]); | ||
519 | DRIVER_STATE_PRINT_INT(tx_allocated_pkts[1]); | ||
520 | DRIVER_STATE_PRINT_INT(tx_allocated_pkts[2]); | ||
521 | DRIVER_STATE_PRINT_INT(tx_allocated_pkts[3]); | ||
522 | DRIVER_STATE_PRINT_INT(tx_frames_cnt); | ||
523 | DRIVER_STATE_PRINT_LHEX(tx_frames_map[0]); | ||
524 | DRIVER_STATE_PRINT_INT(tx_queue_count[0]); | ||
525 | DRIVER_STATE_PRINT_INT(tx_queue_count[1]); | ||
526 | DRIVER_STATE_PRINT_INT(tx_queue_count[2]); | ||
527 | DRIVER_STATE_PRINT_INT(tx_queue_count[3]); | ||
528 | DRIVER_STATE_PRINT_INT(tx_packets_count); | ||
529 | DRIVER_STATE_PRINT_INT(tx_results_count); | ||
530 | DRIVER_STATE_PRINT_LHEX(flags); | ||
531 | DRIVER_STATE_PRINT_INT(tx_blocks_freed); | ||
532 | DRIVER_STATE_PRINT_INT(rx_counter); | ||
533 | DRIVER_STATE_PRINT_INT(state); | ||
534 | DRIVER_STATE_PRINT_INT(channel); | ||
535 | DRIVER_STATE_PRINT_INT(band); | ||
536 | DRIVER_STATE_PRINT_INT(power_level); | ||
537 | DRIVER_STATE_PRINT_INT(sg_enabled); | ||
538 | DRIVER_STATE_PRINT_INT(enable_11a); | ||
539 | DRIVER_STATE_PRINT_INT(noise); | ||
540 | DRIVER_STATE_PRINT_HEX(ap_fw_ps_map); | ||
541 | DRIVER_STATE_PRINT_LHEX(ap_ps_map); | ||
542 | DRIVER_STATE_PRINT_HEX(quirks); | ||
543 | DRIVER_STATE_PRINT_HEX(irq); | ||
544 | DRIVER_STATE_PRINT_HEX(ref_clock); | ||
545 | DRIVER_STATE_PRINT_HEX(tcxo_clock); | ||
546 | DRIVER_STATE_PRINT_HEX(hw_pg_ver); | ||
547 | DRIVER_STATE_PRINT_HEX(platform_quirks); | ||
548 | DRIVER_STATE_PRINT_HEX(chip.id); | ||
549 | DRIVER_STATE_PRINT_STR(chip.fw_ver_str); | ||
550 | DRIVER_STATE_PRINT_INT(sched_scanning); | ||
551 | |||
552 | #undef DRIVER_STATE_PRINT_INT | ||
553 | #undef DRIVER_STATE_PRINT_LONG | ||
554 | #undef DRIVER_STATE_PRINT_HEX | ||
555 | #undef DRIVER_STATE_PRINT_LHEX | ||
556 | #undef DRIVER_STATE_PRINT_STR | ||
557 | #undef DRIVER_STATE_PRINT | ||
558 | #undef DRIVER_STATE_BUF_LEN | ||
559 | |||
560 | mutex_unlock(&wl->mutex); | ||
561 | |||
562 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, res); | ||
563 | kfree(buf); | ||
564 | return ret; | ||
565 | } | ||
566 | |||
567 | static const struct file_operations driver_state_ops = { | ||
568 | .read = driver_state_read, | ||
569 | .open = wl1271_open_file_generic, | ||
570 | .llseek = default_llseek, | ||
571 | }; | ||
572 | |||
573 | static ssize_t vifs_state_read(struct file *file, char __user *user_buf, | ||
574 | size_t count, loff_t *ppos) | ||
575 | { | ||
576 | struct wl1271 *wl = file->private_data; | ||
577 | struct wl12xx_vif *wlvif; | ||
578 | int ret, res = 0; | ||
579 | const int buf_size = 4096; | ||
580 | char *buf; | ||
581 | char tmp_buf[64]; | ||
582 | |||
583 | buf = kzalloc(buf_size, GFP_KERNEL); | ||
584 | if (!buf) | ||
585 | return -ENOMEM; | ||
586 | |||
587 | mutex_lock(&wl->mutex); | ||
588 | |||
589 | #define VIF_STATE_PRINT(x, fmt) \ | ||
590 | (res += scnprintf(buf + res, buf_size - res, \ | ||
591 | #x " = " fmt "\n", wlvif->x)) | ||
592 | |||
593 | #define VIF_STATE_PRINT_LONG(x) VIF_STATE_PRINT(x, "%ld") | ||
594 | #define VIF_STATE_PRINT_INT(x) VIF_STATE_PRINT(x, "%d") | ||
595 | #define VIF_STATE_PRINT_STR(x) VIF_STATE_PRINT(x, "%s") | ||
596 | #define VIF_STATE_PRINT_LHEX(x) VIF_STATE_PRINT(x, "0x%lx") | ||
597 | #define VIF_STATE_PRINT_LLHEX(x) VIF_STATE_PRINT(x, "0x%llx") | ||
598 | #define VIF_STATE_PRINT_HEX(x) VIF_STATE_PRINT(x, "0x%x") | ||
599 | |||
600 | #define VIF_STATE_PRINT_NSTR(x, len) \ | ||
601 | do { \ | ||
602 | memset(tmp_buf, 0, sizeof(tmp_buf)); \ | ||
603 | memcpy(tmp_buf, wlvif->x, \ | ||
604 | min_t(u8, len, sizeof(tmp_buf) - 1)); \ | ||
605 | res += scnprintf(buf + res, buf_size - res, \ | ||
606 | #x " = %s\n", tmp_buf); \ | ||
607 | } while (0) | ||
608 | |||
609 | wl12xx_for_each_wlvif(wl, wlvif) { | ||
610 | VIF_STATE_PRINT_INT(role_id); | ||
611 | VIF_STATE_PRINT_INT(bss_type); | ||
612 | VIF_STATE_PRINT_LHEX(flags); | ||
613 | VIF_STATE_PRINT_INT(p2p); | ||
614 | VIF_STATE_PRINT_INT(dev_role_id); | ||
615 | VIF_STATE_PRINT_INT(dev_hlid); | ||
616 | |||
617 | if (wlvif->bss_type == BSS_TYPE_STA_BSS || | ||
618 | wlvif->bss_type == BSS_TYPE_IBSS) { | ||
619 | VIF_STATE_PRINT_INT(sta.hlid); | ||
620 | VIF_STATE_PRINT_INT(sta.ba_rx_bitmap); | ||
621 | VIF_STATE_PRINT_INT(sta.basic_rate_idx); | ||
622 | VIF_STATE_PRINT_INT(sta.ap_rate_idx); | ||
623 | VIF_STATE_PRINT_INT(sta.p2p_rate_idx); | ||
624 | VIF_STATE_PRINT_INT(sta.qos); | ||
625 | } else { | ||
626 | VIF_STATE_PRINT_INT(ap.global_hlid); | ||
627 | VIF_STATE_PRINT_INT(ap.bcast_hlid); | ||
628 | VIF_STATE_PRINT_LHEX(ap.sta_hlid_map[0]); | ||
629 | VIF_STATE_PRINT_INT(ap.mgmt_rate_idx); | ||
630 | VIF_STATE_PRINT_INT(ap.bcast_rate_idx); | ||
631 | VIF_STATE_PRINT_INT(ap.ucast_rate_idx[0]); | ||
632 | VIF_STATE_PRINT_INT(ap.ucast_rate_idx[1]); | ||
633 | VIF_STATE_PRINT_INT(ap.ucast_rate_idx[2]); | ||
634 | VIF_STATE_PRINT_INT(ap.ucast_rate_idx[3]); | ||
635 | } | ||
636 | VIF_STATE_PRINT_INT(last_tx_hlid); | ||
637 | VIF_STATE_PRINT_LHEX(links_map[0]); | ||
638 | VIF_STATE_PRINT_NSTR(ssid, wlvif->ssid_len); | ||
639 | VIF_STATE_PRINT_INT(band); | ||
640 | VIF_STATE_PRINT_INT(channel); | ||
641 | VIF_STATE_PRINT_HEX(bitrate_masks[0]); | ||
642 | VIF_STATE_PRINT_HEX(bitrate_masks[1]); | ||
643 | VIF_STATE_PRINT_HEX(basic_rate_set); | ||
644 | VIF_STATE_PRINT_HEX(basic_rate); | ||
645 | VIF_STATE_PRINT_HEX(rate_set); | ||
646 | VIF_STATE_PRINT_INT(beacon_int); | ||
647 | VIF_STATE_PRINT_INT(default_key); | ||
648 | VIF_STATE_PRINT_INT(aid); | ||
649 | VIF_STATE_PRINT_INT(session_counter); | ||
650 | VIF_STATE_PRINT_INT(psm_entry_retry); | ||
651 | VIF_STATE_PRINT_INT(power_level); | ||
652 | VIF_STATE_PRINT_INT(rssi_thold); | ||
653 | VIF_STATE_PRINT_INT(last_rssi_event); | ||
654 | VIF_STATE_PRINT_INT(ba_support); | ||
655 | VIF_STATE_PRINT_INT(ba_allowed); | ||
656 | VIF_STATE_PRINT_LLHEX(tx_security_seq); | ||
657 | VIF_STATE_PRINT_INT(tx_security_last_seq_lsb); | ||
658 | } | ||
659 | |||
660 | #undef VIF_STATE_PRINT_INT | ||
661 | #undef VIF_STATE_PRINT_LONG | ||
662 | #undef VIF_STATE_PRINT_HEX | ||
663 | #undef VIF_STATE_PRINT_LHEX | ||
664 | #undef VIF_STATE_PRINT_LLHEX | ||
665 | #undef VIF_STATE_PRINT_STR | ||
666 | #undef VIF_STATE_PRINT_NSTR | ||
667 | #undef VIF_STATE_PRINT | ||
668 | |||
669 | mutex_unlock(&wl->mutex); | ||
670 | |||
671 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, res); | ||
672 | kfree(buf); | ||
673 | return ret; | ||
674 | } | ||
675 | |||
676 | static const struct file_operations vifs_state_ops = { | ||
677 | .read = vifs_state_read, | ||
678 | .open = wl1271_open_file_generic, | ||
679 | .llseek = default_llseek, | ||
680 | }; | ||
681 | |||
682 | static ssize_t dtim_interval_read(struct file *file, char __user *user_buf, | ||
683 | size_t count, loff_t *ppos) | ||
684 | { | ||
685 | struct wl1271 *wl = file->private_data; | ||
686 | u8 value; | ||
687 | |||
688 | if (wl->conf.conn.wake_up_event == CONF_WAKE_UP_EVENT_DTIM || | ||
689 | wl->conf.conn.wake_up_event == CONF_WAKE_UP_EVENT_N_DTIM) | ||
690 | value = wl->conf.conn.listen_interval; | ||
691 | else | ||
692 | value = 0; | ||
693 | |||
694 | return wl1271_format_buffer(user_buf, count, ppos, "%d\n", value); | ||
695 | } | ||
696 | |||
697 | static ssize_t dtim_interval_write(struct file *file, | ||
698 | const char __user *user_buf, | ||
699 | size_t count, loff_t *ppos) | ||
700 | { | ||
701 | struct wl1271 *wl = file->private_data; | ||
702 | unsigned long value; | ||
703 | int ret; | ||
704 | |||
705 | ret = kstrtoul_from_user(user_buf, count, 10, &value); | ||
706 | if (ret < 0) { | ||
707 | wl1271_warning("illegal value for dtim_interval"); | ||
708 | return -EINVAL; | ||
709 | } | ||
710 | |||
711 | if (value < 1 || value > 10) { | ||
712 | wl1271_warning("dtim value is not in valid range"); | ||
713 | return -ERANGE; | ||
714 | } | ||
715 | |||
716 | mutex_lock(&wl->mutex); | ||
717 | |||
718 | wl->conf.conn.listen_interval = value; | ||
719 | /* for some reason there are different event types for 1 and >1 */ | ||
720 | if (value == 1) | ||
721 | wl->conf.conn.wake_up_event = CONF_WAKE_UP_EVENT_DTIM; | ||
722 | else | ||
723 | wl->conf.conn.wake_up_event = CONF_WAKE_UP_EVENT_N_DTIM; | ||
724 | |||
725 | /* | ||
726 | * we don't reconfigure ACX_WAKE_UP_CONDITIONS now, so it will only | ||
727 | * take effect on the next time we enter psm. | ||
728 | */ | ||
729 | mutex_unlock(&wl->mutex); | ||
730 | return count; | ||
731 | } | ||
732 | |||
733 | static const struct file_operations dtim_interval_ops = { | ||
734 | .read = dtim_interval_read, | ||
735 | .write = dtim_interval_write, | ||
736 | .open = wl1271_open_file_generic, | ||
737 | .llseek = default_llseek, | ||
738 | }; | ||
739 | |||
740 | |||
741 | |||
742 | static ssize_t suspend_dtim_interval_read(struct file *file, | ||
743 | char __user *user_buf, | ||
744 | size_t count, loff_t *ppos) | ||
745 | { | ||
746 | struct wl1271 *wl = file->private_data; | ||
747 | u8 value; | ||
748 | |||
749 | if (wl->conf.conn.suspend_wake_up_event == CONF_WAKE_UP_EVENT_DTIM || | ||
750 | wl->conf.conn.suspend_wake_up_event == CONF_WAKE_UP_EVENT_N_DTIM) | ||
751 | value = wl->conf.conn.suspend_listen_interval; | ||
752 | else | ||
753 | value = 0; | ||
754 | |||
755 | return wl1271_format_buffer(user_buf, count, ppos, "%d\n", value); | ||
756 | } | ||
757 | |||
758 | static ssize_t suspend_dtim_interval_write(struct file *file, | ||
759 | const char __user *user_buf, | ||
760 | size_t count, loff_t *ppos) | ||
761 | { | ||
762 | struct wl1271 *wl = file->private_data; | ||
763 | unsigned long value; | ||
764 | int ret; | ||
765 | |||
766 | ret = kstrtoul_from_user(user_buf, count, 10, &value); | ||
767 | if (ret < 0) { | ||
768 | wl1271_warning("illegal value for suspend_dtim_interval"); | ||
769 | return -EINVAL; | ||
770 | } | ||
771 | |||
772 | if (value < 1 || value > 10) { | ||
773 | wl1271_warning("suspend_dtim value is not in valid range"); | ||
774 | return -ERANGE; | ||
775 | } | ||
776 | |||
777 | mutex_lock(&wl->mutex); | ||
778 | |||
779 | wl->conf.conn.suspend_listen_interval = value; | ||
780 | /* for some reason there are different event types for 1 and >1 */ | ||
781 | if (value == 1) | ||
782 | wl->conf.conn.suspend_wake_up_event = CONF_WAKE_UP_EVENT_DTIM; | ||
783 | else | ||
784 | wl->conf.conn.suspend_wake_up_event = CONF_WAKE_UP_EVENT_N_DTIM; | ||
785 | |||
786 | mutex_unlock(&wl->mutex); | ||
787 | return count; | ||
788 | } | ||
789 | |||
790 | |||
791 | static const struct file_operations suspend_dtim_interval_ops = { | ||
792 | .read = suspend_dtim_interval_read, | ||
793 | .write = suspend_dtim_interval_write, | ||
794 | .open = wl1271_open_file_generic, | ||
795 | .llseek = default_llseek, | ||
796 | }; | ||
797 | |||
798 | static ssize_t beacon_interval_read(struct file *file, char __user *user_buf, | ||
799 | size_t count, loff_t *ppos) | ||
800 | { | ||
801 | struct wl1271 *wl = file->private_data; | ||
802 | u8 value; | ||
803 | |||
804 | if (wl->conf.conn.wake_up_event == CONF_WAKE_UP_EVENT_BEACON || | ||
805 | wl->conf.conn.wake_up_event == CONF_WAKE_UP_EVENT_N_BEACONS) | ||
806 | value = wl->conf.conn.listen_interval; | ||
807 | else | ||
808 | value = 0; | ||
809 | |||
810 | return wl1271_format_buffer(user_buf, count, ppos, "%d\n", value); | ||
811 | } | ||
812 | |||
813 | static ssize_t beacon_interval_write(struct file *file, | ||
814 | const char __user *user_buf, | ||
815 | size_t count, loff_t *ppos) | ||
816 | { | ||
817 | struct wl1271 *wl = file->private_data; | ||
818 | unsigned long value; | ||
819 | int ret; | ||
820 | |||
821 | ret = kstrtoul_from_user(user_buf, count, 10, &value); | ||
822 | if (ret < 0) { | ||
823 | wl1271_warning("illegal value for beacon_interval"); | ||
824 | return -EINVAL; | ||
825 | } | ||
826 | |||
827 | if (value < 1 || value > 255) { | ||
828 | wl1271_warning("beacon interval value is not in valid range"); | ||
829 | return -ERANGE; | ||
830 | } | ||
831 | |||
832 | mutex_lock(&wl->mutex); | ||
833 | |||
834 | wl->conf.conn.listen_interval = value; | ||
835 | /* for some reason there are different event types for 1 and >1 */ | ||
836 | if (value == 1) | ||
837 | wl->conf.conn.wake_up_event = CONF_WAKE_UP_EVENT_BEACON; | ||
838 | else | ||
839 | wl->conf.conn.wake_up_event = CONF_WAKE_UP_EVENT_N_BEACONS; | ||
840 | |||
841 | /* | ||
842 | * we don't reconfigure ACX_WAKE_UP_CONDITIONS now, so it will only | ||
843 | * take effect on the next time we enter psm. | ||
844 | */ | ||
845 | mutex_unlock(&wl->mutex); | ||
846 | return count; | ||
847 | } | ||
848 | |||
849 | static const struct file_operations beacon_interval_ops = { | ||
850 | .read = beacon_interval_read, | ||
851 | .write = beacon_interval_write, | ||
852 | .open = wl1271_open_file_generic, | ||
853 | .llseek = default_llseek, | ||
854 | }; | ||
855 | |||
856 | static ssize_t rx_streaming_interval_write(struct file *file, | ||
857 | const char __user *user_buf, | ||
858 | size_t count, loff_t *ppos) | ||
859 | { | ||
860 | struct wl1271 *wl = file->private_data; | ||
861 | struct wl12xx_vif *wlvif; | ||
862 | unsigned long value; | ||
863 | int ret; | ||
864 | |||
865 | ret = kstrtoul_from_user(user_buf, count, 10, &value); | ||
866 | if (ret < 0) { | ||
867 | wl1271_warning("illegal value in rx_streaming_interval!"); | ||
868 | return -EINVAL; | ||
869 | } | ||
870 | |||
871 | /* valid values: 0, 10-100 */ | ||
872 | if (value && (value < 10 || value > 100)) { | ||
873 | wl1271_warning("value is not in range!"); | ||
874 | return -ERANGE; | ||
875 | } | ||
876 | |||
877 | mutex_lock(&wl->mutex); | ||
878 | |||
879 | wl->conf.rx_streaming.interval = value; | ||
880 | |||
881 | ret = wl1271_ps_elp_wakeup(wl); | ||
882 | if (ret < 0) | ||
883 | goto out; | ||
884 | |||
885 | wl12xx_for_each_wlvif_sta(wl, wlvif) { | ||
886 | wl1271_recalc_rx_streaming(wl, wlvif); | ||
887 | } | ||
888 | |||
889 | wl1271_ps_elp_sleep(wl); | ||
890 | out: | ||
891 | mutex_unlock(&wl->mutex); | ||
892 | return count; | ||
893 | } | ||
894 | |||
895 | static ssize_t rx_streaming_interval_read(struct file *file, | ||
896 | char __user *userbuf, | ||
897 | size_t count, loff_t *ppos) | ||
898 | { | ||
899 | struct wl1271 *wl = file->private_data; | ||
900 | return wl1271_format_buffer(userbuf, count, ppos, | ||
901 | "%d\n", wl->conf.rx_streaming.interval); | ||
902 | } | ||
903 | |||
904 | static const struct file_operations rx_streaming_interval_ops = { | ||
905 | .read = rx_streaming_interval_read, | ||
906 | .write = rx_streaming_interval_write, | ||
907 | .open = wl1271_open_file_generic, | ||
908 | .llseek = default_llseek, | ||
909 | }; | ||
910 | |||
911 | static ssize_t rx_streaming_always_write(struct file *file, | ||
912 | const char __user *user_buf, | ||
913 | size_t count, loff_t *ppos) | ||
914 | { | ||
915 | struct wl1271 *wl = file->private_data; | ||
916 | struct wl12xx_vif *wlvif; | ||
917 | unsigned long value; | ||
918 | int ret; | ||
919 | |||
920 | ret = kstrtoul_from_user(user_buf, count, 10, &value); | ||
921 | if (ret < 0) { | ||
922 | wl1271_warning("illegal value in rx_streaming_write!"); | ||
923 | return -EINVAL; | ||
924 | } | ||
925 | |||
926 | /* valid values: 0, 10-100 */ | ||
927 | if (!(value == 0 || value == 1)) { | ||
928 | wl1271_warning("value is not in valid!"); | ||
929 | return -EINVAL; | ||
930 | } | ||
931 | |||
932 | mutex_lock(&wl->mutex); | ||
933 | |||
934 | wl->conf.rx_streaming.always = value; | ||
935 | |||
936 | ret = wl1271_ps_elp_wakeup(wl); | ||
937 | if (ret < 0) | ||
938 | goto out; | ||
939 | |||
940 | wl12xx_for_each_wlvif_sta(wl, wlvif) { | ||
941 | wl1271_recalc_rx_streaming(wl, wlvif); | ||
942 | } | ||
943 | |||
944 | wl1271_ps_elp_sleep(wl); | ||
945 | out: | ||
946 | mutex_unlock(&wl->mutex); | ||
947 | return count; | ||
948 | } | ||
949 | |||
950 | static ssize_t rx_streaming_always_read(struct file *file, | ||
951 | char __user *userbuf, | ||
952 | size_t count, loff_t *ppos) | ||
953 | { | ||
954 | struct wl1271 *wl = file->private_data; | ||
955 | return wl1271_format_buffer(userbuf, count, ppos, | ||
956 | "%d\n", wl->conf.rx_streaming.always); | ||
957 | } | ||
958 | |||
959 | static const struct file_operations rx_streaming_always_ops = { | ||
960 | .read = rx_streaming_always_read, | ||
961 | .write = rx_streaming_always_write, | ||
962 | .open = wl1271_open_file_generic, | ||
963 | .llseek = default_llseek, | ||
964 | }; | ||
965 | |||
966 | static ssize_t beacon_filtering_write(struct file *file, | ||
967 | const char __user *user_buf, | ||
968 | size_t count, loff_t *ppos) | ||
969 | { | ||
970 | struct wl1271 *wl = file->private_data; | ||
971 | struct wl12xx_vif *wlvif; | ||
972 | char buf[10]; | ||
973 | size_t len; | ||
974 | unsigned long value; | ||
975 | int ret; | ||
976 | |||
977 | len = min(count, sizeof(buf) - 1); | ||
978 | if (copy_from_user(buf, user_buf, len)) | ||
979 | return -EFAULT; | ||
980 | buf[len] = '\0'; | ||
981 | |||
982 | ret = kstrtoul(buf, 0, &value); | ||
983 | if (ret < 0) { | ||
984 | wl1271_warning("illegal value for beacon_filtering!"); | ||
985 | return -EINVAL; | ||
986 | } | ||
987 | |||
988 | mutex_lock(&wl->mutex); | ||
989 | |||
990 | ret = wl1271_ps_elp_wakeup(wl); | ||
991 | if (ret < 0) | ||
992 | goto out; | ||
993 | |||
994 | wl12xx_for_each_wlvif(wl, wlvif) { | ||
995 | ret = wl1271_acx_beacon_filter_opt(wl, wlvif, !!value); | ||
996 | } | ||
997 | |||
998 | wl1271_ps_elp_sleep(wl); | ||
999 | out: | ||
1000 | mutex_unlock(&wl->mutex); | ||
1001 | return count; | ||
1002 | } | ||
1003 | |||
1004 | static const struct file_operations beacon_filtering_ops = { | ||
1005 | .write = beacon_filtering_write, | ||
1006 | .open = wl1271_open_file_generic, | ||
1007 | .llseek = default_llseek, | ||
1008 | }; | ||
1009 | |||
1010 | static int wl1271_debugfs_add_files(struct wl1271 *wl, | ||
1011 | struct dentry *rootdir) | ||
1012 | { | ||
1013 | int ret = 0; | ||
1014 | struct dentry *entry, *stats, *streaming; | ||
1015 | |||
1016 | stats = debugfs_create_dir("fw-statistics", rootdir); | ||
1017 | if (!stats || IS_ERR(stats)) { | ||
1018 | entry = stats; | ||
1019 | goto err; | ||
1020 | } | ||
1021 | |||
1022 | DEBUGFS_FWSTATS_ADD(tx, internal_desc_overflow); | ||
1023 | |||
1024 | DEBUGFS_FWSTATS_ADD(rx, out_of_mem); | ||
1025 | DEBUGFS_FWSTATS_ADD(rx, hdr_overflow); | ||
1026 | DEBUGFS_FWSTATS_ADD(rx, hw_stuck); | ||
1027 | DEBUGFS_FWSTATS_ADD(rx, dropped); | ||
1028 | DEBUGFS_FWSTATS_ADD(rx, fcs_err); | ||
1029 | DEBUGFS_FWSTATS_ADD(rx, xfr_hint_trig); | ||
1030 | DEBUGFS_FWSTATS_ADD(rx, path_reset); | ||
1031 | DEBUGFS_FWSTATS_ADD(rx, reset_counter); | ||
1032 | |||
1033 | DEBUGFS_FWSTATS_ADD(dma, rx_requested); | ||
1034 | DEBUGFS_FWSTATS_ADD(dma, rx_errors); | ||
1035 | DEBUGFS_FWSTATS_ADD(dma, tx_requested); | ||
1036 | DEBUGFS_FWSTATS_ADD(dma, tx_errors); | ||
1037 | |||
1038 | DEBUGFS_FWSTATS_ADD(isr, cmd_cmplt); | ||
1039 | DEBUGFS_FWSTATS_ADD(isr, fiqs); | ||
1040 | DEBUGFS_FWSTATS_ADD(isr, rx_headers); | ||
1041 | DEBUGFS_FWSTATS_ADD(isr, rx_mem_overflow); | ||
1042 | DEBUGFS_FWSTATS_ADD(isr, rx_rdys); | ||
1043 | DEBUGFS_FWSTATS_ADD(isr, irqs); | ||
1044 | DEBUGFS_FWSTATS_ADD(isr, tx_procs); | ||
1045 | DEBUGFS_FWSTATS_ADD(isr, decrypt_done); | ||
1046 | DEBUGFS_FWSTATS_ADD(isr, dma0_done); | ||
1047 | DEBUGFS_FWSTATS_ADD(isr, dma1_done); | ||
1048 | DEBUGFS_FWSTATS_ADD(isr, tx_exch_complete); | ||
1049 | DEBUGFS_FWSTATS_ADD(isr, commands); | ||
1050 | DEBUGFS_FWSTATS_ADD(isr, rx_procs); | ||
1051 | DEBUGFS_FWSTATS_ADD(isr, hw_pm_mode_changes); | ||
1052 | DEBUGFS_FWSTATS_ADD(isr, host_acknowledges); | ||
1053 | DEBUGFS_FWSTATS_ADD(isr, pci_pm); | ||
1054 | DEBUGFS_FWSTATS_ADD(isr, wakeups); | ||
1055 | DEBUGFS_FWSTATS_ADD(isr, low_rssi); | ||
1056 | |||
1057 | DEBUGFS_FWSTATS_ADD(wep, addr_key_count); | ||
1058 | DEBUGFS_FWSTATS_ADD(wep, default_key_count); | ||
1059 | /* skipping wep.reserved */ | ||
1060 | DEBUGFS_FWSTATS_ADD(wep, key_not_found); | ||
1061 | DEBUGFS_FWSTATS_ADD(wep, decrypt_fail); | ||
1062 | DEBUGFS_FWSTATS_ADD(wep, packets); | ||
1063 | DEBUGFS_FWSTATS_ADD(wep, interrupt); | ||
1064 | |||
1065 | DEBUGFS_FWSTATS_ADD(pwr, ps_enter); | ||
1066 | DEBUGFS_FWSTATS_ADD(pwr, elp_enter); | ||
1067 | DEBUGFS_FWSTATS_ADD(pwr, missing_bcns); | ||
1068 | DEBUGFS_FWSTATS_ADD(pwr, wake_on_host); | ||
1069 | DEBUGFS_FWSTATS_ADD(pwr, wake_on_timer_exp); | ||
1070 | DEBUGFS_FWSTATS_ADD(pwr, tx_with_ps); | ||
1071 | DEBUGFS_FWSTATS_ADD(pwr, tx_without_ps); | ||
1072 | DEBUGFS_FWSTATS_ADD(pwr, rcvd_beacons); | ||
1073 | DEBUGFS_FWSTATS_ADD(pwr, power_save_off); | ||
1074 | DEBUGFS_FWSTATS_ADD(pwr, enable_ps); | ||
1075 | DEBUGFS_FWSTATS_ADD(pwr, disable_ps); | ||
1076 | DEBUGFS_FWSTATS_ADD(pwr, fix_tsf_ps); | ||
1077 | /* skipping cont_miss_bcns_spread for now */ | ||
1078 | DEBUGFS_FWSTATS_ADD(pwr, rcvd_awake_beacons); | ||
1079 | |||
1080 | DEBUGFS_FWSTATS_ADD(mic, rx_pkts); | ||
1081 | DEBUGFS_FWSTATS_ADD(mic, calc_failure); | ||
1082 | |||
1083 | DEBUGFS_FWSTATS_ADD(aes, encrypt_fail); | ||
1084 | DEBUGFS_FWSTATS_ADD(aes, decrypt_fail); | ||
1085 | DEBUGFS_FWSTATS_ADD(aes, encrypt_packets); | ||
1086 | DEBUGFS_FWSTATS_ADD(aes, decrypt_packets); | ||
1087 | DEBUGFS_FWSTATS_ADD(aes, encrypt_interrupt); | ||
1088 | DEBUGFS_FWSTATS_ADD(aes, decrypt_interrupt); | ||
1089 | |||
1090 | DEBUGFS_FWSTATS_ADD(event, heart_beat); | ||
1091 | DEBUGFS_FWSTATS_ADD(event, calibration); | ||
1092 | DEBUGFS_FWSTATS_ADD(event, rx_mismatch); | ||
1093 | DEBUGFS_FWSTATS_ADD(event, rx_mem_empty); | ||
1094 | DEBUGFS_FWSTATS_ADD(event, rx_pool); | ||
1095 | DEBUGFS_FWSTATS_ADD(event, oom_late); | ||
1096 | DEBUGFS_FWSTATS_ADD(event, phy_transmit_error); | ||
1097 | DEBUGFS_FWSTATS_ADD(event, tx_stuck); | ||
1098 | |||
1099 | DEBUGFS_FWSTATS_ADD(ps, pspoll_timeouts); | ||
1100 | DEBUGFS_FWSTATS_ADD(ps, upsd_timeouts); | ||
1101 | DEBUGFS_FWSTATS_ADD(ps, upsd_max_sptime); | ||
1102 | DEBUGFS_FWSTATS_ADD(ps, upsd_max_apturn); | ||
1103 | DEBUGFS_FWSTATS_ADD(ps, pspoll_max_apturn); | ||
1104 | DEBUGFS_FWSTATS_ADD(ps, pspoll_utilization); | ||
1105 | DEBUGFS_FWSTATS_ADD(ps, upsd_utilization); | ||
1106 | |||
1107 | DEBUGFS_FWSTATS_ADD(rxpipe, rx_prep_beacon_drop); | ||
1108 | DEBUGFS_FWSTATS_ADD(rxpipe, descr_host_int_trig_rx_data); | ||
1109 | DEBUGFS_FWSTATS_ADD(rxpipe, beacon_buffer_thres_host_int_trig_rx_data); | ||
1110 | DEBUGFS_FWSTATS_ADD(rxpipe, missed_beacon_host_int_trig_rx_data); | ||
1111 | DEBUGFS_FWSTATS_ADD(rxpipe, tx_xfr_host_int_trig_rx_data); | ||
1112 | |||
1113 | DEBUGFS_ADD(tx_queue_len, rootdir); | ||
1114 | DEBUGFS_ADD(retry_count, rootdir); | ||
1115 | DEBUGFS_ADD(excessive_retries, rootdir); | ||
1116 | |||
1117 | DEBUGFS_ADD(gpio_power, rootdir); | ||
1118 | DEBUGFS_ADD(start_recovery, rootdir); | ||
1119 | DEBUGFS_ADD(driver_state, rootdir); | ||
1120 | DEBUGFS_ADD(vifs_state, rootdir); | ||
1121 | DEBUGFS_ADD(dtim_interval, rootdir); | ||
1122 | DEBUGFS_ADD(suspend_dtim_interval, rootdir); | ||
1123 | DEBUGFS_ADD(beacon_interval, rootdir); | ||
1124 | DEBUGFS_ADD(beacon_filtering, rootdir); | ||
1125 | DEBUGFS_ADD(dynamic_ps_timeout, rootdir); | ||
1126 | DEBUGFS_ADD(forced_ps, rootdir); | ||
1127 | DEBUGFS_ADD(split_scan_timeout, rootdir); | ||
1128 | |||
1129 | streaming = debugfs_create_dir("rx_streaming", rootdir); | ||
1130 | if (!streaming || IS_ERR(streaming)) | ||
1131 | goto err; | ||
1132 | |||
1133 | DEBUGFS_ADD_PREFIX(rx_streaming, interval, streaming); | ||
1134 | DEBUGFS_ADD_PREFIX(rx_streaming, always, streaming); | ||
1135 | |||
1136 | |||
1137 | return 0; | ||
1138 | |||
1139 | err: | ||
1140 | if (IS_ERR(entry)) | ||
1141 | ret = PTR_ERR(entry); | ||
1142 | else | ||
1143 | ret = -ENOMEM; | ||
1144 | |||
1145 | return ret; | ||
1146 | } | ||
1147 | |||
1148 | void wl1271_debugfs_reset(struct wl1271 *wl) | ||
1149 | { | ||
1150 | if (!wl->stats.fw_stats) | ||
1151 | return; | ||
1152 | |||
1153 | memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats)); | ||
1154 | wl->stats.retry_count = 0; | ||
1155 | wl->stats.excessive_retries = 0; | ||
1156 | } | ||
1157 | |||
1158 | int wl1271_debugfs_init(struct wl1271 *wl) | ||
1159 | { | ||
1160 | int ret; | ||
1161 | struct dentry *rootdir; | ||
1162 | |||
1163 | rootdir = debugfs_create_dir(KBUILD_MODNAME, | ||
1164 | wl->hw->wiphy->debugfsdir); | ||
1165 | |||
1166 | if (IS_ERR(rootdir)) { | ||
1167 | ret = PTR_ERR(rootdir); | ||
1168 | goto err; | ||
1169 | } | ||
1170 | |||
1171 | wl->stats.fw_stats = kzalloc(sizeof(*wl->stats.fw_stats), | ||
1172 | GFP_KERNEL); | ||
1173 | |||
1174 | if (!wl->stats.fw_stats) { | ||
1175 | ret = -ENOMEM; | ||
1176 | goto err_fw; | ||
1177 | } | ||
1178 | |||
1179 | wl->stats.fw_stats_update = jiffies; | ||
1180 | |||
1181 | ret = wl1271_debugfs_add_files(wl, rootdir); | ||
1182 | |||
1183 | if (ret < 0) | ||
1184 | goto err_file; | ||
1185 | |||
1186 | return 0; | ||
1187 | |||
1188 | err_file: | ||
1189 | kfree(wl->stats.fw_stats); | ||
1190 | wl->stats.fw_stats = NULL; | ||
1191 | |||
1192 | err_fw: | ||
1193 | debugfs_remove_recursive(rootdir); | ||
1194 | |||
1195 | err: | ||
1196 | return ret; | ||
1197 | } | ||
1198 | |||
1199 | void wl1271_debugfs_exit(struct wl1271 *wl) | ||
1200 | { | ||
1201 | kfree(wl->stats.fw_stats); | ||
1202 | wl->stats.fw_stats = NULL; | ||
1203 | } | ||
diff --git a/drivers/net/wireless/ti/wl12xx/debugfs.h b/drivers/net/wireless/ti/wl12xx/debugfs.h new file mode 100644 index 000000000000..254c5b292cf6 --- /dev/null +++ b/drivers/net/wireless/ti/wl12xx/debugfs.h | |||
@@ -0,0 +1,33 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2009 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 __DEBUGFS_H__ | ||
25 | #define __DEBUGFS_H__ | ||
26 | |||
27 | #include "wl12xx.h" | ||
28 | |||
29 | int wl1271_debugfs_init(struct wl1271 *wl); | ||
30 | void wl1271_debugfs_exit(struct wl1271 *wl); | ||
31 | void wl1271_debugfs_reset(struct wl1271 *wl); | ||
32 | |||
33 | #endif /* WL1271_DEBUGFS_H */ | ||
diff --git a/drivers/net/wireless/ti/wl12xx/event.c b/drivers/net/wireless/ti/wl12xx/event.c new file mode 100644 index 000000000000..96f06a89c2a9 --- /dev/null +++ b/drivers/net/wireless/ti/wl12xx/event.c | |||
@@ -0,0 +1,313 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2008-2009 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 | #include "wl12xx.h" | ||
25 | #include "debug.h" | ||
26 | #include "reg.h" | ||
27 | #include "io.h" | ||
28 | #include "event.h" | ||
29 | #include "ps.h" | ||
30 | #include "scan.h" | ||
31 | #include "wl12xx_80211.h" | ||
32 | |||
33 | static void wl1271_event_rssi_trigger(struct wl1271 *wl, | ||
34 | struct wl12xx_vif *wlvif, | ||
35 | struct event_mailbox *mbox) | ||
36 | { | ||
37 | struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); | ||
38 | enum nl80211_cqm_rssi_threshold_event event; | ||
39 | s8 metric = mbox->rssi_snr_trigger_metric[0]; | ||
40 | |||
41 | wl1271_debug(DEBUG_EVENT, "RSSI trigger metric: %d", metric); | ||
42 | |||
43 | if (metric <= wlvif->rssi_thold) | ||
44 | event = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW; | ||
45 | else | ||
46 | event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH; | ||
47 | |||
48 | if (event != wlvif->last_rssi_event) | ||
49 | ieee80211_cqm_rssi_notify(vif, event, GFP_KERNEL); | ||
50 | wlvif->last_rssi_event = event; | ||
51 | } | ||
52 | |||
53 | static void wl1271_stop_ba_event(struct wl1271 *wl, struct wl12xx_vif *wlvif) | ||
54 | { | ||
55 | struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); | ||
56 | |||
57 | if (wlvif->bss_type != BSS_TYPE_AP_BSS) { | ||
58 | if (!wlvif->sta.ba_rx_bitmap) | ||
59 | return; | ||
60 | ieee80211_stop_rx_ba_session(vif, wlvif->sta.ba_rx_bitmap, | ||
61 | vif->bss_conf.bssid); | ||
62 | } else { | ||
63 | u8 hlid; | ||
64 | struct wl1271_link *lnk; | ||
65 | for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, | ||
66 | WL12XX_MAX_LINKS) { | ||
67 | lnk = &wl->links[hlid]; | ||
68 | if (!lnk->ba_bitmap) | ||
69 | continue; | ||
70 | |||
71 | ieee80211_stop_rx_ba_session(vif, | ||
72 | lnk->ba_bitmap, | ||
73 | lnk->addr); | ||
74 | } | ||
75 | } | ||
76 | } | ||
77 | |||
78 | static void wl12xx_event_soft_gemini_sense(struct wl1271 *wl, | ||
79 | u8 enable) | ||
80 | { | ||
81 | struct wl12xx_vif *wlvif; | ||
82 | |||
83 | if (enable) { | ||
84 | set_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags); | ||
85 | } else { | ||
86 | clear_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags); | ||
87 | wl12xx_for_each_wlvif_sta(wl, wlvif) { | ||
88 | wl1271_recalc_rx_streaming(wl, wlvif); | ||
89 | } | ||
90 | } | ||
91 | |||
92 | } | ||
93 | |||
94 | static void wl1271_event_mbox_dump(struct event_mailbox *mbox) | ||
95 | { | ||
96 | wl1271_debug(DEBUG_EVENT, "MBOX DUMP:"); | ||
97 | wl1271_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector); | ||
98 | wl1271_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask); | ||
99 | } | ||
100 | |||
101 | static int wl1271_event_process(struct wl1271 *wl) | ||
102 | { | ||
103 | struct event_mailbox *mbox = wl->mbox; | ||
104 | struct ieee80211_vif *vif; | ||
105 | struct wl12xx_vif *wlvif; | ||
106 | u32 vector; | ||
107 | bool beacon_loss = false; | ||
108 | bool disconnect_sta = false; | ||
109 | unsigned long sta_bitmap = 0; | ||
110 | |||
111 | wl1271_event_mbox_dump(mbox); | ||
112 | |||
113 | vector = le32_to_cpu(mbox->events_vector); | ||
114 | vector &= ~(le32_to_cpu(mbox->events_mask)); | ||
115 | wl1271_debug(DEBUG_EVENT, "vector: 0x%x", vector); | ||
116 | |||
117 | if (vector & SCAN_COMPLETE_EVENT_ID) { | ||
118 | wl1271_debug(DEBUG_EVENT, "status: 0x%x", | ||
119 | mbox->scheduled_scan_status); | ||
120 | |||
121 | wl1271_scan_stm(wl, wl->scan_vif); | ||
122 | } | ||
123 | |||
124 | if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) { | ||
125 | wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_REPORT_EVENT " | ||
126 | "(status 0x%0x)", mbox->scheduled_scan_status); | ||
127 | |||
128 | wl1271_scan_sched_scan_results(wl); | ||
129 | } | ||
130 | |||
131 | if (vector & PERIODIC_SCAN_COMPLETE_EVENT_ID) { | ||
132 | wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_COMPLETE_EVENT " | ||
133 | "(status 0x%0x)", mbox->scheduled_scan_status); | ||
134 | if (wl->sched_scanning) { | ||
135 | ieee80211_sched_scan_stopped(wl->hw); | ||
136 | wl->sched_scanning = false; | ||
137 | } | ||
138 | } | ||
139 | |||
140 | if (vector & SOFT_GEMINI_SENSE_EVENT_ID) | ||
141 | wl12xx_event_soft_gemini_sense(wl, | ||
142 | mbox->soft_gemini_sense_info); | ||
143 | |||
144 | /* | ||
145 | * The BSS_LOSE_EVENT_ID is only needed while psm (and hence beacon | ||
146 | * filtering) is enabled. Without PSM, the stack will receive all | ||
147 | * beacons and can detect beacon loss by itself. | ||
148 | * | ||
149 | * As there's possibility that the driver disables PSM before receiving | ||
150 | * BSS_LOSE_EVENT, beacon loss has to be reported to the stack. | ||
151 | * | ||
152 | */ | ||
153 | if (vector & BSS_LOSE_EVENT_ID) { | ||
154 | /* TODO: check for multi-role */ | ||
155 | wl1271_info("Beacon loss detected."); | ||
156 | |||
157 | /* indicate to the stack, that beacons have been lost */ | ||
158 | beacon_loss = true; | ||
159 | } | ||
160 | |||
161 | if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) { | ||
162 | /* TODO: check actual multi-role support */ | ||
163 | wl1271_debug(DEBUG_EVENT, "RSSI_SNR_TRIGGER_0_EVENT"); | ||
164 | wl12xx_for_each_wlvif_sta(wl, wlvif) { | ||
165 | wl1271_event_rssi_trigger(wl, wlvif, mbox); | ||
166 | } | ||
167 | } | ||
168 | |||
169 | if (vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID) { | ||
170 | u8 role_id = mbox->role_id; | ||
171 | wl1271_debug(DEBUG_EVENT, "BA_SESSION_RX_CONSTRAINT_EVENT_ID. " | ||
172 | "ba_allowed = 0x%x, role_id=%d", | ||
173 | mbox->rx_ba_allowed, role_id); | ||
174 | |||
175 | wl12xx_for_each_wlvif(wl, wlvif) { | ||
176 | if (role_id != 0xff && role_id != wlvif->role_id) | ||
177 | continue; | ||
178 | |||
179 | wlvif->ba_allowed = !!mbox->rx_ba_allowed; | ||
180 | if (!wlvif->ba_allowed) | ||
181 | wl1271_stop_ba_event(wl, wlvif); | ||
182 | } | ||
183 | } | ||
184 | |||
185 | if (vector & CHANNEL_SWITCH_COMPLETE_EVENT_ID) { | ||
186 | wl1271_debug(DEBUG_EVENT, "CHANNEL_SWITCH_COMPLETE_EVENT_ID. " | ||
187 | "status = 0x%x", | ||
188 | mbox->channel_switch_status); | ||
189 | /* | ||
190 | * That event uses for two cases: | ||
191 | * 1) channel switch complete with status=0 | ||
192 | * 2) channel switch failed status=1 | ||
193 | */ | ||
194 | |||
195 | /* TODO: configure only the relevant vif */ | ||
196 | wl12xx_for_each_wlvif_sta(wl, wlvif) { | ||
197 | bool success; | ||
198 | |||
199 | if (!test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, | ||
200 | &wlvif->flags)) | ||
201 | continue; | ||
202 | |||
203 | success = mbox->channel_switch_status ? false : true; | ||
204 | vif = wl12xx_wlvif_to_vif(wlvif); | ||
205 | |||
206 | ieee80211_chswitch_done(vif, success); | ||
207 | } | ||
208 | } | ||
209 | |||
210 | if ((vector & DUMMY_PACKET_EVENT_ID)) { | ||
211 | wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID"); | ||
212 | wl1271_tx_dummy_packet(wl); | ||
213 | } | ||
214 | |||
215 | /* | ||
216 | * "TX retries exceeded" has a different meaning according to mode. | ||
217 | * In AP mode the offending station is disconnected. | ||
218 | */ | ||
219 | if (vector & MAX_TX_RETRY_EVENT_ID) { | ||
220 | wl1271_debug(DEBUG_EVENT, "MAX_TX_RETRY_EVENT_ID"); | ||
221 | sta_bitmap |= le16_to_cpu(mbox->sta_tx_retry_exceeded); | ||
222 | disconnect_sta = true; | ||
223 | } | ||
224 | |||
225 | if (vector & INACTIVE_STA_EVENT_ID) { | ||
226 | wl1271_debug(DEBUG_EVENT, "INACTIVE_STA_EVENT_ID"); | ||
227 | sta_bitmap |= le16_to_cpu(mbox->sta_aging_status); | ||
228 | disconnect_sta = true; | ||
229 | } | ||
230 | |||
231 | if (disconnect_sta) { | ||
232 | u32 num_packets = wl->conf.tx.max_tx_retries; | ||
233 | struct ieee80211_sta *sta; | ||
234 | const u8 *addr; | ||
235 | int h; | ||
236 | |||
237 | for_each_set_bit(h, &sta_bitmap, WL12XX_MAX_LINKS) { | ||
238 | bool found = false; | ||
239 | /* find the ap vif connected to this sta */ | ||
240 | wl12xx_for_each_wlvif_ap(wl, wlvif) { | ||
241 | if (!test_bit(h, wlvif->ap.sta_hlid_map)) | ||
242 | continue; | ||
243 | found = true; | ||
244 | break; | ||
245 | } | ||
246 | if (!found) | ||
247 | continue; | ||
248 | |||
249 | vif = wl12xx_wlvif_to_vif(wlvif); | ||
250 | addr = wl->links[h].addr; | ||
251 | |||
252 | rcu_read_lock(); | ||
253 | sta = ieee80211_find_sta(vif, addr); | ||
254 | if (sta) { | ||
255 | wl1271_debug(DEBUG_EVENT, "remove sta %d", h); | ||
256 | ieee80211_report_low_ack(sta, num_packets); | ||
257 | } | ||
258 | rcu_read_unlock(); | ||
259 | } | ||
260 | } | ||
261 | |||
262 | if (beacon_loss) | ||
263 | wl12xx_for_each_wlvif_sta(wl, wlvif) { | ||
264 | vif = wl12xx_wlvif_to_vif(wlvif); | ||
265 | ieee80211_connection_loss(vif); | ||
266 | } | ||
267 | |||
268 | return 0; | ||
269 | } | ||
270 | |||
271 | int wl1271_event_unmask(struct wl1271 *wl) | ||
272 | { | ||
273 | int ret; | ||
274 | |||
275 | ret = wl1271_acx_event_mbox_mask(wl, ~(wl->event_mask)); | ||
276 | if (ret < 0) | ||
277 | return ret; | ||
278 | |||
279 | return 0; | ||
280 | } | ||
281 | |||
282 | void wl1271_event_mbox_config(struct wl1271 *wl) | ||
283 | { | ||
284 | wl->mbox_ptr[0] = wl1271_read32(wl, REG_EVENT_MAILBOX_PTR); | ||
285 | wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox); | ||
286 | |||
287 | wl1271_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x", | ||
288 | wl->mbox_ptr[0], wl->mbox_ptr[1]); | ||
289 | } | ||
290 | |||
291 | int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num) | ||
292 | { | ||
293 | int ret; | ||
294 | |||
295 | wl1271_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num); | ||
296 | |||
297 | if (mbox_num > 1) | ||
298 | return -EINVAL; | ||
299 | |||
300 | /* first we read the mbox descriptor */ | ||
301 | wl1271_read(wl, wl->mbox_ptr[mbox_num], wl->mbox, | ||
302 | sizeof(*wl->mbox), false); | ||
303 | |||
304 | /* process the descriptor */ | ||
305 | ret = wl1271_event_process(wl); | ||
306 | if (ret < 0) | ||
307 | return ret; | ||
308 | |||
309 | /* then we let the firmware know it can go on...*/ | ||
310 | wl1271_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK); | ||
311 | |||
312 | return 0; | ||
313 | } | ||
diff --git a/drivers/net/wireless/ti/wl12xx/event.h b/drivers/net/wireless/ti/wl12xx/event.h new file mode 100644 index 000000000000..8acba0d43976 --- /dev/null +++ b/drivers/net/wireless/ti/wl12xx/event.h | |||
@@ -0,0 +1,141 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. | ||
5 | * Copyright (C) 2008-2009 Nokia Corporation | ||
6 | * | ||
7 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef __EVENT_H__ | ||
26 | #define __EVENT_H__ | ||
27 | |||
28 | /* | ||
29 | * Mbox events | ||
30 | * | ||
31 | * The event mechanism is based on a pair of event buffers (buffers A and | ||
32 | * B) at fixed locations in the target's memory. The host processes one | ||
33 | * buffer while the other buffer continues to collect events. If the host | ||
34 | * is not processing events, an interrupt is issued to signal that a buffer | ||
35 | * is ready. Once the host is done with processing events from one buffer, | ||
36 | * it signals the target (with an ACK interrupt) that the event buffer is | ||
37 | * free. | ||
38 | */ | ||
39 | |||
40 | enum { | ||
41 | RSSI_SNR_TRIGGER_0_EVENT_ID = BIT(0), | ||
42 | RSSI_SNR_TRIGGER_1_EVENT_ID = BIT(1), | ||
43 | RSSI_SNR_TRIGGER_2_EVENT_ID = BIT(2), | ||
44 | RSSI_SNR_TRIGGER_3_EVENT_ID = BIT(3), | ||
45 | RSSI_SNR_TRIGGER_4_EVENT_ID = BIT(4), | ||
46 | RSSI_SNR_TRIGGER_5_EVENT_ID = BIT(5), | ||
47 | RSSI_SNR_TRIGGER_6_EVENT_ID = BIT(6), | ||
48 | RSSI_SNR_TRIGGER_7_EVENT_ID = BIT(7), | ||
49 | MEASUREMENT_START_EVENT_ID = BIT(8), | ||
50 | MEASUREMENT_COMPLETE_EVENT_ID = BIT(9), | ||
51 | SCAN_COMPLETE_EVENT_ID = BIT(10), | ||
52 | WFD_DISCOVERY_COMPLETE_EVENT_ID = BIT(11), | ||
53 | AP_DISCOVERY_COMPLETE_EVENT_ID = BIT(12), | ||
54 | RESERVED1 = BIT(13), | ||
55 | PSPOLL_DELIVERY_FAILURE_EVENT_ID = BIT(14), | ||
56 | ROLE_STOP_COMPLETE_EVENT_ID = BIT(15), | ||
57 | RADAR_DETECTED_EVENT_ID = BIT(16), | ||
58 | CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(17), | ||
59 | BSS_LOSE_EVENT_ID = BIT(18), | ||
60 | REGAINED_BSS_EVENT_ID = BIT(19), | ||
61 | MAX_TX_RETRY_EVENT_ID = BIT(20), | ||
62 | DUMMY_PACKET_EVENT_ID = BIT(21), | ||
63 | SOFT_GEMINI_SENSE_EVENT_ID = BIT(22), | ||
64 | CHANGE_AUTO_MODE_TIMEOUT_EVENT_ID = BIT(23), | ||
65 | SOFT_GEMINI_AVALANCHE_EVENT_ID = BIT(24), | ||
66 | PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(25), | ||
67 | INACTIVE_STA_EVENT_ID = BIT(26), | ||
68 | PEER_REMOVE_COMPLETE_EVENT_ID = BIT(27), | ||
69 | PERIODIC_SCAN_COMPLETE_EVENT_ID = BIT(28), | ||
70 | PERIODIC_SCAN_REPORT_EVENT_ID = BIT(29), | ||
71 | BA_SESSION_RX_CONSTRAINT_EVENT_ID = BIT(30), | ||
72 | REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID = BIT(31), | ||
73 | EVENT_MBOX_ALL_EVENT_ID = 0x7fffffff, | ||
74 | }; | ||
75 | |||
76 | enum { | ||
77 | EVENT_ENTER_POWER_SAVE_FAIL = 0, | ||
78 | EVENT_ENTER_POWER_SAVE_SUCCESS, | ||
79 | }; | ||
80 | |||
81 | #define NUM_OF_RSSI_SNR_TRIGGERS 8 | ||
82 | |||
83 | struct event_mailbox { | ||
84 | __le32 events_vector; | ||
85 | __le32 events_mask; | ||
86 | __le32 reserved_1; | ||
87 | __le32 reserved_2; | ||
88 | |||
89 | u8 number_of_scan_results; | ||
90 | u8 scan_tag; | ||
91 | u8 completed_scan_status; | ||
92 | u8 reserved_3; | ||
93 | |||
94 | u8 soft_gemini_sense_info; | ||
95 | u8 soft_gemini_protective_info; | ||
96 | s8 rssi_snr_trigger_metric[NUM_OF_RSSI_SNR_TRIGGERS]; | ||
97 | u8 change_auto_mode_timeout; | ||
98 | u8 scheduled_scan_status; | ||
99 | u8 reserved4; | ||
100 | /* tuned channel (roc) */ | ||
101 | u8 roc_channel; | ||
102 | |||
103 | __le16 hlid_removed_bitmap; | ||
104 | |||
105 | /* bitmap of aged stations (by HLID) */ | ||
106 | __le16 sta_aging_status; | ||
107 | |||
108 | /* bitmap of stations (by HLID) which exceeded max tx retries */ | ||
109 | __le16 sta_tx_retry_exceeded; | ||
110 | |||
111 | /* discovery completed results */ | ||
112 | u8 discovery_tag; | ||
113 | u8 number_of_preq_results; | ||
114 | u8 number_of_prsp_results; | ||
115 | u8 reserved_5; | ||
116 | |||
117 | /* rx ba constraint */ | ||
118 | u8 role_id; /* 0xFF means any role. */ | ||
119 | u8 rx_ba_allowed; | ||
120 | u8 reserved_6[2]; | ||
121 | |||
122 | /* Channel switch results */ | ||
123 | |||
124 | u8 channel_switch_role_id; | ||
125 | u8 channel_switch_status; | ||
126 | u8 reserved_7[2]; | ||
127 | |||
128 | u8 ps_poll_delivery_failure_role_ids; | ||
129 | u8 stopped_role_ids; | ||
130 | u8 started_role_ids; | ||
131 | |||
132 | u8 reserved_8[9]; | ||
133 | } __packed; | ||
134 | |||
135 | struct wl1271; | ||
136 | |||
137 | int wl1271_event_unmask(struct wl1271 *wl); | ||
138 | void wl1271_event_mbox_config(struct wl1271 *wl); | ||
139 | int wl1271_event_handle(struct wl1271 *wl, u8 mbox); | ||
140 | |||
141 | #endif | ||
diff --git a/drivers/net/wireless/ti/wl12xx/ini.h b/drivers/net/wireless/ti/wl12xx/ini.h new file mode 100644 index 000000000000..4cf9ecc56212 --- /dev/null +++ b/drivers/net/wireless/ti/wl12xx/ini.h | |||
@@ -0,0 +1,220 @@ | |||
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 __INI_H__ | ||
25 | #define __INI_H__ | ||
26 | |||
27 | #define GENERAL_SETTINGS_DRPW_LPD 0xc0 | ||
28 | #define SCRATCH_ENABLE_LPD BIT(25) | ||
29 | |||
30 | #define WL1271_INI_MAX_SMART_REFLEX_PARAM 16 | ||
31 | |||
32 | struct wl1271_ini_general_params { | ||
33 | u8 ref_clock; | ||
34 | u8 settling_time; | ||
35 | u8 clk_valid_on_wakeup; | ||
36 | u8 dc2dc_mode; | ||
37 | u8 dual_mode_select; | ||
38 | u8 tx_bip_fem_auto_detect; | ||
39 | u8 tx_bip_fem_manufacturer; | ||
40 | u8 general_settings; | ||
41 | u8 sr_state; | ||
42 | u8 srf1[WL1271_INI_MAX_SMART_REFLEX_PARAM]; | ||
43 | u8 srf2[WL1271_INI_MAX_SMART_REFLEX_PARAM]; | ||
44 | u8 srf3[WL1271_INI_MAX_SMART_REFLEX_PARAM]; | ||
45 | } __packed; | ||
46 | |||
47 | #define WL128X_INI_MAX_SETTINGS_PARAM 4 | ||
48 | |||
49 | struct wl128x_ini_general_params { | ||
50 | u8 ref_clock; | ||
51 | u8 settling_time; | ||
52 | u8 clk_valid_on_wakeup; | ||
53 | u8 tcxo_ref_clock; | ||
54 | u8 tcxo_settling_time; | ||
55 | u8 tcxo_valid_on_wakeup; | ||
56 | u8 tcxo_ldo_voltage; | ||
57 | u8 xtal_itrim_val; | ||
58 | u8 platform_conf; | ||
59 | u8 dual_mode_select; | ||
60 | u8 tx_bip_fem_auto_detect; | ||
61 | u8 tx_bip_fem_manufacturer; | ||
62 | u8 general_settings[WL128X_INI_MAX_SETTINGS_PARAM]; | ||
63 | u8 sr_state; | ||
64 | u8 srf1[WL1271_INI_MAX_SMART_REFLEX_PARAM]; | ||
65 | u8 srf2[WL1271_INI_MAX_SMART_REFLEX_PARAM]; | ||
66 | u8 srf3[WL1271_INI_MAX_SMART_REFLEX_PARAM]; | ||
67 | } __packed; | ||
68 | |||
69 | #define WL1271_INI_RSSI_PROCESS_COMPENS_SIZE 15 | ||
70 | |||
71 | struct wl1271_ini_band_params_2 { | ||
72 | u8 rx_trace_insertion_loss; | ||
73 | u8 tx_trace_loss; | ||
74 | u8 rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE]; | ||
75 | } __packed; | ||
76 | |||
77 | #define WL1271_INI_CHANNEL_COUNT_2 14 | ||
78 | |||
79 | struct wl128x_ini_band_params_2 { | ||
80 | u8 rx_trace_insertion_loss; | ||
81 | u8 tx_trace_loss[WL1271_INI_CHANNEL_COUNT_2]; | ||
82 | u8 rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE]; | ||
83 | } __packed; | ||
84 | |||
85 | #define WL1271_INI_RATE_GROUP_COUNT 6 | ||
86 | |||
87 | struct wl1271_ini_fem_params_2 { | ||
88 | __le16 tx_bip_ref_pd_voltage; | ||
89 | u8 tx_bip_ref_power; | ||
90 | u8 tx_bip_ref_offset; | ||
91 | u8 tx_per_rate_pwr_limits_normal[WL1271_INI_RATE_GROUP_COUNT]; | ||
92 | u8 tx_per_rate_pwr_limits_degraded[WL1271_INI_RATE_GROUP_COUNT]; | ||
93 | u8 tx_per_rate_pwr_limits_extreme[WL1271_INI_RATE_GROUP_COUNT]; | ||
94 | u8 tx_per_chan_pwr_limits_11b[WL1271_INI_CHANNEL_COUNT_2]; | ||
95 | u8 tx_per_chan_pwr_limits_ofdm[WL1271_INI_CHANNEL_COUNT_2]; | ||
96 | u8 tx_pd_vs_rate_offsets[WL1271_INI_RATE_GROUP_COUNT]; | ||
97 | u8 tx_ibias[WL1271_INI_RATE_GROUP_COUNT]; | ||
98 | u8 rx_fem_insertion_loss; | ||
99 | u8 degraded_low_to_normal_thr; | ||
100 | u8 normal_to_degraded_high_thr; | ||
101 | } __packed; | ||
102 | |||
103 | #define WL128X_INI_RATE_GROUP_COUNT 7 | ||
104 | /* low and high temperatures */ | ||
105 | #define WL128X_INI_PD_VS_TEMPERATURE_RANGES 2 | ||
106 | |||
107 | struct wl128x_ini_fem_params_2 { | ||
108 | __le16 tx_bip_ref_pd_voltage; | ||
109 | u8 tx_bip_ref_power; | ||
110 | u8 tx_bip_ref_offset; | ||
111 | u8 tx_per_rate_pwr_limits_normal[WL128X_INI_RATE_GROUP_COUNT]; | ||
112 | u8 tx_per_rate_pwr_limits_degraded[WL128X_INI_RATE_GROUP_COUNT]; | ||
113 | u8 tx_per_rate_pwr_limits_extreme[WL128X_INI_RATE_GROUP_COUNT]; | ||
114 | u8 tx_per_chan_pwr_limits_11b[WL1271_INI_CHANNEL_COUNT_2]; | ||
115 | u8 tx_per_chan_pwr_limits_ofdm[WL1271_INI_CHANNEL_COUNT_2]; | ||
116 | u8 tx_pd_vs_rate_offsets[WL128X_INI_RATE_GROUP_COUNT]; | ||
117 | u8 tx_ibias[WL128X_INI_RATE_GROUP_COUNT + 1]; | ||
118 | u8 tx_pd_vs_chan_offsets[WL1271_INI_CHANNEL_COUNT_2]; | ||
119 | u8 tx_pd_vs_temperature[WL128X_INI_PD_VS_TEMPERATURE_RANGES]; | ||
120 | u8 rx_fem_insertion_loss; | ||
121 | u8 degraded_low_to_normal_thr; | ||
122 | u8 normal_to_degraded_high_thr; | ||
123 | } __packed; | ||
124 | |||
125 | #define WL1271_INI_CHANNEL_COUNT_5 35 | ||
126 | #define WL1271_INI_SUB_BAND_COUNT_5 7 | ||
127 | |||
128 | struct wl1271_ini_band_params_5 { | ||
129 | u8 rx_trace_insertion_loss[WL1271_INI_SUB_BAND_COUNT_5]; | ||
130 | u8 tx_trace_loss[WL1271_INI_SUB_BAND_COUNT_5]; | ||
131 | u8 rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE]; | ||
132 | } __packed; | ||
133 | |||
134 | struct wl128x_ini_band_params_5 { | ||
135 | u8 rx_trace_insertion_loss[WL1271_INI_SUB_BAND_COUNT_5]; | ||
136 | u8 tx_trace_loss[WL1271_INI_CHANNEL_COUNT_5]; | ||
137 | u8 rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE]; | ||
138 | } __packed; | ||
139 | |||
140 | struct wl1271_ini_fem_params_5 { | ||
141 | __le16 tx_bip_ref_pd_voltage[WL1271_INI_SUB_BAND_COUNT_5]; | ||
142 | u8 tx_bip_ref_power[WL1271_INI_SUB_BAND_COUNT_5]; | ||
143 | u8 tx_bip_ref_offset[WL1271_INI_SUB_BAND_COUNT_5]; | ||
144 | u8 tx_per_rate_pwr_limits_normal[WL1271_INI_RATE_GROUP_COUNT]; | ||
145 | u8 tx_per_rate_pwr_limits_degraded[WL1271_INI_RATE_GROUP_COUNT]; | ||
146 | u8 tx_per_rate_pwr_limits_extreme[WL1271_INI_RATE_GROUP_COUNT]; | ||
147 | u8 tx_per_chan_pwr_limits_ofdm[WL1271_INI_CHANNEL_COUNT_5]; | ||
148 | u8 tx_pd_vs_rate_offsets[WL1271_INI_RATE_GROUP_COUNT]; | ||
149 | u8 tx_ibias[WL1271_INI_RATE_GROUP_COUNT]; | ||
150 | u8 rx_fem_insertion_loss[WL1271_INI_SUB_BAND_COUNT_5]; | ||
151 | u8 degraded_low_to_normal_thr; | ||
152 | u8 normal_to_degraded_high_thr; | ||
153 | } __packed; | ||
154 | |||
155 | struct wl128x_ini_fem_params_5 { | ||
156 | __le16 tx_bip_ref_pd_voltage[WL1271_INI_SUB_BAND_COUNT_5]; | ||
157 | u8 tx_bip_ref_power[WL1271_INI_SUB_BAND_COUNT_5]; | ||
158 | u8 tx_bip_ref_offset[WL1271_INI_SUB_BAND_COUNT_5]; | ||
159 | u8 tx_per_rate_pwr_limits_normal[WL128X_INI_RATE_GROUP_COUNT]; | ||
160 | u8 tx_per_rate_pwr_limits_degraded[WL128X_INI_RATE_GROUP_COUNT]; | ||
161 | u8 tx_per_rate_pwr_limits_extreme[WL128X_INI_RATE_GROUP_COUNT]; | ||
162 | u8 tx_per_chan_pwr_limits_ofdm[WL1271_INI_CHANNEL_COUNT_5]; | ||
163 | u8 tx_pd_vs_rate_offsets[WL128X_INI_RATE_GROUP_COUNT]; | ||
164 | u8 tx_ibias[WL128X_INI_RATE_GROUP_COUNT]; | ||
165 | u8 tx_pd_vs_chan_offsets[WL1271_INI_CHANNEL_COUNT_5]; | ||
166 | u8 tx_pd_vs_temperature[WL1271_INI_SUB_BAND_COUNT_5 * | ||
167 | WL128X_INI_PD_VS_TEMPERATURE_RANGES]; | ||
168 | u8 rx_fem_insertion_loss[WL1271_INI_SUB_BAND_COUNT_5]; | ||
169 | u8 degraded_low_to_normal_thr; | ||
170 | u8 normal_to_degraded_high_thr; | ||
171 | } __packed; | ||
172 | |||
173 | /* NVS data structure */ | ||
174 | #define WL1271_INI_NVS_SECTION_SIZE 468 | ||
175 | #define WL1271_INI_FEM_MODULE_COUNT 2 | ||
176 | |||
177 | #define WL1271_INI_LEGACY_NVS_FILE_SIZE 800 | ||
178 | |||
179 | struct wl1271_nvs_file { | ||
180 | /* NVS section - must be first! */ | ||
181 | u8 nvs[WL1271_INI_NVS_SECTION_SIZE]; | ||
182 | |||
183 | /* INI section */ | ||
184 | struct wl1271_ini_general_params general_params; | ||
185 | u8 padding1; | ||
186 | struct wl1271_ini_band_params_2 stat_radio_params_2; | ||
187 | u8 padding2; | ||
188 | struct { | ||
189 | struct wl1271_ini_fem_params_2 params; | ||
190 | u8 padding; | ||
191 | } dyn_radio_params_2[WL1271_INI_FEM_MODULE_COUNT]; | ||
192 | struct wl1271_ini_band_params_5 stat_radio_params_5; | ||
193 | u8 padding3; | ||
194 | struct { | ||
195 | struct wl1271_ini_fem_params_5 params; | ||
196 | u8 padding; | ||
197 | } dyn_radio_params_5[WL1271_INI_FEM_MODULE_COUNT]; | ||
198 | } __packed; | ||
199 | |||
200 | struct wl128x_nvs_file { | ||
201 | /* NVS section - must be first! */ | ||
202 | u8 nvs[WL1271_INI_NVS_SECTION_SIZE]; | ||
203 | |||
204 | /* INI section */ | ||
205 | struct wl128x_ini_general_params general_params; | ||
206 | u8 fem_vendor_and_options; | ||
207 | struct wl128x_ini_band_params_2 stat_radio_params_2; | ||
208 | u8 padding2; | ||
209 | struct { | ||
210 | struct wl128x_ini_fem_params_2 params; | ||
211 | u8 padding; | ||
212 | } dyn_radio_params_2[WL1271_INI_FEM_MODULE_COUNT]; | ||
213 | struct wl128x_ini_band_params_5 stat_radio_params_5; | ||
214 | u8 padding3; | ||
215 | struct { | ||
216 | struct wl128x_ini_fem_params_5 params; | ||
217 | u8 padding; | ||
218 | } dyn_radio_params_5[WL1271_INI_FEM_MODULE_COUNT]; | ||
219 | } __packed; | ||
220 | #endif | ||
diff --git a/drivers/net/wireless/ti/wl12xx/init.c b/drivers/net/wireless/ti/wl12xx/init.c new file mode 100644 index 000000000000..203fbebf09eb --- /dev/null +++ b/drivers/net/wireless/ti/wl12xx/init.c | |||
@@ -0,0 +1,765 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2009 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 | #include <linux/kernel.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/slab.h> | ||
27 | |||
28 | #include "debug.h" | ||
29 | #include "init.h" | ||
30 | #include "wl12xx_80211.h" | ||
31 | #include "acx.h" | ||
32 | #include "cmd.h" | ||
33 | #include "reg.h" | ||
34 | #include "tx.h" | ||
35 | #include "io.h" | ||
36 | |||
37 | int wl1271_init_templates_config(struct wl1271 *wl) | ||
38 | { | ||
39 | int ret, i; | ||
40 | size_t max_size; | ||
41 | |||
42 | /* send empty templates for fw memory reservation */ | ||
43 | ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, | ||
44 | CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL, | ||
45 | WL1271_CMD_TEMPL_MAX_SIZE, | ||
46 | 0, WL1271_RATE_AUTOMATIC); | ||
47 | if (ret < 0) | ||
48 | return ret; | ||
49 | |||
50 | ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, | ||
51 | CMD_TEMPL_CFG_PROBE_REQ_5, | ||
52 | NULL, WL1271_CMD_TEMPL_MAX_SIZE, 0, | ||
53 | WL1271_RATE_AUTOMATIC); | ||
54 | if (ret < 0) | ||
55 | return ret; | ||
56 | |||
57 | ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, | ||
58 | CMD_TEMPL_NULL_DATA, NULL, | ||
59 | sizeof(struct wl12xx_null_data_template), | ||
60 | 0, WL1271_RATE_AUTOMATIC); | ||
61 | if (ret < 0) | ||
62 | return ret; | ||
63 | |||
64 | ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, | ||
65 | CMD_TEMPL_PS_POLL, NULL, | ||
66 | sizeof(struct wl12xx_ps_poll_template), | ||
67 | 0, WL1271_RATE_AUTOMATIC); | ||
68 | if (ret < 0) | ||
69 | return ret; | ||
70 | |||
71 | ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, | ||
72 | CMD_TEMPL_QOS_NULL_DATA, NULL, | ||
73 | sizeof | ||
74 | (struct ieee80211_qos_hdr), | ||
75 | 0, WL1271_RATE_AUTOMATIC); | ||
76 | if (ret < 0) | ||
77 | return ret; | ||
78 | |||
79 | ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, | ||
80 | CMD_TEMPL_PROBE_RESPONSE, NULL, | ||
81 | WL1271_CMD_TEMPL_DFLT_SIZE, | ||
82 | 0, WL1271_RATE_AUTOMATIC); | ||
83 | if (ret < 0) | ||
84 | return ret; | ||
85 | |||
86 | ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, | ||
87 | CMD_TEMPL_BEACON, NULL, | ||
88 | WL1271_CMD_TEMPL_DFLT_SIZE, | ||
89 | 0, WL1271_RATE_AUTOMATIC); | ||
90 | if (ret < 0) | ||
91 | return ret; | ||
92 | |||
93 | max_size = sizeof(struct wl12xx_arp_rsp_template) + | ||
94 | WL1271_EXTRA_SPACE_MAX; | ||
95 | ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, | ||
96 | CMD_TEMPL_ARP_RSP, NULL, | ||
97 | max_size, | ||
98 | 0, WL1271_RATE_AUTOMATIC); | ||
99 | if (ret < 0) | ||
100 | return ret; | ||
101 | |||
102 | /* | ||
103 | * Put very large empty placeholders for all templates. These | ||
104 | * reserve memory for later. | ||
105 | */ | ||
106 | ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, | ||
107 | CMD_TEMPL_AP_PROBE_RESPONSE, NULL, | ||
108 | WL1271_CMD_TEMPL_MAX_SIZE, | ||
109 | 0, WL1271_RATE_AUTOMATIC); | ||
110 | if (ret < 0) | ||
111 | return ret; | ||
112 | |||
113 | ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, | ||
114 | CMD_TEMPL_AP_BEACON, NULL, | ||
115 | WL1271_CMD_TEMPL_MAX_SIZE, | ||
116 | 0, WL1271_RATE_AUTOMATIC); | ||
117 | if (ret < 0) | ||
118 | return ret; | ||
119 | |||
120 | ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, | ||
121 | CMD_TEMPL_DEAUTH_AP, NULL, | ||
122 | sizeof | ||
123 | (struct wl12xx_disconn_template), | ||
124 | 0, WL1271_RATE_AUTOMATIC); | ||
125 | if (ret < 0) | ||
126 | return ret; | ||
127 | |||
128 | for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) { | ||
129 | ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, | ||
130 | CMD_TEMPL_KLV, NULL, | ||
131 | sizeof(struct ieee80211_qos_hdr), | ||
132 | i, WL1271_RATE_AUTOMATIC); | ||
133 | if (ret < 0) | ||
134 | return ret; | ||
135 | } | ||
136 | |||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | static int wl1271_ap_init_deauth_template(struct wl1271 *wl, | ||
141 | struct wl12xx_vif *wlvif) | ||
142 | { | ||
143 | struct wl12xx_disconn_template *tmpl; | ||
144 | int ret; | ||
145 | u32 rate; | ||
146 | |||
147 | tmpl = kzalloc(sizeof(*tmpl), GFP_KERNEL); | ||
148 | if (!tmpl) { | ||
149 | ret = -ENOMEM; | ||
150 | goto out; | ||
151 | } | ||
152 | |||
153 | tmpl->header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
154 | IEEE80211_STYPE_DEAUTH); | ||
155 | |||
156 | rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); | ||
157 | ret = wl1271_cmd_template_set(wl, wlvif->role_id, | ||
158 | CMD_TEMPL_DEAUTH_AP, | ||
159 | tmpl, sizeof(*tmpl), 0, rate); | ||
160 | |||
161 | out: | ||
162 | kfree(tmpl); | ||
163 | return ret; | ||
164 | } | ||
165 | |||
166 | static int wl1271_ap_init_null_template(struct wl1271 *wl, | ||
167 | struct ieee80211_vif *vif) | ||
168 | { | ||
169 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | ||
170 | struct ieee80211_hdr_3addr *nullfunc; | ||
171 | int ret; | ||
172 | u32 rate; | ||
173 | |||
174 | nullfunc = kzalloc(sizeof(*nullfunc), GFP_KERNEL); | ||
175 | if (!nullfunc) { | ||
176 | ret = -ENOMEM; | ||
177 | goto out; | ||
178 | } | ||
179 | |||
180 | nullfunc->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | | ||
181 | IEEE80211_STYPE_NULLFUNC | | ||
182 | IEEE80211_FCTL_FROMDS); | ||
183 | |||
184 | /* nullfunc->addr1 is filled by FW */ | ||
185 | |||
186 | memcpy(nullfunc->addr2, vif->addr, ETH_ALEN); | ||
187 | memcpy(nullfunc->addr3, vif->addr, ETH_ALEN); | ||
188 | |||
189 | rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); | ||
190 | ret = wl1271_cmd_template_set(wl, wlvif->role_id, | ||
191 | CMD_TEMPL_NULL_DATA, nullfunc, | ||
192 | sizeof(*nullfunc), 0, rate); | ||
193 | |||
194 | out: | ||
195 | kfree(nullfunc); | ||
196 | return ret; | ||
197 | } | ||
198 | |||
199 | static int wl1271_ap_init_qos_null_template(struct wl1271 *wl, | ||
200 | struct ieee80211_vif *vif) | ||
201 | { | ||
202 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | ||
203 | struct ieee80211_qos_hdr *qosnull; | ||
204 | int ret; | ||
205 | u32 rate; | ||
206 | |||
207 | qosnull = kzalloc(sizeof(*qosnull), GFP_KERNEL); | ||
208 | if (!qosnull) { | ||
209 | ret = -ENOMEM; | ||
210 | goto out; | ||
211 | } | ||
212 | |||
213 | qosnull->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | | ||
214 | IEEE80211_STYPE_QOS_NULLFUNC | | ||
215 | IEEE80211_FCTL_FROMDS); | ||
216 | |||
217 | /* qosnull->addr1 is filled by FW */ | ||
218 | |||
219 | memcpy(qosnull->addr2, vif->addr, ETH_ALEN); | ||
220 | memcpy(qosnull->addr3, vif->addr, ETH_ALEN); | ||
221 | |||
222 | rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); | ||
223 | ret = wl1271_cmd_template_set(wl, wlvif->role_id, | ||
224 | CMD_TEMPL_QOS_NULL_DATA, qosnull, | ||
225 | sizeof(*qosnull), 0, rate); | ||
226 | |||
227 | out: | ||
228 | kfree(qosnull); | ||
229 | return ret; | ||
230 | } | ||
231 | |||
232 | static int wl12xx_init_rx_config(struct wl1271 *wl) | ||
233 | { | ||
234 | int ret; | ||
235 | |||
236 | ret = wl1271_acx_rx_msdu_life_time(wl); | ||
237 | if (ret < 0) | ||
238 | return ret; | ||
239 | |||
240 | return 0; | ||
241 | } | ||
242 | |||
243 | static int wl12xx_init_phy_vif_config(struct wl1271 *wl, | ||
244 | struct wl12xx_vif *wlvif) | ||
245 | { | ||
246 | int ret; | ||
247 | |||
248 | ret = wl1271_acx_slot(wl, wlvif, DEFAULT_SLOT_TIME); | ||
249 | if (ret < 0) | ||
250 | return ret; | ||
251 | |||
252 | ret = wl1271_acx_service_period_timeout(wl, wlvif); | ||
253 | if (ret < 0) | ||
254 | return ret; | ||
255 | |||
256 | ret = wl1271_acx_rts_threshold(wl, wlvif, wl->hw->wiphy->rts_threshold); | ||
257 | if (ret < 0) | ||
258 | return ret; | ||
259 | |||
260 | return 0; | ||
261 | } | ||
262 | |||
263 | static int wl1271_init_sta_beacon_filter(struct wl1271 *wl, | ||
264 | struct wl12xx_vif *wlvif) | ||
265 | { | ||
266 | int ret; | ||
267 | |||
268 | ret = wl1271_acx_beacon_filter_table(wl, wlvif); | ||
269 | if (ret < 0) | ||
270 | return ret; | ||
271 | |||
272 | /* enable beacon filtering */ | ||
273 | ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true); | ||
274 | if (ret < 0) | ||
275 | return ret; | ||
276 | |||
277 | return 0; | ||
278 | } | ||
279 | |||
280 | int wl1271_init_pta(struct wl1271 *wl) | ||
281 | { | ||
282 | int ret; | ||
283 | |||
284 | ret = wl12xx_acx_sg_cfg(wl); | ||
285 | if (ret < 0) | ||
286 | return ret; | ||
287 | |||
288 | ret = wl1271_acx_sg_enable(wl, wl->sg_enabled); | ||
289 | if (ret < 0) | ||
290 | return ret; | ||
291 | |||
292 | return 0; | ||
293 | } | ||
294 | |||
295 | int wl1271_init_energy_detection(struct wl1271 *wl) | ||
296 | { | ||
297 | int ret; | ||
298 | |||
299 | ret = wl1271_acx_cca_threshold(wl); | ||
300 | if (ret < 0) | ||
301 | return ret; | ||
302 | |||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | static int wl1271_init_beacon_broadcast(struct wl1271 *wl, | ||
307 | struct wl12xx_vif *wlvif) | ||
308 | { | ||
309 | int ret; | ||
310 | |||
311 | ret = wl1271_acx_bcn_dtim_options(wl, wlvif); | ||
312 | if (ret < 0) | ||
313 | return ret; | ||
314 | |||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | static int wl12xx_init_fwlog(struct wl1271 *wl) | ||
319 | { | ||
320 | int ret; | ||
321 | |||
322 | if (wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) | ||
323 | return 0; | ||
324 | |||
325 | ret = wl12xx_cmd_config_fwlog(wl); | ||
326 | if (ret < 0) | ||
327 | return ret; | ||
328 | |||
329 | return 0; | ||
330 | } | ||
331 | |||
332 | /* generic sta initialization (non vif-specific) */ | ||
333 | static int wl1271_sta_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif) | ||
334 | { | ||
335 | int ret; | ||
336 | |||
337 | /* PS config */ | ||
338 | ret = wl12xx_acx_config_ps(wl, wlvif); | ||
339 | if (ret < 0) | ||
340 | return ret; | ||
341 | |||
342 | /* FM WLAN coexistence */ | ||
343 | ret = wl1271_acx_fm_coex(wl); | ||
344 | if (ret < 0) | ||
345 | return ret; | ||
346 | |||
347 | ret = wl1271_acx_sta_rate_policies(wl, wlvif); | ||
348 | if (ret < 0) | ||
349 | return ret; | ||
350 | |||
351 | return 0; | ||
352 | } | ||
353 | |||
354 | static int wl1271_sta_hw_init_post_mem(struct wl1271 *wl, | ||
355 | struct ieee80211_vif *vif) | ||
356 | { | ||
357 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | ||
358 | int ret, i; | ||
359 | |||
360 | /* disable all keep-alive templates */ | ||
361 | for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) { | ||
362 | ret = wl1271_acx_keep_alive_config(wl, wlvif, i, | ||
363 | ACX_KEEP_ALIVE_TPL_INVALID); | ||
364 | if (ret < 0) | ||
365 | return ret; | ||
366 | } | ||
367 | |||
368 | /* disable the keep-alive feature */ | ||
369 | ret = wl1271_acx_keep_alive_mode(wl, wlvif, false); | ||
370 | if (ret < 0) | ||
371 | return ret; | ||
372 | |||
373 | return 0; | ||
374 | } | ||
375 | |||
376 | /* generic ap initialization (non vif-specific) */ | ||
377 | static int wl1271_ap_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif) | ||
378 | { | ||
379 | int ret; | ||
380 | |||
381 | ret = wl1271_init_ap_rates(wl, wlvif); | ||
382 | if (ret < 0) | ||
383 | return ret; | ||
384 | |||
385 | return 0; | ||
386 | } | ||
387 | |||
388 | int wl1271_ap_init_templates(struct wl1271 *wl, struct ieee80211_vif *vif) | ||
389 | { | ||
390 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | ||
391 | int ret; | ||
392 | |||
393 | ret = wl1271_ap_init_deauth_template(wl, wlvif); | ||
394 | if (ret < 0) | ||
395 | return ret; | ||
396 | |||
397 | ret = wl1271_ap_init_null_template(wl, vif); | ||
398 | if (ret < 0) | ||
399 | return ret; | ||
400 | |||
401 | ret = wl1271_ap_init_qos_null_template(wl, vif); | ||
402 | if (ret < 0) | ||
403 | return ret; | ||
404 | |||
405 | /* | ||
406 | * when operating as AP we want to receive external beacons for | ||
407 | * configuring ERP protection. | ||
408 | */ | ||
409 | ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false); | ||
410 | if (ret < 0) | ||
411 | return ret; | ||
412 | |||
413 | return 0; | ||
414 | } | ||
415 | |||
416 | static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl, | ||
417 | struct ieee80211_vif *vif) | ||
418 | { | ||
419 | return wl1271_ap_init_templates(wl, vif); | ||
420 | } | ||
421 | |||
422 | int wl1271_init_ap_rates(struct wl1271 *wl, struct wl12xx_vif *wlvif) | ||
423 | { | ||
424 | int i, ret; | ||
425 | struct conf_tx_rate_class rc; | ||
426 | u32 supported_rates; | ||
427 | |||
428 | wl1271_debug(DEBUG_AP, "AP basic rate set: 0x%x", | ||
429 | wlvif->basic_rate_set); | ||
430 | |||
431 | if (wlvif->basic_rate_set == 0) | ||
432 | return -EINVAL; | ||
433 | |||
434 | rc.enabled_rates = wlvif->basic_rate_set; | ||
435 | rc.long_retry_limit = 10; | ||
436 | rc.short_retry_limit = 10; | ||
437 | rc.aflags = 0; | ||
438 | ret = wl1271_acx_ap_rate_policy(wl, &rc, wlvif->ap.mgmt_rate_idx); | ||
439 | if (ret < 0) | ||
440 | return ret; | ||
441 | |||
442 | /* use the min basic rate for AP broadcast/multicast */ | ||
443 | rc.enabled_rates = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); | ||
444 | rc.short_retry_limit = 10; | ||
445 | rc.long_retry_limit = 10; | ||
446 | rc.aflags = 0; | ||
447 | ret = wl1271_acx_ap_rate_policy(wl, &rc, wlvif->ap.bcast_rate_idx); | ||
448 | if (ret < 0) | ||
449 | return ret; | ||
450 | |||
451 | /* | ||
452 | * If the basic rates contain OFDM rates, use OFDM only | ||
453 | * rates for unicast TX as well. Else use all supported rates. | ||
454 | */ | ||
455 | if ((wlvif->basic_rate_set & CONF_TX_OFDM_RATES)) | ||
456 | supported_rates = CONF_TX_OFDM_RATES; | ||
457 | else | ||
458 | supported_rates = CONF_TX_AP_ENABLED_RATES; | ||
459 | |||
460 | /* unconditionally enable HT rates */ | ||
461 | supported_rates |= CONF_TX_MCS_RATES; | ||
462 | |||
463 | /* configure unicast TX rate classes */ | ||
464 | for (i = 0; i < wl->conf.tx.ac_conf_count; i++) { | ||
465 | rc.enabled_rates = supported_rates; | ||
466 | rc.short_retry_limit = 10; | ||
467 | rc.long_retry_limit = 10; | ||
468 | rc.aflags = 0; | ||
469 | ret = wl1271_acx_ap_rate_policy(wl, &rc, | ||
470 | wlvif->ap.ucast_rate_idx[i]); | ||
471 | if (ret < 0) | ||
472 | return ret; | ||
473 | } | ||
474 | |||
475 | return 0; | ||
476 | } | ||
477 | |||
478 | static int wl1271_set_ba_policies(struct wl1271 *wl, struct wl12xx_vif *wlvif) | ||
479 | { | ||
480 | /* Reset the BA RX indicators */ | ||
481 | wlvif->ba_allowed = true; | ||
482 | wl->ba_rx_session_count = 0; | ||
483 | |||
484 | /* BA is supported in STA/AP modes */ | ||
485 | if (wlvif->bss_type != BSS_TYPE_AP_BSS && | ||
486 | wlvif->bss_type != BSS_TYPE_STA_BSS) { | ||
487 | wlvif->ba_support = false; | ||
488 | return 0; | ||
489 | } | ||
490 | |||
491 | wlvif->ba_support = true; | ||
492 | |||
493 | /* 802.11n initiator BA session setting */ | ||
494 | return wl12xx_acx_set_ba_initiator_policy(wl, wlvif); | ||
495 | } | ||
496 | |||
497 | int wl1271_chip_specific_init(struct wl1271 *wl) | ||
498 | { | ||
499 | int ret = 0; | ||
500 | |||
501 | if (wl->chip.id == CHIP_ID_1283_PG20) { | ||
502 | u32 host_cfg_bitmap = HOST_IF_CFG_RX_FIFO_ENABLE; | ||
503 | |||
504 | if (!(wl->quirks & WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT)) | ||
505 | /* Enable SDIO padding */ | ||
506 | host_cfg_bitmap |= HOST_IF_CFG_TX_PAD_TO_SDIO_BLK; | ||
507 | |||
508 | /* Must be before wl1271_acx_init_mem_config() */ | ||
509 | ret = wl1271_acx_host_if_cfg_bitmap(wl, host_cfg_bitmap); | ||
510 | if (ret < 0) | ||
511 | goto out; | ||
512 | } | ||
513 | out: | ||
514 | return ret; | ||
515 | } | ||
516 | |||
517 | /* vif-specifc initialization */ | ||
518 | static int wl12xx_init_sta_role(struct wl1271 *wl, struct wl12xx_vif *wlvif) | ||
519 | { | ||
520 | int ret; | ||
521 | |||
522 | ret = wl1271_acx_group_address_tbl(wl, wlvif, true, NULL, 0); | ||
523 | if (ret < 0) | ||
524 | return ret; | ||
525 | |||
526 | /* Initialize connection monitoring thresholds */ | ||
527 | ret = wl1271_acx_conn_monit_params(wl, wlvif, false); | ||
528 | if (ret < 0) | ||
529 | return ret; | ||
530 | |||
531 | /* Beacon filtering */ | ||
532 | ret = wl1271_init_sta_beacon_filter(wl, wlvif); | ||
533 | if (ret < 0) | ||
534 | return ret; | ||
535 | |||
536 | /* Beacons and broadcast settings */ | ||
537 | ret = wl1271_init_beacon_broadcast(wl, wlvif); | ||
538 | if (ret < 0) | ||
539 | return ret; | ||
540 | |||
541 | /* Configure rssi/snr averaging weights */ | ||
542 | ret = wl1271_acx_rssi_snr_avg_weights(wl, wlvif); | ||
543 | if (ret < 0) | ||
544 | return ret; | ||
545 | |||
546 | return 0; | ||
547 | } | ||
548 | |||
549 | /* vif-specific intialization */ | ||
550 | static int wl12xx_init_ap_role(struct wl1271 *wl, struct wl12xx_vif *wlvif) | ||
551 | { | ||
552 | int ret; | ||
553 | |||
554 | ret = wl1271_acx_ap_max_tx_retry(wl, wlvif); | ||
555 | if (ret < 0) | ||
556 | return ret; | ||
557 | |||
558 | /* initialize Tx power */ | ||
559 | ret = wl1271_acx_tx_power(wl, wlvif, wlvif->power_level); | ||
560 | if (ret < 0) | ||
561 | return ret; | ||
562 | |||
563 | return 0; | ||
564 | } | ||
565 | |||
566 | int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif) | ||
567 | { | ||
568 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | ||
569 | struct conf_tx_ac_category *conf_ac; | ||
570 | struct conf_tx_tid *conf_tid; | ||
571 | bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); | ||
572 | int ret, i; | ||
573 | |||
574 | /* | ||
575 | * consider all existing roles before configuring psm. | ||
576 | * TODO: reconfigure on interface removal. | ||
577 | */ | ||
578 | if (!wl->ap_count) { | ||
579 | if (is_ap) { | ||
580 | /* Configure for power always on */ | ||
581 | ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM); | ||
582 | if (ret < 0) | ||
583 | return ret; | ||
584 | } else if (!wl->sta_count) { | ||
585 | /* Configure for ELP power saving */ | ||
586 | ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP); | ||
587 | if (ret < 0) | ||
588 | return ret; | ||
589 | } | ||
590 | } | ||
591 | |||
592 | /* Mode specific init */ | ||
593 | if (is_ap) { | ||
594 | ret = wl1271_ap_hw_init(wl, wlvif); | ||
595 | if (ret < 0) | ||
596 | return ret; | ||
597 | |||
598 | ret = wl12xx_init_ap_role(wl, wlvif); | ||
599 | if (ret < 0) | ||
600 | return ret; | ||
601 | } else { | ||
602 | ret = wl1271_sta_hw_init(wl, wlvif); | ||
603 | if (ret < 0) | ||
604 | return ret; | ||
605 | |||
606 | ret = wl12xx_init_sta_role(wl, wlvif); | ||
607 | if (ret < 0) | ||
608 | return ret; | ||
609 | } | ||
610 | |||
611 | wl12xx_init_phy_vif_config(wl, wlvif); | ||
612 | |||
613 | /* Default TID/AC configuration */ | ||
614 | BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count); | ||
615 | for (i = 0; i < wl->conf.tx.tid_conf_count; i++) { | ||
616 | conf_ac = &wl->conf.tx.ac_conf[i]; | ||
617 | ret = wl1271_acx_ac_cfg(wl, wlvif, conf_ac->ac, | ||
618 | conf_ac->cw_min, conf_ac->cw_max, | ||
619 | conf_ac->aifsn, conf_ac->tx_op_limit); | ||
620 | if (ret < 0) | ||
621 | return ret; | ||
622 | |||
623 | conf_tid = &wl->conf.tx.tid_conf[i]; | ||
624 | ret = wl1271_acx_tid_cfg(wl, wlvif, | ||
625 | conf_tid->queue_id, | ||
626 | conf_tid->channel_type, | ||
627 | conf_tid->tsid, | ||
628 | conf_tid->ps_scheme, | ||
629 | conf_tid->ack_policy, | ||
630 | conf_tid->apsd_conf[0], | ||
631 | conf_tid->apsd_conf[1]); | ||
632 | if (ret < 0) | ||
633 | return ret; | ||
634 | } | ||
635 | |||
636 | /* Configure HW encryption */ | ||
637 | ret = wl1271_acx_feature_cfg(wl, wlvif); | ||
638 | if (ret < 0) | ||
639 | return ret; | ||
640 | |||
641 | /* Mode specific init - post mem init */ | ||
642 | if (is_ap) | ||
643 | ret = wl1271_ap_hw_init_post_mem(wl, vif); | ||
644 | else | ||
645 | ret = wl1271_sta_hw_init_post_mem(wl, vif); | ||
646 | |||
647 | if (ret < 0) | ||
648 | return ret; | ||
649 | |||
650 | /* Configure initiator BA sessions policies */ | ||
651 | ret = wl1271_set_ba_policies(wl, wlvif); | ||
652 | if (ret < 0) | ||
653 | return ret; | ||
654 | |||
655 | return 0; | ||
656 | } | ||
657 | |||
658 | int wl1271_hw_init(struct wl1271 *wl) | ||
659 | { | ||
660 | int ret; | ||
661 | |||
662 | if (wl->chip.id == CHIP_ID_1283_PG20) { | ||
663 | ret = wl128x_cmd_general_parms(wl); | ||
664 | if (ret < 0) | ||
665 | return ret; | ||
666 | ret = wl128x_cmd_radio_parms(wl); | ||
667 | if (ret < 0) | ||
668 | return ret; | ||
669 | } else { | ||
670 | ret = wl1271_cmd_general_parms(wl); | ||
671 | if (ret < 0) | ||
672 | return ret; | ||
673 | ret = wl1271_cmd_radio_parms(wl); | ||
674 | if (ret < 0) | ||
675 | return ret; | ||
676 | ret = wl1271_cmd_ext_radio_parms(wl); | ||
677 | if (ret < 0) | ||
678 | return ret; | ||
679 | } | ||
680 | |||
681 | /* Chip-specific init */ | ||
682 | ret = wl1271_chip_specific_init(wl); | ||
683 | if (ret < 0) | ||
684 | return ret; | ||
685 | |||
686 | /* Init templates */ | ||
687 | ret = wl1271_init_templates_config(wl); | ||
688 | if (ret < 0) | ||
689 | return ret; | ||
690 | |||
691 | ret = wl12xx_acx_mem_cfg(wl); | ||
692 | if (ret < 0) | ||
693 | return ret; | ||
694 | |||
695 | /* Configure the FW logger */ | ||
696 | ret = wl12xx_init_fwlog(wl); | ||
697 | if (ret < 0) | ||
698 | return ret; | ||
699 | |||
700 | /* Bluetooth WLAN coexistence */ | ||
701 | ret = wl1271_init_pta(wl); | ||
702 | if (ret < 0) | ||
703 | return ret; | ||
704 | |||
705 | /* Default memory configuration */ | ||
706 | ret = wl1271_acx_init_mem_config(wl); | ||
707 | if (ret < 0) | ||
708 | return ret; | ||
709 | |||
710 | /* RX config */ | ||
711 | ret = wl12xx_init_rx_config(wl); | ||
712 | if (ret < 0) | ||
713 | goto out_free_memmap; | ||
714 | |||
715 | ret = wl1271_acx_dco_itrim_params(wl); | ||
716 | if (ret < 0) | ||
717 | goto out_free_memmap; | ||
718 | |||
719 | /* Configure TX patch complete interrupt behavior */ | ||
720 | ret = wl1271_acx_tx_config_options(wl); | ||
721 | if (ret < 0) | ||
722 | goto out_free_memmap; | ||
723 | |||
724 | /* RX complete interrupt pacing */ | ||
725 | ret = wl1271_acx_init_rx_interrupt(wl); | ||
726 | if (ret < 0) | ||
727 | goto out_free_memmap; | ||
728 | |||
729 | /* Energy detection */ | ||
730 | ret = wl1271_init_energy_detection(wl); | ||
731 | if (ret < 0) | ||
732 | goto out_free_memmap; | ||
733 | |||
734 | /* Default fragmentation threshold */ | ||
735 | ret = wl1271_acx_frag_threshold(wl, wl->hw->wiphy->frag_threshold); | ||
736 | if (ret < 0) | ||
737 | goto out_free_memmap; | ||
738 | |||
739 | /* Enable data path */ | ||
740 | ret = wl1271_cmd_data_path(wl, 1); | ||
741 | if (ret < 0) | ||
742 | goto out_free_memmap; | ||
743 | |||
744 | /* configure PM */ | ||
745 | ret = wl1271_acx_pm_config(wl); | ||
746 | if (ret < 0) | ||
747 | goto out_free_memmap; | ||
748 | |||
749 | ret = wl12xx_acx_set_rate_mgmt_params(wl); | ||
750 | if (ret < 0) | ||
751 | goto out_free_memmap; | ||
752 | |||
753 | /* configure hangover */ | ||
754 | ret = wl12xx_acx_config_hangover(wl); | ||
755 | if (ret < 0) | ||
756 | goto out_free_memmap; | ||
757 | |||
758 | return 0; | ||
759 | |||
760 | out_free_memmap: | ||
761 | kfree(wl->target_mem_map); | ||
762 | wl->target_mem_map = NULL; | ||
763 | |||
764 | return ret; | ||
765 | } | ||
diff --git a/drivers/net/wireless/ti/wl12xx/init.h b/drivers/net/wireless/ti/wl12xx/init.h new file mode 100644 index 000000000000..2da0f404ef6e --- /dev/null +++ b/drivers/net/wireless/ti/wl12xx/init.h | |||
@@ -0,0 +1,39 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2009 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 __INIT_H__ | ||
25 | #define __INIT_H__ | ||
26 | |||
27 | #include "wl12xx.h" | ||
28 | |||
29 | int wl1271_hw_init_power_auth(struct wl1271 *wl); | ||
30 | int wl1271_init_templates_config(struct wl1271 *wl); | ||
31 | int wl1271_init_pta(struct wl1271 *wl); | ||
32 | int wl1271_init_energy_detection(struct wl1271 *wl); | ||
33 | int wl1271_chip_specific_init(struct wl1271 *wl); | ||
34 | int wl1271_hw_init(struct wl1271 *wl); | ||
35 | int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif); | ||
36 | int wl1271_init_ap_rates(struct wl1271 *wl, struct wl12xx_vif *wlvif); | ||
37 | int wl1271_ap_init_templates(struct wl1271 *wl, struct ieee80211_vif *vif); | ||
38 | |||
39 | #endif | ||
diff --git a/drivers/net/wireless/ti/wl12xx/io.c b/drivers/net/wireless/ti/wl12xx/io.c new file mode 100644 index 000000000000..c574a3b31e31 --- /dev/null +++ b/drivers/net/wireless/ti/wl12xx/io.c | |||
@@ -0,0 +1,244 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2008-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 | #include <linux/module.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/spi/spi.h> | ||
27 | #include <linux/interrupt.h> | ||
28 | |||
29 | #include "wl12xx.h" | ||
30 | #include "debug.h" | ||
31 | #include "wl12xx_80211.h" | ||
32 | #include "io.h" | ||
33 | #include "tx.h" | ||
34 | |||
35 | #define OCP_CMD_LOOP 32 | ||
36 | |||
37 | #define OCP_CMD_WRITE 0x1 | ||
38 | #define OCP_CMD_READ 0x2 | ||
39 | |||
40 | #define OCP_READY_MASK BIT(18) | ||
41 | #define OCP_STATUS_MASK (BIT(16) | BIT(17)) | ||
42 | |||
43 | #define OCP_STATUS_NO_RESP 0x00000 | ||
44 | #define OCP_STATUS_OK 0x10000 | ||
45 | #define OCP_STATUS_REQ_FAILED 0x20000 | ||
46 | #define OCP_STATUS_RESP_ERROR 0x30000 | ||
47 | |||
48 | struct wl1271_partition_set wl12xx_part_table[PART_TABLE_LEN] = { | ||
49 | [PART_DOWN] = { | ||
50 | .mem = { | ||
51 | .start = 0x00000000, | ||
52 | .size = 0x000177c0 | ||
53 | }, | ||
54 | .reg = { | ||
55 | .start = REGISTERS_BASE, | ||
56 | .size = 0x00008800 | ||
57 | }, | ||
58 | .mem2 = { | ||
59 | .start = 0x00000000, | ||
60 | .size = 0x00000000 | ||
61 | }, | ||
62 | .mem3 = { | ||
63 | .start = 0x00000000, | ||
64 | .size = 0x00000000 | ||
65 | }, | ||
66 | }, | ||
67 | |||
68 | [PART_WORK] = { | ||
69 | .mem = { | ||
70 | .start = 0x00040000, | ||
71 | .size = 0x00014fc0 | ||
72 | }, | ||
73 | .reg = { | ||
74 | .start = REGISTERS_BASE, | ||
75 | .size = 0x0000a000 | ||
76 | }, | ||
77 | .mem2 = { | ||
78 | .start = 0x003004f8, | ||
79 | .size = 0x00000004 | ||
80 | }, | ||
81 | .mem3 = { | ||
82 | .start = 0x00040404, | ||
83 | .size = 0x00000000 | ||
84 | }, | ||
85 | }, | ||
86 | |||
87 | [PART_DRPW] = { | ||
88 | .mem = { | ||
89 | .start = 0x00040000, | ||
90 | .size = 0x00014fc0 | ||
91 | }, | ||
92 | .reg = { | ||
93 | .start = DRPW_BASE, | ||
94 | .size = 0x00006000 | ||
95 | }, | ||
96 | .mem2 = { | ||
97 | .start = 0x00000000, | ||
98 | .size = 0x00000000 | ||
99 | }, | ||
100 | .mem3 = { | ||
101 | .start = 0x00000000, | ||
102 | .size = 0x00000000 | ||
103 | } | ||
104 | } | ||
105 | }; | ||
106 | |||
107 | bool wl1271_set_block_size(struct wl1271 *wl) | ||
108 | { | ||
109 | if (wl->if_ops->set_block_size) { | ||
110 | wl->if_ops->set_block_size(wl->dev, WL12XX_BUS_BLOCK_SIZE); | ||
111 | return true; | ||
112 | } | ||
113 | |||
114 | return false; | ||
115 | } | ||
116 | |||
117 | void wl1271_disable_interrupts(struct wl1271 *wl) | ||
118 | { | ||
119 | disable_irq(wl->irq); | ||
120 | } | ||
121 | |||
122 | void wl1271_enable_interrupts(struct wl1271 *wl) | ||
123 | { | ||
124 | enable_irq(wl->irq); | ||
125 | } | ||
126 | |||
127 | /* Set the SPI partitions to access the chip addresses | ||
128 | * | ||
129 | * To simplify driver code, a fixed (virtual) memory map is defined for | ||
130 | * register and memory addresses. Because in the chipset, in different stages | ||
131 | * of operation, those addresses will move around, an address translation | ||
132 | * mechanism is required. | ||
133 | * | ||
134 | * There are four partitions (three memory and one register partition), | ||
135 | * which are mapped to two different areas of the hardware memory. | ||
136 | * | ||
137 | * Virtual address | ||
138 | * space | ||
139 | * | ||
140 | * | | | ||
141 | * ...+----+--> mem.start | ||
142 | * Physical address ... | | | ||
143 | * space ... | | [PART_0] | ||
144 | * ... | | | ||
145 | * 00000000 <--+----+... ...+----+--> mem.start + mem.size | ||
146 | * | | ... | | | ||
147 | * |MEM | ... | | | ||
148 | * | | ... | | | ||
149 | * mem.size <--+----+... | | {unused area) | ||
150 | * | | ... | | | ||
151 | * |REG | ... | | | ||
152 | * mem.size | | ... | | | ||
153 | * + <--+----+... ...+----+--> reg.start | ||
154 | * reg.size | | ... | | | ||
155 | * |MEM2| ... | | [PART_1] | ||
156 | * | | ... | | | ||
157 | * ...+----+--> reg.start + reg.size | ||
158 | * | | | ||
159 | * | ||
160 | */ | ||
161 | int wl1271_set_partition(struct wl1271 *wl, | ||
162 | struct wl1271_partition_set *p) | ||
163 | { | ||
164 | /* copy partition info */ | ||
165 | memcpy(&wl->part, p, sizeof(*p)); | ||
166 | |||
167 | wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | ||
168 | p->mem.start, p->mem.size); | ||
169 | wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | ||
170 | p->reg.start, p->reg.size); | ||
171 | wl1271_debug(DEBUG_SPI, "mem2_start %08X mem2_size %08X", | ||
172 | p->mem2.start, p->mem2.size); | ||
173 | wl1271_debug(DEBUG_SPI, "mem3_start %08X mem3_size %08X", | ||
174 | p->mem3.start, p->mem3.size); | ||
175 | |||
176 | /* write partition info to the chipset */ | ||
177 | wl1271_raw_write32(wl, HW_PART0_START_ADDR, p->mem.start); | ||
178 | wl1271_raw_write32(wl, HW_PART0_SIZE_ADDR, p->mem.size); | ||
179 | wl1271_raw_write32(wl, HW_PART1_START_ADDR, p->reg.start); | ||
180 | wl1271_raw_write32(wl, HW_PART1_SIZE_ADDR, p->reg.size); | ||
181 | wl1271_raw_write32(wl, HW_PART2_START_ADDR, p->mem2.start); | ||
182 | wl1271_raw_write32(wl, HW_PART2_SIZE_ADDR, p->mem2.size); | ||
183 | wl1271_raw_write32(wl, HW_PART3_START_ADDR, p->mem3.start); | ||
184 | |||
185 | return 0; | ||
186 | } | ||
187 | EXPORT_SYMBOL_GPL(wl1271_set_partition); | ||
188 | |||
189 | void wl1271_io_reset(struct wl1271 *wl) | ||
190 | { | ||
191 | if (wl->if_ops->reset) | ||
192 | wl->if_ops->reset(wl->dev); | ||
193 | } | ||
194 | |||
195 | void wl1271_io_init(struct wl1271 *wl) | ||
196 | { | ||
197 | if (wl->if_ops->init) | ||
198 | wl->if_ops->init(wl->dev); | ||
199 | } | ||
200 | |||
201 | void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val) | ||
202 | { | ||
203 | /* write address >> 1 + 0x30000 to OCP_POR_CTR */ | ||
204 | addr = (addr >> 1) + 0x30000; | ||
205 | wl1271_write32(wl, OCP_POR_CTR, addr); | ||
206 | |||
207 | /* write value to OCP_POR_WDATA */ | ||
208 | wl1271_write32(wl, OCP_DATA_WRITE, val); | ||
209 | |||
210 | /* write 1 to OCP_CMD */ | ||
211 | wl1271_write32(wl, OCP_CMD, OCP_CMD_WRITE); | ||
212 | } | ||
213 | |||
214 | u16 wl1271_top_reg_read(struct wl1271 *wl, int addr) | ||
215 | { | ||
216 | u32 val; | ||
217 | int timeout = OCP_CMD_LOOP; | ||
218 | |||
219 | /* write address >> 1 + 0x30000 to OCP_POR_CTR */ | ||
220 | addr = (addr >> 1) + 0x30000; | ||
221 | wl1271_write32(wl, OCP_POR_CTR, addr); | ||
222 | |||
223 | /* write 2 to OCP_CMD */ | ||
224 | wl1271_write32(wl, OCP_CMD, OCP_CMD_READ); | ||
225 | |||
226 | /* poll for data ready */ | ||
227 | do { | ||
228 | val = wl1271_read32(wl, OCP_DATA_READ); | ||
229 | } while (!(val & OCP_READY_MASK) && --timeout); | ||
230 | |||
231 | if (!timeout) { | ||
232 | wl1271_warning("Top register access timed out."); | ||
233 | return 0xffff; | ||
234 | } | ||
235 | |||
236 | /* check data status and return if OK */ | ||
237 | if ((val & OCP_STATUS_MASK) == OCP_STATUS_OK) | ||
238 | return val & 0xffff; | ||
239 | else { | ||
240 | wl1271_warning("Top register access returned error."); | ||
241 | return 0xffff; | ||
242 | } | ||
243 | } | ||
244 | |||
diff --git a/drivers/net/wireless/ti/wl12xx/io.h b/drivers/net/wireless/ti/wl12xx/io.h new file mode 100644 index 000000000000..4fb3dab8c3b2 --- /dev/null +++ b/drivers/net/wireless/ti/wl12xx/io.h | |||
@@ -0,0 +1,181 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. | ||
5 | * Copyright (C) 2008-2010 Nokia Corporation | ||
6 | * | ||
7 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef __IO_H__ | ||
26 | #define __IO_H__ | ||
27 | |||
28 | #include <linux/irqreturn.h> | ||
29 | #include "reg.h" | ||
30 | |||
31 | #define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0 | ||
32 | |||
33 | #define HW_PARTITION_REGISTERS_ADDR 0x1FFC0 | ||
34 | #define HW_PART0_SIZE_ADDR (HW_PARTITION_REGISTERS_ADDR) | ||
35 | #define HW_PART0_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 4) | ||
36 | #define HW_PART1_SIZE_ADDR (HW_PARTITION_REGISTERS_ADDR + 8) | ||
37 | #define HW_PART1_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 12) | ||
38 | #define HW_PART2_SIZE_ADDR (HW_PARTITION_REGISTERS_ADDR + 16) | ||
39 | #define HW_PART2_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 20) | ||
40 | #define HW_PART3_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 24) | ||
41 | |||
42 | #define HW_ACCESS_REGISTER_SIZE 4 | ||
43 | |||
44 | #define HW_ACCESS_PRAM_MAX_RANGE 0x3c000 | ||
45 | |||
46 | extern struct wl1271_partition_set wl12xx_part_table[PART_TABLE_LEN]; | ||
47 | |||
48 | struct wl1271; | ||
49 | |||
50 | void wl1271_disable_interrupts(struct wl1271 *wl); | ||
51 | void wl1271_enable_interrupts(struct wl1271 *wl); | ||
52 | |||
53 | void wl1271_io_reset(struct wl1271 *wl); | ||
54 | void wl1271_io_init(struct wl1271 *wl); | ||
55 | |||
56 | /* Raw target IO, address is not translated */ | ||
57 | static inline void wl1271_raw_write(struct wl1271 *wl, int addr, void *buf, | ||
58 | size_t len, bool fixed) | ||
59 | { | ||
60 | wl->if_ops->write(wl->dev, addr, buf, len, fixed); | ||
61 | } | ||
62 | |||
63 | static inline void wl1271_raw_read(struct wl1271 *wl, int addr, void *buf, | ||
64 | size_t len, bool fixed) | ||
65 | { | ||
66 | wl->if_ops->read(wl->dev, addr, buf, len, fixed); | ||
67 | } | ||
68 | |||
69 | static inline u32 wl1271_raw_read32(struct wl1271 *wl, int addr) | ||
70 | { | ||
71 | wl1271_raw_read(wl, addr, &wl->buffer_32, | ||
72 | sizeof(wl->buffer_32), false); | ||
73 | |||
74 | return le32_to_cpu(wl->buffer_32); | ||
75 | } | ||
76 | |||
77 | static inline void wl1271_raw_write32(struct wl1271 *wl, int addr, u32 val) | ||
78 | { | ||
79 | wl->buffer_32 = cpu_to_le32(val); | ||
80 | wl1271_raw_write(wl, addr, &wl->buffer_32, | ||
81 | sizeof(wl->buffer_32), false); | ||
82 | } | ||
83 | |||
84 | /* Translated target IO */ | ||
85 | static inline int wl1271_translate_addr(struct wl1271 *wl, int addr) | ||
86 | { | ||
87 | /* | ||
88 | * To translate, first check to which window of addresses the | ||
89 | * particular address belongs. Then subtract the starting address | ||
90 | * of that window from the address. Then, add offset of the | ||
91 | * translated region. | ||
92 | * | ||
93 | * The translated regions occur next to each other in physical device | ||
94 | * memory, so just add the sizes of the preceding address regions to | ||
95 | * get the offset to the new region. | ||
96 | * | ||
97 | * Currently, only the two first regions are addressed, and the | ||
98 | * assumption is that all addresses will fall into either of those | ||
99 | * two. | ||
100 | */ | ||
101 | if ((addr >= wl->part.reg.start) && | ||
102 | (addr < wl->part.reg.start + wl->part.reg.size)) | ||
103 | return addr - wl->part.reg.start + wl->part.mem.size; | ||
104 | else | ||
105 | return addr - wl->part.mem.start; | ||
106 | } | ||
107 | |||
108 | static inline void wl1271_read(struct wl1271 *wl, int addr, void *buf, | ||
109 | size_t len, bool fixed) | ||
110 | { | ||
111 | int physical; | ||
112 | |||
113 | physical = wl1271_translate_addr(wl, addr); | ||
114 | |||
115 | wl1271_raw_read(wl, physical, buf, len, fixed); | ||
116 | } | ||
117 | |||
118 | static inline void wl1271_write(struct wl1271 *wl, int addr, void *buf, | ||
119 | size_t len, bool fixed) | ||
120 | { | ||
121 | int physical; | ||
122 | |||
123 | physical = wl1271_translate_addr(wl, addr); | ||
124 | |||
125 | wl1271_raw_write(wl, physical, buf, len, fixed); | ||
126 | } | ||
127 | |||
128 | static inline void wl1271_read_hwaddr(struct wl1271 *wl, int hwaddr, | ||
129 | void *buf, size_t len, bool fixed) | ||
130 | { | ||
131 | int physical; | ||
132 | int addr; | ||
133 | |||
134 | /* Addresses are stored internally as addresses to 32 bytes blocks */ | ||
135 | addr = hwaddr << 5; | ||
136 | |||
137 | physical = wl1271_translate_addr(wl, addr); | ||
138 | |||
139 | wl1271_raw_read(wl, physical, buf, len, fixed); | ||
140 | } | ||
141 | |||
142 | static inline u32 wl1271_read32(struct wl1271 *wl, int addr) | ||
143 | { | ||
144 | return wl1271_raw_read32(wl, wl1271_translate_addr(wl, addr)); | ||
145 | } | ||
146 | |||
147 | static inline void wl1271_write32(struct wl1271 *wl, int addr, u32 val) | ||
148 | { | ||
149 | wl1271_raw_write32(wl, wl1271_translate_addr(wl, addr), val); | ||
150 | } | ||
151 | |||
152 | static inline void wl1271_power_off(struct wl1271 *wl) | ||
153 | { | ||
154 | wl->if_ops->power(wl->dev, false); | ||
155 | clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); | ||
156 | } | ||
157 | |||
158 | static inline int wl1271_power_on(struct wl1271 *wl) | ||
159 | { | ||
160 | int ret = wl->if_ops->power(wl->dev, true); | ||
161 | if (ret == 0) | ||
162 | set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); | ||
163 | |||
164 | return ret; | ||
165 | } | ||
166 | |||
167 | |||
168 | /* Top Register IO */ | ||
169 | void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val); | ||
170 | u16 wl1271_top_reg_read(struct wl1271 *wl, int addr); | ||
171 | |||
172 | int wl1271_set_partition(struct wl1271 *wl, | ||
173 | struct wl1271_partition_set *p); | ||
174 | |||
175 | bool wl1271_set_block_size(struct wl1271 *wl); | ||
176 | |||
177 | /* Functions from wl1271_main.c */ | ||
178 | |||
179 | int wl1271_tx_dummy_packet(struct wl1271 *wl); | ||
180 | |||
181 | #endif | ||
diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c new file mode 100644 index 000000000000..96ca25a92b76 --- /dev/null +++ b/drivers/net/wireless/ti/wl12xx/main.c | |||
@@ -0,0 +1,5633 @@ | |||
1 | |||
2 | /* | ||
3 | * This file is part of wl1271 | ||
4 | * | ||
5 | * Copyright (C) 2008-2010 Nokia Corporation | ||
6 | * | ||
7 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #include <linux/module.h> | ||
26 | #include <linux/firmware.h> | ||
27 | #include <linux/delay.h> | ||
28 | #include <linux/spi/spi.h> | ||
29 | #include <linux/crc32.h> | ||
30 | #include <linux/etherdevice.h> | ||
31 | #include <linux/vmalloc.h> | ||
32 | #include <linux/platform_device.h> | ||
33 | #include <linux/slab.h> | ||
34 | #include <linux/wl12xx.h> | ||
35 | #include <linux/sched.h> | ||
36 | #include <linux/interrupt.h> | ||
37 | |||
38 | #include "wl12xx.h" | ||
39 | #include "debug.h" | ||
40 | #include "wl12xx_80211.h" | ||
41 | #include "reg.h" | ||
42 | #include "io.h" | ||
43 | #include "event.h" | ||
44 | #include "tx.h" | ||
45 | #include "rx.h" | ||
46 | #include "ps.h" | ||
47 | #include "init.h" | ||
48 | #include "debugfs.h" | ||
49 | #include "cmd.h" | ||
50 | #include "boot.h" | ||
51 | #include "testmode.h" | ||
52 | #include "scan.h" | ||
53 | |||
54 | #define WL1271_BOOT_RETRIES 3 | ||
55 | |||
56 | static struct conf_drv_settings default_conf = { | ||
57 | .sg = { | ||
58 | .params = { | ||
59 | [CONF_SG_ACL_BT_MASTER_MIN_BR] = 10, | ||
60 | [CONF_SG_ACL_BT_MASTER_MAX_BR] = 180, | ||
61 | [CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10, | ||
62 | [CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180, | ||
63 | [CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10, | ||
64 | [CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80, | ||
65 | [CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10, | ||
66 | [CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80, | ||
67 | [CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8, | ||
68 | [CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8, | ||
69 | [CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20, | ||
70 | [CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20, | ||
71 | [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20, | ||
72 | [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35, | ||
73 | [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16, | ||
74 | [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35, | ||
75 | [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32, | ||
76 | [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50, | ||
77 | [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28, | ||
78 | [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50, | ||
79 | [CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10, | ||
80 | [CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20, | ||
81 | [CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75, | ||
82 | [CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15, | ||
83 | [CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27, | ||
84 | [CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17, | ||
85 | /* active scan params */ | ||
86 | [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170, | ||
87 | [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50, | ||
88 | [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100, | ||
89 | /* passive scan params */ | ||
90 | [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800, | ||
91 | [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200, | ||
92 | [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200, | ||
93 | /* passive scan in dual antenna params */ | ||
94 | [CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0, | ||
95 | [CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0, | ||
96 | [CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0, | ||
97 | /* general params */ | ||
98 | [CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1, | ||
99 | [CONF_SG_ANTENNA_CONFIGURATION] = 0, | ||
100 | [CONF_SG_BEACON_MISS_PERCENT] = 60, | ||
101 | [CONF_SG_DHCP_TIME] = 5000, | ||
102 | [CONF_SG_RXT] = 1200, | ||
103 | [CONF_SG_TXT] = 1000, | ||
104 | [CONF_SG_ADAPTIVE_RXT_TXT] = 1, | ||
105 | [CONF_SG_GENERAL_USAGE_BIT_MAP] = 3, | ||
106 | [CONF_SG_HV3_MAX_SERVED] = 6, | ||
107 | [CONF_SG_PS_POLL_TIMEOUT] = 10, | ||
108 | [CONF_SG_UPSD_TIMEOUT] = 10, | ||
109 | [CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2, | ||
110 | [CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5, | ||
111 | [CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30, | ||
112 | /* AP params */ | ||
113 | [CONF_AP_BEACON_MISS_TX] = 3, | ||
114 | [CONF_AP_RX_WINDOW_AFTER_BEACON] = 10, | ||
115 | [CONF_AP_BEACON_WINDOW_INTERVAL] = 2, | ||
116 | [CONF_AP_CONNECTION_PROTECTION_TIME] = 0, | ||
117 | [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25, | ||
118 | [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25, | ||
119 | /* CTS Diluting params */ | ||
120 | [CONF_SG_CTS_DILUTED_BAD_RX_PACKETS_TH] = 0, | ||
121 | [CONF_SG_CTS_CHOP_IN_DUAL_ANT_SCO_MASTER] = 0, | ||
122 | }, | ||
123 | .state = CONF_SG_PROTECTIVE, | ||
124 | }, | ||
125 | .rx = { | ||
126 | .rx_msdu_life_time = 512000, | ||
127 | .packet_detection_threshold = 0, | ||
128 | .ps_poll_timeout = 15, | ||
129 | .upsd_timeout = 15, | ||
130 | .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD, | ||
131 | .rx_cca_threshold = 0, | ||
132 | .irq_blk_threshold = 0xFFFF, | ||
133 | .irq_pkt_threshold = 0, | ||
134 | .irq_timeout = 600, | ||
135 | .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY, | ||
136 | }, | ||
137 | .tx = { | ||
138 | .tx_energy_detection = 0, | ||
139 | .sta_rc_conf = { | ||
140 | .enabled_rates = 0, | ||
141 | .short_retry_limit = 10, | ||
142 | .long_retry_limit = 10, | ||
143 | .aflags = 0, | ||
144 | }, | ||
145 | .ac_conf_count = 4, | ||
146 | .ac_conf = { | ||
147 | [CONF_TX_AC_BE] = { | ||
148 | .ac = CONF_TX_AC_BE, | ||
149 | .cw_min = 15, | ||
150 | .cw_max = 63, | ||
151 | .aifsn = 3, | ||
152 | .tx_op_limit = 0, | ||
153 | }, | ||
154 | [CONF_TX_AC_BK] = { | ||
155 | .ac = CONF_TX_AC_BK, | ||
156 | .cw_min = 15, | ||
157 | .cw_max = 63, | ||
158 | .aifsn = 7, | ||
159 | .tx_op_limit = 0, | ||
160 | }, | ||
161 | [CONF_TX_AC_VI] = { | ||
162 | .ac = CONF_TX_AC_VI, | ||
163 | .cw_min = 15, | ||
164 | .cw_max = 63, | ||
165 | .aifsn = CONF_TX_AIFS_PIFS, | ||
166 | .tx_op_limit = 3008, | ||
167 | }, | ||
168 | [CONF_TX_AC_VO] = { | ||
169 | .ac = CONF_TX_AC_VO, | ||
170 | .cw_min = 15, | ||
171 | .cw_max = 63, | ||
172 | .aifsn = CONF_TX_AIFS_PIFS, | ||
173 | .tx_op_limit = 1504, | ||
174 | }, | ||
175 | }, | ||
176 | .max_tx_retries = 100, | ||
177 | .ap_aging_period = 300, | ||
178 | .tid_conf_count = 4, | ||
179 | .tid_conf = { | ||
180 | [CONF_TX_AC_BE] = { | ||
181 | .queue_id = CONF_TX_AC_BE, | ||
182 | .channel_type = CONF_CHANNEL_TYPE_EDCF, | ||
183 | .tsid = CONF_TX_AC_BE, | ||
184 | .ps_scheme = CONF_PS_SCHEME_LEGACY, | ||
185 | .ack_policy = CONF_ACK_POLICY_LEGACY, | ||
186 | .apsd_conf = {0, 0}, | ||
187 | }, | ||
188 | [CONF_TX_AC_BK] = { | ||
189 | .queue_id = CONF_TX_AC_BK, | ||
190 | .channel_type = CONF_CHANNEL_TYPE_EDCF, | ||
191 | .tsid = CONF_TX_AC_BK, | ||
192 | .ps_scheme = CONF_PS_SCHEME_LEGACY, | ||
193 | .ack_policy = CONF_ACK_POLICY_LEGACY, | ||
194 | .apsd_conf = {0, 0}, | ||
195 | }, | ||
196 | [CONF_TX_AC_VI] = { | ||
197 | .queue_id = CONF_TX_AC_VI, | ||
198 | .channel_type = CONF_CHANNEL_TYPE_EDCF, | ||
199 | .tsid = CONF_TX_AC_VI, | ||
200 | .ps_scheme = CONF_PS_SCHEME_LEGACY, | ||
201 | .ack_policy = CONF_ACK_POLICY_LEGACY, | ||
202 | .apsd_conf = {0, 0}, | ||
203 | }, | ||
204 | [CONF_TX_AC_VO] = { | ||
205 | .queue_id = CONF_TX_AC_VO, | ||
206 | .channel_type = CONF_CHANNEL_TYPE_EDCF, | ||
207 | .tsid = CONF_TX_AC_VO, | ||
208 | .ps_scheme = CONF_PS_SCHEME_LEGACY, | ||
209 | .ack_policy = CONF_ACK_POLICY_LEGACY, | ||
210 | .apsd_conf = {0, 0}, | ||
211 | }, | ||
212 | }, | ||
213 | .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD, | ||
214 | .tx_compl_timeout = 700, | ||
215 | .tx_compl_threshold = 4, | ||
216 | .basic_rate = CONF_HW_BIT_RATE_1MBPS, | ||
217 | .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS, | ||
218 | .tmpl_short_retry_limit = 10, | ||
219 | .tmpl_long_retry_limit = 10, | ||
220 | .tx_watchdog_timeout = 5000, | ||
221 | }, | ||
222 | .conn = { | ||
223 | .wake_up_event = CONF_WAKE_UP_EVENT_DTIM, | ||
224 | .listen_interval = 1, | ||
225 | .suspend_wake_up_event = CONF_WAKE_UP_EVENT_N_DTIM, | ||
226 | .suspend_listen_interval = 3, | ||
227 | .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED, | ||
228 | .bcn_filt_ie_count = 2, | ||
229 | .bcn_filt_ie = { | ||
230 | [0] = { | ||
231 | .ie = WLAN_EID_CHANNEL_SWITCH, | ||
232 | .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE, | ||
233 | }, | ||
234 | [1] = { | ||
235 | .ie = WLAN_EID_HT_OPERATION, | ||
236 | .rule = CONF_BCN_RULE_PASS_ON_CHANGE, | ||
237 | }, | ||
238 | }, | ||
239 | .synch_fail_thold = 10, | ||
240 | .bss_lose_timeout = 100, | ||
241 | .beacon_rx_timeout = 10000, | ||
242 | .broadcast_timeout = 20000, | ||
243 | .rx_broadcast_in_ps = 1, | ||
244 | .ps_poll_threshold = 10, | ||
245 | .bet_enable = CONF_BET_MODE_ENABLE, | ||
246 | .bet_max_consecutive = 50, | ||
247 | .psm_entry_retries = 8, | ||
248 | .psm_exit_retries = 16, | ||
249 | .psm_entry_nullfunc_retries = 3, | ||
250 | .dynamic_ps_timeout = 200, | ||
251 | .forced_ps = false, | ||
252 | .keep_alive_interval = 55000, | ||
253 | .max_listen_interval = 20, | ||
254 | }, | ||
255 | .itrim = { | ||
256 | .enable = false, | ||
257 | .timeout = 50000, | ||
258 | }, | ||
259 | .pm_config = { | ||
260 | .host_clk_settling_time = 5000, | ||
261 | .host_fast_wakeup_support = false | ||
262 | }, | ||
263 | .roam_trigger = { | ||
264 | .trigger_pacing = 1, | ||
265 | .avg_weight_rssi_beacon = 20, | ||
266 | .avg_weight_rssi_data = 10, | ||
267 | .avg_weight_snr_beacon = 20, | ||
268 | .avg_weight_snr_data = 10, | ||
269 | }, | ||
270 | .scan = { | ||
271 | .min_dwell_time_active = 7500, | ||
272 | .max_dwell_time_active = 30000, | ||
273 | .min_dwell_time_passive = 100000, | ||
274 | .max_dwell_time_passive = 100000, | ||
275 | .num_probe_reqs = 2, | ||
276 | .split_scan_timeout = 50000, | ||
277 | }, | ||
278 | .sched_scan = { | ||
279 | /* | ||
280 | * Values are in TU/1000 but since sched scan FW command | ||
281 | * params are in TUs rounding up may occur. | ||
282 | */ | ||
283 | .base_dwell_time = 7500, | ||
284 | .max_dwell_time_delta = 22500, | ||
285 | /* based on 250bits per probe @1Mbps */ | ||
286 | .dwell_time_delta_per_probe = 2000, | ||
287 | /* based on 250bits per probe @6Mbps (plus a bit more) */ | ||
288 | .dwell_time_delta_per_probe_5 = 350, | ||
289 | .dwell_time_passive = 100000, | ||
290 | .dwell_time_dfs = 150000, | ||
291 | .num_probe_reqs = 2, | ||
292 | .rssi_threshold = -90, | ||
293 | .snr_threshold = 0, | ||
294 | }, | ||
295 | .rf = { | ||
296 | .tx_per_channel_power_compensation_2 = { | ||
297 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
298 | }, | ||
299 | .tx_per_channel_power_compensation_5 = { | ||
300 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
301 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
302 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
303 | }, | ||
304 | }, | ||
305 | .ht = { | ||
306 | .rx_ba_win_size = 8, | ||
307 | .tx_ba_win_size = 64, | ||
308 | .inactivity_timeout = 10000, | ||
309 | .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP, | ||
310 | }, | ||
311 | .mem_wl127x = { | ||
312 | .num_stations = 1, | ||
313 | .ssid_profiles = 1, | ||
314 | .rx_block_num = 70, | ||
315 | .tx_min_block_num = 40, | ||
316 | .dynamic_memory = 1, | ||
317 | .min_req_tx_blocks = 100, | ||
318 | .min_req_rx_blocks = 22, | ||
319 | .tx_min = 27, | ||
320 | }, | ||
321 | .mem_wl128x = { | ||
322 | .num_stations = 1, | ||
323 | .ssid_profiles = 1, | ||
324 | .rx_block_num = 40, | ||
325 | .tx_min_block_num = 40, | ||
326 | .dynamic_memory = 1, | ||
327 | .min_req_tx_blocks = 45, | ||
328 | .min_req_rx_blocks = 22, | ||
329 | .tx_min = 27, | ||
330 | }, | ||
331 | .fm_coex = { | ||
332 | .enable = true, | ||
333 | .swallow_period = 5, | ||
334 | .n_divider_fref_set_1 = 0xff, /* default */ | ||
335 | .n_divider_fref_set_2 = 12, | ||
336 | .m_divider_fref_set_1 = 148, | ||
337 | .m_divider_fref_set_2 = 0xffff, /* default */ | ||
338 | .coex_pll_stabilization_time = 0xffffffff, /* default */ | ||
339 | .ldo_stabilization_time = 0xffff, /* default */ | ||
340 | .fm_disturbed_band_margin = 0xff, /* default */ | ||
341 | .swallow_clk_diff = 0xff, /* default */ | ||
342 | }, | ||
343 | .rx_streaming = { | ||
344 | .duration = 150, | ||
345 | .queues = 0x1, | ||
346 | .interval = 20, | ||
347 | .always = 0, | ||
348 | }, | ||
349 | .fwlog = { | ||
350 | .mode = WL12XX_FWLOG_ON_DEMAND, | ||
351 | .mem_blocks = 2, | ||
352 | .severity = 0, | ||
353 | .timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED, | ||
354 | .output = WL12XX_FWLOG_OUTPUT_HOST, | ||
355 | .threshold = 0, | ||
356 | }, | ||
357 | .hci_io_ds = HCI_IO_DS_6MA, | ||
358 | .rate = { | ||
359 | .rate_retry_score = 32000, | ||
360 | .per_add = 8192, | ||
361 | .per_th1 = 2048, | ||
362 | .per_th2 = 4096, | ||
363 | .max_per = 8100, | ||
364 | .inverse_curiosity_factor = 5, | ||
365 | .tx_fail_low_th = 4, | ||
366 | .tx_fail_high_th = 10, | ||
367 | .per_alpha_shift = 4, | ||
368 | .per_add_shift = 13, | ||
369 | .per_beta1_shift = 10, | ||
370 | .per_beta2_shift = 8, | ||
371 | .rate_check_up = 2, | ||
372 | .rate_check_down = 12, | ||
373 | .rate_retry_policy = { | ||
374 | 0x00, 0x00, 0x00, 0x00, 0x00, | ||
375 | 0x00, 0x00, 0x00, 0x00, 0x00, | ||
376 | 0x00, 0x00, 0x00, | ||
377 | }, | ||
378 | }, | ||
379 | .hangover = { | ||
380 | .recover_time = 0, | ||
381 | .hangover_period = 20, | ||
382 | .dynamic_mode = 1, | ||
383 | .early_termination_mode = 1, | ||
384 | .max_period = 20, | ||
385 | .min_period = 1, | ||
386 | .increase_delta = 1, | ||
387 | .decrease_delta = 2, | ||
388 | .quiet_time = 4, | ||
389 | .increase_time = 1, | ||
390 | .window_size = 16, | ||
391 | }, | ||
392 | }; | ||
393 | |||
394 | static char *fwlog_param; | ||
395 | static bool bug_on_recovery; | ||
396 | |||
397 | static void __wl1271_op_remove_interface(struct wl1271 *wl, | ||
398 | struct ieee80211_vif *vif, | ||
399 | bool reset_tx_queues); | ||
400 | static void wl1271_op_stop(struct ieee80211_hw *hw); | ||
401 | static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif); | ||
402 | |||
403 | static int wl12xx_set_authorized(struct wl1271 *wl, | ||
404 | struct wl12xx_vif *wlvif) | ||
405 | { | ||
406 | int ret; | ||
407 | |||
408 | if (WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS)) | ||
409 | return -EINVAL; | ||
410 | |||
411 | if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) | ||
412 | return 0; | ||
413 | |||
414 | if (test_and_set_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags)) | ||
415 | return 0; | ||
416 | |||
417 | ret = wl12xx_cmd_set_peer_state(wl, wlvif->sta.hlid); | ||
418 | if (ret < 0) | ||
419 | return ret; | ||
420 | |||
421 | wl12xx_croc(wl, wlvif->role_id); | ||
422 | |||
423 | wl1271_info("Association completed."); | ||
424 | return 0; | ||
425 | } | ||
426 | |||
427 | static int wl1271_reg_notify(struct wiphy *wiphy, | ||
428 | struct regulatory_request *request) | ||
429 | { | ||
430 | struct ieee80211_supported_band *band; | ||
431 | struct ieee80211_channel *ch; | ||
432 | int i; | ||
433 | |||
434 | band = wiphy->bands[IEEE80211_BAND_5GHZ]; | ||
435 | for (i = 0; i < band->n_channels; i++) { | ||
436 | ch = &band->channels[i]; | ||
437 | if (ch->flags & IEEE80211_CHAN_DISABLED) | ||
438 | continue; | ||
439 | |||
440 | if (ch->flags & IEEE80211_CHAN_RADAR) | ||
441 | ch->flags |= IEEE80211_CHAN_NO_IBSS | | ||
442 | IEEE80211_CHAN_PASSIVE_SCAN; | ||
443 | |||
444 | } | ||
445 | |||
446 | return 0; | ||
447 | } | ||
448 | |||
449 | static int wl1271_set_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
450 | bool enable) | ||
451 | { | ||
452 | int ret = 0; | ||
453 | |||
454 | /* we should hold wl->mutex */ | ||
455 | ret = wl1271_acx_ps_rx_streaming(wl, wlvif, enable); | ||
456 | if (ret < 0) | ||
457 | goto out; | ||
458 | |||
459 | if (enable) | ||
460 | set_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags); | ||
461 | else | ||
462 | clear_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags); | ||
463 | out: | ||
464 | return ret; | ||
465 | } | ||
466 | |||
467 | /* | ||
468 | * this function is being called when the rx_streaming interval | ||
469 | * has beed changed or rx_streaming should be disabled | ||
470 | */ | ||
471 | int wl1271_recalc_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif) | ||
472 | { | ||
473 | int ret = 0; | ||
474 | int period = wl->conf.rx_streaming.interval; | ||
475 | |||
476 | /* don't reconfigure if rx_streaming is disabled */ | ||
477 | if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags)) | ||
478 | goto out; | ||
479 | |||
480 | /* reconfigure/disable according to new streaming_period */ | ||
481 | if (period && | ||
482 | test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) && | ||
483 | (wl->conf.rx_streaming.always || | ||
484 | test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags))) | ||
485 | ret = wl1271_set_rx_streaming(wl, wlvif, true); | ||
486 | else { | ||
487 | ret = wl1271_set_rx_streaming(wl, wlvif, false); | ||
488 | /* don't cancel_work_sync since we might deadlock */ | ||
489 | del_timer_sync(&wlvif->rx_streaming_timer); | ||
490 | } | ||
491 | out: | ||
492 | return ret; | ||
493 | } | ||
494 | |||
495 | static void wl1271_rx_streaming_enable_work(struct work_struct *work) | ||
496 | { | ||
497 | int ret; | ||
498 | struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif, | ||
499 | rx_streaming_enable_work); | ||
500 | struct wl1271 *wl = wlvif->wl; | ||
501 | |||
502 | mutex_lock(&wl->mutex); | ||
503 | |||
504 | if (test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags) || | ||
505 | !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) || | ||
506 | (!wl->conf.rx_streaming.always && | ||
507 | !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags))) | ||
508 | goto out; | ||
509 | |||
510 | if (!wl->conf.rx_streaming.interval) | ||
511 | goto out; | ||
512 | |||
513 | ret = wl1271_ps_elp_wakeup(wl); | ||
514 | if (ret < 0) | ||
515 | goto out; | ||
516 | |||
517 | ret = wl1271_set_rx_streaming(wl, wlvif, true); | ||
518 | if (ret < 0) | ||
519 | goto out_sleep; | ||
520 | |||
521 | /* stop it after some time of inactivity */ | ||
522 | mod_timer(&wlvif->rx_streaming_timer, | ||
523 | jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration)); | ||
524 | |||
525 | out_sleep: | ||
526 | wl1271_ps_elp_sleep(wl); | ||
527 | out: | ||
528 | mutex_unlock(&wl->mutex); | ||
529 | } | ||
530 | |||
531 | static void wl1271_rx_streaming_disable_work(struct work_struct *work) | ||
532 | { | ||
533 | int ret; | ||
534 | struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif, | ||
535 | rx_streaming_disable_work); | ||
536 | struct wl1271 *wl = wlvif->wl; | ||
537 | |||
538 | mutex_lock(&wl->mutex); | ||
539 | |||
540 | if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags)) | ||
541 | goto out; | ||
542 | |||
543 | ret = wl1271_ps_elp_wakeup(wl); | ||
544 | if (ret < 0) | ||
545 | goto out; | ||
546 | |||
547 | ret = wl1271_set_rx_streaming(wl, wlvif, false); | ||
548 | if (ret) | ||
549 | goto out_sleep; | ||
550 | |||
551 | out_sleep: | ||
552 | wl1271_ps_elp_sleep(wl); | ||
553 | out: | ||
554 | mutex_unlock(&wl->mutex); | ||
555 | } | ||
556 | |||
557 | static void wl1271_rx_streaming_timer(unsigned long data) | ||
558 | { | ||
559 | struct wl12xx_vif *wlvif = (struct wl12xx_vif *)data; | ||
560 | struct wl1271 *wl = wlvif->wl; | ||
561 | ieee80211_queue_work(wl->hw, &wlvif->rx_streaming_disable_work); | ||
562 | } | ||
563 | |||
564 | /* wl->mutex must be taken */ | ||
565 | void wl12xx_rearm_tx_watchdog_locked(struct wl1271 *wl) | ||
566 | { | ||
567 | /* if the watchdog is not armed, don't do anything */ | ||
568 | if (wl->tx_allocated_blocks == 0) | ||
569 | return; | ||
570 | |||
571 | cancel_delayed_work(&wl->tx_watchdog_work); | ||
572 | ieee80211_queue_delayed_work(wl->hw, &wl->tx_watchdog_work, | ||
573 | msecs_to_jiffies(wl->conf.tx.tx_watchdog_timeout)); | ||
574 | } | ||
575 | |||
576 | static void wl12xx_tx_watchdog_work(struct work_struct *work) | ||
577 | { | ||
578 | struct delayed_work *dwork; | ||
579 | struct wl1271 *wl; | ||
580 | |||
581 | dwork = container_of(work, struct delayed_work, work); | ||
582 | wl = container_of(dwork, struct wl1271, tx_watchdog_work); | ||
583 | |||
584 | mutex_lock(&wl->mutex); | ||
585 | |||
586 | if (unlikely(wl->state == WL1271_STATE_OFF)) | ||
587 | goto out; | ||
588 | |||
589 | /* Tx went out in the meantime - everything is ok */ | ||
590 | if (unlikely(wl->tx_allocated_blocks == 0)) | ||
591 | goto out; | ||
592 | |||
593 | /* | ||
594 | * if a ROC is in progress, we might not have any Tx for a long | ||
595 | * time (e.g. pending Tx on the non-ROC channels) | ||
596 | */ | ||
597 | if (find_first_bit(wl->roc_map, WL12XX_MAX_ROLES) < WL12XX_MAX_ROLES) { | ||
598 | wl1271_debug(DEBUG_TX, "No Tx (in FW) for %d ms due to ROC", | ||
599 | wl->conf.tx.tx_watchdog_timeout); | ||
600 | wl12xx_rearm_tx_watchdog_locked(wl); | ||
601 | goto out; | ||
602 | } | ||
603 | |||
604 | /* | ||
605 | * if a scan is in progress, we might not have any Tx for a long | ||
606 | * time | ||
607 | */ | ||
608 | if (wl->scan.state != WL1271_SCAN_STATE_IDLE) { | ||
609 | wl1271_debug(DEBUG_TX, "No Tx (in FW) for %d ms due to scan", | ||
610 | wl->conf.tx.tx_watchdog_timeout); | ||
611 | wl12xx_rearm_tx_watchdog_locked(wl); | ||
612 | goto out; | ||
613 | } | ||
614 | |||
615 | /* | ||
616 | * AP might cache a frame for a long time for a sleeping station, | ||
617 | * so rearm the timer if there's an AP interface with stations. If | ||
618 | * Tx is genuinely stuck we will most hopefully discover it when all | ||
619 | * stations are removed due to inactivity. | ||
620 | */ | ||
621 | if (wl->active_sta_count) { | ||
622 | wl1271_debug(DEBUG_TX, "No Tx (in FW) for %d ms. AP has " | ||
623 | " %d stations", | ||
624 | wl->conf.tx.tx_watchdog_timeout, | ||
625 | wl->active_sta_count); | ||
626 | wl12xx_rearm_tx_watchdog_locked(wl); | ||
627 | goto out; | ||
628 | } | ||
629 | |||
630 | wl1271_error("Tx stuck (in FW) for %d ms. Starting recovery", | ||
631 | wl->conf.tx.tx_watchdog_timeout); | ||
632 | wl12xx_queue_recovery_work(wl); | ||
633 | |||
634 | out: | ||
635 | mutex_unlock(&wl->mutex); | ||
636 | } | ||
637 | |||
638 | static void wl1271_conf_init(struct wl1271 *wl) | ||
639 | { | ||
640 | |||
641 | /* | ||
642 | * This function applies the default configuration to the driver. This | ||
643 | * function is invoked upon driver load (spi probe.) | ||
644 | * | ||
645 | * The configuration is stored in a run-time structure in order to | ||
646 | * facilitate for run-time adjustment of any of the parameters. Making | ||
647 | * changes to the configuration structure will apply the new values on | ||
648 | * the next interface up (wl1271_op_start.) | ||
649 | */ | ||
650 | |||
651 | /* apply driver default configuration */ | ||
652 | memcpy(&wl->conf, &default_conf, sizeof(default_conf)); | ||
653 | |||
654 | /* Adjust settings according to optional module parameters */ | ||
655 | if (fwlog_param) { | ||
656 | if (!strcmp(fwlog_param, "continuous")) { | ||
657 | wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS; | ||
658 | } else if (!strcmp(fwlog_param, "ondemand")) { | ||
659 | wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND; | ||
660 | } else if (!strcmp(fwlog_param, "dbgpins")) { | ||
661 | wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS; | ||
662 | wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS; | ||
663 | } else if (!strcmp(fwlog_param, "disable")) { | ||
664 | wl->conf.fwlog.mem_blocks = 0; | ||
665 | wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_NONE; | ||
666 | } else { | ||
667 | wl1271_error("Unknown fwlog parameter %s", fwlog_param); | ||
668 | } | ||
669 | } | ||
670 | } | ||
671 | |||
672 | static int wl1271_plt_init(struct wl1271 *wl) | ||
673 | { | ||
674 | int ret; | ||
675 | |||
676 | if (wl->chip.id == CHIP_ID_1283_PG20) | ||
677 | ret = wl128x_cmd_general_parms(wl); | ||
678 | else | ||
679 | ret = wl1271_cmd_general_parms(wl); | ||
680 | if (ret < 0) | ||
681 | return ret; | ||
682 | |||
683 | if (wl->chip.id == CHIP_ID_1283_PG20) | ||
684 | ret = wl128x_cmd_radio_parms(wl); | ||
685 | else | ||
686 | ret = wl1271_cmd_radio_parms(wl); | ||
687 | if (ret < 0) | ||
688 | return ret; | ||
689 | |||
690 | if (wl->chip.id != CHIP_ID_1283_PG20) { | ||
691 | ret = wl1271_cmd_ext_radio_parms(wl); | ||
692 | if (ret < 0) | ||
693 | return ret; | ||
694 | } | ||
695 | |||
696 | /* Chip-specific initializations */ | ||
697 | ret = wl1271_chip_specific_init(wl); | ||
698 | if (ret < 0) | ||
699 | return ret; | ||
700 | |||
701 | ret = wl1271_acx_init_mem_config(wl); | ||
702 | if (ret < 0) | ||
703 | return ret; | ||
704 | |||
705 | ret = wl12xx_acx_mem_cfg(wl); | ||
706 | if (ret < 0) | ||
707 | goto out_free_memmap; | ||
708 | |||
709 | /* Enable data path */ | ||
710 | ret = wl1271_cmd_data_path(wl, 1); | ||
711 | if (ret < 0) | ||
712 | goto out_free_memmap; | ||
713 | |||
714 | /* Configure for CAM power saving (ie. always active) */ | ||
715 | ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM); | ||
716 | if (ret < 0) | ||
717 | goto out_free_memmap; | ||
718 | |||
719 | /* configure PM */ | ||
720 | ret = wl1271_acx_pm_config(wl); | ||
721 | if (ret < 0) | ||
722 | goto out_free_memmap; | ||
723 | |||
724 | return 0; | ||
725 | |||
726 | out_free_memmap: | ||
727 | kfree(wl->target_mem_map); | ||
728 | wl->target_mem_map = NULL; | ||
729 | |||
730 | return ret; | ||
731 | } | ||
732 | |||
733 | static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, | ||
734 | struct wl12xx_vif *wlvif, | ||
735 | u8 hlid, u8 tx_pkts) | ||
736 | { | ||
737 | bool fw_ps, single_sta; | ||
738 | |||
739 | fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); | ||
740 | single_sta = (wl->active_sta_count == 1); | ||
741 | |||
742 | /* | ||
743 | * Wake up from high level PS if the STA is asleep with too little | ||
744 | * packets in FW or if the STA is awake. | ||
745 | */ | ||
746 | if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS) | ||
747 | wl12xx_ps_link_end(wl, wlvif, hlid); | ||
748 | |||
749 | /* | ||
750 | * Start high-level PS if the STA is asleep with enough blocks in FW. | ||
751 | * Make an exception if this is the only connected station. In this | ||
752 | * case FW-memory congestion is not a problem. | ||
753 | */ | ||
754 | else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS) | ||
755 | wl12xx_ps_link_start(wl, wlvif, hlid, true); | ||
756 | } | ||
757 | |||
758 | static void wl12xx_irq_update_links_status(struct wl1271 *wl, | ||
759 | struct wl12xx_vif *wlvif, | ||
760 | struct wl12xx_fw_status *status) | ||
761 | { | ||
762 | struct wl1271_link *lnk; | ||
763 | u32 cur_fw_ps_map; | ||
764 | u8 hlid, cnt; | ||
765 | |||
766 | /* TODO: also use link_fast_bitmap here */ | ||
767 | |||
768 | cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap); | ||
769 | if (wl->ap_fw_ps_map != cur_fw_ps_map) { | ||
770 | wl1271_debug(DEBUG_PSM, | ||
771 | "link ps prev 0x%x cur 0x%x changed 0x%x", | ||
772 | wl->ap_fw_ps_map, cur_fw_ps_map, | ||
773 | wl->ap_fw_ps_map ^ cur_fw_ps_map); | ||
774 | |||
775 | wl->ap_fw_ps_map = cur_fw_ps_map; | ||
776 | } | ||
777 | |||
778 | for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS) { | ||
779 | lnk = &wl->links[hlid]; | ||
780 | cnt = status->tx_lnk_free_pkts[hlid] - lnk->prev_freed_pkts; | ||
781 | |||
782 | lnk->prev_freed_pkts = status->tx_lnk_free_pkts[hlid]; | ||
783 | lnk->allocated_pkts -= cnt; | ||
784 | |||
785 | wl12xx_irq_ps_regulate_link(wl, wlvif, hlid, | ||
786 | lnk->allocated_pkts); | ||
787 | } | ||
788 | } | ||
789 | |||
790 | static void wl12xx_fw_status(struct wl1271 *wl, | ||
791 | struct wl12xx_fw_status *status) | ||
792 | { | ||
793 | struct wl12xx_vif *wlvif; | ||
794 | struct timespec ts; | ||
795 | u32 old_tx_blk_count = wl->tx_blocks_available; | ||
796 | int avail, freed_blocks; | ||
797 | int i; | ||
798 | |||
799 | wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false); | ||
800 | |||
801 | wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, " | ||
802 | "drv_rx_counter = %d, tx_results_counter = %d)", | ||
803 | status->intr, | ||
804 | status->fw_rx_counter, | ||
805 | status->drv_rx_counter, | ||
806 | status->tx_results_counter); | ||
807 | |||
808 | for (i = 0; i < NUM_TX_QUEUES; i++) { | ||
809 | /* prevent wrap-around in freed-packets counter */ | ||
810 | wl->tx_allocated_pkts[i] -= | ||
811 | (status->tx_released_pkts[i] - | ||
812 | wl->tx_pkts_freed[i]) & 0xff; | ||
813 | |||
814 | wl->tx_pkts_freed[i] = status->tx_released_pkts[i]; | ||
815 | } | ||
816 | |||
817 | /* prevent wrap-around in total blocks counter */ | ||
818 | if (likely(wl->tx_blocks_freed <= | ||
819 | le32_to_cpu(status->total_released_blks))) | ||
820 | freed_blocks = le32_to_cpu(status->total_released_blks) - | ||
821 | wl->tx_blocks_freed; | ||
822 | else | ||
823 | freed_blocks = 0x100000000LL - wl->tx_blocks_freed + | ||
824 | le32_to_cpu(status->total_released_blks); | ||
825 | |||
826 | wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks); | ||
827 | |||
828 | wl->tx_allocated_blocks -= freed_blocks; | ||
829 | |||
830 | /* | ||
831 | * If the FW freed some blocks: | ||
832 | * If we still have allocated blocks - re-arm the timer, Tx is | ||
833 | * not stuck. Otherwise, cancel the timer (no Tx currently). | ||
834 | */ | ||
835 | if (freed_blocks) { | ||
836 | if (wl->tx_allocated_blocks) | ||
837 | wl12xx_rearm_tx_watchdog_locked(wl); | ||
838 | else | ||
839 | cancel_delayed_work(&wl->tx_watchdog_work); | ||
840 | } | ||
841 | |||
842 | avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks; | ||
843 | |||
844 | /* | ||
845 | * The FW might change the total number of TX memblocks before | ||
846 | * we get a notification about blocks being released. Thus, the | ||
847 | * available blocks calculation might yield a temporary result | ||
848 | * which is lower than the actual available blocks. Keeping in | ||
849 | * mind that only blocks that were allocated can be moved from | ||
850 | * TX to RX, tx_blocks_available should never decrease here. | ||
851 | */ | ||
852 | wl->tx_blocks_available = max((int)wl->tx_blocks_available, | ||
853 | avail); | ||
854 | |||
855 | /* if more blocks are available now, tx work can be scheduled */ | ||
856 | if (wl->tx_blocks_available > old_tx_blk_count) | ||
857 | clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); | ||
858 | |||
859 | /* for AP update num of allocated TX blocks per link and ps status */ | ||
860 | wl12xx_for_each_wlvif_ap(wl, wlvif) { | ||
861 | wl12xx_irq_update_links_status(wl, wlvif, status); | ||
862 | } | ||
863 | |||
864 | /* update the host-chipset time offset */ | ||
865 | getnstimeofday(&ts); | ||
866 | wl->time_offset = (timespec_to_ns(&ts) >> 10) - | ||
867 | (s64)le32_to_cpu(status->fw_localtime); | ||
868 | } | ||
869 | |||
870 | static void wl1271_flush_deferred_work(struct wl1271 *wl) | ||
871 | { | ||
872 | struct sk_buff *skb; | ||
873 | |||
874 | /* Pass all received frames to the network stack */ | ||
875 | while ((skb = skb_dequeue(&wl->deferred_rx_queue))) | ||
876 | ieee80211_rx_ni(wl->hw, skb); | ||
877 | |||
878 | /* Return sent skbs to the network stack */ | ||
879 | while ((skb = skb_dequeue(&wl->deferred_tx_queue))) | ||
880 | ieee80211_tx_status_ni(wl->hw, skb); | ||
881 | } | ||
882 | |||
883 | static void wl1271_netstack_work(struct work_struct *work) | ||
884 | { | ||
885 | struct wl1271 *wl = | ||
886 | container_of(work, struct wl1271, netstack_work); | ||
887 | |||
888 | do { | ||
889 | wl1271_flush_deferred_work(wl); | ||
890 | } while (skb_queue_len(&wl->deferred_rx_queue)); | ||
891 | } | ||
892 | |||
893 | #define WL1271_IRQ_MAX_LOOPS 256 | ||
894 | |||
895 | static irqreturn_t wl1271_irq(int irq, void *cookie) | ||
896 | { | ||
897 | int ret; | ||
898 | u32 intr; | ||
899 | int loopcount = WL1271_IRQ_MAX_LOOPS; | ||
900 | struct wl1271 *wl = (struct wl1271 *)cookie; | ||
901 | bool done = false; | ||
902 | unsigned int defer_count; | ||
903 | unsigned long flags; | ||
904 | |||
905 | /* TX might be handled here, avoid redundant work */ | ||
906 | set_bit(WL1271_FLAG_TX_PENDING, &wl->flags); | ||
907 | cancel_work_sync(&wl->tx_work); | ||
908 | |||
909 | /* | ||
910 | * In case edge triggered interrupt must be used, we cannot iterate | ||
911 | * more than once without introducing race conditions with the hardirq. | ||
912 | */ | ||
913 | if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) | ||
914 | loopcount = 1; | ||
915 | |||
916 | mutex_lock(&wl->mutex); | ||
917 | |||
918 | wl1271_debug(DEBUG_IRQ, "IRQ work"); | ||
919 | |||
920 | if (unlikely(wl->state == WL1271_STATE_OFF)) | ||
921 | goto out; | ||
922 | |||
923 | ret = wl1271_ps_elp_wakeup(wl); | ||
924 | if (ret < 0) | ||
925 | goto out; | ||
926 | |||
927 | while (!done && loopcount--) { | ||
928 | /* | ||
929 | * In order to avoid a race with the hardirq, clear the flag | ||
930 | * before acknowledging the chip. Since the mutex is held, | ||
931 | * wl1271_ps_elp_wakeup cannot be called concurrently. | ||
932 | */ | ||
933 | clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags); | ||
934 | smp_mb__after_clear_bit(); | ||
935 | |||
936 | wl12xx_fw_status(wl, wl->fw_status); | ||
937 | intr = le32_to_cpu(wl->fw_status->intr); | ||
938 | intr &= WL1271_INTR_MASK; | ||
939 | if (!intr) { | ||
940 | done = true; | ||
941 | continue; | ||
942 | } | ||
943 | |||
944 | if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) { | ||
945 | wl1271_error("watchdog interrupt received! " | ||
946 | "starting recovery."); | ||
947 | wl12xx_queue_recovery_work(wl); | ||
948 | |||
949 | /* restarting the chip. ignore any other interrupt. */ | ||
950 | goto out; | ||
951 | } | ||
952 | |||
953 | if (likely(intr & WL1271_ACX_INTR_DATA)) { | ||
954 | wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA"); | ||
955 | |||
956 | wl12xx_rx(wl, wl->fw_status); | ||
957 | |||
958 | /* Check if any tx blocks were freed */ | ||
959 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
960 | if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) && | ||
961 | wl1271_tx_total_queue_count(wl) > 0) { | ||
962 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
963 | /* | ||
964 | * In order to avoid starvation of the TX path, | ||
965 | * call the work function directly. | ||
966 | */ | ||
967 | wl1271_tx_work_locked(wl); | ||
968 | } else { | ||
969 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
970 | } | ||
971 | |||
972 | /* check for tx results */ | ||
973 | if (wl->fw_status->tx_results_counter != | ||
974 | (wl->tx_results_count & 0xff)) | ||
975 | wl1271_tx_complete(wl); | ||
976 | |||
977 | /* Make sure the deferred queues don't get too long */ | ||
978 | defer_count = skb_queue_len(&wl->deferred_tx_queue) + | ||
979 | skb_queue_len(&wl->deferred_rx_queue); | ||
980 | if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT) | ||
981 | wl1271_flush_deferred_work(wl); | ||
982 | } | ||
983 | |||
984 | if (intr & WL1271_ACX_INTR_EVENT_A) { | ||
985 | wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A"); | ||
986 | wl1271_event_handle(wl, 0); | ||
987 | } | ||
988 | |||
989 | if (intr & WL1271_ACX_INTR_EVENT_B) { | ||
990 | wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B"); | ||
991 | wl1271_event_handle(wl, 1); | ||
992 | } | ||
993 | |||
994 | if (intr & WL1271_ACX_INTR_INIT_COMPLETE) | ||
995 | wl1271_debug(DEBUG_IRQ, | ||
996 | "WL1271_ACX_INTR_INIT_COMPLETE"); | ||
997 | |||
998 | if (intr & WL1271_ACX_INTR_HW_AVAILABLE) | ||
999 | wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE"); | ||
1000 | } | ||
1001 | |||
1002 | wl1271_ps_elp_sleep(wl); | ||
1003 | |||
1004 | out: | ||
1005 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
1006 | /* In case TX was not handled here, queue TX work */ | ||
1007 | clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags); | ||
1008 | if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) && | ||
1009 | wl1271_tx_total_queue_count(wl) > 0) | ||
1010 | ieee80211_queue_work(wl->hw, &wl->tx_work); | ||
1011 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
1012 | |||
1013 | mutex_unlock(&wl->mutex); | ||
1014 | |||
1015 | return IRQ_HANDLED; | ||
1016 | } | ||
1017 | |||
1018 | struct vif_counter_data { | ||
1019 | u8 counter; | ||
1020 | |||
1021 | struct ieee80211_vif *cur_vif; | ||
1022 | bool cur_vif_running; | ||
1023 | }; | ||
1024 | |||
1025 | static void wl12xx_vif_count_iter(void *data, u8 *mac, | ||
1026 | struct ieee80211_vif *vif) | ||
1027 | { | ||
1028 | struct vif_counter_data *counter = data; | ||
1029 | |||
1030 | counter->counter++; | ||
1031 | if (counter->cur_vif == vif) | ||
1032 | counter->cur_vif_running = true; | ||
1033 | } | ||
1034 | |||
1035 | /* caller must not hold wl->mutex, as it might deadlock */ | ||
1036 | static void wl12xx_get_vif_count(struct ieee80211_hw *hw, | ||
1037 | struct ieee80211_vif *cur_vif, | ||
1038 | struct vif_counter_data *data) | ||
1039 | { | ||
1040 | memset(data, 0, sizeof(*data)); | ||
1041 | data->cur_vif = cur_vif; | ||
1042 | |||
1043 | ieee80211_iterate_active_interfaces(hw, | ||
1044 | wl12xx_vif_count_iter, data); | ||
1045 | } | ||
1046 | |||
1047 | static int wl12xx_fetch_firmware(struct wl1271 *wl, bool plt) | ||
1048 | { | ||
1049 | const struct firmware *fw; | ||
1050 | const char *fw_name; | ||
1051 | enum wl12xx_fw_type fw_type; | ||
1052 | int ret; | ||
1053 | |||
1054 | if (plt) { | ||
1055 | fw_type = WL12XX_FW_TYPE_PLT; | ||
1056 | if (wl->chip.id == CHIP_ID_1283_PG20) | ||
1057 | fw_name = WL128X_PLT_FW_NAME; | ||
1058 | else | ||
1059 | fw_name = WL127X_PLT_FW_NAME; | ||
1060 | } else { | ||
1061 | /* | ||
1062 | * we can't call wl12xx_get_vif_count() here because | ||
1063 | * wl->mutex is taken, so use the cached last_vif_count value | ||
1064 | */ | ||
1065 | if (wl->last_vif_count > 1) { | ||
1066 | fw_type = WL12XX_FW_TYPE_MULTI; | ||
1067 | if (wl->chip.id == CHIP_ID_1283_PG20) | ||
1068 | fw_name = WL128X_FW_NAME_MULTI; | ||
1069 | else | ||
1070 | fw_name = WL127X_FW_NAME_MULTI; | ||
1071 | } else { | ||
1072 | fw_type = WL12XX_FW_TYPE_NORMAL; | ||
1073 | if (wl->chip.id == CHIP_ID_1283_PG20) | ||
1074 | fw_name = WL128X_FW_NAME_SINGLE; | ||
1075 | else | ||
1076 | fw_name = WL127X_FW_NAME_SINGLE; | ||
1077 | } | ||
1078 | } | ||
1079 | |||
1080 | if (wl->fw_type == fw_type) | ||
1081 | return 0; | ||
1082 | |||
1083 | wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name); | ||
1084 | |||
1085 | ret = request_firmware(&fw, fw_name, wl->dev); | ||
1086 | |||
1087 | if (ret < 0) { | ||
1088 | wl1271_error("could not get firmware %s: %d", fw_name, ret); | ||
1089 | return ret; | ||
1090 | } | ||
1091 | |||
1092 | if (fw->size % 4) { | ||
1093 | wl1271_error("firmware size is not multiple of 32 bits: %zu", | ||
1094 | fw->size); | ||
1095 | ret = -EILSEQ; | ||
1096 | goto out; | ||
1097 | } | ||
1098 | |||
1099 | vfree(wl->fw); | ||
1100 | wl->fw_type = WL12XX_FW_TYPE_NONE; | ||
1101 | wl->fw_len = fw->size; | ||
1102 | wl->fw = vmalloc(wl->fw_len); | ||
1103 | |||
1104 | if (!wl->fw) { | ||
1105 | wl1271_error("could not allocate memory for the firmware"); | ||
1106 | ret = -ENOMEM; | ||
1107 | goto out; | ||
1108 | } | ||
1109 | |||
1110 | memcpy(wl->fw, fw->data, wl->fw_len); | ||
1111 | ret = 0; | ||
1112 | wl->fw_type = fw_type; | ||
1113 | out: | ||
1114 | release_firmware(fw); | ||
1115 | |||
1116 | return ret; | ||
1117 | } | ||
1118 | |||
1119 | static int wl1271_fetch_nvs(struct wl1271 *wl) | ||
1120 | { | ||
1121 | const struct firmware *fw; | ||
1122 | int ret; | ||
1123 | |||
1124 | ret = request_firmware(&fw, WL12XX_NVS_NAME, wl->dev); | ||
1125 | |||
1126 | if (ret < 0) { | ||
1127 | wl1271_error("could not get nvs file %s: %d", WL12XX_NVS_NAME, | ||
1128 | ret); | ||
1129 | return ret; | ||
1130 | } | ||
1131 | |||
1132 | wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL); | ||
1133 | |||
1134 | if (!wl->nvs) { | ||
1135 | wl1271_error("could not allocate memory for the nvs file"); | ||
1136 | ret = -ENOMEM; | ||
1137 | goto out; | ||
1138 | } | ||
1139 | |||
1140 | wl->nvs_len = fw->size; | ||
1141 | |||
1142 | out: | ||
1143 | release_firmware(fw); | ||
1144 | |||
1145 | return ret; | ||
1146 | } | ||
1147 | |||
1148 | void wl12xx_queue_recovery_work(struct wl1271 *wl) | ||
1149 | { | ||
1150 | if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) | ||
1151 | ieee80211_queue_work(wl->hw, &wl->recovery_work); | ||
1152 | } | ||
1153 | |||
1154 | size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen) | ||
1155 | { | ||
1156 | size_t len = 0; | ||
1157 | |||
1158 | /* The FW log is a length-value list, find where the log end */ | ||
1159 | while (len < maxlen) { | ||
1160 | if (memblock[len] == 0) | ||
1161 | break; | ||
1162 | if (len + memblock[len] + 1 > maxlen) | ||
1163 | break; | ||
1164 | len += memblock[len] + 1; | ||
1165 | } | ||
1166 | |||
1167 | /* Make sure we have enough room */ | ||
1168 | len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size)); | ||
1169 | |||
1170 | /* Fill the FW log file, consumed by the sysfs fwlog entry */ | ||
1171 | memcpy(wl->fwlog + wl->fwlog_size, memblock, len); | ||
1172 | wl->fwlog_size += len; | ||
1173 | |||
1174 | return len; | ||
1175 | } | ||
1176 | |||
1177 | static void wl12xx_read_fwlog_panic(struct wl1271 *wl) | ||
1178 | { | ||
1179 | u32 addr; | ||
1180 | u32 first_addr; | ||
1181 | u8 *block; | ||
1182 | |||
1183 | if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) || | ||
1184 | (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) || | ||
1185 | (wl->conf.fwlog.mem_blocks == 0)) | ||
1186 | return; | ||
1187 | |||
1188 | wl1271_info("Reading FW panic log"); | ||
1189 | |||
1190 | block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL); | ||
1191 | if (!block) | ||
1192 | return; | ||
1193 | |||
1194 | /* | ||
1195 | * Make sure the chip is awake and the logger isn't active. | ||
1196 | * This might fail if the firmware hanged. | ||
1197 | */ | ||
1198 | if (!wl1271_ps_elp_wakeup(wl)) | ||
1199 | wl12xx_cmd_stop_fwlog(wl); | ||
1200 | |||
1201 | /* Read the first memory block address */ | ||
1202 | wl12xx_fw_status(wl, wl->fw_status); | ||
1203 | first_addr = le32_to_cpu(wl->fw_status->log_start_addr); | ||
1204 | if (!first_addr) | ||
1205 | goto out; | ||
1206 | |||
1207 | /* Traverse the memory blocks linked list */ | ||
1208 | addr = first_addr; | ||
1209 | do { | ||
1210 | memset(block, 0, WL12XX_HW_BLOCK_SIZE); | ||
1211 | wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE, | ||
1212 | false); | ||
1213 | |||
1214 | /* | ||
1215 | * Memory blocks are linked to one another. The first 4 bytes | ||
1216 | * of each memory block hold the hardware address of the next | ||
1217 | * one. The last memory block points to the first one. | ||
1218 | */ | ||
1219 | addr = le32_to_cpup((__le32 *)block); | ||
1220 | if (!wl12xx_copy_fwlog(wl, block + sizeof(addr), | ||
1221 | WL12XX_HW_BLOCK_SIZE - sizeof(addr))) | ||
1222 | break; | ||
1223 | } while (addr && (addr != first_addr)); | ||
1224 | |||
1225 | wake_up_interruptible(&wl->fwlog_waitq); | ||
1226 | |||
1227 | out: | ||
1228 | kfree(block); | ||
1229 | } | ||
1230 | |||
1231 | static void wl1271_recovery_work(struct work_struct *work) | ||
1232 | { | ||
1233 | struct wl1271 *wl = | ||
1234 | container_of(work, struct wl1271, recovery_work); | ||
1235 | struct wl12xx_vif *wlvif; | ||
1236 | struct ieee80211_vif *vif; | ||
1237 | |||
1238 | mutex_lock(&wl->mutex); | ||
1239 | |||
1240 | if (wl->state != WL1271_STATE_ON || wl->plt) | ||
1241 | goto out_unlock; | ||
1242 | |||
1243 | /* Avoid a recursive recovery */ | ||
1244 | set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags); | ||
1245 | |||
1246 | wl12xx_read_fwlog_panic(wl); | ||
1247 | |||
1248 | wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x", | ||
1249 | wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4)); | ||
1250 | |||
1251 | BUG_ON(bug_on_recovery && | ||
1252 | !test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags)); | ||
1253 | |||
1254 | /* | ||
1255 | * Advance security sequence number to overcome potential progress | ||
1256 | * in the firmware during recovery. This doens't hurt if the network is | ||
1257 | * not encrypted. | ||
1258 | */ | ||
1259 | wl12xx_for_each_wlvif(wl, wlvif) { | ||
1260 | if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) || | ||
1261 | test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) | ||
1262 | wlvif->tx_security_seq += | ||
1263 | WL1271_TX_SQN_POST_RECOVERY_PADDING; | ||
1264 | } | ||
1265 | |||
1266 | /* Prevent spurious TX during FW restart */ | ||
1267 | ieee80211_stop_queues(wl->hw); | ||
1268 | |||
1269 | if (wl->sched_scanning) { | ||
1270 | ieee80211_sched_scan_stopped(wl->hw); | ||
1271 | wl->sched_scanning = false; | ||
1272 | } | ||
1273 | |||
1274 | /* reboot the chipset */ | ||
1275 | while (!list_empty(&wl->wlvif_list)) { | ||
1276 | wlvif = list_first_entry(&wl->wlvif_list, | ||
1277 | struct wl12xx_vif, list); | ||
1278 | vif = wl12xx_wlvif_to_vif(wlvif); | ||
1279 | __wl1271_op_remove_interface(wl, vif, false); | ||
1280 | } | ||
1281 | mutex_unlock(&wl->mutex); | ||
1282 | wl1271_op_stop(wl->hw); | ||
1283 | |||
1284 | clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags); | ||
1285 | |||
1286 | ieee80211_restart_hw(wl->hw); | ||
1287 | |||
1288 | /* | ||
1289 | * Its safe to enable TX now - the queues are stopped after a request | ||
1290 | * to restart the HW. | ||
1291 | */ | ||
1292 | ieee80211_wake_queues(wl->hw); | ||
1293 | return; | ||
1294 | out_unlock: | ||
1295 | mutex_unlock(&wl->mutex); | ||
1296 | } | ||
1297 | |||
1298 | static void wl1271_fw_wakeup(struct wl1271 *wl) | ||
1299 | { | ||
1300 | u32 elp_reg; | ||
1301 | |||
1302 | elp_reg = ELPCTRL_WAKE_UP; | ||
1303 | wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg); | ||
1304 | } | ||
1305 | |||
1306 | static int wl1271_setup(struct wl1271 *wl) | ||
1307 | { | ||
1308 | wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL); | ||
1309 | if (!wl->fw_status) | ||
1310 | return -ENOMEM; | ||
1311 | |||
1312 | wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL); | ||
1313 | if (!wl->tx_res_if) { | ||
1314 | kfree(wl->fw_status); | ||
1315 | return -ENOMEM; | ||
1316 | } | ||
1317 | |||
1318 | return 0; | ||
1319 | } | ||
1320 | |||
1321 | static int wl12xx_set_power_on(struct wl1271 *wl) | ||
1322 | { | ||
1323 | int ret; | ||
1324 | |||
1325 | msleep(WL1271_PRE_POWER_ON_SLEEP); | ||
1326 | ret = wl1271_power_on(wl); | ||
1327 | if (ret < 0) | ||
1328 | goto out; | ||
1329 | msleep(WL1271_POWER_ON_SLEEP); | ||
1330 | wl1271_io_reset(wl); | ||
1331 | wl1271_io_init(wl); | ||
1332 | |||
1333 | wl1271_set_partition(wl, &wl12xx_part_table[PART_DOWN]); | ||
1334 | |||
1335 | /* ELP module wake up */ | ||
1336 | wl1271_fw_wakeup(wl); | ||
1337 | |||
1338 | out: | ||
1339 | return ret; | ||
1340 | } | ||
1341 | |||
1342 | static int wl12xx_chip_wakeup(struct wl1271 *wl, bool plt) | ||
1343 | { | ||
1344 | int ret = 0; | ||
1345 | |||
1346 | ret = wl12xx_set_power_on(wl); | ||
1347 | if (ret < 0) | ||
1348 | goto out; | ||
1349 | |||
1350 | /* | ||
1351 | * For wl127x based devices we could use the default block | ||
1352 | * size (512 bytes), but due to a bug in the sdio driver, we | ||
1353 | * need to set it explicitly after the chip is powered on. To | ||
1354 | * simplify the code and since the performance impact is | ||
1355 | * negligible, we use the same block size for all different | ||
1356 | * chip types. | ||
1357 | */ | ||
1358 | if (!wl1271_set_block_size(wl)) | ||
1359 | wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT; | ||
1360 | |||
1361 | switch (wl->chip.id) { | ||
1362 | case CHIP_ID_1271_PG10: | ||
1363 | wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete", | ||
1364 | wl->chip.id); | ||
1365 | |||
1366 | ret = wl1271_setup(wl); | ||
1367 | if (ret < 0) | ||
1368 | goto out; | ||
1369 | wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT; | ||
1370 | break; | ||
1371 | |||
1372 | case CHIP_ID_1271_PG20: | ||
1373 | wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)", | ||
1374 | wl->chip.id); | ||
1375 | |||
1376 | ret = wl1271_setup(wl); | ||
1377 | if (ret < 0) | ||
1378 | goto out; | ||
1379 | wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT; | ||
1380 | break; | ||
1381 | |||
1382 | case CHIP_ID_1283_PG20: | ||
1383 | wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)", | ||
1384 | wl->chip.id); | ||
1385 | |||
1386 | ret = wl1271_setup(wl); | ||
1387 | if (ret < 0) | ||
1388 | goto out; | ||
1389 | break; | ||
1390 | case CHIP_ID_1283_PG10: | ||
1391 | default: | ||
1392 | wl1271_warning("unsupported chip id: 0x%x", wl->chip.id); | ||
1393 | ret = -ENODEV; | ||
1394 | goto out; | ||
1395 | } | ||
1396 | |||
1397 | ret = wl12xx_fetch_firmware(wl, plt); | ||
1398 | if (ret < 0) | ||
1399 | goto out; | ||
1400 | |||
1401 | /* No NVS from netlink, try to get it from the filesystem */ | ||
1402 | if (wl->nvs == NULL) { | ||
1403 | ret = wl1271_fetch_nvs(wl); | ||
1404 | if (ret < 0) | ||
1405 | goto out; | ||
1406 | } | ||
1407 | |||
1408 | out: | ||
1409 | return ret; | ||
1410 | } | ||
1411 | |||
1412 | int wl1271_plt_start(struct wl1271 *wl) | ||
1413 | { | ||
1414 | int retries = WL1271_BOOT_RETRIES; | ||
1415 | struct wiphy *wiphy = wl->hw->wiphy; | ||
1416 | int ret; | ||
1417 | |||
1418 | mutex_lock(&wl->mutex); | ||
1419 | |||
1420 | wl1271_notice("power up"); | ||
1421 | |||
1422 | if (wl->state != WL1271_STATE_OFF) { | ||
1423 | wl1271_error("cannot go into PLT state because not " | ||
1424 | "in off state: %d", wl->state); | ||
1425 | ret = -EBUSY; | ||
1426 | goto out; | ||
1427 | } | ||
1428 | |||
1429 | while (retries) { | ||
1430 | retries--; | ||
1431 | ret = wl12xx_chip_wakeup(wl, true); | ||
1432 | if (ret < 0) | ||
1433 | goto power_off; | ||
1434 | |||
1435 | ret = wl1271_boot(wl); | ||
1436 | if (ret < 0) | ||
1437 | goto power_off; | ||
1438 | |||
1439 | ret = wl1271_plt_init(wl); | ||
1440 | if (ret < 0) | ||
1441 | goto irq_disable; | ||
1442 | |||
1443 | wl->plt = true; | ||
1444 | wl->state = WL1271_STATE_ON; | ||
1445 | wl1271_notice("firmware booted in PLT mode (%s)", | ||
1446 | wl->chip.fw_ver_str); | ||
1447 | |||
1448 | /* update hw/fw version info in wiphy struct */ | ||
1449 | wiphy->hw_version = wl->chip.id; | ||
1450 | strncpy(wiphy->fw_version, wl->chip.fw_ver_str, | ||
1451 | sizeof(wiphy->fw_version)); | ||
1452 | |||
1453 | goto out; | ||
1454 | |||
1455 | irq_disable: | ||
1456 | mutex_unlock(&wl->mutex); | ||
1457 | /* Unlocking the mutex in the middle of handling is | ||
1458 | inherently unsafe. In this case we deem it safe to do, | ||
1459 | because we need to let any possibly pending IRQ out of | ||
1460 | the system (and while we are WL1271_STATE_OFF the IRQ | ||
1461 | work function will not do anything.) Also, any other | ||
1462 | possible concurrent operations will fail due to the | ||
1463 | current state, hence the wl1271 struct should be safe. */ | ||
1464 | wl1271_disable_interrupts(wl); | ||
1465 | wl1271_flush_deferred_work(wl); | ||
1466 | cancel_work_sync(&wl->netstack_work); | ||
1467 | mutex_lock(&wl->mutex); | ||
1468 | power_off: | ||
1469 | wl1271_power_off(wl); | ||
1470 | } | ||
1471 | |||
1472 | wl1271_error("firmware boot in PLT mode failed despite %d retries", | ||
1473 | WL1271_BOOT_RETRIES); | ||
1474 | out: | ||
1475 | mutex_unlock(&wl->mutex); | ||
1476 | |||
1477 | return ret; | ||
1478 | } | ||
1479 | |||
1480 | int wl1271_plt_stop(struct wl1271 *wl) | ||
1481 | { | ||
1482 | int ret = 0; | ||
1483 | |||
1484 | wl1271_notice("power down"); | ||
1485 | |||
1486 | /* | ||
1487 | * Interrupts must be disabled before setting the state to OFF. | ||
1488 | * Otherwise, the interrupt handler might be called and exit without | ||
1489 | * reading the interrupt status. | ||
1490 | */ | ||
1491 | wl1271_disable_interrupts(wl); | ||
1492 | mutex_lock(&wl->mutex); | ||
1493 | if (!wl->plt) { | ||
1494 | mutex_unlock(&wl->mutex); | ||
1495 | |||
1496 | /* | ||
1497 | * This will not necessarily enable interrupts as interrupts | ||
1498 | * may have been disabled when op_stop was called. It will, | ||
1499 | * however, balance the above call to disable_interrupts(). | ||
1500 | */ | ||
1501 | wl1271_enable_interrupts(wl); | ||
1502 | |||
1503 | wl1271_error("cannot power down because not in PLT " | ||
1504 | "state: %d", wl->state); | ||
1505 | ret = -EBUSY; | ||
1506 | goto out; | ||
1507 | } | ||
1508 | |||
1509 | mutex_unlock(&wl->mutex); | ||
1510 | |||
1511 | wl1271_flush_deferred_work(wl); | ||
1512 | cancel_work_sync(&wl->netstack_work); | ||
1513 | cancel_work_sync(&wl->recovery_work); | ||
1514 | cancel_delayed_work_sync(&wl->elp_work); | ||
1515 | cancel_delayed_work_sync(&wl->tx_watchdog_work); | ||
1516 | |||
1517 | mutex_lock(&wl->mutex); | ||
1518 | wl1271_power_off(wl); | ||
1519 | wl->flags = 0; | ||
1520 | wl->state = WL1271_STATE_OFF; | ||
1521 | wl->plt = false; | ||
1522 | wl->rx_counter = 0; | ||
1523 | mutex_unlock(&wl->mutex); | ||
1524 | |||
1525 | out: | ||
1526 | return ret; | ||
1527 | } | ||
1528 | |||
1529 | static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | ||
1530 | { | ||
1531 | struct wl1271 *wl = hw->priv; | ||
1532 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
1533 | struct ieee80211_vif *vif = info->control.vif; | ||
1534 | struct wl12xx_vif *wlvif = NULL; | ||
1535 | unsigned long flags; | ||
1536 | int q, mapping; | ||
1537 | u8 hlid; | ||
1538 | |||
1539 | if (vif) | ||
1540 | wlvif = wl12xx_vif_to_data(vif); | ||
1541 | |||
1542 | mapping = skb_get_queue_mapping(skb); | ||
1543 | q = wl1271_tx_get_queue(mapping); | ||
1544 | |||
1545 | hlid = wl12xx_tx_get_hlid(wl, wlvif, skb); | ||
1546 | |||
1547 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
1548 | |||
1549 | /* queue the packet */ | ||
1550 | if (hlid == WL12XX_INVALID_LINK_ID || | ||
1551 | (wlvif && !test_bit(hlid, wlvif->links_map))) { | ||
1552 | wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q); | ||
1553 | ieee80211_free_txskb(hw, skb); | ||
1554 | goto out; | ||
1555 | } | ||
1556 | |||
1557 | wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d len %d", | ||
1558 | hlid, q, skb->len); | ||
1559 | skb_queue_tail(&wl->links[hlid].tx_queue[q], skb); | ||
1560 | |||
1561 | wl->tx_queue_count[q]++; | ||
1562 | |||
1563 | /* | ||
1564 | * The workqueue is slow to process the tx_queue and we need stop | ||
1565 | * the queue here, otherwise the queue will get too long. | ||
1566 | */ | ||
1567 | if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) { | ||
1568 | wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q); | ||
1569 | ieee80211_stop_queue(wl->hw, mapping); | ||
1570 | set_bit(q, &wl->stopped_queues_map); | ||
1571 | } | ||
1572 | |||
1573 | /* | ||
1574 | * The chip specific setup must run before the first TX packet - | ||
1575 | * before that, the tx_work will not be initialized! | ||
1576 | */ | ||
1577 | |||
1578 | if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) && | ||
1579 | !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags)) | ||
1580 | ieee80211_queue_work(wl->hw, &wl->tx_work); | ||
1581 | |||
1582 | out: | ||
1583 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
1584 | } | ||
1585 | |||
1586 | int wl1271_tx_dummy_packet(struct wl1271 *wl) | ||
1587 | { | ||
1588 | unsigned long flags; | ||
1589 | int q; | ||
1590 | |||
1591 | /* no need to queue a new dummy packet if one is already pending */ | ||
1592 | if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) | ||
1593 | return 0; | ||
1594 | |||
1595 | q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet)); | ||
1596 | |||
1597 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
1598 | set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags); | ||
1599 | wl->tx_queue_count[q]++; | ||
1600 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
1601 | |||
1602 | /* The FW is low on RX memory blocks, so send the dummy packet asap */ | ||
1603 | if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags)) | ||
1604 | wl1271_tx_work_locked(wl); | ||
1605 | |||
1606 | /* | ||
1607 | * If the FW TX is busy, TX work will be scheduled by the threaded | ||
1608 | * interrupt handler function | ||
1609 | */ | ||
1610 | return 0; | ||
1611 | } | ||
1612 | |||
1613 | /* | ||
1614 | * The size of the dummy packet should be at least 1400 bytes. However, in | ||
1615 | * order to minimize the number of bus transactions, aligning it to 512 bytes | ||
1616 | * boundaries could be beneficial, performance wise | ||
1617 | */ | ||
1618 | #define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512)) | ||
1619 | |||
1620 | static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl) | ||
1621 | { | ||
1622 | struct sk_buff *skb; | ||
1623 | struct ieee80211_hdr_3addr *hdr; | ||
1624 | unsigned int dummy_packet_size; | ||
1625 | |||
1626 | dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE - | ||
1627 | sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr); | ||
1628 | |||
1629 | skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE); | ||
1630 | if (!skb) { | ||
1631 | wl1271_warning("Failed to allocate a dummy packet skb"); | ||
1632 | return NULL; | ||
1633 | } | ||
1634 | |||
1635 | skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr)); | ||
1636 | |||
1637 | hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr)); | ||
1638 | memset(hdr, 0, sizeof(*hdr)); | ||
1639 | hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | | ||
1640 | IEEE80211_STYPE_NULLFUNC | | ||
1641 | IEEE80211_FCTL_TODS); | ||
1642 | |||
1643 | memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size); | ||
1644 | |||
1645 | /* Dummy packets require the TID to be management */ | ||
1646 | skb->priority = WL1271_TID_MGMT; | ||
1647 | |||
1648 | /* Initialize all fields that might be used */ | ||
1649 | skb_set_queue_mapping(skb, 0); | ||
1650 | memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info)); | ||
1651 | |||
1652 | return skb; | ||
1653 | } | ||
1654 | |||
1655 | |||
1656 | #ifdef CONFIG_PM | ||
1657 | static int wl1271_configure_suspend_sta(struct wl1271 *wl, | ||
1658 | struct wl12xx_vif *wlvif) | ||
1659 | { | ||
1660 | int ret = 0; | ||
1661 | |||
1662 | if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) | ||
1663 | goto out; | ||
1664 | |||
1665 | ret = wl1271_ps_elp_wakeup(wl); | ||
1666 | if (ret < 0) | ||
1667 | goto out; | ||
1668 | |||
1669 | ret = wl1271_acx_wake_up_conditions(wl, wlvif, | ||
1670 | wl->conf.conn.suspend_wake_up_event, | ||
1671 | wl->conf.conn.suspend_listen_interval); | ||
1672 | |||
1673 | if (ret < 0) | ||
1674 | wl1271_error("suspend: set wake up conditions failed: %d", ret); | ||
1675 | |||
1676 | wl1271_ps_elp_sleep(wl); | ||
1677 | |||
1678 | out: | ||
1679 | return ret; | ||
1680 | |||
1681 | } | ||
1682 | |||
1683 | static int wl1271_configure_suspend_ap(struct wl1271 *wl, | ||
1684 | struct wl12xx_vif *wlvif) | ||
1685 | { | ||
1686 | int ret = 0; | ||
1687 | |||
1688 | if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) | ||
1689 | goto out; | ||
1690 | |||
1691 | ret = wl1271_ps_elp_wakeup(wl); | ||
1692 | if (ret < 0) | ||
1693 | goto out; | ||
1694 | |||
1695 | ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true); | ||
1696 | |||
1697 | wl1271_ps_elp_sleep(wl); | ||
1698 | out: | ||
1699 | return ret; | ||
1700 | |||
1701 | } | ||
1702 | |||
1703 | static int wl1271_configure_suspend(struct wl1271 *wl, | ||
1704 | struct wl12xx_vif *wlvif) | ||
1705 | { | ||
1706 | if (wlvif->bss_type == BSS_TYPE_STA_BSS) | ||
1707 | return wl1271_configure_suspend_sta(wl, wlvif); | ||
1708 | if (wlvif->bss_type == BSS_TYPE_AP_BSS) | ||
1709 | return wl1271_configure_suspend_ap(wl, wlvif); | ||
1710 | return 0; | ||
1711 | } | ||
1712 | |||
1713 | static void wl1271_configure_resume(struct wl1271 *wl, | ||
1714 | struct wl12xx_vif *wlvif) | ||
1715 | { | ||
1716 | int ret = 0; | ||
1717 | bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS; | ||
1718 | bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS; | ||
1719 | |||
1720 | if ((!is_ap) && (!is_sta)) | ||
1721 | return; | ||
1722 | |||
1723 | ret = wl1271_ps_elp_wakeup(wl); | ||
1724 | if (ret < 0) | ||
1725 | return; | ||
1726 | |||
1727 | if (is_sta) { | ||
1728 | ret = wl1271_acx_wake_up_conditions(wl, wlvif, | ||
1729 | wl->conf.conn.wake_up_event, | ||
1730 | wl->conf.conn.listen_interval); | ||
1731 | |||
1732 | if (ret < 0) | ||
1733 | wl1271_error("resume: wake up conditions failed: %d", | ||
1734 | ret); | ||
1735 | |||
1736 | } else if (is_ap) { | ||
1737 | ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false); | ||
1738 | } | ||
1739 | |||
1740 | wl1271_ps_elp_sleep(wl); | ||
1741 | } | ||
1742 | |||
1743 | static int wl1271_op_suspend(struct ieee80211_hw *hw, | ||
1744 | struct cfg80211_wowlan *wow) | ||
1745 | { | ||
1746 | struct wl1271 *wl = hw->priv; | ||
1747 | struct wl12xx_vif *wlvif; | ||
1748 | int ret; | ||
1749 | |||
1750 | wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow); | ||
1751 | WARN_ON(!wow || !wow->any); | ||
1752 | |||
1753 | wl1271_tx_flush(wl); | ||
1754 | |||
1755 | mutex_lock(&wl->mutex); | ||
1756 | wl->wow_enabled = true; | ||
1757 | wl12xx_for_each_wlvif(wl, wlvif) { | ||
1758 | ret = wl1271_configure_suspend(wl, wlvif); | ||
1759 | if (ret < 0) { | ||
1760 | wl1271_warning("couldn't prepare device to suspend"); | ||
1761 | return ret; | ||
1762 | } | ||
1763 | } | ||
1764 | mutex_unlock(&wl->mutex); | ||
1765 | /* flush any remaining work */ | ||
1766 | wl1271_debug(DEBUG_MAC80211, "flushing remaining works"); | ||
1767 | |||
1768 | /* | ||
1769 | * disable and re-enable interrupts in order to flush | ||
1770 | * the threaded_irq | ||
1771 | */ | ||
1772 | wl1271_disable_interrupts(wl); | ||
1773 | |||
1774 | /* | ||
1775 | * set suspended flag to avoid triggering a new threaded_irq | ||
1776 | * work. no need for spinlock as interrupts are disabled. | ||
1777 | */ | ||
1778 | set_bit(WL1271_FLAG_SUSPENDED, &wl->flags); | ||
1779 | |||
1780 | wl1271_enable_interrupts(wl); | ||
1781 | flush_work(&wl->tx_work); | ||
1782 | flush_delayed_work(&wl->elp_work); | ||
1783 | |||
1784 | return 0; | ||
1785 | } | ||
1786 | |||
1787 | static int wl1271_op_resume(struct ieee80211_hw *hw) | ||
1788 | { | ||
1789 | struct wl1271 *wl = hw->priv; | ||
1790 | struct wl12xx_vif *wlvif; | ||
1791 | unsigned long flags; | ||
1792 | bool run_irq_work = false; | ||
1793 | |||
1794 | wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d", | ||
1795 | wl->wow_enabled); | ||
1796 | WARN_ON(!wl->wow_enabled); | ||
1797 | |||
1798 | /* | ||
1799 | * re-enable irq_work enqueuing, and call irq_work directly if | ||
1800 | * there is a pending work. | ||
1801 | */ | ||
1802 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
1803 | clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags); | ||
1804 | if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags)) | ||
1805 | run_irq_work = true; | ||
1806 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
1807 | |||
1808 | if (run_irq_work) { | ||
1809 | wl1271_debug(DEBUG_MAC80211, | ||
1810 | "run postponed irq_work directly"); | ||
1811 | wl1271_irq(0, wl); | ||
1812 | wl1271_enable_interrupts(wl); | ||
1813 | } | ||
1814 | |||
1815 | mutex_lock(&wl->mutex); | ||
1816 | wl12xx_for_each_wlvif(wl, wlvif) { | ||
1817 | wl1271_configure_resume(wl, wlvif); | ||
1818 | } | ||
1819 | wl->wow_enabled = false; | ||
1820 | mutex_unlock(&wl->mutex); | ||
1821 | |||
1822 | return 0; | ||
1823 | } | ||
1824 | #endif | ||
1825 | |||
1826 | static int wl1271_op_start(struct ieee80211_hw *hw) | ||
1827 | { | ||
1828 | wl1271_debug(DEBUG_MAC80211, "mac80211 start"); | ||
1829 | |||
1830 | /* | ||
1831 | * We have to delay the booting of the hardware because | ||
1832 | * we need to know the local MAC address before downloading and | ||
1833 | * initializing the firmware. The MAC address cannot be changed | ||
1834 | * after boot, and without the proper MAC address, the firmware | ||
1835 | * will not function properly. | ||
1836 | * | ||
1837 | * The MAC address is first known when the corresponding interface | ||
1838 | * is added. That is where we will initialize the hardware. | ||
1839 | */ | ||
1840 | |||
1841 | return 0; | ||
1842 | } | ||
1843 | |||
1844 | static void wl1271_op_stop(struct ieee80211_hw *hw) | ||
1845 | { | ||
1846 | struct wl1271 *wl = hw->priv; | ||
1847 | int i; | ||
1848 | |||
1849 | wl1271_debug(DEBUG_MAC80211, "mac80211 stop"); | ||
1850 | |||
1851 | /* | ||
1852 | * Interrupts must be disabled before setting the state to OFF. | ||
1853 | * Otherwise, the interrupt handler might be called and exit without | ||
1854 | * reading the interrupt status. | ||
1855 | */ | ||
1856 | wl1271_disable_interrupts(wl); | ||
1857 | mutex_lock(&wl->mutex); | ||
1858 | if (wl->state == WL1271_STATE_OFF) { | ||
1859 | mutex_unlock(&wl->mutex); | ||
1860 | |||
1861 | /* | ||
1862 | * This will not necessarily enable interrupts as interrupts | ||
1863 | * may have been disabled when op_stop was called. It will, | ||
1864 | * however, balance the above call to disable_interrupts(). | ||
1865 | */ | ||
1866 | wl1271_enable_interrupts(wl); | ||
1867 | return; | ||
1868 | } | ||
1869 | |||
1870 | /* | ||
1871 | * this must be before the cancel_work calls below, so that the work | ||
1872 | * functions don't perform further work. | ||
1873 | */ | ||
1874 | wl->state = WL1271_STATE_OFF; | ||
1875 | mutex_unlock(&wl->mutex); | ||
1876 | |||
1877 | wl1271_flush_deferred_work(wl); | ||
1878 | cancel_delayed_work_sync(&wl->scan_complete_work); | ||
1879 | cancel_work_sync(&wl->netstack_work); | ||
1880 | cancel_work_sync(&wl->tx_work); | ||
1881 | cancel_delayed_work_sync(&wl->elp_work); | ||
1882 | cancel_delayed_work_sync(&wl->tx_watchdog_work); | ||
1883 | |||
1884 | /* let's notify MAC80211 about the remaining pending TX frames */ | ||
1885 | wl12xx_tx_reset(wl, true); | ||
1886 | mutex_lock(&wl->mutex); | ||
1887 | |||
1888 | wl1271_power_off(wl); | ||
1889 | |||
1890 | wl->band = IEEE80211_BAND_2GHZ; | ||
1891 | |||
1892 | wl->rx_counter = 0; | ||
1893 | wl->power_level = WL1271_DEFAULT_POWER_LEVEL; | ||
1894 | wl->tx_blocks_available = 0; | ||
1895 | wl->tx_allocated_blocks = 0; | ||
1896 | wl->tx_results_count = 0; | ||
1897 | wl->tx_packets_count = 0; | ||
1898 | wl->time_offset = 0; | ||
1899 | wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT; | ||
1900 | wl->ap_fw_ps_map = 0; | ||
1901 | wl->ap_ps_map = 0; | ||
1902 | wl->sched_scanning = false; | ||
1903 | memset(wl->roles_map, 0, sizeof(wl->roles_map)); | ||
1904 | memset(wl->links_map, 0, sizeof(wl->links_map)); | ||
1905 | memset(wl->roc_map, 0, sizeof(wl->roc_map)); | ||
1906 | wl->active_sta_count = 0; | ||
1907 | |||
1908 | /* The system link is always allocated */ | ||
1909 | __set_bit(WL12XX_SYSTEM_HLID, wl->links_map); | ||
1910 | |||
1911 | /* | ||
1912 | * this is performed after the cancel_work calls and the associated | ||
1913 | * mutex_lock, so that wl1271_op_add_interface does not accidentally | ||
1914 | * get executed before all these vars have been reset. | ||
1915 | */ | ||
1916 | wl->flags = 0; | ||
1917 | |||
1918 | wl->tx_blocks_freed = 0; | ||
1919 | |||
1920 | for (i = 0; i < NUM_TX_QUEUES; i++) { | ||
1921 | wl->tx_pkts_freed[i] = 0; | ||
1922 | wl->tx_allocated_pkts[i] = 0; | ||
1923 | } | ||
1924 | |||
1925 | wl1271_debugfs_reset(wl); | ||
1926 | |||
1927 | kfree(wl->fw_status); | ||
1928 | wl->fw_status = NULL; | ||
1929 | kfree(wl->tx_res_if); | ||
1930 | wl->tx_res_if = NULL; | ||
1931 | kfree(wl->target_mem_map); | ||
1932 | wl->target_mem_map = NULL; | ||
1933 | |||
1934 | mutex_unlock(&wl->mutex); | ||
1935 | } | ||
1936 | |||
1937 | static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx) | ||
1938 | { | ||
1939 | u8 policy = find_first_zero_bit(wl->rate_policies_map, | ||
1940 | WL12XX_MAX_RATE_POLICIES); | ||
1941 | if (policy >= WL12XX_MAX_RATE_POLICIES) | ||
1942 | return -EBUSY; | ||
1943 | |||
1944 | __set_bit(policy, wl->rate_policies_map); | ||
1945 | *idx = policy; | ||
1946 | return 0; | ||
1947 | } | ||
1948 | |||
1949 | static void wl12xx_free_rate_policy(struct wl1271 *wl, u8 *idx) | ||
1950 | { | ||
1951 | if (WARN_ON(*idx >= WL12XX_MAX_RATE_POLICIES)) | ||
1952 | return; | ||
1953 | |||
1954 | __clear_bit(*idx, wl->rate_policies_map); | ||
1955 | *idx = WL12XX_MAX_RATE_POLICIES; | ||
1956 | } | ||
1957 | |||
1958 | static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif) | ||
1959 | { | ||
1960 | switch (wlvif->bss_type) { | ||
1961 | case BSS_TYPE_AP_BSS: | ||
1962 | if (wlvif->p2p) | ||
1963 | return WL1271_ROLE_P2P_GO; | ||
1964 | else | ||
1965 | return WL1271_ROLE_AP; | ||
1966 | |||
1967 | case BSS_TYPE_STA_BSS: | ||
1968 | if (wlvif->p2p) | ||
1969 | return WL1271_ROLE_P2P_CL; | ||
1970 | else | ||
1971 | return WL1271_ROLE_STA; | ||
1972 | |||
1973 | case BSS_TYPE_IBSS: | ||
1974 | return WL1271_ROLE_IBSS; | ||
1975 | |||
1976 | default: | ||
1977 | wl1271_error("invalid bss_type: %d", wlvif->bss_type); | ||
1978 | } | ||
1979 | return WL12XX_INVALID_ROLE_TYPE; | ||
1980 | } | ||
1981 | |||
1982 | static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif) | ||
1983 | { | ||
1984 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | ||
1985 | int i; | ||
1986 | |||
1987 | /* clear everything but the persistent data */ | ||
1988 | memset(wlvif, 0, offsetof(struct wl12xx_vif, persistent)); | ||
1989 | |||
1990 | switch (ieee80211_vif_type_p2p(vif)) { | ||
1991 | case NL80211_IFTYPE_P2P_CLIENT: | ||
1992 | wlvif->p2p = 1; | ||
1993 | /* fall-through */ | ||
1994 | case NL80211_IFTYPE_STATION: | ||
1995 | wlvif->bss_type = BSS_TYPE_STA_BSS; | ||
1996 | break; | ||
1997 | case NL80211_IFTYPE_ADHOC: | ||
1998 | wlvif->bss_type = BSS_TYPE_IBSS; | ||
1999 | break; | ||
2000 | case NL80211_IFTYPE_P2P_GO: | ||
2001 | wlvif->p2p = 1; | ||
2002 | /* fall-through */ | ||
2003 | case NL80211_IFTYPE_AP: | ||
2004 | wlvif->bss_type = BSS_TYPE_AP_BSS; | ||
2005 | break; | ||
2006 | default: | ||
2007 | wlvif->bss_type = MAX_BSS_TYPE; | ||
2008 | return -EOPNOTSUPP; | ||
2009 | } | ||
2010 | |||
2011 | wlvif->role_id = WL12XX_INVALID_ROLE_ID; | ||
2012 | wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID; | ||
2013 | wlvif->dev_hlid = WL12XX_INVALID_LINK_ID; | ||
2014 | |||
2015 | if (wlvif->bss_type == BSS_TYPE_STA_BSS || | ||
2016 | wlvif->bss_type == BSS_TYPE_IBSS) { | ||
2017 | /* init sta/ibss data */ | ||
2018 | wlvif->sta.hlid = WL12XX_INVALID_LINK_ID; | ||
2019 | wl12xx_allocate_rate_policy(wl, &wlvif->sta.basic_rate_idx); | ||
2020 | wl12xx_allocate_rate_policy(wl, &wlvif->sta.ap_rate_idx); | ||
2021 | wl12xx_allocate_rate_policy(wl, &wlvif->sta.p2p_rate_idx); | ||
2022 | } else { | ||
2023 | /* init ap data */ | ||
2024 | wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID; | ||
2025 | wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID; | ||
2026 | wl12xx_allocate_rate_policy(wl, &wlvif->ap.mgmt_rate_idx); | ||
2027 | wl12xx_allocate_rate_policy(wl, &wlvif->ap.bcast_rate_idx); | ||
2028 | for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++) | ||
2029 | wl12xx_allocate_rate_policy(wl, | ||
2030 | &wlvif->ap.ucast_rate_idx[i]); | ||
2031 | } | ||
2032 | |||
2033 | wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate; | ||
2034 | wlvif->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5; | ||
2035 | wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC; | ||
2036 | wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC; | ||
2037 | wlvif->rate_set = CONF_TX_RATE_MASK_BASIC; | ||
2038 | wlvif->beacon_int = WL1271_DEFAULT_BEACON_INT; | ||
2039 | |||
2040 | /* | ||
2041 | * mac80211 configures some values globally, while we treat them | ||
2042 | * per-interface. thus, on init, we have to copy them from wl | ||
2043 | */ | ||
2044 | wlvif->band = wl->band; | ||
2045 | wlvif->channel = wl->channel; | ||
2046 | wlvif->power_level = wl->power_level; | ||
2047 | |||
2048 | INIT_WORK(&wlvif->rx_streaming_enable_work, | ||
2049 | wl1271_rx_streaming_enable_work); | ||
2050 | INIT_WORK(&wlvif->rx_streaming_disable_work, | ||
2051 | wl1271_rx_streaming_disable_work); | ||
2052 | INIT_LIST_HEAD(&wlvif->list); | ||
2053 | |||
2054 | setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer, | ||
2055 | (unsigned long) wlvif); | ||
2056 | return 0; | ||
2057 | } | ||
2058 | |||
2059 | static bool wl12xx_init_fw(struct wl1271 *wl) | ||
2060 | { | ||
2061 | int retries = WL1271_BOOT_RETRIES; | ||
2062 | bool booted = false; | ||
2063 | struct wiphy *wiphy = wl->hw->wiphy; | ||
2064 | int ret; | ||
2065 | |||
2066 | while (retries) { | ||
2067 | retries--; | ||
2068 | ret = wl12xx_chip_wakeup(wl, false); | ||
2069 | if (ret < 0) | ||
2070 | goto power_off; | ||
2071 | |||
2072 | ret = wl1271_boot(wl); | ||
2073 | if (ret < 0) | ||
2074 | goto power_off; | ||
2075 | |||
2076 | ret = wl1271_hw_init(wl); | ||
2077 | if (ret < 0) | ||
2078 | goto irq_disable; | ||
2079 | |||
2080 | booted = true; | ||
2081 | break; | ||
2082 | |||
2083 | irq_disable: | ||
2084 | mutex_unlock(&wl->mutex); | ||
2085 | /* Unlocking the mutex in the middle of handling is | ||
2086 | inherently unsafe. In this case we deem it safe to do, | ||
2087 | because we need to let any possibly pending IRQ out of | ||
2088 | the system (and while we are WL1271_STATE_OFF the IRQ | ||
2089 | work function will not do anything.) Also, any other | ||
2090 | possible concurrent operations will fail due to the | ||
2091 | current state, hence the wl1271 struct should be safe. */ | ||
2092 | wl1271_disable_interrupts(wl); | ||
2093 | wl1271_flush_deferred_work(wl); | ||
2094 | cancel_work_sync(&wl->netstack_work); | ||
2095 | mutex_lock(&wl->mutex); | ||
2096 | power_off: | ||
2097 | wl1271_power_off(wl); | ||
2098 | } | ||
2099 | |||
2100 | if (!booted) { | ||
2101 | wl1271_error("firmware boot failed despite %d retries", | ||
2102 | WL1271_BOOT_RETRIES); | ||
2103 | goto out; | ||
2104 | } | ||
2105 | |||
2106 | wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str); | ||
2107 | |||
2108 | /* update hw/fw version info in wiphy struct */ | ||
2109 | wiphy->hw_version = wl->chip.id; | ||
2110 | strncpy(wiphy->fw_version, wl->chip.fw_ver_str, | ||
2111 | sizeof(wiphy->fw_version)); | ||
2112 | |||
2113 | /* | ||
2114 | * Now we know if 11a is supported (info from the NVS), so disable | ||
2115 | * 11a channels if not supported | ||
2116 | */ | ||
2117 | if (!wl->enable_11a) | ||
2118 | wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0; | ||
2119 | |||
2120 | wl1271_debug(DEBUG_MAC80211, "11a is %ssupported", | ||
2121 | wl->enable_11a ? "" : "not "); | ||
2122 | |||
2123 | wl->state = WL1271_STATE_ON; | ||
2124 | out: | ||
2125 | return booted; | ||
2126 | } | ||
2127 | |||
2128 | static bool wl12xx_dev_role_started(struct wl12xx_vif *wlvif) | ||
2129 | { | ||
2130 | return wlvif->dev_hlid != WL12XX_INVALID_LINK_ID; | ||
2131 | } | ||
2132 | |||
2133 | /* | ||
2134 | * Check whether a fw switch (i.e. moving from one loaded | ||
2135 | * fw to another) is needed. This function is also responsible | ||
2136 | * for updating wl->last_vif_count, so it must be called before | ||
2137 | * loading a non-plt fw (so the correct fw (single-role/multi-role) | ||
2138 | * will be used). | ||
2139 | */ | ||
2140 | static bool wl12xx_need_fw_change(struct wl1271 *wl, | ||
2141 | struct vif_counter_data vif_counter_data, | ||
2142 | bool add) | ||
2143 | { | ||
2144 | enum wl12xx_fw_type current_fw = wl->fw_type; | ||
2145 | u8 vif_count = vif_counter_data.counter; | ||
2146 | |||
2147 | if (test_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags)) | ||
2148 | return false; | ||
2149 | |||
2150 | /* increase the vif count if this is a new vif */ | ||
2151 | if (add && !vif_counter_data.cur_vif_running) | ||
2152 | vif_count++; | ||
2153 | |||
2154 | wl->last_vif_count = vif_count; | ||
2155 | |||
2156 | /* no need for fw change if the device is OFF */ | ||
2157 | if (wl->state == WL1271_STATE_OFF) | ||
2158 | return false; | ||
2159 | |||
2160 | if (vif_count > 1 && current_fw == WL12XX_FW_TYPE_NORMAL) | ||
2161 | return true; | ||
2162 | if (vif_count <= 1 && current_fw == WL12XX_FW_TYPE_MULTI) | ||
2163 | return true; | ||
2164 | |||
2165 | return false; | ||
2166 | } | ||
2167 | |||
2168 | /* | ||
2169 | * Enter "forced psm". Make sure the sta is in psm against the ap, | ||
2170 | * to make the fw switch a bit more disconnection-persistent. | ||
2171 | */ | ||
2172 | static void wl12xx_force_active_psm(struct wl1271 *wl) | ||
2173 | { | ||
2174 | struct wl12xx_vif *wlvif; | ||
2175 | |||
2176 | wl12xx_for_each_wlvif_sta(wl, wlvif) { | ||
2177 | wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE); | ||
2178 | } | ||
2179 | } | ||
2180 | |||
2181 | static int wl1271_op_add_interface(struct ieee80211_hw *hw, | ||
2182 | struct ieee80211_vif *vif) | ||
2183 | { | ||
2184 | struct wl1271 *wl = hw->priv; | ||
2185 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | ||
2186 | struct vif_counter_data vif_count; | ||
2187 | int ret = 0; | ||
2188 | u8 role_type; | ||
2189 | bool booted = false; | ||
2190 | |||
2191 | vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | | ||
2192 | IEEE80211_VIF_SUPPORTS_CQM_RSSI; | ||
2193 | |||
2194 | wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", | ||
2195 | ieee80211_vif_type_p2p(vif), vif->addr); | ||
2196 | |||
2197 | wl12xx_get_vif_count(hw, vif, &vif_count); | ||
2198 | |||
2199 | mutex_lock(&wl->mutex); | ||
2200 | ret = wl1271_ps_elp_wakeup(wl); | ||
2201 | if (ret < 0) | ||
2202 | goto out_unlock; | ||
2203 | |||
2204 | /* | ||
2205 | * in some very corner case HW recovery scenarios its possible to | ||
2206 | * get here before __wl1271_op_remove_interface is complete, so | ||
2207 | * opt out if that is the case. | ||
2208 | */ | ||
2209 | if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags) || | ||
2210 | test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) { | ||
2211 | ret = -EBUSY; | ||
2212 | goto out; | ||
2213 | } | ||
2214 | |||
2215 | |||
2216 | ret = wl12xx_init_vif_data(wl, vif); | ||
2217 | if (ret < 0) | ||
2218 | goto out; | ||
2219 | |||
2220 | wlvif->wl = wl; | ||
2221 | role_type = wl12xx_get_role_type(wl, wlvif); | ||
2222 | if (role_type == WL12XX_INVALID_ROLE_TYPE) { | ||
2223 | ret = -EINVAL; | ||
2224 | goto out; | ||
2225 | } | ||
2226 | |||
2227 | if (wl12xx_need_fw_change(wl, vif_count, true)) { | ||
2228 | wl12xx_force_active_psm(wl); | ||
2229 | set_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags); | ||
2230 | mutex_unlock(&wl->mutex); | ||
2231 | wl1271_recovery_work(&wl->recovery_work); | ||
2232 | return 0; | ||
2233 | } | ||
2234 | |||
2235 | /* | ||
2236 | * TODO: after the nvs issue will be solved, move this block | ||
2237 | * to start(), and make sure here the driver is ON. | ||
2238 | */ | ||
2239 | if (wl->state == WL1271_STATE_OFF) { | ||
2240 | /* | ||
2241 | * we still need this in order to configure the fw | ||
2242 | * while uploading the nvs | ||
2243 | */ | ||
2244 | memcpy(wl->addresses[0].addr, vif->addr, ETH_ALEN); | ||
2245 | |||
2246 | booted = wl12xx_init_fw(wl); | ||
2247 | if (!booted) { | ||
2248 | ret = -EINVAL; | ||
2249 | goto out; | ||
2250 | } | ||
2251 | } | ||
2252 | |||
2253 | if (wlvif->bss_type == BSS_TYPE_STA_BSS || | ||
2254 | wlvif->bss_type == BSS_TYPE_IBSS) { | ||
2255 | /* | ||
2256 | * The device role is a special role used for | ||
2257 | * rx and tx frames prior to association (as | ||
2258 | * the STA role can get packets only from | ||
2259 | * its associated bssid) | ||
2260 | */ | ||
2261 | ret = wl12xx_cmd_role_enable(wl, vif->addr, | ||
2262 | WL1271_ROLE_DEVICE, | ||
2263 | &wlvif->dev_role_id); | ||
2264 | if (ret < 0) | ||
2265 | goto out; | ||
2266 | } | ||
2267 | |||
2268 | ret = wl12xx_cmd_role_enable(wl, vif->addr, | ||
2269 | role_type, &wlvif->role_id); | ||
2270 | if (ret < 0) | ||
2271 | goto out; | ||
2272 | |||
2273 | ret = wl1271_init_vif_specific(wl, vif); | ||
2274 | if (ret < 0) | ||
2275 | goto out; | ||
2276 | |||
2277 | list_add(&wlvif->list, &wl->wlvif_list); | ||
2278 | set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags); | ||
2279 | |||
2280 | if (wlvif->bss_type == BSS_TYPE_AP_BSS) | ||
2281 | wl->ap_count++; | ||
2282 | else | ||
2283 | wl->sta_count++; | ||
2284 | out: | ||
2285 | wl1271_ps_elp_sleep(wl); | ||
2286 | out_unlock: | ||
2287 | mutex_unlock(&wl->mutex); | ||
2288 | |||
2289 | return ret; | ||
2290 | } | ||
2291 | |||
2292 | static void __wl1271_op_remove_interface(struct wl1271 *wl, | ||
2293 | struct ieee80211_vif *vif, | ||
2294 | bool reset_tx_queues) | ||
2295 | { | ||
2296 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | ||
2297 | int i, ret; | ||
2298 | |||
2299 | wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface"); | ||
2300 | |||
2301 | if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) | ||
2302 | return; | ||
2303 | |||
2304 | /* because of hardware recovery, we may get here twice */ | ||
2305 | if (wl->state != WL1271_STATE_ON) | ||
2306 | return; | ||
2307 | |||
2308 | wl1271_info("down"); | ||
2309 | |||
2310 | if (wl->scan.state != WL1271_SCAN_STATE_IDLE && | ||
2311 | wl->scan_vif == vif) { | ||
2312 | /* | ||
2313 | * Rearm the tx watchdog just before idling scan. This | ||
2314 | * prevents just-finished scans from triggering the watchdog | ||
2315 | */ | ||
2316 | wl12xx_rearm_tx_watchdog_locked(wl); | ||
2317 | |||
2318 | wl->scan.state = WL1271_SCAN_STATE_IDLE; | ||
2319 | memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); | ||
2320 | wl->scan_vif = NULL; | ||
2321 | wl->scan.req = NULL; | ||
2322 | ieee80211_scan_completed(wl->hw, true); | ||
2323 | } | ||
2324 | |||
2325 | if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) { | ||
2326 | /* disable active roles */ | ||
2327 | ret = wl1271_ps_elp_wakeup(wl); | ||
2328 | if (ret < 0) | ||
2329 | goto deinit; | ||
2330 | |||
2331 | if (wlvif->bss_type == BSS_TYPE_STA_BSS || | ||
2332 | wlvif->bss_type == BSS_TYPE_IBSS) { | ||
2333 | if (wl12xx_dev_role_started(wlvif)) | ||
2334 | wl12xx_stop_dev(wl, wlvif); | ||
2335 | |||
2336 | ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id); | ||
2337 | if (ret < 0) | ||
2338 | goto deinit; | ||
2339 | } | ||
2340 | |||
2341 | ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id); | ||
2342 | if (ret < 0) | ||
2343 | goto deinit; | ||
2344 | |||
2345 | wl1271_ps_elp_sleep(wl); | ||
2346 | } | ||
2347 | deinit: | ||
2348 | /* clear all hlids (except system_hlid) */ | ||
2349 | wlvif->dev_hlid = WL12XX_INVALID_LINK_ID; | ||
2350 | |||
2351 | if (wlvif->bss_type == BSS_TYPE_STA_BSS || | ||
2352 | wlvif->bss_type == BSS_TYPE_IBSS) { | ||
2353 | wlvif->sta.hlid = WL12XX_INVALID_LINK_ID; | ||
2354 | wl12xx_free_rate_policy(wl, &wlvif->sta.basic_rate_idx); | ||
2355 | wl12xx_free_rate_policy(wl, &wlvif->sta.ap_rate_idx); | ||
2356 | wl12xx_free_rate_policy(wl, &wlvif->sta.p2p_rate_idx); | ||
2357 | } else { | ||
2358 | wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID; | ||
2359 | wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID; | ||
2360 | wl12xx_free_rate_policy(wl, &wlvif->ap.mgmt_rate_idx); | ||
2361 | wl12xx_free_rate_policy(wl, &wlvif->ap.bcast_rate_idx); | ||
2362 | for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++) | ||
2363 | wl12xx_free_rate_policy(wl, | ||
2364 | &wlvif->ap.ucast_rate_idx[i]); | ||
2365 | wl1271_free_ap_keys(wl, wlvif); | ||
2366 | } | ||
2367 | |||
2368 | dev_kfree_skb(wlvif->probereq); | ||
2369 | wlvif->probereq = NULL; | ||
2370 | wl12xx_tx_reset_wlvif(wl, wlvif); | ||
2371 | if (wl->last_wlvif == wlvif) | ||
2372 | wl->last_wlvif = NULL; | ||
2373 | list_del(&wlvif->list); | ||
2374 | memset(wlvif->ap.sta_hlid_map, 0, sizeof(wlvif->ap.sta_hlid_map)); | ||
2375 | wlvif->role_id = WL12XX_INVALID_ROLE_ID; | ||
2376 | wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID; | ||
2377 | |||
2378 | if (wlvif->bss_type == BSS_TYPE_AP_BSS) | ||
2379 | wl->ap_count--; | ||
2380 | else | ||
2381 | wl->sta_count--; | ||
2382 | |||
2383 | mutex_unlock(&wl->mutex); | ||
2384 | |||
2385 | del_timer_sync(&wlvif->rx_streaming_timer); | ||
2386 | cancel_work_sync(&wlvif->rx_streaming_enable_work); | ||
2387 | cancel_work_sync(&wlvif->rx_streaming_disable_work); | ||
2388 | |||
2389 | mutex_lock(&wl->mutex); | ||
2390 | } | ||
2391 | |||
2392 | static void wl1271_op_remove_interface(struct ieee80211_hw *hw, | ||
2393 | struct ieee80211_vif *vif) | ||
2394 | { | ||
2395 | struct wl1271 *wl = hw->priv; | ||
2396 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | ||
2397 | struct wl12xx_vif *iter; | ||
2398 | struct vif_counter_data vif_count; | ||
2399 | bool cancel_recovery = true; | ||
2400 | |||
2401 | wl12xx_get_vif_count(hw, vif, &vif_count); | ||
2402 | mutex_lock(&wl->mutex); | ||
2403 | |||
2404 | if (wl->state == WL1271_STATE_OFF || | ||
2405 | !test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) | ||
2406 | goto out; | ||
2407 | |||
2408 | /* | ||
2409 | * wl->vif can be null here if someone shuts down the interface | ||
2410 | * just when hardware recovery has been started. | ||
2411 | */ | ||
2412 | wl12xx_for_each_wlvif(wl, iter) { | ||
2413 | if (iter != wlvif) | ||
2414 | continue; | ||
2415 | |||
2416 | __wl1271_op_remove_interface(wl, vif, true); | ||
2417 | break; | ||
2418 | } | ||
2419 | WARN_ON(iter != wlvif); | ||
2420 | if (wl12xx_need_fw_change(wl, vif_count, false)) { | ||
2421 | wl12xx_force_active_psm(wl); | ||
2422 | set_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags); | ||
2423 | wl12xx_queue_recovery_work(wl); | ||
2424 | cancel_recovery = false; | ||
2425 | } | ||
2426 | out: | ||
2427 | mutex_unlock(&wl->mutex); | ||
2428 | if (cancel_recovery) | ||
2429 | cancel_work_sync(&wl->recovery_work); | ||
2430 | } | ||
2431 | |||
2432 | static int wl12xx_op_change_interface(struct ieee80211_hw *hw, | ||
2433 | struct ieee80211_vif *vif, | ||
2434 | enum nl80211_iftype new_type, bool p2p) | ||
2435 | { | ||
2436 | struct wl1271 *wl = hw->priv; | ||
2437 | int ret; | ||
2438 | |||
2439 | set_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags); | ||
2440 | wl1271_op_remove_interface(hw, vif); | ||
2441 | |||
2442 | vif->type = new_type; | ||
2443 | vif->p2p = p2p; | ||
2444 | ret = wl1271_op_add_interface(hw, vif); | ||
2445 | |||
2446 | clear_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags); | ||
2447 | return ret; | ||
2448 | } | ||
2449 | |||
2450 | static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
2451 | bool set_assoc) | ||
2452 | { | ||
2453 | int ret; | ||
2454 | bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS); | ||
2455 | |||
2456 | /* | ||
2457 | * One of the side effects of the JOIN command is that is clears | ||
2458 | * WPA/WPA2 keys from the chipset. Performing a JOIN while associated | ||
2459 | * to a WPA/WPA2 access point will therefore kill the data-path. | ||
2460 | * Currently the only valid scenario for JOIN during association | ||
2461 | * is on roaming, in which case we will also be given new keys. | ||
2462 | * Keep the below message for now, unless it starts bothering | ||
2463 | * users who really like to roam a lot :) | ||
2464 | */ | ||
2465 | if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) | ||
2466 | wl1271_info("JOIN while associated."); | ||
2467 | |||
2468 | /* clear encryption type */ | ||
2469 | wlvif->encryption_type = KEY_NONE; | ||
2470 | |||
2471 | if (set_assoc) | ||
2472 | set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags); | ||
2473 | |||
2474 | if (is_ibss) | ||
2475 | ret = wl12xx_cmd_role_start_ibss(wl, wlvif); | ||
2476 | else | ||
2477 | ret = wl12xx_cmd_role_start_sta(wl, wlvif); | ||
2478 | if (ret < 0) | ||
2479 | goto out; | ||
2480 | |||
2481 | if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) | ||
2482 | goto out; | ||
2483 | |||
2484 | /* | ||
2485 | * The join command disable the keep-alive mode, shut down its process, | ||
2486 | * and also clear the template config, so we need to reset it all after | ||
2487 | * the join. The acx_aid starts the keep-alive process, and the order | ||
2488 | * of the commands below is relevant. | ||
2489 | */ | ||
2490 | ret = wl1271_acx_keep_alive_mode(wl, wlvif, true); | ||
2491 | if (ret < 0) | ||
2492 | goto out; | ||
2493 | |||
2494 | ret = wl1271_acx_aid(wl, wlvif, wlvif->aid); | ||
2495 | if (ret < 0) | ||
2496 | goto out; | ||
2497 | |||
2498 | ret = wl12xx_cmd_build_klv_null_data(wl, wlvif); | ||
2499 | if (ret < 0) | ||
2500 | goto out; | ||
2501 | |||
2502 | ret = wl1271_acx_keep_alive_config(wl, wlvif, | ||
2503 | CMD_TEMPL_KLV_IDX_NULL_DATA, | ||
2504 | ACX_KEEP_ALIVE_TPL_VALID); | ||
2505 | if (ret < 0) | ||
2506 | goto out; | ||
2507 | |||
2508 | out: | ||
2509 | return ret; | ||
2510 | } | ||
2511 | |||
2512 | static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif) | ||
2513 | { | ||
2514 | int ret; | ||
2515 | |||
2516 | if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) { | ||
2517 | struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); | ||
2518 | |||
2519 | wl12xx_cmd_stop_channel_switch(wl); | ||
2520 | ieee80211_chswitch_done(vif, false); | ||
2521 | } | ||
2522 | |||
2523 | /* to stop listening to a channel, we disconnect */ | ||
2524 | ret = wl12xx_cmd_role_stop_sta(wl, wlvif); | ||
2525 | if (ret < 0) | ||
2526 | goto out; | ||
2527 | |||
2528 | /* reset TX security counters on a clean disconnect */ | ||
2529 | wlvif->tx_security_last_seq_lsb = 0; | ||
2530 | wlvif->tx_security_seq = 0; | ||
2531 | |||
2532 | out: | ||
2533 | return ret; | ||
2534 | } | ||
2535 | |||
2536 | static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif) | ||
2537 | { | ||
2538 | wlvif->basic_rate_set = wlvif->bitrate_masks[wlvif->band]; | ||
2539 | wlvif->rate_set = wlvif->basic_rate_set; | ||
2540 | } | ||
2541 | |||
2542 | static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
2543 | bool idle) | ||
2544 | { | ||
2545 | int ret; | ||
2546 | bool cur_idle = !test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags); | ||
2547 | |||
2548 | if (idle == cur_idle) | ||
2549 | return 0; | ||
2550 | |||
2551 | if (idle) { | ||
2552 | /* no need to croc if we weren't busy (e.g. during boot) */ | ||
2553 | if (wl12xx_dev_role_started(wlvif)) { | ||
2554 | ret = wl12xx_stop_dev(wl, wlvif); | ||
2555 | if (ret < 0) | ||
2556 | goto out; | ||
2557 | } | ||
2558 | wlvif->rate_set = | ||
2559 | wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); | ||
2560 | ret = wl1271_acx_sta_rate_policies(wl, wlvif); | ||
2561 | if (ret < 0) | ||
2562 | goto out; | ||
2563 | ret = wl1271_acx_keep_alive_config( | ||
2564 | wl, wlvif, CMD_TEMPL_KLV_IDX_NULL_DATA, | ||
2565 | ACX_KEEP_ALIVE_TPL_INVALID); | ||
2566 | if (ret < 0) | ||
2567 | goto out; | ||
2568 | clear_bit(WLVIF_FLAG_IN_USE, &wlvif->flags); | ||
2569 | } else { | ||
2570 | /* The current firmware only supports sched_scan in idle */ | ||
2571 | if (wl->sched_scanning) { | ||
2572 | wl1271_scan_sched_scan_stop(wl); | ||
2573 | ieee80211_sched_scan_stopped(wl->hw); | ||
2574 | } | ||
2575 | |||
2576 | ret = wl12xx_start_dev(wl, wlvif); | ||
2577 | if (ret < 0) | ||
2578 | goto out; | ||
2579 | set_bit(WLVIF_FLAG_IN_USE, &wlvif->flags); | ||
2580 | } | ||
2581 | |||
2582 | out: | ||
2583 | return ret; | ||
2584 | } | ||
2585 | |||
2586 | static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
2587 | struct ieee80211_conf *conf, u32 changed) | ||
2588 | { | ||
2589 | bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); | ||
2590 | int channel, ret; | ||
2591 | |||
2592 | channel = ieee80211_frequency_to_channel(conf->channel->center_freq); | ||
2593 | |||
2594 | /* if the channel changes while joined, join again */ | ||
2595 | if (changed & IEEE80211_CONF_CHANGE_CHANNEL && | ||
2596 | ((wlvif->band != conf->channel->band) || | ||
2597 | (wlvif->channel != channel))) { | ||
2598 | /* send all pending packets */ | ||
2599 | wl1271_tx_work_locked(wl); | ||
2600 | wlvif->band = conf->channel->band; | ||
2601 | wlvif->channel = channel; | ||
2602 | |||
2603 | if (!is_ap) { | ||
2604 | /* | ||
2605 | * FIXME: the mac80211 should really provide a fixed | ||
2606 | * rate to use here. for now, just use the smallest | ||
2607 | * possible rate for the band as a fixed rate for | ||
2608 | * association frames and other control messages. | ||
2609 | */ | ||
2610 | if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) | ||
2611 | wl1271_set_band_rate(wl, wlvif); | ||
2612 | |||
2613 | wlvif->basic_rate = | ||
2614 | wl1271_tx_min_rate_get(wl, | ||
2615 | wlvif->basic_rate_set); | ||
2616 | ret = wl1271_acx_sta_rate_policies(wl, wlvif); | ||
2617 | if (ret < 0) | ||
2618 | wl1271_warning("rate policy for channel " | ||
2619 | "failed %d", ret); | ||
2620 | |||
2621 | /* | ||
2622 | * change the ROC channel. do it only if we are | ||
2623 | * not idle. otherwise, CROC will be called | ||
2624 | * anyway. | ||
2625 | */ | ||
2626 | if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, | ||
2627 | &wlvif->flags) && | ||
2628 | wl12xx_dev_role_started(wlvif) && | ||
2629 | !(conf->flags & IEEE80211_CONF_IDLE)) { | ||
2630 | ret = wl12xx_stop_dev(wl, wlvif); | ||
2631 | if (ret < 0) | ||
2632 | return ret; | ||
2633 | |||
2634 | ret = wl12xx_start_dev(wl, wlvif); | ||
2635 | if (ret < 0) | ||
2636 | return ret; | ||
2637 | } | ||
2638 | } | ||
2639 | } | ||
2640 | |||
2641 | if ((changed & IEEE80211_CONF_CHANGE_PS) && !is_ap) { | ||
2642 | |||
2643 | if ((conf->flags & IEEE80211_CONF_PS) && | ||
2644 | test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) && | ||
2645 | !test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) { | ||
2646 | |||
2647 | int ps_mode; | ||
2648 | char *ps_mode_str; | ||
2649 | |||
2650 | if (wl->conf.conn.forced_ps) { | ||
2651 | ps_mode = STATION_POWER_SAVE_MODE; | ||
2652 | ps_mode_str = "forced"; | ||
2653 | } else { | ||
2654 | ps_mode = STATION_AUTO_PS_MODE; | ||
2655 | ps_mode_str = "auto"; | ||
2656 | } | ||
2657 | |||
2658 | wl1271_debug(DEBUG_PSM, "%s ps enabled", ps_mode_str); | ||
2659 | |||
2660 | ret = wl1271_ps_set_mode(wl, wlvif, ps_mode); | ||
2661 | |||
2662 | if (ret < 0) | ||
2663 | wl1271_warning("enter %s ps failed %d", | ||
2664 | ps_mode_str, ret); | ||
2665 | |||
2666 | } else if (!(conf->flags & IEEE80211_CONF_PS) && | ||
2667 | test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) { | ||
2668 | |||
2669 | wl1271_debug(DEBUG_PSM, "auto ps disabled"); | ||
2670 | |||
2671 | ret = wl1271_ps_set_mode(wl, wlvif, | ||
2672 | STATION_ACTIVE_MODE); | ||
2673 | if (ret < 0) | ||
2674 | wl1271_warning("exit auto ps failed %d", ret); | ||
2675 | } | ||
2676 | } | ||
2677 | |||
2678 | if (conf->power_level != wlvif->power_level) { | ||
2679 | ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level); | ||
2680 | if (ret < 0) | ||
2681 | return ret; | ||
2682 | |||
2683 | wlvif->power_level = conf->power_level; | ||
2684 | } | ||
2685 | |||
2686 | return 0; | ||
2687 | } | ||
2688 | |||
2689 | static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) | ||
2690 | { | ||
2691 | struct wl1271 *wl = hw->priv; | ||
2692 | struct wl12xx_vif *wlvif; | ||
2693 | struct ieee80211_conf *conf = &hw->conf; | ||
2694 | int channel, ret = 0; | ||
2695 | |||
2696 | channel = ieee80211_frequency_to_channel(conf->channel->center_freq); | ||
2697 | |||
2698 | wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s" | ||
2699 | " changed 0x%x", | ||
2700 | channel, | ||
2701 | conf->flags & IEEE80211_CONF_PS ? "on" : "off", | ||
2702 | conf->power_level, | ||
2703 | conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use", | ||
2704 | changed); | ||
2705 | |||
2706 | /* | ||
2707 | * mac80211 will go to idle nearly immediately after transmitting some | ||
2708 | * frames, such as the deauth. To make sure those frames reach the air, | ||
2709 | * wait here until the TX queue is fully flushed. | ||
2710 | */ | ||
2711 | if ((changed & IEEE80211_CONF_CHANGE_IDLE) && | ||
2712 | (conf->flags & IEEE80211_CONF_IDLE)) | ||
2713 | wl1271_tx_flush(wl); | ||
2714 | |||
2715 | mutex_lock(&wl->mutex); | ||
2716 | |||
2717 | /* we support configuring the channel and band even while off */ | ||
2718 | if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { | ||
2719 | wl->band = conf->channel->band; | ||
2720 | wl->channel = channel; | ||
2721 | } | ||
2722 | |||
2723 | if (changed & IEEE80211_CONF_CHANGE_POWER) | ||
2724 | wl->power_level = conf->power_level; | ||
2725 | |||
2726 | if (unlikely(wl->state == WL1271_STATE_OFF)) | ||
2727 | goto out; | ||
2728 | |||
2729 | ret = wl1271_ps_elp_wakeup(wl); | ||
2730 | if (ret < 0) | ||
2731 | goto out; | ||
2732 | |||
2733 | /* configure each interface */ | ||
2734 | wl12xx_for_each_wlvif(wl, wlvif) { | ||
2735 | ret = wl12xx_config_vif(wl, wlvif, conf, changed); | ||
2736 | if (ret < 0) | ||
2737 | goto out_sleep; | ||
2738 | } | ||
2739 | |||
2740 | out_sleep: | ||
2741 | wl1271_ps_elp_sleep(wl); | ||
2742 | |||
2743 | out: | ||
2744 | mutex_unlock(&wl->mutex); | ||
2745 | |||
2746 | return ret; | ||
2747 | } | ||
2748 | |||
2749 | struct wl1271_filter_params { | ||
2750 | bool enabled; | ||
2751 | int mc_list_length; | ||
2752 | u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN]; | ||
2753 | }; | ||
2754 | |||
2755 | static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, | ||
2756 | struct netdev_hw_addr_list *mc_list) | ||
2757 | { | ||
2758 | struct wl1271_filter_params *fp; | ||
2759 | struct netdev_hw_addr *ha; | ||
2760 | struct wl1271 *wl = hw->priv; | ||
2761 | |||
2762 | if (unlikely(wl->state == WL1271_STATE_OFF)) | ||
2763 | return 0; | ||
2764 | |||
2765 | fp = kzalloc(sizeof(*fp), GFP_ATOMIC); | ||
2766 | if (!fp) { | ||
2767 | wl1271_error("Out of memory setting filters."); | ||
2768 | return 0; | ||
2769 | } | ||
2770 | |||
2771 | /* update multicast filtering parameters */ | ||
2772 | fp->mc_list_length = 0; | ||
2773 | if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) { | ||
2774 | fp->enabled = false; | ||
2775 | } else { | ||
2776 | fp->enabled = true; | ||
2777 | netdev_hw_addr_list_for_each(ha, mc_list) { | ||
2778 | memcpy(fp->mc_list[fp->mc_list_length], | ||
2779 | ha->addr, ETH_ALEN); | ||
2780 | fp->mc_list_length++; | ||
2781 | } | ||
2782 | } | ||
2783 | |||
2784 | return (u64)(unsigned long)fp; | ||
2785 | } | ||
2786 | |||
2787 | #define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \ | ||
2788 | FIF_ALLMULTI | \ | ||
2789 | FIF_FCSFAIL | \ | ||
2790 | FIF_BCN_PRBRESP_PROMISC | \ | ||
2791 | FIF_CONTROL | \ | ||
2792 | FIF_OTHER_BSS) | ||
2793 | |||
2794 | static void wl1271_op_configure_filter(struct ieee80211_hw *hw, | ||
2795 | unsigned int changed, | ||
2796 | unsigned int *total, u64 multicast) | ||
2797 | { | ||
2798 | struct wl1271_filter_params *fp = (void *)(unsigned long)multicast; | ||
2799 | struct wl1271 *wl = hw->priv; | ||
2800 | struct wl12xx_vif *wlvif; | ||
2801 | |||
2802 | int ret; | ||
2803 | |||
2804 | wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x" | ||
2805 | " total %x", changed, *total); | ||
2806 | |||
2807 | mutex_lock(&wl->mutex); | ||
2808 | |||
2809 | *total &= WL1271_SUPPORTED_FILTERS; | ||
2810 | changed &= WL1271_SUPPORTED_FILTERS; | ||
2811 | |||
2812 | if (unlikely(wl->state == WL1271_STATE_OFF)) | ||
2813 | goto out; | ||
2814 | |||
2815 | ret = wl1271_ps_elp_wakeup(wl); | ||
2816 | if (ret < 0) | ||
2817 | goto out; | ||
2818 | |||
2819 | wl12xx_for_each_wlvif(wl, wlvif) { | ||
2820 | if (wlvif->bss_type != BSS_TYPE_AP_BSS) { | ||
2821 | if (*total & FIF_ALLMULTI) | ||
2822 | ret = wl1271_acx_group_address_tbl(wl, wlvif, | ||
2823 | false, | ||
2824 | NULL, 0); | ||
2825 | else if (fp) | ||
2826 | ret = wl1271_acx_group_address_tbl(wl, wlvif, | ||
2827 | fp->enabled, | ||
2828 | fp->mc_list, | ||
2829 | fp->mc_list_length); | ||
2830 | if (ret < 0) | ||
2831 | goto out_sleep; | ||
2832 | } | ||
2833 | } | ||
2834 | |||
2835 | /* | ||
2836 | * the fw doesn't provide an api to configure the filters. instead, | ||
2837 | * the filters configuration is based on the active roles / ROC | ||
2838 | * state. | ||
2839 | */ | ||
2840 | |||
2841 | out_sleep: | ||
2842 | wl1271_ps_elp_sleep(wl); | ||
2843 | |||
2844 | out: | ||
2845 | mutex_unlock(&wl->mutex); | ||
2846 | kfree(fp); | ||
2847 | } | ||
2848 | |||
2849 | static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
2850 | u8 id, u8 key_type, u8 key_size, | ||
2851 | const u8 *key, u8 hlid, u32 tx_seq_32, | ||
2852 | u16 tx_seq_16) | ||
2853 | { | ||
2854 | struct wl1271_ap_key *ap_key; | ||
2855 | int i; | ||
2856 | |||
2857 | wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id); | ||
2858 | |||
2859 | if (key_size > MAX_KEY_SIZE) | ||
2860 | return -EINVAL; | ||
2861 | |||
2862 | /* | ||
2863 | * Find next free entry in ap_keys. Also check we are not replacing | ||
2864 | * an existing key. | ||
2865 | */ | ||
2866 | for (i = 0; i < MAX_NUM_KEYS; i++) { | ||
2867 | if (wlvif->ap.recorded_keys[i] == NULL) | ||
2868 | break; | ||
2869 | |||
2870 | if (wlvif->ap.recorded_keys[i]->id == id) { | ||
2871 | wl1271_warning("trying to record key replacement"); | ||
2872 | return -EINVAL; | ||
2873 | } | ||
2874 | } | ||
2875 | |||
2876 | if (i == MAX_NUM_KEYS) | ||
2877 | return -EBUSY; | ||
2878 | |||
2879 | ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL); | ||
2880 | if (!ap_key) | ||
2881 | return -ENOMEM; | ||
2882 | |||
2883 | ap_key->id = id; | ||
2884 | ap_key->key_type = key_type; | ||
2885 | ap_key->key_size = key_size; | ||
2886 | memcpy(ap_key->key, key, key_size); | ||
2887 | ap_key->hlid = hlid; | ||
2888 | ap_key->tx_seq_32 = tx_seq_32; | ||
2889 | ap_key->tx_seq_16 = tx_seq_16; | ||
2890 | |||
2891 | wlvif->ap.recorded_keys[i] = ap_key; | ||
2892 | return 0; | ||
2893 | } | ||
2894 | |||
2895 | static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif) | ||
2896 | { | ||
2897 | int i; | ||
2898 | |||
2899 | for (i = 0; i < MAX_NUM_KEYS; i++) { | ||
2900 | kfree(wlvif->ap.recorded_keys[i]); | ||
2901 | wlvif->ap.recorded_keys[i] = NULL; | ||
2902 | } | ||
2903 | } | ||
2904 | |||
2905 | static int wl1271_ap_init_hwenc(struct wl1271 *wl, struct wl12xx_vif *wlvif) | ||
2906 | { | ||
2907 | int i, ret = 0; | ||
2908 | struct wl1271_ap_key *key; | ||
2909 | bool wep_key_added = false; | ||
2910 | |||
2911 | for (i = 0; i < MAX_NUM_KEYS; i++) { | ||
2912 | u8 hlid; | ||
2913 | if (wlvif->ap.recorded_keys[i] == NULL) | ||
2914 | break; | ||
2915 | |||
2916 | key = wlvif->ap.recorded_keys[i]; | ||
2917 | hlid = key->hlid; | ||
2918 | if (hlid == WL12XX_INVALID_LINK_ID) | ||
2919 | hlid = wlvif->ap.bcast_hlid; | ||
2920 | |||
2921 | ret = wl1271_cmd_set_ap_key(wl, wlvif, KEY_ADD_OR_REPLACE, | ||
2922 | key->id, key->key_type, | ||
2923 | key->key_size, key->key, | ||
2924 | hlid, key->tx_seq_32, | ||
2925 | key->tx_seq_16); | ||
2926 | if (ret < 0) | ||
2927 | goto out; | ||
2928 | |||
2929 | if (key->key_type == KEY_WEP) | ||
2930 | wep_key_added = true; | ||
2931 | } | ||
2932 | |||
2933 | if (wep_key_added) { | ||
2934 | ret = wl12xx_cmd_set_default_wep_key(wl, wlvif->default_key, | ||
2935 | wlvif->ap.bcast_hlid); | ||
2936 | if (ret < 0) | ||
2937 | goto out; | ||
2938 | } | ||
2939 | |||
2940 | out: | ||
2941 | wl1271_free_ap_keys(wl, wlvif); | ||
2942 | return ret; | ||
2943 | } | ||
2944 | |||
2945 | static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
2946 | u16 action, u8 id, u8 key_type, | ||
2947 | u8 key_size, const u8 *key, u32 tx_seq_32, | ||
2948 | u16 tx_seq_16, struct ieee80211_sta *sta) | ||
2949 | { | ||
2950 | int ret; | ||
2951 | bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); | ||
2952 | |||
2953 | if (is_ap) { | ||
2954 | struct wl1271_station *wl_sta; | ||
2955 | u8 hlid; | ||
2956 | |||
2957 | if (sta) { | ||
2958 | wl_sta = (struct wl1271_station *)sta->drv_priv; | ||
2959 | hlid = wl_sta->hlid; | ||
2960 | } else { | ||
2961 | hlid = wlvif->ap.bcast_hlid; | ||
2962 | } | ||
2963 | |||
2964 | if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) { | ||
2965 | /* | ||
2966 | * We do not support removing keys after AP shutdown. | ||
2967 | * Pretend we do to make mac80211 happy. | ||
2968 | */ | ||
2969 | if (action != KEY_ADD_OR_REPLACE) | ||
2970 | return 0; | ||
2971 | |||
2972 | ret = wl1271_record_ap_key(wl, wlvif, id, | ||
2973 | key_type, key_size, | ||
2974 | key, hlid, tx_seq_32, | ||
2975 | tx_seq_16); | ||
2976 | } else { | ||
2977 | ret = wl1271_cmd_set_ap_key(wl, wlvif, action, | ||
2978 | id, key_type, key_size, | ||
2979 | key, hlid, tx_seq_32, | ||
2980 | tx_seq_16); | ||
2981 | } | ||
2982 | |||
2983 | if (ret < 0) | ||
2984 | return ret; | ||
2985 | } else { | ||
2986 | const u8 *addr; | ||
2987 | static const u8 bcast_addr[ETH_ALEN] = { | ||
2988 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff | ||
2989 | }; | ||
2990 | |||
2991 | /* | ||
2992 | * A STA set to GEM cipher requires 2 tx spare blocks. | ||
2993 | * Return to default value when GEM cipher key is removed | ||
2994 | */ | ||
2995 | if (key_type == KEY_GEM) { | ||
2996 | if (action == KEY_ADD_OR_REPLACE) | ||
2997 | wl->tx_spare_blocks = 2; | ||
2998 | else if (action == KEY_REMOVE) | ||
2999 | wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT; | ||
3000 | } | ||
3001 | |||
3002 | addr = sta ? sta->addr : bcast_addr; | ||
3003 | |||
3004 | if (is_zero_ether_addr(addr)) { | ||
3005 | /* We dont support TX only encryption */ | ||
3006 | return -EOPNOTSUPP; | ||
3007 | } | ||
3008 | |||
3009 | /* The wl1271 does not allow to remove unicast keys - they | ||
3010 | will be cleared automatically on next CMD_JOIN. Ignore the | ||
3011 | request silently, as we dont want the mac80211 to emit | ||
3012 | an error message. */ | ||
3013 | if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr)) | ||
3014 | return 0; | ||
3015 | |||
3016 | /* don't remove key if hlid was already deleted */ | ||
3017 | if (action == KEY_REMOVE && | ||
3018 | wlvif->sta.hlid == WL12XX_INVALID_LINK_ID) | ||
3019 | return 0; | ||
3020 | |||
3021 | ret = wl1271_cmd_set_sta_key(wl, wlvif, action, | ||
3022 | id, key_type, key_size, | ||
3023 | key, addr, tx_seq_32, | ||
3024 | tx_seq_16); | ||
3025 | if (ret < 0) | ||
3026 | return ret; | ||
3027 | |||
3028 | /* the default WEP key needs to be configured at least once */ | ||
3029 | if (key_type == KEY_WEP) { | ||
3030 | ret = wl12xx_cmd_set_default_wep_key(wl, | ||
3031 | wlvif->default_key, | ||
3032 | wlvif->sta.hlid); | ||
3033 | if (ret < 0) | ||
3034 | return ret; | ||
3035 | } | ||
3036 | } | ||
3037 | |||
3038 | return 0; | ||
3039 | } | ||
3040 | |||
3041 | static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | ||
3042 | struct ieee80211_vif *vif, | ||
3043 | struct ieee80211_sta *sta, | ||
3044 | struct ieee80211_key_conf *key_conf) | ||
3045 | { | ||
3046 | struct wl1271 *wl = hw->priv; | ||
3047 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | ||
3048 | int ret; | ||
3049 | u32 tx_seq_32 = 0; | ||
3050 | u16 tx_seq_16 = 0; | ||
3051 | u8 key_type; | ||
3052 | |||
3053 | wl1271_debug(DEBUG_MAC80211, "mac80211 set key"); | ||
3054 | |||
3055 | wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta); | ||
3056 | wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x", | ||
3057 | key_conf->cipher, key_conf->keyidx, | ||
3058 | key_conf->keylen, key_conf->flags); | ||
3059 | wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen); | ||
3060 | |||
3061 | mutex_lock(&wl->mutex); | ||
3062 | |||
3063 | if (unlikely(wl->state == WL1271_STATE_OFF)) { | ||
3064 | ret = -EAGAIN; | ||
3065 | goto out_unlock; | ||
3066 | } | ||
3067 | |||
3068 | ret = wl1271_ps_elp_wakeup(wl); | ||
3069 | if (ret < 0) | ||
3070 | goto out_unlock; | ||
3071 | |||
3072 | switch (key_conf->cipher) { | ||
3073 | case WLAN_CIPHER_SUITE_WEP40: | ||
3074 | case WLAN_CIPHER_SUITE_WEP104: | ||
3075 | key_type = KEY_WEP; | ||
3076 | |||
3077 | key_conf->hw_key_idx = key_conf->keyidx; | ||
3078 | break; | ||
3079 | case WLAN_CIPHER_SUITE_TKIP: | ||
3080 | key_type = KEY_TKIP; | ||
3081 | |||
3082 | key_conf->hw_key_idx = key_conf->keyidx; | ||
3083 | tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq); | ||
3084 | tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq); | ||
3085 | break; | ||
3086 | case WLAN_CIPHER_SUITE_CCMP: | ||
3087 | key_type = KEY_AES; | ||
3088 | |||
3089 | key_conf->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE; | ||
3090 | tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq); | ||
3091 | tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq); | ||
3092 | break; | ||
3093 | case WL1271_CIPHER_SUITE_GEM: | ||
3094 | key_type = KEY_GEM; | ||
3095 | tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq); | ||
3096 | tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq); | ||
3097 | break; | ||
3098 | default: | ||
3099 | wl1271_error("Unknown key algo 0x%x", key_conf->cipher); | ||
3100 | |||
3101 | ret = -EOPNOTSUPP; | ||
3102 | goto out_sleep; | ||
3103 | } | ||
3104 | |||
3105 | switch (cmd) { | ||
3106 | case SET_KEY: | ||
3107 | ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE, | ||
3108 | key_conf->keyidx, key_type, | ||
3109 | key_conf->keylen, key_conf->key, | ||
3110 | tx_seq_32, tx_seq_16, sta); | ||
3111 | if (ret < 0) { | ||
3112 | wl1271_error("Could not add or replace key"); | ||
3113 | goto out_sleep; | ||
3114 | } | ||
3115 | |||
3116 | /* | ||
3117 | * reconfiguring arp response if the unicast (or common) | ||
3118 | * encryption key type was changed | ||
3119 | */ | ||
3120 | if (wlvif->bss_type == BSS_TYPE_STA_BSS && | ||
3121 | (sta || key_type == KEY_WEP) && | ||
3122 | wlvif->encryption_type != key_type) { | ||
3123 | wlvif->encryption_type = key_type; | ||
3124 | ret = wl1271_cmd_build_arp_rsp(wl, wlvif); | ||
3125 | if (ret < 0) { | ||
3126 | wl1271_warning("build arp rsp failed: %d", ret); | ||
3127 | goto out_sleep; | ||
3128 | } | ||
3129 | } | ||
3130 | break; | ||
3131 | |||
3132 | case DISABLE_KEY: | ||
3133 | ret = wl1271_set_key(wl, wlvif, KEY_REMOVE, | ||
3134 | key_conf->keyidx, key_type, | ||
3135 | key_conf->keylen, key_conf->key, | ||
3136 | 0, 0, sta); | ||
3137 | if (ret < 0) { | ||
3138 | wl1271_error("Could not remove key"); | ||
3139 | goto out_sleep; | ||
3140 | } | ||
3141 | break; | ||
3142 | |||
3143 | default: | ||
3144 | wl1271_error("Unsupported key cmd 0x%x", cmd); | ||
3145 | ret = -EOPNOTSUPP; | ||
3146 | break; | ||
3147 | } | ||
3148 | |||
3149 | out_sleep: | ||
3150 | wl1271_ps_elp_sleep(wl); | ||
3151 | |||
3152 | out_unlock: | ||
3153 | mutex_unlock(&wl->mutex); | ||
3154 | |||
3155 | return ret; | ||
3156 | } | ||
3157 | |||
3158 | static int wl1271_op_hw_scan(struct ieee80211_hw *hw, | ||
3159 | struct ieee80211_vif *vif, | ||
3160 | struct cfg80211_scan_request *req) | ||
3161 | { | ||
3162 | struct wl1271 *wl = hw->priv; | ||
3163 | int ret; | ||
3164 | u8 *ssid = NULL; | ||
3165 | size_t len = 0; | ||
3166 | |||
3167 | wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan"); | ||
3168 | |||
3169 | if (req->n_ssids) { | ||
3170 | ssid = req->ssids[0].ssid; | ||
3171 | len = req->ssids[0].ssid_len; | ||
3172 | } | ||
3173 | |||
3174 | mutex_lock(&wl->mutex); | ||
3175 | |||
3176 | if (wl->state == WL1271_STATE_OFF) { | ||
3177 | /* | ||
3178 | * We cannot return -EBUSY here because cfg80211 will expect | ||
3179 | * a call to ieee80211_scan_completed if we do - in this case | ||
3180 | * there won't be any call. | ||
3181 | */ | ||
3182 | ret = -EAGAIN; | ||
3183 | goto out; | ||
3184 | } | ||
3185 | |||
3186 | ret = wl1271_ps_elp_wakeup(wl); | ||
3187 | if (ret < 0) | ||
3188 | goto out; | ||
3189 | |||
3190 | /* fail if there is any role in ROC */ | ||
3191 | if (find_first_bit(wl->roc_map, WL12XX_MAX_ROLES) < WL12XX_MAX_ROLES) { | ||
3192 | /* don't allow scanning right now */ | ||
3193 | ret = -EBUSY; | ||
3194 | goto out_sleep; | ||
3195 | } | ||
3196 | |||
3197 | ret = wl1271_scan(hw->priv, vif, ssid, len, req); | ||
3198 | out_sleep: | ||
3199 | wl1271_ps_elp_sleep(wl); | ||
3200 | out: | ||
3201 | mutex_unlock(&wl->mutex); | ||
3202 | |||
3203 | return ret; | ||
3204 | } | ||
3205 | |||
3206 | static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw, | ||
3207 | struct ieee80211_vif *vif) | ||
3208 | { | ||
3209 | struct wl1271 *wl = hw->priv; | ||
3210 | int ret; | ||
3211 | |||
3212 | wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan"); | ||
3213 | |||
3214 | mutex_lock(&wl->mutex); | ||
3215 | |||
3216 | if (wl->state == WL1271_STATE_OFF) | ||
3217 | goto out; | ||
3218 | |||
3219 | if (wl->scan.state == WL1271_SCAN_STATE_IDLE) | ||
3220 | goto out; | ||
3221 | |||
3222 | ret = wl1271_ps_elp_wakeup(wl); | ||
3223 | if (ret < 0) | ||
3224 | goto out; | ||
3225 | |||
3226 | if (wl->scan.state != WL1271_SCAN_STATE_DONE) { | ||
3227 | ret = wl1271_scan_stop(wl); | ||
3228 | if (ret < 0) | ||
3229 | goto out_sleep; | ||
3230 | } | ||
3231 | |||
3232 | /* | ||
3233 | * Rearm the tx watchdog just before idling scan. This | ||
3234 | * prevents just-finished scans from triggering the watchdog | ||
3235 | */ | ||
3236 | wl12xx_rearm_tx_watchdog_locked(wl); | ||
3237 | |||
3238 | wl->scan.state = WL1271_SCAN_STATE_IDLE; | ||
3239 | memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); | ||
3240 | wl->scan_vif = NULL; | ||
3241 | wl->scan.req = NULL; | ||
3242 | ieee80211_scan_completed(wl->hw, true); | ||
3243 | |||
3244 | out_sleep: | ||
3245 | wl1271_ps_elp_sleep(wl); | ||
3246 | out: | ||
3247 | mutex_unlock(&wl->mutex); | ||
3248 | |||
3249 | cancel_delayed_work_sync(&wl->scan_complete_work); | ||
3250 | } | ||
3251 | |||
3252 | static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw, | ||
3253 | struct ieee80211_vif *vif, | ||
3254 | struct cfg80211_sched_scan_request *req, | ||
3255 | struct ieee80211_sched_scan_ies *ies) | ||
3256 | { | ||
3257 | struct wl1271 *wl = hw->priv; | ||
3258 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | ||
3259 | int ret; | ||
3260 | |||
3261 | wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start"); | ||
3262 | |||
3263 | mutex_lock(&wl->mutex); | ||
3264 | |||
3265 | if (wl->state == WL1271_STATE_OFF) { | ||
3266 | ret = -EAGAIN; | ||
3267 | goto out; | ||
3268 | } | ||
3269 | |||
3270 | ret = wl1271_ps_elp_wakeup(wl); | ||
3271 | if (ret < 0) | ||
3272 | goto out; | ||
3273 | |||
3274 | ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies); | ||
3275 | if (ret < 0) | ||
3276 | goto out_sleep; | ||
3277 | |||
3278 | ret = wl1271_scan_sched_scan_start(wl, wlvif); | ||
3279 | if (ret < 0) | ||
3280 | goto out_sleep; | ||
3281 | |||
3282 | wl->sched_scanning = true; | ||
3283 | |||
3284 | out_sleep: | ||
3285 | wl1271_ps_elp_sleep(wl); | ||
3286 | out: | ||
3287 | mutex_unlock(&wl->mutex); | ||
3288 | return ret; | ||
3289 | } | ||
3290 | |||
3291 | static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw, | ||
3292 | struct ieee80211_vif *vif) | ||
3293 | { | ||
3294 | struct wl1271 *wl = hw->priv; | ||
3295 | int ret; | ||
3296 | |||
3297 | wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop"); | ||
3298 | |||
3299 | mutex_lock(&wl->mutex); | ||
3300 | |||
3301 | if (wl->state == WL1271_STATE_OFF) | ||
3302 | goto out; | ||
3303 | |||
3304 | ret = wl1271_ps_elp_wakeup(wl); | ||
3305 | if (ret < 0) | ||
3306 | goto out; | ||
3307 | |||
3308 | wl1271_scan_sched_scan_stop(wl); | ||
3309 | |||
3310 | wl1271_ps_elp_sleep(wl); | ||
3311 | out: | ||
3312 | mutex_unlock(&wl->mutex); | ||
3313 | } | ||
3314 | |||
3315 | static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value) | ||
3316 | { | ||
3317 | struct wl1271 *wl = hw->priv; | ||
3318 | int ret = 0; | ||
3319 | |||
3320 | mutex_lock(&wl->mutex); | ||
3321 | |||
3322 | if (unlikely(wl->state == WL1271_STATE_OFF)) { | ||
3323 | ret = -EAGAIN; | ||
3324 | goto out; | ||
3325 | } | ||
3326 | |||
3327 | ret = wl1271_ps_elp_wakeup(wl); | ||
3328 | if (ret < 0) | ||
3329 | goto out; | ||
3330 | |||
3331 | ret = wl1271_acx_frag_threshold(wl, value); | ||
3332 | if (ret < 0) | ||
3333 | wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret); | ||
3334 | |||
3335 | wl1271_ps_elp_sleep(wl); | ||
3336 | |||
3337 | out: | ||
3338 | mutex_unlock(&wl->mutex); | ||
3339 | |||
3340 | return ret; | ||
3341 | } | ||
3342 | |||
3343 | static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) | ||
3344 | { | ||
3345 | struct wl1271 *wl = hw->priv; | ||
3346 | struct wl12xx_vif *wlvif; | ||
3347 | int ret = 0; | ||
3348 | |||
3349 | mutex_lock(&wl->mutex); | ||
3350 | |||
3351 | if (unlikely(wl->state == WL1271_STATE_OFF)) { | ||
3352 | ret = -EAGAIN; | ||
3353 | goto out; | ||
3354 | } | ||
3355 | |||
3356 | ret = wl1271_ps_elp_wakeup(wl); | ||
3357 | if (ret < 0) | ||
3358 | goto out; | ||
3359 | |||
3360 | wl12xx_for_each_wlvif(wl, wlvif) { | ||
3361 | ret = wl1271_acx_rts_threshold(wl, wlvif, value); | ||
3362 | if (ret < 0) | ||
3363 | wl1271_warning("set rts threshold failed: %d", ret); | ||
3364 | } | ||
3365 | wl1271_ps_elp_sleep(wl); | ||
3366 | |||
3367 | out: | ||
3368 | mutex_unlock(&wl->mutex); | ||
3369 | |||
3370 | return ret; | ||
3371 | } | ||
3372 | |||
3373 | static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb, | ||
3374 | int offset) | ||
3375 | { | ||
3376 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | ||
3377 | u8 ssid_len; | ||
3378 | const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset, | ||
3379 | skb->len - offset); | ||
3380 | |||
3381 | if (!ptr) { | ||
3382 | wl1271_error("No SSID in IEs!"); | ||
3383 | return -ENOENT; | ||
3384 | } | ||
3385 | |||
3386 | ssid_len = ptr[1]; | ||
3387 | if (ssid_len > IEEE80211_MAX_SSID_LEN) { | ||
3388 | wl1271_error("SSID is too long!"); | ||
3389 | return -EINVAL; | ||
3390 | } | ||
3391 | |||
3392 | wlvif->ssid_len = ssid_len; | ||
3393 | memcpy(wlvif->ssid, ptr+2, ssid_len); | ||
3394 | return 0; | ||
3395 | } | ||
3396 | |||
3397 | static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset) | ||
3398 | { | ||
3399 | int len; | ||
3400 | const u8 *next, *end = skb->data + skb->len; | ||
3401 | u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset, | ||
3402 | skb->len - ieoffset); | ||
3403 | if (!ie) | ||
3404 | return; | ||
3405 | len = ie[1] + 2; | ||
3406 | next = ie + len; | ||
3407 | memmove(ie, next, end - next); | ||
3408 | skb_trim(skb, skb->len - len); | ||
3409 | } | ||
3410 | |||
3411 | static void wl12xx_remove_vendor_ie(struct sk_buff *skb, | ||
3412 | unsigned int oui, u8 oui_type, | ||
3413 | int ieoffset) | ||
3414 | { | ||
3415 | int len; | ||
3416 | const u8 *next, *end = skb->data + skb->len; | ||
3417 | u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type, | ||
3418 | skb->data + ieoffset, | ||
3419 | skb->len - ieoffset); | ||
3420 | if (!ie) | ||
3421 | return; | ||
3422 | len = ie[1] + 2; | ||
3423 | next = ie + len; | ||
3424 | memmove(ie, next, end - next); | ||
3425 | skb_trim(skb, skb->len - len); | ||
3426 | } | ||
3427 | |||
3428 | static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates, | ||
3429 | struct ieee80211_vif *vif) | ||
3430 | { | ||
3431 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | ||
3432 | struct sk_buff *skb; | ||
3433 | int ret; | ||
3434 | |||
3435 | skb = ieee80211_proberesp_get(wl->hw, vif); | ||
3436 | if (!skb) | ||
3437 | return -EOPNOTSUPP; | ||
3438 | |||
3439 | ret = wl1271_cmd_template_set(wl, wlvif->role_id, | ||
3440 | CMD_TEMPL_AP_PROBE_RESPONSE, | ||
3441 | skb->data, | ||
3442 | skb->len, 0, | ||
3443 | rates); | ||
3444 | |||
3445 | dev_kfree_skb(skb); | ||
3446 | return ret; | ||
3447 | } | ||
3448 | |||
3449 | static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl, | ||
3450 | struct ieee80211_vif *vif, | ||
3451 | u8 *probe_rsp_data, | ||
3452 | size_t probe_rsp_len, | ||
3453 | u32 rates) | ||
3454 | { | ||
3455 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | ||
3456 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; | ||
3457 | u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE]; | ||
3458 | int ssid_ie_offset, ie_offset, templ_len; | ||
3459 | const u8 *ptr; | ||
3460 | |||
3461 | /* no need to change probe response if the SSID is set correctly */ | ||
3462 | if (wlvif->ssid_len > 0) | ||
3463 | return wl1271_cmd_template_set(wl, wlvif->role_id, | ||
3464 | CMD_TEMPL_AP_PROBE_RESPONSE, | ||
3465 | probe_rsp_data, | ||
3466 | probe_rsp_len, 0, | ||
3467 | rates); | ||
3468 | |||
3469 | if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) { | ||
3470 | wl1271_error("probe_rsp template too big"); | ||
3471 | return -EINVAL; | ||
3472 | } | ||
3473 | |||
3474 | /* start searching from IE offset */ | ||
3475 | ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); | ||
3476 | |||
3477 | ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset, | ||
3478 | probe_rsp_len - ie_offset); | ||
3479 | if (!ptr) { | ||
3480 | wl1271_error("No SSID in beacon!"); | ||
3481 | return -EINVAL; | ||
3482 | } | ||
3483 | |||
3484 | ssid_ie_offset = ptr - probe_rsp_data; | ||
3485 | ptr += (ptr[1] + 2); | ||
3486 | |||
3487 | memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset); | ||
3488 | |||
3489 | /* insert SSID from bss_conf */ | ||
3490 | probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID; | ||
3491 | probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len; | ||
3492 | memcpy(probe_rsp_templ + ssid_ie_offset + 2, | ||
3493 | bss_conf->ssid, bss_conf->ssid_len); | ||
3494 | templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len; | ||
3495 | |||
3496 | memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len, | ||
3497 | ptr, probe_rsp_len - (ptr - probe_rsp_data)); | ||
3498 | templ_len += probe_rsp_len - (ptr - probe_rsp_data); | ||
3499 | |||
3500 | return wl1271_cmd_template_set(wl, wlvif->role_id, | ||
3501 | CMD_TEMPL_AP_PROBE_RESPONSE, | ||
3502 | probe_rsp_templ, | ||
3503 | templ_len, 0, | ||
3504 | rates); | ||
3505 | } | ||
3506 | |||
3507 | static int wl1271_bss_erp_info_changed(struct wl1271 *wl, | ||
3508 | struct ieee80211_vif *vif, | ||
3509 | struct ieee80211_bss_conf *bss_conf, | ||
3510 | u32 changed) | ||
3511 | { | ||
3512 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | ||
3513 | int ret = 0; | ||
3514 | |||
3515 | if (changed & BSS_CHANGED_ERP_SLOT) { | ||
3516 | if (bss_conf->use_short_slot) | ||
3517 | ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_SHORT); | ||
3518 | else | ||
3519 | ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_LONG); | ||
3520 | if (ret < 0) { | ||
3521 | wl1271_warning("Set slot time failed %d", ret); | ||
3522 | goto out; | ||
3523 | } | ||
3524 | } | ||
3525 | |||
3526 | if (changed & BSS_CHANGED_ERP_PREAMBLE) { | ||
3527 | if (bss_conf->use_short_preamble) | ||
3528 | wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_SHORT); | ||
3529 | else | ||
3530 | wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_LONG); | ||
3531 | } | ||
3532 | |||
3533 | if (changed & BSS_CHANGED_ERP_CTS_PROT) { | ||
3534 | if (bss_conf->use_cts_prot) | ||
3535 | ret = wl1271_acx_cts_protect(wl, wlvif, | ||
3536 | CTSPROTECT_ENABLE); | ||
3537 | else | ||
3538 | ret = wl1271_acx_cts_protect(wl, wlvif, | ||
3539 | CTSPROTECT_DISABLE); | ||
3540 | if (ret < 0) { | ||
3541 | wl1271_warning("Set ctsprotect failed %d", ret); | ||
3542 | goto out; | ||
3543 | } | ||
3544 | } | ||
3545 | |||
3546 | out: | ||
3547 | return ret; | ||
3548 | } | ||
3549 | |||
3550 | static int wl1271_bss_beacon_info_changed(struct wl1271 *wl, | ||
3551 | struct ieee80211_vif *vif, | ||
3552 | struct ieee80211_bss_conf *bss_conf, | ||
3553 | u32 changed) | ||
3554 | { | ||
3555 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | ||
3556 | bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); | ||
3557 | int ret = 0; | ||
3558 | |||
3559 | if ((changed & BSS_CHANGED_BEACON_INT)) { | ||
3560 | wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d", | ||
3561 | bss_conf->beacon_int); | ||
3562 | |||
3563 | wlvif->beacon_int = bss_conf->beacon_int; | ||
3564 | } | ||
3565 | |||
3566 | if ((changed & BSS_CHANGED_AP_PROBE_RESP) && is_ap) { | ||
3567 | u32 rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); | ||
3568 | if (!wl1271_ap_set_probe_resp_tmpl(wl, rate, vif)) { | ||
3569 | wl1271_debug(DEBUG_AP, "probe response updated"); | ||
3570 | set_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags); | ||
3571 | } | ||
3572 | } | ||
3573 | |||
3574 | if ((changed & BSS_CHANGED_BEACON)) { | ||
3575 | struct ieee80211_hdr *hdr; | ||
3576 | u32 min_rate; | ||
3577 | int ieoffset = offsetof(struct ieee80211_mgmt, | ||
3578 | u.beacon.variable); | ||
3579 | struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif); | ||
3580 | u16 tmpl_id; | ||
3581 | |||
3582 | if (!beacon) { | ||
3583 | ret = -EINVAL; | ||
3584 | goto out; | ||
3585 | } | ||
3586 | |||
3587 | wl1271_debug(DEBUG_MASTER, "beacon updated"); | ||
3588 | |||
3589 | ret = wl1271_ssid_set(vif, beacon, ieoffset); | ||
3590 | if (ret < 0) { | ||
3591 | dev_kfree_skb(beacon); | ||
3592 | goto out; | ||
3593 | } | ||
3594 | min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); | ||
3595 | tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON : | ||
3596 | CMD_TEMPL_BEACON; | ||
3597 | ret = wl1271_cmd_template_set(wl, wlvif->role_id, tmpl_id, | ||
3598 | beacon->data, | ||
3599 | beacon->len, 0, | ||
3600 | min_rate); | ||
3601 | if (ret < 0) { | ||
3602 | dev_kfree_skb(beacon); | ||
3603 | goto out; | ||
3604 | } | ||
3605 | |||
3606 | /* | ||
3607 | * In case we already have a probe-resp beacon set explicitly | ||
3608 | * by usermode, don't use the beacon data. | ||
3609 | */ | ||
3610 | if (test_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags)) | ||
3611 | goto end_bcn; | ||
3612 | |||
3613 | /* remove TIM ie from probe response */ | ||
3614 | wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset); | ||
3615 | |||
3616 | /* | ||
3617 | * remove p2p ie from probe response. | ||
3618 | * the fw reponds to probe requests that don't include | ||
3619 | * the p2p ie. probe requests with p2p ie will be passed, | ||
3620 | * and will be responded by the supplicant (the spec | ||
3621 | * forbids including the p2p ie when responding to probe | ||
3622 | * requests that didn't include it). | ||
3623 | */ | ||
3624 | wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA, | ||
3625 | WLAN_OUI_TYPE_WFA_P2P, ieoffset); | ||
3626 | |||
3627 | hdr = (struct ieee80211_hdr *) beacon->data; | ||
3628 | hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
3629 | IEEE80211_STYPE_PROBE_RESP); | ||
3630 | if (is_ap) | ||
3631 | ret = wl1271_ap_set_probe_resp_tmpl_legacy(wl, vif, | ||
3632 | beacon->data, | ||
3633 | beacon->len, | ||
3634 | min_rate); | ||
3635 | else | ||
3636 | ret = wl1271_cmd_template_set(wl, wlvif->role_id, | ||
3637 | CMD_TEMPL_PROBE_RESPONSE, | ||
3638 | beacon->data, | ||
3639 | beacon->len, 0, | ||
3640 | min_rate); | ||
3641 | end_bcn: | ||
3642 | dev_kfree_skb(beacon); | ||
3643 | if (ret < 0) | ||
3644 | goto out; | ||
3645 | } | ||
3646 | |||
3647 | out: | ||
3648 | if (ret != 0) | ||
3649 | wl1271_error("beacon info change failed: %d", ret); | ||
3650 | return ret; | ||
3651 | } | ||
3652 | |||
3653 | /* AP mode changes */ | ||
3654 | static void wl1271_bss_info_changed_ap(struct wl1271 *wl, | ||
3655 | struct ieee80211_vif *vif, | ||
3656 | struct ieee80211_bss_conf *bss_conf, | ||
3657 | u32 changed) | ||
3658 | { | ||
3659 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | ||
3660 | int ret = 0; | ||
3661 | |||
3662 | if ((changed & BSS_CHANGED_BASIC_RATES)) { | ||
3663 | u32 rates = bss_conf->basic_rates; | ||
3664 | |||
3665 | wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates, | ||
3666 | wlvif->band); | ||
3667 | wlvif->basic_rate = wl1271_tx_min_rate_get(wl, | ||
3668 | wlvif->basic_rate_set); | ||
3669 | |||
3670 | ret = wl1271_init_ap_rates(wl, wlvif); | ||
3671 | if (ret < 0) { | ||
3672 | wl1271_error("AP rate policy change failed %d", ret); | ||
3673 | goto out; | ||
3674 | } | ||
3675 | |||
3676 | ret = wl1271_ap_init_templates(wl, vif); | ||
3677 | if (ret < 0) | ||
3678 | goto out; | ||
3679 | } | ||
3680 | |||
3681 | ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed); | ||
3682 | if (ret < 0) | ||
3683 | goto out; | ||
3684 | |||
3685 | if ((changed & BSS_CHANGED_BEACON_ENABLED)) { | ||
3686 | if (bss_conf->enable_beacon) { | ||
3687 | if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) { | ||
3688 | ret = wl12xx_cmd_role_start_ap(wl, wlvif); | ||
3689 | if (ret < 0) | ||
3690 | goto out; | ||
3691 | |||
3692 | ret = wl1271_ap_init_hwenc(wl, wlvif); | ||
3693 | if (ret < 0) | ||
3694 | goto out; | ||
3695 | |||
3696 | set_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags); | ||
3697 | wl1271_debug(DEBUG_AP, "started AP"); | ||
3698 | } | ||
3699 | } else { | ||
3700 | if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) { | ||
3701 | ret = wl12xx_cmd_role_stop_ap(wl, wlvif); | ||
3702 | if (ret < 0) | ||
3703 | goto out; | ||
3704 | |||
3705 | clear_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags); | ||
3706 | clear_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, | ||
3707 | &wlvif->flags); | ||
3708 | wl1271_debug(DEBUG_AP, "stopped AP"); | ||
3709 | } | ||
3710 | } | ||
3711 | } | ||
3712 | |||
3713 | ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed); | ||
3714 | if (ret < 0) | ||
3715 | goto out; | ||
3716 | |||
3717 | /* Handle HT information change */ | ||
3718 | if ((changed & BSS_CHANGED_HT) && | ||
3719 | (bss_conf->channel_type != NL80211_CHAN_NO_HT)) { | ||
3720 | ret = wl1271_acx_set_ht_information(wl, wlvif, | ||
3721 | bss_conf->ht_operation_mode); | ||
3722 | if (ret < 0) { | ||
3723 | wl1271_warning("Set ht information failed %d", ret); | ||
3724 | goto out; | ||
3725 | } | ||
3726 | } | ||
3727 | |||
3728 | out: | ||
3729 | return; | ||
3730 | } | ||
3731 | |||
3732 | /* STA/IBSS mode changes */ | ||
3733 | static void wl1271_bss_info_changed_sta(struct wl1271 *wl, | ||
3734 | struct ieee80211_vif *vif, | ||
3735 | struct ieee80211_bss_conf *bss_conf, | ||
3736 | u32 changed) | ||
3737 | { | ||
3738 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | ||
3739 | bool do_join = false, set_assoc = false; | ||
3740 | bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS); | ||
3741 | bool ibss_joined = false; | ||
3742 | u32 sta_rate_set = 0; | ||
3743 | int ret; | ||
3744 | struct ieee80211_sta *sta; | ||
3745 | bool sta_exists = false; | ||
3746 | struct ieee80211_sta_ht_cap sta_ht_cap; | ||
3747 | |||
3748 | if (is_ibss) { | ||
3749 | ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, | ||
3750 | changed); | ||
3751 | if (ret < 0) | ||
3752 | goto out; | ||
3753 | } | ||
3754 | |||
3755 | if (changed & BSS_CHANGED_IBSS) { | ||
3756 | if (bss_conf->ibss_joined) { | ||
3757 | set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags); | ||
3758 | ibss_joined = true; | ||
3759 | } else { | ||
3760 | if (test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED, | ||
3761 | &wlvif->flags)) | ||
3762 | wl1271_unjoin(wl, wlvif); | ||
3763 | } | ||
3764 | } | ||
3765 | |||
3766 | if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined) | ||
3767 | do_join = true; | ||
3768 | |||
3769 | /* Need to update the SSID (for filtering etc) */ | ||
3770 | if ((changed & BSS_CHANGED_BEACON) && ibss_joined) | ||
3771 | do_join = true; | ||
3772 | |||
3773 | if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) { | ||
3774 | wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s", | ||
3775 | bss_conf->enable_beacon ? "enabled" : "disabled"); | ||
3776 | |||
3777 | do_join = true; | ||
3778 | } | ||
3779 | |||
3780 | if (changed & BSS_CHANGED_IDLE && !is_ibss) { | ||
3781 | ret = wl1271_sta_handle_idle(wl, wlvif, bss_conf->idle); | ||
3782 | if (ret < 0) | ||
3783 | wl1271_warning("idle mode change failed %d", ret); | ||
3784 | } | ||
3785 | |||
3786 | if ((changed & BSS_CHANGED_CQM)) { | ||
3787 | bool enable = false; | ||
3788 | if (bss_conf->cqm_rssi_thold) | ||
3789 | enable = true; | ||
3790 | ret = wl1271_acx_rssi_snr_trigger(wl, wlvif, enable, | ||
3791 | bss_conf->cqm_rssi_thold, | ||
3792 | bss_conf->cqm_rssi_hyst); | ||
3793 | if (ret < 0) | ||
3794 | goto out; | ||
3795 | wlvif->rssi_thold = bss_conf->cqm_rssi_thold; | ||
3796 | } | ||
3797 | |||
3798 | if (changed & BSS_CHANGED_BSSID) | ||
3799 | if (!is_zero_ether_addr(bss_conf->bssid)) { | ||
3800 | ret = wl12xx_cmd_build_null_data(wl, wlvif); | ||
3801 | if (ret < 0) | ||
3802 | goto out; | ||
3803 | |||
3804 | ret = wl1271_build_qos_null_data(wl, vif); | ||
3805 | if (ret < 0) | ||
3806 | goto out; | ||
3807 | } | ||
3808 | |||
3809 | if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) { | ||
3810 | rcu_read_lock(); | ||
3811 | sta = ieee80211_find_sta(vif, bss_conf->bssid); | ||
3812 | if (!sta) | ||
3813 | goto sta_not_found; | ||
3814 | |||
3815 | /* save the supp_rates of the ap */ | ||
3816 | sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band]; | ||
3817 | if (sta->ht_cap.ht_supported) | ||
3818 | sta_rate_set |= | ||
3819 | (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET); | ||
3820 | sta_ht_cap = sta->ht_cap; | ||
3821 | sta_exists = true; | ||
3822 | |||
3823 | sta_not_found: | ||
3824 | rcu_read_unlock(); | ||
3825 | } | ||
3826 | |||
3827 | if ((changed & BSS_CHANGED_ASSOC)) { | ||
3828 | if (bss_conf->assoc) { | ||
3829 | u32 rates; | ||
3830 | int ieoffset; | ||
3831 | wlvif->aid = bss_conf->aid; | ||
3832 | wlvif->beacon_int = bss_conf->beacon_int; | ||
3833 | do_join = true; | ||
3834 | set_assoc = true; | ||
3835 | |||
3836 | /* | ||
3837 | * use basic rates from AP, and determine lowest rate | ||
3838 | * to use with control frames. | ||
3839 | */ | ||
3840 | rates = bss_conf->basic_rates; | ||
3841 | wlvif->basic_rate_set = | ||
3842 | wl1271_tx_enabled_rates_get(wl, rates, | ||
3843 | wlvif->band); | ||
3844 | wlvif->basic_rate = | ||
3845 | wl1271_tx_min_rate_get(wl, | ||
3846 | wlvif->basic_rate_set); | ||
3847 | if (sta_rate_set) | ||
3848 | wlvif->rate_set = | ||
3849 | wl1271_tx_enabled_rates_get(wl, | ||
3850 | sta_rate_set, | ||
3851 | wlvif->band); | ||
3852 | ret = wl1271_acx_sta_rate_policies(wl, wlvif); | ||
3853 | if (ret < 0) | ||
3854 | goto out; | ||
3855 | |||
3856 | /* | ||
3857 | * with wl1271, we don't need to update the | ||
3858 | * beacon_int and dtim_period, because the firmware | ||
3859 | * updates it by itself when the first beacon is | ||
3860 | * received after a join. | ||
3861 | */ | ||
3862 | ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid); | ||
3863 | if (ret < 0) | ||
3864 | goto out; | ||
3865 | |||
3866 | /* | ||
3867 | * Get a template for hardware connection maintenance | ||
3868 | */ | ||
3869 | dev_kfree_skb(wlvif->probereq); | ||
3870 | wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl, | ||
3871 | wlvif, | ||
3872 | NULL); | ||
3873 | ieoffset = offsetof(struct ieee80211_mgmt, | ||
3874 | u.probe_req.variable); | ||
3875 | wl1271_ssid_set(vif, wlvif->probereq, ieoffset); | ||
3876 | |||
3877 | /* enable the connection monitoring feature */ | ||
3878 | ret = wl1271_acx_conn_monit_params(wl, wlvif, true); | ||
3879 | if (ret < 0) | ||
3880 | goto out; | ||
3881 | } else { | ||
3882 | /* use defaults when not associated */ | ||
3883 | bool was_assoc = | ||
3884 | !!test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED, | ||
3885 | &wlvif->flags); | ||
3886 | bool was_ifup = | ||
3887 | !!test_and_clear_bit(WLVIF_FLAG_STA_STATE_SENT, | ||
3888 | &wlvif->flags); | ||
3889 | wlvif->aid = 0; | ||
3890 | |||
3891 | /* free probe-request template */ | ||
3892 | dev_kfree_skb(wlvif->probereq); | ||
3893 | wlvif->probereq = NULL; | ||
3894 | |||
3895 | /* revert back to minimum rates for the current band */ | ||
3896 | wl1271_set_band_rate(wl, wlvif); | ||
3897 | wlvif->basic_rate = | ||
3898 | wl1271_tx_min_rate_get(wl, | ||
3899 | wlvif->basic_rate_set); | ||
3900 | ret = wl1271_acx_sta_rate_policies(wl, wlvif); | ||
3901 | if (ret < 0) | ||
3902 | goto out; | ||
3903 | |||
3904 | /* disable connection monitor features */ | ||
3905 | ret = wl1271_acx_conn_monit_params(wl, wlvif, false); | ||
3906 | |||
3907 | /* Disable the keep-alive feature */ | ||
3908 | ret = wl1271_acx_keep_alive_mode(wl, wlvif, false); | ||
3909 | if (ret < 0) | ||
3910 | goto out; | ||
3911 | |||
3912 | /* restore the bssid filter and go to dummy bssid */ | ||
3913 | if (was_assoc) { | ||
3914 | /* | ||
3915 | * we might have to disable roc, if there was | ||
3916 | * no IF_OPER_UP notification. | ||
3917 | */ | ||
3918 | if (!was_ifup) { | ||
3919 | ret = wl12xx_croc(wl, wlvif->role_id); | ||
3920 | if (ret < 0) | ||
3921 | goto out; | ||
3922 | } | ||
3923 | /* | ||
3924 | * (we also need to disable roc in case of | ||
3925 | * roaming on the same channel. until we will | ||
3926 | * have a better flow...) | ||
3927 | */ | ||
3928 | if (test_bit(wlvif->dev_role_id, wl->roc_map)) { | ||
3929 | ret = wl12xx_croc(wl, | ||
3930 | wlvif->dev_role_id); | ||
3931 | if (ret < 0) | ||
3932 | goto out; | ||
3933 | } | ||
3934 | |||
3935 | wl1271_unjoin(wl, wlvif); | ||
3936 | if (!bss_conf->idle) | ||
3937 | wl12xx_start_dev(wl, wlvif); | ||
3938 | } | ||
3939 | } | ||
3940 | } | ||
3941 | |||
3942 | if (changed & BSS_CHANGED_IBSS) { | ||
3943 | wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d", | ||
3944 | bss_conf->ibss_joined); | ||
3945 | |||
3946 | if (bss_conf->ibss_joined) { | ||
3947 | u32 rates = bss_conf->basic_rates; | ||
3948 | wlvif->basic_rate_set = | ||
3949 | wl1271_tx_enabled_rates_get(wl, rates, | ||
3950 | wlvif->band); | ||
3951 | wlvif->basic_rate = | ||
3952 | wl1271_tx_min_rate_get(wl, | ||
3953 | wlvif->basic_rate_set); | ||
3954 | |||
3955 | /* by default, use 11b + OFDM rates */ | ||
3956 | wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES; | ||
3957 | ret = wl1271_acx_sta_rate_policies(wl, wlvif); | ||
3958 | if (ret < 0) | ||
3959 | goto out; | ||
3960 | } | ||
3961 | } | ||
3962 | |||
3963 | ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed); | ||
3964 | if (ret < 0) | ||
3965 | goto out; | ||
3966 | |||
3967 | if (do_join) { | ||
3968 | ret = wl1271_join(wl, wlvif, set_assoc); | ||
3969 | if (ret < 0) { | ||
3970 | wl1271_warning("cmd join failed %d", ret); | ||
3971 | goto out; | ||
3972 | } | ||
3973 | |||
3974 | /* ROC until connected (after EAPOL exchange) */ | ||
3975 | if (!is_ibss) { | ||
3976 | ret = wl12xx_roc(wl, wlvif, wlvif->role_id); | ||
3977 | if (ret < 0) | ||
3978 | goto out; | ||
3979 | |||
3980 | if (test_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags)) | ||
3981 | wl12xx_set_authorized(wl, wlvif); | ||
3982 | } | ||
3983 | /* | ||
3984 | * stop device role if started (we might already be in | ||
3985 | * STA/IBSS role). | ||
3986 | */ | ||
3987 | if (wl12xx_dev_role_started(wlvif)) { | ||
3988 | ret = wl12xx_stop_dev(wl, wlvif); | ||
3989 | if (ret < 0) | ||
3990 | goto out; | ||
3991 | } | ||
3992 | } | ||
3993 | |||
3994 | /* Handle new association with HT. Do this after join. */ | ||
3995 | if (sta_exists) { | ||
3996 | if ((changed & BSS_CHANGED_HT) && | ||
3997 | (bss_conf->channel_type != NL80211_CHAN_NO_HT)) { | ||
3998 | ret = wl1271_acx_set_ht_capabilities(wl, | ||
3999 | &sta_ht_cap, | ||
4000 | true, | ||
4001 | wlvif->sta.hlid); | ||
4002 | if (ret < 0) { | ||
4003 | wl1271_warning("Set ht cap true failed %d", | ||
4004 | ret); | ||
4005 | goto out; | ||
4006 | } | ||
4007 | } | ||
4008 | /* handle new association without HT and disassociation */ | ||
4009 | else if (changed & BSS_CHANGED_ASSOC) { | ||
4010 | ret = wl1271_acx_set_ht_capabilities(wl, | ||
4011 | &sta_ht_cap, | ||
4012 | false, | ||
4013 | wlvif->sta.hlid); | ||
4014 | if (ret < 0) { | ||
4015 | wl1271_warning("Set ht cap false failed %d", | ||
4016 | ret); | ||
4017 | goto out; | ||
4018 | } | ||
4019 | } | ||
4020 | } | ||
4021 | |||
4022 | /* Handle HT information change. Done after join. */ | ||
4023 | if ((changed & BSS_CHANGED_HT) && | ||
4024 | (bss_conf->channel_type != NL80211_CHAN_NO_HT)) { | ||
4025 | ret = wl1271_acx_set_ht_information(wl, wlvif, | ||
4026 | bss_conf->ht_operation_mode); | ||
4027 | if (ret < 0) { | ||
4028 | wl1271_warning("Set ht information failed %d", ret); | ||
4029 | goto out; | ||
4030 | } | ||
4031 | } | ||
4032 | |||
4033 | /* Handle arp filtering. Done after join. */ | ||
4034 | if ((changed & BSS_CHANGED_ARP_FILTER) || | ||
4035 | (!is_ibss && (changed & BSS_CHANGED_QOS))) { | ||
4036 | __be32 addr = bss_conf->arp_addr_list[0]; | ||
4037 | wlvif->sta.qos = bss_conf->qos; | ||
4038 | WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS); | ||
4039 | |||
4040 | if (bss_conf->arp_addr_cnt == 1 && | ||
4041 | bss_conf->arp_filter_enabled) { | ||
4042 | wlvif->ip_addr = addr; | ||
4043 | /* | ||
4044 | * The template should have been configured only upon | ||
4045 | * association. however, it seems that the correct ip | ||
4046 | * isn't being set (when sending), so we have to | ||
4047 | * reconfigure the template upon every ip change. | ||
4048 | */ | ||
4049 | ret = wl1271_cmd_build_arp_rsp(wl, wlvif); | ||
4050 | if (ret < 0) { | ||
4051 | wl1271_warning("build arp rsp failed: %d", ret); | ||
4052 | goto out; | ||
4053 | } | ||
4054 | |||
4055 | ret = wl1271_acx_arp_ip_filter(wl, wlvif, | ||
4056 | (ACX_ARP_FILTER_ARP_FILTERING | | ||
4057 | ACX_ARP_FILTER_AUTO_ARP), | ||
4058 | addr); | ||
4059 | } else { | ||
4060 | wlvif->ip_addr = 0; | ||
4061 | ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr); | ||
4062 | } | ||
4063 | |||
4064 | if (ret < 0) | ||
4065 | goto out; | ||
4066 | } | ||
4067 | |||
4068 | out: | ||
4069 | return; | ||
4070 | } | ||
4071 | |||
4072 | static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, | ||
4073 | struct ieee80211_vif *vif, | ||
4074 | struct ieee80211_bss_conf *bss_conf, | ||
4075 | u32 changed) | ||
4076 | { | ||
4077 | struct wl1271 *wl = hw->priv; | ||
4078 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | ||
4079 | bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); | ||
4080 | int ret; | ||
4081 | |||
4082 | wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x", | ||
4083 | (int)changed); | ||
4084 | |||
4085 | mutex_lock(&wl->mutex); | ||
4086 | |||
4087 | if (unlikely(wl->state == WL1271_STATE_OFF)) | ||
4088 | goto out; | ||
4089 | |||
4090 | if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))) | ||
4091 | goto out; | ||
4092 | |||
4093 | ret = wl1271_ps_elp_wakeup(wl); | ||
4094 | if (ret < 0) | ||
4095 | goto out; | ||
4096 | |||
4097 | if (is_ap) | ||
4098 | wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed); | ||
4099 | else | ||
4100 | wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed); | ||
4101 | |||
4102 | wl1271_ps_elp_sleep(wl); | ||
4103 | |||
4104 | out: | ||
4105 | mutex_unlock(&wl->mutex); | ||
4106 | } | ||
4107 | |||
4108 | static int wl1271_op_conf_tx(struct ieee80211_hw *hw, | ||
4109 | struct ieee80211_vif *vif, u16 queue, | ||
4110 | const struct ieee80211_tx_queue_params *params) | ||
4111 | { | ||
4112 | struct wl1271 *wl = hw->priv; | ||
4113 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | ||
4114 | u8 ps_scheme; | ||
4115 | int ret = 0; | ||
4116 | |||
4117 | mutex_lock(&wl->mutex); | ||
4118 | |||
4119 | wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue); | ||
4120 | |||
4121 | if (params->uapsd) | ||
4122 | ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER; | ||
4123 | else | ||
4124 | ps_scheme = CONF_PS_SCHEME_LEGACY; | ||
4125 | |||
4126 | if (!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) | ||
4127 | goto out; | ||
4128 | |||
4129 | ret = wl1271_ps_elp_wakeup(wl); | ||
4130 | if (ret < 0) | ||
4131 | goto out; | ||
4132 | |||
4133 | /* | ||
4134 | * the txop is confed in units of 32us by the mac80211, | ||
4135 | * we need us | ||
4136 | */ | ||
4137 | ret = wl1271_acx_ac_cfg(wl, wlvif, wl1271_tx_get_queue(queue), | ||
4138 | params->cw_min, params->cw_max, | ||
4139 | params->aifs, params->txop << 5); | ||
4140 | if (ret < 0) | ||
4141 | goto out_sleep; | ||
4142 | |||
4143 | ret = wl1271_acx_tid_cfg(wl, wlvif, wl1271_tx_get_queue(queue), | ||
4144 | CONF_CHANNEL_TYPE_EDCF, | ||
4145 | wl1271_tx_get_queue(queue), | ||
4146 | ps_scheme, CONF_ACK_POLICY_LEGACY, | ||
4147 | 0, 0); | ||
4148 | |||
4149 | out_sleep: | ||
4150 | wl1271_ps_elp_sleep(wl); | ||
4151 | |||
4152 | out: | ||
4153 | mutex_unlock(&wl->mutex); | ||
4154 | |||
4155 | return ret; | ||
4156 | } | ||
4157 | |||
4158 | static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw, | ||
4159 | struct ieee80211_vif *vif) | ||
4160 | { | ||
4161 | |||
4162 | struct wl1271 *wl = hw->priv; | ||
4163 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | ||
4164 | u64 mactime = ULLONG_MAX; | ||
4165 | int ret; | ||
4166 | |||
4167 | wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf"); | ||
4168 | |||
4169 | mutex_lock(&wl->mutex); | ||
4170 | |||
4171 | if (unlikely(wl->state == WL1271_STATE_OFF)) | ||
4172 | goto out; | ||
4173 | |||
4174 | ret = wl1271_ps_elp_wakeup(wl); | ||
4175 | if (ret < 0) | ||
4176 | goto out; | ||
4177 | |||
4178 | ret = wl12xx_acx_tsf_info(wl, wlvif, &mactime); | ||
4179 | if (ret < 0) | ||
4180 | goto out_sleep; | ||
4181 | |||
4182 | out_sleep: | ||
4183 | wl1271_ps_elp_sleep(wl); | ||
4184 | |||
4185 | out: | ||
4186 | mutex_unlock(&wl->mutex); | ||
4187 | return mactime; | ||
4188 | } | ||
4189 | |||
4190 | static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx, | ||
4191 | struct survey_info *survey) | ||
4192 | { | ||
4193 | struct wl1271 *wl = hw->priv; | ||
4194 | struct ieee80211_conf *conf = &hw->conf; | ||
4195 | |||
4196 | if (idx != 0) | ||
4197 | return -ENOENT; | ||
4198 | |||
4199 | survey->channel = conf->channel; | ||
4200 | survey->filled = SURVEY_INFO_NOISE_DBM; | ||
4201 | survey->noise = wl->noise; | ||
4202 | |||
4203 | return 0; | ||
4204 | } | ||
4205 | |||
4206 | static int wl1271_allocate_sta(struct wl1271 *wl, | ||
4207 | struct wl12xx_vif *wlvif, | ||
4208 | struct ieee80211_sta *sta) | ||
4209 | { | ||
4210 | struct wl1271_station *wl_sta; | ||
4211 | int ret; | ||
4212 | |||
4213 | |||
4214 | if (wl->active_sta_count >= AP_MAX_STATIONS) { | ||
4215 | wl1271_warning("could not allocate HLID - too much stations"); | ||
4216 | return -EBUSY; | ||
4217 | } | ||
4218 | |||
4219 | wl_sta = (struct wl1271_station *)sta->drv_priv; | ||
4220 | ret = wl12xx_allocate_link(wl, wlvif, &wl_sta->hlid); | ||
4221 | if (ret < 0) { | ||
4222 | wl1271_warning("could not allocate HLID - too many links"); | ||
4223 | return -EBUSY; | ||
4224 | } | ||
4225 | |||
4226 | set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map); | ||
4227 | memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN); | ||
4228 | wl->active_sta_count++; | ||
4229 | return 0; | ||
4230 | } | ||
4231 | |||
4232 | void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid) | ||
4233 | { | ||
4234 | if (!test_bit(hlid, wlvif->ap.sta_hlid_map)) | ||
4235 | return; | ||
4236 | |||
4237 | clear_bit(hlid, wlvif->ap.sta_hlid_map); | ||
4238 | memset(wl->links[hlid].addr, 0, ETH_ALEN); | ||
4239 | wl->links[hlid].ba_bitmap = 0; | ||
4240 | __clear_bit(hlid, &wl->ap_ps_map); | ||
4241 | __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); | ||
4242 | wl12xx_free_link(wl, wlvif, &hlid); | ||
4243 | wl->active_sta_count--; | ||
4244 | |||
4245 | /* | ||
4246 | * rearm the tx watchdog when the last STA is freed - give the FW a | ||
4247 | * chance to return STA-buffered packets before complaining. | ||
4248 | */ | ||
4249 | if (wl->active_sta_count == 0) | ||
4250 | wl12xx_rearm_tx_watchdog_locked(wl); | ||
4251 | } | ||
4252 | |||
4253 | static int wl12xx_sta_add(struct wl1271 *wl, | ||
4254 | struct wl12xx_vif *wlvif, | ||
4255 | struct ieee80211_sta *sta) | ||
4256 | { | ||
4257 | struct wl1271_station *wl_sta; | ||
4258 | int ret = 0; | ||
4259 | u8 hlid; | ||
4260 | |||
4261 | wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid); | ||
4262 | |||
4263 | ret = wl1271_allocate_sta(wl, wlvif, sta); | ||
4264 | if (ret < 0) | ||
4265 | return ret; | ||
4266 | |||
4267 | wl_sta = (struct wl1271_station *)sta->drv_priv; | ||
4268 | hlid = wl_sta->hlid; | ||
4269 | |||
4270 | ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid); | ||
4271 | if (ret < 0) | ||
4272 | wl1271_free_sta(wl, wlvif, hlid); | ||
4273 | |||
4274 | return ret; | ||
4275 | } | ||
4276 | |||
4277 | static int wl12xx_sta_remove(struct wl1271 *wl, | ||
4278 | struct wl12xx_vif *wlvif, | ||
4279 | struct ieee80211_sta *sta) | ||
4280 | { | ||
4281 | struct wl1271_station *wl_sta; | ||
4282 | int ret = 0, id; | ||
4283 | |||
4284 | wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid); | ||
4285 | |||
4286 | wl_sta = (struct wl1271_station *)sta->drv_priv; | ||
4287 | id = wl_sta->hlid; | ||
4288 | if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map))) | ||
4289 | return -EINVAL; | ||
4290 | |||
4291 | ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid); | ||
4292 | if (ret < 0) | ||
4293 | return ret; | ||
4294 | |||
4295 | wl1271_free_sta(wl, wlvif, wl_sta->hlid); | ||
4296 | return ret; | ||
4297 | } | ||
4298 | |||
4299 | static int wl12xx_update_sta_state(struct wl1271 *wl, | ||
4300 | struct wl12xx_vif *wlvif, | ||
4301 | struct ieee80211_sta *sta, | ||
4302 | enum ieee80211_sta_state old_state, | ||
4303 | enum ieee80211_sta_state new_state) | ||
4304 | { | ||
4305 | struct wl1271_station *wl_sta; | ||
4306 | u8 hlid; | ||
4307 | bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS; | ||
4308 | bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS; | ||
4309 | int ret; | ||
4310 | |||
4311 | wl_sta = (struct wl1271_station *)sta->drv_priv; | ||
4312 | hlid = wl_sta->hlid; | ||
4313 | |||
4314 | /* Add station (AP mode) */ | ||
4315 | if (is_ap && | ||
4316 | old_state == IEEE80211_STA_NOTEXIST && | ||
4317 | new_state == IEEE80211_STA_NONE) | ||
4318 | return wl12xx_sta_add(wl, wlvif, sta); | ||
4319 | |||
4320 | /* Remove station (AP mode) */ | ||
4321 | if (is_ap && | ||
4322 | old_state == IEEE80211_STA_NONE && | ||
4323 | new_state == IEEE80211_STA_NOTEXIST) { | ||
4324 | /* must not fail */ | ||
4325 | wl12xx_sta_remove(wl, wlvif, sta); | ||
4326 | return 0; | ||
4327 | } | ||
4328 | |||
4329 | /* Authorize station (AP mode) */ | ||
4330 | if (is_ap && | ||
4331 | new_state == IEEE80211_STA_AUTHORIZED) { | ||
4332 | ret = wl12xx_cmd_set_peer_state(wl, hlid); | ||
4333 | if (ret < 0) | ||
4334 | return ret; | ||
4335 | |||
4336 | ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, | ||
4337 | hlid); | ||
4338 | return ret; | ||
4339 | } | ||
4340 | |||
4341 | /* Authorize station */ | ||
4342 | if (is_sta && | ||
4343 | new_state == IEEE80211_STA_AUTHORIZED) { | ||
4344 | set_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags); | ||
4345 | return wl12xx_set_authorized(wl, wlvif); | ||
4346 | } | ||
4347 | |||
4348 | if (is_sta && | ||
4349 | old_state == IEEE80211_STA_AUTHORIZED && | ||
4350 | new_state == IEEE80211_STA_ASSOC) { | ||
4351 | clear_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags); | ||
4352 | return 0; | ||
4353 | } | ||
4354 | |||
4355 | return 0; | ||
4356 | } | ||
4357 | |||
4358 | static int wl12xx_op_sta_state(struct ieee80211_hw *hw, | ||
4359 | struct ieee80211_vif *vif, | ||
4360 | struct ieee80211_sta *sta, | ||
4361 | enum ieee80211_sta_state old_state, | ||
4362 | enum ieee80211_sta_state new_state) | ||
4363 | { | ||
4364 | struct wl1271 *wl = hw->priv; | ||
4365 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | ||
4366 | int ret; | ||
4367 | |||
4368 | wl1271_debug(DEBUG_MAC80211, "mac80211 sta %d state=%d->%d", | ||
4369 | sta->aid, old_state, new_state); | ||
4370 | |||
4371 | mutex_lock(&wl->mutex); | ||
4372 | |||
4373 | if (unlikely(wl->state == WL1271_STATE_OFF)) { | ||
4374 | ret = -EBUSY; | ||
4375 | goto out; | ||
4376 | } | ||
4377 | |||
4378 | ret = wl1271_ps_elp_wakeup(wl); | ||
4379 | if (ret < 0) | ||
4380 | goto out; | ||
4381 | |||
4382 | ret = wl12xx_update_sta_state(wl, wlvif, sta, old_state, new_state); | ||
4383 | |||
4384 | wl1271_ps_elp_sleep(wl); | ||
4385 | out: | ||
4386 | mutex_unlock(&wl->mutex); | ||
4387 | if (new_state < old_state) | ||
4388 | return 0; | ||
4389 | return ret; | ||
4390 | } | ||
4391 | |||
4392 | static int wl1271_op_ampdu_action(struct ieee80211_hw *hw, | ||
4393 | struct ieee80211_vif *vif, | ||
4394 | enum ieee80211_ampdu_mlme_action action, | ||
4395 | struct ieee80211_sta *sta, u16 tid, u16 *ssn, | ||
4396 | u8 buf_size) | ||
4397 | { | ||
4398 | struct wl1271 *wl = hw->priv; | ||
4399 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | ||
4400 | int ret; | ||
4401 | u8 hlid, *ba_bitmap; | ||
4402 | |||
4403 | wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action, | ||
4404 | tid); | ||
4405 | |||
4406 | /* sanity check - the fields in FW are only 8bits wide */ | ||
4407 | if (WARN_ON(tid > 0xFF)) | ||
4408 | return -ENOTSUPP; | ||
4409 | |||
4410 | mutex_lock(&wl->mutex); | ||
4411 | |||
4412 | if (unlikely(wl->state == WL1271_STATE_OFF)) { | ||
4413 | ret = -EAGAIN; | ||
4414 | goto out; | ||
4415 | } | ||
4416 | |||
4417 | if (wlvif->bss_type == BSS_TYPE_STA_BSS) { | ||
4418 | hlid = wlvif->sta.hlid; | ||
4419 | ba_bitmap = &wlvif->sta.ba_rx_bitmap; | ||
4420 | } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) { | ||
4421 | struct wl1271_station *wl_sta; | ||
4422 | |||
4423 | wl_sta = (struct wl1271_station *)sta->drv_priv; | ||
4424 | hlid = wl_sta->hlid; | ||
4425 | ba_bitmap = &wl->links[hlid].ba_bitmap; | ||
4426 | } else { | ||
4427 | ret = -EINVAL; | ||
4428 | goto out; | ||
4429 | } | ||
4430 | |||
4431 | ret = wl1271_ps_elp_wakeup(wl); | ||
4432 | if (ret < 0) | ||
4433 | goto out; | ||
4434 | |||
4435 | wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d", | ||
4436 | tid, action); | ||
4437 | |||
4438 | switch (action) { | ||
4439 | case IEEE80211_AMPDU_RX_START: | ||
4440 | if (!wlvif->ba_support || !wlvif->ba_allowed) { | ||
4441 | ret = -ENOTSUPP; | ||
4442 | break; | ||
4443 | } | ||
4444 | |||
4445 | if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) { | ||
4446 | ret = -EBUSY; | ||
4447 | wl1271_error("exceeded max RX BA sessions"); | ||
4448 | break; | ||
4449 | } | ||
4450 | |||
4451 | if (*ba_bitmap & BIT(tid)) { | ||
4452 | ret = -EINVAL; | ||
4453 | wl1271_error("cannot enable RX BA session on active " | ||
4454 | "tid: %d", tid); | ||
4455 | break; | ||
4456 | } | ||
4457 | |||
4458 | ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true, | ||
4459 | hlid); | ||
4460 | if (!ret) { | ||
4461 | *ba_bitmap |= BIT(tid); | ||
4462 | wl->ba_rx_session_count++; | ||
4463 | } | ||
4464 | break; | ||
4465 | |||
4466 | case IEEE80211_AMPDU_RX_STOP: | ||
4467 | if (!(*ba_bitmap & BIT(tid))) { | ||
4468 | ret = -EINVAL; | ||
4469 | wl1271_error("no active RX BA session on tid: %d", | ||
4470 | tid); | ||
4471 | break; | ||
4472 | } | ||
4473 | |||
4474 | ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false, | ||
4475 | hlid); | ||
4476 | if (!ret) { | ||
4477 | *ba_bitmap &= ~BIT(tid); | ||
4478 | wl->ba_rx_session_count--; | ||
4479 | } | ||
4480 | break; | ||
4481 | |||
4482 | /* | ||
4483 | * The BA initiator session management in FW independently. | ||
4484 | * Falling break here on purpose for all TX APDU commands. | ||
4485 | */ | ||
4486 | case IEEE80211_AMPDU_TX_START: | ||
4487 | case IEEE80211_AMPDU_TX_STOP: | ||
4488 | case IEEE80211_AMPDU_TX_OPERATIONAL: | ||
4489 | ret = -EINVAL; | ||
4490 | break; | ||
4491 | |||
4492 | default: | ||
4493 | wl1271_error("Incorrect ampdu action id=%x\n", action); | ||
4494 | ret = -EINVAL; | ||
4495 | } | ||
4496 | |||
4497 | wl1271_ps_elp_sleep(wl); | ||
4498 | |||
4499 | out: | ||
4500 | mutex_unlock(&wl->mutex); | ||
4501 | |||
4502 | return ret; | ||
4503 | } | ||
4504 | |||
4505 | static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw, | ||
4506 | struct ieee80211_vif *vif, | ||
4507 | const struct cfg80211_bitrate_mask *mask) | ||
4508 | { | ||
4509 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | ||
4510 | struct wl1271 *wl = hw->priv; | ||
4511 | int i, ret = 0; | ||
4512 | |||
4513 | wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x", | ||
4514 | mask->control[NL80211_BAND_2GHZ].legacy, | ||
4515 | mask->control[NL80211_BAND_5GHZ].legacy); | ||
4516 | |||
4517 | mutex_lock(&wl->mutex); | ||
4518 | |||
4519 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) | ||
4520 | wlvif->bitrate_masks[i] = | ||
4521 | wl1271_tx_enabled_rates_get(wl, | ||
4522 | mask->control[i].legacy, | ||
4523 | i); | ||
4524 | |||
4525 | if (unlikely(wl->state == WL1271_STATE_OFF)) | ||
4526 | goto out; | ||
4527 | |||
4528 | if (wlvif->bss_type == BSS_TYPE_STA_BSS && | ||
4529 | !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) { | ||
4530 | |||
4531 | ret = wl1271_ps_elp_wakeup(wl); | ||
4532 | if (ret < 0) | ||
4533 | goto out; | ||
4534 | |||
4535 | wl1271_set_band_rate(wl, wlvif); | ||
4536 | wlvif->basic_rate = | ||
4537 | wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); | ||
4538 | ret = wl1271_acx_sta_rate_policies(wl, wlvif); | ||
4539 | |||
4540 | wl1271_ps_elp_sleep(wl); | ||
4541 | } | ||
4542 | out: | ||
4543 | mutex_unlock(&wl->mutex); | ||
4544 | |||
4545 | return ret; | ||
4546 | } | ||
4547 | |||
4548 | static void wl12xx_op_channel_switch(struct ieee80211_hw *hw, | ||
4549 | struct ieee80211_channel_switch *ch_switch) | ||
4550 | { | ||
4551 | struct wl1271 *wl = hw->priv; | ||
4552 | struct wl12xx_vif *wlvif; | ||
4553 | int ret; | ||
4554 | |||
4555 | wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch"); | ||
4556 | |||
4557 | wl1271_tx_flush(wl); | ||
4558 | |||
4559 | mutex_lock(&wl->mutex); | ||
4560 | |||
4561 | if (unlikely(wl->state == WL1271_STATE_OFF)) { | ||
4562 | wl12xx_for_each_wlvif_sta(wl, wlvif) { | ||
4563 | struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); | ||
4564 | ieee80211_chswitch_done(vif, false); | ||
4565 | } | ||
4566 | goto out; | ||
4567 | } | ||
4568 | |||
4569 | ret = wl1271_ps_elp_wakeup(wl); | ||
4570 | if (ret < 0) | ||
4571 | goto out; | ||
4572 | |||
4573 | /* TODO: change mac80211 to pass vif as param */ | ||
4574 | wl12xx_for_each_wlvif_sta(wl, wlvif) { | ||
4575 | ret = wl12xx_cmd_channel_switch(wl, wlvif, ch_switch); | ||
4576 | |||
4577 | if (!ret) | ||
4578 | set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags); | ||
4579 | } | ||
4580 | |||
4581 | wl1271_ps_elp_sleep(wl); | ||
4582 | |||
4583 | out: | ||
4584 | mutex_unlock(&wl->mutex); | ||
4585 | } | ||
4586 | |||
4587 | static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw) | ||
4588 | { | ||
4589 | struct wl1271 *wl = hw->priv; | ||
4590 | bool ret = false; | ||
4591 | |||
4592 | mutex_lock(&wl->mutex); | ||
4593 | |||
4594 | if (unlikely(wl->state == WL1271_STATE_OFF)) | ||
4595 | goto out; | ||
4596 | |||
4597 | /* packets are considered pending if in the TX queue or the FW */ | ||
4598 | ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0); | ||
4599 | out: | ||
4600 | mutex_unlock(&wl->mutex); | ||
4601 | |||
4602 | return ret; | ||
4603 | } | ||
4604 | |||
4605 | /* can't be const, mac80211 writes to this */ | ||
4606 | static struct ieee80211_rate wl1271_rates[] = { | ||
4607 | { .bitrate = 10, | ||
4608 | .hw_value = CONF_HW_BIT_RATE_1MBPS, | ||
4609 | .hw_value_short = CONF_HW_BIT_RATE_1MBPS, }, | ||
4610 | { .bitrate = 20, | ||
4611 | .hw_value = CONF_HW_BIT_RATE_2MBPS, | ||
4612 | .hw_value_short = CONF_HW_BIT_RATE_2MBPS, | ||
4613 | .flags = IEEE80211_RATE_SHORT_PREAMBLE }, | ||
4614 | { .bitrate = 55, | ||
4615 | .hw_value = CONF_HW_BIT_RATE_5_5MBPS, | ||
4616 | .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS, | ||
4617 | .flags = IEEE80211_RATE_SHORT_PREAMBLE }, | ||
4618 | { .bitrate = 110, | ||
4619 | .hw_value = CONF_HW_BIT_RATE_11MBPS, | ||
4620 | .hw_value_short = CONF_HW_BIT_RATE_11MBPS, | ||
4621 | .flags = IEEE80211_RATE_SHORT_PREAMBLE }, | ||
4622 | { .bitrate = 60, | ||
4623 | .hw_value = CONF_HW_BIT_RATE_6MBPS, | ||
4624 | .hw_value_short = CONF_HW_BIT_RATE_6MBPS, }, | ||
4625 | { .bitrate = 90, | ||
4626 | .hw_value = CONF_HW_BIT_RATE_9MBPS, | ||
4627 | .hw_value_short = CONF_HW_BIT_RATE_9MBPS, }, | ||
4628 | { .bitrate = 120, | ||
4629 | .hw_value = CONF_HW_BIT_RATE_12MBPS, | ||
4630 | .hw_value_short = CONF_HW_BIT_RATE_12MBPS, }, | ||
4631 | { .bitrate = 180, | ||
4632 | .hw_value = CONF_HW_BIT_RATE_18MBPS, | ||
4633 | .hw_value_short = CONF_HW_BIT_RATE_18MBPS, }, | ||
4634 | { .bitrate = 240, | ||
4635 | .hw_value = CONF_HW_BIT_RATE_24MBPS, | ||
4636 | .hw_value_short = CONF_HW_BIT_RATE_24MBPS, }, | ||
4637 | { .bitrate = 360, | ||
4638 | .hw_value = CONF_HW_BIT_RATE_36MBPS, | ||
4639 | .hw_value_short = CONF_HW_BIT_RATE_36MBPS, }, | ||
4640 | { .bitrate = 480, | ||
4641 | .hw_value = CONF_HW_BIT_RATE_48MBPS, | ||
4642 | .hw_value_short = CONF_HW_BIT_RATE_48MBPS, }, | ||
4643 | { .bitrate = 540, | ||
4644 | .hw_value = CONF_HW_BIT_RATE_54MBPS, | ||
4645 | .hw_value_short = CONF_HW_BIT_RATE_54MBPS, }, | ||
4646 | }; | ||
4647 | |||
4648 | /* can't be const, mac80211 writes to this */ | ||
4649 | static struct ieee80211_channel wl1271_channels[] = { | ||
4650 | { .hw_value = 1, .center_freq = 2412, .max_power = 25 }, | ||
4651 | { .hw_value = 2, .center_freq = 2417, .max_power = 25 }, | ||
4652 | { .hw_value = 3, .center_freq = 2422, .max_power = 25 }, | ||
4653 | { .hw_value = 4, .center_freq = 2427, .max_power = 25 }, | ||
4654 | { .hw_value = 5, .center_freq = 2432, .max_power = 25 }, | ||
4655 | { .hw_value = 6, .center_freq = 2437, .max_power = 25 }, | ||
4656 | { .hw_value = 7, .center_freq = 2442, .max_power = 25 }, | ||
4657 | { .hw_value = 8, .center_freq = 2447, .max_power = 25 }, | ||
4658 | { .hw_value = 9, .center_freq = 2452, .max_power = 25 }, | ||
4659 | { .hw_value = 10, .center_freq = 2457, .max_power = 25 }, | ||
4660 | { .hw_value = 11, .center_freq = 2462, .max_power = 25 }, | ||
4661 | { .hw_value = 12, .center_freq = 2467, .max_power = 25 }, | ||
4662 | { .hw_value = 13, .center_freq = 2472, .max_power = 25 }, | ||
4663 | { .hw_value = 14, .center_freq = 2484, .max_power = 25 }, | ||
4664 | }; | ||
4665 | |||
4666 | /* mapping to indexes for wl1271_rates */ | ||
4667 | static const u8 wl1271_rate_to_idx_2ghz[] = { | ||
4668 | /* MCS rates are used only with 11n */ | ||
4669 | 7, /* CONF_HW_RXTX_RATE_MCS7_SGI */ | ||
4670 | 7, /* CONF_HW_RXTX_RATE_MCS7 */ | ||
4671 | 6, /* CONF_HW_RXTX_RATE_MCS6 */ | ||
4672 | 5, /* CONF_HW_RXTX_RATE_MCS5 */ | ||
4673 | 4, /* CONF_HW_RXTX_RATE_MCS4 */ | ||
4674 | 3, /* CONF_HW_RXTX_RATE_MCS3 */ | ||
4675 | 2, /* CONF_HW_RXTX_RATE_MCS2 */ | ||
4676 | 1, /* CONF_HW_RXTX_RATE_MCS1 */ | ||
4677 | 0, /* CONF_HW_RXTX_RATE_MCS0 */ | ||
4678 | |||
4679 | 11, /* CONF_HW_RXTX_RATE_54 */ | ||
4680 | 10, /* CONF_HW_RXTX_RATE_48 */ | ||
4681 | 9, /* CONF_HW_RXTX_RATE_36 */ | ||
4682 | 8, /* CONF_HW_RXTX_RATE_24 */ | ||
4683 | |||
4684 | /* TI-specific rate */ | ||
4685 | CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */ | ||
4686 | |||
4687 | 7, /* CONF_HW_RXTX_RATE_18 */ | ||
4688 | 6, /* CONF_HW_RXTX_RATE_12 */ | ||
4689 | 3, /* CONF_HW_RXTX_RATE_11 */ | ||
4690 | 5, /* CONF_HW_RXTX_RATE_9 */ | ||
4691 | 4, /* CONF_HW_RXTX_RATE_6 */ | ||
4692 | 2, /* CONF_HW_RXTX_RATE_5_5 */ | ||
4693 | 1, /* CONF_HW_RXTX_RATE_2 */ | ||
4694 | 0 /* CONF_HW_RXTX_RATE_1 */ | ||
4695 | }; | ||
4696 | |||
4697 | /* 11n STA capabilities */ | ||
4698 | #define HW_RX_HIGHEST_RATE 72 | ||
4699 | |||
4700 | #define WL12XX_HT_CAP { \ | ||
4701 | .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \ | ||
4702 | (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \ | ||
4703 | .ht_supported = true, \ | ||
4704 | .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \ | ||
4705 | .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \ | ||
4706 | .mcs = { \ | ||
4707 | .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \ | ||
4708 | .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \ | ||
4709 | .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \ | ||
4710 | }, \ | ||
4711 | } | ||
4712 | |||
4713 | /* can't be const, mac80211 writes to this */ | ||
4714 | static struct ieee80211_supported_band wl1271_band_2ghz = { | ||
4715 | .channels = wl1271_channels, | ||
4716 | .n_channels = ARRAY_SIZE(wl1271_channels), | ||
4717 | .bitrates = wl1271_rates, | ||
4718 | .n_bitrates = ARRAY_SIZE(wl1271_rates), | ||
4719 | .ht_cap = WL12XX_HT_CAP, | ||
4720 | }; | ||
4721 | |||
4722 | /* 5 GHz data rates for WL1273 */ | ||
4723 | static struct ieee80211_rate wl1271_rates_5ghz[] = { | ||
4724 | { .bitrate = 60, | ||
4725 | .hw_value = CONF_HW_BIT_RATE_6MBPS, | ||
4726 | .hw_value_short = CONF_HW_BIT_RATE_6MBPS, }, | ||
4727 | { .bitrate = 90, | ||
4728 | .hw_value = CONF_HW_BIT_RATE_9MBPS, | ||
4729 | .hw_value_short = CONF_HW_BIT_RATE_9MBPS, }, | ||
4730 | { .bitrate = 120, | ||
4731 | .hw_value = CONF_HW_BIT_RATE_12MBPS, | ||
4732 | .hw_value_short = CONF_HW_BIT_RATE_12MBPS, }, | ||
4733 | { .bitrate = 180, | ||
4734 | .hw_value = CONF_HW_BIT_RATE_18MBPS, | ||
4735 | .hw_value_short = CONF_HW_BIT_RATE_18MBPS, }, | ||
4736 | { .bitrate = 240, | ||
4737 | .hw_value = CONF_HW_BIT_RATE_24MBPS, | ||
4738 | .hw_value_short = CONF_HW_BIT_RATE_24MBPS, }, | ||
4739 | { .bitrate = 360, | ||
4740 | .hw_value = CONF_HW_BIT_RATE_36MBPS, | ||
4741 | .hw_value_short = CONF_HW_BIT_RATE_36MBPS, }, | ||
4742 | { .bitrate = 480, | ||
4743 | .hw_value = CONF_HW_BIT_RATE_48MBPS, | ||
4744 | .hw_value_short = CONF_HW_BIT_RATE_48MBPS, }, | ||
4745 | { .bitrate = 540, | ||
4746 | .hw_value = CONF_HW_BIT_RATE_54MBPS, | ||
4747 | .hw_value_short = CONF_HW_BIT_RATE_54MBPS, }, | ||
4748 | }; | ||
4749 | |||
4750 | /* 5 GHz band channels for WL1273 */ | ||
4751 | static struct ieee80211_channel wl1271_channels_5ghz[] = { | ||
4752 | { .hw_value = 7, .center_freq = 5035, .max_power = 25 }, | ||
4753 | { .hw_value = 8, .center_freq = 5040, .max_power = 25 }, | ||
4754 | { .hw_value = 9, .center_freq = 5045, .max_power = 25 }, | ||
4755 | { .hw_value = 11, .center_freq = 5055, .max_power = 25 }, | ||
4756 | { .hw_value = 12, .center_freq = 5060, .max_power = 25 }, | ||
4757 | { .hw_value = 16, .center_freq = 5080, .max_power = 25 }, | ||
4758 | { .hw_value = 34, .center_freq = 5170, .max_power = 25 }, | ||
4759 | { .hw_value = 36, .center_freq = 5180, .max_power = 25 }, | ||
4760 | { .hw_value = 38, .center_freq = 5190, .max_power = 25 }, | ||
4761 | { .hw_value = 40, .center_freq = 5200, .max_power = 25 }, | ||
4762 | { .hw_value = 42, .center_freq = 5210, .max_power = 25 }, | ||
4763 | { .hw_value = 44, .center_freq = 5220, .max_power = 25 }, | ||
4764 | { .hw_value = 46, .center_freq = 5230, .max_power = 25 }, | ||
4765 | { .hw_value = 48, .center_freq = 5240, .max_power = 25 }, | ||
4766 | { .hw_value = 52, .center_freq = 5260, .max_power = 25 }, | ||
4767 | { .hw_value = 56, .center_freq = 5280, .max_power = 25 }, | ||
4768 | { .hw_value = 60, .center_freq = 5300, .max_power = 25 }, | ||
4769 | { .hw_value = 64, .center_freq = 5320, .max_power = 25 }, | ||
4770 | { .hw_value = 100, .center_freq = 5500, .max_power = 25 }, | ||
4771 | { .hw_value = 104, .center_freq = 5520, .max_power = 25 }, | ||
4772 | { .hw_value = 108, .center_freq = 5540, .max_power = 25 }, | ||
4773 | { .hw_value = 112, .center_freq = 5560, .max_power = 25 }, | ||
4774 | { .hw_value = 116, .center_freq = 5580, .max_power = 25 }, | ||
4775 | { .hw_value = 120, .center_freq = 5600, .max_power = 25 }, | ||
4776 | { .hw_value = 124, .center_freq = 5620, .max_power = 25 }, | ||
4777 | { .hw_value = 128, .center_freq = 5640, .max_power = 25 }, | ||
4778 | { .hw_value = 132, .center_freq = 5660, .max_power = 25 }, | ||
4779 | { .hw_value = 136, .center_freq = 5680, .max_power = 25 }, | ||
4780 | { .hw_value = 140, .center_freq = 5700, .max_power = 25 }, | ||
4781 | { .hw_value = 149, .center_freq = 5745, .max_power = 25 }, | ||
4782 | { .hw_value = 153, .center_freq = 5765, .max_power = 25 }, | ||
4783 | { .hw_value = 157, .center_freq = 5785, .max_power = 25 }, | ||
4784 | { .hw_value = 161, .center_freq = 5805, .max_power = 25 }, | ||
4785 | { .hw_value = 165, .center_freq = 5825, .max_power = 25 }, | ||
4786 | }; | ||
4787 | |||
4788 | /* mapping to indexes for wl1271_rates_5ghz */ | ||
4789 | static const u8 wl1271_rate_to_idx_5ghz[] = { | ||
4790 | /* MCS rates are used only with 11n */ | ||
4791 | 7, /* CONF_HW_RXTX_RATE_MCS7_SGI */ | ||
4792 | 7, /* CONF_HW_RXTX_RATE_MCS7 */ | ||
4793 | 6, /* CONF_HW_RXTX_RATE_MCS6 */ | ||
4794 | 5, /* CONF_HW_RXTX_RATE_MCS5 */ | ||
4795 | 4, /* CONF_HW_RXTX_RATE_MCS4 */ | ||
4796 | 3, /* CONF_HW_RXTX_RATE_MCS3 */ | ||
4797 | 2, /* CONF_HW_RXTX_RATE_MCS2 */ | ||
4798 | 1, /* CONF_HW_RXTX_RATE_MCS1 */ | ||
4799 | 0, /* CONF_HW_RXTX_RATE_MCS0 */ | ||
4800 | |||
4801 | 7, /* CONF_HW_RXTX_RATE_54 */ | ||
4802 | 6, /* CONF_HW_RXTX_RATE_48 */ | ||
4803 | 5, /* CONF_HW_RXTX_RATE_36 */ | ||
4804 | 4, /* CONF_HW_RXTX_RATE_24 */ | ||
4805 | |||
4806 | /* TI-specific rate */ | ||
4807 | CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */ | ||
4808 | |||
4809 | 3, /* CONF_HW_RXTX_RATE_18 */ | ||
4810 | 2, /* CONF_HW_RXTX_RATE_12 */ | ||
4811 | CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */ | ||
4812 | 1, /* CONF_HW_RXTX_RATE_9 */ | ||
4813 | 0, /* CONF_HW_RXTX_RATE_6 */ | ||
4814 | CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */ | ||
4815 | CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */ | ||
4816 | CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */ | ||
4817 | }; | ||
4818 | |||
4819 | static struct ieee80211_supported_band wl1271_band_5ghz = { | ||
4820 | .channels = wl1271_channels_5ghz, | ||
4821 | .n_channels = ARRAY_SIZE(wl1271_channels_5ghz), | ||
4822 | .bitrates = wl1271_rates_5ghz, | ||
4823 | .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz), | ||
4824 | .ht_cap = WL12XX_HT_CAP, | ||
4825 | }; | ||
4826 | |||
4827 | static const u8 *wl1271_band_rate_to_idx[] = { | ||
4828 | [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz, | ||
4829 | [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz | ||
4830 | }; | ||
4831 | |||
4832 | static const struct ieee80211_ops wl1271_ops = { | ||
4833 | .start = wl1271_op_start, | ||
4834 | .stop = wl1271_op_stop, | ||
4835 | .add_interface = wl1271_op_add_interface, | ||
4836 | .remove_interface = wl1271_op_remove_interface, | ||
4837 | .change_interface = wl12xx_op_change_interface, | ||
4838 | #ifdef CONFIG_PM | ||
4839 | .suspend = wl1271_op_suspend, | ||
4840 | .resume = wl1271_op_resume, | ||
4841 | #endif | ||
4842 | .config = wl1271_op_config, | ||
4843 | .prepare_multicast = wl1271_op_prepare_multicast, | ||
4844 | .configure_filter = wl1271_op_configure_filter, | ||
4845 | .tx = wl1271_op_tx, | ||
4846 | .set_key = wl1271_op_set_key, | ||
4847 | .hw_scan = wl1271_op_hw_scan, | ||
4848 | .cancel_hw_scan = wl1271_op_cancel_hw_scan, | ||
4849 | .sched_scan_start = wl1271_op_sched_scan_start, | ||
4850 | .sched_scan_stop = wl1271_op_sched_scan_stop, | ||
4851 | .bss_info_changed = wl1271_op_bss_info_changed, | ||
4852 | .set_frag_threshold = wl1271_op_set_frag_threshold, | ||
4853 | .set_rts_threshold = wl1271_op_set_rts_threshold, | ||
4854 | .conf_tx = wl1271_op_conf_tx, | ||
4855 | .get_tsf = wl1271_op_get_tsf, | ||
4856 | .get_survey = wl1271_op_get_survey, | ||
4857 | .sta_state = wl12xx_op_sta_state, | ||
4858 | .ampdu_action = wl1271_op_ampdu_action, | ||
4859 | .tx_frames_pending = wl1271_tx_frames_pending, | ||
4860 | .set_bitrate_mask = wl12xx_set_bitrate_mask, | ||
4861 | .channel_switch = wl12xx_op_channel_switch, | ||
4862 | CFG80211_TESTMODE_CMD(wl1271_tm_cmd) | ||
4863 | }; | ||
4864 | |||
4865 | |||
4866 | u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band) | ||
4867 | { | ||
4868 | u8 idx; | ||
4869 | |||
4870 | BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *)); | ||
4871 | |||
4872 | if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) { | ||
4873 | wl1271_error("Illegal RX rate from HW: %d", rate); | ||
4874 | return 0; | ||
4875 | } | ||
4876 | |||
4877 | idx = wl1271_band_rate_to_idx[band][rate]; | ||
4878 | if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) { | ||
4879 | wl1271_error("Unsupported RX rate from HW: %d", rate); | ||
4880 | return 0; | ||
4881 | } | ||
4882 | |||
4883 | return idx; | ||
4884 | } | ||
4885 | |||
4886 | static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev, | ||
4887 | struct device_attribute *attr, | ||
4888 | char *buf) | ||
4889 | { | ||
4890 | struct wl1271 *wl = dev_get_drvdata(dev); | ||
4891 | ssize_t len; | ||
4892 | |||
4893 | len = PAGE_SIZE; | ||
4894 | |||
4895 | mutex_lock(&wl->mutex); | ||
4896 | len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n", | ||
4897 | wl->sg_enabled); | ||
4898 | mutex_unlock(&wl->mutex); | ||
4899 | |||
4900 | return len; | ||
4901 | |||
4902 | } | ||
4903 | |||
4904 | static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev, | ||
4905 | struct device_attribute *attr, | ||
4906 | const char *buf, size_t count) | ||
4907 | { | ||
4908 | struct wl1271 *wl = dev_get_drvdata(dev); | ||
4909 | unsigned long res; | ||
4910 | int ret; | ||
4911 | |||
4912 | ret = kstrtoul(buf, 10, &res); | ||
4913 | if (ret < 0) { | ||
4914 | wl1271_warning("incorrect value written to bt_coex_mode"); | ||
4915 | return count; | ||
4916 | } | ||
4917 | |||
4918 | mutex_lock(&wl->mutex); | ||
4919 | |||
4920 | res = !!res; | ||
4921 | |||
4922 | if (res == wl->sg_enabled) | ||
4923 | goto out; | ||
4924 | |||
4925 | wl->sg_enabled = res; | ||
4926 | |||
4927 | if (wl->state == WL1271_STATE_OFF) | ||
4928 | goto out; | ||
4929 | |||
4930 | ret = wl1271_ps_elp_wakeup(wl); | ||
4931 | if (ret < 0) | ||
4932 | goto out; | ||
4933 | |||
4934 | wl1271_acx_sg_enable(wl, wl->sg_enabled); | ||
4935 | wl1271_ps_elp_sleep(wl); | ||
4936 | |||
4937 | out: | ||
4938 | mutex_unlock(&wl->mutex); | ||
4939 | return count; | ||
4940 | } | ||
4941 | |||
4942 | static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR, | ||
4943 | wl1271_sysfs_show_bt_coex_state, | ||
4944 | wl1271_sysfs_store_bt_coex_state); | ||
4945 | |||
4946 | static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev, | ||
4947 | struct device_attribute *attr, | ||
4948 | char *buf) | ||
4949 | { | ||
4950 | struct wl1271 *wl = dev_get_drvdata(dev); | ||
4951 | ssize_t len; | ||
4952 | |||
4953 | len = PAGE_SIZE; | ||
4954 | |||
4955 | mutex_lock(&wl->mutex); | ||
4956 | if (wl->hw_pg_ver >= 0) | ||
4957 | len = snprintf(buf, len, "%d\n", wl->hw_pg_ver); | ||
4958 | else | ||
4959 | len = snprintf(buf, len, "n/a\n"); | ||
4960 | mutex_unlock(&wl->mutex); | ||
4961 | |||
4962 | return len; | ||
4963 | } | ||
4964 | |||
4965 | static DEVICE_ATTR(hw_pg_ver, S_IRUGO, | ||
4966 | wl1271_sysfs_show_hw_pg_ver, NULL); | ||
4967 | |||
4968 | static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj, | ||
4969 | struct bin_attribute *bin_attr, | ||
4970 | char *buffer, loff_t pos, size_t count) | ||
4971 | { | ||
4972 | struct device *dev = container_of(kobj, struct device, kobj); | ||
4973 | struct wl1271 *wl = dev_get_drvdata(dev); | ||
4974 | ssize_t len; | ||
4975 | int ret; | ||
4976 | |||
4977 | ret = mutex_lock_interruptible(&wl->mutex); | ||
4978 | if (ret < 0) | ||
4979 | return -ERESTARTSYS; | ||
4980 | |||
4981 | /* Let only one thread read the log at a time, blocking others */ | ||
4982 | while (wl->fwlog_size == 0) { | ||
4983 | DEFINE_WAIT(wait); | ||
4984 | |||
4985 | prepare_to_wait_exclusive(&wl->fwlog_waitq, | ||
4986 | &wait, | ||
4987 | TASK_INTERRUPTIBLE); | ||
4988 | |||
4989 | if (wl->fwlog_size != 0) { | ||
4990 | finish_wait(&wl->fwlog_waitq, &wait); | ||
4991 | break; | ||
4992 | } | ||
4993 | |||
4994 | mutex_unlock(&wl->mutex); | ||
4995 | |||
4996 | schedule(); | ||
4997 | finish_wait(&wl->fwlog_waitq, &wait); | ||
4998 | |||
4999 | if (signal_pending(current)) | ||
5000 | return -ERESTARTSYS; | ||
5001 | |||
5002 | ret = mutex_lock_interruptible(&wl->mutex); | ||
5003 | if (ret < 0) | ||
5004 | return -ERESTARTSYS; | ||
5005 | } | ||
5006 | |||
5007 | /* Check if the fwlog is still valid */ | ||
5008 | if (wl->fwlog_size < 0) { | ||
5009 | mutex_unlock(&wl->mutex); | ||
5010 | return 0; | ||
5011 | } | ||
5012 | |||
5013 | /* Seeking is not supported - old logs are not kept. Disregard pos. */ | ||
5014 | len = min(count, (size_t)wl->fwlog_size); | ||
5015 | wl->fwlog_size -= len; | ||
5016 | memcpy(buffer, wl->fwlog, len); | ||
5017 | |||
5018 | /* Make room for new messages */ | ||
5019 | memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size); | ||
5020 | |||
5021 | mutex_unlock(&wl->mutex); | ||
5022 | |||
5023 | return len; | ||
5024 | } | ||
5025 | |||
5026 | static struct bin_attribute fwlog_attr = { | ||
5027 | .attr = {.name = "fwlog", .mode = S_IRUSR}, | ||
5028 | .read = wl1271_sysfs_read_fwlog, | ||
5029 | }; | ||
5030 | |||
5031 | static bool wl12xx_mac_in_fuse(struct wl1271 *wl) | ||
5032 | { | ||
5033 | bool supported = false; | ||
5034 | u8 major, minor; | ||
5035 | |||
5036 | if (wl->chip.id == CHIP_ID_1283_PG20) { | ||
5037 | major = WL128X_PG_GET_MAJOR(wl->hw_pg_ver); | ||
5038 | minor = WL128X_PG_GET_MINOR(wl->hw_pg_ver); | ||
5039 | |||
5040 | /* in wl128x we have the MAC address if the PG is >= (2, 1) */ | ||
5041 | if (major > 2 || (major == 2 && minor >= 1)) | ||
5042 | supported = true; | ||
5043 | } else { | ||
5044 | major = WL127X_PG_GET_MAJOR(wl->hw_pg_ver); | ||
5045 | minor = WL127X_PG_GET_MINOR(wl->hw_pg_ver); | ||
5046 | |||
5047 | /* in wl127x we have the MAC address if the PG is >= (3, 1) */ | ||
5048 | if (major == 3 && minor >= 1) | ||
5049 | supported = true; | ||
5050 | } | ||
5051 | |||
5052 | wl1271_debug(DEBUG_PROBE, | ||
5053 | "PG Ver major = %d minor = %d, MAC %s present", | ||
5054 | major, minor, supported ? "is" : "is not"); | ||
5055 | |||
5056 | return supported; | ||
5057 | } | ||
5058 | |||
5059 | static void wl12xx_derive_mac_addresses(struct wl1271 *wl, | ||
5060 | u32 oui, u32 nic, int n) | ||
5061 | { | ||
5062 | int i; | ||
5063 | |||
5064 | wl1271_debug(DEBUG_PROBE, "base address: oui %06x nic %06x, n %d", | ||
5065 | oui, nic, n); | ||
5066 | |||
5067 | if (nic + n - 1 > 0xffffff) | ||
5068 | wl1271_warning("NIC part of the MAC address wraps around!"); | ||
5069 | |||
5070 | for (i = 0; i < n; i++) { | ||
5071 | wl->addresses[i].addr[0] = (u8)(oui >> 16); | ||
5072 | wl->addresses[i].addr[1] = (u8)(oui >> 8); | ||
5073 | wl->addresses[i].addr[2] = (u8) oui; | ||
5074 | wl->addresses[i].addr[3] = (u8)(nic >> 16); | ||
5075 | wl->addresses[i].addr[4] = (u8)(nic >> 8); | ||
5076 | wl->addresses[i].addr[5] = (u8) nic; | ||
5077 | nic++; | ||
5078 | } | ||
5079 | |||
5080 | wl->hw->wiphy->n_addresses = n; | ||
5081 | wl->hw->wiphy->addresses = wl->addresses; | ||
5082 | } | ||
5083 | |||
5084 | static void wl12xx_get_fuse_mac(struct wl1271 *wl) | ||
5085 | { | ||
5086 | u32 mac1, mac2; | ||
5087 | |||
5088 | wl1271_set_partition(wl, &wl12xx_part_table[PART_DRPW]); | ||
5089 | |||
5090 | mac1 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_1); | ||
5091 | mac2 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_2); | ||
5092 | |||
5093 | /* these are the two parts of the BD_ADDR */ | ||
5094 | wl->fuse_oui_addr = ((mac2 & 0xffff) << 8) + | ||
5095 | ((mac1 & 0xff000000) >> 24); | ||
5096 | wl->fuse_nic_addr = mac1 & 0xffffff; | ||
5097 | |||
5098 | wl1271_set_partition(wl, &wl12xx_part_table[PART_DOWN]); | ||
5099 | } | ||
5100 | |||
5101 | static int wl12xx_get_hw_info(struct wl1271 *wl) | ||
5102 | { | ||
5103 | int ret; | ||
5104 | u32 die_info; | ||
5105 | |||
5106 | ret = wl12xx_set_power_on(wl); | ||
5107 | if (ret < 0) | ||
5108 | goto out; | ||
5109 | |||
5110 | wl->chip.id = wl1271_read32(wl, CHIP_ID_B); | ||
5111 | |||
5112 | if (wl->chip.id == CHIP_ID_1283_PG20) | ||
5113 | die_info = wl1271_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1); | ||
5114 | else | ||
5115 | die_info = wl1271_top_reg_read(wl, WL127X_REG_FUSE_DATA_2_1); | ||
5116 | |||
5117 | wl->hw_pg_ver = (s8) (die_info & PG_VER_MASK) >> PG_VER_OFFSET; | ||
5118 | |||
5119 | if (!wl12xx_mac_in_fuse(wl)) { | ||
5120 | wl->fuse_oui_addr = 0; | ||
5121 | wl->fuse_nic_addr = 0; | ||
5122 | } else { | ||
5123 | wl12xx_get_fuse_mac(wl); | ||
5124 | } | ||
5125 | |||
5126 | wl1271_power_off(wl); | ||
5127 | out: | ||
5128 | return ret; | ||
5129 | } | ||
5130 | |||
5131 | static int wl1271_register_hw(struct wl1271 *wl) | ||
5132 | { | ||
5133 | int ret; | ||
5134 | u32 oui_addr = 0, nic_addr = 0; | ||
5135 | |||
5136 | if (wl->mac80211_registered) | ||
5137 | return 0; | ||
5138 | |||
5139 | ret = wl12xx_get_hw_info(wl); | ||
5140 | if (ret < 0) { | ||
5141 | wl1271_error("couldn't get hw info"); | ||
5142 | goto out; | ||
5143 | } | ||
5144 | |||
5145 | ret = wl1271_fetch_nvs(wl); | ||
5146 | if (ret == 0) { | ||
5147 | /* NOTE: The wl->nvs->nvs element must be first, in | ||
5148 | * order to simplify the casting, we assume it is at | ||
5149 | * the beginning of the wl->nvs structure. | ||
5150 | */ | ||
5151 | u8 *nvs_ptr = (u8 *)wl->nvs; | ||
5152 | |||
5153 | oui_addr = | ||
5154 | (nvs_ptr[11] << 16) + (nvs_ptr[10] << 8) + nvs_ptr[6]; | ||
5155 | nic_addr = | ||
5156 | (nvs_ptr[5] << 16) + (nvs_ptr[4] << 8) + nvs_ptr[3]; | ||
5157 | } | ||
5158 | |||
5159 | /* if the MAC address is zeroed in the NVS derive from fuse */ | ||
5160 | if (oui_addr == 0 && nic_addr == 0) { | ||
5161 | oui_addr = wl->fuse_oui_addr; | ||
5162 | /* fuse has the BD_ADDR, the WLAN addresses are the next two */ | ||
5163 | nic_addr = wl->fuse_nic_addr + 1; | ||
5164 | } | ||
5165 | |||
5166 | wl12xx_derive_mac_addresses(wl, oui_addr, nic_addr, 2); | ||
5167 | |||
5168 | ret = ieee80211_register_hw(wl->hw); | ||
5169 | if (ret < 0) { | ||
5170 | wl1271_error("unable to register mac80211 hw: %d", ret); | ||
5171 | goto out; | ||
5172 | } | ||
5173 | |||
5174 | wl->mac80211_registered = true; | ||
5175 | |||
5176 | wl1271_debugfs_init(wl); | ||
5177 | |||
5178 | wl1271_notice("loaded"); | ||
5179 | |||
5180 | out: | ||
5181 | return ret; | ||
5182 | } | ||
5183 | |||
5184 | static void wl1271_unregister_hw(struct wl1271 *wl) | ||
5185 | { | ||
5186 | if (wl->plt) | ||
5187 | wl1271_plt_stop(wl); | ||
5188 | |||
5189 | ieee80211_unregister_hw(wl->hw); | ||
5190 | wl->mac80211_registered = false; | ||
5191 | |||
5192 | } | ||
5193 | |||
5194 | static int wl1271_init_ieee80211(struct wl1271 *wl) | ||
5195 | { | ||
5196 | static const u32 cipher_suites[] = { | ||
5197 | WLAN_CIPHER_SUITE_WEP40, | ||
5198 | WLAN_CIPHER_SUITE_WEP104, | ||
5199 | WLAN_CIPHER_SUITE_TKIP, | ||
5200 | WLAN_CIPHER_SUITE_CCMP, | ||
5201 | WL1271_CIPHER_SUITE_GEM, | ||
5202 | }; | ||
5203 | |||
5204 | /* The tx descriptor buffer and the TKIP space. */ | ||
5205 | wl->hw->extra_tx_headroom = WL1271_EXTRA_SPACE_TKIP + | ||
5206 | sizeof(struct wl1271_tx_hw_descr); | ||
5207 | |||
5208 | /* unit us */ | ||
5209 | /* FIXME: find a proper value */ | ||
5210 | wl->hw->channel_change_time = 10000; | ||
5211 | wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval; | ||
5212 | |||
5213 | wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | | ||
5214 | IEEE80211_HW_SUPPORTS_PS | | ||
5215 | IEEE80211_HW_SUPPORTS_DYNAMIC_PS | | ||
5216 | IEEE80211_HW_SUPPORTS_UAPSD | | ||
5217 | IEEE80211_HW_HAS_RATE_CONTROL | | ||
5218 | IEEE80211_HW_CONNECTION_MONITOR | | ||
5219 | IEEE80211_HW_REPORTS_TX_ACK_STATUS | | ||
5220 | IEEE80211_HW_SPECTRUM_MGMT | | ||
5221 | IEEE80211_HW_AP_LINK_PS | | ||
5222 | IEEE80211_HW_AMPDU_AGGREGATION | | ||
5223 | IEEE80211_HW_TX_AMPDU_SETUP_IN_HW | | ||
5224 | IEEE80211_HW_SCAN_WHILE_IDLE; | ||
5225 | |||
5226 | wl->hw->wiphy->cipher_suites = cipher_suites; | ||
5227 | wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); | ||
5228 | |||
5229 | wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | | ||
5230 | BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) | | ||
5231 | BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO); | ||
5232 | wl->hw->wiphy->max_scan_ssids = 1; | ||
5233 | wl->hw->wiphy->max_sched_scan_ssids = 16; | ||
5234 | wl->hw->wiphy->max_match_sets = 16; | ||
5235 | /* | ||
5236 | * Maximum length of elements in scanning probe request templates | ||
5237 | * should be the maximum length possible for a template, without | ||
5238 | * the IEEE80211 header of the template | ||
5239 | */ | ||
5240 | wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE - | ||
5241 | sizeof(struct ieee80211_header); | ||
5242 | |||
5243 | wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE - | ||
5244 | sizeof(struct ieee80211_header); | ||
5245 | |||
5246 | wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; | ||
5247 | |||
5248 | /* make sure all our channels fit in the scanned_ch bitmask */ | ||
5249 | BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) + | ||
5250 | ARRAY_SIZE(wl1271_channels_5ghz) > | ||
5251 | WL1271_MAX_CHANNELS); | ||
5252 | /* | ||
5253 | * We keep local copies of the band structs because we need to | ||
5254 | * modify them on a per-device basis. | ||
5255 | */ | ||
5256 | memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz, | ||
5257 | sizeof(wl1271_band_2ghz)); | ||
5258 | memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz, | ||
5259 | sizeof(wl1271_band_5ghz)); | ||
5260 | |||
5261 | wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = | ||
5262 | &wl->bands[IEEE80211_BAND_2GHZ]; | ||
5263 | wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = | ||
5264 | &wl->bands[IEEE80211_BAND_5GHZ]; | ||
5265 | |||
5266 | wl->hw->queues = 4; | ||
5267 | wl->hw->max_rates = 1; | ||
5268 | |||
5269 | wl->hw->wiphy->reg_notifier = wl1271_reg_notify; | ||
5270 | |||
5271 | /* the FW answers probe-requests in AP-mode */ | ||
5272 | wl->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; | ||
5273 | wl->hw->wiphy->probe_resp_offload = | ||
5274 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | | ||
5275 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | | ||
5276 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P; | ||
5277 | |||
5278 | SET_IEEE80211_DEV(wl->hw, wl->dev); | ||
5279 | |||
5280 | wl->hw->sta_data_size = sizeof(struct wl1271_station); | ||
5281 | wl->hw->vif_data_size = sizeof(struct wl12xx_vif); | ||
5282 | |||
5283 | wl->hw->max_rx_aggregation_subframes = 8; | ||
5284 | |||
5285 | return 0; | ||
5286 | } | ||
5287 | |||
5288 | #define WL1271_DEFAULT_CHANNEL 0 | ||
5289 | |||
5290 | static struct ieee80211_hw *wl1271_alloc_hw(void) | ||
5291 | { | ||
5292 | struct ieee80211_hw *hw; | ||
5293 | struct wl1271 *wl; | ||
5294 | int i, j, ret; | ||
5295 | unsigned int order; | ||
5296 | |||
5297 | BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS); | ||
5298 | |||
5299 | hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops); | ||
5300 | if (!hw) { | ||
5301 | wl1271_error("could not alloc ieee80211_hw"); | ||
5302 | ret = -ENOMEM; | ||
5303 | goto err_hw_alloc; | ||
5304 | } | ||
5305 | |||
5306 | wl = hw->priv; | ||
5307 | memset(wl, 0, sizeof(*wl)); | ||
5308 | |||
5309 | INIT_LIST_HEAD(&wl->wlvif_list); | ||
5310 | |||
5311 | wl->hw = hw; | ||
5312 | |||
5313 | for (i = 0; i < NUM_TX_QUEUES; i++) | ||
5314 | for (j = 0; j < WL12XX_MAX_LINKS; j++) | ||
5315 | skb_queue_head_init(&wl->links[j].tx_queue[i]); | ||
5316 | |||
5317 | skb_queue_head_init(&wl->deferred_rx_queue); | ||
5318 | skb_queue_head_init(&wl->deferred_tx_queue); | ||
5319 | |||
5320 | INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work); | ||
5321 | INIT_WORK(&wl->netstack_work, wl1271_netstack_work); | ||
5322 | INIT_WORK(&wl->tx_work, wl1271_tx_work); | ||
5323 | INIT_WORK(&wl->recovery_work, wl1271_recovery_work); | ||
5324 | INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work); | ||
5325 | INIT_DELAYED_WORK(&wl->tx_watchdog_work, wl12xx_tx_watchdog_work); | ||
5326 | |||
5327 | wl->freezable_wq = create_freezable_workqueue("wl12xx_wq"); | ||
5328 | if (!wl->freezable_wq) { | ||
5329 | ret = -ENOMEM; | ||
5330 | goto err_hw; | ||
5331 | } | ||
5332 | |||
5333 | wl->channel = WL1271_DEFAULT_CHANNEL; | ||
5334 | wl->rx_counter = 0; | ||
5335 | wl->power_level = WL1271_DEFAULT_POWER_LEVEL; | ||
5336 | wl->band = IEEE80211_BAND_2GHZ; | ||
5337 | wl->flags = 0; | ||
5338 | wl->sg_enabled = true; | ||
5339 | wl->hw_pg_ver = -1; | ||
5340 | wl->ap_ps_map = 0; | ||
5341 | wl->ap_fw_ps_map = 0; | ||
5342 | wl->quirks = 0; | ||
5343 | wl->platform_quirks = 0; | ||
5344 | wl->sched_scanning = false; | ||
5345 | wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT; | ||
5346 | wl->system_hlid = WL12XX_SYSTEM_HLID; | ||
5347 | wl->active_sta_count = 0; | ||
5348 | wl->fwlog_size = 0; | ||
5349 | init_waitqueue_head(&wl->fwlog_waitq); | ||
5350 | |||
5351 | /* The system link is always allocated */ | ||
5352 | __set_bit(WL12XX_SYSTEM_HLID, wl->links_map); | ||
5353 | |||
5354 | memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map)); | ||
5355 | for (i = 0; i < ACX_TX_DESCRIPTORS; i++) | ||
5356 | wl->tx_frames[i] = NULL; | ||
5357 | |||
5358 | spin_lock_init(&wl->wl_lock); | ||
5359 | |||
5360 | wl->state = WL1271_STATE_OFF; | ||
5361 | wl->fw_type = WL12XX_FW_TYPE_NONE; | ||
5362 | mutex_init(&wl->mutex); | ||
5363 | |||
5364 | /* Apply default driver configuration. */ | ||
5365 | wl1271_conf_init(wl); | ||
5366 | |||
5367 | order = get_order(WL1271_AGGR_BUFFER_SIZE); | ||
5368 | wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order); | ||
5369 | if (!wl->aggr_buf) { | ||
5370 | ret = -ENOMEM; | ||
5371 | goto err_wq; | ||
5372 | } | ||
5373 | |||
5374 | wl->dummy_packet = wl12xx_alloc_dummy_packet(wl); | ||
5375 | if (!wl->dummy_packet) { | ||
5376 | ret = -ENOMEM; | ||
5377 | goto err_aggr; | ||
5378 | } | ||
5379 | |||
5380 | /* Allocate one page for the FW log */ | ||
5381 | wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL); | ||
5382 | if (!wl->fwlog) { | ||
5383 | ret = -ENOMEM; | ||
5384 | goto err_dummy_packet; | ||
5385 | } | ||
5386 | |||
5387 | wl->mbox = kmalloc(sizeof(*wl->mbox), GFP_DMA); | ||
5388 | if (!wl->mbox) { | ||
5389 | ret = -ENOMEM; | ||
5390 | goto err_fwlog; | ||
5391 | } | ||
5392 | |||
5393 | return hw; | ||
5394 | |||
5395 | err_fwlog: | ||
5396 | free_page((unsigned long)wl->fwlog); | ||
5397 | |||
5398 | err_dummy_packet: | ||
5399 | dev_kfree_skb(wl->dummy_packet); | ||
5400 | |||
5401 | err_aggr: | ||
5402 | free_pages((unsigned long)wl->aggr_buf, order); | ||
5403 | |||
5404 | err_wq: | ||
5405 | destroy_workqueue(wl->freezable_wq); | ||
5406 | |||
5407 | err_hw: | ||
5408 | wl1271_debugfs_exit(wl); | ||
5409 | ieee80211_free_hw(hw); | ||
5410 | |||
5411 | err_hw_alloc: | ||
5412 | |||
5413 | return ERR_PTR(ret); | ||
5414 | } | ||
5415 | |||
5416 | static int wl1271_free_hw(struct wl1271 *wl) | ||
5417 | { | ||
5418 | /* Unblock any fwlog readers */ | ||
5419 | mutex_lock(&wl->mutex); | ||
5420 | wl->fwlog_size = -1; | ||
5421 | wake_up_interruptible_all(&wl->fwlog_waitq); | ||
5422 | mutex_unlock(&wl->mutex); | ||
5423 | |||
5424 | device_remove_bin_file(wl->dev, &fwlog_attr); | ||
5425 | |||
5426 | device_remove_file(wl->dev, &dev_attr_hw_pg_ver); | ||
5427 | |||
5428 | device_remove_file(wl->dev, &dev_attr_bt_coex_state); | ||
5429 | free_page((unsigned long)wl->fwlog); | ||
5430 | dev_kfree_skb(wl->dummy_packet); | ||
5431 | free_pages((unsigned long)wl->aggr_buf, | ||
5432 | get_order(WL1271_AGGR_BUFFER_SIZE)); | ||
5433 | |||
5434 | wl1271_debugfs_exit(wl); | ||
5435 | |||
5436 | vfree(wl->fw); | ||
5437 | wl->fw = NULL; | ||
5438 | wl->fw_type = WL12XX_FW_TYPE_NONE; | ||
5439 | kfree(wl->nvs); | ||
5440 | wl->nvs = NULL; | ||
5441 | |||
5442 | kfree(wl->fw_status); | ||
5443 | kfree(wl->tx_res_if); | ||
5444 | destroy_workqueue(wl->freezable_wq); | ||
5445 | |||
5446 | ieee80211_free_hw(wl->hw); | ||
5447 | |||
5448 | return 0; | ||
5449 | } | ||
5450 | |||
5451 | static irqreturn_t wl12xx_hardirq(int irq, void *cookie) | ||
5452 | { | ||
5453 | struct wl1271 *wl = cookie; | ||
5454 | unsigned long flags; | ||
5455 | |||
5456 | wl1271_debug(DEBUG_IRQ, "IRQ"); | ||
5457 | |||
5458 | /* complete the ELP completion */ | ||
5459 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
5460 | set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags); | ||
5461 | if (wl->elp_compl) { | ||
5462 | complete(wl->elp_compl); | ||
5463 | wl->elp_compl = NULL; | ||
5464 | } | ||
5465 | |||
5466 | if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) { | ||
5467 | /* don't enqueue a work right now. mark it as pending */ | ||
5468 | set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags); | ||
5469 | wl1271_debug(DEBUG_IRQ, "should not enqueue work"); | ||
5470 | disable_irq_nosync(wl->irq); | ||
5471 | pm_wakeup_event(wl->dev, 0); | ||
5472 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
5473 | return IRQ_HANDLED; | ||
5474 | } | ||
5475 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
5476 | |||
5477 | return IRQ_WAKE_THREAD; | ||
5478 | } | ||
5479 | |||
5480 | static int __devinit wl12xx_probe(struct platform_device *pdev) | ||
5481 | { | ||
5482 | struct wl12xx_platform_data *pdata = pdev->dev.platform_data; | ||
5483 | struct ieee80211_hw *hw; | ||
5484 | struct wl1271 *wl; | ||
5485 | unsigned long irqflags; | ||
5486 | int ret = -ENODEV; | ||
5487 | |||
5488 | hw = wl1271_alloc_hw(); | ||
5489 | if (IS_ERR(hw)) { | ||
5490 | wl1271_error("can't allocate hw"); | ||
5491 | ret = PTR_ERR(hw); | ||
5492 | goto out; | ||
5493 | } | ||
5494 | |||
5495 | wl = hw->priv; | ||
5496 | wl->irq = platform_get_irq(pdev, 0); | ||
5497 | wl->ref_clock = pdata->board_ref_clock; | ||
5498 | wl->tcxo_clock = pdata->board_tcxo_clock; | ||
5499 | wl->platform_quirks = pdata->platform_quirks; | ||
5500 | wl->set_power = pdata->set_power; | ||
5501 | wl->dev = &pdev->dev; | ||
5502 | wl->if_ops = pdata->ops; | ||
5503 | |||
5504 | platform_set_drvdata(pdev, wl); | ||
5505 | |||
5506 | if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) | ||
5507 | irqflags = IRQF_TRIGGER_RISING; | ||
5508 | else | ||
5509 | irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT; | ||
5510 | |||
5511 | ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wl1271_irq, | ||
5512 | irqflags, | ||
5513 | pdev->name, wl); | ||
5514 | if (ret < 0) { | ||
5515 | wl1271_error("request_irq() failed: %d", ret); | ||
5516 | goto out_free_hw; | ||
5517 | } | ||
5518 | |||
5519 | ret = enable_irq_wake(wl->irq); | ||
5520 | if (!ret) { | ||
5521 | wl->irq_wake_enabled = true; | ||
5522 | device_init_wakeup(wl->dev, 1); | ||
5523 | if (pdata->pwr_in_suspend) | ||
5524 | hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY; | ||
5525 | |||
5526 | } | ||
5527 | disable_irq(wl->irq); | ||
5528 | |||
5529 | ret = wl1271_init_ieee80211(wl); | ||
5530 | if (ret) | ||
5531 | goto out_irq; | ||
5532 | |||
5533 | ret = wl1271_register_hw(wl); | ||
5534 | if (ret) | ||
5535 | goto out_irq; | ||
5536 | |||
5537 | /* Create sysfs file to control bt coex state */ | ||
5538 | ret = device_create_file(wl->dev, &dev_attr_bt_coex_state); | ||
5539 | if (ret < 0) { | ||
5540 | wl1271_error("failed to create sysfs file bt_coex_state"); | ||
5541 | goto out_irq; | ||
5542 | } | ||
5543 | |||
5544 | /* Create sysfs file to get HW PG version */ | ||
5545 | ret = device_create_file(wl->dev, &dev_attr_hw_pg_ver); | ||
5546 | if (ret < 0) { | ||
5547 | wl1271_error("failed to create sysfs file hw_pg_ver"); | ||
5548 | goto out_bt_coex_state; | ||
5549 | } | ||
5550 | |||
5551 | /* Create sysfs file for the FW log */ | ||
5552 | ret = device_create_bin_file(wl->dev, &fwlog_attr); | ||
5553 | if (ret < 0) { | ||
5554 | wl1271_error("failed to create sysfs file fwlog"); | ||
5555 | goto out_hw_pg_ver; | ||
5556 | } | ||
5557 | |||
5558 | return 0; | ||
5559 | |||
5560 | out_hw_pg_ver: | ||
5561 | device_remove_file(wl->dev, &dev_attr_hw_pg_ver); | ||
5562 | |||
5563 | out_bt_coex_state: | ||
5564 | device_remove_file(wl->dev, &dev_attr_bt_coex_state); | ||
5565 | |||
5566 | out_irq: | ||
5567 | free_irq(wl->irq, wl); | ||
5568 | |||
5569 | out_free_hw: | ||
5570 | wl1271_free_hw(wl); | ||
5571 | |||
5572 | out: | ||
5573 | return ret; | ||
5574 | } | ||
5575 | |||
5576 | static int __devexit wl12xx_remove(struct platform_device *pdev) | ||
5577 | { | ||
5578 | struct wl1271 *wl = platform_get_drvdata(pdev); | ||
5579 | |||
5580 | if (wl->irq_wake_enabled) { | ||
5581 | device_init_wakeup(wl->dev, 0); | ||
5582 | disable_irq_wake(wl->irq); | ||
5583 | } | ||
5584 | wl1271_unregister_hw(wl); | ||
5585 | free_irq(wl->irq, wl); | ||
5586 | wl1271_free_hw(wl); | ||
5587 | |||
5588 | return 0; | ||
5589 | } | ||
5590 | |||
5591 | static const struct platform_device_id wl12xx_id_table[] __devinitconst = { | ||
5592 | { "wl12xx", 0 }, | ||
5593 | { } /* Terminating Entry */ | ||
5594 | }; | ||
5595 | MODULE_DEVICE_TABLE(platform, wl12xx_id_table); | ||
5596 | |||
5597 | static struct platform_driver wl12xx_driver = { | ||
5598 | .probe = wl12xx_probe, | ||
5599 | .remove = __devexit_p(wl12xx_remove), | ||
5600 | .id_table = wl12xx_id_table, | ||
5601 | .driver = { | ||
5602 | .name = "wl12xx_driver", | ||
5603 | .owner = THIS_MODULE, | ||
5604 | } | ||
5605 | }; | ||
5606 | |||
5607 | static int __init wl12xx_init(void) | ||
5608 | { | ||
5609 | return platform_driver_register(&wl12xx_driver); | ||
5610 | } | ||
5611 | module_init(wl12xx_init); | ||
5612 | |||
5613 | static void __exit wl12xx_exit(void) | ||
5614 | { | ||
5615 | platform_driver_unregister(&wl12xx_driver); | ||
5616 | } | ||
5617 | module_exit(wl12xx_exit); | ||
5618 | |||
5619 | u32 wl12xx_debug_level = DEBUG_NONE; | ||
5620 | EXPORT_SYMBOL_GPL(wl12xx_debug_level); | ||
5621 | module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR); | ||
5622 | MODULE_PARM_DESC(debug_level, "wl12xx debugging level"); | ||
5623 | |||
5624 | module_param_named(fwlog, fwlog_param, charp, 0); | ||
5625 | MODULE_PARM_DESC(fwlog, | ||
5626 | "FW logger options: continuous, ondemand, dbgpins or disable"); | ||
5627 | |||
5628 | module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR); | ||
5629 | MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery"); | ||
5630 | |||
5631 | MODULE_LICENSE("GPL"); | ||
5632 | MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>"); | ||
5633 | MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); | ||
diff --git a/drivers/net/wireless/ti/wl12xx/ps.c b/drivers/net/wireless/ti/wl12xx/ps.c new file mode 100644 index 000000000000..78f598b4f97b --- /dev/null +++ b/drivers/net/wireless/ti/wl12xx/ps.c | |||
@@ -0,0 +1,304 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2008-2009 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 | #include "reg.h" | ||
25 | #include "ps.h" | ||
26 | #include "io.h" | ||
27 | #include "tx.h" | ||
28 | #include "debug.h" | ||
29 | |||
30 | #define WL1271_WAKEUP_TIMEOUT 500 | ||
31 | |||
32 | void wl1271_elp_work(struct work_struct *work) | ||
33 | { | ||
34 | struct delayed_work *dwork; | ||
35 | struct wl1271 *wl; | ||
36 | struct wl12xx_vif *wlvif; | ||
37 | |||
38 | dwork = container_of(work, struct delayed_work, work); | ||
39 | wl = container_of(dwork, struct wl1271, elp_work); | ||
40 | |||
41 | wl1271_debug(DEBUG_PSM, "elp work"); | ||
42 | |||
43 | mutex_lock(&wl->mutex); | ||
44 | |||
45 | if (unlikely(wl->state == WL1271_STATE_OFF)) | ||
46 | goto out; | ||
47 | |||
48 | /* our work might have been already cancelled */ | ||
49 | if (unlikely(!test_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags))) | ||
50 | goto out; | ||
51 | |||
52 | if (test_bit(WL1271_FLAG_IN_ELP, &wl->flags)) | ||
53 | goto out; | ||
54 | |||
55 | wl12xx_for_each_wlvif(wl, wlvif) { | ||
56 | if (wlvif->bss_type == BSS_TYPE_AP_BSS) | ||
57 | goto out; | ||
58 | |||
59 | if (!test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags) && | ||
60 | test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) | ||
61 | goto out; | ||
62 | } | ||
63 | |||
64 | wl1271_debug(DEBUG_PSM, "chip to elp"); | ||
65 | wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); | ||
66 | set_bit(WL1271_FLAG_IN_ELP, &wl->flags); | ||
67 | |||
68 | out: | ||
69 | mutex_unlock(&wl->mutex); | ||
70 | } | ||
71 | |||
72 | /* Routines to toggle sleep mode while in ELP */ | ||
73 | void wl1271_ps_elp_sleep(struct wl1271 *wl) | ||
74 | { | ||
75 | struct wl12xx_vif *wlvif; | ||
76 | |||
77 | /* we shouldn't get consecutive sleep requests */ | ||
78 | if (WARN_ON(test_and_set_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags))) | ||
79 | return; | ||
80 | |||
81 | wl12xx_for_each_wlvif(wl, wlvif) { | ||
82 | if (wlvif->bss_type == BSS_TYPE_AP_BSS) | ||
83 | return; | ||
84 | |||
85 | if (!test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags) && | ||
86 | test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) | ||
87 | return; | ||
88 | } | ||
89 | |||
90 | ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, | ||
91 | msecs_to_jiffies(wl->conf.conn.dynamic_ps_timeout)); | ||
92 | } | ||
93 | |||
94 | int wl1271_ps_elp_wakeup(struct wl1271 *wl) | ||
95 | { | ||
96 | DECLARE_COMPLETION_ONSTACK(compl); | ||
97 | unsigned long flags; | ||
98 | int ret; | ||
99 | u32 start_time = jiffies; | ||
100 | bool pending = false; | ||
101 | |||
102 | /* | ||
103 | * we might try to wake up even if we didn't go to sleep | ||
104 | * before (e.g. on boot) | ||
105 | */ | ||
106 | if (!test_and_clear_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags)) | ||
107 | return 0; | ||
108 | |||
109 | /* don't cancel_sync as it might contend for a mutex and deadlock */ | ||
110 | cancel_delayed_work(&wl->elp_work); | ||
111 | |||
112 | if (!test_bit(WL1271_FLAG_IN_ELP, &wl->flags)) | ||
113 | return 0; | ||
114 | |||
115 | wl1271_debug(DEBUG_PSM, "waking up chip from elp"); | ||
116 | |||
117 | /* | ||
118 | * The spinlock is required here to synchronize both the work and | ||
119 | * the completion variable in one entity. | ||
120 | */ | ||
121 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
122 | if (test_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags)) | ||
123 | pending = true; | ||
124 | else | ||
125 | wl->elp_compl = &compl; | ||
126 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
127 | |||
128 | wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP); | ||
129 | |||
130 | if (!pending) { | ||
131 | ret = wait_for_completion_timeout( | ||
132 | &compl, msecs_to_jiffies(WL1271_WAKEUP_TIMEOUT)); | ||
133 | if (ret == 0) { | ||
134 | wl1271_error("ELP wakeup timeout!"); | ||
135 | wl12xx_queue_recovery_work(wl); | ||
136 | ret = -ETIMEDOUT; | ||
137 | goto err; | ||
138 | } else if (ret < 0) { | ||
139 | wl1271_error("ELP wakeup completion error."); | ||
140 | goto err; | ||
141 | } | ||
142 | } | ||
143 | |||
144 | clear_bit(WL1271_FLAG_IN_ELP, &wl->flags); | ||
145 | |||
146 | wl1271_debug(DEBUG_PSM, "wakeup time: %u ms", | ||
147 | jiffies_to_msecs(jiffies - start_time)); | ||
148 | goto out; | ||
149 | |||
150 | err: | ||
151 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
152 | wl->elp_compl = NULL; | ||
153 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
154 | return ret; | ||
155 | |||
156 | out: | ||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
161 | enum wl1271_cmd_ps_mode mode) | ||
162 | { | ||
163 | int ret; | ||
164 | u16 timeout = wl->conf.conn.dynamic_ps_timeout; | ||
165 | |||
166 | switch (mode) { | ||
167 | case STATION_AUTO_PS_MODE: | ||
168 | case STATION_POWER_SAVE_MODE: | ||
169 | wl1271_debug(DEBUG_PSM, "entering psm (mode=%d,timeout=%u)", | ||
170 | mode, timeout); | ||
171 | |||
172 | ret = wl1271_acx_wake_up_conditions(wl, wlvif, | ||
173 | wl->conf.conn.wake_up_event, | ||
174 | wl->conf.conn.listen_interval); | ||
175 | if (ret < 0) { | ||
176 | wl1271_error("couldn't set wake up conditions"); | ||
177 | return ret; | ||
178 | } | ||
179 | |||
180 | ret = wl1271_cmd_ps_mode(wl, wlvif, mode, timeout); | ||
181 | if (ret < 0) | ||
182 | return ret; | ||
183 | |||
184 | set_bit(WLVIF_FLAG_IN_PS, &wlvif->flags); | ||
185 | |||
186 | /* enable beacon early termination. Not relevant for 5GHz */ | ||
187 | if (wlvif->band == IEEE80211_BAND_2GHZ) { | ||
188 | ret = wl1271_acx_bet_enable(wl, wlvif, true); | ||
189 | if (ret < 0) | ||
190 | return ret; | ||
191 | } | ||
192 | break; | ||
193 | case STATION_ACTIVE_MODE: | ||
194 | wl1271_debug(DEBUG_PSM, "leaving psm"); | ||
195 | |||
196 | /* disable beacon early termination */ | ||
197 | if (wlvif->band == IEEE80211_BAND_2GHZ) { | ||
198 | ret = wl1271_acx_bet_enable(wl, wlvif, false); | ||
199 | if (ret < 0) | ||
200 | return ret; | ||
201 | } | ||
202 | |||
203 | ret = wl1271_cmd_ps_mode(wl, wlvif, mode, 0); | ||
204 | if (ret < 0) | ||
205 | return ret; | ||
206 | |||
207 | clear_bit(WLVIF_FLAG_IN_PS, &wlvif->flags); | ||
208 | break; | ||
209 | default: | ||
210 | wl1271_warning("trying to set ps to unsupported mode %d", mode); | ||
211 | ret = -EINVAL; | ||
212 | } | ||
213 | |||
214 | return ret; | ||
215 | } | ||
216 | |||
217 | static void wl1271_ps_filter_frames(struct wl1271 *wl, u8 hlid) | ||
218 | { | ||
219 | int i; | ||
220 | struct sk_buff *skb; | ||
221 | struct ieee80211_tx_info *info; | ||
222 | unsigned long flags; | ||
223 | int filtered[NUM_TX_QUEUES]; | ||
224 | |||
225 | /* filter all frames currently in the low level queues for this hlid */ | ||
226 | for (i = 0; i < NUM_TX_QUEUES; i++) { | ||
227 | filtered[i] = 0; | ||
228 | while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) { | ||
229 | filtered[i]++; | ||
230 | |||
231 | if (WARN_ON(wl12xx_is_dummy_packet(wl, skb))) | ||
232 | continue; | ||
233 | |||
234 | info = IEEE80211_SKB_CB(skb); | ||
235 | info->flags |= IEEE80211_TX_STAT_TX_FILTERED; | ||
236 | info->status.rates[0].idx = -1; | ||
237 | ieee80211_tx_status_ni(wl->hw, skb); | ||
238 | } | ||
239 | } | ||
240 | |||
241 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
242 | for (i = 0; i < NUM_TX_QUEUES; i++) | ||
243 | wl->tx_queue_count[i] -= filtered[i]; | ||
244 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
245 | |||
246 | wl1271_handle_tx_low_watermark(wl); | ||
247 | } | ||
248 | |||
249 | void wl12xx_ps_link_start(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
250 | u8 hlid, bool clean_queues) | ||
251 | { | ||
252 | struct ieee80211_sta *sta; | ||
253 | struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); | ||
254 | |||
255 | if (test_bit(hlid, &wl->ap_ps_map)) | ||
256 | return; | ||
257 | |||
258 | wl1271_debug(DEBUG_PSM, "start mac80211 PSM on hlid %d pkts %d " | ||
259 | "clean_queues %d", hlid, wl->links[hlid].allocated_pkts, | ||
260 | clean_queues); | ||
261 | |||
262 | rcu_read_lock(); | ||
263 | sta = ieee80211_find_sta(vif, wl->links[hlid].addr); | ||
264 | if (!sta) { | ||
265 | wl1271_error("could not find sta %pM for starting ps", | ||
266 | wl->links[hlid].addr); | ||
267 | rcu_read_unlock(); | ||
268 | return; | ||
269 | } | ||
270 | |||
271 | ieee80211_sta_ps_transition_ni(sta, true); | ||
272 | rcu_read_unlock(); | ||
273 | |||
274 | /* do we want to filter all frames from this link's queues? */ | ||
275 | if (clean_queues) | ||
276 | wl1271_ps_filter_frames(wl, hlid); | ||
277 | |||
278 | __set_bit(hlid, &wl->ap_ps_map); | ||
279 | } | ||
280 | |||
281 | void wl12xx_ps_link_end(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid) | ||
282 | { | ||
283 | struct ieee80211_sta *sta; | ||
284 | struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); | ||
285 | |||
286 | if (!test_bit(hlid, &wl->ap_ps_map)) | ||
287 | return; | ||
288 | |||
289 | wl1271_debug(DEBUG_PSM, "end mac80211 PSM on hlid %d", hlid); | ||
290 | |||
291 | __clear_bit(hlid, &wl->ap_ps_map); | ||
292 | |||
293 | rcu_read_lock(); | ||
294 | sta = ieee80211_find_sta(vif, wl->links[hlid].addr); | ||
295 | if (!sta) { | ||
296 | wl1271_error("could not find sta %pM for ending ps", | ||
297 | wl->links[hlid].addr); | ||
298 | goto end; | ||
299 | } | ||
300 | |||
301 | ieee80211_sta_ps_transition_ni(sta, false); | ||
302 | end: | ||
303 | rcu_read_unlock(); | ||
304 | } | ||
diff --git a/drivers/net/wireless/ti/wl12xx/ps.h b/drivers/net/wireless/ti/wl12xx/ps.h new file mode 100644 index 000000000000..5f19d4fbbf27 --- /dev/null +++ b/drivers/net/wireless/ti/wl12xx/ps.h | |||
@@ -0,0 +1,41 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2008-2009 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 __PS_H__ | ||
25 | #define __PS_H__ | ||
26 | |||
27 | #include "wl12xx.h" | ||
28 | #include "acx.h" | ||
29 | |||
30 | int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
31 | enum wl1271_cmd_ps_mode mode); | ||
32 | void wl1271_ps_elp_sleep(struct wl1271 *wl); | ||
33 | int wl1271_ps_elp_wakeup(struct wl1271 *wl); | ||
34 | void wl1271_elp_work(struct work_struct *work); | ||
35 | void wl12xx_ps_link_start(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
36 | u8 hlid, bool clean_queues); | ||
37 | void wl12xx_ps_link_end(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid); | ||
38 | |||
39 | #define WL1271_PS_COMPLETE_TIMEOUT 500 | ||
40 | |||
41 | #endif /* __WL1271_PS_H__ */ | ||
diff --git a/drivers/net/wireless/ti/wl12xx/reg.h b/drivers/net/wireless/ti/wl12xx/reg.h new file mode 100644 index 000000000000..340db324bc26 --- /dev/null +++ b/drivers/net/wireless/ti/wl12xx/reg.h | |||
@@ -0,0 +1,555 @@ | |||
1 | /* | ||
2 | * This file is part of wl12xx | ||
3 | * | ||
4 | * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. | ||
5 | * Copyright (C) 2009 Nokia Corporation | ||
6 | * | ||
7 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef __REG_H__ | ||
26 | #define __REG_H__ | ||
27 | |||
28 | #include <linux/bitops.h> | ||
29 | |||
30 | #define REGISTERS_BASE 0x00300000 | ||
31 | #define DRPW_BASE 0x00310000 | ||
32 | |||
33 | #define REGISTERS_DOWN_SIZE 0x00008800 | ||
34 | #define REGISTERS_WORK_SIZE 0x0000b000 | ||
35 | |||
36 | #define HW_ACCESS_ELP_CTRL_REG_ADDR 0x1FFFC | ||
37 | #define FW_STATUS_ADDR (0x14FC0 + 0xA000) | ||
38 | |||
39 | /* ELP register commands */ | ||
40 | #define ELPCTRL_WAKE_UP 0x1 | ||
41 | #define ELPCTRL_WAKE_UP_WLAN_READY 0x5 | ||
42 | #define ELPCTRL_SLEEP 0x0 | ||
43 | /* ELP WLAN_READY bit */ | ||
44 | #define ELPCTRL_WLAN_READY 0x2 | ||
45 | |||
46 | /*=============================================== | ||
47 | Host Software Reset - 32bit RW | ||
48 | ------------------------------------------ | ||
49 | [31:1] Reserved | ||
50 | 0 SOFT_RESET Soft Reset - When this bit is set, | ||
51 | it holds the Wlan hardware in a soft reset state. | ||
52 | This reset disables all MAC and baseband processor | ||
53 | clocks except the CardBus/PCI interface clock. | ||
54 | It also initializes all MAC state machines except | ||
55 | the host interface. It does not reload the | ||
56 | contents of the EEPROM. When this bit is cleared | ||
57 | (not self-clearing), the Wlan hardware | ||
58 | exits the software reset state. | ||
59 | ===============================================*/ | ||
60 | #define ACX_REG_SLV_SOFT_RESET (REGISTERS_BASE + 0x0000) | ||
61 | |||
62 | #define WL1271_SLV_REG_DATA (REGISTERS_BASE + 0x0008) | ||
63 | #define WL1271_SLV_REG_ADATA (REGISTERS_BASE + 0x000c) | ||
64 | #define WL1271_SLV_MEM_DATA (REGISTERS_BASE + 0x0018) | ||
65 | |||
66 | #define ACX_REG_INTERRUPT_TRIG (REGISTERS_BASE + 0x0474) | ||
67 | #define ACX_REG_INTERRUPT_TRIG_H (REGISTERS_BASE + 0x0478) | ||
68 | |||
69 | /*============================================= | ||
70 | Host Interrupt Mask Register - 32bit (RW) | ||
71 | ------------------------------------------ | ||
72 | Setting a bit in this register masks the | ||
73 | corresponding interrupt to the host. | ||
74 | 0 - RX0 - Rx first dubble buffer Data Interrupt | ||
75 | 1 - TXD - Tx Data Interrupt | ||
76 | 2 - TXXFR - Tx Transfer Interrupt | ||
77 | 3 - RX1 - Rx second dubble buffer Data Interrupt | ||
78 | 4 - RXXFR - Rx Transfer Interrupt | ||
79 | 5 - EVENT_A - Event Mailbox interrupt | ||
80 | 6 - EVENT_B - Event Mailbox interrupt | ||
81 | 7 - WNONHST - Wake On Host Interrupt | ||
82 | 8 - TRACE_A - Debug Trace interrupt | ||
83 | 9 - TRACE_B - Debug Trace interrupt | ||
84 | 10 - CDCMP - Command Complete Interrupt | ||
85 | 11 - | ||
86 | 12 - | ||
87 | 13 - | ||
88 | 14 - ICOMP - Initialization Complete Interrupt | ||
89 | 16 - SG SE - Soft Gemini - Sense enable interrupt | ||
90 | 17 - SG SD - Soft Gemini - Sense disable interrupt | ||
91 | 18 - - | ||
92 | 19 - - | ||
93 | 20 - - | ||
94 | 21- - | ||
95 | Default: 0x0001 | ||
96 | *==============================================*/ | ||
97 | #define ACX_REG_INTERRUPT_MASK (REGISTERS_BASE + 0x04DC) | ||
98 | |||
99 | /*============================================= | ||
100 | Host Interrupt Mask Set 16bit, (Write only) | ||
101 | ------------------------------------------ | ||
102 | Setting a bit in this register sets | ||
103 | the corresponding bin in ACX_HINT_MASK register | ||
104 | without effecting the mask | ||
105 | state of other bits (0 = no effect). | ||
106 | ==============================================*/ | ||
107 | #define ACX_REG_HINT_MASK_SET (REGISTERS_BASE + 0x04E0) | ||
108 | |||
109 | /*============================================= | ||
110 | Host Interrupt Mask Clear 16bit,(Write only) | ||
111 | ------------------------------------------ | ||
112 | Setting a bit in this register clears | ||
113 | the corresponding bin in ACX_HINT_MASK register | ||
114 | without effecting the mask | ||
115 | state of other bits (0 = no effect). | ||
116 | =============================================*/ | ||
117 | #define ACX_REG_HINT_MASK_CLR (REGISTERS_BASE + 0x04E4) | ||
118 | |||
119 | /*============================================= | ||
120 | Host Interrupt Status Nondestructive Read | ||
121 | 16bit,(Read only) | ||
122 | ------------------------------------------ | ||
123 | The host can read this register to determine | ||
124 | which interrupts are active. | ||
125 | Reading this register doesn't | ||
126 | effect its content. | ||
127 | =============================================*/ | ||
128 | #define ACX_REG_INTERRUPT_NO_CLEAR (REGISTERS_BASE + 0x04E8) | ||
129 | |||
130 | /*============================================= | ||
131 | Host Interrupt Status Clear on Read Register | ||
132 | 16bit,(Read only) | ||
133 | ------------------------------------------ | ||
134 | The host can read this register to determine | ||
135 | which interrupts are active. | ||
136 | Reading this register clears it, | ||
137 | thus making all interrupts inactive. | ||
138 | ==============================================*/ | ||
139 | #define ACX_REG_INTERRUPT_CLEAR (REGISTERS_BASE + 0x04F8) | ||
140 | |||
141 | /*============================================= | ||
142 | Host Interrupt Acknowledge Register | ||
143 | 16bit,(Write only) | ||
144 | ------------------------------------------ | ||
145 | The host can set individual bits in this | ||
146 | register to clear (acknowledge) the corresp. | ||
147 | interrupt status bits in the HINT_STS_CLR and | ||
148 | HINT_STS_ND registers, thus making the | ||
149 | assotiated interrupt inactive. (0-no effect) | ||
150 | ==============================================*/ | ||
151 | #define ACX_REG_INTERRUPT_ACK (REGISTERS_BASE + 0x04F0) | ||
152 | |||
153 | #define RX_DRIVER_COUNTER_ADDRESS (REGISTERS_BASE + 0x0538) | ||
154 | |||
155 | /* Device Configuration registers*/ | ||
156 | #define SOR_CFG (REGISTERS_BASE + 0x0800) | ||
157 | |||
158 | /* Embedded ARM CPU Control */ | ||
159 | |||
160 | /*=============================================== | ||
161 | Halt eCPU - 32bit RW | ||
162 | ------------------------------------------ | ||
163 | 0 HALT_ECPU Halt Embedded CPU - This bit is the | ||
164 | compliment of bit 1 (MDATA2) in the SOR_CFG register. | ||
165 | During a hardware reset, this bit holds | ||
166 | the inverse of MDATA2. | ||
167 | When downloading firmware from the host, | ||
168 | set this bit (pull down MDATA2). | ||
169 | The host clears this bit after downloading the firmware into | ||
170 | zero-wait-state SSRAM. | ||
171 | When loading firmware from Flash, clear this bit (pull up MDATA2) | ||
172 | so that the eCPU can run the bootloader code in Flash | ||
173 | HALT_ECPU eCPU State | ||
174 | -------------------- | ||
175 | 1 halt eCPU | ||
176 | 0 enable eCPU | ||
177 | ===============================================*/ | ||
178 | #define ACX_REG_ECPU_CONTROL (REGISTERS_BASE + 0x0804) | ||
179 | |||
180 | #define HI_CFG (REGISTERS_BASE + 0x0808) | ||
181 | |||
182 | /*=============================================== | ||
183 | EEPROM Burst Read Start - 32bit RW | ||
184 | ------------------------------------------ | ||
185 | [31:1] Reserved | ||
186 | 0 ACX_EE_START - EEPROM Burst Read Start 0 | ||
187 | Setting this bit starts a burst read from | ||
188 | the external EEPROM. | ||
189 | If this bit is set (after reset) before an EEPROM read/write, | ||
190 | the burst read starts at EEPROM address 0. | ||
191 | Otherwise, it starts at the address | ||
192 | following the address of the previous access. | ||
193 | TheWlan hardware hardware clears this bit automatically. | ||
194 | |||
195 | Default: 0x00000000 | ||
196 | *================================================*/ | ||
197 | #define ACX_REG_EE_START (REGISTERS_BASE + 0x080C) | ||
198 | |||
199 | #define OCP_POR_CTR (REGISTERS_BASE + 0x09B4) | ||
200 | #define OCP_DATA_WRITE (REGISTERS_BASE + 0x09B8) | ||
201 | #define OCP_DATA_READ (REGISTERS_BASE + 0x09BC) | ||
202 | #define OCP_CMD (REGISTERS_BASE + 0x09C0) | ||
203 | |||
204 | #define WL1271_HOST_WR_ACCESS (REGISTERS_BASE + 0x09F8) | ||
205 | |||
206 | #define CHIP_ID_B (REGISTERS_BASE + 0x5674) | ||
207 | |||
208 | #define CHIP_ID_1271_PG10 (0x4030101) | ||
209 | #define CHIP_ID_1271_PG20 (0x4030111) | ||
210 | #define CHIP_ID_1283_PG10 (0x05030101) | ||
211 | #define CHIP_ID_1283_PG20 (0x05030111) | ||
212 | |||
213 | #define ENABLE (REGISTERS_BASE + 0x5450) | ||
214 | |||
215 | /* Power Management registers */ | ||
216 | #define ELP_CFG_MODE (REGISTERS_BASE + 0x5804) | ||
217 | #define ELP_CMD (REGISTERS_BASE + 0x5808) | ||
218 | #define PLL_CAL_TIME (REGISTERS_BASE + 0x5810) | ||
219 | #define CLK_REQ_TIME (REGISTERS_BASE + 0x5814) | ||
220 | #define CLK_BUF_TIME (REGISTERS_BASE + 0x5818) | ||
221 | |||
222 | #define CFG_PLL_SYNC_CNT (REGISTERS_BASE + 0x5820) | ||
223 | |||
224 | /* Scratch Pad registers*/ | ||
225 | #define SCR_PAD0 (REGISTERS_BASE + 0x5608) | ||
226 | #define SCR_PAD1 (REGISTERS_BASE + 0x560C) | ||
227 | #define SCR_PAD2 (REGISTERS_BASE + 0x5610) | ||
228 | #define SCR_PAD3 (REGISTERS_BASE + 0x5614) | ||
229 | #define SCR_PAD4 (REGISTERS_BASE + 0x5618) | ||
230 | #define SCR_PAD4_SET (REGISTERS_BASE + 0x561C) | ||
231 | #define SCR_PAD4_CLR (REGISTERS_BASE + 0x5620) | ||
232 | #define SCR_PAD5 (REGISTERS_BASE + 0x5624) | ||
233 | #define SCR_PAD5_SET (REGISTERS_BASE + 0x5628) | ||
234 | #define SCR_PAD5_CLR (REGISTERS_BASE + 0x562C) | ||
235 | #define SCR_PAD6 (REGISTERS_BASE + 0x5630) | ||
236 | #define SCR_PAD7 (REGISTERS_BASE + 0x5634) | ||
237 | #define SCR_PAD8 (REGISTERS_BASE + 0x5638) | ||
238 | #define SCR_PAD9 (REGISTERS_BASE + 0x563C) | ||
239 | |||
240 | /* Spare registers*/ | ||
241 | #define SPARE_A1 (REGISTERS_BASE + 0x0994) | ||
242 | #define SPARE_A2 (REGISTERS_BASE + 0x0998) | ||
243 | #define SPARE_A3 (REGISTERS_BASE + 0x099C) | ||
244 | #define SPARE_A4 (REGISTERS_BASE + 0x09A0) | ||
245 | #define SPARE_A5 (REGISTERS_BASE + 0x09A4) | ||
246 | #define SPARE_A6 (REGISTERS_BASE + 0x09A8) | ||
247 | #define SPARE_A7 (REGISTERS_BASE + 0x09AC) | ||
248 | #define SPARE_A8 (REGISTERS_BASE + 0x09B0) | ||
249 | #define SPARE_B1 (REGISTERS_BASE + 0x5420) | ||
250 | #define SPARE_B2 (REGISTERS_BASE + 0x5424) | ||
251 | #define SPARE_B3 (REGISTERS_BASE + 0x5428) | ||
252 | #define SPARE_B4 (REGISTERS_BASE + 0x542C) | ||
253 | #define SPARE_B5 (REGISTERS_BASE + 0x5430) | ||
254 | #define SPARE_B6 (REGISTERS_BASE + 0x5434) | ||
255 | #define SPARE_B7 (REGISTERS_BASE + 0x5438) | ||
256 | #define SPARE_B8 (REGISTERS_BASE + 0x543C) | ||
257 | |||
258 | #define PLL_PARAMETERS (REGISTERS_BASE + 0x6040) | ||
259 | #define WU_COUNTER_PAUSE (REGISTERS_BASE + 0x6008) | ||
260 | #define WELP_ARM_COMMAND (REGISTERS_BASE + 0x6100) | ||
261 | #define DRPW_SCRATCH_START (DRPW_BASE + 0x002C) | ||
262 | |||
263 | |||
264 | #define ACX_SLV_SOFT_RESET_BIT BIT(1) | ||
265 | #define ACX_REG_EEPROM_START_BIT BIT(1) | ||
266 | |||
267 | /* Command/Information Mailbox Pointers */ | ||
268 | |||
269 | /*=============================================== | ||
270 | Command Mailbox Pointer - 32bit RW | ||
271 | ------------------------------------------ | ||
272 | This register holds the start address of | ||
273 | the command mailbox located in the Wlan hardware memory. | ||
274 | The host must read this pointer after a reset to | ||
275 | find the location of the command mailbox. | ||
276 | The Wlan hardware initializes the command mailbox | ||
277 | pointer with the default address of the command mailbox. | ||
278 | The command mailbox pointer is not valid until after | ||
279 | the host receives the Init Complete interrupt from | ||
280 | the Wlan hardware. | ||
281 | ===============================================*/ | ||
282 | #define REG_COMMAND_MAILBOX_PTR (SCR_PAD0) | ||
283 | |||
284 | /*=============================================== | ||
285 | Information Mailbox Pointer - 32bit RW | ||
286 | ------------------------------------------ | ||
287 | This register holds the start address of | ||
288 | the information mailbox located in the Wlan hardware memory. | ||
289 | The host must read this pointer after a reset to find | ||
290 | the location of the information mailbox. | ||
291 | The Wlan hardware initializes the information mailbox pointer | ||
292 | with the default address of the information mailbox. | ||
293 | The information mailbox pointer is not valid | ||
294 | until after the host receives the Init Complete interrupt from | ||
295 | the Wlan hardware. | ||
296 | ===============================================*/ | ||
297 | #define REG_EVENT_MAILBOX_PTR (SCR_PAD1) | ||
298 | |||
299 | /*=============================================== | ||
300 | EEPROM Read/Write Request 32bit RW | ||
301 | ------------------------------------------ | ||
302 | 1 EE_READ - EEPROM Read Request 1 - Setting this bit | ||
303 | loads a single byte of data into the EE_DATA | ||
304 | register from the EEPROM location specified in | ||
305 | the EE_ADDR register. | ||
306 | The Wlan hardware hardware clears this bit automatically. | ||
307 | EE_DATA is valid when this bit is cleared. | ||
308 | |||
309 | 0 EE_WRITE - EEPROM Write Request - Setting this bit | ||
310 | writes a single byte of data from the EE_DATA register into the | ||
311 | EEPROM location specified in the EE_ADDR register. | ||
312 | The Wlan hardware hardware clears this bit automatically. | ||
313 | *===============================================*/ | ||
314 | #define ACX_EE_CTL_REG EE_CTL | ||
315 | #define EE_WRITE 0x00000001ul | ||
316 | #define EE_READ 0x00000002ul | ||
317 | |||
318 | /*=============================================== | ||
319 | EEPROM Address - 32bit RW | ||
320 | ------------------------------------------ | ||
321 | This register specifies the address | ||
322 | within the EEPROM from/to which to read/write data. | ||
323 | ===============================================*/ | ||
324 | #define ACX_EE_ADDR_REG EE_ADDR | ||
325 | |||
326 | /*=============================================== | ||
327 | EEPROM Data - 32bit RW | ||
328 | ------------------------------------------ | ||
329 | This register either holds the read 8 bits of | ||
330 | data from the EEPROM or the write data | ||
331 | to be written to the EEPROM. | ||
332 | ===============================================*/ | ||
333 | #define ACX_EE_DATA_REG EE_DATA | ||
334 | |||
335 | /*=============================================== | ||
336 | EEPROM Base Address - 32bit RW | ||
337 | ------------------------------------------ | ||
338 | This register holds the upper nine bits | ||
339 | [23:15] of the 24-bit Wlan hardware memory | ||
340 | address for burst reads from EEPROM accesses. | ||
341 | The EEPROM provides the lower 15 bits of this address. | ||
342 | The MSB of the address from the EEPROM is ignored. | ||
343 | ===============================================*/ | ||
344 | #define ACX_EE_CFG EE_CFG | ||
345 | |||
346 | /*=============================================== | ||
347 | GPIO Output Values -32bit, RW | ||
348 | ------------------------------------------ | ||
349 | [31:16] Reserved | ||
350 | [15: 0] Specify the output values (at the output driver inputs) for | ||
351 | GPIO[15:0], respectively. | ||
352 | ===============================================*/ | ||
353 | #define ACX_GPIO_OUT_REG GPIO_OUT | ||
354 | #define ACX_MAX_GPIO_LINES 15 | ||
355 | |||
356 | /*=============================================== | ||
357 | Contention window -32bit, RW | ||
358 | ------------------------------------------ | ||
359 | [31:26] Reserved | ||
360 | [25:16] Max (0x3ff) | ||
361 | [15:07] Reserved | ||
362 | [06:00] Current contention window value - default is 0x1F | ||
363 | ===============================================*/ | ||
364 | #define ACX_CONT_WIND_CFG_REG CONT_WIND_CFG | ||
365 | #define ACX_CONT_WIND_MIN_MASK 0x0000007f | ||
366 | #define ACX_CONT_WIND_MAX 0x03ff0000 | ||
367 | |||
368 | /*=============================================== | ||
369 | HI_CFG Interface Configuration Register Values | ||
370 | ------------------------------------------ | ||
371 | ===============================================*/ | ||
372 | #define HI_CFG_UART_ENABLE 0x00000004 | ||
373 | #define HI_CFG_RST232_ENABLE 0x00000008 | ||
374 | #define HI_CFG_CLOCK_REQ_SELECT 0x00000010 | ||
375 | #define HI_CFG_HOST_INT_ENABLE 0x00000020 | ||
376 | #define HI_CFG_VLYNQ_OUTPUT_ENABLE 0x00000040 | ||
377 | #define HI_CFG_HOST_INT_ACTIVE_LOW 0x00000080 | ||
378 | #define HI_CFG_UART_TX_OUT_GPIO_15 0x00000100 | ||
379 | #define HI_CFG_UART_TX_OUT_GPIO_14 0x00000200 | ||
380 | #define HI_CFG_UART_TX_OUT_GPIO_7 0x00000400 | ||
381 | |||
382 | #define HI_CFG_DEF_VAL \ | ||
383 | (HI_CFG_UART_ENABLE | \ | ||
384 | HI_CFG_RST232_ENABLE | \ | ||
385 | HI_CFG_CLOCK_REQ_SELECT | \ | ||
386 | HI_CFG_HOST_INT_ENABLE) | ||
387 | |||
388 | #define REF_FREQ_19_2 0 | ||
389 | #define REF_FREQ_26_0 1 | ||
390 | #define REF_FREQ_38_4 2 | ||
391 | #define REF_FREQ_40_0 3 | ||
392 | #define REF_FREQ_33_6 4 | ||
393 | #define REF_FREQ_NUM 5 | ||
394 | |||
395 | #define LUT_PARAM_INTEGER_DIVIDER 0 | ||
396 | #define LUT_PARAM_FRACTIONAL_DIVIDER 1 | ||
397 | #define LUT_PARAM_ATTN_BB 2 | ||
398 | #define LUT_PARAM_ALPHA_BB 3 | ||
399 | #define LUT_PARAM_STOP_TIME_BB 4 | ||
400 | #define LUT_PARAM_BB_PLL_LOOP_FILTER 5 | ||
401 | #define LUT_PARAM_NUM 6 | ||
402 | |||
403 | #define ACX_EEPROMLESS_IND_REG (SCR_PAD4) | ||
404 | #define USE_EEPROM 0 | ||
405 | #define SOFT_RESET_MAX_TIME 1000000 | ||
406 | #define SOFT_RESET_STALL_TIME 1000 | ||
407 | #define NVS_DATA_BUNDARY_ALIGNMENT 4 | ||
408 | |||
409 | |||
410 | /* Firmware image load chunk size */ | ||
411 | #define CHUNK_SIZE 16384 | ||
412 | |||
413 | /* Firmware image header size */ | ||
414 | #define FW_HDR_SIZE 8 | ||
415 | |||
416 | #define ECPU_CONTROL_HALT 0x00000101 | ||
417 | |||
418 | |||
419 | /****************************************************************************** | ||
420 | |||
421 | CHANNELS, BAND & REG DOMAINS definitions | ||
422 | |||
423 | ******************************************************************************/ | ||
424 | |||
425 | |||
426 | enum { | ||
427 | RADIO_BAND_2_4GHZ = 0, /* 2.4 Ghz band */ | ||
428 | RADIO_BAND_5GHZ = 1, /* 5 Ghz band */ | ||
429 | RADIO_BAND_JAPAN_4_9_GHZ = 2, | ||
430 | DEFAULT_BAND = RADIO_BAND_2_4GHZ, | ||
431 | INVALID_BAND = 0xFE, | ||
432 | MAX_RADIO_BANDS = 0xFF | ||
433 | }; | ||
434 | |||
435 | #define SHORT_PREAMBLE_BIT BIT(0) /* CCK or Barker depending on the rate */ | ||
436 | #define OFDM_RATE_BIT BIT(6) | ||
437 | #define PBCC_RATE_BIT BIT(7) | ||
438 | |||
439 | enum { | ||
440 | CCK_LONG = 0, | ||
441 | CCK_SHORT = SHORT_PREAMBLE_BIT, | ||
442 | PBCC_LONG = PBCC_RATE_BIT, | ||
443 | PBCC_SHORT = PBCC_RATE_BIT | SHORT_PREAMBLE_BIT, | ||
444 | OFDM = OFDM_RATE_BIT | ||
445 | }; | ||
446 | |||
447 | /****************************************************************************** | ||
448 | |||
449 | Transmit-Descriptor RATE-SET field definitions... | ||
450 | |||
451 | Define a new "Rate-Set" for TX path that incorporates the | ||
452 | Rate & Modulation info into a single 16-bit field. | ||
453 | |||
454 | TxdRateSet_t: | ||
455 | b15 - Indicates Preamble type (1=SHORT, 0=LONG). | ||
456 | Notes: | ||
457 | Must be LONG (0) for 1Mbps rate. | ||
458 | Does not apply (set to 0) for RevG-OFDM rates. | ||
459 | b14 - Indicates PBCC encoding (1=PBCC, 0=not). | ||
460 | Notes: | ||
461 | Does not apply (set to 0) for rates 1 and 2 Mbps. | ||
462 | Does not apply (set to 0) for RevG-OFDM rates. | ||
463 | b13 - Unused (set to 0). | ||
464 | b12-b0 - Supported Rate indicator bits as defined below. | ||
465 | |||
466 | ******************************************************************************/ | ||
467 | |||
468 | |||
469 | /************************************************************************* | ||
470 | |||
471 | Interrupt Trigger Register (Host -> WiLink) | ||
472 | |||
473 | **************************************************************************/ | ||
474 | |||
475 | /* Hardware to Embedded CPU Interrupts - first 32-bit register set */ | ||
476 | |||
477 | /* | ||
478 | * Host Command Interrupt. Setting this bit masks | ||
479 | * the interrupt that the host issues to inform | ||
480 | * the FW that it has sent a command | ||
481 | * to the Wlan hardware Command Mailbox. | ||
482 | */ | ||
483 | #define INTR_TRIG_CMD BIT(0) | ||
484 | |||
485 | /* | ||
486 | * Host Event Acknowlegde Interrupt. The host | ||
487 | * sets this bit to acknowledge that it received | ||
488 | * the unsolicited information from the event | ||
489 | * mailbox. | ||
490 | */ | ||
491 | #define INTR_TRIG_EVENT_ACK BIT(1) | ||
492 | |||
493 | /* | ||
494 | * The host sets this bit to inform the Wlan | ||
495 | * FW that a TX packet is in the XFER | ||
496 | * Buffer #0. | ||
497 | */ | ||
498 | #define INTR_TRIG_TX_PROC0 BIT(2) | ||
499 | |||
500 | /* | ||
501 | * The host sets this bit to inform the FW | ||
502 | * that it read a packet from RX XFER | ||
503 | * Buffer #0. | ||
504 | */ | ||
505 | #define INTR_TRIG_RX_PROC0 BIT(3) | ||
506 | |||
507 | #define INTR_TRIG_DEBUG_ACK BIT(4) | ||
508 | |||
509 | #define INTR_TRIG_STATE_CHANGED BIT(5) | ||
510 | |||
511 | |||
512 | /* Hardware to Embedded CPU Interrupts - second 32-bit register set */ | ||
513 | |||
514 | /* | ||
515 | * The host sets this bit to inform the FW | ||
516 | * that it read a packet from RX XFER | ||
517 | * Buffer #1. | ||
518 | */ | ||
519 | #define INTR_TRIG_RX_PROC1 BIT(17) | ||
520 | |||
521 | /* | ||
522 | * The host sets this bit to inform the Wlan | ||
523 | * hardware that a TX packet is in the XFER | ||
524 | * Buffer #1. | ||
525 | */ | ||
526 | #define INTR_TRIG_TX_PROC1 BIT(18) | ||
527 | |||
528 | #define WL127X_REG_FUSE_DATA_2_1 0x050a | ||
529 | #define WL128X_REG_FUSE_DATA_2_1 0x2152 | ||
530 | #define PG_VER_MASK 0x3c | ||
531 | #define PG_VER_OFFSET 2 | ||
532 | |||
533 | #define WL127X_PG_MAJOR_VER_MASK 0x3 | ||
534 | #define WL127X_PG_MAJOR_VER_OFFSET 0x0 | ||
535 | #define WL127X_PG_MINOR_VER_MASK 0xc | ||
536 | #define WL127X_PG_MINOR_VER_OFFSET 0x2 | ||
537 | |||
538 | #define WL128X_PG_MAJOR_VER_MASK 0xc | ||
539 | #define WL128X_PG_MAJOR_VER_OFFSET 0x2 | ||
540 | #define WL128X_PG_MINOR_VER_MASK 0x3 | ||
541 | #define WL128X_PG_MINOR_VER_OFFSET 0x0 | ||
542 | |||
543 | #define WL127X_PG_GET_MAJOR(pg_ver) ((pg_ver & WL127X_PG_MAJOR_VER_MASK) >> \ | ||
544 | WL127X_PG_MAJOR_VER_OFFSET) | ||
545 | #define WL127X_PG_GET_MINOR(pg_ver) ((pg_ver & WL127X_PG_MINOR_VER_MASK) >> \ | ||
546 | WL127X_PG_MINOR_VER_OFFSET) | ||
547 | #define WL128X_PG_GET_MAJOR(pg_ver) ((pg_ver & WL128X_PG_MAJOR_VER_MASK) >> \ | ||
548 | WL128X_PG_MAJOR_VER_OFFSET) | ||
549 | #define WL128X_PG_GET_MINOR(pg_ver) ((pg_ver & WL128X_PG_MINOR_VER_MASK) >> \ | ||
550 | WL128X_PG_MINOR_VER_OFFSET) | ||
551 | |||
552 | #define WL12XX_REG_FUSE_BD_ADDR_1 0x00310eb4 | ||
553 | #define WL12XX_REG_FUSE_BD_ADDR_2 0x00310eb8 | ||
554 | |||
555 | #endif | ||
diff --git a/drivers/net/wireless/ti/wl12xx/rx.c b/drivers/net/wireless/ti/wl12xx/rx.c new file mode 100644 index 000000000000..cfa6071704c5 --- /dev/null +++ b/drivers/net/wireless/ti/wl12xx/rx.c | |||
@@ -0,0 +1,284 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2009 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 | #include <linux/gfp.h> | ||
25 | #include <linux/sched.h> | ||
26 | |||
27 | #include "wl12xx.h" | ||
28 | #include "debug.h" | ||
29 | #include "acx.h" | ||
30 | #include "reg.h" | ||
31 | #include "rx.h" | ||
32 | #include "tx.h" | ||
33 | #include "io.h" | ||
34 | |||
35 | static u8 wl12xx_rx_get_mem_block(struct wl12xx_fw_status *status, | ||
36 | u32 drv_rx_counter) | ||
37 | { | ||
38 | return le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) & | ||
39 | RX_MEM_BLOCK_MASK; | ||
40 | } | ||
41 | |||
42 | static u32 wl12xx_rx_get_buf_size(struct wl12xx_fw_status *status, | ||
43 | u32 drv_rx_counter) | ||
44 | { | ||
45 | return (le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) & | ||
46 | RX_BUF_SIZE_MASK) >> RX_BUF_SIZE_SHIFT_DIV; | ||
47 | } | ||
48 | |||
49 | static bool wl12xx_rx_get_unaligned(struct wl12xx_fw_status *status, | ||
50 | u32 drv_rx_counter) | ||
51 | { | ||
52 | /* Convert the value to bool */ | ||
53 | return !!(le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) & | ||
54 | RX_BUF_UNALIGNED_PAYLOAD); | ||
55 | } | ||
56 | |||
57 | static void wl1271_rx_status(struct wl1271 *wl, | ||
58 | struct wl1271_rx_descriptor *desc, | ||
59 | struct ieee80211_rx_status *status, | ||
60 | u8 beacon) | ||
61 | { | ||
62 | memset(status, 0, sizeof(struct ieee80211_rx_status)); | ||
63 | |||
64 | if ((desc->flags & WL1271_RX_DESC_BAND_MASK) == WL1271_RX_DESC_BAND_BG) | ||
65 | status->band = IEEE80211_BAND_2GHZ; | ||
66 | else | ||
67 | status->band = IEEE80211_BAND_5GHZ; | ||
68 | |||
69 | status->rate_idx = wl1271_rate_to_idx(desc->rate, status->band); | ||
70 | |||
71 | /* 11n support */ | ||
72 | if (desc->rate <= CONF_HW_RXTX_RATE_MCS0) | ||
73 | status->flag |= RX_FLAG_HT; | ||
74 | |||
75 | status->signal = desc->rssi; | ||
76 | |||
77 | /* | ||
78 | * FIXME: In wl1251, the SNR should be divided by two. In wl1271 we | ||
79 | * need to divide by two for now, but TI has been discussing about | ||
80 | * changing it. This needs to be rechecked. | ||
81 | */ | ||
82 | wl->noise = desc->rssi - (desc->snr >> 1); | ||
83 | |||
84 | status->freq = ieee80211_channel_to_frequency(desc->channel, | ||
85 | status->band); | ||
86 | |||
87 | if (desc->flags & WL1271_RX_DESC_ENCRYPT_MASK) { | ||
88 | u8 desc_err_code = desc->status & WL1271_RX_DESC_STATUS_MASK; | ||
89 | |||
90 | status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED | | ||
91 | RX_FLAG_DECRYPTED; | ||
92 | |||
93 | if (unlikely(desc_err_code == WL1271_RX_DESC_MIC_FAIL)) { | ||
94 | status->flag |= RX_FLAG_MMIC_ERROR; | ||
95 | wl1271_warning("Michael MIC error"); | ||
96 | } | ||
97 | } | ||
98 | } | ||
99 | |||
100 | static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, | ||
101 | bool unaligned, u8 *hlid) | ||
102 | { | ||
103 | struct wl1271_rx_descriptor *desc; | ||
104 | struct sk_buff *skb; | ||
105 | struct ieee80211_hdr *hdr; | ||
106 | u8 *buf; | ||
107 | u8 beacon = 0; | ||
108 | u8 is_data = 0; | ||
109 | u8 reserved = unaligned ? NET_IP_ALIGN : 0; | ||
110 | u16 seq_num; | ||
111 | |||
112 | /* | ||
113 | * In PLT mode we seem to get frames and mac80211 warns about them, | ||
114 | * workaround this by not retrieving them at all. | ||
115 | */ | ||
116 | if (unlikely(wl->plt)) | ||
117 | return -EINVAL; | ||
118 | |||
119 | /* the data read starts with the descriptor */ | ||
120 | desc = (struct wl1271_rx_descriptor *) data; | ||
121 | |||
122 | if (desc->packet_class == WL12XX_RX_CLASS_LOGGER) { | ||
123 | size_t len = length - sizeof(*desc); | ||
124 | wl12xx_copy_fwlog(wl, data + sizeof(*desc), len); | ||
125 | wake_up_interruptible(&wl->fwlog_waitq); | ||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | switch (desc->status & WL1271_RX_DESC_STATUS_MASK) { | ||
130 | /* discard corrupted packets */ | ||
131 | case WL1271_RX_DESC_DRIVER_RX_Q_FAIL: | ||
132 | case WL1271_RX_DESC_DECRYPT_FAIL: | ||
133 | wl1271_warning("corrupted packet in RX with status: 0x%x", | ||
134 | desc->status & WL1271_RX_DESC_STATUS_MASK); | ||
135 | return -EINVAL; | ||
136 | case WL1271_RX_DESC_SUCCESS: | ||
137 | case WL1271_RX_DESC_MIC_FAIL: | ||
138 | break; | ||
139 | default: | ||
140 | wl1271_error("invalid RX descriptor status: 0x%x", | ||
141 | desc->status & WL1271_RX_DESC_STATUS_MASK); | ||
142 | return -EINVAL; | ||
143 | } | ||
144 | |||
145 | /* skb length not included rx descriptor */ | ||
146 | skb = __dev_alloc_skb(length + reserved - sizeof(*desc), GFP_KERNEL); | ||
147 | if (!skb) { | ||
148 | wl1271_error("Couldn't allocate RX frame"); | ||
149 | return -ENOMEM; | ||
150 | } | ||
151 | |||
152 | /* reserve the unaligned payload(if any) */ | ||
153 | skb_reserve(skb, reserved); | ||
154 | |||
155 | buf = skb_put(skb, length - sizeof(*desc)); | ||
156 | |||
157 | /* | ||
158 | * Copy packets from aggregation buffer to the skbs without rx | ||
159 | * descriptor and with packet payload aligned care. In case of unaligned | ||
160 | * packets copy the packets in offset of 2 bytes guarantee IP header | ||
161 | * payload aligned to 4 bytes. | ||
162 | */ | ||
163 | memcpy(buf, data + sizeof(*desc), length - sizeof(*desc)); | ||
164 | *hlid = desc->hlid; | ||
165 | |||
166 | hdr = (struct ieee80211_hdr *)skb->data; | ||
167 | if (ieee80211_is_beacon(hdr->frame_control)) | ||
168 | beacon = 1; | ||
169 | if (ieee80211_is_data_present(hdr->frame_control)) | ||
170 | is_data = 1; | ||
171 | |||
172 | wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon); | ||
173 | |||
174 | seq_num = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; | ||
175 | wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s seq %d hlid %d", skb, | ||
176 | skb->len - desc->pad_len, | ||
177 | beacon ? "beacon" : "", | ||
178 | seq_num, *hlid); | ||
179 | |||
180 | skb_trim(skb, skb->len - desc->pad_len); | ||
181 | |||
182 | skb_queue_tail(&wl->deferred_rx_queue, skb); | ||
183 | queue_work(wl->freezable_wq, &wl->netstack_work); | ||
184 | |||
185 | return is_data; | ||
186 | } | ||
187 | |||
188 | void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status) | ||
189 | { | ||
190 | struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map; | ||
191 | unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0}; | ||
192 | u32 buf_size; | ||
193 | u32 fw_rx_counter = status->fw_rx_counter & NUM_RX_PKT_DESC_MOD_MASK; | ||
194 | u32 drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK; | ||
195 | u32 rx_counter; | ||
196 | u32 mem_block; | ||
197 | u32 pkt_length; | ||
198 | u32 pkt_offset; | ||
199 | u8 hlid; | ||
200 | bool unaligned = false; | ||
201 | |||
202 | while (drv_rx_counter != fw_rx_counter) { | ||
203 | buf_size = 0; | ||
204 | rx_counter = drv_rx_counter; | ||
205 | while (rx_counter != fw_rx_counter) { | ||
206 | pkt_length = wl12xx_rx_get_buf_size(status, rx_counter); | ||
207 | if (buf_size + pkt_length > WL1271_AGGR_BUFFER_SIZE) | ||
208 | break; | ||
209 | buf_size += pkt_length; | ||
210 | rx_counter++; | ||
211 | rx_counter &= NUM_RX_PKT_DESC_MOD_MASK; | ||
212 | } | ||
213 | |||
214 | if (buf_size == 0) { | ||
215 | wl1271_warning("received empty data"); | ||
216 | break; | ||
217 | } | ||
218 | |||
219 | if (wl->chip.id != CHIP_ID_1283_PG20) { | ||
220 | /* | ||
221 | * Choose the block we want to read | ||
222 | * For aggregated packets, only the first memory block | ||
223 | * should be retrieved. The FW takes care of the rest. | ||
224 | */ | ||
225 | mem_block = wl12xx_rx_get_mem_block(status, | ||
226 | drv_rx_counter); | ||
227 | |||
228 | wl->rx_mem_pool_addr.addr = (mem_block << 8) + | ||
229 | le32_to_cpu(wl_mem_map->packet_memory_pool_start); | ||
230 | |||
231 | wl->rx_mem_pool_addr.addr_extra = | ||
232 | wl->rx_mem_pool_addr.addr + 4; | ||
233 | |||
234 | wl1271_write(wl, WL1271_SLV_REG_DATA, | ||
235 | &wl->rx_mem_pool_addr, | ||
236 | sizeof(wl->rx_mem_pool_addr), false); | ||
237 | } | ||
238 | |||
239 | /* Read all available packets at once */ | ||
240 | wl1271_read(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf, | ||
241 | buf_size, true); | ||
242 | |||
243 | /* Split data into separate packets */ | ||
244 | pkt_offset = 0; | ||
245 | while (pkt_offset < buf_size) { | ||
246 | pkt_length = wl12xx_rx_get_buf_size(status, | ||
247 | drv_rx_counter); | ||
248 | |||
249 | unaligned = wl12xx_rx_get_unaligned(status, | ||
250 | drv_rx_counter); | ||
251 | |||
252 | /* | ||
253 | * the handle data call can only fail in memory-outage | ||
254 | * conditions, in that case the received frame will just | ||
255 | * be dropped. | ||
256 | */ | ||
257 | if (wl1271_rx_handle_data(wl, | ||
258 | wl->aggr_buf + pkt_offset, | ||
259 | pkt_length, unaligned, | ||
260 | &hlid) == 1) { | ||
261 | if (hlid < WL12XX_MAX_LINKS) | ||
262 | __set_bit(hlid, active_hlids); | ||
263 | else | ||
264 | WARN(1, | ||
265 | "hlid exceeded WL12XX_MAX_LINKS " | ||
266 | "(%d)\n", hlid); | ||
267 | } | ||
268 | |||
269 | wl->rx_counter++; | ||
270 | drv_rx_counter++; | ||
271 | drv_rx_counter &= NUM_RX_PKT_DESC_MOD_MASK; | ||
272 | pkt_offset += pkt_length; | ||
273 | } | ||
274 | } | ||
275 | |||
276 | /* | ||
277 | * Write the driver's packet counter to the FW. This is only required | ||
278 | * for older hardware revisions | ||
279 | */ | ||
280 | if (wl->quirks & WL12XX_QUIRK_END_OF_TRANSACTION) | ||
281 | wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter); | ||
282 | |||
283 | wl12xx_rearm_rx_streaming(wl, active_hlids); | ||
284 | } | ||
diff --git a/drivers/net/wireless/ti/wl12xx/rx.h b/drivers/net/wireless/ti/wl12xx/rx.h new file mode 100644 index 000000000000..86ba6b1d0cdc --- /dev/null +++ b/drivers/net/wireless/ti/wl12xx/rx.h | |||
@@ -0,0 +1,132 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. | ||
5 | * Copyright (C) 2008-2009 Nokia Corporation | ||
6 | * | ||
7 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef __RX_H__ | ||
26 | #define __RX_H__ | ||
27 | |||
28 | #include <linux/bitops.h> | ||
29 | |||
30 | #define WL1271_RX_MAX_RSSI -30 | ||
31 | #define WL1271_RX_MIN_RSSI -95 | ||
32 | |||
33 | #define SHORT_PREAMBLE_BIT BIT(0) | ||
34 | #define OFDM_RATE_BIT BIT(6) | ||
35 | #define PBCC_RATE_BIT BIT(7) | ||
36 | |||
37 | #define PLCP_HEADER_LENGTH 8 | ||
38 | #define RX_DESC_PACKETID_SHIFT 11 | ||
39 | #define RX_MAX_PACKET_ID 3 | ||
40 | |||
41 | #define NUM_RX_PKT_DESC_MOD_MASK 7 | ||
42 | |||
43 | #define RX_DESC_VALID_FCS 0x0001 | ||
44 | #define RX_DESC_MATCH_RXADDR1 0x0002 | ||
45 | #define RX_DESC_MCAST 0x0004 | ||
46 | #define RX_DESC_STAINTIM 0x0008 | ||
47 | #define RX_DESC_VIRTUAL_BM 0x0010 | ||
48 | #define RX_DESC_BCAST 0x0020 | ||
49 | #define RX_DESC_MATCH_SSID 0x0040 | ||
50 | #define RX_DESC_MATCH_BSSID 0x0080 | ||
51 | #define RX_DESC_ENCRYPTION_MASK 0x0300 | ||
52 | #define RX_DESC_MEASURMENT 0x0400 | ||
53 | #define RX_DESC_SEQNUM_MASK 0x1800 | ||
54 | #define RX_DESC_MIC_FAIL 0x2000 | ||
55 | #define RX_DESC_DECRYPT_FAIL 0x4000 | ||
56 | |||
57 | /* | ||
58 | * RX Descriptor flags: | ||
59 | * | ||
60 | * Bits 0-1 - band | ||
61 | * Bit 2 - STBC | ||
62 | * Bit 3 - A-MPDU | ||
63 | * Bit 4 - HT | ||
64 | * Bits 5-7 - encryption | ||
65 | */ | ||
66 | #define WL1271_RX_DESC_BAND_MASK 0x03 | ||
67 | #define WL1271_RX_DESC_ENCRYPT_MASK 0xE0 | ||
68 | |||
69 | #define WL1271_RX_DESC_BAND_BG 0x00 | ||
70 | #define WL1271_RX_DESC_BAND_J 0x01 | ||
71 | #define WL1271_RX_DESC_BAND_A 0x02 | ||
72 | |||
73 | #define WL1271_RX_DESC_STBC BIT(2) | ||
74 | #define WL1271_RX_DESC_A_MPDU BIT(3) | ||
75 | #define WL1271_RX_DESC_HT BIT(4) | ||
76 | |||
77 | #define WL1271_RX_DESC_ENCRYPT_WEP 0x20 | ||
78 | #define WL1271_RX_DESC_ENCRYPT_TKIP 0x40 | ||
79 | #define WL1271_RX_DESC_ENCRYPT_AES 0x60 | ||
80 | #define WL1271_RX_DESC_ENCRYPT_GEM 0x80 | ||
81 | |||
82 | /* | ||
83 | * RX Descriptor status | ||
84 | * | ||
85 | * Bits 0-2 - error code | ||
86 | * Bits 3-5 - process_id tag (AP mode FW) | ||
87 | * Bits 6-7 - reserved | ||
88 | */ | ||
89 | #define WL1271_RX_DESC_STATUS_MASK 0x03 | ||
90 | |||
91 | #define WL1271_RX_DESC_SUCCESS 0x00 | ||
92 | #define WL1271_RX_DESC_DECRYPT_FAIL 0x01 | ||
93 | #define WL1271_RX_DESC_MIC_FAIL 0x02 | ||
94 | #define WL1271_RX_DESC_DRIVER_RX_Q_FAIL 0x03 | ||
95 | |||
96 | #define RX_MEM_BLOCK_MASK 0xFF | ||
97 | #define RX_BUF_SIZE_MASK 0xFFF00 | ||
98 | #define RX_BUF_SIZE_SHIFT_DIV 6 | ||
99 | /* If set, the start of IP payload is not 4 bytes aligned */ | ||
100 | #define RX_BUF_UNALIGNED_PAYLOAD BIT(20) | ||
101 | |||
102 | enum { | ||
103 | WL12XX_RX_CLASS_UNKNOWN, | ||
104 | WL12XX_RX_CLASS_MANAGEMENT, | ||
105 | WL12XX_RX_CLASS_DATA, | ||
106 | WL12XX_RX_CLASS_QOS_DATA, | ||
107 | WL12XX_RX_CLASS_BCN_PRBRSP, | ||
108 | WL12XX_RX_CLASS_EAPOL, | ||
109 | WL12XX_RX_CLASS_BA_EVENT, | ||
110 | WL12XX_RX_CLASS_AMSDU, | ||
111 | WL12XX_RX_CLASS_LOGGER, | ||
112 | }; | ||
113 | |||
114 | struct wl1271_rx_descriptor { | ||
115 | __le16 length; | ||
116 | u8 status; | ||
117 | u8 flags; | ||
118 | u8 rate; | ||
119 | u8 channel; | ||
120 | s8 rssi; | ||
121 | u8 snr; | ||
122 | __le32 timestamp; | ||
123 | u8 packet_class; | ||
124 | u8 hlid; | ||
125 | u8 pad_len; | ||
126 | u8 reserved; | ||
127 | } __packed; | ||
128 | |||
129 | void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status); | ||
130 | u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band); | ||
131 | |||
132 | #endif | ||
diff --git a/drivers/net/wireless/ti/wl12xx/scan.c b/drivers/net/wireless/ti/wl12xx/scan.c new file mode 100644 index 000000000000..a57f333d07f5 --- /dev/null +++ b/drivers/net/wireless/ti/wl12xx/scan.c | |||
@@ -0,0 +1,790 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2009-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 | #include <linux/ieee80211.h> | ||
25 | |||
26 | #include "wl12xx.h" | ||
27 | #include "debug.h" | ||
28 | #include "cmd.h" | ||
29 | #include "scan.h" | ||
30 | #include "acx.h" | ||
31 | #include "ps.h" | ||
32 | #include "tx.h" | ||
33 | |||
34 | void wl1271_scan_complete_work(struct work_struct *work) | ||
35 | { | ||
36 | struct delayed_work *dwork; | ||
37 | struct wl1271 *wl; | ||
38 | struct ieee80211_vif *vif; | ||
39 | struct wl12xx_vif *wlvif; | ||
40 | int ret; | ||
41 | |||
42 | dwork = container_of(work, struct delayed_work, work); | ||
43 | wl = container_of(dwork, struct wl1271, scan_complete_work); | ||
44 | |||
45 | wl1271_debug(DEBUG_SCAN, "Scanning complete"); | ||
46 | |||
47 | mutex_lock(&wl->mutex); | ||
48 | |||
49 | if (wl->state == WL1271_STATE_OFF) | ||
50 | goto out; | ||
51 | |||
52 | if (wl->scan.state == WL1271_SCAN_STATE_IDLE) | ||
53 | goto out; | ||
54 | |||
55 | vif = wl->scan_vif; | ||
56 | wlvif = wl12xx_vif_to_data(vif); | ||
57 | |||
58 | /* | ||
59 | * Rearm the tx watchdog just before idling scan. This | ||
60 | * prevents just-finished scans from triggering the watchdog | ||
61 | */ | ||
62 | wl12xx_rearm_tx_watchdog_locked(wl); | ||
63 | |||
64 | wl->scan.state = WL1271_SCAN_STATE_IDLE; | ||
65 | memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); | ||
66 | wl->scan.req = NULL; | ||
67 | wl->scan_vif = NULL; | ||
68 | |||
69 | ret = wl1271_ps_elp_wakeup(wl); | ||
70 | if (ret < 0) | ||
71 | goto out; | ||
72 | |||
73 | if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) { | ||
74 | /* restore hardware connection monitoring template */ | ||
75 | wl1271_cmd_build_ap_probe_req(wl, wlvif, wlvif->probereq); | ||
76 | } | ||
77 | |||
78 | wl1271_ps_elp_sleep(wl); | ||
79 | |||
80 | if (wl->scan.failed) { | ||
81 | wl1271_info("Scan completed due to error."); | ||
82 | wl12xx_queue_recovery_work(wl); | ||
83 | } | ||
84 | |||
85 | ieee80211_scan_completed(wl->hw, false); | ||
86 | |||
87 | out: | ||
88 | mutex_unlock(&wl->mutex); | ||
89 | |||
90 | } | ||
91 | |||
92 | |||
93 | static int wl1271_get_scan_channels(struct wl1271 *wl, | ||
94 | struct cfg80211_scan_request *req, | ||
95 | struct basic_scan_channel_params *channels, | ||
96 | enum ieee80211_band band, bool passive) | ||
97 | { | ||
98 | struct conf_scan_settings *c = &wl->conf.scan; | ||
99 | int i, j; | ||
100 | u32 flags; | ||
101 | |||
102 | for (i = 0, j = 0; | ||
103 | i < req->n_channels && j < WL1271_SCAN_MAX_CHANNELS; | ||
104 | i++) { | ||
105 | flags = req->channels[i]->flags; | ||
106 | |||
107 | if (!test_bit(i, wl->scan.scanned_ch) && | ||
108 | !(flags & IEEE80211_CHAN_DISABLED) && | ||
109 | (req->channels[i]->band == band) && | ||
110 | /* | ||
111 | * In passive scans, we scan all remaining | ||
112 | * channels, even if not marked as such. | ||
113 | * In active scans, we only scan channels not | ||
114 | * marked as passive. | ||
115 | */ | ||
116 | (passive || !(flags & IEEE80211_CHAN_PASSIVE_SCAN))) { | ||
117 | wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ", | ||
118 | req->channels[i]->band, | ||
119 | req->channels[i]->center_freq); | ||
120 | wl1271_debug(DEBUG_SCAN, "hw_value %d, flags %X", | ||
121 | req->channels[i]->hw_value, | ||
122 | req->channels[i]->flags); | ||
123 | wl1271_debug(DEBUG_SCAN, | ||
124 | "max_antenna_gain %d, max_power %d", | ||
125 | req->channels[i]->max_antenna_gain, | ||
126 | req->channels[i]->max_power); | ||
127 | wl1271_debug(DEBUG_SCAN, "beacon_found %d", | ||
128 | req->channels[i]->beacon_found); | ||
129 | |||
130 | if (!passive) { | ||
131 | channels[j].min_duration = | ||
132 | cpu_to_le32(c->min_dwell_time_active); | ||
133 | channels[j].max_duration = | ||
134 | cpu_to_le32(c->max_dwell_time_active); | ||
135 | } else { | ||
136 | channels[j].min_duration = | ||
137 | cpu_to_le32(c->min_dwell_time_passive); | ||
138 | channels[j].max_duration = | ||
139 | cpu_to_le32(c->max_dwell_time_passive); | ||
140 | } | ||
141 | channels[j].early_termination = 0; | ||
142 | channels[j].tx_power_att = req->channels[i]->max_power; | ||
143 | channels[j].channel = req->channels[i]->hw_value; | ||
144 | |||
145 | memset(&channels[j].bssid_lsb, 0xff, 4); | ||
146 | memset(&channels[j].bssid_msb, 0xff, 2); | ||
147 | |||
148 | /* Mark the channels we already used */ | ||
149 | set_bit(i, wl->scan.scanned_ch); | ||
150 | |||
151 | j++; | ||
152 | } | ||
153 | } | ||
154 | |||
155 | return j; | ||
156 | } | ||
157 | |||
158 | #define WL1271_NOTHING_TO_SCAN 1 | ||
159 | |||
160 | static int wl1271_scan_send(struct wl1271 *wl, struct ieee80211_vif *vif, | ||
161 | enum ieee80211_band band, | ||
162 | bool passive, u32 basic_rate) | ||
163 | { | ||
164 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | ||
165 | struct wl1271_cmd_scan *cmd; | ||
166 | struct wl1271_cmd_trigger_scan_to *trigger; | ||
167 | int ret; | ||
168 | u16 scan_options = 0; | ||
169 | |||
170 | /* skip active scans if we don't have SSIDs */ | ||
171 | if (!passive && wl->scan.req->n_ssids == 0) | ||
172 | return WL1271_NOTHING_TO_SCAN; | ||
173 | |||
174 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
175 | trigger = kzalloc(sizeof(*trigger), GFP_KERNEL); | ||
176 | if (!cmd || !trigger) { | ||
177 | ret = -ENOMEM; | ||
178 | goto out; | ||
179 | } | ||
180 | |||
181 | if (wl->conf.scan.split_scan_timeout) | ||
182 | scan_options |= WL1271_SCAN_OPT_SPLIT_SCAN; | ||
183 | |||
184 | if (passive) | ||
185 | scan_options |= WL1271_SCAN_OPT_PASSIVE; | ||
186 | |||
187 | if (wlvif->bss_type == BSS_TYPE_AP_BSS || | ||
188 | test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) | ||
189 | cmd->params.role_id = wlvif->role_id; | ||
190 | else | ||
191 | cmd->params.role_id = wlvif->dev_role_id; | ||
192 | |||
193 | if (WARN_ON(cmd->params.role_id == WL12XX_INVALID_ROLE_ID)) { | ||
194 | ret = -EINVAL; | ||
195 | goto out; | ||
196 | } | ||
197 | |||
198 | cmd->params.scan_options = cpu_to_le16(scan_options); | ||
199 | |||
200 | cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req, | ||
201 | cmd->channels, | ||
202 | band, passive); | ||
203 | if (cmd->params.n_ch == 0) { | ||
204 | ret = WL1271_NOTHING_TO_SCAN; | ||
205 | goto out; | ||
206 | } | ||
207 | |||
208 | cmd->params.tx_rate = cpu_to_le32(basic_rate); | ||
209 | cmd->params.n_probe_reqs = wl->conf.scan.num_probe_reqs; | ||
210 | cmd->params.tid_trigger = CONF_TX_AC_ANY_TID; | ||
211 | cmd->params.scan_tag = WL1271_SCAN_DEFAULT_TAG; | ||
212 | |||
213 | if (band == IEEE80211_BAND_2GHZ) | ||
214 | cmd->params.band = WL1271_SCAN_BAND_2_4_GHZ; | ||
215 | else | ||
216 | cmd->params.band = WL1271_SCAN_BAND_5_GHZ; | ||
217 | |||
218 | if (wl->scan.ssid_len && wl->scan.ssid) { | ||
219 | cmd->params.ssid_len = wl->scan.ssid_len; | ||
220 | memcpy(cmd->params.ssid, wl->scan.ssid, wl->scan.ssid_len); | ||
221 | } | ||
222 | |||
223 | memcpy(cmd->addr, vif->addr, ETH_ALEN); | ||
224 | |||
225 | ret = wl12xx_cmd_build_probe_req(wl, wlvif, | ||
226 | cmd->params.role_id, band, | ||
227 | wl->scan.ssid, wl->scan.ssid_len, | ||
228 | wl->scan.req->ie, | ||
229 | wl->scan.req->ie_len); | ||
230 | if (ret < 0) { | ||
231 | wl1271_error("PROBE request template failed"); | ||
232 | goto out; | ||
233 | } | ||
234 | |||
235 | trigger->timeout = cpu_to_le32(wl->conf.scan.split_scan_timeout); | ||
236 | ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, | ||
237 | sizeof(*trigger), 0); | ||
238 | if (ret < 0) { | ||
239 | wl1271_error("trigger scan to failed for hw scan"); | ||
240 | goto out; | ||
241 | } | ||
242 | |||
243 | wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd)); | ||
244 | |||
245 | ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0); | ||
246 | if (ret < 0) { | ||
247 | wl1271_error("SCAN failed"); | ||
248 | goto out; | ||
249 | } | ||
250 | |||
251 | out: | ||
252 | kfree(cmd); | ||
253 | kfree(trigger); | ||
254 | return ret; | ||
255 | } | ||
256 | |||
257 | void wl1271_scan_stm(struct wl1271 *wl, struct ieee80211_vif *vif) | ||
258 | { | ||
259 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | ||
260 | int ret = 0; | ||
261 | enum ieee80211_band band; | ||
262 | u32 rate, mask; | ||
263 | |||
264 | switch (wl->scan.state) { | ||
265 | case WL1271_SCAN_STATE_IDLE: | ||
266 | break; | ||
267 | |||
268 | case WL1271_SCAN_STATE_2GHZ_ACTIVE: | ||
269 | band = IEEE80211_BAND_2GHZ; | ||
270 | mask = wlvif->bitrate_masks[band]; | ||
271 | if (wl->scan.req->no_cck) { | ||
272 | mask &= ~CONF_TX_CCK_RATES; | ||
273 | if (!mask) | ||
274 | mask = CONF_TX_RATE_MASK_BASIC_P2P; | ||
275 | } | ||
276 | rate = wl1271_tx_min_rate_get(wl, mask); | ||
277 | ret = wl1271_scan_send(wl, vif, band, false, rate); | ||
278 | if (ret == WL1271_NOTHING_TO_SCAN) { | ||
279 | wl->scan.state = WL1271_SCAN_STATE_2GHZ_PASSIVE; | ||
280 | wl1271_scan_stm(wl, vif); | ||
281 | } | ||
282 | |||
283 | break; | ||
284 | |||
285 | case WL1271_SCAN_STATE_2GHZ_PASSIVE: | ||
286 | band = IEEE80211_BAND_2GHZ; | ||
287 | mask = wlvif->bitrate_masks[band]; | ||
288 | if (wl->scan.req->no_cck) { | ||
289 | mask &= ~CONF_TX_CCK_RATES; | ||
290 | if (!mask) | ||
291 | mask = CONF_TX_RATE_MASK_BASIC_P2P; | ||
292 | } | ||
293 | rate = wl1271_tx_min_rate_get(wl, mask); | ||
294 | ret = wl1271_scan_send(wl, vif, band, true, rate); | ||
295 | if (ret == WL1271_NOTHING_TO_SCAN) { | ||
296 | if (wl->enable_11a) | ||
297 | wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE; | ||
298 | else | ||
299 | wl->scan.state = WL1271_SCAN_STATE_DONE; | ||
300 | wl1271_scan_stm(wl, vif); | ||
301 | } | ||
302 | |||
303 | break; | ||
304 | |||
305 | case WL1271_SCAN_STATE_5GHZ_ACTIVE: | ||
306 | band = IEEE80211_BAND_5GHZ; | ||
307 | rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]); | ||
308 | ret = wl1271_scan_send(wl, vif, band, false, rate); | ||
309 | if (ret == WL1271_NOTHING_TO_SCAN) { | ||
310 | wl->scan.state = WL1271_SCAN_STATE_5GHZ_PASSIVE; | ||
311 | wl1271_scan_stm(wl, vif); | ||
312 | } | ||
313 | |||
314 | break; | ||
315 | |||
316 | case WL1271_SCAN_STATE_5GHZ_PASSIVE: | ||
317 | band = IEEE80211_BAND_5GHZ; | ||
318 | rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]); | ||
319 | ret = wl1271_scan_send(wl, vif, band, true, rate); | ||
320 | if (ret == WL1271_NOTHING_TO_SCAN) { | ||
321 | wl->scan.state = WL1271_SCAN_STATE_DONE; | ||
322 | wl1271_scan_stm(wl, vif); | ||
323 | } | ||
324 | |||
325 | break; | ||
326 | |||
327 | case WL1271_SCAN_STATE_DONE: | ||
328 | wl->scan.failed = false; | ||
329 | cancel_delayed_work(&wl->scan_complete_work); | ||
330 | ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, | ||
331 | msecs_to_jiffies(0)); | ||
332 | break; | ||
333 | |||
334 | default: | ||
335 | wl1271_error("invalid scan state"); | ||
336 | break; | ||
337 | } | ||
338 | |||
339 | if (ret < 0) { | ||
340 | cancel_delayed_work(&wl->scan_complete_work); | ||
341 | ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, | ||
342 | msecs_to_jiffies(0)); | ||
343 | } | ||
344 | } | ||
345 | |||
346 | int wl1271_scan(struct wl1271 *wl, struct ieee80211_vif *vif, | ||
347 | const u8 *ssid, size_t ssid_len, | ||
348 | struct cfg80211_scan_request *req) | ||
349 | { | ||
350 | /* | ||
351 | * cfg80211 should guarantee that we don't get more channels | ||
352 | * than what we have registered. | ||
353 | */ | ||
354 | BUG_ON(req->n_channels > WL1271_MAX_CHANNELS); | ||
355 | |||
356 | if (wl->scan.state != WL1271_SCAN_STATE_IDLE) | ||
357 | return -EBUSY; | ||
358 | |||
359 | wl->scan.state = WL1271_SCAN_STATE_2GHZ_ACTIVE; | ||
360 | |||
361 | if (ssid_len && ssid) { | ||
362 | wl->scan.ssid_len = ssid_len; | ||
363 | memcpy(wl->scan.ssid, ssid, ssid_len); | ||
364 | } else { | ||
365 | wl->scan.ssid_len = 0; | ||
366 | } | ||
367 | |||
368 | wl->scan_vif = vif; | ||
369 | wl->scan.req = req; | ||
370 | memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); | ||
371 | |||
372 | /* we assume failure so that timeout scenarios are handled correctly */ | ||
373 | wl->scan.failed = true; | ||
374 | ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, | ||
375 | msecs_to_jiffies(WL1271_SCAN_TIMEOUT)); | ||
376 | |||
377 | wl1271_scan_stm(wl, vif); | ||
378 | |||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | int wl1271_scan_stop(struct wl1271 *wl) | ||
383 | { | ||
384 | struct wl1271_cmd_header *cmd = NULL; | ||
385 | int ret = 0; | ||
386 | |||
387 | if (WARN_ON(wl->scan.state == WL1271_SCAN_STATE_IDLE)) | ||
388 | return -EINVAL; | ||
389 | |||
390 | wl1271_debug(DEBUG_CMD, "cmd scan stop"); | ||
391 | |||
392 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
393 | if (!cmd) { | ||
394 | ret = -ENOMEM; | ||
395 | goto out; | ||
396 | } | ||
397 | |||
398 | ret = wl1271_cmd_send(wl, CMD_STOP_SCAN, cmd, | ||
399 | sizeof(*cmd), 0); | ||
400 | if (ret < 0) { | ||
401 | wl1271_error("cmd stop_scan failed"); | ||
402 | goto out; | ||
403 | } | ||
404 | out: | ||
405 | kfree(cmd); | ||
406 | return ret; | ||
407 | } | ||
408 | |||
409 | static int | ||
410 | wl1271_scan_get_sched_scan_channels(struct wl1271 *wl, | ||
411 | struct cfg80211_sched_scan_request *req, | ||
412 | struct conn_scan_ch_params *channels, | ||
413 | u32 band, bool radar, bool passive, | ||
414 | int start, int max_channels) | ||
415 | { | ||
416 | struct conf_sched_scan_settings *c = &wl->conf.sched_scan; | ||
417 | int i, j; | ||
418 | u32 flags; | ||
419 | bool force_passive = !req->n_ssids; | ||
420 | u32 min_dwell_time_active, max_dwell_time_active, delta_per_probe; | ||
421 | u32 dwell_time_passive, dwell_time_dfs; | ||
422 | |||
423 | if (band == IEEE80211_BAND_5GHZ) | ||
424 | delta_per_probe = c->dwell_time_delta_per_probe_5; | ||
425 | else | ||
426 | delta_per_probe = c->dwell_time_delta_per_probe; | ||
427 | |||
428 | min_dwell_time_active = c->base_dwell_time + | ||
429 | req->n_ssids * c->num_probe_reqs * delta_per_probe; | ||
430 | |||
431 | max_dwell_time_active = min_dwell_time_active + c->max_dwell_time_delta; | ||
432 | |||
433 | min_dwell_time_active = DIV_ROUND_UP(min_dwell_time_active, 1000); | ||
434 | max_dwell_time_active = DIV_ROUND_UP(max_dwell_time_active, 1000); | ||
435 | dwell_time_passive = DIV_ROUND_UP(c->dwell_time_passive, 1000); | ||
436 | dwell_time_dfs = DIV_ROUND_UP(c->dwell_time_dfs, 1000); | ||
437 | |||
438 | for (i = 0, j = start; | ||
439 | i < req->n_channels && j < max_channels; | ||
440 | i++) { | ||
441 | flags = req->channels[i]->flags; | ||
442 | |||
443 | if (force_passive) | ||
444 | flags |= IEEE80211_CHAN_PASSIVE_SCAN; | ||
445 | |||
446 | if ((req->channels[i]->band == band) && | ||
447 | !(flags & IEEE80211_CHAN_DISABLED) && | ||
448 | (!!(flags & IEEE80211_CHAN_RADAR) == radar) && | ||
449 | /* if radar is set, we ignore the passive flag */ | ||
450 | (radar || | ||
451 | !!(flags & IEEE80211_CHAN_PASSIVE_SCAN) == passive)) { | ||
452 | wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ", | ||
453 | req->channels[i]->band, | ||
454 | req->channels[i]->center_freq); | ||
455 | wl1271_debug(DEBUG_SCAN, "hw_value %d, flags %X", | ||
456 | req->channels[i]->hw_value, | ||
457 | req->channels[i]->flags); | ||
458 | wl1271_debug(DEBUG_SCAN, "max_power %d", | ||
459 | req->channels[i]->max_power); | ||
460 | wl1271_debug(DEBUG_SCAN, "min_dwell_time %d max dwell time %d", | ||
461 | min_dwell_time_active, | ||
462 | max_dwell_time_active); | ||
463 | |||
464 | if (flags & IEEE80211_CHAN_RADAR) { | ||
465 | channels[j].flags |= SCAN_CHANNEL_FLAGS_DFS; | ||
466 | |||
467 | channels[j].passive_duration = | ||
468 | cpu_to_le16(dwell_time_dfs); | ||
469 | } else { | ||
470 | channels[j].passive_duration = | ||
471 | cpu_to_le16(dwell_time_passive); | ||
472 | } | ||
473 | |||
474 | channels[j].min_duration = | ||
475 | cpu_to_le16(min_dwell_time_active); | ||
476 | channels[j].max_duration = | ||
477 | cpu_to_le16(max_dwell_time_active); | ||
478 | |||
479 | channels[j].tx_power_att = req->channels[i]->max_power; | ||
480 | channels[j].channel = req->channels[i]->hw_value; | ||
481 | |||
482 | j++; | ||
483 | } | ||
484 | } | ||
485 | |||
486 | return j - start; | ||
487 | } | ||
488 | |||
489 | static bool | ||
490 | wl1271_scan_sched_scan_channels(struct wl1271 *wl, | ||
491 | struct cfg80211_sched_scan_request *req, | ||
492 | struct wl1271_cmd_sched_scan_config *cfg) | ||
493 | { | ||
494 | cfg->passive[0] = | ||
495 | wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_2, | ||
496 | IEEE80211_BAND_2GHZ, | ||
497 | false, true, 0, | ||
498 | MAX_CHANNELS_2GHZ); | ||
499 | cfg->active[0] = | ||
500 | wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_2, | ||
501 | IEEE80211_BAND_2GHZ, | ||
502 | false, false, | ||
503 | cfg->passive[0], | ||
504 | MAX_CHANNELS_2GHZ); | ||
505 | cfg->passive[1] = | ||
506 | wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_5, | ||
507 | IEEE80211_BAND_5GHZ, | ||
508 | false, true, 0, | ||
509 | MAX_CHANNELS_5GHZ); | ||
510 | cfg->dfs = | ||
511 | wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_5, | ||
512 | IEEE80211_BAND_5GHZ, | ||
513 | true, true, | ||
514 | cfg->passive[1], | ||
515 | MAX_CHANNELS_5GHZ); | ||
516 | cfg->active[1] = | ||
517 | wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_5, | ||
518 | IEEE80211_BAND_5GHZ, | ||
519 | false, false, | ||
520 | cfg->passive[1] + cfg->dfs, | ||
521 | MAX_CHANNELS_5GHZ); | ||
522 | /* 802.11j channels are not supported yet */ | ||
523 | cfg->passive[2] = 0; | ||
524 | cfg->active[2] = 0; | ||
525 | |||
526 | wl1271_debug(DEBUG_SCAN, " 2.4GHz: active %d passive %d", | ||
527 | cfg->active[0], cfg->passive[0]); | ||
528 | wl1271_debug(DEBUG_SCAN, " 5GHz: active %d passive %d", | ||
529 | cfg->active[1], cfg->passive[1]); | ||
530 | wl1271_debug(DEBUG_SCAN, " DFS: %d", cfg->dfs); | ||
531 | |||
532 | return cfg->passive[0] || cfg->active[0] || | ||
533 | cfg->passive[1] || cfg->active[1] || cfg->dfs || | ||
534 | cfg->passive[2] || cfg->active[2]; | ||
535 | } | ||
536 | |||
537 | /* Returns the scan type to be used or a negative value on error */ | ||
538 | static int | ||
539 | wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl, | ||
540 | struct cfg80211_sched_scan_request *req) | ||
541 | { | ||
542 | struct wl1271_cmd_sched_scan_ssid_list *cmd = NULL; | ||
543 | struct cfg80211_match_set *sets = req->match_sets; | ||
544 | struct cfg80211_ssid *ssids = req->ssids; | ||
545 | int ret = 0, type, i, j, n_match_ssids = 0; | ||
546 | |||
547 | wl1271_debug(DEBUG_CMD, "cmd sched scan ssid list"); | ||
548 | |||
549 | /* count the match sets that contain SSIDs */ | ||
550 | for (i = 0; i < req->n_match_sets; i++) | ||
551 | if (sets[i].ssid.ssid_len > 0) | ||
552 | n_match_ssids++; | ||
553 | |||
554 | /* No filter, no ssids or only bcast ssid */ | ||
555 | if (!n_match_ssids && | ||
556 | (!req->n_ssids || | ||
557 | (req->n_ssids == 1 && req->ssids[0].ssid_len == 0))) { | ||
558 | type = SCAN_SSID_FILTER_ANY; | ||
559 | goto out; | ||
560 | } | ||
561 | |||
562 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
563 | if (!cmd) { | ||
564 | ret = -ENOMEM; | ||
565 | goto out; | ||
566 | } | ||
567 | |||
568 | if (!n_match_ssids) { | ||
569 | /* No filter, with ssids */ | ||
570 | type = SCAN_SSID_FILTER_DISABLED; | ||
571 | |||
572 | for (i = 0; i < req->n_ssids; i++) { | ||
573 | cmd->ssids[cmd->n_ssids].type = (ssids[i].ssid_len) ? | ||
574 | SCAN_SSID_TYPE_HIDDEN : SCAN_SSID_TYPE_PUBLIC; | ||
575 | cmd->ssids[cmd->n_ssids].len = ssids[i].ssid_len; | ||
576 | memcpy(cmd->ssids[cmd->n_ssids].ssid, ssids[i].ssid, | ||
577 | ssids[i].ssid_len); | ||
578 | cmd->n_ssids++; | ||
579 | } | ||
580 | } else { | ||
581 | type = SCAN_SSID_FILTER_LIST; | ||
582 | |||
583 | /* Add all SSIDs from the filters */ | ||
584 | for (i = 0; i < req->n_match_sets; i++) { | ||
585 | /* ignore sets without SSIDs */ | ||
586 | if (!sets[i].ssid.ssid_len) | ||
587 | continue; | ||
588 | |||
589 | cmd->ssids[cmd->n_ssids].type = SCAN_SSID_TYPE_PUBLIC; | ||
590 | cmd->ssids[cmd->n_ssids].len = sets[i].ssid.ssid_len; | ||
591 | memcpy(cmd->ssids[cmd->n_ssids].ssid, | ||
592 | sets[i].ssid.ssid, sets[i].ssid.ssid_len); | ||
593 | cmd->n_ssids++; | ||
594 | } | ||
595 | if ((req->n_ssids > 1) || | ||
596 | (req->n_ssids == 1 && req->ssids[0].ssid_len > 0)) { | ||
597 | /* | ||
598 | * Mark all the SSIDs passed in the SSID list as HIDDEN, | ||
599 | * so they're used in probe requests. | ||
600 | */ | ||
601 | for (i = 0; i < req->n_ssids; i++) { | ||
602 | if (!req->ssids[i].ssid_len) | ||
603 | continue; | ||
604 | |||
605 | for (j = 0; j < cmd->n_ssids; j++) | ||
606 | if (!memcmp(req->ssids[i].ssid, | ||
607 | cmd->ssids[j].ssid, | ||
608 | req->ssids[i].ssid_len)) { | ||
609 | cmd->ssids[j].type = | ||
610 | SCAN_SSID_TYPE_HIDDEN; | ||
611 | break; | ||
612 | } | ||
613 | /* Fail if SSID isn't present in the filters */ | ||
614 | if (j == cmd->n_ssids) { | ||
615 | ret = -EINVAL; | ||
616 | goto out_free; | ||
617 | } | ||
618 | } | ||
619 | } | ||
620 | } | ||
621 | |||
622 | wl1271_dump(DEBUG_SCAN, "SSID_LIST: ", cmd, sizeof(*cmd)); | ||
623 | |||
624 | ret = wl1271_cmd_send(wl, CMD_CONNECTION_SCAN_SSID_CFG, cmd, | ||
625 | sizeof(*cmd), 0); | ||
626 | if (ret < 0) { | ||
627 | wl1271_error("cmd sched scan ssid list failed"); | ||
628 | goto out_free; | ||
629 | } | ||
630 | |||
631 | out_free: | ||
632 | kfree(cmd); | ||
633 | out: | ||
634 | if (ret < 0) | ||
635 | return ret; | ||
636 | return type; | ||
637 | } | ||
638 | |||
639 | int wl1271_scan_sched_scan_config(struct wl1271 *wl, | ||
640 | struct wl12xx_vif *wlvif, | ||
641 | struct cfg80211_sched_scan_request *req, | ||
642 | struct ieee80211_sched_scan_ies *ies) | ||
643 | { | ||
644 | struct wl1271_cmd_sched_scan_config *cfg = NULL; | ||
645 | struct conf_sched_scan_settings *c = &wl->conf.sched_scan; | ||
646 | int i, ret; | ||
647 | bool force_passive = !req->n_ssids; | ||
648 | |||
649 | wl1271_debug(DEBUG_CMD, "cmd sched_scan scan config"); | ||
650 | |||
651 | cfg = kzalloc(sizeof(*cfg), GFP_KERNEL); | ||
652 | if (!cfg) | ||
653 | return -ENOMEM; | ||
654 | |||
655 | cfg->rssi_threshold = c->rssi_threshold; | ||
656 | cfg->snr_threshold = c->snr_threshold; | ||
657 | cfg->n_probe_reqs = c->num_probe_reqs; | ||
658 | /* cycles set to 0 it means infinite (until manually stopped) */ | ||
659 | cfg->cycles = 0; | ||
660 | /* report APs when at least 1 is found */ | ||
661 | cfg->report_after = 1; | ||
662 | /* don't stop scanning automatically when something is found */ | ||
663 | cfg->terminate = 0; | ||
664 | cfg->tag = WL1271_SCAN_DEFAULT_TAG; | ||
665 | /* don't filter on BSS type */ | ||
666 | cfg->bss_type = SCAN_BSS_TYPE_ANY; | ||
667 | /* currently NL80211 supports only a single interval */ | ||
668 | for (i = 0; i < SCAN_MAX_CYCLE_INTERVALS; i++) | ||
669 | cfg->intervals[i] = cpu_to_le32(req->interval); | ||
670 | |||
671 | cfg->ssid_len = 0; | ||
672 | ret = wl12xx_scan_sched_scan_ssid_list(wl, req); | ||
673 | if (ret < 0) | ||
674 | goto out; | ||
675 | |||
676 | cfg->filter_type = ret; | ||
677 | |||
678 | wl1271_debug(DEBUG_SCAN, "filter_type = %d", cfg->filter_type); | ||
679 | |||
680 | if (!wl1271_scan_sched_scan_channels(wl, req, cfg)) { | ||
681 | wl1271_error("scan channel list is empty"); | ||
682 | ret = -EINVAL; | ||
683 | goto out; | ||
684 | } | ||
685 | |||
686 | if (!force_passive && cfg->active[0]) { | ||
687 | u8 band = IEEE80211_BAND_2GHZ; | ||
688 | ret = wl12xx_cmd_build_probe_req(wl, wlvif, | ||
689 | wlvif->dev_role_id, band, | ||
690 | req->ssids[0].ssid, | ||
691 | req->ssids[0].ssid_len, | ||
692 | ies->ie[band], | ||
693 | ies->len[band]); | ||
694 | if (ret < 0) { | ||
695 | wl1271_error("2.4GHz PROBE request template failed"); | ||
696 | goto out; | ||
697 | } | ||
698 | } | ||
699 | |||
700 | if (!force_passive && cfg->active[1]) { | ||
701 | u8 band = IEEE80211_BAND_5GHZ; | ||
702 | ret = wl12xx_cmd_build_probe_req(wl, wlvif, | ||
703 | wlvif->dev_role_id, band, | ||
704 | req->ssids[0].ssid, | ||
705 | req->ssids[0].ssid_len, | ||
706 | ies->ie[band], | ||
707 | ies->len[band]); | ||
708 | if (ret < 0) { | ||
709 | wl1271_error("5GHz PROBE request template failed"); | ||
710 | goto out; | ||
711 | } | ||
712 | } | ||
713 | |||
714 | wl1271_dump(DEBUG_SCAN, "SCAN_CFG: ", cfg, sizeof(*cfg)); | ||
715 | |||
716 | ret = wl1271_cmd_send(wl, CMD_CONNECTION_SCAN_CFG, cfg, | ||
717 | sizeof(*cfg), 0); | ||
718 | if (ret < 0) { | ||
719 | wl1271_error("SCAN configuration failed"); | ||
720 | goto out; | ||
721 | } | ||
722 | out: | ||
723 | kfree(cfg); | ||
724 | return ret; | ||
725 | } | ||
726 | |||
727 | int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif) | ||
728 | { | ||
729 | struct wl1271_cmd_sched_scan_start *start; | ||
730 | int ret = 0; | ||
731 | |||
732 | wl1271_debug(DEBUG_CMD, "cmd periodic scan start"); | ||
733 | |||
734 | if (wlvif->bss_type != BSS_TYPE_STA_BSS) | ||
735 | return -EOPNOTSUPP; | ||
736 | |||
737 | if (test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) | ||
738 | return -EBUSY; | ||
739 | |||
740 | start = kzalloc(sizeof(*start), GFP_KERNEL); | ||
741 | if (!start) | ||
742 | return -ENOMEM; | ||
743 | |||
744 | start->tag = WL1271_SCAN_DEFAULT_TAG; | ||
745 | |||
746 | ret = wl1271_cmd_send(wl, CMD_START_PERIODIC_SCAN, start, | ||
747 | sizeof(*start), 0); | ||
748 | if (ret < 0) { | ||
749 | wl1271_error("failed to send scan start command"); | ||
750 | goto out_free; | ||
751 | } | ||
752 | |||
753 | out_free: | ||
754 | kfree(start); | ||
755 | return ret; | ||
756 | } | ||
757 | |||
758 | void wl1271_scan_sched_scan_results(struct wl1271 *wl) | ||
759 | { | ||
760 | wl1271_debug(DEBUG_SCAN, "got periodic scan results"); | ||
761 | |||
762 | ieee80211_sched_scan_results(wl->hw); | ||
763 | } | ||
764 | |||
765 | void wl1271_scan_sched_scan_stop(struct wl1271 *wl) | ||
766 | { | ||
767 | struct wl1271_cmd_sched_scan_stop *stop; | ||
768 | int ret = 0; | ||
769 | |||
770 | wl1271_debug(DEBUG_CMD, "cmd periodic scan stop"); | ||
771 | |||
772 | /* FIXME: what to do if alloc'ing to stop fails? */ | ||
773 | stop = kzalloc(sizeof(*stop), GFP_KERNEL); | ||
774 | if (!stop) { | ||
775 | wl1271_error("failed to alloc memory to send sched scan stop"); | ||
776 | return; | ||
777 | } | ||
778 | |||
779 | stop->tag = WL1271_SCAN_DEFAULT_TAG; | ||
780 | |||
781 | ret = wl1271_cmd_send(wl, CMD_STOP_PERIODIC_SCAN, stop, | ||
782 | sizeof(*stop), 0); | ||
783 | if (ret < 0) { | ||
784 | wl1271_error("failed to send sched scan stop command"); | ||
785 | goto out_free; | ||
786 | } | ||
787 | |||
788 | out_free: | ||
789 | kfree(stop); | ||
790 | } | ||
diff --git a/drivers/net/wireless/ti/wl12xx/scan.h b/drivers/net/wireless/ti/wl12xx/scan.h new file mode 100644 index 000000000000..2b300f4d0be9 --- /dev/null +++ b/drivers/net/wireless/ti/wl12xx/scan.h | |||
@@ -0,0 +1,233 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2009-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 __SCAN_H__ | ||
25 | #define __SCAN_H__ | ||
26 | |||
27 | #include "wl12xx.h" | ||
28 | |||
29 | int wl1271_scan(struct wl1271 *wl, struct ieee80211_vif *vif, | ||
30 | const u8 *ssid, size_t ssid_len, | ||
31 | struct cfg80211_scan_request *req); | ||
32 | int wl1271_scan_stop(struct wl1271 *wl); | ||
33 | int wl1271_scan_build_probe_req(struct wl1271 *wl, | ||
34 | const u8 *ssid, size_t ssid_len, | ||
35 | const u8 *ie, size_t ie_len, u8 band); | ||
36 | void wl1271_scan_stm(struct wl1271 *wl, struct ieee80211_vif *vif); | ||
37 | void wl1271_scan_complete_work(struct work_struct *work); | ||
38 | int wl1271_scan_sched_scan_config(struct wl1271 *wl, | ||
39 | struct wl12xx_vif *wlvif, | ||
40 | struct cfg80211_sched_scan_request *req, | ||
41 | struct ieee80211_sched_scan_ies *ies); | ||
42 | int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif); | ||
43 | void wl1271_scan_sched_scan_stop(struct wl1271 *wl); | ||
44 | void wl1271_scan_sched_scan_results(struct wl1271 *wl); | ||
45 | |||
46 | #define WL1271_SCAN_MAX_CHANNELS 24 | ||
47 | #define WL1271_SCAN_DEFAULT_TAG 1 | ||
48 | #define WL1271_SCAN_CURRENT_TX_PWR 0 | ||
49 | #define WL1271_SCAN_OPT_ACTIVE 0 | ||
50 | #define WL1271_SCAN_OPT_PASSIVE 1 | ||
51 | #define WL1271_SCAN_OPT_SPLIT_SCAN 2 | ||
52 | #define WL1271_SCAN_OPT_PRIORITY_HIGH 4 | ||
53 | /* scan even if we fail to enter psm */ | ||
54 | #define WL1271_SCAN_OPT_FORCE 8 | ||
55 | #define WL1271_SCAN_BAND_2_4_GHZ 0 | ||
56 | #define WL1271_SCAN_BAND_5_GHZ 1 | ||
57 | |||
58 | #define WL1271_SCAN_TIMEOUT 30000 /* msec */ | ||
59 | |||
60 | enum { | ||
61 | WL1271_SCAN_STATE_IDLE, | ||
62 | WL1271_SCAN_STATE_2GHZ_ACTIVE, | ||
63 | WL1271_SCAN_STATE_2GHZ_PASSIVE, | ||
64 | WL1271_SCAN_STATE_5GHZ_ACTIVE, | ||
65 | WL1271_SCAN_STATE_5GHZ_PASSIVE, | ||
66 | WL1271_SCAN_STATE_DONE | ||
67 | }; | ||
68 | |||
69 | struct basic_scan_params { | ||
70 | /* Scan option flags (WL1271_SCAN_OPT_*) */ | ||
71 | __le16 scan_options; | ||
72 | u8 role_id; | ||
73 | /* Number of scan channels in the list (maximum 30) */ | ||
74 | u8 n_ch; | ||
75 | /* This field indicates the number of probe requests to send | ||
76 | per channel for an active scan */ | ||
77 | u8 n_probe_reqs; | ||
78 | u8 tid_trigger; | ||
79 | u8 ssid_len; | ||
80 | u8 use_ssid_list; | ||
81 | |||
82 | /* Rate bit field for sending the probes */ | ||
83 | __le32 tx_rate; | ||
84 | |||
85 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | ||
86 | /* Band to scan */ | ||
87 | u8 band; | ||
88 | |||
89 | u8 scan_tag; | ||
90 | u8 padding2[2]; | ||
91 | } __packed; | ||
92 | |||
93 | struct basic_scan_channel_params { | ||
94 | /* Duration in TU to wait for frames on a channel for active scan */ | ||
95 | __le32 min_duration; | ||
96 | __le32 max_duration; | ||
97 | __le32 bssid_lsb; | ||
98 | __le16 bssid_msb; | ||
99 | u8 early_termination; | ||
100 | u8 tx_power_att; | ||
101 | u8 channel; | ||
102 | /* FW internal use only! */ | ||
103 | u8 dfs_candidate; | ||
104 | u8 activity_detected; | ||
105 | u8 pad; | ||
106 | } __packed; | ||
107 | |||
108 | struct wl1271_cmd_scan { | ||
109 | struct wl1271_cmd_header header; | ||
110 | |||
111 | struct basic_scan_params params; | ||
112 | struct basic_scan_channel_params channels[WL1271_SCAN_MAX_CHANNELS]; | ||
113 | |||
114 | /* src mac address */ | ||
115 | u8 addr[ETH_ALEN]; | ||
116 | u8 padding[2]; | ||
117 | } __packed; | ||
118 | |||
119 | struct wl1271_cmd_trigger_scan_to { | ||
120 | struct wl1271_cmd_header header; | ||
121 | |||
122 | __le32 timeout; | ||
123 | } __packed; | ||
124 | |||
125 | #define MAX_CHANNELS_2GHZ 14 | ||
126 | #define MAX_CHANNELS_5GHZ 23 | ||
127 | #define MAX_CHANNELS_4GHZ 4 | ||
128 | |||
129 | #define SCAN_MAX_CYCLE_INTERVALS 16 | ||
130 | #define SCAN_MAX_BANDS 3 | ||
131 | |||
132 | enum { | ||
133 | SCAN_SSID_FILTER_ANY = 0, | ||
134 | SCAN_SSID_FILTER_SPECIFIC = 1, | ||
135 | SCAN_SSID_FILTER_LIST = 2, | ||
136 | SCAN_SSID_FILTER_DISABLED = 3 | ||
137 | }; | ||
138 | |||
139 | enum { | ||
140 | SCAN_BSS_TYPE_INDEPENDENT, | ||
141 | SCAN_BSS_TYPE_INFRASTRUCTURE, | ||
142 | SCAN_BSS_TYPE_ANY, | ||
143 | }; | ||
144 | |||
145 | #define SCAN_CHANNEL_FLAGS_DFS BIT(0) | ||
146 | #define SCAN_CHANNEL_FLAGS_DFS_ENABLED BIT(1) | ||
147 | |||
148 | struct conn_scan_ch_params { | ||
149 | __le16 min_duration; | ||
150 | __le16 max_duration; | ||
151 | __le16 passive_duration; | ||
152 | |||
153 | u8 channel; | ||
154 | u8 tx_power_att; | ||
155 | |||
156 | /* bit 0: DFS channel; bit 1: DFS enabled */ | ||
157 | u8 flags; | ||
158 | |||
159 | u8 padding[3]; | ||
160 | } __packed; | ||
161 | |||
162 | struct wl1271_cmd_sched_scan_config { | ||
163 | struct wl1271_cmd_header header; | ||
164 | |||
165 | __le32 intervals[SCAN_MAX_CYCLE_INTERVALS]; | ||
166 | |||
167 | s8 rssi_threshold; /* for filtering (in dBm) */ | ||
168 | s8 snr_threshold; /* for filtering (in dB) */ | ||
169 | |||
170 | u8 cycles; /* maximum number of scan cycles */ | ||
171 | u8 report_after; /* report when this number of results are received */ | ||
172 | u8 terminate; /* stop scanning after reporting */ | ||
173 | |||
174 | u8 tag; | ||
175 | u8 bss_type; /* for filtering */ | ||
176 | u8 filter_type; | ||
177 | |||
178 | u8 ssid_len; /* For SCAN_SSID_FILTER_SPECIFIC */ | ||
179 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | ||
180 | |||
181 | u8 n_probe_reqs; /* Number of probes requests per channel */ | ||
182 | |||
183 | u8 passive[SCAN_MAX_BANDS]; | ||
184 | u8 active[SCAN_MAX_BANDS]; | ||
185 | |||
186 | u8 dfs; | ||
187 | |||
188 | u8 padding[3]; | ||
189 | |||
190 | struct conn_scan_ch_params channels_2[MAX_CHANNELS_2GHZ]; | ||
191 | struct conn_scan_ch_params channels_5[MAX_CHANNELS_5GHZ]; | ||
192 | struct conn_scan_ch_params channels_4[MAX_CHANNELS_4GHZ]; | ||
193 | } __packed; | ||
194 | |||
195 | |||
196 | #define SCHED_SCAN_MAX_SSIDS 16 | ||
197 | |||
198 | enum { | ||
199 | SCAN_SSID_TYPE_PUBLIC = 0, | ||
200 | SCAN_SSID_TYPE_HIDDEN = 1, | ||
201 | }; | ||
202 | |||
203 | struct wl1271_ssid { | ||
204 | u8 type; | ||
205 | u8 len; | ||
206 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | ||
207 | /* u8 padding[2]; */ | ||
208 | } __packed; | ||
209 | |||
210 | struct wl1271_cmd_sched_scan_ssid_list { | ||
211 | struct wl1271_cmd_header header; | ||
212 | |||
213 | u8 n_ssids; | ||
214 | struct wl1271_ssid ssids[SCHED_SCAN_MAX_SSIDS]; | ||
215 | u8 padding[3]; | ||
216 | } __packed; | ||
217 | |||
218 | struct wl1271_cmd_sched_scan_start { | ||
219 | struct wl1271_cmd_header header; | ||
220 | |||
221 | u8 tag; | ||
222 | u8 padding[3]; | ||
223 | } __packed; | ||
224 | |||
225 | struct wl1271_cmd_sched_scan_stop { | ||
226 | struct wl1271_cmd_header header; | ||
227 | |||
228 | u8 tag; | ||
229 | u8 padding[3]; | ||
230 | } __packed; | ||
231 | |||
232 | |||
233 | #endif /* __WL1271_SCAN_H__ */ | ||
diff --git a/drivers/net/wireless/ti/wl12xx/sdio.c b/drivers/net/wireless/ti/wl12xx/sdio.c new file mode 100644 index 000000000000..4b3c32774bae --- /dev/null +++ b/drivers/net/wireless/ti/wl12xx/sdio.c | |||
@@ -0,0 +1,378 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2009-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 | #include <linux/irq.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/vmalloc.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | #include <linux/mmc/sdio_func.h> | ||
29 | #include <linux/mmc/sdio_ids.h> | ||
30 | #include <linux/mmc/card.h> | ||
31 | #include <linux/mmc/host.h> | ||
32 | #include <linux/gpio.h> | ||
33 | #include <linux/wl12xx.h> | ||
34 | #include <linux/pm_runtime.h> | ||
35 | |||
36 | #include "wl12xx.h" | ||
37 | #include "wl12xx_80211.h" | ||
38 | #include "io.h" | ||
39 | |||
40 | #ifndef SDIO_VENDOR_ID_TI | ||
41 | #define SDIO_VENDOR_ID_TI 0x0097 | ||
42 | #endif | ||
43 | |||
44 | #ifndef SDIO_DEVICE_ID_TI_WL1271 | ||
45 | #define SDIO_DEVICE_ID_TI_WL1271 0x4076 | ||
46 | #endif | ||
47 | |||
48 | struct wl12xx_sdio_glue { | ||
49 | struct device *dev; | ||
50 | struct platform_device *core; | ||
51 | }; | ||
52 | |||
53 | static const struct sdio_device_id wl1271_devices[] __devinitconst = { | ||
54 | { SDIO_DEVICE(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271) }, | ||
55 | {} | ||
56 | }; | ||
57 | MODULE_DEVICE_TABLE(sdio, wl1271_devices); | ||
58 | |||
59 | static void wl1271_sdio_set_block_size(struct device *child, | ||
60 | unsigned int blksz) | ||
61 | { | ||
62 | struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent); | ||
63 | struct sdio_func *func = dev_to_sdio_func(glue->dev); | ||
64 | |||
65 | sdio_claim_host(func); | ||
66 | sdio_set_block_size(func, blksz); | ||
67 | sdio_release_host(func); | ||
68 | } | ||
69 | |||
70 | static void wl12xx_sdio_raw_read(struct device *child, int addr, void *buf, | ||
71 | size_t len, bool fixed) | ||
72 | { | ||
73 | int ret; | ||
74 | struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent); | ||
75 | struct sdio_func *func = dev_to_sdio_func(glue->dev); | ||
76 | |||
77 | sdio_claim_host(func); | ||
78 | |||
79 | if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) { | ||
80 | ((u8 *)buf)[0] = sdio_f0_readb(func, addr, &ret); | ||
81 | dev_dbg(child->parent, "sdio read 52 addr 0x%x, byte 0x%02x\n", | ||
82 | addr, ((u8 *)buf)[0]); | ||
83 | } else { | ||
84 | if (fixed) | ||
85 | ret = sdio_readsb(func, buf, addr, len); | ||
86 | else | ||
87 | ret = sdio_memcpy_fromio(func, buf, addr, len); | ||
88 | |||
89 | dev_dbg(child->parent, "sdio read 53 addr 0x%x, %zu bytes\n", | ||
90 | addr, len); | ||
91 | } | ||
92 | |||
93 | sdio_release_host(func); | ||
94 | |||
95 | if (ret) | ||
96 | dev_err(child->parent, "sdio read failed (%d)\n", ret); | ||
97 | } | ||
98 | |||
99 | static void wl12xx_sdio_raw_write(struct device *child, int addr, void *buf, | ||
100 | size_t len, bool fixed) | ||
101 | { | ||
102 | int ret; | ||
103 | struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent); | ||
104 | struct sdio_func *func = dev_to_sdio_func(glue->dev); | ||
105 | |||
106 | sdio_claim_host(func); | ||
107 | |||
108 | if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) { | ||
109 | sdio_f0_writeb(func, ((u8 *)buf)[0], addr, &ret); | ||
110 | dev_dbg(child->parent, "sdio write 52 addr 0x%x, byte 0x%02x\n", | ||
111 | addr, ((u8 *)buf)[0]); | ||
112 | } else { | ||
113 | dev_dbg(child->parent, "sdio write 53 addr 0x%x, %zu bytes\n", | ||
114 | addr, len); | ||
115 | |||
116 | if (fixed) | ||
117 | ret = sdio_writesb(func, addr, buf, len); | ||
118 | else | ||
119 | ret = sdio_memcpy_toio(func, addr, buf, len); | ||
120 | } | ||
121 | |||
122 | sdio_release_host(func); | ||
123 | |||
124 | if (ret) | ||
125 | dev_err(child->parent, "sdio write failed (%d)\n", ret); | ||
126 | } | ||
127 | |||
128 | static int wl12xx_sdio_power_on(struct wl12xx_sdio_glue *glue) | ||
129 | { | ||
130 | int ret; | ||
131 | struct sdio_func *func = dev_to_sdio_func(glue->dev); | ||
132 | |||
133 | /* If enabled, tell runtime PM not to power off the card */ | ||
134 | if (pm_runtime_enabled(&func->dev)) { | ||
135 | ret = pm_runtime_get_sync(&func->dev); | ||
136 | if (ret < 0) | ||
137 | goto out; | ||
138 | } else { | ||
139 | /* Runtime PM is disabled: power up the card manually */ | ||
140 | ret = mmc_power_restore_host(func->card->host); | ||
141 | if (ret < 0) | ||
142 | goto out; | ||
143 | } | ||
144 | |||
145 | sdio_claim_host(func); | ||
146 | sdio_enable_func(func); | ||
147 | sdio_release_host(func); | ||
148 | |||
149 | out: | ||
150 | return ret; | ||
151 | } | ||
152 | |||
153 | static int wl12xx_sdio_power_off(struct wl12xx_sdio_glue *glue) | ||
154 | { | ||
155 | int ret; | ||
156 | struct sdio_func *func = dev_to_sdio_func(glue->dev); | ||
157 | |||
158 | sdio_claim_host(func); | ||
159 | sdio_disable_func(func); | ||
160 | sdio_release_host(func); | ||
161 | |||
162 | /* Power off the card manually, even if runtime PM is enabled. */ | ||
163 | ret = mmc_power_save_host(func->card->host); | ||
164 | if (ret < 0) | ||
165 | return ret; | ||
166 | |||
167 | /* If enabled, let runtime PM know the card is powered off */ | ||
168 | if (pm_runtime_enabled(&func->dev)) | ||
169 | ret = pm_runtime_put_sync(&func->dev); | ||
170 | |||
171 | return ret; | ||
172 | } | ||
173 | |||
174 | static int wl12xx_sdio_set_power(struct device *child, bool enable) | ||
175 | { | ||
176 | struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent); | ||
177 | |||
178 | if (enable) | ||
179 | return wl12xx_sdio_power_on(glue); | ||
180 | else | ||
181 | return wl12xx_sdio_power_off(glue); | ||
182 | } | ||
183 | |||
184 | static struct wl1271_if_operations sdio_ops = { | ||
185 | .read = wl12xx_sdio_raw_read, | ||
186 | .write = wl12xx_sdio_raw_write, | ||
187 | .power = wl12xx_sdio_set_power, | ||
188 | .set_block_size = wl1271_sdio_set_block_size, | ||
189 | }; | ||
190 | |||
191 | static int __devinit wl1271_probe(struct sdio_func *func, | ||
192 | const struct sdio_device_id *id) | ||
193 | { | ||
194 | struct wl12xx_platform_data *wlan_data; | ||
195 | struct wl12xx_sdio_glue *glue; | ||
196 | struct resource res[1]; | ||
197 | mmc_pm_flag_t mmcflags; | ||
198 | int ret = -ENOMEM; | ||
199 | |||
200 | /* We are only able to handle the wlan function */ | ||
201 | if (func->num != 0x02) | ||
202 | return -ENODEV; | ||
203 | |||
204 | glue = kzalloc(sizeof(*glue), GFP_KERNEL); | ||
205 | if (!glue) { | ||
206 | dev_err(&func->dev, "can't allocate glue\n"); | ||
207 | goto out; | ||
208 | } | ||
209 | |||
210 | glue->dev = &func->dev; | ||
211 | |||
212 | /* Grab access to FN0 for ELP reg. */ | ||
213 | func->card->quirks |= MMC_QUIRK_LENIENT_FN0; | ||
214 | |||
215 | /* Use block mode for transferring over one block size of data */ | ||
216 | func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; | ||
217 | |||
218 | wlan_data = wl12xx_get_platform_data(); | ||
219 | if (IS_ERR(wlan_data)) { | ||
220 | ret = PTR_ERR(wlan_data); | ||
221 | dev_err(glue->dev, "missing wlan platform data: %d\n", ret); | ||
222 | goto out_free_glue; | ||
223 | } | ||
224 | |||
225 | /* if sdio can keep power while host is suspended, enable wow */ | ||
226 | mmcflags = sdio_get_host_pm_caps(func); | ||
227 | dev_dbg(glue->dev, "sdio PM caps = 0x%x\n", mmcflags); | ||
228 | |||
229 | if (mmcflags & MMC_PM_KEEP_POWER) | ||
230 | wlan_data->pwr_in_suspend = true; | ||
231 | |||
232 | wlan_data->ops = &sdio_ops; | ||
233 | |||
234 | sdio_set_drvdata(func, glue); | ||
235 | |||
236 | /* Tell PM core that we don't need the card to be powered now */ | ||
237 | pm_runtime_put_noidle(&func->dev); | ||
238 | |||
239 | glue->core = platform_device_alloc("wl12xx", -1); | ||
240 | if (!glue->core) { | ||
241 | dev_err(glue->dev, "can't allocate platform_device"); | ||
242 | ret = -ENOMEM; | ||
243 | goto out_free_glue; | ||
244 | } | ||
245 | |||
246 | glue->core->dev.parent = &func->dev; | ||
247 | |||
248 | memset(res, 0x00, sizeof(res)); | ||
249 | |||
250 | res[0].start = wlan_data->irq; | ||
251 | res[0].flags = IORESOURCE_IRQ; | ||
252 | res[0].name = "irq"; | ||
253 | |||
254 | ret = platform_device_add_resources(glue->core, res, ARRAY_SIZE(res)); | ||
255 | if (ret) { | ||
256 | dev_err(glue->dev, "can't add resources\n"); | ||
257 | goto out_dev_put; | ||
258 | } | ||
259 | |||
260 | ret = platform_device_add_data(glue->core, wlan_data, | ||
261 | sizeof(*wlan_data)); | ||
262 | if (ret) { | ||
263 | dev_err(glue->dev, "can't add platform data\n"); | ||
264 | goto out_dev_put; | ||
265 | } | ||
266 | |||
267 | ret = platform_device_add(glue->core); | ||
268 | if (ret) { | ||
269 | dev_err(glue->dev, "can't add platform device\n"); | ||
270 | goto out_dev_put; | ||
271 | } | ||
272 | return 0; | ||
273 | |||
274 | out_dev_put: | ||
275 | platform_device_put(glue->core); | ||
276 | |||
277 | out_free_glue: | ||
278 | kfree(glue); | ||
279 | |||
280 | out: | ||
281 | return ret; | ||
282 | } | ||
283 | |||
284 | static void __devexit wl1271_remove(struct sdio_func *func) | ||
285 | { | ||
286 | struct wl12xx_sdio_glue *glue = sdio_get_drvdata(func); | ||
287 | |||
288 | /* Undo decrement done above in wl1271_probe */ | ||
289 | pm_runtime_get_noresume(&func->dev); | ||
290 | |||
291 | platform_device_del(glue->core); | ||
292 | platform_device_put(glue->core); | ||
293 | kfree(glue); | ||
294 | } | ||
295 | |||
296 | #ifdef CONFIG_PM | ||
297 | static int wl1271_suspend(struct device *dev) | ||
298 | { | ||
299 | /* Tell MMC/SDIO core it's OK to power down the card | ||
300 | * (if it isn't already), but not to remove it completely */ | ||
301 | struct sdio_func *func = dev_to_sdio_func(dev); | ||
302 | struct wl12xx_sdio_glue *glue = sdio_get_drvdata(func); | ||
303 | struct wl1271 *wl = platform_get_drvdata(glue->core); | ||
304 | mmc_pm_flag_t sdio_flags; | ||
305 | int ret = 0; | ||
306 | |||
307 | dev_dbg(dev, "wl1271 suspend. wow_enabled: %d\n", | ||
308 | wl->wow_enabled); | ||
309 | |||
310 | /* check whether sdio should keep power */ | ||
311 | if (wl->wow_enabled) { | ||
312 | sdio_flags = sdio_get_host_pm_caps(func); | ||
313 | |||
314 | if (!(sdio_flags & MMC_PM_KEEP_POWER)) { | ||
315 | dev_err(dev, "can't keep power while host " | ||
316 | "is suspended\n"); | ||
317 | ret = -EINVAL; | ||
318 | goto out; | ||
319 | } | ||
320 | |||
321 | /* keep power while host suspended */ | ||
322 | ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); | ||
323 | if (ret) { | ||
324 | dev_err(dev, "error while trying to keep power\n"); | ||
325 | goto out; | ||
326 | } | ||
327 | } | ||
328 | out: | ||
329 | return ret; | ||
330 | } | ||
331 | |||
332 | static int wl1271_resume(struct device *dev) | ||
333 | { | ||
334 | dev_dbg(dev, "wl1271 resume\n"); | ||
335 | |||
336 | return 0; | ||
337 | } | ||
338 | |||
339 | static const struct dev_pm_ops wl1271_sdio_pm_ops = { | ||
340 | .suspend = wl1271_suspend, | ||
341 | .resume = wl1271_resume, | ||
342 | }; | ||
343 | #endif | ||
344 | |||
345 | static struct sdio_driver wl1271_sdio_driver = { | ||
346 | .name = "wl1271_sdio", | ||
347 | .id_table = wl1271_devices, | ||
348 | .probe = wl1271_probe, | ||
349 | .remove = __devexit_p(wl1271_remove), | ||
350 | #ifdef CONFIG_PM | ||
351 | .drv = { | ||
352 | .pm = &wl1271_sdio_pm_ops, | ||
353 | }, | ||
354 | #endif | ||
355 | }; | ||
356 | |||
357 | static int __init wl1271_init(void) | ||
358 | { | ||
359 | return sdio_register_driver(&wl1271_sdio_driver); | ||
360 | } | ||
361 | |||
362 | static void __exit wl1271_exit(void) | ||
363 | { | ||
364 | sdio_unregister_driver(&wl1271_sdio_driver); | ||
365 | } | ||
366 | |||
367 | module_init(wl1271_init); | ||
368 | module_exit(wl1271_exit); | ||
369 | |||
370 | MODULE_LICENSE("GPL"); | ||
371 | MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>"); | ||
372 | MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); | ||
373 | MODULE_FIRMWARE(WL127X_FW_NAME_SINGLE); | ||
374 | MODULE_FIRMWARE(WL127X_FW_NAME_MULTI); | ||
375 | MODULE_FIRMWARE(WL127X_PLT_FW_NAME); | ||
376 | MODULE_FIRMWARE(WL128X_FW_NAME_SINGLE); | ||
377 | MODULE_FIRMWARE(WL128X_FW_NAME_MULTI); | ||
378 | MODULE_FIRMWARE(WL128X_PLT_FW_NAME); | ||
diff --git a/drivers/net/wireless/ti/wl12xx/spi.c b/drivers/net/wireless/ti/wl12xx/spi.c new file mode 100644 index 000000000000..2fc18a8dcce8 --- /dev/null +++ b/drivers/net/wireless/ti/wl12xx/spi.c | |||
@@ -0,0 +1,442 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2008-2009 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 | #include <linux/interrupt.h> | ||
25 | #include <linux/irq.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/crc7.h> | ||
28 | #include <linux/spi/spi.h> | ||
29 | #include <linux/wl12xx.h> | ||
30 | #include <linux/platform_device.h> | ||
31 | #include <linux/slab.h> | ||
32 | |||
33 | #include "wl12xx.h" | ||
34 | #include "wl12xx_80211.h" | ||
35 | #include "io.h" | ||
36 | |||
37 | #include "reg.h" | ||
38 | |||
39 | #define WSPI_CMD_READ 0x40000000 | ||
40 | #define WSPI_CMD_WRITE 0x00000000 | ||
41 | #define WSPI_CMD_FIXED 0x20000000 | ||
42 | #define WSPI_CMD_BYTE_LENGTH 0x1FFE0000 | ||
43 | #define WSPI_CMD_BYTE_LENGTH_OFFSET 17 | ||
44 | #define WSPI_CMD_BYTE_ADDR 0x0001FFFF | ||
45 | |||
46 | #define WSPI_INIT_CMD_CRC_LEN 5 | ||
47 | |||
48 | #define WSPI_INIT_CMD_START 0x00 | ||
49 | #define WSPI_INIT_CMD_TX 0x40 | ||
50 | /* the extra bypass bit is sampled by the TNET as '1' */ | ||
51 | #define WSPI_INIT_CMD_BYPASS_BIT 0x80 | ||
52 | #define WSPI_INIT_CMD_FIXEDBUSY_LEN 0x07 | ||
53 | #define WSPI_INIT_CMD_EN_FIXEDBUSY 0x80 | ||
54 | #define WSPI_INIT_CMD_DIS_FIXEDBUSY 0x00 | ||
55 | #define WSPI_INIT_CMD_IOD 0x40 | ||
56 | #define WSPI_INIT_CMD_IP 0x20 | ||
57 | #define WSPI_INIT_CMD_CS 0x10 | ||
58 | #define WSPI_INIT_CMD_WS 0x08 | ||
59 | #define WSPI_INIT_CMD_WSPI 0x01 | ||
60 | #define WSPI_INIT_CMD_END 0x01 | ||
61 | |||
62 | #define WSPI_INIT_CMD_LEN 8 | ||
63 | |||
64 | #define HW_ACCESS_WSPI_FIXED_BUSY_LEN \ | ||
65 | ((WL1271_BUSY_WORD_LEN - 4) / sizeof(u32)) | ||
66 | #define HW_ACCESS_WSPI_INIT_CMD_MASK 0 | ||
67 | |||
68 | /* HW limitation: maximum possible chunk size is 4095 bytes */ | ||
69 | #define WSPI_MAX_CHUNK_SIZE 4092 | ||
70 | |||
71 | #define WSPI_MAX_NUM_OF_CHUNKS (WL1271_AGGR_BUFFER_SIZE / WSPI_MAX_CHUNK_SIZE) | ||
72 | |||
73 | struct wl12xx_spi_glue { | ||
74 | struct device *dev; | ||
75 | struct platform_device *core; | ||
76 | }; | ||
77 | |||
78 | static void wl12xx_spi_reset(struct device *child) | ||
79 | { | ||
80 | struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent); | ||
81 | u8 *cmd; | ||
82 | struct spi_transfer t; | ||
83 | struct spi_message m; | ||
84 | |||
85 | cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); | ||
86 | if (!cmd) { | ||
87 | dev_err(child->parent, | ||
88 | "could not allocate cmd for spi reset\n"); | ||
89 | return; | ||
90 | } | ||
91 | |||
92 | memset(&t, 0, sizeof(t)); | ||
93 | spi_message_init(&m); | ||
94 | |||
95 | memset(cmd, 0xff, WSPI_INIT_CMD_LEN); | ||
96 | |||
97 | t.tx_buf = cmd; | ||
98 | t.len = WSPI_INIT_CMD_LEN; | ||
99 | spi_message_add_tail(&t, &m); | ||
100 | |||
101 | spi_sync(to_spi_device(glue->dev), &m); | ||
102 | |||
103 | kfree(cmd); | ||
104 | } | ||
105 | |||
106 | static void wl12xx_spi_init(struct device *child) | ||
107 | { | ||
108 | struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent); | ||
109 | u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd; | ||
110 | struct spi_transfer t; | ||
111 | struct spi_message m; | ||
112 | |||
113 | cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); | ||
114 | if (!cmd) { | ||
115 | dev_err(child->parent, | ||
116 | "could not allocate cmd for spi init\n"); | ||
117 | return; | ||
118 | } | ||
119 | |||
120 | memset(crc, 0, sizeof(crc)); | ||
121 | memset(&t, 0, sizeof(t)); | ||
122 | spi_message_init(&m); | ||
123 | |||
124 | /* | ||
125 | * Set WSPI_INIT_COMMAND | ||
126 | * the data is being send from the MSB to LSB | ||
127 | */ | ||
128 | cmd[2] = 0xff; | ||
129 | cmd[3] = 0xff; | ||
130 | cmd[1] = WSPI_INIT_CMD_START | WSPI_INIT_CMD_TX; | ||
131 | cmd[0] = 0; | ||
132 | cmd[7] = 0; | ||
133 | cmd[6] |= HW_ACCESS_WSPI_INIT_CMD_MASK << 3; | ||
134 | cmd[6] |= HW_ACCESS_WSPI_FIXED_BUSY_LEN & WSPI_INIT_CMD_FIXEDBUSY_LEN; | ||
135 | |||
136 | if (HW_ACCESS_WSPI_FIXED_BUSY_LEN == 0) | ||
137 | cmd[5] |= WSPI_INIT_CMD_DIS_FIXEDBUSY; | ||
138 | else | ||
139 | cmd[5] |= WSPI_INIT_CMD_EN_FIXEDBUSY; | ||
140 | |||
141 | cmd[5] |= WSPI_INIT_CMD_IOD | WSPI_INIT_CMD_IP | WSPI_INIT_CMD_CS | ||
142 | | WSPI_INIT_CMD_WSPI | WSPI_INIT_CMD_WS; | ||
143 | |||
144 | crc[0] = cmd[1]; | ||
145 | crc[1] = cmd[0]; | ||
146 | crc[2] = cmd[7]; | ||
147 | crc[3] = cmd[6]; | ||
148 | crc[4] = cmd[5]; | ||
149 | |||
150 | cmd[4] |= crc7(0, crc, WSPI_INIT_CMD_CRC_LEN) << 1; | ||
151 | cmd[4] |= WSPI_INIT_CMD_END; | ||
152 | |||
153 | t.tx_buf = cmd; | ||
154 | t.len = WSPI_INIT_CMD_LEN; | ||
155 | spi_message_add_tail(&t, &m); | ||
156 | |||
157 | spi_sync(to_spi_device(glue->dev), &m); | ||
158 | kfree(cmd); | ||
159 | } | ||
160 | |||
161 | #define WL1271_BUSY_WORD_TIMEOUT 1000 | ||
162 | |||
163 | static int wl12xx_spi_read_busy(struct device *child) | ||
164 | { | ||
165 | struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent); | ||
166 | struct wl1271 *wl = dev_get_drvdata(child); | ||
167 | struct spi_transfer t[1]; | ||
168 | struct spi_message m; | ||
169 | u32 *busy_buf; | ||
170 | int num_busy_bytes = 0; | ||
171 | |||
172 | /* | ||
173 | * Read further busy words from SPI until a non-busy word is | ||
174 | * encountered, then read the data itself into the buffer. | ||
175 | */ | ||
176 | |||
177 | num_busy_bytes = WL1271_BUSY_WORD_TIMEOUT; | ||
178 | busy_buf = wl->buffer_busyword; | ||
179 | while (num_busy_bytes) { | ||
180 | num_busy_bytes--; | ||
181 | spi_message_init(&m); | ||
182 | memset(t, 0, sizeof(t)); | ||
183 | t[0].rx_buf = busy_buf; | ||
184 | t[0].len = sizeof(u32); | ||
185 | t[0].cs_change = true; | ||
186 | spi_message_add_tail(&t[0], &m); | ||
187 | spi_sync(to_spi_device(glue->dev), &m); | ||
188 | |||
189 | if (*busy_buf & 0x1) | ||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | /* The SPI bus is unresponsive, the read failed. */ | ||
194 | dev_err(child->parent, "SPI read busy-word timeout!\n"); | ||
195 | return -ETIMEDOUT; | ||
196 | } | ||
197 | |||
198 | static void wl12xx_spi_raw_read(struct device *child, int addr, void *buf, | ||
199 | size_t len, bool fixed) | ||
200 | { | ||
201 | struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent); | ||
202 | struct wl1271 *wl = dev_get_drvdata(child); | ||
203 | struct spi_transfer t[2]; | ||
204 | struct spi_message m; | ||
205 | u32 *busy_buf; | ||
206 | u32 *cmd; | ||
207 | u32 chunk_len; | ||
208 | |||
209 | while (len > 0) { | ||
210 | chunk_len = min((size_t)WSPI_MAX_CHUNK_SIZE, len); | ||
211 | |||
212 | cmd = &wl->buffer_cmd; | ||
213 | busy_buf = wl->buffer_busyword; | ||
214 | |||
215 | *cmd = 0; | ||
216 | *cmd |= WSPI_CMD_READ; | ||
217 | *cmd |= (chunk_len << WSPI_CMD_BYTE_LENGTH_OFFSET) & | ||
218 | WSPI_CMD_BYTE_LENGTH; | ||
219 | *cmd |= addr & WSPI_CMD_BYTE_ADDR; | ||
220 | |||
221 | if (fixed) | ||
222 | *cmd |= WSPI_CMD_FIXED; | ||
223 | |||
224 | spi_message_init(&m); | ||
225 | memset(t, 0, sizeof(t)); | ||
226 | |||
227 | t[0].tx_buf = cmd; | ||
228 | t[0].len = 4; | ||
229 | t[0].cs_change = true; | ||
230 | spi_message_add_tail(&t[0], &m); | ||
231 | |||
232 | /* Busy and non busy words read */ | ||
233 | t[1].rx_buf = busy_buf; | ||
234 | t[1].len = WL1271_BUSY_WORD_LEN; | ||
235 | t[1].cs_change = true; | ||
236 | spi_message_add_tail(&t[1], &m); | ||
237 | |||
238 | spi_sync(to_spi_device(glue->dev), &m); | ||
239 | |||
240 | if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1) && | ||
241 | wl12xx_spi_read_busy(child)) { | ||
242 | memset(buf, 0, chunk_len); | ||
243 | return; | ||
244 | } | ||
245 | |||
246 | spi_message_init(&m); | ||
247 | memset(t, 0, sizeof(t)); | ||
248 | |||
249 | t[0].rx_buf = buf; | ||
250 | t[0].len = chunk_len; | ||
251 | t[0].cs_change = true; | ||
252 | spi_message_add_tail(&t[0], &m); | ||
253 | |||
254 | spi_sync(to_spi_device(glue->dev), &m); | ||
255 | |||
256 | if (!fixed) | ||
257 | addr += chunk_len; | ||
258 | buf += chunk_len; | ||
259 | len -= chunk_len; | ||
260 | } | ||
261 | } | ||
262 | |||
263 | static void wl12xx_spi_raw_write(struct device *child, int addr, void *buf, | ||
264 | size_t len, bool fixed) | ||
265 | { | ||
266 | struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent); | ||
267 | struct spi_transfer t[2 * WSPI_MAX_NUM_OF_CHUNKS]; | ||
268 | struct spi_message m; | ||
269 | u32 commands[WSPI_MAX_NUM_OF_CHUNKS]; | ||
270 | u32 *cmd; | ||
271 | u32 chunk_len; | ||
272 | int i; | ||
273 | |||
274 | WARN_ON(len > WL1271_AGGR_BUFFER_SIZE); | ||
275 | |||
276 | spi_message_init(&m); | ||
277 | memset(t, 0, sizeof(t)); | ||
278 | |||
279 | cmd = &commands[0]; | ||
280 | i = 0; | ||
281 | while (len > 0) { | ||
282 | chunk_len = min((size_t)WSPI_MAX_CHUNK_SIZE, len); | ||
283 | |||
284 | *cmd = 0; | ||
285 | *cmd |= WSPI_CMD_WRITE; | ||
286 | *cmd |= (chunk_len << WSPI_CMD_BYTE_LENGTH_OFFSET) & | ||
287 | WSPI_CMD_BYTE_LENGTH; | ||
288 | *cmd |= addr & WSPI_CMD_BYTE_ADDR; | ||
289 | |||
290 | if (fixed) | ||
291 | *cmd |= WSPI_CMD_FIXED; | ||
292 | |||
293 | t[i].tx_buf = cmd; | ||
294 | t[i].len = sizeof(*cmd); | ||
295 | spi_message_add_tail(&t[i++], &m); | ||
296 | |||
297 | t[i].tx_buf = buf; | ||
298 | t[i].len = chunk_len; | ||
299 | spi_message_add_tail(&t[i++], &m); | ||
300 | |||
301 | if (!fixed) | ||
302 | addr += chunk_len; | ||
303 | buf += chunk_len; | ||
304 | len -= chunk_len; | ||
305 | cmd++; | ||
306 | } | ||
307 | |||
308 | spi_sync(to_spi_device(glue->dev), &m); | ||
309 | } | ||
310 | |||
311 | static struct wl1271_if_operations spi_ops = { | ||
312 | .read = wl12xx_spi_raw_read, | ||
313 | .write = wl12xx_spi_raw_write, | ||
314 | .reset = wl12xx_spi_reset, | ||
315 | .init = wl12xx_spi_init, | ||
316 | .set_block_size = NULL, | ||
317 | }; | ||
318 | |||
319 | static int __devinit wl1271_probe(struct spi_device *spi) | ||
320 | { | ||
321 | struct wl12xx_spi_glue *glue; | ||
322 | struct wl12xx_platform_data *pdata; | ||
323 | struct resource res[1]; | ||
324 | int ret = -ENOMEM; | ||
325 | |||
326 | pdata = spi->dev.platform_data; | ||
327 | if (!pdata) { | ||
328 | dev_err(&spi->dev, "no platform data\n"); | ||
329 | return -ENODEV; | ||
330 | } | ||
331 | |||
332 | pdata->ops = &spi_ops; | ||
333 | |||
334 | glue = kzalloc(sizeof(*glue), GFP_KERNEL); | ||
335 | if (!glue) { | ||
336 | dev_err(&spi->dev, "can't allocate glue\n"); | ||
337 | goto out; | ||
338 | } | ||
339 | |||
340 | glue->dev = &spi->dev; | ||
341 | |||
342 | spi_set_drvdata(spi, glue); | ||
343 | |||
344 | /* This is the only SPI value that we need to set here, the rest | ||
345 | * comes from the board-peripherals file */ | ||
346 | spi->bits_per_word = 32; | ||
347 | |||
348 | ret = spi_setup(spi); | ||
349 | if (ret < 0) { | ||
350 | dev_err(glue->dev, "spi_setup failed\n"); | ||
351 | goto out_free_glue; | ||
352 | } | ||
353 | |||
354 | glue->core = platform_device_alloc("wl12xx", -1); | ||
355 | if (!glue->core) { | ||
356 | dev_err(glue->dev, "can't allocate platform_device\n"); | ||
357 | ret = -ENOMEM; | ||
358 | goto out_free_glue; | ||
359 | } | ||
360 | |||
361 | glue->core->dev.parent = &spi->dev; | ||
362 | |||
363 | memset(res, 0x00, sizeof(res)); | ||
364 | |||
365 | res[0].start = spi->irq; | ||
366 | res[0].flags = IORESOURCE_IRQ; | ||
367 | res[0].name = "irq"; | ||
368 | |||
369 | ret = platform_device_add_resources(glue->core, res, ARRAY_SIZE(res)); | ||
370 | if (ret) { | ||
371 | dev_err(glue->dev, "can't add resources\n"); | ||
372 | goto out_dev_put; | ||
373 | } | ||
374 | |||
375 | ret = platform_device_add_data(glue->core, pdata, sizeof(*pdata)); | ||
376 | if (ret) { | ||
377 | dev_err(glue->dev, "can't add platform data\n"); | ||
378 | goto out_dev_put; | ||
379 | } | ||
380 | |||
381 | ret = platform_device_add(glue->core); | ||
382 | if (ret) { | ||
383 | dev_err(glue->dev, "can't register platform device\n"); | ||
384 | goto out_dev_put; | ||
385 | } | ||
386 | |||
387 | return 0; | ||
388 | |||
389 | out_dev_put: | ||
390 | platform_device_put(glue->core); | ||
391 | |||
392 | out_free_glue: | ||
393 | kfree(glue); | ||
394 | out: | ||
395 | return ret; | ||
396 | } | ||
397 | |||
398 | static int __devexit wl1271_remove(struct spi_device *spi) | ||
399 | { | ||
400 | struct wl12xx_spi_glue *glue = spi_get_drvdata(spi); | ||
401 | |||
402 | platform_device_del(glue->core); | ||
403 | platform_device_put(glue->core); | ||
404 | kfree(glue); | ||
405 | |||
406 | return 0; | ||
407 | } | ||
408 | |||
409 | |||
410 | static struct spi_driver wl1271_spi_driver = { | ||
411 | .driver = { | ||
412 | .name = "wl1271_spi", | ||
413 | .owner = THIS_MODULE, | ||
414 | }, | ||
415 | |||
416 | .probe = wl1271_probe, | ||
417 | .remove = __devexit_p(wl1271_remove), | ||
418 | }; | ||
419 | |||
420 | static int __init wl1271_init(void) | ||
421 | { | ||
422 | return spi_register_driver(&wl1271_spi_driver); | ||
423 | } | ||
424 | |||
425 | static void __exit wl1271_exit(void) | ||
426 | { | ||
427 | spi_unregister_driver(&wl1271_spi_driver); | ||
428 | } | ||
429 | |||
430 | module_init(wl1271_init); | ||
431 | module_exit(wl1271_exit); | ||
432 | |||
433 | MODULE_LICENSE("GPL"); | ||
434 | MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>"); | ||
435 | MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); | ||
436 | MODULE_FIRMWARE(WL127X_FW_NAME_SINGLE); | ||
437 | MODULE_FIRMWARE(WL127X_FW_NAME_MULTI); | ||
438 | MODULE_FIRMWARE(WL127X_PLT_FW_NAME); | ||
439 | MODULE_FIRMWARE(WL128X_FW_NAME_SINGLE); | ||
440 | MODULE_FIRMWARE(WL128X_FW_NAME_MULTI); | ||
441 | MODULE_FIRMWARE(WL128X_PLT_FW_NAME); | ||
442 | MODULE_ALIAS("spi:wl1271"); | ||
diff --git a/drivers/net/wireless/ti/wl12xx/testmode.c b/drivers/net/wireless/ti/wl12xx/testmode.c new file mode 100644 index 000000000000..1e93bb9c0246 --- /dev/null +++ b/drivers/net/wireless/ti/wl12xx/testmode.c | |||
@@ -0,0 +1,344 @@ | |||
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 | #include "testmode.h" | ||
24 | |||
25 | #include <linux/slab.h> | ||
26 | #include <net/genetlink.h> | ||
27 | |||
28 | #include "wl12xx.h" | ||
29 | #include "debug.h" | ||
30 | #include "acx.h" | ||
31 | #include "reg.h" | ||
32 | #include "ps.h" | ||
33 | #include "io.h" | ||
34 | |||
35 | #define WL1271_TM_MAX_DATA_LENGTH 1024 | ||
36 | |||
37 | enum wl1271_tm_commands { | ||
38 | WL1271_TM_CMD_UNSPEC, | ||
39 | WL1271_TM_CMD_TEST, | ||
40 | WL1271_TM_CMD_INTERROGATE, | ||
41 | WL1271_TM_CMD_CONFIGURE, | ||
42 | WL1271_TM_CMD_NVS_PUSH, /* Not in use. Keep to not break ABI */ | ||
43 | WL1271_TM_CMD_SET_PLT_MODE, | ||
44 | WL1271_TM_CMD_RECOVER, | ||
45 | WL1271_TM_CMD_GET_MAC, | ||
46 | |||
47 | __WL1271_TM_CMD_AFTER_LAST | ||
48 | }; | ||
49 | #define WL1271_TM_CMD_MAX (__WL1271_TM_CMD_AFTER_LAST - 1) | ||
50 | |||
51 | enum wl1271_tm_attrs { | ||
52 | WL1271_TM_ATTR_UNSPEC, | ||
53 | WL1271_TM_ATTR_CMD_ID, | ||
54 | WL1271_TM_ATTR_ANSWER, | ||
55 | WL1271_TM_ATTR_DATA, | ||
56 | WL1271_TM_ATTR_IE_ID, | ||
57 | WL1271_TM_ATTR_PLT_MODE, | ||
58 | |||
59 | __WL1271_TM_ATTR_AFTER_LAST | ||
60 | }; | ||
61 | #define WL1271_TM_ATTR_MAX (__WL1271_TM_ATTR_AFTER_LAST - 1) | ||
62 | |||
63 | static struct nla_policy wl1271_tm_policy[WL1271_TM_ATTR_MAX + 1] = { | ||
64 | [WL1271_TM_ATTR_CMD_ID] = { .type = NLA_U32 }, | ||
65 | [WL1271_TM_ATTR_ANSWER] = { .type = NLA_U8 }, | ||
66 | [WL1271_TM_ATTR_DATA] = { .type = NLA_BINARY, | ||
67 | .len = WL1271_TM_MAX_DATA_LENGTH }, | ||
68 | [WL1271_TM_ATTR_IE_ID] = { .type = NLA_U32 }, | ||
69 | [WL1271_TM_ATTR_PLT_MODE] = { .type = NLA_U32 }, | ||
70 | }; | ||
71 | |||
72 | |||
73 | static int wl1271_tm_cmd_test(struct wl1271 *wl, struct nlattr *tb[]) | ||
74 | { | ||
75 | int buf_len, ret, len; | ||
76 | struct sk_buff *skb; | ||
77 | void *buf; | ||
78 | u8 answer = 0; | ||
79 | |||
80 | wl1271_debug(DEBUG_TESTMODE, "testmode cmd test"); | ||
81 | |||
82 | if (!tb[WL1271_TM_ATTR_DATA]) | ||
83 | return -EINVAL; | ||
84 | |||
85 | buf = nla_data(tb[WL1271_TM_ATTR_DATA]); | ||
86 | buf_len = nla_len(tb[WL1271_TM_ATTR_DATA]); | ||
87 | |||
88 | if (tb[WL1271_TM_ATTR_ANSWER]) | ||
89 | answer = nla_get_u8(tb[WL1271_TM_ATTR_ANSWER]); | ||
90 | |||
91 | if (buf_len > sizeof(struct wl1271_command)) | ||
92 | return -EMSGSIZE; | ||
93 | |||
94 | mutex_lock(&wl->mutex); | ||
95 | |||
96 | if (wl->state == WL1271_STATE_OFF) { | ||
97 | ret = -EINVAL; | ||
98 | goto out; | ||
99 | } | ||
100 | |||
101 | ret = wl1271_ps_elp_wakeup(wl); | ||
102 | if (ret < 0) | ||
103 | goto out; | ||
104 | |||
105 | ret = wl1271_cmd_test(wl, buf, buf_len, answer); | ||
106 | if (ret < 0) { | ||
107 | wl1271_warning("testmode cmd test failed: %d", ret); | ||
108 | goto out_sleep; | ||
109 | } | ||
110 | |||
111 | if (answer) { | ||
112 | len = nla_total_size(buf_len); | ||
113 | skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, len); | ||
114 | if (!skb) { | ||
115 | ret = -ENOMEM; | ||
116 | goto out_sleep; | ||
117 | } | ||
118 | |||
119 | NLA_PUT(skb, WL1271_TM_ATTR_DATA, buf_len, buf); | ||
120 | ret = cfg80211_testmode_reply(skb); | ||
121 | if (ret < 0) | ||
122 | goto out_sleep; | ||
123 | } | ||
124 | |||
125 | out_sleep: | ||
126 | wl1271_ps_elp_sleep(wl); | ||
127 | out: | ||
128 | mutex_unlock(&wl->mutex); | ||
129 | |||
130 | return ret; | ||
131 | |||
132 | nla_put_failure: | ||
133 | kfree_skb(skb); | ||
134 | ret = -EMSGSIZE; | ||
135 | goto out_sleep; | ||
136 | } | ||
137 | |||
138 | static int wl1271_tm_cmd_interrogate(struct wl1271 *wl, struct nlattr *tb[]) | ||
139 | { | ||
140 | int ret; | ||
141 | struct wl1271_command *cmd; | ||
142 | struct sk_buff *skb; | ||
143 | u8 ie_id; | ||
144 | |||
145 | wl1271_debug(DEBUG_TESTMODE, "testmode cmd interrogate"); | ||
146 | |||
147 | if (!tb[WL1271_TM_ATTR_IE_ID]) | ||
148 | return -EINVAL; | ||
149 | |||
150 | ie_id = nla_get_u8(tb[WL1271_TM_ATTR_IE_ID]); | ||
151 | |||
152 | mutex_lock(&wl->mutex); | ||
153 | |||
154 | if (wl->state == WL1271_STATE_OFF) { | ||
155 | ret = -EINVAL; | ||
156 | goto out; | ||
157 | } | ||
158 | |||
159 | ret = wl1271_ps_elp_wakeup(wl); | ||
160 | if (ret < 0) | ||
161 | goto out; | ||
162 | |||
163 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
164 | if (!cmd) { | ||
165 | ret = -ENOMEM; | ||
166 | goto out_sleep; | ||
167 | } | ||
168 | |||
169 | ret = wl1271_cmd_interrogate(wl, ie_id, cmd, sizeof(*cmd)); | ||
170 | if (ret < 0) { | ||
171 | wl1271_warning("testmode cmd interrogate failed: %d", ret); | ||
172 | goto out_free; | ||
173 | } | ||
174 | |||
175 | skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, sizeof(*cmd)); | ||
176 | if (!skb) { | ||
177 | ret = -ENOMEM; | ||
178 | goto out_free; | ||
179 | } | ||
180 | |||
181 | NLA_PUT(skb, WL1271_TM_ATTR_DATA, sizeof(*cmd), cmd); | ||
182 | ret = cfg80211_testmode_reply(skb); | ||
183 | if (ret < 0) | ||
184 | goto out_free; | ||
185 | |||
186 | out_free: | ||
187 | kfree(cmd); | ||
188 | out_sleep: | ||
189 | wl1271_ps_elp_sleep(wl); | ||
190 | out: | ||
191 | mutex_unlock(&wl->mutex); | ||
192 | |||
193 | return ret; | ||
194 | |||
195 | nla_put_failure: | ||
196 | kfree_skb(skb); | ||
197 | ret = -EMSGSIZE; | ||
198 | goto out_free; | ||
199 | } | ||
200 | |||
201 | static int wl1271_tm_cmd_configure(struct wl1271 *wl, struct nlattr *tb[]) | ||
202 | { | ||
203 | int buf_len, ret; | ||
204 | void *buf; | ||
205 | u8 ie_id; | ||
206 | |||
207 | wl1271_debug(DEBUG_TESTMODE, "testmode cmd configure"); | ||
208 | |||
209 | if (!tb[WL1271_TM_ATTR_DATA]) | ||
210 | return -EINVAL; | ||
211 | if (!tb[WL1271_TM_ATTR_IE_ID]) | ||
212 | return -EINVAL; | ||
213 | |||
214 | ie_id = nla_get_u8(tb[WL1271_TM_ATTR_IE_ID]); | ||
215 | buf = nla_data(tb[WL1271_TM_ATTR_DATA]); | ||
216 | buf_len = nla_len(tb[WL1271_TM_ATTR_DATA]); | ||
217 | |||
218 | if (buf_len > sizeof(struct wl1271_command)) | ||
219 | return -EMSGSIZE; | ||
220 | |||
221 | mutex_lock(&wl->mutex); | ||
222 | ret = wl1271_cmd_configure(wl, ie_id, buf, buf_len); | ||
223 | mutex_unlock(&wl->mutex); | ||
224 | |||
225 | if (ret < 0) { | ||
226 | wl1271_warning("testmode cmd configure failed: %d", ret); | ||
227 | return ret; | ||
228 | } | ||
229 | |||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | static int wl1271_tm_cmd_set_plt_mode(struct wl1271 *wl, struct nlattr *tb[]) | ||
234 | { | ||
235 | u32 val; | ||
236 | int ret; | ||
237 | |||
238 | wl1271_debug(DEBUG_TESTMODE, "testmode cmd set plt mode"); | ||
239 | |||
240 | if (!tb[WL1271_TM_ATTR_PLT_MODE]) | ||
241 | return -EINVAL; | ||
242 | |||
243 | val = nla_get_u32(tb[WL1271_TM_ATTR_PLT_MODE]); | ||
244 | |||
245 | switch (val) { | ||
246 | case 0: | ||
247 | ret = wl1271_plt_stop(wl); | ||
248 | break; | ||
249 | case 1: | ||
250 | ret = wl1271_plt_start(wl); | ||
251 | break; | ||
252 | default: | ||
253 | ret = -EINVAL; | ||
254 | break; | ||
255 | } | ||
256 | |||
257 | return ret; | ||
258 | } | ||
259 | |||
260 | static int wl1271_tm_cmd_recover(struct wl1271 *wl, struct nlattr *tb[]) | ||
261 | { | ||
262 | wl1271_debug(DEBUG_TESTMODE, "testmode cmd recover"); | ||
263 | |||
264 | wl12xx_queue_recovery_work(wl); | ||
265 | |||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | static int wl12xx_tm_cmd_get_mac(struct wl1271 *wl, struct nlattr *tb[]) | ||
270 | { | ||
271 | struct sk_buff *skb; | ||
272 | u8 mac_addr[ETH_ALEN]; | ||
273 | int ret = 0; | ||
274 | |||
275 | mutex_lock(&wl->mutex); | ||
276 | |||
277 | if (!wl->plt) { | ||
278 | ret = -EINVAL; | ||
279 | goto out; | ||
280 | } | ||
281 | |||
282 | if (wl->fuse_oui_addr == 0 && wl->fuse_nic_addr == 0) { | ||
283 | ret = -EOPNOTSUPP; | ||
284 | goto out; | ||
285 | } | ||
286 | |||
287 | mac_addr[0] = (u8)(wl->fuse_oui_addr >> 16); | ||
288 | mac_addr[1] = (u8)(wl->fuse_oui_addr >> 8); | ||
289 | mac_addr[2] = (u8) wl->fuse_oui_addr; | ||
290 | mac_addr[3] = (u8)(wl->fuse_nic_addr >> 16); | ||
291 | mac_addr[4] = (u8)(wl->fuse_nic_addr >> 8); | ||
292 | mac_addr[5] = (u8) wl->fuse_nic_addr; | ||
293 | |||
294 | skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, ETH_ALEN); | ||
295 | if (!skb) { | ||
296 | ret = -ENOMEM; | ||
297 | goto out; | ||
298 | } | ||
299 | |||
300 | NLA_PUT(skb, WL1271_TM_ATTR_DATA, ETH_ALEN, mac_addr); | ||
301 | ret = cfg80211_testmode_reply(skb); | ||
302 | if (ret < 0) | ||
303 | goto out; | ||
304 | |||
305 | out: | ||
306 | mutex_unlock(&wl->mutex); | ||
307 | return ret; | ||
308 | |||
309 | nla_put_failure: | ||
310 | kfree_skb(skb); | ||
311 | ret = -EMSGSIZE; | ||
312 | goto out; | ||
313 | } | ||
314 | |||
315 | int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len) | ||
316 | { | ||
317 | struct wl1271 *wl = hw->priv; | ||
318 | struct nlattr *tb[WL1271_TM_ATTR_MAX + 1]; | ||
319 | int err; | ||
320 | |||
321 | err = nla_parse(tb, WL1271_TM_ATTR_MAX, data, len, wl1271_tm_policy); | ||
322 | if (err) | ||
323 | return err; | ||
324 | |||
325 | if (!tb[WL1271_TM_ATTR_CMD_ID]) | ||
326 | return -EINVAL; | ||
327 | |||
328 | switch (nla_get_u32(tb[WL1271_TM_ATTR_CMD_ID])) { | ||
329 | case WL1271_TM_CMD_TEST: | ||
330 | return wl1271_tm_cmd_test(wl, tb); | ||
331 | case WL1271_TM_CMD_INTERROGATE: | ||
332 | return wl1271_tm_cmd_interrogate(wl, tb); | ||
333 | case WL1271_TM_CMD_CONFIGURE: | ||
334 | return wl1271_tm_cmd_configure(wl, tb); | ||
335 | case WL1271_TM_CMD_SET_PLT_MODE: | ||
336 | return wl1271_tm_cmd_set_plt_mode(wl, tb); | ||
337 | case WL1271_TM_CMD_RECOVER: | ||
338 | return wl1271_tm_cmd_recover(wl, tb); | ||
339 | case WL1271_TM_CMD_GET_MAC: | ||
340 | return wl12xx_tm_cmd_get_mac(wl, tb); | ||
341 | default: | ||
342 | return -EOPNOTSUPP; | ||
343 | } | ||
344 | } | ||
diff --git a/drivers/net/wireless/ti/wl12xx/testmode.h b/drivers/net/wireless/ti/wl12xx/testmode.h new file mode 100644 index 000000000000..8071654259ea --- /dev/null +++ b/drivers/net/wireless/ti/wl12xx/testmode.h | |||
@@ -0,0 +1,31 @@ | |||
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 __TESTMODE_H__ | ||
25 | #define __TESTMODE_H__ | ||
26 | |||
27 | #include <net/mac80211.h> | ||
28 | |||
29 | int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len); | ||
30 | |||
31 | #endif /* __WL1271_TESTMODE_H__ */ | ||
diff --git a/drivers/net/wireless/ti/wl12xx/tx.c b/drivers/net/wireless/ti/wl12xx/tx.c new file mode 100644 index 000000000000..43ae49143d68 --- /dev/null +++ b/drivers/net/wireless/ti/wl12xx/tx.c | |||
@@ -0,0 +1,1079 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2009 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 | #include <linux/kernel.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/etherdevice.h> | ||
27 | |||
28 | #include "wl12xx.h" | ||
29 | #include "debug.h" | ||
30 | #include "io.h" | ||
31 | #include "reg.h" | ||
32 | #include "ps.h" | ||
33 | #include "tx.h" | ||
34 | #include "event.h" | ||
35 | |||
36 | static int wl1271_set_default_wep_key(struct wl1271 *wl, | ||
37 | struct wl12xx_vif *wlvif, u8 id) | ||
38 | { | ||
39 | int ret; | ||
40 | bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); | ||
41 | |||
42 | if (is_ap) | ||
43 | ret = wl12xx_cmd_set_default_wep_key(wl, id, | ||
44 | wlvif->ap.bcast_hlid); | ||
45 | else | ||
46 | ret = wl12xx_cmd_set_default_wep_key(wl, id, wlvif->sta.hlid); | ||
47 | |||
48 | if (ret < 0) | ||
49 | return ret; | ||
50 | |||
51 | wl1271_debug(DEBUG_CRYPT, "default wep key idx: %d", (int)id); | ||
52 | return 0; | ||
53 | } | ||
54 | |||
55 | static int wl1271_alloc_tx_id(struct wl1271 *wl, struct sk_buff *skb) | ||
56 | { | ||
57 | int id; | ||
58 | |||
59 | id = find_first_zero_bit(wl->tx_frames_map, ACX_TX_DESCRIPTORS); | ||
60 | if (id >= ACX_TX_DESCRIPTORS) | ||
61 | return -EBUSY; | ||
62 | |||
63 | __set_bit(id, wl->tx_frames_map); | ||
64 | wl->tx_frames[id] = skb; | ||
65 | wl->tx_frames_cnt++; | ||
66 | return id; | ||
67 | } | ||
68 | |||
69 | static void wl1271_free_tx_id(struct wl1271 *wl, int id) | ||
70 | { | ||
71 | if (__test_and_clear_bit(id, wl->tx_frames_map)) { | ||
72 | if (unlikely(wl->tx_frames_cnt == ACX_TX_DESCRIPTORS)) | ||
73 | clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); | ||
74 | |||
75 | wl->tx_frames[id] = NULL; | ||
76 | wl->tx_frames_cnt--; | ||
77 | } | ||
78 | } | ||
79 | |||
80 | static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl, | ||
81 | struct sk_buff *skb) | ||
82 | { | ||
83 | struct ieee80211_hdr *hdr; | ||
84 | |||
85 | /* | ||
86 | * add the station to the known list before transmitting the | ||
87 | * authentication response. this way it won't get de-authed by FW | ||
88 | * when transmitting too soon. | ||
89 | */ | ||
90 | hdr = (struct ieee80211_hdr *)(skb->data + | ||
91 | sizeof(struct wl1271_tx_hw_descr)); | ||
92 | if (ieee80211_is_auth(hdr->frame_control)) | ||
93 | wl1271_acx_set_inconnection_sta(wl, hdr->addr1); | ||
94 | } | ||
95 | |||
96 | static void wl1271_tx_regulate_link(struct wl1271 *wl, | ||
97 | struct wl12xx_vif *wlvif, | ||
98 | u8 hlid) | ||
99 | { | ||
100 | bool fw_ps, single_sta; | ||
101 | u8 tx_pkts; | ||
102 | |||
103 | if (WARN_ON(!test_bit(hlid, wlvif->links_map))) | ||
104 | return; | ||
105 | |||
106 | fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); | ||
107 | tx_pkts = wl->links[hlid].allocated_pkts; | ||
108 | single_sta = (wl->active_sta_count == 1); | ||
109 | |||
110 | /* | ||
111 | * if in FW PS and there is enough data in FW we can put the link | ||
112 | * into high-level PS and clean out its TX queues. | ||
113 | * Make an exception if this is the only connected station. In this | ||
114 | * case FW-memory congestion is not a problem. | ||
115 | */ | ||
116 | if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS) | ||
117 | wl12xx_ps_link_start(wl, wlvif, hlid, true); | ||
118 | } | ||
119 | |||
120 | bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb) | ||
121 | { | ||
122 | return wl->dummy_packet == skb; | ||
123 | } | ||
124 | |||
125 | u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
126 | struct sk_buff *skb) | ||
127 | { | ||
128 | struct ieee80211_tx_info *control = IEEE80211_SKB_CB(skb); | ||
129 | |||
130 | if (control->control.sta) { | ||
131 | struct wl1271_station *wl_sta; | ||
132 | |||
133 | wl_sta = (struct wl1271_station *) | ||
134 | control->control.sta->drv_priv; | ||
135 | return wl_sta->hlid; | ||
136 | } else { | ||
137 | struct ieee80211_hdr *hdr; | ||
138 | |||
139 | if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) | ||
140 | return wl->system_hlid; | ||
141 | |||
142 | hdr = (struct ieee80211_hdr *)skb->data; | ||
143 | if (ieee80211_is_mgmt(hdr->frame_control)) | ||
144 | return wlvif->ap.global_hlid; | ||
145 | else | ||
146 | return wlvif->ap.bcast_hlid; | ||
147 | } | ||
148 | } | ||
149 | |||
150 | u8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
151 | struct sk_buff *skb) | ||
152 | { | ||
153 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||
154 | |||
155 | if (!wlvif || wl12xx_is_dummy_packet(wl, skb)) | ||
156 | return wl->system_hlid; | ||
157 | |||
158 | if (wlvif->bss_type == BSS_TYPE_AP_BSS) | ||
159 | return wl12xx_tx_get_hlid_ap(wl, wlvif, skb); | ||
160 | |||
161 | if ((test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) || | ||
162 | test_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags)) && | ||
163 | !ieee80211_is_auth(hdr->frame_control) && | ||
164 | !ieee80211_is_assoc_req(hdr->frame_control)) | ||
165 | return wlvif->sta.hlid; | ||
166 | else | ||
167 | return wlvif->dev_hlid; | ||
168 | } | ||
169 | |||
170 | static unsigned int wl12xx_calc_packet_alignment(struct wl1271 *wl, | ||
171 | unsigned int packet_length) | ||
172 | { | ||
173 | if (wl->quirks & WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT) | ||
174 | return ALIGN(packet_length, WL1271_TX_ALIGN_TO); | ||
175 | else | ||
176 | return ALIGN(packet_length, WL12XX_BUS_BLOCK_SIZE); | ||
177 | } | ||
178 | |||
179 | static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
180 | struct sk_buff *skb, u32 extra, u32 buf_offset, | ||
181 | u8 hlid) | ||
182 | { | ||
183 | struct wl1271_tx_hw_descr *desc; | ||
184 | u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra; | ||
185 | u32 len; | ||
186 | u32 total_blocks; | ||
187 | int id, ret = -EBUSY, ac; | ||
188 | u32 spare_blocks = wl->tx_spare_blocks; | ||
189 | bool is_dummy = false; | ||
190 | |||
191 | if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE) | ||
192 | return -EAGAIN; | ||
193 | |||
194 | /* allocate free identifier for the packet */ | ||
195 | id = wl1271_alloc_tx_id(wl, skb); | ||
196 | if (id < 0) | ||
197 | return id; | ||
198 | |||
199 | /* approximate the number of blocks required for this packet | ||
200 | in the firmware */ | ||
201 | len = wl12xx_calc_packet_alignment(wl, total_len); | ||
202 | |||
203 | /* in case of a dummy packet, use default amount of spare mem blocks */ | ||
204 | if (unlikely(wl12xx_is_dummy_packet(wl, skb))) { | ||
205 | is_dummy = true; | ||
206 | spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT; | ||
207 | } | ||
208 | |||
209 | total_blocks = (len + TX_HW_BLOCK_SIZE - 1) / TX_HW_BLOCK_SIZE + | ||
210 | spare_blocks; | ||
211 | |||
212 | if (total_blocks <= wl->tx_blocks_available) { | ||
213 | desc = (struct wl1271_tx_hw_descr *)skb_push( | ||
214 | skb, total_len - skb->len); | ||
215 | |||
216 | /* HW descriptor fields change between wl127x and wl128x */ | ||
217 | if (wl->chip.id == CHIP_ID_1283_PG20) { | ||
218 | desc->wl128x_mem.total_mem_blocks = total_blocks; | ||
219 | } else { | ||
220 | desc->wl127x_mem.extra_blocks = spare_blocks; | ||
221 | desc->wl127x_mem.total_mem_blocks = total_blocks; | ||
222 | } | ||
223 | |||
224 | desc->id = id; | ||
225 | |||
226 | wl->tx_blocks_available -= total_blocks; | ||
227 | wl->tx_allocated_blocks += total_blocks; | ||
228 | |||
229 | /* If the FW was empty before, arm the Tx watchdog */ | ||
230 | if (wl->tx_allocated_blocks == total_blocks) | ||
231 | wl12xx_rearm_tx_watchdog_locked(wl); | ||
232 | |||
233 | ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); | ||
234 | wl->tx_allocated_pkts[ac]++; | ||
235 | |||
236 | if (!is_dummy && wlvif && | ||
237 | wlvif->bss_type == BSS_TYPE_AP_BSS && | ||
238 | test_bit(hlid, wlvif->ap.sta_hlid_map)) | ||
239 | wl->links[hlid].allocated_pkts++; | ||
240 | |||
241 | ret = 0; | ||
242 | |||
243 | wl1271_debug(DEBUG_TX, | ||
244 | "tx_allocate: size: %d, blocks: %d, id: %d", | ||
245 | total_len, total_blocks, id); | ||
246 | } else { | ||
247 | wl1271_free_tx_id(wl, id); | ||
248 | } | ||
249 | |||
250 | return ret; | ||
251 | } | ||
252 | |||
253 | static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
254 | struct sk_buff *skb, u32 extra, | ||
255 | struct ieee80211_tx_info *control, u8 hlid) | ||
256 | { | ||
257 | struct timespec ts; | ||
258 | struct wl1271_tx_hw_descr *desc; | ||
259 | int aligned_len, ac, rate_idx; | ||
260 | s64 hosttime; | ||
261 | u16 tx_attr = 0; | ||
262 | __le16 frame_control; | ||
263 | struct ieee80211_hdr *hdr; | ||
264 | u8 *frame_start; | ||
265 | bool is_dummy; | ||
266 | |||
267 | desc = (struct wl1271_tx_hw_descr *) skb->data; | ||
268 | frame_start = (u8 *)(desc + 1); | ||
269 | hdr = (struct ieee80211_hdr *)(frame_start + extra); | ||
270 | frame_control = hdr->frame_control; | ||
271 | |||
272 | /* relocate space for security header */ | ||
273 | if (extra) { | ||
274 | int hdrlen = ieee80211_hdrlen(frame_control); | ||
275 | memmove(frame_start, hdr, hdrlen); | ||
276 | } | ||
277 | |||
278 | /* configure packet life time */ | ||
279 | getnstimeofday(&ts); | ||
280 | hosttime = (timespec_to_ns(&ts) >> 10); | ||
281 | desc->start_time = cpu_to_le32(hosttime - wl->time_offset); | ||
282 | |||
283 | is_dummy = wl12xx_is_dummy_packet(wl, skb); | ||
284 | if (is_dummy || !wlvif || wlvif->bss_type != BSS_TYPE_AP_BSS) | ||
285 | desc->life_time = cpu_to_le16(TX_HW_MGMT_PKT_LIFETIME_TU); | ||
286 | else | ||
287 | desc->life_time = cpu_to_le16(TX_HW_AP_MODE_PKT_LIFETIME_TU); | ||
288 | |||
289 | /* queue */ | ||
290 | ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); | ||
291 | desc->tid = skb->priority; | ||
292 | |||
293 | if (is_dummy) { | ||
294 | /* | ||
295 | * FW expects the dummy packet to have an invalid session id - | ||
296 | * any session id that is different than the one set in the join | ||
297 | */ | ||
298 | tx_attr = (SESSION_COUNTER_INVALID << | ||
299 | TX_HW_ATTR_OFST_SESSION_COUNTER) & | ||
300 | TX_HW_ATTR_SESSION_COUNTER; | ||
301 | |||
302 | tx_attr |= TX_HW_ATTR_TX_DUMMY_REQ; | ||
303 | } else if (wlvif) { | ||
304 | /* configure the tx attributes */ | ||
305 | tx_attr = wlvif->session_counter << | ||
306 | TX_HW_ATTR_OFST_SESSION_COUNTER; | ||
307 | } | ||
308 | |||
309 | desc->hlid = hlid; | ||
310 | if (is_dummy || !wlvif) | ||
311 | rate_idx = 0; | ||
312 | else if (wlvif->bss_type != BSS_TYPE_AP_BSS) { | ||
313 | /* if the packets are destined for AP (have a STA entry) | ||
314 | send them with AP rate policies, otherwise use default | ||
315 | basic rates */ | ||
316 | if (control->flags & IEEE80211_TX_CTL_NO_CCK_RATE) | ||
317 | rate_idx = wlvif->sta.p2p_rate_idx; | ||
318 | else if (control->control.sta) | ||
319 | rate_idx = wlvif->sta.ap_rate_idx; | ||
320 | else | ||
321 | rate_idx = wlvif->sta.basic_rate_idx; | ||
322 | } else { | ||
323 | if (hlid == wlvif->ap.global_hlid) | ||
324 | rate_idx = wlvif->ap.mgmt_rate_idx; | ||
325 | else if (hlid == wlvif->ap.bcast_hlid) | ||
326 | rate_idx = wlvif->ap.bcast_rate_idx; | ||
327 | else | ||
328 | rate_idx = wlvif->ap.ucast_rate_idx[ac]; | ||
329 | } | ||
330 | |||
331 | tx_attr |= rate_idx << TX_HW_ATTR_OFST_RATE_POLICY; | ||
332 | desc->reserved = 0; | ||
333 | |||
334 | aligned_len = wl12xx_calc_packet_alignment(wl, skb->len); | ||
335 | |||
336 | if (wl->chip.id == CHIP_ID_1283_PG20) { | ||
337 | desc->wl128x_mem.extra_bytes = aligned_len - skb->len; | ||
338 | desc->length = cpu_to_le16(aligned_len >> 2); | ||
339 | |||
340 | wl1271_debug(DEBUG_TX, "tx_fill_hdr: hlid: %d " | ||
341 | "tx_attr: 0x%x len: %d life: %d mem: %d", | ||
342 | desc->hlid, tx_attr, | ||
343 | le16_to_cpu(desc->length), | ||
344 | le16_to_cpu(desc->life_time), | ||
345 | desc->wl128x_mem.total_mem_blocks); | ||
346 | } else { | ||
347 | int pad; | ||
348 | |||
349 | /* Store the aligned length in terms of words */ | ||
350 | desc->length = cpu_to_le16(aligned_len >> 2); | ||
351 | |||
352 | /* calculate number of padding bytes */ | ||
353 | pad = aligned_len - skb->len; | ||
354 | tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD; | ||
355 | |||
356 | wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d hlid: %d " | ||
357 | "tx_attr: 0x%x len: %d life: %d mem: %d", pad, | ||
358 | desc->hlid, tx_attr, | ||
359 | le16_to_cpu(desc->length), | ||
360 | le16_to_cpu(desc->life_time), | ||
361 | desc->wl127x_mem.total_mem_blocks); | ||
362 | } | ||
363 | |||
364 | /* for WEP shared auth - no fw encryption is needed */ | ||
365 | if (ieee80211_is_auth(frame_control) && | ||
366 | ieee80211_has_protected(frame_control)) | ||
367 | tx_attr |= TX_HW_ATTR_HOST_ENCRYPT; | ||
368 | |||
369 | desc->tx_attr = cpu_to_le16(tx_attr); | ||
370 | } | ||
371 | |||
372 | /* caller must hold wl->mutex */ | ||
373 | static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
374 | struct sk_buff *skb, u32 buf_offset) | ||
375 | { | ||
376 | struct ieee80211_tx_info *info; | ||
377 | u32 extra = 0; | ||
378 | int ret = 0; | ||
379 | u32 total_len; | ||
380 | u8 hlid; | ||
381 | bool is_dummy; | ||
382 | |||
383 | if (!skb) | ||
384 | return -EINVAL; | ||
385 | |||
386 | info = IEEE80211_SKB_CB(skb); | ||
387 | |||
388 | /* TODO: handle dummy packets on multi-vifs */ | ||
389 | is_dummy = wl12xx_is_dummy_packet(wl, skb); | ||
390 | |||
391 | if (info->control.hw_key && | ||
392 | info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) | ||
393 | extra = WL1271_EXTRA_SPACE_TKIP; | ||
394 | |||
395 | if (info->control.hw_key) { | ||
396 | bool is_wep; | ||
397 | u8 idx = info->control.hw_key->hw_key_idx; | ||
398 | u32 cipher = info->control.hw_key->cipher; | ||
399 | |||
400 | is_wep = (cipher == WLAN_CIPHER_SUITE_WEP40) || | ||
401 | (cipher == WLAN_CIPHER_SUITE_WEP104); | ||
402 | |||
403 | if (unlikely(is_wep && wlvif->default_key != idx)) { | ||
404 | ret = wl1271_set_default_wep_key(wl, wlvif, idx); | ||
405 | if (ret < 0) | ||
406 | return ret; | ||
407 | wlvif->default_key = idx; | ||
408 | } | ||
409 | } | ||
410 | hlid = wl12xx_tx_get_hlid(wl, wlvif, skb); | ||
411 | if (hlid == WL12XX_INVALID_LINK_ID) { | ||
412 | wl1271_error("invalid hlid. dropping skb 0x%p", skb); | ||
413 | return -EINVAL; | ||
414 | } | ||
415 | |||
416 | ret = wl1271_tx_allocate(wl, wlvif, skb, extra, buf_offset, hlid); | ||
417 | if (ret < 0) | ||
418 | return ret; | ||
419 | |||
420 | wl1271_tx_fill_hdr(wl, wlvif, skb, extra, info, hlid); | ||
421 | |||
422 | if (!is_dummy && wlvif && wlvif->bss_type == BSS_TYPE_AP_BSS) { | ||
423 | wl1271_tx_ap_update_inconnection_sta(wl, skb); | ||
424 | wl1271_tx_regulate_link(wl, wlvif, hlid); | ||
425 | } | ||
426 | |||
427 | /* | ||
428 | * The length of each packet is stored in terms of | ||
429 | * words. Thus, we must pad the skb data to make sure its | ||
430 | * length is aligned. The number of padding bytes is computed | ||
431 | * and set in wl1271_tx_fill_hdr. | ||
432 | * In special cases, we want to align to a specific block size | ||
433 | * (eg. for wl128x with SDIO we align to 256). | ||
434 | */ | ||
435 | total_len = wl12xx_calc_packet_alignment(wl, skb->len); | ||
436 | |||
437 | memcpy(wl->aggr_buf + buf_offset, skb->data, skb->len); | ||
438 | memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len); | ||
439 | |||
440 | /* Revert side effects in the dummy packet skb, so it can be reused */ | ||
441 | if (is_dummy) | ||
442 | skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); | ||
443 | |||
444 | return total_len; | ||
445 | } | ||
446 | |||
447 | u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set, | ||
448 | enum ieee80211_band rate_band) | ||
449 | { | ||
450 | struct ieee80211_supported_band *band; | ||
451 | u32 enabled_rates = 0; | ||
452 | int bit; | ||
453 | |||
454 | band = wl->hw->wiphy->bands[rate_band]; | ||
455 | for (bit = 0; bit < band->n_bitrates; bit++) { | ||
456 | if (rate_set & 0x1) | ||
457 | enabled_rates |= band->bitrates[bit].hw_value; | ||
458 | rate_set >>= 1; | ||
459 | } | ||
460 | |||
461 | /* MCS rates indication are on bits 16 - 23 */ | ||
462 | rate_set >>= HW_HT_RATES_OFFSET - band->n_bitrates; | ||
463 | |||
464 | for (bit = 0; bit < 8; bit++) { | ||
465 | if (rate_set & 0x1) | ||
466 | enabled_rates |= (CONF_HW_BIT_RATE_MCS_0 << bit); | ||
467 | rate_set >>= 1; | ||
468 | } | ||
469 | |||
470 | return enabled_rates; | ||
471 | } | ||
472 | |||
473 | void wl1271_handle_tx_low_watermark(struct wl1271 *wl) | ||
474 | { | ||
475 | unsigned long flags; | ||
476 | int i; | ||
477 | |||
478 | for (i = 0; i < NUM_TX_QUEUES; i++) { | ||
479 | if (test_bit(i, &wl->stopped_queues_map) && | ||
480 | wl->tx_queue_count[i] <= WL1271_TX_QUEUE_LOW_WATERMARK) { | ||
481 | /* firmware buffer has space, restart queues */ | ||
482 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
483 | ieee80211_wake_queue(wl->hw, | ||
484 | wl1271_tx_get_mac80211_queue(i)); | ||
485 | clear_bit(i, &wl->stopped_queues_map); | ||
486 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
487 | } | ||
488 | } | ||
489 | } | ||
490 | |||
491 | static struct sk_buff_head *wl1271_select_queue(struct wl1271 *wl, | ||
492 | struct sk_buff_head *queues) | ||
493 | { | ||
494 | int i, q = -1, ac; | ||
495 | u32 min_pkts = 0xffffffff; | ||
496 | |||
497 | /* | ||
498 | * Find a non-empty ac where: | ||
499 | * 1. There are packets to transmit | ||
500 | * 2. The FW has the least allocated blocks | ||
501 | * | ||
502 | * We prioritize the ACs according to VO>VI>BE>BK | ||
503 | */ | ||
504 | for (i = 0; i < NUM_TX_QUEUES; i++) { | ||
505 | ac = wl1271_tx_get_queue(i); | ||
506 | if (!skb_queue_empty(&queues[ac]) && | ||
507 | (wl->tx_allocated_pkts[ac] < min_pkts)) { | ||
508 | q = ac; | ||
509 | min_pkts = wl->tx_allocated_pkts[q]; | ||
510 | } | ||
511 | } | ||
512 | |||
513 | if (q == -1) | ||
514 | return NULL; | ||
515 | |||
516 | return &queues[q]; | ||
517 | } | ||
518 | |||
519 | static struct sk_buff *wl12xx_lnk_skb_dequeue(struct wl1271 *wl, | ||
520 | struct wl1271_link *lnk) | ||
521 | { | ||
522 | struct sk_buff *skb; | ||
523 | unsigned long flags; | ||
524 | struct sk_buff_head *queue; | ||
525 | |||
526 | queue = wl1271_select_queue(wl, lnk->tx_queue); | ||
527 | if (!queue) | ||
528 | return NULL; | ||
529 | |||
530 | skb = skb_dequeue(queue); | ||
531 | if (skb) { | ||
532 | int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); | ||
533 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
534 | WARN_ON_ONCE(wl->tx_queue_count[q] <= 0); | ||
535 | wl->tx_queue_count[q]--; | ||
536 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
537 | } | ||
538 | |||
539 | return skb; | ||
540 | } | ||
541 | |||
542 | static struct sk_buff *wl12xx_vif_skb_dequeue(struct wl1271 *wl, | ||
543 | struct wl12xx_vif *wlvif) | ||
544 | { | ||
545 | struct sk_buff *skb = NULL; | ||
546 | int i, h, start_hlid; | ||
547 | |||
548 | /* start from the link after the last one */ | ||
549 | start_hlid = (wlvif->last_tx_hlid + 1) % WL12XX_MAX_LINKS; | ||
550 | |||
551 | /* dequeue according to AC, round robin on each link */ | ||
552 | for (i = 0; i < WL12XX_MAX_LINKS; i++) { | ||
553 | h = (start_hlid + i) % WL12XX_MAX_LINKS; | ||
554 | |||
555 | /* only consider connected stations */ | ||
556 | if (!test_bit(h, wlvif->links_map)) | ||
557 | continue; | ||
558 | |||
559 | skb = wl12xx_lnk_skb_dequeue(wl, &wl->links[h]); | ||
560 | if (!skb) | ||
561 | continue; | ||
562 | |||
563 | wlvif->last_tx_hlid = h; | ||
564 | break; | ||
565 | } | ||
566 | |||
567 | if (!skb) | ||
568 | wlvif->last_tx_hlid = 0; | ||
569 | |||
570 | return skb; | ||
571 | } | ||
572 | |||
573 | static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl) | ||
574 | { | ||
575 | unsigned long flags; | ||
576 | struct wl12xx_vif *wlvif = wl->last_wlvif; | ||
577 | struct sk_buff *skb = NULL; | ||
578 | |||
579 | /* continue from last wlvif (round robin) */ | ||
580 | if (wlvif) { | ||
581 | wl12xx_for_each_wlvif_continue(wl, wlvif) { | ||
582 | skb = wl12xx_vif_skb_dequeue(wl, wlvif); | ||
583 | if (skb) { | ||
584 | wl->last_wlvif = wlvif; | ||
585 | break; | ||
586 | } | ||
587 | } | ||
588 | } | ||
589 | |||
590 | /* dequeue from the system HLID before the restarting wlvif list */ | ||
591 | if (!skb) | ||
592 | skb = wl12xx_lnk_skb_dequeue(wl, &wl->links[wl->system_hlid]); | ||
593 | |||
594 | /* do a new pass over the wlvif list */ | ||
595 | if (!skb) { | ||
596 | wl12xx_for_each_wlvif(wl, wlvif) { | ||
597 | skb = wl12xx_vif_skb_dequeue(wl, wlvif); | ||
598 | if (skb) { | ||
599 | wl->last_wlvif = wlvif; | ||
600 | break; | ||
601 | } | ||
602 | |||
603 | /* | ||
604 | * No need to continue after last_wlvif. The previous | ||
605 | * pass should have found it. | ||
606 | */ | ||
607 | if (wlvif == wl->last_wlvif) | ||
608 | break; | ||
609 | } | ||
610 | } | ||
611 | |||
612 | if (!skb && | ||
613 | test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) { | ||
614 | int q; | ||
615 | |||
616 | skb = wl->dummy_packet; | ||
617 | q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); | ||
618 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
619 | WARN_ON_ONCE(wl->tx_queue_count[q] <= 0); | ||
620 | wl->tx_queue_count[q]--; | ||
621 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
622 | } | ||
623 | |||
624 | return skb; | ||
625 | } | ||
626 | |||
627 | static void wl1271_skb_queue_head(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
628 | struct sk_buff *skb) | ||
629 | { | ||
630 | unsigned long flags; | ||
631 | int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); | ||
632 | |||
633 | if (wl12xx_is_dummy_packet(wl, skb)) { | ||
634 | set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags); | ||
635 | } else { | ||
636 | u8 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb); | ||
637 | skb_queue_head(&wl->links[hlid].tx_queue[q], skb); | ||
638 | |||
639 | /* make sure we dequeue the same packet next time */ | ||
640 | wlvif->last_tx_hlid = (hlid + WL12XX_MAX_LINKS - 1) % | ||
641 | WL12XX_MAX_LINKS; | ||
642 | } | ||
643 | |||
644 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
645 | wl->tx_queue_count[q]++; | ||
646 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
647 | } | ||
648 | |||
649 | static bool wl1271_tx_is_data_present(struct sk_buff *skb) | ||
650 | { | ||
651 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); | ||
652 | |||
653 | return ieee80211_is_data_present(hdr->frame_control); | ||
654 | } | ||
655 | |||
656 | void wl12xx_rearm_rx_streaming(struct wl1271 *wl, unsigned long *active_hlids) | ||
657 | { | ||
658 | struct wl12xx_vif *wlvif; | ||
659 | u32 timeout; | ||
660 | u8 hlid; | ||
661 | |||
662 | if (!wl->conf.rx_streaming.interval) | ||
663 | return; | ||
664 | |||
665 | if (!wl->conf.rx_streaming.always && | ||
666 | !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)) | ||
667 | return; | ||
668 | |||
669 | timeout = wl->conf.rx_streaming.duration; | ||
670 | wl12xx_for_each_wlvif_sta(wl, wlvif) { | ||
671 | bool found = false; | ||
672 | for_each_set_bit(hlid, active_hlids, WL12XX_MAX_LINKS) { | ||
673 | if (test_bit(hlid, wlvif->links_map)) { | ||
674 | found = true; | ||
675 | break; | ||
676 | } | ||
677 | } | ||
678 | |||
679 | if (!found) | ||
680 | continue; | ||
681 | |||
682 | /* enable rx streaming */ | ||
683 | if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags)) | ||
684 | ieee80211_queue_work(wl->hw, | ||
685 | &wlvif->rx_streaming_enable_work); | ||
686 | |||
687 | mod_timer(&wlvif->rx_streaming_timer, | ||
688 | jiffies + msecs_to_jiffies(timeout)); | ||
689 | } | ||
690 | } | ||
691 | |||
692 | void wl1271_tx_work_locked(struct wl1271 *wl) | ||
693 | { | ||
694 | struct wl12xx_vif *wlvif; | ||
695 | struct sk_buff *skb; | ||
696 | struct wl1271_tx_hw_descr *desc; | ||
697 | u32 buf_offset = 0; | ||
698 | bool sent_packets = false; | ||
699 | unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0}; | ||
700 | int ret; | ||
701 | |||
702 | if (unlikely(wl->state == WL1271_STATE_OFF)) | ||
703 | return; | ||
704 | |||
705 | while ((skb = wl1271_skb_dequeue(wl))) { | ||
706 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
707 | bool has_data = false; | ||
708 | |||
709 | wlvif = NULL; | ||
710 | if (!wl12xx_is_dummy_packet(wl, skb) && info->control.vif) | ||
711 | wlvif = wl12xx_vif_to_data(info->control.vif); | ||
712 | |||
713 | has_data = wlvif && wl1271_tx_is_data_present(skb); | ||
714 | ret = wl1271_prepare_tx_frame(wl, wlvif, skb, buf_offset); | ||
715 | if (ret == -EAGAIN) { | ||
716 | /* | ||
717 | * Aggregation buffer is full. | ||
718 | * Flush buffer and try again. | ||
719 | */ | ||
720 | wl1271_skb_queue_head(wl, wlvif, skb); | ||
721 | wl1271_write(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf, | ||
722 | buf_offset, true); | ||
723 | sent_packets = true; | ||
724 | buf_offset = 0; | ||
725 | continue; | ||
726 | } else if (ret == -EBUSY) { | ||
727 | /* | ||
728 | * Firmware buffer is full. | ||
729 | * Queue back last skb, and stop aggregating. | ||
730 | */ | ||
731 | wl1271_skb_queue_head(wl, wlvif, skb); | ||
732 | /* No work left, avoid scheduling redundant tx work */ | ||
733 | set_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); | ||
734 | goto out_ack; | ||
735 | } else if (ret < 0) { | ||
736 | if (wl12xx_is_dummy_packet(wl, skb)) | ||
737 | /* | ||
738 | * fw still expects dummy packet, | ||
739 | * so re-enqueue it | ||
740 | */ | ||
741 | wl1271_skb_queue_head(wl, wlvif, skb); | ||
742 | else | ||
743 | ieee80211_free_txskb(wl->hw, skb); | ||
744 | goto out_ack; | ||
745 | } | ||
746 | buf_offset += ret; | ||
747 | wl->tx_packets_count++; | ||
748 | if (has_data) { | ||
749 | desc = (struct wl1271_tx_hw_descr *) skb->data; | ||
750 | __set_bit(desc->hlid, active_hlids); | ||
751 | } | ||
752 | } | ||
753 | |||
754 | out_ack: | ||
755 | if (buf_offset) { | ||
756 | wl1271_write(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf, | ||
757 | buf_offset, true); | ||
758 | sent_packets = true; | ||
759 | } | ||
760 | if (sent_packets) { | ||
761 | /* | ||
762 | * Interrupt the firmware with the new packets. This is only | ||
763 | * required for older hardware revisions | ||
764 | */ | ||
765 | if (wl->quirks & WL12XX_QUIRK_END_OF_TRANSACTION) | ||
766 | wl1271_write32(wl, WL1271_HOST_WR_ACCESS, | ||
767 | wl->tx_packets_count); | ||
768 | |||
769 | wl1271_handle_tx_low_watermark(wl); | ||
770 | } | ||
771 | wl12xx_rearm_rx_streaming(wl, active_hlids); | ||
772 | } | ||
773 | |||
774 | void wl1271_tx_work(struct work_struct *work) | ||
775 | { | ||
776 | struct wl1271 *wl = container_of(work, struct wl1271, tx_work); | ||
777 | int ret; | ||
778 | |||
779 | mutex_lock(&wl->mutex); | ||
780 | ret = wl1271_ps_elp_wakeup(wl); | ||
781 | if (ret < 0) | ||
782 | goto out; | ||
783 | |||
784 | wl1271_tx_work_locked(wl); | ||
785 | |||
786 | wl1271_ps_elp_sleep(wl); | ||
787 | out: | ||
788 | mutex_unlock(&wl->mutex); | ||
789 | } | ||
790 | |||
791 | static u8 wl1271_tx_get_rate_flags(u8 rate_class_index) | ||
792 | { | ||
793 | u8 flags = 0; | ||
794 | |||
795 | if (rate_class_index >= CONF_HW_RXTX_RATE_MCS_MIN && | ||
796 | rate_class_index <= CONF_HW_RXTX_RATE_MCS_MAX) | ||
797 | flags |= IEEE80211_TX_RC_MCS; | ||
798 | if (rate_class_index == CONF_HW_RXTX_RATE_MCS7_SGI) | ||
799 | flags |= IEEE80211_TX_RC_SHORT_GI; | ||
800 | return flags; | ||
801 | } | ||
802 | |||
803 | static void wl1271_tx_complete_packet(struct wl1271 *wl, | ||
804 | struct wl1271_tx_hw_res_descr *result) | ||
805 | { | ||
806 | struct ieee80211_tx_info *info; | ||
807 | struct ieee80211_vif *vif; | ||
808 | struct wl12xx_vif *wlvif; | ||
809 | struct sk_buff *skb; | ||
810 | int id = result->id; | ||
811 | int rate = -1; | ||
812 | u8 rate_flags = 0; | ||
813 | u8 retries = 0; | ||
814 | |||
815 | /* check for id legality */ | ||
816 | if (unlikely(id >= ACX_TX_DESCRIPTORS || wl->tx_frames[id] == NULL)) { | ||
817 | wl1271_warning("TX result illegal id: %d", id); | ||
818 | return; | ||
819 | } | ||
820 | |||
821 | skb = wl->tx_frames[id]; | ||
822 | info = IEEE80211_SKB_CB(skb); | ||
823 | |||
824 | if (wl12xx_is_dummy_packet(wl, skb)) { | ||
825 | wl1271_free_tx_id(wl, id); | ||
826 | return; | ||
827 | } | ||
828 | |||
829 | /* info->control is valid as long as we don't update info->status */ | ||
830 | vif = info->control.vif; | ||
831 | wlvif = wl12xx_vif_to_data(vif); | ||
832 | |||
833 | /* update the TX status info */ | ||
834 | if (result->status == TX_SUCCESS) { | ||
835 | if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) | ||
836 | info->flags |= IEEE80211_TX_STAT_ACK; | ||
837 | rate = wl1271_rate_to_idx(result->rate_class_index, | ||
838 | wlvif->band); | ||
839 | rate_flags = wl1271_tx_get_rate_flags(result->rate_class_index); | ||
840 | retries = result->ack_failures; | ||
841 | } else if (result->status == TX_RETRY_EXCEEDED) { | ||
842 | wl->stats.excessive_retries++; | ||
843 | retries = result->ack_failures; | ||
844 | } | ||
845 | |||
846 | info->status.rates[0].idx = rate; | ||
847 | info->status.rates[0].count = retries; | ||
848 | info->status.rates[0].flags = rate_flags; | ||
849 | info->status.ack_signal = -1; | ||
850 | |||
851 | wl->stats.retry_count += result->ack_failures; | ||
852 | |||
853 | /* | ||
854 | * update sequence number only when relevant, i.e. only in | ||
855 | * sessions of TKIP, AES and GEM (not in open or WEP sessions) | ||
856 | */ | ||
857 | if (info->control.hw_key && | ||
858 | (info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP || | ||
859 | info->control.hw_key->cipher == WLAN_CIPHER_SUITE_CCMP || | ||
860 | info->control.hw_key->cipher == WL1271_CIPHER_SUITE_GEM)) { | ||
861 | u8 fw_lsb = result->tx_security_sequence_number_lsb; | ||
862 | u8 cur_lsb = wlvif->tx_security_last_seq_lsb; | ||
863 | |||
864 | /* | ||
865 | * update security sequence number, taking care of potential | ||
866 | * wrap-around | ||
867 | */ | ||
868 | wlvif->tx_security_seq += (fw_lsb - cur_lsb) & 0xff; | ||
869 | wlvif->tx_security_last_seq_lsb = fw_lsb; | ||
870 | } | ||
871 | |||
872 | /* remove private header from packet */ | ||
873 | skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); | ||
874 | |||
875 | /* remove TKIP header space if present */ | ||
876 | if (info->control.hw_key && | ||
877 | info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) { | ||
878 | int hdrlen = ieee80211_get_hdrlen_from_skb(skb); | ||
879 | memmove(skb->data + WL1271_EXTRA_SPACE_TKIP, skb->data, | ||
880 | hdrlen); | ||
881 | skb_pull(skb, WL1271_EXTRA_SPACE_TKIP); | ||
882 | } | ||
883 | |||
884 | wl1271_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x" | ||
885 | " status 0x%x", | ||
886 | result->id, skb, result->ack_failures, | ||
887 | result->rate_class_index, result->status); | ||
888 | |||
889 | /* return the packet to the stack */ | ||
890 | skb_queue_tail(&wl->deferred_tx_queue, skb); | ||
891 | queue_work(wl->freezable_wq, &wl->netstack_work); | ||
892 | wl1271_free_tx_id(wl, result->id); | ||
893 | } | ||
894 | |||
895 | /* Called upon reception of a TX complete interrupt */ | ||
896 | void wl1271_tx_complete(struct wl1271 *wl) | ||
897 | { | ||
898 | struct wl1271_acx_mem_map *memmap = | ||
899 | (struct wl1271_acx_mem_map *)wl->target_mem_map; | ||
900 | u32 count, fw_counter; | ||
901 | u32 i; | ||
902 | |||
903 | /* read the tx results from the chipset */ | ||
904 | wl1271_read(wl, le32_to_cpu(memmap->tx_result), | ||
905 | wl->tx_res_if, sizeof(*wl->tx_res_if), false); | ||
906 | fw_counter = le32_to_cpu(wl->tx_res_if->tx_result_fw_counter); | ||
907 | |||
908 | /* write host counter to chipset (to ack) */ | ||
909 | wl1271_write32(wl, le32_to_cpu(memmap->tx_result) + | ||
910 | offsetof(struct wl1271_tx_hw_res_if, | ||
911 | tx_result_host_counter), fw_counter); | ||
912 | |||
913 | count = fw_counter - wl->tx_results_count; | ||
914 | wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count); | ||
915 | |||
916 | /* verify that the result buffer is not getting overrun */ | ||
917 | if (unlikely(count > TX_HW_RESULT_QUEUE_LEN)) | ||
918 | wl1271_warning("TX result overflow from chipset: %d", count); | ||
919 | |||
920 | /* process the results */ | ||
921 | for (i = 0; i < count; i++) { | ||
922 | struct wl1271_tx_hw_res_descr *result; | ||
923 | u8 offset = wl->tx_results_count & TX_HW_RESULT_QUEUE_LEN_MASK; | ||
924 | |||
925 | /* process the packet */ | ||
926 | result = &(wl->tx_res_if->tx_results_queue[offset]); | ||
927 | wl1271_tx_complete_packet(wl, result); | ||
928 | |||
929 | wl->tx_results_count++; | ||
930 | } | ||
931 | } | ||
932 | |||
933 | void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid) | ||
934 | { | ||
935 | struct sk_buff *skb; | ||
936 | int i; | ||
937 | unsigned long flags; | ||
938 | struct ieee80211_tx_info *info; | ||
939 | int total[NUM_TX_QUEUES]; | ||
940 | |||
941 | for (i = 0; i < NUM_TX_QUEUES; i++) { | ||
942 | total[i] = 0; | ||
943 | while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) { | ||
944 | wl1271_debug(DEBUG_TX, "link freeing skb 0x%p", skb); | ||
945 | |||
946 | if (!wl12xx_is_dummy_packet(wl, skb)) { | ||
947 | info = IEEE80211_SKB_CB(skb); | ||
948 | info->status.rates[0].idx = -1; | ||
949 | info->status.rates[0].count = 0; | ||
950 | ieee80211_tx_status_ni(wl->hw, skb); | ||
951 | } | ||
952 | |||
953 | total[i]++; | ||
954 | } | ||
955 | } | ||
956 | |||
957 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
958 | for (i = 0; i < NUM_TX_QUEUES; i++) | ||
959 | wl->tx_queue_count[i] -= total[i]; | ||
960 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
961 | |||
962 | wl1271_handle_tx_low_watermark(wl); | ||
963 | } | ||
964 | |||
965 | /* caller must hold wl->mutex and TX must be stopped */ | ||
966 | void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif) | ||
967 | { | ||
968 | int i; | ||
969 | |||
970 | /* TX failure */ | ||
971 | for_each_set_bit(i, wlvif->links_map, WL12XX_MAX_LINKS) { | ||
972 | if (wlvif->bss_type == BSS_TYPE_AP_BSS) | ||
973 | wl1271_free_sta(wl, wlvif, i); | ||
974 | else | ||
975 | wlvif->sta.ba_rx_bitmap = 0; | ||
976 | |||
977 | wl->links[i].allocated_pkts = 0; | ||
978 | wl->links[i].prev_freed_pkts = 0; | ||
979 | } | ||
980 | wlvif->last_tx_hlid = 0; | ||
981 | |||
982 | } | ||
983 | /* caller must hold wl->mutex and TX must be stopped */ | ||
984 | void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues) | ||
985 | { | ||
986 | int i; | ||
987 | struct sk_buff *skb; | ||
988 | struct ieee80211_tx_info *info; | ||
989 | |||
990 | /* only reset the queues if something bad happened */ | ||
991 | if (WARN_ON_ONCE(wl1271_tx_total_queue_count(wl) != 0)) { | ||
992 | for (i = 0; i < WL12XX_MAX_LINKS; i++) | ||
993 | wl1271_tx_reset_link_queues(wl, i); | ||
994 | |||
995 | for (i = 0; i < NUM_TX_QUEUES; i++) | ||
996 | wl->tx_queue_count[i] = 0; | ||
997 | } | ||
998 | |||
999 | wl->stopped_queues_map = 0; | ||
1000 | |||
1001 | /* | ||
1002 | * Make sure the driver is at a consistent state, in case this | ||
1003 | * function is called from a context other than interface removal. | ||
1004 | * This call will always wake the TX queues. | ||
1005 | */ | ||
1006 | if (reset_tx_queues) | ||
1007 | wl1271_handle_tx_low_watermark(wl); | ||
1008 | |||
1009 | for (i = 0; i < ACX_TX_DESCRIPTORS; i++) { | ||
1010 | if (wl->tx_frames[i] == NULL) | ||
1011 | continue; | ||
1012 | |||
1013 | skb = wl->tx_frames[i]; | ||
1014 | wl1271_free_tx_id(wl, i); | ||
1015 | wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb); | ||
1016 | |||
1017 | if (!wl12xx_is_dummy_packet(wl, skb)) { | ||
1018 | /* | ||
1019 | * Remove private headers before passing the skb to | ||
1020 | * mac80211 | ||
1021 | */ | ||
1022 | info = IEEE80211_SKB_CB(skb); | ||
1023 | skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); | ||
1024 | if (info->control.hw_key && | ||
1025 | info->control.hw_key->cipher == | ||
1026 | WLAN_CIPHER_SUITE_TKIP) { | ||
1027 | int hdrlen = ieee80211_get_hdrlen_from_skb(skb); | ||
1028 | memmove(skb->data + WL1271_EXTRA_SPACE_TKIP, | ||
1029 | skb->data, hdrlen); | ||
1030 | skb_pull(skb, WL1271_EXTRA_SPACE_TKIP); | ||
1031 | } | ||
1032 | |||
1033 | info->status.rates[0].idx = -1; | ||
1034 | info->status.rates[0].count = 0; | ||
1035 | |||
1036 | ieee80211_tx_status_ni(wl->hw, skb); | ||
1037 | } | ||
1038 | } | ||
1039 | } | ||
1040 | |||
1041 | #define WL1271_TX_FLUSH_TIMEOUT 500000 | ||
1042 | |||
1043 | /* caller must *NOT* hold wl->mutex */ | ||
1044 | void wl1271_tx_flush(struct wl1271 *wl) | ||
1045 | { | ||
1046 | unsigned long timeout; | ||
1047 | int i; | ||
1048 | timeout = jiffies + usecs_to_jiffies(WL1271_TX_FLUSH_TIMEOUT); | ||
1049 | |||
1050 | while (!time_after(jiffies, timeout)) { | ||
1051 | mutex_lock(&wl->mutex); | ||
1052 | wl1271_debug(DEBUG_TX, "flushing tx buffer: %d %d", | ||
1053 | wl->tx_frames_cnt, | ||
1054 | wl1271_tx_total_queue_count(wl)); | ||
1055 | if ((wl->tx_frames_cnt == 0) && | ||
1056 | (wl1271_tx_total_queue_count(wl) == 0)) { | ||
1057 | mutex_unlock(&wl->mutex); | ||
1058 | return; | ||
1059 | } | ||
1060 | mutex_unlock(&wl->mutex); | ||
1061 | msleep(1); | ||
1062 | } | ||
1063 | |||
1064 | wl1271_warning("Unable to flush all TX buffers, timed out."); | ||
1065 | |||
1066 | /* forcibly flush all Tx buffers on our queues */ | ||
1067 | mutex_lock(&wl->mutex); | ||
1068 | for (i = 0; i < WL12XX_MAX_LINKS; i++) | ||
1069 | wl1271_tx_reset_link_queues(wl, i); | ||
1070 | mutex_unlock(&wl->mutex); | ||
1071 | } | ||
1072 | |||
1073 | u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set) | ||
1074 | { | ||
1075 | if (WARN_ON(!rate_set)) | ||
1076 | return 0; | ||
1077 | |||
1078 | return BIT(__ffs(rate_set)); | ||
1079 | } | ||
diff --git a/drivers/net/wireless/ti/wl12xx/tx.h b/drivers/net/wireless/ti/wl12xx/tx.h new file mode 100644 index 000000000000..5cf8c32d40d1 --- /dev/null +++ b/drivers/net/wireless/ti/wl12xx/tx.h | |||
@@ -0,0 +1,232 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. | ||
5 | * Copyright (C) 2009 Nokia Corporation | ||
6 | * | ||
7 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef __TX_H__ | ||
26 | #define __TX_H__ | ||
27 | |||
28 | #define TX_HW_BLOCK_SPARE_DEFAULT 1 | ||
29 | #define TX_HW_BLOCK_SIZE 252 | ||
30 | |||
31 | #define TX_HW_MGMT_PKT_LIFETIME_TU 2000 | ||
32 | #define TX_HW_AP_MODE_PKT_LIFETIME_TU 8000 | ||
33 | |||
34 | #define TX_HW_ATTR_SAVE_RETRIES BIT(0) | ||
35 | #define TX_HW_ATTR_HEADER_PAD BIT(1) | ||
36 | #define TX_HW_ATTR_SESSION_COUNTER (BIT(2) | BIT(3) | BIT(4)) | ||
37 | #define TX_HW_ATTR_RATE_POLICY (BIT(5) | BIT(6) | BIT(7) | \ | ||
38 | BIT(8) | BIT(9)) | ||
39 | #define TX_HW_ATTR_LAST_WORD_PAD (BIT(10) | BIT(11)) | ||
40 | #define TX_HW_ATTR_TX_CMPLT_REQ BIT(12) | ||
41 | #define TX_HW_ATTR_TX_DUMMY_REQ BIT(13) | ||
42 | #define TX_HW_ATTR_HOST_ENCRYPT BIT(14) | ||
43 | |||
44 | #define TX_HW_ATTR_OFST_SAVE_RETRIES 0 | ||
45 | #define TX_HW_ATTR_OFST_HEADER_PAD 1 | ||
46 | #define TX_HW_ATTR_OFST_SESSION_COUNTER 2 | ||
47 | #define TX_HW_ATTR_OFST_RATE_POLICY 5 | ||
48 | #define TX_HW_ATTR_OFST_LAST_WORD_PAD 10 | ||
49 | #define TX_HW_ATTR_OFST_TX_CMPLT_REQ 12 | ||
50 | |||
51 | #define TX_HW_RESULT_QUEUE_LEN 16 | ||
52 | #define TX_HW_RESULT_QUEUE_LEN_MASK 0xf | ||
53 | |||
54 | #define WL1271_TX_ALIGN_TO 4 | ||
55 | #define WL1271_EXTRA_SPACE_TKIP 4 | ||
56 | #define WL1271_EXTRA_SPACE_AES 8 | ||
57 | #define WL1271_EXTRA_SPACE_MAX 8 | ||
58 | |||
59 | /* Used for management frames and dummy packets */ | ||
60 | #define WL1271_TID_MGMT 7 | ||
61 | |||
62 | struct wl127x_tx_mem { | ||
63 | /* | ||
64 | * Number of extra memory blocks to allocate for this packet | ||
65 | * in addition to the number of blocks derived from the packet | ||
66 | * length. | ||
67 | */ | ||
68 | u8 extra_blocks; | ||
69 | /* | ||
70 | * Total number of memory blocks allocated by the host for | ||
71 | * this packet. Must be equal or greater than the actual | ||
72 | * blocks number allocated by HW. | ||
73 | */ | ||
74 | u8 total_mem_blocks; | ||
75 | } __packed; | ||
76 | |||
77 | struct wl128x_tx_mem { | ||
78 | /* | ||
79 | * Total number of memory blocks allocated by the host for | ||
80 | * this packet. | ||
81 | */ | ||
82 | u8 total_mem_blocks; | ||
83 | /* | ||
84 | * Number of extra bytes, at the end of the frame. the host | ||
85 | * uses this padding to complete each frame to integer number | ||
86 | * of SDIO blocks. | ||
87 | */ | ||
88 | u8 extra_bytes; | ||
89 | } __packed; | ||
90 | |||
91 | /* | ||
92 | * On wl128x based devices, when TX packets are aggregated, each packet | ||
93 | * size must be aligned to the SDIO block size. The maximum block size | ||
94 | * is bounded by the type of the padded bytes field that is sent to the | ||
95 | * FW. Currently the type is u8, so the maximum block size is 256 bytes. | ||
96 | */ | ||
97 | #define WL12XX_BUS_BLOCK_SIZE min(512u, \ | ||
98 | (1u << (8 * sizeof(((struct wl128x_tx_mem *) 0)->extra_bytes)))) | ||
99 | |||
100 | struct wl1271_tx_hw_descr { | ||
101 | /* Length of packet in words, including descriptor+header+data */ | ||
102 | __le16 length; | ||
103 | union { | ||
104 | struct wl127x_tx_mem wl127x_mem; | ||
105 | struct wl128x_tx_mem wl128x_mem; | ||
106 | } __packed; | ||
107 | /* Device time (in us) when the packet arrived to the driver */ | ||
108 | __le32 start_time; | ||
109 | /* | ||
110 | * Max delay in TUs until transmission. The last device time the | ||
111 | * packet can be transmitted is: start_time + (1024 * life_time) | ||
112 | */ | ||
113 | __le16 life_time; | ||
114 | /* Bitwise fields - see TX_ATTR... definitions above. */ | ||
115 | __le16 tx_attr; | ||
116 | /* Packet identifier used also in the Tx-Result. */ | ||
117 | u8 id; | ||
118 | /* The packet TID value (as User-Priority) */ | ||
119 | u8 tid; | ||
120 | /* host link ID (HLID) */ | ||
121 | u8 hlid; | ||
122 | u8 reserved; | ||
123 | } __packed; | ||
124 | |||
125 | enum wl1271_tx_hw_res_status { | ||
126 | TX_SUCCESS = 0, | ||
127 | TX_HW_ERROR = 1, | ||
128 | TX_DISABLED = 2, | ||
129 | TX_RETRY_EXCEEDED = 3, | ||
130 | TX_TIMEOUT = 4, | ||
131 | TX_KEY_NOT_FOUND = 5, | ||
132 | TX_PEER_NOT_FOUND = 6, | ||
133 | TX_SESSION_MISMATCH = 7, | ||
134 | TX_LINK_NOT_VALID = 8, | ||
135 | }; | ||
136 | |||
137 | struct wl1271_tx_hw_res_descr { | ||
138 | /* Packet Identifier - same value used in the Tx descriptor.*/ | ||
139 | u8 id; | ||
140 | /* The status of the transmission, indicating success or one of | ||
141 | several possible reasons for failure. */ | ||
142 | u8 status; | ||
143 | /* Total air access duration including all retrys and overheads.*/ | ||
144 | __le16 medium_usage; | ||
145 | /* The time passed from host xfer to Tx-complete.*/ | ||
146 | __le32 fw_handling_time; | ||
147 | /* Total media delay | ||
148 | (from 1st EDCA AIFS counter until TX Complete). */ | ||
149 | __le32 medium_delay; | ||
150 | /* LS-byte of last TKIP seq-num (saved per AC for recovery). */ | ||
151 | u8 tx_security_sequence_number_lsb; | ||
152 | /* Retry count - number of transmissions without successful ACK.*/ | ||
153 | u8 ack_failures; | ||
154 | /* The rate that succeeded getting ACK | ||
155 | (Valid only if status=SUCCESS). */ | ||
156 | u8 rate_class_index; | ||
157 | /* for 4-byte alignment. */ | ||
158 | u8 spare; | ||
159 | } __packed; | ||
160 | |||
161 | struct wl1271_tx_hw_res_if { | ||
162 | __le32 tx_result_fw_counter; | ||
163 | __le32 tx_result_host_counter; | ||
164 | struct wl1271_tx_hw_res_descr tx_results_queue[TX_HW_RESULT_QUEUE_LEN]; | ||
165 | } __packed; | ||
166 | |||
167 | static inline int wl1271_tx_get_queue(int queue) | ||
168 | { | ||
169 | switch (queue) { | ||
170 | case 0: | ||
171 | return CONF_TX_AC_VO; | ||
172 | case 1: | ||
173 | return CONF_TX_AC_VI; | ||
174 | case 2: | ||
175 | return CONF_TX_AC_BE; | ||
176 | case 3: | ||
177 | return CONF_TX_AC_BK; | ||
178 | default: | ||
179 | return CONF_TX_AC_BE; | ||
180 | } | ||
181 | } | ||
182 | |||
183 | static inline int wl1271_tx_get_mac80211_queue(int queue) | ||
184 | { | ||
185 | switch (queue) { | ||
186 | case CONF_TX_AC_VO: | ||
187 | return 0; | ||
188 | case CONF_TX_AC_VI: | ||
189 | return 1; | ||
190 | case CONF_TX_AC_BE: | ||
191 | return 2; | ||
192 | case CONF_TX_AC_BK: | ||
193 | return 3; | ||
194 | default: | ||
195 | return 2; | ||
196 | } | ||
197 | } | ||
198 | |||
199 | static inline int wl1271_tx_total_queue_count(struct wl1271 *wl) | ||
200 | { | ||
201 | int i, count = 0; | ||
202 | |||
203 | for (i = 0; i < NUM_TX_QUEUES; i++) | ||
204 | count += wl->tx_queue_count[i]; | ||
205 | |||
206 | return count; | ||
207 | } | ||
208 | |||
209 | void wl1271_tx_work(struct work_struct *work); | ||
210 | void wl1271_tx_work_locked(struct wl1271 *wl); | ||
211 | void wl1271_tx_complete(struct wl1271 *wl); | ||
212 | void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif); | ||
213 | void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues); | ||
214 | void wl1271_tx_flush(struct wl1271 *wl); | ||
215 | u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band); | ||
216 | u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set, | ||
217 | enum ieee80211_band rate_band); | ||
218 | u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set); | ||
219 | u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
220 | struct sk_buff *skb); | ||
221 | u8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif, | ||
222 | struct sk_buff *skb); | ||
223 | void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid); | ||
224 | void wl1271_handle_tx_low_watermark(struct wl1271 *wl); | ||
225 | bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb); | ||
226 | void wl12xx_rearm_rx_streaming(struct wl1271 *wl, unsigned long *active_hlids); | ||
227 | |||
228 | /* from main.c */ | ||
229 | void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid); | ||
230 | void wl12xx_rearm_tx_watchdog_locked(struct wl1271 *wl); | ||
231 | |||
232 | #endif | ||
diff --git a/drivers/net/wireless/ti/wl12xx/wl12xx.h b/drivers/net/wireless/ti/wl12xx/wl12xx.h new file mode 100644 index 000000000000..82802d1c0782 --- /dev/null +++ b/drivers/net/wireless/ti/wl12xx/wl12xx.h | |||
@@ -0,0 +1,698 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. | ||
5 | * Copyright (C) 2008-2009 Nokia Corporation | ||
6 | * | ||
7 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef __WL12XX_H__ | ||
26 | #define __WL12XX_H__ | ||
27 | |||
28 | #include <linux/mutex.h> | ||
29 | #include <linux/completion.h> | ||
30 | #include <linux/spinlock.h> | ||
31 | #include <linux/list.h> | ||
32 | #include <linux/bitops.h> | ||
33 | #include <net/mac80211.h> | ||
34 | |||
35 | #include "conf.h" | ||
36 | #include "ini.h" | ||
37 | #include "event.h" | ||
38 | |||
39 | #define WL127X_FW_NAME_MULTI "ti-connectivity/wl127x-fw-4-mr.bin" | ||
40 | #define WL127X_FW_NAME_SINGLE "ti-connectivity/wl127x-fw-4-sr.bin" | ||
41 | |||
42 | #define WL128X_FW_NAME_MULTI "ti-connectivity/wl128x-fw-4-mr.bin" | ||
43 | #define WL128X_FW_NAME_SINGLE "ti-connectivity/wl128x-fw-4-sr.bin" | ||
44 | |||
45 | #define WL127X_PLT_FW_NAME "ti-connectivity/wl127x-fw-4-plt.bin" | ||
46 | #define WL128X_PLT_FW_NAME "ti-connectivity/wl128x-fw-4-plt.bin" | ||
47 | |||
48 | /* | ||
49 | * wl127x and wl128x are using the same NVS file name. However, the | ||
50 | * ini parameters between them are different. The driver validates | ||
51 | * the correct NVS size in wl1271_boot_upload_nvs(). | ||
52 | */ | ||
53 | #define WL12XX_NVS_NAME "ti-connectivity/wl1271-nvs.bin" | ||
54 | |||
55 | #define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff)) | ||
56 | #define WL1271_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff)) | ||
57 | #define WL1271_TX_SQN_POST_RECOVERY_PADDING 0xff | ||
58 | |||
59 | #define WL1271_CIPHER_SUITE_GEM 0x00147201 | ||
60 | |||
61 | #define WL1271_BUSY_WORD_CNT 1 | ||
62 | #define WL1271_BUSY_WORD_LEN (WL1271_BUSY_WORD_CNT * sizeof(u32)) | ||
63 | |||
64 | #define WL1271_ELP_HW_STATE_ASLEEP 0 | ||
65 | #define WL1271_ELP_HW_STATE_IRQ 1 | ||
66 | |||
67 | #define WL1271_DEFAULT_BEACON_INT 100 | ||
68 | #define WL1271_DEFAULT_DTIM_PERIOD 1 | ||
69 | |||
70 | #define WL12XX_MAX_ROLES 4 | ||
71 | #define WL12XX_MAX_LINKS 12 | ||
72 | #define WL12XX_INVALID_ROLE_ID 0xff | ||
73 | #define WL12XX_INVALID_LINK_ID 0xff | ||
74 | |||
75 | #define WL12XX_MAX_RATE_POLICIES 16 | ||
76 | |||
77 | /* Defined by FW as 0. Will not be freed or allocated. */ | ||
78 | #define WL12XX_SYSTEM_HLID 0 | ||
79 | |||
80 | /* | ||
81 | * When in AP-mode, we allow (at least) this number of packets | ||
82 | * to be transmitted to FW for a STA in PS-mode. Only when packets are | ||
83 | * present in the FW buffers it will wake the sleeping STA. We want to put | ||
84 | * enough packets for the driver to transmit all of its buffered data before | ||
85 | * the STA goes to sleep again. But we don't want to take too much memory | ||
86 | * as it might hurt the throughput of active STAs. | ||
87 | */ | ||
88 | #define WL1271_PS_STA_MAX_PACKETS 2 | ||
89 | |||
90 | #define WL1271_AP_BSS_INDEX 0 | ||
91 | #define WL1271_AP_DEF_BEACON_EXP 20 | ||
92 | |||
93 | #define ACX_TX_DESCRIPTORS 16 | ||
94 | |||
95 | #define WL1271_AGGR_BUFFER_SIZE (4 * PAGE_SIZE) | ||
96 | |||
97 | enum wl1271_state { | ||
98 | WL1271_STATE_OFF, | ||
99 | WL1271_STATE_ON, | ||
100 | }; | ||
101 | |||
102 | enum wl12xx_fw_type { | ||
103 | WL12XX_FW_TYPE_NONE, | ||
104 | WL12XX_FW_TYPE_NORMAL, | ||
105 | WL12XX_FW_TYPE_MULTI, | ||
106 | WL12XX_FW_TYPE_PLT, | ||
107 | }; | ||
108 | |||
109 | enum wl1271_partition_type { | ||
110 | PART_DOWN, | ||
111 | PART_WORK, | ||
112 | PART_DRPW, | ||
113 | |||
114 | PART_TABLE_LEN | ||
115 | }; | ||
116 | |||
117 | struct wl1271_partition { | ||
118 | u32 size; | ||
119 | u32 start; | ||
120 | }; | ||
121 | |||
122 | struct wl1271_partition_set { | ||
123 | struct wl1271_partition mem; | ||
124 | struct wl1271_partition reg; | ||
125 | struct wl1271_partition mem2; | ||
126 | struct wl1271_partition mem3; | ||
127 | }; | ||
128 | |||
129 | struct wl1271; | ||
130 | |||
131 | enum { | ||
132 | FW_VER_CHIP, | ||
133 | FW_VER_IF_TYPE, | ||
134 | FW_VER_MAJOR, | ||
135 | FW_VER_SUBTYPE, | ||
136 | FW_VER_MINOR, | ||
137 | |||
138 | NUM_FW_VER | ||
139 | }; | ||
140 | |||
141 | #define FW_VER_CHIP_WL127X 6 | ||
142 | #define FW_VER_CHIP_WL128X 7 | ||
143 | |||
144 | #define FW_VER_IF_TYPE_STA 1 | ||
145 | #define FW_VER_IF_TYPE_AP 2 | ||
146 | |||
147 | #define FW_VER_MINOR_1_SPARE_STA_MIN 58 | ||
148 | #define FW_VER_MINOR_1_SPARE_AP_MIN 47 | ||
149 | |||
150 | #define FW_VER_MINOR_FWLOG_STA_MIN 70 | ||
151 | |||
152 | struct wl1271_chip { | ||
153 | u32 id; | ||
154 | char fw_ver_str[ETHTOOL_BUSINFO_LEN]; | ||
155 | unsigned int fw_ver[NUM_FW_VER]; | ||
156 | }; | ||
157 | |||
158 | struct wl1271_stats { | ||
159 | struct acx_statistics *fw_stats; | ||
160 | unsigned long fw_stats_update; | ||
161 | |||
162 | unsigned int retry_count; | ||
163 | unsigned int excessive_retries; | ||
164 | }; | ||
165 | |||
166 | #define NUM_TX_QUEUES 4 | ||
167 | #define NUM_RX_PKT_DESC 8 | ||
168 | |||
169 | #define AP_MAX_STATIONS 8 | ||
170 | |||
171 | /* FW status registers */ | ||
172 | struct wl12xx_fw_status { | ||
173 | __le32 intr; | ||
174 | u8 fw_rx_counter; | ||
175 | u8 drv_rx_counter; | ||
176 | u8 reserved; | ||
177 | u8 tx_results_counter; | ||
178 | __le32 rx_pkt_descs[NUM_RX_PKT_DESC]; | ||
179 | __le32 fw_localtime; | ||
180 | |||
181 | /* | ||
182 | * A bitmap (where each bit represents a single HLID) | ||
183 | * to indicate if the station is in PS mode. | ||
184 | */ | ||
185 | __le32 link_ps_bitmap; | ||
186 | |||
187 | /* | ||
188 | * A bitmap (where each bit represents a single HLID) to indicate | ||
189 | * if the station is in Fast mode | ||
190 | */ | ||
191 | __le32 link_fast_bitmap; | ||
192 | |||
193 | /* Cumulative counter of total released mem blocks since FW-reset */ | ||
194 | __le32 total_released_blks; | ||
195 | |||
196 | /* Size (in Memory Blocks) of TX pool */ | ||
197 | __le32 tx_total; | ||
198 | |||
199 | /* Cumulative counter of released packets per AC */ | ||
200 | u8 tx_released_pkts[NUM_TX_QUEUES]; | ||
201 | |||
202 | /* Cumulative counter of freed packets per HLID */ | ||
203 | u8 tx_lnk_free_pkts[WL12XX_MAX_LINKS]; | ||
204 | |||
205 | /* Cumulative counter of released Voice memory blocks */ | ||
206 | u8 tx_voice_released_blks; | ||
207 | u8 padding_1[3]; | ||
208 | __le32 log_start_addr; | ||
209 | } __packed; | ||
210 | |||
211 | struct wl1271_rx_mem_pool_addr { | ||
212 | u32 addr; | ||
213 | u32 addr_extra; | ||
214 | }; | ||
215 | |||
216 | #define WL1271_MAX_CHANNELS 64 | ||
217 | struct wl1271_scan { | ||
218 | struct cfg80211_scan_request *req; | ||
219 | unsigned long scanned_ch[BITS_TO_LONGS(WL1271_MAX_CHANNELS)]; | ||
220 | bool failed; | ||
221 | u8 state; | ||
222 | u8 ssid[IEEE80211_MAX_SSID_LEN+1]; | ||
223 | size_t ssid_len; | ||
224 | }; | ||
225 | |||
226 | struct wl1271_if_operations { | ||
227 | void (*read)(struct device *child, int addr, void *buf, size_t len, | ||
228 | bool fixed); | ||
229 | void (*write)(struct device *child, int addr, void *buf, size_t len, | ||
230 | bool fixed); | ||
231 | void (*reset)(struct device *child); | ||
232 | void (*init)(struct device *child); | ||
233 | int (*power)(struct device *child, bool enable); | ||
234 | void (*set_block_size) (struct device *child, unsigned int blksz); | ||
235 | }; | ||
236 | |||
237 | #define MAX_NUM_KEYS 14 | ||
238 | #define MAX_KEY_SIZE 32 | ||
239 | |||
240 | struct wl1271_ap_key { | ||
241 | u8 id; | ||
242 | u8 key_type; | ||
243 | u8 key_size; | ||
244 | u8 key[MAX_KEY_SIZE]; | ||
245 | u8 hlid; | ||
246 | u32 tx_seq_32; | ||
247 | u16 tx_seq_16; | ||
248 | }; | ||
249 | |||
250 | enum wl12xx_flags { | ||
251 | WL1271_FLAG_GPIO_POWER, | ||
252 | WL1271_FLAG_TX_QUEUE_STOPPED, | ||
253 | WL1271_FLAG_TX_PENDING, | ||
254 | WL1271_FLAG_IN_ELP, | ||
255 | WL1271_FLAG_ELP_REQUESTED, | ||
256 | WL1271_FLAG_IRQ_RUNNING, | ||
257 | WL1271_FLAG_FW_TX_BUSY, | ||
258 | WL1271_FLAG_DUMMY_PACKET_PENDING, | ||
259 | WL1271_FLAG_SUSPENDED, | ||
260 | WL1271_FLAG_PENDING_WORK, | ||
261 | WL1271_FLAG_SOFT_GEMINI, | ||
262 | WL1271_FLAG_RECOVERY_IN_PROGRESS, | ||
263 | WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, | ||
264 | WL1271_FLAG_INTENDED_FW_RECOVERY, | ||
265 | }; | ||
266 | |||
267 | enum wl12xx_vif_flags { | ||
268 | WLVIF_FLAG_INITIALIZED, | ||
269 | WLVIF_FLAG_STA_ASSOCIATED, | ||
270 | WLVIF_FLAG_STA_AUTHORIZED, | ||
271 | WLVIF_FLAG_IBSS_JOINED, | ||
272 | WLVIF_FLAG_AP_STARTED, | ||
273 | WLVIF_FLAG_IN_PS, | ||
274 | WLVIF_FLAG_STA_STATE_SENT, | ||
275 | WLVIF_FLAG_RX_STREAMING_STARTED, | ||
276 | WLVIF_FLAG_PSPOLL_FAILURE, | ||
277 | WLVIF_FLAG_CS_PROGRESS, | ||
278 | WLVIF_FLAG_AP_PROBE_RESP_SET, | ||
279 | WLVIF_FLAG_IN_USE, | ||
280 | }; | ||
281 | |||
282 | struct wl1271_link { | ||
283 | /* AP-mode - TX queue per AC in link */ | ||
284 | struct sk_buff_head tx_queue[NUM_TX_QUEUES]; | ||
285 | |||
286 | /* accounting for allocated / freed packets in FW */ | ||
287 | u8 allocated_pkts; | ||
288 | u8 prev_freed_pkts; | ||
289 | |||
290 | u8 addr[ETH_ALEN]; | ||
291 | |||
292 | /* bitmap of TIDs where RX BA sessions are active for this link */ | ||
293 | u8 ba_bitmap; | ||
294 | }; | ||
295 | |||
296 | struct wl1271 { | ||
297 | struct ieee80211_hw *hw; | ||
298 | bool mac80211_registered; | ||
299 | |||
300 | struct device *dev; | ||
301 | |||
302 | void *if_priv; | ||
303 | |||
304 | struct wl1271_if_operations *if_ops; | ||
305 | |||
306 | void (*set_power)(bool enable); | ||
307 | int irq; | ||
308 | int ref_clock; | ||
309 | |||
310 | spinlock_t wl_lock; | ||
311 | |||
312 | enum wl1271_state state; | ||
313 | enum wl12xx_fw_type fw_type; | ||
314 | bool plt; | ||
315 | u8 last_vif_count; | ||
316 | struct mutex mutex; | ||
317 | |||
318 | unsigned long flags; | ||
319 | |||
320 | struct wl1271_partition_set part; | ||
321 | |||
322 | struct wl1271_chip chip; | ||
323 | |||
324 | int cmd_box_addr; | ||
325 | int event_box_addr; | ||
326 | |||
327 | u8 *fw; | ||
328 | size_t fw_len; | ||
329 | void *nvs; | ||
330 | size_t nvs_len; | ||
331 | |||
332 | s8 hw_pg_ver; | ||
333 | |||
334 | /* address read from the fuse ROM */ | ||
335 | u32 fuse_oui_addr; | ||
336 | u32 fuse_nic_addr; | ||
337 | |||
338 | /* we have up to 2 MAC addresses */ | ||
339 | struct mac_address addresses[2]; | ||
340 | int channel; | ||
341 | u8 system_hlid; | ||
342 | |||
343 | unsigned long links_map[BITS_TO_LONGS(WL12XX_MAX_LINKS)]; | ||
344 | unsigned long roles_map[BITS_TO_LONGS(WL12XX_MAX_ROLES)]; | ||
345 | unsigned long roc_map[BITS_TO_LONGS(WL12XX_MAX_ROLES)]; | ||
346 | unsigned long rate_policies_map[ | ||
347 | BITS_TO_LONGS(WL12XX_MAX_RATE_POLICIES)]; | ||
348 | |||
349 | struct list_head wlvif_list; | ||
350 | |||
351 | u8 sta_count; | ||
352 | u8 ap_count; | ||
353 | |||
354 | struct wl1271_acx_mem_map *target_mem_map; | ||
355 | |||
356 | /* Accounting for allocated / available TX blocks on HW */ | ||
357 | u32 tx_blocks_freed; | ||
358 | u32 tx_blocks_available; | ||
359 | u32 tx_allocated_blocks; | ||
360 | u32 tx_results_count; | ||
361 | |||
362 | /* amount of spare TX blocks to use */ | ||
363 | u32 tx_spare_blocks; | ||
364 | |||
365 | /* Accounting for allocated / available Tx packets in HW */ | ||
366 | u32 tx_pkts_freed[NUM_TX_QUEUES]; | ||
367 | u32 tx_allocated_pkts[NUM_TX_QUEUES]; | ||
368 | |||
369 | /* Transmitted TX packets counter for chipset interface */ | ||
370 | u32 tx_packets_count; | ||
371 | |||
372 | /* Time-offset between host and chipset clocks */ | ||
373 | s64 time_offset; | ||
374 | |||
375 | /* Frames scheduled for transmission, not handled yet */ | ||
376 | int tx_queue_count[NUM_TX_QUEUES]; | ||
377 | long stopped_queues_map; | ||
378 | |||
379 | /* Frames received, not handled yet by mac80211 */ | ||
380 | struct sk_buff_head deferred_rx_queue; | ||
381 | |||
382 | /* Frames sent, not returned yet to mac80211 */ | ||
383 | struct sk_buff_head deferred_tx_queue; | ||
384 | |||
385 | struct work_struct tx_work; | ||
386 | struct workqueue_struct *freezable_wq; | ||
387 | |||
388 | /* Pending TX frames */ | ||
389 | unsigned long tx_frames_map[BITS_TO_LONGS(ACX_TX_DESCRIPTORS)]; | ||
390 | struct sk_buff *tx_frames[ACX_TX_DESCRIPTORS]; | ||
391 | int tx_frames_cnt; | ||
392 | |||
393 | /* FW Rx counter */ | ||
394 | u32 rx_counter; | ||
395 | |||
396 | /* Rx memory pool address */ | ||
397 | struct wl1271_rx_mem_pool_addr rx_mem_pool_addr; | ||
398 | |||
399 | /* Intermediate buffer, used for packet aggregation */ | ||
400 | u8 *aggr_buf; | ||
401 | |||
402 | /* Reusable dummy packet template */ | ||
403 | struct sk_buff *dummy_packet; | ||
404 | |||
405 | /* Network stack work */ | ||
406 | struct work_struct netstack_work; | ||
407 | |||
408 | /* FW log buffer */ | ||
409 | u8 *fwlog; | ||
410 | |||
411 | /* Number of valid bytes in the FW log buffer */ | ||
412 | ssize_t fwlog_size; | ||
413 | |||
414 | /* Sysfs FW log entry readers wait queue */ | ||
415 | wait_queue_head_t fwlog_waitq; | ||
416 | |||
417 | /* Hardware recovery work */ | ||
418 | struct work_struct recovery_work; | ||
419 | |||
420 | struct event_mailbox *mbox; | ||
421 | |||
422 | /* The mbox event mask */ | ||
423 | u32 event_mask; | ||
424 | |||
425 | /* Mailbox pointers */ | ||
426 | u32 mbox_ptr[2]; | ||
427 | |||
428 | /* Are we currently scanning */ | ||
429 | struct ieee80211_vif *scan_vif; | ||
430 | struct wl1271_scan scan; | ||
431 | struct delayed_work scan_complete_work; | ||
432 | |||
433 | bool sched_scanning; | ||
434 | |||
435 | /* The current band */ | ||
436 | enum ieee80211_band band; | ||
437 | |||
438 | struct completion *elp_compl; | ||
439 | struct delayed_work elp_work; | ||
440 | |||
441 | /* in dBm */ | ||
442 | int power_level; | ||
443 | |||
444 | struct wl1271_stats stats; | ||
445 | |||
446 | __le32 buffer_32; | ||
447 | u32 buffer_cmd; | ||
448 | u32 buffer_busyword[WL1271_BUSY_WORD_CNT]; | ||
449 | |||
450 | struct wl12xx_fw_status *fw_status; | ||
451 | struct wl1271_tx_hw_res_if *tx_res_if; | ||
452 | |||
453 | /* Current chipset configuration */ | ||
454 | struct conf_drv_settings conf; | ||
455 | |||
456 | bool sg_enabled; | ||
457 | |||
458 | bool enable_11a; | ||
459 | |||
460 | /* Most recently reported noise in dBm */ | ||
461 | s8 noise; | ||
462 | |||
463 | /* bands supported by this instance of wl12xx */ | ||
464 | struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS]; | ||
465 | |||
466 | int tcxo_clock; | ||
467 | |||
468 | /* | ||
469 | * wowlan trigger was configured during suspend. | ||
470 | * (currently, only "ANY" trigger is supported) | ||
471 | */ | ||
472 | bool wow_enabled; | ||
473 | bool irq_wake_enabled; | ||
474 | |||
475 | /* | ||
476 | * AP-mode - links indexed by HLID. The global and broadcast links | ||
477 | * are always active. | ||
478 | */ | ||
479 | struct wl1271_link links[WL12XX_MAX_LINKS]; | ||
480 | |||
481 | /* AP-mode - a bitmap of links currently in PS mode according to FW */ | ||
482 | u32 ap_fw_ps_map; | ||
483 | |||
484 | /* AP-mode - a bitmap of links currently in PS mode in mac80211 */ | ||
485 | unsigned long ap_ps_map; | ||
486 | |||
487 | /* Quirks of specific hardware revisions */ | ||
488 | unsigned int quirks; | ||
489 | |||
490 | /* Platform limitations */ | ||
491 | unsigned int platform_quirks; | ||
492 | |||
493 | /* number of currently active RX BA sessions */ | ||
494 | int ba_rx_session_count; | ||
495 | |||
496 | /* AP-mode - number of currently connected stations */ | ||
497 | int active_sta_count; | ||
498 | |||
499 | /* last wlvif we transmitted from */ | ||
500 | struct wl12xx_vif *last_wlvif; | ||
501 | |||
502 | /* work to fire when Tx is stuck */ | ||
503 | struct delayed_work tx_watchdog_work; | ||
504 | }; | ||
505 | |||
506 | struct wl1271_station { | ||
507 | u8 hlid; | ||
508 | }; | ||
509 | |||
510 | struct wl12xx_vif { | ||
511 | struct wl1271 *wl; | ||
512 | struct list_head list; | ||
513 | unsigned long flags; | ||
514 | u8 bss_type; | ||
515 | u8 p2p; /* we are using p2p role */ | ||
516 | u8 role_id; | ||
517 | |||
518 | /* sta/ibss specific */ | ||
519 | u8 dev_role_id; | ||
520 | u8 dev_hlid; | ||
521 | |||
522 | union { | ||
523 | struct { | ||
524 | u8 hlid; | ||
525 | u8 ba_rx_bitmap; | ||
526 | |||
527 | u8 basic_rate_idx; | ||
528 | u8 ap_rate_idx; | ||
529 | u8 p2p_rate_idx; | ||
530 | |||
531 | bool qos; | ||
532 | } sta; | ||
533 | struct { | ||
534 | u8 global_hlid; | ||
535 | u8 bcast_hlid; | ||
536 | |||
537 | /* HLIDs bitmap of associated stations */ | ||
538 | unsigned long sta_hlid_map[BITS_TO_LONGS( | ||
539 | WL12XX_MAX_LINKS)]; | ||
540 | |||
541 | /* recoreded keys - set here before AP startup */ | ||
542 | struct wl1271_ap_key *recorded_keys[MAX_NUM_KEYS]; | ||
543 | |||
544 | u8 mgmt_rate_idx; | ||
545 | u8 bcast_rate_idx; | ||
546 | u8 ucast_rate_idx[CONF_TX_MAX_AC_COUNT]; | ||
547 | } ap; | ||
548 | }; | ||
549 | |||
550 | /* the hlid of the last transmitted skb */ | ||
551 | int last_tx_hlid; | ||
552 | |||
553 | unsigned long links_map[BITS_TO_LONGS(WL12XX_MAX_LINKS)]; | ||
554 | |||
555 | u8 ssid[IEEE80211_MAX_SSID_LEN + 1]; | ||
556 | u8 ssid_len; | ||
557 | |||
558 | /* The current band */ | ||
559 | enum ieee80211_band band; | ||
560 | int channel; | ||
561 | |||
562 | u32 bitrate_masks[IEEE80211_NUM_BANDS]; | ||
563 | u32 basic_rate_set; | ||
564 | |||
565 | /* | ||
566 | * currently configured rate set: | ||
567 | * bits 0-15 - 802.11abg rates | ||
568 | * bits 16-23 - 802.11n MCS index mask | ||
569 | * support only 1 stream, thus only 8 bits for the MCS rates (0-7). | ||
570 | */ | ||
571 | u32 basic_rate; | ||
572 | u32 rate_set; | ||
573 | |||
574 | /* probe-req template for the current AP */ | ||
575 | struct sk_buff *probereq; | ||
576 | |||
577 | /* Beaconing interval (needed for ad-hoc) */ | ||
578 | u32 beacon_int; | ||
579 | |||
580 | /* Default key (for WEP) */ | ||
581 | u32 default_key; | ||
582 | |||
583 | /* Our association ID */ | ||
584 | u16 aid; | ||
585 | |||
586 | /* Session counter for the chipset */ | ||
587 | int session_counter; | ||
588 | |||
589 | /* retry counter for PSM entries */ | ||
590 | u8 psm_entry_retry; | ||
591 | |||
592 | /* in dBm */ | ||
593 | int power_level; | ||
594 | |||
595 | int rssi_thold; | ||
596 | int last_rssi_event; | ||
597 | |||
598 | /* save the current encryption type for auto-arp config */ | ||
599 | u8 encryption_type; | ||
600 | __be32 ip_addr; | ||
601 | |||
602 | /* RX BA constraint value */ | ||
603 | bool ba_support; | ||
604 | bool ba_allowed; | ||
605 | |||
606 | /* Rx Streaming */ | ||
607 | struct work_struct rx_streaming_enable_work; | ||
608 | struct work_struct rx_streaming_disable_work; | ||
609 | struct timer_list rx_streaming_timer; | ||
610 | |||
611 | /* | ||
612 | * This struct must be last! | ||
613 | * data that has to be saved acrossed reconfigs (e.g. recovery) | ||
614 | * should be declared in this struct. | ||
615 | */ | ||
616 | struct { | ||
617 | u8 persistent[0]; | ||
618 | /* | ||
619 | * Security sequence number | ||
620 | * bits 0-15: lower 16 bits part of sequence number | ||
621 | * bits 16-47: higher 32 bits part of sequence number | ||
622 | * bits 48-63: not in use | ||
623 | */ | ||
624 | u64 tx_security_seq; | ||
625 | |||
626 | /* 8 bits of the last sequence number in use */ | ||
627 | u8 tx_security_last_seq_lsb; | ||
628 | }; | ||
629 | }; | ||
630 | |||
631 | static inline struct wl12xx_vif *wl12xx_vif_to_data(struct ieee80211_vif *vif) | ||
632 | { | ||
633 | return (struct wl12xx_vif *)vif->drv_priv; | ||
634 | } | ||
635 | |||
636 | static inline | ||
637 | struct ieee80211_vif *wl12xx_wlvif_to_vif(struct wl12xx_vif *wlvif) | ||
638 | { | ||
639 | return container_of((void *)wlvif, struct ieee80211_vif, drv_priv); | ||
640 | } | ||
641 | |||
642 | #define wl12xx_for_each_wlvif(wl, wlvif) \ | ||
643 | list_for_each_entry(wlvif, &wl->wlvif_list, list) | ||
644 | |||
645 | #define wl12xx_for_each_wlvif_continue(wl, wlvif) \ | ||
646 | list_for_each_entry_continue(wlvif, &wl->wlvif_list, list) | ||
647 | |||
648 | #define wl12xx_for_each_wlvif_bss_type(wl, wlvif, _bss_type) \ | ||
649 | wl12xx_for_each_wlvif(wl, wlvif) \ | ||
650 | if (wlvif->bss_type == _bss_type) | ||
651 | |||
652 | #define wl12xx_for_each_wlvif_sta(wl, wlvif) \ | ||
653 | wl12xx_for_each_wlvif_bss_type(wl, wlvif, BSS_TYPE_STA_BSS) | ||
654 | |||
655 | #define wl12xx_for_each_wlvif_ap(wl, wlvif) \ | ||
656 | wl12xx_for_each_wlvif_bss_type(wl, wlvif, BSS_TYPE_AP_BSS) | ||
657 | |||
658 | int wl1271_plt_start(struct wl1271 *wl); | ||
659 | int wl1271_plt_stop(struct wl1271 *wl); | ||
660 | int wl1271_recalc_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif); | ||
661 | void wl12xx_queue_recovery_work(struct wl1271 *wl); | ||
662 | size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen); | ||
663 | |||
664 | #define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */ | ||
665 | |||
666 | #define SESSION_COUNTER_MAX 6 /* maximum value for the session counter */ | ||
667 | #define SESSION_COUNTER_INVALID 7 /* used with dummy_packet */ | ||
668 | |||
669 | #define WL1271_DEFAULT_POWER_LEVEL 0 | ||
670 | |||
671 | #define WL1271_TX_QUEUE_LOW_WATERMARK 32 | ||
672 | #define WL1271_TX_QUEUE_HIGH_WATERMARK 256 | ||
673 | |||
674 | #define WL1271_DEFERRED_QUEUE_LIMIT 64 | ||
675 | |||
676 | /* WL1271 needs a 200ms sleep after power on, and a 20ms sleep before power | ||
677 | on in case is has been shut down shortly before */ | ||
678 | #define WL1271_PRE_POWER_ON_SLEEP 20 /* in milliseconds */ | ||
679 | #define WL1271_POWER_ON_SLEEP 200 /* in milliseconds */ | ||
680 | |||
681 | /* Macros to handle wl1271.sta_rate_set */ | ||
682 | #define HW_BG_RATES_MASK 0xffff | ||
683 | #define HW_HT_RATES_OFFSET 16 | ||
684 | |||
685 | /* Quirks */ | ||
686 | |||
687 | /* Each RX/TX transaction requires an end-of-transaction transfer */ | ||
688 | #define WL12XX_QUIRK_END_OF_TRANSACTION BIT(0) | ||
689 | |||
690 | /* wl127x and SPI don't support SDIO block size alignment */ | ||
691 | #define WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT BIT(2) | ||
692 | |||
693 | /* Older firmwares did not implement the FW logger over bus feature */ | ||
694 | #define WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED BIT(4) | ||
695 | |||
696 | #define WL12XX_HW_BLOCK_SIZE 256 | ||
697 | |||
698 | #endif | ||
diff --git a/drivers/net/wireless/ti/wl12xx/wl12xx_80211.h b/drivers/net/wireless/ti/wl12xx/wl12xx_80211.h new file mode 100644 index 000000000000..22b0bc98d7b5 --- /dev/null +++ b/drivers/net/wireless/ti/wl12xx/wl12xx_80211.h | |||
@@ -0,0 +1,137 @@ | |||
1 | #ifndef __WL12XX_80211_H__ | ||
2 | #define __WL12XX_80211_H__ | ||
3 | |||
4 | #include <linux/if_ether.h> /* ETH_ALEN */ | ||
5 | #include <linux/if_arp.h> | ||
6 | |||
7 | /* RATES */ | ||
8 | #define IEEE80211_CCK_RATE_1MB 0x02 | ||
9 | #define IEEE80211_CCK_RATE_2MB 0x04 | ||
10 | #define IEEE80211_CCK_RATE_5MB 0x0B | ||
11 | #define IEEE80211_CCK_RATE_11MB 0x16 | ||
12 | #define IEEE80211_OFDM_RATE_6MB 0x0C | ||
13 | #define IEEE80211_OFDM_RATE_9MB 0x12 | ||
14 | #define IEEE80211_OFDM_RATE_12MB 0x18 | ||
15 | #define IEEE80211_OFDM_RATE_18MB 0x24 | ||
16 | #define IEEE80211_OFDM_RATE_24MB 0x30 | ||
17 | #define IEEE80211_OFDM_RATE_36MB 0x48 | ||
18 | #define IEEE80211_OFDM_RATE_48MB 0x60 | ||
19 | #define IEEE80211_OFDM_RATE_54MB 0x6C | ||
20 | #define IEEE80211_BASIC_RATE_MASK 0x80 | ||
21 | |||
22 | #define IEEE80211_CCK_RATE_1MB_MASK (1<<0) | ||
23 | #define IEEE80211_CCK_RATE_2MB_MASK (1<<1) | ||
24 | #define IEEE80211_CCK_RATE_5MB_MASK (1<<2) | ||
25 | #define IEEE80211_CCK_RATE_11MB_MASK (1<<3) | ||
26 | #define IEEE80211_OFDM_RATE_6MB_MASK (1<<4) | ||
27 | #define IEEE80211_OFDM_RATE_9MB_MASK (1<<5) | ||
28 | #define IEEE80211_OFDM_RATE_12MB_MASK (1<<6) | ||
29 | #define IEEE80211_OFDM_RATE_18MB_MASK (1<<7) | ||
30 | #define IEEE80211_OFDM_RATE_24MB_MASK (1<<8) | ||
31 | #define IEEE80211_OFDM_RATE_36MB_MASK (1<<9) | ||
32 | #define IEEE80211_OFDM_RATE_48MB_MASK (1<<10) | ||
33 | #define IEEE80211_OFDM_RATE_54MB_MASK (1<<11) | ||
34 | |||
35 | #define IEEE80211_CCK_RATES_MASK 0x0000000F | ||
36 | #define IEEE80211_CCK_BASIC_RATES_MASK (IEEE80211_CCK_RATE_1MB_MASK | \ | ||
37 | IEEE80211_CCK_RATE_2MB_MASK) | ||
38 | #define IEEE80211_CCK_DEFAULT_RATES_MASK (IEEE80211_CCK_BASIC_RATES_MASK | \ | ||
39 | IEEE80211_CCK_RATE_5MB_MASK | \ | ||
40 | IEEE80211_CCK_RATE_11MB_MASK) | ||
41 | |||
42 | #define IEEE80211_OFDM_RATES_MASK 0x00000FF0 | ||
43 | #define IEEE80211_OFDM_BASIC_RATES_MASK (IEEE80211_OFDM_RATE_6MB_MASK | \ | ||
44 | IEEE80211_OFDM_RATE_12MB_MASK | \ | ||
45 | IEEE80211_OFDM_RATE_24MB_MASK) | ||
46 | #define IEEE80211_OFDM_DEFAULT_RATES_MASK (IEEE80211_OFDM_BASIC_RATES_MASK | \ | ||
47 | IEEE80211_OFDM_RATE_9MB_MASK | \ | ||
48 | IEEE80211_OFDM_RATE_18MB_MASK | \ | ||
49 | IEEE80211_OFDM_RATE_36MB_MASK | \ | ||
50 | IEEE80211_OFDM_RATE_48MB_MASK | \ | ||
51 | IEEE80211_OFDM_RATE_54MB_MASK) | ||
52 | #define IEEE80211_DEFAULT_RATES_MASK (IEEE80211_OFDM_DEFAULT_RATES_MASK | \ | ||
53 | IEEE80211_CCK_DEFAULT_RATES_MASK) | ||
54 | |||
55 | |||
56 | /* This really should be 8, but not for our firmware */ | ||
57 | #define MAX_SUPPORTED_RATES 32 | ||
58 | #define MAX_COUNTRY_TRIPLETS 32 | ||
59 | |||
60 | /* Headers */ | ||
61 | struct ieee80211_header { | ||
62 | __le16 frame_ctl; | ||
63 | __le16 duration_id; | ||
64 | u8 da[ETH_ALEN]; | ||
65 | u8 sa[ETH_ALEN]; | ||
66 | u8 bssid[ETH_ALEN]; | ||
67 | __le16 seq_ctl; | ||
68 | u8 payload[0]; | ||
69 | } __packed; | ||
70 | |||
71 | struct wl12xx_ie_header { | ||
72 | u8 id; | ||
73 | u8 len; | ||
74 | } __packed; | ||
75 | |||
76 | /* IEs */ | ||
77 | |||
78 | struct wl12xx_ie_ssid { | ||
79 | struct wl12xx_ie_header header; | ||
80 | char ssid[IEEE80211_MAX_SSID_LEN]; | ||
81 | } __packed; | ||
82 | |||
83 | struct wl12xx_ie_rates { | ||
84 | struct wl12xx_ie_header header; | ||
85 | u8 rates[MAX_SUPPORTED_RATES]; | ||
86 | } __packed; | ||
87 | |||
88 | struct wl12xx_ie_ds_params { | ||
89 | struct wl12xx_ie_header header; | ||
90 | u8 channel; | ||
91 | } __packed; | ||
92 | |||
93 | struct country_triplet { | ||
94 | u8 channel; | ||
95 | u8 num_channels; | ||
96 | u8 max_tx_power; | ||
97 | } __packed; | ||
98 | |||
99 | struct wl12xx_ie_country { | ||
100 | struct wl12xx_ie_header header; | ||
101 | u8 country_string[IEEE80211_COUNTRY_STRING_LEN]; | ||
102 | struct country_triplet triplets[MAX_COUNTRY_TRIPLETS]; | ||
103 | } __packed; | ||
104 | |||
105 | |||
106 | /* Templates */ | ||
107 | |||
108 | struct wl12xx_null_data_template { | ||
109 | struct ieee80211_header header; | ||
110 | } __packed; | ||
111 | |||
112 | struct wl12xx_ps_poll_template { | ||
113 | __le16 fc; | ||
114 | __le16 aid; | ||
115 | u8 bssid[ETH_ALEN]; | ||
116 | u8 ta[ETH_ALEN]; | ||
117 | } __packed; | ||
118 | |||
119 | struct wl12xx_arp_rsp_template { | ||
120 | /* not including ieee80211 header */ | ||
121 | |||
122 | u8 llc_hdr[sizeof(rfc1042_header)]; | ||
123 | __be16 llc_type; | ||
124 | |||
125 | struct arphdr arp_hdr; | ||
126 | u8 sender_hw[ETH_ALEN]; | ||
127 | __be32 sender_ip; | ||
128 | u8 target_hw[ETH_ALEN]; | ||
129 | __be32 target_ip; | ||
130 | } __packed; | ||
131 | |||
132 | struct wl12xx_disconn_template { | ||
133 | struct ieee80211_header header; | ||
134 | __le16 disconn_reason; | ||
135 | } __packed; | ||
136 | |||
137 | #endif | ||
diff --git a/drivers/net/wireless/ti/wl12xx/wl12xx_platform_data.c b/drivers/net/wireless/ti/wl12xx/wl12xx_platform_data.c new file mode 100644 index 000000000000..998e95895f9d --- /dev/null +++ b/drivers/net/wireless/ti/wl12xx/wl12xx_platform_data.c | |||
@@ -0,0 +1,49 @@ | |||
1 | /* | ||
2 | * This file is part of wl12xx | ||
3 | * | ||
4 | * Copyright (C) 2010-2011 Texas Instruments, Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * version 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
18 | * 02110-1301 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/err.h> | ||
24 | #include <linux/wl12xx.h> | ||
25 | |||
26 | static struct wl12xx_platform_data *platform_data; | ||
27 | |||
28 | int __init wl12xx_set_platform_data(const struct wl12xx_platform_data *data) | ||
29 | { | ||
30 | if (platform_data) | ||
31 | return -EBUSY; | ||
32 | if (!data) | ||
33 | return -EINVAL; | ||
34 | |||
35 | platform_data = kmemdup(data, sizeof(*data), GFP_KERNEL); | ||
36 | if (!platform_data) | ||
37 | return -ENOMEM; | ||
38 | |||
39 | return 0; | ||
40 | } | ||
41 | |||
42 | struct wl12xx_platform_data *wl12xx_get_platform_data(void) | ||
43 | { | ||
44 | if (!platform_data) | ||
45 | return ERR_PTR(-ENODEV); | ||
46 | |||
47 | return platform_data; | ||
48 | } | ||
49 | EXPORT_SYMBOL(wl12xx_get_platform_data); | ||