[PATCH 8/8] x86/intel_rdt/mba: Add schemata file support for MBA

From: Vikas Shivappa
Date: Fri Feb 17 2017 - 14:58:56 EST


Add support to update the MBA bandwidth values for the domains. The MBA
bandwidth values are specified for each domain by updating the schemata.
The schemata string is parsed and validated for the correct bandwidth
values for meeting the minimum b/w and b/w granularity requirements. OS
updates the corresponding domain PQOS_MSRs which are indexed from 0xD50
for MBA.

For linear scale the granularity is just the 100-max_delay. For
non-linear values, it is obtained by the mapping between the delay
values and percentage b/w values.

Signed-off-by: Vikas Shivappa <vikas.shivappa@xxxxxxxxxxxxxxx>
---
arch/x86/include/asm/intel_rdt.h | 3 +++
arch/x86/kernel/cpu/intel_rdt.c | 35 ++++++++++++++++++++++++++++++
arch/x86/kernel/cpu/intel_rdt_schemata.c | 37 ++++++++++++++++++++++++++++++++
3 files changed, 75 insertions(+)

diff --git a/arch/x86/include/asm/intel_rdt.h b/arch/x86/include/asm/intel_rdt.h
index 8748b0d..869fee1 100644
--- a/arch/x86/include/asm/intel_rdt.h
+++ b/arch/x86/include/asm/intel_rdt.h
@@ -13,6 +13,7 @@
#define IA32_L2_CBM_BASE 0xd10
#define IA32_MBA_THRTL_BASE 0xd50
#define MAX_MBA_THRTL 100u
+#define INVALID_DELAY 100u
#define MBA_IS_LINEAR 0x4

#define L3_QOS_CDP_ENABLE 0x01ULL
@@ -157,7 +158,9 @@ struct msr_param {
void rdt_get_cache_infofile(struct rdt_resource *r);
void rdt_get_mba_infofile(struct rdt_resource *r);
int parse_cbm(char *buf, struct rdt_resource *r);
+int parse_thrtl(char *buf, struct rdt_resource *r);
void cqm_wrmsr(void *a1, void *a2, struct rdt_resource *r);
+void mba_wrmsr(void *a1, void *a2, struct rdt_resource *r);

extern struct mutex rdtgroup_mutex;

diff --git a/arch/x86/kernel/cpu/intel_rdt.c b/arch/x86/kernel/cpu/intel_rdt.c
index 7ce4453..c0e56a7 100644
--- a/arch/x86/kernel/cpu/intel_rdt.c
+++ b/arch/x86/kernel/cpu/intel_rdt.c
@@ -92,6 +92,9 @@ struct rdt_resource rdt_resources_all[] = {
.name = "MB",
.domains = domain_init(RDT_RESOURCE_MBA),
.msr_base = IA32_MBA_THRTL_BASE,
+ .parse_ctrlval = parse_thrtl,
+ .msr_update = mba_wrmsr,
+ .format_str = "%d=%d",
.cache_level = 3,
.cbm_idx_multi = 1,
.cbm_idx_offset = 0
@@ -151,6 +154,19 @@ static inline bool cache_alloc_hsw_probe(void)
}

/*
+ * Map the memory b/w percentage value to delay values
+ * that can be written to QOS_MSRs.
+ * There are currently no SKUs which support non linear delay values.
+ */
+static u32 delay_bw_map(unsigned long bw, struct rdt_resource *r)
+{
+ if (r->delay_linear)
+ return MAX_MBA_THRTL - bw;
+
+ return INVALID_DELAY;
+}
+
+/*
* rdt_get_mb_table() - get a mapping of b/w percentage values
* exposed to user interface and the h/w understandable delay values.
*
@@ -270,6 +286,25 @@ static int get_cache_id(int cpu, int level)
return -1;
}

+void mba_wrmsr(void *a1, void *a2, struct rdt_resource *r)
+{
+ struct rdt_domain *d = (struct rdt_domain *)a2;
+ struct msr_param *m = (struct msr_param *)a1;
+ int i;
+
+ for (i = m->low; i < m->high; i++) {
+ int idx = cbm_idx(r, i);
+
+ /*
+ * Write the delay value for mba.
+ * delay_bw_map will return a correct value
+ * for this call as a nonexistant map throws error
+ * on init.
+ */
+ wrmsrl(r->msr_base + idx, delay_bw_map(d->ctrl_val[i], r));
+ }
+}
+
void cqm_wrmsr(void *a1, void *a2, struct rdt_resource *r)
{
struct rdt_domain *d = (struct rdt_domain *)a2;
diff --git a/arch/x86/kernel/cpu/intel_rdt_schemata.c b/arch/x86/kernel/cpu/intel_rdt_schemata.c
index 4141662..1c016c2 100644
--- a/arch/x86/kernel/cpu/intel_rdt_schemata.c
+++ b/arch/x86/kernel/cpu/intel_rdt_schemata.c
@@ -29,6 +29,43 @@
#include <asm/intel_rdt.h>

/*
+ * Check whether MBA bandwidth percentage value is correct.
+ * The value is checked against the minimum bandwidth
+ * values and the b/w granularity specified by the h/w.
+ */
+static int thrtl_validate(char *buf, unsigned long *data, struct rdt_resource *r)
+{
+ unsigned long bw;
+ int ret;
+
+ ret = kstrtoul(buf, 10, &bw);
+ if (ret)
+ return ret;
+
+ if (bw < r->min_bw || bw > MAX_MBA_THRTL || (bw % r->bw_gran))
+ return -EINVAL;
+ *data = bw;
+
+ return 0;
+}
+
+/*
+ * Read the user RDT control value into tempory buffer:
+ * Cache bit mask (hex) or Memory b/w throttle (decimal).
+ * Check that it is valid for the current resource type.
+ */
+int parse_thrtl(char *buf, struct rdt_resource *r)
+{
+ unsigned long data;
+ int ret;
+
+ ret = thrtl_validate(buf, &data, r);
+ r->tmp_ctrl[r->num_tmp_ctrl++] = data;
+
+ return ret;
+}
+
+/*
* Check whether a cache bit mask is valid. The SDM says:
* Please note that all (and only) contiguous '1' combinations
* are allowed (e.g. FFFFH, 0FF0H, 003CH, etc.).
--
1.9.1