container_of(work, struct hl_device_reset_work,
                                reset_work.work);
        struct hl_device *hdev = device_reset_work->hdev;
+       u32 flags;
        int rc;
 
-       rc = hl_device_reset(hdev, HL_RESET_HARD | HL_RESET_FROM_RESET_THREAD);
+       flags = HL_RESET_HARD | HL_RESET_FROM_RESET_THREAD;
+
+       if (device_reset_work->fw_reset)
+               flags |= HL_RESET_FW;
+
+       rc = hl_device_reset(hdev, flags);
        if ((rc == -EBUSY) && !hdev->device_fini_pending) {
                dev_info(hdev->dev,
                        "Could not reset device. will try again in %u seconds",
        mutex_unlock(&hdev->fpriv_list_lock);
 }
 
-static void cleanup_resources(struct hl_device *hdev, bool hard_reset)
+static void cleanup_resources(struct hl_device *hdev, bool hard_reset, bool fw_reset)
 {
        if (hard_reset)
                device_late_fini(hdev);
         * completions from H/W and we won't have any accesses from the
         * H/W to the host machine
         */
-       hdev->asic_funcs->halt_engines(hdev, hard_reset);
+       hdev->asic_funcs->halt_engines(hdev, hard_reset, fw_reset);
 
        /* Go over all the queues, release all CS and their jobs */
        hl_cs_rollback_all(hdev);
 int hl_device_reset(struct hl_device *hdev, u32 flags)
 {
        u64 idle_mask[HL_BUSY_ENGINES_MASK_EXT_SIZE] = {0};
-       bool hard_reset, from_hard_reset_thread, hard_instead_soft = false;
+       bool hard_reset, from_hard_reset_thread, fw_reset, hard_instead_soft = false;
        int i, rc;
 
        if (!hdev->init_done) {
 
        hard_reset = !!(flags & HL_RESET_HARD);
        from_hard_reset_thread = !!(flags & HL_RESET_FROM_RESET_THREAD);
+       fw_reset = !!(flags & HL_RESET_FW);
 
        if (!hard_reset && !hdev->supports_soft_reset) {
                hard_instead_soft = true;
                else
                        hdev->curr_reset_cause = HL_RESET_CAUSE_UNKNOWN;
 
-               /*
-                * if reset is due to heartbeat, device CPU is no responsive in
-                * which case no point sending PCI disable message to it
+               /* If reset is due to heartbeat, device CPU is no responsive in
+                * which case no point sending PCI disable message to it.
+                *
+                * If F/W is performing the reset, no need to send it a message to disable
+                * PCI access
                 */
-               if (hard_reset && !(flags & HL_RESET_HEARTBEAT)) {
+               if (hard_reset && !(flags & (HL_RESET_HEARTBEAT | HL_RESET_FW))) {
                        /* Disable PCI access from device F/W so he won't send
                         * us additional interrupts. We disable MSI/MSI-X at
                         * the halt_engines function and we can't have the F/W
 
                hdev->process_kill_trial_cnt = 0;
 
+               hdev->device_reset_work.fw_reset = fw_reset;
+
                /*
                 * Because the reset function can't run from heartbeat work,
                 * we need to call the reset function from a dedicated work.
                return 0;
        }
 
-       cleanup_resources(hdev, hard_reset);
+       cleanup_resources(hdev, hard_reset, fw_reset);
 
 kill_processes:
        if (hard_reset) {
        }
 
        /* Reset the H/W. It will be in idle state after this returns */
-       hdev->asic_funcs->hw_fini(hdev, hard_reset);
+       hdev->asic_funcs->hw_fini(hdev, hard_reset, fw_reset);
 
        if (hard_reset) {
                hdev->fw_loader.linux_loaded = false;
 
        hl_hwmon_fini(hdev);
 
-       cleanup_resources(hdev, true);
+       cleanup_resources(hdev, true, false);
 
        /* Kill processes here after CS rollback. This is because the process
         * can't really exit until all its CSs are done, which is what we
        hl_cb_pool_fini(hdev);
 
        /* Reset the H/W. It will be in idle state after this returns */
-       hdev->asic_funcs->hw_fini(hdev, true);
+       hdev->asic_funcs->hw_fini(hdev, true, false);
 
        hdev->fw_loader.linux_loaded = false;
 
 
  *
  * - HL_RESET_DEVICE_RELEASE
  *       Set if reset is due to device release
+ *
+ * - HL_RESET_FW
+ *       F/W will perform the reset. No need to ask it to reset the device. This is relevant
+ *       only when running with secured f/w
  */
 #define HL_RESET_HARD                  (1 << 0)
 #define HL_RESET_FROM_RESET_THREAD     (1 << 1)
 #define HL_RESET_HEARTBEAT             (1 << 2)
 #define HL_RESET_TDR                   (1 << 3)
 #define HL_RESET_DEVICE_RELEASE                (1 << 4)
+#define HL_RESET_FW                    (1 << 5)
 
 #define HL_MAX_SOBS_PER_MONITOR        8
 
        int (*sw_init)(struct hl_device *hdev);
        int (*sw_fini)(struct hl_device *hdev);
        int (*hw_init)(struct hl_device *hdev);
-       void (*hw_fini)(struct hl_device *hdev, bool hard_reset);
-       void (*halt_engines)(struct hl_device *hdev, bool hard_reset);
+       void (*hw_fini)(struct hl_device *hdev, bool hard_reset, bool fw_reset);
+       void (*halt_engines)(struct hl_device *hdev, bool hard_reset, bool fw_reset);
        int (*suspend)(struct hl_device *hdev);
        int (*resume)(struct hl_device *hdev);
        int (*mmap)(struct hl_device *hdev, struct vm_area_struct *vma,
  * @wq: work queue for device reset procedure.
  * @reset_work: reset work to be done.
  * @hdev: habanalabs device structure.
+ * @fw_reset: whether f/w will do the reset without us sending them a message to do it.
  */
 struct hl_device_reset_work {
        struct workqueue_struct         *wq;
        struct delayed_work             reset_work;
        struct hl_device                *hdev;
+       bool                            fw_reset;
 };
 
 /**
 
                result = PCI_ERS_RESULT_NONE;
        }
 
-       hdev->asic_funcs->halt_engines(hdev, true);
+       hdev->asic_funcs->halt_engines(hdev, true, false);
 
        return result;
 }
 
                                        GAUDI_BOOT_FIT_REQ_TIMEOUT_USEC);
        if (rc) {
                if (hdev->reset_on_preboot_fail)
-                       hdev->asic_funcs->hw_fini(hdev, true);
+                       hdev->asic_funcs->hw_fini(hdev, true, false);
                goto pci_fini;
        }
 
        if (gaudi_get_hw_state(hdev) == HL_DEVICE_HW_STATE_DIRTY) {
                dev_info(hdev->dev,
                        "H/W state is dirty, must reset before initializing\n");
-               hdev->asic_funcs->hw_fini(hdev, true);
+               hdev->asic_funcs->hw_fini(hdev, true, false);
        }
 
        return 0;
        WREG32(mmPSOC_TIMESTAMP_BASE - CFG_BASE, 0);
 }
 
-static void gaudi_halt_engines(struct hl_device *hdev, bool hard_reset)
+static void gaudi_halt_engines(struct hl_device *hdev, bool hard_reset, bool fw_reset)
 {
        u32 wait_timeout_ms;
 
        else
                wait_timeout_ms = GAUDI_RESET_WAIT_MSEC;
 
+       if (fw_reset)
+               goto skip_engines;
+
        gaudi_stop_nic_qmans(hdev);
        gaudi_stop_mme_qmans(hdev);
        gaudi_stop_tpc_qmans(hdev);
 
        gaudi_disable_timestamp(hdev);
 
+skip_engines:
        gaudi_disable_msi(hdev);
 }
 
        return rc;
 }
 
-static void gaudi_hw_fini(struct hl_device *hdev, bool hard_reset)
+static void gaudi_hw_fini(struct hl_device *hdev, bool hard_reset, bool fw_reset)
 {
        struct cpu_dyn_regs *dyn_regs =
                        &hdev->fw_loader.dynamic_loader.comm_desc.cpu_dyn_regs;
                cpu_timeout_ms = GAUDI_CPU_RESET_WAIT_MSEC;
        }
 
+       if (fw_reset) {
+               dev_info(hdev->dev,
+                       "Firmware performs HARD reset, going to wait %dms\n",
+                       reset_timeout_ms);
+
+               goto skip_reset;
+       }
+
        driver_performs_reset = !!(!hdev->asic_prop.fw_security_enabled &&
                                        !hdev->asic_prop.hard_reset_done_by_fw);
 
                        reset_timeout_ms);
        }
 
+skip_reset:
        /*
         * After hard reset, we can't poll the BTM_FSM register because the PSOC
         * itself is in reset. Need to wait until the reset is deasserted
                                        tpc_dec_event_to_tpc_id(event_type),
                                        "AXI_SLV_DEC_Error");
                if (reset_required) {
-                       dev_err(hdev->dev, "hard reset required due to %s\n",
+                       dev_err(hdev->dev, "reset required due to %s\n",
                                gaudi_irq_map_table[event_type].name);
 
-                       goto reset_device;
+                       hl_device_reset(hdev, 0);
                } else {
                        hl_fw_unmask_irq(hdev, event_type);
                }
                                        tpc_krn_event_to_tpc_id(event_type),
                                        "KRN_ERR");
                if (reset_required) {
-                       dev_err(hdev->dev, "hard reset required due to %s\n",
+                       dev_err(hdev->dev, "reset required due to %s\n",
                                gaudi_irq_map_table[event_type].name);
 
-                       goto reset_device;
+                       hl_device_reset(hdev, 0);
                } else {
                        hl_fw_unmask_irq(hdev, event_type);
                }
        return;
 
 reset_device:
-       if (hdev->hard_reset_on_fw_events)
+       if (hdev->asic_prop.fw_security_enabled)
+               hl_device_reset(hdev, HL_RESET_HARD | HL_RESET_FW);
+       else if (hdev->hard_reset_on_fw_events)
                hl_device_reset(hdev, HL_RESET_HARD);
        else
                hl_fw_unmask_irq(hdev, event_type);
 
                                        GOYA_BOOT_FIT_REQ_TIMEOUT_USEC);
        if (rc) {
                if (hdev->reset_on_preboot_fail)
-                       hdev->asic_funcs->hw_fini(hdev, true);
+                       hdev->asic_funcs->hw_fini(hdev, true, false);
                goto pci_fini;
        }
 
        if (goya_get_hw_state(hdev) == HL_DEVICE_HW_STATE_DIRTY) {
                dev_info(hdev->dev,
                        "H/W state is dirty, must reset before initializing\n");
-               hdev->asic_funcs->hw_fini(hdev, true);
+               hdev->asic_funcs->hw_fini(hdev, true, false);
        }
 
        if (!hdev->pldm) {
        WREG32(mmPSOC_TIMESTAMP_BASE - CFG_BASE, 0);
 }
 
-static void goya_halt_engines(struct hl_device *hdev, bool hard_reset)
+static void goya_halt_engines(struct hl_device *hdev, bool hard_reset, bool fw_reset)
 {
        u32 wait_timeout_ms;
 
        return rc;
 }
 
-/*
- * goya_hw_fini - Goya hardware tear-down code
- *
- * @hdev: pointer to hl_device structure
- * @hard_reset: should we do hard reset to all engines or just reset the
- *              compute/dma engines
- */
-static void goya_hw_fini(struct hl_device *hdev, bool hard_reset)
+static void goya_hw_fini(struct hl_device *hdev, bool hard_reset, bool fw_reset)
 {
        struct goya_device *goya = hdev->asic_specific;
        u32 reset_timeout_ms, cpu_timeout_ms, status;