1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2018 Broadcom
7 * DOC: VC4 V3D performance monitor module
9 * The V3D block provides 16 hardware counters which can count various events.
15 #define VC4_PERFMONID_MIN 1
16 #define VC4_PERFMONID_MAX U32_MAX
18 void vc4_perfmon_get(struct vc4_perfmon
*perfmon
)
21 refcount_inc(&perfmon
->refcnt
);
24 void vc4_perfmon_put(struct vc4_perfmon
*perfmon
)
26 if (perfmon
&& refcount_dec_and_test(&perfmon
->refcnt
))
30 void vc4_perfmon_start(struct vc4_dev
*vc4
, struct vc4_perfmon
*perfmon
)
35 if (WARN_ON_ONCE(!perfmon
|| vc4
->active_perfmon
))
38 for (i
= 0; i
< perfmon
->ncounters
; i
++)
39 V3D_WRITE(V3D_PCTRS(i
), perfmon
->events
[i
]);
41 mask
= GENMASK(perfmon
->ncounters
- 1, 0);
42 V3D_WRITE(V3D_PCTRC
, mask
);
43 V3D_WRITE(V3D_PCTRE
, V3D_PCTRE_EN
| mask
);
44 vc4
->active_perfmon
= perfmon
;
47 void vc4_perfmon_stop(struct vc4_dev
*vc4
, struct vc4_perfmon
*perfmon
,
52 if (WARN_ON_ONCE(!vc4
->active_perfmon
||
53 perfmon
!= vc4
->active_perfmon
))
57 for (i
= 0; i
< perfmon
->ncounters
; i
++)
58 perfmon
->counters
[i
] += V3D_READ(V3D_PCTR(i
));
61 V3D_WRITE(V3D_PCTRE
, 0);
62 vc4
->active_perfmon
= NULL
;
65 struct vc4_perfmon
*vc4_perfmon_find(struct vc4_file
*vc4file
, int id
)
67 struct vc4_perfmon
*perfmon
;
69 mutex_lock(&vc4file
->perfmon
.lock
);
70 perfmon
= idr_find(&vc4file
->perfmon
.idr
, id
);
71 vc4_perfmon_get(perfmon
);
72 mutex_unlock(&vc4file
->perfmon
.lock
);
77 void vc4_perfmon_open_file(struct vc4_file
*vc4file
)
79 mutex_init(&vc4file
->perfmon
.lock
);
80 idr_init_base(&vc4file
->perfmon
.idr
, VC4_PERFMONID_MIN
);
83 static int vc4_perfmon_idr_del(int id
, void *elem
, void *data
)
85 struct vc4_perfmon
*perfmon
= elem
;
87 vc4_perfmon_put(perfmon
);
92 void vc4_perfmon_close_file(struct vc4_file
*vc4file
)
94 mutex_lock(&vc4file
->perfmon
.lock
);
95 idr_for_each(&vc4file
->perfmon
.idr
, vc4_perfmon_idr_del
, NULL
);
96 idr_destroy(&vc4file
->perfmon
.idr
);
97 mutex_unlock(&vc4file
->perfmon
.lock
);
100 int vc4_perfmon_create_ioctl(struct drm_device
*dev
, void *data
,
101 struct drm_file
*file_priv
)
103 struct vc4_dev
*vc4
= to_vc4_dev(dev
);
104 struct vc4_file
*vc4file
= file_priv
->driver_priv
;
105 struct drm_vc4_perfmon_create
*req
= data
;
106 struct vc4_perfmon
*perfmon
;
111 DRM_DEBUG("Creating perfmon no VC4 V3D probed\n");
115 /* Number of monitored counters cannot exceed HW limits. */
116 if (req
->ncounters
> DRM_VC4_MAX_PERF_COUNTERS
||
120 /* Make sure all events are valid. */
121 for (i
= 0; i
< req
->ncounters
; i
++) {
122 if (req
->events
[i
] >= VC4_PERFCNT_NUM_EVENTS
)
126 perfmon
= kzalloc(struct_size(perfmon
, counters
, req
->ncounters
),
131 for (i
= 0; i
< req
->ncounters
; i
++)
132 perfmon
->events
[i
] = req
->events
[i
];
134 perfmon
->ncounters
= req
->ncounters
;
136 refcount_set(&perfmon
->refcnt
, 1);
138 mutex_lock(&vc4file
->perfmon
.lock
);
139 ret
= idr_alloc(&vc4file
->perfmon
.idr
, perfmon
, VC4_PERFMONID_MIN
,
140 VC4_PERFMONID_MAX
, GFP_KERNEL
);
141 mutex_unlock(&vc4file
->perfmon
.lock
);
152 int vc4_perfmon_destroy_ioctl(struct drm_device
*dev
, void *data
,
153 struct drm_file
*file_priv
)
155 struct vc4_dev
*vc4
= to_vc4_dev(dev
);
156 struct vc4_file
*vc4file
= file_priv
->driver_priv
;
157 struct drm_vc4_perfmon_destroy
*req
= data
;
158 struct vc4_perfmon
*perfmon
;
161 DRM_DEBUG("Destroying perfmon no VC4 V3D probed\n");
165 mutex_lock(&vc4file
->perfmon
.lock
);
166 perfmon
= idr_remove(&vc4file
->perfmon
.idr
, req
->id
);
167 mutex_unlock(&vc4file
->perfmon
.lock
);
172 vc4_perfmon_put(perfmon
);
176 int vc4_perfmon_get_values_ioctl(struct drm_device
*dev
, void *data
,
177 struct drm_file
*file_priv
)
179 struct vc4_dev
*vc4
= to_vc4_dev(dev
);
180 struct vc4_file
*vc4file
= file_priv
->driver_priv
;
181 struct drm_vc4_perfmon_get_values
*req
= data
;
182 struct vc4_perfmon
*perfmon
;
186 DRM_DEBUG("Getting perfmon no VC4 V3D probed\n");
190 mutex_lock(&vc4file
->perfmon
.lock
);
191 perfmon
= idr_find(&vc4file
->perfmon
.idr
, req
->id
);
192 vc4_perfmon_get(perfmon
);
193 mutex_unlock(&vc4file
->perfmon
.lock
);
198 if (copy_to_user(u64_to_user_ptr(req
->values_ptr
), perfmon
->counters
,
199 perfmon
->ncounters
* sizeof(u64
)))
204 vc4_perfmon_put(perfmon
);