summaryrefslogtreecommitdiff
path: root/mali_kbase/backend/gpu/mali_kbase_pm_event_log.c
blob: b752af804f905cc9a9498970e570cbbf953b5436 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
// SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
/*
 *
 * (C) COPYRIGHT 2022 Google LLC. All rights reserved.
 *
 * This program is free software and is provided to you under the terms of the
 * GNU General Public License version 2 as published by the Free Software
 * Foundation, and any use by you of this program is subject to the terms
 * of such GNU license.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, you can access it online at
 * http://www.gnu.org/licenses/gpl-2.0.html.
 *
 */

#include <backend/gpu/mali_kbase_pm_event_log.h>

static inline u32 kbase_pm_next_log_event(
	struct kbase_pm_event_log *log)
{
	u32 ret = log->last_event;
	++ret;
	ret %= EVENT_LOG_MAX;
	log->last_event = ret;
	return ret;
}

struct kbase_pm_event_log_event *kbase_pm_add_log_event(
	struct kbase_device *kbdev)
{
	struct kbase_pm_event_log *log = &kbdev->pm.backend.event_log;
	struct kbase_pm_event_log_event *ret = NULL;

	lockdep_assert_held(&kbdev->hwaccess_lock);
	ret = &log->events[kbase_pm_next_log_event(log)];

	memset(ret, 0, sizeof(*ret));
	ret->timestamp = ktime_get();
	return ret;
}

/**
 * struct kbase_pm_event_log_metadata - Info about the event log.
 *
 * @magic: always 'kpel', helps find the log in memory dumps
 * @version: updated whenever the binary layout changes
 * @events_address: the memory address of the log, or in a file the offset
 *                  from the start of the metadata to the log
 * @num_events: the capacity of the event log
 * @event_stride: distance between log entries, to aid in parsing if only some
 *                entry types are supported by the parser
 **/
struct kbase_pm_event_log_metadata {
	char magic[4];
	u8 version;
	u64 events_address;
	u32 num_events;
	u32 event_stride;
} __attribute__((packed));

static struct kbase_pm_event_log_metadata global_event_log_metadata;

void kbase_pm_init_event_log(struct kbase_device *kbdev)
{
	struct kbase_pm_event_log_metadata *md =
			&global_event_log_metadata;
	kbdev->pm.backend.event_log.last_event = -1;
	md->magic[0] = 'k';
	md->magic[1] = 'p';
	md->magic[2] = 'e';
	md->magic[3] = 'l';
	md->version = 1;
	md->num_events = EVENT_LOG_MAX;
	md->events_address = (u64)kbdev->pm.backend.event_log.events;
	md->event_stride = ((u8*)&kbdev->pm.backend.event_log.events[1] -
			    (u8*)&kbdev->pm.backend.event_log.events[0]);
}

u64 kbase_pm_max_event_log_size(struct kbase_device *kbdev)
{
	return sizeof(struct kbase_pm_event_log_metadata)
			+ sizeof(kbdev->pm.backend.event_log.events);
}

int kbase_pm_copy_event_log(struct kbase_device *kbdev,
		void *buffer, u64 size)
{
	lockdep_assert_held(&kbdev->hwaccess_lock);
	if (size < kbase_pm_max_event_log_size(kbdev)) {
		return -EINVAL;
	}
	memcpy(buffer, &global_event_log_metadata,
	       sizeof(global_event_log_metadata));
	memcpy(((u8*)buffer) + sizeof(global_event_log_metadata),
	       &kbdev->pm.backend.event_log.events,
	       sizeof(kbdev->pm.backend.event_log.events));
	((struct kbase_pm_event_log_metadata*)buffer)->events_address =
			sizeof(struct kbase_pm_event_log_metadata);

	return 0;
}