Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 91782
b: refs/heads/master
c: eb1860b
h: refs/heads/master
v: v3
  • Loading branch information
Jarkko Lavinen authored and Pierre Ossman committed Apr 18, 2008
1 parent 88f35ab commit a556a29
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 11 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 2a50b8889b707b9c7bcd09c0ae4cbcef7dca4e29
refs/heads/master: eb1860bccd01a75b20fd7298af89b9cbda2202ba
93 changes: 83 additions & 10 deletions trunk/drivers/mmc/host/omap.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,9 @@ struct mmc_omap_host {
unsigned char bus_mode;
unsigned char hw_bus_mode;

struct work_struct cmd_abort;
struct timer_list cmd_timer;

unsigned int sg_len;
int sg_idx;
u16 * buffer;
Expand Down Expand Up @@ -314,6 +317,8 @@ mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd)
if (host->data && !(host->data->flags & MMC_DATA_WRITE))
cmdreg |= 1 << 15;

mod_timer(&host->cmd_timer, jiffies + HZ/2);

OMAP_MMC_WRITE(host, CTO, 200);
OMAP_MMC_WRITE(host, ARGL, cmd->arg & 0xffff);
OMAP_MMC_WRITE(host, ARGH, cmd->arg >> 16);
Expand Down Expand Up @@ -372,10 +377,38 @@ mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data)
mmc_omap_start_command(host, data->stop);
}

static void
mmc_omap_send_abort(struct mmc_omap_host *host)
{
struct mmc_omap_slot *slot = host->current_slot;
unsigned int restarts, passes, timeout;
u16 stat = 0;

/* Sending abort takes 80 clocks. Have some extra and round up */
timeout = (120*1000000 + slot->fclk_freq - 1)/slot->fclk_freq;
restarts = 0;
while (restarts < 10000) {
OMAP_MMC_WRITE(host, STAT, 0xFFFF);
OMAP_MMC_WRITE(host, CMD, (3 << 12) | (1 << 7));

passes = 0;
while (passes < timeout) {
stat = OMAP_MMC_READ(host, STAT);
if (stat & OMAP_MMC_STAT_END_OF_CMD)
goto out;
udelay(1);
passes++;
}

restarts++;
}
out:
OMAP_MMC_WRITE(host, STAT, stat);
}

static void
mmc_omap_abort_xfer(struct mmc_omap_host *host, struct mmc_data *data)
{
int loops;
u16 ie;

if (host->dma_in_use)
Expand All @@ -386,16 +419,8 @@ mmc_omap_abort_xfer(struct mmc_omap_host *host, struct mmc_data *data)

ie = OMAP_MMC_READ(host, IE);
OMAP_MMC_WRITE(host, IE, 0);
OMAP_MMC_WRITE(host, CMD, 1 << 7);
loops = 0;
while (!(OMAP_MMC_READ(host, STAT) & OMAP_MMC_STAT_END_OF_CMD)) {
udelay(1);
loops++;
if (loops == 100000)
break;
}
OMAP_MMC_WRITE(host, STAT, OMAP_MMC_STAT_END_OF_CMD);
OMAP_MMC_WRITE(host, IE, ie);
mmc_omap_send_abort(host);
}

static void
Expand Down Expand Up @@ -451,6 +476,8 @@ mmc_omap_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd)
{
host->cmd = NULL;

del_timer(&host->cmd_timer);

if (cmd->flags & MMC_RSP_PRESENT) {
if (cmd->flags & MMC_RSP_136) {
/* response type 2 */
Expand Down Expand Up @@ -486,6 +513,47 @@ mmc_omap_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd)
}
}

/*
* Abort stuck command. Can occur when card is removed while it is being
* read.
*/
static void mmc_omap_abort_command(struct work_struct *work)
{
struct mmc_omap_host *host = container_of(work, struct mmc_omap_host,
cmd_abort);
u16 ie;

ie = OMAP_MMC_READ(host, IE);
OMAP_MMC_WRITE(host, IE, 0);

if (!host->cmd) {
OMAP_MMC_WRITE(host, IE, ie);
return;
}

dev_dbg(mmc_dev(host->mmc), "Aborting stuck command CMD%d\n",
host->cmd->opcode);

if (host->data && host->dma_in_use)
mmc_omap_release_dma(host, host->data, 1);

host->data = NULL;
host->sg_len = 0;

mmc_omap_send_abort(host);
host->cmd->error = -ETIMEDOUT;
mmc_omap_cmd_done(host, host->cmd);
OMAP_MMC_WRITE(host, IE, ie);
}

static void
mmc_omap_cmd_timer(unsigned long data)
{
struct mmc_omap_host *host = (struct mmc_omap_host *) data;

schedule_work(&host->cmd_abort);
}

/* PIO only */
static void
mmc_omap_sg_to_buf(struct mmc_omap_host *host)
Expand Down Expand Up @@ -1233,6 +1301,11 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
goto err_free_mem_region;
}

INIT_WORK(&host->cmd_abort, mmc_omap_abort_command);
init_timer(&host->cmd_timer);
host->cmd_timer.function = mmc_omap_cmd_timer;
host->cmd_timer.data = (unsigned long) host;

spin_lock_init(&host->dma_lock);
init_timer(&host->dma_timer);
spin_lock_init(&host->slot_lock);
Expand Down

0 comments on commit a556a29

Please sign in to comment.