[PATCH v2 2/2] crypto: hisilicon/qm - implement uacce get_dev_usage callback

From: Weili Qian

Date: Mon Sep 21 2026 - 06:21:45 EST


The HiSilicon QM driver does not implement the get_dev_usage callback,
so the dev_usage sysfs attribute is hidden on its UACCE devices.

Implement hisi_qm_get_dev_usage and register it in uacce_qm_ops. For
each channel the callback reads the channel-usage register and derives
the usage via the existing qm_usage_percent() helper, moved to qm.c
with a shared declaration in qm_common.h.

The callback uses hisi_qm_get_dfx_access() so that a sysfs read does
not wake a runtime-suspended device; 0 is reported per channel when
suspended.

The channel-usage registers exist only on QM_HW_V5 and later, so the
callback returns -ENODEV on older revisions.

Signed-off-by: Weili Qian <qianweili@xxxxxxxxxx>
---
drivers/crypto/hisilicon/debugfs.c | 17 -------
drivers/crypto/hisilicon/qm.c | 66 ++++++++++++++++++++++++++++
drivers/crypto/hisilicon/qm_common.h | 1 +
3 files changed, 67 insertions(+), 17 deletions(-)

diff --git a/drivers/crypto/hisilicon/debugfs.c b/drivers/crypto/hisilicon/debugfs.c
index 3ee6de16e3f1..83dfbe74e704 100644
--- a/drivers/crypto/hisilicon/debugfs.c
+++ b/drivers/crypto/hisilicon/debugfs.c
@@ -1040,23 +1040,6 @@ void hisi_qm_show_last_dfx_regs(struct hisi_qm *qm)
}
}

-static int qm_usage_percent(struct hisi_qm *qm, int chan_num)
-{
- u32 val, used_bw, total_bw;
-
- val = readl(qm->io_base + QM_CHANNEL_USAGE_OFFSET +
- chan_num * QM_CHANNEL_ADDR_INTRVL);
- used_bw = lower_16_bits(val);
- total_bw = upper_16_bits(val);
- if (!total_bw)
- return -EIO;
-
- if (total_bw <= used_bw)
- return QM_MAX_DEV_USAGE;
-
- return (used_bw * QM_DEV_USAGE_RATE) / total_bw;
-}
-
static int qm_usage_show(struct seq_file *s, void *unused)
{
struct hisi_qm *qm = s->private;
diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c
index c01966a4a33f..7dd7cf617570 100644
--- a/drivers/crypto/hisilicon/qm.c
+++ b/drivers/crypto/hisilicon/qm.c
@@ -2884,6 +2884,71 @@ static u32 hisi_qm_isolate_threshold_read(struct uacce_device *uacce)
return qm->isolate_data.err_threshold;
}

+int qm_usage_percent(struct hisi_qm *qm, int chan_idx)
+{
+ u32 val, used_bw, max_bw;
+
+ /*
+ * Channel-usage register: lower 16 bits = current used bandwidth,
+ * upper 16 bits = per-channel maximum bandwidth (static capability,
+ * non-zero once the device is initialized).
+ */
+ val = readl(qm->io_base + QM_CHANNEL_USAGE_OFFSET +
+ chan_idx * QM_CHANNEL_ADDR_INTRVL);
+ used_bw = lower_16_bits(val);
+ max_bw = upper_16_bits(val);
+ if (!max_bw)
+ return -EIO;
+
+ if (max_bw <= used_bw)
+ return QM_MAX_DEV_USAGE;
+
+ return (used_bw * QM_DEV_USAGE_RATE) / max_bw;
+}
+
+static int hisi_qm_get_dev_usage(struct uacce_device *uacce, char *buf, int size)
+{
+ struct hisi_qm *qm = uacce->priv;
+ struct qm_channel *channel_data = &qm->channel_data;
+ bool dev_is_active = true;
+ const char *sep = "";
+ int ret, i, len = 0;
+
+ if (qm->ver < QM_HW_V5)
+ return -ENODEV;
+
+ /* If runtime-suspended, skip register reads and report 0. */
+ ret = hisi_qm_get_dfx_access(qm);
+ if (ret == -EAGAIN) {
+ dev_is_active = false;
+ ret = 0;
+ } else if (ret) {
+ return ret;
+ }
+
+ for (i = 0; i < channel_data->channel_num; i++) {
+ if (dev_is_active) {
+ ret = qm_usage_percent(qm, i);
+ if (ret < 0)
+ goto out;
+ }
+
+ if (len >= size)
+ break;
+
+ len += scnprintf(buf + len, size - len, "%s%s: %d",
+ sep, channel_data->channel_name[i], ret);
+ sep = "\n";
+ }
+
+ ret = len;
+out:
+ if (dev_is_active)
+ hisi_qm_put_dfx_access(qm);
+
+ return ret;
+}
+
static const struct uacce_ops uacce_qm_ops = {
.get_available_instances = hisi_qm_get_available_instances,
.get_queue = hisi_qm_uacce_get_queue,
@@ -2896,6 +2961,7 @@ static const struct uacce_ops uacce_qm_ops = {
.get_isolate_state = hisi_qm_get_isolate_state,
.isolate_err_threshold_write = hisi_qm_isolate_threshold_write,
.isolate_err_threshold_read = hisi_qm_isolate_threshold_read,
+ .get_dev_usage = hisi_qm_get_dev_usage,
};

static void qm_remove_uacce(struct hisi_qm *qm)
diff --git a/drivers/crypto/hisilicon/qm_common.h b/drivers/crypto/hisilicon/qm_common.h
index 0760bf55f13e..78bcf40bd851 100644
--- a/drivers/crypto/hisilicon/qm_common.h
+++ b/drivers/crypto/hisilicon/qm_common.h
@@ -75,5 +75,6 @@ struct qm_aeqc {
int qm_set_and_get_xqc(struct hisi_qm *qm, u8 cmd, void *xqc, u32 qp_id, bool op);
void hisi_qm_show_last_dfx_regs(struct hisi_qm *qm);
void hisi_qm_set_algqos_init(struct hisi_qm *qm);
+int qm_usage_percent(struct hisi_qm *qm, int chan_idx);

#endif
--
2.43.0