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

Commit bf533af9 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "mmc: core: Add tracepoints to enhance pm debugging"

parents cb0f99b5 53ffc855
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -871,7 +871,8 @@ static inline int mmc_blk_part_switch(struct mmc_card *card,
	int ret = 0;
	struct mmc_blk_data *main_md = dev_get_drvdata(&card->dev);

	if (main_md->part_curr == part_type)
	if ((main_md->part_curr == part_type) &&
		(card->part_curr == part_type))
		return 0;

	if (mmc_card_mmc(card)) {
+216 −66
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
#include <linux/mmc/mmc.h>
#include <linux/reboot.h>
#include <trace/events/mmc.h>

#include "core.h"
#include "card.h"
@@ -356,6 +358,53 @@ static void mmc_manage_gp_partitions(struct mmc_card *card, u8 *ext_csd)
	}
}

/* check whether the eMMC card supports HPI */
void mmc_check_hpi_support(struct mmc_card *card, u8 *ext_csd)
{
	if ((ext_csd[EXT_CSD_HPI_FEATURES] & 0x1) &&
		!(card->quirks & MMC_QUIRK_BROKEN_HPI)) {
		card->ext_csd.hpi = 1;
		if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x2)
			card->ext_csd.hpi_cmd = MMC_STOP_TRANSMISSION;
		else
			card->ext_csd.hpi_cmd = MMC_SEND_STATUS;
		/*
		 * Indicate the maximum timeout to close
		 * a command interrupted by HPI
		 */
		card->ext_csd.out_of_int_time =
			ext_csd[EXT_CSD_OUT_OF_INTERRUPT_TIME] * 10;
		pr_info("%s: Out-of-interrupt timeout is %d[ms]\n",
				mmc_hostname(card->host),
				card->ext_csd.out_of_int_time);
	}

}

/* Check bkops support of card */
void mmc_check_bkops_support(struct mmc_card *card, u8 *ext_csd)
{
	if (!mmc_card_broken_hpi(card) &&
	    (ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) &&
			card->ext_csd.hpi) {
		card->ext_csd.bkops = 1;
		card->ext_csd.man_bkops_en =
				(ext_csd[EXT_CSD_BKOPS_EN] &
					EXT_CSD_MANUAL_BKOPS_MASK);
		card->ext_csd.raw_bkops_status =
			ext_csd[EXT_CSD_BKOPS_STATUS];
		if (card->ext_csd.man_bkops_en)
			pr_debug("%s: MAN_BKOPS_EN bit is set\n",
				mmc_hostname(card->host));
		card->ext_csd.auto_bkops_en =
				(ext_csd[EXT_CSD_BKOPS_EN] &
					EXT_CSD_AUTO_BKOPS_MASK);
		if (card->ext_csd.auto_bkops_en)
			pr_debug("%s: AUTO_BKOPS_EN bit is set\n",
				mmc_hostname(card->host));
	}
}

/* Minimum partition switch timeout in milliseconds */
#define MMC_MIN_PART_SWITCH_TIME	300

@@ -521,30 +570,15 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
			ext_csd[EXT_CSD_PWR_CL_DDR_200_360];
	}

	mmc_check_hpi_support(card, ext_csd);

	if (card->ext_csd.rev >= 5) {
		/* Adjust production date as per JEDEC JESD84-B451 */
		if (card->cid.year < 2010)
			card->cid.year += 16;

		/* check whether the eMMC card supports BKOPS */
		if (!mmc_card_broken_hpi(card) &&
		    ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) {
			card->ext_csd.bkops = 1;
			card->ext_csd.man_bkops_en =
					(ext_csd[EXT_CSD_BKOPS_EN] &
						EXT_CSD_MANUAL_BKOPS_MASK);
			card->ext_csd.raw_bkops_status =
				ext_csd[EXT_CSD_BKOPS_STATUS];
			if (card->ext_csd.man_bkops_en)
				pr_debug("%s: MAN_BKOPS_EN bit is set\n",
					mmc_hostname(card->host));
			card->ext_csd.auto_bkops_en =
					(ext_csd[EXT_CSD_BKOPS_EN] &
						EXT_CSD_AUTO_BKOPS_MASK);
			if (card->ext_csd.auto_bkops_en)
				pr_debug("%s: AUTO_BKOPS_EN bit is set\n",
					mmc_hostname(card->host));
		}
		mmc_check_bkops_support(card, ext_csd);

		/* check whether the eMMC card supports HPI */
		if (!mmc_card_broken_hpi(card) &&
@@ -659,6 +693,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)

static int mmc_read_ext_csd(struct mmc_card *card)
{
	struct mmc_host *host = card->host;
	u8 *ext_csd;
	int err;

@@ -667,6 +702,8 @@ static int mmc_read_ext_csd(struct mmc_card *card)

	err = mmc_get_ext_csd(card, &ext_csd);
	if (err) {
		pr_err("%s: %s: mmc_get_ext_csd() fails %d\n",
			mmc_hostname(host), __func__, err);
		/* If the host or the card can't do the switch,
		 * fail more gracefully. */
		if ((err != -EINVAL)
@@ -1529,6 +1566,17 @@ static int mmc_select_hs200(struct mmc_card *card)
	return err;
}

static int mmc_reboot_notify(struct notifier_block *notify_block,
		unsigned long event, void *unused)
{
	struct mmc_card *card = container_of(
			notify_block, struct mmc_card, reboot_notify);

	card->pon_type = (event != SYS_RESTART) ? MMC_LONG_PON : MMC_SHRT_PON;

	return NOTIFY_OK;
}

/*
 * Activate High Speed, HS200 or HS400ES mode if supported.
 */
@@ -1582,8 +1630,7 @@ static int mmc_hs200_tuning(struct mmc_card *card)
	 */
	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 &&
	    host->ios.bus_width == MMC_BUS_WIDTH_8)
		if (host->ops->prepare_hs400_tuning)
			host->ops->prepare_hs400_tuning(host, &host->ios);
		mmc_set_timing(host, MMC_TIMING_MMC_HS400);

	return mmc_execute_tuning(card);
}
@@ -1827,6 +1874,21 @@ static int mmc_change_bus_speed_deferred(struct mmc_host *host,
out:
	return err;
}

void mmc_init_setup_scaling(struct mmc_card *card,
			struct mmc_host *host)
{
	card->clk_scaling_lowest = host->f_min;
	if ((card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400) ||
			(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200))
		card->clk_scaling_highest = card->ext_csd.hs200_max_dtr;
	else if ((card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS) ||
			(card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52))
		card->clk_scaling_highest = card->ext_csd.hs_max_dtr;
	else
		card->clk_scaling_highest = card->csd.max_dtr;
}

/*
 * Handle the detection and initialisation of a card.
 *
@@ -1858,8 +1920,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,

	/* The extra bit indicates that we support high capacity */
	err = mmc_send_op_cond(host, ocr | (1 << 30), &rocr);
	if (err)
	if (err) {
		pr_err("%s: %s: mmc_send_op_cond() fails %d\n",
				mmc_hostname(host), __func__, err);
		goto err;
	}

	/*
	 * For SPI, enable CRC as appropriate.
@@ -1874,12 +1939,17 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
	 * Fetch CID from card.
	 */
	err = mmc_send_cid(host, cid);
	if (err)
	if (err) {
		pr_err("%s: %s: mmc_send_cid() fails %d\n",
				mmc_hostname(host), __func__, err);
		goto err;
	}

	if (oldcard) {
		if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0) {
			err = -ENOENT;
			pr_err("%s: %s: CID memcmp failed %d\n",
					mmc_hostname(host), __func__, err);
			goto err;
		}

@@ -1891,6 +1961,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
		card = mmc_alloc_card(host, &mmc_type);
		if (IS_ERR(card)) {
			err = PTR_ERR(card);
			pr_err("%s: %s: no memory to allocate for card %d\n",
					mmc_hostname(host), __func__, err);
			goto err;
		}

@@ -1899,6 +1971,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
		card->rca = 1;
		memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
		host->card = card;
		card->reboot_notify.notifier_call = mmc_reboot_notify;
	}

	/*
@@ -1912,8 +1985,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
	 */
	if (!mmc_host_is_spi(host)) {
		err = mmc_set_relative_addr(card);
		if (err)
		if (err) {
			pr_err("%s: %s: mmc_set_relative_addr() fails %d\n",
					mmc_hostname(host), __func__, err);
			goto free_card;
		}

		mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
	}
@@ -1923,16 +1999,25 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
		 * Fetch CSD from card.
		 */
		err = mmc_send_csd(card, card->raw_csd);
		if (err)
		if (err) {
			pr_err("%s: %s: mmc_send_csd() fails %d\n",
					mmc_hostname(host), __func__, err);
			goto free_card;
		}

		err = mmc_decode_csd(card);
		if (err)
		if (err) {
			pr_err("%s: %s: mmc_decode_csd() fails %d\n",
					mmc_hostname(host), __func__, err);
			goto free_card;
		}
		err = mmc_decode_cid(card);
		if (err)
		if (err) {
			pr_err("%s: %s: mmc_decode_cid() fails %d\n",
					mmc_hostname(host), __func__, err);
			goto free_card;
		}
	}

	/*
	 * handling only for cards supporting DSR and hosts requesting
@@ -1946,15 +2031,21 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
	 */
	if (!mmc_host_is_spi(host)) {
		err = mmc_select_card(card);
		if (err)
		if (err) {
			pr_err("%s: %s: mmc_select_card() fails %d\n",
					mmc_hostname(host), __func__, err);
			goto free_card;
		}
	}

	if (!oldcard) {
		/* Read extended CSD. */
		err = mmc_read_ext_csd(card);
		if (err)
		if (err) {
			pr_err("%s: %s: mmc_read_ext_csd() fails %d\n",
					mmc_hostname(host), __func__, err);
			goto free_card;
		}

		/*
		 * If doing byte addressing, check if required to do sector
@@ -1975,8 +2066,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
				 EXT_CSD_ERASE_GROUP_DEF, 1,
				 card->ext_csd.generic_cmd6_time);

		if (err && err != -EBADMSG)
		if (err && err != -EBADMSG) {
			pr_err("%s: %s: mmc_switch() for ERASE_GRP_DEF fails %d\n",
					mmc_hostname(host), __func__, err);
			goto free_card;
		}

		if (err) {
			err = 0;
@@ -2006,9 +2100,14 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONFIG,
				 card->ext_csd.part_config,
				 card->ext_csd.part_time);
		if (err && err != -EBADMSG)
		if (err && err != -EBADMSG) {
			pr_err("%s: %s: mmc_switch() for PART_CONFIG fails %d\n",
				mmc_hostname(host), __func__, err);
			goto free_card;
		}
		card->part_curr = card->ext_csd.part_config &
					EXT_CSD_PART_CONFIG_ACC_MASK;
	}

	/*
	 * Enable power_off_notification byte in the ext_csd register
@@ -2018,8 +2117,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
				 EXT_CSD_POWER_OFF_NOTIFICATION,
				 EXT_CSD_POWER_ON,
				 card->ext_csd.generic_cmd6_time);
		if (err && err != -EBADMSG)
		if (err && err != -EBADMSG) {
			pr_err("%s: %s: mmc_switch() for POWER_ON PON fails %d\n",
					mmc_hostname(host), __func__, err);
			goto free_card;
		}

		/*
		 * The err can be -EBADMSG or 0,
@@ -2033,8 +2135,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
	 * Select timing interface
	 */
	err = mmc_select_timing(card);
	if (err)
	if (err) {
		pr_err("%s: %s: mmc_select_timing() fails %d\n",
				mmc_hostname(host), __func__, err);
		goto free_card;
	}

	if (mmc_card_hs200(card)) {
		err = mmc_hs200_tuning(card);
@@ -2054,15 +2159,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
		}
	}

	card->clk_scaling_lowest = host->f_min;
	if ((card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400) ||
			(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200))
		card->clk_scaling_highest = card->ext_csd.hs200_max_dtr;
	else if ((card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS) ||
			(card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52))
		card->clk_scaling_highest = card->ext_csd.hs_max_dtr;
	else
		card->clk_scaling_highest = card->csd.max_dtr;
	mmc_init_setup_scaling(card, host);

	/*
	 * Choose the power class with selected bus interface
@@ -2076,8 +2173,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
				EXT_CSD_HPI_MGMT, 1,
				card->ext_csd.generic_cmd6_time);
		if (err && err != -EBADMSG)
		if (err && err != -EBADMSG) {
			pr_err("%s: %s: mmc_switch() for HPI_MGMT fails %d\n",
					mmc_hostname(host), __func__, err);
			goto free_card;
		}
		if (err) {
			pr_warn("%s: Enabling HPI failed\n",
				mmc_hostname(card->host));
@@ -2092,13 +2192,17 @@ 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 (!mmc_card_broken_hpi(card) &&
	    card->ext_csd.cache_size > 0) {
	if (!mmc_card_broken_hpi(card) && card->ext_csd.cache_size > 0) {
		if (card->ext_csd.hpi_en &&
			(!(card->quirks & MMC_QUIRK_CACHE_DISABLE))) {
			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
					EXT_CSD_CACHE_CTRL, 1,
					card->ext_csd.generic_cmd6_time);
		if (err && err != -EBADMSG)
			if (err && err != -EBADMSG) {
				pr_err("%s: %s: fail on CACHE_CTRL ON %d\n",
					mmc_hostname(host), __func__, err);
				goto free_card;
			}

			/*
			 * Only if no error, cache is turned on successfully.
@@ -2111,6 +2215,24 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
			} else {
				card->ext_csd.cache_ctrl = 1;
			}
		} else {
			/*
			 * mmc standard doesn't say what is the card default
			 * value for EXT_CSD_CACHE_CTRL.
			 * Hence, cache may be enabled by default by
			 * card vendors.
			 * Thus, it is best to explicitly disable cache in case
			 * we want to avoid cache.
			 */
			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
					EXT_CSD_CACHE_CTRL, 0,
					card->ext_csd.generic_cmd6_time);
			if (err) {
				pr_err("%s: %s: fail on CACHE_CTRL OFF %d\n",
					mmc_hostname(host), __func__, err);
				goto free_card;
			}
		}
	}

	/*
@@ -2163,8 +2285,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
	return 0;

free_card:
	if (!oldcard)
	if (!oldcard) {
		host->card = NULL;
		mmc_remove_card(card);
	}
err:
	return err;
}
@@ -2279,6 +2403,7 @@ int mmc_send_pon(struct mmc_card *card)
static void mmc_remove(struct mmc_host *host)
{
	mmc_exit_clk_scaling(host);
	unregister_reboot_notifier(&host->card->reboot_notify);
	mmc_remove_card(host->card);
	mmc_claim_host(host);
	host->card = NULL;
@@ -2322,8 +2447,6 @@ static void mmc_detect(struct mmc_host *host)
static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
{
	int err = 0;
	unsigned int notify_type = is_suspend ? EXT_CSD_POWER_OFF_SHORT :
					EXT_CSD_POWER_OFF_LONG;

	err = mmc_suspend_clk_scaling(host);
	if (err) {
@@ -2354,10 +2477,7 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
	if (err)
		goto out;

	if (mmc_can_poweroff_notify(host->card) &&
		((host->caps2 & MMC_CAP2_FULL_PWR_CYCLE) || !is_suspend))
		err = mmc_poweroff_notify(host->card, notify_type);
	else if (mmc_can_sleep(host->card))
	if (mmc_can_sleep(host->card))
		err = mmc_sleep(host);
	else if (!mmc_host_is_spi(host))
		err = mmc_deselect_cards(host);
@@ -2380,6 +2500,7 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
static int mmc_suspend(struct mmc_host *host)
{
	int err;
	ktime_t start = ktime_get();

	err = _mmc_suspend(host, true);
	if (!err) {
@@ -2387,6 +2508,8 @@ static int mmc_suspend(struct mmc_host *host)
		pm_runtime_set_suspended(&host->card->dev);
	}

	trace_mmc_suspend(mmc_hostname(host), err,
			ktime_to_us(ktime_sub(ktime_get(), start)));
	return err;
}

@@ -2397,6 +2520,7 @@ static int mmc_suspend(struct mmc_host *host)
static int _mmc_resume(struct mmc_host *host)
{
	int err = 0;
	int retries = 3;

	mmc_claim_host(host);

@@ -2407,7 +2531,20 @@ static int _mmc_resume(struct mmc_host *host)

	mmc_log_string(host, "Enter\n");
	mmc_power_up(host, host->card->ocr);
	while (retries) {
		err = mmc_init_card(host, host->card->ocr, host->card);
		if (err) {
			pr_err("%s: MMC card re-init failed rc = %d (retries = %d)\n",
					mmc_hostname(host), err, retries);
			retries--;
			mmc_power_off(host);
			usleep_range(5000, 5500);
			mmc_power_up(host, host->card->ocr);
			mmc_select_voltage(host, host->card->ocr);
			continue;
		}
		break;
	}
	mmc_card_clr_suspended(host->card);

	mmc_log_string(host, "Exit err %d\n", err);
@@ -2482,11 +2619,14 @@ static int mmc_shutdown(struct mmc_host *host)
static int mmc_resume(struct mmc_host *host)
{
	int err = 0;
	ktime_t start = ktime_get();

	err = _mmc_resume(host);
	pm_runtime_set_active(&host->card->dev);
	pm_runtime_mark_last_busy(&host->card->dev);
	pm_runtime_enable(&host->card->dev);
	trace_mmc_resume(mmc_hostname(host), err,
			ktime_to_us(ktime_sub(ktime_get(), start)));

	mmc_log_string(host, "Done\n");

@@ -2516,6 +2656,7 @@ static int mmc_deferred_resume(struct mmc_host *host)
static int mmc_runtime_suspend(struct mmc_host *host)
{
	int err;
	ktime_t start = ktime_get();

	if (!(host->caps & MMC_CAP_AGGRESSIVE_PM))
		return 0;
@@ -2524,6 +2665,9 @@ static int mmc_runtime_suspend(struct mmc_host *host)
	if (err)
		pr_err("%s: error %d doing aggressive suspend\n",
			mmc_hostname(host), err);
	trace_mmc_runtime_suspend(mmc_hostname(host), err,
			ktime_to_us(ktime_sub(ktime_get(), start)));

	mmc_log_string(host, "done err %d\n", err);
	return err;
}
@@ -2534,11 +2678,15 @@ static int mmc_runtime_suspend(struct mmc_host *host)
static int mmc_runtime_resume(struct mmc_host *host)
{
	int err;
	ktime_t start = ktime_get();

	err = _mmc_resume(host);
	if (err && err != -ENOMEDIUM)
		pr_err("%s: error %d doing runtime resume\n",
			mmc_hostname(host), err);

	trace_mmc_runtime_resume(mmc_hostname(host), err,
			ktime_to_us(ktime_sub(ktime_get(), start)));
	mmc_log_string(host, "done err %d\n", err);
	return 0;
}
@@ -2662,6 +2810,8 @@ int mmc_attach_mmc(struct mmc_host *host)
		goto remove_card;
	}

	register_reboot_notifier(&host->card->reboot_notify);

	return 0;

remove_card:
+3 −2
Original line number Diff line number Diff line
@@ -802,7 +802,7 @@ static int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status)
	unsigned int opcode;
	int err;

	if (!card->ext_csd.hpi) {
	if (!card->ext_csd.hpi_en) {
		pr_warn("%s: Card didn't support HPI command\n",
			mmc_hostname(card->host));
		return -EINVAL;
@@ -1017,7 +1017,8 @@ int mmc_flush_cache(struct mmc_card *card)

	if (mmc_card_mmc(card) &&
			(card->ext_csd.cache_size > 0) &&
			(card->ext_csd.cache_ctrl & 1)) {
			(card->ext_csd.cache_ctrl & 1) &&
			(!(card->quirks & MMC_QUIRK_CACHE_DISABLE))) {
		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
				EXT_CSD_FLUSH_CACHE, 1, 0);
		if (err)
+8 −0
Original line number Diff line number Diff line
@@ -117,6 +117,10 @@ static const struct mmc_fixup mmc_blk_fixups[] = {
	MMC_FIXUP("SEM04G", 0x45, CID_OEMID_ANY, add_quirk_mmc,
		  MMC_QUIRK_INAND_DATA_TIMEOUT),

	/* Disable cache for specific cards */
	MMC_FIXUP("MMC16G", CID_MANFID_KINGSTON, CID_OEMID_ANY, add_quirk_mmc,
		  MMC_QUIRK_CACHE_DISABLE),

	END_FIXUP
};

@@ -134,6 +138,10 @@ static const struct mmc_fixup mmc_ext_csd_fixups[] = {
	MMC_FIXUP_EXT_CSD_REV(CID_NAME_ANY, CID_MANFID_NUMONYX,
			      0x014e, add_quirk, MMC_QUIRK_BROKEN_HPI, 6),

	/* avoid HPI for specific cards */
	MMC_FIXUP_EXT_CSD_REV("MMC16G", CID_MANFID_KINGSTON, CID_OEMID_ANY,
			add_quirk, MMC_QUIRK_BROKEN_HPI, MMC_V4_41),

	END_FIXUP
};