int (*enable_comms)(struct adf_accel_dev *accel_dev);
        u32 (*get_pf2vf_offset)(u32 i);
        u32 (*get_vf2pf_offset)(u32 i);
-       u32 (*get_vf2pf_sources)(void __iomem *pmisc_addr);
        void (*enable_vf2pf_interrupts)(void __iomem *pmisc_addr, u32 vf_mask);
        void (*disable_vf2pf_interrupts)(void __iomem *pmisc_addr, u32 vf_mask);
+       u32 (*disable_pending_vf2pf_interrupts)(void __iomem *pmisc_addr);
        int (*send_msg)(struct adf_accel_dev *accel_dev, struct pfvf_message msg,
                        u32 pfvf_offset, struct mutex *csr_lock);
        struct pfvf_message (*recv_msg)(struct adf_accel_dev *accel_dev,
 
 #include "adf_pfvf_utils.h"
 
  /* VF2PF interrupts */
+#define ADF_GEN2_VF_MSK                        0xFFFF
 #define ADF_GEN2_ERR_REG_VF2PF(vf_src) (((vf_src) & 0x01FFFE00) >> 9)
 #define ADF_GEN2_ERR_MSK_VF2PF(vf_mask)        (((vf_mask) & 0xFFFF) << 9)
 
        return ADF_GEN2_VF_PF2VF_OFFSET;
 }
 
-static u32 adf_gen2_get_vf2pf_sources(void __iomem *pmisc_addr)
-{
-       u32 errsou3, errmsk3, vf_int_mask;
-
-       /* Get the interrupt sources triggered by VFs */
-       errsou3 = ADF_CSR_RD(pmisc_addr, ADF_GEN2_ERRSOU3);
-       vf_int_mask = ADF_GEN2_ERR_REG_VF2PF(errsou3);
-
-       /* To avoid adding duplicate entries to work queue, clear
-        * vf_int_mask_sets bits that are already masked in ERRMSK register.
-        */
-       errmsk3 = ADF_CSR_RD(pmisc_addr, ADF_GEN2_ERRMSK3);
-       vf_int_mask &= ~ADF_GEN2_ERR_REG_VF2PF(errmsk3);
-
-       return vf_int_mask;
-}
-
 static void adf_gen2_enable_vf2pf_interrupts(void __iomem *pmisc_addr,
                                             u32 vf_mask)
 {
        }
 }
 
+static u32 adf_gen2_disable_pending_vf2pf_interrupts(void __iomem *pmisc_addr)
+{
+       u32 sources, disabled, pending;
+       u32 errsou3, errmsk3;
+
+       /* Get the interrupt sources triggered by VFs */
+       errsou3 = ADF_CSR_RD(pmisc_addr, ADF_GEN2_ERRSOU3);
+       sources = ADF_GEN2_ERR_REG_VF2PF(errsou3);
+
+       if (!sources)
+               return 0;
+
+       /* Get the already disabled interrupts */
+       errmsk3 = ADF_CSR_RD(pmisc_addr, ADF_GEN2_ERRMSK3);
+       disabled = ADF_GEN2_ERR_REG_VF2PF(errmsk3);
+
+       pending = sources & ~disabled;
+       if (!pending)
+               return 0;
+
+       /* Due to HW limitations, when disabling the interrupts, we can't
+        * just disable the requested sources, as this would lead to missed
+        * interrupts if ERRSOU3 changes just before writing to ERRMSK3.
+        * To work around it, disable all and re-enable only the sources that
+        * are not in vf_mask and were not already disabled. Re-enabling will
+        * trigger a new interrupt for the sources that have changed in the
+        * meantime, if any.
+        */
+       errmsk3 |= ADF_GEN2_ERR_MSK_VF2PF(ADF_GEN2_VF_MSK);
+       ADF_CSR_WR(pmisc_addr, ADF_GEN2_ERRMSK3, errmsk3);
+
+       errmsk3 &= ADF_GEN2_ERR_MSK_VF2PF(sources | disabled);
+       ADF_CSR_WR(pmisc_addr, ADF_GEN2_ERRMSK3, errmsk3);
+
+       /* Return the sources of the (new) interrupt(s) */
+       return pending;
+}
+
 static u32 gen2_csr_get_int_bit(enum gen2_csr_pos offset)
 {
        return ADF_PFVF_INT << offset;
        pfvf_ops->enable_comms = adf_enable_pf2vf_comms;
        pfvf_ops->get_pf2vf_offset = adf_gen2_pf_get_pfvf_offset;
        pfvf_ops->get_vf2pf_offset = adf_gen2_pf_get_pfvf_offset;
-       pfvf_ops->get_vf2pf_sources = adf_gen2_get_vf2pf_sources;
        pfvf_ops->enable_vf2pf_interrupts = adf_gen2_enable_vf2pf_interrupts;
        pfvf_ops->disable_vf2pf_interrupts = adf_gen2_disable_vf2pf_interrupts;
+       pfvf_ops->disable_pending_vf2pf_interrupts = adf_gen2_disable_pending_vf2pf_interrupts;
        pfvf_ops->send_msg = adf_gen2_pf2vf_send;
        pfvf_ops->recv_msg = adf_gen2_vf2pf_recv;
 }
 
 /* VF2PF interrupt source registers */
 #define ADF_4XXX_VM2PF_SOU             0x41A180
 #define ADF_4XXX_VM2PF_MSK             0x41A1C0
+#define ADF_GEN4_VF_MSK                        0xFFFF
 
 #define ADF_PFVF_GEN4_MSGTYPE_SHIFT    2
 #define ADF_PFVF_GEN4_MSGTYPE_MASK     0x3F
        return ADF_4XXX_VM2PF_OFFSET(i);
 }
 
-static u32 adf_gen4_get_vf2pf_sources(void __iomem *pmisc_addr)
-{
-       u32 sou, mask;
-
-       sou = ADF_CSR_RD(pmisc_addr, ADF_4XXX_VM2PF_SOU);
-       mask = ADF_CSR_RD(pmisc_addr, ADF_4XXX_VM2PF_MSK);
-
-       return sou & ~mask;
-}
-
 static void adf_gen4_enable_vf2pf_interrupts(void __iomem *pmisc_addr,
                                             u32 vf_mask)
 {
        ADF_CSR_WR(pmisc_addr, ADF_4XXX_VM2PF_MSK, val);
 }
 
+static u32 adf_gen4_disable_pending_vf2pf_interrupts(void __iomem *pmisc_addr)
+{
+       u32 sources, disabled, pending;
+
+       /* Get the interrupt sources triggered by VFs */
+       sources = ADF_CSR_RD(pmisc_addr, ADF_4XXX_VM2PF_SOU);
+       if (!sources)
+               return 0;
+
+       /* Get the already disabled interrupts */
+       disabled = ADF_CSR_RD(pmisc_addr, ADF_4XXX_VM2PF_MSK);
+
+       pending = sources & ~disabled;
+       if (!pending)
+               return 0;
+
+       /* Due to HW limitations, when disabling the interrupts, we can't
+        * just disable the requested sources, as this would lead to missed
+        * interrupts if VM2PF_SOU changes just before writing to VM2PF_MSK.
+        * To work around it, disable all and re-enable only the sources that
+        * are not in vf_mask and were not already disabled. Re-enabling will
+        * trigger a new interrupt for the sources that have changed in the
+        * meantime, if any.
+        */
+       ADF_CSR_WR(pmisc_addr, ADF_4XXX_VM2PF_MSK, ADF_GEN4_VF_MSK);
+       ADF_CSR_WR(pmisc_addr, ADF_4XXX_VM2PF_MSK, disabled | sources);
+
+       /* Return the sources of the (new) interrupt(s) */
+       return pending;
+}
+
 static int adf_gen4_pfvf_send(struct adf_accel_dev *accel_dev,
                              struct pfvf_message msg, u32 pfvf_offset,
                              struct mutex *csr_lock)
        pfvf_ops->enable_comms = adf_enable_pf2vf_comms;
        pfvf_ops->get_pf2vf_offset = adf_gen4_pf_get_pf2vf_offset;
        pfvf_ops->get_vf2pf_offset = adf_gen4_pf_get_vf2pf_offset;
-       pfvf_ops->get_vf2pf_sources = adf_gen4_get_vf2pf_sources;
        pfvf_ops->enable_vf2pf_interrupts = adf_gen4_enable_vf2pf_interrupts;
        pfvf_ops->disable_vf2pf_interrupts = adf_gen4_disable_vf2pf_interrupts;
+       pfvf_ops->disable_pending_vf2pf_interrupts = adf_gen4_disable_pending_vf2pf_interrupts;
        pfvf_ops->send_msg = adf_gen4_pfvf_send;
        pfvf_ops->recv_msg = adf_gen4_pfvf_recv;
 }
 
        spin_unlock_irqrestore(&accel_dev->pf.vf2pf_ints_lock, flags);
 }
 
-static void adf_disable_vf2pf_interrupts_irq(struct adf_accel_dev *accel_dev,
-                                            u32 vf_mask)
+static u32 adf_disable_pending_vf2pf_interrupts(struct adf_accel_dev *accel_dev)
 {
        void __iomem *pmisc_addr = adf_get_pmisc_base(accel_dev);
+       u32 pending;
 
        spin_lock(&accel_dev->pf.vf2pf_ints_lock);
-       GET_PFVF_OPS(accel_dev)->disable_vf2pf_interrupts(pmisc_addr, vf_mask);
+       pending = GET_PFVF_OPS(accel_dev)->disable_pending_vf2pf_interrupts(pmisc_addr);
        spin_unlock(&accel_dev->pf.vf2pf_ints_lock);
+
+       return pending;
 }
 
 static bool adf_handle_vf2pf_int(struct adf_accel_dev *accel_dev)
 {
-       void __iomem *pmisc_addr = adf_get_pmisc_base(accel_dev);
        bool irq_handled = false;
        unsigned long vf_mask;
 
-       /* Get the interrupt sources triggered by VFs */
-       vf_mask = GET_PFVF_OPS(accel_dev)->get_vf2pf_sources(pmisc_addr);
-
+       /* Get the interrupt sources triggered by VFs, except for those already disabled */
+       vf_mask = adf_disable_pending_vf2pf_interrupts(accel_dev);
        if (vf_mask) {
                struct adf_accel_vf_info *vf_info;
                int i;
 
-               /* Disable VF2PF interrupts for VFs with pending ints */
-               adf_disable_vf2pf_interrupts_irq(accel_dev, vf_mask);
-
                /*
                 * Handle VF2PF interrupt unless the VF is malicious and
                 * is attempting to flood the host OS with VF2PF interrupts.
 
 #include "adf_dh895xcc_hw_data.h"
 #include "icp_qat_hw.h"
 
+#define ADF_DH895XCC_VF_MSK    0xFFFFFFFF
+
 /* Worker thread to service arbiter mappings */
 static const u32 thrd_to_arb_map[ADF_DH895XCC_MAX_ACCELENGINES] = {
        0x12222AAA, 0x11666666, 0x12222AAA, 0x11666666,
        return thrd_to_arb_map;
 }
 
-static u32 get_vf2pf_sources(void __iomem *pmisc_bar)
-{
-       u32 errsou3, errmsk3, errsou5, errmsk5, vf_int_mask;
-
-       /* Get the interrupt sources triggered by VFs */
-       errsou3 = ADF_CSR_RD(pmisc_bar, ADF_GEN2_ERRSOU3);
-       vf_int_mask = ADF_DH895XCC_ERR_REG_VF2PF_L(errsou3);
-
-       /* To avoid adding duplicate entries to work queue, clear
-        * vf_int_mask_sets bits that are already masked in ERRMSK register.
-        */
-       errmsk3 = ADF_CSR_RD(pmisc_bar, ADF_GEN2_ERRMSK3);
-       vf_int_mask &= ~ADF_DH895XCC_ERR_REG_VF2PF_L(errmsk3);
-
-       /* Do the same for ERRSOU5 */
-       errsou5 = ADF_CSR_RD(pmisc_bar, ADF_GEN2_ERRSOU5);
-       errmsk5 = ADF_CSR_RD(pmisc_bar, ADF_GEN2_ERRMSK5);
-       vf_int_mask |= ADF_DH895XCC_ERR_REG_VF2PF_U(errsou5);
-       vf_int_mask &= ~ADF_DH895XCC_ERR_REG_VF2PF_U(errmsk5);
-
-       return vf_int_mask;
-}
-
 static void enable_vf2pf_interrupts(void __iomem *pmisc_addr, u32 vf_mask)
 {
        /* Enable VF2PF Messaging Ints - VFs 0 through 15 per vf_mask[15:0] */
        if (vf_mask >> 16) {
                u32 val = ADF_CSR_RD(pmisc_addr, ADF_GEN2_ERRMSK5)
                          & ~ADF_DH895XCC_ERR_MSK_VF2PF_U(vf_mask);
-
                ADF_CSR_WR(pmisc_addr, ADF_GEN2_ERRMSK5, val);
        }
 }
        }
 }
 
+static u32 disable_pending_vf2pf_interrupts(void __iomem *pmisc_addr)
+{
+       u32 sources, pending, disabled;
+       u32 errsou3, errmsk3;
+       u32 errsou5, errmsk5;
+
+       /* Get the interrupt sources triggered by VFs */
+       errsou3 = ADF_CSR_RD(pmisc_addr, ADF_GEN2_ERRSOU3);
+       errsou5 = ADF_CSR_RD(pmisc_addr, ADF_GEN2_ERRSOU5);
+       sources = ADF_DH895XCC_ERR_REG_VF2PF_L(errsou3)
+                 | ADF_DH895XCC_ERR_REG_VF2PF_U(errsou5);
+
+       if (!sources)
+               return 0;
+
+       /* Get the already disabled interrupts */
+       errmsk3 = ADF_CSR_RD(pmisc_addr, ADF_GEN2_ERRMSK3);
+       errmsk5 = ADF_CSR_RD(pmisc_addr, ADF_GEN2_ERRMSK5);
+       disabled = ADF_DH895XCC_ERR_REG_VF2PF_L(errmsk3)
+                  | ADF_DH895XCC_ERR_REG_VF2PF_U(errmsk5);
+
+       pending = sources & ~disabled;
+       if (!pending)
+               return 0;
+
+       /* Due to HW limitations, when disabling the interrupts, we can't
+        * just disable the requested sources, as this would lead to missed
+        * interrupts if sources changes just before writing to ERRMSK3 and
+        * ERRMSK5.
+        * To work around it, disable all and re-enable only the sources that
+        * are not in vf_mask and were not already disabled. Re-enabling will
+        * trigger a new interrupt for the sources that have changed in the
+        * meantime, if any.
+        */
+       errmsk3 |= ADF_DH895XCC_ERR_MSK_VF2PF_L(ADF_DH895XCC_VF_MSK);
+       errmsk5 |= ADF_DH895XCC_ERR_MSK_VF2PF_U(ADF_DH895XCC_VF_MSK);
+       ADF_CSR_WR(pmisc_addr, ADF_GEN2_ERRMSK3, errmsk3);
+       ADF_CSR_WR(pmisc_addr, ADF_GEN2_ERRMSK5, errmsk5);
+
+       errmsk3 &= ADF_DH895XCC_ERR_MSK_VF2PF_L(sources | disabled);
+       errmsk5 &= ADF_DH895XCC_ERR_MSK_VF2PF_U(sources | disabled);
+       ADF_CSR_WR(pmisc_addr, ADF_GEN2_ERRMSK3, errmsk3);
+       ADF_CSR_WR(pmisc_addr, ADF_GEN2_ERRMSK5, errmsk5);
+
+       /* Return the sources of the (new) interrupt(s) */
+       return pending;
+}
+
 static void configure_iov_threads(struct adf_accel_dev *accel_dev, bool enable)
 {
        adf_gen2_cfg_iov_thds(accel_dev, enable,
        hw_data->disable_iov = adf_disable_sriov;
 
        adf_gen2_init_pf_pfvf_ops(&hw_data->pfvf_ops);
-       hw_data->pfvf_ops.get_vf2pf_sources = get_vf2pf_sources;
        hw_data->pfvf_ops.enable_vf2pf_interrupts = enable_vf2pf_interrupts;
        hw_data->pfvf_ops.disable_vf2pf_interrupts = disable_vf2pf_interrupts;
+       hw_data->pfvf_ops.disable_pending_vf2pf_interrupts = disable_pending_vf2pf_interrupts;
        adf_gen2_init_hw_csr_ops(&hw_data->csr_ops);
 }