| Commit | Line | Data |
|---|---|---|
| c8fe38ae MD |
1 | /*- |
| 2 | * Copyright (c) 1992 Terrence R. Lambert. | |
| 3 | * Copyright (c) 1982, 1987, 1990 The Regents of the University of California. | |
| 4 | * Copyright (c) 1997 KATO Takenori. | |
| 5 | * Copyright (c) 2008 The DragonFly Project. | |
| 6 | * All rights reserved. | |
| 7 | * | |
| 8 | * This code is derived from software contributed to Berkeley by | |
| 9 | * William Jolitz. | |
| 10 | * | |
| 11 | * Redistribution and use in source and binary forms, with or without | |
| 12 | * modification, are permitted provided that the following conditions | |
| 13 | * are met: | |
| 14 | * 1. Redistributions of source code must retain the above copyright | |
| 15 | * notice, this list of conditions and the following disclaimer. | |
| 16 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 17 | * notice, this list of conditions and the following disclaimer in the | |
| 18 | * documentation and/or other materials provided with the distribution. | |
| 19 | * 3. All advertising materials mentioning features or use of this software | |
| 20 | * must display the following acknowledgement: | |
| 21 | * This product includes software developed by the University of | |
| 22 | * California, Berkeley and its contributors. | |
| 23 | * 4. Neither the name of the University nor the names of its contributors | |
| 24 | * may be used to endorse or promote products derived from this software | |
| 25 | * without specific prior written permission. | |
| 26 | * | |
| 27 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
| 28 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 29 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| 30 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
| 31 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| 32 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
| 33 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| 35 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
| 36 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 37 | * SUCH DAMAGE. | |
| 38 | * | |
| 39 | * from: Id: machdep.c,v 1.193 1996/06/18 01:22:04 bde Exp | |
| 9e3d0133 | 40 | * $DragonFly: src/sys/platform/pc64/amd64/identcpu.c,v 1.2 2008/11/24 13:14:21 swildner Exp $ |
| c8fe38ae MD |
41 | */ |
| 42 | ||
| 43 | #include "opt_cpu.h" | |
| 44 | ||
| 45 | #include <sys/param.h> | |
| 46 | #include <sys/bus.h> | |
| 47 | #if JG | |
| 48 | #include <sys/cpu.h> | |
| 49 | #endif | |
| 50 | #include <sys/eventhandler.h> | |
| 51 | #include <sys/systm.h> | |
| 52 | #include <sys/kernel.h> | |
| 53 | #include <sys/sysctl.h> | |
| 54 | #include <sys/power.h> | |
| 55 | ||
| 56 | #include <machine/asmacros.h> | |
| 57 | #include <machine/clock.h> | |
| 58 | #include <machine/cputypes.h> | |
| 59 | #include <machine/frame.h> | |
| 46d4e165 | 60 | #include <machine_base/isa/intr_machdep.h> |
| c8fe38ae MD |
61 | #include <machine/segments.h> |
| 62 | #include <machine/specialreg.h> | |
| 63 | #include <machine/md_var.h> | |
| 64 | ||
| 65 | #if JG | |
| 66 | #include <amd64/isa/icu.h> | |
| 67 | #endif | |
| 68 | ||
| 69 | /* XXX - should be in header file: */ | |
| 70 | void printcpuinfo(void); | |
| 71 | void identify_cpu(void); | |
| 72 | void earlysetcpuclass(void); | |
| 73 | void panicifcpuunsupported(void); | |
| 74 | ||
| 75 | static void print_AMD_info(void); | |
| 76 | static void print_AMD_assoc(int i); | |
| 77 | ||
| 78 | int cpu_class; | |
| 79 | char machine[] = "amd64"; | |
| 80 | SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, | |
| 81 | machine, 0, "Machine class"); | |
| 82 | ||
| 83 | static char cpu_model[128]; | |
| 84 | SYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD, | |
| 85 | cpu_model, 0, "Machine model"); | |
| 86 | ||
| 87 | static int hw_clockrate; | |
| 88 | SYSCTL_INT(_hw, OID_AUTO, clockrate, CTLFLAG_RD, | |
| 89 | &hw_clockrate, 0, "CPU instruction clock rate"); | |
| 90 | ||
| 91 | static char cpu_brand[48]; | |
| 92 | ||
| 93 | static struct { | |
| 94 | char *cpu_name; | |
| 95 | int cpu_class; | |
| 96 | } amd64_cpus[] = { | |
| e774ca6d MD |
97 | { "Clawhammer", CPUCLASS_386 }, /* CPU_CLAWHAMMER */ |
| 98 | { "Sledgehammer", CPUCLASS_386 }, /* CPU_SLEDGEHAMMER */ | |
| c8fe38ae MD |
99 | }; |
| 100 | ||
| 101 | int cpu_cores; | |
| 102 | int cpu_logical; | |
| 103 | ||
| 104 | ||
| 105 | extern int pq_l2size; | |
| 106 | extern int pq_l2nways; | |
| 107 | ||
| 108 | void | |
| 109 | printcpuinfo(void) | |
| 110 | { | |
| 111 | u_int regs[4], i; | |
| 112 | char *brand; | |
| 113 | ||
| 114 | cpu_class = amd64_cpus[cpu].cpu_class; | |
| 115 | kprintf("CPU: "); | |
| 116 | strncpy(cpu_model, amd64_cpus[cpu].cpu_name, sizeof (cpu_model)); | |
| 117 | ||
| 118 | /* Check for extended CPUID information and a processor name. */ | |
| 119 | if (cpu_exthigh >= 0x80000004) { | |
| 120 | brand = cpu_brand; | |
| 121 | for (i = 0x80000002; i < 0x80000005; i++) { | |
| 122 | do_cpuid(i, regs); | |
| 123 | memcpy(brand, regs, sizeof(regs)); | |
| 124 | brand += sizeof(regs); | |
| 125 | } | |
| 126 | } | |
| 127 | ||
| 128 | if (strcmp(cpu_vendor, "GenuineIntel") == 0) { | |
| 129 | /* Please make up your mind folks! */ | |
| 130 | strcat(cpu_model, "EM64T"); | |
| 131 | } else if (strcmp(cpu_vendor, "AuthenticAMD") == 0) { | |
| 132 | /* | |
| 133 | * Values taken from AMD Processor Recognition | |
| 134 | * http://www.amd.com/K6/k6docs/pdf/20734g.pdf | |
| 135 | * (also describes ``Features'' encodings. | |
| 136 | */ | |
| 137 | strcpy(cpu_model, "AMD "); | |
| 138 | switch (cpu_id & 0xF00) { | |
| 139 | case 0xf00: | |
| 140 | strcat(cpu_model, "AMD64 Processor"); | |
| 141 | break; | |
| 142 | default: | |
| 143 | strcat(cpu_model, "Unknown"); | |
| 144 | break; | |
| 145 | } | |
| 146 | } | |
| 147 | ||
| 148 | /* | |
| 149 | * Replace cpu_model with cpu_brand minus leading spaces if | |
| 150 | * we have one. | |
| 151 | */ | |
| 152 | brand = cpu_brand; | |
| 153 | while (*brand == ' ') | |
| 154 | ++brand; | |
| 155 | if (*brand != '\0') | |
| 156 | strcpy(cpu_model, brand); | |
| 157 | ||
| 158 | kprintf("%s (", cpu_model); | |
| 159 | switch(cpu_class) { | |
| e774ca6d | 160 | case CPUCLASS_386: |
| c8fe38ae MD |
161 | #if JG |
| 162 | hw_clockrate = (tsc_freq + 5000) / 1000000; | |
| 163 | kprintf("%jd.%02d-MHz ", | |
| 164 | (intmax_t)(tsc_freq + 4999) / 1000000, | |
| 165 | (u_int)((tsc_freq + 4999) / 10000) % 100); | |
| 166 | #endif | |
| 167 | kprintf("K8"); | |
| 168 | break; | |
| 169 | default: | |
| 170 | kprintf("Unknown"); /* will panic below... */ | |
| 171 | } | |
| 172 | kprintf("-class CPU)\n"); | |
| 173 | if(*cpu_vendor) | |
| 174 | kprintf(" Origin = \"%s\"",cpu_vendor); | |
| 175 | if(cpu_id) | |
| 176 | kprintf(" Id = 0x%x", cpu_id); | |
| 177 | ||
| 178 | if (strcmp(cpu_vendor, "GenuineIntel") == 0 || | |
| 179 | strcmp(cpu_vendor, "AuthenticAMD") == 0) { | |
| 180 | kprintf(" Stepping = %u", cpu_id & 0xf); | |
| 181 | if (cpu_high > 0) { | |
| 182 | u_int cmp = 1, htt = 1; | |
| 183 | ||
| 184 | /* | |
| 185 | * Here we should probably set up flags indicating | |
| 186 | * whether or not various features are available. | |
| 187 | * The interesting ones are probably VME, PSE, PAE, | |
| 188 | * and PGE. The code already assumes without bothering | |
| 189 | * to check that all CPUs >= Pentium have a TSC and | |
| 190 | * MSRs. | |
| 191 | */ | |
| 192 | kprintf("\n Features=0x%b", cpu_feature, | |
| 193 | "\020" | |
| 194 | "\001FPU" /* Integral FPU */ | |
| 195 | "\002VME" /* Extended VM86 mode support */ | |
| 196 | "\003DE" /* Debugging Extensions (CR4.DE) */ | |
| 197 | "\004PSE" /* 4MByte page tables */ | |
| 198 | "\005TSC" /* Timestamp counter */ | |
| 199 | "\006MSR" /* Machine specific registers */ | |
| 200 | "\007PAE" /* Physical address extension */ | |
| 201 | "\010MCE" /* Machine Check support */ | |
| 202 | "\011CX8" /* CMPEXCH8 instruction */ | |
| 203 | "\012APIC" /* SMP local APIC */ | |
| 204 | "\013oldMTRR" /* Previous implementation of MTRR */ | |
| 205 | "\014SEP" /* Fast System Call */ | |
| 206 | "\015MTRR" /* Memory Type Range Registers */ | |
| 207 | "\016PGE" /* PG_G (global bit) support */ | |
| 208 | "\017MCA" /* Machine Check Architecture */ | |
| 209 | "\020CMOV" /* CMOV instruction */ | |
| 210 | "\021PAT" /* Page attributes table */ | |
| 211 | "\022PSE36" /* 36 bit address space support */ | |
| 212 | "\023PN" /* Processor Serial number */ | |
| 213 | "\024CLFLUSH" /* Has the CLFLUSH instruction */ | |
| 214 | "\025<b20>" | |
| 215 | "\026DTS" /* Debug Trace Store */ | |
| 216 | "\027ACPI" /* ACPI support */ | |
| 217 | "\030MMX" /* MMX instructions */ | |
| 218 | "\031FXSR" /* FXSAVE/FXRSTOR */ | |
| 219 | "\032SSE" /* Streaming SIMD Extensions */ | |
| 220 | "\033SSE2" /* Streaming SIMD Extensions #2 */ | |
| 221 | "\034SS" /* Self snoop */ | |
| 222 | "\035HTT" /* Hyperthreading (see EBX bit 16-23) */ | |
| 223 | "\036TM" /* Thermal Monitor clock slowdown */ | |
| 224 | "\037IA64" /* CPU can execute IA64 instructions */ | |
| 225 | "\040PBE" /* Pending Break Enable */ | |
| 226 | ); | |
| 227 | ||
| 228 | if (cpu_feature2 != 0) { | |
| 229 | kprintf("\n Features2=0x%b", cpu_feature2, | |
| 230 | "\020" | |
| 231 | "\001SSE3" /* SSE3 */ | |
| 232 | "\002<b1>" | |
| 233 | "\003DTES64" /* 64-bit Debug Trace */ | |
| 234 | "\004MON" /* MONITOR/MWAIT Instructions */ | |
| 235 | "\005DS_CPL" /* CPL Qualified Debug Store */ | |
| 236 | "\006VMX" /* Virtual Machine Extensions */ | |
| 237 | "\007SMX" /* Safer Mode Extensions */ | |
| 238 | "\010EST" /* Enhanced SpeedStep */ | |
| 239 | "\011TM2" /* Thermal Monitor 2 */ | |
| 240 | "\012SSSE3" /* SSSE3 */ | |
| 241 | "\013CNXT-ID" /* L1 context ID available */ | |
| 242 | "\014<b11>" | |
| 243 | "\015<b12>" | |
| 244 | "\016CX16" /* CMPXCHG16B Instruction */ | |
| 245 | "\017xTPR" /* Send Task Priority Messages*/ | |
| 246 | "\020PDCM" /* Perf/Debug Capability MSR */ | |
| 247 | "\021<b16>" | |
| 248 | "\022<b17>" | |
| 249 | "\023DCA" /* Direct Cache Access */ | |
| 250 | "\024SSE4.1" | |
| 251 | "\025SSE4.2" | |
| 252 | "\026x2APIC" /* xAPIC Extensions */ | |
| 33a33a56 | 253 | "\027MOVBE" /* MOVBE instruction */ |
| c8fe38ae MD |
254 | "\030POPCNT" |
| 255 | "\031<b24>" | |
| 256 | "\032<b25>" | |
| 9e3d0133 SW |
257 | "\033XSAVE" |
| 258 | "\034OSXSAVE" | |
| c8fe38ae MD |
259 | "\035<b28>" |
| 260 | "\036<b29>" | |
| 261 | "\037<b30>" | |
| 262 | "\040<b31>" | |
| 263 | ); | |
| 264 | } | |
| 265 | ||
| 266 | /* | |
| 267 | * AMD64 Architecture Programmer's Manual Volume 3: | |
| 268 | * General-Purpose and System Instructions | |
| 269 | * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/24594.pdf | |
| 270 | * | |
| 271 | * IA-32 Intel Architecture Software Developer's Manual, | |
| 272 | * Volume 2A: Instruction Set Reference, A-M | |
| 273 | * ftp://download.intel.com/design/Pentium4/manuals/25366617.pdf | |
| 274 | */ | |
| 275 | if (amd_feature != 0) { | |
| 276 | kprintf("\n AMD Features=0x%b", amd_feature, | |
| 277 | "\020" /* in hex */ | |
| 278 | "\001<s0>" /* Same */ | |
| 279 | "\002<s1>" /* Same */ | |
| 280 | "\003<s2>" /* Same */ | |
| 281 | "\004<s3>" /* Same */ | |
| 282 | "\005<s4>" /* Same */ | |
| 283 | "\006<s5>" /* Same */ | |
| 284 | "\007<s6>" /* Same */ | |
| 285 | "\010<s7>" /* Same */ | |
| 286 | "\011<s8>" /* Same */ | |
| 287 | "\012<s9>" /* Same */ | |
| 288 | "\013<b10>" /* Undefined */ | |
| 289 | "\014SYSCALL" /* Have SYSCALL/SYSRET */ | |
| 290 | "\015<s12>" /* Same */ | |
| 291 | "\016<s13>" /* Same */ | |
| 292 | "\017<s14>" /* Same */ | |
| 293 | "\020<s15>" /* Same */ | |
| 294 | "\021<s16>" /* Same */ | |
| 295 | "\022<s17>" /* Same */ | |
| 296 | "\023<b18>" /* Reserved, unknown */ | |
| 297 | "\024MP" /* Multiprocessor Capable */ | |
| 298 | "\025NX" /* Has EFER.NXE, NX */ | |
| 299 | "\026<b21>" /* Undefined */ | |
| 300 | "\027MMX+" /* AMD MMX Extensions */ | |
| 301 | "\030<s23>" /* Same */ | |
| 302 | "\031<s24>" /* Same */ | |
| 303 | "\032FFXSR" /* Fast FXSAVE/FXRSTOR */ | |
| 304 | "\033Page1GB" /* 1-GB large page support */ | |
| 305 | "\034RDTSCP" /* RDTSCP */ | |
| 306 | "\035<b28>" /* Undefined */ | |
| 307 | "\036LM" /* 64 bit long mode */ | |
| 308 | "\0373DNow!+" /* AMD 3DNow! Extensions */ | |
| 309 | "\0403DNow!" /* AMD 3DNow! */ | |
| 310 | ); | |
| 311 | } | |
| 312 | ||
| 313 | if (amd_feature2 != 0) { | |
| 314 | kprintf("\n AMD Features2=0x%b", amd_feature2, | |
| 315 | "\020" | |
| 316 | "\001LAHF" /* LAHF/SAHF in long mode */ | |
| 317 | "\002CMP" /* CMP legacy */ | |
| 318 | "\003SVM" /* Secure Virtual Mode */ | |
| 319 | "\004ExtAPIC" /* Extended APIC register */ | |
| 320 | "\005CR8" /* CR8 in legacy mode */ | |
| 321 | "\006<b5>" | |
| 322 | "\007<b6>" | |
| 323 | "\010<b7>" | |
| 324 | "\011Prefetch" /* 3DNow! Prefetch/PrefetchW */ | |
| 325 | "\012<b9>" | |
| 326 | "\013<b10>" | |
| 327 | "\014<b11>" | |
| 328 | "\015<b12>" | |
| 329 | "\016<b13>" | |
| 330 | "\017<b14>" | |
| 331 | "\020<b15>" | |
| 332 | "\021<b16>" | |
| 333 | "\022<b17>" | |
| 334 | "\023<b18>" | |
| 335 | "\024<b19>" | |
| 336 | "\025<b20>" | |
| 337 | "\026<b21>" | |
| 338 | "\027<b22>" | |
| 339 | "\030<b23>" | |
| 340 | "\031<b24>" | |
| 341 | "\032<b25>" | |
| 342 | "\033<b26>" | |
| 343 | "\034<b27>" | |
| 344 | "\035<b28>" | |
| 345 | "\036<b29>" | |
| 346 | "\037<b30>" | |
| 347 | "\040<b31>" | |
| 348 | ); | |
| 349 | } | |
| 350 | ||
| 351 | if (cpu_feature & CPUID_HTT && strcmp(cpu_vendor, | |
| 352 | "AuthenticAMD") == 0) | |
| 353 | cpu_feature &= ~CPUID_HTT; | |
| 354 | ||
| 355 | /* | |
| 356 | * If this CPU supports HTT or CMP then mention the | |
| 357 | * number of physical/logical cores it contains. | |
| 358 | */ | |
| 359 | if (cpu_feature & CPUID_HTT) | |
| 360 | htt = (cpu_procinfo & CPUID_HTT_CORES) >> 16; | |
| 361 | if (strcmp(cpu_vendor, "AuthenticAMD") == 0 && | |
| 362 | (amd_feature2 & AMDID2_CMP)) | |
| 363 | cmp = (cpu_procinfo2 & AMDID_CMP_CORES) + 1; | |
| 364 | else if (strcmp(cpu_vendor, "GenuineIntel") == 0 && | |
| 365 | (cpu_high >= 4)) { | |
| 366 | cpuid_count(4, 0, regs); | |
| 367 | if ((regs[0] & 0x1f) != 0) | |
| 368 | cmp = ((regs[0] >> 26) & 0x3f) + 1; | |
| 369 | } | |
| 370 | cpu_cores = cmp; | |
| 371 | cpu_logical = htt / cmp; | |
| 372 | if (cmp > 1) | |
| 373 | kprintf("\n Cores per package: %d", cmp); | |
| 374 | if ((htt / cmp) > 1) | |
| 375 | kprintf("\n Logical CPUs per core: %d", | |
| 376 | cpu_logical); | |
| 377 | } | |
| 378 | } | |
| 379 | /* Avoid ugly blank lines: only print newline when we have to. */ | |
| 380 | if (*cpu_vendor || cpu_id) | |
| 381 | kprintf("\n"); | |
| 382 | ||
| 383 | if (!bootverbose) | |
| 384 | return; | |
| 385 | ||
| 386 | if (strcmp(cpu_vendor, "AuthenticAMD") == 0) | |
| 387 | print_AMD_info(); | |
| 388 | } | |
| 389 | ||
| 390 | void | |
| 391 | panicifcpuunsupported(void) | |
| 392 | { | |
| 393 | ||
| 394 | #ifndef HAMMER_CPU | |
| 395 | #error "You need to specify a cpu type" | |
| 396 | #endif | |
| 397 | /* | |
| 398 | * Now that we have told the user what they have, | |
| 399 | * let them know if that machine type isn't configured. | |
| 400 | */ | |
| 401 | switch (cpu_class) { | |
| e774ca6d MD |
402 | /* |
| 403 | * A 286 and 386 should not make it this far, anyway. | |
| 404 | */ | |
| 405 | case CPUCLASS_286: | |
| 406 | case CPUCLASS_386: | |
| 407 | #if !defined(I486_CPU) | |
| 408 | case CPUCLASS_486: | |
| 409 | #endif | |
| 410 | #if !defined(I586_CPU) | |
| 411 | case CPUCLASS_586: | |
| 412 | #endif | |
| 413 | #if !defined(I686_CPU) | |
| 414 | case CPUCLASS_686: | |
| c8fe38ae MD |
415 | #endif |
| 416 | panic("CPU class not configured"); | |
| 417 | default: | |
| 418 | break; | |
| 419 | } | |
| 420 | } | |
| 421 | ||
| 422 | ||
| 423 | #if JG | |
| 424 | /* Update TSC freq with the value indicated by the caller. */ | |
| 425 | static void | |
| 426 | tsc_freq_changed(void *arg, const struct cf_level *level, int status) | |
| 427 | { | |
| 428 | /* If there was an error during the transition, don't do anything. */ | |
| 429 | if (status != 0) | |
| 430 | return; | |
| 431 | ||
| 432 | /* Total setting for this level gives the new frequency in MHz. */ | |
| 433 | hw_clockrate = level->total_set.freq; | |
| 434 | } | |
| 435 | ||
| 436 | EVENTHANDLER_DEFINE(cpufreq_post_change, tsc_freq_changed, NULL, | |
| 437 | EVENTHANDLER_PRI_ANY); | |
| 438 | #endif | |
| 439 | ||
| 440 | /* | |
| 441 | * Final stage of CPU identification. -- Should I check TI? | |
| 442 | */ | |
| 443 | void | |
| 444 | identify_cpu(void) | |
| 445 | { | |
| 446 | u_int regs[4]; | |
| 447 | ||
| 448 | do_cpuid(0, regs); | |
| 449 | cpu_high = regs[0]; | |
| 450 | ((u_int *)&cpu_vendor)[0] = regs[1]; | |
| 451 | ((u_int *)&cpu_vendor)[1] = regs[3]; | |
| 452 | ((u_int *)&cpu_vendor)[2] = regs[2]; | |
| 453 | cpu_vendor[12] = '\0'; | |
| 454 | ||
| 455 | do_cpuid(1, regs); | |
| 456 | cpu_id = regs[0]; | |
| 457 | cpu_procinfo = regs[1]; | |
| 458 | cpu_feature = regs[3]; | |
| 459 | cpu_feature2 = regs[2]; | |
| 460 | ||
| 461 | if (strcmp(cpu_vendor, "GenuineIntel") == 0 || | |
| 462 | strcmp(cpu_vendor, "AuthenticAMD") == 0) { | |
| 463 | do_cpuid(0x80000000, regs); | |
| 464 | cpu_exthigh = regs[0]; | |
| 465 | } | |
| 466 | if (cpu_exthigh >= 0x80000001) { | |
| 467 | do_cpuid(0x80000001, regs); | |
| 468 | amd_feature = regs[3] & ~(cpu_feature & 0x0183f3ff); | |
| 469 | amd_feature2 = regs[2]; | |
| 470 | } | |
| 471 | if (cpu_exthigh >= 0x80000008) { | |
| 472 | do_cpuid(0x80000008, regs); | |
| 473 | cpu_procinfo2 = regs[2]; | |
| 474 | } | |
| 475 | ||
| 476 | /* XXX */ | |
| e774ca6d | 477 | cpu = CPU_386SX; |
| c8fe38ae MD |
478 | } |
| 479 | ||
| 480 | static void | |
| 481 | print_AMD_assoc(int i) | |
| 482 | { | |
| 483 | if (i == 255) | |
| 484 | kprintf(", fully associative\n"); | |
| 485 | else | |
| 486 | kprintf(", %d-way associative\n", i); | |
| 487 | } | |
| 488 | ||
| 489 | static void | |
| 490 | print_AMD_l2_assoc(int i) | |
| 491 | { | |
| 492 | switch (i & 0x0f) { | |
| 493 | case 0: kprintf(", disabled/not present\n"); break; | |
| 494 | case 1: kprintf(", direct mapped\n"); break; | |
| 495 | case 2: kprintf(", 2-way associative\n"); break; | |
| 496 | case 4: kprintf(", 4-way associative\n"); break; | |
| 497 | case 6: kprintf(", 8-way associative\n"); break; | |
| 498 | case 8: kprintf(", 16-way associative\n"); break; | |
| 499 | case 15: kprintf(", fully associative\n"); break; | |
| 500 | default: kprintf(", reserved configuration\n"); break; | |
| 501 | } | |
| 502 | } | |
| 503 | ||
| 504 | static void | |
| 505 | print_AMD_info(void) | |
| 506 | { | |
| 507 | u_int regs[4]; | |
| 508 | ||
| 509 | if (cpu_exthigh < 0x80000005) | |
| 510 | return; | |
| 511 | ||
| 512 | do_cpuid(0x80000005, regs); | |
| 513 | kprintf("L1 2MB data TLB: %d entries", (regs[0] >> 16) & 0xff); | |
| 514 | print_AMD_assoc(regs[0] >> 24); | |
| 515 | ||
| 516 | kprintf("L1 2MB instruction TLB: %d entries", regs[0] & 0xff); | |
| 517 | print_AMD_assoc((regs[0] >> 8) & 0xff); | |
| 518 | ||
| 519 | kprintf("L1 4KB data TLB: %d entries", (regs[1] >> 16) & 0xff); | |
| 520 | print_AMD_assoc(regs[1] >> 24); | |
| 521 | ||
| 522 | kprintf("L1 4KB instruction TLB: %d entries", regs[1] & 0xff); | |
| 523 | print_AMD_assoc((regs[1] >> 8) & 0xff); | |
| 524 | ||
| 525 | kprintf("L1 data cache: %d kbytes", regs[2] >> 24); | |
| 526 | kprintf(", %d bytes/line", regs[2] & 0xff); | |
| 527 | kprintf(", %d lines/tag", (regs[2] >> 8) & 0xff); | |
| 528 | print_AMD_assoc((regs[2] >> 16) & 0xff); | |
| 529 | ||
| 530 | kprintf("L1 instruction cache: %d kbytes", regs[3] >> 24); | |
| 531 | kprintf(", %d bytes/line", regs[3] & 0xff); | |
| 532 | kprintf(", %d lines/tag", (regs[3] >> 8) & 0xff); | |
| 533 | print_AMD_assoc((regs[3] >> 16) & 0xff); | |
| 534 | ||
| 535 | if (cpu_exthigh >= 0x80000006) { | |
| 536 | do_cpuid(0x80000006, regs); | |
| 537 | if ((regs[0] >> 16) != 0) { | |
| 538 | kprintf("L2 2MB data TLB: %d entries", | |
| 539 | (regs[0] >> 16) & 0xfff); | |
| 540 | print_AMD_l2_assoc(regs[0] >> 28); | |
| 541 | kprintf("L2 2MB instruction TLB: %d entries", | |
| 542 | regs[0] & 0xfff); | |
| 543 | print_AMD_l2_assoc((regs[0] >> 28) & 0xf); | |
| 544 | } else { | |
| 545 | kprintf("L2 2MB unified TLB: %d entries", | |
| 546 | regs[0] & 0xfff); | |
| 547 | print_AMD_l2_assoc((regs[0] >> 28) & 0xf); | |
| 548 | } | |
| 549 | if ((regs[1] >> 16) != 0) { | |
| 550 | kprintf("L2 4KB data TLB: %d entries", | |
| 551 | (regs[1] >> 16) & 0xfff); | |
| 552 | print_AMD_l2_assoc(regs[1] >> 28); | |
| 553 | ||
| 554 | kprintf("L2 4KB instruction TLB: %d entries", | |
| 555 | (regs[1] >> 16) & 0xfff); | |
| 556 | print_AMD_l2_assoc((regs[1] >> 28) & 0xf); | |
| 557 | } else { | |
| 558 | kprintf("L2 4KB unified TLB: %d entries", | |
| 559 | (regs[1] >> 16) & 0xfff); | |
| 560 | print_AMD_l2_assoc((regs[1] >> 28) & 0xf); | |
| 561 | } | |
| 562 | kprintf("L2 unified cache: %d kbytes", regs[2] >> 16); | |
| 563 | kprintf(", %d bytes/line", regs[2] & 0xff); | |
| 564 | kprintf(", %d lines/tag", (regs[2] >> 8) & 0x0f); | |
| 565 | print_AMD_l2_assoc((regs[2] >> 12) & 0x0f); | |
| 566 | } | |
| 567 | } |