0001
0002
0003
0004
0005
0006 #include <linux/vmalloc.h>
0007
0008 #include "debugfs.h"
0009
0010 #include "core.h"
0011 #include "debug.h"
0012 #include "wmi.h"
0013 #include "hal_rx.h"
0014 #include "dp_tx.h"
0015 #include "debugfs_htt_stats.h"
0016 #include "peer.h"
0017
0018 static const char *htt_bp_umac_ring[HTT_SW_UMAC_RING_IDX_MAX] = {
0019 "REO2SW1_RING",
0020 "REO2SW2_RING",
0021 "REO2SW3_RING",
0022 "REO2SW4_RING",
0023 "WBM2REO_LINK_RING",
0024 "REO2TCL_RING",
0025 "REO2FW_RING",
0026 "RELEASE_RING",
0027 "PPE_RELEASE_RING",
0028 "TCL2TQM_RING",
0029 "TQM_RELEASE_RING",
0030 "REO_RELEASE_RING",
0031 "WBM2SW0_RELEASE_RING",
0032 "WBM2SW1_RELEASE_RING",
0033 "WBM2SW2_RELEASE_RING",
0034 "WBM2SW3_RELEASE_RING",
0035 "REO_CMD_RING",
0036 "REO_STATUS_RING",
0037 };
0038
0039 static const char *htt_bp_lmac_ring[HTT_SW_LMAC_RING_IDX_MAX] = {
0040 "FW2RXDMA_BUF_RING",
0041 "FW2RXDMA_STATUS_RING",
0042 "FW2RXDMA_LINK_RING",
0043 "SW2RXDMA_BUF_RING",
0044 "WBM2RXDMA_LINK_RING",
0045 "RXDMA2FW_RING",
0046 "RXDMA2SW_RING",
0047 "RXDMA2RELEASE_RING",
0048 "RXDMA2REO_RING",
0049 "MONITOR_STATUS_RING",
0050 "MONITOR_BUF_RING",
0051 "MONITOR_DESC_RING",
0052 "MONITOR_DEST_RING",
0053 };
0054
0055 void ath11k_debugfs_add_dbring_entry(struct ath11k *ar,
0056 enum wmi_direct_buffer_module id,
0057 enum ath11k_dbg_dbr_event event,
0058 struct hal_srng *srng)
0059 {
0060 struct ath11k_debug_dbr *dbr_debug;
0061 struct ath11k_dbg_dbr_data *dbr_data;
0062 struct ath11k_dbg_dbr_entry *entry;
0063
0064 if (id >= WMI_DIRECT_BUF_MAX || event >= ATH11K_DBG_DBR_EVENT_MAX)
0065 return;
0066
0067 dbr_debug = ar->debug.dbr_debug[id];
0068 if (!dbr_debug)
0069 return;
0070
0071 if (!dbr_debug->dbr_debug_enabled)
0072 return;
0073
0074 dbr_data = &dbr_debug->dbr_dbg_data;
0075
0076 spin_lock_bh(&dbr_data->lock);
0077
0078 if (dbr_data->entries) {
0079 entry = &dbr_data->entries[dbr_data->dbr_debug_idx];
0080 entry->hp = srng->u.src_ring.hp;
0081 entry->tp = *srng->u.src_ring.tp_addr;
0082 entry->timestamp = jiffies;
0083 entry->event = event;
0084
0085 dbr_data->dbr_debug_idx++;
0086 if (dbr_data->dbr_debug_idx ==
0087 dbr_data->num_ring_debug_entries)
0088 dbr_data->dbr_debug_idx = 0;
0089 }
0090
0091 spin_unlock_bh(&dbr_data->lock);
0092 }
0093
0094 static void ath11k_fw_stats_pdevs_free(struct list_head *head)
0095 {
0096 struct ath11k_fw_stats_pdev *i, *tmp;
0097
0098 list_for_each_entry_safe(i, tmp, head, list) {
0099 list_del(&i->list);
0100 kfree(i);
0101 }
0102 }
0103
0104 static void ath11k_fw_stats_vdevs_free(struct list_head *head)
0105 {
0106 struct ath11k_fw_stats_vdev *i, *tmp;
0107
0108 list_for_each_entry_safe(i, tmp, head, list) {
0109 list_del(&i->list);
0110 kfree(i);
0111 }
0112 }
0113
0114 static void ath11k_fw_stats_bcn_free(struct list_head *head)
0115 {
0116 struct ath11k_fw_stats_bcn *i, *tmp;
0117
0118 list_for_each_entry_safe(i, tmp, head, list) {
0119 list_del(&i->list);
0120 kfree(i);
0121 }
0122 }
0123
0124 static void ath11k_debugfs_fw_stats_reset(struct ath11k *ar)
0125 {
0126 spin_lock_bh(&ar->data_lock);
0127 ar->debug.fw_stats_done = false;
0128 ath11k_fw_stats_pdevs_free(&ar->debug.fw_stats.pdevs);
0129 ath11k_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs);
0130 spin_unlock_bh(&ar->data_lock);
0131 }
0132
0133 void ath11k_debugfs_fw_stats_process(struct ath11k_base *ab, struct sk_buff *skb)
0134 {
0135 struct ath11k_fw_stats stats = {};
0136 struct ath11k *ar;
0137 struct ath11k_pdev *pdev;
0138 bool is_end;
0139 static unsigned int num_vdev, num_bcn;
0140 size_t total_vdevs_started = 0;
0141 int i, ret;
0142
0143 INIT_LIST_HEAD(&stats.pdevs);
0144 INIT_LIST_HEAD(&stats.vdevs);
0145 INIT_LIST_HEAD(&stats.bcn);
0146
0147 ret = ath11k_wmi_pull_fw_stats(ab, skb, &stats);
0148 if (ret) {
0149 ath11k_warn(ab, "failed to pull fw stats: %d\n", ret);
0150 goto free;
0151 }
0152
0153 rcu_read_lock();
0154 ar = ath11k_mac_get_ar_by_pdev_id(ab, stats.pdev_id);
0155 if (!ar) {
0156 rcu_read_unlock();
0157 ath11k_warn(ab, "failed to get ar for pdev_id %d: %d\n",
0158 stats.pdev_id, ret);
0159 goto free;
0160 }
0161
0162 spin_lock_bh(&ar->data_lock);
0163
0164 if (stats.stats_id == WMI_REQUEST_PDEV_STAT) {
0165 list_splice_tail_init(&stats.pdevs, &ar->debug.fw_stats.pdevs);
0166 ar->debug.fw_stats_done = true;
0167 goto complete;
0168 }
0169
0170 if (stats.stats_id == WMI_REQUEST_RSSI_PER_CHAIN_STAT) {
0171 ar->debug.fw_stats_done = true;
0172 goto complete;
0173 }
0174
0175 if (stats.stats_id == WMI_REQUEST_VDEV_STAT) {
0176 if (list_empty(&stats.vdevs)) {
0177 ath11k_warn(ab, "empty vdev stats");
0178 goto complete;
0179 }
0180
0181
0182
0183 for (i = 0; i < ab->num_radios; i++) {
0184 pdev = rcu_dereference(ab->pdevs_active[i]);
0185 if (pdev && pdev->ar)
0186 total_vdevs_started += ar->num_started_vdevs;
0187 }
0188
0189 is_end = ((++num_vdev) == total_vdevs_started);
0190
0191 list_splice_tail_init(&stats.vdevs,
0192 &ar->debug.fw_stats.vdevs);
0193
0194 if (is_end) {
0195 ar->debug.fw_stats_done = true;
0196 num_vdev = 0;
0197 }
0198 goto complete;
0199 }
0200
0201 if (stats.stats_id == WMI_REQUEST_BCN_STAT) {
0202 if (list_empty(&stats.bcn)) {
0203 ath11k_warn(ab, "empty bcn stats");
0204 goto complete;
0205 }
0206
0207
0208
0209 is_end = ((++num_bcn) == ar->num_started_vdevs);
0210
0211 list_splice_tail_init(&stats.bcn,
0212 &ar->debug.fw_stats.bcn);
0213
0214 if (is_end) {
0215 ar->debug.fw_stats_done = true;
0216 num_bcn = 0;
0217 }
0218 }
0219 complete:
0220 complete(&ar->debug.fw_stats_complete);
0221 rcu_read_unlock();
0222 spin_unlock_bh(&ar->data_lock);
0223
0224 free:
0225 ath11k_fw_stats_pdevs_free(&stats.pdevs);
0226 ath11k_fw_stats_vdevs_free(&stats.vdevs);
0227 ath11k_fw_stats_bcn_free(&stats.bcn);
0228 }
0229
0230 static int ath11k_debugfs_fw_stats_request(struct ath11k *ar,
0231 struct stats_request_params *req_param)
0232 {
0233 struct ath11k_base *ab = ar->ab;
0234 unsigned long timeout, time_left;
0235 int ret;
0236
0237 lockdep_assert_held(&ar->conf_mutex);
0238
0239
0240
0241
0242
0243
0244 timeout = jiffies + msecs_to_jiffies(3 * 1000);
0245
0246 ath11k_debugfs_fw_stats_reset(ar);
0247
0248 reinit_completion(&ar->debug.fw_stats_complete);
0249
0250 ret = ath11k_wmi_send_stats_request_cmd(ar, req_param);
0251
0252 if (ret) {
0253 ath11k_warn(ab, "could not request fw stats (%d)\n",
0254 ret);
0255 return ret;
0256 }
0257
0258 time_left =
0259 wait_for_completion_timeout(&ar->debug.fw_stats_complete,
0260 1 * HZ);
0261 if (!time_left)
0262 return -ETIMEDOUT;
0263
0264 for (;;) {
0265 if (time_after(jiffies, timeout))
0266 break;
0267
0268 spin_lock_bh(&ar->data_lock);
0269 if (ar->debug.fw_stats_done) {
0270 spin_unlock_bh(&ar->data_lock);
0271 break;
0272 }
0273 spin_unlock_bh(&ar->data_lock);
0274 }
0275 return 0;
0276 }
0277
0278 int ath11k_debugfs_get_fw_stats(struct ath11k *ar, u32 pdev_id,
0279 u32 vdev_id, u32 stats_id)
0280 {
0281 struct ath11k_base *ab = ar->ab;
0282 struct stats_request_params req_param;
0283 int ret;
0284
0285 mutex_lock(&ar->conf_mutex);
0286
0287 if (ar->state != ATH11K_STATE_ON) {
0288 ret = -ENETDOWN;
0289 goto err_unlock;
0290 }
0291
0292 req_param.pdev_id = pdev_id;
0293 req_param.vdev_id = vdev_id;
0294 req_param.stats_id = stats_id;
0295
0296 ret = ath11k_debugfs_fw_stats_request(ar, &req_param);
0297 if (ret)
0298 ath11k_warn(ab, "failed to request fw stats: %d\n", ret);
0299
0300 ath11k_dbg(ab, ATH11K_DBG_WMI,
0301 "debug get fw stat pdev id %d vdev id %d stats id 0x%x\n",
0302 pdev_id, vdev_id, stats_id);
0303
0304 err_unlock:
0305 mutex_unlock(&ar->conf_mutex);
0306
0307 return ret;
0308 }
0309
0310 static int ath11k_open_pdev_stats(struct inode *inode, struct file *file)
0311 {
0312 struct ath11k *ar = inode->i_private;
0313 struct ath11k_base *ab = ar->ab;
0314 struct stats_request_params req_param;
0315 void *buf = NULL;
0316 int ret;
0317
0318 mutex_lock(&ar->conf_mutex);
0319
0320 if (ar->state != ATH11K_STATE_ON) {
0321 ret = -ENETDOWN;
0322 goto err_unlock;
0323 }
0324
0325 buf = vmalloc(ATH11K_FW_STATS_BUF_SIZE);
0326 if (!buf) {
0327 ret = -ENOMEM;
0328 goto err_unlock;
0329 }
0330
0331 req_param.pdev_id = ar->pdev->pdev_id;
0332 req_param.vdev_id = 0;
0333 req_param.stats_id = WMI_REQUEST_PDEV_STAT;
0334
0335 ret = ath11k_debugfs_fw_stats_request(ar, &req_param);
0336 if (ret) {
0337 ath11k_warn(ab, "failed to request fw pdev stats: %d\n", ret);
0338 goto err_free;
0339 }
0340
0341 ath11k_wmi_fw_stats_fill(ar, &ar->debug.fw_stats, req_param.stats_id,
0342 buf);
0343
0344 file->private_data = buf;
0345
0346 mutex_unlock(&ar->conf_mutex);
0347 return 0;
0348
0349 err_free:
0350 vfree(buf);
0351
0352 err_unlock:
0353 mutex_unlock(&ar->conf_mutex);
0354 return ret;
0355 }
0356
0357 static int ath11k_release_pdev_stats(struct inode *inode, struct file *file)
0358 {
0359 vfree(file->private_data);
0360
0361 return 0;
0362 }
0363
0364 static ssize_t ath11k_read_pdev_stats(struct file *file,
0365 char __user *user_buf,
0366 size_t count, loff_t *ppos)
0367 {
0368 const char *buf = file->private_data;
0369 size_t len = strlen(buf);
0370
0371 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
0372 }
0373
0374 static const struct file_operations fops_pdev_stats = {
0375 .open = ath11k_open_pdev_stats,
0376 .release = ath11k_release_pdev_stats,
0377 .read = ath11k_read_pdev_stats,
0378 .owner = THIS_MODULE,
0379 .llseek = default_llseek,
0380 };
0381
0382 static int ath11k_open_vdev_stats(struct inode *inode, struct file *file)
0383 {
0384 struct ath11k *ar = inode->i_private;
0385 struct stats_request_params req_param;
0386 void *buf = NULL;
0387 int ret;
0388
0389 mutex_lock(&ar->conf_mutex);
0390
0391 if (ar->state != ATH11K_STATE_ON) {
0392 ret = -ENETDOWN;
0393 goto err_unlock;
0394 }
0395
0396 buf = vmalloc(ATH11K_FW_STATS_BUF_SIZE);
0397 if (!buf) {
0398 ret = -ENOMEM;
0399 goto err_unlock;
0400 }
0401
0402 req_param.pdev_id = ar->pdev->pdev_id;
0403
0404 req_param.vdev_id = 0;
0405 req_param.stats_id = WMI_REQUEST_VDEV_STAT;
0406
0407 ret = ath11k_debugfs_fw_stats_request(ar, &req_param);
0408 if (ret) {
0409 ath11k_warn(ar->ab, "failed to request fw vdev stats: %d\n", ret);
0410 goto err_free;
0411 }
0412
0413 ath11k_wmi_fw_stats_fill(ar, &ar->debug.fw_stats, req_param.stats_id,
0414 buf);
0415
0416 file->private_data = buf;
0417
0418 mutex_unlock(&ar->conf_mutex);
0419 return 0;
0420
0421 err_free:
0422 vfree(buf);
0423
0424 err_unlock:
0425 mutex_unlock(&ar->conf_mutex);
0426 return ret;
0427 }
0428
0429 static int ath11k_release_vdev_stats(struct inode *inode, struct file *file)
0430 {
0431 vfree(file->private_data);
0432
0433 return 0;
0434 }
0435
0436 static ssize_t ath11k_read_vdev_stats(struct file *file,
0437 char __user *user_buf,
0438 size_t count, loff_t *ppos)
0439 {
0440 const char *buf = file->private_data;
0441 size_t len = strlen(buf);
0442
0443 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
0444 }
0445
0446 static const struct file_operations fops_vdev_stats = {
0447 .open = ath11k_open_vdev_stats,
0448 .release = ath11k_release_vdev_stats,
0449 .read = ath11k_read_vdev_stats,
0450 .owner = THIS_MODULE,
0451 .llseek = default_llseek,
0452 };
0453
0454 static int ath11k_open_bcn_stats(struct inode *inode, struct file *file)
0455 {
0456 struct ath11k *ar = inode->i_private;
0457 struct ath11k_vif *arvif;
0458 struct stats_request_params req_param;
0459 void *buf = NULL;
0460 int ret;
0461
0462 mutex_lock(&ar->conf_mutex);
0463
0464 if (ar->state != ATH11K_STATE_ON) {
0465 ret = -ENETDOWN;
0466 goto err_unlock;
0467 }
0468
0469 buf = vmalloc(ATH11K_FW_STATS_BUF_SIZE);
0470 if (!buf) {
0471 ret = -ENOMEM;
0472 goto err_unlock;
0473 }
0474
0475 req_param.stats_id = WMI_REQUEST_BCN_STAT;
0476 req_param.pdev_id = ar->pdev->pdev_id;
0477
0478
0479 list_for_each_entry(arvif, &ar->arvifs, list) {
0480 if (!arvif->is_up)
0481 continue;
0482
0483 req_param.vdev_id = arvif->vdev_id;
0484 ret = ath11k_debugfs_fw_stats_request(ar, &req_param);
0485 if (ret) {
0486 ath11k_warn(ar->ab, "failed to request fw bcn stats: %d\n", ret);
0487 goto err_free;
0488 }
0489 }
0490
0491 ath11k_wmi_fw_stats_fill(ar, &ar->debug.fw_stats, req_param.stats_id,
0492 buf);
0493
0494
0495
0496
0497 spin_lock_bh(&ar->data_lock);
0498 ath11k_fw_stats_bcn_free(&ar->debug.fw_stats.bcn);
0499 spin_unlock_bh(&ar->data_lock);
0500
0501 file->private_data = buf;
0502
0503 mutex_unlock(&ar->conf_mutex);
0504 return 0;
0505
0506 err_free:
0507 vfree(buf);
0508
0509 err_unlock:
0510 mutex_unlock(&ar->conf_mutex);
0511 return ret;
0512 }
0513
0514 static int ath11k_release_bcn_stats(struct inode *inode, struct file *file)
0515 {
0516 vfree(file->private_data);
0517
0518 return 0;
0519 }
0520
0521 static ssize_t ath11k_read_bcn_stats(struct file *file,
0522 char __user *user_buf,
0523 size_t count, loff_t *ppos)
0524 {
0525 const char *buf = file->private_data;
0526 size_t len = strlen(buf);
0527
0528 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
0529 }
0530
0531 static const struct file_operations fops_bcn_stats = {
0532 .open = ath11k_open_bcn_stats,
0533 .release = ath11k_release_bcn_stats,
0534 .read = ath11k_read_bcn_stats,
0535 .owner = THIS_MODULE,
0536 .llseek = default_llseek,
0537 };
0538
0539 static ssize_t ath11k_read_simulate_fw_crash(struct file *file,
0540 char __user *user_buf,
0541 size_t count, loff_t *ppos)
0542 {
0543 const char buf[] =
0544 "To simulate firmware crash write one of the keywords to this file:\n"
0545 "`assert` - this will send WMI_FORCE_FW_HANG_CMDID to firmware to cause assert.\n"
0546 "`hw-restart` - this will simply queue hw restart without fw/hw actually crashing.\n";
0547
0548 return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
0549 }
0550
0551
0552
0553
0554
0555
0556
0557
0558 static ssize_t ath11k_write_simulate_fw_crash(struct file *file,
0559 const char __user *user_buf,
0560 size_t count, loff_t *ppos)
0561 {
0562 struct ath11k_base *ab = file->private_data;
0563 struct ath11k_pdev *pdev;
0564 struct ath11k *ar = ab->pdevs[0].ar;
0565 char buf[32] = {0};
0566 ssize_t rc;
0567 int i, ret, radioup = 0;
0568
0569 for (i = 0; i < ab->num_radios; i++) {
0570 pdev = &ab->pdevs[i];
0571 ar = pdev->ar;
0572 if (ar && ar->state == ATH11K_STATE_ON) {
0573 radioup = 1;
0574 break;
0575 }
0576 }
0577
0578 if (*ppos != 0 || count >= sizeof(buf) || count == 0)
0579 return -EINVAL;
0580
0581 rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
0582 if (rc < 0)
0583 return rc;
0584
0585
0586 if (buf[*ppos - 1] == '\n')
0587 buf[*ppos - 1] = '\0';
0588
0589 if (radioup == 0) {
0590 ret = -ENETDOWN;
0591 goto exit;
0592 }
0593
0594 if (!strcmp(buf, "assert")) {
0595 ath11k_info(ab, "simulating firmware assert crash\n");
0596 ret = ath11k_wmi_force_fw_hang_cmd(ar,
0597 ATH11K_WMI_FW_HANG_ASSERT_TYPE,
0598 ATH11K_WMI_FW_HANG_DELAY);
0599 } else if (!strcmp(buf, "hw-restart")) {
0600 ath11k_info(ab, "user requested hw restart\n");
0601 queue_work(ab->workqueue_aux, &ab->reset_work);
0602 ret = 0;
0603 } else {
0604 ret = -EINVAL;
0605 goto exit;
0606 }
0607
0608 if (ret) {
0609 ath11k_warn(ab, "failed to simulate firmware crash: %d\n", ret);
0610 goto exit;
0611 }
0612
0613 ret = count;
0614
0615 exit:
0616 return ret;
0617 }
0618
0619 static const struct file_operations fops_simulate_fw_crash = {
0620 .read = ath11k_read_simulate_fw_crash,
0621 .write = ath11k_write_simulate_fw_crash,
0622 .open = simple_open,
0623 .owner = THIS_MODULE,
0624 .llseek = default_llseek,
0625 };
0626
0627 static ssize_t ath11k_write_enable_extd_tx_stats(struct file *file,
0628 const char __user *ubuf,
0629 size_t count, loff_t *ppos)
0630 {
0631 struct ath11k *ar = file->private_data;
0632 u32 filter;
0633 int ret;
0634
0635 if (kstrtouint_from_user(ubuf, count, 0, &filter))
0636 return -EINVAL;
0637
0638 mutex_lock(&ar->conf_mutex);
0639
0640 if (ar->state != ATH11K_STATE_ON) {
0641 ret = -ENETDOWN;
0642 goto out;
0643 }
0644
0645 if (filter == ar->debug.extd_tx_stats) {
0646 ret = count;
0647 goto out;
0648 }
0649
0650 ar->debug.extd_tx_stats = filter;
0651 ret = count;
0652
0653 out:
0654 mutex_unlock(&ar->conf_mutex);
0655 return ret;
0656 }
0657
0658 static ssize_t ath11k_read_enable_extd_tx_stats(struct file *file,
0659 char __user *ubuf,
0660 size_t count, loff_t *ppos)
0661
0662 {
0663 char buf[32] = {0};
0664 struct ath11k *ar = file->private_data;
0665 int len = 0;
0666
0667 mutex_lock(&ar->conf_mutex);
0668 len = scnprintf(buf, sizeof(buf) - len, "%08x\n",
0669 ar->debug.extd_tx_stats);
0670 mutex_unlock(&ar->conf_mutex);
0671
0672 return simple_read_from_buffer(ubuf, count, ppos, buf, len);
0673 }
0674
0675 static const struct file_operations fops_extd_tx_stats = {
0676 .read = ath11k_read_enable_extd_tx_stats,
0677 .write = ath11k_write_enable_extd_tx_stats,
0678 .open = simple_open
0679 };
0680
0681 static ssize_t ath11k_write_extd_rx_stats(struct file *file,
0682 const char __user *ubuf,
0683 size_t count, loff_t *ppos)
0684 {
0685 struct ath11k *ar = file->private_data;
0686 struct ath11k_base *ab = ar->ab;
0687 struct htt_rx_ring_tlv_filter tlv_filter = {0};
0688 u32 enable, rx_filter = 0, ring_id;
0689 int i;
0690 int ret;
0691
0692 if (kstrtouint_from_user(ubuf, count, 0, &enable))
0693 return -EINVAL;
0694
0695 mutex_lock(&ar->conf_mutex);
0696
0697 if (ar->state != ATH11K_STATE_ON) {
0698 ret = -ENETDOWN;
0699 goto exit;
0700 }
0701
0702 if (enable > 1) {
0703 ret = -EINVAL;
0704 goto exit;
0705 }
0706
0707 if (enable == ar->debug.extd_rx_stats) {
0708 ret = count;
0709 goto exit;
0710 }
0711
0712 if (test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags)) {
0713 ar->debug.extd_rx_stats = enable;
0714 ret = count;
0715 goto exit;
0716 }
0717
0718 if (enable) {
0719 rx_filter = HTT_RX_FILTER_TLV_FLAGS_MPDU_START;
0720 rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_START;
0721 rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END;
0722 rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS;
0723 rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS_EXT;
0724 rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END_STATUS_DONE;
0725
0726 tlv_filter.rx_filter = rx_filter;
0727 tlv_filter.pkt_filter_flags0 = HTT_RX_FP_MGMT_FILTER_FLAGS0;
0728 tlv_filter.pkt_filter_flags1 = HTT_RX_FP_MGMT_FILTER_FLAGS1;
0729 tlv_filter.pkt_filter_flags2 = HTT_RX_FP_CTRL_FILTER_FLASG2;
0730 tlv_filter.pkt_filter_flags3 = HTT_RX_FP_CTRL_FILTER_FLASG3 |
0731 HTT_RX_FP_DATA_FILTER_FLASG3;
0732 } else {
0733 tlv_filter = ath11k_mac_mon_status_filter_default;
0734 }
0735
0736 ar->debug.rx_filter = tlv_filter.rx_filter;
0737
0738 for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) {
0739 ring_id = ar->dp.rx_mon_status_refill_ring[i].refill_buf_ring.ring_id;
0740 ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, ar->dp.mac_id,
0741 HAL_RXDMA_MONITOR_STATUS,
0742 DP_RX_BUFFER_SIZE, &tlv_filter);
0743
0744 if (ret) {
0745 ath11k_warn(ar->ab, "failed to set rx filter for monitor status ring\n");
0746 goto exit;
0747 }
0748 }
0749
0750 ar->debug.extd_rx_stats = enable;
0751 ret = count;
0752 exit:
0753 mutex_unlock(&ar->conf_mutex);
0754 return ret;
0755 }
0756
0757 static ssize_t ath11k_read_extd_rx_stats(struct file *file,
0758 char __user *ubuf,
0759 size_t count, loff_t *ppos)
0760 {
0761 struct ath11k *ar = file->private_data;
0762 char buf[32];
0763 int len = 0;
0764
0765 mutex_lock(&ar->conf_mutex);
0766 len = scnprintf(buf, sizeof(buf) - len, "%d\n",
0767 ar->debug.extd_rx_stats);
0768 mutex_unlock(&ar->conf_mutex);
0769
0770 return simple_read_from_buffer(ubuf, count, ppos, buf, len);
0771 }
0772
0773 static const struct file_operations fops_extd_rx_stats = {
0774 .read = ath11k_read_extd_rx_stats,
0775 .write = ath11k_write_extd_rx_stats,
0776 .open = simple_open,
0777 };
0778
0779 static int ath11k_fill_bp_stats(struct ath11k_base *ab,
0780 struct ath11k_bp_stats *bp_stats,
0781 char *buf, int len, int size)
0782 {
0783 lockdep_assert_held(&ab->base_lock);
0784
0785 len += scnprintf(buf + len, size - len, "count: %u\n",
0786 bp_stats->count);
0787 len += scnprintf(buf + len, size - len, "hp: %u\n",
0788 bp_stats->hp);
0789 len += scnprintf(buf + len, size - len, "tp: %u\n",
0790 bp_stats->tp);
0791 len += scnprintf(buf + len, size - len, "seen before: %ums\n\n",
0792 jiffies_to_msecs(jiffies - bp_stats->jiffies));
0793 return len;
0794 }
0795
0796 static ssize_t ath11k_debugfs_dump_soc_ring_bp_stats(struct ath11k_base *ab,
0797 char *buf, int size)
0798 {
0799 struct ath11k_bp_stats *bp_stats;
0800 bool stats_rxd = false;
0801 u8 i, pdev_idx;
0802 int len = 0;
0803
0804 len += scnprintf(buf + len, size - len, "\nBackpressure Stats\n");
0805 len += scnprintf(buf + len, size - len, "==================\n");
0806
0807 spin_lock_bh(&ab->base_lock);
0808 for (i = 0; i < HTT_SW_UMAC_RING_IDX_MAX; i++) {
0809 bp_stats = &ab->soc_stats.bp_stats.umac_ring_bp_stats[i];
0810
0811 if (!bp_stats->count)
0812 continue;
0813
0814 len += scnprintf(buf + len, size - len, "Ring: %s\n",
0815 htt_bp_umac_ring[i]);
0816 len = ath11k_fill_bp_stats(ab, bp_stats, buf, len, size);
0817 stats_rxd = true;
0818 }
0819
0820 for (i = 0; i < HTT_SW_LMAC_RING_IDX_MAX; i++) {
0821 for (pdev_idx = 0; pdev_idx < MAX_RADIOS; pdev_idx++) {
0822 bp_stats =
0823 &ab->soc_stats.bp_stats.lmac_ring_bp_stats[i][pdev_idx];
0824
0825 if (!bp_stats->count)
0826 continue;
0827
0828 len += scnprintf(buf + len, size - len, "Ring: %s\n",
0829 htt_bp_lmac_ring[i]);
0830 len += scnprintf(buf + len, size - len, "pdev: %d\n",
0831 pdev_idx);
0832 len = ath11k_fill_bp_stats(ab, bp_stats, buf, len, size);
0833 stats_rxd = true;
0834 }
0835 }
0836 spin_unlock_bh(&ab->base_lock);
0837
0838 if (!stats_rxd)
0839 len += scnprintf(buf + len, size - len,
0840 "No Ring Backpressure stats received\n\n");
0841
0842 return len;
0843 }
0844
0845 static ssize_t ath11k_debugfs_dump_soc_dp_stats(struct file *file,
0846 char __user *user_buf,
0847 size_t count, loff_t *ppos)
0848 {
0849 struct ath11k_base *ab = file->private_data;
0850 struct ath11k_soc_dp_stats *soc_stats = &ab->soc_stats;
0851 int len = 0, i, retval;
0852 const int size = 4096;
0853 static const char *rxdma_err[HAL_REO_ENTR_RING_RXDMA_ECODE_MAX] = {
0854 "Overflow", "MPDU len", "FCS", "Decrypt", "TKIP MIC",
0855 "Unencrypt", "MSDU len", "MSDU limit", "WiFi parse",
0856 "AMSDU parse", "SA timeout", "DA timeout",
0857 "Flow timeout", "Flush req"};
0858 static const char *reo_err[HAL_REO_DEST_RING_ERROR_CODE_MAX] = {
0859 "Desc addr zero", "Desc inval", "AMPDU in non BA",
0860 "Non BA dup", "BA dup", "Frame 2k jump", "BAR 2k jump",
0861 "Frame OOR", "BAR OOR", "No BA session",
0862 "Frame SN equal SSN", "PN check fail", "2k err",
0863 "PN err", "Desc blocked"};
0864
0865 char *buf;
0866
0867 buf = kzalloc(size, GFP_KERNEL);
0868 if (!buf)
0869 return -ENOMEM;
0870
0871 len += scnprintf(buf + len, size - len, "SOC RX STATS:\n\n");
0872 len += scnprintf(buf + len, size - len, "err ring pkts: %u\n",
0873 soc_stats->err_ring_pkts);
0874 len += scnprintf(buf + len, size - len, "Invalid RBM: %u\n\n",
0875 soc_stats->invalid_rbm);
0876 len += scnprintf(buf + len, size - len, "RXDMA errors:\n");
0877 for (i = 0; i < HAL_REO_ENTR_RING_RXDMA_ECODE_MAX; i++)
0878 len += scnprintf(buf + len, size - len, "%s: %u\n",
0879 rxdma_err[i], soc_stats->rxdma_error[i]);
0880
0881 len += scnprintf(buf + len, size - len, "\nREO errors:\n");
0882 for (i = 0; i < HAL_REO_DEST_RING_ERROR_CODE_MAX; i++)
0883 len += scnprintf(buf + len, size - len, "%s: %u\n",
0884 reo_err[i], soc_stats->reo_error[i]);
0885
0886 len += scnprintf(buf + len, size - len, "\nHAL REO errors:\n");
0887 len += scnprintf(buf + len, size - len,
0888 "ring0: %u\nring1: %u\nring2: %u\nring3: %u\n",
0889 soc_stats->hal_reo_error[0],
0890 soc_stats->hal_reo_error[1],
0891 soc_stats->hal_reo_error[2],
0892 soc_stats->hal_reo_error[3]);
0893
0894 len += scnprintf(buf + len, size - len, "\nSOC TX STATS:\n");
0895 len += scnprintf(buf + len, size - len, "\nTCL Ring Full Failures:\n");
0896
0897 for (i = 0; i < ab->hw_params.max_tx_ring; i++)
0898 len += scnprintf(buf + len, size - len, "ring%d: %u\n",
0899 i, soc_stats->tx_err.desc_na[i]);
0900
0901 len += scnprintf(buf + len, size - len,
0902 "\nMisc Transmit Failures: %d\n",
0903 atomic_read(&soc_stats->tx_err.misc_fail));
0904
0905 len += ath11k_debugfs_dump_soc_ring_bp_stats(ab, buf + len, size - len);
0906
0907 if (len > size)
0908 len = size;
0909 retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
0910 kfree(buf);
0911
0912 return retval;
0913 }
0914
0915 static const struct file_operations fops_soc_dp_stats = {
0916 .read = ath11k_debugfs_dump_soc_dp_stats,
0917 .open = simple_open,
0918 .owner = THIS_MODULE,
0919 .llseek = default_llseek,
0920 };
0921
0922 static ssize_t ath11k_write_fw_dbglog(struct file *file,
0923 const char __user *user_buf,
0924 size_t count, loff_t *ppos)
0925 {
0926 struct ath11k *ar = file->private_data;
0927 char buf[128] = {0};
0928 struct ath11k_fw_dbglog dbglog;
0929 unsigned int param, mod_id_index, is_end;
0930 u64 value;
0931 int ret, num;
0932
0933 ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
0934 user_buf, count);
0935 if (ret <= 0)
0936 return ret;
0937
0938 num = sscanf(buf, "%u %llx %u %u", ¶m, &value, &mod_id_index, &is_end);
0939
0940 if (num < 2)
0941 return -EINVAL;
0942
0943 mutex_lock(&ar->conf_mutex);
0944 if (param == WMI_DEBUG_LOG_PARAM_MOD_ENABLE_BITMAP ||
0945 param == WMI_DEBUG_LOG_PARAM_WOW_MOD_ENABLE_BITMAP) {
0946 if (num != 4 || mod_id_index > (MAX_MODULE_ID_BITMAP_WORDS - 1)) {
0947 ret = -EINVAL;
0948 goto out;
0949 }
0950 ar->debug.module_id_bitmap[mod_id_index] = upper_32_bits(value);
0951 if (!is_end) {
0952 ret = count;
0953 goto out;
0954 }
0955 } else {
0956 if (num != 2) {
0957 ret = -EINVAL;
0958 goto out;
0959 }
0960 }
0961
0962 dbglog.param = param;
0963 dbglog.value = lower_32_bits(value);
0964 ret = ath11k_wmi_fw_dbglog_cfg(ar, ar->debug.module_id_bitmap, &dbglog);
0965 if (ret) {
0966 ath11k_warn(ar->ab, "fw dbglog config failed from debugfs: %d\n",
0967 ret);
0968 goto out;
0969 }
0970
0971 ret = count;
0972
0973 out:
0974 mutex_unlock(&ar->conf_mutex);
0975 return ret;
0976 }
0977
0978 static const struct file_operations fops_fw_dbglog = {
0979 .write = ath11k_write_fw_dbglog,
0980 .open = simple_open,
0981 .owner = THIS_MODULE,
0982 .llseek = default_llseek,
0983 };
0984
0985 int ath11k_debugfs_pdev_create(struct ath11k_base *ab)
0986 {
0987 if (test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags))
0988 return 0;
0989
0990 ab->debugfs_soc = debugfs_create_dir(ab->hw_params.name, ab->debugfs_ath11k);
0991 if (IS_ERR(ab->debugfs_soc))
0992 return PTR_ERR(ab->debugfs_soc);
0993
0994 debugfs_create_file("simulate_fw_crash", 0600, ab->debugfs_soc, ab,
0995 &fops_simulate_fw_crash);
0996
0997 debugfs_create_file("soc_dp_stats", 0600, ab->debugfs_soc, ab,
0998 &fops_soc_dp_stats);
0999
1000 return 0;
1001 }
1002
1003 void ath11k_debugfs_pdev_destroy(struct ath11k_base *ab)
1004 {
1005 debugfs_remove_recursive(ab->debugfs_soc);
1006 ab->debugfs_soc = NULL;
1007 }
1008
1009 int ath11k_debugfs_soc_create(struct ath11k_base *ab)
1010 {
1011 ab->debugfs_ath11k = debugfs_create_dir("ath11k", NULL);
1012
1013 return PTR_ERR_OR_ZERO(ab->debugfs_ath11k);
1014 }
1015
1016 void ath11k_debugfs_soc_destroy(struct ath11k_base *ab)
1017 {
1018 debugfs_remove_recursive(ab->debugfs_ath11k);
1019 ab->debugfs_ath11k = NULL;
1020 }
1021 EXPORT_SYMBOL(ath11k_debugfs_soc_destroy);
1022
1023 void ath11k_debugfs_fw_stats_init(struct ath11k *ar)
1024 {
1025 struct dentry *fwstats_dir = debugfs_create_dir("fw_stats",
1026 ar->debug.debugfs_pdev);
1027
1028 ar->debug.fw_stats.debugfs_fwstats = fwstats_dir;
1029
1030
1031
1032
1033 debugfs_create_file("pdev_stats", 0600, fwstats_dir, ar,
1034 &fops_pdev_stats);
1035 debugfs_create_file("vdev_stats", 0600, fwstats_dir, ar,
1036 &fops_vdev_stats);
1037 debugfs_create_file("beacon_stats", 0600, fwstats_dir, ar,
1038 &fops_bcn_stats);
1039
1040 INIT_LIST_HEAD(&ar->debug.fw_stats.pdevs);
1041 INIT_LIST_HEAD(&ar->debug.fw_stats.vdevs);
1042 INIT_LIST_HEAD(&ar->debug.fw_stats.bcn);
1043
1044 init_completion(&ar->debug.fw_stats_complete);
1045 }
1046
1047 static ssize_t ath11k_write_pktlog_filter(struct file *file,
1048 const char __user *ubuf,
1049 size_t count, loff_t *ppos)
1050 {
1051 struct ath11k *ar = file->private_data;
1052 struct ath11k_base *ab = ar->ab;
1053 struct htt_rx_ring_tlv_filter tlv_filter = {0};
1054 u32 rx_filter = 0, ring_id, filter, mode;
1055 u8 buf[128] = {0};
1056 int i, ret, rx_buf_sz = 0;
1057 ssize_t rc;
1058
1059 mutex_lock(&ar->conf_mutex);
1060 if (ar->state != ATH11K_STATE_ON) {
1061 ret = -ENETDOWN;
1062 goto out;
1063 }
1064
1065 rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count);
1066 if (rc < 0) {
1067 ret = rc;
1068 goto out;
1069 }
1070 buf[rc] = '\0';
1071
1072 ret = sscanf(buf, "0x%x %u", &filter, &mode);
1073 if (ret != 2) {
1074 ret = -EINVAL;
1075 goto out;
1076 }
1077
1078 if (filter) {
1079 ret = ath11k_wmi_pdev_pktlog_enable(ar, filter);
1080 if (ret) {
1081 ath11k_warn(ar->ab,
1082 "failed to enable pktlog filter %x: %d\n",
1083 ar->debug.pktlog_filter, ret);
1084 goto out;
1085 }
1086 } else {
1087 ret = ath11k_wmi_pdev_pktlog_disable(ar);
1088 if (ret) {
1089 ath11k_warn(ar->ab, "failed to disable pktlog: %d\n", ret);
1090 goto out;
1091 }
1092 }
1093
1094
1095 for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) {
1096 ring_id = ar->dp.rx_mon_status_refill_ring[i].refill_buf_ring.ring_id;
1097 ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, ar->dp.mac_id,
1098 HAL_RXDMA_MONITOR_STATUS,
1099 rx_buf_sz, &tlv_filter);
1100 if (ret) {
1101 ath11k_warn(ar->ab, "failed to set rx filter for monitor status ring\n");
1102 goto out;
1103 }
1104 }
1105 #define HTT_RX_FILTER_TLV_LITE_MODE \
1106 (HTT_RX_FILTER_TLV_FLAGS_PPDU_START | \
1107 HTT_RX_FILTER_TLV_FLAGS_PPDU_END | \
1108 HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS | \
1109 HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS_EXT | \
1110 HTT_RX_FILTER_TLV_FLAGS_PPDU_END_STATUS_DONE | \
1111 HTT_RX_FILTER_TLV_FLAGS_MPDU_START)
1112
1113 if (mode == ATH11K_PKTLOG_MODE_FULL) {
1114 rx_filter = HTT_RX_FILTER_TLV_LITE_MODE |
1115 HTT_RX_FILTER_TLV_FLAGS_MSDU_START |
1116 HTT_RX_FILTER_TLV_FLAGS_MSDU_END |
1117 HTT_RX_FILTER_TLV_FLAGS_MPDU_END |
1118 HTT_RX_FILTER_TLV_FLAGS_PACKET_HEADER |
1119 HTT_RX_FILTER_TLV_FLAGS_ATTENTION;
1120 rx_buf_sz = DP_RX_BUFFER_SIZE;
1121 } else if (mode == ATH11K_PKTLOG_MODE_LITE) {
1122 ret = ath11k_dp_tx_htt_h2t_ppdu_stats_req(ar,
1123 HTT_PPDU_STATS_TAG_PKTLOG);
1124 if (ret) {
1125 ath11k_err(ar->ab, "failed to enable pktlog lite: %d\n", ret);
1126 goto out;
1127 }
1128
1129 rx_filter = HTT_RX_FILTER_TLV_LITE_MODE;
1130 rx_buf_sz = DP_RX_BUFFER_SIZE_LITE;
1131 } else {
1132 rx_buf_sz = DP_RX_BUFFER_SIZE;
1133 tlv_filter = ath11k_mac_mon_status_filter_default;
1134 rx_filter = tlv_filter.rx_filter;
1135
1136 ret = ath11k_dp_tx_htt_h2t_ppdu_stats_req(ar,
1137 HTT_PPDU_STATS_TAG_DEFAULT);
1138 if (ret) {
1139 ath11k_err(ar->ab, "failed to send htt ppdu stats req: %d\n",
1140 ret);
1141 goto out;
1142 }
1143 }
1144
1145 tlv_filter.rx_filter = rx_filter;
1146 if (rx_filter) {
1147 tlv_filter.pkt_filter_flags0 = HTT_RX_FP_MGMT_FILTER_FLAGS0;
1148 tlv_filter.pkt_filter_flags1 = HTT_RX_FP_MGMT_FILTER_FLAGS1;
1149 tlv_filter.pkt_filter_flags2 = HTT_RX_FP_CTRL_FILTER_FLASG2;
1150 tlv_filter.pkt_filter_flags3 = HTT_RX_FP_CTRL_FILTER_FLASG3 |
1151 HTT_RX_FP_DATA_FILTER_FLASG3;
1152 }
1153
1154 for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) {
1155 ring_id = ar->dp.rx_mon_status_refill_ring[i].refill_buf_ring.ring_id;
1156 ret = ath11k_dp_tx_htt_rx_filter_setup(ab, ring_id,
1157 ar->dp.mac_id + i,
1158 HAL_RXDMA_MONITOR_STATUS,
1159 rx_buf_sz, &tlv_filter);
1160
1161 if (ret) {
1162 ath11k_warn(ab, "failed to set rx filter for monitor status ring\n");
1163 goto out;
1164 }
1165 }
1166
1167 ath11k_info(ab, "pktlog mode %s\n",
1168 ((mode == ATH11K_PKTLOG_MODE_FULL) ? "full" : "lite"));
1169
1170 ar->debug.pktlog_filter = filter;
1171 ar->debug.pktlog_mode = mode;
1172 ret = count;
1173
1174 out:
1175 mutex_unlock(&ar->conf_mutex);
1176 return ret;
1177 }
1178
1179 static ssize_t ath11k_read_pktlog_filter(struct file *file,
1180 char __user *ubuf,
1181 size_t count, loff_t *ppos)
1182
1183 {
1184 char buf[32] = {0};
1185 struct ath11k *ar = file->private_data;
1186 int len = 0;
1187
1188 mutex_lock(&ar->conf_mutex);
1189 len = scnprintf(buf, sizeof(buf) - len, "%08x %08x\n",
1190 ar->debug.pktlog_filter,
1191 ar->debug.pktlog_mode);
1192 mutex_unlock(&ar->conf_mutex);
1193
1194 return simple_read_from_buffer(ubuf, count, ppos, buf, len);
1195 }
1196
1197 static const struct file_operations fops_pktlog_filter = {
1198 .read = ath11k_read_pktlog_filter,
1199 .write = ath11k_write_pktlog_filter,
1200 .open = simple_open
1201 };
1202
1203 static ssize_t ath11k_write_simulate_radar(struct file *file,
1204 const char __user *user_buf,
1205 size_t count, loff_t *ppos)
1206 {
1207 struct ath11k *ar = file->private_data;
1208 int ret;
1209
1210 ret = ath11k_wmi_simulate_radar(ar);
1211 if (ret)
1212 return ret;
1213
1214 return count;
1215 }
1216
1217 static const struct file_operations fops_simulate_radar = {
1218 .write = ath11k_write_simulate_radar,
1219 .open = simple_open
1220 };
1221
1222 static ssize_t ath11k_debug_dump_dbr_entries(struct file *file,
1223 char __user *user_buf,
1224 size_t count, loff_t *ppos)
1225 {
1226 struct ath11k_dbg_dbr_data *dbr_dbg_data = file->private_data;
1227 static const char * const event_id_to_string[] = {"empty", "Rx", "Replenish"};
1228 int size = ATH11K_DEBUG_DBR_ENTRIES_MAX * 100;
1229 char *buf;
1230 int i, ret;
1231 int len = 0;
1232
1233 buf = kzalloc(size, GFP_KERNEL);
1234 if (!buf)
1235 return -ENOMEM;
1236
1237 len += scnprintf(buf + len, size - len,
1238 "-----------------------------------------\n");
1239 len += scnprintf(buf + len, size - len,
1240 "| idx | hp | tp | timestamp | event |\n");
1241 len += scnprintf(buf + len, size - len,
1242 "-----------------------------------------\n");
1243
1244 spin_lock_bh(&dbr_dbg_data->lock);
1245
1246 for (i = 0; i < dbr_dbg_data->num_ring_debug_entries; i++) {
1247 len += scnprintf(buf + len, size - len,
1248 "|%4u|%8u|%8u|%11llu|%8s|\n", i,
1249 dbr_dbg_data->entries[i].hp,
1250 dbr_dbg_data->entries[i].tp,
1251 dbr_dbg_data->entries[i].timestamp,
1252 event_id_to_string[dbr_dbg_data->entries[i].event]);
1253 }
1254
1255 spin_unlock_bh(&dbr_dbg_data->lock);
1256
1257 ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
1258 kfree(buf);
1259
1260 return ret;
1261 }
1262
1263 static const struct file_operations fops_debug_dump_dbr_entries = {
1264 .read = ath11k_debug_dump_dbr_entries,
1265 .open = simple_open,
1266 .owner = THIS_MODULE,
1267 .llseek = default_llseek,
1268 };
1269
1270 static void ath11k_debugfs_dbr_dbg_destroy(struct ath11k *ar, int dbr_id)
1271 {
1272 struct ath11k_debug_dbr *dbr_debug;
1273 struct ath11k_dbg_dbr_data *dbr_dbg_data;
1274
1275 if (!ar->debug.dbr_debug[dbr_id])
1276 return;
1277
1278 dbr_debug = ar->debug.dbr_debug[dbr_id];
1279 dbr_dbg_data = &dbr_debug->dbr_dbg_data;
1280
1281 debugfs_remove_recursive(dbr_debug->dbr_debugfs);
1282 kfree(dbr_dbg_data->entries);
1283 kfree(dbr_debug);
1284 ar->debug.dbr_debug[dbr_id] = NULL;
1285 }
1286
1287 static int ath11k_debugfs_dbr_dbg_init(struct ath11k *ar, int dbr_id)
1288 {
1289 struct ath11k_debug_dbr *dbr_debug;
1290 struct ath11k_dbg_dbr_data *dbr_dbg_data;
1291 static const char * const dbr_id_to_str[] = {"spectral", "CFR"};
1292
1293 if (ar->debug.dbr_debug[dbr_id])
1294 return 0;
1295
1296 ar->debug.dbr_debug[dbr_id] = kzalloc(sizeof(*dbr_debug),
1297 GFP_KERNEL);
1298
1299 if (!ar->debug.dbr_debug[dbr_id])
1300 return -ENOMEM;
1301
1302 dbr_debug = ar->debug.dbr_debug[dbr_id];
1303 dbr_dbg_data = &dbr_debug->dbr_dbg_data;
1304
1305 if (dbr_debug->dbr_debugfs)
1306 return 0;
1307
1308 dbr_debug->dbr_debugfs = debugfs_create_dir(dbr_id_to_str[dbr_id],
1309 ar->debug.debugfs_pdev);
1310 if (IS_ERR_OR_NULL(dbr_debug->dbr_debugfs)) {
1311 if (IS_ERR(dbr_debug->dbr_debugfs))
1312 return PTR_ERR(dbr_debug->dbr_debugfs);
1313 return -ENOMEM;
1314 }
1315
1316 dbr_debug->dbr_debug_enabled = true;
1317 dbr_dbg_data->num_ring_debug_entries = ATH11K_DEBUG_DBR_ENTRIES_MAX;
1318 dbr_dbg_data->dbr_debug_idx = 0;
1319 dbr_dbg_data->entries = kcalloc(ATH11K_DEBUG_DBR_ENTRIES_MAX,
1320 sizeof(struct ath11k_dbg_dbr_entry),
1321 GFP_KERNEL);
1322 if (!dbr_dbg_data->entries)
1323 return -ENOMEM;
1324
1325 spin_lock_init(&dbr_dbg_data->lock);
1326
1327 debugfs_create_file("dump_dbr_debug", 0444, dbr_debug->dbr_debugfs,
1328 dbr_dbg_data, &fops_debug_dump_dbr_entries);
1329
1330 return 0;
1331 }
1332
1333 static ssize_t ath11k_debugfs_write_enable_dbr_dbg(struct file *file,
1334 const char __user *ubuf,
1335 size_t count, loff_t *ppos)
1336 {
1337 struct ath11k *ar = file->private_data;
1338 char buf[32] = {0};
1339 u32 dbr_id, enable;
1340 int ret;
1341
1342 mutex_lock(&ar->conf_mutex);
1343
1344 if (ar->state != ATH11K_STATE_ON) {
1345 ret = -ENETDOWN;
1346 goto out;
1347 }
1348
1349 ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count);
1350 if (ret < 0)
1351 goto out;
1352
1353 buf[ret] = '\0';
1354 ret = sscanf(buf, "%u %u", &dbr_id, &enable);
1355 if (ret != 2 || dbr_id > 1 || enable > 1) {
1356 ret = -EINVAL;
1357 ath11k_warn(ar->ab, "usage: echo <dbr_id> <val> dbr_id:0-Spectral 1-CFR val:0-disable 1-enable\n");
1358 goto out;
1359 }
1360
1361 if (enable) {
1362 ret = ath11k_debugfs_dbr_dbg_init(ar, dbr_id);
1363 if (ret) {
1364 ath11k_warn(ar->ab, "db ring module debugfs init failed: %d\n",
1365 ret);
1366 goto out;
1367 }
1368 } else {
1369 ath11k_debugfs_dbr_dbg_destroy(ar, dbr_id);
1370 }
1371
1372 ret = count;
1373 out:
1374 mutex_unlock(&ar->conf_mutex);
1375 return ret;
1376 }
1377
1378 static const struct file_operations fops_dbr_debug = {
1379 .write = ath11k_debugfs_write_enable_dbr_dbg,
1380 .open = simple_open,
1381 .owner = THIS_MODULE,
1382 .llseek = default_llseek,
1383 };
1384
1385 int ath11k_debugfs_register(struct ath11k *ar)
1386 {
1387 struct ath11k_base *ab = ar->ab;
1388 char pdev_name[5];
1389 char buf[100] = {0};
1390
1391 snprintf(pdev_name, sizeof(pdev_name), "%s%d", "mac", ar->pdev_idx);
1392
1393 ar->debug.debugfs_pdev = debugfs_create_dir(pdev_name, ab->debugfs_soc);
1394 if (IS_ERR(ar->debug.debugfs_pdev))
1395 return PTR_ERR(ar->debug.debugfs_pdev);
1396
1397
1398 snprintf(buf, 100, "../../ath11k/%pd2", ar->debug.debugfs_pdev);
1399 debugfs_create_symlink("ath11k", ar->hw->wiphy->debugfsdir, buf);
1400
1401 ath11k_debugfs_htt_stats_init(ar);
1402
1403 ath11k_debugfs_fw_stats_init(ar);
1404
1405 debugfs_create_file("ext_tx_stats", 0644,
1406 ar->debug.debugfs_pdev, ar,
1407 &fops_extd_tx_stats);
1408 debugfs_create_file("ext_rx_stats", 0644,
1409 ar->debug.debugfs_pdev, ar,
1410 &fops_extd_rx_stats);
1411 debugfs_create_file("pktlog_filter", 0644,
1412 ar->debug.debugfs_pdev, ar,
1413 &fops_pktlog_filter);
1414 debugfs_create_file("fw_dbglog_config", 0600,
1415 ar->debug.debugfs_pdev, ar,
1416 &fops_fw_dbglog);
1417
1418 if (ar->hw->wiphy->bands[NL80211_BAND_5GHZ]) {
1419 debugfs_create_file("dfs_simulate_radar", 0200,
1420 ar->debug.debugfs_pdev, ar,
1421 &fops_simulate_radar);
1422 debugfs_create_bool("dfs_block_radar_events", 0200,
1423 ar->debug.debugfs_pdev,
1424 &ar->dfs_block_radar_events);
1425 }
1426
1427 if (ab->hw_params.dbr_debug_support)
1428 debugfs_create_file("enable_dbr_debug", 0200, ar->debug.debugfs_pdev,
1429 ar, &fops_dbr_debug);
1430
1431 return 0;
1432 }
1433
1434 void ath11k_debugfs_unregister(struct ath11k *ar)
1435 {
1436 struct ath11k_debug_dbr *dbr_debug;
1437 struct ath11k_dbg_dbr_data *dbr_dbg_data;
1438 int i;
1439
1440 for (i = 0; i < WMI_DIRECT_BUF_MAX; i++) {
1441 dbr_debug = ar->debug.dbr_debug[i];
1442 if (!dbr_debug)
1443 continue;
1444
1445 dbr_dbg_data = &dbr_debug->dbr_dbg_data;
1446 kfree(dbr_dbg_data->entries);
1447 debugfs_remove_recursive(dbr_debug->dbr_debugfs);
1448 kfree(dbr_debug);
1449 ar->debug.dbr_debug[i] = NULL;
1450 }
1451 }
1452
1453 static ssize_t ath11k_write_twt_add_dialog(struct file *file,
1454 const char __user *ubuf,
1455 size_t count, loff_t *ppos)
1456 {
1457 struct ath11k_vif *arvif = file->private_data;
1458 struct wmi_twt_add_dialog_params params = { 0 };
1459 u8 buf[128] = {0};
1460 int ret;
1461
1462 if (arvif->ar->twt_enabled == 0) {
1463 ath11k_err(arvif->ar->ab, "twt support is not enabled\n");
1464 return -EOPNOTSUPP;
1465 }
1466
1467 ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count);
1468 if (ret < 0)
1469 return ret;
1470
1471 buf[ret] = '\0';
1472 ret = sscanf(buf,
1473 "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx %u %u %u %u %u %hhu %hhu %hhu %hhu %hhu",
1474 ¶ms.peer_macaddr[0],
1475 ¶ms.peer_macaddr[1],
1476 ¶ms.peer_macaddr[2],
1477 ¶ms.peer_macaddr[3],
1478 ¶ms.peer_macaddr[4],
1479 ¶ms.peer_macaddr[5],
1480 ¶ms.dialog_id,
1481 ¶ms.wake_intvl_us,
1482 ¶ms.wake_intvl_mantis,
1483 ¶ms.wake_dura_us,
1484 ¶ms.sp_offset_us,
1485 ¶ms.twt_cmd,
1486 ¶ms.flag_bcast,
1487 ¶ms.flag_trigger,
1488 ¶ms.flag_flow_type,
1489 ¶ms.flag_protection);
1490 if (ret != 16)
1491 return -EINVAL;
1492
1493 params.vdev_id = arvif->vdev_id;
1494
1495 ret = ath11k_wmi_send_twt_add_dialog_cmd(arvif->ar, ¶ms);
1496 if (ret)
1497 return ret;
1498
1499 return count;
1500 }
1501
1502 static ssize_t ath11k_write_twt_del_dialog(struct file *file,
1503 const char __user *ubuf,
1504 size_t count, loff_t *ppos)
1505 {
1506 struct ath11k_vif *arvif = file->private_data;
1507 struct wmi_twt_del_dialog_params params = { 0 };
1508 u8 buf[64] = {0};
1509 int ret;
1510
1511 if (arvif->ar->twt_enabled == 0) {
1512 ath11k_err(arvif->ar->ab, "twt support is not enabled\n");
1513 return -EOPNOTSUPP;
1514 }
1515
1516 ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count);
1517 if (ret < 0)
1518 return ret;
1519
1520 buf[ret] = '\0';
1521 ret = sscanf(buf, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx %u",
1522 ¶ms.peer_macaddr[0],
1523 ¶ms.peer_macaddr[1],
1524 ¶ms.peer_macaddr[2],
1525 ¶ms.peer_macaddr[3],
1526 ¶ms.peer_macaddr[4],
1527 ¶ms.peer_macaddr[5],
1528 ¶ms.dialog_id);
1529 if (ret != 7)
1530 return -EINVAL;
1531
1532 params.vdev_id = arvif->vdev_id;
1533
1534 ret = ath11k_wmi_send_twt_del_dialog_cmd(arvif->ar, ¶ms);
1535 if (ret)
1536 return ret;
1537
1538 return count;
1539 }
1540
1541 static ssize_t ath11k_write_twt_pause_dialog(struct file *file,
1542 const char __user *ubuf,
1543 size_t count, loff_t *ppos)
1544 {
1545 struct ath11k_vif *arvif = file->private_data;
1546 struct wmi_twt_pause_dialog_params params = { 0 };
1547 u8 buf[64] = {0};
1548 int ret;
1549
1550 if (arvif->ar->twt_enabled == 0) {
1551 ath11k_err(arvif->ar->ab, "twt support is not enabled\n");
1552 return -EOPNOTSUPP;
1553 }
1554
1555 ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count);
1556 if (ret < 0)
1557 return ret;
1558
1559 buf[ret] = '\0';
1560 ret = sscanf(buf, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx %u",
1561 ¶ms.peer_macaddr[0],
1562 ¶ms.peer_macaddr[1],
1563 ¶ms.peer_macaddr[2],
1564 ¶ms.peer_macaddr[3],
1565 ¶ms.peer_macaddr[4],
1566 ¶ms.peer_macaddr[5],
1567 ¶ms.dialog_id);
1568 if (ret != 7)
1569 return -EINVAL;
1570
1571 params.vdev_id = arvif->vdev_id;
1572
1573 ret = ath11k_wmi_send_twt_pause_dialog_cmd(arvif->ar, ¶ms);
1574 if (ret)
1575 return ret;
1576
1577 return count;
1578 }
1579
1580 static ssize_t ath11k_write_twt_resume_dialog(struct file *file,
1581 const char __user *ubuf,
1582 size_t count, loff_t *ppos)
1583 {
1584 struct ath11k_vif *arvif = file->private_data;
1585 struct wmi_twt_resume_dialog_params params = { 0 };
1586 u8 buf[64] = {0};
1587 int ret;
1588
1589 if (arvif->ar->twt_enabled == 0) {
1590 ath11k_err(arvif->ar->ab, "twt support is not enabled\n");
1591 return -EOPNOTSUPP;
1592 }
1593
1594 ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count);
1595 if (ret < 0)
1596 return ret;
1597
1598 buf[ret] = '\0';
1599 ret = sscanf(buf, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx %u %u %u",
1600 ¶ms.peer_macaddr[0],
1601 ¶ms.peer_macaddr[1],
1602 ¶ms.peer_macaddr[2],
1603 ¶ms.peer_macaddr[3],
1604 ¶ms.peer_macaddr[4],
1605 ¶ms.peer_macaddr[5],
1606 ¶ms.dialog_id,
1607 ¶ms.sp_offset_us,
1608 ¶ms.next_twt_size);
1609 if (ret != 9)
1610 return -EINVAL;
1611
1612 params.vdev_id = arvif->vdev_id;
1613
1614 ret = ath11k_wmi_send_twt_resume_dialog_cmd(arvif->ar, ¶ms);
1615 if (ret)
1616 return ret;
1617
1618 return count;
1619 }
1620
1621 static const struct file_operations ath11k_fops_twt_add_dialog = {
1622 .write = ath11k_write_twt_add_dialog,
1623 .open = simple_open
1624 };
1625
1626 static const struct file_operations ath11k_fops_twt_del_dialog = {
1627 .write = ath11k_write_twt_del_dialog,
1628 .open = simple_open
1629 };
1630
1631 static const struct file_operations ath11k_fops_twt_pause_dialog = {
1632 .write = ath11k_write_twt_pause_dialog,
1633 .open = simple_open
1634 };
1635
1636 static const struct file_operations ath11k_fops_twt_resume_dialog = {
1637 .write = ath11k_write_twt_resume_dialog,
1638 .open = simple_open
1639 };
1640
1641 int ath11k_debugfs_add_interface(struct ath11k_vif *arvif)
1642 {
1643 if (arvif->vif->type == NL80211_IFTYPE_AP && !arvif->debugfs_twt) {
1644 arvif->debugfs_twt = debugfs_create_dir("twt",
1645 arvif->vif->debugfs_dir);
1646 if (!arvif->debugfs_twt || IS_ERR(arvif->debugfs_twt)) {
1647 ath11k_warn(arvif->ar->ab,
1648 "failed to create directory %p\n",
1649 arvif->debugfs_twt);
1650 arvif->debugfs_twt = NULL;
1651 return -1;
1652 }
1653
1654 debugfs_create_file("add_dialog", 0200, arvif->debugfs_twt,
1655 arvif, &ath11k_fops_twt_add_dialog);
1656
1657 debugfs_create_file("del_dialog", 0200, arvif->debugfs_twt,
1658 arvif, &ath11k_fops_twt_del_dialog);
1659
1660 debugfs_create_file("pause_dialog", 0200, arvif->debugfs_twt,
1661 arvif, &ath11k_fops_twt_pause_dialog);
1662
1663 debugfs_create_file("resume_dialog", 0200, arvif->debugfs_twt,
1664 arvif, &ath11k_fops_twt_resume_dialog);
1665 }
1666 return 0;
1667 }
1668
1669 void ath11k_debugfs_remove_interface(struct ath11k_vif *arvif)
1670 {
1671 debugfs_remove_recursive(arvif->debugfs_twt);
1672 arvif->debugfs_twt = NULL;
1673 }