[PATCH 19/21] x86/intel_rdt/mbm: Basic counting of MBM events (total and local)

From: Vikas Shivappa
Date: Mon Jun 26 2017 - 14:55:26 EST


From: Tony Luck <tony.luck@xxxxxxxxx>

Check CPUID bits for whether each of the MBM events is supported.
Allocate space for each RMID for each counter in each domain to save
previous MSR counter value and running total of data.
Create files in each of the monitor directories.

Signed-off-by: Tony Luck <tony.luck@xxxxxxxxx>
Signed-off-by: Vikas Shivappa <vikas.shivappa@xxxxxxxxxxxxxxx>
---
arch/x86/kernel/cpu/intel_rdt.c | 33 ++++++++++++++++++++++++++++-
arch/x86/kernel/cpu/intel_rdt.h | 32 ++++++++++++++++++++++++++++
arch/x86/kernel/cpu/intel_rdt_ctrlmondata.c | 1 +
arch/x86/kernel/cpu/intel_rdt_monitor.c | 31 ++++++++++++++++++++++++++-
4 files changed, 95 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kernel/cpu/intel_rdt.c b/arch/x86/kernel/cpu/intel_rdt.c
index 8c7643d..a17f323 100644
--- a/arch/x86/kernel/cpu/intel_rdt.c
+++ b/arch/x86/kernel/cpu/intel_rdt.c
@@ -395,6 +395,27 @@ static int domain_setup_ctrlval(struct rdt_resource *r, struct rdt_domain *d)
return 0;
}

+static bool domain_setup_mbm_state(struct rdt_resource *r, struct rdt_domain *d)
+{
+ size_t tsize;
+
+ if (is_mbm_total_enabled()) {
+ tsize = sizeof(*d->mbm_total);
+ d->mbm_total = kcalloc(r->num_rmid, tsize, GFP_KERNEL);
+ if (!d->mbm_total)
+ return false;
+ }
+ if (is_mbm_local_enabled()) {
+ tsize = sizeof(*d->mbm_local);
+ d->mbm_local = kcalloc(r->num_rmid, tsize, GFP_KERNEL);
+ if (!d->mbm_local) {
+ kfree(d->mbm_total);
+ return false;
+ }
+ }
+ return true;
+}
+
/*
* domain_add_cpu - Add a cpu to a resource's domain list.
*
@@ -430,13 +451,17 @@ static void domain_add_cpu(int cpu, struct rdt_resource *r)
return;

d->id = id;
+ cpumask_set_cpu(cpu, &d->cpu_mask);

if (r->alloc_capable && domain_setup_ctrlval(r, d)) {
kfree(d);
return;
}

- cpumask_set_cpu(cpu, &d->cpu_mask);
+ if (r->mon_capable && !domain_setup_mbm_state(r, d)) {
+ kfree(d);
+ return;
+ }
list_add_tail(&d->list, add_pos);

/*
@@ -467,6 +492,8 @@ static void domain_remove_cpu(int cpu, struct rdt_resource *r)
if (static_branch_unlikely(&rdt_mon_enable_key))
rmdir_mondata_subdir_allrdtgrp(r, d->id);
kfree(d->ctrl_val);
+ kfree(d->mbm_total);
+ kfree(d->mbm_local);
list_del(&d->list);
kfree(d);
}
@@ -560,6 +587,10 @@ static __init bool get_rdt_resources(void)

if (boot_cpu_has(X86_FEATURE_CQM_OCCUP_LLC))
rdt_mon_features |= (1 << QOS_L3_OCCUP_EVENT_ID);
+ if (boot_cpu_has(X86_FEATURE_CQM_MBM_TOTAL))
+ rdt_mon_features |= (1 << QOS_L3_MBM_TOTAL_EVENT_ID);
+ if (boot_cpu_has(X86_FEATURE_CQM_MBM_LOCAL))
+ rdt_mon_features |= (1 << QOS_L3_MBM_LOCAL_EVENT_ID);

if (rdt_mon_features)
rdt_get_mon_l3_config(&rdt_resources_all[RDT_RESOURCE_L3]);
diff --git a/arch/x86/kernel/cpu/intel_rdt.h b/arch/x86/kernel/cpu/intel_rdt.h
index b771dae..ab010fb 100644
--- a/arch/x86/kernel/cpu/intel_rdt.h
+++ b/arch/x86/kernel/cpu/intel_rdt.h
@@ -20,6 +20,8 @@
#define QOS_L3_MBM_TOTAL_EVENT_ID 0x02
#define QOS_L3_MBM_LOCAL_EVENT_ID 0x03

+#define MBM_CNTR_WIDTH 24
+
#define RMID_VAL_ERROR (1ULL << 63)
#define RMID_VAL_UNAVAIL (1ULL << 62)

@@ -53,6 +55,7 @@ struct mon_evt {

struct rmid_read {
struct rdtgroup *rgrp;
+ struct rdt_domain *d;
int evtid;
u64 val;
};
@@ -159,10 +162,22 @@ struct rftype {
};

/**
+ * struct mbm_state - status for each MBM counter in each domain
+ * @chunks: Total data moved (multiply by rdt_group.mon_scale to get bytes)
+ * @prev_msr: Value of IA32_QM_CTR for this RMID last time we read it
+ */
+struct mbm_state {
+ u64 chunks;
+ u64 prev_msr;
+};
+
+/**
* struct rdt_domain - group of cpus sharing an RDT resource
* @list: all instances of this resource
* @id: unique id for this instance
* @cpu_mask: which cpus share this resource
+ * @mbm_total: saved state for MBM total bandwidth
+ * @mbm_local: saved state for MBM local bandwidth
* @ctrl_val: array of cache or mem ctrl values (indexed by CLOSID)
* @new_ctrl: new ctrl value to be loaded
* @have_new_ctrl: did user provide new_ctrl for this domain
@@ -171,6 +186,8 @@ struct rdt_domain {
struct list_head list;
int id;
struct cpumask cpu_mask;
+ struct mbm_state *mbm_total;
+ struct mbm_state *mbm_local;
u32 *ctrl_val;
u32 new_ctrl;
bool have_new_ctrl;
@@ -221,6 +238,21 @@ struct rdt_membw {
u32 *mb_map;
};

+static inline bool is_mbm_total_enabled(void)
+{
+ return (rdt_mon_features & (1 << QOS_L3_MBM_TOTAL_EVENT_ID));
+}
+
+static inline bool is_mbm_local_enabled(void)
+{
+ return (rdt_mon_features & (1 << QOS_L3_MBM_LOCAL_EVENT_ID));
+}
+
+static inline bool is_mbm_enabled(void)
+{
+ return (is_mbm_total_enabled() || is_mbm_local_enabled());
+}
+
/**
* struct rdt_resource - attributes of an RDT resource
* @alloc_enabled: Is allocation enabled on this machine
diff --git a/arch/x86/kernel/cpu/intel_rdt_ctrlmondata.c b/arch/x86/kernel/cpu/intel_rdt_ctrlmondata.c
index 0c8bca0..926d889 100644
--- a/arch/x86/kernel/cpu/intel_rdt_ctrlmondata.c
+++ b/arch/x86/kernel/cpu/intel_rdt_ctrlmondata.c
@@ -315,6 +315,7 @@ int rdtgroup_mondata_show(struct seq_file *m, void *arg)
*/
rr.rgrp = rdtgrp;
rr.evtid = evtid;
+ rr.d = d;
rr.val = 0;

smp_call_function_any(&d->cpu_mask, mon_event_count, &rr, 1);
diff --git a/arch/x86/kernel/cpu/intel_rdt_monitor.c b/arch/x86/kernel/cpu/intel_rdt_monitor.c
index a7247ca..2c5768c 100644
--- a/arch/x86/kernel/cpu/intel_rdt_monitor.c
+++ b/arch/x86/kernel/cpu/intel_rdt_monitor.c
@@ -209,7 +209,8 @@ void free_rmid(u32 rmid)

static bool __mon_event_count(u32 rmid, struct rmid_read *rr)
{
- u64 tval;
+ u64 chunks, shift, tval;
+ struct mbm_state *m;

tval = __rmid_read(rmid, rr->evtid);
if (tval & (RMID_VAL_ERROR | RMID_VAL_UNAVAIL)) {
@@ -220,9 +221,23 @@ static bool __mon_event_count(u32 rmid, struct rmid_read *rr)
case QOS_L3_OCCUP_EVENT_ID:
rr->val += tval;
return true;
+ case QOS_L3_MBM_TOTAL_EVENT_ID:
+ m = &rr->d->mbm_total[rmid];
+ break;
+ case QOS_L3_MBM_LOCAL_EVENT_ID:
+ m = &rr->d->mbm_local[rmid];
+ break;
default:
return false;
}
+ shift = 64 - MBM_CNTR_WIDTH;
+ chunks = (tval << shift) - (m->prev_msr << shift);
+ chunks >>= shift;
+ m->chunks += chunks;
+ m->prev_msr = tval;
+
+ rr->val += m->chunks;
+ return true;
}

void mon_event_count(void *info)
@@ -285,12 +300,26 @@ static int dom_data_init(struct rdt_resource *r)
.evtid = QOS_L3_OCCUP_EVENT_ID,
};

+static struct mon_evt mbm_total_event = {
+ .name = "mbm_total_bytes",
+ .evtid = QOS_L3_MBM_TOTAL_EVENT_ID,
+};
+
+static struct mon_evt mbm_local_event = {
+ .name = "mbm_local_bytes",
+ .evtid = QOS_L3_MBM_LOCAL_EVENT_ID,
+};
+
static void l3_mon_evt_init(struct rdt_resource *r)
{
INIT_LIST_HEAD(&r->evt_list);

if (rdt_mon_features & (1 << QOS_L3_OCCUP_EVENT_ID))
list_add_tail(&llc_occupancy_event.list, &r->evt_list);
+ if (is_mbm_total_enabled())
+ list_add_tail(&mbm_total_event.list, &r->evt_list);
+ if (is_mbm_local_enabled())
+ list_add_tail(&mbm_local_event.list, &r->evt_list);
}

void rdt_get_mon_l3_config(struct rdt_resource *r)
--
1.9.1