Commit 03336d0f authored by Suzuki K Poulose's avatar Suzuki K Poulose Committed by Greg Kroah-Hartman
Browse files

coresight: etm4x: Add sysreg access helpers

ETM architecture defines the system instructions for accessing
via register accesses. Add basic support for accessing a given
register via system instructions.

We split the list of registers as :
 1) Accessible only from memory mapped interface
 2) Accessible from system register instructions.

All registers are accessible via the memory-mapped interface.
However, some registers are not accessible via the system
instructions. This list is then used to further filter out
the files we expose via sysfs.

Link: https://lore.kernel.org/r/20210110224850.1880240-12-suzuki.poulose@arm.com


Cc: Mike Leach <mike.leach@linaro.org>
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: default avatarSuzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: default avatarMathieu Poirier <mathieu.poirier@linaro.org>
Link: https://lore.kernel.org/r/20210201181351.1475223-14-mathieu.poirier@linaro.org


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 4f2a6726
Loading
Loading
Loading
Loading
+32 −0
Original line number Original line Diff line number Diff line
@@ -75,6 +75,38 @@ static inline bool etm4x_sspcicrn_present(struct etmv4_drvdata *drvdata, int n)
	       (drvdata->config.ss_status[n] & TRCSSCSRn_PC);
	       (drvdata->config.ss_status[n] & TRCSSCSRn_PC);
}
}


u64 etm4x_sysreg_read(u32 offset, bool _relaxed, bool _64bit)
{
	u64 res = 0;

	switch (offset) {
	ETM4x_READ_SYSREG_CASES(res)
	default :
		pr_warn_ratelimited("etm4x: trying to read unsupported register @%x\n",
			 offset);
	}

	if (!_relaxed)
		__iormb(res);	/* Imitate the !relaxed I/O helpers */

	return res;
}

void etm4x_sysreg_write(u64 val, u32 offset, bool _relaxed, bool _64bit)
{
	if (!_relaxed)
		__iowmb();	/* Imitate the !relaxed I/O helpers */
	if (!_64bit)
		val &= GENMASK(31, 0);

	switch (offset) {
	ETM4x_WRITE_SYSREG_CASES(val)
	default :
		pr_warn_ratelimited("etm4x: trying to write to unsupported register @%x\n",
			offset);
	}
}

static void etm4_os_unlock_csa(struct etmv4_drvdata *drvdata, struct csdev_access *csa)
static void etm4_os_unlock_csa(struct etmv4_drvdata *drvdata, struct csdev_access *csa)
{
{
	/* Writing 0 to TRCOSLAR unlocks the trace registers */
	/* Writing 0 to TRCOSLAR unlocks the trace registers */
+321 −22
Original line number Original line Diff line number Diff line
@@ -126,29 +126,325 @@
#define TRCCIDR2			0xFF8
#define TRCCIDR2			0xFF8
#define TRCCIDR3			0xFFC
#define TRCCIDR3			0xFFC


#define etm4x_relaxed_read32(csa, offset)		\
/*
	readl_relaxed((csa)->base + (offset))
 * System instructions to access ETM registers.

 * See ETMv4.4 spec ARM IHI0064F section 4.3.6 System instructions
#define etm4x_read32(csa, offset)			\
 */
	readl((csa)->base + (offset))
#define ETM4x_OFFSET_TO_REG(x)		((x) >> 2)

#define ETM4x_CRn(n)			(((n) >> 7) & 0x7)
#define ETM4x_Op2(n)			(((n) >> 4) & 0x7)
#define ETM4x_CRm(n)			((n) & 0xf)

#include <asm/sysreg.h>
#define ETM4x_REG_NUM_TO_SYSREG(n)				\
	sys_reg(2, 1, ETM4x_CRn(n), ETM4x_CRm(n), ETM4x_Op2(n))

#define READ_ETM4x_REG(reg)					\
	read_sysreg_s(ETM4x_REG_NUM_TO_SYSREG((reg)))
#define WRITE_ETM4x_REG(val, reg)				\
	write_sysreg_s(val, ETM4x_REG_NUM_TO_SYSREG((reg)))

#define read_etm4x_sysreg_const_offset(offset)			\
	READ_ETM4x_REG(ETM4x_OFFSET_TO_REG(offset))

#define write_etm4x_sysreg_const_offset(val, offset)		\
	WRITE_ETM4x_REG(val, ETM4x_OFFSET_TO_REG(offset))

#define CASE_READ(res, x)					\
	case (x): { (res) = read_etm4x_sysreg_const_offset((x)); break; }

#define CASE_WRITE(val, x)					\
	case (x): { write_etm4x_sysreg_const_offset((val), (x)); break; }

/* List of registers accessible via System instructions */
#define ETM_SYSREG_LIST(op, val)		\
	CASE_##op((val), TRCPRGCTLR)		\
	CASE_##op((val), TRCPROCSELR)		\
	CASE_##op((val), TRCSTATR)		\
	CASE_##op((val), TRCCONFIGR)		\
	CASE_##op((val), TRCAUXCTLR)		\
	CASE_##op((val), TRCEVENTCTL0R)		\
	CASE_##op((val), TRCEVENTCTL1R)		\
	CASE_##op((val), TRCSTALLCTLR)		\
	CASE_##op((val), TRCTSCTLR)		\
	CASE_##op((val), TRCSYNCPR)		\
	CASE_##op((val), TRCCCCTLR)		\
	CASE_##op((val), TRCBBCTLR)		\
	CASE_##op((val), TRCTRACEIDR)		\
	CASE_##op((val), TRCQCTLR)		\
	CASE_##op((val), TRCVICTLR)		\
	CASE_##op((val), TRCVIIECTLR)		\
	CASE_##op((val), TRCVISSCTLR)		\
	CASE_##op((val), TRCVIPCSSCTLR)		\
	CASE_##op((val), TRCVDCTLR)		\
	CASE_##op((val), TRCVDSACCTLR)		\
	CASE_##op((val), TRCVDARCCTLR)		\
	CASE_##op((val), TRCSEQEVRn(0))		\
	CASE_##op((val), TRCSEQEVRn(1))		\
	CASE_##op((val), TRCSEQEVRn(2))		\
	CASE_##op((val), TRCSEQRSTEVR)		\
	CASE_##op((val), TRCSEQSTR)		\
	CASE_##op((val), TRCEXTINSELR)		\
	CASE_##op((val), TRCCNTRLDVRn(0))	\
	CASE_##op((val), TRCCNTRLDVRn(1))	\
	CASE_##op((val), TRCCNTRLDVRn(2))	\
	CASE_##op((val), TRCCNTRLDVRn(3))	\
	CASE_##op((val), TRCCNTCTLRn(0))	\
	CASE_##op((val), TRCCNTCTLRn(1))	\
	CASE_##op((val), TRCCNTCTLRn(2))	\
	CASE_##op((val), TRCCNTCTLRn(3))	\
	CASE_##op((val), TRCCNTVRn(0))		\
	CASE_##op((val), TRCCNTVRn(1))		\
	CASE_##op((val), TRCCNTVRn(2))		\
	CASE_##op((val), TRCCNTVRn(3))		\
	CASE_##op((val), TRCIDR8)		\
	CASE_##op((val), TRCIDR9)		\
	CASE_##op((val), TRCIDR10)		\
	CASE_##op((val), TRCIDR11)		\
	CASE_##op((val), TRCIDR12)		\
	CASE_##op((val), TRCIDR13)		\
	CASE_##op((val), TRCIMSPECn(0))		\
	CASE_##op((val), TRCIMSPECn(1))		\
	CASE_##op((val), TRCIMSPECn(2))		\
	CASE_##op((val), TRCIMSPECn(3))		\
	CASE_##op((val), TRCIMSPECn(4))		\
	CASE_##op((val), TRCIMSPECn(5))		\
	CASE_##op((val), TRCIMSPECn(6))		\
	CASE_##op((val), TRCIMSPECn(7))		\
	CASE_##op((val), TRCIDR0)		\
	CASE_##op((val), TRCIDR1)		\
	CASE_##op((val), TRCIDR2)		\
	CASE_##op((val), TRCIDR3)		\
	CASE_##op((val), TRCIDR4)		\
	CASE_##op((val), TRCIDR5)		\
	CASE_##op((val), TRCIDR6)		\
	CASE_##op((val), TRCIDR7)		\
	CASE_##op((val), TRCRSCTLRn(2))		\
	CASE_##op((val), TRCRSCTLRn(3))		\
	CASE_##op((val), TRCRSCTLRn(4))		\
	CASE_##op((val), TRCRSCTLRn(5))		\
	CASE_##op((val), TRCRSCTLRn(6))		\
	CASE_##op((val), TRCRSCTLRn(7))		\
	CASE_##op((val), TRCRSCTLRn(8))		\
	CASE_##op((val), TRCRSCTLRn(9))		\
	CASE_##op((val), TRCRSCTLRn(10))	\
	CASE_##op((val), TRCRSCTLRn(11))	\
	CASE_##op((val), TRCRSCTLRn(12))	\
	CASE_##op((val), TRCRSCTLRn(13))	\
	CASE_##op((val), TRCRSCTLRn(14))	\
	CASE_##op((val), TRCRSCTLRn(15))	\
	CASE_##op((val), TRCRSCTLRn(16))	\
	CASE_##op((val), TRCRSCTLRn(17))	\
	CASE_##op((val), TRCRSCTLRn(18))	\
	CASE_##op((val), TRCRSCTLRn(19))	\
	CASE_##op((val), TRCRSCTLRn(20))	\
	CASE_##op((val), TRCRSCTLRn(21))	\
	CASE_##op((val), TRCRSCTLRn(22))	\
	CASE_##op((val), TRCRSCTLRn(23))	\
	CASE_##op((val), TRCRSCTLRn(24))	\
	CASE_##op((val), TRCRSCTLRn(25))	\
	CASE_##op((val), TRCRSCTLRn(26))	\
	CASE_##op((val), TRCRSCTLRn(27))	\
	CASE_##op((val), TRCRSCTLRn(28))	\
	CASE_##op((val), TRCRSCTLRn(29))	\
	CASE_##op((val), TRCRSCTLRn(30))	\
	CASE_##op((val), TRCRSCTLRn(31))	\
	CASE_##op((val), TRCSSCCRn(0))		\
	CASE_##op((val), TRCSSCCRn(1))		\
	CASE_##op((val), TRCSSCCRn(2))		\
	CASE_##op((val), TRCSSCCRn(3))		\
	CASE_##op((val), TRCSSCCRn(4))		\
	CASE_##op((val), TRCSSCCRn(5))		\
	CASE_##op((val), TRCSSCCRn(6))		\
	CASE_##op((val), TRCSSCCRn(7))		\
	CASE_##op((val), TRCSSCSRn(0))		\
	CASE_##op((val), TRCSSCSRn(1))		\
	CASE_##op((val), TRCSSCSRn(2))		\
	CASE_##op((val), TRCSSCSRn(3))		\
	CASE_##op((val), TRCSSCSRn(4))		\
	CASE_##op((val), TRCSSCSRn(5))		\
	CASE_##op((val), TRCSSCSRn(6))		\
	CASE_##op((val), TRCSSCSRn(7))		\
	CASE_##op((val), TRCSSPCICRn(0))	\
	CASE_##op((val), TRCSSPCICRn(1))	\
	CASE_##op((val), TRCSSPCICRn(2))	\
	CASE_##op((val), TRCSSPCICRn(3))	\
	CASE_##op((val), TRCSSPCICRn(4))	\
	CASE_##op((val), TRCSSPCICRn(5))	\
	CASE_##op((val), TRCSSPCICRn(6))	\
	CASE_##op((val), TRCSSPCICRn(7))	\
	CASE_##op((val), TRCOSLAR)		\
	CASE_##op((val), TRCOSLSR)		\
	CASE_##op((val), TRCACVRn(0))		\
	CASE_##op((val), TRCACVRn(1))		\
	CASE_##op((val), TRCACVRn(2))		\
	CASE_##op((val), TRCACVRn(3))		\
	CASE_##op((val), TRCACVRn(4))		\
	CASE_##op((val), TRCACVRn(5))		\
	CASE_##op((val), TRCACVRn(6))		\
	CASE_##op((val), TRCACVRn(7))		\
	CASE_##op((val), TRCACVRn(8))		\
	CASE_##op((val), TRCACVRn(9))		\
	CASE_##op((val), TRCACVRn(10))		\
	CASE_##op((val), TRCACVRn(11))		\
	CASE_##op((val), TRCACVRn(12))		\
	CASE_##op((val), TRCACVRn(13))		\
	CASE_##op((val), TRCACVRn(14))		\
	CASE_##op((val), TRCACVRn(15))		\
	CASE_##op((val), TRCACATRn(0))		\
	CASE_##op((val), TRCACATRn(1))		\
	CASE_##op((val), TRCACATRn(2))		\
	CASE_##op((val), TRCACATRn(3))		\
	CASE_##op((val), TRCACATRn(4))		\
	CASE_##op((val), TRCACATRn(5))		\
	CASE_##op((val), TRCACATRn(6))		\
	CASE_##op((val), TRCACATRn(7))		\
	CASE_##op((val), TRCACATRn(8))		\
	CASE_##op((val), TRCACATRn(9))		\
	CASE_##op((val), TRCACATRn(10))		\
	CASE_##op((val), TRCACATRn(11))		\
	CASE_##op((val), TRCACATRn(12))		\
	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))		\
	CASE_##op((val), TRCCIDCVRn(3))		\
	CASE_##op((val), TRCCIDCVRn(4))		\
	CASE_##op((val), TRCCIDCVRn(5))		\
	CASE_##op((val), TRCCIDCVRn(6))		\
	CASE_##op((val), TRCCIDCVRn(7))		\
	CASE_##op((val), TRCVMIDCVRn(0))	\
	CASE_##op((val), TRCVMIDCVRn(1))	\
	CASE_##op((val), TRCVMIDCVRn(2))	\
	CASE_##op((val), TRCVMIDCVRn(3))	\
	CASE_##op((val), TRCVMIDCVRn(4))	\
	CASE_##op((val), TRCVMIDCVRn(5))	\
	CASE_##op((val), TRCVMIDCVRn(6))	\
	CASE_##op((val), TRCVMIDCVRn(7))	\
	CASE_##op((val), TRCCIDCCTLR0)		\
	CASE_##op((val), TRCCIDCCTLR1)		\
	CASE_##op((val), TRCVMIDCCTLR0)		\
	CASE_##op((val), TRCVMIDCCTLR1)		\
	CASE_##op((val), TRCCLAIMSET)		\
	CASE_##op((val), TRCCLAIMCLR)		\
	CASE_##op((val), TRCAUTHSTATUS)		\
	CASE_##op((val), TRCDEVARCH)		\
	CASE_##op((val), TRCDEVID)

/* List of registers only accessible via memory-mapped interface */
#define ETM_MMAP_LIST(op, val)			\
	CASE_##op((val), TRCDEVTYPE)		\
	CASE_##op((val), TRCPDCR)		\
	CASE_##op((val), TRCPDSR)		\
	CASE_##op((val), TRCDEVAFF0)		\
	CASE_##op((val), TRCDEVAFF1)		\
	CASE_##op((val), TRCLAR)		\
	CASE_##op((val), TRCLSR)		\
	CASE_##op((val), TRCITCTRL)		\
	CASE_##op((val), TRCPIDR4)		\
	CASE_##op((val), TRCPIDR0)		\
	CASE_##op((val), TRCPIDR1)		\
	CASE_##op((val), TRCPIDR2)		\
	CASE_##op((val), TRCPIDR3)

#define ETM4x_READ_SYSREG_CASES(res)	ETM_SYSREG_LIST(READ, (res))
#define ETM4x_WRITE_SYSREG_CASES(val)	ETM_SYSREG_LIST(WRITE, (val))

#define read_etm4x_sysreg_offset(offset, _64bit)				\
	({									\
		u64 __val;							\
										\
		if (__builtin_constant_p((offset)))				\
			__val = read_etm4x_sysreg_const_offset((offset));	\
		else								\
			__val = etm4x_sysreg_read((offset), true, (_64bit));	\
		__val;								\
	 })

#define write_etm4x_sysreg_offset(val, offset, _64bit)			\
	do {								\
		if (__builtin_constant_p((offset)))			\
			write_etm4x_sysreg_const_offset((val),		\
							(offset));	\
		else							\
			etm4x_sysreg_write((val), (offset), true,	\
					   (_64bit));			\
	} while (0)


#define etm4x_relaxed_write32(csa, val, offset)		\
	writel_relaxed((val), (csa)->base + (offset))


#define etm4x_write32(csa, val, offset)			\
#define etm4x_relaxed_read32(csa, offset)				\
	writel((val), (csa)->base + (offset))
	((u32)((csa)->io_mem ?						\
		 readl_relaxed((csa)->base + (offset)) :		\
		 read_etm4x_sysreg_offset((offset), false)))


#define etm4x_relaxed_read64(csa, offset)				\
#define etm4x_relaxed_read64(csa, offset)				\
	readq_relaxed((csa)->base + (offset))
	((u64)((csa)->io_mem ?						\
		 readq_relaxed((csa)->base + (offset)) :		\
		 read_etm4x_sysreg_offset((offset), true)))

#define etm4x_read32(csa, offset)					\
	({								\
		u32 __val = etm4x_relaxed_read32((csa), (offset));	\
		__iormb(__val);						\
		__val;							\
	 })


#define etm4x_read64(csa, offset)					\
#define etm4x_read64(csa, offset)					\
	readq((csa)->base + (offset))
	({								\
		u64 __val = etm4x_relaxed_read64((csa), (offset));	\
		__iormb(__val);						\
		__val;							\
	 })

#define etm4x_relaxed_write32(csa, val, offset)				\
	do {								\
		if ((csa)->io_mem)					\
			writel_relaxed((val), (csa)->base + (offset));	\
		else							\
			write_etm4x_sysreg_offset((val), (offset),	\
						  false);		\
	} while (0)


#define etm4x_relaxed_write64(csa, val, offset)				\
#define etm4x_relaxed_write64(csa, val, offset)				\
	writeq_relaxed((val), (csa)->base + (offset))
	do {								\
		if ((csa)->io_mem)					\
			writeq_relaxed((val), (csa)->base + (offset));	\
		else							\
			write_etm4x_sysreg_offset((val), (offset),	\
						  true);		\
	} while (0)

#define etm4x_write32(csa, val, offset)					\
	do {								\
		__iowmb();						\
		etm4x_relaxed_write32((csa), (val), (offset));		\
	} while (0)


#define etm4x_write64(csa, val, offset)					\
#define etm4x_write64(csa, val, offset)					\
	writeq((val), (csa)->base + (offset))
	do {								\
		__iowmb();						\
		etm4x_relaxed_write64((csa), (val), (offset));		\
	} while (0)



/* ETMv4 resources */
/* ETMv4 resources */
#define ETM_MAX_NR_PE			8
#define ETM_MAX_NR_PE			8
@@ -522,4 +818,7 @@ enum etm_addr_ctxtype {


extern const struct attribute_group *coresight_etmv4_groups[];
extern const struct attribute_group *coresight_etmv4_groups[];
void etm4_config_trace_mode(struct etmv4_config *config);
void etm4_config_trace_mode(struct etmv4_config *config);

u64 etm4x_sysreg_read(u32 offset, bool _relaxed, bool _64bit);
void etm4x_sysreg_write(u64 val, u32 offset, bool _relaxed, bool _64bit);
#endif
#endif