Skip to content

Commit

Permalink
Merge commit 'd293875' into mvebu/boards
Browse files Browse the repository at this point in the history
Pulled in mmc/mmc-next up to:

d293875 mmc: mvsdio: add pinctrl integration
  • Loading branch information
Jason Cooper committed Jan 31, 2013
2 parents 2229221 + d293875 commit 04ee16b
Show file tree
Hide file tree
Showing 22 changed files with 869 additions and 330 deletions.
18 changes: 18 additions & 0 deletions Documentation/devicetree/bindings/mmc/brcm,bcm2835-sdhci.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
Broadcom BCM2835 SDHCI controller

This file documents differences between the core properties described
by mmc.txt and the properties that represent the BCM2835 controller.

Required properties:
- compatible : Should be "brcm,bcm2835-sdhci".
- clocks : The clock feeding the SDHCI controller.

Example:

sdhci: sdhci {
compatible = "brcm,bcm2835-sdhci";
reg = <0x7e300000 0x100>;
interrupts = <2 30>;
clocks = <&clk_mmc>;
bus-width = <4>;
};
17 changes: 17 additions & 0 deletions Documentation/devicetree/bindings/mmc/orion-sdio.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
* Marvell orion-sdio controller

This file documents differences between the core properties in mmc.txt
and the properties used by the orion-sdio driver.

- compatible: Should be "marvell,orion-sdio"
- clocks: reference to the clock of the SDIO interface

Example:

mvsdio@d00d4000 {
compatible = "marvell,orion-sdio";
reg = <0xd00d4000 0x200>;
interrupts = <54>;
clocks = <&gateclk 17>;
status = "disabled";
};
30 changes: 17 additions & 13 deletions drivers/mmc/card/block.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,17 +113,6 @@ struct mmc_blk_data {

static DEFINE_MUTEX(open_lock);

enum mmc_blk_status {
MMC_BLK_SUCCESS = 0,
MMC_BLK_PARTIAL,
MMC_BLK_CMD_ERR,
MMC_BLK_RETRY,
MMC_BLK_ABORT,
MMC_BLK_DATA_ERR,
MMC_BLK_ECC_ERR,
MMC_BLK_NOMEDIUM,
};

module_param(perdev_minors, int, 0444);
MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device");

Expand Down Expand Up @@ -1364,8 +1353,11 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
} else
areq = NULL;
areq = mmc_start_req(card->host, areq, (int *) &status);
if (!areq)
if (!areq) {
if (status == MMC_BLK_NEW_REQUEST)
mq->flags |= MMC_QUEUE_NEW_REQUEST;
return 0;
}

mq_rq = container_of(areq, struct mmc_queue_req, mmc_active);
brq = &mq_rq->brq;
Expand Down Expand Up @@ -1438,6 +1430,10 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
break;
case MMC_BLK_NOMEDIUM:
goto cmd_abort;
default:
pr_err("%s: Unhandled return value (%d)",
req->rq_disk->disk_name, status);
goto cmd_abort;
}

if (ret) {
Expand Down Expand Up @@ -1472,6 +1468,8 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
int ret;
struct mmc_blk_data *md = mq->data;
struct mmc_card *card = md->queue.card;
struct mmc_host *host = card->host;
unsigned long flags;

if (req && !mq->mqrq_prev->req)
/* claim host only for the first request */
Expand All @@ -1486,6 +1484,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
goto out;
}

mq->flags &= ~MMC_QUEUE_NEW_REQUEST;
if (req && req->cmd_flags & REQ_DISCARD) {
/* complete ongoing async transfer before issuing discard */
if (card->host->areq)
Expand All @@ -1501,11 +1500,16 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
mmc_blk_issue_rw_rq(mq, NULL);
ret = mmc_blk_issue_flush(mq, req);
} else {
if (!req && host->areq) {
spin_lock_irqsave(&host->context_info.lock, flags);
host->context_info.is_waiting_last_req = true;
spin_unlock_irqrestore(&host->context_info.lock, flags);
}
ret = mmc_blk_issue_rw_rq(mq, req);
}

out:
if (!req)
if (!req && !(mq->flags & MMC_QUEUE_NEW_REQUEST))
/* release host only when there are no more requests */
mmc_release_host(card->host);
return ret;
Expand Down
32 changes: 30 additions & 2 deletions drivers/mmc/card/queue.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@

#define MMC_QUEUE_BOUNCESZ 65536

#define MMC_QUEUE_SUSPENDED (1 << 0)

#define MMC_REQ_SPECIAL_MASK (REQ_DISCARD | REQ_FLUSH)

/*
* Prepare a MMC request. This just filters out odd stuff.
Expand Down Expand Up @@ -58,6 +59,7 @@ static int mmc_queue_thread(void *d)
do {
struct request *req = NULL;
struct mmc_queue_req *tmp;
unsigned int cmd_flags = 0;

spin_lock_irq(q->queue_lock);
set_current_state(TASK_INTERRUPTIBLE);
Expand All @@ -67,12 +69,23 @@ static int mmc_queue_thread(void *d)

if (req || mq->mqrq_prev->req) {
set_current_state(TASK_RUNNING);
cmd_flags = req ? req->cmd_flags : 0;
mq->issue_fn(mq, req);
if (mq->flags & MMC_QUEUE_NEW_REQUEST) {
mq->flags &= ~MMC_QUEUE_NEW_REQUEST;
continue; /* fetch again */
}

/*
* Current request becomes previous request
* and vice versa.
* In case of special requests, current request
* has been finished. Do not assign it to previous
* request.
*/
if (cmd_flags & MMC_REQ_SPECIAL_MASK)
mq->mqrq_cur->req = NULL;

mq->mqrq_prev->brq.mrq.data = NULL;
mq->mqrq_prev->req = NULL;
tmp = mq->mqrq_prev;
Expand Down Expand Up @@ -103,6 +116,8 @@ static void mmc_request_fn(struct request_queue *q)
{
struct mmc_queue *mq = q->queuedata;
struct request *req;
unsigned long flags;
struct mmc_context_info *cntx;

if (!mq) {
while ((req = blk_fetch_request(q)) != NULL) {
Expand All @@ -112,7 +127,20 @@ static void mmc_request_fn(struct request_queue *q)
return;
}

if (!mq->mqrq_cur->req && !mq->mqrq_prev->req)
cntx = &mq->card->host->context_info;
if (!mq->mqrq_cur->req && mq->mqrq_prev->req) {
/*
* New MMC request arrived when MMC thread may be
* blocked on the previous request to be complete
* with no current request fetched
*/
spin_lock_irqsave(&cntx->lock, flags);
if (cntx->is_waiting_last_req) {
cntx->is_new_req = true;
wake_up_interruptible(&cntx->wait);
}
spin_unlock_irqrestore(&cntx->lock, flags);
} else if (!mq->mqrq_cur->req && !mq->mqrq_prev->req)
wake_up_process(mq->thread);
}

Expand Down
3 changes: 3 additions & 0 deletions drivers/mmc/card/queue.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ struct mmc_queue {
struct task_struct *thread;
struct semaphore thread_sem;
unsigned int flags;
#define MMC_QUEUE_SUSPENDED (1 << 0)
#define MMC_QUEUE_NEW_REQUEST (1 << 1)

int (*issue_fn)(struct mmc_queue *, struct request *);
void *data;
struct request_queue *queue;
Expand Down
1 change: 1 addition & 0 deletions drivers/mmc/core/bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,7 @@ int mmc_add_card(struct mmc_card *card)
#ifdef CONFIG_DEBUG_FS
mmc_add_card_debugfs(card);
#endif
mmc_init_context_info(card->host);

ret = device_add(&card->dev);
if (ret)
Expand Down
121 changes: 118 additions & 3 deletions drivers/mmc/core/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -319,11 +319,44 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception)
}
EXPORT_SYMBOL(mmc_start_bkops);

/*
* mmc_wait_data_done() - done callback for data request
* @mrq: done data request
*
* Wakes up mmc context, passed as a callback to host controller driver
*/
static void mmc_wait_data_done(struct mmc_request *mrq)
{
mrq->host->context_info.is_done_rcv = true;
wake_up_interruptible(&mrq->host->context_info.wait);
}

static void mmc_wait_done(struct mmc_request *mrq)
{
complete(&mrq->completion);
}

/*
*__mmc_start_data_req() - starts data request
* @host: MMC host to start the request
* @mrq: data request to start
*
* Sets the done callback to be called when request is completed by the card.
* Starts data mmc request execution
*/
static int __mmc_start_data_req(struct mmc_host *host, struct mmc_request *mrq)
{
mrq->done = mmc_wait_data_done;
mrq->host = host;
if (mmc_card_removed(host->card)) {
mrq->cmd->error = -ENOMEDIUM;
return -ENOMEDIUM;
}
mmc_start_request(host, mrq);

return 0;
}

static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
{
init_completion(&mrq->completion);
Expand All @@ -337,6 +370,62 @@ static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
return 0;
}

/*
* 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 {
pr_info("%s: req failed (CMD%u): %d, retrying...\n",
mmc_hostname(host),
cmd->opcode, cmd->error);
cmd->retries--;
cmd->error = 0;
host->ops->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) {
err = MMC_BLK_NEW_REQUEST;
break; /* return err */
}
}
}
return err;
}

static void mmc_wait_for_req_done(struct mmc_host *host,
struct mmc_request *mrq)
{
Expand Down Expand Up @@ -426,8 +515,17 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host,
mmc_pre_req(host, areq->mrq, !host->areq);

if (host->areq) {
mmc_wait_for_req_done(host, host->areq->mrq);
err = host->areq->err_check(host->card, 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
*/
Expand All @@ -439,7 +537,7 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host,
}

if (!err && areq)
start_err = __mmc_start_req(host, areq->mrq);
start_err = __mmc_start_data_req(host, areq->mrq);

if (host->areq)
mmc_post_req(host, host->areq->mrq, 0);
Expand Down Expand Up @@ -2581,6 +2679,23 @@ int mmc_pm_notify(struct notifier_block *notify_block,
}
#endif

/**
* mmc_init_context_info() - init synchronization context
* @host: mmc host
*
* Init struct context_info needed to implement asynchronous
* request mechanism, used by mmc core, host driver and mmc requests
* supplier.
*/
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);
}

static int __init mmc_init(void)
{
int ret;
Expand Down
1 change: 1 addition & 0 deletions drivers/mmc/core/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,5 +76,6 @@ void mmc_remove_host_debugfs(struct mmc_host *host);
void mmc_add_card_debugfs(struct mmc_card *card);
void mmc_remove_card_debugfs(struct mmc_card *card);

void mmc_init_context_info(struct mmc_host *host);
#endif

Loading

0 comments on commit 04ee16b

Please sign in to comment.