18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/****************************************************************************** 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright(c) 2003 - 2014, 2018 - 2020 Intel Corporation. All rights reserved. 58c2ecf20Sopenharmony_ci * Copyright(c) 2015 Intel Deutschland GmbH 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Portions of this file are derived from the ipw3945 project, as well 88c2ecf20Sopenharmony_ci * as portions of the ieee80211 subsystem header files. 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Contact Information: 118c2ecf20Sopenharmony_ci * Intel Linux Wireless <linuxwifi@intel.com> 128c2ecf20Sopenharmony_ci * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci *****************************************************************************/ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <linux/kernel.h> 198c2ecf20Sopenharmony_ci#include <linux/module.h> 208c2ecf20Sopenharmony_ci#include <linux/init.h> 218c2ecf20Sopenharmony_ci#include <linux/slab.h> 228c2ecf20Sopenharmony_ci#include <linux/delay.h> 238c2ecf20Sopenharmony_ci#include <linux/sched.h> 248c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 258c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 268c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 278c2ecf20Sopenharmony_ci#include <linux/if_arp.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#include <net/mac80211.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include <asm/div64.h> 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include "iwl-eeprom-read.h" 348c2ecf20Sopenharmony_ci#include "iwl-eeprom-parse.h" 358c2ecf20Sopenharmony_ci#include "iwl-io.h" 368c2ecf20Sopenharmony_ci#include "iwl-trans.h" 378c2ecf20Sopenharmony_ci#include "iwl-op-mode.h" 388c2ecf20Sopenharmony_ci#include "iwl-drv.h" 398c2ecf20Sopenharmony_ci#include "iwl-modparams.h" 408c2ecf20Sopenharmony_ci#include "iwl-prph.h" 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#include "dev.h" 438c2ecf20Sopenharmony_ci#include "calib.h" 448c2ecf20Sopenharmony_ci#include "agn.h" 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/****************************************************************************** 488c2ecf20Sopenharmony_ci * 498c2ecf20Sopenharmony_ci * module boiler plate 508c2ecf20Sopenharmony_ci * 518c2ecf20Sopenharmony_ci ******************************************************************************/ 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#define DRV_DESCRIPTION "Intel(R) Wireless WiFi Link AGN driver for Linux" 548c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRV_DESCRIPTION); 558c2ecf20Sopenharmony_ciMODULE_AUTHOR(DRV_AUTHOR); 568c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/* Please keep this array *SORTED* by hex value. 598c2ecf20Sopenharmony_ci * Access is done through binary search. 608c2ecf20Sopenharmony_ci * A warning will be triggered on violation. 618c2ecf20Sopenharmony_ci */ 628c2ecf20Sopenharmony_cistatic const struct iwl_hcmd_names iwl_dvm_cmd_names[] = { 638c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_ALIVE), 648c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_ERROR), 658c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_ECHO), 668c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_RXON), 678c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_RXON_ASSOC), 688c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_QOS_PARAM), 698c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_RXON_TIMING), 708c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_ADD_STA), 718c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_REMOVE_STA), 728c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_REMOVE_ALL_STA), 738c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_TX), 748c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_TXFIFO_FLUSH), 758c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_WEPKEY), 768c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_LEDS_CMD), 778c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_TX_LINK_QUALITY_CMD), 788c2ecf20Sopenharmony_ci HCMD_NAME(COEX_PRIORITY_TABLE_CMD), 798c2ecf20Sopenharmony_ci HCMD_NAME(COEX_MEDIUM_NOTIFICATION), 808c2ecf20Sopenharmony_ci HCMD_NAME(COEX_EVENT_CMD), 818c2ecf20Sopenharmony_ci HCMD_NAME(TEMPERATURE_NOTIFICATION), 828c2ecf20Sopenharmony_ci HCMD_NAME(CALIBRATION_CFG_CMD), 838c2ecf20Sopenharmony_ci HCMD_NAME(CALIBRATION_RES_NOTIFICATION), 848c2ecf20Sopenharmony_ci HCMD_NAME(CALIBRATION_COMPLETE_NOTIFICATION), 858c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_QUIET_CMD), 868c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_CHANNEL_SWITCH), 878c2ecf20Sopenharmony_ci HCMD_NAME(CHANNEL_SWITCH_NOTIFICATION), 888c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_SPECTRUM_MEASUREMENT_CMD), 898c2ecf20Sopenharmony_ci HCMD_NAME(SPECTRUM_MEASURE_NOTIFICATION), 908c2ecf20Sopenharmony_ci HCMD_NAME(POWER_TABLE_CMD), 918c2ecf20Sopenharmony_ci HCMD_NAME(PM_SLEEP_NOTIFICATION), 928c2ecf20Sopenharmony_ci HCMD_NAME(PM_DEBUG_STATISTIC_NOTIFIC), 938c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_SCAN_CMD), 948c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_SCAN_ABORT_CMD), 958c2ecf20Sopenharmony_ci HCMD_NAME(SCAN_START_NOTIFICATION), 968c2ecf20Sopenharmony_ci HCMD_NAME(SCAN_RESULTS_NOTIFICATION), 978c2ecf20Sopenharmony_ci HCMD_NAME(SCAN_COMPLETE_NOTIFICATION), 988c2ecf20Sopenharmony_ci HCMD_NAME(BEACON_NOTIFICATION), 998c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_TX_BEACON), 1008c2ecf20Sopenharmony_ci HCMD_NAME(WHO_IS_AWAKE_NOTIFICATION), 1018c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_TX_POWER_DBM_CMD), 1028c2ecf20Sopenharmony_ci HCMD_NAME(QUIET_NOTIFICATION), 1038c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_TX_PWR_TABLE_CMD), 1048c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_TX_POWER_DBM_CMD_V1), 1058c2ecf20Sopenharmony_ci HCMD_NAME(TX_ANT_CONFIGURATION_CMD), 1068c2ecf20Sopenharmony_ci HCMD_NAME(MEASURE_ABORT_NOTIFICATION), 1078c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_BT_CONFIG), 1088c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_STATISTICS_CMD), 1098c2ecf20Sopenharmony_ci HCMD_NAME(STATISTICS_NOTIFICATION), 1108c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_CARD_STATE_CMD), 1118c2ecf20Sopenharmony_ci HCMD_NAME(CARD_STATE_NOTIFICATION), 1128c2ecf20Sopenharmony_ci HCMD_NAME(MISSED_BEACONS_NOTIFICATION), 1138c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_CT_KILL_CONFIG_CMD), 1148c2ecf20Sopenharmony_ci HCMD_NAME(SENSITIVITY_CMD), 1158c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_PHY_CALIBRATION_CMD), 1168c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_WIPAN_PARAMS), 1178c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_WIPAN_RXON), 1188c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_WIPAN_RXON_TIMING), 1198c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_WIPAN_RXON_ASSOC), 1208c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_WIPAN_QOS_PARAM), 1218c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_WIPAN_WEPKEY), 1228c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_WIPAN_P2P_CHANNEL_SWITCH), 1238c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_WIPAN_NOA_NOTIFICATION), 1248c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_WIPAN_DEACTIVATION_COMPLETE), 1258c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_RX_PHY_CMD), 1268c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_RX_MPDU_CMD), 1278c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_RX), 1288c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_COMPRESSED_BA), 1298c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_BT_COEX_PRIO_TABLE), 1308c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_BT_COEX_PROT_ENV), 1318c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_BT_COEX_PROFILE_NOTIF), 1328c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_D3_CONFIG), 1338c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_WOWLAN_PATTERNS), 1348c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_WOWLAN_WAKEUP_FILTER), 1358c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_WOWLAN_TSC_RSC_PARAMS), 1368c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_WOWLAN_TKIP_PARAMS), 1378c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_WOWLAN_KEK_KCK_MATERIAL), 1388c2ecf20Sopenharmony_ci HCMD_NAME(REPLY_WOWLAN_GET_STATUS), 1398c2ecf20Sopenharmony_ci}; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic const struct iwl_hcmd_arr iwl_dvm_groups[] = { 1428c2ecf20Sopenharmony_ci [0x0] = HCMD_ARR(iwl_dvm_cmd_names), 1438c2ecf20Sopenharmony_ci}; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic const struct iwl_op_mode_ops iwl_dvm_ops; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_civoid iwl_update_chain_flags(struct iwl_priv *priv) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci struct iwl_rxon_context *ctx; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci for_each_context(priv, ctx) { 1528c2ecf20Sopenharmony_ci iwlagn_set_rxon_chain(priv, ctx); 1538c2ecf20Sopenharmony_ci if (ctx->active.rx_chain != ctx->staging.rx_chain) 1548c2ecf20Sopenharmony_ci iwlagn_commit_rxon(priv, ctx); 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci/* Parse the beacon frame to find the TIM element and set tim_idx & tim_size */ 1598c2ecf20Sopenharmony_cistatic void iwl_set_beacon_tim(struct iwl_priv *priv, 1608c2ecf20Sopenharmony_ci struct iwl_tx_beacon_cmd *tx_beacon_cmd, 1618c2ecf20Sopenharmony_ci u8 *beacon, u32 frame_size) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci u16 tim_idx; 1648c2ecf20Sopenharmony_ci struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)beacon; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci /* 1678c2ecf20Sopenharmony_ci * The index is relative to frame start but we start looking at the 1688c2ecf20Sopenharmony_ci * variable-length part of the beacon. 1698c2ecf20Sopenharmony_ci */ 1708c2ecf20Sopenharmony_ci tim_idx = mgmt->u.beacon.variable - beacon; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci /* Parse variable-length elements of beacon to find WLAN_EID_TIM */ 1738c2ecf20Sopenharmony_ci while ((tim_idx < (frame_size - 2)) && 1748c2ecf20Sopenharmony_ci (beacon[tim_idx] != WLAN_EID_TIM)) 1758c2ecf20Sopenharmony_ci tim_idx += beacon[tim_idx+1] + 2; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci /* If TIM field was found, set variables */ 1788c2ecf20Sopenharmony_ci if ((tim_idx < (frame_size - 1)) && (beacon[tim_idx] == WLAN_EID_TIM)) { 1798c2ecf20Sopenharmony_ci tx_beacon_cmd->tim_idx = cpu_to_le16(tim_idx); 1808c2ecf20Sopenharmony_ci tx_beacon_cmd->tim_size = beacon[tim_idx+1]; 1818c2ecf20Sopenharmony_ci } else 1828c2ecf20Sopenharmony_ci IWL_WARN(priv, "Unable to find TIM Element in beacon\n"); 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ciint iwlagn_send_beacon_cmd(struct iwl_priv *priv) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci struct iwl_tx_beacon_cmd *tx_beacon_cmd; 1888c2ecf20Sopenharmony_ci struct iwl_host_cmd cmd = { 1898c2ecf20Sopenharmony_ci .id = REPLY_TX_BEACON, 1908c2ecf20Sopenharmony_ci }; 1918c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info; 1928c2ecf20Sopenharmony_ci u32 frame_size; 1938c2ecf20Sopenharmony_ci u32 rate_flags; 1948c2ecf20Sopenharmony_ci u32 rate; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci /* 1978c2ecf20Sopenharmony_ci * We have to set up the TX command, the TX Beacon command, and the 1988c2ecf20Sopenharmony_ci * beacon contents. 1998c2ecf20Sopenharmony_ci */ 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci lockdep_assert_held(&priv->mutex); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci if (!priv->beacon_ctx) { 2048c2ecf20Sopenharmony_ci IWL_ERR(priv, "trying to build beacon w/o beacon context!\n"); 2058c2ecf20Sopenharmony_ci return 0; 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci if (WARN_ON(!priv->beacon_skb)) 2098c2ecf20Sopenharmony_ci return -EINVAL; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci /* Allocate beacon command */ 2128c2ecf20Sopenharmony_ci if (!priv->beacon_cmd) 2138c2ecf20Sopenharmony_ci priv->beacon_cmd = kzalloc(sizeof(*tx_beacon_cmd), GFP_KERNEL); 2148c2ecf20Sopenharmony_ci tx_beacon_cmd = priv->beacon_cmd; 2158c2ecf20Sopenharmony_ci if (!tx_beacon_cmd) 2168c2ecf20Sopenharmony_ci return -ENOMEM; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci frame_size = priv->beacon_skb->len; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci /* Set up TX command fields */ 2218c2ecf20Sopenharmony_ci tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size); 2228c2ecf20Sopenharmony_ci tx_beacon_cmd->tx.sta_id = priv->beacon_ctx->bcast_sta_id; 2238c2ecf20Sopenharmony_ci tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; 2248c2ecf20Sopenharmony_ci tx_beacon_cmd->tx.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK | 2258c2ecf20Sopenharmony_ci TX_CMD_FLG_TSF_MSK | TX_CMD_FLG_STA_RATE_MSK; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci /* Set up TX beacon command fields */ 2288c2ecf20Sopenharmony_ci iwl_set_beacon_tim(priv, tx_beacon_cmd, priv->beacon_skb->data, 2298c2ecf20Sopenharmony_ci frame_size); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci /* Set up packet rate and flags */ 2328c2ecf20Sopenharmony_ci info = IEEE80211_SKB_CB(priv->beacon_skb); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci /* 2358c2ecf20Sopenharmony_ci * Let's set up the rate at least somewhat correctly; 2368c2ecf20Sopenharmony_ci * it will currently not actually be used by the uCode, 2378c2ecf20Sopenharmony_ci * it uses the broadcast station's rate instead. 2388c2ecf20Sopenharmony_ci */ 2398c2ecf20Sopenharmony_ci if (info->control.rates[0].idx < 0 || 2408c2ecf20Sopenharmony_ci info->control.rates[0].flags & IEEE80211_TX_RC_MCS) 2418c2ecf20Sopenharmony_ci rate = 0; 2428c2ecf20Sopenharmony_ci else 2438c2ecf20Sopenharmony_ci rate = info->control.rates[0].idx; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant, 2468c2ecf20Sopenharmony_ci priv->nvm_data->valid_tx_ant); 2478c2ecf20Sopenharmony_ci rate_flags = iwl_ant_idx_to_flags(priv->mgmt_tx_ant); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci /* In mac80211, rates for 5 GHz start at 0 */ 2508c2ecf20Sopenharmony_ci if (info->band == NL80211_BAND_5GHZ) 2518c2ecf20Sopenharmony_ci rate += IWL_FIRST_OFDM_RATE; 2528c2ecf20Sopenharmony_ci else if (rate >= IWL_FIRST_CCK_RATE && rate <= IWL_LAST_CCK_RATE) 2538c2ecf20Sopenharmony_ci rate_flags |= RATE_MCS_CCK_MSK; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci tx_beacon_cmd->tx.rate_n_flags = 2568c2ecf20Sopenharmony_ci iwl_hw_set_rate_n_flags(rate, rate_flags); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci /* Submit command */ 2598c2ecf20Sopenharmony_ci cmd.len[0] = sizeof(*tx_beacon_cmd); 2608c2ecf20Sopenharmony_ci cmd.data[0] = tx_beacon_cmd; 2618c2ecf20Sopenharmony_ci cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY; 2628c2ecf20Sopenharmony_ci cmd.len[1] = frame_size; 2638c2ecf20Sopenharmony_ci cmd.data[1] = priv->beacon_skb->data; 2648c2ecf20Sopenharmony_ci cmd.dataflags[1] = IWL_HCMD_DFL_NOCOPY; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci return iwl_dvm_send_cmd(priv, &cmd); 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistatic void iwl_bg_beacon_update(struct work_struct *work) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci struct iwl_priv *priv = 2728c2ecf20Sopenharmony_ci container_of(work, struct iwl_priv, beacon_update); 2738c2ecf20Sopenharmony_ci struct sk_buff *beacon; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci mutex_lock(&priv->mutex); 2768c2ecf20Sopenharmony_ci if (!priv->beacon_ctx) { 2778c2ecf20Sopenharmony_ci IWL_ERR(priv, "updating beacon w/o beacon context!\n"); 2788c2ecf20Sopenharmony_ci goto out; 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci if (priv->beacon_ctx->vif->type != NL80211_IFTYPE_AP) { 2828c2ecf20Sopenharmony_ci /* 2838c2ecf20Sopenharmony_ci * The ucode will send beacon notifications even in 2848c2ecf20Sopenharmony_ci * IBSS mode, but we don't want to process them. But 2858c2ecf20Sopenharmony_ci * we need to defer the type check to here due to 2868c2ecf20Sopenharmony_ci * requiring locking around the beacon_ctx access. 2878c2ecf20Sopenharmony_ci */ 2888c2ecf20Sopenharmony_ci goto out; 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci /* Pull updated AP beacon from mac80211. will fail if not in AP mode */ 2928c2ecf20Sopenharmony_ci beacon = ieee80211_beacon_get(priv->hw, priv->beacon_ctx->vif); 2938c2ecf20Sopenharmony_ci if (!beacon) { 2948c2ecf20Sopenharmony_ci IWL_ERR(priv, "update beacon failed -- keeping old\n"); 2958c2ecf20Sopenharmony_ci goto out; 2968c2ecf20Sopenharmony_ci } 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci /* new beacon skb is allocated every time; dispose previous.*/ 2998c2ecf20Sopenharmony_ci dev_kfree_skb(priv->beacon_skb); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci priv->beacon_skb = beacon; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci iwlagn_send_beacon_cmd(priv); 3048c2ecf20Sopenharmony_ci out: 3058c2ecf20Sopenharmony_ci mutex_unlock(&priv->mutex); 3068c2ecf20Sopenharmony_ci} 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_cistatic void iwl_bg_bt_runtime_config(struct work_struct *work) 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci struct iwl_priv *priv = 3118c2ecf20Sopenharmony_ci container_of(work, struct iwl_priv, bt_runtime_config); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci mutex_lock(&priv->mutex); 3148c2ecf20Sopenharmony_ci if (test_bit(STATUS_EXIT_PENDING, &priv->status)) 3158c2ecf20Sopenharmony_ci goto out; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci /* dont send host command if rf-kill is on */ 3188c2ecf20Sopenharmony_ci if (!iwl_is_ready_rf(priv)) 3198c2ecf20Sopenharmony_ci goto out; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci iwlagn_send_advance_bt_config(priv); 3228c2ecf20Sopenharmony_ciout: 3238c2ecf20Sopenharmony_ci mutex_unlock(&priv->mutex); 3248c2ecf20Sopenharmony_ci} 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cistatic void iwl_bg_bt_full_concurrency(struct work_struct *work) 3278c2ecf20Sopenharmony_ci{ 3288c2ecf20Sopenharmony_ci struct iwl_priv *priv = 3298c2ecf20Sopenharmony_ci container_of(work, struct iwl_priv, bt_full_concurrency); 3308c2ecf20Sopenharmony_ci struct iwl_rxon_context *ctx; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci mutex_lock(&priv->mutex); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if (test_bit(STATUS_EXIT_PENDING, &priv->status)) 3358c2ecf20Sopenharmony_ci goto out; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci /* dont send host command if rf-kill is on */ 3388c2ecf20Sopenharmony_ci if (!iwl_is_ready_rf(priv)) 3398c2ecf20Sopenharmony_ci goto out; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci IWL_DEBUG_INFO(priv, "BT coex in %s mode\n", 3428c2ecf20Sopenharmony_ci priv->bt_full_concurrent ? 3438c2ecf20Sopenharmony_ci "full concurrency" : "3-wire"); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci /* 3468c2ecf20Sopenharmony_ci * LQ & RXON updated cmds must be sent before BT Config cmd 3478c2ecf20Sopenharmony_ci * to avoid 3-wire collisions 3488c2ecf20Sopenharmony_ci */ 3498c2ecf20Sopenharmony_ci for_each_context(priv, ctx) { 3508c2ecf20Sopenharmony_ci iwlagn_set_rxon_chain(priv, ctx); 3518c2ecf20Sopenharmony_ci iwlagn_commit_rxon(priv, ctx); 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci iwlagn_send_advance_bt_config(priv); 3558c2ecf20Sopenharmony_ciout: 3568c2ecf20Sopenharmony_ci mutex_unlock(&priv->mutex); 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ciint iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear) 3608c2ecf20Sopenharmony_ci{ 3618c2ecf20Sopenharmony_ci struct iwl_statistics_cmd statistics_cmd = { 3628c2ecf20Sopenharmony_ci .configuration_flags = 3638c2ecf20Sopenharmony_ci clear ? IWL_STATS_CONF_CLEAR_STATS : 0, 3648c2ecf20Sopenharmony_ci }; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci if (flags & CMD_ASYNC) 3678c2ecf20Sopenharmony_ci return iwl_dvm_send_cmd_pdu(priv, REPLY_STATISTICS_CMD, 3688c2ecf20Sopenharmony_ci CMD_ASYNC, 3698c2ecf20Sopenharmony_ci sizeof(struct iwl_statistics_cmd), 3708c2ecf20Sopenharmony_ci &statistics_cmd); 3718c2ecf20Sopenharmony_ci else 3728c2ecf20Sopenharmony_ci return iwl_dvm_send_cmd_pdu(priv, REPLY_STATISTICS_CMD, 0, 3738c2ecf20Sopenharmony_ci sizeof(struct iwl_statistics_cmd), 3748c2ecf20Sopenharmony_ci &statistics_cmd); 3758c2ecf20Sopenharmony_ci} 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci/* 3788c2ecf20Sopenharmony_ci * iwl_bg_statistics_periodic - Timer callback to queue statistics 3798c2ecf20Sopenharmony_ci * 3808c2ecf20Sopenharmony_ci * This callback is provided in order to send a statistics request. 3818c2ecf20Sopenharmony_ci * 3828c2ecf20Sopenharmony_ci * This timer function is continually reset to execute within 3838c2ecf20Sopenharmony_ci * REG_RECALIB_PERIOD seconds since the last STATISTICS_NOTIFICATION 3848c2ecf20Sopenharmony_ci * was received. We need to ensure we receive the statistics in order 3858c2ecf20Sopenharmony_ci * to update the temperature used for calibrating the TXPOWER. 3868c2ecf20Sopenharmony_ci */ 3878c2ecf20Sopenharmony_cistatic void iwl_bg_statistics_periodic(struct timer_list *t) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci struct iwl_priv *priv = from_timer(priv, t, statistics_periodic); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci if (test_bit(STATUS_EXIT_PENDING, &priv->status)) 3928c2ecf20Sopenharmony_ci return; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci /* dont send host command if rf-kill is on */ 3958c2ecf20Sopenharmony_ci if (!iwl_is_ready_rf(priv)) 3968c2ecf20Sopenharmony_ci return; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci iwl_send_statistics_request(priv, CMD_ASYNC, false); 3998c2ecf20Sopenharmony_ci} 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_cistatic void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base, 4038c2ecf20Sopenharmony_ci u32 start_idx, u32 num_events, 4048c2ecf20Sopenharmony_ci u32 capacity, u32 mode) 4058c2ecf20Sopenharmony_ci{ 4068c2ecf20Sopenharmony_ci u32 i; 4078c2ecf20Sopenharmony_ci u32 ptr; /* SRAM byte address of log data */ 4088c2ecf20Sopenharmony_ci u32 ev, time, data; /* event log data */ 4098c2ecf20Sopenharmony_ci unsigned long reg_flags; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci if (mode == 0) 4128c2ecf20Sopenharmony_ci ptr = base + (4 * sizeof(u32)) + (start_idx * 2 * sizeof(u32)); 4138c2ecf20Sopenharmony_ci else 4148c2ecf20Sopenharmony_ci ptr = base + (4 * sizeof(u32)) + (start_idx * 3 * sizeof(u32)); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci /* Make sure device is powered up for SRAM reads */ 4178c2ecf20Sopenharmony_ci if (!iwl_trans_grab_nic_access(priv->trans, ®_flags)) 4188c2ecf20Sopenharmony_ci return; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci /* Set starting address; reads will auto-increment */ 4218c2ecf20Sopenharmony_ci iwl_write32(priv->trans, HBUS_TARG_MEM_RADDR, ptr); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci /* 4248c2ecf20Sopenharmony_ci * Refuse to read more than would have fit into the log from 4258c2ecf20Sopenharmony_ci * the current start_idx. This used to happen due to the race 4268c2ecf20Sopenharmony_ci * described below, but now WARN because the code below should 4278c2ecf20Sopenharmony_ci * prevent it from happening here. 4288c2ecf20Sopenharmony_ci */ 4298c2ecf20Sopenharmony_ci if (WARN_ON(num_events > capacity - start_idx)) 4308c2ecf20Sopenharmony_ci num_events = capacity - start_idx; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci /* 4338c2ecf20Sopenharmony_ci * "time" is actually "data" for mode 0 (no timestamp). 4348c2ecf20Sopenharmony_ci * place event id # at far right for easier visual parsing. 4358c2ecf20Sopenharmony_ci */ 4368c2ecf20Sopenharmony_ci for (i = 0; i < num_events; i++) { 4378c2ecf20Sopenharmony_ci ev = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT); 4388c2ecf20Sopenharmony_ci time = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT); 4398c2ecf20Sopenharmony_ci if (mode == 0) { 4408c2ecf20Sopenharmony_ci trace_iwlwifi_dev_ucode_cont_event( 4418c2ecf20Sopenharmony_ci priv->trans->dev, 0, time, ev); 4428c2ecf20Sopenharmony_ci } else { 4438c2ecf20Sopenharmony_ci data = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT); 4448c2ecf20Sopenharmony_ci trace_iwlwifi_dev_ucode_cont_event( 4458c2ecf20Sopenharmony_ci priv->trans->dev, time, data, ev); 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci } 4488c2ecf20Sopenharmony_ci /* Allow device to power down */ 4498c2ecf20Sopenharmony_ci iwl_trans_release_nic_access(priv->trans, ®_flags); 4508c2ecf20Sopenharmony_ci} 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_cistatic void iwl_continuous_event_trace(struct iwl_priv *priv) 4538c2ecf20Sopenharmony_ci{ 4548c2ecf20Sopenharmony_ci u32 capacity; /* event log capacity in # entries */ 4558c2ecf20Sopenharmony_ci struct { 4568c2ecf20Sopenharmony_ci u32 capacity; 4578c2ecf20Sopenharmony_ci u32 mode; 4588c2ecf20Sopenharmony_ci u32 wrap_counter; 4598c2ecf20Sopenharmony_ci u32 write_counter; 4608c2ecf20Sopenharmony_ci } __packed read; 4618c2ecf20Sopenharmony_ci u32 base; /* SRAM byte address of event log header */ 4628c2ecf20Sopenharmony_ci u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */ 4638c2ecf20Sopenharmony_ci u32 num_wraps; /* # times uCode wrapped to top of log */ 4648c2ecf20Sopenharmony_ci u32 next_entry; /* index of next entry to be written by uCode */ 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci base = priv->device_pointers.log_event_table; 4678c2ecf20Sopenharmony_ci if (iwlagn_hw_valid_rtc_data_addr(base)) { 4688c2ecf20Sopenharmony_ci iwl_trans_read_mem_bytes(priv->trans, base, 4698c2ecf20Sopenharmony_ci &read, sizeof(read)); 4708c2ecf20Sopenharmony_ci capacity = read.capacity; 4718c2ecf20Sopenharmony_ci mode = read.mode; 4728c2ecf20Sopenharmony_ci num_wraps = read.wrap_counter; 4738c2ecf20Sopenharmony_ci next_entry = read.write_counter; 4748c2ecf20Sopenharmony_ci } else 4758c2ecf20Sopenharmony_ci return; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci /* 4788c2ecf20Sopenharmony_ci * Unfortunately, the uCode doesn't use temporary variables. 4798c2ecf20Sopenharmony_ci * Therefore, it can happen that we read next_entry == capacity, 4808c2ecf20Sopenharmony_ci * which really means next_entry == 0. 4818c2ecf20Sopenharmony_ci */ 4828c2ecf20Sopenharmony_ci if (unlikely(next_entry == capacity)) 4838c2ecf20Sopenharmony_ci next_entry = 0; 4848c2ecf20Sopenharmony_ci /* 4858c2ecf20Sopenharmony_ci * Additionally, the uCode increases the write pointer before 4868c2ecf20Sopenharmony_ci * the wraps counter, so if the write pointer is smaller than 4878c2ecf20Sopenharmony_ci * the old write pointer (wrap occurred) but we read that no 4888c2ecf20Sopenharmony_ci * wrap occurred, we actually read between the next_entry and 4898c2ecf20Sopenharmony_ci * num_wraps update (this does happen in practice!!) -- take 4908c2ecf20Sopenharmony_ci * that into account by increasing num_wraps. 4918c2ecf20Sopenharmony_ci */ 4928c2ecf20Sopenharmony_ci if (unlikely(next_entry < priv->event_log.next_entry && 4938c2ecf20Sopenharmony_ci num_wraps == priv->event_log.num_wraps)) 4948c2ecf20Sopenharmony_ci num_wraps++; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci if (num_wraps == priv->event_log.num_wraps) { 4978c2ecf20Sopenharmony_ci iwl_print_cont_event_trace( 4988c2ecf20Sopenharmony_ci priv, base, priv->event_log.next_entry, 4998c2ecf20Sopenharmony_ci next_entry - priv->event_log.next_entry, 5008c2ecf20Sopenharmony_ci capacity, mode); 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci priv->event_log.non_wraps_count++; 5038c2ecf20Sopenharmony_ci } else { 5048c2ecf20Sopenharmony_ci if (num_wraps - priv->event_log.num_wraps > 1) 5058c2ecf20Sopenharmony_ci priv->event_log.wraps_more_count++; 5068c2ecf20Sopenharmony_ci else 5078c2ecf20Sopenharmony_ci priv->event_log.wraps_once_count++; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci trace_iwlwifi_dev_ucode_wrap_event(priv->trans->dev, 5108c2ecf20Sopenharmony_ci num_wraps - priv->event_log.num_wraps, 5118c2ecf20Sopenharmony_ci next_entry, priv->event_log.next_entry); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci if (next_entry < priv->event_log.next_entry) { 5148c2ecf20Sopenharmony_ci iwl_print_cont_event_trace( 5158c2ecf20Sopenharmony_ci priv, base, priv->event_log.next_entry, 5168c2ecf20Sopenharmony_ci capacity - priv->event_log.next_entry, 5178c2ecf20Sopenharmony_ci capacity, mode); 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci iwl_print_cont_event_trace( 5208c2ecf20Sopenharmony_ci priv, base, 0, next_entry, capacity, mode); 5218c2ecf20Sopenharmony_ci } else { 5228c2ecf20Sopenharmony_ci iwl_print_cont_event_trace( 5238c2ecf20Sopenharmony_ci priv, base, next_entry, 5248c2ecf20Sopenharmony_ci capacity - next_entry, 5258c2ecf20Sopenharmony_ci capacity, mode); 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci iwl_print_cont_event_trace( 5288c2ecf20Sopenharmony_ci priv, base, 0, next_entry, capacity, mode); 5298c2ecf20Sopenharmony_ci } 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci priv->event_log.num_wraps = num_wraps; 5338c2ecf20Sopenharmony_ci priv->event_log.next_entry = next_entry; 5348c2ecf20Sopenharmony_ci} 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci/* 5378c2ecf20Sopenharmony_ci * iwl_bg_ucode_trace - Timer callback to log ucode event 5388c2ecf20Sopenharmony_ci * 5398c2ecf20Sopenharmony_ci * The timer is continually set to execute every 5408c2ecf20Sopenharmony_ci * UCODE_TRACE_PERIOD milliseconds after the last timer expired 5418c2ecf20Sopenharmony_ci * this function is to perform continuous uCode event logging operation 5428c2ecf20Sopenharmony_ci * if enabled 5438c2ecf20Sopenharmony_ci */ 5448c2ecf20Sopenharmony_cistatic void iwl_bg_ucode_trace(struct timer_list *t) 5458c2ecf20Sopenharmony_ci{ 5468c2ecf20Sopenharmony_ci struct iwl_priv *priv = from_timer(priv, t, ucode_trace); 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci if (test_bit(STATUS_EXIT_PENDING, &priv->status)) 5498c2ecf20Sopenharmony_ci return; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci if (priv->event_log.ucode_trace) { 5528c2ecf20Sopenharmony_ci iwl_continuous_event_trace(priv); 5538c2ecf20Sopenharmony_ci /* Reschedule the timer to occur in UCODE_TRACE_PERIOD */ 5548c2ecf20Sopenharmony_ci mod_timer(&priv->ucode_trace, 5558c2ecf20Sopenharmony_ci jiffies + msecs_to_jiffies(UCODE_TRACE_PERIOD)); 5568c2ecf20Sopenharmony_ci } 5578c2ecf20Sopenharmony_ci} 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_cistatic void iwl_bg_tx_flush(struct work_struct *work) 5608c2ecf20Sopenharmony_ci{ 5618c2ecf20Sopenharmony_ci struct iwl_priv *priv = 5628c2ecf20Sopenharmony_ci container_of(work, struct iwl_priv, tx_flush); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci if (test_bit(STATUS_EXIT_PENDING, &priv->status)) 5658c2ecf20Sopenharmony_ci return; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci /* do nothing if rf-kill is on */ 5688c2ecf20Sopenharmony_ci if (!iwl_is_ready_rf(priv)) 5698c2ecf20Sopenharmony_ci return; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci IWL_DEBUG_INFO(priv, "device request: flush all tx frames\n"); 5728c2ecf20Sopenharmony_ci iwlagn_dev_txfifo_flush(priv); 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci/* 5768c2ecf20Sopenharmony_ci * queue/FIFO/AC mapping definitions 5778c2ecf20Sopenharmony_ci */ 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_cistatic const u8 iwlagn_bss_ac_to_fifo[] = { 5808c2ecf20Sopenharmony_ci IWL_TX_FIFO_VO, 5818c2ecf20Sopenharmony_ci IWL_TX_FIFO_VI, 5828c2ecf20Sopenharmony_ci IWL_TX_FIFO_BE, 5838c2ecf20Sopenharmony_ci IWL_TX_FIFO_BK, 5848c2ecf20Sopenharmony_ci}; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_cistatic const u8 iwlagn_bss_ac_to_queue[] = { 5878c2ecf20Sopenharmony_ci 0, 1, 2, 3, 5888c2ecf20Sopenharmony_ci}; 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_cistatic const u8 iwlagn_pan_ac_to_fifo[] = { 5918c2ecf20Sopenharmony_ci IWL_TX_FIFO_VO_IPAN, 5928c2ecf20Sopenharmony_ci IWL_TX_FIFO_VI_IPAN, 5938c2ecf20Sopenharmony_ci IWL_TX_FIFO_BE_IPAN, 5948c2ecf20Sopenharmony_ci IWL_TX_FIFO_BK_IPAN, 5958c2ecf20Sopenharmony_ci}; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_cistatic const u8 iwlagn_pan_ac_to_queue[] = { 5988c2ecf20Sopenharmony_ci 7, 6, 5, 4, 5998c2ecf20Sopenharmony_ci}; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_cistatic void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags) 6028c2ecf20Sopenharmony_ci{ 6038c2ecf20Sopenharmony_ci int i; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci /* 6068c2ecf20Sopenharmony_ci * The default context is always valid, 6078c2ecf20Sopenharmony_ci * the PAN context depends on uCode. 6088c2ecf20Sopenharmony_ci */ 6098c2ecf20Sopenharmony_ci priv->valid_contexts = BIT(IWL_RXON_CTX_BSS); 6108c2ecf20Sopenharmony_ci if (ucode_flags & IWL_UCODE_TLV_FLAGS_PAN) 6118c2ecf20Sopenharmony_ci priv->valid_contexts |= BIT(IWL_RXON_CTX_PAN); 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci for (i = 0; i < NUM_IWL_RXON_CTX; i++) 6148c2ecf20Sopenharmony_ci priv->contexts[i].ctxid = i; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci priv->contexts[IWL_RXON_CTX_BSS].always_active = true; 6178c2ecf20Sopenharmony_ci priv->contexts[IWL_RXON_CTX_BSS].is_active = true; 6188c2ecf20Sopenharmony_ci priv->contexts[IWL_RXON_CTX_BSS].rxon_cmd = REPLY_RXON; 6198c2ecf20Sopenharmony_ci priv->contexts[IWL_RXON_CTX_BSS].rxon_timing_cmd = REPLY_RXON_TIMING; 6208c2ecf20Sopenharmony_ci priv->contexts[IWL_RXON_CTX_BSS].rxon_assoc_cmd = REPLY_RXON_ASSOC; 6218c2ecf20Sopenharmony_ci priv->contexts[IWL_RXON_CTX_BSS].qos_cmd = REPLY_QOS_PARAM; 6228c2ecf20Sopenharmony_ci priv->contexts[IWL_RXON_CTX_BSS].ap_sta_id = IWL_AP_ID; 6238c2ecf20Sopenharmony_ci priv->contexts[IWL_RXON_CTX_BSS].wep_key_cmd = REPLY_WEPKEY; 6248c2ecf20Sopenharmony_ci priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID; 6258c2ecf20Sopenharmony_ci priv->contexts[IWL_RXON_CTX_BSS].exclusive_interface_modes = 6268c2ecf20Sopenharmony_ci BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_MONITOR); 6278c2ecf20Sopenharmony_ci priv->contexts[IWL_RXON_CTX_BSS].interface_modes = 6288c2ecf20Sopenharmony_ci BIT(NL80211_IFTYPE_STATION); 6298c2ecf20Sopenharmony_ci priv->contexts[IWL_RXON_CTX_BSS].ap_devtype = RXON_DEV_TYPE_AP; 6308c2ecf20Sopenharmony_ci priv->contexts[IWL_RXON_CTX_BSS].ibss_devtype = RXON_DEV_TYPE_IBSS; 6318c2ecf20Sopenharmony_ci priv->contexts[IWL_RXON_CTX_BSS].station_devtype = RXON_DEV_TYPE_ESS; 6328c2ecf20Sopenharmony_ci priv->contexts[IWL_RXON_CTX_BSS].unused_devtype = RXON_DEV_TYPE_ESS; 6338c2ecf20Sopenharmony_ci memcpy(priv->contexts[IWL_RXON_CTX_BSS].ac_to_queue, 6348c2ecf20Sopenharmony_ci iwlagn_bss_ac_to_queue, sizeof(iwlagn_bss_ac_to_queue)); 6358c2ecf20Sopenharmony_ci memcpy(priv->contexts[IWL_RXON_CTX_BSS].ac_to_fifo, 6368c2ecf20Sopenharmony_ci iwlagn_bss_ac_to_fifo, sizeof(iwlagn_bss_ac_to_fifo)); 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci priv->contexts[IWL_RXON_CTX_PAN].rxon_cmd = REPLY_WIPAN_RXON; 6398c2ecf20Sopenharmony_ci priv->contexts[IWL_RXON_CTX_PAN].rxon_timing_cmd = 6408c2ecf20Sopenharmony_ci REPLY_WIPAN_RXON_TIMING; 6418c2ecf20Sopenharmony_ci priv->contexts[IWL_RXON_CTX_PAN].rxon_assoc_cmd = 6428c2ecf20Sopenharmony_ci REPLY_WIPAN_RXON_ASSOC; 6438c2ecf20Sopenharmony_ci priv->contexts[IWL_RXON_CTX_PAN].qos_cmd = REPLY_WIPAN_QOS_PARAM; 6448c2ecf20Sopenharmony_ci priv->contexts[IWL_RXON_CTX_PAN].ap_sta_id = IWL_AP_ID_PAN; 6458c2ecf20Sopenharmony_ci priv->contexts[IWL_RXON_CTX_PAN].wep_key_cmd = REPLY_WIPAN_WEPKEY; 6468c2ecf20Sopenharmony_ci priv->contexts[IWL_RXON_CTX_PAN].bcast_sta_id = IWLAGN_PAN_BCAST_ID; 6478c2ecf20Sopenharmony_ci priv->contexts[IWL_RXON_CTX_PAN].station_flags = STA_FLG_PAN_STATION; 6488c2ecf20Sopenharmony_ci priv->contexts[IWL_RXON_CTX_PAN].interface_modes = 6498c2ecf20Sopenharmony_ci BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP); 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci priv->contexts[IWL_RXON_CTX_PAN].ap_devtype = RXON_DEV_TYPE_CP; 6528c2ecf20Sopenharmony_ci priv->contexts[IWL_RXON_CTX_PAN].station_devtype = RXON_DEV_TYPE_2STA; 6538c2ecf20Sopenharmony_ci priv->contexts[IWL_RXON_CTX_PAN].unused_devtype = RXON_DEV_TYPE_P2P; 6548c2ecf20Sopenharmony_ci memcpy(priv->contexts[IWL_RXON_CTX_PAN].ac_to_queue, 6558c2ecf20Sopenharmony_ci iwlagn_pan_ac_to_queue, sizeof(iwlagn_pan_ac_to_queue)); 6568c2ecf20Sopenharmony_ci memcpy(priv->contexts[IWL_RXON_CTX_PAN].ac_to_fifo, 6578c2ecf20Sopenharmony_ci iwlagn_pan_ac_to_fifo, sizeof(iwlagn_pan_ac_to_fifo)); 6588c2ecf20Sopenharmony_ci priv->contexts[IWL_RXON_CTX_PAN].mcast_queue = IWL_IPAN_MCAST_QUEUE; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2); 6618c2ecf20Sopenharmony_ci} 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_cistatic void iwl_rf_kill_ct_config(struct iwl_priv *priv) 6648c2ecf20Sopenharmony_ci{ 6658c2ecf20Sopenharmony_ci struct iwl_ct_kill_config cmd; 6668c2ecf20Sopenharmony_ci struct iwl_ct_kill_throttling_config adv_cmd; 6678c2ecf20Sopenharmony_ci int ret = 0; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR, 6708c2ecf20Sopenharmony_ci CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci priv->thermal_throttle.ct_kill_toggle = false; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci if (priv->lib->support_ct_kill_exit) { 6758c2ecf20Sopenharmony_ci adv_cmd.critical_temperature_enter = 6768c2ecf20Sopenharmony_ci cpu_to_le32(priv->hw_params.ct_kill_threshold); 6778c2ecf20Sopenharmony_ci adv_cmd.critical_temperature_exit = 6788c2ecf20Sopenharmony_ci cpu_to_le32(priv->hw_params.ct_kill_exit_threshold); 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci ret = iwl_dvm_send_cmd_pdu(priv, 6818c2ecf20Sopenharmony_ci REPLY_CT_KILL_CONFIG_CMD, 6828c2ecf20Sopenharmony_ci 0, sizeof(adv_cmd), &adv_cmd); 6838c2ecf20Sopenharmony_ci if (ret) 6848c2ecf20Sopenharmony_ci IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n"); 6858c2ecf20Sopenharmony_ci else 6868c2ecf20Sopenharmony_ci IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD " 6878c2ecf20Sopenharmony_ci "succeeded, critical temperature enter is %d," 6888c2ecf20Sopenharmony_ci "exit is %d\n", 6898c2ecf20Sopenharmony_ci priv->hw_params.ct_kill_threshold, 6908c2ecf20Sopenharmony_ci priv->hw_params.ct_kill_exit_threshold); 6918c2ecf20Sopenharmony_ci } else { 6928c2ecf20Sopenharmony_ci cmd.critical_temperature_R = 6938c2ecf20Sopenharmony_ci cpu_to_le32(priv->hw_params.ct_kill_threshold); 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci ret = iwl_dvm_send_cmd_pdu(priv, 6968c2ecf20Sopenharmony_ci REPLY_CT_KILL_CONFIG_CMD, 6978c2ecf20Sopenharmony_ci 0, sizeof(cmd), &cmd); 6988c2ecf20Sopenharmony_ci if (ret) 6998c2ecf20Sopenharmony_ci IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n"); 7008c2ecf20Sopenharmony_ci else 7018c2ecf20Sopenharmony_ci IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD " 7028c2ecf20Sopenharmony_ci "succeeded, " 7038c2ecf20Sopenharmony_ci "critical temperature is %d\n", 7048c2ecf20Sopenharmony_ci priv->hw_params.ct_kill_threshold); 7058c2ecf20Sopenharmony_ci } 7068c2ecf20Sopenharmony_ci} 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_cistatic int iwlagn_send_calib_cfg_rt(struct iwl_priv *priv, u32 cfg) 7098c2ecf20Sopenharmony_ci{ 7108c2ecf20Sopenharmony_ci struct iwl_calib_cfg_cmd calib_cfg_cmd; 7118c2ecf20Sopenharmony_ci struct iwl_host_cmd cmd = { 7128c2ecf20Sopenharmony_ci .id = CALIBRATION_CFG_CMD, 7138c2ecf20Sopenharmony_ci .len = { sizeof(struct iwl_calib_cfg_cmd), }, 7148c2ecf20Sopenharmony_ci .data = { &calib_cfg_cmd, }, 7158c2ecf20Sopenharmony_ci }; 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci memset(&calib_cfg_cmd, 0, sizeof(calib_cfg_cmd)); 7188c2ecf20Sopenharmony_ci calib_cfg_cmd.ucd_calib_cfg.once.is_enable = IWL_CALIB_RT_CFG_ALL; 7198c2ecf20Sopenharmony_ci calib_cfg_cmd.ucd_calib_cfg.once.start = cpu_to_le32(cfg); 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci return iwl_dvm_send_cmd(priv, &cmd); 7228c2ecf20Sopenharmony_ci} 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_cistatic int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant) 7268c2ecf20Sopenharmony_ci{ 7278c2ecf20Sopenharmony_ci struct iwl_tx_ant_config_cmd tx_ant_cmd = { 7288c2ecf20Sopenharmony_ci .valid = cpu_to_le32(valid_tx_ant), 7298c2ecf20Sopenharmony_ci }; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci if (IWL_UCODE_API(priv->fw->ucode_ver) > 1) { 7328c2ecf20Sopenharmony_ci IWL_DEBUG_HC(priv, "select valid tx ant: %u\n", valid_tx_ant); 7338c2ecf20Sopenharmony_ci return iwl_dvm_send_cmd_pdu(priv, TX_ANT_CONFIGURATION_CMD, 0, 7348c2ecf20Sopenharmony_ci sizeof(struct iwl_tx_ant_config_cmd), 7358c2ecf20Sopenharmony_ci &tx_ant_cmd); 7368c2ecf20Sopenharmony_ci } else { 7378c2ecf20Sopenharmony_ci IWL_DEBUG_HC(priv, "TX_ANT_CONFIGURATION_CMD not supported\n"); 7388c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 7398c2ecf20Sopenharmony_ci } 7408c2ecf20Sopenharmony_ci} 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_cistatic void iwl_send_bt_config(struct iwl_priv *priv) 7438c2ecf20Sopenharmony_ci{ 7448c2ecf20Sopenharmony_ci struct iwl_bt_cmd bt_cmd = { 7458c2ecf20Sopenharmony_ci .lead_time = BT_LEAD_TIME_DEF, 7468c2ecf20Sopenharmony_ci .max_kill = BT_MAX_KILL_DEF, 7478c2ecf20Sopenharmony_ci .kill_ack_mask = 0, 7488c2ecf20Sopenharmony_ci .kill_cts_mask = 0, 7498c2ecf20Sopenharmony_ci }; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci if (!iwlwifi_mod_params.bt_coex_active) 7528c2ecf20Sopenharmony_ci bt_cmd.flags = BT_COEX_DISABLE; 7538c2ecf20Sopenharmony_ci else 7548c2ecf20Sopenharmony_ci bt_cmd.flags = BT_COEX_ENABLE; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci priv->bt_enable_flag = bt_cmd.flags; 7578c2ecf20Sopenharmony_ci IWL_DEBUG_INFO(priv, "BT coex %s\n", 7588c2ecf20Sopenharmony_ci (bt_cmd.flags == BT_COEX_DISABLE) ? "disable" : "active"); 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci if (iwl_dvm_send_cmd_pdu(priv, REPLY_BT_CONFIG, 7618c2ecf20Sopenharmony_ci 0, sizeof(struct iwl_bt_cmd), &bt_cmd)) 7628c2ecf20Sopenharmony_ci IWL_ERR(priv, "failed to send BT Coex Config\n"); 7638c2ecf20Sopenharmony_ci} 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci/* 7668c2ecf20Sopenharmony_ci * iwl_alive_start - called after REPLY_ALIVE notification received 7678c2ecf20Sopenharmony_ci * from protocol/runtime uCode (initialization uCode's 7688c2ecf20Sopenharmony_ci * Alive gets handled by iwl_init_alive_start()). 7698c2ecf20Sopenharmony_ci */ 7708c2ecf20Sopenharmony_ciint iwl_alive_start(struct iwl_priv *priv) 7718c2ecf20Sopenharmony_ci{ 7728c2ecf20Sopenharmony_ci int ret = 0; 7738c2ecf20Sopenharmony_ci struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci IWL_DEBUG_INFO(priv, "Runtime Alive received.\n"); 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci /* After the ALIVE response, we can send host commands to the uCode */ 7788c2ecf20Sopenharmony_ci set_bit(STATUS_ALIVE, &priv->status); 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci if (iwl_is_rfkill(priv)) 7818c2ecf20Sopenharmony_ci return -ERFKILL; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci if (priv->event_log.ucode_trace) { 7848c2ecf20Sopenharmony_ci /* start collecting data now */ 7858c2ecf20Sopenharmony_ci mod_timer(&priv->ucode_trace, jiffies); 7868c2ecf20Sopenharmony_ci } 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci /* download priority table before any calibration request */ 7898c2ecf20Sopenharmony_ci if (priv->lib->bt_params && 7908c2ecf20Sopenharmony_ci priv->lib->bt_params->advanced_bt_coexist) { 7918c2ecf20Sopenharmony_ci /* Configure Bluetooth device coexistence support */ 7928c2ecf20Sopenharmony_ci if (priv->lib->bt_params->bt_sco_disable) 7938c2ecf20Sopenharmony_ci priv->bt_enable_pspoll = false; 7948c2ecf20Sopenharmony_ci else 7958c2ecf20Sopenharmony_ci priv->bt_enable_pspoll = true; 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci priv->bt_valid = IWLAGN_BT_ALL_VALID_MSK; 7988c2ecf20Sopenharmony_ci priv->kill_ack_mask = IWLAGN_BT_KILL_ACK_MASK_DEFAULT; 7998c2ecf20Sopenharmony_ci priv->kill_cts_mask = IWLAGN_BT_KILL_CTS_MASK_DEFAULT; 8008c2ecf20Sopenharmony_ci iwlagn_send_advance_bt_config(priv); 8018c2ecf20Sopenharmony_ci priv->bt_valid = IWLAGN_BT_VALID_ENABLE_FLAGS; 8028c2ecf20Sopenharmony_ci priv->cur_rssi_ctx = NULL; 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci iwl_send_prio_tbl(priv); 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci /* FIXME: w/a to force change uCode BT state machine */ 8078c2ecf20Sopenharmony_ci ret = iwl_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN, 8088c2ecf20Sopenharmony_ci BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); 8098c2ecf20Sopenharmony_ci if (ret) 8108c2ecf20Sopenharmony_ci return ret; 8118c2ecf20Sopenharmony_ci ret = iwl_send_bt_env(priv, IWL_BT_COEX_ENV_CLOSE, 8128c2ecf20Sopenharmony_ci BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); 8138c2ecf20Sopenharmony_ci if (ret) 8148c2ecf20Sopenharmony_ci return ret; 8158c2ecf20Sopenharmony_ci } else if (priv->lib->bt_params) { 8168c2ecf20Sopenharmony_ci /* 8178c2ecf20Sopenharmony_ci * default is 2-wire BT coexexistence support 8188c2ecf20Sopenharmony_ci */ 8198c2ecf20Sopenharmony_ci iwl_send_bt_config(priv); 8208c2ecf20Sopenharmony_ci } 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci /* 8238c2ecf20Sopenharmony_ci * Perform runtime calibrations, including DC calibration. 8248c2ecf20Sopenharmony_ci */ 8258c2ecf20Sopenharmony_ci iwlagn_send_calib_cfg_rt(priv, IWL_CALIB_CFG_DC_IDX); 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci ieee80211_wake_queues(priv->hw); 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci /* Configure Tx antenna selection based on H/W config */ 8308c2ecf20Sopenharmony_ci iwlagn_send_tx_ant_config(priv, priv->nvm_data->valid_tx_ant); 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci if (iwl_is_associated_ctx(ctx) && !priv->wowlan) { 8338c2ecf20Sopenharmony_ci struct iwl_rxon_cmd *active_rxon = 8348c2ecf20Sopenharmony_ci (struct iwl_rxon_cmd *)&ctx->active; 8358c2ecf20Sopenharmony_ci /* apply any changes in staging */ 8368c2ecf20Sopenharmony_ci ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK; 8378c2ecf20Sopenharmony_ci active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; 8388c2ecf20Sopenharmony_ci } else { 8398c2ecf20Sopenharmony_ci struct iwl_rxon_context *tmp; 8408c2ecf20Sopenharmony_ci /* Initialize our rx_config data */ 8418c2ecf20Sopenharmony_ci for_each_context(priv, tmp) 8428c2ecf20Sopenharmony_ci iwl_connection_init_rx_config(priv, tmp); 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci iwlagn_set_rxon_chain(priv, ctx); 8458c2ecf20Sopenharmony_ci } 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci if (!priv->wowlan) { 8488c2ecf20Sopenharmony_ci /* WoWLAN ucode will not reply in the same way, skip it */ 8498c2ecf20Sopenharmony_ci iwl_reset_run_time_calib(priv); 8508c2ecf20Sopenharmony_ci } 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci set_bit(STATUS_READY, &priv->status); 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci /* Configure the adapter for unassociated operation */ 8558c2ecf20Sopenharmony_ci ret = iwlagn_commit_rxon(priv, ctx); 8568c2ecf20Sopenharmony_ci if (ret) 8578c2ecf20Sopenharmony_ci return ret; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci /* At this point, the NIC is initialized and operational */ 8608c2ecf20Sopenharmony_ci iwl_rf_kill_ct_config(priv); 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n"); 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci return iwl_power_update_mode(priv, true); 8658c2ecf20Sopenharmony_ci} 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci/** 8688c2ecf20Sopenharmony_ci * iwl_clear_driver_stations - clear knowledge of all stations from driver 8698c2ecf20Sopenharmony_ci * @priv: iwl priv struct 8708c2ecf20Sopenharmony_ci * 8718c2ecf20Sopenharmony_ci * This is called during iwl_down() to make sure that in the case 8728c2ecf20Sopenharmony_ci * we're coming there from a hardware restart mac80211 will be 8738c2ecf20Sopenharmony_ci * able to reconfigure stations -- if we're getting there in the 8748c2ecf20Sopenharmony_ci * normal down flow then the stations will already be cleared. 8758c2ecf20Sopenharmony_ci */ 8768c2ecf20Sopenharmony_cistatic void iwl_clear_driver_stations(struct iwl_priv *priv) 8778c2ecf20Sopenharmony_ci{ 8788c2ecf20Sopenharmony_ci struct iwl_rxon_context *ctx; 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci spin_lock_bh(&priv->sta_lock); 8818c2ecf20Sopenharmony_ci memset(priv->stations, 0, sizeof(priv->stations)); 8828c2ecf20Sopenharmony_ci priv->num_stations = 0; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci priv->ucode_key_table = 0; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci for_each_context(priv, ctx) { 8878c2ecf20Sopenharmony_ci /* 8888c2ecf20Sopenharmony_ci * Remove all key information that is not stored as part 8898c2ecf20Sopenharmony_ci * of station information since mac80211 may not have had 8908c2ecf20Sopenharmony_ci * a chance to remove all the keys. When device is 8918c2ecf20Sopenharmony_ci * reconfigured by mac80211 after an error all keys will 8928c2ecf20Sopenharmony_ci * be reconfigured. 8938c2ecf20Sopenharmony_ci */ 8948c2ecf20Sopenharmony_ci memset(ctx->wep_keys, 0, sizeof(ctx->wep_keys)); 8958c2ecf20Sopenharmony_ci ctx->key_mapping_keys = 0; 8968c2ecf20Sopenharmony_ci } 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci spin_unlock_bh(&priv->sta_lock); 8998c2ecf20Sopenharmony_ci} 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_civoid iwl_down(struct iwl_priv *priv) 9028c2ecf20Sopenharmony_ci{ 9038c2ecf20Sopenharmony_ci int exit_pending; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci IWL_DEBUG_INFO(priv, DRV_NAME " is going down\n"); 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci lockdep_assert_held(&priv->mutex); 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci iwl_scan_cancel_timeout(priv, 200); 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci exit_pending = 9128c2ecf20Sopenharmony_ci test_and_set_bit(STATUS_EXIT_PENDING, &priv->status); 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci iwl_clear_ucode_stations(priv, NULL); 9158c2ecf20Sopenharmony_ci iwl_dealloc_bcast_stations(priv); 9168c2ecf20Sopenharmony_ci iwl_clear_driver_stations(priv); 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci /* reset BT coex data */ 9198c2ecf20Sopenharmony_ci priv->bt_status = 0; 9208c2ecf20Sopenharmony_ci priv->cur_rssi_ctx = NULL; 9218c2ecf20Sopenharmony_ci priv->bt_is_sco = 0; 9228c2ecf20Sopenharmony_ci if (priv->lib->bt_params) 9238c2ecf20Sopenharmony_ci priv->bt_traffic_load = 9248c2ecf20Sopenharmony_ci priv->lib->bt_params->bt_init_traffic_load; 9258c2ecf20Sopenharmony_ci else 9268c2ecf20Sopenharmony_ci priv->bt_traffic_load = 0; 9278c2ecf20Sopenharmony_ci priv->bt_full_concurrent = false; 9288c2ecf20Sopenharmony_ci priv->bt_ci_compliance = 0; 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci /* Wipe out the EXIT_PENDING status bit if we are not actually 9318c2ecf20Sopenharmony_ci * exiting the module */ 9328c2ecf20Sopenharmony_ci if (!exit_pending) 9338c2ecf20Sopenharmony_ci clear_bit(STATUS_EXIT_PENDING, &priv->status); 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci if (priv->mac80211_registered) 9368c2ecf20Sopenharmony_ci ieee80211_stop_queues(priv->hw); 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci priv->ucode_loaded = false; 9398c2ecf20Sopenharmony_ci iwl_trans_stop_device(priv->trans); 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci /* Set num_aux_in_flight must be done after the transport is stopped */ 9428c2ecf20Sopenharmony_ci atomic_set(&priv->num_aux_in_flight, 0); 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci /* Clear out all status bits but a few that are stable across reset */ 9458c2ecf20Sopenharmony_ci priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) << 9468c2ecf20Sopenharmony_ci STATUS_RF_KILL_HW | 9478c2ecf20Sopenharmony_ci test_bit(STATUS_FW_ERROR, &priv->status) << 9488c2ecf20Sopenharmony_ci STATUS_FW_ERROR | 9498c2ecf20Sopenharmony_ci test_bit(STATUS_EXIT_PENDING, &priv->status) << 9508c2ecf20Sopenharmony_ci STATUS_EXIT_PENDING; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci dev_kfree_skb(priv->beacon_skb); 9538c2ecf20Sopenharmony_ci priv->beacon_skb = NULL; 9548c2ecf20Sopenharmony_ci} 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci/***************************************************************************** 9578c2ecf20Sopenharmony_ci * 9588c2ecf20Sopenharmony_ci * Workqueue callbacks 9598c2ecf20Sopenharmony_ci * 9608c2ecf20Sopenharmony_ci *****************************************************************************/ 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_cistatic void iwl_bg_run_time_calib_work(struct work_struct *work) 9638c2ecf20Sopenharmony_ci{ 9648c2ecf20Sopenharmony_ci struct iwl_priv *priv = container_of(work, struct iwl_priv, 9658c2ecf20Sopenharmony_ci run_time_calib_work); 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci mutex_lock(&priv->mutex); 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci if (test_bit(STATUS_EXIT_PENDING, &priv->status) || 9708c2ecf20Sopenharmony_ci test_bit(STATUS_SCANNING, &priv->status)) { 9718c2ecf20Sopenharmony_ci mutex_unlock(&priv->mutex); 9728c2ecf20Sopenharmony_ci return; 9738c2ecf20Sopenharmony_ci } 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci if (priv->start_calib) { 9768c2ecf20Sopenharmony_ci iwl_chain_noise_calibration(priv); 9778c2ecf20Sopenharmony_ci iwl_sensitivity_calibration(priv); 9788c2ecf20Sopenharmony_ci } 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci mutex_unlock(&priv->mutex); 9818c2ecf20Sopenharmony_ci} 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_civoid iwlagn_prepare_restart(struct iwl_priv *priv) 9848c2ecf20Sopenharmony_ci{ 9858c2ecf20Sopenharmony_ci bool bt_full_concurrent; 9868c2ecf20Sopenharmony_ci u8 bt_ci_compliance; 9878c2ecf20Sopenharmony_ci u8 bt_load; 9888c2ecf20Sopenharmony_ci u8 bt_status; 9898c2ecf20Sopenharmony_ci bool bt_is_sco; 9908c2ecf20Sopenharmony_ci int i; 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci lockdep_assert_held(&priv->mutex); 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci priv->is_open = 0; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci /* 9978c2ecf20Sopenharmony_ci * __iwl_down() will clear the BT status variables, 9988c2ecf20Sopenharmony_ci * which is correct, but when we restart we really 9998c2ecf20Sopenharmony_ci * want to keep them so restore them afterwards. 10008c2ecf20Sopenharmony_ci * 10018c2ecf20Sopenharmony_ci * The restart process will later pick them up and 10028c2ecf20Sopenharmony_ci * re-configure the hw when we reconfigure the BT 10038c2ecf20Sopenharmony_ci * command. 10048c2ecf20Sopenharmony_ci */ 10058c2ecf20Sopenharmony_ci bt_full_concurrent = priv->bt_full_concurrent; 10068c2ecf20Sopenharmony_ci bt_ci_compliance = priv->bt_ci_compliance; 10078c2ecf20Sopenharmony_ci bt_load = priv->bt_traffic_load; 10088c2ecf20Sopenharmony_ci bt_status = priv->bt_status; 10098c2ecf20Sopenharmony_ci bt_is_sco = priv->bt_is_sco; 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci iwl_down(priv); 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci priv->bt_full_concurrent = bt_full_concurrent; 10148c2ecf20Sopenharmony_ci priv->bt_ci_compliance = bt_ci_compliance; 10158c2ecf20Sopenharmony_ci priv->bt_traffic_load = bt_load; 10168c2ecf20Sopenharmony_ci priv->bt_status = bt_status; 10178c2ecf20Sopenharmony_ci priv->bt_is_sco = bt_is_sco; 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci /* reset aggregation queues */ 10208c2ecf20Sopenharmony_ci for (i = IWLAGN_FIRST_AMPDU_QUEUE; i < IWL_MAX_HW_QUEUES; i++) 10218c2ecf20Sopenharmony_ci priv->queue_to_mac80211[i] = IWL_INVALID_MAC80211_QUEUE; 10228c2ecf20Sopenharmony_ci /* and stop counts */ 10238c2ecf20Sopenharmony_ci for (i = 0; i < IWL_MAX_HW_QUEUES; i++) 10248c2ecf20Sopenharmony_ci atomic_set(&priv->queue_stop_count[i], 0); 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci memset(priv->agg_q_alloc, 0, sizeof(priv->agg_q_alloc)); 10278c2ecf20Sopenharmony_ci} 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_cistatic void iwl_bg_restart(struct work_struct *data) 10308c2ecf20Sopenharmony_ci{ 10318c2ecf20Sopenharmony_ci struct iwl_priv *priv = container_of(data, struct iwl_priv, restart); 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci if (test_bit(STATUS_EXIT_PENDING, &priv->status)) 10348c2ecf20Sopenharmony_ci return; 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci if (test_and_clear_bit(STATUS_FW_ERROR, &priv->status)) { 10378c2ecf20Sopenharmony_ci mutex_lock(&priv->mutex); 10388c2ecf20Sopenharmony_ci iwlagn_prepare_restart(priv); 10398c2ecf20Sopenharmony_ci mutex_unlock(&priv->mutex); 10408c2ecf20Sopenharmony_ci iwl_cancel_deferred_work(priv); 10418c2ecf20Sopenharmony_ci if (priv->mac80211_registered) 10428c2ecf20Sopenharmony_ci ieee80211_restart_hw(priv->hw); 10438c2ecf20Sopenharmony_ci else 10448c2ecf20Sopenharmony_ci IWL_ERR(priv, 10458c2ecf20Sopenharmony_ci "Cannot request restart before registering with mac80211\n"); 10468c2ecf20Sopenharmony_ci } else { 10478c2ecf20Sopenharmony_ci WARN_ON(1); 10488c2ecf20Sopenharmony_ci } 10498c2ecf20Sopenharmony_ci} 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci/***************************************************************************** 10528c2ecf20Sopenharmony_ci * 10538c2ecf20Sopenharmony_ci * driver setup and teardown 10548c2ecf20Sopenharmony_ci * 10558c2ecf20Sopenharmony_ci *****************************************************************************/ 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_cistatic void iwl_setup_deferred_work(struct iwl_priv *priv) 10588c2ecf20Sopenharmony_ci{ 10598c2ecf20Sopenharmony_ci priv->workqueue = alloc_ordered_workqueue(DRV_NAME, 0); 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci INIT_WORK(&priv->restart, iwl_bg_restart); 10628c2ecf20Sopenharmony_ci INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update); 10638c2ecf20Sopenharmony_ci INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work); 10648c2ecf20Sopenharmony_ci INIT_WORK(&priv->tx_flush, iwl_bg_tx_flush); 10658c2ecf20Sopenharmony_ci INIT_WORK(&priv->bt_full_concurrency, iwl_bg_bt_full_concurrency); 10668c2ecf20Sopenharmony_ci INIT_WORK(&priv->bt_runtime_config, iwl_bg_bt_runtime_config); 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci iwl_setup_scan_deferred_work(priv); 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci if (priv->lib->bt_params) 10718c2ecf20Sopenharmony_ci iwlagn_bt_setup_deferred_work(priv); 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci timer_setup(&priv->statistics_periodic, iwl_bg_statistics_periodic, 0); 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci timer_setup(&priv->ucode_trace, iwl_bg_ucode_trace, 0); 10768c2ecf20Sopenharmony_ci} 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_civoid iwl_cancel_deferred_work(struct iwl_priv *priv) 10798c2ecf20Sopenharmony_ci{ 10808c2ecf20Sopenharmony_ci if (priv->lib->bt_params) 10818c2ecf20Sopenharmony_ci iwlagn_bt_cancel_deferred_work(priv); 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci cancel_work_sync(&priv->run_time_calib_work); 10848c2ecf20Sopenharmony_ci cancel_work_sync(&priv->beacon_update); 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci iwl_cancel_scan_deferred_work(priv); 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci cancel_work_sync(&priv->bt_full_concurrency); 10898c2ecf20Sopenharmony_ci cancel_work_sync(&priv->bt_runtime_config); 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci del_timer_sync(&priv->statistics_periodic); 10928c2ecf20Sopenharmony_ci del_timer_sync(&priv->ucode_trace); 10938c2ecf20Sopenharmony_ci} 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_cistatic int iwl_init_drv(struct iwl_priv *priv) 10968c2ecf20Sopenharmony_ci{ 10978c2ecf20Sopenharmony_ci spin_lock_init(&priv->sta_lock); 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci mutex_init(&priv->mutex); 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&priv->calib_results); 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci priv->band = NL80211_BAND_2GHZ; 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci priv->plcp_delta_threshold = priv->lib->plcp_delta_threshold; 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci priv->iw_mode = NL80211_IFTYPE_STATION; 11088c2ecf20Sopenharmony_ci priv->current_ht_config.smps = IEEE80211_SMPS_STATIC; 11098c2ecf20Sopenharmony_ci priv->missed_beacon_threshold = IWL_MISSED_BEACON_THRESHOLD_DEF; 11108c2ecf20Sopenharmony_ci priv->agg_tids_count = 0; 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci priv->rx_statistics_jiffies = jiffies; 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci /* Choose which receivers/antennas to use */ 11158c2ecf20Sopenharmony_ci iwlagn_set_rxon_chain(priv, &priv->contexts[IWL_RXON_CTX_BSS]); 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci iwl_init_scan_params(priv); 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci /* init bt coex */ 11208c2ecf20Sopenharmony_ci if (priv->lib->bt_params && 11218c2ecf20Sopenharmony_ci priv->lib->bt_params->advanced_bt_coexist) { 11228c2ecf20Sopenharmony_ci priv->kill_ack_mask = IWLAGN_BT_KILL_ACK_MASK_DEFAULT; 11238c2ecf20Sopenharmony_ci priv->kill_cts_mask = IWLAGN_BT_KILL_CTS_MASK_DEFAULT; 11248c2ecf20Sopenharmony_ci priv->bt_valid = IWLAGN_BT_ALL_VALID_MSK; 11258c2ecf20Sopenharmony_ci priv->bt_on_thresh = BT_ON_THRESHOLD_DEF; 11268c2ecf20Sopenharmony_ci priv->bt_duration = BT_DURATION_LIMIT_DEF; 11278c2ecf20Sopenharmony_ci priv->dynamic_frag_thresh = BT_FRAG_THRESHOLD_DEF; 11288c2ecf20Sopenharmony_ci } 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci return 0; 11318c2ecf20Sopenharmony_ci} 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_cistatic void iwl_uninit_drv(struct iwl_priv *priv) 11348c2ecf20Sopenharmony_ci{ 11358c2ecf20Sopenharmony_ci kfree(priv->scan_cmd); 11368c2ecf20Sopenharmony_ci kfree(priv->beacon_cmd); 11378c2ecf20Sopenharmony_ci kfree(rcu_dereference_raw(priv->noa_data)); 11388c2ecf20Sopenharmony_ci iwl_calib_free_results(priv); 11398c2ecf20Sopenharmony_ci#ifdef CONFIG_IWLWIFI_DEBUGFS 11408c2ecf20Sopenharmony_ci kfree(priv->wowlan_sram); 11418c2ecf20Sopenharmony_ci#endif 11428c2ecf20Sopenharmony_ci} 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_cistatic void iwl_set_hw_params(struct iwl_priv *priv) 11458c2ecf20Sopenharmony_ci{ 11468c2ecf20Sopenharmony_ci if (priv->cfg->ht_params) 11478c2ecf20Sopenharmony_ci priv->hw_params.use_rts_for_aggregation = 11488c2ecf20Sopenharmony_ci priv->cfg->ht_params->use_rts_for_aggregation; 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci /* Device-specific setup */ 11518c2ecf20Sopenharmony_ci priv->lib->set_hw_params(priv); 11528c2ecf20Sopenharmony_ci} 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci/* show what optional capabilities we have */ 11578c2ecf20Sopenharmony_cistatic void iwl_option_config(struct iwl_priv *priv) 11588c2ecf20Sopenharmony_ci{ 11598c2ecf20Sopenharmony_ci#ifdef CONFIG_IWLWIFI_DEBUG 11608c2ecf20Sopenharmony_ci IWL_INFO(priv, "CONFIG_IWLWIFI_DEBUG enabled\n"); 11618c2ecf20Sopenharmony_ci#else 11628c2ecf20Sopenharmony_ci IWL_INFO(priv, "CONFIG_IWLWIFI_DEBUG disabled\n"); 11638c2ecf20Sopenharmony_ci#endif 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci#ifdef CONFIG_IWLWIFI_DEBUGFS 11668c2ecf20Sopenharmony_ci IWL_INFO(priv, "CONFIG_IWLWIFI_DEBUGFS enabled\n"); 11678c2ecf20Sopenharmony_ci#else 11688c2ecf20Sopenharmony_ci IWL_INFO(priv, "CONFIG_IWLWIFI_DEBUGFS disabled\n"); 11698c2ecf20Sopenharmony_ci#endif 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci#ifdef CONFIG_IWLWIFI_DEVICE_TRACING 11728c2ecf20Sopenharmony_ci IWL_INFO(priv, "CONFIG_IWLWIFI_DEVICE_TRACING enabled\n"); 11738c2ecf20Sopenharmony_ci#else 11748c2ecf20Sopenharmony_ci IWL_INFO(priv, "CONFIG_IWLWIFI_DEVICE_TRACING disabled\n"); 11758c2ecf20Sopenharmony_ci#endif 11768c2ecf20Sopenharmony_ci} 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_cistatic int iwl_eeprom_init_hw_params(struct iwl_priv *priv) 11798c2ecf20Sopenharmony_ci{ 11808c2ecf20Sopenharmony_ci struct iwl_nvm_data *data = priv->nvm_data; 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci if (data->sku_cap_11n_enable && 11838c2ecf20Sopenharmony_ci !priv->cfg->ht_params) { 11848c2ecf20Sopenharmony_ci IWL_ERR(priv, "Invalid 11n configuration\n"); 11858c2ecf20Sopenharmony_ci return -EINVAL; 11868c2ecf20Sopenharmony_ci } 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci if (!data->sku_cap_11n_enable && !data->sku_cap_band_24ghz_enable && 11898c2ecf20Sopenharmony_ci !data->sku_cap_band_52ghz_enable) { 11908c2ecf20Sopenharmony_ci IWL_ERR(priv, "Invalid device sku\n"); 11918c2ecf20Sopenharmony_ci return -EINVAL; 11928c2ecf20Sopenharmony_ci } 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci IWL_DEBUG_INFO(priv, 11958c2ecf20Sopenharmony_ci "Device SKU: 24GHz %s %s, 52GHz %s %s, 11.n %s %s\n", 11968c2ecf20Sopenharmony_ci data->sku_cap_band_24ghz_enable ? "" : "NOT", "enabled", 11978c2ecf20Sopenharmony_ci data->sku_cap_band_52ghz_enable ? "" : "NOT", "enabled", 11988c2ecf20Sopenharmony_ci data->sku_cap_11n_enable ? "" : "NOT", "enabled"); 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci priv->hw_params.tx_chains_num = 12018c2ecf20Sopenharmony_ci num_of_ant(data->valid_tx_ant); 12028c2ecf20Sopenharmony_ci if (priv->cfg->rx_with_siso_diversity) 12038c2ecf20Sopenharmony_ci priv->hw_params.rx_chains_num = 1; 12048c2ecf20Sopenharmony_ci else 12058c2ecf20Sopenharmony_ci priv->hw_params.rx_chains_num = 12068c2ecf20Sopenharmony_ci num_of_ant(data->valid_rx_ant); 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci IWL_DEBUG_INFO(priv, "Valid Tx ant: 0x%X, Valid Rx ant: 0x%X\n", 12098c2ecf20Sopenharmony_ci data->valid_tx_ant, 12108c2ecf20Sopenharmony_ci data->valid_rx_ant); 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci return 0; 12138c2ecf20Sopenharmony_ci} 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_cistatic int iwl_nvm_check_version(struct iwl_nvm_data *data, 12168c2ecf20Sopenharmony_ci struct iwl_trans *trans) 12178c2ecf20Sopenharmony_ci{ 12188c2ecf20Sopenharmony_ci if (data->nvm_version >= trans->cfg->nvm_ver || 12198c2ecf20Sopenharmony_ci data->calib_version >= trans->cfg->nvm_calib_ver) { 12208c2ecf20Sopenharmony_ci IWL_DEBUG_INFO(trans, "device EEPROM VER=0x%x, CALIB=0x%x\n", 12218c2ecf20Sopenharmony_ci data->nvm_version, data->calib_version); 12228c2ecf20Sopenharmony_ci return 0; 12238c2ecf20Sopenharmony_ci } 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci IWL_ERR(trans, 12268c2ecf20Sopenharmony_ci "Unsupported (too old) EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n", 12278c2ecf20Sopenharmony_ci data->nvm_version, trans->cfg->nvm_ver, 12288c2ecf20Sopenharmony_ci data->calib_version, trans->cfg->nvm_calib_ver); 12298c2ecf20Sopenharmony_ci return -EINVAL; 12308c2ecf20Sopenharmony_ci} 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_cistatic struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, 12338c2ecf20Sopenharmony_ci const struct iwl_cfg *cfg, 12348c2ecf20Sopenharmony_ci const struct iwl_fw *fw, 12358c2ecf20Sopenharmony_ci struct dentry *dbgfs_dir) 12368c2ecf20Sopenharmony_ci{ 12378c2ecf20Sopenharmony_ci struct iwl_priv *priv; 12388c2ecf20Sopenharmony_ci struct ieee80211_hw *hw; 12398c2ecf20Sopenharmony_ci struct iwl_op_mode *op_mode; 12408c2ecf20Sopenharmony_ci u16 num_mac; 12418c2ecf20Sopenharmony_ci u32 ucode_flags; 12428c2ecf20Sopenharmony_ci struct iwl_trans_config trans_cfg = {}; 12438c2ecf20Sopenharmony_ci static const u8 no_reclaim_cmds[] = { 12448c2ecf20Sopenharmony_ci REPLY_RX_PHY_CMD, 12458c2ecf20Sopenharmony_ci REPLY_RX_MPDU_CMD, 12468c2ecf20Sopenharmony_ci REPLY_COMPRESSED_BA, 12478c2ecf20Sopenharmony_ci STATISTICS_NOTIFICATION, 12488c2ecf20Sopenharmony_ci REPLY_TX, 12498c2ecf20Sopenharmony_ci }; 12508c2ecf20Sopenharmony_ci int i; 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci /************************ 12538c2ecf20Sopenharmony_ci * 1. Allocating HW data 12548c2ecf20Sopenharmony_ci ************************/ 12558c2ecf20Sopenharmony_ci hw = iwl_alloc_all(); 12568c2ecf20Sopenharmony_ci if (!hw) { 12578c2ecf20Sopenharmony_ci pr_err("%s: Cannot allocate network device\n", trans->name); 12588c2ecf20Sopenharmony_ci goto out; 12598c2ecf20Sopenharmony_ci } 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci op_mode = hw->priv; 12628c2ecf20Sopenharmony_ci op_mode->ops = &iwl_dvm_ops; 12638c2ecf20Sopenharmony_ci priv = IWL_OP_MODE_GET_DVM(op_mode); 12648c2ecf20Sopenharmony_ci priv->trans = trans; 12658c2ecf20Sopenharmony_ci priv->dev = trans->dev; 12668c2ecf20Sopenharmony_ci priv->cfg = cfg; 12678c2ecf20Sopenharmony_ci priv->fw = fw; 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci switch (priv->trans->trans_cfg->device_family) { 12708c2ecf20Sopenharmony_ci case IWL_DEVICE_FAMILY_1000: 12718c2ecf20Sopenharmony_ci case IWL_DEVICE_FAMILY_100: 12728c2ecf20Sopenharmony_ci priv->lib = &iwl_dvm_1000_cfg; 12738c2ecf20Sopenharmony_ci break; 12748c2ecf20Sopenharmony_ci case IWL_DEVICE_FAMILY_2000: 12758c2ecf20Sopenharmony_ci priv->lib = &iwl_dvm_2000_cfg; 12768c2ecf20Sopenharmony_ci break; 12778c2ecf20Sopenharmony_ci case IWL_DEVICE_FAMILY_105: 12788c2ecf20Sopenharmony_ci priv->lib = &iwl_dvm_105_cfg; 12798c2ecf20Sopenharmony_ci break; 12808c2ecf20Sopenharmony_ci case IWL_DEVICE_FAMILY_2030: 12818c2ecf20Sopenharmony_ci case IWL_DEVICE_FAMILY_135: 12828c2ecf20Sopenharmony_ci priv->lib = &iwl_dvm_2030_cfg; 12838c2ecf20Sopenharmony_ci break; 12848c2ecf20Sopenharmony_ci case IWL_DEVICE_FAMILY_5000: 12858c2ecf20Sopenharmony_ci priv->lib = &iwl_dvm_5000_cfg; 12868c2ecf20Sopenharmony_ci break; 12878c2ecf20Sopenharmony_ci case IWL_DEVICE_FAMILY_5150: 12888c2ecf20Sopenharmony_ci priv->lib = &iwl_dvm_5150_cfg; 12898c2ecf20Sopenharmony_ci break; 12908c2ecf20Sopenharmony_ci case IWL_DEVICE_FAMILY_6000: 12918c2ecf20Sopenharmony_ci case IWL_DEVICE_FAMILY_6000i: 12928c2ecf20Sopenharmony_ci priv->lib = &iwl_dvm_6000_cfg; 12938c2ecf20Sopenharmony_ci break; 12948c2ecf20Sopenharmony_ci case IWL_DEVICE_FAMILY_6005: 12958c2ecf20Sopenharmony_ci priv->lib = &iwl_dvm_6005_cfg; 12968c2ecf20Sopenharmony_ci break; 12978c2ecf20Sopenharmony_ci case IWL_DEVICE_FAMILY_6050: 12988c2ecf20Sopenharmony_ci case IWL_DEVICE_FAMILY_6150: 12998c2ecf20Sopenharmony_ci priv->lib = &iwl_dvm_6050_cfg; 13008c2ecf20Sopenharmony_ci break; 13018c2ecf20Sopenharmony_ci case IWL_DEVICE_FAMILY_6030: 13028c2ecf20Sopenharmony_ci priv->lib = &iwl_dvm_6030_cfg; 13038c2ecf20Sopenharmony_ci break; 13048c2ecf20Sopenharmony_ci default: 13058c2ecf20Sopenharmony_ci break; 13068c2ecf20Sopenharmony_ci } 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci if (WARN_ON(!priv->lib)) 13098c2ecf20Sopenharmony_ci goto out_free_hw; 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci /* 13128c2ecf20Sopenharmony_ci * Populate the state variables that the transport layer needs 13138c2ecf20Sopenharmony_ci * to know about. 13148c2ecf20Sopenharmony_ci */ 13158c2ecf20Sopenharmony_ci trans_cfg.op_mode = op_mode; 13168c2ecf20Sopenharmony_ci trans_cfg.no_reclaim_cmds = no_reclaim_cmds; 13178c2ecf20Sopenharmony_ci trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds); 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci switch (iwlwifi_mod_params.amsdu_size) { 13208c2ecf20Sopenharmony_ci case IWL_AMSDU_DEF: 13218c2ecf20Sopenharmony_ci case IWL_AMSDU_4K: 13228c2ecf20Sopenharmony_ci trans_cfg.rx_buf_size = IWL_AMSDU_4K; 13238c2ecf20Sopenharmony_ci break; 13248c2ecf20Sopenharmony_ci case IWL_AMSDU_8K: 13258c2ecf20Sopenharmony_ci trans_cfg.rx_buf_size = IWL_AMSDU_8K; 13268c2ecf20Sopenharmony_ci break; 13278c2ecf20Sopenharmony_ci case IWL_AMSDU_12K: 13288c2ecf20Sopenharmony_ci default: 13298c2ecf20Sopenharmony_ci trans_cfg.rx_buf_size = IWL_AMSDU_4K; 13308c2ecf20Sopenharmony_ci pr_err("Unsupported amsdu_size: %d\n", 13318c2ecf20Sopenharmony_ci iwlwifi_mod_params.amsdu_size); 13328c2ecf20Sopenharmony_ci } 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci trans_cfg.cmd_q_wdg_timeout = IWL_WATCHDOG_DISABLED; 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci trans_cfg.command_groups = iwl_dvm_groups; 13378c2ecf20Sopenharmony_ci trans_cfg.command_groups_size = ARRAY_SIZE(iwl_dvm_groups); 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci trans_cfg.cmd_fifo = IWLAGN_CMD_FIFO_NUM; 13408c2ecf20Sopenharmony_ci trans_cfg.cb_data_offs = offsetof(struct ieee80211_tx_info, 13418c2ecf20Sopenharmony_ci driver_data[2]); 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci WARN_ON(sizeof(priv->transport_queue_stop) * BITS_PER_BYTE < 13448c2ecf20Sopenharmony_ci priv->trans->trans_cfg->base_params->num_of_queues); 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci ucode_flags = fw->ucode_capa.flags; 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci if (ucode_flags & IWL_UCODE_TLV_FLAGS_PAN) { 13498c2ecf20Sopenharmony_ci priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN; 13508c2ecf20Sopenharmony_ci trans_cfg.cmd_queue = IWL_IPAN_CMD_QUEUE_NUM; 13518c2ecf20Sopenharmony_ci } else { 13528c2ecf20Sopenharmony_ci priv->sta_key_max_num = STA_KEY_MAX_NUM; 13538c2ecf20Sopenharmony_ci trans_cfg.cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM; 13548c2ecf20Sopenharmony_ci } 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci /* Configure transport layer */ 13578c2ecf20Sopenharmony_ci iwl_trans_configure(priv->trans, &trans_cfg); 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci trans->rx_mpdu_cmd = REPLY_RX_MPDU_CMD; 13608c2ecf20Sopenharmony_ci trans->rx_mpdu_cmd_hdr_size = sizeof(struct iwl_rx_mpdu_res_start); 13618c2ecf20Sopenharmony_ci trans->command_groups = trans_cfg.command_groups; 13628c2ecf20Sopenharmony_ci trans->command_groups_size = trans_cfg.command_groups_size; 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci /* At this point both hw and priv are allocated. */ 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci SET_IEEE80211_DEV(priv->hw, priv->trans->dev); 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci iwl_option_config(priv); 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci IWL_DEBUG_INFO(priv, "*** LOAD DRIVER ***\n"); 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci /* bt channel inhibition enabled*/ 13738c2ecf20Sopenharmony_ci priv->bt_ch_announce = true; 13748c2ecf20Sopenharmony_ci IWL_DEBUG_INFO(priv, "BT channel inhibition is %s\n", 13758c2ecf20Sopenharmony_ci (priv->bt_ch_announce) ? "On" : "Off"); 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci /* these spin locks will be used in apm_ops.init and EEPROM access 13788c2ecf20Sopenharmony_ci * we should init now 13798c2ecf20Sopenharmony_ci */ 13808c2ecf20Sopenharmony_ci spin_lock_init(&priv->statistics.lock); 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci /*********************** 13838c2ecf20Sopenharmony_ci * 2. Read REV register 13848c2ecf20Sopenharmony_ci ***********************/ 13858c2ecf20Sopenharmony_ci IWL_INFO(priv, "Detected %s, REV=0x%X\n", 13868c2ecf20Sopenharmony_ci priv->trans->name, priv->trans->hw_rev); 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci if (iwl_trans_start_hw(priv->trans)) 13898c2ecf20Sopenharmony_ci goto out_free_hw; 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci /* Read the EEPROM */ 13928c2ecf20Sopenharmony_ci if (iwl_read_eeprom(priv->trans, &priv->eeprom_blob, 13938c2ecf20Sopenharmony_ci &priv->eeprom_blob_size)) { 13948c2ecf20Sopenharmony_ci IWL_ERR(priv, "Unable to init EEPROM\n"); 13958c2ecf20Sopenharmony_ci goto out_free_hw; 13968c2ecf20Sopenharmony_ci } 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci /* Reset chip to save power until we load uCode during "up". */ 13998c2ecf20Sopenharmony_ci iwl_trans_stop_device(priv->trans); 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci priv->nvm_data = iwl_parse_eeprom_data(priv->trans, priv->cfg, 14028c2ecf20Sopenharmony_ci priv->eeprom_blob, 14038c2ecf20Sopenharmony_ci priv->eeprom_blob_size); 14048c2ecf20Sopenharmony_ci if (!priv->nvm_data) 14058c2ecf20Sopenharmony_ci goto out_free_eeprom_blob; 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci if (iwl_nvm_check_version(priv->nvm_data, priv->trans)) 14088c2ecf20Sopenharmony_ci goto out_free_eeprom; 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci if (iwl_eeprom_init_hw_params(priv)) 14118c2ecf20Sopenharmony_ci goto out_free_eeprom; 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci /* extract MAC Address */ 14148c2ecf20Sopenharmony_ci memcpy(priv->addresses[0].addr, priv->nvm_data->hw_addr, ETH_ALEN); 14158c2ecf20Sopenharmony_ci IWL_DEBUG_INFO(priv, "MAC address: %pM\n", priv->addresses[0].addr); 14168c2ecf20Sopenharmony_ci priv->hw->wiphy->addresses = priv->addresses; 14178c2ecf20Sopenharmony_ci priv->hw->wiphy->n_addresses = 1; 14188c2ecf20Sopenharmony_ci num_mac = priv->nvm_data->n_hw_addrs; 14198c2ecf20Sopenharmony_ci if (num_mac > 1) { 14208c2ecf20Sopenharmony_ci memcpy(priv->addresses[1].addr, priv->addresses[0].addr, 14218c2ecf20Sopenharmony_ci ETH_ALEN); 14228c2ecf20Sopenharmony_ci priv->addresses[1].addr[5]++; 14238c2ecf20Sopenharmony_ci priv->hw->wiphy->n_addresses++; 14248c2ecf20Sopenharmony_ci } 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci /************************ 14278c2ecf20Sopenharmony_ci * 4. Setup HW constants 14288c2ecf20Sopenharmony_ci ************************/ 14298c2ecf20Sopenharmony_ci iwl_set_hw_params(priv); 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci if (!(priv->nvm_data->sku_cap_ipan_enable)) { 14328c2ecf20Sopenharmony_ci IWL_DEBUG_INFO(priv, "Your EEPROM disabled PAN\n"); 14338c2ecf20Sopenharmony_ci ucode_flags &= ~IWL_UCODE_TLV_FLAGS_PAN; 14348c2ecf20Sopenharmony_ci /* 14358c2ecf20Sopenharmony_ci * if not PAN, then don't support P2P -- might be a uCode 14368c2ecf20Sopenharmony_ci * packaging bug or due to the eeprom check above 14378c2ecf20Sopenharmony_ci */ 14388c2ecf20Sopenharmony_ci priv->sta_key_max_num = STA_KEY_MAX_NUM; 14398c2ecf20Sopenharmony_ci trans_cfg.cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM; 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci /* Configure transport layer again*/ 14428c2ecf20Sopenharmony_ci iwl_trans_configure(priv->trans, &trans_cfg); 14438c2ecf20Sopenharmony_ci } 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ci /******************* 14468c2ecf20Sopenharmony_ci * 5. Setup priv 14478c2ecf20Sopenharmony_ci *******************/ 14488c2ecf20Sopenharmony_ci for (i = 0; i < IWL_MAX_HW_QUEUES; i++) { 14498c2ecf20Sopenharmony_ci priv->queue_to_mac80211[i] = IWL_INVALID_MAC80211_QUEUE; 14508c2ecf20Sopenharmony_ci if (i < IWLAGN_FIRST_AMPDU_QUEUE && 14518c2ecf20Sopenharmony_ci i != IWL_DEFAULT_CMD_QUEUE_NUM && 14528c2ecf20Sopenharmony_ci i != IWL_IPAN_CMD_QUEUE_NUM) 14538c2ecf20Sopenharmony_ci priv->queue_to_mac80211[i] = i; 14548c2ecf20Sopenharmony_ci atomic_set(&priv->queue_stop_count[i], 0); 14558c2ecf20Sopenharmony_ci } 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci if (iwl_init_drv(priv)) 14588c2ecf20Sopenharmony_ci goto out_free_eeprom; 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci /* At this point both hw and priv are initialized. */ 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci /******************** 14638c2ecf20Sopenharmony_ci * 6. Setup services 14648c2ecf20Sopenharmony_ci ********************/ 14658c2ecf20Sopenharmony_ci iwl_setup_deferred_work(priv); 14668c2ecf20Sopenharmony_ci iwl_setup_rx_handlers(priv); 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci iwl_power_initialize(priv); 14698c2ecf20Sopenharmony_ci iwl_tt_initialize(priv); 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci snprintf(priv->hw->wiphy->fw_version, 14728c2ecf20Sopenharmony_ci sizeof(priv->hw->wiphy->fw_version), 14738c2ecf20Sopenharmony_ci "%s", fw->fw_version); 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci priv->new_scan_threshold_behaviour = 14768c2ecf20Sopenharmony_ci !!(ucode_flags & IWL_UCODE_TLV_FLAGS_NEWSCAN); 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci priv->phy_calib_chain_noise_reset_cmd = 14798c2ecf20Sopenharmony_ci fw->ucode_capa.standard_phy_calibration_size; 14808c2ecf20Sopenharmony_ci priv->phy_calib_chain_noise_gain_cmd = 14818c2ecf20Sopenharmony_ci fw->ucode_capa.standard_phy_calibration_size + 1; 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci /* initialize all valid contexts */ 14848c2ecf20Sopenharmony_ci iwl_init_context(priv, ucode_flags); 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci /************************************************** 14878c2ecf20Sopenharmony_ci * This is still part of probe() in a sense... 14888c2ecf20Sopenharmony_ci * 14898c2ecf20Sopenharmony_ci * 7. Setup and register with mac80211 and debugfs 14908c2ecf20Sopenharmony_ci **************************************************/ 14918c2ecf20Sopenharmony_ci if (iwlagn_mac_setup_register(priv, &fw->ucode_capa)) 14928c2ecf20Sopenharmony_ci goto out_destroy_workqueue; 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci iwl_dbgfs_register(priv, dbgfs_dir); 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci return op_mode; 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ciout_destroy_workqueue: 14998c2ecf20Sopenharmony_ci iwl_tt_exit(priv); 15008c2ecf20Sopenharmony_ci iwl_cancel_deferred_work(priv); 15018c2ecf20Sopenharmony_ci destroy_workqueue(priv->workqueue); 15028c2ecf20Sopenharmony_ci priv->workqueue = NULL; 15038c2ecf20Sopenharmony_ci iwl_uninit_drv(priv); 15048c2ecf20Sopenharmony_ciout_free_eeprom_blob: 15058c2ecf20Sopenharmony_ci kfree(priv->eeprom_blob); 15068c2ecf20Sopenharmony_ciout_free_eeprom: 15078c2ecf20Sopenharmony_ci kfree(priv->nvm_data); 15088c2ecf20Sopenharmony_ciout_free_hw: 15098c2ecf20Sopenharmony_ci ieee80211_free_hw(priv->hw); 15108c2ecf20Sopenharmony_ciout: 15118c2ecf20Sopenharmony_ci op_mode = NULL; 15128c2ecf20Sopenharmony_ci return op_mode; 15138c2ecf20Sopenharmony_ci} 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_cistatic void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode) 15168c2ecf20Sopenharmony_ci{ 15178c2ecf20Sopenharmony_ci struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci IWL_DEBUG_INFO(priv, "*** UNLOAD DRIVER ***\n"); 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci iwlagn_mac_unregister(priv); 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci iwl_tt_exit(priv); 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci kfree(priv->eeprom_blob); 15268c2ecf20Sopenharmony_ci kfree(priv->nvm_data); 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_ci /*netif_stop_queue(dev); */ 15298c2ecf20Sopenharmony_ci flush_workqueue(priv->workqueue); 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci /* ieee80211_unregister_hw calls iwlagn_mac_stop, which flushes 15328c2ecf20Sopenharmony_ci * priv->workqueue... so we can't take down the workqueue 15338c2ecf20Sopenharmony_ci * until now... */ 15348c2ecf20Sopenharmony_ci destroy_workqueue(priv->workqueue); 15358c2ecf20Sopenharmony_ci priv->workqueue = NULL; 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci iwl_uninit_drv(priv); 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci dev_kfree_skb(priv->beacon_skb); 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_ci iwl_trans_op_mode_leave(priv->trans); 15428c2ecf20Sopenharmony_ci ieee80211_free_hw(priv->hw); 15438c2ecf20Sopenharmony_ci} 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_cistatic const char * const desc_lookup_text[] = { 15468c2ecf20Sopenharmony_ci "OK", 15478c2ecf20Sopenharmony_ci "FAIL", 15488c2ecf20Sopenharmony_ci "BAD_PARAM", 15498c2ecf20Sopenharmony_ci "BAD_CHECKSUM", 15508c2ecf20Sopenharmony_ci "NMI_INTERRUPT_WDG", 15518c2ecf20Sopenharmony_ci "SYSASSERT", 15528c2ecf20Sopenharmony_ci "FATAL_ERROR", 15538c2ecf20Sopenharmony_ci "BAD_COMMAND", 15548c2ecf20Sopenharmony_ci "HW_ERROR_TUNE_LOCK", 15558c2ecf20Sopenharmony_ci "HW_ERROR_TEMPERATURE", 15568c2ecf20Sopenharmony_ci "ILLEGAL_CHAN_FREQ", 15578c2ecf20Sopenharmony_ci "VCC_NOT_STABLE", 15588c2ecf20Sopenharmony_ci "FH_ERROR", 15598c2ecf20Sopenharmony_ci "NMI_INTERRUPT_HOST", 15608c2ecf20Sopenharmony_ci "NMI_INTERRUPT_ACTION_PT", 15618c2ecf20Sopenharmony_ci "NMI_INTERRUPT_UNKNOWN", 15628c2ecf20Sopenharmony_ci "UCODE_VERSION_MISMATCH", 15638c2ecf20Sopenharmony_ci "HW_ERROR_ABS_LOCK", 15648c2ecf20Sopenharmony_ci "HW_ERROR_CAL_LOCK_FAIL", 15658c2ecf20Sopenharmony_ci "NMI_INTERRUPT_INST_ACTION_PT", 15668c2ecf20Sopenharmony_ci "NMI_INTERRUPT_DATA_ACTION_PT", 15678c2ecf20Sopenharmony_ci "NMI_TRM_HW_ER", 15688c2ecf20Sopenharmony_ci "NMI_INTERRUPT_TRM", 15698c2ecf20Sopenharmony_ci "NMI_INTERRUPT_BREAK_POINT", 15708c2ecf20Sopenharmony_ci "DEBUG_0", 15718c2ecf20Sopenharmony_ci "DEBUG_1", 15728c2ecf20Sopenharmony_ci "DEBUG_2", 15738c2ecf20Sopenharmony_ci "DEBUG_3", 15748c2ecf20Sopenharmony_ci}; 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_cistatic struct { char *name; u8 num; } advanced_lookup[] = { 15778c2ecf20Sopenharmony_ci { "NMI_INTERRUPT_WDG", 0x34 }, 15788c2ecf20Sopenharmony_ci { "SYSASSERT", 0x35 }, 15798c2ecf20Sopenharmony_ci { "UCODE_VERSION_MISMATCH", 0x37 }, 15808c2ecf20Sopenharmony_ci { "BAD_COMMAND", 0x38 }, 15818c2ecf20Sopenharmony_ci { "NMI_INTERRUPT_DATA_ACTION_PT", 0x3C }, 15828c2ecf20Sopenharmony_ci { "FATAL_ERROR", 0x3D }, 15838c2ecf20Sopenharmony_ci { "NMI_TRM_HW_ERR", 0x46 }, 15848c2ecf20Sopenharmony_ci { "NMI_INTERRUPT_TRM", 0x4C }, 15858c2ecf20Sopenharmony_ci { "NMI_INTERRUPT_BREAK_POINT", 0x54 }, 15868c2ecf20Sopenharmony_ci { "NMI_INTERRUPT_WDG_RXF_FULL", 0x5C }, 15878c2ecf20Sopenharmony_ci { "NMI_INTERRUPT_WDG_NO_RBD_RXF_FULL", 0x64 }, 15888c2ecf20Sopenharmony_ci { "NMI_INTERRUPT_HOST", 0x66 }, 15898c2ecf20Sopenharmony_ci { "NMI_INTERRUPT_ACTION_PT", 0x7C }, 15908c2ecf20Sopenharmony_ci { "NMI_INTERRUPT_UNKNOWN", 0x84 }, 15918c2ecf20Sopenharmony_ci { "NMI_INTERRUPT_INST_ACTION_PT", 0x86 }, 15928c2ecf20Sopenharmony_ci { "ADVANCED_SYSASSERT", 0 }, 15938c2ecf20Sopenharmony_ci}; 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_cistatic const char *desc_lookup(u32 num) 15968c2ecf20Sopenharmony_ci{ 15978c2ecf20Sopenharmony_ci int i; 15988c2ecf20Sopenharmony_ci int max = ARRAY_SIZE(desc_lookup_text); 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci if (num < max) 16018c2ecf20Sopenharmony_ci return desc_lookup_text[num]; 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci max = ARRAY_SIZE(advanced_lookup) - 1; 16048c2ecf20Sopenharmony_ci for (i = 0; i < max; i++) { 16058c2ecf20Sopenharmony_ci if (advanced_lookup[i].num == num) 16068c2ecf20Sopenharmony_ci break; 16078c2ecf20Sopenharmony_ci } 16088c2ecf20Sopenharmony_ci return advanced_lookup[i].name; 16098c2ecf20Sopenharmony_ci} 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci#define ERROR_START_OFFSET (1 * sizeof(u32)) 16128c2ecf20Sopenharmony_ci#define ERROR_ELEM_SIZE (7 * sizeof(u32)) 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_cistatic void iwl_dump_nic_error_log(struct iwl_priv *priv) 16158c2ecf20Sopenharmony_ci{ 16168c2ecf20Sopenharmony_ci struct iwl_trans *trans = priv->trans; 16178c2ecf20Sopenharmony_ci u32 base; 16188c2ecf20Sopenharmony_ci struct iwl_error_event_table table; 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci base = priv->device_pointers.error_event_table; 16218c2ecf20Sopenharmony_ci if (priv->cur_ucode == IWL_UCODE_INIT) { 16228c2ecf20Sopenharmony_ci if (!base) 16238c2ecf20Sopenharmony_ci base = priv->fw->init_errlog_ptr; 16248c2ecf20Sopenharmony_ci } else { 16258c2ecf20Sopenharmony_ci if (!base) 16268c2ecf20Sopenharmony_ci base = priv->fw->inst_errlog_ptr; 16278c2ecf20Sopenharmony_ci } 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_ci if (!iwlagn_hw_valid_rtc_data_addr(base)) { 16308c2ecf20Sopenharmony_ci IWL_ERR(priv, 16318c2ecf20Sopenharmony_ci "Not valid error log pointer 0x%08X for %s uCode\n", 16328c2ecf20Sopenharmony_ci base, 16338c2ecf20Sopenharmony_ci (priv->cur_ucode == IWL_UCODE_INIT) 16348c2ecf20Sopenharmony_ci ? "Init" : "RT"); 16358c2ecf20Sopenharmony_ci return; 16368c2ecf20Sopenharmony_ci } 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci /*TODO: Update dbgfs with ISR error stats obtained below */ 16398c2ecf20Sopenharmony_ci iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table)); 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { 16428c2ecf20Sopenharmony_ci IWL_ERR(trans, "Start IWL Error Log Dump:\n"); 16438c2ecf20Sopenharmony_ci IWL_ERR(trans, "Status: 0x%08lX, count: %d\n", 16448c2ecf20Sopenharmony_ci priv->status, table.valid); 16458c2ecf20Sopenharmony_ci } 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci IWL_ERR(priv, "0x%08X | %-28s\n", table.error_id, 16488c2ecf20Sopenharmony_ci desc_lookup(table.error_id)); 16498c2ecf20Sopenharmony_ci IWL_ERR(priv, "0x%08X | uPc\n", table.pc); 16508c2ecf20Sopenharmony_ci IWL_ERR(priv, "0x%08X | branchlink1\n", table.blink1); 16518c2ecf20Sopenharmony_ci IWL_ERR(priv, "0x%08X | branchlink2\n", table.blink2); 16528c2ecf20Sopenharmony_ci IWL_ERR(priv, "0x%08X | interruptlink1\n", table.ilink1); 16538c2ecf20Sopenharmony_ci IWL_ERR(priv, "0x%08X | interruptlink2\n", table.ilink2); 16548c2ecf20Sopenharmony_ci IWL_ERR(priv, "0x%08X | data1\n", table.data1); 16558c2ecf20Sopenharmony_ci IWL_ERR(priv, "0x%08X | data2\n", table.data2); 16568c2ecf20Sopenharmony_ci IWL_ERR(priv, "0x%08X | line\n", table.line); 16578c2ecf20Sopenharmony_ci IWL_ERR(priv, "0x%08X | beacon time\n", table.bcon_time); 16588c2ecf20Sopenharmony_ci IWL_ERR(priv, "0x%08X | tsf low\n", table.tsf_low); 16598c2ecf20Sopenharmony_ci IWL_ERR(priv, "0x%08X | tsf hi\n", table.tsf_hi); 16608c2ecf20Sopenharmony_ci IWL_ERR(priv, "0x%08X | time gp1\n", table.gp1); 16618c2ecf20Sopenharmony_ci IWL_ERR(priv, "0x%08X | time gp2\n", table.gp2); 16628c2ecf20Sopenharmony_ci IWL_ERR(priv, "0x%08X | time gp3\n", table.gp3); 16638c2ecf20Sopenharmony_ci IWL_ERR(priv, "0x%08X | uCode version\n", table.ucode_ver); 16648c2ecf20Sopenharmony_ci IWL_ERR(priv, "0x%08X | hw version\n", table.hw_ver); 16658c2ecf20Sopenharmony_ci IWL_ERR(priv, "0x%08X | board version\n", table.brd_ver); 16668c2ecf20Sopenharmony_ci IWL_ERR(priv, "0x%08X | hcmd\n", table.hcmd); 16678c2ecf20Sopenharmony_ci IWL_ERR(priv, "0x%08X | isr0\n", table.isr0); 16688c2ecf20Sopenharmony_ci IWL_ERR(priv, "0x%08X | isr1\n", table.isr1); 16698c2ecf20Sopenharmony_ci IWL_ERR(priv, "0x%08X | isr2\n", table.isr2); 16708c2ecf20Sopenharmony_ci IWL_ERR(priv, "0x%08X | isr3\n", table.isr3); 16718c2ecf20Sopenharmony_ci IWL_ERR(priv, "0x%08X | isr4\n", table.isr4); 16728c2ecf20Sopenharmony_ci IWL_ERR(priv, "0x%08X | isr_pref\n", table.isr_pref); 16738c2ecf20Sopenharmony_ci IWL_ERR(priv, "0x%08X | wait_event\n", table.wait_event); 16748c2ecf20Sopenharmony_ci IWL_ERR(priv, "0x%08X | l2p_control\n", table.l2p_control); 16758c2ecf20Sopenharmony_ci IWL_ERR(priv, "0x%08X | l2p_duration\n", table.l2p_duration); 16768c2ecf20Sopenharmony_ci IWL_ERR(priv, "0x%08X | l2p_mhvalid\n", table.l2p_mhvalid); 16778c2ecf20Sopenharmony_ci IWL_ERR(priv, "0x%08X | l2p_addr_match\n", table.l2p_addr_match); 16788c2ecf20Sopenharmony_ci IWL_ERR(priv, "0x%08X | lmpm_pmg_sel\n", table.lmpm_pmg_sel); 16798c2ecf20Sopenharmony_ci IWL_ERR(priv, "0x%08X | timestamp\n", table.u_timestamp); 16808c2ecf20Sopenharmony_ci IWL_ERR(priv, "0x%08X | flow_handler\n", table.flow_handler); 16818c2ecf20Sopenharmony_ci} 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_ci#define EVENT_START_OFFSET (4 * sizeof(u32)) 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci/* 16868c2ecf20Sopenharmony_ci * iwl_print_event_log - Dump error event log to syslog 16878c2ecf20Sopenharmony_ci */ 16888c2ecf20Sopenharmony_cistatic int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, 16898c2ecf20Sopenharmony_ci u32 num_events, u32 mode, 16908c2ecf20Sopenharmony_ci int pos, char **buf, size_t bufsz) 16918c2ecf20Sopenharmony_ci{ 16928c2ecf20Sopenharmony_ci u32 i; 16938c2ecf20Sopenharmony_ci u32 base; /* SRAM byte address of event log header */ 16948c2ecf20Sopenharmony_ci u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */ 16958c2ecf20Sopenharmony_ci u32 ptr; /* SRAM byte address of log data */ 16968c2ecf20Sopenharmony_ci u32 ev, time, data; /* event log data */ 16978c2ecf20Sopenharmony_ci unsigned long reg_flags; 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_ci struct iwl_trans *trans = priv->trans; 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_ci if (num_events == 0) 17028c2ecf20Sopenharmony_ci return pos; 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_ci base = priv->device_pointers.log_event_table; 17058c2ecf20Sopenharmony_ci if (priv->cur_ucode == IWL_UCODE_INIT) { 17068c2ecf20Sopenharmony_ci if (!base) 17078c2ecf20Sopenharmony_ci base = priv->fw->init_evtlog_ptr; 17088c2ecf20Sopenharmony_ci } else { 17098c2ecf20Sopenharmony_ci if (!base) 17108c2ecf20Sopenharmony_ci base = priv->fw->inst_evtlog_ptr; 17118c2ecf20Sopenharmony_ci } 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_ci if (mode == 0) 17148c2ecf20Sopenharmony_ci event_size = 2 * sizeof(u32); 17158c2ecf20Sopenharmony_ci else 17168c2ecf20Sopenharmony_ci event_size = 3 * sizeof(u32); 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci ptr = base + EVENT_START_OFFSET + (start_idx * event_size); 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_ci /* Make sure device is powered up for SRAM reads */ 17218c2ecf20Sopenharmony_ci if (!iwl_trans_grab_nic_access(trans, ®_flags)) 17228c2ecf20Sopenharmony_ci return pos; 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci /* Set starting address; reads will auto-increment */ 17258c2ecf20Sopenharmony_ci iwl_write32(trans, HBUS_TARG_MEM_RADDR, ptr); 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_ci /* "time" is actually "data" for mode 0 (no timestamp). 17288c2ecf20Sopenharmony_ci * place event id # at far right for easier visual parsing. */ 17298c2ecf20Sopenharmony_ci for (i = 0; i < num_events; i++) { 17308c2ecf20Sopenharmony_ci ev = iwl_read32(trans, HBUS_TARG_MEM_RDAT); 17318c2ecf20Sopenharmony_ci time = iwl_read32(trans, HBUS_TARG_MEM_RDAT); 17328c2ecf20Sopenharmony_ci if (mode == 0) { 17338c2ecf20Sopenharmony_ci /* data, ev */ 17348c2ecf20Sopenharmony_ci if (bufsz) { 17358c2ecf20Sopenharmony_ci pos += scnprintf(*buf + pos, bufsz - pos, 17368c2ecf20Sopenharmony_ci "EVT_LOG:0x%08x:%04u\n", 17378c2ecf20Sopenharmony_ci time, ev); 17388c2ecf20Sopenharmony_ci } else { 17398c2ecf20Sopenharmony_ci trace_iwlwifi_dev_ucode_event(trans->dev, 0, 17408c2ecf20Sopenharmony_ci time, ev); 17418c2ecf20Sopenharmony_ci IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n", 17428c2ecf20Sopenharmony_ci time, ev); 17438c2ecf20Sopenharmony_ci } 17448c2ecf20Sopenharmony_ci } else { 17458c2ecf20Sopenharmony_ci data = iwl_read32(trans, HBUS_TARG_MEM_RDAT); 17468c2ecf20Sopenharmony_ci if (bufsz) { 17478c2ecf20Sopenharmony_ci pos += scnprintf(*buf + pos, bufsz - pos, 17488c2ecf20Sopenharmony_ci "EVT_LOGT:%010u:0x%08x:%04u\n", 17498c2ecf20Sopenharmony_ci time, data, ev); 17508c2ecf20Sopenharmony_ci } else { 17518c2ecf20Sopenharmony_ci IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n", 17528c2ecf20Sopenharmony_ci time, data, ev); 17538c2ecf20Sopenharmony_ci trace_iwlwifi_dev_ucode_event(trans->dev, time, 17548c2ecf20Sopenharmony_ci data, ev); 17558c2ecf20Sopenharmony_ci } 17568c2ecf20Sopenharmony_ci } 17578c2ecf20Sopenharmony_ci } 17588c2ecf20Sopenharmony_ci 17598c2ecf20Sopenharmony_ci /* Allow device to power down */ 17608c2ecf20Sopenharmony_ci iwl_trans_release_nic_access(trans, ®_flags); 17618c2ecf20Sopenharmony_ci return pos; 17628c2ecf20Sopenharmony_ci} 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_ci/* 17658c2ecf20Sopenharmony_ci * iwl_print_last_event_logs - Dump the newest # of event log to syslog 17668c2ecf20Sopenharmony_ci */ 17678c2ecf20Sopenharmony_cistatic int iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity, 17688c2ecf20Sopenharmony_ci u32 num_wraps, u32 next_entry, 17698c2ecf20Sopenharmony_ci u32 size, u32 mode, 17708c2ecf20Sopenharmony_ci int pos, char **buf, size_t bufsz) 17718c2ecf20Sopenharmony_ci{ 17728c2ecf20Sopenharmony_ci /* 17738c2ecf20Sopenharmony_ci * display the newest DEFAULT_LOG_ENTRIES entries 17748c2ecf20Sopenharmony_ci * i.e the entries just before the next ont that uCode would fill. 17758c2ecf20Sopenharmony_ci */ 17768c2ecf20Sopenharmony_ci if (num_wraps) { 17778c2ecf20Sopenharmony_ci if (next_entry < size) { 17788c2ecf20Sopenharmony_ci pos = iwl_print_event_log(priv, 17798c2ecf20Sopenharmony_ci capacity - (size - next_entry), 17808c2ecf20Sopenharmony_ci size - next_entry, mode, 17818c2ecf20Sopenharmony_ci pos, buf, bufsz); 17828c2ecf20Sopenharmony_ci pos = iwl_print_event_log(priv, 0, 17838c2ecf20Sopenharmony_ci next_entry, mode, 17848c2ecf20Sopenharmony_ci pos, buf, bufsz); 17858c2ecf20Sopenharmony_ci } else 17868c2ecf20Sopenharmony_ci pos = iwl_print_event_log(priv, next_entry - size, 17878c2ecf20Sopenharmony_ci size, mode, pos, buf, bufsz); 17888c2ecf20Sopenharmony_ci } else { 17898c2ecf20Sopenharmony_ci if (next_entry < size) { 17908c2ecf20Sopenharmony_ci pos = iwl_print_event_log(priv, 0, next_entry, 17918c2ecf20Sopenharmony_ci mode, pos, buf, bufsz); 17928c2ecf20Sopenharmony_ci } else { 17938c2ecf20Sopenharmony_ci pos = iwl_print_event_log(priv, next_entry - size, 17948c2ecf20Sopenharmony_ci size, mode, pos, buf, bufsz); 17958c2ecf20Sopenharmony_ci } 17968c2ecf20Sopenharmony_ci } 17978c2ecf20Sopenharmony_ci return pos; 17988c2ecf20Sopenharmony_ci} 17998c2ecf20Sopenharmony_ci 18008c2ecf20Sopenharmony_ci#define DEFAULT_DUMP_EVENT_LOG_ENTRIES (20) 18018c2ecf20Sopenharmony_ci 18028c2ecf20Sopenharmony_ciint iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log, 18038c2ecf20Sopenharmony_ci char **buf) 18048c2ecf20Sopenharmony_ci{ 18058c2ecf20Sopenharmony_ci u32 base; /* SRAM byte address of event log header */ 18068c2ecf20Sopenharmony_ci u32 capacity; /* event log capacity in # entries */ 18078c2ecf20Sopenharmony_ci u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */ 18088c2ecf20Sopenharmony_ci u32 num_wraps; /* # times uCode wrapped to top of log */ 18098c2ecf20Sopenharmony_ci u32 next_entry; /* index of next entry to be written by uCode */ 18108c2ecf20Sopenharmony_ci u32 size; /* # entries that we'll print */ 18118c2ecf20Sopenharmony_ci u32 logsize; 18128c2ecf20Sopenharmony_ci int pos = 0; 18138c2ecf20Sopenharmony_ci size_t bufsz = 0; 18148c2ecf20Sopenharmony_ci struct iwl_trans *trans = priv->trans; 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci base = priv->device_pointers.log_event_table; 18178c2ecf20Sopenharmony_ci if (priv->cur_ucode == IWL_UCODE_INIT) { 18188c2ecf20Sopenharmony_ci logsize = priv->fw->init_evtlog_size; 18198c2ecf20Sopenharmony_ci if (!base) 18208c2ecf20Sopenharmony_ci base = priv->fw->init_evtlog_ptr; 18218c2ecf20Sopenharmony_ci } else { 18228c2ecf20Sopenharmony_ci logsize = priv->fw->inst_evtlog_size; 18238c2ecf20Sopenharmony_ci if (!base) 18248c2ecf20Sopenharmony_ci base = priv->fw->inst_evtlog_ptr; 18258c2ecf20Sopenharmony_ci } 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_ci if (!iwlagn_hw_valid_rtc_data_addr(base)) { 18288c2ecf20Sopenharmony_ci IWL_ERR(priv, 18298c2ecf20Sopenharmony_ci "Invalid event log pointer 0x%08X for %s uCode\n", 18308c2ecf20Sopenharmony_ci base, 18318c2ecf20Sopenharmony_ci (priv->cur_ucode == IWL_UCODE_INIT) 18328c2ecf20Sopenharmony_ci ? "Init" : "RT"); 18338c2ecf20Sopenharmony_ci return -EINVAL; 18348c2ecf20Sopenharmony_ci } 18358c2ecf20Sopenharmony_ci 18368c2ecf20Sopenharmony_ci /* event log header */ 18378c2ecf20Sopenharmony_ci capacity = iwl_trans_read_mem32(trans, base); 18388c2ecf20Sopenharmony_ci mode = iwl_trans_read_mem32(trans, base + (1 * sizeof(u32))); 18398c2ecf20Sopenharmony_ci num_wraps = iwl_trans_read_mem32(trans, base + (2 * sizeof(u32))); 18408c2ecf20Sopenharmony_ci next_entry = iwl_trans_read_mem32(trans, base + (3 * sizeof(u32))); 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_ci if (capacity > logsize) { 18438c2ecf20Sopenharmony_ci IWL_ERR(priv, "Log capacity %d is bogus, limit to %d " 18448c2ecf20Sopenharmony_ci "entries\n", capacity, logsize); 18458c2ecf20Sopenharmony_ci capacity = logsize; 18468c2ecf20Sopenharmony_ci } 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_ci if (next_entry > logsize) { 18498c2ecf20Sopenharmony_ci IWL_ERR(priv, "Log write index %d is bogus, limit to %d\n", 18508c2ecf20Sopenharmony_ci next_entry, logsize); 18518c2ecf20Sopenharmony_ci next_entry = logsize; 18528c2ecf20Sopenharmony_ci } 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_ci size = num_wraps ? capacity : next_entry; 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_ci /* bail out if nothing in log */ 18578c2ecf20Sopenharmony_ci if (size == 0) { 18588c2ecf20Sopenharmony_ci IWL_ERR(trans, "Start IWL Event Log Dump: nothing in log\n"); 18598c2ecf20Sopenharmony_ci return pos; 18608c2ecf20Sopenharmony_ci } 18618c2ecf20Sopenharmony_ci 18628c2ecf20Sopenharmony_ci if (!(iwl_have_debug_level(IWL_DL_FW)) && !full_log) 18638c2ecf20Sopenharmony_ci size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES) 18648c2ecf20Sopenharmony_ci ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size; 18658c2ecf20Sopenharmony_ci IWL_ERR(priv, "Start IWL Event Log Dump: display last %u entries\n", 18668c2ecf20Sopenharmony_ci size); 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci#ifdef CONFIG_IWLWIFI_DEBUG 18698c2ecf20Sopenharmony_ci if (buf) { 18708c2ecf20Sopenharmony_ci if (full_log) 18718c2ecf20Sopenharmony_ci bufsz = capacity * 48; 18728c2ecf20Sopenharmony_ci else 18738c2ecf20Sopenharmony_ci bufsz = size * 48; 18748c2ecf20Sopenharmony_ci *buf = kmalloc(bufsz, GFP_KERNEL); 18758c2ecf20Sopenharmony_ci if (!*buf) 18768c2ecf20Sopenharmony_ci return -ENOMEM; 18778c2ecf20Sopenharmony_ci } 18788c2ecf20Sopenharmony_ci if (iwl_have_debug_level(IWL_DL_FW) || full_log) { 18798c2ecf20Sopenharmony_ci /* 18808c2ecf20Sopenharmony_ci * if uCode has wrapped back to top of log, 18818c2ecf20Sopenharmony_ci * start at the oldest entry, 18828c2ecf20Sopenharmony_ci * i.e the next one that uCode would fill. 18838c2ecf20Sopenharmony_ci */ 18848c2ecf20Sopenharmony_ci if (num_wraps) 18858c2ecf20Sopenharmony_ci pos = iwl_print_event_log(priv, next_entry, 18868c2ecf20Sopenharmony_ci capacity - next_entry, mode, 18878c2ecf20Sopenharmony_ci pos, buf, bufsz); 18888c2ecf20Sopenharmony_ci /* (then/else) start at top of log */ 18898c2ecf20Sopenharmony_ci pos = iwl_print_event_log(priv, 0, 18908c2ecf20Sopenharmony_ci next_entry, mode, pos, buf, bufsz); 18918c2ecf20Sopenharmony_ci } else 18928c2ecf20Sopenharmony_ci pos = iwl_print_last_event_logs(priv, capacity, num_wraps, 18938c2ecf20Sopenharmony_ci next_entry, size, mode, 18948c2ecf20Sopenharmony_ci pos, buf, bufsz); 18958c2ecf20Sopenharmony_ci#else 18968c2ecf20Sopenharmony_ci pos = iwl_print_last_event_logs(priv, capacity, num_wraps, 18978c2ecf20Sopenharmony_ci next_entry, size, mode, 18988c2ecf20Sopenharmony_ci pos, buf, bufsz); 18998c2ecf20Sopenharmony_ci#endif 19008c2ecf20Sopenharmony_ci return pos; 19018c2ecf20Sopenharmony_ci} 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_cistatic void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand) 19048c2ecf20Sopenharmony_ci{ 19058c2ecf20Sopenharmony_ci unsigned int reload_msec; 19068c2ecf20Sopenharmony_ci unsigned long reload_jiffies; 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_ci if (iwl_have_debug_level(IWL_DL_FW)) 19098c2ecf20Sopenharmony_ci iwl_print_rx_config_cmd(priv, IWL_RXON_CTX_BSS); 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_ci /* uCode is no longer loaded. */ 19128c2ecf20Sopenharmony_ci priv->ucode_loaded = false; 19138c2ecf20Sopenharmony_ci 19148c2ecf20Sopenharmony_ci /* Set the FW error flag -- cleared on iwl_down */ 19158c2ecf20Sopenharmony_ci set_bit(STATUS_FW_ERROR, &priv->status); 19168c2ecf20Sopenharmony_ci 19178c2ecf20Sopenharmony_ci iwl_abort_notification_waits(&priv->notif_wait); 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_ci /* Keep the restart process from trying to send host 19208c2ecf20Sopenharmony_ci * commands by clearing the ready bit */ 19218c2ecf20Sopenharmony_ci clear_bit(STATUS_READY, &priv->status); 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_ci if (!ondemand) { 19248c2ecf20Sopenharmony_ci /* 19258c2ecf20Sopenharmony_ci * If firmware keep reloading, then it indicate something 19268c2ecf20Sopenharmony_ci * serious wrong and firmware having problem to recover 19278c2ecf20Sopenharmony_ci * from it. Instead of keep trying which will fill the syslog 19288c2ecf20Sopenharmony_ci * and hang the system, let's just stop it 19298c2ecf20Sopenharmony_ci */ 19308c2ecf20Sopenharmony_ci reload_jiffies = jiffies; 19318c2ecf20Sopenharmony_ci reload_msec = jiffies_to_msecs((long) reload_jiffies - 19328c2ecf20Sopenharmony_ci (long) priv->reload_jiffies); 19338c2ecf20Sopenharmony_ci priv->reload_jiffies = reload_jiffies; 19348c2ecf20Sopenharmony_ci if (reload_msec <= IWL_MIN_RELOAD_DURATION) { 19358c2ecf20Sopenharmony_ci priv->reload_count++; 19368c2ecf20Sopenharmony_ci if (priv->reload_count >= IWL_MAX_CONTINUE_RELOAD_CNT) { 19378c2ecf20Sopenharmony_ci IWL_ERR(priv, "BUG_ON, Stop restarting\n"); 19388c2ecf20Sopenharmony_ci return; 19398c2ecf20Sopenharmony_ci } 19408c2ecf20Sopenharmony_ci } else 19418c2ecf20Sopenharmony_ci priv->reload_count = 0; 19428c2ecf20Sopenharmony_ci } 19438c2ecf20Sopenharmony_ci 19448c2ecf20Sopenharmony_ci if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) { 19458c2ecf20Sopenharmony_ci if (iwlwifi_mod_params.fw_restart) { 19468c2ecf20Sopenharmony_ci IWL_DEBUG_FW(priv, 19478c2ecf20Sopenharmony_ci "Restarting adapter due to uCode error.\n"); 19488c2ecf20Sopenharmony_ci queue_work(priv->workqueue, &priv->restart); 19498c2ecf20Sopenharmony_ci } else 19508c2ecf20Sopenharmony_ci IWL_DEBUG_FW(priv, 19518c2ecf20Sopenharmony_ci "Detected FW error, but not restarting\n"); 19528c2ecf20Sopenharmony_ci } 19538c2ecf20Sopenharmony_ci} 19548c2ecf20Sopenharmony_ci 19558c2ecf20Sopenharmony_cistatic void iwl_nic_error(struct iwl_op_mode *op_mode) 19568c2ecf20Sopenharmony_ci{ 19578c2ecf20Sopenharmony_ci struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); 19588c2ecf20Sopenharmony_ci 19598c2ecf20Sopenharmony_ci IWL_ERR(priv, "Loaded firmware version: %s\n", 19608c2ecf20Sopenharmony_ci priv->fw->fw_version); 19618c2ecf20Sopenharmony_ci 19628c2ecf20Sopenharmony_ci iwl_dump_nic_error_log(priv); 19638c2ecf20Sopenharmony_ci iwl_dump_nic_event_log(priv, false, NULL); 19648c2ecf20Sopenharmony_ci 19658c2ecf20Sopenharmony_ci iwlagn_fw_error(priv, false); 19668c2ecf20Sopenharmony_ci} 19678c2ecf20Sopenharmony_ci 19688c2ecf20Sopenharmony_cistatic void iwl_cmd_queue_full(struct iwl_op_mode *op_mode) 19698c2ecf20Sopenharmony_ci{ 19708c2ecf20Sopenharmony_ci struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); 19718c2ecf20Sopenharmony_ci 19728c2ecf20Sopenharmony_ci if (!iwl_check_for_ct_kill(priv)) { 19738c2ecf20Sopenharmony_ci IWL_ERR(priv, "Restarting adapter queue is full\n"); 19748c2ecf20Sopenharmony_ci iwlagn_fw_error(priv, false); 19758c2ecf20Sopenharmony_ci } 19768c2ecf20Sopenharmony_ci} 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_ci#define EEPROM_RF_CONFIG_TYPE_MAX 0x3 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_cistatic void iwl_nic_config(struct iwl_op_mode *op_mode) 19818c2ecf20Sopenharmony_ci{ 19828c2ecf20Sopenharmony_ci struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_ci /* SKU Control */ 19858c2ecf20Sopenharmony_ci iwl_trans_set_bits_mask(priv->trans, CSR_HW_IF_CONFIG_REG, 19868c2ecf20Sopenharmony_ci CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH | 19878c2ecf20Sopenharmony_ci CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP, 19888c2ecf20Sopenharmony_ci (CSR_HW_REV_STEP(priv->trans->hw_rev) << 19898c2ecf20Sopenharmony_ci CSR_HW_IF_CONFIG_REG_POS_MAC_STEP) | 19908c2ecf20Sopenharmony_ci (CSR_HW_REV_DASH(priv->trans->hw_rev) << 19918c2ecf20Sopenharmony_ci CSR_HW_IF_CONFIG_REG_POS_MAC_DASH)); 19928c2ecf20Sopenharmony_ci 19938c2ecf20Sopenharmony_ci /* write radio config values to register */ 19948c2ecf20Sopenharmony_ci if (priv->nvm_data->radio_cfg_type <= EEPROM_RF_CONFIG_TYPE_MAX) { 19958c2ecf20Sopenharmony_ci u32 reg_val = 19968c2ecf20Sopenharmony_ci priv->nvm_data->radio_cfg_type << 19978c2ecf20Sopenharmony_ci CSR_HW_IF_CONFIG_REG_POS_PHY_TYPE | 19988c2ecf20Sopenharmony_ci priv->nvm_data->radio_cfg_step << 19998c2ecf20Sopenharmony_ci CSR_HW_IF_CONFIG_REG_POS_PHY_STEP | 20008c2ecf20Sopenharmony_ci priv->nvm_data->radio_cfg_dash << 20018c2ecf20Sopenharmony_ci CSR_HW_IF_CONFIG_REG_POS_PHY_DASH; 20028c2ecf20Sopenharmony_ci 20038c2ecf20Sopenharmony_ci iwl_trans_set_bits_mask(priv->trans, CSR_HW_IF_CONFIG_REG, 20048c2ecf20Sopenharmony_ci CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE | 20058c2ecf20Sopenharmony_ci CSR_HW_IF_CONFIG_REG_MSK_PHY_STEP | 20068c2ecf20Sopenharmony_ci CSR_HW_IF_CONFIG_REG_MSK_PHY_DASH, 20078c2ecf20Sopenharmony_ci reg_val); 20088c2ecf20Sopenharmony_ci 20098c2ecf20Sopenharmony_ci IWL_INFO(priv, "Radio type=0x%x-0x%x-0x%x\n", 20108c2ecf20Sopenharmony_ci priv->nvm_data->radio_cfg_type, 20118c2ecf20Sopenharmony_ci priv->nvm_data->radio_cfg_step, 20128c2ecf20Sopenharmony_ci priv->nvm_data->radio_cfg_dash); 20138c2ecf20Sopenharmony_ci } else { 20148c2ecf20Sopenharmony_ci WARN_ON(1); 20158c2ecf20Sopenharmony_ci } 20168c2ecf20Sopenharmony_ci 20178c2ecf20Sopenharmony_ci /* set CSR_HW_CONFIG_REG for uCode use */ 20188c2ecf20Sopenharmony_ci iwl_set_bit(priv->trans, CSR_HW_IF_CONFIG_REG, 20198c2ecf20Sopenharmony_ci CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | 20208c2ecf20Sopenharmony_ci CSR_HW_IF_CONFIG_REG_BIT_MAC_SI); 20218c2ecf20Sopenharmony_ci 20228c2ecf20Sopenharmony_ci /* W/A : NIC is stuck in a reset state after Early PCIe power off 20238c2ecf20Sopenharmony_ci * (PCIe power is lost before PERST# is asserted), 20248c2ecf20Sopenharmony_ci * causing ME FW to lose ownership and not being able to obtain it back. 20258c2ecf20Sopenharmony_ci */ 20268c2ecf20Sopenharmony_ci iwl_set_bits_mask_prph(priv->trans, APMG_PS_CTRL_REG, 20278c2ecf20Sopenharmony_ci APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS, 20288c2ecf20Sopenharmony_ci ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS); 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_ci if (priv->lib->nic_config) 20318c2ecf20Sopenharmony_ci priv->lib->nic_config(priv); 20328c2ecf20Sopenharmony_ci} 20338c2ecf20Sopenharmony_ci 20348c2ecf20Sopenharmony_cistatic void iwl_wimax_active(struct iwl_op_mode *op_mode) 20358c2ecf20Sopenharmony_ci{ 20368c2ecf20Sopenharmony_ci struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_ci clear_bit(STATUS_READY, &priv->status); 20398c2ecf20Sopenharmony_ci IWL_ERR(priv, "RF is used by WiMAX\n"); 20408c2ecf20Sopenharmony_ci} 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_cistatic void iwl_stop_sw_queue(struct iwl_op_mode *op_mode, int queue) 20438c2ecf20Sopenharmony_ci{ 20448c2ecf20Sopenharmony_ci struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); 20458c2ecf20Sopenharmony_ci int mq = priv->queue_to_mac80211[queue]; 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(mq == IWL_INVALID_MAC80211_QUEUE)) 20488c2ecf20Sopenharmony_ci return; 20498c2ecf20Sopenharmony_ci 20508c2ecf20Sopenharmony_ci if (atomic_inc_return(&priv->queue_stop_count[mq]) > 1) { 20518c2ecf20Sopenharmony_ci IWL_DEBUG_TX_QUEUES(priv, 20528c2ecf20Sopenharmony_ci "queue %d (mac80211 %d) already stopped\n", 20538c2ecf20Sopenharmony_ci queue, mq); 20548c2ecf20Sopenharmony_ci return; 20558c2ecf20Sopenharmony_ci } 20568c2ecf20Sopenharmony_ci 20578c2ecf20Sopenharmony_ci set_bit(mq, &priv->transport_queue_stop); 20588c2ecf20Sopenharmony_ci ieee80211_stop_queue(priv->hw, mq); 20598c2ecf20Sopenharmony_ci} 20608c2ecf20Sopenharmony_ci 20618c2ecf20Sopenharmony_cistatic void iwl_wake_sw_queue(struct iwl_op_mode *op_mode, int queue) 20628c2ecf20Sopenharmony_ci{ 20638c2ecf20Sopenharmony_ci struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); 20648c2ecf20Sopenharmony_ci int mq = priv->queue_to_mac80211[queue]; 20658c2ecf20Sopenharmony_ci 20668c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(mq == IWL_INVALID_MAC80211_QUEUE)) 20678c2ecf20Sopenharmony_ci return; 20688c2ecf20Sopenharmony_ci 20698c2ecf20Sopenharmony_ci if (atomic_dec_return(&priv->queue_stop_count[mq]) > 0) { 20708c2ecf20Sopenharmony_ci IWL_DEBUG_TX_QUEUES(priv, 20718c2ecf20Sopenharmony_ci "queue %d (mac80211 %d) already awake\n", 20728c2ecf20Sopenharmony_ci queue, mq); 20738c2ecf20Sopenharmony_ci return; 20748c2ecf20Sopenharmony_ci } 20758c2ecf20Sopenharmony_ci 20768c2ecf20Sopenharmony_ci clear_bit(mq, &priv->transport_queue_stop); 20778c2ecf20Sopenharmony_ci 20788c2ecf20Sopenharmony_ci if (!priv->passive_no_rx) 20798c2ecf20Sopenharmony_ci ieee80211_wake_queue(priv->hw, mq); 20808c2ecf20Sopenharmony_ci} 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_civoid iwlagn_lift_passive_no_rx(struct iwl_priv *priv) 20838c2ecf20Sopenharmony_ci{ 20848c2ecf20Sopenharmony_ci int mq; 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_ci if (!priv->passive_no_rx) 20878c2ecf20Sopenharmony_ci return; 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_ci for (mq = 0; mq < IWLAGN_FIRST_AMPDU_QUEUE; mq++) { 20908c2ecf20Sopenharmony_ci if (!test_bit(mq, &priv->transport_queue_stop)) { 20918c2ecf20Sopenharmony_ci IWL_DEBUG_TX_QUEUES(priv, "Wake queue %d\n", mq); 20928c2ecf20Sopenharmony_ci ieee80211_wake_queue(priv->hw, mq); 20938c2ecf20Sopenharmony_ci } else { 20948c2ecf20Sopenharmony_ci IWL_DEBUG_TX_QUEUES(priv, "Don't wake queue %d\n", mq); 20958c2ecf20Sopenharmony_ci } 20968c2ecf20Sopenharmony_ci } 20978c2ecf20Sopenharmony_ci 20988c2ecf20Sopenharmony_ci priv->passive_no_rx = false; 20998c2ecf20Sopenharmony_ci} 21008c2ecf20Sopenharmony_ci 21018c2ecf20Sopenharmony_cistatic void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb) 21028c2ecf20Sopenharmony_ci{ 21038c2ecf20Sopenharmony_ci struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); 21048c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info; 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_ci info = IEEE80211_SKB_CB(skb); 21078c2ecf20Sopenharmony_ci iwl_trans_free_tx_cmd(priv->trans, info->driver_data[1]); 21088c2ecf20Sopenharmony_ci ieee80211_free_txskb(priv->hw, skb); 21098c2ecf20Sopenharmony_ci} 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_cistatic bool iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) 21128c2ecf20Sopenharmony_ci{ 21138c2ecf20Sopenharmony_ci struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); 21148c2ecf20Sopenharmony_ci 21158c2ecf20Sopenharmony_ci if (state) 21168c2ecf20Sopenharmony_ci set_bit(STATUS_RF_KILL_HW, &priv->status); 21178c2ecf20Sopenharmony_ci else 21188c2ecf20Sopenharmony_ci clear_bit(STATUS_RF_KILL_HW, &priv->status); 21198c2ecf20Sopenharmony_ci 21208c2ecf20Sopenharmony_ci wiphy_rfkill_set_hw_state(priv->hw->wiphy, state); 21218c2ecf20Sopenharmony_ci 21228c2ecf20Sopenharmony_ci return false; 21238c2ecf20Sopenharmony_ci} 21248c2ecf20Sopenharmony_ci 21258c2ecf20Sopenharmony_cistatic const struct iwl_op_mode_ops iwl_dvm_ops = { 21268c2ecf20Sopenharmony_ci .start = iwl_op_mode_dvm_start, 21278c2ecf20Sopenharmony_ci .stop = iwl_op_mode_dvm_stop, 21288c2ecf20Sopenharmony_ci .rx = iwl_rx_dispatch, 21298c2ecf20Sopenharmony_ci .queue_full = iwl_stop_sw_queue, 21308c2ecf20Sopenharmony_ci .queue_not_full = iwl_wake_sw_queue, 21318c2ecf20Sopenharmony_ci .hw_rf_kill = iwl_set_hw_rfkill_state, 21328c2ecf20Sopenharmony_ci .free_skb = iwl_free_skb, 21338c2ecf20Sopenharmony_ci .nic_error = iwl_nic_error, 21348c2ecf20Sopenharmony_ci .cmd_queue_full = iwl_cmd_queue_full, 21358c2ecf20Sopenharmony_ci .nic_config = iwl_nic_config, 21368c2ecf20Sopenharmony_ci .wimax_active = iwl_wimax_active, 21378c2ecf20Sopenharmony_ci}; 21388c2ecf20Sopenharmony_ci 21398c2ecf20Sopenharmony_ci/***************************************************************************** 21408c2ecf20Sopenharmony_ci * 21418c2ecf20Sopenharmony_ci * driver and module entry point 21428c2ecf20Sopenharmony_ci * 21438c2ecf20Sopenharmony_ci *****************************************************************************/ 21448c2ecf20Sopenharmony_cistatic int __init iwl_init(void) 21458c2ecf20Sopenharmony_ci{ 21468c2ecf20Sopenharmony_ci 21478c2ecf20Sopenharmony_ci int ret; 21488c2ecf20Sopenharmony_ci 21498c2ecf20Sopenharmony_ci ret = iwlagn_rate_control_register(); 21508c2ecf20Sopenharmony_ci if (ret) { 21518c2ecf20Sopenharmony_ci pr_err("Unable to register rate control algorithm: %d\n", ret); 21528c2ecf20Sopenharmony_ci return ret; 21538c2ecf20Sopenharmony_ci } 21548c2ecf20Sopenharmony_ci 21558c2ecf20Sopenharmony_ci ret = iwl_opmode_register("iwldvm", &iwl_dvm_ops); 21568c2ecf20Sopenharmony_ci if (ret) { 21578c2ecf20Sopenharmony_ci pr_err("Unable to register op_mode: %d\n", ret); 21588c2ecf20Sopenharmony_ci iwlagn_rate_control_unregister(); 21598c2ecf20Sopenharmony_ci } 21608c2ecf20Sopenharmony_ci 21618c2ecf20Sopenharmony_ci return ret; 21628c2ecf20Sopenharmony_ci} 21638c2ecf20Sopenharmony_cimodule_init(iwl_init); 21648c2ecf20Sopenharmony_ci 21658c2ecf20Sopenharmony_cistatic void __exit iwl_exit(void) 21668c2ecf20Sopenharmony_ci{ 21678c2ecf20Sopenharmony_ci iwl_opmode_deregister("iwldvm"); 21688c2ecf20Sopenharmony_ci iwlagn_rate_control_unregister(); 21698c2ecf20Sopenharmony_ci} 21708c2ecf20Sopenharmony_cimodule_exit(iwl_exit); 2171