diff options
Diffstat (limited to 'drivers/mmc/core/block.c')
| -rw-r--r-- | drivers/mmc/core/block.c | 66 |
1 files changed, 41 insertions, 25 deletions
diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index d317e5e9b79a..16c313a62129 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -129,6 +129,13 @@ static inline int mmc_blk_part_switch(struct mmc_card *card, struct mmc_blk_data *md); static int get_card_status(struct mmc_card *card, u32 *status, int retries); +static void mmc_blk_requeue(struct request_queue *q, struct request *req) +{ + spin_lock_irq(q->queue_lock); + blk_requeue_request(q, req); + spin_unlock_irq(q->queue_lock); +} + static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk) { struct mmc_blk_data *md; @@ -1585,11 +1592,14 @@ static bool mmc_blk_rw_cmd_err(struct mmc_blk_data *md, struct mmc_card *card, return req_pending; } -static void mmc_blk_rw_cmd_abort(struct mmc_card *card, struct request *req) +static void mmc_blk_rw_cmd_abort(struct mmc_queue *mq, struct mmc_card *card, + struct request *req, + struct mmc_queue_req *mqrq) { if (mmc_card_removed(card)) req->rq_flags |= RQF_QUIET; while (blk_end_request(req, -EIO, blk_rq_cur_bytes(req))); + mmc_queue_req_free(mq, mqrq); } /** @@ -1609,6 +1619,7 @@ static void mmc_blk_rw_try_restart(struct mmc_queue *mq, struct request *req, if (mmc_card_removed(mq->card)) { req->rq_flags |= RQF_QUIET; blk_end_request_all(req, -EIO); + mmc_queue_req_free(mq, mqrq); return; } /* Else proceed and try to restart the current async request */ @@ -1623,14 +1634,23 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req) struct mmc_blk_request *brq; int disable_multi = 0, retry = 0, type, retune_retry_done = 0; enum mmc_blk_status status; - struct mmc_queue_req *mqrq_cur = mq->mqrq_cur; + struct mmc_queue_req *mqrq_cur = NULL; struct mmc_queue_req *mq_rq; struct request *old_req; struct mmc_async_req *new_areq; struct mmc_async_req *old_areq; bool req_pending = true; - if (!new_req && !mq->mqrq_prev->req) + if (new_req) { + mqrq_cur = mmc_queue_req_find(mq, new_req); + if (!mqrq_cur) { + WARN_ON(1); + mmc_blk_requeue(mq->queue, new_req); + new_req = NULL; + } + } + + if (!mq->qcnt) return; do { @@ -1643,7 +1663,7 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req) !IS_ALIGNED(blk_rq_sectors(new_req), 8)) { pr_err("%s: Transfer size is not 4KB sector size aligned\n", new_req->rq_disk->disk_name); - mmc_blk_rw_cmd_abort(card, new_req); + mmc_blk_rw_cmd_abort(mq, card, new_req, mqrq_cur); return; } @@ -1659,8 +1679,6 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req) * and there is nothing more to do until it is * complete. */ - if (status == MMC_BLK_NEW_REQUEST) - mq->new_request = true; return; } @@ -1693,7 +1711,7 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req) pr_err("%s BUG rq_tot %d d_xfer %d\n", __func__, blk_rq_bytes(old_req), brq->data.bytes_xfered); - mmc_blk_rw_cmd_abort(card, old_req); + mmc_blk_rw_cmd_abort(mq, card, old_req, mq_rq); return; } break; @@ -1701,11 +1719,14 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req) req_pending = mmc_blk_rw_cmd_err(md, card, brq, old_req, req_pending); if (mmc_blk_reset(md, card->host, type)) { if (req_pending) - mmc_blk_rw_cmd_abort(card, old_req); + mmc_blk_rw_cmd_abort(mq, card, old_req, mq_rq); + else + mmc_queue_req_free(mq, mq_rq); mmc_blk_rw_try_restart(mq, new_req, mqrq_cur); return; } if (!req_pending) { + mmc_queue_req_free(mq, mq_rq); mmc_blk_rw_try_restart(mq, new_req, mqrq_cur); return; } @@ -1718,7 +1739,7 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req) case MMC_BLK_ABORT: if (!mmc_blk_reset(md, card->host, type)) break; - mmc_blk_rw_cmd_abort(card, old_req); + mmc_blk_rw_cmd_abort(mq, card, old_req, mq_rq); mmc_blk_rw_try_restart(mq, new_req, mqrq_cur); return; case MMC_BLK_DATA_ERR: { @@ -1728,7 +1749,7 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req) if (!err) break; if (err == -ENODEV) { - mmc_blk_rw_cmd_abort(card, old_req); + mmc_blk_rw_cmd_abort(mq, card, old_req, mq_rq); mmc_blk_rw_try_restart(mq, new_req, mqrq_cur); return; } @@ -1750,18 +1771,19 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req) req_pending = blk_end_request(old_req, -EIO, brq->data.blksz); if (!req_pending) { + mmc_queue_req_free(mq, mq_rq); mmc_blk_rw_try_restart(mq, new_req, mqrq_cur); return; } break; case MMC_BLK_NOMEDIUM: - mmc_blk_rw_cmd_abort(card, old_req); + mmc_blk_rw_cmd_abort(mq, card, old_req, mq_rq); mmc_blk_rw_try_restart(mq, new_req, mqrq_cur); return; default: pr_err("%s: Unhandled return value (%d)", old_req->rq_disk->disk_name, status); - mmc_blk_rw_cmd_abort(card, old_req); + mmc_blk_rw_cmd_abort(mq, card, old_req, mq_rq); mmc_blk_rw_try_restart(mq, new_req, mqrq_cur); return; } @@ -1778,6 +1800,8 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req) mq_rq->brq.retune_retry_done = retune_retry_done; } } while (req_pending); + + mmc_queue_req_free(mq, mq_rq); } void mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) @@ -1785,9 +1809,8 @@ void mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) int ret; struct mmc_blk_data *md = mq->blkdata; struct mmc_card *card = md->queue.card; - bool req_is_special = mmc_req_is_special(req); - if (req && !mq->mqrq_prev->req) + if (req && !mq->qcnt) /* claim host only for the first request */ mmc_get_card(card); @@ -1799,20 +1822,19 @@ void mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) goto out; } - mq->new_request = false; if (req && req_op(req) == REQ_OP_DISCARD) { /* complete ongoing async transfer before issuing discard */ - if (card->host->areq) + if (mq->qcnt) mmc_blk_issue_rw_rq(mq, NULL); mmc_blk_issue_discard_rq(mq, req); } else if (req && req_op(req) == REQ_OP_SECURE_ERASE) { /* complete ongoing async transfer before issuing secure erase*/ - if (card->host->areq) + if (mq->qcnt) mmc_blk_issue_rw_rq(mq, NULL); mmc_blk_issue_secdiscard_rq(mq, req); } else if (req && req_op(req) == REQ_OP_FLUSH) { /* complete ongoing async transfer before issuing flush */ - if (card->host->areq) + if (mq->qcnt) mmc_blk_issue_rw_rq(mq, NULL); mmc_blk_issue_flush(mq, req); } else { @@ -1821,13 +1843,7 @@ void mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) } out: - if ((!req && !mq->new_request) || req_is_special) - /* - * Release host when there are no more requests - * and after special request(discard, flush) is done. - * In case sepecial request, there is no reentry to - * the 'mmc_blk_issue_rq' with 'mqrq_prev->req'. - */ + if (!mq->qcnt) mmc_put_card(card); } |
