summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/mvm/ops.c
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2015-02-10 11:35:36 -0800
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2015-02-10 11:35:36 -0800
commit4ba24fef3eb3b142197135223b90ced2f319cd53 (patch)
treea20c125b27740ec7b4c761b11d801108e1b316b2 /drivers/net/wireless/iwlwifi/mvm/ops.c
parent47c1ffb2b6b630894e9a16442611c056ab21c057 (diff)
parent98a4a59ee31a12105a2b84f5b8b515ac2cb208ef (diff)
Merge branch 'next' into for-linus
Prepare first round of input updates for 3.20.
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/ops.c')
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/ops.c135
1 files changed, 94 insertions, 41 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c
index 610dbcb0dc2..97dfba50c68 100644
--- a/drivers/net/wireless/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/iwlwifi/mvm/ops.c
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -242,6 +244,8 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
iwl_mvm_rx_scan_offload_complete_notif, true),
RX_HANDLER(MATCH_FOUND_NOTIFICATION, iwl_mvm_rx_scan_offload_results,
false),
+ RX_HANDLER(SCAN_COMPLETE_UMAC, iwl_mvm_rx_umac_scan_complete_notif,
+ true),
RX_HANDLER(RADIO_VERSION_NOTIFICATION, iwl_mvm_rx_radio_ver, false),
RX_HANDLER(CARD_STATE_NOTIFICATION, iwl_mvm_rx_card_state_notif, false),
@@ -252,6 +256,12 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
RX_HANDLER(REPLY_ERROR, iwl_mvm_rx_fw_error, false),
RX_HANDLER(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION,
iwl_mvm_power_uapsd_misbehaving_ap_notif, false),
+ RX_HANDLER(DTS_MEASUREMENT_NOTIFICATION, iwl_mvm_temp_notif, true),
+
+ RX_HANDLER(TDLS_CHANNEL_SWITCH_NOTIFICATION, iwl_mvm_rx_tdls_notif,
+ true),
+ RX_HANDLER(MFUART_LOAD_NOTIFICATION, iwl_mvm_rx_mfuart_notif, false),
+
};
#undef RX_HANDLER
#define CMD(x) [x] = #x
@@ -315,11 +325,9 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = {
CMD(WOWLAN_KEK_KCK_MATERIAL),
CMD(WOWLAN_GET_STATUSES),
CMD(WOWLAN_TX_POWER_PER_DB),
- CMD(NET_DETECT_CONFIG_CMD),
- CMD(NET_DETECT_PROFILES_QUERY_CMD),
- CMD(NET_DETECT_PROFILES_CMD),
- CMD(NET_DETECT_HOTSPOTS_CMD),
- CMD(NET_DETECT_HOTSPOTS_QUERY_CMD),
+ CMD(SCAN_OFFLOAD_PROFILES_QUERY_CMD),
+ CMD(SCAN_OFFLOAD_HOTSPOTS_CONFIG_CMD),
+ CMD(SCAN_OFFLOAD_HOTSPOTS_QUERY_CMD),
CMD(CARD_STATE_NOTIFICATION),
CMD(MISSED_BEACONS_NOTIFICATION),
CMD(BT_COEX_PRIO_TABLE),
@@ -330,14 +338,25 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = {
CMD(BCAST_FILTER_CMD),
CMD(REPLY_SF_CFG_CMD),
CMD(REPLY_BEACON_FILTERING_CMD),
+ CMD(CMD_DTS_MEASUREMENT_TRIGGER),
+ CMD(DTS_MEASUREMENT_NOTIFICATION),
CMD(REPLY_THERMAL_MNG_BACKOFF),
CMD(MAC_PM_POWER_TABLE),
+ CMD(LTR_CONFIG),
CMD(BT_COEX_CI),
CMD(BT_COEX_UPDATE_SW_BOOST),
CMD(BT_COEX_UPDATE_CORUN_LUT),
CMD(BT_COEX_UPDATE_REDUCED_TXP),
CMD(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION),
CMD(ANTENNA_COUPLING_NOTIFICATION),
+ CMD(SCD_QUEUE_CFG),
+ CMD(SCAN_CFG_CMD),
+ CMD(SCAN_REQ_UMAC),
+ CMD(SCAN_ABORT_UMAC),
+ CMD(SCAN_COMPLETE_UMAC),
+ CMD(TDLS_CHANNEL_SWITCH_CMD),
+ CMD(TDLS_CHANNEL_SWITCH_NOTIFICATION),
+ CMD(TDLS_CONFIG_CMD),
};
#undef CMD
@@ -362,6 +381,8 @@ static u32 calc_min_backoff(struct iwl_trans *trans, const struct iwl_cfg *cfg)
return 0;
}
+static void iwl_mvm_fw_error_dump_wk(struct work_struct *work);
+
static struct iwl_op_mode *
iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
const struct iwl_fw *fw, struct dentry *dbgfs_dir)
@@ -395,6 +416,9 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
if (cfg->max_rx_agg_size)
hw->max_rx_aggregation_subframes = cfg->max_rx_agg_size;
+ if (cfg->max_tx_agg_size)
+ hw->max_tx_aggregation_subframes = cfg->max_tx_agg_size;
+
op_mode = hw->priv;
op_mode->ops = &iwl_mvm_ops;
@@ -415,6 +439,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
mvm->first_agg_queue = 12;
}
mvm->sf_state = SF_UNINIT;
+ mvm->low_latency_agg_frame_limit = 6;
+ mvm->cur_ucode = IWL_UCODE_INIT;
mutex_init(&mvm->mutex);
mutex_init(&mvm->d0i3_suspend_mutex);
@@ -428,6 +454,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
INIT_WORK(&mvm->roc_done_wk, iwl_mvm_roc_done_wk);
INIT_WORK(&mvm->sta_drained_wk, iwl_mvm_sta_drained_wk);
INIT_WORK(&mvm->d0i3_exit_work, iwl_mvm_d0i3_exit_work);
+ INIT_WORK(&mvm->fw_error_dump_wk, iwl_mvm_fw_error_dump_wk);
+ INIT_DELAYED_WORK(&mvm->tdls_cs.dwork, iwl_mvm_tdls_ch_switch_work);
spin_lock_init(&mvm->d0i3_tx_lock);
spin_lock_init(&mvm->refs_lock);
@@ -456,7 +484,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
trans_cfg.command_names = iwl_mvm_cmd_strings;
trans_cfg.cmd_queue = IWL_MVM_CMD_QUEUE;
- trans_cfg.cmd_fifo = IWL_MVM_CMD_FIFO;
+ trans_cfg.cmd_fifo = IWL_MVM_TX_FIFO_CMD;
+ trans_cfg.scd_set_active = true;
snprintf(mvm->hw->wiphy->fw_version,
sizeof(mvm->hw->wiphy->fw_version),
@@ -467,6 +496,10 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
trans->rx_mpdu_cmd = REPLY_RX_MPDU_CMD;
trans->rx_mpdu_cmd_hdr_size = sizeof(struct iwl_rx_mpdu_res_start);
+ trans->dbg_dest_tlv = mvm->fw->dbg_dest_tlv;
+ trans->dbg_dest_reg_num = mvm->fw->dbg_dest_reg_num;
+ memcpy(trans->dbg_conf_tlv, mvm->fw->dbg_conf_tlv,
+ sizeof(trans->dbg_conf_tlv));
/* set up notification wait support */
iwl_notification_wait_init(&mvm->notif_wait);
@@ -494,7 +527,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
goto out_free;
/*
- * Even if nvm exists in the nvm_file driver should read agin the nvm
+ * Even if nvm exists in the nvm_file driver should read again the nvm
* from the nic because there might be entries that exist in the OTP
* and not in the file.
* for nics with no_power_up_nic_in_init: rely completley on nvm_file
@@ -510,7 +543,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
mutex_lock(&mvm->mutex);
err = iwl_run_init_mvm_ucode(mvm, true);
- iwl_trans_stop_device(trans);
+ if (!err || !iwlmvm_mod_params.init_dbg)
+ iwl_trans_stop_device(trans);
mutex_unlock(&mvm->mutex);
/* returns 0 if successful, 1 if success but in rfkill */
if (err < 0 && !iwlmvm_mod_params.init_dbg) {
@@ -519,16 +553,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
}
}
- if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)
- scan_size = sizeof(struct iwl_scan_req_unified_lmac) +
- sizeof(struct iwl_scan_channel_cfg_lmac) *
- mvm->fw->ucode_capa.n_scan_channels +
- sizeof(struct iwl_scan_probe_req);
- else
- scan_size = sizeof(struct iwl_scan_cmd) +
- mvm->fw->ucode_capa.max_probe_length +
- mvm->fw->ucode_capa.n_scan_channels *
- sizeof(struct iwl_scan_channel);
+ scan_size = iwl_mvm_scan_size(mvm);
mvm->scan_cmd = kmalloc(scan_size, GFP_KERNEL);
if (!mvm->scan_cmd)
@@ -573,16 +598,16 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
ieee80211_unregister_hw(mvm->hw);
kfree(mvm->scan_cmd);
- if (mvm->fw_error_dump) {
- vfree(mvm->fw_error_dump->op_mode_ptr);
- vfree(mvm->fw_error_dump->trans_ptr);
- kfree(mvm->fw_error_dump);
- }
kfree(mvm->mcast_filter_cmd);
mvm->mcast_filter_cmd = NULL;
#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_IWLWIFI_DEBUGFS)
kfree(mvm->d3_resume_sram);
+ if (mvm->nd_config) {
+ kfree(mvm->nd_config->match_sets);
+ kfree(mvm->nd_config);
+ mvm->nd_config = NULL;
+ }
#endif
iwl_trans_op_mode_leave(mvm->trans);
@@ -700,14 +725,13 @@ static void iwl_mvm_stop_sw_queue(struct iwl_op_mode *op_mode, int queue)
if (WARN_ON_ONCE(mq == IWL_INVALID_MAC80211_QUEUE))
return;
- if (atomic_inc_return(&mvm->queue_stop_count[mq]) > 1) {
+ if (atomic_inc_return(&mvm->mac80211_queue_stop_count[mq]) > 1) {
IWL_DEBUG_TX_QUEUES(mvm,
"queue %d (mac80211 %d) already stopped\n",
queue, mq);
return;
}
- set_bit(mq, &mvm->transport_queue_stop);
ieee80211_stop_queue(mvm->hw, mq);
}
@@ -719,15 +743,13 @@ static void iwl_mvm_wake_sw_queue(struct iwl_op_mode *op_mode, int queue)
if (WARN_ON_ONCE(mq == IWL_INVALID_MAC80211_QUEUE))
return;
- if (atomic_dec_return(&mvm->queue_stop_count[mq]) > 0) {
+ if (atomic_dec_return(&mvm->mac80211_queue_stop_count[mq]) > 0) {
IWL_DEBUG_TX_QUEUES(mvm,
- "queue %d (mac80211 %d) already awake\n",
+ "queue %d (mac80211 %d) still stopped\n",
queue, mq);
return;
}
- clear_bit(mq, &mvm->transport_queue_stop);
-
ieee80211_wake_queue(mvm->hw, mq);
}
@@ -744,6 +766,7 @@ void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state)
static bool iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state)
{
struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
+ bool calibrating = ACCESS_ONCE(mvm->calibrating);
if (state)
set_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status);
@@ -752,7 +775,15 @@ static bool iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state)
wiphy_rfkill_set_hw_state(mvm->hw->wiphy, iwl_mvm_is_radio_killed(mvm));
- return state && mvm->cur_ucode != IWL_UCODE_INIT;
+ /* iwl_run_init_mvm_ucode is waiting for results, abort it */
+ if (calibrating)
+ iwl_abort_notification_waits(&mvm->notif_wait);
+
+ /*
+ * Stop the device if we run OPERATIONAL firmware or if we are in the
+ * middle of the calibrations.
+ */
+ return state && (mvm->cur_ucode != IWL_UCODE_INIT || calibrating);
}
static void iwl_mvm_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb)
@@ -781,6 +812,16 @@ static void iwl_mvm_reprobe_wk(struct work_struct *wk)
module_put(THIS_MODULE);
}
+static void iwl_mvm_fw_error_dump_wk(struct work_struct *work)
+{
+ struct iwl_mvm *mvm =
+ container_of(work, struct iwl_mvm, fw_error_dump_wk);
+
+ mutex_lock(&mvm->mutex);
+ iwl_mvm_fw_error_dump(mvm);
+ mutex_unlock(&mvm->mutex);
+}
+
void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error)
{
iwl_abort_notification_waits(&mvm->notif_wait);
@@ -846,6 +887,8 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error)
if (fw_error && mvm->restart_fw > 0)
mvm->restart_fw--;
ieee80211_restart_hw(mvm->hw);
+ } else if (fw_error) {
+ schedule_work(&mvm->fw_error_dump_wk);
}
}
@@ -961,7 +1004,7 @@ static void iwl_mvm_enter_d0i3_iterator(void *_data, u8 *mac,
}
static void iwl_mvm_set_wowlan_data(struct iwl_mvm *mvm,
- struct iwl_wowlan_config_cmd_v3 *cmd,
+ struct iwl_wowlan_config_cmd *cmd,
struct iwl_d0i3_iter_data *iter_data)
{
struct ieee80211_sta *ap_sta;
@@ -977,14 +1020,14 @@ static void iwl_mvm_set_wowlan_data(struct iwl_mvm *mvm,
goto out;
mvm_ap_sta = iwl_mvm_sta_from_mac80211(ap_sta);
- cmd->common.is_11n_connection = ap_sta->ht_cap.ht_supported;
+ cmd->is_11n_connection = ap_sta->ht_cap.ht_supported;
cmd->offloading_tid = iter_data->offloading_tid;
/*
* The d0i3 uCode takes care of the nonqos counters,
* so configure only the qos seq ones.
*/
- iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, &cmd->common);
+ iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, cmd);
out:
rcu_read_unlock();
}
@@ -996,14 +1039,11 @@ static int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode)
struct iwl_d0i3_iter_data d0i3_iter_data = {
.mvm = mvm,
};
- struct iwl_wowlan_config_cmd_v3 wowlan_config_cmd = {
- .common = {
- .wakeup_filter =
- cpu_to_le32(IWL_WOWLAN_WAKEUP_RX_FRAME |
- IWL_WOWLAN_WAKEUP_BEACON_MISS |
- IWL_WOWLAN_WAKEUP_LINK_CHANGE |
- IWL_WOWLAN_WAKEUP_BCN_FILTERING),
- },
+ struct iwl_wowlan_config_cmd wowlan_config_cmd = {
+ .wakeup_filter = cpu_to_le32(IWL_WOWLAN_WAKEUP_RX_FRAME |
+ IWL_WOWLAN_WAKEUP_BEACON_MISS |
+ IWL_WOWLAN_WAKEUP_LINK_CHANGE |
+ IWL_WOWLAN_WAKEUP_BCN_FILTERING),
};
struct iwl_d3_manager_config d3_cfg_cmd = {
.min_sleep_time = cpu_to_le32(1000),
@@ -1015,6 +1055,19 @@ static int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode)
set_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status);
synchronize_net();
+ /*
+ * iwl_mvm_ref_sync takes a reference before checking the flag.
+ * so by checking there is no held reference we prevent a state
+ * in which iwl_mvm_ref_sync continues successfully while we
+ * configure the firmware to enter d0i3
+ */
+ if (iwl_mvm_ref_taken(mvm)) {
+ IWL_DEBUG_RPM(mvm->trans, "abort d0i3 due to taken ref\n");
+ clear_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status);
+ wake_up(&mvm->d0i3_exit_waitq);
+ return 1;
+ }
+
ieee80211_iterate_active_interfaces_atomic(mvm->hw,
IEEE80211_IFACE_ITER_NORMAL,
iwl_mvm_enter_d0i3_iterator,