diff options
author | Fancy Fang <B47543@freescale.com> | 2013-11-21 06:44:45 -0500 |
---|---|---|
committer | Nitin Garg <nitin.garg@freescale.com> | 2014-04-16 09:47:23 -0400 |
commit | 94f609967b18344dd664e69e9ee28d517b428429 (patch) | |
tree | e74e02d53f49df0fca2cb4f1eaf71cfb7271262e | |
parent | f2da7fb11242e1951ecb52c4549f5ef14d21483b (diff) |
ENGR00289237 PXP: fix a multiple instances hang issue
In pxp_issue_pending(), the wait for pxp done processes will be woken up
together in PXP ISR. So there will be some situations that one process will
set PXP hardware registers after another process's setting but before the
first PXP task done. So the PXP hardware may be corrupted and hang maybe
happen.
Signed-off-by: Fancy Fang <B47543@freescale.com>
-rw-r--r-- | drivers/dma/pxp/pxp_device.c | 8 | ||||
-rw-r--r-- | drivers/dma/pxp/pxp_dma_v2.c | 18 |
2 files changed, 11 insertions, 15 deletions
diff --git a/drivers/dma/pxp/pxp_device.c b/drivers/dma/pxp/pxp_device.c index 140dce0a99f6..d05b06df0c90 100644 --- a/drivers/dma/pxp/pxp_device.c +++ b/drivers/dma/pxp/pxp_device.c | |||
@@ -433,12 +433,10 @@ static long pxp_device_ioctl(struct file *filp, | |||
433 | if (chan_id < 0 || chan_id >= NR_PXP_VIRT_CHANNEL) | 433 | if (chan_id < 0 || chan_id >= NR_PXP_VIRT_CHANNEL) |
434 | return -ENODEV; | 434 | return -ENODEV; |
435 | 435 | ||
436 | if (!wait_event_interruptible_timeout | 436 | ret = wait_event_interruptible |
437 | (irq_info[chan_id].waitq, | 437 | (irq_info[chan_id].waitq, |
438 | (irq_info[chan_id].irq_pending != 0), 2 * HZ)) { | 438 | (irq_info[chan_id].irq_pending != 0)); |
439 | pr_warning("pxp blocking: timeout.\n"); | 439 | if (ret < 0) { |
440 | return -ETIME; | ||
441 | } else if (signal_pending(current)) { | ||
442 | printk(KERN_WARNING | 440 | printk(KERN_WARNING |
443 | "pxp interrupt received.\n"); | 441 | "pxp interrupt received.\n"); |
444 | return -ERESTARTSYS; | 442 | return -ERESTARTSYS; |
diff --git a/drivers/dma/pxp/pxp_dma_v2.c b/drivers/dma/pxp/pxp_dma_v2.c index 0df4200d2481..55c35b35a875 100644 --- a/drivers/dma/pxp/pxp_dma_v2.c +++ b/drivers/dma/pxp/pxp_dma_v2.c | |||
@@ -477,10 +477,11 @@ static void pxp_set_oln(int layer_no, struct pxps *pxp) | |||
477 | struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state; | 477 | struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state; |
478 | struct pxp_layer_param *olparams_data = &pxp_conf->ol_param[layer_no]; | 478 | struct pxp_layer_param *olparams_data = &pxp_conf->ol_param[layer_no]; |
479 | dma_addr_t phys_addr = olparams_data->paddr; | 479 | dma_addr_t phys_addr = olparams_data->paddr; |
480 | __raw_writel(phys_addr, pxp->base + HW_PXP_AS_BUF); | ||
481 | u32 pitch = olparams_data->stride ? olparams_data->stride : | 480 | u32 pitch = olparams_data->stride ? olparams_data->stride : |
482 | olparams_data->width; | 481 | olparams_data->width; |
483 | 482 | ||
483 | __raw_writel(phys_addr, pxp->base + HW_PXP_AS_BUF); | ||
484 | |||
484 | /* Fixme */ | 485 | /* Fixme */ |
485 | if (olparams_data->width == 0 && olparams_data->height == 0) { | 486 | if (olparams_data->width == 0 && olparams_data->height == 0) { |
486 | __raw_writel(0xffffffff, pxp->base + HW_PXP_OUT_AS_ULC); | 487 | __raw_writel(0xffffffff, pxp->base + HW_PXP_OUT_AS_ULC); |
@@ -1114,9 +1115,6 @@ static void pxpdma_dostart_work(struct pxps *pxp) | |||
1114 | struct pxp_channel *pxp_chan = NULL; | 1115 | struct pxp_channel *pxp_chan = NULL; |
1115 | unsigned long flags, flags1; | 1116 | unsigned long flags, flags1; |
1116 | 1117 | ||
1117 | while (__raw_readl(pxp->base + HW_PXP_CTRL) & BM_PXP_CTRL_ENABLE) | ||
1118 | ; | ||
1119 | |||
1120 | spin_lock_irqsave(&pxp->lock, flags); | 1118 | spin_lock_irqsave(&pxp->lock, flags); |
1121 | if (list_empty(&head)) { | 1119 | if (list_empty(&head)) { |
1122 | pxp->pxp_ongoing = 0; | 1120 | pxp->pxp_ongoing = 0; |
@@ -1323,7 +1321,7 @@ static irqreturn_t pxp_irq(int irq, void *dev_id) | |||
1323 | list_splice_init(&desc->tx_list, &pxp_chan->free_list); | 1321 | list_splice_init(&desc->tx_list, &pxp_chan->free_list); |
1324 | list_move(&desc->list, &pxp_chan->free_list); | 1322 | list_move(&desc->list, &pxp_chan->free_list); |
1325 | 1323 | ||
1326 | wake_up(&pxp->done); | 1324 | wake_up_interruptible(&pxp->done); |
1327 | pxp->pxp_ongoing = 0; | 1325 | pxp->pxp_ongoing = 0; |
1328 | mod_timer(&pxp->clk_timer, jiffies + msecs_to_jiffies(timeout_in_ms)); | 1326 | mod_timer(&pxp->clk_timer, jiffies + msecs_to_jiffies(timeout_in_ms)); |
1329 | 1327 | ||
@@ -1439,6 +1437,7 @@ static void pxp_issue_pending(struct dma_chan *chan) | |||
1439 | struct pxp_dma *pxp_dma = to_pxp_dma(chan->device); | 1437 | struct pxp_dma *pxp_dma = to_pxp_dma(chan->device); |
1440 | struct pxps *pxp = to_pxp(pxp_dma); | 1438 | struct pxps *pxp = to_pxp(pxp_dma); |
1441 | unsigned long flags0, flags; | 1439 | unsigned long flags0, flags; |
1440 | int ret; | ||
1442 | 1441 | ||
1443 | spin_lock_irqsave(&pxp->lock, flags0); | 1442 | spin_lock_irqsave(&pxp->lock, flags0); |
1444 | spin_lock_irqsave(&pxp_chan->lock, flags); | 1443 | spin_lock_irqsave(&pxp_chan->lock, flags); |
@@ -1456,11 +1455,10 @@ static void pxp_issue_pending(struct dma_chan *chan) | |||
1456 | spin_unlock_irqrestore(&pxp->lock, flags0); | 1455 | spin_unlock_irqrestore(&pxp->lock, flags0); |
1457 | 1456 | ||
1458 | pxp_clk_enable(pxp); | 1457 | pxp_clk_enable(pxp); |
1459 | if (!wait_event_interruptible_timeout(pxp->done, PXP_WAITCON, 2 * HZ) || | 1458 | again: |
1460 | signal_pending(current)) { | 1459 | ret = wait_event_interruptible_exclusive(pxp->done, PXP_WAITCON); |
1461 | pxp_clk_disable(pxp); | 1460 | if (ret < 0) |
1462 | return; | 1461 | goto again; |
1463 | } | ||
1464 | 1462 | ||
1465 | spin_lock_irqsave(&pxp->lock, flags); | 1463 | spin_lock_irqsave(&pxp->lock, flags); |
1466 | pxp->pxp_ongoing = 1; | 1464 | pxp->pxp_ongoing = 1; |