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;
}
|