// SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
|
/*
|
*
|
* (C) COPYRIGHT 2016-2023 ARM Limited. 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 <linux/thermal.h>
|
|
#include "mali_kbase_ipa_counter_common_jm.h"
|
#include "mali_kbase.h"
|
#include <backend/gpu/mali_kbase_model_linux.h>
|
|
/* Performance counter blocks base offsets */
|
#define JM_BASE (0 * KBASE_IPA_NR_BYTES_PER_BLOCK)
|
#define MEMSYS_BASE (2 * KBASE_IPA_NR_BYTES_PER_BLOCK)
|
|
/* JM counter block offsets */
|
#define JM_GPU_ACTIVE (KBASE_IPA_NR_BYTES_PER_CNT * 6)
|
|
/* MEMSYS counter block offsets */
|
#define MEMSYS_L2_ANY_LOOKUP (KBASE_IPA_NR_BYTES_PER_CNT * 25)
|
|
/* SC counter block offsets */
|
#define SC_EXEC_INSTR_FMA (KBASE_IPA_NR_BYTES_PER_CNT * 27)
|
#define SC_EXEC_INSTR_COUNT (KBASE_IPA_NR_BYTES_PER_CNT * 28)
|
#define SC_EXEC_INSTR_MSG (KBASE_IPA_NR_BYTES_PER_CNT * 30)
|
#define SC_TEX_FILT_NUM_OPERATIONS (KBASE_IPA_NR_BYTES_PER_CNT * 39)
|
#define SC_TEX_COORD_ISSUE (KBASE_IPA_NR_BYTES_PER_CNT * 40)
|
#define SC_TEX_TFCH_NUM_OPERATIONS (KBASE_IPA_NR_BYTES_PER_CNT * 42)
|
#define SC_VARY_INSTR (KBASE_IPA_NR_BYTES_PER_CNT * 49)
|
#define SC_BEATS_WR_TIB (KBASE_IPA_NR_BYTES_PER_CNT * 62)
|
|
/**
|
* kbase_g7x_power_model_get_jm_counter() - get performance counter offset
|
* inside the Job Manager block
|
* @model_data: pointer to GPU model data.
|
* @counter_block_offset: offset in bytes of the performance counter inside
|
* the Job Manager block.
|
*
|
* Return: Block offset in bytes of the required performance counter.
|
*/
|
static u32 kbase_g7x_power_model_get_jm_counter(struct kbase_ipa_model_vinstr_data *model_data,
|
u32 counter_block_offset)
|
{
|
return JM_BASE + counter_block_offset;
|
}
|
|
/**
|
* kbase_g7x_power_model_get_memsys_counter() - get performance counter offset
|
* inside the Memory System block
|
* @model_data: pointer to GPU model data.
|
* @counter_block_offset: offset in bytes of the performance counter inside
|
* the (first) Memory System block.
|
*
|
* Return: Block offset in bytes of the required performance counter.
|
*/
|
static u32 kbase_g7x_power_model_get_memsys_counter(struct kbase_ipa_model_vinstr_data *model_data,
|
u32 counter_block_offset)
|
{
|
/* The base address of Memory System performance counters is always the same, although their number
|
* may vary based on the number of cores. For the moment it's ok to return a constant.
|
*/
|
return MEMSYS_BASE + counter_block_offset;
|
}
|
|
/**
|
* kbase_g7x_power_model_get_sc_counter() - get performance counter offset
|
* inside the Shader Cores block
|
* @model_data: pointer to GPU model data.
|
* @counter_block_offset: offset in bytes of the performance counter inside
|
* the (first) Shader Cores block.
|
*
|
* Return: Block offset in bytes of the required performance counter.
|
*/
|
static u32 kbase_g7x_power_model_get_sc_counter(struct kbase_ipa_model_vinstr_data *model_data,
|
u32 counter_block_offset)
|
{
|
#if IS_ENABLED(CONFIG_MALI_BIFROST_NO_MALI)
|
const u32 sc_base = MEMSYS_BASE +
|
(KBASE_DUMMY_MODEL_MAX_MEMSYS_BLOCKS *
|
KBASE_IPA_NR_BYTES_PER_BLOCK);
|
#else
|
const u32 sc_base = MEMSYS_BASE +
|
(model_data->kbdev->gpu_props.props.l2_props.num_l2_slices *
|
KBASE_IPA_NR_BYTES_PER_BLOCK);
|
#endif
|
return sc_base + counter_block_offset;
|
}
|
|
/**
|
* kbase_g7x_sum_all_memsys_blocks() - calculate energy for a single Memory
|
* System performance counter.
|
* @model_data: pointer to GPU model data.
|
* @coeff: default value of coefficient for IPA group.
|
* @counter_block_offset: offset in bytes of the counter inside the block it
|
* belongs to.
|
*
|
* Return: Energy estimation for a single Memory System performance counter.
|
*/
|
static s64 kbase_g7x_sum_all_memsys_blocks(
|
struct kbase_ipa_model_vinstr_data *model_data,
|
s32 coeff,
|
u32 counter_block_offset)
|
{
|
u32 counter;
|
|
counter = kbase_g7x_power_model_get_memsys_counter(model_data,
|
counter_block_offset);
|
return kbase_ipa_sum_all_memsys_blocks(model_data, coeff, counter);
|
}
|
|
/**
|
* kbase_g7x_sum_all_shader_cores() - calculate energy for a Shader Cores
|
* performance counter for all cores.
|
* @model_data: pointer to GPU model data.
|
* @coeff: default value of coefficient for IPA group.
|
* @counter_block_offset: offset in bytes of the counter inside the block it
|
* belongs to.
|
*
|
* Return: Energy estimation for a Shader Cores performance counter for all
|
* cores.
|
*/
|
static s64 kbase_g7x_sum_all_shader_cores(
|
struct kbase_ipa_model_vinstr_data *model_data,
|
s32 coeff,
|
u32 counter_block_offset)
|
{
|
u32 counter;
|
|
counter = kbase_g7x_power_model_get_sc_counter(model_data,
|
counter_block_offset);
|
return kbase_ipa_sum_all_shader_cores(model_data, coeff, counter);
|
}
|
|
/**
|
* kbase_g7x_jm_single_counter() - calculate energy for a single Job Manager performance counter.
|
* @model_data: pointer to GPU model data.
|
* @coeff: default value of coefficient for IPA group.
|
* @counter_block_offset: offset in bytes of the counter inside the block it belongs to.
|
*
|
* Return: Energy estimation for a single Job Manager performance counter.
|
*/
|
static s64 kbase_g7x_jm_single_counter(
|
struct kbase_ipa_model_vinstr_data *model_data,
|
s32 coeff,
|
u32 counter_block_offset)
|
{
|
u32 counter;
|
|
counter = kbase_g7x_power_model_get_jm_counter(model_data,
|
counter_block_offset);
|
return kbase_ipa_single_counter(model_data, coeff, counter);
|
}
|
|
/**
|
* kbase_g7x_get_active_cycles() - return the GPU_ACTIVE counter
|
* @model_data: pointer to GPU model data.
|
*
|
* Return: the number of cycles the GPU was active during the counter sampling
|
* period.
|
*/
|
static u32 kbase_g7x_get_active_cycles(
|
struct kbase_ipa_model_vinstr_data *model_data)
|
{
|
u32 counter = kbase_g7x_power_model_get_jm_counter(model_data, JM_GPU_ACTIVE);
|
|
/* Counters are only 32-bit, so we can safely multiply by 1 then cast
|
* the 64-bit result back to a u32.
|
*/
|
return kbase_ipa_single_counter(model_data, 1, counter);
|
}
|
|
/* Table of IPA group definitions.
|
*
|
* For each IPA group, this table defines a function to access the given performance block counter (or counters,
|
* if the operation needs to be iterated on multiple blocks) and calculate energy estimation.
|
*/
|
|
static const struct kbase_ipa_group ipa_groups_def_g71[] = {
|
{
|
.name = "l2_access",
|
.default_value = 526300,
|
.op = kbase_g7x_sum_all_memsys_blocks,
|
.counter_block_offset = MEMSYS_L2_ANY_LOOKUP,
|
},
|
{
|
.name = "exec_instr_count",
|
.default_value = 301100,
|
.op = kbase_g7x_sum_all_shader_cores,
|
.counter_block_offset = SC_EXEC_INSTR_COUNT,
|
},
|
{
|
.name = "tex_issue",
|
.default_value = 197400,
|
.op = kbase_g7x_sum_all_shader_cores,
|
.counter_block_offset = SC_TEX_COORD_ISSUE,
|
},
|
{
|
.name = "tile_wb",
|
.default_value = -156400,
|
.op = kbase_g7x_sum_all_shader_cores,
|
.counter_block_offset = SC_BEATS_WR_TIB,
|
},
|
{
|
.name = "gpu_active",
|
.default_value = 115800,
|
.op = kbase_g7x_jm_single_counter,
|
.counter_block_offset = JM_GPU_ACTIVE,
|
},
|
};
|
|
static const struct kbase_ipa_group ipa_groups_def_g72[] = {
|
{
|
.name = "l2_access",
|
.default_value = 393000,
|
.op = kbase_g7x_sum_all_memsys_blocks,
|
.counter_block_offset = MEMSYS_L2_ANY_LOOKUP,
|
},
|
{
|
.name = "exec_instr_count",
|
.default_value = 227000,
|
.op = kbase_g7x_sum_all_shader_cores,
|
.counter_block_offset = SC_EXEC_INSTR_COUNT,
|
},
|
{
|
.name = "tex_issue",
|
.default_value = 181900,
|
.op = kbase_g7x_sum_all_shader_cores,
|
.counter_block_offset = SC_TEX_COORD_ISSUE,
|
},
|
{
|
.name = "tile_wb",
|
.default_value = -120200,
|
.op = kbase_g7x_sum_all_shader_cores,
|
.counter_block_offset = SC_BEATS_WR_TIB,
|
},
|
{
|
.name = "gpu_active",
|
.default_value = 133100,
|
.op = kbase_g7x_jm_single_counter,
|
.counter_block_offset = JM_GPU_ACTIVE,
|
},
|
};
|
|
static const struct kbase_ipa_group ipa_groups_def_g76[] = {
|
{
|
.name = "gpu_active",
|
.default_value = 122000,
|
.op = kbase_g7x_jm_single_counter,
|
.counter_block_offset = JM_GPU_ACTIVE,
|
},
|
{
|
.name = "exec_instr_count",
|
.default_value = 488900,
|
.op = kbase_g7x_sum_all_shader_cores,
|
.counter_block_offset = SC_EXEC_INSTR_COUNT,
|
},
|
{
|
.name = "vary_instr",
|
.default_value = 212100,
|
.op = kbase_g7x_sum_all_shader_cores,
|
.counter_block_offset = SC_VARY_INSTR,
|
},
|
{
|
.name = "tex_tfch_num_operations",
|
.default_value = 288000,
|
.op = kbase_g7x_sum_all_shader_cores,
|
.counter_block_offset = SC_TEX_TFCH_NUM_OPERATIONS,
|
},
|
{
|
.name = "l2_access",
|
.default_value = 378100,
|
.op = kbase_g7x_sum_all_memsys_blocks,
|
.counter_block_offset = MEMSYS_L2_ANY_LOOKUP,
|
},
|
};
|
|
static const struct kbase_ipa_group ipa_groups_def_g52_r1[] = {
|
{
|
.name = "gpu_active",
|
.default_value = 224200,
|
.op = kbase_g7x_jm_single_counter,
|
.counter_block_offset = JM_GPU_ACTIVE,
|
},
|
{
|
.name = "exec_instr_count",
|
.default_value = 384700,
|
.op = kbase_g7x_sum_all_shader_cores,
|
.counter_block_offset = SC_EXEC_INSTR_COUNT,
|
},
|
{
|
.name = "vary_instr",
|
.default_value = 271900,
|
.op = kbase_g7x_sum_all_shader_cores,
|
.counter_block_offset = SC_VARY_INSTR,
|
},
|
{
|
.name = "tex_tfch_num_operations",
|
.default_value = 477700,
|
.op = kbase_g7x_sum_all_shader_cores,
|
.counter_block_offset = SC_TEX_TFCH_NUM_OPERATIONS,
|
},
|
{
|
.name = "l2_access",
|
.default_value = 551400,
|
.op = kbase_g7x_sum_all_memsys_blocks,
|
.counter_block_offset = MEMSYS_L2_ANY_LOOKUP,
|
},
|
};
|
|
static const struct kbase_ipa_group ipa_groups_def_g51[] = {
|
{
|
.name = "gpu_active",
|
.default_value = 201400,
|
.op = kbase_g7x_jm_single_counter,
|
.counter_block_offset = JM_GPU_ACTIVE,
|
},
|
{
|
.name = "exec_instr_count",
|
.default_value = 392700,
|
.op = kbase_g7x_sum_all_shader_cores,
|
.counter_block_offset = SC_EXEC_INSTR_COUNT,
|
},
|
{
|
.name = "vary_instr",
|
.default_value = 274000,
|
.op = kbase_g7x_sum_all_shader_cores,
|
.counter_block_offset = SC_VARY_INSTR,
|
},
|
{
|
.name = "tex_tfch_num_operations",
|
.default_value = 528000,
|
.op = kbase_g7x_sum_all_shader_cores,
|
.counter_block_offset = SC_TEX_TFCH_NUM_OPERATIONS,
|
},
|
{
|
.name = "l2_access",
|
.default_value = 506400,
|
.op = kbase_g7x_sum_all_memsys_blocks,
|
.counter_block_offset = MEMSYS_L2_ANY_LOOKUP,
|
},
|
};
|
|
static const struct kbase_ipa_group ipa_groups_def_g77[] = {
|
{
|
.name = "l2_access",
|
.default_value = 710800,
|
.op = kbase_g7x_sum_all_memsys_blocks,
|
.counter_block_offset = MEMSYS_L2_ANY_LOOKUP,
|
},
|
{
|
.name = "exec_instr_msg",
|
.default_value = 2375300,
|
.op = kbase_g7x_sum_all_shader_cores,
|
.counter_block_offset = SC_EXEC_INSTR_MSG,
|
},
|
{
|
.name = "exec_instr_fma",
|
.default_value = 656100,
|
.op = kbase_g7x_sum_all_shader_cores,
|
.counter_block_offset = SC_EXEC_INSTR_FMA,
|
},
|
{
|
.name = "tex_filt_num_operations",
|
.default_value = 318800,
|
.op = kbase_g7x_sum_all_shader_cores,
|
.counter_block_offset = SC_TEX_FILT_NUM_OPERATIONS,
|
},
|
{
|
.name = "gpu_active",
|
.default_value = 172800,
|
.op = kbase_g7x_jm_single_counter,
|
.counter_block_offset = JM_GPU_ACTIVE,
|
},
|
};
|
|
static const struct kbase_ipa_group ipa_groups_def_tbex[] = {
|
{
|
.name = "l2_access",
|
.default_value = 599800,
|
.op = kbase_g7x_sum_all_memsys_blocks,
|
.counter_block_offset = MEMSYS_L2_ANY_LOOKUP,
|
},
|
{
|
.name = "exec_instr_msg",
|
.default_value = 1830200,
|
.op = kbase_g7x_sum_all_shader_cores,
|
.counter_block_offset = SC_EXEC_INSTR_MSG,
|
},
|
{
|
.name = "exec_instr_fma",
|
.default_value = 407300,
|
.op = kbase_g7x_sum_all_shader_cores,
|
.counter_block_offset = SC_EXEC_INSTR_FMA,
|
},
|
{
|
.name = "tex_filt_num_operations",
|
.default_value = 224500,
|
.op = kbase_g7x_sum_all_shader_cores,
|
.counter_block_offset = SC_TEX_FILT_NUM_OPERATIONS,
|
},
|
{
|
.name = "gpu_active",
|
.default_value = 153800,
|
.op = kbase_g7x_jm_single_counter,
|
.counter_block_offset = JM_GPU_ACTIVE,
|
},
|
};
|
|
static const struct kbase_ipa_group ipa_groups_def_tbax[] = {
|
{
|
.name = "l2_access",
|
.default_value = 599800,
|
.op = kbase_g7x_sum_all_memsys_blocks,
|
.counter_block_offset = MEMSYS_L2_ANY_LOOKUP,
|
},
|
{
|
.name = "exec_instr_msg",
|
.default_value = 1830200,
|
.op = kbase_g7x_sum_all_shader_cores,
|
.counter_block_offset = SC_EXEC_INSTR_MSG,
|
},
|
{
|
.name = "exec_instr_fma",
|
.default_value = 407300,
|
.op = kbase_g7x_sum_all_shader_cores,
|
.counter_block_offset = SC_EXEC_INSTR_FMA,
|
},
|
{
|
.name = "tex_filt_num_operations",
|
.default_value = 224500,
|
.op = kbase_g7x_sum_all_shader_cores,
|
.counter_block_offset = SC_TEX_FILT_NUM_OPERATIONS,
|
},
|
{
|
.name = "gpu_active",
|
.default_value = 153800,
|
.op = kbase_g7x_jm_single_counter,
|
.counter_block_offset = JM_GPU_ACTIVE,
|
},
|
};
|
|
#define IPA_POWER_MODEL_OPS(gpu, init_token) \
|
static const struct kbase_ipa_model_ops kbase_##gpu##_ipa_model_ops = { \
|
.name = "mali-" #gpu "-power-model", \
|
.init = kbase_##init_token##_power_model_init, \
|
.term = kbase_ipa_vinstr_common_model_term, \
|
.get_dynamic_coeff = kbase_ipa_vinstr_dynamic_coeff, \
|
.reset_counter_data = kbase_ipa_vinstr_reset_data, \
|
}
|
|
#define STANDARD_POWER_MODEL(gpu, reference_voltage) \
|
static int kbase_ ## gpu ## _power_model_init(\
|
struct kbase_ipa_model *model) \
|
{ \
|
BUILD_BUG_ON(ARRAY_SIZE(ipa_groups_def_ ## gpu) > \
|
KBASE_IPA_MAX_GROUP_DEF_NUM); \
|
return kbase_ipa_vinstr_common_model_init(model, \
|
ipa_groups_def_ ## gpu, \
|
ARRAY_SIZE(ipa_groups_def_ ## gpu), \
|
kbase_g7x_get_active_cycles, \
|
(reference_voltage)); \
|
} \
|
IPA_POWER_MODEL_OPS(gpu, gpu)
|
|
#define ALIAS_POWER_MODEL(gpu, as_gpu) \
|
IPA_POWER_MODEL_OPS(gpu, as_gpu)
|
|
STANDARD_POWER_MODEL(g71, 800);
|
STANDARD_POWER_MODEL(g72, 800);
|
STANDARD_POWER_MODEL(g76, 800);
|
STANDARD_POWER_MODEL(g52_r1, 1000);
|
STANDARD_POWER_MODEL(g51, 1000);
|
STANDARD_POWER_MODEL(g77, 1000);
|
STANDARD_POWER_MODEL(tbex, 1000);
|
STANDARD_POWER_MODEL(tbax, 1000);
|
|
/* g52 is an alias of g76 (TNOX) for IPA */
|
ALIAS_POWER_MODEL(g52, g76);
|
/* tnax is an alias of g77 (TTRX) for IPA */
|
ALIAS_POWER_MODEL(tnax, g77);
|
|
static const struct kbase_ipa_model_ops *ipa_counter_model_ops[] = {
|
&kbase_g71_ipa_model_ops,
|
&kbase_g72_ipa_model_ops,
|
&kbase_g76_ipa_model_ops,
|
&kbase_g52_ipa_model_ops,
|
&kbase_g52_r1_ipa_model_ops,
|
&kbase_g51_ipa_model_ops,
|
&kbase_g77_ipa_model_ops,
|
&kbase_tnax_ipa_model_ops,
|
&kbase_tbex_ipa_model_ops,
|
&kbase_tbax_ipa_model_ops
|
};
|
|
const struct kbase_ipa_model_ops *kbase_ipa_counter_model_ops_find(
|
struct kbase_device *kbdev, const char *name)
|
{
|
int i;
|
|
for (i = 0; i < ARRAY_SIZE(ipa_counter_model_ops); ++i) {
|
const struct kbase_ipa_model_ops *ops =
|
ipa_counter_model_ops[i];
|
|
if (!strcmp(ops->name, name))
|
return ops;
|
}
|
|
dev_err(kbdev->dev, "power model \'%s\' not found\n", name);
|
|
return NULL;
|
}
|
|
const char *kbase_ipa_counter_model_name_from_id(u32 gpu_id)
|
{
|
const u32 prod_id =
|
(gpu_id & GPU_ID_VERSION_PRODUCT_ID) >> KBASE_GPU_ID_VERSION_PRODUCT_ID_SHIFT;
|
|
switch (GPU_ID2_MODEL_MATCH_VALUE(prod_id)) {
|
case GPU_ID2_PRODUCT_TMIX:
|
return "mali-g71-power-model";
|
case GPU_ID2_PRODUCT_THEX:
|
return "mali-g72-power-model";
|
case GPU_ID2_PRODUCT_TNOX:
|
return "mali-g76-power-model";
|
case GPU_ID2_PRODUCT_TSIX:
|
return "mali-g51-power-model";
|
case GPU_ID2_PRODUCT_TGOX:
|
if ((gpu_id & GPU_ID2_VERSION_MAJOR) ==
|
(0 << GPU_ID2_VERSION_MAJOR_SHIFT))
|
/* g52 aliased to g76 power-model's ops */
|
return "mali-g52-power-model";
|
else
|
return "mali-g52_r1-power-model";
|
case GPU_ID2_PRODUCT_TNAX:
|
return "mali-tnax-power-model";
|
case GPU_ID2_PRODUCT_TTRX:
|
return "mali-g77-power-model";
|
case GPU_ID2_PRODUCT_TBEX:
|
return "mali-tbex-power-model";
|
case GPU_ID2_PRODUCT_TBAX:
|
return "mali-tbax-power-model";
|
default:
|
return NULL;
|
}
|
}
|