brintos

brintos / linux-shallow public Read only

0
0
Text · 8.0 KiB · f72f568 Raw
274 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Ampere SoC PMU (Performance Monitor Unit)4 *5 * Copyright (c) 2023, Ampere Computing LLC6 */7#include <linux/io.h>8#include <linux/module.h>9#include <linux/topology.h>10 11#include "arm_cspmu.h"12 13#define PMAUXR0		0xD8014#define PMAUXR1		0xD8415#define PMAUXR2		0xD8816#define PMAUXR3		0xD8C17 18#define to_ampere_cspmu_ctx(cspmu)	((struct ampere_cspmu_ctx *)(cspmu->impl.ctx))19 20struct ampere_cspmu_ctx {21	const char *name;22	struct attribute **event_attr;23	struct attribute **format_attr;24};25 26static DEFINE_IDA(mcu_pmu_ida);27 28#define SOC_PMU_EVENT_ATTR_EXTRACTOR(_name, _config, _start, _end)        \29	static inline u32 get_##_name(const struct perf_event *event)     \30	{                                                                 \31		return FIELD_GET(GENMASK_ULL(_end, _start),               \32				 event->attr._config);                    \33	}                                                                 \34 35SOC_PMU_EVENT_ATTR_EXTRACTOR(event, config, 0, 8);36SOC_PMU_EVENT_ATTR_EXTRACTOR(threshold, config1, 0, 7);37SOC_PMU_EVENT_ATTR_EXTRACTOR(rank, config1, 8, 23);38SOC_PMU_EVENT_ATTR_EXTRACTOR(bank, config1, 24, 55);39 40static struct attribute *ampereone_mcu_pmu_event_attrs[] = {41	ARM_CSPMU_EVENT_ATTR(cycle_count,		0x00),42	ARM_CSPMU_EVENT_ATTR(act_sent,			0x01),43	ARM_CSPMU_EVENT_ATTR(pre_sent,			0x02),44	ARM_CSPMU_EVENT_ATTR(rd_sent,			0x03),45	ARM_CSPMU_EVENT_ATTR(rda_sent,			0x04),46	ARM_CSPMU_EVENT_ATTR(wr_sent,			0x05),47	ARM_CSPMU_EVENT_ATTR(wra_sent,			0x06),48	ARM_CSPMU_EVENT_ATTR(pd_entry_vld,		0x07),49	ARM_CSPMU_EVENT_ATTR(sref_entry_vld,		0x08),50	ARM_CSPMU_EVENT_ATTR(prea_sent,			0x09),51	ARM_CSPMU_EVENT_ATTR(pre_sb_sent,		0x0a),52	ARM_CSPMU_EVENT_ATTR(ref_sent,			0x0b),53	ARM_CSPMU_EVENT_ATTR(rfm_sent,			0x0c),54	ARM_CSPMU_EVENT_ATTR(ref_sb_sent,		0x0d),55	ARM_CSPMU_EVENT_ATTR(rfm_sb_sent,		0x0e),56	ARM_CSPMU_EVENT_ATTR(rd_rda_sent,		0x0f),57	ARM_CSPMU_EVENT_ATTR(wr_wra_sent,		0x10),58	ARM_CSPMU_EVENT_ATTR(raw_hazard,		0x11),59	ARM_CSPMU_EVENT_ATTR(war_hazard,		0x12),60	ARM_CSPMU_EVENT_ATTR(waw_hazard,		0x13),61	ARM_CSPMU_EVENT_ATTR(rar_hazard,		0x14),62	ARM_CSPMU_EVENT_ATTR(raw_war_waw_hazard,	0x15),63	ARM_CSPMU_EVENT_ATTR(hprd_lprd_wr_req_vld,	0x16),64	ARM_CSPMU_EVENT_ATTR(lprd_req_vld,		0x17),65	ARM_CSPMU_EVENT_ATTR(hprd_req_vld,		0x18),66	ARM_CSPMU_EVENT_ATTR(hprd_lprd_req_vld,		0x19),67	ARM_CSPMU_EVENT_ATTR(prefetch_tgt,		0x1a),68	ARM_CSPMU_EVENT_ATTR(wr_req_vld,		0x1b),69	ARM_CSPMU_EVENT_ATTR(partial_wr_req_vld,	0x1c),70	ARM_CSPMU_EVENT_ATTR(rd_retry,			0x1d),71	ARM_CSPMU_EVENT_ATTR(wr_retry,			0x1e),72	ARM_CSPMU_EVENT_ATTR(retry_gnt,			0x1f),73	ARM_CSPMU_EVENT_ATTR(rank_change,		0x20),74	ARM_CSPMU_EVENT_ATTR(dir_change,		0x21),75	ARM_CSPMU_EVENT_ATTR(rank_dir_change,		0x22),76	ARM_CSPMU_EVENT_ATTR(rank_active,		0x23),77	ARM_CSPMU_EVENT_ATTR(rank_idle,			0x24),78	ARM_CSPMU_EVENT_ATTR(rank_pd,			0x25),79	ARM_CSPMU_EVENT_ATTR(rank_sref,			0x26),80	ARM_CSPMU_EVENT_ATTR(queue_fill_gt_thresh,	0x27),81	ARM_CSPMU_EVENT_ATTR(queue_rds_gt_thresh,	0x28),82	ARM_CSPMU_EVENT_ATTR(queue_wrs_gt_thresh,	0x29),83	ARM_CSPMU_EVENT_ATTR(phy_updt_complt,		0x2a),84	ARM_CSPMU_EVENT_ATTR(tz_fail,			0x2b),85	ARM_CSPMU_EVENT_ATTR(dram_errc,			0x2c),86	ARM_CSPMU_EVENT_ATTR(dram_errd,			0x2d),87	ARM_CSPMU_EVENT_ATTR(read_data_return,		0x32),88	ARM_CSPMU_EVENT_ATTR(chi_wr_data_delta,		0x33),89	ARM_CSPMU_EVENT_ATTR(zq_start,			0x34),90	ARM_CSPMU_EVENT_ATTR(zq_latch,			0x35),91	ARM_CSPMU_EVENT_ATTR(wr_fifo_full,		0x36),92	ARM_CSPMU_EVENT_ATTR(info_fifo_full,		0x37),93	ARM_CSPMU_EVENT_ATTR(cmd_fifo_full,		0x38),94	ARM_CSPMU_EVENT_ATTR(dfi_nop,			0x39),95	ARM_CSPMU_EVENT_ATTR(dfi_cmd,			0x3a),96	ARM_CSPMU_EVENT_ATTR(rd_run_len,		0x3b),97	ARM_CSPMU_EVENT_ATTR(wr_run_len,		0x3c),98 99	ARM_CSPMU_EVENT_ATTR(cycles, ARM_CSPMU_EVT_CYCLES_DEFAULT),100	NULL,101};102 103static struct attribute *ampereone_mcu_format_attrs[] = {104	ARM_CSPMU_FORMAT_EVENT_ATTR,105	ARM_CSPMU_FORMAT_ATTR(threshold, "config1:0-7"),106	ARM_CSPMU_FORMAT_ATTR(rank, "config1:8-23"),107	ARM_CSPMU_FORMAT_ATTR(bank, "config1:24-55"),108	NULL,109};110 111static struct attribute **112ampere_cspmu_get_event_attrs(const struct arm_cspmu *cspmu)113{114	const struct ampere_cspmu_ctx *ctx = to_ampere_cspmu_ctx(cspmu);115 116	return ctx->event_attr;117}118 119static struct attribute **120ampere_cspmu_get_format_attrs(const struct arm_cspmu *cspmu)121{122	const struct ampere_cspmu_ctx *ctx = to_ampere_cspmu_ctx(cspmu);123 124	return ctx->format_attr;125}126 127static const char *128ampere_cspmu_get_name(const struct arm_cspmu *cspmu)129{130	const struct ampere_cspmu_ctx *ctx = to_ampere_cspmu_ctx(cspmu);131 132	return ctx->name;133}134 135static u32 ampere_cspmu_event_filter(const struct perf_event *event)136{137	/*138	 * PMEVFILTR or PMCCFILTR aren't used in Ampere SoC PMU but are marked139	 * as RES0. Make sure, PMCCFILTR is written zero.140	 */141	return 0;142}143 144static void ampere_cspmu_set_ev_filter(struct arm_cspmu *cspmu,145				       struct hw_perf_event *hwc,146				       u32 filter)147{148	struct perf_event *event;149	unsigned int idx;150	u32 threshold, rank, bank;151 152	/*153	 * At this point, all the events have the same filter settings.154	 * Therefore, take the first event and use its configuration.155	 */156	idx = find_first_bit(cspmu->hw_events.used_ctrs,157			     cspmu->cycle_counter_logical_idx);158 159	event = cspmu->hw_events.events[idx];160 161	threshold	= get_threshold(event);162	rank		= get_rank(event);163	bank		= get_bank(event);164 165	writel(threshold, cspmu->base0 + PMAUXR0);166	writel(rank, cspmu->base0 + PMAUXR1);167	writel(bank, cspmu->base0 + PMAUXR2);168}169 170static int ampere_cspmu_validate_configs(struct perf_event *event,171					 struct perf_event *event2)172{173	if (get_threshold(event) != get_threshold(event2) ||174	    get_rank(event) != get_rank(event2) ||175	    get_bank(event) != get_bank(event2))176		return -EINVAL;177 178	return 0;179}180 181static int ampere_cspmu_validate_event(struct arm_cspmu *cspmu,182				       struct perf_event *new)183{184	struct perf_event *curr, *leader = new->group_leader;185	unsigned int idx;186	int ret;187 188	ret = ampere_cspmu_validate_configs(new, leader);189	if (ret)190		return ret;191 192	/* We compare the global filter settings to the existing events */193	idx = find_first_bit(cspmu->hw_events.used_ctrs,194			     cspmu->cycle_counter_logical_idx);195 196	/* This is the first event, thus any configuration is fine */197	if (idx == cspmu->cycle_counter_logical_idx)198		return 0;199 200	curr = cspmu->hw_events.events[idx];201 202	return ampere_cspmu_validate_configs(curr, new);203}204 205static char *ampere_cspmu_format_name(const struct arm_cspmu *cspmu,206				      const char *name_pattern)207{208	struct device *dev = cspmu->dev;209	int id;210 211	id = ida_alloc(&mcu_pmu_ida, GFP_KERNEL);212	if (id < 0)213		return ERR_PTR(id);214 215	return devm_kasprintf(dev, GFP_KERNEL, name_pattern, id);216}217 218static int ampere_cspmu_init_ops(struct arm_cspmu *cspmu)219{220	struct device *dev = cspmu->dev;221	struct ampere_cspmu_ctx *ctx;222	struct arm_cspmu_impl_ops *impl_ops = &cspmu->impl.ops;223 224	ctx = devm_kzalloc(dev, sizeof(struct ampere_cspmu_ctx), GFP_KERNEL);225	if (!ctx)226		return -ENOMEM;227 228	ctx->event_attr	= ampereone_mcu_pmu_event_attrs;229	ctx->format_attr = ampereone_mcu_format_attrs;230	ctx->name = ampere_cspmu_format_name(cspmu, "ampere_mcu_pmu_%d");231	if (IS_ERR_OR_NULL(ctx->name))232		return ctx->name ? PTR_ERR(ctx->name) : -ENOMEM;233 234	cspmu->impl.ctx = ctx;235 236	impl_ops->event_filter		= ampere_cspmu_event_filter;237	impl_ops->set_ev_filter		= ampere_cspmu_set_ev_filter;238	impl_ops->validate_event	= ampere_cspmu_validate_event;239	impl_ops->get_name		= ampere_cspmu_get_name;240	impl_ops->get_event_attrs	= ampere_cspmu_get_event_attrs;241	impl_ops->get_format_attrs	= ampere_cspmu_get_format_attrs;242 243	return 0;244}245 246/* Match all Ampere Coresight PMU devices */247static const struct arm_cspmu_impl_match ampere_cspmu_param = {248	.pmiidr_val	= ARM_CSPMU_IMPL_ID_AMPERE,249	.module		= THIS_MODULE,250	.impl_init_ops	= ampere_cspmu_init_ops251};252 253static int __init ampere_cspmu_init(void)254{255	int ret;256 257	ret = arm_cspmu_impl_register(&ampere_cspmu_param);258	if (ret)259		pr_err("ampere_cspmu backend registration error: %d\n", ret);260 261	return ret;262}263 264static void __exit ampere_cspmu_exit(void)265{266	arm_cspmu_impl_unregister(&ampere_cspmu_param);267}268 269module_init(ampere_cspmu_init);270module_exit(ampere_cspmu_exit);271 272MODULE_DESCRIPTION("Ampere SoC Performance Monitor Driver");273MODULE_LICENSE("GPL");274