aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/host/omap.c
diff options
context:
space:
mode:
authorJarkko Lavinen <jarkko.lavinen@nokia.com>2008-03-26 16:09:58 -0400
committerPierre Ossman <drzeus@drzeus.cx>2008-04-18 14:05:31 -0400
commit0f602ec79ac4fd2a42075c5a170086ded439f36d (patch)
treebaeade53563c97d687aa3c5f214c13f682c186d4 /drivers/mmc/host/omap.c
parent0807a9b5739a73ba0d0fcd9f36a51794757be881 (diff)
MMC: OMAP: Start new commands from work queue instead of irq
Use work queues for starting new commands instead of starting them directly from irq handler. The command scheduling needs to be delayed a bit for some cards which should not be done from an interrupt. Signed-off-by: Jarkko Lavinen <jarkko.lavinen@nokia.com> Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
Diffstat (limited to 'drivers/mmc/host/omap.c')
-rw-r--r--drivers/mmc/host/omap.c48
1 files changed, 42 insertions, 6 deletions
diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c
index 3d59c5d81b3d..ab0974d261e5 100644
--- a/drivers/mmc/host/omap.c
+++ b/drivers/mmc/host/omap.c
@@ -138,6 +138,11 @@ struct mmc_omap_host {
138 unsigned abort:1; 138 unsigned abort:1;
139 struct timer_list cmd_abort_timer; 139 struct timer_list cmd_abort_timer;
140 140
141 struct work_struct slot_release_work;
142 struct mmc_omap_slot *next_slot;
143 struct work_struct send_stop_work;
144 struct mmc_data *stop_data;
145
141 unsigned int sg_len; 146 unsigned int sg_len;
142 int sg_idx; 147 int sg_idx;
143 u16 * buffer; 148 u16 * buffer;
@@ -236,6 +241,21 @@ no_claim:
236static void mmc_omap_start_request(struct mmc_omap_host *host, 241static void mmc_omap_start_request(struct mmc_omap_host *host,
237 struct mmc_request *req); 242 struct mmc_request *req);
238 243
244static void mmc_omap_slot_release_work(struct work_struct *work)
245{
246 struct mmc_omap_host *host = container_of(work, struct mmc_omap_host,
247 slot_release_work);
248 struct mmc_omap_slot *next_slot = host->next_slot;
249 struct mmc_request *rq;
250
251 host->next_slot = NULL;
252 mmc_omap_select_slot(next_slot, 1);
253
254 rq = next_slot->mrq;
255 next_slot->mrq = NULL;
256 mmc_omap_start_request(host, rq);
257}
258
239static void mmc_omap_release_slot(struct mmc_omap_slot *slot, int clk_enabled) 259static void mmc_omap_release_slot(struct mmc_omap_slot *slot, int clk_enabled)
240{ 260{
241 struct mmc_omap_host *host = slot->host; 261 struct mmc_omap_host *host = slot->host;
@@ -257,21 +277,19 @@ static void mmc_omap_release_slot(struct mmc_omap_slot *slot, int clk_enabled)
257 /* Check for any pending requests */ 277 /* Check for any pending requests */
258 for (i = 0; i < host->nr_slots; i++) { 278 for (i = 0; i < host->nr_slots; i++) {
259 struct mmc_omap_slot *new_slot; 279 struct mmc_omap_slot *new_slot;
260 struct mmc_request *rq;
261 280
262 if (host->slots[i] == NULL || host->slots[i]->mrq == NULL) 281 if (host->slots[i] == NULL || host->slots[i]->mrq == NULL)
263 continue; 282 continue;
264 283
284 BUG_ON(host->next_slot != NULL);
265 new_slot = host->slots[i]; 285 new_slot = host->slots[i];
266 /* The current slot should not have a request in queue */ 286 /* The current slot should not have a request in queue */
267 BUG_ON(new_slot == host->current_slot); 287 BUG_ON(new_slot == host->current_slot);
268 288
289 host->next_slot = new_slot;
269 host->mmc = new_slot->mmc; 290 host->mmc = new_slot->mmc;
270 spin_unlock_irqrestore(&host->slot_lock, flags); 291 spin_unlock_irqrestore(&host->slot_lock, flags);
271 mmc_omap_select_slot(new_slot, 1); 292 schedule_work(&host->slot_release_work);
272 rq = new_slot->mrq;
273 new_slot->mrq = NULL;
274 mmc_omap_start_request(host, rq);
275 return; 293 return;
276 } 294 }
277 295
@@ -400,6 +418,20 @@ mmc_omap_release_dma(struct mmc_omap_host *host, struct mmc_data *data,
400 dma_data_dir); 418 dma_data_dir);
401} 419}
402 420
421static void mmc_omap_send_stop_work(struct work_struct *work)
422{
423 struct mmc_omap_host *host = container_of(work, struct mmc_omap_host,
424 send_stop_work);
425 struct mmc_omap_slot *slot = host->current_slot;
426 struct mmc_data *data = host->stop_data;
427 unsigned long tick_ns;
428
429 tick_ns = (1000000000 + slot->fclk_freq - 1)/slot->fclk_freq;
430 ndelay(8*tick_ns);
431
432 mmc_omap_start_command(host, data->stop);
433}
434
403static void 435static void
404mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data) 436mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data)
405{ 437{
@@ -424,7 +456,8 @@ mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data)
424 return; 456 return;
425 } 457 }
426 458
427 mmc_omap_start_command(host, data->stop); 459 host->stop_data = data;
460 schedule_work(&host->send_stop_work);
428} 461}
429 462
430static void 463static void
@@ -1389,6 +1422,9 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
1389 goto err_free_mem_region; 1422 goto err_free_mem_region;
1390 } 1423 }
1391 1424
1425 INIT_WORK(&host->slot_release_work, mmc_omap_slot_release_work);
1426 INIT_WORK(&host->send_stop_work, mmc_omap_send_stop_work);
1427
1392 INIT_WORK(&host->cmd_abort_work, mmc_omap_abort_command); 1428 INIT_WORK(&host->cmd_abort_work, mmc_omap_abort_command);
1393 setup_timer(&host->cmd_abort_timer, mmc_omap_cmd_timer, 1429 setup_timer(&host->cmd_abort_timer, mmc_omap_cmd_timer,
1394 (unsigned long) host); 1430 (unsigned long) host);