Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Rohit Mathew and committed by
Catalin Marinas
9e5afb7c fdc29a14

+126 -19
+126 -19
drivers/resctrl/mpam_devices.c
··· 905 905 int err; 906 906 }; 907 907 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 + 908 952 static void gen_msmon_ctl_flt_vals(struct mon_read *m, u32 *ctl_val, 909 953 u32 *flt_val) 910 954 { ··· 975 931 *flt_val |= FIELD_PREP(MSMON_CFG_CSU_FLT_XCL, ctx->csu_exclude_clean); 976 932 977 933 break; 978 - case mpam_feat_msmon_mbwu: 934 + case mpam_feat_msmon_mbwu_31counter: 935 + case mpam_feat_msmon_mbwu_44counter: 936 + case mpam_feat_msmon_mbwu_63counter: 979 937 *ctl_val |= MSMON_CFG_MBWU_CTL_TYPE_MBWU; 980 938 981 939 if (mpam_has_feature(mpam_feat_msmon_mbwu_rwbw, &m->ris->props)) ··· 999 953 *ctl_val = mpam_read_monsel_reg(msc, CFG_CSU_CTL); 1000 954 *flt_val = mpam_read_monsel_reg(msc, CFG_CSU_FLT); 1001 955 break; 1002 - case mpam_feat_msmon_mbwu: 956 + case mpam_feat_msmon_mbwu_31counter: 957 + case mpam_feat_msmon_mbwu_44counter: 958 + case mpam_feat_msmon_mbwu_63counter: 1003 959 *ctl_val = mpam_read_monsel_reg(msc, CFG_MBWU_CTL); 1004 960 *flt_val = mpam_read_monsel_reg(msc, CFG_MBWU_FLT); 1005 961 break; ··· 1014 966 static inline void clean_msmon_ctl_val(u32 *cur_ctl) 1015 967 { 1016 968 *cur_ctl &= ~MSMON_CFG_x_CTL_OFLOW_STATUS; 969 + 970 + if (FIELD_GET(MSMON_CFG_x_CTL_TYPE, *cur_ctl) == MSMON_CFG_MBWU_CTL_TYPE_MBWU) 971 + *cur_ctl &= ~MSMON_CFG_MBWU_CTL_OFLOW_STATUS_L; 1017 972 } 1018 973 1019 974 static void write_msmon_ctl_flt_vals(struct mon_read *m, u32 ctl_val, ··· 1035 984 mpam_write_monsel_reg(msc, CSU, 0); 1036 985 mpam_write_monsel_reg(msc, CFG_CSU_CTL, ctl_val | MSMON_CFG_x_CTL_EN); 1037 986 break; 1038 - case mpam_feat_msmon_mbwu: 987 + case mpam_feat_msmon_mbwu_31counter: 988 + case mpam_feat_msmon_mbwu_44counter: 989 + case mpam_feat_msmon_mbwu_63counter: 1039 990 mpam_write_monsel_reg(msc, CFG_MBWU_FLT, flt_val); 1040 991 mpam_write_monsel_reg(msc, CFG_MBWU_CTL, ctl_val); 1041 992 mpam_write_monsel_reg(msc, CFG_MBWU_CTL, ctl_val | MSMON_CFG_x_CTL_EN); 1042 993 /* Counting monitors require NRDY to be reset by software */ 1043 - mpam_write_monsel_reg(msc, MBWU, 0); 994 + if (m->type == mpam_feat_msmon_mbwu_31counter) 995 + mpam_write_monsel_reg(msc, MBWU, 0); 996 + else 997 + mpam_msc_zero_mbwu_l(m->ris->vmsc->msc); 1044 998 break; 1045 999 default: 1046 1000 pr_warn("Unexpected monitor type %d\n", m->type); ··· 1054 998 1055 999 static u64 mpam_msmon_overflow_val(enum mpam_device_features type) 1056 1000 { 1057 - /* TODO: scaling, and long counters */ 1058 - return BIT_ULL(hweight_long(MSMON___VALUE)); 1001 + /* TODO: implement scaling counters */ 1002 + switch (type) { 1003 + case mpam_feat_msmon_mbwu_63counter: 1004 + return BIT_ULL(hweight_long(MSMON___LWD_VALUE)); 1005 + case mpam_feat_msmon_mbwu_44counter: 1006 + return BIT_ULL(hweight_long(MSMON___L_VALUE)); 1007 + case mpam_feat_msmon_mbwu_31counter: 1008 + return BIT_ULL(hweight_long(MSMON___VALUE)); 1009 + default: 1010 + return 0; 1011 + } 1059 1012 } 1060 1013 1061 1014 static void __ris_msmon_read(void *arg) ··· 1094 1029 * This saves waiting for 'nrdy' on subsequent reads. 1095 1030 */ 1096 1031 read_msmon_ctl_flt_vals(m, &cur_ctl, &cur_flt); 1097 - overflow = cur_ctl & MSMON_CFG_x_CTL_OFLOW_STATUS; 1032 + 1033 + if (mpam_feat_msmon_mbwu_31counter == m->type) 1034 + overflow = cur_ctl & MSMON_CFG_x_CTL_OFLOW_STATUS; 1035 + else if (mpam_feat_msmon_mbwu_44counter == m->type || 1036 + mpam_feat_msmon_mbwu_63counter == m->type) 1037 + overflow = cur_ctl & MSMON_CFG_MBWU_CTL_OFLOW_STATUS_L; 1098 1038 1099 1039 clean_msmon_ctl_val(&cur_ctl); 1100 1040 gen_msmon_ctl_flt_vals(m, &ctl_val, &flt_val); ··· 1111 1041 overflow = false; 1112 1042 } else if (overflow) { 1113 1043 mpam_write_monsel_reg(msc, CFG_MBWU_CTL, 1114 - cur_ctl & ~MSMON_CFG_x_CTL_OFLOW_STATUS); 1044 + cur_ctl & 1045 + ~(MSMON_CFG_x_CTL_OFLOW_STATUS | 1046 + MSMON_CFG_MBWU_CTL_OFLOW_STATUS_L)); 1115 1047 } 1116 1048 1117 1049 switch (m->type) { ··· 1123 1051 nrdy = now & MSMON___NRDY; 1124 1052 now = FIELD_GET(MSMON___VALUE, now); 1125 1053 break; 1126 - case mpam_feat_msmon_mbwu: 1127 - now = mpam_read_monsel_reg(msc, MBWU); 1128 - if (mpam_has_feature(mpam_feat_msmon_mbwu_hw_nrdy, rprops)) 1129 - nrdy = now & MSMON___NRDY; 1130 - now = FIELD_GET(MSMON___VALUE, now); 1054 + case mpam_feat_msmon_mbwu_31counter: 1055 + case mpam_feat_msmon_mbwu_44counter: 1056 + case mpam_feat_msmon_mbwu_63counter: 1057 + if (m->type != mpam_feat_msmon_mbwu_31counter) { 1058 + now = mpam_msc_read_mbwu_l(msc); 1059 + if (mpam_has_feature(mpam_feat_msmon_mbwu_hw_nrdy, rprops)) 1060 + nrdy = now & MSMON___L_NRDY; 1061 + 1062 + if (m->type == mpam_feat_msmon_mbwu_63counter) 1063 + now = FIELD_GET(MSMON___LWD_VALUE, now); 1064 + else 1065 + now = FIELD_GET(MSMON___L_VALUE, now); 1066 + } else { 1067 + now = mpam_read_monsel_reg(msc, MBWU); 1068 + if (mpam_has_feature(mpam_feat_msmon_mbwu_hw_nrdy, rprops)) 1069 + nrdy = now & MSMON___NRDY; 1070 + now = FIELD_GET(MSMON___VALUE, now); 1071 + } 1131 1072 1132 1073 if (nrdy) 1133 1074 break; ··· 1203 1118 return any_err; 1204 1119 } 1205 1120 1121 + static enum mpam_device_features mpam_msmon_choose_counter(struct mpam_class *class) 1122 + { 1123 + struct mpam_props *cprops = &class->props; 1124 + 1125 + if (mpam_has_feature(mpam_feat_msmon_mbwu_63counter, cprops)) 1126 + return mpam_feat_msmon_mbwu_63counter; 1127 + if (mpam_has_feature(mpam_feat_msmon_mbwu_44counter, cprops)) 1128 + return mpam_feat_msmon_mbwu_44counter; 1129 + 1130 + return mpam_feat_msmon_mbwu_31counter; 1131 + } 1132 + 1206 1133 int mpam_msmon_read(struct mpam_component *comp, struct mon_cfg *ctx, 1207 1134 enum mpam_device_features type, u64 *val) 1208 1135 { 1209 1136 int err; 1210 1137 struct mon_read arg; 1211 1138 u64 wait_jiffies = 0; 1212 - struct mpam_props *cprops = &comp->class->props; 1139 + struct mpam_class *class = comp->class; 1140 + struct mpam_props *cprops = &class->props; 1213 1141 1214 1142 might_sleep(); 1215 1143 ··· 1232 1134 if (!mpam_has_feature(type, cprops)) 1233 1135 return -EOPNOTSUPP; 1234 1136 1137 + if (type == mpam_feat_msmon_mbwu) 1138 + type = mpam_msmon_choose_counter(class); 1139 + 1235 1140 arg = (struct mon_read) { 1236 1141 .ctx = ctx, 1237 1142 .type = type, ··· 1243 1142 *val = 0; 1244 1143 1245 1144 err = _msmon_read(comp, &arg); 1246 - if (err == -EBUSY && comp->class->nrdy_usec) 1247 - wait_jiffies = usecs_to_jiffies(comp->class->nrdy_usec); 1145 + if (err == -EBUSY && class->nrdy_usec) 1146 + wait_jiffies = usecs_to_jiffies(class->nrdy_usec); 1248 1147 1249 1148 while (wait_jiffies) 1250 1149 wait_jiffies = schedule_timeout_uninterruptible(wait_jiffies); ··· 1383 1282 int i; 1384 1283 struct mon_read mwbu_arg; 1385 1284 struct mpam_msc_ris *ris = _ris; 1285 + struct mpam_class *class = ris->vmsc->comp->class; 1386 1286 1387 1287 for (i = 0; i < ris->props.num_mbwu_mon; i++) { 1388 1288 if (ris->mbwu_state[i].enabled) { 1389 1289 mwbu_arg.ris = ris; 1390 1290 mwbu_arg.ctx = &ris->mbwu_state[i].cfg; 1391 - mwbu_arg.type = mpam_feat_msmon_mbwu; 1291 + mwbu_arg.type = mpam_msmon_choose_counter(class); 1392 1292 1393 1293 __ris_msmon_read(&mwbu_arg); 1394 1294 } ··· 1424 1322 cur_ctl = mpam_read_monsel_reg(msc, CFG_MBWU_CTL); 1425 1323 mpam_write_monsel_reg(msc, CFG_MBWU_CTL, 0); 1426 1324 1427 - val = mpam_read_monsel_reg(msc, MBWU); 1428 - mpam_write_monsel_reg(msc, MBWU, 0); 1325 + if (mpam_ris_has_mbwu_long_counter(ris)) { 1326 + val = mpam_msc_read_mbwu_l(msc); 1327 + mpam_msc_zero_mbwu_l(msc); 1328 + } else { 1329 + val = mpam_read_monsel_reg(msc, MBWU); 1330 + mpam_write_monsel_reg(msc, MBWU, 0); 1331 + } 1429 1332 1430 1333 cfg->mon = i; 1431 1334 cfg->pmg = FIELD_GET(MSMON_CFG_x_FLT_PMG, cur_flt);