summaryrefslogtreecommitdiff
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.c553
1 files changed, 365 insertions, 188 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index cff5829790c9..f57d97ff41f0 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -40,6 +40,7 @@
#include <trace/events/mmc.h>
#include "core.h"
+#include "card.h"
#include "bus.h"
#include "host.h"
#include "sdio_bus.h"
@@ -63,6 +64,8 @@
static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
+static int __mmc_max_reserved_idx = -1;
+
/*
* Enabling software CRCs on the data blocks can be a significant (30%)
* performance cost, and for other reasons may not always be desired.
@@ -171,14 +174,16 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
trace_mmc_request_done(host, mrq);
- if (err && cmd->retries && !mmc_card_removed(host->card)) {
- /*
- * Request starter must handle retries - see
- * mmc_wait_for_req_done().
- */
- if (mrq->done)
- mrq->done(mrq);
- } else {
+ /*
+ * We list various conditions for the command to be considered
+ * properly done:
+ *
+ * - There was no error, OK fine then
+ * - We are not doing some kind of retry
+ * - The card was removed (...so just complete everything no matter
+ * if there are errors or retries)
+ */
+ if (!err || !cmd->retries || mmc_card_removed(host->card)) {
mmc_should_fail_request(host, mrq);
if (!host->ongoing_mrq)
@@ -210,10 +215,13 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
mrq->stop->resp[0], mrq->stop->resp[1],
mrq->stop->resp[2], mrq->stop->resp[3]);
}
-
- if (mrq->done)
- mrq->done(mrq);
}
+ /*
+ * Request starter must handle retries - see
+ * mmc_wait_for_req_done().
+ */
+ if (mrq->done)
+ mrq->done(mrq);
}
EXPORT_SYMBOL(mmc_request_done);
@@ -233,8 +241,10 @@ static void __mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
/*
* For sdio rw commands we must wait for card busy otherwise some
* sdio devices won't work properly.
+ * And bypass I/O abort, reset and bus suspend operations.
*/
- if (mmc_is_io_op(mrq->cmd->opcode) && host->ops->card_busy) {
+ if (sdio_is_io_busy(mrq->cmd->opcode, mrq->cmd->arg) &&
+ host->ops->card_busy) {
int tries = 500; /* Wait aprox 500ms at maximum */
while (host->ops->card_busy(host) && --tries)
@@ -258,29 +268,29 @@ static void __mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
trace_mmc_request_start(host, mrq);
+ if (host->cqe_on)
+ host->cqe_ops->cqe_off(host);
+
host->ops->request(host, mrq);
}
-static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
+static void mmc_mrq_pr_debug(struct mmc_host *host, struct mmc_request *mrq,
+ bool cqe)
{
-#ifdef CONFIG_MMC_DEBUG
- unsigned int i, sz;
- struct scatterlist *sg;
-#endif
- mmc_retune_hold(host);
-
- if (mmc_card_removed(host->card))
- return -ENOMEDIUM;
-
if (mrq->sbc) {
pr_debug("<%s: starting CMD%u arg %08x flags %08x>\n",
mmc_hostname(host), mrq->sbc->opcode,
mrq->sbc->arg, mrq->sbc->flags);
}
- pr_debug("%s: starting CMD%u arg %08x flags %08x\n",
- mmc_hostname(host), mrq->cmd->opcode,
- mrq->cmd->arg, mrq->cmd->flags);
+ if (mrq->cmd) {
+ pr_debug("%s: starting %sCMD%u arg %08x flags %08x\n",
+ mmc_hostname(host), cqe ? "CQE direct " : "",
+ mrq->cmd->opcode, mrq->cmd->arg, mrq->cmd->flags);
+ } else if (cqe) {
+ pr_debug("%s: starting CQE transfer for tag %d blkaddr %u\n",
+ mmc_hostname(host), mrq->tag, mrq->data->blk_addr);
+ }
if (mrq->data) {
pr_debug("%s: blksz %d blocks %d flags %08x "
@@ -296,29 +306,36 @@ static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
mmc_hostname(host), mrq->stop->opcode,
mrq->stop->arg, mrq->stop->flags);
}
+}
- WARN_ON(!host->claimed);
+static int mmc_mrq_prep(struct mmc_host *host, struct mmc_request *mrq)
+{
+#ifdef CONFIG_MMC_DEBUG
+ unsigned int i, sz;
+ struct scatterlist *sg;
+#endif
- mrq->cmd->error = 0;
- mrq->cmd->mrq = mrq;
+ if (mrq->cmd) {
+ mrq->cmd->error = 0;
+ mrq->cmd->mrq = mrq;
+ mrq->cmd->data = mrq->data;
+ }
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);
- BUG_ON(mrq->data->blocks * mrq->data->blksz >
- host->max_req_size);
-
+ if (mrq->data->blksz > host->max_blk_size ||
+ mrq->data->blocks > host->max_blk_count ||
+ mrq->data->blocks * mrq->data->blksz > host->max_req_size)
+ return -EINVAL;
#ifdef CONFIG_MMC_DEBUG
sz = 0;
for_each_sg(mrq->data->sg, sg, mrq->data->sg_len, i)
sz += sg->length;
- BUG_ON(sz != mrq->data->blocks * mrq->data->blksz);
+ if (sz != mrq->data->blocks * mrq->data->blksz)
+ return -EINVAL;
#endif
-
- mrq->cmd->data = mrq->data;
mrq->data->error = 0;
mrq->data->mrq = mrq;
if (mrq->stop) {
@@ -327,6 +344,27 @@ static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
mrq->stop->mrq = mrq;
}
}
+
+ return 0;
+}
+
+static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
+{
+ int err;
+
+ mmc_retune_hold(host);
+
+ if (mmc_card_removed(host->card))
+ return -ENOMEDIUM;
+
+ mmc_mrq_pr_debug(host, mrq, false);
+
+ WARN_ON(!host->claimed);
+
+ err = mmc_mrq_prep(host, mrq);
+ if (err)
+ return err;
+
led_trigger_event(host->led, LED_FULL);
__mmc_start_request(host, mrq);
@@ -349,8 +387,6 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception)
int timeout;
bool use_busy_signal;
- BUG_ON(!card);
-
if (!card->ext_csd.man_bkops_en || mmc_card_doing_bkops(card))
return;
@@ -380,7 +416,7 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception)
mmc_retune_hold(card->host);
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_BKOPS_START, 1, timeout,
+ EXT_CSD_BKOPS_START, 1, timeout, 0,
use_busy_signal, true, false);
if (err) {
pr_warn("%s: Error %d starting bkops\n",
@@ -486,63 +522,6 @@ static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
return err;
}
-/*
- * mmc_wait_for_data_req_done() - wait for request completed
- * @host: MMC host to prepare the command.
- * @mrq: MMC request to wait for
- *
- * Blocks MMC context till host controller will ack end of data request
- * execution or new request notification arrives from the block layer.
- * Handles command retries.
- *
- * Returns enum mmc_blk_status after checking errors.
- */
-static int mmc_wait_for_data_req_done(struct mmc_host *host,
- struct mmc_request *mrq,
- struct mmc_async_req *next_req)
-{
- struct mmc_command *cmd;
- struct mmc_context_info *context_info = &host->context_info;
- int err;
- unsigned long flags;
-
- while (1) {
- wait_event_interruptible(context_info->wait,
- (context_info->is_done_rcv ||
- context_info->is_new_req));
- spin_lock_irqsave(&context_info->lock, flags);
- context_info->is_waiting_last_req = false;
- spin_unlock_irqrestore(&context_info->lock, flags);
- if (context_info->is_done_rcv) {
- context_info->is_done_rcv = false;
- context_info->is_new_req = false;
- cmd = mrq->cmd;
-
- if (!cmd->error || !cmd->retries ||
- mmc_card_removed(host->card)) {
- err = host->areq->err_check(host->card,
- host->areq);
- break; /* return err */
- } else {
- mmc_retune_recheck(host);
- pr_info("%s: req failed (CMD%u): %d, retrying...\n",
- mmc_hostname(host),
- cmd->opcode, cmd->error);
- cmd->retries--;
- cmd->error = 0;
- __mmc_start_request(host, mrq);
- continue; /* wait for done/new event again */
- }
- } else if (context_info->is_new_req) {
- context_info->is_new_req = false;
- if (!next_req)
- return MMC_BLK_NEW_REQUEST;
- }
- }
- mmc_retune_release(host);
- return err;
-}
-
void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq)
{
struct mmc_command *cmd;
@@ -586,6 +565,139 @@ void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq)
}
EXPORT_SYMBOL(mmc_wait_for_req_done);
+int mmc_cqe_start_req(struct mmc_host *host, struct mmc_request *mrq)
+{
+ int err;
+
+ /* Caller must hold retuning while CQE is in use */
+ err = mmc_retune(host);
+ if (err)
+ goto out_err;
+
+ mrq->host = host;
+
+ mmc_mrq_pr_debug(host, mrq, true);
+
+ err = mmc_mrq_prep(host, mrq);
+ if (err)
+ goto out_err;
+
+ err = host->cqe_ops->cqe_request(host, mrq);
+ if (err)
+ goto out_err;
+
+ trace_mmc_request_start(host, mrq);
+
+ return 0;
+
+out_err:
+ if (mrq->cmd) {
+ pr_debug("%s: failed to start CQE direct CMD%u, error %d\n",
+ mmc_hostname(host), mrq->cmd->opcode, err);
+ } else {
+ pr_debug("%s: failed to start CQE transfer for tag %d, error %d\n",
+ mmc_hostname(host), mrq->tag, err);
+ }
+ return err;
+}
+EXPORT_SYMBOL(mmc_cqe_start_req);
+
+static void __mmc_cqe_request_done(struct mmc_host *host,
+ struct mmc_request *mrq)
+{
+ mmc_should_fail_request(host, mrq);
+
+ /* Flag re-tuning needed on CRC errors */
+ if ((mrq->cmd && mrq->cmd->error == -EILSEQ) ||
+ (mrq->data && mrq->data->error == -EILSEQ))
+ mmc_retune_needed(host);
+
+ trace_mmc_request_done(host, mrq);
+
+ if (mrq->cmd) {
+ pr_debug("%s: CQE req done (direct CMD%u): %d\n",
+ mmc_hostname(host), mrq->cmd->opcode, mrq->cmd->error);
+ } else {
+ pr_debug("%s: CQE transfer done tag %d\n",
+ mmc_hostname(host), mrq->tag);
+ }
+
+ if (mrq->data) {
+ pr_debug("%s: %d bytes transferred: %d\n",
+ mmc_hostname(host),
+ mrq->data->bytes_xfered, mrq->data->error);
+ }
+}
+
+/**
+ * mmc_cqe_request_done - CQE has finished processing an MMC request
+ * @host: MMC host which completed request
+ * @mrq: MMC request which completed
+ *
+ * CQE drivers should call this function when they have completed
+ * their processing of a request.
+ */
+void mmc_cqe_request_done(struct mmc_host *host, struct mmc_request *mrq)
+{
+ __mmc_cqe_request_done(host, mrq);
+
+ mrq->done(mrq);
+}
+EXPORT_SYMBOL(mmc_cqe_request_done);
+
+/**
+ * mmc_cqe_post_req - CQE post process of a completed MMC request
+ * @host: MMC host
+ * @mrq: MMC request to be processed
+ */
+void mmc_cqe_post_req(struct mmc_host *host, struct mmc_request *mrq)
+{
+ if (host->cqe_ops->cqe_post_req)
+ host->cqe_ops->cqe_post_req(host, mrq);
+}
+EXPORT_SYMBOL(mmc_cqe_post_req);
+
+/* Arbitrary 1 second timeout */
+#define MMC_CQE_RECOVERY_TIMEOUT 1000
+
+int mmc_cqe_recovery(struct mmc_host *host)
+{
+ struct mmc_command cmd;
+ int err;
+
+ mmc_retune_hold_now(host);
+
+ /*
+ * Recovery is expected seldom, if at all, but it reduces performance,
+ * so make sure it is not completely silent.
+ */
+ pr_warn("%s: running CQE recovery\n", mmc_hostname(host));
+
+ host->cqe_ops->cqe_recovery_start(host);
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.opcode = MMC_STOP_TRANSMISSION,
+ cmd.flags = MMC_RSP_R1B | MMC_CMD_AC,
+ cmd.flags &= ~MMC_RSP_CRC; /* Ignore CRC */
+ cmd.busy_timeout = MMC_CQE_RECOVERY_TIMEOUT,
+ mmc_wait_for_cmd(host, &cmd, 0);
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.opcode = MMC_CMDQ_TASK_MGMT;
+ cmd.arg = 1; /* Discard entire queue */
+ cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
+ cmd.flags &= ~MMC_RSP_CRC; /* Ignore CRC */
+ cmd.busy_timeout = MMC_CQE_RECOVERY_TIMEOUT,
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+
+ host->cqe_ops->cqe_recovery_finish(host);
+
+ mmc_retune_release(host);
+
+ return err;
+}
+EXPORT_SYMBOL(mmc_cqe_recovery);
+
/**
* mmc_is_req_done - Determine if a 'cap_cmd_during_tfr' request is done
* @host: MMC host
@@ -611,18 +723,15 @@ EXPORT_SYMBOL(mmc_is_req_done);
* mmc_pre_req - Prepare for a new request
* @host: MMC host to prepare command
* @mrq: MMC request to prepare for
- * @is_first_req: true if there is no previous started request
- * that may run in parellel to this call, otherwise false
*
* mmc_pre_req() is called in prior to mmc_start_req() to let
* host prepare for the new request. Preparation of a request may be
* performed while another request is running on the host.
*/
-static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq,
- bool is_first_req)
+static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq)
{
if (host->ops->pre_req)
- host->ops->pre_req(host, mrq, is_first_req);
+ host->ops->pre_req(host, mrq);
}
/**
@@ -642,10 +751,71 @@ static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq,
}
/**
- * mmc_start_req - start a non-blocking request
+ * mmc_finalize_areq() - finalize an asynchronous request
+ * @host: MMC host to finalize any ongoing request on
+ *
+ * Returns the status of the ongoing asynchronous request, but
+ * MMC_BLK_SUCCESS if no request was going on.
+ */
+static enum mmc_blk_status mmc_finalize_areq(struct mmc_host *host)
+{
+ struct mmc_context_info *context_info = &host->context_info;
+ enum mmc_blk_status status;
+
+ if (!host->areq)
+ return MMC_BLK_SUCCESS;
+
+ while (1) {
+ wait_event_interruptible(context_info->wait,
+ (context_info->is_done_rcv ||
+ context_info->is_new_req));
+
+ if (context_info->is_done_rcv) {
+ struct mmc_command *cmd;
+
+ context_info->is_done_rcv = false;
+ cmd = host->areq->mrq->cmd;
+
+ if (!cmd->error || !cmd->retries ||
+ mmc_card_removed(host->card)) {
+ status = host->areq->err_check(host->card,
+ host->areq);
+ break; /* return status */
+ } else {
+ mmc_retune_recheck(host);
+ pr_info("%s: req failed (CMD%u): %d, retrying...\n",
+ mmc_hostname(host),
+ cmd->opcode, cmd->error);
+ cmd->retries--;
+ cmd->error = 0;
+ __mmc_start_request(host, host->areq->mrq);
+ continue; /* wait for done/new event again */
+ }
+ }
+
+ return MMC_BLK_NEW_REQUEST;
+ }
+
+ mmc_retune_release(host);
+
+ /*
+ * Check BKOPS urgency for each R1 response
+ */
+ 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)) {
+ mmc_start_bkops(host->card, true);
+ }
+
+ return status;
+}
+
+/**
+ * mmc_start_areq - start an asynchronous request
* @host: MMC host to start command
- * @areq: async request to start
- * @error: out parameter returns 0 for success, otherwise non zero
+ * @areq: asynchronous request to start
+ * @ret_stat: out parameter for status
*
* Start a new MMC custom command request for a host.
* If there is on ongoing async request wait for completion
@@ -657,68 +827,47 @@ static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq,
* return the completed request. If there is no ongoing request, NULL
* is returned without waiting. NULL is not an error condition.
*/
-struct mmc_async_req *mmc_start_req(struct mmc_host *host,
- struct mmc_async_req *areq, int *error)
+struct mmc_async_req *mmc_start_areq(struct mmc_host *host,
+ struct mmc_async_req *areq,
+ enum mmc_blk_status *ret_stat)
{
- int err = 0;
+ enum mmc_blk_status status;
int start_err = 0;
- struct mmc_async_req *data = host->areq;
+ struct mmc_async_req *previous = host->areq;
/* Prepare a new request */
if (areq)
- mmc_pre_req(host, areq->mrq, !host->areq);
+ mmc_pre_req(host, areq->mrq);
- if (host->areq) {
- err = mmc_wait_for_data_req_done(host, host->areq->mrq, areq);
- if (err == MMC_BLK_NEW_REQUEST) {
- if (error)
- *error = err;
- /*
- * The previous request was not completed,
- * nothing to return
- */
- return NULL;
- }
- /*
- * Check BKOPS urgency for each R1 response
- */
- 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)) {
+ /* Finalize previous request */
+ status = mmc_finalize_areq(host);
+ if (ret_stat)
+ *ret_stat = status;
- /* 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);
- }
- }
+ /* The previous request is still going on... */
+ if (status == MMC_BLK_NEW_REQUEST)
+ return NULL;
- if (!err && areq)
+ /* Fine so far, start the new request! */
+ if (status == MMC_BLK_SUCCESS && areq)
start_err = __mmc_start_data_req(host, areq->mrq);
+ /* Postprocess the old request at this point */
if (host->areq)
mmc_post_req(host, host->areq->mrq, 0);
- /* Cancel a prepared request if it was not started. */
- if ((err || start_err) && areq)
+ /* Cancel a prepared request if it was not started. */
+ if ((status != MMC_BLK_SUCCESS || start_err) && areq)
mmc_post_req(host, areq->mrq, -EINVAL);
- if (err)
+ if (status != MMC_BLK_SUCCESS)
host->areq = NULL;
else
host->areq = areq;
- if (error)
- *error = err;
- return data;
+ return previous;
}
-EXPORT_SYMBOL(mmc_start_req);
+EXPORT_SYMBOL(mmc_start_areq);
/**
* mmc_wait_for_req - start a request and wait for completion
@@ -754,8 +903,6 @@ int mmc_interrupt_hpi(struct mmc_card *card)
u32 status;
unsigned long prg_wait;
- BUG_ON(!card);
-
if (!card->ext_csd.hpi_en) {
pr_info("%s: HPI enable bit unset\n", mmc_hostname(card->host));
return 1;
@@ -820,7 +967,7 @@ EXPORT_SYMBOL(mmc_interrupt_hpi);
*/
int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries)
{
- struct mmc_request mrq = {NULL};
+ struct mmc_request mrq = {};
WARN_ON(!host->claimed);
@@ -850,7 +997,6 @@ int mmc_stop_bkops(struct mmc_card *card)
{
int err = 0;
- BUG_ON(!card);
err = mmc_interrupt_hpi(card);
/*
@@ -1164,6 +1310,9 @@ int mmc_execute_tuning(struct mmc_card *card)
if (!host->ops->execute_tuning)
return 0;
+ if (host->cqe_on)
+ host->cqe_ops->cqe_off(host);
+
if (mmc_card_mmc(card))
opcode = MMC_SEND_TUNING_BLOCK_HS200;
else
@@ -1203,6 +1352,9 @@ void mmc_set_bus_width(struct mmc_host *host, unsigned int width)
*/
void mmc_set_initial_state(struct mmc_host *host)
{
+ if (host->cqe_on)
+ host->cqe_ops->cqe_off(host);
+
mmc_retune_disable(host);
if (mmc_host_is_spi(host))
@@ -1644,7 +1796,7 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
return ocr;
}
-int __mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage)
+int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage)
{
int err = 0;
int old_signal_voltage = host->ios.signal_voltage;
@@ -1660,21 +1812,12 @@ int __mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage)
}
-int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr)
+int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr)
{
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
int err = 0;
u32 clock;
- BUG_ON(!host);
-
- /*
- * Send CMD11 only if the request is to switch the card to
- * 1.8V signalling.
- */
- if (signal_voltage == MMC_SIGNAL_VOLTAGE_330)
- return __mmc_set_signal_voltage(host, signal_voltage);
-
/*
* If we cannot switch voltages, return failure so the caller
* can continue without UHS mode
@@ -1713,7 +1856,7 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr)
host->ios.clock = 0;
mmc_set_ios(host);
- if (__mmc_set_signal_voltage(host, signal_voltage)) {
+ if (mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180)) {
/*
* Voltages may not have been switched, but we've already
* sent CMD11, so a power cycle is required anyway
@@ -1822,11 +1965,11 @@ void mmc_power_up(struct mmc_host *host, u32 ocr)
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)
+ if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330))
dev_dbg(mmc_dev(host), "Initial signal voltage of 3.3v\n");
- else if (__mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180) == 0)
+ else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180))
dev_dbg(mmc_dev(host), "Initial signal voltage of 1.8v\n");
- else if (__mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120) == 0)
+ else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120))
dev_dbg(mmc_dev(host), "Initial signal voltage of 1.2v\n");
/*
@@ -1884,9 +2027,7 @@ void mmc_power_cycle(struct mmc_host *host, u32 ocr)
*/
static void __mmc_release_bus(struct mmc_host *host)
{
- BUG_ON(!host);
- BUG_ON(host->bus_refs);
- BUG_ON(!host->bus_dead);
+ WARN_ON(!host->bus_dead);
host->bus_ops = NULL;
}
@@ -1926,15 +2067,12 @@ void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops)
{
unsigned long flags;
- BUG_ON(!host);
- BUG_ON(!ops);
-
WARN_ON(!host->claimed);
spin_lock_irqsave(&host->lock, flags);
- BUG_ON(host->bus_ops);
- BUG_ON(host->bus_refs);
+ WARN_ON(host->bus_ops);
+ WARN_ON(host->bus_refs);
host->bus_ops = ops;
host->bus_refs = 1;
@@ -1950,8 +2088,6 @@ void mmc_detach_bus(struct mmc_host *host)
{
unsigned long flags;
- BUG_ON(!host);
-
WARN_ON(!host->claimed);
WARN_ON(!host->bus_ops);
@@ -2152,7 +2288,7 @@ static unsigned int mmc_erase_timeout(struct mmc_card *card,
static int mmc_do_erase(struct mmc_card *card, unsigned int from,
unsigned int to, unsigned int arg)
{
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
unsigned int qty = 0, busy_timeout = 0;
bool use_r1b_resp = false;
unsigned long timeout;
@@ -2572,9 +2708,15 @@ unsigned int mmc_calc_max_discard(struct mmc_card *card)
}
EXPORT_SYMBOL(mmc_calc_max_discard);
+bool mmc_card_is_blockaddr(struct mmc_card *card)
+{
+ return card ? mmc_card_blockaddr(card) : false;
+}
+EXPORT_SYMBOL(mmc_card_is_blockaddr);
+
int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
{
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
if (mmc_card_blockaddr(card) || mmc_card_ddr52(card) ||
mmc_card_hs400(card) || mmc_card_hs400es(card))
@@ -2590,7 +2732,7 @@ EXPORT_SYMBOL(mmc_set_blocklen);
int mmc_set_blockcount(struct mmc_card *card, unsigned int blockcount,
bool is_rel_write)
{
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
cmd.opcode = MMC_SET_BLOCK_COUNT;
cmd.arg = blockcount & 0x0000FFFF;
@@ -2603,6 +2745,8 @@ EXPORT_SYMBOL(mmc_set_blockcount);
static void mmc_hw_reset_for_init(struct mmc_host *host)
{
+ mmc_pwrseq_reset(host);
+
if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset)
return;
host->ops->hw_reset(host);
@@ -2824,15 +2968,15 @@ void mmc_start_host(struct mmc_host *host)
host->rescan_disable = 0;
host->ios.power_mode = MMC_POWER_UNDEFINED;
- mmc_claim_host(host);
- if (host->caps2 & MMC_CAP2_NO_PRESCAN_POWERUP)
- mmc_power_off(host);
- else
+ if (!(host->caps2 & MMC_CAP2_NO_PRESCAN_POWERUP)) {
+ mmc_claim_host(host);
mmc_power_up(host, host->ocr_avail);
- mmc_release_host(host);
+ mmc_release_host(host);
+ }
mmc_gpiod_request_cd_irq(host);
- _mmc_detect_change(host, 0, false);
+ if (!(host->caps2 & MMC_CAP2_CD_POST))
+ _mmc_detect_change(host, 0, false);
}
void mmc_stop_host(struct mmc_host *host)
@@ -2865,8 +3009,6 @@ void mmc_stop_host(struct mmc_host *host)
}
mmc_bus_put(host);
- BUG_ON(host->card);
-
mmc_claim_host(host);
mmc_power_off(host);
mmc_release_host(host);
@@ -3027,17 +3169,52 @@ void mmc_unregister_pm_notifier(struct mmc_host *host)
*/
void mmc_init_context_info(struct mmc_host *host)
{
- spin_lock_init(&host->context_info.lock);
host->context_info.is_new_req = false;
host->context_info.is_done_rcv = false;
host->context_info.is_waiting_last_req = false;
init_waitqueue_head(&host->context_info.wait);
}
+/*
+ * mmc_first_nonreserved_index() - get the first index that
+ * is not reserved
+ */
+int mmc_first_nonreserved_index(void)
+{
+ return __mmc_max_reserved_idx + 1;
+}
+EXPORT_SYMBOL(mmc_first_nonreserved_index);
+
+/*
+ * mmc_get_reserved_index() - get the index reserved for this host
+ * Return: The index reserved for this host or negative error value
+ * if no index is reserved for this host
+ */
+int mmc_get_reserved_index(struct mmc_host *host)
+{
+ return of_alias_get_id(host->parent->of_node, "mmc");
+}
+EXPORT_SYMBOL(mmc_get_reserved_index);
+
+static void mmc_of_reserve_idx(void)
+{
+ int max;
+
+ max = of_alias_max_index("mmc");
+ if (max < 0)
+ return;
+
+ __mmc_max_reserved_idx = max;
+ pr_debug("MMC: reserving %d slots for of aliases\n",
+ __mmc_max_reserved_idx + 1);
+}
+
static int __init mmc_init(void)
{
int ret;
+ mmc_of_reserve_idx();
+
ret = mmc_register_bus();
if (ret)
return ret;