Merge remote-tracking branch 'coresight/next-ETE-TRBE' into kvmarm-master/next
Signed-off-by: Marc Zyngier <maz@kernel.org>
This commit is contained in:
@@ -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.
|
||||
@@ -0,0 +1,75 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause
|
||||
# Copyright 2021, Arm Ltd
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/arm/ete.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
|
||||
title: ARM Embedded Trace Extensions
|
||||
|
||||
maintainers:
|
||||
- Suzuki K Poulose <suzuki.poulose@arm.com>
|
||||
- Mathieu Poirier <mathieu.poirier@linaro.org>
|
||||
|
||||
description: |
|
||||
Arm Embedded Trace Extension(ETE) is a per CPU trace component that
|
||||
allows tracing the CPU execution. It overlaps with the CoreSight ETMv4
|
||||
architecture and has extended support for future architecture changes.
|
||||
The trace generated by the ETE could be stored via legacy CoreSight
|
||||
components (e.g, TMC-ETR) or other means (e.g, using a per CPU buffer
|
||||
Arm Trace Buffer Extension (TRBE)). Since the ETE can be connected to
|
||||
legacy CoreSight components, a node must be listed per instance, along
|
||||
with any optional connection graph as per the coresight bindings.
|
||||
See bindings/arm/coresight.txt.
|
||||
|
||||
properties:
|
||||
$nodename:
|
||||
pattern: "^ete([0-9a-f]+)$"
|
||||
compatible:
|
||||
items:
|
||||
- const: arm,embedded-trace-extension
|
||||
|
||||
cpu:
|
||||
description: |
|
||||
Handle to the cpu this ETE is bound to.
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
|
||||
out-ports:
|
||||
description: |
|
||||
Output connections from the ETE to legacy CoreSight trace bus.
|
||||
$ref: /schemas/graph.yaml#/properties/ports
|
||||
properties:
|
||||
port:
|
||||
description: Output connection from the ETE to legacy CoreSight Trace bus.
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- cpu
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
|
||||
# An ETE node without legacy CoreSight connections
|
||||
- |
|
||||
ete0 {
|
||||
compatible = "arm,embedded-trace-extension";
|
||||
cpu = <&cpu_0>;
|
||||
};
|
||||
# An ETE node with legacy CoreSight connections
|
||||
- |
|
||||
ete1 {
|
||||
compatible = "arm,embedded-trace-extension";
|
||||
cpu = <&cpu_1>;
|
||||
|
||||
out-ports { /* legacy coresight connection */
|
||||
port {
|
||||
ete1_out_port: endpoint {
|
||||
remote-endpoint = <&funnel_in_port0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
@@ -0,0 +1,49 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause
|
||||
# Copyright 2021, Arm Ltd
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/arm/trbe.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
|
||||
title: ARM Trace Buffer Extensions
|
||||
|
||||
maintainers:
|
||||
- Anshuman Khandual <anshuman.khandual@arm.com>
|
||||
|
||||
description: |
|
||||
Arm Trace Buffer Extension (TRBE) is a per CPU component
|
||||
for storing trace generated on the CPU to memory. It is
|
||||
accessed via CPU system registers. The software can verify
|
||||
if it is permitted to use the component by checking the
|
||||
TRBIDR register.
|
||||
|
||||
properties:
|
||||
$nodename:
|
||||
const: "trbe"
|
||||
compatible:
|
||||
items:
|
||||
- const: arm,trace-buffer-extension
|
||||
|
||||
interrupts:
|
||||
description: |
|
||||
Exactly 1 PPI must be listed. For heterogeneous systems where
|
||||
TRBE is only supported on a subset of the CPUs, please consult
|
||||
the arm,gic-v3 binding for details on describing a PPI partition.
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- interrupts
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
trbe {
|
||||
compatible = "arm,trace-buffer-extension";
|
||||
interrupts = <GIC_PPI 15 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
...
|
||||
@@ -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
|
||||
@@ -1761,6 +1761,8 @@ F: Documentation/ABI/testing/sysfs-bus-coresight-devices-*
|
||||
F: Documentation/devicetree/bindings/arm/coresight-cpu-debug.txt
|
||||
F: Documentation/devicetree/bindings/arm/coresight-cti.yaml
|
||||
F: Documentation/devicetree/bindings/arm/coresight.txt
|
||||
F: Documentation/devicetree/bindings/arm/ete.yaml
|
||||
F: Documentation/devicetree/bindings/arm/trbe.yaml
|
||||
F: Documentation/trace/coresight/*
|
||||
F: drivers/hwtracing/coresight/*
|
||||
F: include/dt-bindings/arm/coresight-cti-dt.h
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#define dsb(opt) asm volatile("dsb " #opt : : : "memory")
|
||||
|
||||
#define psb_csync() asm volatile("hint #17" : : : "memory")
|
||||
#define tsb_csync() asm volatile("hint #18" : : : "memory")
|
||||
#define csdb() asm volatile("hint #20" : : : "memory")
|
||||
|
||||
#define spec_bar() asm volatile(ALTERNATIVE("dsb nsh\nisb\n", \
|
||||
|
||||
@@ -65,6 +65,19 @@
|
||||
// use EL1&0 translation.
|
||||
|
||||
.Lskip_spe_\@:
|
||||
/* Trace buffer */
|
||||
ubfx x0, x1, #ID_AA64DFR0_TRBE_SHIFT, #4
|
||||
cbz x0, .Lskip_trace_\@ // Skip if TraceBuffer is not present
|
||||
|
||||
mrs_s x0, SYS_TRBIDR_EL1
|
||||
and x0, x0, TRBIDR_PROG
|
||||
cbnz x0, .Lskip_trace_\@ // If TRBE is available at EL2
|
||||
|
||||
mov x0, #(MDCR_EL2_E2TB_MASK << MDCR_EL2_E2TB_SHIFT)
|
||||
orr x2, x2, x0 // allow the EL1&0 translation
|
||||
// to own it.
|
||||
|
||||
.Lskip_trace_\@:
|
||||
msr mdcr_el2, x2 // Configure debug traps
|
||||
.endm
|
||||
|
||||
|
||||
@@ -278,6 +278,9 @@
|
||||
#define CPTR_EL2_DEFAULT CPTR_EL2_RES1
|
||||
|
||||
/* Hyp Debug Configuration Register bits */
|
||||
#define MDCR_EL2_E2TB_MASK (UL(0x3))
|
||||
#define MDCR_EL2_E2TB_SHIFT (UL(24))
|
||||
#define MDCR_EL2_TTRF (1 << 19)
|
||||
#define MDCR_EL2_TPMS (1 << 14)
|
||||
#define MDCR_EL2_E2PB_MASK (UL(0x3))
|
||||
#define MDCR_EL2_E2PB_SHIFT (UL(12))
|
||||
|
||||
@@ -315,6 +315,8 @@ struct kvm_vcpu_arch {
|
||||
struct kvm_guest_debug_arch regs;
|
||||
/* Statistical profiling extension */
|
||||
u64 pmscr_el1;
|
||||
/* Self-hosted trace */
|
||||
u64 trfcr_el1;
|
||||
} host_debug_state;
|
||||
|
||||
/* VGIC state */
|
||||
@@ -400,6 +402,8 @@ struct kvm_vcpu_arch {
|
||||
#define KVM_ARM64_GUEST_HAS_PTRAUTH (1 << 7) /* PTRAUTH exposed to guest */
|
||||
#define KVM_ARM64_PENDING_EXCEPTION (1 << 8) /* Exception pending */
|
||||
#define KVM_ARM64_EXCEPT_MASK (7 << 9) /* Target EL/MODE */
|
||||
#define KVM_ARM64_DEBUG_STATE_SAVE_SPE (1 << 12) /* Save SPE context if active */
|
||||
#define KVM_ARM64_DEBUG_STATE_SAVE_TRBE (1 << 13) /* Save TRBE context if active */
|
||||
|
||||
/*
|
||||
* When KVM_ARM64_PENDING_EXCEPTION is set, KVM_ARM64_EXCEPT_MASK can
|
||||
@@ -734,6 +738,10 @@ static inline bool kvm_pmu_counter_deferred(struct perf_event_attr *attr)
|
||||
return (!has_vhe() && attr->exclude_host);
|
||||
}
|
||||
|
||||
/* Flags for host debug state */
|
||||
void kvm_arch_vcpu_load_debug_state_flags(struct kvm_vcpu *vcpu);
|
||||
void kvm_arch_vcpu_put_debug_state_flags(struct kvm_vcpu *vcpu);
|
||||
|
||||
#ifdef CONFIG_KVM /* Avoid conflicts with core headers if CONFIG_KVM=n */
|
||||
static inline int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
|
||||
@@ -333,6 +333,55 @@
|
||||
|
||||
/*** End of Statistical Profiling Extension ***/
|
||||
|
||||
/*
|
||||
* TRBE Registers
|
||||
*/
|
||||
#define SYS_TRBLIMITR_EL1 sys_reg(3, 0, 9, 11, 0)
|
||||
#define SYS_TRBPTR_EL1 sys_reg(3, 0, 9, 11, 1)
|
||||
#define SYS_TRBBASER_EL1 sys_reg(3, 0, 9, 11, 2)
|
||||
#define SYS_TRBSR_EL1 sys_reg(3, 0, 9, 11, 3)
|
||||
#define SYS_TRBMAR_EL1 sys_reg(3, 0, 9, 11, 4)
|
||||
#define SYS_TRBTRG_EL1 sys_reg(3, 0, 9, 11, 6)
|
||||
#define SYS_TRBIDR_EL1 sys_reg(3, 0, 9, 11, 7)
|
||||
|
||||
#define TRBLIMITR_LIMIT_MASK GENMASK_ULL(51, 0)
|
||||
#define TRBLIMITR_LIMIT_SHIFT 12
|
||||
#define TRBLIMITR_NVM BIT(5)
|
||||
#define TRBLIMITR_TRIG_MODE_MASK GENMASK(1, 0)
|
||||
#define TRBLIMITR_TRIG_MODE_SHIFT 3
|
||||
#define TRBLIMITR_FILL_MODE_MASK GENMASK(1, 0)
|
||||
#define TRBLIMITR_FILL_MODE_SHIFT 1
|
||||
#define TRBLIMITR_ENABLE BIT(0)
|
||||
#define TRBPTR_PTR_MASK GENMASK_ULL(63, 0)
|
||||
#define TRBPTR_PTR_SHIFT 0
|
||||
#define TRBBASER_BASE_MASK GENMASK_ULL(51, 0)
|
||||
#define TRBBASER_BASE_SHIFT 12
|
||||
#define TRBSR_EC_MASK GENMASK(5, 0)
|
||||
#define TRBSR_EC_SHIFT 26
|
||||
#define TRBSR_IRQ BIT(22)
|
||||
#define TRBSR_TRG BIT(21)
|
||||
#define TRBSR_WRAP BIT(20)
|
||||
#define TRBSR_ABORT BIT(18)
|
||||
#define TRBSR_STOP BIT(17)
|
||||
#define TRBSR_MSS_MASK GENMASK(15, 0)
|
||||
#define TRBSR_MSS_SHIFT 0
|
||||
#define TRBSR_BSC_MASK GENMASK(5, 0)
|
||||
#define TRBSR_BSC_SHIFT 0
|
||||
#define TRBSR_FSC_MASK GENMASK(5, 0)
|
||||
#define TRBSR_FSC_SHIFT 0
|
||||
#define TRBMAR_SHARE_MASK GENMASK(1, 0)
|
||||
#define TRBMAR_SHARE_SHIFT 8
|
||||
#define TRBMAR_OUTER_MASK GENMASK(3, 0)
|
||||
#define TRBMAR_OUTER_SHIFT 4
|
||||
#define TRBMAR_INNER_MASK GENMASK(3, 0)
|
||||
#define TRBMAR_INNER_SHIFT 0
|
||||
#define TRBTRG_TRG_MASK GENMASK(31, 0)
|
||||
#define TRBTRG_TRG_SHIFT 0
|
||||
#define TRBIDR_FLAG BIT(5)
|
||||
#define TRBIDR_PROG BIT(4)
|
||||
#define TRBIDR_ALIGN_MASK GENMASK(3, 0)
|
||||
#define TRBIDR_ALIGN_SHIFT 0
|
||||
|
||||
#define SYS_PMINTENSET_EL1 sys_reg(3, 0, 9, 14, 1)
|
||||
#define SYS_PMINTENCLR_EL1 sys_reg(3, 0, 9, 14, 2)
|
||||
|
||||
@@ -840,6 +889,7 @@
|
||||
#define ID_AA64MMFR2_CNP_SHIFT 0
|
||||
|
||||
/* id_aa64dfr0 */
|
||||
#define ID_AA64DFR0_TRBE_SHIFT 44
|
||||
#define ID_AA64DFR0_TRACE_FILT_SHIFT 40
|
||||
#define ID_AA64DFR0_DOUBLELOCK_SHIFT 36
|
||||
#define ID_AA64DFR0_PMSVER_SHIFT 32
|
||||
|
||||
@@ -383,7 +383,6 @@ static const struct arm64_ftr_bits ftr_id_aa64dfr0[] = {
|
||||
* of support.
|
||||
*/
|
||||
S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_EXACT, ID_AA64DFR0_PMUVER_SHIFT, 4, 0),
|
||||
ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64DFR0_TRACEVER_SHIFT, 4, 0),
|
||||
ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64DFR0_DEBUGVER_SHIFT, 4, 0x6),
|
||||
ARM64_FTR_END,
|
||||
};
|
||||
|
||||
@@ -115,9 +115,10 @@ SYM_CODE_START_LOCAL(mutate_to_vhe)
|
||||
mrs_s x0, SYS_VBAR_EL12
|
||||
msr vbar_el1, x0
|
||||
|
||||
// Use EL2 translations for SPE and disable access from EL1
|
||||
// Use EL2 translations for SPE & TRBE and disable access from EL1
|
||||
mrs x0, mdcr_el2
|
||||
bic x0, x0, #(MDCR_EL2_E2PB_MASK << MDCR_EL2_E2PB_SHIFT)
|
||||
bic x0, x0, #(MDCR_EL2_E2TB_MASK << MDCR_EL2_E2TB_SHIFT)
|
||||
msr mdcr_el2, x0
|
||||
|
||||
// Transfer the MM state from EL1 to EL2
|
||||
|
||||
@@ -416,10 +416,12 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
|
||||
|
||||
if (vcpu_has_ptrauth(vcpu))
|
||||
vcpu_ptrauth_disable(vcpu);
|
||||
kvm_arch_vcpu_load_debug_state_flags(vcpu);
|
||||
}
|
||||
|
||||
void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
kvm_arch_vcpu_put_debug_state_flags(vcpu);
|
||||
kvm_arch_vcpu_put_fp(vcpu);
|
||||
if (has_vhe())
|
||||
kvm_vcpu_put_sysregs_vhe(vcpu);
|
||||
|
||||
+33
-2
@@ -89,6 +89,7 @@ void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu)
|
||||
* - Debug ROM Address (MDCR_EL2_TDRA)
|
||||
* - OS related registers (MDCR_EL2_TDOSA)
|
||||
* - Statistical profiler (MDCR_EL2_TPMS/MDCR_EL2_E2PB)
|
||||
* - Self-hosted Trace (MDCR_EL2_TTRF/MDCR_EL2_E2TB)
|
||||
*
|
||||
* Additionally, KVM only traps guest accesses to the debug registers if
|
||||
* the guest is not actively using them (see the KVM_ARM64_DEBUG_DIRTY
|
||||
@@ -106,12 +107,13 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
|
||||
trace_kvm_arm_setup_debug(vcpu, vcpu->guest_debug);
|
||||
|
||||
/*
|
||||
* This also clears MDCR_EL2_E2PB_MASK to disable guest access
|
||||
* to the profiling buffer.
|
||||
* This also clears MDCR_EL2_E2PB_MASK and MDCR_EL2_E2TB_MASK
|
||||
* to disable guest access to the profiling and trace buffers
|
||||
*/
|
||||
vcpu->arch.mdcr_el2 = __this_cpu_read(mdcr_el2) & MDCR_EL2_HPMN_MASK;
|
||||
vcpu->arch.mdcr_el2 |= (MDCR_EL2_TPM |
|
||||
MDCR_EL2_TPMS |
|
||||
MDCR_EL2_TTRF |
|
||||
MDCR_EL2_TPMCR |
|
||||
MDCR_EL2_TDRA |
|
||||
MDCR_EL2_TDOSA);
|
||||
@@ -229,3 +231,32 @@ void kvm_arm_clear_debug(struct kvm_vcpu *vcpu)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void kvm_arch_vcpu_load_debug_state_flags(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
u64 dfr0;
|
||||
|
||||
/* For VHE, there is nothing to do */
|
||||
if (has_vhe())
|
||||
return;
|
||||
|
||||
dfr0 = read_sysreg(id_aa64dfr0_el1);
|
||||
/*
|
||||
* If SPE is present on this CPU and is available at current EL,
|
||||
* we may need to check if the host state needs to be saved.
|
||||
*/
|
||||
if (cpuid_feature_extract_unsigned_field(dfr0, ID_AA64DFR0_PMSVER_SHIFT) &&
|
||||
!(read_sysreg_s(SYS_PMBIDR_EL1) & BIT(SYS_PMBIDR_EL1_P_SHIFT)))
|
||||
vcpu->arch.flags |= KVM_ARM64_DEBUG_STATE_SAVE_SPE;
|
||||
|
||||
/* Check if we have TRBE implemented and available at the host */
|
||||
if (cpuid_feature_extract_unsigned_field(dfr0, ID_AA64DFR0_TRBE_SHIFT) &&
|
||||
!(read_sysreg_s(SYS_TRBIDR_EL1) & TRBIDR_PROG))
|
||||
vcpu->arch.flags |= KVM_ARM64_DEBUG_STATE_SAVE_TRBE;
|
||||
}
|
||||
|
||||
void kvm_arch_vcpu_put_debug_state_flags(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
vcpu->arch.flags &= ~(KVM_ARM64_DEBUG_STATE_SAVE_SPE |
|
||||
KVM_ARM64_DEBUG_STATE_SAVE_TRBE);
|
||||
}
|
||||
|
||||
@@ -21,17 +21,11 @@ static void __debug_save_spe(u64 *pmscr_el1)
|
||||
/* Clear pmscr in case of early return */
|
||||
*pmscr_el1 = 0;
|
||||
|
||||
/* SPE present on this CPU? */
|
||||
if (!cpuid_feature_extract_unsigned_field(read_sysreg(id_aa64dfr0_el1),
|
||||
ID_AA64DFR0_PMSVER_SHIFT))
|
||||
return;
|
||||
|
||||
/* Yes; is it owned by EL3? */
|
||||
reg = read_sysreg_s(SYS_PMBIDR_EL1);
|
||||
if (reg & BIT(SYS_PMBIDR_EL1_P_SHIFT))
|
||||
return;
|
||||
|
||||
/* No; is the host actually using the thing? */
|
||||
/*
|
||||
* At this point, we know that this CPU implements
|
||||
* SPE and is available to the host.
|
||||
* Check if the host is actually using it ?
|
||||
*/
|
||||
reg = read_sysreg_s(SYS_PMBLIMITR_EL1);
|
||||
if (!(reg & BIT(SYS_PMBLIMITR_EL1_E_SHIFT)))
|
||||
return;
|
||||
@@ -58,10 +52,43 @@ static void __debug_restore_spe(u64 pmscr_el1)
|
||||
write_sysreg_s(pmscr_el1, SYS_PMSCR_EL1);
|
||||
}
|
||||
|
||||
static void __debug_save_trace(u64 *trfcr_el1)
|
||||
{
|
||||
*trfcr_el1 = 0;
|
||||
|
||||
/* Check if the TRBE is enabled */
|
||||
if (!(read_sysreg_s(SYS_TRBLIMITR_EL1) & TRBLIMITR_ENABLE))
|
||||
return;
|
||||
/*
|
||||
* Prohibit trace generation while we are in guest.
|
||||
* Since access to TRFCR_EL1 is trapped, the guest can't
|
||||
* modify the filtering set by the host.
|
||||
*/
|
||||
*trfcr_el1 = read_sysreg_s(SYS_TRFCR_EL1);
|
||||
write_sysreg_s(0, SYS_TRFCR_EL1);
|
||||
isb();
|
||||
/* Drain the trace buffer to memory */
|
||||
tsb_csync();
|
||||
dsb(nsh);
|
||||
}
|
||||
|
||||
static void __debug_restore_trace(u64 trfcr_el1)
|
||||
{
|
||||
if (!trfcr_el1)
|
||||
return;
|
||||
|
||||
/* Restore trace filter controls */
|
||||
write_sysreg_s(trfcr_el1, SYS_TRFCR_EL1);
|
||||
}
|
||||
|
||||
void __debug_save_host_buffers_nvhe(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
/* Disable and flush SPE data generation */
|
||||
__debug_save_spe(&vcpu->arch.host_debug_state.pmscr_el1);
|
||||
if (vcpu->arch.flags & KVM_ARM64_DEBUG_STATE_SAVE_SPE)
|
||||
__debug_save_spe(&vcpu->arch.host_debug_state.pmscr_el1);
|
||||
/* Disable and flush Self-Hosted Trace generation */
|
||||
if (vcpu->arch.flags & KVM_ARM64_DEBUG_STATE_SAVE_TRBE)
|
||||
__debug_save_trace(&vcpu->arch.host_debug_state.trfcr_el1);
|
||||
}
|
||||
|
||||
void __debug_switch_to_guest(struct kvm_vcpu *vcpu)
|
||||
@@ -71,7 +98,10 @@ void __debug_switch_to_guest(struct kvm_vcpu *vcpu)
|
||||
|
||||
void __debug_restore_host_buffers_nvhe(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
__debug_restore_spe(vcpu->arch.host_debug_state.pmscr_el1);
|
||||
if (vcpu->arch.flags & KVM_ARM64_DEBUG_STATE_SAVE_SPE)
|
||||
__debug_restore_spe(vcpu->arch.host_debug_state.pmscr_el1);
|
||||
if (vcpu->arch.flags & KVM_ARM64_DEBUG_STATE_SAVE_TRBE)
|
||||
__debug_restore_trace(vcpu->arch.host_debug_state.trfcr_el1);
|
||||
}
|
||||
|
||||
void __debug_switch_to_host(struct kvm_vcpu *vcpu)
|
||||
|
||||
@@ -95,6 +95,7 @@ static void __deactivate_traps(struct kvm_vcpu *vcpu)
|
||||
|
||||
mdcr_el2 &= MDCR_EL2_HPMN_MASK;
|
||||
mdcr_el2 |= MDCR_EL2_E2PB_MASK << MDCR_EL2_E2PB_SHIFT;
|
||||
mdcr_el2 |= MDCR_EL2_E2TB_MASK << MDCR_EL2_E2TB_SHIFT;
|
||||
|
||||
write_sysreg(mdcr_el2, mdcr_el2);
|
||||
if (is_protected_kvm_enabled())
|
||||
|
||||
@@ -1472,6 +1472,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
|
||||
{ SYS_DESC(SYS_GCR_EL1), undef_access },
|
||||
|
||||
{ SYS_DESC(SYS_ZCR_EL1), NULL, reset_val, ZCR_EL1, 0, .visibility = sve_visibility },
|
||||
{ SYS_DESC(SYS_TRFCR_EL1), undef_access },
|
||||
{ SYS_DESC(SYS_TTBR0_EL1), access_vm_reg, reset_unknown, TTBR0_EL1 },
|
||||
{ SYS_DESC(SYS_TTBR1_EL1), access_vm_reg, reset_unknown, TTBR1_EL1 },
|
||||
{ SYS_DESC(SYS_TCR_EL1), access_vm_reg, reset_val, TCR_EL1, 0 },
|
||||
|
||||
@@ -97,15 +97,15 @@ config CORESIGHT_SOURCE_ETM3X
|
||||
module will be called coresight-etm3x.
|
||||
|
||||
config CORESIGHT_SOURCE_ETM4X
|
||||
tristate "CoreSight Embedded Trace Macrocell 4.x driver"
|
||||
tristate "CoreSight ETMv4.x / ETE driver"
|
||||
depends on ARM64
|
||||
select CORESIGHT_LINKS_AND_SINKS
|
||||
select PID_IN_CONTEXTIDR
|
||||
help
|
||||
This driver provides support for the ETM4.x tracer module, tracing the
|
||||
instructions that a processor is executing. This is primarily useful
|
||||
for instruction level tracing. Depending on the implemented version
|
||||
data tracing may also be available.
|
||||
This driver provides support for the CoreSight Embedded Trace Macrocell
|
||||
version 4.x and the Embedded Trace Extensions (ETE). Both are CPU tracer
|
||||
modules, tracing the instructions that a processor is executing. This is
|
||||
primarily useful for instruction level tracing.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called coresight-etm4x.
|
||||
@@ -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
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "coresight-priv.h"
|
||||
|
||||
static DEFINE_MUTEX(coresight_mutex);
|
||||
DEFINE_PER_CPU(struct coresight_device *, csdev_sink);
|
||||
|
||||
/**
|
||||
* struct coresight_node - elements of a path, from source to sink
|
||||
@@ -70,6 +71,18 @@ void coresight_remove_cti_ops(void)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(coresight_remove_cti_ops);
|
||||
|
||||
void coresight_set_percpu_sink(int cpu, struct coresight_device *csdev)
|
||||
{
|
||||
per_cpu(csdev_sink, cpu) = csdev;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(coresight_set_percpu_sink);
|
||||
|
||||
struct coresight_device *coresight_get_percpu_sink(int cpu)
|
||||
{
|
||||
return per_cpu(csdev_sink, cpu);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(coresight_get_percpu_sink);
|
||||
|
||||
static int coresight_id_match(struct device *dev, void *data)
|
||||
{
|
||||
int trace_id, i_trace_id;
|
||||
@@ -784,6 +797,14 @@ static int _coresight_build_path(struct coresight_device *csdev,
|
||||
if (csdev == sink)
|
||||
goto out;
|
||||
|
||||
if (coresight_is_percpu_source(csdev) && coresight_is_percpu_sink(sink) &&
|
||||
sink == per_cpu(csdev_sink, source_ops(csdev)->cpu_id(csdev))) {
|
||||
if (_coresight_build_path(sink, sink, path) == 0) {
|
||||
found = true;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Not a sink - recursively explore each port found on this element */
|
||||
for (i = 0; i < csdev->pdata->nr_outport; i++) {
|
||||
struct coresight_device *child_dev;
|
||||
@@ -999,8 +1020,12 @@ coresight_find_default_sink(struct coresight_device *csdev)
|
||||
int depth = 0;
|
||||
|
||||
/* look for a default sink if we have not found for this device */
|
||||
if (!csdev->def_sink)
|
||||
csdev->def_sink = coresight_find_sink(csdev, &depth);
|
||||
if (!csdev->def_sink) {
|
||||
if (coresight_is_percpu_source(csdev))
|
||||
csdev->def_sink = per_cpu(csdev_sink, source_ops(csdev)->cpu_id(csdev));
|
||||
if (!csdev->def_sink)
|
||||
csdev->def_sink = coresight_find_sink(csdev, &depth);
|
||||
}
|
||||
return csdev->def_sink;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,26 @@
|
||||
static struct pmu etm_pmu;
|
||||
static bool etm_perf_up;
|
||||
|
||||
static DEFINE_PER_CPU(struct perf_output_handle, ctx_handle);
|
||||
/*
|
||||
* An ETM context for a running event includes the perf aux handle
|
||||
* and aux_data. For ETM, the aux_data (etm_event_data), consists of
|
||||
* the trace path and the sink configuration. The event data is accessible
|
||||
* via perf_get_aux(handle). However, a sink could "end" a perf output
|
||||
* handle via the IRQ handler. And if the "sink" encounters a failure
|
||||
* to "begin" another session (e.g due to lack of space in the buffer),
|
||||
* the handle will be cleared. Thus, the event_data may not be accessible
|
||||
* from the handle when we get to the etm_event_stop(), which is required
|
||||
* for stopping the trace path. The event_data is guaranteed to stay alive
|
||||
* until "free_aux()", which cannot happen as long as the event is active on
|
||||
* the ETM. Thus the event_data for the session must be part of the ETM context
|
||||
* to make sure we can disable the trace path.
|
||||
*/
|
||||
struct etm_ctxt {
|
||||
struct perf_output_handle handle;
|
||||
struct etm_event_data *event_data;
|
||||
};
|
||||
|
||||
static DEFINE_PER_CPU(struct etm_ctxt, etm_ctxt);
|
||||
static DEFINE_PER_CPU(struct coresight_device *, csdev_src);
|
||||
|
||||
/*
|
||||
@@ -232,6 +251,25 @@ static void etm_free_aux(void *data)
|
||||
schedule_work(&event_data->work);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if two given sinks are compatible with each other,
|
||||
* so that they can use the same sink buffers, when an event
|
||||
* moves around.
|
||||
*/
|
||||
static bool sinks_compatible(struct coresight_device *a,
|
||||
struct coresight_device *b)
|
||||
{
|
||||
if (!a || !b)
|
||||
return false;
|
||||
/*
|
||||
* If the sinks are of the same subtype and driven
|
||||
* by the same driver, we can use the same buffer
|
||||
* on these sinks.
|
||||
*/
|
||||
return (a->subtype.sink_subtype == b->subtype.sink_subtype) &&
|
||||
(sink_ops(a) == sink_ops(b));
|
||||
}
|
||||
|
||||
static void *etm_setup_aux(struct perf_event *event, void **pages,
|
||||
int nr_pages, bool overwrite)
|
||||
{
|
||||
@@ -239,6 +277,7 @@ static void *etm_setup_aux(struct perf_event *event, void **pages,
|
||||
int cpu = event->cpu;
|
||||
cpumask_t *mask;
|
||||
struct coresight_device *sink = NULL;
|
||||
struct coresight_device *user_sink = NULL, *last_sink = NULL;
|
||||
struct etm_event_data *event_data = NULL;
|
||||
|
||||
event_data = alloc_event_data(cpu);
|
||||
@@ -249,7 +288,7 @@ static void *etm_setup_aux(struct perf_event *event, void **pages,
|
||||
/* First get the selected sink from user space. */
|
||||
if (event->attr.config2) {
|
||||
id = (u32)event->attr.config2;
|
||||
sink = coresight_get_sink_by_id(id);
|
||||
sink = user_sink = coresight_get_sink_by_id(id);
|
||||
}
|
||||
|
||||
mask = &event_data->mask;
|
||||
@@ -277,14 +316,33 @@ static void *etm_setup_aux(struct perf_event *event, void **pages,
|
||||
}
|
||||
|
||||
/*
|
||||
* No sink provided - look for a default sink for one of the
|
||||
* devices. At present we only support topology where all CPUs
|
||||
* use the same sink [N:1], so only need to find one sink. The
|
||||
* coresight_build_path later will remove any CPU that does not
|
||||
* attach to the sink, or if we have not found a sink.
|
||||
* No sink provided - look for a default sink for all the ETMs,
|
||||
* where this event can be scheduled.
|
||||
* We allocate the sink specific buffers only once for this
|
||||
* event. If the ETMs have different default sink devices, we
|
||||
* can only use a single "type" of sink as the event can carry
|
||||
* only one sink specific buffer. Thus we have to make sure
|
||||
* that the sinks are of the same type and driven by the same
|
||||
* driver, as the one we allocate the buffer for. As such
|
||||
* we choose the first sink and check if the remaining ETMs
|
||||
* have a compatible default sink. We don't trace on a CPU
|
||||
* if the sink is not compatible.
|
||||
*/
|
||||
if (!sink)
|
||||
if (!user_sink) {
|
||||
/* Find the default sink for this ETM */
|
||||
sink = coresight_find_default_sink(csdev);
|
||||
if (!sink) {
|
||||
cpumask_clear_cpu(cpu, mask);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check if this sink compatible with the last sink */
|
||||
if (last_sink && !sinks_compatible(last_sink, sink)) {
|
||||
cpumask_clear_cpu(cpu, mask);
|
||||
continue;
|
||||
}
|
||||
last_sink = sink;
|
||||
}
|
||||
|
||||
/*
|
||||
* Building a path doesn't enable it, it simply builds a
|
||||
@@ -312,7 +370,12 @@ static void *etm_setup_aux(struct perf_event *event, void **pages,
|
||||
if (!sink_ops(sink)->alloc_buffer || !sink_ops(sink)->free_buffer)
|
||||
goto err;
|
||||
|
||||
/* Allocate the sink buffer for this session */
|
||||
/*
|
||||
* Allocate the sink buffer for this session. All the sinks
|
||||
* where this event can be scheduled are ensured to be of the
|
||||
* same type. Thus the same sink configuration is used by the
|
||||
* sinks.
|
||||
*/
|
||||
event_data->snk_config =
|
||||
sink_ops(sink)->alloc_buffer(sink, event, pages,
|
||||
nr_pages, overwrite);
|
||||
@@ -332,13 +395,18 @@ static void etm_event_start(struct perf_event *event, int flags)
|
||||
{
|
||||
int cpu = smp_processor_id();
|
||||
struct etm_event_data *event_data;
|
||||
struct perf_output_handle *handle = this_cpu_ptr(&ctx_handle);
|
||||
struct etm_ctxt *ctxt = this_cpu_ptr(&etm_ctxt);
|
||||
struct perf_output_handle *handle = &ctxt->handle;
|
||||
struct coresight_device *sink, *csdev = per_cpu(csdev_src, cpu);
|
||||
struct list_head *path;
|
||||
|
||||
if (!csdev)
|
||||
goto fail;
|
||||
|
||||
/* Have we messed up our tracking ? */
|
||||
if (WARN_ON(ctxt->event_data))
|
||||
goto fail;
|
||||
|
||||
/*
|
||||
* Deal with the ring buffer API and get a handle on the
|
||||
* session's information.
|
||||
@@ -374,6 +442,8 @@ static void etm_event_start(struct perf_event *event, int flags)
|
||||
if (source_ops(csdev)->enable(csdev, event, CS_MODE_PERF))
|
||||
goto fail_disable_path;
|
||||
|
||||
/* Save the event_data for this ETM */
|
||||
ctxt->event_data = event_data;
|
||||
out:
|
||||
return;
|
||||
|
||||
@@ -392,13 +462,30 @@ static void etm_event_stop(struct perf_event *event, int mode)
|
||||
int cpu = smp_processor_id();
|
||||
unsigned long size;
|
||||
struct coresight_device *sink, *csdev = per_cpu(csdev_src, cpu);
|
||||
struct perf_output_handle *handle = this_cpu_ptr(&ctx_handle);
|
||||
struct etm_event_data *event_data = perf_get_aux(handle);
|
||||
struct etm_ctxt *ctxt = this_cpu_ptr(&etm_ctxt);
|
||||
struct perf_output_handle *handle = &ctxt->handle;
|
||||
struct etm_event_data *event_data;
|
||||
struct list_head *path;
|
||||
|
||||
/*
|
||||
* If we still have access to the event_data via handle,
|
||||
* confirm that we haven't messed up the tracking.
|
||||
*/
|
||||
if (handle->event &&
|
||||
WARN_ON(perf_get_aux(handle) != ctxt->event_data))
|
||||
return;
|
||||
|
||||
event_data = ctxt->event_data;
|
||||
/* Clear the event_data as this ETM is stopping the trace. */
|
||||
ctxt->event_data = NULL;
|
||||
|
||||
if (event->hw.state == PERF_HES_STOPPED)
|
||||
return;
|
||||
|
||||
/* We must have a valid event_data for a running event */
|
||||
if (WARN_ON(!event_data))
|
||||
return;
|
||||
|
||||
if (!csdev)
|
||||
return;
|
||||
|
||||
@@ -416,7 +503,13 @@ static void etm_event_stop(struct perf_event *event, int mode)
|
||||
/* tell the core */
|
||||
event->hw.state = PERF_HES_STOPPED;
|
||||
|
||||
if (mode & PERF_EF_UPDATE) {
|
||||
/*
|
||||
* If the handle is not bound to an event anymore
|
||||
* (e.g, the sink driver was unable to restart the
|
||||
* handle due to lack of buffer space), we don't
|
||||
* have to do anything here.
|
||||
*/
|
||||
if (handle->event && (mode & PERF_EF_UPDATE)) {
|
||||
if (WARN_ON_ONCE(handle->event != event))
|
||||
return;
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/property.h>
|
||||
|
||||
#include <asm/barrier.h>
|
||||
#include <asm/sections.h>
|
||||
#include <asm/sysreg.h>
|
||||
#include <asm/local.h>
|
||||
@@ -114,30 +115,91 @@ void etm4x_sysreg_write(u64 val, u32 offset, bool _relaxed, bool _64bit)
|
||||
}
|
||||
}
|
||||
|
||||
static void etm4_os_unlock_csa(struct etmv4_drvdata *drvdata, struct csdev_access *csa)
|
||||
static u64 ete_sysreg_read(u32 offset, bool _relaxed, bool _64bit)
|
||||
{
|
||||
/* Writing 0 to TRCOSLAR unlocks the trace registers */
|
||||
etm4x_relaxed_write32(csa, 0x0, TRCOSLAR);
|
||||
drvdata->os_unlock = true;
|
||||
u64 res = 0;
|
||||
|
||||
switch (offset) {
|
||||
ETE_READ_CASES(res)
|
||||
default :
|
||||
pr_warn_ratelimited("ete: trying to read unsupported register @%x\n",
|
||||
offset);
|
||||
}
|
||||
|
||||
if (!_relaxed)
|
||||
__iormb(res); /* Imitate the !relaxed I/O helpers */
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void ete_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) {
|
||||
ETE_WRITE_CASES(val)
|
||||
default :
|
||||
pr_warn_ratelimited("ete: trying to write to unsupported register @%x\n",
|
||||
offset);
|
||||
}
|
||||
}
|
||||
|
||||
static void etm_detect_os_lock(struct etmv4_drvdata *drvdata,
|
||||
struct csdev_access *csa)
|
||||
{
|
||||
u32 oslsr = etm4x_relaxed_read32(csa, TRCOSLSR);
|
||||
|
||||
drvdata->os_lock_model = ETM_OSLSR_OSLM(oslsr);
|
||||
}
|
||||
|
||||
static void etm_write_os_lock(struct etmv4_drvdata *drvdata,
|
||||
struct csdev_access *csa, u32 val)
|
||||
{
|
||||
val = !!val;
|
||||
|
||||
switch (drvdata->os_lock_model) {
|
||||
case ETM_OSLOCK_PRESENT:
|
||||
etm4x_relaxed_write32(csa, val, TRCOSLAR);
|
||||
break;
|
||||
case ETM_OSLOCK_PE:
|
||||
write_sysreg_s(val, SYS_OSLAR_EL1);
|
||||
break;
|
||||
default:
|
||||
pr_warn_once("CPU%d: Unsupported Trace OSLock model: %x\n",
|
||||
smp_processor_id(), drvdata->os_lock_model);
|
||||
fallthrough;
|
||||
case ETM_OSLOCK_NI:
|
||||
return;
|
||||
}
|
||||
isb();
|
||||
}
|
||||
|
||||
static inline void etm4_os_unlock_csa(struct etmv4_drvdata *drvdata,
|
||||
struct csdev_access *csa)
|
||||
{
|
||||
WARN_ON(drvdata->cpu != smp_processor_id());
|
||||
|
||||
/* Writing 0 to OS Lock unlocks the trace unit registers */
|
||||
etm_write_os_lock(drvdata, csa, 0x0);
|
||||
drvdata->os_unlock = true;
|
||||
}
|
||||
|
||||
static void etm4_os_unlock(struct etmv4_drvdata *drvdata)
|
||||
{
|
||||
if (!WARN_ON(!drvdata->csdev))
|
||||
etm4_os_unlock_csa(drvdata, &drvdata->csdev->access);
|
||||
|
||||
}
|
||||
|
||||
static void etm4_os_lock(struct etmv4_drvdata *drvdata)
|
||||
{
|
||||
if (WARN_ON(!drvdata->csdev))
|
||||
return;
|
||||
|
||||
/* Writing 0x1 to TRCOSLAR locks the trace registers */
|
||||
etm4x_relaxed_write32(&drvdata->csdev->access, 0x1, TRCOSLAR);
|
||||
/* Writing 0x1 to OS Lock locks the trace registers */
|
||||
etm_write_os_lock(drvdata, &drvdata->csdev->access, 0x1);
|
||||
drvdata->os_unlock = false;
|
||||
isb();
|
||||
}
|
||||
|
||||
static void etm4_cs_lock(struct etmv4_drvdata *drvdata,
|
||||
@@ -371,6 +433,13 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
|
||||
etm4x_relaxed_write32(csa, trcpdcr | TRCPDCR_PU, TRCPDCR);
|
||||
}
|
||||
|
||||
/*
|
||||
* ETE mandates that the TRCRSR is written to before
|
||||
* enabling it.
|
||||
*/
|
||||
if (etm4x_is_ete(drvdata))
|
||||
etm4x_relaxed_write32(csa, TRCRSR_TA, TRCRSR);
|
||||
|
||||
/* Enable the trace unit */
|
||||
etm4x_relaxed_write32(csa, 1, TRCPRGCTLR);
|
||||
|
||||
@@ -654,6 +723,7 @@ static int etm4_enable(struct coresight_device *csdev,
|
||||
static void etm4_disable_hw(void *info)
|
||||
{
|
||||
u32 control;
|
||||
u64 trfcr;
|
||||
struct etmv4_drvdata *drvdata = info;
|
||||
struct etmv4_config *config = &drvdata->config;
|
||||
struct coresight_device *csdev = drvdata->csdev;
|
||||
@@ -676,6 +746,16 @@ static void etm4_disable_hw(void *info)
|
||||
/* EN, bit[0] Trace unit enable bit */
|
||||
control &= ~0x1;
|
||||
|
||||
/*
|
||||
* If the CPU supports v8.4 Trace filter Control,
|
||||
* set the ETM to trace prohibited region.
|
||||
*/
|
||||
if (drvdata->trfc) {
|
||||
trfcr = read_sysreg_s(SYS_TRFCR_EL1);
|
||||
write_sysreg_s(trfcr & ~(TRFCR_ELx_ExTRE | TRFCR_ELx_E0TRE),
|
||||
SYS_TRFCR_EL1);
|
||||
isb();
|
||||
}
|
||||
/*
|
||||
* Make sure everything completes before disabling, as recommended
|
||||
* by section 7.3.77 ("TRCVICTLR, ViewInst Main Control Register,
|
||||
@@ -683,12 +763,16 @@ static void etm4_disable_hw(void *info)
|
||||
*/
|
||||
dsb(sy);
|
||||
isb();
|
||||
/* Trace synchronization barrier, is a nop if not supported */
|
||||
tsb_csync();
|
||||
etm4x_relaxed_write32(csa, control, TRCPRGCTLR);
|
||||
|
||||
/* wait for TRCSTATR.PMSTABLE to go to '1' */
|
||||
if (coresight_timeout(csa, TRCSTATR, TRCSTATR_PMSTABLE_BIT, 1))
|
||||
dev_err(etm_dev,
|
||||
"timeout while waiting for PM stable Trace Status\n");
|
||||
if (drvdata->trfc)
|
||||
write_sysreg_s(trfcr, SYS_TRFCR_EL1);
|
||||
|
||||
/* read the status of the single shot comparators */
|
||||
for (i = 0; i < drvdata->nr_ss_cmp; i++) {
|
||||
@@ -817,13 +901,24 @@ static bool etm4_init_sysreg_access(struct etmv4_drvdata *drvdata,
|
||||
* ETMs implementing sysreg access must implement TRCDEVARCH.
|
||||
*/
|
||||
devarch = read_etm4x_sysreg_const_offset(TRCDEVARCH);
|
||||
if ((devarch & ETM_DEVARCH_ID_MASK) != ETM_DEVARCH_ETMv4x_ARCH)
|
||||
switch (devarch & ETM_DEVARCH_ID_MASK) {
|
||||
case ETM_DEVARCH_ETMv4x_ARCH:
|
||||
*csa = (struct csdev_access) {
|
||||
.io_mem = false,
|
||||
.read = etm4x_sysreg_read,
|
||||
.write = etm4x_sysreg_write,
|
||||
};
|
||||
break;
|
||||
case ETM_DEVARCH_ETE_ARCH:
|
||||
*csa = (struct csdev_access) {
|
||||
.io_mem = false,
|
||||
.read = ete_sysreg_read,
|
||||
.write = ete_sysreg_write,
|
||||
};
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
*csa = (struct csdev_access) {
|
||||
.io_mem = false,
|
||||
.read = etm4x_sysreg_read,
|
||||
.write = etm4x_sysreg_write,
|
||||
};
|
||||
}
|
||||
|
||||
drvdata->arch = etm_devarch_to_arch(devarch);
|
||||
return true;
|
||||
@@ -873,7 +968,7 @@ static bool etm4_init_csdev_access(struct etmv4_drvdata *drvdata,
|
||||
return false;
|
||||
}
|
||||
|
||||
static void cpu_enable_tracing(void)
|
||||
static void cpu_enable_tracing(struct etmv4_drvdata *drvdata)
|
||||
{
|
||||
u64 dfr0 = read_sysreg(id_aa64dfr0_el1);
|
||||
u64 trfcr;
|
||||
@@ -881,6 +976,7 @@ static void cpu_enable_tracing(void)
|
||||
if (!cpuid_feature_extract_unsigned_field(dfr0, ID_AA64DFR0_TRACE_FILT_SHIFT))
|
||||
return;
|
||||
|
||||
drvdata->trfc = true;
|
||||
/*
|
||||
* If the CPU supports v8.4 SelfHosted Tracing, enable
|
||||
* tracing at the kernel EL and EL0, forcing to use the
|
||||
@@ -920,6 +1016,9 @@ static void etm4_init_arch_data(void *info)
|
||||
if (!etm4_init_csdev_access(drvdata, csa))
|
||||
return;
|
||||
|
||||
/* Detect the support for OS Lock before we actually use it */
|
||||
etm_detect_os_lock(drvdata, csa);
|
||||
|
||||
/* Make sure all registers are accessible */
|
||||
etm4_os_unlock_csa(drvdata, csa);
|
||||
etm4_cs_unlock(drvdata, csa);
|
||||
@@ -1082,7 +1181,7 @@ static void etm4_init_arch_data(void *info)
|
||||
/* NUMCNTR, bits[30:28] number of counters available for tracing */
|
||||
drvdata->nr_cntr = BMVAL(etmidr5, 28, 30);
|
||||
etm4_cs_lock(drvdata, csa);
|
||||
cpu_enable_tracing();
|
||||
cpu_enable_tracing(drvdata);
|
||||
}
|
||||
|
||||
static inline u32 etm4_get_victlr_access_type(struct etmv4_config *config)
|
||||
@@ -1760,6 +1859,8 @@ static int etm4_probe(struct device *dev, void __iomem *base, u32 etm_pid)
|
||||
struct etmv4_drvdata *drvdata;
|
||||
struct coresight_desc desc = { 0 };
|
||||
struct etm4_init_arg init_arg = { 0 };
|
||||
u8 major, minor;
|
||||
char *type_name;
|
||||
|
||||
drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
|
||||
if (!drvdata)
|
||||
@@ -1786,10 +1887,6 @@ static int etm4_probe(struct device *dev, void __iomem *base, u32 etm_pid)
|
||||
if (drvdata->cpu < 0)
|
||||
return drvdata->cpu;
|
||||
|
||||
desc.name = devm_kasprintf(dev, GFP_KERNEL, "etm%d", drvdata->cpu);
|
||||
if (!desc.name)
|
||||
return -ENOMEM;
|
||||
|
||||
init_arg.drvdata = drvdata;
|
||||
init_arg.csa = &desc.access;
|
||||
init_arg.pid = etm_pid;
|
||||
@@ -1806,6 +1903,22 @@ static int etm4_probe(struct device *dev, void __iomem *base, u32 etm_pid)
|
||||
fwnode_property_present(dev_fwnode(dev), "qcom,skip-power-up"))
|
||||
drvdata->skip_power_up = true;
|
||||
|
||||
major = ETM_ARCH_MAJOR_VERSION(drvdata->arch);
|
||||
minor = ETM_ARCH_MINOR_VERSION(drvdata->arch);
|
||||
|
||||
if (etm4x_is_ete(drvdata)) {
|
||||
type_name = "ete";
|
||||
/* ETE v1 has major version == 0b101. Adjust this for logging.*/
|
||||
major -= 4;
|
||||
} else {
|
||||
type_name = "etm";
|
||||
}
|
||||
|
||||
desc.name = devm_kasprintf(dev, GFP_KERNEL,
|
||||
"%s%d", type_name, drvdata->cpu);
|
||||
if (!desc.name)
|
||||
return -ENOMEM;
|
||||
|
||||
etm4_init_trace_id(drvdata);
|
||||
etm4_set_default(&drvdata->config);
|
||||
|
||||
@@ -1833,9 +1946,8 @@ static int etm4_probe(struct device *dev, void __iomem *base, u32 etm_pid)
|
||||
|
||||
etmdrvdata[drvdata->cpu] = drvdata;
|
||||
|
||||
dev_info(&drvdata->csdev->dev, "CPU%d: ETM v%d.%d initialized\n",
|
||||
drvdata->cpu, ETM_ARCH_MAJOR_VERSION(drvdata->arch),
|
||||
ETM_ARCH_MINOR_VERSION(drvdata->arch));
|
||||
dev_info(&drvdata->csdev->dev, "CPU%d: %s v%d.%d initialized\n",
|
||||
drvdata->cpu, type_name, major, minor);
|
||||
|
||||
if (boot_enable) {
|
||||
coresight_enable(drvdata->csdev);
|
||||
@@ -1978,6 +2090,7 @@ static struct amba_driver etm4x_amba_driver = {
|
||||
|
||||
static const struct of_device_id etm4_sysreg_match[] = {
|
||||
{ .compatible = "arm,coresight-etm4x-sysreg" },
|
||||
{ .compatible = "arm,embedded-trace-extension" },
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
@@ -2374,12 +2374,20 @@ static inline bool
|
||||
etm4x_register_implemented(struct etmv4_drvdata *drvdata, u32 offset)
|
||||
{
|
||||
switch (offset) {
|
||||
ETM4x_SYSREG_LIST_CASES
|
||||
ETM_COMMON_SYSREG_LIST_CASES
|
||||
/*
|
||||
* Registers accessible via system instructions are always
|
||||
* implemented.
|
||||
* Common registers to ETE & ETM4x accessible via system
|
||||
* instructions are always implemented.
|
||||
*/
|
||||
return true;
|
||||
|
||||
ETM4x_ONLY_SYSREG_LIST_CASES
|
||||
/*
|
||||
* We only support etm4x and ete. So if the device is not
|
||||
* ETE, it must be ETMv4x.
|
||||
*/
|
||||
return !etm4x_is_ete(drvdata);
|
||||
|
||||
ETM4x_MMAP_LIST_CASES
|
||||
/*
|
||||
* Registers accessible only via memory-mapped registers
|
||||
@@ -2389,8 +2397,13 @@ etm4x_register_implemented(struct etmv4_drvdata *drvdata, u32 offset)
|
||||
* coresight_register() and the csdev is not initialized
|
||||
* until that is done. So rely on the drvdata->base to
|
||||
* detect if we have a memory mapped access.
|
||||
* Also ETE doesn't implement memory mapped access, thus
|
||||
* it is sufficient to check that we are using mmio.
|
||||
*/
|
||||
return !!drvdata->base;
|
||||
|
||||
ETE_ONLY_SYSREG_LIST_CASES
|
||||
return etm4x_is_ete(drvdata);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#define TRCAUXCTLR 0x018
|
||||
#define TRCEVENTCTL0R 0x020
|
||||
#define TRCEVENTCTL1R 0x024
|
||||
#define TRCRSR 0x028
|
||||
#define TRCSTALLCTLR 0x02C
|
||||
#define TRCTSCTLR 0x030
|
||||
#define TRCSYNCPR 0x034
|
||||
@@ -49,6 +50,7 @@
|
||||
#define TRCSEQRSTEVR 0x118
|
||||
#define TRCSEQSTR 0x11C
|
||||
#define TRCEXTINSELR 0x120
|
||||
#define TRCEXTINSELRn(n) (0x120 + (n * 4)) /* n = 0-3 */
|
||||
#define TRCCNTRLDVRn(n) (0x140 + (n * 4)) /* n = 0-3 */
|
||||
#define TRCCNTCTLRn(n) (0x150 + (n * 4)) /* n = 0-3 */
|
||||
#define TRCCNTVRn(n) (0x160 + (n * 4)) /* n = 0-3 */
|
||||
@@ -126,6 +128,8 @@
|
||||
#define TRCCIDR2 0xFF8
|
||||
#define TRCCIDR3 0xFFC
|
||||
|
||||
#define TRCRSR_TA BIT(12)
|
||||
|
||||
/*
|
||||
* System instructions to access ETM registers.
|
||||
* See ETMv4.4 spec ARM IHI0064F section 4.3.6 System instructions
|
||||
@@ -160,10 +164,22 @@
|
||||
#define CASE_NOP(__unused, x) \
|
||||
case (x): /* fall through */
|
||||
|
||||
#define ETE_ONLY_SYSREG_LIST(op, val) \
|
||||
CASE_##op((val), TRCRSR) \
|
||||
CASE_##op((val), TRCEXTINSELRn(1)) \
|
||||
CASE_##op((val), TRCEXTINSELRn(2)) \
|
||||
CASE_##op((val), TRCEXTINSELRn(3))
|
||||
|
||||
/* List of registers accessible via System instructions */
|
||||
#define ETM_SYSREG_LIST(op, val) \
|
||||
CASE_##op((val), TRCPRGCTLR) \
|
||||
#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) \
|
||||
CASE_##op((val), TRCPRGCTLR) \
|
||||
CASE_##op((val), TRCSTATR) \
|
||||
CASE_##op((val), TRCCONFIGR) \
|
||||
CASE_##op((val), TRCAUXCTLR) \
|
||||
@@ -180,9 +196,6 @@
|
||||
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)) \
|
||||
@@ -277,7 +290,6 @@
|
||||
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)) \
|
||||
@@ -369,12 +381,38 @@
|
||||
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 ETM4x_READ_SYSREG_CASES(res) \
|
||||
ETM_COMMON_SYSREG_LIST(READ, (res)) \
|
||||
ETM4x_ONLY_SYSREG_LIST(READ, (res))
|
||||
|
||||
#define ETM4x_WRITE_SYSREG_CASES(val) \
|
||||
ETM_COMMON_SYSREG_LIST(WRITE, (val)) \
|
||||
ETM4x_ONLY_SYSREG_LIST(WRITE, (val))
|
||||
|
||||
#define ETM_COMMON_SYSREG_LIST_CASES \
|
||||
ETM_COMMON_SYSREG_LIST(NOP, __unused)
|
||||
|
||||
#define ETM4x_ONLY_SYSREG_LIST_CASES \
|
||||
ETM4x_ONLY_SYSREG_LIST(NOP, __unused)
|
||||
|
||||
#define ETM4x_SYSREG_LIST_CASES \
|
||||
ETM_COMMON_SYSREG_LIST_CASES \
|
||||
ETM4x_ONLY_SYSREG_LIST(NOP, __unused)
|
||||
|
||||
#define ETM4x_SYSREG_LIST_CASES ETM_SYSREG_LIST(NOP, __unused)
|
||||
#define ETM4x_MMAP_LIST_CASES ETM_MMAP_LIST(NOP, __unused)
|
||||
|
||||
/* ETE only supports system register access */
|
||||
#define ETE_READ_CASES(res) \
|
||||
ETM_COMMON_SYSREG_LIST(READ, (res)) \
|
||||
ETE_ONLY_SYSREG_LIST(READ, (res))
|
||||
|
||||
#define ETE_WRITE_CASES(val) \
|
||||
ETM_COMMON_SYSREG_LIST(WRITE, (val)) \
|
||||
ETE_ONLY_SYSREG_LIST(WRITE, (val))
|
||||
|
||||
#define ETE_ONLY_SYSREG_LIST_CASES \
|
||||
ETE_ONLY_SYSREG_LIST(NOP, __unused)
|
||||
|
||||
#define read_etm4x_sysreg_offset(offset, _64bit) \
|
||||
({ \
|
||||
u64 __val; \
|
||||
@@ -505,6 +543,20 @@
|
||||
ETM_MODE_EXCL_KERN | \
|
||||
ETM_MODE_EXCL_USER)
|
||||
|
||||
/*
|
||||
* TRCOSLSR.OSLM advertises the OS Lock model.
|
||||
* OSLM[2:0] = TRCOSLSR[4:3,0]
|
||||
*
|
||||
* 0b000 - Trace OS Lock is not implemented.
|
||||
* 0b010 - Trace OS Lock is implemented.
|
||||
* 0b100 - Trace OS Lock is not implemented, unit is controlled by PE OS Lock.
|
||||
*/
|
||||
#define ETM_OSLOCK_NI 0b000
|
||||
#define ETM_OSLOCK_PRESENT 0b010
|
||||
#define ETM_OSLOCK_PE 0b100
|
||||
|
||||
#define ETM_OSLSR_OSLM(oslsr) ((((oslsr) & GENMASK(4, 3)) >> 2) | (oslsr & 0x1))
|
||||
|
||||
/*
|
||||
* TRCDEVARCH Bit field definitions
|
||||
* Bits[31:21] - ARCHITECT = Always Arm Ltd.
|
||||
@@ -541,11 +593,14 @@
|
||||
((ETM_DEVARCH_MAKE_ARCHID_ARCH_VER(major)) | ETM_DEVARCH_ARCHID_ARCH_PART(0xA13))
|
||||
|
||||
#define ETM_DEVARCH_ARCHID_ETMv4x ETM_DEVARCH_MAKE_ARCHID(0x4)
|
||||
#define ETM_DEVARCH_ARCHID_ETE ETM_DEVARCH_MAKE_ARCHID(0x5)
|
||||
|
||||
#define ETM_DEVARCH_ID_MASK \
|
||||
(ETM_DEVARCH_ARCHITECT_MASK | ETM_DEVARCH_ARCHID_MASK | ETM_DEVARCH_PRESENT)
|
||||
#define ETM_DEVARCH_ETMv4x_ARCH \
|
||||
(ETM_DEVARCH_ARCHITECT_ARM | ETM_DEVARCH_ARCHID_ETMv4x | ETM_DEVARCH_PRESENT)
|
||||
#define ETM_DEVARCH_ETE_ARCH \
|
||||
(ETM_DEVARCH_ARCHITECT_ARM | ETM_DEVARCH_ARCHID_ETE | ETM_DEVARCH_PRESENT)
|
||||
|
||||
#define TRCSTATR_IDLE_BIT 0
|
||||
#define TRCSTATR_PMSTABLE_BIT 1
|
||||
@@ -635,6 +690,8 @@
|
||||
#define ETM_ARCH_MINOR_VERSION(arch) ((arch) & 0xfU)
|
||||
|
||||
#define ETM_ARCH_V4 ETM_ARCH_VERSION(4, 0)
|
||||
#define ETM_ARCH_ETE ETM_ARCH_VERSION(5, 0)
|
||||
|
||||
/* Interpretation of resource numbers change at ETM v4.3 architecture */
|
||||
#define ETM_ARCH_V4_3 ETM_ARCH_VERSION(4, 3)
|
||||
|
||||
@@ -862,6 +919,7 @@ struct etmv4_save_state {
|
||||
* @nooverflow: Indicate if overflow prevention is supported.
|
||||
* @atbtrig: If the implementation can support ATB triggers
|
||||
* @lpoverride: If the implementation can support low-power state over.
|
||||
* @trfc: If the implementation supports Arm v8.4 trace filter controls.
|
||||
* @config: structure holding configuration parameters.
|
||||
* @save_state: State to be preserved across power loss
|
||||
* @state_needs_restore: True when there is context to restore after PM exit
|
||||
@@ -897,6 +955,7 @@ struct etmv4_drvdata {
|
||||
u8 s_ex_level;
|
||||
u8 ns_ex_level;
|
||||
u8 q_support;
|
||||
u8 os_lock_model;
|
||||
bool sticky_enable;
|
||||
bool boot_enable;
|
||||
bool os_unlock;
|
||||
@@ -912,6 +971,7 @@ struct etmv4_drvdata {
|
||||
bool nooverflow;
|
||||
bool atbtrig;
|
||||
bool lpoverride;
|
||||
bool trfc;
|
||||
struct etmv4_config config;
|
||||
struct etmv4_save_state *save_state;
|
||||
bool state_needs_restore;
|
||||
@@ -940,4 +1000,9 @@ 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);
|
||||
|
||||
static inline bool etm4x_is_ete(struct etmv4_drvdata *drvdata)
|
||||
{
|
||||
return drvdata->arch >= ETM_ARCH_ETE;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -90,6 +90,12 @@ static void of_coresight_get_ports_legacy(const struct device_node *node,
|
||||
struct of_endpoint endpoint;
|
||||
int in = 0, out = 0;
|
||||
|
||||
/*
|
||||
* Avoid warnings in of_graph_get_next_endpoint()
|
||||
* if the device doesn't have any graph connections
|
||||
*/
|
||||
if (!of_graph_is_present(node))
|
||||
return;
|
||||
do {
|
||||
ep = of_graph_get_next_endpoint(node, ep);
|
||||
if (!ep)
|
||||
|
||||
@@ -232,4 +232,7 @@ coresight_find_csdev_by_fwnode(struct fwnode_handle *r_fwnode);
|
||||
void coresight_set_assoc_ectdev_mutex(struct coresight_device *csdev,
|
||||
struct coresight_device *ect_csdev);
|
||||
|
||||
void coresight_set_percpu_sink(int cpu, struct coresight_device *csdev);
|
||||
struct coresight_device *coresight_get_percpu_sink(int cpu);
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,152 @@
|
||||
/* 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 addr = trblimitr & (TRBLIMITR_LIMIT_MASK << 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);
|
||||
}
|
||||
@@ -50,6 +50,7 @@ enum coresight_dev_subtype_sink {
|
||||
CORESIGHT_DEV_SUBTYPE_SINK_PORT,
|
||||
CORESIGHT_DEV_SUBTYPE_SINK_BUFFER,
|
||||
CORESIGHT_DEV_SUBTYPE_SINK_SYSMEM,
|
||||
CORESIGHT_DEV_SUBTYPE_SINK_PERCPU_SYSMEM,
|
||||
};
|
||||
|
||||
enum coresight_dev_subtype_link {
|
||||
@@ -455,6 +456,18 @@ static inline void csdev_access_write64(struct csdev_access *csa, u64 val, u32 o
|
||||
}
|
||||
#endif /* CONFIG_64BIT */
|
||||
|
||||
static inline bool coresight_is_percpu_source(struct coresight_device *csdev)
|
||||
{
|
||||
return csdev && (csdev->type == CORESIGHT_DEV_TYPE_SOURCE) &&
|
||||
(csdev->subtype.source_subtype == CORESIGHT_DEV_SUBTYPE_SOURCE_PROC);
|
||||
}
|
||||
|
||||
static inline bool coresight_is_percpu_sink(struct coresight_device *csdev)
|
||||
{
|
||||
return csdev && (csdev->type == CORESIGHT_DEV_TYPE_SINK) &&
|
||||
(csdev->subtype.sink_subtype == CORESIGHT_DEV_SUBTYPE_SINK_PERCPU_SYSMEM);
|
||||
}
|
||||
|
||||
extern struct coresight_device *
|
||||
coresight_register(struct coresight_desc *desc);
|
||||
extern void coresight_unregister(struct coresight_device *csdev);
|
||||
|
||||
@@ -1156,10 +1156,15 @@ enum perf_callchain_context {
|
||||
/**
|
||||
* PERF_RECORD_AUX::flags bits
|
||||
*/
|
||||
#define PERF_AUX_FLAG_TRUNCATED 0x01 /* record was truncated to fit */
|
||||
#define PERF_AUX_FLAG_OVERWRITE 0x02 /* snapshot from overwrite mode */
|
||||
#define PERF_AUX_FLAG_PARTIAL 0x04 /* record contains gaps */
|
||||
#define PERF_AUX_FLAG_COLLISION 0x08 /* sample collided with another */
|
||||
#define PERF_AUX_FLAG_TRUNCATED 0x01 /* record was truncated to fit */
|
||||
#define PERF_AUX_FLAG_OVERWRITE 0x02 /* snapshot from overwrite mode */
|
||||
#define PERF_AUX_FLAG_PARTIAL 0x04 /* record contains gaps */
|
||||
#define PERF_AUX_FLAG_COLLISION 0x08 /* sample collided with another */
|
||||
#define PERF_AUX_FLAG_PMU_FORMAT_TYPE_MASK 0xff00 /* PMU specific trace format type */
|
||||
|
||||
/* CoreSight PMU AUX buffer formats */
|
||||
#define PERF_AUX_FLAG_CORESIGHT_FORMAT_CORESIGHT 0x0000 /* Default for backward compatibility */
|
||||
#define PERF_AUX_FLAG_CORESIGHT_FORMAT_RAW 0x0100 /* Raw format of the source */
|
||||
|
||||
#define PERF_FLAG_FD_NO_GROUP (1UL << 0)
|
||||
#define PERF_FLAG_FD_OUTPUT (1UL << 1)
|
||||
|
||||
Reference in New Issue
Block a user