2020-02-12 04:14:26

by Baolin Wang

[permalink] [raw]
Subject: [PATCH v9 0/5] Add MMC software queue support

Hi All,

Now the MMC read/write stack will always wait for previous request is
completed by mmc_blk_rw_wait(), before sending a new request to hardware,
or queue a work to complete request, that will bring context switching
overhead, especially for high I/O per second rates, to affect the IO
performance.

Thus this patch set will introduce the MMC software command queue support
based on command queue engine's interfaces, and set the queue depth as 64
to allow more requests can be be prepared, merged and inserted into IO
scheduler, but we only allow 2 requests in flight, that is enough to let
the irq handler always trigger the next request without a context switch,
as well as avoiding a long latency.

Moreover we can expand the MMC software queue interface to support
MMC packed request or packed command instead of adding new interfaces,
according to previosus discussion.

Below are some comparison data with fio tool. The fio command I used
is like below with changing the '--rw' parameter and enabling the direct
IO flag to measure the actual hardware transfer speed in 4K block size.

./fio --filename=/dev/mmcblk0p30 --direct=1 --iodepth=20 --rw=read --bs=4K --size=1G --group_reporting --numjobs=20 --name=test_read

My eMMC card working at HS400 Enhanced strobe mode:
[ 2.229856] mmc0: new HS400 Enhanced strobe MMC card at address 0001
[ 2.237566] mmcblk0: mmc0:0001 HBG4a2 29.1 GiB
[ 2.242621] mmcblk0boot0: mmc0:0001 HBG4a2 partition 1 4.00 MiB
[ 2.249110] mmcblk0boot1: mmc0:0001 HBG4a2 partition 2 4.00 MiB
[ 2.255307] mmcblk0rpmb: mmc0:0001 HBG4a2 partition 3 4.00 MiB, chardev (248:0)

1. Without MMC software queue
I tested 5 times for each case and output a average speed.

1) Sequential read:
Speed: 59.4MiB/s, 63.4MiB/s, 57.5MiB/s, 57.2MiB/s, 60.8MiB/s
Average speed: 59.66MiB/s

2) Random read:
Speed: 26.9MiB/s, 26.9MiB/s, 27.1MiB/s, 27.1MiB/s, 27.2MiB/s
Average speed: 27.04MiB/s

3) Sequential write:
Speed: 71.6MiB/s, 72.5MiB/s, 72.2MiB/s, 64.6MiB/s, 67.5MiB/s
Average speed: 69.68MiB/s

4) Random write:
Speed: 36.3MiB/s, 35.4MiB/s, 38.6MiB/s, 34MiB/s, 35.5MiB/s
Average speed: 35.96MiB/s

2. With MMC software queue
I tested 5 times for each case and output a average speed.

1) Sequential read:
Speed: 59.2MiB/s, 60.4MiB/s, 63.6MiB/s, 60.3MiB/s, 59.9MiB/s
Average speed: 60.68MiB/s

2) Random read:
Speed: 31.3MiB/s, 31.4MiB/s, 31.5MiB/s, 31.3MiB/s, 31.3MiB/s
Average speed: 31.36MiB/s

3) Sequential write:
Speed: 71MiB/s, 71.8MiB/s, 72.3MiB/s, 72.2MiB/s, 71MiB/s
Average speed: 71.66MiB/s

4) Random write:
Speed: 68.9MiB/s, 68.7MiB/s, 68.8MiB/s, 68.6MiB/s, 68.8MiB/s
Average speed: 68.76MiB/s

Form above data, we can see the MMC software queue can help to improve some
performance obviously for random read and write, though no obvious improvement
for sequential read and write.

Any comments are welcome. Thanks a lot.

Changes from v8:
- Add more description in the commit message.
- Optimize the failure log when calling cqe_enable().

Changes from v7:
- Add reviewed tag from Arnd.
- Use the 'hsq' acronym for varibles and functions in the core layer.
- Check the 'card->ext_csd.cmdq_en' in cqhci.c to make sure the CQE
can work normally.
- Add a new patch to enable the host software queue for the SD card.
- Use the default MMC queue depth for host software queue.

Changes from v6:
- Change the patch order and set host->always_defer_done = true for the
Spreadtrum host driver.

Changes from v5:
- Modify the condition of defering to complete request suggested by Adrian.

Changes from v4:
- Add a seperate patch to introduce a variable to defer to complete
data requests for some host drivers, when using host software queue.

Changes from v3:
- Use host software queue instead of sqhci.
- Fix random config building issue.
- Change queue depth to 32, but still only allow 2 requests in flight.
- Update the testing data.

Changes from v2:
- Remove reference to 'struct cqhci_host' and 'struct cqhci_slot',
instead adding 'struct sqhci_host', which is only used by software queue.

Changes from v1:
- Add request_done ops for sdhci_ops.
- Replace virtual command queue with software queue for functions and
variables.
- Rename the software queue file and add sqhci.h header file.

Baolin Wang (5):
mmc: Add MMC host software queue support
mmc: core: Enable the MMC host software queue for the SD card
mmc: host: sdhci: Add request_done ops for struct sdhci_ops
mmc: host: sdhci: Add a variable to defer to complete requests if
needed
mmc: host: sdhci-sprd: Add software queue support

drivers/mmc/core/block.c | 61 ++++++++
drivers/mmc/core/mmc.c | 18 ++-
drivers/mmc/core/queue.c | 22 ++-
drivers/mmc/core/sd.c | 10 ++
drivers/mmc/host/Kconfig | 8 +
drivers/mmc/host/Makefile | 1 +
drivers/mmc/host/cqhci.c | 8 +-
drivers/mmc/host/mmc_hsq.c | 343 +++++++++++++++++++++++++++++++++++++++++
drivers/mmc/host/mmc_hsq.h | 30 ++++
drivers/mmc/host/sdhci-sprd.c | 28 ++++
drivers/mmc/host/sdhci.c | 14 +-
drivers/mmc/host/sdhci.h | 3 +
include/linux/mmc/host.h | 3 +
13 files changed, 534 insertions(+), 15 deletions(-)
create mode 100644 drivers/mmc/host/mmc_hsq.c
create mode 100644 drivers/mmc/host/mmc_hsq.h

--
1.7.9.5


2020-02-12 04:14:31

by Baolin Wang

[permalink] [raw]
Subject: [PATCH v9 1/5] mmc: Add MMC host software queue support

From: Baolin Wang <[email protected]>

Now the MMC read/write stack will always wait for previous request is
completed by mmc_blk_rw_wait(), before sending a new request to hardware,
or queue a work to complete request, that will bring context switching
overhead and spend some extra time to poll the card for busy completion
for I/O writes via sending CMD13, especially for high I/O per second
rates, to affect the IO performance.

Thus this patch introduces MMC software queue interface based on the
hardware command queue engine's interfaces, which is similar with the
hardware command queue engine's idea, that can remove the context
switching. Moreover we set the default queue depth as 64 for software
queue, which allows more requests to be prepared, merged and inserted
into IO scheduler to improve performance, but we only allow 2 requests
in flight, that is enough to let the irq handler always trigger the
next request without a context switch, as well as avoiding a long latency.

Moreover the host controller should support HW busy detection for I/O
operations when enabling the host software queue. That means, the host
controller must not complete a data transfer request, until after the
card stops signals busy.

From the fio testing data in cover letter, we can see the software
queue can improve some performance with 4K block size, increasing
about 16% for random read, increasing about 90% for random write,
though no obvious improvement for sequential read and write.

Moreover we can expand the software queue interface to support MMC
packed request or packed command in future.

Reviewed-by: Arnd Bergmann <[email protected]>
Signed-off-by: Baolin Wang <[email protected]>
Signed-off-by: Baolin Wang <[email protected]>
---
drivers/mmc/core/block.c | 61 ++++++++
drivers/mmc/core/mmc.c | 18 ++-
drivers/mmc/core/queue.c | 22 ++-
drivers/mmc/host/Kconfig | 7 +
drivers/mmc/host/Makefile | 1 +
drivers/mmc/host/cqhci.c | 8 +-
drivers/mmc/host/mmc_hsq.c | 343 ++++++++++++++++++++++++++++++++++++++++++++
drivers/mmc/host/mmc_hsq.h | 30 ++++
include/linux/mmc/host.h | 3 +
9 files changed, 481 insertions(+), 12 deletions(-)
create mode 100644 drivers/mmc/host/mmc_hsq.c
create mode 100644 drivers/mmc/host/mmc_hsq.h

diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
index 663d879..55d52fc 100644
--- a/drivers/mmc/core/block.c
+++ b/drivers/mmc/core/block.c
@@ -168,6 +168,11 @@ struct mmc_rpmb_data {

static inline int mmc_blk_part_switch(struct mmc_card *card,
unsigned int part_type);
+static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
+ struct mmc_card *card,
+ int disable_multi,
+ struct mmc_queue *mq);
+static void mmc_blk_hsq_req_done(struct mmc_request *mrq);

static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
{
@@ -1532,9 +1537,30 @@ static int mmc_blk_cqe_issue_flush(struct mmc_queue *mq, struct request *req)
return mmc_blk_cqe_start_req(mq->card->host, mrq);
}

+static int mmc_blk_hsq_issue_rw_rq(struct mmc_queue *mq, struct request *req)
+{
+ struct mmc_queue_req *mqrq = req_to_mmc_queue_req(req);
+ struct mmc_host *host = mq->card->host;
+ int err;
+
+ mmc_blk_rw_rq_prep(mqrq, mq->card, 0, mq);
+ mqrq->brq.mrq.done = mmc_blk_hsq_req_done;
+ mmc_pre_req(host, &mqrq->brq.mrq);
+
+ err = mmc_cqe_start_req(host, &mqrq->brq.mrq);
+ if (err)
+ mmc_post_req(host, &mqrq->brq.mrq, err);
+
+ return err;
+}
+
static int mmc_blk_cqe_issue_rw_rq(struct mmc_queue *mq, struct request *req)
{
struct mmc_queue_req *mqrq = req_to_mmc_queue_req(req);
+ struct mmc_host *host = mq->card->host;
+
+ if (host->hsq_enabled)
+ return mmc_blk_hsq_issue_rw_rq(mq, req);

mmc_blk_data_prep(mq, mqrq, 0, NULL, NULL);

@@ -1920,6 +1946,41 @@ static void mmc_blk_urgent_bkops(struct mmc_queue *mq,
mmc_run_bkops(mq->card);
}

+static void mmc_blk_hsq_req_done(struct mmc_request *mrq)
+{
+ struct mmc_queue_req *mqrq =
+ container_of(mrq, struct mmc_queue_req, brq.mrq);
+ struct request *req = mmc_queue_req_to_req(mqrq);
+ struct request_queue *q = req->q;
+ struct mmc_queue *mq = q->queuedata;
+ struct mmc_host *host = mq->card->host;
+ unsigned long flags;
+
+ if (mmc_blk_rq_error(&mqrq->brq) ||
+ mmc_blk_urgent_bkops_needed(mq, mqrq)) {
+ spin_lock_irqsave(&mq->lock, flags);
+ mq->recovery_needed = true;
+ mq->recovery_req = req;
+ spin_unlock_irqrestore(&mq->lock, flags);
+
+ host->cqe_ops->cqe_recovery_start(host);
+
+ schedule_work(&mq->recovery_work);
+ return;
+ }
+
+ mmc_blk_rw_reset_success(mq, req);
+
+ /*
+ * Block layer timeouts race with completions which means the normal
+ * completion path cannot be used during recovery.
+ */
+ if (mq->in_recovery)
+ mmc_blk_cqe_complete_rq(mq, req);
+ else
+ blk_mq_complete_request(req);
+}
+
void mmc_blk_mq_complete(struct request *req)
{
struct mmc_queue *mq = req->q->queuedata;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index f6912de..693921e 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1851,15 +1851,19 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
*/
card->reenable_cmdq = card->ext_csd.cmdq_en;

- if (card->ext_csd.cmdq_en && !host->cqe_enabled) {
+ if (host->cqe_ops && !host->cqe_enabled) {
err = host->cqe_ops->cqe_enable(host, card);
- if (err) {
- pr_err("%s: Failed to enable CQE, error %d\n",
- mmc_hostname(host), err);
- } else {
+ if (!err) {
host->cqe_enabled = true;
- pr_info("%s: Command Queue Engine enabled\n",
- mmc_hostname(host));
+
+ if (card->ext_csd.cmdq_en) {
+ pr_info("%s: Command Queue Engine enabled\n",
+ mmc_hostname(host));
+ } else {
+ host->hsq_enabled = true;
+ pr_info("%s: Host Software Queue enabled\n",
+ mmc_hostname(host));
+ }
}
}

diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c
index 9edc086..25bee3d 100644
--- a/drivers/mmc/core/queue.c
+++ b/drivers/mmc/core/queue.c
@@ -62,7 +62,7 @@ enum mmc_issue_type mmc_issue_type(struct mmc_queue *mq, struct request *req)
{
struct mmc_host *host = mq->card->host;

- if (mq->use_cqe)
+ if (mq->use_cqe && !host->hsq_enabled)
return mmc_cqe_issue_type(host, req);

if (req_op(req) == REQ_OP_READ || req_op(req) == REQ_OP_WRITE)
@@ -124,12 +124,14 @@ static enum blk_eh_timer_return mmc_mq_timed_out(struct request *req,
{
struct request_queue *q = req->q;
struct mmc_queue *mq = q->queuedata;
+ struct mmc_card *card = mq->card;
+ struct mmc_host *host = card->host;
unsigned long flags;
int ret;

spin_lock_irqsave(&mq->lock, flags);

- if (mq->recovery_needed || !mq->use_cqe)
+ if (mq->recovery_needed || !mq->use_cqe || host->hsq_enabled)
ret = BLK_EH_RESET_TIMER;
else
ret = mmc_cqe_timed_out(req);
@@ -144,12 +146,13 @@ static void mmc_mq_recovery_handler(struct work_struct *work)
struct mmc_queue *mq = container_of(work, struct mmc_queue,
recovery_work);
struct request_queue *q = mq->queue;
+ struct mmc_host *host = mq->card->host;

mmc_get_card(mq->card, &mq->ctx);

mq->in_recovery = true;

- if (mq->use_cqe)
+ if (mq->use_cqe && !host->hsq_enabled)
mmc_blk_cqe_recovery(mq);
else
mmc_blk_mq_recovery(mq);
@@ -160,6 +163,9 @@ static void mmc_mq_recovery_handler(struct work_struct *work)
mq->recovery_needed = false;
spin_unlock_irq(&mq->lock);

+ if (host->hsq_enabled)
+ host->cqe_ops->cqe_recovery_finish(host);
+
mmc_put_card(mq->card, &mq->ctx);

blk_mq_run_hw_queues(q, true);
@@ -279,6 +285,14 @@ static blk_status_t mmc_mq_queue_rq(struct blk_mq_hw_ctx *hctx,
}
break;
case MMC_ISSUE_ASYNC:
+ /*
+ * For MMC host software queue, we only allow 2 requests in
+ * flight to avoid a long latency.
+ */
+ if (host->hsq_enabled && mq->in_flight[issue_type] > 2) {
+ spin_unlock_irq(&mq->lock);
+ return BLK_STS_RESOURCE;
+ }
break;
default:
/*
@@ -430,7 +444,7 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card)
* The queue depth for CQE must match the hardware because the request
* tag is used to index the hardware queue.
*/
- if (mq->use_cqe)
+ if (mq->use_cqe && !host->hsq_enabled)
mq->tag_set.queue_depth =
min_t(int, card->ext_csd.cmdq_depth, host->cqe_qdepth);
else
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 3a5089f..65d3966 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -949,6 +949,13 @@ config MMC_CQHCI

If unsure, say N.

+config MMC_HSQ
+ tristate "MMC Host Software Queue support"
+ help
+ This selects the Software Queue support.
+
+ If unsure, say N.
+
config MMC_TOSHIBA_PCI
tristate "Toshiba Type A SD/MMC Card Interface Driver"
depends on PCI
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 21d9089..b929ef9 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -100,6 +100,7 @@ obj-$(CONFIG_MMC_SDHCI_BRCMSTB) += sdhci-brcmstb.o
obj-$(CONFIG_MMC_SDHCI_OMAP) += sdhci-omap.o
obj-$(CONFIG_MMC_SDHCI_SPRD) += sdhci-sprd.o
obj-$(CONFIG_MMC_CQHCI) += cqhci.o
+obj-$(CONFIG_MMC_HSQ) += mmc_hsq.o

ifeq ($(CONFIG_CB710_DEBUG),y)
CFLAGS-cb710-mmc += -DDEBUG
diff --git a/drivers/mmc/host/cqhci.c b/drivers/mmc/host/cqhci.c
index 5047f73..e2ea2c4 100644
--- a/drivers/mmc/host/cqhci.c
+++ b/drivers/mmc/host/cqhci.c
@@ -321,14 +321,20 @@ static int cqhci_enable(struct mmc_host *mmc, struct mmc_card *card)
struct cqhci_host *cq_host = mmc->cqe_private;
int err;

+ if (!card->ext_csd.cmdq_en)
+ return -EINVAL;
+
if (cq_host->enabled)
return 0;

cq_host->rca = card->rca;

err = cqhci_host_alloc_tdl(cq_host);
- if (err)
+ if (err) {
+ pr_err("%s: Failed to enable CQE, error %d\n",
+ mmc_hostname(mmc), err);
return err;
+ }

__cqhci_enable(cq_host);

diff --git a/drivers/mmc/host/mmc_hsq.c b/drivers/mmc/host/mmc_hsq.c
new file mode 100644
index 0000000..2011988
--- /dev/null
+++ b/drivers/mmc/host/mmc_hsq.c
@@ -0,0 +1,343 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MMC software queue support based on command queue interfaces
+ *
+ * Copyright (C) 2019 Linaro, Inc.
+ * Author: Baolin Wang <[email protected]>
+ */
+
+#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
+
+#include "mmc_hsq.h"
+
+#define HSQ_NUM_SLOTS 64
+#define HSQ_INVALID_TAG HSQ_NUM_SLOTS
+
+static void mmc_hsq_pump_requests(struct mmc_hsq *hsq)
+{
+ struct mmc_host *mmc = hsq->mmc;
+ struct hsq_slot *slot;
+ unsigned long flags;
+
+ spin_lock_irqsave(&hsq->lock, flags);
+
+ /* Make sure we are not already running a request now */
+ if (hsq->mrq) {
+ spin_unlock_irqrestore(&hsq->lock, flags);
+ return;
+ }
+
+ /* Make sure there are remain requests need to pump */
+ if (!hsq->qcnt || !hsq->enabled) {
+ spin_unlock_irqrestore(&hsq->lock, flags);
+ return;
+ }
+
+ slot = &hsq->slot[hsq->next_tag];
+ hsq->mrq = slot->mrq;
+ hsq->qcnt--;
+
+ spin_unlock_irqrestore(&hsq->lock, flags);
+
+ mmc->ops->request(mmc, hsq->mrq);
+}
+
+static void mmc_hsq_update_next_tag(struct mmc_hsq *hsq, int remains)
+{
+ struct hsq_slot *slot;
+ int tag;
+
+ /*
+ * If there are no remain requests in software queue, then set a invalid
+ * tag.
+ */
+ if (!remains) {
+ hsq->next_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;
+
+ hsq->next_tag = tag;
+}
+
+static void mmc_hsq_post_request(struct mmc_hsq *hsq)
+{
+ unsigned long flags;
+ int remains;
+
+ spin_lock_irqsave(&hsq->lock, flags);
+
+ remains = hsq->qcnt;
+ hsq->mrq = NULL;
+
+ /* Update the next available tag to be queued. */
+ mmc_hsq_update_next_tag(hsq, remains);
+
+ if (hsq->waiting_for_idle && !remains) {
+ hsq->waiting_for_idle = false;
+ wake_up(&hsq->wait_queue);
+ }
+
+ /* Do not pump new request in recovery mode. */
+ if (hsq->recovery_halt) {
+ spin_unlock_irqrestore(&hsq->lock, flags);
+ return;
+ }
+
+ spin_unlock_irqrestore(&hsq->lock, flags);
+
+ /*
+ * Try to pump new request to host controller as fast as possible,
+ * after completing previous request.
+ */
+ if (remains > 0)
+ mmc_hsq_pump_requests(hsq);
+}
+
+/**
+ * mmc_hsq_finalize_request - finalize one request if the request is done
+ * @mmc: the host controller
+ * @mrq: the request need to be finalized
+ *
+ * Return true if we finalized the corresponding request in software queue,
+ * otherwise return false.
+ */
+bool mmc_hsq_finalize_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+ struct mmc_hsq *hsq = mmc->cqe_private;
+ unsigned long flags;
+
+ spin_lock_irqsave(&hsq->lock, flags);
+
+ if (!hsq->enabled || !hsq->mrq || hsq->mrq != mrq) {
+ spin_unlock_irqrestore(&hsq->lock, flags);
+ return false;
+ }
+
+ /*
+ * Clear current completed slot request to make a room for new request.
+ */
+ hsq->slot[hsq->next_tag].mrq = NULL;
+
+ spin_unlock_irqrestore(&hsq->lock, flags);
+
+ mmc_cqe_request_done(mmc, hsq->mrq);
+
+ mmc_hsq_post_request(hsq);
+
+ return true;
+}
+EXPORT_SYMBOL_GPL(mmc_hsq_finalize_request);
+
+static void mmc_hsq_recovery_start(struct mmc_host *mmc)
+{
+ struct mmc_hsq *hsq = mmc->cqe_private;
+ unsigned long flags;
+
+ spin_lock_irqsave(&hsq->lock, flags);
+
+ hsq->recovery_halt = true;
+
+ spin_unlock_irqrestore(&hsq->lock, flags);
+}
+
+static void mmc_hsq_recovery_finish(struct mmc_host *mmc)
+{
+ struct mmc_hsq *hsq = mmc->cqe_private;
+ int remains;
+
+ spin_lock_irq(&hsq->lock);
+
+ hsq->recovery_halt = false;
+ remains = hsq->qcnt;
+
+ spin_unlock_irq(&hsq->lock);
+
+ /*
+ * Try to pump new request if there are request pending in software
+ * queue after finishing recovery.
+ */
+ if (remains > 0)
+ mmc_hsq_pump_requests(hsq);
+}
+
+static int mmc_hsq_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+ struct mmc_hsq *hsq = mmc->cqe_private;
+ int tag = mrq->tag;
+
+ spin_lock_irq(&hsq->lock);
+
+ if (!hsq->enabled) {
+ spin_unlock_irq(&hsq->lock);
+ return -ESHUTDOWN;
+ }
+
+ /* Do not queue any new requests in recovery mode. */
+ if (hsq->recovery_halt) {
+ spin_unlock_irq(&hsq->lock);
+ return -EBUSY;
+ }
+
+ hsq->slot[tag].mrq = mrq;
+
+ /*
+ * Set the next tag as current request tag if no available
+ * next tag.
+ */
+ if (hsq->next_tag == HSQ_INVALID_TAG)
+ hsq->next_tag = tag;
+
+ hsq->qcnt++;
+
+ spin_unlock_irq(&hsq->lock);
+
+ mmc_hsq_pump_requests(hsq);
+
+ return 0;
+}
+
+static void mmc_hsq_post_req(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+ if (mmc->ops->post_req)
+ mmc->ops->post_req(mmc, mrq, 0);
+}
+
+static bool mmc_hsq_queue_is_idle(struct mmc_hsq *hsq, int *ret)
+{
+ bool is_idle;
+
+ spin_lock_irq(&hsq->lock);
+
+ is_idle = (!hsq->mrq && !hsq->qcnt) ||
+ hsq->recovery_halt;
+
+ *ret = hsq->recovery_halt ? -EBUSY : 0;
+ hsq->waiting_for_idle = !is_idle;
+
+ spin_unlock_irq(&hsq->lock);
+
+ return is_idle;
+}
+
+static int mmc_hsq_wait_for_idle(struct mmc_host *mmc)
+{
+ struct mmc_hsq *hsq = mmc->cqe_private;
+ int ret;
+
+ wait_event(hsq->wait_queue,
+ mmc_hsq_queue_is_idle(hsq, &ret));
+
+ return ret;
+}
+
+static void mmc_hsq_disable(struct mmc_host *mmc)
+{
+ struct mmc_hsq *hsq = mmc->cqe_private;
+ u32 timeout = 500;
+ int ret;
+
+ spin_lock_irq(&hsq->lock);
+
+ if (!hsq->enabled) {
+ spin_unlock_irq(&hsq->lock);
+ return;
+ }
+
+ spin_unlock_irq(&hsq->lock);
+
+ ret = wait_event_timeout(hsq->wait_queue,
+ mmc_hsq_queue_is_idle(hsq, &ret),
+ msecs_to_jiffies(timeout));
+ if (ret == 0) {
+ pr_warn("could not stop mmc software queue\n");
+ return;
+ }
+
+ spin_lock_irq(&hsq->lock);
+
+ hsq->enabled = false;
+
+ spin_unlock_irq(&hsq->lock);
+}
+
+static int mmc_hsq_enable(struct mmc_host *mmc, struct mmc_card *card)
+{
+ struct mmc_hsq *hsq = mmc->cqe_private;
+
+ spin_lock_irq(&hsq->lock);
+
+ if (hsq->enabled) {
+ spin_unlock_irq(&hsq->lock);
+ return -EBUSY;
+ }
+
+ hsq->enabled = true;
+
+ spin_unlock_irq(&hsq->lock);
+
+ return 0;
+}
+
+static const struct mmc_cqe_ops mmc_hsq_ops = {
+ .cqe_enable = mmc_hsq_enable,
+ .cqe_disable = mmc_hsq_disable,
+ .cqe_request = mmc_hsq_request,
+ .cqe_post_req = mmc_hsq_post_req,
+ .cqe_wait_for_idle = mmc_hsq_wait_for_idle,
+ .cqe_recovery_start = mmc_hsq_recovery_start,
+ .cqe_recovery_finish = mmc_hsq_recovery_finish,
+};
+
+int mmc_hsq_init(struct mmc_hsq *hsq, struct mmc_host *mmc)
+{
+ hsq->num_slots = HSQ_NUM_SLOTS;
+ hsq->next_tag = HSQ_INVALID_TAG;
+
+ hsq->slot = devm_kcalloc(mmc_dev(mmc), hsq->num_slots,
+ sizeof(struct hsq_slot), GFP_KERNEL);
+ if (!hsq->slot)
+ return -ENOMEM;
+
+ hsq->mmc = mmc;
+ hsq->mmc->cqe_private = hsq;
+ mmc->cqe_ops = &mmc_hsq_ops;
+
+ spin_lock_init(&hsq->lock);
+ init_waitqueue_head(&hsq->wait_queue);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mmc_hsq_init);
+
+void mmc_hsq_suspend(struct mmc_host *mmc)
+{
+ mmc_hsq_disable(mmc);
+}
+EXPORT_SYMBOL_GPL(mmc_hsq_suspend);
+
+int mmc_hsq_resume(struct mmc_host *mmc)
+{
+ return mmc_hsq_enable(mmc, NULL);
+}
+EXPORT_SYMBOL_GPL(mmc_hsq_resume);
diff --git a/drivers/mmc/host/mmc_hsq.h b/drivers/mmc/host/mmc_hsq.h
new file mode 100644
index 0000000..d51beb7
--- /dev/null
+++ b/drivers/mmc/host/mmc_hsq.h
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0
+#ifndef LINUX_MMC_HSQ_H
+#define LINUX_MMC_HSQ_H
+
+struct hsq_slot {
+ struct mmc_request *mrq;
+};
+
+struct mmc_hsq {
+ struct mmc_host *mmc;
+ struct mmc_request *mrq;
+ wait_queue_head_t wait_queue;
+ struct hsq_slot *slot;
+ spinlock_t lock;
+
+ int next_tag;
+ int num_slots;
+ int qcnt;
+
+ bool enabled;
+ bool waiting_for_idle;
+ bool recovery_halt;
+};
+
+int mmc_hsq_init(struct mmc_hsq *hsq, struct mmc_host *mmc);
+void mmc_hsq_suspend(struct mmc_host *mmc);
+int mmc_hsq_resume(struct mmc_host *mmc);
+bool mmc_hsq_finalize_request(struct mmc_host *mmc, struct mmc_request *mrq);
+
+#endif
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index ba70338..562ed06 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -462,6 +462,9 @@ struct mmc_host {
bool cqe_enabled;
bool cqe_on;

+ /* Host Software Queue support */
+ bool hsq_enabled;
+
unsigned long private[0] ____cacheline_aligned;
};

--
1.7.9.5

2020-02-12 04:14:37

by Baolin Wang

[permalink] [raw]
Subject: [PATCH v9 2/5] mmc: core: Enable the MMC host software queue for the SD card

From: Baolin Wang <[email protected]>

Enable the MMC host software queue for the SD card if the host controller
supports the MMC host software queue.

On my Spreadtrum platform, I did not see any obvious performance changes
in 4K block size when changing to use hsq for the SD cards, I think the
reason is the SD card works at a low speed on my platform, and most of
time is spent in the hardware. But we can see some obvious improvements
when enabling the packed request based on hsq, that's why we still add hsq
support for the SD cards.

Signed-off-by: Baolin Wang <[email protected]>
Signed-off-by: Baolin Wang <[email protected]>
---
drivers/mmc/core/sd.c | 10 ++++++++++
1 file changed, 10 insertions(+)

diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index fe914ff..76c7add 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1082,6 +1082,16 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
}
}

+ if (host->cqe_ops && !host->cqe_enabled) {
+ err = host->cqe_ops->cqe_enable(host, card);
+ if (!err) {
+ host->cqe_enabled = true;
+ host->hsq_enabled = true;
+ pr_info("%s: Host Software Queue enabled\n",
+ mmc_hostname(host));
+ }
+ }
+
if (host->caps2 & MMC_CAP2_AVOID_3_3V &&
host->ios.signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
pr_err("%s: Host failed to negotiate down from 3.3V\n",
--
1.7.9.5

2020-02-12 04:14:53

by Baolin Wang

[permalink] [raw]
Subject: [PATCH v9 3/5] mmc: host: sdhci: Add request_done ops for struct sdhci_ops

From: Baolin Wang <[email protected]>

Add request_done ops for struct sdhci_ops as a preparation in case some
host controllers have different method to complete one request, such as
supporting request completion of MMC software queue.

Suggested-by: Adrian Hunter <[email protected]>
Signed-off-by: Baolin Wang <[email protected]>
Signed-off-by: Baolin Wang <[email protected]>
---
drivers/mmc/host/sdhci.c | 12 ++++++++++--
drivers/mmc/host/sdhci.h | 2 ++
2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 63db844..9761981 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2944,7 +2944,10 @@ static bool sdhci_request_done(struct sdhci_host *host)

spin_unlock_irqrestore(&host->lock, flags);

- mmc_request_done(host->mmc, mrq);
+ if (host->ops->request_done)
+ host->ops->request_done(host, mrq);
+ else
+ mmc_request_done(host->mmc, mrq);

return false;
}
@@ -3372,7 +3375,12 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)

/* Process mrqs ready for immediate completion */
for (i = 0; i < SDHCI_MAX_MRQS; i++) {
- if (mrqs_done[i])
+ if (!mrqs_done[i])
+ continue;
+
+ if (host->ops->request_done)
+ host->ops->request_done(host, mrqs_done[i]);
+ else
mmc_request_done(host->mmc, mrqs_done[i]);
}

diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index a6a3ddc..3e95f74 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -654,6 +654,8 @@ struct sdhci_ops {
void (*voltage_switch)(struct sdhci_host *host);
void (*adma_write_desc)(struct sdhci_host *host, void **desc,
dma_addr_t addr, int len, unsigned int cmd);
+ void (*request_done)(struct sdhci_host *host,
+ struct mmc_request *mrq);
};

#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
--
1.7.9.5

2020-02-12 04:15:09

by Baolin Wang

[permalink] [raw]
Subject: [PATCH v9 5/5] mmc: host: sdhci-sprd: Add software queue support

From: Baolin Wang <[email protected]>

Add software queue support to improve the performance.

Signed-off-by: Baolin Wang <[email protected]>
Signed-off-by: Baolin Wang <[email protected]>
---
drivers/mmc/host/Kconfig | 1 +
drivers/mmc/host/sdhci-sprd.c | 28 ++++++++++++++++++++++++++++
2 files changed, 29 insertions(+)

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 65d3966..3ea45be 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -645,6 +645,7 @@ config MMC_SDHCI_SPRD
depends on ARCH_SPRD
depends on MMC_SDHCI_PLTFM
select MMC_SDHCI_IO_ACCESSORS
+ select MMC_HSQ
help
This selects the SDIO Host Controller in Spreadtrum
SoCs, this driver supports R11(IP version: R11P0).
diff --git a/drivers/mmc/host/sdhci-sprd.c b/drivers/mmc/host/sdhci-sprd.c
index d07b979..d346223 100644
--- a/drivers/mmc/host/sdhci-sprd.c
+++ b/drivers/mmc/host/sdhci-sprd.c
@@ -19,6 +19,7 @@
#include <linux/slab.h>

#include "sdhci-pltfm.h"
+#include "mmc_hsq.h"

/* SDHCI_ARGUMENT2 register high 16bit */
#define SDHCI_SPRD_ARG2_STUFF GENMASK(31, 16)
@@ -379,6 +380,16 @@ static unsigned int sdhci_sprd_get_ro(struct sdhci_host *host)
return 0;
}

+static void sdhci_sprd_request_done(struct sdhci_host *host,
+ struct mmc_request *mrq)
+{
+ /* Validate if the request was from software queue firstly. */
+ if (mmc_hsq_finalize_request(host->mmc, mrq))
+ return;
+
+ mmc_request_done(host->mmc, mrq);
+}
+
static struct sdhci_ops sdhci_sprd_ops = {
.read_l = sdhci_sprd_readl,
.write_l = sdhci_sprd_writel,
@@ -392,6 +403,7 @@ static unsigned int sdhci_sprd_get_ro(struct sdhci_host *host)
.hw_reset = sdhci_sprd_hw_reset,
.get_max_timeout_count = sdhci_sprd_get_max_timeout_count,
.get_ro = sdhci_sprd_get_ro,
+ .request_done = sdhci_sprd_request_done,
};

static void sdhci_sprd_request(struct mmc_host *mmc, struct mmc_request *mrq)
@@ -521,6 +533,7 @@ static int sdhci_sprd_probe(struct platform_device *pdev)
{
struct sdhci_host *host;
struct sdhci_sprd_host *sprd_host;
+ struct mmc_hsq *hsq;
struct clk *clk;
int ret = 0;

@@ -631,6 +644,18 @@ static int sdhci_sprd_probe(struct platform_device *pdev)

sprd_host->flags = host->flags;

+ hsq = devm_kzalloc(&pdev->dev, sizeof(*hsq), GFP_KERNEL);
+ if (!hsq) {
+ ret = -ENOMEM;
+ goto err_cleanup_host;
+ }
+
+ ret = mmc_hsq_init(hsq, host->mmc);
+ if (ret)
+ goto err_cleanup_host;
+
+ host->always_defer_done = true;
+
ret = __sdhci_add_host(host);
if (ret)
goto err_cleanup_host;
@@ -689,6 +714,7 @@ static int sdhci_sprd_runtime_suspend(struct device *dev)
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host);

+ mmc_hsq_suspend(host->mmc);
sdhci_runtime_suspend_host(host);

clk_disable_unprepare(sprd_host->clk_sdio);
@@ -717,6 +743,8 @@ static int sdhci_sprd_runtime_resume(struct device *dev)
goto clk_disable;

sdhci_runtime_resume_host(host, 1);
+ mmc_hsq_resume(host->mmc);
+
return 0;

clk_disable:
--
1.7.9.5

2020-02-12 04:15:26

by Baolin Wang

[permalink] [raw]
Subject: [PATCH v9 4/5] mmc: host: sdhci: Add a variable to defer to complete requests if needed

From: Baolin Wang <[email protected]>

When using the host software queue, it will trigger the next request in
irq handler without a context switch. But the sdhci_request() can not be
called in interrupt context when using host software queue for some host
drivers, due to the get_cd() ops can be sleepable.

But for some host drivers, such as Spreadtrum host driver, the card is
nonremovable, so the get_cd() ops is not sleepable, which means we can
complete the data request and trigger the next request in irq handler
to remove the context switch for the Spreadtrum host driver.

As suggested by Adrian, we should introduce a request_atomic() API to
indicate that a request can be called in interrupt context to remove
the context switch when using mmc host software queue. But this should
be done in another thread to convert the users of mmc host software queue.
Thus we can introduce a variable in struct sdhci_host to indicate that
we will always to defer to complete requests when using the host software
queue.

Suggested-by: Adrian Hunter <[email protected]>
Signed-off-by: Baolin Wang <[email protected]>
Signed-off-by: Baolin Wang <[email protected]>
---
drivers/mmc/host/sdhci.c | 2 +-
drivers/mmc/host/sdhci.h | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 9761981..9c37451 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -3250,7 +3250,7 @@ static inline bool sdhci_defer_done(struct sdhci_host *host,
{
struct mmc_data *data = mrq->data;

- return host->pending_reset ||
+ return host->pending_reset || host->always_defer_done ||
((host->flags & SDHCI_REQ_USE_DMA) && data &&
data->host_cookie == COOKIE_MAPPED);
}
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 3e95f74..cac2d97 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -537,6 +537,7 @@ struct sdhci_host {
bool irq_wake_enabled; /* IRQ wakeup is enabled */
bool v4_mode; /* Host Version 4 Enable */
bool use_external_dma; /* Host selects to use external DMA */
+ bool always_defer_done; /* Always defer to complete requests */

struct mmc_request *mrqs_done[SDHCI_MAX_MRQS]; /* Requests done */
struct mmc_command *cmd; /* Current command */
--
1.7.9.5

2020-02-18 23:40:48

by Ulf Hansson

[permalink] [raw]
Subject: Re: [PATCH v9 0/5] Add MMC software queue support

On Wed, 12 Feb 2020 at 05:14, Baolin Wang <[email protected]> wrote:
>
> Hi All,
>
> Now the MMC read/write stack will always wait for previous request is
> completed by mmc_blk_rw_wait(), before sending a new request to hardware,
> or queue a work to complete request, that will bring context switching
> overhead, especially for high I/O per second rates, to affect the IO
> performance.
>
> Thus this patch set will introduce the MMC software command queue support
> based on command queue engine's interfaces, and set the queue depth as 64
> to allow more requests can be be prepared, merged and inserted into IO
> scheduler, but we only allow 2 requests in flight, that is enough to let
> the irq handler always trigger the next request without a context switch,
> as well as avoiding a long latency.
>
> Moreover we can expand the MMC software queue interface to support
> MMC packed request or packed command instead of adding new interfaces,
> according to previosus discussion.
>
> Below are some comparison data with fio tool. The fio command I used
> is like below with changing the '--rw' parameter and enabling the direct
> IO flag to measure the actual hardware transfer speed in 4K block size.
>
> ./fio --filename=/dev/mmcblk0p30 --direct=1 --iodepth=20 --rw=read --bs=4K --size=1G --group_reporting --numjobs=20 --name=test_read
>
> My eMMC card working at HS400 Enhanced strobe mode:
> [ 2.229856] mmc0: new HS400 Enhanced strobe MMC card at address 0001
> [ 2.237566] mmcblk0: mmc0:0001 HBG4a2 29.1 GiB
> [ 2.242621] mmcblk0boot0: mmc0:0001 HBG4a2 partition 1 4.00 MiB
> [ 2.249110] mmcblk0boot1: mmc0:0001 HBG4a2 partition 2 4.00 MiB
> [ 2.255307] mmcblk0rpmb: mmc0:0001 HBG4a2 partition 3 4.00 MiB, chardev (248:0)
>
> 1. Without MMC software queue
> I tested 5 times for each case and output a average speed.
>
> 1) Sequential read:
> Speed: 59.4MiB/s, 63.4MiB/s, 57.5MiB/s, 57.2MiB/s, 60.8MiB/s
> Average speed: 59.66MiB/s
>
> 2) Random read:
> Speed: 26.9MiB/s, 26.9MiB/s, 27.1MiB/s, 27.1MiB/s, 27.2MiB/s
> Average speed: 27.04MiB/s
>
> 3) Sequential write:
> Speed: 71.6MiB/s, 72.5MiB/s, 72.2MiB/s, 64.6MiB/s, 67.5MiB/s
> Average speed: 69.68MiB/s
>
> 4) Random write:
> Speed: 36.3MiB/s, 35.4MiB/s, 38.6MiB/s, 34MiB/s, 35.5MiB/s
> Average speed: 35.96MiB/s
>
> 2. With MMC software queue
> I tested 5 times for each case and output a average speed.
>
> 1) Sequential read:
> Speed: 59.2MiB/s, 60.4MiB/s, 63.6MiB/s, 60.3MiB/s, 59.9MiB/s
> Average speed: 60.68MiB/s
>
> 2) Random read:
> Speed: 31.3MiB/s, 31.4MiB/s, 31.5MiB/s, 31.3MiB/s, 31.3MiB/s
> Average speed: 31.36MiB/s
>
> 3) Sequential write:
> Speed: 71MiB/s, 71.8MiB/s, 72.3MiB/s, 72.2MiB/s, 71MiB/s
> Average speed: 71.66MiB/s
>
> 4) Random write:
> Speed: 68.9MiB/s, 68.7MiB/s, 68.8MiB/s, 68.6MiB/s, 68.8MiB/s
> Average speed: 68.76MiB/s
>
> Form above data, we can see the MMC software queue can help to improve some
> performance obviously for random read and write, though no obvious improvement
> for sequential read and write.
>
> Any comments are welcome. Thanks a lot.
>
> Changes from v8:
> - Add more description in the commit message.
> - Optimize the failure log when calling cqe_enable().
>
> Changes from v7:
> - Add reviewed tag from Arnd.
> - Use the 'hsq' acronym for varibles and functions in the core layer.
> - Check the 'card->ext_csd.cmdq_en' in cqhci.c to make sure the CQE
> can work normally.
> - Add a new patch to enable the host software queue for the SD card.
> - Use the default MMC queue depth for host software queue.
>
> Changes from v6:
> - Change the patch order and set host->always_defer_done = true for the
> Spreadtrum host driver.
>
> Changes from v5:
> - Modify the condition of defering to complete request suggested by Adrian.
>
> Changes from v4:
> - Add a seperate patch to introduce a variable to defer to complete
> data requests for some host drivers, when using host software queue.
>
> Changes from v3:
> - Use host software queue instead of sqhci.
> - Fix random config building issue.
> - Change queue depth to 32, but still only allow 2 requests in flight.
> - Update the testing data.
>
> Changes from v2:
> - Remove reference to 'struct cqhci_host' and 'struct cqhci_slot',
> instead adding 'struct sqhci_host', which is only used by software queue.
>
> Changes from v1:
> - Add request_done ops for sdhci_ops.
> - Replace virtual command queue with software queue for functions and
> variables.
> - Rename the software queue file and add sqhci.h header file.
>
> Baolin Wang (5):
> mmc: Add MMC host software queue support
> mmc: core: Enable the MMC host software queue for the SD card
> mmc: host: sdhci: Add request_done ops for struct sdhci_ops
> mmc: host: sdhci: Add a variable to defer to complete requests if
> needed
> mmc: host: sdhci-sprd: Add software queue support
>
> drivers/mmc/core/block.c | 61 ++++++++
> drivers/mmc/core/mmc.c | 18 ++-
> drivers/mmc/core/queue.c | 22 ++-
> drivers/mmc/core/sd.c | 10 ++
> drivers/mmc/host/Kconfig | 8 +
> drivers/mmc/host/Makefile | 1 +
> drivers/mmc/host/cqhci.c | 8 +-
> drivers/mmc/host/mmc_hsq.c | 343 +++++++++++++++++++++++++++++++++++++++++
> drivers/mmc/host/mmc_hsq.h | 30 ++++
> drivers/mmc/host/sdhci-sprd.c | 28 ++++
> drivers/mmc/host/sdhci.c | 14 +-
> drivers/mmc/host/sdhci.h | 3 +
> include/linux/mmc/host.h | 3 +
> 13 files changed, 534 insertions(+), 15 deletions(-)
> create mode 100644 drivers/mmc/host/mmc_hsq.c
> create mode 100644 drivers/mmc/host/mmc_hsq.h
>
> --
> 1.7.9.5
>

Applied for next, thanks! Also, thanks for your patience while moving
forward during the reviews!

Note, I did some amending of patch1 to resolve some checkpatch
warnings. SPDX licence and Kconfig help texts, please have a look and
tell if there are something that doesn't look good.

Kind regards
Uffe

2020-02-19 01:37:50

by Baolin Wang

[permalink] [raw]
Subject: Re: [PATCH v9 0/5] Add MMC software queue support

On Wed, Feb 19, 2020 at 7:38 AM Ulf Hansson <[email protected]> wrote:
>
> On Wed, 12 Feb 2020 at 05:14, Baolin Wang <[email protected]> wrote:
> >
> > Hi All,
> >
> > Now the MMC read/write stack will always wait for previous request is
> > completed by mmc_blk_rw_wait(), before sending a new request to hardware,
> > or queue a work to complete request, that will bring context switching
> > overhead, especially for high I/O per second rates, to affect the IO
> > performance.
> >
> > Thus this patch set will introduce the MMC software command queue support
> > based on command queue engine's interfaces, and set the queue depth as 64
> > to allow more requests can be be prepared, merged and inserted into IO
> > scheduler, but we only allow 2 requests in flight, that is enough to let
> > the irq handler always trigger the next request without a context switch,
> > as well as avoiding a long latency.
> >
> > Moreover we can expand the MMC software queue interface to support
> > MMC packed request or packed command instead of adding new interfaces,
> > according to previosus discussion.
> >
> > Below are some comparison data with fio tool. The fio command I used
> > is like below with changing the '--rw' parameter and enabling the direct
> > IO flag to measure the actual hardware transfer speed in 4K block size.
> >
> > ./fio --filename=/dev/mmcblk0p30 --direct=1 --iodepth=20 --rw=read --bs=4K --size=1G --group_reporting --numjobs=20 --name=test_read
> >
> > My eMMC card working at HS400 Enhanced strobe mode:
> > [ 2.229856] mmc0: new HS400 Enhanced strobe MMC card at address 0001
> > [ 2.237566] mmcblk0: mmc0:0001 HBG4a2 29.1 GiB
> > [ 2.242621] mmcblk0boot0: mmc0:0001 HBG4a2 partition 1 4.00 MiB
> > [ 2.249110] mmcblk0boot1: mmc0:0001 HBG4a2 partition 2 4.00 MiB
> > [ 2.255307] mmcblk0rpmb: mmc0:0001 HBG4a2 partition 3 4.00 MiB, chardev (248:0)
> >
> > 1. Without MMC software queue
> > I tested 5 times for each case and output a average speed.
> >
> > 1) Sequential read:
> > Speed: 59.4MiB/s, 63.4MiB/s, 57.5MiB/s, 57.2MiB/s, 60.8MiB/s
> > Average speed: 59.66MiB/s
> >
> > 2) Random read:
> > Speed: 26.9MiB/s, 26.9MiB/s, 27.1MiB/s, 27.1MiB/s, 27.2MiB/s
> > Average speed: 27.04MiB/s
> >
> > 3) Sequential write:
> > Speed: 71.6MiB/s, 72.5MiB/s, 72.2MiB/s, 64.6MiB/s, 67.5MiB/s
> > Average speed: 69.68MiB/s
> >
> > 4) Random write:
> > Speed: 36.3MiB/s, 35.4MiB/s, 38.6MiB/s, 34MiB/s, 35.5MiB/s
> > Average speed: 35.96MiB/s
> >
> > 2. With MMC software queue
> > I tested 5 times for each case and output a average speed.
> >
> > 1) Sequential read:
> > Speed: 59.2MiB/s, 60.4MiB/s, 63.6MiB/s, 60.3MiB/s, 59.9MiB/s
> > Average speed: 60.68MiB/s
> >
> > 2) Random read:
> > Speed: 31.3MiB/s, 31.4MiB/s, 31.5MiB/s, 31.3MiB/s, 31.3MiB/s
> > Average speed: 31.36MiB/s
> >
> > 3) Sequential write:
> > Speed: 71MiB/s, 71.8MiB/s, 72.3MiB/s, 72.2MiB/s, 71MiB/s
> > Average speed: 71.66MiB/s
> >
> > 4) Random write:
> > Speed: 68.9MiB/s, 68.7MiB/s, 68.8MiB/s, 68.6MiB/s, 68.8MiB/s
> > Average speed: 68.76MiB/s
> >
> > Form above data, we can see the MMC software queue can help to improve some
> > performance obviously for random read and write, though no obvious improvement
> > for sequential read and write.
> >
> > Any comments are welcome. Thanks a lot.
> >
> > Changes from v8:
> > - Add more description in the commit message.
> > - Optimize the failure log when calling cqe_enable().
> >
> > Changes from v7:
> > - Add reviewed tag from Arnd.
> > - Use the 'hsq' acronym for varibles and functions in the core layer.
> > - Check the 'card->ext_csd.cmdq_en' in cqhci.c to make sure the CQE
> > can work normally.
> > - Add a new patch to enable the host software queue for the SD card.
> > - Use the default MMC queue depth for host software queue.
> >
> > Changes from v6:
> > - Change the patch order and set host->always_defer_done = true for the
> > Spreadtrum host driver.
> >
> > Changes from v5:
> > - Modify the condition of defering to complete request suggested by Adrian.
> >
> > Changes from v4:
> > - Add a seperate patch to introduce a variable to defer to complete
> > data requests for some host drivers, when using host software queue.
> >
> > Changes from v3:
> > - Use host software queue instead of sqhci.
> > - Fix random config building issue.
> > - Change queue depth to 32, but still only allow 2 requests in flight.
> > - Update the testing data.
> >
> > Changes from v2:
> > - Remove reference to 'struct cqhci_host' and 'struct cqhci_slot',
> > instead adding 'struct sqhci_host', which is only used by software queue.
> >
> > Changes from v1:
> > - Add request_done ops for sdhci_ops.
> > - Replace virtual command queue with software queue for functions and
> > variables.
> > - Rename the software queue file and add sqhci.h header file.
> >
> > Baolin Wang (5):
> > mmc: Add MMC host software queue support
> > mmc: core: Enable the MMC host software queue for the SD card
> > mmc: host: sdhci: Add request_done ops for struct sdhci_ops
> > mmc: host: sdhci: Add a variable to defer to complete requests if
> > needed
> > mmc: host: sdhci-sprd: Add software queue support
> >
> > drivers/mmc/core/block.c | 61 ++++++++
> > drivers/mmc/core/mmc.c | 18 ++-
> > drivers/mmc/core/queue.c | 22 ++-
> > drivers/mmc/core/sd.c | 10 ++
> > drivers/mmc/host/Kconfig | 8 +
> > drivers/mmc/host/Makefile | 1 +
> > drivers/mmc/host/cqhci.c | 8 +-
> > drivers/mmc/host/mmc_hsq.c | 343 +++++++++++++++++++++++++++++++++++++++++
> > drivers/mmc/host/mmc_hsq.h | 30 ++++
> > drivers/mmc/host/sdhci-sprd.c | 28 ++++
> > drivers/mmc/host/sdhci.c | 14 +-
> > drivers/mmc/host/sdhci.h | 3 +
> > include/linux/mmc/host.h | 3 +
> > 13 files changed, 534 insertions(+), 15 deletions(-)
> > create mode 100644 drivers/mmc/host/mmc_hsq.c
> > create mode 100644 drivers/mmc/host/mmc_hsq.h
> >
> > --
> > 1.7.9.5
> >
>
> Applied for next, thanks! Also, thanks for your patience while moving
> forward during the reviews!

I am very appreciated for you and Arnd's good sugestion when
introducing the hsq.

>
> Note, I did some amending of patch1 to resolve some checkpatch
> warnings. SPDX licence and Kconfig help texts, please have a look and
> tell if there are something that doesn't look good.

Thanks for your help and looks good to me.

2020-06-08 06:38:17

by Bough Chen

[permalink] [raw]
Subject: RE: [PATCH v9 0/5] Add MMC software queue support

> -----Original Message-----
> From: [email protected]
> [mailto:[email protected]] On Behalf Of Baolin Wang
> Sent: 2020年2月19日 9:35
> To: Ulf Hansson <[email protected]>
> Cc: Adrian Hunter <[email protected]>; Asutosh Das
> <[email protected]>; Orson Zhai <[email protected]>; Chunyan
> Zhang <[email protected]>; Arnd Bergmann <[email protected]>; Linus
> Walleij <[email protected]>; Baolin Wang <[email protected]>;
> [email protected]; Linux Kernel Mailing List
> <[email protected]>
> Subject: Re: [PATCH v9 0/5] Add MMC software queue support
>
> On Wed, Feb 19, 2020 at 7:38 AM Ulf Hansson <[email protected]>
> wrote:
> >
> > On Wed, 12 Feb 2020 at 05:14, Baolin Wang <[email protected]>
> wrote:
> > >
> > > Hi All,
> > >
> > > Now the MMC read/write stack will always wait for previous request
> > > is completed by mmc_blk_rw_wait(), before sending a new request to
> > > hardware, or queue a work to complete request, that will bring
> > > context switching overhead, especially for high I/O per second
> > > rates, to affect the IO performance.
> > >
> > > Thus this patch set will introduce the MMC software command queue
> > > support based on command queue engine's interfaces, and set the
> > > queue depth as 64 to allow more requests can be be prepared, merged
> > > and inserted into IO scheduler, but we only allow 2 requests in
> > > flight, that is enough to let the irq handler always trigger the
> > > next request without a context switch, as well as avoiding a long latency.
> > >
> > > Moreover we can expand the MMC software queue interface to support
> > > MMC packed request or packed command instead of adding new
> > > interfaces, according to previosus discussion.
> > >
> > > Below are some comparison data with fio tool. The fio command I used
> > > is like below with changing the '--rw' parameter and enabling the
> > > direct IO flag to measure the actual hardware transfer speed in 4K block
> size.
> > >
> > > ./fio --filename=/dev/mmcblk0p30 --direct=1 --iodepth=20 --rw=read
> > > --bs=4K --size=1G --group_reporting --numjobs=20 --name=test_read
> > >
> > > My eMMC card working at HS400 Enhanced strobe mode:
> > > [ 2.229856] mmc0: new HS400 Enhanced strobe MMC card at address
> 0001
> > > [ 2.237566] mmcblk0: mmc0:0001 HBG4a2 29.1 GiB
> > > [ 2.242621] mmcblk0boot0: mmc0:0001 HBG4a2 partition 1 4.00 MiB
> > > [ 2.249110] mmcblk0boot1: mmc0:0001 HBG4a2 partition 2 4.00 MiB
> > > [ 2.255307] mmcblk0rpmb: mmc0:0001 HBG4a2 partition 3 4.00 MiB,
> chardev (248:0)
> > >
> > > 1. Without MMC software queue
> > > I tested 5 times for each case and output a average speed.
> > >
> > > 1) Sequential read:
> > > Speed: 59.4MiB/s, 63.4MiB/s, 57.5MiB/s, 57.2MiB/s, 60.8MiB/s Average
> > > speed: 59.66MiB/s
> > >
> > > 2) Random read:
> > > Speed: 26.9MiB/s, 26.9MiB/s, 27.1MiB/s, 27.1MiB/s, 27.2MiB/s Average
> > > speed: 27.04MiB/s
> > >
> > > 3) Sequential write:
> > > Speed: 71.6MiB/s, 72.5MiB/s, 72.2MiB/s, 64.6MiB/s, 67.5MiB/s Average
> > > speed: 69.68MiB/s
> > >
> > > 4) Random write:
> > > Speed: 36.3MiB/s, 35.4MiB/s, 38.6MiB/s, 34MiB/s, 35.5MiB/s Average
> > > speed: 35.96MiB/s
> > >
> > > 2. With MMC software queue
> > > I tested 5 times for each case and output a average speed.
> > >
> > > 1) Sequential read:
> > > Speed: 59.2MiB/s, 60.4MiB/s, 63.6MiB/s, 60.3MiB/s, 59.9MiB/s Average
> > > speed: 60.68MiB/s
> > >
> > > 2) Random read:
> > > Speed: 31.3MiB/s, 31.4MiB/s, 31.5MiB/s, 31.3MiB/s, 31.3MiB/s Average
> > > speed: 31.36MiB/s
> > >
> > > 3) Sequential write:
> > > Speed: 71MiB/s, 71.8MiB/s, 72.3MiB/s, 72.2MiB/s, 71MiB/s Average
> > > speed: 71.66MiB/s
> > >
> > > 4) Random write:
> > > Speed: 68.9MiB/s, 68.7MiB/s, 68.8MiB/s, 68.6MiB/s, 68.8MiB/s Average
> > > speed: 68.76MiB/s
> > >
> > > Form above data, we can see the MMC software queue can help to
> > > improve some performance obviously for random read and write, though
> > > no obvious improvement for sequential read and write.
> > >
> > > Any comments are welcome. Thanks a lot.
> > >

Hi Baolin,

I refer to your code, and add the software queue support on i.MX based on the Linux next-20200602, but unfortunately, I see an obvious performance drop when change to use software queue.
I test on our imx850-evk board, with eMMC soldered.
From the result listing below, only random write has a little performance improve, for others, seems performance drop a lot.
I noticed that, this software queue need no-removable card, any other limitation? For host?
From the code logic, software queue complete the request in irq handler, seems no other change, I do not figure out why this will trigger a performance drop on my platform. Any comment would be appreciate!

Without software queue, normal read/write method:
Sequential read: 56MB/s
Random read: 23.5MB/s
Sequential write: 43.7MB/s
Random write: 19MB/s

With mmc software queue:
Sequential read: 33.5MB/s
Random read: 18.7 MB/s
Sequential write: 37.7MB/s
Random write: 19.8MB/s


Here, I also list my change code to support software queue

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index eb85237bf2d6..996b8cc5c381 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -254,6 +254,7 @@ config MMC_SDHCI_ESDHC_IMX
depends on MMC_SDHCI_PLTFM
select MMC_SDHCI_IO_ACCESSORS
select MMC_CQHCI
+ select MMC_HSQ
help
This selects the Freescale eSDHC/uSDHC controller support
found on i.MX25, i.MX35 i.MX5x and i.MX6x.
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 1d7f84b23a22..6f163695b08d 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -29,6 +29,7 @@
#include "sdhci-pltfm.h"
#include "sdhci-esdhc.h"
#include "cqhci.h"
+#include "mmc_hsq.h"

#define ESDHC_SYS_CTRL_DTOCV_MASK 0x0f
#define ESDHC_CTRL_D3CD 0x08
@@ -1220,6 +1221,15 @@ static u32 esdhc_cqhci_irq(struct sdhci_host *host, u32 intmask)
return 0;
}

+static void esdhc_request_done(struct sdhci_host *host, struct mmc_request *mrq)
+{
+ /* Validate if the request was from software queue firstly. */
+ if (mmc_hsq_finalize_request(host->mmc, mrq))
+ return;
+
+ mmc_request_done(host->mmc, mrq);
+}
+
static struct sdhci_ops sdhci_esdhc_ops = {
.read_l = esdhc_readl_le,
.read_w = esdhc_readw_le,
@@ -1237,6 +1247,7 @@ static struct sdhci_ops sdhci_esdhc_ops = {
.set_uhs_signaling = esdhc_set_uhs_signaling,
.reset = esdhc_reset,
.irq = esdhc_cqhci_irq,
+ .request_done = esdhc_request_done,
};

static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
@@ -1301,6 +1312,19 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host)
writel(tmp, host->ioaddr + ESDHC_VEND_SPEC2);

host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ;
+
+ /*
+ * On i.MX8MM, we are running Dual Linux OS, with 1st Linux using SD Card
+ * as rootfs storage, 2nd Linux using eMMC as rootfs storage. We let the
+ * the 1st linux configure power/clock for the 2nd Linux.
+ *
+ * When the 2nd Linux is booting into rootfs stage, we let the 1st Linux
+ * to destroy the 2nd linux, then restart the 2nd linux, we met SDHCI dump.
+ * After we clear the pending interrupt and halt CQCTL, issue gone.
+ */
+ tmp = cqhci_readl(cq_host, CQHCI_IS);
+ cqhci_writel(cq_host, tmp, CQHCI_IS);
+ cqhci_writel(cq_host, CQHCI_HALT, CQHCI_CTL);
}

if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) {
@@ -1351,9 +1375,6 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host)
* After we clear the pending interrupt and halt CQCTL, issue gone.
*/
if (cq_host) {
- tmp = cqhci_readl(cq_host, CQHCI_IS);
- cqhci_writel(cq_host, tmp, CQHCI_IS);
- cqhci_writel(cq_host, CQHCI_HALT, CQHCI_CTL);
}
}
}
@@ -1555,6 +1576,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
struct sdhci_pltfm_host *pltfm_host;
struct sdhci_host *host;
struct cqhci_host *cq_host;
+ struct mmc_hsq *hsq;
int err;
struct pltfm_imx_data *imx_data;

@@ -1664,6 +1686,16 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
err = cqhci_init(cq_host, host->mmc, false);
if (err)
goto disable_ahb_clk;
+ } else if (esdhc_is_usdhc(imx_data)) {
+ hsq = devm_kzalloc(&pdev->dev, sizeof(*hsq), GFP_KERNEL);
+ if (!hsq) {
+ err = -ENOMEM;
+ goto disable_ahb_clk;
+ }
+
+ err = mmc_hsq_init(hsq, host->mmc);
+ if (err)
+ goto disable_ahb_clk;
}

if (of_id)
@@ -1673,6 +1705,11 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
if (err)
goto disable_ahb_clk;

+ if (!mmc_card_is_removable(host->mmc))
+ host->mmc_host_ops.request_atomic = sdhci_request_atomic;
+ else
+ host->always_defer_done = true;
+
sdhci_esdhc_imx_hwinit(host);

err = sdhci_add_host(host);
@@ -1737,6 +1774,8 @@ static int sdhci_esdhc_suspend(struct device *dev)
ret = cqhci_suspend(host->mmc);
if (ret)
return ret;
+ } else if (esdhc_is_usdhc(imx_data)) {
+ mmc_hsq_suspend(host->mmc);
}

if ((imx_data->socdata->flags & ESDHC_FLAG_STATE_LOST_IN_LPMODE) &&
@@ -1764,6 +1803,8 @@ static int sdhci_esdhc_suspend(struct device *dev)
static int sdhci_esdhc_resume(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
int ret;

ret = pinctrl_pm_select_default_state(dev);
@@ -1777,8 +1818,11 @@ static int sdhci_esdhc_resume(struct device *dev)
if (ret)
return ret;

- if (host->mmc->caps2 & MMC_CAP2_CQE)
+ if (host->mmc->caps2 & MMC_CAP2_CQE) {
ret = cqhci_resume(host->mmc);
+ } else if (esdhc_is_usdhc(imx_data)) {
+ mmc_hsq_resume(host->mmc);
+ }

if (!ret)
ret = mmc_gpio_set_cd_wake(host->mmc, false);
@@ -1799,6 +1843,8 @@ static int sdhci_esdhc_runtime_suspend(struct device *dev)
ret = cqhci_suspend(host->mmc);
if (ret)
return ret;
+ } else if (esdhc_is_usdhc(imx_data)) {
+ mmc_hsq_suspend(host->mmc);
}

ret = sdhci_runtime_suspend_host(host);
@@ -1851,8 +1897,11 @@ static int sdhci_esdhc_runtime_resume(struct device *dev)
if (err)
goto disable_ipg_clk;

- if (host->mmc->caps2 & MMC_CAP2_CQE)
+ if (host->mmc->caps2 & MMC_CAP2_CQE) {
err = cqhci_resume(host->mmc);
+ } else if (esdhc_is_usdhc(imx_data)) {
+ mmc_hsq_resume(host->mmc);
+ }

return err;



> > > Changes from v8:
> > > - Add more description in the commit message.
> > > - Optimize the failure log when calling cqe_enable().
> > >
> > > Changes from v7:
> > > - Add reviewed tag from Arnd.
> > > - Use the 'hsq' acronym for varibles and functions in the core layer.
> > > - Check the 'card->ext_csd.cmdq_en' in cqhci.c to make sure the CQE
> > > can work normally.
> > > - Add a new patch to enable the host software queue for the SD card.
> > > - Use the default MMC queue depth for host software queue.
> > >
> > > Changes from v6:
> > > - Change the patch order and set host->always_defer_done = true for
> > > the Spreadtrum host driver.
> > >
> > > Changes from v5:
> > > - Modify the condition of defering to complete request suggested by
> Adrian.
> > >
> > > Changes from v4:
> > > - Add a seperate patch to introduce a variable to defer to complete
> > > data requests for some host drivers, when using host software queue.
> > >
> > > Changes from v3:
> > > - Use host software queue instead of sqhci.
> > > - Fix random config building issue.
> > > - Change queue depth to 32, but still only allow 2 requests in flight.
> > > - Update the testing data.
> > >
> > > Changes from v2:
> > > - Remove reference to 'struct cqhci_host' and 'struct cqhci_slot',
> > > instead adding 'struct sqhci_host', which is only used by software queue.
> > >
> > > Changes from v1:
> > > - Add request_done ops for sdhci_ops.
> > > - Replace virtual command queue with software queue for functions
> > > and variables.
> > > - Rename the software queue file and add sqhci.h header file.
> > >
> > > Baolin Wang (5):
> > > mmc: Add MMC host software queue support
> > > mmc: core: Enable the MMC host software queue for the SD card
> > > mmc: host: sdhci: Add request_done ops for struct sdhci_ops
> > > mmc: host: sdhci: Add a variable to defer to complete requests if
> > > needed
> > > mmc: host: sdhci-sprd: Add software queue support
> > >
> > > drivers/mmc/core/block.c | 61 ++++++++
> > > drivers/mmc/core/mmc.c | 18 ++-
> > > drivers/mmc/core/queue.c | 22 ++-
> > > drivers/mmc/core/sd.c | 10 ++
> > > drivers/mmc/host/Kconfig | 8 +
> > > drivers/mmc/host/Makefile | 1 +
> > > drivers/mmc/host/cqhci.c | 8 +-
> > > drivers/mmc/host/mmc_hsq.c | 343
> +++++++++++++++++++++++++++++++++++++++++
> > > drivers/mmc/host/mmc_hsq.h | 30 ++++
> > > drivers/mmc/host/sdhci-sprd.c | 28 ++++
> > > drivers/mmc/host/sdhci.c | 14 +-
> > > drivers/mmc/host/sdhci.h | 3 +
> > > include/linux/mmc/host.h | 3 +
> > > 13 files changed, 534 insertions(+), 15 deletions(-) create mode
> > > 100644 drivers/mmc/host/mmc_hsq.c create mode 100644
> > > drivers/mmc/host/mmc_hsq.h
> > >
> > > --
> > > 1.7.9.5
> > >
> >
> > Applied for next, thanks! Also, thanks for your patience while moving
> > forward during the reviews!
>
> I am very appreciated for you and Arnd's good sugestion when introducing the
> hsq.
>
> >
> > Note, I did some amending of patch1 to resolve some checkpatch
> > warnings. SPDX licence and Kconfig help texts, please have a look and
> > tell if there are something that doesn't look good.
>
> Thanks for your help and looks good to me.

2020-06-08 11:57:19

by Baolin Wang

[permalink] [raw]
Subject: Re: [PATCH v9 0/5] Add MMC software queue support

Hi Haibo.

On Mon, Jun 8, 2020 at 2:35 PM BOUGH CHEN <[email protected]> wrote:
>
> > -----Original Message-----
> > From: [email protected]
> > [mailto:[email protected]] On Behalf Of Baolin Wang
> > Sent: 2020年2月19日 9:35
> > To: Ulf Hansson <[email protected]>
> > Cc: Adrian Hunter <[email protected]>; Asutosh Das
> > <[email protected]>; Orson Zhai <[email protected]>; Chunyan
> > Zhang <[email protected]>; Arnd Bergmann <[email protected]>; Linus
> > Walleij <[email protected]>; Baolin Wang <[email protected]>;
> > [email protected]; Linux Kernel Mailing List
> > <[email protected]>
> > Subject: Re: [PATCH v9 0/5] Add MMC software queue support
> >
> > On Wed, Feb 19, 2020 at 7:38 AM Ulf Hansson <[email protected]>
> > wrote:
> > >
> > > On Wed, 12 Feb 2020 at 05:14, Baolin Wang <[email protected]>
> > wrote:
> > > >
> > > > Hi All,
> > > >
> > > > Now the MMC read/write stack will always wait for previous request
> > > > is completed by mmc_blk_rw_wait(), before sending a new request to
> > > > hardware, or queue a work to complete request, that will bring
> > > > context switching overhead, especially for high I/O per second
> > > > rates, to affect the IO performance.
> > > >
> > > > Thus this patch set will introduce the MMC software command queue
> > > > support based on command queue engine's interfaces, and set the
> > > > queue depth as 64 to allow more requests can be be prepared, merged
> > > > and inserted into IO scheduler, but we only allow 2 requests in
> > > > flight, that is enough to let the irq handler always trigger the
> > > > next request without a context switch, as well as avoiding a long latency.
> > > >
> > > > Moreover we can expand the MMC software queue interface to support
> > > > MMC packed request or packed command instead of adding new
> > > > interfaces, according to previosus discussion.
> > > >
> > > > Below are some comparison data with fio tool. The fio command I used
> > > > is like below with changing the '--rw' parameter and enabling the
> > > > direct IO flag to measure the actual hardware transfer speed in 4K block
> > size.
> > > >
> > > > ./fio --filename=/dev/mmcblk0p30 --direct=1 --iodepth=20 --rw=read
> > > > --bs=4K --size=1G --group_reporting --numjobs=20 --name=test_read
> > > >
> > > > My eMMC card working at HS400 Enhanced strobe mode:
> > > > [ 2.229856] mmc0: new HS400 Enhanced strobe MMC card at address
> > 0001
> > > > [ 2.237566] mmcblk0: mmc0:0001 HBG4a2 29.1 GiB
> > > > [ 2.242621] mmcblk0boot0: mmc0:0001 HBG4a2 partition 1 4.00 MiB
> > > > [ 2.249110] mmcblk0boot1: mmc0:0001 HBG4a2 partition 2 4.00 MiB
> > > > [ 2.255307] mmcblk0rpmb: mmc0:0001 HBG4a2 partition 3 4.00 MiB,
> > chardev (248:0)
> > > >
> > > > 1. Without MMC software queue
> > > > I tested 5 times for each case and output a average speed.
> > > >
> > > > 1) Sequential read:
> > > > Speed: 59.4MiB/s, 63.4MiB/s, 57.5MiB/s, 57.2MiB/s, 60.8MiB/s Average
> > > > speed: 59.66MiB/s
> > > >
> > > > 2) Random read:
> > > > Speed: 26.9MiB/s, 26.9MiB/s, 27.1MiB/s, 27.1MiB/s, 27.2MiB/s Average
> > > > speed: 27.04MiB/s
> > > >
> > > > 3) Sequential write:
> > > > Speed: 71.6MiB/s, 72.5MiB/s, 72.2MiB/s, 64.6MiB/s, 67.5MiB/s Average
> > > > speed: 69.68MiB/s
> > > >
> > > > 4) Random write:
> > > > Speed: 36.3MiB/s, 35.4MiB/s, 38.6MiB/s, 34MiB/s, 35.5MiB/s Average
> > > > speed: 35.96MiB/s
> > > >
> > > > 2. With MMC software queue
> > > > I tested 5 times for each case and output a average speed.
> > > >
> > > > 1) Sequential read:
> > > > Speed: 59.2MiB/s, 60.4MiB/s, 63.6MiB/s, 60.3MiB/s, 59.9MiB/s Average
> > > > speed: 60.68MiB/s
> > > >
> > > > 2) Random read:
> > > > Speed: 31.3MiB/s, 31.4MiB/s, 31.5MiB/s, 31.3MiB/s, 31.3MiB/s Average
> > > > speed: 31.36MiB/s
> > > >
> > > > 3) Sequential write:
> > > > Speed: 71MiB/s, 71.8MiB/s, 72.3MiB/s, 72.2MiB/s, 71MiB/s Average
> > > > speed: 71.66MiB/s
> > > >
> > > > 4) Random write:
> > > > Speed: 68.9MiB/s, 68.7MiB/s, 68.8MiB/s, 68.6MiB/s, 68.8MiB/s Average
> > > > speed: 68.76MiB/s
> > > >
> > > > Form above data, we can see the MMC software queue can help to
> > > > improve some performance obviously for random read and write, though
> > > > no obvious improvement for sequential read and write.
> > > >
> > > > Any comments are welcome. Thanks a lot.
> > > >
>
> Hi Baolin,
>
> I refer to your code, and add the software queue support on i.MX based on the Linux next-20200602, but unfortunately, I see an obvious performance drop when change to use software queue.
> I test on our imx850-evk board, with eMMC soldered.
> From the result listing below, only random write has a little performance improve, for others, seems performance drop a lot.
> I noticed that, this software queue need no-removable card, any other limitation? For host?
> From the code logic, software queue complete the request in irq handler, seems no other change, I do not figure out why this will trigger a performance drop on my platform. Any comment would be appreciate!

Have you tested with below patches, which introduce an atomic_request
host ops to submit next request in the irq hard handler context to
reduce latency?
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=ed6330330276cba39058e8dbdb28ab8d013d926e
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=a374a72baa817388a04825118b7c1ba13064c8c6
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=98a2642f91a47dcd1215d037c14e0e5de33a247d
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=e872f1e22ea5f678ae42812949477387fda6725b
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=845c939ee22943786a6eb1d13d03c77b19fcc2c8
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=6db96e5810e0a6a345b7d78549de7676ae5b2662
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=48ef8a2a1e5e6a2a189009e880e341ddb452971d
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=61ab64e2f54f4c607428667f83f411cb659843a3

> Without software queue, normal read/write method:
> Sequential read: 56MB/s
> Random read: 23.5MB/s
> Sequential write: 43.7MB/s
> Random write: 19MB/s
>
> With mmc software queue:
> Sequential read: 33.5MB/s
> Random read: 18.7 MB/s
> Sequential write: 37.7MB/s
> Random write: 19.8MB/s
>
>
> Here, I also list my change code to support software queue
>
> diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
> index eb85237bf2d6..996b8cc5c381 100644
> --- a/drivers/mmc/host/Kconfig
> +++ b/drivers/mmc/host/Kconfig
> @@ -254,6 +254,7 @@ config MMC_SDHCI_ESDHC_IMX
> depends on MMC_SDHCI_PLTFM
> select MMC_SDHCI_IO_ACCESSORS
> select MMC_CQHCI
> + select MMC_HSQ
> help
> This selects the Freescale eSDHC/uSDHC controller support
> found on i.MX25, i.MX35 i.MX5x and i.MX6x.
> diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
> index 1d7f84b23a22..6f163695b08d 100644
> --- a/drivers/mmc/host/sdhci-esdhc-imx.c
> +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
> @@ -29,6 +29,7 @@
> #include "sdhci-pltfm.h"
> #include "sdhci-esdhc.h"
> #include "cqhci.h"
> +#include "mmc_hsq.h"
>
> #define ESDHC_SYS_CTRL_DTOCV_MASK 0x0f
> #define ESDHC_CTRL_D3CD 0x08
> @@ -1220,6 +1221,15 @@ static u32 esdhc_cqhci_irq(struct sdhci_host *host, u32 intmask)
> return 0;
> }
>
> +static void esdhc_request_done(struct sdhci_host *host, struct mmc_request *mrq)
> +{
> + /* Validate if the request was from software queue firstly. */
> + if (mmc_hsq_finalize_request(host->mmc, mrq))
> + return;
> +
> + mmc_request_done(host->mmc, mrq);
> +}
> +
> static struct sdhci_ops sdhci_esdhc_ops = {
> .read_l = esdhc_readl_le,
> .read_w = esdhc_readw_le,
> @@ -1237,6 +1247,7 @@ static struct sdhci_ops sdhci_esdhc_ops = {
> .set_uhs_signaling = esdhc_set_uhs_signaling,
> .reset = esdhc_reset,
> .irq = esdhc_cqhci_irq,
> + .request_done = esdhc_request_done,
> };
>
> static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
> @@ -1301,6 +1312,19 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host)
> writel(tmp, host->ioaddr + ESDHC_VEND_SPEC2);
>
> host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ;
> +
> + /*
> + * On i.MX8MM, we are running Dual Linux OS, with 1st Linux using SD Card
> + * as rootfs storage, 2nd Linux using eMMC as rootfs storage. We let the
> + * the 1st linux configure power/clock for the 2nd Linux.
> + *
> + * When the 2nd Linux is booting into rootfs stage, we let the 1st Linux
> + * to destroy the 2nd linux, then restart the 2nd linux, we met SDHCI dump.
> + * After we clear the pending interrupt and halt CQCTL, issue gone.
> + */
> + tmp = cqhci_readl(cq_host, CQHCI_IS);
> + cqhci_writel(cq_host, tmp, CQHCI_IS);
> + cqhci_writel(cq_host, CQHCI_HALT, CQHCI_CTL);
> }
>
> if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) {
> @@ -1351,9 +1375,6 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host)
> * After we clear the pending interrupt and halt CQCTL, issue gone.
> */
> if (cq_host) {
> - tmp = cqhci_readl(cq_host, CQHCI_IS);
> - cqhci_writel(cq_host, tmp, CQHCI_IS);
> - cqhci_writel(cq_host, CQHCI_HALT, CQHCI_CTL);
> }
> }
> }
> @@ -1555,6 +1576,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
> struct sdhci_pltfm_host *pltfm_host;
> struct sdhci_host *host;
> struct cqhci_host *cq_host;
> + struct mmc_hsq *hsq;
> int err;
> struct pltfm_imx_data *imx_data;
>
> @@ -1664,6 +1686,16 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
> err = cqhci_init(cq_host, host->mmc, false);
> if (err)
> goto disable_ahb_clk;
> + } else if (esdhc_is_usdhc(imx_data)) {
> + hsq = devm_kzalloc(&pdev->dev, sizeof(*hsq), GFP_KERNEL);
> + if (!hsq) {
> + err = -ENOMEM;
> + goto disable_ahb_clk;
> + }
> +
> + err = mmc_hsq_init(hsq, host->mmc);
> + if (err)
> + goto disable_ahb_clk;
> }
>
> if (of_id)
> @@ -1673,6 +1705,11 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
> if (err)
> goto disable_ahb_clk;
>
> + if (!mmc_card_is_removable(host->mmc))
> + host->mmc_host_ops.request_atomic = sdhci_request_atomic;
> + else
> + host->always_defer_done = true;
> +
> sdhci_esdhc_imx_hwinit(host);
>
> err = sdhci_add_host(host);
> @@ -1737,6 +1774,8 @@ static int sdhci_esdhc_suspend(struct device *dev)
> ret = cqhci_suspend(host->mmc);
> if (ret)
> return ret;
> + } else if (esdhc_is_usdhc(imx_data)) {
> + mmc_hsq_suspend(host->mmc);
> }
>
> if ((imx_data->socdata->flags & ESDHC_FLAG_STATE_LOST_IN_LPMODE) &&
> @@ -1764,6 +1803,8 @@ static int sdhci_esdhc_suspend(struct device *dev)
> static int sdhci_esdhc_resume(struct device *dev)
> {
> struct sdhci_host *host = dev_get_drvdata(dev);
> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
> + struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
> int ret;
>
> ret = pinctrl_pm_select_default_state(dev);
> @@ -1777,8 +1818,11 @@ static int sdhci_esdhc_resume(struct device *dev)
> if (ret)
> return ret;
>
> - if (host->mmc->caps2 & MMC_CAP2_CQE)
> + if (host->mmc->caps2 & MMC_CAP2_CQE) {
> ret = cqhci_resume(host->mmc);
> + } else if (esdhc_is_usdhc(imx_data)) {
> + mmc_hsq_resume(host->mmc);
> + }
>
> if (!ret)
> ret = mmc_gpio_set_cd_wake(host->mmc, false);
> @@ -1799,6 +1843,8 @@ static int sdhci_esdhc_runtime_suspend(struct device *dev)
> ret = cqhci_suspend(host->mmc);
> if (ret)
> return ret;
> + } else if (esdhc_is_usdhc(imx_data)) {
> + mmc_hsq_suspend(host->mmc);
> }
>
> ret = sdhci_runtime_suspend_host(host);
> @@ -1851,8 +1897,11 @@ static int sdhci_esdhc_runtime_resume(struct device *dev)
> if (err)
> goto disable_ipg_clk;
>
> - if (host->mmc->caps2 & MMC_CAP2_CQE)
> + if (host->mmc->caps2 & MMC_CAP2_CQE) {
> err = cqhci_resume(host->mmc);
> + } else if (esdhc_is_usdhc(imx_data)) {
> + mmc_hsq_resume(host->mmc);
> + }
>
> return err;
>
>
>
> > > > Changes from v8:
> > > > - Add more description in the commit message.
> > > > - Optimize the failure log when calling cqe_enable().
> > > >
> > > > Changes from v7:
> > > > - Add reviewed tag from Arnd.
> > > > - Use the 'hsq' acronym for varibles and functions in the core layer.
> > > > - Check the 'card->ext_csd.cmdq_en' in cqhci.c to make sure the CQE
> > > > can work normally.
> > > > - Add a new patch to enable the host software queue for the SD card.
> > > > - Use the default MMC queue depth for host software queue.
> > > >
> > > > Changes from v6:
> > > > - Change the patch order and set host->always_defer_done = true for
> > > > the Spreadtrum host driver.
> > > >
> > > > Changes from v5:
> > > > - Modify the condition of defering to complete request suggested by
> > Adrian.
> > > >
> > > > Changes from v4:
> > > > - Add a seperate patch to introduce a variable to defer to complete
> > > > data requests for some host drivers, when using host software queue.
> > > >
> > > > Changes from v3:
> > > > - Use host software queue instead of sqhci.
> > > > - Fix random config building issue.
> > > > - Change queue depth to 32, but still only allow 2 requests in flight.
> > > > - Update the testing data.
> > > >
> > > > Changes from v2:
> > > > - Remove reference to 'struct cqhci_host' and 'struct cqhci_slot',
> > > > instead adding 'struct sqhci_host', which is only used by software queue.
> > > >
> > > > Changes from v1:
> > > > - Add request_done ops for sdhci_ops.
> > > > - Replace virtual command queue with software queue for functions
> > > > and variables.
> > > > - Rename the software queue file and add sqhci.h header file.
> > > >
> > > > Baolin Wang (5):
> > > > mmc: Add MMC host software queue support
> > > > mmc: core: Enable the MMC host software queue for the SD card
> > > > mmc: host: sdhci: Add request_done ops for struct sdhci_ops
> > > > mmc: host: sdhci: Add a variable to defer to complete requests if
> > > > needed
> > > > mmc: host: sdhci-sprd: Add software queue support
> > > >
> > > > drivers/mmc/core/block.c | 61 ++++++++
> > > > drivers/mmc/core/mmc.c | 18 ++-
> > > > drivers/mmc/core/queue.c | 22 ++-
> > > > drivers/mmc/core/sd.c | 10 ++
> > > > drivers/mmc/host/Kconfig | 8 +
> > > > drivers/mmc/host/Makefile | 1 +
> > > > drivers/mmc/host/cqhci.c | 8 +-
> > > > drivers/mmc/host/mmc_hsq.c | 343
> > +++++++++++++++++++++++++++++++++++++++++
> > > > drivers/mmc/host/mmc_hsq.h | 30 ++++
> > > > drivers/mmc/host/sdhci-sprd.c | 28 ++++
> > > > drivers/mmc/host/sdhci.c | 14 +-
> > > > drivers/mmc/host/sdhci.h | 3 +
> > > > include/linux/mmc/host.h | 3 +
> > > > 13 files changed, 534 insertions(+), 15 deletions(-) create mode
> > > > 100644 drivers/mmc/host/mmc_hsq.c create mode 100644
> > > > drivers/mmc/host/mmc_hsq.h
> > > >
> > > > --
> > > > 1.7.9.5
> > > >
> > >
> > > Applied for next, thanks! Also, thanks for your patience while moving
> > > forward during the reviews!
> >
> > I am very appreciated for you and Arnd's good sugestion when introducing the
> > hsq.
> >
> > >
> > > Note, I did some amending of patch1 to resolve some checkpatch
> > > warnings. SPDX licence and Kconfig help texts, please have a look and
> > > tell if there are something that doesn't look good.
> >
> > Thanks for your help and looks good to me.



--
Baolin Wang

2020-06-10 02:31:09

by Bough Chen

[permalink] [raw]
Subject: RE: [PATCH v9 0/5] Add MMC software queue support

> -----Original Message-----
> From: Baolin Wang [mailto:[email protected]]
> Sent: 2020年6月8日 19:54
> To: BOUGH CHEN <[email protected]>
> Cc: Ulf Hansson <[email protected]>; Adrian Hunter
> <[email protected]>; Asutosh Das <[email protected]>; Orson
> Zhai <[email protected]>; Chunyan Zhang <[email protected]>; Arnd
> Bergmann <[email protected]>; Linus Walleij <[email protected]>; Baolin
> Wang <[email protected]>; [email protected]; Linux Kernel
> Mailing List <[email protected]>; dl-linux-imx <[email protected]>
> Subject: Re: [PATCH v9 0/5] Add MMC software queue support
>
> Hi Haibo.
>
> On Mon, Jun 8, 2020 at 2:35 PM BOUGH CHEN <[email protected]> wrote:
> >
> > > -----Original Message-----
> > > From: [email protected]
> > > [mailto:[email protected]] On Behalf Of Baolin Wang
> > > Sent: 2020年2月19日 9:35
> > > To: Ulf Hansson <[email protected]>
> > > Cc: Adrian Hunter <[email protected]>; Asutosh Das
> > > <[email protected]>; Orson Zhai <[email protected]>;
> Chunyan
> > > Zhang <[email protected]>; Arnd Bergmann <[email protected]>; Linus
> > > Walleij <[email protected]>; Baolin Wang
> > > <[email protected]>; [email protected]; Linux Kernel
> > > Mailing List <[email protected]>
> > > Subject: Re: [PATCH v9 0/5] Add MMC software queue support
> > >
> > > On Wed, Feb 19, 2020 at 7:38 AM Ulf Hansson <[email protected]>
> > > wrote:
> > > >
> > > > On Wed, 12 Feb 2020 at 05:14, Baolin Wang <[email protected]>
> > > wrote:
> > > > >
> > > > > Hi All,
> > > > >
> > > > > Now the MMC read/write stack will always wait for previous
> > > > > request is completed by mmc_blk_rw_wait(), before sending a new
> > > > > request to hardware, or queue a work to complete request, that
> > > > > will bring context switching overhead, especially for high I/O
> > > > > per second rates, to affect the IO performance.
> > > > >
> > > > > Thus this patch set will introduce the MMC software command
> > > > > queue support based on command queue engine's interfaces, and
> > > > > set the queue depth as 64 to allow more requests can be be
> > > > > prepared, merged and inserted into IO scheduler, but we only
> > > > > allow 2 requests in flight, that is enough to let the irq
> > > > > handler always trigger the next request without a context switch, as
> well as avoiding a long latency.
> > > > >
> > > > > Moreover we can expand the MMC software queue interface to
> > > > > support MMC packed request or packed command instead of adding
> > > > > new interfaces, according to previosus discussion.
> > > > >
> > > > > Below are some comparison data with fio tool. The fio command I
> > > > > used is like below with changing the '--rw' parameter and
> > > > > enabling the direct IO flag to measure the actual hardware
> > > > > transfer speed in 4K block
> > > size.
> > > > >
> > > > > ./fio --filename=/dev/mmcblk0p30 --direct=1 --iodepth=20
> > > > > --rw=read --bs=4K --size=1G --group_reporting --numjobs=20
> > > > > --name=test_read
> > > > >
> > > > > My eMMC card working at HS400 Enhanced strobe mode:
> > > > > [ 2.229856] mmc0: new HS400 Enhanced strobe MMC card at
> address
> > > 0001
> > > > > [ 2.237566] mmcblk0: mmc0:0001 HBG4a2 29.1 GiB
> > > > > [ 2.242621] mmcblk0boot0: mmc0:0001 HBG4a2 partition 1 4.00
> MiB
> > > > > [ 2.249110] mmcblk0boot1: mmc0:0001 HBG4a2 partition 2 4.00
> MiB
> > > > > [ 2.255307] mmcblk0rpmb: mmc0:0001 HBG4a2 partition 3 4.00
> MiB,
> > > chardev (248:0)
> > > > >
> > > > > 1. Without MMC software queue
> > > > > I tested 5 times for each case and output a average speed.
> > > > >
> > > > > 1) Sequential read:
> > > > > Speed: 59.4MiB/s, 63.4MiB/s, 57.5MiB/s, 57.2MiB/s, 60.8MiB/s
> > > > > Average
> > > > > speed: 59.66MiB/s
> > > > >
> > > > > 2) Random read:
> > > > > Speed: 26.9MiB/s, 26.9MiB/s, 27.1MiB/s, 27.1MiB/s, 27.2MiB/s
> > > > > Average
> > > > > speed: 27.04MiB/s
> > > > >
> > > > > 3) Sequential write:
> > > > > Speed: 71.6MiB/s, 72.5MiB/s, 72.2MiB/s, 64.6MiB/s, 67.5MiB/s
> > > > > Average
> > > > > speed: 69.68MiB/s
> > > > >
> > > > > 4) Random write:
> > > > > Speed: 36.3MiB/s, 35.4MiB/s, 38.6MiB/s, 34MiB/s, 35.5MiB/s
> > > > > Average
> > > > > speed: 35.96MiB/s
> > > > >
> > > > > 2. With MMC software queue
> > > > > I tested 5 times for each case and output a average speed.
> > > > >
> > > > > 1) Sequential read:
> > > > > Speed: 59.2MiB/s, 60.4MiB/s, 63.6MiB/s, 60.3MiB/s, 59.9MiB/s
> > > > > Average
> > > > > speed: 60.68MiB/s
> > > > >
> > > > > 2) Random read:
> > > > > Speed: 31.3MiB/s, 31.4MiB/s, 31.5MiB/s, 31.3MiB/s, 31.3MiB/s
> > > > > Average
> > > > > speed: 31.36MiB/s
> > > > >
> > > > > 3) Sequential write:
> > > > > Speed: 71MiB/s, 71.8MiB/s, 72.3MiB/s, 72.2MiB/s, 71MiB/s Average
> > > > > speed: 71.66MiB/s
> > > > >
> > > > > 4) Random write:
> > > > > Speed: 68.9MiB/s, 68.7MiB/s, 68.8MiB/s, 68.6MiB/s, 68.8MiB/s
> > > > > Average
> > > > > speed: 68.76MiB/s
> > > > >
> > > > > Form above data, we can see the MMC software queue can help to
> > > > > improve some performance obviously for random read and write,
> > > > > though no obvious improvement for sequential read and write.
> > > > >
> > > > > Any comments are welcome. Thanks a lot.
> > > > >
> >
> > Hi Baolin,
> >
> > I refer to your code, and add the software queue support on i.MX based on
> the Linux next-20200602, but unfortunately, I see an obvious performance drop
> when change to use software queue.
> > I test on our imx850-evk board, with eMMC soldered.
> > From the result listing below, only random write has a little performance
> improve, for others, seems performance drop a lot.
> > I noticed that, this software queue need no-removable card, any other
> limitation? For host?
> > From the code logic, software queue complete the request in irq handler,
> seems no other change, I do not figure out why this will trigger a performance
> drop on my platform. Any comment would be appreciate!
>
> Have you tested with below patches, which introduce an atomic_request host
> ops to submit next request in the irq hard handler context to reduce latency?

Hi Baolin,

The Linux code base I use is Linux-next-20200602, which already contain all the patch you listed, including the atomic_request.
I do not test the atomic_request alone. I just enable software queue, and this software queue use the atomic request.
So, do you mean, I need to first disable software queue, and just enable the atomic_request, to confirm whether the atomic_request has some performance impact on my platform?

Best Regards
Haibo Chen

> https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.kern
> el.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%2Fco
> mmit%2F%3Fid%3Ded6330330276cba39058e8dbdb28ab8d013d926e&amp;dat
> a=02%7C01%7Chaibo.chen%40nxp.com%7C8618eba906ad4fdb4e1708d80ba2
> c447%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C1%7C6372721409928
> 90127&amp;sdata=JJVYXczOXYUdpdNkcJhGMaO6a6EeZkQ72hF090BMAHY%3
> D&amp;reserved=0
> https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.kern
> el.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%2Fco
> mmit%2F%3Fid%3Da374a72baa817388a04825118b7c1ba13064c8c6&amp;dat
> a=02%7C01%7Chaibo.chen%40nxp.com%7C8618eba906ad4fdb4e1708d80ba2
> c447%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C1%7C6372721409928
> 90127&amp;sdata=RaL685%2FtijHmnmr%2B9wOyr6bN53gLLXpEBgS9wwBqIi8
> %3D&amp;reserved=0
> https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.kern
> el.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%2Fco
> mmit%2F%3Fid%3D98a2642f91a47dcd1215d037c14e0e5de33a247d&amp;dat
> a=02%7C01%7Chaibo.chen%40nxp.com%7C8618eba906ad4fdb4e1708d80ba2
> c447%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C1%7C6372721409928
> 90127&amp;sdata=%2B3TBD1lyYOA7D6gvhw0mikvoALMMlyaf9xPGra%2FCnU
> I%3D&amp;reserved=0
> https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.kern
> el.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%2Fco
> mmit%2F%3Fid%3De872f1e22ea5f678ae42812949477387fda6725b&amp;data
> =02%7C01%7Chaibo.chen%40nxp.com%7C8618eba906ad4fdb4e1708d80ba2c
> 447%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C1%7C63727214099289
> 0127&amp;sdata=7kByREznCyEUzibneJB1JMlXdaW%2FZs0FN1MWSzDAPAg%
> 3D&amp;reserved=0
> https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.kern
> el.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%2Fco
> mmit%2F%3Fid%3D845c939ee22943786a6eb1d13d03c77b19fcc2c8&amp;data
> =02%7C01%7Chaibo.chen%40nxp.com%7C8618eba906ad4fdb4e1708d80ba2c
> 447%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C1%7C63727214099289
> 0127&amp;sdata=zxV8REvhSnBTFeyi9HHjFEPcYYrPJGJpNj%2FcOORY0%2BE%3
> D&amp;reserved=0
> https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.kern
> el.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%2Fco
> mmit%2F%3Fid%3D6db96e5810e0a6a345b7d78549de7676ae5b2662&amp;da
> ta=02%7C01%7Chaibo.chen%40nxp.com%7C8618eba906ad4fdb4e1708d80ba2
> c447%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C1%7C6372721409928
> 90127&amp;sdata=5J26bs7%2FmJbhcU2%2FJRAdvY6BLd2QIJLafjq37sVKfYA%3
> D&amp;reserved=0
> https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.kern
> el.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%2Fco
> mmit%2F%3Fid%3D48ef8a2a1e5e6a2a189009e880e341ddb452971d&amp;dat
> a=02%7C01%7Chaibo.chen%40nxp.com%7C8618eba906ad4fdb4e1708d80ba2
> c447%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C1%7C6372721409928
> 90127&amp;sdata=yM6znnt3BDaLR0G1%2FtWyx1OogCKP2cxErZvvZxDDzbQ%
> 3D&amp;reserved=0
> https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.kern
> el.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%2Fco
> mmit%2F%3Fid%3D61ab64e2f54f4c607428667f83f411cb659843a3&amp;data
> =02%7C01%7Chaibo.chen%40nxp.com%7C8618eba906ad4fdb4e1708d80ba2c
> 447%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C1%7C63727214099289
> 0127&amp;sdata=GZfSBBYZ9eOJfxLPEKCfVUJTcvc6oci6AmeSUCWD8Dc%3D&
> amp;reserved=0
>
> > Without software queue, normal read/write method:
> > Sequential read: 56MB/s
> > Random read: 23.5MB/s
> > Sequential write: 43.7MB/s
> > Random write: 19MB/s
> >
> > With mmc software queue:
> > Sequential read: 33.5MB/s
> > Random read: 18.7 MB/s
> > Sequential write: 37.7MB/s
> > Random write: 19.8MB/s
> >
> >
> > Here, I also list my change code to support software queue
> >
> > diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index
> > eb85237bf2d6..996b8cc5c381 100644
> > --- a/drivers/mmc/host/Kconfig
> > +++ b/drivers/mmc/host/Kconfig
> > @@ -254,6 +254,7 @@ config MMC_SDHCI_ESDHC_IMX
> > depends on MMC_SDHCI_PLTFM
> > select MMC_SDHCI_IO_ACCESSORS
> > select MMC_CQHCI
> > + select MMC_HSQ
> > help
> > This selects the Freescale eSDHC/uSDHC controller support
> > found on i.MX25, i.MX35 i.MX5x and i.MX6x.
> > diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c
> > b/drivers/mmc/host/sdhci-esdhc-imx.c
> > index 1d7f84b23a22..6f163695b08d 100644
> > --- a/drivers/mmc/host/sdhci-esdhc-imx.c
> > +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
> > @@ -29,6 +29,7 @@
> > #include "sdhci-pltfm.h"
> > #include "sdhci-esdhc.h"
> > #include "cqhci.h"
> > +#include "mmc_hsq.h"
> >
> > #define ESDHC_SYS_CTRL_DTOCV_MASK 0x0f
> > #define ESDHC_CTRL_D3CD 0x08
> > @@ -1220,6 +1221,15 @@ static u32 esdhc_cqhci_irq(struct sdhci_host
> *host, u32 intmask)
> > return 0;
> > }
> >
> > +static void esdhc_request_done(struct sdhci_host *host, struct
> > +mmc_request *mrq) {
> > + /* Validate if the request was from software queue firstly. */
> > + if (mmc_hsq_finalize_request(host->mmc, mrq))
> > + return;
> > +
> > + mmc_request_done(host->mmc, mrq); }
> > +
> > static struct sdhci_ops sdhci_esdhc_ops = {
> > .read_l = esdhc_readl_le,
> > .read_w = esdhc_readw_le,
> > @@ -1237,6 +1247,7 @@ static struct sdhci_ops sdhci_esdhc_ops = {
> > .set_uhs_signaling = esdhc_set_uhs_signaling,
> > .reset = esdhc_reset,
> > .irq = esdhc_cqhci_irq,
> > + .request_done = esdhc_request_done,
> > };
> >
> > static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { @@
> > -1301,6 +1312,19 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host
> *host)
> > writel(tmp, host->ioaddr +
> ESDHC_VEND_SPEC2);
> >
> > host->quirks &=
> ~SDHCI_QUIRK_NO_BUSY_IRQ;
> > +
> > + /*
> > + * On i.MX8MM, we are running Dual Linux OS,
> with 1st Linux using SD Card
> > + * as rootfs storage, 2nd Linux using eMMC as
> rootfs storage. We let the
> > + * the 1st linux configure power/clock for the
> 2nd Linux.
> > + *
> > + * When the 2nd Linux is booting into rootfs
> stage, we let the 1st Linux
> > + * to destroy the 2nd linux, then restart the
> 2nd linux, we met SDHCI dump.
> > + * After we clear the pending interrupt and halt
> CQCTL, issue gone.
> > + */
> > + tmp = cqhci_readl(cq_host, CQHCI_IS);
> > + cqhci_writel(cq_host, tmp, CQHCI_IS);
> > + cqhci_writel(cq_host, CQHCI_HALT,
> CQHCI_CTL);
> > }
> >
> > if (imx_data->socdata->flags &
> ESDHC_FLAG_STD_TUNING)
> > { @@ -1351,9 +1375,6 @@ static void sdhci_esdhc_imx_hwinit(struct
> sdhci_host *host)
> > * After we clear the pending interrupt and halt CQCTL,
> issue gone.
> > */
> > if (cq_host) {
> > - tmp = cqhci_readl(cq_host, CQHCI_IS);
> > - cqhci_writel(cq_host, tmp, CQHCI_IS);
> > - cqhci_writel(cq_host, CQHCI_HALT,
> CQHCI_CTL);
> > }
> > }
> > }
> > @@ -1555,6 +1576,7 @@ static int sdhci_esdhc_imx_probe(struct
> platform_device *pdev)
> > struct sdhci_pltfm_host *pltfm_host;
> > struct sdhci_host *host;
> > struct cqhci_host *cq_host;
> > + struct mmc_hsq *hsq;
> > int err;
> > struct pltfm_imx_data *imx_data;
> >
> > @@ -1664,6 +1686,16 @@ static int sdhci_esdhc_imx_probe(struct
> platform_device *pdev)
> > err = cqhci_init(cq_host, host->mmc, false);
> > if (err)
> > goto disable_ahb_clk;
> > + } else if (esdhc_is_usdhc(imx_data)) {
> > + hsq = devm_kzalloc(&pdev->dev, sizeof(*hsq),
> GFP_KERNEL);
> > + if (!hsq) {
> > + err = -ENOMEM;
> > + goto disable_ahb_clk;
> > + }
> > +
> > + err = mmc_hsq_init(hsq, host->mmc);
> > + if (err)
> > + goto disable_ahb_clk;
> > }
> >
> > if (of_id)
> > @@ -1673,6 +1705,11 @@ static int sdhci_esdhc_imx_probe(struct
> platform_device *pdev)
> > if (err)
> > goto disable_ahb_clk;
> >
> > + if (!mmc_card_is_removable(host->mmc))
> > + host->mmc_host_ops.request_atomic =
> sdhci_request_atomic;
> > + else
> > + host->always_defer_done = true;
> > +
> > sdhci_esdhc_imx_hwinit(host);
> >
> > err = sdhci_add_host(host);
> > @@ -1737,6 +1774,8 @@ static int sdhci_esdhc_suspend(struct device
> *dev)
> > ret = cqhci_suspend(host->mmc);
> > if (ret)
> > return ret;
> > + } else if (esdhc_is_usdhc(imx_data)) {
> > + mmc_hsq_suspend(host->mmc);
> > }
> >
> > if ((imx_data->socdata->flags &
> > ESDHC_FLAG_STATE_LOST_IN_LPMODE) && @@ -1764,6 +1803,8 @@
> static int
> > sdhci_esdhc_suspend(struct device *dev) static int
> > sdhci_esdhc_resume(struct device *dev) {
> > struct sdhci_host *host = dev_get_drvdata(dev);
> > + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
> > + struct pltfm_imx_data *imx_data =
> > + sdhci_pltfm_priv(pltfm_host);
> > int ret;
> >
> > ret = pinctrl_pm_select_default_state(dev);
> > @@ -1777,8 +1818,11 @@ static int sdhci_esdhc_resume(struct device
> *dev)
> > if (ret)
> > return ret;
> >
> > - if (host->mmc->caps2 & MMC_CAP2_CQE)
> > + if (host->mmc->caps2 & MMC_CAP2_CQE) {
> > ret = cqhci_resume(host->mmc);
> > + } else if (esdhc_is_usdhc(imx_data)) {
> > + mmc_hsq_resume(host->mmc);
> > + }
> >
> > if (!ret)
> > ret = mmc_gpio_set_cd_wake(host->mmc, false); @@
> > -1799,6 +1843,8 @@ static int sdhci_esdhc_runtime_suspend(struct device
> *dev)
> > ret = cqhci_suspend(host->mmc);
> > if (ret)
> > return ret;
> > + } else if (esdhc_is_usdhc(imx_data)) {
> > + mmc_hsq_suspend(host->mmc);
> > }
> >
> > ret = sdhci_runtime_suspend_host(host); @@ -1851,8 +1897,11
> @@
> > static int sdhci_esdhc_runtime_resume(struct device *dev)
> > if (err)
> > goto disable_ipg_clk;
> >
> > - if (host->mmc->caps2 & MMC_CAP2_CQE)
> > + if (host->mmc->caps2 & MMC_CAP2_CQE) {
> > err = cqhci_resume(host->mmc);
> > + } else if (esdhc_is_usdhc(imx_data)) {
> > + mmc_hsq_resume(host->mmc);
> > + }
> >
> > return err;
> >
> >
> >
> > > > > Changes from v8:
> > > > > - Add more description in the commit message.
> > > > > - Optimize the failure log when calling cqe_enable().
> > > > >
> > > > > Changes from v7:
> > > > > - Add reviewed tag from Arnd.
> > > > > - Use the 'hsq' acronym for varibles and functions in the core layer.
> > > > > - Check the 'card->ext_csd.cmdq_en' in cqhci.c to make sure the
> > > > > CQE can work normally.
> > > > > - Add a new patch to enable the host software queue for the SD card.
> > > > > - Use the default MMC queue depth for host software queue.
> > > > >
> > > > > Changes from v6:
> > > > > - Change the patch order and set host->always_defer_done = true
> > > > > for the Spreadtrum host driver.
> > > > >
> > > > > Changes from v5:
> > > > > - Modify the condition of defering to complete request
> > > > > suggested by
> > > Adrian.
> > > > >
> > > > > Changes from v4:
> > > > > - Add a seperate patch to introduce a variable to defer to
> > > > > complete data requests for some host drivers, when using host
> software queue.
> > > > >
> > > > > Changes from v3:
> > > > > - Use host software queue instead of sqhci.
> > > > > - Fix random config building issue.
> > > > > - Change queue depth to 32, but still only allow 2 requests in flight.
> > > > > - Update the testing data.
> > > > >
> > > > > Changes from v2:
> > > > > - Remove reference to 'struct cqhci_host' and 'struct
> > > > > cqhci_slot', instead adding 'struct sqhci_host', which is only used by
> software queue.
> > > > >
> > > > > Changes from v1:
> > > > > - Add request_done ops for sdhci_ops.
> > > > > - Replace virtual command queue with software queue for
> > > > > functions and variables.
> > > > > - Rename the software queue file and add sqhci.h header file.
> > > > >
> > > > > Baolin Wang (5):
> > > > > mmc: Add MMC host software queue support
> > > > > mmc: core: Enable the MMC host software queue for the SD card
> > > > > mmc: host: sdhci: Add request_done ops for struct sdhci_ops
> > > > > mmc: host: sdhci: Add a variable to defer to complete requests if
> > > > > needed
> > > > > mmc: host: sdhci-sprd: Add software queue support
> > > > >
> > > > > drivers/mmc/core/block.c | 61 ++++++++
> > > > > drivers/mmc/core/mmc.c | 18 ++-
> > > > > drivers/mmc/core/queue.c | 22 ++-
> > > > > drivers/mmc/core/sd.c | 10 ++
> > > > > drivers/mmc/host/Kconfig | 8 +
> > > > > drivers/mmc/host/Makefile | 1 +
> > > > > drivers/mmc/host/cqhci.c | 8 +-
> > > > > drivers/mmc/host/mmc_hsq.c | 343
> > > +++++++++++++++++++++++++++++++++++++++++
> > > > > drivers/mmc/host/mmc_hsq.h | 30 ++++
> > > > > drivers/mmc/host/sdhci-sprd.c | 28 ++++
> > > > > drivers/mmc/host/sdhci.c | 14 +-
> > > > > drivers/mmc/host/sdhci.h | 3 +
> > > > > include/linux/mmc/host.h | 3 +
> > > > > 13 files changed, 534 insertions(+), 15 deletions(-) create
> > > > > mode
> > > > > 100644 drivers/mmc/host/mmc_hsq.c create mode 100644
> > > > > drivers/mmc/host/mmc_hsq.h
> > > > >
> > > > > --
> > > > > 1.7.9.5
> > > > >
> > > >
> > > > Applied for next, thanks! Also, thanks for your patience while
> > > > moving forward during the reviews!
> > >
> > > I am very appreciated for you and Arnd's good sugestion when
> > > introducing the hsq.
> > >
> > > >
> > > > Note, I did some amending of patch1 to resolve some checkpatch
> > > > warnings. SPDX licence and Kconfig help texts, please have a look
> > > > and tell if there are something that doesn't look good.
> > >
> > > Thanks for your help and looks good to me.
>
>
>
> --
> Baolin Wang

2020-06-14 15:08:43

by Baolin Wang

[permalink] [raw]
Subject: Re: [PATCH v9 0/5] Add MMC software queue support

On Wed, Jun 10, 2020 at 10:26 AM BOUGH CHEN <[email protected]> wrote:
>
> > -----Original Message-----
> > From: Baolin Wang [mailto:[email protected]]
> > Sent: 2020年6月8日 19:54
> > To: BOUGH CHEN <[email protected]>
> > Cc: Ulf Hansson <[email protected]>; Adrian Hunter
> > <[email protected]>; Asutosh Das <[email protected]>; Orson
> > Zhai <[email protected]>; Chunyan Zhang <[email protected]>; Arnd
> > Bergmann <[email protected]>; Linus Walleij <[email protected]>; Baolin
> > Wang <[email protected]>; [email protected]; Linux Kernel
> > Mailing List <[email protected]>; dl-linux-imx <[email protected]>
> > Subject: Re: [PATCH v9 0/5] Add MMC software queue support
> >
> > Hi Haibo.
> >
> > On Mon, Jun 8, 2020 at 2:35 PM BOUGH CHEN <[email protected]> wrote:
> > >
> > > > -----Original Message-----
> > > > From: [email protected]
> > > > [mailto:[email protected]] On Behalf Of Baolin Wang
> > > > Sent: 2020年2月19日 9:35
> > > > To: Ulf Hansson <[email protected]>
> > > > Cc: Adrian Hunter <[email protected]>; Asutosh Das
> > > > <[email protected]>; Orson Zhai <[email protected]>;
> > Chunyan
> > > > Zhang <[email protected]>; Arnd Bergmann <[email protected]>; Linus
> > > > Walleij <[email protected]>; Baolin Wang
> > > > <[email protected]>; [email protected]; Linux Kernel
> > > > Mailing List <[email protected]>
> > > > Subject: Re: [PATCH v9 0/5] Add MMC software queue support
> > > >
> > > > On Wed, Feb 19, 2020 at 7:38 AM Ulf Hansson <[email protected]>
> > > > wrote:
> > > > >
> > > > > On Wed, 12 Feb 2020 at 05:14, Baolin Wang <[email protected]>
> > > > wrote:
> > > > > >
> > > > > > Hi All,
> > > > > >
> > > > > > Now the MMC read/write stack will always wait for previous
> > > > > > request is completed by mmc_blk_rw_wait(), before sending a new
> > > > > > request to hardware, or queue a work to complete request, that
> > > > > > will bring context switching overhead, especially for high I/O
> > > > > > per second rates, to affect the IO performance.
> > > > > >
> > > > > > Thus this patch set will introduce the MMC software command
> > > > > > queue support based on command queue engine's interfaces, and
> > > > > > set the queue depth as 64 to allow more requests can be be
> > > > > > prepared, merged and inserted into IO scheduler, but we only
> > > > > > allow 2 requests in flight, that is enough to let the irq
> > > > > > handler always trigger the next request without a context switch, as
> > well as avoiding a long latency.
> > > > > >
> > > > > > Moreover we can expand the MMC software queue interface to
> > > > > > support MMC packed request or packed command instead of adding
> > > > > > new interfaces, according to previosus discussion.
> > > > > >
> > > > > > Below are some comparison data with fio tool. The fio command I
> > > > > > used is like below with changing the '--rw' parameter and
> > > > > > enabling the direct IO flag to measure the actual hardware
> > > > > > transfer speed in 4K block
> > > > size.
> > > > > >
> > > > > > ./fio --filename=/dev/mmcblk0p30 --direct=1 --iodepth=20
> > > > > > --rw=read --bs=4K --size=1G --group_reporting --numjobs=20
> > > > > > --name=test_read
> > > > > >
> > > > > > My eMMC card working at HS400 Enhanced strobe mode:
> > > > > > [ 2.229856] mmc0: new HS400 Enhanced strobe MMC card at
> > address
> > > > 0001
> > > > > > [ 2.237566] mmcblk0: mmc0:0001 HBG4a2 29.1 GiB
> > > > > > [ 2.242621] mmcblk0boot0: mmc0:0001 HBG4a2 partition 1 4.00
> > MiB
> > > > > > [ 2.249110] mmcblk0boot1: mmc0:0001 HBG4a2 partition 2 4.00
> > MiB
> > > > > > [ 2.255307] mmcblk0rpmb: mmc0:0001 HBG4a2 partition 3 4.00
> > MiB,
> > > > chardev (248:0)
> > > > > >
> > > > > > 1. Without MMC software queue
> > > > > > I tested 5 times for each case and output a average speed.
> > > > > >
> > > > > > 1) Sequential read:
> > > > > > Speed: 59.4MiB/s, 63.4MiB/s, 57.5MiB/s, 57.2MiB/s, 60.8MiB/s
> > > > > > Average
> > > > > > speed: 59.66MiB/s
> > > > > >
> > > > > > 2) Random read:
> > > > > > Speed: 26.9MiB/s, 26.9MiB/s, 27.1MiB/s, 27.1MiB/s, 27.2MiB/s
> > > > > > Average
> > > > > > speed: 27.04MiB/s
> > > > > >
> > > > > > 3) Sequential write:
> > > > > > Speed: 71.6MiB/s, 72.5MiB/s, 72.2MiB/s, 64.6MiB/s, 67.5MiB/s
> > > > > > Average
> > > > > > speed: 69.68MiB/s
> > > > > >
> > > > > > 4) Random write:
> > > > > > Speed: 36.3MiB/s, 35.4MiB/s, 38.6MiB/s, 34MiB/s, 35.5MiB/s
> > > > > > Average
> > > > > > speed: 35.96MiB/s
> > > > > >
> > > > > > 2. With MMC software queue
> > > > > > I tested 5 times for each case and output a average speed.
> > > > > >
> > > > > > 1) Sequential read:
> > > > > > Speed: 59.2MiB/s, 60.4MiB/s, 63.6MiB/s, 60.3MiB/s, 59.9MiB/s
> > > > > > Average
> > > > > > speed: 60.68MiB/s
> > > > > >
> > > > > > 2) Random read:
> > > > > > Speed: 31.3MiB/s, 31.4MiB/s, 31.5MiB/s, 31.3MiB/s, 31.3MiB/s
> > > > > > Average
> > > > > > speed: 31.36MiB/s
> > > > > >
> > > > > > 3) Sequential write:
> > > > > > Speed: 71MiB/s, 71.8MiB/s, 72.3MiB/s, 72.2MiB/s, 71MiB/s Average
> > > > > > speed: 71.66MiB/s
> > > > > >
> > > > > > 4) Random write:
> > > > > > Speed: 68.9MiB/s, 68.7MiB/s, 68.8MiB/s, 68.6MiB/s, 68.8MiB/s
> > > > > > Average
> > > > > > speed: 68.76MiB/s
> > > > > >
> > > > > > Form above data, we can see the MMC software queue can help to
> > > > > > improve some performance obviously for random read and write,
> > > > > > though no obvious improvement for sequential read and write.
> > > > > >
> > > > > > Any comments are welcome. Thanks a lot.
> > > > > >
> > >
> > > Hi Baolin,
> > >
> > > I refer to your code, and add the software queue support on i.MX based on
> > the Linux next-20200602, but unfortunately, I see an obvious performance drop
> > when change to use software queue.
> > > I test on our imx850-evk board, with eMMC soldered.
> > > From the result listing below, only random write has a little performance
> > improve, for others, seems performance drop a lot.
> > > I noticed that, this software queue need no-removable card, any other
> > limitation? For host?
> > > From the code logic, software queue complete the request in irq handler,
> > seems no other change, I do not figure out why this will trigger a performance
> > drop on my platform. Any comment would be appreciate!
> >
> > Have you tested with below patches, which introduce an atomic_request host
> > ops to submit next request in the irq hard handler context to reduce latency?
>
> Hi Baolin,
>
> The Linux code base I use is Linux-next-20200602, which already contain all the patch you listed, including the atomic_request.
> I do not test the atomic_request alone. I just enable software queue, and this software queue use the atomic request.
> So, do you mean, I need to first disable software queue, and just enable the atomic_request, to confirm whether the atomic_request has some performance impact on my platform?

NO, the HSQ will support atomic_request ops, and I think you should
implement the atomic_request ops in your driver if possible, like
below patch:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=61ab64e2f54f4c607428667f83f411cb659843a3

> > > Without software queue, normal read/write method:
> > > Sequential read: 56MB/s
> > > Random read: 23.5MB/s
> > > Sequential write: 43.7MB/s
> > > Random write: 19MB/s
> > >
> > > With mmc software queue:
> > > Sequential read: 33.5MB/s
> > > Random read: 18.7 MB/s
> > > Sequential write: 37.7MB/s
> > > Random write: 19.8MB/s
> > >
> > >
> > > Here, I also list my change code to support software queue
> > >
> > > diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index
> > > eb85237bf2d6..996b8cc5c381 100644
> > > --- a/drivers/mmc/host/Kconfig
> > > +++ b/drivers/mmc/host/Kconfig
> > > @@ -254,6 +254,7 @@ config MMC_SDHCI_ESDHC_IMX
> > > depends on MMC_SDHCI_PLTFM
> > > select MMC_SDHCI_IO_ACCESSORS
> > > select MMC_CQHCI
> > > + select MMC_HSQ
> > > help
> > > This selects the Freescale eSDHC/uSDHC controller support
> > > found on i.MX25, i.MX35 i.MX5x and i.MX6x.
> > > diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c
> > > b/drivers/mmc/host/sdhci-esdhc-imx.c
> > > index 1d7f84b23a22..6f163695b08d 100644
> > > --- a/drivers/mmc/host/sdhci-esdhc-imx.c
> > > +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
> > > @@ -29,6 +29,7 @@
> > > #include "sdhci-pltfm.h"
> > > #include "sdhci-esdhc.h"
> > > #include "cqhci.h"
> > > +#include "mmc_hsq.h"
> > >
> > > #define ESDHC_SYS_CTRL_DTOCV_MASK 0x0f
> > > #define ESDHC_CTRL_D3CD 0x08
> > > @@ -1220,6 +1221,15 @@ static u32 esdhc_cqhci_irq(struct sdhci_host
> > *host, u32 intmask)
> > > return 0;
> > > }
> > >
> > > +static void esdhc_request_done(struct sdhci_host *host, struct
> > > +mmc_request *mrq) {
> > > + /* Validate if the request was from software queue firstly. */
> > > + if (mmc_hsq_finalize_request(host->mmc, mrq))
> > > + return;
> > > +
> > > + mmc_request_done(host->mmc, mrq); }
> > > +
> > > static struct sdhci_ops sdhci_esdhc_ops = {
> > > .read_l = esdhc_readl_le,
> > > .read_w = esdhc_readw_le,
> > > @@ -1237,6 +1247,7 @@ static struct sdhci_ops sdhci_esdhc_ops = {
> > > .set_uhs_signaling = esdhc_set_uhs_signaling,
> > > .reset = esdhc_reset,
> > > .irq = esdhc_cqhci_irq,
> > > + .request_done = esdhc_request_done,
> > > };
> > >
> > > static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { @@
> > > -1301,6 +1312,19 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host
> > *host)
> > > writel(tmp, host->ioaddr +
> > ESDHC_VEND_SPEC2);
> > >
> > > host->quirks &=
> > ~SDHCI_QUIRK_NO_BUSY_IRQ;
> > > +
> > > + /*
> > > + * On i.MX8MM, we are running Dual Linux OS,
> > with 1st Linux using SD Card
> > > + * as rootfs storage, 2nd Linux using eMMC as
> > rootfs storage. We let the
> > > + * the 1st linux configure power/clock for the
> > 2nd Linux.
> > > + *
> > > + * When the 2nd Linux is booting into rootfs
> > stage, we let the 1st Linux
> > > + * to destroy the 2nd linux, then restart the
> > 2nd linux, we met SDHCI dump.
> > > + * After we clear the pending interrupt and halt
> > CQCTL, issue gone.
> > > + */
> > > + tmp = cqhci_readl(cq_host, CQHCI_IS);
> > > + cqhci_writel(cq_host, tmp, CQHCI_IS);
> > > + cqhci_writel(cq_host, CQHCI_HALT,
> > CQHCI_CTL);
> > > }
> > >
> > > if (imx_data->socdata->flags &
> > ESDHC_FLAG_STD_TUNING)
> > > { @@ -1351,9 +1375,6 @@ static void sdhci_esdhc_imx_hwinit(struct
> > sdhci_host *host)
> > > * After we clear the pending interrupt and halt CQCTL,
> > issue gone.
> > > */
> > > if (cq_host) {
> > > - tmp = cqhci_readl(cq_host, CQHCI_IS);
> > > - cqhci_writel(cq_host, tmp, CQHCI_IS);
> > > - cqhci_writel(cq_host, CQHCI_HALT,
> > CQHCI_CTL);
> > > }
> > > }
> > > }
> > > @@ -1555,6 +1576,7 @@ static int sdhci_esdhc_imx_probe(struct
> > platform_device *pdev)
> > > struct sdhci_pltfm_host *pltfm_host;
> > > struct sdhci_host *host;
> > > struct cqhci_host *cq_host;
> > > + struct mmc_hsq *hsq;
> > > int err;
> > > struct pltfm_imx_data *imx_data;
> > >
> > > @@ -1664,6 +1686,16 @@ static int sdhci_esdhc_imx_probe(struct
> > platform_device *pdev)
> > > err = cqhci_init(cq_host, host->mmc, false);
> > > if (err)
> > > goto disable_ahb_clk;
> > > + } else if (esdhc_is_usdhc(imx_data)) {
> > > + hsq = devm_kzalloc(&pdev->dev, sizeof(*hsq),
> > GFP_KERNEL);
> > > + if (!hsq) {
> > > + err = -ENOMEM;
> > > + goto disable_ahb_clk;
> > > + }
> > > +
> > > + err = mmc_hsq_init(hsq, host->mmc);
> > > + if (err)
> > > + goto disable_ahb_clk;
> > > }
> > >
> > > if (of_id)
> > > @@ -1673,6 +1705,11 @@ static int sdhci_esdhc_imx_probe(struct
> > platform_device *pdev)
> > > if (err)
> > > goto disable_ahb_clk;
> > >
> > > + if (!mmc_card_is_removable(host->mmc))
> > > + host->mmc_host_ops.request_atomic =
> > sdhci_request_atomic;
> > > + else
> > > + host->always_defer_done = true;
> > > +
> > > sdhci_esdhc_imx_hwinit(host);
> > >
> > > err = sdhci_add_host(host);
> > > @@ -1737,6 +1774,8 @@ static int sdhci_esdhc_suspend(struct device
> > *dev)
> > > ret = cqhci_suspend(host->mmc);
> > > if (ret)
> > > return ret;
> > > + } else if (esdhc_is_usdhc(imx_data)) {
> > > + mmc_hsq_suspend(host->mmc);
> > > }
> > >
> > > if ((imx_data->socdata->flags &
> > > ESDHC_FLAG_STATE_LOST_IN_LPMODE) && @@ -1764,6 +1803,8 @@
> > static int
> > > sdhci_esdhc_suspend(struct device *dev) static int
> > > sdhci_esdhc_resume(struct device *dev) {
> > > struct sdhci_host *host = dev_get_drvdata(dev);
> > > + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
> > > + struct pltfm_imx_data *imx_data =
> > > + sdhci_pltfm_priv(pltfm_host);
> > > int ret;
> > >
> > > ret = pinctrl_pm_select_default_state(dev);
> > > @@ -1777,8 +1818,11 @@ static int sdhci_esdhc_resume(struct device
> > *dev)
> > > if (ret)
> > > return ret;
> > >
> > > - if (host->mmc->caps2 & MMC_CAP2_CQE)
> > > + if (host->mmc->caps2 & MMC_CAP2_CQE) {
> > > ret = cqhci_resume(host->mmc);
> > > + } else if (esdhc_is_usdhc(imx_data)) {
> > > + mmc_hsq_resume(host->mmc);
> > > + }
> > >
> > > if (!ret)
> > > ret = mmc_gpio_set_cd_wake(host->mmc, false); @@
> > > -1799,6 +1843,8 @@ static int sdhci_esdhc_runtime_suspend(struct device
> > *dev)
> > > ret = cqhci_suspend(host->mmc);
> > > if (ret)
> > > return ret;
> > > + } else if (esdhc_is_usdhc(imx_data)) {
> > > + mmc_hsq_suspend(host->mmc);
> > > }
> > >
> > > ret = sdhci_runtime_suspend_host(host); @@ -1851,8 +1897,11
> > @@
> > > static int sdhci_esdhc_runtime_resume(struct device *dev)
> > > if (err)
> > > goto disable_ipg_clk;
> > >
> > > - if (host->mmc->caps2 & MMC_CAP2_CQE)
> > > + if (host->mmc->caps2 & MMC_CAP2_CQE) {
> > > err = cqhci_resume(host->mmc);
> > > + } else if (esdhc_is_usdhc(imx_data)) {
> > > + mmc_hsq_resume(host->mmc);
> > > + }
> > >
> > > return err;
> > >
> > >
> > >
> > > > > > Changes from v8:
> > > > > > - Add more description in the commit message.
> > > > > > - Optimize the failure log when calling cqe_enable().
> > > > > >
> > > > > > Changes from v7:
> > > > > > - Add reviewed tag from Arnd.
> > > > > > - Use the 'hsq' acronym for varibles and functions in the core layer.
> > > > > > - Check the 'card->ext_csd.cmdq_en' in cqhci.c to make sure the
> > > > > > CQE can work normally.
> > > > > > - Add a new patch to enable the host software queue for the SD card.
> > > > > > - Use the default MMC queue depth for host software queue.
> > > > > >
> > > > > > Changes from v6:
> > > > > > - Change the patch order and set host->always_defer_done = true
> > > > > > for the Spreadtrum host driver.
> > > > > >
> > > > > > Changes from v5:
> > > > > > - Modify the condition of defering to complete request
> > > > > > suggested by
> > > > Adrian.
> > > > > >
> > > > > > Changes from v4:
> > > > > > - Add a seperate patch to introduce a variable to defer to
> > > > > > complete data requests for some host drivers, when using host
> > software queue.
> > > > > >
> > > > > > Changes from v3:
> > > > > > - Use host software queue instead of sqhci.
> > > > > > - Fix random config building issue.
> > > > > > - Change queue depth to 32, but still only allow 2 requests in flight.
> > > > > > - Update the testing data.
> > > > > >
> > > > > > Changes from v2:
> > > > > > - Remove reference to 'struct cqhci_host' and 'struct
> > > > > > cqhci_slot', instead adding 'struct sqhci_host', which is only used by
> > software queue.
> > > > > >
> > > > > > Changes from v1:
> > > > > > - Add request_done ops for sdhci_ops.
> > > > > > - Replace virtual command queue with software queue for
> > > > > > functions and variables.
> > > > > > - Rename the software queue file and add sqhci.h header file.
> > > > > >
> > > > > > Baolin Wang (5):
> > > > > > mmc: Add MMC host software queue support
> > > > > > mmc: core: Enable the MMC host software queue for the SD card
> > > > > > mmc: host: sdhci: Add request_done ops for struct sdhci_ops
> > > > > > mmc: host: sdhci: Add a variable to defer to complete requests if
> > > > > > needed
> > > > > > mmc: host: sdhci-sprd: Add software queue support
> > > > > >
> > > > > > drivers/mmc/core/block.c | 61 ++++++++
> > > > > > drivers/mmc/core/mmc.c | 18 ++-
> > > > > > drivers/mmc/core/queue.c | 22 ++-
> > > > > > drivers/mmc/core/sd.c | 10 ++
> > > > > > drivers/mmc/host/Kconfig | 8 +
> > > > > > drivers/mmc/host/Makefile | 1 +
> > > > > > drivers/mmc/host/cqhci.c | 8 +-
> > > > > > drivers/mmc/host/mmc_hsq.c | 343
> > > > +++++++++++++++++++++++++++++++++++++++++
> > > > > > drivers/mmc/host/mmc_hsq.h | 30 ++++
> > > > > > drivers/mmc/host/sdhci-sprd.c | 28 ++++
> > > > > > drivers/mmc/host/sdhci.c | 14 +-
> > > > > > drivers/mmc/host/sdhci.h | 3 +
> > > > > > include/linux/mmc/host.h | 3 +
> > > > > > 13 files changed, 534 insertions(+), 15 deletions(-) create
> > > > > > mode
> > > > > > 100644 drivers/mmc/host/mmc_hsq.c create mode 100644
> > > > > > drivers/mmc/host/mmc_hsq.h
> > > > > >
> > > > > > --
> > > > > > 1.7.9.5
> > > > > >
> > > > >
> > > > > Applied for next, thanks! Also, thanks for your patience while
> > > > > moving forward during the reviews!
> > > >
> > > > I am very appreciated for you and Arnd's good sugestion when
> > > > introducing the hsq.
> > > >
> > > > >
> > > > > Note, I did some amending of patch1 to resolve some checkpatch
> > > > > warnings. SPDX licence and Kconfig help texts, please have a look
> > > > > and tell if there are something that doesn't look good.
> > > >
> > > > Thanks for your help and looks good to me.
> >
> >
> >
> > --
> > Baolin Wang



--
Baolin Wang

2020-06-14 23:28:06

by Baolin Wang

[permalink] [raw]
Subject: Re: [PATCH v9 0/5] Add MMC software queue support

On Sun, Jun 14, 2020 at 11:05 PM Baolin Wang <[email protected]> wrote:
>
> On Wed, Jun 10, 2020 at 10:26 AM BOUGH CHEN <[email protected]> wrote:
> >
> > > -----Original Message-----
> > > From: Baolin Wang [mailto:[email protected]]
> > > Sent: 2020年6月8日 19:54
> > > To: BOUGH CHEN <[email protected]>
> > > Cc: Ulf Hansson <[email protected]>; Adrian Hunter
> > > <[email protected]>; Asutosh Das <[email protected]>; Orson
> > > Zhai <[email protected]>; Chunyan Zhang <[email protected]>; Arnd
> > > Bergmann <[email protected]>; Linus Walleij <[email protected]>; Baolin
> > > Wang <[email protected]>; [email protected]; Linux Kernel
> > > Mailing List <[email protected]>; dl-linux-imx <[email protected]>
> > > Subject: Re: [PATCH v9 0/5] Add MMC software queue support
> > >
> > > Hi Haibo.
> > >
> > > On Mon, Jun 8, 2020 at 2:35 PM BOUGH CHEN <[email protected]> wrote:
> > > >
> > > > > -----Original Message-----
> > > > > From: [email protected]
> > > > > [mailto:[email protected]] On Behalf Of Baolin Wang
> > > > > Sent: 2020年2月19日 9:35
> > > > > To: Ulf Hansson <[email protected]>
> > > > > Cc: Adrian Hunter <[email protected]>; Asutosh Das
> > > > > <[email protected]>; Orson Zhai <[email protected]>;
> > > Chunyan
> > > > > Zhang <[email protected]>; Arnd Bergmann <[email protected]>; Linus
> > > > > Walleij <[email protected]>; Baolin Wang
> > > > > <[email protected]>; [email protected]; Linux Kernel
> > > > > Mailing List <[email protected]>
> > > > > Subject: Re: [PATCH v9 0/5] Add MMC software queue support
> > > > >
> > > > > On Wed, Feb 19, 2020 at 7:38 AM Ulf Hansson <[email protected]>
> > > > > wrote:
> > > > > >
> > > > > > On Wed, 12 Feb 2020 at 05:14, Baolin Wang <[email protected]>
> > > > > wrote:
> > > > > > >
> > > > > > > Hi All,
> > > > > > >
> > > > > > > Now the MMC read/write stack will always wait for previous
> > > > > > > request is completed by mmc_blk_rw_wait(), before sending a new
> > > > > > > request to hardware, or queue a work to complete request, that
> > > > > > > will bring context switching overhead, especially for high I/O
> > > > > > > per second rates, to affect the IO performance.
> > > > > > >
> > > > > > > Thus this patch set will introduce the MMC software command
> > > > > > > queue support based on command queue engine's interfaces, and
> > > > > > > set the queue depth as 64 to allow more requests can be be
> > > > > > > prepared, merged and inserted into IO scheduler, but we only
> > > > > > > allow 2 requests in flight, that is enough to let the irq
> > > > > > > handler always trigger the next request without a context switch, as
> > > well as avoiding a long latency.
> > > > > > >
> > > > > > > Moreover we can expand the MMC software queue interface to
> > > > > > > support MMC packed request or packed command instead of adding
> > > > > > > new interfaces, according to previosus discussion.
> > > > > > >
> > > > > > > Below are some comparison data with fio tool. The fio command I
> > > > > > > used is like below with changing the '--rw' parameter and
> > > > > > > enabling the direct IO flag to measure the actual hardware
> > > > > > > transfer speed in 4K block
> > > > > size.
> > > > > > >
> > > > > > > ./fio --filename=/dev/mmcblk0p30 --direct=1 --iodepth=20
> > > > > > > --rw=read --bs=4K --size=1G --group_reporting --numjobs=20
> > > > > > > --name=test_read
> > > > > > >
> > > > > > > My eMMC card working at HS400 Enhanced strobe mode:
> > > > > > > [ 2.229856] mmc0: new HS400 Enhanced strobe MMC card at
> > > address
> > > > > 0001
> > > > > > > [ 2.237566] mmcblk0: mmc0:0001 HBG4a2 29.1 GiB
> > > > > > > [ 2.242621] mmcblk0boot0: mmc0:0001 HBG4a2 partition 1 4.00
> > > MiB
> > > > > > > [ 2.249110] mmcblk0boot1: mmc0:0001 HBG4a2 partition 2 4.00
> > > MiB
> > > > > > > [ 2.255307] mmcblk0rpmb: mmc0:0001 HBG4a2 partition 3 4.00
> > > MiB,
> > > > > chardev (248:0)
> > > > > > >
> > > > > > > 1. Without MMC software queue
> > > > > > > I tested 5 times for each case and output a average speed.
> > > > > > >
> > > > > > > 1) Sequential read:
> > > > > > > Speed: 59.4MiB/s, 63.4MiB/s, 57.5MiB/s, 57.2MiB/s, 60.8MiB/s
> > > > > > > Average
> > > > > > > speed: 59.66MiB/s
> > > > > > >
> > > > > > > 2) Random read:
> > > > > > > Speed: 26.9MiB/s, 26.9MiB/s, 27.1MiB/s, 27.1MiB/s, 27.2MiB/s
> > > > > > > Average
> > > > > > > speed: 27.04MiB/s
> > > > > > >
> > > > > > > 3) Sequential write:
> > > > > > > Speed: 71.6MiB/s, 72.5MiB/s, 72.2MiB/s, 64.6MiB/s, 67.5MiB/s
> > > > > > > Average
> > > > > > > speed: 69.68MiB/s
> > > > > > >
> > > > > > > 4) Random write:
> > > > > > > Speed: 36.3MiB/s, 35.4MiB/s, 38.6MiB/s, 34MiB/s, 35.5MiB/s
> > > > > > > Average
> > > > > > > speed: 35.96MiB/s
> > > > > > >
> > > > > > > 2. With MMC software queue
> > > > > > > I tested 5 times for each case and output a average speed.
> > > > > > >
> > > > > > > 1) Sequential read:
> > > > > > > Speed: 59.2MiB/s, 60.4MiB/s, 63.6MiB/s, 60.3MiB/s, 59.9MiB/s
> > > > > > > Average
> > > > > > > speed: 60.68MiB/s
> > > > > > >
> > > > > > > 2) Random read:
> > > > > > > Speed: 31.3MiB/s, 31.4MiB/s, 31.5MiB/s, 31.3MiB/s, 31.3MiB/s
> > > > > > > Average
> > > > > > > speed: 31.36MiB/s
> > > > > > >
> > > > > > > 3) Sequential write:
> > > > > > > Speed: 71MiB/s, 71.8MiB/s, 72.3MiB/s, 72.2MiB/s, 71MiB/s Average
> > > > > > > speed: 71.66MiB/s
> > > > > > >
> > > > > > > 4) Random write:
> > > > > > > Speed: 68.9MiB/s, 68.7MiB/s, 68.8MiB/s, 68.6MiB/s, 68.8MiB/s
> > > > > > > Average
> > > > > > > speed: 68.76MiB/s
> > > > > > >
> > > > > > > Form above data, we can see the MMC software queue can help to
> > > > > > > improve some performance obviously for random read and write,
> > > > > > > though no obvious improvement for sequential read and write.
> > > > > > >
> > > > > > > Any comments are welcome. Thanks a lot.
> > > > > > >
> > > >
> > > > Hi Baolin,
> > > >
> > > > I refer to your code, and add the software queue support on i.MX based on
> > > the Linux next-20200602, but unfortunately, I see an obvious performance drop
> > > when change to use software queue.
> > > > I test on our imx850-evk board, with eMMC soldered.
> > > > From the result listing below, only random write has a little performance
> > > improve, for others, seems performance drop a lot.
> > > > I noticed that, this software queue need no-removable card, any other
> > > limitation? For host?
> > > > From the code logic, software queue complete the request in irq handler,
> > > seems no other change, I do not figure out why this will trigger a performance
> > > drop on my platform. Any comment would be appreciate!
> > >
> > > Have you tested with below patches, which introduce an atomic_request host
> > > ops to submit next request in the irq hard handler context to reduce latency?
> >
> > Hi Baolin,
> >
> > The Linux code base I use is Linux-next-20200602, which already contain all the patch you listed, including the atomic_request.
> > I do not test the atomic_request alone. I just enable software queue, and this software queue use the atomic request.
> > So, do you mean, I need to first disable software queue, and just enable the atomic_request, to confirm whether the atomic_request has some performance impact on my platform?
>
> NO, the HSQ will support atomic_request ops, and I think you should
> implement the atomic_request ops in your driver if possible, like
> below patch:
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=61ab64e2f54f4c607428667f83f411cb659843a3

Ah, sorry, I saw you've implemented the atomic_request ops. Moreover
I've tested the mainline, and I still got some performance
improvement.

What's the IO scheduler you selected?

>
> > > > Without software queue, normal read/write method:
> > > > Sequential read: 56MB/s
> > > > Random read: 23.5MB/s
> > > > Sequential write: 43.7MB/s
> > > > Random write: 19MB/s
> > > >
> > > > With mmc software queue:
> > > > Sequential read: 33.5MB/s
> > > > Random read: 18.7 MB/s
> > > > Sequential write: 37.7MB/s
> > > > Random write: 19.8MB/s
> > > >
> > > >
> > > > Here, I also list my change code to support software queue
> > > >
> > > > diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index
> > > > eb85237bf2d6..996b8cc5c381 100644
> > > > --- a/drivers/mmc/host/Kconfig
> > > > +++ b/drivers/mmc/host/Kconfig
> > > > @@ -254,6 +254,7 @@ config MMC_SDHCI_ESDHC_IMX
> > > > depends on MMC_SDHCI_PLTFM
> > > > select MMC_SDHCI_IO_ACCESSORS
> > > > select MMC_CQHCI
> > > > + select MMC_HSQ
> > > > help
> > > > This selects the Freescale eSDHC/uSDHC controller support
> > > > found on i.MX25, i.MX35 i.MX5x and i.MX6x.
> > > > diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c
> > > > b/drivers/mmc/host/sdhci-esdhc-imx.c
> > > > index 1d7f84b23a22..6f163695b08d 100644
> > > > --- a/drivers/mmc/host/sdhci-esdhc-imx.c
> > > > +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
> > > > @@ -29,6 +29,7 @@
> > > > #include "sdhci-pltfm.h"
> > > > #include "sdhci-esdhc.h"
> > > > #include "cqhci.h"
> > > > +#include "mmc_hsq.h"
> > > >
> > > > #define ESDHC_SYS_CTRL_DTOCV_MASK 0x0f
> > > > #define ESDHC_CTRL_D3CD 0x08
> > > > @@ -1220,6 +1221,15 @@ static u32 esdhc_cqhci_irq(struct sdhci_host
> > > *host, u32 intmask)
> > > > return 0;
> > > > }
> > > >
> > > > +static void esdhc_request_done(struct sdhci_host *host, struct
> > > > +mmc_request *mrq) {
> > > > + /* Validate if the request was from software queue firstly. */
> > > > + if (mmc_hsq_finalize_request(host->mmc, mrq))
> > > > + return;
> > > > +
> > > > + mmc_request_done(host->mmc, mrq); }
> > > > +
> > > > static struct sdhci_ops sdhci_esdhc_ops = {
> > > > .read_l = esdhc_readl_le,
> > > > .read_w = esdhc_readw_le,
> > > > @@ -1237,6 +1247,7 @@ static struct sdhci_ops sdhci_esdhc_ops = {
> > > > .set_uhs_signaling = esdhc_set_uhs_signaling,
> > > > .reset = esdhc_reset,
> > > > .irq = esdhc_cqhci_irq,
> > > > + .request_done = esdhc_request_done,
> > > > };
> > > >
> > > > static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { @@
> > > > -1301,6 +1312,19 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host
> > > *host)
> > > > writel(tmp, host->ioaddr +
> > > ESDHC_VEND_SPEC2);
> > > >
> > > > host->quirks &=
> > > ~SDHCI_QUIRK_NO_BUSY_IRQ;
> > > > +
> > > > + /*
> > > > + * On i.MX8MM, we are running Dual Linux OS,
> > > with 1st Linux using SD Card
> > > > + * as rootfs storage, 2nd Linux using eMMC as
> > > rootfs storage. We let the
> > > > + * the 1st linux configure power/clock for the
> > > 2nd Linux.
> > > > + *
> > > > + * When the 2nd Linux is booting into rootfs
> > > stage, we let the 1st Linux
> > > > + * to destroy the 2nd linux, then restart the
> > > 2nd linux, we met SDHCI dump.
> > > > + * After we clear the pending interrupt and halt
> > > CQCTL, issue gone.
> > > > + */
> > > > + tmp = cqhci_readl(cq_host, CQHCI_IS);
> > > > + cqhci_writel(cq_host, tmp, CQHCI_IS);
> > > > + cqhci_writel(cq_host, CQHCI_HALT,
> > > CQHCI_CTL);
> > > > }
> > > >
> > > > if (imx_data->socdata->flags &
> > > ESDHC_FLAG_STD_TUNING)
> > > > { @@ -1351,9 +1375,6 @@ static void sdhci_esdhc_imx_hwinit(struct
> > > sdhci_host *host)
> > > > * After we clear the pending interrupt and halt CQCTL,
> > > issue gone.
> > > > */
> > > > if (cq_host) {
> > > > - tmp = cqhci_readl(cq_host, CQHCI_IS);
> > > > - cqhci_writel(cq_host, tmp, CQHCI_IS);
> > > > - cqhci_writel(cq_host, CQHCI_HALT,
> > > CQHCI_CTL);
> > > > }
> > > > }
> > > > }
> > > > @@ -1555,6 +1576,7 @@ static int sdhci_esdhc_imx_probe(struct
> > > platform_device *pdev)
> > > > struct sdhci_pltfm_host *pltfm_host;
> > > > struct sdhci_host *host;
> > > > struct cqhci_host *cq_host;
> > > > + struct mmc_hsq *hsq;
> > > > int err;
> > > > struct pltfm_imx_data *imx_data;
> > > >
> > > > @@ -1664,6 +1686,16 @@ static int sdhci_esdhc_imx_probe(struct
> > > platform_device *pdev)
> > > > err = cqhci_init(cq_host, host->mmc, false);
> > > > if (err)
> > > > goto disable_ahb_clk;
> > > > + } else if (esdhc_is_usdhc(imx_data)) {
> > > > + hsq = devm_kzalloc(&pdev->dev, sizeof(*hsq),
> > > GFP_KERNEL);
> > > > + if (!hsq) {
> > > > + err = -ENOMEM;
> > > > + goto disable_ahb_clk;
> > > > + }
> > > > +
> > > > + err = mmc_hsq_init(hsq, host->mmc);
> > > > + if (err)
> > > > + goto disable_ahb_clk;
> > > > }
> > > >
> > > > if (of_id)
> > > > @@ -1673,6 +1705,11 @@ static int sdhci_esdhc_imx_probe(struct
> > > platform_device *pdev)
> > > > if (err)
> > > > goto disable_ahb_clk;
> > > >
> > > > + if (!mmc_card_is_removable(host->mmc))
> > > > + host->mmc_host_ops.request_atomic =
> > > sdhci_request_atomic;
> > > > + else
> > > > + host->always_defer_done = true;
> > > > +
> > > > sdhci_esdhc_imx_hwinit(host);
> > > >
> > > > err = sdhci_add_host(host);
> > > > @@ -1737,6 +1774,8 @@ static int sdhci_esdhc_suspend(struct device
> > > *dev)
> > > > ret = cqhci_suspend(host->mmc);
> > > > if (ret)
> > > > return ret;
> > > > + } else if (esdhc_is_usdhc(imx_data)) {
> > > > + mmc_hsq_suspend(host->mmc);
> > > > }
> > > >
> > > > if ((imx_data->socdata->flags &
> > > > ESDHC_FLAG_STATE_LOST_IN_LPMODE) && @@ -1764,6 +1803,8 @@
> > > static int
> > > > sdhci_esdhc_suspend(struct device *dev) static int
> > > > sdhci_esdhc_resume(struct device *dev) {
> > > > struct sdhci_host *host = dev_get_drvdata(dev);
> > > > + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
> > > > + struct pltfm_imx_data *imx_data =
> > > > + sdhci_pltfm_priv(pltfm_host);
> > > > int ret;
> > > >
> > > > ret = pinctrl_pm_select_default_state(dev);
> > > > @@ -1777,8 +1818,11 @@ static int sdhci_esdhc_resume(struct device
> > > *dev)
> > > > if (ret)
> > > > return ret;
> > > >
> > > > - if (host->mmc->caps2 & MMC_CAP2_CQE)
> > > > + if (host->mmc->caps2 & MMC_CAP2_CQE) {
> > > > ret = cqhci_resume(host->mmc);
> > > > + } else if (esdhc_is_usdhc(imx_data)) {
> > > > + mmc_hsq_resume(host->mmc);
> > > > + }
> > > >
> > > > if (!ret)
> > > > ret = mmc_gpio_set_cd_wake(host->mmc, false); @@
> > > > -1799,6 +1843,8 @@ static int sdhci_esdhc_runtime_suspend(struct device
> > > *dev)
> > > > ret = cqhci_suspend(host->mmc);
> > > > if (ret)
> > > > return ret;
> > > > + } else if (esdhc_is_usdhc(imx_data)) {
> > > > + mmc_hsq_suspend(host->mmc);
> > > > }
> > > >
> > > > ret = sdhci_runtime_suspend_host(host); @@ -1851,8 +1897,11
> > > @@
> > > > static int sdhci_esdhc_runtime_resume(struct device *dev)
> > > > if (err)
> > > > goto disable_ipg_clk;
> > > >
> > > > - if (host->mmc->caps2 & MMC_CAP2_CQE)
> > > > + if (host->mmc->caps2 & MMC_CAP2_CQE) {
> > > > err = cqhci_resume(host->mmc);
> > > > + } else if (esdhc_is_usdhc(imx_data)) {
> > > > + mmc_hsq_resume(host->mmc);
> > > > + }
> > > >
> > > > return err;
> > > >
> > > >
> > > >
> > > > > > > Changes from v8:
> > > > > > > - Add more description in the commit message.
> > > > > > > - Optimize the failure log when calling cqe_enable().
> > > > > > >
> > > > > > > Changes from v7:
> > > > > > > - Add reviewed tag from Arnd.
> > > > > > > - Use the 'hsq' acronym for varibles and functions in the core layer.
> > > > > > > - Check the 'card->ext_csd.cmdq_en' in cqhci.c to make sure the
> > > > > > > CQE can work normally.
> > > > > > > - Add a new patch to enable the host software queue for the SD card.
> > > > > > > - Use the default MMC queue depth for host software queue.
> > > > > > >
> > > > > > > Changes from v6:
> > > > > > > - Change the patch order and set host->always_defer_done = true
> > > > > > > for the Spreadtrum host driver.
> > > > > > >
> > > > > > > Changes from v5:
> > > > > > > - Modify the condition of defering to complete request
> > > > > > > suggested by
> > > > > Adrian.
> > > > > > >
> > > > > > > Changes from v4:
> > > > > > > - Add a seperate patch to introduce a variable to defer to
> > > > > > > complete data requests for some host drivers, when using host
> > > software queue.
> > > > > > >
> > > > > > > Changes from v3:
> > > > > > > - Use host software queue instead of sqhci.
> > > > > > > - Fix random config building issue.
> > > > > > > - Change queue depth to 32, but still only allow 2 requests in flight.
> > > > > > > - Update the testing data.
> > > > > > >
> > > > > > > Changes from v2:
> > > > > > > - Remove reference to 'struct cqhci_host' and 'struct
> > > > > > > cqhci_slot', instead adding 'struct sqhci_host', which is only used by
> > > software queue.
> > > > > > >
> > > > > > > Changes from v1:
> > > > > > > - Add request_done ops for sdhci_ops.
> > > > > > > - Replace virtual command queue with software queue for
> > > > > > > functions and variables.
> > > > > > > - Rename the software queue file and add sqhci.h header file.
> > > > > > >
> > > > > > > Baolin Wang (5):
> > > > > > > mmc: Add MMC host software queue support
> > > > > > > mmc: core: Enable the MMC host software queue for the SD card
> > > > > > > mmc: host: sdhci: Add request_done ops for struct sdhci_ops
> > > > > > > mmc: host: sdhci: Add a variable to defer to complete requests if
> > > > > > > needed
> > > > > > > mmc: host: sdhci-sprd: Add software queue support
> > > > > > >
> > > > > > > drivers/mmc/core/block.c | 61 ++++++++
> > > > > > > drivers/mmc/core/mmc.c | 18 ++-
> > > > > > > drivers/mmc/core/queue.c | 22 ++-
> > > > > > > drivers/mmc/core/sd.c | 10 ++
> > > > > > > drivers/mmc/host/Kconfig | 8 +
> > > > > > > drivers/mmc/host/Makefile | 1 +
> > > > > > > drivers/mmc/host/cqhci.c | 8 +-
> > > > > > > drivers/mmc/host/mmc_hsq.c | 343
> > > > > +++++++++++++++++++++++++++++++++++++++++
> > > > > > > drivers/mmc/host/mmc_hsq.h | 30 ++++
> > > > > > > drivers/mmc/host/sdhci-sprd.c | 28 ++++
> > > > > > > drivers/mmc/host/sdhci.c | 14 +-
> > > > > > > drivers/mmc/host/sdhci.h | 3 +
> > > > > > > include/linux/mmc/host.h | 3 +
> > > > > > > 13 files changed, 534 insertions(+), 15 deletions(-) create
> > > > > > > mode
> > > > > > > 100644 drivers/mmc/host/mmc_hsq.c create mode 100644
> > > > > > > drivers/mmc/host/mmc_hsq.h
> > > > > > >
> > > > > > > --
> > > > > > > 1.7.9.5
> > > > > > >
> > > > > >
> > > > > > Applied for next, thanks! Also, thanks for your patience while
> > > > > > moving forward during the reviews!
> > > > >
> > > > > I am very appreciated for you and Arnd's good sugestion when
> > > > > introducing the hsq.
> > > > >
> > > > > >
> > > > > > Note, I did some amending of patch1 to resolve some checkpatch
> > > > > > warnings. SPDX licence and Kconfig help texts, please have a look
> > > > > > and tell if there are something that doesn't look good.
> > > > >
> > > > > Thanks for your help and looks good to me.
> > >
> > >
> > >
> > > --
> > > Baolin Wang
>
>
>
> --
> Baolin Wang



--
Baolin Wang

2020-06-15 02:35:20

by Bough Chen

[permalink] [raw]
Subject: RE: [PATCH v9 0/5] Add MMC software queue support


> -----Original Message-----
> From: Baolin Wang [mailto:[email protected]]
> Sent: 2020年6月15日 7:26
> To: BOUGH CHEN <[email protected]>
> Cc: Ulf Hansson <[email protected]>; Adrian Hunter
> <[email protected]>; Asutosh Das <[email protected]>; Orson
> Zhai <[email protected]>; Chunyan Zhang <[email protected]>; Arnd
> Bergmann <[email protected]>; Linus Walleij <[email protected]>; Baolin
> Wang <[email protected]>; [email protected]; Linux Kernel
> Mailing List <[email protected]>; dl-linux-imx <[email protected]>
> Subject: Re: [PATCH v9 0/5] Add MMC software queue support
>
> On Sun, Jun 14, 2020 at 11:05 PM Baolin Wang <[email protected]>
> wrote:
> >
> > On Wed, Jun 10, 2020 at 10:26 AM BOUGH CHEN <[email protected]>
> wrote:
> > >
> > > > -----Original Message-----
> > > > From: Baolin Wang [mailto:[email protected]]
> > > > Sent: 2020年6月8日 19:54
> > > > To: BOUGH CHEN <[email protected]>
> > > > Cc: Ulf Hansson <[email protected]>; Adrian Hunter
> > > > <[email protected]>; Asutosh Das <[email protected]>;
> > > > Orson Zhai <[email protected]>; Chunyan Zhang
> > > > <[email protected]>; Arnd Bergmann <[email protected]>; Linus
> > > > Walleij <[email protected]>; Baolin Wang
> > > > <[email protected]>; [email protected]; Linux Kernel
> > > > Mailing List <[email protected]>; dl-linux-imx
> > > > <[email protected]>
> > > > Subject: Re: [PATCH v9 0/5] Add MMC software queue support
> > > >
> > > > Hi Haibo.
> > > >
> > > > On Mon, Jun 8, 2020 at 2:35 PM BOUGH CHEN <[email protected]>
> wrote:
> > > > >
> > > > > > -----Original Message-----
> > > > > > From: [email protected]
> > > > > > [mailto:[email protected]] On Behalf Of Baolin
> > > > > > Wang
> > > > > > Sent: 2020年2月19日 9:35
> > > > > > To: Ulf Hansson <[email protected]>
> > > > > > Cc: Adrian Hunter <[email protected]>; Asutosh Das
> > > > > > <[email protected]>; Orson Zhai <[email protected]>;
> > > > Chunyan
> > > > > > Zhang <[email protected]>; Arnd Bergmann <[email protected]>;
> > > > > > Linus Walleij <[email protected]>; Baolin Wang
> > > > > > <[email protected]>; [email protected]; Linux
> > > > > > Kernel Mailing List <[email protected]>
> > > > > > Subject: Re: [PATCH v9 0/5] Add MMC software queue support
> > > > > >
> > > > > > On Wed, Feb 19, 2020 at 7:38 AM Ulf Hansson
> > > > > > <[email protected]>
> > > > > > wrote:
> > > > > > >
> > > > > > > On Wed, 12 Feb 2020 at 05:14, Baolin Wang
> > > > > > > <[email protected]>
> > > > > > wrote:
> > > > > > > >
> > > > > > > > Hi All,
> > > > > > > >
> > > > > > > > Now the MMC read/write stack will always wait for previous
> > > > > > > > request is completed by mmc_blk_rw_wait(), before sending
> > > > > > > > a new request to hardware, or queue a work to complete
> > > > > > > > request, that will bring context switching overhead,
> > > > > > > > especially for high I/O per second rates, to affect the IO
> performance.
> > > > > > > >
> > > > > > > > Thus this patch set will introduce the MMC software
> > > > > > > > command queue support based on command queue engine's
> > > > > > > > interfaces, and set the queue depth as 64 to allow more
> > > > > > > > requests can be be prepared, merged and inserted into IO
> > > > > > > > scheduler, but we only allow 2 requests in flight, that is
> > > > > > > > enough to let the irq handler always trigger the next
> > > > > > > > request without a context switch, as
> > > > well as avoiding a long latency.
> > > > > > > >
> > > > > > > > Moreover we can expand the MMC software queue interface to
> > > > > > > > support MMC packed request or packed command instead of
> > > > > > > > adding new interfaces, according to previosus discussion.
> > > > > > > >
> > > > > > > > Below are some comparison data with fio tool. The fio
> > > > > > > > command I used is like below with changing the '--rw'
> > > > > > > > parameter and enabling the direct IO flag to measure the
> > > > > > > > actual hardware transfer speed in 4K block
> > > > > > size.
> > > > > > > >
> > > > > > > > ./fio --filename=/dev/mmcblk0p30 --direct=1 --iodepth=20
> > > > > > > > --rw=read --bs=4K --size=1G --group_reporting --numjobs=20
> > > > > > > > --name=test_read
> > > > > > > >
> > > > > > > > My eMMC card working at HS400 Enhanced strobe mode:
> > > > > > > > [ 2.229856] mmc0: new HS400 Enhanced strobe MMC card at
> > > > address
> > > > > > 0001
> > > > > > > > [ 2.237566] mmcblk0: mmc0:0001 HBG4a2 29.1 GiB
> > > > > > > > [ 2.242621] mmcblk0boot0: mmc0:0001 HBG4a2 partition 1
> 4.00
> > > > MiB
> > > > > > > > [ 2.249110] mmcblk0boot1: mmc0:0001 HBG4a2 partition 2
> 4.00
> > > > MiB
> > > > > > > > [ 2.255307] mmcblk0rpmb: mmc0:0001 HBG4a2 partition 3
> 4.00
> > > > MiB,
> > > > > > chardev (248:0)
> > > > > > > >
> > > > > > > > 1. Without MMC software queue I tested 5 times for each
> > > > > > > > case and output a average speed.
> > > > > > > >
> > > > > > > > 1) Sequential read:
> > > > > > > > Speed: 59.4MiB/s, 63.4MiB/s, 57.5MiB/s, 57.2MiB/s,
> > > > > > > > 60.8MiB/s Average
> > > > > > > > speed: 59.66MiB/s
> > > > > > > >
> > > > > > > > 2) Random read:
> > > > > > > > Speed: 26.9MiB/s, 26.9MiB/s, 27.1MiB/s, 27.1MiB/s,
> > > > > > > > 27.2MiB/s Average
> > > > > > > > speed: 27.04MiB/s
> > > > > > > >
> > > > > > > > 3) Sequential write:
> > > > > > > > Speed: 71.6MiB/s, 72.5MiB/s, 72.2MiB/s, 64.6MiB/s,
> > > > > > > > 67.5MiB/s Average
> > > > > > > > speed: 69.68MiB/s
> > > > > > > >
> > > > > > > > 4) Random write:
> > > > > > > > Speed: 36.3MiB/s, 35.4MiB/s, 38.6MiB/s, 34MiB/s, 35.5MiB/s
> > > > > > > > Average
> > > > > > > > speed: 35.96MiB/s
> > > > > > > >
> > > > > > > > 2. With MMC software queue I tested 5 times for each case
> > > > > > > > and output a average speed.
> > > > > > > >
> > > > > > > > 1) Sequential read:
> > > > > > > > Speed: 59.2MiB/s, 60.4MiB/s, 63.6MiB/s, 60.3MiB/s,
> > > > > > > > 59.9MiB/s Average
> > > > > > > > speed: 60.68MiB/s
> > > > > > > >
> > > > > > > > 2) Random read:
> > > > > > > > Speed: 31.3MiB/s, 31.4MiB/s, 31.5MiB/s, 31.3MiB/s,
> > > > > > > > 31.3MiB/s Average
> > > > > > > > speed: 31.36MiB/s
> > > > > > > >
> > > > > > > > 3) Sequential write:
> > > > > > > > Speed: 71MiB/s, 71.8MiB/s, 72.3MiB/s, 72.2MiB/s, 71MiB/s
> > > > > > > > Average
> > > > > > > > speed: 71.66MiB/s
> > > > > > > >
> > > > > > > > 4) Random write:
> > > > > > > > Speed: 68.9MiB/s, 68.7MiB/s, 68.8MiB/s, 68.6MiB/s,
> > > > > > > > 68.8MiB/s Average
> > > > > > > > speed: 68.76MiB/s
> > > > > > > >
> > > > > > > > Form above data, we can see the MMC software queue can
> > > > > > > > help to improve some performance obviously for random read
> > > > > > > > and write, though no obvious improvement for sequential read and
> write.
> > > > > > > >
> > > > > > > > Any comments are welcome. Thanks a lot.
> > > > > > > >
> > > > >
> > > > > Hi Baolin,
> > > > >
> > > > > I refer to your code, and add the software queue support on i.MX
> > > > > based on
> > > > the Linux next-20200602, but unfortunately, I see an obvious
> > > > performance drop when change to use software queue.
> > > > > I test on our imx850-evk board, with eMMC soldered.
> > > > > From the result listing below, only random write has a little
> > > > > performance
> > > > improve, for others, seems performance drop a lot.
> > > > > I noticed that, this software queue need no-removable card, any
> > > > > other
> > > > limitation? For host?
> > > > > From the code logic, software queue complete the request in irq
> > > > > handler,
> > > > seems no other change, I do not figure out why this will trigger a
> > > > performance drop on my platform. Any comment would be appreciate!
> > > >
> > > > Have you tested with below patches, which introduce an
> > > > atomic_request host ops to submit next request in the irq hard handler
> context to reduce latency?
> > >
> > > Hi Baolin,
> > >
> > > The Linux code base I use is Linux-next-20200602, which already contain all
> the patch you listed, including the atomic_request.
> > > I do not test the atomic_request alone. I just enable software queue, and
> this software queue use the atomic request.
> > > So, do you mean, I need to first disable software queue, and just enable the
> atomic_request, to confirm whether the atomic_request has some
> performance impact on my platform?
> >
> > NO, the HSQ will support atomic_request ops, and I think you should
> > implement the atomic_request ops in your driver if possible, like
> > below patch:
> > https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.
> >
> kernel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%2
> >
> Fcommit%2F%3Fid%3D61ab64e2f54f4c607428667f83f411cb659843a3&amp;d
> ata=02
> > %7C01%7Chaibo.chen%40nxp.com%7C500e3b7d66954c14d2f208d810ba488
> 3%7C686e
> >
> a1d3bc2b4c6fa92cd99c5c301635%7C0%7C1%7C637277739547832756&amp;s
> data=0j
> > RbAi8gvllPKc0IPjdQfK7nTGQ9piefGu80lWQIG5Y%3D&amp;reserved=0
>
> Ah, sorry, I saw you've implemented the atomic_request ops. Moreover I've
> tested the mainline, and I still got some performance improvement.
>
> What's the IO scheduler you selected?
>

Hi Baolin,

I do not change the setting of IO scheduler, so should be the default IO scheduler.
One thing I find when I go through your patch set, is that you said the HSQ need host side to has the flag MMC_CAP_WAIT_WHILE_BUSY.
But for i.MX usdhc host, it do not support this flag, not sure whether it caused the performance difference.


Best Regards
Haibo Chen
> >
> > > > > Without software queue, normal read/write method:
> > > > > Sequential read: 56MB/s
> > > > > Random read: 23.5MB/s
> > > > > Sequential write: 43.7MB/s
> > > > > Random write: 19MB/s
> > > > >
> > > > > With mmc software queue:
> > > > > Sequential read: 33.5MB/s
> > > > > Random read: 18.7 MB/s
> > > > > Sequential write: 37.7MB/s
> > > > > Random write: 19.8MB/s
> > > > >
> > > > >
> > > > > Here, I also list my change code to support software queue
> > > > >
> > > > > diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
> > > > > index
> > > > > eb85237bf2d6..996b8cc5c381 100644
> > > > > --- a/drivers/mmc/host/Kconfig
> > > > > +++ b/drivers/mmc/host/Kconfig
> > > > > @@ -254,6 +254,7 @@ config MMC_SDHCI_ESDHC_IMX
> > > > > depends on MMC_SDHCI_PLTFM
> > > > > select MMC_SDHCI_IO_ACCESSORS
> > > > > select MMC_CQHCI
> > > > > + select MMC_HSQ
> > > > > help
> > > > > This selects the Freescale eSDHC/uSDHC controller
> support
> > > > > found on i.MX25, i.MX35 i.MX5x and i.MX6x.
> > > > > diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c
> > > > > b/drivers/mmc/host/sdhci-esdhc-imx.c
> > > > > index 1d7f84b23a22..6f163695b08d 100644
> > > > > --- a/drivers/mmc/host/sdhci-esdhc-imx.c
> > > > > +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
> > > > > @@ -29,6 +29,7 @@
> > > > > #include "sdhci-pltfm.h"
> > > > > #include "sdhci-esdhc.h"
> > > > > #include "cqhci.h"
> > > > > +#include "mmc_hsq.h"
> > > > >
> > > > > #define ESDHC_SYS_CTRL_DTOCV_MASK 0x0f
> > > > > #define ESDHC_CTRL_D3CD 0x08
> > > > > @@ -1220,6 +1221,15 @@ static u32 esdhc_cqhci_irq(struct
> > > > > sdhci_host
> > > > *host, u32 intmask)
> > > > > return 0;
> > > > > }
> > > > >
> > > > > +static void esdhc_request_done(struct sdhci_host *host, struct
> > > > > +mmc_request *mrq) {
> > > > > + /* Validate if the request was from software queue firstly. */
> > > > > + if (mmc_hsq_finalize_request(host->mmc, mrq))
> > > > > + return;
> > > > > +
> > > > > + mmc_request_done(host->mmc, mrq); }
> > > > > +
> > > > > static struct sdhci_ops sdhci_esdhc_ops = {
> > > > > .read_l = esdhc_readl_le,
> > > > > .read_w = esdhc_readw_le, @@ -1237,6 +1247,7 @@ static
> > > > > struct sdhci_ops sdhci_esdhc_ops = {
> > > > > .set_uhs_signaling = esdhc_set_uhs_signaling,
> > > > > .reset = esdhc_reset,
> > > > > .irq = esdhc_cqhci_irq,
> > > > > + .request_done = esdhc_request_done,
> > > > > };
> > > > >
> > > > > static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
> > > > > @@
> > > > > -1301,6 +1312,19 @@ static void sdhci_esdhc_imx_hwinit(struct
> > > > > sdhci_host
> > > > *host)
> > > > > writel(tmp, host->ioaddr +
> > > > ESDHC_VEND_SPEC2);
> > > > >
> > > > > host->quirks &=
> > > > ~SDHCI_QUIRK_NO_BUSY_IRQ;
> > > > > +
> > > > > + /*
> > > > > + * On i.MX8MM, we are running Dual
> Linux
> > > > > + OS,
> > > > with 1st Linux using SD Card
> > > > > + * as rootfs storage, 2nd Linux using
> > > > > + eMMC as
> > > > rootfs storage. We let the
> > > > > + * the 1st linux configure power/clock
> > > > > + for the
> > > > 2nd Linux.
> > > > > + *
> > > > > + * When the 2nd Linux is booting into
> > > > > + rootfs
> > > > stage, we let the 1st Linux
> > > > > + * to destroy the 2nd linux, then
> > > > > + restart the
> > > > 2nd linux, we met SDHCI dump.
> > > > > + * After we clear the pending interrupt
> > > > > + and halt
> > > > CQCTL, issue gone.
> > > > > + */
> > > > > + tmp = cqhci_readl(cq_host, CQHCI_IS);
> > > > > + cqhci_writel(cq_host, tmp, CQHCI_IS);
> > > > > + cqhci_writel(cq_host, CQHCI_HALT,
> > > > CQHCI_CTL);
> > > > > }
> > > > >
> > > > > if (imx_data->socdata->flags &
> > > > ESDHC_FLAG_STD_TUNING)
> > > > > { @@ -1351,9 +1375,6 @@ static void
> > > > > sdhci_esdhc_imx_hwinit(struct
> > > > sdhci_host *host)
> > > > > * After we clear the pending interrupt and halt
> > > > > CQCTL,
> > > > issue gone.
> > > > > */
> > > > > if (cq_host) {
> > > > > - tmp = cqhci_readl(cq_host, CQHCI_IS);
> > > > > - cqhci_writel(cq_host, tmp, CQHCI_IS);
> > > > > - cqhci_writel(cq_host, CQHCI_HALT,
> > > > CQHCI_CTL);
> > > > > }
> > > > > }
> > > > > }
> > > > > @@ -1555,6 +1576,7 @@ static int sdhci_esdhc_imx_probe(struct
> > > > platform_device *pdev)
> > > > > struct sdhci_pltfm_host *pltfm_host;
> > > > > struct sdhci_host *host;
> > > > > struct cqhci_host *cq_host;
> > > > > + struct mmc_hsq *hsq;
> > > > > int err;
> > > > > struct pltfm_imx_data *imx_data;
> > > > >
> > > > > @@ -1664,6 +1686,16 @@ static int sdhci_esdhc_imx_probe(struct
> > > > platform_device *pdev)
> > > > > err = cqhci_init(cq_host, host->mmc, false);
> > > > > if (err)
> > > > > goto disable_ahb_clk;
> > > > > + } else if (esdhc_is_usdhc(imx_data)) {
> > > > > + hsq = devm_kzalloc(&pdev->dev, sizeof(*hsq),
> > > > GFP_KERNEL);
> > > > > + if (!hsq) {
> > > > > + err = -ENOMEM;
> > > > > + goto disable_ahb_clk;
> > > > > + }
> > > > > +
> > > > > + err = mmc_hsq_init(hsq, host->mmc);
> > > > > + if (err)
> > > > > + goto disable_ahb_clk;
> > > > > }
> > > > >
> > > > > if (of_id)
> > > > > @@ -1673,6 +1705,11 @@ static int sdhci_esdhc_imx_probe(struct
> > > > platform_device *pdev)
> > > > > if (err)
> > > > > goto disable_ahb_clk;
> > > > >
> > > > > + if (!mmc_card_is_removable(host->mmc))
> > > > > + host->mmc_host_ops.request_atomic =
> > > > sdhci_request_atomic;
> > > > > + else
> > > > > + host->always_defer_done = true;
> > > > > +
> > > > > sdhci_esdhc_imx_hwinit(host);
> > > > >
> > > > > err = sdhci_add_host(host); @@ -1737,6 +1774,8 @@ static
> > > > > int sdhci_esdhc_suspend(struct device
> > > > *dev)
> > > > > ret = cqhci_suspend(host->mmc);
> > > > > if (ret)
> > > > > return ret;
> > > > > + } else if (esdhc_is_usdhc(imx_data)) {
> > > > > + mmc_hsq_suspend(host->mmc);
> > > > > }
> > > > >
> > > > > if ((imx_data->socdata->flags &
> > > > > ESDHC_FLAG_STATE_LOST_IN_LPMODE) && @@ -1764,6 +1803,8 @@
> > > > static int
> > > > > sdhci_esdhc_suspend(struct device *dev) static int
> > > > > sdhci_esdhc_resume(struct device *dev) {
> > > > > struct sdhci_host *host = dev_get_drvdata(dev);
> > > > > + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
> > > > > + struct pltfm_imx_data *imx_data =
> > > > > + sdhci_pltfm_priv(pltfm_host);
> > > > > int ret;
> > > > >
> > > > > ret = pinctrl_pm_select_default_state(dev);
> > > > > @@ -1777,8 +1818,11 @@ static int sdhci_esdhc_resume(struct
> > > > > device
> > > > *dev)
> > > > > if (ret)
> > > > > return ret;
> > > > >
> > > > > - if (host->mmc->caps2 & MMC_CAP2_CQE)
> > > > > + if (host->mmc->caps2 & MMC_CAP2_CQE) {
> > > > > ret = cqhci_resume(host->mmc);
> > > > > + } else if (esdhc_is_usdhc(imx_data)) {
> > > > > + mmc_hsq_resume(host->mmc);
> > > > > + }
> > > > >
> > > > > if (!ret)
> > > > > ret = mmc_gpio_set_cd_wake(host->mmc, false);
> @@
> > > > > -1799,6 +1843,8 @@ static int sdhci_esdhc_runtime_suspend(struct
> > > > > device
> > > > *dev)
> > > > > ret = cqhci_suspend(host->mmc);
> > > > > if (ret)
> > > > > return ret;
> > > > > + } else if (esdhc_is_usdhc(imx_data)) {
> > > > > + mmc_hsq_suspend(host->mmc);
> > > > > }
> > > > >
> > > > > ret = sdhci_runtime_suspend_host(host); @@ -1851,8
> > > > > +1897,11
> > > > @@
> > > > > static int sdhci_esdhc_runtime_resume(struct device *dev)
> > > > > if (err)
> > > > > goto disable_ipg_clk;
> > > > >
> > > > > - if (host->mmc->caps2 & MMC_CAP2_CQE)
> > > > > + if (host->mmc->caps2 & MMC_CAP2_CQE) {
> > > > > err = cqhci_resume(host->mmc);
> > > > > + } else if (esdhc_is_usdhc(imx_data)) {
> > > > > + mmc_hsq_resume(host->mmc);
> > > > > + }
> > > > >
> > > > > return err;
> > > > >
> > > > >
> > > > >
> > > > > > > > Changes from v8:
> > > > > > > > - Add more description in the commit message.
> > > > > > > > - Optimize the failure log when calling cqe_enable().
> > > > > > > >
> > > > > > > > Changes from v7:
> > > > > > > > - Add reviewed tag from Arnd.
> > > > > > > > - Use the 'hsq' acronym for varibles and functions in the core
> layer.
> > > > > > > > - Check the 'card->ext_csd.cmdq_en' in cqhci.c to make
> > > > > > > > sure the CQE can work normally.
> > > > > > > > - Add a new patch to enable the host software queue for the SD
> card.
> > > > > > > > - Use the default MMC queue depth for host software queue.
> > > > > > > >
> > > > > > > > Changes from v6:
> > > > > > > > - Change the patch order and set host->always_defer_done
> > > > > > > > = true for the Spreadtrum host driver.
> > > > > > > >
> > > > > > > > Changes from v5:
> > > > > > > > - Modify the condition of defering to complete request
> > > > > > > > suggested by
> > > > > > Adrian.
> > > > > > > >
> > > > > > > > Changes from v4:
> > > > > > > > - Add a seperate patch to introduce a variable to defer
> > > > > > > > to complete data requests for some host drivers, when
> > > > > > > > using host
> > > > software queue.
> > > > > > > >
> > > > > > > > Changes from v3:
> > > > > > > > - Use host software queue instead of sqhci.
> > > > > > > > - Fix random config building issue.
> > > > > > > > - Change queue depth to 32, but still only allow 2 requests in
> flight.
> > > > > > > > - Update the testing data.
> > > > > > > >
> > > > > > > > Changes from v2:
> > > > > > > > - Remove reference to 'struct cqhci_host' and 'struct
> > > > > > > > cqhci_slot', instead adding 'struct sqhci_host', which is
> > > > > > > > only used by
> > > > software queue.
> > > > > > > >
> > > > > > > > Changes from v1:
> > > > > > > > - Add request_done ops for sdhci_ops.
> > > > > > > > - Replace virtual command queue with software queue for
> > > > > > > > functions and variables.
> > > > > > > > - Rename the software queue file and add sqhci.h header file.
> > > > > > > >
> > > > > > > > Baolin Wang (5):
> > > > > > > > mmc: Add MMC host software queue support
> > > > > > > > mmc: core: Enable the MMC host software queue for the SD
> card
> > > > > > > > mmc: host: sdhci: Add request_done ops for struct sdhci_ops
> > > > > > > > mmc: host: sdhci: Add a variable to defer to complete requests
> if
> > > > > > > > needed
> > > > > > > > mmc: host: sdhci-sprd: Add software queue support
> > > > > > > >
> > > > > > > > drivers/mmc/core/block.c | 61 ++++++++
> > > > > > > > drivers/mmc/core/mmc.c | 18 ++-
> > > > > > > > drivers/mmc/core/queue.c | 22 ++-
> > > > > > > > drivers/mmc/core/sd.c | 10 ++
> > > > > > > > drivers/mmc/host/Kconfig | 8 +
> > > > > > > > drivers/mmc/host/Makefile | 1 +
> > > > > > > > drivers/mmc/host/cqhci.c | 8 +-
> > > > > > > > drivers/mmc/host/mmc_hsq.c | 343
> > > > > > +++++++++++++++++++++++++++++++++++++++++
> > > > > > > > drivers/mmc/host/mmc_hsq.h | 30 ++++
> > > > > > > > drivers/mmc/host/sdhci-sprd.c | 28 ++++
> > > > > > > > drivers/mmc/host/sdhci.c | 14 +-
> > > > > > > > drivers/mmc/host/sdhci.h | 3 +
> > > > > > > > include/linux/mmc/host.h | 3 +
> > > > > > > > 13 files changed, 534 insertions(+), 15 deletions(-)
> > > > > > > > create mode
> > > > > > > > 100644 drivers/mmc/host/mmc_hsq.c create mode 100644
> > > > > > > > drivers/mmc/host/mmc_hsq.h
> > > > > > > >
> > > > > > > > --
> > > > > > > > 1.7.9.5
> > > > > > > >
> > > > > > >
> > > > > > > Applied for next, thanks! Also, thanks for your patience
> > > > > > > while moving forward during the reviews!
> > > > > >
> > > > > > I am very appreciated for you and Arnd's good sugestion when
> > > > > > introducing the hsq.
> > > > > >
> > > > > > >
> > > > > > > Note, I did some amending of patch1 to resolve some
> > > > > > > checkpatch warnings. SPDX licence and Kconfig help texts,
> > > > > > > please have a look and tell if there are something that doesn't look
> good.
> > > > > >
> > > > > > Thanks for your help and looks good to me.
> > > >
> > > >
> > > >
> > > > --
> > > > Baolin Wang
> >
> >
> >
> > --
> > Baolin Wang
>
>
>
> --
> Baolin Wang