[PATCH V4 29/38] x86/intel_rdt: Pseudo-lock region creation/removal core

2018-05-22 Thread Reinette Chatre
The user requests a pseudo-locked region by providing a schemata to a
resource group that is in the pseudo-locksetup mode. This is the
functionality that consumes the parsed user data and creates the
pseudo-locked region.

First, required information is deduced from user provided data.
This includes, how much memory does the requested bitmask represent,
which CPU the requested region is associated with, and what is the
cache line size of that cache (to learn the stride needed for locking).
Second, a contiguous block of memory matching the requested bitmask is
allocated.

Finally, pseudo-locking is performed. The resource group already has the
allocation that reflects the requested bitmask. With this class of service
active and interference minimized, the allocated memory is loaded into the
cache.

Signed-off-by: Reinette Chatre 
---
 arch/x86/kernel/cpu/intel_rdt.h |  17 ++
 arch/x86/kernel/cpu/intel_rdt_pseudo_lock.c | 334 
 2 files changed, 351 insertions(+)

diff --git a/arch/x86/kernel/cpu/intel_rdt.h b/arch/x86/kernel/cpu/intel_rdt.h
index 119645c83e27..886cd28b305f 100644
--- a/arch/x86/kernel/cpu/intel_rdt.h
+++ b/arch/x86/kernel/cpu/intel_rdt.h
@@ -129,11 +129,26 @@ struct mongroup {
  * @d: RDT domain to which this pseudo-locked region
  * belongs
  * @cbm:   bitmask of the pseudo-locked region
+ * @lock_thread_wq:waitqueue used to wait on the pseudo-locking thread
+ * completion
+ * @thread_done:   variable used by waitqueue to test if pseudo-locking
+ * thread completed
+ * @cpu:   core associated with the cache on which the setup code
+ * will be run
+ * @line_size: size of the cache lines
+ * @size:  size of pseudo-locked region in bytes
+ * @kmem:  the kernel memory associated with pseudo-locked region
  */
 struct pseudo_lock_region {
struct rdt_resource *r;
struct rdt_domain   *d;
u32 cbm;
+   wait_queue_head_t   lock_thread_wq;
+   int thread_done;
+   int cpu;
+   unsigned intline_size;
+   unsigned intsize;
+   void*kmem;
 };
 
 /**
@@ -505,6 +520,8 @@ int rdtgroup_locksetup_enter(struct rdtgroup *rdtgrp);
 int rdtgroup_locksetup_exit(struct rdtgroup *rdtgrp);
 bool rdtgroup_cbm_overlaps_pseudo_locked(struct rdt_domain *d, u32 _cbm);
 bool rdtgroup_pseudo_locked_in_hierarchy(struct rdt_domain *d);
+int rdtgroup_pseudo_lock_create(struct rdtgroup *rdtgrp);
+void rdtgroup_pseudo_lock_remove(struct rdtgroup *rdtgrp);
 struct rdt_domain *get_domain_from_cpu(int cpu, struct rdt_resource *r);
 int update_domains(struct rdt_resource *r, int closid);
 void closid_free(int closid);
diff --git a/arch/x86/kernel/cpu/intel_rdt_pseudo_lock.c 
b/arch/x86/kernel/cpu/intel_rdt_pseudo_lock.c
index 310c67b12a63..bced04dd90b6 100644
--- a/arch/x86/kernel/cpu/intel_rdt_pseudo_lock.c
+++ b/arch/x86/kernel/cpu/intel_rdt_pseudo_lock.c
@@ -11,8 +11,14 @@
 
 #define pr_fmt(fmt)KBUILD_MODNAME ": " fmt
 
+#include 
+#include 
+#include 
+#include 
 #include 
+#include 
 #include 
+#include 
 #include "intel_rdt.h"
 
 /*
@@ -80,6 +86,51 @@ static u64 get_prefetch_disable_bits(void)
 }
 
 /**
+ * pseudo_lock_region_init - Initialize pseudo-lock region information
+ * @plr: pseudo-lock region
+ *
+ * Called after user provided a schemata to be pseudo-locked. From the
+ * schemata the  pseudo_lock_region is on entry already initialized
+ * with the resource, domain, and capacity bitmask. Here the information
+ * required for pseudo-locking is deduced from this data and 
+ * pseudo_lock_region initialized further. This information includes:
+ * - size in bytes of the region to be pseudo-locked
+ * - cache line size to know the stride with which data needs to be accessed
+ *   to be pseudo-locked
+ * - a cpu associated with the cache instance on which the pseudo-locking
+ *   flow can be executed
+ *
+ * Return: 0 on success, <0 on failure. Descriptive error will be written
+ * to last_cmd_status buffer.
+ */
+static int pseudo_lock_region_init(struct pseudo_lock_region *plr)
+{
+   struct cpu_cacheinfo *ci = get_cpu_cacheinfo(plr->cpu);
+   int i;
+
+   /* Pick the first cpu we find that is associated with the cache. */
+   plr->cpu = cpumask_first(>d->cpu_mask);
+
+   if (!cpu_online(plr->cpu)) {
+   rdt_last_cmd_printf("cpu %u associated with cache not online\n",
+   plr->cpu);
+   return -ENODEV;
+   }
+
+   plr->size = rdtgroup_cbm_to_size(plr->r, plr->d, plr->cbm);
+
+   for (i = 0; i < ci->num_leaves; i++) {
+   if (ci->info_list[i].level == plr->r->cache_level) {
+   plr->line_size = 

[PATCH V4 29/38] x86/intel_rdt: Pseudo-lock region creation/removal core

2018-05-22 Thread Reinette Chatre
The user requests a pseudo-locked region by providing a schemata to a
resource group that is in the pseudo-locksetup mode. This is the
functionality that consumes the parsed user data and creates the
pseudo-locked region.

First, required information is deduced from user provided data.
This includes, how much memory does the requested bitmask represent,
which CPU the requested region is associated with, and what is the
cache line size of that cache (to learn the stride needed for locking).
Second, a contiguous block of memory matching the requested bitmask is
allocated.

Finally, pseudo-locking is performed. The resource group already has the
allocation that reflects the requested bitmask. With this class of service
active and interference minimized, the allocated memory is loaded into the
cache.

Signed-off-by: Reinette Chatre 
---
 arch/x86/kernel/cpu/intel_rdt.h |  17 ++
 arch/x86/kernel/cpu/intel_rdt_pseudo_lock.c | 334 
 2 files changed, 351 insertions(+)

diff --git a/arch/x86/kernel/cpu/intel_rdt.h b/arch/x86/kernel/cpu/intel_rdt.h
index 119645c83e27..886cd28b305f 100644
--- a/arch/x86/kernel/cpu/intel_rdt.h
+++ b/arch/x86/kernel/cpu/intel_rdt.h
@@ -129,11 +129,26 @@ struct mongroup {
  * @d: RDT domain to which this pseudo-locked region
  * belongs
  * @cbm:   bitmask of the pseudo-locked region
+ * @lock_thread_wq:waitqueue used to wait on the pseudo-locking thread
+ * completion
+ * @thread_done:   variable used by waitqueue to test if pseudo-locking
+ * thread completed
+ * @cpu:   core associated with the cache on which the setup code
+ * will be run
+ * @line_size: size of the cache lines
+ * @size:  size of pseudo-locked region in bytes
+ * @kmem:  the kernel memory associated with pseudo-locked region
  */
 struct pseudo_lock_region {
struct rdt_resource *r;
struct rdt_domain   *d;
u32 cbm;
+   wait_queue_head_t   lock_thread_wq;
+   int thread_done;
+   int cpu;
+   unsigned intline_size;
+   unsigned intsize;
+   void*kmem;
 };
 
 /**
@@ -505,6 +520,8 @@ int rdtgroup_locksetup_enter(struct rdtgroup *rdtgrp);
 int rdtgroup_locksetup_exit(struct rdtgroup *rdtgrp);
 bool rdtgroup_cbm_overlaps_pseudo_locked(struct rdt_domain *d, u32 _cbm);
 bool rdtgroup_pseudo_locked_in_hierarchy(struct rdt_domain *d);
+int rdtgroup_pseudo_lock_create(struct rdtgroup *rdtgrp);
+void rdtgroup_pseudo_lock_remove(struct rdtgroup *rdtgrp);
 struct rdt_domain *get_domain_from_cpu(int cpu, struct rdt_resource *r);
 int update_domains(struct rdt_resource *r, int closid);
 void closid_free(int closid);
diff --git a/arch/x86/kernel/cpu/intel_rdt_pseudo_lock.c 
b/arch/x86/kernel/cpu/intel_rdt_pseudo_lock.c
index 310c67b12a63..bced04dd90b6 100644
--- a/arch/x86/kernel/cpu/intel_rdt_pseudo_lock.c
+++ b/arch/x86/kernel/cpu/intel_rdt_pseudo_lock.c
@@ -11,8 +11,14 @@
 
 #define pr_fmt(fmt)KBUILD_MODNAME ": " fmt
 
+#include 
+#include 
+#include 
+#include 
 #include 
+#include 
 #include 
+#include 
 #include "intel_rdt.h"
 
 /*
@@ -80,6 +86,51 @@ static u64 get_prefetch_disable_bits(void)
 }
 
 /**
+ * pseudo_lock_region_init - Initialize pseudo-lock region information
+ * @plr: pseudo-lock region
+ *
+ * Called after user provided a schemata to be pseudo-locked. From the
+ * schemata the  pseudo_lock_region is on entry already initialized
+ * with the resource, domain, and capacity bitmask. Here the information
+ * required for pseudo-locking is deduced from this data and 
+ * pseudo_lock_region initialized further. This information includes:
+ * - size in bytes of the region to be pseudo-locked
+ * - cache line size to know the stride with which data needs to be accessed
+ *   to be pseudo-locked
+ * - a cpu associated with the cache instance on which the pseudo-locking
+ *   flow can be executed
+ *
+ * Return: 0 on success, <0 on failure. Descriptive error will be written
+ * to last_cmd_status buffer.
+ */
+static int pseudo_lock_region_init(struct pseudo_lock_region *plr)
+{
+   struct cpu_cacheinfo *ci = get_cpu_cacheinfo(plr->cpu);
+   int i;
+
+   /* Pick the first cpu we find that is associated with the cache. */
+   plr->cpu = cpumask_first(>d->cpu_mask);
+
+   if (!cpu_online(plr->cpu)) {
+   rdt_last_cmd_printf("cpu %u associated with cache not online\n",
+   plr->cpu);
+   return -ENODEV;
+   }
+
+   plr->size = rdtgroup_cbm_to_size(plr->r, plr->d, plr->cbm);
+
+   for (i = 0; i < ci->num_leaves; i++) {
+   if (ci->info_list[i].level == plr->r->cache_level) {
+   plr->line_size = ci->info_list[i].coherency_line_size;
+