xref: /aosp_15_r20/external/cpuinfo/src/x86/cache/deterministic.c (revision 2b54f0db79fd8303838913b20ff3780cddaa909f)
1*2b54f0dbSXin Li #include <stdint.h>
2*2b54f0dbSXin Li 
3*2b54f0dbSXin Li #include <cpuinfo.h>
4*2b54f0dbSXin Li #include <x86/cpuid.h>
5*2b54f0dbSXin Li #include <cpuinfo/utils.h>
6*2b54f0dbSXin Li #include <cpuinfo/log.h>
7*2b54f0dbSXin Li 
8*2b54f0dbSXin Li 
9*2b54f0dbSXin Li enum cache_type {
10*2b54f0dbSXin Li 	cache_type_none = 0,
11*2b54f0dbSXin Li 	cache_type_data = 1,
12*2b54f0dbSXin Li 	cache_type_instruction = 2,
13*2b54f0dbSXin Li 	cache_type_unified = 3,
14*2b54f0dbSXin Li };
15*2b54f0dbSXin Li 
cpuinfo_x86_decode_deterministic_cache_parameters(struct cpuid_regs regs,struct cpuinfo_x86_caches * cache,uint32_t * package_cores_max)16*2b54f0dbSXin Li bool cpuinfo_x86_decode_deterministic_cache_parameters(
17*2b54f0dbSXin Li 	struct cpuid_regs regs,
18*2b54f0dbSXin Li 	struct cpuinfo_x86_caches* cache,
19*2b54f0dbSXin Li 	uint32_t* package_cores_max)
20*2b54f0dbSXin Li {
21*2b54f0dbSXin Li 	const uint32_t type = regs.eax & UINT32_C(0x1F);
22*2b54f0dbSXin Li 	if (type == cache_type_none) {
23*2b54f0dbSXin Li 		return false;
24*2b54f0dbSXin Li 	}
25*2b54f0dbSXin Li 
26*2b54f0dbSXin Li 	/* Level starts at 1 */
27*2b54f0dbSXin Li 	const uint32_t level = (regs.eax >> 5) & UINT32_C(0x7);
28*2b54f0dbSXin Li 
29*2b54f0dbSXin Li 	const uint32_t sets = 1 + regs.ecx;
30*2b54f0dbSXin Li 	const uint32_t line_size = 1 + (regs.ebx & UINT32_C(0x00000FFF));
31*2b54f0dbSXin Li 	const uint32_t partitions = 1 + ((regs.ebx >> 12) & UINT32_C(0x000003FF));
32*2b54f0dbSXin Li 	const uint32_t associativity = 1 + (regs.ebx >> 22);
33*2b54f0dbSXin Li 
34*2b54f0dbSXin Li 	*package_cores_max = 1 + (regs.eax >> 26);
35*2b54f0dbSXin Li 	const uint32_t processors = 1 + ((regs.eax >> 14) & UINT32_C(0x00000FFF));
36*2b54f0dbSXin Li 	const uint32_t apic_bits = bit_length(processors);
37*2b54f0dbSXin Li 
38*2b54f0dbSXin Li 	uint32_t flags = 0;
39*2b54f0dbSXin Li 	if (regs.edx & UINT32_C(0x00000002)) {
40*2b54f0dbSXin Li 		flags |= CPUINFO_CACHE_INCLUSIVE;
41*2b54f0dbSXin Li 	}
42*2b54f0dbSXin Li 	if (regs.edx & UINT32_C(0x00000004)) {
43*2b54f0dbSXin Li 		flags |= CPUINFO_CACHE_COMPLEX_INDEXING;
44*2b54f0dbSXin Li 	}
45*2b54f0dbSXin Li 	switch (level) {
46*2b54f0dbSXin Li 		case 1:
47*2b54f0dbSXin Li 			switch (type) {
48*2b54f0dbSXin Li 				case cache_type_unified:
49*2b54f0dbSXin Li 					cache->l1d = cache->l1i = (struct cpuinfo_x86_cache) {
50*2b54f0dbSXin Li 						.size = associativity * partitions * line_size * sets,
51*2b54f0dbSXin Li 						.associativity = associativity,
52*2b54f0dbSXin Li 						.sets = sets,
53*2b54f0dbSXin Li 						.partitions = partitions,
54*2b54f0dbSXin Li 						.line_size = line_size,
55*2b54f0dbSXin Li 						.flags = flags | CPUINFO_CACHE_UNIFIED,
56*2b54f0dbSXin Li 						.apic_bits = apic_bits
57*2b54f0dbSXin Li 					};
58*2b54f0dbSXin Li 					break;
59*2b54f0dbSXin Li 				case cache_type_data:
60*2b54f0dbSXin Li 					cache->l1d = (struct cpuinfo_x86_cache) {
61*2b54f0dbSXin Li 						.size = associativity * partitions * line_size * sets,
62*2b54f0dbSXin Li 						.associativity = associativity,
63*2b54f0dbSXin Li 						.sets = sets,
64*2b54f0dbSXin Li 						.partitions = partitions,
65*2b54f0dbSXin Li 						.line_size = line_size,
66*2b54f0dbSXin Li 						.flags = flags,
67*2b54f0dbSXin Li 						.apic_bits = apic_bits
68*2b54f0dbSXin Li 					};
69*2b54f0dbSXin Li 					break;
70*2b54f0dbSXin Li 				case cache_type_instruction:
71*2b54f0dbSXin Li 					cache->l1i = (struct cpuinfo_x86_cache) {
72*2b54f0dbSXin Li 						.size = associativity * partitions * line_size * sets,
73*2b54f0dbSXin Li 						.associativity = associativity,
74*2b54f0dbSXin Li 						.sets = sets,
75*2b54f0dbSXin Li 						.partitions = partitions,
76*2b54f0dbSXin Li 						.line_size = line_size,
77*2b54f0dbSXin Li 						.flags = flags,
78*2b54f0dbSXin Li 						.apic_bits = apic_bits
79*2b54f0dbSXin Li 					};
80*2b54f0dbSXin Li 					break;
81*2b54f0dbSXin Li 			}
82*2b54f0dbSXin Li 			break;
83*2b54f0dbSXin Li 		case 2:
84*2b54f0dbSXin Li 			switch (type) {
85*2b54f0dbSXin Li 				case cache_type_instruction:
86*2b54f0dbSXin Li 					cpuinfo_log_warning("unexpected L2 instruction cache reported in leaf 0x00000004 is ignored");
87*2b54f0dbSXin Li 					break;
88*2b54f0dbSXin Li 				case cache_type_unified:
89*2b54f0dbSXin Li 					flags |= CPUINFO_CACHE_UNIFIED;
90*2b54f0dbSXin Li 				case cache_type_data:
91*2b54f0dbSXin Li 					cache->l2 = (struct cpuinfo_x86_cache) {
92*2b54f0dbSXin Li 						.size = associativity * partitions * line_size * sets,
93*2b54f0dbSXin Li 						.associativity = associativity,
94*2b54f0dbSXin Li 						.sets = sets,
95*2b54f0dbSXin Li 						.partitions = partitions,
96*2b54f0dbSXin Li 						.line_size = line_size,
97*2b54f0dbSXin Li 						.flags = flags,
98*2b54f0dbSXin Li 						.apic_bits = apic_bits
99*2b54f0dbSXin Li 					};
100*2b54f0dbSXin Li 					break;
101*2b54f0dbSXin Li 			}
102*2b54f0dbSXin Li 			break;
103*2b54f0dbSXin Li 		case 3:
104*2b54f0dbSXin Li 			switch (type) {
105*2b54f0dbSXin Li 				case cache_type_instruction:
106*2b54f0dbSXin Li 					cpuinfo_log_warning("unexpected L3 instruction cache reported in leaf 0x00000004 is ignored");
107*2b54f0dbSXin Li 					break;
108*2b54f0dbSXin Li 				case cache_type_unified:
109*2b54f0dbSXin Li 					flags |= CPUINFO_CACHE_UNIFIED;
110*2b54f0dbSXin Li 				case cache_type_data:
111*2b54f0dbSXin Li 					cache->l3 = (struct cpuinfo_x86_cache) {
112*2b54f0dbSXin Li 						.size = associativity * partitions * line_size * sets,
113*2b54f0dbSXin Li 						.associativity = associativity,
114*2b54f0dbSXin Li 						.sets = sets,
115*2b54f0dbSXin Li 						.partitions = partitions,
116*2b54f0dbSXin Li 						.line_size = line_size,
117*2b54f0dbSXin Li 						.flags = flags,
118*2b54f0dbSXin Li 						.apic_bits = apic_bits
119*2b54f0dbSXin Li 					};
120*2b54f0dbSXin Li 					break;
121*2b54f0dbSXin Li 			}
122*2b54f0dbSXin Li 			break;
123*2b54f0dbSXin Li 		case 4:
124*2b54f0dbSXin Li 			switch (type) {
125*2b54f0dbSXin Li 				case cache_type_instruction:
126*2b54f0dbSXin Li 					cpuinfo_log_warning("unexpected L4 instruction cache reported in leaf 0x00000004 is ignored");
127*2b54f0dbSXin Li 					break;
128*2b54f0dbSXin Li 				case cache_type_unified:
129*2b54f0dbSXin Li 					flags |= CPUINFO_CACHE_UNIFIED;
130*2b54f0dbSXin Li 				case cache_type_data:
131*2b54f0dbSXin Li 					cache->l4 = (struct cpuinfo_x86_cache) {
132*2b54f0dbSXin Li 						.size = associativity * partitions * line_size * sets,
133*2b54f0dbSXin Li 						.associativity = associativity,
134*2b54f0dbSXin Li 						.sets = sets,
135*2b54f0dbSXin Li 						.partitions = partitions,
136*2b54f0dbSXin Li 						.line_size = line_size,
137*2b54f0dbSXin Li 						.flags = flags,
138*2b54f0dbSXin Li 						.apic_bits = apic_bits
139*2b54f0dbSXin Li 					};
140*2b54f0dbSXin Li 					break;
141*2b54f0dbSXin Li 			}
142*2b54f0dbSXin Li 			break;
143*2b54f0dbSXin Li 		default:
144*2b54f0dbSXin Li 			cpuinfo_log_warning("unexpected L%"PRIu32" cache reported in leaf 0x00000004 is ignored", level);
145*2b54f0dbSXin Li 			break;
146*2b54f0dbSXin Li 	}
147*2b54f0dbSXin Li 	return true;
148*2b54f0dbSXin Li }
149*2b54f0dbSXin Li 
150*2b54f0dbSXin Li 
cpuinfo_x86_decode_cache_properties(struct cpuid_regs regs,struct cpuinfo_x86_caches * cache)151*2b54f0dbSXin Li bool cpuinfo_x86_decode_cache_properties(
152*2b54f0dbSXin Li 	struct cpuid_regs regs,
153*2b54f0dbSXin Li 	struct cpuinfo_x86_caches* cache)
154*2b54f0dbSXin Li {
155*2b54f0dbSXin Li 	const uint32_t type = regs.eax & UINT32_C(0x1F);
156*2b54f0dbSXin Li 	if (type == cache_type_none) {
157*2b54f0dbSXin Li 		return false;
158*2b54f0dbSXin Li 	}
159*2b54f0dbSXin Li 
160*2b54f0dbSXin Li 	const uint32_t level = (regs.eax >> 5) & UINT32_C(0x7);
161*2b54f0dbSXin Li 	const uint32_t cores = 1 + ((regs.eax >> 14) & UINT32_C(0x00000FFF));
162*2b54f0dbSXin Li 	const uint32_t apic_bits = bit_length(cores);
163*2b54f0dbSXin Li 
164*2b54f0dbSXin Li 	const uint32_t sets = 1 + regs.ecx;
165*2b54f0dbSXin Li 	const uint32_t line_size = 1 + (regs.ebx & UINT32_C(0x00000FFF));
166*2b54f0dbSXin Li 	const uint32_t partitions = 1 + ((regs.ebx >> 12) & UINT32_C(0x000003FF));
167*2b54f0dbSXin Li 	const uint32_t associativity = 1 + (regs.ebx >> 22);
168*2b54f0dbSXin Li 
169*2b54f0dbSXin Li 	uint32_t flags = 0;
170*2b54f0dbSXin Li 	if (regs.edx & UINT32_C(0x00000002)) {
171*2b54f0dbSXin Li 		flags |= CPUINFO_CACHE_INCLUSIVE;
172*2b54f0dbSXin Li 	}
173*2b54f0dbSXin Li 
174*2b54f0dbSXin Li 	switch (level) {
175*2b54f0dbSXin Li 		case 1:
176*2b54f0dbSXin Li 			switch (type) {
177*2b54f0dbSXin Li 				case cache_type_unified:
178*2b54f0dbSXin Li 					cache->l1d = cache->l1i = (struct cpuinfo_x86_cache) {
179*2b54f0dbSXin Li 						.size = associativity * partitions * line_size * sets,
180*2b54f0dbSXin Li 						.associativity = associativity,
181*2b54f0dbSXin Li 						.sets = sets,
182*2b54f0dbSXin Li 						.partitions = partitions,
183*2b54f0dbSXin Li 						.line_size = line_size,
184*2b54f0dbSXin Li 						.flags = flags | CPUINFO_CACHE_UNIFIED,
185*2b54f0dbSXin Li 						.apic_bits = apic_bits
186*2b54f0dbSXin Li 					};
187*2b54f0dbSXin Li 					break;
188*2b54f0dbSXin Li 				case cache_type_data:
189*2b54f0dbSXin Li 					cache->l1d = (struct cpuinfo_x86_cache) {
190*2b54f0dbSXin Li 						.size = associativity * partitions * line_size * sets,
191*2b54f0dbSXin Li 						.associativity = associativity,
192*2b54f0dbSXin Li 						.sets = sets,
193*2b54f0dbSXin Li 						.partitions = partitions,
194*2b54f0dbSXin Li 						.line_size = line_size,
195*2b54f0dbSXin Li 						.flags = flags,
196*2b54f0dbSXin Li 						.apic_bits = apic_bits
197*2b54f0dbSXin Li 					};
198*2b54f0dbSXin Li 					break;
199*2b54f0dbSXin Li 				case cache_type_instruction:
200*2b54f0dbSXin Li 					cache->l1i = (struct cpuinfo_x86_cache) {
201*2b54f0dbSXin Li 						.size = associativity * partitions * line_size * sets,
202*2b54f0dbSXin Li 						.associativity = associativity,
203*2b54f0dbSXin Li 						.sets = sets,
204*2b54f0dbSXin Li 						.partitions = partitions,
205*2b54f0dbSXin Li 						.line_size = line_size,
206*2b54f0dbSXin Li 						.flags = flags,
207*2b54f0dbSXin Li 						.apic_bits = apic_bits
208*2b54f0dbSXin Li 					};
209*2b54f0dbSXin Li 					break;
210*2b54f0dbSXin Li 			}
211*2b54f0dbSXin Li 			break;
212*2b54f0dbSXin Li 		case 2:
213*2b54f0dbSXin Li 			switch (type) {
214*2b54f0dbSXin Li 				case cache_type_instruction:
215*2b54f0dbSXin Li 					cpuinfo_log_warning("unexpected L2 instruction cache reported in leaf 0x8000001D is ignored");
216*2b54f0dbSXin Li 					break;
217*2b54f0dbSXin Li 				case cache_type_unified:
218*2b54f0dbSXin Li 					flags |= CPUINFO_CACHE_UNIFIED;
219*2b54f0dbSXin Li 				case cache_type_data:
220*2b54f0dbSXin Li 					cache->l2 = (struct cpuinfo_x86_cache) {
221*2b54f0dbSXin Li 						.size = associativity * partitions * line_size * sets,
222*2b54f0dbSXin Li 						.associativity = associativity,
223*2b54f0dbSXin Li 						.sets = sets,
224*2b54f0dbSXin Li 						.partitions = partitions,
225*2b54f0dbSXin Li 						.line_size = line_size,
226*2b54f0dbSXin Li 						.flags = flags,
227*2b54f0dbSXin Li 						.apic_bits = apic_bits
228*2b54f0dbSXin Li 					};
229*2b54f0dbSXin Li 					break;
230*2b54f0dbSXin Li 			}
231*2b54f0dbSXin Li 			break;
232*2b54f0dbSXin Li 		case 3:
233*2b54f0dbSXin Li 			switch (type) {
234*2b54f0dbSXin Li 				case cache_type_instruction:
235*2b54f0dbSXin Li 					cpuinfo_log_warning("unexpected L3 instruction cache reported in leaf 0x8000001D is ignored");
236*2b54f0dbSXin Li 					break;
237*2b54f0dbSXin Li 				case cache_type_unified:
238*2b54f0dbSXin Li 					flags |= CPUINFO_CACHE_UNIFIED;
239*2b54f0dbSXin Li 				case cache_type_data:
240*2b54f0dbSXin Li 					cache->l3 = (struct cpuinfo_x86_cache) {
241*2b54f0dbSXin Li 						.size = associativity * partitions * line_size * sets,
242*2b54f0dbSXin Li 						.associativity = associativity,
243*2b54f0dbSXin Li 						.sets = sets,
244*2b54f0dbSXin Li 						.partitions = partitions,
245*2b54f0dbSXin Li 						.line_size = line_size,
246*2b54f0dbSXin Li 						.flags = flags,
247*2b54f0dbSXin Li 						.apic_bits = apic_bits
248*2b54f0dbSXin Li 					};
249*2b54f0dbSXin Li 					break;
250*2b54f0dbSXin Li 			}
251*2b54f0dbSXin Li 			break;
252*2b54f0dbSXin Li 		default:
253*2b54f0dbSXin Li 			cpuinfo_log_warning("unexpected L%"PRIu32" cache reported in leaf 0x8000001D is ignored", level);
254*2b54f0dbSXin Li 			break;
255*2b54f0dbSXin Li 	}
256*2b54f0dbSXin Li 	return true;
257*2b54f0dbSXin Li }
258