coresight: resolve pcsave and etm tracing concurreny issue

Always clear ETMCR[pwrdwn] while enabling trace. This is used as
a logic enable and is a pre-requisite while enabling trace. So
switch to an implementation that does this and removes the save
and restore for pwrdwn and pwrup.

Change-Id: I8a14efe8fd76368ed1e177a701013a504aa1876f
Signed-off-by: Pratik Patel <pratikp@codeaurora.org>
This commit is contained in:
Pratik Patel 2012-10-19 16:19:12 -07:00 committed by Iliyan Malchev
parent 72ae7be066
commit 807d04fd7d

View file

@ -195,6 +195,7 @@ struct etm_drvdata {
struct wake_lock wake_lock;
int cpu;
uint8_t arch;
bool enable;
uint8_t nr_addr_cmp;
uint8_t nr_cntr;
uint8_t nr_ext_inp;
@ -203,7 +204,6 @@ struct etm_drvdata {
uint8_t reset;
uint32_t mode;
uint32_t ctrl;
uint8_t ctrl_pwrdwn;
uint32_t trigger_event;
uint32_t startstop_ctrl;
uint32_t enable_event;
@ -230,7 +230,6 @@ struct etm_drvdata {
uint32_t ctxid_mask;
uint32_t sync_freq;
uint32_t timestamp_event;
uint8_t pdcr_pwrup;
bool pcsave_impl;
bool pcsave_enable;
};
@ -339,48 +338,18 @@ static void etm_clr_prog(struct etm_drvdata *drvdata)
etm_readl(drvdata, ETMSR));
}
static void etm_save_pwrdwn(struct etm_drvdata *drvdata)
{
drvdata->ctrl_pwrdwn = BVAL(etm_readl(drvdata, ETMCR), 0);
}
static void etm_restore_pwrdwn(struct etm_drvdata *drvdata)
{
uint32_t etmcr;
etmcr = etm_readl(drvdata, ETMCR);
etmcr = (etmcr & ~BIT(0)) | drvdata->ctrl_pwrdwn;
etm_writel(drvdata, etmcr, ETMCR);
}
static void etm_save_pwrup(struct etm_drvdata *drvdata)
{
drvdata->pdcr_pwrup = BVAL(etm_readl_mm(drvdata, ETMPDCR), 3);
}
static void etm_restore_pwrup(struct etm_drvdata *drvdata)
{
uint32_t etmpdcr;
etmpdcr = etm_readl_mm(drvdata, ETMPDCR);
etmpdcr = (etmpdcr & ~BIT(3)) | (drvdata->pdcr_pwrup << 3);
etm_writel_mm(drvdata, etmpdcr, ETMPDCR);
}
static void etm_enable_pcsave(void *info)
{
struct etm_drvdata *drvdata = info;
ETM_UNLOCK(drvdata);
etm_save_pwrup(drvdata);
/*
* ETMPDCR is only accessible via memory mapped interface and so use
* it first to enable power/clock to allow subsequent cp14 accesses.
*/
etm_set_pwrup(drvdata);
etm_clr_pwrdwn(drvdata);
etm_restore_pwrup(drvdata);
ETM_LOCK(drvdata);
}
@ -391,14 +360,10 @@ static void etm_disable_pcsave(void *info)
ETM_UNLOCK(drvdata);
etm_save_pwrup(drvdata);
/*
* ETMPDCR is only accessible via memory mapped interface and so use
* it first to enable power/clock to allow subsequent cp14 accesses.
*/
etm_set_pwrup(drvdata);
etm_set_pwrdwn(drvdata);
etm_restore_pwrup(drvdata);
if (!drvdata->enable) {
etm_set_pwrdwn(drvdata);
etm_clr_pwrup(drvdata);
}
ETM_LOCK(drvdata);
}
@ -416,10 +381,10 @@ static void __etm_enable(void *info)
* to allow subsequent cp14 accesses.
*/
etm_set_pwrup(drvdata);
etm_save_pwrdwn(drvdata);
/*
* Clear power down bit since when this bit is set writes to
* certain registers might be ignored.
* certain registers might be ignored. This is also a pre-requisite
* for trace enable.
*/
etm_clr_pwrdwn(drvdata);
etm_set_prog(drvdata);
@ -463,7 +428,6 @@ static void __etm_enable(void *info)
etm_writel(drvdata, 0x00000000, ETMVMIDCVR);
etm_clr_prog(drvdata);
etm_restore_pwrdwn(drvdata);
ETM_LOCK(drvdata);
dev_dbg(drvdata->dev, "cpu: %d enable smp call done\n", drvdata->cpu);
@ -481,10 +445,12 @@ static int etm_enable(struct coresight_device *csdev)
goto err_clk;
mutex_lock(&drvdata->mutex);
/* executing __etm_enable on the cpu whose ETM is being enabled
/*
* Executing __etm_enable on the cpu whose ETM is being enabled
* ensures that register writes occur when cpu is powered.
*/
smp_call_function_single(drvdata->cpu, __etm_enable, drvdata, 1);
drvdata->enable = true;
mutex_unlock(&drvdata->mutex);
wake_unlock(&drvdata->wake_lock);
@ -501,20 +467,15 @@ static void __etm_disable(void *info)
struct etm_drvdata *drvdata = info;
ETM_UNLOCK(drvdata);
etm_save_pwrdwn(drvdata);
/*
* Clear power down bit since when this bit is set writes to
* certain registers might be ignored.
*/
etm_clr_pwrdwn(drvdata);
etm_set_prog(drvdata);
/* program trace enable to low by using always false event */
etm_writel(drvdata, 0x6F | BIT(14), ETMTEEVR);
etm_restore_pwrdwn(drvdata);
/* Vote for ETM power/clock disable */
etm_clr_pwrup(drvdata);
if (!drvdata->pcsave_enable) {
etm_set_pwrdwn(drvdata);
etm_clr_pwrup(drvdata);
}
ETM_LOCK(drvdata);
dev_dbg(drvdata->dev, "cpu: %d disable smp call done\n", drvdata->cpu);
@ -527,10 +488,12 @@ static void etm_disable(struct coresight_device *csdev)
wake_lock(&drvdata->wake_lock);
mutex_lock(&drvdata->mutex);
/* executing __etm_disable on the cpu whose ETM is being disabled
/*
* Executing __etm_disable on the cpu whose ETM is being disabled
* ensures that register writes occur when cpu is powered.
*/
smp_call_function_single(drvdata->cpu, __etm_disable, drvdata, 1);
drvdata->enable = false;
mutex_unlock(&drvdata->mutex);
clk_disable_unprepare(drvdata->clk);
@ -1677,7 +1640,6 @@ static void __devinit etm_init_arch_data(void *info)
drvdata->nr_ctxid_cmp = BMVAL(etmccr, 24, 25);
etm_set_pwrdwn(drvdata);
/* Vote for ETM power/clock disable */
etm_clr_pwrup(drvdata);
ETM_LOCK(drvdata);
}