|
@@ -129,6 +129,13 @@ static inline int mmc_blk_part_switch(struct mmc_card *card,
|
|
struct mmc_blk_data *md);
|
|
struct mmc_blk_data *md);
|
|
static int get_card_status(struct mmc_card *card, u32 *status, int retries);
|
|
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)
|
|
static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
|
|
{
|
|
{
|
|
struct mmc_blk_data *md;
|
|
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;
|
|
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))
|
|
if (mmc_card_removed(card))
|
|
req->rq_flags |= RQF_QUIET;
|
|
req->rq_flags |= RQF_QUIET;
|
|
while (blk_end_request(req, -EIO, blk_rq_cur_bytes(req)));
|
|
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)) {
|
|
if (mmc_card_removed(mq->card)) {
|
|
req->rq_flags |= RQF_QUIET;
|
|
req->rq_flags |= RQF_QUIET;
|
|
blk_end_request_all(req, -EIO);
|
|
blk_end_request_all(req, -EIO);
|
|
|
|
+ mmc_queue_req_free(mq, mqrq);
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
/* Else proceed and try to restart the current async request */
|
|
/* 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;
|
|
struct mmc_blk_request *brq;
|
|
int disable_multi = 0, retry = 0, type, retune_retry_done = 0;
|
|
int disable_multi = 0, retry = 0, type, retune_retry_done = 0;
|
|
enum mmc_blk_status status;
|
|
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 mmc_queue_req *mq_rq;
|
|
struct request *old_req;
|
|
struct request *old_req;
|
|
struct mmc_async_req *new_areq;
|
|
struct mmc_async_req *new_areq;
|
|
struct mmc_async_req *old_areq;
|
|
struct mmc_async_req *old_areq;
|
|
bool req_pending = true;
|
|
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;
|
|
return;
|
|
|
|
|
|
do {
|
|
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)) {
|
|
!IS_ALIGNED(blk_rq_sectors(new_req), 8)) {
|
|
pr_err("%s: Transfer size is not 4KB sector size aligned\n",
|
|
pr_err("%s: Transfer size is not 4KB sector size aligned\n",
|
|
new_req->rq_disk->disk_name);
|
|
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;
|
|
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
|
|
* and there is nothing more to do until it is
|
|
* complete.
|
|
* complete.
|
|
*/
|
|
*/
|
|
- if (status == MMC_BLK_NEW_REQUEST)
|
|
|
|
- mq->new_request = true;
|
|
|
|
return;
|
|
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",
|
|
pr_err("%s BUG rq_tot %d d_xfer %d\n",
|
|
__func__, blk_rq_bytes(old_req),
|
|
__func__, blk_rq_bytes(old_req),
|
|
brq->data.bytes_xfered);
|
|
brq->data.bytes_xfered);
|
|
- mmc_blk_rw_cmd_abort(card, old_req);
|
|
|
|
|
|
+ mmc_blk_rw_cmd_abort(mq, card, old_req, mq_rq);
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
break;
|
|
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);
|
|
req_pending = mmc_blk_rw_cmd_err(md, card, brq, old_req, req_pending);
|
|
if (mmc_blk_reset(md, card->host, type)) {
|
|
if (mmc_blk_reset(md, card->host, type)) {
|
|
if (req_pending)
|
|
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);
|
|
mmc_blk_rw_try_restart(mq, new_req, mqrq_cur);
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
if (!req_pending) {
|
|
if (!req_pending) {
|
|
|
|
+ mmc_queue_req_free(mq, mq_rq);
|
|
mmc_blk_rw_try_restart(mq, new_req, mqrq_cur);
|
|
mmc_blk_rw_try_restart(mq, new_req, mqrq_cur);
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
@@ -1718,7 +1739,7 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req)
|
|
case MMC_BLK_ABORT:
|
|
case MMC_BLK_ABORT:
|
|
if (!mmc_blk_reset(md, card->host, type))
|
|
if (!mmc_blk_reset(md, card->host, type))
|
|
break;
|
|
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);
|
|
mmc_blk_rw_try_restart(mq, new_req, mqrq_cur);
|
|
return;
|
|
return;
|
|
case MMC_BLK_DATA_ERR: {
|
|
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)
|
|
if (!err)
|
|
break;
|
|
break;
|
|
if (err == -ENODEV) {
|
|
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);
|
|
mmc_blk_rw_try_restart(mq, new_req, mqrq_cur);
|
|
return;
|
|
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,
|
|
req_pending = blk_end_request(old_req, -EIO,
|
|
brq->data.blksz);
|
|
brq->data.blksz);
|
|
if (!req_pending) {
|
|
if (!req_pending) {
|
|
|
|
+ mmc_queue_req_free(mq, mq_rq);
|
|
mmc_blk_rw_try_restart(mq, new_req, mqrq_cur);
|
|
mmc_blk_rw_try_restart(mq, new_req, mqrq_cur);
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
break;
|
|
break;
|
|
case MMC_BLK_NOMEDIUM:
|
|
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);
|
|
mmc_blk_rw_try_restart(mq, new_req, mqrq_cur);
|
|
return;
|
|
return;
|
|
default:
|
|
default:
|
|
pr_err("%s: Unhandled return value (%d)",
|
|
pr_err("%s: Unhandled return value (%d)",
|
|
old_req->rq_disk->disk_name, status);
|
|
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);
|
|
mmc_blk_rw_try_restart(mq, new_req, mqrq_cur);
|
|
return;
|
|
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;
|
|
mq_rq->brq.retune_retry_done = retune_retry_done;
|
|
}
|
|
}
|
|
} while (req_pending);
|
|
} while (req_pending);
|
|
|
|
+
|
|
|
|
+ mmc_queue_req_free(mq, mq_rq);
|
|
}
|
|
}
|
|
|
|
|
|
void mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
|
|
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;
|
|
int ret;
|
|
struct mmc_blk_data *md = mq->blkdata;
|
|
struct mmc_blk_data *md = mq->blkdata;
|
|
struct mmc_card *card = md->queue.card;
|
|
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 */
|
|
/* claim host only for the first request */
|
|
mmc_get_card(card);
|
|
mmc_get_card(card);
|
|
|
|
|
|
@@ -1799,20 +1822,19 @@ void mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
|
|
- mq->new_request = false;
|
|
|
|
if (req && req_op(req) == REQ_OP_DISCARD) {
|
|
if (req && req_op(req) == REQ_OP_DISCARD) {
|
|
/* complete ongoing async transfer before issuing 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_rw_rq(mq, NULL);
|
|
mmc_blk_issue_discard_rq(mq, req);
|
|
mmc_blk_issue_discard_rq(mq, req);
|
|
} else if (req && req_op(req) == REQ_OP_SECURE_ERASE) {
|
|
} else if (req && req_op(req) == REQ_OP_SECURE_ERASE) {
|
|
/* complete ongoing async transfer before issuing 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_rw_rq(mq, NULL);
|
|
mmc_blk_issue_secdiscard_rq(mq, req);
|
|
mmc_blk_issue_secdiscard_rq(mq, req);
|
|
} else if (req && req_op(req) == REQ_OP_FLUSH) {
|
|
} else if (req && req_op(req) == REQ_OP_FLUSH) {
|
|
/* complete ongoing async transfer before issuing 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_rw_rq(mq, NULL);
|
|
mmc_blk_issue_flush(mq, req);
|
|
mmc_blk_issue_flush(mq, req);
|
|
} else {
|
|
} else {
|
|
@@ -1821,13 +1843,7 @@ void mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
|
|
}
|
|
}
|
|
|
|
|
|
out:
|
|
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);
|
|
mmc_put_card(card);
|
|
}
|
|
}
|
|
|
|
|