FROMLIST: coresight: sink: Add TRBE driver
Trace Buffer Extension (TRBE) implements a trace buffer per CPU which is accessible via the system registers. The TRBE supports different addressing modes including CPU virtual address and buffer modes including the circular buffer mode. The TRBE buffer is addressed by a base pointer (TRBBASER_EL1), an write pointer (TRBPTR_EL1) and a limit pointer (TRBLIMITR_EL1). But the access to the trace buffer could be prohibited by a higher exception level (EL3 or EL2), indicated by TRBIDR_EL1.P. The TRBE can also generate a CPU private interrupt (PPI) on address translation errors and when the buffer is full. Overall implementation here is inspired from the Arm SPE driver. Bug: 174685394 Cc: Mathieu Poirier <mathieu.poirier@linaro.org> Cc: Mike Leach <mike.leach@linaro.org> Cc: Suzuki K Poulose <suzuki.poulose@arm.com> Signed-off-by: Anshuman Khandual <anshuman.khandual@arm.com> Link: https://lore.kernel.org/linux-arm-kernel/20210225193543.2920532-19-suzuki.poulose@arm.com/ Signed-off-by: Qais Yousef <qais.yousef@arm.com> Change-Id: I7b19c009c9f4b98d7d10d6e9c9a7ce76f9096eac
This commit is contained in:

committed by
Todd Kjos

parent
253877635b
commit
c122dd3c01
14
Documentation/ABI/testing/sysfs-bus-coresight-devices-trbe
Normal file
14
Documentation/ABI/testing/sysfs-bus-coresight-devices-trbe
Normal file
@@ -0,0 +1,14 @@
|
||||
What: /sys/bus/coresight/devices/trbe<cpu>/align
|
||||
Date: March 2021
|
||||
KernelVersion: 5.13
|
||||
Contact: Anshuman Khandual <anshuman.khandual@arm.com>
|
||||
Description: (Read) Shows the TRBE write pointer alignment. This value
|
||||
is fetched from the TRBIDR register.
|
||||
|
||||
What: /sys/bus/coresight/devices/trbe<cpu>/flag
|
||||
Date: March 2021
|
||||
KernelVersion: 5.13
|
||||
Contact: Anshuman Khandual <anshuman.khandual@arm.com>
|
||||
Description: (Read) Shows if TRBE updates in the memory are with access
|
||||
and dirty flag updates as well. This value is fetched from
|
||||
the TRBIDR register.
|
38
Documentation/trace/coresight/coresight-trbe.rst
Normal file
38
Documentation/trace/coresight/coresight-trbe.rst
Normal file
@@ -0,0 +1,38 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
==============================
|
||||
Trace Buffer Extension (TRBE).
|
||||
==============================
|
||||
|
||||
:Author: Anshuman Khandual <anshuman.khandual@arm.com>
|
||||
:Date: November 2020
|
||||
|
||||
Hardware Description
|
||||
--------------------
|
||||
|
||||
Trace Buffer Extension (TRBE) is a percpu hardware which captures in system
|
||||
memory, CPU traces generated from a corresponding percpu tracing unit. This
|
||||
gets plugged in as a coresight sink device because the corresponding trace
|
||||
generators (ETE), are plugged in as source device.
|
||||
|
||||
The TRBE is not compliant to CoreSight architecture specifications, but is
|
||||
driven via the CoreSight driver framework to support the ETE (which is
|
||||
CoreSight compliant) integration.
|
||||
|
||||
Sysfs files and directories
|
||||
---------------------------
|
||||
|
||||
The TRBE devices appear on the existing coresight bus alongside the other
|
||||
coresight devices::
|
||||
|
||||
>$ ls /sys/bus/coresight/devices
|
||||
trbe0 trbe1 trbe2 trbe3
|
||||
|
||||
The ``trbe<N>`` named TRBEs are associated with a CPU.::
|
||||
|
||||
>$ ls /sys/bus/coresight/devices/trbe0/
|
||||
align flag
|
||||
|
||||
*Key file items are:-*
|
||||
* ``align``: TRBE write pointer alignment
|
||||
* ``flag``: TRBE updates memory with access and dirty flags
|
@@ -173,4 +173,18 @@ config CORESIGHT_CTI_INTEGRATION_REGS
|
||||
CTI trigger connections between this and other devices.These
|
||||
registers are not used in normal operation and can leave devices in
|
||||
an inconsistent state.
|
||||
|
||||
config CORESIGHT_TRBE
|
||||
tristate "Trace Buffer Extension (TRBE) driver"
|
||||
depends on ARM64 && CORESIGHT_SOURCE_ETM4X
|
||||
help
|
||||
This driver provides support for percpu Trace Buffer Extension (TRBE).
|
||||
TRBE always needs to be used along with it's corresponding percpu ETE
|
||||
component. ETE generates trace data which is then captured with TRBE.
|
||||
Unlike traditional sink devices, TRBE is a CPU feature accessible via
|
||||
system registers. But it's explicit dependency with trace unit (ETE)
|
||||
requires it to be plugged in as a coresight sink device.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called coresight-trbe.
|
||||
endif
|
||||
|
@@ -21,5 +21,6 @@ obj-$(CONFIG_CORESIGHT_STM) += coresight-stm.o
|
||||
obj-$(CONFIG_CORESIGHT_CPU_DEBUG) += coresight-cpu-debug.o
|
||||
obj-$(CONFIG_CORESIGHT_CATU) += coresight-catu.o
|
||||
obj-$(CONFIG_CORESIGHT_CTI) += coresight-cti.o
|
||||
obj-$(CONFIG_CORESIGHT_TRBE) += coresight-trbe.o
|
||||
coresight-cti-y := coresight-cti-core.o coresight-cti-platform.o \
|
||||
coresight-cti-sysfs.o
|
||||
|
1149
drivers/hwtracing/coresight/coresight-trbe.c
Normal file
1149
drivers/hwtracing/coresight/coresight-trbe.c
Normal file
File diff suppressed because it is too large
Load Diff
153
drivers/hwtracing/coresight/coresight-trbe.h
Normal file
153
drivers/hwtracing/coresight/coresight-trbe.h
Normal file
@@ -0,0 +1,153 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* This contains all required hardware related helper functions for
|
||||
* Trace Buffer Extension (TRBE) driver in the coresight framework.
|
||||
*
|
||||
* Copyright (C) 2020 ARM Ltd.
|
||||
*
|
||||
* Author: Anshuman Khandual <anshuman.khandual@arm.com>
|
||||
*/
|
||||
#include <linux/coresight.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/smp.h>
|
||||
|
||||
#include "coresight-etm-perf.h"
|
||||
|
||||
static inline bool is_trbe_available(void)
|
||||
{
|
||||
u64 aa64dfr0 = read_sysreg_s(SYS_ID_AA64DFR0_EL1);
|
||||
unsigned int trbe = cpuid_feature_extract_unsigned_field(aa64dfr0, ID_AA64DFR0_TRBE_SHIFT);
|
||||
|
||||
return trbe >= 0b0001;
|
||||
}
|
||||
|
||||
static inline bool is_trbe_enabled(void)
|
||||
{
|
||||
u64 trblimitr = read_sysreg_s(SYS_TRBLIMITR_EL1);
|
||||
|
||||
return trblimitr & TRBLIMITR_ENABLE;
|
||||
}
|
||||
|
||||
#define TRBE_EC_OTHERS 0
|
||||
#define TRBE_EC_STAGE1_ABORT 36
|
||||
#define TRBE_EC_STAGE2_ABORT 37
|
||||
|
||||
static inline int get_trbe_ec(u64 trbsr)
|
||||
{
|
||||
return (trbsr >> TRBSR_EC_SHIFT) & TRBSR_EC_MASK;
|
||||
}
|
||||
|
||||
#define TRBE_BSC_NOT_STOPPED 0
|
||||
#define TRBE_BSC_FILLED 1
|
||||
#define TRBE_BSC_TRIGGERED 2
|
||||
|
||||
static inline int get_trbe_bsc(u64 trbsr)
|
||||
{
|
||||
return (trbsr >> TRBSR_BSC_SHIFT) & TRBSR_BSC_MASK;
|
||||
}
|
||||
|
||||
static inline void clr_trbe_irq(void)
|
||||
{
|
||||
u64 trbsr = read_sysreg_s(SYS_TRBSR_EL1);
|
||||
|
||||
trbsr &= ~TRBSR_IRQ;
|
||||
write_sysreg_s(trbsr, SYS_TRBSR_EL1);
|
||||
}
|
||||
|
||||
static inline bool is_trbe_irq(u64 trbsr)
|
||||
{
|
||||
return trbsr & TRBSR_IRQ;
|
||||
}
|
||||
|
||||
static inline bool is_trbe_trg(u64 trbsr)
|
||||
{
|
||||
return trbsr & TRBSR_TRG;
|
||||
}
|
||||
|
||||
static inline bool is_trbe_wrap(u64 trbsr)
|
||||
{
|
||||
return trbsr & TRBSR_WRAP;
|
||||
}
|
||||
|
||||
static inline bool is_trbe_abort(u64 trbsr)
|
||||
{
|
||||
return trbsr & TRBSR_ABORT;
|
||||
}
|
||||
|
||||
static inline bool is_trbe_running(u64 trbsr)
|
||||
{
|
||||
return !(trbsr & TRBSR_STOP);
|
||||
}
|
||||
|
||||
#define TRBE_TRIG_MODE_STOP 0
|
||||
#define TRBE_TRIG_MODE_IRQ 1
|
||||
#define TRBE_TRIG_MODE_IGNORE 3
|
||||
|
||||
#define TRBE_FILL_MODE_FILL 0
|
||||
#define TRBE_FILL_MODE_WRAP 1
|
||||
#define TRBE_FILL_MODE_CIRCULAR_BUFFER 3
|
||||
|
||||
static inline void set_trbe_disabled(void)
|
||||
{
|
||||
u64 trblimitr = read_sysreg_s(SYS_TRBLIMITR_EL1);
|
||||
|
||||
trblimitr &= ~TRBLIMITR_ENABLE;
|
||||
write_sysreg_s(trblimitr, SYS_TRBLIMITR_EL1);
|
||||
}
|
||||
|
||||
static inline bool get_trbe_flag_update(u64 trbidr)
|
||||
{
|
||||
return trbidr & TRBIDR_FLAG;
|
||||
}
|
||||
|
||||
static inline bool is_trbe_programmable(u64 trbidr)
|
||||
{
|
||||
return !(trbidr & TRBIDR_PROG);
|
||||
}
|
||||
|
||||
static inline int get_trbe_address_align(u64 trbidr)
|
||||
{
|
||||
return (trbidr >> TRBIDR_ALIGN_SHIFT) & TRBIDR_ALIGN_MASK;
|
||||
}
|
||||
|
||||
static inline unsigned long get_trbe_write_pointer(void)
|
||||
{
|
||||
return read_sysreg_s(SYS_TRBPTR_EL1);
|
||||
}
|
||||
|
||||
static inline void set_trbe_write_pointer(unsigned long addr)
|
||||
{
|
||||
WARN_ON(is_trbe_enabled());
|
||||
write_sysreg_s(addr, SYS_TRBPTR_EL1);
|
||||
}
|
||||
|
||||
static inline unsigned long get_trbe_limit_pointer(void)
|
||||
{
|
||||
u64 trblimitr = read_sysreg_s(SYS_TRBLIMITR_EL1);
|
||||
unsigned long limit = (trblimitr >> TRBLIMITR_LIMIT_SHIFT) & TRBLIMITR_LIMIT_MASK;
|
||||
unsigned long addr = limit << TRBLIMITR_LIMIT_SHIFT;
|
||||
|
||||
WARN_ON(!IS_ALIGNED(addr, PAGE_SIZE));
|
||||
return addr;
|
||||
}
|
||||
|
||||
static inline unsigned long get_trbe_base_pointer(void)
|
||||
{
|
||||
u64 trbbaser = read_sysreg_s(SYS_TRBBASER_EL1);
|
||||
unsigned long addr = trbbaser & (TRBBASER_BASE_MASK << TRBBASER_BASE_SHIFT);
|
||||
|
||||
WARN_ON(!IS_ALIGNED(addr, PAGE_SIZE));
|
||||
return addr;
|
||||
}
|
||||
|
||||
static inline void set_trbe_base_pointer(unsigned long addr)
|
||||
{
|
||||
WARN_ON(is_trbe_enabled());
|
||||
WARN_ON(!IS_ALIGNED(addr, (1UL << TRBBASER_BASE_SHIFT)));
|
||||
WARN_ON(!IS_ALIGNED(addr, PAGE_SIZE));
|
||||
write_sysreg_s(addr, SYS_TRBBASER_EL1);
|
||||
}
|
Reference in New Issue
Block a user