Skip to content

Commit 9445c70

Browse files
babumogerbp3tk0v
authored andcommitted
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
1 parent 48068e5 commit 9445c70

4 files changed

Lines changed: 188 additions & 3 deletions

File tree

Documentation/filesystems/resctrl.rst

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ The 'info' directory contains information about the enabled
7373
resources. Each resource has its own subdirectory. The subdirectory
7474
names reflect the resource names.
7575

76+
Most of the files in the resource's subdirectory are read-only, and
77+
describe properties of the resource. Resources that support global
78+
configuration options also include writable files that can be used
79+
to modify those settings.
80+
7681
Each subdirectory contains the following files with respect to
7782
allocation:
7883

@@ -152,6 +157,31 @@ related to allocation:
152157
"not supported":
153158
Support not available for this resource.
154159

160+
The feature can be modified by writing to the interface, for example:
161+
162+
To enable::
163+
164+
# echo 1 > /sys/fs/resctrl/info/L3/io_alloc
165+
166+
To disable::
167+
168+
# echo 0 > /sys/fs/resctrl/info/L3/io_alloc
169+
170+
The underlying implementation may reduce resources available to
171+
general (CPU) cache allocation. See architecture specific notes
172+
below. Depending on usage requirements the feature can be enabled
173+
or disabled.
174+
175+
On AMD systems, io_alloc feature is supported by the L3 Smart
176+
Data Cache Injection Allocation Enforcement (SDCIAE). The CLOSID for
177+
io_alloc is the highest CLOSID supported by the resource. When
178+
io_alloc is enabled, the highest CLOSID is dedicated to io_alloc and
179+
no longer available for general (CPU) cache allocation. When CDP is
180+
enabled, io_alloc routes I/O traffic using the highest CLOSID allocated
181+
for the instruction cache (CDP_CODE), making this CLOSID no longer
182+
available for general (CPU) cache allocation for both the CDP_CODE
183+
and CDP_DATA resources.
184+
155185
Memory bandwidth(MB) subdirectory contains the following files
156186
with respect to allocation:
157187

fs/resctrl/ctrlmondata.c

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -697,3 +697,129 @@ int resctrl_io_alloc_show(struct kernfs_open_file *of, struct seq_file *seq, voi
697697

698698
return 0;
699699
}
700+
701+
/*
702+
* resctrl_io_alloc_closid_supported() - io_alloc feature utilizes the
703+
* highest CLOSID value to direct I/O traffic. Ensure that io_alloc_closid
704+
* is in the supported range.
705+
*/
706+
static bool resctrl_io_alloc_closid_supported(u32 io_alloc_closid)
707+
{
708+
return io_alloc_closid < closids_supported();
709+
}
710+
711+
/*
712+
* Initialize io_alloc CLOSID cache resource CBM with all usable (shared
713+
* and unused) cache portions.
714+
*/
715+
static int resctrl_io_alloc_init_cbm(struct resctrl_schema *s, u32 closid)
716+
{
717+
enum resctrl_conf_type peer_type;
718+
struct rdt_resource *r = s->res;
719+
struct rdt_ctrl_domain *d;
720+
int ret;
721+
722+
rdt_staged_configs_clear();
723+
724+
ret = rdtgroup_init_cat(s, closid);
725+
if (ret < 0)
726+
goto out;
727+
728+
/* Keep CDP_CODE and CDP_DATA of io_alloc CLOSID's CBM in sync. */
729+
if (resctrl_arch_get_cdp_enabled(r->rid)) {
730+
peer_type = resctrl_peer_type(s->conf_type);
731+
list_for_each_entry(d, &s->res->ctrl_domains, hdr.list)
732+
memcpy(&d->staged_config[peer_type],
733+
&d->staged_config[s->conf_type],
734+
sizeof(d->staged_config[0]));
735+
}
736+
737+
ret = resctrl_arch_update_domains(r, closid);
738+
out:
739+
rdt_staged_configs_clear();
740+
return ret;
741+
}
742+
743+
/*
744+
* resctrl_io_alloc_closid() - io_alloc feature routes I/O traffic using
745+
* the highest available CLOSID. Retrieve the maximum CLOSID supported by the
746+
* resource. Note that if Code Data Prioritization (CDP) is enabled, the number
747+
* of available CLOSIDs is reduced by half.
748+
*/
749+
static u32 resctrl_io_alloc_closid(struct rdt_resource *r)
750+
{
751+
if (resctrl_arch_get_cdp_enabled(r->rid))
752+
return resctrl_arch_get_num_closid(r) / 2 - 1;
753+
else
754+
return resctrl_arch_get_num_closid(r) - 1;
755+
}
756+
757+
ssize_t resctrl_io_alloc_write(struct kernfs_open_file *of, char *buf,
758+
size_t nbytes, loff_t off)
759+
{
760+
struct resctrl_schema *s = rdt_kn_parent_priv(of->kn);
761+
struct rdt_resource *r = s->res;
762+
char const *grp_name;
763+
u32 io_alloc_closid;
764+
bool enable;
765+
int ret;
766+
767+
ret = kstrtobool(buf, &enable);
768+
if (ret)
769+
return ret;
770+
771+
cpus_read_lock();
772+
mutex_lock(&rdtgroup_mutex);
773+
774+
rdt_last_cmd_clear();
775+
776+
if (!r->cache.io_alloc_capable) {
777+
rdt_last_cmd_printf("io_alloc is not supported on %s\n", s->name);
778+
ret = -ENODEV;
779+
goto out_unlock;
780+
}
781+
782+
/* If the feature is already up to date, no action is needed. */
783+
if (resctrl_arch_get_io_alloc_enabled(r) == enable)
784+
goto out_unlock;
785+
786+
io_alloc_closid = resctrl_io_alloc_closid(r);
787+
if (!resctrl_io_alloc_closid_supported(io_alloc_closid)) {
788+
rdt_last_cmd_printf("io_alloc CLOSID (ctrl_hw_id) %u is not available\n",
789+
io_alloc_closid);
790+
ret = -EINVAL;
791+
goto out_unlock;
792+
}
793+
794+
if (enable) {
795+
if (!closid_alloc_fixed(io_alloc_closid)) {
796+
grp_name = rdtgroup_name_by_closid(io_alloc_closid);
797+
WARN_ON_ONCE(!grp_name);
798+
rdt_last_cmd_printf("CLOSID (ctrl_hw_id) %u for io_alloc is used by %s group\n",
799+
io_alloc_closid, grp_name ? grp_name : "another");
800+
ret = -ENOSPC;
801+
goto out_unlock;
802+
}
803+
804+
ret = resctrl_io_alloc_init_cbm(s, io_alloc_closid);
805+
if (ret) {
806+
rdt_last_cmd_puts("Failed to initialize io_alloc allocations\n");
807+
closid_free(io_alloc_closid);
808+
goto out_unlock;
809+
}
810+
} else {
811+
closid_free(io_alloc_closid);
812+
}
813+
814+
ret = resctrl_arch_io_alloc_enable(r, enable);
815+
if (enable && ret) {
816+
rdt_last_cmd_puts("Failed to enable io_alloc feature\n");
817+
closid_free(io_alloc_closid);
818+
}
819+
820+
out_unlock:
821+
mutex_unlock(&rdtgroup_mutex);
822+
cpus_read_unlock();
823+
824+
return ret ?: nbytes;
825+
}

fs/resctrl/internal.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,8 @@ void rdt_staged_configs_clear(void);
390390

391391
bool closid_allocated(unsigned int closid);
392392

393+
bool closid_alloc_fixed(u32 closid);
394+
393395
int resctrl_find_cleanest_closid(void);
394396

395397
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
428430
loff_t off);
429431
int resctrl_io_alloc_show(struct kernfs_open_file *of, struct seq_file *seq, void *v);
430432

433+
int rdtgroup_init_cat(struct resctrl_schema *s, u32 closid);
434+
435+
enum resctrl_conf_type resctrl_peer_type(enum resctrl_conf_type my_type);
436+
437+
ssize_t resctrl_io_alloc_write(struct kernfs_open_file *of, char *buf,
438+
size_t nbytes, loff_t off);
439+
440+
const char *rdtgroup_name_by_closid(u32 closid);
441+
431442
#ifdef CONFIG_RESCTRL_FS_PSEUDO_LOCK
432443
int rdtgroup_locksetup_enter(struct rdtgroup *rdtgrp);
433444

fs/resctrl/rdtgroup.c

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,11 @@ bool closid_allocated(unsigned int closid)
226226
return !test_bit(closid, closid_free_map);
227227
}
228228

229+
bool closid_alloc_fixed(u32 closid)
230+
{
231+
return __test_and_clear_bit(closid, closid_free_map);
232+
}
233+
229234
/**
230235
* rdtgroup_mode_by_closid - Return mode of resource group with closid
231236
* @closid: closid if the resource group
@@ -1247,7 +1252,7 @@ static int rdtgroup_mode_show(struct kernfs_open_file *of,
12471252
return 0;
12481253
}
12491254

1250-
static enum resctrl_conf_type resctrl_peer_type(enum resctrl_conf_type my_type)
1255+
enum resctrl_conf_type resctrl_peer_type(enum resctrl_conf_type my_type)
12511256
{
12521257
switch (my_type) {
12531258
case CDP_CODE:
@@ -1838,6 +1843,18 @@ void resctrl_bmec_files_show(struct rdt_resource *r, struct kernfs_node *l3_mon_
18381843
kernfs_put(mon_kn);
18391844
}
18401845

1846+
const char *rdtgroup_name_by_closid(u32 closid)
1847+
{
1848+
struct rdtgroup *rdtgrp;
1849+
1850+
list_for_each_entry(rdtgrp, &rdt_all_groups, rdtgroup_list) {
1851+
if (rdtgrp->closid == closid)
1852+
return rdt_kn_name(rdtgrp->kn);
1853+
}
1854+
1855+
return NULL;
1856+
}
1857+
18411858
/* rdtgroup information files for one cache resource. */
18421859
static struct rftype res_common_files[] = {
18431860
{
@@ -1949,9 +1966,10 @@ static struct rftype res_common_files[] = {
19491966
},
19501967
{
19511968
.name = "io_alloc",
1952-
.mode = 0444,
1969+
.mode = 0644,
19531970
.kf_ops = &rdtgroup_kf_single_ops,
19541971
.seq_show = resctrl_io_alloc_show,
1972+
.write = resctrl_io_alloc_write,
19551973
},
19561974
{
19571975
.name = "max_threshold_occupancy",
@@ -3501,7 +3519,7 @@ static int __init_one_rdt_domain(struct rdt_ctrl_domain *d, struct resctrl_schem
35013519
* If there are no more shareable bits available on any domain then
35023520
* the entire allocation will fail.
35033521
*/
3504-
static int rdtgroup_init_cat(struct resctrl_schema *s, u32 closid)
3522+
int rdtgroup_init_cat(struct resctrl_schema *s, u32 closid)
35053523
{
35063524
struct rdt_ctrl_domain *d;
35073525
int ret;

0 commit comments

Comments
 (0)