coresight: don't call clk apis from atomic context

Rearrange CTI clock voting to avoid calling clk_prepare_enable
and clk_disable_unprepare apis from atomic context. This will
prevent scheduling while in atomic context.

Change-Id: I0b8a484cb38d67255dc6f0ba7c6162252d1f0c8e
Signed-off-by: Pratik Patel <pratikp@codeaurora.org>
This commit is contained in:
Pratik Patel 2014-10-13 13:52:08 -07:00
parent 2d3171d729
commit 7490eb5e7f
1 changed files with 82 additions and 40 deletions

View File

@ -222,20 +222,13 @@ out:
}
EXPORT_SYMBOL(coresight_cti_ctx_restore);
static int cti_enable(struct cti_drvdata *drvdata)
static void cti_enable(struct cti_drvdata *drvdata)
{
int ret;
ret = clk_prepare_enable(drvdata->clk);
if (ret)
return ret;
CTI_UNLOCK(drvdata);
cti_writel(drvdata, 0x1, CTICONTROL);
CTI_LOCK(drvdata);
return 0;
}
int cti_trigin_gpio_enable(struct cti_drvdata *drvdata)
@ -330,16 +323,12 @@ void cti_trigout_gpio_disable(struct cti_drvdata *drvdata)
drvdata->gpio_trigout->pctrl = NULL;
}
static int __cti_map_trigin(struct cti_drvdata *drvdata, int trig, int ch)
static void __cti_map_trigin(struct cti_drvdata *drvdata, int trig, int ch)
{
uint32_t ctien;
int ret;
if (drvdata->refcnt == 0) {
ret = cti_enable(drvdata);
if (ret)
return ret;
}
if (drvdata->refcnt == 0)
cti_enable(drvdata);
CTI_UNLOCK(drvdata);
@ -351,10 +340,9 @@ static int __cti_map_trigin(struct cti_drvdata *drvdata, int trig, int ch)
CTI_LOCK(drvdata);
drvdata->refcnt++;
return 0;
return;
out:
CTI_LOCK(drvdata);
return 0;
}
int coresight_cti_map_trigin(struct coresight_cti *cti, int trig, int ch)
@ -382,18 +370,36 @@ int coresight_cti_map_trigin(struct coresight_cti *cti, int trig, int ch)
goto err0;
}
/*
* refcnt can be used here since in all cases its value is modified only
* within the mutex lock region in addition to within the spinlock.
*/
if (drvdata->refcnt == 0) {
ret = clk_prepare_enable(drvdata->clk);
if (ret)
goto err1;
}
spin_lock_irqsave(&drvdata->spinlock, flag);
ret = cti_cpu_verify_access(drvdata);
if (ret)
goto err1;
goto err2;
ret = __cti_map_trigin(drvdata, trig, ch);
__cti_map_trigin(drvdata, trig, ch);
spin_unlock_irqrestore(&drvdata->spinlock, flag);
mutex_unlock(&drvdata->mutex);
return 0;
err1:
err2:
spin_unlock_irqrestore(&drvdata->spinlock, flag);
/*
* We come here before refcnt is potentially modified in
* __cti_map_trigin so it is safe to check it against 0 without
* adjusting its value.
*/
if (drvdata->refcnt == 0)
clk_disable_unprepare(drvdata->clk);
err1:
cti_trigin_gpio_disable(drvdata);
err0:
mutex_unlock(&drvdata->mutex);
@ -401,16 +407,12 @@ err0:
}
EXPORT_SYMBOL(coresight_cti_map_trigin);
static int __cti_map_trigout(struct cti_drvdata *drvdata, int trig, int ch)
static void __cti_map_trigout(struct cti_drvdata *drvdata, int trig, int ch)
{
uint32_t ctien;
int ret;
if (drvdata->refcnt == 0) {
ret = cti_enable(drvdata);
if (ret)
return ret;
}
if (drvdata->refcnt == 0)
cti_enable(drvdata);
CTI_UNLOCK(drvdata);
@ -422,10 +424,9 @@ static int __cti_map_trigout(struct cti_drvdata *drvdata, int trig, int ch)
CTI_LOCK(drvdata);
drvdata->refcnt++;
return 0;
return;
out:
CTI_LOCK(drvdata);
return 0;
}
int coresight_cti_map_trigout(struct coresight_cti *cti, int trig, int ch)
@ -453,18 +454,35 @@ int coresight_cti_map_trigout(struct coresight_cti *cti, int trig, int ch)
goto err0;
}
/*
* refcnt can be used here since in all cases its value is modified only
* within the mutex lock region in addition to within the spinlock.
*/
if (drvdata->refcnt == 0) {
ret = clk_prepare_enable(drvdata->clk);
if (ret)
goto err1;
}
spin_lock_irqsave(&drvdata->spinlock, flag);
ret = cti_cpu_verify_access(drvdata);
if (ret)
goto err1;
goto err2;
ret = __cti_map_trigout(drvdata, trig, ch);
__cti_map_trigout(drvdata, trig, ch);
spin_unlock_irqrestore(&drvdata->spinlock, flag);
mutex_unlock(&drvdata->mutex);
return 0;
err1:
err2:
spin_unlock_irqrestore(&drvdata->spinlock, flag);
/*
* We come here before refcnt is potentially incremented in
* __cti_map_trigout so it is safe to check it against 0.
*/
if (drvdata->refcnt == 0)
clk_disable_unprepare(drvdata->clk);
err1:
cti_trigout_gpio_disable(drvdata);
err0:
mutex_unlock(&drvdata->mutex);
@ -483,8 +501,6 @@ static void cti_disable(struct cti_drvdata *drvdata)
cti_writel(drvdata, 0x0, CTICONTROL);
CTI_LOCK(drvdata);
clk_disable_unprepare(drvdata->clk);
}
static void __cti_unmap_trigin(struct cti_drvdata *drvdata, int trig, int ch)
@ -500,13 +516,13 @@ static void __cti_unmap_trigin(struct cti_drvdata *drvdata, int trig, int ch)
CTI_LOCK(drvdata);
if (drvdata->refcnt == 1)
cti_disable(drvdata);
drvdata->refcnt--;
if (drvdata->refcnt == 0)
cti_disable(drvdata);
return;
out:
CTI_LOCK(drvdata);
return;
}
void coresight_cti_unmap_trigin(struct coresight_cti *cti, int trig, int ch)
@ -528,10 +544,23 @@ void coresight_cti_unmap_trigin(struct coresight_cti *cti, int trig, int ch)
spin_lock_irqsave(&drvdata->spinlock, flag);
if (cti_cpu_verify_access(drvdata))
goto err;
/*
* This is required to avoid clk_disable_unprepare call from being made
* when unmap is called without the corresponding map function call.
*/
if (!drvdata->refcnt)
goto err;
__cti_unmap_trigin(drvdata, trig, ch);
spin_unlock_irqrestore(&drvdata->spinlock, flag);
/*
* refcnt can be used here since in all cases its value is modified only
* within the mutex lock region in addition to within the spinlock.
*/
if (drvdata->refcnt == 0)
clk_disable_unprepare(drvdata->clk);
if (drvdata->gpio_trigin->trig == trig)
cti_trigin_gpio_disable(drvdata);
@ -556,13 +585,13 @@ static void __cti_unmap_trigout(struct cti_drvdata *drvdata, int trig, int ch)
CTI_LOCK(drvdata);
if (drvdata->refcnt == 1)
cti_disable(drvdata);
drvdata->refcnt--;
if (drvdata->refcnt == 0)
cti_disable(drvdata);
return;
out:
CTI_LOCK(drvdata);
return;
}
void coresight_cti_unmap_trigout(struct coresight_cti *cti, int trig, int ch)
@ -584,10 +613,23 @@ void coresight_cti_unmap_trigout(struct coresight_cti *cti, int trig, int ch)
spin_lock_irqsave(&drvdata->spinlock, flag);
if (cti_cpu_verify_access(drvdata))
goto err;
/*
* This is required to avoid clk_disable_unprepare call from being made
* when unmap is called without the corresponding map function call.
*/
if (!drvdata->refcnt)
goto err;
__cti_unmap_trigout(drvdata, trig, ch);
spin_unlock_irqrestore(&drvdata->spinlock, flag);
/*
* refcnt can be used here since in all cases its value is modified only
* within the mutex lock region in addition to within the spinlock.
*/
if (drvdata->refcnt == 0)
clk_disable_unprepare(drvdata->clk);
if (drvdata->gpio_trigout->trig == trig)
cti_trigout_gpio_disable(drvdata);