1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * This file is part of wl1271 |
4 | * |
5 | * Copyright (C) 2008-2009 Nokia Corporation |
6 | * |
7 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> |
8 | */ |
9 | |
10 | #include "acx.h" |
11 | |
12 | #include <linux/module.h> |
13 | #include <linux/platform_device.h> |
14 | #include <linux/spi/spi.h> |
15 | #include <linux/slab.h> |
16 | |
17 | #include "wlcore.h" |
18 | #include "debug.h" |
19 | #include "wl12xx_80211.h" |
20 | #include "hw_ops.h" |
21 | |
22 | int wl1271_acx_wake_up_conditions(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
23 | u8 wake_up_event, u8 listen_interval) |
24 | { |
25 | struct acx_wake_up_condition *wake_up; |
26 | int ret; |
27 | |
28 | wl1271_debug(DEBUG_ACX, "acx wake up conditions (wake_up_event %d listen_interval %d)" , |
29 | wake_up_event, listen_interval); |
30 | |
31 | wake_up = kzalloc(size: sizeof(*wake_up), GFP_KERNEL); |
32 | if (!wake_up) { |
33 | ret = -ENOMEM; |
34 | goto out; |
35 | } |
36 | |
37 | wake_up->role_id = wlvif->role_id; |
38 | wake_up->wake_up_event = wake_up_event; |
39 | wake_up->listen_interval = listen_interval; |
40 | |
41 | ret = wl1271_cmd_configure(wl, id: ACX_WAKE_UP_CONDITIONS, |
42 | buf: wake_up, len: sizeof(*wake_up)); |
43 | if (ret < 0) { |
44 | wl1271_warning("could not set wake up conditions: %d" , ret); |
45 | goto out; |
46 | } |
47 | |
48 | out: |
49 | kfree(objp: wake_up); |
50 | return ret; |
51 | } |
52 | |
53 | int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth) |
54 | { |
55 | struct acx_sleep_auth *auth; |
56 | int ret; |
57 | |
58 | wl1271_debug(DEBUG_ACX, "acx sleep auth %d" , sleep_auth); |
59 | |
60 | auth = kzalloc(size: sizeof(*auth), GFP_KERNEL); |
61 | if (!auth) { |
62 | ret = -ENOMEM; |
63 | goto out; |
64 | } |
65 | |
66 | auth->sleep_auth = sleep_auth; |
67 | |
68 | ret = wl1271_cmd_configure(wl, id: ACX_SLEEP_AUTH, buf: auth, len: sizeof(*auth)); |
69 | if (ret < 0) { |
70 | wl1271_error("could not configure sleep_auth to %d: %d" , |
71 | sleep_auth, ret); |
72 | goto out; |
73 | } |
74 | |
75 | wl->sleep_auth = sleep_auth; |
76 | out: |
77 | kfree(objp: auth); |
78 | return ret; |
79 | } |
80 | EXPORT_SYMBOL_GPL(wl1271_acx_sleep_auth); |
81 | |
82 | int wl1271_acx_tx_power(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
83 | int power) |
84 | { |
85 | struct acx_current_tx_power *acx; |
86 | int ret; |
87 | |
88 | wl1271_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr %d" , power); |
89 | |
90 | if (power < 0 || power > 25) |
91 | return -EINVAL; |
92 | |
93 | acx = kzalloc(size: sizeof(*acx), GFP_KERNEL); |
94 | if (!acx) { |
95 | ret = -ENOMEM; |
96 | goto out; |
97 | } |
98 | |
99 | acx->role_id = wlvif->role_id; |
100 | acx->current_tx_power = power * 10; |
101 | |
102 | ret = wl1271_cmd_configure(wl, id: DOT11_CUR_TX_PWR, buf: acx, len: sizeof(*acx)); |
103 | if (ret < 0) { |
104 | wl1271_warning("configure of tx power failed: %d" , ret); |
105 | goto out; |
106 | } |
107 | |
108 | out: |
109 | kfree(objp: acx); |
110 | return ret; |
111 | } |
112 | |
113 | int wl1271_acx_feature_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif) |
114 | { |
115 | struct acx_feature_config *feature; |
116 | int ret; |
117 | |
118 | wl1271_debug(DEBUG_ACX, "acx feature cfg" ); |
119 | |
120 | feature = kzalloc(size: sizeof(*feature), GFP_KERNEL); |
121 | if (!feature) { |
122 | ret = -ENOMEM; |
123 | goto out; |
124 | } |
125 | |
126 | /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */ |
127 | feature->role_id = wlvif->role_id; |
128 | feature->data_flow_options = 0; |
129 | feature->options = 0; |
130 | |
131 | ret = wl1271_cmd_configure(wl, id: ACX_FEATURE_CFG, |
132 | buf: feature, len: sizeof(*feature)); |
133 | if (ret < 0) { |
134 | wl1271_error("Couldn't set HW encryption" ); |
135 | goto out; |
136 | } |
137 | |
138 | out: |
139 | kfree(objp: feature); |
140 | return ret; |
141 | } |
142 | |
143 | int wl1271_acx_mem_map(struct wl1271 *wl, struct acx_header *mem_map, |
144 | size_t len) |
145 | { |
146 | int ret; |
147 | |
148 | wl1271_debug(DEBUG_ACX, "acx mem map" ); |
149 | |
150 | ret = wl1271_cmd_interrogate(wl, id: ACX_MEM_MAP, buf: mem_map, |
151 | cmd_len: sizeof(struct acx_header), res_len: len); |
152 | if (ret < 0) |
153 | return ret; |
154 | |
155 | return 0; |
156 | } |
157 | |
158 | int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl) |
159 | { |
160 | struct acx_rx_msdu_lifetime *acx; |
161 | int ret; |
162 | |
163 | wl1271_debug(DEBUG_ACX, "acx rx msdu life time" ); |
164 | |
165 | acx = kzalloc(size: sizeof(*acx), GFP_KERNEL); |
166 | if (!acx) { |
167 | ret = -ENOMEM; |
168 | goto out; |
169 | } |
170 | |
171 | acx->lifetime = cpu_to_le32(wl->conf.rx.rx_msdu_life_time); |
172 | ret = wl1271_cmd_configure(wl, id: DOT11_RX_MSDU_LIFE_TIME, |
173 | buf: acx, len: sizeof(*acx)); |
174 | if (ret < 0) { |
175 | wl1271_warning("failed to set rx msdu life time: %d" , ret); |
176 | goto out; |
177 | } |
178 | |
179 | out: |
180 | kfree(objp: acx); |
181 | return ret; |
182 | } |
183 | |
184 | int wl1271_acx_slot(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
185 | enum acx_slot_type slot_time) |
186 | { |
187 | struct acx_slot *slot; |
188 | int ret; |
189 | |
190 | wl1271_debug(DEBUG_ACX, "acx slot" ); |
191 | |
192 | slot = kzalloc(size: sizeof(*slot), GFP_KERNEL); |
193 | if (!slot) { |
194 | ret = -ENOMEM; |
195 | goto out; |
196 | } |
197 | |
198 | slot->role_id = wlvif->role_id; |
199 | slot->wone_index = STATION_WONE_INDEX; |
200 | slot->slot_time = slot_time; |
201 | |
202 | ret = wl1271_cmd_configure(wl, id: ACX_SLOT, buf: slot, len: sizeof(*slot)); |
203 | if (ret < 0) { |
204 | wl1271_warning("failed to set slot time: %d" , ret); |
205 | goto out; |
206 | } |
207 | |
208 | out: |
209 | kfree(objp: slot); |
210 | return ret; |
211 | } |
212 | |
213 | int wl1271_acx_group_address_tbl(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
214 | bool enable, void *mc_list, u32 mc_list_len) |
215 | { |
216 | struct acx_dot11_grp_addr_tbl *acx; |
217 | int ret; |
218 | |
219 | wl1271_debug(DEBUG_ACX, "acx group address tbl" ); |
220 | |
221 | acx = kzalloc(size: sizeof(*acx), GFP_KERNEL); |
222 | if (!acx) { |
223 | ret = -ENOMEM; |
224 | goto out; |
225 | } |
226 | |
227 | /* MAC filtering */ |
228 | acx->role_id = wlvif->role_id; |
229 | acx->enabled = enable; |
230 | acx->num_groups = mc_list_len; |
231 | memcpy(acx->mac_table, mc_list, mc_list_len * ETH_ALEN); |
232 | |
233 | ret = wl1271_cmd_configure(wl, id: DOT11_GROUP_ADDRESS_TBL, |
234 | buf: acx, len: sizeof(*acx)); |
235 | if (ret < 0) { |
236 | wl1271_warning("failed to set group addr table: %d" , ret); |
237 | goto out; |
238 | } |
239 | |
240 | out: |
241 | kfree(objp: acx); |
242 | return ret; |
243 | } |
244 | |
245 | int wl1271_acx_service_period_timeout(struct wl1271 *wl, |
246 | struct wl12xx_vif *wlvif) |
247 | { |
248 | struct acx_rx_timeout *rx_timeout; |
249 | int ret; |
250 | |
251 | rx_timeout = kzalloc(size: sizeof(*rx_timeout), GFP_KERNEL); |
252 | if (!rx_timeout) { |
253 | ret = -ENOMEM; |
254 | goto out; |
255 | } |
256 | |
257 | wl1271_debug(DEBUG_ACX, "acx service period timeout" ); |
258 | |
259 | rx_timeout->role_id = wlvif->role_id; |
260 | rx_timeout->ps_poll_timeout = cpu_to_le16(wl->conf.rx.ps_poll_timeout); |
261 | rx_timeout->upsd_timeout = cpu_to_le16(wl->conf.rx.upsd_timeout); |
262 | |
263 | ret = wl1271_cmd_configure(wl, id: ACX_SERVICE_PERIOD_TIMEOUT, |
264 | buf: rx_timeout, len: sizeof(*rx_timeout)); |
265 | if (ret < 0) { |
266 | wl1271_warning("failed to set service period timeout: %d" , |
267 | ret); |
268 | goto out; |
269 | } |
270 | |
271 | out: |
272 | kfree(objp: rx_timeout); |
273 | return ret; |
274 | } |
275 | |
276 | int wl1271_acx_rts_threshold(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
277 | u32 rts_threshold) |
278 | { |
279 | struct acx_rts_threshold *rts; |
280 | int ret; |
281 | |
282 | /* |
283 | * If the RTS threshold is not configured or out of range, use the |
284 | * default value. |
285 | */ |
286 | if (rts_threshold > IEEE80211_MAX_RTS_THRESHOLD) |
287 | rts_threshold = wl->conf.rx.rts_threshold; |
288 | |
289 | wl1271_debug(DEBUG_ACX, "acx rts threshold: %d" , rts_threshold); |
290 | |
291 | rts = kzalloc(size: sizeof(*rts), GFP_KERNEL); |
292 | if (!rts) { |
293 | ret = -ENOMEM; |
294 | goto out; |
295 | } |
296 | |
297 | rts->role_id = wlvif->role_id; |
298 | rts->threshold = cpu_to_le16((u16)rts_threshold); |
299 | |
300 | ret = wl1271_cmd_configure(wl, id: DOT11_RTS_THRESHOLD, buf: rts, len: sizeof(*rts)); |
301 | if (ret < 0) { |
302 | wl1271_warning("failed to set rts threshold: %d" , ret); |
303 | goto out; |
304 | } |
305 | |
306 | out: |
307 | kfree(objp: rts); |
308 | return ret; |
309 | } |
310 | |
311 | int wl1271_acx_dco_itrim_params(struct wl1271 *wl) |
312 | { |
313 | struct acx_dco_itrim_params *dco; |
314 | struct conf_itrim_settings *c = &wl->conf.itrim; |
315 | int ret; |
316 | |
317 | wl1271_debug(DEBUG_ACX, "acx dco itrim parameters" ); |
318 | |
319 | dco = kzalloc(size: sizeof(*dco), GFP_KERNEL); |
320 | if (!dco) { |
321 | ret = -ENOMEM; |
322 | goto out; |
323 | } |
324 | |
325 | dco->enable = c->enable; |
326 | dco->timeout = cpu_to_le32(c->timeout); |
327 | |
328 | ret = wl1271_cmd_configure(wl, id: ACX_SET_DCO_ITRIM_PARAMS, |
329 | buf: dco, len: sizeof(*dco)); |
330 | if (ret < 0) { |
331 | wl1271_warning("failed to set dco itrim parameters: %d" , ret); |
332 | goto out; |
333 | } |
334 | |
335 | out: |
336 | kfree(objp: dco); |
337 | return ret; |
338 | } |
339 | |
340 | int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
341 | bool enable_filter) |
342 | { |
343 | struct acx_beacon_filter_option *beacon_filter = NULL; |
344 | int ret = 0; |
345 | |
346 | wl1271_debug(DEBUG_ACX, "acx beacon filter opt enable=%d" , |
347 | enable_filter); |
348 | |
349 | if (enable_filter && |
350 | wl->conf.conn.bcn_filt_mode == CONF_BCN_FILT_MODE_DISABLED) |
351 | goto out; |
352 | |
353 | beacon_filter = kzalloc(size: sizeof(*beacon_filter), GFP_KERNEL); |
354 | if (!beacon_filter) { |
355 | ret = -ENOMEM; |
356 | goto out; |
357 | } |
358 | |
359 | beacon_filter->role_id = wlvif->role_id; |
360 | beacon_filter->enable = enable_filter; |
361 | |
362 | /* |
363 | * When set to zero, and the filter is enabled, beacons |
364 | * without the unicast TIM bit set are dropped. |
365 | */ |
366 | beacon_filter->max_num_beacons = 0; |
367 | |
368 | ret = wl1271_cmd_configure(wl, id: ACX_BEACON_FILTER_OPT, |
369 | buf: beacon_filter, len: sizeof(*beacon_filter)); |
370 | if (ret < 0) { |
371 | wl1271_warning("failed to set beacon filter opt: %d" , ret); |
372 | goto out; |
373 | } |
374 | |
375 | out: |
376 | kfree(objp: beacon_filter); |
377 | return ret; |
378 | } |
379 | |
380 | int wl1271_acx_beacon_filter_table(struct wl1271 *wl, |
381 | struct wl12xx_vif *wlvif) |
382 | { |
383 | struct acx_beacon_filter_ie_table *ie_table; |
384 | int i, idx = 0; |
385 | int ret; |
386 | bool vendor_spec = false; |
387 | |
388 | wl1271_debug(DEBUG_ACX, "acx beacon filter table" ); |
389 | |
390 | ie_table = kzalloc(size: sizeof(*ie_table), GFP_KERNEL); |
391 | if (!ie_table) { |
392 | ret = -ENOMEM; |
393 | goto out; |
394 | } |
395 | |
396 | /* configure default beacon pass-through rules */ |
397 | ie_table->role_id = wlvif->role_id; |
398 | ie_table->num_ie = 0; |
399 | for (i = 0; i < wl->conf.conn.bcn_filt_ie_count; i++) { |
400 | struct conf_bcn_filt_rule *r = &(wl->conf.conn.bcn_filt_ie[i]); |
401 | ie_table->table[idx++] = r->ie; |
402 | ie_table->table[idx++] = r->rule; |
403 | |
404 | if (r->ie == WLAN_EID_VENDOR_SPECIFIC) { |
405 | /* only one vendor specific ie allowed */ |
406 | if (vendor_spec) |
407 | continue; |
408 | |
409 | /* for vendor specific rules configure the |
410 | additional fields */ |
411 | memcpy(&(ie_table->table[idx]), r->oui, |
412 | CONF_BCN_IE_OUI_LEN); |
413 | idx += CONF_BCN_IE_OUI_LEN; |
414 | ie_table->table[idx++] = r->type; |
415 | memcpy(&(ie_table->table[idx]), r->version, |
416 | CONF_BCN_IE_VER_LEN); |
417 | idx += CONF_BCN_IE_VER_LEN; |
418 | vendor_spec = true; |
419 | } |
420 | |
421 | ie_table->num_ie++; |
422 | } |
423 | |
424 | ret = wl1271_cmd_configure(wl, id: ACX_BEACON_FILTER_TABLE, |
425 | buf: ie_table, len: sizeof(*ie_table)); |
426 | if (ret < 0) { |
427 | wl1271_warning("failed to set beacon filter table: %d" , ret); |
428 | goto out; |
429 | } |
430 | |
431 | out: |
432 | kfree(objp: ie_table); |
433 | return ret; |
434 | } |
435 | |
436 | #define ACX_CONN_MONIT_DISABLE_VALUE 0xffffffff |
437 | |
438 | int wl1271_acx_conn_monit_params(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
439 | bool enable) |
440 | { |
441 | struct acx_conn_monit_params *acx; |
442 | u32 threshold = ACX_CONN_MONIT_DISABLE_VALUE; |
443 | u32 timeout = ACX_CONN_MONIT_DISABLE_VALUE; |
444 | int ret; |
445 | |
446 | wl1271_debug(DEBUG_ACX, "acx connection monitor parameters: %s" , |
447 | enable ? "enabled" : "disabled" ); |
448 | |
449 | acx = kzalloc(size: sizeof(*acx), GFP_KERNEL); |
450 | if (!acx) { |
451 | ret = -ENOMEM; |
452 | goto out; |
453 | } |
454 | |
455 | if (enable) { |
456 | threshold = wl->conf.conn.synch_fail_thold; |
457 | timeout = wl->conf.conn.bss_lose_timeout; |
458 | } |
459 | |
460 | acx->role_id = wlvif->role_id; |
461 | acx->synch_fail_thold = cpu_to_le32(threshold); |
462 | acx->bss_lose_timeout = cpu_to_le32(timeout); |
463 | |
464 | ret = wl1271_cmd_configure(wl, id: ACX_CONN_MONIT_PARAMS, |
465 | buf: acx, len: sizeof(*acx)); |
466 | if (ret < 0) { |
467 | wl1271_warning("failed to set connection monitor " |
468 | "parameters: %d" , ret); |
469 | goto out; |
470 | } |
471 | |
472 | out: |
473 | kfree(objp: acx); |
474 | return ret; |
475 | } |
476 | |
477 | |
478 | int wl1271_acx_sg_enable(struct wl1271 *wl, bool enable) |
479 | { |
480 | struct acx_bt_wlan_coex *pta; |
481 | int ret; |
482 | |
483 | wl1271_debug(DEBUG_ACX, "acx sg enable" ); |
484 | |
485 | pta = kzalloc(size: sizeof(*pta), GFP_KERNEL); |
486 | if (!pta) { |
487 | ret = -ENOMEM; |
488 | goto out; |
489 | } |
490 | |
491 | if (enable) |
492 | pta->enable = wl->conf.sg.state; |
493 | else |
494 | pta->enable = CONF_SG_DISABLE; |
495 | |
496 | ret = wl1271_cmd_configure(wl, id: ACX_SG_ENABLE, buf: pta, len: sizeof(*pta)); |
497 | if (ret < 0) { |
498 | wl1271_warning("failed to set softgemini enable: %d" , ret); |
499 | goto out; |
500 | } |
501 | |
502 | out: |
503 | kfree(objp: pta); |
504 | return ret; |
505 | } |
506 | |
507 | int wl12xx_acx_sg_cfg(struct wl1271 *wl) |
508 | { |
509 | struct acx_bt_wlan_coex_param *param; |
510 | struct conf_sg_settings *c = &wl->conf.sg; |
511 | int i, ret; |
512 | |
513 | wl1271_debug(DEBUG_ACX, "acx sg cfg" ); |
514 | |
515 | param = kzalloc(size: sizeof(*param), GFP_KERNEL); |
516 | if (!param) { |
517 | ret = -ENOMEM; |
518 | goto out; |
519 | } |
520 | |
521 | /* BT-WLAN coext parameters */ |
522 | for (i = 0; i < WLCORE_CONF_SG_PARAMS_MAX; i++) |
523 | param->params[i] = cpu_to_le32(c->params[i]); |
524 | param->param_idx = WLCORE_CONF_SG_PARAMS_ALL; |
525 | |
526 | ret = wl1271_cmd_configure(wl, id: ACX_SG_CFG, buf: param, len: sizeof(*param)); |
527 | if (ret < 0) { |
528 | wl1271_warning("failed to set sg config: %d" , ret); |
529 | goto out; |
530 | } |
531 | |
532 | out: |
533 | kfree(objp: param); |
534 | return ret; |
535 | } |
536 | |
537 | int wl1271_acx_cca_threshold(struct wl1271 *wl) |
538 | { |
539 | struct acx_energy_detection *detection; |
540 | int ret; |
541 | |
542 | wl1271_debug(DEBUG_ACX, "acx cca threshold" ); |
543 | |
544 | detection = kzalloc(size: sizeof(*detection), GFP_KERNEL); |
545 | if (!detection) { |
546 | ret = -ENOMEM; |
547 | goto out; |
548 | } |
549 | |
550 | detection->rx_cca_threshold = cpu_to_le16(wl->conf.rx.rx_cca_threshold); |
551 | detection->tx_energy_detection = wl->conf.tx.tx_energy_detection; |
552 | |
553 | ret = wl1271_cmd_configure(wl, id: ACX_CCA_THRESHOLD, |
554 | buf: detection, len: sizeof(*detection)); |
555 | if (ret < 0) |
556 | wl1271_warning("failed to set cca threshold: %d" , ret); |
557 | |
558 | out: |
559 | kfree(objp: detection); |
560 | return ret; |
561 | } |
562 | |
563 | int wl1271_acx_bcn_dtim_options(struct wl1271 *wl, struct wl12xx_vif *wlvif) |
564 | { |
565 | struct acx_beacon_broadcast *bb; |
566 | int ret; |
567 | |
568 | wl1271_debug(DEBUG_ACX, "acx bcn dtim options" ); |
569 | |
570 | bb = kzalloc(size: sizeof(*bb), GFP_KERNEL); |
571 | if (!bb) { |
572 | ret = -ENOMEM; |
573 | goto out; |
574 | } |
575 | |
576 | bb->role_id = wlvif->role_id; |
577 | bb->beacon_rx_timeout = cpu_to_le16(wl->conf.conn.beacon_rx_timeout); |
578 | bb->broadcast_timeout = cpu_to_le16(wl->conf.conn.broadcast_timeout); |
579 | bb->rx_broadcast_in_ps = wl->conf.conn.rx_broadcast_in_ps; |
580 | bb->ps_poll_threshold = wl->conf.conn.ps_poll_threshold; |
581 | |
582 | ret = wl1271_cmd_configure(wl, id: ACX_BCN_DTIM_OPTIONS, buf: bb, len: sizeof(*bb)); |
583 | if (ret < 0) { |
584 | wl1271_warning("failed to set rx config: %d" , ret); |
585 | goto out; |
586 | } |
587 | |
588 | out: |
589 | kfree(objp: bb); |
590 | return ret; |
591 | } |
592 | |
593 | int wl1271_acx_aid(struct wl1271 *wl, struct wl12xx_vif *wlvif, u16 aid) |
594 | { |
595 | struct acx_aid *acx_aid; |
596 | int ret; |
597 | |
598 | wl1271_debug(DEBUG_ACX, "acx aid" ); |
599 | |
600 | acx_aid = kzalloc(size: sizeof(*acx_aid), GFP_KERNEL); |
601 | if (!acx_aid) { |
602 | ret = -ENOMEM; |
603 | goto out; |
604 | } |
605 | |
606 | acx_aid->role_id = wlvif->role_id; |
607 | acx_aid->aid = cpu_to_le16(aid); |
608 | |
609 | ret = wl1271_cmd_configure(wl, id: ACX_AID, buf: acx_aid, len: sizeof(*acx_aid)); |
610 | if (ret < 0) { |
611 | wl1271_warning("failed to set aid: %d" , ret); |
612 | goto out; |
613 | } |
614 | |
615 | out: |
616 | kfree(objp: acx_aid); |
617 | return ret; |
618 | } |
619 | |
620 | int wl1271_acx_event_mbox_mask(struct wl1271 *wl, u32 event_mask) |
621 | { |
622 | struct acx_event_mask *mask; |
623 | int ret; |
624 | |
625 | wl1271_debug(DEBUG_ACX, "acx event mbox mask" ); |
626 | |
627 | mask = kzalloc(size: sizeof(*mask), GFP_KERNEL); |
628 | if (!mask) { |
629 | ret = -ENOMEM; |
630 | goto out; |
631 | } |
632 | |
633 | /* high event mask is unused */ |
634 | mask->high_event_mask = cpu_to_le32(0xffffffff); |
635 | mask->event_mask = cpu_to_le32(event_mask); |
636 | |
637 | ret = wl1271_cmd_configure(wl, id: ACX_EVENT_MBOX_MASK, |
638 | buf: mask, len: sizeof(*mask)); |
639 | if (ret < 0) { |
640 | wl1271_warning("failed to set acx_event_mbox_mask: %d" , ret); |
641 | goto out; |
642 | } |
643 | |
644 | out: |
645 | kfree(objp: mask); |
646 | return ret; |
647 | } |
648 | |
649 | int wl1271_acx_set_preamble(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
650 | enum acx_preamble_type preamble) |
651 | { |
652 | struct acx_preamble *acx; |
653 | int ret; |
654 | |
655 | wl1271_debug(DEBUG_ACX, "acx_set_preamble" ); |
656 | |
657 | acx = kzalloc(size: sizeof(*acx), GFP_KERNEL); |
658 | if (!acx) { |
659 | ret = -ENOMEM; |
660 | goto out; |
661 | } |
662 | |
663 | acx->role_id = wlvif->role_id; |
664 | acx->preamble = preamble; |
665 | |
666 | ret = wl1271_cmd_configure(wl, id: ACX_PREAMBLE_TYPE, buf: acx, len: sizeof(*acx)); |
667 | if (ret < 0) { |
668 | wl1271_warning("Setting of preamble failed: %d" , ret); |
669 | goto out; |
670 | } |
671 | |
672 | out: |
673 | kfree(objp: acx); |
674 | return ret; |
675 | } |
676 | |
677 | int wl1271_acx_cts_protect(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
678 | enum acx_ctsprotect_type ctsprotect) |
679 | { |
680 | struct acx_ctsprotect *acx; |
681 | int ret; |
682 | |
683 | wl1271_debug(DEBUG_ACX, "acx_set_ctsprotect" ); |
684 | |
685 | acx = kzalloc(size: sizeof(*acx), GFP_KERNEL); |
686 | if (!acx) { |
687 | ret = -ENOMEM; |
688 | goto out; |
689 | } |
690 | |
691 | acx->role_id = wlvif->role_id; |
692 | acx->ctsprotect = ctsprotect; |
693 | |
694 | ret = wl1271_cmd_configure(wl, id: ACX_CTS_PROTECTION, buf: acx, len: sizeof(*acx)); |
695 | if (ret < 0) { |
696 | wl1271_warning("Setting of ctsprotect failed: %d" , ret); |
697 | goto out; |
698 | } |
699 | |
700 | out: |
701 | kfree(objp: acx); |
702 | return ret; |
703 | } |
704 | |
705 | int wl1271_acx_statistics(struct wl1271 *wl, void *stats) |
706 | { |
707 | int ret; |
708 | |
709 | wl1271_debug(DEBUG_ACX, "acx statistics" ); |
710 | |
711 | ret = wl1271_cmd_interrogate(wl, id: ACX_STATISTICS, buf: stats, |
712 | cmd_len: sizeof(struct acx_header), |
713 | res_len: wl->stats.fw_stats_len); |
714 | if (ret < 0) { |
715 | wl1271_warning("acx statistics failed: %d" , ret); |
716 | return -ENOMEM; |
717 | } |
718 | |
719 | return 0; |
720 | } |
721 | |
722 | int wl1271_acx_sta_rate_policies(struct wl1271 *wl, struct wl12xx_vif *wlvif) |
723 | { |
724 | struct acx_rate_policy *acx; |
725 | struct conf_tx_rate_class *c = &wl->conf.tx.sta_rc_conf; |
726 | int ret = 0; |
727 | |
728 | wl1271_debug(DEBUG_ACX, "acx rate policies" ); |
729 | |
730 | acx = kzalloc(size: sizeof(*acx), GFP_KERNEL); |
731 | |
732 | if (!acx) { |
733 | ret = -ENOMEM; |
734 | goto out; |
735 | } |
736 | |
737 | wl1271_debug(DEBUG_ACX, "basic_rate: 0x%x, full_rate: 0x%x" , |
738 | wlvif->basic_rate, wlvif->rate_set); |
739 | |
740 | /* configure one basic rate class */ |
741 | acx->rate_policy_idx = cpu_to_le32(wlvif->sta.basic_rate_idx); |
742 | acx->rate_policy.enabled_rates = cpu_to_le32(wlvif->basic_rate); |
743 | acx->rate_policy.short_retry_limit = c->short_retry_limit; |
744 | acx->rate_policy.long_retry_limit = c->long_retry_limit; |
745 | acx->rate_policy.aflags = c->aflags; |
746 | |
747 | ret = wl1271_cmd_configure(wl, id: ACX_RATE_POLICY, buf: acx, len: sizeof(*acx)); |
748 | if (ret < 0) { |
749 | wl1271_warning("Setting of rate policies failed: %d" , ret); |
750 | goto out; |
751 | } |
752 | |
753 | /* configure one AP supported rate class */ |
754 | acx->rate_policy_idx = cpu_to_le32(wlvif->sta.ap_rate_idx); |
755 | |
756 | /* the AP policy is HW specific */ |
757 | acx->rate_policy.enabled_rates = |
758 | cpu_to_le32(wlcore_hw_sta_get_ap_rate_mask(wl, wlvif)); |
759 | acx->rate_policy.short_retry_limit = c->short_retry_limit; |
760 | acx->rate_policy.long_retry_limit = c->long_retry_limit; |
761 | acx->rate_policy.aflags = c->aflags; |
762 | |
763 | ret = wl1271_cmd_configure(wl, id: ACX_RATE_POLICY, buf: acx, len: sizeof(*acx)); |
764 | if (ret < 0) { |
765 | wl1271_warning("Setting of rate policies failed: %d" , ret); |
766 | goto out; |
767 | } |
768 | |
769 | /* |
770 | * configure one rate class for basic p2p operations. |
771 | * (p2p packets should always go out with OFDM rates, even |
772 | * if we are currently connected to 11b AP) |
773 | */ |
774 | acx->rate_policy_idx = cpu_to_le32(wlvif->sta.p2p_rate_idx); |
775 | acx->rate_policy.enabled_rates = |
776 | cpu_to_le32(CONF_TX_RATE_MASK_BASIC_P2P); |
777 | acx->rate_policy.short_retry_limit = c->short_retry_limit; |
778 | acx->rate_policy.long_retry_limit = c->long_retry_limit; |
779 | acx->rate_policy.aflags = c->aflags; |
780 | |
781 | ret = wl1271_cmd_configure(wl, id: ACX_RATE_POLICY, buf: acx, len: sizeof(*acx)); |
782 | if (ret < 0) { |
783 | wl1271_warning("Setting of rate policies failed: %d" , ret); |
784 | goto out; |
785 | } |
786 | |
787 | out: |
788 | kfree(objp: acx); |
789 | return ret; |
790 | } |
791 | |
792 | int wl1271_acx_ap_rate_policy(struct wl1271 *wl, struct conf_tx_rate_class *c, |
793 | u8 idx) |
794 | { |
795 | struct acx_rate_policy *acx; |
796 | int ret = 0; |
797 | |
798 | wl1271_debug(DEBUG_ACX, "acx ap rate policy %d rates 0x%x" , |
799 | idx, c->enabled_rates); |
800 | |
801 | acx = kzalloc(size: sizeof(*acx), GFP_KERNEL); |
802 | if (!acx) { |
803 | ret = -ENOMEM; |
804 | goto out; |
805 | } |
806 | |
807 | acx->rate_policy.enabled_rates = cpu_to_le32(c->enabled_rates); |
808 | acx->rate_policy.short_retry_limit = c->short_retry_limit; |
809 | acx->rate_policy.long_retry_limit = c->long_retry_limit; |
810 | acx->rate_policy.aflags = c->aflags; |
811 | |
812 | acx->rate_policy_idx = cpu_to_le32(idx); |
813 | |
814 | ret = wl1271_cmd_configure(wl, id: ACX_RATE_POLICY, buf: acx, len: sizeof(*acx)); |
815 | if (ret < 0) { |
816 | wl1271_warning("Setting of ap rate policy failed: %d" , ret); |
817 | goto out; |
818 | } |
819 | |
820 | out: |
821 | kfree(objp: acx); |
822 | return ret; |
823 | } |
824 | |
825 | int wl1271_acx_ac_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
826 | u8 ac, u8 cw_min, u16 cw_max, u8 aifsn, u16 txop) |
827 | { |
828 | struct acx_ac_cfg *acx; |
829 | int ret = 0; |
830 | |
831 | wl1271_debug(DEBUG_ACX, "acx ac cfg %d cw_ming %d cw_max %d " |
832 | "aifs %d txop %d" , ac, cw_min, cw_max, aifsn, txop); |
833 | |
834 | acx = kzalloc(size: sizeof(*acx), GFP_KERNEL); |
835 | |
836 | if (!acx) { |
837 | ret = -ENOMEM; |
838 | goto out; |
839 | } |
840 | |
841 | acx->role_id = wlvif->role_id; |
842 | acx->ac = ac; |
843 | acx->cw_min = cw_min; |
844 | acx->cw_max = cpu_to_le16(cw_max); |
845 | acx->aifsn = aifsn; |
846 | acx->tx_op_limit = cpu_to_le16(txop); |
847 | |
848 | ret = wl1271_cmd_configure(wl, id: ACX_AC_CFG, buf: acx, len: sizeof(*acx)); |
849 | if (ret < 0) { |
850 | wl1271_warning("acx ac cfg failed: %d" , ret); |
851 | goto out; |
852 | } |
853 | |
854 | out: |
855 | kfree(objp: acx); |
856 | return ret; |
857 | } |
858 | |
859 | int wl1271_acx_tid_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
860 | u8 queue_id, u8 channel_type, |
861 | u8 tsid, u8 ps_scheme, u8 ack_policy, |
862 | u32 apsd_conf0, u32 apsd_conf1) |
863 | { |
864 | struct acx_tid_config *acx; |
865 | int ret = 0; |
866 | |
867 | wl1271_debug(DEBUG_ACX, "acx tid config" ); |
868 | |
869 | acx = kzalloc(size: sizeof(*acx), GFP_KERNEL); |
870 | |
871 | if (!acx) { |
872 | ret = -ENOMEM; |
873 | goto out; |
874 | } |
875 | |
876 | acx->role_id = wlvif->role_id; |
877 | acx->queue_id = queue_id; |
878 | acx->channel_type = channel_type; |
879 | acx->tsid = tsid; |
880 | acx->ps_scheme = ps_scheme; |
881 | acx->ack_policy = ack_policy; |
882 | acx->apsd_conf[0] = cpu_to_le32(apsd_conf0); |
883 | acx->apsd_conf[1] = cpu_to_le32(apsd_conf1); |
884 | |
885 | ret = wl1271_cmd_configure(wl, id: ACX_TID_CFG, buf: acx, len: sizeof(*acx)); |
886 | if (ret < 0) { |
887 | wl1271_warning("Setting of tid config failed: %d" , ret); |
888 | goto out; |
889 | } |
890 | |
891 | out: |
892 | kfree(objp: acx); |
893 | return ret; |
894 | } |
895 | |
896 | int wl1271_acx_frag_threshold(struct wl1271 *wl, u32 frag_threshold) |
897 | { |
898 | struct acx_frag_threshold *acx; |
899 | int ret = 0; |
900 | |
901 | /* |
902 | * If the fragmentation is not configured or out of range, use the |
903 | * default value. |
904 | */ |
905 | if (frag_threshold > IEEE80211_MAX_FRAG_THRESHOLD) |
906 | frag_threshold = wl->conf.tx.frag_threshold; |
907 | |
908 | wl1271_debug(DEBUG_ACX, "acx frag threshold: %d" , frag_threshold); |
909 | |
910 | acx = kzalloc(size: sizeof(*acx), GFP_KERNEL); |
911 | |
912 | if (!acx) { |
913 | ret = -ENOMEM; |
914 | goto out; |
915 | } |
916 | |
917 | acx->frag_threshold = cpu_to_le16((u16)frag_threshold); |
918 | ret = wl1271_cmd_configure(wl, id: ACX_FRAG_CFG, buf: acx, len: sizeof(*acx)); |
919 | if (ret < 0) { |
920 | wl1271_warning("Setting of frag threshold failed: %d" , ret); |
921 | goto out; |
922 | } |
923 | |
924 | out: |
925 | kfree(objp: acx); |
926 | return ret; |
927 | } |
928 | |
929 | int wl1271_acx_tx_config_options(struct wl1271 *wl) |
930 | { |
931 | struct acx_tx_config_options *acx; |
932 | int ret = 0; |
933 | |
934 | wl1271_debug(DEBUG_ACX, "acx tx config options" ); |
935 | |
936 | acx = kzalloc(size: sizeof(*acx), GFP_KERNEL); |
937 | |
938 | if (!acx) { |
939 | ret = -ENOMEM; |
940 | goto out; |
941 | } |
942 | |
943 | acx->tx_compl_timeout = cpu_to_le16(wl->conf.tx.tx_compl_timeout); |
944 | acx->tx_compl_threshold = cpu_to_le16(wl->conf.tx.tx_compl_threshold); |
945 | ret = wl1271_cmd_configure(wl, id: ACX_TX_CONFIG_OPT, buf: acx, len: sizeof(*acx)); |
946 | if (ret < 0) { |
947 | wl1271_warning("Setting of tx options failed: %d" , ret); |
948 | goto out; |
949 | } |
950 | |
951 | out: |
952 | kfree(objp: acx); |
953 | return ret; |
954 | } |
955 | |
956 | int wl12xx_acx_mem_cfg(struct wl1271 *wl) |
957 | { |
958 | struct wl12xx_acx_config_memory *mem_conf; |
959 | struct conf_memory_settings *mem; |
960 | int ret; |
961 | |
962 | wl1271_debug(DEBUG_ACX, "wl1271 mem cfg" ); |
963 | |
964 | mem_conf = kzalloc(size: sizeof(*mem_conf), GFP_KERNEL); |
965 | if (!mem_conf) { |
966 | ret = -ENOMEM; |
967 | goto out; |
968 | } |
969 | |
970 | mem = &wl->conf.mem; |
971 | |
972 | /* memory config */ |
973 | mem_conf->num_stations = mem->num_stations; |
974 | mem_conf->rx_mem_block_num = mem->rx_block_num; |
975 | mem_conf->tx_min_mem_block_num = mem->tx_min_block_num; |
976 | mem_conf->num_ssid_profiles = mem->ssid_profiles; |
977 | mem_conf->total_tx_descriptors = cpu_to_le32(wl->num_tx_desc); |
978 | mem_conf->dyn_mem_enable = mem->dynamic_memory; |
979 | mem_conf->tx_free_req = mem->min_req_tx_blocks; |
980 | mem_conf->rx_free_req = mem->min_req_rx_blocks; |
981 | mem_conf->tx_min = mem->tx_min; |
982 | mem_conf->fwlog_blocks = wl->conf.fwlog.mem_blocks; |
983 | |
984 | ret = wl1271_cmd_configure(wl, id: ACX_MEM_CFG, buf: mem_conf, |
985 | len: sizeof(*mem_conf)); |
986 | if (ret < 0) { |
987 | wl1271_warning("wl1271 mem config failed: %d" , ret); |
988 | goto out; |
989 | } |
990 | |
991 | out: |
992 | kfree(objp: mem_conf); |
993 | return ret; |
994 | } |
995 | EXPORT_SYMBOL_GPL(wl12xx_acx_mem_cfg); |
996 | |
997 | int wl1271_acx_init_mem_config(struct wl1271 *wl) |
998 | { |
999 | int ret; |
1000 | |
1001 | wl->target_mem_map = kzalloc(size: sizeof(struct wl1271_acx_mem_map), |
1002 | GFP_KERNEL); |
1003 | if (!wl->target_mem_map) { |
1004 | wl1271_error("couldn't allocate target memory map" ); |
1005 | return -ENOMEM; |
1006 | } |
1007 | |
1008 | /* we now ask for the firmware built memory map */ |
1009 | ret = wl1271_acx_mem_map(wl, mem_map: (void *)wl->target_mem_map, |
1010 | len: sizeof(struct wl1271_acx_mem_map)); |
1011 | if (ret < 0) { |
1012 | wl1271_error("couldn't retrieve firmware memory map" ); |
1013 | kfree(objp: wl->target_mem_map); |
1014 | wl->target_mem_map = NULL; |
1015 | return ret; |
1016 | } |
1017 | |
1018 | /* initialize TX block book keeping */ |
1019 | wl->tx_blocks_available = |
1020 | le32_to_cpu(wl->target_mem_map->num_tx_mem_blocks); |
1021 | wl1271_debug(DEBUG_TX, "available tx blocks: %d" , |
1022 | wl->tx_blocks_available); |
1023 | |
1024 | return 0; |
1025 | } |
1026 | EXPORT_SYMBOL_GPL(wl1271_acx_init_mem_config); |
1027 | |
1028 | int wl1271_acx_init_rx_interrupt(struct wl1271 *wl) |
1029 | { |
1030 | struct wl1271_acx_rx_config_opt *rx_conf; |
1031 | int ret; |
1032 | |
1033 | wl1271_debug(DEBUG_ACX, "wl1271 rx interrupt config" ); |
1034 | |
1035 | rx_conf = kzalloc(size: sizeof(*rx_conf), GFP_KERNEL); |
1036 | if (!rx_conf) { |
1037 | ret = -ENOMEM; |
1038 | goto out; |
1039 | } |
1040 | |
1041 | rx_conf->threshold = cpu_to_le16(wl->conf.rx.irq_pkt_threshold); |
1042 | rx_conf->timeout = cpu_to_le16(wl->conf.rx.irq_timeout); |
1043 | rx_conf->mblk_threshold = cpu_to_le16(wl->conf.rx.irq_blk_threshold); |
1044 | rx_conf->queue_type = wl->conf.rx.queue_type; |
1045 | |
1046 | ret = wl1271_cmd_configure(wl, id: ACX_RX_CONFIG_OPT, buf: rx_conf, |
1047 | len: sizeof(*rx_conf)); |
1048 | if (ret < 0) { |
1049 | wl1271_warning("wl1271 rx config opt failed: %d" , ret); |
1050 | goto out; |
1051 | } |
1052 | |
1053 | out: |
1054 | kfree(objp: rx_conf); |
1055 | return ret; |
1056 | } |
1057 | |
1058 | int wl1271_acx_bet_enable(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
1059 | bool enable) |
1060 | { |
1061 | struct wl1271_acx_bet_enable *acx = NULL; |
1062 | int ret = 0; |
1063 | |
1064 | wl1271_debug(DEBUG_ACX, "acx bet enable" ); |
1065 | |
1066 | if (enable && wl->conf.conn.bet_enable == CONF_BET_MODE_DISABLE) |
1067 | goto out; |
1068 | |
1069 | acx = kzalloc(size: sizeof(*acx), GFP_KERNEL); |
1070 | if (!acx) { |
1071 | ret = -ENOMEM; |
1072 | goto out; |
1073 | } |
1074 | |
1075 | acx->role_id = wlvif->role_id; |
1076 | acx->enable = enable ? CONF_BET_MODE_ENABLE : CONF_BET_MODE_DISABLE; |
1077 | acx->max_consecutive = wl->conf.conn.bet_max_consecutive; |
1078 | |
1079 | ret = wl1271_cmd_configure(wl, id: ACX_BET_ENABLE, buf: acx, len: sizeof(*acx)); |
1080 | if (ret < 0) { |
1081 | wl1271_warning("acx bet enable failed: %d" , ret); |
1082 | goto out; |
1083 | } |
1084 | |
1085 | out: |
1086 | kfree(objp: acx); |
1087 | return ret; |
1088 | } |
1089 | |
1090 | int wl1271_acx_arp_ip_filter(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
1091 | u8 enable, __be32 address) |
1092 | { |
1093 | struct wl1271_acx_arp_filter *acx; |
1094 | int ret; |
1095 | |
1096 | wl1271_debug(DEBUG_ACX, "acx arp ip filter, enable: %d" , enable); |
1097 | |
1098 | acx = kzalloc(size: sizeof(*acx), GFP_KERNEL); |
1099 | if (!acx) { |
1100 | ret = -ENOMEM; |
1101 | goto out; |
1102 | } |
1103 | |
1104 | acx->role_id = wlvif->role_id; |
1105 | acx->version = ACX_IPV4_VERSION; |
1106 | acx->enable = enable; |
1107 | |
1108 | if (enable) |
1109 | memcpy(acx->address, &address, ACX_IPV4_ADDR_SIZE); |
1110 | |
1111 | ret = wl1271_cmd_configure(wl, id: ACX_ARP_IP_FILTER, |
1112 | buf: acx, len: sizeof(*acx)); |
1113 | if (ret < 0) { |
1114 | wl1271_warning("failed to set arp ip filter: %d" , ret); |
1115 | goto out; |
1116 | } |
1117 | |
1118 | out: |
1119 | kfree(objp: acx); |
1120 | return ret; |
1121 | } |
1122 | |
1123 | int wl1271_acx_pm_config(struct wl1271 *wl) |
1124 | { |
1125 | struct wl1271_acx_pm_config *acx = NULL; |
1126 | struct conf_pm_config_settings *c = &wl->conf.pm_config; |
1127 | int ret = 0; |
1128 | |
1129 | wl1271_debug(DEBUG_ACX, "acx pm config" ); |
1130 | |
1131 | acx = kzalloc(size: sizeof(*acx), GFP_KERNEL); |
1132 | if (!acx) { |
1133 | ret = -ENOMEM; |
1134 | goto out; |
1135 | } |
1136 | |
1137 | acx->host_clk_settling_time = cpu_to_le32(c->host_clk_settling_time); |
1138 | acx->host_fast_wakeup_support = c->host_fast_wakeup_support; |
1139 | |
1140 | ret = wl1271_cmd_configure(wl, id: ACX_PM_CONFIG, buf: acx, len: sizeof(*acx)); |
1141 | if (ret < 0) { |
1142 | wl1271_warning("acx pm config failed: %d" , ret); |
1143 | goto out; |
1144 | } |
1145 | |
1146 | out: |
1147 | kfree(objp: acx); |
1148 | return ret; |
1149 | } |
1150 | EXPORT_SYMBOL_GPL(wl1271_acx_pm_config); |
1151 | |
1152 | int wl1271_acx_keep_alive_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
1153 | bool enable) |
1154 | { |
1155 | struct wl1271_acx_keep_alive_mode *acx = NULL; |
1156 | int ret = 0; |
1157 | |
1158 | wl1271_debug(DEBUG_ACX, "acx keep alive mode: %d" , enable); |
1159 | |
1160 | acx = kzalloc(size: sizeof(*acx), GFP_KERNEL); |
1161 | if (!acx) { |
1162 | ret = -ENOMEM; |
1163 | goto out; |
1164 | } |
1165 | |
1166 | acx->role_id = wlvif->role_id; |
1167 | acx->enabled = enable; |
1168 | |
1169 | ret = wl1271_cmd_configure(wl, id: ACX_KEEP_ALIVE_MODE, buf: acx, len: sizeof(*acx)); |
1170 | if (ret < 0) { |
1171 | wl1271_warning("acx keep alive mode failed: %d" , ret); |
1172 | goto out; |
1173 | } |
1174 | |
1175 | out: |
1176 | kfree(objp: acx); |
1177 | return ret; |
1178 | } |
1179 | |
1180 | int wl1271_acx_keep_alive_config(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
1181 | u8 index, u8 tpl_valid) |
1182 | { |
1183 | struct wl1271_acx_keep_alive_config *acx = NULL; |
1184 | int ret = 0; |
1185 | |
1186 | wl1271_debug(DEBUG_ACX, "acx keep alive config" ); |
1187 | |
1188 | acx = kzalloc(size: sizeof(*acx), GFP_KERNEL); |
1189 | if (!acx) { |
1190 | ret = -ENOMEM; |
1191 | goto out; |
1192 | } |
1193 | |
1194 | acx->role_id = wlvif->role_id; |
1195 | acx->period = cpu_to_le32(wl->conf.conn.keep_alive_interval); |
1196 | acx->index = index; |
1197 | acx->tpl_validation = tpl_valid; |
1198 | acx->trigger = ACX_KEEP_ALIVE_NO_TX; |
1199 | |
1200 | ret = wl1271_cmd_configure(wl, id: ACX_SET_KEEP_ALIVE_CONFIG, |
1201 | buf: acx, len: sizeof(*acx)); |
1202 | if (ret < 0) { |
1203 | wl1271_warning("acx keep alive config failed: %d" , ret); |
1204 | goto out; |
1205 | } |
1206 | |
1207 | out: |
1208 | kfree(objp: acx); |
1209 | return ret; |
1210 | } |
1211 | |
1212 | int (struct wl1271 *wl, struct wl12xx_vif *wlvif, |
1213 | bool enable, s16 thold, u8 hyst) |
1214 | { |
1215 | struct wl1271_acx_rssi_snr_trigger *acx = NULL; |
1216 | int ret = 0; |
1217 | |
1218 | wl1271_debug(DEBUG_ACX, "acx rssi snr trigger" ); |
1219 | |
1220 | acx = kzalloc(size: sizeof(*acx), GFP_KERNEL); |
1221 | if (!acx) { |
1222 | ret = -ENOMEM; |
1223 | goto out; |
1224 | } |
1225 | |
1226 | wlvif->last_rssi_event = -1; |
1227 | |
1228 | acx->role_id = wlvif->role_id; |
1229 | acx->pacing = cpu_to_le16(wl->conf.roam_trigger.trigger_pacing); |
1230 | acx->metric = WL1271_ACX_TRIG_METRIC_RSSI_BEACON; |
1231 | acx->type = WL1271_ACX_TRIG_TYPE_EDGE; |
1232 | if (enable) |
1233 | acx->enable = WL1271_ACX_TRIG_ENABLE; |
1234 | else |
1235 | acx->enable = WL1271_ACX_TRIG_DISABLE; |
1236 | |
1237 | acx->index = WL1271_ACX_TRIG_IDX_RSSI; |
1238 | acx->dir = WL1271_ACX_TRIG_DIR_BIDIR; |
1239 | acx->threshold = cpu_to_le16(thold); |
1240 | acx->hysteresis = hyst; |
1241 | |
1242 | ret = wl1271_cmd_configure(wl, id: ACX_RSSI_SNR_TRIGGER, buf: acx, len: sizeof(*acx)); |
1243 | if (ret < 0) { |
1244 | wl1271_warning("acx rssi snr trigger setting failed: %d" , ret); |
1245 | goto out; |
1246 | } |
1247 | |
1248 | out: |
1249 | kfree(objp: acx); |
1250 | return ret; |
1251 | } |
1252 | |
1253 | int (struct wl1271 *wl, |
1254 | struct wl12xx_vif *wlvif) |
1255 | { |
1256 | struct wl1271_acx_rssi_snr_avg_weights *acx = NULL; |
1257 | struct conf_roam_trigger_settings *c = &wl->conf.roam_trigger; |
1258 | int ret = 0; |
1259 | |
1260 | wl1271_debug(DEBUG_ACX, "acx rssi snr avg weights" ); |
1261 | |
1262 | acx = kzalloc(size: sizeof(*acx), GFP_KERNEL); |
1263 | if (!acx) { |
1264 | ret = -ENOMEM; |
1265 | goto out; |
1266 | } |
1267 | |
1268 | acx->role_id = wlvif->role_id; |
1269 | acx->rssi_beacon = c->avg_weight_rssi_beacon; |
1270 | acx->rssi_data = c->avg_weight_rssi_data; |
1271 | acx->snr_beacon = c->avg_weight_snr_beacon; |
1272 | acx->snr_data = c->avg_weight_snr_data; |
1273 | |
1274 | ret = wl1271_cmd_configure(wl, id: ACX_RSSI_SNR_WEIGHTS, buf: acx, len: sizeof(*acx)); |
1275 | if (ret < 0) { |
1276 | wl1271_warning("acx rssi snr trigger weights failed: %d" , ret); |
1277 | goto out; |
1278 | } |
1279 | |
1280 | out: |
1281 | kfree(objp: acx); |
1282 | return ret; |
1283 | } |
1284 | |
1285 | int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, |
1286 | struct ieee80211_sta_ht_cap *ht_cap, |
1287 | bool allow_ht_operation, u8 hlid) |
1288 | { |
1289 | struct wl1271_acx_ht_capabilities *acx; |
1290 | int ret = 0; |
1291 | u32 ht_capabilites = 0; |
1292 | |
1293 | wl1271_debug(DEBUG_ACX, "acx ht capabilities setting " |
1294 | "sta supp: %d sta cap: %d" , ht_cap->ht_supported, |
1295 | ht_cap->cap); |
1296 | |
1297 | acx = kzalloc(size: sizeof(*acx), GFP_KERNEL); |
1298 | if (!acx) { |
1299 | ret = -ENOMEM; |
1300 | goto out; |
1301 | } |
1302 | |
1303 | if (allow_ht_operation && ht_cap->ht_supported) { |
1304 | /* no need to translate capabilities - use the spec values */ |
1305 | ht_capabilites = ht_cap->cap; |
1306 | |
1307 | /* |
1308 | * this bit is not employed by the spec but only by FW to |
1309 | * indicate peer HT support |
1310 | */ |
1311 | ht_capabilites |= WL12XX_HT_CAP_HT_OPERATION; |
1312 | |
1313 | /* get data from A-MPDU parameters field */ |
1314 | acx->ampdu_max_length = ht_cap->ampdu_factor; |
1315 | acx->ampdu_min_spacing = ht_cap->ampdu_density; |
1316 | } |
1317 | |
1318 | acx->hlid = hlid; |
1319 | acx->ht_capabilites = cpu_to_le32(ht_capabilites); |
1320 | |
1321 | ret = wl1271_cmd_configure(wl, id: ACX_PEER_HT_CAP, buf: acx, len: sizeof(*acx)); |
1322 | if (ret < 0) { |
1323 | wl1271_warning("acx ht capabilities setting failed: %d" , ret); |
1324 | goto out; |
1325 | } |
1326 | |
1327 | out: |
1328 | kfree(objp: acx); |
1329 | return ret; |
1330 | } |
1331 | EXPORT_SYMBOL_GPL(wl1271_acx_set_ht_capabilities); |
1332 | |
1333 | |
1334 | int wl1271_acx_set_ht_information(struct wl1271 *wl, |
1335 | struct wl12xx_vif *wlvif, |
1336 | u16 ht_operation_mode) |
1337 | { |
1338 | struct wl1271_acx_ht_information *acx; |
1339 | int ret = 0; |
1340 | |
1341 | wl1271_debug(DEBUG_ACX, "acx ht information setting" ); |
1342 | |
1343 | acx = kzalloc(size: sizeof(*acx), GFP_KERNEL); |
1344 | if (!acx) { |
1345 | ret = -ENOMEM; |
1346 | goto out; |
1347 | } |
1348 | |
1349 | acx->role_id = wlvif->role_id; |
1350 | acx->ht_protection = |
1351 | (u8)(ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION); |
1352 | acx->rifs_mode = 0; |
1353 | acx->gf_protection = |
1354 | !!(ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); |
1355 | acx->ht_tx_burst_limit = 0; |
1356 | acx->dual_cts_protection = 0; |
1357 | |
1358 | ret = wl1271_cmd_configure(wl, id: ACX_HT_BSS_OPERATION, buf: acx, len: sizeof(*acx)); |
1359 | |
1360 | if (ret < 0) { |
1361 | wl1271_warning("acx ht information setting failed: %d" , ret); |
1362 | goto out; |
1363 | } |
1364 | |
1365 | out: |
1366 | kfree(objp: acx); |
1367 | return ret; |
1368 | } |
1369 | |
1370 | /* Configure BA session initiator/receiver parameters setting in the FW. */ |
1371 | int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl, |
1372 | struct wl12xx_vif *wlvif) |
1373 | { |
1374 | struct wl1271_acx_ba_initiator_policy *acx; |
1375 | int ret; |
1376 | |
1377 | wl1271_debug(DEBUG_ACX, "acx ba initiator policy" ); |
1378 | |
1379 | acx = kzalloc(size: sizeof(*acx), GFP_KERNEL); |
1380 | if (!acx) { |
1381 | ret = -ENOMEM; |
1382 | goto out; |
1383 | } |
1384 | |
1385 | /* set for the current role */ |
1386 | acx->role_id = wlvif->role_id; |
1387 | acx->tid_bitmap = wl->conf.ht.tx_ba_tid_bitmap; |
1388 | acx->win_size = wl->conf.ht.tx_ba_win_size; |
1389 | acx->inactivity_timeout = wl->conf.ht.inactivity_timeout; |
1390 | |
1391 | ret = wl1271_cmd_configure(wl, |
1392 | id: ACX_BA_SESSION_INIT_POLICY, |
1393 | buf: acx, |
1394 | len: sizeof(*acx)); |
1395 | if (ret < 0) { |
1396 | wl1271_warning("acx ba initiator policy failed: %d" , ret); |
1397 | goto out; |
1398 | } |
1399 | |
1400 | out: |
1401 | kfree(objp: acx); |
1402 | return ret; |
1403 | } |
1404 | |
1405 | /* setup BA session receiver setting in the FW. */ |
1406 | int wl12xx_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, |
1407 | u16 ssn, bool enable, u8 peer_hlid, |
1408 | u8 win_size) |
1409 | { |
1410 | struct wl1271_acx_ba_receiver_setup *acx; |
1411 | int ret; |
1412 | |
1413 | wl1271_debug(DEBUG_ACX, "acx ba receiver session setting" ); |
1414 | |
1415 | acx = kzalloc(size: sizeof(*acx), GFP_KERNEL); |
1416 | if (!acx) { |
1417 | ret = -ENOMEM; |
1418 | goto out; |
1419 | } |
1420 | |
1421 | acx->hlid = peer_hlid; |
1422 | acx->tid = tid_index; |
1423 | acx->enable = enable; |
1424 | acx->win_size = win_size; |
1425 | acx->ssn = ssn; |
1426 | |
1427 | ret = wlcore_cmd_configure_failsafe(wl, id: ACX_BA_SESSION_RX_SETUP, buf: acx, |
1428 | len: sizeof(*acx), |
1429 | BIT(CMD_STATUS_NO_RX_BA_SESSION)); |
1430 | if (ret < 0) { |
1431 | wl1271_warning("acx ba receiver session failed: %d" , ret); |
1432 | goto out; |
1433 | } |
1434 | |
1435 | /* sometimes we can't start the session */ |
1436 | if (ret == CMD_STATUS_NO_RX_BA_SESSION) { |
1437 | wl1271_warning("no fw rx ba on tid %d" , tid_index); |
1438 | ret = -EBUSY; |
1439 | goto out; |
1440 | } |
1441 | |
1442 | ret = 0; |
1443 | out: |
1444 | kfree(objp: acx); |
1445 | return ret; |
1446 | } |
1447 | |
1448 | int wl12xx_acx_tsf_info(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
1449 | u64 *mactime) |
1450 | { |
1451 | struct wl12xx_acx_fw_tsf_information *tsf_info; |
1452 | int ret; |
1453 | |
1454 | tsf_info = kzalloc(size: sizeof(*tsf_info), GFP_KERNEL); |
1455 | if (!tsf_info) { |
1456 | ret = -ENOMEM; |
1457 | goto out; |
1458 | } |
1459 | |
1460 | tsf_info->role_id = wlvif->role_id; |
1461 | |
1462 | ret = wl1271_cmd_interrogate(wl, id: ACX_TSF_INFO, buf: tsf_info, |
1463 | cmd_len: sizeof(struct acx_header), res_len: sizeof(*tsf_info)); |
1464 | if (ret < 0) { |
1465 | wl1271_warning("acx tsf info interrogate failed" ); |
1466 | goto out; |
1467 | } |
1468 | |
1469 | *mactime = le32_to_cpu(tsf_info->current_tsf_low) | |
1470 | ((u64) le32_to_cpu(tsf_info->current_tsf_high) << 32); |
1471 | |
1472 | out: |
1473 | kfree(objp: tsf_info); |
1474 | return ret; |
1475 | } |
1476 | |
1477 | int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
1478 | bool enable) |
1479 | { |
1480 | struct wl1271_acx_ps_rx_streaming *rx_streaming; |
1481 | u32 conf_queues, enable_queues; |
1482 | int i, ret = 0; |
1483 | |
1484 | wl1271_debug(DEBUG_ACX, "acx ps rx streaming" ); |
1485 | |
1486 | rx_streaming = kzalloc(size: sizeof(*rx_streaming), GFP_KERNEL); |
1487 | if (!rx_streaming) { |
1488 | ret = -ENOMEM; |
1489 | goto out; |
1490 | } |
1491 | |
1492 | conf_queues = wl->conf.rx_streaming.queues; |
1493 | if (enable) |
1494 | enable_queues = conf_queues; |
1495 | else |
1496 | enable_queues = 0; |
1497 | |
1498 | for (i = 0; i < 8; i++) { |
1499 | /* |
1500 | * Skip non-changed queues, to avoid redundant acxs. |
1501 | * this check assumes conf.rx_streaming.queues can't |
1502 | * be changed while rx_streaming is enabled. |
1503 | */ |
1504 | if (!(conf_queues & BIT(i))) |
1505 | continue; |
1506 | |
1507 | rx_streaming->role_id = wlvif->role_id; |
1508 | rx_streaming->tid = i; |
1509 | rx_streaming->enable = enable_queues & BIT(i); |
1510 | rx_streaming->period = wl->conf.rx_streaming.interval; |
1511 | rx_streaming->timeout = wl->conf.rx_streaming.interval; |
1512 | |
1513 | ret = wl1271_cmd_configure(wl, id: ACX_PS_RX_STREAMING, |
1514 | buf: rx_streaming, |
1515 | len: sizeof(*rx_streaming)); |
1516 | if (ret < 0) { |
1517 | wl1271_warning("acx ps rx streaming failed: %d" , ret); |
1518 | goto out; |
1519 | } |
1520 | } |
1521 | out: |
1522 | kfree(objp: rx_streaming); |
1523 | return ret; |
1524 | } |
1525 | |
1526 | int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl, struct wl12xx_vif *wlvif) |
1527 | { |
1528 | struct wl1271_acx_ap_max_tx_retry *acx = NULL; |
1529 | int ret; |
1530 | |
1531 | wl1271_debug(DEBUG_ACX, "acx ap max tx retry" ); |
1532 | |
1533 | acx = kzalloc(size: sizeof(*acx), GFP_KERNEL); |
1534 | if (!acx) |
1535 | return -ENOMEM; |
1536 | |
1537 | acx->role_id = wlvif->role_id; |
1538 | acx->max_tx_retry = cpu_to_le16(wl->conf.tx.max_tx_retries); |
1539 | |
1540 | ret = wl1271_cmd_configure(wl, id: ACX_MAX_TX_FAILURE, buf: acx, len: sizeof(*acx)); |
1541 | if (ret < 0) { |
1542 | wl1271_warning("acx ap max tx retry failed: %d" , ret); |
1543 | goto out; |
1544 | } |
1545 | |
1546 | out: |
1547 | kfree(objp: acx); |
1548 | return ret; |
1549 | } |
1550 | |
1551 | int wl12xx_acx_config_ps(struct wl1271 *wl, struct wl12xx_vif *wlvif) |
1552 | { |
1553 | struct wl1271_acx_config_ps *config_ps; |
1554 | int ret; |
1555 | |
1556 | wl1271_debug(DEBUG_ACX, "acx config ps" ); |
1557 | |
1558 | config_ps = kzalloc(size: sizeof(*config_ps), GFP_KERNEL); |
1559 | if (!config_ps) { |
1560 | ret = -ENOMEM; |
1561 | goto out; |
1562 | } |
1563 | |
1564 | config_ps->exit_retries = wl->conf.conn.psm_exit_retries; |
1565 | config_ps->enter_retries = wl->conf.conn.psm_entry_retries; |
1566 | config_ps->null_data_rate = cpu_to_le32(wlvif->basic_rate); |
1567 | |
1568 | ret = wl1271_cmd_configure(wl, id: ACX_CONFIG_PS, buf: config_ps, |
1569 | len: sizeof(*config_ps)); |
1570 | |
1571 | if (ret < 0) { |
1572 | wl1271_warning("acx config ps failed: %d" , ret); |
1573 | goto out; |
1574 | } |
1575 | |
1576 | out: |
1577 | kfree(objp: config_ps); |
1578 | return ret; |
1579 | } |
1580 | |
1581 | int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, |
1582 | struct wl12xx_vif *wlvif, u8 *addr) |
1583 | { |
1584 | struct wl1271_acx_inconnection_sta *acx = NULL; |
1585 | int ret; |
1586 | |
1587 | wl1271_debug(DEBUG_ACX, "acx set inconnaction sta %pM" , addr); |
1588 | |
1589 | acx = kzalloc(size: sizeof(*acx), GFP_KERNEL); |
1590 | if (!acx) |
1591 | return -ENOMEM; |
1592 | |
1593 | memcpy(acx->addr, addr, ETH_ALEN); |
1594 | acx->role_id = wlvif->role_id; |
1595 | |
1596 | ret = wl1271_cmd_configure(wl, id: ACX_UPDATE_INCONNECTION_STA_LIST, |
1597 | buf: acx, len: sizeof(*acx)); |
1598 | if (ret < 0) { |
1599 | wl1271_warning("acx set inconnaction sta failed: %d" , ret); |
1600 | goto out; |
1601 | } |
1602 | |
1603 | out: |
1604 | kfree(objp: acx); |
1605 | return ret; |
1606 | } |
1607 | |
1608 | int wl1271_acx_fm_coex(struct wl1271 *wl) |
1609 | { |
1610 | struct wl1271_acx_fm_coex *acx; |
1611 | int ret; |
1612 | |
1613 | wl1271_debug(DEBUG_ACX, "acx fm coex setting" ); |
1614 | |
1615 | acx = kzalloc(size: sizeof(*acx), GFP_KERNEL); |
1616 | if (!acx) { |
1617 | ret = -ENOMEM; |
1618 | goto out; |
1619 | } |
1620 | |
1621 | acx->enable = wl->conf.fm_coex.enable; |
1622 | acx->swallow_period = wl->conf.fm_coex.swallow_period; |
1623 | acx->n_divider_fref_set_1 = wl->conf.fm_coex.n_divider_fref_set_1; |
1624 | acx->n_divider_fref_set_2 = wl->conf.fm_coex.n_divider_fref_set_2; |
1625 | acx->m_divider_fref_set_1 = |
1626 | cpu_to_le16(wl->conf.fm_coex.m_divider_fref_set_1); |
1627 | acx->m_divider_fref_set_2 = |
1628 | cpu_to_le16(wl->conf.fm_coex.m_divider_fref_set_2); |
1629 | acx->coex_pll_stabilization_time = |
1630 | cpu_to_le32(wl->conf.fm_coex.coex_pll_stabilization_time); |
1631 | acx->ldo_stabilization_time = |
1632 | cpu_to_le16(wl->conf.fm_coex.ldo_stabilization_time); |
1633 | acx->fm_disturbed_band_margin = |
1634 | wl->conf.fm_coex.fm_disturbed_band_margin; |
1635 | acx->swallow_clk_diff = wl->conf.fm_coex.swallow_clk_diff; |
1636 | |
1637 | ret = wl1271_cmd_configure(wl, id: ACX_FM_COEX_CFG, buf: acx, len: sizeof(*acx)); |
1638 | if (ret < 0) { |
1639 | wl1271_warning("acx fm coex setting failed: %d" , ret); |
1640 | goto out; |
1641 | } |
1642 | |
1643 | out: |
1644 | kfree(objp: acx); |
1645 | return ret; |
1646 | } |
1647 | |
1648 | int wl12xx_acx_set_rate_mgmt_params(struct wl1271 *wl) |
1649 | { |
1650 | struct wl12xx_acx_set_rate_mgmt_params *acx = NULL; |
1651 | struct conf_rate_policy_settings *conf = &wl->conf.rate; |
1652 | int ret; |
1653 | |
1654 | wl1271_debug(DEBUG_ACX, "acx set rate mgmt params" ); |
1655 | |
1656 | acx = kzalloc(size: sizeof(*acx), GFP_KERNEL); |
1657 | if (!acx) |
1658 | return -ENOMEM; |
1659 | |
1660 | acx->index = ACX_RATE_MGMT_ALL_PARAMS; |
1661 | acx->rate_retry_score = cpu_to_le16(conf->rate_retry_score); |
1662 | acx->per_add = cpu_to_le16(conf->per_add); |
1663 | acx->per_th1 = cpu_to_le16(conf->per_th1); |
1664 | acx->per_th2 = cpu_to_le16(conf->per_th2); |
1665 | acx->max_per = cpu_to_le16(conf->max_per); |
1666 | acx->inverse_curiosity_factor = conf->inverse_curiosity_factor; |
1667 | acx->tx_fail_low_th = conf->tx_fail_low_th; |
1668 | acx->tx_fail_high_th = conf->tx_fail_high_th; |
1669 | acx->per_alpha_shift = conf->per_alpha_shift; |
1670 | acx->per_add_shift = conf->per_add_shift; |
1671 | acx->per_beta1_shift = conf->per_beta1_shift; |
1672 | acx->per_beta2_shift = conf->per_beta2_shift; |
1673 | acx->rate_check_up = conf->rate_check_up; |
1674 | acx->rate_check_down = conf->rate_check_down; |
1675 | memcpy(acx->rate_retry_policy, conf->rate_retry_policy, |
1676 | sizeof(acx->rate_retry_policy)); |
1677 | |
1678 | ret = wl1271_cmd_configure(wl, id: ACX_SET_RATE_MGMT_PARAMS, |
1679 | buf: acx, len: sizeof(*acx)); |
1680 | if (ret < 0) { |
1681 | wl1271_warning("acx set rate mgmt params failed: %d" , ret); |
1682 | goto out; |
1683 | } |
1684 | |
1685 | out: |
1686 | kfree(objp: acx); |
1687 | return ret; |
1688 | } |
1689 | |
1690 | int wl12xx_acx_config_hangover(struct wl1271 *wl) |
1691 | { |
1692 | struct wl12xx_acx_config_hangover *acx; |
1693 | struct conf_hangover_settings *conf = &wl->conf.hangover; |
1694 | int ret; |
1695 | |
1696 | wl1271_debug(DEBUG_ACX, "acx config hangover" ); |
1697 | |
1698 | acx = kzalloc(size: sizeof(*acx), GFP_KERNEL); |
1699 | if (!acx) { |
1700 | ret = -ENOMEM; |
1701 | goto out; |
1702 | } |
1703 | |
1704 | acx->recover_time = cpu_to_le32(conf->recover_time); |
1705 | acx->hangover_period = conf->hangover_period; |
1706 | acx->dynamic_mode = conf->dynamic_mode; |
1707 | acx->early_termination_mode = conf->early_termination_mode; |
1708 | acx->max_period = conf->max_period; |
1709 | acx->min_period = conf->min_period; |
1710 | acx->increase_delta = conf->increase_delta; |
1711 | acx->decrease_delta = conf->decrease_delta; |
1712 | acx->quiet_time = conf->quiet_time; |
1713 | acx->increase_time = conf->increase_time; |
1714 | acx->window_size = conf->window_size; |
1715 | |
1716 | ret = wl1271_cmd_configure(wl, id: ACX_CONFIG_HANGOVER, buf: acx, |
1717 | len: sizeof(*acx)); |
1718 | |
1719 | if (ret < 0) { |
1720 | wl1271_warning("acx config hangover failed: %d" , ret); |
1721 | goto out; |
1722 | } |
1723 | |
1724 | out: |
1725 | kfree(objp: acx); |
1726 | return ret; |
1727 | |
1728 | } |
1729 | |
1730 | int (struct wl1271 *wl, struct wl12xx_vif *wlvif, |
1731 | s8 *) |
1732 | { |
1733 | struct acx_roaming_stats *acx; |
1734 | int ret = 0; |
1735 | |
1736 | wl1271_debug(DEBUG_ACX, "acx roaming statistics" ); |
1737 | |
1738 | acx = kzalloc(size: sizeof(*acx), GFP_KERNEL); |
1739 | if (!acx) { |
1740 | ret = -ENOMEM; |
1741 | goto out; |
1742 | } |
1743 | |
1744 | acx->role_id = wlvif->role_id; |
1745 | ret = wl1271_cmd_interrogate(wl, id: ACX_ROAMING_STATISTICS_TBL, |
1746 | buf: acx, cmd_len: sizeof(*acx), res_len: sizeof(*acx)); |
1747 | if (ret < 0) { |
1748 | wl1271_warning("acx roaming statistics failed: %d" , ret); |
1749 | ret = -ENOMEM; |
1750 | goto out; |
1751 | } |
1752 | |
1753 | *avg_rssi = acx->rssi_beacon; |
1754 | out: |
1755 | kfree(objp: acx); |
1756 | return ret; |
1757 | } |
1758 | |
1759 | #ifdef CONFIG_PM |
1760 | /* Set the global behaviour of RX filters - On/Off + default action */ |
1761 | int wl1271_acx_default_rx_filter_enable(struct wl1271 *wl, bool enable, |
1762 | enum rx_filter_action action) |
1763 | { |
1764 | struct acx_default_rx_filter *acx; |
1765 | int ret; |
1766 | |
1767 | wl1271_debug(DEBUG_ACX, "acx default rx filter en: %d act: %d" , |
1768 | enable, action); |
1769 | |
1770 | acx = kzalloc(size: sizeof(*acx), GFP_KERNEL); |
1771 | if (!acx) |
1772 | return -ENOMEM; |
1773 | |
1774 | acx->enable = enable; |
1775 | acx->default_action = action; |
1776 | |
1777 | ret = wl1271_cmd_configure(wl, id: ACX_ENABLE_RX_DATA_FILTER, buf: acx, |
1778 | len: sizeof(*acx)); |
1779 | if (ret < 0) { |
1780 | wl1271_warning("acx default rx filter enable failed: %d" , ret); |
1781 | goto out; |
1782 | } |
1783 | |
1784 | out: |
1785 | kfree(objp: acx); |
1786 | return ret; |
1787 | } |
1788 | |
1789 | /* Configure or disable a specific RX filter pattern */ |
1790 | int wl1271_acx_set_rx_filter(struct wl1271 *wl, u8 index, bool enable, |
1791 | struct wl12xx_rx_filter *filter) |
1792 | { |
1793 | struct acx_rx_filter_cfg *acx; |
1794 | int fields_size = 0; |
1795 | int acx_size; |
1796 | int ret; |
1797 | |
1798 | WARN_ON(enable && !filter); |
1799 | WARN_ON(index >= WL1271_MAX_RX_FILTERS); |
1800 | |
1801 | wl1271_debug(DEBUG_ACX, |
1802 | "acx set rx filter idx: %d enable: %d filter: %p" , |
1803 | index, enable, filter); |
1804 | |
1805 | if (enable) { |
1806 | fields_size = wl1271_rx_filter_get_fields_size(filter); |
1807 | |
1808 | wl1271_debug(DEBUG_ACX, "act: %d num_fields: %d field_size: %d" , |
1809 | filter->action, filter->num_fields, fields_size); |
1810 | } |
1811 | |
1812 | acx_size = ALIGN(sizeof(*acx) + fields_size, 4); |
1813 | acx = kzalloc(size: acx_size, GFP_KERNEL); |
1814 | |
1815 | if (!acx) |
1816 | return -ENOMEM; |
1817 | |
1818 | acx->enable = enable; |
1819 | acx->index = index; |
1820 | |
1821 | if (enable) { |
1822 | acx->num_fields = filter->num_fields; |
1823 | acx->action = filter->action; |
1824 | wl1271_rx_filter_flatten_fields(filter, buf: acx->fields); |
1825 | } |
1826 | |
1827 | wl1271_dump(DEBUG_ACX, "RX_FILTER: " , acx, acx_size); |
1828 | |
1829 | ret = wl1271_cmd_configure(wl, id: ACX_SET_RX_DATA_FILTER, buf: acx, len: acx_size); |
1830 | if (ret < 0) { |
1831 | wl1271_warning("setting rx filter failed: %d" , ret); |
1832 | goto out; |
1833 | } |
1834 | |
1835 | out: |
1836 | kfree(objp: acx); |
1837 | return ret; |
1838 | } |
1839 | #endif /* CONFIG_PM */ |
1840 | |