Skip to content

Commit e5745f3

Browse files
wziembaxherbertx
authored andcommitted
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>
1 parent f734409 commit e5745f3

File tree

11 files changed

+252
-16
lines changed

11 files changed

+252
-16
lines changed

drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <adf_common_drv.h>
77
#include <adf_gen4_hw_data.h>
88
#include <adf_gen4_pfvf.h>
9+
#include <adf_gen4_pm.h>
910
#include "adf_4xxx_hw_data.h"
1011
#include "icp_qat_hw.h"
1112

@@ -257,18 +258,18 @@ static int adf_init_device(struct adf_accel_dev *accel_dev)
257258

258259
/* Temporarily mask PM interrupt */
259260
csr = ADF_CSR_RD(addr, ADF_GEN4_ERRMSK2);
260-
csr |= ADF_4XXX_PM_SOU;
261+
csr |= ADF_GEN4_PM_SOU;
261262
ADF_CSR_WR(addr, ADF_GEN4_ERRMSK2, csr);
262263

263264
/* Set DRV_ACTIVE bit to power up the device */
264-
ADF_CSR_WR(addr, ADF_4XXX_PM_INTERRUPT, ADF_4XXX_PM_DRV_ACTIVE);
265+
ADF_CSR_WR(addr, ADF_GEN4_PM_INTERRUPT, ADF_GEN4_PM_DRV_ACTIVE);
265266

266267
/* Poll status register to make sure the device is powered up */
267268
ret = read_poll_timeout(ADF_CSR_RD, status,
268-
status & ADF_4XXX_PM_INIT_STATE,
269-
ADF_4XXX_PM_POLL_DELAY_US,
270-
ADF_4XXX_PM_POLL_TIMEOUT_US, true, addr,
271-
ADF_4XXX_PM_STATUS);
269+
status & ADF_GEN4_PM_INIT_STATE,
270+
ADF_GEN4_PM_POLL_DELAY_US,
271+
ADF_GEN4_PM_POLL_TIMEOUT_US, true, addr,
272+
ADF_GEN4_PM_STATUS);
272273
if (ret)
273274
dev_err(&GET_DEV(accel_dev), "Failed to power up the device\n");
274275

@@ -354,6 +355,8 @@ void adf_init_hw_data_4xxx(struct adf_hw_device_data *hw_data)
354355
hw_data->set_ssm_wdtimer = adf_gen4_set_ssm_wdtimer;
355356
hw_data->disable_iov = adf_disable_sriov;
356357
hw_data->ring_pair_reset = adf_gen4_ring_pair_reset;
358+
hw_data->enable_pm = adf_gen4_enable_pm;
359+
hw_data->handle_pm_interrupt = adf_gen4_handle_pm_interrupt;
357360

358361
adf_gen4_init_hw_csr_ops(&hw_data->csr_ops);
359362
adf_gen4_init_pf_pfvf_ops(&hw_data->pfvf_ops);

drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.h

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -49,16 +49,6 @@
4949
#define ADF_4XXX_ADMINMSGLR_OFFSET (0x500578)
5050
#define ADF_4XXX_MAILBOX_BASE_OFFSET (0x600970)
5151

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-
6252
/* Firmware Binaries */
6353
#define ADF_4XXX_FW "qat_4xxx.bin"
6454
#define ADF_4XXX_MMP "qat_4xxx_mmp.bin"

drivers/crypto/qat/qat_common/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ intel_qat-objs := adf_cfg.o \
1212
adf_hw_arbiter.o \
1313
adf_gen2_hw_data.o \
1414
adf_gen4_hw_data.o \
15+
adf_gen4_pm.o \
1516
qat_crypto.o \
1617
qat_algs.o \
1718
qat_asym_algs.o \

drivers/crypto/qat/qat_common/adf_accel_devices.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,8 @@ struct adf_hw_device_data {
184184
void (*exit_arb)(struct adf_accel_dev *accel_dev);
185185
const u32 *(*get_arb_mapping)(void);
186186
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);
187189
void (*disable_iov)(struct adf_accel_dev *accel_dev);
188190
void (*configure_iov_threads)(struct adf_accel_dev *accel_dev,
189191
bool enable);

drivers/crypto/qat/qat_common/adf_admin.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,43 @@ int adf_send_admin_init(struct adf_accel_dev *accel_dev)
251251
}
252252
EXPORT_SYMBOL_GPL(adf_send_admin_init);
253253

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+
254291
int adf_init_admin_comms(struct adf_accel_dev *accel_dev)
255292
{
256293
struct adf_admin_comms *admin;

drivers/crypto/qat/qat_common/adf_common_drv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ void adf_exit_aer(void);
102102
int adf_init_admin_comms(struct adf_accel_dev *accel_dev);
103103
void adf_exit_admin_comms(struct adf_accel_dev *accel_dev);
104104
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);
105106
int adf_init_arb(struct adf_accel_dev *accel_dev);
106107
void adf_exit_arb(struct adf_accel_dev *accel_dev);
107108
void adf_update_ring_arb(struct adf_etr_ring_data *ring);
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
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);
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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

drivers/crypto/qat/qat_common/adf_init.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,12 @@ int adf_dev_start(struct adf_accel_dev *accel_dev)
181181
if (hw_data->set_ssm_wdtimer)
182182
hw_data->set_ssm_wdtimer(accel_dev);
183183

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+
184190
list_for_each(list_itr, &service_table) {
185191
service = list_entry(list_itr, struct service_hndl, list);
186192
if (service->event_hld(accel_dev, ADF_EVENT_START)) {

drivers/crypto/qat/qat_common/adf_isr.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,17 @@ static bool adf_handle_vf2pf_int(struct adf_accel_dev *accel_dev)
124124
}
125125
#endif /* CONFIG_PCI_IOV */
126126

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+
127138
static irqreturn_t adf_msix_isr_ae(int irq, void *dev_ptr)
128139
{
129140
struct adf_accel_dev *accel_dev = dev_ptr;
@@ -134,6 +145,9 @@ static irqreturn_t adf_msix_isr_ae(int irq, void *dev_ptr)
134145
return IRQ_HANDLED;
135146
#endif /* CONFIG_PCI_IOV */
136147

148+
if (adf_handle_pm_int(accel_dev))
149+
return IRQ_HANDLED;
150+
137151
dev_dbg(&GET_DEV(accel_dev), "qat_dev%d spurious AE interrupt\n",
138152
accel_dev->accel_id);
139153

0 commit comments

Comments
 (0)