xref: /openbsd-src/sys/dev/pci/drm/amd/amdgpu/amdgpu_pmu.c (revision f005ef32267c16bdb134f0e9fa4477dbe07c263a)
1c349dbc7Sjsg /*
2c349dbc7Sjsg  * Copyright 2019 Advanced Micro Devices, Inc.
3c349dbc7Sjsg  *
4c349dbc7Sjsg  * Permission is hereby granted, free of charge, to any person obtaining a
5c349dbc7Sjsg  * copy of this software and associated documentation files (the "Software"),
6c349dbc7Sjsg  * to deal in the Software without restriction, including without limitation
7c349dbc7Sjsg  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8c349dbc7Sjsg  * and/or sell copies of the Software, and to permit persons to whom the
9c349dbc7Sjsg  * Software is furnished to do so, subject to the following conditions:
10c349dbc7Sjsg  *
11c349dbc7Sjsg  * The above copyright notice and this permission notice shall be included in
12c349dbc7Sjsg  * all copies or substantial portions of the Software.
13c349dbc7Sjsg  *
14c349dbc7Sjsg  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15c349dbc7Sjsg  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16c349dbc7Sjsg  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17c349dbc7Sjsg  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18c349dbc7Sjsg  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19c349dbc7Sjsg  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20c349dbc7Sjsg  * OTHER DEALINGS IN THE SOFTWARE.
21c349dbc7Sjsg  *
22c349dbc7Sjsg  */
23c349dbc7Sjsg 
24c349dbc7Sjsg #include <linux/perf_event.h>
25c349dbc7Sjsg #include <linux/init.h>
26c349dbc7Sjsg #include "amdgpu.h"
27c349dbc7Sjsg #include "amdgpu_pmu.h"
28c349dbc7Sjsg 
29c349dbc7Sjsg #define PMU_NAME_SIZE 32
305ca02815Sjsg #define NUM_FORMATS_AMDGPU_PMU		4
315ca02815Sjsg #define NUM_FORMATS_DF_VEGA20		3
325ca02815Sjsg #define NUM_EVENTS_DF_VEGA20		8
335ca02815Sjsg #define NUM_EVENT_TYPES_VEGA20		1
345ca02815Sjsg #define NUM_EVENTS_VEGA20_XGMI		2
355ca02815Sjsg #define NUM_EVENTS_VEGA20_MAX		NUM_EVENTS_VEGA20_XGMI
365ca02815Sjsg #define NUM_EVENT_TYPES_ARCTURUS	1
375ca02815Sjsg #define NUM_EVENTS_ARCTURUS_XGMI	6
385ca02815Sjsg #define NUM_EVENTS_ARCTURUS_MAX		NUM_EVENTS_ARCTURUS_XGMI
395ca02815Sjsg 
405ca02815Sjsg struct amdgpu_pmu_event_attribute {
415ca02815Sjsg 	struct device_attribute attr;
425ca02815Sjsg 	const char *event_str;
435ca02815Sjsg 	unsigned int type;
445ca02815Sjsg };
45c349dbc7Sjsg 
46c349dbc7Sjsg /* record to keep track of pmu entry per pmu type per device */
47c349dbc7Sjsg struct amdgpu_pmu_entry {
48c349dbc7Sjsg 	struct list_head entry;
49c349dbc7Sjsg 	struct amdgpu_device *adev;
50c349dbc7Sjsg 	struct pmu pmu;
51c349dbc7Sjsg 	unsigned int pmu_perf_type;
525ca02815Sjsg 	char *pmu_type_name;
535ca02815Sjsg 	char *pmu_file_prefix;
545ca02815Sjsg 	struct attribute_group fmt_attr_group;
555ca02815Sjsg 	struct amdgpu_pmu_event_attribute *fmt_attr;
565ca02815Sjsg 	struct attribute_group evt_attr_group;
575ca02815Sjsg 	struct amdgpu_pmu_event_attribute *evt_attr;
58c349dbc7Sjsg };
59c349dbc7Sjsg 
amdgpu_pmu_event_show(struct device * dev,struct device_attribute * attr,char * buf)605ca02815Sjsg static ssize_t amdgpu_pmu_event_show(struct device *dev,
615ca02815Sjsg 				struct device_attribute *attr, char *buf)
625ca02815Sjsg {
635ca02815Sjsg 	struct amdgpu_pmu_event_attribute *amdgpu_pmu_attr;
645ca02815Sjsg 
655ca02815Sjsg 	amdgpu_pmu_attr = container_of(attr, struct amdgpu_pmu_event_attribute,
665ca02815Sjsg 									attr);
675ca02815Sjsg 
685ca02815Sjsg 	if (!amdgpu_pmu_attr->type)
695ca02815Sjsg 		return sprintf(buf, "%s\n", amdgpu_pmu_attr->event_str);
705ca02815Sjsg 
715ca02815Sjsg 	return sprintf(buf, "%s,type=0x%x\n",
725ca02815Sjsg 			amdgpu_pmu_attr->event_str, amdgpu_pmu_attr->type);
735ca02815Sjsg }
745ca02815Sjsg 
75c349dbc7Sjsg static DRM_LIST_HEAD(amdgpu_pmu_list);
76c349dbc7Sjsg 
77c349dbc7Sjsg 
785ca02815Sjsg struct amdgpu_pmu_attr {
795ca02815Sjsg 	const char *name;
805ca02815Sjsg 	const char *config;
815ca02815Sjsg };
825ca02815Sjsg 
835ca02815Sjsg struct amdgpu_pmu_type {
845ca02815Sjsg 	const unsigned int type;
855ca02815Sjsg 	const unsigned int num_of_type;
865ca02815Sjsg };
875ca02815Sjsg 
885ca02815Sjsg struct amdgpu_pmu_config {
895ca02815Sjsg 	struct amdgpu_pmu_attr *formats;
905ca02815Sjsg 	unsigned int num_formats;
915ca02815Sjsg 	struct amdgpu_pmu_attr *events;
925ca02815Sjsg 	unsigned int num_events;
935ca02815Sjsg 	struct amdgpu_pmu_type *types;
945ca02815Sjsg 	unsigned int num_types;
955ca02815Sjsg };
965ca02815Sjsg 
975ca02815Sjsg /*
985ca02815Sjsg  * Events fall under two categories:
995ca02815Sjsg  *  - PMU typed
1005ca02815Sjsg  *    Events in /sys/bus/event_source/devices/amdgpu_<pmu_type>_<dev_num> have
1015ca02815Sjsg  *    performance counter operations handled by one IP <pmu_type>.  Formats and
1025ca02815Sjsg  *    events should be defined by <pmu_type>_<asic_type>_formats and
1035ca02815Sjsg  *    <pmu_type>_<asic_type>_events respectively.
1045ca02815Sjsg  *
1055ca02815Sjsg  *  - Event config typed
1065ca02815Sjsg  *    Events in /sys/bus/event_source/devices/amdgpu_<dev_num> have performance
1075ca02815Sjsg  *    counter operations that can be handled by multiple IPs dictated by their
1085ca02815Sjsg  *    "type" format field.  Formats and events should be defined by
1095ca02815Sjsg  *    amdgpu_pmu_formats and <asic_type>_events respectively.  Format field
1105ca02815Sjsg  *    "type" is generated in amdgpu_pmu_event_show and defined in
1115ca02815Sjsg  *    <asic_type>_event_config_types.
1125ca02815Sjsg  */
1135ca02815Sjsg 
1145ca02815Sjsg static struct amdgpu_pmu_attr amdgpu_pmu_formats[NUM_FORMATS_AMDGPU_PMU] = {
1155ca02815Sjsg 	{ .name = "event", .config = "config:0-7" },
1165ca02815Sjsg 	{ .name = "instance", .config = "config:8-15" },
1175ca02815Sjsg 	{ .name = "umask", .config = "config:16-23"},
1185ca02815Sjsg 	{ .name = "type", .config = "config:56-63"}
1195ca02815Sjsg };
1205ca02815Sjsg 
1215ca02815Sjsg /* Vega20 events */
1225ca02815Sjsg static struct amdgpu_pmu_attr vega20_events[NUM_EVENTS_VEGA20_MAX] = {
1235ca02815Sjsg 	{ .name = "xgmi_link0_data_outbound",
1245ca02815Sjsg 			.config = "event=0x7,instance=0x46,umask=0x2" },
1255ca02815Sjsg 	{ .name = "xgmi_link1_data_outbound",
1265ca02815Sjsg 			.config = "event=0x7,instance=0x47,umask=0x2" }
1275ca02815Sjsg };
1285ca02815Sjsg 
1295ca02815Sjsg static struct amdgpu_pmu_type vega20_types[NUM_EVENT_TYPES_VEGA20] = {
1305ca02815Sjsg 	{ .type = AMDGPU_PMU_EVENT_CONFIG_TYPE_XGMI,
1315ca02815Sjsg 					.num_of_type = NUM_EVENTS_VEGA20_XGMI }
1325ca02815Sjsg };
1335ca02815Sjsg 
1345ca02815Sjsg static struct amdgpu_pmu_config vega20_config = {
1355ca02815Sjsg 	.formats = amdgpu_pmu_formats,
1365ca02815Sjsg 	.num_formats = ARRAY_SIZE(amdgpu_pmu_formats),
1375ca02815Sjsg 	.events = vega20_events,
1385ca02815Sjsg 	.num_events = ARRAY_SIZE(vega20_events),
1395ca02815Sjsg 	.types = vega20_types,
1405ca02815Sjsg 	.num_types = ARRAY_SIZE(vega20_types)
1415ca02815Sjsg };
1425ca02815Sjsg 
1435ca02815Sjsg /* Vega20 data fabric (DF) events */
1445ca02815Sjsg static struct amdgpu_pmu_attr df_vega20_formats[NUM_FORMATS_DF_VEGA20] = {
1455ca02815Sjsg 	{ .name = "event", .config = "config:0-7" },
1465ca02815Sjsg 	{ .name = "instance", .config = "config:8-15" },
1475ca02815Sjsg 	{ .name = "umask", .config = "config:16-23"}
1485ca02815Sjsg };
1495ca02815Sjsg 
1505ca02815Sjsg static struct amdgpu_pmu_attr df_vega20_events[NUM_EVENTS_DF_VEGA20] = {
1515ca02815Sjsg 	{ .name = "cake0_pcsout_txdata",
1525ca02815Sjsg 			.config = "event=0x7,instance=0x46,umask=0x2" },
1535ca02815Sjsg 	{ .name = "cake1_pcsout_txdata",
1545ca02815Sjsg 			.config = "event=0x7,instance=0x47,umask=0x2" },
1555ca02815Sjsg 	{ .name = "cake0_pcsout_txmeta",
1565ca02815Sjsg 			.config = "event=0x7,instance=0x46,umask=0x4" },
1575ca02815Sjsg 	{ .name = "cake1_pcsout_txmeta",
1585ca02815Sjsg 			.config = "event=0x7,instance=0x47,umask=0x4" },
1595ca02815Sjsg 	{ .name = "cake0_ftiinstat_reqalloc",
1605ca02815Sjsg 			.config = "event=0xb,instance=0x46,umask=0x4" },
1615ca02815Sjsg 	{ .name = "cake1_ftiinstat_reqalloc",
1625ca02815Sjsg 			.config = "event=0xb,instance=0x47,umask=0x4" },
1635ca02815Sjsg 	{ .name = "cake0_ftiinstat_rspalloc",
1645ca02815Sjsg 			.config = "event=0xb,instance=0x46,umask=0x8" },
1655ca02815Sjsg 	{ .name = "cake1_ftiinstat_rspalloc",
1665ca02815Sjsg 			.config = "event=0xb,instance=0x47,umask=0x8" }
1675ca02815Sjsg };
1685ca02815Sjsg 
1695ca02815Sjsg static struct amdgpu_pmu_config df_vega20_config = {
1705ca02815Sjsg 	.formats = df_vega20_formats,
1715ca02815Sjsg 	.num_formats = ARRAY_SIZE(df_vega20_formats),
1725ca02815Sjsg 	.events = df_vega20_events,
1735ca02815Sjsg 	.num_events = ARRAY_SIZE(df_vega20_events),
1745ca02815Sjsg 	.types = NULL,
1755ca02815Sjsg 	.num_types = 0
1765ca02815Sjsg };
1775ca02815Sjsg 
1785ca02815Sjsg /* Arcturus events */
1795ca02815Sjsg static struct amdgpu_pmu_attr arcturus_events[NUM_EVENTS_ARCTURUS_MAX] = {
1805ca02815Sjsg 	{ .name = "xgmi_link0_data_outbound",
1815ca02815Sjsg 			.config = "event=0x7,instance=0x4b,umask=0x2" },
1825ca02815Sjsg 	{ .name = "xgmi_link1_data_outbound",
1835ca02815Sjsg 			.config = "event=0x7,instance=0x4c,umask=0x2" },
1845ca02815Sjsg 	{ .name = "xgmi_link2_data_outbound",
1855ca02815Sjsg 			.config = "event=0x7,instance=0x4d,umask=0x2" },
1865ca02815Sjsg 	{ .name = "xgmi_link3_data_outbound",
1875ca02815Sjsg 			.config = "event=0x7,instance=0x4e,umask=0x2" },
1885ca02815Sjsg 	{ .name = "xgmi_link4_data_outbound",
1895ca02815Sjsg 			.config = "event=0x7,instance=0x4f,umask=0x2" },
1905ca02815Sjsg 	{ .name = "xgmi_link5_data_outbound",
1915ca02815Sjsg 			.config = "event=0x7,instance=0x50,umask=0x2" }
1925ca02815Sjsg };
1935ca02815Sjsg 
1945ca02815Sjsg static struct amdgpu_pmu_type arcturus_types[NUM_EVENT_TYPES_ARCTURUS] = {
1955ca02815Sjsg 	{ .type = AMDGPU_PMU_EVENT_CONFIG_TYPE_XGMI,
1965ca02815Sjsg 				.num_of_type = NUM_EVENTS_ARCTURUS_XGMI }
1975ca02815Sjsg };
1985ca02815Sjsg 
1995ca02815Sjsg static struct amdgpu_pmu_config arcturus_config = {
2005ca02815Sjsg 	.formats = amdgpu_pmu_formats,
2015ca02815Sjsg 	.num_formats = ARRAY_SIZE(amdgpu_pmu_formats),
2025ca02815Sjsg 	.events = arcturus_events,
2035ca02815Sjsg 	.num_events = ARRAY_SIZE(arcturus_events),
2045ca02815Sjsg 	.types = arcturus_types,
2055ca02815Sjsg 	.num_types = ARRAY_SIZE(arcturus_types)
2065ca02815Sjsg };
2075ca02815Sjsg 
208c349dbc7Sjsg /* initialize perf counter */
amdgpu_perf_event_init(struct perf_event * event)209c349dbc7Sjsg static int amdgpu_perf_event_init(struct perf_event *event)
210c349dbc7Sjsg {
211c349dbc7Sjsg 	struct hw_perf_event *hwc = &event->hw;
212c349dbc7Sjsg 
213c349dbc7Sjsg 	/* test the event attr type check for PMU enumeration */
214c349dbc7Sjsg 	if (event->attr.type != event->pmu->type)
215c349dbc7Sjsg 		return -ENOENT;
216c349dbc7Sjsg 
217c349dbc7Sjsg 	/* update the hw_perf_event struct with config data */
218c349dbc7Sjsg 	hwc->config = event->attr.config;
2195ca02815Sjsg 	hwc->config_base = AMDGPU_PMU_PERF_TYPE_NONE;
220c349dbc7Sjsg 
221c349dbc7Sjsg 	return 0;
222c349dbc7Sjsg }
223c349dbc7Sjsg 
224c349dbc7Sjsg /* start perf counter */
amdgpu_perf_start(struct perf_event * event,int flags)225c349dbc7Sjsg static void amdgpu_perf_start(struct perf_event *event, int flags)
226c349dbc7Sjsg {
227c349dbc7Sjsg 	struct hw_perf_event *hwc = &event->hw;
228c349dbc7Sjsg 	struct amdgpu_pmu_entry *pe = container_of(event->pmu,
229c349dbc7Sjsg 						  struct amdgpu_pmu_entry,
230c349dbc7Sjsg 						  pmu);
2315ca02815Sjsg 	int target_cntr = 0;
232c349dbc7Sjsg 
233c349dbc7Sjsg 	if (WARN_ON_ONCE(!(hwc->state & PERF_HES_STOPPED)))
234c349dbc7Sjsg 		return;
235c349dbc7Sjsg 
2361bb76ff1Sjsg 	if ((!pe->adev->df.funcs) ||
2371bb76ff1Sjsg 	    (!pe->adev->df.funcs->pmc_start))
2381bb76ff1Sjsg 		return;
2391bb76ff1Sjsg 
240c349dbc7Sjsg 	WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE));
241c349dbc7Sjsg 	hwc->state = 0;
242c349dbc7Sjsg 
2435ca02815Sjsg 	switch (hwc->config_base) {
2445ca02815Sjsg 	case AMDGPU_PMU_EVENT_CONFIG_TYPE_DF:
2455ca02815Sjsg 	case AMDGPU_PMU_EVENT_CONFIG_TYPE_XGMI:
2465ca02815Sjsg 		if (!(flags & PERF_EF_RELOAD)) {
2475ca02815Sjsg 			target_cntr = pe->adev->df.funcs->pmc_start(pe->adev,
2485ca02815Sjsg 						hwc->config, 0 /* unused */,
2495ca02815Sjsg 						1 /* add counter */);
2505ca02815Sjsg 			if (target_cntr < 0)
2515ca02815Sjsg 				break;
252c349dbc7Sjsg 
2535ca02815Sjsg 			hwc->idx = target_cntr;
2545ca02815Sjsg 		}
2555ca02815Sjsg 
2565ca02815Sjsg 		pe->adev->df.funcs->pmc_start(pe->adev, hwc->config,
2575ca02815Sjsg 								hwc->idx, 0);
258c349dbc7Sjsg 		break;
259c349dbc7Sjsg 	default:
260c349dbc7Sjsg 		break;
261c349dbc7Sjsg 	}
262c349dbc7Sjsg 
263c349dbc7Sjsg 	perf_event_update_userpage(event);
264c349dbc7Sjsg }
265c349dbc7Sjsg 
266c349dbc7Sjsg /* read perf counter */
amdgpu_perf_read(struct perf_event * event)267c349dbc7Sjsg static void amdgpu_perf_read(struct perf_event *event)
268c349dbc7Sjsg {
269c349dbc7Sjsg 	struct hw_perf_event *hwc = &event->hw;
270c349dbc7Sjsg 	struct amdgpu_pmu_entry *pe = container_of(event->pmu,
271c349dbc7Sjsg 						  struct amdgpu_pmu_entry,
272c349dbc7Sjsg 						  pmu);
273c349dbc7Sjsg 	u64 count, prev;
274c349dbc7Sjsg 
2751bb76ff1Sjsg 	if ((!pe->adev->df.funcs) ||
2761bb76ff1Sjsg 	    (!pe->adev->df.funcs->pmc_get_count))
2771bb76ff1Sjsg 		return;
2781bb76ff1Sjsg 
279c349dbc7Sjsg 	prev = local64_read(&hwc->prev_count);
280*f005ef32Sjsg 	do {
2815ca02815Sjsg 		switch (hwc->config_base) {
2825ca02815Sjsg 		case AMDGPU_PMU_EVENT_CONFIG_TYPE_DF:
2835ca02815Sjsg 		case AMDGPU_PMU_EVENT_CONFIG_TYPE_XGMI:
2845ca02815Sjsg 			pe->adev->df.funcs->pmc_get_count(pe->adev,
2855ca02815Sjsg 						hwc->config, hwc->idx, &count);
286c349dbc7Sjsg 			break;
287c349dbc7Sjsg 		default:
288c349dbc7Sjsg 			count = 0;
289c349dbc7Sjsg 			break;
290c349dbc7Sjsg 		}
291*f005ef32Sjsg 	} while (!local64_try_cmpxchg(&hwc->prev_count, &prev, count));
292c349dbc7Sjsg 
293c349dbc7Sjsg 	local64_add(count - prev, &event->count);
294c349dbc7Sjsg }
295c349dbc7Sjsg 
296c349dbc7Sjsg /* stop perf counter */
amdgpu_perf_stop(struct perf_event * event,int flags)297c349dbc7Sjsg static void amdgpu_perf_stop(struct perf_event *event, int flags)
298c349dbc7Sjsg {
299c349dbc7Sjsg 	struct hw_perf_event *hwc = &event->hw;
300c349dbc7Sjsg 	struct amdgpu_pmu_entry *pe = container_of(event->pmu,
301c349dbc7Sjsg 						  struct amdgpu_pmu_entry,
302c349dbc7Sjsg 						  pmu);
303c349dbc7Sjsg 
304c349dbc7Sjsg 	if (hwc->state & PERF_HES_UPTODATE)
305c349dbc7Sjsg 		return;
306c349dbc7Sjsg 
3071bb76ff1Sjsg 	if ((!pe->adev->df.funcs) ||
3081bb76ff1Sjsg 	    (!pe->adev->df.funcs->pmc_stop))
3091bb76ff1Sjsg 		return;
3101bb76ff1Sjsg 
3115ca02815Sjsg 	switch (hwc->config_base) {
3125ca02815Sjsg 	case AMDGPU_PMU_EVENT_CONFIG_TYPE_DF:
3135ca02815Sjsg 	case AMDGPU_PMU_EVENT_CONFIG_TYPE_XGMI:
3145ca02815Sjsg 		pe->adev->df.funcs->pmc_stop(pe->adev, hwc->config, hwc->idx,
3155ca02815Sjsg 									0);
316c349dbc7Sjsg 		break;
317c349dbc7Sjsg 	default:
318c349dbc7Sjsg 		break;
319c349dbc7Sjsg 	}
320c349dbc7Sjsg 
321c349dbc7Sjsg 	WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED);
322c349dbc7Sjsg 	hwc->state |= PERF_HES_STOPPED;
323c349dbc7Sjsg 
324c349dbc7Sjsg 	if (hwc->state & PERF_HES_UPTODATE)
325c349dbc7Sjsg 		return;
326c349dbc7Sjsg 
327c349dbc7Sjsg 	amdgpu_perf_read(event);
328c349dbc7Sjsg 	hwc->state |= PERF_HES_UPTODATE;
329c349dbc7Sjsg }
330c349dbc7Sjsg 
331c349dbc7Sjsg /* add perf counter */
amdgpu_perf_add(struct perf_event * event,int flags)332c349dbc7Sjsg static int amdgpu_perf_add(struct perf_event *event, int flags)
333c349dbc7Sjsg {
334c349dbc7Sjsg 	struct hw_perf_event *hwc = &event->hw;
3355ca02815Sjsg 	int retval = 0, target_cntr;
336c349dbc7Sjsg 	struct amdgpu_pmu_entry *pe = container_of(event->pmu,
337c349dbc7Sjsg 						  struct amdgpu_pmu_entry,
338c349dbc7Sjsg 						  pmu);
339c349dbc7Sjsg 
3401bb76ff1Sjsg 	if ((!pe->adev->df.funcs) ||
3411bb76ff1Sjsg 	    (!pe->adev->df.funcs->pmc_start))
3421bb76ff1Sjsg 		return -EINVAL;
3431bb76ff1Sjsg 
3445ca02815Sjsg 	switch (pe->pmu_perf_type) {
3455ca02815Sjsg 	case AMDGPU_PMU_PERF_TYPE_DF:
3465ca02815Sjsg 		hwc->config_base = AMDGPU_PMU_EVENT_CONFIG_TYPE_DF;
3475ca02815Sjsg 		break;
3485ca02815Sjsg 	case AMDGPU_PMU_PERF_TYPE_ALL:
3495ca02815Sjsg 		hwc->config_base = (hwc->config >>
3505ca02815Sjsg 					AMDGPU_PMU_EVENT_CONFIG_TYPE_SHIFT) &
3515ca02815Sjsg 					AMDGPU_PMU_EVENT_CONFIG_TYPE_MASK;
3525ca02815Sjsg 		break;
3535ca02815Sjsg 	}
3545ca02815Sjsg 
355c349dbc7Sjsg 	event->hw.state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
356c349dbc7Sjsg 
3575ca02815Sjsg 	switch (hwc->config_base) {
3585ca02815Sjsg 	case AMDGPU_PMU_EVENT_CONFIG_TYPE_DF:
3595ca02815Sjsg 	case AMDGPU_PMU_EVENT_CONFIG_TYPE_XGMI:
3605ca02815Sjsg 		target_cntr = pe->adev->df.funcs->pmc_start(pe->adev,
3615ca02815Sjsg 						hwc->config, 0 /* unused */,
3625ca02815Sjsg 						1 /* add counter */);
3635ca02815Sjsg 		if (target_cntr < 0)
3645ca02815Sjsg 			retval = target_cntr;
3655ca02815Sjsg 		else
3665ca02815Sjsg 			hwc->idx = target_cntr;
3675ca02815Sjsg 
368c349dbc7Sjsg 		break;
369c349dbc7Sjsg 	default:
370c349dbc7Sjsg 		return 0;
371c349dbc7Sjsg 	}
372c349dbc7Sjsg 
373c349dbc7Sjsg 	if (retval)
374c349dbc7Sjsg 		return retval;
375c349dbc7Sjsg 
376c349dbc7Sjsg 	if (flags & PERF_EF_START)
377c349dbc7Sjsg 		amdgpu_perf_start(event, PERF_EF_RELOAD);
378c349dbc7Sjsg 
379c349dbc7Sjsg 	return retval;
380c349dbc7Sjsg }
381c349dbc7Sjsg 
382c349dbc7Sjsg /* delete perf counter  */
amdgpu_perf_del(struct perf_event * event,int flags)383c349dbc7Sjsg static void amdgpu_perf_del(struct perf_event *event, int flags)
384c349dbc7Sjsg {
385c349dbc7Sjsg 	struct hw_perf_event *hwc = &event->hw;
386c349dbc7Sjsg 	struct amdgpu_pmu_entry *pe = container_of(event->pmu,
387c349dbc7Sjsg 						  struct amdgpu_pmu_entry,
388c349dbc7Sjsg 						  pmu);
3891bb76ff1Sjsg 	if ((!pe->adev->df.funcs) ||
3901bb76ff1Sjsg 	    (!pe->adev->df.funcs->pmc_stop))
3911bb76ff1Sjsg 		return;
392c349dbc7Sjsg 
393c349dbc7Sjsg 	amdgpu_perf_stop(event, PERF_EF_UPDATE);
394c349dbc7Sjsg 
3955ca02815Sjsg 	switch (hwc->config_base) {
3965ca02815Sjsg 	case AMDGPU_PMU_EVENT_CONFIG_TYPE_DF:
3975ca02815Sjsg 	case AMDGPU_PMU_EVENT_CONFIG_TYPE_XGMI:
3985ca02815Sjsg 		pe->adev->df.funcs->pmc_stop(pe->adev, hwc->config, hwc->idx,
3995ca02815Sjsg 									1);
400c349dbc7Sjsg 		break;
401c349dbc7Sjsg 	default:
402c349dbc7Sjsg 		break;
403c349dbc7Sjsg 	}
404c349dbc7Sjsg 
405c349dbc7Sjsg 	perf_event_update_userpage(event);
406c349dbc7Sjsg }
407c349dbc7Sjsg 
amdgpu_pmu_create_event_attrs_by_type(struct attribute_group * attr_group,struct amdgpu_pmu_event_attribute * pmu_attr,struct amdgpu_pmu_attr events[],int s_offset,int e_offset,unsigned int type)4085ca02815Sjsg static void amdgpu_pmu_create_event_attrs_by_type(
4095ca02815Sjsg 				struct attribute_group *attr_group,
4105ca02815Sjsg 				struct amdgpu_pmu_event_attribute *pmu_attr,
4115ca02815Sjsg 				struct amdgpu_pmu_attr events[],
4125ca02815Sjsg 				int s_offset,
4135ca02815Sjsg 				int e_offset,
4145ca02815Sjsg 				unsigned int type)
415c349dbc7Sjsg {
4165ca02815Sjsg 	int i;
417c349dbc7Sjsg 
4185ca02815Sjsg 	pmu_attr += s_offset;
419c349dbc7Sjsg 
4205ca02815Sjsg 	for (i = s_offset; i < e_offset; i++) {
4215ca02815Sjsg 		attr_group->attrs[i] = &pmu_attr->attr.attr;
4225ca02815Sjsg 		sysfs_attr_init(&pmu_attr->attr.attr);
4235ca02815Sjsg 		pmu_attr->attr.attr.name = events[i].name;
4245ca02815Sjsg 		pmu_attr->attr.attr.mode = 0444;
4255ca02815Sjsg 		pmu_attr->attr.show = amdgpu_pmu_event_show;
4265ca02815Sjsg 		pmu_attr->event_str = events[i].config;
4275ca02815Sjsg 		pmu_attr->type = type;
4285ca02815Sjsg 		pmu_attr++;
4295ca02815Sjsg 	}
4305ca02815Sjsg }
4315ca02815Sjsg 
amdgpu_pmu_create_attrs(struct attribute_group * attr_group,struct amdgpu_pmu_event_attribute * pmu_attr,struct amdgpu_pmu_attr events[],int num_events)4325ca02815Sjsg static void amdgpu_pmu_create_attrs(struct attribute_group *attr_group,
4335ca02815Sjsg 				struct amdgpu_pmu_event_attribute *pmu_attr,
4345ca02815Sjsg 				struct amdgpu_pmu_attr events[],
4355ca02815Sjsg 				int num_events)
4365ca02815Sjsg {
4375ca02815Sjsg 	amdgpu_pmu_create_event_attrs_by_type(attr_group, pmu_attr, events, 0,
4385ca02815Sjsg 				num_events, AMDGPU_PMU_EVENT_CONFIG_TYPE_NONE);
4395ca02815Sjsg }
4405ca02815Sjsg 
4415ca02815Sjsg 
amdgpu_pmu_alloc_pmu_attrs(struct attribute_group * fmt_attr_group,struct amdgpu_pmu_event_attribute ** fmt_attr,struct attribute_group * evt_attr_group,struct amdgpu_pmu_event_attribute ** evt_attr,struct amdgpu_pmu_config * config)4425ca02815Sjsg static int amdgpu_pmu_alloc_pmu_attrs(
4435ca02815Sjsg 				struct attribute_group *fmt_attr_group,
4445ca02815Sjsg 				struct amdgpu_pmu_event_attribute **fmt_attr,
4455ca02815Sjsg 				struct attribute_group *evt_attr_group,
4465ca02815Sjsg 				struct amdgpu_pmu_event_attribute **evt_attr,
4475ca02815Sjsg 				struct amdgpu_pmu_config *config)
4485ca02815Sjsg {
4495ca02815Sjsg 	*fmt_attr = kcalloc(config->num_formats, sizeof(**fmt_attr),
4505ca02815Sjsg 								GFP_KERNEL);
4515ca02815Sjsg 
4525ca02815Sjsg 	if (!(*fmt_attr))
453c349dbc7Sjsg 		return -ENOMEM;
454c349dbc7Sjsg 
4555ca02815Sjsg 	fmt_attr_group->attrs = kcalloc(config->num_formats + 1,
4565ca02815Sjsg 				sizeof(*fmt_attr_group->attrs), GFP_KERNEL);
4575ca02815Sjsg 
4585ca02815Sjsg 	if (!fmt_attr_group->attrs)
4595ca02815Sjsg 		goto err_fmt_attr_grp;
4605ca02815Sjsg 
4615ca02815Sjsg 	*evt_attr = kcalloc(config->num_events, sizeof(**evt_attr), GFP_KERNEL);
4625ca02815Sjsg 
4635ca02815Sjsg 	if (!(*evt_attr))
4645ca02815Sjsg 		goto err_evt_attr;
4655ca02815Sjsg 
4665ca02815Sjsg 	evt_attr_group->attrs = kcalloc(config->num_events + 1,
4675ca02815Sjsg 				sizeof(*evt_attr_group->attrs), GFP_KERNEL);
4685ca02815Sjsg 
4695ca02815Sjsg 	if (!evt_attr_group->attrs)
4705ca02815Sjsg 		goto err_evt_attr_grp;
4715ca02815Sjsg 
4725ca02815Sjsg 	return 0;
4735ca02815Sjsg err_evt_attr_grp:
4745ca02815Sjsg 	kfree(*evt_attr);
4755ca02815Sjsg err_evt_attr:
4765ca02815Sjsg 	kfree(fmt_attr_group->attrs);
4775ca02815Sjsg err_fmt_attr_grp:
4785ca02815Sjsg 	kfree(*fmt_attr);
4795ca02815Sjsg 	return -ENOMEM;
4805ca02815Sjsg }
4815ca02815Sjsg 
4825ca02815Sjsg /* init pmu tracking per pmu type */
init_pmu_entry_by_type_and_add(struct amdgpu_pmu_entry * pmu_entry,struct amdgpu_pmu_config * config)4835ca02815Sjsg static int init_pmu_entry_by_type_and_add(struct amdgpu_pmu_entry *pmu_entry,
4845ca02815Sjsg 			struct amdgpu_pmu_config *config)
4855ca02815Sjsg {
4865ca02815Sjsg 	const struct attribute_group *attr_groups[] = {
4875ca02815Sjsg 		&pmu_entry->fmt_attr_group,
4885ca02815Sjsg 		&pmu_entry->evt_attr_group,
4895ca02815Sjsg 		NULL
4905ca02815Sjsg 	};
4915ca02815Sjsg 	char pmu_name[PMU_NAME_SIZE];
4925ca02815Sjsg 	int ret = 0, total_num_events = 0;
4935ca02815Sjsg 
494c349dbc7Sjsg 	pmu_entry->pmu = (struct pmu){
495c349dbc7Sjsg 		.event_init = amdgpu_perf_event_init,
496c349dbc7Sjsg 		.add = amdgpu_perf_add,
497c349dbc7Sjsg 		.del = amdgpu_perf_del,
498c349dbc7Sjsg 		.start = amdgpu_perf_start,
499c349dbc7Sjsg 		.stop = amdgpu_perf_stop,
500c349dbc7Sjsg 		.read = amdgpu_perf_read,
501c349dbc7Sjsg 		.task_ctx_nr = perf_invalid_context,
502c349dbc7Sjsg 	};
503c349dbc7Sjsg 
5045ca02815Sjsg 	ret = amdgpu_pmu_alloc_pmu_attrs(&pmu_entry->fmt_attr_group,
5055ca02815Sjsg 					&pmu_entry->fmt_attr,
5065ca02815Sjsg 					&pmu_entry->evt_attr_group,
5075ca02815Sjsg 					&pmu_entry->evt_attr,
5085ca02815Sjsg 					config);
5095ca02815Sjsg 
5105ca02815Sjsg 	if (ret)
5115ca02815Sjsg 		goto err_out;
5125ca02815Sjsg 
5135ca02815Sjsg 	amdgpu_pmu_create_attrs(&pmu_entry->fmt_attr_group, pmu_entry->fmt_attr,
5145ca02815Sjsg 					config->formats, config->num_formats);
5155ca02815Sjsg 
5165ca02815Sjsg 	if (pmu_entry->pmu_perf_type == AMDGPU_PMU_PERF_TYPE_ALL) {
5175ca02815Sjsg 		int i;
5185ca02815Sjsg 
5195ca02815Sjsg 		for (i = 0; i < config->num_types; i++) {
5205ca02815Sjsg 			amdgpu_pmu_create_event_attrs_by_type(
5215ca02815Sjsg 					&pmu_entry->evt_attr_group,
5225ca02815Sjsg 					pmu_entry->evt_attr,
5235ca02815Sjsg 					config->events,
5245ca02815Sjsg 					total_num_events,
5255ca02815Sjsg 					total_num_events +
5265ca02815Sjsg 						config->types[i].num_of_type,
5275ca02815Sjsg 					config->types[i].type);
5285ca02815Sjsg 			total_num_events += config->types[i].num_of_type;
5295ca02815Sjsg 		}
5305ca02815Sjsg 	} else {
5315ca02815Sjsg 		amdgpu_pmu_create_attrs(&pmu_entry->evt_attr_group,
5325ca02815Sjsg 					pmu_entry->evt_attr,
5335ca02815Sjsg 					config->events, config->num_events);
5345ca02815Sjsg 		total_num_events = config->num_events;
5355ca02815Sjsg 	}
5365ca02815Sjsg 
5375ca02815Sjsg 	pmu_entry->pmu.attr_groups = kmemdup(attr_groups, sizeof(attr_groups),
5385ca02815Sjsg 								GFP_KERNEL);
5395ca02815Sjsg 
5405ca02815Sjsg 	if (!pmu_entry->pmu.attr_groups) {
5415ca02815Sjsg 		ret = -ENOMEM;
5425ca02815Sjsg 		goto err_attr_group;
5435ca02815Sjsg 	}
5445ca02815Sjsg 
5455ca02815Sjsg 	snprintf(pmu_name, PMU_NAME_SIZE, "%s_%d", pmu_entry->pmu_file_prefix,
5465ca02815Sjsg 				adev_to_drm(pmu_entry->adev)->primary->index);
547c349dbc7Sjsg 
548c349dbc7Sjsg 	ret = perf_pmu_register(&pmu_entry->pmu, pmu_name, -1);
549c349dbc7Sjsg 
5505ca02815Sjsg 	if (ret)
5515ca02815Sjsg 		goto err_register;
552c349dbc7Sjsg 
5535ca02815Sjsg 	if (pmu_entry->pmu_perf_type != AMDGPU_PMU_PERF_TYPE_ALL)
554c349dbc7Sjsg 		pr_info("Detected AMDGPU %s Counters. # of Counters = %d.\n",
5555ca02815Sjsg 				pmu_entry->pmu_type_name, total_num_events);
5565ca02815Sjsg 	else
5575ca02815Sjsg 		pr_info("Detected AMDGPU %d Perf Events.\n", total_num_events);
5585ca02815Sjsg 
559c349dbc7Sjsg 
560c349dbc7Sjsg 	list_add_tail(&pmu_entry->entry, &amdgpu_pmu_list);
561c349dbc7Sjsg 
562c349dbc7Sjsg 	return 0;
5635ca02815Sjsg err_register:
5645ca02815Sjsg 	kfree(pmu_entry->pmu.attr_groups);
5655ca02815Sjsg err_attr_group:
5665ca02815Sjsg 	kfree(pmu_entry->fmt_attr_group.attrs);
5675ca02815Sjsg 	kfree(pmu_entry->fmt_attr);
5685ca02815Sjsg 	kfree(pmu_entry->evt_attr_group.attrs);
5695ca02815Sjsg 	kfree(pmu_entry->evt_attr);
5705ca02815Sjsg err_out:
5715ca02815Sjsg 	pr_warn("Error initializing AMDGPU %s PMUs.\n",
5725ca02815Sjsg 						pmu_entry->pmu_type_name);
5735ca02815Sjsg 	return ret;
574c349dbc7Sjsg }
575c349dbc7Sjsg 
576c349dbc7Sjsg /* destroy all pmu data associated with target device */
amdgpu_pmu_fini(struct amdgpu_device * adev)577c349dbc7Sjsg void amdgpu_pmu_fini(struct amdgpu_device *adev)
578c349dbc7Sjsg {
579c349dbc7Sjsg 	struct amdgpu_pmu_entry *pe, *temp;
580c349dbc7Sjsg 
581c349dbc7Sjsg 	list_for_each_entry_safe(pe, temp, &amdgpu_pmu_list, entry) {
5825ca02815Sjsg 		if (pe->adev != adev)
5835ca02815Sjsg 			continue;
584c349dbc7Sjsg 		list_del(&pe->entry);
585c349dbc7Sjsg 		perf_pmu_unregister(&pe->pmu);
5865ca02815Sjsg 		kfree(pe->pmu.attr_groups);
5875ca02815Sjsg 		kfree(pe->fmt_attr_group.attrs);
5885ca02815Sjsg 		kfree(pe->fmt_attr);
5895ca02815Sjsg 		kfree(pe->evt_attr_group.attrs);
5905ca02815Sjsg 		kfree(pe->evt_attr);
591c349dbc7Sjsg 		kfree(pe);
592c349dbc7Sjsg 	}
593c349dbc7Sjsg }
5945ca02815Sjsg 
create_pmu_entry(struct amdgpu_device * adev,unsigned int pmu_type,char * pmu_type_name,char * pmu_file_prefix)5955ca02815Sjsg static struct amdgpu_pmu_entry *create_pmu_entry(struct amdgpu_device *adev,
5965ca02815Sjsg 						unsigned int pmu_type,
5975ca02815Sjsg 						char *pmu_type_name,
5985ca02815Sjsg 						char *pmu_file_prefix)
5995ca02815Sjsg {
6005ca02815Sjsg 	struct amdgpu_pmu_entry *pmu_entry;
6015ca02815Sjsg 
6025ca02815Sjsg 	pmu_entry = kzalloc(sizeof(struct amdgpu_pmu_entry), GFP_KERNEL);
6035ca02815Sjsg 
6045ca02815Sjsg 	if (!pmu_entry)
6055ca02815Sjsg 		return pmu_entry;
6065ca02815Sjsg 
6075ca02815Sjsg 	pmu_entry->adev = adev;
6085ca02815Sjsg 	pmu_entry->fmt_attr_group.name = "format";
6095ca02815Sjsg 	pmu_entry->fmt_attr_group.attrs = NULL;
6105ca02815Sjsg 	pmu_entry->evt_attr_group.name = "events";
6115ca02815Sjsg 	pmu_entry->evt_attr_group.attrs = NULL;
6125ca02815Sjsg 	pmu_entry->pmu_perf_type = pmu_type;
6135ca02815Sjsg 	pmu_entry->pmu_type_name = pmu_type_name;
6145ca02815Sjsg 	pmu_entry->pmu_file_prefix = pmu_file_prefix;
6155ca02815Sjsg 
6165ca02815Sjsg 	return pmu_entry;
6175ca02815Sjsg }
6185ca02815Sjsg 
6195ca02815Sjsg /* init amdgpu_pmu */
amdgpu_pmu_init(struct amdgpu_device * adev)6205ca02815Sjsg int amdgpu_pmu_init(struct amdgpu_device *adev)
6215ca02815Sjsg {
6225ca02815Sjsg 	int ret = 0;
6235ca02815Sjsg 	struct amdgpu_pmu_entry *pmu_entry, *pmu_entry_df;
6245ca02815Sjsg 
6255ca02815Sjsg 	switch (adev->asic_type) {
6265ca02815Sjsg 	case CHIP_VEGA20:
6275ca02815Sjsg 		pmu_entry_df = create_pmu_entry(adev, AMDGPU_PMU_PERF_TYPE_DF,
6285ca02815Sjsg 						"DF", "amdgpu_df");
6295ca02815Sjsg 
6305ca02815Sjsg 		if (!pmu_entry_df)
6315ca02815Sjsg 			return -ENOMEM;
6325ca02815Sjsg 
6335ca02815Sjsg 		ret = init_pmu_entry_by_type_and_add(pmu_entry_df,
6345ca02815Sjsg 							&df_vega20_config);
6355ca02815Sjsg 
6365ca02815Sjsg 		if (ret) {
6375ca02815Sjsg 			kfree(pmu_entry_df);
6385ca02815Sjsg 			return ret;
6395ca02815Sjsg 		}
6405ca02815Sjsg 
6415ca02815Sjsg 		pmu_entry = create_pmu_entry(adev, AMDGPU_PMU_PERF_TYPE_ALL,
6425ca02815Sjsg 						"", "amdgpu");
6435ca02815Sjsg 
6445ca02815Sjsg 		if (!pmu_entry) {
6455ca02815Sjsg 			amdgpu_pmu_fini(adev);
6465ca02815Sjsg 			return -ENOMEM;
6475ca02815Sjsg 		}
6485ca02815Sjsg 
6495ca02815Sjsg 		ret = init_pmu_entry_by_type_and_add(pmu_entry,
6505ca02815Sjsg 							&vega20_config);
6515ca02815Sjsg 
6525ca02815Sjsg 		if (ret) {
6535ca02815Sjsg 			kfree(pmu_entry);
6545ca02815Sjsg 			amdgpu_pmu_fini(adev);
6555ca02815Sjsg 			return ret;
6565ca02815Sjsg 		}
6575ca02815Sjsg 
6585ca02815Sjsg 		break;
6595ca02815Sjsg 	case CHIP_ARCTURUS:
6605ca02815Sjsg 		pmu_entry = create_pmu_entry(adev, AMDGPU_PMU_PERF_TYPE_ALL,
6615ca02815Sjsg 						"", "amdgpu");
6625ca02815Sjsg 		if (!pmu_entry)
6635ca02815Sjsg 			return -ENOMEM;
6645ca02815Sjsg 
6655ca02815Sjsg 		ret = init_pmu_entry_by_type_and_add(pmu_entry,
6665ca02815Sjsg 							&arcturus_config);
6675ca02815Sjsg 
6685ca02815Sjsg 		if (ret) {
6695ca02815Sjsg 			kfree(pmu_entry);
6705ca02815Sjsg 			return -ENOMEM;
6715ca02815Sjsg 		}
6725ca02815Sjsg 
6735ca02815Sjsg 		break;
6745ca02815Sjsg 
6755ca02815Sjsg 	default:
6765ca02815Sjsg 		return 0;
6775ca02815Sjsg 	}
6785ca02815Sjsg 
6795ca02815Sjsg 	return ret;
680c349dbc7Sjsg }
681