Date:2010-07-12 22:49:53 (13 years 8 months ago)
Author:Lars C.
Commit:ef5286907666baca5edc4f8c243db32a6691d9bb
Message:MMC: jz4740: Rework state handling

Instead of sleeping inside the threaded irq handler there is now a state
variable which determines in which action has to be executed next after an irq.
Files: drivers/mmc/host/jz4740_mmc.c (16 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
2927#include <linux/bitops.h>
3028#include <linux/gpio.h>
3129#include <asm/mach-jz4740/gpio.h>
...... 
105103
106104#define JZ_MMC_CLK_RATE 24000000
107105
106enum jz4740_mmc_state {
107    JZ4740_MMC_STATE_READ_RESPONSE,
108    JZ4740_MMC_STATE_TRANSFER_DATA,
109    JZ4740_MMC_STATE_SEND_STOP,
110    JZ4740_MMC_STATE_DONE,
111};
112
108113struct jz4740_mmc_host {
109114    struct mmc_host *mmc;
110115    struct platform_device *pdev;
...... 
129134    spinlock_t lock;
130135
131136    struct timer_list timeout_timer;
132    struct completion completion;
137    struct sg_mapping_iter miter;
138    enum jz4740_mmc_state state;
133139};
134140
135141static void jz4740_mmc_set_irq_enabled(struct jz4740_mmc_host *host,
...... 
161167static void jz4740_mmc_clock_disable(struct jz4740_mmc_host *host)
162168{
163169    uint32_t status;
170    unsigned int timeout = 1000;
164171
165172    writew(JZ_MMC_STRPCL_CLOCK_STOP, host->base + JZ_REG_MMC_STRPCL);
166173    do {
167174        status = readl(host->base + JZ_REG_MMC_STATUS);
168    } while (status & JZ_MMC_STATUS_CLK_EN);
175    } while (status & JZ_MMC_STATUS_CLK_EN && --timeout);
169176}
170177
171178static void jz4740_mmc_reset(struct jz4740_mmc_host *host)
172179{
173180    uint32_t status;
181    unsigned int timeout = 1000;
174182
175183    writew(JZ_MMC_STRPCL_RESET, host->base + JZ_REG_MMC_STRPCL);
176184    udelay(10);
177185    do {
178186        status = readl(host->base + JZ_REG_MMC_STATUS);
179    } while (status & JZ_MMC_STATUS_IS_RESETTING);
187    } while (status & JZ_MMC_STATUS_IS_RESETTING && --timeout);
180188}
181189
182190static void jz4740_mmc_request_done(struct jz4740_mmc_host *host)
...... 
188196
189197    mmc_request_done(host->mmc, req);
190198}
191static unsigned int jz4740_mmc_wait_irq(struct jz4740_mmc_host *host,
199static unsigned int jz4740_mmc_poll_irq(struct jz4740_mmc_host *host,
192200    unsigned int irq)
193201{
194202    unsigned int timeout = 1000;
...... 
199207    } while (!(status & irq) && --timeout);
200208
201209    if (timeout == 0) {
202        INIT_COMPLETION(host->completion);
210        set_bit(0, &host->waiting);
211        mod_timer(&host->timeout_timer, jiffies + 5*HZ);
203212        jz4740_mmc_set_irq_enabled(host, irq, true);
204        timeout = wait_for_completion_timeout(&host->completion, HZ);
213        return true;
205214    }
206215
207    return timeout;
216    return false;
208217}
209218
210static void jz4740_mmc_write_data(struct jz4740_mmc_host *host,
219static void jz4740_mmc_transfer_check_state(struct jz4740_mmc_host *host,
211220    struct mmc_data *data)
212221{
213    struct sg_mapping_iter miter;
214    uint32_t *buf;
215222    int status;
216    unsigned int timeout;
223
224    status = readl(host->base + JZ_REG_MMC_STATUS);
225    if (status & JZ_MMC_STATUS_WRITE_ERROR_MASK) {
226        if (status & (JZ_MMC_STATUS_TIMEOUT_WRITE)) {
227            host->req->cmd->error = -ETIMEDOUT;
228            data->error = -ETIMEDOUT;
229        } else {
230            host->req->cmd->error = -EIO;
231            data->error = -EIO;
232        }
233    }
234}
235
236static bool jz4740_mmc_write_data(struct jz4740_mmc_host *host,
237    struct mmc_data *data)
238{
239    struct sg_mapping_iter *miter = &host->miter;
240    uint32_t *buf;
241    bool timeout;
217242    size_t i, j;
218243
219    sg_miter_start(&miter, data->sg, data->sg_len, SG_MITER_FROM_SG);
220    while (sg_miter_next(&miter)) {
221        buf = miter.addr;
222        i = miter.length / 4;
223        j = i >> 3;
244    while (sg_miter_next(miter)) {
245        buf = miter->addr;
246        i = miter->length / 4;
247        j = i / 8;
224248        i = i & 0x7;
225249        while (j) {
226            timeout = jz4740_mmc_wait_irq(host, JZ_MMC_IRQ_TXFIFO_WR_REQ);
227            if (unlikely(timeout == 0)) {
228                sg_miter_stop(&miter);
229                goto err_timeout;
230            }
250            timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_TXFIFO_WR_REQ);
251            if (unlikely(timeout))
252                goto poll_timeout;
231253
232254            writel(buf[0], host->base + JZ_REG_MMC_TXFIFO);
233255            writel(buf[1], host->base + JZ_REG_MMC_TXFIFO);
...... 
241263            --j;
242264        }
243265        if (unlikely(i)) {
244            timeout = jz4740_mmc_wait_irq(host, JZ_MMC_IRQ_TXFIFO_WR_REQ);
245            if (unlikely(timeout == 0)) {
246                sg_miter_stop(&miter);
247                goto err_timeout;
248            }
266            timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_TXFIFO_WR_REQ);
267            if (unlikely(timeout))
268                goto poll_timeout;
249269
250270            while (i) {
251271                writel(*buf, host->base + JZ_REG_MMC_TXFIFO);
...... 
253273                --i;
254274            }
255275        }
256        data->bytes_xfered += miter.length;
276        data->bytes_xfered += miter->length;
257277    }
258    sg_miter_stop(&miter);
278    sg_miter_stop(miter);
259279
260    status = readl(host->base + JZ_REG_MMC_STATUS);
261    if (status & JZ_MMC_STATUS_WRITE_ERROR_MASK) {
262        if (status & (JZ_MMC_STATUS_TIMEOUT_WRITE)) {
263            host->req->cmd->error = -ETIMEDOUT;
264            data->error = -ETIMEDOUT;
265        } else {
266            host->req->cmd->error = -EIO;
267            data->error = -EIO;
268        }
269        return;
270    }
271
272    timeout = jz4740_mmc_wait_irq(host, JZ_MMC_IRQ_DATA_TRAN_DONE);
273    if (unlikely(timeout == 0))
274        goto err_timeout;
280    return false;
275281
276    writew(JZ_MMC_IRQ_DATA_TRAN_DONE, host->base + JZ_REG_MMC_IREG);
282poll_timeout:
283    miter->consumed = (void *)buf - miter->addr;
284    data->bytes_xfered += miter->consumed;
285    sg_miter_stop(miter);
277286
278    return;
279
280err_timeout:
281    host->req->cmd->error = -ETIMEDOUT;
282    data->error = -ETIMEDOUT;
287    return true;
283288}
284289
285static void jz4740_mmc_read_data(struct jz4740_mmc_host *host,
290static bool jz4740_mmc_read_data(struct jz4740_mmc_host *host,
286291                struct mmc_data *data)
287292{
288    struct sg_mapping_iter miter;
293    struct sg_mapping_iter *miter = &host->miter;
289294    uint32_t *buf;
290295    uint32_t d;
291    uint16_t status = 0;
296    uint16_t status;
292297    size_t i, j;
293298    unsigned int timeout;
294299
295    sg_miter_start(&miter, data->sg, data->sg_len, SG_MITER_TO_SG);
296    while (sg_miter_next(&miter)) {
297        buf = miter.addr;
298        i = miter.length;
299        j = i >> 5;
300    while (sg_miter_next(miter)) {
301        buf = miter->addr;
302        i = miter->length;
303        j = i / 32;
300304        i = i & 0x1f;
301305        while (j) {
302            timeout = jz4740_mmc_wait_irq(host, JZ_MMC_IRQ_RXFIFO_RD_REQ);
303            if (unlikely(timeout == 0)) {
304                sg_miter_stop(&miter);
305                goto err_timeout;
306            }
306            timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_RXFIFO_RD_REQ);
307            if (unlikely(timeout))
308                goto poll_timeout;
307309
308310            buf[0] = readl(host->base + JZ_REG_MMC_RXFIFO);
309311            buf[1] = readl(host->base + JZ_REG_MMC_RXFIFO);
...... 
318320            --j;
319321        }
320322
321        while (i >= 4) {
322            timeout = jz4740_mmc_wait_irq(host, JZ_MMC_IRQ_RXFIFO_RD_REQ);
323            if (unlikely(timeout == 0)) {
324                sg_miter_stop(&miter);
325                goto err_timeout;
326            }
323        if (unlikely(i)) {
324            timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_RXFIFO_RD_REQ);
325            if (unlikely(timeout))
326                goto poll_timeout;
327327
328            *buf++ = readl(host->base + JZ_REG_MMC_RXFIFO);
329            i -= 4;
330        }
331        if (unlikely(i > 0)) {
332            d = readl(host->base + JZ_REG_MMC_RXFIFO);
333            memcpy(buf, &d, i);
328            while (i >= 4) {
329                *buf++ = readl(host->base + JZ_REG_MMC_RXFIFO);
330                i -= 4;
331            }
332            if (unlikely(i > 0)) {
333                d = readl(host->base + JZ_REG_MMC_RXFIFO);
334                memcpy(buf, &d, i);
335            }
334336        }
335        data->bytes_xfered += miter.length;
336
337        /* This can go away once MIPS implements flush_kernel_dcache_page */
338        flush_dcache_page(miter.page);
339    }
340    sg_miter_stop(&miter);
337        data->bytes_xfered += miter->length;
341338
342    status = readl(host->base + JZ_REG_MMC_STATUS);
343    if (status & JZ_MMC_STATUS_READ_ERROR_MASK) {
344        if (status & JZ_MMC_STATUS_TIMEOUT_READ) {
345            host->req->cmd->error = -ETIMEDOUT;
346            data->error = -ETIMEDOUT;
347        } else {
348            host->req->cmd->error = -EIO;
349            data->error = -EIO;
350        }
351        return;
339        /* This can go away once MIPS implements
340         * flush_kernel_dcache_page */
341        flush_dcache_page(miter->page);
352342    }
343    sg_miter_stop(miter);
353344
354345    /* For whatever reason there is sometime one word more in the fifo then
355346     * requested */
356    while ((status & JZ_MMC_STATUS_DATA_FIFO_EMPTY) == 0 && --timeout) {
347    timeout = 1000;
348    status = readl(host->base + JZ_REG_MMC_STATUS);
349    while (!(status & JZ_MMC_STATUS_DATA_FIFO_EMPTY) && --timeout) {
357350        d = readl(host->base + JZ_REG_MMC_RXFIFO);
358351        status = readl(host->base + JZ_REG_MMC_STATUS);
359352    }
360    return;
361353
362err_timeout:
363    host->req->cmd->error = -ETIMEDOUT;
364    data->error = -ETIMEDOUT;
354    return false;
355
356poll_timeout:
357    miter->consumed = (void *)buf - miter->addr;
358    data->bytes_xfered += miter->consumed;
359    sg_miter_stop(miter);
360
361    return true;
365362}
366363
367364static void jz4740_mmc_timeout(unsigned long data)
...... 
444441    jz4740_mmc_clock_enable(host, 1);
445442}
446443
444static void jz_mmc_prepare_data_transfer(struct jz4740_mmc_host *host)
445{
446    struct mmc_command *cmd = host->req->cmd;
447    struct mmc_data *data = cmd->data;
448    int direction;
449
450    if (cmd->data->flags & MMC_DATA_READ)
451        direction = SG_MITER_TO_SG;
452    else
453        direction = SG_MITER_FROM_SG;
454
455    sg_miter_start(&host->miter, data->sg, data->sg_len, direction);
456}
457
447458
448459static irqreturn_t jz_mmc_irq_worker(int irq, void *devid)
449460{
450461    struct jz4740_mmc_host *host = (struct jz4740_mmc_host *)devid;
451462    struct mmc_command *cmd = host->req->cmd;
452463    struct mmc_request *req = host->req;
453    unsigned int timeout;
464    bool timedout = false;
454465
455466    if (cmd->error)
456        goto done;
467        host->state = JZ4740_MMC_STATE_DONE;
457468
458    if (cmd->flags & MMC_RSP_PRESENT)
459        jz4740_mmc_read_response(host, cmd);
469    switch (host->state) {
470    case JZ4740_MMC_STATE_READ_RESPONSE:
471        if (cmd->flags & MMC_RSP_PRESENT)
472            jz4740_mmc_read_response(host, cmd);
460473
461    if (cmd->data) {
474        if (!cmd->data)
475            break;
476
477        jz_mmc_prepare_data_transfer(host);
478
479    case JZ4740_MMC_STATE_TRANSFER_DATA:
462480        if (cmd->data->flags & MMC_DATA_READ)
463            jz4740_mmc_read_data(host, cmd->data);
481            timedout = jz4740_mmc_read_data(host, cmd->data);
464482        else
465            jz4740_mmc_write_data(host, cmd->data);
466    }
483            timedout = jz4740_mmc_write_data(host, cmd->data);
467484
468    if (req->stop) {
469        jz4740_mmc_send_command(host, req->stop);
485        if (unlikely(timedout)) {
486            host->state = JZ4740_MMC_STATE_TRANSFER_DATA;
487            break;
488        }
470489
471        timeout = jz4740_mmc_wait_irq(host, JZ_MMC_IRQ_PRG_DONE);
472        writew(JZ_MMC_IRQ_PRG_DONE, host->base + JZ_REG_MMC_IREG);
490        jz4740_mmc_transfer_check_state(host, cmd->data);
473491
474        if (unlikely(timeout == 0))
475            req->stop->error = -ETIMEDOUT;
476    }
492        timedout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_DATA_TRAN_DONE);
493        if (unlikely(timedout)) {
494            host->state = JZ4740_MMC_STATE_SEND_STOP;
495            break;
496        }
497        writew(JZ_MMC_IRQ_DATA_TRAN_DONE, host->base + JZ_REG_MMC_IREG);
477498
499    case JZ4740_MMC_STATE_SEND_STOP:
500        if (!req->stop)
501            break;
478502
479done:
480    jz4740_mmc_request_done(host);
503        jz4740_mmc_send_command(host, req->stop);
504
505        timedout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_PRG_DONE);
506        if (timedout) {
507            host->state = JZ4740_MMC_STATE_DONE;
508            break;
509        }
510    case JZ4740_MMC_STATE_DONE:
511        break;
512    }
513
514    if (!timedout)
515        jz4740_mmc_request_done(host);
481516
482517    return IRQ_HANDLED;
483518}
...... 
486521{
487522    struct jz4740_mmc_host *host = devid;
488523    uint16_t irq_reg, status, tmp;
489    irqreturn_t ret = IRQ_HANDLED;
490524
491525    irq_reg = readw(host->base + JZ_REG_MMC_IREG);
492526
...... 
502536    if (irq_reg & JZ_MMC_IRQ_SDIO) {
503537        writew(JZ_MMC_IRQ_SDIO, host->base + JZ_REG_MMC_IREG);
504538        mmc_signal_sdio_irq(host->mmc);
539        irq_reg &= ~JZ_MMC_IRQ_SDIO;
505540    }
506541
507    if (!host->req || !host->cmd)
508        goto handled;
509
510    if (irq_reg & JZ_MMC_IRQ_END_CMD_RES) {
511
542    if (host->req && host->cmd && irq_reg) {
512543        if (test_and_clear_bit(0, &host->waiting)) {
513544            del_timer(&host->timeout_timer);
514545
...... 
526557                host->cmd->data->error = -EIO;
527558            }
528559
529            ret = IRQ_WAKE_THREAD;
530        }
560            jz4740_mmc_set_irq_enabled(host, irq_reg, false);
561            writew(irq_reg, host->base + JZ_REG_MMC_IREG);
531562
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);
563            return IRQ_WAKE_THREAD;
564        }
538565    }
539566
540handled:
541    return ret;
567    return IRQ_HANDLED;
542568}
543569
544570static int jz4740_mmc_set_clock_rate(struct jz4740_mmc_host *host, int rate)
...... 
571597    writew(JZ_MMC_IRQ_END_CMD_RES, host->base + JZ_REG_MMC_IREG);
572598    jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_END_CMD_RES, true);
573599
600    host->state = JZ4740_MMC_STATE_READ_RESPONSE;
574601    set_bit(0, &host->waiting);
575602    mod_timer(&host->timeout_timer, jiffies + 5*HZ);
576603    jz4740_mmc_send_command(host, req->cmd);
...... 
770797
771798    host->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
772799    if (!host->mem) {
773        ret = -ENXIO;
800        ret = -ENOENT;
774801        dev_err(&pdev->dev, "Failed to get base platform memory\n");
775802        goto err_clk_put;
776803    }
...... 
848875    jz4740_mmc_clock_disable(host);
849876    setup_timer(&host->timeout_timer, jz4740_mmc_timeout,
850877            (unsigned long)host);
851    init_completion(&host->completion);
878    /* It is not that important when it times out, it just needs to timeout. */
879    set_timer_slack(&host->timeout_timer, HZ);
852880
853881    platform_set_drvdata(pdev, host);
854882    ret = mmc_add_host(mmc);

Archive Download the corresponding diff file



interactive