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

Unverified Commit 6ac29dad authored by derfelot's avatar derfelot
Browse files

mmc: Add mmc debug and Sony modifications

Taken from Sony 47.2.A.10.107 stock kernel
parent bb0ac6ee
Loading
Loading
Loading
Loading
+46 −3
Original line number Diff line number Diff line
@@ -17,6 +17,11 @@
 * Author:  Andrew Christian
 *          28 May 2002
 */
/*
 * NOTE: This file has been modified by Sony Mobile Communications Inc.
 * Modifications are Copyright (c) 2013 Sony Mobile Communications Inc,
 * and licensed under the license of the file.
 */
#include <linux/moduleparam.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -1537,12 +1542,19 @@ static int get_card_status(struct mmc_card *card, u32 *status, int retries)
	return err;
}

#define EXE_ERRORS \
	(R1_OUT_OF_RANGE |   /* Command argument out of range */ \
	 R1_ADDRESS_ERROR |   /* Misaligned address */ \
	 R1_WP_VIOLATION |    /* Tried to write to protected block */ \
	 R1_CARD_ECC_FAILED | /* ECC error */ \
	 R1_ERROR)            /* General/unknown error */

static int card_busy_detect(struct mmc_card *card, unsigned int timeout_ms,
		bool hw_busy_detect, struct request *req, int *gen_err)
{
	unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
	int err = 0;
	u32 status;
	u32 status, first_status = 0;

	do {
		err = get_card_status(card, &status, 5);
@@ -1552,6 +1564,9 @@ static int card_busy_detect(struct mmc_card *card, unsigned int timeout_ms,
			return err;
		}

		if (!first_status)
			first_status = status;

		if (status & R1_ERROR) {
			pr_err("%s: %s: error sending status cmd, status %#x\n",
				req->rq_disk->disk_name, __func__, status);
@@ -1582,6 +1597,14 @@ static int card_busy_detect(struct mmc_card *card, unsigned int timeout_ms,
	} while (!(status & R1_READY_FOR_DATA) ||
		 (R1_CURRENT_STATE(status) == R1_STATE_PRG));

	/* Check for errors during cmd execution. In this case
	 * the execution was terminated. */
	if (first_status & EXE_ERRORS) {
		pr_err("%s: error during r/w command, err status %#x, status %#x\n",
		       req->rq_disk->disk_name, first_status, status);
		return MMC_BLK_ABORT;
	}

	return err;
}

@@ -2264,12 +2287,25 @@ static int mmc_blk_err_check(struct mmc_card *card,
		return MMC_BLK_ABORT;
	}

	/* Check execution mode errors. If stop cmd was sent, these
	 * errors would be reported in response to it. In this case
	 * the execution is retried using single-block read. */
	if (brq->stop.resp[0] & EXE_ERRORS) {
		pr_err("%s: error during r/w command, stop response %#x\n",
		       req->rq_disk->disk_name, brq->stop.resp[0]);
		return MMC_BLK_RETRY_SINGLE;
	}

	/*
	 * Everything else is either success, or a data error of some
	 * kind.  If it was a write, we may have transitioned to
	 * program mode, which we have to wait for it to complete.
	 * If pre defined block count (CMD23) was used, no stop
	 * cmd was sent and we need to read status to check
	 * for errors during cmd execution.
	 */
	if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) {
	if (!mmc_host_is_spi(card->host) &&
	    (rq_data_dir(req) != READ || brq->sbc.opcode == MMC_SET_BLOCK_COUNT)) {
		int err;

		/* Check stop command response */
@@ -3849,6 +3885,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
				break;
			goto cmd_abort;
		}
		case MMC_BLK_RETRY_SINGLE:
		case MMC_BLK_ECC_ERR:
			if (brq->data.blocks > 1) {
				/* Redo read one sector at a time */
@@ -4735,7 +4772,13 @@ static int mmc_blk_probe(struct mmc_card *card)
	}

	pm_runtime_use_autosuspend(&card->dev);

	if (mmc_card_sd(card))
		pm_runtime_set_autosuspend_delay(&card->dev,
			MMC_SDCARD_AUTOSUSPEND_DELAY_MS);
	else
		pm_runtime_set_autosuspend_delay(&card->dev, MMC_AUTOSUSPEND_DELAY_MS);

	pm_runtime_use_autosuspend(&card->dev);

	/*
+16 −0
Original line number Diff line number Diff line
@@ -37,3 +37,19 @@ config MMC_CLKGATE
	  support handling this in order for it to be of any use.

	  If unsure, say N.

config MMC_CMD_DEBUG
	bool "Debug feature to get mmc command issued"
	default n
	help
	  This is a debug feature to get the mmc command issued
	  in order to debug certain issues from the logs.

config MMC_CMD_QUEUE_SIZE
	int "mmc command queue size"
	depends on MMC_CMD_DEBUG
	default 256
	help
	  Select the size of the circular queue to store the MMC command
	  issued.
+34 −1
Original line number Diff line number Diff line
@@ -10,6 +10,11 @@
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */
/*
 * NOTE: This file has been modified by Sony Mobile Communications Inc.
 * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc,
 * and licensed under the license of the file.
 */
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
@@ -1106,6 +1111,24 @@ static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
	if (mmc_card_removed(host->card))
		return -ENOMEDIUM;

#ifdef CONFIG_MMC_CMD_DEBUG
	if (host->card) {
		struct mmc_cmdq *cq = NULL;
		cq = &host->card->cmd_stats.cmdq[host->card->
						cmd_stats.next_idx];
		cq->opcode = mrq->cmd->opcode;
		cq->arg = mrq->cmd->arg;
		cq->flags = mrq->cmd->flags;
		cq->timestamp = sched_clock();
		host->card->cmd_stats.next_idx++;

		if (host->card->cmd_stats.next_idx == CMD_QUEUE_SIZE) {
			host->card->cmd_stats.next_idx = 0;
			host->card->cmd_stats.wrapped = 1;
		}
	}
#endif

	if (mrq->sbc) {
		pr_debug("<%s: starting CMD%u arg %08x flags %08x>\n",
			 mmc_hostname(host), mrq->sbc->opcode,
@@ -3073,7 +3096,10 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr)

	host->card_clock_off = false;
	/* Wait for at least 1 ms according to spec */
	if (host->caps & MMC_CAP_NONREMOVABLE)
		mmc_delay(1);
	else
		mmc_delay(40);

	/*
	 * Failure to switch is indicated by the card holding
@@ -4184,6 +4210,8 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
		return 0;
	if (!mmc_attach_sd(host))
		return 0;
	else
		mmc_gpio_tray_close_set_uim2(host, 1);
	if (!mmc_attach_mmc(host))
		return 0;

@@ -4384,6 +4412,8 @@ void mmc_stop_host(struct mmc_host *host)
	cancel_delayed_work_sync(&host->detect);
	mmc_flush_scheduled_work();

	mmc_gpio_set_uim2_en(host, 0);

	/* clear pm flags now and let card drivers set them as needed */
	host->pm_flags = 0;

@@ -4549,6 +4579,9 @@ int mmc_pm_notify(struct notifier_block *notify_block,
		host->rescan_disable = 1;
		spin_unlock_irqrestore(&host->lock, flags);
		cancel_delayed_work_sync(&host->detect);
#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
		mmc_cd_prepare_suspend(host);
#endif

		if (!host->bus_ops)
			break;
+55 −1
Original line number Diff line number Diff line
@@ -7,6 +7,11 @@
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */
/*
 * NOTE: This file has been modified by Sony Mobile Communications Inc.
 * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc,
 * and licensed under the license of the file.
 */
#include <linux/moduleparam.h>
#include <linux/export.h>
#include <linux/debugfs.h>
@@ -866,6 +871,50 @@ static const struct file_operations mmc_dbg_bkops_stats_fops = {
	.write		= mmc_bkops_stats_write,
};

#ifdef CONFIG_MMC_CMD_DEBUG
static int mmc_cmd_stats_show(struct seq_file *s, void *data)
{
	int i;
	struct mmc_card *card = s->private;
	unsigned long long t;
	unsigned long rem_nsec;

	if (card->cmd_stats.wrapped) {
		for (i = card->cmd_stats.next_idx; i < CMD_QUEUE_SIZE; i++) {
			t = card->cmd_stats.cmdq[i].timestamp;
			rem_nsec = do_div(t, 1000000000);
			seq_printf(s, "[%5llu.%06lu] CMD%u arg %08x flags %08x\n",
				t, (rem_nsec/1000),
				card->cmd_stats.cmdq[i].opcode,
				card->cmd_stats.cmdq[i].arg,
				card->cmd_stats.cmdq[i].flags);
		}
	}

	for (i = 0; i < card->cmd_stats.next_idx; i++) {
		t = card->cmd_stats.cmdq[i].timestamp;
		rem_nsec = do_div(t, 1000000000);
		seq_printf(s, "[%5llu.%06lu] CMD%u arg %08x flags %08x\n",
			t, (rem_nsec/1000),
			card->cmd_stats.cmdq[i].opcode,
			card->cmd_stats.cmdq[i].arg,
			card->cmd_stats.cmdq[i].flags);
	}

	return 0;
}

static int mmc_cmd_stats_open(struct inode *inode, struct file *filp)
{
	return single_open(filp, mmc_cmd_stats_show, inode->i_private);
}

static const struct file_operations mmc_dbg_card_rq_cmdq_fops = {
	.open		= mmc_cmd_stats_open,
	.read		= seq_read,
};
#endif

void mmc_add_card_debugfs(struct mmc_card *card)
{
	struct mmc_host	*host = card->host;
@@ -892,7 +941,12 @@ void mmc_add_card_debugfs(struct mmc_card *card)
		if (!debugfs_create_file("status", S_IRUSR, root, card,
					&mmc_dbg_card_status_fops))
			goto err;

#ifdef CONFIG_MMC_CMD_DEBUG
	if (mmc_card_mmc(card) || mmc_card_sd(card))
		if (!debugfs_create_file("mmc_cmd_stats", S_IRUSR, root,
				card, &mmc_dbg_card_rq_cmdq_fops))
			goto err;
#endif
	if (mmc_card_mmc(card))
		if (!debugfs_create_file("ext_csd", S_IRUSR, root, card,
					&mmc_dbg_ext_csd_fops))
+6 −1
Original line number Diff line number Diff line
@@ -9,6 +9,11 @@
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */
/*
 * NOTE: This file has been modified by Sony Mobile Communications Inc.
 * Modifications are Copyright (c) 2016 Sony Mobile Communications Inc,
 * and licensed under the license of the file.
 */

#include <linux/err.h>
#include <linux/sizes.h>
@@ -322,7 +327,7 @@ static int mmc_read_switch(struct mmc_card *card)
	 * The argument does not matter, as the support bits do not
	 * change with the arguments.
	 */
	err = mmc_sd_switch(card, 0, 0, 0, status);
	err = mmc_sd_switch(card, 0, 0, 1, status);
	if (err) {
		/*
		 * If the host or the card can't do the switch,
Loading