xref: /openbsd-src/sys/arch/amd64/amd64/cacheinfo.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: cacheinfo.c,v 1.8 2016/02/03 03:25:07 guenther Exp $	*/
2 
3 /*-
4  * Copyright (c) 2000 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jason R. Thorpe.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 
35 #include <machine/cpu.h>
36 #include <machine/specialreg.h>
37 
38 static char *print_cache_config(struct cpu_info *, int, char *, char *);
39 static char *print_tlb_config(struct cpu_info *, int, char *, char *);
40 
41 static char *
42 print_cache_config(struct cpu_info *ci, int cache_tag, char *name, char *sep)
43 {
44 	struct x86_cache_info *cai = &ci->ci_cinfo[cache_tag];
45 
46 	if (cai->cai_totalsize == 0)
47 		return sep;
48 
49 	if (sep == NULL)
50 		printf("%s: ", ci->ci_dev->dv_xname);
51 	else
52 		printf("%s", sep);
53 
54 	if (cai->cai_string != NULL)
55 		printf("%s ", cai->cai_string);
56 	else if (cai->cai_totalsize >= 1024*1024)
57 		printf("%dMB %db/line ", cai->cai_totalsize / 1024 / 1024,
58 		    cai->cai_linesize);
59 	else
60 		printf("%dKB %db/line ", cai->cai_totalsize / 1024,
61 		    cai->cai_linesize);
62 
63 	switch (cai->cai_associativity) {
64 	case    0:
65 		printf("disabled");
66 		break;
67 	case    1:
68 		printf("direct-mapped");
69 		break;
70 	case 0xff:
71 		printf("fully associative");
72 		break;
73 	default:
74 		printf("%d-way", cai->cai_associativity);
75 		break;
76 	}
77 
78 	if (name != NULL)
79 		printf(" %s", name);
80 
81 	return ", ";
82 }
83 
84 static char *
85 print_tlb_config(struct cpu_info *ci, int cache_tag, char *name, char *sep)
86 {
87 	struct x86_cache_info *cai = &ci->ci_cinfo[cache_tag];
88 
89 	if (cai->cai_totalsize == 0)
90 		return sep;
91 
92 	if (sep == NULL)
93 		printf("%s: ", ci->ci_dev->dv_xname);
94 	else
95 		printf("%s", sep);
96 	if (name != NULL)
97 		printf("%s ", name);
98 
99 	if (cai->cai_string != NULL) {
100 		printf("%s", cai->cai_string);
101 	} else {
102 		if (cai->cai_linesize >= 1024*1024)
103 			printf("%d %dMB entries ", cai->cai_totalsize,
104 			    cai->cai_linesize / 1024 / 1024);
105 		else
106 			printf("%d %dKB entries ", cai->cai_totalsize,
107 			    cai->cai_linesize / 1024);
108 		switch (cai->cai_associativity) {
109 		case 0:
110 			printf("disabled");
111 			break;
112 		case 1:
113 			printf("direct-mapped");
114 			break;
115 		case 0xff:
116 			printf("fully associative");
117 			break;
118 		default:
119 			printf("%d-way", cai->cai_associativity);
120 			break;
121 		}
122 	}
123 	return ", ";
124 }
125 
126 const struct x86_cache_info *
127 cache_info_lookup(const struct x86_cache_info *cai, u_int8_t desc)
128 {
129 	int i;
130 
131 	for (i = 0; cai[i].cai_desc != 0; i++) {
132 		if (cai[i].cai_desc == desc)
133 			return (&cai[i]);
134 	}
135 
136 	return (NULL);
137 }
138 
139 
140 static const struct x86_cache_info amd_cpuid_l2cache_assoc_info[] = {
141 	{ 0, 0x01,    1 },
142 	{ 0, 0x02,    2 },
143 	{ 0, 0x04,    4 },
144 	{ 0, 0x06,    8 },
145 	{ 0, 0x08,   16 },
146 	{ 0, 0x0a,   32 },
147 	{ 0, 0x0b,   48 },
148 	{ 0, 0x0c,   64 },
149 	{ 0, 0x0d,   96 },
150 	{ 0, 0x0e,  128 },
151 	{ 0, 0x0f, 0xff },
152 	{ 0, 0x00,    0 },
153 };
154 
155 void
156 amd_cpu_cacheinfo(struct cpu_info *ci)
157 {
158 	const struct x86_cache_info *cp;
159 	struct x86_cache_info *cai;
160 	int family, model;
161 	u_int descs[4];
162 
163 	family = ci->ci_family;
164 	model = ci->ci_model;
165 
166 	/*
167 	 * K5 model 0 has none of this info.
168 	 */
169 	if (family == 5 && model == 0)
170 		return;
171 
172 	/*
173 	 * Determine L1 cache/TLB info.
174 	 */
175 	if (ci->ci_pnfeatset < 0x80000005) {
176 		/* No L1 cache info available. */
177 		return;
178 	}
179 
180 	CPUID(0x80000005, descs[0], descs[1], descs[2], descs[3]);
181 	ci->ci_amdcacheinfo[0] = descs[0];
182 	ci->ci_amdcacheinfo[1] = descs[1];
183 	ci->ci_amdcacheinfo[2] = descs[2];
184 	ci->ci_amdcacheinfo[3] = descs[3];
185 
186 	/*
187 	 * K6-III and higher have large page TLBs.
188 	 */
189 	if ((family == 5 && model >= 9) || family >= 6) {
190 		cai = &ci->ci_cinfo[CAI_ITLB2];
191 		cai->cai_totalsize = AMD_L1_EAX_ITLB_ENTRIES(descs[0]);
192 		cai->cai_associativity = AMD_L1_EAX_ITLB_ASSOC(descs[0]);
193 		cai->cai_linesize = (4 * 1024 * 1024);
194 
195 		cai = &ci->ci_cinfo[CAI_DTLB2];
196 		cai->cai_totalsize = AMD_L1_EAX_DTLB_ENTRIES(descs[0]);
197 		cai->cai_associativity = AMD_L1_EAX_DTLB_ASSOC(descs[0]);
198 		cai->cai_linesize = (4 * 1024 * 1024);
199 	}
200 
201 	cai = &ci->ci_cinfo[CAI_ITLB];
202 	cai->cai_totalsize = AMD_L1_EBX_ITLB_ENTRIES(descs[1]);
203 	cai->cai_associativity = AMD_L1_EBX_ITLB_ASSOC(descs[1]);
204 	cai->cai_linesize = (4 * 1024);
205 
206 	cai = &ci->ci_cinfo[CAI_DTLB];
207 	cai->cai_totalsize = AMD_L1_EBX_DTLB_ENTRIES(descs[1]);
208 	cai->cai_associativity = AMD_L1_EBX_DTLB_ASSOC(descs[1]);
209 	cai->cai_linesize = (4 * 1024);
210 
211 	cai = &ci->ci_cinfo[CAI_DCACHE];
212 	cai->cai_totalsize = AMD_L1_ECX_DC_SIZE(descs[2]);
213 	cai->cai_associativity = AMD_L1_ECX_DC_ASSOC(descs[2]);
214 	cai->cai_linesize = AMD_L1_EDX_IC_LS(descs[2]);
215 
216 	cai = &ci->ci_cinfo[CAI_ICACHE];
217 	cai->cai_totalsize = AMD_L1_EDX_IC_SIZE(descs[3]);
218 	cai->cai_associativity = AMD_L1_EDX_IC_ASSOC(descs[3]);
219 	cai->cai_linesize = AMD_L1_EDX_IC_LS(descs[3]);
220 
221 	/*
222 	 * Determine L2 cache/TLB info.
223 	 */
224 	if (ci->ci_pnfeatset < 0x80000006) {
225 		/* No L2 cache info available. */
226 		return;
227 	}
228 
229 	CPUID(0x80000006, descs[0], descs[1], descs[2], descs[3]);
230 	ci->ci_extcacheinfo[0] = descs[0];
231 	ci->ci_extcacheinfo[1] = descs[1];
232 	ci->ci_extcacheinfo[2] = descs[2];
233 	ci->ci_extcacheinfo[3] = descs[3];
234 
235 	cai = &ci->ci_cinfo[CAI_L2CACHE];
236 	cai->cai_totalsize = AMD_L2_ECX_C_SIZE(descs[2]);
237 	cai->cai_associativity = AMD_L2_ECX_C_ASSOC(descs[2]);
238 	cai->cai_linesize = AMD_L2_ECX_C_LS(descs[2]);
239 
240 	cp = cache_info_lookup(amd_cpuid_l2cache_assoc_info,
241 	    cai->cai_associativity);
242 	if (cp != NULL)
243 		cai->cai_associativity = cp->cai_associativity;
244 	else
245 		cai->cai_associativity = 0;	/* XXX Unknown/reserved */
246 
247 	/*
248 	 * Determine L3 cache, Intel is different
249 	 */
250 	if (!strcmp(cpu_vendor, "AuthenticAMD") && family >= 0xf) {
251 		cai = &ci->ci_cinfo[CAI_L3CACHE];
252 		cai->cai_totalsize = AMD_L3_EDX_C_SIZE(descs[3]);
253 		cai->cai_associativity = AMD_L3_EDX_C_ASSOC(descs[3]);
254 		cai->cai_linesize = AMD_L3_EDX_C_LS(descs[3]);
255 		cp = cache_info_lookup(amd_cpuid_l2cache_assoc_info,
256 		    cai->cai_associativity);
257 		if (cp != NULL)
258 			cai->cai_associativity = cp->cai_associativity;
259 		else
260 			cai->cai_associativity = 0;	/* XXX Unknown/reserved */
261 	}
262 }
263 
264 void
265 x86_print_cacheinfo(struct cpu_info *ci)
266 {
267 	char *sep;
268 
269 	sep = print_cache_config(ci, CAI_ICACHE, "I-cache", NULL);
270 	sep = print_cache_config(ci, CAI_DCACHE, "D-cache", sep);
271 	sep = print_cache_config(ci, CAI_L2CACHE, "L2 cache", sep);
272 	sep = print_cache_config(ci, CAI_L3CACHE, "L3 cache", sep);
273 	if (sep != NULL)
274 		printf("\n");
275 	sep = print_tlb_config(ci, CAI_ITLB, "ITLB", NULL);
276 	sep = print_tlb_config(ci, CAI_ITLB2, NULL, sep);
277 	if (sep != NULL)
278 		printf("\n");
279 	sep = print_tlb_config(ci, CAI_DTLB, "DTLB", NULL);
280 	sep = print_tlb_config(ci, CAI_DTLB2, NULL, sep);
281 	if (sep != NULL)
282 		printf("\n");
283 }
284