aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdrian Hunter <adrian.hunter@nokia.com>2010-08-11 17:17:47 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-08-12 11:43:30 -0400
commitbd788c9665fb7c543aac21317059375632343337 (patch)
tree8d4a2a629cafefa2e0f2a9a44a558d10d3c7bddd
parentdfe86cba7676d58db8de7e623f5e72f1b0d3ca35 (diff)
mmc_block: add discard support
Enable MMC to service discard requests. In the case of SD and MMC cards that do not support trim, discards become erases. In the case of cards (MMC) that only allow erases in multiples of erase group size, round to the nearest completely discarded erase group. Signed-off-by: Adrian Hunter <adrian.hunter@nokia.com> Acked-by: Jens Axboe <axboe@kernel.dk> Cc: Kyungmin Park <kmpark@infradead.org> Cc: Madhusudhan Chikkature <madhu.cr@ti.com> Cc: Christoph Hellwig <hch@lst.de> Cc: Ben Gardiner <bengardiner@nanometrics.ca> Cc: <linux-mmc@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/mmc/card/block.c42
-rw-r--r--drivers/mmc/card/queue.c16
2 files changed, 55 insertions, 3 deletions
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 8433cde29c8b..03f96e975fe5 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -247,7 +247,40 @@ static u32 get_card_status(struct mmc_card *card, struct request *req)
247 return cmd.resp[0]; 247 return cmd.resp[0];
248} 248}
249 249
250static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) 250static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
251{
252 struct mmc_blk_data *md = mq->data;
253 struct mmc_card *card = md->queue.card;
254 unsigned int from, nr, arg;
255 int err = 0;
256
257 mmc_claim_host(card->host);
258
259 if (!mmc_can_erase(card)) {
260 err = -EOPNOTSUPP;
261 goto out;
262 }
263
264 from = blk_rq_pos(req);
265 nr = blk_rq_sectors(req);
266
267 if (mmc_can_trim(card))
268 arg = MMC_TRIM_ARG;
269 else
270 arg = MMC_ERASE_ARG;
271
272 err = mmc_erase(card, from, nr, arg);
273out:
274 spin_lock_irq(&md->lock);
275 __blk_end_request(req, err, blk_rq_bytes(req));
276 spin_unlock_irq(&md->lock);
277
278 mmc_release_host(card->host);
279
280 return err ? 0 : 1;
281}
282
283static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
251{ 284{
252 struct mmc_blk_data *md = mq->data; 285 struct mmc_blk_data *md = mq->data;
253 struct mmc_card *card = md->queue.card; 286 struct mmc_card *card = md->queue.card;
@@ -475,6 +508,13 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
475 return 0; 508 return 0;
476} 509}
477 510
511static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
512{
513 if (req->cmd_flags & REQ_DISCARD)
514 return mmc_blk_issue_discard_rq(mq, req);
515 else
516 return mmc_blk_issue_rw_rq(mq, req);
517}
478 518
479static inline int mmc_blk_readonly(struct mmc_card *card) 519static inline int mmc_blk_readonly(struct mmc_card *card)
480{ 520{
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index c77eb49eda0e..3b15884e435c 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -30,9 +30,9 @@
30static int mmc_prep_request(struct request_queue *q, struct request *req) 30static int mmc_prep_request(struct request_queue *q, struct request *req)
31{ 31{
32 /* 32 /*
33 * We only like normal block requests. 33 * We only like normal block requests and discards.
34 */ 34 */
35 if (req->cmd_type != REQ_TYPE_FS) { 35 if (req->cmd_type != REQ_TYPE_FS && !(req->cmd_flags & REQ_DISCARD)) {
36 blk_dump_rq_flags(req, "MMC bad request"); 36 blk_dump_rq_flags(req, "MMC bad request");
37 return BLKPREP_KILL; 37 return BLKPREP_KILL;
38 } 38 }
@@ -130,6 +130,18 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
130 blk_queue_prep_rq(mq->queue, mmc_prep_request); 130 blk_queue_prep_rq(mq->queue, mmc_prep_request);
131 blk_queue_ordered(mq->queue, QUEUE_ORDERED_DRAIN); 131 blk_queue_ordered(mq->queue, QUEUE_ORDERED_DRAIN);
132 queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue); 132 queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue);
133 if (mmc_can_erase(card)) {
134 queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, mq->queue);
135 mq->queue->limits.max_discard_sectors = UINT_MAX;
136 if (card->erased_byte == 0)
137 mq->queue->limits.discard_zeroes_data = 1;
138 if (!mmc_can_trim(card) && is_power_of_2(card->erase_size)) {
139 mq->queue->limits.discard_granularity =
140 card->erase_size << 9;
141 mq->queue->limits.discard_alignment =
142 card->erase_size << 9;
143 }
144 }
133 145
134#ifdef CONFIG_MMC_BLOCK_BOUNCE 146#ifdef CONFIG_MMC_BLOCK_BOUNCE
135 if (host->max_hw_segs == 1) { 147 if (host->max_hw_segs == 1) {