Skip to content

Commit f188b5e

Browse files
Andrew Murraygregkh
authored andcommitted
coresight: etm4x: Save/restore state across CPU low power states
Some hardware will ignore bit TRCPDCR.PU which is used to signal to hardware that power should not be removed from the trace unit. Let's mitigate against this by conditionally saving and restoring the trace unit state when the CPU enters low power states. This patchset introduces a firmware property named 'arm,coresight-loses-context-with-cpu' - when this is present the hardware state will be conditionally saved and restored. A module parameter 'pm_save_enable' is also introduced which can be configured to override the firmware property. This can be set to never allow save/restore or to conditionally allow it (only for self-hosted). The default value is determined by firmware. We avoid saving the hardware state when self-hosted coresight isn't in use to reduce PM latency - we can't determine this by reading the claim tags (TRCCLAIMCLR) as these are 'trace' registers which need power and clocking, something we can't easily provide in the PM context. Therefore we rely on the existing drvdata->mode internal state that is set when self-hosted coresight is used (and powered). Signed-off-by: Andrew Murray <andrew.murray@arm.com> Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org> Link: https://lore.kernel.org/r/20191104181251.26732-2-mathieu.poirier@linaro.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 891e603 commit f188b5e

File tree

4 files changed

+394
-0
lines changed

4 files changed

+394
-0
lines changed

drivers/hwtracing/coresight/coresight-etm4x.c

Lines changed: 318 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <linux/stat.h>
1919
#include <linux/clk.h>
2020
#include <linux/cpu.h>
21+
#include <linux/cpu_pm.h>
2122
#include <linux/coresight.h>
2223
#include <linux/coresight-pmu.h>
2324
#include <linux/pm_wakeup.h>
@@ -26,6 +27,7 @@
2627
#include <linux/uaccess.h>
2728
#include <linux/perf_event.h>
2829
#include <linux/pm_runtime.h>
30+
#include <linux/property.h>
2931
#include <asm/sections.h>
3032
#include <asm/local.h>
3133
#include <asm/virt.h>
@@ -37,6 +39,15 @@ static int boot_enable;
3739
module_param(boot_enable, int, 0444);
3840
MODULE_PARM_DESC(boot_enable, "Enable tracing on boot");
3941

42+
#define PARAM_PM_SAVE_FIRMWARE 0 /* save self-hosted state as per firmware */
43+
#define PARAM_PM_SAVE_NEVER 1 /* never save any state */
44+
#define PARAM_PM_SAVE_SELF_HOSTED 2 /* save self-hosted state only */
45+
46+
static int pm_save_enable = PARAM_PM_SAVE_FIRMWARE;
47+
module_param(pm_save_enable, int, 0444);
48+
MODULE_PARM_DESC(pm_save_enable,
49+
"Save/restore state on power down: 1 = never, 2 = self-hosted");
50+
4051
/* The number of ETMv4 currently registered */
4152
static int etm4_count;
4253
static struct etmv4_drvdata *etmdrvdata[NR_CPUS];
@@ -54,6 +65,14 @@ static void etm4_os_unlock(struct etmv4_drvdata *drvdata)
5465
isb();
5566
}
5667

68+
static void etm4_os_lock(struct etmv4_drvdata *drvdata)
69+
{
70+
/* Writing 0x1 to TRCOSLAR locks the trace registers */
71+
writel_relaxed(0x1, drvdata->base + TRCOSLAR);
72+
drvdata->os_unlock = false;
73+
isb();
74+
}
75+
5776
static bool etm4_arch_supported(u8 arch)
5877
{
5978
/* Mask out the minor version number */
@@ -1085,6 +1104,288 @@ static void etm4_init_trace_id(struct etmv4_drvdata *drvdata)
10851104
drvdata->trcid = coresight_get_trace_id(drvdata->cpu);
10861105
}
10871106

1107+
#ifdef CONFIG_CPU_PM
1108+
static int etm4_cpu_save(struct etmv4_drvdata *drvdata)
1109+
{
1110+
int i, ret = 0;
1111+
struct etmv4_save_state *state;
1112+
struct device *etm_dev = &drvdata->csdev->dev;
1113+
1114+
/*
1115+
* As recommended by 3.4.1 ("The procedure when powering down the PE")
1116+
* of ARM IHI 0064D
1117+
*/
1118+
dsb(sy);
1119+
isb();
1120+
1121+
CS_UNLOCK(drvdata->base);
1122+
1123+
/* Lock the OS lock to disable trace and external debugger access */
1124+
etm4_os_lock(drvdata);
1125+
1126+
/* wait for TRCSTATR.PMSTABLE to go up */
1127+
if (coresight_timeout(drvdata->base, TRCSTATR,
1128+
TRCSTATR_PMSTABLE_BIT, 1)) {
1129+
dev_err(etm_dev,
1130+
"timeout while waiting for PM Stable Status\n");
1131+
etm4_os_unlock(drvdata);
1132+
ret = -EBUSY;
1133+
goto out;
1134+
}
1135+
1136+
state = drvdata->save_state;
1137+
1138+
state->trcprgctlr = readl(drvdata->base + TRCPRGCTLR);
1139+
state->trcprocselr = readl(drvdata->base + TRCPROCSELR);
1140+
state->trcconfigr = readl(drvdata->base + TRCCONFIGR);
1141+
state->trcauxctlr = readl(drvdata->base + TRCAUXCTLR);
1142+
state->trceventctl0r = readl(drvdata->base + TRCEVENTCTL0R);
1143+
state->trceventctl1r = readl(drvdata->base + TRCEVENTCTL1R);
1144+
state->trcstallctlr = readl(drvdata->base + TRCSTALLCTLR);
1145+
state->trctsctlr = readl(drvdata->base + TRCTSCTLR);
1146+
state->trcsyncpr = readl(drvdata->base + TRCSYNCPR);
1147+
state->trcccctlr = readl(drvdata->base + TRCCCCTLR);
1148+
state->trcbbctlr = readl(drvdata->base + TRCBBCTLR);
1149+
state->trctraceidr = readl(drvdata->base + TRCTRACEIDR);
1150+
state->trcqctlr = readl(drvdata->base + TRCQCTLR);
1151+
1152+
state->trcvictlr = readl(drvdata->base + TRCVICTLR);
1153+
state->trcviiectlr = readl(drvdata->base + TRCVIIECTLR);
1154+
state->trcvissctlr = readl(drvdata->base + TRCVISSCTLR);
1155+
state->trcvipcssctlr = readl(drvdata->base + TRCVIPCSSCTLR);
1156+
state->trcvdctlr = readl(drvdata->base + TRCVDCTLR);
1157+
state->trcvdsacctlr = readl(drvdata->base + TRCVDSACCTLR);
1158+
state->trcvdarcctlr = readl(drvdata->base + TRCVDARCCTLR);
1159+
1160+
for (i = 0; i < drvdata->nrseqstate; i++)
1161+
state->trcseqevr[i] = readl(drvdata->base + TRCSEQEVRn(i));
1162+
1163+
state->trcseqrstevr = readl(drvdata->base + TRCSEQRSTEVR);
1164+
state->trcseqstr = readl(drvdata->base + TRCSEQSTR);
1165+
state->trcextinselr = readl(drvdata->base + TRCEXTINSELR);
1166+
1167+
for (i = 0; i < drvdata->nr_cntr; i++) {
1168+
state->trccntrldvr[i] = readl(drvdata->base + TRCCNTRLDVRn(i));
1169+
state->trccntctlr[i] = readl(drvdata->base + TRCCNTCTLRn(i));
1170+
state->trccntvr[i] = readl(drvdata->base + TRCCNTVRn(i));
1171+
}
1172+
1173+
for (i = 0; i < drvdata->nr_resource * 2; i++)
1174+
state->trcrsctlr[i] = readl(drvdata->base + TRCRSCTLRn(i));
1175+
1176+
for (i = 0; i < drvdata->nr_ss_cmp; i++) {
1177+
state->trcssccr[i] = readl(drvdata->base + TRCSSCCRn(i));
1178+
state->trcsscsr[i] = readl(drvdata->base + TRCSSCSRn(i));
1179+
state->trcsspcicr[i] = readl(drvdata->base + TRCSSPCICRn(i));
1180+
}
1181+
1182+
for (i = 0; i < drvdata->nr_addr_cmp * 2; i++) {
1183+
state->trcacvr[i] = readl(drvdata->base + TRCACVRn(i));
1184+
state->trcacatr[i] = readl(drvdata->base + TRCACATRn(i));
1185+
}
1186+
1187+
/*
1188+
* Data trace stream is architecturally prohibited for A profile cores
1189+
* so we don't save (or later restore) trcdvcvr and trcdvcmr - As per
1190+
* section 1.3.4 ("Possible functional configurations of an ETMv4 trace
1191+
* unit") of ARM IHI 0064D.
1192+
*/
1193+
1194+
for (i = 0; i < drvdata->numcidc; i++)
1195+
state->trccidcvr[i] = readl(drvdata->base + TRCCIDCVRn(i));
1196+
1197+
for (i = 0; i < drvdata->numvmidc; i++)
1198+
state->trcvmidcvr[i] = readl(drvdata->base + TRCVMIDCVRn(i));
1199+
1200+
state->trccidcctlr0 = readl(drvdata->base + TRCCIDCCTLR0);
1201+
state->trccidcctlr1 = readl(drvdata->base + TRCCIDCCTLR1);
1202+
1203+
state->trcvmidcctlr0 = readl(drvdata->base + TRCVMIDCCTLR0);
1204+
state->trcvmidcctlr0 = readl(drvdata->base + TRCVMIDCCTLR1);
1205+
1206+
state->trcclaimset = readl(drvdata->base + TRCCLAIMCLR);
1207+
1208+
state->trcpdcr = readl(drvdata->base + TRCPDCR);
1209+
1210+
/* wait for TRCSTATR.IDLE to go up */
1211+
if (coresight_timeout(drvdata->base, TRCSTATR, TRCSTATR_IDLE_BIT, 1)) {
1212+
dev_err(etm_dev,
1213+
"timeout while waiting for Idle Trace Status\n");
1214+
etm4_os_unlock(drvdata);
1215+
ret = -EBUSY;
1216+
goto out;
1217+
}
1218+
1219+
drvdata->state_needs_restore = true;
1220+
1221+
/*
1222+
* Power can be removed from the trace unit now. We do this to
1223+
* potentially save power on systems that respect the TRCPDCR_PU
1224+
* despite requesting software to save/restore state.
1225+
*/
1226+
writel_relaxed((state->trcpdcr & ~TRCPDCR_PU),
1227+
drvdata->base + TRCPDCR);
1228+
1229+
out:
1230+
CS_LOCK(drvdata->base);
1231+
return ret;
1232+
}
1233+
1234+
static void etm4_cpu_restore(struct etmv4_drvdata *drvdata)
1235+
{
1236+
int i;
1237+
struct etmv4_save_state *state = drvdata->save_state;
1238+
1239+
CS_UNLOCK(drvdata->base);
1240+
1241+
writel_relaxed(state->trcclaimset, drvdata->base + TRCCLAIMSET);
1242+
1243+
writel_relaxed(state->trcprgctlr, drvdata->base + TRCPRGCTLR);
1244+
writel_relaxed(state->trcprocselr, drvdata->base + TRCPROCSELR);
1245+
writel_relaxed(state->trcconfigr, drvdata->base + TRCCONFIGR);
1246+
writel_relaxed(state->trcauxctlr, drvdata->base + TRCAUXCTLR);
1247+
writel_relaxed(state->trceventctl0r, drvdata->base + TRCEVENTCTL0R);
1248+
writel_relaxed(state->trceventctl1r, drvdata->base + TRCEVENTCTL1R);
1249+
writel_relaxed(state->trcstallctlr, drvdata->base + TRCSTALLCTLR);
1250+
writel_relaxed(state->trctsctlr, drvdata->base + TRCTSCTLR);
1251+
writel_relaxed(state->trcsyncpr, drvdata->base + TRCSYNCPR);
1252+
writel_relaxed(state->trcccctlr, drvdata->base + TRCCCCTLR);
1253+
writel_relaxed(state->trcbbctlr, drvdata->base + TRCBBCTLR);
1254+
writel_relaxed(state->trctraceidr, drvdata->base + TRCTRACEIDR);
1255+
writel_relaxed(state->trcqctlr, drvdata->base + TRCQCTLR);
1256+
1257+
writel_relaxed(state->trcvictlr, drvdata->base + TRCVICTLR);
1258+
writel_relaxed(state->trcviiectlr, drvdata->base + TRCVIIECTLR);
1259+
writel_relaxed(state->trcvissctlr, drvdata->base + TRCVISSCTLR);
1260+
writel_relaxed(state->trcvipcssctlr, drvdata->base + TRCVIPCSSCTLR);
1261+
writel_relaxed(state->trcvdctlr, drvdata->base + TRCVDCTLR);
1262+
writel_relaxed(state->trcvdsacctlr, drvdata->base + TRCVDSACCTLR);
1263+
writel_relaxed(state->trcvdarcctlr, drvdata->base + TRCVDARCCTLR);
1264+
1265+
for (i = 0; i < drvdata->nrseqstate; i++)
1266+
writel_relaxed(state->trcseqevr[i],
1267+
drvdata->base + TRCSEQEVRn(i));
1268+
1269+
writel_relaxed(state->trcseqrstevr, drvdata->base + TRCSEQRSTEVR);
1270+
writel_relaxed(state->trcseqstr, drvdata->base + TRCSEQSTR);
1271+
writel_relaxed(state->trcextinselr, drvdata->base + TRCEXTINSELR);
1272+
1273+
for (i = 0; i < drvdata->nr_cntr; i++) {
1274+
writel_relaxed(state->trccntrldvr[i],
1275+
drvdata->base + TRCCNTRLDVRn(i));
1276+
writel_relaxed(state->trccntctlr[i],
1277+
drvdata->base + TRCCNTCTLRn(i));
1278+
writel_relaxed(state->trccntvr[i],
1279+
drvdata->base + TRCCNTVRn(i));
1280+
}
1281+
1282+
for (i = 0; i < drvdata->nr_resource * 2; i++)
1283+
writel_relaxed(state->trcrsctlr[i],
1284+
drvdata->base + TRCRSCTLRn(i));
1285+
1286+
for (i = 0; i < drvdata->nr_ss_cmp; i++) {
1287+
writel_relaxed(state->trcssccr[i],
1288+
drvdata->base + TRCSSCCRn(i));
1289+
writel_relaxed(state->trcsscsr[i],
1290+
drvdata->base + TRCSSCSRn(i));
1291+
writel_relaxed(state->trcsspcicr[i],
1292+
drvdata->base + TRCSSPCICRn(i));
1293+
}
1294+
1295+
for (i = 0; i < drvdata->nr_addr_cmp * 2; i++) {
1296+
writel_relaxed(state->trcacvr[i],
1297+
drvdata->base + TRCACVRn(i));
1298+
writel_relaxed(state->trcacatr[i],
1299+
drvdata->base + TRCACATRn(i));
1300+
}
1301+
1302+
for (i = 0; i < drvdata->numcidc; i++)
1303+
writel_relaxed(state->trccidcvr[i],
1304+
drvdata->base + TRCCIDCVRn(i));
1305+
1306+
for (i = 0; i < drvdata->numvmidc; i++)
1307+
writel_relaxed(state->trcvmidcvr[i],
1308+
drvdata->base + TRCVMIDCVRn(i));
1309+
1310+
writel_relaxed(state->trccidcctlr0, drvdata->base + TRCCIDCCTLR0);
1311+
writel_relaxed(state->trccidcctlr1, drvdata->base + TRCCIDCCTLR1);
1312+
1313+
writel_relaxed(state->trcvmidcctlr0, drvdata->base + TRCVMIDCCTLR0);
1314+
writel_relaxed(state->trcvmidcctlr0, drvdata->base + TRCVMIDCCTLR1);
1315+
1316+
writel_relaxed(state->trcclaimset, drvdata->base + TRCCLAIMSET);
1317+
1318+
writel_relaxed(state->trcpdcr, drvdata->base + TRCPDCR);
1319+
1320+
drvdata->state_needs_restore = false;
1321+
1322+
/*
1323+
* As recommended by section 4.3.7 ("Synchronization when using the
1324+
* memory-mapped interface") of ARM IHI 0064D
1325+
*/
1326+
dsb(sy);
1327+
isb();
1328+
1329+
/* Unlock the OS lock to re-enable trace and external debug access */
1330+
etm4_os_unlock(drvdata);
1331+
CS_LOCK(drvdata->base);
1332+
}
1333+
1334+
static int etm4_cpu_pm_notify(struct notifier_block *nb, unsigned long cmd,
1335+
void *v)
1336+
{
1337+
struct etmv4_drvdata *drvdata;
1338+
unsigned int cpu = smp_processor_id();
1339+
1340+
if (!etmdrvdata[cpu])
1341+
return NOTIFY_OK;
1342+
1343+
drvdata = etmdrvdata[cpu];
1344+
1345+
if (!drvdata->save_state)
1346+
return NOTIFY_OK;
1347+
1348+
if (WARN_ON_ONCE(drvdata->cpu != cpu))
1349+
return NOTIFY_BAD;
1350+
1351+
switch (cmd) {
1352+
case CPU_PM_ENTER:
1353+
/* save the state if self-hosted coresight is in use */
1354+
if (local_read(&drvdata->mode))
1355+
if (etm4_cpu_save(drvdata))
1356+
return NOTIFY_BAD;
1357+
break;
1358+
case CPU_PM_EXIT:
1359+
/* fallthrough */
1360+
case CPU_PM_ENTER_FAILED:
1361+
if (drvdata->state_needs_restore)
1362+
etm4_cpu_restore(drvdata);
1363+
break;
1364+
default:
1365+
return NOTIFY_DONE;
1366+
}
1367+
1368+
return NOTIFY_OK;
1369+
}
1370+
1371+
static struct notifier_block etm4_cpu_pm_nb = {
1372+
.notifier_call = etm4_cpu_pm_notify,
1373+
};
1374+
1375+
static int etm4_cpu_pm_register(void)
1376+
{
1377+
return cpu_pm_register_notifier(&etm4_cpu_pm_nb);
1378+
}
1379+
1380+
static void etm4_cpu_pm_unregister(void)
1381+
{
1382+
cpu_pm_unregister_notifier(&etm4_cpu_pm_nb);
1383+
}
1384+
#else
1385+
static int etm4_cpu_pm_register(void) { return 0; }
1386+
static void etm4_cpu_pm_unregister(void) { }
1387+
#endif
1388+
10881389
static int etm4_probe(struct amba_device *adev, const struct amba_id *id)
10891390
{
10901391
int ret;
@@ -1101,6 +1402,17 @@ static int etm4_probe(struct amba_device *adev, const struct amba_id *id)
11011402

11021403
dev_set_drvdata(dev, drvdata);
11031404

1405+
if (pm_save_enable == PARAM_PM_SAVE_FIRMWARE)
1406+
pm_save_enable = coresight_loses_context_with_cpu(dev) ?
1407+
PARAM_PM_SAVE_SELF_HOSTED : PARAM_PM_SAVE_NEVER;
1408+
1409+
if (pm_save_enable != PARAM_PM_SAVE_NEVER) {
1410+
drvdata->save_state = devm_kmalloc(dev,
1411+
sizeof(struct etmv4_save_state), GFP_KERNEL);
1412+
if (!drvdata->save_state)
1413+
return -ENOMEM;
1414+
}
1415+
11041416
/* Validity for the resource is already checked by the AMBA core */
11051417
base = devm_ioremap_resource(dev, res);
11061418
if (IS_ERR(base))
@@ -1135,6 +1447,10 @@ static int etm4_probe(struct amba_device *adev, const struct amba_id *id)
11351447
if (ret < 0)
11361448
goto err_arch_supported;
11371449
hp_online = ret;
1450+
1451+
ret = etm4_cpu_pm_register();
1452+
if (ret)
1453+
goto err_arch_supported;
11381454
}
11391455

11401456
cpus_read_unlock();
@@ -1185,6 +1501,8 @@ static int etm4_probe(struct amba_device *adev, const struct amba_id *id)
11851501

11861502
err_arch_supported:
11871503
if (--etm4_count == 0) {
1504+
etm4_cpu_pm_unregister();
1505+
11881506
cpuhp_remove_state_nocalls(CPUHP_AP_ARM_CORESIGHT_STARTING);
11891507
if (hp_online)
11901508
cpuhp_remove_state_nocalls(hp_online);

0 commit comments

Comments
 (0)