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