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