Skip to content

Commit 9e5afb7

Browse files
rohit-armctmarinas
authored andcommitted
arm_mpam: Use long MBWU counters if supported
Now that the larger counter sizes are probed, make use of them. Callers of mpam_msmon_read() may not know (or care!) about the different counter sizes. Allow them to specify mpam_feat_msmon_mbwu and have the driver pick the counter to use. Only 32bit accesses to the MSC are required to be supported by the spec, but these registers are 64bits. The lower half may overflow into the higher half between two 32bit reads. To avoid this, use a helper that reads the top half multiple times to check for overflow. Signed-off-by: Rohit Mathew <rohit.mathew@arm.com> [morse: merged multiple patches from Rohit, added explicit counter selection ] Signed-off-by: James Morse <james.morse@arm.com> Cc: Peter Newman <peternewman@google.com> Reviewed-by: Ben Horgan <ben.horgan@arm.com> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com> Reviewed-by: Fenghua Yu <fenghuay@nvidia.com> Reviewed-by: Gavin Shan <gshan@redhat.com> Reviewed-by: Shaopeng Tan <tan.shaopeng@jp.fujitsu.com> Tested-by: Fenghua Yu <fenghuay@nvidia.com> Tested-by: Shaopeng Tan <tan.shaopeng@jp.fujitsu.com> Tested-by: Carl Worth <carl@os.amperecomputing.com> Tested-by: Gavin Shan <gshan@redhat.com> Tested-by: Zeng Heng <zengheng4@huawei.com> Tested-by: Hanjun Guo <guohanjun@huawei.com> Signed-off-by: Ben Horgan <ben.horgan@arm.com> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
1 parent fdc29a1 commit 9e5afb7

1 file changed

Lines changed: 126 additions & 19 deletions

File tree

drivers/resctrl/mpam_devices.c

Lines changed: 126 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -905,6 +905,50 @@ struct mon_read {
905905
int err;
906906
};
907907

908+
static bool mpam_ris_has_mbwu_long_counter(struct mpam_msc_ris *ris)
909+
{
910+
return (mpam_has_feature(mpam_feat_msmon_mbwu_63counter, &ris->props) ||
911+
mpam_has_feature(mpam_feat_msmon_mbwu_44counter, &ris->props));
912+
}
913+
914+
static u64 mpam_msc_read_mbwu_l(struct mpam_msc *msc)
915+
{
916+
int retry = 3;
917+
u32 mbwu_l_low;
918+
u64 mbwu_l_high1, mbwu_l_high2;
919+
920+
mpam_mon_sel_lock_held(msc);
921+
922+
WARN_ON_ONCE((MSMON_MBWU_L + sizeof(u64)) > msc->mapped_hwpage_sz);
923+
WARN_ON_ONCE(!cpumask_test_cpu(smp_processor_id(), &msc->accessibility));
924+
925+
mbwu_l_high2 = __mpam_read_reg(msc, MSMON_MBWU_L + 4);
926+
do {
927+
mbwu_l_high1 = mbwu_l_high2;
928+
mbwu_l_low = __mpam_read_reg(msc, MSMON_MBWU_L);
929+
mbwu_l_high2 = __mpam_read_reg(msc, MSMON_MBWU_L + 4);
930+
931+
retry--;
932+
} while (mbwu_l_high1 != mbwu_l_high2 && retry > 0);
933+
934+
if (mbwu_l_high1 == mbwu_l_high2)
935+
return (mbwu_l_high1 << 32) | mbwu_l_low;
936+
937+
pr_warn("Failed to read a stable value\n");
938+
return MSMON___L_NRDY;
939+
}
940+
941+
static void mpam_msc_zero_mbwu_l(struct mpam_msc *msc)
942+
{
943+
mpam_mon_sel_lock_held(msc);
944+
945+
WARN_ON_ONCE((MSMON_MBWU_L + sizeof(u64)) > msc->mapped_hwpage_sz);
946+
WARN_ON_ONCE(!cpumask_test_cpu(smp_processor_id(), &msc->accessibility));
947+
948+
__mpam_write_reg(msc, MSMON_MBWU_L, 0);
949+
__mpam_write_reg(msc, MSMON_MBWU_L + 4, 0);
950+
}
951+
908952
static void gen_msmon_ctl_flt_vals(struct mon_read *m, u32 *ctl_val,
909953
u32 *flt_val)
910954
{
@@ -931,7 +975,9 @@ static void gen_msmon_ctl_flt_vals(struct mon_read *m, u32 *ctl_val,
931975
*flt_val |= FIELD_PREP(MSMON_CFG_CSU_FLT_XCL, ctx->csu_exclude_clean);
932976

933977
break;
934-
case mpam_feat_msmon_mbwu:
978+
case mpam_feat_msmon_mbwu_31counter:
979+
case mpam_feat_msmon_mbwu_44counter:
980+
case mpam_feat_msmon_mbwu_63counter:
935981
*ctl_val |= MSMON_CFG_MBWU_CTL_TYPE_MBWU;
936982

937983
if (mpam_has_feature(mpam_feat_msmon_mbwu_rwbw, &m->ris->props))
@@ -953,7 +999,9 @@ static void read_msmon_ctl_flt_vals(struct mon_read *m, u32 *ctl_val,
953999
*ctl_val = mpam_read_monsel_reg(msc, CFG_CSU_CTL);
9541000
*flt_val = mpam_read_monsel_reg(msc, CFG_CSU_FLT);
9551001
break;
956-
case mpam_feat_msmon_mbwu:
1002+
case mpam_feat_msmon_mbwu_31counter:
1003+
case mpam_feat_msmon_mbwu_44counter:
1004+
case mpam_feat_msmon_mbwu_63counter:
9571005
*ctl_val = mpam_read_monsel_reg(msc, CFG_MBWU_CTL);
9581006
*flt_val = mpam_read_monsel_reg(msc, CFG_MBWU_FLT);
9591007
break;
@@ -966,6 +1014,9 @@ static void read_msmon_ctl_flt_vals(struct mon_read *m, u32 *ctl_val,
9661014
static inline void clean_msmon_ctl_val(u32 *cur_ctl)
9671015
{
9681016
*cur_ctl &= ~MSMON_CFG_x_CTL_OFLOW_STATUS;
1017+
1018+
if (FIELD_GET(MSMON_CFG_x_CTL_TYPE, *cur_ctl) == MSMON_CFG_MBWU_CTL_TYPE_MBWU)
1019+
*cur_ctl &= ~MSMON_CFG_MBWU_CTL_OFLOW_STATUS_L;
9691020
}
9701021

9711022
static void write_msmon_ctl_flt_vals(struct mon_read *m, u32 ctl_val,
@@ -984,12 +1035,17 @@ static void write_msmon_ctl_flt_vals(struct mon_read *m, u32 ctl_val,
9841035
mpam_write_monsel_reg(msc, CSU, 0);
9851036
mpam_write_monsel_reg(msc, CFG_CSU_CTL, ctl_val | MSMON_CFG_x_CTL_EN);
9861037
break;
987-
case mpam_feat_msmon_mbwu:
1038+
case mpam_feat_msmon_mbwu_31counter:
1039+
case mpam_feat_msmon_mbwu_44counter:
1040+
case mpam_feat_msmon_mbwu_63counter:
9881041
mpam_write_monsel_reg(msc, CFG_MBWU_FLT, flt_val);
9891042
mpam_write_monsel_reg(msc, CFG_MBWU_CTL, ctl_val);
9901043
mpam_write_monsel_reg(msc, CFG_MBWU_CTL, ctl_val | MSMON_CFG_x_CTL_EN);
9911044
/* Counting monitors require NRDY to be reset by software */
992-
mpam_write_monsel_reg(msc, MBWU, 0);
1045+
if (m->type == mpam_feat_msmon_mbwu_31counter)
1046+
mpam_write_monsel_reg(msc, MBWU, 0);
1047+
else
1048+
mpam_msc_zero_mbwu_l(m->ris->vmsc->msc);
9931049
break;
9941050
default:
9951051
pr_warn("Unexpected monitor type %d\n", m->type);
@@ -998,8 +1054,17 @@ static void write_msmon_ctl_flt_vals(struct mon_read *m, u32 ctl_val,
9981054

9991055
static u64 mpam_msmon_overflow_val(enum mpam_device_features type)
10001056
{
1001-
/* TODO: scaling, and long counters */
1002-
return BIT_ULL(hweight_long(MSMON___VALUE));
1057+
/* TODO: implement scaling counters */
1058+
switch (type) {
1059+
case mpam_feat_msmon_mbwu_63counter:
1060+
return BIT_ULL(hweight_long(MSMON___LWD_VALUE));
1061+
case mpam_feat_msmon_mbwu_44counter:
1062+
return BIT_ULL(hweight_long(MSMON___L_VALUE));
1063+
case mpam_feat_msmon_mbwu_31counter:
1064+
return BIT_ULL(hweight_long(MSMON___VALUE));
1065+
default:
1066+
return 0;
1067+
}
10031068
}
10041069

10051070
static void __ris_msmon_read(void *arg)
@@ -1029,7 +1094,12 @@ static void __ris_msmon_read(void *arg)
10291094
* This saves waiting for 'nrdy' on subsequent reads.
10301095
*/
10311096
read_msmon_ctl_flt_vals(m, &cur_ctl, &cur_flt);
1032-
overflow = cur_ctl & MSMON_CFG_x_CTL_OFLOW_STATUS;
1097+
1098+
if (mpam_feat_msmon_mbwu_31counter == m->type)
1099+
overflow = cur_ctl & MSMON_CFG_x_CTL_OFLOW_STATUS;
1100+
else if (mpam_feat_msmon_mbwu_44counter == m->type ||
1101+
mpam_feat_msmon_mbwu_63counter == m->type)
1102+
overflow = cur_ctl & MSMON_CFG_MBWU_CTL_OFLOW_STATUS_L;
10331103

10341104
clean_msmon_ctl_val(&cur_ctl);
10351105
gen_msmon_ctl_flt_vals(m, &ctl_val, &flt_val);
@@ -1041,7 +1111,9 @@ static void __ris_msmon_read(void *arg)
10411111
overflow = false;
10421112
} else if (overflow) {
10431113
mpam_write_monsel_reg(msc, CFG_MBWU_CTL,
1044-
cur_ctl & ~MSMON_CFG_x_CTL_OFLOW_STATUS);
1114+
cur_ctl &
1115+
~(MSMON_CFG_x_CTL_OFLOW_STATUS |
1116+
MSMON_CFG_MBWU_CTL_OFLOW_STATUS_L));
10451117
}
10461118

10471119
switch (m->type) {
@@ -1051,11 +1123,24 @@ static void __ris_msmon_read(void *arg)
10511123
nrdy = now & MSMON___NRDY;
10521124
now = FIELD_GET(MSMON___VALUE, now);
10531125
break;
1054-
case mpam_feat_msmon_mbwu:
1055-
now = mpam_read_monsel_reg(msc, MBWU);
1056-
if (mpam_has_feature(mpam_feat_msmon_mbwu_hw_nrdy, rprops))
1057-
nrdy = now & MSMON___NRDY;
1058-
now = FIELD_GET(MSMON___VALUE, now);
1126+
case mpam_feat_msmon_mbwu_31counter:
1127+
case mpam_feat_msmon_mbwu_44counter:
1128+
case mpam_feat_msmon_mbwu_63counter:
1129+
if (m->type != mpam_feat_msmon_mbwu_31counter) {
1130+
now = mpam_msc_read_mbwu_l(msc);
1131+
if (mpam_has_feature(mpam_feat_msmon_mbwu_hw_nrdy, rprops))
1132+
nrdy = now & MSMON___L_NRDY;
1133+
1134+
if (m->type == mpam_feat_msmon_mbwu_63counter)
1135+
now = FIELD_GET(MSMON___LWD_VALUE, now);
1136+
else
1137+
now = FIELD_GET(MSMON___L_VALUE, now);
1138+
} else {
1139+
now = mpam_read_monsel_reg(msc, MBWU);
1140+
if (mpam_has_feature(mpam_feat_msmon_mbwu_hw_nrdy, rprops))
1141+
nrdy = now & MSMON___NRDY;
1142+
now = FIELD_GET(MSMON___VALUE, now);
1143+
}
10591144

10601145
if (nrdy)
10611146
break;
@@ -1118,13 +1203,26 @@ static int _msmon_read(struct mpam_component *comp, struct mon_read *arg)
11181203
return any_err;
11191204
}
11201205

1206+
static enum mpam_device_features mpam_msmon_choose_counter(struct mpam_class *class)
1207+
{
1208+
struct mpam_props *cprops = &class->props;
1209+
1210+
if (mpam_has_feature(mpam_feat_msmon_mbwu_63counter, cprops))
1211+
return mpam_feat_msmon_mbwu_63counter;
1212+
if (mpam_has_feature(mpam_feat_msmon_mbwu_44counter, cprops))
1213+
return mpam_feat_msmon_mbwu_44counter;
1214+
1215+
return mpam_feat_msmon_mbwu_31counter;
1216+
}
1217+
11211218
int mpam_msmon_read(struct mpam_component *comp, struct mon_cfg *ctx,
11221219
enum mpam_device_features type, u64 *val)
11231220
{
11241221
int err;
11251222
struct mon_read arg;
11261223
u64 wait_jiffies = 0;
1127-
struct mpam_props *cprops = &comp->class->props;
1224+
struct mpam_class *class = comp->class;
1225+
struct mpam_props *cprops = &class->props;
11281226

11291227
might_sleep();
11301228

@@ -1134,6 +1232,9 @@ int mpam_msmon_read(struct mpam_component *comp, struct mon_cfg *ctx,
11341232
if (!mpam_has_feature(type, cprops))
11351233
return -EOPNOTSUPP;
11361234

1235+
if (type == mpam_feat_msmon_mbwu)
1236+
type = mpam_msmon_choose_counter(class);
1237+
11371238
arg = (struct mon_read) {
11381239
.ctx = ctx,
11391240
.type = type,
@@ -1142,8 +1243,8 @@ int mpam_msmon_read(struct mpam_component *comp, struct mon_cfg *ctx,
11421243
*val = 0;
11431244

11441245
err = _msmon_read(comp, &arg);
1145-
if (err == -EBUSY && comp->class->nrdy_usec)
1146-
wait_jiffies = usecs_to_jiffies(comp->class->nrdy_usec);
1246+
if (err == -EBUSY && class->nrdy_usec)
1247+
wait_jiffies = usecs_to_jiffies(class->nrdy_usec);
11471248

11481249
while (wait_jiffies)
11491250
wait_jiffies = schedule_timeout_uninterruptible(wait_jiffies);
@@ -1282,12 +1383,13 @@ static int mpam_restore_mbwu_state(void *_ris)
12821383
int i;
12831384
struct mon_read mwbu_arg;
12841385
struct mpam_msc_ris *ris = _ris;
1386+
struct mpam_class *class = ris->vmsc->comp->class;
12851387

12861388
for (i = 0; i < ris->props.num_mbwu_mon; i++) {
12871389
if (ris->mbwu_state[i].enabled) {
12881390
mwbu_arg.ris = ris;
12891391
mwbu_arg.ctx = &ris->mbwu_state[i].cfg;
1290-
mwbu_arg.type = mpam_feat_msmon_mbwu;
1392+
mwbu_arg.type = mpam_msmon_choose_counter(class);
12911393

12921394
__ris_msmon_read(&mwbu_arg);
12931395
}
@@ -1322,8 +1424,13 @@ static int mpam_save_mbwu_state(void *arg)
13221424
cur_ctl = mpam_read_monsel_reg(msc, CFG_MBWU_CTL);
13231425
mpam_write_monsel_reg(msc, CFG_MBWU_CTL, 0);
13241426

1325-
val = mpam_read_monsel_reg(msc, MBWU);
1326-
mpam_write_monsel_reg(msc, MBWU, 0);
1427+
if (mpam_ris_has_mbwu_long_counter(ris)) {
1428+
val = mpam_msc_read_mbwu_l(msc);
1429+
mpam_msc_zero_mbwu_l(msc);
1430+
} else {
1431+
val = mpam_read_monsel_reg(msc, MBWU);
1432+
mpam_write_monsel_reg(msc, MBWU, 0);
1433+
}
13271434

13281435
cfg->mon = i;
13291436
cfg->pmg = FIELD_GET(MSMON_CFG_x_FLT_PMG, cur_flt);

0 commit comments

Comments
 (0)