Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

crypto: qat - enable power management for QAT GEN4

Add support for HW QAT Power Management (PM) feature.
This feature is enabled at init time (1) by sending an admin message to
the firmware, targeting the admin AE, that sets the idle time before
the device changes state and (2) by unmasking the PM source of interrupt
in ERRMSK2.

The interrupt handler is extended to handle a PM interrupt which
is triggered by HW when a PM transition occurs. In this case, the
driver responds acknowledging the transaction using the HOST_MSG
mailbox.

Signed-off-by: Wojciech Ziemba <wojciech.ziemba@intel.com>
Co-developed-by: Marcinx Malinowski <marcinx.malinowski@intel.com>
Signed-off-by: Marcinx Malinowski <marcinx.malinowski@intel.com>
Reviewed-by: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
Reviewed-by: Marco Chiappero <marco.chiappero@intel.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

authored by

Wojciech Ziemba and committed by
Herbert Xu
e5745f34 f734409c

+252 -16
+9 -6
drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c
··· 6 6 #include <adf_common_drv.h> 7 7 #include <adf_gen4_hw_data.h> 8 8 #include <adf_gen4_pfvf.h> 9 + #include <adf_gen4_pm.h> 9 10 #include "adf_4xxx_hw_data.h" 10 11 #include "icp_qat_hw.h" 11 12 ··· 258 257 259 258 /* Temporarily mask PM interrupt */ 260 259 csr = ADF_CSR_RD(addr, ADF_GEN4_ERRMSK2); 261 - csr |= ADF_4XXX_PM_SOU; 260 + csr |= ADF_GEN4_PM_SOU; 262 261 ADF_CSR_WR(addr, ADF_GEN4_ERRMSK2, csr); 263 262 264 263 /* Set DRV_ACTIVE bit to power up the device */ 265 - ADF_CSR_WR(addr, ADF_4XXX_PM_INTERRUPT, ADF_4XXX_PM_DRV_ACTIVE); 264 + ADF_CSR_WR(addr, ADF_GEN4_PM_INTERRUPT, ADF_GEN4_PM_DRV_ACTIVE); 266 265 267 266 /* Poll status register to make sure the device is powered up */ 268 267 ret = read_poll_timeout(ADF_CSR_RD, status, 269 - status & ADF_4XXX_PM_INIT_STATE, 270 - ADF_4XXX_PM_POLL_DELAY_US, 271 - ADF_4XXX_PM_POLL_TIMEOUT_US, true, addr, 272 - ADF_4XXX_PM_STATUS); 268 + status & ADF_GEN4_PM_INIT_STATE, 269 + ADF_GEN4_PM_POLL_DELAY_US, 270 + ADF_GEN4_PM_POLL_TIMEOUT_US, true, addr, 271 + ADF_GEN4_PM_STATUS); 273 272 if (ret) 274 273 dev_err(&GET_DEV(accel_dev), "Failed to power up the device\n"); 275 274 ··· 355 354 hw_data->set_ssm_wdtimer = adf_gen4_set_ssm_wdtimer; 356 355 hw_data->disable_iov = adf_disable_sriov; 357 356 hw_data->ring_pair_reset = adf_gen4_ring_pair_reset; 357 + hw_data->enable_pm = adf_gen4_enable_pm; 358 + hw_data->handle_pm_interrupt = adf_gen4_handle_pm_interrupt; 358 359 359 360 adf_gen4_init_hw_csr_ops(&hw_data->csr_ops); 360 361 adf_gen4_init_pf_pfvf_ops(&hw_data->pfvf_ops);
-10
drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.h
··· 49 49 #define ADF_4XXX_ADMINMSGLR_OFFSET (0x500578) 50 50 #define ADF_4XXX_MAILBOX_BASE_OFFSET (0x600970) 51 51 52 - /* Power management */ 53 - #define ADF_4XXX_PM_POLL_DELAY_US 20 54 - #define ADF_4XXX_PM_POLL_TIMEOUT_US USEC_PER_SEC 55 - #define ADF_4XXX_PM_STATUS (0x50A00C) 56 - #define ADF_4XXX_PM_INTERRUPT (0x50A028) 57 - #define ADF_4XXX_PM_DRV_ACTIVE BIT(20) 58 - #define ADF_4XXX_PM_INIT_STATE BIT(21) 59 - /* Power management source in ERRSOU2 and ERRMSK2 */ 60 - #define ADF_4XXX_PM_SOU BIT(18) 61 - 62 52 /* Firmware Binaries */ 63 53 #define ADF_4XXX_FW "qat_4xxx.bin" 64 54 #define ADF_4XXX_MMP "qat_4xxx_mmp.bin"
+1
drivers/crypto/qat/qat_common/Makefile
··· 12 12 adf_hw_arbiter.o \ 13 13 adf_gen2_hw_data.o \ 14 14 adf_gen4_hw_data.o \ 15 + adf_gen4_pm.o \ 15 16 qat_crypto.o \ 16 17 qat_algs.o \ 17 18 qat_asym_algs.o \
+2
drivers/crypto/qat/qat_common/adf_accel_devices.h
··· 184 184 void (*exit_arb)(struct adf_accel_dev *accel_dev); 185 185 const u32 *(*get_arb_mapping)(void); 186 186 int (*init_device)(struct adf_accel_dev *accel_dev); 187 + int (*enable_pm)(struct adf_accel_dev *accel_dev); 188 + bool (*handle_pm_interrupt)(struct adf_accel_dev *accel_dev); 187 189 void (*disable_iov)(struct adf_accel_dev *accel_dev); 188 190 void (*configure_iov_threads)(struct adf_accel_dev *accel_dev, 189 191 bool enable);
+37
drivers/crypto/qat/qat_common/adf_admin.c
··· 251 251 } 252 252 EXPORT_SYMBOL_GPL(adf_send_admin_init); 253 253 254 + /** 255 + * adf_init_admin_pm() - Function sends PM init message to FW 256 + * @accel_dev: Pointer to acceleration device. 257 + * @idle_delay: QAT HW idle time before power gating is initiated. 258 + * 000 - 64us 259 + * 001 - 128us 260 + * 010 - 256us 261 + * 011 - 512us 262 + * 100 - 1ms 263 + * 101 - 2ms 264 + * 110 - 4ms 265 + * 111 - 8ms 266 + * 267 + * Function sends to the FW the admin init message for the PM state 268 + * configuration. 269 + * 270 + * Return: 0 on success, error code otherwise. 271 + */ 272 + int adf_init_admin_pm(struct adf_accel_dev *accel_dev, u32 idle_delay) 273 + { 274 + struct adf_hw_device_data *hw_data = accel_dev->hw_device; 275 + struct icp_qat_fw_init_admin_resp resp = {0}; 276 + struct icp_qat_fw_init_admin_req req = {0}; 277 + u32 ae_mask = hw_data->admin_ae_mask; 278 + 279 + if (!accel_dev->admin) { 280 + dev_err(&GET_DEV(accel_dev), "adf_admin is not available\n"); 281 + return -EFAULT; 282 + } 283 + 284 + req.cmd_id = ICP_QAT_FW_PM_STATE_CONFIG; 285 + req.idle_filter = idle_delay; 286 + 287 + return adf_send_admin(accel_dev, &req, &resp, ae_mask); 288 + } 289 + EXPORT_SYMBOL_GPL(adf_init_admin_pm); 290 + 254 291 int adf_init_admin_comms(struct adf_accel_dev *accel_dev) 255 292 { 256 293 struct adf_admin_comms *admin;
+1
drivers/crypto/qat/qat_common/adf_common_drv.h
··· 102 102 int adf_init_admin_comms(struct adf_accel_dev *accel_dev); 103 103 void adf_exit_admin_comms(struct adf_accel_dev *accel_dev); 104 104 int adf_send_admin_init(struct adf_accel_dev *accel_dev); 105 + int adf_init_admin_pm(struct adf_accel_dev *accel_dev, u32 idle_delay); 105 106 int adf_init_arb(struct adf_accel_dev *accel_dev); 106 107 void adf_exit_arb(struct adf_accel_dev *accel_dev); 107 108 void adf_update_ring_arb(struct adf_etr_ring_data *ring);
+137
drivers/crypto/qat/qat_common/adf_gen4_pm.c
··· 1 + // SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) 2 + /* Copyright(c) 2022 Intel Corporation */ 3 + #include <linux/bitfield.h> 4 + #include <linux/iopoll.h> 5 + #include "adf_accel_devices.h" 6 + #include "adf_common_drv.h" 7 + #include "adf_gen4_pm.h" 8 + #include "adf_cfg_strings.h" 9 + #include "icp_qat_fw_init_admin.h" 10 + #include "adf_gen4_hw_data.h" 11 + #include "adf_cfg.h" 12 + 13 + enum qat_pm_host_msg { 14 + PM_NO_CHANGE = 0, 15 + PM_SET_MIN, 16 + }; 17 + 18 + struct adf_gen4_pm_data { 19 + struct work_struct pm_irq_work; 20 + struct adf_accel_dev *accel_dev; 21 + u32 pm_int_sts; 22 + }; 23 + 24 + static int send_host_msg(struct adf_accel_dev *accel_dev) 25 + { 26 + void __iomem *pmisc = adf_get_pmisc_base(accel_dev); 27 + u32 msg; 28 + 29 + msg = ADF_CSR_RD(pmisc, ADF_GEN4_PM_HOST_MSG); 30 + if (msg & ADF_GEN4_PM_MSG_PENDING) 31 + return -EBUSY; 32 + 33 + /* Send HOST_MSG */ 34 + msg = FIELD_PREP(ADF_GEN4_PM_MSG_PAYLOAD_BIT_MASK, PM_SET_MIN); 35 + msg |= ADF_GEN4_PM_MSG_PENDING; 36 + ADF_CSR_WR(pmisc, ADF_GEN4_PM_HOST_MSG, msg); 37 + 38 + /* Poll status register to make sure the HOST_MSG has been processed */ 39 + return read_poll_timeout(ADF_CSR_RD, msg, 40 + !(msg & ADF_GEN4_PM_MSG_PENDING), 41 + ADF_GEN4_PM_MSG_POLL_DELAY_US, 42 + ADF_GEN4_PM_POLL_TIMEOUT_US, true, pmisc, 43 + ADF_GEN4_PM_HOST_MSG); 44 + } 45 + 46 + static void pm_bh_handler(struct work_struct *work) 47 + { 48 + struct adf_gen4_pm_data *pm_data = 49 + container_of(work, struct adf_gen4_pm_data, pm_irq_work); 50 + struct adf_accel_dev *accel_dev = pm_data->accel_dev; 51 + void __iomem *pmisc = adf_get_pmisc_base(accel_dev); 52 + u32 pm_int_sts = pm_data->pm_int_sts; 53 + u32 val; 54 + 55 + /* PM Idle interrupt */ 56 + if (pm_int_sts & ADF_GEN4_PM_IDLE_STS) { 57 + /* Issue host message to FW */ 58 + if (send_host_msg(accel_dev)) 59 + dev_warn_ratelimited(&GET_DEV(accel_dev), 60 + "Failed to send host msg to FW\n"); 61 + } 62 + 63 + /* Clear interrupt status */ 64 + ADF_CSR_WR(pmisc, ADF_GEN4_PM_INTERRUPT, pm_int_sts); 65 + 66 + /* Reenable PM interrupt */ 67 + val = ADF_CSR_RD(pmisc, ADF_GEN4_ERRMSK2); 68 + val &= ~ADF_GEN4_PM_SOU; 69 + ADF_CSR_WR(pmisc, ADF_GEN4_ERRMSK2, val); 70 + 71 + kfree(pm_data); 72 + } 73 + 74 + bool adf_gen4_handle_pm_interrupt(struct adf_accel_dev *accel_dev) 75 + { 76 + void __iomem *pmisc = adf_get_pmisc_base(accel_dev); 77 + struct adf_gen4_pm_data *pm_data = NULL; 78 + u32 errsou2; 79 + u32 errmsk2; 80 + u32 val; 81 + 82 + /* Only handle the interrupt triggered by PM */ 83 + errmsk2 = ADF_CSR_RD(pmisc, ADF_GEN4_ERRMSK2); 84 + if (errmsk2 & ADF_GEN4_PM_SOU) 85 + return false; 86 + 87 + errsou2 = ADF_CSR_RD(pmisc, ADF_GEN4_ERRSOU2); 88 + if (!(errsou2 & ADF_GEN4_PM_SOU)) 89 + return false; 90 + 91 + /* Disable interrupt */ 92 + val = ADF_CSR_RD(pmisc, ADF_GEN4_ERRMSK2); 93 + val |= ADF_GEN4_PM_SOU; 94 + ADF_CSR_WR(pmisc, ADF_GEN4_ERRMSK2, val); 95 + 96 + val = ADF_CSR_RD(pmisc, ADF_GEN4_PM_INTERRUPT); 97 + 98 + pm_data = kzalloc(sizeof(*pm_data), GFP_ATOMIC); 99 + if (!pm_data) 100 + return false; 101 + 102 + pm_data->pm_int_sts = val; 103 + pm_data->accel_dev = accel_dev; 104 + 105 + INIT_WORK(&pm_data->pm_irq_work, pm_bh_handler); 106 + adf_misc_wq_queue_work(&pm_data->pm_irq_work); 107 + 108 + return true; 109 + } 110 + EXPORT_SYMBOL_GPL(adf_gen4_handle_pm_interrupt); 111 + 112 + int adf_gen4_enable_pm(struct adf_accel_dev *accel_dev) 113 + { 114 + void __iomem *pmisc = adf_get_pmisc_base(accel_dev); 115 + int ret; 116 + u32 val; 117 + 118 + ret = adf_init_admin_pm(accel_dev, ADF_GEN4_PM_DEFAULT_IDLE_FILTER); 119 + if (ret) 120 + return ret; 121 + 122 + /* Enable default PM interrupts: IDLE, THROTTLE */ 123 + val = ADF_CSR_RD(pmisc, ADF_GEN4_PM_INTERRUPT); 124 + val |= ADF_GEN4_PM_INT_EN_DEFAULT; 125 + 126 + /* Clear interrupt status */ 127 + val |= ADF_GEN4_PM_INT_STS_MASK; 128 + ADF_CSR_WR(pmisc, ADF_GEN4_PM_INTERRUPT, val); 129 + 130 + /* Unmask PM Interrupt */ 131 + val = ADF_CSR_RD(pmisc, ADF_GEN4_ERRMSK2); 132 + val &= ~ADF_GEN4_PM_SOU; 133 + ADF_CSR_WR(pmisc, ADF_GEN4_ERRMSK2, val); 134 + 135 + return 0; 136 + } 137 + EXPORT_SYMBOL_GPL(adf_gen4_enable_pm);
+44
drivers/crypto/qat/qat_common/adf_gen4_pm.h
··· 1 + /* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) */ 2 + /* Copyright(c) 2022 Intel Corporation */ 3 + #ifndef ADF_GEN4_PM_H 4 + #define ADF_GEN4_PM_H 5 + 6 + #include "adf_accel_devices.h" 7 + 8 + /* Power management registers */ 9 + #define ADF_GEN4_PM_HOST_MSG (0x50A01C) 10 + 11 + /* Power management */ 12 + #define ADF_GEN4_PM_POLL_DELAY_US 20 13 + #define ADF_GEN4_PM_POLL_TIMEOUT_US USEC_PER_SEC 14 + #define ADF_GEN4_PM_MSG_POLL_DELAY_US (10 * USEC_PER_MSEC) 15 + #define ADF_GEN4_PM_STATUS (0x50A00C) 16 + #define ADF_GEN4_PM_INTERRUPT (0x50A028) 17 + 18 + /* Power management source in ERRSOU2 and ERRMSK2 */ 19 + #define ADF_GEN4_PM_SOU BIT(18) 20 + 21 + #define ADF_GEN4_PM_IDLE_INT_EN BIT(18) 22 + #define ADF_GEN4_PM_THROTTLE_INT_EN BIT(19) 23 + #define ADF_GEN4_PM_DRV_ACTIVE BIT(20) 24 + #define ADF_GEN4_PM_INIT_STATE BIT(21) 25 + #define ADF_GEN4_PM_INT_EN_DEFAULT (ADF_GEN4_PM_IDLE_INT_EN | \ 26 + ADF_GEN4_PM_THROTTLE_INT_EN) 27 + 28 + #define ADF_GEN4_PM_THR_STS BIT(0) 29 + #define ADF_GEN4_PM_IDLE_STS BIT(1) 30 + #define ADF_GEN4_PM_FW_INT_STS BIT(2) 31 + #define ADF_GEN4_PM_INT_STS_MASK (ADF_GEN4_PM_THR_STS | \ 32 + ADF_GEN4_PM_IDLE_STS | \ 33 + ADF_GEN4_PM_FW_INT_STS) 34 + 35 + #define ADF_GEN4_PM_MSG_PENDING BIT(0) 36 + #define ADF_GEN4_PM_MSG_PAYLOAD_BIT_MASK GENMASK(28, 1) 37 + 38 + #define ADF_GEN4_PM_DEFAULT_IDLE_FILTER (0x0) 39 + #define ADF_GEN4_PM_MAX_IDLE_FILTER (0x7) 40 + 41 + int adf_gen4_enable_pm(struct adf_accel_dev *accel_dev); 42 + bool adf_gen4_handle_pm_interrupt(struct adf_accel_dev *accel_dev); 43 + 44 + #endif
+6
drivers/crypto/qat/qat_common/adf_init.c
··· 181 181 if (hw_data->set_ssm_wdtimer) 182 182 hw_data->set_ssm_wdtimer(accel_dev); 183 183 184 + /* Enable Power Management */ 185 + if (hw_data->enable_pm && hw_data->enable_pm(accel_dev)) { 186 + dev_err(&GET_DEV(accel_dev), "Failed to configure Power Management\n"); 187 + return -EFAULT; 188 + } 189 + 184 190 list_for_each(list_itr, &service_table) { 185 191 service = list_entry(list_itr, struct service_hndl, list); 186 192 if (service->event_hld(accel_dev, ADF_EVENT_START)) {
+14
drivers/crypto/qat/qat_common/adf_isr.c
··· 124 124 } 125 125 #endif /* CONFIG_PCI_IOV */ 126 126 127 + static bool adf_handle_pm_int(struct adf_accel_dev *accel_dev) 128 + { 129 + struct adf_hw_device_data *hw_data = accel_dev->hw_device; 130 + 131 + if (hw_data->handle_pm_interrupt && 132 + hw_data->handle_pm_interrupt(accel_dev)) 133 + return true; 134 + 135 + return false; 136 + } 137 + 127 138 static irqreturn_t adf_msix_isr_ae(int irq, void *dev_ptr) 128 139 { 129 140 struct adf_accel_dev *accel_dev = dev_ptr; ··· 144 133 if (accel_dev->pf.vf_info && adf_handle_vf2pf_int(accel_dev)) 145 134 return IRQ_HANDLED; 146 135 #endif /* CONFIG_PCI_IOV */ 136 + 137 + if (adf_handle_pm_int(accel_dev)) 138 + return IRQ_HANDLED; 147 139 148 140 dev_dbg(&GET_DEV(accel_dev), "qat_dev%d spurious AE interrupt\n", 149 141 accel_dev->accel_id);
+1
drivers/crypto/qat/qat_common/icp_qat_fw_init_admin.h
··· 16 16 ICP_QAT_FW_HEARTBEAT_SYNC = 7, 17 17 ICP_QAT_FW_HEARTBEAT_GET = 8, 18 18 ICP_QAT_FW_COMP_CAPABILITY_GET = 9, 19 + ICP_QAT_FW_PM_STATE_CONFIG = 128, 19 20 }; 20 21 21 22 enum icp_qat_fw_init_admin_resp_status {