int (*mac_lv1_rcvy)(struct rtw89_dev *rtwdev, enum rtw89_lv1_rcvy_step step);
        void (*dump_err_status)(struct rtw89_dev *rtwdev);
        int (*napi_poll)(struct napi_struct *napi, int budget);
+
+       /* Deal with locks inside recovery_start and recovery_complete callbacks
+        * by hci instance, and handle things which need to consider under SER.
+        * e.g. turn on/off interrupts except for the one for halt notification.
+        */
+       void (*recovery_start)(struct rtw89_dev *rtwdev);
+       void (*recovery_complete)(struct rtw89_dev *rtwdev);
 };
 
 struct rtw89_hci_info {
                return rtwdev->hci.ops->flush_queues(rtwdev, queues, drop);
 }
 
+static inline void rtw89_hci_recovery_start(struct rtw89_dev *rtwdev)
+{
+       if (rtwdev->hci.ops->recovery_start)
+               rtwdev->hci.ops->recovery_start(rtwdev);
+}
+
+static inline void rtw89_hci_recovery_complete(struct rtw89_dev *rtwdev)
+{
+       if (rtwdev->hci.ops->recovery_complete)
+               rtwdev->hci.ops->recovery_complete(rtwdev);
+}
+
 static inline u8 rtw89_read8(struct rtw89_dev *rtwdev, u32 addr)
 {
        return rtwdev->hci.ops->read8(rtwdev, addr);
 
        rtw89_write32(rtwdev, R_AX_PCIE_HIMR10, 0);
 }
 
+static void rtw89_pci_ops_recovery_start(struct rtw89_dev *rtwdev)
+{
+       struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
+       unsigned long flags;
+
+       spin_lock_irqsave(&rtwpci->irq_lock, flags);
+       rtwpci->under_recovery = true;
+       rtw89_write32(rtwdev, R_AX_PCIE_HIMR00, 0);
+       rtw89_write32(rtwdev, R_AX_PCIE_HIMR10, 0);
+       spin_unlock_irqrestore(&rtwpci->irq_lock, flags);
+}
+
+static void rtw89_pci_ops_recovery_complete(struct rtw89_dev *rtwdev)
+{
+       struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
+       unsigned long flags;
+
+       spin_lock_irqsave(&rtwpci->irq_lock, flags);
+       rtwpci->under_recovery = false;
+       rtw89_pci_enable_intr(rtwdev, rtwpci);
+       spin_unlock_irqrestore(&rtwpci->irq_lock, flags);
+}
+
 static irqreturn_t rtw89_pci_interrupt_threadfn(int irq, void *dev)
 {
        struct rtw89_dev *rtwdev = dev;
        if (unlikely(isrs.halt_c2h_isrs & B_AX_HALT_C2H_INT_EN))
                rtw89_ser_notify(rtwdev, rtw89_mac_get_err_status(rtwdev));
 
+       if (unlikely(rtwpci->under_recovery))
+               return IRQ_HANDLED;
+
        if (likely(rtwpci->running)) {
                local_bh_disable();
                napi_schedule(&rtwdev->napi);
        .mac_lv1_rcvy   = rtw89_pci_ops_mac_lv1_recovery,
        .dump_err_status = rtw89_pci_ops_dump_err_status,
        .napi_poll      = rtw89_pci_napi_poll,
+
+       .recovery_start = rtw89_pci_ops_recovery_start,
+       .recovery_complete = rtw89_pci_ops_recovery_complete,
 };
 
 int rtw89_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
 /* state handler */
 static void ser_idle_st_hdl(struct rtw89_ser *ser, u8 evt)
 {
+       struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser);
+
        switch (evt) {
        case SER_EV_STATE_IN:
+               rtw89_hci_recovery_complete(rtwdev);
                break;
        case SER_EV_L1_RESET:
                ser_state_goto(ser, SER_RESET_TRX_ST);
                ser_state_goto(ser, SER_L2_RESET_ST);
                break;
        case SER_EV_STATE_OUT:
+               rtw89_hci_recovery_start(rtwdev);
        default:
                break;
        }