Date:2010-07-04 03:19:37 (13 years 8 months ago)
Author:Lars C.
Commit:59a98c35190fb9bbdb00eec048b04600d9e3e124
Message:MMC: jz4740: Don't spin to long waiting for an irq

If we spin too long while waiting for an irq, we'll enable the interrupt and put
the spinning thread to sleep and wake it up again from the irq handler.
This reduces busy-looping time while keeping performance up.
Files: drivers/mmc/host/jz4740_mmc.c (10 diffs)

Change Details

drivers/mmc/host/jz4740_mmc.c
2424#include <linux/clk.h>
2525#include <linux/mmc/jz4740_mmc.h>
2626
27#include <linux/completion.h>
28
2729#include <linux/bitops.h>
2830#include <linux/gpio.h>
2931#include <asm/mach-jz4740/gpio.h>
...... 
103105
104106#define JZ_MMC_CLK_RATE 24000000
105107
106#define JZ4740_MMC_MAX_TIMEOUT 10000000
107
108108struct jz4740_mmc_host {
109109    struct mmc_host *mmc;
110110    struct platform_device *pdev;
...... 
129129    spinlock_t lock;
130130
131131    struct timer_list timeout_timer;
132    struct completion completion;
132133};
133134
134135static void jz4740_mmc_set_irq_enabled(struct jz4740_mmc_host *host,
...... 
187188
188189    mmc_request_done(host->mmc, req);
189190}
190
191static inline unsigned int jz4740_mmc_wait_irq(struct jz4740_mmc_host *host,
191static unsigned int jz4740_mmc_wait_irq(struct jz4740_mmc_host *host,
192192    unsigned int irq)
193193{
194    unsigned int timeout = JZ4740_MMC_MAX_TIMEOUT;
194    unsigned int timeout = 1000;
195195    uint16_t status;
196196
197197    do {
198198        status = readw(host->base + JZ_REG_MMC_IREG);
199199    } while (!(status & irq) && --timeout);
200200
201    if (timeout == 0) {
202        INIT_COMPLETION(host->completion);
203        jz4740_mmc_set_irq_enabled(host, irq, true);
204        timeout = wait_for_completion_timeout(&host->completion, HZ);
205    }
206
201207    return timeout;
202208}
203209
...... 
263269        return;
264270    }
265271
266    timeout = JZ4740_MMC_MAX_TIMEOUT;
267    do {
268        status = readl(host->base + JZ_REG_MMC_STATUS);
269    } while ((status & JZ_MMC_STATUS_DATA_TRAN_DONE) == 0 && --timeout);
270
272    timeout = jz4740_mmc_wait_irq(host, JZ_MMC_IRQ_TXFIFO_WR_REQ);
271273    if (unlikely(timeout == 0))
272274        goto err_timeout;
275
273276    writew(JZ_MMC_IRQ_DATA_TRAN_DONE, host->base + JZ_REG_MMC_IREG);
274277
275278    return;
...... 
447450    struct jz4740_mmc_host *host = (struct jz4740_mmc_host *)devid;
448451    struct mmc_command *cmd = host->req->cmd;
449452    struct mmc_request *req = host->req;
450    unsigned int timeout = JZ4740_MMC_MAX_TIMEOUT;
451    uint32_t status;
453    unsigned int timeout;
452454
453455    if (cmd->error)
454456        goto done;
...... 
465467
466468    if (req->stop) {
467469        jz4740_mmc_send_command(host, req->stop);
468        do {
469            status = readw(host->base + JZ_REG_MMC_IREG);
470        } while ((status & JZ_MMC_IRQ_PRG_DONE) == 0 && --timeout);
470
471        timeout = jz4740_mmc_wait_irq(host, JZ_MMC_IRQ_PRG_DONE);
471472        writew(JZ_MMC_IRQ_PRG_DONE, host->base + JZ_REG_MMC_IREG);
473
474        if (unlikely(timeout == 0))
475            req->stop->error = -ETIMEDOUT;
472476    }
473477
474    if (unlikely(timeout == 0))
475        req->stop->error = -ETIMEDOUT;
476478
477479done:
478480    jz4740_mmc_request_done(host);
...... 
492494    irq_reg &= ~host->irq_mask;
493495
494496    tmp &= ~(JZ_MMC_IRQ_TXFIFO_WR_REQ | JZ_MMC_IRQ_RXFIFO_RD_REQ |
495            JZ_MMC_IRQ_PRG_DONE | JZ_MMC_IRQ_DATA_TRAN_DONE);
497        JZ_MMC_IRQ_PRG_DONE | JZ_MMC_IRQ_DATA_TRAN_DONE);
496498
497499    if (tmp != irq_reg)
498500        writew(tmp & ~irq_reg, host->base + JZ_REG_MMC_IREG);
...... 
505507    if (!host->req || !host->cmd)
506508        goto handled;
507509
508    if (!(irq_reg & JZ_MMC_IRQ_END_CMD_RES))
509        goto handled;
510    if (irq_reg & JZ_MMC_IRQ_END_CMD_RES) {
510511
511    if (test_and_clear_bit(0, &host->waiting)) {
512        del_timer(&host->timeout_timer);
513
514        status = readl(host->base + JZ_REG_MMC_STATUS);
515
516        if (status & JZ_MMC_STATUS_TIMEOUT_RES) {
517            host->cmd->error = -ETIMEDOUT;
518        } else if (status & JZ_MMC_STATUS_CRC_RES_ERR) {
519            host->cmd->error = -EIO;
520        } else if (status & (JZ_MMC_STATUS_CRC_READ_ERROR |
521                JZ_MMC_STATUS_CRC_WRITE_ERROR)) {
522            host->cmd->data->error = -EIO;
523        } else if (status & (JZ_MMC_STATUS_CRC_READ_ERROR |
524                JZ_MMC_STATUS_CRC_WRITE_ERROR)) {
525            host->cmd->data->error = -EIO;
512        if (test_and_clear_bit(0, &host->waiting)) {
513            del_timer(&host->timeout_timer);
514
515            status = readl(host->base + JZ_REG_MMC_STATUS);
516
517            if (status & JZ_MMC_STATUS_TIMEOUT_RES) {
518                host->cmd->error = -ETIMEDOUT;
519            } else if (status & JZ_MMC_STATUS_CRC_RES_ERR) {
520                host->cmd->error = -EIO;
521            } else if (status & (JZ_MMC_STATUS_CRC_READ_ERROR |
522                    JZ_MMC_STATUS_CRC_WRITE_ERROR)) {
523                host->cmd->data->error = -EIO;
524            } else if (status & (JZ_MMC_STATUS_CRC_READ_ERROR |
525                    JZ_MMC_STATUS_CRC_WRITE_ERROR)) {
526                host->cmd->data->error = -EIO;
527            }
528
529            ret = IRQ_WAKE_THREAD;
526530        }
527531
528        ret = IRQ_WAKE_THREAD;
532        jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_END_CMD_RES, false);
533        writew(JZ_MMC_IRQ_END_CMD_RES, host->base + JZ_REG_MMC_IREG);
534    } else {
535        complete(&host->completion);
536        jz4740_mmc_set_irq_enabled(host, irq_reg, false);
537        writew(irq_reg, host->base + JZ_REG_MMC_IREG);
529538    }
530539
531    jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_END_CMD_RES, false);
532    writew(JZ_MMC_IRQ_END_CMD_RES, host->base + JZ_REG_MMC_IREG);
533
534540handled:
535541    return ret;
536542}
...... 
842848    jz4740_mmc_clock_disable(host);
843849    setup_timer(&host->timeout_timer, jz4740_mmc_timeout,
844850            (unsigned long)host);
851    init_completion(&host->completion);
845852
846853    platform_set_drvdata(pdev, host);
847854    ret = mmc_add_host(mmc);

Archive Download the corresponding diff file



interactive