diff --git a/arch/x86/kernel/cpu/intel_rdt.c b/arch/x86/kernel/cpu/intel_rdt.c index 4c17a7060dfd..de26aa7971d4 100644 --- a/arch/x86/kernel/cpu/intel_rdt.c +++ b/arch/x86/kernel/cpu/intel_rdt.c @@ -348,12 +348,10 @@ void rdt_ctrl_update(void *arg) int 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)) { - r->msr_update(d, m, r); - return; - } + d = get_domain_from_cpu(cpu, r); + if (d) { + r->msr_update(d, m, r); + return; } pr_warn_once("cpu %d not found in any domain for resource %s\n", cpu, r->name); @@ -447,6 +445,11 @@ static int domain_setup_mon_state(struct rdt_resource *r, struct rdt_domain *d) } } + if (is_mbm_enabled()) { + INIT_DELAYED_WORK(&d->mbm_over, mbm_handle_overflow); + mbm_setup_overflow_handler(d); + } + return 0; } @@ -531,7 +534,13 @@ static void domain_remove_cpu(int cpu, struct rdt_resource *r) kfree(d->mbm_total); kfree(d->mbm_local); list_del(&d->list); + if (is_mbm_enabled()) + cancel_delayed_work(&d->mbm_over); kfree(d); + } else if (r == &rdt_resources_all[RDT_RESOURCE_L3] && + cpu == d->mbm_work_cpu && is_mbm_enabled()) { + cancel_delayed_work(&d->mbm_over); + mbm_setup_overflow_handler(d); } } diff --git a/arch/x86/kernel/cpu/intel_rdt.h b/arch/x86/kernel/cpu/intel_rdt.h index f160403324d3..94e488af082e 100644 --- a/arch/x86/kernel/cpu/intel_rdt.h +++ b/arch/x86/kernel/cpu/intel_rdt.h @@ -21,10 +21,13 @@ #define QOS_L3_MBM_LOCAL_EVENT_ID 0x03 #define MBM_CNTR_WIDTH 24 +#define MBM_OVERFLOW_INTERVAL 1000 #define RMID_VAL_ERROR BIT_ULL(63) #define RMID_VAL_UNAVAIL BIT_ULL(62) +DECLARE_STATIC_KEY_FALSE(rdt_enable_key); + /** * struct mon_evt - Entry in the event list of a resource * @evtid: event id @@ -183,6 +186,9 @@ struct mbm_state { * bitmap of which limbo RMIDs are above threshold * @mbm_total: saved state for MBM total bandwidth * @mbm_local: saved state for MBM local bandwidth + * @mbm_over: worker to periodically read MBM h/w counters + * @mbm_work_cpu: + * worker cpu for MBM h/w counters * @ctrl_val: array of cache or mem ctrl values (indexed by CLOSID) * @new_ctrl: new ctrl value to be loaded * @have_new_ctrl: did user provide new_ctrl for this domain @@ -194,6 +200,8 @@ struct rdt_domain { unsigned long *rmid_busy_llc; struct mbm_state *mbm_total; struct mbm_state *mbm_local; + struct delayed_work mbm_over; + int mbm_work_cpu; u32 *ctrl_val; u32 new_ctrl; bool have_new_ctrl; @@ -411,5 +419,7 @@ void mkdir_mondata_subdir_allrdtgrp(struct rdt_resource *r, struct rdt_domain *d); void mon_event_read(struct rmid_read *rr, struct rdt_domain *d, struct rdtgroup *rdtgrp, int evtid, int first); +void mbm_setup_overflow_handler(struct rdt_domain *dom); +void mbm_handle_overflow(struct work_struct *work); #endif /* _ASM_X86_INTEL_RDT_H */ diff --git a/arch/x86/kernel/cpu/intel_rdt_monitor.c b/arch/x86/kernel/cpu/intel_rdt_monitor.c index 383a023fca35..d6bfdfd22abe 100644 --- a/arch/x86/kernel/cpu/intel_rdt_monitor.c +++ b/arch/x86/kernel/cpu/intel_rdt_monitor.c @@ -366,6 +366,69 @@ void mon_event_count(void *info) } } +static void mbm_update(struct rdt_domain *d, int rmid) +{ + struct rmid_read rr; + + rr.first = false; + rr.d = d; + + /* + * This is protected from concurrent reads from user + * as both the user and we hold the global mutex. + */ + if (is_mbm_total_enabled()) { + rr.evtid = QOS_L3_MBM_TOTAL_EVENT_ID; + __mon_event_count(rmid, &rr); + } + if (is_mbm_local_enabled()) { + rr.evtid = QOS_L3_MBM_LOCAL_EVENT_ID; + __mon_event_count(rmid, &rr); + } +} + +void mbm_handle_overflow(struct work_struct *work) +{ + unsigned long delay = msecs_to_jiffies(MBM_OVERFLOW_INTERVAL); + struct rdtgroup *prgrp, *crgrp; + int cpu = smp_processor_id(); + struct list_head *head; + struct rdt_domain *d; + + mutex_lock(&rdtgroup_mutex); + + if (!static_branch_likely(&rdt_enable_key)) + goto out_unlock; + + d = get_domain_from_cpu(cpu, &rdt_resources_all[RDT_RESOURCE_L3]); + if (!d) + goto out_unlock; + + list_for_each_entry(prgrp, &rdt_all_groups, rdtgroup_list) { + mbm_update(d, prgrp->mon.rmid); + + head = &prgrp->mon.crdtgrp_list; + list_for_each_entry(crgrp, head, mon.crdtgrp_list) + mbm_update(d, crgrp->mon.rmid); + } + + schedule_delayed_work_on(cpu, &d->mbm_over, delay); +out_unlock: + mutex_unlock(&rdtgroup_mutex); +} + +void mbm_setup_overflow_handler(struct rdt_domain *dom) +{ + unsigned long delay = msecs_to_jiffies(MBM_OVERFLOW_INTERVAL); + int cpu; + + if (!static_branch_likely(&rdt_enable_key)) + return; + cpu = cpumask_any(&dom->cpu_mask); + dom->mbm_work_cpu = cpu; + schedule_delayed_work_on(cpu, &dom->mbm_over, delay); +} + static int dom_data_init(struct rdt_resource *r) { struct rmid_entry *entry = NULL; diff --git a/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c b/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c index 05088e301ef8..c24dd067b9c5 100644 --- a/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c +++ b/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c @@ -1060,6 +1060,8 @@ static struct dentry *rdt_mount(struct file_system_type *fs_type, int flags, const char *unused_dev_name, void *data) { + struct rdt_domain *dom; + struct rdt_resource *r; struct dentry *dentry; int ret; @@ -1118,6 +1120,13 @@ static struct dentry *rdt_mount(struct file_system_type *fs_type, if (rdt_alloc_capable || rdt_mon_capable) static_branch_enable(&rdt_enable_key); + + if (is_mbm_enabled()) { + r = &rdt_resources_all[RDT_RESOURCE_L3]; + list_for_each_entry(dom, &r->domains, list) + mbm_setup_overflow_handler(dom); + } + goto out; out_mondata: