Skip to content

Commit bbfdde7

Browse files
simingwaherbertx
authored andcommitted
crypto: qat - add bank save and restore flows
Add logic to save, restore, quiesce and drain a ring bank for QAT GEN4 devices. This allows to save and restore the state of a Virtual Function (VF) and will be used to implement VM live migration. Signed-off-by: Siming Wan <[email protected]> Reviewed-by: Giovanni Cabiddu <[email protected]> Signed-off-by: Xin Zeng <[email protected]> Signed-off-by: Herbert Xu <[email protected]>
1 parent 3fa1057 commit bbfdde7

File tree

4 files changed

+338
-0
lines changed

4 files changed

+338
-0
lines changed

drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,8 @@ void adf_init_hw_data_4xxx(struct adf_hw_device_data *hw_data, u32 dev_id)
455455
hw_data->get_ring_to_svc_map = adf_gen4_get_ring_to_svc_map;
456456
hw_data->disable_iov = adf_disable_sriov;
457457
hw_data->ring_pair_reset = adf_gen4_ring_pair_reset;
458+
hw_data->bank_state_save = adf_gen4_bank_state_save;
459+
hw_data->bank_state_restore = adf_gen4_bank_state_restore;
458460
hw_data->enable_pm = adf_gen4_enable_pm;
459461
hw_data->handle_pm_interrupt = adf_gen4_handle_pm_interrupt;
460462
hw_data->dev_config = adf_gen4_dev_config;

drivers/crypto/intel/qat/qat_common/adf_accel_devices.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,40 @@ struct admin_info {
140140
u32 mailbox_offset;
141141
};
142142

143+
struct ring_config {
144+
u64 base;
145+
u32 config;
146+
u32 head;
147+
u32 tail;
148+
u32 reserved0;
149+
};
150+
151+
struct bank_state {
152+
u32 ringstat0;
153+
u32 ringstat1;
154+
u32 ringuostat;
155+
u32 ringestat;
156+
u32 ringnestat;
157+
u32 ringnfstat;
158+
u32 ringfstat;
159+
u32 ringcstat0;
160+
u32 ringcstat1;
161+
u32 ringcstat2;
162+
u32 ringcstat3;
163+
u32 iaintflagen;
164+
u32 iaintflagreg;
165+
u32 iaintflagsrcsel0;
166+
u32 iaintflagsrcsel1;
167+
u32 iaintcolen;
168+
u32 iaintcolctl;
169+
u32 iaintflagandcolen;
170+
u32 ringexpstat;
171+
u32 ringexpintenable;
172+
u32 ringsrvarben;
173+
u32 reserved0;
174+
struct ring_config rings[ADF_ETR_MAX_RINGS_PER_BANK];
175+
};
176+
143177
struct adf_hw_csr_ops {
144178
u64 (*build_csr_ring_base_addr)(dma_addr_t addr, u32 size);
145179
u32 (*read_csr_ring_head)(void __iomem *csr_base_addr, u32 bank,
@@ -271,6 +305,10 @@ struct adf_hw_device_data {
271305
void (*enable_ints)(struct adf_accel_dev *accel_dev);
272306
void (*set_ssm_wdtimer)(struct adf_accel_dev *accel_dev);
273307
int (*ring_pair_reset)(struct adf_accel_dev *accel_dev, u32 bank_nr);
308+
int (*bank_state_save)(struct adf_accel_dev *accel_dev, u32 bank_number,
309+
struct bank_state *state);
310+
int (*bank_state_restore)(struct adf_accel_dev *accel_dev,
311+
u32 bank_number, struct bank_state *state);
274312
void (*reset_device)(struct adf_accel_dev *accel_dev);
275313
void (*set_msix_rttable)(struct adf_accel_dev *accel_dev);
276314
const char *(*uof_get_name)(struct adf_accel_dev *accel_dev, u32 obj_num);

drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.c

Lines changed: 279 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only)
22
/* Copyright(c) 2020 Intel Corporation */
33
#include <linux/iopoll.h>
4+
#include <asm/div64.h>
45
#include "adf_accel_devices.h"
56
#include "adf_cfg_services.h"
67
#include "adf_common_drv.h"
@@ -390,3 +391,281 @@ u16 adf_gen4_get_ring_to_svc_map(struct adf_accel_dev *accel_dev)
390391
return ring_to_svc_map;
391392
}
392393
EXPORT_SYMBOL_GPL(adf_gen4_get_ring_to_svc_map);
394+
395+
/*
396+
* adf_gen4_bank_quiesce_coal_timer() - quiesce bank coalesced interrupt timer
397+
* @accel_dev: Pointer to the device structure
398+
* @bank_idx: Offset to the bank within this device
399+
* @timeout_ms: Timeout in milliseconds for the operation
400+
*
401+
* This function tries to quiesce the coalesced interrupt timer of a bank if
402+
* it has been enabled and triggered.
403+
*
404+
* Returns 0 on success, error code otherwise
405+
*
406+
*/
407+
int adf_gen4_bank_quiesce_coal_timer(struct adf_accel_dev *accel_dev,
408+
u32 bank_idx, int timeout_ms)
409+
{
410+
struct adf_hw_device_data *hw_data = GET_HW_DATA(accel_dev);
411+
struct adf_hw_csr_ops *csr_ops = GET_CSR_OPS(accel_dev);
412+
void __iomem *csr_misc = adf_get_pmisc_base(accel_dev);
413+
void __iomem *csr_etr = adf_get_etr_base(accel_dev);
414+
u32 int_col_ctl, int_col_mask, int_col_en;
415+
u32 e_stat, intsrc;
416+
u64 wait_us;
417+
int ret;
418+
419+
if (timeout_ms < 0)
420+
return -EINVAL;
421+
422+
int_col_ctl = csr_ops->read_csr_int_col_ctl(csr_etr, bank_idx);
423+
int_col_mask = csr_ops->get_int_col_ctl_enable_mask();
424+
if (!(int_col_ctl & int_col_mask))
425+
return 0;
426+
427+
int_col_en = csr_ops->read_csr_int_col_en(csr_etr, bank_idx);
428+
int_col_en &= BIT(ADF_WQM_CSR_RP_IDX_RX);
429+
430+
e_stat = csr_ops->read_csr_e_stat(csr_etr, bank_idx);
431+
if (!(~e_stat & int_col_en))
432+
return 0;
433+
434+
wait_us = 2 * ((int_col_ctl & ~int_col_mask) << 8) * USEC_PER_SEC;
435+
do_div(wait_us, hw_data->clock_frequency);
436+
wait_us = min(wait_us, (u64)timeout_ms * USEC_PER_MSEC);
437+
dev_dbg(&GET_DEV(accel_dev),
438+
"wait for bank %d - coalesced timer expires in %llu us (max=%u ms estat=0x%x intcolen=0x%x)\n",
439+
bank_idx, wait_us, timeout_ms, e_stat, int_col_en);
440+
441+
ret = read_poll_timeout(ADF_CSR_RD, intsrc, intsrc,
442+
ADF_COALESCED_POLL_DELAY_US, wait_us, true,
443+
csr_misc, ADF_WQM_CSR_RPINTSOU(bank_idx));
444+
if (ret)
445+
dev_warn(&GET_DEV(accel_dev),
446+
"coalesced timer for bank %d expired (%llu us)\n",
447+
bank_idx, wait_us);
448+
449+
return ret;
450+
}
451+
EXPORT_SYMBOL_GPL(adf_gen4_bank_quiesce_coal_timer);
452+
453+
static int drain_bank(void __iomem *csr, u32 bank_number, int timeout_us)
454+
{
455+
u32 status;
456+
457+
ADF_CSR_WR(csr, ADF_WQM_CSR_RPRESETCTL(bank_number),
458+
ADF_WQM_CSR_RPRESETCTL_DRAIN);
459+
460+
return read_poll_timeout(ADF_CSR_RD, status,
461+
status & ADF_WQM_CSR_RPRESETSTS_STATUS,
462+
ADF_RPRESET_POLL_DELAY_US, timeout_us, true,
463+
csr, ADF_WQM_CSR_RPRESETSTS(bank_number));
464+
}
465+
466+
void adf_gen4_bank_drain_finish(struct adf_accel_dev *accel_dev,
467+
u32 bank_number)
468+
{
469+
void __iomem *csr = adf_get_etr_base(accel_dev);
470+
471+
ADF_CSR_WR(csr, ADF_WQM_CSR_RPRESETSTS(bank_number),
472+
ADF_WQM_CSR_RPRESETSTS_STATUS);
473+
}
474+
475+
int adf_gen4_bank_drain_start(struct adf_accel_dev *accel_dev,
476+
u32 bank_number, int timeout_us)
477+
{
478+
void __iomem *csr = adf_get_etr_base(accel_dev);
479+
int ret;
480+
481+
dev_dbg(&GET_DEV(accel_dev), "Drain bank %d\n", bank_number);
482+
483+
ret = drain_bank(csr, bank_number, timeout_us);
484+
if (ret)
485+
dev_err(&GET_DEV(accel_dev), "Bank drain failed (timeout)\n");
486+
else
487+
dev_dbg(&GET_DEV(accel_dev), "Bank drain successful\n");
488+
489+
return ret;
490+
}
491+
492+
static void bank_state_save(struct adf_hw_csr_ops *ops, void __iomem *base,
493+
u32 bank, struct bank_state *state, u32 num_rings)
494+
{
495+
u32 i;
496+
497+
state->ringstat0 = ops->read_csr_stat(base, bank);
498+
state->ringuostat = ops->read_csr_uo_stat(base, bank);
499+
state->ringestat = ops->read_csr_e_stat(base, bank);
500+
state->ringnestat = ops->read_csr_ne_stat(base, bank);
501+
state->ringnfstat = ops->read_csr_nf_stat(base, bank);
502+
state->ringfstat = ops->read_csr_f_stat(base, bank);
503+
state->ringcstat0 = ops->read_csr_c_stat(base, bank);
504+
state->iaintflagen = ops->read_csr_int_en(base, bank);
505+
state->iaintflagreg = ops->read_csr_int_flag(base, bank);
506+
state->iaintflagsrcsel0 = ops->read_csr_int_srcsel(base, bank);
507+
state->iaintcolen = ops->read_csr_int_col_en(base, bank);
508+
state->iaintcolctl = ops->read_csr_int_col_ctl(base, bank);
509+
state->iaintflagandcolen = ops->read_csr_int_flag_and_col(base, bank);
510+
state->ringexpstat = ops->read_csr_exp_stat(base, bank);
511+
state->ringexpintenable = ops->read_csr_exp_int_en(base, bank);
512+
state->ringsrvarben = ops->read_csr_ring_srv_arb_en(base, bank);
513+
514+
for (i = 0; i < num_rings; i++) {
515+
state->rings[i].head = ops->read_csr_ring_head(base, bank, i);
516+
state->rings[i].tail = ops->read_csr_ring_tail(base, bank, i);
517+
state->rings[i].config = ops->read_csr_ring_config(base, bank, i);
518+
state->rings[i].base = ops->read_csr_ring_base(base, bank, i);
519+
}
520+
}
521+
522+
#define CHECK_STAT(op, expect_val, name, args...) \
523+
({ \
524+
u32 __expect_val = (expect_val); \
525+
u32 actual_val = op(args); \
526+
(__expect_val == actual_val) ? 0 : \
527+
(pr_err("QAT: Fail to restore %s register. Expected 0x%x, actual 0x%x\n", \
528+
name, __expect_val, actual_val), -EINVAL); \
529+
})
530+
531+
static int bank_state_restore(struct adf_hw_csr_ops *ops, void __iomem *base,
532+
u32 bank, struct bank_state *state, u32 num_rings,
533+
int tx_rx_gap)
534+
{
535+
u32 val, tmp_val, i;
536+
int ret;
537+
538+
for (i = 0; i < num_rings; i++)
539+
ops->write_csr_ring_base(base, bank, i, state->rings[i].base);
540+
541+
for (i = 0; i < num_rings; i++)
542+
ops->write_csr_ring_config(base, bank, i, state->rings[i].config);
543+
544+
for (i = 0; i < num_rings / 2; i++) {
545+
int tx = i * (tx_rx_gap + 1);
546+
int rx = tx + tx_rx_gap;
547+
548+
ops->write_csr_ring_head(base, bank, tx, state->rings[tx].head);
549+
ops->write_csr_ring_tail(base, bank, tx, state->rings[tx].tail);
550+
551+
/*
552+
* The TX ring head needs to be updated again to make sure that
553+
* the HW will not consider the ring as full when it is empty
554+
* and the correct state flags are set to match the recovered state.
555+
*/
556+
if (state->ringestat & BIT(tx)) {
557+
val = ops->read_csr_int_srcsel(base, bank);
558+
val |= ADF_RP_INT_SRC_SEL_F_RISE_MASK;
559+
ops->write_csr_int_srcsel_w_val(base, bank, val);
560+
ops->write_csr_ring_head(base, bank, tx, state->rings[tx].head);
561+
}
562+
563+
ops->write_csr_ring_tail(base, bank, rx, state->rings[rx].tail);
564+
val = ops->read_csr_int_srcsel(base, bank);
565+
val |= ADF_RP_INT_SRC_SEL_F_RISE_MASK << ADF_RP_INT_SRC_SEL_RANGE_WIDTH;
566+
ops->write_csr_int_srcsel_w_val(base, bank, val);
567+
568+
ops->write_csr_ring_head(base, bank, rx, state->rings[rx].head);
569+
val = ops->read_csr_int_srcsel(base, bank);
570+
val |= ADF_RP_INT_SRC_SEL_F_FALL_MASK << ADF_RP_INT_SRC_SEL_RANGE_WIDTH;
571+
ops->write_csr_int_srcsel_w_val(base, bank, val);
572+
573+
/*
574+
* The RX ring tail needs to be updated again to make sure that
575+
* the HW will not consider the ring as empty when it is full
576+
* and the correct state flags are set to match the recovered state.
577+
*/
578+
if (state->ringfstat & BIT(rx))
579+
ops->write_csr_ring_tail(base, bank, rx, state->rings[rx].tail);
580+
}
581+
582+
ops->write_csr_int_flag_and_col(base, bank, state->iaintflagandcolen);
583+
ops->write_csr_int_en(base, bank, state->iaintflagen);
584+
ops->write_csr_int_col_en(base, bank, state->iaintcolen);
585+
ops->write_csr_int_srcsel_w_val(base, bank, state->iaintflagsrcsel0);
586+
ops->write_csr_exp_int_en(base, bank, state->ringexpintenable);
587+
ops->write_csr_int_col_ctl(base, bank, state->iaintcolctl);
588+
ops->write_csr_ring_srv_arb_en(base, bank, state->ringsrvarben);
589+
590+
/* Check that all ring statuses match the saved state. */
591+
ret = CHECK_STAT(ops->read_csr_stat, state->ringstat0, "ringstat",
592+
base, bank);
593+
if (ret)
594+
return ret;
595+
596+
ret = CHECK_STAT(ops->read_csr_e_stat, state->ringestat, "ringestat",
597+
base, bank);
598+
if (ret)
599+
return ret;
600+
601+
ret = CHECK_STAT(ops->read_csr_ne_stat, state->ringnestat, "ringnestat",
602+
base, bank);
603+
if (ret)
604+
return ret;
605+
606+
ret = CHECK_STAT(ops->read_csr_nf_stat, state->ringnfstat, "ringnfstat",
607+
base, bank);
608+
if (ret)
609+
return ret;
610+
611+
ret = CHECK_STAT(ops->read_csr_f_stat, state->ringfstat, "ringfstat",
612+
base, bank);
613+
if (ret)
614+
return ret;
615+
616+
ret = CHECK_STAT(ops->read_csr_c_stat, state->ringcstat0, "ringcstat",
617+
base, bank);
618+
if (ret)
619+
return ret;
620+
621+
tmp_val = ops->read_csr_exp_stat(base, bank);
622+
val = state->ringexpstat;
623+
if (tmp_val && !val) {
624+
pr_err("QAT: Bank was restored with exception: 0x%x\n", val);
625+
return -EINVAL;
626+
}
627+
628+
return 0;
629+
}
630+
631+
int adf_gen4_bank_state_save(struct adf_accel_dev *accel_dev, u32 bank_number,
632+
struct bank_state *state)
633+
{
634+
struct adf_hw_device_data *hw_data = GET_HW_DATA(accel_dev);
635+
struct adf_hw_csr_ops *csr_ops = GET_CSR_OPS(accel_dev);
636+
void __iomem *csr_base = adf_get_etr_base(accel_dev);
637+
638+
if (bank_number >= hw_data->num_banks || !state)
639+
return -EINVAL;
640+
641+
dev_dbg(&GET_DEV(accel_dev), "Saving state of bank %d\n", bank_number);
642+
643+
bank_state_save(csr_ops, csr_base, bank_number, state,
644+
hw_data->num_rings_per_bank);
645+
646+
return 0;
647+
}
648+
EXPORT_SYMBOL_GPL(adf_gen4_bank_state_save);
649+
650+
int adf_gen4_bank_state_restore(struct adf_accel_dev *accel_dev, u32 bank_number,
651+
struct bank_state *state)
652+
{
653+
struct adf_hw_device_data *hw_data = GET_HW_DATA(accel_dev);
654+
struct adf_hw_csr_ops *csr_ops = GET_CSR_OPS(accel_dev);
655+
void __iomem *csr_base = adf_get_etr_base(accel_dev);
656+
int ret;
657+
658+
if (bank_number >= hw_data->num_banks || !state)
659+
return -EINVAL;
660+
661+
dev_dbg(&GET_DEV(accel_dev), "Restoring state of bank %d\n", bank_number);
662+
663+
ret = bank_state_restore(csr_ops, csr_base, bank_number, state,
664+
hw_data->num_rings_per_bank, hw_data->tx_rx_gap);
665+
if (ret)
666+
dev_err(&GET_DEV(accel_dev),
667+
"Unable to restore state of bank %d\n", bank_number);
668+
669+
return ret;
670+
}
671+
EXPORT_SYMBOL_GPL(adf_gen4_bank_state_restore);

drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,19 @@
7777
#define ADF_RPRESET_POLL_TIMEOUT_US (5 * USEC_PER_SEC)
7878
#define ADF_RPRESET_POLL_DELAY_US 20
7979
#define ADF_WQM_CSR_RPRESETCTL_RESET BIT(0)
80+
#define ADF_WQM_CSR_RPRESETCTL_DRAIN BIT(2)
8081
#define ADF_WQM_CSR_RPRESETCTL(bank) (0x6000 + ((bank) << 3))
8182
#define ADF_WQM_CSR_RPRESETSTS_STATUS BIT(0)
8283
#define ADF_WQM_CSR_RPRESETSTS(bank) (ADF_WQM_CSR_RPRESETCTL(bank) + 4)
8384

85+
/* Ring interrupt */
86+
#define ADF_RP_INT_SRC_SEL_F_RISE_MASK BIT(2)
87+
#define ADF_RP_INT_SRC_SEL_F_FALL_MASK GENMASK(2, 0)
88+
#define ADF_RP_INT_SRC_SEL_RANGE_WIDTH 4
89+
#define ADF_COALESCED_POLL_DELAY_US 1000
90+
#define ADF_WQM_CSR_RPINTSOU(bank) (0x200000 + ((bank) << 12))
91+
#define ADF_WQM_CSR_RP_IDX_RX 1
92+
8493
/* Error source registers */
8594
#define ADF_GEN4_ERRSOU0 (0x41A200)
8695
#define ADF_GEN4_ERRSOU1 (0x41A204)
@@ -150,5 +159,15 @@ void adf_gen4_set_msix_default_rttable(struct adf_accel_dev *accel_dev);
150159
void adf_gen4_set_ssm_wdtimer(struct adf_accel_dev *accel_dev);
151160
int adf_gen4_init_thd2arb_map(struct adf_accel_dev *accel_dev);
152161
u16 adf_gen4_get_ring_to_svc_map(struct adf_accel_dev *accel_dev);
162+
int adf_gen4_bank_quiesce_coal_timer(struct adf_accel_dev *accel_dev,
163+
u32 bank_idx, int timeout_ms);
164+
int adf_gen4_bank_drain_start(struct adf_accel_dev *accel_dev,
165+
u32 bank_number, int timeout_us);
166+
void adf_gen4_bank_drain_finish(struct adf_accel_dev *accel_dev,
167+
u32 bank_number);
168+
int adf_gen4_bank_state_save(struct adf_accel_dev *accel_dev, u32 bank_number,
169+
struct bank_state *state);
170+
int adf_gen4_bank_state_restore(struct adf_accel_dev *accel_dev,
171+
u32 bank_number, struct bank_state *state);
153172

154173
#endif

0 commit comments

Comments
 (0)