diff options
author | Liu Ying <Ying.Liu@freescale.com> | 2015-04-22 11:35:09 +0800 |
---|---|---|
committer | Jason Liu <r64343@freescale.com> | 2015-05-08 17:25:06 +0800 |
commit | 80a0013f2f7c8bbc9b80fe12d39d87b0b490dbd7 (patch) | |
tree | e4749600fc471da9db67affb0af3b002d5edf17f | |
parent | 17109fc39d3f10db3f21b1cac85b093f0a7c3377 (diff) |
MLK-10714 mxc IPUv3: PRE: Fix deadlock possibility in PRE interrupt handler
The PRE interrupt handler is protected by the spin lock pre->lock.
The spin lock is also locked/unlocked in non-interrupt contexts.
So, we need to use spin_lock_irqsave() and spin_unlock_irqrestore()
primitives in the non-interrupt contexts to avoid deadlock in the
interrupt handler.
Signed-off-by: Liu Ying <Ying.Liu@freescale.com>
-rw-r--r-- | drivers/mxc/ipu3/pre.c | 70 |
1 files changed, 41 insertions, 29 deletions
diff --git a/drivers/mxc/ipu3/pre.c b/drivers/mxc/ipu3/pre.c index 28ddb0986056..628d279748a4 100644 --- a/drivers/mxc/ipu3/pre.c +++ b/drivers/mxc/ipu3/pre.c @@ -188,12 +188,13 @@ static int ipu_pre_set_ctrl(unsigned int id, unsigned int prefetch_mode) { struct ipu_pre_data *pre = get_pre(id); + unsigned long lock_flags; int ret = 0; if (!pre) return -EINVAL; - spin_lock(&pre->lock); + spin_lock_irqsave(&pre->lock, lock_flags); pre_write(pre, BF_PRE_CTRL_TPR_RESET_SEL(1), HW_PRE_CTRL_SET); if (repeat) @@ -290,7 +291,7 @@ static int ipu_pre_set_ctrl(unsigned int id, pre_write(pre, BM_PRE_CTRL_SDW_UPDATE, HW_PRE_CTRL_CLR); err: - spin_unlock(&pre->lock); + spin_unlock_irqrestore(&pre->lock, lock_flags); return ret; } @@ -309,14 +310,15 @@ static int ipu_pre_buf_set(unsigned int id, unsigned long cur_buf, unsigned long next_buf) { struct ipu_pre_data *pre = get_pre(id); + unsigned long lock_flags; if (!pre) return -EINVAL; - spin_lock(&pre->lock); + spin_lock_irqsave(&pre->lock, lock_flags); pre_write(pre, cur_buf, HW_PRE_CUR_BUF); pre_write(pre, next_buf, HW_PRE_NEXT_BUF); - spin_unlock(&pre->lock); + spin_unlock_irqrestore(&pre->lock, lock_flags); return 0; } @@ -326,15 +328,16 @@ static int ipu_pre_plane_buf_off_set(unsigned int id, unsigned long trd_buf_off) { struct ipu_pre_data *pre = get_pre(id); + unsigned long lock_flags; if (!pre || sec_buf_off & BM_PRE_U_BUF_OFFSET_RSVD0 || trd_buf_off & BM_PRE_V_BUF_OFFSET_RSVD0) return -EINVAL; - spin_lock(&pre->lock); + spin_lock_irqsave(&pre->lock, lock_flags); pre_write(pre, sec_buf_off, HW_PRE_U_BUF_OFFSET); pre_write(pre, trd_buf_off, HW_PRE_V_BUF_OFFSET); - spin_unlock(&pre->lock); + spin_unlock_irqrestore(&pre->lock, lock_flags); return 0; } @@ -342,6 +345,7 @@ static int ipu_pre_plane_buf_off_set(unsigned int id, static int ipu_pre_tpr_set(unsigned int id, unsigned int tile_fmt) { struct ipu_pre_data *pre = get_pre(id); + unsigned long lock_flags; unsigned int tpr_ctrl, fmt; if (!pre) @@ -380,12 +384,12 @@ static int ipu_pre_tpr_set(unsigned int id, unsigned int tile_fmt) return -EINVAL; } - spin_lock(&pre->lock); + spin_lock_irqsave(&pre->lock, lock_flags); tpr_ctrl = pre_read(pre, HW_PRE_TPR_CTRL); tpr_ctrl &= ~BM_PRE_TPR_CTRL_TILE_FORMAT; tpr_ctrl |= fmt; pre_write(pre, tpr_ctrl, HW_PRE_TPR_CTRL); - spin_unlock(&pre->lock); + spin_unlock_irqrestore(&pre->lock, lock_flags); return 0; } @@ -393,14 +397,15 @@ static int ipu_pre_tpr_set(unsigned int id, unsigned int tile_fmt) static int ipu_pre_set_shift(int id, unsigned int offset, unsigned int width) { struct ipu_pre_data *pre = get_pre(id); + unsigned long lock_flags; if (!pre) return -EINVAL; - spin_lock(&pre->lock); + spin_lock_irqsave(&pre->lock, lock_flags); pre_write(pre, offset, HW_PRE_PREFETCH_ENGINE_SHIFT_OFFSET); pre_write(pre, width, HW_PRE_PREFETCH_ENGINE_SHIFT_WIDTH); - spin_unlock(&pre->lock); + spin_unlock_irqrestore(&pre->lock, lock_flags); return 0; } @@ -422,11 +427,12 @@ static int ipu_pre_prefetch(unsigned int id, unsigned int prefetch_ctrl = 0; unsigned int input_y_pitch = 0, input_uv_pitch = 0; struct ipu_pre_data *pre = get_pre(id); + unsigned long lock_flags; if (!pre) return -EINVAL; - spin_lock(&pre->lock); + spin_lock_irqsave(&pre->lock, lock_flags); prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_PREFETCH_EN(1); switch (read_burst) { case 0x0: @@ -445,8 +451,8 @@ static int ipu_pre_prefetch(unsigned int id, prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES(0x4); break; default: + spin_unlock_irqrestore(&pre->lock, lock_flags); dev_err(pre->dev, "invalid read burst for prefetch engine\n"); - spin_unlock(&pre->lock); return -EINVAL; } @@ -464,8 +470,8 @@ static int ipu_pre_prefetch(unsigned int id, prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP(0x3); break; default: + spin_unlock_irqrestore(&pre->lock, lock_flags); dev_err(pre->dev, "invalid input bpp for prefetch engine\n"); - spin_unlock(&pre->lock); return -EINVAL; } @@ -513,8 +519,8 @@ static int ipu_pre_prefetch(unsigned int id, input_uv_pitch = input_width; break; default: + spin_unlock_irqrestore(&pre->lock, lock_flags); dev_err(pre->dev, "invalid input pixel format for prefetch engine\n"); - spin_unlock(&pre->lock); return -EINVAL; } @@ -538,7 +544,7 @@ static int ipu_pre_prefetch(unsigned int id, pre_write(pre, BF_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET_INTERLACE_OFFSET(interlace_offset), HW_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET); pre_write(pre, prefetch_ctrl, HW_PRE_PREFETCH_ENGINE_CTRL); - spin_unlock(&pre->lock); + spin_unlock_irqrestore(&pre->lock, lock_flags); return 0; } @@ -557,11 +563,12 @@ static int ipu_pre_store(unsigned int id, { struct ipu_pre_data *pre = get_pre(id); unsigned int store_ctrl = 0; + unsigned long lock_flags; if (!pre) return -EINVAL; - spin_lock(&pre->lock); + spin_lock_irqsave(&pre->lock, lock_flags); store_ctrl |= BF_PRE_STORE_ENGINE_CTRL_STORE_EN(store_en ? 1 : 0); if (store_en) { @@ -582,8 +589,8 @@ static int ipu_pre_store(unsigned int id, store_ctrl |= BF_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES(0x4); break; default: + spin_unlock_irqrestore(&pre->lock, lock_flags); dev_err(pre->dev, "invalid write burst value for store engine\n"); - spin_unlock(&pre->lock); return -EINVAL; } @@ -601,8 +608,8 @@ static int ipu_pre_store(unsigned int id, store_ctrl |= BF_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP(0x3); break; default: + spin_unlock_irqrestore(&pre->lock, lock_flags); dev_err(pre->dev, "invalid ouput bpp for store engine\n"); - spin_unlock(&pre->lock); return -EINVAL; } @@ -618,7 +625,7 @@ static int ipu_pre_store(unsigned int id, } pre_write(pre, store_ctrl, HW_PRE_STORE_ENGINE_CTRL); - spin_unlock(&pre->lock); + spin_unlock_irqrestore(&pre->lock, lock_flags); return 0; } @@ -667,14 +674,15 @@ static irqreturn_t ipu_pre_irq_handle(int irq, void *dev_id) static void ipu_pre_out_of_reset(unsigned int id) { struct ipu_pre_data *pre = get_pre(id); + unsigned long lock_flags; if (!pre) return; - spin_lock(&pre->lock); + spin_lock_irqsave(&pre->lock, lock_flags); pre_write(pre, BF_PRE_CTRL_SFTRST(1) | BF_PRE_CTRL_CLKGATE(1), HW_PRE_CTRL_CLR); - spin_unlock(&pre->lock); + spin_unlock_irqrestore(&pre->lock, lock_flags); } int ipu_pre_config(int id, struct ipu_pre_context *config) @@ -750,6 +758,7 @@ int ipu_pre_enable(int id) { int ret = 0; struct ipu_pre_data *pre = get_pre(id); + unsigned long lock_flags; if (!pre) return -EINVAL; @@ -760,9 +769,9 @@ int ipu_pre_enable(int id) clk_prepare_enable(pre->clk); /* start the pre engine */ - spin_lock(&pre->lock); + spin_lock_irqsave(&pre->lock, lock_flags); pre_write(pre, BF_PRE_CTRL_ENABLE(1), HW_PRE_CTRL_SET); - spin_unlock(&pre->lock); + spin_unlock_irqrestore(&pre->lock, lock_flags); pre->enabled = true; @@ -774,6 +783,7 @@ int ipu_pre_sdw_update(int id) { int ret = 0; struct ipu_pre_data *pre = get_pre(id); + unsigned long lock_flags; if (!pre) return -EINVAL; @@ -782,9 +792,9 @@ int ipu_pre_sdw_update(int id) clk_prepare_enable(pre->clk); /* start the pre engine */ - spin_lock(&pre->lock); + spin_lock_irqsave(&pre->lock, lock_flags); pre_write(pre, BF_PRE_CTRL_SDW_UPDATE(1), HW_PRE_CTRL_SET); - spin_unlock(&pre->lock); + spin_unlock_irqrestore(&pre->lock, lock_flags); if (!pre->enabled) clk_disable_unprepare(pre->clk); @@ -796,6 +806,7 @@ EXPORT_SYMBOL(ipu_pre_sdw_update); void ipu_pre_disable(int id) { struct ipu_pre_data *pre = get_pre(id); + unsigned long lock_flags; if (!pre) return; @@ -804,11 +815,11 @@ void ipu_pre_disable(int id) return; /* stop the pre engine */ - spin_lock(&pre->lock); + spin_lock_irqsave(&pre->lock, lock_flags); pre_write(pre, BF_PRE_CTRL_ENABLE(1), HW_PRE_CTRL_CLR); pre_write(pre, BF_PRE_CTRL_SDW_UPDATE(1), HW_PRE_CTRL_SET); pre_write(pre, BF_PRE_CTRL_SFTRST(1), HW_PRE_CTRL_SET); - spin_unlock(&pre->lock); + spin_unlock_irqrestore(&pre->lock, lock_flags); clk_disable_unprepare(pre->clk); @@ -823,11 +834,12 @@ int ipu_pre_set_fb_buffer(int id, unsigned long fb_paddr, unsigned int trd_buf_off) { struct ipu_pre_data *pre = get_pre(id); + unsigned long lock_flags; if (!pre) return -EINVAL; - spin_lock(&pre->lock); + spin_lock_irqsave(&pre->lock, lock_flags); pre_write(pre, fb_paddr, HW_PRE_NEXT_BUF); pre_write(pre, sec_buf_off, HW_PRE_U_BUF_OFFSET); pre_write(pre, trd_buf_off, HW_PRE_V_BUF_OFFSET); @@ -835,7 +847,7 @@ int ipu_pre_set_fb_buffer(int id, unsigned long fb_paddr, BF_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_Y(y_crop), HW_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC); pre_write(pre, BF_PRE_CTRL_SDW_UPDATE(1), HW_PRE_CTRL_SET); - spin_unlock(&pre->lock); + spin_unlock_irqrestore(&pre->lock, lock_flags); return 0; } |