mmc: core: Add halt support

Halt is a controller feature that can change the controller mode
from command-queue to legacy. This feature is very helpful in
error cases.

Change-Id: I7f1465b609afed68886256bd605d4019716964f4
Signed-off-by: Asutosh Das <asutoshd@codeaurora.org>
This commit is contained in:
Asutosh Das 2015-05-21 17:21:07 +05:30 committed by Gerrit - the friendly Code Review server
parent c9bb6d045d
commit 58e91e920d
4 changed files with 52 additions and 0 deletions

View File

@ -57,6 +57,7 @@ static inline bool mmc_cmdq_should_pull_reqs(struct mmc_host *host,
struct mmc_cmdq_context_info *ctx)
{
if (test_bit(CMDQ_STATE_DCMD_ACTIVE, &ctx->curr_state) ||
mmc_host_halt(host) ||
test_bit(CMDQ_STATE_ERR, &ctx->curr_state)) {
pr_debug("%s: %s: skip pulling reqs: state: %lu\n",
mmc_hostname(host), __func__, ctx->curr_state);

View File

@ -947,6 +947,39 @@ void mmc_cmdq_post_req(struct mmc_host *host, struct mmc_request *mrq, int err)
}
EXPORT_SYMBOL(mmc_cmdq_post_req);
/**
* mmc_cmdq_halt - halt/un-halt the command queue engine
* @host: host instance
* @halt: true - halt, un-halt otherwise
*
* Host halts the command queue engine. It should complete
* the ongoing transfer and release the bus.
* All legacy commands can be sent upon successful
* completion of this function.
* Returns 0 on success, negative otherwise
*/
int mmc_cmdq_halt(struct mmc_host *host, bool halt)
{
int err = 0;
if ((halt && mmc_host_halt(host)) ||
(!halt && !mmc_host_halt(host)))
return -EINVAL;
if (host->cmdq_ops->halt) {
err = host->cmdq_ops->halt(host, halt);
if (!err && halt)
mmc_host_set_halt(host);
else if (!err && !halt)
mmc_host_clr_halt(host);
} else {
err = -ENOSYS;
}
return err;
}
EXPORT_SYMBOL(mmc_cmdq_halt);
int mmc_cmdq_start_req(struct mmc_host *host, struct mmc_cmdq_req *cmdq_req)
{
struct mmc_request *mrq = &cmdq_req->mrq;

View File

@ -115,6 +115,7 @@ struct mmc_card;
struct mmc_async_req;
struct mmc_cmdq_req;
extern int mmc_cmdq_halt(struct mmc_host *host, bool enable);
extern void mmc_cmdq_post_req(struct mmc_host *host, struct mmc_request *mrq,
int err);
extern int mmc_cmdq_start_req(struct mmc_host *host,

View File

@ -97,6 +97,7 @@ struct mmc_cmdq_host_ops {
int (*request)(struct mmc_host *host, struct mmc_request *mrq);
void (*post_req)(struct mmc_host *host, struct mmc_request *mrq,
int err);
int (*halt)(struct mmc_host *host, bool halt);
};
struct mmc_host_ops {
@ -236,6 +237,7 @@ struct mmc_cmdq_context_info {
unsigned long curr_state;
#define CMDQ_STATE_ERR 0
#define CMDQ_STATE_DCMD_ACTIVE 1
#define CMDQ_STATE_HALT 2
/* no free tag available */
unsigned long req_starved;
};
@ -656,6 +658,21 @@ static inline int mmc_host_packed_wr(struct mmc_host *host)
return host->caps2 & MMC_CAP2_PACKED_WR;
}
static inline void mmc_host_set_halt(struct mmc_host *host)
{
set_bit(CMDQ_STATE_HALT, &host->cmdq_ctx.curr_state);
}
static inline void mmc_host_clr_halt(struct mmc_host *host)
{
clear_bit(CMDQ_STATE_HALT, &host->cmdq_ctx.curr_state);
}
static inline int mmc_host_halt(struct mmc_host *host)
{
return test_bit(CMDQ_STATE_HALT, &host->cmdq_ctx.curr_state);
}
#ifdef CONFIG_MMC_CLKGATE
void mmc_host_clk_hold(struct mmc_host *host);
void mmc_host_clk_release(struct mmc_host *host);