crypto: qat - fix handling of VF to PF interrupts
authorMarco Chiappero <marco.chiappero@intel.com>
Tue, 28 Sep 2021 11:44:32 +0000 (12:44 +0100)
committerHerbert Xu <herbert@gondor.apana.org.au>
Fri, 8 Oct 2021 12:02:40 +0000 (20:02 +0800)
Currently, VF to PF interrupt handling is based on the DH895XCC device
behavior, which is not entirely common to all devices.

In order to make interrupt detection and handling correct for all of the
supported devices, make the interrupt handling device specific by:
 - introducing get_vf2pf_sources() for getting a 32 bits long value
   where each bit represents a vf2pf interrupt;
 - adding the device [enable|disable]_vf2pf_interrupts to hw_data;
 - defining [enable|disable]_vf2pf_interrupts for all the devices that
   are currently supported, using only their required and specific
   ERRSOU|ERRMASK registers (DH895XCC has 32 interrupts spread across
   ERRSOU3 and ERRSOU5, C62X/C3XXX has 16 in ERRSOU3 only, etc).
Code has been shared by different devices wherever possible.

This patch is based on earlier work done by Salvatore Benedetto.

Signed-off-by: Marco Chiappero <marco.chiappero@intel.com>
Co-developed-by: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
Signed-off-by: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
drivers/crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.c
drivers/crypto/qat/qat_c62x/adf_c62x_hw_data.c
drivers/crypto/qat/qat_common/adf_accel_devices.h
drivers/crypto/qat/qat_common/adf_gen2_hw_data.c
drivers/crypto/qat/qat_common/adf_gen2_hw_data.h
drivers/crypto/qat/qat_common/adf_isr.c
drivers/crypto/qat/qat_common/adf_pf2vf_msg.c
drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c
drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.h

index 3027c01..b9bd52e 100644 (file)
@@ -206,6 +206,9 @@ void adf_init_hw_data_c3xxx(struct adf_hw_device_data *hw_data)
        hw_data->reset_device = adf_reset_flr;
        hw_data->set_ssm_wdtimer = adf_gen2_set_ssm_wdtimer;
        hw_data->get_pf2vf_offset = get_pf2vf_offset;
+       hw_data->get_vf2pf_sources = adf_gen2_get_vf2pf_sources;
+       hw_data->enable_vf2pf_interrupts = adf_gen2_enable_vf2pf_interrupts;
+       hw_data->disable_vf2pf_interrupts = adf_gen2_disable_vf2pf_interrupts;
        hw_data->enable_pfvf_comms = adf_enable_pf2vf_comms;
        hw_data->disable_iov = adf_disable_sriov;
        hw_data->min_iov_compat_ver = ADF_PFVF_COMPAT_THIS_VERSION;
index b023c80..f28dae0 100644 (file)
@@ -208,6 +208,9 @@ void adf_init_hw_data_c62x(struct adf_hw_device_data *hw_data)
        hw_data->reset_device = adf_reset_flr;
        hw_data->set_ssm_wdtimer = adf_gen2_set_ssm_wdtimer;
        hw_data->get_pf2vf_offset = get_pf2vf_offset;
+       hw_data->get_vf2pf_sources = adf_gen2_get_vf2pf_sources;
+       hw_data->enable_vf2pf_interrupts = adf_gen2_enable_vf2pf_interrupts;
+       hw_data->disable_vf2pf_interrupts = adf_gen2_disable_vf2pf_interrupts;
        hw_data->enable_pfvf_comms = adf_enable_pf2vf_comms;
        hw_data->disable_iov = adf_disable_sriov;
        hw_data->min_iov_compat_ver = ADF_PFVF_COMPAT_THIS_VERSION;
index ca8e23f..57d9ca0 100644 (file)
@@ -177,6 +177,11 @@ struct adf_hw_device_data {
        void (*enable_ints)(struct adf_accel_dev *accel_dev);
        void (*set_ssm_wdtimer)(struct adf_accel_dev *accel_dev);
        int (*enable_pfvf_comms)(struct adf_accel_dev *accel_dev);
+       u32 (*get_vf2pf_sources)(void __iomem *pmisc_addr);
+       void (*enable_vf2pf_interrupts)(void __iomem *pmisc_bar_addr,
+                                       u32 vf_mask);
+       void (*disable_vf2pf_interrupts)(void __iomem *pmisc_bar_addr,
+                                        u32 vf_mask);
        void (*reset_device)(struct adf_accel_dev *accel_dev);
        void (*set_msix_rttable)(struct adf_accel_dev *accel_dev);
        char *(*uof_get_name)(u32 obj_num);
index 9e560c7..5669180 100644 (file)
@@ -4,6 +4,46 @@
 #include "icp_qat_hw.h"
 #include <linux/pci.h>
 
+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;
+}
+EXPORT_SYMBOL_GPL(adf_gen2_get_vf2pf_sources);
+
+void adf_gen2_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 & 0xFFFF) {
+               u32 val = ADF_CSR_RD(pmisc_addr, ADF_GEN2_ERRMSK3)
+                         & ~ADF_GEN2_ERR_MSK_VF2PF(vf_mask);
+               ADF_CSR_WR(pmisc_addr, ADF_GEN2_ERRMSK3, val);
+       }
+}
+EXPORT_SYMBOL_GPL(adf_gen2_enable_vf2pf_interrupts);
+
+void adf_gen2_disable_vf2pf_interrupts(void __iomem *pmisc_addr, u32 vf_mask)
+{
+       /* Disable VF2PF interrupts for VFs 0 through 15 per vf_mask[15:0] */
+       if (vf_mask & 0xFFFF) {
+               u32 val = ADF_CSR_RD(pmisc_addr, ADF_GEN2_ERRMSK3)
+                         | ADF_GEN2_ERR_MSK_VF2PF(vf_mask);
+               ADF_CSR_WR(pmisc_addr, ADF_GEN2_ERRMSK3, val);
+       }
+}
+EXPORT_SYMBOL_GPL(adf_gen2_disable_vf2pf_interrupts);
+
 void adf_gen2_cfg_iov_thds(struct adf_accel_dev *accel_dev, bool enable,
                           int num_a_regs, int num_b_regs)
 {
index 756b0dd..3486e51 100644 (file)
@@ -125,6 +125,18 @@ do { \
 #define ADF_SSMWDT(i)          (ADF_SSMWDT_OFFSET + ((i) * 0x4000))
 #define ADF_SSMWDTPKE(i)       (ADF_SSMWDTPKE_OFFSET + ((i) * 0x4000))
 
+ /* VF2PF interrupts */
+#define ADF_GEN2_ERRSOU3 (0x3A000 + 0x0C)
+#define ADF_GEN2_ERRSOU5 (0x3A000 + 0xD8)
+#define ADF_GEN2_ERRMSK3 (0x3A000 + 0x1C)
+#define ADF_GEN2_ERRMSK5 (0x3A000 + 0xDC)
+#define ADF_GEN2_ERR_REG_VF2PF(vf_src) (((vf_src) & 0x01FFFE00) >> 9)
+#define ADF_GEN2_ERR_MSK_VF2PF(vf_mask)        (((vf_mask) & 0xFFFF) << 9)
+
+u32 adf_gen2_get_vf2pf_sources(void __iomem *pmisc_bar);
+void adf_gen2_enable_vf2pf_interrupts(void __iomem *pmisc_addr, u32 vf_mask);
+void adf_gen2_disable_vf2pf_interrupts(void __iomem *pmisc_addr, u32 vf_mask);
+
 void adf_gen2_cfg_iov_thds(struct adf_accel_dev *accel_dev, bool enable,
                           int num_a_regs, int num_b_regs);
 void adf_gen2_init_hw_csr_ops(struct adf_hw_csr_ops *csr_ops);
index c55a9f1..40593c9 100644 (file)
 #include "adf_transport_internal.h"
 
 #define ADF_MAX_NUM_VFS        32
-#define ADF_ERRSOU3    (0x3A000 + 0x0C)
-#define ADF_ERRSOU5    (0x3A000 + 0xD8)
-#define ADF_ERRMSK3    (0x3A000 + 0x1C)
-#define ADF_ERRMSK5    (0x3A000 + 0xDC)
-#define ADF_ERR_REG_VF2PF_L(vf_src)    (((vf_src) & 0x01FFFE00) >> 9)
-#define ADF_ERR_REG_VF2PF_U(vf_src)    (((vf_src) & 0x0000FFFF) << 16)
 
 static int adf_enable_msix(struct adf_accel_dev *accel_dev)
 {
@@ -71,22 +65,10 @@ static irqreturn_t adf_msix_isr_ae(int irq, void *dev_ptr)
                struct adf_bar *pmisc =
                        &GET_BARS(accel_dev)[hw_data->get_misc_bar_id(hw_data)];
                void __iomem *pmisc_addr = pmisc->virt_addr;
-               u32 errsou3, errsou5, errmsk3, errmsk5;
                unsigned long vf_mask;
 
                /* Get the interrupt sources triggered by VFs */
-               errsou3 = ADF_CSR_RD(pmisc_addr, ADF_ERRSOU3);
-               errsou5 = ADF_CSR_RD(pmisc_addr, ADF_ERRSOU5);
-               vf_mask = ADF_ERR_REG_VF2PF_L(errsou3);
-               vf_mask |= ADF_ERR_REG_VF2PF_U(errsou5);
-
-               /* 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_ERRMSK3);
-               errmsk5 = ADF_CSR_RD(pmisc_addr, ADF_ERRMSK5);
-               vf_mask &= ~ADF_ERR_REG_VF2PF_L(errmsk3);
-               vf_mask &= ~ADF_ERR_REG_VF2PF_U(errmsk5);
+               vf_mask = hw_data->get_vf2pf_sources(pmisc_addr);
 
                if (vf_mask) {
                        struct adf_accel_vf_info *vf_info;
index d3f6ff6..cdef6c3 100644 (file)
@@ -5,82 +5,42 @@
 #include "adf_common_drv.h"
 #include "adf_pf2vf_msg.h"
 
-#define ADF_DH895XCC_EP_OFFSET 0x3A000
-#define ADF_DH895XCC_ERRMSK3   (ADF_DH895XCC_EP_OFFSET + 0x1C)
-#define ADF_DH895XCC_ERRMSK3_VF2PF_L_MASK(vf_mask) ((vf_mask & 0xFFFF) << 9)
-#define ADF_DH895XCC_ERRMSK5   (ADF_DH895XCC_EP_OFFSET + 0xDC)
-#define ADF_DH895XCC_ERRMSK5_VF2PF_U_MASK(vf_mask) (vf_mask >> 16)
-
-static void __adf_enable_vf2pf_interrupts(struct adf_accel_dev *accel_dev,
-                                         u32 vf_mask)
+void adf_enable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 vf_mask)
 {
        struct adf_hw_device_data *hw_data = accel_dev->hw_device;
-       struct adf_bar *pmisc =
-                       &GET_BARS(accel_dev)[hw_data->get_misc_bar_id(hw_data)];
+       u32 misc_bar_id = hw_data->get_misc_bar_id(hw_data);
+       struct adf_bar *pmisc = &GET_BARS(accel_dev)[misc_bar_id];
        void __iomem *pmisc_addr = pmisc->virt_addr;
-       u32 reg;
-
-       /* Enable VF2PF Messaging Ints - VFs 1 through 16 per vf_mask[15:0] */
-       if (vf_mask & 0xFFFF) {
-               reg = ADF_CSR_RD(pmisc_addr, ADF_DH895XCC_ERRMSK3);
-               reg &= ~ADF_DH895XCC_ERRMSK3_VF2PF_L_MASK(vf_mask);
-               ADF_CSR_WR(pmisc_addr, ADF_DH895XCC_ERRMSK3, reg);
-       }
-
-       /* Enable VF2PF Messaging Ints - VFs 17 through 32 per vf_mask[31:16] */
-       if (vf_mask >> 16) {
-               reg = ADF_CSR_RD(pmisc_addr, ADF_DH895XCC_ERRMSK5);
-               reg &= ~ADF_DH895XCC_ERRMSK5_VF2PF_U_MASK(vf_mask);
-               ADF_CSR_WR(pmisc_addr, ADF_DH895XCC_ERRMSK5, reg);
-       }
-}
-
-void adf_enable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 vf_mask)
-{
        unsigned long flags;
 
        spin_lock_irqsave(&accel_dev->pf.vf2pf_ints_lock, flags);
-       __adf_enable_vf2pf_interrupts(accel_dev, vf_mask);
+       hw_data->enable_vf2pf_interrupts(pmisc_addr, vf_mask);
        spin_unlock_irqrestore(&accel_dev->pf.vf2pf_ints_lock, flags);
 }
 
-static void __adf_disable_vf2pf_interrupts(struct adf_accel_dev *accel_dev,
-                                          u32 vf_mask)
+void adf_disable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 vf_mask)
 {
        struct adf_hw_device_data *hw_data = accel_dev->hw_device;
-       struct adf_bar *pmisc =
-                       &GET_BARS(accel_dev)[hw_data->get_misc_bar_id(hw_data)];
+       u32 misc_bar_id = hw_data->get_misc_bar_id(hw_data);
+       struct adf_bar *pmisc = &GET_BARS(accel_dev)[misc_bar_id];
        void __iomem *pmisc_addr = pmisc->virt_addr;
-       u32 reg;
-
-       /* Disable VF2PF interrupts for VFs 1 through 16 per vf_mask[15:0] */
-       if (vf_mask & 0xFFFF) {
-               reg = ADF_CSR_RD(pmisc_addr, ADF_DH895XCC_ERRMSK3) |
-                       ADF_DH895XCC_ERRMSK3_VF2PF_L_MASK(vf_mask);
-               ADF_CSR_WR(pmisc_addr, ADF_DH895XCC_ERRMSK3, reg);
-       }
-
-       /* Disable VF2PF interrupts for VFs 17 through 32 per vf_mask[31:16] */
-       if (vf_mask >> 16) {
-               reg = ADF_CSR_RD(pmisc_addr, ADF_DH895XCC_ERRMSK5) |
-                       ADF_DH895XCC_ERRMSK5_VF2PF_U_MASK(vf_mask);
-               ADF_CSR_WR(pmisc_addr, ADF_DH895XCC_ERRMSK5, reg);
-       }
-}
-
-void adf_disable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 vf_mask)
-{
        unsigned long flags;
 
        spin_lock_irqsave(&accel_dev->pf.vf2pf_ints_lock, flags);
-       __adf_disable_vf2pf_interrupts(accel_dev, vf_mask);
+       hw_data->disable_vf2pf_interrupts(pmisc_addr, vf_mask);
        spin_unlock_irqrestore(&accel_dev->pf.vf2pf_ints_lock, flags);
 }
 
-void adf_disable_vf2pf_interrupts_irq(struct adf_accel_dev *accel_dev, u32 vf_mask)
+void adf_disable_vf2pf_interrupts_irq(struct adf_accel_dev *accel_dev,
+                                     u32 vf_mask)
 {
+       struct adf_hw_device_data *hw_data = accel_dev->hw_device;
+       u32 misc_bar_id = hw_data->get_misc_bar_id(hw_data);
+       struct adf_bar *pmisc = &GET_BARS(accel_dev)[misc_bar_id];
+       void __iomem *pmisc_addr = pmisc->virt_addr;
+
        spin_lock(&accel_dev->pf.vf2pf_ints_lock);
-       __adf_disable_vf2pf_interrupts(accel_dev, vf_mask);
+       hw_data->disable_vf2pf_interrupts(pmisc_addr, vf_mask);
        spin_unlock(&accel_dev->pf.vf2pf_ints_lock);
 }
 
index 0a9ce36..b496032 100644 (file)
@@ -175,6 +175,52 @@ static void adf_enable_ints(struct adf_accel_dev *accel_dev)
                   ADF_DH895XCC_SMIA1_MASK);
 }
 
+static u32 get_vf2pf_sources(void __iomem *pmisc_bar)
+{
+       u32 errsou5, errmsk5, vf_int_mask;
+
+       vf_int_mask = adf_gen2_get_vf2pf_sources(pmisc_bar);
+
+       /* Get the interrupt sources triggered by VFs, but to avoid duplicates
+        * in the work queue, clear vf_int_mask_sets bits that are already
+        * masked in ERRMSK register.
+        */
+       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] */
+       adf_gen2_enable_vf2pf_interrupts(pmisc_addr, vf_mask);
+
+       /* Enable VF2PF Messaging Ints - VFs 16 through 31 per vf_mask[31:16] */
+       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 void disable_vf2pf_interrupts(void __iomem *pmisc_addr, u32 vf_mask)
+{
+       /* Disable VF2PF interrupts for VFs 0 through 15 per vf_mask[15:0] */
+       adf_gen2_disable_vf2pf_interrupts(pmisc_addr, vf_mask);
+
+       /* Disable VF2PF interrupts for VFs 16 through 31 per vf_mask[31:16] */
+       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 int adf_enable_pf2vf_comms(struct adf_accel_dev *accel_dev)
 {
        spin_lock_init(&accel_dev->pf.vf2pf_ints_lock);
@@ -226,6 +272,9 @@ void adf_init_hw_data_dh895xcc(struct adf_hw_device_data *hw_data)
        hw_data->enable_ints = adf_enable_ints;
        hw_data->reset_device = adf_reset_sbr;
        hw_data->get_pf2vf_offset = get_pf2vf_offset;
+       hw_data->get_vf2pf_sources = get_vf2pf_sources;
+       hw_data->enable_vf2pf_interrupts = enable_vf2pf_interrupts;
+       hw_data->disable_vf2pf_interrupts = disable_vf2pf_interrupts;
        hw_data->enable_pfvf_comms = adf_enable_pf2vf_comms;
        hw_data->disable_iov = adf_disable_sriov;
        hw_data->min_iov_compat_ver = ADF_PFVF_COMPAT_THIS_VERSION;
index f99319c..0f9f24b 100644 (file)
 #define ADF_DH895XCC_CERRSSMSH(i) (i * 0x4000 + 0x10)
 #define ADF_DH895XCC_ERRSSMSH_EN BIT(3)
 
-#define ADF_DH895XCC_PF2VF_OFFSET(i)   (0x3A000 + 0x280 + ((i) * 0x04))
+/* Masks for VF2PF interrupts */
+#define ADF_DH895XCC_ERR_REG_VF2PF_U(vf_src)   (((vf_src) & 0x0000FFFF) << 16)
+#define ADF_DH895XCC_ERR_MSK_VF2PF_U(vf_mask)  ((vf_mask) >> 16)
+#define ADF_DH895XCC_PF2VF_OFFSET(i)           (0x3A000 + 0x280 + ((i) * 0x04))
 
 /* AE to function mapping */
 #define ADF_DH895XCC_AE2FUNC_MAP_GRP_A_NUM_REGS 96