diff options
Diffstat (limited to 'drivers/mmc/mmc_queue.c')
-rw-r--r-- | drivers/mmc/mmc_queue.c | 63 |
1 files changed, 36 insertions, 27 deletions
diff --git a/drivers/mmc/mmc_queue.c b/drivers/mmc/mmc_queue.c index 61a1de85cb23..a17423a4ed8f 100644 --- a/drivers/mmc/mmc_queue.c +++ b/drivers/mmc/mmc_queue.c | |||
@@ -10,13 +10,13 @@ | |||
10 | */ | 10 | */ |
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/blkdev.h> | 12 | #include <linux/blkdev.h> |
13 | #include <linux/kthread.h> | ||
13 | 14 | ||
14 | #include <linux/mmc/card.h> | 15 | #include <linux/mmc/card.h> |
15 | #include <linux/mmc/host.h> | 16 | #include <linux/mmc/host.h> |
16 | #include "mmc_queue.h" | 17 | #include "mmc_queue.h" |
17 | 18 | ||
18 | #define MMC_QUEUE_EXIT (1 << 0) | 19 | #define MMC_QUEUE_SUSPENDED (1 << 0) |
19 | #define MMC_QUEUE_SUSPENDED (1 << 1) | ||
20 | 20 | ||
21 | /* | 21 | /* |
22 | * Prepare a MMC request. Essentially, this means passing the | 22 | * Prepare a MMC request. Essentially, this means passing the |
@@ -59,7 +59,6 @@ static int mmc_queue_thread(void *d) | |||
59 | { | 59 | { |
60 | struct mmc_queue *mq = d; | 60 | struct mmc_queue *mq = d; |
61 | struct request_queue *q = mq->queue; | 61 | struct request_queue *q = mq->queue; |
62 | DECLARE_WAITQUEUE(wait, current); | ||
63 | 62 | ||
64 | /* | 63 | /* |
65 | * Set iothread to ensure that we aren't put to sleep by | 64 | * Set iothread to ensure that we aren't put to sleep by |
@@ -67,12 +66,7 @@ static int mmc_queue_thread(void *d) | |||
67 | */ | 66 | */ |
68 | current->flags |= PF_MEMALLOC|PF_NOFREEZE; | 67 | current->flags |= PF_MEMALLOC|PF_NOFREEZE; |
69 | 68 | ||
70 | daemonize("mmcqd"); | ||
71 | |||
72 | complete(&mq->thread_complete); | ||
73 | |||
74 | down(&mq->thread_sem); | 69 | down(&mq->thread_sem); |
75 | add_wait_queue(&mq->thread_wq, &wait); | ||
76 | do { | 70 | do { |
77 | struct request *req = NULL; | 71 | struct request *req = NULL; |
78 | 72 | ||
@@ -84,7 +78,7 @@ static int mmc_queue_thread(void *d) | |||
84 | spin_unlock_irq(q->queue_lock); | 78 | spin_unlock_irq(q->queue_lock); |
85 | 79 | ||
86 | if (!req) { | 80 | if (!req) { |
87 | if (mq->flags & MMC_QUEUE_EXIT) | 81 | if (kthread_should_stop()) |
88 | break; | 82 | break; |
89 | up(&mq->thread_sem); | 83 | up(&mq->thread_sem); |
90 | schedule(); | 84 | schedule(); |
@@ -95,10 +89,8 @@ static int mmc_queue_thread(void *d) | |||
95 | 89 | ||
96 | mq->issue_fn(mq, req); | 90 | mq->issue_fn(mq, req); |
97 | } while (1); | 91 | } while (1); |
98 | remove_wait_queue(&mq->thread_wq, &wait); | ||
99 | up(&mq->thread_sem); | 92 | up(&mq->thread_sem); |
100 | 93 | ||
101 | complete_and_exit(&mq->thread_complete, 0); | ||
102 | return 0; | 94 | return 0; |
103 | } | 95 | } |
104 | 96 | ||
@@ -111,9 +103,22 @@ static int mmc_queue_thread(void *d) | |||
111 | static void mmc_request(request_queue_t *q) | 103 | static void mmc_request(request_queue_t *q) |
112 | { | 104 | { |
113 | struct mmc_queue *mq = q->queuedata; | 105 | struct mmc_queue *mq = q->queuedata; |
106 | struct request *req; | ||
107 | int ret; | ||
108 | |||
109 | if (!mq) { | ||
110 | printk(KERN_ERR "MMC: killing requests for dead queue\n"); | ||
111 | while ((req = elv_next_request(q)) != NULL) { | ||
112 | do { | ||
113 | ret = end_that_request_chunk(req, 0, | ||
114 | req->current_nr_sectors << 9); | ||
115 | } while (ret); | ||
116 | } | ||
117 | return; | ||
118 | } | ||
114 | 119 | ||
115 | if (!mq->req) | 120 | if (!mq->req) |
116 | wake_up(&mq->thread_wq); | 121 | wake_up_process(mq->thread); |
117 | } | 122 | } |
118 | 123 | ||
119 | /** | 124 | /** |
@@ -152,36 +157,40 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock | |||
152 | GFP_KERNEL); | 157 | GFP_KERNEL); |
153 | if (!mq->sg) { | 158 | if (!mq->sg) { |
154 | ret = -ENOMEM; | 159 | ret = -ENOMEM; |
155 | goto cleanup; | 160 | goto cleanup_queue; |
156 | } | 161 | } |
157 | 162 | ||
158 | init_completion(&mq->thread_complete); | ||
159 | init_waitqueue_head(&mq->thread_wq); | ||
160 | init_MUTEX(&mq->thread_sem); | 163 | init_MUTEX(&mq->thread_sem); |
161 | 164 | ||
162 | ret = kernel_thread(mmc_queue_thread, mq, CLONE_KERNEL); | 165 | mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd"); |
163 | if (ret >= 0) { | 166 | if (IS_ERR(mq->thread)) { |
164 | wait_for_completion(&mq->thread_complete); | 167 | ret = PTR_ERR(mq->thread); |
165 | init_completion(&mq->thread_complete); | 168 | goto free_sg; |
166 | ret = 0; | ||
167 | goto out; | ||
168 | } | 169 | } |
169 | 170 | ||
170 | cleanup: | 171 | return 0; |
172 | |||
173 | free_sg: | ||
171 | kfree(mq->sg); | 174 | kfree(mq->sg); |
172 | mq->sg = NULL; | 175 | mq->sg = NULL; |
173 | 176 | cleanup_queue: | |
174 | blk_cleanup_queue(mq->queue); | 177 | blk_cleanup_queue(mq->queue); |
175 | out: | ||
176 | return ret; | 178 | return ret; |
177 | } | 179 | } |
178 | EXPORT_SYMBOL(mmc_init_queue); | 180 | EXPORT_SYMBOL(mmc_init_queue); |
179 | 181 | ||
180 | void mmc_cleanup_queue(struct mmc_queue *mq) | 182 | void mmc_cleanup_queue(struct mmc_queue *mq) |
181 | { | 183 | { |
182 | mq->flags |= MMC_QUEUE_EXIT; | 184 | request_queue_t *q = mq->queue; |
183 | wake_up(&mq->thread_wq); | 185 | unsigned long flags; |
184 | wait_for_completion(&mq->thread_complete); | 186 | |
187 | /* Mark that we should start throwing out stragglers */ | ||
188 | spin_lock_irqsave(q->queue_lock, flags); | ||
189 | q->queuedata = NULL; | ||
190 | spin_unlock_irqrestore(q->queue_lock, flags); | ||
191 | |||
192 | /* Then terminate our worker thread */ | ||
193 | kthread_stop(mq->thread); | ||
185 | 194 | ||
186 | kfree(mq->sg); | 195 | kfree(mq->sg); |
187 | mq->sg = NULL; | 196 | mq->sg = NULL; |