Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86/intel_rdt: Build structures for each resource based on cache topology

We use the cpu hotplug notifier to catch each cpu in turn and look at
its cache topology w.r.t each of the resource groups. As we discover
new resources, we initialize the bitmask array for each to the default
(full access) value.

Signed-off-by: Tony Luck <tony.luck@intel.com>
Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
Cc: "Ravi V Shankar" <ravi.v.shankar@intel.com>
Cc: "Shaohua Li" <shli@fb.com>
Cc: "Sai Prakhya" <sai.praneeth.prakhya@intel.com>
Cc: "Peter Zijlstra" <peterz@infradead.org>
Cc: "Stephane Eranian" <eranian@google.com>
Cc: "Dave Hansen" <dave.hansen@intel.com>
Cc: "David Carrillo-Cisneros" <davidcc@google.com>
Cc: "Nilay Vaish" <nilayvaish@gmail.com>
Cc: "Vikas Shivappa" <vikas.shivappa@linux.intel.com>
Cc: "Ingo Molnar" <mingo@elte.hu>
Cc: "Borislav Petkov" <bp@suse.de>
Cc: "H. Peter Anvin" <h.peter.anvin@intel.com>
Link: http://lkml.kernel.org/r/1477692289-37412-3-git-send-email-fenghua.yu@intel.com
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

authored by

Tony Luck and committed by
Thomas Gleixner
2264d9c7 f20e5789

+225 -1
+35
arch/x86/include/asm/intel_rdt.h
··· 39 39 int cbm_idx_offset; 40 40 }; 41 41 42 + /** 43 + * struct rdt_domain - group of cpus sharing an RDT resource 44 + * @list: all instances of this resource 45 + * @id: unique id for this instance 46 + * @cpu_mask: which cpus share this resource 47 + * @cbm: array of cache bit masks (indexed by CLOSID) 48 + */ 49 + struct rdt_domain { 50 + struct list_head list; 51 + int id; 52 + struct cpumask cpu_mask; 53 + u32 *cbm; 54 + }; 55 + 56 + /** 57 + * struct msr_param - set a range of MSRs from a domain 58 + * @res: The resource to use 59 + * @low: Beginning index from base MSR 60 + * @high: End index 61 + */ 62 + struct msr_param { 63 + struct rdt_resource *res; 64 + int low; 65 + int high; 66 + }; 67 + 68 + extern struct mutex rdtgroup_mutex; 69 + 42 70 extern struct rdt_resource rdt_resources_all[]; 43 71 44 72 enum { ··· 84 56 r++) \ 85 57 if (r->capable) 86 58 59 + #define for_each_enabled_rdt_resource(r) \ 60 + for (r = rdt_resources_all; r < rdt_resources_all + RDT_NUM_RESOURCES;\ 61 + r++) \ 62 + if (r->enabled) 63 + 87 64 /* CPUID.(EAX=10H, ECX=ResID=1).EAX */ 88 65 union cpuid_0x10_1_eax { 89 66 struct { ··· 104 71 } split; 105 72 unsigned int full; 106 73 }; 74 + 75 + void rdt_cbm_update(void *arg); 107 76 #endif /* _ASM_X86_INTEL_RDT_H */
+190 -1
arch/x86/kernel/cpu/intel_rdt.c
··· 26 26 27 27 #include <linux/slab.h> 28 28 #include <linux/err.h> 29 + #include <linux/cacheinfo.h> 30 + #include <linux/cpuhotplug.h> 29 31 30 32 #include <asm/intel_rdt_common.h> 31 33 #include <asm/intel-family.h> 32 34 #include <asm/intel_rdt.h> 35 + 36 + /* Mutex to protect rdtgroup access. */ 37 + DEFINE_MUTEX(rdtgroup_mutex); 33 38 34 39 #define domain_init(id) LIST_HEAD_INIT(rdt_resources_all[id].domains) 35 40 ··· 76 71 .cbm_idx_offset = 0 77 72 }, 78 73 }; 74 + 75 + static int cbm_idx(struct rdt_resource *r, int closid) 76 + { 77 + return closid * r->cbm_idx_multi + r->cbm_idx_offset; 78 + } 79 79 80 80 /* 81 81 * cache_alloc_hsw_probe() - Have to probe for Intel haswell server CPUs ··· 186 176 return ret; 187 177 } 188 178 189 - static int __init intel_rdt_late_init(void) 179 + static int get_cache_id(int cpu, int level) 180 + { 181 + struct cpu_cacheinfo *ci = get_cpu_cacheinfo(cpu); 182 + int i; 183 + 184 + for (i = 0; i < ci->num_leaves; i++) { 185 + if (ci->info_list[i].level == level) 186 + return ci->info_list[i].id; 187 + } 188 + 189 + return -1; 190 + } 191 + 192 + void rdt_cbm_update(void *arg) 193 + { 194 + struct msr_param *m = (struct msr_param *)arg; 195 + struct rdt_resource *r = m->res; 196 + int i, cpu = smp_processor_id(); 197 + struct rdt_domain *d; 198 + 199 + list_for_each_entry(d, &r->domains, list) { 200 + /* Find the domain that contains this CPU */ 201 + if (cpumask_test_cpu(cpu, &d->cpu_mask)) 202 + goto found; 203 + } 204 + pr_info_once("cpu %d not found in any domain for resource %s\n", 205 + cpu, r->name); 206 + 207 + return; 208 + 209 + found: 210 + for (i = m->low; i < m->high; i++) { 211 + int idx = cbm_idx(r, i); 212 + 213 + wrmsrl(r->msr_base + idx, d->cbm[i]); 214 + } 215 + } 216 + 217 + /* 218 + * rdt_find_domain - Find a domain in a resource that matches input resource id 219 + * 220 + * Search resource r's domain list to find the resource id. If the resource 221 + * id is found in a domain, return the domain. Otherwise, if requested by 222 + * caller, return the first domain whose id is bigger than the input id. 223 + * The domain list is sorted by id in ascending order. 224 + */ 225 + static struct rdt_domain *rdt_find_domain(struct rdt_resource *r, int id, 226 + struct list_head **pos) 227 + { 228 + struct rdt_domain *d; 229 + struct list_head *l; 230 + 231 + if (id < 0) 232 + return ERR_PTR(id); 233 + 234 + list_for_each(l, &r->domains) { 235 + d = list_entry(l, struct rdt_domain, list); 236 + /* When id is found, return its domain. */ 237 + if (id == d->id) 238 + return d; 239 + /* Stop searching when finding id's position in sorted list. */ 240 + if (id < d->id) 241 + break; 242 + } 243 + 244 + if (pos) 245 + *pos = l; 246 + 247 + return NULL; 248 + } 249 + 250 + /* 251 + * domain_add_cpu - Add a cpu to a resource's domain list. 252 + * 253 + * If an existing domain in the resource r's domain list matches the cpu's 254 + * resource id, add the cpu in the domain. 255 + * 256 + * Otherwise, a new domain is allocated and inserted into the right position 257 + * in the domain list sorted by id in ascending order. 258 + * 259 + * The order in the domain list is visible to users when we print entries 260 + * in the schemata file and schemata input is validated to have the same order 261 + * as this list. 262 + */ 263 + static void domain_add_cpu(int cpu, struct rdt_resource *r) 264 + { 265 + int i, id = get_cache_id(cpu, r->cache_level); 266 + struct list_head *add_pos = NULL; 267 + struct rdt_domain *d; 268 + 269 + d = rdt_find_domain(r, id, &add_pos); 270 + if (IS_ERR(d)) { 271 + pr_warn("Could't find cache id for cpu %d\n", cpu); 272 + return; 273 + } 274 + 275 + if (d) { 276 + cpumask_set_cpu(cpu, &d->cpu_mask); 277 + return; 278 + } 279 + 280 + d = kzalloc_node(sizeof(*d), GFP_KERNEL, cpu_to_node(cpu)); 281 + if (!d) 282 + return; 283 + 284 + d->id = id; 285 + 286 + d->cbm = kmalloc_array(r->num_closid, sizeof(*d->cbm), GFP_KERNEL); 287 + if (!d->cbm) { 288 + kfree(d); 289 + return; 290 + } 291 + 292 + for (i = 0; i < r->num_closid; i++) { 293 + int idx = cbm_idx(r, i); 294 + 295 + d->cbm[i] = r->max_cbm; 296 + wrmsrl(r->msr_base + idx, d->cbm[i]); 297 + } 298 + 299 + cpumask_set_cpu(cpu, &d->cpu_mask); 300 + list_add_tail(&d->list, add_pos); 301 + r->num_domains++; 302 + } 303 + 304 + static void domain_remove_cpu(int cpu, struct rdt_resource *r) 305 + { 306 + int id = get_cache_id(cpu, r->cache_level); 307 + struct rdt_domain *d; 308 + 309 + d = rdt_find_domain(r, id, NULL); 310 + if (IS_ERR_OR_NULL(d)) { 311 + pr_warn("Could't find cache id for cpu %d\n", cpu); 312 + return; 313 + } 314 + 315 + cpumask_clear_cpu(cpu, &d->cpu_mask); 316 + if (cpumask_empty(&d->cpu_mask)) { 317 + r->num_domains--; 318 + kfree(d->cbm); 319 + list_del(&d->list); 320 + kfree(d); 321 + } 322 + } 323 + 324 + static int intel_rdt_online_cpu(unsigned int cpu) 325 + { 326 + struct intel_pqr_state *state = this_cpu_ptr(&pqr_state); 327 + struct rdt_resource *r; 328 + 329 + mutex_lock(&rdtgroup_mutex); 330 + for_each_capable_rdt_resource(r) 331 + domain_add_cpu(cpu, r); 332 + state->closid = 0; 333 + wrmsr(MSR_IA32_PQR_ASSOC, state->rmid, 0); 334 + mutex_unlock(&rdtgroup_mutex); 335 + 336 + return 0; 337 + } 338 + 339 + static int intel_rdt_offline_cpu(unsigned int cpu) 190 340 { 191 341 struct rdt_resource *r; 192 342 343 + mutex_lock(&rdtgroup_mutex); 344 + for_each_capable_rdt_resource(r) 345 + domain_remove_cpu(cpu, r); 346 + mutex_unlock(&rdtgroup_mutex); 347 + 348 + return 0; 349 + } 350 + 351 + static int __init intel_rdt_late_init(void) 352 + { 353 + struct rdt_resource *r; 354 + int state; 355 + 193 356 if (!get_rdt_resources()) 194 357 return -ENODEV; 358 + 359 + state = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, 360 + "x86/rdt/cat:online:", 361 + intel_rdt_online_cpu, intel_rdt_offline_cpu); 362 + if (state < 0) 363 + return state; 195 364 196 365 for_each_capable_rdt_resource(r) 197 366 pr_info("Intel RDT %s allocation detected\n", r->name);