linux/drivers/perf/arm-cmn.c

// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2016-2020 Arm Limited
// CMN-600 Coherent Mesh Network PMU driver

#include <linux/acpi.h>
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/debugfs.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/perf_event.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/sort.h>

/* Common register stuff */
#define CMN_NODE_INFO
#define CMN_NI_NODE_TYPE
#define CMN_NI_NODE_ID
#define CMN_NI_LOGICAL_ID

#define CMN_NODEID_DEVID(reg)
#define CMN_NODEID_EXT_DEVID(reg)
#define CMN_NODEID_PID(reg)
#define CMN_NODEID_EXT_PID(reg)
#define CMN_NODEID_1x1_PID(reg)
#define CMN_NODEID_X(reg, bits)
#define CMN_NODEID_Y(reg, bits)

#define CMN_CHILD_INFO
#define CMN_CI_CHILD_COUNT
#define CMN_CI_CHILD_PTR_OFFSET

#define CMN_CHILD_NODE_ADDR
#define CMN_CHILD_NODE_EXTERNAL

#define CMN_MAX_DIMENSION
#define CMN_MAX_XPS
#define CMN_MAX_DTMS

/* The CFG node has various info besides the discovery tree */
#define CMN_CFGM_PERIPH_ID_01
#define CMN_CFGM_PID0_PART_0
#define CMN_CFGM_PID1_PART_1
#define CMN_CFGM_PERIPH_ID_23
#define CMN_CFGM_PID2_REVISION

#define CMN_CFGM_INFO_GLOBAL
#define CMN_INFO_MULTIPLE_DTM_EN
#define CMN_INFO_RSP_VC_NUM
#define CMN_INFO_DAT_VC_NUM

#define CMN_CFGM_INFO_GLOBAL_1
#define CMN_INFO_SNP_VC_NUM
#define CMN_INFO_REQ_VC_NUM

/* XPs also have some local topology info which has uses too */
#define CMN_MXP__CONNECT_INFO(p)
#define CMN__CONNECT_INFO_DEVICE_TYPE

#define CMN_MAX_PORTS
#define CI700_CONNECT_INFO_P2_5_OFFSET

/* PMU registers occupy the 3rd 4KB page of each node's region */
#define CMN_PMU_OFFSET

/* For most nodes, this is all there is */
#define CMN_PMU_EVENT_SEL
#define CMN__PMU_CBUSY_SNTHROTTLE_SEL
#define CMN__PMU_SN_HOME_SEL
#define CMN__PMU_HBT_LBT_SEL
#define CMN__PMU_CLASS_OCCUP_ID
/* Technically this is 4 bits wide on DNs, but we only use 2 there anyway */
#define CMN__PMU_OCCUP1_ID

/* HN-Ps are weird... */
#define CMN_HNP_PMU_EVENT_SEL

/* DTMs live in the PMU space of XP registers */
#define CMN_DTM_WPn(n)
#define CMN_DTM_WPn_CONFIG(n)
#define CMN_DTM_WPn_CONFIG_WP_CHN_NUM
#define CMN_DTM_WPn_CONFIG_WP_DEV_SEL2
#define CMN_DTM_WPn_CONFIG_WP_COMBINE
#define CMN_DTM_WPn_CONFIG_WP_EXCLUSIVE
#define CMN600_WPn_CONFIG_WP_COMBINE
#define CMN600_WPn_CONFIG_WP_EXCLUSIVE
#define CMN_DTM_WPn_CONFIG_WP_GRP
#define CMN_DTM_WPn_CONFIG_WP_CHN_SEL
#define CMN_DTM_WPn_CONFIG_WP_DEV_SEL
#define CMN_DTM_WPn_VAL(n)
#define CMN_DTM_WPn_MASK(n)

#define CMN_DTM_PMU_CONFIG
#define CMN__PMEVCNT0_INPUT_SEL
#define CMN__PMEVCNT0_INPUT_SEL_WP
#define CMN__PMEVCNT0_INPUT_SEL_XP
#define CMN__PMEVCNT0_INPUT_SEL_DEV
#define CMN__PMEVCNT0_GLOBAL_NUM
#define CMN__PMEVCNTn_GLOBAL_NUM_SHIFT(n)
#define CMN__PMEVCNT_PAIRED(n)
#define CMN__PMEVCNT23_COMBINED
#define CMN__PMEVCNT01_COMBINED
#define CMN_DTM_PMU_CONFIG_PMU_EN

#define CMN_DTM_PMEVCNT

#define CMN_DTM_PMEVCNTSR

#define CMN650_DTM_UNIT_INFO
#define CMN_DTM_UNIT_INFO
#define CMN_DTM_UNIT_INFO_DTC_DOMAIN

#define CMN_DTM_NUM_COUNTERS
/* Want more local counters? Why not replicate the whole DTM! Ugh... */
#define CMN_DTM_OFFSET(n)

/* The DTC node is where the magic happens */
#define CMN_DT_DTC_CTL
#define CMN_DT_DTC_CTL_DT_EN

/* DTC counters are paired in 64-bit registers on a 16-byte stride. Yuck */
#define _CMN_DT_CNT_REG(n)
#define CMN_DT_PMEVCNT(n)
#define CMN_DT_PMCCNTR

#define CMN_DT_PMEVCNTSR(n)
#define CMN_DT_PMCCNTRSR

#define CMN_DT_PMCR
#define CMN_DT_PMCR_PMU_EN
#define CMN_DT_PMCR_CNTR_RST
#define CMN_DT_PMCR_OVFL_INTR_EN

#define CMN_DT_PMOVSR
#define CMN_DT_PMOVSR_CLR

#define CMN_DT_PMSSR
#define CMN_DT_PMSSR_SS_STATUS(n)

#define CMN_DT_PMSRR
#define CMN_DT_PMSRR_SS_REQ

#define CMN_DT_NUM_COUNTERS
#define CMN_MAX_DTCS

/*
 * Even in the worst case a DTC counter can't wrap in fewer than 2^42 cycles,
 * so throwing away one bit to make overflow handling easy is no big deal.
 */
#define CMN_COUNTER_INIT
/* Similarly for the 40-bit cycle counter */
#define CMN_CC_INIT


/* Event attributes */
#define CMN_CONFIG_TYPE
#define CMN_CONFIG_EVENTID
#define CMN_CONFIG_OCCUPID
#define CMN_CONFIG_BYNODEID
#define CMN_CONFIG_NODEID

#define CMN_EVENT_TYPE(event)
#define CMN_EVENT_EVENTID(event)
#define CMN_EVENT_OCCUPID(event)
#define CMN_EVENT_BYNODEID(event)
#define CMN_EVENT_NODEID(event)

#define CMN_CONFIG_WP_COMBINE
#define CMN_CONFIG_WP_DEV_SEL
#define CMN_CONFIG_WP_CHN_SEL
#define CMN_CONFIG_WP_GRP
#define CMN_CONFIG_WP_EXCLUSIVE
#define CMN_CONFIG1_WP_VAL
#define CMN_CONFIG2_WP_MASK

#define CMN_EVENT_WP_COMBINE(event)
#define CMN_EVENT_WP_DEV_SEL(event)
#define CMN_EVENT_WP_CHN_SEL(event)
#define CMN_EVENT_WP_GRP(event)
#define CMN_EVENT_WP_EXCLUSIVE(event)
#define CMN_EVENT_WP_VAL(event)
#define CMN_EVENT_WP_MASK(event)

/* Made-up event IDs for watchpoint direction */
#define CMN_WP_UP
#define CMN_WP_DOWN


/* Internal values for encoding event support */
enum cmn_model {};

/* Actual part numbers and revision IDs defined by the hardware */
enum cmn_part {};

/* CMN-600 r0px shouldn't exist in silicon, thankfully */
enum cmn_revision {};

enum cmn_node_type {};

enum cmn_filter_select {};

struct arm_cmn_node {};

struct arm_cmn_dtm {};

struct arm_cmn_dtc {};

#define CMN_STATE_DISABLED
#define CMN_STATE_TXN

struct arm_cmn {};

#define to_cmn(p)

static int arm_cmn_hp_state;

struct arm_cmn_nodeid {};

static int arm_cmn_xyidbits(const struct arm_cmn *cmn)
{}

static struct arm_cmn_nodeid arm_cmn_nid(const struct arm_cmn *cmn, u16 id)
{}

static struct arm_cmn_node *arm_cmn_node_to_xp(const struct arm_cmn *cmn,
					       const struct arm_cmn_node *dn)
{}
static struct arm_cmn_node *arm_cmn_node(const struct arm_cmn *cmn,
					 enum cmn_node_type type)
{}

static enum cmn_model arm_cmn_model(const struct arm_cmn *cmn)
{}

static u32 arm_cmn_device_connect_info(const struct arm_cmn *cmn,
				       const struct arm_cmn_node *xp, int port)
{}

static struct dentry *arm_cmn_debugfs;

#ifdef CONFIG_DEBUG_FS
static const char *arm_cmn_device_type(u8 type)
{}

static void arm_cmn_show_logid(struct seq_file *s, int x, int y, int p, int d)
{}

static int arm_cmn_map_show(struct seq_file *s, void *data)
{}
DEFINE_SHOW_ATTRIBUTE();

static void arm_cmn_debugfs_init(struct arm_cmn *cmn, int id)
{}
#else
static void arm_cmn_debugfs_init(struct arm_cmn *cmn, int id) {}
#endif

struct arm_cmn_hw_event {};

#define for_each_hw_dn(hw, dn, i)

/* @i is the DTC number, @idx is the counter index on that DTC */
#define for_each_hw_dtc_idx(hw, i, idx)

static struct arm_cmn_hw_event *to_cmn_hw(struct perf_event *event)
{}

static void arm_cmn_set_index(u64 x[], unsigned int pos, unsigned int val)
{}

static unsigned int arm_cmn_get_index(u64 x[], unsigned int pos)
{}

static void arm_cmn_set_wp_idx(unsigned long *wp_idx, unsigned int pos, bool val)
{}

static unsigned int arm_cmn_get_wp_idx(unsigned long *wp_idx, unsigned int pos)
{}

struct arm_cmn_event_attr {};

struct arm_cmn_format_attr {};

#define _CMN_EVENT_ATTR(_model, _name, _type, _eventid, _occupid, _fsel)
#define CMN_EVENT_ATTR(_model, _name, _type, _eventid)

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

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

#define _CMN_EVENT_DVM(_model, _name, _event, _occup, _fsel)
#define CMN_EVENT_DTC(_name)
#define CMN_EVENT_HNF(_model, _name, _event)
#define CMN_EVENT_HNI(_name, _event)
#define CMN_EVENT_HNP(_name, _event)
#define __CMN_EVENT_XP(_name, _event)
#define CMN_EVENT_SBSX(_model, _name, _event)
#define CMN_EVENT_RNID(_model, _name, _event)
#define CMN_EVENT_MTSX(_name, _event)
#define CMN_EVENT_CXRA(_model, _name, _event)
#define CMN_EVENT_CXHA(_name, _event)
#define CMN_EVENT_CCRA(_name, _event)
#define CMN_EVENT_CCHA(_name, _event)
#define CMN_EVENT_CCLA(_name, _event)
#define CMN_EVENT_CCLA_RNI(_name, _event)
#define CMN_EVENT_HNS(_name, _event)

#define CMN_EVENT_DVM(_model, _name, _event)
#define CMN_EVENT_DVM_OCC(_model, _name, _event)

#define CMN_EVENT_HN_OCC(_model, _name, _type, _event)
#define CMN_EVENT_HN_CLS(_model, _name, _type, _event)
#define CMN_EVENT_HN_SNT(_model, _name, _type, _event)

#define CMN_EVENT_HNF_OCC(_model, _name, _event)
#define CMN_EVENT_HNF_CLS(_model, _name, _event)
#define CMN_EVENT_HNF_SNT(_model, _name, _event)

#define CMN_EVENT_HNS_OCC(_name, _event)
#define CMN_EVENT_HNS_CLS( _name, _event)
#define CMN_EVENT_HNS_SNT(_name, _event)
#define CMN_EVENT_HNS_HBT(_name, _event)
#define CMN_EVENT_HNS_SNH(_name, _event)

#define _CMN_EVENT_XP_MESH(_name, _event)

#define _CMN_EVENT_XP_PORT(_name, _event)

#define _CMN_EVENT_XP(_name, _event)

/* Good thing there are only 3 fundamental XP events... */
#define CMN_EVENT_XP(_name, _event)

#define CMN_EVENT_XP_DAT(_name, _event)


static struct attribute *arm_cmn_event_attrs[] =;

static const struct attribute_group arm_cmn_event_attrs_group =;

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

#define _CMN_FORMAT_ATTR(_name, _cfg, _fld)
#define CMN_FORMAT_ATTR(_name, _fld)

static struct attribute *arm_cmn_format_attrs[] =;

static const struct attribute_group arm_cmn_format_attrs_group =;

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

static struct device_attribute arm_cmn_cpumask_attr =;

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

static struct device_attribute arm_cmn_identifier_attr =;

static struct attribute *arm_cmn_other_attrs[] =;

static const struct attribute_group arm_cmn_other_attrs_group =;

static const struct attribute_group *arm_cmn_attr_groups[] =;

static int arm_cmn_find_free_wp_idx(struct arm_cmn_dtm *dtm,
				    struct perf_event *event)
{}

static int arm_cmn_get_assigned_wp_idx(struct perf_event *event,
				       struct arm_cmn_hw_event *hw,
				       unsigned int pos)
{}

static void arm_cmn_claim_wp_idx(struct arm_cmn_dtm *dtm,
				 struct perf_event *event,
				 unsigned int dtc, int wp_idx,
				 unsigned int pos)
{}

static u32 arm_cmn_wp_config(struct perf_event *event, int wp_idx)
{}

static void arm_cmn_set_state(struct arm_cmn *cmn, u32 state)
{}

static void arm_cmn_clear_state(struct arm_cmn *cmn, u32 state)
{}

static void arm_cmn_pmu_enable(struct pmu *pmu)
{}

static void arm_cmn_pmu_disable(struct pmu *pmu)
{}

static u64 arm_cmn_read_dtm(struct arm_cmn *cmn, struct arm_cmn_hw_event *hw,
			    bool snapshot)
{}

static u64 arm_cmn_read_cc(struct arm_cmn_dtc *dtc)
{}

static u32 arm_cmn_read_counter(struct arm_cmn_dtc *dtc, int idx)
{}

static void arm_cmn_init_counter(struct perf_event *event)
{}

static void arm_cmn_event_read(struct perf_event *event)
{}

static int arm_cmn_set_event_sel_hi(struct arm_cmn_node *dn,
				    enum cmn_filter_select fsel, u8 occupid)
{}

static void arm_cmn_set_event_sel_lo(struct arm_cmn_node *dn, int dtm_idx,
				     int eventid, bool wide_sel)
{}

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

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

struct arm_cmn_val {};

static int arm_cmn_val_find_free_wp_config(struct perf_event *event,
					  struct arm_cmn_val *val, int dtm)
{}

static void arm_cmn_val_add_event(struct arm_cmn *cmn, struct arm_cmn_val *val,
				  struct perf_event *event)
{}

static int arm_cmn_validate_group(struct arm_cmn *cmn, struct perf_event *event)
{}

static enum cmn_filter_select arm_cmn_filter_sel(const struct arm_cmn *cmn,
						 enum cmn_node_type type,
						 unsigned int eventid)
{}


static int arm_cmn_event_init(struct perf_event *event)
{}

static void arm_cmn_event_clear(struct arm_cmn *cmn, struct perf_event *event,
				int i)
{}

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

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

/*
 * We stop the PMU for both add and read, to avoid skew across DTM counters.
 * In theory we could use snapshots to read without stopping, but then it
 * becomes a lot trickier to deal with overlow and racing against interrupts,
 * plus it seems they don't work properly on some hardware anyway :(
 */
static void arm_cmn_start_txn(struct pmu *pmu, unsigned int flags)
{}

static void arm_cmn_end_txn(struct pmu *pmu)
{}

static int arm_cmn_commit_txn(struct pmu *pmu)
{}

static void arm_cmn_migrate(struct arm_cmn *cmn, unsigned int cpu)
{}

static int arm_cmn_pmu_online_cpu(unsigned int cpu, struct hlist_node *cpuhp_node)
{}

static int arm_cmn_pmu_offline_cpu(unsigned int cpu, struct hlist_node *cpuhp_node)
{}

static irqreturn_t arm_cmn_handle_irq(int irq, void *dev_id)
{}

/* We can reasonably accommodate DTCs of the same CMN sharing IRQs */
static int arm_cmn_init_irqs(struct arm_cmn *cmn)
{}

static void arm_cmn_init_dtm(struct arm_cmn_dtm *dtm, struct arm_cmn_node *xp, int idx)
{}

static int arm_cmn_init_dtc(struct arm_cmn *cmn, struct arm_cmn_node *dn, int idx)
{}

static int arm_cmn_node_cmp(const void *a, const void *b)
{}

static int arm_cmn_init_dtcs(struct arm_cmn *cmn)
{}

static unsigned int arm_cmn_dtc_domain(struct arm_cmn *cmn, void __iomem *xp_region)
{}

static void arm_cmn_init_node_info(struct arm_cmn *cmn, u32 offset, struct arm_cmn_node *node)
{}

static enum cmn_node_type arm_cmn_subtype(enum cmn_node_type type)
{}

static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset)
{}

static int arm_cmn600_acpi_probe(struct platform_device *pdev, struct arm_cmn *cmn)
{}

static int arm_cmn600_of_probe(struct device_node *np)
{}

static int arm_cmn_probe(struct platform_device *pdev)
{}

static void arm_cmn_remove(struct platform_device *pdev)
{}

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

#ifdef CONFIG_ACPI
static const struct acpi_device_id arm_cmn_acpi_match[] =;
MODULE_DEVICE_TABLE(acpi, arm_cmn_acpi_match);
#endif

static struct platform_driver arm_cmn_driver =;

static int __init arm_cmn_init(void)
{}

static void __exit arm_cmn_exit(void)
{}

module_init();
module_exit(arm_cmn_exit);

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