Commit 0f602ec7 authored by Jarkko Lavinen's avatar Jarkko Lavinen Committed by Pierre Ossman

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: default avatarJarkko Lavinen <jarkko.lavinen@nokia.com>
Signed-off-by: default avatarPierre Ossman <drzeus@drzeus.cx>
parent 0807a9b5
...@@ -138,6 +138,11 @@ struct mmc_omap_host { ...@@ -138,6 +138,11 @@ struct mmc_omap_host {
unsigned abort:1; unsigned abort:1;
struct timer_list cmd_abort_timer; struct timer_list cmd_abort_timer;
struct work_struct slot_release_work;
struct mmc_omap_slot *next_slot;
struct work_struct send_stop_work;
struct mmc_data *stop_data;
unsigned int sg_len; unsigned int sg_len;
int sg_idx; int sg_idx;
u16 * buffer; u16 * buffer;
...@@ -236,6 +241,21 @@ static void mmc_omap_select_slot(struct mmc_omap_slot *slot, int claimed) ...@@ -236,6 +241,21 @@ static void mmc_omap_select_slot(struct mmc_omap_slot *slot, int claimed)
static void mmc_omap_start_request(struct mmc_omap_host *host, static void mmc_omap_start_request(struct mmc_omap_host *host,
struct mmc_request *req); struct mmc_request *req);
static void mmc_omap_slot_release_work(struct work_struct *work)
{
struct mmc_omap_host *host = container_of(work, struct mmc_omap_host,
slot_release_work);
struct mmc_omap_slot *next_slot = host->next_slot;
struct mmc_request *rq;
host->next_slot = NULL;
mmc_omap_select_slot(next_slot, 1);
rq = next_slot->mrq;
next_slot->mrq = NULL;
mmc_omap_start_request(host, rq);
}
static void mmc_omap_release_slot(struct mmc_omap_slot *slot, int clk_enabled) static void mmc_omap_release_slot(struct mmc_omap_slot *slot, int clk_enabled)
{ {
struct mmc_omap_host *host = slot->host; 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,21 +277,19 @@ static void mmc_omap_release_slot(struct mmc_omap_slot *slot, int clk_enabled)
/* Check for any pending requests */ /* Check for any pending requests */
for (i = 0; i < host->nr_slots; i++) { for (i = 0; i < host->nr_slots; i++) {
struct mmc_omap_slot *new_slot; struct mmc_omap_slot *new_slot;
struct mmc_request *rq;
if (host->slots[i] == NULL || host->slots[i]->mrq == NULL) if (host->slots[i] == NULL || host->slots[i]->mrq == NULL)
continue; continue;
BUG_ON(host->next_slot != NULL);
new_slot = host->slots[i]; new_slot = host->slots[i];
/* The current slot should not have a request in queue */ /* The current slot should not have a request in queue */
BUG_ON(new_slot == host->current_slot); BUG_ON(new_slot == host->current_slot);
host->next_slot = new_slot;
host->mmc = new_slot->mmc; host->mmc = new_slot->mmc;
spin_unlock_irqrestore(&host->slot_lock, flags); spin_unlock_irqrestore(&host->slot_lock, flags);
mmc_omap_select_slot(new_slot, 1); schedule_work(&host->slot_release_work);
rq = new_slot->mrq;
new_slot->mrq = NULL;
mmc_omap_start_request(host, rq);
return; return;
} }
...@@ -400,6 +418,20 @@ mmc_omap_release_dma(struct mmc_omap_host *host, struct mmc_data *data, ...@@ -400,6 +418,20 @@ mmc_omap_release_dma(struct mmc_omap_host *host, struct mmc_data *data,
dma_data_dir); dma_data_dir);
} }
static void mmc_omap_send_stop_work(struct work_struct *work)
{
struct mmc_omap_host *host = container_of(work, struct mmc_omap_host,
send_stop_work);
struct mmc_omap_slot *slot = host->current_slot;
struct mmc_data *data = host->stop_data;
unsigned long tick_ns;
tick_ns = (1000000000 + slot->fclk_freq - 1)/slot->fclk_freq;
ndelay(8*tick_ns);
mmc_omap_start_command(host, data->stop);
}
static void static void
mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data) mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data)
{ {
...@@ -424,7 +456,8 @@ mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data) ...@@ -424,7 +456,8 @@ mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data)
return; return;
} }
mmc_omap_start_command(host, data->stop); host->stop_data = data;
schedule_work(&host->send_stop_work);
} }
static void static void
...@@ -1389,6 +1422,9 @@ static int __init mmc_omap_probe(struct platform_device *pdev) ...@@ -1389,6 +1422,9 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
goto err_free_mem_region; goto err_free_mem_region;
} }
INIT_WORK(&host->slot_release_work, mmc_omap_slot_release_work);
INIT_WORK(&host->send_stop_work, mmc_omap_send_stop_work);
INIT_WORK(&host->cmd_abort_work, mmc_omap_abort_command); INIT_WORK(&host->cmd_abort_work, mmc_omap_abort_command);
setup_timer(&host->cmd_abort_timer, mmc_omap_cmd_timer, setup_timer(&host->cmd_abort_timer, mmc_omap_cmd_timer,
(unsigned long) host); (unsigned long) host);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment