// SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
*/
static ssize_t ath12k_read_simulate_fw_crash(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{ constchar buf[] = "To simulate firmware crash write one of the keywords to this file:\n" "`assert` - send WMI_FORCE_FW_HANG_CMDID to firmware to cause assert.\n";
if (band == NL80211_BAND_5GHZ || band == NL80211_BAND_6GHZ) { switch (pream_bw) { case WMI_TPC_PREAM_HT20: case WMI_TPC_PREAM_VHT20:
*mode_idx = ATH12K_TPC_STATS_CTL_MODE_HT_VHT20_5GHZ_6GHZ; break; case WMI_TPC_PREAM_HE20: case WMI_TPC_PREAM_EHT20:
*mode_idx = ATH12K_TPC_STATS_CTL_MODE_HE_EHT20_5GHZ_6GHZ; break; case WMI_TPC_PREAM_HT40: case WMI_TPC_PREAM_VHT40:
*mode_idx = ATH12K_TPC_STATS_CTL_MODE_HT_VHT40_5GHZ_6GHZ; break; case WMI_TPC_PREAM_HE40: case WMI_TPC_PREAM_EHT40:
*mode_idx = ATH12K_TPC_STATS_CTL_MODE_HE_EHT40_5GHZ_6GHZ; break; case WMI_TPC_PREAM_VHT80:
*mode_idx = ATH12K_TPC_STATS_CTL_MODE_VHT80_5GHZ_6GHZ; break; case WMI_TPC_PREAM_EHT60:
*mode_idx = ATH12K_TPC_STATS_CTL_MODE_EHT80_SU_PUNC20; break; case WMI_TPC_PREAM_HE80: case WMI_TPC_PREAM_EHT80:
*mode_idx = ATH12K_TPC_STATS_CTL_MODE_HE_EHT80_5GHZ_6GHZ; break; case WMI_TPC_PREAM_VHT160:
*mode_idx = ATH12K_TPC_STATS_CTL_MODE_VHT160_5GHZ_6GHZ; break; case WMI_TPC_PREAM_EHT120: case WMI_TPC_PREAM_EHT140:
*mode_idx = ATH12K_TPC_STATS_CTL_MODE_EHT160_SU_PUNC20; break; case WMI_TPC_PREAM_HE160: case WMI_TPC_PREAM_EHT160:
*mode_idx = ATH12K_TPC_STATS_CTL_MODE_HE_EHT160_5GHZ_6GHZ; break; case WMI_TPC_PREAM_EHT200:
*mode_idx = ATH12K_TPC_STATS_CTL_MODE_EHT320_SU_PUNC120; break; case WMI_TPC_PREAM_EHT240:
*mode_idx = ATH12K_TPC_STATS_CTL_MODE_EHT320_SU_PUNC80; break; case WMI_TPC_PREAM_EHT280:
*mode_idx = ATH12K_TPC_STATS_CTL_MODE_EHT320_SU_PUNC40; break; case WMI_TPC_PREAM_EHT320:
*mode_idx = ATH12K_TPC_STATS_CTL_MODE_HE_EHT320_5GHZ_6GHZ; break; default: /* for 5GHZ and 6GHZ, default case will be for OFDM */
*mode_idx = ATH12K_TPC_STATS_CTL_MODE_LEGACY_5GHZ_6GHZ; break;
}
} else { switch (pream_bw) { case WMI_TPC_PREAM_OFDM:
*mode_idx = ATH12K_TPC_STATS_CTL_MODE_LEGACY_2GHZ; break; case WMI_TPC_PREAM_HT20: case WMI_TPC_PREAM_VHT20: case WMI_TPC_PREAM_HE20: case WMI_TPC_PREAM_EHT20:
*mode_idx = ATH12K_TPC_STATS_CTL_MODE_HT20_2GHZ; break; case WMI_TPC_PREAM_HT40: case WMI_TPC_PREAM_VHT40: case WMI_TPC_PREAM_HE40: case WMI_TPC_PREAM_EHT40:
*mode_idx = ATH12K_TPC_STATS_CTL_MODE_HT40_2GHZ; break; default: /* for 2GHZ, default case will be CCK */
*mode_idx = ATH12K_TPC_STATS_CTL_MODE_CCK_2GHZ; break;
}
}
/* MODULATION_LIMIT is the maximum power limit,tpc should not exceed * modulation limit even if min tpc of all three array is greater * modulation limit
*/
tpc = min_t(s16, tpc, MODULATION_LIMIT);
/* Below assignments are just for printing purpose only */ switch (pream_idx) { case WMI_TPC_PREAM_CCK:
mode_type = WMI_RATE_PREAMBLE_CCK; break; case WMI_TPC_PREAM_OFDM:
mode_type = WMI_RATE_PREAMBLE_OFDM; break; case WMI_TPC_PREAM_HT20: case WMI_TPC_PREAM_HT40:
mode_type = WMI_RATE_PREAMBLE_HT; break; case WMI_TPC_PREAM_VHT20: case WMI_TPC_PREAM_VHT40: case WMI_TPC_PREAM_VHT80: case WMI_TPC_PREAM_VHT160:
mode_type = WMI_RATE_PREAMBLE_VHT; break; case WMI_TPC_PREAM_HE20: case WMI_TPC_PREAM_HE40: case WMI_TPC_PREAM_HE80: case WMI_TPC_PREAM_HE160:
mode_type = WMI_RATE_PREAMBLE_HE; break; case WMI_TPC_PREAM_EHT20: case WMI_TPC_PREAM_EHT40: case WMI_TPC_PREAM_EHT60: case WMI_TPC_PREAM_EHT80: case WMI_TPC_PREAM_EHT120: case WMI_TPC_PREAM_EHT140: case WMI_TPC_PREAM_EHT160: case WMI_TPC_PREAM_EHT200: case WMI_TPC_PREAM_EHT240: case WMI_TPC_PREAM_EHT280: case WMI_TPC_PREAM_EHT320:
mode_type = WMI_RATE_PREAMBLE_EHT; if (mcs_rate == 0 || mcs_rate == 1)
mcs_rate += 14; else
mcs_rate -= 2; break; default: return mode_type;
} return ((mode_type << 8) | ((nss & 0x7) << 5) | (mcs_rate & 0x1F));
}
for (nss = 0; nss < max_nss; nss++) { for (rates = 0; rates < max_rates; rates++, rate_idx++, max_rix++) { /* FW send extra MCS(10&11) for VHT and HE rates, * this is not used. Hence skipping it here
*/ if (pream_type == WMI_RATE_PREAMBLE_VHT &&
rates > ATH12K_VHT_MCS_MAX) continue;
if (pream_type == WMI_RATE_PREAMBLE_HE &&
rates > ATH12K_HE_MCS_MAX) continue;
if (pream_type == WMI_RATE_PREAMBLE_EHT &&
rates > ATH12K_EHT_MCS_MAX) continue;
/* mcs 12&13 is sent by FW for certain HWs in rate array, skipping it as * it is not supported
*/ if (he_ext_mcs) { for (i = WMI_TPC_PREAM_HE20; i <= WMI_TPC_PREAM_HE160; ++i)
max_rates[i] = ATH12K_HE_RATES;
}
if (type == WMI_HALPHY_PDEV_TX_MU_STATS ||
type == WMI_HALPHY_PDEV_TX_MUTXBF_STATS) {
pream_idx = WMI_TPC_PREAM_VHT20;
for (i = WMI_TPC_PREAM_CCK; i <= WMI_TPC_PREAM_HT40; ++i)
max_rix += max_nss[i] * max_rates[i];
} /* Enumerate all the rate indices */ for (i = rate_pream_idx + 1; i < WMI_TPC_PREAM_MAX; i++) {
nss = (max_nss[i - 1] < num_tx_chain ?
max_nss[i - 1] : num_tx_chain);
len += scnprintf(buf + len, buf_len - len, "**************** %s ****************\n",
type_str[type]);
len += scnprintf(buf + len, buf_len - len, "\t\t\t\tTPC values for Active chains\n");
len += scnprintf(buf + len, buf_len - len, "Rate idx Preamble Rate code");
for (i = 1; i <= active_tx_chains; ++i) {
len += scnprintf(buf + len, buf_len - len, "\t%d-Chain", i);
}
len += scnprintf(buf + len, buf_len - len, "\n"); for (i = pream_idx; i < WMI_TPC_PREAM_MAX; i++) { if (chan_freq <= 2483) { if (i == WMI_TPC_PREAM_VHT80 ||
i == WMI_TPC_PREAM_VHT160 ||
i == WMI_TPC_PREAM_HE80 ||
i == WMI_TPC_PREAM_HE160 ||
(i >= WMI_TPC_PREAM_EHT60 &&
i <= WMI_TPC_PREAM_EHT320)) {
max_rix += max_nss[i] * max_rates[i]; continue;
}
} else { if (i == WMI_TPC_PREAM_CCK) {
max_rix += max_rates[i]; continue;
}
}
if (!(caps &
(1 << ATH12K_TPC_STATS_SUPPORT_BE_PUNC))) { if (i == WMI_TPC_PREAM_EHT60 || i == WMI_TPC_PREAM_EHT120 ||
i == WMI_TPC_PREAM_EHT140 || i == WMI_TPC_PREAM_EHT200 ||
i == WMI_TPC_PREAM_EHT240 || i == WMI_TPC_PREAM_EHT280) {
max_rix += max_nss[i] * max_rates[i]; continue;
}
}
len = ath12k_tpc_fill_pream(ar, buf, buf_len, len, i, max_rix, nss,
max_rates[i], pream_type[i],
type, rate_idx[i], eht_rate_idx[eht_idx]);
if (pream_type[i] == WMI_RATE_PREAMBLE_EHT) /*For fetch the next index eht rates from rates array2*/
++eht_idx;
for (i = 0; i < ar->ab->hw_params->num_rxdma_per_pdev; i++) {
ring_id = ar->dp.rxdma_mon_dst_ring[i].ring_id;
ret = ath12k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, ar->dp.mac_id + i,
HAL_RXDMA_MONITOR_DST,
DP_RXDMA_REFILL_RING_SIZE,
&tlv_filter); if (ret) {
ath12k_warn(ar->ab, "failed to set rx filter for monitor status ring\n"); gotoexit;
}
}
len += scnprintf(buf + len, size - len, "DEVICE RX STATS:\n\n");
len += scnprintf(buf + len, size - len, "err ring pkts: %u\n",
device_stats->err_ring_pkts);
len += scnprintf(buf + len, size - len, "Invalid RBM: %u\n\n",
device_stats->invalid_rbm);
len += scnprintf(buf + len, size - len, "RXDMA errors:\n");
for (i = 0; i < HAL_REO_ENTR_RING_RXDMA_ECODE_MAX; i++)
len += scnprintf(buf + len, size - len, "%s: %u\n",
rxdma_err[i], device_stats->rxdma_error[i]);
len += scnprintf(buf + len, size - len, "\nREO errors:\n");
for (i = 0; i < HAL_REO_DEST_RING_ERROR_CODE_MAX; i++)
len += scnprintf(buf + len, size - len, "%s: %u\n",
reo_err[i], device_stats->reo_error[i]);
len += scnprintf(buf + len, size - len, "\ntx_wbm_rel_source:");
for (i = 0; i < HAL_WBM_REL_SRC_MODULE_MAX; i++)
len += scnprintf(buf + len, size - len, " %d:%u",
i, device_stats->tx_wbm_rel_source[i]);
len += scnprintf(buf + len, size - len, "\n");
len += scnprintf(buf + len, size - len, "\ntqm_rel_reason:");
for (i = 0; i < MAX_TQM_RELEASE_REASON; i++)
len += scnprintf(buf + len, size - len, " %d:%u",
i, device_stats->tqm_rel_reason[i]);
len += scnprintf(buf + len, size - len, "\n");
len += scnprintf(buf + len, size - len, "\nfw_tx_status:");
for (i = 0; i < MAX_FW_TX_STATUS; i++)
len += scnprintf(buf + len, size - len, " %d:%u",
i, device_stats->fw_tx_status[i]);
len += scnprintf(buf + len, size - len, "\n");
len += scnprintf(buf + len, size - len, "\ntx_enqueued:");
for (i = 0; i < DP_TCL_NUM_RING_MAX; i++)
len += scnprintf(buf + len, size - len, " %d:%u", i,
device_stats->tx_enqueued[i]);
len += scnprintf(buf + len, size - len, "\n");
len += scnprintf(buf + len, size - len, "\ntx_completed:");
for (i = 0; i < DP_TCL_NUM_RING_MAX; i++)
len += scnprintf(buf + len, size - len, " %d:%u",
i, device_stats->tx_completed[i]);
len += scnprintf(buf + len, size - len, "\n");
for (i = 0; i < ab->num_radios; i++) {
ar = ath12k_mac_get_ar_by_pdev_id(ab, DP_SW2HW_MACID(i)); if (ar) {
len += scnprintf(buf + len, size - len, "\nradio%d tx_pending: %u\n", i,
atomic_read(&ar->dp.num_tx_pending));
}
}
debugfs_ath12k = debugfs_lookup("ath12k", NULL); if (debugfs_ath12k) { /* a dentry from lookup() needs dput() after we don't use it */
dput_needed = true;
} else {
debugfs_ath12k = debugfs_create_dir("ath12k", NULL); if (IS_ERR_OR_NULL(debugfs_ath12k)) return;
dput_needed = false;
}
void ath12k_debugfs_soc_destroy(struct ath12k_base *ab)
{
debugfs_remove_recursive(ab->debugfs_soc);
ab->debugfs_soc = NULL; /* We are not removing ath12k directory on purpose, even if it * would be empty. This simplifies the directory handling and it's * a minor cosmetic issue to leave an empty ath12k directory to * debugfs.
*/
}
if (ah->state != ATH12K_HW_STATE_ON) return -ENETDOWN;
void *buf __free(kfree) = kzalloc(ATH12K_FW_STATS_BUF_SIZE, GFP_ATOMIC); if (!buf) return -ENOMEM;
param.pdev_id = ath12k_mac_get_target_pdev_id(ar); /* VDEV stats is always sent for all active VDEVs from FW */
param.vdev_id = 0;
param.stats_id = WMI_REQUEST_VDEV_STAT;
ret = ath12k_mac_get_fw_stats(ar, ¶m); if (ret) {
ath12k_warn(ar->ab, "failed to request fw vdev stats: %d\n", ret); return ret;
}
/* loop all active VDEVs for bcn stats */
list_for_each_entry(arvif, &ar->arvifs, list) { if (!arvif->is_up) continue;
param.vdev_id = arvif->vdev_id;
ret = ath12k_mac_get_fw_stats(ar, ¶m); if (ret) {
ath12k_warn(ar->ab, "failed to request fw bcn stats: %d\n", ret); return ret;
}
}
ath12k_wmi_fw_stats_dump(ar, &ar->fw_stats, param.stats_id,
buf); /* since beacon stats request is looped for all active VDEVs, saved fw * stats is not freed for each request until done for all active VDEVs
*/
spin_lock_bh(&ar->data_lock);
ath12k_fw_stats_bcn_free(&ar->fw_stats.bcn);
spin_unlock_bh(&ar->data_lock);
/* all stats debugfs files created are under "fw_stats" directory * created per PDEV
*/
debugfs_create_file("vdev_stats", 0600, fwstats_dir, ar,
&fops_vdev_stats);
debugfs_create_file("beacon_stats", 0600, fwstats_dir, ar,
&fops_bcn_stats);
debugfs_create_file("pdev_stats", 0600, fwstats_dir, ar,
&fops_pdev_stats);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.