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 | ||
---|---|---|
24 | 24 | #include <linux/clk.h> |
25 | 25 | #include <linux/mmc/jz4740_mmc.h> |
26 | 26 | |
27 | #include <linux/completion.h> | |
28 | ||
27 | 29 | #include <linux/bitops.h> |
28 | 30 | #include <linux/gpio.h> |
29 | 31 | #include <asm/mach-jz4740/gpio.h> |
... | ... | |
103 | 105 | |
104 | 106 | #define JZ_MMC_CLK_RATE 24000000 |
105 | 107 | |
106 | #define JZ4740_MMC_MAX_TIMEOUT 10000000 | |
107 | ||
108 | 108 | struct jz4740_mmc_host { |
109 | 109 | struct mmc_host *mmc; |
110 | 110 | struct platform_device *pdev; |
... | ... | |
129 | 129 | spinlock_t lock; |
130 | 130 | |
131 | 131 | struct timer_list timeout_timer; |
132 | struct completion completion; | |
132 | 133 | }; |
133 | 134 | |
134 | 135 | static void jz4740_mmc_set_irq_enabled(struct jz4740_mmc_host *host, |
... | ... | |
187 | 188 | |
188 | 189 | mmc_request_done(host->mmc, req); |
189 | 190 | } |
190 | ||
191 | static inline unsigned int jz4740_mmc_wait_irq(struct jz4740_mmc_host *host, | |
191 | static unsigned int jz4740_mmc_wait_irq(struct jz4740_mmc_host *host, | |
192 | 192 | unsigned int irq) |
193 | 193 | { |
194 | unsigned int timeout = JZ4740_MMC_MAX_TIMEOUT; | |
194 | unsigned int timeout = 1000; | |
195 | 195 | uint16_t status; |
196 | 196 | |
197 | 197 | do { |
198 | 198 | status = readw(host->base + JZ_REG_MMC_IREG); |
199 | 199 | } while (!(status & irq) && --timeout); |
200 | 200 | |
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 | ||
201 | 207 | return timeout; |
202 | 208 | } |
203 | 209 | |
... | ... | |
263 | 269 | return; |
264 | 270 | } |
265 | 271 | |
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); | |
271 | 273 | if (unlikely(timeout == 0)) |
272 | 274 | goto err_timeout; |
275 | ||
273 | 276 | writew(JZ_MMC_IRQ_DATA_TRAN_DONE, host->base + JZ_REG_MMC_IREG); |
274 | 277 | |
275 | 278 | return; |
... | ... | |
447 | 450 | struct jz4740_mmc_host *host = (struct jz4740_mmc_host *)devid; |
448 | 451 | struct mmc_command *cmd = host->req->cmd; |
449 | 452 | struct mmc_request *req = host->req; |
450 | unsigned int timeout = JZ4740_MMC_MAX_TIMEOUT; | |
451 | uint32_t status; | |
453 | unsigned int timeout; | |
452 | 454 | |
453 | 455 | if (cmd->error) |
454 | 456 | goto done; |
... | ... | |
465 | 467 | |
466 | 468 | if (req->stop) { |
467 | 469 | 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); | |
471 | 472 | writew(JZ_MMC_IRQ_PRG_DONE, host->base + JZ_REG_MMC_IREG); |
473 | ||
474 | if (unlikely(timeout == 0)) | |
475 | req->stop->error = -ETIMEDOUT; | |
472 | 476 | } |
473 | 477 | |
474 | if (unlikely(timeout == 0)) | |
475 | req->stop->error = -ETIMEDOUT; | |
476 | 478 | |
477 | 479 | done: |
478 | 480 | jz4740_mmc_request_done(host); |
... | ... | |
492 | 494 | irq_reg &= ~host->irq_mask; |
493 | 495 | |
494 | 496 | 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); | |
496 | 498 | |
497 | 499 | if (tmp != irq_reg) |
498 | 500 | writew(tmp & ~irq_reg, host->base + JZ_REG_MMC_IREG); |
... | ... | |
505 | 507 | if (!host->req || !host->cmd) |
506 | 508 | goto handled; |
507 | 509 | |
508 | if (!(irq_reg & JZ_MMC_IRQ_END_CMD_RES)) | |
509 | goto handled; | |
510 | if (irq_reg & JZ_MMC_IRQ_END_CMD_RES) { | |
510 | 511 | |
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; | |
526 | 530 | } |
527 | 531 | |
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); | |
529 | 538 | } |
530 | 539 | |
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 | ||
534 | 540 | handled: |
535 | 541 | return ret; |
536 | 542 | } |
... | ... | |
842 | 848 | jz4740_mmc_clock_disable(host); |
843 | 849 | setup_timer(&host->timeout_timer, jz4740_mmc_timeout, |
844 | 850 | (unsigned long)host); |
851 | init_completion(&host->completion); | |
845 | 852 | |
846 | 853 | platform_set_drvdata(pdev, host); |
847 | 854 | ret = mmc_add_host(mmc); |
Branches:
ben-wpan
ben-wpan-stefan
5396a9238205f20f811ea57898980d3ca82df0b6
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9