The max_discard_sectors value is UINT_MAX which means kernel block
layer can pass down unlimited count of sectors to erase, but for some host
controller, erasing so many sectors at one time may be failed.

This patch added a new mmc capability to set the max_discard_sectors value
to one erase block which will be a safe value for those host controllers to
use. If host controller capability doesnot contain the new capability, the
max_discard_sectors value will not be changed.

Signed-off-by: Chuanxiao Dong <[email protected]>
---
 drivers/mmc/card/queue.c |    5 ++++-
 drivers/mmc/core/core.c  |   36 ++++++++++++++++++++++++++++++++++++
 include/linux/mmc/core.h |    2 ++
 include/linux/mmc/host.h |    2 ++
 4 files changed, 44 insertions(+), 1 deletions(-)

diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index f01528b..14c3492 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -131,7 +131,10 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card 
*card, spinlock_t *lock
        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;
+               /* get a suitable max_discard_sectors limitation */
+               mq->queue->limits.max_discard_sectors =
+                       mmc_set_discard_limit(card);
+
                if (card->erased_byte == 0)
                        mq->queue->limits.discard_zeroes_data = 1;
                if (!mmc_can_trim(card) && is_power_of_2(card->erase_size)) {
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index d464252..f28ae28 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1415,6 +1415,42 @@ int mmc_erase_group_aligned(struct mmc_card *card, 
unsigned int from,
 }
 EXPORT_SYMBOL(mmc_erase_group_aligned);
 
+/*
+ * mmc_set_discard_limit: set the max_discard_sectors according
+ * to host controller timeout capability.
+ *
+ * return value:
+ * nr: one erase block size if host has MMC_CAP_ERASE_SINGLE capbility
+ * UINT_MAX: no limitation if the erase block size to be 0 or host hasn't
+ * MMC_CAP_ERASE_SINGLE cap.
+ */
+int mmc_set_discard_limit(struct mmc_card *card)
+{
+       struct mmc_host *host;
+       unsigned int nr = 0;
+       host = card->host;
+       if (host->caps & MMC_CAP_ERASE_SINGLE) {
+               /*
+                * Have to set a small limitation for request queue
+                * to ensure that host controller won't generate a
+                * timeout interrupt during waiting, here let limitation
+                * to be 1 erase block. And this will let TRIM/ERASE
+                * performance lower.
+                */
+               nr = 1;
+               if (card->erase_shift)
+                       nr <<= card->erase_shift;
+               else
+                       nr *= card->erase_size;
+       }
+
+       if (nr == 0)
+               return UINT_MAX;
+       else
+               return nr;
+}
+EXPORT_SYMBOL(mmc_set_discard_limit);
+
 int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
 {
        struct mmc_command cmd;
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 64e013f..32b5d26 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -153,6 +153,8 @@ 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 int mmc_set_discard_limit(struct mmc_card *card);
+
 extern int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen);
 
 extern void mmc_set_data_timeout(struct mmc_data *, const struct mmc_card *);
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 01e4886..781507b 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -168,6 +168,8 @@ struct mmc_host {
                                                /* DDR mode at 1.8V */
 #define MMC_CAP_1_2V_DDR       (1 << 12)       /* can support */
                                                /* DDR mode at 1.2V */
+#define MMC_CAP_ERASE_SINGLE   (1 << 13)
+                               /* Erase signle erase block each time */
 
        mmc_pm_flag_t           pm_caps;        /* supported pm features */
 
-- 
1.6.6.1

_______________________________________________
MeeGo-kernel mailing list
[email protected]
http://lists.meego.com/listinfo/meego-kernel

Reply via email to