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