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        /* 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
 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) */
 351static 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
 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        return 0;
 396}
 397
 398int 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
 426static 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
 432int 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
 491static 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 */
 511static 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 */
 543static 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
 559int 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
 658int 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}
 751