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: Track bandwidth counter state for power management

Bandwidth counters need to run continuously to correctly reflect the
bandwidth.

Save the counter state when the hardware is reset due to CPU hotplug.
Add struct mbwu_state to track the bandwidth counter. Support for
tracking overflow with the same structure will be added in a
subsequent commit.

Cc: Zeng Heng <zengheng4@huawei.com>
Reviewed-by: Gavin Shan <gshan@redhat.com>
Reviewed-by: Zeng Heng <zengheng4@huawei.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Reviewed-by: Shaopeng Tan <tan.shaopeng@jp.fujitsu.com>
Reviewed-by: Fenghua Yu <fenghuay@nvidia.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: Shaopeng Tan <tan.shaopeng@jp.fujitsu.com>
Tested-by: Hanjun Guo <guohanjun@huawei.com>
Signed-off-by: James Morse <james.morse@arm.com>
Signed-off-by: Ben Horgan <ben.horgan@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>

authored by

James Morse and committed by
Catalin Marinas
41e8a149 823e7c37

+145 -2
+125 -1
drivers/resctrl/mpam_devices.c
··· 993 993 struct mon_read *m = arg; 994 994 struct mon_cfg *ctx = m->ctx; 995 995 struct mpam_msc_ris *ris = m->ris; 996 + struct msmon_mbwu_state *mbwu_state; 996 997 struct mpam_props *rprops = &ris->props; 997 998 struct mpam_msc *msc = m->ris->vmsc->msc; 998 999 u32 mon_sel, ctl_val, flt_val, cur_ctl, cur_flt; ··· 1024 1023 now = mpam_read_monsel_reg(msc, CSU); 1025 1024 if (mpam_has_feature(mpam_feat_msmon_csu_hw_nrdy, rprops)) 1026 1025 nrdy = now & MSMON___NRDY; 1026 + now = FIELD_GET(MSMON___VALUE, now); 1027 1027 break; 1028 1028 case mpam_feat_msmon_mbwu: 1029 1029 now = mpam_read_monsel_reg(msc, MBWU); 1030 1030 if (mpam_has_feature(mpam_feat_msmon_mbwu_hw_nrdy, rprops)) 1031 1031 nrdy = now & MSMON___NRDY; 1032 + now = FIELD_GET(MSMON___VALUE, now); 1033 + 1034 + if (nrdy) 1035 + break; 1036 + 1037 + mbwu_state = &ris->mbwu_state[ctx->mon]; 1038 + 1039 + /* Include bandwidth consumed before the last hardware reset */ 1040 + now += mbwu_state->correction; 1032 1041 break; 1033 1042 default: 1034 1043 m->err = -EINVAL; ··· 1050 1039 return; 1051 1040 } 1052 1041 1053 - now = FIELD_GET(MSMON___VALUE, now); 1054 1042 *m->val += now; 1055 1043 } 1056 1044 ··· 1245 1235 mutex_unlock(&msc->part_sel_lock); 1246 1236 } 1247 1237 1238 + /* Call with msc cfg_lock held */ 1239 + static int mpam_restore_mbwu_state(void *_ris) 1240 + { 1241 + int i; 1242 + struct mon_read mwbu_arg; 1243 + struct mpam_msc_ris *ris = _ris; 1244 + 1245 + for (i = 0; i < ris->props.num_mbwu_mon; i++) { 1246 + if (ris->mbwu_state[i].enabled) { 1247 + mwbu_arg.ris = ris; 1248 + mwbu_arg.ctx = &ris->mbwu_state[i].cfg; 1249 + mwbu_arg.type = mpam_feat_msmon_mbwu; 1250 + 1251 + __ris_msmon_read(&mwbu_arg); 1252 + } 1253 + } 1254 + 1255 + return 0; 1256 + } 1257 + 1258 + /* Call with MSC cfg_lock held */ 1259 + static int mpam_save_mbwu_state(void *arg) 1260 + { 1261 + int i; 1262 + u64 val; 1263 + struct mon_cfg *cfg; 1264 + u32 cur_flt, cur_ctl, mon_sel; 1265 + struct mpam_msc_ris *ris = arg; 1266 + struct msmon_mbwu_state *mbwu_state; 1267 + struct mpam_msc *msc = ris->vmsc->msc; 1268 + 1269 + for (i = 0; i < ris->props.num_mbwu_mon; i++) { 1270 + mbwu_state = &ris->mbwu_state[i]; 1271 + cfg = &mbwu_state->cfg; 1272 + 1273 + if (WARN_ON_ONCE(!mpam_mon_sel_lock(msc))) 1274 + return -EIO; 1275 + 1276 + mon_sel = FIELD_PREP(MSMON_CFG_MON_SEL_MON_SEL, i) | 1277 + FIELD_PREP(MSMON_CFG_MON_SEL_RIS, ris->ris_idx); 1278 + mpam_write_monsel_reg(msc, CFG_MON_SEL, mon_sel); 1279 + 1280 + cur_flt = mpam_read_monsel_reg(msc, CFG_MBWU_FLT); 1281 + cur_ctl = mpam_read_monsel_reg(msc, CFG_MBWU_CTL); 1282 + mpam_write_monsel_reg(msc, CFG_MBWU_CTL, 0); 1283 + 1284 + val = mpam_read_monsel_reg(msc, MBWU); 1285 + mpam_write_monsel_reg(msc, MBWU, 0); 1286 + 1287 + cfg->mon = i; 1288 + cfg->pmg = FIELD_GET(MSMON_CFG_x_FLT_PMG, cur_flt); 1289 + cfg->match_pmg = FIELD_GET(MSMON_CFG_x_CTL_MATCH_PMG, cur_ctl); 1290 + cfg->partid = FIELD_GET(MSMON_CFG_x_FLT_PARTID, cur_flt); 1291 + mbwu_state->correction += val; 1292 + mbwu_state->enabled = FIELD_GET(MSMON_CFG_x_CTL_EN, cur_ctl); 1293 + mpam_mon_sel_unlock(msc); 1294 + } 1295 + 1296 + return 0; 1297 + } 1298 + 1248 1299 static void mpam_init_reset_cfg(struct mpam_config *reset_cfg) 1249 1300 { 1250 1301 *reset_cfg = (struct mpam_config) { ··· 1414 1343 mpam_touch_msc(msc, __write_config, &arg); 1415 1344 } 1416 1345 ris->in_reset_state = reset; 1346 + 1347 + if (mpam_has_feature(mpam_feat_msmon_mbwu, &ris->props)) 1348 + mpam_touch_msc(msc, &mpam_restore_mbwu_state, ris); 1417 1349 } 1418 1350 mutex_unlock(&msc->cfg_lock); 1419 1351 } ··· 1510 1436 * lost while the CPUs are offline. 1511 1437 */ 1512 1438 ris->in_reset_state = false; 1439 + 1440 + if (mpam_is_enabled()) 1441 + mpam_touch_msc(msc, &mpam_save_mbwu_state, ris); 1513 1442 } 1514 1443 mutex_unlock(&msc->cfg_lock); 1515 1444 } ··· 2186 2109 2187 2110 static void __destroy_component_cfg(struct mpam_component *comp) 2188 2111 { 2112 + struct mpam_msc *msc; 2113 + struct mpam_vmsc *vmsc; 2114 + struct mpam_msc_ris *ris; 2115 + 2116 + lockdep_assert_held(&mpam_list_lock); 2117 + 2189 2118 add_to_garbage(comp->cfg); 2119 + list_for_each_entry(vmsc, &comp->vmsc, comp_list) { 2120 + msc = vmsc->msc; 2121 + 2122 + if (mpam_mon_sel_lock(msc)) { 2123 + list_for_each_entry(ris, &vmsc->ris, vmsc_list) 2124 + add_to_garbage(ris->mbwu_state); 2125 + mpam_mon_sel_unlock(msc); 2126 + } 2127 + } 2190 2128 } 2191 2129 2192 2130 static void mpam_reset_component_cfg(struct mpam_component *comp) ··· 2227 2135 2228 2136 static int __allocate_component_cfg(struct mpam_component *comp) 2229 2137 { 2138 + struct mpam_vmsc *vmsc; 2139 + 2230 2140 mpam_assert_partid_sizes_fixed(); 2231 2141 2232 2142 if (comp->cfg) ··· 2245 2151 init_garbage(&comp->cfg[0].garbage); 2246 2152 2247 2153 mpam_reset_component_cfg(comp); 2154 + 2155 + list_for_each_entry(vmsc, &comp->vmsc, comp_list) { 2156 + struct mpam_msc *msc; 2157 + struct mpam_msc_ris *ris; 2158 + struct msmon_mbwu_state *mbwu_state; 2159 + 2160 + if (!vmsc->props.num_mbwu_mon) 2161 + continue; 2162 + 2163 + msc = vmsc->msc; 2164 + list_for_each_entry(ris, &vmsc->ris, vmsc_list) { 2165 + if (!ris->props.num_mbwu_mon) 2166 + continue; 2167 + 2168 + mbwu_state = kcalloc(ris->props.num_mbwu_mon, 2169 + sizeof(*ris->mbwu_state), 2170 + GFP_KERNEL); 2171 + if (!mbwu_state) { 2172 + __destroy_component_cfg(comp); 2173 + return -ENOMEM; 2174 + } 2175 + 2176 + init_garbage(&mbwu_state[0].garbage); 2177 + 2178 + if (mpam_mon_sel_lock(msc)) { 2179 + ris->mbwu_state = mbwu_state; 2180 + mpam_mon_sel_unlock(msc); 2181 + } 2182 + } 2183 + } 2248 2184 2249 2185 return 0; 2250 2186 }
+20 -1
drivers/resctrl/mpam_internal.h
··· 91 91 */ 92 92 struct mutex part_sel_lock; 93 93 94 - /* cfg_lock protects the msc configuration. */ 94 + /* 95 + * cfg_lock protects the msc configuration and guards against mbwu_state 96 + * save and restore racing. 97 + */ 95 98 struct mutex cfg_lock; 96 99 97 100 /* ··· 205 202 enum mon_filter_options opts; 206 203 }; 207 204 205 + /* Changes to msmon_mbwu_state are protected by the msc's mon_sel_lock. */ 206 + struct msmon_mbwu_state { 207 + bool enabled; 208 + struct mon_cfg cfg; 209 + 210 + /* 211 + * The value to add to the new reading to account for power management. 212 + */ 213 + u64 correction; 214 + 215 + struct mpam_garbage garbage; 216 + }; 217 + 208 218 struct mpam_class { 209 219 /* mpam_components in this class */ 210 220 struct list_head components; ··· 310 294 311 295 /* parent: */ 312 296 struct mpam_vmsc *vmsc; 297 + 298 + /* msmon mbwu configuration is preserved over reset */ 299 + struct msmon_mbwu_state *mbwu_state; 313 300 314 301 struct mpam_garbage garbage; 315 302 };