[PATCH 3/3] coresight etm4x: Add 32-bit read/write option to split 64-bit words

Leo Yan leo.yan at linaro.org
Tue Mar 7 23:04:46 PST 2023


Hi Steve,

On Sun, Mar 05, 2023 at 10:54:08PM -0700, Steve Clevenger wrote:
> An Ampere Computing design decision to not support 64-bit read/write
> access in the ETMv4.6 implementation.
> 
> The Ampere work around is to split ETMv4.6 64-bit register access
> into 2 ea. 32-bit read/write accesses.
> AC03_DEBUG_10 is described in the AmpereOne Developer Errata document:
> 
> https://solutions.amperecomputing.com/customer-connect/products/AmpereOne-device-documentation
> 
> Signed-off-by: Steve Clevenger <scclevenger at os.amperecomputing.com>
> ---
>  drivers/hwtracing/coresight/coresight-etm4x.h | 58 ++++++++++++++-----
>  1 file changed, 44 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h
> index 434f4e95ee17..17457ec71876 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x.h
> +++ b/drivers/hwtracing/coresight/coresight-etm4x.h
> @@ -539,11 +539,6 @@
>  		 readl_relaxed((csa)->base + (offset)) :		\
>  		 read_etm4x_sysreg_offset((offset), false)))
>  
> -#define etm4x_relaxed_read64(csa, 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));	\
> @@ -567,15 +562,6 @@
>  						  false);		\
>  	} while (0)
>  
> -#define etm4x_relaxed_write64(csa, val, 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 {								\
>  		__io_bw();						\
> @@ -1091,6 +1077,50 @@ 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);
>  
> +/* 64-bit aligned to convert 64-bit access to 2 ea. 32-bit access */
> +#pragma pack(push, 8)
> +
> +struct etm_quad_split {
> +	u32 lsw;
> +	u32 msw;
> +};
> +
> +#pragma pack(pop)
> +
> +static inline u64 etm4x_relaxed_read64(struct csdev_access *csa, unsigned int offset)
> +{
> +	if (csa->io_mem) {
> +		if (csa->no_quad_mmio) {
> +			/* split 64-bit reads into 2 consecutive 32-bit reads */
> +			struct etm_quad_split container;
> +
> +			container.lsw = etm4x_read32(csa, offset);
> +			container.msw = etm4x_read32(csa, offset + sizeof(u32));
> +
> +			return *(u64 *) &container;

To be honest, I am not familiar with this part, just want to remind two
things.

Firstly, here you could use hi_lo_readq_relaxed(), seems to me,
hi_lo_readq_relaxed() does the same thing with above section and
you don't need to define the structure etm_quad_split().

Secondly, IIUC, a main problem with splitting 64-bit access into two
32-bit accesses is breaking atomicity.  If here have race condition
between reading and writing 64-bit registers, we need to consider to
use spinlock for register accessing.

I'd like to leave the second issue to Suzuki/Mike/James for
comfirmation in case I introduced complexity.

> +		} else
> +			return readq_relaxed(csa->base + offset);
> +	} else
> +		return read_etm4x_sysreg_offset(offset, true);

Here need to add brackets:

        } else {
                return read_etm4x_sysreg_offset(offset, true);
        }

> +}
> +
> +static inline void etm4x_relaxed_write64(struct csdev_access *csa, u64 quad, unsigned int offset)
> +{
> +	if (csa->io_mem) {
> +		/* split 64-bit writes into 2 consecutive 32-bit writes */
> +		if (csa->no_quad_mmio) {
> +			struct etm_quad_split container;
> +
> +			*(u64 *) &container = quad;
> +
> +			etm4x_relaxed_write32(csa, container.lsw, offset);
> +			etm4x_relaxed_write32(csa, container.msw, offset + sizeof(u32));
> +		} else
> +			writeq_relaxed(quad, csa->base + offset);
> +	} else
> +		write_etm4x_sysreg_offset(quad, offset, true);		\

Ditto.  Please drop the character '\' at the end of the line.

Thanks,
Leo

P.s. I have a ADLink AVA platform (Ampere Altra SoC with 32 CPUs), I
am glad to give a test if you can confirm this patch set can apply on
it (and please clarify if there have any prerequisite for firmwares).

> +}
> +
>  static inline bool etm4x_is_ete(struct etmv4_drvdata *drvdata)
>  {
>  	return drvdata->arch >= ETM_ARCH_ETE;
> -- 
> 2.25.1
>



More information about the linux-arm-kernel mailing list