]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
wifi: ath12k: Add support to simulate firmware crash
authorDinesh Karthikeyan <quic_dinek@quicinc.com>
Thu, 17 Apr 2025 06:52:37 +0000 (12:22 +0530)
committerJeff Johnson <jeff.johnson@oss.qualcomm.com>
Fri, 16 May 2025 19:38:52 +0000 (12:38 -0700)
Add debugfs support to simulate firmware crash to test firmware restart.

Usage:
-----
echo assert > /sys/kernel/debug/ath12k/pci-0000\:58\:00.0/simulate_fw_crash

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1

Signed-off-by: Dinesh Karthikeyan <quic_dinek@quicinc.com>
Signed-off-by: Ramya Gnanasekar <quic_rgnanase@quicinc.com>
Signed-off-by: Maharaja Kennadyrajan <maharaja.kennadyrajan@oss.qualcomm.com>
Reviewed-by: Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com>
Link: https://patch.msgid.link/20250417065237.2507613-1-maharaja.kennadyrajan@oss.qualcomm.com
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
drivers/net/wireless/ath/ath12k/debugfs.c
drivers/net/wireless/ath/ath12k/debugfs.h
drivers/net/wireless/ath/ath12k/mac.c

index bab7be9c5a383859adb21bbc70779613187fd25c..1f0983c33885f2ee6b8999b9214d273def3fbf93 100644 (file)
@@ -33,6 +33,82 @@ static const struct file_operations fops_simulate_radar = {
        .open = simple_open
 };
 
+static ssize_t ath12k_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` - send WMI_FORCE_FW_HANG_CMDID to firmware to cause assert.\n";
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
+}
+
+static ssize_t
+ath12k_write_simulate_fw_crash(struct file *file,
+                              const char __user *user_buf,
+                              size_t count, loff_t *ppos)
+{
+       struct ath12k_base *ab = file->private_data;
+       struct ath12k_pdev *pdev;
+       struct ath12k *ar = NULL;
+       char buf[32] = {0};
+       int i, ret;
+       ssize_t rc;
+
+       /* 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';
+
+       for (i = 0; i < ab->num_radios; i++) {
+               pdev = &ab->pdevs[i];
+               ar = pdev->ar;
+               if (ar)
+                       break;
+       }
+
+       if (!ar)
+               return -ENETDOWN;
+
+       if (!strcmp(buf, "assert")) {
+               ath12k_info(ab, "simulating firmware assert crash\n");
+               ret = ath12k_wmi_force_fw_hang_cmd(ar,
+                                                  ATH12K_WMI_FW_HANG_ASSERT_TYPE,
+                                                  ATH12K_WMI_FW_HANG_DELAY);
+       } else {
+               return -EINVAL;
+       }
+
+       if (ret) {
+               ath12k_warn(ab, "failed to simulate firmware crash: %d\n", ret);
+               return ret;
+       }
+
+       return count;
+}
+
+static const struct file_operations fops_simulate_fw_crash = {
+       .read = ath12k_read_simulate_fw_crash,
+       .write = ath12k_write_simulate_fw_crash,
+       .open = simple_open,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
+void ath12k_debugfs_pdev_create(struct ath12k_base *ab)
+{
+       debugfs_create_file("simulate_fw_crash", 0600, ab->debugfs_soc, ab,
+                           &fops_simulate_fw_crash);
+}
+
 static ssize_t ath12k_write_tpc_stats_type(struct file *file,
                                           const char __user *user_buf,
                                           size_t count, loff_t *ppos)
index 74a255a27886dafc8020789f150932c18c86037c..ebef7dace3448e4bdf2d6cb155d089267315172c 100644 (file)
@@ -16,6 +16,7 @@ void ath12k_debugfs_fw_stats_process(struct ath12k *ar,
                                     struct ath12k_fw_stats *stats);
 void ath12k_debugfs_op_vif_add(struct ieee80211_hw *hw,
                               struct ieee80211_vif *vif);
+void ath12k_debugfs_pdev_create(struct ath12k_base *ab);
 
 static inline bool ath12k_debugfs_is_extd_rx_stats_enabled(struct ath12k *ar)
 {
@@ -144,6 +145,10 @@ static inline void ath12k_debugfs_op_vif_add(struct ieee80211_hw *hw,
                                             struct ieee80211_vif *vif)
 {
 }
+
+static inline void ath12k_debugfs_pdev_create(struct ath12k_base *ab)
+{
+}
 #endif /* CONFIG_ATH12K_DEBUGFS */
 
 #endif /* _ATH12K_DEBUGFS_H_ */
index 64a748c873f3b71f55a47804bab75c5f3840256c..2deffcf3682692fd414800d3c3d67f844c090835 100644 (file)
@@ -12033,6 +12033,7 @@ int ath12k_mac_allocate(struct ath12k_hw_group *ag)
                if (!ab)
                        continue;
 
+               ath12k_debugfs_pdev_create(ab);
                ath12k_mac_set_device_defaults(ab);
                total_radio += ab->num_radios;
        }