Pull arm64 MPAM fixes from Catalin Marinas: - Fix NULL dereference and a false-positive warning when the driver probes hardware with surprising version numbers - Fix writing values to the wrong registers when probing cache-utilisation counters. Replace 'NRDY' probing with a version that is robust for platforms where the bit is writeable by both hardware and software * tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux: arm_mpam: Check whether the config array is allocated before destroying it arm_mpam: Fix false positive assert failure during mpam_disable() arm_mpam: Improve check for whether or not NRDY is hardware managed arm_mpam: Pretend that NRDY is always hardware managed arm_mpam: Fix monitor instance selection when checking for hardware NRDY
Unified · Split
| @@ -164,11 +164,17 @@ static void mpam_free_garbage(void) · 163 unmodified lines | ||
| 164 | 164 | /* |
| 165 | 165 | * Once mpam is enabled, new requestors cannot further reduce the available |
| 166 | 166 | * partid. Assert that the size is fixed, and new requestors will be turned |
| 167 | − * away. | |
| 167 | + * away. This is needed when walking over structures sized by PARTID. | |
| 168 | + * | |
| 169 | + * During mpam_disable() these structures are not fixed, but the MSC state | |
| 170 | + * is still reset using whatever sizes have been discovered so far. As only | |
| 171 | + * PARTID 0 will be used after mpam_disable(), any race would be benign. | |
| 172 | + * Skip the check if a mpam_disable_reason has been set. | |
| 168 | 173 | */ |
| 169 | 174 | static void mpam_assert_partid_sizes_fixed(void) |
| 170 | 175 | { |
| 171 | − WARN_ON_ONCE(!partid_max_published); | |
| 176 | + if (!mpam_disable_reason) | |
| 177 | + WARN_ON_ONCE(!partid_max_published); | |
| 172 | 178 | } |
| 173 | 179 | |
| 174 | 180 | static u32 __mpam_read_reg(struct mpam_msc *msc, u16 reg) |
| @@ -728,10 +734,9 @@ static void mpam_enable_quirks(struct mpam_msc *msc) · 553 unmodified lines | ||
| 728 | 734 | * Try and see what values stick in this bit. If we can write either value, |
| 729 | 735 | * its probably not implemented by hardware. |
| 730 | 736 | */ |
| 731 | −static bool _mpam_ris_hw_probe_hw_nrdy(struct mpam_msc_ris *ris, u32 mon_reg) | |
| 737 | +static bool mpam_ris_hw_probe_csu_nrdy(struct mpam_msc_ris *ris) | |
| 732 | 738 | { |
| 733 | − u32 now; | |
| 734 | − u64 mon_sel; | |
| 739 | + u32 now, mon_sel, ctl_val; | |
| 735 | 740 | bool can_set, can_clear; |
| 736 | 741 | struct mpam_msc *msc = ris->vmsc->msc; |
| 737 | 742 | |
| @@ -740,23 +745,30 @@ static bool _mpam_ris_hw_probe_hw_nrdy(struct mpam_msc_ris *ris, u32 mon_reg) · 2 unmodified lines | ||
| 740 | 745 | |
| 741 | 746 | mon_sel = FIELD_PREP(MSMON_CFG_MON_SEL_MON_SEL, 0) | |
| 742 | 747 | FIELD_PREP(MSMON_CFG_MON_SEL_RIS, ris->ris_idx); |
| 743 | − _mpam_write_monsel_reg(msc, mon_reg, mon_sel); | |
| 748 | + mpam_write_monsel_reg(msc, CFG_MON_SEL, mon_sel); | |
| 749 | + | |
| 750 | + /* Hardware might ignore nrdy if it's not enabled */ | |
| 751 | + ctl_val = MSMON_CFG_CSU_CTL_TYPE_CSU; | |
| 752 | + ctl_val |= MSMON_CFG_x_CTL_MATCH_PARTID; | |
| 753 | + ctl_val |= MSMON_CFG_x_CTL_MATCH_PMG; | |
| 754 | + ctl_val |= MSMON_CFG_x_CTL_EN; | |
| 755 | + mpam_write_monsel_reg(msc, CFG_CSU_FLT, 0); | |
| 756 | + mpam_write_monsel_reg(msc, CFG_CSU_CTL, ctl_val); | |
| 744 | 757 | |
| 745 | − _mpam_write_monsel_reg(msc, mon_reg, MSMON___NRDY); | |
| 746 | − now = _mpam_read_monsel_reg(msc, mon_reg); | |
| 758 | + _mpam_write_monsel_reg(msc, MSMON_CSU, MSMON___NRDY); | |
| 759 | + now = _mpam_read_monsel_reg(msc, MSMON_CSU); | |
| 747 | 760 | can_set = now & MSMON___NRDY; |
| 748 | 761 | |
| 749 | − _mpam_write_monsel_reg(msc, mon_reg, 0); | |
| 750 | − now = _mpam_read_monsel_reg(msc, mon_reg); | |
| 762 | + _mpam_write_monsel_reg(msc, MSMON_CSU, 0); | |
| 763 | + /* Configuration change to try and coax hardware into setting nrdy */ | |
| 764 | + mpam_write_monsel_reg(msc, CFG_CSU_FLT, 0x1); | |
| 765 | + now = _mpam_read_monsel_reg(msc, MSMON_CSU); | |
| 751 | 766 | can_clear = !(now & MSMON___NRDY); |
| 752 | 767 | mpam_mon_sel_unlock(msc); |
| 753 | 768 | |
| 754 | 769 | return (!can_set || !can_clear); |
| 755 | 770 | } |
| 756 | 771 | |
| 757 | −#define mpam_ris_hw_probe_hw_nrdy(_ris, _mon_reg) \ | |
| 758 | − _mpam_ris_hw_probe_hw_nrdy(_ris, MSMON_##_mon_reg) | |
| 759 | − | |
| 760 | 772 | static void mpam_ris_hw_probe(struct mpam_msc_ris *ris) |
| 761 | 773 | { |
| 762 | 774 | int err; |
| @@ -873,20 +885,18 @@ static void mpam_ris_hw_probe(struct mpam_msc_ris *ris) · 110 unmodified lines | ||
| 873 | 885 | mpam_set_feature(mpam_feat_msmon_csu_xcl, props); |
| 874 | 886 | |
| 875 | 887 | /* Is NRDY hardware managed? */ |
| 876 | − hw_managed = mpam_ris_hw_probe_hw_nrdy(ris, CSU); | |
| 877 | − if (hw_managed) | |
| 878 | − mpam_set_feature(mpam_feat_msmon_csu_hw_nrdy, props); | |
| 879 | − } | |
| 888 | + hw_managed = mpam_ris_hw_probe_csu_nrdy(ris); | |
| 880 | 889 | |
| 881 | − /* | |
| 882 | − * Accept the missing firmware property if NRDY appears | |
| 883 | − * un-implemented. | |
| 884 | − */ | |
| 885 | − if (err && mpam_has_feature(mpam_feat_msmon_csu_hw_nrdy, props)) | |
| 886 | − dev_err_once(dev, "Counters are not usable because not-ready timeout was not provided by firmware."); | |
| 890 | + /* | |
| 891 | + * Accept the missing firmware property if NRDY appears | |
| 892 | + * un-implemented. | |
| 893 | + */ | |
| 894 | + if (err && hw_managed) | |
| 895 | + dev_err_once(dev, "Counters are not usable because not-ready timeout was not provided by firmware."); | |
| 896 | + } | |
| 887 | 897 | } |
| 888 | 898 | if (FIELD_GET(MPAMF_MSMON_IDR_MSMON_MBWU, msmon_features)) { |
| 889 | − bool has_long, hw_managed; | |
| 899 | + bool has_long; | |
| 890 | 900 | u32 mbwumon_idr = mpam_read_partsel_reg(msc, MBWUMON_IDR); |
| 891 | 901 | |
| 892 | 902 | props->num_mbwu_mon = FIELD_GET(MPAMF_MBWUMON_IDR_NUM_MON, mbwumon_idr); |
| @@ -905,16 +915,6 @@ static void mpam_ris_hw_probe(struct mpam_msc_ris *ris) · 12 unmodified lines | ||
| 905 | 915 | } else { |
| 906 | 916 | mpam_set_feature(mpam_feat_msmon_mbwu_31counter, props); |
| 907 | 917 | } |
| 908 | − | |
| 909 | − /* Is NRDY hardware managed? */ | |
| 910 | − hw_managed = mpam_ris_hw_probe_hw_nrdy(ris, MBWU); | |
| 911 | − if (hw_managed) | |
| 912 | − mpam_set_feature(mpam_feat_msmon_mbwu_hw_nrdy, props); | |
| 913 | − | |
| 914 | − /* | |
| 915 | − * Don't warn about any missing firmware property for | |
| 916 | − * MBWU NRDY - it doesn't make any sense! | |
| 917 | − */ | |
| 918 | 918 | } |
| 919 | 919 | } |
| 920 | 920 | } |
| @@ -1197,7 +1197,6 @@ static void __ris_msmon_read(void *arg) · 276 unmodified lines | ||
| 1197 | 1197 | bool reset_on_next_read = false; |
| 1198 | 1198 | struct mpam_msc_ris *ris = m->ris; |
| 1199 | 1199 | struct msmon_mbwu_state *mbwu_state; |
| 1200 | − struct mpam_props *rprops = &ris->props; | |
| 1201 | 1200 | struct mpam_msc *msc = m->ris->vmsc->msc; |
| 1202 | 1201 | u32 mon_sel, ctl_val, flt_val, cur_ctl, cur_flt; |
| 1203 | 1202 | |
| @@ -1253,8 +1252,7 @@ static void __ris_msmon_read(void *arg) · 49 unmodified lines | ||
| 1253 | 1252 | switch (m->type) { |
| 1254 | 1253 | case mpam_feat_msmon_csu: |
| 1255 | 1254 | now = mpam_read_monsel_reg(msc, CSU); |
| 1256 | − if (mpam_has_feature(mpam_feat_msmon_csu_hw_nrdy, rprops)) | |
| 1257 | − nrdy = now & MSMON___NRDY; | |
| 1255 | + nrdy = now & MSMON___NRDY; | |
| 1258 | 1256 | now = FIELD_GET(MSMON___VALUE, now); |
| 1259 | 1257 | |
| 1260 | 1258 | if (mpam_has_quirk(IGNORE_CSU_NRDY, msc) && m->waited_timeout) |
| @@ -1266,8 +1264,7 @@ static void __ris_msmon_read(void *arg) · 5 unmodified lines | ||
| 1266 | 1264 | case mpam_feat_msmon_mbwu_63counter: |
| 1267 | 1265 | if (m->type != mpam_feat_msmon_mbwu_31counter) { |
| 1268 | 1266 | now = mpam_msc_read_mbwu_l(msc); |
| 1269 | − if (mpam_has_feature(mpam_feat_msmon_mbwu_hw_nrdy, rprops)) | |
| 1270 | − nrdy = now & MSMON___L_NRDY; | |
| 1267 | + nrdy = now & MSMON___L_NRDY; | |
| 1271 | 1268 | |
| 1272 | 1269 | if (m->type == mpam_feat_msmon_mbwu_63counter) |
| 1273 | 1270 | now = FIELD_GET(MSMON___LWD_VALUE, now); |
| @@ -1275,8 +1272,7 @@ static void __ris_msmon_read(void *arg) · 1 unmodified line | ||
| 1275 | 1272 | now = FIELD_GET(MSMON___L_VALUE, now); |
| 1276 | 1273 | } else { |
| 1277 | 1274 | now = mpam_read_monsel_reg(msc, MBWU); |
| 1278 | − if (mpam_has_feature(mpam_feat_msmon_mbwu_hw_nrdy, rprops)) | |
| 1279 | − nrdy = now & MSMON___NRDY; | |
| 1275 | + nrdy = now & MSMON___NRDY; | |
| 1280 | 1276 | now = FIELD_GET(MSMON___VALUE, now); |
| 1281 | 1277 | } |
| 1282 | 1278 | |
| @@ -2585,6 +2581,9 @@ static void __destroy_component_cfg(struct mpam_component *comp) · 1302 unmodified lines | ||
| 2585 | 2581 | |
| 2586 | 2582 | lockdep_assert_held(&mpam_list_lock); |
| 2587 | 2583 | |
| 2584 | + if (!comp->cfg) | |
| 2585 | + return; | |
| 2586 | + | |
| 2588 | 2587 | add_to_garbage(comp->cfg); |
| 2589 | 2588 | list_for_each_entry(vmsc, &comp->vmsc, comp_list) { |
| 2590 | 2589 | msc = vmsc->msc; |
| @@ -181,14 +181,12 @@ enum mpam_device_features { · 180 unmodified lines | ||
| 181 | 181 | mpam_feat_msmon_csu, |
| 182 | 182 | mpam_feat_msmon_csu_capture, |
| 183 | 183 | mpam_feat_msmon_csu_xcl, |
| 184 | − mpam_feat_msmon_csu_hw_nrdy, | |
| 185 | 184 | mpam_feat_msmon_mbwu, |
| 186 | 185 | mpam_feat_msmon_mbwu_31counter, |
| 187 | 186 | mpam_feat_msmon_mbwu_44counter, |
| 188 | 187 | mpam_feat_msmon_mbwu_63counter, |
| 189 | 188 | mpam_feat_msmon_mbwu_capture, |
| 190 | 189 | mpam_feat_msmon_mbwu_rwbw, |
| 191 | − mpam_feat_msmon_mbwu_hw_nrdy, | |
| 192 | 190 | mpam_feat_partid_nrw, |
| 193 | 191 | MPAM_FEATURE_LAST |
| 194 | 192 | }; |