コード例 #1
0
ファイル: mmc_ops.c プロジェクト: a2hojsjsjs/linux
/**
 *	__mmc_switch - modify EXT_CSD register
 *	@card: the MMC card associated with the data transfer
 *	@set: cmd set values
 *	@index: EXT_CSD register index
 *	@value: value to program into EXT_CSD register
 *	@timeout_ms: timeout (ms) for operation performed by register write,
 *                   timeout of zero implies maximum possible timeout
 *	@use_busy_signal: use the busy signal as response type
 *	@send_status: send status cmd to poll for busy
 *	@ignore_crc: ignore CRC errors when sending status cmd to poll for busy
 *
 *	Modifies the EXT_CSD register for selected card.
 */
int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
		unsigned int timeout_ms, bool use_busy_signal, bool send_status,
		bool ignore_crc)
{
	struct mmc_host *host = card->host;
	int err;
	struct mmc_command cmd = {0};
	unsigned long timeout;
	u32 status = 0;
	bool use_r1b_resp = use_busy_signal;
	bool expired = false;

	mmc_retune_hold(host);

	/*
	 * If the cmd timeout and the max_busy_timeout of the host are both
	 * specified, let's validate them. A failure means we need to prevent
	 * the host from doing hw busy detection, which is done by converting
	 * to a R1 response instead of a R1B.
	 */
	if (timeout_ms && host->max_busy_timeout &&
		(timeout_ms > host->max_busy_timeout))
		use_r1b_resp = false;

	cmd.opcode = MMC_SWITCH;
	cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
		  (index << 16) |
		  (value << 8) |
		  set;
	cmd.flags = MMC_CMD_AC;
	if (use_r1b_resp) {
		cmd.flags |= MMC_RSP_SPI_R1B | MMC_RSP_R1B;
		/*
		 * A busy_timeout of zero means the host can decide to use
		 * whatever value it finds suitable.
		 */
		cmd.busy_timeout = timeout_ms;
	} else {
		cmd.flags |= MMC_RSP_SPI_R1 | MMC_RSP_R1;
	}

	if (index == EXT_CSD_SANITIZE_START)
		cmd.sanitize_busy = true;

	err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
	if (err)
		goto out;

	/* No need to check card status in case of unblocking command */
	if (!use_busy_signal)
		goto out;

	/*
	 * CRC errors shall only be ignored in cases were CMD13 is used to poll
	 * to detect busy completion.
	 */
	if ((host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp)
		ignore_crc = false;

	/* We have an unspecified cmd timeout, use the fallback value. */
	if (!timeout_ms)
		timeout_ms = MMC_OPS_TIMEOUT_MS;

	/* Must check status to be sure of no errors. */
	timeout = jiffies + msecs_to_jiffies(timeout_ms);
	do {
		if (send_status) {
			/*
			 * Due to the possibility of being preempted after
			 * sending the status command, check the expiration
			 * time first.
			 */
			expired = time_after(jiffies, timeout);
			err = __mmc_send_status(card, &status, ignore_crc);
			if (err)
				goto out;
		}
		if ((host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp)
			break;
		if (mmc_host_is_spi(host))
			break;

		/*
		 * We are not allowed to issue a status command and the host
		 * does'nt support MMC_CAP_WAIT_WHILE_BUSY, then we can only
		 * rely on waiting for the stated timeout to be sufficient.
		 */
		if (!send_status) {
			mmc_delay(timeout_ms);
			goto out;
		}

		/* Timeout if the device never leaves the program state. */
		if (expired && R1_CURRENT_STATE(status) == R1_STATE_PRG) {
			pr_err("%s: Card stuck in programming state! %s\n",
				mmc_hostname(host), __func__);
			err = -ETIMEDOUT;
			goto out;
		}
	} while (R1_CURRENT_STATE(status) == R1_STATE_PRG);

	err = mmc_switch_status_error(host, status);
out:
	mmc_retune_release(host);

	return err;
}
コード例 #2
0
ファイル: mmc_ops.c プロジェクト: asmalldev/linux
/**
 *	__mmc_switch - modify EXT_CSD register
 *	@card: the MMC card associated with the data transfer
 *	@set: cmd set values
 *	@index: EXT_CSD register index
 *	@value: value to program into EXT_CSD register
 *	@timeout_ms: timeout (ms) for operation performed by register write,
 *                   timeout of zero implies maximum possible timeout
 *	@timing: new timing to change to
 *	@use_busy_signal: use the busy signal as response type
 *	@send_status: send status cmd to poll for busy
 *	@retry_crc_err: retry when CRC errors when polling with CMD13 for busy
 *
 *	Modifies the EXT_CSD register for selected card.
 */
int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
		unsigned int timeout_ms, unsigned char timing,
		bool use_busy_signal, bool send_status,	bool retry_crc_err)
{
	struct mmc_host *host = card->host;
	int err;
	struct mmc_command cmd = {};
	bool use_r1b_resp = use_busy_signal;
	unsigned char old_timing = host->ios.timing;

	mmc_retune_hold(host);

	/*
	 * If the cmd timeout and the max_busy_timeout of the host are both
	 * specified, let's validate them. A failure means we need to prevent
	 * the host from doing hw busy detection, which is done by converting
	 * to a R1 response instead of a R1B.
	 */
	if (timeout_ms && host->max_busy_timeout &&
		(timeout_ms > host->max_busy_timeout))
		use_r1b_resp = false;

	cmd.opcode = MMC_SWITCH;
	cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
		  (index << 16) |
		  (value << 8) |
		  set;
	cmd.flags = MMC_CMD_AC;
	if (use_r1b_resp) {
		cmd.flags |= MMC_RSP_SPI_R1B | MMC_RSP_R1B;
		/*
		 * A busy_timeout of zero means the host can decide to use
		 * whatever value it finds suitable.
		 */
		cmd.busy_timeout = timeout_ms;
	} else {
		cmd.flags |= MMC_RSP_SPI_R1 | MMC_RSP_R1;
	}

	if (index == EXT_CSD_SANITIZE_START)
		cmd.sanitize_busy = true;

	err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
	if (err)
		goto out;

	/* No need to check card status in case of unblocking command */
	if (!use_busy_signal)
		goto out;

	/*If SPI or used HW busy detection above, then we don't need to poll. */
	if (((host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp) ||
		mmc_host_is_spi(host))
		goto out_tim;

	/* Let's try to poll to find out when the command is completed. */
	err = mmc_poll_for_busy(card, timeout_ms, send_status, retry_crc_err);
	if (err)
		goto out;

out_tim:
	/* Switch to new timing before check switch status. */
	if (timing)
		mmc_set_timing(host, timing);

	if (send_status) {
		err = mmc_switch_status(card);
		if (err && timing)
			mmc_set_timing(host, old_timing);
	}
out:
	mmc_retune_release(host);

	return err;
}