mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 03:48:59 +00:00
1b5b1646e6
The CTI module has some hard coded refcounting code that has a leak. For example running perf and then trying to unload it fails: perf record -e cs_etm// -a -- ls rmmod coresight_cti rmmod: ERROR: Module coresight_cti is in use The coresight core already handles references of devices in use, so by making CTI a normal helper device, we get working refcounting for free. Reviewed-by: Mike Leach <mike.leach@linaro.org> Signed-off-by: James Clark <james.clark@arm.com> Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com> Link: https://lore.kernel.org/r/20230425143542.2305069-14-james.clark@arm.com
242 lines
7.4 KiB
C
242 lines
7.4 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* Copyright (c) 2018 Linaro Limited, All rights reserved.
|
|
* Author: Mike Leach <mike.leach@linaro.org>
|
|
*/
|
|
|
|
#ifndef _CORESIGHT_CORESIGHT_CTI_H
|
|
#define _CORESIGHT_CORESIGHT_CTI_H
|
|
|
|
#include <linux/coresight.h>
|
|
#include <linux/device.h>
|
|
#include <linux/fwnode.h>
|
|
#include <linux/list.h>
|
|
#include <linux/spinlock.h>
|
|
#include <linux/sysfs.h>
|
|
#include <linux/types.h>
|
|
|
|
#include "coresight-priv.h"
|
|
|
|
/*
|
|
* Device registers
|
|
* 0x000 - 0x144: CTI programming and status
|
|
* 0xEDC - 0xEF8: CTI integration test.
|
|
* 0xF00 - 0xFFC: Coresight management registers.
|
|
*/
|
|
/* CTI programming registers */
|
|
#define CTICONTROL 0x000
|
|
#define CTIINTACK 0x010
|
|
#define CTIAPPSET 0x014
|
|
#define CTIAPPCLEAR 0x018
|
|
#define CTIAPPPULSE 0x01C
|
|
#define CTIINEN(n) (0x020 + (4 * n))
|
|
#define CTIOUTEN(n) (0x0A0 + (4 * n))
|
|
#define CTITRIGINSTATUS 0x130
|
|
#define CTITRIGOUTSTATUS 0x134
|
|
#define CTICHINSTATUS 0x138
|
|
#define CTICHOUTSTATUS 0x13C
|
|
#define CTIGATE 0x140
|
|
#define ASICCTL 0x144
|
|
/* Integration test registers */
|
|
#define ITCHINACK 0xEDC /* WO CTI CSSoc 400 only*/
|
|
#define ITTRIGINACK 0xEE0 /* WO CTI CSSoc 400 only*/
|
|
#define ITCHOUT 0xEE4 /* WO RW-600 */
|
|
#define ITTRIGOUT 0xEE8 /* WO RW-600 */
|
|
#define ITCHOUTACK 0xEEC /* RO CTI CSSoc 400 only*/
|
|
#define ITTRIGOUTACK 0xEF0 /* RO CTI CSSoc 400 only*/
|
|
#define ITCHIN 0xEF4 /* RO */
|
|
#define ITTRIGIN 0xEF8 /* RO */
|
|
/* management registers */
|
|
#define CTIDEVAFF0 0xFA8
|
|
#define CTIDEVAFF1 0xFAC
|
|
|
|
/*
|
|
* CTI CSSoc 600 has a max of 32 trigger signals per direction.
|
|
* CTI CSSoc 400 has 8 IO triggers - other CTIs can be impl def.
|
|
* Max of in and out defined in the DEVID register.
|
|
* - pick up actual number used from .dts parameters if present.
|
|
*/
|
|
#define CTIINOUTEN_MAX 32
|
|
|
|
/**
|
|
* Group of related trigger signals
|
|
*
|
|
* @nr_sigs: number of signals in the group.
|
|
* @used_mask: bitmask representing the signal indexes in the group.
|
|
* @sig_types: array of types for the signals, length nr_sigs.
|
|
*/
|
|
struct cti_trig_grp {
|
|
int nr_sigs;
|
|
u32 used_mask;
|
|
int sig_types[];
|
|
};
|
|
|
|
/**
|
|
* Trigger connection - connection between a CTI and other (coresight) device
|
|
* lists input and output trigger signals for the device
|
|
*
|
|
* @con_in: connected CTIIN signals for the device.
|
|
* @con_out: connected CTIOUT signals for the device.
|
|
* @con_dev: coresight device connected to the CTI, NULL if not CS device
|
|
* @con_dev_name: name of connected device (CS or CPU)
|
|
* @node: entry node in list of connections.
|
|
* @con_attrs: Dynamic sysfs attributes specific to this connection.
|
|
* @attr_group: Dynamic attribute group created for this connection.
|
|
*/
|
|
struct cti_trig_con {
|
|
struct cti_trig_grp *con_in;
|
|
struct cti_trig_grp *con_out;
|
|
struct coresight_device *con_dev;
|
|
const char *con_dev_name;
|
|
struct list_head node;
|
|
struct attribute **con_attrs;
|
|
struct attribute_group *attr_group;
|
|
};
|
|
|
|
/**
|
|
* struct cti_device - description of CTI device properties.
|
|
*
|
|
* @nt_trig_con: Number of external devices connected to this device.
|
|
* @ctm_id: which CTM this device is connected to (by default it is
|
|
* assumed there is a single CTM per SoC, ID 0).
|
|
* @trig_cons: list of connections to this device.
|
|
* @cpu: CPU ID if associated with CPU, -1 otherwise.
|
|
* @con_groups: combined static and dynamic sysfs groups for trigger
|
|
* connections.
|
|
*/
|
|
struct cti_device {
|
|
int nr_trig_con;
|
|
u32 ctm_id;
|
|
struct list_head trig_cons;
|
|
int cpu;
|
|
const struct attribute_group **con_groups;
|
|
};
|
|
|
|
/**
|
|
* struct cti_config - configuration of the CTI device hardware
|
|
*
|
|
* @nr_trig_max: Max number of trigger signals implemented on device.
|
|
* (max of trig_in or trig_out) - from ID register.
|
|
* @nr_ctm_channels: number of available CTM channels - from ID register.
|
|
* @enable_req_count: CTI is enabled alongside >=1 associated devices.
|
|
* @hw_enabled: true if hw is currently enabled.
|
|
* @hw_powered: true if associated cpu powered on, or no cpu.
|
|
* @trig_in_use: bitfield of in triggers registered as in use.
|
|
* @trig_out_use: bitfield of out triggers registered as in use.
|
|
* @trig_out_filter: bitfield of out triggers that are blocked if filter
|
|
* enabled. Typically this would be dbgreq / restart on
|
|
* a core CTI.
|
|
* @trig_filter_enable: 1 if filtering enabled.
|
|
* @xtrig_rchan_sel: channel selection for xtrigger connection show.
|
|
* @ctiappset: CTI Software application channel set.
|
|
* @ctiinout_sel: register selector for INEN and OUTEN regs.
|
|
* @ctiinen: enable input trigger to a channel.
|
|
* @ctiouten: enable output trigger from a channel.
|
|
* @ctigate: gate channel output from CTI to CTM.
|
|
* @asicctl: asic control register.
|
|
*/
|
|
struct cti_config {
|
|
/* hardware description */
|
|
int nr_ctm_channels;
|
|
int nr_trig_max;
|
|
|
|
/* cti enable control */
|
|
int enable_req_count;
|
|
bool hw_enabled;
|
|
bool hw_powered;
|
|
|
|
/* registered triggers and filtering */
|
|
u32 trig_in_use;
|
|
u32 trig_out_use;
|
|
u32 trig_out_filter;
|
|
bool trig_filter_enable;
|
|
u8 xtrig_rchan_sel;
|
|
|
|
/* cti cross trig programmable regs */
|
|
u32 ctiappset;
|
|
u8 ctiinout_sel;
|
|
u32 ctiinen[CTIINOUTEN_MAX];
|
|
u32 ctiouten[CTIINOUTEN_MAX];
|
|
u32 ctigate;
|
|
u32 asicctl;
|
|
};
|
|
|
|
/**
|
|
* struct cti_drvdata - specifics for the CTI device
|
|
* @base: Memory mapped base address for this component..
|
|
* @csdev: Standard CoreSight device information.
|
|
* @ctidev: Extra information needed by the CTI/CTM framework.
|
|
* @spinlock: Control data access to one at a time.
|
|
* @config: Configuration data for this CTI device.
|
|
* @node: List entry of this device in the list of CTI devices.
|
|
* @csdev_release: release function for underlying coresight_device.
|
|
*/
|
|
struct cti_drvdata {
|
|
void __iomem *base;
|
|
struct coresight_device *csdev;
|
|
struct cti_device ctidev;
|
|
spinlock_t spinlock;
|
|
struct cti_config config;
|
|
struct list_head node;
|
|
void (*csdev_release)(struct device *dev);
|
|
};
|
|
|
|
/*
|
|
* Channel operation types.
|
|
*/
|
|
enum cti_chan_op {
|
|
CTI_CHAN_ATTACH,
|
|
CTI_CHAN_DETACH,
|
|
};
|
|
|
|
enum cti_trig_dir {
|
|
CTI_TRIG_IN,
|
|
CTI_TRIG_OUT,
|
|
};
|
|
|
|
enum cti_chan_gate_op {
|
|
CTI_GATE_CHAN_ENABLE,
|
|
CTI_GATE_CHAN_DISABLE,
|
|
};
|
|
|
|
enum cti_chan_set_op {
|
|
CTI_CHAN_SET,
|
|
CTI_CHAN_CLR,
|
|
CTI_CHAN_PULSE,
|
|
};
|
|
|
|
/* private cti driver fns & vars */
|
|
extern const struct attribute_group *coresight_cti_groups[];
|
|
int cti_add_default_connection(struct device *dev,
|
|
struct cti_drvdata *drvdata);
|
|
int cti_add_connection_entry(struct device *dev, struct cti_drvdata *drvdata,
|
|
struct cti_trig_con *tc,
|
|
struct coresight_device *csdev,
|
|
const char *assoc_dev_name);
|
|
struct cti_trig_con *cti_allocate_trig_con(struct device *dev, int in_sigs,
|
|
int out_sigs);
|
|
int cti_enable(struct coresight_device *csdev, enum cs_mode mode, void *data);
|
|
int cti_disable(struct coresight_device *csdev, void *data);
|
|
void cti_write_all_hw_regs(struct cti_drvdata *drvdata);
|
|
void cti_write_intack(struct device *dev, u32 ackval);
|
|
void cti_write_single_reg(struct cti_drvdata *drvdata, int offset, u32 value);
|
|
int cti_channel_trig_op(struct device *dev, enum cti_chan_op op,
|
|
enum cti_trig_dir direction, u32 channel_idx,
|
|
u32 trigger_idx);
|
|
int cti_channel_gate_op(struct device *dev, enum cti_chan_gate_op op,
|
|
u32 channel_idx);
|
|
int cti_channel_setop(struct device *dev, enum cti_chan_set_op op,
|
|
u32 channel_idx);
|
|
int cti_create_cons_sysfs(struct device *dev, struct cti_drvdata *drvdata);
|
|
struct coresight_platform_data *
|
|
coresight_cti_get_platform_data(struct device *dev);
|
|
const char *cti_plat_get_node_name(struct fwnode_handle *fwnode);
|
|
|
|
/* cti powered and enabled */
|
|
static inline bool cti_active(struct cti_config *cfg)
|
|
{
|
|
return cfg->hw_powered && cfg->hw_enabled;
|
|
}
|
|
|
|
#endif /* _CORESIGHT_CORESIGHT_CTI_H */
|