Torsten Duwe 2dc170
From e5745f34113b758b45d134dec04a7df94dc67131 Mon Sep 17 00:00:00 2001
Torsten Duwe 2dc170
From: Wojciech Ziemba <wojciech.ziemba@intel.com>
Torsten Duwe 2dc170
Date: Thu, 10 Feb 2022 13:38:27 +0000
Torsten Duwe 2dc170
Subject: [PATCH] crypto: qat - enable power management for QAT GEN4
Torsten Duwe 2dc170
Git-commit: e5745f34113b758b45d134dec04a7df94dc67131
Torsten Duwe 2dc170
Patch-mainline: v5.18-rc1
Torsten Duwe 2dc170
References: jsc#PED-1073
Torsten Duwe 2dc170
Torsten Duwe 2dc170
Add support for HW QAT Power Management (PM) feature.
Torsten Duwe 2dc170
This feature is enabled at init time (1) by sending an admin message to
Torsten Duwe 2dc170
the firmware, targeting the admin AE, that sets the idle time before
Torsten Duwe 2dc170
the device changes state and (2) by unmasking the PM source of interrupt
Torsten Duwe 2dc170
in ERRMSK2.
Torsten Duwe 2dc170
Torsten Duwe 2dc170
The interrupt handler is extended to handle a PM interrupt which
Torsten Duwe 2dc170
is triggered by HW when a PM transition occurs. In this case, the
Torsten Duwe 2dc170
driver responds acknowledging the transaction using the HOST_MSG
Torsten Duwe 2dc170
mailbox.
Torsten Duwe 2dc170
Torsten Duwe 2dc170
Signed-off-by: Wojciech Ziemba <wojciech.ziemba@intel.com>
Torsten Duwe 2dc170
Co-developed-by: Marcinx Malinowski <marcinx.malinowski@intel.com>
Torsten Duwe 2dc170
Signed-off-by: Marcinx Malinowski <marcinx.malinowski@intel.com>
Torsten Duwe 2dc170
Reviewed-by: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
Torsten Duwe 2dc170
Reviewed-by: Marco Chiappero <marco.chiappero@intel.com>
Torsten Duwe 2dc170
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Torsten Duwe 2dc170
Signed-off-by: Torsten Duwe <duwe@suse.de>
Torsten Duwe 2dc170
Torsten Duwe 2dc170
---
Torsten Duwe 2dc170
 .../crypto/qat/qat_4xxx/adf_4xxx_hw_data.c    |  15 +-
Torsten Duwe 2dc170
 .../crypto/qat/qat_4xxx/adf_4xxx_hw_data.h    |  10 --
Torsten Duwe 2dc170
 drivers/crypto/qat/qat_common/Makefile        |   1 +
Torsten Duwe 2dc170
 .../crypto/qat/qat_common/adf_accel_devices.h |   2 +
Torsten Duwe 2dc170
 drivers/crypto/qat/qat_common/adf_admin.c     |  37 +++++
Torsten Duwe 2dc170
 .../crypto/qat/qat_common/adf_common_drv.h    |   1 +
Torsten Duwe 2dc170
 drivers/crypto/qat/qat_common/adf_gen4_pm.c   | 137 ++++++++++++++++++
Torsten Duwe 2dc170
 drivers/crypto/qat/qat_common/adf_gen4_pm.h   |  44 ++++++
Torsten Duwe 2dc170
 drivers/crypto/qat/qat_common/adf_init.c      |   6 +
Torsten Duwe 2dc170
 drivers/crypto/qat/qat_common/adf_isr.c       |  14 ++
Torsten Duwe 2dc170
 .../qat/qat_common/icp_qat_fw_init_admin.h    |   1 +
Torsten Duwe 2dc170
 11 files changed, 252 insertions(+), 16 deletions(-)
Torsten Duwe 2dc170
 create mode 100644 drivers/crypto/qat/qat_common/adf_gen4_pm.c
Torsten Duwe 2dc170
 create mode 100644 drivers/crypto/qat/qat_common/adf_gen4_pm.h
Torsten Duwe 2dc170
Torsten Duwe 2dc170
diff --git a/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c b/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c
Torsten Duwe 2dc170
index 69fb271c85dd6..fb5970a684844 100644
Torsten Duwe 2dc170
--- a/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c
Torsten Duwe 2dc170
+++ b/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c
Torsten Duwe 2dc170
@@ -6,6 +6,7 @@
Torsten Duwe 2dc170
 #include <adf_common_drv.h>
Torsten Duwe 2dc170
 #include <adf_gen4_hw_data.h>
Torsten Duwe 2dc170
 #include <adf_gen4_pfvf.h>
Torsten Duwe 2dc170
+#include <adf_gen4_pm.h>
Torsten Duwe 2dc170
 #include "adf_4xxx_hw_data.h"
Torsten Duwe 2dc170
 #include "icp_qat_hw.h"
Torsten Duwe 2dc170
 
Torsten Duwe 2dc170
@@ -257,18 +258,18 @@ static int adf_init_device(struct adf_accel_dev *accel_dev)
Torsten Duwe 2dc170
 
Torsten Duwe 2dc170
 	/* Temporarily mask PM interrupt */
Torsten Duwe 2dc170
 	csr = ADF_CSR_RD(addr, ADF_GEN4_ERRMSK2);
Torsten Duwe 2dc170
-	csr |= ADF_4XXX_PM_SOU;
Torsten Duwe 2dc170
+	csr |= ADF_GEN4_PM_SOU;
Torsten Duwe 2dc170
 	ADF_CSR_WR(addr, ADF_GEN4_ERRMSK2, csr);
Torsten Duwe 2dc170
 
Torsten Duwe 2dc170
 	/* Set DRV_ACTIVE bit to power up the device */
Torsten Duwe 2dc170
-	ADF_CSR_WR(addr, ADF_4XXX_PM_INTERRUPT, ADF_4XXX_PM_DRV_ACTIVE);
Torsten Duwe 2dc170
+	ADF_CSR_WR(addr, ADF_GEN4_PM_INTERRUPT, ADF_GEN4_PM_DRV_ACTIVE);
Torsten Duwe 2dc170
 
Torsten Duwe 2dc170
 	/* Poll status register to make sure the device is powered up */
Torsten Duwe 2dc170
 	ret = read_poll_timeout(ADF_CSR_RD, status,
Torsten Duwe 2dc170
-				status & ADF_4XXX_PM_INIT_STATE,
Torsten Duwe 2dc170
-				ADF_4XXX_PM_POLL_DELAY_US,
Torsten Duwe 2dc170
-				ADF_4XXX_PM_POLL_TIMEOUT_US, true, addr,
Torsten Duwe 2dc170
-				ADF_4XXX_PM_STATUS);
Torsten Duwe 2dc170
+				status & ADF_GEN4_PM_INIT_STATE,
Torsten Duwe 2dc170
+				ADF_GEN4_PM_POLL_DELAY_US,
Torsten Duwe 2dc170
+				ADF_GEN4_PM_POLL_TIMEOUT_US, true, addr,
Torsten Duwe 2dc170
+				ADF_GEN4_PM_STATUS);
Torsten Duwe 2dc170
 	if (ret)
Torsten Duwe 2dc170
 		dev_err(&GET_DEV(accel_dev), "Failed to power up the device\n");
Torsten Duwe 2dc170
 
Torsten Duwe 2dc170
@@ -354,6 +355,8 @@ void adf_init_hw_data_4xxx(struct adf_hw_device_data *hw_data)
Torsten Duwe 2dc170
 	hw_data->set_ssm_wdtimer = adf_gen4_set_ssm_wdtimer;
Torsten Duwe 2dc170
 	hw_data->disable_iov = adf_disable_sriov;
Torsten Duwe 2dc170
 	hw_data->ring_pair_reset = adf_gen4_ring_pair_reset;
Torsten Duwe 2dc170
+	hw_data->enable_pm = adf_gen4_enable_pm;
Torsten Duwe 2dc170
+	hw_data->handle_pm_interrupt = adf_gen4_handle_pm_interrupt;
Torsten Duwe 2dc170
 
Torsten Duwe 2dc170
 	adf_gen4_init_hw_csr_ops(&hw_data->csr_ops);
Torsten Duwe 2dc170
 	adf_gen4_init_pf_pfvf_ops(&hw_data->pfvf_ops);
Torsten Duwe 2dc170
diff --git a/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.h b/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.h
Torsten Duwe 2dc170
index 857b93a3c032d..1034752845ca2 100644
Torsten Duwe 2dc170
--- a/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.h
Torsten Duwe 2dc170
+++ b/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.h
Torsten Duwe 2dc170
@@ -49,16 +49,6 @@
Torsten Duwe 2dc170
 #define ADF_4XXX_ADMINMSGLR_OFFSET	(0x500578)
Torsten Duwe 2dc170
 #define ADF_4XXX_MAILBOX_BASE_OFFSET	(0x600970)
Torsten Duwe 2dc170
 
Torsten Duwe 2dc170
-/* Power management */
Torsten Duwe 2dc170
-#define ADF_4XXX_PM_POLL_DELAY_US	20
Torsten Duwe 2dc170
-#define ADF_4XXX_PM_POLL_TIMEOUT_US	USEC_PER_SEC
Torsten Duwe 2dc170
-#define ADF_4XXX_PM_STATUS		(0x50A00C)
Torsten Duwe 2dc170
-#define ADF_4XXX_PM_INTERRUPT		(0x50A028)
Torsten Duwe 2dc170
-#define ADF_4XXX_PM_DRV_ACTIVE		BIT(20)
Torsten Duwe 2dc170
-#define ADF_4XXX_PM_INIT_STATE		BIT(21)
Torsten Duwe 2dc170
-/* Power management source in ERRSOU2 and ERRMSK2 */
Torsten Duwe 2dc170
-#define ADF_4XXX_PM_SOU			BIT(18)
Torsten Duwe 2dc170
-
Torsten Duwe 2dc170
 /* Firmware Binaries */
Torsten Duwe 2dc170
 #define ADF_4XXX_FW		"qat_4xxx.bin"
Torsten Duwe 2dc170
 #define ADF_4XXX_MMP		"qat_4xxx_mmp.bin"
Torsten Duwe 2dc170
diff --git a/drivers/crypto/qat/qat_common/Makefile b/drivers/crypto/qat/qat_common/Makefile
Torsten Duwe 2dc170
index 7e191a42a5c7e..f25a6c8edfc73 100644
Torsten Duwe 2dc170
--- a/drivers/crypto/qat/qat_common/Makefile
Torsten Duwe 2dc170
+++ b/drivers/crypto/qat/qat_common/Makefile
Torsten Duwe 2dc170
@@ -12,6 +12,7 @@ intel_qat-objs := adf_cfg.o \
Torsten Duwe 2dc170
 	adf_hw_arbiter.o \
Torsten Duwe 2dc170
 	adf_gen2_hw_data.o \
Torsten Duwe 2dc170
 	adf_gen4_hw_data.o \
Torsten Duwe 2dc170
+	adf_gen4_pm.o \
Torsten Duwe 2dc170
 	qat_crypto.o \
Torsten Duwe 2dc170
 	qat_algs.o \
Torsten Duwe 2dc170
 	qat_asym_algs.o \
Torsten Duwe 2dc170
diff --git a/drivers/crypto/qat/qat_common/adf_accel_devices.h b/drivers/crypto/qat/qat_common/adf_accel_devices.h
Torsten Duwe 2dc170
index 2d4cd7c7cf33b..a03c6cf723312 100644
Torsten Duwe 2dc170
--- a/drivers/crypto/qat/qat_common/adf_accel_devices.h
Torsten Duwe 2dc170
+++ b/drivers/crypto/qat/qat_common/adf_accel_devices.h
Torsten Duwe 2dc170
@@ -184,6 +184,8 @@ struct adf_hw_device_data {
Torsten Duwe 2dc170
 	void (*exit_arb)(struct adf_accel_dev *accel_dev);
Torsten Duwe 2dc170
 	const u32 *(*get_arb_mapping)(void);
Torsten Duwe 2dc170
 	int (*init_device)(struct adf_accel_dev *accel_dev);
Torsten Duwe 2dc170
+	int (*enable_pm)(struct adf_accel_dev *accel_dev);
Torsten Duwe 2dc170
+	bool (*handle_pm_interrupt)(struct adf_accel_dev *accel_dev);
Torsten Duwe 2dc170
 	void (*disable_iov)(struct adf_accel_dev *accel_dev);
Torsten Duwe 2dc170
 	void (*configure_iov_threads)(struct adf_accel_dev *accel_dev,
Torsten Duwe 2dc170
 				      bool enable);
Torsten Duwe 2dc170
diff --git a/drivers/crypto/qat/qat_common/adf_admin.c b/drivers/crypto/qat/qat_common/adf_admin.c
Torsten Duwe 2dc170
index 498eb6f690e37..3b6184c350811 100644
Torsten Duwe 2dc170
--- a/drivers/crypto/qat/qat_common/adf_admin.c
Torsten Duwe 2dc170
+++ b/drivers/crypto/qat/qat_common/adf_admin.c
Torsten Duwe 2dc170
@@ -251,6 +251,43 @@ int adf_send_admin_init(struct adf_accel_dev *accel_dev)
Torsten Duwe 2dc170
 }
Torsten Duwe 2dc170
 EXPORT_SYMBOL_GPL(adf_send_admin_init);
Torsten Duwe 2dc170
 
Torsten Duwe 2dc170
+/**
Torsten Duwe 2dc170
+ * adf_init_admin_pm() - Function sends PM init message to FW
Torsten Duwe 2dc170
+ * @accel_dev: Pointer to acceleration device.
Torsten Duwe 2dc170
+ * @idle_delay: QAT HW idle time before power gating is initiated.
Torsten Duwe 2dc170
+ *		000 - 64us
Torsten Duwe 2dc170
+ *		001 - 128us
Torsten Duwe 2dc170
+ *		010 - 256us
Torsten Duwe 2dc170
+ *		011 - 512us
Torsten Duwe 2dc170
+ *		100 - 1ms
Torsten Duwe 2dc170
+ *		101 - 2ms
Torsten Duwe 2dc170
+ *		110 - 4ms
Torsten Duwe 2dc170
+ *		111 - 8ms
Torsten Duwe 2dc170
+ *
Torsten Duwe 2dc170
+ * Function sends to the FW the admin init message for the PM state
Torsten Duwe 2dc170
+ * configuration.
Torsten Duwe 2dc170
+ *
Torsten Duwe 2dc170
+ * Return: 0 on success, error code otherwise.
Torsten Duwe 2dc170
+ */
Torsten Duwe 2dc170
+int adf_init_admin_pm(struct adf_accel_dev *accel_dev, u32 idle_delay)
Torsten Duwe 2dc170
+{
Torsten Duwe 2dc170
+	struct adf_hw_device_data *hw_data = accel_dev->hw_device;
Torsten Duwe 2dc170
+	struct icp_qat_fw_init_admin_resp resp = {0};
Torsten Duwe 2dc170
+	struct icp_qat_fw_init_admin_req req = {0};
Torsten Duwe 2dc170
+	u32 ae_mask = hw_data->admin_ae_mask;
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
+	if (!accel_dev->admin) {
Torsten Duwe 2dc170
+		dev_err(&GET_DEV(accel_dev), "adf_admin is not available\n");
Torsten Duwe 2dc170
+		return -EFAULT;
Torsten Duwe 2dc170
+	}
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
+	req.cmd_id = ICP_QAT_FW_PM_STATE_CONFIG;
Torsten Duwe 2dc170
+	req.idle_filter = idle_delay;
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
+	return adf_send_admin(accel_dev, &req, &resp, ae_mask);
Torsten Duwe 2dc170
+}
Torsten Duwe 2dc170
+EXPORT_SYMBOL_GPL(adf_init_admin_pm);
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
 int adf_init_admin_comms(struct adf_accel_dev *accel_dev)
Torsten Duwe 2dc170
 {
Torsten Duwe 2dc170
 	struct adf_admin_comms *admin;
Torsten Duwe 2dc170
diff --git a/drivers/crypto/qat/qat_common/adf_common_drv.h b/drivers/crypto/qat/qat_common/adf_common_drv.h
Torsten Duwe 2dc170
index 0775491768797..e8c9b77c0d66b 100644
Torsten Duwe 2dc170
--- a/drivers/crypto/qat/qat_common/adf_common_drv.h
Torsten Duwe 2dc170
+++ b/drivers/crypto/qat/qat_common/adf_common_drv.h
Torsten Duwe 2dc170
@@ -102,6 +102,7 @@ void adf_exit_aer(void);
Torsten Duwe 2dc170
 int adf_init_admin_comms(struct adf_accel_dev *accel_dev);
Torsten Duwe 2dc170
 void adf_exit_admin_comms(struct adf_accel_dev *accel_dev);
Torsten Duwe 2dc170
 int adf_send_admin_init(struct adf_accel_dev *accel_dev);
Torsten Duwe 2dc170
+int adf_init_admin_pm(struct adf_accel_dev *accel_dev, u32 idle_delay);
Torsten Duwe 2dc170
 int adf_init_arb(struct adf_accel_dev *accel_dev);
Torsten Duwe 2dc170
 void adf_exit_arb(struct adf_accel_dev *accel_dev);
Torsten Duwe 2dc170
 void adf_update_ring_arb(struct adf_etr_ring_data *ring);
Torsten Duwe 2dc170
diff --git a/drivers/crypto/qat/qat_common/adf_gen4_pm.c b/drivers/crypto/qat/qat_common/adf_gen4_pm.c
Torsten Duwe 2dc170
new file mode 100644
Torsten Duwe 2dc170
index 0000000000000..7037c0892a8a2
Torsten Duwe 2dc170
--- /dev/null
Torsten Duwe 2dc170
+++ b/drivers/crypto/qat/qat_common/adf_gen4_pm.c
Torsten Duwe 2dc170
@@ -0,0 +1,137 @@
Torsten Duwe 2dc170
+// SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only)
Torsten Duwe 2dc170
+/* Copyright(c) 2022 Intel Corporation */
Torsten Duwe 2dc170
+#include <linux/bitfield.h>
Torsten Duwe 2dc170
+#include <linux/iopoll.h>
Torsten Duwe 2dc170
+#include "adf_accel_devices.h"
Torsten Duwe 2dc170
+#include "adf_common_drv.h"
Torsten Duwe 2dc170
+#include "adf_gen4_pm.h"
Torsten Duwe 2dc170
+#include "adf_cfg_strings.h"
Torsten Duwe 2dc170
+#include "icp_qat_fw_init_admin.h"
Torsten Duwe 2dc170
+#include "adf_gen4_hw_data.h"
Torsten Duwe 2dc170
+#include "adf_cfg.h"
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
+enum qat_pm_host_msg {
Torsten Duwe 2dc170
+	PM_NO_CHANGE = 0,
Torsten Duwe 2dc170
+	PM_SET_MIN,
Torsten Duwe 2dc170
+};
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
+struct adf_gen4_pm_data {
Torsten Duwe 2dc170
+	struct work_struct pm_irq_work;
Torsten Duwe 2dc170
+	struct adf_accel_dev *accel_dev;
Torsten Duwe 2dc170
+	u32 pm_int_sts;
Torsten Duwe 2dc170
+};
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
+static int send_host_msg(struct adf_accel_dev *accel_dev)
Torsten Duwe 2dc170
+{
Torsten Duwe 2dc170
+	void __iomem *pmisc = adf_get_pmisc_base(accel_dev);
Torsten Duwe 2dc170
+	u32 msg;
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
+	msg = ADF_CSR_RD(pmisc, ADF_GEN4_PM_HOST_MSG);
Torsten Duwe 2dc170
+	if (msg & ADF_GEN4_PM_MSG_PENDING)
Torsten Duwe 2dc170
+		return -EBUSY;
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
+	/* Send HOST_MSG */
Torsten Duwe 2dc170
+	msg = FIELD_PREP(ADF_GEN4_PM_MSG_PAYLOAD_BIT_MASK, PM_SET_MIN);
Torsten Duwe 2dc170
+	msg |= ADF_GEN4_PM_MSG_PENDING;
Torsten Duwe 2dc170
+	ADF_CSR_WR(pmisc, ADF_GEN4_PM_HOST_MSG, msg);
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
+	/* Poll status register to make sure the HOST_MSG has been processed */
Torsten Duwe 2dc170
+	return read_poll_timeout(ADF_CSR_RD, msg,
Torsten Duwe 2dc170
+				!(msg & ADF_GEN4_PM_MSG_PENDING),
Torsten Duwe 2dc170
+				ADF_GEN4_PM_MSG_POLL_DELAY_US,
Torsten Duwe 2dc170
+				ADF_GEN4_PM_POLL_TIMEOUT_US, true, pmisc,
Torsten Duwe 2dc170
+				ADF_GEN4_PM_HOST_MSG);
Torsten Duwe 2dc170
+}
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
+static void pm_bh_handler(struct work_struct *work)
Torsten Duwe 2dc170
+{
Torsten Duwe 2dc170
+	struct adf_gen4_pm_data *pm_data =
Torsten Duwe 2dc170
+		container_of(work, struct adf_gen4_pm_data, pm_irq_work);
Torsten Duwe 2dc170
+	struct adf_accel_dev *accel_dev = pm_data->accel_dev;
Torsten Duwe 2dc170
+	void __iomem *pmisc = adf_get_pmisc_base(accel_dev);
Torsten Duwe 2dc170
+	u32 pm_int_sts = pm_data->pm_int_sts;
Torsten Duwe 2dc170
+	u32 val;
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
+	/* PM Idle interrupt */
Torsten Duwe 2dc170
+	if (pm_int_sts & ADF_GEN4_PM_IDLE_STS) {
Torsten Duwe 2dc170
+		/* Issue host message to FW */
Torsten Duwe 2dc170
+		if (send_host_msg(accel_dev))
Torsten Duwe 2dc170
+			dev_warn_ratelimited(&GET_DEV(accel_dev),
Torsten Duwe 2dc170
+					     "Failed to send host msg to FW\n");
Torsten Duwe 2dc170
+	}
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
+	/* Clear interrupt status */
Torsten Duwe 2dc170
+	ADF_CSR_WR(pmisc, ADF_GEN4_PM_INTERRUPT, pm_int_sts);
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
+	/* Reenable PM interrupt */
Torsten Duwe 2dc170
+	val = ADF_CSR_RD(pmisc, ADF_GEN4_ERRMSK2);
Torsten Duwe 2dc170
+	val &= ~ADF_GEN4_PM_SOU;
Torsten Duwe 2dc170
+	ADF_CSR_WR(pmisc, ADF_GEN4_ERRMSK2, val);
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
+	kfree(pm_data);
Torsten Duwe 2dc170
+}
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
+bool adf_gen4_handle_pm_interrupt(struct adf_accel_dev *accel_dev)
Torsten Duwe 2dc170
+{
Torsten Duwe 2dc170
+	void __iomem *pmisc = adf_get_pmisc_base(accel_dev);
Torsten Duwe 2dc170
+	struct adf_gen4_pm_data *pm_data = NULL;
Torsten Duwe 2dc170
+	u32 errsou2;
Torsten Duwe 2dc170
+	u32 errmsk2;
Torsten Duwe 2dc170
+	u32 val;
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
+	/* Only handle the interrupt triggered by PM */
Torsten Duwe 2dc170
+	errmsk2 = ADF_CSR_RD(pmisc, ADF_GEN4_ERRMSK2);
Torsten Duwe 2dc170
+	if (errmsk2 & ADF_GEN4_PM_SOU)
Torsten Duwe 2dc170
+		return false;
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
+	errsou2 = ADF_CSR_RD(pmisc, ADF_GEN4_ERRSOU2);
Torsten Duwe 2dc170
+	if (!(errsou2 & ADF_GEN4_PM_SOU))
Torsten Duwe 2dc170
+		return false;
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
+	/* Disable interrupt */
Torsten Duwe 2dc170
+	val = ADF_CSR_RD(pmisc, ADF_GEN4_ERRMSK2);
Torsten Duwe 2dc170
+	val |= ADF_GEN4_PM_SOU;
Torsten Duwe 2dc170
+	ADF_CSR_WR(pmisc, ADF_GEN4_ERRMSK2, val);
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
+	val = ADF_CSR_RD(pmisc, ADF_GEN4_PM_INTERRUPT);
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
+	pm_data = kzalloc(sizeof(*pm_data), GFP_ATOMIC);
Torsten Duwe 2dc170
+	if (!pm_data)
Torsten Duwe 2dc170
+		return false;
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
+	pm_data->pm_int_sts = val;
Torsten Duwe 2dc170
+	pm_data->accel_dev = accel_dev;
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
+	INIT_WORK(&pm_data->pm_irq_work, pm_bh_handler);
Torsten Duwe 2dc170
+	adf_misc_wq_queue_work(&pm_data->pm_irq_work);
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
+	return true;
Torsten Duwe 2dc170
+}
Torsten Duwe 2dc170
+EXPORT_SYMBOL_GPL(adf_gen4_handle_pm_interrupt);
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
+int adf_gen4_enable_pm(struct adf_accel_dev *accel_dev)
Torsten Duwe 2dc170
+{
Torsten Duwe 2dc170
+	void __iomem *pmisc = adf_get_pmisc_base(accel_dev);
Torsten Duwe 2dc170
+	int ret;
Torsten Duwe 2dc170
+	u32 val;
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
+	ret = adf_init_admin_pm(accel_dev, ADF_GEN4_PM_DEFAULT_IDLE_FILTER);
Torsten Duwe 2dc170
+	if (ret)
Torsten Duwe 2dc170
+		return ret;
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
+	/* Enable default PM interrupts: IDLE, THROTTLE */
Torsten Duwe 2dc170
+	val = ADF_CSR_RD(pmisc, ADF_GEN4_PM_INTERRUPT);
Torsten Duwe 2dc170
+	val |= ADF_GEN4_PM_INT_EN_DEFAULT;
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
+	/* Clear interrupt status */
Torsten Duwe 2dc170
+	val |= ADF_GEN4_PM_INT_STS_MASK;
Torsten Duwe 2dc170
+	ADF_CSR_WR(pmisc, ADF_GEN4_PM_INTERRUPT, val);
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
+	/* Unmask PM Interrupt */
Torsten Duwe 2dc170
+	val = ADF_CSR_RD(pmisc, ADF_GEN4_ERRMSK2);
Torsten Duwe 2dc170
+	val &= ~ADF_GEN4_PM_SOU;
Torsten Duwe 2dc170
+	ADF_CSR_WR(pmisc, ADF_GEN4_ERRMSK2, val);
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
+	return 0;
Torsten Duwe 2dc170
+}
Torsten Duwe 2dc170
+EXPORT_SYMBOL_GPL(adf_gen4_enable_pm);
Torsten Duwe 2dc170
diff --git a/drivers/crypto/qat/qat_common/adf_gen4_pm.h b/drivers/crypto/qat/qat_common/adf_gen4_pm.h
Torsten Duwe 2dc170
new file mode 100644
Torsten Duwe 2dc170
index 0000000000000..f8f8a9ee29e5b
Torsten Duwe 2dc170
--- /dev/null
Torsten Duwe 2dc170
+++ b/drivers/crypto/qat/qat_common/adf_gen4_pm.h
Torsten Duwe 2dc170
@@ -0,0 +1,44 @@
Torsten Duwe 2dc170
+/* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) */
Torsten Duwe 2dc170
+/* Copyright(c) 2022 Intel Corporation */
Torsten Duwe 2dc170
+#ifndef ADF_GEN4_PM_H
Torsten Duwe 2dc170
+#define ADF_GEN4_PM_H
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
+#include "adf_accel_devices.h"
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
+/* Power management registers */
Torsten Duwe 2dc170
+#define ADF_GEN4_PM_HOST_MSG (0x50A01C)
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
+/* Power management */
Torsten Duwe 2dc170
+#define ADF_GEN4_PM_POLL_DELAY_US	20
Torsten Duwe 2dc170
+#define ADF_GEN4_PM_POLL_TIMEOUT_US	USEC_PER_SEC
Torsten Duwe 2dc170
+#define ADF_GEN4_PM_MSG_POLL_DELAY_US	(10 * USEC_PER_MSEC)
Torsten Duwe 2dc170
+#define ADF_GEN4_PM_STATUS		(0x50A00C)
Torsten Duwe 2dc170
+#define ADF_GEN4_PM_INTERRUPT		(0x50A028)
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
+/* Power management source in ERRSOU2 and ERRMSK2 */
Torsten Duwe 2dc170
+#define ADF_GEN4_PM_SOU			BIT(18)
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
+#define ADF_GEN4_PM_IDLE_INT_EN		BIT(18)
Torsten Duwe 2dc170
+#define ADF_GEN4_PM_THROTTLE_INT_EN	BIT(19)
Torsten Duwe 2dc170
+#define ADF_GEN4_PM_DRV_ACTIVE		BIT(20)
Torsten Duwe 2dc170
+#define ADF_GEN4_PM_INIT_STATE		BIT(21)
Torsten Duwe 2dc170
+#define ADF_GEN4_PM_INT_EN_DEFAULT	(ADF_GEN4_PM_IDLE_INT_EN | \
Torsten Duwe 2dc170
+					ADF_GEN4_PM_THROTTLE_INT_EN)
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
+#define ADF_GEN4_PM_THR_STS	BIT(0)
Torsten Duwe 2dc170
+#define ADF_GEN4_PM_IDLE_STS	BIT(1)
Torsten Duwe 2dc170
+#define ADF_GEN4_PM_FW_INT_STS	BIT(2)
Torsten Duwe 2dc170
+#define ADF_GEN4_PM_INT_STS_MASK (ADF_GEN4_PM_THR_STS | \
Torsten Duwe 2dc170
+				 ADF_GEN4_PM_IDLE_STS | \
Torsten Duwe 2dc170
+				 ADF_GEN4_PM_FW_INT_STS)
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
+#define ADF_GEN4_PM_MSG_PENDING			BIT(0)
Torsten Duwe 2dc170
+#define ADF_GEN4_PM_MSG_PAYLOAD_BIT_MASK	GENMASK(28, 1)
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
+#define ADF_GEN4_PM_DEFAULT_IDLE_FILTER		(0x0)
Torsten Duwe 2dc170
+#define ADF_GEN4_PM_MAX_IDLE_FILTER		(0x7)
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
+int adf_gen4_enable_pm(struct adf_accel_dev *accel_dev);
Torsten Duwe 2dc170
+bool adf_gen4_handle_pm_interrupt(struct adf_accel_dev *accel_dev);
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
+#endif
Torsten Duwe 2dc170
diff --git a/drivers/crypto/qat/qat_common/adf_init.c b/drivers/crypto/qat/qat_common/adf_init.c
Torsten Duwe 2dc170
index 2edc63c6b6caa..c2c718f1b4895 100644
Torsten Duwe 2dc170
--- a/drivers/crypto/qat/qat_common/adf_init.c
Torsten Duwe 2dc170
+++ b/drivers/crypto/qat/qat_common/adf_init.c
Torsten Duwe 2dc170
@@ -181,6 +181,12 @@ int adf_dev_start(struct adf_accel_dev *accel_dev)
Torsten Duwe 2dc170
 	if (hw_data->set_ssm_wdtimer)
Torsten Duwe 2dc170
 		hw_data->set_ssm_wdtimer(accel_dev);
Torsten Duwe 2dc170
 
Torsten Duwe 2dc170
+	/* Enable Power Management */
Torsten Duwe 2dc170
+	if (hw_data->enable_pm && hw_data->enable_pm(accel_dev)) {
Torsten Duwe 2dc170
+		dev_err(&GET_DEV(accel_dev), "Failed to configure Power Management\n");
Torsten Duwe 2dc170
+		return -EFAULT;
Torsten Duwe 2dc170
+	}
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
 	list_for_each(list_itr, &service_table) {
Torsten Duwe 2dc170
 		service = list_entry(list_itr, struct service_hndl, list);
Torsten Duwe 2dc170
 		if (service->event_hld(accel_dev, ADF_EVENT_START)) {
Torsten Duwe 2dc170
diff --git a/drivers/crypto/qat/qat_common/adf_isr.c b/drivers/crypto/qat/qat_common/adf_isr.c
Torsten Duwe 2dc170
index 803b89ba9670c..a35149f8bf1ee 100644
Torsten Duwe 2dc170
--- a/drivers/crypto/qat/qat_common/adf_isr.c
Torsten Duwe 2dc170
+++ b/drivers/crypto/qat/qat_common/adf_isr.c
Torsten Duwe 2dc170
@@ -124,6 +124,17 @@ static bool adf_handle_vf2pf_int(struct adf_accel_dev *accel_dev)
Torsten Duwe 2dc170
 }
Torsten Duwe 2dc170
 #endif /* CONFIG_PCI_IOV */
Torsten Duwe 2dc170
 
Torsten Duwe 2dc170
+static bool adf_handle_pm_int(struct adf_accel_dev *accel_dev)
Torsten Duwe 2dc170
+{
Torsten Duwe 2dc170
+	struct adf_hw_device_data *hw_data = accel_dev->hw_device;
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
+	if (hw_data->handle_pm_interrupt &&
Torsten Duwe 2dc170
+	    hw_data->handle_pm_interrupt(accel_dev))
Torsten Duwe 2dc170
+		return true;
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
+	return false;
Torsten Duwe 2dc170
+}
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
 static irqreturn_t adf_msix_isr_ae(int irq, void *dev_ptr)
Torsten Duwe 2dc170
 {
Torsten Duwe 2dc170
 	struct adf_accel_dev *accel_dev = dev_ptr;
Torsten Duwe 2dc170
@@ -134,6 +145,9 @@ static irqreturn_t adf_msix_isr_ae(int irq, void *dev_ptr)
Torsten Duwe 2dc170
 		return IRQ_HANDLED;
Torsten Duwe 2dc170
 #endif /* CONFIG_PCI_IOV */
Torsten Duwe 2dc170
 
Torsten Duwe 2dc170
+	if (adf_handle_pm_int(accel_dev))
Torsten Duwe 2dc170
+		return IRQ_HANDLED;
Torsten Duwe 2dc170
+
Torsten Duwe 2dc170
 	dev_dbg(&GET_DEV(accel_dev), "qat_dev%d spurious AE interrupt\n",
Torsten Duwe 2dc170
 		accel_dev->accel_id);
Torsten Duwe 2dc170
 
Torsten Duwe 2dc170
diff --git a/drivers/crypto/qat/qat_common/icp_qat_fw_init_admin.h b/drivers/crypto/qat/qat_common/icp_qat_fw_init_admin.h
Torsten Duwe 2dc170
index afe59a7684ac5..56cb827f93ea3 100644
Torsten Duwe 2dc170
--- a/drivers/crypto/qat/qat_common/icp_qat_fw_init_admin.h
Torsten Duwe 2dc170
+++ b/drivers/crypto/qat/qat_common/icp_qat_fw_init_admin.h
Torsten Duwe 2dc170
@@ -16,6 +16,7 @@ enum icp_qat_fw_init_admin_cmd_id {
Torsten Duwe 2dc170
 	ICP_QAT_FW_HEARTBEAT_SYNC = 7,
Torsten Duwe 2dc170
 	ICP_QAT_FW_HEARTBEAT_GET = 8,
Torsten Duwe 2dc170
 	ICP_QAT_FW_COMP_CAPABILITY_GET = 9,
Torsten Duwe 2dc170
+	ICP_QAT_FW_PM_STATE_CONFIG = 128,
Torsten Duwe 2dc170
 };
Torsten Duwe 2dc170
 
Torsten Duwe 2dc170
 enum icp_qat_fw_init_admin_resp_status {
Torsten Duwe 2dc170
-- 
Torsten Duwe 2dc170
2.35.3
Torsten Duwe 2dc170