]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - arch/x86/kernel/cpu/intel_rdt.c
Documentation, x86: Documentation for Intel resource allocation user interface
[mirror_ubuntu-bionic-kernel.git] / arch / x86 / kernel / cpu / intel_rdt.c
CommitLineData
78e99b4a
FY
1/*
2 * Resource Director Technology(RDT)
3 * - Cache Allocation code.
4 *
5 * Copyright (C) 2016 Intel Corporation
6 *
7 * Authors:
8 * Fenghua Yu <fenghua.yu@intel.com>
9 * Tony Luck <tony.luck@intel.com>
10 * Vikas Shivappa <vikas.shivappa@intel.com>
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms and conditions of the GNU General Public License,
14 * version 2, as published by the Free Software Foundation.
15 *
16 * This program is distributed in the hope it will be useful, but WITHOUT
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 * more details.
20 *
21 * More information about RDT be found in the Intel (R) x86 Architecture
22 * Software Developer Manual June 2016, volume 3, section 17.17.
23 */
24
25#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
26
27#include <linux/slab.h>
28#include <linux/err.h>
29
113c6097
FY
30#include <asm/intel_rdt_common.h>
31#include <asm/intel-family.h>
32#include <asm/intel_rdt.h>
33
c1c7c3f9
FY
34#define domain_init(id) LIST_HEAD_INIT(rdt_resources_all[id].domains)
35
36struct rdt_resource rdt_resources_all[] = {
37 {
38 .name = "L3",
39 .domains = domain_init(RDT_RESOURCE_L3),
40 .msr_base = IA32_L3_CBM_BASE,
41 .min_cbm_bits = 1,
42 .cache_level = 3,
43 .cbm_idx_multi = 1,
44 .cbm_idx_offset = 0
45 },
46 {
47 .name = "L3DATA",
48 .domains = domain_init(RDT_RESOURCE_L3DATA),
49 .msr_base = IA32_L3_CBM_BASE,
50 .min_cbm_bits = 1,
51 .cache_level = 3,
52 .cbm_idx_multi = 2,
53 .cbm_idx_offset = 0
54 },
55 {
56 .name = "L3CODE",
57 .domains = domain_init(RDT_RESOURCE_L3CODE),
58 .msr_base = IA32_L3_CBM_BASE,
59 .min_cbm_bits = 1,
60 .cache_level = 3,
61 .cbm_idx_multi = 2,
62 .cbm_idx_offset = 1
63 },
64 {
65 .name = "L2",
66 .domains = domain_init(RDT_RESOURCE_L2),
67 .msr_base = IA32_L2_CBM_BASE,
68 .min_cbm_bits = 1,
69 .cache_level = 2,
70 .cbm_idx_multi = 1,
71 .cbm_idx_offset = 0
72 },
73};
74
113c6097
FY
75/*
76 * cache_alloc_hsw_probe() - Have to probe for Intel haswell server CPUs
77 * as they do not have CPUID enumeration support for Cache allocation.
78 * The check for Vendor/Family/Model is not enough to guarantee that
79 * the MSRs won't #GP fault because only the following SKUs support
80 * CAT:
81 * Intel(R) Xeon(R) CPU E5-2658 v3 @ 2.20GHz
82 * Intel(R) Xeon(R) CPU E5-2648L v3 @ 1.80GHz
83 * Intel(R) Xeon(R) CPU E5-2628L v3 @ 2.00GHz
84 * Intel(R) Xeon(R) CPU E5-2618L v3 @ 2.30GHz
85 * Intel(R) Xeon(R) CPU E5-2608L v3 @ 2.00GHz
86 * Intel(R) Xeon(R) CPU E5-2658A v3 @ 2.20GHz
87 *
88 * Probe by trying to write the first of the L3 cach mask registers
89 * and checking that the bits stick. Max CLOSids is always 4 and max cbm length
90 * is always 20 on hsw server parts. The minimum cache bitmask length
91 * allowed for HSW server is always 2 bits. Hardcode all of them.
92 */
93static inline bool cache_alloc_hsw_probe(void)
94{
95 if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
96 boot_cpu_data.x86 == 6 &&
97 boot_cpu_data.x86_model == INTEL_FAM6_HASWELL_X) {
c1c7c3f9 98 struct rdt_resource *r = &rdt_resources_all[RDT_RESOURCE_L3];
113c6097
FY
99 u32 l, h, max_cbm = BIT_MASK(20) - 1;
100
101 if (wrmsr_safe(IA32_L3_CBM_BASE, max_cbm, 0))
102 return false;
103 rdmsr(IA32_L3_CBM_BASE, l, h);
104
105 /* If all the bits were set in MSR, return success */
c1c7c3f9
FY
106 if (l != max_cbm)
107 return false;
108
109 r->num_closid = 4;
110 r->cbm_len = 20;
111 r->max_cbm = max_cbm;
112 r->min_cbm_bits = 2;
113 r->capable = true;
114 r->enabled = true;
115
116 return true;
113c6097
FY
117 }
118
119 return false;
120}
121
c1c7c3f9
FY
122static void rdt_get_config(int idx, struct rdt_resource *r)
123{
124 union cpuid_0x10_1_eax eax;
125 union cpuid_0x10_1_edx edx;
126 u32 ebx, ecx;
127
128 cpuid_count(0x00000010, idx, &eax.full, &ebx, &ecx, &edx.full);
129 r->num_closid = edx.split.cos_max + 1;
130 r->cbm_len = eax.split.cbm_len + 1;
131 r->max_cbm = BIT_MASK(eax.split.cbm_len + 1) - 1;
132 r->capable = true;
133 r->enabled = true;
134}
135
136static void rdt_get_cdp_l3_config(int type)
137{
138 struct rdt_resource *r_l3 = &rdt_resources_all[RDT_RESOURCE_L3];
139 struct rdt_resource *r = &rdt_resources_all[type];
140
141 r->num_closid = r_l3->num_closid / 2;
142 r->cbm_len = r_l3->cbm_len;
143 r->max_cbm = r_l3->max_cbm;
144 r->capable = true;
145 /*
146 * By default, CDP is disabled. CDP can be enabled by mount parameter
147 * "cdp" during resctrl file system mount time.
148 */
149 r->enabled = false;
150}
151
78e99b4a
FY
152static inline bool get_rdt_resources(void)
153{
c1c7c3f9
FY
154 bool ret = false;
155
113c6097
FY
156 if (cache_alloc_hsw_probe())
157 return true;
78e99b4a
FY
158
159 if (!boot_cpu_has(X86_FEATURE_RDT_A))
160 return false;
78e99b4a 161
c1c7c3f9
FY
162 if (boot_cpu_has(X86_FEATURE_CAT_L3)) {
163 rdt_get_config(1, &rdt_resources_all[RDT_RESOURCE_L3]);
164 if (boot_cpu_has(X86_FEATURE_CDP_L3)) {
165 rdt_get_cdp_l3_config(RDT_RESOURCE_L3DATA);
166 rdt_get_cdp_l3_config(RDT_RESOURCE_L3CODE);
167 }
168 ret = true;
169 }
170 if (boot_cpu_has(X86_FEATURE_CAT_L2)) {
171 /* CPUID 0x10.2 fields are same format at 0x10.1 */
172 rdt_get_config(2, &rdt_resources_all[RDT_RESOURCE_L2]);
173 ret = true;
174 }
175
176 return ret;
78e99b4a
FY
177}
178
179static int __init intel_rdt_late_init(void)
180{
c1c7c3f9
FY
181 struct rdt_resource *r;
182
78e99b4a
FY
183 if (!get_rdt_resources())
184 return -ENODEV;
185
c1c7c3f9
FY
186 for_each_capable_rdt_resource(r)
187 pr_info("Intel RDT %s allocation detected\n", r->name);
78e99b4a
FY
188
189 return 0;
190}
191
192late_initcall(intel_rdt_late_init);