linux/drivers/net/wireless/ti/wlcore/init.c
<<
>>
Prefs
   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
  37int 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
 158static 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
 179out:
 180        kfree(tmpl);
 181        return ret;
 182}
 183
 184static 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
 212out:
 213        kfree(nullfunc);
 214        return ret;
 215}
 216
 217static 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
 245out:
 246        kfree(qosnull);
 247        return ret;
 248}
 249
 250static 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
 261static 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
 281static 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        /* disable beacon filtering until we get the first beacon */
 291        ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false);
 292        if (ret < 0)
 293                return ret;
 294
 295        return 0;
 296}
 297
 298int 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
 313int 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
 324static 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
 336static 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) */
 351int 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
 372static 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) */
 387static 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        /* configure AP sleep, if enabled */
 396        ret = wlcore_hw_ap_sleep(wl);
 397        if (ret < 0)
 398                return ret;
 399
 400        return 0;
 401}
 402
 403int wl1271_ap_init_templates(struct wl1271 *wl, struct ieee80211_vif *vif)
 404{
 405        struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
 406        int ret;
 407
 408        ret = wl1271_ap_init_deauth_template(wl, wlvif);
 409        if (ret < 0)
 410                return ret;
 411
 412        ret = wl1271_ap_init_null_template(wl, vif);
 413        if (ret < 0)
 414                return ret;
 415
 416        ret = wl1271_ap_init_qos_null_template(wl, vif);
 417        if (ret < 0)
 418                return ret;
 419
 420        /*
 421         * when operating as AP we want to receive external beacons for
 422         * configuring ERP protection.
 423         */
 424        ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false);
 425        if (ret < 0)
 426                return ret;
 427
 428        return 0;
 429}
 430
 431static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl,
 432                                      struct ieee80211_vif *vif)
 433{
 434        return wl1271_ap_init_templates(wl, vif);
 435}
 436
 437int wl1271_init_ap_rates(struct wl1271 *wl, struct wl12xx_vif *wlvif)
 438{
 439        int i, ret;
 440        struct conf_tx_rate_class rc;
 441        u32 supported_rates;
 442
 443        wl1271_debug(DEBUG_AP, "AP basic rate set: 0x%x",
 444                     wlvif->basic_rate_set);
 445
 446        if (wlvif->basic_rate_set == 0)
 447                return -EINVAL;
 448
 449        rc.enabled_rates = wlvif->basic_rate_set;
 450        rc.long_retry_limit = 10;
 451        rc.short_retry_limit = 10;
 452        rc.aflags = 0;
 453        ret = wl1271_acx_ap_rate_policy(wl, &rc, wlvif->ap.mgmt_rate_idx);
 454        if (ret < 0)
 455                return ret;
 456
 457        /* use the min basic rate for AP broadcast/multicast */
 458        rc.enabled_rates = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
 459        rc.short_retry_limit = 10;
 460        rc.long_retry_limit = 10;
 461        rc.aflags = 0;
 462        ret = wl1271_acx_ap_rate_policy(wl, &rc, wlvif->ap.bcast_rate_idx);
 463        if (ret < 0)
 464                return ret;
 465
 466        /*
 467         * If the basic rates contain OFDM rates, use OFDM only
 468         * rates for unicast TX as well. Else use all supported rates.
 469         */
 470        if (wl->ofdm_only_ap && (wlvif->basic_rate_set & CONF_TX_OFDM_RATES))
 471                supported_rates = CONF_TX_OFDM_RATES;
 472        else
 473                supported_rates = CONF_TX_ENABLED_RATES;
 474
 475        /* unconditionally enable HT rates */
 476        supported_rates |= CONF_TX_MCS_RATES;
 477
 478        /* get extra MIMO or wide-chan rates where the HW supports it */
 479        supported_rates |= wlcore_hw_ap_get_mimo_wide_rate_mask(wl, wlvif);
 480
 481        /* configure unicast TX rate classes */
 482        for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
 483                rc.enabled_rates = supported_rates;
 484                rc.short_retry_limit = 10;
 485                rc.long_retry_limit = 10;
 486                rc.aflags = 0;
 487                ret = wl1271_acx_ap_rate_policy(wl, &rc,
 488                                                wlvif->ap.ucast_rate_idx[i]);
 489                if (ret < 0)
 490                        return ret;
 491        }
 492
 493        return 0;
 494}
 495
 496static int wl1271_set_ba_policies(struct wl1271 *wl, struct wl12xx_vif *wlvif)
 497{
 498        /* Reset the BA RX indicators */
 499        wlvif->ba_allowed = true;
 500        wl->ba_rx_session_count = 0;
 501
 502        /* BA is supported in STA/AP modes */
 503        if (wlvif->bss_type != BSS_TYPE_AP_BSS &&
 504            wlvif->bss_type != BSS_TYPE_STA_BSS) {
 505                wlvif->ba_support = false;
 506                return 0;
 507        }
 508
 509        wlvif->ba_support = true;
 510
 511        /* 802.11n initiator BA session setting */
 512        return wl12xx_acx_set_ba_initiator_policy(wl, wlvif);
 513}
 514
 515/* vif-specifc initialization */
 516static int wl12xx_init_sta_role(struct wl1271 *wl, struct wl12xx_vif *wlvif)
 517{
 518        int ret;
 519
 520        ret = wl1271_acx_group_address_tbl(wl, wlvif, true, NULL, 0);
 521        if (ret < 0)
 522                return ret;
 523
 524        /* Initialize connection monitoring thresholds */
 525        ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
 526        if (ret < 0)
 527                return ret;
 528
 529        /* Beacon filtering */
 530        ret = wl1271_init_sta_beacon_filter(wl, wlvif);
 531        if (ret < 0)
 532                return ret;
 533
 534        /* Beacons and broadcast settings */
 535        ret = wl1271_init_beacon_broadcast(wl, wlvif);
 536        if (ret < 0)
 537                return ret;
 538
 539        /* Configure rssi/snr averaging weights */
 540        ret = wl1271_acx_rssi_snr_avg_weights(wl, wlvif);
 541        if (ret < 0)
 542                return ret;
 543
 544        return 0;
 545}
 546
 547/* vif-specific intialization */
 548static int wl12xx_init_ap_role(struct wl1271 *wl, struct wl12xx_vif *wlvif)
 549{
 550        int ret;
 551
 552        ret = wl1271_acx_ap_max_tx_retry(wl, wlvif);
 553        if (ret < 0)
 554                return ret;
 555
 556        /* initialize Tx power */
 557        ret = wl1271_acx_tx_power(wl, wlvif, wlvif->power_level);
 558        if (ret < 0)
 559                return ret;
 560
 561        return 0;
 562}
 563
 564int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif)
 565{
 566        struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
 567        struct conf_tx_ac_category *conf_ac;
 568        struct conf_tx_tid *conf_tid;
 569        bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
 570        int ret, i;
 571
 572        /* consider all existing roles before configuring psm. */
 573
 574        if (wl->ap_count == 0 && is_ap) { /* first AP */
 575                ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
 576                if (ret < 0)
 577                        return ret;
 578
 579                /* unmask ap events */
 580                wl->event_mask |= wl->ap_event_mask;
 581                ret = wl1271_event_unmask(wl);
 582                if (ret < 0)
 583                        return ret;
 584        /* first STA, no APs */
 585        } else if (wl->sta_count == 0 && wl->ap_count == 0 && !is_ap) {
 586                u8 sta_auth = wl->conf.conn.sta_sleep_auth;
 587                /* Configure for power according to debugfs */
 588                if (sta_auth != WL1271_PSM_ILLEGAL)
 589                        ret = wl1271_acx_sleep_auth(wl, sta_auth);
 590                /* Configure for ELP power saving */
 591                else
 592                        ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
 593
 594                if (ret < 0)
 595                        return ret;
 596        }
 597
 598        /* Mode specific init */
 599        if (is_ap) {
 600                ret = wl1271_ap_hw_init(wl, wlvif);
 601                if (ret < 0)
 602                        return ret;
 603
 604                ret = wl12xx_init_ap_role(wl, wlvif);
 605                if (ret < 0)
 606                        return ret;
 607        } else {
 608                ret = wl1271_sta_hw_init(wl, wlvif);
 609                if (ret < 0)
 610                        return ret;
 611
 612                ret = wl12xx_init_sta_role(wl, wlvif);
 613                if (ret < 0)
 614                        return ret;
 615        }
 616
 617        wl12xx_init_phy_vif_config(wl, wlvif);
 618
 619        /* Default TID/AC configuration */
 620        BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
 621        for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
 622                conf_ac = &wl->conf.tx.ac_conf[i];
 623                ret = wl1271_acx_ac_cfg(wl, wlvif, conf_ac->ac,
 624                                        conf_ac->cw_min, conf_ac->cw_max,
 625                                        conf_ac->aifsn, conf_ac->tx_op_limit);
 626                if (ret < 0)
 627                        return ret;
 628
 629                conf_tid = &wl->conf.tx.tid_conf[i];
 630                ret = wl1271_acx_tid_cfg(wl, wlvif,
 631                                         conf_tid->queue_id,
 632                                         conf_tid->channel_type,
 633                                         conf_tid->tsid,
 634                                         conf_tid->ps_scheme,
 635                                         conf_tid->ack_policy,
 636                                         conf_tid->apsd_conf[0],
 637                                         conf_tid->apsd_conf[1]);
 638                if (ret < 0)
 639                        return ret;
 640        }
 641
 642        /* Configure HW encryption */
 643        ret = wl1271_acx_feature_cfg(wl, wlvif);
 644        if (ret < 0)
 645                return ret;
 646
 647        /* Mode specific init - post mem init */
 648        if (is_ap)
 649                ret = wl1271_ap_hw_init_post_mem(wl, vif);
 650        else
 651                ret = wl1271_sta_hw_init_post_mem(wl, vif);
 652
 653        if (ret < 0)
 654                return ret;
 655
 656        /* Configure initiator BA sessions policies */
 657        ret = wl1271_set_ba_policies(wl, wlvif);
 658        if (ret < 0)
 659                return ret;
 660
 661        ret = wlcore_hw_init_vif(wl, wlvif);
 662        if (ret < 0)
 663                return ret;
 664
 665        return 0;
 666}
 667
 668int wl1271_hw_init(struct wl1271 *wl)
 669{
 670        int ret;
 671
 672        /* Chip-specific hw init */
 673        ret = wl->ops->hw_init(wl);
 674        if (ret < 0)
 675                return ret;
 676
 677        /* Init templates */
 678        ret = wl1271_init_templates_config(wl);
 679        if (ret < 0)
 680                return ret;
 681
 682        ret = wl12xx_acx_mem_cfg(wl);
 683        if (ret < 0)
 684                return ret;
 685
 686        /* Configure the FW logger */
 687        ret = wl12xx_init_fwlog(wl);
 688        if (ret < 0)
 689                return ret;
 690
 691        ret = wlcore_cmd_regdomain_config_locked(wl);
 692        if (ret < 0)
 693                return ret;
 694
 695        /* Bluetooth WLAN coexistence */
 696        ret = wl1271_init_pta(wl);
 697        if (ret < 0)
 698                return ret;
 699
 700        /* Default memory configuration */
 701        ret = wl1271_acx_init_mem_config(wl);
 702        if (ret < 0)
 703                return ret;
 704
 705        /* RX config */
 706        ret = wl12xx_init_rx_config(wl);
 707        if (ret < 0)
 708                goto out_free_memmap;
 709
 710        ret = wl1271_acx_dco_itrim_params(wl);
 711        if (ret < 0)
 712                goto out_free_memmap;
 713
 714        /* Configure TX patch complete interrupt behavior */
 715        ret = wl1271_acx_tx_config_options(wl);
 716        if (ret < 0)
 717                goto out_free_memmap;
 718
 719        /* RX complete interrupt pacing */
 720        ret = wl1271_acx_init_rx_interrupt(wl);
 721        if (ret < 0)
 722                goto out_free_memmap;
 723
 724        /* Energy detection */
 725        ret = wl1271_init_energy_detection(wl);
 726        if (ret < 0)
 727                goto out_free_memmap;
 728
 729        /* Default fragmentation threshold */
 730        ret = wl1271_acx_frag_threshold(wl, wl->hw->wiphy->frag_threshold);
 731        if (ret < 0)
 732                goto out_free_memmap;
 733
 734        /* Enable data path */
 735        ret = wl1271_cmd_data_path(wl, 1);
 736        if (ret < 0)
 737                goto out_free_memmap;
 738
 739        /* configure PM */
 740        ret = wl1271_acx_pm_config(wl);
 741        if (ret < 0)
 742                goto out_free_memmap;
 743
 744        ret = wl12xx_acx_set_rate_mgmt_params(wl);
 745        if (ret < 0)
 746                goto out_free_memmap;
 747
 748        /* configure hangover */
 749        ret = wl12xx_acx_config_hangover(wl);
 750        if (ret < 0)
 751                goto out_free_memmap;
 752
 753        return 0;
 754
 755 out_free_memmap:
 756        kfree(wl->target_mem_map);
 757        wl->target_mem_map = NULL;
 758
 759        return ret;
 760}
 761