コード例 #1
0
static void sh_mmcif_stop_cmd(struct sh_mmcif_host *host,
		struct mmc_request *mrq, struct mmc_command *cmd)
{
	long time;

	if (mrq->cmd->opcode == MMC_READ_MULTIPLE_BLOCK)
		sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MCMD12DRE);
	else if (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK)
		sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MCMD12RBE);
	else {
		pr_err(DRIVER_NAME": not support stop cmd\n");
		cmd->error = sh_mmcif_error_manage(host);
		return;
	}

	time = wait_event_interruptible_timeout(host->intr_wait,
			host->wait_int == 1 ||
			host->sd_error == 1, host->timeout);
	if (host->wait_int != 1 && (time == 0 || host->sd_error != 0)) {
		cmd->error = sh_mmcif_error_manage(host);
		return;
	}
	sh_mmcif_get_cmd12response(host, cmd);
	host->wait_int = 0;
	cmd->error = 0;
}
コード例 #2
0
static irqreturn_t sh_mmcif_irqt(int irq, void *dev_id)
{
	struct sh_mmcif_host *host = dev_id;
	struct mmc_request *mrq;
	bool wait = false;

	cancel_delayed_work_sync(&host->timeout_work);

	mutex_lock(&host->thread_lock);

	mrq = host->mrq;
	if (!mrq) {
		dev_dbg(&host->pd->dev, "IRQ thread state %u, wait %u: NULL mrq!\n",
			host->state, host->wait_for);
		mutex_unlock(&host->thread_lock);
		return IRQ_HANDLED;
	}

	/*
	 * All handlers return true, if processing continues, and false, if the
	 * request has to be completed - successfully or not
	 */
	switch (host->wait_for) {
	case MMCIF_WAIT_FOR_REQUEST:
		/* We're too late, the timeout has already kicked in */
		mutex_unlock(&host->thread_lock);
		return IRQ_HANDLED;
	case MMCIF_WAIT_FOR_CMD:
		/* Wait for data? */
		wait = sh_mmcif_end_cmd(host);
		break;
	case MMCIF_WAIT_FOR_MREAD:
		/* Wait for more data? */
		wait = sh_mmcif_mread_block(host);
		break;
	case MMCIF_WAIT_FOR_READ:
		/* Wait for data end? */
		wait = sh_mmcif_read_block(host);
		break;
	case MMCIF_WAIT_FOR_MWRITE:
		/* Wait data to write? */
		wait = sh_mmcif_mwrite_block(host);
		break;
	case MMCIF_WAIT_FOR_WRITE:
		/* Wait for data end? */
		wait = sh_mmcif_write_block(host);
		break;
	case MMCIF_WAIT_FOR_STOP:
		if (host->sd_error) {
			mrq->stop->error = sh_mmcif_error_manage(host);
			dev_dbg(&host->pd->dev, "%s(): %d\n", __func__, mrq->stop->error);
			break;
		}
		sh_mmcif_get_cmd12response(host, mrq->stop);
		mrq->stop->error = 0;
		break;
	case MMCIF_WAIT_FOR_READ_END:
	case MMCIF_WAIT_FOR_WRITE_END:
		if (host->sd_error) {
			mrq->data->error = sh_mmcif_error_manage(host);
			dev_dbg(&host->pd->dev, "%s(): %d\n", __func__, mrq->data->error);
		}
		break;
	default:
		BUG();
	}

	if (wait) {
		schedule_delayed_work(&host->timeout_work, host->timeout);
		/* Wait for more data */
		mutex_unlock(&host->thread_lock);
		return IRQ_HANDLED;
	}

	if (host->wait_for != MMCIF_WAIT_FOR_STOP) {
		struct mmc_data *data = mrq->data;
		if (!mrq->cmd->error && data && !data->error)
			data->bytes_xfered =
				data->blocks * data->blksz;

		if (mrq->stop && !mrq->cmd->error && (!data || !data->error)) {
			sh_mmcif_stop_cmd(host, mrq);
			if (!mrq->stop->error) {
				schedule_delayed_work(&host->timeout_work, host->timeout);
				mutex_unlock(&host->thread_lock);
				return IRQ_HANDLED;
			}
		}
	}

	host->wait_for = MMCIF_WAIT_FOR_REQUEST;
	host->state = STATE_IDLE;
	host->mrq = NULL;
	mmc_request_done(host->mmc, mrq);

	mutex_unlock(&host->thread_lock);

	return IRQ_HANDLED;
}
コード例 #3
0
ファイル: sh_mmcif.c プロジェクト: Apaisal/u-boot
static int sh_mmcif_start_cmd(struct sh_mmcif_host *host,
				struct mmc_data *data, struct mmc_cmd *cmd)
{
	long time;
	int ret = 0, mask = 0;
	u32 opc = cmd->cmdidx;

	if (opc == MMC_CMD_STOP_TRANSMISSION) {
		/* MMCIF sends the STOP command automatically */
		if (host->last_cmd == MMC_CMD_READ_MULTIPLE_BLOCK)
			sh_mmcif_bitset(MASK_MCMD12DRE,
					&host->regs->ce_int_mask);
		else
			sh_mmcif_bitset(MASK_MCMD12RBE,
					&host->regs->ce_int_mask);

		time = mmcif_wait_interrupt_flag(host);
		if (time == 0 || host->sd_error != 0)
			return sh_mmcif_error_manage(host);

		sh_mmcif_get_cmd12response(host, cmd);
		return 0;
	}
	if (opc == MMC_CMD_SWITCH)
		mask = MASK_MRBSYE;
	else
		mask = MASK_MCRSPE;

	mask |=	MASK_MCMDVIO | MASK_MBUFVIO | MASK_MWDATERR |
		MASK_MRDATERR | MASK_MRIDXERR | MASK_MRSPERR |
		MASK_MCCSTO | MASK_MCRCSTO | MASK_MWDATTO |
		MASK_MRDATTO | MASK_MRBSYTO | MASK_MRSPTO;

	if (host->data) {
		sh_mmcif_write(0, &host->regs->ce_block_set);
		sh_mmcif_write(data->blocksize, &host->regs->ce_block_set);
	}
	opc = sh_mmcif_set_cmd(host, data, cmd);

	sh_mmcif_write(INT_START_MAGIC, &host->regs->ce_int);
	sh_mmcif_write(mask, &host->regs->ce_int_mask);

	debug("CMD%d ARG:%08x\n", cmd->cmdidx, cmd->cmdarg);
	/* set arg */
	sh_mmcif_write(cmd->cmdarg, &host->regs->ce_arg);
	host->wait_int = 0;
	/* set cmd */
	sh_mmcif_write(opc, &host->regs->ce_cmd_set);

	time = mmcif_wait_interrupt_flag(host);
	if (time == 0)
		return sh_mmcif_error_manage(host);

	if (host->sd_error) {
		switch (cmd->cmdidx) {
		case MMC_CMD_ALL_SEND_CID:
		case MMC_CMD_SELECT_CARD:
		case MMC_CMD_APP_CMD:
			ret = TIMEOUT;
			break;
		default:
			printf(DRIVER_NAME": Cmd(d'%d) err\n", cmd->cmdidx);
			ret = sh_mmcif_error_manage(host);
			break;
		}
		host->sd_error = 0;
		host->wait_int = 0;
		return ret;
	}

	/* if no response */
	if (!(opc & 0x00C00000))
		return 0;

	if (host->wait_int == 1) {
		sh_mmcif_get_response(host, cmd);
		host->wait_int = 0;
	}
	if (host->data)
		ret = sh_mmcif_data_trans(host, data, cmd->cmdidx);
	host->last_cmd = cmd->cmdidx;

	return ret;
}