cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

init.c (16879B)


      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}