Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
[deliverable/linux.git] / drivers / net / wireless / ti / wlcore / init.c
1 /*
2 * This file is part of wl1271
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24 #include <linux/kernel.h>
25 #include <linux/module.h>
26 #include <linux/slab.h>
27
28 #include "debug.h"
29 #include "init.h"
30 #include "wl12xx_80211.h"
31 #include "acx.h"
32 #include "cmd.h"
33 #include "tx.h"
34 #include "io.h"
35 #include "hw_ops.h"
36
37 int wl1271_init_templates_config(struct wl1271 *wl)
38 {
39 int ret, i;
40 size_t max_size;
41
42 /* send empty templates for fw memory reservation */
43 ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
44 CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL,
45 WL1271_CMD_TEMPL_MAX_SIZE,
46 0, WL1271_RATE_AUTOMATIC);
47 if (ret < 0)
48 return ret;
49
50 ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
51 CMD_TEMPL_CFG_PROBE_REQ_5,
52 NULL, WL1271_CMD_TEMPL_MAX_SIZE, 0,
53 WL1271_RATE_AUTOMATIC);
54 if (ret < 0)
55 return ret;
56
57 ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
58 CMD_TEMPL_NULL_DATA, NULL,
59 sizeof(struct wl12xx_null_data_template),
60 0, WL1271_RATE_AUTOMATIC);
61 if (ret < 0)
62 return ret;
63
64 ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
65 CMD_TEMPL_PS_POLL, NULL,
66 sizeof(struct wl12xx_ps_poll_template),
67 0, WL1271_RATE_AUTOMATIC);
68 if (ret < 0)
69 return ret;
70
71 ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
72 CMD_TEMPL_QOS_NULL_DATA, NULL,
73 sizeof
74 (struct ieee80211_qos_hdr),
75 0, WL1271_RATE_AUTOMATIC);
76 if (ret < 0)
77 return ret;
78
79 ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
80 CMD_TEMPL_PROBE_RESPONSE, NULL,
81 WL1271_CMD_TEMPL_DFLT_SIZE,
82 0, WL1271_RATE_AUTOMATIC);
83 if (ret < 0)
84 return ret;
85
86 ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
87 CMD_TEMPL_BEACON, NULL,
88 WL1271_CMD_TEMPL_DFLT_SIZE,
89 0, WL1271_RATE_AUTOMATIC);
90 if (ret < 0)
91 return ret;
92
93 max_size = sizeof(struct wl12xx_arp_rsp_template) +
94 WL1271_EXTRA_SPACE_MAX;
95 ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
96 CMD_TEMPL_ARP_RSP, NULL,
97 max_size,
98 0, WL1271_RATE_AUTOMATIC);
99 if (ret < 0)
100 return ret;
101
102 /*
103 * Put very large empty placeholders for all templates. These
104 * reserve memory for later.
105 */
106 ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
107 CMD_TEMPL_AP_PROBE_RESPONSE, NULL,
108 WL1271_CMD_TEMPL_MAX_SIZE,
109 0, WL1271_RATE_AUTOMATIC);
110 if (ret < 0)
111 return ret;
112
113 ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
114 CMD_TEMPL_AP_BEACON, NULL,
115 WL1271_CMD_TEMPL_MAX_SIZE,
116 0, WL1271_RATE_AUTOMATIC);
117 if (ret < 0)
118 return ret;
119
120 ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
121 CMD_TEMPL_DEAUTH_AP, NULL,
122 sizeof
123 (struct wl12xx_disconn_template),
124 0, WL1271_RATE_AUTOMATIC);
125 if (ret < 0)
126 return ret;
127
128 for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) {
129 ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
130 CMD_TEMPL_KLV, NULL,
131 sizeof(struct ieee80211_qos_hdr),
132 i, WL1271_RATE_AUTOMATIC);
133 if (ret < 0)
134 return ret;
135 }
136
137 return 0;
138 }
139
140 static int wl1271_ap_init_deauth_template(struct wl1271 *wl,
141 struct wl12xx_vif *wlvif)
142 {
143 struct wl12xx_disconn_template *tmpl;
144 int ret;
145 u32 rate;
146
147 tmpl = kzalloc(sizeof(*tmpl), GFP_KERNEL);
148 if (!tmpl) {
149 ret = -ENOMEM;
150 goto out;
151 }
152
153 tmpl->header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT |
154 IEEE80211_STYPE_DEAUTH);
155
156 rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
157 ret = wl1271_cmd_template_set(wl, wlvif->role_id,
158 CMD_TEMPL_DEAUTH_AP,
159 tmpl, sizeof(*tmpl), 0, rate);
160
161 out:
162 kfree(tmpl);
163 return ret;
164 }
165
166 static int wl1271_ap_init_null_template(struct wl1271 *wl,
167 struct ieee80211_vif *vif)
168 {
169 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
170 struct ieee80211_hdr_3addr *nullfunc;
171 int ret;
172 u32 rate;
173
174 nullfunc = kzalloc(sizeof(*nullfunc), GFP_KERNEL);
175 if (!nullfunc) {
176 ret = -ENOMEM;
177 goto out;
178 }
179
180 nullfunc->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
181 IEEE80211_STYPE_NULLFUNC |
182 IEEE80211_FCTL_FROMDS);
183
184 /* nullfunc->addr1 is filled by FW */
185
186 memcpy(nullfunc->addr2, vif->addr, ETH_ALEN);
187 memcpy(nullfunc->addr3, vif->addr, ETH_ALEN);
188
189 rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
190 ret = wl1271_cmd_template_set(wl, wlvif->role_id,
191 CMD_TEMPL_NULL_DATA, nullfunc,
192 sizeof(*nullfunc), 0, rate);
193
194 out:
195 kfree(nullfunc);
196 return ret;
197 }
198
199 static int wl1271_ap_init_qos_null_template(struct wl1271 *wl,
200 struct ieee80211_vif *vif)
201 {
202 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
203 struct ieee80211_qos_hdr *qosnull;
204 int ret;
205 u32 rate;
206
207 qosnull = kzalloc(sizeof(*qosnull), GFP_KERNEL);
208 if (!qosnull) {
209 ret = -ENOMEM;
210 goto out;
211 }
212
213 qosnull->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
214 IEEE80211_STYPE_QOS_NULLFUNC |
215 IEEE80211_FCTL_FROMDS);
216
217 /* qosnull->addr1 is filled by FW */
218
219 memcpy(qosnull->addr2, vif->addr, ETH_ALEN);
220 memcpy(qosnull->addr3, vif->addr, ETH_ALEN);
221
222 rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
223 ret = wl1271_cmd_template_set(wl, wlvif->role_id,
224 CMD_TEMPL_QOS_NULL_DATA, qosnull,
225 sizeof(*qosnull), 0, rate);
226
227 out:
228 kfree(qosnull);
229 return ret;
230 }
231
232 static int wl12xx_init_rx_config(struct wl1271 *wl)
233 {
234 int ret;
235
236 ret = wl1271_acx_rx_msdu_life_time(wl);
237 if (ret < 0)
238 return ret;
239
240 return 0;
241 }
242
243 static int wl12xx_init_phy_vif_config(struct wl1271 *wl,
244 struct wl12xx_vif *wlvif)
245 {
246 int ret;
247
248 ret = wl1271_acx_slot(wl, wlvif, DEFAULT_SLOT_TIME);
249 if (ret < 0)
250 return ret;
251
252 ret = wl1271_acx_service_period_timeout(wl, wlvif);
253 if (ret < 0)
254 return ret;
255
256 ret = wl1271_acx_rts_threshold(wl, wlvif, wl->hw->wiphy->rts_threshold);
257 if (ret < 0)
258 return ret;
259
260 return 0;
261 }
262
263 static int wl1271_init_sta_beacon_filter(struct wl1271 *wl,
264 struct wl12xx_vif *wlvif)
265 {
266 int ret;
267
268 ret = wl1271_acx_beacon_filter_table(wl, wlvif);
269 if (ret < 0)
270 return ret;
271
272 /* enable beacon filtering */
273 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
274 if (ret < 0)
275 return ret;
276
277 return 0;
278 }
279
280 int wl1271_init_pta(struct wl1271 *wl)
281 {
282 int ret;
283
284 ret = wl12xx_acx_sg_cfg(wl);
285 if (ret < 0)
286 return ret;
287
288 ret = wl1271_acx_sg_enable(wl, wl->sg_enabled);
289 if (ret < 0)
290 return ret;
291
292 return 0;
293 }
294
295 int wl1271_init_energy_detection(struct wl1271 *wl)
296 {
297 int ret;
298
299 ret = wl1271_acx_cca_threshold(wl);
300 if (ret < 0)
301 return ret;
302
303 return 0;
304 }
305
306 static int wl1271_init_beacon_broadcast(struct wl1271 *wl,
307 struct wl12xx_vif *wlvif)
308 {
309 int ret;
310
311 ret = wl1271_acx_bcn_dtim_options(wl, wlvif);
312 if (ret < 0)
313 return ret;
314
315 return 0;
316 }
317
318 static int wl12xx_init_fwlog(struct wl1271 *wl)
319 {
320 int ret;
321
322 if (wl->quirks & WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED)
323 return 0;
324
325 ret = wl12xx_cmd_config_fwlog(wl);
326 if (ret < 0)
327 return ret;
328
329 return 0;
330 }
331
332 /* generic sta initialization (non vif-specific) */
333 static int wl1271_sta_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif)
334 {
335 int ret;
336
337 /* PS config */
338 ret = wl12xx_acx_config_ps(wl, wlvif);
339 if (ret < 0)
340 return ret;
341
342 /* FM WLAN coexistence */
343 ret = wl1271_acx_fm_coex(wl);
344 if (ret < 0)
345 return ret;
346
347 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
348 if (ret < 0)
349 return ret;
350
351 return 0;
352 }
353
354 static int wl1271_sta_hw_init_post_mem(struct wl1271 *wl,
355 struct ieee80211_vif *vif)
356 {
357 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
358 int ret, i;
359
360 /* disable all keep-alive templates */
361 for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) {
362 ret = wl1271_acx_keep_alive_config(wl, wlvif, i,
363 ACX_KEEP_ALIVE_TPL_INVALID);
364 if (ret < 0)
365 return ret;
366 }
367
368 /* disable the keep-alive feature */
369 ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
370 if (ret < 0)
371 return ret;
372
373 return 0;
374 }
375
376 /* generic ap initialization (non vif-specific) */
377 static int wl1271_ap_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif)
378 {
379 int ret;
380
381 ret = wl1271_init_ap_rates(wl, wlvif);
382 if (ret < 0)
383 return ret;
384
385 return 0;
386 }
387
388 int wl1271_ap_init_templates(struct wl1271 *wl, struct ieee80211_vif *vif)
389 {
390 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
391 int ret;
392
393 ret = wl1271_ap_init_deauth_template(wl, wlvif);
394 if (ret < 0)
395 return ret;
396
397 ret = wl1271_ap_init_null_template(wl, vif);
398 if (ret < 0)
399 return ret;
400
401 ret = wl1271_ap_init_qos_null_template(wl, vif);
402 if (ret < 0)
403 return ret;
404
405 /*
406 * when operating as AP we want to receive external beacons for
407 * configuring ERP protection.
408 */
409 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false);
410 if (ret < 0)
411 return ret;
412
413 return 0;
414 }
415
416 static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl,
417 struct ieee80211_vif *vif)
418 {
419 return wl1271_ap_init_templates(wl, vif);
420 }
421
422 int wl1271_init_ap_rates(struct wl1271 *wl, struct wl12xx_vif *wlvif)
423 {
424 int i, ret;
425 struct conf_tx_rate_class rc;
426 u32 supported_rates;
427
428 wl1271_debug(DEBUG_AP, "AP basic rate set: 0x%x",
429 wlvif->basic_rate_set);
430
431 if (wlvif->basic_rate_set == 0)
432 return -EINVAL;
433
434 rc.enabled_rates = wlvif->basic_rate_set;
435 rc.long_retry_limit = 10;
436 rc.short_retry_limit = 10;
437 rc.aflags = 0;
438 ret = wl1271_acx_ap_rate_policy(wl, &rc, wlvif->ap.mgmt_rate_idx);
439 if (ret < 0)
440 return ret;
441
442 /* use the min basic rate for AP broadcast/multicast */
443 rc.enabled_rates = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
444 rc.short_retry_limit = 10;
445 rc.long_retry_limit = 10;
446 rc.aflags = 0;
447 ret = wl1271_acx_ap_rate_policy(wl, &rc, wlvif->ap.bcast_rate_idx);
448 if (ret < 0)
449 return ret;
450
451 /*
452 * If the basic rates contain OFDM rates, use OFDM only
453 * rates for unicast TX as well. Else use all supported rates.
454 */
455 if ((wlvif->basic_rate_set & CONF_TX_OFDM_RATES))
456 supported_rates = CONF_TX_OFDM_RATES;
457 else
458 supported_rates = CONF_TX_AP_ENABLED_RATES;
459
460 /* unconditionally enable HT rates */
461 supported_rates |= CONF_TX_MCS_RATES;
462
463 /* configure unicast TX rate classes */
464 for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
465 rc.enabled_rates = supported_rates;
466 rc.short_retry_limit = 10;
467 rc.long_retry_limit = 10;
468 rc.aflags = 0;
469 ret = wl1271_acx_ap_rate_policy(wl, &rc,
470 wlvif->ap.ucast_rate_idx[i]);
471 if (ret < 0)
472 return ret;
473 }
474
475 return 0;
476 }
477
478 static int wl1271_set_ba_policies(struct wl1271 *wl, struct wl12xx_vif *wlvif)
479 {
480 /* Reset the BA RX indicators */
481 wlvif->ba_allowed = true;
482 wl->ba_rx_session_count = 0;
483
484 /* BA is supported in STA/AP modes */
485 if (wlvif->bss_type != BSS_TYPE_AP_BSS &&
486 wlvif->bss_type != BSS_TYPE_STA_BSS) {
487 wlvif->ba_support = false;
488 return 0;
489 }
490
491 wlvif->ba_support = true;
492
493 /* 802.11n initiator BA session setting */
494 return wl12xx_acx_set_ba_initiator_policy(wl, wlvif);
495 }
496
497 /* vif-specifc initialization */
498 static int wl12xx_init_sta_role(struct wl1271 *wl, struct wl12xx_vif *wlvif)
499 {
500 int ret;
501
502 ret = wl1271_acx_group_address_tbl(wl, wlvif, true, NULL, 0);
503 if (ret < 0)
504 return ret;
505
506 /* Initialize connection monitoring thresholds */
507 ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
508 if (ret < 0)
509 return ret;
510
511 /* Beacon filtering */
512 ret = wl1271_init_sta_beacon_filter(wl, wlvif);
513 if (ret < 0)
514 return ret;
515
516 /* Beacons and broadcast settings */
517 ret = wl1271_init_beacon_broadcast(wl, wlvif);
518 if (ret < 0)
519 return ret;
520
521 /* Configure rssi/snr averaging weights */
522 ret = wl1271_acx_rssi_snr_avg_weights(wl, wlvif);
523 if (ret < 0)
524 return ret;
525
526 return 0;
527 }
528
529 /* vif-specific intialization */
530 static int wl12xx_init_ap_role(struct wl1271 *wl, struct wl12xx_vif *wlvif)
531 {
532 int ret;
533
534 ret = wl1271_acx_ap_max_tx_retry(wl, wlvif);
535 if (ret < 0)
536 return ret;
537
538 /* initialize Tx power */
539 ret = wl1271_acx_tx_power(wl, wlvif, wlvif->power_level);
540 if (ret < 0)
541 return ret;
542
543 return 0;
544 }
545
546 int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif)
547 {
548 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
549 struct conf_tx_ac_category *conf_ac;
550 struct conf_tx_tid *conf_tid;
551 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
552 int ret, i;
553
554 /*
555 * consider all existing roles before configuring psm.
556 * TODO: reconfigure on interface removal.
557 */
558 if (!wl->ap_count) {
559 if (is_ap) {
560 /* Configure for power always on */
561 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
562 if (ret < 0)
563 return ret;
564 } else if (!wl->sta_count) {
565 if (wl->quirks & WLCORE_QUIRK_NO_ELP) {
566 /* Configure for power always on */
567 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
568 if (ret < 0)
569 return ret;
570 } else {
571 /* Configure for ELP power saving */
572 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
573 if (ret < 0)
574 return ret;
575 }
576 }
577 }
578
579 /* Mode specific init */
580 if (is_ap) {
581 ret = wl1271_ap_hw_init(wl, wlvif);
582 if (ret < 0)
583 return ret;
584
585 ret = wl12xx_init_ap_role(wl, wlvif);
586 if (ret < 0)
587 return ret;
588 } else {
589 ret = wl1271_sta_hw_init(wl, wlvif);
590 if (ret < 0)
591 return ret;
592
593 ret = wl12xx_init_sta_role(wl, wlvif);
594 if (ret < 0)
595 return ret;
596 }
597
598 wl12xx_init_phy_vif_config(wl, wlvif);
599
600 /* Default TID/AC configuration */
601 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
602 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
603 conf_ac = &wl->conf.tx.ac_conf[i];
604 ret = wl1271_acx_ac_cfg(wl, wlvif, conf_ac->ac,
605 conf_ac->cw_min, conf_ac->cw_max,
606 conf_ac->aifsn, conf_ac->tx_op_limit);
607 if (ret < 0)
608 return ret;
609
610 conf_tid = &wl->conf.tx.tid_conf[i];
611 ret = wl1271_acx_tid_cfg(wl, wlvif,
612 conf_tid->queue_id,
613 conf_tid->channel_type,
614 conf_tid->tsid,
615 conf_tid->ps_scheme,
616 conf_tid->ack_policy,
617 conf_tid->apsd_conf[0],
618 conf_tid->apsd_conf[1]);
619 if (ret < 0)
620 return ret;
621 }
622
623 /* Configure HW encryption */
624 ret = wl1271_acx_feature_cfg(wl, wlvif);
625 if (ret < 0)
626 return ret;
627
628 /* Mode specific init - post mem init */
629 if (is_ap)
630 ret = wl1271_ap_hw_init_post_mem(wl, vif);
631 else
632 ret = wl1271_sta_hw_init_post_mem(wl, vif);
633
634 if (ret < 0)
635 return ret;
636
637 /* Configure initiator BA sessions policies */
638 ret = wl1271_set_ba_policies(wl, wlvif);
639 if (ret < 0)
640 return ret;
641
642 ret = wlcore_hw_init_vif(wl, wlvif);
643 if (ret < 0)
644 return ret;
645
646 return 0;
647 }
648
649 int wl1271_hw_init(struct wl1271 *wl)
650 {
651 int ret;
652
653 /* Chip-specific hw init */
654 ret = wl->ops->hw_init(wl);
655 if (ret < 0)
656 return ret;
657
658 /* Init templates */
659 ret = wl1271_init_templates_config(wl);
660 if (ret < 0)
661 return ret;
662
663 ret = wl12xx_acx_mem_cfg(wl);
664 if (ret < 0)
665 return ret;
666
667 /* Configure the FW logger */
668 ret = wl12xx_init_fwlog(wl);
669 if (ret < 0)
670 return ret;
671
672 /* Bluetooth WLAN coexistence */
673 ret = wl1271_init_pta(wl);
674 if (ret < 0)
675 return ret;
676
677 /* Default memory configuration */
678 ret = wl1271_acx_init_mem_config(wl);
679 if (ret < 0)
680 return ret;
681
682 /* RX config */
683 ret = wl12xx_init_rx_config(wl);
684 if (ret < 0)
685 goto out_free_memmap;
686
687 ret = wl1271_acx_dco_itrim_params(wl);
688 if (ret < 0)
689 goto out_free_memmap;
690
691 /* Configure TX patch complete interrupt behavior */
692 ret = wl1271_acx_tx_config_options(wl);
693 if (ret < 0)
694 goto out_free_memmap;
695
696 /* RX complete interrupt pacing */
697 ret = wl1271_acx_init_rx_interrupt(wl);
698 if (ret < 0)
699 goto out_free_memmap;
700
701 /* Energy detection */
702 ret = wl1271_init_energy_detection(wl);
703 if (ret < 0)
704 goto out_free_memmap;
705
706 /* Default fragmentation threshold */
707 ret = wl1271_acx_frag_threshold(wl, wl->hw->wiphy->frag_threshold);
708 if (ret < 0)
709 goto out_free_memmap;
710
711 /* Enable data path */
712 ret = wl1271_cmd_data_path(wl, 1);
713 if (ret < 0)
714 goto out_free_memmap;
715
716 /* configure PM */
717 ret = wl1271_acx_pm_config(wl);
718 if (ret < 0)
719 goto out_free_memmap;
720
721 ret = wl12xx_acx_set_rate_mgmt_params(wl);
722 if (ret < 0)
723 goto out_free_memmap;
724
725 /* configure hangover */
726 ret = wl12xx_acx_config_hangover(wl);
727 if (ret < 0)
728 goto out_free_memmap;
729
730 return 0;
731
732 out_free_memmap:
733 kfree(wl->target_mem_map);
734 wl->target_mem_map = NULL;
735
736 return ret;
737 }
This page took 0.051188 seconds and 5 git commands to generate.