linux/drivers/perf/arm_smmuv3_pmu.c

// SPDX-License-Identifier: GPL-2.0

/*
 * This driver adds support for perf events to use the Performance
 * Monitor Counter Groups (PMCG) associated with an SMMUv3 node
 * to monitor that node.
 *
 * SMMUv3 PMCG devices are named as smmuv3_pmcg_<phys_addr_page> where
 * <phys_addr_page> is the physical page address of the SMMU PMCG wrapped
 * to 4K boundary. For example, the PMCG at 0xff88840000 is named
 * smmuv3_pmcg_ff88840
 *
 * Filtering by stream id is done by specifying filtering parameters
 * with the event. options are:
 *   filter_enable    - 0 = no filtering, 1 = filtering enabled
 *   filter_span      - 0 = exact match, 1 = pattern match
 *   filter_stream_id - pattern to filter against
 *
 * To match a partial StreamID where the X most-significant bits must match
 * but the Y least-significant bits might differ, STREAMID is programmed
 * with a value that contains:
 *  STREAMID[Y - 1] == 0.
 *  STREAMID[Y - 2:0] == 1 (where Y > 1).
 * The remainder of implemented bits of STREAMID (X bits, from bit Y upwards)
 * contain a value to match from the corresponding bits of event StreamID.
 *
 * Example: perf stat -e smmuv3_pmcg_ff88840/transaction,filter_enable=1,
 *                    filter_span=1,filter_stream_id=0x42/ -a netperf
 * Applies filter pattern 0x42 to transaction events, which means events
 * matching stream ids 0x42 and 0x43 are counted. Further filtering
 * information is available in the SMMU documentation.
 *
 * SMMU events are not attributable to a CPU, so task mode and sampling
 * are not supported.
 */

#include <linux/acpi.h>
#include <linux/acpi_iort.h>
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/cpuhotplug.h>
#include <linux/cpumask.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/msi.h>
#include <linux/of.h>
#include <linux/perf_event.h>
#include <linux/platform_device.h>
#include <linux/smp.h>
#include <linux/sysfs.h>
#include <linux/types.h>

#define SMMU_PMCG_EVCNTR0
#define SMMU_PMCG_EVCNTR(n, stride)
#define SMMU_PMCG_EVTYPER0
#define SMMU_PMCG_EVTYPER(n)
#define SMMU_PMCG_SID_SPAN_SHIFT
#define SMMU_PMCG_SMR0
#define SMMU_PMCG_SMR(n)
#define SMMU_PMCG_CNTENSET0
#define SMMU_PMCG_CNTENCLR0
#define SMMU_PMCG_INTENSET0
#define SMMU_PMCG_INTENCLR0
#define SMMU_PMCG_OVSCLR0
#define SMMU_PMCG_OVSSET0
#define SMMU_PMCG_CFGR
#define SMMU_PMCG_CFGR_SID_FILTER_TYPE
#define SMMU_PMCG_CFGR_MSI
#define SMMU_PMCG_CFGR_RELOC_CTRS
#define SMMU_PMCG_CFGR_SIZE
#define SMMU_PMCG_CFGR_NCTR
#define SMMU_PMCG_CR
#define SMMU_PMCG_CR_ENABLE
#define SMMU_PMCG_IIDR
#define SMMU_PMCG_IIDR_PRODUCTID
#define SMMU_PMCG_IIDR_VARIANT
#define SMMU_PMCG_IIDR_REVISION
#define SMMU_PMCG_IIDR_IMPLEMENTER
#define SMMU_PMCG_CEID0
#define SMMU_PMCG_CEID1
#define SMMU_PMCG_IRQ_CTRL
#define SMMU_PMCG_IRQ_CTRL_IRQEN
#define SMMU_PMCG_IRQ_CFG0
#define SMMU_PMCG_IRQ_CFG1
#define SMMU_PMCG_IRQ_CFG2

/* IMP-DEF ID registers */
#define SMMU_PMCG_PIDR0
#define SMMU_PMCG_PIDR0_PART_0
#define SMMU_PMCG_PIDR1
#define SMMU_PMCG_PIDR1_DES_0
#define SMMU_PMCG_PIDR1_PART_1
#define SMMU_PMCG_PIDR2
#define SMMU_PMCG_PIDR2_REVISION
#define SMMU_PMCG_PIDR2_DES_1
#define SMMU_PMCG_PIDR3
#define SMMU_PMCG_PIDR3_REVAND
#define SMMU_PMCG_PIDR4
#define SMMU_PMCG_PIDR4_DES_2

/* MSI config fields */
#define MSI_CFG0_ADDR_MASK
#define MSI_CFG2_MEMATTR_DEVICE_nGnRE

#define SMMU_PMCG_DEFAULT_FILTER_SPAN
#define SMMU_PMCG_DEFAULT_FILTER_SID

#define SMMU_PMCG_MAX_COUNTERS
#define SMMU_PMCG_ARCH_MAX_EVENTS

#define SMMU_PMCG_PA_SHIFT

#define SMMU_PMCG_EVCNTR_RDONLY
#define SMMU_PMCG_HARDEN_DISABLE

static int cpuhp_state_num;

struct smmu_pmu {};

#define to_smmu_pmu(p)

#define SMMU_PMU_EVENT_ATTR_EXTRACTOR(_name, _config, _start, _end)                                                                  \

SMMU_PMU_EVENT_ATTR_EXTRACTOR(event, config, 0, 15);
SMMU_PMU_EVENT_ATTR_EXTRACTOR(filter_stream_id, config1, 0, 31);
SMMU_PMU_EVENT_ATTR_EXTRACTOR(filter_span, config1, 32, 32);
SMMU_PMU_EVENT_ATTR_EXTRACTOR(filter_enable, config1, 33, 33);

static inline void smmu_pmu_enable(struct pmu *pmu)
{}

static int smmu_pmu_apply_event_filter(struct smmu_pmu *smmu_pmu,
				       struct perf_event *event, int idx);

static inline void smmu_pmu_enable_quirk_hip08_09(struct pmu *pmu)
{}

static inline void smmu_pmu_disable(struct pmu *pmu)
{}

static inline void smmu_pmu_disable_quirk_hip08_09(struct pmu *pmu)
{}

static inline void smmu_pmu_counter_set_value(struct smmu_pmu *smmu_pmu,
					      u32 idx, u64 value)
{}

static inline u64 smmu_pmu_counter_get_value(struct smmu_pmu *smmu_pmu, u32 idx)
{}

static inline void smmu_pmu_counter_enable(struct smmu_pmu *smmu_pmu, u32 idx)
{}

static inline void smmu_pmu_counter_disable(struct smmu_pmu *smmu_pmu, u32 idx)
{}

static inline void smmu_pmu_interrupt_enable(struct smmu_pmu *smmu_pmu, u32 idx)
{}

static inline void smmu_pmu_interrupt_disable(struct smmu_pmu *smmu_pmu,
					      u32 idx)
{}

static inline void smmu_pmu_set_evtyper(struct smmu_pmu *smmu_pmu, u32 idx,
					u32 val)
{}

static inline void smmu_pmu_set_smr(struct smmu_pmu *smmu_pmu, u32 idx, u32 val)
{}

static void smmu_pmu_event_update(struct perf_event *event)
{}

static void smmu_pmu_set_period(struct smmu_pmu *smmu_pmu,
				struct hw_perf_event *hwc)
{}

static void smmu_pmu_set_event_filter(struct perf_event *event,
				      int idx, u32 span, u32 sid)
{}

static bool smmu_pmu_check_global_filter(struct perf_event *curr,
					 struct perf_event *new)
{}

static int smmu_pmu_apply_event_filter(struct smmu_pmu *smmu_pmu,
				       struct perf_event *event, int idx)
{}

static int smmu_pmu_get_event_idx(struct smmu_pmu *smmu_pmu,
				  struct perf_event *event)
{}

static bool smmu_pmu_events_compatible(struct perf_event *curr,
				       struct perf_event *new)
{}

/*
 * Implementation of abstract pmu functionality required by
 * the core perf events code.
 */

static int smmu_pmu_event_init(struct perf_event *event)
{}

static void smmu_pmu_event_start(struct perf_event *event, int flags)
{}

static void smmu_pmu_event_stop(struct perf_event *event, int flags)
{}

static int smmu_pmu_event_add(struct perf_event *event, int flags)
{}

static void smmu_pmu_event_del(struct perf_event *event, int flags)
{}

static void smmu_pmu_event_read(struct perf_event *event)
{}

/* cpumask */

static ssize_t smmu_pmu_cpumask_show(struct device *dev,
				     struct device_attribute *attr,
				     char *buf)
{}

static struct device_attribute smmu_pmu_cpumask_attr =;

static struct attribute *smmu_pmu_cpumask_attrs[] =;

static const struct attribute_group smmu_pmu_cpumask_group =;

/* Events */

static ssize_t smmu_pmu_event_show(struct device *dev,
				   struct device_attribute *attr, char *page)
{}

#define SMMU_EVENT_ATTR(name, config)

static struct attribute *smmu_pmu_events[] =;

static umode_t smmu_pmu_event_is_visible(struct kobject *kobj,
					 struct attribute *attr, int unused)
{}

static const struct attribute_group smmu_pmu_events_group =;

static ssize_t smmu_pmu_identifier_attr_show(struct device *dev,
					struct device_attribute *attr,
					char *page)
{}

static umode_t smmu_pmu_identifier_attr_visible(struct kobject *kobj,
						struct attribute *attr,
						int n)
{}

static struct device_attribute smmu_pmu_identifier_attr =;

static struct attribute *smmu_pmu_identifier_attrs[] =;

static const struct attribute_group smmu_pmu_identifier_group =;

/* Formats */
PMU_FORMAT_ATTR();
PMU_FORMAT_ATTR();
PMU_FORMAT_ATTR();
PMU_FORMAT_ATTR();

static struct attribute *smmu_pmu_formats[] =;

static const struct attribute_group smmu_pmu_format_group =;

static const struct attribute_group *smmu_pmu_attr_grps[] =;

/*
 * Generic device handlers
 */

static int smmu_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node)
{}

static irqreturn_t smmu_pmu_handle_irq(int irq_num, void *data)
{}

static void smmu_pmu_free_msis(void *data)
{}

static void smmu_pmu_write_msi_msg(struct msi_desc *desc, struct msi_msg *msg)
{}

static void smmu_pmu_setup_msi(struct smmu_pmu *pmu)
{}

static int smmu_pmu_setup_irq(struct smmu_pmu *pmu)
{}

static void smmu_pmu_reset(struct smmu_pmu *smmu_pmu)
{}

static void smmu_pmu_get_acpi_options(struct smmu_pmu *smmu_pmu)
{}

static bool smmu_pmu_coresight_id_regs(struct smmu_pmu *smmu_pmu)
{}

static void smmu_pmu_get_iidr(struct smmu_pmu *smmu_pmu)
{}

static int smmu_pmu_probe(struct platform_device *pdev)
{}

static void smmu_pmu_remove(struct platform_device *pdev)
{}

static void smmu_pmu_shutdown(struct platform_device *pdev)
{}

#ifdef CONFIG_OF
static const struct of_device_id smmu_pmu_of_match[] =;
MODULE_DEVICE_TABLE(of, smmu_pmu_of_match);
#endif

static struct platform_driver smmu_pmu_driver =;

static int __init arm_smmu_pmu_init(void)
{}
module_init();

static void __exit arm_smmu_pmu_exit(void)
{}

module_exit(arm_smmu_pmu_exit);

MODULE_ALIAS();
MODULE_DESCRIPTION();
MODULE_AUTHOR();
MODULE_AUTHOR();
MODULE_LICENSE();