public inbox for linux-mmc@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] maximum discard size
@ 2011-06-28 14:16 Adrian Hunter
  2011-06-28 14:16 ` [PATCH 1/2] mmc: queue: let host controllers specify maximum discard timeout Adrian Hunter
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Adrian Hunter @ 2011-06-28 14:16 UTC (permalink / raw)
  To: Chris Ball; +Cc: linux-mmc, Philip Rakity, Adrian Hunter

Hi

Here is a patch that sets a maximum discard size for host controllers
that cannot manage large timeouts.  And another patch putting it into
use for shdci.

Adrian Hunter (2):
      mmc: queue: let host controllers specify maximum discard timeout
      mmc: sdhci: specify maximum discard timeout

 drivers/mmc/card/queue.c |   33 ++++++++++++++------
 drivers/mmc/core/core.c  |   76 ++++++++++++++++++++++++++++++++++++++++++++++
 drivers/mmc/host/sdhci.c |    5 +++
 include/linux/mmc/core.h |    1 +
 include/linux/mmc/host.h |    1 +
 5 files changed, 106 insertions(+), 10 deletions(-)

Regards
Adrian Hunter

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/2] mmc: queue: let host controllers specify maximum discard timeout
  2011-06-28 14:16 [PATCH 0/2] maximum discard size Adrian Hunter
@ 2011-06-28 14:16 ` Adrian Hunter
  2011-06-28 14:16 ` [PATCH 2/2] mmc: sdhci: " Adrian Hunter
  2011-07-15 18:59 ` [PATCH 0/2] maximum discard size Adrian Hunter
  2 siblings, 0 replies; 5+ messages in thread
From: Adrian Hunter @ 2011-06-28 14:16 UTC (permalink / raw)
  To: Chris Ball; +Cc: linux-mmc, Philip Rakity, Adrian Hunter

Some host controllers will not operate without a hardware
timeout that is limited in value.  However large discards
require large timeouts, so there needs to be a way to
specify the maximum discard size.

A host controller driver may now specify the maximum discard
timeout possible so that max_discard_sectors can be calculated.

However, for eMMC when the High Capacity Erase Group Size
is not in use, the timeout calculation depends on clock
rate which may change.  For that case Preferred Erase Size
is used instead.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/mmc/card/queue.c |   33 ++++++++++++++------
 drivers/mmc/core/core.c  |   76 ++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/mmc/core.h |    1 +
 include/linux/mmc/host.h |    1 +
 4 files changed, 101 insertions(+), 10 deletions(-)

diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index 6413afa..defc11b 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -101,6 +101,27 @@ static void mmc_request(struct request_queue *q)
 		wake_up_process(mq->thread);
 }
 
+static void mmc_queue_setup_discard(struct request_queue *q,
+				    struct mmc_card *card)
+{
+	unsigned max_discard;
+
+	max_discard = mmc_calc_max_discard(card);
+	if (!max_discard)
+		return;
+
+	queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q);
+	q->limits.max_discard_sectors = max_discard;
+	if (card->erased_byte == 0)
+		q->limits.discard_zeroes_data = 1;
+	q->limits.discard_granularity = card->pref_erase << 9;
+	/* granularity must not be greater than max. discard */
+	if (card->pref_erase > max_discard)
+		q->limits.discard_granularity = 0;
+	if (mmc_can_secure_erase_trim(card))
+		queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD, q);
+}
+
 /**
  * mmc_init_queue - initialise a queue structure.
  * @mq: mmc queue
@@ -130,16 +151,8 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
 
 	blk_queue_prep_rq(mq->queue, mmc_prep_request);
 	queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue);
-	if (mmc_can_erase(card)) {
-		queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, mq->queue);
-		mq->queue->limits.max_discard_sectors = UINT_MAX;
-		if (card->erased_byte == 0)
-			mq->queue->limits.discard_zeroes_data = 1;
-		mq->queue->limits.discard_granularity = card->pref_erase << 9;
-		if (mmc_can_secure_erase_trim(card))
-			queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD,
-						mq->queue);
-	}
+	if (mmc_can_erase(card))
+		mmc_queue_setup_discard(mq->queue, card);
 
 #ifdef CONFIG_MMC_BLOCK_BOUNCE
 	if (host->max_segs == 1) {
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 7843efe..ac82865 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1516,6 +1516,82 @@ int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from,
 }
 EXPORT_SYMBOL(mmc_erase_group_aligned);
 
+static unsigned int mmc_do_calc_max_discard(struct mmc_card *card,
+					    unsigned int arg)
+{
+	struct mmc_host *host = card->host;
+	unsigned int max_discard, x, y, qty = 0, max_qty, timeout;
+	unsigned int last_timeout = 0;
+
+	if (card->erase_shift)
+		max_qty = UINT_MAX >> card->erase_shift;
+	else if (mmc_card_sd(card))
+		max_qty = UINT_MAX;
+	else
+		max_qty = UINT_MAX / card->erase_size;
+
+	/* Find the largest qty with an OK timeout */
+	do {
+		y = 0;
+		for (x = 1; x && x <= max_qty && max_qty - x >= qty; x <<= 1) {
+			timeout = mmc_erase_timeout(card, arg, qty + x);
+			if (timeout > host->max_discard_to)
+				break;
+			if (timeout < last_timeout)
+				break;
+			last_timeout = timeout;
+			y = x;
+		}
+		qty += y;
+	} while (y);
+
+	if (!qty)
+		return 0;
+
+	if (qty == 1)
+		return 1;
+
+	/* Convert qty to sectors */
+	if (card->erase_shift)
+		max_discard = --qty << card->erase_shift;
+	else if (mmc_card_sd(card))
+		max_discard = qty;
+	else
+		max_discard = --qty * card->erase_size;
+
+	return max_discard;
+}
+
+unsigned int mmc_calc_max_discard(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	unsigned int max_discard, max_trim;
+
+	if (!host->max_discard_to)
+		return UINT_MAX;
+
+	/*
+	 * Without erase_group_def set, MMC erase timeout depends on clock
+	 * frequence which can change.  In that case, the best choice is
+	 * just the preferred erase size.
+	 */
+	if (mmc_card_mmc(card) && !(card->ext_csd.erase_group_def & 1))
+		return card->pref_erase;
+
+	max_discard = mmc_do_calc_max_discard(card, MMC_ERASE_ARG);
+	if (mmc_can_trim(card)) {
+		max_trim = mmc_do_calc_max_discard(card, MMC_TRIM_ARG);
+		if (max_trim < max_discard)
+			max_discard = max_trim;
+	} else if (max_discard < card->erase_size) {
+		max_discard = 0;
+	}
+	pr_debug("%s: calculated max. discard sectors %u for timeout %u ms\n",
+		 mmc_hostname(host), max_discard, host->max_discard_to);
+	return max_discard;
+}
+EXPORT_SYMBOL(mmc_calc_max_discard);
+
 int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
 {
 	struct mmc_command cmd = {0};
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 791f060..86d81cf 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -155,6 +155,7 @@ extern int mmc_can_trim(struct mmc_card *card);
 extern int mmc_can_secure_erase_trim(struct mmc_card *card);
 extern int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from,
 				   unsigned int nr);
+extern unsigned int mmc_calc_max_discard(struct mmc_card *card);
 
 extern int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen);
 
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index ac3fbac..0adecb1 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -230,6 +230,7 @@ struct mmc_host {
 	unsigned int		max_req_size;	/* maximum number of bytes in one req */
 	unsigned int		max_blk_size;	/* maximum size of one mmc block */
 	unsigned int		max_blk_count;	/* maximum number of blocks in one req */
+	unsigned int		max_discard_to;	/* max. discard timeout in ms */
 
 	/* private data */
 	spinlock_t		lock;		/* lock for claim and bus ops */
-- 
1.7.4.4


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/2] mmc: sdhci: specify maximum discard timeout
  2011-06-28 14:16 [PATCH 0/2] maximum discard size Adrian Hunter
  2011-06-28 14:16 ` [PATCH 1/2] mmc: queue: let host controllers specify maximum discard timeout Adrian Hunter
@ 2011-06-28 14:16 ` Adrian Hunter
  2011-07-15 18:59 ` [PATCH 0/2] maximum discard size Adrian Hunter
  2 siblings, 0 replies; 5+ messages in thread
From: Adrian Hunter @ 2011-06-28 14:16 UTC (permalink / raw)
  To: Chris Ball; +Cc: linux-mmc, Philip Rakity, Adrian Hunter

In general, SDHC hardware timeout cannot be avoided.
Accordingly, the maximum timeout is specified to limit
the maximum discard size.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/mmc/host/sdhci.c |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 91d9892..f7e0434 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2488,6 +2488,11 @@ int sdhci_add_host(struct sdhci_host *host)
 	} else
 		mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200;
 
+	if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)
+		mmc->max_discard_to = (1 << 27) / (mmc->f_max / 1000);
+	else
+		mmc->max_discard_to = (1 << 27) / host->timeout_clk;
+
 	mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23;
 
 	if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12)
-- 
1.7.4.4


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 0/2] maximum discard size
  2011-06-28 14:16 [PATCH 0/2] maximum discard size Adrian Hunter
  2011-06-28 14:16 ` [PATCH 1/2] mmc: queue: let host controllers specify maximum discard timeout Adrian Hunter
  2011-06-28 14:16 ` [PATCH 2/2] mmc: sdhci: " Adrian Hunter
@ 2011-07-15 18:59 ` Adrian Hunter
  2011-07-15 21:46   ` Chris Ball
  2 siblings, 1 reply; 5+ messages in thread
From: Adrian Hunter @ 2011-07-15 18:59 UTC (permalink / raw)
  To: Chris Ball; +Cc: Adrian Hunter, linux-mmc, Philip Rakity

On 28/06/2011 5:16 p.m., Adrian Hunter wrote:
> Hi
>
> Here is a patch that sets a maximum discard size for host controllers
> that cannot manage large timeouts.  And another patch putting it into
> use for shdci.

Can this be applied?

> Adrian Hunter (2):
>        mmc: queue: let host controllers specify maximum discard timeout
>        mmc: sdhci: specify maximum discard timeout
>
>   drivers/mmc/card/queue.c |   33 ++++++++++++++------
>   drivers/mmc/core/core.c  |   76 ++++++++++++++++++++++++++++++++++++++++++++++
>   drivers/mmc/host/sdhci.c |    5 +++
>   include/linux/mmc/core.h |    1 +
>   include/linux/mmc/host.h |    1 +
>   5 files changed, 106 insertions(+), 10 deletions(-)
>
> Regards
> Adrian Hunter
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 0/2] maximum discard size
  2011-07-15 18:59 ` [PATCH 0/2] maximum discard size Adrian Hunter
@ 2011-07-15 21:46   ` Chris Ball
  0 siblings, 0 replies; 5+ messages in thread
From: Chris Ball @ 2011-07-15 21:46 UTC (permalink / raw)
  To: Adrian Hunter; +Cc: linux-mmc, Philip Rakity

Hi Adrian,

On Fri, Jul 15 2011, Adrian Hunter wrote:
>> Here is a patch that sets a maximum discard size for host controllers
>> that cannot manage large timeouts.  And another patch putting it into
>> use for shdci.
>
> Can this be applied?
>
>> Adrian Hunter (2):
>>        mmc: queue: let host controllers specify maximum discard timeout
>>        mmc: sdhci: specify maximum discard timeout

These two are already in mmc-next for 3.1 -- looks like I forgot to send
an e-mail letting you know I'd merged them, sorry.

Thanks,

- Chris.
-- 
Chris Ball   <cjb@laptop.org>   <http://printf.net/>
One Laptop Per Child

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2011-07-15 21:47 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-06-28 14:16 [PATCH 0/2] maximum discard size Adrian Hunter
2011-06-28 14:16 ` [PATCH 1/2] mmc: queue: let host controllers specify maximum discard timeout Adrian Hunter
2011-06-28 14:16 ` [PATCH 2/2] mmc: sdhci: " Adrian Hunter
2011-07-15 18:59 ` [PATCH 0/2] maximum discard size Adrian Hunter
2011-07-15 21:46   ` Chris Ball

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox