[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250914114549.650671-3-wangjianzheng@vivo.com>
Date: Sun, 14 Sep 2025 19:45:45 +0800
From: Wang Jianzheng <wangjianzheng@...o.com>
To: Jens Axboe <axboe@...nel.dk>,
Alim Akhtar <alim.akhtar@...sung.com>,
Avri Altman <avri.altman@....com>,
Bart Van Assche <bvanassche@....org>,
"James E.J. Bottomley" <James.Bottomley@...senPartnership.com>,
"Martin K. Petersen" <martin.petersen@...cle.com>,
"Rafael J. Wysocki" <rafael@...nel.org>,
Peter Wang <peter.wang@...iatek.com>,
Bean Huo <beanhuo@...ron.com>,
"Bao D. Nguyen" <quic_nguyenb@...cinc.com>,
Adrian Hunter <adrian.hunter@...el.com>,
linux-block@...r.kernel.org,
linux-kernel@...r.kernel.org,
linux-scsi@...r.kernel.org,
linux-pm@...r.kernel.org
Cc: Wang Jianzheng <wangjianzheng@...o.com>
Subject: [PATCH 2/3] block: add support for device frequency PM QoS tuning
This mechanism use the PM QoS framework to add device frequency
constraints during Block IO is running. When critical processing
I/O requests that could block latency-sensitive threads, it
dynamically applies frequency restrictions. These constraints will
be removed through a timeout-based reset mechanism.
Signed-off-by: Wang Jianzheng <wangjianzheng@...o.com>
---
block/blk-mq.c | 58 ++++++++++++++++++++++++++++++++++++++++++
include/linux/blkdev.h | 9 +++++++
include/linux/pm_qos.h | 6 +++++
3 files changed, 73 insertions(+)
diff --git a/block/blk-mq.c b/block/blk-mq.c
index ba3a4b77f578..fcb4034287d3 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -11,6 +11,7 @@
#include <linux/bio.h>
#include <linux/blkdev.h>
#include <linux/blk-integrity.h>
+#include <linux/blk-pm.h>
#include <linux/kmemleak.h>
#include <linux/mm.h>
#include <linux/init.h>
@@ -28,6 +29,7 @@
#include <linux/prefetch.h>
#include <linux/blk-crypto.h>
#include <linux/part_stat.h>
+#include <linux/pm_qos.h>
#include <linux/sched/isolation.h>
#include <trace/events/block.h>
@@ -3095,6 +3097,54 @@ static bool bio_unaligned(const struct bio *bio, struct request_queue *q)
return false;
}
+#ifdef CONFIG_PM
+static void blk_mq_dev_frequency_work(struct work_struct *work)
+{
+ struct request_queue *q =
+ container_of(work, struct request_queue, dev_freq_work.work);
+ unsigned long timeout;
+ struct dev_pm_qos_request *qos = q->dev_freq_qos;
+
+ timeout = msecs_to_jiffies(q->disk->dev_freq_timeout);
+ if (!q || IS_ERR_OR_NULL(q->dev) || IS_ERR_OR_NULL(qos))
+ return;
+
+ if (q->pm_qos_status == PM_QOS_ACTIVE) {
+ q->pm_qos_status = PM_QOS_FREQ_SET;
+ dev_pm_qos_add_request(q->dev, qos, DEV_PM_QOS_MIN_FREQUENCY,
+ FREQ_QOS_MAX_DEFAULT_VALUE);
+ } else {
+ if (time_after(jiffies, READ_ONCE(q->last_active) + timeout))
+ q->pm_qos_status = PM_QOS_FREQ_REMOV;
+ }
+
+ if (q->pm_qos_status == PM_QOS_FREQ_REMOV) {
+ dev_pm_qos_remove_request(qos);
+ q->pm_qos_status = PM_QOS_ACTIVE;
+ } else {
+ schedule_delayed_work(&q->dev_freq_work,
+ q->last_active + timeout - jiffies);
+ }
+}
+
+static void blk_pm_qos_dev_freq_update(struct request_queue *q, struct bio *bio)
+{
+ if (IS_ERR_OR_NULL(q->dev) || !q->disk->dev_freq_timeout)
+ return;
+
+ if ((bio->bi_opf & REQ_SYNC || bio_op(bio) == REQ_OP_READ)) {
+ WRITE_ONCE(q->last_active, jiffies);
+ if (q->pm_qos_status == PM_QOS_ACTIVE)
+ schedule_delayed_work(&q->dev_freq_work, 0);
+ }
+}
+#else
+static void blk_pm_qos_dev_freq_update(struct request_queue *q, struct bio *bio)
+{
+ return;
+}
+#endif
+
/**
* blk_mq_submit_bio - Create and send a request to block device.
* @bio: Bio pointer.
@@ -3161,6 +3211,8 @@ void blk_mq_submit_bio(struct bio *bio)
goto queue_exit;
}
+ blk_pm_qos_dev_freq_update(q, bio);
+
bio = __bio_split_to_limits(bio, &q->limits, &nr_segs);
if (!bio)
goto queue_exit;
@@ -4601,6 +4653,12 @@ int blk_mq_init_allocated_queue(struct blk_mq_tag_set *set,
q->queue_flags |= QUEUE_FLAG_MQ_DEFAULT;
INIT_DELAYED_WORK(&q->requeue_work, blk_mq_requeue_work);
+#ifdef CONFIG_PM
+ INIT_DELAYED_WORK(&q->dev_freq_work, blk_mq_dev_frequency_work);
+ q->dev_freq_qos = kzalloc(sizeof(*q->dev_freq_qos), GFP_KERNEL);
+ if (IS_ERR_OR_NULL(q->dev_freq_qos))
+ goto err_hctxs;
+#endif
INIT_LIST_HEAD(&q->flush_list);
INIT_LIST_HEAD(&q->requeue_list);
spin_lock_init(&q->requeue_lock);
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 950ad047dd81..ea6dfff6b0f5 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -26,6 +26,7 @@
#include <linux/xarray.h>
#include <linux/file.h>
#include <linux/lockdep.h>
+#include <linux/pm_qos.h>
struct module;
struct request_queue;
@@ -522,6 +523,14 @@ struct request_queue {
#ifdef CONFIG_PM
struct device *dev;
enum rpm_status rpm_status;
+ enum pm_qos_status pm_qos_status;
+ unsigned long last_active;
+
+ /** @dev_freq_work: Work to handle dev frequency PM QoS limits. */
+ struct delayed_work dev_freq_work;
+
+ /** @dev_freq_qos: PM QoS frequency limits for dev. */
+ struct dev_pm_qos_request *dev_freq_qos;
#endif
/*
diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h
index 4a69d4af3ff8..e0d77ff65942 100644
--- a/include/linux/pm_qos.h
+++ b/include/linux/pm_qos.h
@@ -95,6 +95,12 @@ struct freq_qos_request {
struct freq_constraints *qos;
};
+enum pm_qos_status {
+ PM_QOS_INVALID = -1,
+ PM_QOS_ACTIVE = 0,
+ PM_QOS_FREQ_SET,
+ PM_QOS_FREQ_REMOV,
+};
enum dev_pm_qos_req_type {
DEV_PM_QOS_RESUME_LATENCY = 1,
--
2.34.1
Powered by blists - more mailing lists