cpuhp callbacks aren't the only time the MSC configuration may need to be reset. Resctrl has an API call to reset a class. If an MPAM error interrupt arrives it indicates the driver has misprogrammed an MSC. The safest thing to do is reset all the MSCs and disable MPAM. Add a helper to reset RIS via their class. Call this from mpam_disable(), which can be scheduled from the error interrupt handler.
Showing the changes to drivers/resctrl (1 of 1 file). Show all
Unified · Split
| @@ -808,15 +808,13 @@ static void mpam_reset_ris_partid(struct mpam_msc_ris *ris, u16 partid) · 807 unmodified lines | ||
| 808 | 808 | |
| 809 | 809 | /* |
| 810 | 810 | * Called via smp_call_on_cpu() to prevent migration, while still being |
| 811 | − * pre-emptible. | |
| 811 | + * pre-emptible. Caller must hold mpam_srcu. | |
| 812 | 812 | */ |
| 813 | 813 | static int mpam_reset_ris(void *arg) |
| 814 | 814 | { |
| 815 | 815 | u16 partid, partid_max; |
| 816 | 816 | struct mpam_msc_ris *ris = arg; |
| 817 | 817 | |
| 818 | − WARN_ON_ONCE(!srcu_read_lock_held((&mpam_srcu))); | |
| 819 | − | |
| 820 | 818 | if (ris->in_reset_state) |
| 821 | 819 | return 0; |
| 822 | 820 | |
| @@ -1337,8 +1335,55 @@ static void mpam_enable_once(void) · 514 unmodified lines | ||
| 1337 | 1335 | mpam_partid_max + 1, mpam_pmg_max + 1); |
| 1338 | 1336 | } |
| 1339 | 1337 | |
| 1338 | +static void mpam_reset_component_locked(struct mpam_component *comp) | |
| 1339 | +{ | |
| 1340 | + struct mpam_vmsc *vmsc; | |
| 1341 | + | |
| 1342 | + lockdep_assert_cpus_held(); | |
| 1343 | + | |
| 1344 | + guard(srcu)(&mpam_srcu); | |
| 1345 | + list_for_each_entry_srcu(vmsc, &comp->vmsc, comp_list, | |
| 1346 | + srcu_read_lock_held(&mpam_srcu)) { | |
| 1347 | + struct mpam_msc *msc = vmsc->msc; | |
| 1348 | + struct mpam_msc_ris *ris; | |
| 1349 | + | |
| 1350 | + list_for_each_entry_srcu(ris, &vmsc->ris, vmsc_list, | |
| 1351 | + srcu_read_lock_held(&mpam_srcu)) { | |
| 1352 | + if (!ris->in_reset_state) | |
| 1353 | + mpam_touch_msc(msc, mpam_reset_ris, ris); | |
| 1354 | + ris->in_reset_state = true; | |
| 1355 | + } | |
| 1356 | + } | |
| 1357 | +} | |
| 1358 | + | |
| 1359 | +static void mpam_reset_class_locked(struct mpam_class *class) | |
| 1360 | +{ | |
| 1361 | + struct mpam_component *comp; | |
| 1362 | + | |
| 1363 | + lockdep_assert_cpus_held(); | |
| 1364 | + | |
| 1365 | + guard(srcu)(&mpam_srcu); | |
| 1366 | + list_for_each_entry_srcu(comp, &class->components, class_list, | |
| 1367 | + srcu_read_lock_held(&mpam_srcu)) | |
| 1368 | + mpam_reset_component_locked(comp); | |
| 1369 | +} | |
| 1370 | + | |
| 1371 | +static void mpam_reset_class(struct mpam_class *class) | |
| 1372 | +{ | |
| 1373 | + cpus_read_lock(); | |
| 1374 | + mpam_reset_class_locked(class); | |
| 1375 | + cpus_read_unlock(); | |
| 1376 | +} | |
| 1377 | + | |
| 1378 | +/* | |
| 1379 | + * Called in response to an error IRQ. | |
| 1380 | + * All of MPAMs errors indicate a software bug, restore any modified | |
| 1381 | + * controls to their reset values. | |
| 1382 | + */ | |
| 1340 | 1383 | void mpam_disable(struct work_struct *ignored) |
| 1341 | 1384 | { |
| 1385 | + int idx; | |
| 1386 | + struct mpam_class *class; | |
| 1342 | 1387 | struct mpam_msc *msc, *tmp; |
| 1343 | 1388 | |
| 1344 | 1389 | mutex_lock(&mpam_cpuhp_state_lock); |
| @@ -1348,6 +1393,12 @@ void mpam_disable(struct work_struct *ignored) · 3 unmodified lines | ||
| 1348 | 1393 | } |
| 1349 | 1394 | mutex_unlock(&mpam_cpuhp_state_lock); |
| 1350 | 1395 | |
| 1396 | + idx = srcu_read_lock(&mpam_srcu); | |
| 1397 | + list_for_each_entry_srcu(class, &mpam_classes, classes_list, | |
| 1398 | + srcu_read_lock_held(&mpam_srcu)) | |
| 1399 | + mpam_reset_class(class); | |
| 1400 | + srcu_read_unlock(&mpam_srcu, idx); | |
| 1401 | + | |
| 1351 | 1402 | mutex_lock(&mpam_list_lock); |
| 1352 | 1403 | list_for_each_entry_safe(msc, tmp, &mpam_all_msc, all_msc_list) |
| 1353 | 1404 | mpam_msc_destroy(msc); |