aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/core/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/core/core.c')
-rw-r--r--drivers/mmc/core/core.c111
1 files changed, 58 insertions, 53 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index f26a5f1d926d..9584bffa8b22 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -149,6 +149,14 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
led_trigger_event(host->led, LED_OFF);
+ if (mrq->sbc) {
+ pr_debug("%s: req done <CMD%u>: %d: %08x %08x %08x %08x\n",
+ mmc_hostname(host), mrq->sbc->opcode,
+ mrq->sbc->error,
+ mrq->sbc->resp[0], mrq->sbc->resp[1],
+ mrq->sbc->resp[2], mrq->sbc->resp[3]);
+ }
+
pr_debug("%s: req done (CMD%u): %d: %08x %08x %08x %08x\n",
mmc_hostname(host), cmd->opcode, err,
cmd->resp[0], cmd->resp[1],
@@ -214,6 +222,10 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
mrq->cmd->error = 0;
mrq->cmd->mrq = mrq;
+ if (mrq->sbc) {
+ mrq->sbc->error = 0;
+ mrq->sbc->mrq = mrq;
+ }
if (mrq->data) {
BUG_ON(mrq->data->blksz > host->max_blk_size);
BUG_ON(mrq->data->blocks > host->max_blk_count);
@@ -538,8 +550,18 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host,
if (host->card && mmc_card_mmc(host->card) &&
((mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1) ||
(mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1B)) &&
- (host->areq->mrq->cmd->resp[0] & R1_EXCEPTION_EVENT))
+ (host->areq->mrq->cmd->resp[0] & R1_EXCEPTION_EVENT)) {
+
+ /* Cancel the prepared request */
+ if (areq)
+ mmc_post_req(host, areq->mrq, -EINVAL);
+
mmc_start_bkops(host->card, true);
+
+ /* prepare the request again */
+ if (areq)
+ mmc_pre_req(host, areq->mrq, !host->areq);
+ }
}
if (!err && areq)
@@ -709,27 +731,16 @@ int mmc_read_bkops_status(struct mmc_card *card)
int err;
u8 *ext_csd;
- /*
- * In future work, we should consider storing the entire ext_csd.
- */
- ext_csd = kmalloc(512, GFP_KERNEL);
- if (!ext_csd) {
- pr_err("%s: could not allocate buffer to receive the ext_csd.\n",
- mmc_hostname(card->host));
- return -ENOMEM;
- }
-
mmc_claim_host(card->host);
- err = mmc_send_ext_csd(card, ext_csd);
+ err = mmc_get_ext_csd(card, &ext_csd);
mmc_release_host(card->host);
if (err)
- goto out;
+ return err;
card->ext_csd.raw_bkops_status = ext_csd[EXT_CSD_BKOPS_STATUS];
card->ext_csd.raw_exception_status = ext_csd[EXT_CSD_EXP_EVENTS_STATUS];
-out:
kfree(ext_csd);
- return err;
+ return 0;
}
EXPORT_SYMBOL(mmc_read_bkops_status);
@@ -1088,6 +1099,22 @@ void mmc_set_bus_width(struct mmc_host *host, unsigned int width)
mmc_host_clk_release(host);
}
+/*
+ * Set initial state after a power cycle or a hw_reset.
+ */
+void mmc_set_initial_state(struct mmc_host *host)
+{
+ if (mmc_host_is_spi(host))
+ host->ios.chip_select = MMC_CS_HIGH;
+ else
+ host->ios.chip_select = MMC_CS_DONTCARE;
+ host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
+ host->ios.bus_width = MMC_BUS_WIDTH_1;
+ host->ios.timing = MMC_TIMING_LEGACY;
+
+ mmc_set_ios(host);
+}
+
/**
* mmc_vdd_to_ocrbitnum - Convert a voltage to the OCR bit number
* @vdd: voltage (mV)
@@ -1420,18 +1447,20 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr)
pr_warn("%s: cannot verify signal voltage switch\n",
mmc_hostname(host));
+ mmc_host_clk_hold(host);
+
cmd.opcode = SD_SWITCH_VOLTAGE;
cmd.arg = 0;
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(host, &cmd, 0);
if (err)
- return err;
+ goto err_command;
- if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR))
- return -EIO;
-
- mmc_host_clk_hold(host);
+ if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR)) {
+ err = -EIO;
+ goto err_command;
+ }
/*
* The card should drive cmd and dat[0:3] low immediately
* after the response of cmd11, but wait 1 ms to be sure
@@ -1480,6 +1509,7 @@ power_cycle:
mmc_power_cycle(host, ocr);
}
+err_command:
mmc_host_clk_release(host);
return err;
@@ -1526,15 +1556,9 @@ void mmc_power_up(struct mmc_host *host, u32 ocr)
mmc_host_clk_hold(host);
host->ios.vdd = fls(ocr) - 1;
- if (mmc_host_is_spi(host))
- host->ios.chip_select = MMC_CS_HIGH;
- else
- host->ios.chip_select = MMC_CS_DONTCARE;
- host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
host->ios.power_mode = MMC_POWER_UP;
- host->ios.bus_width = MMC_BUS_WIDTH_1;
- host->ios.timing = MMC_TIMING_LEGACY;
- mmc_set_ios(host);
+ /* Set initial state and call mmc_set_ios */
+ mmc_set_initial_state(host);
/* Try to set signal voltage to 3.3V but fall back to 1.8v or 1.2v */
if (__mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330) == 0)
@@ -1574,14 +1598,9 @@ void mmc_power_off(struct mmc_host *host)
host->ios.clock = 0;
host->ios.vdd = 0;
- if (!mmc_host_is_spi(host)) {
- host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
- host->ios.chip_select = MMC_CS_DONTCARE;
- }
host->ios.power_mode = MMC_POWER_OFF;
- host->ios.bus_width = MMC_BUS_WIDTH_1;
- host->ios.timing = MMC_TIMING_LEGACY;
- mmc_set_ios(host);
+ /* Set initial state and call mmc_set_ios */
+ mmc_set_initial_state(host);
/*
* Some configurations, such as the 802.11 SDIO card in the OLPC
@@ -2259,30 +2278,16 @@ static int mmc_do_hw_reset(struct mmc_host *host, int check)
/* If the reset has happened, then a status command will fail */
if (check) {
- struct mmc_command cmd = {0};
- int err;
+ u32 status;
- cmd.opcode = MMC_SEND_STATUS;
- if (!mmc_host_is_spi(card->host))
- cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
- err = mmc_wait_for_cmd(card->host, &cmd, 0);
- if (!err) {
+ if (!mmc_send_status(card, &status)) {
mmc_host_clk_release(host);
return -ENOSYS;
}
}
- if (mmc_host_is_spi(host)) {
- host->ios.chip_select = MMC_CS_HIGH;
- host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
- } else {
- host->ios.chip_select = MMC_CS_DONTCARE;
- host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
- }
- host->ios.bus_width = MMC_BUS_WIDTH_1;
- host->ios.timing = MMC_TIMING_LEGACY;
- mmc_set_ios(host);
+ /* Set initial state and call mmc_set_ios */
+ mmc_set_initial_state(host);
mmc_host_clk_release(host);