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 initialization */
 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        if (wl->radar_debug_mode)
 562                wlcore_cmd_generic_cfg(wl, wlvif,
 563                                       WLCORE_CFG_FEATURE_RADAR_DEBUG,
 564                                       wl->radar_debug_mode, 0);
 565
 566        return 0;
 567}
 568
 569int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif)
 570{
 571        struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
 572        struct conf_tx_ac_category *conf_ac;
 573        struct conf_tx_tid *conf_tid;
 574        bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
 575        int ret, i;
 576
 577        /* consider all existing roles before configuring psm. */
 578
 579        if (wl->ap_count == 0 && is_ap) { /* first AP */
 580                ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
 581                if (ret < 0)
 582                        return ret;
 583
 584                /* unmask ap events */
 585                wl->event_mask |= wl->ap_event_mask;
 586                ret = wl1271_event_unmask(wl);
 587                if (ret < 0)
 588                        return ret;
 589        /* first STA, no APs */
 590        } else if (wl->sta_count == 0 && wl->ap_count == 0 && !is_ap) {
 591                u8 sta_auth = wl->conf.conn.sta_sleep_auth;
 592                /* Configure for power according to debugfs */
 593                if (sta_auth != WL1271_PSM_ILLEGAL)
 594                        ret = wl1271_acx_sleep_auth(wl, sta_auth);
 595                /* Configure for ELP power saving */
 596                else
 597                        ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
 598
 599                if (ret < 0)
 600                        return ret;
 601        }
 602
 603        /* Mode specific init */
 604        if (is_ap) {
 605                ret = wl1271_ap_hw_init(wl, wlvif);
 606                if (ret < 0)
 607                        return ret;
 608
 609                ret = wl12xx_init_ap_role(wl, wlvif);
 610                if (ret < 0)
 611                        return ret;
 612        } else {
 613                ret = wl1271_sta_hw_init(wl, wlvif);
 614                if (ret < 0)
 615                        return ret;
 616
 617                ret = wl12xx_init_sta_role(wl, wlvif);
 618                if (ret < 0)
 619                        return ret;
 620        }
 621
 622        wl12xx_init_phy_vif_config(wl, wlvif);
 623
 624        /* Default TID/AC configuration */
 625        BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
 626        for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
 627                conf_ac = &wl->conf.tx.ac_conf[i];
 628                ret = wl1271_acx_ac_cfg(wl, wlvif, conf_ac->ac,
 629                                        conf_ac->cw_min, conf_ac->cw_max,
 630                                        conf_ac->aifsn, conf_ac->tx_op_limit);
 631                if (ret < 0)
 632                        return ret;
 633
 634                conf_tid = &wl->conf.tx.tid_conf[i];
 635                ret = wl1271_acx_tid_cfg(wl, wlvif,
 636                                         conf_tid->queue_id,
 637                                         conf_tid->channel_type,
 638                                         conf_tid->tsid,
 639                                         conf_tid->ps_scheme,
 640                                         conf_tid->ack_policy,
 641                                         conf_tid->apsd_conf[0],
 642                                         conf_tid->apsd_conf[1]);
 643                if (ret < 0)
 644                        return ret;
 645        }
 646
 647        /* Configure HW encryption */
 648        ret = wl1271_acx_feature_cfg(wl, wlvif);
 649        if (ret < 0)
 650                return ret;
 651
 652        /* Mode specific init - post mem init */
 653        if (is_ap)
 654                ret = wl1271_ap_hw_init_post_mem(wl, vif);
 655        else
 656                ret = wl1271_sta_hw_init_post_mem(wl, vif);
 657
 658        if (ret < 0)
 659                return ret;
 660
 661        /* Configure initiator BA sessions policies */
 662        ret = wl1271_set_ba_policies(wl, wlvif);
 663        if (ret < 0)
 664                return ret;
 665
 666        ret = wlcore_hw_init_vif(wl, wlvif);
 667        if (ret < 0)
 668                return ret;
 669
 670        return 0;
 671}
 672
 673int wl1271_hw_init(struct wl1271 *wl)
 674{
 675        int ret;
 676
 677        /* Chip-specific hw init */
 678        ret = wl->ops->hw_init(wl);
 679        if (ret < 0)
 680                return ret;
 681
 682        /* Init templates */
 683        ret = wl1271_init_templates_config(wl);
 684        if (ret < 0)
 685                return ret;
 686
 687        ret = wl12xx_acx_mem_cfg(wl);
 688        if (ret < 0)
 689                return ret;
 690
 691        /* Configure the FW logger */
 692        ret = wl12xx_init_fwlog(wl);
 693        if (ret < 0)
 694                return ret;
 695
 696        ret = wlcore_cmd_regdomain_config_locked(wl);
 697        if (ret < 0)
 698                return ret;
 699
 700        /* Bluetooth WLAN coexistence */
 701        ret = wl1271_init_pta(wl);
 702        if (ret < 0)
 703                return ret;
 704
 705        /* Default memory configuration */
 706        ret = wl1271_acx_init_mem_config(wl);
 707        if (ret < 0)
 708                return ret;
 709
 710        /* RX config */
 711        ret = wl12xx_init_rx_config(wl);
 712        if (ret < 0)
 713                goto out_free_memmap;
 714
 715        ret = wl1271_acx_dco_itrim_params(wl);
 716        if (ret < 0)
 717                goto out_free_memmap;
 718
 719        /* Configure TX patch complete interrupt behavior */
 720        ret = wl1271_acx_tx_config_options(wl);
 721        if (ret < 0)
 722                goto out_free_memmap;
 723
 724        /* RX complete interrupt pacing */
 725        ret = wl1271_acx_init_rx_interrupt(wl);
 726        if (ret < 0)
 727                goto out_free_memmap;
 728
 729        /* Energy detection */
 730        ret = wl1271_init_energy_detection(wl);
 731        if (ret < 0)
 732                goto out_free_memmap;
 733
 734        /* Default fragmentation threshold */
 735        ret = wl1271_acx_frag_threshold(wl, wl->hw->wiphy->frag_threshold);
 736        if (ret < 0)
 737                goto out_free_memmap;
 738
 739        /* Enable data path */
 740        ret = wl1271_cmd_data_path(wl, 1);
 741        if (ret < 0)
 742                goto out_free_memmap;
 743
 744        /* configure PM */
 745        ret = wl1271_acx_pm_config(wl);
 746        if (ret < 0)
 747                goto out_free_memmap;
 748
 749        ret = wl12xx_acx_set_rate_mgmt_params(wl);
 750        if (ret < 0)
 751                goto out_free_memmap;
 752
 753        /* configure hangover */
 754        ret = wl12xx_acx_config_hangover(wl);
 755        if (ret < 0)
 756                goto out_free_memmap;
 757
 758        return 0;
 759
 760 out_free_memmap:
 761        kfree(wl->target_mem_map);
 762        wl->target_mem_map = NULL;
 763
 764        return ret;
 765}
 766