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.
Showing the changes to drivers/resctrl (2 of 2 files). Show all
Unified · Split
| @@ -993,6 +993,7 @@ static void __ris_msmon_read(void *arg) · 992 unmodified lines | |||
| 993 | struct mon_read *m = arg; | 993 | struct mon_read *m = arg; |
| 994 | struct mon_cfg *ctx = m->ctx; | 994 | struct mon_cfg *ctx = m->ctx; |
| 995 | struct mpam_msc_ris *ris = m->ris; | 995 | struct mpam_msc_ris *ris = m->ris; |
| 996 | struct msmon_mbwu_state *mbwu_state; | ||
| 996 | struct mpam_props *rprops = &ris->props; | 997 | struct mpam_props *rprops = &ris->props; |
| 997 | struct mpam_msc *msc = m->ris->vmsc->msc; | 998 | struct mpam_msc *msc = m->ris->vmsc->msc; |
| 998 | u32 mon_sel, ctl_val, flt_val, cur_ctl, cur_flt; | 999 | u32 mon_sel, ctl_val, flt_val, cur_ctl, cur_flt; |
| @@ -1023,11 +1024,21 @@ static void __ris_msmon_read(void *arg) · 24 unmodified lines | |||
| 1023 | now = mpam_read_monsel_reg(msc, CSU); | 1024 | now = mpam_read_monsel_reg(msc, CSU); |
| 1024 | if (mpam_has_feature(mpam_feat_msmon_csu_hw_nrdy, rprops)) | 1025 | if (mpam_has_feature(mpam_feat_msmon_csu_hw_nrdy, rprops)) |
| 1025 | nrdy = now & MSMON___NRDY; | 1026 | nrdy = now & MSMON___NRDY; |
| 1027 | now = FIELD_GET(MSMON___VALUE, now); | ||
| 1026 | break; | 1028 | break; |
| 1027 | case mpam_feat_msmon_mbwu: | 1029 | case mpam_feat_msmon_mbwu: |
| 1028 | now = mpam_read_monsel_reg(msc, MBWU); | 1030 | now = mpam_read_monsel_reg(msc, MBWU); |
| 1029 | if (mpam_has_feature(mpam_feat_msmon_mbwu_hw_nrdy, rprops)) | 1031 | if (mpam_has_feature(mpam_feat_msmon_mbwu_hw_nrdy, rprops)) |
| 1030 | nrdy = now & MSMON___NRDY; | 1032 | nrdy = now & MSMON___NRDY; |
| 1033 | now = FIELD_GET(MSMON___VALUE, now); | ||
| 1034 | |||
| 1035 | if (nrdy) | ||
| 1036 | break; | ||
| 1037 | |||
| 1038 | mbwu_state = &ris->mbwu_state[ctx->mon]; | ||
| 1039 | |||
| 1040 | /* Include bandwidth consumed before the last hardware reset */ | ||
| 1041 | now += mbwu_state->correction; | ||
| 1031 | break; | 1042 | break; |
| 1032 | default: | 1043 | default: |
| 1033 | m->err = -EINVAL; | 1044 | m->err = -EINVAL; |
| @@ -1039,7 +1050,6 @@ static void __ris_msmon_read(void *arg) · 5 unmodified lines | |||
| 1039 | return; | 1050 | return; |
| 1040 | } | 1051 | } |
| 1041 | 1052 | ||
| 1042 | now = FIELD_GET(MSMON___VALUE, now); | ||
| 1043 | *m->val += now; | 1053 | *m->val += now; |
| 1044 | } | 1054 | } |
| 1045 | 1055 | ||
| @@ -1235,6 +1245,67 @@ static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid, · 189 unmodified lines | |||
| 1235 | mutex_unlock(&msc->part_sel_lock); | 1245 | mutex_unlock(&msc->part_sel_lock); |
| 1236 | } | 1246 | } |
| 1237 | 1247 | ||
| 1248 | /* Call with msc cfg_lock held */ | ||
| 1249 | static int mpam_restore_mbwu_state(void *_ris) | ||
| 1250 | { | ||
| 1251 | int i; | ||
| 1252 | struct mon_read mwbu_arg; | ||
| 1253 | struct mpam_msc_ris *ris = _ris; | ||
| 1254 | |||
| 1255 | for (i = 0; i < ris->props.num_mbwu_mon; i++) { | ||
| 1256 | if (ris->mbwu_state[i].enabled) { | ||
| 1257 | mwbu_arg.ris = ris; | ||
| 1258 | mwbu_arg.ctx = &ris->mbwu_state[i].cfg; | ||
| 1259 | mwbu_arg.type = mpam_feat_msmon_mbwu; | ||
| 1260 | |||
| 1261 | __ris_msmon_read(&mwbu_arg); | ||
| 1262 | } | ||
| 1263 | } | ||
| 1264 | |||
| 1265 | return 0; | ||
| 1266 | } | ||
| 1267 | |||
| 1268 | /* Call with MSC cfg_lock held */ | ||
| 1269 | static int mpam_save_mbwu_state(void *arg) | ||
| 1270 | { | ||
| 1271 | int i; | ||
| 1272 | u64 val; | ||
| 1273 | struct mon_cfg *cfg; | ||
| 1274 | u32 cur_flt, cur_ctl, mon_sel; | ||
| 1275 | struct mpam_msc_ris *ris = arg; | ||
| 1276 | struct msmon_mbwu_state *mbwu_state; | ||
| 1277 | struct mpam_msc *msc = ris->vmsc->msc; | ||
| 1278 | |||
| 1279 | for (i = 0; i < ris->props.num_mbwu_mon; i++) { | ||
| 1280 | mbwu_state = &ris->mbwu_state[i]; | ||
| 1281 | cfg = &mbwu_state->cfg; | ||
| 1282 | |||
| 1283 | if (WARN_ON_ONCE(!mpam_mon_sel_lock(msc))) | ||
| 1284 | return -EIO; | ||
| 1285 | |||
| 1286 | mon_sel = FIELD_PREP(MSMON_CFG_MON_SEL_MON_SEL, i) | | ||
| 1287 | FIELD_PREP(MSMON_CFG_MON_SEL_RIS, ris->ris_idx); | ||
| 1288 | mpam_write_monsel_reg(msc, CFG_MON_SEL, mon_sel); | ||
| 1289 | |||
| 1290 | cur_flt = mpam_read_monsel_reg(msc, CFG_MBWU_FLT); | ||
| 1291 | cur_ctl = mpam_read_monsel_reg(msc, CFG_MBWU_CTL); | ||
| 1292 | mpam_write_monsel_reg(msc, CFG_MBWU_CTL, 0); | ||
| 1293 | |||
| 1294 | val = mpam_read_monsel_reg(msc, MBWU); | ||
| 1295 | mpam_write_monsel_reg(msc, MBWU, 0); | ||
| 1296 | |||
| 1297 | cfg->mon = i; | ||
| 1298 | cfg->pmg = FIELD_GET(MSMON_CFG_x_FLT_PMG, cur_flt); | ||
| 1299 | cfg->match_pmg = FIELD_GET(MSMON_CFG_x_CTL_MATCH_PMG, cur_ctl); | ||
| 1300 | cfg->partid = FIELD_GET(MSMON_CFG_x_FLT_PARTID, cur_flt); | ||
| 1301 | mbwu_state->correction += val; | ||
| 1302 | mbwu_state->enabled = FIELD_GET(MSMON_CFG_x_CTL_EN, cur_ctl); | ||
| 1303 | mpam_mon_sel_unlock(msc); | ||
| 1304 | } | ||
| 1305 | |||
| 1306 | return 0; | ||
| 1307 | } | ||
| 1308 | |||
| 1238 | static void mpam_init_reset_cfg(struct mpam_config *reset_cfg) | 1309 | static void mpam_init_reset_cfg(struct mpam_config *reset_cfg) |
| 1239 | { | 1310 | { |
| 1240 | *reset_cfg = (struct mpam_config) { | 1311 | *reset_cfg = (struct mpam_config) { |
| @@ -1343,6 +1414,9 @@ static void mpam_reprogram_msc(struct mpam_msc *msc) · 102 unmodified lines | |||
| 1343 | mpam_touch_msc(msc, __write_config, &arg); | 1414 | mpam_touch_msc(msc, __write_config, &arg); |
| 1344 | } | 1415 | } |
| 1345 | ris->in_reset_state = reset; | 1416 | ris->in_reset_state = reset; |
| 1417 | |||
| 1418 | if (mpam_has_feature(mpam_feat_msmon_mbwu, &ris->props)) | ||
| 1419 | mpam_touch_msc(msc, &mpam_restore_mbwu_state, ris); | ||
| 1346 | } | 1420 | } |
| 1347 | mutex_unlock(&msc->cfg_lock); | 1421 | mutex_unlock(&msc->cfg_lock); |
| 1348 | } | 1422 | } |
| @@ -1436,6 +1510,9 @@ static int mpam_cpu_offline(unsigned int cpu) · 87 unmodified lines | |||
| 1436 | * lost while the CPUs are offline. | 1510 | * lost while the CPUs are offline. |
| 1437 | */ | 1511 | */ |
| 1438 | ris->in_reset_state = false; | 1512 | ris->in_reset_state = false; |
| 1513 | |||
| 1514 | if (mpam_is_enabled()) | ||
| 1515 | mpam_touch_msc(msc, &mpam_save_mbwu_state, ris); | ||
| 1439 | } | 1516 | } |
| 1440 | mutex_unlock(&msc->cfg_lock); | 1517 | mutex_unlock(&msc->cfg_lock); |
| 1441 | } | 1518 | } |
| @@ -2109,7 +2186,22 @@ static void mpam_unregister_irqs(void) · 667 unmodified lines | |||
| 2109 | 2186 | ||
| 2110 | static void __destroy_component_cfg(struct mpam_component *comp) | 2187 | static void __destroy_component_cfg(struct mpam_component *comp) |
| 2111 | { | 2188 | { |
| 2189 | struct mpam_msc *msc; | ||
| 2190 | struct mpam_vmsc *vmsc; | ||
| 2191 | struct mpam_msc_ris *ris; | ||
| 2192 | |||
| 2193 | lockdep_assert_held(&mpam_list_lock); | ||
| 2194 | |||
| 2112 | add_to_garbage(comp->cfg); | 2195 | add_to_garbage(comp->cfg); |
| 2196 | list_for_each_entry(vmsc, &comp->vmsc, comp_list) { | ||
| 2197 | msc = vmsc->msc; | ||
| 2198 | |||
| 2199 | if (mpam_mon_sel_lock(msc)) { | ||
| 2200 | list_for_each_entry(ris, &vmsc->ris, vmsc_list) | ||
| 2201 | add_to_garbage(ris->mbwu_state); | ||
| 2202 | mpam_mon_sel_unlock(msc); | ||
| 2203 | } | ||
| 2204 | } | ||
| 2113 | } | 2205 | } |
| 2114 | 2206 | ||
| 2115 | static void mpam_reset_component_cfg(struct mpam_component *comp) | 2207 | static void mpam_reset_component_cfg(struct mpam_component *comp) |
| @@ -2135,6 +2227,8 @@ static void mpam_reset_component_cfg(struct mpam_component *comp) · 19 unmodified lines | |||
| 2135 | 2227 | ||
| 2136 | static int __allocate_component_cfg(struct mpam_component *comp) | 2228 | static int __allocate_component_cfg(struct mpam_component *comp) |
| 2137 | { | 2229 | { |
| 2230 | struct mpam_vmsc *vmsc; | ||
| 2231 | |||
| 2138 | mpam_assert_partid_sizes_fixed(); | 2232 | mpam_assert_partid_sizes_fixed(); |
| 2139 | 2233 | ||
| 2140 | if (comp->cfg) | 2234 | if (comp->cfg) |
| @@ -2152,6 +2246,36 @@ static int __allocate_component_cfg(struct mpam_component *comp) · 11 unmodified lines | |||
| 2152 | 2246 | ||
| 2153 | mpam_reset_component_cfg(comp); | 2247 | mpam_reset_component_cfg(comp); |
| 2154 | 2248 | ||
| 2249 | list_for_each_entry(vmsc, &comp->vmsc, comp_list) { | ||
| 2250 | struct mpam_msc *msc; | ||
| 2251 | struct mpam_msc_ris *ris; | ||
| 2252 | struct msmon_mbwu_state *mbwu_state; | ||
| 2253 | |||
| 2254 | if (!vmsc->props.num_mbwu_mon) | ||
| 2255 | continue; | ||
| 2256 | |||
| 2257 | msc = vmsc->msc; | ||
| 2258 | list_for_each_entry(ris, &vmsc->ris, vmsc_list) { | ||
| 2259 | if (!ris->props.num_mbwu_mon) | ||
| 2260 | continue; | ||
| 2261 | |||
| 2262 | mbwu_state = kcalloc(ris->props.num_mbwu_mon, | ||
| 2263 | sizeof(*ris->mbwu_state), | ||
| 2264 | GFP_KERNEL); | ||
| 2265 | if (!mbwu_state) { | ||
| 2266 | __destroy_component_cfg(comp); | ||
| 2267 | return -ENOMEM; | ||
| 2268 | } | ||
| 2269 | |||
| 2270 | init_garbage(&mbwu_state[0].garbage); | ||
| 2271 | |||
| 2272 | if (mpam_mon_sel_lock(msc)) { | ||
| 2273 | ris->mbwu_state = mbwu_state; | ||
| 2274 | mpam_mon_sel_unlock(msc); | ||
| 2275 | } | ||
| 2276 | } | ||
| 2277 | } | ||
| 2278 | |||
| 2155 | return 0; | 2279 | return 0; |
| 2156 | } | 2280 | } |
| 2157 | 2281 | ||
| @@ -91,7 +91,10 @@ struct mpam_msc { · 90 unmodified lines | |||
| 91 | */ | 91 | */ |
| 92 | struct mutex part_sel_lock; | 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 | struct mutex cfg_lock; | 98 | struct mutex cfg_lock; |
| 96 | 99 | ||
| 97 | /* | 100 | /* |
| @@ -202,6 +205,19 @@ struct mon_cfg { · 104 unmodified lines | |||
| 202 | enum mon_filter_options opts; | 205 | enum mon_filter_options opts; |
| 203 | }; | 206 | }; |
| 204 | 207 | ||
| 208 | /* Changes to msmon_mbwu_state are protected by the msc's mon_sel_lock. */ | ||
| 209 | struct msmon_mbwu_state { | ||
| 210 | bool enabled; | ||
| 211 | struct mon_cfg cfg; | ||
| 212 | |||
| 213 | /* | ||
| 214 | * The value to add to the new reading to account for power management. | ||
| 215 | */ | ||
| 216 | u64 correction; | ||
| 217 | |||
| 218 | struct mpam_garbage garbage; | ||
| 219 | }; | ||
| 220 | |||
| 205 | struct mpam_class { | 221 | struct mpam_class { |
| 206 | /* mpam_components in this class */ | 222 | /* mpam_components in this class */ |
| 207 | struct list_head components; | 223 | struct list_head components; |
| @@ -295,6 +311,9 @@ struct mpam_msc_ris { · 87 unmodified lines | |||
| 295 | /* parent: */ | 311 | /* parent: */ |
| 296 | struct mpam_vmsc *vmsc; | 312 | struct mpam_vmsc *vmsc; |
| 297 | 313 | ||
| 314 | /* msmon mbwu configuration is preserved over reset */ | ||
| 315 | struct msmon_mbwu_state *mbwu_state; | ||
| 316 | |||
| 298 | struct mpam_garbage garbage; | 317 | struct mpam_garbage garbage; |
| 299 | }; | 318 | }; |
| 300 | 319 | ||