diff options
| author | Richard Zhao <richard.zhao@freescale.com> | 2012-05-11 03:14:27 -0400 |
|---|---|---|
| committer | Vinod Koul <vinod.koul@linux.intel.com> | 2012-05-11 04:30:38 -0400 |
| commit | 2ccaef0520d18d0072153f090d4110b4075c332c (patch) | |
| tree | c4fcc9cbac1f7448263701ae5c5926f28351935c | |
| parent | 922ee08baad2052d0759f100e026d49798c51fef (diff) | |
dma: imx-sdma: make channel0 operations atomic
device_prep_dma_cyclic may be call in audio trigger function which is
atomic context, so we make it atomic too.
- change channel0 lock to spinlock.
- Use polling to wait for channel0 finish running.
Signed-off-by: Richard Zhao <richard.zhao@freescale.com>
Acked-by: Shawn Guo <shawn.guo@linaro.org>
Signed-off-by: Vinod Koul <vinod.koul@linux.intel.com>
| -rw-r--r-- | drivers/dma/imx-sdma.c | 57 |
1 files changed, 31 insertions, 26 deletions
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index cd0619a897ff..a472a29d8497 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c | |||
| @@ -24,7 +24,7 @@ | |||
| 24 | #include <linux/mm.h> | 24 | #include <linux/mm.h> |
| 25 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
| 26 | #include <linux/clk.h> | 26 | #include <linux/clk.h> |
| 27 | #include <linux/wait.h> | 27 | #include <linux/delay.h> |
| 28 | #include <linux/sched.h> | 28 | #include <linux/sched.h> |
| 29 | #include <linux/semaphore.h> | 29 | #include <linux/semaphore.h> |
| 30 | #include <linux/spinlock.h> | 30 | #include <linux/spinlock.h> |
| @@ -324,7 +324,7 @@ struct sdma_engine { | |||
| 324 | dma_addr_t context_phys; | 324 | dma_addr_t context_phys; |
| 325 | struct dma_device dma_device; | 325 | struct dma_device dma_device; |
| 326 | struct clk *clk; | 326 | struct clk *clk; |
| 327 | struct mutex channel_0_lock; | 327 | spinlock_t channel_0_lock; |
| 328 | struct sdma_script_start_addrs *script_addrs; | 328 | struct sdma_script_start_addrs *script_addrs; |
| 329 | }; | 329 | }; |
| 330 | 330 | ||
| @@ -402,19 +402,27 @@ static void sdma_enable_channel(struct sdma_engine *sdma, int channel) | |||
| 402 | } | 402 | } |
| 403 | 403 | ||
| 404 | /* | 404 | /* |
| 405 | * sdma_run_channel - run a channel and wait till it's done | 405 | * sdma_run_channel0 - run a channel and wait till it's done |
| 406 | */ | 406 | */ |
| 407 | static int sdma_run_channel(struct sdma_channel *sdmac) | 407 | static int sdma_run_channel0(struct sdma_engine *sdma) |
| 408 | { | 408 | { |
| 409 | struct sdma_engine *sdma = sdmac->sdma; | ||
| 410 | int channel = sdmac->channel; | ||
| 411 | int ret; | 409 | int ret; |
| 410 | unsigned long timeout = 500; | ||
| 412 | 411 | ||
| 413 | init_completion(&sdmac->done); | 412 | sdma_enable_channel(sdma, 0); |
| 414 | 413 | ||
| 415 | sdma_enable_channel(sdma, channel); | 414 | while (!(ret = readl_relaxed(sdma->regs + SDMA_H_INTR) & 1)) { |
| 415 | if (timeout-- <= 0) | ||
| 416 | break; | ||
| 417 | udelay(1); | ||
| 418 | } | ||
| 416 | 419 | ||
| 417 | ret = wait_for_completion_timeout(&sdmac->done, HZ); | 420 | if (ret) { |
| 421 | /* Clear the interrupt status */ | ||
| 422 | writel_relaxed(ret, sdma->regs + SDMA_H_INTR); | ||
| 423 | } else { | ||
| 424 | dev_err(sdma->dev, "Timeout waiting for CH0 ready\n"); | ||
| 425 | } | ||
| 418 | 426 | ||
| 419 | return ret ? 0 : -ETIMEDOUT; | 427 | return ret ? 0 : -ETIMEDOUT; |
| 420 | } | 428 | } |
| @@ -426,17 +434,17 @@ static int sdma_load_script(struct sdma_engine *sdma, void *buf, int size, | |||
| 426 | void *buf_virt; | 434 | void *buf_virt; |
| 427 | dma_addr_t buf_phys; | 435 | dma_addr_t buf_phys; |
| 428 | int ret; | 436 | int ret; |
| 429 | 437 | unsigned long flags; | |
| 430 | mutex_lock(&sdma->channel_0_lock); | ||
| 431 | 438 | ||
| 432 | buf_virt = dma_alloc_coherent(NULL, | 439 | buf_virt = dma_alloc_coherent(NULL, |
| 433 | size, | 440 | size, |
| 434 | &buf_phys, GFP_KERNEL); | 441 | &buf_phys, GFP_KERNEL); |
| 435 | if (!buf_virt) { | 442 | if (!buf_virt) { |
| 436 | ret = -ENOMEM; | 443 | return -ENOMEM; |
| 437 | goto err_out; | ||
| 438 | } | 444 | } |
| 439 | 445 | ||
| 446 | spin_lock_irqsave(&sdma->channel_0_lock, flags); | ||
| 447 | |||
| 440 | bd0->mode.command = C0_SETPM; | 448 | bd0->mode.command = C0_SETPM; |
| 441 | bd0->mode.status = BD_DONE | BD_INTR | BD_WRAP | BD_EXTD; | 449 | bd0->mode.status = BD_DONE | BD_INTR | BD_WRAP | BD_EXTD; |
| 442 | bd0->mode.count = size / 2; | 450 | bd0->mode.count = size / 2; |
| @@ -445,12 +453,11 @@ static int sdma_load_script(struct sdma_engine *sdma, void *buf, int size, | |||
| 445 | 453 | ||
| 446 | memcpy(buf_virt, buf, size); | 454 | memcpy(buf_virt, buf, size); |
| 447 | 455 | ||
| 448 | ret = sdma_run_channel(&sdma->channel[0]); | 456 | ret = sdma_run_channel0(sdma); |
| 449 | 457 | ||
| 450 | dma_free_coherent(NULL, size, buf_virt, buf_phys); | 458 | spin_unlock_irqrestore(&sdma->channel_0_lock, flags); |
| 451 | 459 | ||
| 452 | err_out: | 460 | dma_free_coherent(NULL, size, buf_virt, buf_phys); |
| 453 | mutex_unlock(&sdma->channel_0_lock); | ||
| 454 | 461 | ||
| 455 | return ret; | 462 | return ret; |
| 456 | } | 463 | } |
| @@ -541,10 +548,6 @@ static void sdma_tasklet(unsigned long data) | |||
| 541 | 548 | ||
| 542 | complete(&sdmac->done); | 549 | complete(&sdmac->done); |
| 543 | 550 | ||
| 544 | /* not interested in channel 0 interrupts */ | ||
| 545 | if (sdmac->channel == 0) | ||
| 546 | return; | ||
| 547 | |||
| 548 | if (sdmac->flags & IMX_DMA_SG_LOOP) | 551 | if (sdmac->flags & IMX_DMA_SG_LOOP) |
| 549 | sdma_handle_channel_loop(sdmac); | 552 | sdma_handle_channel_loop(sdmac); |
| 550 | else | 553 | else |
| @@ -557,6 +560,8 @@ static irqreturn_t sdma_int_handler(int irq, void *dev_id) | |||
| 557 | unsigned long stat; | 560 | unsigned long stat; |
| 558 | 561 | ||
| 559 | stat = readl_relaxed(sdma->regs + SDMA_H_INTR); | 562 | stat = readl_relaxed(sdma->regs + SDMA_H_INTR); |
| 563 | /* not interested in channel 0 interrupts */ | ||
| 564 | stat &= ~1; | ||
| 560 | writel_relaxed(stat, sdma->regs + SDMA_H_INTR); | 565 | writel_relaxed(stat, sdma->regs + SDMA_H_INTR); |
| 561 | 566 | ||
| 562 | while (stat) { | 567 | while (stat) { |
| @@ -662,6 +667,7 @@ static int sdma_load_context(struct sdma_channel *sdmac) | |||
| 662 | struct sdma_context_data *context = sdma->context; | 667 | struct sdma_context_data *context = sdma->context; |
| 663 | struct sdma_buffer_descriptor *bd0 = sdma->channel[0].bd; | 668 | struct sdma_buffer_descriptor *bd0 = sdma->channel[0].bd; |
| 664 | int ret; | 669 | int ret; |
| 670 | unsigned long flags; | ||
| 665 | 671 | ||
| 666 | if (sdmac->direction == DMA_DEV_TO_MEM) { | 672 | if (sdmac->direction == DMA_DEV_TO_MEM) { |
| 667 | load_address = sdmac->pc_from_device; | 673 | load_address = sdmac->pc_from_device; |
| @@ -679,7 +685,7 @@ static int sdma_load_context(struct sdma_channel *sdmac) | |||
| 679 | dev_dbg(sdma->dev, "event_mask0 = 0x%08x\n", (u32)sdmac->event_mask[0]); | 685 | dev_dbg(sdma->dev, "event_mask0 = 0x%08x\n", (u32)sdmac->event_mask[0]); |
| 680 | dev_dbg(sdma->dev, "event_mask1 = 0x%08x\n", (u32)sdmac->event_mask[1]); | 686 | dev_dbg(sdma->dev, "event_mask1 = 0x%08x\n", (u32)sdmac->event_mask[1]); |
| 681 | 687 | ||
| 682 | mutex_lock(&sdma->channel_0_lock); | 688 | spin_lock_irqsave(&sdma->channel_0_lock, flags); |
| 683 | 689 | ||
| 684 | memset(context, 0, sizeof(*context)); | 690 | memset(context, 0, sizeof(*context)); |
| 685 | context->channel_state.pc = load_address; | 691 | context->channel_state.pc = load_address; |
| @@ -698,10 +704,9 @@ static int sdma_load_context(struct sdma_channel *sdmac) | |||
| 698 | bd0->mode.count = sizeof(*context) / 4; | 704 | bd0->mode.count = sizeof(*context) / 4; |
| 699 | bd0->buffer_addr = sdma->context_phys; | 705 | bd0->buffer_addr = sdma->context_phys; |
| 700 | bd0->ext_buffer_addr = 2048 + (sizeof(*context) / 4) * channel; | 706 | bd0->ext_buffer_addr = 2048 + (sizeof(*context) / 4) * channel; |
| 707 | ret = sdma_run_channel0(sdma); | ||
| 701 | 708 | ||
| 702 | ret = sdma_run_channel(&sdma->channel[0]); | 709 | spin_unlock_irqrestore(&sdma->channel_0_lock, flags); |
| 703 | |||
| 704 | mutex_unlock(&sdma->channel_0_lock); | ||
| 705 | 710 | ||
| 706 | return ret; | 711 | return ret; |
| 707 | } | 712 | } |
| @@ -1300,7 +1305,7 @@ static int __init sdma_probe(struct platform_device *pdev) | |||
| 1300 | if (!sdma) | 1305 | if (!sdma) |
| 1301 | return -ENOMEM; | 1306 | return -ENOMEM; |
| 1302 | 1307 | ||
| 1303 | mutex_init(&sdma->channel_0_lock); | 1308 | spin_lock_init(&sdma->channel_0_lock); |
| 1304 | 1309 | ||
| 1305 | sdma->dev = &pdev->dev; | 1310 | sdma->dev = &pdev->dev; |
| 1306 | 1311 | ||
