Skip to content

Commit 2a3c79c

Browse files
author
James Morse
committed
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>
1 parent 1458c4f commit 2a3c79c

3 files changed

Lines changed: 85 additions & 1 deletion

File tree

drivers/resctrl/mpam_internal.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,14 @@ struct platform_device;
2929
#define PACKED_FOR_KUNIT
3030
#endif
3131

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+
3240
static inline bool mpam_is_enabled(void)
3341
{
3442
return static_branch_likely(&mpam_enabled);
@@ -216,7 +224,11 @@ enum mon_filter_options {
216224
};
217225

218226
struct mon_cfg {
219-
u16 mon;
227+
/*
228+
* mon must be large enough to hold out of range values like
229+
* USE_PRE_ALLOCATED
230+
*/
231+
u32 mon;
220232
u8 pmg;
221233
bool match_pmg;
222234
bool csu_exclude_clean;

drivers/resctrl/mpam_resctrl.c

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222

2323
#include "mpam_internal.h"
2424

25+
DECLARE_WAIT_QUEUE_HEAD(resctrl_mon_ctx_waiters);
26+
2527
/*
2628
* The classes we've picked to map to resctrl resources, wrapped
2729
* in with their resctrl structure.
@@ -289,6 +291,71 @@ struct rdt_resource *resctrl_arch_get_resource(enum resctrl_res_level l)
289291
return &mpam_resctrl_controls[l].resctrl_res;
290292
}
291293

294+
static int resctrl_arch_mon_ctx_alloc_no_wait(enum resctrl_event_id evtid)
295+
{
296+
struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[evtid];
297+
298+
if (!mon->class)
299+
return -EINVAL;
300+
301+
switch (evtid) {
302+
case QOS_L3_OCCUP_EVENT_ID:
303+
/* With CDP, one monitor gets used for both code/data reads */
304+
return mpam_alloc_csu_mon(mon->class);
305+
case QOS_L3_MBM_LOCAL_EVENT_ID:
306+
case QOS_L3_MBM_TOTAL_EVENT_ID:
307+
return USE_PRE_ALLOCATED;
308+
default:
309+
return -EOPNOTSUPP;
310+
}
311+
}
312+
313+
void *resctrl_arch_mon_ctx_alloc(struct rdt_resource *r,
314+
enum resctrl_event_id evtid)
315+
{
316+
DEFINE_WAIT(wait);
317+
int *ret;
318+
319+
ret = kmalloc_obj(*ret);
320+
if (!ret)
321+
return ERR_PTR(-ENOMEM);
322+
323+
do {
324+
prepare_to_wait(&resctrl_mon_ctx_waiters, &wait,
325+
TASK_INTERRUPTIBLE);
326+
*ret = resctrl_arch_mon_ctx_alloc_no_wait(evtid);
327+
if (*ret == -ENOSPC)
328+
schedule();
329+
} while (*ret == -ENOSPC && !signal_pending(current));
330+
finish_wait(&resctrl_mon_ctx_waiters, &wait);
331+
332+
return ret;
333+
}
334+
335+
static void resctrl_arch_mon_ctx_free_no_wait(enum resctrl_event_id evtid,
336+
u32 mon_idx)
337+
{
338+
struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[evtid];
339+
340+
if (!mon->class)
341+
return;
342+
343+
if (evtid == QOS_L3_OCCUP_EVENT_ID)
344+
mpam_free_csu_mon(mon->class, mon_idx);
345+
346+
wake_up(&resctrl_mon_ctx_waiters);
347+
}
348+
349+
void resctrl_arch_mon_ctx_free(struct rdt_resource *r,
350+
enum resctrl_event_id evtid, void *arch_mon_ctx)
351+
{
352+
u32 mon_idx = *(u32 *)arch_mon_ctx;
353+
354+
kfree(arch_mon_ctx);
355+
356+
resctrl_arch_mon_ctx_free_no_wait(evtid, mon_idx);
357+
}
358+
292359
static bool cache_has_usable_cpor(struct mpam_class *class)
293360
{
294361
struct mpam_props *cprops = &class->props;

include/linux/arm_mpam.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#define __LINUX_ARM_MPAM_H
66

77
#include <linux/acpi.h>
8+
#include <linux/resctrl_types.h>
89
#include <linux/types.h>
910

1011
struct mpam_msc;
@@ -62,6 +63,10 @@ u32 resctrl_arch_rmid_idx_encode(u32 closid, u32 rmid);
6263
void resctrl_arch_rmid_idx_decode(u32 idx, u32 *closid, u32 *rmid);
6364
u32 resctrl_arch_system_num_rmid_idx(void);
6465

66+
struct rdt_resource;
67+
void *resctrl_arch_mon_ctx_alloc(struct rdt_resource *r, enum resctrl_event_id evtid);
68+
void resctrl_arch_mon_ctx_free(struct rdt_resource *r, enum resctrl_event_id evtid, void *ctx);
69+
6570
/**
6671
* mpam_register_requestor() - Register a requestor with the MPAM driver
6772
* @partid_max: The maximum PARTID value the requestor can generate.

0 commit comments

Comments
 (0)