]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
Merge branch 'x86/cpufeature' into x86/cache
authorThomas Gleixner <tglx@linutronix.de>
Wed, 16 Nov 2016 13:19:34 +0000 (14:19 +0100)
committerThomas Gleixner <tglx@linutronix.de>
Wed, 16 Nov 2016 13:19:34 +0000 (14:19 +0100)
Resolve the cpu/scattered conflict.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
20 files changed:
Documentation/ABI/testing/sysfs-devices-system-cpu
Documentation/x86/intel_rdt_ui.txt [new file with mode: 0644]
MAINTAINERS
arch/x86/Kconfig
arch/x86/events/intel/cqm.c
arch/x86/include/asm/cpufeatures.h
arch/x86/include/asm/intel_rdt.h [new file with mode: 0644]
arch/x86/include/asm/intel_rdt_common.h [new file with mode: 0644]
arch/x86/kernel/cpu/Makefile
arch/x86/kernel/cpu/intel_cacheinfo.c
arch/x86/kernel/cpu/intel_rdt.c [new file with mode: 0644]
arch/x86/kernel/cpu/intel_rdt_rdtgroup.c [new file with mode: 0644]
arch/x86/kernel/cpu/intel_rdt_schemata.c [new file with mode: 0644]
arch/x86/kernel/cpu/scattered.c
arch/x86/kernel/process_32.c
arch/x86/kernel/process_64.c
drivers/base/cacheinfo.c
include/linux/cacheinfo.h
include/linux/sched.h
include/uapi/linux/magic.h

index 49874173705507f72fac2f5f55da46fc34c3cc52..2a4a423d08e0d3ed8bce7cc0c9bcd36bb30bb19d 100644 (file)
@@ -272,6 +272,22 @@ Description:       Parameters for the CPU cache attributes
                                     the modified cache line is written to main
                                     memory only when it is replaced
 
+
+What:          /sys/devices/system/cpu/cpu*/cache/index*/id
+Date:          September 2016
+Contact:       Linux kernel mailing list <linux-kernel@vger.kernel.org>
+Description:   Cache id
+
+               The id provides a unique number for a specific instance of
+               a cache of a particular type. E.g. there may be a level
+               3 unified cache on each socket in a server and we may
+               assign them ids 0, 1, 2, ...
+
+               Note that id value can be non-contiguous. E.g. level 1
+               caches typically exist per core, but there may not be a
+               power of two cores on a socket, so these caches may be
+               numbered 0, 1, 2, 3, 4, 5, 8, 9, 10, ...
+
 What:          /sys/devices/system/cpu/cpuX/cpufreq/throttle_stats
                /sys/devices/system/cpu/cpuX/cpufreq/throttle_stats/turbo_stat
                /sys/devices/system/cpu/cpuX/cpufreq/throttle_stats/sub_turbo_stat
diff --git a/Documentation/x86/intel_rdt_ui.txt b/Documentation/x86/intel_rdt_ui.txt
new file mode 100644 (file)
index 0000000..d918d26
--- /dev/null
@@ -0,0 +1,214 @@
+User Interface for Resource Allocation in Intel Resource Director Technology
+
+Copyright (C) 2016 Intel Corporation
+
+Fenghua Yu <fenghua.yu@intel.com>
+Tony Luck <tony.luck@intel.com>
+
+This feature is enabled by the CONFIG_INTEL_RDT_A Kconfig and the
+X86 /proc/cpuinfo flag bits "rdt", "cat_l3" and "cdp_l3".
+
+To use the feature mount the file system:
+
+ # mount -t resctrl resctrl [-o cdp] /sys/fs/resctrl
+
+mount options are:
+
+"cdp": Enable code/data prioritization in L3 cache allocations.
+
+
+Info directory
+--------------
+
+The 'info' directory contains information about the enabled
+resources. Each resource has its own subdirectory. The subdirectory
+names reflect the resource names. Each subdirectory contains the
+following files:
+
+"num_closids":  The number of CLOSIDs which are valid for this
+               resource. The kernel uses the smallest number of
+               CLOSIDs of all enabled resources as limit.
+
+"cbm_mask":     The bitmask which is valid for this resource. This
+               mask is equivalent to 100%.
+
+"min_cbm_bits": The minimum number of consecutive bits which must be
+               set when writing a mask.
+
+
+Resource groups
+---------------
+Resource groups are represented as directories in the resctrl file
+system. The default group is the root directory. Other groups may be
+created as desired by the system administrator using the "mkdir(1)"
+command, and removed using "rmdir(1)".
+
+There are three files associated with each group:
+
+"tasks": A list of tasks that belongs to this group. Tasks can be
+       added to a group by writing the task ID to the "tasks" file
+       (which will automatically remove them from the previous
+       group to which they belonged). New tasks created by fork(2)
+       and clone(2) are added to the same group as their parent.
+       If a pid is not in any sub partition, it is in root partition
+       (i.e. default partition).
+
+"cpus": A bitmask of logical CPUs assigned to this group. Writing
+       a new mask can add/remove CPUs from this group. Added CPUs
+       are removed from their previous group. Removed ones are
+       given to the default (root) group. You cannot remove CPUs
+       from the default group.
+
+"schemata": A list of all the resources available to this group.
+       Each resource has its own line and format - see below for
+       details.
+
+When a task is running the following rules define which resources
+are available to it:
+
+1) If the task is a member of a non-default group, then the schemata
+for that group is used.
+
+2) Else if the task belongs to the default group, but is running on a
+CPU that is assigned to some specific group, then the schemata for
+the CPU's group is used.
+
+3) Otherwise the schemata for the default group is used.
+
+
+Schemata files - general concepts
+---------------------------------
+Each line in the file describes one resource. The line starts with
+the name of the resource, followed by specific values to be applied
+in each of the instances of that resource on the system.
+
+Cache IDs
+---------
+On current generation systems there is one L3 cache per socket and L2
+caches are generally just shared by the hyperthreads on a core, but this
+isn't an architectural requirement. We could have multiple separate L3
+caches on a socket, multiple cores could share an L2 cache. So instead
+of using "socket" or "core" to define the set of logical cpus sharing
+a resource we use a "Cache ID". At a given cache level this will be a
+unique number across the whole system (but it isn't guaranteed to be a
+contiguous sequence, there may be gaps).  To find the ID for each logical
+CPU look in /sys/devices/system/cpu/cpu*/cache/index*/id
+
+Cache Bit Masks (CBM)
+---------------------
+For cache resources we describe the portion of the cache that is available
+for allocation using a bitmask. The maximum value of the mask is defined
+by each cpu model (and may be different for different cache levels). It
+is found using CPUID, but is also provided in the "info" directory of
+the resctrl file system in "info/{resource}/cbm_mask". X86 hardware
+requires that these masks have all the '1' bits in a contiguous block. So
+0x3, 0x6 and 0xC are legal 4-bit masks with two bits set, but 0x5, 0x9
+and 0xA are not.  On a system with a 20-bit mask each bit represents 5%
+of the capacity of the cache. You could partition the cache into four
+equal parts with masks: 0x1f, 0x3e0, 0x7c00, 0xf8000.
+
+
+L3 details (code and data prioritization disabled)
+--------------------------------------------------
+With CDP disabled the L3 schemata format is:
+
+       L3:<cache_id0>=<cbm>;<cache_id1>=<cbm>;...
+
+L3 details (CDP enabled via mount option to resctrl)
+----------------------------------------------------
+When CDP is enabled L3 control is split into two separate resources
+so you can specify independent masks for code and data like this:
+
+       L3data:<cache_id0>=<cbm>;<cache_id1>=<cbm>;...
+       L3code:<cache_id0>=<cbm>;<cache_id1>=<cbm>;...
+
+L2 details
+----------
+L2 cache does not support code and data prioritization, so the
+schemata format is always:
+
+       L2:<cache_id0>=<cbm>;<cache_id1>=<cbm>;...
+
+Example 1
+---------
+On a two socket machine (one L3 cache per socket) with just four bits
+for cache bit masks
+
+# mount -t resctrl resctrl /sys/fs/resctrl
+# cd /sys/fs/resctrl
+# mkdir p0 p1
+# echo "L3:0=3;1=c" > /sys/fs/resctrl/p0/schemata
+# echo "L3:0=3;1=3" > /sys/fs/resctrl/p1/schemata
+
+The default resource group is unmodified, so we have access to all parts
+of all caches (its schemata file reads "L3:0=f;1=f").
+
+Tasks that are under the control of group "p0" may only allocate from the
+"lower" 50% on cache ID 0, and the "upper" 50% of cache ID 1.
+Tasks in group "p1" use the "lower" 50% of cache on both sockets.
+
+Example 2
+---------
+Again two sockets, but this time with a more realistic 20-bit mask.
+
+Two real time tasks pid=1234 running on processor 0 and pid=5678 running on
+processor 1 on socket 0 on a 2-socket and dual core machine. To avoid noisy
+neighbors, each of the two real-time tasks exclusively occupies one quarter
+of L3 cache on socket 0.
+
+# mount -t resctrl resctrl /sys/fs/resctrl
+# cd /sys/fs/resctrl
+
+First we reset the schemata for the default group so that the "upper"
+50% of the L3 cache on socket 0 cannot be used by ordinary tasks:
+
+# echo "L3:0=3ff;1=fffff" > schemata
+
+Next we make a resource group for our first real time task and give
+it access to the "top" 25% of the cache on socket 0.
+
+# mkdir p0
+# echo "L3:0=f8000;1=fffff" > p0/schemata
+
+Finally we move our first real time task into this resource group. We
+also use taskset(1) to ensure the task always runs on a dedicated CPU
+on socket 0. Most uses of resource groups will also constrain which
+processors tasks run on.
+
+# echo 1234 > p0/tasks
+# taskset -cp 1 1234
+
+Ditto for the second real time task (with the remaining 25% of cache):
+
+# mkdir p1
+# echo "L3:0=7c00;1=fffff" > p1/schemata
+# echo 5678 > p1/tasks
+# taskset -cp 2 5678
+
+Example 3
+---------
+
+A single socket system which has real-time tasks running on core 4-7 and
+non real-time workload assigned to core 0-3. The real-time tasks share text
+and data, so a per task association is not required and due to interaction
+with the kernel it's desired that the kernel on these cores shares L3 with
+the tasks.
+
+# mount -t resctrl resctrl /sys/fs/resctrl
+# cd /sys/fs/resctrl
+
+First we reset the schemata for the default group so that the "upper"
+50% of the L3 cache on socket 0 cannot be used by ordinary tasks:
+
+# echo "L3:0=3ff" > schemata
+
+Next we make a resource group for our real time cores and give
+it access to the "top" 50% of the cache on socket 0.
+
+# mkdir p0
+# echo "L3:0=ffc00;" > p0/schemata
+
+Finally we move core 4-7 over to the new group and make sure that the
+kernel and the tasks running there get 50% of the cache.
+
+# echo C0 > p0/cpus
index 851b89b9edcb5e99e84270e67510e10a19418b21..c6a3d8c86f6f1ae2475f5298c90cb17b1a9bbedb 100644 (file)
@@ -10122,6 +10122,14 @@ L:     linux-rdma@vger.kernel.org
 S:     Supported
 F:     drivers/infiniband/sw/rdmavt
 
+RDT - RESOURCE ALLOCATION
+M:     Fenghua Yu <fenghua.yu@intel.com>
+L:     linux-kernel@vger.kernel.org
+S:     Supported
+F:     arch/x86/kernel/cpu/intel_rdt*
+F:     arch/x86/include/asm/intel_rdt*
+F:     Documentation/x86/intel_rdt*
+
 READ-COPY UPDATE (RCU)
 M:     "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
 M:     Josh Triplett <josh@joshtriplett.org>
index bada636d1065c5451d3e42f54820757e4cf30455..dcca4ec427703a5a886333b5bd4d490c74487b25 100644 (file)
@@ -407,6 +407,19 @@ config GOLDFISH
        def_bool y
        depends on X86_GOLDFISH
 
+config INTEL_RDT_A
+       bool "Intel Resource Director Technology Allocation support"
+       default n
+       depends on X86 && CPU_SUP_INTEL
+       select KERNFS
+       help
+         Select to enable resource allocation which is a sub-feature of
+         Intel Resource Director Technology(RDT). More information about
+         RDT can be found in the Intel x86 Architecture Software
+         Developer Manual.
+
+         Say N if unsure.
+
 if X86_32
 config X86_EXTENDED_PLATFORM
        bool "Support for extended (non-PC) x86 platforms"
index 8f82b02934fa701a451ee5e7d8f76193eaefc2fa..0c45cc8e64ba77f6988cff5a0e5443dfe0449435 100644 (file)
@@ -7,9 +7,9 @@
 #include <linux/perf_event.h>
 #include <linux/slab.h>
 #include <asm/cpu_device_id.h>
+#include <asm/intel_rdt_common.h>
 #include "../perf_event.h"
 
-#define MSR_IA32_PQR_ASSOC     0x0c8f
 #define MSR_IA32_QM_CTR                0x0c8e
 #define MSR_IA32_QM_EVTSEL     0x0c8d
 
@@ -24,32 +24,13 @@ static unsigned int cqm_l3_scale; /* supposedly cacheline size */
 static bool cqm_enabled, mbm_enabled;
 unsigned int mbm_socket_max;
 
-/**
- * struct intel_pqr_state - State cache for the PQR MSR
- * @rmid:              The cached Resource Monitoring ID
- * @closid:            The cached Class Of Service ID
- * @rmid_usecnt:       The usage counter for rmid
- *
- * The upper 32 bits of MSR_IA32_PQR_ASSOC contain closid and the
- * lower 10 bits rmid. The update to MSR_IA32_PQR_ASSOC always
- * contains both parts, so we need to cache them.
- *
- * The cache also helps to avoid pointless updates if the value does
- * not change.
- */
-struct intel_pqr_state {
-       u32                     rmid;
-       u32                     closid;
-       int                     rmid_usecnt;
-};
-
 /*
  * The cached intel_pqr_state is strictly per CPU and can never be
  * updated from a remote CPU. Both functions which modify the state
  * (intel_cqm_event_start and intel_cqm_event_stop) are called with
  * interrupts disabled, which is sufficient for the protection.
  */
-static DEFINE_PER_CPU(struct intel_pqr_state, pqr_state);
+DEFINE_PER_CPU(struct intel_pqr_state, pqr_state);
 static struct hrtimer *mbm_timers;
 /**
  * struct sample - mbm event's (local or total) data
index a39629206864e5bb74aaddea15ca1ab762877042..90b8c0b185c30f13ba3b6015b13f50c92a4e0df7 100644 (file)
 
 #define X86_FEATURE_CPB                ( 7*32+ 2) /* AMD Core Performance Boost */
 #define X86_FEATURE_EPB                ( 7*32+ 3) /* IA32_ENERGY_PERF_BIAS support */
+#define X86_FEATURE_CAT_L3     ( 7*32+ 4) /* Cache Allocation Technology L3 */
+#define X86_FEATURE_CAT_L2     ( 7*32+ 5) /* Cache Allocation Technology L2 */
+#define X86_FEATURE_CDP_L3     ( 7*32+ 6) /* Code and Data Prioritization L3 */
 
 #define X86_FEATURE_HW_PSTATE  ( 7*32+ 8) /* AMD HW-PState */
 #define X86_FEATURE_PROC_FEEDBACK ( 7*32+ 9) /* AMD ProcFeedbackInterface */
 #define X86_FEATURE_RTM                ( 9*32+11) /* Restricted Transactional Memory */
 #define X86_FEATURE_CQM                ( 9*32+12) /* Cache QoS Monitoring */
 #define X86_FEATURE_MPX                ( 9*32+14) /* Memory Protection Extension */
+#define X86_FEATURE_RDT_A      ( 9*32+15) /* Resource Director Technology Allocation */
 #define X86_FEATURE_AVX512F    ( 9*32+16) /* AVX-512 Foundation */
 #define X86_FEATURE_AVX512DQ   ( 9*32+17) /* AVX-512 DQ (Double/Quad granular) Instructions */
 #define X86_FEATURE_RDSEED     ( 9*32+18) /* The RDSEED instruction */
diff --git a/arch/x86/include/asm/intel_rdt.h b/arch/x86/include/asm/intel_rdt.h
new file mode 100644 (file)
index 0000000..6e90e87
--- /dev/null
@@ -0,0 +1,222 @@
+#ifndef _ASM_X86_INTEL_RDT_H
+#define _ASM_X86_INTEL_RDT_H
+
+#ifdef CONFIG_INTEL_RDT_A
+
+#include <linux/kernfs.h>
+#include <linux/jump_label.h>
+
+#include <asm/intel_rdt_common.h>
+
+#define IA32_L3_QOS_CFG                0xc81
+#define IA32_L3_CBM_BASE       0xc90
+#define IA32_L2_CBM_BASE       0xd10
+
+#define L3_QOS_CDP_ENABLE      0x01ULL
+
+/**
+ * struct rdtgroup - store rdtgroup's data in resctrl file system.
+ * @kn:                                kernfs node
+ * @rdtgroup_list:             linked list for all rdtgroups
+ * @closid:                    closid for this rdtgroup
+ * @cpu_mask:                  CPUs assigned to this rdtgroup
+ * @flags:                     status bits
+ * @waitcount:                 how many cpus expect to find this
+ *                             group when they acquire rdtgroup_mutex
+ */
+struct rdtgroup {
+       struct kernfs_node      *kn;
+       struct list_head        rdtgroup_list;
+       int                     closid;
+       struct cpumask          cpu_mask;
+       int                     flags;
+       atomic_t                waitcount;
+};
+
+/* rdtgroup.flags */
+#define        RDT_DELETED             1
+
+/* List of all resource groups */
+extern struct list_head rdt_all_groups;
+
+int __init rdtgroup_init(void);
+
+/**
+ * struct rftype - describe each file in the resctrl file system
+ * @name: file name
+ * @mode: access mode
+ * @kf_ops: operations
+ * @seq_show: show content of the file
+ * @write: write to the file
+ */
+struct rftype {
+       char                    *name;
+       umode_t                 mode;
+       struct kernfs_ops       *kf_ops;
+
+       int (*seq_show)(struct kernfs_open_file *of,
+                       struct seq_file *sf, void *v);
+       /*
+        * write() is the generic write callback which maps directly to
+        * kernfs write operation and overrides all other operations.
+        * Maximum write size is determined by ->max_write_len.
+        */
+       ssize_t (*write)(struct kernfs_open_file *of,
+                        char *buf, size_t nbytes, loff_t off);
+};
+
+/**
+ * struct rdt_resource - attributes of an RDT resource
+ * @enabled:                   Is this feature enabled on this machine
+ * @capable:                   Is this feature available on this machine
+ * @name:                      Name to use in "schemata" file
+ * @num_closid:                        Number of CLOSIDs available
+ * @max_cbm:                   Largest Cache Bit Mask allowed
+ * @min_cbm_bits:              Minimum number of consecutive bits to be set
+ *                             in a cache bit mask
+ * @domains:                   All domains for this resource
+ * @num_domains:               Number of domains active
+ * @msr_base:                  Base MSR address for CBMs
+ * @tmp_cbms:                  Scratch space when updating schemata
+ * @num_tmp_cbms:              Number of CBMs in tmp_cbms
+ * @cache_level:               Which cache level defines scope of this domain
+ * @cbm_idx_multi:             Multiplier of CBM index
+ * @cbm_idx_offset:            Offset of CBM index. CBM index is computed by:
+ *                             closid * cbm_idx_multi + cbm_idx_offset
+ */
+struct rdt_resource {
+       bool                    enabled;
+       bool                    capable;
+       char                    *name;
+       int                     num_closid;
+       int                     cbm_len;
+       int                     min_cbm_bits;
+       u32                     max_cbm;
+       struct list_head        domains;
+       int                     num_domains;
+       int                     msr_base;
+       u32                     *tmp_cbms;
+       int                     num_tmp_cbms;
+       int                     cache_level;
+       int                     cbm_idx_multi;
+       int                     cbm_idx_offset;
+};
+
+/**
+ * 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
+ * @cbm:       array of cache bit masks (indexed by CLOSID)
+ */
+struct rdt_domain {
+       struct list_head        list;
+       int                     id;
+       struct cpumask          cpu_mask;
+       u32                     *cbm;
+};
+
+/**
+ * struct msr_param - set a range of MSRs from a domain
+ * @res:       The resource to use
+ * @low:       Beginning index from base MSR
+ * @high:      End index
+ */
+struct msr_param {
+       struct rdt_resource     *res;
+       int                     low;
+       int                     high;
+};
+
+extern struct mutex rdtgroup_mutex;
+
+extern struct rdt_resource rdt_resources_all[];
+extern struct rdtgroup rdtgroup_default;
+DECLARE_STATIC_KEY_FALSE(rdt_enable_key);
+
+int __init rdtgroup_init(void);
+
+enum {
+       RDT_RESOURCE_L3,
+       RDT_RESOURCE_L3DATA,
+       RDT_RESOURCE_L3CODE,
+       RDT_RESOURCE_L2,
+
+       /* Must be the last */
+       RDT_NUM_RESOURCES,
+};
+
+#define for_each_capable_rdt_resource(r)                                     \
+       for (r = rdt_resources_all; r < rdt_resources_all + RDT_NUM_RESOURCES;\
+            r++)                                                             \
+               if (r->capable)
+
+#define for_each_enabled_rdt_resource(r)                                     \
+       for (r = rdt_resources_all; r < rdt_resources_all + RDT_NUM_RESOURCES;\
+            r++)                                                             \
+               if (r->enabled)
+
+/* CPUID.(EAX=10H, ECX=ResID=1).EAX */
+union cpuid_0x10_1_eax {
+       struct {
+               unsigned int cbm_len:5;
+       } split;
+       unsigned int full;
+};
+
+/* CPUID.(EAX=10H, ECX=ResID=1).EDX */
+union cpuid_0x10_1_edx {
+       struct {
+               unsigned int cos_max:16;
+       } split;
+       unsigned int full;
+};
+
+DECLARE_PER_CPU_READ_MOSTLY(int, cpu_closid);
+
+void rdt_cbm_update(void *arg);
+struct rdtgroup *rdtgroup_kn_lock_live(struct kernfs_node *kn);
+void rdtgroup_kn_unlock(struct kernfs_node *kn);
+ssize_t rdtgroup_schemata_write(struct kernfs_open_file *of,
+                               char *buf, size_t nbytes, loff_t off);
+int rdtgroup_schemata_show(struct kernfs_open_file *of,
+                          struct seq_file *s, void *v);
+
+/*
+ * intel_rdt_sched_in() - Writes the task's CLOSid to IA32_PQR_MSR
+ *
+ * Following considerations are made so that this has minimal impact
+ * on scheduler hot path:
+ * - This will stay as no-op unless we are running on an Intel SKU
+ *   which supports resource control and we enable by mounting the
+ *   resctrl file system.
+ * - Caches the per cpu CLOSid values and does the MSR write only
+ *   when a task with a different CLOSid is scheduled in.
+ */
+static inline void intel_rdt_sched_in(void)
+{
+       if (static_branch_likely(&rdt_enable_key)) {
+               struct intel_pqr_state *state = this_cpu_ptr(&pqr_state);
+               int closid;
+
+               /*
+                * If this task has a closid assigned, use it.
+                * Else use the closid assigned to this cpu.
+                */
+               closid = current->closid;
+               if (closid == 0)
+                       closid = this_cpu_read(cpu_closid);
+
+               if (closid != state->closid) {
+                       state->closid = closid;
+                       wrmsr(MSR_IA32_PQR_ASSOC, state->rmid, closid);
+               }
+       }
+}
+
+#else
+
+static inline void intel_rdt_sched_in(void) {}
+
+#endif /* CONFIG_INTEL_RDT_A */
+#endif /* _ASM_X86_INTEL_RDT_H */
diff --git a/arch/x86/include/asm/intel_rdt_common.h b/arch/x86/include/asm/intel_rdt_common.h
new file mode 100644 (file)
index 0000000..b31081b
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef _ASM_X86_INTEL_RDT_COMMON_H
+#define _ASM_X86_INTEL_RDT_COMMON_H
+
+#define MSR_IA32_PQR_ASSOC     0x0c8f
+
+/**
+ * struct intel_pqr_state - State cache for the PQR MSR
+ * @rmid:              The cached Resource Monitoring ID
+ * @closid:            The cached Class Of Service ID
+ * @rmid_usecnt:       The usage counter for rmid
+ *
+ * The upper 32 bits of MSR_IA32_PQR_ASSOC contain closid and the
+ * lower 10 bits rmid. The update to MSR_IA32_PQR_ASSOC always
+ * contains both parts, so we need to cache them.
+ *
+ * The cache also helps to avoid pointless updates if the value does
+ * not change.
+ */
+struct intel_pqr_state {
+       u32                     rmid;
+       u32                     closid;
+       int                     rmid_usecnt;
+};
+
+DECLARE_PER_CPU(struct intel_pqr_state, pqr_state);
+
+#endif /* _ASM_X86_INTEL_RDT_COMMON_H */
index 4a8697f7d4ef804921c7422fac02f28c4b8b0c2b..c9f8c818d104ef7a5cb00be95a0eba565b81d997 100644 (file)
@@ -34,6 +34,8 @@ obj-$(CONFIG_CPU_SUP_CENTAUR)         += centaur.o
 obj-$(CONFIG_CPU_SUP_TRANSMETA_32)     += transmeta.o
 obj-$(CONFIG_CPU_SUP_UMC_32)           += umc.o
 
+obj-$(CONFIG_INTEL_RDT_A)      += intel_rdt.o intel_rdt_rdtgroup.o intel_rdt_schemata.o
+
 obj-$(CONFIG_X86_MCE)                  += mcheck/
 obj-$(CONFIG_MTRR)                     += mtrr/
 obj-$(CONFIG_MICROCODE)                        += microcode/
index de6626c18e427b771ea902451ae77ab52e233915..8dc572085fb47609befdbc0f81cc6d263b456a47 100644 (file)
@@ -153,6 +153,7 @@ struct _cpuid4_info_regs {
        union _cpuid4_leaf_eax eax;
        union _cpuid4_leaf_ebx ebx;
        union _cpuid4_leaf_ecx ecx;
+       unsigned int id;
        unsigned long size;
        struct amd_northbridge *nb;
 };
@@ -894,6 +895,8 @@ static void __cache_cpumap_setup(unsigned int cpu, int index,
 static void ci_leaf_init(struct cacheinfo *this_leaf,
                         struct _cpuid4_info_regs *base)
 {
+       this_leaf->id = base->id;
+       this_leaf->attributes = CACHE_ID;
        this_leaf->level = base->eax.split.level;
        this_leaf->type = cache_type_map[base->eax.split.type];
        this_leaf->coherency_line_size =
@@ -920,6 +923,22 @@ static int __init_cache_level(unsigned int cpu)
        return 0;
 }
 
+/*
+ * The max shared threads number comes from CPUID.4:EAX[25-14] with input
+ * ECX as cache index. Then right shift apicid by the number's order to get
+ * cache id for this cache node.
+ */
+static void get_cache_id(int cpu, struct _cpuid4_info_regs *id4_regs)
+{
+       struct cpuinfo_x86 *c = &cpu_data(cpu);
+       unsigned long num_threads_sharing;
+       int index_msb;
+
+       num_threads_sharing = 1 + id4_regs->eax.split.num_threads_sharing;
+       index_msb = get_count_order(num_threads_sharing);
+       id4_regs->id = c->apicid >> index_msb;
+}
+
 static int __populate_cache_leaves(unsigned int cpu)
 {
        unsigned int idx, ret;
@@ -931,6 +950,7 @@ static int __populate_cache_leaves(unsigned int cpu)
                ret = cpuid4_cache_lookup_regs(idx, &id4_regs);
                if (ret)
                        return ret;
+               get_cache_id(cpu, &id4_regs);
                ci_leaf_init(this_leaf++, &id4_regs);
                __cache_cpumap_setup(cpu, idx, &id4_regs);
        }
diff --git a/arch/x86/kernel/cpu/intel_rdt.c b/arch/x86/kernel/cpu/intel_rdt.c
new file mode 100644 (file)
index 0000000..5a533fe
--- /dev/null
@@ -0,0 +1,403 @@
+/*
+ * Resource Director Technology(RDT)
+ * - Cache Allocation code.
+ *
+ * Copyright (C) 2016 Intel Corporation
+ *
+ * Authors:
+ *    Fenghua Yu <fenghua.yu@intel.com>
+ *    Tony Luck <tony.luck@intel.com>
+ *    Vikas Shivappa <vikas.shivappa@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * More information about RDT be found in the Intel (R) x86 Architecture
+ * Software Developer Manual June 2016, volume 3, section 17.17.
+ */
+
+#define pr_fmt(fmt)    KBUILD_MODNAME ": " fmt
+
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/cacheinfo.h>
+#include <linux/cpuhotplug.h>
+
+#include <asm/intel-family.h>
+#include <asm/intel_rdt.h>
+
+/* Mutex to protect rdtgroup access. */
+DEFINE_MUTEX(rdtgroup_mutex);
+
+DEFINE_PER_CPU_READ_MOSTLY(int, cpu_closid);
+
+#define domain_init(id) LIST_HEAD_INIT(rdt_resources_all[id].domains)
+
+struct rdt_resource rdt_resources_all[] = {
+       {
+               .name           = "L3",
+               .domains        = domain_init(RDT_RESOURCE_L3),
+               .msr_base       = IA32_L3_CBM_BASE,
+               .min_cbm_bits   = 1,
+               .cache_level    = 3,
+               .cbm_idx_multi  = 1,
+               .cbm_idx_offset = 0
+       },
+       {
+               .name           = "L3DATA",
+               .domains        = domain_init(RDT_RESOURCE_L3DATA),
+               .msr_base       = IA32_L3_CBM_BASE,
+               .min_cbm_bits   = 1,
+               .cache_level    = 3,
+               .cbm_idx_multi  = 2,
+               .cbm_idx_offset = 0
+       },
+       {
+               .name           = "L3CODE",
+               .domains        = domain_init(RDT_RESOURCE_L3CODE),
+               .msr_base       = IA32_L3_CBM_BASE,
+               .min_cbm_bits   = 1,
+               .cache_level    = 3,
+               .cbm_idx_multi  = 2,
+               .cbm_idx_offset = 1
+       },
+       {
+               .name           = "L2",
+               .domains        = domain_init(RDT_RESOURCE_L2),
+               .msr_base       = IA32_L2_CBM_BASE,
+               .min_cbm_bits   = 1,
+               .cache_level    = 2,
+               .cbm_idx_multi  = 1,
+               .cbm_idx_offset = 0
+       },
+};
+
+static int cbm_idx(struct rdt_resource *r, int closid)
+{
+       return closid * r->cbm_idx_multi + r->cbm_idx_offset;
+}
+
+/*
+ * cache_alloc_hsw_probe() - Have to probe for Intel haswell server CPUs
+ * as they do not have CPUID enumeration support for Cache allocation.
+ * The check for Vendor/Family/Model is not enough to guarantee that
+ * the MSRs won't #GP fault because only the following SKUs support
+ * CAT:
+ *     Intel(R) Xeon(R)  CPU E5-2658  v3  @  2.20GHz
+ *     Intel(R) Xeon(R)  CPU E5-2648L v3  @  1.80GHz
+ *     Intel(R) Xeon(R)  CPU E5-2628L v3  @  2.00GHz
+ *     Intel(R) Xeon(R)  CPU E5-2618L v3  @  2.30GHz
+ *     Intel(R) Xeon(R)  CPU E5-2608L v3  @  2.00GHz
+ *     Intel(R) Xeon(R)  CPU E5-2658A v3  @  2.20GHz
+ *
+ * Probe by trying to write the first of the L3 cach mask registers
+ * and checking that the bits stick. Max CLOSids is always 4 and max cbm length
+ * is always 20 on hsw server parts. The minimum cache bitmask length
+ * allowed for HSW server is always 2 bits. Hardcode all of them.
+ */
+static inline bool cache_alloc_hsw_probe(void)
+{
+       if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
+           boot_cpu_data.x86 == 6 &&
+           boot_cpu_data.x86_model == INTEL_FAM6_HASWELL_X) {
+               struct rdt_resource *r  = &rdt_resources_all[RDT_RESOURCE_L3];
+               u32 l, h, max_cbm = BIT_MASK(20) - 1;
+
+               if (wrmsr_safe(IA32_L3_CBM_BASE, max_cbm, 0))
+                       return false;
+               rdmsr(IA32_L3_CBM_BASE, l, h);
+
+               /* If all the bits were set in MSR, return success */
+               if (l != max_cbm)
+                       return false;
+
+               r->num_closid = 4;
+               r->cbm_len = 20;
+               r->max_cbm = max_cbm;
+               r->min_cbm_bits = 2;
+               r->capable = true;
+               r->enabled = true;
+
+               return true;
+       }
+
+       return false;
+}
+
+static void rdt_get_config(int idx, struct rdt_resource *r)
+{
+       union cpuid_0x10_1_eax eax;
+       union cpuid_0x10_1_edx edx;
+       u32 ebx, ecx;
+
+       cpuid_count(0x00000010, idx, &eax.full, &ebx, &ecx, &edx.full);
+       r->num_closid = edx.split.cos_max + 1;
+       r->cbm_len = eax.split.cbm_len + 1;
+       r->max_cbm = BIT_MASK(eax.split.cbm_len + 1) - 1;
+       r->capable = true;
+       r->enabled = true;
+}
+
+static void rdt_get_cdp_l3_config(int type)
+{
+       struct rdt_resource *r_l3 = &rdt_resources_all[RDT_RESOURCE_L3];
+       struct rdt_resource *r = &rdt_resources_all[type];
+
+       r->num_closid = r_l3->num_closid / 2;
+       r->cbm_len = r_l3->cbm_len;
+       r->max_cbm = r_l3->max_cbm;
+       r->capable = true;
+       /*
+        * By default, CDP is disabled. CDP can be enabled by mount parameter
+        * "cdp" during resctrl file system mount time.
+        */
+       r->enabled = false;
+}
+
+static inline bool get_rdt_resources(void)
+{
+       bool ret = false;
+
+       if (cache_alloc_hsw_probe())
+               return true;
+
+       if (!boot_cpu_has(X86_FEATURE_RDT_A))
+               return false;
+
+       if (boot_cpu_has(X86_FEATURE_CAT_L3)) {
+               rdt_get_config(1, &rdt_resources_all[RDT_RESOURCE_L3]);
+               if (boot_cpu_has(X86_FEATURE_CDP_L3)) {
+                       rdt_get_cdp_l3_config(RDT_RESOURCE_L3DATA);
+                       rdt_get_cdp_l3_config(RDT_RESOURCE_L3CODE);
+               }
+               ret = true;
+       }
+       if (boot_cpu_has(X86_FEATURE_CAT_L2)) {
+               /* CPUID 0x10.2 fields are same format at 0x10.1 */
+               rdt_get_config(2, &rdt_resources_all[RDT_RESOURCE_L2]);
+               ret = true;
+       }
+
+       return ret;
+}
+
+static int get_cache_id(int cpu, int level)
+{
+       struct cpu_cacheinfo *ci = get_cpu_cacheinfo(cpu);
+       int i;
+
+       for (i = 0; i < ci->num_leaves; i++) {
+               if (ci->info_list[i].level == level)
+                       return ci->info_list[i].id;
+       }
+
+       return -1;
+}
+
+void rdt_cbm_update(void *arg)
+{
+       struct msr_param *m = (struct msr_param *)arg;
+       struct rdt_resource *r = m->res;
+       int i, cpu = smp_processor_id();
+       struct rdt_domain *d;
+
+       list_for_each_entry(d, &r->domains, list) {
+               /* Find the domain that contains this CPU */
+               if (cpumask_test_cpu(cpu, &d->cpu_mask))
+                       goto found;
+       }
+       pr_info_once("cpu %d not found in any domain for resource %s\n",
+                    cpu, r->name);
+
+       return;
+
+found:
+       for (i = m->low; i < m->high; i++) {
+               int idx = cbm_idx(r, i);
+
+               wrmsrl(r->msr_base + idx, d->cbm[i]);
+       }
+}
+
+/*
+ * rdt_find_domain - Find a domain in a resource that matches input resource id
+ *
+ * Search resource r's domain list to find the resource id. If the resource
+ * id is found in a domain, return the domain. Otherwise, if requested by
+ * caller, return the first domain whose id is bigger than the input id.
+ * The domain list is sorted by id in ascending order.
+ */
+static struct rdt_domain *rdt_find_domain(struct rdt_resource *r, int id,
+                                         struct list_head **pos)
+{
+       struct rdt_domain *d;
+       struct list_head *l;
+
+       if (id < 0)
+               return ERR_PTR(id);
+
+       list_for_each(l, &r->domains) {
+               d = list_entry(l, struct rdt_domain, list);
+               /* When id is found, return its domain. */
+               if (id == d->id)
+                       return d;
+               /* Stop searching when finding id's position in sorted list. */
+               if (id < d->id)
+                       break;
+       }
+
+       if (pos)
+               *pos = l;
+
+       return NULL;
+}
+
+/*
+ * domain_add_cpu - Add a cpu to a resource's domain list.
+ *
+ * If an existing domain in the resource r's domain list matches the cpu's
+ * resource id, add the cpu in the domain.
+ *
+ * Otherwise, a new domain is allocated and inserted into the right position
+ * in the domain list sorted by id in ascending order.
+ *
+ * The order in the domain list is visible to users when we print entries
+ * in the schemata file and schemata input is validated to have the same order
+ * as this list.
+ */
+static void domain_add_cpu(int cpu, struct rdt_resource *r)
+{
+       int i, id = get_cache_id(cpu, r->cache_level);
+       struct list_head *add_pos = NULL;
+       struct rdt_domain *d;
+
+       d = rdt_find_domain(r, id, &add_pos);
+       if (IS_ERR(d)) {
+               pr_warn("Could't find cache id for cpu %d\n", cpu);
+               return;
+       }
+
+       if (d) {
+               cpumask_set_cpu(cpu, &d->cpu_mask);
+               return;
+       }
+
+       d = kzalloc_node(sizeof(*d), GFP_KERNEL, cpu_to_node(cpu));
+       if (!d)
+               return;
+
+       d->id = id;
+
+       d->cbm = kmalloc_array(r->num_closid, sizeof(*d->cbm), GFP_KERNEL);
+       if (!d->cbm) {
+               kfree(d);
+               return;
+       }
+
+       for (i = 0; i < r->num_closid; i++) {
+               int idx = cbm_idx(r, i);
+
+               d->cbm[i] = r->max_cbm;
+               wrmsrl(r->msr_base + idx, d->cbm[i]);
+       }
+
+       cpumask_set_cpu(cpu, &d->cpu_mask);
+       list_add_tail(&d->list, add_pos);
+       r->num_domains++;
+}
+
+static void domain_remove_cpu(int cpu, struct rdt_resource *r)
+{
+       int id = get_cache_id(cpu, r->cache_level);
+       struct rdt_domain *d;
+
+       d = rdt_find_domain(r, id, NULL);
+       if (IS_ERR_OR_NULL(d)) {
+               pr_warn("Could't find cache id for cpu %d\n", cpu);
+               return;
+       }
+
+       cpumask_clear_cpu(cpu, &d->cpu_mask);
+       if (cpumask_empty(&d->cpu_mask)) {
+               r->num_domains--;
+               kfree(d->cbm);
+               list_del(&d->list);
+               kfree(d);
+       }
+}
+
+static void clear_closid(int cpu)
+{
+       struct intel_pqr_state *state = this_cpu_ptr(&pqr_state);
+
+       per_cpu(cpu_closid, cpu) = 0;
+       state->closid = 0;
+       wrmsr(MSR_IA32_PQR_ASSOC, state->rmid, 0);
+}
+
+static int intel_rdt_online_cpu(unsigned int cpu)
+{
+       struct rdt_resource *r;
+
+       mutex_lock(&rdtgroup_mutex);
+       for_each_capable_rdt_resource(r)
+               domain_add_cpu(cpu, r);
+       /* The cpu is set in default rdtgroup after online. */
+       cpumask_set_cpu(cpu, &rdtgroup_default.cpu_mask);
+       clear_closid(cpu);
+       mutex_unlock(&rdtgroup_mutex);
+
+       return 0;
+}
+
+static int intel_rdt_offline_cpu(unsigned int cpu)
+{
+       struct rdtgroup *rdtgrp;
+       struct rdt_resource *r;
+
+       mutex_lock(&rdtgroup_mutex);
+       for_each_capable_rdt_resource(r)
+               domain_remove_cpu(cpu, r);
+       list_for_each_entry(rdtgrp, &rdt_all_groups, rdtgroup_list) {
+               if (cpumask_test_and_clear_cpu(cpu, &rdtgrp->cpu_mask))
+                       break;
+       }
+       clear_closid(cpu);
+       mutex_unlock(&rdtgroup_mutex);
+
+       return 0;
+}
+
+static int __init intel_rdt_late_init(void)
+{
+       struct rdt_resource *r;
+       int state, ret;
+
+       if (!get_rdt_resources())
+               return -ENODEV;
+
+       state = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
+                                 "x86/rdt/cat:online:",
+                                 intel_rdt_online_cpu, intel_rdt_offline_cpu);
+       if (state < 0)
+               return state;
+
+       ret = rdtgroup_init();
+       if (ret) {
+               cpuhp_remove_state(state);
+               return ret;
+       }
+
+       for_each_capable_rdt_resource(r)
+               pr_info("Intel RDT %s allocation detected\n", r->name);
+
+       return 0;
+}
+
+late_initcall(intel_rdt_late_init);
diff --git a/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c b/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c
new file mode 100644 (file)
index 0000000..98edba4
--- /dev/null
@@ -0,0 +1,1052 @@
+/*
+ * User interface for Resource Alloction in Resource Director Technology(RDT)
+ *
+ * Copyright (C) 2016 Intel Corporation
+ *
+ * Author: Fenghua Yu <fenghua.yu@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * More information about RDT be found in the Intel (R) x86 Architecture
+ * Software Developer Manual.
+ */
+
+#define pr_fmt(fmt)    KBUILD_MODNAME ": " fmt
+
+#include <linux/cpu.h>
+#include <linux/fs.h>
+#include <linux/sysfs.h>
+#include <linux/kernfs.h>
+#include <linux/seq_file.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/cpu.h>
+#include <linux/task_work.h>
+
+#include <uapi/linux/magic.h>
+
+#include <asm/intel_rdt.h>
+#include <asm/intel_rdt_common.h>
+
+DEFINE_STATIC_KEY_FALSE(rdt_enable_key);
+struct kernfs_root *rdt_root;
+struct rdtgroup rdtgroup_default;
+LIST_HEAD(rdt_all_groups);
+
+/* Kernel fs node for "info" directory under root */
+static struct kernfs_node *kn_info;
+
+/*
+ * Trivial allocator for CLOSIDs. Since h/w only supports a small number,
+ * we can keep a bitmap of free CLOSIDs in a single integer.
+ *
+ * Using a global CLOSID across all resources has some advantages and
+ * some drawbacks:
+ * + We can simply set "current->closid" to assign a task to a resource
+ *   group.
+ * + Context switch code can avoid extra memory references deciding which
+ *   CLOSID to load into the PQR_ASSOC MSR
+ * - We give up some options in configuring resource groups across multi-socket
+ *   systems.
+ * - Our choices on how to configure each resource become progressively more
+ *   limited as the number of resources grows.
+ */
+static int closid_free_map;
+
+static void closid_init(void)
+{
+       struct rdt_resource *r;
+       int rdt_min_closid = 32;
+
+       /* Compute rdt_min_closid across all resources */
+       for_each_enabled_rdt_resource(r)
+               rdt_min_closid = min(rdt_min_closid, r->num_closid);
+
+       closid_free_map = BIT_MASK(rdt_min_closid) - 1;
+
+       /* CLOSID 0 is always reserved for the default group */
+       closid_free_map &= ~1;
+}
+
+int closid_alloc(void)
+{
+       int closid = ffs(closid_free_map);
+
+       if (closid == 0)
+               return -ENOSPC;
+       closid--;
+       closid_free_map &= ~(1 << closid);
+
+       return closid;
+}
+
+static void closid_free(int closid)
+{
+       closid_free_map |= 1 << closid;
+}
+
+/* set uid and gid of rdtgroup dirs and files to that of the creator */
+static int rdtgroup_kn_set_ugid(struct kernfs_node *kn)
+{
+       struct iattr iattr = { .ia_valid = ATTR_UID | ATTR_GID,
+                               .ia_uid = current_fsuid(),
+                               .ia_gid = current_fsgid(), };
+
+       if (uid_eq(iattr.ia_uid, GLOBAL_ROOT_UID) &&
+           gid_eq(iattr.ia_gid, GLOBAL_ROOT_GID))
+               return 0;
+
+       return kernfs_setattr(kn, &iattr);
+}
+
+static int rdtgroup_add_file(struct kernfs_node *parent_kn, struct rftype *rft)
+{
+       struct kernfs_node *kn;
+       int ret;
+
+       kn = __kernfs_create_file(parent_kn, rft->name, rft->mode,
+                                 0, rft->kf_ops, rft, NULL, NULL);
+       if (IS_ERR(kn))
+               return PTR_ERR(kn);
+
+       ret = rdtgroup_kn_set_ugid(kn);
+       if (ret) {
+               kernfs_remove(kn);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int rdtgroup_add_files(struct kernfs_node *kn, struct rftype *rfts,
+                             int len)
+{
+       struct rftype *rft;
+       int ret;
+
+       lockdep_assert_held(&rdtgroup_mutex);
+
+       for (rft = rfts; rft < rfts + len; rft++) {
+               ret = rdtgroup_add_file(kn, rft);
+               if (ret)
+                       goto error;
+       }
+
+       return 0;
+error:
+       pr_warn("Failed to add %s, err=%d\n", rft->name, ret);
+       while (--rft >= rfts)
+               kernfs_remove_by_name(kn, rft->name);
+       return ret;
+}
+
+static int rdtgroup_seqfile_show(struct seq_file *m, void *arg)
+{
+       struct kernfs_open_file *of = m->private;
+       struct rftype *rft = of->kn->priv;
+
+       if (rft->seq_show)
+               return rft->seq_show(of, m, arg);
+       return 0;
+}
+
+static ssize_t rdtgroup_file_write(struct kernfs_open_file *of, char *buf,
+                                  size_t nbytes, loff_t off)
+{
+       struct rftype *rft = of->kn->priv;
+
+       if (rft->write)
+               return rft->write(of, buf, nbytes, off);
+
+       return -EINVAL;
+}
+
+static struct kernfs_ops rdtgroup_kf_single_ops = {
+       .atomic_write_len       = PAGE_SIZE,
+       .write                  = rdtgroup_file_write,
+       .seq_show               = rdtgroup_seqfile_show,
+};
+
+static int rdtgroup_cpus_show(struct kernfs_open_file *of,
+                             struct seq_file *s, void *v)
+{
+       struct rdtgroup *rdtgrp;
+       int ret = 0;
+
+       rdtgrp = rdtgroup_kn_lock_live(of->kn);
+
+       if (rdtgrp)
+               seq_printf(s, "%*pb\n", cpumask_pr_args(&rdtgrp->cpu_mask));
+       else
+               ret = -ENOENT;
+       rdtgroup_kn_unlock(of->kn);
+
+       return ret;
+}
+
+/*
+ * This is safe against intel_rdt_sched_in() called from __switch_to()
+ * because __switch_to() is executed with interrupts disabled. A local call
+ * from rdt_update_percpu_closid() is proteced against __switch_to() because
+ * preemption is disabled.
+ */
+static void rdt_update_cpu_closid(void *v)
+{
+       this_cpu_write(cpu_closid, *(int *)v);
+       /*
+        * We cannot unconditionally write the MSR because the current
+        * executing task might have its own closid selected. Just reuse
+        * the context switch code.
+        */
+       intel_rdt_sched_in();
+}
+
+/* Update the per cpu closid and eventually the PGR_ASSOC MSR */
+static void rdt_update_percpu_closid(const struct cpumask *cpu_mask, int closid)
+{
+       int cpu = get_cpu();
+
+       if (cpumask_test_cpu(cpu, cpu_mask))
+               rdt_update_cpu_closid(&closid);
+       smp_call_function_many(cpu_mask, rdt_update_cpu_closid, &closid, 1);
+       put_cpu();
+}
+
+static ssize_t rdtgroup_cpus_write(struct kernfs_open_file *of,
+                                  char *buf, size_t nbytes, loff_t off)
+{
+       cpumask_var_t tmpmask, newmask;
+       struct rdtgroup *rdtgrp, *r;
+       int ret;
+
+       if (!buf)
+               return -EINVAL;
+
+       if (!zalloc_cpumask_var(&tmpmask, GFP_KERNEL))
+               return -ENOMEM;
+       if (!zalloc_cpumask_var(&newmask, GFP_KERNEL)) {
+               free_cpumask_var(tmpmask);
+               return -ENOMEM;
+       }
+
+       rdtgrp = rdtgroup_kn_lock_live(of->kn);
+       if (!rdtgrp) {
+               ret = -ENOENT;
+               goto unlock;
+       }
+
+       ret = cpumask_parse(buf, newmask);
+       if (ret)
+               goto unlock;
+
+       /* check that user didn't specify any offline cpus */
+       cpumask_andnot(tmpmask, newmask, cpu_online_mask);
+       if (cpumask_weight(tmpmask)) {
+               ret = -EINVAL;
+               goto unlock;
+       }
+
+       /* Check whether cpus are dropped from this group */
+       cpumask_andnot(tmpmask, &rdtgrp->cpu_mask, newmask);
+       if (cpumask_weight(tmpmask)) {
+               /* Can't drop from default group */
+               if (rdtgrp == &rdtgroup_default) {
+                       ret = -EINVAL;
+                       goto unlock;
+               }
+               /* Give any dropped cpus to rdtgroup_default */
+               cpumask_or(&rdtgroup_default.cpu_mask,
+                          &rdtgroup_default.cpu_mask, tmpmask);
+               rdt_update_percpu_closid(tmpmask, rdtgroup_default.closid);
+       }
+
+       /*
+        * If we added cpus, remove them from previous group that owned them
+        * and update per-cpu closid
+        */
+       cpumask_andnot(tmpmask, newmask, &rdtgrp->cpu_mask);
+       if (cpumask_weight(tmpmask)) {
+               list_for_each_entry(r, &rdt_all_groups, rdtgroup_list) {
+                       if (r == rdtgrp)
+                               continue;
+                       cpumask_andnot(&r->cpu_mask, &r->cpu_mask, tmpmask);
+               }
+               rdt_update_percpu_closid(tmpmask, rdtgroup_default.closid);
+       }
+
+       /* Done pushing/pulling - update this group with new mask */
+       cpumask_copy(&rdtgrp->cpu_mask, newmask);
+
+unlock:
+       rdtgroup_kn_unlock(of->kn);
+       free_cpumask_var(tmpmask);
+       free_cpumask_var(newmask);
+
+       return ret ?: nbytes;
+}
+
+struct task_move_callback {
+       struct callback_head    work;
+       struct rdtgroup         *rdtgrp;
+};
+
+static void move_myself(struct callback_head *head)
+{
+       struct task_move_callback *callback;
+       struct rdtgroup *rdtgrp;
+
+       callback = container_of(head, struct task_move_callback, work);
+       rdtgrp = callback->rdtgrp;
+
+       /*
+        * If resource group was deleted before this task work callback
+        * was invoked, then assign the task to root group and free the
+        * resource group.
+        */
+       if (atomic_dec_and_test(&rdtgrp->waitcount) &&
+           (rdtgrp->flags & RDT_DELETED)) {
+               current->closid = 0;
+               kfree(rdtgrp);
+       }
+
+       /* update PQR_ASSOC MSR to make resource group go into effect */
+       intel_rdt_sched_in();
+
+       kfree(callback);
+}
+
+static int __rdtgroup_move_task(struct task_struct *tsk,
+                               struct rdtgroup *rdtgrp)
+{
+       struct task_move_callback *callback;
+       int ret;
+
+       callback = kzalloc(sizeof(*callback), GFP_KERNEL);
+       if (!callback)
+               return -ENOMEM;
+       callback->work.func = move_myself;
+       callback->rdtgrp = rdtgrp;
+
+       /*
+        * Take a refcount, so rdtgrp cannot be freed before the
+        * callback has been invoked.
+        */
+       atomic_inc(&rdtgrp->waitcount);
+       ret = task_work_add(tsk, &callback->work, true);
+       if (ret) {
+               /*
+                * Task is exiting. Drop the refcount and free the callback.
+                * No need to check the refcount as the group cannot be
+                * deleted before the write function unlocks rdtgroup_mutex.
+                */
+               atomic_dec(&rdtgrp->waitcount);
+               kfree(callback);
+       } else {
+               tsk->closid = rdtgrp->closid;
+       }
+       return ret;
+}
+
+static int rdtgroup_task_write_permission(struct task_struct *task,
+                                         struct kernfs_open_file *of)
+{
+       const struct cred *tcred = get_task_cred(task);
+       const struct cred *cred = current_cred();
+       int ret = 0;
+
+       /*
+        * Even if we're attaching all tasks in the thread group, we only
+        * need to check permissions on one of them.
+        */
+       if (!uid_eq(cred->euid, GLOBAL_ROOT_UID) &&
+           !uid_eq(cred->euid, tcred->uid) &&
+           !uid_eq(cred->euid, tcred->suid))
+               ret = -EPERM;
+
+       put_cred(tcred);
+       return ret;
+}
+
+static int rdtgroup_move_task(pid_t pid, struct rdtgroup *rdtgrp,
+                             struct kernfs_open_file *of)
+{
+       struct task_struct *tsk;
+       int ret;
+
+       rcu_read_lock();
+       if (pid) {
+               tsk = find_task_by_vpid(pid);
+               if (!tsk) {
+                       rcu_read_unlock();
+                       return -ESRCH;
+               }
+       } else {
+               tsk = current;
+       }
+
+       get_task_struct(tsk);
+       rcu_read_unlock();
+
+       ret = rdtgroup_task_write_permission(tsk, of);
+       if (!ret)
+               ret = __rdtgroup_move_task(tsk, rdtgrp);
+
+       put_task_struct(tsk);
+       return ret;
+}
+
+static ssize_t rdtgroup_tasks_write(struct kernfs_open_file *of,
+                                   char *buf, size_t nbytes, loff_t off)
+{
+       struct rdtgroup *rdtgrp;
+       int ret = 0;
+       pid_t pid;
+
+       if (kstrtoint(strstrip(buf), 0, &pid) || pid < 0)
+               return -EINVAL;
+       rdtgrp = rdtgroup_kn_lock_live(of->kn);
+
+       if (rdtgrp)
+               ret = rdtgroup_move_task(pid, rdtgrp, of);
+       else
+               ret = -ENOENT;
+
+       rdtgroup_kn_unlock(of->kn);
+
+       return ret ?: nbytes;
+}
+
+static void show_rdt_tasks(struct rdtgroup *r, struct seq_file *s)
+{
+       struct task_struct *p, *t;
+
+       rcu_read_lock();
+       for_each_process_thread(p, t) {
+               if (t->closid == r->closid)
+                       seq_printf(s, "%d\n", t->pid);
+       }
+       rcu_read_unlock();
+}
+
+static int rdtgroup_tasks_show(struct kernfs_open_file *of,
+                              struct seq_file *s, void *v)
+{
+       struct rdtgroup *rdtgrp;
+       int ret = 0;
+
+       rdtgrp = rdtgroup_kn_lock_live(of->kn);
+       if (rdtgrp)
+               show_rdt_tasks(rdtgrp, s);
+       else
+               ret = -ENOENT;
+       rdtgroup_kn_unlock(of->kn);
+
+       return ret;
+}
+
+/* Files in each rdtgroup */
+static struct rftype rdtgroup_base_files[] = {
+       {
+               .name           = "cpus",
+               .mode           = 0644,
+               .kf_ops         = &rdtgroup_kf_single_ops,
+               .write          = rdtgroup_cpus_write,
+               .seq_show       = rdtgroup_cpus_show,
+       },
+       {
+               .name           = "tasks",
+               .mode           = 0644,
+               .kf_ops         = &rdtgroup_kf_single_ops,
+               .write          = rdtgroup_tasks_write,
+               .seq_show       = rdtgroup_tasks_show,
+       },
+       {
+               .name           = "schemata",
+               .mode           = 0644,
+               .kf_ops         = &rdtgroup_kf_single_ops,
+               .write          = rdtgroup_schemata_write,
+               .seq_show       = rdtgroup_schemata_show,
+       },
+};
+
+static int rdt_num_closids_show(struct kernfs_open_file *of,
+                               struct seq_file *seq, void *v)
+{
+       struct rdt_resource *r = of->kn->parent->priv;
+
+       seq_printf(seq, "%d\n", r->num_closid);
+
+       return 0;
+}
+
+static int rdt_cbm_mask_show(struct kernfs_open_file *of,
+                            struct seq_file *seq, void *v)
+{
+       struct rdt_resource *r = of->kn->parent->priv;
+
+       seq_printf(seq, "%x\n", r->max_cbm);
+
+       return 0;
+}
+
+static int rdt_min_cbm_bits_show(struct kernfs_open_file *of,
+                            struct seq_file *seq, void *v)
+{
+       struct rdt_resource *r = of->kn->parent->priv;
+
+       seq_printf(seq, "%d\n", r->min_cbm_bits);
+
+       return 0;
+}
+
+/* rdtgroup information files for one cache resource. */
+static struct rftype res_info_files[] = {
+       {
+               .name           = "num_closids",
+               .mode           = 0444,
+               .kf_ops         = &rdtgroup_kf_single_ops,
+               .seq_show       = rdt_num_closids_show,
+       },
+       {
+               .name           = "cbm_mask",
+               .mode           = 0444,
+               .kf_ops         = &rdtgroup_kf_single_ops,
+               .seq_show       = rdt_cbm_mask_show,
+       },
+       {
+               .name           = "min_cbm_bits",
+               .mode           = 0444,
+               .kf_ops         = &rdtgroup_kf_single_ops,
+               .seq_show       = rdt_min_cbm_bits_show,
+       },
+};
+
+static int rdtgroup_create_info_dir(struct kernfs_node *parent_kn)
+{
+       struct kernfs_node *kn_subdir;
+       struct rdt_resource *r;
+       int ret;
+
+       /* create the directory */
+       kn_info = kernfs_create_dir(parent_kn, "info", parent_kn->mode, NULL);
+       if (IS_ERR(kn_info))
+               return PTR_ERR(kn_info);
+       kernfs_get(kn_info);
+
+       for_each_enabled_rdt_resource(r) {
+               kn_subdir = kernfs_create_dir(kn_info, r->name,
+                                             kn_info->mode, r);
+               if (IS_ERR(kn_subdir)) {
+                       ret = PTR_ERR(kn_subdir);
+                       goto out_destroy;
+               }
+               kernfs_get(kn_subdir);
+               ret = rdtgroup_kn_set_ugid(kn_subdir);
+               if (ret)
+                       goto out_destroy;
+               ret = rdtgroup_add_files(kn_subdir, res_info_files,
+                                        ARRAY_SIZE(res_info_files));
+               if (ret)
+                       goto out_destroy;
+               kernfs_activate(kn_subdir);
+       }
+
+       /*
+        * This extra ref will be put in kernfs_remove() and guarantees
+        * that @rdtgrp->kn is always accessible.
+        */
+       kernfs_get(kn_info);
+
+       ret = rdtgroup_kn_set_ugid(kn_info);
+       if (ret)
+               goto out_destroy;
+
+       kernfs_activate(kn_info);
+
+       return 0;
+
+out_destroy:
+       kernfs_remove(kn_info);
+       return ret;
+}
+
+static void l3_qos_cfg_update(void *arg)
+{
+       bool *enable = arg;
+
+       wrmsrl(IA32_L3_QOS_CFG, *enable ? L3_QOS_CDP_ENABLE : 0ULL);
+}
+
+static int set_l3_qos_cfg(struct rdt_resource *r, bool enable)
+{
+       cpumask_var_t cpu_mask;
+       struct rdt_domain *d;
+       int cpu;
+
+       if (!zalloc_cpumask_var(&cpu_mask, GFP_KERNEL))
+               return -ENOMEM;
+
+       list_for_each_entry(d, &r->domains, list) {
+               /* Pick one CPU from each domain instance to update MSR */
+               cpumask_set_cpu(cpumask_any(&d->cpu_mask), cpu_mask);
+       }
+       cpu = get_cpu();
+       /* Update QOS_CFG MSR on this cpu if it's in cpu_mask. */
+       if (cpumask_test_cpu(cpu, cpu_mask))
+               l3_qos_cfg_update(&enable);
+       /* Update QOS_CFG MSR on all other cpus in cpu_mask. */
+       smp_call_function_many(cpu_mask, l3_qos_cfg_update, &enable, 1);
+       put_cpu();
+
+       free_cpumask_var(cpu_mask);
+
+       return 0;
+}
+
+static int cdp_enable(void)
+{
+       struct rdt_resource *r_l3data = &rdt_resources_all[RDT_RESOURCE_L3DATA];
+       struct rdt_resource *r_l3code = &rdt_resources_all[RDT_RESOURCE_L3CODE];
+       struct rdt_resource *r_l3 = &rdt_resources_all[RDT_RESOURCE_L3];
+       int ret;
+
+       if (!r_l3->capable || !r_l3data->capable || !r_l3code->capable)
+               return -EINVAL;
+
+       ret = set_l3_qos_cfg(r_l3, true);
+       if (!ret) {
+               r_l3->enabled = false;
+               r_l3data->enabled = true;
+               r_l3code->enabled = true;
+       }
+       return ret;
+}
+
+static void cdp_disable(void)
+{
+       struct rdt_resource *r = &rdt_resources_all[RDT_RESOURCE_L3];
+
+       r->enabled = r->capable;
+
+       if (rdt_resources_all[RDT_RESOURCE_L3DATA].enabled) {
+               rdt_resources_all[RDT_RESOURCE_L3DATA].enabled = false;
+               rdt_resources_all[RDT_RESOURCE_L3CODE].enabled = false;
+               set_l3_qos_cfg(r, false);
+       }
+}
+
+static int parse_rdtgroupfs_options(char *data)
+{
+       char *token, *o = data;
+       int ret = 0;
+
+       while ((token = strsep(&o, ",")) != NULL) {
+               if (!*token)
+                       return -EINVAL;
+
+               if (!strcmp(token, "cdp"))
+                       ret = cdp_enable();
+       }
+
+       return ret;
+}
+
+/*
+ * We don't allow rdtgroup directories to be created anywhere
+ * except the root directory. Thus when looking for the rdtgroup
+ * structure for a kernfs node we are either looking at a directory,
+ * in which case the rdtgroup structure is pointed at by the "priv"
+ * field, otherwise we have a file, and need only look to the parent
+ * to find the rdtgroup.
+ */
+static struct rdtgroup *kernfs_to_rdtgroup(struct kernfs_node *kn)
+{
+       if (kernfs_type(kn) == KERNFS_DIR) {
+               /*
+                * All the resource directories use "kn->priv"
+                * to point to the "struct rdtgroup" for the
+                * resource. "info" and its subdirectories don't
+                * have rdtgroup structures, so return NULL here.
+                */
+               if (kn == kn_info || kn->parent == kn_info)
+                       return NULL;
+               else
+                       return kn->priv;
+       } else {
+               return kn->parent->priv;
+       }
+}
+
+struct rdtgroup *rdtgroup_kn_lock_live(struct kernfs_node *kn)
+{
+       struct rdtgroup *rdtgrp = kernfs_to_rdtgroup(kn);
+
+       if (!rdtgrp)
+               return NULL;
+
+       atomic_inc(&rdtgrp->waitcount);
+       kernfs_break_active_protection(kn);
+
+       mutex_lock(&rdtgroup_mutex);
+
+       /* Was this group deleted while we waited? */
+       if (rdtgrp->flags & RDT_DELETED)
+               return NULL;
+
+       return rdtgrp;
+}
+
+void rdtgroup_kn_unlock(struct kernfs_node *kn)
+{
+       struct rdtgroup *rdtgrp = kernfs_to_rdtgroup(kn);
+
+       if (!rdtgrp)
+               return;
+
+       mutex_unlock(&rdtgroup_mutex);
+
+       if (atomic_dec_and_test(&rdtgrp->waitcount) &&
+           (rdtgrp->flags & RDT_DELETED)) {
+               kernfs_unbreak_active_protection(kn);
+               kernfs_put(kn);
+               kfree(rdtgrp);
+       } else {
+               kernfs_unbreak_active_protection(kn);
+       }
+}
+
+static struct dentry *rdt_mount(struct file_system_type *fs_type,
+                               int flags, const char *unused_dev_name,
+                               void *data)
+{
+       struct dentry *dentry;
+       int ret;
+
+       mutex_lock(&rdtgroup_mutex);
+       /*
+        * resctrl file system can only be mounted once.
+        */
+       if (static_branch_unlikely(&rdt_enable_key)) {
+               dentry = ERR_PTR(-EBUSY);
+               goto out;
+       }
+
+       ret = parse_rdtgroupfs_options(data);
+       if (ret) {
+               dentry = ERR_PTR(ret);
+               goto out_cdp;
+       }
+
+       closid_init();
+
+       ret = rdtgroup_create_info_dir(rdtgroup_default.kn);
+       if (ret) {
+               dentry = ERR_PTR(ret);
+               goto out_cdp;
+       }
+
+       dentry = kernfs_mount(fs_type, flags, rdt_root,
+                             RDTGROUP_SUPER_MAGIC, NULL);
+       if (IS_ERR(dentry))
+               goto out_cdp;
+
+       static_branch_enable(&rdt_enable_key);
+       goto out;
+
+out_cdp:
+       cdp_disable();
+out:
+       mutex_unlock(&rdtgroup_mutex);
+
+       return dentry;
+}
+
+static int reset_all_cbms(struct rdt_resource *r)
+{
+       struct msr_param msr_param;
+       cpumask_var_t cpu_mask;
+       struct rdt_domain *d;
+       int i, cpu;
+
+       if (!zalloc_cpumask_var(&cpu_mask, GFP_KERNEL))
+               return -ENOMEM;
+
+       msr_param.res = r;
+       msr_param.low = 0;
+       msr_param.high = r->num_closid;
+
+       /*
+        * Disable resource control for this resource by setting all
+        * CBMs in all domains to the maximum mask value. Pick one CPU
+        * from each domain to update the MSRs below.
+        */
+       list_for_each_entry(d, &r->domains, list) {
+               cpumask_set_cpu(cpumask_any(&d->cpu_mask), cpu_mask);
+
+               for (i = 0; i < r->num_closid; i++)
+                       d->cbm[i] = r->max_cbm;
+       }
+       cpu = get_cpu();
+       /* Update CBM on this cpu if it's in cpu_mask. */
+       if (cpumask_test_cpu(cpu, cpu_mask))
+               rdt_cbm_update(&msr_param);
+       /* Update CBM on all other cpus in cpu_mask. */
+       smp_call_function_many(cpu_mask, rdt_cbm_update, &msr_param, 1);
+       put_cpu();
+
+       free_cpumask_var(cpu_mask);
+
+       return 0;
+}
+
+/*
+ * Forcibly remove all of subdirectories under root.
+ */
+static void rmdir_all_sub(void)
+{
+       struct rdtgroup *rdtgrp, *tmp;
+       struct task_struct *p, *t;
+
+       /* move all tasks to default resource group */
+       read_lock(&tasklist_lock);
+       for_each_process_thread(p, t)
+               t->closid = 0;
+       read_unlock(&tasklist_lock);
+
+       list_for_each_entry_safe(rdtgrp, tmp, &rdt_all_groups, rdtgroup_list) {
+               /* Remove each rdtgroup other than root */
+               if (rdtgrp == &rdtgroup_default)
+                       continue;
+
+               /*
+                * Give any CPUs back to the default group. We cannot copy
+                * cpu_online_mask because a CPU might have executed the
+                * offline callback already, but is still marked online.
+                */
+               cpumask_or(&rdtgroup_default.cpu_mask,
+                          &rdtgroup_default.cpu_mask, &rdtgrp->cpu_mask);
+
+               rdt_update_percpu_closid(&rdtgrp->cpu_mask,
+                                        rdtgroup_default.closid);
+
+               kernfs_remove(rdtgrp->kn);
+               list_del(&rdtgrp->rdtgroup_list);
+               kfree(rdtgrp);
+       }
+       kernfs_remove(kn_info);
+}
+
+static void rdt_kill_sb(struct super_block *sb)
+{
+       struct rdt_resource *r;
+
+       mutex_lock(&rdtgroup_mutex);
+
+       /*Put everything back to default values. */
+       for_each_enabled_rdt_resource(r)
+               reset_all_cbms(r);
+       cdp_disable();
+       rmdir_all_sub();
+       static_branch_disable(&rdt_enable_key);
+       kernfs_kill_sb(sb);
+       mutex_unlock(&rdtgroup_mutex);
+}
+
+static struct file_system_type rdt_fs_type = {
+       .name    = "resctrl",
+       .mount   = rdt_mount,
+       .kill_sb = rdt_kill_sb,
+};
+
+static int rdtgroup_mkdir(struct kernfs_node *parent_kn, const char *name,
+                         umode_t mode)
+{
+       struct rdtgroup *parent, *rdtgrp;
+       struct kernfs_node *kn;
+       int ret, closid;
+
+       /* Only allow mkdir in the root directory */
+       if (parent_kn != rdtgroup_default.kn)
+               return -EPERM;
+
+       /* Do not accept '\n' to avoid unparsable situation. */
+       if (strchr(name, '\n'))
+               return -EINVAL;
+
+       parent = rdtgroup_kn_lock_live(parent_kn);
+       if (!parent) {
+               ret = -ENODEV;
+               goto out_unlock;
+       }
+
+       ret = closid_alloc();
+       if (ret < 0)
+               goto out_unlock;
+       closid = ret;
+
+       /* allocate the rdtgroup. */
+       rdtgrp = kzalloc(sizeof(*rdtgrp), GFP_KERNEL);
+       if (!rdtgrp) {
+               ret = -ENOSPC;
+               goto out_closid_free;
+       }
+       rdtgrp->closid = closid;
+       list_add(&rdtgrp->rdtgroup_list, &rdt_all_groups);
+
+       /* kernfs creates the directory for rdtgrp */
+       kn = kernfs_create_dir(parent->kn, name, mode, rdtgrp);
+       if (IS_ERR(kn)) {
+               ret = PTR_ERR(kn);
+               goto out_cancel_ref;
+       }
+       rdtgrp->kn = kn;
+
+       /*
+        * kernfs_remove() will drop the reference count on "kn" which
+        * will free it. But we still need it to stick around for the
+        * rdtgroup_kn_unlock(kn} call below. Take one extra reference
+        * here, which will be dropped inside rdtgroup_kn_unlock().
+        */
+       kernfs_get(kn);
+
+       ret = rdtgroup_kn_set_ugid(kn);
+       if (ret)
+               goto out_destroy;
+
+       ret = rdtgroup_add_files(kn, rdtgroup_base_files,
+                                ARRAY_SIZE(rdtgroup_base_files));
+       if (ret)
+               goto out_destroy;
+
+       kernfs_activate(kn);
+
+       ret = 0;
+       goto out_unlock;
+
+out_destroy:
+       kernfs_remove(rdtgrp->kn);
+out_cancel_ref:
+       list_del(&rdtgrp->rdtgroup_list);
+       kfree(rdtgrp);
+out_closid_free:
+       closid_free(closid);
+out_unlock:
+       rdtgroup_kn_unlock(parent_kn);
+       return ret;
+}
+
+static int rdtgroup_rmdir(struct kernfs_node *kn)
+{
+       struct task_struct *p, *t;
+       struct rdtgroup *rdtgrp;
+
+       rdtgrp = rdtgroup_kn_lock_live(kn);
+       if (!rdtgrp) {
+               rdtgroup_kn_unlock(kn);
+               return -EPERM;
+       }
+
+       /* Give any tasks back to the default group */
+       read_lock(&tasklist_lock);
+       for_each_process_thread(p, t) {
+               if (t->closid == rdtgrp->closid)
+                       t->closid = 0;
+       }
+       read_unlock(&tasklist_lock);
+
+       /* Give any CPUs back to the default group */
+       cpumask_or(&rdtgroup_default.cpu_mask,
+                  &rdtgroup_default.cpu_mask, &rdtgrp->cpu_mask);
+       rdt_update_percpu_closid(&rdtgrp->cpu_mask, rdtgroup_default.closid);
+
+       rdtgrp->flags = RDT_DELETED;
+       closid_free(rdtgrp->closid);
+       list_del(&rdtgrp->rdtgroup_list);
+
+       /*
+        * one extra hold on this, will drop when we kfree(rdtgrp)
+        * in rdtgroup_kn_unlock()
+        */
+       kernfs_get(kn);
+       kernfs_remove(rdtgrp->kn);
+
+       rdtgroup_kn_unlock(kn);
+       return 0;
+}
+
+static struct kernfs_syscall_ops rdtgroup_kf_syscall_ops = {
+       .mkdir  = rdtgroup_mkdir,
+       .rmdir  = rdtgroup_rmdir,
+};
+
+static int __init rdtgroup_setup_root(void)
+{
+       int ret;
+
+       rdt_root = kernfs_create_root(&rdtgroup_kf_syscall_ops,
+                                     KERNFS_ROOT_CREATE_DEACTIVATED,
+                                     &rdtgroup_default);
+       if (IS_ERR(rdt_root))
+               return PTR_ERR(rdt_root);
+
+       mutex_lock(&rdtgroup_mutex);
+
+       rdtgroup_default.closid = 0;
+       list_add(&rdtgroup_default.rdtgroup_list, &rdt_all_groups);
+
+       ret = rdtgroup_add_files(rdt_root->kn, rdtgroup_base_files,
+                                ARRAY_SIZE(rdtgroup_base_files));
+       if (ret) {
+               kernfs_destroy_root(rdt_root);
+               goto out;
+       }
+
+       rdtgroup_default.kn = rdt_root->kn;
+       kernfs_activate(rdtgroup_default.kn);
+
+out:
+       mutex_unlock(&rdtgroup_mutex);
+
+       return ret;
+}
+
+/*
+ * rdtgroup_init - rdtgroup initialization
+ *
+ * Setup resctrl file system including set up root, create mount point,
+ * register rdtgroup filesystem, and initialize files under root directory.
+ *
+ * Return: 0 on success or -errno
+ */
+int __init rdtgroup_init(void)
+{
+       int ret = 0;
+
+       ret = rdtgroup_setup_root();
+       if (ret)
+               return ret;
+
+       ret = sysfs_create_mount_point(fs_kobj, "resctrl");
+       if (ret)
+               goto cleanup_root;
+
+       ret = register_filesystem(&rdt_fs_type);
+       if (ret)
+               goto cleanup_mountpoint;
+
+       return 0;
+
+cleanup_mountpoint:
+       sysfs_remove_mount_point(fs_kobj, "resctrl");
+cleanup_root:
+       kernfs_destroy_root(rdt_root);
+
+       return ret;
+}
diff --git a/arch/x86/kernel/cpu/intel_rdt_schemata.c b/arch/x86/kernel/cpu/intel_rdt_schemata.c
new file mode 100644 (file)
index 0000000..f369cb8
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * Resource Director Technology(RDT)
+ * - Cache Allocation code.
+ *
+ * Copyright (C) 2016 Intel Corporation
+ *
+ * Authors:
+ *    Fenghua Yu <fenghua.yu@intel.com>
+ *    Tony Luck <tony.luck@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * More information about RDT be found in the Intel (R) x86 Architecture
+ * Software Developer Manual June 2016, volume 3, section 17.17.
+ */
+
+#define pr_fmt(fmt)    KBUILD_MODNAME ": " fmt
+
+#include <linux/kernfs.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <asm/intel_rdt.h>
+
+/*
+ * 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.).
+ * Additionally Haswell requires at least two bits set.
+ */
+static bool cbm_validate(unsigned long var, struct rdt_resource *r)
+{
+       unsigned long first_bit, zero_bit;
+
+       if (var == 0 || var > r->max_cbm)
+               return false;
+
+       first_bit = find_first_bit(&var, r->cbm_len);
+       zero_bit = find_next_zero_bit(&var, r->cbm_len, first_bit);
+
+       if (find_next_bit(&var, r->cbm_len, zero_bit) < r->cbm_len)
+               return false;
+
+       if ((zero_bit - first_bit) < r->min_cbm_bits)
+               return false;
+       return true;
+}
+
+/*
+ * Read one cache bit mask (hex). Check that it is valid for the current
+ * resource type.
+ */
+static int parse_cbm(char *buf, struct rdt_resource *r)
+{
+       unsigned long data;
+       int ret;
+
+       ret = kstrtoul(buf, 16, &data);
+       if (ret)
+               return ret;
+       if (!cbm_validate(data, r))
+               return -EINVAL;
+       r->tmp_cbms[r->num_tmp_cbms++] = data;
+
+       return 0;
+}
+
+/*
+ * For each domain in this resource we expect to find a series of:
+ *     id=mask
+ * separated by ";". The "id" is in decimal, and must appear in the
+ * right order.
+ */
+static int parse_line(char *line, struct rdt_resource *r)
+{
+       char *dom = NULL, *id;
+       struct rdt_domain *d;
+       unsigned long dom_id;
+
+       list_for_each_entry(d, &r->domains, list) {
+               dom = strsep(&line, ";");
+               if (!dom)
+                       return -EINVAL;
+               id = strsep(&dom, "=");
+               if (kstrtoul(id, 10, &dom_id) || dom_id != d->id)
+                       return -EINVAL;
+               if (parse_cbm(dom, r))
+                       return -EINVAL;
+       }
+
+       /* Any garbage at the end of the line? */
+       if (line && line[0])
+               return -EINVAL;
+       return 0;
+}
+
+static int update_domains(struct rdt_resource *r, int closid)
+{
+       struct msr_param msr_param;
+       cpumask_var_t cpu_mask;
+       struct rdt_domain *d;
+       int cpu, idx = 0;
+
+       if (!zalloc_cpumask_var(&cpu_mask, GFP_KERNEL))
+               return -ENOMEM;
+
+       msr_param.low = closid;
+       msr_param.high = msr_param.low + 1;
+       msr_param.res = r;
+
+       list_for_each_entry(d, &r->domains, list) {
+               cpumask_set_cpu(cpumask_any(&d->cpu_mask), cpu_mask);
+               d->cbm[msr_param.low] = r->tmp_cbms[idx++];
+       }
+       cpu = get_cpu();
+       /* Update CBM on this cpu if it's in cpu_mask. */
+       if (cpumask_test_cpu(cpu, cpu_mask))
+               rdt_cbm_update(&msr_param);
+       /* Update CBM on other cpus. */
+       smp_call_function_many(cpu_mask, rdt_cbm_update, &msr_param, 1);
+       put_cpu();
+
+       free_cpumask_var(cpu_mask);
+
+       return 0;
+}
+
+ssize_t rdtgroup_schemata_write(struct kernfs_open_file *of,
+                               char *buf, size_t nbytes, loff_t off)
+{
+       struct rdtgroup *rdtgrp;
+       struct rdt_resource *r;
+       char *tok, *resname;
+       int closid, ret = 0;
+       u32 *l3_cbms = NULL;
+
+       /* Valid input requires a trailing newline */
+       if (nbytes == 0 || buf[nbytes - 1] != '\n')
+               return -EINVAL;
+       buf[nbytes - 1] = '\0';
+
+       rdtgrp = rdtgroup_kn_lock_live(of->kn);
+       if (!rdtgrp) {
+               rdtgroup_kn_unlock(of->kn);
+               return -ENOENT;
+       }
+
+       closid = rdtgrp->closid;
+
+       /* get scratch space to save all the masks while we validate input */
+       for_each_enabled_rdt_resource(r) {
+               r->tmp_cbms = kcalloc(r->num_domains, sizeof(*l3_cbms),
+                                     GFP_KERNEL);
+               if (!r->tmp_cbms) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+               r->num_tmp_cbms = 0;
+       }
+
+       while ((tok = strsep(&buf, "\n")) != NULL) {
+               resname = strsep(&tok, ":");
+               if (!tok) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+               for_each_enabled_rdt_resource(r) {
+                       if (!strcmp(resname, r->name) &&
+                           closid < r->num_closid) {
+                               ret = parse_line(tok, r);
+                               if (ret)
+                                       goto out;
+                               break;
+                       }
+               }
+               if (!r->name) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+       }
+
+       /* Did the parser find all the masks we need? */
+       for_each_enabled_rdt_resource(r) {
+               if (r->num_tmp_cbms != r->num_domains) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+       }
+
+       for_each_enabled_rdt_resource(r) {
+               ret = update_domains(r, closid);
+               if (ret)
+                       goto out;
+       }
+
+out:
+       rdtgroup_kn_unlock(of->kn);
+       for_each_enabled_rdt_resource(r) {
+               kfree(r->tmp_cbms);
+               r->tmp_cbms = NULL;
+       }
+       return ret ?: nbytes;
+}
+
+static void show_doms(struct seq_file *s, struct rdt_resource *r, int closid)
+{
+       struct rdt_domain *dom;
+       bool sep = false;
+
+       seq_printf(s, "%s:", r->name);
+       list_for_each_entry(dom, &r->domains, list) {
+               if (sep)
+                       seq_puts(s, ";");
+               seq_printf(s, "%d=%x", dom->id, dom->cbm[closid]);
+               sep = true;
+       }
+       seq_puts(s, "\n");
+}
+
+int rdtgroup_schemata_show(struct kernfs_open_file *of,
+                          struct seq_file *s, void *v)
+{
+       struct rdtgroup *rdtgrp;
+       struct rdt_resource *r;
+       int closid, ret = 0;
+
+       rdtgrp = rdtgroup_kn_lock_live(of->kn);
+       if (rdtgrp) {
+               closid = rdtgrp->closid;
+               for_each_enabled_rdt_resource(r) {
+                       if (closid < r->num_closid)
+                               show_doms(s, r, closid);
+               }
+       } else {
+               ret = -ENOENT;
+       }
+       rdtgroup_kn_unlock(of->kn);
+       return ret;
+}
index d1316f9c8329846b0d3f7dede754fa0eef256bd3..d9794060fe225f72f34e78cdc74959aa1bf38934 100644 (file)
@@ -20,12 +20,15 @@ struct cpuid_bit {
 /* Please keep the leaf sorted by cpuid_bit.level for faster search. */
 static const struct cpuid_bit cpuid_bits[] = {
        { X86_FEATURE_APERFMPERF,       CPUID_ECX,  0, 0x00000006, 0 },
-       { X86_FEATURE_EPB,              CPUID_ECX,  3, 0x00000006, 0 },
-       { X86_FEATURE_INTEL_PT,         CPUID_EBX, 25, 0x00000007, 0 },
+       { X86_FEATURE_EPB,              CPUID_ECX,  3, 0x00000006, 0 },
+       { X86_FEATURE_INTEL_PT,         CPUID_EBX, 25, 0x00000007, 0 },
        { X86_FEATURE_AVX512_4VNNIW,    CPUID_EDX,  2, 0x00000007, 0 },
        { X86_FEATURE_AVX512_4FMAPS,    CPUID_EDX,  3, 0x00000007, 0 },
-       { X86_FEATURE_HW_PSTATE,        CPUID_EDX,  7, 0x80000007, 0 },
-       { X86_FEATURE_CPB,              CPUID_EDX,  9, 0x80000007, 0 },
+       { X86_FEATURE_CAT_L3,           CPUID_EBX,  1, 0x00000010, 0 },
+       { X86_FEATURE_CAT_L2,           CPUID_EBX,  2, 0x00000010, 0 },
+       { X86_FEATURE_CDP_L3,           CPUID_ECX,  2, 0x00000010, 1 },
+       { X86_FEATURE_HW_PSTATE,        CPUID_EDX,  7, 0x80000007, 0 },
+       { X86_FEATURE_CPB,              CPUID_EDX,  9, 0x80000007, 0 },
        { X86_FEATURE_PROC_FEEDBACK,    CPUID_EDX, 11, 0x80000007, 0 },
        { 0, 0, 0, 0, 0 }
 };
index bd7be8efdc4ce7ae49f155b7f701f6d6d800293f..efe7f9fce44ebe30841921ed22607a25542fe776 100644 (file)
@@ -54,6 +54,7 @@
 #include <asm/debugreg.h>
 #include <asm/switch_to.h>
 #include <asm/vm86.h>
+#include <asm/intel_rdt.h>
 
 void __show_regs(struct pt_regs *regs, int all)
 {
@@ -299,5 +300,8 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
 
        this_cpu_write(current_task, next_p);
 
+       /* Load the Intel cache allocation PQR MSR. */
+       intel_rdt_sched_in();
+
        return prev_p;
 }
index b3760b3c1ca09734a4479f63f3787dac42275a24..acd7d6f507aff093bb0c121ace26d105b378b112 100644 (file)
@@ -50,6 +50,7 @@
 #include <asm/switch_to.h>
 #include <asm/xen/hypervisor.h>
 #include <asm/vdso.h>
+#include <asm/intel_rdt.h>
 
 __visible DEFINE_PER_CPU(unsigned long, rsp_scratch);
 
@@ -473,6 +474,9 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
                        loadsegment(ss, __KERNEL_DS);
        }
 
+       /* Load the Intel cache allocation PQR MSR. */
+       intel_rdt_sched_in();
+
        return prev_p;
 }
 
index e9fd32e91668992e478f31423c1e56be0724e1d2..00a9688043f4dfffcb1c4db468a5095a48000389 100644 (file)
@@ -233,6 +233,7 @@ static ssize_t file_name##_show(struct device *dev,         \
        return sprintf(buf, "%u\n", this_leaf->object);         \
 }
 
+show_one(id, id);
 show_one(level, level);
 show_one(coherency_line_size, coherency_line_size);
 show_one(number_of_sets, number_of_sets);
@@ -314,6 +315,7 @@ static ssize_t write_policy_show(struct device *dev,
        return n;
 }
 
+static DEVICE_ATTR_RO(id);
 static DEVICE_ATTR_RO(level);
 static DEVICE_ATTR_RO(type);
 static DEVICE_ATTR_RO(coherency_line_size);
@@ -327,6 +329,7 @@ static DEVICE_ATTR_RO(shared_cpu_list);
 static DEVICE_ATTR_RO(physical_line_partition);
 
 static struct attribute *cache_default_attrs[] = {
+       &dev_attr_id.attr,
        &dev_attr_type.attr,
        &dev_attr_level.attr,
        &dev_attr_shared_cpu_map.attr,
@@ -350,6 +353,8 @@ cache_default_attrs_is_visible(struct kobject *kobj,
        const struct cpumask *mask = &this_leaf->shared_cpu_map;
        umode_t mode = attr->mode;
 
+       if ((attr == &dev_attr_id.attr) && (this_leaf->attributes & CACHE_ID))
+               return mode;
        if ((attr == &dev_attr_type.attr) && this_leaf->type)
                return mode;
        if ((attr == &dev_attr_level.attr) && this_leaf->level)
index 2189935075b48e3d5b06012f9279f6eea4973fa7..0bcbb674da9d1352138af9626e149265c0705f25 100644 (file)
@@ -18,6 +18,7 @@ enum cache_type {
 
 /**
  * struct cacheinfo - represent a cache leaf node
+ * @id: This cache's id. It is unique among caches with the same (type, level).
  * @type: type of the cache - data, inst or unified
  * @level: represents the hierarchy in the multi-level cache
  * @coherency_line_size: size of each cache line usually representing
@@ -44,6 +45,7 @@ enum cache_type {
  * keeping, the remaining members form the core properties of the cache
  */
 struct cacheinfo {
+       unsigned int id;
        enum cache_type type;
        unsigned int level;
        unsigned int coherency_line_size;
@@ -61,6 +63,7 @@ struct cacheinfo {
 #define CACHE_WRITE_ALLOCATE   BIT(3)
 #define CACHE_ALLOCATE_POLICY_MASK     \
        (CACHE_READ_ALLOCATE | CACHE_WRITE_ALLOCATE)
+#define CACHE_ID               BIT(4)
 
        struct device_node *of_node;
        bool disable_sysfs;
index 348f51b0ec92ed02e72a2060eedb03f37cd0995f..c8f4152e726541840aac6e6851ab5cfa83c13247 100644 (file)
@@ -1791,6 +1791,9 @@ struct task_struct {
        /* cg_list protected by css_set_lock and tsk->alloc_lock */
        struct list_head cg_list;
 #endif
+#ifdef CONFIG_INTEL_RDT_A
+       int closid;
+#endif
 #ifdef CONFIG_FUTEX
        struct robust_list_head __user *robust_list;
 #ifdef CONFIG_COMPAT
index 9bd559472c9280a6317e336f3a62471fd0aafa49..e230af2e68558fa8ed1778b2c154686f8b1e2481 100644 (file)
@@ -57,6 +57,7 @@
 #define CGROUP_SUPER_MAGIC     0x27e0eb
 #define CGROUP2_SUPER_MAGIC    0x63677270
 
+#define RDTGROUP_SUPER_MAGIC   0x7655821
 
 #define STACK_END_MAGIC                0x57AC6E9D