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