The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/contrib/dev/iwlwifi/mvm/utils.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 3d5a2d8f7983e4fb3bbbd0a333eb3bb9


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.