diff mbox

[[RFC] 5/5] MMC: Toshiba eMMC - Part reliability improvement.

Message ID 1299295274-32130-6-git-send-email-andreiw@motorola.com (mailing list archive)
State New, archived
Headers show

Commit Message

Andrei Warkentin March 5, 2011, 3:21 a.m. UTC
None
diff mbox

Patch

diff --git a/drivers/mmc/card/Kconfig b/drivers/mmc/card/Kconfig
index af2800e..5c2f090 100644
--- a/drivers/mmc/card/Kconfig
+++ b/drivers/mmc/card/Kconfig
@@ -29,6 +29,37 @@  config MMC_BLOCK_QUIRK_TOSHIBA_32NM
          Say Y if you have a Toshiba 32nm technology flash device,
 	 such as MMC32G or MMC16G eMMCs.
 
+config MMC_BLOCK_QUIRK_TOSHIBA_32NM_REL
+       tristate "Toshiba MMC 32nm reliability quirk"
+       depends on MMC_BLOCK_QUIRK_TOSHIBA_32NM
+       default n
+       help
+         Say Y if you want to enable the improved reliability workaround
+	 for your Toshiba 32nm parts. This will result in certain-sized
+	 writes to be split up into 8K chunks, to ensure they are placed
+	 in the smaller 8KB buffer instead of the 4MB buffer, which should
+	 reduce the number of flash write-erase cycles and improve
+	 reliability. By default accesses in the 24k-32k range are
+	 split.
+
+config MMC_BLOCK_QUIRK_TOSHIBA_32NM_REL_L
+       hex "Toshiba reliability lower bound (in blocks)"
+       depends on MMC_BLOCK_QUIRK_TOSHIBA_32NM_REL
+       default "30"
+       help
+         Accesses smaller than the lower bound will not be split.
+	 This value should be experimentally found to match load
+	 and performance characteristics.
+
+config MMC_BLOCK_QUIRK_TOSHIBA_32NM_REL_U
+       hex "Toshiba reliability upper bound (in blocks)"
+       depends on MMC_BLOCK_QUIRK_TOSHIBA_32NM_REL
+       default "40"
+       help
+         Accesses bigger than the upper bound will not be split.
+	 This value should be experimentally found to match load
+	 and performance characteristics.
+
 config MMC_BLOCK_BOUNCE
 	bool "Use bounce buffer for simple hosts"
 	depends on MMC_BLOCK
diff --git a/drivers/mmc/card/block-quirks.c b/drivers/mmc/card/block-quirks.c
index 4afa872..c918e12 100644
--- a/drivers/mmc/card/block-quirks.c
+++ b/drivers/mmc/card/block-quirks.c
@@ -9,8 +9,10 @@ 
  *
  */
 #include <linux/kernel.h>
+#include <linux/blkdev.h>
 #include <linux/semaphore.h>
 #include <linux/mmc/card.h>
+#include <linux/mmc/mmc.h>
 
 #include "queue.h"
 #include "blk.h"
@@ -19,6 +21,11 @@ 
 static int toshiba_32nm_probe(struct mmc_blk_data *md, struct mmc_card *card)
 {
 	printk(KERN_INFO "Applying Toshiba 32nm workarounds\n");
+#ifdef CONFIG_MMC_BLOCK_QUIRK_TOSHIBA_32NM_REL
+	printk(KERN_INFO "Toshiba 32nm reliability splits over 0x%x-0x%x blocks\n",
+	       CONFIG_MMC_BLOCK_QUIRK_TOSHIBA_32NM_REL_L,
+	       CONFIG_MMC_BLOCK_QUIRK_TOSHIBA_32NM_REL_U);
+#endif
 
 	/* Page size 8K, this card doesn't like unaligned writes
 	   across 8K boundary. */
@@ -29,6 +36,43 @@  static int toshiba_32nm_probe(struct mmc_blk_data *md, struct mmc_card *card)
 	md->write_align_limit = 12288;
 	return 0;
 }
+
+#ifdef CONFIG_MMC_BLOCK_QUIRK_TOSHIBA_32NM_REL
+static void toshiba_32nm_adjust(struct mmc_queue *mq,
+				struct request *req,
+				struct mmc_request *mrq)
+{
+
+	int err;
+	struct mmc_command cmd;
+	struct mmc_blk_data *md = mq->data;
+	struct mmc_card *card = md->queue.card;
+
+	if (rq_data_dir(req) != WRITE)
+		return;
+
+	if (blk_rq_sectors(req) > CONFIG_MMC_BLOCK_QUIRK_TOSHIBA_32NM_REL_U ||
+	    blk_rq_sectors(req) < CONFIG_MMC_BLOCK_QUIRK_TOSHIBA_32NM_REL_L)
+		return;
+
+	/* 8K chunks */
+	if (mrq->data->blocks > 16)
+		mrq->data->blocks = 16;
+
+	/*
+	  We know what the valid values for this card are,
+	  no need to check EXT_CSD_REL_WR_SEC_C.
+	 */
+	cmd.opcode = MMC_SET_BLOCK_COUNT | (1 << 31);
+	cmd.arg = mrq->data->blocks;
+	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+	err = mmc_wait_for_cmd(card->host, &cmd, 0);
+	if (!err)
+		mrq->stop = NULL;
+}
+#else
+#define toshiba_32nm_adjust NULL
+#endif /* CONFIG_MMC_BLOCK_QUIRK_TOSHIBA_32NM_REL */
 #endif /* CONFIG_MMC_BLOCK_QUIRK_TOSHIBA_32NM */
 
 /*
@@ -39,8 +83,10 @@  static int toshiba_32nm_probe(struct mmc_blk_data *md, struct mmc_card *card)
 */
 struct mmc_blk_quirk mmc_blk_quirks[] = {
 #ifdef CONFIG_MMC_BLOCK_QUIRK_TOSHIBA_32NM
-        MMC_BLK_QUIRK("MMC16G", 0x11, 0x0, toshiba_32nm_probe, NULL),
-        MMC_BLK_QUIRK("MMC32G", 0x11, 0x0100, toshiba_32nm_probe, NULL),
+        MMC_BLK_QUIRK("MMC16G", 0x11, 0x0,
+		      toshiba_32nm_probe, toshiba_32nm_adjust),
+        MMC_BLK_QUIRK("MMC32G", 0x11, 0x0100,
+		      toshiba_32nm_probe, toshiba_32nm_adjust),
 #endif /* CONFIG_MMC_BLOCK_QUIRK_TOSHIBA_32NM */
 };