mirror of
https://github.com/torvalds/linux.git
synced 2026-05-12 16:18:45 +02:00
fs/resctrl: Add user interface to enable/disable io_alloc feature
AMD's SDCIAE forces all SDCI lines to be placed into the L3 cache portions identified by the highest-supported L3_MASK_n register, where n is the maximum supported CLOSID. To support this, when io_alloc resctrl feature is enabled, reserve the highest CLOSID exclusively for I/O allocation traffic making it no longer available for general CPU cache allocation. Introduce user interface to enable/disable io_alloc feature and encourage users to enable io_alloc only when running workloads that can benefit from this functionality. On enable, initialize the io_alloc CLOSID with all usable CBMs across all the domains. Since CLOSIDs are managed by resctrl fs, it is least invasive to make "io_alloc is supported by maximum supported CLOSID" part of the initial resctrl fs support for io_alloc. Take care to minimally (only in error messages) expose this use of CLOSID for io_alloc to user space so that this is not required from other architectures that may support io_alloc differently in the future. When resctrl is mounted with "-o cdp" to enable code/data prioritization, there are two L3 resources that can support I/O allocation: L3CODE and L3DATA. From resctrl fs perspective the two resources share a CLOSID and the architecture's available CLOSID are halved to support this. The architecture's underlying CLOSID used by SDCIAE when CDP is enabled is the CLOSID associated with the CDP_CODE resource, but from resctrl's perspective there is only one CLOSID for both CDP_CODE and CDP_DATA. CDP_DATA is thus not usable for general (CPU) cache allocation nor I/O allocation. Keep the CDP_CODE and CDP_DATA I/O alloc status in sync to avoid any confusion to user space. That is, enabling io_alloc on CDP_CODE does so on CDP_DATA and vice-versa, and keep the I/O allocation CBMs of CDP_CODE and CDP_DATA in sync. Signed-off-by: Babu Moger <babu.moger@amd.com> Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de> Reviewed-by: Reinette Chatre <reinette.chatre@intel.com> Link: https://patch.msgid.link/c7d3037795e653e22b02d8fc73ca80d9b075031c.1762995456.git.babu.moger@amd.com
This commit is contained in:
parent
48068e5650
commit
9445c7059c
|
|
@ -73,6 +73,11 @@ The 'info' directory contains information about the enabled
|
|||
resources. Each resource has its own subdirectory. The subdirectory
|
||||
names reflect the resource names.
|
||||
|
||||
Most of the files in the resource's subdirectory are read-only, and
|
||||
describe properties of the resource. Resources that support global
|
||||
configuration options also include writable files that can be used
|
||||
to modify those settings.
|
||||
|
||||
Each subdirectory contains the following files with respect to
|
||||
allocation:
|
||||
|
||||
|
|
@ -152,6 +157,31 @@ related to allocation:
|
|||
"not supported":
|
||||
Support not available for this resource.
|
||||
|
||||
The feature can be modified by writing to the interface, for example:
|
||||
|
||||
To enable::
|
||||
|
||||
# echo 1 > /sys/fs/resctrl/info/L3/io_alloc
|
||||
|
||||
To disable::
|
||||
|
||||
# echo 0 > /sys/fs/resctrl/info/L3/io_alloc
|
||||
|
||||
The underlying implementation may reduce resources available to
|
||||
general (CPU) cache allocation. See architecture specific notes
|
||||
below. Depending on usage requirements the feature can be enabled
|
||||
or disabled.
|
||||
|
||||
On AMD systems, io_alloc feature is supported by the L3 Smart
|
||||
Data Cache Injection Allocation Enforcement (SDCIAE). The CLOSID for
|
||||
io_alloc is the highest CLOSID supported by the resource. When
|
||||
io_alloc is enabled, the highest CLOSID is dedicated to io_alloc and
|
||||
no longer available for general (CPU) cache allocation. When CDP is
|
||||
enabled, io_alloc routes I/O traffic using the highest CLOSID allocated
|
||||
for the instruction cache (CDP_CODE), making this CLOSID no longer
|
||||
available for general (CPU) cache allocation for both the CDP_CODE
|
||||
and CDP_DATA resources.
|
||||
|
||||
Memory bandwidth(MB) subdirectory contains the following files
|
||||
with respect to allocation:
|
||||
|
||||
|
|
|
|||
|
|
@ -697,3 +697,129 @@ int resctrl_io_alloc_show(struct kernfs_open_file *of, struct seq_file *seq, voi
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* resctrl_io_alloc_closid_supported() - io_alloc feature utilizes the
|
||||
* highest CLOSID value to direct I/O traffic. Ensure that io_alloc_closid
|
||||
* is in the supported range.
|
||||
*/
|
||||
static bool resctrl_io_alloc_closid_supported(u32 io_alloc_closid)
|
||||
{
|
||||
return io_alloc_closid < closids_supported();
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize io_alloc CLOSID cache resource CBM with all usable (shared
|
||||
* and unused) cache portions.
|
||||
*/
|
||||
static int resctrl_io_alloc_init_cbm(struct resctrl_schema *s, u32 closid)
|
||||
{
|
||||
enum resctrl_conf_type peer_type;
|
||||
struct rdt_resource *r = s->res;
|
||||
struct rdt_ctrl_domain *d;
|
||||
int ret;
|
||||
|
||||
rdt_staged_configs_clear();
|
||||
|
||||
ret = rdtgroup_init_cat(s, closid);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
/* Keep CDP_CODE and CDP_DATA of io_alloc CLOSID's CBM in sync. */
|
||||
if (resctrl_arch_get_cdp_enabled(r->rid)) {
|
||||
peer_type = resctrl_peer_type(s->conf_type);
|
||||
list_for_each_entry(d, &s->res->ctrl_domains, hdr.list)
|
||||
memcpy(&d->staged_config[peer_type],
|
||||
&d->staged_config[s->conf_type],
|
||||
sizeof(d->staged_config[0]));
|
||||
}
|
||||
|
||||
ret = resctrl_arch_update_domains(r, closid);
|
||||
out:
|
||||
rdt_staged_configs_clear();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* resctrl_io_alloc_closid() - io_alloc feature routes I/O traffic using
|
||||
* the highest available CLOSID. Retrieve the maximum CLOSID supported by the
|
||||
* resource. Note that if Code Data Prioritization (CDP) is enabled, the number
|
||||
* of available CLOSIDs is reduced by half.
|
||||
*/
|
||||
static u32 resctrl_io_alloc_closid(struct rdt_resource *r)
|
||||
{
|
||||
if (resctrl_arch_get_cdp_enabled(r->rid))
|
||||
return resctrl_arch_get_num_closid(r) / 2 - 1;
|
||||
else
|
||||
return resctrl_arch_get_num_closid(r) - 1;
|
||||
}
|
||||
|
||||
ssize_t resctrl_io_alloc_write(struct kernfs_open_file *of, char *buf,
|
||||
size_t nbytes, loff_t off)
|
||||
{
|
||||
struct resctrl_schema *s = rdt_kn_parent_priv(of->kn);
|
||||
struct rdt_resource *r = s->res;
|
||||
char const *grp_name;
|
||||
u32 io_alloc_closid;
|
||||
bool enable;
|
||||
int ret;
|
||||
|
||||
ret = kstrtobool(buf, &enable);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
cpus_read_lock();
|
||||
mutex_lock(&rdtgroup_mutex);
|
||||
|
||||
rdt_last_cmd_clear();
|
||||
|
||||
if (!r->cache.io_alloc_capable) {
|
||||
rdt_last_cmd_printf("io_alloc is not supported on %s\n", s->name);
|
||||
ret = -ENODEV;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
/* If the feature is already up to date, no action is needed. */
|
||||
if (resctrl_arch_get_io_alloc_enabled(r) == enable)
|
||||
goto out_unlock;
|
||||
|
||||
io_alloc_closid = resctrl_io_alloc_closid(r);
|
||||
if (!resctrl_io_alloc_closid_supported(io_alloc_closid)) {
|
||||
rdt_last_cmd_printf("io_alloc CLOSID (ctrl_hw_id) %u is not available\n",
|
||||
io_alloc_closid);
|
||||
ret = -EINVAL;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (enable) {
|
||||
if (!closid_alloc_fixed(io_alloc_closid)) {
|
||||
grp_name = rdtgroup_name_by_closid(io_alloc_closid);
|
||||
WARN_ON_ONCE(!grp_name);
|
||||
rdt_last_cmd_printf("CLOSID (ctrl_hw_id) %u for io_alloc is used by %s group\n",
|
||||
io_alloc_closid, grp_name ? grp_name : "another");
|
||||
ret = -ENOSPC;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
ret = resctrl_io_alloc_init_cbm(s, io_alloc_closid);
|
||||
if (ret) {
|
||||
rdt_last_cmd_puts("Failed to initialize io_alloc allocations\n");
|
||||
closid_free(io_alloc_closid);
|
||||
goto out_unlock;
|
||||
}
|
||||
} else {
|
||||
closid_free(io_alloc_closid);
|
||||
}
|
||||
|
||||
ret = resctrl_arch_io_alloc_enable(r, enable);
|
||||
if (enable && ret) {
|
||||
rdt_last_cmd_puts("Failed to enable io_alloc feature\n");
|
||||
closid_free(io_alloc_closid);
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&rdtgroup_mutex);
|
||||
cpus_read_unlock();
|
||||
|
||||
return ret ?: nbytes;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -390,6 +390,8 @@ void rdt_staged_configs_clear(void);
|
|||
|
||||
bool closid_allocated(unsigned int closid);
|
||||
|
||||
bool closid_alloc_fixed(u32 closid);
|
||||
|
||||
int resctrl_find_cleanest_closid(void);
|
||||
|
||||
void *rdt_kn_parent_priv(struct kernfs_node *kn);
|
||||
|
|
@ -428,6 +430,15 @@ ssize_t mbm_L3_assignments_write(struct kernfs_open_file *of, char *buf, size_t
|
|||
loff_t off);
|
||||
int resctrl_io_alloc_show(struct kernfs_open_file *of, struct seq_file *seq, void *v);
|
||||
|
||||
int rdtgroup_init_cat(struct resctrl_schema *s, u32 closid);
|
||||
|
||||
enum resctrl_conf_type resctrl_peer_type(enum resctrl_conf_type my_type);
|
||||
|
||||
ssize_t resctrl_io_alloc_write(struct kernfs_open_file *of, char *buf,
|
||||
size_t nbytes, loff_t off);
|
||||
|
||||
const char *rdtgroup_name_by_closid(u32 closid);
|
||||
|
||||
#ifdef CONFIG_RESCTRL_FS_PSEUDO_LOCK
|
||||
int rdtgroup_locksetup_enter(struct rdtgroup *rdtgrp);
|
||||
|
||||
|
|
|
|||
|
|
@ -226,6 +226,11 @@ bool closid_allocated(unsigned int closid)
|
|||
return !test_bit(closid, closid_free_map);
|
||||
}
|
||||
|
||||
bool closid_alloc_fixed(u32 closid)
|
||||
{
|
||||
return __test_and_clear_bit(closid, closid_free_map);
|
||||
}
|
||||
|
||||
/**
|
||||
* rdtgroup_mode_by_closid - Return mode of resource group with closid
|
||||
* @closid: closid if the resource group
|
||||
|
|
@ -1247,7 +1252,7 @@ static int rdtgroup_mode_show(struct kernfs_open_file *of,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static enum resctrl_conf_type resctrl_peer_type(enum resctrl_conf_type my_type)
|
||||
enum resctrl_conf_type resctrl_peer_type(enum resctrl_conf_type my_type)
|
||||
{
|
||||
switch (my_type) {
|
||||
case CDP_CODE:
|
||||
|
|
@ -1838,6 +1843,18 @@ void resctrl_bmec_files_show(struct rdt_resource *r, struct kernfs_node *l3_mon_
|
|||
kernfs_put(mon_kn);
|
||||
}
|
||||
|
||||
const char *rdtgroup_name_by_closid(u32 closid)
|
||||
{
|
||||
struct rdtgroup *rdtgrp;
|
||||
|
||||
list_for_each_entry(rdtgrp, &rdt_all_groups, rdtgroup_list) {
|
||||
if (rdtgrp->closid == closid)
|
||||
return rdt_kn_name(rdtgrp->kn);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* rdtgroup information files for one cache resource. */
|
||||
static struct rftype res_common_files[] = {
|
||||
{
|
||||
|
|
@ -1949,9 +1966,10 @@ static struct rftype res_common_files[] = {
|
|||
},
|
||||
{
|
||||
.name = "io_alloc",
|
||||
.mode = 0444,
|
||||
.mode = 0644,
|
||||
.kf_ops = &rdtgroup_kf_single_ops,
|
||||
.seq_show = resctrl_io_alloc_show,
|
||||
.write = resctrl_io_alloc_write,
|
||||
},
|
||||
{
|
||||
.name = "max_threshold_occupancy",
|
||||
|
|
@ -3501,7 +3519,7 @@ static int __init_one_rdt_domain(struct rdt_ctrl_domain *d, struct resctrl_schem
|
|||
* If there are no more shareable bits available on any domain then
|
||||
* the entire allocation will fail.
|
||||
*/
|
||||
static int rdtgroup_init_cat(struct resctrl_schema *s, u32 closid)
|
||||
int rdtgroup_init_cat(struct resctrl_schema *s, u32 closid)
|
||||
{
|
||||
struct rdt_ctrl_domain *d;
|
||||
int ret;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user