xref: /openbsd-src/sys/arch/amd64/amd64/cacheinfo.c (revision 2b0358df1d88d06ef4139321dd05bd5e05d91eaf)
1 /*	$OpenBSD: cacheinfo.c,v 1.5 2009/02/16 15:50:05 jsg 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, 0x0f, 0xff },
147 	{ 0, 0x00,    0 },
148 };
149 
150 void
151 amd_cpu_cacheinfo(struct cpu_info *ci)
152 {
153 	const struct x86_cache_info *cp;
154 	struct x86_cache_info *cai;
155 	int family, model;
156 	u_int descs[4];
157 	u_int lfunc;
158 
159 	family = ci->ci_family;
160 	model = ci->ci_model;
161 
162 	/*
163 	 * K5 model 0 has none of this info.
164 	 */
165 	if (family == 5 && model == 0)
166 		return;
167 
168 	/*
169 	 * Determine the largest extended function value.
170 	 */
171 	CPUID(0x80000000, descs[0], descs[1], descs[2], descs[3]);
172 	lfunc = descs[0];
173 
174 	/*
175 	 * Determine L1 cache/TLB info.
176 	 */
177 	if (lfunc < 0x80000005) {
178 		/* No L1 cache info available. */
179 		return;
180 	}
181 
182 	CPUID(0x80000005, descs[0], descs[1], descs[2], descs[3]);
183 
184 	/*
185 	 * K6-III and higher have large page TLBs.
186 	 */
187 	if ((family == 5 && model >= 9) || family >= 6) {
188 		cai = &ci->ci_cinfo[CAI_ITLB2];
189 		cai->cai_totalsize = AMD_L1_EAX_ITLB_ENTRIES(descs[0]);
190 		cai->cai_associativity = AMD_L1_EAX_ITLB_ASSOC(descs[0]);
191 		cai->cai_linesize = (4 * 1024 * 1024);
192 
193 		cai = &ci->ci_cinfo[CAI_DTLB2];
194 		cai->cai_totalsize = AMD_L1_EAX_DTLB_ENTRIES(descs[0]);
195 		cai->cai_associativity = AMD_L1_EAX_DTLB_ASSOC(descs[0]);
196 		cai->cai_linesize = (4 * 1024 * 1024);
197 	}
198 
199 	cai = &ci->ci_cinfo[CAI_ITLB];
200 	cai->cai_totalsize = AMD_L1_EBX_ITLB_ENTRIES(descs[1]);
201 	cai->cai_associativity = AMD_L1_EBX_ITLB_ASSOC(descs[1]);
202 	cai->cai_linesize = (4 * 1024);
203 
204 	cai = &ci->ci_cinfo[CAI_DTLB];
205 	cai->cai_totalsize = AMD_L1_EBX_DTLB_ENTRIES(descs[1]);
206 	cai->cai_associativity = AMD_L1_EBX_DTLB_ASSOC(descs[1]);
207 	cai->cai_linesize = (4 * 1024);
208 
209 	cai = &ci->ci_cinfo[CAI_DCACHE];
210 	cai->cai_totalsize = AMD_L1_ECX_DC_SIZE(descs[2]);
211 	cai->cai_associativity = AMD_L1_ECX_DC_ASSOC(descs[2]);
212 	cai->cai_linesize = AMD_L1_EDX_IC_LS(descs[2]);
213 
214 	cai = &ci->ci_cinfo[CAI_ICACHE];
215 	cai->cai_totalsize = AMD_L1_EDX_IC_SIZE(descs[3]);
216 	cai->cai_associativity = AMD_L1_EDX_IC_ASSOC(descs[3]);
217 	cai->cai_linesize = AMD_L1_EDX_IC_LS(descs[3]);
218 
219 	/*
220 	 * Determine L2 cache/TLB info.
221 	 */
222 	if (lfunc < 0x80000006) {
223 		/* No L2 cache info available. */
224 		return;
225 	}
226 
227 	CPUID(0x80000006, descs[0], descs[1], descs[2], descs[3]);
228 
229 	cai = &ci->ci_cinfo[CAI_L2CACHE];
230 	cai->cai_totalsize = AMD_L2_ECX_C_SIZE(descs[2]);
231 	cai->cai_associativity = AMD_L2_ECX_C_ASSOC(descs[2]);
232 	cai->cai_linesize = AMD_L2_ECX_C_LS(descs[2]);
233 
234 	cp = cache_info_lookup(amd_cpuid_l2cache_assoc_info,
235 	    cai->cai_associativity);
236 	if (cp != NULL)
237 		cai->cai_associativity = cp->cai_associativity;
238 	else
239 		cai->cai_associativity = 0;	/* XXX Unknown/reserved */
240 }
241 
242 void
243 x86_print_cacheinfo(struct cpu_info *ci)
244 {
245 	char *sep;
246 
247 	sep = NULL;
248 	if (ci->ci_cinfo[CAI_ICACHE].cai_totalsize != 0 ||
249 	    ci->ci_cinfo[CAI_DCACHE].cai_totalsize != 0) {
250 		sep = print_cache_config(ci, CAI_ICACHE, "I-cache", NULL);
251 		sep = print_cache_config(ci, CAI_DCACHE, "D-cache", sep);
252 	}
253 	if (ci->ci_cinfo[CAI_L2CACHE].cai_totalsize != 0) {
254 		sep = print_cache_config(ci, CAI_L2CACHE, "L2 cache", sep);
255 		if (sep != NULL)
256 			printf("\n");
257 	}
258 	if (ci->ci_cinfo[CAI_ITLB].cai_totalsize != 0) {
259 		sep = print_tlb_config(ci, CAI_ITLB, "ITLB", NULL);
260 		sep = print_tlb_config(ci, CAI_ITLB2, NULL, sep);
261 		if (sep != NULL)
262 			printf("\n");
263 	}
264 	if (ci->ci_cinfo[CAI_DTLB].cai_totalsize != 0) {
265 		sep = print_tlb_config(ci, CAI_DTLB, "DTLB", NULL);
266 		sep = print_tlb_config(ci, CAI_DTLB2, NULL, sep);
267 		if (sep != NULL)
268 			printf("\n");
269 	}
270 }
271