1258 lines · c
1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause2/*3 * Copyright (C) 2012-2014, 2018-2024 Intel Corporation4 * Copyright (C) 2013-2014 Intel Mobile Communications GmbH5 * Copyright (C) 2015-2017 Intel Deutschland GmbH6 */7#include <net/mac80211.h>8 9#include "iwl-debug.h"10#include "iwl-io.h"11#include "iwl-prph.h"12#include "iwl-csr.h"13#include "mvm.h"14#include "fw/api/rs.h"15#include "fw/img.h"16 17/*18 * Will return 0 even if the cmd failed when RFKILL is asserted unless19 * CMD_WANT_SKB is set in cmd->flags.20 */21int iwl_mvm_send_cmd(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd)22{23 int ret;24 25#if defined(CONFIG_IWLWIFI_DEBUGFS) && defined(CONFIG_PM_SLEEP)26 if (WARN_ON(mvm->d3_test_active))27 return -EIO;28#endif29 30 /*31 * Synchronous commands from this op-mode must hold32 * the mutex, this ensures we don't try to send two33 * (or more) synchronous commands at a time.34 */35 if (!(cmd->flags & CMD_ASYNC))36 lockdep_assert_held(&mvm->mutex);37 38 ret = iwl_trans_send_cmd(mvm->trans, cmd);39 40 /*41 * If the caller wants the SKB, then don't hide any problems, the42 * caller might access the response buffer which will be NULL if43 * the command failed.44 */45 if (cmd->flags & CMD_WANT_SKB)46 return ret;47 48 /*49 * Silently ignore failures if RFKILL is asserted or50 * we are in suspend\resume process51 */52 if (!ret || ret == -ERFKILL || ret == -EHOSTDOWN)53 return 0;54 return ret;55}56 57int iwl_mvm_send_cmd_pdu(struct iwl_mvm *mvm, u32 id,58 u32 flags, u16 len, const void *data)59{60 struct iwl_host_cmd cmd = {61 .id = id,62 .len = { len, },63 .data = { data, },64 .flags = flags,65 };66 67 return iwl_mvm_send_cmd(mvm, &cmd);68}69 70/*71 * We assume that the caller set the status to the success value72 */73int iwl_mvm_send_cmd_status(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd,74 u32 *status)75{76 struct iwl_rx_packet *pkt;77 struct iwl_cmd_response *resp;78 int ret, resp_len;79 80 lockdep_assert_held(&mvm->mutex);81 82#if defined(CONFIG_IWLWIFI_DEBUGFS) && defined(CONFIG_PM_SLEEP)83 if (WARN_ON(mvm->d3_test_active))84 return -EIO;85#endif86 87 /*88 * Only synchronous commands can wait for status,89 * we use WANT_SKB so the caller can't.90 */91 if (WARN_ONCE(cmd->flags & (CMD_ASYNC | CMD_WANT_SKB),92 "cmd flags %x", cmd->flags))93 return -EINVAL;94 95 cmd->flags |= CMD_WANT_SKB;96 97 ret = iwl_trans_send_cmd(mvm->trans, cmd);98 if (ret == -ERFKILL) {99 /*100 * The command failed because of RFKILL, don't update101 * the status, leave it as success and return 0.102 */103 return 0;104 } else if (ret) {105 return ret;106 }107 108 pkt = cmd->resp_pkt;109 110 resp_len = iwl_rx_packet_payload_len(pkt);111 if (WARN_ON_ONCE(resp_len != sizeof(*resp))) {112 ret = -EIO;113 goto out_free_resp;114 }115 116 resp = (void *)pkt->data;117 *status = le32_to_cpu(resp->status);118 out_free_resp:119 iwl_free_resp(cmd);120 return ret;121}122 123/*124 * We assume that the caller set the status to the sucess value125 */126int iwl_mvm_send_cmd_pdu_status(struct iwl_mvm *mvm, u32 id, u16 len,127 const void *data, u32 *status)128{129 struct iwl_host_cmd cmd = {130 .id = id,131 .len = { len, },132 .data = { data, },133 };134 135 return iwl_mvm_send_cmd_status(mvm, &cmd, status);136}137 138int iwl_mvm_legacy_hw_idx_to_mac80211_idx(u32 rate_n_flags,139 enum nl80211_band band)140{141 int format = rate_n_flags & RATE_MCS_MOD_TYPE_MSK;142 int rate = rate_n_flags & RATE_LEGACY_RATE_MSK;143 bool is_LB = band == NL80211_BAND_2GHZ;144 145 if (format == RATE_MCS_LEGACY_OFDM_MSK)146 return is_LB ? rate + IWL_FIRST_OFDM_RATE :147 rate;148 149 /* CCK is not allowed in HB */150 return is_LB ? rate : -1;151}152 153int iwl_mvm_legacy_rate_to_mac80211_idx(u32 rate_n_flags,154 enum nl80211_band band)155{156 int rate = rate_n_flags & RATE_LEGACY_RATE_MSK_V1;157 int idx;158 int band_offset = 0;159 160 /* Legacy rate format, search for match in table */161 if (band != NL80211_BAND_2GHZ)162 band_offset = IWL_FIRST_OFDM_RATE;163 for (idx = band_offset; idx < IWL_RATE_COUNT_LEGACY; idx++)164 if (iwl_fw_rate_idx_to_plcp(idx) == rate)165 return idx - band_offset;166 167 return -1;168}169 170u8 iwl_mvm_mac80211_idx_to_hwrate(const struct iwl_fw *fw, int rate_idx)171{172 if (iwl_fw_lookup_cmd_ver(fw, TX_CMD, 0) > 8)173 /* In the new rate legacy rates are indexed:174 * 0 - 3 for CCK and 0 - 7 for OFDM.175 */176 return (rate_idx >= IWL_FIRST_OFDM_RATE ?177 rate_idx - IWL_FIRST_OFDM_RATE :178 rate_idx);179 180 return iwl_fw_rate_idx_to_plcp(rate_idx);181}182 183u8 iwl_mvm_mac80211_ac_to_ucode_ac(enum ieee80211_ac_numbers ac)184{185 static const u8 mac80211_ac_to_ucode_ac[] = {186 AC_VO,187 AC_VI,188 AC_BE,189 AC_BK190 };191 192 return mac80211_ac_to_ucode_ac[ac];193}194 195void iwl_mvm_rx_fw_error(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)196{197 struct iwl_rx_packet *pkt = rxb_addr(rxb);198 struct iwl_error_resp *err_resp = (void *)pkt->data;199 200 IWL_ERR(mvm, "FW Error notification: type 0x%08X cmd_id 0x%02X\n",201 le32_to_cpu(err_resp->error_type), err_resp->cmd_id);202 IWL_ERR(mvm, "FW Error notification: seq 0x%04X service 0x%08X\n",203 le16_to_cpu(err_resp->bad_cmd_seq_num),204 le32_to_cpu(err_resp->error_service));205 IWL_ERR(mvm, "FW Error notification: timestamp 0x%016llX\n",206 le64_to_cpu(err_resp->timestamp));207}208 209/*210 * Returns the first antenna as ANT_[ABC], as defined in iwl-config.h.211 * The parameter should also be a combination of ANT_[ABC].212 */213u8 first_antenna(u8 mask)214{215 BUILD_BUG_ON(ANT_A != BIT(0)); /* using ffs is wrong if not */216 if (WARN_ON_ONCE(!mask)) /* ffs will return 0 if mask is zeroed */217 return BIT(0);218 return BIT(ffs(mask) - 1);219}220 221#define MAX_ANT_NUM 2222/*223 * Toggles between TX antennas to send the probe request on.224 * Receives the bitmask of valid TX antennas and the *index* used225 * for the last TX, and returns the next valid *index* to use.226 * In order to set it in the tx_cmd, must do BIT(idx).227 */228u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx)229{230 u8 ind = last_idx;231 int i;232 233 for (i = 0; i < MAX_ANT_NUM; i++) {234 ind = (ind + 1) % MAX_ANT_NUM;235 if (valid & BIT(ind))236 return ind;237 }238 239 WARN_ONCE(1, "Failed to toggle between antennas 0x%x", valid);240 return last_idx;241}242 243/**244 * iwl_mvm_send_lq_cmd() - Send link quality command245 * @mvm: Driver data.246 * @lq: Link quality command to send.247 *248 * The link quality command is sent as the last step of station creation.249 * This is the special case in which init is set and we call a callback in250 * this case to clear the state indicating that station creation is in251 * progress.252 *253 * Returns: an error code indicating success or failure254 */255int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq)256{257 struct iwl_host_cmd cmd = {258 .id = LQ_CMD,259 .len = { sizeof(struct iwl_lq_cmd), },260 .flags = CMD_ASYNC,261 .data = { lq, },262 };263 264 if (WARN_ON(lq->sta_id == IWL_MVM_INVALID_STA ||265 iwl_mvm_has_tlc_offload(mvm)))266 return -EINVAL;267 268 return iwl_mvm_send_cmd(mvm, &cmd);269}270 271/**272 * iwl_mvm_update_smps - Get a request to change the SMPS mode273 * @mvm: Driver data.274 * @vif: Pointer to the ieee80211_vif structure275 * @req_type: The part of the driver who call for a change.276 * @smps_request: The request to change the SMPS mode.277 * @link_id: for MLO link_id, otherwise 0 (deflink)278 *279 * Get a requst to change the SMPS mode,280 * and change it according to all other requests in the driver.281 */282void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif,283 enum iwl_mvm_smps_type_request req_type,284 enum ieee80211_smps_mode smps_request,285 unsigned int link_id)286{287 struct iwl_mvm_vif *mvmvif;288 enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_AUTOMATIC;289 int i;290 291 lockdep_assert_held(&mvm->mutex);292 293 /* SMPS is irrelevant for NICs that don't have at least 2 RX antenna */294 if (num_of_ant(iwl_mvm_get_valid_rx_ant(mvm)) == 1)295 return;296 297 if (vif->type != NL80211_IFTYPE_STATION)298 return;299 300 /* SMPS is handled by firmware */301 if (iwl_mvm_has_rlc_offload(mvm))302 return;303 304 mvmvif = iwl_mvm_vif_from_mac80211(vif);305 306 if (WARN_ON_ONCE(!mvmvif->link[link_id]))307 return;308 309 mvmvif->link[link_id]->smps_requests[req_type] = smps_request;310 for (i = 0; i < NUM_IWL_MVM_SMPS_REQ; i++) {311 if (mvmvif->link[link_id]->smps_requests[i] ==312 IEEE80211_SMPS_STATIC) {313 smps_mode = IEEE80211_SMPS_STATIC;314 break;315 }316 if (mvmvif->link[link_id]->smps_requests[i] ==317 IEEE80211_SMPS_DYNAMIC)318 smps_mode = IEEE80211_SMPS_DYNAMIC;319 }320 321 /* SMPS is disabled in eSR */322 if (mvmvif->esr_active)323 smps_mode = IEEE80211_SMPS_OFF;324 325 ieee80211_request_smps(vif, link_id, smps_mode);326}327 328void iwl_mvm_update_smps_on_active_links(struct iwl_mvm *mvm,329 struct ieee80211_vif *vif,330 enum iwl_mvm_smps_type_request req_type,331 enum ieee80211_smps_mode smps_request)332{333 struct ieee80211_bss_conf *link_conf;334 unsigned int link_id;335 336 rcu_read_lock();337 for_each_vif_active_link(vif, link_conf, link_id)338 iwl_mvm_update_smps(mvm, vif, req_type, smps_request,339 link_id);340 rcu_read_unlock();341}342 343static bool iwl_wait_stats_complete(struct iwl_notif_wait_data *notif_wait,344 struct iwl_rx_packet *pkt, void *data)345{346 WARN_ON(pkt->hdr.cmd != STATISTICS_NOTIFICATION);347 348 return true;349}350 351#define PERIODIC_STAT_RATE 5352 353int iwl_mvm_request_periodic_system_statistics(struct iwl_mvm *mvm, bool enable)354{355 u32 flags = enable ? 0 : IWL_STATS_CFG_FLG_DISABLE_NTFY_MSK;356 u32 type = enable ? (IWL_STATS_NTFY_TYPE_ID_OPER |357 IWL_STATS_NTFY_TYPE_ID_OPER_PART1) : 0;358 struct iwl_system_statistics_cmd system_cmd = {359 .cfg_mask = cpu_to_le32(flags),360 .config_time_sec = cpu_to_le32(enable ?361 PERIODIC_STAT_RATE : 0),362 .type_id_mask = cpu_to_le32(type),363 };364 365 return iwl_mvm_send_cmd_pdu(mvm,366 WIDE_ID(SYSTEM_GROUP,367 SYSTEM_STATISTICS_CMD),368 0, sizeof(system_cmd), &system_cmd);369}370 371static int iwl_mvm_request_system_statistics(struct iwl_mvm *mvm, bool clear,372 u8 cmd_ver)373{374 struct iwl_system_statistics_cmd system_cmd = {375 .cfg_mask = clear ?376 cpu_to_le32(IWL_STATS_CFG_FLG_ON_DEMAND_NTFY_MSK) :377 cpu_to_le32(IWL_STATS_CFG_FLG_RESET_MSK |378 IWL_STATS_CFG_FLG_ON_DEMAND_NTFY_MSK),379 .type_id_mask = cpu_to_le32(IWL_STATS_NTFY_TYPE_ID_OPER |380 IWL_STATS_NTFY_TYPE_ID_OPER_PART1),381 };382 struct iwl_host_cmd cmd = {383 .id = WIDE_ID(SYSTEM_GROUP, SYSTEM_STATISTICS_CMD),384 .len[0] = sizeof(system_cmd),385 .data[0] = &system_cmd,386 };387 struct iwl_notification_wait stats_wait;388 static const u16 stats_complete[] = {389 WIDE_ID(SYSTEM_GROUP, SYSTEM_STATISTICS_END_NOTIF),390 };391 int ret;392 393 if (cmd_ver != 1) {394 IWL_FW_CHECK_FAILED(mvm,395 "Invalid system statistics command version:%d\n",396 cmd_ver);397 return -EOPNOTSUPP;398 }399 400 iwl_init_notification_wait(&mvm->notif_wait, &stats_wait,401 stats_complete, ARRAY_SIZE(stats_complete),402 NULL, NULL);403 404 mvm->statistics_clear = clear;405 ret = iwl_mvm_send_cmd(mvm, &cmd);406 if (ret) {407 iwl_remove_notification(&mvm->notif_wait, &stats_wait);408 return ret;409 }410 411 /* 500ms for OPERATIONAL, PART1 and END notification should be enough412 * for FW to collect data from all LMACs and send413 * STATISTICS_NOTIFICATION to host414 */415 ret = iwl_wait_notification(&mvm->notif_wait, &stats_wait, HZ / 2);416 if (ret)417 return ret;418 419 if (clear)420 iwl_mvm_accu_radio_stats(mvm);421 422 return ret;423}424 425int iwl_mvm_request_statistics(struct iwl_mvm *mvm, bool clear)426{427 struct iwl_statistics_cmd scmd = {428 .flags = clear ? cpu_to_le32(IWL_STATISTICS_FLG_CLEAR) : 0,429 };430 431 struct iwl_host_cmd cmd = {432 .id = STATISTICS_CMD,433 .len[0] = sizeof(scmd),434 .data[0] = &scmd,435 };436 u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw,437 WIDE_ID(SYSTEM_GROUP,438 SYSTEM_STATISTICS_CMD),439 IWL_FW_CMD_VER_UNKNOWN);440 int ret;441 442 /*443 * Don't request statistics during restart, they'll not have any useful444 * information right after restart, nor is clearing needed445 */446 if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))447 return 0;448 449 if (cmd_ver != IWL_FW_CMD_VER_UNKNOWN)450 return iwl_mvm_request_system_statistics(mvm, clear, cmd_ver);451 452 /* From version 15 - STATISTICS_NOTIFICATION, the reply for453 * STATISTICS_CMD is empty, and the response is with454 * STATISTICS_NOTIFICATION notification455 */456 if (iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP,457 STATISTICS_NOTIFICATION, 0) < 15) {458 cmd.flags = CMD_WANT_SKB;459 460 ret = iwl_mvm_send_cmd(mvm, &cmd);461 if (ret)462 return ret;463 464 iwl_mvm_handle_rx_statistics(mvm, cmd.resp_pkt);465 iwl_free_resp(&cmd);466 } else {467 struct iwl_notification_wait stats_wait;468 static const u16 stats_complete[] = {469 STATISTICS_NOTIFICATION,470 };471 472 iwl_init_notification_wait(&mvm->notif_wait, &stats_wait,473 stats_complete, ARRAY_SIZE(stats_complete),474 iwl_wait_stats_complete, NULL);475 476 ret = iwl_mvm_send_cmd(mvm, &cmd);477 if (ret) {478 iwl_remove_notification(&mvm->notif_wait, &stats_wait);479 return ret;480 }481 482 /* 200ms should be enough for FW to collect data from all483 * LMACs and send STATISTICS_NOTIFICATION to host484 */485 ret = iwl_wait_notification(&mvm->notif_wait, &stats_wait, HZ / 5);486 if (ret)487 return ret;488 }489 490 if (clear)491 iwl_mvm_accu_radio_stats(mvm);492 493 return 0;494}495 496void iwl_mvm_accu_radio_stats(struct iwl_mvm *mvm)497{498 mvm->accu_radio_stats.rx_time += mvm->radio_stats.rx_time;499 mvm->accu_radio_stats.tx_time += mvm->radio_stats.tx_time;500 mvm->accu_radio_stats.on_time_rf += mvm->radio_stats.on_time_rf;501 mvm->accu_radio_stats.on_time_scan += mvm->radio_stats.on_time_scan;502}503 504struct iwl_mvm_diversity_iter_data {505 struct iwl_mvm_phy_ctxt *ctxt;506 bool result;507};508 509static void iwl_mvm_diversity_iter(void *_data, u8 *mac,510 struct ieee80211_vif *vif)511{512 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);513 struct iwl_mvm_diversity_iter_data *data = _data;514 int i, link_id;515 516 for_each_mvm_vif_valid_link(mvmvif, link_id) {517 struct iwl_mvm_vif_link_info *link_info = mvmvif->link[link_id];518 519 if (link_info->phy_ctxt != data->ctxt)520 continue;521 522 for (i = 0; i < NUM_IWL_MVM_SMPS_REQ; i++) {523 if (link_info->smps_requests[i] == IEEE80211_SMPS_STATIC ||524 link_info->smps_requests[i] == IEEE80211_SMPS_DYNAMIC) {525 data->result = false;526 break;527 }528 }529 }530}531 532bool iwl_mvm_rx_diversity_allowed(struct iwl_mvm *mvm,533 struct iwl_mvm_phy_ctxt *ctxt)534{535 struct iwl_mvm_diversity_iter_data data = {536 .ctxt = ctxt,537 .result = true,538 };539 540 lockdep_assert_held(&mvm->mutex);541 542 if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM)543 return false;544 545 if (num_of_ant(iwl_mvm_get_valid_rx_ant(mvm)) == 1)546 return false;547 548 if (mvm->cfg->rx_with_siso_diversity)549 return false;550 551 ieee80211_iterate_active_interfaces_atomic(552 mvm->hw, IEEE80211_IFACE_ITER_NORMAL,553 iwl_mvm_diversity_iter, &data);554 555 return data.result;556}557 558void iwl_mvm_send_low_latency_cmd(struct iwl_mvm *mvm,559 bool low_latency, u16 mac_id)560{561 struct iwl_mac_low_latency_cmd cmd = {562 .mac_id = cpu_to_le32(mac_id)563 };564 565 if (!fw_has_capa(&mvm->fw->ucode_capa,566 IWL_UCODE_TLV_CAPA_DYNAMIC_QUOTA))567 return;568 569 if (low_latency) {570 /* currently we don't care about the direction */571 cmd.low_latency_rx = 1;572 cmd.low_latency_tx = 1;573 }574 575 if (iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(MAC_CONF_GROUP, LOW_LATENCY_CMD),576 0, sizeof(cmd), &cmd))577 IWL_ERR(mvm, "Failed to send low latency command\n");578}579 580int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif,581 bool low_latency,582 enum iwl_mvm_low_latency_cause cause)583{584 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);585 int res;586 bool prev;587 588 lockdep_assert_held(&mvm->mutex);589 590 prev = iwl_mvm_vif_low_latency(mvmvif);591 iwl_mvm_vif_set_low_latency(mvmvif, low_latency, cause);592 593 low_latency = iwl_mvm_vif_low_latency(mvmvif);594 595 if (low_latency == prev)596 return 0;597 598 iwl_mvm_send_low_latency_cmd(mvm, low_latency, mvmvif->id);599 600 res = iwl_mvm_update_quotas(mvm, false, NULL);601 if (res)602 return res;603 604 iwl_mvm_bt_coex_vif_change(mvm);605 606 return iwl_mvm_power_update_mac(mvm);607}608 609struct iwl_mvm_low_latency_iter {610 bool result;611 bool result_per_band[NUM_NL80211_BANDS];612};613 614static void iwl_mvm_ll_iter(void *_data, u8 *mac, struct ieee80211_vif *vif)615{616 struct iwl_mvm_low_latency_iter *result = _data;617 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);618 enum nl80211_band band;619 620 if (iwl_mvm_vif_low_latency(mvmvif)) {621 result->result = true;622 623 if (!mvmvif->deflink.phy_ctxt)624 return;625 626 band = mvmvif->deflink.phy_ctxt->channel->band;627 result->result_per_band[band] = true;628 }629}630 631bool iwl_mvm_low_latency(struct iwl_mvm *mvm)632{633 struct iwl_mvm_low_latency_iter data = {};634 635 ieee80211_iterate_active_interfaces_atomic(636 mvm->hw, IEEE80211_IFACE_ITER_NORMAL,637 iwl_mvm_ll_iter, &data);638 639 return data.result;640}641 642bool iwl_mvm_low_latency_band(struct iwl_mvm *mvm, enum nl80211_band band)643{644 struct iwl_mvm_low_latency_iter data = {};645 646 ieee80211_iterate_active_interfaces_atomic(647 mvm->hw, IEEE80211_IFACE_ITER_NORMAL,648 iwl_mvm_ll_iter, &data);649 650 return data.result_per_band[band];651}652 653struct iwl_bss_iter_data {654 struct ieee80211_vif *vif;655 bool error;656};657 658static void iwl_mvm_bss_iface_iterator(void *_data, u8 *mac,659 struct ieee80211_vif *vif)660{661 struct iwl_bss_iter_data *data = _data;662 663 if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)664 return;665 666 if (data->vif) {667 data->error = true;668 return;669 }670 671 data->vif = vif;672}673 674struct ieee80211_vif *iwl_mvm_get_bss_vif(struct iwl_mvm *mvm)675{676 struct iwl_bss_iter_data bss_iter_data = {};677 678 ieee80211_iterate_active_interfaces_atomic(679 mvm->hw, IEEE80211_IFACE_ITER_NORMAL,680 iwl_mvm_bss_iface_iterator, &bss_iter_data);681 682 if (bss_iter_data.error) {683 IWL_ERR(mvm, "More than one managed interface active!\n");684 return ERR_PTR(-EINVAL);685 }686 687 return bss_iter_data.vif;688}689 690struct iwl_bss_find_iter_data {691 struct ieee80211_vif *vif;692 u32 macid;693};694 695static void iwl_mvm_bss_find_iface_iterator(void *_data, u8 *mac,696 struct ieee80211_vif *vif)697{698 struct iwl_bss_find_iter_data *data = _data;699 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);700 701 if (mvmvif->id == data->macid)702 data->vif = vif;703}704 705struct ieee80211_vif *iwl_mvm_get_vif_by_macid(struct iwl_mvm *mvm, u32 macid)706{707 struct iwl_bss_find_iter_data data = {708 .macid = macid,709 };710 711 lockdep_assert_held(&mvm->mutex);712 713 ieee80211_iterate_active_interfaces_atomic(714 mvm->hw, IEEE80211_IFACE_ITER_NORMAL,715 iwl_mvm_bss_find_iface_iterator, &data);716 717 return data.vif;718}719 720struct iwl_sta_iter_data {721 bool assoc;722};723 724static void iwl_mvm_sta_iface_iterator(void *_data, u8 *mac,725 struct ieee80211_vif *vif)726{727 struct iwl_sta_iter_data *data = _data;728 729 if (vif->type != NL80211_IFTYPE_STATION)730 return;731 732 if (vif->cfg.assoc)733 data->assoc = true;734}735 736bool iwl_mvm_is_vif_assoc(struct iwl_mvm *mvm)737{738 struct iwl_sta_iter_data data = {739 .assoc = false,740 };741 742 ieee80211_iterate_active_interfaces_atomic(mvm->hw,743 IEEE80211_IFACE_ITER_NORMAL,744 iwl_mvm_sta_iface_iterator,745 &data);746 return data.assoc;747}748 749unsigned int iwl_mvm_get_wd_timeout(struct iwl_mvm *mvm,750 struct ieee80211_vif *vif)751{752 unsigned int default_timeout =753 mvm->trans->trans_cfg->base_params->wd_timeout;754 755 /*756 * We can't know when the station is asleep or awake, so we757 * must disable the queue hang detection.758 */759 if (fw_has_capa(&mvm->fw->ucode_capa,760 IWL_UCODE_TLV_CAPA_STA_PM_NOTIF) &&761 vif->type == NL80211_IFTYPE_AP)762 return IWL_WATCHDOG_DISABLED;763 return default_timeout;764}765 766void iwl_mvm_connection_loss(struct iwl_mvm *mvm, struct ieee80211_vif *vif,767 const char *errmsg)768{769 struct iwl_fw_dbg_trigger_tlv *trig;770 struct iwl_fw_dbg_trigger_mlme *trig_mlme;771 772 trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, ieee80211_vif_to_wdev(vif),773 FW_DBG_TRIGGER_MLME);774 if (!trig)775 goto out;776 777 trig_mlme = (void *)trig->data;778 779 if (trig_mlme->stop_connection_loss &&780 --trig_mlme->stop_connection_loss)781 goto out;782 783 iwl_fw_dbg_collect_trig(&mvm->fwrt, trig, "%s", errmsg);784 785out:786 ieee80211_connection_loss(vif);787}788 789void iwl_mvm_event_frame_timeout_callback(struct iwl_mvm *mvm,790 struct ieee80211_vif *vif,791 const struct ieee80211_sta *sta,792 u16 tid)793{794 struct iwl_fw_dbg_trigger_tlv *trig;795 struct iwl_fw_dbg_trigger_ba *ba_trig;796 797 trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, ieee80211_vif_to_wdev(vif),798 FW_DBG_TRIGGER_BA);799 if (!trig)800 return;801 802 ba_trig = (void *)trig->data;803 804 if (!(le16_to_cpu(ba_trig->frame_timeout) & BIT(tid)))805 return;806 807 iwl_fw_dbg_collect_trig(&mvm->fwrt, trig,808 "Frame from %pM timed out, tid %d",809 sta->addr, tid);810}811 812u8 iwl_mvm_tcm_load_percentage(u32 airtime, u32 elapsed)813{814 if (!elapsed)815 return 0;816 817 return (100 * airtime / elapsed) / USEC_PER_MSEC;818}819 820static enum iwl_mvm_traffic_load821iwl_mvm_tcm_load(struct iwl_mvm *mvm, u32 airtime, unsigned long elapsed)822{823 u8 load = iwl_mvm_tcm_load_percentage(airtime, elapsed);824 825 if (load > IWL_MVM_TCM_LOAD_HIGH_THRESH)826 return IWL_MVM_TRAFFIC_HIGH;827 if (load > IWL_MVM_TCM_LOAD_MEDIUM_THRESH)828 return IWL_MVM_TRAFFIC_MEDIUM;829 830 return IWL_MVM_TRAFFIC_LOW;831}832 833static void iwl_mvm_tcm_iter(void *_data, u8 *mac, struct ieee80211_vif *vif)834{835 struct iwl_mvm *mvm = _data;836 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);837 bool low_latency, prev = mvmvif->low_latency & LOW_LATENCY_TRAFFIC;838 839 if (mvmvif->id >= NUM_MAC_INDEX_DRIVER)840 return;841 842 low_latency = mvm->tcm.result.low_latency[mvmvif->id];843 844 if (!mvm->tcm.result.change[mvmvif->id] &&845 prev == low_latency) {846 iwl_mvm_update_quotas(mvm, false, NULL);847 return;848 }849 850 if (prev != low_latency) {851 /* this sends traffic load and updates quota as well */852 iwl_mvm_update_low_latency(mvm, vif, low_latency,853 LOW_LATENCY_TRAFFIC);854 } else {855 iwl_mvm_update_quotas(mvm, false, NULL);856 }857}858 859static void iwl_mvm_tcm_results(struct iwl_mvm *mvm)860{861 guard(mvm)(mvm);862 863 ieee80211_iterate_active_interfaces(864 mvm->hw, IEEE80211_IFACE_ITER_NORMAL,865 iwl_mvm_tcm_iter, mvm);866 867 if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN))868 iwl_mvm_config_scan(mvm);869}870 871static void iwl_mvm_tcm_uapsd_nonagg_detected_wk(struct work_struct *wk)872{873 struct iwl_mvm *mvm;874 struct iwl_mvm_vif *mvmvif;875 struct ieee80211_vif *vif;876 877 mvmvif = container_of(wk, struct iwl_mvm_vif,878 uapsd_nonagg_detected_wk.work);879 vif = container_of((void *)mvmvif, struct ieee80211_vif, drv_priv);880 mvm = mvmvif->mvm;881 882 if (mvm->tcm.data[mvmvif->id].opened_rx_ba_sessions)883 return;884 885 /* remember that this AP is broken */886 memcpy(mvm->uapsd_noagg_bssids[mvm->uapsd_noagg_bssid_write_idx].addr,887 vif->bss_conf.bssid, ETH_ALEN);888 mvm->uapsd_noagg_bssid_write_idx++;889 if (mvm->uapsd_noagg_bssid_write_idx >= IWL_MVM_UAPSD_NOAGG_LIST_LEN)890 mvm->uapsd_noagg_bssid_write_idx = 0;891 892 iwl_mvm_connection_loss(mvm, vif,893 "AP isn't using AMPDU with uAPSD enabled");894}895 896static void iwl_mvm_uapsd_agg_disconnect(struct iwl_mvm *mvm,897 struct ieee80211_vif *vif)898{899 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);900 901 if (vif->type != NL80211_IFTYPE_STATION)902 return;903 904 if (!vif->cfg.assoc)905 return;906 907 if (!mvmvif->deflink.queue_params[IEEE80211_AC_VO].uapsd &&908 !mvmvif->deflink.queue_params[IEEE80211_AC_VI].uapsd &&909 !mvmvif->deflink.queue_params[IEEE80211_AC_BE].uapsd &&910 !mvmvif->deflink.queue_params[IEEE80211_AC_BK].uapsd)911 return;912 913 if (mvm->tcm.data[mvmvif->id].uapsd_nonagg_detect.detected)914 return;915 916 mvm->tcm.data[mvmvif->id].uapsd_nonagg_detect.detected = true;917 IWL_INFO(mvm,918 "detected AP should do aggregation but isn't, likely due to U-APSD\n");919 schedule_delayed_work(&mvmvif->uapsd_nonagg_detected_wk,920 15 * HZ);921}922 923static void iwl_mvm_check_uapsd_agg_expected_tpt(struct iwl_mvm *mvm,924 unsigned int elapsed,925 int mac)926{927 u64 bytes = mvm->tcm.data[mac].uapsd_nonagg_detect.rx_bytes;928 u64 tpt;929 unsigned long rate;930 struct ieee80211_vif *vif;931 932 rate = ewma_rate_read(&mvm->tcm.data[mac].uapsd_nonagg_detect.rate);933 934 if (!rate || mvm->tcm.data[mac].opened_rx_ba_sessions ||935 mvm->tcm.data[mac].uapsd_nonagg_detect.detected)936 return;937 938 if (iwl_mvm_has_new_rx_api(mvm)) {939 tpt = 8 * bytes; /* kbps */940 do_div(tpt, elapsed);941 rate *= 1000; /* kbps */942 if (tpt < 22 * rate / 100)943 return;944 } else {945 /*946 * the rate here is actually the threshold, in 100Kbps units,947 * so do the needed conversion from bytes to 100Kbps:948 * 100kb = bits / (100 * 1000),949 * 100kbps = 100kb / (msecs / 1000) ==950 * (bits / (100 * 1000)) / (msecs / 1000) ==951 * bits / (100 * msecs)952 */953 tpt = (8 * bytes);954 do_div(tpt, elapsed * 100);955 if (tpt < rate)956 return;957 }958 959 rcu_read_lock();960 vif = rcu_dereference(mvm->vif_id_to_mac[mac]);961 if (vif)962 iwl_mvm_uapsd_agg_disconnect(mvm, vif);963 rcu_read_unlock();964}965 966static void iwl_mvm_tcm_iterator(void *_data, u8 *mac,967 struct ieee80211_vif *vif)968{969 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);970 u32 *band = _data;971 972 if (!mvmvif->deflink.phy_ctxt)973 return;974 975 band[mvmvif->id] = mvmvif->deflink.phy_ctxt->channel->band;976}977 978static unsigned long iwl_mvm_calc_tcm_stats(struct iwl_mvm *mvm,979 unsigned long ts,980 bool handle_uapsd)981{982 unsigned int elapsed = jiffies_to_msecs(ts - mvm->tcm.ts);983 unsigned int uapsd_elapsed =984 jiffies_to_msecs(ts - mvm->tcm.uapsd_nonagg_ts);985 u32 total_airtime = 0;986 u32 band_airtime[NUM_NL80211_BANDS] = {0};987 u32 band[NUM_MAC_INDEX_DRIVER] = {0};988 int ac, mac, i;989 bool low_latency = false;990 enum iwl_mvm_traffic_load load, band_load;991 bool handle_ll = time_after(ts, mvm->tcm.ll_ts + MVM_LL_PERIOD);992 993 if (handle_ll)994 mvm->tcm.ll_ts = ts;995 if (handle_uapsd)996 mvm->tcm.uapsd_nonagg_ts = ts;997 998 mvm->tcm.result.elapsed = elapsed;999 1000 ieee80211_iterate_active_interfaces_atomic(mvm->hw,1001 IEEE80211_IFACE_ITER_NORMAL,1002 iwl_mvm_tcm_iterator,1003 &band);1004 1005 for (mac = 0; mac < NUM_MAC_INDEX_DRIVER; mac++) {1006 struct iwl_mvm_tcm_mac *mdata = &mvm->tcm.data[mac];1007 u32 vo_vi_pkts = 0;1008 u32 airtime = mdata->rx.airtime + mdata->tx.airtime;1009 1010 total_airtime += airtime;1011 band_airtime[band[mac]] += airtime;1012 1013 load = iwl_mvm_tcm_load(mvm, airtime, elapsed);1014 mvm->tcm.result.change[mac] = load != mvm->tcm.result.load[mac];1015 mvm->tcm.result.load[mac] = load;1016 mvm->tcm.result.airtime[mac] = airtime;1017 1018 for (ac = IEEE80211_AC_VO; ac <= IEEE80211_AC_VI; ac++)1019 vo_vi_pkts += mdata->rx.pkts[ac] +1020 mdata->tx.pkts[ac];1021 1022 /* enable immediately with enough packets but defer disabling */1023 if (vo_vi_pkts > IWL_MVM_TCM_LOWLAT_ENABLE_THRESH)1024 mvm->tcm.result.low_latency[mac] = true;1025 else if (handle_ll)1026 mvm->tcm.result.low_latency[mac] = false;1027 1028 if (handle_ll) {1029 /* clear old data */1030 memset(&mdata->rx.pkts, 0, sizeof(mdata->rx.pkts));1031 memset(&mdata->tx.pkts, 0, sizeof(mdata->tx.pkts));1032 }1033 low_latency |= mvm->tcm.result.low_latency[mac];1034 1035 if (!mvm->tcm.result.low_latency[mac] && handle_uapsd)1036 iwl_mvm_check_uapsd_agg_expected_tpt(mvm, uapsd_elapsed,1037 mac);1038 /* clear old data */1039 if (handle_uapsd)1040 mdata->uapsd_nonagg_detect.rx_bytes = 0;1041 memset(&mdata->rx.airtime, 0, sizeof(mdata->rx.airtime));1042 memset(&mdata->tx.airtime, 0, sizeof(mdata->tx.airtime));1043 }1044 1045 load = iwl_mvm_tcm_load(mvm, total_airtime, elapsed);1046 mvm->tcm.result.global_load = load;1047 1048 for (i = 0; i < NUM_NL80211_BANDS; i++) {1049 band_load = iwl_mvm_tcm_load(mvm, band_airtime[i], elapsed);1050 mvm->tcm.result.band_load[i] = band_load;1051 }1052 1053 /*1054 * If the current load isn't low we need to force re-evaluation1055 * in the TCM period, so that we can return to low load if there1056 * was no traffic at all (and thus iwl_mvm_recalc_tcm didn't get1057 * triggered by traffic).1058 */1059 if (load != IWL_MVM_TRAFFIC_LOW)1060 return MVM_TCM_PERIOD;1061 /*1062 * If low-latency is active we need to force re-evaluation after1063 * (the longer) MVM_LL_PERIOD, so that we can disable low-latency1064 * when there's no traffic at all.1065 */1066 if (low_latency)1067 return MVM_LL_PERIOD;1068 /*1069 * Otherwise, we don't need to run the work struct because we're1070 * in the default "idle" state - traffic indication is low (which1071 * also covers the "no traffic" case) and low-latency is disabled1072 * so there's no state that may need to be disabled when there's1073 * no traffic at all.1074 *1075 * Note that this has no impact on the regular scheduling of the1076 * updates triggered by traffic - those happen whenever one of the1077 * two timeouts expire (if there's traffic at all.)1078 */1079 return 0;1080}1081 1082void iwl_mvm_recalc_tcm(struct iwl_mvm *mvm)1083{1084 unsigned long ts = jiffies;1085 bool handle_uapsd =1086 time_after(ts, mvm->tcm.uapsd_nonagg_ts +1087 msecs_to_jiffies(IWL_MVM_UAPSD_NONAGG_PERIOD));1088 1089 spin_lock(&mvm->tcm.lock);1090 if (mvm->tcm.paused || !time_after(ts, mvm->tcm.ts + MVM_TCM_PERIOD)) {1091 spin_unlock(&mvm->tcm.lock);1092 return;1093 }1094 spin_unlock(&mvm->tcm.lock);1095 1096 if (handle_uapsd && iwl_mvm_has_new_rx_api(mvm)) {1097 guard(mvm)(mvm);1098 if (iwl_mvm_request_statistics(mvm, true))1099 handle_uapsd = false;1100 }1101 1102 spin_lock(&mvm->tcm.lock);1103 /* re-check if somebody else won the recheck race */1104 if (!mvm->tcm.paused && time_after(ts, mvm->tcm.ts + MVM_TCM_PERIOD)) {1105 /* calculate statistics */1106 unsigned long work_delay = iwl_mvm_calc_tcm_stats(mvm, ts,1107 handle_uapsd);1108 1109 /* the memset needs to be visible before the timestamp */1110 smp_mb();1111 mvm->tcm.ts = ts;1112 if (work_delay)1113 schedule_delayed_work(&mvm->tcm.work, work_delay);1114 }1115 spin_unlock(&mvm->tcm.lock);1116 1117 iwl_mvm_tcm_results(mvm);1118}1119 1120void iwl_mvm_tcm_work(struct work_struct *work)1121{1122 struct delayed_work *delayed_work = to_delayed_work(work);1123 struct iwl_mvm *mvm = container_of(delayed_work, struct iwl_mvm,1124 tcm.work);1125 1126 iwl_mvm_recalc_tcm(mvm);1127}1128 1129void iwl_mvm_pause_tcm(struct iwl_mvm *mvm, bool with_cancel)1130{1131 spin_lock_bh(&mvm->tcm.lock);1132 mvm->tcm.paused = true;1133 spin_unlock_bh(&mvm->tcm.lock);1134 if (with_cancel)1135 cancel_delayed_work_sync(&mvm->tcm.work);1136}1137 1138void iwl_mvm_resume_tcm(struct iwl_mvm *mvm)1139{1140 int mac;1141 bool low_latency = false;1142 1143 spin_lock_bh(&mvm->tcm.lock);1144 mvm->tcm.ts = jiffies;1145 mvm->tcm.ll_ts = jiffies;1146 for (mac = 0; mac < NUM_MAC_INDEX_DRIVER; mac++) {1147 struct iwl_mvm_tcm_mac *mdata = &mvm->tcm.data[mac];1148 1149 memset(&mdata->rx.pkts, 0, sizeof(mdata->rx.pkts));1150 memset(&mdata->tx.pkts, 0, sizeof(mdata->tx.pkts));1151 memset(&mdata->rx.airtime, 0, sizeof(mdata->rx.airtime));1152 memset(&mdata->tx.airtime, 0, sizeof(mdata->tx.airtime));1153 1154 if (mvm->tcm.result.low_latency[mac])1155 low_latency = true;1156 }1157 /* The TCM data needs to be reset before "paused" flag changes */1158 smp_mb();1159 mvm->tcm.paused = false;1160 1161 /*1162 * if the current load is not low or low latency is active, force1163 * re-evaluation to cover the case of no traffic.1164 */1165 if (mvm->tcm.result.global_load > IWL_MVM_TRAFFIC_LOW)1166 schedule_delayed_work(&mvm->tcm.work, MVM_TCM_PERIOD);1167 else if (low_latency)1168 schedule_delayed_work(&mvm->tcm.work, MVM_LL_PERIOD);1169 1170 spin_unlock_bh(&mvm->tcm.lock);1171}1172 1173void iwl_mvm_tcm_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif)1174{1175 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);1176 1177 INIT_DELAYED_WORK(&mvmvif->uapsd_nonagg_detected_wk,1178 iwl_mvm_tcm_uapsd_nonagg_detected_wk);1179}1180 1181void iwl_mvm_tcm_rm_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif)1182{1183 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);1184 1185 cancel_delayed_work_sync(&mvmvif->uapsd_nonagg_detected_wk);1186}1187 1188u32 iwl_mvm_get_systime(struct iwl_mvm *mvm)1189{1190 u32 reg_addr = DEVICE_SYSTEM_TIME_REG;1191 1192 if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22000 &&1193 mvm->trans->cfg->gp2_reg_addr)1194 reg_addr = mvm->trans->cfg->gp2_reg_addr;1195 1196 return iwl_read_prph(mvm->trans, reg_addr);1197}1198 1199void iwl_mvm_get_sync_time(struct iwl_mvm *mvm, int clock_type,1200 u32 *gp2, u64 *boottime, ktime_t *realtime)1201{1202 bool ps_disabled;1203 1204 lockdep_assert_held(&mvm->mutex);1205 1206 /* Disable power save when reading GP2 */1207 ps_disabled = mvm->ps_disabled;1208 if (!ps_disabled) {1209 mvm->ps_disabled = true;1210 iwl_mvm_power_update_device(mvm);1211 }1212 1213 *gp2 = iwl_mvm_get_systime(mvm);1214 1215 if (clock_type == CLOCK_BOOTTIME && boottime)1216 *boottime = ktime_get_boottime_ns();1217 else if (clock_type == CLOCK_REALTIME && realtime)1218 *realtime = ktime_get_real();1219 1220 if (!ps_disabled) {1221 mvm->ps_disabled = ps_disabled;1222 iwl_mvm_power_update_device(mvm);1223 }1224}1225 1226/* Find if at least two links from different vifs use same channel1227 * FIXME: consider having a refcount array in struct iwl_mvm_vif for1228 * used phy_ctxt ids.1229 */1230bool iwl_mvm_have_links_same_channel(struct iwl_mvm_vif *vif1,1231 struct iwl_mvm_vif *vif2)1232{1233 unsigned int i, j;1234 1235 for_each_mvm_vif_valid_link(vif1, i) {1236 for_each_mvm_vif_valid_link(vif2, j) {1237 if (vif1->link[i]->phy_ctxt == vif2->link[j]->phy_ctxt)1238 return true;1239 }1240 }1241 1242 return false;1243}1244 1245bool iwl_mvm_vif_is_active(struct iwl_mvm_vif *mvmvif)1246{1247 unsigned int i;1248 1249 /* FIXME: can it fail when phy_ctxt is assigned? */1250 for_each_mvm_vif_valid_link(mvmvif, i) {1251 if (mvmvif->link[i]->phy_ctxt &&1252 mvmvif->link[i]->phy_ctxt->id < NUM_PHY_CTX)1253 return true;1254 }1255 1256 return false;1257}1258