mmc: use percentage changed sectors as indication to check BKOPS need
In order to keep card endurance, it is best not to check the need for
BKOPS every time the MMC is idle.
However, the decision when to check the card need for BKOPS according
to number of changed sectors doesn't fit all cards sizes. Therefore,
the check for BKOPS need is based on percentages of changed sectors
of the card size.
In order to assure that BKOPS will be triggered again in case it was
interrupted, the accumulated number of changed sectors is cleared only
in case BKOPS was completed without interruption.
Change-Id: I598f64b652a524a431b87d103fd5890b808f11b1
Signed-off-by: Maya Erez <merez@codeaurora.org>
(cherry picked from commit e1eae988976536834759a45cf7f62e1cb2b82838)
diff --git a/Documentation/mmc/mmc-dev-attrs.txt b/Documentation/mmc/mmc-dev-attrs.txt
index 7dde34f..6b712dd 100644
--- a/Documentation/mmc/mmc-dev-attrs.txt
+++ b/Documentation/mmc/mmc-dev-attrs.txt
@@ -25,14 +25,14 @@
running parallel lmdd write and lmdd read operations and calculating
the max number of packed writes requests.
- min_sectors_to_check_bkops_status This attribute is used to
- determine whether the status bit that indicates the need for BKOPS
- should be checked. The value is stored in this attribute represents
- 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>/min_sectors_to_check_bkops_status
+ 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 b3cf4c7..3348aef 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -121,7 +121,7 @@
struct device_attribute force_ro;
struct device_attribute power_ro_lock;
struct device_attribute num_wr_reqs_to_start_packing;
- struct device_attribute min_sectors_to_check_bkops_status;
+ struct device_attribute bkops_check_threshold;
int area_type;
};
@@ -308,43 +308,60 @@
}
static ssize_t
-min_sectors_to_check_bkops_status_show(struct device *dev,
+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));
- unsigned int min_sectors_to_check_bkops_status;
struct mmc_card *card = md->queue.card;
int ret;
if (!card)
- return -EINVAL;
-
- min_sectors_to_check_bkops_status =
- card->bkops_info.min_sectors_to_queue_delayed_work;
-
- ret = snprintf(buf, PAGE_SIZE, "%d\n",
- min_sectors_to_check_bkops_status);
+ ret = -EINVAL;
+ else
+ ret = snprintf(buf, PAGE_SIZE, "%d\n",
+ card->bkops_info.size_percentage_to_queue_delayed_work);
mmc_blk_put(md);
return ret;
}
static ssize_t
-min_sectors_to_check_bkops_status_store(struct device *dev,
+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)
- return -EINVAL;
+ if (!card) {
+ ret = -EINVAL;
+ goto exit;
+ }
sscanf(buf, "%d", &value);
- if (value >= 0)
- card->bkops_info.min_sectors_to_queue_delayed_work = 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_queue_delayed_work = value;
+ card->bkops_info.min_sectors_to_queue_delayed_work =
+ (card_size * value) / 100;
+
+ pr_debug("%s: size_percentage = %d, min_sectors = %d",
+ mmc_hostname(card->host),
+ card->bkops_info.size_percentage_to_queue_delayed_work,
+ card->bkops_info.min_sectors_to_queue_delayed_work);
+
+exit:
mmc_blk_put(md);
return count;
}
@@ -2094,6 +2111,8 @@
{
struct mmc_blk_data *md;
int devidx, ret;
+ unsigned int percentage =
+ BKOPS_SIZE_PERCENTAGE_TO_QUEUE_DELAYED_WORK;
devidx = find_first_zero_bit(dev_use, max_devices);
if (devidx >= max_devices)
@@ -2171,6 +2190,10 @@
blk_queue_logical_block_size(md->queue.queue, 512);
set_capacity(md->disk, size);
+ card->bkops_info.size_percentage_to_queue_delayed_work = percentage;
+ card->bkops_info.min_sectors_to_queue_delayed_work =
+ ((unsigned int)size * percentage) / 100;
+
if (mmc_host_cmd23(card->host)) {
if (mmc_card_mmc(card) ||
(mmc_card_sd(card) &&
@@ -2363,22 +2386,19 @@
if (ret)
goto num_wr_reqs_to_start_packing_fail;
- md->min_sectors_to_check_bkops_status.show =
- min_sectors_to_check_bkops_status_show;
- md->min_sectors_to_check_bkops_status.store =
- min_sectors_to_check_bkops_status_store;
- sysfs_attr_init(&md->min_sectors_to_check_bkops_status.attr);
- md->min_sectors_to_check_bkops_status.attr.name =
- "min_sectors_to_check_bkops_status";
- md->min_sectors_to_check_bkops_status.attr.mode = S_IRUGO | S_IWUSR;
+ md->bkops_check_threshold.show = bkops_check_threshold_show;
+ md->bkops_check_threshold.store = bkops_check_threshold_store;
+ sysfs_attr_init(&md->bkops_check_threshold.attr);
+ md->bkops_check_threshold.attr.name = "bkops_check_threshold";
+ md->bkops_check_threshold.attr.mode = S_IRUGO | S_IWUSR;
ret = device_create_file(disk_to_dev(md->disk),
- &md->min_sectors_to_check_bkops_status);
+ &md->bkops_check_threshold);
if (ret)
- goto min_sectors_to_check_bkops_status_fails;
+ goto bkops_check_threshold_fails;
return ret;
-min_sectors_to_check_bkops_status_fails:
+bkops_check_threshold_fails:
device_remove_file(disk_to_dev(md->disk),
&md->num_wr_reqs_to_start_packing);
num_wr_reqs_to_start_packing_fail:
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 95c4426..33d9178 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -297,8 +297,6 @@
pr_debug("%s: %s: queueing delayed_bkops_work\n",
mmc_hostname(card->host), __func__);
- card->bkops_info.sectors_changed = 0;
-
/*
* cancel_delayed_bkops_work will prevent a race condition between
* fetching a request by the mmcqd and the delayed work, in case
@@ -448,6 +446,7 @@
pr_debug("%s: %s: completed BKOPs, exit polling\n",
mmc_hostname(card->host), __func__);
mmc_card_clr_doing_bkops(card);
+ card->bkops_info.sectors_changed = 0;
goto out;
}
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 38fce13..d4af93d 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1334,9 +1334,6 @@
if (card->bkops_info.host_delay_ms)
card->bkops_info.delay_ms =
card->bkops_info.host_delay_ms;
-
- card->bkops_info.min_sectors_to_queue_delayed_work =
- BKOPS_MIN_SECTORS_TO_QUEUE_DELAYED_WORK;
}
}
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 8807ef1..e592709 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -236,6 +236,12 @@
* @host_delay_ms: The host controller time to start bkops
* @delay_ms: The time to start the BKOPS
* delayed work once MMC thread is idle
+ * @min_sectors_to_queue_delayed_work: the changed
+ * number of sectors that should issue check for BKOPS
+ * need
+ * @size_percentage_to_queue_delayed_work: the changed
+ * percentage of sectors that should issue check for
+ * BKOPS need
* @poll_for_completion: Poll on BKOPS completion
* @cancel_delayed_work: A flag to indicate if the delayed work
* should be cancelled
@@ -247,6 +253,7 @@
unsigned int host_delay_ms;
unsigned int delay_ms;
unsigned int min_sectors_to_queue_delayed_work;
+ unsigned int size_percentage_to_queue_delayed_work;
/*
* A default time for checking the need for non urgent BKOPS once mmcqd
* is idle.
@@ -264,9 +271,8 @@
* mmcqd thread is idle.
* The delayed work for idle BKOPS will be scheduled only after a significant
* amount of write or discard data.
- * 100MB is chosen based on benchmark tests.
*/
-#define BKOPS_MIN_SECTORS_TO_QUEUE_DELAYED_WORK 204800 /* 100MB */
+#define BKOPS_SIZE_PERCENTAGE_TO_QUEUE_DELAYED_WORK 1 /* 1% */
};
/*