diff mbox series

[10/49] ath11k: add debug.c

Message ID 1566316095-27507-11-git-send-email-kvalo@codeaurora.org (mailing list archive)
State Changes Requested
Delegated to: Kalle Valo
Headers show
Series ath11k: driver for Qualcomm IEEE 802.11ax devices | expand

Commit Message

Kalle Valo Aug. 20, 2019, 3:47 p.m. UTC
---
 drivers/net/wireless/ath/ath11k/debug.c | 1041 +++++++++++++++++++++++++++++++
 1 file changed, 1041 insertions(+)

Comments

Sven Eckelmann Aug. 26, 2019, 1:47 p.m. UTC | #1
On Tuesday, 20 August 2019 17:47:36 CEST Kalle Valo wrote:
> +static ssize_t ath11k_read_simulate_fw_crash(struct file *file,
> +                                            char __user *user_buf,
> +                                            size_t count, loff_t *ppos)
> +{
> +       const char buf[] =
> +               "To simulate firmware crash write one of the keywords to this file:\n"
> +               "`assert` - this will send WMI_FORCE_FW_HANG_CMDID to firmware to cause assert.\n"
> +               "`hw-restart` - this will simply queue hw restart without fw/hw actually crashing.\n";
> +
> +       return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
> +}

There is nothing in the write handler which handles "hw-restart". It just 
causes an -EINVAL.

> +
> +/* Simulate firmware crash:
> + * 'soft': Call wmi command causing firmware hang. This firmware hang is
> + * recoverable by warm firmware reset.
> + * 'hard': Force firmware crash by setting any vdev parameter for not allowed
> + * vdev id. This is hard firmware crash because it is recoverable only by cold
> + * firmware reset.
> + */
> +static ssize_t ath11k_write_simulate_fw_crash(struct file *file,
> +                                             const char __user *user_buf,
> +                                             size_t count, loff_t *ppos)
> +{
> +       struct ath11k_base *ab = file->private_data;
> +       struct ath11k_pdev *pdev;
> +       struct ath11k *ar = ab->pdevs[0].ar;
> +       char buf[32] = {0};
> +       ssize_t rc;
> +       int i, ret, radioup;
> +
> +       for (i = 0; i < ab->num_radios; i++) {
> +               pdev = &ab->pdevs[i];
> +               ar = pdev->ar;
> +               if (ar && ar->state == ATH11K_STATE_ON) {
> +                       radioup = 1;
> +                       break;
> +               }
> +       }
> +       /* filter partial writes and invalid commands */
> +       if (*ppos != 0 || count >= sizeof(buf) || count == 0)
> +               return -EINVAL;
> +
> +       rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
> +       if (rc < 0)
> +               return rc;
> +
> +       /* drop the possible '\n' from the end */
> +       if (buf[*ppos - 1] == '\n')
> +               buf[*ppos - 1] = '\0';
> +
> +       if (radioup == 0) {
> +               ret = -ENETDOWN;
> +               goto exit;
> +       }
> +
> +       if (!strcmp(buf, "assert")) {
> +               ath11k_info(ab, "simulating firmware assert crash\n");
> +               ret = ath11k_wmi_force_fw_hang_cmd(ar,
> +                                                  ATH11K_WMI_FW_HANG_ASSERT_TYPE,
> +                                                  ATH11K_WMI_FW_HANG_DELAY);
> +       } else {
> +               ret = -EINVAL;
> +               goto exit;
> +       }
> +
> +       if (ret) {
> +               ath11k_warn(ab, "failed to simulate firmware crash: %d\n", ret);
> +               goto exit;
> +       }
> +
> +       ret = count;
> +
> +exit:
> +       return ret;
> +}

And right now, the write of an "assert" to this file just causes an fatal error for the system:

    [ 4312.409255] qcom-q6v5-wcss-pil cd00000.qcom_q6v5_wcss: fatal error received:
    [ 4312.409255] QC Image Version: QC_IMAGE_VERSION_STRING=WLAN.HK.2.1.0.1-00410-QCAHKSWPL_SILICONZ-2
    [ 4312.409255] Image Variant : IMAGE_VARIANT_STRING=8074.wlanfw.eval_v2Q
    [ 4312.409255] 
    [ 4312.409255] wlan_wmi.c:234 Assertion 0 failedparam0 :zero, param1 :zero, param2 :zero.
    [ 4312.409255] Thread ID      : 0x00000069  Thread name    : WLAN RT0  Process ID     : 0
    [ 4312.409255] Register:
    [ 4312.409255] SP : 0x4c168d58
    [ 4312.409255] FP : 0x4c168d60
    [ 4312.409255] PC : 0x4b1c8850
    [ 4312.409255] SSR : 0x00000008
    [ 4312.409255] BADVA : 0x00020000
    [ 4312.409255] LR : 0x4b1c7c68
    [ 4312.409255] 
    [ 4312.409255] Stack Dump
    [ 4312.409255] from : 0x4c168d58
    [ 4312.409255] to   : 0x4c168f00
    [ 4312.409255] 
    [ 4312.455997] remoteproc remoteproc0: crash detected in cd00000.qcom_q6v5_wcss: type fatal error
    [ 4312.478259] remoteproc remoteproc0: handling crash #1 in cd00000.qcom_q6v5_wcss
    [ 4312.486826] Kernel panic - not syncing: remoteproc remoteproc0: Resetting the SoC - cd00000.qcom_q6v5_wcss crashed
    [ 4312.494028] CPU: 2 PID: 5590 Comm: kworker/2:0 Tainted: G        W       4.4.60 #0
    [ 4312.504436] Hardware name: Generic DT based system
    [ 4312.511991] Workqueue: events rproc_crash_handler_work
    [ 4312.521880] [<8021e86c>] (unwind_backtrace) from [<8021b404>] (show_stack+0x10/0x14)
    [ 4312.521979] [<8021b404>] (show_stack) from [<803dd818>] (dump_stack+0x7c/0x9c)
    [ 4312.529789] [<803dd818>] (dump_stack) from [<80225d80>] (panic+0x84/0x1f8)
    [ 4312.536818] [<80225d80>] (panic) from [<80555278>] (rproc_crash_handler_work+0x90/0x98)
    [ 4312.543678] [<80555278>] (rproc_crash_handler_work) from [<802380e8>] (process_one_work+0x1c0/0x2f8)
    [ 4312.551578] [<802380e8>] (process_one_work) from [<80238d24>] (worker_thread+0x2b0/0x3ec)
    [ 4312.560952] [<80238d24>] (worker_thread) from [<8023cf84>] (kthread+0xd8/0xec)
    [ 4312.569023] [<8023cf84>] (kthread) from [<80209be8>] (ret_from_fork+0x14/0x2c)
    [ 4312.576141] CPU0: stopping
    [ 4312.583335] CPU: 0 PID: 0 Comm: swapper/0 Tainted: G        W       4.4.60 #0
    [ 4312.586032] Hardware name: Generic DT based system
    [ 4312.593237] [<8021e86c>] (unwind_backtrace) from [<8021b404>] (show_stack+0x10/0x14)
    [ 4312.597930] [<8021b404>] (show_stack) from [<803dd818>] (dump_stack+0x7c/0x9c)
    [ 4312.605827] [<803dd818>] (dump_stack) from [<8021dc3c>] (handle_IPI+0xe8/0x180)
    [ 4312.612858] [<8021dc3c>] (handle_IPI) from [<802093a4>] (gic_handle_irq+0x78/0x94)
    [ 4312.620063] [<802093a4>] (gic_handle_irq) from [<8020a480>] (__irq_svc+0x40/0x74)
    [ 4312.627701] Exception stack(0x80c67f60 to 0x80c67fa8)
    [ 4312.635249] 7f60: 00000001 00000000 00000000 8020b320 00000000 80c66000 00000000 80c612cc
    [ 4312.640291] 7f80: 80c67fb8 808f3a30 80cae010 00000000 00000000 80c67fb0 80218edc 80218ee0
    [ 4312.648448] 7fa0: 60000013 ffffffff
    [ 4312.656601] [<8020a480>] (__irq_svc) from [<80218ee0>] (arch_cpu_idle+0x2c/0x50)
    [ 4312.659909] [<80218ee0>] (arch_cpu_idle) from [<80254b38>] (cpu_startup_entry+0x134/0x214)
    [ 4312.667553] [<80254b38>] (cpu_startup_entry) from [<808cac48>] (start_kernel+0x380/0x404)
    [ 4312.675620] CPU1: stopping
    [ 4312.683855] CPU: 1 PID: 0 Comm: swapper/1 Tainted: G        W       4.4.60 #0
    [ 4312.686466] Hardware name: Generic DT based system
    [ 4312.693671] [<8021e86c>] (unwind_backtrace) from [<8021b404>] (show_stack+0x10/0x14)
    [ 4312.698363] [<8021b404>] (show_stack) from [<803dd818>] (dump_stack+0x7c/0x9c)
    [ 4312.706263] [<803dd818>] (dump_stack) from [<8021dc3c>] (handle_IPI+0xe8/0x180)
    [ 4312.713293] [<8021dc3c>] (handle_IPI) from [<802093a4>] (gic_handle_irq+0x78/0x94)
    [ 4312.720497] [<802093a4>] (gic_handle_irq) from [<8020a480>] (__irq_svc+0x40/0x74)
    [ 4312.728135] Exception stack(0xbe083f98 to 0xbe083fe0)
    [ 4312.735683] 3f80:                                                       00000001 00000000
    [ 4312.740725] 3fa0: 00000000 8020b320 00000000 be082000 00000000 80c612cc be083ff0 410fd034
    [ 4312.748884] 3fc0: 00000000 00000000 00000000 be083fe8 80218edc 80218ee0 60000013 ffffffff
    [ 4312.757045] [<8020a480>] (__irq_svc) from [<80218ee0>] (arch_cpu_idle+0x2c/0x50)
    [ 4312.765203] [<80218ee0>] (arch_cpu_idle) from [<80254b38>] (cpu_startup_entry+0x134/0x214)
    [ 4312.772669] [<80254b38>] (cpu_startup_entry) from [<4120944c>] (0x4120944c)
    [ 4312.780737] CPU3: stopping
    [ 4312.787589] CPU: 3 PID: 0 Comm: swapper/3 Tainted: G        W       4.4.60 #0
    [ 4312.790372] Hardware name: Generic DT based system
    [ 4312.797577] [<8021e86c>] (unwind_backtrace) from [<8021b404>] (show_stack+0x10/0x14)
    [ 4312.802270] [<8021b404>] (show_stack) from [<803dd818>] (dump_stack+0x7c/0x9c)
    [ 4312.810167] [<803dd818>] (dump_stack) from [<8021dc3c>] (handle_IPI+0xe8/0x180)
    [ 4312.817199] [<8021dc3c>] (handle_IPI) from [<802093a4>] (gic_handle_irq+0x78/0x94)
    [ 4312.824403] [<802093a4>] (gic_handle_irq) from [<8020a480>] (__irq_svc+0x40/0x74)
    [ 4312.832041] Exception stack(0xbe087f98 to 0xbe087fe0)
    [ 4312.839588] 7f80:                                                       00000001 00000000
    [ 4312.844630] 7fa0: 00000000 8020b320 00000000 be086000 00000000 80c612cc be087ff0 410fd034
    [ 4312.852791] 7fc0: 00000000 00000000 00000000 be087fe8 80218edc 80218ee0 60000013 ffffffff
    [ 4312.860951] [<8020a480>] (__irq_svc) from [<80218ee0>] (arch_cpu_idle+0x2c/0x50)
    [ 4312.869109] [<80218ee0>] (arch_cpu_idle) from [<80254b38>] (cpu_startup_entry+0x134/0x214)
    [ 4312.876576] [<80254b38>] (cpu_startup_entry) from [<4120944c>] (0x4120944c)
    [ 4312.884650] The reading for sensor 4 is 0x002041f7
    [ 4312.891499] The reading for sensor 5 is 0x002051f4
    [ 4312.896415] Couldn't get reading for sensor 6
    [ 4312.901189] Couldn't get reading for sensor 7
    [ 4312.905561] The reading for sensor 8 is 0x002081e0
    [ 4312.909902] The reading for sensor 9 is 0x002091f7
    [ 4312.914645] Couldn't get reading for sensor 10
    [ 4312.919364] The reading for sensor 11 is 0x0020b1fa
    [ 4312.923791] The reading for sensor 12 is 0x0020c1fa
    [ 4312.928621] Couldn't get reading for sensor 13
    [ 4312.933425] The reading for sensor 14 is 0x0020e1f4
    [ 4312.937941] The reading for sensor 15 is 0x0020f1e7
    [ 4313.942700] Rebooting in 3 seconds..

Maybe can be fixed by a different kernel (for the remoteproc). But I don't 
have this kernel at the moment.


Kind regards,
	Sven
Anilkumar Kolli Aug. 27, 2019, 7:33 a.m. UTC | #2
On 2019-08-26 19:17, Sven Eckelmann wrote:
> On Tuesday, 20 August 2019 17:47:36 CEST Kalle Valo wrote:
>> +static ssize_t ath11k_read_simulate_fw_crash(struct file *file,
>> +                                            char __user *user_buf,
>> +                                            size_t count, loff_t 
>> *ppos)
>> +{
>> +       const char buf[] =
>> +               "To simulate firmware crash write one of the keywords 
>> to this file:\n"
>> +               "`assert` - this will send WMI_FORCE_FW_HANG_CMDID to 
>> firmware to cause assert.\n"
>> +               "`hw-restart` - this will simply queue hw restart 
>> without fw/hw actually crashing.\n";
>> +
>> +       return simple_read_from_buffer(user_buf, count, ppos, buf, 
>> strlen(buf));
>> +}
> 
> There is nothing in the write handler which handles "hw-restart". It 
> just
> causes an -EINVAL.
> 

Yes. I will add "hw-restart".

>> +
>> +/* Simulate firmware crash:
>> + * 'soft': Call wmi command causing firmware hang. This firmware hang 
>> is
>> + * recoverable by warm firmware reset.
>> + * 'hard': Force firmware crash by setting any vdev parameter for not 
>> allowed
>> + * vdev id. This is hard firmware crash because it is recoverable 
>> only by cold
>> + * firmware reset.
>> + */
>> +static ssize_t ath11k_write_simulate_fw_crash(struct file *file,
>> +                                             const char __user 
>> *user_buf,
>> +                                             size_t count, loff_t 
>> *ppos)
>> +{
>> +       struct ath11k_base *ab = file->private_data;
>> +       struct ath11k_pdev *pdev;
>> +       struct ath11k *ar = ab->pdevs[0].ar;
>> +       char buf[32] = {0};
>> +       ssize_t rc;
>> +       int i, ret, radioup;
>> +
>> +       for (i = 0; i < ab->num_radios; i++) {
>> +               pdev = &ab->pdevs[i];
>> +               ar = pdev->ar;
>> +               if (ar && ar->state == ATH11K_STATE_ON) {
>> +                       radioup = 1;
>> +                       break;
>> +               }
>> +       }
>> +       /* filter partial writes and invalid commands */
>> +       if (*ppos != 0 || count >= sizeof(buf) || count == 0)
>> +               return -EINVAL;
>> +
>> +       rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, 
>> user_buf, count);
>> +       if (rc < 0)
>> +               return rc;
>> +
>> +       /* drop the possible '\n' from the end */
>> +       if (buf[*ppos - 1] == '\n')
>> +               buf[*ppos - 1] = '\0';
>> +
>> +       if (radioup == 0) {
>> +               ret = -ENETDOWN;
>> +               goto exit;
>> +       }
>> +
>> +       if (!strcmp(buf, "assert")) {
>> +               ath11k_info(ab, "simulating firmware assert crash\n");
>> +               ret = ath11k_wmi_force_fw_hang_cmd(ar,
>> +                                                  
>> ATH11K_WMI_FW_HANG_ASSERT_TYPE,
>> +                                                  
>> ATH11K_WMI_FW_HANG_DELAY);
>> +       } else {
>> +               ret = -EINVAL;
>> +               goto exit;
>> +       }
>> +
>> +       if (ret) {
>> +               ath11k_warn(ab, "failed to simulate firmware crash: 
>> %d\n", ret);
>> +               goto exit;
>> +       }
>> +
>> +       ret = count;
>> +
>> +exit:
>> +       return ret;
>> +}
> 
> And right now, the write of an "assert" to this file just causes an
> fatal error for the system:
> 
>     [ 4312.409255] qcom-q6v5-wcss-pil cd00000.qcom_q6v5_wcss: fatal
> error received:
>     [ 4312.409255] QC Image Version:
> QC_IMAGE_VERSION_STRING=WLAN.HK.2.1.0.1-00410-QCAHKSWPL_SILICONZ-2
>     [ 4312.409255] Image Variant : 
> IMAGE_VARIANT_STRING=8074.wlanfw.eval_v2Q
>     [ 4312.409255]
>     [ 4312.409255] wlan_wmi.c:234 Assertion 0 failedparam0 :zero,
> param1 :zero, param2 :zero.
>     [ 4312.409255] Thread ID      : 0x00000069  Thread name    : WLAN
> RT0  Process ID     : 0
>     [ 4312.409255] Register:
>     [ 4312.409255] SP : 0x4c168d58
>     [ 4312.409255] FP : 0x4c168d60
>     [ 4312.409255] PC : 0x4b1c8850
>     [ 4312.409255] SSR : 0x00000008
>     [ 4312.409255] BADVA : 0x00020000
>     [ 4312.409255] LR : 0x4b1c7c68
>     [ 4312.409255]
>     [ 4312.409255] Stack Dump
>     [ 4312.409255] from : 0x4c168d58
>     [ 4312.409255] to   : 0x4c168f00
>     [ 4312.409255]
>     [ 4312.455997] remoteproc remoteproc0: crash detected in
> cd00000.qcom_q6v5_wcss: type fatal error
>     [ 4312.478259] remoteproc remoteproc0: handling crash #1 in
> cd00000.qcom_q6v5_wcss
>     [ 4312.486826] Kernel panic - not syncing: remoteproc remoteproc0:
> Resetting the SoC - cd00000.qcom_q6v5_wcss crashed
>     [ 4312.494028] CPU: 2 PID: 5590 Comm: kworker/2:0 Tainted: G
>  W       4.4.60 #0
>     [ 4312.504436] Hardware name: Generic DT based system
>     [ 4312.511991] Workqueue: events rproc_crash_handler_work
>     [ 4312.521880] [<8021e86c>] (unwind_backtrace) from [<8021b404>]
> (show_stack+0x10/0x14)
>     [ 4312.521979] [<8021b404>] (show_stack) from [<803dd818>]
> (dump_stack+0x7c/0x9c)
>     [ 4312.529789] [<803dd818>] (dump_stack) from [<80225d80>]
> (panic+0x84/0x1f8)
>     [ 4312.536818] [<80225d80>] (panic) from [<80555278>]
> (rproc_crash_handler_work+0x90/0x98)
>     [ 4312.543678] [<80555278>] (rproc_crash_handler_work) from
> [<802380e8>] (process_one_work+0x1c0/0x2f8)
>     [ 4312.551578] [<802380e8>] (process_one_work) from [<80238d24>]
> (worker_thread+0x2b0/0x3ec)
>     [ 4312.560952] [<80238d24>] (worker_thread) from [<8023cf84>]
> (kthread+0xd8/0xec)
>     [ 4312.569023] [<8023cf84>] (kthread) from [<80209be8>]
> (ret_from_fork+0x14/0x2c)
>     [ 4312.576141] CPU0: stopping
>     [ 4312.583335] CPU: 0 PID: 0 Comm: swapper/0 Tainted: G        W
>     4.4.60 #0
>     [ 4312.586032] Hardware name: Generic DT based system
>     [ 4312.593237] [<8021e86c>] (unwind_backtrace) from [<8021b404>]
> (show_stack+0x10/0x14)
>     [ 4312.597930] [<8021b404>] (show_stack) from [<803dd818>]
> (dump_stack+0x7c/0x9c)
>     [ 4312.605827] [<803dd818>] (dump_stack) from [<8021dc3c>]
> (handle_IPI+0xe8/0x180)
>     [ 4312.612858] [<8021dc3c>] (handle_IPI) from [<802093a4>]
> (gic_handle_irq+0x78/0x94)
>     [ 4312.620063] [<802093a4>] (gic_handle_irq) from [<8020a480>]
> (__irq_svc+0x40/0x74)
>     [ 4312.627701] Exception stack(0x80c67f60 to 0x80c67fa8)
>     [ 4312.635249] 7f60: 00000001 00000000 00000000 8020b320 00000000
> 80c66000 00000000 80c612cc
>     [ 4312.640291] 7f80: 80c67fb8 808f3a30 80cae010 00000000 00000000
> 80c67fb0 80218edc 80218ee0
>     [ 4312.648448] 7fa0: 60000013 ffffffff
>     [ 4312.656601] [<8020a480>] (__irq_svc) from [<80218ee0>]
> (arch_cpu_idle+0x2c/0x50)
>     [ 4312.659909] [<80218ee0>] (arch_cpu_idle) from [<80254b38>]
> (cpu_startup_entry+0x134/0x214)
>     [ 4312.667553] [<80254b38>] (cpu_startup_entry) from [<808cac48>]
> (start_kernel+0x380/0x404)
>     [ 4312.675620] CPU1: stopping
>     [ 4312.683855] CPU: 1 PID: 0 Comm: swapper/1 Tainted: G        W
>     4.4.60 #0
>     [ 4312.686466] Hardware name: Generic DT based system
>     [ 4312.693671] [<8021e86c>] (unwind_backtrace) from [<8021b404>]
> (show_stack+0x10/0x14)
>     [ 4312.698363] [<8021b404>] (show_stack) from [<803dd818>]
> (dump_stack+0x7c/0x9c)
>     [ 4312.706263] [<803dd818>] (dump_stack) from [<8021dc3c>]
> (handle_IPI+0xe8/0x180)
>     [ 4312.713293] [<8021dc3c>] (handle_IPI) from [<802093a4>]
> (gic_handle_irq+0x78/0x94)
>     [ 4312.720497] [<802093a4>] (gic_handle_irq) from [<8020a480>]
> (__irq_svc+0x40/0x74)
>     [ 4312.728135] Exception stack(0xbe083f98 to 0xbe083fe0)
>     [ 4312.735683] 3f80:
>         00000001 00000000
>     [ 4312.740725] 3fa0: 00000000 8020b320 00000000 be082000 00000000
> 80c612cc be083ff0 410fd034
>     [ 4312.748884] 3fc0: 00000000 00000000 00000000 be083fe8 80218edc
> 80218ee0 60000013 ffffffff
>     [ 4312.757045] [<8020a480>] (__irq_svc) from [<80218ee0>]
> (arch_cpu_idle+0x2c/0x50)
>     [ 4312.765203] [<80218ee0>] (arch_cpu_idle) from [<80254b38>]
> (cpu_startup_entry+0x134/0x214)
>     [ 4312.772669] [<80254b38>] (cpu_startup_entry) from [<4120944c>]
> (0x4120944c)
>     [ 4312.780737] CPU3: stopping
>     [ 4312.787589] CPU: 3 PID: 0 Comm: swapper/3 Tainted: G        W
>     4.4.60 #0
>     [ 4312.790372] Hardware name: Generic DT based system
>     [ 4312.797577] [<8021e86c>] (unwind_backtrace) from [<8021b404>]
> (show_stack+0x10/0x14)
>     [ 4312.802270] [<8021b404>] (show_stack) from [<803dd818>]
> (dump_stack+0x7c/0x9c)
>     [ 4312.810167] [<803dd818>] (dump_stack) from [<8021dc3c>]
> (handle_IPI+0xe8/0x180)
>     [ 4312.817199] [<8021dc3c>] (handle_IPI) from [<802093a4>]
> (gic_handle_irq+0x78/0x94)
>     [ 4312.824403] [<802093a4>] (gic_handle_irq) from [<8020a480>]
> (__irq_svc+0x40/0x74)
>     [ 4312.832041] Exception stack(0xbe087f98 to 0xbe087fe0)
>     [ 4312.839588] 7f80:
>         00000001 00000000
>     [ 4312.844630] 7fa0: 00000000 8020b320 00000000 be086000 00000000
> 80c612cc be087ff0 410fd034
>     [ 4312.852791] 7fc0: 00000000 00000000 00000000 be087fe8 80218edc
> 80218ee0 60000013 ffffffff
>     [ 4312.860951] [<8020a480>] (__irq_svc) from [<80218ee0>]
> (arch_cpu_idle+0x2c/0x50)
>     [ 4312.869109] [<80218ee0>] (arch_cpu_idle) from [<80254b38>]
> (cpu_startup_entry+0x134/0x214)
>     [ 4312.876576] [<80254b38>] (cpu_startup_entry) from [<4120944c>]
> (0x4120944c)
>     [ 4312.884650] The reading for sensor 4 is 0x002041f7
>     [ 4312.891499] The reading for sensor 5 is 0x002051f4
>     [ 4312.896415] Couldn't get reading for sensor 6
>     [ 4312.901189] Couldn't get reading for sensor 7
>     [ 4312.905561] The reading for sensor 8 is 0x002081e0
>     [ 4312.909902] The reading for sensor 9 is 0x002091f7
>     [ 4312.914645] Couldn't get reading for sensor 10
>     [ 4312.919364] The reading for sensor 11 is 0x0020b1fa
>     [ 4312.923791] The reading for sensor 12 is 0x0020c1fa
>     [ 4312.928621] Couldn't get reading for sensor 13
>     [ 4312.933425] The reading for sensor 14 is 0x0020e1f4
>     [ 4312.937941] The reading for sensor 15 is 0x0020f1e7
>     [ 4313.942700] Rebooting in 3 seconds..
> 
> Maybe can be fixed by a different kernel (for the remoteproc). But I 
> don't
> have this kernel at the moment.
> 

The write of an "assert", sends 'WMI_FORCE_FW_HANG_CMDID' WMI command to 
target firmware.
This WMI command forces the target to assert.

Anil

> 
> Kind regards,
> 	Sven
> _______________________________________________
> ath11k mailing list
> ath11k@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/ath11k
Sven Eckelmann Aug. 27, 2019, 7:35 a.m. UTC | #3
On Tuesday, 27 August 2019 09:33:39 CEST Anilkumar Kolli wrote:
[...]
> >     [ 4312.884650] The reading for sensor 4 is 0x002041f7
> >     [ 4312.891499] The reading for sensor 5 is 0x002051f4
> >     [ 4312.896415] Couldn't get reading for sensor 6
> >     [ 4312.901189] Couldn't get reading for sensor 7
> >     [ 4312.905561] The reading for sensor 8 is 0x002081e0
> >     [ 4312.909902] The reading for sensor 9 is 0x002091f7
> >     [ 4312.914645] Couldn't get reading for sensor 10
> >     [ 4312.919364] The reading for sensor 11 is 0x0020b1fa
> >     [ 4312.923791] The reading for sensor 12 is 0x0020c1fa
> >     [ 4312.928621] Couldn't get reading for sensor 13
> >     [ 4312.933425] The reading for sensor 14 is 0x0020e1f4
> >     [ 4312.937941] The reading for sensor 15 is 0x0020f1e7
> >     [ 4313.942700] Rebooting in 3 seconds..
> > 
> > Maybe can be fixed by a different kernel (for the remoteproc). But I 
> > don't
> > have this kernel at the moment.
> > 
> 
> The write of an "assert", sends 'WMI_FORCE_FW_HANG_CMDID' WMI command to 
> target firmware.
> This WMI command forces the target to assert.

Yes, but it shouldn't kill the complete system.

Kind regards,
	Sven
Anilkumar Kolli Aug. 27, 2019, 9:04 a.m. UTC | #4
On 2019-08-27 13:05, Sven Eckelmann wrote:
> On Tuesday, 27 August 2019 09:33:39 CEST Anilkumar Kolli wrote:
> [...]
>> >     [ 4312.884650] The reading for sensor 4 is 0x002041f7
>> >     [ 4312.891499] The reading for sensor 5 is 0x002051f4
>> >     [ 4312.896415] Couldn't get reading for sensor 6
>> >     [ 4312.901189] Couldn't get reading for sensor 7
>> >     [ 4312.905561] The reading for sensor 8 is 0x002081e0
>> >     [ 4312.909902] The reading for sensor 9 is 0x002091f7
>> >     [ 4312.914645] Couldn't get reading for sensor 10
>> >     [ 4312.919364] The reading for sensor 11 is 0x0020b1fa
>> >     [ 4312.923791] The reading for sensor 12 is 0x0020c1fa
>> >     [ 4312.928621] Couldn't get reading for sensor 13
>> >     [ 4312.933425] The reading for sensor 14 is 0x0020e1f4
>> >     [ 4312.937941] The reading for sensor 15 is 0x0020f1e7
>> >     [ 4313.942700] Rebooting in 3 seconds..
>> >
>> > Maybe can be fixed by a different kernel (for the remoteproc). But I
>> > don't
>> > have this kernel at the moment.
>> >
>> 
>> The write of an "assert", sends 'WMI_FORCE_FW_HANG_CMDID' WMI command 
>> to
>> target firmware.
>> This WMI command forces the target to assert.
> 
> Yes, but it shouldn't kill the complete system.
> 
This will not kill the whole system, This will crash target and we have 
mechanism to recover the system.

Hope u have generated the crash with below patch,
https://source.codeaurora.org/quic/qsdk/oss/system/feeds/wlan-open/tree/mac80211/patches/019-ath11k-disable-q6-recovery-to-crash-kernel.patch?h=win_ap.1.0

Please remove this patch to see the target recover after the crash.

Thanks
Anil
Sven Eckelmann Aug. 27, 2019, 9:53 a.m. UTC | #5
On Tuesday, 27 August 2019 11:04:23 CEST Anilkumar Kolli wrote:
[...]
> > Yes, but it shouldn't kill the complete system.
> > 
> This will not kill the whole system, This will crash target and we have 
> mechanism to recover the system.
> 
> Hope u have generated the crash with below patch,
> https://source.codeaurora.org/quic/qsdk/oss/system/feeds/wlan-open/tree/mac80211/patches/019-ath11k-disable-q6-recovery-to-crash-kernel.patch?h=win_ap.1.0
> 
> Please remove this patch to see the target recover after the crash.

John also pointed me to this patch yesterday and I have now removed it.

But the wifi hardware doesn't recover after issuing an assert. All(?) firmware 
request will just timeout:

    [ 1093.114530] ath11k c000000.wifi1: wmi command 20488 timeout
    [ 1093.114555] ath11k c000000.wifi1: failed to send WMI_VDEV_SET_PARAM_CMDID
    [ 1093.118903] ath11k c000000.wifi1: Failed to set dtim period for VDEV 0: -11
    [ 1096.124532] ath11k c000000.wifi1: wmi command 20488 timeout
    [ 1096.124554] ath11k c000000.wifi1: failed to send WMI_VDEV_SET_PARAM_CMDID
    [ 1096.128902] ath11k c000000.wifi1: Failed to set CTS prot for VDEV: 0
    [ 1099.134527] ath11k c000000.wifi1: wmi command 20488 timeout
    [ 1099.134547] ath11k c000000.wifi1: failed to send WMI_VDEV_SET_PARAM_CMDID
    [ 1099.138895] ath11k c000000.wifi1: Failed to set preamble for VDEV: 0
    [ 1102.144526] ath11k c000000.wifi1: wmi command 20488 timeout
    [ 1102.144546] ath11k c000000.wifi1: failed to send WMI_VDEV_SET_PARAM_CMDID
    [ 1102.148894] ath11k c000000.wifi1: failed to set mgmt tx rate -11
    [ 1105.154526] ath11k c000000.wifi1: wmi command 20488 timeout
    [ 1105.154547] ath11k c000000.wifi1: failed to send WMI_VDEV_SET_PARAM_CMDID
    [ 1105.158895] ath11k c000000.wifi1: failed to set beacon tx rate -11
    [ 1114.164529] ath11k c000000.wifi1: wmi command 16387 timeout
    [ 1114.164553] ath11k c000000.wifi1: failed to send WMI_PDEV_SET_PARAM cmd
    [ 1114.168899] ath11k c000000.wifi1: Failed to set beacon mode for VDEV: 0
    [ 1117.174527] ath11k c000000.wifi1: wmi command 28675 timeout
    [ 1117.174550] ath11k c000000.wifi1: failed to send WMI_BCN_TMPL_CMDID
    [ 1117.178899] ath11k c000000.wifi1: failed to submit beacon template command: -11
    [ 1117.185231] ath11k c000000.wifi1: failed to update bcn template: -11
    [ 1120.184524] ath11k c000000.wifi1: wmi command 20488 timeout
    [ 1120.184545] ath11k c000000.wifi1: failed to send WMI_VDEV_SET_PARAM_CMDID
    [ 1120.188893] ath11k c000000.wifi1: Failed to set dtim period for VDEV 0: -11
    [ 1123.194527] ath11k c000000.wifi1: wmi command 20488 timeout
    [ 1123.194548] ath11k c000000.wifi1: failed to send WMI_VDEV_SET_PARAM_CMDID
    [ 1123.198895] ath11k c000000.wifi1: Failed to set CTS prot for VDEV: 0
    [ 1126.204526] ath11k c000000.wifi1: wmi command 20488 timeout
    [ 1126.204547] ath11k c000000.wifi1: failed to send WMI_VDEV_SET_PARAM_CMDID
    [ 1126.208894] ath11k c000000.wifi1: Failed to set preamble for VDEV: 0
    [ 1129.214527] ath11k c000000.wifi1: wmi command 20488 timeout
    [ 1129.214548] ath11k c000000.wifi1: failed to send WMI_VDEV_SET_PARAM_CMDID
    [ 1129.218897] ath11k c000000.wifi1: failed to set mgmt tx rate -11
    [ 1132.224525] ath11k c000000.wifi1: wmi command 20488 timeout
    [ 1132.224546] ath11k c000000.wifi1: failed to send WMI_VDEV_SET_PARAM_CMDID
    [ 1132.228894] ath11k c000000.wifi1: failed to set beacon tx rate -11

ath11k must be unloaded + loaded again to fix this problem.

Kind regards,
	Sven
Anilkumar Kolli Aug. 27, 2019, 10:04 a.m. UTC | #6
On 2019-08-27 15:23, Sven Eckelmann wrote:
> On Tuesday, 27 August 2019 11:04:23 CEST Anilkumar Kolli wrote:
> [...]
>> > Yes, but it shouldn't kill the complete system.
>> >
>> This will not kill the whole system, This will crash target and we 
>> have
>> mechanism to recover the system.
>> 
>> Hope u have generated the crash with below patch,
>> https://source.codeaurora.org/quic/qsdk/oss/system/feeds/wlan-open/tree/mac80211/patches/019-ath11k-disable-q6-recovery-to-crash-kernel.patch?h=win_ap.1.0
>> 
>> Please remove this patch to see the target recover after the crash.
> 
> John also pointed me to this patch yesterday and I have now removed it.
> 
> But the wifi hardware doesn't recover after issuing an assert. All(?) 
> firmware
> request will just timeout:
> 
>     [ 1093.114530] ath11k c000000.wifi1: wmi command 20488 timeout
>     [ 1093.114555] ath11k c000000.wifi1: failed to send 
> WMI_VDEV_SET_PARAM_CMDID
>     [ 1093.118903] ath11k c000000.wifi1: Failed to set dtim period for
> VDEV 0: -11
>     [ 1096.124532] ath11k c000000.wifi1: wmi command 20488 timeout
>     [ 1096.124554] ath11k c000000.wifi1: failed to send 
> WMI_VDEV_SET_PARAM_CMDID
>     [ 1096.128902] ath11k c000000.wifi1: Failed to set CTS prot for 
> VDEV: 0
>     [ 1099.134527] ath11k c000000.wifi1: wmi command 20488 timeout
>     [ 1099.134547] ath11k c000000.wifi1: failed to send 
> WMI_VDEV_SET_PARAM_CMDID
>     [ 1099.138895] ath11k c000000.wifi1: Failed to set preamble for 
> VDEV: 0
>     [ 1102.144526] ath11k c000000.wifi1: wmi command 20488 timeout
>     [ 1102.144546] ath11k c000000.wifi1: failed to send 
> WMI_VDEV_SET_PARAM_CMDID
>     [ 1102.148894] ath11k c000000.wifi1: failed to set mgmt tx rate -11
>     [ 1105.154526] ath11k c000000.wifi1: wmi command 20488 timeout
>     [ 1105.154547] ath11k c000000.wifi1: failed to send 
> WMI_VDEV_SET_PARAM_CMDID
>     [ 1105.158895] ath11k c000000.wifi1: failed to set beacon tx rate 
> -11
>     [ 1114.164529] ath11k c000000.wifi1: wmi command 16387 timeout
>     [ 1114.164553] ath11k c000000.wifi1: failed to send 
> WMI_PDEV_SET_PARAM cmd
>     [ 1114.168899] ath11k c000000.wifi1: Failed to set beacon mode for 
> VDEV: 0
>     [ 1117.174527] ath11k c000000.wifi1: wmi command 28675 timeout
>     [ 1117.174550] ath11k c000000.wifi1: failed to send 
> WMI_BCN_TMPL_CMDID
>     [ 1117.178899] ath11k c000000.wifi1: failed to submit beacon
> template command: -11
>     [ 1117.185231] ath11k c000000.wifi1: failed to update bcn template: 
> -11
>     [ 1120.184524] ath11k c000000.wifi1: wmi command 20488 timeout
>     [ 1120.184545] ath11k c000000.wifi1: failed to send 
> WMI_VDEV_SET_PARAM_CMDID
>     [ 1120.188893] ath11k c000000.wifi1: Failed to set dtim period for
> VDEV 0: -11
>     [ 1123.194527] ath11k c000000.wifi1: wmi command 20488 timeout
>     [ 1123.194548] ath11k c000000.wifi1: failed to send 
> WMI_VDEV_SET_PARAM_CMDID
>     [ 1123.198895] ath11k c000000.wifi1: Failed to set CTS prot for 
> VDEV: 0
>     [ 1126.204526] ath11k c000000.wifi1: wmi command 20488 timeout
>     [ 1126.204547] ath11k c000000.wifi1: failed to send 
> WMI_VDEV_SET_PARAM_CMDID
>     [ 1126.208894] ath11k c000000.wifi1: Failed to set preamble for 
> VDEV: 0
>     [ 1129.214527] ath11k c000000.wifi1: wmi command 20488 timeout
>     [ 1129.214548] ath11k c000000.wifi1: failed to send 
> WMI_VDEV_SET_PARAM_CMDID
>     [ 1129.218897] ath11k c000000.wifi1: failed to set mgmt tx rate -11
>     [ 1132.224525] ath11k c000000.wifi1: wmi command 20488 timeout
>     [ 1132.224546] ath11k c000000.wifi1: failed to send 
> WMI_VDEV_SET_PARAM_CMDID
>     [ 1132.228894] ath11k c000000.wifi1: failed to set beacon tx rate 
> -11
> 
> ath11k must be unloaded + loaded again to fix this problem.
> 

Could you plz try removing below patch?
https://source.codeaurora.org/quic/qsdk/oss/system/feeds/wlan-open/tree/mac80211/patches/072-ath11k-print-stats-on-crash.patch?h=win_ap.1.0
Sven Eckelmann Aug. 27, 2019, 10:49 a.m. UTC | #7
On Tuesday, 27 August 2019 12:04:27 CEST Anilkumar Kolli wrote:
> Could you plz try removing below patch?
> https://source.codeaurora.org/quic/qsdk/oss/system/feeds/wlan-open/tree/mac80211/patches/072-ath11k-print-stats-on-crash.patch?h=win_ap.1.0

It is not applied. At least I can't find any ath11k_core_dump_bp_stats

Kind regards,
	Sven
diff mbox series

Patch

diff --git a/drivers/net/wireless/ath/ath11k/debug.c b/drivers/net/wireless/ath/ath11k/debug.c
new file mode 100644
index 000000000000..dc247b41390d
--- /dev/null
+++ b/drivers/net/wireless/ath/ath11k/debug.c
@@ -0,0 +1,1041 @@ 
+// SPDX-License-Identifier: ISC
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/vmalloc.h>
+#include "core.h"
+#include "debug.h"
+#include "wmi.h"
+#include "hal_rx.h"
+#include "dp_tx.h"
+#include "debug_htt_stats.h"
+#include "peer.h"
+
+void ath11k_info(struct ath11k_base *ab, const char *fmt, ...)
+{
+	struct va_format vaf = {
+		.fmt = fmt,
+	};
+	va_list args;
+
+	va_start(args, fmt);
+	vaf.va = &args;
+	dev_info(ab->dev, "%pV", &vaf);
+	/* TODO: Trace the log */
+	va_end(args);
+}
+
+void ath11k_err(struct ath11k_base *ab, const char *fmt, ...)
+{
+	struct va_format vaf = {
+		.fmt = fmt,
+	};
+	va_list args;
+
+	va_start(args, fmt);
+	vaf.va = &args;
+	dev_err(ab->dev, "%pV", &vaf);
+	/* TODO: Trace the log */
+	va_end(args);
+}
+
+void ath11k_warn(struct ath11k_base *ab, const char *fmt, ...)
+{
+	struct va_format vaf = {
+		.fmt = fmt,
+	};
+	va_list args;
+
+	va_start(args, fmt);
+	vaf.va = &args;
+	dev_warn_ratelimited(ab->dev, "%pV", &vaf);
+	/* TODO: Trace the log */
+	va_end(args);
+}
+
+#ifdef CONFIG_ATH11K_DEBUG
+void __ath11k_dbg(struct ath11k_base *ab, enum ath11k_debug_mask mask,
+		  const char *fmt, ...)
+{
+	struct va_format vaf;
+	va_list args;
+
+	va_start(args, fmt);
+
+	vaf.fmt = fmt;
+	vaf.va = &args;
+
+	if (ath11k_debug_mask & mask)
+		dev_printk(KERN_DEBUG, ab->dev, "%pV", &vaf);
+
+	/* TODO: trace log */
+
+	va_end(args);
+}
+
+void ath11k_dbg_dump(struct ath11k_base *ab,
+		     enum ath11k_debug_mask mask,
+		     const char *msg, const char *prefix,
+		     const void *buf, size_t len)
+{
+	char linebuf[256];
+	size_t linebuflen;
+	const void *ptr;
+
+	if (ath11k_debug_mask & mask) {
+		if (msg)
+			__ath11k_dbg(ab, mask, "%s\n", msg);
+
+		for (ptr = buf; (ptr - buf) < len; ptr += 16) {
+			linebuflen = 0;
+			linebuflen += scnprintf(linebuf + linebuflen,
+						sizeof(linebuf) - linebuflen,
+						"%s%08x: ",
+						(prefix ? prefix : ""),
+						(unsigned int)(ptr - buf));
+			hex_dump_to_buffer(ptr, len - (ptr - buf), 16, 1,
+					   linebuf + linebuflen,
+					   sizeof(linebuf) - linebuflen, true);
+			dev_printk(KERN_DEBUG, ab->dev, "%s\n", linebuf);
+		}
+	}
+}
+
+#endif
+
+#ifdef CONFIG_ATH11K_DEBUGFS
+static void ath11k_fw_stats_pdevs_free(struct list_head *head)
+{
+	struct ath11k_fw_stats_pdev *i, *tmp;
+
+	list_for_each_entry_safe(i, tmp, head, list) {
+		list_del(&i->list);
+		kfree(i);
+	}
+}
+
+static void ath11k_fw_stats_vdevs_free(struct list_head *head)
+{
+	struct ath11k_fw_stats_vdev *i, *tmp;
+
+	list_for_each_entry_safe(i, tmp, head, list) {
+		list_del(&i->list);
+		kfree(i);
+	}
+}
+
+static void ath11k_fw_stats_bcn_free(struct list_head *head)
+{
+	struct ath11k_fw_stats_bcn *i, *tmp;
+
+	list_for_each_entry_safe(i, tmp, head, list) {
+		list_del(&i->list);
+		kfree(i);
+	}
+}
+
+static void ath11k_debug_fw_stats_reset(struct ath11k *ar)
+{
+	spin_lock_bh(&ar->data_lock);
+	ar->debug.fw_stats_done = false;
+	ath11k_fw_stats_pdevs_free(&ar->debug.fw_stats.pdevs);
+	ath11k_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs);
+	spin_unlock_bh(&ar->data_lock);
+}
+
+void ath11k_debug_fw_stats_process(struct ath11k_base *ab, struct sk_buff *skb)
+{
+	struct ath11k_fw_stats stats = {};
+	struct ath11k *ar;
+	struct ath11k_pdev *pdev;
+	bool is_end;
+	static unsigned int num_vdev, num_bcn;
+	size_t total_vdevs_started = 0;
+	int i, ret;
+
+	INIT_LIST_HEAD(&stats.pdevs);
+	INIT_LIST_HEAD(&stats.vdevs);
+	INIT_LIST_HEAD(&stats.bcn);
+
+	ret = ath11k_wmi_pull_fw_stats(ab, skb, &stats);
+	if (ret) {
+		ath11k_warn(ab, "failed to pull fw stats: %d\n", ret);
+		goto free;
+	}
+
+	rcu_read_lock();
+	ar = ath11k_mac_get_ar_by_pdev_id(ab, stats.pdev_id);
+	if (!ar) {
+		rcu_read_unlock();
+		ath11k_warn(ab, "failed to get ar for pdev_id %d: %d\n",
+			    stats.pdev_id, ret);
+		goto free;
+	}
+
+	spin_lock_bh(&ar->data_lock);
+
+	if (stats.stats_id == WMI_REQUEST_PDEV_STAT) {
+		list_splice_tail_init(&stats.pdevs, &ar->debug.fw_stats.pdevs);
+		ar->debug.fw_stats_done = true;
+		goto complete;
+	}
+
+	if (stats.stats_id == WMI_REQUEST_VDEV_STAT) {
+		if (list_empty(&stats.vdevs)) {
+			ath11k_warn(ab, "empty vdev stats");
+			goto complete;
+		}
+		/* FW sends all the active VDEV stats irrespective of PDEV,
+		 * hence limit until the count of all VDEVs started
+		 */
+		for (i = 0; i < ab->num_radios; i++) {
+			pdev = rcu_dereference(ab->pdevs_active[i]);
+			if (pdev && pdev->ar)
+				total_vdevs_started += ar->num_started_vdevs;
+		}
+
+		is_end = ((++num_vdev) == total_vdevs_started ? true : false);
+
+		list_splice_tail_init(&stats.vdevs,
+				      &ar->debug.fw_stats.vdevs);
+
+		if (is_end) {
+			ar->debug.fw_stats_done = true;
+			num_vdev = 0;
+		}
+		goto complete;
+	}
+
+	if (stats.stats_id == WMI_REQUEST_BCN_STAT) {
+		if (list_empty(&stats.bcn)) {
+			ath11k_warn(ab, "empty bcn stats");
+			goto complete;
+		}
+		/* Mark end until we reached the count of all started VDEVs
+		 * within the PDEV
+		 */
+		is_end = ((++num_bcn) == ar->num_started_vdevs ? true : false);
+
+		list_splice_tail_init(&stats.bcn,
+				      &ar->debug.fw_stats.bcn);
+
+		if (is_end) {
+			ar->debug.fw_stats_done = true;
+			num_bcn = 0;
+		}
+	}
+complete:
+	complete(&ar->debug.fw_stats_complete);
+	rcu_read_unlock();
+	spin_unlock_bh(&ar->data_lock);
+
+free:
+	ath11k_fw_stats_pdevs_free(&stats.pdevs);
+	ath11k_fw_stats_vdevs_free(&stats.vdevs);
+	ath11k_fw_stats_bcn_free(&stats.bcn);
+}
+
+static int ath11k_debug_fw_stats_request(struct ath11k *ar,
+					 struct stats_request_params *req_param)
+{
+	struct ath11k_base *ab = ar->ab;
+	unsigned long timeout, time_left;
+	int ret;
+
+	lockdep_assert_held(&ar->conf_mutex);
+
+	/* FW stats can get split when exceeding the stats data buffer limit.
+	 * In that case, since there is no end marking for the back-to-back
+	 * received 'update stats' event, we keep a 3 seconds timeout in case,
+	 * fw_stats_done is not marked yet
+	 */
+	timeout = jiffies + msecs_to_jiffies(3 * HZ);
+
+	ath11k_debug_fw_stats_reset(ar);
+
+	reinit_completion(&ar->debug.fw_stats_complete);
+
+	ret = ath11k_wmi_send_stats_request_cmd(ar, req_param);
+
+	if (ret) {
+		ath11k_warn(ab, "could not request fw stats (%d)\n",
+			    ret);
+		return ret;
+	}
+
+	time_left =
+	wait_for_completion_timeout(&ar->debug.fw_stats_complete,
+				    1 * HZ);
+	if (!time_left)
+		return -ETIMEDOUT;
+
+	for (;;) {
+		if (time_after(jiffies, timeout))
+			break;
+
+		spin_lock_bh(&ar->data_lock);
+		if (ar->debug.fw_stats_done) {
+			spin_unlock_bh(&ar->data_lock);
+			break;
+		}
+		spin_unlock_bh(&ar->data_lock);
+	}
+	return 0;
+}
+
+static int ath11k_open_pdev_stats(struct inode *inode, struct file *file)
+{
+	struct ath11k *ar = inode->i_private;
+	struct ath11k_base *ab = ar->ab;
+	struct stats_request_params req_param;
+	void *buf = NULL;
+	int ret;
+
+	mutex_lock(&ar->conf_mutex);
+
+	if (ar->state != ATH11K_STATE_ON) {
+		ret = -ENETDOWN;
+		goto err_unlock;
+	}
+
+	buf = vmalloc(ATH11K_FW_STATS_BUF_SIZE);
+	if (!buf) {
+		ret = -ENOMEM;
+		goto err_unlock;
+	}
+
+	req_param.pdev_id = ar->pdev->pdev_id;
+	req_param.vdev_id = 0;
+	req_param.stats_id = WMI_REQUEST_PDEV_STAT;
+
+	ret = ath11k_debug_fw_stats_request(ar, &req_param);
+	if (ret) {
+		ath11k_warn(ab, "failed to request fw pdev stats: %d\n", ret);
+		goto err_free;
+	}
+
+	ath11k_wmi_fw_stats_fill(ar, &ar->debug.fw_stats, req_param.stats_id,
+				 buf);
+
+	file->private_data = buf;
+
+	mutex_unlock(&ar->conf_mutex);
+	return 0;
+
+err_free:
+	vfree(buf);
+
+err_unlock:
+	mutex_unlock(&ar->conf_mutex);
+	return ret;
+}
+
+static int ath11k_release_pdev_stats(struct inode *inode, struct file *file)
+{
+	vfree(file->private_data);
+
+	return 0;
+}
+
+static ssize_t ath11k_read_pdev_stats(struct file *file,
+				      char __user *user_buf,
+				      size_t count, loff_t *ppos)
+{
+	const char *buf = file->private_data;
+	size_t len = strlen(buf);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_pdev_stats = {
+	.open = ath11k_open_pdev_stats,
+	.release = ath11k_release_pdev_stats,
+	.read = ath11k_read_pdev_stats,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
+static int ath11k_open_vdev_stats(struct inode *inode, struct file *file)
+{
+	struct ath11k *ar = inode->i_private;
+	struct stats_request_params req_param;
+	void *buf = NULL;
+	int ret;
+
+	mutex_lock(&ar->conf_mutex);
+
+	if (ar->state != ATH11K_STATE_ON) {
+		ret = -ENETDOWN;
+		goto err_unlock;
+	}
+
+	buf = vmalloc(ATH11K_FW_STATS_BUF_SIZE);
+	if (!buf) {
+		ret = -ENOMEM;
+		goto err_unlock;
+	}
+
+	req_param.pdev_id = ar->pdev->pdev_id;
+	/* VDEV stats is always sent for all active VDEVs from FW */
+	req_param.vdev_id = 0;
+	req_param.stats_id = WMI_REQUEST_VDEV_STAT;
+
+	ret = ath11k_debug_fw_stats_request(ar, &req_param);
+	if (ret) {
+		ath11k_warn(ar->ab, "failed to request fw vdev stats: %d\n", ret);
+		goto err_free;
+	}
+
+	ath11k_wmi_fw_stats_fill(ar, &ar->debug.fw_stats, req_param.stats_id,
+				 buf);
+
+	file->private_data = buf;
+
+	mutex_unlock(&ar->conf_mutex);
+	return 0;
+
+err_free:
+	vfree(buf);
+
+err_unlock:
+	mutex_unlock(&ar->conf_mutex);
+	return ret;
+}
+
+static int ath11k_release_vdev_stats(struct inode *inode, struct file *file)
+{
+	vfree(file->private_data);
+
+	return 0;
+}
+
+static ssize_t ath11k_read_vdev_stats(struct file *file,
+				      char __user *user_buf,
+				      size_t count, loff_t *ppos)
+{
+	const char *buf = file->private_data;
+	size_t len = strlen(buf);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_vdev_stats = {
+	.open = ath11k_open_vdev_stats,
+	.release = ath11k_release_vdev_stats,
+	.read = ath11k_read_vdev_stats,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
+static int ath11k_open_bcn_stats(struct inode *inode, struct file *file)
+{
+	struct ath11k *ar = inode->i_private;
+	struct ath11k_vif *arvif;
+	struct stats_request_params req_param;
+	void *buf = NULL;
+	int ret;
+
+	mutex_lock(&ar->conf_mutex);
+
+	if (ar->state != ATH11K_STATE_ON) {
+		ret = -ENETDOWN;
+		goto err_unlock;
+	}
+
+	buf = vmalloc(ATH11K_FW_STATS_BUF_SIZE);
+	if (!buf) {
+		ret = -ENOMEM;
+		goto err_unlock;
+	}
+
+	req_param.stats_id = WMI_REQUEST_BCN_STAT;
+	req_param.pdev_id = ar->pdev->pdev_id;
+
+	/* loop all active VDEVs for bcn stats */
+	list_for_each_entry(arvif, &ar->arvifs, list) {
+		if (!arvif->is_up)
+			continue;
+
+		req_param.vdev_id = arvif->vdev_id;
+		ret = ath11k_debug_fw_stats_request(ar, &req_param);
+		if (ret) {
+			ath11k_warn(ar->ab, "failed to request fw bcn stats: %d\n", ret);
+			goto err_free;
+		}
+	}
+
+	ath11k_wmi_fw_stats_fill(ar, &ar->debug.fw_stats, req_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);
+	ath11k_fw_stats_bcn_free(&ar->debug.fw_stats.bcn);
+	spin_unlock_bh(&ar->data_lock);
+
+	file->private_data = buf;
+
+	mutex_unlock(&ar->conf_mutex);
+	return 0;
+
+err_free:
+	vfree(buf);
+
+err_unlock:
+	mutex_unlock(&ar->conf_mutex);
+	return ret;
+}
+
+static int ath11k_release_bcn_stats(struct inode *inode, struct file *file)
+{
+	vfree(file->private_data);
+
+	return 0;
+}
+
+static ssize_t ath11k_read_bcn_stats(struct file *file,
+				     char __user *user_buf,
+				     size_t count, loff_t *ppos)
+{
+	const char *buf = file->private_data;
+	size_t len = strlen(buf);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_bcn_stats = {
+	.open = ath11k_open_bcn_stats,
+	.release = ath11k_release_bcn_stats,
+	.read = ath11k_read_bcn_stats,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
+static ssize_t ath11k_read_simulate_fw_crash(struct file *file,
+					     char __user *user_buf,
+					     size_t count, loff_t *ppos)
+{
+	const char buf[] =
+		"To simulate firmware crash write one of the keywords to this file:\n"
+		"`assert` - this will send WMI_FORCE_FW_HANG_CMDID to firmware to cause assert.\n"
+		"`hw-restart` - this will simply queue hw restart without fw/hw actually crashing.\n";
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
+}
+
+/* Simulate firmware crash:
+ * 'soft': Call wmi command causing firmware hang. This firmware hang is
+ * recoverable by warm firmware reset.
+ * 'hard': Force firmware crash by setting any vdev parameter for not allowed
+ * vdev id. This is hard firmware crash because it is recoverable only by cold
+ * firmware reset.
+ */
+static ssize_t ath11k_write_simulate_fw_crash(struct file *file,
+					      const char __user *user_buf,
+					      size_t count, loff_t *ppos)
+{
+	struct ath11k_base *ab = file->private_data;
+	struct ath11k_pdev *pdev;
+	struct ath11k *ar = ab->pdevs[0].ar;
+	char buf[32] = {0};
+	ssize_t rc;
+	int i, ret, radioup;
+
+	for (i = 0; i < ab->num_radios; i++) {
+		pdev = &ab->pdevs[i];
+		ar = pdev->ar;
+		if (ar && ar->state == ATH11K_STATE_ON) {
+			radioup = 1;
+			break;
+		}
+	}
+	/* filter partial writes and invalid commands */
+	if (*ppos != 0 || count >= sizeof(buf) || count == 0)
+		return -EINVAL;
+
+	rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
+	if (rc < 0)
+		return rc;
+
+	/* drop the possible '\n' from the end */
+	if (buf[*ppos - 1] == '\n')
+		buf[*ppos - 1] = '\0';
+
+	if (radioup == 0) {
+		ret = -ENETDOWN;
+		goto exit;
+	}
+
+	if (!strcmp(buf, "assert")) {
+		ath11k_info(ab, "simulating firmware assert crash\n");
+		ret = ath11k_wmi_force_fw_hang_cmd(ar,
+						   ATH11K_WMI_FW_HANG_ASSERT_TYPE,
+						   ATH11K_WMI_FW_HANG_DELAY);
+	} else {
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	if (ret) {
+		ath11k_warn(ab, "failed to simulate firmware crash: %d\n", ret);
+		goto exit;
+	}
+
+	ret = count;
+
+exit:
+	return ret;
+}
+
+static const struct file_operations fops_simulate_fw_crash = {
+	.read = ath11k_read_simulate_fw_crash,
+	.write = ath11k_write_simulate_fw_crash,
+	.open = simple_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
+static ssize_t ath11k_write_enable_extd_tx_stats(struct file *file,
+						 const char __user *ubuf,
+						 size_t count, loff_t *ppos)
+{
+	struct ath11k *ar = file->private_data;
+	u32 filter;
+	int ret;
+
+	if (kstrtouint_from_user(ubuf, count, 0, &filter))
+		return -EINVAL;
+
+	mutex_lock(&ar->conf_mutex);
+
+	if (ar->state != ATH11K_STATE_ON) {
+		ret = -ENETDOWN;
+		goto out;
+	}
+
+	if (filter == ar->debug.extd_tx_stats) {
+		ret = count;
+		goto out;
+	}
+
+	ar->debug.extd_tx_stats = filter;
+	ret = count;
+
+out:
+	mutex_unlock(&ar->conf_mutex);
+	return ret;
+}
+
+static ssize_t ath11k_read_enable_extd_tx_stats(struct file *file,
+						char __user *ubuf,
+						size_t count, loff_t *ppos)
+
+{
+	char buf[32] = {0};
+	struct ath11k *ar = file->private_data;
+	int len = 0;
+
+	mutex_lock(&ar->conf_mutex);
+	len = scnprintf(buf, sizeof(buf) - len, "%08x\n",
+			ar->debug.extd_tx_stats);
+	mutex_unlock(&ar->conf_mutex);
+
+	return simple_read_from_buffer(ubuf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_extd_tx_stats = {
+	.read = ath11k_read_enable_extd_tx_stats,
+	.write = ath11k_write_enable_extd_tx_stats,
+	.open = simple_open
+};
+
+static ssize_t ath11k_write_extd_rx_stats(struct file *file,
+					  const char __user *ubuf,
+					  size_t count, loff_t *ppos)
+{
+	struct ath11k *ar = file->private_data;
+	struct htt_rx_ring_tlv_filter tlv_filter = {0};
+	u32 enable, rx_filter = 0, ring_id;
+	int ret;
+
+	if (kstrtouint_from_user(ubuf, count, 0, &enable))
+		return -EINVAL;
+
+	mutex_lock(&ar->conf_mutex);
+
+	if (ar->state != ATH11K_STATE_ON) {
+		ret = -ENETDOWN;
+		goto exit;
+	}
+
+	if (enable > 1) {
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	if (enable == ar->debug.extd_rx_stats) {
+		ret = count;
+		goto exit;
+	}
+
+	if (enable) {
+		rx_filter =  HTT_RX_FILTER_TLV_FLAGS_MPDU_START;
+		rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_START;
+		rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END;
+		rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS;
+		rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS_EXT;
+		rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END_STATUS_DONE;
+
+		tlv_filter.rx_filter = rx_filter;
+		tlv_filter.pkt_filter_flags0 = HTT_RX_FP_MGMT_FILTER_FLAGS0;
+		tlv_filter.pkt_filter_flags1 = HTT_RX_FP_MGMT_FILTER_FLAGS1;
+		tlv_filter.pkt_filter_flags2 = HTT_RX_FP_CTRL_FILTER_FLASG2;
+		tlv_filter.pkt_filter_flags3 = HTT_RX_FP_CTRL_FILTER_FLASG3 |
+			HTT_RX_FP_DATA_FILTER_FLASG3;
+	} else {
+		tlv_filter = ath11k_mac_mon_status_filter_default;
+	}
+
+	ring_id = ar->dp.rx_mon_status_refill_ring.refill_buf_ring.ring_id;
+	ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, ar->dp.mac_id,
+					       HAL_RXDMA_MONITOR_STATUS,
+					       DP_RX_BUFFER_SIZE, &tlv_filter);
+
+	if (ret) {
+		ath11k_warn(ar->ab, "failed to set rx filter for moniter status ring\n");
+		goto exit;
+	}
+
+	ar->debug.extd_rx_stats = enable;
+	ret = count;
+exit:
+	mutex_unlock(&ar->conf_mutex);
+	return ret;
+}
+
+static ssize_t ath11k_read_extd_rx_stats(struct file *file,
+					 char __user *ubuf,
+					 size_t count, loff_t *ppos)
+{
+	struct ath11k *ar = file->private_data;
+	char buf[32];
+	int len = 0;
+
+	mutex_lock(&ar->conf_mutex);
+	len = scnprintf(buf, sizeof(buf) - len, "%d\n",
+			ar->debug.extd_rx_stats);
+	mutex_unlock(&ar->conf_mutex);
+
+	return simple_read_from_buffer(ubuf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_extd_rx_stats = {
+	.read = ath11k_read_extd_rx_stats,
+	.write = ath11k_write_extd_rx_stats,
+	.open = simple_open,
+};
+
+static ssize_t ath11k_debug_dump_soc_rx_stats(struct file *file,
+					      char __user *user_buf,
+					      size_t count, loff_t *ppos)
+{
+	struct ath11k_base *ab = file->private_data;
+	struct ath11k_soc_dp_rx_stats *soc_stats = &ab->soc_stats;
+	int len = 0, i, retval;
+	const int size = 4096;
+	static const char *rxdma_err[HAL_REO_ENTR_RING_RXDMA_ECODE_MAX] = {
+			"Overflow", "MPDU len", "FCS", "Decrypt", "TKIP MIC",
+			"Unencrypt", "MSDU len", "MSDU limit", "WiFi parse",
+			"AMSDU parse", "SA timeout", "DA timeout",
+			"Flow timeout", "Flush req"};
+	static const char *reo_err[HAL_REO_DEST_RING_ERROR_CODE_MAX] = {
+			"Desc addr zero", "Desc inval", "AMPDU in non BA",
+			"Non BA dup", "BA dup", "Frame 2k jump", "BAR 2k jump",
+			"Frame OOR", "BAR OOR", "No BA session",
+			"Frame SN equal SSN", "PN check fail", "2k err",
+			"PN err", "Desc blocked"};
+
+	char *buf;
+
+	buf = kzalloc(size, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	len += scnprintf(buf + len, size - len, "SOC RX STATS:\n\n");
+	len += scnprintf(buf + len, size - len, "err ring pkts: %u\n",
+			 soc_stats->err_ring_pkts);
+	len += scnprintf(buf + len, size - len, "Invalid RBM: %u\n\n",
+			 soc_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], soc_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], soc_stats->reo_error[i]);
+
+	len += scnprintf(buf + len, size - len, "\nHAL REO errors:\n");
+	len += scnprintf(buf + len, size - len,
+			 "ring0: %u\nring1: %u\nring2: %u\nring3: %u\n",
+			 soc_stats->hal_reo_error[0],
+			 soc_stats->hal_reo_error[1],
+			 soc_stats->hal_reo_error[2],
+			 soc_stats->hal_reo_error[3]);
+
+	if (len > size)
+		len = size;
+	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+	kfree(buf);
+
+	return retval;
+}
+
+static const struct file_operations fops_soc_rx_stats = {
+	.read = ath11k_debug_dump_soc_rx_stats,
+	.open = simple_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
+int ath11k_debug_soc_create(struct ath11k_base *ab)
+{
+	ab->debugfs_soc = debugfs_create_dir("ath11k", NULL);
+
+	if (IS_ERR_OR_NULL(ab->debugfs_soc)) {
+		if (IS_ERR(ab->debugfs_soc))
+			return PTR_ERR(ab->debugfs_soc);
+		return -ENOMEM;
+	}
+
+	debugfs_create_file("simulate_fw_crash", 0600, ab->debugfs_soc, ab,
+			    &fops_simulate_fw_crash);
+
+	debugfs_create_file("soc_rx_stats", 0600, ab->debugfs_soc, ab,
+			    &fops_soc_rx_stats);
+
+	return 0;
+}
+
+void ath11k_debug_soc_destroy(struct ath11k_base *ab)
+{
+	debugfs_remove_recursive(ab->debugfs_soc);
+	ab->debugfs_soc = NULL;
+}
+
+void ath11k_debug_fw_stats_init(struct ath11k *ar)
+{
+	struct dentry *fwstats_dir = debugfs_create_dir("fw_stats",
+							ar->debug.debugfs_pdev);
+
+	ar->debug.fw_stats.debugfs_fwstats = fwstats_dir;
+
+	/* all stats debugfs files created are under "fw_stats" directory
+	 * created per PDEV
+	 */
+	debugfs_create_file("pdev_stats", 0600, fwstats_dir, ar,
+			    &fops_pdev_stats);
+	debugfs_create_file("vdev_stats", 0600, fwstats_dir, ar,
+			    &fops_vdev_stats);
+	debugfs_create_file("beacon_stats", 0600, fwstats_dir, ar,
+			    &fops_bcn_stats);
+
+	INIT_LIST_HEAD(&ar->debug.fw_stats.pdevs);
+	INIT_LIST_HEAD(&ar->debug.fw_stats.vdevs);
+	INIT_LIST_HEAD(&ar->debug.fw_stats.bcn);
+
+	init_completion(&ar->debug.fw_stats_complete);
+}
+
+static ssize_t ath11k_write_pktlog_filter(struct file *file,
+					  const char __user *ubuf,
+					  size_t count, loff_t *ppos)
+{
+	struct ath11k *ar = file->private_data;
+	struct htt_rx_ring_tlv_filter tlv_filter = {0};
+	u32 rx_filter = 0, ring_id, filter, mode;
+	u8 buf[128] = {0};
+	int ret;
+	ssize_t rc;
+
+	mutex_lock(&ar->conf_mutex);
+	if (ar->state != ATH11K_STATE_ON) {
+		ret = -ENETDOWN;
+		goto out;
+	}
+
+	rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count);
+	if (rc < 0) {
+		ret = rc;
+		goto out;
+	}
+	buf[rc] = '\0';
+
+	ret = sscanf(buf, "0x%x %u", &filter, &mode);
+	if (ret != 2) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (filter) {
+		ret = ath11k_wmi_pdev_pktlog_enable(ar, filter);
+		if (ret) {
+			ath11k_warn(ar->ab,
+				    "failed to enable pktlog filter %x: %d\n",
+				    ar->debug.pktlog_filter, ret);
+			goto out;
+		}
+	} else {
+		ret = ath11k_wmi_pdev_pktlog_disable(ar);
+		if (ret) {
+			ath11k_warn(ar->ab, "failed to disable pktlog: %d\n", ret);
+			goto out;
+		}
+	}
+
+#define HTT_RX_FILTER_TLV_LITE_MODE \
+			(HTT_RX_FILTER_TLV_FLAGS_PPDU_START | \
+			HTT_RX_FILTER_TLV_FLAGS_PPDU_END | \
+			HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS | \
+			HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS_EXT | \
+			HTT_RX_FILTER_TLV_FLAGS_PPDU_END_STATUS_DONE | \
+			HTT_RX_FILTER_TLV_FLAGS_MPDU_START)
+
+	if (mode == ATH11K_PKTLOG_MODE_FULL) {
+		rx_filter = HTT_RX_FILTER_TLV_LITE_MODE |
+			    HTT_RX_FILTER_TLV_FLAGS_MSDU_START |
+			    HTT_RX_FILTER_TLV_FLAGS_MSDU_END |
+			    HTT_RX_FILTER_TLV_FLAGS_MPDU_END |
+			    HTT_RX_FILTER_TLV_FLAGS_PACKET_HEADER |
+			    HTT_RX_FILTER_TLV_FLAGS_ATTENTION;
+	} else if (mode == ATH11K_PKTLOG_MODE_LITE) {
+		rx_filter = HTT_RX_FILTER_TLV_LITE_MODE;
+	}
+
+	tlv_filter.rx_filter = rx_filter;
+	if (rx_filter) {
+		tlv_filter.pkt_filter_flags0 = HTT_RX_FP_MGMT_FILTER_FLAGS0;
+		tlv_filter.pkt_filter_flags1 = HTT_RX_FP_MGMT_FILTER_FLAGS1;
+		tlv_filter.pkt_filter_flags2 = HTT_RX_FP_CTRL_FILTER_FLASG2;
+		tlv_filter.pkt_filter_flags3 = HTT_RX_FP_CTRL_FILTER_FLASG3 |
+					       HTT_RX_FP_DATA_FILTER_FLASG3;
+	}
+
+	ring_id = ar->dp.rx_mon_status_refill_ring.refill_buf_ring.ring_id;
+	ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, ar->dp.mac_id,
+					       HAL_RXDMA_MONITOR_STATUS,
+					       DP_RX_BUFFER_SIZE, &tlv_filter);
+	if (ret) {
+		ath11k_warn(ar->ab, "failed to set rx filter for moniter status ring\n");
+		goto out;
+	}
+
+	ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "pktlog filter %d mode %s\n",
+		   filter, ((mode == ATH11K_PKTLOG_MODE_FULL) ? "full" : "lite"));
+
+	ar->debug.pktlog_filter = filter;
+	ar->debug.pktlog_mode = mode;
+	ret = count;
+
+out:
+	mutex_unlock(&ar->conf_mutex);
+	return ret;
+}
+
+static ssize_t ath11k_read_pktlog_filter(struct file *file,
+					 char __user *ubuf,
+					 size_t count, loff_t *ppos)
+
+{
+	char buf[32] = {0};
+	struct ath11k *ar = file->private_data;
+	int len = 0;
+
+	mutex_lock(&ar->conf_mutex);
+	len = scnprintf(buf, sizeof(buf) - len, "%08x %08x\n",
+			ar->debug.pktlog_filter,
+			ar->debug.pktlog_mode);
+	mutex_unlock(&ar->conf_mutex);
+
+	return simple_read_from_buffer(ubuf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_pktlog_filter = {
+	.read = ath11k_read_pktlog_filter,
+	.write = ath11k_write_pktlog_filter,
+	.open = simple_open
+};
+
+static ssize_t ath11k_write_simulate_radar(struct file *file,
+					   const char __user *user_buf,
+					   size_t count, loff_t *ppos)
+{
+	struct ath11k *ar = file->private_data;
+	int ret;
+
+	ret = ath11k_wmi_simulate_radar(ar);
+	if (ret)
+		return ret;
+
+	return count;
+}
+
+static const struct file_operations fops_simulate_radar = {
+	.write = ath11k_write_simulate_radar,
+	.open = simple_open
+};
+
+int ath11k_debug_register(struct ath11k *ar)
+{
+	struct ath11k_base *ab = ar->ab;
+	char pdev_name[5];
+	char buf[100] = {0};
+
+	snprintf(pdev_name, sizeof(pdev_name), "%s%d", "mac", ar->pdev_idx);
+
+	ar->debug.debugfs_pdev = debugfs_create_dir(pdev_name, ab->debugfs_soc);
+
+	if (IS_ERR_OR_NULL(ar->debug.debugfs_pdev)) {
+		if (IS_ERR(ar->debug.debugfs_pdev))
+			return PTR_ERR(ar->debug.debugfs_pdev);
+
+		return -ENOMEM;
+	}
+
+	/* Create a symlink under ieee80211/phy* */
+	snprintf(buf, 100, "../../%pd2", ar->debug.debugfs_pdev);
+	debugfs_create_symlink("ath11k", ar->hw->wiphy->debugfsdir, buf);
+
+	ath11k_debug_htt_stats_init(ar);
+
+	ath11k_debug_fw_stats_init(ar);
+
+	debugfs_create_file("ext_tx_stats", 0644,
+			    ar->debug.debugfs_pdev, ar,
+			    &fops_extd_tx_stats);
+	debugfs_create_file("ext_rx_stats", 0644,
+			    ar->debug.debugfs_pdev, ar,
+			    &fops_extd_rx_stats);
+	debugfs_create_file("pktlog_filter", 0644,
+			    ar->debug.debugfs_pdev, ar,
+			    &fops_pktlog_filter);
+
+	if (ar->hw->wiphy->bands[NL80211_BAND_5GHZ]) {
+		debugfs_create_file("dfs_simulate_radar", 0200,
+				    ar->debug.debugfs_pdev, ar,
+				    &fops_simulate_radar);
+		debugfs_create_bool("dfs_block_radar_events", 0200,
+				    ar->debug.debugfs_pdev,
+				    &ar->dfs_block_radar_events);
+	}
+
+	return 0;
+}
+
+void ath11k_debug_unregister(struct ath11k *ar)
+{
+}
+#endif /* CONFIG_ATH11K_DEBUGFS */