660 lines
16 KiB
C
660 lines
16 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (c) 2020 MediaTek Inc.
|
|
*/
|
|
#include <linux/io.h>
|
|
#include <linux/spinlock.h>
|
|
#include <linux/types.h>
|
|
#include <linux/bitmap.h>
|
|
|
|
#include "mdla_hw_reg.h"
|
|
#include "mdla_pmu.h"
|
|
#include "mdla.h"
|
|
#include "mdla_trace.h"
|
|
#include "mdla_debug.h"
|
|
|
|
#define COUNTER_CLEAR 0xFFFFFFFF
|
|
#define MN MTK_MDLA_MAX_NUM
|
|
#define PL PRIORITY_LEVEL
|
|
#define MPC MDLA_PMU_COUNTERS
|
|
|
|
/* for core id 0 */
|
|
DECLARE_BITMAP(pmu0_bitmap, MPC);
|
|
/* for core id 1 */
|
|
DECLARE_BITMAP(pmu1_bitmap, MPC);
|
|
|
|
spinlock_t pmu_lock[MN];
|
|
|
|
/* saved registers, used to restore config after pmu reset */
|
|
u32 cfg_pmu_event[MN][MPC];
|
|
|
|
/* used to save event from ioctl */
|
|
u32 cfg_pmu_event_trace[MPC];
|
|
|
|
//static u32 cfg_pmu_clr_mode[MN];
|
|
static u8 cfg_pmu_percmd_mode[MN][PL];
|
|
/* lastest register values, since last command end */
|
|
static u16 l_cmd_cnt[MN][PL];
|
|
static u16 l_cmd_id[MN][PL];
|
|
static u32 l_counters[MN][PL][MPC];
|
|
static u32 l_start_t[MN][PL];
|
|
static u32 l_end_t[MN][PL];
|
|
static u32 l_cycle[MN][PL];
|
|
static u32 number_of_event[PL];
|
|
//static struct mdla_pmu_event_handle mdla_pmu_event_hnd[MN];
|
|
static u32 pmu_event_handle[MN][PL][MPC];
|
|
|
|
unsigned int pmu_reg_read_with_mdlaid(u32 mdlaid, u32 offset)
|
|
{
|
|
return ioread32(mdla_reg_control[mdlaid].apu_mdla_biu_top + offset);
|
|
}
|
|
|
|
static void pmu_reg_write_with_mdlaid(u32 mdlaid, u32 value, u32 offset)
|
|
{
|
|
iowrite32(value, mdla_reg_control[mdlaid].apu_mdla_biu_top + offset);
|
|
}
|
|
|
|
#define pmu_reg_set_with_mdlaid(id, mask, offset) \
|
|
pmu_reg_write_with_mdlaid(id, \
|
|
pmu_reg_read_with_mdlaid(id, offset) | (mask), (offset))
|
|
|
|
#define pmu_reg_clear_with_mdlaid(id, mask, offset) \
|
|
pmu_reg_write_with_mdlaid(id, \
|
|
pmu_reg_read_with_mdlaid(id, offset) & ~(mask), (offset))
|
|
|
|
/*
|
|
* API naming rules
|
|
* pmu_xxx_save(): save registers to variables
|
|
* pmu_xxx_get(): load values from saved variables.
|
|
* pmu_xxx_read(): read values from registers.
|
|
* pmu_xxx_write(): write values to registers.
|
|
*/
|
|
|
|
static int pmu_event_write(u32 mdlaid, u32 handle, u32 val)
|
|
{
|
|
u32 mask;
|
|
|
|
if (handle >= MPC)
|
|
return -EINVAL;
|
|
|
|
mask = 1 << (handle+17);
|
|
|
|
if (val == COUNTER_CLEAR) {
|
|
mdla_pmu_debug("%s: clear pmu counter[%d]\n",
|
|
__func__, handle);
|
|
pmu_reg_write_with_mdlaid(mdlaid, 0, PMU_EVENT_OFFSET +
|
|
(handle) * PMU_CNT_SHIFT);
|
|
pmu_reg_clear_with_mdlaid(mdlaid, mask, PMU_CFG_PMCR);
|
|
} else {
|
|
mdla_pmu_debug("%s: set pmu counter[%d] = 0x%x\n",
|
|
__func__, handle, val);
|
|
pmu_reg_write_with_mdlaid(mdlaid, val, PMU_EVENT_OFFSET +
|
|
(handle) * PMU_CNT_SHIFT);
|
|
pmu_reg_set_with_mdlaid(mdlaid, mask, PMU_CFG_PMCR);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int pmu_event_write_all(u32 mdlaid, u16 priority)
|
|
{
|
|
int i;
|
|
|
|
if (!cfg_apusys_trace) {
|
|
for (i = 0; i < number_of_event[priority]; i++) {
|
|
pmu_event_write(mdlaid, i,
|
|
pmu_event_handle[mdlaid][priority][i]);
|
|
}
|
|
} else {
|
|
for (i = 0; i < MPC; i++) {
|
|
pmu_event_write(mdlaid, i,
|
|
pmu_event_handle[mdlaid][priority][i]);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* for ioctrl */
|
|
int pmu_counter_alloc(u32 mdlaid, u32 interface, u32 event)
|
|
{
|
|
unsigned long flags;
|
|
int handle;
|
|
|
|
//mutex_lock(&mdla_devices[mdlaid].cmd_lock);
|
|
mutex_lock(&mdla_devices[mdlaid].power_lock);
|
|
|
|
spin_lock_irqsave(&pmu_lock[mdlaid], flags);
|
|
|
|
if (mdlaid == 0)
|
|
handle = bitmap_find_free_region(pmu0_bitmap,
|
|
MPC, 0);
|
|
else{
|
|
handle = -EINVAL;
|
|
goto out;
|
|
}
|
|
|
|
spin_unlock_irqrestore(&pmu_lock[mdlaid], flags);
|
|
if (unlikely(handle < 0))
|
|
goto out;
|
|
|
|
pmu_counter_event_save(mdlaid, handle, ((interface << 16) | event));
|
|
|
|
out:
|
|
mutex_unlock(&mdla_devices[mdlaid].power_lock);
|
|
//mutex_unlock(&mdla_devices[mdlaid].cmd_lock);
|
|
return handle;
|
|
}
|
|
EXPORT_SYMBOL(pmu_counter_alloc);
|
|
|
|
/* for ioctrl */
|
|
int pmu_counter_free(u32 mdlaid, int handle)
|
|
{
|
|
int ret = 0;
|
|
|
|
if ((handle >= MPC) || (handle < 0))
|
|
return -EINVAL;
|
|
|
|
//mutex_lock(&mdla_devices[mdlaid].cmd_lock);
|
|
mutex_lock(&mdla_devices[mdlaid].power_lock);
|
|
|
|
if (mdlaid == 0)
|
|
bitmap_release_region(pmu0_bitmap, handle, 0);
|
|
else if (mdlaid == 1)
|
|
bitmap_release_region(pmu1_bitmap, handle, 0);
|
|
else{
|
|
handle = -EINVAL;
|
|
goto out;
|
|
}
|
|
|
|
if (get_power_on_status(mdlaid))
|
|
pmu_event_write(mdlaid, handle, COUNTER_CLEAR);
|
|
|
|
out:
|
|
mutex_unlock(&mdla_devices[mdlaid].power_lock);
|
|
//mutex_unlock(&mdla_devices[mdlaid].cmd_lock);
|
|
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(pmu_counter_free);
|
|
|
|
/* for ioctrl */
|
|
int pmu_counter_event_save(u32 mdlaid, u32 handle, u32 val)
|
|
{
|
|
if (handle >= MPC)
|
|
return -EINVAL;
|
|
|
|
cfg_pmu_event[mdlaid][handle] = val;
|
|
|
|
if (!get_power_on_status(mdlaid))
|
|
return -1;
|
|
|
|
return pmu_event_write(mdlaid, handle, val);
|
|
}
|
|
|
|
/* for ioctrl */
|
|
int pmu_counter_event_get(u32 mdlaid, int handle)
|
|
{
|
|
u32 event;
|
|
|
|
if ((handle >= MPC) || (handle < 0))
|
|
return -EINVAL;
|
|
|
|
event = cfg_pmu_event[mdlaid][handle];
|
|
|
|
return (event == COUNTER_CLEAR) ? -ENOENT : event;
|
|
}
|
|
|
|
/* for mdla_trace */
|
|
int pmu_counter_event_get_all(u32 mdlaid, u32 out[MPC])
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < MPC; i++)
|
|
out[i] = cfg_pmu_event_trace[i];
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* for mdla_trace and apusys_hnd */
|
|
void pmu_counter_read_all(u32 mdlaid, u32 out[MPC])
|
|
{
|
|
int i;
|
|
u32 offset;
|
|
u32 reg;
|
|
|
|
offset = PMU_CNT_OFFSET;
|
|
reg = pmu_reg_read_with_mdlaid(mdlaid, PMU_CFG_PMCR);
|
|
|
|
if ((1<<PMU_CLR_CMDE_SHIFT) & reg)
|
|
offset = offset + 4;
|
|
|
|
for (i = 0; i < MPC; i++)
|
|
out[i] += pmu_reg_read_with_mdlaid(mdlaid,
|
|
offset + (i * PMU_CNT_SHIFT));
|
|
}
|
|
|
|
u32 pmu_counter_get(u32 mdlaid, int handle, u16 priority)
|
|
{
|
|
if ((handle >= MPC) || (handle < 0))
|
|
return -EINVAL;
|
|
|
|
return l_counters[mdlaid][priority][handle];
|
|
}
|
|
|
|
void pmu_counter_get_all(u32 mdlaid, u32 out[MPC], u16 priority)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < MPC; i++)
|
|
out[i] = l_counters[mdlaid][priority][i];
|
|
}
|
|
|
|
u32 pmu_get_perf_start(u32 mdlaid, u16 priority)
|
|
{
|
|
return l_start_t[mdlaid][priority];
|
|
}
|
|
|
|
u32 pmu_get_perf_end(u32 mdlaid, u16 priority)
|
|
{
|
|
return l_end_t[mdlaid][priority];
|
|
}
|
|
|
|
u32 pmu_get_perf_cycle(u32 mdlaid, u16 priority)
|
|
{
|
|
return l_cycle[mdlaid][priority];
|
|
}
|
|
|
|
u16 pmu_get_perf_cmdid(u32 mdlaid, u16 priority)
|
|
{
|
|
return l_cmd_id[mdlaid][priority];
|
|
}
|
|
|
|
void pmu_reset_counter(u32 mdlaid)
|
|
{
|
|
mdla_pmu_debug("mdla: %s\n", __func__);
|
|
|
|
if (!get_power_on_status(mdlaid))
|
|
return;
|
|
/*Reset Clock counter to zero. Return to zero when reset done.*/
|
|
pmu_reg_set_with_mdlaid(mdlaid, PMU_PMCR_CNT_RST, PMU_CFG_PMCR);
|
|
while (pmu_reg_read_with_mdlaid(mdlaid, PMU_CFG_PMCR) &
|
|
PMU_PMCR_CNT_RST) {
|
|
}
|
|
}
|
|
|
|
void pmu_reset_cycle(u32 mdlaid)
|
|
{
|
|
mdla_pmu_debug("mdla: %s\n", __func__);
|
|
|
|
if (!get_power_on_status(mdlaid))
|
|
return;
|
|
|
|
pmu_reg_set_with_mdlaid(mdlaid,
|
|
(PMU_PMCR_CCNT_EN | PMU_PMCR_CCNT_RST), PMU_CFG_PMCR);
|
|
while (pmu_reg_read_with_mdlaid(mdlaid, PMU_CFG_PMCR) &
|
|
PMU_PMCR_CCNT_RST) {
|
|
}
|
|
}
|
|
|
|
/* it set mode to register */
|
|
void pmu_percmd_mode_write(u32 mdlaid, u16 priority)
|
|
{
|
|
u32 mask = (1 << PMU_CLR_CMDE_SHIFT);
|
|
u32 mode = cfg_pmu_percmd_mode[mdlaid][priority];
|
|
|
|
if (!get_power_on_status(mdlaid))
|
|
return;
|
|
|
|
if (mode)
|
|
pmu_reg_set_with_mdlaid(mdlaid, mask, PMU_CFG_PMCR);
|
|
else
|
|
pmu_reg_clear_with_mdlaid(mdlaid, mask, PMU_CFG_PMCR);
|
|
}
|
|
|
|
/* it save mode setting to local variable */
|
|
void pmu_percmd_mode_save(u32 mdlaid, u32 mode, u16 priority)
|
|
{
|
|
cfg_pmu_percmd_mode[mdlaid][priority] = mode;
|
|
}
|
|
|
|
/* save pmu registers for query after power off */
|
|
void pmu_reg_save(u32 mdlaid, u16 priority)
|
|
{
|
|
u32 val = 0;
|
|
|
|
if (mdla_devices[mdlaid].pmu[priority].pmu_mode == NORMAL)
|
|
l_cmd_cnt[mdlaid][priority] = 1;
|
|
else {
|
|
val = pmu_reg_read_with_mdlaid(mdlaid, PMU_CMDID_LATCH);
|
|
if (val != l_cmd_id[mdlaid][priority])
|
|
l_cmd_cnt[mdlaid][priority]++;
|
|
}
|
|
|
|
l_cmd_id[mdlaid][priority] = (u16)val;
|
|
l_cycle[mdlaid][priority] +=
|
|
pmu_reg_read_with_mdlaid(mdlaid, PMU_CYCLE);
|
|
l_end_t[mdlaid][priority] +=
|
|
pmu_reg_read_with_mdlaid(mdlaid, PMU_END_TSTAMP);
|
|
l_start_t[mdlaid][priority] =
|
|
pmu_reg_read_with_mdlaid(mdlaid, PMU_START_TSTAMP);
|
|
|
|
pmu_counter_read_all(mdlaid, l_counters[mdlaid][priority]);
|
|
}
|
|
|
|
void pmu_reset(u32 mdlaid)
|
|
{
|
|
int i;
|
|
|
|
pmu_reg_write_with_mdlaid(mdlaid, (CFG_PMCR_DEFAULT|
|
|
PMU_PMCR_CCNT_RST|PMU_PMCR_CNT_RST), PMU_CFG_PMCR);
|
|
|
|
while (pmu_reg_read_with_mdlaid(mdlaid, PMU_CFG_PMCR) &
|
|
(PMU_PMCR_CCNT_RST|PMU_PMCR_CNT_RST)) {
|
|
}
|
|
/* reset to 0 */
|
|
for (i = 0; i < MPC; i++)
|
|
pmu_event_write(mdlaid, i, COUNTER_CLEAR);
|
|
/*reset to normal */
|
|
pmu_percmd_mode_write(mdlaid, NORMAL);
|
|
|
|
mdla_pmu_debug("mdla: %s, PMU_CFG_PMCR: 0x%x\n",
|
|
__func__, pmu_reg_read_with_mdlaid(mdlaid, PMU_CFG_PMCR));
|
|
|
|
}
|
|
|
|
void pmu_reset_counter_variable(u32 mdlaid, u16 priority)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < MPC; i++)
|
|
l_counters[mdlaid][priority][i] = 0;
|
|
|
|
l_cmd_id[mdlaid][priority] = 0;
|
|
l_cmd_cnt[mdlaid][priority] = 0;
|
|
}
|
|
|
|
void pmu_reset_cycle_variable(u32 mdlaid, u16 priority)
|
|
{
|
|
l_cycle[mdlaid][priority] = 0;
|
|
l_end_t[mdlaid][priority] = 0;
|
|
l_start_t[mdlaid][priority] = 0;
|
|
}
|
|
|
|
void pmu_init(u32 mdlaid)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < PL; i++)
|
|
cfg_pmu_percmd_mode[mdlaid][i] = NORMAL;
|
|
spin_lock_init(&pmu_lock[mdlaid]);
|
|
}
|
|
|
|
#ifndef __APUSYS_MDLA_SW_PORTING_WORKAROUND__
|
|
int pmu_apusys_pmu_addr_check(struct apusys_cmd_hnd *apusys_hd)
|
|
{
|
|
int ret = 0;
|
|
struct mdla_pmu_hnd *pmu_hnd;
|
|
|
|
if ((apusys_hd == NULL) ||
|
|
(apusys_hd->pmu_kva == apusys_hd->cmd_entry) ||
|
|
(apusys_hd->pmu_kva == 0))
|
|
return ret = -1;
|
|
pmu_hnd = (struct mdla_pmu_hnd *)apusys_hd->pmu_kva;
|
|
if (pmu_hnd->number_of_event > MPC)
|
|
return -1;
|
|
mdla_pmu_debug("command entry:%08llx, pmu kva: %08llx\n",
|
|
apusys_hd->cmd_entry,
|
|
apusys_hd->pmu_kva);
|
|
return ret;
|
|
}
|
|
|
|
/* initial local variable and extract pmu setting from input */
|
|
int pmu_cmd_handle(struct mdla_dev *mdla_info,
|
|
struct apusys_cmd_hnd *apusys_hd, u16 priority)
|
|
{
|
|
int i;
|
|
u32 cid = mdla_info->mdlaid;
|
|
|
|
pmu_reset_counter_variable(mdla_info->mdlaid, priority);
|
|
pmu_reset_cycle_variable(mdla_info->mdlaid, priority);
|
|
|
|
if (!pmu_apusys_pmu_addr_check(apusys_hd)) {
|
|
pmu_percmd_mode_save(mdla_info->mdlaid,
|
|
mdla_info->pmu[priority].pmu_mode, priority);
|
|
number_of_event[priority] =
|
|
mdla_info->pmu[priority].pmu_hnd->number_of_event;
|
|
mdla_pmu_debug("PMU number_of_event:%d, mode: %d\n",
|
|
mdla_info->pmu[priority].pmu_hnd->number_of_event,
|
|
mdla_info->pmu[priority].pmu_mode);
|
|
} else {
|
|
number_of_event[priority] = MPC;
|
|
}
|
|
|
|
if (!cfg_apusys_trace) {
|
|
if (pmu_apusys_pmu_addr_check(apusys_hd)) {
|
|
for (i = 0; i < MPC; i++) {
|
|
pmu_event_handle[cid][priority][i] =
|
|
COUNTER_CLEAR;
|
|
}
|
|
return -1;
|
|
}
|
|
for (i = 0; i < number_of_event[priority]; i++) {
|
|
u32 high =
|
|
mdla_info->pmu[priority].pmu_hnd->event[i];
|
|
u32 low =
|
|
mdla_info->pmu[priority].pmu_hnd->event[i];
|
|
pmu_event_handle[mdla_info->mdlaid][priority][i] =
|
|
((high&0x1f00)<<8) | (low&0xf);
|
|
}
|
|
} else {
|
|
for (i = 0; i < MPC; i++) {
|
|
pmu_event_handle[mdla_info->mdlaid][priority][i] =
|
|
(cfg_pmu_event_trace[i]&0x1f0000) |
|
|
(cfg_pmu_event_trace[i]&0xf);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* extract pmu_hnd form pmu_kva and set mdla_info->pmu */
|
|
int pmu_command_prepare(struct mdla_dev *mdla_info,
|
|
struct apusys_cmd_hnd *apusys_hd, u16 priority)
|
|
{
|
|
mdla_info->pmu[priority].pmu_hnd =
|
|
(struct mdla_pmu_hnd *)apusys_hd->pmu_kva;
|
|
|
|
/*mdla pmu mode switch from ioctl or apusys cmd*/
|
|
if (cfg_pmu_percmd_mode[mdla_info->mdlaid][priority] < CMD_MODE_MAX)
|
|
mdla_info->pmu[priority].pmu_mode =
|
|
cfg_pmu_percmd_mode[mdla_info->mdlaid][priority];
|
|
else
|
|
mdla_info->pmu[priority].pmu_mode =
|
|
mdla_info->pmu[priority].pmu_hnd->mode;
|
|
|
|
if (mdla_info->pmu[priority].pmu_mode >= CMD_MODE_MAX)
|
|
return -1;
|
|
|
|
mdla_info->pmu[priority].cmd_id = apusys_hd->cmd_id;
|
|
|
|
mdla_info->pmu[priority].PMU_res_buf_addr0 = apusys_hd->cmd_entry +
|
|
mdla_info->pmu[priority].pmu_hnd->offset_to_PMU_res_buf0;
|
|
mdla_info->pmu[priority].PMU_res_buf_addr1 = apusys_hd->cmd_entry +
|
|
mdla_info->pmu[priority].pmu_hnd->offset_to_PMU_res_buf1;
|
|
|
|
if (mdla_info->pmu[priority].pmu_mode == PER_CMD)
|
|
cfg_timer_en = 1;
|
|
|
|
mdla_pmu_debug("pmu addr0: %08llx, pmu addr1: %08llx\n",
|
|
mdla_info->pmu[priority].PMU_res_buf_addr0,
|
|
mdla_info->pmu[priority].PMU_res_buf_addr1);
|
|
return 0;
|
|
}
|
|
|
|
/* write pmu setting to register */
|
|
int pmu_set_reg(u32 mdlaid, u16 priority)
|
|
{
|
|
|
|
int i;
|
|
|
|
if (!get_power_on_status(mdlaid))
|
|
return -1;
|
|
|
|
pmu_reg_set_with_mdlaid(mdlaid,
|
|
CFG_PMCR_DEFAULT |
|
|
PMU_PMCR_CNT_RST |
|
|
PMU_PMCR_CCNT_EN |
|
|
PMU_PMCR_CCNT_RST,
|
|
PMU_CFG_PMCR);
|
|
|
|
while (pmu_reg_read_with_mdlaid(mdlaid, PMU_CFG_PMCR) &
|
|
(PMU_PMCR_CNT_RST | PMU_PMCR_CCNT_RST)) {
|
|
}
|
|
|
|
pmu_percmd_mode_write(mdlaid, priority);
|
|
|
|
if (!cfg_apusys_trace) {
|
|
for (i = 0; i < number_of_event[priority]; i++) {
|
|
if (i < MPC)
|
|
pmu_event_write(
|
|
mdlaid,
|
|
i,
|
|
pmu_event_handle[mdlaid][priority][i]);
|
|
else
|
|
pmu_event_write(mdlaid, i, COUNTER_CLEAR);
|
|
}
|
|
} else {
|
|
for (i = 0; i < MPC; i++)
|
|
pmu_event_write(
|
|
mdlaid,
|
|
i,
|
|
pmu_event_handle[mdlaid][priority][i]);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
void pmu_command_counter_prt(
|
|
struct apusys_cmd_hnd *apusys_hd,
|
|
struct mdla_dev *mdla_info,
|
|
u16 priority,
|
|
struct command_entry *ce)
|
|
{
|
|
int i;
|
|
struct mdla_pmu_result result;
|
|
struct mdla_pmu_result check;
|
|
void *base = NULL, *desc = NULL, *src = NULL;
|
|
uint32_t sz = 0;
|
|
uint16_t event_num = 0;
|
|
int offset = 0;
|
|
u16 final_len = 0;
|
|
u16 loop_count =
|
|
mdla_info->pmu[priority].pmu_hnd->number_of_event;
|
|
u32 cid = mdla_info->mdlaid;
|
|
uint32_t repeat_sz = 0;
|
|
uint32_t out_sz = 0;
|
|
uint32_t out_length = 0;
|
|
|
|
result.cmd_len = l_cmd_cnt[mdla_info->mdlaid][priority];
|
|
result.cmd_id = pmu_get_perf_cmdid(mdla_info->mdlaid, priority);
|
|
event_num = mdla_info->pmu[priority].pmu_hnd->number_of_event + 1;
|
|
|
|
sz = sizeof(u16) * 2 + sizeof(u32) * event_num;
|
|
repeat_sz = sz - sizeof(u16);
|
|
|
|
if (mdla_info->mdlaid == 0) {
|
|
base = (void *)mdla_info->pmu[priority].PMU_res_buf_addr0;
|
|
out_sz = apusys_hd->cmd_entry -
|
|
mdla_info->pmu[priority].PMU_res_buf_addr0 +
|
|
apusys_hd->cmd_size;
|
|
} else {
|
|
mdla_pmu_debug("unknown mdlaid: %d\n", mdla_info->mdlaid);
|
|
return;
|
|
}
|
|
if (apusys_hd->cmd_entry > (uint64_t)base)
|
|
return;
|
|
if ((uint64_t)base > (apusys_hd->cmd_entry + apusys_hd->cmd_size))
|
|
return;
|
|
if (out_sz < sizeof(uint16_t))
|
|
return;
|
|
out_length = (out_sz - sizeof(uint16_t)) / repeat_sz;
|
|
if (loop_count > MDLA_PMU_COUNTERS)
|
|
return;
|
|
if (mdla_info->pmu[priority].pmu_mode == PER_CMD) {
|
|
if (ce->count > out_length)
|
|
return;
|
|
} else if (mdla_info->pmu[priority].pmu_mode == NORMAL) {
|
|
if (out_sz < sz)
|
|
return;
|
|
}
|
|
|
|
mdla_pmu_debug("mode: %d, cmd_len: %d, cmd_id: %d, sz: %d\n",
|
|
mdla_info->pmu[priority].pmu_hnd->mode,
|
|
result.cmd_len, result.cmd_id, sz);
|
|
|
|
if (mdla_info->pmu[priority].pmu_mode == PER_CMD)
|
|
result.pmu_val[0] =
|
|
pmu_get_perf_end(mdla_info->mdlaid, priority);
|
|
else
|
|
result.pmu_val[0] =
|
|
pmu_get_perf_cycle(mdla_info->mdlaid, priority);
|
|
|
|
mdla_pmu_debug("global counter:%08x\n", result.pmu_val[0]);
|
|
|
|
for (i = 0; i < loop_count; i++) {
|
|
result.pmu_val[i + 1] =
|
|
pmu_counter_get(mdla_info->mdlaid,
|
|
pmu_event_handle[cid][priority][i],
|
|
priority);
|
|
mdla_pmu_debug("event %d cnt :%08x\n",
|
|
(i + 1), result.pmu_val[i + 1]);
|
|
}
|
|
|
|
/* update pmu result buffer */
|
|
if (result.cmd_len == 1) {
|
|
desc = base;
|
|
src = &result;
|
|
memcpy(desc, src, sz);
|
|
} else if (result.cmd_len > 1) {
|
|
offset = sz + (result.cmd_len - 2) * (sz - sizeof(u16));
|
|
desc = (void *)(base + offset);
|
|
src = (void *)&(result.cmd_id);
|
|
memcpy(desc, src, sz - sizeof(u16));
|
|
}
|
|
|
|
if (result.cmd_id == mdla_info->max_cmd_id) {
|
|
final_len = result.cmd_len;
|
|
desc = base;
|
|
memcpy(desc, &final_len, sizeof(u16));
|
|
if (unlikely(mdla_klog&MDLA_DBG_PMU)) {
|
|
memcpy(&check, desc, sz);
|
|
|
|
mdla_pmu_debug("[-] check cmd_len: %d\n",
|
|
check.cmd_len);
|
|
mdla_pmu_debug("[-] check cmd_id: %d\n",
|
|
check.cmd_id);
|
|
mdla_pmu_debug("[-] check cmd_val[1]: %08x\n",
|
|
check.pmu_val[1]);
|
|
|
|
if (result.cmd_len > 1) {
|
|
offset =
|
|
sz +
|
|
(result.cmd_len - 2) *
|
|
(sz - sizeof(u16));
|
|
desc = (void *)(base + offset);
|
|
memcpy(
|
|
(void *)&(check.cmd_id),
|
|
desc,
|
|
sz - sizeof(u16));
|
|
|
|
mdla_pmu_debug("[-] offset: %d\n", offset);
|
|
mdla_pmu_debug("[-] check cmd_id: %d\n",
|
|
check.cmd_id);
|
|
mdla_pmu_debug("[-] check cmd_val[1]: %08x\n",
|
|
check.pmu_val[1]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|