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: Allow resctrl to allocate monitors

When resctrl wants to read a domain's 'QOS_L3_OCCUP', it needs to allocate
a monitor on the corresponding resource. Monitors are allocated by class
instead of component.

Add helpers to allocate a CSU monitor. These helper return an out of range
value for MBM counters.

Allocating a montitor context is expected to block until hardware resources
become available. This only makes sense for QOS_L3_OCCUP as unallocated MBM
counters are losing data.

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

+85 -1
+13 -1
drivers/resctrl/mpam_internal.h
··· 29 29 #define PACKED_FOR_KUNIT 30 30 #endif 31 31 32 + /* 33 + * This 'mon' values must not alias an actual monitor, so must be larger than 34 + * U16_MAX, but not be confused with an errno value, so smaller than 35 + * (u32)-SZ_4K. 36 + * USE_PRE_ALLOCATED is used to avoid confusion with an actual monitor. 37 + */ 38 + #define USE_PRE_ALLOCATED (U16_MAX + 1) 39 + 32 40 static inline bool mpam_is_enabled(void) 33 41 { 34 42 return static_branch_likely(&mpam_enabled); ··· 224 216 }; 225 217 226 218 struct mon_cfg { 227 - u16 mon; 219 + /* 220 + * mon must be large enough to hold out of range values like 221 + * USE_PRE_ALLOCATED 222 + */ 223 + u32 mon; 228 224 u8 pmg; 229 225 bool match_pmg; 230 226 bool csu_exclude_clean;
+67
drivers/resctrl/mpam_resctrl.c
··· 22 22 23 23 #include "mpam_internal.h" 24 24 25 + DECLARE_WAIT_QUEUE_HEAD(resctrl_mon_ctx_waiters); 26 + 25 27 /* 26 28 * The classes we've picked to map to resctrl resources, wrapped 27 29 * in with their resctrl structure. ··· 289 287 return NULL; 290 288 291 289 return &mpam_resctrl_controls[l].resctrl_res; 290 + } 291 + 292 + static int resctrl_arch_mon_ctx_alloc_no_wait(enum resctrl_event_id evtid) 293 + { 294 + struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[evtid]; 295 + 296 + if (!mon->class) 297 + return -EINVAL; 298 + 299 + switch (evtid) { 300 + case QOS_L3_OCCUP_EVENT_ID: 301 + /* With CDP, one monitor gets used for both code/data reads */ 302 + return mpam_alloc_csu_mon(mon->class); 303 + case QOS_L3_MBM_LOCAL_EVENT_ID: 304 + case QOS_L3_MBM_TOTAL_EVENT_ID: 305 + return USE_PRE_ALLOCATED; 306 + default: 307 + return -EOPNOTSUPP; 308 + } 309 + } 310 + 311 + void *resctrl_arch_mon_ctx_alloc(struct rdt_resource *r, 312 + enum resctrl_event_id evtid) 313 + { 314 + DEFINE_WAIT(wait); 315 + int *ret; 316 + 317 + ret = kmalloc_obj(*ret); 318 + if (!ret) 319 + return ERR_PTR(-ENOMEM); 320 + 321 + do { 322 + prepare_to_wait(&resctrl_mon_ctx_waiters, &wait, 323 + TASK_INTERRUPTIBLE); 324 + *ret = resctrl_arch_mon_ctx_alloc_no_wait(evtid); 325 + if (*ret == -ENOSPC) 326 + schedule(); 327 + } while (*ret == -ENOSPC && !signal_pending(current)); 328 + finish_wait(&resctrl_mon_ctx_waiters, &wait); 329 + 330 + return ret; 331 + } 332 + 333 + static void resctrl_arch_mon_ctx_free_no_wait(enum resctrl_event_id evtid, 334 + u32 mon_idx) 335 + { 336 + struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[evtid]; 337 + 338 + if (!mon->class) 339 + return; 340 + 341 + if (evtid == QOS_L3_OCCUP_EVENT_ID) 342 + mpam_free_csu_mon(mon->class, mon_idx); 343 + 344 + wake_up(&resctrl_mon_ctx_waiters); 345 + } 346 + 347 + void resctrl_arch_mon_ctx_free(struct rdt_resource *r, 348 + enum resctrl_event_id evtid, void *arch_mon_ctx) 349 + { 350 + u32 mon_idx = *(u32 *)arch_mon_ctx; 351 + 352 + kfree(arch_mon_ctx); 353 + 354 + resctrl_arch_mon_ctx_free_no_wait(evtid, mon_idx); 292 355 } 293 356 294 357 static bool cache_has_usable_cpor(struct mpam_class *class)
+5
include/linux/arm_mpam.h
··· 5 5 #define __LINUX_ARM_MPAM_H 6 6 7 7 #include <linux/acpi.h> 8 + #include <linux/resctrl_types.h> 8 9 #include <linux/types.h> 9 10 10 11 struct mpam_msc; ··· 62 61 u32 resctrl_arch_rmid_idx_encode(u32 closid, u32 rmid); 63 62 void resctrl_arch_rmid_idx_decode(u32 idx, u32 *closid, u32 *rmid); 64 63 u32 resctrl_arch_system_num_rmid_idx(void); 64 + 65 + struct rdt_resource; 66 + void *resctrl_arch_mon_ctx_alloc(struct rdt_resource *r, enum resctrl_event_id evtid); 67 + void resctrl_arch_mon_ctx_free(struct rdt_resource *r, enum resctrl_event_id evtid, void *ctx); 65 68 66 69 /** 67 70 * mpam_register_requestor() - Register a requestor with the MPAM driver