Merge tag 'x86_cache_for_v6.9_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / arch / x86 / kernel / cpu / resctrl / core.c
index 19e0681..83e4034 100644 (file)
@@ -16,6 +16,7 @@
 
 #define pr_fmt(fmt)    "resctrl: " fmt
 
+#include <linux/cpu.h>
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/cacheinfo.h>
 #include <asm/resctrl.h>
 #include "internal.h"
 
-/* Mutex to protect rdtgroup access. */
-DEFINE_MUTEX(rdtgroup_mutex);
+/*
+ * rdt_domain structures are kfree()d when their last CPU goes offline,
+ * and allocated when the first CPU in a new domain comes online.
+ * The rdt_resource's domain list is updated when this happens. Readers of
+ * the domain list must either take cpus_read_lock(), or rely on an RCU
+ * read-side critical section, to avoid observing concurrent modification.
+ * All writers take this mutex:
+ */
+static DEFINE_MUTEX(domain_list_lock);
 
 /*
  * The cached resctrl_pqr_state is strictly per CPU and can never be
@@ -136,15 +144,15 @@ static inline void cache_alloc_hsw_probe(void)
 {
        struct rdt_hw_resource *hw_res = &rdt_resources_all[RDT_RESOURCE_L3];
        struct rdt_resource *r  = &hw_res->r_resctrl;
-       u32 l, h, max_cbm = BIT_MASK(20) - 1;
+       u64 max_cbm = BIT_ULL_MASK(20) - 1, l3_cbm_0;
 
-       if (wrmsr_safe(MSR_IA32_L3_CBM_BASE, max_cbm, 0))
+       if (wrmsrl_safe(MSR_IA32_L3_CBM_BASE, max_cbm))
                return;
 
-       rdmsr(MSR_IA32_L3_CBM_BASE, l, h);
+       rdmsrl(MSR_IA32_L3_CBM_BASE, l3_cbm_0);
 
        /* If all the bits were set in MSR, return success */
-       if (l != max_cbm)
+       if (l3_cbm_0 != max_cbm)
                return;
 
        hw_res->num_closid = 4;
@@ -231,9 +239,7 @@ static bool __get_mem_config_intel(struct rdt_resource *r)
 static bool __rdt_get_mem_config_amd(struct rdt_resource *r)
 {
        struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r);
-       union cpuid_0x10_3_eax eax;
-       union cpuid_0x10_x_edx edx;
-       u32 ebx, ecx, subleaf;
+       u32 eax, ebx, ecx, edx, subleaf;
 
        /*
         * Query CPUID_Fn80000020_EDX_x01 for MBA and
@@ -241,9 +247,9 @@ static bool __rdt_get_mem_config_amd(struct rdt_resource *r)
         */
        subleaf = (r->rid == RDT_RESOURCE_SMBA) ? 2 :  1;
 
-       cpuid_count(0x80000020, subleaf, &eax.full, &ebx, &ecx, &edx.full);
-       hw_res->num_closid = edx.split.cos_max + 1;
-       r->default_ctrl = MAX_MBA_BW_AMD;
+       cpuid_count(0x80000020, subleaf, &eax, &ebx, &ecx, &edx);
+       hw_res->num_closid = edx + 1;
+       r->default_ctrl = 1 << eax;
 
        /* AMD does not use delay */
        r->membw.delay_linear = false;
@@ -512,6 +518,8 @@ static void domain_add_cpu(int cpu, struct rdt_resource *r)
        struct rdt_domain *d;
        int err;
 
+       lockdep_assert_held(&domain_list_lock);
+
        d = rdt_find_domain(r, id, &add_pos);
        if (IS_ERR(d)) {
                pr_warn("Couldn't find cache id for CPU %d\n", cpu);
@@ -545,11 +553,12 @@ static void domain_add_cpu(int cpu, struct rdt_resource *r)
                return;
        }
 
-       list_add_tail(&d->list, add_pos);
+       list_add_tail_rcu(&d->list, add_pos);
 
        err = resctrl_online_domain(r, d);
        if (err) {
-               list_del(&d->list);
+               list_del_rcu(&d->list);
+               synchronize_rcu();
                domain_free(hw_dom);
        }
 }
@@ -560,6 +569,8 @@ static void domain_remove_cpu(int cpu, struct rdt_resource *r)
        struct rdt_hw_domain *hw_dom;
        struct rdt_domain *d;
 
+       lockdep_assert_held(&domain_list_lock);
+
        d = rdt_find_domain(r, id, NULL);
        if (IS_ERR_OR_NULL(d)) {
                pr_warn("Couldn't find cache id for CPU %d\n", cpu);
@@ -570,7 +581,8 @@ static void domain_remove_cpu(int cpu, struct rdt_resource *r)
        cpumask_clear_cpu(cpu, &d->cpu_mask);
        if (cpumask_empty(&d->cpu_mask)) {
                resctrl_offline_domain(r, d);
-               list_del(&d->list);
+               list_del_rcu(&d->list);
+               synchronize_rcu();
 
                /*
                 * rdt_domain "d" is going to be freed below, so clear
@@ -582,73 +594,47 @@ static void domain_remove_cpu(int cpu, struct rdt_resource *r)
 
                return;
        }
-
-       if (r == &rdt_resources_all[RDT_RESOURCE_L3].r_resctrl) {
-               if (is_mbm_enabled() && cpu == d->mbm_work_cpu) {
-                       cancel_delayed_work(&d->mbm_over);
-                       mbm_setup_overflow_handler(d, 0);
-               }
-               if (is_llc_occupancy_enabled() && cpu == d->cqm_work_cpu &&
-                   has_busy_rmid(r, d)) {
-                       cancel_delayed_work(&d->cqm_limbo);
-                       cqm_setup_limbo_handler(d, 0);
-               }
-       }
 }
 
 static void clear_closid_rmid(int cpu)
 {
        struct resctrl_pqr_state *state = this_cpu_ptr(&pqr_state);
 
-       state->default_closid = 0;
-       state->default_rmid = 0;
-       state->cur_closid = 0;
-       state->cur_rmid = 0;
-       wrmsr(MSR_IA32_PQR_ASSOC, 0, 0);
+       state->default_closid = RESCTRL_RESERVED_CLOSID;
+       state->default_rmid = RESCTRL_RESERVED_RMID;
+       state->cur_closid = RESCTRL_RESERVED_CLOSID;
+       state->cur_rmid = RESCTRL_RESERVED_RMID;
+       wrmsr(MSR_IA32_PQR_ASSOC, RESCTRL_RESERVED_RMID,
+             RESCTRL_RESERVED_CLOSID);
 }
 
-static int resctrl_online_cpu(unsigned int cpu)
+static int resctrl_arch_online_cpu(unsigned int cpu)
 {
        struct rdt_resource *r;
 
-       mutex_lock(&rdtgroup_mutex);
+       mutex_lock(&domain_list_lock);
        for_each_capable_rdt_resource(r)
                domain_add_cpu(cpu, r);
-       /* The cpu is set in default rdtgroup after online. */
-       cpumask_set_cpu(cpu, &rdtgroup_default.cpu_mask);
+       mutex_unlock(&domain_list_lock);
+
        clear_closid_rmid(cpu);
-       mutex_unlock(&rdtgroup_mutex);
+       resctrl_online_cpu(cpu);
 
        return 0;
 }
 
-static void clear_childcpus(struct rdtgroup *r, unsigned int cpu)
-{
-       struct rdtgroup *cr;
-
-       list_for_each_entry(cr, &r->mon.crdtgrp_list, mon.crdtgrp_list) {
-               if (cpumask_test_and_clear_cpu(cpu, &cr->cpu_mask)) {
-                       break;
-               }
-       }
-}
-
-static int resctrl_offline_cpu(unsigned int cpu)
+static int resctrl_arch_offline_cpu(unsigned int cpu)
 {
-       struct rdtgroup *rdtgrp;
        struct rdt_resource *r;
 
-       mutex_lock(&rdtgroup_mutex);
+       resctrl_offline_cpu(cpu);
+
+       mutex_lock(&domain_list_lock);
        for_each_capable_rdt_resource(r)
                domain_remove_cpu(cpu, r);
-       list_for_each_entry(rdtgrp, &rdt_all_groups, rdtgroup_list) {
-               if (cpumask_test_and_clear_cpu(cpu, &rdtgrp->cpu_mask)) {
-                       clear_childcpus(rdtgrp, cpu);
-                       break;
-               }
-       }
+       mutex_unlock(&domain_list_lock);
+
        clear_closid_rmid(cpu);
-       mutex_unlock(&rdtgroup_mutex);
 
        return 0;
 }
@@ -968,7 +954,8 @@ static int __init resctrl_late_init(void)
 
        state = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
                                  "x86/resctrl/cat:online:",
-                                 resctrl_online_cpu, resctrl_offline_cpu);
+                                 resctrl_arch_online_cpu,
+                                 resctrl_arch_offline_cpu);
        if (state < 0)
                return state;
 
@@ -992,8 +979,14 @@ late_initcall(resctrl_late_init);
 
 static void __exit resctrl_exit(void)
 {
+       struct rdt_resource *r = &rdt_resources_all[RDT_RESOURCE_L3].r_resctrl;
+
        cpuhp_remove_state(rdt_online);
+
        rdtgroup_exit();
+
+       if (r->mon_capable)
+               rdt_put_mon_l3_config();
 }
 
 __exitcall(resctrl_exit);