mirror of
https://github.com/torvalds/linux.git
synced 2026-06-08 06:25:52 +02:00
vcodec: fix enable race condition when power on/off
When multi-instances power on at same time the condition enabled maybe set mutli-times. Use atomic function to replace orginal read/compare/change operation to avoid multi-instances. Also add power on/off count to debugfs for checking Signed-off-by: Herman Chen <herman.chen@rock-chips.com>
This commit is contained in:
parent
8967167af2
commit
41dad664eb
|
|
@ -416,7 +416,9 @@ typedef struct vpu_service_info {
|
|||
struct list_head done; /* link to link_reg in struct vpu_reg */
|
||||
struct list_head session; /* link to list_session in struct vpu_session */
|
||||
atomic_t total_running;
|
||||
bool enabled;
|
||||
atomic_t enabled;
|
||||
atomic_t power_on_cnt;
|
||||
atomic_t power_off_cnt;
|
||||
vpu_reg *reg_codec;
|
||||
vpu_reg *reg_pproc;
|
||||
vpu_reg *reg_resev;
|
||||
|
|
@ -522,9 +524,10 @@ static void vcodec_enter_mode(struct vpu_subdev_data *data)
|
|||
#if defined(CONFIG_VCODEC_MMU)
|
||||
if (data->mmu_dev && !test_bit(MMU_ACTIVATED, &data->state)) {
|
||||
set_bit(MMU_ACTIVATED, &data->state);
|
||||
BUG_ON(!pservice->enabled);
|
||||
if (pservice->enabled)
|
||||
if (atomic_read(&pservice->enabled))
|
||||
rockchip_iovmm_activate(data->dev);
|
||||
else
|
||||
BUG_ON(!atomic_read(&pservice->enabled));
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
|
|
@ -565,9 +568,10 @@ static void vcodec_enter_mode(struct vpu_subdev_data *data)
|
|||
#if defined(CONFIG_VCODEC_MMU)
|
||||
if (data->mmu_dev && !test_bit(MMU_ACTIVATED, &data->state)) {
|
||||
set_bit(MMU_ACTIVATED, &data->state);
|
||||
BUG_ON(!pservice->enabled);
|
||||
if (pservice->enabled)
|
||||
if (atomic_read(&pservice->enabled))
|
||||
rockchip_iovmm_activate(data->dev);
|
||||
else
|
||||
BUG_ON(!atomic_read(&pservice->enabled));
|
||||
}
|
||||
#endif
|
||||
pservice->prev_mode = pservice->curr_mode;
|
||||
|
|
@ -618,8 +622,10 @@ static int vpu_get_clk(struct vpu_service_info *pservice)
|
|||
}
|
||||
if (pservice->pd_video == NULL) {
|
||||
pservice->pd_video = devm_clk_get(pservice->dev, "pd_video");
|
||||
if (IS_ERR(pservice->pd_video))
|
||||
if (IS_ERR(pservice->pd_video)) {
|
||||
pservice->pd_video = NULL;
|
||||
dev_info(pservice->dev, "do not have pd_video\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
@ -683,9 +689,10 @@ static void vpu_reset(struct vpu_subdev_data *data)
|
|||
#if defined(CONFIG_VCODEC_MMU)
|
||||
if (data->mmu_dev && test_bit(MMU_ACTIVATED, &data->state)) {
|
||||
clear_bit(MMU_ACTIVATED, &data->state);
|
||||
BUG_ON(!pservice->enabled);
|
||||
if (pservice->enabled)
|
||||
if (atomic_read(&pservice->enabled))
|
||||
rockchip_iovmm_deactivate(data->dev);
|
||||
else
|
||||
BUG_ON(!atomic_read(&pservice->enabled));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
@ -713,10 +720,10 @@ static void vpu_service_power_off(struct vpu_service_info *pservice)
|
|||
{
|
||||
int total_running;
|
||||
struct vpu_subdev_data *data = NULL, *n;
|
||||
if (!pservice->enabled)
|
||||
int ret = atomic_add_unless(&pservice->enabled, -1, 0);
|
||||
if (!ret)
|
||||
return;
|
||||
|
||||
pservice->enabled = false;
|
||||
total_running = atomic_read(&pservice->total_running);
|
||||
if (total_running) {
|
||||
pr_alert("alert: power off when %d task running!!\n", total_running);
|
||||
|
|
@ -750,6 +757,7 @@ static void vpu_service_power_off(struct vpu_service_info *pservice)
|
|||
clk_disable_unprepare(pservice->clk_cabac);
|
||||
#endif
|
||||
|
||||
atomic_add(1, &pservice->power_off_cnt);
|
||||
wake_unlock(&pservice->wake_lock);
|
||||
pr_info("done\n");
|
||||
}
|
||||
|
|
@ -775,6 +783,7 @@ static void vpu_power_off_work(struct work_struct *work_s)
|
|||
|
||||
static void vpu_service_power_on(struct vpu_service_info *pservice)
|
||||
{
|
||||
int ret;
|
||||
static ktime_t last;
|
||||
ktime_t now = ktime_get();
|
||||
if (ktime_to_ns(ktime_sub(now, last)) > NSEC_PER_SEC) {
|
||||
|
|
@ -782,7 +791,8 @@ static void vpu_service_power_on(struct vpu_service_info *pservice)
|
|||
vpu_queue_power_off_work(pservice);
|
||||
last = now;
|
||||
}
|
||||
if (pservice->enabled)
|
||||
ret = atomic_add_unless(&pservice->enabled, 1, 1);
|
||||
if (!ret)
|
||||
return ;
|
||||
|
||||
pr_info("%s: power on\n", dev_name(pservice->dev));
|
||||
|
|
@ -807,7 +817,7 @@ static void vpu_service_power_on(struct vpu_service_info *pservice)
|
|||
#endif
|
||||
|
||||
udelay(10);
|
||||
pservice->enabled = true;
|
||||
atomic_add(1, &pservice->power_on_cnt);
|
||||
wake_lock(&pservice->wake_lock);
|
||||
}
|
||||
|
||||
|
|
@ -2163,7 +2173,9 @@ static void vcodec_init_drvdata(struct vpu_service_info *pservice)
|
|||
|
||||
pservice->reg_pproc = NULL;
|
||||
atomic_set(&pservice->total_running, 0);
|
||||
pservice->enabled = false;
|
||||
atomic_set(&pservice->enabled, 0);
|
||||
atomic_set(&pservice->power_on_cnt, 0);
|
||||
atomic_set(&pservice->power_off_cnt, 0);
|
||||
|
||||
INIT_DELAYED_WORK(&pservice->power_off_work, vpu_power_off_work);
|
||||
|
||||
|
|
@ -2596,7 +2608,12 @@ static int debug_vcodec_show(struct seq_file *s, void *unused)
|
|||
seq_printf(s, "done register set\n");
|
||||
}
|
||||
}
|
||||
|
||||
seq_printf(s, "\npower counter: on %d off %d\n",
|
||||
atomic_read(&pservice->power_on_cnt),
|
||||
atomic_read(&pservice->power_off_cnt));
|
||||
mutex_unlock(&pservice->lock);
|
||||
vpu_service_power_off(pservice);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user