| /* SPDX-License-Identifier: GPL-2.0 |
| * |
| * ARM CoreSight Architecture PMU driver. |
| * Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. |
| * |
| */ |
| |
| #ifndef __ARM_CSPMU_H__ |
| #define __ARM_CSPMU_H__ |
| |
| #include <linux/bitfield.h> |
| #include <linux/cpumask.h> |
| #include <linux/device.h> |
| #include <linux/kernel.h> |
| #include <linux/module.h> |
| #include <linux/perf_event.h> |
| #include <linux/platform_device.h> |
| #include <linux/types.h> |
| |
| #define to_arm_cspmu(p) (container_of(p, struct arm_cspmu, pmu)) |
| |
| #define ARM_CSPMU_EXT_ATTR(_name, _func, _config) \ |
| (&((struct dev_ext_attribute[]){ \ |
| { \ |
| .attr = __ATTR(_name, 0444, _func, NULL), \ |
| .var = (void *)_config \ |
| } \ |
| })[0].attr.attr) |
| |
| #define ARM_CSPMU_FORMAT_ATTR(_name, _config) \ |
| ARM_CSPMU_EXT_ATTR(_name, arm_cspmu_sysfs_format_show, (char *)_config) |
| |
| #define ARM_CSPMU_EVENT_ATTR(_name, _config) \ |
| PMU_EVENT_ATTR_ID(_name, arm_cspmu_sysfs_event_show, _config) |
| |
| |
| /* Default event id mask */ |
| #define ARM_CSPMU_EVENT_MASK GENMASK_ULL(63, 0) |
| |
| /* Default filter value mask */ |
| #define ARM_CSPMU_FILTER_MASK GENMASK_ULL(63, 0) |
| |
| /* Default event format */ |
| #define ARM_CSPMU_FORMAT_EVENT_ATTR \ |
| ARM_CSPMU_FORMAT_ATTR(event, "config:0-32") |
| |
| /* Default filter format */ |
| #define ARM_CSPMU_FORMAT_FILTER_ATTR \ |
| ARM_CSPMU_FORMAT_ATTR(filter, "config1:0-31") |
| |
| /* |
| * This is the default event number for cycle count, if supported, since the |
| * ARM Coresight PMU specification does not define a standard event code |
| * for cycle count. |
| */ |
| #define ARM_CSPMU_EVT_CYCLES_DEFAULT (0x1ULL << 32) |
| |
| /* |
| * The ARM Coresight PMU supports up to 256 event counters. |
| * If the counters are larger-than 32-bits, then the PMU includes at |
| * most 128 counters. |
| */ |
| #define ARM_CSPMU_MAX_HW_CNTRS 256 |
| |
| /* The cycle counter, if implemented, is located at counter[31]. */ |
| #define ARM_CSPMU_CYCLE_CNTR_IDX 31 |
| |
| /* PMIIDR register field */ |
| #define ARM_CSPMU_PMIIDR_IMPLEMENTER GENMASK(11, 0) |
| #define ARM_CSPMU_PMIIDR_PRODUCTID GENMASK(31, 20) |
| |
| /* JEDEC-assigned JEP106 identification code */ |
| #define ARM_CSPMU_IMPL_ID_NVIDIA 0x36B |
| #define ARM_CSPMU_IMPL_ID_AMPERE 0xA16 |
| |
| struct arm_cspmu; |
| |
| /* This tracks the events assigned to each counter in the PMU. */ |
| struct arm_cspmu_hw_events { |
| /* The events that are active on the PMU for a given logical index. */ |
| struct perf_event **events; |
| |
| /* |
| * Each bit indicates a logical counter is being used (or not) for an |
| * event. If cycle counter is supported and there is a gap between |
| * regular and cycle counter, the last logical counter is mapped to |
| * cycle counter. Otherwise, logical and physical have 1-to-1 mapping. |
| */ |
| DECLARE_BITMAP(used_ctrs, ARM_CSPMU_MAX_HW_CNTRS); |
| }; |
| |
| /* Contains ops to query vendor/implementer specific attribute. */ |
| struct arm_cspmu_impl_ops { |
| /* Get event attributes */ |
| struct attribute **(*get_event_attrs)(const struct arm_cspmu *cspmu); |
| /* Get format attributes */ |
| struct attribute **(*get_format_attrs)(const struct arm_cspmu *cspmu); |
| /* Get string identifier */ |
| const char *(*get_identifier)(const struct arm_cspmu *cspmu); |
| /* Get PMU name to register to core perf */ |
| const char *(*get_name)(const struct arm_cspmu *cspmu); |
| /* Check if the event corresponds to cycle count event */ |
| bool (*is_cycle_counter_event)(const struct perf_event *event); |
| /* Decode event type/id from configs */ |
| u32 (*event_type)(const struct perf_event *event); |
| /* Decode filter value from configs */ |
| u32 (*event_filter)(const struct perf_event *event); |
| /* Set event filter */ |
| void (*set_ev_filter)(struct arm_cspmu *cspmu, |
| struct hw_perf_event *hwc, u32 filter); |
| /* Implementation specific event validation */ |
| int (*validate_event)(struct arm_cspmu *cspmu, |
| struct perf_event *event); |
| /* Hide/show unsupported events */ |
| umode_t (*event_attr_is_visible)(struct kobject *kobj, |
| struct attribute *attr, int unused); |
| }; |
| |
| /* Vendor/implementer registration parameter. */ |
| struct arm_cspmu_impl_match { |
| /* Backend module. */ |
| struct module *module; |
| const char *module_name; |
| /* PMIIDR value/mask. */ |
| u32 pmiidr_val; |
| u32 pmiidr_mask; |
| /* Callback to vendor backend to init arm_cspmu_impl::ops. */ |
| int (*impl_init_ops)(struct arm_cspmu *cspmu); |
| }; |
| |
| /* Vendor/implementer descriptor. */ |
| struct arm_cspmu_impl { |
| u32 pmiidr; |
| struct module *module; |
| struct arm_cspmu_impl_match *match; |
| struct arm_cspmu_impl_ops ops; |
| void *ctx; |
| }; |
| |
| /* Coresight PMU descriptor. */ |
| struct arm_cspmu { |
| struct pmu pmu; |
| struct device *dev; |
| const char *name; |
| const char *identifier; |
| void __iomem *base0; |
| void __iomem *base1; |
| cpumask_t associated_cpus; |
| cpumask_t active_cpu; |
| struct hlist_node cpuhp_node; |
| int irq; |
| |
| bool has_atomic_dword; |
| u32 pmcfgr; |
| u32 num_logical_ctrs; |
| u32 num_set_clr_reg; |
| int cycle_counter_logical_idx; |
| |
| struct arm_cspmu_hw_events hw_events; |
| const struct attribute_group *attr_groups[5]; |
| |
| struct arm_cspmu_impl impl; |
| }; |
| |
| /* Default function to show event attribute in sysfs. */ |
| ssize_t arm_cspmu_sysfs_event_show(struct device *dev, |
| struct device_attribute *attr, |
| char *buf); |
| |
| /* Default function to show format attribute in sysfs. */ |
| ssize_t arm_cspmu_sysfs_format_show(struct device *dev, |
| struct device_attribute *attr, |
| char *buf); |
| |
| /* Register vendor backend. */ |
| int arm_cspmu_impl_register(const struct arm_cspmu_impl_match *impl_match); |
| |
| /* Unregister vendor backend. */ |
| void arm_cspmu_impl_unregister(const struct arm_cspmu_impl_match *impl_match); |
| |
| #endif /* __ARM_CSPMU_H__ */ |