Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 881d1c25 authored by Seungwon Jeon's avatar Seungwon Jeon Committed by Chris Ball
Browse files

mmc: core: Add cache control for eMMC4.5 device



This patch adds cache feature of eMMC4.5 Spec.
If device supports cache capability, host can utilize some specific
operations.

Signed-off-by: default avatarSeungwon Jeon <tgih.jun@samsung.com>
Signed-off-by: default avatarJaehoon Chung <jh80.chung@samsung.com>
Signed-off-by: default avatarChris Ball <cjb@laptop.org>
parent 71fe3eb0
Loading
Loading
Loading
Loading
+8 −6
Original line number Diff line number Diff line
@@ -851,16 +851,18 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req)
{
	struct mmc_blk_data *md = mq->data;
	struct mmc_card *card = md->queue.card;
	int ret = 0;

	ret = mmc_flush_cache(card);
	if (ret)
		ret = -EIO;

	/*
	 * No-op, only service this because we need REQ_FUA for reliable
	 * writes.
	 */
	spin_lock_irq(&md->lock);
	__blk_end_request_all(req, 0);
	__blk_end_request_all(req, ret);
	spin_unlock_irq(&md->lock);

	return 1;
	return ret ? 0 : 1;
}

/*
+63 −0
Original line number Diff line number Diff line
@@ -2158,6 +2158,65 @@ int mmc_card_can_sleep(struct mmc_host *host)
}
EXPORT_SYMBOL(mmc_card_can_sleep);

/*
 * Flush the cache to the non-volatile storage.
 */
int mmc_flush_cache(struct mmc_card *card)
{
	struct mmc_host *host = card->host;
	int err = 0;

	if (!(host->caps2 & MMC_CAP2_CACHE_CTRL))
		return err;

	if (mmc_card_mmc(card) &&
			(card->ext_csd.cache_size > 0) &&
			(card->ext_csd.cache_ctrl & 1)) {
		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
				EXT_CSD_FLUSH_CACHE, 1, 0);
		if (err)
			pr_err("%s: cache flush error %d\n",
					mmc_hostname(card->host), err);
	}

	return err;
}
EXPORT_SYMBOL(mmc_flush_cache);

/*
 * Turn the cache ON/OFF.
 * Turning the cache OFF shall trigger flushing of the data
 * to the non-volatile storage.
 */
int mmc_cache_ctrl(struct mmc_host *host, u8 enable)
{
	struct mmc_card *card = host->card;
	int err = 0;

	if (!(host->caps2 & MMC_CAP2_CACHE_CTRL) ||
			mmc_card_is_removable(host))
		return err;

	if (card && mmc_card_mmc(card) &&
			(card->ext_csd.cache_size > 0)) {
		enable = !!enable;

		if (card->ext_csd.cache_ctrl ^ enable)
			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
					EXT_CSD_CACHE_CTRL, enable, 0);
		if (err)
			pr_err("%s: cache %s error %d\n",
					mmc_hostname(card->host),
					enable ? "on" : "off",
					err);
		else
			card->ext_csd.cache_ctrl = enable;
	}

	return err;
}
EXPORT_SYMBOL(mmc_cache_ctrl);

#ifdef CONFIG_PM

/**
@@ -2172,6 +2231,9 @@ int mmc_suspend_host(struct mmc_host *host)
		cancel_delayed_work(&host->disable);
	cancel_delayed_work(&host->detect);
	mmc_flush_scheduled_work();
	err = mmc_cache_ctrl(host, 0);
	if (err)
		goto out;

	mmc_bus_get(host);
	if (host->bus_ops && !host->bus_dead) {
@@ -2197,6 +2259,7 @@ int mmc_suspend_host(struct mmc_host *host)
	if (!err && !mmc_card_keep_power(host))
		mmc_power_off(host);

out:
	return err;
}

+23 −0
Original line number Diff line number Diff line
@@ -470,6 +470,12 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
	} else
		card->ext_csd.generic_cmd6_time = 0;

	card->ext_csd.cache_size =
		ext_csd[EXT_CSD_CACHE_SIZE + 0] << 0 |
		ext_csd[EXT_CSD_CACHE_SIZE + 1] << 8 |
		ext_csd[EXT_CSD_CACHE_SIZE + 2] << 16 |
		ext_csd[EXT_CSD_CACHE_SIZE + 3] << 24;

out:
	return err;
}
@@ -1020,6 +1026,23 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
		}
	}

	/*
	 * If cache size is higher than 0, this indicates
	 * the existence of cache and it can be turned on.
	 */
	if ((host->caps2 & MMC_CAP2_CACHE_CTRL) &&
			card->ext_csd.cache_size > 0) {
		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
				EXT_CSD_CACHE_CTRL, 1, 0);
		if (err && err != -EBADMSG)
			goto free_card;

		/*
		 * Only if no error, cache is turned on successfully.
		 */
		card->ext_csd.cache_ctrl = err ? 0 : 1;
	}

	if (!oldcard)
		host->card = card;

+2 −0
Original line number Diff line number Diff line
@@ -51,6 +51,7 @@ struct mmc_ext_csd {
	u8			rel_sectors;
	u8			rel_param;
	u8			part_config;
	u8			cache_ctrl;
	u8			rst_n_function;
	unsigned int		part_time;		/* Units: ms */
	unsigned int		sa_timeout;		/* Units: 100ns */
@@ -67,6 +68,7 @@ struct mmc_ext_csd {
	bool			enhanced_area_en;	/* enable bit */
	unsigned long long	enhanced_area_offset;	/* Units: Byte */
	unsigned int		enhanced_area_size;	/* Units: KB */
	unsigned int		cache_size;		/* Units: KB */
	u8			raw_partition_support;	/* 160 */
	u8			raw_erased_mem_count;	/* 181 */
	u8			raw_ext_csd_structure;	/* 194 */
+2 −0
Original line number Diff line number Diff line
@@ -177,6 +177,8 @@ extern void mmc_release_host(struct mmc_host *host);
extern void mmc_do_release_host(struct mmc_host *host);
extern int mmc_try_claim_host(struct mmc_host *host);

extern int mmc_flush_cache(struct mmc_card *);

/**
 *	mmc_claim_host - exclusively claim a host
 *	@host: mmc host to claim
Loading