mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-07 13:43:51 +00:00
coresight: hwtracing subsystem updates for v6.9
Changes targeting Linux v6.9 include: - CoreSight: Enable W=1 warnings as default - CoreSight: Clean up sysfs/perf mode handling for tracing - Support for Qualcomm TPDM CMB Dataset - Miscellaneous fixes to the CoreSight subsystem - Fix for hisi_ptt PMU to reject events targeting other PMUs Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com> -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEuFy0byloRoXZHaWBxcXRZPKyBqEFAmXfD1gACgkQxcXRZPKy BqEbiRAAks3YgMt1PC610hhvDFps3GoedEGnJBLajtdh7v/gWP6a/LYIP7YU9dkA pskkhvvZm87PdCu9vc7r2NaYVb+8rVyTdafd2DjA1HAdOK2/BoT6tJQzwG3W62EE 0hvRTAgoq40jU4pix1s/wiQjFYa0l98cN85mu6HmMaWu+ulDgEAudcCyqX4kiY+k S1llq7m5JlQdobcDa2a2IbU8L6t6m9hPittgHZwvXBy9OxFJ6GDLoKO0YOn2mp8W yZa1fMAlkCG4asRZyhLb/mRubzVRHfYrJOvgZUJGV67fRUPU/Lwsx5WAwy4NECv5 rooiXEw5TVaQ9/l18W0Zj2WAveVWLGI5HGmIywZ4HEc8fukLWsgLG78Bomu2FkGD Is9mgeXL8oXfGufEHvCxOvI53rHg3tBLsX13mPylkFH+DAD3EPZ8ASoQOa0SbCpV fp8SBznv8q8mHBiFR6Mb4qSDkIjq7h9ygNXzTh1j5BMEf06oTbasNiHmi62dSZsa uYlnPBmSZ0OgvQjRhvdlVKRQIbbni2Ddt93Wnl/6tPvwcv6MmnTKi2cmTZ9IrFPn QFeSeU19gLlAjNAF/1BtubaV0Z4Sj3Tks6TpCcLT4em+Z57efRW9ZGwOGrRsHHiB P0SXCNLiVsAkpZP9wVryEYjb0CnlRljKqiNSO9p3AGhkPJpDhyc= =cz5l -----END PGP SIGNATURE----- Merge tag 'coresight-next-v6.9' of git://git.kernel.org/pub/scm/linux/kernel/git/coresight/linux into char-misc-next Suzuki writes: coresight: hwtracing subsystem updates for v6.9 Changes targeting Linux v6.9 include: - CoreSight: Enable W=1 warnings as default - CoreSight: Clean up sysfs/perf mode handling for tracing - Support for Qualcomm TPDM CMB Dataset - Miscellaneous fixes to the CoreSight subsystem - Fix for hisi_ptt PMU to reject events targeting other PMUs Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com> * tag 'coresight-next-v6.9' of git://git.kernel.org/pub/scm/linux/kernel/git/coresight/linux: (32 commits) coresight-tpda: Change qcom,dsb-element-size to qcom,dsb-elem-bits dt-bindings: arm: qcom,coresight-tpdm: Rename qcom,dsb-element-size hwtracing: hisi_ptt: Move type check to the beginning of hisi_ptt_pmu_event_init() coresight: tpdm: Fix build break due to uninitialised field coresight: etm4x: Set skip_power_up in etm4_init_arch_data function coresight-tpdm: Add msr register support for CMB dt-bindings: arm: qcom,coresight-tpdm: Add support for TPDM CMB MSR register coresight-tpdm: Add timestamp control register support for the CMB coresight-tpdm: Add pattern registers support for CMB coresight-tpdm: Add support to configure CMB coresight-tpda: Add support to configure CMB element coresight-tpdm: Add CMB dataset support dt-bindings: arm: qcom,coresight-tpdm: Add support for CMB element size coresight-tpdm: Optimize the useage of tpdm_has_dsb_dataset coresight-tpdm: Optimize the store function of tpdm simple dataset coresight: Add helper for setting csdev->mode coresight: Add a helper for getting csdev->mode coresight: Add helper for atomically taking the device coresight: Add explicit member initializers to coresight_dev_type coresight: Remove unused stubs ...
This commit is contained in:
commit
bac2f2cfe2
@ -170,3 +170,90 @@ Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_t
|
||||
Description:
|
||||
(RW) Set/Get the MSR(mux select register) for the DSB subunit
|
||||
TPDM.
|
||||
|
||||
What: /sys/bus/coresight/devices/<tpdm-name>/cmb_mode
|
||||
Date: January 2024
|
||||
KernelVersion 6.9
|
||||
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
|
||||
Description: (Write) Set the data collection mode of CMB tpdm. Continuous
|
||||
change creates CMB data set elements on every CMBCLK edge.
|
||||
Trace-on-change creates CMB data set elements only when a new
|
||||
data set element differs in value from the previous element
|
||||
in a CMB data set.
|
||||
|
||||
Accepts only one of the 2 values - 0 or 1.
|
||||
0 : Continuous CMB collection mode.
|
||||
1 : Trace-on-change CMB collection mode.
|
||||
|
||||
What: /sys/bus/coresight/devices/<tpdm-name>/cmb_trig_patt/xpr[0:1]
|
||||
Date: January 2024
|
||||
KernelVersion 6.9
|
||||
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
|
||||
Description:
|
||||
(RW) Set/Get the value of the trigger pattern for the CMB
|
||||
subunit TPDM.
|
||||
|
||||
What: /sys/bus/coresight/devices/<tpdm-name>/cmb_trig_patt/xpmr[0:1]
|
||||
Date: January 2024
|
||||
KernelVersion 6.9
|
||||
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
|
||||
Description:
|
||||
(RW) Set/Get the mask of the trigger pattern for the CMB
|
||||
subunit TPDM.
|
||||
|
||||
What: /sys/bus/coresight/devices/<tpdm-name>/dsb_patt/tpr[0:1]
|
||||
Date: January 2024
|
||||
KernelVersion 6.9
|
||||
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
|
||||
Description:
|
||||
(RW) Set/Get the value of the pattern for the CMB subunit TPDM.
|
||||
|
||||
What: /sys/bus/coresight/devices/<tpdm-name>/dsb_patt/tpmr[0:1]
|
||||
Date: January 2024
|
||||
KernelVersion 6.9
|
||||
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
|
||||
Description:
|
||||
(RW) Set/Get the mask of the pattern for the CMB subunit TPDM.
|
||||
|
||||
What: /sys/bus/coresight/devices/<tpdm-name>/cmb_patt/enable_ts
|
||||
Date: January 2024
|
||||
KernelVersion 6.9
|
||||
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
|
||||
Description:
|
||||
(Write) Set the pattern timestamp of CMB tpdm. Read
|
||||
the pattern timestamp of CMB tpdm.
|
||||
|
||||
Accepts only one of the 2 values - 0 or 1.
|
||||
0 : Disable CMB pattern timestamp.
|
||||
1 : Enable CMB pattern timestamp.
|
||||
|
||||
What: /sys/bus/coresight/devices/<tpdm-name>/cmb_trig_ts
|
||||
Date: January 2024
|
||||
KernelVersion 6.9
|
||||
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
|
||||
Description:
|
||||
(RW) Set/Get the trigger timestamp of the CMB for tpdm.
|
||||
|
||||
Accepts only one of the 2 values - 0 or 1.
|
||||
0 : Set the CMB trigger type to false
|
||||
1 : Set the CMB trigger type to true
|
||||
|
||||
What: /sys/bus/coresight/devices/<tpdm-name>/cmb_ts_all
|
||||
Date: January 2024
|
||||
KernelVersion 6.9
|
||||
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
|
||||
Description:
|
||||
(RW) Read or write the status of timestamp upon all interface.
|
||||
Only value 0 and 1 can be written to this node. Set this node to 1 to requeset
|
||||
timestamp to all trace packet.
|
||||
Accepts only one of the 2 values - 0 or 1.
|
||||
0 : Disable the timestamp of all trace packets.
|
||||
1 : Enable the timestamp of all trace packets.
|
||||
|
||||
What: /sys/bus/coresight/devices/<tpdm-name>/cmb_msr/msr[0:31]
|
||||
Date: January 2024
|
||||
KernelVersion 6.9
|
||||
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
|
||||
Description:
|
||||
(RW) Set/Get the MSR(mux select register) for the CMB subunit
|
||||
TPDM.
|
||||
|
@ -44,14 +44,21 @@ properties:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
qcom,dsb-element-size:
|
||||
qcom,dsb-element-bits:
|
||||
description:
|
||||
Specifies the DSB(Discrete Single Bit) element size supported by
|
||||
the monitor. The associated aggregator will read this size before it
|
||||
is enabled. DSB element size currently only supports 32-bit and 64-bit.
|
||||
$ref: /schemas/types.yaml#/definitions/uint8
|
||||
enum: [32, 64]
|
||||
|
||||
qcom,cmb-element-bits:
|
||||
description:
|
||||
Specifies the CMB(Continuous Multi-Bit) element size supported by
|
||||
the monitor. The associated aggregator will read this size before it
|
||||
is enabled. CMB element size currently only supports 8-bit, 32-bit
|
||||
and 64-bit.
|
||||
enum: [8, 32, 64]
|
||||
|
||||
qcom,dsb-msrs-num:
|
||||
description:
|
||||
Specifies the number of DSB(Discrete Single Bit) MSR(mux select register)
|
||||
@ -61,6 +68,15 @@ properties:
|
||||
minimum: 0
|
||||
maximum: 32
|
||||
|
||||
qcom,cmb-msrs-num:
|
||||
description:
|
||||
Specifies the number of CMB MSR(mux select register) registers supported
|
||||
by the monitor. If this property is not configured or set to 0, it means
|
||||
this TPDM doesn't support CMB MSR.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
maximum: 32
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
@ -94,7 +110,7 @@ examples:
|
||||
compatible = "qcom,coresight-tpdm", "arm,primecell";
|
||||
reg = <0x0684c000 0x1000>;
|
||||
|
||||
qcom,dsb-element-size = /bits/ 8 <32>;
|
||||
qcom,dsb-element-bits = <32>;
|
||||
qcom,dsb-msrs-num = <16>;
|
||||
|
||||
clocks = <&aoss_qmp>;
|
||||
@ -110,4 +126,22 @@ examples:
|
||||
};
|
||||
};
|
||||
|
||||
tpdm@6c29000 {
|
||||
compatible = "qcom,coresight-tpdm", "arm,primecell";
|
||||
reg = <0x06c29000 0x1000>;
|
||||
|
||||
qcom,cmb-element-bits = <64>;
|
||||
qcom,cmb-msrs-num = <32>;
|
||||
|
||||
clocks = <&aoss_qmp>;
|
||||
clock-names = "apb_pclk";
|
||||
|
||||
out-ports {
|
||||
port {
|
||||
tpdm_ipcc_out_funnel_center: endpoint {
|
||||
remote-endpoint = <&funnel_center_in_tpdm_ipcc>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
||||
|
@ -2,6 +2,26 @@
|
||||
#
|
||||
# Makefile for CoreSight drivers.
|
||||
#
|
||||
|
||||
# Current W=1 warnings
|
||||
subdir-ccflags-y += -Wextra -Wunused -Wno-unused-parameter
|
||||
subdir-ccflags-y += -Wmissing-declarations
|
||||
subdir-ccflags-y += -Wmissing-format-attribute
|
||||
subdir-ccflags-y += -Wmissing-prototypes
|
||||
subdir-ccflags-y += -Wold-style-definition
|
||||
subdir-ccflags-y += -Wmissing-include-dirs
|
||||
subdir-ccflags-y += -Wno-sign-compare
|
||||
condflags := \
|
||||
$(call cc-option, -Wrestrict) \
|
||||
$(call cc-option, -Wunused-but-set-variable) \
|
||||
$(call cc-option, -Wunused-const-variable) \
|
||||
$(call cc-option, -Wpacked-not-aligned) \
|
||||
$(call cc-option, -Wformat-overflow) \
|
||||
$(call cc-option, -Wformat-truncation) \
|
||||
$(call cc-option, -Wstringop-overflow) \
|
||||
$(call cc-option, -Wstringop-truncation)
|
||||
subdir-ccflags-y += $(condflags)
|
||||
|
||||
obj-$(CONFIG_CORESIGHT) += coresight.o
|
||||
coresight-y := coresight-core.o coresight-etm-perf.o coresight-platform.o \
|
||||
coresight-sysfs.o coresight-syscfg.o coresight-config.o \
|
||||
|
@ -9,6 +9,7 @@
|
||||
/* ETMv4 includes and features */
|
||||
#if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X)
|
||||
#include "coresight-etm4x-cfg.h"
|
||||
#include "coresight-cfg-preload.h"
|
||||
|
||||
/* preload configurations and features */
|
||||
|
||||
|
@ -9,7 +9,6 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/slab.h>
|
||||
@ -25,15 +24,12 @@
|
||||
#include "coresight-priv.h"
|
||||
#include "coresight-syscfg.h"
|
||||
|
||||
static DEFINE_MUTEX(coresight_mutex);
|
||||
static DEFINE_PER_CPU(struct coresight_device *, csdev_sink);
|
||||
|
||||
/*
|
||||
* Use IDR to map the hash of the source's device name
|
||||
* to the pointer of path for the source. The idr is for
|
||||
* the sources which aren't associated with CPU.
|
||||
* Mutex used to lock all sysfs enable and disable actions and loading and
|
||||
* unloading devices by the Coresight core.
|
||||
*/
|
||||
static DEFINE_IDR(path_idr);
|
||||
DEFINE_MUTEX(coresight_mutex);
|
||||
static DEFINE_PER_CPU(struct coresight_device *, csdev_sink);
|
||||
|
||||
/**
|
||||
* struct coresight_node - elements of a path, from source to sink
|
||||
@ -45,12 +41,6 @@ struct coresight_node {
|
||||
struct list_head link;
|
||||
};
|
||||
|
||||
/*
|
||||
* When operating Coresight drivers from the sysFS interface, only a single
|
||||
* path can exist from a tracer (associated to a CPU) to a sink.
|
||||
*/
|
||||
static DEFINE_PER_CPU(struct list_head *, tracer_path);
|
||||
|
||||
/*
|
||||
* When losing synchronisation a new barrier packet needs to be inserted at the
|
||||
* beginning of the data collected in a buffer. That way the decoder knows that
|
||||
@ -61,34 +51,6 @@ EXPORT_SYMBOL_GPL(coresight_barrier_pkt);
|
||||
|
||||
static const struct cti_assoc_op *cti_assoc_ops;
|
||||
|
||||
ssize_t coresight_simple_show_pair(struct device *_dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct coresight_device *csdev = container_of(_dev, struct coresight_device, dev);
|
||||
struct cs_pair_attribute *cs_attr = container_of(attr, struct cs_pair_attribute, attr);
|
||||
u64 val;
|
||||
|
||||
pm_runtime_get_sync(_dev->parent);
|
||||
val = csdev_access_relaxed_read_pair(&csdev->access, cs_attr->lo_off, cs_attr->hi_off);
|
||||
pm_runtime_put_sync(_dev->parent);
|
||||
return sysfs_emit(buf, "0x%llx\n", val);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(coresight_simple_show_pair);
|
||||
|
||||
ssize_t coresight_simple_show32(struct device *_dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct coresight_device *csdev = container_of(_dev, struct coresight_device, dev);
|
||||
struct cs_off_attribute *cs_attr = container_of(attr, struct cs_off_attribute, attr);
|
||||
u64 val;
|
||||
|
||||
pm_runtime_get_sync(_dev->parent);
|
||||
val = csdev_access_relaxed_read32(&csdev->access, cs_attr->off);
|
||||
pm_runtime_put_sync(_dev->parent);
|
||||
return sysfs_emit(buf, "0x%llx\n", val);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(coresight_simple_show32);
|
||||
|
||||
void coresight_set_cti_ops(const struct cti_assoc_op *cti_op)
|
||||
{
|
||||
cti_assoc_ops = cti_op;
|
||||
@ -279,42 +241,18 @@ EXPORT_SYMBOL_GPL(coresight_add_helper);
|
||||
static int coresight_enable_sink(struct coresight_device *csdev,
|
||||
enum cs_mode mode, void *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* We need to make sure the "new" session is compatible with the
|
||||
* existing "mode" of operation.
|
||||
*/
|
||||
if (!sink_ops(csdev)->enable)
|
||||
return -EINVAL;
|
||||
|
||||
ret = sink_ops(csdev)->enable(csdev, mode, data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
csdev->enable = true;
|
||||
|
||||
return 0;
|
||||
return sink_ops(csdev)->enable(csdev, mode, data);
|
||||
}
|
||||
|
||||
static void coresight_disable_sink(struct coresight_device *csdev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!sink_ops(csdev)->disable)
|
||||
return;
|
||||
|
||||
ret = sink_ops(csdev)->disable(csdev);
|
||||
if (ret)
|
||||
return;
|
||||
csdev->enable = false;
|
||||
sink_ops(csdev)->disable(csdev);
|
||||
}
|
||||
|
||||
static int coresight_enable_link(struct coresight_device *csdev,
|
||||
struct coresight_device *parent,
|
||||
struct coresight_device *child)
|
||||
{
|
||||
int ret = 0;
|
||||
int link_subtype;
|
||||
struct coresight_connection *inconn, *outconn;
|
||||
|
||||
@ -330,21 +268,13 @@ static int coresight_enable_link(struct coresight_device *csdev,
|
||||
if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT && IS_ERR(outconn))
|
||||
return PTR_ERR(outconn);
|
||||
|
||||
if (link_ops(csdev)->enable) {
|
||||
ret = link_ops(csdev)->enable(csdev, inconn, outconn);
|
||||
if (!ret)
|
||||
csdev->enable = true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return link_ops(csdev)->enable(csdev, inconn, outconn);
|
||||
}
|
||||
|
||||
static void coresight_disable_link(struct coresight_device *csdev,
|
||||
struct coresight_device *parent,
|
||||
struct coresight_device *child)
|
||||
{
|
||||
int i;
|
||||
int link_subtype;
|
||||
struct coresight_connection *inconn, *outconn;
|
||||
|
||||
if (!parent || !child)
|
||||
@ -352,50 +282,10 @@ static void coresight_disable_link(struct coresight_device *csdev,
|
||||
|
||||
inconn = coresight_find_out_connection(parent, csdev);
|
||||
outconn = coresight_find_out_connection(csdev, child);
|
||||
link_subtype = csdev->subtype.link_subtype;
|
||||
|
||||
if (link_ops(csdev)->disable) {
|
||||
link_ops(csdev)->disable(csdev, inconn, outconn);
|
||||
}
|
||||
|
||||
if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG) {
|
||||
for (i = 0; i < csdev->pdata->nr_inconns; i++)
|
||||
if (atomic_read(&csdev->pdata->in_conns[i]->dest_refcnt) !=
|
||||
0)
|
||||
return;
|
||||
} else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT) {
|
||||
for (i = 0; i < csdev->pdata->nr_outconns; i++)
|
||||
if (atomic_read(&csdev->pdata->out_conns[i]->src_refcnt) !=
|
||||
0)
|
||||
return;
|
||||
} else {
|
||||
if (atomic_read(&csdev->refcnt) != 0)
|
||||
return;
|
||||
}
|
||||
|
||||
csdev->enable = false;
|
||||
link_ops(csdev)->disable(csdev, inconn, outconn);
|
||||
}
|
||||
|
||||
int coresight_enable_source(struct coresight_device *csdev, enum cs_mode mode,
|
||||
void *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!csdev->enable) {
|
||||
if (source_ops(csdev)->enable) {
|
||||
ret = source_ops(csdev)->enable(csdev, data, mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
csdev->enable = true;
|
||||
}
|
||||
|
||||
atomic_inc(&csdev->refcnt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(coresight_enable_source);
|
||||
|
||||
static bool coresight_is_helper(struct coresight_device *csdev)
|
||||
{
|
||||
return csdev->type == CORESIGHT_DEV_TYPE_HELPER;
|
||||
@ -404,29 +294,12 @@ static bool coresight_is_helper(struct coresight_device *csdev)
|
||||
static int coresight_enable_helper(struct coresight_device *csdev,
|
||||
enum cs_mode mode, void *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!helper_ops(csdev)->enable)
|
||||
return 0;
|
||||
ret = helper_ops(csdev)->enable(csdev, mode, data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
csdev->enable = true;
|
||||
return 0;
|
||||
return helper_ops(csdev)->enable(csdev, mode, data);
|
||||
}
|
||||
|
||||
static void coresight_disable_helper(struct coresight_device *csdev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!helper_ops(csdev)->disable)
|
||||
return;
|
||||
|
||||
ret = helper_ops(csdev)->disable(csdev, NULL);
|
||||
if (ret)
|
||||
return;
|
||||
csdev->enable = false;
|
||||
helper_ops(csdev)->disable(csdev, NULL);
|
||||
}
|
||||
|
||||
static void coresight_disable_helpers(struct coresight_device *csdev)
|
||||
@ -441,25 +314,20 @@ static void coresight_disable_helpers(struct coresight_device *csdev)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* coresight_disable_source - Drop the reference count by 1 and disable
|
||||
* the device if there are no users left.
|
||||
/*
|
||||
* Helper function to call source_ops(csdev)->disable and also disable the
|
||||
* helpers.
|
||||
*
|
||||
* @csdev: The coresight device to disable
|
||||
* @data: Opaque data to pass on to the disable function of the source device.
|
||||
* For example in perf mode this is a pointer to the struct perf_event.
|
||||
*
|
||||
* Returns true if the device has been disabled.
|
||||
* There is an imbalance between coresight_enable_path() and
|
||||
* coresight_disable_path(). Enabling also enables the source's helpers as part
|
||||
* of the path, but disabling always skips the first item in the path (which is
|
||||
* the source), so sources and their helpers don't get disabled as part of that
|
||||
* function and we need the extra step here.
|
||||
*/
|
||||
bool coresight_disable_source(struct coresight_device *csdev, void *data)
|
||||
void coresight_disable_source(struct coresight_device *csdev, void *data)
|
||||
{
|
||||
if (atomic_dec_return(&csdev->refcnt) == 0) {
|
||||
if (source_ops(csdev)->disable)
|
||||
source_ops(csdev)->disable(csdev, data);
|
||||
coresight_disable_helpers(csdev);
|
||||
csdev->enable = false;
|
||||
}
|
||||
return !csdev->enable;
|
||||
source_ops(csdev)->disable(csdev, data);
|
||||
coresight_disable_helpers(csdev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(coresight_disable_source);
|
||||
|
||||
@ -484,7 +352,7 @@ static void coresight_disable_path_from(struct list_head *path,
|
||||
/*
|
||||
* ETF devices are tricky... They can be a link or a sink,
|
||||
* depending on how they are configured. If an ETF has been
|
||||
* "activated" it will be configured as a sink, otherwise
|
||||
* selected as a sink it will be configured as a sink, otherwise
|
||||
* go ahead with the link configuration.
|
||||
*/
|
||||
if (type == CORESIGHT_DEV_TYPE_LINKSINK)
|
||||
@ -562,7 +430,7 @@ int coresight_enable_path(struct list_head *path, enum cs_mode mode,
|
||||
/*
|
||||
* ETF devices are tricky... They can be a link or a sink,
|
||||
* depending on how they are configured. If an ETF has been
|
||||
* "activated" it will be configured as a sink, otherwise
|
||||
* selected as a sink it will be configured as a sink, otherwise
|
||||
* go ahead with the link configuration.
|
||||
*/
|
||||
if (type == CORESIGHT_DEV_TYPE_LINKSINK)
|
||||
@ -619,48 +487,6 @@ struct coresight_device *coresight_get_sink(struct list_head *path)
|
||||
return csdev;
|
||||
}
|
||||
|
||||
static struct coresight_device *
|
||||
coresight_find_enabled_sink(struct coresight_device *csdev)
|
||||
{
|
||||
int i;
|
||||
struct coresight_device *sink = NULL;
|
||||
|
||||
if ((csdev->type == CORESIGHT_DEV_TYPE_SINK ||
|
||||
csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) &&
|
||||
csdev->activated)
|
||||
return csdev;
|
||||
|
||||
/*
|
||||
* Recursively explore each port found on this element.
|
||||
*/
|
||||
for (i = 0; i < csdev->pdata->nr_outconns; i++) {
|
||||
struct coresight_device *child_dev;
|
||||
|
||||
child_dev = csdev->pdata->out_conns[i]->dest_dev;
|
||||
if (child_dev)
|
||||
sink = coresight_find_enabled_sink(child_dev);
|
||||
if (sink)
|
||||
return sink;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* coresight_get_enabled_sink - returns the first enabled sink using
|
||||
* connection based search starting from the source reference
|
||||
*
|
||||
* @source: Coresight source device reference
|
||||
*/
|
||||
struct coresight_device *
|
||||
coresight_get_enabled_sink(struct coresight_device *source)
|
||||
{
|
||||
if (!source)
|
||||
return NULL;
|
||||
|
||||
return coresight_find_enabled_sink(source);
|
||||
}
|
||||
|
||||
static int coresight_sink_by_id(struct device *dev, const void *data)
|
||||
{
|
||||
struct coresight_device *csdev = to_coresight_device(dev);
|
||||
@ -794,11 +620,10 @@ static void coresight_drop_device(struct coresight_device *csdev)
|
||||
* @sink: The final sink we want in this path.
|
||||
* @path: The list to add devices to.
|
||||
*
|
||||
* The tree of Coresight device is traversed until an activated sink is
|
||||
* found. From there the sink is added to the list along with all the
|
||||
* devices that led to that point - the end result is a list from source
|
||||
* to sink. In that list the source is the first device and the sink the
|
||||
* last one.
|
||||
* The tree of Coresight device is traversed until @sink is found.
|
||||
* From there the sink is added to the list along with all the devices that led
|
||||
* to that point - the end result is a list from source to sink. In that list
|
||||
* the source is the first device and the sink the last one.
|
||||
*/
|
||||
static int _coresight_build_path(struct coresight_device *csdev,
|
||||
struct coresight_device *sink,
|
||||
@ -808,7 +633,7 @@ static int _coresight_build_path(struct coresight_device *csdev,
|
||||
bool found = false;
|
||||
struct coresight_node *node;
|
||||
|
||||
/* An activated sink has been found. Enqueue the element */
|
||||
/* The sink has been found. Enqueue the element */
|
||||
if (csdev == sink)
|
||||
goto out;
|
||||
|
||||
@ -1072,269 +897,6 @@ static void coresight_clear_default_sink(struct coresight_device *csdev)
|
||||
}
|
||||
}
|
||||
|
||||
/** coresight_validate_source - make sure a source has the right credentials
|
||||
* @csdev: the device structure for a source.
|
||||
* @function: the function this was called from.
|
||||
*
|
||||
* Assumes the coresight_mutex is held.
|
||||
*/
|
||||
static int coresight_validate_source(struct coresight_device *csdev,
|
||||
const char *function)
|
||||
{
|
||||
u32 type, subtype;
|
||||
|
||||
type = csdev->type;
|
||||
subtype = csdev->subtype.source_subtype;
|
||||
|
||||
if (type != CORESIGHT_DEV_TYPE_SOURCE) {
|
||||
dev_err(&csdev->dev, "wrong device type in %s\n", function);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_PROC &&
|
||||
subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE &&
|
||||
subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM &&
|
||||
subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS) {
|
||||
dev_err(&csdev->dev, "wrong device subtype in %s\n", function);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int coresight_enable(struct coresight_device *csdev)
|
||||
{
|
||||
int cpu, ret = 0;
|
||||
struct coresight_device *sink;
|
||||
struct list_head *path;
|
||||
enum coresight_dev_subtype_source subtype;
|
||||
u32 hash;
|
||||
|
||||
subtype = csdev->subtype.source_subtype;
|
||||
|
||||
mutex_lock(&coresight_mutex);
|
||||
|
||||
ret = coresight_validate_source(csdev, __func__);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (csdev->enable) {
|
||||
/*
|
||||
* There could be multiple applications driving the software
|
||||
* source. So keep the refcount for each such user when the
|
||||
* source is already enabled.
|
||||
*/
|
||||
if (subtype == CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE)
|
||||
atomic_inc(&csdev->refcnt);
|
||||
goto out;
|
||||
}
|
||||
|
||||
sink = coresight_get_enabled_sink(csdev);
|
||||
if (!sink) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
path = coresight_build_path(csdev, sink);
|
||||
if (IS_ERR(path)) {
|
||||
pr_err("building path(s) failed\n");
|
||||
ret = PTR_ERR(path);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = coresight_enable_path(path, CS_MODE_SYSFS, NULL);
|
||||
if (ret)
|
||||
goto err_path;
|
||||
|
||||
ret = coresight_enable_source(csdev, CS_MODE_SYSFS, NULL);
|
||||
if (ret)
|
||||
goto err_source;
|
||||
|
||||
switch (subtype) {
|
||||
case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC:
|
||||
/*
|
||||
* When working from sysFS it is important to keep track
|
||||
* of the paths that were created so that they can be
|
||||
* undone in 'coresight_disable()'. Since there can only
|
||||
* be a single session per tracer (when working from sysFS)
|
||||
* a per-cpu variable will do just fine.
|
||||
*/
|
||||
cpu = source_ops(csdev)->cpu_id(csdev);
|
||||
per_cpu(tracer_path, cpu) = path;
|
||||
break;
|
||||
case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE:
|
||||
case CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM:
|
||||
case CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS:
|
||||
/*
|
||||
* Use the hash of source's device name as ID
|
||||
* and map the ID to the pointer of the path.
|
||||
*/
|
||||
hash = hashlen_hash(hashlen_string(NULL, dev_name(&csdev->dev)));
|
||||
ret = idr_alloc_u32(&path_idr, path, &hash, hash, GFP_KERNEL);
|
||||
if (ret)
|
||||
goto err_source;
|
||||
break;
|
||||
default:
|
||||
/* We can't be here */
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&coresight_mutex);
|
||||
return ret;
|
||||
|
||||
err_source:
|
||||
coresight_disable_path(path);
|
||||
|
||||
err_path:
|
||||
coresight_release_path(path);
|
||||
goto out;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(coresight_enable);
|
||||
|
||||
void coresight_disable(struct coresight_device *csdev)
|
||||
{
|
||||
int cpu, ret;
|
||||
struct list_head *path = NULL;
|
||||
u32 hash;
|
||||
|
||||
mutex_lock(&coresight_mutex);
|
||||
|
||||
ret = coresight_validate_source(csdev, __func__);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (!csdev->enable || !coresight_disable_source(csdev, NULL))
|
||||
goto out;
|
||||
|
||||
switch (csdev->subtype.source_subtype) {
|
||||
case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC:
|
||||
cpu = source_ops(csdev)->cpu_id(csdev);
|
||||
path = per_cpu(tracer_path, cpu);
|
||||
per_cpu(tracer_path, cpu) = NULL;
|
||||
break;
|
||||
case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE:
|
||||
case CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM:
|
||||
case CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS:
|
||||
hash = hashlen_hash(hashlen_string(NULL, dev_name(&csdev->dev)));
|
||||
/* Find the path by the hash. */
|
||||
path = idr_find(&path_idr, hash);
|
||||
if (path == NULL) {
|
||||
pr_err("Path is not found for %s\n", dev_name(&csdev->dev));
|
||||
goto out;
|
||||
}
|
||||
idr_remove(&path_idr, hash);
|
||||
break;
|
||||
default:
|
||||
/* We can't be here */
|
||||
break;
|
||||
}
|
||||
|
||||
coresight_disable_path(path);
|
||||
coresight_release_path(path);
|
||||
|
||||
out:
|
||||
mutex_unlock(&coresight_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(coresight_disable);
|
||||
|
||||
static ssize_t enable_sink_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct coresight_device *csdev = to_coresight_device(dev);
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%u\n", csdev->activated);
|
||||
}
|
||||
|
||||
static ssize_t enable_sink_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
int ret;
|
||||
unsigned long val;
|
||||
struct coresight_device *csdev = to_coresight_device(dev);
|
||||
|
||||
ret = kstrtoul(buf, 10, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (val)
|
||||
csdev->activated = true;
|
||||
else
|
||||
csdev->activated = false;
|
||||
|
||||
return size;
|
||||
|
||||
}
|
||||
static DEVICE_ATTR_RW(enable_sink);
|
||||
|
||||
static ssize_t enable_source_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct coresight_device *csdev = to_coresight_device(dev);
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%u\n", csdev->enable);
|
||||
}
|
||||
|
||||
static ssize_t enable_source_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned long val;
|
||||
struct coresight_device *csdev = to_coresight_device(dev);
|
||||
|
||||
ret = kstrtoul(buf, 10, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (val) {
|
||||
ret = coresight_enable(csdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
coresight_disable(csdev);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
static DEVICE_ATTR_RW(enable_source);
|
||||
|
||||
static struct attribute *coresight_sink_attrs[] = {
|
||||
&dev_attr_enable_sink.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(coresight_sink);
|
||||
|
||||
static struct attribute *coresight_source_attrs[] = {
|
||||
&dev_attr_enable_source.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(coresight_source);
|
||||
|
||||
static struct device_type coresight_dev_type[] = {
|
||||
{
|
||||
.name = "sink",
|
||||
.groups = coresight_sink_groups,
|
||||
},
|
||||
{
|
||||
.name = "link",
|
||||
},
|
||||
{
|
||||
.name = "linksink",
|
||||
.groups = coresight_sink_groups,
|
||||
},
|
||||
{
|
||||
.name = "source",
|
||||
.groups = coresight_source_groups,
|
||||
},
|
||||
{
|
||||
.name = "helper",
|
||||
}
|
||||
};
|
||||
/* Ensure the enum matches the names and groups */
|
||||
static_assert(ARRAY_SIZE(coresight_dev_type) == CORESIGHT_DEV_TYPE_MAX);
|
||||
|
||||
static void coresight_device_release(struct device *dev)
|
||||
{
|
||||
struct coresight_device *csdev = to_coresight_device(dev);
|
||||
@ -1799,7 +1361,7 @@ char *coresight_alloc_device_name(struct coresight_dev_list *dict,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(coresight_alloc_device_name);
|
||||
|
||||
struct bus_type coresight_bustype = {
|
||||
const struct bus_type coresight_bustype = {
|
||||
.name = "coresight",
|
||||
};
|
||||
|
||||
|
@ -974,7 +974,7 @@ static const struct amba_id cti_ids[] = {
|
||||
CS_AMBA_ID(0x000bb9aa), /* CTI - C-A73 */
|
||||
CS_AMBA_UCI_ID(0x000bb9da, uci_id_cti), /* CTI - C-A35 */
|
||||
CS_AMBA_UCI_ID(0x000bb9ed, uci_id_cti), /* Coresight CTI (SoC 600) */
|
||||
{ 0, 0},
|
||||
{ 0, 0, NULL },
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(amba, cti_ids);
|
||||
|
@ -76,7 +76,6 @@ DEFINE_CORESIGHT_DEVLIST(etb_devs, "etb");
|
||||
* @pid: Process ID of the process being monitored by the session
|
||||
* that is using this component.
|
||||
* @buf: area of memory where ETB buffer content gets sent.
|
||||
* @mode: this ETB is being used.
|
||||
* @buffer_depth: size of @buf.
|
||||
* @trigger_cntr: amount of words to store after a trigger.
|
||||
*/
|
||||
@ -89,7 +88,6 @@ struct etb_drvdata {
|
||||
local_t reading;
|
||||
pid_t pid;
|
||||
u8 *buf;
|
||||
u32 mode;
|
||||
u32 buffer_depth;
|
||||
u32 trigger_cntr;
|
||||
};
|
||||
@ -150,20 +148,20 @@ static int etb_enable_sysfs(struct coresight_device *csdev)
|
||||
spin_lock_irqsave(&drvdata->spinlock, flags);
|
||||
|
||||
/* Don't messup with perf sessions. */
|
||||
if (drvdata->mode == CS_MODE_PERF) {
|
||||
if (coresight_get_mode(csdev) == CS_MODE_PERF) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (drvdata->mode == CS_MODE_DISABLED) {
|
||||
if (coresight_get_mode(csdev) == CS_MODE_DISABLED) {
|
||||
ret = etb_enable_hw(drvdata);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
drvdata->mode = CS_MODE_SYSFS;
|
||||
coresight_set_mode(csdev, CS_MODE_SYSFS);
|
||||
}
|
||||
|
||||
atomic_inc(&csdev->refcnt);
|
||||
csdev->refcnt++;
|
||||
out:
|
||||
spin_unlock_irqrestore(&drvdata->spinlock, flags);
|
||||
return ret;
|
||||
@ -181,7 +179,7 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data)
|
||||
spin_lock_irqsave(&drvdata->spinlock, flags);
|
||||
|
||||
/* No need to continue if the component is already in used by sysFS. */
|
||||
if (drvdata->mode == CS_MODE_SYSFS) {
|
||||
if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
@ -199,7 +197,7 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data)
|
||||
* use for this session.
|
||||
*/
|
||||
if (drvdata->pid == pid) {
|
||||
atomic_inc(&csdev->refcnt);
|
||||
csdev->refcnt++;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -216,8 +214,8 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data)
|
||||
if (!ret) {
|
||||
/* Associate with monitored process. */
|
||||
drvdata->pid = pid;
|
||||
drvdata->mode = CS_MODE_PERF;
|
||||
atomic_inc(&csdev->refcnt);
|
||||
coresight_set_mode(drvdata->csdev, CS_MODE_PERF);
|
||||
csdev->refcnt++;
|
||||
}
|
||||
|
||||
out:
|
||||
@ -356,17 +354,18 @@ static int etb_disable(struct coresight_device *csdev)
|
||||
|
||||
spin_lock_irqsave(&drvdata->spinlock, flags);
|
||||
|
||||
if (atomic_dec_return(&csdev->refcnt)) {
|
||||
csdev->refcnt--;
|
||||
if (csdev->refcnt) {
|
||||
spin_unlock_irqrestore(&drvdata->spinlock, flags);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* Complain if we (somehow) got out of sync */
|
||||
WARN_ON_ONCE(drvdata->mode == CS_MODE_DISABLED);
|
||||
WARN_ON_ONCE(coresight_get_mode(csdev) == CS_MODE_DISABLED);
|
||||
etb_disable_hw(drvdata);
|
||||
/* Dissociate from monitored process. */
|
||||
drvdata->pid = -1;
|
||||
drvdata->mode = CS_MODE_DISABLED;
|
||||
coresight_set_mode(csdev, CS_MODE_DISABLED);
|
||||
spin_unlock_irqrestore(&drvdata->spinlock, flags);
|
||||
|
||||
dev_dbg(&csdev->dev, "ETB disabled\n");
|
||||
@ -447,7 +446,7 @@ static unsigned long etb_update_buffer(struct coresight_device *csdev,
|
||||
spin_lock_irqsave(&drvdata->spinlock, flags);
|
||||
|
||||
/* Don't do anything if another tracer is using this sink */
|
||||
if (atomic_read(&csdev->refcnt) != 1)
|
||||
if (csdev->refcnt != 1)
|
||||
goto out;
|
||||
|
||||
__etb_disable_hw(drvdata);
|
||||
@ -589,7 +588,7 @@ static void etb_dump(struct etb_drvdata *drvdata)
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&drvdata->spinlock, flags);
|
||||
if (drvdata->mode == CS_MODE_SYSFS) {
|
||||
if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) {
|
||||
__etb_disable_hw(drvdata);
|
||||
etb_dump_hw(drvdata);
|
||||
__etb_enable_hw(drvdata);
|
||||
@ -837,7 +836,7 @@ static const struct amba_id etb_ids[] = {
|
||||
.id = 0x000bb907,
|
||||
.mask = 0x000fffff,
|
||||
},
|
||||
{ 0, 0},
|
||||
{ 0, 0, NULL },
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(amba, etb_ids);
|
||||
|
@ -589,7 +589,7 @@ static void etm_event_stop(struct perf_event *event, int mode)
|
||||
return;
|
||||
|
||||
/* stop tracer */
|
||||
source_ops(csdev)->disable(csdev, event);
|
||||
coresight_disable_source(csdev, event);
|
||||
|
||||
/* tell the core */
|
||||
event->hw.state = PERF_HES_STOPPED;
|
||||
|
@ -215,7 +215,6 @@ struct etm_config {
|
||||
* @port_size: port size as reported by ETMCR bit 4-6 and 21.
|
||||
* @arch: ETM/PTM version number.
|
||||
* @use_cpu14: true if management registers need to be accessed via CP14.
|
||||
* @mode: this tracer's mode, i.e sysFS, Perf or disabled.
|
||||
* @sticky_enable: true if ETM base configuration has been done.
|
||||
* @boot_enable:true if we should start tracing at boot time.
|
||||
* @os_unlock: true if access to management registers is allowed.
|
||||
@ -238,7 +237,6 @@ struct etm_drvdata {
|
||||
int port_size;
|
||||
u8 arch;
|
||||
bool use_cp14;
|
||||
local_t mode;
|
||||
bool sticky_enable;
|
||||
bool boot_enable;
|
||||
bool os_unlock;
|
||||
|
@ -115,7 +115,7 @@ static void etm_clr_pwrup(struct etm_drvdata *drvdata)
|
||||
*
|
||||
* Basically the same as @coresight_timeout except for the register access
|
||||
* method where we have to account for CP14 configurations.
|
||||
|
||||
*
|
||||
* Return: 0 as soon as the bit has taken the desired state or -EAGAIN if
|
||||
* TIMEOUT_US has elapsed, which ever happens first.
|
||||
*/
|
||||
@ -556,14 +556,12 @@ static int etm_enable(struct coresight_device *csdev, struct perf_event *event,
|
||||
enum cs_mode mode)
|
||||
{
|
||||
int ret;
|
||||
u32 val;
|
||||
struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
|
||||
|
||||
val = local_cmpxchg(&drvdata->mode, CS_MODE_DISABLED, mode);
|
||||
|
||||
/* Someone is already using the tracer */
|
||||
if (val)
|
||||
if (!coresight_take_mode(csdev, mode)) {
|
||||
/* Someone is already using the tracer */
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
case CS_MODE_SYSFS:
|
||||
@ -578,7 +576,7 @@ static int etm_enable(struct coresight_device *csdev, struct perf_event *event,
|
||||
|
||||
/* The tracer didn't start */
|
||||
if (ret)
|
||||
local_set(&drvdata->mode, CS_MODE_DISABLED);
|
||||
coresight_set_mode(drvdata->csdev, CS_MODE_DISABLED);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -672,14 +670,13 @@ static void etm_disable(struct coresight_device *csdev,
|
||||
struct perf_event *event)
|
||||
{
|
||||
enum cs_mode mode;
|
||||
struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
|
||||
|
||||
/*
|
||||
* For as long as the tracer isn't disabled another entity can't
|
||||
* change its status. As such we can read the status here without
|
||||
* fearing it will change under us.
|
||||
*/
|
||||
mode = local_read(&drvdata->mode);
|
||||
mode = coresight_get_mode(csdev);
|
||||
|
||||
switch (mode) {
|
||||
case CS_MODE_DISABLED:
|
||||
@ -696,7 +693,7 @@ static void etm_disable(struct coresight_device *csdev,
|
||||
}
|
||||
|
||||
if (mode)
|
||||
local_set(&drvdata->mode, CS_MODE_DISABLED);
|
||||
coresight_set_mode(csdev, CS_MODE_DISABLED);
|
||||
}
|
||||
|
||||
static const struct coresight_ops_source etm_source_ops = {
|
||||
@ -715,7 +712,7 @@ static int etm_online_cpu(unsigned int cpu)
|
||||
return 0;
|
||||
|
||||
if (etmdrvdata[cpu]->boot_enable && !etmdrvdata[cpu]->sticky_enable)
|
||||
coresight_enable(etmdrvdata[cpu]->csdev);
|
||||
coresight_enable_sysfs(etmdrvdata[cpu]->csdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -730,7 +727,7 @@ static int etm_starting_cpu(unsigned int cpu)
|
||||
etmdrvdata[cpu]->os_unlock = true;
|
||||
}
|
||||
|
||||
if (local_read(&etmdrvdata[cpu]->mode))
|
||||
if (coresight_get_mode(etmdrvdata[cpu]->csdev))
|
||||
etm_enable_hw(etmdrvdata[cpu]);
|
||||
spin_unlock(&etmdrvdata[cpu]->spinlock);
|
||||
return 0;
|
||||
@ -742,7 +739,7 @@ static int etm_dying_cpu(unsigned int cpu)
|
||||
return 0;
|
||||
|
||||
spin_lock(&etmdrvdata[cpu]->spinlock);
|
||||
if (local_read(&etmdrvdata[cpu]->mode))
|
||||
if (coresight_get_mode(etmdrvdata[cpu]->csdev))
|
||||
etm_disable_hw(etmdrvdata[cpu]);
|
||||
spin_unlock(&etmdrvdata[cpu]->spinlock);
|
||||
return 0;
|
||||
@ -925,7 +922,7 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id)
|
||||
dev_info(&drvdata->csdev->dev,
|
||||
"%s initialized\n", (char *)coresight_get_uci_data(id));
|
||||
if (boot_enable) {
|
||||
coresight_enable(drvdata->csdev);
|
||||
coresight_enable_sysfs(drvdata->csdev);
|
||||
drvdata->boot_enable = true;
|
||||
}
|
||||
|
||||
@ -1003,7 +1000,7 @@ static const struct amba_id etm_ids[] = {
|
||||
CS_AMBA_ID_DATA(0x000bb95f, "PTM 1.1"),
|
||||
/* PTM 1.1 Qualcomm */
|
||||
CS_AMBA_ID_DATA(0x000b006f, "PTM 1.1"),
|
||||
{ 0, 0},
|
||||
{ 0, 0, NULL},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(amba, etm_ids);
|
||||
|
@ -722,7 +722,7 @@ static ssize_t cntr_val_show(struct device *dev,
|
||||
struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
struct etm_config *config = &drvdata->config;
|
||||
|
||||
if (!local_read(&drvdata->mode)) {
|
||||
if (!coresight_get_mode(drvdata->csdev)) {
|
||||
spin_lock(&drvdata->spinlock);
|
||||
for (i = 0; i < drvdata->nr_cntr; i++)
|
||||
ret += sprintf(buf, "counter %d: %x\n",
|
||||
@ -941,7 +941,7 @@ static ssize_t seq_curr_state_show(struct device *dev,
|
||||
struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
struct etm_config *config = &drvdata->config;
|
||||
|
||||
if (!local_read(&drvdata->mode)) {
|
||||
if (!coresight_get_mode(drvdata->csdev)) {
|
||||
val = config->seq_curr_state;
|
||||
goto out;
|
||||
}
|
||||
|
@ -840,14 +840,11 @@ static int etm4_enable(struct coresight_device *csdev, struct perf_event *event,
|
||||
enum cs_mode mode)
|
||||
{
|
||||
int ret;
|
||||
u32 val;
|
||||
struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
|
||||
|
||||
val = local_cmpxchg(&drvdata->mode, CS_MODE_DISABLED, mode);
|
||||
|
||||
/* Someone is already using the tracer */
|
||||
if (val)
|
||||
if (!coresight_take_mode(csdev, mode)) {
|
||||
/* Someone is already using the tracer */
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
case CS_MODE_SYSFS:
|
||||
@ -862,7 +859,7 @@ static int etm4_enable(struct coresight_device *csdev, struct perf_event *event,
|
||||
|
||||
/* The tracer didn't start */
|
||||
if (ret)
|
||||
local_set(&drvdata->mode, CS_MODE_DISABLED);
|
||||
coresight_set_mode(csdev, CS_MODE_DISABLED);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -1004,14 +1001,13 @@ static void etm4_disable(struct coresight_device *csdev,
|
||||
struct perf_event *event)
|
||||
{
|
||||
enum cs_mode mode;
|
||||
struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
|
||||
|
||||
/*
|
||||
* For as long as the tracer isn't disabled another entity can't
|
||||
* change its status. As such we can read the status here without
|
||||
* fearing it will change under us.
|
||||
*/
|
||||
mode = local_read(&drvdata->mode);
|
||||
mode = coresight_get_mode(csdev);
|
||||
|
||||
switch (mode) {
|
||||
case CS_MODE_DISABLED:
|
||||
@ -1025,7 +1021,7 @@ static void etm4_disable(struct coresight_device *csdev,
|
||||
}
|
||||
|
||||
if (mode)
|
||||
local_set(&drvdata->mode, CS_MODE_DISABLED);
|
||||
coresight_set_mode(csdev, CS_MODE_DISABLED);
|
||||
}
|
||||
|
||||
static const struct coresight_ops_source etm4_source_ops = {
|
||||
@ -1200,6 +1196,7 @@ static void etm4_init_arch_data(void *info)
|
||||
struct etm4_init_arg *init_arg = info;
|
||||
struct etmv4_drvdata *drvdata;
|
||||
struct csdev_access *csa;
|
||||
struct device *dev = init_arg->dev;
|
||||
int i;
|
||||
|
||||
drvdata = dev_get_drvdata(init_arg->dev);
|
||||
@ -1213,6 +1210,10 @@ static void etm4_init_arch_data(void *info)
|
||||
if (!etm4_init_csdev_access(drvdata, csa))
|
||||
return;
|
||||
|
||||
if (!csa->io_mem ||
|
||||
fwnode_property_present(dev_fwnode(dev), "qcom,skip-power-up"))
|
||||
drvdata->skip_power_up = true;
|
||||
|
||||
/* Detect the support for OS Lock before we actually use it */
|
||||
etm_detect_os_lock(drvdata, csa);
|
||||
|
||||
@ -1650,7 +1651,7 @@ static int etm4_online_cpu(unsigned int cpu)
|
||||
return etm4_probe_cpu(cpu);
|
||||
|
||||
if (etmdrvdata[cpu]->boot_enable && !etmdrvdata[cpu]->sticky_enable)
|
||||
coresight_enable(etmdrvdata[cpu]->csdev);
|
||||
coresight_enable_sysfs(etmdrvdata[cpu]->csdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1663,7 +1664,7 @@ static int etm4_starting_cpu(unsigned int cpu)
|
||||
if (!etmdrvdata[cpu]->os_unlock)
|
||||
etm4_os_unlock(etmdrvdata[cpu]);
|
||||
|
||||
if (local_read(&etmdrvdata[cpu]->mode))
|
||||
if (coresight_get_mode(etmdrvdata[cpu]->csdev))
|
||||
etm4_enable_hw(etmdrvdata[cpu]);
|
||||
spin_unlock(&etmdrvdata[cpu]->spinlock);
|
||||
return 0;
|
||||
@ -1675,7 +1676,7 @@ static int etm4_dying_cpu(unsigned int cpu)
|
||||
return 0;
|
||||
|
||||
spin_lock(&etmdrvdata[cpu]->spinlock);
|
||||
if (local_read(&etmdrvdata[cpu]->mode))
|
||||
if (coresight_get_mode(etmdrvdata[cpu]->csdev))
|
||||
etm4_disable_hw(etmdrvdata[cpu]);
|
||||
spin_unlock(&etmdrvdata[cpu]->spinlock);
|
||||
return 0;
|
||||
@ -1833,7 +1834,7 @@ static int etm4_cpu_save(struct etmv4_drvdata *drvdata)
|
||||
* Save and restore the ETM Trace registers only if
|
||||
* the ETM is active.
|
||||
*/
|
||||
if (local_read(&drvdata->mode) && drvdata->save_state)
|
||||
if (coresight_get_mode(drvdata->csdev) && drvdata->save_state)
|
||||
ret = __etm4_cpu_save(drvdata);
|
||||
return ret;
|
||||
}
|
||||
@ -2040,11 +2041,6 @@ static int etm4_add_coresight_dev(struct etm4_init_arg *init_arg)
|
||||
if (!drvdata->arch)
|
||||
return -EINVAL;
|
||||
|
||||
/* TRCPDCR is not accessible with system instructions. */
|
||||
if (!desc.access.io_mem ||
|
||||
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);
|
||||
|
||||
@ -2098,7 +2094,7 @@ static int etm4_add_coresight_dev(struct etm4_init_arg *init_arg)
|
||||
drvdata->cpu, type_name, major, minor);
|
||||
|
||||
if (boot_enable) {
|
||||
coresight_enable(drvdata->csdev);
|
||||
coresight_enable_sysfs(drvdata->csdev);
|
||||
drvdata->boot_enable = true;
|
||||
}
|
||||
|
||||
@ -2390,7 +2386,7 @@ static const struct of_device_id etm4_sysreg_match[] = {
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id etm4x_acpi_ids[] = {
|
||||
{"ARMHC500", 0}, /* ARM CoreSight ETM4x */
|
||||
{"ARMHC500", 0, 0, 0}, /* ARM CoreSight ETM4x */
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, etm4x_acpi_ids);
|
||||
|
@ -1016,7 +1016,6 @@ struct etmv4_drvdata {
|
||||
void __iomem *base;
|
||||
struct coresight_device *csdev;
|
||||
spinlock_t spinlock;
|
||||
local_t mode;
|
||||
int cpu;
|
||||
u8 arch;
|
||||
u8 nr_pe;
|
||||
|
@ -350,7 +350,7 @@ MODULE_DEVICE_TABLE(of, static_funnel_match);
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id static_funnel_ids[] = {
|
||||
{"ARMHC9FE", 0},
|
||||
{"ARMHC9FE", 0, 0, 0},
|
||||
{},
|
||||
};
|
||||
|
||||
@ -391,7 +391,7 @@ static const struct amba_id dynamic_funnel_ids[] = {
|
||||
.id = 0x000bb9eb,
|
||||
.mask = 0x000fffff,
|
||||
},
|
||||
{ 0, 0},
|
||||
{ 0, 0, NULL },
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(amba, dynamic_funnel_ids);
|
||||
|
@ -12,6 +12,9 @@
|
||||
#include <linux/coresight.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
extern struct mutex coresight_mutex;
|
||||
extern struct device_type coresight_dev_type[];
|
||||
|
||||
/*
|
||||
* Coresight management registers (0xf00-0xfcc)
|
||||
* 0xfa0 - 0xfa4: Management registers in PFTv1.0
|
||||
@ -130,8 +133,6 @@ void coresight_disable_path(struct list_head *path);
|
||||
int coresight_enable_path(struct list_head *path, enum cs_mode mode,
|
||||
void *sink_data);
|
||||
struct coresight_device *coresight_get_sink(struct list_head *path);
|
||||
struct coresight_device *
|
||||
coresight_get_enabled_sink(struct coresight_device *source);
|
||||
struct coresight_device *coresight_get_sink_by_id(u32 id);
|
||||
struct coresight_device *
|
||||
coresight_find_default_sink(struct coresight_device *csdev);
|
||||
@ -231,8 +232,6 @@ void coresight_add_helper(struct coresight_device *csdev,
|
||||
|
||||
void coresight_set_percpu_sink(int cpu, struct coresight_device *csdev);
|
||||
struct coresight_device *coresight_get_percpu_sink(int cpu);
|
||||
int coresight_enable_source(struct coresight_device *csdev, enum cs_mode mode,
|
||||
void *data);
|
||||
bool coresight_disable_source(struct coresight_device *csdev, void *data);
|
||||
void coresight_disable_source(struct coresight_device *csdev, void *data);
|
||||
|
||||
#endif
|
||||
|
@ -363,7 +363,7 @@ MODULE_DEVICE_TABLE(of, static_replicator_match);
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id static_replicator_acpi_ids[] = {
|
||||
{"ARMHC985", 0}, /* ARM CoreSight Static Replicator */
|
||||
{"ARMHC985", 0, 0, 0}, /* ARM CoreSight Static Replicator */
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -119,7 +119,6 @@ DEFINE_CORESIGHT_DEVLIST(stm_devs, "stm");
|
||||
* @spinlock: only one at a time pls.
|
||||
* @chs: the channels accociated to this STM.
|
||||
* @stm: structure associated to the generic STM interface.
|
||||
* @mode: this tracer's mode (enum cs_mode), i.e sysFS, or disabled.
|
||||
* @traceid: value of the current ID for this component.
|
||||
* @write_bytes: Maximus bytes this STM can write at a time.
|
||||
* @stmsper: settings for register STMSPER.
|
||||
@ -136,7 +135,6 @@ struct stm_drvdata {
|
||||
spinlock_t spinlock;
|
||||
struct channel_space chs;
|
||||
struct stm_data stm;
|
||||
local_t mode;
|
||||
u8 traceid;
|
||||
u32 write_bytes;
|
||||
u32 stmsper;
|
||||
@ -195,17 +193,15 @@ static void stm_enable_hw(struct stm_drvdata *drvdata)
|
||||
static int stm_enable(struct coresight_device *csdev, struct perf_event *event,
|
||||
enum cs_mode mode)
|
||||
{
|
||||
u32 val;
|
||||
struct stm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
|
||||
|
||||
if (mode != CS_MODE_SYSFS)
|
||||
return -EINVAL;
|
||||
|
||||
val = local_cmpxchg(&drvdata->mode, CS_MODE_DISABLED, mode);
|
||||
|
||||
/* Someone is already using the tracer */
|
||||
if (val)
|
||||
if (!coresight_take_mode(csdev, mode)) {
|
||||
/* Someone is already using the tracer */
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
pm_runtime_get_sync(csdev->dev.parent);
|
||||
|
||||
@ -266,7 +262,7 @@ static void stm_disable(struct coresight_device *csdev,
|
||||
* change its status. As such we can read the status here without
|
||||
* fearing it will change under us.
|
||||
*/
|
||||
if (local_read(&drvdata->mode) == CS_MODE_SYSFS) {
|
||||
if (coresight_get_mode(csdev) == CS_MODE_SYSFS) {
|
||||
spin_lock(&drvdata->spinlock);
|
||||
stm_disable_hw(drvdata);
|
||||
spin_unlock(&drvdata->spinlock);
|
||||
@ -276,7 +272,7 @@ static void stm_disable(struct coresight_device *csdev,
|
||||
|
||||
pm_runtime_put(csdev->dev.parent);
|
||||
|
||||
local_set(&drvdata->mode, CS_MODE_DISABLED);
|
||||
coresight_set_mode(csdev, CS_MODE_DISABLED);
|
||||
dev_dbg(&csdev->dev, "STM tracing disabled\n");
|
||||
}
|
||||
}
|
||||
@ -334,7 +330,7 @@ static int stm_generic_link(struct stm_data *stm_data,
|
||||
if (!drvdata || !drvdata->csdev)
|
||||
return -EINVAL;
|
||||
|
||||
return coresight_enable(drvdata->csdev);
|
||||
return coresight_enable_sysfs(drvdata->csdev);
|
||||
}
|
||||
|
||||
static void stm_generic_unlink(struct stm_data *stm_data,
|
||||
@ -345,7 +341,7 @@ static void stm_generic_unlink(struct stm_data *stm_data,
|
||||
if (!drvdata || !drvdata->csdev)
|
||||
return;
|
||||
|
||||
coresight_disable(drvdata->csdev);
|
||||
coresight_disable_sysfs(drvdata->csdev);
|
||||
}
|
||||
|
||||
static phys_addr_t
|
||||
@ -373,7 +369,7 @@ static long stm_generic_set_options(struct stm_data *stm_data,
|
||||
{
|
||||
struct stm_drvdata *drvdata = container_of(stm_data,
|
||||
struct stm_drvdata, stm);
|
||||
if (!(drvdata && local_read(&drvdata->mode)))
|
||||
if (!(drvdata && coresight_get_mode(drvdata->csdev)))
|
||||
return -EINVAL;
|
||||
|
||||
if (channel >= drvdata->numsp)
|
||||
@ -408,7 +404,7 @@ static ssize_t notrace stm_generic_packet(struct stm_data *stm_data,
|
||||
struct stm_drvdata, stm);
|
||||
unsigned int stm_flags;
|
||||
|
||||
if (!(drvdata && local_read(&drvdata->mode)))
|
||||
if (!(drvdata && coresight_get_mode(drvdata->csdev)))
|
||||
return -EACCES;
|
||||
|
||||
if (channel >= drvdata->numsp)
|
||||
@ -515,7 +511,7 @@ static ssize_t port_select_show(struct device *dev,
|
||||
struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
unsigned long val;
|
||||
|
||||
if (!local_read(&drvdata->mode)) {
|
||||
if (!coresight_get_mode(drvdata->csdev)) {
|
||||
val = drvdata->stmspscr;
|
||||
} else {
|
||||
spin_lock(&drvdata->spinlock);
|
||||
@ -541,7 +537,7 @@ static ssize_t port_select_store(struct device *dev,
|
||||
spin_lock(&drvdata->spinlock);
|
||||
drvdata->stmspscr = val;
|
||||
|
||||
if (local_read(&drvdata->mode)) {
|
||||
if (coresight_get_mode(drvdata->csdev)) {
|
||||
CS_UNLOCK(drvdata->base);
|
||||
/* Process as per ARM's TRM recommendation */
|
||||
stmsper = readl_relaxed(drvdata->base + STMSPER);
|
||||
@ -562,7 +558,7 @@ static ssize_t port_enable_show(struct device *dev,
|
||||
struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
unsigned long val;
|
||||
|
||||
if (!local_read(&drvdata->mode)) {
|
||||
if (!coresight_get_mode(drvdata->csdev)) {
|
||||
val = drvdata->stmsper;
|
||||
} else {
|
||||
spin_lock(&drvdata->spinlock);
|
||||
@ -588,7 +584,7 @@ static ssize_t port_enable_store(struct device *dev,
|
||||
spin_lock(&drvdata->spinlock);
|
||||
drvdata->stmsper = val;
|
||||
|
||||
if (local_read(&drvdata->mode)) {
|
||||
if (coresight_get_mode(drvdata->csdev)) {
|
||||
CS_UNLOCK(drvdata->base);
|
||||
writel_relaxed(drvdata->stmsper, drvdata->base + STMSPER);
|
||||
CS_LOCK(drvdata->base);
|
||||
@ -950,7 +946,7 @@ static const struct dev_pm_ops stm_dev_pm_ops = {
|
||||
static const struct amba_id stm_ids[] = {
|
||||
CS_AMBA_ID_DATA(0x000bb962, "STM32"),
|
||||
CS_AMBA_ID_DATA(0x000bb963, "STM500"),
|
||||
{ 0, 0},
|
||||
{ 0, 0, NULL },
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(amba, stm_ids);
|
||||
|
@ -5,10 +5,401 @@
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include "coresight-priv.h"
|
||||
|
||||
/*
|
||||
* Use IDR to map the hash of the source's device name
|
||||
* to the pointer of path for the source. The idr is for
|
||||
* the sources which aren't associated with CPU.
|
||||
*/
|
||||
static DEFINE_IDR(path_idr);
|
||||
|
||||
/*
|
||||
* When operating Coresight drivers from the sysFS interface, only a single
|
||||
* path can exist from a tracer (associated to a CPU) to a sink.
|
||||
*/
|
||||
static DEFINE_PER_CPU(struct list_head *, tracer_path);
|
||||
|
||||
ssize_t coresight_simple_show_pair(struct device *_dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct coresight_device *csdev = container_of(_dev, struct coresight_device, dev);
|
||||
struct cs_pair_attribute *cs_attr = container_of(attr, struct cs_pair_attribute, attr);
|
||||
u64 val;
|
||||
|
||||
pm_runtime_get_sync(_dev->parent);
|
||||
val = csdev_access_relaxed_read_pair(&csdev->access, cs_attr->lo_off, cs_attr->hi_off);
|
||||
pm_runtime_put_sync(_dev->parent);
|
||||
return sysfs_emit(buf, "0x%llx\n", val);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(coresight_simple_show_pair);
|
||||
|
||||
ssize_t coresight_simple_show32(struct device *_dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct coresight_device *csdev = container_of(_dev, struct coresight_device, dev);
|
||||
struct cs_off_attribute *cs_attr = container_of(attr, struct cs_off_attribute, attr);
|
||||
u64 val;
|
||||
|
||||
pm_runtime_get_sync(_dev->parent);
|
||||
val = csdev_access_relaxed_read32(&csdev->access, cs_attr->off);
|
||||
pm_runtime_put_sync(_dev->parent);
|
||||
return sysfs_emit(buf, "0x%llx\n", val);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(coresight_simple_show32);
|
||||
|
||||
static int coresight_enable_source_sysfs(struct coresight_device *csdev,
|
||||
enum cs_mode mode, void *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Comparison with CS_MODE_SYSFS works without taking any device
|
||||
* specific spinlock because the truthyness of that comparison can only
|
||||
* change with coresight_mutex held, which we already have here.
|
||||
*/
|
||||
lockdep_assert_held(&coresight_mutex);
|
||||
if (coresight_get_mode(csdev) != CS_MODE_SYSFS) {
|
||||
ret = source_ops(csdev)->enable(csdev, data, mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
csdev->refcnt++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* coresight_disable_source_sysfs - Drop the reference count by 1 and disable
|
||||
* the device if there are no users left.
|
||||
*
|
||||
* @csdev: The coresight device to disable
|
||||
* @data: Opaque data to pass on to the disable function of the source device.
|
||||
* For example in perf mode this is a pointer to the struct perf_event.
|
||||
*
|
||||
* Returns true if the device has been disabled.
|
||||
*/
|
||||
static bool coresight_disable_source_sysfs(struct coresight_device *csdev,
|
||||
void *data)
|
||||
{
|
||||
lockdep_assert_held(&coresight_mutex);
|
||||
if (coresight_get_mode(csdev) != CS_MODE_SYSFS)
|
||||
return false;
|
||||
|
||||
csdev->refcnt--;
|
||||
if (csdev->refcnt == 0) {
|
||||
coresight_disable_source(csdev, data);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* coresight_find_activated_sysfs_sink - returns the first sink activated via
|
||||
* sysfs using connection based search starting from the source reference.
|
||||
*
|
||||
* @csdev: Coresight source device reference
|
||||
*/
|
||||
static struct coresight_device *
|
||||
coresight_find_activated_sysfs_sink(struct coresight_device *csdev)
|
||||
{
|
||||
int i;
|
||||
struct coresight_device *sink = NULL;
|
||||
|
||||
if ((csdev->type == CORESIGHT_DEV_TYPE_SINK ||
|
||||
csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) &&
|
||||
csdev->sysfs_sink_activated)
|
||||
return csdev;
|
||||
|
||||
/*
|
||||
* Recursively explore each port found on this element.
|
||||
*/
|
||||
for (i = 0; i < csdev->pdata->nr_outconns; i++) {
|
||||
struct coresight_device *child_dev;
|
||||
|
||||
child_dev = csdev->pdata->out_conns[i]->dest_dev;
|
||||
if (child_dev)
|
||||
sink = coresight_find_activated_sysfs_sink(child_dev);
|
||||
if (sink)
|
||||
return sink;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** coresight_validate_source - make sure a source has the right credentials to
|
||||
* be used via sysfs.
|
||||
* @csdev: the device structure for a source.
|
||||
* @function: the function this was called from.
|
||||
*
|
||||
* Assumes the coresight_mutex is held.
|
||||
*/
|
||||
static int coresight_validate_source_sysfs(struct coresight_device *csdev,
|
||||
const char *function)
|
||||
{
|
||||
u32 type, subtype;
|
||||
|
||||
type = csdev->type;
|
||||
subtype = csdev->subtype.source_subtype;
|
||||
|
||||
if (type != CORESIGHT_DEV_TYPE_SOURCE) {
|
||||
dev_err(&csdev->dev, "wrong device type in %s\n", function);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_PROC &&
|
||||
subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE &&
|
||||
subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM &&
|
||||
subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS) {
|
||||
dev_err(&csdev->dev, "wrong device subtype in %s\n", function);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int coresight_enable_sysfs(struct coresight_device *csdev)
|
||||
{
|
||||
int cpu, ret = 0;
|
||||
struct coresight_device *sink;
|
||||
struct list_head *path;
|
||||
enum coresight_dev_subtype_source subtype;
|
||||
u32 hash;
|
||||
|
||||
subtype = csdev->subtype.source_subtype;
|
||||
|
||||
mutex_lock(&coresight_mutex);
|
||||
|
||||
ret = coresight_validate_source_sysfs(csdev, __func__);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* mode == SYSFS implies that it's already enabled. Don't look at the
|
||||
* refcount to determine this because we don't claim the source until
|
||||
* coresight_enable_source() so can still race with Perf mode which
|
||||
* doesn't hold coresight_mutex.
|
||||
*/
|
||||
if (coresight_get_mode(csdev) == CS_MODE_SYSFS) {
|
||||
/*
|
||||
* There could be multiple applications driving the software
|
||||
* source. So keep the refcount for each such user when the
|
||||
* source is already enabled.
|
||||
*/
|
||||
if (subtype == CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE)
|
||||
csdev->refcnt++;
|
||||
goto out;
|
||||
}
|
||||
|
||||
sink = coresight_find_activated_sysfs_sink(csdev);
|
||||
if (!sink) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
path = coresight_build_path(csdev, sink);
|
||||
if (IS_ERR(path)) {
|
||||
pr_err("building path(s) failed\n");
|
||||
ret = PTR_ERR(path);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = coresight_enable_path(path, CS_MODE_SYSFS, NULL);
|
||||
if (ret)
|
||||
goto err_path;
|
||||
|
||||
ret = coresight_enable_source_sysfs(csdev, CS_MODE_SYSFS, NULL);
|
||||
if (ret)
|
||||
goto err_source;
|
||||
|
||||
switch (subtype) {
|
||||
case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC:
|
||||
/*
|
||||
* When working from sysFS it is important to keep track
|
||||
* of the paths that were created so that they can be
|
||||
* undone in 'coresight_disable()'. Since there can only
|
||||
* be a single session per tracer (when working from sysFS)
|
||||
* a per-cpu variable will do just fine.
|
||||
*/
|
||||
cpu = source_ops(csdev)->cpu_id(csdev);
|
||||
per_cpu(tracer_path, cpu) = path;
|
||||
break;
|
||||
case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE:
|
||||
case CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM:
|
||||
case CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS:
|
||||
/*
|
||||
* Use the hash of source's device name as ID
|
||||
* and map the ID to the pointer of the path.
|
||||
*/
|
||||
hash = hashlen_hash(hashlen_string(NULL, dev_name(&csdev->dev)));
|
||||
ret = idr_alloc_u32(&path_idr, path, &hash, hash, GFP_KERNEL);
|
||||
if (ret)
|
||||
goto err_source;
|
||||
break;
|
||||
default:
|
||||
/* We can't be here */
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&coresight_mutex);
|
||||
return ret;
|
||||
|
||||
err_source:
|
||||
coresight_disable_path(path);
|
||||
|
||||
err_path:
|
||||
coresight_release_path(path);
|
||||
goto out;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(coresight_enable_sysfs);
|
||||
|
||||
void coresight_disable_sysfs(struct coresight_device *csdev)
|
||||
{
|
||||
int cpu, ret;
|
||||
struct list_head *path = NULL;
|
||||
u32 hash;
|
||||
|
||||
mutex_lock(&coresight_mutex);
|
||||
|
||||
ret = coresight_validate_source_sysfs(csdev, __func__);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (!coresight_disable_source_sysfs(csdev, NULL))
|
||||
goto out;
|
||||
|
||||
switch (csdev->subtype.source_subtype) {
|
||||
case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC:
|
||||
cpu = source_ops(csdev)->cpu_id(csdev);
|
||||
path = per_cpu(tracer_path, cpu);
|
||||
per_cpu(tracer_path, cpu) = NULL;
|
||||
break;
|
||||
case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE:
|
||||
case CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM:
|
||||
case CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS:
|
||||
hash = hashlen_hash(hashlen_string(NULL, dev_name(&csdev->dev)));
|
||||
/* Find the path by the hash. */
|
||||
path = idr_find(&path_idr, hash);
|
||||
if (path == NULL) {
|
||||
pr_err("Path is not found for %s\n", dev_name(&csdev->dev));
|
||||
goto out;
|
||||
}
|
||||
idr_remove(&path_idr, hash);
|
||||
break;
|
||||
default:
|
||||
/* We can't be here */
|
||||
break;
|
||||
}
|
||||
|
||||
coresight_disable_path(path);
|
||||
coresight_release_path(path);
|
||||
|
||||
out:
|
||||
mutex_unlock(&coresight_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(coresight_disable_sysfs);
|
||||
|
||||
static ssize_t enable_sink_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct coresight_device *csdev = to_coresight_device(dev);
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%u\n", csdev->sysfs_sink_activated);
|
||||
}
|
||||
|
||||
static ssize_t enable_sink_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
int ret;
|
||||
unsigned long val;
|
||||
struct coresight_device *csdev = to_coresight_device(dev);
|
||||
|
||||
ret = kstrtoul(buf, 10, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
csdev->sysfs_sink_activated = !!val;
|
||||
|
||||
return size;
|
||||
|
||||
}
|
||||
static DEVICE_ATTR_RW(enable_sink);
|
||||
|
||||
static ssize_t enable_source_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct coresight_device *csdev = to_coresight_device(dev);
|
||||
|
||||
guard(mutex)(&coresight_mutex);
|
||||
return scnprintf(buf, PAGE_SIZE, "%u\n",
|
||||
coresight_get_mode(csdev) == CS_MODE_SYSFS);
|
||||
}
|
||||
|
||||
static ssize_t enable_source_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned long val;
|
||||
struct coresight_device *csdev = to_coresight_device(dev);
|
||||
|
||||
ret = kstrtoul(buf, 10, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (val) {
|
||||
ret = coresight_enable_sysfs(csdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
coresight_disable_sysfs(csdev);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
static DEVICE_ATTR_RW(enable_source);
|
||||
|
||||
static struct attribute *coresight_sink_attrs[] = {
|
||||
&dev_attr_enable_sink.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(coresight_sink);
|
||||
|
||||
static struct attribute *coresight_source_attrs[] = {
|
||||
&dev_attr_enable_source.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(coresight_source);
|
||||
|
||||
struct device_type coresight_dev_type[] = {
|
||||
[CORESIGHT_DEV_TYPE_SINK] = {
|
||||
.name = "sink",
|
||||
.groups = coresight_sink_groups,
|
||||
},
|
||||
[CORESIGHT_DEV_TYPE_LINK] = {
|
||||
.name = "link",
|
||||
},
|
||||
[CORESIGHT_DEV_TYPE_LINKSINK] = {
|
||||
.name = "linksink",
|
||||
.groups = coresight_sink_groups,
|
||||
},
|
||||
[CORESIGHT_DEV_TYPE_SOURCE] = {
|
||||
.name = "source",
|
||||
.groups = coresight_source_groups,
|
||||
},
|
||||
[CORESIGHT_DEV_TYPE_HELPER] = {
|
||||
.name = "helper",
|
||||
}
|
||||
};
|
||||
/* Ensure the enum matches the names and groups */
|
||||
static_assert(ARRAY_SIZE(coresight_dev_type) == CORESIGHT_DEV_TYPE_MAX);
|
||||
|
||||
/*
|
||||
* Connections group - links attribute.
|
||||
* Count of created links between coresight components in the group.
|
||||
|
@ -558,7 +558,7 @@ static void tmc_shutdown(struct amba_device *adev)
|
||||
|
||||
spin_lock_irqsave(&drvdata->spinlock, flags);
|
||||
|
||||
if (drvdata->mode == CS_MODE_DISABLED)
|
||||
if (coresight_get_mode(drvdata->csdev) == CS_MODE_DISABLED)
|
||||
goto out;
|
||||
|
||||
if (drvdata->config_type == TMC_CONFIG_TYPE_ETR)
|
||||
@ -594,7 +594,7 @@ static const struct amba_id tmc_ids[] = {
|
||||
CS_AMBA_ID(0x000bb9e9),
|
||||
/* Coresight SoC 600 TMC-ETF */
|
||||
CS_AMBA_ID(0x000bb9ea),
|
||||
{ 0, 0},
|
||||
{ 0, 0, NULL },
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(amba, tmc_ids);
|
||||
|
@ -89,7 +89,7 @@ static void __tmc_etb_disable_hw(struct tmc_drvdata *drvdata)
|
||||
* When operating in sysFS mode the content of the buffer needs to be
|
||||
* read before the TMC is disabled.
|
||||
*/
|
||||
if (drvdata->mode == CS_MODE_SYSFS)
|
||||
if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS)
|
||||
tmc_etb_dump_hw(drvdata);
|
||||
tmc_disable_hw(drvdata);
|
||||
|
||||
@ -205,8 +205,8 @@ static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev)
|
||||
* sink is already enabled no memory is needed and the HW need not be
|
||||
* touched.
|
||||
*/
|
||||
if (drvdata->mode == CS_MODE_SYSFS) {
|
||||
atomic_inc(&csdev->refcnt);
|
||||
if (coresight_get_mode(csdev) == CS_MODE_SYSFS) {
|
||||
csdev->refcnt++;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -228,8 +228,8 @@ static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev)
|
||||
|
||||
ret = tmc_etb_enable_hw(drvdata);
|
||||
if (!ret) {
|
||||
drvdata->mode = CS_MODE_SYSFS;
|
||||
atomic_inc(&csdev->refcnt);
|
||||
coresight_set_mode(csdev, CS_MODE_SYSFS);
|
||||
csdev->refcnt++;
|
||||
} else {
|
||||
/* Free up the buffer if we failed to enable */
|
||||
used = false;
|
||||
@ -262,7 +262,7 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data)
|
||||
* No need to continue if the ETB/ETF is already operated
|
||||
* from sysFS.
|
||||
*/
|
||||
if (drvdata->mode == CS_MODE_SYSFS) {
|
||||
if (coresight_get_mode(csdev) == CS_MODE_SYSFS) {
|
||||
ret = -EBUSY;
|
||||
break;
|
||||
}
|
||||
@ -284,7 +284,7 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data)
|
||||
* use for this session.
|
||||
*/
|
||||
if (drvdata->pid == pid) {
|
||||
atomic_inc(&csdev->refcnt);
|
||||
csdev->refcnt++;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -292,8 +292,8 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data)
|
||||
if (!ret) {
|
||||
/* Associate with monitored process. */
|
||||
drvdata->pid = pid;
|
||||
drvdata->mode = CS_MODE_PERF;
|
||||
atomic_inc(&csdev->refcnt);
|
||||
coresight_set_mode(csdev, CS_MODE_PERF);
|
||||
csdev->refcnt++;
|
||||
}
|
||||
} while (0);
|
||||
spin_unlock_irqrestore(&drvdata->spinlock, flags);
|
||||
@ -338,17 +338,18 @@ static int tmc_disable_etf_sink(struct coresight_device *csdev)
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (atomic_dec_return(&csdev->refcnt)) {
|
||||
csdev->refcnt--;
|
||||
if (csdev->refcnt) {
|
||||
spin_unlock_irqrestore(&drvdata->spinlock, flags);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* Complain if we (somehow) got out of sync */
|
||||
WARN_ON_ONCE(drvdata->mode == CS_MODE_DISABLED);
|
||||
WARN_ON_ONCE(coresight_get_mode(csdev) == CS_MODE_DISABLED);
|
||||
tmc_etb_disable_hw(drvdata);
|
||||
/* Dissociate from monitored process. */
|
||||
drvdata->pid = -1;
|
||||
drvdata->mode = CS_MODE_DISABLED;
|
||||
coresight_set_mode(csdev, CS_MODE_DISABLED);
|
||||
|
||||
spin_unlock_irqrestore(&drvdata->spinlock, flags);
|
||||
|
||||
@ -371,15 +372,15 @@ static int tmc_enable_etf_link(struct coresight_device *csdev,
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (atomic_read(&csdev->refcnt) == 0) {
|
||||
if (csdev->refcnt == 0) {
|
||||
ret = tmc_etf_enable_hw(drvdata);
|
||||
if (!ret) {
|
||||
drvdata->mode = CS_MODE_SYSFS;
|
||||
coresight_set_mode(csdev, CS_MODE_SYSFS);
|
||||
first_enable = true;
|
||||
}
|
||||
}
|
||||
if (!ret)
|
||||
atomic_inc(&csdev->refcnt);
|
||||
csdev->refcnt++;
|
||||
spin_unlock_irqrestore(&drvdata->spinlock, flags);
|
||||
|
||||
if (first_enable)
|
||||
@ -401,9 +402,10 @@ static void tmc_disable_etf_link(struct coresight_device *csdev,
|
||||
return;
|
||||
}
|
||||
|
||||
if (atomic_dec_return(&csdev->refcnt) == 0) {
|
||||
csdev->refcnt--;
|
||||
if (csdev->refcnt == 0) {
|
||||
tmc_etf_disable_hw(drvdata);
|
||||
drvdata->mode = CS_MODE_DISABLED;
|
||||
coresight_set_mode(csdev, CS_MODE_DISABLED);
|
||||
last_disable = true;
|
||||
}
|
||||
spin_unlock_irqrestore(&drvdata->spinlock, flags);
|
||||
@ -483,13 +485,13 @@ static unsigned long tmc_update_etf_buffer(struct coresight_device *csdev,
|
||||
return 0;
|
||||
|
||||
/* This shouldn't happen */
|
||||
if (WARN_ON_ONCE(drvdata->mode != CS_MODE_PERF))
|
||||
if (WARN_ON_ONCE(coresight_get_mode(csdev) != CS_MODE_PERF))
|
||||
return 0;
|
||||
|
||||
spin_lock_irqsave(&drvdata->spinlock, flags);
|
||||
|
||||
/* Don't do anything if another tracer is using this sink */
|
||||
if (atomic_read(&csdev->refcnt) != 1)
|
||||
if (csdev->refcnt != 1)
|
||||
goto out;
|
||||
|
||||
CS_UNLOCK(drvdata->base);
|
||||
@ -629,7 +631,7 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
|
||||
}
|
||||
|
||||
/* Don't interfere if operated from Perf */
|
||||
if (drvdata->mode == CS_MODE_PERF) {
|
||||
if (coresight_get_mode(drvdata->csdev) == CS_MODE_PERF) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@ -641,7 +643,7 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
|
||||
}
|
||||
|
||||
/* Disable the TMC if need be */
|
||||
if (drvdata->mode == CS_MODE_SYSFS) {
|
||||
if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) {
|
||||
/* There is no point in reading a TMC in HW FIFO mode */
|
||||
mode = readl_relaxed(drvdata->base + TMC_MODE);
|
||||
if (mode != TMC_MODE_CIRCULAR_BUFFER) {
|
||||
@ -673,7 +675,7 @@ int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata)
|
||||
spin_lock_irqsave(&drvdata->spinlock, flags);
|
||||
|
||||
/* Re-enable the TMC if need be */
|
||||
if (drvdata->mode == CS_MODE_SYSFS) {
|
||||
if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) {
|
||||
/* There is no point in reading a TMC in HW FIFO mode */
|
||||
mode = readl_relaxed(drvdata->base + TMC_MODE);
|
||||
if (mode != TMC_MODE_CIRCULAR_BUFFER) {
|
||||
|
@ -1143,7 +1143,7 @@ static void __tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
|
||||
* When operating in sysFS mode the content of the buffer needs to be
|
||||
* read before the TMC is disabled.
|
||||
*/
|
||||
if (drvdata->mode == CS_MODE_SYSFS)
|
||||
if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS)
|
||||
tmc_etr_sync_sysfs_buf(drvdata);
|
||||
|
||||
tmc_disable_hw(drvdata);
|
||||
@ -1189,7 +1189,7 @@ static struct etr_buf *tmc_etr_get_sysfs_buffer(struct coresight_device *csdev)
|
||||
spin_lock_irqsave(&drvdata->spinlock, flags);
|
||||
}
|
||||
|
||||
if (drvdata->reading || drvdata->mode == CS_MODE_PERF) {
|
||||
if (drvdata->reading || coresight_get_mode(csdev) == CS_MODE_PERF) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
@ -1230,15 +1230,15 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
|
||||
* sink is already enabled no memory is needed and the HW need not be
|
||||
* touched, even if the buffer size has changed.
|
||||
*/
|
||||
if (drvdata->mode == CS_MODE_SYSFS) {
|
||||
atomic_inc(&csdev->refcnt);
|
||||
if (coresight_get_mode(csdev) == CS_MODE_SYSFS) {
|
||||
csdev->refcnt++;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = tmc_etr_enable_hw(drvdata, sysfs_buf);
|
||||
if (!ret) {
|
||||
drvdata->mode = CS_MODE_SYSFS;
|
||||
atomic_inc(&csdev->refcnt);
|
||||
coresight_set_mode(csdev, CS_MODE_SYSFS);
|
||||
csdev->refcnt++;
|
||||
}
|
||||
|
||||
out:
|
||||
@ -1564,7 +1564,7 @@ tmc_update_etr_buffer(struct coresight_device *csdev,
|
||||
spin_lock_irqsave(&drvdata->spinlock, flags);
|
||||
|
||||
/* Don't do anything if another tracer is using this sink */
|
||||
if (atomic_read(&csdev->refcnt) != 1) {
|
||||
if (csdev->refcnt != 1) {
|
||||
spin_unlock_irqrestore(&drvdata->spinlock, flags);
|
||||
goto out;
|
||||
}
|
||||
@ -1652,7 +1652,7 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data)
|
||||
|
||||
spin_lock_irqsave(&drvdata->spinlock, flags);
|
||||
/* Don't use this sink if it is already claimed by sysFS */
|
||||
if (drvdata->mode == CS_MODE_SYSFS) {
|
||||
if (coresight_get_mode(csdev) == CS_MODE_SYSFS) {
|
||||
rc = -EBUSY;
|
||||
goto unlock_out;
|
||||
}
|
||||
@ -1676,7 +1676,7 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data)
|
||||
* use for this session.
|
||||
*/
|
||||
if (drvdata->pid == pid) {
|
||||
atomic_inc(&csdev->refcnt);
|
||||
csdev->refcnt++;
|
||||
goto unlock_out;
|
||||
}
|
||||
|
||||
@ -1684,9 +1684,9 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data)
|
||||
if (!rc) {
|
||||
/* Associate with monitored process. */
|
||||
drvdata->pid = pid;
|
||||
drvdata->mode = CS_MODE_PERF;
|
||||
coresight_set_mode(csdev, CS_MODE_PERF);
|
||||
drvdata->perf_buf = etr_perf->etr_buf;
|
||||
atomic_inc(&csdev->refcnt);
|
||||
csdev->refcnt++;
|
||||
}
|
||||
|
||||
unlock_out:
|
||||
@ -1719,17 +1719,18 @@ static int tmc_disable_etr_sink(struct coresight_device *csdev)
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (atomic_dec_return(&csdev->refcnt)) {
|
||||
csdev->refcnt--;
|
||||
if (csdev->refcnt) {
|
||||
spin_unlock_irqrestore(&drvdata->spinlock, flags);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* Complain if we (somehow) got out of sync */
|
||||
WARN_ON_ONCE(drvdata->mode == CS_MODE_DISABLED);
|
||||
WARN_ON_ONCE(coresight_get_mode(csdev) == CS_MODE_DISABLED);
|
||||
tmc_etr_disable_hw(drvdata);
|
||||
/* Dissociate from monitored process. */
|
||||
drvdata->pid = -1;
|
||||
drvdata->mode = CS_MODE_DISABLED;
|
||||
coresight_set_mode(csdev, CS_MODE_DISABLED);
|
||||
/* Reset perf specific data */
|
||||
drvdata->perf_buf = NULL;
|
||||
|
||||
@ -1777,7 +1778,7 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
|
||||
}
|
||||
|
||||
/* Disable the TMC if we are trying to read from a running session. */
|
||||
if (drvdata->mode == CS_MODE_SYSFS)
|
||||
if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS)
|
||||
__tmc_etr_disable_hw(drvdata);
|
||||
|
||||
drvdata->reading = true;
|
||||
@ -1799,7 +1800,7 @@ int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
|
||||
spin_lock_irqsave(&drvdata->spinlock, flags);
|
||||
|
||||
/* RE-enable the TMC if need be */
|
||||
if (drvdata->mode == CS_MODE_SYSFS) {
|
||||
if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) {
|
||||
/*
|
||||
* The trace run will continue with the same allocated trace
|
||||
* buffer. Since the tracer is still enabled drvdata::buf can't
|
||||
|
@ -178,7 +178,6 @@ struct etr_buf {
|
||||
* @size: trace buffer size for this TMC (common for all modes).
|
||||
* @max_burst_size: The maximum burst size that can be initiated by
|
||||
* TMC-ETR on AXI bus.
|
||||
* @mode: how this TMC is being used.
|
||||
* @config_type: TMC variant, must be of type @tmc_config_type.
|
||||
* @memwidth: width of the memory interface databus, in bytes.
|
||||
* @trigger_cntr: amount of words to store after a trigger.
|
||||
@ -203,7 +202,6 @@ struct tmc_drvdata {
|
||||
u32 len;
|
||||
u32 size;
|
||||
u32 max_burst_size;
|
||||
u32 mode;
|
||||
enum tmc_config_type config_type;
|
||||
enum tmc_mem_intf_width memwidth;
|
||||
u32 trigger_cntr;
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "coresight-priv.h"
|
||||
#include "coresight-tpda.h"
|
||||
#include "coresight-trace-id.h"
|
||||
#include "coresight-tpdm.h"
|
||||
|
||||
DEFINE_CORESIGHT_DEVLIST(tpda_devs, "tpda");
|
||||
|
||||
@ -28,24 +29,59 @@ static bool coresight_device_is_tpdm(struct coresight_device *csdev)
|
||||
CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the DSB element size from the TPDM device
|
||||
* Returns
|
||||
* The dsb element size read from the devicetree if available.
|
||||
* 0 - Otherwise, with a warning once.
|
||||
*/
|
||||
static int tpdm_read_dsb_element_size(struct coresight_device *csdev)
|
||||
static void tpda_clear_element_size(struct coresight_device *csdev)
|
||||
{
|
||||
int rc = 0;
|
||||
u8 size = 0;
|
||||
struct tpda_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
|
||||
|
||||
drvdata->dsb_esize = 0;
|
||||
drvdata->cmb_esize = 0;
|
||||
}
|
||||
|
||||
static void tpda_set_element_size(struct tpda_drvdata *drvdata, u32 *val)
|
||||
{
|
||||
/* Clear all relevant fields */
|
||||
*val &= ~(TPDA_Pn_CR_DSBSIZE | TPDA_Pn_CR_CMBSIZE);
|
||||
|
||||
if (drvdata->dsb_esize == 64)
|
||||
*val |= TPDA_Pn_CR_DSBSIZE;
|
||||
else if (drvdata->dsb_esize == 32)
|
||||
*val &= ~TPDA_Pn_CR_DSBSIZE;
|
||||
|
||||
if (drvdata->cmb_esize == 64)
|
||||
*val |= FIELD_PREP(TPDA_Pn_CR_CMBSIZE, 0x2);
|
||||
else if (drvdata->cmb_esize == 32)
|
||||
*val |= FIELD_PREP(TPDA_Pn_CR_CMBSIZE, 0x1);
|
||||
else if (drvdata->cmb_esize == 8)
|
||||
*val &= ~TPDA_Pn_CR_CMBSIZE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the element size from the TPDM device. One TPDM must have at least one of the
|
||||
* element size property.
|
||||
* Returns
|
||||
* 0 - The element size property is read
|
||||
* Others - Cannot read the property of the element size
|
||||
*/
|
||||
static int tpdm_read_element_size(struct tpda_drvdata *drvdata,
|
||||
struct coresight_device *csdev)
|
||||
{
|
||||
int rc = -EINVAL;
|
||||
struct tpdm_drvdata *tpdm_data = dev_get_drvdata(csdev->dev.parent);
|
||||
|
||||
if (tpdm_has_dsb_dataset(tpdm_data)) {
|
||||
rc = fwnode_property_read_u32(dev_fwnode(csdev->dev.parent),
|
||||
"qcom,dsb-element-bits", &drvdata->dsb_esize);
|
||||
}
|
||||
if (tpdm_has_cmb_dataset(tpdm_data)) {
|
||||
rc = fwnode_property_read_u32(dev_fwnode(csdev->dev.parent),
|
||||
"qcom,cmb-element-bits", &drvdata->cmb_esize);
|
||||
}
|
||||
|
||||
rc = fwnode_property_read_u8(dev_fwnode(csdev->dev.parent),
|
||||
"qcom,dsb-element-size", &size);
|
||||
if (rc)
|
||||
dev_warn_once(&csdev->dev,
|
||||
"Failed to read TPDM DSB Element size: %d\n", rc);
|
||||
"Failed to read TPDM Element size: %d\n", rc);
|
||||
|
||||
return size;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -56,11 +92,12 @@ static int tpdm_read_dsb_element_size(struct coresight_device *csdev)
|
||||
* Parameter "inport" is used to pass in the input port number
|
||||
* of TPDA, and it is set to -1 in the recursize call.
|
||||
*/
|
||||
static int tpda_get_element_size(struct coresight_device *csdev,
|
||||
static int tpda_get_element_size(struct tpda_drvdata *drvdata,
|
||||
struct coresight_device *csdev,
|
||||
int inport)
|
||||
{
|
||||
int dsb_size = -ENOENT;
|
||||
int i, size;
|
||||
int rc = 0;
|
||||
int i;
|
||||
struct coresight_device *in;
|
||||
|
||||
for (i = 0; i < csdev->pdata->nr_inconns; i++) {
|
||||
@ -69,30 +106,26 @@ static int tpda_get_element_size(struct coresight_device *csdev,
|
||||
continue;
|
||||
|
||||
/* Ignore the paths that do not match port */
|
||||
if (inport > 0 &&
|
||||
if (inport >= 0 &&
|
||||
csdev->pdata->in_conns[i]->dest_port != inport)
|
||||
continue;
|
||||
|
||||
if (coresight_device_is_tpdm(in)) {
|
||||
size = tpdm_read_dsb_element_size(in);
|
||||
if (drvdata->dsb_esize || drvdata->cmb_esize)
|
||||
return -EEXIST;
|
||||
rc = tpdm_read_element_size(drvdata, in);
|
||||
if (rc)
|
||||
return rc;
|
||||
} else {
|
||||
/* Recurse down the path */
|
||||
size = tpda_get_element_size(in, -1);
|
||||
}
|
||||
|
||||
if (size < 0)
|
||||
return size;
|
||||
|
||||
if (dsb_size < 0) {
|
||||
/* Found a size, save it. */
|
||||
dsb_size = size;
|
||||
} else {
|
||||
/* Found duplicate TPDMs */
|
||||
return -EEXIST;
|
||||
rc = tpda_get_element_size(drvdata, in, -1);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return dsb_size;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Settings pre enabling port control register */
|
||||
@ -109,37 +142,24 @@ static void tpda_enable_pre_port(struct tpda_drvdata *drvdata)
|
||||
static int tpda_enable_port(struct tpda_drvdata *drvdata, int port)
|
||||
{
|
||||
u32 val;
|
||||
int size;
|
||||
int rc;
|
||||
|
||||
val = readl_relaxed(drvdata->base + TPDA_Pn_CR(port));
|
||||
/*
|
||||
* Configure aggregator port n DSB data set element size
|
||||
* Set the bit to 0 if the size is 32
|
||||
* Set the bit to 1 if the size is 64
|
||||
*/
|
||||
size = tpda_get_element_size(drvdata->csdev, port);
|
||||
switch (size) {
|
||||
case 32:
|
||||
val &= ~TPDA_Pn_CR_DSBSIZE;
|
||||
break;
|
||||
case 64:
|
||||
val |= TPDA_Pn_CR_DSBSIZE;
|
||||
break;
|
||||
case 0:
|
||||
return -EEXIST;
|
||||
case -EEXIST:
|
||||
tpda_clear_element_size(drvdata->csdev);
|
||||
rc = tpda_get_element_size(drvdata, drvdata->csdev, port);
|
||||
if (!rc && (drvdata->dsb_esize || drvdata->cmb_esize)) {
|
||||
tpda_set_element_size(drvdata, &val);
|
||||
/* Enable the port */
|
||||
val |= TPDA_Pn_CR_ENA;
|
||||
writel_relaxed(val, drvdata->base + TPDA_Pn_CR(port));
|
||||
} else if (rc == -EEXIST)
|
||||
dev_warn_once(&drvdata->csdev->dev,
|
||||
"Detected multiple TPDMs on port %d", -EEXIST);
|
||||
return -EEXIST;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
"Detected multiple TPDMs on port %d", port);
|
||||
else
|
||||
dev_warn_once(&drvdata->csdev->dev,
|
||||
"Didn't find TPDM element size");
|
||||
|
||||
/* Enable the port */
|
||||
val |= TPDA_Pn_CR_ENA;
|
||||
writel_relaxed(val, drvdata->base + TPDA_Pn_CR(port));
|
||||
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __tpda_enable(struct tpda_drvdata *drvdata, int port)
|
||||
@ -148,7 +168,12 @@ static int __tpda_enable(struct tpda_drvdata *drvdata, int port)
|
||||
|
||||
CS_UNLOCK(drvdata->base);
|
||||
|
||||
if (!drvdata->csdev->enable)
|
||||
/*
|
||||
* Only do pre-port enable for first port that calls enable when the
|
||||
* device's main refcount is still 0
|
||||
*/
|
||||
lockdep_assert_held(&drvdata->spinlock);
|
||||
if (!drvdata->csdev->refcnt)
|
||||
tpda_enable_pre_port(drvdata);
|
||||
|
||||
ret = tpda_enable_port(drvdata, port);
|
||||
@ -169,6 +194,7 @@ static int tpda_enable(struct coresight_device *csdev,
|
||||
ret = __tpda_enable(drvdata, in->dest_port);
|
||||
if (!ret) {
|
||||
atomic_inc(&in->dest_refcnt);
|
||||
csdev->refcnt++;
|
||||
dev_dbg(drvdata->dev, "TPDA inport %d enabled.\n", in->dest_port);
|
||||
}
|
||||
}
|
||||
@ -197,9 +223,10 @@ static void tpda_disable(struct coresight_device *csdev,
|
||||
struct tpda_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
|
||||
|
||||
spin_lock(&drvdata->spinlock);
|
||||
if (atomic_dec_return(&in->dest_refcnt) == 0)
|
||||
if (atomic_dec_return(&in->dest_refcnt) == 0) {
|
||||
__tpda_disable(drvdata, in->dest_port);
|
||||
|
||||
csdev->refcnt--;
|
||||
}
|
||||
spin_unlock(&drvdata->spinlock);
|
||||
|
||||
dev_dbg(drvdata->dev, "TPDA inport %d disabled\n", in->dest_port);
|
||||
@ -300,7 +327,7 @@ static struct amba_id tpda_ids[] = {
|
||||
.id = 0x000f0f00,
|
||||
.mask = 0x000fff00,
|
||||
},
|
||||
{ 0, 0},
|
||||
{ 0, 0, NULL },
|
||||
};
|
||||
|
||||
static struct amba_driver tpda_driver = {
|
||||
|
@ -10,6 +10,8 @@
|
||||
#define TPDA_Pn_CR(n) (0x004 + (n * 4))
|
||||
/* Aggregator port enable bit */
|
||||
#define TPDA_Pn_CR_ENA BIT(0)
|
||||
/* Aggregator port CMB data set element size bit */
|
||||
#define TPDA_Pn_CR_CMBSIZE GENMASK(7, 6)
|
||||
/* Aggregator port DSB data set element size bit */
|
||||
#define TPDA_Pn_CR_DSBSIZE BIT(8)
|
||||
|
||||
@ -25,6 +27,8 @@
|
||||
* @csdev: component vitals needed by the framework.
|
||||
* @spinlock: lock for the drvdata value.
|
||||
* @enable: enable status of the component.
|
||||
* @dsb_esize Record the DSB element size.
|
||||
* @cmb_esize Record the CMB element size.
|
||||
*/
|
||||
struct tpda_drvdata {
|
||||
void __iomem *base;
|
||||
@ -32,6 +36,8 @@ struct tpda_drvdata {
|
||||
struct coresight_device *csdev;
|
||||
spinlock_t spinlock;
|
||||
u8 atid;
|
||||
u32 dsb_esize;
|
||||
u32 cmb_esize;
|
||||
};
|
||||
|
||||
#endif /* _CORESIGHT_CORESIGHT_TPDA_H */
|
||||
|
@ -66,6 +66,31 @@ static ssize_t tpdm_simple_dataset_show(struct device *dev,
|
||||
return -EINVAL;
|
||||
return sysfs_emit(buf, "0x%x\n",
|
||||
drvdata->dsb->msr[tpdm_attr->idx]);
|
||||
case CMB_TRIG_PATT:
|
||||
if (tpdm_attr->idx >= TPDM_CMB_MAX_PATT)
|
||||
return -EINVAL;
|
||||
return sysfs_emit(buf, "0x%x\n",
|
||||
drvdata->cmb->trig_patt[tpdm_attr->idx]);
|
||||
case CMB_TRIG_PATT_MASK:
|
||||
if (tpdm_attr->idx >= TPDM_CMB_MAX_PATT)
|
||||
return -EINVAL;
|
||||
return sysfs_emit(buf, "0x%x\n",
|
||||
drvdata->cmb->trig_patt_mask[tpdm_attr->idx]);
|
||||
case CMB_PATT:
|
||||
if (tpdm_attr->idx >= TPDM_CMB_MAX_PATT)
|
||||
return -EINVAL;
|
||||
return sysfs_emit(buf, "0x%x\n",
|
||||
drvdata->cmb->patt_val[tpdm_attr->idx]);
|
||||
case CMB_PATT_MASK:
|
||||
if (tpdm_attr->idx >= TPDM_CMB_MAX_PATT)
|
||||
return -EINVAL;
|
||||
return sysfs_emit(buf, "0x%x\n",
|
||||
drvdata->cmb->patt_mask[tpdm_attr->idx]);
|
||||
case CMB_MSR:
|
||||
if (tpdm_attr->idx >= drvdata->cmb_msr_num)
|
||||
return -EINVAL;
|
||||
return sysfs_emit(buf, "0x%x\n",
|
||||
drvdata->cmb->msr[tpdm_attr->idx]);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -77,60 +102,84 @@ static ssize_t tpdm_simple_dataset_store(struct device *dev,
|
||||
size_t size)
|
||||
{
|
||||
unsigned long val;
|
||||
ssize_t ret = size;
|
||||
ssize_t ret = -EINVAL;
|
||||
|
||||
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
struct tpdm_dataset_attribute *tpdm_attr =
|
||||
container_of(attr, struct tpdm_dataset_attribute, attr);
|
||||
|
||||
if (kstrtoul(buf, 0, &val))
|
||||
return -EINVAL;
|
||||
return ret;
|
||||
|
||||
spin_lock(&drvdata->spinlock);
|
||||
guard(spinlock)(&drvdata->spinlock);
|
||||
switch (tpdm_attr->mem) {
|
||||
case DSB_TRIG_PATT:
|
||||
if (tpdm_attr->idx < TPDM_DSB_MAX_PATT)
|
||||
if (tpdm_attr->idx < TPDM_DSB_MAX_PATT) {
|
||||
drvdata->dsb->trig_patt[tpdm_attr->idx] = val;
|
||||
else
|
||||
ret = -EINVAL;
|
||||
ret = size;
|
||||
}
|
||||
break;
|
||||
case DSB_TRIG_PATT_MASK:
|
||||
if (tpdm_attr->idx < TPDM_DSB_MAX_PATT)
|
||||
if (tpdm_attr->idx < TPDM_DSB_MAX_PATT) {
|
||||
drvdata->dsb->trig_patt_mask[tpdm_attr->idx] = val;
|
||||
else
|
||||
ret = -EINVAL;
|
||||
ret = size;
|
||||
}
|
||||
break;
|
||||
case DSB_PATT:
|
||||
if (tpdm_attr->idx < TPDM_DSB_MAX_PATT)
|
||||
if (tpdm_attr->idx < TPDM_DSB_MAX_PATT) {
|
||||
drvdata->dsb->patt_val[tpdm_attr->idx] = val;
|
||||
else
|
||||
ret = -EINVAL;
|
||||
ret = size;
|
||||
}
|
||||
break;
|
||||
case DSB_PATT_MASK:
|
||||
if (tpdm_attr->idx < TPDM_DSB_MAX_PATT)
|
||||
if (tpdm_attr->idx < TPDM_DSB_MAX_PATT) {
|
||||
drvdata->dsb->patt_mask[tpdm_attr->idx] = val;
|
||||
else
|
||||
ret = -EINVAL;
|
||||
ret = size;
|
||||
}
|
||||
break;
|
||||
case DSB_MSR:
|
||||
if (tpdm_attr->idx < drvdata->dsb_msr_num)
|
||||
if (tpdm_attr->idx < drvdata->dsb_msr_num) {
|
||||
drvdata->dsb->msr[tpdm_attr->idx] = val;
|
||||
else
|
||||
ret = -EINVAL;
|
||||
ret = size;
|
||||
}
|
||||
break;
|
||||
case CMB_TRIG_PATT:
|
||||
if (tpdm_attr->idx < TPDM_CMB_MAX_PATT) {
|
||||
drvdata->cmb->trig_patt[tpdm_attr->idx] = val;
|
||||
ret = size;
|
||||
}
|
||||
break;
|
||||
case CMB_TRIG_PATT_MASK:
|
||||
if (tpdm_attr->idx < TPDM_CMB_MAX_PATT) {
|
||||
drvdata->cmb->trig_patt_mask[tpdm_attr->idx] = val;
|
||||
ret = size;
|
||||
}
|
||||
break;
|
||||
case CMB_PATT:
|
||||
if (tpdm_attr->idx < TPDM_CMB_MAX_PATT) {
|
||||
drvdata->cmb->patt_val[tpdm_attr->idx] = val;
|
||||
ret = size;
|
||||
}
|
||||
break;
|
||||
case CMB_PATT_MASK:
|
||||
if (tpdm_attr->idx < TPDM_CMB_MAX_PATT) {
|
||||
drvdata->cmb->patt_mask[tpdm_attr->idx] = val;
|
||||
ret = size;
|
||||
}
|
||||
break;
|
||||
case CMB_MSR:
|
||||
if (tpdm_attr->idx < drvdata->cmb_msr_num) {
|
||||
drvdata->cmb->msr[tpdm_attr->idx] = val;
|
||||
ret = size;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
spin_unlock(&drvdata->spinlock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool tpdm_has_dsb_dataset(struct tpdm_drvdata *drvdata)
|
||||
{
|
||||
return (drvdata->datasets & TPDM_PIDR0_DS_DSB);
|
||||
}
|
||||
|
||||
static umode_t tpdm_dsb_is_visible(struct kobject *kobj,
|
||||
struct attribute *attr, int n)
|
||||
{
|
||||
@ -143,6 +192,18 @@ static umode_t tpdm_dsb_is_visible(struct kobject *kobj,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static umode_t tpdm_cmb_is_visible(struct kobject *kobj,
|
||||
struct attribute *attr, int n)
|
||||
{
|
||||
struct device *dev = kobj_to_dev(kobj);
|
||||
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
|
||||
if (drvdata && tpdm_has_cmb_dataset(drvdata))
|
||||
return attr->mode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static umode_t tpdm_dsb_msr_is_visible(struct kobject *kobj,
|
||||
struct attribute *attr, int n)
|
||||
{
|
||||
@ -159,6 +220,23 @@ static umode_t tpdm_dsb_msr_is_visible(struct kobject *kobj,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static umode_t tpdm_cmb_msr_is_visible(struct kobject *kobj,
|
||||
struct attribute *attr, int n)
|
||||
{
|
||||
struct device *dev = kobj_to_dev(kobj);
|
||||
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
|
||||
struct device_attribute *dev_attr =
|
||||
container_of(attr, struct device_attribute, attr);
|
||||
struct tpdm_dataset_attribute *tpdm_attr =
|
||||
container_of(dev_attr, struct tpdm_dataset_attribute, attr);
|
||||
|
||||
if (tpdm_attr->idx < drvdata->cmb_msr_num)
|
||||
return attr->mode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tpdm_reset_datasets(struct tpdm_drvdata *drvdata)
|
||||
{
|
||||
if (tpdm_has_dsb_dataset(drvdata)) {
|
||||
@ -167,6 +245,9 @@ static void tpdm_reset_datasets(struct tpdm_drvdata *drvdata)
|
||||
drvdata->dsb->trig_ts = true;
|
||||
drvdata->dsb->trig_type = false;
|
||||
}
|
||||
|
||||
if (drvdata->cmb)
|
||||
memset(drvdata->cmb, 0, sizeof(struct cmb_dataset));
|
||||
}
|
||||
|
||||
static void set_dsb_mode(struct tpdm_drvdata *drvdata, u32 *val)
|
||||
@ -233,25 +314,27 @@ static void tpdm_enable_dsb(struct tpdm_drvdata *drvdata)
|
||||
{
|
||||
u32 val, i;
|
||||
|
||||
if (!tpdm_has_dsb_dataset(drvdata))
|
||||
return;
|
||||
|
||||
for (i = 0; i < TPDM_DSB_MAX_EDCR; i++)
|
||||
writel_relaxed(drvdata->dsb->edge_ctrl[i],
|
||||
drvdata->base + TPDM_DSB_EDCR(i));
|
||||
drvdata->base + TPDM_DSB_EDCR(i));
|
||||
for (i = 0; i < TPDM_DSB_MAX_EDCMR; i++)
|
||||
writel_relaxed(drvdata->dsb->edge_ctrl_mask[i],
|
||||
drvdata->base + TPDM_DSB_EDCMR(i));
|
||||
drvdata->base + TPDM_DSB_EDCMR(i));
|
||||
for (i = 0; i < TPDM_DSB_MAX_PATT; i++) {
|
||||
writel_relaxed(drvdata->dsb->patt_val[i],
|
||||
drvdata->base + TPDM_DSB_TPR(i));
|
||||
drvdata->base + TPDM_DSB_TPR(i));
|
||||
writel_relaxed(drvdata->dsb->patt_mask[i],
|
||||
drvdata->base + TPDM_DSB_TPMR(i));
|
||||
drvdata->base + TPDM_DSB_TPMR(i));
|
||||
writel_relaxed(drvdata->dsb->trig_patt[i],
|
||||
drvdata->base + TPDM_DSB_XPR(i));
|
||||
drvdata->base + TPDM_DSB_XPR(i));
|
||||
writel_relaxed(drvdata->dsb->trig_patt_mask[i],
|
||||
drvdata->base + TPDM_DSB_XPMR(i));
|
||||
drvdata->base + TPDM_DSB_XPMR(i));
|
||||
}
|
||||
|
||||
set_dsb_tier(drvdata);
|
||||
|
||||
set_dsb_msr(drvdata);
|
||||
|
||||
val = readl_relaxed(drvdata->base + TPDM_DSB_CR);
|
||||
@ -267,6 +350,76 @@ static void tpdm_enable_dsb(struct tpdm_drvdata *drvdata)
|
||||
writel_relaxed(val, drvdata->base + TPDM_DSB_CR);
|
||||
}
|
||||
|
||||
static void set_cmb_tier(struct tpdm_drvdata *drvdata)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = readl_relaxed(drvdata->base + TPDM_CMB_TIER);
|
||||
|
||||
/* Clear all relevant fields */
|
||||
val &= ~(TPDM_CMB_TIER_PATT_TSENAB | TPDM_CMB_TIER_TS_ALL |
|
||||
TPDM_CMB_TIER_XTRIG_TSENAB);
|
||||
|
||||
/* Set pattern timestamp type and enablement */
|
||||
if (drvdata->cmb->patt_ts)
|
||||
val |= TPDM_CMB_TIER_PATT_TSENAB;
|
||||
|
||||
/* Set trigger timestamp */
|
||||
if (drvdata->cmb->trig_ts)
|
||||
val |= TPDM_CMB_TIER_XTRIG_TSENAB;
|
||||
|
||||
/* Set all timestamp enablement*/
|
||||
if (drvdata->cmb->ts_all)
|
||||
val |= TPDM_CMB_TIER_TS_ALL;
|
||||
|
||||
writel_relaxed(val, drvdata->base + TPDM_CMB_TIER);
|
||||
}
|
||||
|
||||
static void set_cmb_msr(struct tpdm_drvdata *drvdata)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < drvdata->cmb_msr_num; i++)
|
||||
writel_relaxed(drvdata->cmb->msr[i],
|
||||
drvdata->base + TPDM_CMB_MSR(i));
|
||||
}
|
||||
|
||||
static void tpdm_enable_cmb(struct tpdm_drvdata *drvdata)
|
||||
{
|
||||
u32 val, i;
|
||||
|
||||
if (!tpdm_has_cmb_dataset(drvdata))
|
||||
return;
|
||||
|
||||
/* Configure pattern registers */
|
||||
for (i = 0; i < TPDM_CMB_MAX_PATT; i++) {
|
||||
writel_relaxed(drvdata->cmb->patt_val[i],
|
||||
drvdata->base + TPDM_CMB_TPR(i));
|
||||
writel_relaxed(drvdata->cmb->patt_mask[i],
|
||||
drvdata->base + TPDM_CMB_TPMR(i));
|
||||
writel_relaxed(drvdata->cmb->trig_patt[i],
|
||||
drvdata->base + TPDM_CMB_XPR(i));
|
||||
writel_relaxed(drvdata->cmb->trig_patt_mask[i],
|
||||
drvdata->base + TPDM_CMB_XPMR(i));
|
||||
}
|
||||
|
||||
set_cmb_tier(drvdata);
|
||||
set_cmb_msr(drvdata);
|
||||
|
||||
val = readl_relaxed(drvdata->base + TPDM_CMB_CR);
|
||||
/*
|
||||
* Set to 0 for continuous CMB collection mode,
|
||||
* 1 for trace-on-change CMB collection mode.
|
||||
*/
|
||||
if (drvdata->cmb->trace_mode)
|
||||
val |= TPDM_CMB_CR_MODE;
|
||||
else
|
||||
val &= ~TPDM_CMB_CR_MODE;
|
||||
/* Set the enable bit of CMB control register to 1 */
|
||||
val |= TPDM_CMB_CR_ENA;
|
||||
writel_relaxed(val, drvdata->base + TPDM_CMB_CR);
|
||||
}
|
||||
|
||||
/*
|
||||
* TPDM enable operations
|
||||
* The TPDM or Monitor serves as data collection component for various
|
||||
@ -279,8 +432,8 @@ static void __tpdm_enable(struct tpdm_drvdata *drvdata)
|
||||
{
|
||||
CS_UNLOCK(drvdata->base);
|
||||
|
||||
if (tpdm_has_dsb_dataset(drvdata))
|
||||
tpdm_enable_dsb(drvdata);
|
||||
tpdm_enable_dsb(drvdata);
|
||||
tpdm_enable_cmb(drvdata);
|
||||
|
||||
CS_LOCK(drvdata->base);
|
||||
}
|
||||
@ -308,19 +461,35 @@ static void tpdm_disable_dsb(struct tpdm_drvdata *drvdata)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
if (!tpdm_has_dsb_dataset(drvdata))
|
||||
return;
|
||||
|
||||
/* Set the enable bit of DSB control register to 0 */
|
||||
val = readl_relaxed(drvdata->base + TPDM_DSB_CR);
|
||||
val &= ~TPDM_DSB_CR_ENA;
|
||||
writel_relaxed(val, drvdata->base + TPDM_DSB_CR);
|
||||
}
|
||||
|
||||
static void tpdm_disable_cmb(struct tpdm_drvdata *drvdata)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
if (!tpdm_has_cmb_dataset(drvdata))
|
||||
return;
|
||||
|
||||
val = readl_relaxed(drvdata->base + TPDM_CMB_CR);
|
||||
/* Set the enable bit of CMB control register to 0 */
|
||||
val &= ~TPDM_CMB_CR_ENA;
|
||||
writel_relaxed(val, drvdata->base + TPDM_CMB_CR);
|
||||
}
|
||||
|
||||
/* TPDM disable operations */
|
||||
static void __tpdm_disable(struct tpdm_drvdata *drvdata)
|
||||
{
|
||||
CS_UNLOCK(drvdata->base);
|
||||
|
||||
if (tpdm_has_dsb_dataset(drvdata))
|
||||
tpdm_disable_dsb(drvdata);
|
||||
tpdm_disable_dsb(drvdata);
|
||||
tpdm_disable_cmb(drvdata);
|
||||
|
||||
CS_LOCK(drvdata->base);
|
||||
}
|
||||
@ -366,6 +535,12 @@ static int tpdm_datasets_setup(struct tpdm_drvdata *drvdata)
|
||||
if (!drvdata->dsb)
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (tpdm_has_cmb_dataset(drvdata) && (!drvdata->cmb)) {
|
||||
drvdata->cmb = devm_kzalloc(drvdata->dev,
|
||||
sizeof(*drvdata->cmb), GFP_KERNEL);
|
||||
if (!drvdata->cmb)
|
||||
return -ENOMEM;
|
||||
}
|
||||
tpdm_reset_datasets(drvdata);
|
||||
|
||||
return 0;
|
||||
@ -577,9 +752,18 @@ static ssize_t enable_ts_show(struct device *dev,
|
||||
char *buf)
|
||||
{
|
||||
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
struct tpdm_dataset_attribute *tpdm_attr =
|
||||
container_of(attr, struct tpdm_dataset_attribute, attr);
|
||||
ssize_t size = -EINVAL;
|
||||
|
||||
return sysfs_emit(buf, "%u\n",
|
||||
(unsigned int)drvdata->dsb->patt_ts);
|
||||
if (tpdm_attr->mem == DSB_PATT)
|
||||
size = sysfs_emit(buf, "%u\n",
|
||||
(unsigned int)drvdata->dsb->patt_ts);
|
||||
else if (tpdm_attr->mem == CMB_PATT)
|
||||
size = sysfs_emit(buf, "%u\n",
|
||||
(unsigned int)drvdata->cmb->patt_ts);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -591,17 +775,23 @@ static ssize_t enable_ts_store(struct device *dev,
|
||||
size_t size)
|
||||
{
|
||||
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
struct tpdm_dataset_attribute *tpdm_attr =
|
||||
container_of(attr, struct tpdm_dataset_attribute, attr);
|
||||
unsigned long val;
|
||||
|
||||
if ((kstrtoul(buf, 0, &val)) || (val & ~1UL))
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock(&drvdata->spinlock);
|
||||
drvdata->dsb->patt_ts = !!val;
|
||||
spin_unlock(&drvdata->spinlock);
|
||||
guard(spinlock)(&drvdata->spinlock);
|
||||
if (tpdm_attr->mem == DSB_PATT)
|
||||
drvdata->dsb->patt_ts = !!val;
|
||||
else if (tpdm_attr->mem == CMB_PATT)
|
||||
drvdata->cmb->patt_ts = !!val;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
return size;
|
||||
}
|
||||
static DEVICE_ATTR_RW(enable_ts);
|
||||
|
||||
static ssize_t set_type_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
@ -704,6 +894,96 @@ static ssize_t dsb_trig_ts_store(struct device *dev,
|
||||
}
|
||||
static DEVICE_ATTR_RW(dsb_trig_ts);
|
||||
|
||||
static ssize_t cmb_mode_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
|
||||
return sysfs_emit(buf, "%x\n", drvdata->cmb->trace_mode);
|
||||
|
||||
}
|
||||
|
||||
static ssize_t cmb_mode_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t size)
|
||||
{
|
||||
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
unsigned long trace_mode;
|
||||
|
||||
if (kstrtoul(buf, 0, &trace_mode) || (trace_mode & ~1UL))
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock(&drvdata->spinlock);
|
||||
drvdata->cmb->trace_mode = trace_mode;
|
||||
spin_unlock(&drvdata->spinlock);
|
||||
return size;
|
||||
}
|
||||
static DEVICE_ATTR_RW(cmb_mode);
|
||||
|
||||
static ssize_t cmb_ts_all_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
|
||||
return sysfs_emit(buf, "%u\n",
|
||||
(unsigned int)drvdata->cmb->ts_all);
|
||||
}
|
||||
|
||||
static ssize_t cmb_ts_all_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t size)
|
||||
{
|
||||
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
unsigned long val;
|
||||
|
||||
if ((kstrtoul(buf, 0, &val)) || (val & ~1UL))
|
||||
return -EINVAL;
|
||||
|
||||
guard(spinlock)(&drvdata->spinlock);
|
||||
if (val)
|
||||
drvdata->cmb->ts_all = true;
|
||||
else
|
||||
drvdata->cmb->ts_all = false;
|
||||
|
||||
return size;
|
||||
}
|
||||
static DEVICE_ATTR_RW(cmb_ts_all);
|
||||
|
||||
static ssize_t cmb_trig_ts_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
|
||||
return sysfs_emit(buf, "%u\n",
|
||||
(unsigned int)drvdata->cmb->trig_ts);
|
||||
}
|
||||
|
||||
static ssize_t cmb_trig_ts_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t size)
|
||||
{
|
||||
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
unsigned long val;
|
||||
|
||||
if ((kstrtoul(buf, 0, &val)) || (val & ~1UL))
|
||||
return -EINVAL;
|
||||
|
||||
guard(spinlock)(&drvdata->spinlock);
|
||||
if (val)
|
||||
drvdata->cmb->trig_ts = true;
|
||||
else
|
||||
drvdata->cmb->trig_ts = false;
|
||||
|
||||
return size;
|
||||
}
|
||||
static DEVICE_ATTR_RW(cmb_trig_ts);
|
||||
|
||||
static struct attribute *tpdm_dsb_edge_attrs[] = {
|
||||
&dev_attr_ctrl_idx.attr,
|
||||
&dev_attr_ctrl_val.attr,
|
||||
@ -772,7 +1052,7 @@ static struct attribute *tpdm_dsb_patt_attrs[] = {
|
||||
DSB_PATT_MASK_ATTR(5),
|
||||
DSB_PATT_MASK_ATTR(6),
|
||||
DSB_PATT_MASK_ATTR(7),
|
||||
&dev_attr_enable_ts.attr,
|
||||
DSB_PATT_ENABLE_TS,
|
||||
&dev_attr_set_type.attr,
|
||||
NULL,
|
||||
};
|
||||
@ -813,6 +1093,59 @@ static struct attribute *tpdm_dsb_msr_attrs[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute *tpdm_cmb_trig_patt_attrs[] = {
|
||||
CMB_TRIG_PATT_ATTR(0),
|
||||
CMB_TRIG_PATT_ATTR(1),
|
||||
CMB_TRIG_PATT_MASK_ATTR(0),
|
||||
CMB_TRIG_PATT_MASK_ATTR(1),
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute *tpdm_cmb_patt_attrs[] = {
|
||||
CMB_PATT_ATTR(0),
|
||||
CMB_PATT_ATTR(1),
|
||||
CMB_PATT_MASK_ATTR(0),
|
||||
CMB_PATT_MASK_ATTR(1),
|
||||
CMB_PATT_ENABLE_TS,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute *tpdm_cmb_msr_attrs[] = {
|
||||
CMB_MSR_ATTR(0),
|
||||
CMB_MSR_ATTR(1),
|
||||
CMB_MSR_ATTR(2),
|
||||
CMB_MSR_ATTR(3),
|
||||
CMB_MSR_ATTR(4),
|
||||
CMB_MSR_ATTR(5),
|
||||
CMB_MSR_ATTR(6),
|
||||
CMB_MSR_ATTR(7),
|
||||
CMB_MSR_ATTR(8),
|
||||
CMB_MSR_ATTR(9),
|
||||
CMB_MSR_ATTR(10),
|
||||
CMB_MSR_ATTR(11),
|
||||
CMB_MSR_ATTR(12),
|
||||
CMB_MSR_ATTR(13),
|
||||
CMB_MSR_ATTR(14),
|
||||
CMB_MSR_ATTR(15),
|
||||
CMB_MSR_ATTR(16),
|
||||
CMB_MSR_ATTR(17),
|
||||
CMB_MSR_ATTR(18),
|
||||
CMB_MSR_ATTR(19),
|
||||
CMB_MSR_ATTR(20),
|
||||
CMB_MSR_ATTR(21),
|
||||
CMB_MSR_ATTR(22),
|
||||
CMB_MSR_ATTR(23),
|
||||
CMB_MSR_ATTR(24),
|
||||
CMB_MSR_ATTR(25),
|
||||
CMB_MSR_ATTR(26),
|
||||
CMB_MSR_ATTR(27),
|
||||
CMB_MSR_ATTR(28),
|
||||
CMB_MSR_ATTR(29),
|
||||
CMB_MSR_ATTR(30),
|
||||
CMB_MSR_ATTR(31),
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute *tpdm_dsb_attrs[] = {
|
||||
&dev_attr_dsb_mode.attr,
|
||||
&dev_attr_dsb_trig_ts.attr,
|
||||
@ -820,6 +1153,13 @@ static struct attribute *tpdm_dsb_attrs[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute *tpdm_cmb_attrs[] = {
|
||||
&dev_attr_cmb_mode.attr,
|
||||
&dev_attr_cmb_ts_all.attr,
|
||||
&dev_attr_cmb_trig_ts.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group tpdm_dsb_attr_grp = {
|
||||
.attrs = tpdm_dsb_attrs,
|
||||
.is_visible = tpdm_dsb_is_visible,
|
||||
@ -849,6 +1189,29 @@ static struct attribute_group tpdm_dsb_msr_grp = {
|
||||
.name = "dsb_msr",
|
||||
};
|
||||
|
||||
static struct attribute_group tpdm_cmb_attr_grp = {
|
||||
.attrs = tpdm_cmb_attrs,
|
||||
.is_visible = tpdm_cmb_is_visible,
|
||||
};
|
||||
|
||||
static struct attribute_group tpdm_cmb_trig_patt_grp = {
|
||||
.attrs = tpdm_cmb_trig_patt_attrs,
|
||||
.is_visible = tpdm_cmb_is_visible,
|
||||
.name = "cmb_trig_patt",
|
||||
};
|
||||
|
||||
static struct attribute_group tpdm_cmb_patt_grp = {
|
||||
.attrs = tpdm_cmb_patt_attrs,
|
||||
.is_visible = tpdm_cmb_is_visible,
|
||||
.name = "cmb_patt",
|
||||
};
|
||||
|
||||
static struct attribute_group tpdm_cmb_msr_grp = {
|
||||
.attrs = tpdm_cmb_msr_attrs,
|
||||
.is_visible = tpdm_cmb_msr_is_visible,
|
||||
.name = "cmb_msr",
|
||||
};
|
||||
|
||||
static const struct attribute_group *tpdm_attr_grps[] = {
|
||||
&tpdm_attr_grp,
|
||||
&tpdm_dsb_attr_grp,
|
||||
@ -856,6 +1219,10 @@ static const struct attribute_group *tpdm_attr_grps[] = {
|
||||
&tpdm_dsb_trig_patt_grp,
|
||||
&tpdm_dsb_patt_grp,
|
||||
&tpdm_dsb_msr_grp,
|
||||
&tpdm_cmb_attr_grp,
|
||||
&tpdm_cmb_trig_patt_grp,
|
||||
&tpdm_cmb_patt_grp,
|
||||
&tpdm_cmb_msr_grp,
|
||||
NULL,
|
||||
};
|
||||
|
||||
@ -894,6 +1261,10 @@ static int tpdm_probe(struct amba_device *adev, const struct amba_id *id)
|
||||
of_property_read_u32(drvdata->dev->of_node,
|
||||
"qcom,dsb-msrs-num", &drvdata->dsb_msr_num);
|
||||
|
||||
if (drvdata && tpdm_has_cmb_dataset(drvdata))
|
||||
of_property_read_u32(drvdata->dev->of_node,
|
||||
"qcom,cmb-msrs-num", &drvdata->cmb_msr_num);
|
||||
|
||||
/* Set up coresight component description */
|
||||
desc.name = coresight_alloc_device_name(&tpdm_devs, dev);
|
||||
if (!desc.name)
|
||||
@ -933,7 +1304,7 @@ static struct amba_id tpdm_ids[] = {
|
||||
.id = 0x000f0e00,
|
||||
.mask = 0x000fff00,
|
||||
},
|
||||
{ 0, 0},
|
||||
{ 0, 0, NULL },
|
||||
};
|
||||
|
||||
static struct amba_driver tpdm_driver = {
|
||||
|
@ -9,6 +9,38 @@
|
||||
/* The max number of the datasets that TPDM supports */
|
||||
#define TPDM_DATASETS 7
|
||||
|
||||
/* CMB Subunit Registers */
|
||||
#define TPDM_CMB_CR (0xA00)
|
||||
/* CMB subunit timestamp insertion enable register */
|
||||
#define TPDM_CMB_TIER (0xA04)
|
||||
/* CMB subunit timestamp pattern registers */
|
||||
#define TPDM_CMB_TPR(n) (0xA08 + (n * 4))
|
||||
/* CMB subunit timestamp pattern mask registers */
|
||||
#define TPDM_CMB_TPMR(n) (0xA10 + (n * 4))
|
||||
/* CMB subunit trigger pattern registers */
|
||||
#define TPDM_CMB_XPR(n) (0xA18 + (n * 4))
|
||||
/* CMB subunit trigger pattern mask registers */
|
||||
#define TPDM_CMB_XPMR(n) (0xA20 + (n * 4))
|
||||
/* CMB MSR register */
|
||||
#define TPDM_CMB_MSR(n) (0xA80 + (n * 4))
|
||||
|
||||
/* Enable bit for CMB subunit */
|
||||
#define TPDM_CMB_CR_ENA BIT(0)
|
||||
/* Trace collection mode for CMB subunit */
|
||||
#define TPDM_CMB_CR_MODE BIT(1)
|
||||
/* Timestamp control for pattern match */
|
||||
#define TPDM_CMB_TIER_PATT_TSENAB BIT(0)
|
||||
/* CMB CTI timestamp request */
|
||||
#define TPDM_CMB_TIER_XTRIG_TSENAB BIT(1)
|
||||
/* For timestamp fo all trace */
|
||||
#define TPDM_CMB_TIER_TS_ALL BIT(2)
|
||||
|
||||
/* Patten register number */
|
||||
#define TPDM_CMB_MAX_PATT 2
|
||||
|
||||
/* MAX number of DSB MSR */
|
||||
#define TPDM_CMB_MAX_MSR 32
|
||||
|
||||
/* DSB Subunit Registers */
|
||||
#define TPDM_DSB_CR (0x780)
|
||||
#define TPDM_DSB_TIER (0x784)
|
||||
@ -79,10 +111,12 @@
|
||||
*
|
||||
* PERIPHIDR0[0] : Fix to 1 if ImplDef subunit present, else 0
|
||||
* PERIPHIDR0[1] : Fix to 1 if DSB subunit present, else 0
|
||||
* PERIPHIDR0[2] : Fix to 1 if CMB subunit present, else 0
|
||||
*/
|
||||
|
||||
#define TPDM_PIDR0_DS_IMPDEF BIT(0)
|
||||
#define TPDM_PIDR0_DS_DSB BIT(1)
|
||||
#define TPDM_PIDR0_DS_CMB BIT(2)
|
||||
|
||||
#define TPDM_DSB_MAX_LINES 256
|
||||
/* MAX number of EDCR registers */
|
||||
@ -113,6 +147,16 @@
|
||||
} \
|
||||
})[0].attr.attr)
|
||||
|
||||
#define tpdm_patt_enable_ts(name, mem) \
|
||||
(&((struct tpdm_dataset_attribute[]) { \
|
||||
{ \
|
||||
__ATTR(name, 0644, enable_ts_show, \
|
||||
enable_ts_store), \
|
||||
mem, \
|
||||
0, \
|
||||
} \
|
||||
})[0].attr.attr)
|
||||
|
||||
#define DSB_EDGE_CTRL_ATTR(nr) \
|
||||
tpdm_simple_dataset_ro(edcr##nr, \
|
||||
DSB_EDGE_CTRL, nr)
|
||||
@ -137,10 +181,38 @@
|
||||
tpdm_simple_dataset_rw(tpmr##nr, \
|
||||
DSB_PATT_MASK, nr)
|
||||
|
||||
#define DSB_PATT_ENABLE_TS \
|
||||
tpdm_patt_enable_ts(enable_ts, \
|
||||
DSB_PATT)
|
||||
|
||||
#define DSB_MSR_ATTR(nr) \
|
||||
tpdm_simple_dataset_rw(msr##nr, \
|
||||
DSB_MSR, nr)
|
||||
|
||||
#define CMB_TRIG_PATT_ATTR(nr) \
|
||||
tpdm_simple_dataset_rw(xpr##nr, \
|
||||
CMB_TRIG_PATT, nr)
|
||||
|
||||
#define CMB_TRIG_PATT_MASK_ATTR(nr) \
|
||||
tpdm_simple_dataset_rw(xpmr##nr, \
|
||||
CMB_TRIG_PATT_MASK, nr)
|
||||
|
||||
#define CMB_PATT_ATTR(nr) \
|
||||
tpdm_simple_dataset_rw(tpr##nr, \
|
||||
CMB_PATT, nr)
|
||||
|
||||
#define CMB_PATT_MASK_ATTR(nr) \
|
||||
tpdm_simple_dataset_rw(tpmr##nr, \
|
||||
CMB_PATT_MASK, nr)
|
||||
|
||||
#define CMB_PATT_ENABLE_TS \
|
||||
tpdm_patt_enable_ts(enable_ts, \
|
||||
CMB_PATT)
|
||||
|
||||
#define CMB_MSR_ATTR(nr) \
|
||||
tpdm_simple_dataset_rw(msr##nr, \
|
||||
CMB_MSR, nr)
|
||||
|
||||
/**
|
||||
* struct dsb_dataset - specifics associated to dsb dataset
|
||||
* @mode: DSB programming mode
|
||||
@ -173,6 +245,30 @@ struct dsb_dataset {
|
||||
bool trig_type;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cmb_dataset
|
||||
* @trace_mode: Dataset collection mode
|
||||
* @patt_val: Save value for pattern
|
||||
* @patt_mask: Save value for pattern mask
|
||||
* @trig_patt: Save value for trigger pattern
|
||||
* @trig_patt_mask: Save value for trigger pattern mask
|
||||
* @msr Save value for MSR
|
||||
* @patt_ts: Indicates if pattern match for timestamp is enabled.
|
||||
* @trig_ts: Indicates if CTI trigger for timestamp is enabled.
|
||||
* @ts_all: Indicates if timestamp is enabled for all packets.
|
||||
*/
|
||||
struct cmb_dataset {
|
||||
u32 trace_mode;
|
||||
u32 patt_val[TPDM_CMB_MAX_PATT];
|
||||
u32 patt_mask[TPDM_CMB_MAX_PATT];
|
||||
u32 trig_patt[TPDM_CMB_MAX_PATT];
|
||||
u32 trig_patt_mask[TPDM_CMB_MAX_PATT];
|
||||
u32 msr[TPDM_CMB_MAX_MSR];
|
||||
bool patt_ts;
|
||||
bool trig_ts;
|
||||
bool ts_all;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tpdm_drvdata - specifics associated to an TPDM component
|
||||
* @base: memory mapped base address for this component.
|
||||
@ -182,7 +278,9 @@ struct dsb_dataset {
|
||||
* @enable: enable status of the component.
|
||||
* @datasets: The datasets types present of the TPDM.
|
||||
* @dsb Specifics associated to TPDM DSB.
|
||||
* @cmb Specifics associated to TPDM CMB.
|
||||
* @dsb_msr_num Number of MSR supported by DSB TPDM
|
||||
* @cmb_msr_num Number of MSR supported by CMB TPDM
|
||||
*/
|
||||
|
||||
struct tpdm_drvdata {
|
||||
@ -193,7 +291,9 @@ struct tpdm_drvdata {
|
||||
bool enable;
|
||||
unsigned long datasets;
|
||||
struct dsb_dataset *dsb;
|
||||
struct cmb_dataset *cmb;
|
||||
u32 dsb_msr_num;
|
||||
u32 cmb_msr_num;
|
||||
};
|
||||
|
||||
/* Enumerate members of various datasets */
|
||||
@ -205,6 +305,11 @@ enum dataset_mem {
|
||||
DSB_PATT,
|
||||
DSB_PATT_MASK,
|
||||
DSB_MSR,
|
||||
CMB_TRIG_PATT,
|
||||
CMB_TRIG_PATT_MASK,
|
||||
CMB_PATT,
|
||||
CMB_PATT_MASK,
|
||||
CMB_MSR
|
||||
};
|
||||
|
||||
/**
|
||||
@ -220,4 +325,13 @@ struct tpdm_dataset_attribute {
|
||||
u32 idx;
|
||||
};
|
||||
|
||||
static bool tpdm_has_dsb_dataset(struct tpdm_drvdata *drvdata)
|
||||
{
|
||||
return (drvdata->datasets & TPDM_PIDR0_DS_DSB);
|
||||
}
|
||||
|
||||
static bool tpdm_has_cmb_dataset(struct tpdm_drvdata *drvdata)
|
||||
{
|
||||
return (drvdata->datasets & TPDM_PIDR0_DS_CMB);
|
||||
}
|
||||
#endif /* _CORESIGHT_CORESIGHT_TPDM_H */
|
||||
|
@ -58,6 +58,7 @@ struct tpiu_drvdata {
|
||||
void __iomem *base;
|
||||
struct clk *atclk;
|
||||
struct coresight_device *csdev;
|
||||
spinlock_t spinlock;
|
||||
};
|
||||
|
||||
static void tpiu_enable_hw(struct csdev_access *csa)
|
||||
@ -72,8 +73,11 @@ static void tpiu_enable_hw(struct csdev_access *csa)
|
||||
static int tpiu_enable(struct coresight_device *csdev, enum cs_mode mode,
|
||||
void *__unused)
|
||||
{
|
||||
struct tpiu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
|
||||
|
||||
guard(spinlock)(&drvdata->spinlock);
|
||||
tpiu_enable_hw(&csdev->access);
|
||||
atomic_inc(&csdev->refcnt);
|
||||
csdev->refcnt++;
|
||||
dev_dbg(&csdev->dev, "TPIU enabled\n");
|
||||
return 0;
|
||||
}
|
||||
@ -96,7 +100,11 @@ static void tpiu_disable_hw(struct csdev_access *csa)
|
||||
|
||||
static int tpiu_disable(struct coresight_device *csdev)
|
||||
{
|
||||
if (atomic_dec_return(&csdev->refcnt))
|
||||
struct tpiu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
|
||||
|
||||
guard(spinlock)(&drvdata->spinlock);
|
||||
csdev->refcnt--;
|
||||
if (csdev->refcnt)
|
||||
return -EBUSY;
|
||||
|
||||
tpiu_disable_hw(&csdev->access);
|
||||
@ -132,6 +140,8 @@ static int tpiu_probe(struct amba_device *adev, const struct amba_id *id)
|
||||
if (!drvdata)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&drvdata->spinlock);
|
||||
|
||||
drvdata->atclk = devm_clk_get(&adev->dev, "atclk"); /* optional */
|
||||
if (!IS_ERR(drvdata->atclk)) {
|
||||
ret = clk_prepare_enable(drvdata->atclk);
|
||||
@ -218,7 +228,7 @@ static const struct amba_id tpiu_ids[] = {
|
||||
.id = 0x000bb9e7,
|
||||
.mask = 0x000fffff,
|
||||
},
|
||||
{ 0, 0},
|
||||
{ 0, 0, NULL },
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(amba, tpiu_ids);
|
||||
|
@ -103,7 +103,7 @@ static int smb_open(struct inode *inode, struct file *file)
|
||||
if (drvdata->reading)
|
||||
return -EBUSY;
|
||||
|
||||
if (atomic_read(&drvdata->csdev->refcnt))
|
||||
if (drvdata->csdev->refcnt)
|
||||
return -EBUSY;
|
||||
|
||||
smb_update_data_size(drvdata);
|
||||
@ -207,11 +207,11 @@ static void smb_enable_sysfs(struct coresight_device *csdev)
|
||||
{
|
||||
struct smb_drv_data *drvdata = dev_get_drvdata(csdev->dev.parent);
|
||||
|
||||
if (drvdata->mode != CS_MODE_DISABLED)
|
||||
if (coresight_get_mode(csdev) != CS_MODE_DISABLED)
|
||||
return;
|
||||
|
||||
smb_enable_hw(drvdata);
|
||||
drvdata->mode = CS_MODE_SYSFS;
|
||||
coresight_set_mode(csdev, CS_MODE_SYSFS);
|
||||
}
|
||||
|
||||
static int smb_enable_perf(struct coresight_device *csdev, void *data)
|
||||
@ -234,7 +234,7 @@ static int smb_enable_perf(struct coresight_device *csdev, void *data)
|
||||
if (drvdata->pid == -1) {
|
||||
smb_enable_hw(drvdata);
|
||||
drvdata->pid = pid;
|
||||
drvdata->mode = CS_MODE_PERF;
|
||||
coresight_set_mode(csdev, CS_MODE_PERF);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -253,7 +253,8 @@ static int smb_enable(struct coresight_device *csdev, enum cs_mode mode,
|
||||
return -EBUSY;
|
||||
|
||||
/* Do nothing, the SMB is already enabled as other mode */
|
||||
if (drvdata->mode != CS_MODE_DISABLED && drvdata->mode != mode)
|
||||
if (coresight_get_mode(csdev) != CS_MODE_DISABLED &&
|
||||
coresight_get_mode(csdev) != mode)
|
||||
return -EBUSY;
|
||||
|
||||
switch (mode) {
|
||||
@ -270,7 +271,7 @@ static int smb_enable(struct coresight_device *csdev, enum cs_mode mode,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
atomic_inc(&csdev->refcnt);
|
||||
csdev->refcnt++;
|
||||
dev_dbg(&csdev->dev, "Ultrasoc SMB enabled\n");
|
||||
|
||||
return ret;
|
||||
@ -285,17 +286,18 @@ static int smb_disable(struct coresight_device *csdev)
|
||||
if (drvdata->reading)
|
||||
return -EBUSY;
|
||||
|
||||
if (atomic_dec_return(&csdev->refcnt))
|
||||
csdev->refcnt--;
|
||||
if (csdev->refcnt)
|
||||
return -EBUSY;
|
||||
|
||||
/* Complain if we (somehow) got out of sync */
|
||||
WARN_ON_ONCE(drvdata->mode == CS_MODE_DISABLED);
|
||||
WARN_ON_ONCE(coresight_get_mode(csdev) == CS_MODE_DISABLED);
|
||||
|
||||
smb_disable_hw(drvdata);
|
||||
|
||||
/* Dissociate from the target process. */
|
||||
drvdata->pid = -1;
|
||||
drvdata->mode = CS_MODE_DISABLED;
|
||||
coresight_set_mode(csdev, CS_MODE_DISABLED);
|
||||
dev_dbg(&csdev->dev, "Ultrasoc SMB disabled\n");
|
||||
|
||||
return 0;
|
||||
@ -380,7 +382,7 @@ static unsigned long smb_update_buffer(struct coresight_device *csdev,
|
||||
guard(spinlock)(&drvdata->spinlock);
|
||||
|
||||
/* Don't do anything if another tracer is using this sink. */
|
||||
if (atomic_read(&csdev->refcnt) != 1)
|
||||
if (csdev->refcnt != 1)
|
||||
return 0;
|
||||
|
||||
smb_disable_hw(drvdata);
|
||||
@ -586,7 +588,7 @@ static void smb_remove(struct platform_device *pdev)
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id ultrasoc_smb_acpi_match[] = {
|
||||
{"HISI03A1", 0},
|
||||
{"HISI03A1", 0, 0, 0},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, ultrasoc_smb_acpi_match);
|
||||
|
@ -109,7 +109,6 @@ struct smb_data_buffer {
|
||||
* @reading: Synchronise user space access to SMB buffer.
|
||||
* @pid: Process ID of the process being monitored by the
|
||||
* session that is using this component.
|
||||
* @mode: How this SMB is being used, perf mode or sysfs mode.
|
||||
*/
|
||||
struct smb_drv_data {
|
||||
void __iomem *base;
|
||||
@ -119,7 +118,6 @@ struct smb_drv_data {
|
||||
spinlock_t spinlock;
|
||||
bool reading;
|
||||
pid_t pid;
|
||||
enum cs_mode mode;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -998,6 +998,9 @@ static int hisi_ptt_pmu_event_init(struct perf_event *event)
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
if (event->attr.type != hisi_ptt->hisi_ptt_pmu.type)
|
||||
return -ENOENT;
|
||||
|
||||
if (event->cpu < 0) {
|
||||
dev_dbg(event->pmu->dev, "Per-task mode not supported\n");
|
||||
return -EOPNOTSUPP;
|
||||
@ -1006,9 +1009,6 @@ static int hisi_ptt_pmu_event_init(struct perf_event *event)
|
||||
if (event->attach_state & PERF_ATTACH_TASK)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (event->attr.type != hisi_ptt->hisi_ptt_pmu.type)
|
||||
return -ENOENT;
|
||||
|
||||
ret = hisi_ptt_trace_valid_filter(hisi_ptt, event->attr.config);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -35,7 +35,7 @@
|
||||
|
||||
#define CORESIGHT_UNLOCK 0xc5acce55
|
||||
|
||||
extern struct bus_type coresight_bustype;
|
||||
extern const struct bus_type coresight_bustype;
|
||||
|
||||
enum coresight_dev_type {
|
||||
CORESIGHT_DEV_TYPE_SINK,
|
||||
@ -226,13 +226,26 @@ struct coresight_sysfs_link {
|
||||
* by @coresight_ops.
|
||||
* @access: Device i/o access abstraction for this device.
|
||||
* @dev: The device entity associated to this component.
|
||||
* @refcnt: keep track of what is in use.
|
||||
* @mode: This tracer's mode, i.e sysFS, Perf or disabled. This is
|
||||
* actually an 'enum cs_mode', but is stored in an atomic type.
|
||||
* This is always accessed through local_read() and local_set(),
|
||||
* but wherever it's done from within the Coresight device's lock,
|
||||
* a non-atomic read would also work. This is the main point of
|
||||
* synchronisation between code happening inside the sysfs mode's
|
||||
* coresight_mutex and outside when running in Perf mode. A compare
|
||||
* and exchange swap is done to atomically claim one mode or the
|
||||
* other.
|
||||
* @refcnt: keep track of what is in use. Only access this outside of the
|
||||
* device's spinlock when the coresight_mutex held and mode ==
|
||||
* CS_MODE_SYSFS. Otherwise it must be accessed from inside the
|
||||
* spinlock.
|
||||
* @orphan: true if the component has connections that haven't been linked.
|
||||
* @enable: 'true' if component is currently part of an active path.
|
||||
* @activated: 'true' only if a _sink_ has been activated. A sink can be
|
||||
* activated but not yet enabled. Enabling for a _sink_
|
||||
* happens when a source has been selected and a path is enabled
|
||||
* from source to that sink.
|
||||
* @sysfs_sink_activated: 'true' when a sink has been selected for use via sysfs
|
||||
* by writing a 1 to the 'enable_sink' file. A sink can be
|
||||
* activated but not yet enabled. Enabling for a _sink_ happens
|
||||
* when a source has been selected and a path is enabled from
|
||||
* source to that sink. A sink can also become enabled but not
|
||||
* activated if it's used via Perf.
|
||||
* @ea: Device attribute for sink representation under PMU directory.
|
||||
* @def_sink: cached reference to default sink found for this device.
|
||||
* @nr_links: number of sysfs links created to other components from this
|
||||
@ -250,11 +263,11 @@ struct coresight_device {
|
||||
const struct coresight_ops *ops;
|
||||
struct csdev_access access;
|
||||
struct device dev;
|
||||
atomic_t refcnt;
|
||||
local_t mode;
|
||||
int refcnt;
|
||||
bool orphan;
|
||||
bool enable; /* true only if configured as part of a path */
|
||||
/* sink specific fields */
|
||||
bool activated; /* true only if a sink is part of a path */
|
||||
bool sysfs_sink_activated;
|
||||
struct dev_ext_attribute *ea;
|
||||
struct coresight_device *def_sink;
|
||||
/* sysfs links between components */
|
||||
@ -378,8 +391,6 @@ struct coresight_ops {
|
||||
const struct coresight_ops_helper *helper_ops;
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_CORESIGHT)
|
||||
|
||||
static inline u32 csdev_access_relaxed_read32(struct csdev_access *csa,
|
||||
u32 offset)
|
||||
{
|
||||
@ -569,11 +580,43 @@ static inline bool coresight_is_percpu_sink(struct coresight_device *csdev)
|
||||
(csdev->subtype.sink_subtype == CORESIGHT_DEV_SUBTYPE_SINK_PERCPU_SYSMEM);
|
||||
}
|
||||
|
||||
/*
|
||||
* Atomically try to take the device and set a new mode. Returns true on
|
||||
* success, false if the device is already taken by someone else.
|
||||
*/
|
||||
static inline bool coresight_take_mode(struct coresight_device *csdev,
|
||||
enum cs_mode new_mode)
|
||||
{
|
||||
return local_cmpxchg(&csdev->mode, CS_MODE_DISABLED, new_mode) ==
|
||||
CS_MODE_DISABLED;
|
||||
}
|
||||
|
||||
static inline enum cs_mode coresight_get_mode(struct coresight_device *csdev)
|
||||
{
|
||||
return local_read(&csdev->mode);
|
||||
}
|
||||
|
||||
static inline void coresight_set_mode(struct coresight_device *csdev,
|
||||
enum cs_mode new_mode)
|
||||
{
|
||||
enum cs_mode current_mode = coresight_get_mode(csdev);
|
||||
|
||||
/*
|
||||
* Changing to a new mode must be done from an already disabled state
|
||||
* unless it's synchronized with coresight_take_mode(). Otherwise the
|
||||
* device is already in use and signifies a locking issue.
|
||||
*/
|
||||
WARN(new_mode != CS_MODE_DISABLED && current_mode != CS_MODE_DISABLED &&
|
||||
current_mode != new_mode, "Device already in use\n");
|
||||
|
||||
local_set(&csdev->mode, new_mode);
|
||||
}
|
||||
|
||||
extern struct coresight_device *
|
||||
coresight_register(struct coresight_desc *desc);
|
||||
extern void coresight_unregister(struct coresight_device *csdev);
|
||||
extern int coresight_enable(struct coresight_device *csdev);
|
||||
extern void coresight_disable(struct coresight_device *csdev);
|
||||
extern int coresight_enable_sysfs(struct coresight_device *csdev);
|
||||
extern void coresight_disable_sysfs(struct coresight_device *csdev);
|
||||
extern int coresight_timeout(struct csdev_access *csa, u32 offset,
|
||||
int position, int value);
|
||||
|
||||
@ -598,83 +641,6 @@ void coresight_relaxed_write64(struct coresight_device *csdev,
|
||||
u64 val, u32 offset);
|
||||
void coresight_write64(struct coresight_device *csdev, u64 val, u32 offset);
|
||||
|
||||
#else
|
||||
static inline struct coresight_device *
|
||||
coresight_register(struct coresight_desc *desc) { return NULL; }
|
||||
static inline void coresight_unregister(struct coresight_device *csdev) {}
|
||||
static inline int
|
||||
coresight_enable(struct coresight_device *csdev) { return -ENOSYS; }
|
||||
static inline void coresight_disable(struct coresight_device *csdev) {}
|
||||
|
||||
static inline int coresight_timeout(struct csdev_access *csa, u32 offset,
|
||||
int position, int value)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int coresight_claim_device_unlocked(struct coresight_device *csdev)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline int coresight_claim_device(struct coresight_device *csdev)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline void coresight_disclaim_device(struct coresight_device *csdev) {}
|
||||
static inline void coresight_disclaim_device_unlocked(struct coresight_device *csdev) {}
|
||||
|
||||
static inline bool coresight_loses_context_with_cpu(struct device *dev)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline u32 coresight_relaxed_read32(struct coresight_device *csdev, u32 offset)
|
||||
{
|
||||
WARN_ON_ONCE(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline u32 coresight_read32(struct coresight_device *csdev, u32 offset)
|
||||
{
|
||||
WARN_ON_ONCE(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void coresight_write32(struct coresight_device *csdev, u32 val, u32 offset)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void coresight_relaxed_write32(struct coresight_device *csdev,
|
||||
u32 val, u32 offset)
|
||||
{
|
||||
}
|
||||
|
||||
static inline u64 coresight_relaxed_read64(struct coresight_device *csdev,
|
||||
u32 offset)
|
||||
{
|
||||
WARN_ON_ONCE(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline u64 coresight_read64(struct coresight_device *csdev, u32 offset)
|
||||
{
|
||||
WARN_ON_ONCE(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void coresight_relaxed_write64(struct coresight_device *csdev,
|
||||
u64 val, u32 offset)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void coresight_write64(struct coresight_device *csdev, u64 val, u32 offset)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* IS_ENABLED(CONFIG_CORESIGHT) */
|
||||
|
||||
extern int coresight_get_cpu(struct device *dev);
|
||||
|
||||
struct coresight_platform_data *coresight_get_platform_data(struct device *dev);
|
||||
|
Loading…
Reference in New Issue
Block a user