Unverified Commit 5cdf8021 authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!11478 coresight: etm4x: Fix CPU idle PM support for ETE

Merge Pull Request from: @ci-robot 
 
PR sync from: Junhao He <hejunhao3@huawei.com>
https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/INFZMM7UEFVK5DEGVSZKHFO6JAEWFCLD/ 
Our CPUidle state save restore has some bugs which are triggered for an ETM with
system instructions (e.g. ETE). This is a series of fixes to address them.

Add CPU hotplug support for probing.

Suzuki K Poulose (4):
  coresight: etm4x: Do not hardcode IOMEM access for register restore
  coresight: etm4x: Do not save/restore Data trace control registers
  coresight: etm4x: Safe access for TRCQCLTR
  coresight: etm4x: Fix access to resource selector registers

Tamas Zsoldos (1):
  coresight: etm4x: add CPU hotplug support for probing


-- 
2.33.0
 
https://gitee.com/openeuler/kernel/issues/IAKVFA 
 
Link:https://gitee.com/openeuler/kernel/pulls/11478

 

Signed-off-by: default avatarYang Yingliang <yangyingliang@huawei.com>
parents a6042799 00e07787
Loading
Loading
Loading
Loading
+117 −45
Original line number Diff line number Diff line
@@ -65,10 +65,13 @@ static u64 etm4_get_access_type(struct etmv4_config *config);
static enum cpuhp_state hp_online;

struct etm4_init_arg {
	struct etmv4_drvdata	*drvdata;
	struct device		*dev;
	struct csdev_access	*csa;
};

static DEFINE_PER_CPU(struct etm4_init_arg *, delayed_probe);
static int etm4_probe_cpu(unsigned int cpu);

u64 etm4x_sysreg_read(u32 offset, bool _relaxed, bool _64bit)
{
	u64 res = 0;
@@ -1064,7 +1067,7 @@ static void etm4_init_arch_data(void *info)
	struct csdev_access *csa;
	int i;

	drvdata = init_arg->drvdata;
	drvdata = dev_get_drvdata(init_arg->dev);
	csa = init_arg->csa;

	/*
@@ -1119,6 +1122,8 @@ static void etm4_init_arch_data(void *info)
	drvdata->nr_event = BMVAL(etmidr0, 10, 11);
	/* QSUPP, bits[16:15] Q element support field */
	drvdata->q_support = BMVAL(etmidr0, 15, 16);
	if (drvdata->q_support)
		drvdata->q_filt = BMVAL(etmidr0, 14, 14);
	/* TSSIZE, bits[28:24] Global timestamp size field */
	drvdata->ts_size = BMVAL(etmidr0, 24, 28);

@@ -1553,7 +1558,7 @@ void etm4_config_trace_mode(struct etmv4_config *config)
static int etm4_online_cpu(unsigned int cpu)
{
	if (!etmdrvdata[cpu])
		return 0;
		return etm4_probe_cpu(cpu);

	if (etmdrvdata[cpu]->boot_enable && !etmdrvdata[cpu]->sticky_enable)
		coresight_enable(etmdrvdata[cpu]->csdev);
@@ -1642,6 +1647,7 @@ static int __etm4_cpu_save(struct etmv4_drvdata *drvdata)
	state->trcccctlr = etm4x_read32(csa, TRCCCCTLR);
	state->trcbbctlr = etm4x_read32(csa, TRCBBCTLR);
	state->trctraceidr = etm4x_read32(csa, TRCTRACEIDR);
	if (drvdata->q_filt)
		state->trcqctlr = etm4x_read32(csa, TRCQCTLR);

	state->trcvictlr = etm4x_read32(csa, TRCVICTLR);
@@ -1649,9 +1655,6 @@ static int __etm4_cpu_save(struct etmv4_drvdata *drvdata)
	state->trcvissctlr = etm4x_read32(csa, TRCVISSCTLR);
	if (drvdata->nr_pe_cmp)
		state->trcvipcssctlr = etm4x_read32(csa, TRCVIPCSSCTLR);
	state->trcvdctlr = etm4x_read32(csa, TRCVDCTLR);
	state->trcvdsacctlr = etm4x_read32(csa, TRCVDSACCTLR);
	state->trcvdarcctlr = etm4x_read32(csa, TRCVDARCCTLR);

	for (i = 0; i < drvdata->nrseqstate - 1; i++)
		state->trcseqevr[i] = etm4x_read32(csa, TRCSEQEVRn(i));
@@ -1668,7 +1671,8 @@ static int __etm4_cpu_save(struct etmv4_drvdata *drvdata)
		state->trccntvr[i] = etm4x_read32(csa, TRCCNTVRn(i));
	}

	for (i = 0; i < drvdata->nr_resource * 2; i++)
	/* Resource selector pair 0 is reserved */
	for (i = 2; i < drvdata->nr_resource * 2; i++)
		state->trcrsctlr[i] = etm4x_read32(csa, TRCRSCTLRn(i));

	for (i = 0; i < drvdata->nr_ss_cmp; i++) {
@@ -1752,8 +1756,10 @@ static void __etm4_cpu_restore(struct etmv4_drvdata *drvdata)
{
	int i;
	struct etmv4_save_state *state = drvdata->save_state;
	struct csdev_access tmp_csa = CSDEV_ACCESS_IOMEM(drvdata->base);
	struct csdev_access *csa = &tmp_csa;
	struct csdev_access *csa = &drvdata->csdev->access;

	if (WARN_ON(!drvdata->csdev))
		return;

	etm4_cs_unlock(drvdata, csa);
	etm4x_relaxed_write32(csa, state->trcclaimset, TRCCLAIMSET);
@@ -1772,6 +1778,7 @@ static void __etm4_cpu_restore(struct etmv4_drvdata *drvdata)
	etm4x_relaxed_write32(csa, state->trcccctlr, TRCCCCTLR);
	etm4x_relaxed_write32(csa, state->trcbbctlr, TRCBBCTLR);
	etm4x_relaxed_write32(csa, state->trctraceidr, TRCTRACEIDR);
	if (drvdata->q_filt)
		etm4x_relaxed_write32(csa, state->trcqctlr, TRCQCTLR);

	etm4x_relaxed_write32(csa, state->trcvictlr, TRCVICTLR);
@@ -1779,9 +1786,6 @@ static void __etm4_cpu_restore(struct etmv4_drvdata *drvdata)
	etm4x_relaxed_write32(csa, state->trcvissctlr, TRCVISSCTLR);
	if (drvdata->nr_pe_cmp)
		etm4x_relaxed_write32(csa, state->trcvipcssctlr, TRCVIPCSSCTLR);
	etm4x_relaxed_write32(csa, state->trcvdctlr, TRCVDCTLR);
	etm4x_relaxed_write32(csa, state->trcvdsacctlr, TRCVDSACCTLR);
	etm4x_relaxed_write32(csa, state->trcvdarcctlr, TRCVDARCCTLR);

	for (i = 0; i < drvdata->nrseqstate - 1; i++)
		etm4x_relaxed_write32(csa, state->trcseqevr[i], TRCSEQEVRn(i));
@@ -1798,7 +1802,8 @@ static void __etm4_cpu_restore(struct etmv4_drvdata *drvdata)
		etm4x_relaxed_write32(csa, state->trccntvr[i], TRCCNTVRn(i));
	}

	for (i = 0; i < drvdata->nr_resource * 2; i++)
	/* Resource selector pair 0 is reserved */
	for (i = 2; i < drvdata->nr_resource * 2; i++)
		etm4x_relaxed_write32(csa, state->trcrsctlr[i], TRCRSCTLRn(i));

	for (i = 0; i < drvdata->nr_ss_cmp; i++) {
@@ -1931,42 +1936,20 @@ static void etm4_pm_clear(void)
	}
}

static int etm4_probe(struct device *dev)
static int etm4_add_coresight_dev(struct etm4_init_arg *init_arg)
{
	int ret;
	struct coresight_platform_data *pdata = NULL;
	struct device *dev = init_arg->dev;
	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev);
	struct coresight_desc desc = { 0 };
	struct etm4_init_arg init_arg = { 0 };
	u8 major, minor;
	char *type_name;

	if (WARN_ON(!drvdata))
		return -ENOMEM;

	if (pm_save_enable == PARAM_PM_SAVE_FIRMWARE)
		pm_save_enable = coresight_loses_context_with_cpu(dev) ?
			       PARAM_PM_SAVE_SELF_HOSTED : PARAM_PM_SAVE_NEVER;

	if (pm_save_enable != PARAM_PM_SAVE_NEVER) {
		drvdata->save_state = devm_kmalloc(dev,
				sizeof(struct etmv4_save_state), GFP_KERNEL);
		if (!drvdata->save_state)
			return -ENOMEM;
	}

	spin_lock_init(&drvdata->spinlock);

	drvdata->cpu = coresight_get_cpu(dev);
	if (drvdata->cpu < 0)
		return drvdata->cpu;

	init_arg.drvdata = drvdata;
	init_arg.csa = &desc.access;
	if (!drvdata)
		return -EINVAL;

	if (smp_call_function_single(drvdata->cpu,
				etm4_init_arch_data,  &init_arg, 1))
		dev_err(dev, "ETM arch init failed\n");
	desc.access = *init_arg->csa;

	if (!drvdata->arch)
		return -EINVAL;
@@ -2032,6 +2015,59 @@ static int etm4_probe(struct device *dev)
	return 0;
}

static int etm4_probe(struct device *dev)
{
	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev);
	struct csdev_access access = { 0 };
	struct etm4_init_arg init_arg = { 0 };
	struct etm4_init_arg *delayed;

	if (pm_save_enable == PARAM_PM_SAVE_FIRMWARE)
		pm_save_enable = coresight_loses_context_with_cpu(dev) ?
			       PARAM_PM_SAVE_SELF_HOSTED : PARAM_PM_SAVE_NEVER;

	if (pm_save_enable != PARAM_PM_SAVE_NEVER) {
		drvdata->save_state = devm_kmalloc(dev,
				sizeof(struct etmv4_save_state), GFP_KERNEL);
		if (!drvdata->save_state)
			return -ENOMEM;
	}

	spin_lock_init(&drvdata->spinlock);

	drvdata->cpu = coresight_get_cpu(dev);
	if (drvdata->cpu < 0)
		return drvdata->cpu;

	init_arg.dev = dev;
	init_arg.csa = &access;

	/*
	 * Serialize against CPUHP callbacks to avoid race condition
	 * between the smp call and saving the delayed probe.
	 */
	cpus_read_lock();
	if (smp_call_function_single(drvdata->cpu,
				etm4_init_arch_data,  &init_arg, 1)) {
		/* The CPU was offline, try again once it comes online. */
		delayed = devm_kmalloc(dev, sizeof(*delayed), GFP_KERNEL);
		if (!delayed) {
			cpus_read_unlock();
			return -ENOMEM;
		}

		*delayed = init_arg;

		per_cpu(delayed_probe, drvdata->cpu) = delayed;

		cpus_read_unlock();
		return 0;
	}
	cpus_read_unlock();

	return etm4_add_coresight_dev(&init_arg);
}

static int etm4_probe_amba(struct amba_device *adev, const struct amba_id *id)
{
	struct etmv4_drvdata *drvdata;
@@ -2094,6 +2130,35 @@ static int etm4_probe_platform_dev(struct platform_device *pdev)
	return ret;
}

static int etm4_probe_cpu(unsigned int cpu)
{
	int ret;
	struct etm4_init_arg init_arg;
	struct csdev_access access = { 0 };
	struct etm4_init_arg *iap = *this_cpu_ptr(&delayed_probe);

	if (!iap)
		return 0;

	init_arg = *iap;
	devm_kfree(init_arg.dev, iap);
	*this_cpu_ptr(&delayed_probe) = NULL;

	ret = pm_runtime_resume_and_get(init_arg.dev);
	if (ret < 0) {
		dev_err(init_arg.dev, "Failed to get PM runtime!\n");
		return 0;
	}

	init_arg.csa = &access;
	etm4_init_arch_data(&init_arg);

	etm4_add_coresight_dev(&init_arg);

	pm_runtime_put(init_arg.dev);
	return 0;
}

static struct amba_cs_uci_id uci_id_etm4[] = {
	{
		/*  ETMv4 UCI data */
@@ -2108,16 +2173,20 @@ static void clear_etmdrvdata(void *info)
	int cpu = *(int *)info;

	etmdrvdata[cpu] = NULL;
	per_cpu(delayed_probe, cpu) = NULL;
}

static int __exit etm4_remove_dev(struct etmv4_drvdata *drvdata)
{
	etm_perf_symlink(drvdata->csdev, false);
	bool had_delayed_probe;
	/*
	 * Taking hotplug lock here to avoid racing between etm4_remove_dev()
	 * and CPU hotplug call backs.
	 */
	cpus_read_lock();

	had_delayed_probe = per_cpu(delayed_probe, drvdata->cpu);

	/*
	 * The readers for etmdrvdata[] are CPU hotplug call backs
	 * and PM notification call backs. Change etmdrvdata[i] on
@@ -2125,11 +2194,14 @@ static int __exit etm4_remove_dev(struct etmv4_drvdata *drvdata)
	 * inside one call back function.
	 */
	if (smp_call_function_single(drvdata->cpu, clear_etmdrvdata, &drvdata->cpu, 1))
		etmdrvdata[drvdata->cpu] = NULL;
		clear_etmdrvdata(&drvdata->cpu);

	cpus_read_unlock();

	if (!had_delayed_probe) {
		etm_perf_symlink(drvdata->csdev, false);
		coresight_unregister(drvdata->csdev);
	}

	return 0;
}
+2 −27
Original line number Diff line number Diff line
@@ -43,9 +43,6 @@
#define TRCVIIECTLR			0x084
#define TRCVISSCTLR			0x088
#define TRCVIPCSSCTLR			0x08C
#define TRCVDCTLR			0x0A0
#define TRCVDSACCTLR			0x0A4
#define TRCVDARCCTLR			0x0A8
/* Derived resources registers */
#define TRCSEQEVRn(n)			(0x100 + (n * 4))
#define TRCSEQRSTEVR			0x118
@@ -87,8 +84,6 @@
/* Comparator registers */
#define TRCACVRn(n)			(0x400 + (n * 8))
#define TRCACATRn(n)			(0x480 + (n * 8))
#define TRCDVCVRn(n)			(0x500 + (n * 16))
#define TRCDVCMRn(n)			(0x580 + (n * 16))
#define TRCCIDCVRn(n)			(0x600 + (n * 8))
#define TRCVMIDCVRn(n)			(0x640 + (n * 8))
#define TRCCIDCCTLR0			0x680
@@ -169,9 +164,6 @@
/* List of registers accessible via System instructions */
#define ETM4x_ONLY_SYSREG_LIST(op, val)		\
	CASE_##op((val), TRCPROCSELR)		\
	CASE_##op((val), TRCVDCTLR)		\
	CASE_##op((val), TRCVDSACCTLR)		\
	CASE_##op((val), TRCVDARCCTLR)		\
	CASE_##op((val), TRCOSLAR)

#define ETM_COMMON_SYSREG_LIST(op, val)		\
@@ -319,22 +311,6 @@
	CASE_##op((val), TRCACATRn(13))		\
	CASE_##op((val), TRCACATRn(14))		\
	CASE_##op((val), TRCACATRn(15))		\
	CASE_##op((val), TRCDVCVRn(0))		\
	CASE_##op((val), TRCDVCVRn(1))		\
	CASE_##op((val), TRCDVCVRn(2))		\
	CASE_##op((val), TRCDVCVRn(3))		\
	CASE_##op((val), TRCDVCVRn(4))		\
	CASE_##op((val), TRCDVCVRn(5))		\
	CASE_##op((val), TRCDVCVRn(6))		\
	CASE_##op((val), TRCDVCVRn(7))		\
	CASE_##op((val), TRCDVCMRn(0))		\
	CASE_##op((val), TRCDVCMRn(1))		\
	CASE_##op((val), TRCDVCMRn(2))		\
	CASE_##op((val), TRCDVCMRn(3))		\
	CASE_##op((val), TRCDVCMRn(4))		\
	CASE_##op((val), TRCDVCMRn(5))		\
	CASE_##op((val), TRCDVCMRn(6))		\
	CASE_##op((val), TRCDVCMRn(7))		\
	CASE_##op((val), TRCCIDCVRn(0))		\
	CASE_##op((val), TRCCIDCVRn(1))		\
	CASE_##op((val), TRCCIDCVRn(2))		\
@@ -807,9 +783,6 @@ struct etmv4_save_state {
	u32	trcviiectlr;
	u32	trcvissctlr;
	u32	trcvipcssctlr;
	u32	trcvdctlr;
	u32	trcvdsacctlr;
	u32	trcvdarcctlr;

	u32	trcseqevr[ETM_MAX_SEQ_STATES];
	u32	trcseqrstevr;
@@ -882,6 +855,7 @@ struct etmv4_save_state {
 * @os_unlock:  True if access to management registers is allowed.
 * @instrp0:	Tracing of load and store instructions
 *		as P0 elements is supported.
 * @q_filt:	Q element filtering support, if Q elements are supported.
 * @trcbb:	Indicates if the trace unit supports branch broadcast tracing.
 * @trccond:	If the trace unit supports conditional
 *		instruction tracing.
@@ -945,6 +919,7 @@ struct etmv4_drvdata {
	bool				boot_enable;
	bool				os_unlock;
	bool				instrp0;
	bool				q_filt;
	bool				trcbb;
	bool				trccond;
	bool				retstack;