]> bbs.cooldavid.org Git - net-next-2.6.git/blame - drivers/mmc/mmc_queue.c
Linux 2.6.19
[net-next-2.6.git] / drivers / mmc / mmc_queue.c
CommitLineData
1da177e4
LT
1/*
2 * linux/drivers/mmc/mmc_queue.c
3 *
4 * Copyright (C) 2003 Russell King, All Rights Reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 */
11#include <linux/module.h>
12#include <linux/blkdev.h>
13
14#include <linux/mmc/card.h>
15#include <linux/mmc/host.h>
16#include "mmc_queue.h"
17
18#define MMC_QUEUE_EXIT (1 << 0)
19#define MMC_QUEUE_SUSPENDED (1 << 1)
20
21/*
22 * Prepare a MMC request. Essentially, this means passing the
23 * preparation off to the media driver. The media driver will
24 * create a mmc_io_request in req->special.
25 */
26static int mmc_prep_request(struct request_queue *q, struct request *req)
27{
28 struct mmc_queue *mq = q->queuedata;
29 int ret = BLKPREP_KILL;
30
4aff5e23 31 if (blk_special_request(req)) {
1da177e4
LT
32 /*
33 * Special commands already have the command
34 * blocks already setup in req->special.
35 */
36 BUG_ON(!req->special);
37
38 ret = BLKPREP_OK;
4aff5e23 39 } else if (blk_fs_request(req) || blk_pc_request(req)) {
1da177e4
LT
40 /*
41 * Block I/O requests need translating according
42 * to the protocol.
43 */
44 ret = mq->prep_fn(mq, req);
45 } else {
46 /*
47 * Everything else is invalid.
48 */
49 blk_dump_rq_flags(req, "MMC bad request");
50 }
51
52 if (ret == BLKPREP_OK)
4aff5e23 53 req->cmd_flags |= REQ_DONTPREP;
1da177e4
LT
54
55 return ret;
56}
57
58static int mmc_queue_thread(void *d)
59{
60 struct mmc_queue *mq = d;
61 struct request_queue *q = mq->queue;
62 DECLARE_WAITQUEUE(wait, current);
63
64 /*
65 * Set iothread to ensure that we aren't put to sleep by
66 * the process freezing. We handle suspension ourselves.
67 */
68 current->flags |= PF_MEMALLOC|PF_NOFREEZE;
69
70 daemonize("mmcqd");
71
72 complete(&mq->thread_complete);
73
74 down(&mq->thread_sem);
75 add_wait_queue(&mq->thread_wq, &wait);
76 do {
77 struct request *req = NULL;
78
79 spin_lock_irq(q->queue_lock);
80 set_current_state(TASK_INTERRUPTIBLE);
81 if (!blk_queue_plugged(q))
c723e08a
JY
82 req = elv_next_request(q);
83 mq->req = req;
1da177e4
LT
84 spin_unlock_irq(q->queue_lock);
85
86 if (!req) {
87 if (mq->flags & MMC_QUEUE_EXIT)
88 break;
89 up(&mq->thread_sem);
90 schedule();
91 down(&mq->thread_sem);
92 continue;
93 }
94 set_current_state(TASK_RUNNING);
95
96 mq->issue_fn(mq, req);
97 } while (1);
98 remove_wait_queue(&mq->thread_wq, &wait);
99 up(&mq->thread_sem);
100
101 complete_and_exit(&mq->thread_complete, 0);
102 return 0;
103}
104
105/*
106 * Generic MMC request handler. This is called for any queue on a
107 * particular host. When the host is not busy, we look for a request
108 * on any queue on this host, and attempt to issue it. This may
109 * not be the queue we were asked to process.
110 */
111static void mmc_request(request_queue_t *q)
112{
113 struct mmc_queue *mq = q->queuedata;
114
115 if (!mq->req)
116 wake_up(&mq->thread_wq);
117}
118
119/**
120 * mmc_init_queue - initialise a queue structure.
121 * @mq: mmc queue
122 * @card: mmc card to attach this queue
123 * @lock: queue lock
124 *
125 * Initialise a MMC card request queue.
126 */
127int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock)
128{
129 struct mmc_host *host = card->host;
130 u64 limit = BLK_BOUNCE_HIGH;
131 int ret;
132
133 if (host->dev->dma_mask && *host->dev->dma_mask)
134 limit = *host->dev->dma_mask;
135
136 mq->card = card;
137 mq->queue = blk_init_queue(mmc_request, lock);
138 if (!mq->queue)
139 return -ENOMEM;
140
141 blk_queue_prep_rq(mq->queue, mmc_prep_request);
142 blk_queue_bounce_limit(mq->queue, limit);
143 blk_queue_max_sectors(mq->queue, host->max_sectors);
144 blk_queue_max_phys_segments(mq->queue, host->max_phys_segs);
145 blk_queue_max_hw_segments(mq->queue, host->max_hw_segs);
146 blk_queue_max_segment_size(mq->queue, host->max_seg_size);
147
148 mq->queue->queuedata = mq;
149 mq->req = NULL;
150
151 mq->sg = kmalloc(sizeof(struct scatterlist) * host->max_phys_segs,
152 GFP_KERNEL);
153 if (!mq->sg) {
154 ret = -ENOMEM;
155 goto cleanup;
156 }
157
158 init_completion(&mq->thread_complete);
159 init_waitqueue_head(&mq->thread_wq);
160 init_MUTEX(&mq->thread_sem);
161
162 ret = kernel_thread(mmc_queue_thread, mq, CLONE_KERNEL);
163 if (ret >= 0) {
164 wait_for_completion(&mq->thread_complete);
165 init_completion(&mq->thread_complete);
166 ret = 0;
167 goto out;
168 }
169
170 cleanup:
171 kfree(mq->sg);
172 mq->sg = NULL;
173
174 blk_cleanup_queue(mq->queue);
175 out:
176 return ret;
177}
178EXPORT_SYMBOL(mmc_init_queue);
179
180void mmc_cleanup_queue(struct mmc_queue *mq)
181{
182 mq->flags |= MMC_QUEUE_EXIT;
183 wake_up(&mq->thread_wq);
184 wait_for_completion(&mq->thread_complete);
185
186 kfree(mq->sg);
187 mq->sg = NULL;
188
189 blk_cleanup_queue(mq->queue);
190
191 mq->card = NULL;
192}
193EXPORT_SYMBOL(mmc_cleanup_queue);
194
195/**
196 * mmc_queue_suspend - suspend a MMC request queue
197 * @mq: MMC queue to suspend
198 *
199 * Stop the block request queue, and wait for our thread to
200 * complete any outstanding requests. This ensures that we
201 * won't suspend while a request is being processed.
202 */
203void mmc_queue_suspend(struct mmc_queue *mq)
204{
205 request_queue_t *q = mq->queue;
206 unsigned long flags;
207
208 if (!(mq->flags & MMC_QUEUE_SUSPENDED)) {
209 mq->flags |= MMC_QUEUE_SUSPENDED;
210
211 spin_lock_irqsave(q->queue_lock, flags);
212 blk_stop_queue(q);
213 spin_unlock_irqrestore(q->queue_lock, flags);
214
215 down(&mq->thread_sem);
216 }
217}
218EXPORT_SYMBOL(mmc_queue_suspend);
219
220/**
221 * mmc_queue_resume - resume a previously suspended MMC request queue
222 * @mq: MMC queue to resume
223 */
224void mmc_queue_resume(struct mmc_queue *mq)
225{
226 request_queue_t *q = mq->queue;
227 unsigned long flags;
228
229 if (mq->flags & MMC_QUEUE_SUSPENDED) {
230 mq->flags &= ~MMC_QUEUE_SUSPENDED;
231
232 up(&mq->thread_sem);
233
234 spin_lock_irqsave(q->queue_lock, flags);
235 blk_start_queue(q);
236 spin_unlock_irqrestore(q->queue_lock, flags);
237 }
238}
239EXPORT_SYMBOL(mmc_queue_resume);