[PATCH v6] mmc: core: Add support for idle time BKOPS

2013-04-14 Thread Maya Erez
Devices have various maintenance operations need to perform internally.
In order to reduce latencies during time critical operations like read
and write, it is better to execute maintenance operations in other
times - when the host is not being serviced. Such operations are called
Background operations (BKOPS).
The device notifies the status of the BKOPS need by updating BKOPS_STATUS
(EXT_CSD byte [246]).

According to the standard a host that supports BKOPS shall check the
status periodically and start background operations as needed, so that
the device has enough time for its maintenance operations.

This patch adds support for this periodic check of the BKOPS status.
Since foreground operations are of higher priority than background
operations the host will check the need for BKOPS when it is idle
(in runtime suspend), and in case of an incoming request the BKOPS
operation will be interrupted.

If the card raised an exception with need for urgent BKOPS (level 2/3)
a flag will be set to indicate MMC to start the BKOPS activity when it
becomes idle.

Since running the BKOPS too often can impact the eMMC endurance, the card
need for BKOPS is not checked on every runtime suspend. In order to estimate
when is the best time to check for BKOPS need the host will take into
account the card capacity and percentages of changed sectors in the card.
A future enhancement can be to check the card need for BKOPS only in case
of random activity.

Signed-off-by: Maya Erez 
---
This patch depends on the following patches:
[PATCH V2 1/2] mmc: core: Add bus_ops fro runtime pm callbacks
[PATCH V2 2/2] mmc: block: Enable runtime pm for mmc blkdevice
---
diff --git a/Documentation/mmc/mmc-dev-attrs.txt 
b/Documentation/mmc/mmc-dev-attrs.txt
index 189bab0..8257aa6 100644
--- a/Documentation/mmc/mmc-dev-attrs.txt
+++ b/Documentation/mmc/mmc-dev-attrs.txt
@@ -8,6 +8,15 @@ The following attributes are read/write.
 
force_roEnforce read-only access even if write protect 
switch is off.
 
+   bkops_check_threshold   This attribute is used to determine whether
+   the status bit that indicates the need for BKOPS should be checked.
+   The value should be given in percentages of the card size.
+   This value is used to calculate the minimum number of sectors that
+   needs to be changed in the device (written or discarded) in order to
+   require the status-bit of BKOPS to be checked.
+   The value can modified via sysfs by writing the required value to:
+   /sys/block//bkops_check_threshold
+
 SD and MMC Device Attributes
 
 
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 536331a..ef42117 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -116,6 +116,7 @@ struct mmc_blk_data {
unsigned intpart_curr;
struct device_attribute force_ro;
struct device_attribute power_ro_lock;
+   struct device_attribute bkops_check_threshold;
int area_type;
 };
 
@@ -287,6 +288,65 @@ out:
return ret;
 }
 
+static ssize_t
+bkops_check_threshold_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+   struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+   struct mmc_card *card = md->queue.card;
+   int ret;
+
+   if (!card)
+   ret = -EINVAL;
+   else
+   ret = snprintf(buf, PAGE_SIZE, "%d\n",
+   card->bkops_info.size_percentage_to_start_bkops);
+
+   mmc_blk_put(md);
+   return ret;
+}
+
+static ssize_t
+bkops_check_threshold_store(struct device *dev,
+struct device_attribute *attr,
+const char *buf, size_t count)
+{
+   int value;
+   struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+   struct mmc_card *card = md->queue.card;
+   unsigned int card_size;
+   int ret = count;
+
+   if (!card) {
+   ret = -EINVAL;
+   goto exit;
+   }
+
+   sscanf(buf, "%d", );
+   if ((value <= 0) || (value >= 100)) {
+   ret = -EINVAL;
+   goto exit;
+   }
+
+   card_size = (unsigned int)get_capacity(md->disk);
+   if (card_size <= 0) {
+   ret = -EINVAL;
+   goto exit;
+   }
+   card->bkops_info.size_percentage_to_start_bkops = value;
+   card->bkops_info.min_sectors_to_start_bkops =
+   (card_size * value) / 100;
+
+   pr_debug("%s: size_percentage = %d, min_sectors = %d",
+   mmc_hostname(card->host),
+   card->bkops_info.size_percentage_to_start_bkops,
+   card->bkops_info.min_sectors_to_start_bkops);
+
+exit:
+   mmc_blk_put(md);
+   return count;
+}
+
 static int mmc_blk_open(struct block_device *bdev, fmode_t mode)
 {
struct mmc_blk_data *md = mmc_blk_get(bdev->bd_disk);
@@ -914,6 

[PATCH v6] mmc: core: Add support for idle time BKOPS

2013-04-14 Thread Maya Erez
Devices have various maintenance operations need to perform internally.
In order to reduce latencies during time critical operations like read
and write, it is better to execute maintenance operations in other
times - when the host is not being serviced. Such operations are called
Background operations (BKOPS).
The device notifies the status of the BKOPS need by updating BKOPS_STATUS
(EXT_CSD byte [246]).

According to the standard a host that supports BKOPS shall check the
status periodically and start background operations as needed, so that
the device has enough time for its maintenance operations.

This patch adds support for this periodic check of the BKOPS status.
Since foreground operations are of higher priority than background
operations the host will check the need for BKOPS when it is idle
(in runtime suspend), and in case of an incoming request the BKOPS
operation will be interrupted.

If the card raised an exception with need for urgent BKOPS (level 2/3)
a flag will be set to indicate MMC to start the BKOPS activity when it
becomes idle.

Since running the BKOPS too often can impact the eMMC endurance, the card
need for BKOPS is not checked on every runtime suspend. In order to estimate
when is the best time to check for BKOPS need the host will take into
account the card capacity and percentages of changed sectors in the card.
A future enhancement can be to check the card need for BKOPS only in case
of random activity.

Signed-off-by: Maya Erez me...@codeaurora.org
---
This patch depends on the following patches:
[PATCH V2 1/2] mmc: core: Add bus_ops fro runtime pm callbacks
[PATCH V2 2/2] mmc: block: Enable runtime pm for mmc blkdevice
---
diff --git a/Documentation/mmc/mmc-dev-attrs.txt 
b/Documentation/mmc/mmc-dev-attrs.txt
index 189bab0..8257aa6 100644
--- a/Documentation/mmc/mmc-dev-attrs.txt
+++ b/Documentation/mmc/mmc-dev-attrs.txt
@@ -8,6 +8,15 @@ The following attributes are read/write.
 
force_roEnforce read-only access even if write protect 
switch is off.
 
+   bkops_check_threshold   This attribute is used to determine whether
+   the status bit that indicates the need for BKOPS should be checked.
+   The value should be given in percentages of the card size.
+   This value is used to calculate the minimum number of sectors that
+   needs to be changed in the device (written or discarded) in order to
+   require the status-bit of BKOPS to be checked.
+   The value can modified via sysfs by writing the required value to:
+   /sys/block/block_dev_name/bkops_check_threshold
+
 SD and MMC Device Attributes
 
 
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 536331a..ef42117 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -116,6 +116,7 @@ struct mmc_blk_data {
unsigned intpart_curr;
struct device_attribute force_ro;
struct device_attribute power_ro_lock;
+   struct device_attribute bkops_check_threshold;
int area_type;
 };
 
@@ -287,6 +288,65 @@ out:
return ret;
 }
 
+static ssize_t
+bkops_check_threshold_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+   struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+   struct mmc_card *card = md-queue.card;
+   int ret;
+
+   if (!card)
+   ret = -EINVAL;
+   else
+   ret = snprintf(buf, PAGE_SIZE, %d\n,
+   card-bkops_info.size_percentage_to_start_bkops);
+
+   mmc_blk_put(md);
+   return ret;
+}
+
+static ssize_t
+bkops_check_threshold_store(struct device *dev,
+struct device_attribute *attr,
+const char *buf, size_t count)
+{
+   int value;
+   struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+   struct mmc_card *card = md-queue.card;
+   unsigned int card_size;
+   int ret = count;
+
+   if (!card) {
+   ret = -EINVAL;
+   goto exit;
+   }
+
+   sscanf(buf, %d, value);
+   if ((value = 0) || (value = 100)) {
+   ret = -EINVAL;
+   goto exit;
+   }
+
+   card_size = (unsigned int)get_capacity(md-disk);
+   if (card_size = 0) {
+   ret = -EINVAL;
+   goto exit;
+   }
+   card-bkops_info.size_percentage_to_start_bkops = value;
+   card-bkops_info.min_sectors_to_start_bkops =
+   (card_size * value) / 100;
+
+   pr_debug(%s: size_percentage = %d, min_sectors = %d,
+   mmc_hostname(card-host),
+   card-bkops_info.size_percentage_to_start_bkops,
+   card-bkops_info.min_sectors_to_start_bkops);
+
+exit:
+   mmc_blk_put(md);
+   return count;
+}
+
 static int mmc_blk_open(struct block_device *bdev, fmode_t mode)
 {
struct mmc_blk_data *md =