mirror of https://gitee.com/openkylin/linux.git
drm/amdgpu: fix xgmi perfmon a-b-a problem
Mapping hw counters per event config will cause ABA problems so map per event instead. v2: Discontinue starting perf counters if add fails. Make it clear what's happening with pmc_start. Signed-off-by: Jonathan Kim <jonathan.kim@amd.com> Reviewed-by: Harish Kasiviswanathan <harish.kasiviswanathan@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
4b74ed75ae
commit
576e0ec26b
|
@ -44,11 +44,11 @@ struct amdgpu_df_funcs {
|
|||
void (*enable_ecc_force_par_wr_rmw)(struct amdgpu_device *adev,
|
||||
bool enable);
|
||||
int (*pmc_start)(struct amdgpu_device *adev, uint64_t config,
|
||||
int is_add);
|
||||
int counter_idx, int is_add);
|
||||
int (*pmc_stop)(struct amdgpu_device *adev, uint64_t config,
|
||||
int is_remove);
|
||||
int counter_idx, int is_remove);
|
||||
void (*pmc_get_count)(struct amdgpu_device *adev, uint64_t config,
|
||||
uint64_t *count);
|
||||
int counter_idx, uint64_t *count);
|
||||
uint64_t (*get_fica)(struct amdgpu_device *adev, uint32_t ficaa_val);
|
||||
void (*set_fica)(struct amdgpu_device *adev, uint32_t ficaa_val,
|
||||
uint32_t ficadl_val, uint32_t ficadh_val);
|
||||
|
|
|
@ -64,6 +64,7 @@ static void amdgpu_perf_start(struct perf_event *event, int flags)
|
|||
struct amdgpu_pmu_entry *pe = container_of(event->pmu,
|
||||
struct amdgpu_pmu_entry,
|
||||
pmu);
|
||||
int target_cntr = 0;
|
||||
|
||||
if (WARN_ON_ONCE(!(hwc->state & PERF_HES_STOPPED)))
|
||||
return;
|
||||
|
@ -73,17 +74,24 @@ static void amdgpu_perf_start(struct perf_event *event, int flags)
|
|||
|
||||
switch (pe->pmu_perf_type) {
|
||||
case PERF_TYPE_AMDGPU_DF:
|
||||
if (!(flags & PERF_EF_RELOAD))
|
||||
pe->adev->df.funcs->pmc_start(pe->adev, hwc->config, 1);
|
||||
if (!(flags & PERF_EF_RELOAD)) {
|
||||
target_cntr = pe->adev->df.funcs->pmc_start(pe->adev,
|
||||
hwc->config, 0 /* unused */,
|
||||
1 /* add counter */);
|
||||
if (target_cntr < 0)
|
||||
break;
|
||||
|
||||
pe->adev->df.funcs->pmc_start(pe->adev, hwc->config, 0);
|
||||
hwc->idx = target_cntr;
|
||||
}
|
||||
|
||||
pe->adev->df.funcs->pmc_start(pe->adev, hwc->config,
|
||||
hwc->idx, 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
perf_event_update_userpage(event);
|
||||
|
||||
}
|
||||
|
||||
/* read perf counter */
|
||||
|
@ -101,8 +109,8 @@ static void amdgpu_perf_read(struct perf_event *event)
|
|||
|
||||
switch (pe->pmu_perf_type) {
|
||||
case PERF_TYPE_AMDGPU_DF:
|
||||
pe->adev->df.funcs->pmc_get_count(pe->adev, hwc->config,
|
||||
&count);
|
||||
pe->adev->df.funcs->pmc_get_count(pe->adev,
|
||||
hwc->config, hwc->idx, &count);
|
||||
break;
|
||||
default:
|
||||
count = 0;
|
||||
|
@ -126,7 +134,8 @@ static void amdgpu_perf_stop(struct perf_event *event, int flags)
|
|||
|
||||
switch (pe->pmu_perf_type) {
|
||||
case PERF_TYPE_AMDGPU_DF:
|
||||
pe->adev->df.funcs->pmc_stop(pe->adev, hwc->config, 0);
|
||||
pe->adev->df.funcs->pmc_stop(pe->adev, hwc->config, hwc->idx,
|
||||
0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -146,8 +155,7 @@ static void amdgpu_perf_stop(struct perf_event *event, int flags)
|
|||
static int amdgpu_perf_add(struct perf_event *event, int flags)
|
||||
{
|
||||
struct hw_perf_event *hwc = &event->hw;
|
||||
int retval;
|
||||
|
||||
int retval = 0, target_cntr;
|
||||
struct amdgpu_pmu_entry *pe = container_of(event->pmu,
|
||||
struct amdgpu_pmu_entry,
|
||||
pmu);
|
||||
|
@ -156,8 +164,14 @@ static int amdgpu_perf_add(struct perf_event *event, int flags)
|
|||
|
||||
switch (pe->pmu_perf_type) {
|
||||
case PERF_TYPE_AMDGPU_DF:
|
||||
retval = pe->adev->df.funcs->pmc_start(pe->adev,
|
||||
hwc->config, 1);
|
||||
target_cntr = pe->adev->df.funcs->pmc_start(pe->adev,
|
||||
hwc->config, 0 /* unused */,
|
||||
1 /* add counter */);
|
||||
if (target_cntr < 0)
|
||||
retval = target_cntr;
|
||||
else
|
||||
hwc->idx = target_cntr;
|
||||
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
|
@ -170,7 +184,6 @@ static int amdgpu_perf_add(struct perf_event *event, int flags)
|
|||
amdgpu_perf_start(event, PERF_EF_RELOAD);
|
||||
|
||||
return retval;
|
||||
|
||||
}
|
||||
|
||||
/* delete perf counter */
|
||||
|
@ -185,7 +198,8 @@ static void amdgpu_perf_del(struct perf_event *event, int flags)
|
|||
|
||||
switch (pe->pmu_perf_type) {
|
||||
case PERF_TYPE_AMDGPU_DF:
|
||||
pe->adev->df.funcs->pmc_stop(pe->adev, hwc->config, 1);
|
||||
pe->adev->df.funcs->pmc_stop(pe->adev, hwc->config, hwc->idx,
|
||||
1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -391,33 +391,28 @@ static void df_v3_6_get_clockgating_state(struct amdgpu_device *adev,
|
|||
}
|
||||
|
||||
/* get assigned df perfmon ctr as int */
|
||||
static int df_v3_6_pmc_config_2_cntr(struct amdgpu_device *adev,
|
||||
uint64_t config)
|
||||
static bool df_v3_6_pmc_has_counter(struct amdgpu_device *adev,
|
||||
uint64_t config,
|
||||
int counter_idx)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < DF_V3_6_MAX_COUNTERS; i++) {
|
||||
if ((config & 0x0FFFFFFUL) ==
|
||||
adev->df_perfmon_config_assign_mask[i])
|
||||
return i;
|
||||
}
|
||||
return ((config & 0x0FFFFFFUL) ==
|
||||
adev->df_perfmon_config_assign_mask[counter_idx]);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* get address based on counter assignment */
|
||||
static void df_v3_6_pmc_get_addr(struct amdgpu_device *adev,
|
||||
uint64_t config,
|
||||
int counter_idx,
|
||||
int is_ctrl,
|
||||
uint32_t *lo_base_addr,
|
||||
uint32_t *hi_base_addr)
|
||||
{
|
||||
int target_cntr = df_v3_6_pmc_config_2_cntr(adev, config);
|
||||
|
||||
if (target_cntr < 0)
|
||||
if (!df_v3_6_pmc_has_counter(adev, config, counter_idx))
|
||||
return;
|
||||
|
||||
switch (target_cntr) {
|
||||
switch (counter_idx) {
|
||||
|
||||
case 0:
|
||||
*lo_base_addr = is_ctrl ? smnPerfMonCtlLo4 : smnPerfMonCtrLo4;
|
||||
|
@ -443,15 +438,18 @@ static void df_v3_6_pmc_get_addr(struct amdgpu_device *adev,
|
|||
/* get read counter address */
|
||||
static void df_v3_6_pmc_get_read_settings(struct amdgpu_device *adev,
|
||||
uint64_t config,
|
||||
int counter_idx,
|
||||
uint32_t *lo_base_addr,
|
||||
uint32_t *hi_base_addr)
|
||||
{
|
||||
df_v3_6_pmc_get_addr(adev, config, 0, lo_base_addr, hi_base_addr);
|
||||
df_v3_6_pmc_get_addr(adev, config, counter_idx, 0, lo_base_addr,
|
||||
hi_base_addr);
|
||||
}
|
||||
|
||||
/* get control counter settings i.e. address and values to set */
|
||||
static int df_v3_6_pmc_get_ctrl_settings(struct amdgpu_device *adev,
|
||||
uint64_t config,
|
||||
int counter_idx,
|
||||
uint32_t *lo_base_addr,
|
||||
uint32_t *hi_base_addr,
|
||||
uint32_t *lo_val,
|
||||
|
@ -462,7 +460,8 @@ static int df_v3_6_pmc_get_ctrl_settings(struct amdgpu_device *adev,
|
|||
uint32_t eventsel, instance, unitmask;
|
||||
uint32_t instance_10, instance_5432, instance_76;
|
||||
|
||||
df_v3_6_pmc_get_addr(adev, config, 1, lo_base_addr, hi_base_addr);
|
||||
df_v3_6_pmc_get_addr(adev, config, counter_idx, 1, lo_base_addr,
|
||||
hi_base_addr);
|
||||
|
||||
if ((*lo_base_addr == 0) || (*hi_base_addr == 0)) {
|
||||
DRM_ERROR("[DF PMC] addressing not retrieved! Lo: %x, Hi: %x",
|
||||
|
@ -492,18 +491,13 @@ static int df_v3_6_pmc_get_ctrl_settings(struct amdgpu_device *adev,
|
|||
static int df_v3_6_pmc_add_cntr(struct amdgpu_device *adev,
|
||||
uint64_t config)
|
||||
{
|
||||
int i, target_cntr;
|
||||
|
||||
target_cntr = df_v3_6_pmc_config_2_cntr(adev, config);
|
||||
|
||||
if (target_cntr >= 0)
|
||||
return 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < DF_V3_6_MAX_COUNTERS; i++) {
|
||||
if (adev->df_perfmon_config_assign_mask[i] == 0U) {
|
||||
adev->df_perfmon_config_assign_mask[i] =
|
||||
config & 0x0FFFFFFUL;
|
||||
return 0;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -512,59 +506,50 @@ static int df_v3_6_pmc_add_cntr(struct amdgpu_device *adev,
|
|||
|
||||
#define DEFERRED_ARM_MASK (1 << 31)
|
||||
static int df_v3_6_pmc_set_deferred(struct amdgpu_device *adev,
|
||||
uint64_t config, bool is_deferred)
|
||||
int counter_idx, uint64_t config,
|
||||
bool is_deferred)
|
||||
{
|
||||
int target_cntr;
|
||||
|
||||
target_cntr = df_v3_6_pmc_config_2_cntr(adev, config);
|
||||
|
||||
if (target_cntr < 0)
|
||||
if (!df_v3_6_pmc_has_counter(adev, config, counter_idx))
|
||||
return -EINVAL;
|
||||
|
||||
if (is_deferred)
|
||||
adev->df_perfmon_config_assign_mask[target_cntr] |=
|
||||
adev->df_perfmon_config_assign_mask[counter_idx] |=
|
||||
DEFERRED_ARM_MASK;
|
||||
else
|
||||
adev->df_perfmon_config_assign_mask[target_cntr] &=
|
||||
adev->df_perfmon_config_assign_mask[counter_idx] &=
|
||||
~DEFERRED_ARM_MASK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool df_v3_6_pmc_is_deferred(struct amdgpu_device *adev,
|
||||
int counter_idx,
|
||||
uint64_t config)
|
||||
{
|
||||
int target_cntr;
|
||||
|
||||
target_cntr = df_v3_6_pmc_config_2_cntr(adev, config);
|
||||
|
||||
/*
|
||||
* we never get target_cntr < 0 since this funciton is only called in
|
||||
* pmc_count for now but we should check anyways.
|
||||
*/
|
||||
return (target_cntr >= 0 &&
|
||||
(adev->df_perfmon_config_assign_mask[target_cntr]
|
||||
return (df_v3_6_pmc_has_counter(adev, config, counter_idx) &&
|
||||
(adev->df_perfmon_config_assign_mask[counter_idx]
|
||||
& DEFERRED_ARM_MASK));
|
||||
|
||||
}
|
||||
|
||||
/* release performance counter */
|
||||
static void df_v3_6_pmc_release_cntr(struct amdgpu_device *adev,
|
||||
uint64_t config)
|
||||
uint64_t config,
|
||||
int counter_idx)
|
||||
{
|
||||
int target_cntr = df_v3_6_pmc_config_2_cntr(adev, config);
|
||||
|
||||
if (target_cntr >= 0)
|
||||
adev->df_perfmon_config_assign_mask[target_cntr] = 0ULL;
|
||||
if (df_v3_6_pmc_has_counter(adev, config, counter_idx))
|
||||
adev->df_perfmon_config_assign_mask[counter_idx] = 0ULL;
|
||||
}
|
||||
|
||||
|
||||
static void df_v3_6_reset_perfmon_cntr(struct amdgpu_device *adev,
|
||||
uint64_t config)
|
||||
uint64_t config,
|
||||
int counter_idx)
|
||||
{
|
||||
uint32_t lo_base_addr = 0, hi_base_addr = 0;
|
||||
|
||||
df_v3_6_pmc_get_read_settings(adev, config, &lo_base_addr,
|
||||
df_v3_6_pmc_get_read_settings(adev, config, counter_idx, &lo_base_addr,
|
||||
&hi_base_addr);
|
||||
|
||||
if ((lo_base_addr == 0) || (hi_base_addr == 0))
|
||||
|
@ -573,8 +558,9 @@ static void df_v3_6_reset_perfmon_cntr(struct amdgpu_device *adev,
|
|||
df_v3_6_perfmon_wreg(adev, lo_base_addr, 0, hi_base_addr, 0);
|
||||
}
|
||||
|
||||
/* return available counter if is_add == 1 otherwise return error status. */
|
||||
static int df_v3_6_pmc_start(struct amdgpu_device *adev, uint64_t config,
|
||||
int is_add)
|
||||
int counter_idx, int is_add)
|
||||
{
|
||||
uint32_t lo_base_addr, hi_base_addr, lo_val, hi_val;
|
||||
int err = 0, ret = 0;
|
||||
|
@ -584,10 +570,9 @@ static int df_v3_6_pmc_start(struct amdgpu_device *adev, uint64_t config,
|
|||
if (is_add)
|
||||
return df_v3_6_pmc_add_cntr(adev, config);
|
||||
|
||||
df_v3_6_reset_perfmon_cntr(adev, config);
|
||||
|
||||
ret = df_v3_6_pmc_get_ctrl_settings(adev,
|
||||
config,
|
||||
counter_idx,
|
||||
&lo_base_addr,
|
||||
&hi_base_addr,
|
||||
&lo_val,
|
||||
|
@ -604,7 +589,8 @@ static int df_v3_6_pmc_start(struct amdgpu_device *adev, uint64_t config,
|
|||
hi_val);
|
||||
|
||||
if (err)
|
||||
ret = df_v3_6_pmc_set_deferred(adev, config, true);
|
||||
ret = df_v3_6_pmc_set_deferred(adev, config,
|
||||
counter_idx, true);
|
||||
|
||||
break;
|
||||
default:
|
||||
|
@ -615,7 +601,7 @@ static int df_v3_6_pmc_start(struct amdgpu_device *adev, uint64_t config,
|
|||
}
|
||||
|
||||
static int df_v3_6_pmc_stop(struct amdgpu_device *adev, uint64_t config,
|
||||
int is_remove)
|
||||
int counter_idx, int is_remove)
|
||||
{
|
||||
uint32_t lo_base_addr, hi_base_addr, lo_val, hi_val;
|
||||
int ret = 0;
|
||||
|
@ -624,6 +610,7 @@ static int df_v3_6_pmc_stop(struct amdgpu_device *adev, uint64_t config,
|
|||
case CHIP_VEGA20:
|
||||
ret = df_v3_6_pmc_get_ctrl_settings(adev,
|
||||
config,
|
||||
counter_idx,
|
||||
&lo_base_addr,
|
||||
&hi_base_addr,
|
||||
&lo_val,
|
||||
|
@ -635,8 +622,8 @@ static int df_v3_6_pmc_stop(struct amdgpu_device *adev, uint64_t config,
|
|||
|
||||
|
||||
if (is_remove) {
|
||||
df_v3_6_reset_perfmon_cntr(adev, config);
|
||||
df_v3_6_pmc_release_cntr(adev, config);
|
||||
df_v3_6_reset_perfmon_cntr(adev, config, counter_idx);
|
||||
df_v3_6_pmc_release_cntr(adev, config, counter_idx);
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -649,6 +636,7 @@ static int df_v3_6_pmc_stop(struct amdgpu_device *adev, uint64_t config,
|
|||
|
||||
static void df_v3_6_pmc_get_count(struct amdgpu_device *adev,
|
||||
uint64_t config,
|
||||
int counter_idx,
|
||||
uint64_t *count)
|
||||
{
|
||||
uint32_t lo_base_addr = 0, hi_base_addr = 0, lo_val = 0, hi_val = 0;
|
||||
|
@ -656,14 +644,14 @@ static void df_v3_6_pmc_get_count(struct amdgpu_device *adev,
|
|||
|
||||
switch (adev->asic_type) {
|
||||
case CHIP_VEGA20:
|
||||
df_v3_6_pmc_get_read_settings(adev, config, &lo_base_addr,
|
||||
&hi_base_addr);
|
||||
df_v3_6_pmc_get_read_settings(adev, config, counter_idx,
|
||||
&lo_base_addr, &hi_base_addr);
|
||||
|
||||
if ((lo_base_addr == 0) || (hi_base_addr == 0))
|
||||
return;
|
||||
|
||||
/* rearm the counter or throw away count value on failure */
|
||||
if (df_v3_6_pmc_is_deferred(adev, config)) {
|
||||
if (df_v3_6_pmc_is_deferred(adev, config, counter_idx)) {
|
||||
int rearm_err = df_v3_6_perfmon_arm_with_status(adev,
|
||||
lo_base_addr, lo_val,
|
||||
hi_base_addr, hi_val);
|
||||
|
@ -671,7 +659,8 @@ static void df_v3_6_pmc_get_count(struct amdgpu_device *adev,
|
|||
if (rearm_err)
|
||||
return;
|
||||
|
||||
df_v3_6_pmc_set_deferred(adev, config, false);
|
||||
df_v3_6_pmc_set_deferred(adev, config, counter_idx,
|
||||
false);
|
||||
}
|
||||
|
||||
df_v3_6_perfmon_rreg(adev, lo_base_addr, &lo_val,
|
||||
|
|
Loading…
Reference in New Issue