Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,29 @@
# SPDX-License-Identifier: GPL-2.0
#
# Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
config ARM_CORESIGHT_PMU_ARCH_SYSTEM_PMU
tristate "ARM Coresight Architecture PMU"
depends on ARM64 || COMPILE_TEST
help
Provides support for performance monitoring unit (PMU) devices
based on ARM CoreSight PMU architecture. Note that this PMU
architecture does not have relationship with the ARM CoreSight
Self-Hosted Tracing.
config NVIDIA_CORESIGHT_PMU_ARCH_SYSTEM_PMU
tristate "NVIDIA Coresight Architecture PMU"
depends on ARM_CORESIGHT_PMU_ARCH_SYSTEM_PMU
help
Provides NVIDIA specific attributes for performance monitoring unit
(PMU) devices based on ARM CoreSight PMU architecture.
config AMPERE_CORESIGHT_PMU_ARCH_SYSTEM_PMU
tristate "Ampere Coresight Architecture PMU"
depends on ARM_CORESIGHT_PMU_ARCH_SYSTEM_PMU
help
Provides Ampere specific attributes for performance monitoring unit
(PMU) devices based on ARM CoreSight PMU architecture.
In the first phase, the driver enables support on MCU PMU used in
AmpereOne SoC family.
@@ -0,0 +1,10 @@
# Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_ARM_CORESIGHT_PMU_ARCH_SYSTEM_PMU) += arm_cspmu_module.o
arm_cspmu_module-y := arm_cspmu.o
obj-$(CONFIG_NVIDIA_CORESIGHT_PMU_ARCH_SYSTEM_PMU) += nvidia_cspmu.o
obj-$(CONFIG_AMPERE_CORESIGHT_PMU_ARCH_SYSTEM_PMU) += ampere_cspmu.o
@@ -0,0 +1,261 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Ampere SoC PMU (Performance Monitor Unit)
*
* Copyright (c) 2023, Ampere Computing LLC
*/
#include <linux/io.h>
#include <linux/module.h>
#include <linux/topology.h>
#include "arm_cspmu.h"
#define PMAUXR0 PMIMPDEF
#define PMAUXR1 (PMIMPDEF + 0x4)
#define PMAUXR2 (PMIMPDEF + 0x8)
#define PMAUXR3 (PMIMPDEF + 0xC)
#define to_ampere_cspmu_ctx(cspmu) ((struct ampere_cspmu_ctx *)(cspmu->impl.ctx))
struct ampere_cspmu_ctx {
const char *name;
struct attribute **event_attr;
struct attribute **format_attr;
};
static DEFINE_IDA(mcu_pmu_ida);
#define SOC_PMU_EVENT_ATTR_EXTRACTOR(_name, _config, _start, _end) \
static inline u32 get_##_name(const struct perf_event *event) \
{ \
return FIELD_GET(GENMASK_ULL(_end, _start), \
event->attr._config); \
} \
SOC_PMU_EVENT_ATTR_EXTRACTOR(event, config, 0, 8);
SOC_PMU_EVENT_ATTR_EXTRACTOR(threshold, config1, 0, 7);
SOC_PMU_EVENT_ATTR_EXTRACTOR(rank, config1, 8, 23);
SOC_PMU_EVENT_ATTR_EXTRACTOR(bank, config1, 24, 55);
static struct attribute *ampereone_mcu_pmu_event_attrs[] = {
ARM_CSPMU_EVENT_ATTR(cycle_count, 0x00),
ARM_CSPMU_EVENT_ATTR(act_sent, 0x01),
ARM_CSPMU_EVENT_ATTR(pre_sent, 0x02),
ARM_CSPMU_EVENT_ATTR(rd_sent, 0x03),
ARM_CSPMU_EVENT_ATTR(rda_sent, 0x04),
ARM_CSPMU_EVENT_ATTR(wr_sent, 0x05),
ARM_CSPMU_EVENT_ATTR(wra_sent, 0x06),
ARM_CSPMU_EVENT_ATTR(pd_entry_vld, 0x07),
ARM_CSPMU_EVENT_ATTR(sref_entry_vld, 0x08),
ARM_CSPMU_EVENT_ATTR(prea_sent, 0x09),
ARM_CSPMU_EVENT_ATTR(pre_sb_sent, 0x0a),
ARM_CSPMU_EVENT_ATTR(ref_sent, 0x0b),
ARM_CSPMU_EVENT_ATTR(rfm_sent, 0x0c),
ARM_CSPMU_EVENT_ATTR(ref_sb_sent, 0x0d),
ARM_CSPMU_EVENT_ATTR(rfm_sb_sent, 0x0e),
ARM_CSPMU_EVENT_ATTR(rd_rda_sent, 0x0f),
ARM_CSPMU_EVENT_ATTR(wr_wra_sent, 0x10),
ARM_CSPMU_EVENT_ATTR(raw_hazard, 0x11),
ARM_CSPMU_EVENT_ATTR(war_hazard, 0x12),
ARM_CSPMU_EVENT_ATTR(waw_hazard, 0x13),
ARM_CSPMU_EVENT_ATTR(rar_hazard, 0x14),
ARM_CSPMU_EVENT_ATTR(raw_war_waw_hazard, 0x15),
ARM_CSPMU_EVENT_ATTR(hprd_lprd_wr_req_vld, 0x16),
ARM_CSPMU_EVENT_ATTR(lprd_req_vld, 0x17),
ARM_CSPMU_EVENT_ATTR(hprd_req_vld, 0x18),
ARM_CSPMU_EVENT_ATTR(hprd_lprd_req_vld, 0x19),
ARM_CSPMU_EVENT_ATTR(prefetch_tgt, 0x1a),
ARM_CSPMU_EVENT_ATTR(wr_req_vld, 0x1b),
ARM_CSPMU_EVENT_ATTR(partial_wr_req_vld, 0x1c),
ARM_CSPMU_EVENT_ATTR(rd_retry, 0x1d),
ARM_CSPMU_EVENT_ATTR(wr_retry, 0x1e),
ARM_CSPMU_EVENT_ATTR(retry_gnt, 0x1f),
ARM_CSPMU_EVENT_ATTR(rank_change, 0x20),
ARM_CSPMU_EVENT_ATTR(dir_change, 0x21),
ARM_CSPMU_EVENT_ATTR(rank_dir_change, 0x22),
ARM_CSPMU_EVENT_ATTR(rank_active, 0x23),
ARM_CSPMU_EVENT_ATTR(rank_idle, 0x24),
ARM_CSPMU_EVENT_ATTR(rank_pd, 0x25),
ARM_CSPMU_EVENT_ATTR(rank_sref, 0x26),
ARM_CSPMU_EVENT_ATTR(queue_fill_gt_thresh, 0x27),
ARM_CSPMU_EVENT_ATTR(queue_rds_gt_thresh, 0x28),
ARM_CSPMU_EVENT_ATTR(queue_wrs_gt_thresh, 0x29),
ARM_CSPMU_EVENT_ATTR(phy_updt_complt, 0x2a),
ARM_CSPMU_EVENT_ATTR(tz_fail, 0x2b),
ARM_CSPMU_EVENT_ATTR(dram_errc, 0x2c),
ARM_CSPMU_EVENT_ATTR(dram_errd, 0x2d),
ARM_CSPMU_EVENT_ATTR(read_data_return, 0x32),
ARM_CSPMU_EVENT_ATTR(chi_wr_data_delta, 0x33),
ARM_CSPMU_EVENT_ATTR(zq_start, 0x34),
ARM_CSPMU_EVENT_ATTR(zq_latch, 0x35),
ARM_CSPMU_EVENT_ATTR(wr_fifo_full, 0x36),
ARM_CSPMU_EVENT_ATTR(info_fifo_full, 0x37),
ARM_CSPMU_EVENT_ATTR(cmd_fifo_full, 0x38),
ARM_CSPMU_EVENT_ATTR(dfi_nop, 0x39),
ARM_CSPMU_EVENT_ATTR(dfi_cmd, 0x3a),
ARM_CSPMU_EVENT_ATTR(rd_run_len, 0x3b),
ARM_CSPMU_EVENT_ATTR(wr_run_len, 0x3c),
ARM_CSPMU_EVENT_ATTR(cycles, ARM_CSPMU_EVT_CYCLES_DEFAULT),
NULL,
};
static struct attribute *ampereone_mcu_format_attrs[] = {
ARM_CSPMU_FORMAT_EVENT_ATTR,
ARM_CSPMU_FORMAT_ATTR(threshold, "config1:0-7"),
ARM_CSPMU_FORMAT_ATTR(rank, "config1:8-23"),
ARM_CSPMU_FORMAT_ATTR(bank, "config1:24-55"),
NULL,
};
static struct attribute **
ampere_cspmu_get_event_attrs(const struct arm_cspmu *cspmu)
{
const struct ampere_cspmu_ctx *ctx = to_ampere_cspmu_ctx(cspmu);
return ctx->event_attr;
}
static struct attribute **
ampere_cspmu_get_format_attrs(const struct arm_cspmu *cspmu)
{
const struct ampere_cspmu_ctx *ctx = to_ampere_cspmu_ctx(cspmu);
return ctx->format_attr;
}
static const char *
ampere_cspmu_get_name(const struct arm_cspmu *cspmu)
{
const struct ampere_cspmu_ctx *ctx = to_ampere_cspmu_ctx(cspmu);
return ctx->name;
}
static void ampere_cspmu_set_cc_filter(struct arm_cspmu *cspmu,
const struct perf_event *event)
{
/*
* PMCCFILTR is RES0, so this is just a dummy callback to override
* the default implementation and avoid writing to it.
*/
}
static void ampere_cspmu_set_ev_filter(struct arm_cspmu *cspmu,
const struct perf_event *event)
{
u32 threshold, rank, bank;
threshold = get_threshold(event);
rank = get_rank(event);
bank = get_bank(event);
writel(threshold, cspmu->base0 + PMAUXR0);
writel(rank, cspmu->base0 + PMAUXR1);
writel(bank, cspmu->base0 + PMAUXR2);
}
static int ampere_cspmu_validate_configs(struct perf_event *event,
struct perf_event *event2)
{
if (get_threshold(event) != get_threshold(event2) ||
get_rank(event) != get_rank(event2) ||
get_bank(event) != get_bank(event2))
return -EINVAL;
return 0;
}
static int ampere_cspmu_validate_event(struct arm_cspmu *cspmu,
struct perf_event *new)
{
struct perf_event *curr, *leader = new->group_leader;
unsigned int idx;
int ret;
ret = ampere_cspmu_validate_configs(new, leader);
if (ret)
return ret;
/* We compare the global filter settings to the existing events */
idx = find_first_bit(cspmu->hw_events.used_ctrs,
cspmu->cycle_counter_logical_idx);
/* This is the first event, thus any configuration is fine */
if (idx == cspmu->cycle_counter_logical_idx)
return 0;
curr = cspmu->hw_events.events[idx];
return ampere_cspmu_validate_configs(curr, new);
}
static char *ampere_cspmu_format_name(const struct arm_cspmu *cspmu,
const char *name_pattern)
{
struct device *dev = cspmu->dev;
int id;
id = ida_alloc(&mcu_pmu_ida, GFP_KERNEL);
if (id < 0)
return ERR_PTR(id);
return devm_kasprintf(dev, GFP_KERNEL, name_pattern, id);
}
static int ampere_cspmu_init_ops(struct arm_cspmu *cspmu)
{
struct device *dev = cspmu->dev;
struct ampere_cspmu_ctx *ctx;
struct arm_cspmu_impl_ops *impl_ops = &cspmu->impl.ops;
ctx = devm_kzalloc(dev, sizeof(struct ampere_cspmu_ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
ctx->event_attr = ampereone_mcu_pmu_event_attrs;
ctx->format_attr = ampereone_mcu_format_attrs;
ctx->name = ampere_cspmu_format_name(cspmu, "ampere_mcu_pmu_%d");
if (IS_ERR_OR_NULL(ctx->name))
return ctx->name ? PTR_ERR(ctx->name) : -ENOMEM;
cspmu->impl.ctx = ctx;
impl_ops->set_cc_filter = ampere_cspmu_set_cc_filter;
impl_ops->set_ev_filter = ampere_cspmu_set_ev_filter;
impl_ops->validate_event = ampere_cspmu_validate_event;
impl_ops->get_name = ampere_cspmu_get_name;
impl_ops->get_event_attrs = ampere_cspmu_get_event_attrs;
impl_ops->get_format_attrs = ampere_cspmu_get_format_attrs;
return 0;
}
/* Match all Ampere Coresight PMU devices */
static const struct arm_cspmu_impl_match ampere_cspmu_param = {
.pmiidr_val = ARM_CSPMU_IMPL_ID_AMPERE,
.module = THIS_MODULE,
.impl_init_ops = ampere_cspmu_init_ops
};
static int __init ampere_cspmu_init(void)
{
int ret;
ret = arm_cspmu_impl_register(&ampere_cspmu_param);
if (ret)
pr_err("ampere_cspmu backend registration error: %d\n", ret);
return ret;
}
static void __exit ampere_cspmu_exit(void)
{
arm_cspmu_impl_unregister(&ampere_cspmu_param);
}
module_init(ampere_cspmu_init);
module_exit(ampere_cspmu_exit);
MODULE_DESCRIPTION("Ampere SoC Performance Monitor Driver");
MODULE_LICENSE("GPL");
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,273 @@
/* SPDX-License-Identifier: GPL-2.0
*
* ARM CoreSight Architecture PMU driver.
* Copyright (c) 2022-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*
*/
#ifndef __ARM_CSPMU_H__
#define __ARM_CSPMU_H__
#include <linux/acpi.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, device_show_string, _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")
#define ARM_CSPMU_FORMAT_FILTER2_ATTR \
ARM_CSPMU_FORMAT_ATTR(filter2, "config2: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
/*
* CoreSight PMU Arch register offsets.
*/
#define PMEVCNTR_LO 0x0
#define PMEVCNTR_HI 0x4
#define PMEVTYPER 0x400
#define PMCCFILTR 0x47C
#define PMEVFILT2R 0x800
#define PMEVFILTR 0xA00
#define PMCNTENSET 0xC00
#define PMCNTENCLR 0xC20
#define PMINTENSET 0xC40
#define PMINTENCLR 0xC60
#define PMOVSCLR 0xC80
#define PMOVSSET 0xCC0
#define PMIMPDEF 0xD80
#define PMCFGR 0xE00
#define PMCR 0xE04
#define PMIIDR 0xE08
#define PMPIDR0 0xFE0
#define PMPIDR1 0xFE4
#define PMPIDR2 0xFE8
#define PMPIDR3 0xFEC
#define PMPIDR4 0xFD0
/* PMCFGR register field */
#define PMCFGR_NCG GENMASK(31, 28)
#define PMCFGR_HDBG BIT(24)
#define PMCFGR_TRO BIT(23)
#define PMCFGR_SS BIT(22)
#define PMCFGR_FZO BIT(21)
#define PMCFGR_MSI BIT(20)
#define PMCFGR_UEN BIT(19)
#define PMCFGR_NA BIT(17)
#define PMCFGR_EX BIT(16)
#define PMCFGR_CCD BIT(15)
#define PMCFGR_CC BIT(14)
#define PMCFGR_SIZE GENMASK(13, 8)
#define PMCFGR_N GENMASK(7, 0)
/* PMCR register field */
#define PMCR_TRO BIT(11)
#define PMCR_HDBG BIT(10)
#define PMCR_FZO BIT(9)
#define PMCR_NA BIT(8)
#define PMCR_DP BIT(5)
#define PMCR_X BIT(4)
#define PMCR_D BIT(3)
#define PMCR_C BIT(2)
#define PMCR_P BIT(1)
#define PMCR_E BIT(0)
/* PMIIDR register field */
#define PMIIDR_IMPLEMENTER GENMASK(11, 0)
#define PMIIDR_IMPLEMENTER_DES_0 GENMASK(3, 0)
#define PMIIDR_IMPLEMENTER_DES_1 GENMASK(6, 4)
#define PMIIDR_IMPLEMENTER_DES_2 GENMASK(11, 8)
#define PMIIDR_REVISION GENMASK(15, 12)
#define PMIIDR_VARIANT GENMASK(19, 16)
#define PMIIDR_PRODUCTID GENMASK(31, 20)
#define PMIIDR_PRODUCTID_PART_0 GENMASK(27, 20)
#define PMIIDR_PRODUCTID_PART_1 GENMASK(31, 28)
/* PMPIDR0 register field */
#define PMPIDR0_PART_0 GENMASK(7, 0)
/* PMPIDR1 register field */
#define PMPIDR1_DES_0 GENMASK(7, 4)
#define PMPIDR1_PART_1 GENMASK(3, 0)
/* PMPIDR2 register field */
#define PMPIDR2_REVISION GENMASK(7, 4)
#define PMPIDR2_DES_1 GENMASK(2, 0)
/* PMPIDR3 register field */
#define PMPIDR3_REVAND GENMASK(7, 4)
#define PMPIDR3_CMOD GENMASK(3, 0)
/* PMPIDR4 register field */
#define PMPIDR4_SIZE GENMASK(7, 4)
#define PMPIDR4_DES_2 GENMASK(3, 0)
/* 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);
/* Set/reset event filters */
void (*set_cc_filter)(struct arm_cspmu *cspmu,
const struct perf_event *event);
void (*set_ev_filter)(struct arm_cspmu *cspmu,
const struct perf_event *event);
void (*reset_ev_filter)(struct arm_cspmu *cspmu,
const struct perf_event *event);
/* 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);
/* 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);
#if defined(CONFIG_ACPI) && defined(CONFIG_ARM64)
/**
* Get ACPI device associated with the PMU.
* The caller is responsible for calling acpi_dev_put() on the returned device.
*/
struct acpi_device *arm_cspmu_acpi_dev_get(const struct arm_cspmu *cspmu);
#else
static inline struct acpi_device *
arm_cspmu_acpi_dev_get(const struct arm_cspmu *cspmu)
{
return NULL;
}
#endif
#endif /* __ARM_CSPMU_H__ */
File diff suppressed because it is too large Load Diff