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: Add mpam_msmon_read() to read monitor value

Reading a monitor involves configuring what you want to monitor, and
reading the value. Components made up of multiple MSC may need values
from each MSC. MSCs may take time to configure, returning 'not ready'.
The maximum 'not ready' time should have been provided by firmware.

Add mpam_msmon_read() to hide all this. If (one of) the MSC returns
not ready, then wait the full timeout value before trying again.

CC: Shanker Donthineni <sdonthineni@nvidia.com>
Cc: Shaopeng Tan (Fujitsu) <tan.shaopeng@fujitsu.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Reviewed-by: Gavin Shan <gshan@redhat.com>
Reviewed-by: Shaopeng Tan <tan.shaopeng@jp.fujitsu.com>
Reviewed-by: Fenghua Yu <fenghuay@nvidia.com>
Tested-by: Shaopeng Tan <tan.shaopeng@jp.fujitsu.com>
Tested-by: Peter Newman <peternewman@google.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: 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
823e7c37 c891bae6

+254
+235
drivers/resctrl/mpam_devices.c
··· 886 886 return 0; 887 887 } 888 888 889 + struct mon_read { 890 + struct mpam_msc_ris *ris; 891 + struct mon_cfg *ctx; 892 + enum mpam_device_features type; 893 + u64 *val; 894 + int err; 895 + }; 896 + 897 + static void gen_msmon_ctl_flt_vals(struct mon_read *m, u32 *ctl_val, 898 + u32 *flt_val) 899 + { 900 + struct mon_cfg *ctx = m->ctx; 901 + 902 + /* 903 + * For CSU counters its implementation-defined what happens when not 904 + * filtering by partid. 905 + */ 906 + *ctl_val = MSMON_CFG_x_CTL_MATCH_PARTID; 907 + 908 + *flt_val = FIELD_PREP(MSMON_CFG_x_FLT_PARTID, ctx->partid); 909 + 910 + if (m->ctx->match_pmg) { 911 + *ctl_val |= MSMON_CFG_x_CTL_MATCH_PMG; 912 + *flt_val |= FIELD_PREP(MSMON_CFG_x_FLT_PMG, ctx->pmg); 913 + } 914 + 915 + switch (m->type) { 916 + case mpam_feat_msmon_csu: 917 + *ctl_val |= MSMON_CFG_CSU_CTL_TYPE_CSU; 918 + 919 + if (mpam_has_feature(mpam_feat_msmon_csu_xcl, &m->ris->props)) 920 + *flt_val |= FIELD_PREP(MSMON_CFG_CSU_FLT_XCL, ctx->csu_exclude_clean); 921 + 922 + break; 923 + case mpam_feat_msmon_mbwu: 924 + *ctl_val |= MSMON_CFG_MBWU_CTL_TYPE_MBWU; 925 + 926 + if (mpam_has_feature(mpam_feat_msmon_mbwu_rwbw, &m->ris->props)) 927 + *flt_val |= FIELD_PREP(MSMON_CFG_MBWU_FLT_RWBW, ctx->opts); 928 + 929 + break; 930 + default: 931 + pr_warn("Unexpected monitor type %d\n", m->type); 932 + } 933 + } 934 + 935 + static void read_msmon_ctl_flt_vals(struct mon_read *m, u32 *ctl_val, 936 + u32 *flt_val) 937 + { 938 + struct mpam_msc *msc = m->ris->vmsc->msc; 939 + 940 + switch (m->type) { 941 + case mpam_feat_msmon_csu: 942 + *ctl_val = mpam_read_monsel_reg(msc, CFG_CSU_CTL); 943 + *flt_val = mpam_read_monsel_reg(msc, CFG_CSU_FLT); 944 + break; 945 + case mpam_feat_msmon_mbwu: 946 + *ctl_val = mpam_read_monsel_reg(msc, CFG_MBWU_CTL); 947 + *flt_val = mpam_read_monsel_reg(msc, CFG_MBWU_FLT); 948 + break; 949 + default: 950 + pr_warn("Unexpected monitor type %d\n", m->type); 951 + } 952 + } 953 + 954 + /* Remove values set by the hardware to prevent apparent mismatches. */ 955 + static inline void clean_msmon_ctl_val(u32 *cur_ctl) 956 + { 957 + *cur_ctl &= ~MSMON_CFG_x_CTL_OFLOW_STATUS; 958 + } 959 + 960 + static void write_msmon_ctl_flt_vals(struct mon_read *m, u32 ctl_val, 961 + u32 flt_val) 962 + { 963 + struct mpam_msc *msc = m->ris->vmsc->msc; 964 + 965 + /* 966 + * Write the ctl_val with the enable bit cleared, reset the counter, 967 + * then enable counter. 968 + */ 969 + switch (m->type) { 970 + case mpam_feat_msmon_csu: 971 + mpam_write_monsel_reg(msc, CFG_CSU_FLT, flt_val); 972 + mpam_write_monsel_reg(msc, CFG_CSU_CTL, ctl_val); 973 + mpam_write_monsel_reg(msc, CSU, 0); 974 + mpam_write_monsel_reg(msc, CFG_CSU_CTL, ctl_val | MSMON_CFG_x_CTL_EN); 975 + break; 976 + case mpam_feat_msmon_mbwu: 977 + mpam_write_monsel_reg(msc, CFG_MBWU_FLT, flt_val); 978 + mpam_write_monsel_reg(msc, CFG_MBWU_CTL, ctl_val); 979 + mpam_write_monsel_reg(msc, CFG_MBWU_CTL, ctl_val | MSMON_CFG_x_CTL_EN); 980 + /* Counting monitors require NRDY to be reset by software */ 981 + mpam_write_monsel_reg(msc, MBWU, 0); 982 + break; 983 + default: 984 + pr_warn("Unexpected monitor type %d\n", m->type); 985 + } 986 + } 987 + 988 + static void __ris_msmon_read(void *arg) 989 + { 990 + u64 now; 991 + bool nrdy = false; 992 + bool config_mismatch; 993 + struct mon_read *m = arg; 994 + struct mon_cfg *ctx = m->ctx; 995 + struct mpam_msc_ris *ris = m->ris; 996 + struct mpam_props *rprops = &ris->props; 997 + struct mpam_msc *msc = m->ris->vmsc->msc; 998 + u32 mon_sel, ctl_val, flt_val, cur_ctl, cur_flt; 999 + 1000 + if (!mpam_mon_sel_lock(msc)) { 1001 + m->err = -EIO; 1002 + return; 1003 + } 1004 + mon_sel = FIELD_PREP(MSMON_CFG_MON_SEL_MON_SEL, ctx->mon) | 1005 + FIELD_PREP(MSMON_CFG_MON_SEL_RIS, ris->ris_idx); 1006 + mpam_write_monsel_reg(msc, CFG_MON_SEL, mon_sel); 1007 + 1008 + /* 1009 + * Read the existing configuration to avoid re-writing the same values. 1010 + * This saves waiting for 'nrdy' on subsequent reads. 1011 + */ 1012 + read_msmon_ctl_flt_vals(m, &cur_ctl, &cur_flt); 1013 + clean_msmon_ctl_val(&cur_ctl); 1014 + gen_msmon_ctl_flt_vals(m, &ctl_val, &flt_val); 1015 + config_mismatch = cur_flt != flt_val || 1016 + cur_ctl != (ctl_val | MSMON_CFG_x_CTL_EN); 1017 + 1018 + if (config_mismatch) 1019 + write_msmon_ctl_flt_vals(m, ctl_val, flt_val); 1020 + 1021 + switch (m->type) { 1022 + case mpam_feat_msmon_csu: 1023 + now = mpam_read_monsel_reg(msc, CSU); 1024 + if (mpam_has_feature(mpam_feat_msmon_csu_hw_nrdy, rprops)) 1025 + nrdy = now & MSMON___NRDY; 1026 + break; 1027 + case mpam_feat_msmon_mbwu: 1028 + now = mpam_read_monsel_reg(msc, MBWU); 1029 + if (mpam_has_feature(mpam_feat_msmon_mbwu_hw_nrdy, rprops)) 1030 + nrdy = now & MSMON___NRDY; 1031 + break; 1032 + default: 1033 + m->err = -EINVAL; 1034 + } 1035 + mpam_mon_sel_unlock(msc); 1036 + 1037 + if (nrdy) { 1038 + m->err = -EBUSY; 1039 + return; 1040 + } 1041 + 1042 + now = FIELD_GET(MSMON___VALUE, now); 1043 + *m->val += now; 1044 + } 1045 + 1046 + static int _msmon_read(struct mpam_component *comp, struct mon_read *arg) 1047 + { 1048 + int err, any_err = 0; 1049 + struct mpam_vmsc *vmsc; 1050 + 1051 + guard(srcu)(&mpam_srcu); 1052 + list_for_each_entry_srcu(vmsc, &comp->vmsc, comp_list, 1053 + srcu_read_lock_held(&mpam_srcu)) { 1054 + struct mpam_msc *msc = vmsc->msc; 1055 + struct mpam_msc_ris *ris; 1056 + 1057 + list_for_each_entry_srcu(ris, &vmsc->ris, vmsc_list, 1058 + srcu_read_lock_held(&mpam_srcu)) { 1059 + arg->ris = ris; 1060 + 1061 + err = smp_call_function_any(&msc->accessibility, 1062 + __ris_msmon_read, arg, 1063 + true); 1064 + if (!err && arg->err) 1065 + err = arg->err; 1066 + 1067 + /* 1068 + * Save one error to be returned to the caller, but 1069 + * keep reading counters so that get reprogrammed. On 1070 + * platforms with NRDY this lets us wait once. 1071 + */ 1072 + if (err) 1073 + any_err = err; 1074 + } 1075 + } 1076 + 1077 + return any_err; 1078 + } 1079 + 1080 + int mpam_msmon_read(struct mpam_component *comp, struct mon_cfg *ctx, 1081 + enum mpam_device_features type, u64 *val) 1082 + { 1083 + int err; 1084 + struct mon_read arg; 1085 + u64 wait_jiffies = 0; 1086 + struct mpam_props *cprops = &comp->class->props; 1087 + 1088 + might_sleep(); 1089 + 1090 + if (!mpam_is_enabled()) 1091 + return -EIO; 1092 + 1093 + if (!mpam_has_feature(type, cprops)) 1094 + return -EOPNOTSUPP; 1095 + 1096 + arg = (struct mon_read) { 1097 + .ctx = ctx, 1098 + .type = type, 1099 + .val = val, 1100 + }; 1101 + *val = 0; 1102 + 1103 + err = _msmon_read(comp, &arg); 1104 + if (err == -EBUSY && comp->class->nrdy_usec) 1105 + wait_jiffies = usecs_to_jiffies(comp->class->nrdy_usec); 1106 + 1107 + while (wait_jiffies) 1108 + wait_jiffies = schedule_timeout_uninterruptible(wait_jiffies); 1109 + 1110 + if (err == -EBUSY) { 1111 + arg = (struct mon_read) { 1112 + .ctx = ctx, 1113 + .type = type, 1114 + .val = val, 1115 + }; 1116 + *val = 0; 1117 + 1118 + err = _msmon_read(comp, &arg); 1119 + } 1120 + 1121 + return err; 1122 + } 1123 + 889 1124 static void mpam_reset_msc_bitmap(struct mpam_msc *msc, u16 reg, u16 wd) 890 1125 { 891 1126 u32 num_words, msb;
+19
drivers/resctrl/mpam_internal.h
··· 186 186 #define mpam_set_feature(_feat, x) set_bit(_feat, (x)->features) 187 187 #define mpam_clear_feature(_feat, x) clear_bit(_feat, (x)->features) 188 188 189 + /* The values for MSMON_CFG_MBWU_FLT.RWBW */ 190 + enum mon_filter_options { 191 + COUNT_BOTH = 0, 192 + COUNT_WRITE = 1, 193 + COUNT_READ = 2, 194 + }; 195 + 196 + struct mon_cfg { 197 + u16 mon; 198 + u8 pmg; 199 + bool match_pmg; 200 + bool csu_exclude_clean; 201 + u32 partid; 202 + enum mon_filter_options opts; 203 + }; 204 + 189 205 struct mpam_class { 190 206 /* mpam_components in this class */ 191 207 struct list_head components; ··· 344 328 345 329 int mpam_apply_config(struct mpam_component *comp, u16 partid, 346 330 struct mpam_config *cfg); 331 + 332 + int mpam_msmon_read(struct mpam_component *comp, struct mon_cfg *ctx, 333 + enum mpam_device_features, u64 *val); 347 334 348 335 int mpam_get_cpumask_from_cache_id(unsigned long cache_id, u32 cache_level, 349 336 cpumask_t *affinity);