mmc: core: enable BKOPS by read-modify-write instead of override

This change adds a read-modify-write logic to BKOPS feature enable.
It is required in order to avoid overriding other fields defined
in BKOPS_EN register.

Change-Id: I689f5cd14d9ec1bb881f503a0418026a59e6c197
Signed-off-by: Talel Shenhar <tatias@codeaurora.org>
This commit is contained in:
Talel Shenhar 2014-12-30 11:24:39 +02:00
parent 2c3155a818
commit 18a5a61a84
7 changed files with 45 additions and 17 deletions

View File

@ -1352,7 +1352,7 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
from = blk_rq_pos(req);
nr = blk_rq_sectors(req);
if (card->ext_csd.bkops_en)
if (mmc_card_get_bkops_en_manual(card))
card->bkops_info.sectors_changed += blk_rq_sectors(req);
if (mmc_can_discard(card))
@ -2296,7 +2296,7 @@ static u8 mmc_blk_prep_packed_list(struct mmc_queue *mq, struct request *req)
if (rq_data_dir(next) == WRITE) {
mq->num_of_potential_packed_wr_reqs++;
if (card->ext_csd.bkops_en)
if (mmc_card_get_bkops_en_manual(card))
card->bkops_info.sectors_changed +=
blk_rq_sectors(next);
}
@ -2553,7 +2553,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
return 0;
if (rqc) {
if ((card->ext_csd.bkops_en) && (rq_data_dir(rqc) == WRITE))
if (mmc_card_get_bkops_en_manual(card) &&
(rq_data_dir(rqc) == WRITE))
card->bkops_info.sectors_changed += blk_rq_sectors(rqc);
reqs = mmc_blk_prep_packed_list(mq, rqc);
}
@ -2768,7 +2769,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
if (mmc_bus_needs_resume(card->host))
mmc_resume_bus(card->host);
#endif
if (card->ext_csd.bkops_en)
if (mmc_card_get_bkops_en_manual(card))
mmc_stop_bkops(card);
}

View File

@ -1788,7 +1788,7 @@ static int prepare_bkops(struct test_data *td)
bkops_stat = &card->bkops_info.bkops_stats;
if (!card->ext_csd.bkops_en) {
if (!(mmc_card_get_bkops_en_manual(card))) {
pr_err("%s: BKOPS is not enabled by card or host)",
__func__);
return -ENOTSUPP;

View File

@ -400,7 +400,9 @@ EXPORT_SYMBOL(mmc_blk_init_bkops_statistics);
*/
void mmc_start_delayed_bkops(struct mmc_card *card)
{
if (!card || !card->ext_csd.bkops_en || mmc_card_doing_bkops(card))
if (!card ||
!(mmc_card_get_bkops_en_manual(card)) ||
mmc_card_doing_bkops(card))
return;
if (card->bkops_info.sectors_changed <
@ -437,7 +439,7 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception)
int err;
BUG_ON(!card);
if (!card->ext_csd.bkops_en)
if (!(mmc_card_get_bkops_en_manual(card)))
return;
if ((card->bkops_info.cancel_delayed_work) && !from_exception) {

View File

@ -19,6 +19,7 @@
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include "core.h"
#include "mmc_ops.h"
@ -725,7 +726,7 @@ void mmc_add_card_debugfs(struct mmc_card *card)
goto err;
if (mmc_card_mmc(card) && (card->ext_csd.rev >= 5) &&
card->ext_csd.bkops_en)
(mmc_card_get_bkops_en_manual(card)))
if (!debugfs_create_file("bkops_stats", S_IRUSR, root, card,
&mmc_dbg_bkops_stats_fops))
goto err;

View File

@ -10,6 +10,7 @@
* published by the Free Software Foundation.
*/
#include <linux/bitops.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/stat.h>
@ -530,15 +531,19 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
card->ext_csd.bkops_en = ext_csd[EXT_CSD_BKOPS_EN];
card->ext_csd.raw_bkops_status =
ext_csd[EXT_CSD_BKOPS_STATUS];
if (!card->ext_csd.bkops_en &&
if (!(mmc_card_get_bkops_en_manual(card)) &&
card->host->caps2 & MMC_CAP2_INIT_BKOPS) {
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BKOPS_EN, 1, 0);
if (err)
mmc_card_set_bkops_en_manual(card);
err = mmc_switch(card,
EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BKOPS_EN,
card->ext_csd.bkops_en , 0);
if (err) {
pr_warn("%s: Enabling BKOPS failed\n",
mmc_hostname(card->host));
else
card->ext_csd.bkops_en = 1;
mmc_card_clr_bkops_en_manual(card);
}
}
}
@ -1686,8 +1691,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
goto free_card;
}
}
if (card->ext_csd.bkops_en) {
if (mmc_card_get_bkops_en_manual(card)) {
INIT_DELAYED_WORK(&card->bkops_info.dw,
mmc_start_idle_time_bkops);

View File

@ -84,7 +84,7 @@ struct mmc_ext_csd {
bool hpi; /* HPI support bit */
unsigned int hpi_cmd; /* cmd used as HPI */
bool bkops; /* background support bit */
bool bkops_en; /* background enable bit */
u8 bkops_en; /* background enable bits */
unsigned int data_sector_size; /* 512 bytes or 4KB */
unsigned int data_tag_unit_size; /* DATA TAG UNIT size */
unsigned int boot_ro_lock; /* ro lock support */
@ -401,6 +401,23 @@ struct mmc_card {
u8 *cached_ext_csd;
};
/*
* mmc_csd registers get/set/clr helpers
*/
#define mmc_card_get_bkops_en_manual(card) ((card->ext_csd.bkops_en) &\
EXT_CSD_BKOPS_EN_MANUAL_EN)
#define mmc_card_set_bkops_en_manual(card) ((card->ext_csd.bkops_en) |= \
EXT_CSD_BKOPS_EN_MANUAL_EN)
#define mmc_card_clr_bkops_en_manual(card) ((card->ext_csd.bkops_en) &= \
~EXT_CSD_BKOPS_EN_MANUAL_EN)
#define mmc_card_get_bkops_en_auto(card) ((card->ext_csd.bkops_en) & \
EXT_CSD_BKOPS_EN_AUTO_EN)
#define mmc_card_set_bkops_en_auto(card) ((card->ext_csd.bkops_en) |= \
EXT_CSD_BKOPS_EN_AUTO_EN)
#define mmc_card_clr_bkops_en_auto(card) ((card->ext_csd.bkops_en) &= \
~EXT_CSD_BKOPS_EN_AUTO_EN)
/*
* This function fill contents in mmc_part.
*/

View File

@ -282,6 +282,9 @@ struct _mmc_csd {
* EXT_CSD field definitions
*/
#define EXT_CSD_BKOPS_EN_MANUAL_EN BIT(0)
#define EXT_CSD_BKOPS_EN_AUTO_EN BIT(1)
#define EXT_CSD_WR_REL_PARAM_EN (1<<2)
#define EXT_CSD_BOOT_WP_B_PWR_WP_DIS (0x40)