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: resctrl: Add monitor initialisation and domain boilerplate

Add the boilerplate that tells resctrl about the mpam monitors that are
available. resctrl expects all (non-telemetry) monitors to be on the L3 and
so advertise them there and invent an L3 resctrl resource if required. The
L3 cache itself has to exist as the cache ids are used as the domain
ids.

Bring the resctrl monitor domains online and offline based on the cpus
they contain.

Support for specific monitor types is left to later.

Tested-by: Punit Agrawal <punit.agrawal@oss.qualcomm.com>
Reviewed-by: Zeng Heng <zengheng4@huawei.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Signed-off-by: Ben Horgan <ben.horgan@arm.com>
Reviewed-by: Gavin Shan <gshan@redhat.com>
Tested-by: Gavin Shan <gshan@redhat.com>
Tested-by: Shaopeng Tan <tan.shaopeng@jp.fujitsu.com>
Tested-by: Jesse Chick <jessechick@os.amperecomputing.com>
Signed-off-by: James Morse <james.morse@arm.com>

authored by

Ben Horgan and committed by
James Morse
264c2859 5dc8f73e

+235 -11
+15
drivers/resctrl/mpam_internal.h
··· 336 336 337 337 struct mpam_resctrl_dom { 338 338 struct mpam_component *ctrl_comp; 339 + 340 + /* 341 + * There is no single mon_comp because different events may be backed 342 + * by different class/components. mon_comp is indexed by the event 343 + * number. 344 + */ 345 + struct mpam_component *mon_comp[QOS_NUM_EVENTS]; 346 + 339 347 struct rdt_ctrl_domain resctrl_ctrl_dom; 348 + struct rdt_l3_mon_domain resctrl_mon_dom; 340 349 }; 341 350 342 351 struct mpam_resctrl_res { 343 352 struct mpam_class *class; 344 353 struct rdt_resource resctrl_res; 345 354 bool cdp_enabled; 355 + }; 356 + 357 + struct mpam_resctrl_mon { 358 + struct mpam_class *class; 359 + 360 + /* per-class data that resctrl needs will live here */ 346 361 }; 347 362 348 363 static inline int mpam_alloc_csu_mon(struct mpam_class *class)
+220 -11
drivers/resctrl/mpam_resctrl.c
··· 34 34 rid < RDT_NUM_RESOURCES; \ 35 35 rid++, res = &mpam_resctrl_controls[rid]) 36 36 37 + /* 38 + * The classes we've picked to map to resctrl events. 39 + * Resctrl believes all the worlds a Xeon, and these are all on the L3. This 40 + * array lets us find the actual class backing the event counters. e.g. 41 + * the only memory bandwidth counters may be on the memory controller, but to 42 + * make use of them, we pretend they are on L3. Restrict the events considered 43 + * to those supported by MPAM. 44 + * Class pointer may be NULL. 45 + */ 46 + #define MPAM_MAX_EVENT QOS_L3_MBM_TOTAL_EVENT_ID 47 + static struct mpam_resctrl_mon mpam_resctrl_counters[MPAM_MAX_EVENT + 1]; 48 + 49 + #define for_each_mpam_resctrl_mon(mon, eventid) \ 50 + for (eventid = QOS_FIRST_EVENT, mon = &mpam_resctrl_counters[eventid]; \ 51 + eventid <= MPAM_MAX_EVENT; \ 52 + eventid++, mon = &mpam_resctrl_counters[eventid]) 53 + 37 54 /* The lock for modifying resctrl's domain lists from cpuhp callbacks. */ 38 55 static DEFINE_MUTEX(domain_list_lock); 39 56 ··· 80 63 return false; 81 64 } 82 65 66 + bool resctrl_arch_mon_capable(void) 67 + { 68 + struct mpam_resctrl_res *res = &mpam_resctrl_controls[RDT_RESOURCE_L3]; 69 + struct rdt_resource *l3 = &res->resctrl_res; 70 + 71 + /* All monitors are presented as being on the L3 cache */ 72 + return l3->mon_capable; 73 + } 74 + 83 75 bool resctrl_arch_get_cdp_enabled(enum resctrl_res_level rid) 84 76 { 85 77 return mpam_resctrl_controls[rid].cdp_enabled; ··· 115 89 int resctrl_arch_set_cdp_enabled(enum resctrl_res_level rid, bool enable) 116 90 { 117 91 u32 partid_i = RESCTRL_RESERVED_CLOSID, partid_d = RESCTRL_RESERVED_CLOSID; 92 + struct mpam_resctrl_res *res = &mpam_resctrl_controls[RDT_RESOURCE_L3]; 93 + struct rdt_resource *l3 = &res->resctrl_res; 118 94 int cpu; 119 95 120 96 if (!IS_ENABLED(CONFIG_EXPERT) && enable) { ··· 137 109 */ 138 110 cdp_enabled = enable; 139 111 mpam_resctrl_controls[rid].cdp_enabled = enable; 112 + 113 + if (enable) 114 + l3->mon.num_rmid = resctrl_arch_system_num_rmid_idx() / 2; 115 + else 116 + l3->mon.num_rmid = resctrl_arch_system_num_rmid_idx(); 140 117 141 118 /* The mbw_max feature can't hide cdp as it's a per-partid maximum. */ 142 119 if (cdp_enabled && !mpam_resctrl_controls[RDT_RESOURCE_MBA].cdp_enabled) ··· 707 674 return comp->comp_id; 708 675 } 709 676 677 + static int mpam_resctrl_monitor_init(struct mpam_resctrl_mon *mon, 678 + enum resctrl_event_id type) 679 + { 680 + struct mpam_resctrl_res *res = &mpam_resctrl_controls[RDT_RESOURCE_L3]; 681 + struct rdt_resource *l3 = &res->resctrl_res; 682 + 683 + lockdep_assert_cpus_held(); 684 + 685 + /* 686 + * There also needs to be an L3 cache present. 687 + * The check just requires any online CPU and it can't go offline as we 688 + * hold the cpu lock. 689 + */ 690 + if (get_cpu_cacheinfo_id(raw_smp_processor_id(), 3) == -1) 691 + return 0; 692 + 693 + /* 694 + * If there are no MPAM resources on L3, force it into existence. 695 + * topology_matches_l3() already ensures this looks like the L3. 696 + * The domain-ids will be fixed up by mpam_resctrl_domain_hdr_init(). 697 + */ 698 + if (!res->class) { 699 + pr_warn_once("Faking L3 MSC to enable counters.\n"); 700 + res->class = mpam_resctrl_counters[type].class; 701 + } 702 + 703 + /* 704 + * Called multiple times!, once per event type that has a 705 + * monitoring class. 706 + * Setting name is necessary on monitor only platforms. 707 + */ 708 + l3->name = "L3"; 709 + l3->mon_scope = RESCTRL_L3_CACHE; 710 + 711 + /* 712 + * num-rmid is the upper bound for the number of monitoring groups that 713 + * can exist simultaneously, including the default monitoring group for 714 + * each control group. Hence, advertise the whole rmid_idx space even 715 + * though each control group has its own pmg/rmid space. Unfortunately, 716 + * this does mean userspace needs to know the architecture to correctly 717 + * interpret this value. 718 + */ 719 + l3->mon.num_rmid = resctrl_arch_system_num_rmid_idx(); 720 + 721 + if (resctrl_enable_mon_event(type, false, 0, NULL)) 722 + l3->mon_capable = true; 723 + 724 + return 0; 725 + } 726 + 710 727 u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d, 711 728 u32 closid, enum resctrl_conf_type type) 712 729 { ··· 984 901 list_add_tail_rcu(&new->list, pos); 985 902 } 986 903 904 + static struct mpam_component *find_component(struct mpam_class *class, int cpu) 905 + { 906 + struct mpam_component *comp; 907 + 908 + guard(srcu)(&mpam_srcu); 909 + list_for_each_entry_srcu(comp, &class->components, class_list, 910 + srcu_read_lock_held(&mpam_srcu)) { 911 + if (cpumask_test_cpu(cpu, &comp->affinity)) 912 + return comp; 913 + } 914 + 915 + return NULL; 916 + } 917 + 987 918 static struct mpam_resctrl_dom * 988 919 mpam_resctrl_alloc_domain(unsigned int cpu, struct mpam_resctrl_res *res) 989 920 { 990 921 int err; 991 922 struct mpam_resctrl_dom *dom; 923 + struct rdt_l3_mon_domain *mon_d; 992 924 struct rdt_ctrl_domain *ctrl_d; 993 925 struct mpam_class *class = res->class; 994 926 struct mpam_component *comp_iter, *ctrl_comp; ··· 1043 945 } else { 1044 946 pr_debug("Skipped control domain online - no controls\n"); 1045 947 } 948 + 949 + if (r->mon_capable) { 950 + struct mpam_component *any_mon_comp; 951 + struct mpam_resctrl_mon *mon; 952 + enum resctrl_event_id eventid; 953 + 954 + /* 955 + * Even if the monitor domain is backed by a different 956 + * component, the L3 component IDs need to be used... only 957 + * there may be no ctrl_comp for the L3. 958 + * Search each event's class list for a component with 959 + * overlapping CPUs and set up the dom->mon_comp array. 960 + */ 961 + 962 + for_each_mpam_resctrl_mon(mon, eventid) { 963 + struct mpam_component *mon_comp; 964 + 965 + if (!mon->class) 966 + continue; // dummy resource 967 + 968 + mon_comp = find_component(mon->class, cpu); 969 + dom->mon_comp[eventid] = mon_comp; 970 + if (mon_comp) 971 + any_mon_comp = mon_comp; 972 + } 973 + if (!any_mon_comp) { 974 + WARN_ON_ONCE(0); 975 + err = -EFAULT; 976 + goto offline_ctrl_domain; 977 + } 978 + 979 + mon_d = &dom->resctrl_mon_dom; 980 + mpam_resctrl_domain_hdr_init(cpu, any_mon_comp, r->rid, &mon_d->hdr); 981 + mon_d->hdr.type = RESCTRL_MON_DOMAIN; 982 + err = resctrl_online_mon_domain(r, &mon_d->hdr); 983 + if (err) 984 + goto offline_ctrl_domain; 985 + 986 + mpam_resctrl_domain_insert(&r->mon_domains, &mon_d->hdr); 987 + } else { 988 + pr_debug("Skipped monitor domain online - no monitors\n"); 989 + } 990 + 1046 991 return dom; 1047 992 993 + offline_ctrl_domain: 994 + if (r->alloc_capable) { 995 + mpam_resctrl_offline_domain_hdr(cpu, &ctrl_d->hdr); 996 + resctrl_offline_ctrl_domain(r, ctrl_d); 997 + } 1048 998 free_domain: 1049 999 kfree(dom); 1050 1000 dom = ERR_PTR(err); 1051 1001 1052 1002 return dom; 1003 + } 1004 + 1005 + /* 1006 + * We know all the monitors are associated with the L3, even if there are no 1007 + * controls and therefore no control component. Find the cache-id for the CPU 1008 + * and use that to search for existing resctrl domains. 1009 + * This relies on mpam_resctrl_pick_domain_id() using the L3 cache-id 1010 + * for anything that is not a cache. 1011 + */ 1012 + static struct mpam_resctrl_dom *mpam_resctrl_get_mon_domain_from_cpu(int cpu) 1013 + { 1014 + int cache_id; 1015 + struct mpam_resctrl_dom *dom; 1016 + struct mpam_resctrl_res *l3 = &mpam_resctrl_controls[RDT_RESOURCE_L3]; 1017 + 1018 + lockdep_assert_cpus_held(); 1019 + 1020 + if (!l3->class) 1021 + return NULL; 1022 + cache_id = get_cpu_cacheinfo_id(cpu, 3); 1023 + if (cache_id < 0) 1024 + return NULL; 1025 + 1026 + list_for_each_entry_rcu(dom, &l3->resctrl_res.mon_domains, resctrl_mon_dom.hdr.list) { 1027 + if (dom->resctrl_mon_dom.hdr.id == cache_id) 1028 + return dom; 1029 + } 1030 + 1031 + return NULL; 1053 1032 } 1054 1033 1055 1034 static struct mpam_resctrl_dom * ··· 1142 967 return dom; 1143 968 } 1144 969 1145 - return NULL; 970 + if (r->rid != RDT_RESOURCE_L3) 971 + return NULL; 972 + 973 + /* Search the mon domain list too - needed on monitor only platforms. */ 974 + return mpam_resctrl_get_mon_domain_from_cpu(cpu); 1146 975 } 1147 976 1148 977 int mpam_resctrl_online_cpu(unsigned int cpu) ··· 1173 994 1174 995 mpam_resctrl_online_domain_hdr(cpu, &ctrl_d->hdr); 1175 996 } 997 + if (r->mon_capable) { 998 + struct rdt_l3_mon_domain *mon_d = &dom->resctrl_mon_dom; 999 + 1000 + mpam_resctrl_online_domain_hdr(cpu, &mon_d->hdr); 1001 + } 1176 1002 } 1177 1003 } 1178 1004 ··· 1196 1012 guard(mutex)(&domain_list_lock); 1197 1013 for_each_mpam_resctrl_control(res, rid) { 1198 1014 struct mpam_resctrl_dom *dom; 1015 + struct rdt_l3_mon_domain *mon_d; 1199 1016 struct rdt_ctrl_domain *ctrl_d; 1200 - bool ctrl_dom_empty; 1017 + bool ctrl_dom_empty, mon_dom_empty; 1201 1018 struct rdt_resource *r = &res->resctrl_res; 1202 1019 1203 1020 if (!res->class) ··· 1217 1032 ctrl_dom_empty = true; 1218 1033 } 1219 1034 1220 - if (ctrl_dom_empty) 1035 + if (r->mon_capable) { 1036 + mon_d = &dom->resctrl_mon_dom; 1037 + mon_dom_empty = mpam_resctrl_offline_domain_hdr(cpu, &mon_d->hdr); 1038 + if (mon_dom_empty) 1039 + resctrl_offline_mon_domain(&res->resctrl_res, &mon_d->hdr); 1040 + } else { 1041 + mon_dom_empty = true; 1042 + } 1043 + 1044 + if (ctrl_dom_empty && mon_dom_empty) 1221 1045 kfree(dom); 1222 1046 } 1223 1047 } ··· 1236 1042 int err = 0; 1237 1043 struct mpam_resctrl_res *res; 1238 1044 enum resctrl_res_level rid; 1045 + struct mpam_resctrl_mon *mon; 1046 + enum resctrl_event_id eventid; 1239 1047 1240 1048 wait_event(wait_cacheinfo_ready, cacheinfo_ready); 1241 1049 1242 1050 cpus_read_lock(); 1243 1051 for_each_mpam_resctrl_control(res, rid) { 1244 1052 INIT_LIST_HEAD_RCU(&res->resctrl_res.ctrl_domains); 1053 + INIT_LIST_HEAD_RCU(&res->resctrl_res.mon_domains); 1245 1054 res->resctrl_res.rid = rid; 1246 1055 } 1247 1056 ··· 1260 1063 err = mpam_resctrl_control_init(res); 1261 1064 if (err) { 1262 1065 pr_debug("Failed to initialise rid %u\n", rid); 1263 - break; 1066 + goto internal_error; 1264 1067 } 1265 1068 } 1266 - cpus_read_unlock(); 1267 1069 1268 - if (err) { 1269 - pr_debug("Internal error %d - resctrl not supported\n", err); 1270 - return err; 1070 + for_each_mpam_resctrl_mon(mon, eventid) { 1071 + if (!mon->class) 1072 + continue; // dummy resource 1073 + 1074 + err = mpam_resctrl_monitor_init(mon, eventid); 1075 + if (err) { 1076 + pr_debug("Failed to initialise event %u\n", eventid); 1077 + goto internal_error; 1078 + } 1271 1079 } 1272 1080 1273 - if (!resctrl_arch_alloc_capable()) { 1274 - pr_debug("No alloc(%u) found - resctrl not supported\n", 1275 - resctrl_arch_alloc_capable()); 1081 + cpus_read_unlock(); 1082 + 1083 + if (!resctrl_arch_alloc_capable() && !resctrl_arch_mon_capable()) { 1084 + pr_debug("No alloc(%u) or monitor(%u) found - resctrl not supported\n", 1085 + resctrl_arch_alloc_capable(), resctrl_arch_mon_capable()); 1276 1086 return -EOPNOTSUPP; 1277 1087 } 1278 1088 1279 1089 /* TODO: call resctrl_init() */ 1280 1090 1281 1091 return 0; 1092 + 1093 + internal_error: 1094 + cpus_read_unlock(); 1095 + pr_debug("Internal error %d - resctrl not supported\n", err); 1096 + return err; 1282 1097 } 1283 1098 1284 1099 static int __init __cacheinfo_ready(void)