diff --git a/arch/x86/include/asm/resctrl.h b/arch/x86/include/asm/resctrl.h index 2ee668162429f3bbfcd7fa9ac5587f949f7ba425..f695e6e98233114bb463ce0b8de6c17862bc9647 100644 --- a/arch/x86/include/asm/resctrl.h +++ b/arch/x86/include/asm/resctrl.h @@ -223,6 +223,9 @@ void resctrl_cpu_detect(struct cpuinfo_x86 *c); bool resctrl_arch_get_cdp_enabled(enum resctrl_res_level l); int resctrl_arch_set_cdp_enabled(enum resctrl_res_level l, bool enable); +bool resctrl_arch_is_hwdrc_mb_capable(void); +int resctrl_arch_set_hwdrc_enabled(enum resctrl_res_level l, bool hwdrc_mb); + #else static inline void resctrl_sched_in(void) {} diff --git a/arch/x86/kernel/cpu/resctrl/internal.h b/arch/x86/kernel/cpu/resctrl/internal.h index fd781d576cd4409165d957417d3f65f13ab6c2ba..1d15d8c0a9bdc2ef3696b0adf540b8a4d762dcaa 100644 --- a/arch/x86/kernel/cpu/resctrl/internal.h +++ b/arch/x86/kernel/cpu/resctrl/internal.h @@ -11,6 +11,17 @@ #include #include +#include + +/* Memory bandwidth HWDRC */ +#define HWDRC_MSR_OS_MAILBOX_INTERFACE 0xb0 +#define HWDRC_MSR_OS_MAILBOX_DATA 0xb1 +#define HWDRC_MSR_OS_MAILBOX_BUSY_BIT BIT_ULL(31) +#define HWDRC_COMMAND_MEM_CLOS_EN 0xd0 +#define HWDRC_SUB_COMMAND_MEM_CLOS_EN 0x54 +#define HWDRC_MEMCLOS_AVAILABLE BIT_ULL(0) +#define HWDRC_OS_MAILBOX_RETRY_COUNT 30 + #define MSR_IA32_L3_QOS_CFG 0xc81 #define MSR_IA32_L2_QOS_CFG 0xc82 #define MSR_IA32_L3_CBM_BASE 0xc90 @@ -30,6 +41,7 @@ #define RMID_VAL_ERROR BIT_ULL(63) #define RMID_VAL_UNAVAIL BIT_ULL(62) + /* * With the above fields in use 62 bits remain in MSR_IA32_QM_CTR for * data to be returned. The counter width is discovered from the hardware @@ -94,6 +106,84 @@ static inline bool is_mbm_event(int e) e <= QOS_L3_MBM_LOCAL_EVENT_ID); } +/* + * Workaround to detect if memory bandwidth HWDRC feature is capable. + * + * CPUID for memory bandwidth HWDRC feature is not exposed by H/W. + * Check presence of HWDRC OS mailbox MSRs. Read out the discovery bit of + * HWDRC OS mailbox data which indicates if the feature is capable. + */ +static inline bool is_hwdrc_mb_capable(void) +{ + u32 retries; + u64 data; + int status; + + /* Only enable memory bandwidth HWDRC on ICELAKE server */ + if (boot_cpu_data.x86_model != INTEL_FAM6_ICELAKE_X) { + pr_debug("HWDRC: Not on ICELAKE server\n"); + goto out; + } + + /* Check presence of mailbox MSRs */ + if (rdmsrl_safe(HWDRC_MSR_OS_MAILBOX_INTERFACE, &data)) { + pr_debug("HWDRC: Can't access OS mailbox interface MSR\n"); + goto out; + } + + if (rdmsrl_safe(HWDRC_MSR_OS_MAILBOX_DATA, &data)) { + pr_debug("HWDRC: Can't access OS mailbox data MSR\n"); + goto out; + } + + /* Poll for run_busy bit == 0 */ + status = -EBUSY; + retries = HWDRC_OS_MAILBOX_RETRY_COUNT; + do { + rdmsrl(HWDRC_MSR_OS_MAILBOX_INTERFACE, data); + if (!(data & HWDRC_MSR_OS_MAILBOX_BUSY_BIT)) { + status = 0; + break; + } + } while (--retries); + + if (status) + goto out; + + /* Write command register: 0x800054d0 */ + data = HWDRC_MSR_OS_MAILBOX_BUSY_BIT | + HWDRC_SUB_COMMAND_MEM_CLOS_EN << 8 | + HWDRC_COMMAND_MEM_CLOS_EN; + pr_debug("HWDRC: Write command register: 0x%llx\n", data); + if (wrmsrl_safe(HWDRC_MSR_OS_MAILBOX_INTERFACE, data)) { + pr_debug("HWDRC: Write command register 0x%llx failed!\n", data); + goto out; + } + + /* Poll for run_busy bit == 0 */ + retries = HWDRC_OS_MAILBOX_RETRY_COUNT; + do { + rdmsrl(HWDRC_MSR_OS_MAILBOX_INTERFACE, data); + if (!(data & HWDRC_MSR_OS_MAILBOX_BUSY_BIT)) { + rdmsrl(HWDRC_MSR_OS_MAILBOX_DATA, data); + pr_debug("HWDRC: Read MEM_CLOS_EN data: 0x%llx\n", data); + + /* Feature capability bit is set */ + if (data & HWDRC_MEMCLOS_AVAILABLE) { + pr_debug("HWDRC: Memory bandwidth HWDRC is capable\n"); + return true; + } + + /* Feature capability bit is not set */ + break; + } + } while (--retries); + +out: + pr_debug("HWDRC: Memory bandwidth HWDRC is not capable\n"); + return false; +} + /** * struct rdt_hw_resource - arch private attributes of a resctrl resource * @r_resctrl: Attributes of the resource used directly by resctrl. diff --git a/arch/x86/kernel/cpu/resctrl/rdtgroup.c b/arch/x86/kernel/cpu/resctrl/rdtgroup.c index b49e99cd5ce74baf226cb739eaf96ca1e24cbbe6..d802b4ad0ded647c8dbd709ab409d3873ee2e33e 100644 --- a/arch/x86/kernel/cpu/resctrl/rdtgroup.c +++ b/arch/x86/kernel/cpu/resctrl/rdtgroup.c @@ -170,6 +170,57 @@ int resctrl_arch_set_cdp_enabled(enum resctrl_res_level l, bool enable) return 0; } +bool resctrl_arch_is_hwdrc_mb_capable(void) +{ + return is_hwdrc_mb_capable(); +} + +static void mba_enable(enum resctrl_res_level l) +{ + struct rdt_hw_resource *r_hw = &rdt_resources_all[l]; + struct rdt_resource *r = &r_hw->r_resctrl; + + r->alloc_capable = true; +} + +static void mba_disable(enum resctrl_res_level l) +{ + struct rdt_hw_resource *r_hw = &rdt_resources_all[l]; + struct rdt_resource *r = &r_hw->r_resctrl; + + r->alloc_capable = false; +} + +/* + * Currently memory bandwidth HWDRC feature is enabled or disabled by the user + * outside of the scope of the resctrl filesystem. When memory bandwidth HWDRC + * is enabled, it takes over MBA hooks in resctrl for memory bandwidth + * throttling. + * + * Set memory bandwidth HWDRC enabled in resctrl so that the user who enables + * memory bandwidth HWDRC can make sure that resctrl doesn't provide any hooks + * to control MBA. + * + * Set memory bandwidth HWDRC disabled in resctrl, MBA is enabled by default. + */ +int resctrl_arch_set_hwdrc_enabled(enum resctrl_res_level l, bool hwdrc_mb) +{ + struct rdt_resource *r = &rdt_resources_all[l].r_resctrl; + + if (!is_hwdrc_mb_capable() || hwdrc_mb == r->membw.hwdrc_mb) + return -EINVAL; + + /* MBA and memory bandwidth HWDRC features are mutually exclusive */ + if (hwdrc_mb) + mba_disable(l); + else + mba_enable(l); + + r->membw.hwdrc_mb = hwdrc_mb; + + return 0; +} + static int reset_all_ctrls(struct rdt_resource *r) { struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r); diff --git a/fs/resctrl/internal.h b/fs/resctrl/internal.h index f36e6d59a83264c3e675ee0bb8e99beeb44d414a..4b6d0fe9fbdb7d7561c77fdb17020865ac770e3f 100644 --- a/fs/resctrl/internal.h +++ b/fs/resctrl/internal.h @@ -15,6 +15,7 @@ struct rdt_fs_context { bool enable_cdpl2; bool enable_cdpl3; bool enable_mba_mbps; + bool enable_hwdrc_mb; }; static inline struct rdt_fs_context *rdt_fc2context(struct fs_context *fc) @@ -32,6 +33,14 @@ static inline bool is_mba_sc(struct rdt_resource *r) return r->membw.mba_sc; } +static inline bool is_hwdrc_enabled(struct rdt_resource *r) +{ + if (!r) + r = resctrl_arch_get_resource(RDT_RESOURCE_MBA); + + return r->membw.hwdrc_mb; +} + /** * struct mon_evt - Entry in the event list of a resource * @evtid: event id diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c index 5ac1f39f37e2bb4b3e036ed27beacb88594163f5..e02a258d3b4d9f51e407708e0473b77e01bfb2a0 100644 --- a/fs/resctrl/rdtgroup.c +++ b/fs/resctrl/rdtgroup.c @@ -1518,6 +1518,50 @@ static int rdtgroup_id_show(struct kernfs_open_file *of, return ret; } +/* + * rdtgroup_closid_show - Display closid of this resource group + */ +static int rdtgroup_closid_show(struct kernfs_open_file *of, + struct seq_file *s, void *v) +{ + struct rdtgroup *rdtgrp; + + rdtgrp = rdtgroup_kn_lock_live(of->kn); + if (!rdtgrp) { + rdtgroup_kn_unlock(of->kn); + return -ENOENT; + } + + if (rdtgrp->type == RDTCTRL_GROUP) + seq_printf(s, "%u\n", rdtgrp->closid); + else if (rdtgrp->type == RDTMON_GROUP) + seq_printf(s, "%u\n", rdtgrp->mon.parent->closid); + + rdtgroup_kn_unlock(of->kn); + return 0; +} + +/* + * rdtgroup_rmid_show - Display rmid of this resource group + */ +static int rdtgroup_rmid_show(struct kernfs_open_file *of, + struct seq_file *s, void *v) +{ + struct rdtgroup *rdtgrp; + + rdtgrp = rdtgroup_kn_lock_live(of->kn); + if (!rdtgrp) { + rdtgroup_kn_unlock(of->kn); + return -ENOENT; + } + + seq_printf(s, "%u\n", rdtgrp->mon.rmid); + + rdtgroup_kn_unlock(of->kn); + return 0; +} + + /* rdtgroup information files for one cache resource. */ static struct rftype res_common_files[] = { { @@ -1671,6 +1715,20 @@ static struct rftype res_common_files[] = { .seq_show = rdtgroup_id_show, .fflags = RFTYPE_BASE, }, + { + .name = "closid", + .mode = 0444, + .kf_ops = &rdtgroup_kf_single_ops, + .seq_show = rdtgroup_closid_show, + .fflags = RFTYPE_BASE, + }, + { + .name = "rmid", + .mode = 0444, + .kf_ops = &rdtgroup_kf_single_ops, + .seq_show = rdtgroup_rmid_show, + .fflags = RFTYPE_BASE, + }, }; static int rdtgroup_add_files(struct kernfs_node *kn, unsigned long fflags) @@ -2118,9 +2176,23 @@ static int rdt_enable_ctx(struct rdt_fs_context *ctx) if (!ret && ctx->enable_cdpl3) ret = resctrl_arch_set_cdp_enabled(RDT_RESOURCE_L3, true); + /* + * MBA and memory bandwidth HWDRC features are mutually exclusive. + * So mba_MBps and hwdrc_mb options could not be set at the same time. + */ + if (ctx->enable_hwdrc_mb && ctx->enable_mba_mbps) { + pr_debug("Option 'mba_MBps' and 'hwdrc_mb' are mutually exclusive\n"); + ret = -EINVAL; + goto out; + } + + if (!ret && ctx->enable_hwdrc_mb) + ret = resctrl_arch_set_hwdrc_enabled(RDT_RESOURCE_MBA, true); + if (!ret && ctx->enable_mba_mbps) ret = set_mba_sc(true); +out: return ret; } @@ -2330,6 +2402,7 @@ enum rdt_param { Opt_cdp, Opt_cdpl2, Opt_mba_mbps, + Opt_hwdrc_mb, nr__rdt_params }; @@ -2337,6 +2410,7 @@ static const struct fs_parameter_spec rdt_fs_parameters[] = { fsparam_flag("cdp", Opt_cdp), fsparam_flag("cdpl2", Opt_cdpl2), fsparam_flag("mba_MBps", Opt_mba_mbps), + fsparam_flag("hwdrc_mb", Opt_hwdrc_mb), {} }; @@ -2362,6 +2436,11 @@ static int rdt_parse_param(struct fs_context *fc, struct fs_parameter *param) return -EINVAL; ctx->enable_mba_mbps = true; return 0; + case Opt_hwdrc_mb: + if (!resctrl_arch_is_hwdrc_mb_capable()) + return -EINVAL; + ctx->enable_hwdrc_mb = true; + return 0; } return -EINVAL; @@ -2504,6 +2583,7 @@ static void rdt_kill_sb(struct super_block *sb) mutex_lock(&rdtgroup_mutex); set_mba_sc(false); + resctrl_arch_set_hwdrc_enabled(RDT_RESOURCE_MBA, false); /* Put everything back to default values. */ resctrl_arch_reset_resources(); @@ -3304,6 +3384,9 @@ static int rdtgroup_show_options(struct seq_file *seq, struct kernfs_root *kf) if (is_mba_sc(resctrl_arch_get_resource(RDT_RESOURCE_MBA))) seq_puts(seq, ",mba_MBps"); + if (is_hwdrc_enabled(resctrl_arch_get_resource(RDT_RESOURCE_MBA))) + seq_puts(seq, ",hwdrc_mb"); + return 0; } diff --git a/include/linux/arm_mpam.h b/include/linux/arm_mpam.h index 62f75d8a0b546ce4ae2481f2e4608bf836238c6b..2d2e5ff9f5e044a81d10b3be6a19db0f444d38f1 100644 --- a/include/linux/arm_mpam.h +++ b/include/linux/arm_mpam.h @@ -71,6 +71,16 @@ static inline bool resctrl_arch_is_mbm_total_enabled(void) return false; } +static inline bool resctrl_arch_is_hwdrc_mb_capable(void) +{ + return false; +} + +static inline int resctrl_arch_set_hwdrc_enabled(enum resctrl_res_level ignored, bool hwdrc_mb) +{ + return hwdrc_mb ? -EINVAL : 0; +} + /* reset cached configurations, then all devices */ void resctrl_arch_reset_resources(void); diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h index 0f31f29c569523daadadaae914e57dd4a6cd8042..dccd414ea2884e98f8223c4262224faf570cbea9 100644 --- a/include/linux/resctrl.h +++ b/include/linux/resctrl.h @@ -176,6 +176,7 @@ enum membw_throttle_mode { * @throttle_mode: Bandwidth throttling mode when threads request * different memory bandwidths * @mba_sc: True if MBA software controller(mba_sc) is enabled + * @hwdrc_mb: True if memory bandwidth HWDRC is enabled * @mb_map: Mapping of memory B/W percentage to memory B/W delay */ struct resctrl_membw { @@ -185,6 +186,7 @@ struct resctrl_membw { bool arch_needs_linear; enum membw_throttle_mode throttle_mode; bool mba_sc; + bool hwdrc_mb; u32 *mb_map; };