[PATCH v2] mmc:mmc-hsq:use fifo to dispatch mmc_request

From: Michael Wu
Date: Mon Nov 28 2022 - 04:39:01 EST


Current next_tag selection will cause a large delay in some requests and
destroy the scheduling results of the block scheduling layer. Because the
issued mrq tags cannot ensure that each time is sequential, especially when
the IO load is heavy. In the fio performance test, we found that 4k random
read data was sent to mmc_hsq to start calling request_atomic It takes
nearly 200ms to process the request, while mmc_hsq has processed thousands
of other requests. So we use fifo here to ensure the first in, first out
feature of the request and avoid adding additional delay to the request.

Reviewed-by: Wenchao Chen <wenchao.chen@xxxxxxxxxx>
Signed-off-by: Michael Wu <michael@xxxxxxxxxxxxxxxxx>
---
drivers/mmc/host/mmc_hsq.c | 40 ++++++++++++++------------------------
drivers/mmc/host/mmc_hsq.h | 5 +++++
2 files changed, 20 insertions(+), 25 deletions(-)

diff --git a/drivers/mmc/host/mmc_hsq.c b/drivers/mmc/host/mmc_hsq.c
index 9d35453e7371..424dc7b07858 100644
--- a/drivers/mmc/host/mmc_hsq.c
+++ b/drivers/mmc/host/mmc_hsq.c
@@ -13,9 +13,6 @@

#include "mmc_hsq.h"

-#define HSQ_NUM_SLOTS 64
-#define HSQ_INVALID_TAG HSQ_NUM_SLOTS
-
static void mmc_hsq_retry_handler(struct work_struct *work)
{
struct mmc_hsq *hsq = container_of(work, struct mmc_hsq, retry_work);
@@ -73,7 +70,6 @@ static void mmc_hsq_pump_requests(struct mmc_hsq *hsq)

static void mmc_hsq_update_next_tag(struct mmc_hsq *hsq, int remains)
{
- struct hsq_slot *slot;
int tag;

/*
@@ -82,29 +78,12 @@ static void mmc_hsq_update_next_tag(struct mmc_hsq *hsq, int remains)
*/
if (!remains) {
hsq->next_tag = HSQ_INVALID_TAG;
+ hsq->tail_tag = HSQ_INVALID_TAG;
return;
}

- /*
- * Increasing the next tag and check if the corresponding request is
- * available, if yes, then we found a candidate request.
- */
- if (++hsq->next_tag != HSQ_INVALID_TAG) {
- slot = &hsq->slot[hsq->next_tag];
- if (slot->mrq)
- return;
- }
-
- /* Othersie we should iterate all slots to find a available tag. */
- for (tag = 0; tag < HSQ_NUM_SLOTS; tag++) {
- slot = &hsq->slot[tag];
- if (slot->mrq)
- break;
- }
-
- if (tag == HSQ_NUM_SLOTS)
- tag = HSQ_INVALID_TAG;
-
+ tag = hsq->tag_slot[hsq->next_tag];
+ hsq->tag_slot[hsq->next_tag] = HSQ_INVALID_TAG;
hsq->next_tag = tag;
}

@@ -233,8 +212,14 @@ static int mmc_hsq_request(struct mmc_host *mmc, struct mmc_request *mrq)
* Set the next tag as current request tag if no available
* next tag.
*/
- if (hsq->next_tag == HSQ_INVALID_TAG)
+ if (hsq->next_tag == HSQ_INVALID_TAG) {
hsq->next_tag = tag;
+ hsq->tail_tag = tag;
+ hsq->tag_slot[hsq->tail_tag] = HSQ_INVALID_TAG;
+ } else {
+ hsq->tag_slot[hsq->tail_tag] = tag;
+ hsq->tail_tag = tag;
+ }

hsq->qcnt++;

@@ -339,8 +324,10 @@ static const struct mmc_cqe_ops mmc_hsq_ops = {

int mmc_hsq_init(struct mmc_hsq *hsq, struct mmc_host *mmc)
{
+ int i;
hsq->num_slots = HSQ_NUM_SLOTS;
hsq->next_tag = HSQ_INVALID_TAG;
+ hsq->tail_tag = HSQ_INVALID_TAG;

hsq->slot = devm_kcalloc(mmc_dev(mmc), hsq->num_slots,
sizeof(struct hsq_slot), GFP_KERNEL);
@@ -351,6 +338,9 @@ int mmc_hsq_init(struct mmc_hsq *hsq, struct mmc_host *mmc)
hsq->mmc->cqe_private = hsq;
mmc->cqe_ops = &mmc_hsq_ops;

+ for (i = 0; i < HSQ_NUM_SLOTS; i++)
+ hsq->tag_slot[i] = HSQ_INVALID_TAG;
+
INIT_WORK(&hsq->retry_work, mmc_hsq_retry_handler);
spin_lock_init(&hsq->lock);
init_waitqueue_head(&hsq->wait_queue);
diff --git a/drivers/mmc/host/mmc_hsq.h b/drivers/mmc/host/mmc_hsq.h
index ffdd9cd172c3..1808024fc6c5 100644
--- a/drivers/mmc/host/mmc_hsq.h
+++ b/drivers/mmc/host/mmc_hsq.h
@@ -2,6 +2,9 @@
#ifndef LINUX_MMC_HSQ_H
#define LINUX_MMC_HSQ_H

+#define HSQ_NUM_SLOTS 64
+#define HSQ_INVALID_TAG HSQ_NUM_SLOTS
+
struct hsq_slot {
struct mmc_request *mrq;
};
@@ -17,6 +20,8 @@ struct mmc_hsq {
int next_tag;
int num_slots;
int qcnt;
+ int tail_tag;
+ int tag_slot[HSQ_NUM_SLOTS];

bool enabled;
bool waiting_for_idle;
--
2.29.0