diff options
Diffstat (limited to 'drivers/net/wireless/ath/wcn36xx/main.c')
-rw-r--r-- | drivers/net/wireless/ath/wcn36xx/main.c | 321 |
1 files changed, 200 insertions, 121 deletions
diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index b04533bbc3a4..6b8d2889d73f 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -28,6 +28,7 @@ #include <net/ipv6.h> #include "wcn36xx.h" #include "testmode.h" +#include "firmware.h" unsigned int wcn36xx_dbg_mask; module_param_named(debug_mask, wcn36xx_dbg_mask, uint, 0644); @@ -192,84 +193,15 @@ static inline u8 get_sta_index(struct ieee80211_vif *vif, sta_priv->sta_index; } -static const char * const wcn36xx_caps_names[] = { - "MCC", /* 0 */ - "P2P", /* 1 */ - "DOT11AC", /* 2 */ - "SLM_SESSIONIZATION", /* 3 */ - "DOT11AC_OPMODE", /* 4 */ - "SAP32STA", /* 5 */ - "TDLS", /* 6 */ - "P2P_GO_NOA_DECOUPLE_INIT_SCAN",/* 7 */ - "WLANACTIVE_OFFLOAD", /* 8 */ - "BEACON_OFFLOAD", /* 9 */ - "SCAN_OFFLOAD", /* 10 */ - "ROAM_OFFLOAD", /* 11 */ - "BCN_MISS_OFFLOAD", /* 12 */ - "STA_POWERSAVE", /* 13 */ - "STA_ADVANCED_PWRSAVE", /* 14 */ - "AP_UAPSD", /* 15 */ - "AP_DFS", /* 16 */ - "BLOCKACK", /* 17 */ - "PHY_ERR", /* 18 */ - "BCN_FILTER", /* 19 */ - "RTT", /* 20 */ - "RATECTRL", /* 21 */ - "WOW", /* 22 */ - "WLAN_ROAM_SCAN_OFFLOAD", /* 23 */ - "SPECULATIVE_PS_POLL", /* 24 */ - "SCAN_SCH", /* 25 */ - "IBSS_HEARTBEAT_OFFLOAD", /* 26 */ - "WLAN_SCAN_OFFLOAD", /* 27 */ - "WLAN_PERIODIC_TX_PTRN", /* 28 */ - "ADVANCE_TDLS", /* 29 */ - "BATCH_SCAN", /* 30 */ - "FW_IN_TX_PATH", /* 31 */ - "EXTENDED_NSOFFLOAD_SLOT", /* 32 */ - "CH_SWITCH_V1", /* 33 */ - "HT40_OBSS_SCAN", /* 34 */ - "UPDATE_CHANNEL_LIST", /* 35 */ - "WLAN_MCADDR_FLT", /* 36 */ - "WLAN_CH144", /* 37 */ - "NAN", /* 38 */ - "TDLS_SCAN_COEXISTENCE", /* 39 */ - "LINK_LAYER_STATS_MEAS", /* 40 */ - "MU_MIMO", /* 41 */ - "EXTENDED_SCAN", /* 42 */ - "DYNAMIC_WMM_PS", /* 43 */ - "MAC_SPOOFED_SCAN", /* 44 */ - "BMU_ERROR_GENERIC_RECOVERY", /* 45 */ - "DISA", /* 46 */ - "FW_STATS", /* 47 */ - "WPS_PRBRSP_TMPL", /* 48 */ - "BCN_IE_FLT_DELTA", /* 49 */ - "TDLS_OFF_CHANNEL", /* 51 */ - "RTT3", /* 52 */ - "MGMT_FRAME_LOGGING", /* 53 */ - "ENHANCED_TXBD_COMPLETION", /* 54 */ - "LOGGING_ENHANCEMENT", /* 55 */ - "EXT_SCAN_ENHANCED", /* 56 */ - "MEMORY_DUMP_SUPPORTED", /* 57 */ - "PER_PKT_STATS_SUPPORTED", /* 58 */ - "EXT_LL_STAT", /* 60 */ - "WIFI_CONFIG", /* 61 */ - "ANTENNA_DIVERSITY_SELECTION", /* 62 */ -}; - -static const char *wcn36xx_get_cap_name(enum place_holder_in_cap_bitmap x) -{ - if (x >= ARRAY_SIZE(wcn36xx_caps_names)) - return "UNKNOWN"; - return wcn36xx_caps_names[x]; -} - static void wcn36xx_feat_caps_info(struct wcn36xx *wcn) { int i; for (i = 0; i < MAX_FEATURE_SUPPORTED; i++) { - if (get_feat_caps(wcn->fw_feat_caps, i)) - wcn36xx_dbg(WCN36XX_DBG_MAC, "FW Cap %s\n", wcn36xx_get_cap_name(i)); + if (wcn36xx_firmware_get_feat_caps(wcn->fw_feat_caps, i)) { + wcn36xx_dbg(WCN36XX_DBG_MAC, "FW Cap %s\n", + wcn36xx_firmware_get_cap_name(i)); + } } } @@ -331,6 +263,7 @@ static int wcn36xx_start(struct ieee80211_hw *hw) INIT_LIST_HEAD(&wcn->vif_list); spin_lock_init(&wcn->dxe_lock); + spin_lock_init(&wcn->survey_lock); return 0; @@ -380,7 +313,7 @@ static void wcn36xx_change_ps(struct wcn36xx *wcn, bool enable) list_for_each_entry(tmp, &wcn->vif_list, list) { vif = wcn36xx_priv_to_vif(tmp); if (enable && !wcn->sw_scan) { - if (vif->bss_conf.ps) /* ps allowed ? */ + if (vif->cfg.ps) /* ps allowed ? */ wcn36xx_pmc_enter_bmps_state(wcn, vif); } else { wcn36xx_pmc_exit_bmps_state(wcn, vif); @@ -392,16 +325,47 @@ static void wcn36xx_change_opchannel(struct wcn36xx *wcn, int ch) { struct ieee80211_vif *vif = NULL; struct wcn36xx_vif *tmp; + struct ieee80211_supported_band *band; + struct ieee80211_channel *channel = NULL; + unsigned long flags; + int i, j; + + for (i = 0; i < ARRAY_SIZE(wcn->hw->wiphy->bands); i++) { + band = wcn->hw->wiphy->bands[i]; + if (!band) + break; + for (j = 0; j < band->n_channels; j++) { + if (HW_VALUE_CHANNEL(band->channels[j].hw_value) == ch) { + channel = &band->channels[j]; + break; + } + } + if (channel) + break; + } + + if (!channel) { + wcn36xx_err("Cannot tune to channel %d\n", ch); + return; + } + + spin_lock_irqsave(&wcn->survey_lock, flags); + wcn->band = band; + wcn->channel = channel; + spin_unlock_irqrestore(&wcn->survey_lock, flags); list_for_each_entry(tmp, &wcn->vif_list, list) { vif = wcn36xx_priv_to_vif(tmp); wcn36xx_smd_switch_channel(wcn, vif, ch); } + + return; } static int wcn36xx_config(struct ieee80211_hw *hw, u32 changed) { struct wcn36xx *wcn = hw->priv; + int ret; wcn36xx_dbg(WCN36XX_DBG_MAC, "mac config changed 0x%08x\n", changed); @@ -417,17 +381,31 @@ static int wcn36xx_config(struct ieee80211_hw *hw, u32 changed) * want to receive/transmit regular data packets, then * simply stop the scan session and exit PS mode. */ - wcn36xx_smd_finish_scan(wcn, HAL_SYS_MODE_SCAN, - wcn->sw_scan_vif); - wcn->sw_scan_channel = 0; + if (wcn->sw_scan_channel) + wcn36xx_smd_end_scan(wcn, wcn->sw_scan_channel); + if (wcn->sw_scan_init) { + wcn36xx_smd_finish_scan(wcn, HAL_SYS_MODE_SCAN, + wcn->sw_scan_vif); + } } else if (wcn->sw_scan) { /* A scan is ongoing, do not change the operating * channel, but start a scan session on the channel. */ - wcn36xx_smd_init_scan(wcn, HAL_SYS_MODE_SCAN, - wcn->sw_scan_vif); + if (wcn->sw_scan_channel) + wcn36xx_smd_end_scan(wcn, wcn->sw_scan_channel); + if (!wcn->sw_scan_init) { + /* This can fail if we are unable to notify the + * operating channel. + */ + ret = wcn36xx_smd_init_scan(wcn, + HAL_SYS_MODE_SCAN, + wcn->sw_scan_vif); + if (ret) { + mutex_unlock(&wcn->conf_mutex); + return -EIO; + } + } wcn36xx_smd_start_scan(wcn, ch); - wcn->sw_scan_channel = ch; } else { wcn36xx_change_opchannel(wcn, ch); } @@ -655,7 +633,7 @@ static int wcn36xx_hw_scan(struct ieee80211_hw *hw, { struct wcn36xx *wcn = hw->priv; - if (!get_feat_caps(wcn->fw_feat_caps, SCAN_OFFLOAD)) { + if (!wcn36xx_firmware_get_feat_caps(wcn->fw_feat_caps, SCAN_OFFLOAD)) { /* fallback to mac80211 software scan */ return 1; } @@ -693,7 +671,7 @@ static void wcn36xx_cancel_hw_scan(struct ieee80211_hw *hw, wcn->scan_aborted = true; mutex_unlock(&wcn->scan_lock); - if (get_feat_caps(wcn->fw_feat_caps, SCAN_OFFLOAD)) { + if (wcn36xx_firmware_get_feat_caps(wcn->fw_feat_caps, SCAN_OFFLOAD)) { /* ieee80211_scan_completed will be called on FW scan * indication */ wcn36xx_smd_stop_hw_scan(wcn); @@ -707,6 +685,8 @@ static void wcn36xx_sw_scan_start(struct ieee80211_hw *hw, struct wcn36xx *wcn = hw->priv; struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); + wcn36xx_dbg(WCN36XX_DBG_MAC, "sw_scan_start"); + wcn->sw_scan = true; wcn->sw_scan_vif = vif; wcn->sw_scan_channel = 0; @@ -721,8 +701,15 @@ static void wcn36xx_sw_scan_complete(struct ieee80211_hw *hw, { struct wcn36xx *wcn = hw->priv; + wcn36xx_dbg(WCN36XX_DBG_MAC, "sw_scan_complete"); + /* ensure that any scan session is finished */ - wcn36xx_smd_finish_scan(wcn, HAL_SYS_MODE_SCAN, wcn->sw_scan_vif); + if (wcn->sw_scan_channel) + wcn36xx_smd_end_scan(wcn, wcn->sw_scan_channel); + if (wcn->sw_scan_init) { + wcn36xx_smd_finish_scan(wcn, HAL_SYS_MODE_SCAN, + wcn->sw_scan_vif); + } wcn->sw_scan = false; wcn->sw_scan_opchannel = 0; } @@ -733,7 +720,7 @@ static void wcn36xx_update_allowed_rates(struct ieee80211_sta *sta, int i, size; u16 *rates_table; struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(sta); - u32 rates = sta->supp_rates[band]; + u32 rates = sta->deflink.supp_rates[band]; memset(&sta_priv->supported_rates, 0, sizeof(sta_priv->supported_rates)); @@ -759,20 +746,20 @@ static void wcn36xx_update_allowed_rates(struct ieee80211_sta *sta, } } - if (sta->ht_cap.ht_supported) { - BUILD_BUG_ON(sizeof(sta->ht_cap.mcs.rx_mask) > - sizeof(sta_priv->supported_rates.supported_mcs_set)); + if (sta->deflink.ht_cap.ht_supported) { + BUILD_BUG_ON(sizeof(sta->deflink.ht_cap.mcs.rx_mask) > + sizeof(sta_priv->supported_rates.supported_mcs_set)); memcpy(sta_priv->supported_rates.supported_mcs_set, - sta->ht_cap.mcs.rx_mask, - sizeof(sta->ht_cap.mcs.rx_mask)); + sta->deflink.ht_cap.mcs.rx_mask, + sizeof(sta->deflink.ht_cap.mcs.rx_mask)); } - if (sta->vht_cap.vht_supported) { + if (sta->deflink.vht_cap.vht_supported) { sta_priv->supported_rates.op_rate_mode = STA_11ac; sta_priv->supported_rates.vht_rx_mcs_map = - sta->vht_cap.vht_mcs.rx_mcs_map; + sta->deflink.vht_cap.vht_mcs.rx_mcs_map; sta_priv->supported_rates.vht_tx_mcs_map = - sta->vht_cap.vht_mcs.tx_mcs_map; + sta->deflink.vht_cap.vht_mcs.tx_mcs_map; } } @@ -813,7 +800,7 @@ void wcn36xx_set_default_rates_v1(struct wcn36xx_hal_supported_rates_v1 *rates) static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - u32 changed) + u64 changed) { struct wcn36xx *wcn = hw->priv; struct sk_buff *skb = NULL; @@ -821,7 +808,7 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, enum wcn36xx_hal_link_state link_state; struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); - wcn36xx_dbg(WCN36XX_DBG_MAC, "mac bss info changed vif %p changed 0x%08x\n", + wcn36xx_dbg(WCN36XX_DBG_MAC, "mac bss info changed vif %p changed 0x%llx\n", vif, changed); mutex_lock(&wcn->conf_mutex); @@ -860,17 +847,17 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, wcn36xx_dbg(WCN36XX_DBG_MAC, "mac bss changed ssid\n"); wcn36xx_dbg_dump(WCN36XX_DBG_MAC, "ssid ", - bss_conf->ssid, bss_conf->ssid_len); + vif->cfg.ssid, vif->cfg.ssid_len); - vif_priv->ssid.length = bss_conf->ssid_len; + vif_priv->ssid.length = vif->cfg.ssid_len; memcpy(&vif_priv->ssid.ssid, - bss_conf->ssid, - bss_conf->ssid_len); + vif->cfg.ssid, + vif->cfg.ssid_len); } if (changed & BSS_CHANGED_ASSOC) { vif_priv->is_joining = false; - if (bss_conf->assoc) { + if (vif->cfg.assoc) { struct ieee80211_sta *sta; struct wcn36xx_sta *sta_priv; @@ -878,7 +865,7 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, "mac assoc bss %pM vif %pM AID=%d\n", bss_conf->bssid, vif->addr, - bss_conf->aid); + vif->cfg.aid); vif_priv->sta_assoc = true; @@ -904,19 +891,21 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, wcn36xx_smd_config_bss(wcn, vif, sta, bss_conf->bssid, true); - sta_priv->aid = bss_conf->aid; + sta_priv->aid = vif->cfg.aid; /* * config_sta must be called from because this is the * place where AID is available. */ wcn36xx_smd_config_sta(wcn, vif, sta); + if (vif->type == NL80211_IFTYPE_STATION) + wcn36xx_smd_add_beacon_filter(wcn, vif); wcn36xx_enable_keep_alive_null_packet(wcn, vif); } else { wcn36xx_dbg(WCN36XX_DBG_MAC, "disassociated bss %pM vif %pM AID=%d\n", bss_conf->bssid, vif->addr, - bss_conf->aid); + vif->cfg.aid); vif_priv->sta_assoc = false; wcn36xx_smd_set_link_st(wcn, bss_conf->bssid, @@ -949,7 +938,7 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, wcn36xx_smd_config_bss(wcn, vif, NULL, vif->addr, false); skb = ieee80211_beacon_get_tim(hw, vif, &tim_off, - &tim_len); + &tim_len, 0); if (!skb) { wcn36xx_err("failed to alloc beacon skb\n"); goto out; @@ -1196,7 +1185,7 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw, u16 tid = params->tid; u16 *ssn = ¶ms->ssn; int ret = 0; - u8 session; + int session; wcn36xx_dbg(WCN36XX_DBG_MAC, "mac ampdu action action %d tid %d\n", action, tid); @@ -1208,9 +1197,11 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw, sta_priv->tid = tid; session = wcn36xx_smd_add_ba_session(wcn, sta, tid, ssn, 0, get_sta_index(vif, sta_priv)); + if (session < 0) { + ret = session; + goto out; + } wcn36xx_smd_add_ba(wcn, session); - wcn36xx_smd_trigger_ba(wcn, get_sta_index(vif, sta_priv), tid, - session); break; case IEEE80211_AMPDU_RX_STOP: wcn36xx_smd_del_ba(wcn, tid, 0, get_sta_index(vif, sta_priv)); @@ -1220,6 +1211,18 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw, sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_START; spin_unlock_bh(&sta_priv->ampdu_lock); + /* Replace the mac80211 ssn with the firmware one */ + wcn36xx_dbg(WCN36XX_DBG_MAC, "mac ampdu ssn = %u\n", *ssn); + wcn36xx_smd_trigger_ba(wcn, get_sta_index(vif, sta_priv), tid, ssn); + wcn36xx_dbg(WCN36XX_DBG_MAC, "mac ampdu fw-ssn = %u\n", *ssn); + + /* Start BA session */ + session = wcn36xx_smd_add_ba_session(wcn, sta, tid, ssn, 1, + get_sta_index(vif, sta_priv)); + if (session < 0) { + ret = session; + goto out; + } ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; break; case IEEE80211_AMPDU_TX_OPERATIONAL: @@ -1227,8 +1230,6 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw, sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_OPERATIONAL; spin_unlock_bh(&sta_priv->ampdu_lock); - wcn36xx_smd_add_ba_session(wcn, sta, tid, ssn, 1, - get_sta_index(vif, sta_priv)); break; case IEEE80211_AMPDU_TX_STOP_FLUSH: case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: @@ -1244,6 +1245,7 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw, wcn36xx_err("Unknown AMPDU action\n"); } +out: mutex_unlock(&wcn->conf_mutex); return ret; @@ -1277,6 +1279,74 @@ static void wcn36xx_ipv6_addr_change(struct ieee80211_hw *hw, } #endif +static void wcn36xx_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop) +{ + struct wcn36xx *wcn = hw->priv; + + if (wcn36xx_dxe_tx_flush(wcn)) { + wcn36xx_err("Failed to flush hardware tx queues\n"); + } +} + +static int wcn36xx_get_survey(struct ieee80211_hw *hw, int idx, + struct survey_info *survey) +{ + struct wcn36xx *wcn = hw->priv; + struct ieee80211_supported_band *sband; + struct wcn36xx_chan_survey *chan_survey; + int band_idx; + unsigned long flags; + + sband = wcn->hw->wiphy->bands[NL80211_BAND_2GHZ]; + band_idx = idx; + if (band_idx >= sband->n_channels) { + band_idx -= sband->n_channels; + sband = wcn->hw->wiphy->bands[NL80211_BAND_5GHZ]; + } + + if (!sband || band_idx >= sband->n_channels) + return -ENOENT; + + spin_lock_irqsave(&wcn->survey_lock, flags); + + chan_survey = &wcn->chan_survey[idx]; + survey->channel = &sband->channels[band_idx]; + survey->noise = chan_survey->rssi - chan_survey->snr; + survey->filled = 0; + + if (chan_survey->rssi > -100 && chan_survey->rssi < 0) + survey->filled |= SURVEY_INFO_NOISE_DBM; + + if (survey->channel == wcn->channel) + survey->filled |= SURVEY_INFO_IN_USE; + + spin_unlock_irqrestore(&wcn->survey_lock, flags); + + wcn36xx_dbg(WCN36XX_DBG_MAC, + "ch %d rssi %d snr %d noise %d filled %x freq %d\n", + HW_VALUE_CHANNEL(survey->channel->hw_value), + chan_survey->rssi, chan_survey->snr, survey->noise, + survey->filled, survey->channel->center_freq); + + return 0; +} + +static void wcn36xx_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, struct station_info *sinfo) +{ + struct wcn36xx *wcn; + u8 sta_index; + int status; + + wcn = hw->priv; + sta_index = get_sta_index(vif, wcn36xx_sta_to_priv(sta)); + status = wcn36xx_smd_get_stats(wcn, sta_index, HAL_GLOBAL_CLASS_A_STATS_INFO, sinfo); + + if (status) + wcn36xx_err("wcn36xx_smd_get_stats failed\n"); +} + static const struct ieee80211_ops wcn36xx_ops = { .start = wcn36xx_start, .stop = wcn36xx_stop, @@ -1300,10 +1370,13 @@ static const struct ieee80211_ops wcn36xx_ops = { .set_rts_threshold = wcn36xx_set_rts_threshold, .sta_add = wcn36xx_sta_add, .sta_remove = wcn36xx_sta_remove, + .sta_statistics = wcn36xx_sta_statistics, .ampdu_action = wcn36xx_ampdu_action, #if IS_ENABLED(CONFIG_IPV6) .ipv6_addr_change = wcn36xx_ipv6_addr_change, #endif + .flush = wcn36xx_flush, + .get_survey = wcn36xx_get_survey, CFG80211_TESTMODE_CMD(wcn36xx_tm_cmd) }; @@ -1396,25 +1469,20 @@ static int wcn36xx_platform_get_resources(struct wcn36xx *wcn, { struct device_node *mmio_node; struct device_node *iris_node; - struct resource *res; int index; int ret; /* Set TX IRQ */ - res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "tx"); - if (!res) { - wcn36xx_err("failed to get tx_irq\n"); - return -ENOENT; - } - wcn->tx_irq = res->start; + ret = platform_get_irq_byname(pdev, "tx"); + if (ret < 0) + return ret; + wcn->tx_irq = ret; /* Set RX IRQ */ - res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "rx"); - if (!res) { - wcn36xx_err("failed to get rx_irq\n"); - return -ENOENT; - } - wcn->rx_irq = res->start; + ret = platform_get_irq_byname(pdev, "rx"); + if (ret < 0) + return ret; + wcn->rx_irq = ret; /* Acquire SMSM tx enable handle */ wcn->tx_enable_state = qcom_smem_state_get(&pdev->dev, @@ -1463,6 +1531,9 @@ static int wcn36xx_platform_get_resources(struct wcn36xx *wcn, if (iris_node) { if (of_device_is_compatible(iris_node, "qcom,wcn3620")) wcn->rf_id = RF_IRIS_WCN3620; + if (of_device_is_compatible(iris_node, "qcom,wcn3660") || + of_device_is_compatible(iris_node, "qcom,wcn3660b")) + wcn->rf_id = RF_IRIS_WCN3660; if (of_device_is_compatible(iris_node, "qcom,wcn3680")) wcn->rf_id = RF_IRIS_WCN3680; of_node_put(iris_node); @@ -1485,6 +1556,7 @@ static int wcn36xx_probe(struct platform_device *pdev) void *wcnss; int ret; const u8 *addr; + int n_channels; wcn36xx_dbg(WCN36XX_DBG_MAC, "platform probe\n"); @@ -1512,6 +1584,13 @@ static int wcn36xx_probe(struct platform_device *pdev) goto out_wq; } + n_channels = wcn_band_2ghz.n_channels + wcn_band_5ghz.n_channels; + wcn->chan_survey = devm_kmalloc(wcn->dev, n_channels, GFP_KERNEL); + if (!wcn->chan_survey) { + ret = -ENOMEM; + goto out_wq; + } + ret = dma_set_mask_and_coherent(wcn->dev, DMA_BIT_MASK(32)); if (ret < 0) { wcn36xx_err("failed to set DMA mask: %d\n", ret); |