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

Commit fc1fa1b7 authored by Kishon Vijay Abraham I's avatar Kishon Vijay Abraham I Committed by Ulf Hansson
Browse files

mmc: sdhci: Program a relatively accurate SW timeout value



sdhci has a 10 second timeout to catch devices that stop responding.
In the case of quirk SDHCI_QUIRK2_DISABLE_HW_TIMEOUT, instead of
programming 10 second arbitrary value, calculate the total time it would
take for the entire transfer to happen and program the timeout value
accordingly.

Signed-off-by: default avatarKishon Vijay Abraham I <kishon@ti.com>
Signed-off-by: default avatarAdrian Hunter <adrian.hunter@intel.com>
Signed-off-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
parent 0bb28d73
Loading
Loading
Loading
Loading
+45 −7
Original line number Original line Diff line number Diff line
@@ -738,6 +738,39 @@ static unsigned int sdhci_target_timeout(struct sdhci_host *host,
	return target_timeout;
	return target_timeout;
}
}


static void sdhci_calc_sw_timeout(struct sdhci_host *host,
				  struct mmc_command *cmd)
{
	struct mmc_data *data = cmd->data;
	struct mmc_host *mmc = host->mmc;
	struct mmc_ios *ios = &mmc->ios;
	unsigned char bus_width = 1 << ios->bus_width;
	unsigned int blksz;
	unsigned int freq;
	u64 target_timeout;
	u64 transfer_time;

	target_timeout = sdhci_target_timeout(host, cmd, data);
	target_timeout *= NSEC_PER_USEC;

	if (data) {
		blksz = data->blksz;
		freq = host->mmc->actual_clock ? : host->clock;
		transfer_time = (u64)blksz * NSEC_PER_SEC * (8 / bus_width);
		do_div(transfer_time, freq);
		/* multiply by '2' to account for any unknowns */
		transfer_time = transfer_time * 2;
		/* calculate timeout for the entire data */
		host->data_timeout = data->blocks * target_timeout +
				     transfer_time;
	} else {
		host->data_timeout = target_timeout;
	}

	if (host->data_timeout)
		host->data_timeout += MMC_CMD_TRANSFER_TIME;
}

static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd,
static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd,
			     bool *too_big)
			     bool *too_big)
{
{
@@ -831,6 +864,7 @@ static void sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)


		if (too_big &&
		if (too_big &&
		    host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT) {
		    host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT) {
			sdhci_calc_sw_timeout(host, cmd);
			sdhci_set_data_timeout_irq(host, false);
			sdhci_set_data_timeout_irq(host, false);
		} else if (!(host->ier & SDHCI_INT_DATA_TIMEOUT)) {
		} else if (!(host->ier & SDHCI_INT_DATA_TIMEOUT)) {
			sdhci_set_data_timeout_irq(host, true);
			sdhci_set_data_timeout_irq(host, true);
@@ -845,6 +879,8 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
	u8 ctrl;
	u8 ctrl;
	struct mmc_data *data = cmd->data;
	struct mmc_data *data = cmd->data;


	host->data_timeout = 0;

	if (sdhci_data_line_cmd(cmd))
	if (sdhci_data_line_cmd(cmd))
		sdhci_set_timeout(host, cmd);
		sdhci_set_timeout(host, cmd);


@@ -1198,13 +1234,6 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
		mdelay(1);
		mdelay(1);
	}
	}


	timeout = jiffies;
	if (!cmd->data && cmd->busy_timeout > 9000)
		timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
	else
		timeout += 10 * HZ;
	sdhci_mod_timer(host, cmd->mrq, timeout);

	host->cmd = cmd;
	host->cmd = cmd;
	if (sdhci_data_line_cmd(cmd)) {
	if (sdhci_data_line_cmd(cmd)) {
		WARN_ON(host->data_cmd);
		WARN_ON(host->data_cmd);
@@ -1244,6 +1273,15 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
	    cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200)
	    cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200)
		flags |= SDHCI_CMD_DATA;
		flags |= SDHCI_CMD_DATA;


	timeout = jiffies;
	if (host->data_timeout)
		timeout += nsecs_to_jiffies(host->data_timeout);
	else if (!cmd->data && cmd->busy_timeout > 9000)
		timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
	else
		timeout += 10 * HZ;
	sdhci_mod_timer(host, cmd->mrq, timeout);

	sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);
	sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);
}
}
EXPORT_SYMBOL_GPL(sdhci_send_command);
EXPORT_SYMBOL_GPL(sdhci_send_command);
+10 −0
Original line number Original line Diff line number Diff line
@@ -332,6 +332,14 @@ struct sdhci_adma2_64_desc {
/* Allow for a a command request and a data request at the same time */
/* Allow for a a command request and a data request at the same time */
#define SDHCI_MAX_MRQS		2
#define SDHCI_MAX_MRQS		2


/*
 * 48bit command and 136 bit response in 100KHz clock could take upto 2.48ms.
 * However since the start time of the command, the time between
 * command and response, and the time between response and start of data is
 * not known, set the command transfer time to 10ms.
 */
#define MMC_CMD_TRANSFER_TIME	(10 * NSEC_PER_MSEC) /* max 10 ms */

enum sdhci_cookie {
enum sdhci_cookie {
	COOKIE_UNMAPPED,
	COOKIE_UNMAPPED,
	COOKIE_PRE_MAPPED,	/* mapped by sdhci_pre_req() */
	COOKIE_PRE_MAPPED,	/* mapped by sdhci_pre_req() */
@@ -555,6 +563,8 @@ struct sdhci_host {
	/* Host SDMA buffer boundary. */
	/* Host SDMA buffer boundary. */
	u32			sdma_boundary;
	u32			sdma_boundary;


	u64			data_timeout;

	unsigned long private[0] ____cacheline_aligned;
	unsigned long private[0] ____cacheline_aligned;
};
};