blob: 6447a0969ffe66122a2ffca81aad3f4ec1c0eca0 [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
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
Shahar Levi00d20102010-11-08 11:20:10 +000024#include "acx.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025
26#include <linux/module.h>
27#include <linux/platform_device.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030028#include <linux/spi/spi.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090029#include <linux/slab.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030030
Shahar Levi00d20102010-11-08 11:20:10 +000031#include "wl12xx.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030032#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000033#include "reg.h"
34#include "ps.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030035
Juuso Oikarinen51f2be22009-10-13 12:47:42 +030036int wl1271_acx_wake_up_conditions(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030037{
38 struct acx_wake_up_condition *wake_up;
39 int ret;
40
41 wl1271_debug(DEBUG_ACX, "acx wake up conditions");
42
43 wake_up = kzalloc(sizeof(*wake_up), GFP_KERNEL);
44 if (!wake_up) {
45 ret = -ENOMEM;
46 goto out;
47 }
48
Juuso Oikarinen51f2be22009-10-13 12:47:42 +030049 wake_up->wake_up_event = wl->conf.conn.wake_up_event;
50 wake_up->listen_interval = wl->conf.conn.listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030051
52 ret = wl1271_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS,
53 wake_up, sizeof(*wake_up));
54 if (ret < 0) {
55 wl1271_warning("could not set wake up conditions: %d", ret);
56 goto out;
57 }
58
59out:
60 kfree(wake_up);
61 return ret;
62}
63
64int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth)
65{
66 struct acx_sleep_auth *auth;
67 int ret;
68
69 wl1271_debug(DEBUG_ACX, "acx sleep auth");
70
71 auth = kzalloc(sizeof(*auth), GFP_KERNEL);
72 if (!auth) {
73 ret = -ENOMEM;
74 goto out;
75 }
76
77 auth->sleep_auth = sleep_auth;
78
79 ret = wl1271_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth));
80 if (ret < 0)
81 return ret;
82
83out:
84 kfree(auth);
85 return ret;
86}
87
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030088int wl1271_acx_tx_power(struct wl1271 *wl, int power)
89{
90 struct acx_current_tx_power *acx;
91 int ret;
92
Arik Nemtsov097f8822011-06-27 22:06:34 +030093 wl1271_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr %d", power);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030094
95 if (power < 0 || power > 25)
96 return -EINVAL;
97
98 acx = kzalloc(sizeof(*acx), GFP_KERNEL);
99 if (!acx) {
100 ret = -ENOMEM;
101 goto out;
102 }
103
Juuso Oikarinen6f6b5d42010-02-22 08:38:42 +0200104 acx->current_tx_power = power * 10;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300105
106 ret = wl1271_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx));
107 if (ret < 0) {
108 wl1271_warning("configure of tx power failed: %d", ret);
109 goto out;
110 }
111
112out:
113 kfree(acx);
114 return ret;
115}
116
117int wl1271_acx_feature_cfg(struct wl1271 *wl)
118{
119 struct acx_feature_config *feature;
120 int ret;
121
122 wl1271_debug(DEBUG_ACX, "acx feature cfg");
123
124 feature = kzalloc(sizeof(*feature), GFP_KERNEL);
125 if (!feature) {
126 ret = -ENOMEM;
127 goto out;
128 }
129
130 /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */
131 feature->data_flow_options = 0;
132 feature->options = 0;
133
134 ret = wl1271_cmd_configure(wl, ACX_FEATURE_CFG,
135 feature, sizeof(*feature));
136 if (ret < 0) {
137 wl1271_error("Couldnt set HW encryption");
138 goto out;
139 }
140
141out:
142 kfree(feature);
143 return ret;
144}
145
146int wl1271_acx_mem_map(struct wl1271 *wl, struct acx_header *mem_map,
147 size_t len)
148{
149 int ret;
150
151 wl1271_debug(DEBUG_ACX, "acx mem map");
152
153 ret = wl1271_cmd_interrogate(wl, ACX_MEM_MAP, mem_map, len);
154 if (ret < 0)
155 return ret;
156
157 return 0;
158}
159
Juuso Oikarinen8793f9b2009-10-13 12:47:40 +0300160int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300161{
162 struct acx_rx_msdu_lifetime *acx;
163 int ret;
164
165 wl1271_debug(DEBUG_ACX, "acx rx msdu life time");
166
167 acx = kzalloc(sizeof(*acx), GFP_KERNEL);
168 if (!acx) {
169 ret = -ENOMEM;
170 goto out;
171 }
172
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300173 acx->lifetime = cpu_to_le32(wl->conf.rx.rx_msdu_life_time);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300174 ret = wl1271_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME,
175 acx, sizeof(*acx));
176 if (ret < 0) {
177 wl1271_warning("failed to set rx msdu life time: %d", ret);
178 goto out;
179 }
180
181out:
182 kfree(acx);
183 return ret;
184}
185
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300186int wl1271_acx_pd_threshold(struct wl1271 *wl)
187{
188 struct acx_packet_detection *pd;
189 int ret;
190
191 wl1271_debug(DEBUG_ACX, "acx data pd threshold");
192
193 pd = kzalloc(sizeof(*pd), GFP_KERNEL);
194 if (!pd) {
195 ret = -ENOMEM;
196 goto out;
197 }
198
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300199 pd->threshold = cpu_to_le32(wl->conf.rx.packet_detection_threshold);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300200
201 ret = wl1271_cmd_configure(wl, ACX_PD_THRESHOLD, pd, sizeof(*pd));
202 if (ret < 0) {
203 wl1271_warning("failed to set pd threshold: %d", ret);
204 goto out;
205 }
206
207out:
208 kfree(pd);
Julia Lawall36d34412010-08-16 18:27:30 +0200209 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300210}
211
212int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time)
213{
214 struct acx_slot *slot;
215 int ret;
216
217 wl1271_debug(DEBUG_ACX, "acx slot");
218
219 slot = kzalloc(sizeof(*slot), GFP_KERNEL);
220 if (!slot) {
221 ret = -ENOMEM;
222 goto out;
223 }
224
225 slot->wone_index = STATION_WONE_INDEX;
226 slot->slot_time = slot_time;
227
228 ret = wl1271_cmd_configure(wl, ACX_SLOT, slot, sizeof(*slot));
229 if (ret < 0) {
230 wl1271_warning("failed to set slot time: %d", ret);
231 goto out;
232 }
233
234out:
235 kfree(slot);
236 return ret;
237}
238
Juuso Oikarinenc87dec92009-10-08 21:56:31 +0300239int wl1271_acx_group_address_tbl(struct wl1271 *wl, bool enable,
240 void *mc_list, u32 mc_list_len)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300241{
242 struct acx_dot11_grp_addr_tbl *acx;
243 int ret;
244
245 wl1271_debug(DEBUG_ACX, "acx group address tbl");
246
247 acx = kzalloc(sizeof(*acx), GFP_KERNEL);
248 if (!acx) {
249 ret = -ENOMEM;
250 goto out;
251 }
252
253 /* MAC filtering */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +0300254 acx->enabled = enable;
255 acx->num_groups = mc_list_len;
256 memcpy(acx->mac_table, mc_list, mc_list_len * ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300257
258 ret = wl1271_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL,
259 acx, sizeof(*acx));
260 if (ret < 0) {
261 wl1271_warning("failed to set group addr table: %d", ret);
262 goto out;
263 }
264
265out:
266 kfree(acx);
267 return ret;
268}
269
270int wl1271_acx_service_period_timeout(struct wl1271 *wl)
271{
272 struct acx_rx_timeout *rx_timeout;
273 int ret;
274
275 rx_timeout = kzalloc(sizeof(*rx_timeout), GFP_KERNEL);
276 if (!rx_timeout) {
277 ret = -ENOMEM;
278 goto out;
279 }
280
281 wl1271_debug(DEBUG_ACX, "acx service period timeout");
282
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300283 rx_timeout->ps_poll_timeout = cpu_to_le16(wl->conf.rx.ps_poll_timeout);
284 rx_timeout->upsd_timeout = cpu_to_le16(wl->conf.rx.upsd_timeout);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300285
286 ret = wl1271_cmd_configure(wl, ACX_SERVICE_PERIOD_TIMEOUT,
287 rx_timeout, sizeof(*rx_timeout));
288 if (ret < 0) {
289 wl1271_warning("failed to set service period timeout: %d",
290 ret);
291 goto out;
292 }
293
294out:
295 kfree(rx_timeout);
296 return ret;
297}
298
Arik Nemtsov5f704d12011-04-18 14:15:21 +0300299int wl1271_acx_rts_threshold(struct wl1271 *wl, u32 rts_threshold)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300300{
301 struct acx_rts_threshold *rts;
302 int ret;
303
Arik Nemtsov5f704d12011-04-18 14:15:21 +0300304 /*
305 * If the RTS threshold is not configured or out of range, use the
306 * default value.
307 */
308 if (rts_threshold > IEEE80211_MAX_RTS_THRESHOLD)
309 rts_threshold = wl->conf.rx.rts_threshold;
310
311 wl1271_debug(DEBUG_ACX, "acx rts threshold: %d", rts_threshold);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300312
313 rts = kzalloc(sizeof(*rts), GFP_KERNEL);
314 if (!rts) {
315 ret = -ENOMEM;
316 goto out;
317 }
318
Arik Nemtsov5f704d12011-04-18 14:15:21 +0300319 rts->threshold = cpu_to_le16((u16)rts_threshold);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300320
321 ret = wl1271_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts));
322 if (ret < 0) {
323 wl1271_warning("failed to set rts threshold: %d", ret);
324 goto out;
325 }
326
327out:
328 kfree(rts);
329 return ret;
330}
331
Luciano Coelho6e92b412009-12-11 15:40:50 +0200332int wl1271_acx_dco_itrim_params(struct wl1271 *wl)
333{
334 struct acx_dco_itrim_params *dco;
335 struct conf_itrim_settings *c = &wl->conf.itrim;
336 int ret;
337
338 wl1271_debug(DEBUG_ACX, "acx dco itrim parameters");
339
340 dco = kzalloc(sizeof(*dco), GFP_KERNEL);
341 if (!dco) {
342 ret = -ENOMEM;
343 goto out;
344 }
345
346 dco->enable = c->enable;
347 dco->timeout = cpu_to_le32(c->timeout);
348
349 ret = wl1271_cmd_configure(wl, ACX_SET_DCO_ITRIM_PARAMS,
350 dco, sizeof(*dco));
351 if (ret < 0) {
352 wl1271_warning("failed to set dco itrim parameters: %d", ret);
353 goto out;
354 }
355
356out:
357 kfree(dco);
358 return ret;
359}
360
Juuso Oikarinen19221672009-10-08 21:56:35 +0300361int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300362{
Juuso Oikarinen51f2be22009-10-13 12:47:42 +0300363 struct acx_beacon_filter_option *beacon_filter = NULL;
364 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300365
366 wl1271_debug(DEBUG_ACX, "acx beacon filter opt");
367
Juuso Oikarinen51f2be22009-10-13 12:47:42 +0300368 if (enable_filter &&
369 wl->conf.conn.bcn_filt_mode == CONF_BCN_FILT_MODE_DISABLED)
370 goto out;
371
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300372 beacon_filter = kzalloc(sizeof(*beacon_filter), GFP_KERNEL);
373 if (!beacon_filter) {
374 ret = -ENOMEM;
375 goto out;
376 }
377
Juuso Oikarinen19221672009-10-08 21:56:35 +0300378 beacon_filter->enable = enable_filter;
Juuso Oikarinen51f2be22009-10-13 12:47:42 +0300379
380 /*
381 * When set to zero, and the filter is enabled, beacons
382 * without the unicast TIM bit set are dropped.
383 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300384 beacon_filter->max_num_beacons = 0;
385
386 ret = wl1271_cmd_configure(wl, ACX_BEACON_FILTER_OPT,
387 beacon_filter, sizeof(*beacon_filter));
388 if (ret < 0) {
389 wl1271_warning("failed to set beacon filter opt: %d", ret);
390 goto out;
391 }
392
393out:
394 kfree(beacon_filter);
395 return ret;
396}
397
398int wl1271_acx_beacon_filter_table(struct wl1271 *wl)
399{
400 struct acx_beacon_filter_ie_table *ie_table;
Juuso Oikarinen51f2be22009-10-13 12:47:42 +0300401 int i, idx = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300402 int ret;
Juuso Oikarinen51f2be22009-10-13 12:47:42 +0300403 bool vendor_spec = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300404
405 wl1271_debug(DEBUG_ACX, "acx beacon filter table");
406
407 ie_table = kzalloc(sizeof(*ie_table), GFP_KERNEL);
408 if (!ie_table) {
409 ret = -ENOMEM;
410 goto out;
411 }
412
Juuso Oikarinen19221672009-10-08 21:56:35 +0300413 /* configure default beacon pass-through rules */
Juuso Oikarinen51f2be22009-10-13 12:47:42 +0300414 ie_table->num_ie = 0;
415 for (i = 0; i < wl->conf.conn.bcn_filt_ie_count; i++) {
416 struct conf_bcn_filt_rule *r = &(wl->conf.conn.bcn_filt_ie[i]);
417 ie_table->table[idx++] = r->ie;
418 ie_table->table[idx++] = r->rule;
419
420 if (r->ie == WLAN_EID_VENDOR_SPECIFIC) {
421 /* only one vendor specific ie allowed */
422 if (vendor_spec)
423 continue;
424
425 /* for vendor specific rules configure the
426 additional fields */
427 memcpy(&(ie_table->table[idx]), r->oui,
428 CONF_BCN_IE_OUI_LEN);
429 idx += CONF_BCN_IE_OUI_LEN;
430 ie_table->table[idx++] = r->type;
431 memcpy(&(ie_table->table[idx]), r->version,
432 CONF_BCN_IE_VER_LEN);
433 idx += CONF_BCN_IE_VER_LEN;
434 vendor_spec = true;
435 }
436
437 ie_table->num_ie++;
438 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300439
440 ret = wl1271_cmd_configure(wl, ACX_BEACON_FILTER_TABLE,
441 ie_table, sizeof(*ie_table));
442 if (ret < 0) {
443 wl1271_warning("failed to set beacon filter table: %d", ret);
444 goto out;
445 }
446
447out:
448 kfree(ie_table);
449 return ret;
450}
451
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200452#define ACX_CONN_MONIT_DISABLE_VALUE 0xffffffff
453
454int wl1271_acx_conn_monit_params(struct wl1271 *wl, bool enable)
Juuso Oikarinen34415232009-10-08 21:56:33 +0300455{
456 struct acx_conn_monit_params *acx;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200457 u32 threshold = ACX_CONN_MONIT_DISABLE_VALUE;
458 u32 timeout = ACX_CONN_MONIT_DISABLE_VALUE;
Juuso Oikarinen34415232009-10-08 21:56:33 +0300459 int ret;
460
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200461 wl1271_debug(DEBUG_ACX, "acx connection monitor parameters: %s",
462 enable ? "enabled" : "disabled");
Juuso Oikarinen34415232009-10-08 21:56:33 +0300463
464 acx = kzalloc(sizeof(*acx), GFP_KERNEL);
465 if (!acx) {
466 ret = -ENOMEM;
467 goto out;
468 }
469
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200470 if (enable) {
471 threshold = wl->conf.conn.synch_fail_thold;
472 timeout = wl->conf.conn.bss_lose_timeout;
473 }
474
475 acx->synch_fail_thold = cpu_to_le32(threshold);
476 acx->bss_lose_timeout = cpu_to_le32(timeout);
Juuso Oikarinen34415232009-10-08 21:56:33 +0300477
478 ret = wl1271_cmd_configure(wl, ACX_CONN_MONIT_PARAMS,
479 acx, sizeof(*acx));
480 if (ret < 0) {
481 wl1271_warning("failed to set connection monitor "
482 "parameters: %d", ret);
483 goto out;
484 }
485
486out:
487 kfree(acx);
488 return ret;
489}
490
491
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +0200492int wl1271_acx_sg_enable(struct wl1271 *wl, bool enable)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300493{
494 struct acx_bt_wlan_coex *pta;
495 int ret;
496
497 wl1271_debug(DEBUG_ACX, "acx sg enable");
498
499 pta = kzalloc(sizeof(*pta), GFP_KERNEL);
500 if (!pta) {
501 ret = -ENOMEM;
502 goto out;
503 }
504
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +0200505 if (enable)
506 pta->enable = wl->conf.sg.state;
507 else
508 pta->enable = CONF_SG_DISABLE;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300509
510 ret = wl1271_cmd_configure(wl, ACX_SG_ENABLE, pta, sizeof(*pta));
511 if (ret < 0) {
512 wl1271_warning("failed to set softgemini enable: %d", ret);
513 goto out;
514 }
515
516out:
517 kfree(pta);
518 return ret;
519}
520
Arik Nemtsov801f8702011-04-18 14:15:20 +0300521int wl1271_acx_sta_sg_cfg(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300522{
Arik Nemtsov801f8702011-04-18 14:15:20 +0300523 struct acx_sta_bt_wlan_coex_param *param;
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300524 struct conf_sg_settings *c = &wl->conf.sg;
Juuso Oikarinen1b00f542010-03-18 12:26:30 +0200525 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300526
Arik Nemtsov801f8702011-04-18 14:15:20 +0300527 wl1271_debug(DEBUG_ACX, "acx sg sta cfg");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300528
529 param = kzalloc(sizeof(*param), GFP_KERNEL);
530 if (!param) {
531 ret = -ENOMEM;
532 goto out;
533 }
534
535 /* BT-WLAN coext parameters */
Arik Nemtsov801f8702011-04-18 14:15:20 +0300536 for (i = 0; i < CONF_SG_STA_PARAMS_MAX; i++)
537 param->params[i] = cpu_to_le32(c->sta_params[i]);
538 param->param_idx = CONF_SG_PARAMS_ALL;
539
540 ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param));
541 if (ret < 0) {
542 wl1271_warning("failed to set sg config: %d", ret);
543 goto out;
544 }
545
546out:
547 kfree(param);
548 return ret;
549}
550
551int wl1271_acx_ap_sg_cfg(struct wl1271 *wl)
552{
553 struct acx_ap_bt_wlan_coex_param *param;
554 struct conf_sg_settings *c = &wl->conf.sg;
555 int i, ret;
556
557 wl1271_debug(DEBUG_ACX, "acx sg ap cfg");
558
559 param = kzalloc(sizeof(*param), GFP_KERNEL);
560 if (!param) {
561 ret = -ENOMEM;
562 goto out;
563 }
564
565 /* BT-WLAN coext parameters */
566 for (i = 0; i < CONF_SG_AP_PARAMS_MAX; i++)
567 param->params[i] = cpu_to_le32(c->ap_params[i]);
Juuso Oikarinen1b00f542010-03-18 12:26:30 +0200568 param->param_idx = CONF_SG_PARAMS_ALL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300569
570 ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param));
571 if (ret < 0) {
572 wl1271_warning("failed to set sg config: %d", ret);
573 goto out;
574 }
575
576out:
577 kfree(param);
578 return ret;
579}
580
581int wl1271_acx_cca_threshold(struct wl1271 *wl)
582{
583 struct acx_energy_detection *detection;
584 int ret;
585
586 wl1271_debug(DEBUG_ACX, "acx cca threshold");
587
588 detection = kzalloc(sizeof(*detection), GFP_KERNEL);
589 if (!detection) {
590 ret = -ENOMEM;
591 goto out;
592 }
593
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300594 detection->rx_cca_threshold = cpu_to_le16(wl->conf.rx.rx_cca_threshold);
Juuso Oikarinen45b531a2009-10-13 12:47:41 +0300595 detection->tx_energy_detection = wl->conf.tx.tx_energy_detection;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300596
597 ret = wl1271_cmd_configure(wl, ACX_CCA_THRESHOLD,
598 detection, sizeof(*detection));
599 if (ret < 0) {
600 wl1271_warning("failed to set cca threshold: %d", ret);
601 return ret;
602 }
603
604out:
605 kfree(detection);
606 return ret;
607}
608
609int wl1271_acx_bcn_dtim_options(struct wl1271 *wl)
610{
611 struct acx_beacon_broadcast *bb;
612 int ret;
613
614 wl1271_debug(DEBUG_ACX, "acx bcn dtim options");
615
616 bb = kzalloc(sizeof(*bb), GFP_KERNEL);
617 if (!bb) {
618 ret = -ENOMEM;
619 goto out;
620 }
621
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300622 bb->beacon_rx_timeout = cpu_to_le16(wl->conf.conn.beacon_rx_timeout);
623 bb->broadcast_timeout = cpu_to_le16(wl->conf.conn.broadcast_timeout);
Juuso Oikarinen51f2be22009-10-13 12:47:42 +0300624 bb->rx_broadcast_in_ps = wl->conf.conn.rx_broadcast_in_ps;
625 bb->ps_poll_threshold = wl->conf.conn.ps_poll_threshold;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300626
627 ret = wl1271_cmd_configure(wl, ACX_BCN_DTIM_OPTIONS, bb, sizeof(*bb));
628 if (ret < 0) {
629 wl1271_warning("failed to set rx config: %d", ret);
630 goto out;
631 }
632
633out:
634 kfree(bb);
635 return ret;
636}
637
638int wl1271_acx_aid(struct wl1271 *wl, u16 aid)
639{
640 struct acx_aid *acx_aid;
641 int ret;
642
643 wl1271_debug(DEBUG_ACX, "acx aid");
644
645 acx_aid = kzalloc(sizeof(*acx_aid), GFP_KERNEL);
646 if (!acx_aid) {
647 ret = -ENOMEM;
648 goto out;
649 }
650
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300651 acx_aid->aid = cpu_to_le16(aid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300652
653 ret = wl1271_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid));
654 if (ret < 0) {
655 wl1271_warning("failed to set aid: %d", ret);
656 goto out;
657 }
658
659out:
660 kfree(acx_aid);
661 return ret;
662}
663
664int wl1271_acx_event_mbox_mask(struct wl1271 *wl, u32 event_mask)
665{
666 struct acx_event_mask *mask;
667 int ret;
668
669 wl1271_debug(DEBUG_ACX, "acx event mbox mask");
670
671 mask = kzalloc(sizeof(*mask), GFP_KERNEL);
672 if (!mask) {
673 ret = -ENOMEM;
674 goto out;
675 }
676
677 /* high event mask is unused */
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300678 mask->high_event_mask = cpu_to_le32(0xffffffff);
679 mask->event_mask = cpu_to_le32(event_mask);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300680
681 ret = wl1271_cmd_configure(wl, ACX_EVENT_MBOX_MASK,
682 mask, sizeof(*mask));
683 if (ret < 0) {
684 wl1271_warning("failed to set acx_event_mbox_mask: %d", ret);
685 goto out;
686 }
687
688out:
689 kfree(mask);
690 return ret;
691}
692
693int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble)
694{
695 struct acx_preamble *acx;
696 int ret;
697
698 wl1271_debug(DEBUG_ACX, "acx_set_preamble");
699
700 acx = kzalloc(sizeof(*acx), GFP_KERNEL);
701 if (!acx) {
702 ret = -ENOMEM;
703 goto out;
704 }
705
706 acx->preamble = preamble;
707
708 ret = wl1271_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx));
709 if (ret < 0) {
710 wl1271_warning("Setting of preamble failed: %d", ret);
711 goto out;
712 }
713
714out:
715 kfree(acx);
716 return ret;
717}
718
719int wl1271_acx_cts_protect(struct wl1271 *wl,
720 enum acx_ctsprotect_type ctsprotect)
721{
722 struct acx_ctsprotect *acx;
723 int ret;
724
725 wl1271_debug(DEBUG_ACX, "acx_set_ctsprotect");
726
727 acx = kzalloc(sizeof(*acx), GFP_KERNEL);
728 if (!acx) {
729 ret = -ENOMEM;
730 goto out;
731 }
732
733 acx->ctsprotect = ctsprotect;
734
735 ret = wl1271_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx));
736 if (ret < 0) {
737 wl1271_warning("Setting of ctsprotect failed: %d", ret);
738 goto out;
739 }
740
741out:
742 kfree(acx);
743 return ret;
744}
745
746int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats)
747{
748 int ret;
749
750 wl1271_debug(DEBUG_ACX, "acx statistics");
751
752 ret = wl1271_cmd_interrogate(wl, ACX_STATISTICS, stats,
753 sizeof(*stats));
754 if (ret < 0) {
755 wl1271_warning("acx statistics failed: %d", ret);
756 return -ENOMEM;
757 }
758
759 return 0;
760}
761
Arik Nemtsov79b223f2010-10-16 17:52:59 +0200762int wl1271_acx_sta_rate_policies(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300763{
Arik Nemtsov79b223f2010-10-16 17:52:59 +0200764 struct acx_sta_rate_policy *acx;
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200765 struct conf_tx_rate_class *c = &wl->conf.tx.sta_rc_conf;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200766 int idx = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300767 int ret = 0;
768
769 wl1271_debug(DEBUG_ACX, "acx rate policies");
770
771 acx = kzalloc(sizeof(*acx), GFP_KERNEL);
772
773 if (!acx) {
774 ret = -ENOMEM;
775 goto out;
776 }
777
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200778 /* configure one basic rate class */
779 idx = ACX_TX_BASIC_RATE;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300780 acx->rate_class[idx].enabled_rates = cpu_to_le32(wl->basic_rate);
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200781 acx->rate_class[idx].short_retry_limit = c->short_retry_limit;
782 acx->rate_class[idx].long_retry_limit = c->long_retry_limit;
783 acx->rate_class[idx].aflags = c->aflags;
784
785 /* configure one AP supported rate class */
786 idx = ACX_TX_AP_FULL_RATE;
787 acx->rate_class[idx].enabled_rates = cpu_to_le32(wl->rate_set);
788 acx->rate_class[idx].short_retry_limit = c->short_retry_limit;
789 acx->rate_class[idx].long_retry_limit = c->long_retry_limit;
790 acx->rate_class[idx].aflags = c->aflags;
791
792 acx->rate_class_cnt = cpu_to_le32(ACX_TX_RATE_POLICY_CNT);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300793
Eliad Peller72c2d9e2011-02-02 09:59:37 +0200794 wl1271_debug(DEBUG_ACX, "basic_rate: 0x%x, full_rate: 0x%x",
795 acx->rate_class[ACX_TX_BASIC_RATE].enabled_rates,
796 acx->rate_class[ACX_TX_AP_FULL_RATE].enabled_rates);
797
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300798 ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx));
799 if (ret < 0) {
800 wl1271_warning("Setting of rate policies failed: %d", ret);
801 goto out;
802 }
803
804out:
805 kfree(acx);
806 return ret;
807}
808
Arik Nemtsov79b223f2010-10-16 17:52:59 +0200809int wl1271_acx_ap_rate_policy(struct wl1271 *wl, struct conf_tx_rate_class *c,
810 u8 idx)
811{
812 struct acx_ap_rate_policy *acx;
813 int ret = 0;
814
Arik Nemtsov70f47422011-04-18 14:15:25 +0300815 wl1271_debug(DEBUG_ACX, "acx ap rate policy %d rates 0x%x",
816 idx, c->enabled_rates);
Arik Nemtsov79b223f2010-10-16 17:52:59 +0200817
818 acx = kzalloc(sizeof(*acx), GFP_KERNEL);
819 if (!acx) {
820 ret = -ENOMEM;
821 goto out;
822 }
823
824 acx->rate_policy.enabled_rates = cpu_to_le32(c->enabled_rates);
825 acx->rate_policy.short_retry_limit = c->short_retry_limit;
826 acx->rate_policy.long_retry_limit = c->long_retry_limit;
827 acx->rate_policy.aflags = c->aflags;
828
Eliad Peller1d4801f2011-01-16 10:07:10 +0100829 acx->rate_policy_idx = cpu_to_le32(idx);
Arik Nemtsov79b223f2010-10-16 17:52:59 +0200830
831 ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx));
832 if (ret < 0) {
833 wl1271_warning("Setting of ap rate policy failed: %d", ret);
834 goto out;
835 }
836
837out:
838 kfree(acx);
839 return ret;
840}
841
Kalle Valo243eeb52010-02-18 13:25:39 +0200842int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max,
843 u8 aifsn, u16 txop)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300844{
845 struct acx_ac_cfg *acx;
Kalle Valo243eeb52010-02-18 13:25:39 +0200846 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300847
Kalle Valo243eeb52010-02-18 13:25:39 +0200848 wl1271_debug(DEBUG_ACX, "acx ac cfg %d cw_ming %d cw_max %d "
849 "aifs %d txop %d", ac, cw_min, cw_max, aifsn, txop);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300850
851 acx = kzalloc(sizeof(*acx), GFP_KERNEL);
852
853 if (!acx) {
854 ret = -ENOMEM;
855 goto out;
856 }
857
Kalle Valo243eeb52010-02-18 13:25:39 +0200858 acx->ac = ac;
859 acx->cw_min = cw_min;
860 acx->cw_max = cpu_to_le16(cw_max);
861 acx->aifsn = aifsn;
862 acx->tx_op_limit = cpu_to_le16(txop);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300863
Kalle Valo243eeb52010-02-18 13:25:39 +0200864 ret = wl1271_cmd_configure(wl, ACX_AC_CFG, acx, sizeof(*acx));
865 if (ret < 0) {
866 wl1271_warning("acx ac cfg failed: %d", ret);
867 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300868 }
869
870out:
871 kfree(acx);
872 return ret;
873}
874
Kalle Valof2054df2010-02-18 13:25:40 +0200875int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type,
876 u8 tsid, u8 ps_scheme, u8 ack_policy,
877 u32 apsd_conf0, u32 apsd_conf1)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300878{
879 struct acx_tid_config *acx;
Kalle Valof2054df2010-02-18 13:25:40 +0200880 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300881
882 wl1271_debug(DEBUG_ACX, "acx tid config");
883
884 acx = kzalloc(sizeof(*acx), GFP_KERNEL);
885
886 if (!acx) {
887 ret = -ENOMEM;
888 goto out;
889 }
890
Kalle Valof2054df2010-02-18 13:25:40 +0200891 acx->queue_id = queue_id;
892 acx->channel_type = channel_type;
893 acx->tsid = tsid;
894 acx->ps_scheme = ps_scheme;
895 acx->ack_policy = ack_policy;
896 acx->apsd_conf[0] = cpu_to_le32(apsd_conf0);
897 acx->apsd_conf[1] = cpu_to_le32(apsd_conf1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300898
Kalle Valof2054df2010-02-18 13:25:40 +0200899 ret = wl1271_cmd_configure(wl, ACX_TID_CFG, acx, sizeof(*acx));
900 if (ret < 0) {
901 wl1271_warning("Setting of tid config failed: %d", ret);
902 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300903 }
904
905out:
906 kfree(acx);
907 return ret;
908}
909
Arik Nemtsov5f704d12011-04-18 14:15:21 +0300910int wl1271_acx_frag_threshold(struct wl1271 *wl, u32 frag_threshold)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300911{
912 struct acx_frag_threshold *acx;
913 int ret = 0;
914
Arik Nemtsov5f704d12011-04-18 14:15:21 +0300915 /*
916 * If the fragmentation is not configured or out of range, use the
917 * default value.
918 */
919 if (frag_threshold > IEEE80211_MAX_FRAG_THRESHOLD)
920 frag_threshold = wl->conf.tx.frag_threshold;
921
922 wl1271_debug(DEBUG_ACX, "acx frag threshold: %d", frag_threshold);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300923
924 acx = kzalloc(sizeof(*acx), GFP_KERNEL);
925
926 if (!acx) {
927 ret = -ENOMEM;
928 goto out;
929 }
930
Arik Nemtsov5f704d12011-04-18 14:15:21 +0300931 acx->frag_threshold = cpu_to_le16((u16)frag_threshold);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300932 ret = wl1271_cmd_configure(wl, ACX_FRAG_CFG, acx, sizeof(*acx));
933 if (ret < 0) {
934 wl1271_warning("Setting of frag threshold failed: %d", ret);
935 goto out;
936 }
937
938out:
939 kfree(acx);
940 return ret;
941}
942
943int wl1271_acx_tx_config_options(struct wl1271 *wl)
944{
945 struct acx_tx_config_options *acx;
946 int ret = 0;
947
948 wl1271_debug(DEBUG_ACX, "acx tx config options");
949
950 acx = kzalloc(sizeof(*acx), GFP_KERNEL);
951
952 if (!acx) {
953 ret = -ENOMEM;
954 goto out;
955 }
956
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300957 acx->tx_compl_timeout = cpu_to_le16(wl->conf.tx.tx_compl_timeout);
958 acx->tx_compl_threshold = cpu_to_le16(wl->conf.tx.tx_compl_threshold);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300959 ret = wl1271_cmd_configure(wl, ACX_TX_CONFIG_OPT, acx, sizeof(*acx));
960 if (ret < 0) {
961 wl1271_warning("Setting of tx options failed: %d", ret);
962 goto out;
963 }
964
965out:
966 kfree(acx);
967 return ret;
968}
969
Eliad Pellerc8bde242011-02-02 09:59:35 +0200970int wl1271_acx_ap_mem_cfg(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300971{
Eliad Pellerc8bde242011-02-02 09:59:35 +0200972 struct wl1271_acx_ap_config_memory *mem_conf;
Ido Yarivae825e42011-04-18 16:40:14 +0300973 struct conf_memory_settings *mem;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300974 int ret;
975
976 wl1271_debug(DEBUG_ACX, "wl1271 mem cfg");
977
978 mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL);
979 if (!mem_conf) {
980 ret = -ENOMEM;
981 goto out;
982 }
983
Ido Yarivae825e42011-04-18 16:40:14 +0300984 if (wl->chip.id == CHIP_ID_1283_PG20)
985 /*
986 * FIXME: The 128x AP FW does not yet support dynamic memory.
987 * Use the base memory configuration for 128x for now. This
988 * should be fine tuned in the future.
989 */
990 mem = &wl->conf.mem_wl128x;
991 else
992 mem = &wl->conf.mem_wl127x;
993
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300994 /* memory config */
Ido Yarivae825e42011-04-18 16:40:14 +0300995 mem_conf->num_stations = mem->num_stations;
996 mem_conf->rx_mem_block_num = mem->rx_block_num;
997 mem_conf->tx_min_mem_block_num = mem->tx_min_block_num;
998 mem_conf->num_ssid_profiles = mem->ssid_profiles;
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300999 mem_conf->total_tx_descriptors = cpu_to_le32(ACX_TX_DESCRIPTORS);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001000
1001 ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf,
1002 sizeof(*mem_conf));
1003 if (ret < 0) {
1004 wl1271_warning("wl1271 mem config failed: %d", ret);
1005 goto out;
1006 }
1007
1008out:
1009 kfree(mem_conf);
1010 return ret;
1011}
1012
Eliad Pellerc8bde242011-02-02 09:59:35 +02001013int wl1271_acx_sta_mem_cfg(struct wl1271 *wl)
1014{
1015 struct wl1271_acx_sta_config_memory *mem_conf;
Shahar Levi13b107d2011-03-06 16:32:12 +02001016 struct conf_memory_settings *mem;
Eliad Pellerc8bde242011-02-02 09:59:35 +02001017 int ret;
1018
1019 wl1271_debug(DEBUG_ACX, "wl1271 mem cfg");
1020
1021 mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL);
1022 if (!mem_conf) {
1023 ret = -ENOMEM;
1024 goto out;
1025 }
1026
Shahar Levi13b107d2011-03-06 16:32:12 +02001027 if (wl->chip.id == CHIP_ID_1283_PG20)
1028 mem = &wl->conf.mem_wl128x;
1029 else
1030 mem = &wl->conf.mem_wl127x;
1031
Eliad Pellerc8bde242011-02-02 09:59:35 +02001032 /* memory config */
Shahar Levi13b107d2011-03-06 16:32:12 +02001033 mem_conf->num_stations = mem->num_stations;
1034 mem_conf->rx_mem_block_num = mem->rx_block_num;
1035 mem_conf->tx_min_mem_block_num = mem->tx_min_block_num;
1036 mem_conf->num_ssid_profiles = mem->ssid_profiles;
Eliad Pellerc8bde242011-02-02 09:59:35 +02001037 mem_conf->total_tx_descriptors = cpu_to_le32(ACX_TX_DESCRIPTORS);
Shahar Levi13b107d2011-03-06 16:32:12 +02001038 mem_conf->dyn_mem_enable = mem->dynamic_memory;
1039 mem_conf->tx_free_req = mem->min_req_tx_blocks;
1040 mem_conf->rx_free_req = mem->min_req_rx_blocks;
1041 mem_conf->tx_min = mem->tx_min;
Ido Yariv95dac04f2011-06-06 14:57:06 +03001042 mem_conf->fwlog_blocks = wl->conf.fwlog.mem_blocks;
Eliad Pellerc8bde242011-02-02 09:59:35 +02001043
1044 ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf,
1045 sizeof(*mem_conf));
1046 if (ret < 0) {
1047 wl1271_warning("wl1271 mem config failed: %d", ret);
1048 goto out;
1049 }
1050
1051out:
1052 kfree(mem_conf);
1053 return ret;
1054}
1055
Shahar Levi48a61472011-03-06 16:32:08 +02001056int wl1271_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap)
1057{
1058 struct wl1271_acx_host_config_bitmap *bitmap_conf;
1059 int ret;
1060
1061 bitmap_conf = kzalloc(sizeof(*bitmap_conf), GFP_KERNEL);
1062 if (!bitmap_conf) {
1063 ret = -ENOMEM;
1064 goto out;
1065 }
1066
1067 bitmap_conf->host_cfg_bitmap = cpu_to_le32(host_cfg_bitmap);
1068
1069 ret = wl1271_cmd_configure(wl, ACX_HOST_IF_CFG_BITMAP,
1070 bitmap_conf, sizeof(*bitmap_conf));
1071 if (ret < 0) {
1072 wl1271_warning("wl1271 bitmap config opt failed: %d", ret);
1073 goto out;
1074 }
1075
1076out:
1077 kfree(bitmap_conf);
1078
1079 return ret;
1080}
1081
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001082int wl1271_acx_init_mem_config(struct wl1271 *wl)
1083{
1084 int ret;
1085
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001086 wl->target_mem_map = kzalloc(sizeof(struct wl1271_acx_mem_map),
Juuso Oikarinen45b531a2009-10-13 12:47:41 +03001087 GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001088 if (!wl->target_mem_map) {
1089 wl1271_error("couldn't allocate target memory map");
1090 return -ENOMEM;
1091 }
1092
1093 /* we now ask for the firmware built memory map */
1094 ret = wl1271_acx_mem_map(wl, (void *)wl->target_mem_map,
1095 sizeof(struct wl1271_acx_mem_map));
1096 if (ret < 0) {
1097 wl1271_error("couldn't retrieve firmware memory map");
1098 kfree(wl->target_mem_map);
1099 wl->target_mem_map = NULL;
1100 return ret;
1101 }
1102
1103 /* initialize TX block book keeping */
Luciano Coelhod0f63b22009-10-15 10:33:29 +03001104 wl->tx_blocks_available =
1105 le32_to_cpu(wl->target_mem_map->num_tx_mem_blocks);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001106 wl1271_debug(DEBUG_TX, "available tx blocks: %d",
1107 wl->tx_blocks_available);
1108
1109 return 0;
1110}
1111
1112int wl1271_acx_init_rx_interrupt(struct wl1271 *wl)
1113{
1114 struct wl1271_acx_rx_config_opt *rx_conf;
1115 int ret;
1116
1117 wl1271_debug(DEBUG_ACX, "wl1271 rx interrupt config");
1118
1119 rx_conf = kzalloc(sizeof(*rx_conf), GFP_KERNEL);
1120 if (!rx_conf) {
1121 ret = -ENOMEM;
1122 goto out;
1123 }
1124
Luciano Coelhod0f63b22009-10-15 10:33:29 +03001125 rx_conf->threshold = cpu_to_le16(wl->conf.rx.irq_pkt_threshold);
1126 rx_conf->timeout = cpu_to_le16(wl->conf.rx.irq_timeout);
1127 rx_conf->mblk_threshold = cpu_to_le16(wl->conf.rx.irq_blk_threshold);
Juuso Oikarinen8793f9b2009-10-13 12:47:40 +03001128 rx_conf->queue_type = wl->conf.rx.queue_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001129
1130 ret = wl1271_cmd_configure(wl, ACX_RX_CONFIG_OPT, rx_conf,
1131 sizeof(*rx_conf));
1132 if (ret < 0) {
1133 wl1271_warning("wl1271 rx config opt failed: %d", ret);
1134 goto out;
1135 }
1136
1137out:
1138 kfree(rx_conf);
1139 return ret;
1140}
Juuso Oikarinen3cfd6cf2009-10-12 15:08:52 +03001141
Juuso Oikarinen11f70f92009-10-13 12:47:46 +03001142int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable)
1143{
1144 struct wl1271_acx_bet_enable *acx = NULL;
1145 int ret = 0;
1146
1147 wl1271_debug(DEBUG_ACX, "acx bet enable");
1148
1149 if (enable && wl->conf.conn.bet_enable == CONF_BET_MODE_DISABLE)
1150 goto out;
1151
1152 acx = kzalloc(sizeof(*acx), GFP_KERNEL);
1153 if (!acx) {
1154 ret = -ENOMEM;
1155 goto out;
1156 }
1157
1158 acx->enable = enable ? CONF_BET_MODE_ENABLE : CONF_BET_MODE_DISABLE;
1159 acx->max_consecutive = wl->conf.conn.bet_max_consecutive;
1160
1161 ret = wl1271_cmd_configure(wl, ACX_BET_ENABLE, acx, sizeof(*acx));
1162 if (ret < 0) {
1163 wl1271_warning("acx bet enable failed: %d", ret);
1164 goto out;
1165 }
1166
1167out:
1168 kfree(acx);
1169 return ret;
1170}
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001171
Eliad Pellerc5312772010-12-09 11:31:27 +02001172int wl1271_acx_arp_ip_filter(struct wl1271 *wl, u8 enable, __be32 address)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001173{
1174 struct wl1271_acx_arp_filter *acx;
1175 int ret;
1176
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03001177 wl1271_debug(DEBUG_ACX, "acx arp ip filter, enable: %d", enable);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001178
1179 acx = kzalloc(sizeof(*acx), GFP_KERNEL);
1180 if (!acx) {
1181 ret = -ENOMEM;
1182 goto out;
1183 }
1184
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001185 acx->version = ACX_IPV4_VERSION;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03001186 acx->enable = enable;
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001187
Eliad Pellerc5312772010-12-09 11:31:27 +02001188 if (enable)
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03001189 memcpy(acx->address, &address, ACX_IPV4_ADDR_SIZE);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001190
1191 ret = wl1271_cmd_configure(wl, ACX_ARP_IP_FILTER,
1192 acx, sizeof(*acx));
1193 if (ret < 0) {
1194 wl1271_warning("failed to set arp ip filter: %d", ret);
1195 goto out;
1196 }
1197
1198out:
1199 kfree(acx);
1200 return ret;
1201}
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +02001202
1203int wl1271_acx_pm_config(struct wl1271 *wl)
1204{
1205 struct wl1271_acx_pm_config *acx = NULL;
1206 struct conf_pm_config_settings *c = &wl->conf.pm_config;
1207 int ret = 0;
1208
1209 wl1271_debug(DEBUG_ACX, "acx pm config");
1210
1211 acx = kzalloc(sizeof(*acx), GFP_KERNEL);
1212 if (!acx) {
1213 ret = -ENOMEM;
1214 goto out;
1215 }
1216
1217 acx->host_clk_settling_time = cpu_to_le32(c->host_clk_settling_time);
1218 acx->host_fast_wakeup_support = c->host_fast_wakeup_support;
1219
1220 ret = wl1271_cmd_configure(wl, ACX_PM_CONFIG, acx, sizeof(*acx));
1221 if (ret < 0) {
1222 wl1271_warning("acx pm config failed: %d", ret);
1223 goto out;
1224 }
1225
1226out:
1227 kfree(acx);
1228 return ret;
1229}
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001230
1231int wl1271_acx_keep_alive_mode(struct wl1271 *wl, bool enable)
1232{
1233 struct wl1271_acx_keep_alive_mode *acx = NULL;
1234 int ret = 0;
1235
1236 wl1271_debug(DEBUG_ACX, "acx keep alive mode: %d", enable);
1237
1238 acx = kzalloc(sizeof(*acx), GFP_KERNEL);
1239 if (!acx) {
1240 ret = -ENOMEM;
1241 goto out;
1242 }
1243
1244 acx->enabled = enable;
1245
1246 ret = wl1271_cmd_configure(wl, ACX_KEEP_ALIVE_MODE, acx, sizeof(*acx));
1247 if (ret < 0) {
1248 wl1271_warning("acx keep alive mode failed: %d", ret);
1249 goto out;
1250 }
1251
1252out:
1253 kfree(acx);
1254 return ret;
1255}
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03001256
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001257int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid)
1258{
1259 struct wl1271_acx_keep_alive_config *acx = NULL;
1260 int ret = 0;
1261
1262 wl1271_debug(DEBUG_ACX, "acx keep alive config");
1263
1264 acx = kzalloc(sizeof(*acx), GFP_KERNEL);
1265 if (!acx) {
1266 ret = -ENOMEM;
1267 goto out;
1268 }
1269
1270 acx->period = cpu_to_le32(wl->conf.conn.keep_alive_interval);
1271 acx->index = index;
1272 acx->tpl_validation = tpl_valid;
1273 acx->trigger = ACX_KEEP_ALIVE_NO_TX;
1274
1275 ret = wl1271_cmd_configure(wl, ACX_SET_KEEP_ALIVE_CONFIG,
1276 acx, sizeof(*acx));
1277 if (ret < 0) {
1278 wl1271_warning("acx keep alive config failed: %d", ret);
1279 goto out;
1280 }
1281
1282out:
1283 kfree(acx);
1284 return ret;
1285}
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03001286
1287int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable,
1288 s16 thold, u8 hyst)
1289{
1290 struct wl1271_acx_rssi_snr_trigger *acx = NULL;
1291 int ret = 0;
1292
1293 wl1271_debug(DEBUG_ACX, "acx rssi snr trigger");
1294
1295 acx = kzalloc(sizeof(*acx), GFP_KERNEL);
1296 if (!acx) {
1297 ret = -ENOMEM;
1298 goto out;
1299 }
1300
1301 wl->last_rssi_event = -1;
1302
1303 acx->pacing = cpu_to_le16(wl->conf.roam_trigger.trigger_pacing);
1304 acx->metric = WL1271_ACX_TRIG_METRIC_RSSI_BEACON;
1305 acx->type = WL1271_ACX_TRIG_TYPE_EDGE;
1306 if (enable)
1307 acx->enable = WL1271_ACX_TRIG_ENABLE;
1308 else
1309 acx->enable = WL1271_ACX_TRIG_DISABLE;
1310
1311 acx->index = WL1271_ACX_TRIG_IDX_RSSI;
1312 acx->dir = WL1271_ACX_TRIG_DIR_BIDIR;
1313 acx->threshold = cpu_to_le16(thold);
1314 acx->hysteresis = hyst;
1315
1316 ret = wl1271_cmd_configure(wl, ACX_RSSI_SNR_TRIGGER, acx, sizeof(*acx));
1317 if (ret < 0) {
1318 wl1271_warning("acx rssi snr trigger setting failed: %d", ret);
1319 goto out;
1320 }
1321
1322out:
1323 kfree(acx);
1324 return ret;
1325}
1326
1327int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl)
1328{
1329 struct wl1271_acx_rssi_snr_avg_weights *acx = NULL;
1330 struct conf_roam_trigger_settings *c = &wl->conf.roam_trigger;
1331 int ret = 0;
1332
1333 wl1271_debug(DEBUG_ACX, "acx rssi snr avg weights");
1334
1335 acx = kzalloc(sizeof(*acx), GFP_KERNEL);
1336 if (!acx) {
1337 ret = -ENOMEM;
1338 goto out;
1339 }
1340
1341 acx->rssi_beacon = c->avg_weight_rssi_beacon;
1342 acx->rssi_data = c->avg_weight_rssi_data;
1343 acx->snr_beacon = c->avg_weight_snr_beacon;
1344 acx->snr_data = c->avg_weight_snr_data;
1345
1346 ret = wl1271_cmd_configure(wl, ACX_RSSI_SNR_WEIGHTS, acx, sizeof(*acx));
1347 if (ret < 0) {
1348 wl1271_warning("acx rssi snr trigger weights failed: %d", ret);
1349 goto out;
1350 }
1351
1352out:
1353 kfree(acx);
1354 return ret;
1355}
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03001356
Shahar Levic4db1c82010-10-13 16:09:40 +02001357int wl1271_acx_set_ht_capabilities(struct wl1271 *wl,
1358 struct ieee80211_sta_ht_cap *ht_cap,
1359 bool allow_ht_operation)
1360{
1361 struct wl1271_acx_ht_capabilities *acx;
1362 u8 mac_address[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
1363 int ret = 0;
Eliad Peller6177eae2010-12-22 12:38:52 +01001364 u32 ht_capabilites = 0;
Shahar Levic4db1c82010-10-13 16:09:40 +02001365
1366 wl1271_debug(DEBUG_ACX, "acx ht capabilities setting");
1367
1368 acx = kzalloc(sizeof(*acx), GFP_KERNEL);
1369 if (!acx) {
1370 ret = -ENOMEM;
1371 goto out;
1372 }
1373
1374 /* Allow HT Operation ? */
1375 if (allow_ht_operation) {
Eliad Peller6177eae2010-12-22 12:38:52 +01001376 ht_capabilites =
Shahar Levic4db1c82010-10-13 16:09:40 +02001377 WL1271_ACX_FW_CAP_HT_OPERATION;
1378 if (ht_cap->cap & IEEE80211_HT_CAP_GRN_FLD)
Eliad Peller6177eae2010-12-22 12:38:52 +01001379 ht_capabilites |=
Shahar Levic4db1c82010-10-13 16:09:40 +02001380 WL1271_ACX_FW_CAP_GREENFIELD_FRAME_FORMAT;
1381 if (ht_cap->cap & IEEE80211_HT_CAP_SGI_20)
Eliad Peller6177eae2010-12-22 12:38:52 +01001382 ht_capabilites |=
Shahar Levic4db1c82010-10-13 16:09:40 +02001383 WL1271_ACX_FW_CAP_SHORT_GI_FOR_20MHZ_PACKETS;
1384 if (ht_cap->cap & IEEE80211_HT_CAP_LSIG_TXOP_PROT)
Eliad Peller6177eae2010-12-22 12:38:52 +01001385 ht_capabilites |=
Shahar Levic4db1c82010-10-13 16:09:40 +02001386 WL1271_ACX_FW_CAP_LSIG_TXOP_PROTECTION;
1387
1388 /* get data from A-MPDU parameters field */
1389 acx->ampdu_max_length = ht_cap->ampdu_factor;
1390 acx->ampdu_min_spacing = ht_cap->ampdu_density;
Shahar Levic4db1c82010-10-13 16:09:40 +02001391 }
1392
Eliad Peller6dc9fb32011-02-23 00:27:07 +02001393 memcpy(acx->mac_address, mac_address, ETH_ALEN);
Eliad Peller6177eae2010-12-22 12:38:52 +01001394 acx->ht_capabilites = cpu_to_le32(ht_capabilites);
1395
Shahar Levic4db1c82010-10-13 16:09:40 +02001396 ret = wl1271_cmd_configure(wl, ACX_PEER_HT_CAP, acx, sizeof(*acx));
1397 if (ret < 0) {
1398 wl1271_warning("acx ht capabilities setting failed: %d", ret);
1399 goto out;
1400 }
1401
1402out:
1403 kfree(acx);
1404 return ret;
1405}
1406
1407int wl1271_acx_set_ht_information(struct wl1271 *wl,
1408 u16 ht_operation_mode)
1409{
1410 struct wl1271_acx_ht_information *acx;
1411 int ret = 0;
1412
1413 wl1271_debug(DEBUG_ACX, "acx ht information setting");
1414
1415 acx = kzalloc(sizeof(*acx), GFP_KERNEL);
1416 if (!acx) {
1417 ret = -ENOMEM;
1418 goto out;
1419 }
1420
1421 acx->ht_protection =
1422 (u8)(ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION);
1423 acx->rifs_mode = 0;
Helmut Schaa95a77612011-03-02 10:46:46 +01001424 acx->gf_protection =
1425 !!(ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
Shahar Levic4db1c82010-10-13 16:09:40 +02001426 acx->ht_tx_burst_limit = 0;
1427 acx->dual_cts_protection = 0;
1428
1429 ret = wl1271_cmd_configure(wl, ACX_HT_BSS_OPERATION, acx, sizeof(*acx));
1430
1431 if (ret < 0) {
1432 wl1271_warning("acx ht information setting failed: %d", ret);
1433 goto out;
1434 }
1435
1436out:
1437 kfree(acx);
1438 return ret;
1439}
1440
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001441/* Configure BA session initiator/receiver parameters setting in the FW. */
1442int wl1271_acx_set_ba_session(struct wl1271 *wl,
1443 enum ieee80211_back_parties direction,
1444 u8 tid_index, u8 policy)
1445{
1446 struct wl1271_acx_ba_session_policy *acx;
1447 int ret;
1448
1449 wl1271_debug(DEBUG_ACX, "acx ba session setting");
1450
1451 acx = kzalloc(sizeof(*acx), GFP_KERNEL);
1452 if (!acx) {
1453 ret = -ENOMEM;
1454 goto out;
1455 }
1456
1457 /* ANY role */
1458 acx->role_id = 0xff;
1459 acx->tid = tid_index;
1460 acx->enable = policy;
1461 acx->ba_direction = direction;
1462
1463 switch (direction) {
1464 case WLAN_BACK_INITIATOR:
1465 acx->win_size = wl->conf.ht.tx_ba_win_size;
1466 acx->inactivity_timeout = wl->conf.ht.inactivity_timeout;
1467 break;
1468 case WLAN_BACK_RECIPIENT:
1469 acx->win_size = RX_BA_WIN_SIZE;
1470 acx->inactivity_timeout = 0;
1471 break;
1472 default:
1473 wl1271_error("Incorrect acx command id=%x\n", direction);
1474 ret = -EINVAL;
1475 goto out;
1476 }
1477
1478 ret = wl1271_cmd_configure(wl,
1479 ACX_BA_SESSION_POLICY_CFG,
1480 acx,
1481 sizeof(*acx));
1482 if (ret < 0) {
1483 wl1271_warning("acx ba session setting failed: %d", ret);
1484 goto out;
1485 }
1486
1487out:
1488 kfree(acx);
1489 return ret;
1490}
1491
Levi, Shaharbbba3e62011-01-23 07:27:23 +01001492/* setup BA session receiver setting in the FW. */
1493int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn,
1494 bool enable)
1495{
1496 struct wl1271_acx_ba_receiver_setup *acx;
1497 int ret;
1498
1499 wl1271_debug(DEBUG_ACX, "acx ba receiver session setting");
1500
1501 acx = kzalloc(sizeof(*acx), GFP_KERNEL);
1502 if (!acx) {
1503 ret = -ENOMEM;
1504 goto out;
1505 }
1506
1507 /* Single link for now */
1508 acx->link_id = 1;
1509 acx->tid = tid_index;
1510 acx->enable = enable;
1511 acx->win_size = 0;
1512 acx->ssn = ssn;
1513
1514 ret = wl1271_cmd_configure(wl, ACX_BA_SESSION_RX_SETUP, acx,
1515 sizeof(*acx));
1516 if (ret < 0) {
1517 wl1271_warning("acx ba receiver session failed: %d", ret);
1518 goto out;
1519 }
1520
1521out:
1522 kfree(acx);
1523 return ret;
1524}
1525
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03001526int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime)
1527{
1528 struct wl1271_acx_fw_tsf_information *tsf_info;
1529 int ret;
1530
1531 tsf_info = kzalloc(sizeof(*tsf_info), GFP_KERNEL);
1532 if (!tsf_info) {
1533 ret = -ENOMEM;
1534 goto out;
1535 }
1536
1537 ret = wl1271_cmd_interrogate(wl, ACX_TSF_INFO,
1538 tsf_info, sizeof(*tsf_info));
1539 if (ret < 0) {
1540 wl1271_warning("acx tsf info interrogate failed");
1541 goto out;
1542 }
1543
1544 *mactime = le32_to_cpu(tsf_info->current_tsf_low) |
1545 ((u64) le32_to_cpu(tsf_info->current_tsf_high) << 32);
1546
1547out:
1548 kfree(tsf_info);
1549 return ret;
1550}
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001551
Eliad Pellerf84673d2011-05-15 11:10:28 +03001552int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, bool enable)
1553{
1554 struct wl1271_acx_ps_rx_streaming *rx_streaming;
1555 u32 conf_queues, enable_queues;
1556 int i, ret = 0;
1557
1558 wl1271_debug(DEBUG_ACX, "acx ps rx streaming");
1559
1560 rx_streaming = kzalloc(sizeof(*rx_streaming), GFP_KERNEL);
1561 if (!rx_streaming) {
1562 ret = -ENOMEM;
1563 goto out;
1564 }
1565
1566 conf_queues = wl->conf.rx_streaming.queues;
1567 if (enable)
1568 enable_queues = conf_queues;
1569 else
1570 enable_queues = 0;
1571
1572 for (i = 0; i < 8; i++) {
1573 /*
1574 * Skip non-changed queues, to avoid redundant acxs.
1575 * this check assumes conf.rx_streaming.queues can't
1576 * be changed while rx_streaming is enabled.
1577 */
1578 if (!(conf_queues & BIT(i)))
1579 continue;
1580
1581 rx_streaming->tid = i;
1582 rx_streaming->enable = enable_queues & BIT(i);
1583 rx_streaming->period = wl->conf.rx_streaming.interval;
1584 rx_streaming->timeout = wl->conf.rx_streaming.interval;
1585
1586 ret = wl1271_cmd_configure(wl, ACX_PS_RX_STREAMING,
1587 rx_streaming,
1588 sizeof(*rx_streaming));
1589 if (ret < 0) {
1590 wl1271_warning("acx ps rx streaming failed: %d", ret);
1591 goto out;
1592 }
1593 }
1594out:
1595 kfree(rx_streaming);
1596 return ret;
1597}
1598
Arik Nemtsov3618f302011-06-26 10:36:03 +03001599int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl)
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001600{
Arik Nemtsov3618f302011-06-26 10:36:03 +03001601 struct wl1271_acx_ap_max_tx_retry *acx = NULL;
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001602 int ret;
1603
Arik Nemtsov3618f302011-06-26 10:36:03 +03001604 wl1271_debug(DEBUG_ACX, "acx ap max tx retry");
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001605
1606 acx = kzalloc(sizeof(*acx), GFP_KERNEL);
1607 if (!acx)
1608 return -ENOMEM;
1609
Arik Nemtsov3618f302011-06-26 10:36:03 +03001610 acx->max_tx_retry = cpu_to_le16(wl->conf.tx.max_tx_retries);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001611
1612 ret = wl1271_cmd_configure(wl, ACX_MAX_TX_FAILURE, acx, sizeof(*acx));
1613 if (ret < 0) {
Arik Nemtsov3618f302011-06-26 10:36:03 +03001614 wl1271_warning("acx ap max tx retry failed: %d", ret);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001615 goto out;
1616 }
1617
1618out:
1619 kfree(acx);
1620 return ret;
1621}
Eliad Pelleree608332011-02-02 09:59:34 +02001622
1623int wl1271_acx_config_ps(struct wl1271 *wl)
1624{
1625 struct wl1271_acx_config_ps *config_ps;
1626 int ret;
1627
1628 wl1271_debug(DEBUG_ACX, "acx config ps");
1629
1630 config_ps = kzalloc(sizeof(*config_ps), GFP_KERNEL);
1631 if (!config_ps) {
1632 ret = -ENOMEM;
1633 goto out;
1634 }
1635
1636 config_ps->exit_retries = wl->conf.conn.psm_exit_retries;
1637 config_ps->enter_retries = wl->conf.conn.psm_entry_retries;
1638 config_ps->null_data_rate = cpu_to_le32(wl->basic_rate);
1639
1640 ret = wl1271_cmd_configure(wl, ACX_CONFIG_PS, config_ps,
1641 sizeof(*config_ps));
1642
1643 if (ret < 0) {
1644 wl1271_warning("acx config ps failed: %d", ret);
1645 goto out;
1646 }
1647
1648out:
1649 kfree(config_ps);
1650 return ret;
1651}
Arik Nemtsov99a27752011-02-23 00:22:25 +02001652
1653int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr)
1654{
1655 struct wl1271_acx_inconnection_sta *acx = NULL;
1656 int ret;
1657
1658 wl1271_debug(DEBUG_ACX, "acx set inconnaction sta %pM", addr);
1659
1660 acx = kzalloc(sizeof(*acx), GFP_KERNEL);
1661 if (!acx)
1662 return -ENOMEM;
1663
1664 memcpy(acx->addr, addr, ETH_ALEN);
1665
1666 ret = wl1271_cmd_configure(wl, ACX_UPDATE_INCONNECTION_STA_LIST,
1667 acx, sizeof(*acx));
1668 if (ret < 0) {
1669 wl1271_warning("acx set inconnaction sta failed: %d", ret);
1670 goto out;
1671 }
1672
1673out:
1674 kfree(acx);
1675 return ret;
1676}
Shahar Leviff868432011-04-11 15:41:46 +03001677
Arik Nemtsov521a4a22011-04-18 14:15:22 +03001678int wl1271_acx_set_ap_beacon_filter(struct wl1271 *wl, bool enable)
1679{
1680 struct acx_ap_beacon_filter *acx = NULL;
1681 int ret;
1682
1683 wl1271_debug(DEBUG_ACX, "acx set ap beacon filter: %d", enable);
1684
1685 acx = kzalloc(sizeof(*acx), GFP_KERNEL);
1686 if (!acx)
1687 return -ENOMEM;
1688
1689 acx->enable = enable ? 1 : 0;
1690
1691 ret = wl1271_cmd_configure(wl, ACX_AP_BEACON_FILTER_OPT,
1692 acx, sizeof(*acx));
1693 if (ret < 0) {
1694 wl1271_warning("acx set ap beacon filter failed: %d", ret);
1695 goto out;
1696 }
1697
1698out:
1699 kfree(acx);
1700 return ret;
1701}
1702
Shahar Leviff868432011-04-11 15:41:46 +03001703int wl1271_acx_fm_coex(struct wl1271 *wl)
1704{
1705 struct wl1271_acx_fm_coex *acx;
1706 int ret;
1707
1708 wl1271_debug(DEBUG_ACX, "acx fm coex setting");
1709
1710 acx = kzalloc(sizeof(*acx), GFP_KERNEL);
1711 if (!acx) {
1712 ret = -ENOMEM;
1713 goto out;
1714 }
1715
1716 acx->enable = wl->conf.fm_coex.enable;
1717 acx->swallow_period = wl->conf.fm_coex.swallow_period;
1718 acx->n_divider_fref_set_1 = wl->conf.fm_coex.n_divider_fref_set_1;
1719 acx->n_divider_fref_set_2 = wl->conf.fm_coex.n_divider_fref_set_2;
1720 acx->m_divider_fref_set_1 =
1721 cpu_to_le16(wl->conf.fm_coex.m_divider_fref_set_1);
1722 acx->m_divider_fref_set_2 =
1723 cpu_to_le16(wl->conf.fm_coex.m_divider_fref_set_2);
1724 acx->coex_pll_stabilization_time =
1725 cpu_to_le32(wl->conf.fm_coex.coex_pll_stabilization_time);
1726 acx->ldo_stabilization_time =
1727 cpu_to_le16(wl->conf.fm_coex.ldo_stabilization_time);
1728 acx->fm_disturbed_band_margin =
1729 wl->conf.fm_coex.fm_disturbed_band_margin;
1730 acx->swallow_clk_diff = wl->conf.fm_coex.swallow_clk_diff;
1731
1732 ret = wl1271_cmd_configure(wl, ACX_FM_COEX_CFG, acx, sizeof(*acx));
1733 if (ret < 0) {
1734 wl1271_warning("acx fm coex setting failed: %d", ret);
1735 goto out;
1736 }
1737
1738out:
1739 kfree(acx);
1740 return ret;
1741}