blob: ab4d6ddf97a791cfbc601dec95f5741fa4ee46e1 [file] [log] [blame]
/*
* This file is part of the UWB stack for linux.
*
* Copyright (c) 2020 Qorvo US, Inc.
*
* This software is provided under the GNU General Public License, version 2
* (GPLv2), as well as under a Qorvo commercial license.
*
* You may choose to use this software under the terms of the GPLv2 License,
* version 2 ("GPLv2"), as published by the Free Software Foundation.
* You should have received a copy of the GPLv2 along with this program. If
* not, see <http://www.gnu.org/licenses/>.
*
* This program is distributed under the GPLv2 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 GPLv2 for more
* details.
*
* If you cannot meet the requirements of the GPLv2, you may not use this
* software for any purpose without first obtaining a commercial license from
* Qorvo.
* Please contact Qorvo to inquire about licensing terms.
*/
#ifndef __DW3000_PERF_H
#define __DW3000_PERF_H
#include <linux/version.h>
#include <linux/perf_event.h>
static struct perf_event_attr perf_hw_attr[] = {
{
.type = PERF_TYPE_HARDWARE,
.config = PERF_COUNT_HW_CPU_CYCLES,
.size = sizeof(struct perf_event_attr),
.pinned = 1,
.disabled = 1,
},
{
.type = PERF_TYPE_HARDWARE,
.config = PERF_COUNT_HW_INSTRUCTIONS,
.size = sizeof(struct perf_event_attr),
.pinned = 1,
.disabled = 1,
},
{
.type = PERF_TYPE_HARDWARE,
.config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS,
.size = sizeof(struct perf_event_attr),
.pinned = 1,
.disabled = 1,
},
{
.type = PERF_TYPE_HARDWARE,
.config = PERF_COUNT_HW_CACHE_MISSES,
.size = sizeof(struct perf_event_attr),
.pinned = 1,
.disabled = 1,
}
};
#define PERF_EVT_COUNT (ARRAY_SIZE(perf_hw_attr))
static const char *const perf_hw_evt_name[PERF_EVT_COUNT] = {
"cpu cycles ", "instructions", "branch insts", "cache misses"
};
static struct perf_event *perf_hw_evt[PERF_EVT_COUNT];
/* Callback function for perf event subsystem */
static void overflow_callback(struct perf_event *event,
struct perf_sample_data *data,
struct pt_regs *regs)
{
struct dw3000 *dw = event->overflow_handler_context;
event->hw.interrupts = 0;
dev_warn(dw->dev, "test mode: counter overflow for event %x:%llx\n",
event->attr.type, event->attr.config);
}
static inline void perf_event_create_all(struct dw3000 *dw)
{
int i;
for (i = 0; i < PERF_EVT_COUNT; i++) {
struct perf_event *evt = perf_event_create_kernel_counter(
&perf_hw_attr[i], smp_processor_id(), NULL,
overflow_callback, dw);
if (IS_ERR(evt)) {
dev_warn(
dw->dev,
"test mode: cannot create perf_hw_evt %d (err %ld)\n",
i, PTR_ERR(evt));
evt = NULL;
}
perf_hw_evt[i] = evt;
}
}
static inline void perf_event_release_all(void)
{
int i;
for (i = 0; i < PERF_EVT_COUNT; i++) {
struct perf_event *evt = perf_hw_evt[i];
if (evt)
perf_event_release_kernel(evt);
}
}
static inline void perf_event_start_all(void)
{
int i;
for (i = 0; i < PERF_EVT_COUNT; i++) {
struct perf_event *evt = perf_hw_evt[i];
if (evt)
perf_event_enable(evt);
}
}
static inline void perf_event_stop_all(u64 *vals)
{
u64 dummy[2];
int i;
for (i = 0; i < PERF_EVT_COUNT; i++) {
struct perf_event *evt = perf_hw_evt[i];
if (evt) {
vals[i] = perf_event_read_value(evt, &dummy[0],
&dummy[1]);
#if (KERNEL_VERSION(5, 5, 0) > LINUX_VERSION_CODE)
perf_event_disable(evt);
local64_set(&evt->count, 0);
#else
perf_event_pause(evt, true);
#endif
}
}
}
#endif /* __DW3000_PERF_H */