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.
Unified · Split
| @@ -993,6 +993,7 @@ static void __ris_msmon_read(void *arg) · 992 unmodified lines | ||
| 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; |
| @@ -1023,11 +1024,21 @@ static void __ris_msmon_read(void *arg) · 24 unmodified lines | ||
| 1023 | 1024 | now = mpam_read_monsel_reg(msc, CSU); |
| 1024 | 1025 | if (mpam_has_feature(mpam_feat_msmon_csu_hw_nrdy, rprops)) |
| 1025 | 1026 | nrdy = now & MSMON___NRDY; |
| 1027 | + now = FIELD_GET(MSMON___VALUE, now); | |
| 1026 | 1028 | break; |
| 1027 | 1029 | case mpam_feat_msmon_mbwu: |
| 1028 | 1030 | now = mpam_read_monsel_reg(msc, MBWU); |
| 1029 | 1031 | if (mpam_has_feature(mpam_feat_msmon_mbwu_hw_nrdy, rprops)) |
| 1030 | 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 | 1042 | break; |
| 1032 | 1043 | default: |
| 1033 | 1044 | m->err = -EINVAL; |
| @@ -1039,7 +1050,6 @@ static void __ris_msmon_read(void *arg) · 5 unmodified lines | ||
| 1039 | 1050 | return; |
| 1040 | 1051 | } |
| 1041 | 1052 | |
| 1042 | − now = FIELD_GET(MSMON___VALUE, now); | |
| 1043 | 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 | 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 | 1309 | static void mpam_init_reset_cfg(struct mpam_config *reset_cfg) |
| 1239 | 1310 | { |
| 1240 | 1311 | *reset_cfg = (struct mpam_config) { |
| @@ -1343,6 +1414,9 @@ static void mpam_reprogram_msc(struct mpam_msc *msc) · 102 unmodified lines | ||
| 1343 | 1414 | mpam_touch_msc(msc, __write_config, &arg); |
| 1344 | 1415 | } |
| 1345 | 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 | 1421 | mutex_unlock(&msc->cfg_lock); |
| 1348 | 1422 | } |
| @@ -1436,6 +1510,9 @@ static int mpam_cpu_offline(unsigned int cpu) · 87 unmodified lines | ||
| 1436 | 1510 | * lost while the CPUs are offline. |
| 1437 | 1511 | */ |
| 1438 | 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 | 1517 | mutex_unlock(&msc->cfg_lock); |
| 1441 | 1518 | } |
| @@ -2109,7 +2186,22 @@ static void mpam_unregister_irqs(void) · 667 unmodified lines | ||
| 2109 | 2186 | |
| 2110 | 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 | 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 | 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 | 2228 | static int __allocate_component_cfg(struct mpam_component *comp) |
| 2137 | 2229 | { |
| 2230 | + struct mpam_vmsc *vmsc; | |
| 2231 | + | |
| 2138 | 2232 | mpam_assert_partid_sizes_fixed(); |
| 2139 | 2233 | |
| 2140 | 2234 | if (comp->cfg) |
| @@ -2152,6 +2246,36 @@ static int __allocate_component_cfg(struct mpam_component *comp) · 11 unmodified lines | ||
| 2152 | 2246 | |
| 2153 | 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 | 2279 | return 0; |
| 2156 | 2280 | } |
| 2157 | 2281 | |
| @@ -91,7 +91,10 @@ struct mpam_msc { · 90 unmodified lines | ||
| 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 | /* |
| @@ -202,6 +205,19 @@ struct mon_cfg { · 104 unmodified lines | ||
| 202 | 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 | 221 | struct mpam_class { |
| 206 | 222 | /* mpam_components in this class */ |
| 207 | 223 | struct list_head components; |
| @@ -295,6 +311,9 @@ struct mpam_msc_ris { · 87 unmodified lines | ||
| 295 | 311 | /* parent: */ |
| 296 | 312 | struct mpam_vmsc *vmsc; |
| 297 | 313 | |
| 314 | + /* msmon mbwu configuration is preserved over reset */ | |
| 315 | + struct msmon_mbwu_state *mbwu_state; | |
| 316 | + | |
| 298 | 317 | struct mpam_garbage garbage; |
| 299 | 318 | }; |
| 300 | 319 | |