From d7b9bb69c9b3accbd199b51b28d95d08f37049cd Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 31 Aug 2017 12:57:33 +0300 Subject: iwlwifi: mvm: remove support for Link Quality Measurements This was never used by any product. Remove it. Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 71 -------------------------- 1 file changed, 71 deletions(-) (limited to 'drivers/net/wireless/intel/iwlwifi/mvm/utils.c') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 2ea74abad73d..328035640669 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -1389,74 +1389,3 @@ void iwl_mvm_get_sync_time(struct iwl_mvm *mvm, u32 *gp2, u64 *boottime) iwl_mvm_power_update_device(mvm); } } - -int iwl_mvm_send_lqm_cmd(struct ieee80211_vif *vif, - enum iwl_lqm_cmd_operatrions operation, - u32 duration, u32 timeout) -{ - struct iwl_mvm_vif *mvm_vif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_link_qual_msrmnt_cmd cmd = { - .cmd_operation = cpu_to_le32(operation), - .mac_id = cpu_to_le32(mvm_vif->id), - .measurement_time = cpu_to_le32(duration), - .timeout = cpu_to_le32(timeout), - }; - u32 cmdid = - iwl_cmd_id(LINK_QUALITY_MEASUREMENT_CMD, MAC_CONF_GROUP, 0); - int ret; - - if (!fw_has_capa(&mvm_vif->mvm->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_LQM_SUPPORT)) - return -EOPNOTSUPP; - - if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) - return -EINVAL; - - switch (operation) { - case LQM_CMD_OPERATION_START_MEASUREMENT: - if (iwl_mvm_lqm_active(mvm_vif->mvm)) - return -EBUSY; - if (!vif->bss_conf.assoc) - return -EINVAL; - mvm_vif->lqm_active = true; - break; - case LQM_CMD_OPERATION_STOP_MEASUREMENT: - if (!iwl_mvm_lqm_active(mvm_vif->mvm)) - return -EINVAL; - break; - default: - return -EINVAL; - } - - ret = iwl_mvm_send_cmd_pdu(mvm_vif->mvm, cmdid, 0, sizeof(cmd), - &cmd); - - /* command failed - roll back lqm_active state */ - if (ret) { - mvm_vif->lqm_active = - operation == LQM_CMD_OPERATION_STOP_MEASUREMENT; - } - - return ret; -} - -static void iwl_mvm_lqm_active_iterator(void *_data, u8 *mac, - struct ieee80211_vif *vif) -{ - struct iwl_mvm_vif *mvm_vif = iwl_mvm_vif_from_mac80211(vif); - bool *lqm_active = _data; - - *lqm_active = *lqm_active || mvm_vif->lqm_active; -} - -bool iwl_mvm_lqm_active(struct iwl_mvm *mvm) -{ - bool ret = false; - - lockdep_assert_held(&mvm->mutex); - ieee80211_iterate_active_interfaces_atomic( - mvm->hw, IEEE80211_IFACE_ITER_NORMAL, - iwl_mvm_lqm_active_iterator, &ret); - - return ret; -} -- cgit v1.2.3 From 528a542aa6654a9ec03830cc75142cc94276739e Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 31 Aug 2017 11:52:30 +0300 Subject: iwlwifi: mvm: support firmware debug trigger on frame reorder timeout The trigger that collects data when a frame is released because of the timer of the reordering buffer was not implemented for 9000 devices. Fix this. Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 28 ++--------------------- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 6 +++++ drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 5 ++++ drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 1 + drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 25 ++++++++++++++++++++ 5 files changed, 39 insertions(+), 26 deletions(-) (limited to 'drivers/net/wireless/intel/iwlwifi/mvm/utils.c') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 8b4584541272..d7530474c1d3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -4186,31 +4186,6 @@ static void iwl_mvm_event_bar_rx_callback(struct iwl_mvm *mvm, event->u.ba.ssn); } -static void -iwl_mvm_event_frame_timeout_callback(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - const struct ieee80211_event *event) -{ - struct iwl_fw_dbg_trigger_tlv *trig; - struct iwl_fw_dbg_trigger_ba *ba_trig; - - if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_BA)) - return; - - trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_BA); - ba_trig = (void *)trig->data; - if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt, - ieee80211_vif_to_wdev(vif), trig)) - return; - - if (!(le16_to_cpu(ba_trig->frame_timeout) & BIT(event->u.ba.tid))) - return; - - iwl_fw_dbg_collect_trig(&mvm->fwrt, trig, - "Frame from %pM timed out, tid %d", - event->u.ba.sta->addr, event->u.ba.tid); -} - static void iwl_mvm_mac_event_callback(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const struct ieee80211_event *event) @@ -4225,7 +4200,8 @@ static void iwl_mvm_mac_event_callback(struct ieee80211_hw *hw, iwl_mvm_event_bar_rx_callback(mvm, vif, event); break; case BA_FRAME_TIMEOUT: - iwl_mvm_event_frame_timeout_callback(mvm, vif, event); + iwl_mvm_event_frame_timeout_callback(mvm, vif, event->u.ba.sta, + event->u.ba.tid); break; default: break; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index ec2cf248990b..e8be5104b909 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -586,6 +586,7 @@ enum iwl_mvm_tdls_cs_state { * @queue: queue of this reorder buffer * @last_amsdu: track last ASMDU SN for duplication detection * @last_sub_index: track ASMDU sub frame index for duplication detection + * @tid: the tid * @entries: list of skbs stored * @reorder_time: time the packet was stored in the reorder buffer * @reorder_timer: timer for frames are in the reorder buffer. For AMSDU @@ -603,6 +604,7 @@ struct iwl_mvm_reorder_buffer { int queue; u16 last_amsdu; u8 last_sub_index; + u8 tid; struct sk_buff_head entries[IEEE80211_MAX_AMPDU_BUF]; unsigned long reorder_time[IEEE80211_MAX_AMPDU_BUF]; struct timer_list reorder_timer; @@ -1839,6 +1841,10 @@ unsigned int iwl_mvm_get_wd_timeout(struct iwl_mvm *mvm, bool tdls, bool cmd_q); void iwl_mvm_connection_loss(struct iwl_mvm *mvm, struct ieee80211_vif *vif, const char *errmsg); +void iwl_mvm_event_frame_timeout_callback(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + const struct ieee80211_sta *sta, + u16 tid); int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b); int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 67ffd9774712..a0b406e68d55 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -492,13 +492,18 @@ void iwl_mvm_reorder_timer_expired(unsigned long data) if (expired) { struct ieee80211_sta *sta; + struct iwl_mvm_sta *mvmsta; rcu_read_lock(); sta = rcu_dereference(buf->mvm->fw_id_to_mac_id[buf->sta_id]); + mvmsta = iwl_mvm_sta_from_mac80211(sta); + /* SN is set to the last expired frame + 1 */ IWL_DEBUG_HT(buf->mvm, "Releasing expired frames for sta %u, sn %d\n", buf->sta_id, sn); + iwl_mvm_event_frame_timeout_callback(buf->mvm, mvmsta->vif, + sta, buf->tid); iwl_mvm_release_frames(buf->mvm, sta, NULL, buf, sn); rcu_read_unlock(); } else { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 411a2055dc45..3711f226220c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -2158,6 +2158,7 @@ static void iwl_mvm_init_reorder_buffer(struct iwl_mvm *mvm, reorder_buf->mvm = mvm; reorder_buf->queue = i; reorder_buf->sta_id = sta_id; + reorder_buf->tid = data->tid; reorder_buf->valid = false; for (j = 0; j < reorder_buf->buf_size; j++) __skb_queue_head_init(&reorder_buf->entries[j]); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 328035640669..2da1b088ac01 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -1368,6 +1368,31 @@ void iwl_mvm_inactivity_check(struct iwl_mvm *mvm) rcu_read_unlock(); } +void iwl_mvm_event_frame_timeout_callback(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + const struct ieee80211_sta *sta, + u16 tid) +{ + struct iwl_fw_dbg_trigger_tlv *trig; + struct iwl_fw_dbg_trigger_ba *ba_trig; + + if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_BA)) + return; + + trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_BA); + ba_trig = (void *)trig->data; + if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt, + ieee80211_vif_to_wdev(vif), trig)) + return; + + if (!(le16_to_cpu(ba_trig->frame_timeout) & BIT(tid))) + return; + + iwl_fw_dbg_collect_trig(&mvm->fwrt, trig, + "Frame from %pM timed out, tid %d", + sta->addr, tid); +} + void iwl_mvm_get_sync_time(struct iwl_mvm *mvm, u32 *gp2, u64 *boottime) { bool ps_disabled; -- cgit v1.2.3 From 0e1be40a45d767a07c1fb50ebfba273368f57484 Mon Sep 17 00:00:00 2001 From: Beni Lev Date: Thu, 28 Sep 2017 12:10:55 +0300 Subject: iwlwifi: mvm: allow reading UMAC error data from SMEM in A000 devices Currently, UMAC error data reading is restricted to DCCM. A000 NICs use SMEM for this data. Signed-off-by: Beni Lev Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/intel/iwlwifi/mvm/utils.c') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 2da1b088ac01..4ade688db63b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -459,7 +459,8 @@ static void iwl_mvm_dump_umac_error_log(struct iwl_mvm *mvm) base = mvm->umac_error_event_table; - if (base < 0x800000) { + if (base < (mvm->trans->cfg->device_family == IWL_DEVICE_FAMILY_A000 ? + 0x400000 : 0x800000)) { IWL_ERR(mvm, "Not valid error log pointer 0x%08X for %s uCode\n", base, -- cgit v1.2.3 From fb5b28469d2a5be83aae0c754a9a69bb37fec6ff Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Mon, 2 Oct 2017 15:44:20 +0300 Subject: iwlwifi: mvm: move umac_error_event_table validity check to where it's set There's no point in checking the validity of the umac_error_event_table pointer every time we generate a dump. It's cleaner to do so when we read the value, namely when we receive the alive data. Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 13 +++++++++++-- drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 18 ++++-------------- 2 files changed, 15 insertions(+), 16 deletions(-) (limited to 'drivers/net/wireless/intel/iwlwifi/mvm/utils.c') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index f476882291ae..70d0505a176e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -200,10 +200,19 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait, mvm->umac_error_event_table = le32_to_cpu(umac->error_info_addr); + if (mvm->umac_error_event_table < + (mvm->trans->cfg->device_family == IWL_DEVICE_FAMILY_A000 ? + 0x400000 : 0x800000)) + IWL_ERR(mvm, + "Not valid error log pointer 0x%08X for %s uCode\n", + mvm->umac_error_event_table, + (mvm->fwrt.cur_fw_img == IWL_UCODE_INIT) ? + "Init" : "RT"); + else + mvm->support_umac_log = true; + alive_data->scd_base_addr = le32_to_cpu(lmac1->scd_base_ptr); alive_data->valid = status == IWL_ALIVE_STATUS_OK; - if (mvm->umac_error_event_table) - mvm->support_umac_log = true; IWL_DEBUG_FW(mvm, "Alive ucode status 0x%04x revision 0x%01X 0x%01X\n", diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 4ade688db63b..d46115e2d69e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -455,21 +455,12 @@ static void iwl_mvm_dump_umac_error_log(struct iwl_mvm *mvm) { struct iwl_trans *trans = mvm->trans; struct iwl_umac_error_event_table table; - u32 base; - base = mvm->umac_error_event_table; - - if (base < (mvm->trans->cfg->device_family == IWL_DEVICE_FAMILY_A000 ? - 0x400000 : 0x800000)) { - IWL_ERR(mvm, - "Not valid error log pointer 0x%08X for %s uCode\n", - base, - (mvm->fwrt.cur_fw_img == IWL_UCODE_INIT) - ? "Init" : "RT"); + if (!mvm->support_umac_log) return; - } - iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table)); + iwl_trans_read_mem_bytes(trans, mvm->umac_error_event_table, &table, + sizeof(table)); if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { IWL_ERR(trans, "Start IWL Error Log Dump:\n"); @@ -609,8 +600,7 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) if (mvm->error_event_table[1]) iwl_mvm_dump_lmac_error_log(mvm, mvm->error_event_table[1]); - if (mvm->support_umac_log) - iwl_mvm_dump_umac_error_log(mvm); + iwl_mvm_dump_umac_error_log(mvm); } int iwl_mvm_find_free_queue(struct iwl_mvm *mvm, u8 sta_id, u8 minq, u8 maxq) -- cgit v1.2.3 From 0b9832b712d6767d6c7b01965fd788d1ca84fc92 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 13 Nov 2017 09:50:47 +0200 Subject: iwlwifi: mvm: don't use transmit queue hang detection when it is not possible When we act as an AP, new firmware versions handle internally the power saving clients and the driver doesn't know that the peers went to sleep. It is, hence, possible that a peer goes to sleep for a long time and stop pulling frames. This will cause its transmit queue to hang which is a condition that triggers the recovery flow in the driver. While this client is certainly buggy (it should have pulled the frame based on the TIM IE in the beacon), we can't blow up because of a buggy client. Change the current implementation to not enable the transmit queue hang detection on queues that serve peers when we act as an AP / GO. We can still enable this mechanism using the debug configuration which can come in handy when we want to debug why the client doesn't wake up. Cc: stable@vger.kernel.org # v4.13 Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/intel/iwlwifi/mvm/utils.c') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index d46115e2d69e..19c1d1f76e15 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -1134,9 +1134,18 @@ unsigned int iwl_mvm_get_wd_timeout(struct iwl_mvm *mvm, unsigned int default_timeout = cmd_q ? IWL_DEF_WD_TIMEOUT : mvm->cfg->base_params->wd_timeout; - if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_TXQ_TIMERS)) + if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_TXQ_TIMERS)) { + /* + * We can't know when the station is asleep or awake, so we + * must disable the queue hang detection. + */ + if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_STA_PM_NOTIF) && + vif && vif->type == NL80211_IFTYPE_AP) + return IWL_WATCHDOG_DISABLED; return iwlmvm_mod_params.tfd_q_hang_detect ? default_timeout : IWL_WATCHDOG_DISABLED; + } trigger = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_TXQ_TIMERS); txq_timer = (void *)trigger->data; -- cgit v1.2.3 From d1b275ffec459c5ae12b5c7086c84175696e5a9f Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 15 Nov 2017 14:12:30 +0200 Subject: iwlwifi: mvm: fix the TX queue hang timeout for MONITOR vif type The MONITOR type is missing in the interface type switch. Add it. Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless/intel/iwlwifi/mvm/utils.c') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 19c1d1f76e15..03ffd84786ca 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -1172,6 +1172,8 @@ unsigned int iwl_mvm_get_wd_timeout(struct iwl_mvm *mvm, return le32_to_cpu(txq_timer->p2p_go); case NL80211_IFTYPE_P2P_DEVICE: return le32_to_cpu(txq_timer->p2p_device); + case NL80211_IFTYPE_MONITOR: + return default_timeout; default: WARN_ON(1); return mvm->cfg->base_params->wd_timeout; -- cgit v1.2.3