2024-01-27 13:16:20

by Weili Qian

[permalink] [raw]
Subject: [PATCH 0/3] crypto: hisilicon/qm - add stop function and obtain queue status

Patch #1 supports stopping function by sending mailbox to device,
device directly flush out function data.
Patch #2 supports users to obtain the queue stopping result by
querying the debug file.
Patch #3 changes function type.

Weili Qian (3):
crypto: hisilicon/qm - add stop function by hardware
crypto: hisilicon/qm - obtain stop queue status
crypto: hisilicon/qm - change function type to void

Documentation/ABI/testing/debugfs-hisi-hpre | 15 ++
Documentation/ABI/testing/debugfs-hisi-sec | 15 ++
Documentation/ABI/testing/debugfs-hisi-zip | 15 ++
drivers/crypto/hisilicon/debugfs.c | 5 +
drivers/crypto/hisilicon/qm.c | 171 +++++++++++++-------
include/linux/hisi_acc_qm.h | 18 ++-
6 files changed, 179 insertions(+), 60 deletions(-)

--
2.33.0



2024-01-27 13:16:26

by Weili Qian

[permalink] [raw]
Subject: [PATCH 1/3] crypto: hisilicon/qm - add stop function by hardware

Hardware V3 could be able to drain function by sending mailbox
to hardware which will trigger tasks in device to be flushed out.
When the function is reset, the function can be stopped by this way.

Signed-off-by: Weili Qian <[email protected]>
---
drivers/crypto/hisilicon/qm.c | 40 ++++++++++++++++++++++++++++-------
include/linux/hisi_acc_qm.h | 2 ++
2 files changed, 34 insertions(+), 8 deletions(-)

diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c
index 4b20b94e6371..3b015482b4e6 100644
--- a/drivers/crypto/hisilicon/qm.c
+++ b/drivers/crypto/hisilicon/qm.c
@@ -312,6 +312,7 @@ static const struct hisi_qm_cap_info qm_cap_info_comm[] = {
{QM_SUPPORT_DB_ISOLATION, 0x30, 0, BIT(0), 0x0, 0x0, 0x0},
{QM_SUPPORT_FUNC_QOS, 0x3100, 0, BIT(8), 0x0, 0x0, 0x1},
{QM_SUPPORT_STOP_QP, 0x3100, 0, BIT(9), 0x0, 0x0, 0x1},
+ {QM_SUPPORT_STOP_FUNC, 0x3100, 0, BIT(10), 0x0, 0x0, 0x1},
{QM_SUPPORT_MB_COMMAND, 0x3100, 0, BIT(11), 0x0, 0x0, 0x1},
{QM_SUPPORT_SVA_PREFETCH, 0x3100, 0, BIT(14), 0x0, 0x0, 0x1},
};
@@ -1674,6 +1675,11 @@ static int qm_ping_pf(struct hisi_qm *qm, u64 cmd)
return ret;
}

+static int qm_drain_qm(struct hisi_qm *qm)
+{
+ return hisi_qm_mb(qm, QM_MB_CMD_FLUSH_QM, 0, 0, 0);
+}
+
static int qm_stop_qp(struct hisi_qp *qp)
{
return hisi_qm_mb(qp->qm, QM_MB_CMD_STOP_QP, 0, qp->qp_id, 0);
@@ -2088,7 +2094,8 @@ static int qm_drain_qp(struct hisi_qp *qp)

static int qm_stop_qp_nolock(struct hisi_qp *qp)
{
- struct device *dev = &qp->qm->pdev->dev;
+ struct hisi_qm *qm = qp->qm;
+ struct device *dev = &qm->pdev->dev;
int ret;

/*
@@ -2104,11 +2111,14 @@ static int qm_stop_qp_nolock(struct hisi_qp *qp)

atomic_set(&qp->qp_status.flags, QP_STOP);

- ret = qm_drain_qp(qp);
- if (ret)
- dev_err(dev, "Failed to drain out data for stopping!\n");
+ /* V3 supports direct stop function when FLR prepare */
+ if (qm->ver < QM_HW_V3 || qm->status.stop_reason == QM_NORMAL) {
+ ret = qm_drain_qp(qp);
+ if (ret)
+ dev_err(dev, "Failed to drain out data for stopping qp(%u)!\n", qp->qp_id);
+ }

- flush_workqueue(qp->qm->wq);
+ flush_workqueue(qm->wq);
if (unlikely(qp->is_resetting && atomic_read(&qp->qp_status.used)))
qp_stop_fail_cb(qp);

@@ -3112,16 +3122,29 @@ int hisi_qm_stop(struct hisi_qm *qm, enum qm_stop_reason r)

down_write(&qm->qps_lock);

- qm->status.stop_reason = r;
if (atomic_read(&qm->status.flags) == QM_STOP)
goto err_unlock;

/* Stop all the request sending at first. */
atomic_set(&qm->status.flags, QM_STOP);
+ qm->status.stop_reason = r;

- if (qm->status.stop_reason == QM_SOFT_RESET ||
- qm->status.stop_reason == QM_DOWN) {
+ if (qm->status.stop_reason != QM_NORMAL) {
hisi_qm_set_hw_reset(qm, QM_RESET_STOP_TX_OFFSET);
+ /*
+ * When performing soft reset, the hardware will no longer
+ * do tasks, and the tasks in the device will be flushed
+ * out directly since the master ooo is closed.
+ */
+ if (test_bit(QM_SUPPORT_STOP_FUNC, &qm->caps) &&
+ r != QM_SOFT_RESET) {
+ ret = qm_drain_qm(qm);
+ if (ret) {
+ dev_err(dev, "failed to drain qm!\n");
+ goto err_unlock;
+ }
+ }
+
ret = qm_stop_started_qp(qm);
if (ret < 0) {
dev_err(dev, "Failed to stop started qp!\n");
@@ -3141,6 +3164,7 @@ int hisi_qm_stop(struct hisi_qm *qm, enum qm_stop_reason r)
}

qm_clear_queues(qm);
+ qm->status.stop_reason = QM_NORMAL;

err_unlock:
up_write(&qm->qps_lock);
diff --git a/include/linux/hisi_acc_qm.h b/include/linux/hisi_acc_qm.h
index 5f4c74facf6a..720f10874a66 100644
--- a/include/linux/hisi_acc_qm.h
+++ b/include/linux/hisi_acc_qm.h
@@ -43,6 +43,7 @@
#define QM_MB_CMD_CQC_BT 0x5
#define QM_MB_CMD_SQC_VFT_V2 0x6
#define QM_MB_CMD_STOP_QP 0x8
+#define QM_MB_CMD_FLUSH_QM 0x9
#define QM_MB_CMD_SRC 0xc
#define QM_MB_CMD_DST 0xd

@@ -151,6 +152,7 @@ enum qm_cap_bits {
QM_SUPPORT_DB_ISOLATION = 0x0,
QM_SUPPORT_FUNC_QOS,
QM_SUPPORT_STOP_QP,
+ QM_SUPPORT_STOP_FUNC,
QM_SUPPORT_MB_COMMAND,
QM_SUPPORT_SVA_PREFETCH,
QM_SUPPORT_RPM,
--
2.33.0


2024-01-27 13:16:28

by Weili Qian

[permalink] [raw]
Subject: [PATCH 3/3] crypto: hisilicon/qm - change function type to void

The function hisi_qm_stop_qp() always returns zero, and no caller
checks the return value. So this function type is changed to void.

Signed-off-by: Weili Qian <[email protected]>
---
drivers/crypto/hisilicon/qm.c | 36 ++++++++++-------------------------
include/linux/hisi_acc_qm.h | 2 +-
2 files changed, 11 insertions(+), 27 deletions(-)

diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c
index 75d0b2ea117e..d1fe2de0faa7 100644
--- a/drivers/crypto/hisilicon/qm.c
+++ b/drivers/crypto/hisilicon/qm.c
@@ -2118,7 +2118,7 @@ static int qm_drain_qp(struct hisi_qp *qp)
return ret;
}

-static int qm_stop_qp_nolock(struct hisi_qp *qp)
+static void qm_stop_qp_nolock(struct hisi_qp *qp)
{
struct hisi_qm *qm = qp->qm;
struct device *dev = &qm->pdev->dev;
@@ -2132,7 +2132,7 @@ static int qm_stop_qp_nolock(struct hisi_qp *qp)
*/
if (atomic_read(&qp->qp_status.flags) != QP_START) {
qp->is_resetting = false;
- return 0;
+ return;
}

atomic_set(&qp->qp_status.flags, QP_STOP);
@@ -2149,8 +2149,6 @@ static int qm_stop_qp_nolock(struct hisi_qp *qp)
qp_stop_fail_cb(qp);

dev_dbg(dev, "stop queue %u!", qp->qp_id);
-
- return 0;
}

/**
@@ -2159,15 +2157,11 @@ static int qm_stop_qp_nolock(struct hisi_qp *qp)
*
* This function is reverse of hisi_qm_start_qp. Return 0 if successful.
*/
-int hisi_qm_stop_qp(struct hisi_qp *qp)
+void hisi_qm_stop_qp(struct hisi_qp *qp)
{
- int ret;
-
down_write(&qp->qm->qps_lock);
- ret = qm_stop_qp_nolock(qp);
+ qm_stop_qp_nolock(qp);
up_write(&qp->qm->qps_lock);
-
- return ret;
}
EXPORT_SYMBOL_GPL(hisi_qm_stop_qp);

@@ -3109,25 +3103,18 @@ static int qm_restart(struct hisi_qm *qm)
}

/* Stop started qps in reset flow */
-static int qm_stop_started_qp(struct hisi_qm *qm)
+static void qm_stop_started_qp(struct hisi_qm *qm)
{
- struct device *dev = &qm->pdev->dev;
struct hisi_qp *qp;
- int i, ret;
+ int i;

for (i = 0; i < qm->qp_num; i++) {
qp = &qm->qp_array[i];
- if (qp && atomic_read(&qp->qp_status.flags) == QP_START) {
+ if (atomic_read(&qp->qp_status.flags) == QP_START) {
qp->is_resetting = true;
- ret = qm_stop_qp_nolock(qp);
- if (ret < 0) {
- dev_err(dev, "Failed to stop qp%d!\n", i);
- return ret;
- }
+ qm_stop_qp_nolock(qp);
}
}
-
- return 0;
}

/**
@@ -3190,11 +3177,8 @@ int hisi_qm_stop(struct hisi_qm *qm, enum qm_stop_reason r)
}
}

- ret = qm_stop_started_qp(qm);
- if (ret < 0) {
- dev_err(dev, "Failed to stop started qp!\n");
- goto err_unlock;
- }
+ qm_stop_started_qp(qm);
+
hisi_qm_set_hw_reset(qm, QM_RESET_STOP_RX_OFFSET);
}

diff --git a/include/linux/hisi_acc_qm.h b/include/linux/hisi_acc_qm.h
index ec5a70ade511..3c755626ca54 100644
--- a/include/linux/hisi_acc_qm.h
+++ b/include/linux/hisi_acc_qm.h
@@ -539,7 +539,7 @@ void hisi_qm_uninit(struct hisi_qm *qm);
int hisi_qm_start(struct hisi_qm *qm);
int hisi_qm_stop(struct hisi_qm *qm, enum qm_stop_reason r);
int hisi_qm_start_qp(struct hisi_qp *qp, unsigned long arg);
-int hisi_qm_stop_qp(struct hisi_qp *qp);
+void hisi_qm_stop_qp(struct hisi_qp *qp);
int hisi_qp_send(struct hisi_qp *qp, const void *msg);
void hisi_qm_debug_init(struct hisi_qm *qm);
void hisi_qm_debug_regs_clear(struct hisi_qm *qm);
--
2.33.0


2024-01-27 13:16:43

by Weili Qian

[permalink] [raw]
Subject: [PATCH 2/3] crypto: hisilicon/qm - obtain stop queue status

The debugfs files 'dev_state' and 'dev_timeout' are added.
Users can query the current queue stop status through these two
files. And set the waiting timeout when the queue is released.

dev_state: if dev_timeout is set, dev_state indicates the status
of stopping the queue. 0 indicates that the queue is stopped
successfully. Other values indicate that the queue stops fail.
if dev_timeout is not set, the value of dev_state is 0;

dev_timeout: If the queue fails to stop, the queue is released
after waiting dev_timeout * 20ms.

Signed-off-by: Weili Qian <[email protected]>
---
Documentation/ABI/testing/debugfs-hisi-hpre | 15 ++++
Documentation/ABI/testing/debugfs-hisi-sec | 15 ++++
Documentation/ABI/testing/debugfs-hisi-zip | 15 ++++
drivers/crypto/hisilicon/debugfs.c | 5 ++
drivers/crypto/hisilicon/qm.c | 97 +++++++++++++++------
include/linux/hisi_acc_qm.h | 14 +++
6 files changed, 135 insertions(+), 26 deletions(-)

diff --git a/Documentation/ABI/testing/debugfs-hisi-hpre b/Documentation/ABI/testing/debugfs-hisi-hpre
index 6ed9258605c7..e6394a2fb371 100644
--- a/Documentation/ABI/testing/debugfs-hisi-hpre
+++ b/Documentation/ABI/testing/debugfs-hisi-hpre
@@ -118,6 +118,21 @@ Description: Dump the state of the device.
0: busy, 1: idle.
Only available for PF, and take no other effect on HPRE.

+What: /sys/kernel/debug/hisi_hpre/<bdf>/qm/dev_timeout
+Date: Jan 2024
+Contact: [email protected]
+Description: Set the wait time when stop queue fails. Available for both PF
+ and VF, and take no other effect on HPRE.
+ 0: not wait(default), others value: wait dev_timeout * 20 microsecond.
+
+What: /sys/kernel/debug/hisi_hpre/<bdf>/qm/dev_state
+Date: Jan 2024
+Contact: [email protected]
+Description: Dump the stop queue status of the QM. The default value is 0,
+ if dev_timeout is set, when stop queue fails, the dev_state
+ will return non-zero value. Available for both PF and VF,
+ and take no other effect on HPRE.
+
What: /sys/kernel/debug/hisi_hpre/<bdf>/hpre_dfx/diff_regs
Date: Mar 2022
Contact: [email protected]
diff --git a/Documentation/ABI/testing/debugfs-hisi-sec b/Documentation/ABI/testing/debugfs-hisi-sec
index 403f5de96318..2b5db193b5e6 100644
--- a/Documentation/ABI/testing/debugfs-hisi-sec
+++ b/Documentation/ABI/testing/debugfs-hisi-sec
@@ -98,6 +98,21 @@ Description: Dump the state of the device.
0: busy, 1: idle.
Only available for PF, and take no other effect on SEC.

+What: /sys/kernel/debug/hisi_sec2/<bdf>/qm/dev_timeout
+Date: Jan 2024
+Contact: [email protected]
+Description: Set the wait time when stop queue fails. Available for both PF
+ and VF, and take no other effect on SEC.
+ 0: not wait(default), others value: wait dev_timeout * 20 microsecond.
+
+What: /sys/kernel/debug/hisi_sec2/<bdf>/qm/dev_state
+Date: Jan 2024
+Contact: [email protected]
+Description: Dump the stop queue status of the QM. The default value is 0,
+ if dev_timeout is set, when stop queue fails, the dev_state
+ will return non-zero value. Available for both PF and VF,
+ and take no other effect on SEC.
+
What: /sys/kernel/debug/hisi_sec2/<bdf>/sec_dfx/diff_regs
Date: Mar 2022
Contact: [email protected]
diff --git a/Documentation/ABI/testing/debugfs-hisi-zip b/Documentation/ABI/testing/debugfs-hisi-zip
index 2394e6a3cfe2..260c514e0e9e 100644
--- a/Documentation/ABI/testing/debugfs-hisi-zip
+++ b/Documentation/ABI/testing/debugfs-hisi-zip
@@ -111,6 +111,21 @@ Description: Dump the state of the device.
0: busy, 1: idle.
Only available for PF, and take no other effect on ZIP.

+What: /sys/kernel/debug/hisi_zip/<bdf>/qm/dev_timeout
+Date: Jan 2024
+Contact: [email protected]
+Description: Set the wait time when stop queue fails. Available for both PF
+ and VF, and take no other effect on ZIP.
+ 0: not wait(default), others value: wait dev_timeout * 20 microsecond.
+
+What: /sys/kernel/debug/hisi_zip/<bdf>/qm/dev_state
+Date: Jan 2024
+Contact: [email protected]
+Description: Dump the stop queue status of the QM. The default value is 0,
+ if dev_timeout is set, when stop queue fails, the dev_state
+ will return non-zero value. Available for both PF and VF,
+ and take no other effect on ZIP.
+
What: /sys/kernel/debug/hisi_zip/<bdf>/zip_dfx/diff_regs
Date: Mar 2022
Contact: [email protected]
diff --git a/drivers/crypto/hisilicon/debugfs.c b/drivers/crypto/hisilicon/debugfs.c
index 06e67eda409f..cd67fa348ca7 100644
--- a/drivers/crypto/hisilicon/debugfs.c
+++ b/drivers/crypto/hisilicon/debugfs.c
@@ -1112,6 +1112,7 @@ DEFINE_DEBUGFS_ATTRIBUTE(qm_atomic64_ops, qm_debugfs_atomic64_get,
void hisi_qm_debug_init(struct hisi_qm *qm)
{
struct dfx_diff_registers *qm_regs = qm->debug.qm_diff_regs;
+ struct qm_dev_dfx *dev_dfx = &qm->debug.dev_dfx;
struct qm_dfx *dfx = &qm->debug.dfx;
struct dentry *qm_d;
void *data;
@@ -1140,6 +1141,10 @@ void hisi_qm_debug_init(struct hisi_qm *qm)

debugfs_create_file("status", 0444, qm->debug.qm_d, qm,
&qm_status_fops);
+
+ debugfs_create_u32("dev_state", 0444, qm->debug.qm_d, &dev_dfx->dev_state);
+ debugfs_create_u32("dev_timeout", 0644, qm->debug.qm_d, &dev_dfx->dev_timeout);
+
for (i = 0; i < ARRAY_SIZE(qm_dfx_files); i++) {
data = (atomic64_t *)((uintptr_t)dfx + qm_dfx_files[i].offset);
debugfs_create_file(qm_dfx_files[i].name,
diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c
index 3b015482b4e6..75d0b2ea117e 100644
--- a/drivers/crypto/hisilicon/qm.c
+++ b/drivers/crypto/hisilicon/qm.c
@@ -2037,43 +2037,25 @@ static void qp_stop_fail_cb(struct hisi_qp *qp)
}
}

-/**
- * qm_drain_qp() - Drain a qp.
- * @qp: The qp we want to drain.
- *
- * Determine whether the queue is cleared by judging the tail pointers of
- * sq and cq.
- */
-static int qm_drain_qp(struct hisi_qp *qp)
+static int qm_wait_qp_empty(struct hisi_qm *qm, u32 *state, u32 qp_id)
{
- struct hisi_qm *qm = qp->qm;
struct device *dev = &qm->pdev->dev;
struct qm_sqc sqc;
struct qm_cqc cqc;
int ret, i = 0;

- /* No need to judge if master OOO is blocked. */
- if (qm_check_dev_error(qm))
- return 0;
-
- /* Kunpeng930 supports drain qp by device */
- if (test_bit(QM_SUPPORT_STOP_QP, &qm->caps)) {
- ret = qm_stop_qp(qp);
- if (ret)
- dev_err(dev, "Failed to stop qp(%u)!\n", qp->qp_id);
- return ret;
- }
-
while (++i) {
- ret = qm_set_and_get_xqc(qm, QM_MB_CMD_SQC, &sqc, qp->qp_id, 1);
+ ret = qm_set_and_get_xqc(qm, QM_MB_CMD_SQC, &sqc, qp_id, 1);
if (ret) {
dev_err_ratelimited(dev, "Failed to dump sqc!\n");
+ *state = DUMP_SQC_FAIL;
return ret;
}

- ret = qm_set_and_get_xqc(qm, QM_MB_CMD_CQC, &cqc, qp->qp_id, 1);
+ ret = qm_set_and_get_xqc(qm, QM_MB_CMD_CQC, &cqc, qp_id, 1);
if (ret) {
dev_err_ratelimited(dev, "Failed to dump cqc!\n");
+ *state = DUMP_CQC_FAIL;
return ret;
}

@@ -2082,8 +2064,9 @@ static int qm_drain_qp(struct hisi_qp *qp)
break;

if (i == MAX_WAIT_COUNTS) {
- dev_err(dev, "Fail to empty queue %u!\n", qp->qp_id);
- return -EBUSY;
+ dev_err(dev, "Fail to empty queue %u!\n", qp_id);
+ *state = STOP_QUEUE_FAIL;
+ return -ETIMEDOUT;
}

usleep_range(WAIT_PERIOD_US_MIN, WAIT_PERIOD_US_MAX);
@@ -2092,6 +2075,49 @@ static int qm_drain_qp(struct hisi_qp *qp)
return 0;
}

+/**
+ * qm_drain_qp() - Drain a qp.
+ * @qp: The qp we want to drain.
+ *
+ * If the device does not support stopping queue by sending mailbox,
+ * determine whether the queue is cleared by judging the tail pointers of
+ * sq and cq.
+ */
+static int qm_drain_qp(struct hisi_qp *qp)
+{
+ struct hisi_qm *qm = qp->qm;
+ struct hisi_qm *pf_qm = pci_get_drvdata(pci_physfn(qm->pdev));
+ u32 state = 0;
+ int ret;
+
+ /* No need to judge if master OOO is blocked. */
+ if (qm_check_dev_error(pf_qm))
+ return 0;
+
+ /* HW V3 supports drain qp by device */
+ if (test_bit(QM_SUPPORT_STOP_QP, &qm->caps)) {
+ ret = qm_stop_qp(qp);
+ if (ret) {
+ dev_err(&qm->pdev->dev, "Failed to stop qp!\n");
+ state = STOP_QUEUE_FAIL;
+ goto set_dev_state;
+ }
+ return ret;
+ }
+
+ ret = qm_wait_qp_empty(qm, &state, qp->qp_id);
+ if (ret)
+ goto set_dev_state;
+
+ return 0;
+
+set_dev_state:
+ if (qm->debug.dev_dfx.dev_timeout)
+ qm->debug.dev_dfx.dev_state = state;
+
+ return ret;
+}
+
static int qm_stop_qp_nolock(struct hisi_qp *qp)
{
struct hisi_qm *qm = qp->qm;
@@ -2319,7 +2345,26 @@ static int hisi_qm_uacce_start_queue(struct uacce_queue *q)

static void hisi_qm_uacce_stop_queue(struct uacce_queue *q)
{
- hisi_qm_stop_qp(q->priv);
+ struct hisi_qp *qp = q->priv;
+ struct hisi_qm *qm = qp->qm;
+ struct qm_dev_dfx *dev_dfx = &qm->debug.dev_dfx;
+ u32 i = 0;
+
+ hisi_qm_stop_qp(qp);
+
+ if (!dev_dfx->dev_timeout || !dev_dfx->dev_state)
+ return;
+
+ while (++i) {
+ if (!i || i > dev_dfx->dev_timeout) {
+ dev_err(&qm->pdev->dev, "Stop q %u timeout, state %u\n",
+ qp->qp_id, dev_dfx->dev_state);
+ dev_dfx->dev_state = FINISH_WAIT;
+ break;
+ }
+
+ msleep(WAIT_PERIOD);
+ }
}

static int hisi_qm_is_q_updated(struct uacce_queue *q)
diff --git a/include/linux/hisi_acc_qm.h b/include/linux/hisi_acc_qm.h
index 720f10874a66..ec5a70ade511 100644
--- a/include/linux/hisi_acc_qm.h
+++ b/include/linux/hisi_acc_qm.h
@@ -158,6 +158,19 @@ enum qm_cap_bits {
QM_SUPPORT_RPM,
};

+enum qm_dev_fail_state {
+ STOP_QUEUE_FAIL = 1,
+ ALLOC_CTX_FAIL,
+ DUMP_SQC_FAIL,
+ DUMP_CQC_FAIL,
+ FINISH_WAIT,
+};
+
+struct qm_dev_dfx {
+ u32 dev_state;
+ u32 dev_timeout;
+};
+
struct qm_dev_alg {
u64 alg_msk;
const char *alg;
@@ -191,6 +204,7 @@ struct qm_debug {
struct dentry *debug_root;
struct dentry *qm_d;
struct debugfs_file files[DEBUG_FILE_NUM];
+ struct qm_dev_dfx dev_dfx;
unsigned int *qm_last_words;
/* ACC engines recoreding last regs */
unsigned int *last_words;
--
2.33.0


2024-01-29 02:40:59

by liulongfang

[permalink] [raw]
Subject: Re: [PATCH 2/3] crypto: hisilicon/qm - obtain stop queue status

On 2024/1/27 21:15, Weili Qian wrote:
> The debugfs files 'dev_state' and 'dev_timeout' are added.
> Users can query the current queue stop status through these two
> files. And set the waiting timeout when the queue is released.
>
> dev_state: if dev_timeout is set, dev_state indicates the status
> of stopping the queue. 0 indicates that the queue is stopped
> successfully. Other values indicate that the queue stops fail.
> if dev_timeout is not set, the value of dev_state is 0;
>
> dev_timeout: If the queue fails to stop, the queue is released
> after waiting dev_timeout * 20ms.
>
> Signed-off-by: Weili Qian <[email protected]>
> ---
> Documentation/ABI/testing/debugfs-hisi-hpre | 15 ++++
> Documentation/ABI/testing/debugfs-hisi-sec | 15 ++++
> Documentation/ABI/testing/debugfs-hisi-zip | 15 ++++
> drivers/crypto/hisilicon/debugfs.c | 5 ++
> drivers/crypto/hisilicon/qm.c | 97 +++++++++++++++------
> include/linux/hisi_acc_qm.h | 14 +++
> 6 files changed, 135 insertions(+), 26 deletions(-)
>
> diff --git a/Documentation/ABI/testing/debugfs-hisi-hpre b/Documentation/ABI/testing/debugfs-hisi-hpre
> index 6ed9258605c7..e6394a2fb371 100644
> --- a/Documentation/ABI/testing/debugfs-hisi-hpre
> +++ b/Documentation/ABI/testing/debugfs-hisi-hpre
> @@ -118,6 +118,21 @@ Description: Dump the state of the device.
> 0: busy, 1: idle.
> Only available for PF, and take no other effect on HPRE.
>
> +What: /sys/kernel/debug/hisi_hpre/<bdf>/qm/dev_timeout
> +Date: Jan 2024
> +Contact: [email protected]
> +Description: Set the wait time when stop queue fails. Available for both PF
> + and VF, and take no other effect on HPRE.
> + 0: not wait(default), others value: wait dev_timeout * 20 microsecond.
> +
> +What: /sys/kernel/debug/hisi_hpre/<bdf>/qm/dev_state
> +Date: Jan 2024
> +Contact: [email protected]
> +Description: Dump the stop queue status of the QM. The default value is 0,
> + if dev_timeout is set, when stop queue fails, the dev_state
> + will return non-zero value. Available for both PF and VF,
> + and take no other effect on HPRE.
> +
> What: /sys/kernel/debug/hisi_hpre/<bdf>/hpre_dfx/diff_regs
> Date: Mar 2022
> Contact: [email protected]
> diff --git a/Documentation/ABI/testing/debugfs-hisi-sec b/Documentation/ABI/testing/debugfs-hisi-sec
> index 403f5de96318..2b5db193b5e6 100644
> --- a/Documentation/ABI/testing/debugfs-hisi-sec
> +++ b/Documentation/ABI/testing/debugfs-hisi-sec
> @@ -98,6 +98,21 @@ Description: Dump the state of the device.
> 0: busy, 1: idle.
> Only available for PF, and take no other effect on SEC.
>
> +What: /sys/kernel/debug/hisi_sec2/<bdf>/qm/dev_timeout
> +Date: Jan 2024
> +Contact: [email protected]
> +Description: Set the wait time when stop queue fails. Available for both PF
> + and VF, and take no other effect on SEC.
> + 0: not wait(default), others value: wait dev_timeout * 20 microsecond.
> +
> +What: /sys/kernel/debug/hisi_sec2/<bdf>/qm/dev_state
> +Date: Jan 2024
> +Contact: [email protected]
> +Description: Dump the stop queue status of the QM. The default value is 0,
> + if dev_timeout is set, when stop queue fails, the dev_state
> + will return non-zero value. Available for both PF and VF,
> + and take no other effect on SEC.
> +
> What: /sys/kernel/debug/hisi_sec2/<bdf>/sec_dfx/diff_regs
> Date: Mar 2022
> Contact: [email protected]
> diff --git a/Documentation/ABI/testing/debugfs-hisi-zip b/Documentation/ABI/testing/debugfs-hisi-zip
> index 2394e6a3cfe2..260c514e0e9e 100644
> --- a/Documentation/ABI/testing/debugfs-hisi-zip
> +++ b/Documentation/ABI/testing/debugfs-hisi-zip
> @@ -111,6 +111,21 @@ Description: Dump the state of the device.
> 0: busy, 1: idle.
> Only available for PF, and take no other effect on ZIP.
>
> +What: /sys/kernel/debug/hisi_zip/<bdf>/qm/dev_timeout
> +Date: Jan 2024
> +Contact: [email protected]
> +Description: Set the wait time when stop queue fails. Available for both PF
> + and VF, and take no other effect on ZIP.
> + 0: not wait(default), others value: wait dev_timeout * 20 microsecond.
> +
> +What: /sys/kernel/debug/hisi_zip/<bdf>/qm/dev_state
> +Date: Jan 2024
> +Contact: [email protected]
> +Description: Dump the stop queue status of the QM. The default value is 0,
> + if dev_timeout is set, when stop queue fails, the dev_state
> + will return non-zero value. Available for both PF and VF,
> + and take no other effect on ZIP.
> +
> What: /sys/kernel/debug/hisi_zip/<bdf>/zip_dfx/diff_regs
> Date: Mar 2022
> Contact: [email protected]
> diff --git a/drivers/crypto/hisilicon/debugfs.c b/drivers/crypto/hisilicon/debugfs.c
> index 06e67eda409f..cd67fa348ca7 100644
> --- a/drivers/crypto/hisilicon/debugfs.c
> +++ b/drivers/crypto/hisilicon/debugfs.c
> @@ -1112,6 +1112,7 @@ DEFINE_DEBUGFS_ATTRIBUTE(qm_atomic64_ops, qm_debugfs_atomic64_get,
> void hisi_qm_debug_init(struct hisi_qm *qm)
> {
> struct dfx_diff_registers *qm_regs = qm->debug.qm_diff_regs;
> + struct qm_dev_dfx *dev_dfx = &qm->debug.dev_dfx;
> struct qm_dfx *dfx = &qm->debug.dfx;
> struct dentry *qm_d;
> void *data;
> @@ -1140,6 +1141,10 @@ void hisi_qm_debug_init(struct hisi_qm *qm)
>
> debugfs_create_file("status", 0444, qm->debug.qm_d, qm,
> &qm_status_fops);
> +
> + debugfs_create_u32("dev_state", 0444, qm->debug.qm_d, &dev_dfx->dev_state);
> + debugfs_create_u32("dev_timeout", 0644, qm->debug.qm_d, &dev_dfx->dev_timeout);
> +
> for (i = 0; i < ARRAY_SIZE(qm_dfx_files); i++) {
> data = (atomic64_t *)((uintptr_t)dfx + qm_dfx_files[i].offset);
> debugfs_create_file(qm_dfx_files[i].name,
> diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c
> index 3b015482b4e6..75d0b2ea117e 100644
> --- a/drivers/crypto/hisilicon/qm.c
> +++ b/drivers/crypto/hisilicon/qm.c
> @@ -2037,43 +2037,25 @@ static void qp_stop_fail_cb(struct hisi_qp *qp)
> }
> }
>
> -/**
> - * qm_drain_qp() - Drain a qp.
> - * @qp: The qp we want to drain.
> - *
> - * Determine whether the queue is cleared by judging the tail pointers of
> - * sq and cq.
> - */
> -static int qm_drain_qp(struct hisi_qp *qp)
> +static int qm_wait_qp_empty(struct hisi_qm *qm, u32 *state, u32 qp_id)
> {
> - struct hisi_qm *qm = qp->qm;
> struct device *dev = &qm->pdev->dev;
> struct qm_sqc sqc;
> struct qm_cqc cqc;
> int ret, i = 0;
>
> - /* No need to judge if master OOO is blocked. */
> - if (qm_check_dev_error(qm))
> - return 0;
> -
> - /* Kunpeng930 supports drain qp by device */
> - if (test_bit(QM_SUPPORT_STOP_QP, &qm->caps)) {
> - ret = qm_stop_qp(qp);
> - if (ret)
> - dev_err(dev, "Failed to stop qp(%u)!\n", qp->qp_id);
> - return ret;
> - }
> -
> while (++i) {
> - ret = qm_set_and_get_xqc(qm, QM_MB_CMD_SQC, &sqc, qp->qp_id, 1);
> + ret = qm_set_and_get_xqc(qm, QM_MB_CMD_SQC, &sqc, qp_id, 1);
> if (ret) {
> dev_err_ratelimited(dev, "Failed to dump sqc!\n");
> + *state = DUMP_SQC_FAIL;
> return ret;
> }
>
> - ret = qm_set_and_get_xqc(qm, QM_MB_CMD_CQC, &cqc, qp->qp_id, 1);
> + ret = qm_set_and_get_xqc(qm, QM_MB_CMD_CQC, &cqc, qp_id, 1);
> if (ret) {
> dev_err_ratelimited(dev, "Failed to dump cqc!\n");
> + *state = DUMP_CQC_FAIL;
> return ret;
> }
>
> @@ -2082,8 +2064,9 @@ static int qm_drain_qp(struct hisi_qp *qp)
> break;
>
> if (i == MAX_WAIT_COUNTS) {
> - dev_err(dev, "Fail to empty queue %u!\n", qp->qp_id);
> - return -EBUSY;
> + dev_err(dev, "Fail to empty queue %u!\n", qp_id);
> + *state = STOP_QUEUE_FAIL;
> + return -ETIMEDOUT;
> }
>
> usleep_range(WAIT_PERIOD_US_MIN, WAIT_PERIOD_US_MAX);
> @@ -2092,6 +2075,49 @@ static int qm_drain_qp(struct hisi_qp *qp)
> return 0;
> }
>
> +/**
> + * qm_drain_qp() - Drain a qp.
> + * @qp: The qp we want to drain.
> + *
> + * If the device does not support stopping queue by sending mailbox,
> + * determine whether the queue is cleared by judging the tail pointers of
> + * sq and cq.
> + */
> +static int qm_drain_qp(struct hisi_qp *qp)
> +{
> + struct hisi_qm *qm = qp->qm;
> + struct hisi_qm *pf_qm = pci_get_drvdata(pci_physfn(qm->pdev));
> + u32 state = 0;
> + int ret;
> +
> + /* No need to judge if master OOO is blocked. */
> + if (qm_check_dev_error(pf_qm))
> + return 0;
> +
> + /* HW V3 supports drain qp by device */
> + if (test_bit(QM_SUPPORT_STOP_QP, &qm->caps)) {
> + ret = qm_stop_qp(qp);
> + if (ret) {
> + dev_err(&qm->pdev->dev, "Failed to stop qp!\n");
> + state = STOP_QUEUE_FAIL;
> + goto set_dev_state;
> + }
> + return ret;
> + }
> +
> + ret = qm_wait_qp_empty(qm, &state, qp->qp_id);
> + if (ret)
> + goto set_dev_state;
> +
> + return 0;
> +
> +set_dev_state:
> + if (qm->debug.dev_dfx.dev_timeout)
> + qm->debug.dev_dfx.dev_state = state;
> +
> + return ret;
> +}
> +
> static int qm_stop_qp_nolock(struct hisi_qp *qp)
> {
> struct hisi_qm *qm = qp->qm;
> @@ -2319,7 +2345,26 @@ static int hisi_qm_uacce_start_queue(struct uacce_queue *q)
>
> static void hisi_qm_uacce_stop_queue(struct uacce_queue *q)
> {
> - hisi_qm_stop_qp(q->priv);
> + struct hisi_qp *qp = q->priv;
> + struct hisi_qm *qm = qp->qm;
> + struct qm_dev_dfx *dev_dfx = &qm->debug.dev_dfx;
> + u32 i = 0;
> +
> + hisi_qm_stop_qp(qp);
> +
> + if (!dev_dfx->dev_timeout || !dev_dfx->dev_state)
> + return;
> +
> + while (++i) {
> + if (!i || i > dev_dfx->dev_timeout) {


The "!i" judgment here is redundant. What needs to be considered is the situation
if i is equal to dev_timeout and both are UINT_MAX.

Thanks,
Longfang.

> + dev_err(&qm->pdev->dev, "Stop q %u timeout, state %u\n",
> + qp->qp_id, dev_dfx->dev_state);
> + dev_dfx->dev_state = FINISH_WAIT;
> + break;
> + }
> +
> + msleep(WAIT_PERIOD);
> + }
> }
>
> static int hisi_qm_is_q_updated(struct uacce_queue *q)
> diff --git a/include/linux/hisi_acc_qm.h b/include/linux/hisi_acc_qm.h
> index 720f10874a66..ec5a70ade511 100644
> --- a/include/linux/hisi_acc_qm.h
> +++ b/include/linux/hisi_acc_qm.h
> @@ -158,6 +158,19 @@ enum qm_cap_bits {
> QM_SUPPORT_RPM,
> };
>
> +enum qm_dev_fail_state {
> + STOP_QUEUE_FAIL = 1,
> + ALLOC_CTX_FAIL,
> + DUMP_SQC_FAIL,
> + DUMP_CQC_FAIL,
> + FINISH_WAIT,
> +};
> +
> +struct qm_dev_dfx {
> + u32 dev_state;
> + u32 dev_timeout;
> +};
> +
> struct qm_dev_alg {
> u64 alg_msk;
> const char *alg;
> @@ -191,6 +204,7 @@ struct qm_debug {
> struct dentry *debug_root;
> struct dentry *qm_d;
> struct debugfs_file files[DEBUG_FILE_NUM];
> + struct qm_dev_dfx dev_dfx;
> unsigned int *qm_last_words;
> /* ACC engines recoreding last regs */
> unsigned int *last_words;
>