Blob Blame History Raw
From 7eadcfd633d8ef0082b194693c5057c9652fe243 Mon Sep 17 00:00:00 2001
From: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
Date: Thu, 12 Aug 2021 21:21:15 +0100
Subject: [PATCH] crypto: qat - prevent spurious MSI interrupt in VF
Git-commit: 7eadcfd633d8ef0082b194693c5057c9652fe243
Patch-mainline: v5.15-rc1
References: jsc#PED-1073

QAT GEN2 devices suffer from a defect where the MSI interrupt can be
sent multiple times.

If the second (spurious) interrupt is handled before the bottom half
handler runs, then the extra interrupt is effectively ignored because
the bottom half is only scheduled once.
However, if the top half runs again after the bottom half runs, this
will appear as a spurious PF to VF interrupt.

This can be avoided by checking the interrupt mask register in addition
to the interrupt source register in the interrupt handler.

This patch is based on earlier work done by Conor McLoughlin.

Signed-off-by: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
Co-developed-by: Marco Chiappero <marco.chiappero@intel.com>
Signed-off-by: Marco Chiappero <marco.chiappero@intel.com>
Reviewed-by: Fiona Trahe <fiona.trahe@intel.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: Torsten Duwe <duwe@suse.de>

---
 drivers/crypto/qat/qat_common/adf_vf_isr.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/drivers/crypto/qat/qat_common/adf_vf_isr.c b/drivers/crypto/qat/qat_common/adf_vf_isr.c
index 3e4f64d248f9b..4359ca633ea9c 100644
--- a/drivers/crypto/qat/qat_common/adf_vf_isr.c
+++ b/drivers/crypto/qat/qat_common/adf_vf_isr.c
@@ -18,6 +18,7 @@
 #include "adf_pf2vf_msg.h"
 
 #define ADF_VINTSOU_OFFSET	0x204
+#define ADF_VINTMSK_OFFSET	0x208
 #define ADF_VINTSOU_BUN		BIT(0)
 #define ADF_VINTSOU_PF2VF	BIT(1)
 
@@ -161,11 +162,20 @@ static irqreturn_t adf_isr(int irq, void *privdata)
 			&GET_BARS(accel_dev)[hw_data->get_misc_bar_id(hw_data)];
 	void __iomem *pmisc_bar_addr = pmisc->virt_addr;
 	bool handled = false;
-	u32 v_int;
+	u32 v_int, v_mask;
 
 	/* Read VF INT source CSR to determine the source of VF interrupt */
 	v_int = ADF_CSR_RD(pmisc_bar_addr, ADF_VINTSOU_OFFSET);
 
+	/* Read VF INT mask CSR to determine which sources are masked */
+	v_mask = ADF_CSR_RD(pmisc_bar_addr, ADF_VINTMSK_OFFSET);
+
+	/*
+	 * Recompute v_int ignoring sources that are masked. This is to
+	 * avoid rescheduling the tasklet for interrupts already handled
+	 */
+	v_int &= ~v_mask;
+
 	/* Check for PF2VF interrupt */
 	if (v_int & ADF_VINTSOU_PF2VF) {
 		/* Disable PF to VF interrupt */
-- 
2.35.3