18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/****************************************************************************** 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. 58c2ecf20Sopenharmony_ci * Copyright(c) 2015 Intel Deutschland GmbH 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Contact Information: 88c2ecf20Sopenharmony_ci * Intel Linux Wireless <linuxwifi@intel.com> 98c2ecf20Sopenharmony_ci * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci *****************************************************************************/ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 148c2ecf20Sopenharmony_ci#include "iwl-trans.h" 158c2ecf20Sopenharmony_ci#include "iwl-modparams.h" 168c2ecf20Sopenharmony_ci#include "dev.h" 178c2ecf20Sopenharmony_ci#include "agn.h" 188c2ecf20Sopenharmony_ci#include "calib.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci/* 218c2ecf20Sopenharmony_ci * initialize rxon structure with default values from eeprom 228c2ecf20Sopenharmony_ci */ 238c2ecf20Sopenharmony_civoid iwl_connection_init_rx_config(struct iwl_priv *priv, 248c2ecf20Sopenharmony_ci struct iwl_rxon_context *ctx) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci memset(&ctx->staging, 0, sizeof(ctx->staging)); 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci if (!ctx->vif) { 298c2ecf20Sopenharmony_ci ctx->staging.dev_type = ctx->unused_devtype; 308c2ecf20Sopenharmony_ci } else 318c2ecf20Sopenharmony_ci switch (ctx->vif->type) { 328c2ecf20Sopenharmony_ci case NL80211_IFTYPE_AP: 338c2ecf20Sopenharmony_ci ctx->staging.dev_type = ctx->ap_devtype; 348c2ecf20Sopenharmony_ci break; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci case NL80211_IFTYPE_STATION: 378c2ecf20Sopenharmony_ci ctx->staging.dev_type = ctx->station_devtype; 388c2ecf20Sopenharmony_ci ctx->staging.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK; 398c2ecf20Sopenharmony_ci break; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 428c2ecf20Sopenharmony_ci ctx->staging.dev_type = ctx->ibss_devtype; 438c2ecf20Sopenharmony_ci ctx->staging.flags = RXON_FLG_SHORT_PREAMBLE_MSK; 448c2ecf20Sopenharmony_ci ctx->staging.filter_flags = RXON_FILTER_BCON_AWARE_MSK | 458c2ecf20Sopenharmony_ci RXON_FILTER_ACCEPT_GRP_MSK; 468c2ecf20Sopenharmony_ci break; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci case NL80211_IFTYPE_MONITOR: 498c2ecf20Sopenharmony_ci ctx->staging.dev_type = RXON_DEV_TYPE_SNIFFER; 508c2ecf20Sopenharmony_ci break; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci default: 538c2ecf20Sopenharmony_ci IWL_ERR(priv, "Unsupported interface type %d\n", 548c2ecf20Sopenharmony_ci ctx->vif->type); 558c2ecf20Sopenharmony_ci break; 568c2ecf20Sopenharmony_ci } 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci#if 0 598c2ecf20Sopenharmony_ci /* TODO: Figure out when short_preamble would be set and cache from 608c2ecf20Sopenharmony_ci * that */ 618c2ecf20Sopenharmony_ci if (!hw_to_local(priv->hw)->short_preamble) 628c2ecf20Sopenharmony_ci ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; 638c2ecf20Sopenharmony_ci else 648c2ecf20Sopenharmony_ci ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; 658c2ecf20Sopenharmony_ci#endif 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci ctx->staging.channel = 688c2ecf20Sopenharmony_ci cpu_to_le16(priv->hw->conf.chandef.chan->hw_value); 698c2ecf20Sopenharmony_ci priv->band = priv->hw->conf.chandef.chan->band; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci iwl_set_flags_for_band(priv, ctx, priv->band, ctx->vif); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci /* clear both MIX and PURE40 mode flag */ 748c2ecf20Sopenharmony_ci ctx->staging.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED | 758c2ecf20Sopenharmony_ci RXON_FLG_CHANNEL_MODE_PURE_40); 768c2ecf20Sopenharmony_ci if (ctx->vif) 778c2ecf20Sopenharmony_ci memcpy(ctx->staging.node_addr, ctx->vif->addr, ETH_ALEN); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci ctx->staging.ofdm_ht_single_stream_basic_rates = 0xff; 808c2ecf20Sopenharmony_ci ctx->staging.ofdm_ht_dual_stream_basic_rates = 0xff; 818c2ecf20Sopenharmony_ci ctx->staging.ofdm_ht_triple_stream_basic_rates = 0xff; 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic int iwlagn_disable_bss(struct iwl_priv *priv, 858c2ecf20Sopenharmony_ci struct iwl_rxon_context *ctx, 868c2ecf20Sopenharmony_ci struct iwl_rxon_cmd *send) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci __le32 old_filter = send->filter_flags; 898c2ecf20Sopenharmony_ci int ret; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci send->filter_flags &= ~RXON_FILTER_ASSOC_MSK; 928c2ecf20Sopenharmony_ci ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_cmd, 938c2ecf20Sopenharmony_ci 0, sizeof(*send), send); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci send->filter_flags = old_filter; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci if (ret) 988c2ecf20Sopenharmony_ci IWL_DEBUG_QUIET_RFKILL(priv, 998c2ecf20Sopenharmony_ci "Error clearing ASSOC_MSK on BSS (%d)\n", ret); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci return ret; 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic int iwlagn_disable_pan(struct iwl_priv *priv, 1058c2ecf20Sopenharmony_ci struct iwl_rxon_context *ctx, 1068c2ecf20Sopenharmony_ci struct iwl_rxon_cmd *send) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci struct iwl_notification_wait disable_wait; 1098c2ecf20Sopenharmony_ci __le32 old_filter = send->filter_flags; 1108c2ecf20Sopenharmony_ci u8 old_dev_type = send->dev_type; 1118c2ecf20Sopenharmony_ci int ret; 1128c2ecf20Sopenharmony_ci static const u16 deactivate_cmd[] = { 1138c2ecf20Sopenharmony_ci REPLY_WIPAN_DEACTIVATION_COMPLETE 1148c2ecf20Sopenharmony_ci }; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci iwl_init_notification_wait(&priv->notif_wait, &disable_wait, 1178c2ecf20Sopenharmony_ci deactivate_cmd, ARRAY_SIZE(deactivate_cmd), 1188c2ecf20Sopenharmony_ci NULL, NULL); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci send->filter_flags &= ~RXON_FILTER_ASSOC_MSK; 1218c2ecf20Sopenharmony_ci send->dev_type = RXON_DEV_TYPE_P2P; 1228c2ecf20Sopenharmony_ci ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_cmd, 1238c2ecf20Sopenharmony_ci 0, sizeof(*send), send); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci send->filter_flags = old_filter; 1268c2ecf20Sopenharmony_ci send->dev_type = old_dev_type; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci if (ret) { 1298c2ecf20Sopenharmony_ci IWL_ERR(priv, "Error disabling PAN (%d)\n", ret); 1308c2ecf20Sopenharmony_ci iwl_remove_notification(&priv->notif_wait, &disable_wait); 1318c2ecf20Sopenharmony_ci } else { 1328c2ecf20Sopenharmony_ci ret = iwl_wait_notification(&priv->notif_wait, 1338c2ecf20Sopenharmony_ci &disable_wait, HZ); 1348c2ecf20Sopenharmony_ci if (ret) 1358c2ecf20Sopenharmony_ci IWL_ERR(priv, "Timed out waiting for PAN disable\n"); 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci return ret; 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic int iwlagn_disconn_pan(struct iwl_priv *priv, 1428c2ecf20Sopenharmony_ci struct iwl_rxon_context *ctx, 1438c2ecf20Sopenharmony_ci struct iwl_rxon_cmd *send) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci __le32 old_filter = send->filter_flags; 1468c2ecf20Sopenharmony_ci int ret; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci send->filter_flags &= ~RXON_FILTER_ASSOC_MSK; 1498c2ecf20Sopenharmony_ci ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_cmd, 0, 1508c2ecf20Sopenharmony_ci sizeof(*send), send); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci send->filter_flags = old_filter; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci return ret; 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic void iwlagn_update_qos(struct iwl_priv *priv, 1588c2ecf20Sopenharmony_ci struct iwl_rxon_context *ctx) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci int ret; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci if (!ctx->is_active) 1638c2ecf20Sopenharmony_ci return; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci ctx->qos_data.def_qos_parm.qos_flags = 0; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci if (ctx->qos_data.qos_active) 1688c2ecf20Sopenharmony_ci ctx->qos_data.def_qos_parm.qos_flags |= 1698c2ecf20Sopenharmony_ci QOS_PARAM_FLG_UPDATE_EDCA_MSK; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci if (ctx->ht.enabled) 1728c2ecf20Sopenharmony_ci ctx->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci IWL_DEBUG_INFO(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n", 1758c2ecf20Sopenharmony_ci ctx->qos_data.qos_active, 1768c2ecf20Sopenharmony_ci ctx->qos_data.def_qos_parm.qos_flags); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci ret = iwl_dvm_send_cmd_pdu(priv, ctx->qos_cmd, 0, 1798c2ecf20Sopenharmony_ci sizeof(struct iwl_qosparam_cmd), 1808c2ecf20Sopenharmony_ci &ctx->qos_data.def_qos_parm); 1818c2ecf20Sopenharmony_ci if (ret) 1828c2ecf20Sopenharmony_ci IWL_DEBUG_QUIET_RFKILL(priv, "Failed to update QoS\n"); 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_cistatic int iwlagn_update_beacon(struct iwl_priv *priv, 1868c2ecf20Sopenharmony_ci struct ieee80211_vif *vif) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci lockdep_assert_held(&priv->mutex); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci dev_kfree_skb(priv->beacon_skb); 1918c2ecf20Sopenharmony_ci priv->beacon_skb = ieee80211_beacon_get(priv->hw, vif); 1928c2ecf20Sopenharmony_ci if (!priv->beacon_skb) 1938c2ecf20Sopenharmony_ci return -ENOMEM; 1948c2ecf20Sopenharmony_ci return iwlagn_send_beacon_cmd(priv); 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistatic int iwlagn_send_rxon_assoc(struct iwl_priv *priv, 1988c2ecf20Sopenharmony_ci struct iwl_rxon_context *ctx) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci int ret = 0; 2018c2ecf20Sopenharmony_ci struct iwl_rxon_assoc_cmd rxon_assoc; 2028c2ecf20Sopenharmony_ci const struct iwl_rxon_cmd *rxon1 = &ctx->staging; 2038c2ecf20Sopenharmony_ci const struct iwl_rxon_cmd *rxon2 = &ctx->active; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci if ((rxon1->flags == rxon2->flags) && 2068c2ecf20Sopenharmony_ci (rxon1->filter_flags == rxon2->filter_flags) && 2078c2ecf20Sopenharmony_ci (rxon1->cck_basic_rates == rxon2->cck_basic_rates) && 2088c2ecf20Sopenharmony_ci (rxon1->ofdm_ht_single_stream_basic_rates == 2098c2ecf20Sopenharmony_ci rxon2->ofdm_ht_single_stream_basic_rates) && 2108c2ecf20Sopenharmony_ci (rxon1->ofdm_ht_dual_stream_basic_rates == 2118c2ecf20Sopenharmony_ci rxon2->ofdm_ht_dual_stream_basic_rates) && 2128c2ecf20Sopenharmony_ci (rxon1->ofdm_ht_triple_stream_basic_rates == 2138c2ecf20Sopenharmony_ci rxon2->ofdm_ht_triple_stream_basic_rates) && 2148c2ecf20Sopenharmony_ci (rxon1->acquisition_data == rxon2->acquisition_data) && 2158c2ecf20Sopenharmony_ci (rxon1->rx_chain == rxon2->rx_chain) && 2168c2ecf20Sopenharmony_ci (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) { 2178c2ecf20Sopenharmony_ci IWL_DEBUG_INFO(priv, "Using current RXON_ASSOC. Not resending.\n"); 2188c2ecf20Sopenharmony_ci return 0; 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci rxon_assoc.flags = ctx->staging.flags; 2228c2ecf20Sopenharmony_ci rxon_assoc.filter_flags = ctx->staging.filter_flags; 2238c2ecf20Sopenharmony_ci rxon_assoc.ofdm_basic_rates = ctx->staging.ofdm_basic_rates; 2248c2ecf20Sopenharmony_ci rxon_assoc.cck_basic_rates = ctx->staging.cck_basic_rates; 2258c2ecf20Sopenharmony_ci rxon_assoc.reserved1 = 0; 2268c2ecf20Sopenharmony_ci rxon_assoc.reserved2 = 0; 2278c2ecf20Sopenharmony_ci rxon_assoc.reserved3 = 0; 2288c2ecf20Sopenharmony_ci rxon_assoc.ofdm_ht_single_stream_basic_rates = 2298c2ecf20Sopenharmony_ci ctx->staging.ofdm_ht_single_stream_basic_rates; 2308c2ecf20Sopenharmony_ci rxon_assoc.ofdm_ht_dual_stream_basic_rates = 2318c2ecf20Sopenharmony_ci ctx->staging.ofdm_ht_dual_stream_basic_rates; 2328c2ecf20Sopenharmony_ci rxon_assoc.rx_chain_select_flags = ctx->staging.rx_chain; 2338c2ecf20Sopenharmony_ci rxon_assoc.ofdm_ht_triple_stream_basic_rates = 2348c2ecf20Sopenharmony_ci ctx->staging.ofdm_ht_triple_stream_basic_rates; 2358c2ecf20Sopenharmony_ci rxon_assoc.acquisition_data = ctx->staging.acquisition_data; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_assoc_cmd, 2388c2ecf20Sopenharmony_ci CMD_ASYNC, sizeof(rxon_assoc), &rxon_assoc); 2398c2ecf20Sopenharmony_ci return ret; 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic u16 iwl_adjust_beacon_interval(u16 beacon_val, u16 max_beacon_val) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci u16 new_val; 2458c2ecf20Sopenharmony_ci u16 beacon_factor; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci /* 2488c2ecf20Sopenharmony_ci * If mac80211 hasn't given us a beacon interval, program 2498c2ecf20Sopenharmony_ci * the default into the device (not checking this here 2508c2ecf20Sopenharmony_ci * would cause the adjustment below to return the maximum 2518c2ecf20Sopenharmony_ci * value, which may break PAN.) 2528c2ecf20Sopenharmony_ci */ 2538c2ecf20Sopenharmony_ci if (!beacon_val) 2548c2ecf20Sopenharmony_ci return DEFAULT_BEACON_INTERVAL; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci /* 2578c2ecf20Sopenharmony_ci * If the beacon interval we obtained from the peer 2588c2ecf20Sopenharmony_ci * is too large, we'll have to wake up more often 2598c2ecf20Sopenharmony_ci * (and in IBSS case, we'll beacon too much) 2608c2ecf20Sopenharmony_ci * 2618c2ecf20Sopenharmony_ci * For example, if max_beacon_val is 4096, and the 2628c2ecf20Sopenharmony_ci * requested beacon interval is 7000, we'll have to 2638c2ecf20Sopenharmony_ci * use 3500 to be able to wake up on the beacons. 2648c2ecf20Sopenharmony_ci * 2658c2ecf20Sopenharmony_ci * This could badly influence beacon detection stats. 2668c2ecf20Sopenharmony_ci */ 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci beacon_factor = (beacon_val + max_beacon_val) / max_beacon_val; 2698c2ecf20Sopenharmony_ci new_val = beacon_val / beacon_factor; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci if (!new_val) 2728c2ecf20Sopenharmony_ci new_val = max_beacon_val; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci return new_val; 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cistatic int iwl_send_rxon_timing(struct iwl_priv *priv, 2788c2ecf20Sopenharmony_ci struct iwl_rxon_context *ctx) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci u64 tsf; 2818c2ecf20Sopenharmony_ci s32 interval_tm, rem; 2828c2ecf20Sopenharmony_ci struct ieee80211_conf *conf = NULL; 2838c2ecf20Sopenharmony_ci u16 beacon_int; 2848c2ecf20Sopenharmony_ci struct ieee80211_vif *vif = ctx->vif; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci conf = &priv->hw->conf; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci lockdep_assert_held(&priv->mutex); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci memset(&ctx->timing, 0, sizeof(struct iwl_rxon_time_cmd)); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci ctx->timing.timestamp = cpu_to_le64(priv->timestamp); 2938c2ecf20Sopenharmony_ci ctx->timing.listen_interval = cpu_to_le16(conf->listen_interval); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci beacon_int = vif ? vif->bss_conf.beacon_int : 0; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci /* 2988c2ecf20Sopenharmony_ci * TODO: For IBSS we need to get atim_window from mac80211, 2998c2ecf20Sopenharmony_ci * for now just always use 0 3008c2ecf20Sopenharmony_ci */ 3018c2ecf20Sopenharmony_ci ctx->timing.atim_window = 0; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci if (ctx->ctxid == IWL_RXON_CTX_PAN && 3048c2ecf20Sopenharmony_ci (!ctx->vif || ctx->vif->type != NL80211_IFTYPE_STATION) && 3058c2ecf20Sopenharmony_ci iwl_is_associated(priv, IWL_RXON_CTX_BSS) && 3068c2ecf20Sopenharmony_ci priv->contexts[IWL_RXON_CTX_BSS].vif && 3078c2ecf20Sopenharmony_ci priv->contexts[IWL_RXON_CTX_BSS].vif->bss_conf.beacon_int) { 3088c2ecf20Sopenharmony_ci ctx->timing.beacon_interval = 3098c2ecf20Sopenharmony_ci priv->contexts[IWL_RXON_CTX_BSS].timing.beacon_interval; 3108c2ecf20Sopenharmony_ci beacon_int = le16_to_cpu(ctx->timing.beacon_interval); 3118c2ecf20Sopenharmony_ci } else if (ctx->ctxid == IWL_RXON_CTX_BSS && 3128c2ecf20Sopenharmony_ci iwl_is_associated(priv, IWL_RXON_CTX_PAN) && 3138c2ecf20Sopenharmony_ci priv->contexts[IWL_RXON_CTX_PAN].vif && 3148c2ecf20Sopenharmony_ci priv->contexts[IWL_RXON_CTX_PAN].vif->bss_conf.beacon_int && 3158c2ecf20Sopenharmony_ci (!iwl_is_associated_ctx(ctx) || !ctx->vif || 3168c2ecf20Sopenharmony_ci !ctx->vif->bss_conf.beacon_int)) { 3178c2ecf20Sopenharmony_ci ctx->timing.beacon_interval = 3188c2ecf20Sopenharmony_ci priv->contexts[IWL_RXON_CTX_PAN].timing.beacon_interval; 3198c2ecf20Sopenharmony_ci beacon_int = le16_to_cpu(ctx->timing.beacon_interval); 3208c2ecf20Sopenharmony_ci } else { 3218c2ecf20Sopenharmony_ci beacon_int = iwl_adjust_beacon_interval(beacon_int, 3228c2ecf20Sopenharmony_ci IWL_MAX_UCODE_BEACON_INTERVAL * TIME_UNIT); 3238c2ecf20Sopenharmony_ci ctx->timing.beacon_interval = cpu_to_le16(beacon_int); 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci ctx->beacon_int = beacon_int; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci tsf = priv->timestamp; /* tsf is modifed by do_div: copy it */ 3298c2ecf20Sopenharmony_ci interval_tm = beacon_int * TIME_UNIT; 3308c2ecf20Sopenharmony_ci rem = do_div(tsf, interval_tm); 3318c2ecf20Sopenharmony_ci ctx->timing.beacon_init_val = cpu_to_le32(interval_tm - rem); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci ctx->timing.dtim_period = vif ? (vif->bss_conf.dtim_period ?: 1) : 1; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci IWL_DEBUG_ASSOC(priv, 3368c2ecf20Sopenharmony_ci "beacon interval %d beacon timer %d beacon tim %d\n", 3378c2ecf20Sopenharmony_ci le16_to_cpu(ctx->timing.beacon_interval), 3388c2ecf20Sopenharmony_ci le32_to_cpu(ctx->timing.beacon_init_val), 3398c2ecf20Sopenharmony_ci le16_to_cpu(ctx->timing.atim_window)); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci return iwl_dvm_send_cmd_pdu(priv, ctx->rxon_timing_cmd, 3428c2ecf20Sopenharmony_ci 0, sizeof(ctx->timing), &ctx->timing); 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_cistatic int iwlagn_rxon_disconn(struct iwl_priv *priv, 3468c2ecf20Sopenharmony_ci struct iwl_rxon_context *ctx) 3478c2ecf20Sopenharmony_ci{ 3488c2ecf20Sopenharmony_ci int ret; 3498c2ecf20Sopenharmony_ci struct iwl_rxon_cmd *active = (void *)&ctx->active; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci if (ctx->ctxid == IWL_RXON_CTX_BSS) { 3528c2ecf20Sopenharmony_ci ret = iwlagn_disable_bss(priv, ctx, &ctx->staging); 3538c2ecf20Sopenharmony_ci } else { 3548c2ecf20Sopenharmony_ci ret = iwlagn_disable_pan(priv, ctx, &ctx->staging); 3558c2ecf20Sopenharmony_ci if (ret) 3568c2ecf20Sopenharmony_ci return ret; 3578c2ecf20Sopenharmony_ci if (ctx->vif) { 3588c2ecf20Sopenharmony_ci ret = iwl_send_rxon_timing(priv, ctx); 3598c2ecf20Sopenharmony_ci if (ret) { 3608c2ecf20Sopenharmony_ci IWL_ERR(priv, "Failed to send timing (%d)!\n", ret); 3618c2ecf20Sopenharmony_ci return ret; 3628c2ecf20Sopenharmony_ci } 3638c2ecf20Sopenharmony_ci ret = iwlagn_disconn_pan(priv, ctx, &ctx->staging); 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci if (ret) 3678c2ecf20Sopenharmony_ci return ret; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci /* 3708c2ecf20Sopenharmony_ci * Un-assoc RXON clears the station table and WEP 3718c2ecf20Sopenharmony_ci * keys, so we have to restore those afterwards. 3728c2ecf20Sopenharmony_ci */ 3738c2ecf20Sopenharmony_ci iwl_clear_ucode_stations(priv, ctx); 3748c2ecf20Sopenharmony_ci /* update -- might need P2P now */ 3758c2ecf20Sopenharmony_ci iwl_update_bcast_station(priv, ctx); 3768c2ecf20Sopenharmony_ci iwl_restore_stations(priv, ctx); 3778c2ecf20Sopenharmony_ci ret = iwl_restore_default_wep_keys(priv, ctx); 3788c2ecf20Sopenharmony_ci if (ret) { 3798c2ecf20Sopenharmony_ci IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret); 3808c2ecf20Sopenharmony_ci return ret; 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci memcpy(active, &ctx->staging, sizeof(*active)); 3848c2ecf20Sopenharmony_ci return 0; 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_cistatic int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci int ret; 3908c2ecf20Sopenharmony_ci s8 prev_tx_power; 3918c2ecf20Sopenharmony_ci bool defer; 3928c2ecf20Sopenharmony_ci struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci if (priv->calib_disabled & IWL_TX_POWER_CALIB_DISABLED) 3958c2ecf20Sopenharmony_ci return 0; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci lockdep_assert_held(&priv->mutex); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci if (priv->tx_power_user_lmt == tx_power && !force) 4008c2ecf20Sopenharmony_ci return 0; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci if (tx_power < IWLAGN_TX_POWER_TARGET_POWER_MIN) { 4038c2ecf20Sopenharmony_ci IWL_WARN(priv, 4048c2ecf20Sopenharmony_ci "Requested user TXPOWER %d below lower limit %d.\n", 4058c2ecf20Sopenharmony_ci tx_power, 4068c2ecf20Sopenharmony_ci IWLAGN_TX_POWER_TARGET_POWER_MIN); 4078c2ecf20Sopenharmony_ci return -EINVAL; 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci if (tx_power > DIV_ROUND_UP(priv->nvm_data->max_tx_pwr_half_dbm, 2)) { 4118c2ecf20Sopenharmony_ci IWL_WARN(priv, 4128c2ecf20Sopenharmony_ci "Requested user TXPOWER %d above upper limit %d.\n", 4138c2ecf20Sopenharmony_ci tx_power, priv->nvm_data->max_tx_pwr_half_dbm); 4148c2ecf20Sopenharmony_ci return -EINVAL; 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci if (!iwl_is_ready_rf(priv)) 4188c2ecf20Sopenharmony_ci return -EIO; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci /* scan complete and commit_rxon use tx_power_next value, 4218c2ecf20Sopenharmony_ci * it always need to be updated for newest request */ 4228c2ecf20Sopenharmony_ci priv->tx_power_next = tx_power; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci /* do not set tx power when scanning or channel changing */ 4258c2ecf20Sopenharmony_ci defer = test_bit(STATUS_SCANNING, &priv->status) || 4268c2ecf20Sopenharmony_ci memcmp(&ctx->active, &ctx->staging, sizeof(ctx->staging)); 4278c2ecf20Sopenharmony_ci if (defer && !force) { 4288c2ecf20Sopenharmony_ci IWL_DEBUG_INFO(priv, "Deferring tx power set\n"); 4298c2ecf20Sopenharmony_ci return 0; 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci prev_tx_power = priv->tx_power_user_lmt; 4338c2ecf20Sopenharmony_ci priv->tx_power_user_lmt = tx_power; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci ret = iwlagn_send_tx_power(priv); 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci /* if fail to set tx_power, restore the orig. tx power */ 4388c2ecf20Sopenharmony_ci if (ret) { 4398c2ecf20Sopenharmony_ci priv->tx_power_user_lmt = prev_tx_power; 4408c2ecf20Sopenharmony_ci priv->tx_power_next = prev_tx_power; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci return ret; 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_cistatic int iwlagn_rxon_connect(struct iwl_priv *priv, 4468c2ecf20Sopenharmony_ci struct iwl_rxon_context *ctx) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci int ret; 4498c2ecf20Sopenharmony_ci struct iwl_rxon_cmd *active = (void *)&ctx->active; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci /* RXON timing must be before associated RXON */ 4528c2ecf20Sopenharmony_ci if (ctx->ctxid == IWL_RXON_CTX_BSS) { 4538c2ecf20Sopenharmony_ci ret = iwl_send_rxon_timing(priv, ctx); 4548c2ecf20Sopenharmony_ci if (ret) { 4558c2ecf20Sopenharmony_ci IWL_ERR(priv, "Failed to send timing (%d)!\n", ret); 4568c2ecf20Sopenharmony_ci return ret; 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci } 4598c2ecf20Sopenharmony_ci /* QoS info may be cleared by previous un-assoc RXON */ 4608c2ecf20Sopenharmony_ci iwlagn_update_qos(priv, ctx); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci /* 4638c2ecf20Sopenharmony_ci * We'll run into this code path when beaconing is 4648c2ecf20Sopenharmony_ci * enabled, but then we also need to send the beacon 4658c2ecf20Sopenharmony_ci * to the device. 4668c2ecf20Sopenharmony_ci */ 4678c2ecf20Sopenharmony_ci if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_AP)) { 4688c2ecf20Sopenharmony_ci ret = iwlagn_update_beacon(priv, ctx->vif); 4698c2ecf20Sopenharmony_ci if (ret) { 4708c2ecf20Sopenharmony_ci IWL_ERR(priv, 4718c2ecf20Sopenharmony_ci "Error sending required beacon (%d)!\n", 4728c2ecf20Sopenharmony_ci ret); 4738c2ecf20Sopenharmony_ci return ret; 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci priv->start_calib = 0; 4788c2ecf20Sopenharmony_ci /* 4798c2ecf20Sopenharmony_ci * Apply the new configuration. 4808c2ecf20Sopenharmony_ci * 4818c2ecf20Sopenharmony_ci * Associated RXON doesn't clear the station table in uCode, 4828c2ecf20Sopenharmony_ci * so we don't need to restore stations etc. after this. 4838c2ecf20Sopenharmony_ci */ 4848c2ecf20Sopenharmony_ci ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_cmd, 0, 4858c2ecf20Sopenharmony_ci sizeof(struct iwl_rxon_cmd), &ctx->staging); 4868c2ecf20Sopenharmony_ci if (ret) { 4878c2ecf20Sopenharmony_ci IWL_ERR(priv, "Error setting new RXON (%d)\n", ret); 4888c2ecf20Sopenharmony_ci return ret; 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci memcpy(active, &ctx->staging, sizeof(*active)); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci /* IBSS beacon needs to be sent after setting assoc */ 4938c2ecf20Sopenharmony_ci if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_ADHOC)) 4948c2ecf20Sopenharmony_ci if (iwlagn_update_beacon(priv, ctx->vif)) 4958c2ecf20Sopenharmony_ci IWL_ERR(priv, "Error sending IBSS beacon\n"); 4968c2ecf20Sopenharmony_ci iwl_init_sensitivity(priv); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci /* 4998c2ecf20Sopenharmony_ci * If we issue a new RXON command which required a tune then 5008c2ecf20Sopenharmony_ci * we must send a new TXPOWER command or we won't be able to 5018c2ecf20Sopenharmony_ci * Tx any frames. 5028c2ecf20Sopenharmony_ci * 5038c2ecf20Sopenharmony_ci * It's expected we set power here if channel is changing. 5048c2ecf20Sopenharmony_ci */ 5058c2ecf20Sopenharmony_ci ret = iwl_set_tx_power(priv, priv->tx_power_next, true); 5068c2ecf20Sopenharmony_ci if (ret) { 5078c2ecf20Sopenharmony_ci IWL_ERR(priv, "Error sending TX power (%d)\n", ret); 5088c2ecf20Sopenharmony_ci return ret; 5098c2ecf20Sopenharmony_ci } 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci return 0; 5128c2ecf20Sopenharmony_ci} 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ciint iwlagn_set_pan_params(struct iwl_priv *priv) 5158c2ecf20Sopenharmony_ci{ 5168c2ecf20Sopenharmony_ci struct iwl_wipan_params_cmd cmd; 5178c2ecf20Sopenharmony_ci struct iwl_rxon_context *ctx_bss, *ctx_pan; 5188c2ecf20Sopenharmony_ci int slot0 = 300, slot1 = 0; 5198c2ecf20Sopenharmony_ci int ret; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci if (priv->valid_contexts == BIT(IWL_RXON_CTX_BSS)) 5228c2ecf20Sopenharmony_ci return 0; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2); 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci lockdep_assert_held(&priv->mutex); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci ctx_bss = &priv->contexts[IWL_RXON_CTX_BSS]; 5298c2ecf20Sopenharmony_ci ctx_pan = &priv->contexts[IWL_RXON_CTX_PAN]; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci /* 5328c2ecf20Sopenharmony_ci * If the PAN context is inactive, then we don't need 5338c2ecf20Sopenharmony_ci * to update the PAN parameters, the last thing we'll 5348c2ecf20Sopenharmony_ci * have done before it goes inactive is making the PAN 5358c2ecf20Sopenharmony_ci * parameters be WLAN-only. 5368c2ecf20Sopenharmony_ci */ 5378c2ecf20Sopenharmony_ci if (!ctx_pan->is_active) 5388c2ecf20Sopenharmony_ci return 0; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci /* only 2 slots are currently allowed */ 5438c2ecf20Sopenharmony_ci cmd.num_slots = 2; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci cmd.slots[0].type = 0; /* BSS */ 5468c2ecf20Sopenharmony_ci cmd.slots[1].type = 1; /* PAN */ 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci if (ctx_bss->vif && ctx_pan->vif) { 5498c2ecf20Sopenharmony_ci int bcnint = ctx_pan->beacon_int; 5508c2ecf20Sopenharmony_ci int dtim = ctx_pan->vif->bss_conf.dtim_period ?: 1; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci /* should be set, but seems unused?? */ 5538c2ecf20Sopenharmony_ci cmd.flags |= cpu_to_le16(IWL_WIPAN_PARAMS_FLG_SLOTTED_MODE); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci if (ctx_pan->vif->type == NL80211_IFTYPE_AP && 5568c2ecf20Sopenharmony_ci bcnint && 5578c2ecf20Sopenharmony_ci bcnint != ctx_bss->beacon_int) { 5588c2ecf20Sopenharmony_ci IWL_ERR(priv, 5598c2ecf20Sopenharmony_ci "beacon intervals don't match (%d, %d)\n", 5608c2ecf20Sopenharmony_ci ctx_bss->beacon_int, ctx_pan->beacon_int); 5618c2ecf20Sopenharmony_ci } else 5628c2ecf20Sopenharmony_ci bcnint = max_t(int, bcnint, 5638c2ecf20Sopenharmony_ci ctx_bss->beacon_int); 5648c2ecf20Sopenharmony_ci if (!bcnint) 5658c2ecf20Sopenharmony_ci bcnint = DEFAULT_BEACON_INTERVAL; 5668c2ecf20Sopenharmony_ci slot0 = bcnint / 2; 5678c2ecf20Sopenharmony_ci slot1 = bcnint - slot0; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci if (test_bit(STATUS_SCAN_HW, &priv->status) || 5708c2ecf20Sopenharmony_ci (!ctx_bss->vif->bss_conf.idle && 5718c2ecf20Sopenharmony_ci !ctx_bss->vif->bss_conf.assoc)) { 5728c2ecf20Sopenharmony_ci slot0 = dtim * bcnint * 3 - IWL_MIN_SLOT_TIME; 5738c2ecf20Sopenharmony_ci slot1 = IWL_MIN_SLOT_TIME; 5748c2ecf20Sopenharmony_ci } else if (!ctx_pan->vif->bss_conf.idle && 5758c2ecf20Sopenharmony_ci !ctx_pan->vif->bss_conf.assoc) { 5768c2ecf20Sopenharmony_ci slot1 = dtim * bcnint * 3 - IWL_MIN_SLOT_TIME; 5778c2ecf20Sopenharmony_ci slot0 = IWL_MIN_SLOT_TIME; 5788c2ecf20Sopenharmony_ci } 5798c2ecf20Sopenharmony_ci } else if (ctx_pan->vif) { 5808c2ecf20Sopenharmony_ci slot0 = 0; 5818c2ecf20Sopenharmony_ci slot1 = max_t(int, 1, ctx_pan->vif->bss_conf.dtim_period) * 5828c2ecf20Sopenharmony_ci ctx_pan->beacon_int; 5838c2ecf20Sopenharmony_ci slot1 = max_t(int, DEFAULT_BEACON_INTERVAL, slot1); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci if (test_bit(STATUS_SCAN_HW, &priv->status)) { 5868c2ecf20Sopenharmony_ci slot0 = slot1 * 3 - IWL_MIN_SLOT_TIME; 5878c2ecf20Sopenharmony_ci slot1 = IWL_MIN_SLOT_TIME; 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci cmd.slots[0].width = cpu_to_le16(slot0); 5928c2ecf20Sopenharmony_ci cmd.slots[1].width = cpu_to_le16(slot1); 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci ret = iwl_dvm_send_cmd_pdu(priv, REPLY_WIPAN_PARAMS, 0, 5958c2ecf20Sopenharmony_ci sizeof(cmd), &cmd); 5968c2ecf20Sopenharmony_ci if (ret) 5978c2ecf20Sopenharmony_ci IWL_ERR(priv, "Error setting PAN parameters (%d)\n", ret); 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci return ret; 6008c2ecf20Sopenharmony_ci} 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_cistatic void _iwl_set_rxon_ht(struct iwl_priv *priv, 6038c2ecf20Sopenharmony_ci struct iwl_ht_config *ht_conf, 6048c2ecf20Sopenharmony_ci struct iwl_rxon_context *ctx) 6058c2ecf20Sopenharmony_ci{ 6068c2ecf20Sopenharmony_ci struct iwl_rxon_cmd *rxon = &ctx->staging; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci if (!ctx->ht.enabled) { 6098c2ecf20Sopenharmony_ci rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK | 6108c2ecf20Sopenharmony_ci RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK | 6118c2ecf20Sopenharmony_ci RXON_FLG_HT40_PROT_MSK | 6128c2ecf20Sopenharmony_ci RXON_FLG_HT_PROT_MSK); 6138c2ecf20Sopenharmony_ci return; 6148c2ecf20Sopenharmony_ci } 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci /* FIXME: if the definition of ht.protection changed, the "translation" 6178c2ecf20Sopenharmony_ci * will be needed for rxon->flags 6188c2ecf20Sopenharmony_ci */ 6198c2ecf20Sopenharmony_ci rxon->flags |= cpu_to_le32(ctx->ht.protection << 6208c2ecf20Sopenharmony_ci RXON_FLG_HT_OPERATING_MODE_POS); 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci /* Set up channel bandwidth: 6238c2ecf20Sopenharmony_ci * 20 MHz only, 20/40 mixed or pure 40 if ht40 ok */ 6248c2ecf20Sopenharmony_ci /* clear the HT channel mode before set the mode */ 6258c2ecf20Sopenharmony_ci rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK | 6268c2ecf20Sopenharmony_ci RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); 6278c2ecf20Sopenharmony_ci if (iwl_is_ht40_tx_allowed(priv, ctx, NULL)) { 6288c2ecf20Sopenharmony_ci /* pure ht40 */ 6298c2ecf20Sopenharmony_ci if (ctx->ht.protection == 6308c2ecf20Sopenharmony_ci IEEE80211_HT_OP_MODE_PROTECTION_20MHZ) { 6318c2ecf20Sopenharmony_ci rxon->flags |= RXON_FLG_CHANNEL_MODE_PURE_40; 6328c2ecf20Sopenharmony_ci /* 6338c2ecf20Sopenharmony_ci * Note: control channel is opposite of extension 6348c2ecf20Sopenharmony_ci * channel 6358c2ecf20Sopenharmony_ci */ 6368c2ecf20Sopenharmony_ci switch (ctx->ht.extension_chan_offset) { 6378c2ecf20Sopenharmony_ci case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: 6388c2ecf20Sopenharmony_ci rxon->flags &= 6398c2ecf20Sopenharmony_ci ~RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; 6408c2ecf20Sopenharmony_ci break; 6418c2ecf20Sopenharmony_ci case IEEE80211_HT_PARAM_CHA_SEC_BELOW: 6428c2ecf20Sopenharmony_ci rxon->flags |= 6438c2ecf20Sopenharmony_ci RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; 6448c2ecf20Sopenharmony_ci break; 6458c2ecf20Sopenharmony_ci } 6468c2ecf20Sopenharmony_ci } else { 6478c2ecf20Sopenharmony_ci /* 6488c2ecf20Sopenharmony_ci * Note: control channel is opposite of extension 6498c2ecf20Sopenharmony_ci * channel 6508c2ecf20Sopenharmony_ci */ 6518c2ecf20Sopenharmony_ci switch (ctx->ht.extension_chan_offset) { 6528c2ecf20Sopenharmony_ci case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: 6538c2ecf20Sopenharmony_ci rxon->flags &= 6548c2ecf20Sopenharmony_ci ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); 6558c2ecf20Sopenharmony_ci rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED; 6568c2ecf20Sopenharmony_ci break; 6578c2ecf20Sopenharmony_ci case IEEE80211_HT_PARAM_CHA_SEC_BELOW: 6588c2ecf20Sopenharmony_ci rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; 6598c2ecf20Sopenharmony_ci rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED; 6608c2ecf20Sopenharmony_ci break; 6618c2ecf20Sopenharmony_ci case IEEE80211_HT_PARAM_CHA_SEC_NONE: 6628c2ecf20Sopenharmony_ci default: 6638c2ecf20Sopenharmony_ci /* 6648c2ecf20Sopenharmony_ci * channel location only valid if in Mixed 6658c2ecf20Sopenharmony_ci * mode 6668c2ecf20Sopenharmony_ci */ 6678c2ecf20Sopenharmony_ci IWL_ERR(priv, 6688c2ecf20Sopenharmony_ci "invalid extension channel offset\n"); 6698c2ecf20Sopenharmony_ci break; 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci } else { 6738c2ecf20Sopenharmony_ci rxon->flags |= RXON_FLG_CHANNEL_MODE_LEGACY; 6748c2ecf20Sopenharmony_ci } 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci iwlagn_set_rxon_chain(priv, ctx); 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci IWL_DEBUG_ASSOC(priv, "rxon flags 0x%X operation mode :0x%X " 6798c2ecf20Sopenharmony_ci "extension channel offset 0x%x\n", 6808c2ecf20Sopenharmony_ci le32_to_cpu(rxon->flags), ctx->ht.protection, 6818c2ecf20Sopenharmony_ci ctx->ht.extension_chan_offset); 6828c2ecf20Sopenharmony_ci} 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_civoid iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf) 6858c2ecf20Sopenharmony_ci{ 6868c2ecf20Sopenharmony_ci struct iwl_rxon_context *ctx; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci for_each_context(priv, ctx) 6898c2ecf20Sopenharmony_ci _iwl_set_rxon_ht(priv, ht_conf, ctx); 6908c2ecf20Sopenharmony_ci} 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci/* 6938c2ecf20Sopenharmony_ci * iwl_set_rxon_channel - Set the band and channel values in staging RXON 6948c2ecf20Sopenharmony_ci * @ch: requested channel as a pointer to struct ieee80211_channel 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci * NOTE: Does not commit to the hardware; it sets appropriate bit fields 6978c2ecf20Sopenharmony_ci * in the staging RXON flag structure based on the ch->band 6988c2ecf20Sopenharmony_ci */ 6998c2ecf20Sopenharmony_civoid iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch, 7008c2ecf20Sopenharmony_ci struct iwl_rxon_context *ctx) 7018c2ecf20Sopenharmony_ci{ 7028c2ecf20Sopenharmony_ci enum nl80211_band band = ch->band; 7038c2ecf20Sopenharmony_ci u16 channel = ch->hw_value; 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci if ((le16_to_cpu(ctx->staging.channel) == channel) && 7068c2ecf20Sopenharmony_ci (priv->band == band)) 7078c2ecf20Sopenharmony_ci return; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci ctx->staging.channel = cpu_to_le16(channel); 7108c2ecf20Sopenharmony_ci if (band == NL80211_BAND_5GHZ) 7118c2ecf20Sopenharmony_ci ctx->staging.flags &= ~RXON_FLG_BAND_24G_MSK; 7128c2ecf20Sopenharmony_ci else 7138c2ecf20Sopenharmony_ci ctx->staging.flags |= RXON_FLG_BAND_24G_MSK; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci priv->band = band; 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci IWL_DEBUG_INFO(priv, "Staging channel set to %d [%d]\n", channel, band); 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci} 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_civoid iwl_set_flags_for_band(struct iwl_priv *priv, 7228c2ecf20Sopenharmony_ci struct iwl_rxon_context *ctx, 7238c2ecf20Sopenharmony_ci enum nl80211_band band, 7248c2ecf20Sopenharmony_ci struct ieee80211_vif *vif) 7258c2ecf20Sopenharmony_ci{ 7268c2ecf20Sopenharmony_ci if (band == NL80211_BAND_5GHZ) { 7278c2ecf20Sopenharmony_ci ctx->staging.flags &= 7288c2ecf20Sopenharmony_ci ~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK 7298c2ecf20Sopenharmony_ci | RXON_FLG_CCK_MSK); 7308c2ecf20Sopenharmony_ci ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK; 7318c2ecf20Sopenharmony_ci } else { 7328c2ecf20Sopenharmony_ci /* Copied from iwl_post_associate() */ 7338c2ecf20Sopenharmony_ci if (vif && vif->bss_conf.use_short_slot) 7348c2ecf20Sopenharmony_ci ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK; 7358c2ecf20Sopenharmony_ci else 7368c2ecf20Sopenharmony_ci ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci ctx->staging.flags |= RXON_FLG_BAND_24G_MSK; 7398c2ecf20Sopenharmony_ci ctx->staging.flags |= RXON_FLG_AUTO_DETECT_MSK; 7408c2ecf20Sopenharmony_ci ctx->staging.flags &= ~RXON_FLG_CCK_MSK; 7418c2ecf20Sopenharmony_ci } 7428c2ecf20Sopenharmony_ci} 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_cistatic void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, 7458c2ecf20Sopenharmony_ci struct iwl_rxon_context *ctx, int hw_decrypt) 7468c2ecf20Sopenharmony_ci{ 7478c2ecf20Sopenharmony_ci struct iwl_rxon_cmd *rxon = &ctx->staging; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci if (hw_decrypt) 7508c2ecf20Sopenharmony_ci rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK; 7518c2ecf20Sopenharmony_ci else 7528c2ecf20Sopenharmony_ci rxon->filter_flags |= RXON_FILTER_DIS_DECRYPT_MSK; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci} 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci/* validate RXON structure is valid */ 7578c2ecf20Sopenharmony_cistatic int iwl_check_rxon_cmd(struct iwl_priv *priv, 7588c2ecf20Sopenharmony_ci struct iwl_rxon_context *ctx) 7598c2ecf20Sopenharmony_ci{ 7608c2ecf20Sopenharmony_ci struct iwl_rxon_cmd *rxon = &ctx->staging; 7618c2ecf20Sopenharmony_ci u32 errors = 0; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci if (rxon->flags & RXON_FLG_BAND_24G_MSK) { 7648c2ecf20Sopenharmony_ci if (rxon->flags & RXON_FLG_TGJ_NARROW_BAND_MSK) { 7658c2ecf20Sopenharmony_ci IWL_WARN(priv, "check 2.4G: wrong narrow\n"); 7668c2ecf20Sopenharmony_ci errors |= BIT(0); 7678c2ecf20Sopenharmony_ci } 7688c2ecf20Sopenharmony_ci if (rxon->flags & RXON_FLG_RADAR_DETECT_MSK) { 7698c2ecf20Sopenharmony_ci IWL_WARN(priv, "check 2.4G: wrong radar\n"); 7708c2ecf20Sopenharmony_ci errors |= BIT(1); 7718c2ecf20Sopenharmony_ci } 7728c2ecf20Sopenharmony_ci } else { 7738c2ecf20Sopenharmony_ci if (!(rxon->flags & RXON_FLG_SHORT_SLOT_MSK)) { 7748c2ecf20Sopenharmony_ci IWL_WARN(priv, "check 5.2G: not short slot!\n"); 7758c2ecf20Sopenharmony_ci errors |= BIT(2); 7768c2ecf20Sopenharmony_ci } 7778c2ecf20Sopenharmony_ci if (rxon->flags & RXON_FLG_CCK_MSK) { 7788c2ecf20Sopenharmony_ci IWL_WARN(priv, "check 5.2G: CCK!\n"); 7798c2ecf20Sopenharmony_ci errors |= BIT(3); 7808c2ecf20Sopenharmony_ci } 7818c2ecf20Sopenharmony_ci } 7828c2ecf20Sopenharmony_ci if ((rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1) { 7838c2ecf20Sopenharmony_ci IWL_WARN(priv, "mac/bssid mcast!\n"); 7848c2ecf20Sopenharmony_ci errors |= BIT(4); 7858c2ecf20Sopenharmony_ci } 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci /* make sure basic rates 6Mbps and 1Mbps are supported */ 7888c2ecf20Sopenharmony_ci if ((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0 && 7898c2ecf20Sopenharmony_ci (rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0) { 7908c2ecf20Sopenharmony_ci IWL_WARN(priv, "neither 1 nor 6 are basic\n"); 7918c2ecf20Sopenharmony_ci errors |= BIT(5); 7928c2ecf20Sopenharmony_ci } 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci if (le16_to_cpu(rxon->assoc_id) > 2007) { 7958c2ecf20Sopenharmony_ci IWL_WARN(priv, "aid > 2007\n"); 7968c2ecf20Sopenharmony_ci errors |= BIT(6); 7978c2ecf20Sopenharmony_ci } 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci if ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) 8008c2ecf20Sopenharmony_ci == (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) { 8018c2ecf20Sopenharmony_ci IWL_WARN(priv, "CCK and short slot\n"); 8028c2ecf20Sopenharmony_ci errors |= BIT(7); 8038c2ecf20Sopenharmony_ci } 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci if ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) 8068c2ecf20Sopenharmony_ci == (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) { 8078c2ecf20Sopenharmony_ci IWL_WARN(priv, "CCK and auto detect\n"); 8088c2ecf20Sopenharmony_ci errors |= BIT(8); 8098c2ecf20Sopenharmony_ci } 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci if ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK | 8128c2ecf20Sopenharmony_ci RXON_FLG_TGG_PROTECT_MSK)) == 8138c2ecf20Sopenharmony_ci RXON_FLG_TGG_PROTECT_MSK) { 8148c2ecf20Sopenharmony_ci IWL_WARN(priv, "TGg but no auto-detect\n"); 8158c2ecf20Sopenharmony_ci errors |= BIT(9); 8168c2ecf20Sopenharmony_ci } 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci if (rxon->channel == 0) { 8198c2ecf20Sopenharmony_ci IWL_WARN(priv, "zero channel is invalid\n"); 8208c2ecf20Sopenharmony_ci errors |= BIT(10); 8218c2ecf20Sopenharmony_ci } 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci WARN(errors, "Invalid RXON (%#x), channel %d", 8248c2ecf20Sopenharmony_ci errors, le16_to_cpu(rxon->channel)); 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci return errors ? -EINVAL : 0; 8278c2ecf20Sopenharmony_ci} 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci/* 8308c2ecf20Sopenharmony_ci * iwl_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed 8318c2ecf20Sopenharmony_ci * @priv: staging_rxon is compared to active_rxon 8328c2ecf20Sopenharmony_ci * 8338c2ecf20Sopenharmony_ci * If the RXON structure is changing enough to require a new tune, 8348c2ecf20Sopenharmony_ci * or is clearing the RXON_FILTER_ASSOC_MSK, then return 1 to indicate that 8358c2ecf20Sopenharmony_ci * a new tune (full RXON command, rather than RXON_ASSOC cmd) is required. 8368c2ecf20Sopenharmony_ci */ 8378c2ecf20Sopenharmony_cistatic int iwl_full_rxon_required(struct iwl_priv *priv, 8388c2ecf20Sopenharmony_ci struct iwl_rxon_context *ctx) 8398c2ecf20Sopenharmony_ci{ 8408c2ecf20Sopenharmony_ci const struct iwl_rxon_cmd *staging = &ctx->staging; 8418c2ecf20Sopenharmony_ci const struct iwl_rxon_cmd *active = &ctx->active; 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci#define CHK(cond) \ 8448c2ecf20Sopenharmony_ci if ((cond)) { \ 8458c2ecf20Sopenharmony_ci IWL_DEBUG_INFO(priv, "need full RXON - " #cond "\n"); \ 8468c2ecf20Sopenharmony_ci return 1; \ 8478c2ecf20Sopenharmony_ci } 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci#define CHK_NEQ(c1, c2) \ 8508c2ecf20Sopenharmony_ci if ((c1) != (c2)) { \ 8518c2ecf20Sopenharmony_ci IWL_DEBUG_INFO(priv, "need full RXON - " \ 8528c2ecf20Sopenharmony_ci #c1 " != " #c2 " - %d != %d\n", \ 8538c2ecf20Sopenharmony_ci (c1), (c2)); \ 8548c2ecf20Sopenharmony_ci return 1; \ 8558c2ecf20Sopenharmony_ci } 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci /* These items are only settable from the full RXON command */ 8588c2ecf20Sopenharmony_ci CHK(!iwl_is_associated_ctx(ctx)); 8598c2ecf20Sopenharmony_ci CHK(!ether_addr_equal(staging->bssid_addr, active->bssid_addr)); 8608c2ecf20Sopenharmony_ci CHK(!ether_addr_equal(staging->node_addr, active->node_addr)); 8618c2ecf20Sopenharmony_ci CHK(!ether_addr_equal(staging->wlap_bssid_addr, 8628c2ecf20Sopenharmony_ci active->wlap_bssid_addr)); 8638c2ecf20Sopenharmony_ci CHK_NEQ(staging->dev_type, active->dev_type); 8648c2ecf20Sopenharmony_ci CHK_NEQ(staging->channel, active->channel); 8658c2ecf20Sopenharmony_ci CHK_NEQ(staging->air_propagation, active->air_propagation); 8668c2ecf20Sopenharmony_ci CHK_NEQ(staging->ofdm_ht_single_stream_basic_rates, 8678c2ecf20Sopenharmony_ci active->ofdm_ht_single_stream_basic_rates); 8688c2ecf20Sopenharmony_ci CHK_NEQ(staging->ofdm_ht_dual_stream_basic_rates, 8698c2ecf20Sopenharmony_ci active->ofdm_ht_dual_stream_basic_rates); 8708c2ecf20Sopenharmony_ci CHK_NEQ(staging->ofdm_ht_triple_stream_basic_rates, 8718c2ecf20Sopenharmony_ci active->ofdm_ht_triple_stream_basic_rates); 8728c2ecf20Sopenharmony_ci CHK_NEQ(staging->assoc_id, active->assoc_id); 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci /* flags, filter_flags, ofdm_basic_rates, and cck_basic_rates can 8758c2ecf20Sopenharmony_ci * be updated with the RXON_ASSOC command -- however only some 8768c2ecf20Sopenharmony_ci * flag transitions are allowed using RXON_ASSOC */ 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci /* Check if we are not switching bands */ 8798c2ecf20Sopenharmony_ci CHK_NEQ(staging->flags & RXON_FLG_BAND_24G_MSK, 8808c2ecf20Sopenharmony_ci active->flags & RXON_FLG_BAND_24G_MSK); 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci /* Check if we are switching association toggle */ 8838c2ecf20Sopenharmony_ci CHK_NEQ(staging->filter_flags & RXON_FILTER_ASSOC_MSK, 8848c2ecf20Sopenharmony_ci active->filter_flags & RXON_FILTER_ASSOC_MSK); 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci#undef CHK 8878c2ecf20Sopenharmony_ci#undef CHK_NEQ 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci return 0; 8908c2ecf20Sopenharmony_ci} 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci#ifdef CONFIG_IWLWIFI_DEBUG 8938c2ecf20Sopenharmony_civoid iwl_print_rx_config_cmd(struct iwl_priv *priv, 8948c2ecf20Sopenharmony_ci enum iwl_rxon_context_id ctxid) 8958c2ecf20Sopenharmony_ci{ 8968c2ecf20Sopenharmony_ci struct iwl_rxon_context *ctx = &priv->contexts[ctxid]; 8978c2ecf20Sopenharmony_ci struct iwl_rxon_cmd *rxon = &ctx->staging; 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci IWL_DEBUG_RADIO(priv, "RX CONFIG:\n"); 9008c2ecf20Sopenharmony_ci iwl_print_hex_dump(priv, IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); 9018c2ecf20Sopenharmony_ci IWL_DEBUG_RADIO(priv, "u16 channel: 0x%x\n", 9028c2ecf20Sopenharmony_ci le16_to_cpu(rxon->channel)); 9038c2ecf20Sopenharmony_ci IWL_DEBUG_RADIO(priv, "u32 flags: 0x%08X\n", 9048c2ecf20Sopenharmony_ci le32_to_cpu(rxon->flags)); 9058c2ecf20Sopenharmony_ci IWL_DEBUG_RADIO(priv, "u32 filter_flags: 0x%08x\n", 9068c2ecf20Sopenharmony_ci le32_to_cpu(rxon->filter_flags)); 9078c2ecf20Sopenharmony_ci IWL_DEBUG_RADIO(priv, "u8 dev_type: 0x%x\n", rxon->dev_type); 9088c2ecf20Sopenharmony_ci IWL_DEBUG_RADIO(priv, "u8 ofdm_basic_rates: 0x%02x\n", 9098c2ecf20Sopenharmony_ci rxon->ofdm_basic_rates); 9108c2ecf20Sopenharmony_ci IWL_DEBUG_RADIO(priv, "u8 cck_basic_rates: 0x%02x\n", 9118c2ecf20Sopenharmony_ci rxon->cck_basic_rates); 9128c2ecf20Sopenharmony_ci IWL_DEBUG_RADIO(priv, "u8[6] node_addr: %pM\n", rxon->node_addr); 9138c2ecf20Sopenharmony_ci IWL_DEBUG_RADIO(priv, "u8[6] bssid_addr: %pM\n", rxon->bssid_addr); 9148c2ecf20Sopenharmony_ci IWL_DEBUG_RADIO(priv, "u16 assoc_id: 0x%x\n", 9158c2ecf20Sopenharmony_ci le16_to_cpu(rxon->assoc_id)); 9168c2ecf20Sopenharmony_ci} 9178c2ecf20Sopenharmony_ci#endif 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_cistatic void iwl_calc_basic_rates(struct iwl_priv *priv, 9208c2ecf20Sopenharmony_ci struct iwl_rxon_context *ctx) 9218c2ecf20Sopenharmony_ci{ 9228c2ecf20Sopenharmony_ci int lowest_present_ofdm = 100; 9238c2ecf20Sopenharmony_ci int lowest_present_cck = 100; 9248c2ecf20Sopenharmony_ci u8 cck = 0; 9258c2ecf20Sopenharmony_ci u8 ofdm = 0; 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci if (ctx->vif) { 9288c2ecf20Sopenharmony_ci struct ieee80211_supported_band *sband; 9298c2ecf20Sopenharmony_ci unsigned long basic = ctx->vif->bss_conf.basic_rates; 9308c2ecf20Sopenharmony_ci int i; 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci sband = priv->hw->wiphy->bands[priv->hw->conf.chandef.chan->band]; 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci for_each_set_bit(i, &basic, BITS_PER_LONG) { 9358c2ecf20Sopenharmony_ci int hw = sband->bitrates[i].hw_value; 9368c2ecf20Sopenharmony_ci if (hw >= IWL_FIRST_OFDM_RATE) { 9378c2ecf20Sopenharmony_ci ofdm |= BIT(hw - IWL_FIRST_OFDM_RATE); 9388c2ecf20Sopenharmony_ci if (lowest_present_ofdm > hw) 9398c2ecf20Sopenharmony_ci lowest_present_ofdm = hw; 9408c2ecf20Sopenharmony_ci } else { 9418c2ecf20Sopenharmony_ci BUILD_BUG_ON(IWL_FIRST_CCK_RATE != 0); 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci cck |= BIT(hw); 9448c2ecf20Sopenharmony_ci if (lowest_present_cck > hw) 9458c2ecf20Sopenharmony_ci lowest_present_cck = hw; 9468c2ecf20Sopenharmony_ci } 9478c2ecf20Sopenharmony_ci } 9488c2ecf20Sopenharmony_ci } 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci /* 9518c2ecf20Sopenharmony_ci * Now we've got the basic rates as bitmaps in the ofdm and cck 9528c2ecf20Sopenharmony_ci * variables. This isn't sufficient though, as there might not 9538c2ecf20Sopenharmony_ci * be all the right rates in the bitmap. E.g. if the only basic 9548c2ecf20Sopenharmony_ci * rates are 5.5 Mbps and 11 Mbps, we still need to add 1 Mbps 9558c2ecf20Sopenharmony_ci * and 6 Mbps because the 802.11-2007 standard says in 9.6: 9568c2ecf20Sopenharmony_ci * 9578c2ecf20Sopenharmony_ci * [...] a STA responding to a received frame shall transmit 9588c2ecf20Sopenharmony_ci * its Control Response frame [...] at the highest rate in the 9598c2ecf20Sopenharmony_ci * BSSBasicRateSet parameter that is less than or equal to the 9608c2ecf20Sopenharmony_ci * rate of the immediately previous frame in the frame exchange 9618c2ecf20Sopenharmony_ci * sequence ([...]) and that is of the same modulation class 9628c2ecf20Sopenharmony_ci * ([...]) as the received frame. If no rate contained in the 9638c2ecf20Sopenharmony_ci * BSSBasicRateSet parameter meets these conditions, then the 9648c2ecf20Sopenharmony_ci * control frame sent in response to a received frame shall be 9658c2ecf20Sopenharmony_ci * transmitted at the highest mandatory rate of the PHY that is 9668c2ecf20Sopenharmony_ci * less than or equal to the rate of the received frame, and 9678c2ecf20Sopenharmony_ci * that is of the same modulation class as the received frame. 9688c2ecf20Sopenharmony_ci * 9698c2ecf20Sopenharmony_ci * As a consequence, we need to add all mandatory rates that are 9708c2ecf20Sopenharmony_ci * lower than all of the basic rates to these bitmaps. 9718c2ecf20Sopenharmony_ci */ 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci if (IWL_RATE_24M_INDEX < lowest_present_ofdm) 9748c2ecf20Sopenharmony_ci ofdm |= IWL_RATE_24M_MASK >> IWL_FIRST_OFDM_RATE; 9758c2ecf20Sopenharmony_ci if (IWL_RATE_12M_INDEX < lowest_present_ofdm) 9768c2ecf20Sopenharmony_ci ofdm |= IWL_RATE_12M_MASK >> IWL_FIRST_OFDM_RATE; 9778c2ecf20Sopenharmony_ci /* 6M already there or needed so always add */ 9788c2ecf20Sopenharmony_ci ofdm |= IWL_RATE_6M_MASK >> IWL_FIRST_OFDM_RATE; 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci /* 9818c2ecf20Sopenharmony_ci * CCK is a bit more complex with DSSS vs. HR/DSSS vs. ERP. 9828c2ecf20Sopenharmony_ci * Note, however: 9838c2ecf20Sopenharmony_ci * - if no CCK rates are basic, it must be ERP since there must 9848c2ecf20Sopenharmony_ci * be some basic rates at all, so they're OFDM => ERP PHY 9858c2ecf20Sopenharmony_ci * (or we're in 5 GHz, and the cck bitmap will never be used) 9868c2ecf20Sopenharmony_ci * - if 11M is a basic rate, it must be ERP as well, so add 5.5M 9878c2ecf20Sopenharmony_ci * - if 5.5M is basic, 1M and 2M are mandatory 9888c2ecf20Sopenharmony_ci * - if 2M is basic, 1M is mandatory 9898c2ecf20Sopenharmony_ci * - if 1M is basic, that's the only valid ACK rate. 9908c2ecf20Sopenharmony_ci * As a consequence, it's not as complicated as it sounds, just add 9918c2ecf20Sopenharmony_ci * any lower rates to the ACK rate bitmap. 9928c2ecf20Sopenharmony_ci */ 9938c2ecf20Sopenharmony_ci if (IWL_RATE_11M_INDEX < lowest_present_cck) 9948c2ecf20Sopenharmony_ci cck |= IWL_RATE_11M_MASK >> IWL_FIRST_CCK_RATE; 9958c2ecf20Sopenharmony_ci if (IWL_RATE_5M_INDEX < lowest_present_cck) 9968c2ecf20Sopenharmony_ci cck |= IWL_RATE_5M_MASK >> IWL_FIRST_CCK_RATE; 9978c2ecf20Sopenharmony_ci if (IWL_RATE_2M_INDEX < lowest_present_cck) 9988c2ecf20Sopenharmony_ci cck |= IWL_RATE_2M_MASK >> IWL_FIRST_CCK_RATE; 9998c2ecf20Sopenharmony_ci /* 1M already there or needed so always add */ 10008c2ecf20Sopenharmony_ci cck |= IWL_RATE_1M_MASK >> IWL_FIRST_CCK_RATE; 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci IWL_DEBUG_RATE(priv, "Set basic rates cck:0x%.2x ofdm:0x%.2x\n", 10038c2ecf20Sopenharmony_ci cck, ofdm); 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci /* "basic_rates" is a misnomer here -- should be called ACK rates */ 10068c2ecf20Sopenharmony_ci ctx->staging.cck_basic_rates = cck; 10078c2ecf20Sopenharmony_ci ctx->staging.ofdm_basic_rates = ofdm; 10088c2ecf20Sopenharmony_ci} 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci/* 10118c2ecf20Sopenharmony_ci * iwlagn_commit_rxon - commit staging_rxon to hardware 10128c2ecf20Sopenharmony_ci * 10138c2ecf20Sopenharmony_ci * The RXON command in staging_rxon is committed to the hardware and 10148c2ecf20Sopenharmony_ci * the active_rxon structure is updated with the new data. This 10158c2ecf20Sopenharmony_ci * function correctly transitions out of the RXON_ASSOC_MSK state if 10168c2ecf20Sopenharmony_ci * a HW tune is required based on the RXON structure changes. 10178c2ecf20Sopenharmony_ci * 10188c2ecf20Sopenharmony_ci * The connect/disconnect flow should be as the following: 10198c2ecf20Sopenharmony_ci * 10208c2ecf20Sopenharmony_ci * 1. make sure send RXON command with association bit unset if not connect 10218c2ecf20Sopenharmony_ci * this should include the channel and the band for the candidate 10228c2ecf20Sopenharmony_ci * to be connected to 10238c2ecf20Sopenharmony_ci * 2. Add Station before RXON association with the AP 10248c2ecf20Sopenharmony_ci * 3. RXON_timing has to send before RXON for connection 10258c2ecf20Sopenharmony_ci * 4. full RXON command - associated bit set 10268c2ecf20Sopenharmony_ci * 5. use RXON_ASSOC command to update any flags changes 10278c2ecf20Sopenharmony_ci */ 10288c2ecf20Sopenharmony_ciint iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) 10298c2ecf20Sopenharmony_ci{ 10308c2ecf20Sopenharmony_ci /* cast away the const for active_rxon in this function */ 10318c2ecf20Sopenharmony_ci struct iwl_rxon_cmd *active = (void *)&ctx->active; 10328c2ecf20Sopenharmony_ci bool new_assoc = !!(ctx->staging.filter_flags & RXON_FILTER_ASSOC_MSK); 10338c2ecf20Sopenharmony_ci int ret; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci lockdep_assert_held(&priv->mutex); 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci if (!iwl_is_alive(priv)) 10388c2ecf20Sopenharmony_ci return -EBUSY; 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci /* This function hardcodes a bunch of dual-mode assumptions */ 10418c2ecf20Sopenharmony_ci BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2); 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci if (!ctx->is_active) 10448c2ecf20Sopenharmony_ci return 0; 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci /* always get timestamp with Rx frame */ 10478c2ecf20Sopenharmony_ci ctx->staging.flags |= RXON_FLG_TSF2HOST_MSK; 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci /* recalculate basic rates */ 10508c2ecf20Sopenharmony_ci iwl_calc_basic_rates(priv, ctx); 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci /* 10538c2ecf20Sopenharmony_ci * force CTS-to-self frames protection if RTS-CTS is not preferred 10548c2ecf20Sopenharmony_ci * one aggregation protection method 10558c2ecf20Sopenharmony_ci */ 10568c2ecf20Sopenharmony_ci if (!priv->hw_params.use_rts_for_aggregation) 10578c2ecf20Sopenharmony_ci ctx->staging.flags |= RXON_FLG_SELF_CTS_EN; 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci if ((ctx->vif && ctx->vif->bss_conf.use_short_slot) || 10608c2ecf20Sopenharmony_ci !(ctx->staging.flags & RXON_FLG_BAND_24G_MSK)) 10618c2ecf20Sopenharmony_ci ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK; 10628c2ecf20Sopenharmony_ci else 10638c2ecf20Sopenharmony_ci ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK; 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci iwl_print_rx_config_cmd(priv, ctx->ctxid); 10668c2ecf20Sopenharmony_ci ret = iwl_check_rxon_cmd(priv, ctx); 10678c2ecf20Sopenharmony_ci if (ret) { 10688c2ecf20Sopenharmony_ci IWL_ERR(priv, "Invalid RXON configuration. Not committing.\n"); 10698c2ecf20Sopenharmony_ci return -EINVAL; 10708c2ecf20Sopenharmony_ci } 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci /* 10738c2ecf20Sopenharmony_ci * receive commit_rxon request 10748c2ecf20Sopenharmony_ci * abort any previous channel switch if still in process 10758c2ecf20Sopenharmony_ci */ 10768c2ecf20Sopenharmony_ci if (test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status) && 10778c2ecf20Sopenharmony_ci (priv->switch_channel != ctx->staging.channel)) { 10788c2ecf20Sopenharmony_ci IWL_DEBUG_11H(priv, "abort channel switch on %d\n", 10798c2ecf20Sopenharmony_ci le16_to_cpu(priv->switch_channel)); 10808c2ecf20Sopenharmony_ci iwl_chswitch_done(priv, false); 10818c2ecf20Sopenharmony_ci } 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci /* 10848c2ecf20Sopenharmony_ci * If we don't need to send a full RXON, we can use 10858c2ecf20Sopenharmony_ci * iwl_rxon_assoc_cmd which is used to reconfigure filter 10868c2ecf20Sopenharmony_ci * and other flags for the current radio configuration. 10878c2ecf20Sopenharmony_ci */ 10888c2ecf20Sopenharmony_ci if (!iwl_full_rxon_required(priv, ctx)) { 10898c2ecf20Sopenharmony_ci ret = iwlagn_send_rxon_assoc(priv, ctx); 10908c2ecf20Sopenharmony_ci if (ret) { 10918c2ecf20Sopenharmony_ci IWL_ERR(priv, "Error setting RXON_ASSOC (%d)\n", ret); 10928c2ecf20Sopenharmony_ci return ret; 10938c2ecf20Sopenharmony_ci } 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci memcpy(active, &ctx->staging, sizeof(*active)); 10968c2ecf20Sopenharmony_ci /* 10978c2ecf20Sopenharmony_ci * We do not commit tx power settings while channel changing, 10988c2ecf20Sopenharmony_ci * do it now if after settings changed. 10998c2ecf20Sopenharmony_ci */ 11008c2ecf20Sopenharmony_ci iwl_set_tx_power(priv, priv->tx_power_next, false); 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci /* make sure we are in the right PS state */ 11038c2ecf20Sopenharmony_ci iwl_power_update_mode(priv, true); 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci return 0; 11068c2ecf20Sopenharmony_ci } 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci iwl_set_rxon_hwcrypto(priv, ctx, !iwlwifi_mod_params.swcrypto); 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci IWL_DEBUG_INFO(priv, 11118c2ecf20Sopenharmony_ci "Going to commit RXON\n" 11128c2ecf20Sopenharmony_ci " * with%s RXON_FILTER_ASSOC_MSK\n" 11138c2ecf20Sopenharmony_ci " * channel = %d\n" 11148c2ecf20Sopenharmony_ci " * bssid = %pM\n", 11158c2ecf20Sopenharmony_ci (new_assoc ? "" : "out"), 11168c2ecf20Sopenharmony_ci le16_to_cpu(ctx->staging.channel), 11178c2ecf20Sopenharmony_ci ctx->staging.bssid_addr); 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci /* 11208c2ecf20Sopenharmony_ci * Always clear associated first, but with the correct config. 11218c2ecf20Sopenharmony_ci * This is required as for example station addition for the 11228c2ecf20Sopenharmony_ci * AP station must be done after the BSSID is set to correctly 11238c2ecf20Sopenharmony_ci * set up filters in the device. 11248c2ecf20Sopenharmony_ci */ 11258c2ecf20Sopenharmony_ci ret = iwlagn_rxon_disconn(priv, ctx); 11268c2ecf20Sopenharmony_ci if (ret) 11278c2ecf20Sopenharmony_ci return ret; 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci ret = iwlagn_set_pan_params(priv); 11308c2ecf20Sopenharmony_ci if (ret) 11318c2ecf20Sopenharmony_ci return ret; 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci if (new_assoc) 11348c2ecf20Sopenharmony_ci return iwlagn_rxon_connect(priv, ctx); 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci return 0; 11378c2ecf20Sopenharmony_ci} 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_civoid iwlagn_config_ht40(struct ieee80211_conf *conf, 11408c2ecf20Sopenharmony_ci struct iwl_rxon_context *ctx) 11418c2ecf20Sopenharmony_ci{ 11428c2ecf20Sopenharmony_ci if (conf_is_ht40_minus(conf)) { 11438c2ecf20Sopenharmony_ci ctx->ht.extension_chan_offset = 11448c2ecf20Sopenharmony_ci IEEE80211_HT_PARAM_CHA_SEC_BELOW; 11458c2ecf20Sopenharmony_ci ctx->ht.is_40mhz = true; 11468c2ecf20Sopenharmony_ci } else if (conf_is_ht40_plus(conf)) { 11478c2ecf20Sopenharmony_ci ctx->ht.extension_chan_offset = 11488c2ecf20Sopenharmony_ci IEEE80211_HT_PARAM_CHA_SEC_ABOVE; 11498c2ecf20Sopenharmony_ci ctx->ht.is_40mhz = true; 11508c2ecf20Sopenharmony_ci } else { 11518c2ecf20Sopenharmony_ci ctx->ht.extension_chan_offset = 11528c2ecf20Sopenharmony_ci IEEE80211_HT_PARAM_CHA_SEC_NONE; 11538c2ecf20Sopenharmony_ci ctx->ht.is_40mhz = false; 11548c2ecf20Sopenharmony_ci } 11558c2ecf20Sopenharmony_ci} 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ciint iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) 11588c2ecf20Sopenharmony_ci{ 11598c2ecf20Sopenharmony_ci struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); 11608c2ecf20Sopenharmony_ci struct iwl_rxon_context *ctx; 11618c2ecf20Sopenharmony_ci struct ieee80211_conf *conf = &hw->conf; 11628c2ecf20Sopenharmony_ci struct ieee80211_channel *channel = conf->chandef.chan; 11638c2ecf20Sopenharmony_ci int ret = 0; 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci IWL_DEBUG_MAC80211(priv, "enter: changed %#x\n", changed); 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci mutex_lock(&priv->mutex); 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) { 11708c2ecf20Sopenharmony_ci IWL_DEBUG_MAC80211(priv, "leave - scanning\n"); 11718c2ecf20Sopenharmony_ci goto out; 11728c2ecf20Sopenharmony_ci } 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci if (!iwl_is_ready(priv)) { 11758c2ecf20Sopenharmony_ci IWL_DEBUG_MAC80211(priv, "leave - not ready\n"); 11768c2ecf20Sopenharmony_ci goto out; 11778c2ecf20Sopenharmony_ci } 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci if (changed & (IEEE80211_CONF_CHANGE_SMPS | 11808c2ecf20Sopenharmony_ci IEEE80211_CONF_CHANGE_CHANNEL)) { 11818c2ecf20Sopenharmony_ci /* mac80211 uses static for non-HT which is what we want */ 11828c2ecf20Sopenharmony_ci priv->current_ht_config.smps = conf->smps_mode; 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci /* 11858c2ecf20Sopenharmony_ci * Recalculate chain counts. 11868c2ecf20Sopenharmony_ci * 11878c2ecf20Sopenharmony_ci * If monitor mode is enabled then mac80211 will 11888c2ecf20Sopenharmony_ci * set up the SM PS mode to OFF if an HT channel is 11898c2ecf20Sopenharmony_ci * configured. 11908c2ecf20Sopenharmony_ci */ 11918c2ecf20Sopenharmony_ci for_each_context(priv, ctx) 11928c2ecf20Sopenharmony_ci iwlagn_set_rxon_chain(priv, ctx); 11938c2ecf20Sopenharmony_ci } 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { 11968c2ecf20Sopenharmony_ci for_each_context(priv, ctx) { 11978c2ecf20Sopenharmony_ci /* Configure HT40 channels */ 11988c2ecf20Sopenharmony_ci if (ctx->ht.enabled != conf_is_ht(conf)) 11998c2ecf20Sopenharmony_ci ctx->ht.enabled = conf_is_ht(conf); 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci if (ctx->ht.enabled) { 12028c2ecf20Sopenharmony_ci /* if HT40 is used, it should not change 12038c2ecf20Sopenharmony_ci * after associated except channel switch */ 12048c2ecf20Sopenharmony_ci if (!ctx->ht.is_40mhz || 12058c2ecf20Sopenharmony_ci !iwl_is_associated_ctx(ctx)) 12068c2ecf20Sopenharmony_ci iwlagn_config_ht40(conf, ctx); 12078c2ecf20Sopenharmony_ci } else 12088c2ecf20Sopenharmony_ci ctx->ht.is_40mhz = false; 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci /* 12118c2ecf20Sopenharmony_ci * Default to no protection. Protection mode will 12128c2ecf20Sopenharmony_ci * later be set from BSS config in iwl_ht_conf 12138c2ecf20Sopenharmony_ci */ 12148c2ecf20Sopenharmony_ci ctx->ht.protection = IEEE80211_HT_OP_MODE_PROTECTION_NONE; 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci /* if we are switching from ht to 2.4 clear flags 12178c2ecf20Sopenharmony_ci * from any ht related info since 2.4 does not 12188c2ecf20Sopenharmony_ci * support ht */ 12198c2ecf20Sopenharmony_ci if (le16_to_cpu(ctx->staging.channel) != 12208c2ecf20Sopenharmony_ci channel->hw_value) 12218c2ecf20Sopenharmony_ci ctx->staging.flags = 0; 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci iwl_set_rxon_channel(priv, channel, ctx); 12248c2ecf20Sopenharmony_ci iwl_set_rxon_ht(priv, &priv->current_ht_config); 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci iwl_set_flags_for_band(priv, ctx, channel->band, 12278c2ecf20Sopenharmony_ci ctx->vif); 12288c2ecf20Sopenharmony_ci } 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci iwl_update_bcast_stations(priv); 12318c2ecf20Sopenharmony_ci } 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci if (changed & (IEEE80211_CONF_CHANGE_PS | 12348c2ecf20Sopenharmony_ci IEEE80211_CONF_CHANGE_IDLE)) { 12358c2ecf20Sopenharmony_ci ret = iwl_power_update_mode(priv, false); 12368c2ecf20Sopenharmony_ci if (ret) 12378c2ecf20Sopenharmony_ci IWL_DEBUG_MAC80211(priv, "Error setting sleep level\n"); 12388c2ecf20Sopenharmony_ci } 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci if (changed & IEEE80211_CONF_CHANGE_POWER) { 12418c2ecf20Sopenharmony_ci IWL_DEBUG_MAC80211(priv, "TX Power old=%d new=%d\n", 12428c2ecf20Sopenharmony_ci priv->tx_power_user_lmt, conf->power_level); 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci iwl_set_tx_power(priv, conf->power_level, false); 12458c2ecf20Sopenharmony_ci } 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci for_each_context(priv, ctx) { 12488c2ecf20Sopenharmony_ci if (!memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging))) 12498c2ecf20Sopenharmony_ci continue; 12508c2ecf20Sopenharmony_ci iwlagn_commit_rxon(priv, ctx); 12518c2ecf20Sopenharmony_ci } 12528c2ecf20Sopenharmony_ci out: 12538c2ecf20Sopenharmony_ci mutex_unlock(&priv->mutex); 12548c2ecf20Sopenharmony_ci IWL_DEBUG_MAC80211(priv, "leave\n"); 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci return ret; 12578c2ecf20Sopenharmony_ci} 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_cistatic void iwlagn_check_needed_chains(struct iwl_priv *priv, 12608c2ecf20Sopenharmony_ci struct iwl_rxon_context *ctx, 12618c2ecf20Sopenharmony_ci struct ieee80211_bss_conf *bss_conf) 12628c2ecf20Sopenharmony_ci{ 12638c2ecf20Sopenharmony_ci struct ieee80211_vif *vif = ctx->vif; 12648c2ecf20Sopenharmony_ci struct iwl_rxon_context *tmp; 12658c2ecf20Sopenharmony_ci struct ieee80211_sta *sta; 12668c2ecf20Sopenharmony_ci struct iwl_ht_config *ht_conf = &priv->current_ht_config; 12678c2ecf20Sopenharmony_ci struct ieee80211_sta_ht_cap *ht_cap; 12688c2ecf20Sopenharmony_ci bool need_multiple; 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci lockdep_assert_held(&priv->mutex); 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci switch (vif->type) { 12738c2ecf20Sopenharmony_ci case NL80211_IFTYPE_STATION: 12748c2ecf20Sopenharmony_ci rcu_read_lock(); 12758c2ecf20Sopenharmony_ci sta = ieee80211_find_sta(vif, bss_conf->bssid); 12768c2ecf20Sopenharmony_ci if (!sta) { 12778c2ecf20Sopenharmony_ci /* 12788c2ecf20Sopenharmony_ci * If at all, this can only happen through a race 12798c2ecf20Sopenharmony_ci * when the AP disconnects us while we're still 12808c2ecf20Sopenharmony_ci * setting up the connection, in that case mac80211 12818c2ecf20Sopenharmony_ci * will soon tell us about that. 12828c2ecf20Sopenharmony_ci */ 12838c2ecf20Sopenharmony_ci need_multiple = false; 12848c2ecf20Sopenharmony_ci rcu_read_unlock(); 12858c2ecf20Sopenharmony_ci break; 12868c2ecf20Sopenharmony_ci } 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci ht_cap = &sta->ht_cap; 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci need_multiple = true; 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci /* 12938c2ecf20Sopenharmony_ci * If the peer advertises no support for receiving 2 and 3 12948c2ecf20Sopenharmony_ci * stream MCS rates, it can't be transmitting them either. 12958c2ecf20Sopenharmony_ci */ 12968c2ecf20Sopenharmony_ci if (ht_cap->mcs.rx_mask[1] == 0 && 12978c2ecf20Sopenharmony_ci ht_cap->mcs.rx_mask[2] == 0) { 12988c2ecf20Sopenharmony_ci need_multiple = false; 12998c2ecf20Sopenharmony_ci } else if (!(ht_cap->mcs.tx_params & 13008c2ecf20Sopenharmony_ci IEEE80211_HT_MCS_TX_DEFINED)) { 13018c2ecf20Sopenharmony_ci /* If it can't TX MCS at all ... */ 13028c2ecf20Sopenharmony_ci need_multiple = false; 13038c2ecf20Sopenharmony_ci } else if (ht_cap->mcs.tx_params & 13048c2ecf20Sopenharmony_ci IEEE80211_HT_MCS_TX_RX_DIFF) { 13058c2ecf20Sopenharmony_ci int maxstreams; 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci /* 13088c2ecf20Sopenharmony_ci * But if it can receive them, it might still not 13098c2ecf20Sopenharmony_ci * be able to transmit them, which is what we need 13108c2ecf20Sopenharmony_ci * to check here -- so check the number of streams 13118c2ecf20Sopenharmony_ci * it advertises for TX (if different from RX). 13128c2ecf20Sopenharmony_ci */ 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci maxstreams = (ht_cap->mcs.tx_params & 13158c2ecf20Sopenharmony_ci IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK); 13168c2ecf20Sopenharmony_ci maxstreams >>= 13178c2ecf20Sopenharmony_ci IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; 13188c2ecf20Sopenharmony_ci maxstreams += 1; 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci if (maxstreams <= 1) 13218c2ecf20Sopenharmony_ci need_multiple = false; 13228c2ecf20Sopenharmony_ci } 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci rcu_read_unlock(); 13258c2ecf20Sopenharmony_ci break; 13268c2ecf20Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 13278c2ecf20Sopenharmony_ci /* currently */ 13288c2ecf20Sopenharmony_ci need_multiple = false; 13298c2ecf20Sopenharmony_ci break; 13308c2ecf20Sopenharmony_ci default: 13318c2ecf20Sopenharmony_ci /* only AP really */ 13328c2ecf20Sopenharmony_ci need_multiple = true; 13338c2ecf20Sopenharmony_ci break; 13348c2ecf20Sopenharmony_ci } 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci ctx->ht_need_multiple_chains = need_multiple; 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci if (!need_multiple) { 13398c2ecf20Sopenharmony_ci /* check all contexts */ 13408c2ecf20Sopenharmony_ci for_each_context(priv, tmp) { 13418c2ecf20Sopenharmony_ci if (!tmp->vif) 13428c2ecf20Sopenharmony_ci continue; 13438c2ecf20Sopenharmony_ci if (tmp->ht_need_multiple_chains) { 13448c2ecf20Sopenharmony_ci need_multiple = true; 13458c2ecf20Sopenharmony_ci break; 13468c2ecf20Sopenharmony_ci } 13478c2ecf20Sopenharmony_ci } 13488c2ecf20Sopenharmony_ci } 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci ht_conf->single_chain_sufficient = !need_multiple; 13518c2ecf20Sopenharmony_ci} 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_cistatic void iwlagn_chain_noise_reset(struct iwl_priv *priv) 13548c2ecf20Sopenharmony_ci{ 13558c2ecf20Sopenharmony_ci struct iwl_chain_noise_data *data = &priv->chain_noise_data; 13568c2ecf20Sopenharmony_ci int ret; 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci if (priv->calib_disabled & IWL_CHAIN_NOISE_CALIB_DISABLED) 13598c2ecf20Sopenharmony_ci return; 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci if ((data->state == IWL_CHAIN_NOISE_ALIVE) && 13628c2ecf20Sopenharmony_ci iwl_is_any_associated(priv)) { 13638c2ecf20Sopenharmony_ci struct iwl_calib_chain_noise_reset_cmd cmd; 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci /* clear data for chain noise calibration algorithm */ 13668c2ecf20Sopenharmony_ci data->chain_noise_a = 0; 13678c2ecf20Sopenharmony_ci data->chain_noise_b = 0; 13688c2ecf20Sopenharmony_ci data->chain_noise_c = 0; 13698c2ecf20Sopenharmony_ci data->chain_signal_a = 0; 13708c2ecf20Sopenharmony_ci data->chain_signal_b = 0; 13718c2ecf20Sopenharmony_ci data->chain_signal_c = 0; 13728c2ecf20Sopenharmony_ci data->beacon_count = 0; 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 13758c2ecf20Sopenharmony_ci iwl_set_calib_hdr(&cmd.hdr, 13768c2ecf20Sopenharmony_ci priv->phy_calib_chain_noise_reset_cmd); 13778c2ecf20Sopenharmony_ci ret = iwl_dvm_send_cmd_pdu(priv, 13788c2ecf20Sopenharmony_ci REPLY_PHY_CALIBRATION_CMD, 13798c2ecf20Sopenharmony_ci 0, sizeof(cmd), &cmd); 13808c2ecf20Sopenharmony_ci if (ret) 13818c2ecf20Sopenharmony_ci IWL_ERR(priv, 13828c2ecf20Sopenharmony_ci "Could not send REPLY_PHY_CALIBRATION_CMD\n"); 13838c2ecf20Sopenharmony_ci data->state = IWL_CHAIN_NOISE_ACCUMULATE; 13848c2ecf20Sopenharmony_ci IWL_DEBUG_CALIB(priv, "Run chain_noise_calibrate\n"); 13858c2ecf20Sopenharmony_ci } 13868c2ecf20Sopenharmony_ci} 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_civoid iwlagn_bss_info_changed(struct ieee80211_hw *hw, 13898c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 13908c2ecf20Sopenharmony_ci struct ieee80211_bss_conf *bss_conf, 13918c2ecf20Sopenharmony_ci u32 changes) 13928c2ecf20Sopenharmony_ci{ 13938c2ecf20Sopenharmony_ci struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); 13948c2ecf20Sopenharmony_ci struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); 13958c2ecf20Sopenharmony_ci int ret; 13968c2ecf20Sopenharmony_ci bool force = false; 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci mutex_lock(&priv->mutex); 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci if (changes & BSS_CHANGED_IDLE && bss_conf->idle) { 14018c2ecf20Sopenharmony_ci /* 14028c2ecf20Sopenharmony_ci * If we go idle, then clearly no "passive-no-rx" 14038c2ecf20Sopenharmony_ci * workaround is needed any more, this is a reset. 14048c2ecf20Sopenharmony_ci */ 14058c2ecf20Sopenharmony_ci iwlagn_lift_passive_no_rx(priv); 14068c2ecf20Sopenharmony_ci } 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci if (unlikely(!iwl_is_ready(priv))) { 14098c2ecf20Sopenharmony_ci IWL_DEBUG_MAC80211(priv, "leave - not ready\n"); 14108c2ecf20Sopenharmony_ci mutex_unlock(&priv->mutex); 14118c2ecf20Sopenharmony_ci return; 14128c2ecf20Sopenharmony_ci } 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci if (unlikely(!ctx->vif)) { 14158c2ecf20Sopenharmony_ci IWL_DEBUG_MAC80211(priv, "leave - vif is NULL\n"); 14168c2ecf20Sopenharmony_ci mutex_unlock(&priv->mutex); 14178c2ecf20Sopenharmony_ci return; 14188c2ecf20Sopenharmony_ci } 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci if (changes & BSS_CHANGED_BEACON_INT) 14218c2ecf20Sopenharmony_ci force = true; 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci if (changes & BSS_CHANGED_QOS) { 14248c2ecf20Sopenharmony_ci ctx->qos_data.qos_active = bss_conf->qos; 14258c2ecf20Sopenharmony_ci iwlagn_update_qos(priv, ctx); 14268c2ecf20Sopenharmony_ci } 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci ctx->staging.assoc_id = cpu_to_le16(vif->bss_conf.aid); 14298c2ecf20Sopenharmony_ci if (vif->bss_conf.use_short_preamble) 14308c2ecf20Sopenharmony_ci ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; 14318c2ecf20Sopenharmony_ci else 14328c2ecf20Sopenharmony_ci ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci if (changes & BSS_CHANGED_ASSOC) { 14358c2ecf20Sopenharmony_ci if (bss_conf->assoc) { 14368c2ecf20Sopenharmony_ci priv->timestamp = bss_conf->sync_tsf; 14378c2ecf20Sopenharmony_ci ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK; 14388c2ecf20Sopenharmony_ci } else { 14398c2ecf20Sopenharmony_ci ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci if (ctx->ctxid == IWL_RXON_CTX_BSS) 14428c2ecf20Sopenharmony_ci priv->have_rekey_data = false; 14438c2ecf20Sopenharmony_ci } 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ci iwlagn_bt_coex_rssi_monitor(priv); 14468c2ecf20Sopenharmony_ci } 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci if (ctx->ht.enabled) { 14498c2ecf20Sopenharmony_ci ctx->ht.protection = bss_conf->ht_operation_mode & 14508c2ecf20Sopenharmony_ci IEEE80211_HT_OP_MODE_PROTECTION; 14518c2ecf20Sopenharmony_ci ctx->ht.non_gf_sta_present = !!(bss_conf->ht_operation_mode & 14528c2ecf20Sopenharmony_ci IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); 14538c2ecf20Sopenharmony_ci iwlagn_check_needed_chains(priv, ctx, bss_conf); 14548c2ecf20Sopenharmony_ci iwl_set_rxon_ht(priv, &priv->current_ht_config); 14558c2ecf20Sopenharmony_ci } 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci iwlagn_set_rxon_chain(priv, ctx); 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci if (bss_conf->use_cts_prot && (priv->band != NL80211_BAND_5GHZ)) 14608c2ecf20Sopenharmony_ci ctx->staging.flags |= RXON_FLG_TGG_PROTECT_MSK; 14618c2ecf20Sopenharmony_ci else 14628c2ecf20Sopenharmony_ci ctx->staging.flags &= ~RXON_FLG_TGG_PROTECT_MSK; 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci if (bss_conf->use_cts_prot) 14658c2ecf20Sopenharmony_ci ctx->staging.flags |= RXON_FLG_SELF_CTS_EN; 14668c2ecf20Sopenharmony_ci else 14678c2ecf20Sopenharmony_ci ctx->staging.flags &= ~RXON_FLG_SELF_CTS_EN; 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci memcpy(ctx->staging.bssid_addr, bss_conf->bssid, ETH_ALEN); 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci if (vif->type == NL80211_IFTYPE_AP || 14728c2ecf20Sopenharmony_ci vif->type == NL80211_IFTYPE_ADHOC) { 14738c2ecf20Sopenharmony_ci if (vif->bss_conf.enable_beacon) { 14748c2ecf20Sopenharmony_ci ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK; 14758c2ecf20Sopenharmony_ci priv->beacon_ctx = ctx; 14768c2ecf20Sopenharmony_ci } else { 14778c2ecf20Sopenharmony_ci ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; 14788c2ecf20Sopenharmony_ci priv->beacon_ctx = NULL; 14798c2ecf20Sopenharmony_ci } 14808c2ecf20Sopenharmony_ci } 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci /* 14838c2ecf20Sopenharmony_ci * If the ucode decides to do beacon filtering before 14848c2ecf20Sopenharmony_ci * association, it will lose beacons that are needed 14858c2ecf20Sopenharmony_ci * before sending frames out on passive channels. This 14868c2ecf20Sopenharmony_ci * causes association failures on those channels. Enable 14878c2ecf20Sopenharmony_ci * receiving beacons in such cases. 14888c2ecf20Sopenharmony_ci */ 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci if (vif->type == NL80211_IFTYPE_STATION) { 14918c2ecf20Sopenharmony_ci if (!bss_conf->assoc) 14928c2ecf20Sopenharmony_ci ctx->staging.filter_flags |= RXON_FILTER_BCON_AWARE_MSK; 14938c2ecf20Sopenharmony_ci else 14948c2ecf20Sopenharmony_ci ctx->staging.filter_flags &= 14958c2ecf20Sopenharmony_ci ~RXON_FILTER_BCON_AWARE_MSK; 14968c2ecf20Sopenharmony_ci } 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci if (force || memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging))) 14998c2ecf20Sopenharmony_ci iwlagn_commit_rxon(priv, ctx); 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci if (changes & BSS_CHANGED_ASSOC && bss_conf->assoc) { 15028c2ecf20Sopenharmony_ci /* 15038c2ecf20Sopenharmony_ci * The chain noise calibration will enable PM upon 15048c2ecf20Sopenharmony_ci * completion. If calibration has already been run 15058c2ecf20Sopenharmony_ci * then we need to enable power management here. 15068c2ecf20Sopenharmony_ci */ 15078c2ecf20Sopenharmony_ci if (priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE) 15088c2ecf20Sopenharmony_ci iwl_power_update_mode(priv, false); 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ci /* Enable RX differential gain and sensitivity calibrations */ 15118c2ecf20Sopenharmony_ci iwlagn_chain_noise_reset(priv); 15128c2ecf20Sopenharmony_ci priv->start_calib = 1; 15138c2ecf20Sopenharmony_ci } 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci if (changes & BSS_CHANGED_IBSS) { 15168c2ecf20Sopenharmony_ci ret = iwlagn_manage_ibss_station(priv, vif, 15178c2ecf20Sopenharmony_ci bss_conf->ibss_joined); 15188c2ecf20Sopenharmony_ci if (ret) 15198c2ecf20Sopenharmony_ci IWL_ERR(priv, "failed to %s IBSS station %pM\n", 15208c2ecf20Sopenharmony_ci bss_conf->ibss_joined ? "add" : "remove", 15218c2ecf20Sopenharmony_ci bss_conf->bssid); 15228c2ecf20Sopenharmony_ci } 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ci if (changes & BSS_CHANGED_BEACON && priv->beacon_ctx == ctx) { 15258c2ecf20Sopenharmony_ci if (iwlagn_update_beacon(priv, vif)) 15268c2ecf20Sopenharmony_ci IWL_ERR(priv, "Error updating beacon\n"); 15278c2ecf20Sopenharmony_ci } 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci mutex_unlock(&priv->mutex); 15308c2ecf20Sopenharmony_ci} 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_civoid iwlagn_post_scan(struct iwl_priv *priv) 15338c2ecf20Sopenharmony_ci{ 15348c2ecf20Sopenharmony_ci struct iwl_rxon_context *ctx; 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci /* 15378c2ecf20Sopenharmony_ci * We do not commit power settings while scan is pending, 15388c2ecf20Sopenharmony_ci * do it now if the settings changed. 15398c2ecf20Sopenharmony_ci */ 15408c2ecf20Sopenharmony_ci iwl_power_set_mode(priv, &priv->power_data.sleep_cmd_next, false); 15418c2ecf20Sopenharmony_ci iwl_set_tx_power(priv, priv->tx_power_next, false); 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci /* 15448c2ecf20Sopenharmony_ci * Since setting the RXON may have been deferred while 15458c2ecf20Sopenharmony_ci * performing the scan, fire one off if needed 15468c2ecf20Sopenharmony_ci */ 15478c2ecf20Sopenharmony_ci for_each_context(priv, ctx) 15488c2ecf20Sopenharmony_ci if (memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging))) 15498c2ecf20Sopenharmony_ci iwlagn_commit_rxon(priv, ctx); 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_ci iwlagn_set_pan_params(priv); 15528c2ecf20Sopenharmony_ci} 1553