2019-05-29 07:18:02 -07:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
2016-10-28 15:04:42 -07:00
|
|
|
/*
|
2021-03-18 15:28:01 +01:00
|
|
|
* User interface for Resource Allocation in Resource Director Technology(RDT)
|
2016-10-28 15:04:42 -07:00
|
|
|
*
|
|
|
|
* Copyright (C) 2016 Intel Corporation
|
|
|
|
*
|
|
|
|
* Author: Fenghua Yu <fenghua.yu@intel.com>
|
|
|
|
*
|
|
|
|
* More information about RDT be found in the Intel (R) x86 Architecture
|
|
|
|
* Software Developer Manual.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
|
|
|
2016-10-28 15:04:45 -07:00
|
|
|
#include <linux/cpu.h>
|
2018-06-22 15:42:25 -07:00
|
|
|
#include <linux/debugfs.h>
|
2016-10-28 15:04:42 -07:00
|
|
|
#include <linux/fs.h>
|
kernfs, sysfs, cgroup, intel_rdt: Support fs_context
Make kernfs support superblock creation/mount/remount with fs_context.
This requires that sysfs, cgroup and intel_rdt, which are built on kernfs,
be made to support fs_context also.
Notes:
(1) A kernfs_fs_context struct is created to wrap fs_context and the
kernfs mount parameters are moved in here (or are in fs_context).
(2) kernfs_mount{,_ns}() are made into kernfs_get_tree(). The extra
namespace tag parameter is passed in the context if desired
(3) kernfs_free_fs_context() is provided as a destructor for the
kernfs_fs_context struct, but for the moment it does nothing except
get called in the right places.
(4) sysfs doesn't wrap kernfs_fs_context since it has no parameters to
pass, but possibly this should be done anyway in case someone wants to
add a parameter in future.
(5) A cgroup_fs_context struct is created to wrap kernfs_fs_context and
the cgroup v1 and v2 mount parameters are all moved there.
(6) cgroup1 parameter parsing error messages are now handled by invalf(),
which allows userspace to collect them directly.
(7) cgroup1 parameter cleanup is now done in the context destructor rather
than in the mount/get_tree and remount functions.
Weirdies:
(*) cgroup_do_get_tree() calls cset_cgroup_from_root() with locks held,
but then uses the resulting pointer after dropping the locks. I'm
told this is okay and needs commenting.
(*) The cgroup refcount web. This really needs documenting.
(*) cgroup2 only has one root?
Add a suggestion from Thomas Gleixner in which the RDT enablement code is
placed into its own function.
[folded a leak fix from Andrey Vagin]
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
cc: Tejun Heo <tj@kernel.org>
cc: Li Zefan <lizefan@huawei.com>
cc: Johannes Weiner <hannes@cmpxchg.org>
cc: cgroups@vger.kernel.org
cc: fenghua.yu@intel.com
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2018-11-01 23:07:26 +00:00
|
|
|
#include <linux/fs_parser.h>
|
2016-10-28 15:04:42 -07:00
|
|
|
#include <linux/sysfs.h>
|
|
|
|
#include <linux/kernfs.h>
|
2025-05-15 16:58:45 +00:00
|
|
|
#include <linux/resctrl.h>
|
2017-09-25 16:39:33 -07:00
|
|
|
#include <linux/seq_buf.h>
|
2016-10-28 15:04:43 -07:00
|
|
|
#include <linux/seq_file.h>
|
2017-02-08 18:51:30 +01:00
|
|
|
#include <linux/sched/signal.h>
|
2017-02-08 18:51:36 +01:00
|
|
|
#include <linux/sched/task.h>
|
2016-10-28 15:04:42 -07:00
|
|
|
#include <linux/slab.h>
|
2016-10-28 15:04:46 -07:00
|
|
|
#include <linux/task_work.h>
|
kernfs, sysfs, cgroup, intel_rdt: Support fs_context
Make kernfs support superblock creation/mount/remount with fs_context.
This requires that sysfs, cgroup and intel_rdt, which are built on kernfs,
be made to support fs_context also.
Notes:
(1) A kernfs_fs_context struct is created to wrap fs_context and the
kernfs mount parameters are moved in here (or are in fs_context).
(2) kernfs_mount{,_ns}() are made into kernfs_get_tree(). The extra
namespace tag parameter is passed in the context if desired
(3) kernfs_free_fs_context() is provided as a destructor for the
kernfs_fs_context struct, but for the moment it does nothing except
get called in the right places.
(4) sysfs doesn't wrap kernfs_fs_context since it has no parameters to
pass, but possibly this should be done anyway in case someone wants to
add a parameter in future.
(5) A cgroup_fs_context struct is created to wrap kernfs_fs_context and
the cgroup v1 and v2 mount parameters are all moved there.
(6) cgroup1 parameter parsing error messages are now handled by invalf(),
which allows userspace to collect them directly.
(7) cgroup1 parameter cleanup is now done in the context destructor rather
than in the mount/get_tree and remount functions.
Weirdies:
(*) cgroup_do_get_tree() calls cset_cgroup_from_root() with locks held,
but then uses the resulting pointer after dropping the locks. I'm
told this is okay and needs commenting.
(*) The cgroup refcount web. This really needs documenting.
(*) cgroup2 only has one root?
Add a suggestion from Thomas Gleixner in which the RDT enablement code is
placed into its own function.
[folded a leak fix from Andrey Vagin]
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
cc: Tejun Heo <tj@kernel.org>
cc: Li Zefan <lizefan@huawei.com>
cc: Johannes Weiner <hannes@cmpxchg.org>
cc: cgroups@vger.kernel.org
cc: fenghua.yu@intel.com
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2018-11-01 23:07:26 +00:00
|
|
|
#include <linux/user_namespace.h>
|
2016-10-28 15:04:42 -07:00
|
|
|
|
|
|
|
#include <uapi/linux/magic.h>
|
|
|
|
|
2025-04-30 22:42:41 -07:00
|
|
|
#include <asm/msr.h>
|
2018-11-21 20:28:25 +00:00
|
|
|
#include "internal.h"
|
2016-10-28 15:04:42 -07:00
|
|
|
|
2017-07-25 14:14:41 -07:00
|
|
|
DEFINE_STATIC_KEY_FALSE(rdt_enable_key);
|
|
|
|
|
2025-05-15 16:58:54 +00:00
|
|
|
DEFINE_STATIC_KEY_FALSE(rdt_mon_enable_key);
|
2023-10-16 19:23:04 -05:00
|
|
|
|
2025-05-15 16:58:54 +00:00
|
|
|
DEFINE_STATIC_KEY_FALSE(rdt_alloc_enable_key);
|
2018-06-22 15:42:25 -07:00
|
|
|
|
2024-12-06 08:31:42 -08:00
|
|
|
/*
|
2025-05-15 16:58:54 +00:00
|
|
|
* This is safe against resctrl_arch_sched_in() called from __switch_to()
|
|
|
|
* because __switch_to() is executed with interrupts disabled. A local call
|
|
|
|
* from update_closid_rmid() is protected against __switch_to() because
|
|
|
|
* preemption is disabled.
|
2024-12-06 08:31:42 -08:00
|
|
|
*/
|
2025-05-15 16:58:54 +00:00
|
|
|
void resctrl_arch_sync_cpu_closid_rmid(void *info)
|
2023-01-17 13:14:50 -08:00
|
|
|
{
|
2025-05-15 16:58:54 +00:00
|
|
|
struct resctrl_cpu_defaults *r = info;
|
2023-01-17 13:14:50 -08:00
|
|
|
|
2025-05-15 16:58:54 +00:00
|
|
|
if (r) {
|
|
|
|
this_cpu_write(pqr_state.default_closid, r->closid);
|
|
|
|
this_cpu_write(pqr_state.default_rmid, r->rmid);
|
2023-01-17 13:14:50 -08:00
|
|
|
}
|
|
|
|
|
2025-05-15 16:58:54 +00:00
|
|
|
/*
|
|
|
|
* We cannot unconditionally write the MSR because the current
|
|
|
|
* executing task might have its own closid selected. Just reuse
|
|
|
|
* the context switch code.
|
|
|
|
*/
|
|
|
|
resctrl_arch_sched_in(current);
|
2025-03-11 18:37:03 +00:00
|
|
|
}
|
|
|
|
|
2025-05-15 16:58:54 +00:00
|
|
|
#define INVALID_CONFIG_INDEX UINT_MAX
|
2025-03-11 18:37:03 +00:00
|
|
|
|
2025-05-15 16:58:54 +00:00
|
|
|
/**
|
|
|
|
* mon_event_config_index_get - get the hardware index for the
|
|
|
|
* configurable event
|
|
|
|
* @evtid: event id.
|
2016-10-28 15:04:44 -07:00
|
|
|
*
|
2025-05-15 16:58:54 +00:00
|
|
|
* Return: 0 for evtid == QOS_L3_MBM_TOTAL_EVENT_ID
|
|
|
|
* 1 for evtid == QOS_L3_MBM_LOCAL_EVENT_ID
|
|
|
|
* INVALID_CONFIG_INDEX for invalid evtid
|
2016-10-28 15:04:44 -07:00
|
|
|
*/
|
2025-05-15 16:58:54 +00:00
|
|
|
static inline unsigned int mon_event_config_index_get(u32 evtid)
|
2016-10-28 15:04:44 -07:00
|
|
|
{
|
2025-05-15 16:58:54 +00:00
|
|
|
switch (evtid) {
|
|
|
|
case QOS_L3_MBM_TOTAL_EVENT_ID:
|
2025-05-15 16:58:35 +00:00
|
|
|
return 0;
|
2025-05-15 16:58:54 +00:00
|
|
|
case QOS_L3_MBM_LOCAL_EVENT_ID:
|
|
|
|
return 1;
|
|
|
|
default:
|
|
|
|
/* Should never reach here */
|
|
|
|
return INVALID_CONFIG_INDEX;
|
|
|
|
}
|
2016-10-28 15:04:44 -07:00
|
|
|
}
|
|
|
|
|
2025-05-15 16:58:54 +00:00
|
|
|
void resctrl_arch_mon_event_config_read(void *_config_info)
|
2016-10-28 15:04:44 -07:00
|
|
|
{
|
2025-05-15 16:58:54 +00:00
|
|
|
struct resctrl_mon_config_info *config_info = _config_info;
|
|
|
|
unsigned int index;
|
|
|
|
u64 msrval;
|
2024-02-13 18:44:23 +00:00
|
|
|
|
2025-05-15 16:58:54 +00:00
|
|
|
index = mon_event_config_index_get(config_info->evtid);
|
|
|
|
if (index == INVALID_CONFIG_INDEX) {
|
|
|
|
pr_warn_once("Invalid event id %d\n", config_info->evtid);
|
|
|
|
return;
|
2024-02-13 18:44:24 +00:00
|
|
|
}
|
2025-05-27 09:53:02 -07:00
|
|
|
rdmsrq(MSR_IA32_EVT_CFG_BASE + index, msrval);
|
2024-02-13 18:44:23 +00:00
|
|
|
|
2025-05-15 16:58:54 +00:00
|
|
|
/* Report only the valid event configuration bits */
|
|
|
|
config_info->mon_config = msrval & MAX_EVT_CONFIG_BITS;
|
2016-10-28 15:04:44 -07:00
|
|
|
}
|
|
|
|
|
2025-05-15 16:58:54 +00:00
|
|
|
void resctrl_arch_mon_event_config_write(void *_config_info)
|
2018-06-22 15:41:57 -07:00
|
|
|
{
|
2025-05-15 16:58:54 +00:00
|
|
|
struct resctrl_mon_config_info *config_info = _config_info;
|
|
|
|
unsigned int index;
|
2024-02-13 18:44:23 +00:00
|
|
|
|
2025-05-15 16:58:54 +00:00
|
|
|
index = mon_event_config_index_get(config_info->evtid);
|
|
|
|
if (index == INVALID_CONFIG_INDEX) {
|
|
|
|
pr_warn_once("Invalid event id %d\n", config_info->evtid);
|
|
|
|
return;
|
|
|
|
}
|
2025-05-27 09:53:02 -07:00
|
|
|
wrmsrq(MSR_IA32_EVT_CFG_BASE + index, config_info->mon_config);
|
2018-06-22 15:41:57 -07:00
|
|
|
}
|
|
|
|
|
2025-05-15 16:58:54 +00:00
|
|
|
static void l3_qos_cfg_update(void *arg)
|
2018-06-22 15:41:55 -07:00
|
|
|
{
|
2025-05-15 16:58:54 +00:00
|
|
|
bool *enable = arg;
|
2018-06-22 15:41:55 -07:00
|
|
|
|
2025-05-27 09:53:02 -07:00
|
|
|
wrmsrq(MSR_IA32_L3_QOS_CFG, *enable ? L3_QOS_CDP_ENABLE : 0ULL);
|
2018-06-22 15:41:55 -07:00
|
|
|
}
|
|
|
|
|
2025-05-15 16:58:54 +00:00
|
|
|
static void l2_qos_cfg_update(void *arg)
|
2018-06-22 15:41:56 -07:00
|
|
|
{
|
2025-05-15 16:58:54 +00:00
|
|
|
bool *enable = arg;
|
2018-06-22 15:41:56 -07:00
|
|
|
|
2025-05-27 09:53:02 -07:00
|
|
|
wrmsrq(MSR_IA32_L2_QOS_CFG, *enable ? L2_QOS_CDP_ENABLE : 0ULL);
|
2018-06-22 15:41:56 -07:00
|
|
|
}
|
|
|
|
|
2025-05-15 16:58:54 +00:00
|
|
|
static int set_cache_qos_cfg(int level, bool enable)
|
2016-10-28 15:04:43 -07:00
|
|
|
{
|
2025-05-15 16:58:54 +00:00
|
|
|
void (*update)(void *arg);
|
|
|
|
struct rdt_ctrl_domain *d;
|
|
|
|
struct rdt_resource *r_l;
|
|
|
|
cpumask_var_t cpu_mask;
|
|
|
|
int cpu;
|
2016-10-28 15:04:43 -07:00
|
|
|
|
2025-05-15 16:58:54 +00:00
|
|
|
/* Walking r->domains, ensure it can't race with cpuhp */
|
|
|
|
lockdep_assert_cpus_held();
|
2016-10-28 15:04:43 -07:00
|
|
|
|
2025-05-15 16:58:54 +00:00
|
|
|
if (level == RDT_RESOURCE_L3)
|
|
|
|
update = l3_qos_cfg_update;
|
|
|
|
else if (level == RDT_RESOURCE_L2)
|
|
|
|
update = l2_qos_cfg_update;
|
|
|
|
else
|
|
|
|
return -EINVAL;
|
2016-10-28 15:04:43 -07:00
|
|
|
|
2025-05-15 16:58:54 +00:00
|
|
|
if (!zalloc_cpumask_var(&cpu_mask, GFP_KERNEL))
|
|
|
|
return -ENOMEM;
|
2016-10-28 15:04:43 -07:00
|
|
|
|
2025-05-15 16:58:54 +00:00
|
|
|
r_l = &rdt_resources_all[level].r_resctrl;
|
|
|
|
list_for_each_entry(d, &r_l->ctrl_domains, hdr.list) {
|
|
|
|
if (r_l->cache.arch_has_per_cpu_cfg)
|
|
|
|
/* Pick all the CPUs in the domain instance */
|
|
|
|
for_each_cpu(cpu, &d->hdr.cpu_mask)
|
|
|
|
cpumask_set_cpu(cpu, cpu_mask);
|
|
|
|
else
|
|
|
|
/* Pick one CPU from each domain instance to update MSR */
|
|
|
|
cpumask_set_cpu(cpumask_any(&d->hdr.cpu_mask), cpu_mask);
|
2016-10-28 15:04:43 -07:00
|
|
|
}
|
|
|
|
|
2025-05-15 16:58:54 +00:00
|
|
|
/* Update QOS_CFG MSR on all the CPUs in cpu_mask */
|
|
|
|
on_each_cpu_mask(cpu_mask, update, &enable, 1);
|
2016-10-28 15:04:43 -07:00
|
|
|
|
2025-05-15 16:58:54 +00:00
|
|
|
free_cpumask_var(cpu_mask);
|
2016-10-28 15:04:43 -07:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2025-05-15 16:58:54 +00:00
|
|
|
/* Restore the qos cfg state when a domain comes online */
|
|
|
|
void rdt_domain_reconfigure_cdp(struct rdt_resource *r)
|
2016-10-28 15:04:43 -07:00
|
|
|
{
|
2025-05-15 16:58:54 +00:00
|
|
|
struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r);
|
2016-10-28 15:04:43 -07:00
|
|
|
|
2025-05-15 16:58:54 +00:00
|
|
|
if (!r->cdp_capable)
|
|
|
|
return;
|
2017-07-25 14:14:38 -07:00
|
|
|
|
2025-05-15 16:58:54 +00:00
|
|
|
if (r->rid == RDT_RESOURCE_L2)
|
|
|
|
l2_qos_cfg_update(&hw_res->cdp_enabled);
|
2017-04-10 16:52:32 +02:00
|
|
|
|
2025-05-15 16:58:54 +00:00
|
|
|
if (r->rid == RDT_RESOURCE_L3)
|
|
|
|
l3_qos_cfg_update(&hw_res->cdp_enabled);
|
2017-04-10 16:52:32 +02:00
|
|
|
}
|
|
|
|
|
2025-05-15 16:58:54 +00:00
|
|
|
static int cdp_enable(int level)
|
2016-10-28 15:04:45 -07:00
|
|
|
{
|
2025-05-15 16:58:54 +00:00
|
|
|
struct rdt_resource *r_l = &rdt_resources_all[level].r_resctrl;
|
|
|
|
int ret;
|
2016-10-28 15:04:45 -07:00
|
|
|
|
2025-05-15 16:58:54 +00:00
|
|
|
if (!r_l->alloc_capable)
|
|
|
|
return -EINVAL;
|
2016-10-28 15:04:45 -07:00
|
|
|
|
2025-05-15 16:58:54 +00:00
|
|
|
ret = set_cache_qos_cfg(level, true);
|
|
|
|
if (!ret)
|
|
|
|
rdt_resources_all[level].cdp_enabled = true;
|
2016-10-28 15:04:45 -07:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2025-05-15 16:58:54 +00:00
|
|
|
static void cdp_disable(int level)
|
2016-11-11 17:02:38 -08:00
|
|
|
{
|
2025-05-15 16:58:54 +00:00
|
|
|
struct rdt_hw_resource *r_hw = &rdt_resources_all[level];
|
2025-03-11 18:36:55 +00:00
|
|
|
|
2025-05-15 16:58:54 +00:00
|
|
|
if (r_hw->cdp_enabled) {
|
|
|
|
set_cache_qos_cfg(level, false);
|
|
|
|
r_hw->cdp_enabled = false;
|
2025-03-11 18:36:55 +00:00
|
|
|
}
|
2016-11-11 17:02:38 -08:00
|
|
|
}
|
|
|
|
|
2025-05-15 16:58:54 +00:00
|
|
|
int resctrl_arch_set_cdp_enabled(enum resctrl_res_level l, bool enable)
|
2017-07-25 14:14:36 -07:00
|
|
|
{
|
2025-05-15 16:58:54 +00:00
|
|
|
struct rdt_hw_resource *hw_res = &rdt_resources_all[l];
|
2017-07-25 14:14:36 -07:00
|
|
|
|
2025-05-15 16:58:54 +00:00
|
|
|
if (!hw_res->r_resctrl.cdp_capable)
|
2017-07-25 14:14:36 -07:00
|
|
|
return -EINVAL;
|
|
|
|
|
2025-05-15 16:58:54 +00:00
|
|
|
if (enable)
|
|
|
|
return cdp_enable(l);
|
2017-07-25 14:14:36 -07:00
|
|
|
|
2025-05-15 16:58:54 +00:00
|
|
|
cdp_disable(l);
|
2017-07-25 14:14:36 -07:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2025-05-15 16:58:54 +00:00
|
|
|
bool resctrl_arch_get_cdp_enabled(enum resctrl_res_level l)
|
2017-07-25 14:14:36 -07:00
|
|
|
{
|
2025-05-15 16:58:54 +00:00
|
|
|
return rdt_resources_all[l].cdp_enabled;
|
2017-07-25 14:14:36 -07:00
|
|
|
}
|
|
|
|
|
2025-05-15 16:58:54 +00:00
|
|
|
void resctrl_arch_reset_all_ctrls(struct rdt_resource *r)
|
2017-07-25 14:14:35 -07:00
|
|
|
{
|
2025-05-15 16:58:54 +00:00
|
|
|
struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r);
|
|
|
|
struct rdt_hw_ctrl_domain *hw_dom;
|
|
|
|
struct msr_param msr_param;
|
|
|
|
struct rdt_ctrl_domain *d;
|
|
|
|
int i;
|
2017-07-25 14:14:35 -07:00
|
|
|
|
2025-05-15 16:58:54 +00:00
|
|
|
/* Walking r->domains, ensure it can't race with cpuhp */
|
|
|
|
lockdep_assert_cpus_held();
|
2017-07-25 14:14:35 -07:00
|
|
|
|
2025-05-15 16:58:54 +00:00
|
|
|
msr_param.res = r;
|
|
|
|
msr_param.low = 0;
|
|
|
|
msr_param.high = hw_res->num_closid;
|
2017-07-25 14:14:35 -07:00
|
|
|
|
|
|
|
/*
|
2025-05-15 16:58:54 +00:00
|
|
|
* Disable resource control for this resource by setting all
|
|
|
|
* CBMs in all ctrl_domains to the maximum mask value. Pick one CPU
|
|
|
|
* from each domain to update the MSRs below.
|
2017-07-25 14:14:35 -07:00
|
|
|
*/
|
2025-05-15 16:58:54 +00:00
|
|
|
list_for_each_entry(d, &r->ctrl_domains, hdr.list) {
|
|
|
|
hw_dom = resctrl_to_arch_ctrl_dom(d);
|
2017-07-25 14:14:35 -07:00
|
|
|
|
2025-05-15 16:58:54 +00:00
|
|
|
for (i = 0; i < hw_res->num_closid; i++)
|
|
|
|
hw_dom->ctrl_val[i] = resctrl_get_default_ctrl(r);
|
|
|
|
msr_param.dom = d;
|
|
|
|
smp_call_function_any(&d->hdr.cpu_mask, rdt_ctrl_update, &msr_param, 1);
|
2017-07-25 14:14:36 -07:00
|
|
|
}
|
|
|
|
|
2025-05-15 16:58:54 +00:00
|
|
|
return;
|
2018-06-22 15:42:24 -07:00
|
|
|
}
|