return count;
 }
 
+static int rtw89_dbg_trigger_ctrl_error(struct rtw89_dev *rtwdev)
+{
+       struct rtw89_cpuio_ctrl ctrl_para = {0};
+       u16 pkt_id;
+
+       rtw89_leave_ps_mode(rtwdev);
+
+       pkt_id = rtw89_mac_dle_buf_req(rtwdev, 0x20, true);
+       switch (pkt_id) {
+       case 0xffff:
+               return -ETIMEDOUT;
+       case 0xfff:
+               return -ENOMEM;
+       default:
+               break;
+       }
+
+       /* intentionally, enqueue two pkt, but has only one pkt id */
+       ctrl_para.cmd_type = CPUIO_OP_CMD_ENQ_TO_HEAD;
+       ctrl_para.start_pktid = pkt_id;
+       ctrl_para.end_pktid = pkt_id;
+       ctrl_para.pkt_num = 1; /* start from 0 */
+       ctrl_para.dst_pid = WDE_DLE_PORT_ID_WDRLS;
+       ctrl_para.dst_qid = WDE_DLE_QUEID_NO_REPORT;
+
+       if (rtw89_mac_set_cpuio(rtwdev, &ctrl_para, true))
+               return -EFAULT;
+
+       return 0;
+}
+
 static int
 rtw89_debug_priv_fw_crash_get(struct seq_file *m, void *v)
 {
        struct rtw89_dev *rtwdev = debugfs_priv->rtwdev;
 
        seq_printf(m, "%d\n",
-                  test_bit(RTW89_FLAG_RESTART_TRIGGER, rtwdev->flags));
+                  test_bit(RTW89_FLAG_CRASH_SIMULATING, rtwdev->flags));
        return 0;
 }
 
+enum rtw89_dbg_crash_simulation_type {
+       RTW89_DBG_SIM_CPU_EXCEPTION = 1,
+       RTW89_DBG_SIM_CTRL_ERROR = 2,
+};
+
 static ssize_t
 rtw89_debug_priv_fw_crash_set(struct file *filp, const char __user *user_buf,
                              size_t count, loff_t *loff)
        struct seq_file *m = (struct seq_file *)filp->private_data;
        struct rtw89_debugfs_priv *debugfs_priv = m->private;
        struct rtw89_dev *rtwdev = debugfs_priv->rtwdev;
-       bool fw_crash;
+       int (*sim)(struct rtw89_dev *rtwdev);
+       u8 crash_type;
        int ret;
 
-       if (!RTW89_CHK_FW_FEATURE(CRASH_TRIGGER, &rtwdev->fw))
-               return -EOPNOTSUPP;
-
-       ret = kstrtobool_from_user(user_buf, count, &fw_crash);
+       ret = kstrtou8_from_user(user_buf, count, 0, &crash_type);
        if (ret)
                return -EINVAL;
 
-       if (!fw_crash)
+       switch (crash_type) {
+       case RTW89_DBG_SIM_CPU_EXCEPTION:
+               if (!RTW89_CHK_FW_FEATURE(CRASH_TRIGGER, &rtwdev->fw))
+                       return -EOPNOTSUPP;
+               sim = rtw89_fw_h2c_trigger_cpu_exception;
+               break;
+       case RTW89_DBG_SIM_CTRL_ERROR:
+               sim = rtw89_dbg_trigger_ctrl_error;
+               break;
+       default:
                return -EINVAL;
+       }
 
        mutex_lock(&rtwdev->mutex);
-       set_bit(RTW89_FLAG_RESTART_TRIGGER, rtwdev->flags);
-       ret = rtw89_fw_h2c_trigger_cpu_exception(rtwdev);
+       set_bit(RTW89_FLAG_CRASH_SIMULATING, rtwdev->flags);
+       ret = sim(rtwdev);
        mutex_unlock(&rtwdev->mutex);
 
        if (ret)
 
 }
 EXPORT_SYMBOL(rtw89_mac_resume_sch_tx_v1);
 
-static u16 rtw89_mac_dle_buf_req(struct rtw89_dev *rtwdev, u16 buf_len,
-                                bool wd)
+u16 rtw89_mac_dle_buf_req(struct rtw89_dev *rtwdev, u16 buf_len, bool wd)
 {
        u32 val, reg;
        int ret;
        return FIELD_GET(B_AX_WD_BUF_STAT_PKTID_MASK, val);
 }
 
-static int rtw89_mac_set_cpuio(struct rtw89_dev *rtwdev,
-                              struct rtw89_cpuio_ctrl *ctrl_para,
-                              bool wd)
+int rtw89_mac_set_cpuio(struct rtw89_dev *rtwdev,
+                       struct rtw89_cpuio_ctrl *ctrl_para, bool wd)
 {
        u32 val, cmd_type, reg;
        int ret;
 
 int rtw89_mac_write_xtal_si(struct rtw89_dev *rtwdev, u8 offset, u8 val, u8 mask);
 int rtw89_mac_read_xtal_si(struct rtw89_dev *rtwdev, u8 offset, u8 *val);
 void rtw89_mac_pkt_drop_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif);
+u16 rtw89_mac_dle_buf_req(struct rtw89_dev *rtwdev, u16 buf_len, bool wd);
+int rtw89_mac_set_cpuio(struct rtw89_dev *rtwdev,
+                       struct rtw89_cpuio_ctrl *ctrl_para, bool wd);
 
 #endif