Share some common cache info cpuid code between i386 and x86_64.

This commit is contained in:
fvdl 2003-04-25 21:54:29 +00:00
parent 766d04f56a
commit 4b293b5851
10 changed files with 442 additions and 346 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: cpu.c,v 1.13 2003/04/01 20:54:23 thorpej Exp $ */
/* $NetBSD: cpu.c,v 1.14 2003/04/25 21:54:29 fvdl Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
@ -204,7 +204,7 @@ cpu_vm_init(struct cpu_info *ci)
int ncolors = 2, i;
for (i = CAI_ICACHE; i <= CAI_L2CACHE; i++) {
struct i386_cache_info *cai;
struct x86_cache_info *cai;
int tcolors;
cai = &ci->ci_cinfo[i];

View File

@ -1,4 +1,4 @@
/* $NetBSD: identcpu.c,v 1.2 2003/04/05 17:16:06 kent Exp $ */
/* $NetBSD: identcpu.c,v 1.3 2003/04/25 21:54:29 fvdl Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001 The NetBSD Foundation, Inc.
@ -46,8 +46,9 @@
#include <machine/specialreg.h>
#include <machine/pio.h>
#include <machine/cpu.h>
#include <x86/cacheinfo.h>
static const struct i386_cache_info
static const struct x86_cache_info
intel_cpuid_cache_info[] = {
{ CAI_ITLB, 0x01, 4, 32, 4 * 1024 },
{ CAI_ITLB2, 0x02, 0xff, 2, 4 * 1024 * 1024 },
@ -87,9 +88,6 @@ intel_cpuid_cache_info[] = {
{ 0, 0, 0, 0, 0 },
};
static const struct i386_cache_info *
cache_info_lookup(const struct i386_cache_info *cai, u_int8_t desc);
/*
* Map Brand ID from cpuid instruction to brand name.
* Source: Intel Processor Identification and the CPUID Instruction, AP-485
@ -137,7 +135,6 @@ static void amd_family6_probe __P((struct cpu_info *));
static const char *intel_family6_name __P((struct cpu_info *));
static void transmeta_cpu_info __P((struct cpu_info *));
static void amd_cpu_cacheinfo __P((struct cpu_info *));
static __inline u_char
cyrix_read_reg(u_char reg)
@ -153,83 +150,6 @@ cyrix_write_reg(u_char reg, u_char data)
outb(0x23, data);
}
static char *
print_cache_config(struct cpu_info *ci, int cache_tag, char *name, char *sep)
{
char cbuf[7];
struct i386_cache_info *cai = &ci->ci_cinfo[cache_tag];
if (cai->cai_totalsize == 0)
return sep;
if (sep == NULL)
printf("%s: ", ci->ci_dev->dv_xname);
else
printf("%s", sep);
if (name != NULL)
printf("%s ", name);
if (cai->cai_string != NULL) {
printf("%s ", cai->cai_string);
} else {
format_bytes(cbuf, sizeof(cbuf), cai->cai_totalsize);
printf("%s %db/line ", cbuf, cai->cai_linesize);
}
switch (cai->cai_associativity) {
case 0:
printf("disabled");
break;
case 1:
printf("direct-mapped");
break;
case 0xff:
printf("fully associative");
break;
default:
printf("%d-way", cai->cai_associativity);
break;
}
return ", ";
}
static char *
print_tlb_config(struct cpu_info *ci, int cache_tag, char *name, char *sep)
{
char cbuf[7];
struct i386_cache_info *cai = &ci->ci_cinfo[cache_tag];
if (cai->cai_totalsize == 0)
return sep;
if (sep == NULL)
printf("%s: ", ci->ci_dev->dv_xname);
else
printf("%s", sep);
if (name != NULL)
printf("%s ", name);
if (cai->cai_string != NULL) {
printf("%s", cai->cai_string);
} else {
format_bytes(cbuf, sizeof(cbuf), cai->cai_linesize);
printf("%d %s entries ", cai->cai_totalsize, cbuf);
switch (cai->cai_associativity) {
case 0:
printf("disabled");
break;
case 1:
printf("direct-mapped");
break;
case 0xff:
printf("fully associative");
break;
default:
printf("%d-way", cai->cai_associativity);
break;
}
}
return ", ";
}
/*
* Info for CTL_HW
*/
@ -666,11 +586,6 @@ winchip_cpu_setup(ci)
#endif
}
#define CPUID(code, eax, ebx, ecx, edx) \
__asm("cpuid" \
: "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) \
: "a" (code));
void
via_cpu_probe(struct cpu_info *ci)
{
@ -760,7 +675,7 @@ intel_family6_name(struct cpu_info *ci)
static void
cpu_probe_base_features(struct cpu_info *ci)
{
const struct i386_cache_info *cai;
const struct x86_cache_info *cai;
u_int descs[4];
int iterations, i, j;
u_int8_t desc;
@ -1116,204 +1031,6 @@ transmeta_cpu_setup(struct cpu_info *ci)
tmx86_has_longrun = 1;
}
/* ---------------------------------------------------------------------- */
static const struct i386_cache_info *
cache_info_lookup(const struct i386_cache_info *cai, u_int8_t desc)
{
int i;
for (i = 0; cai[i].cai_desc != 0; i++) {
if (cai[i].cai_desc == desc)
return (&cai[i]);
}
return (NULL);
}
/*
* AMD Cache Info:
*
* Athlon, Duron:
*
* Function 8000.0005 L1 TLB/Cache Information
* EAX -- L1 TLB 2/4MB pages
* EBX -- L1 TLB 4K pages
* ECX -- L1 D-cache
* EDX -- L1 I-cache
*
* Function 8000.0006 L2 TLB/Cache Information
* EAX -- L2 TLB 2/4MB pages
* EBX -- L2 TLB 4K pages
* ECX -- L2 Unified cache
* EDX -- reserved
*
* K5, K6:
*
* Function 8000.0005 L1 TLB/Cache Information
* EAX -- reserved
* EBX -- TLB 4K pages
* ECX -- L1 D-cache
* EDX -- L1 I-cache
*
* K6-III:
*
* Function 8000.0006 L2 Cache Information
* EAX -- reserved
* EBX -- reserved
* ECX -- L2 Unified cache
* EDX -- reserved
*/
/* L1 TLB 2/4MB pages */
#define AMD_L1_EAX_DTLB_ASSOC(x) (((x) >> 24) & 0xff)
#define AMD_L1_EAX_DTLB_ENTRIES(x) (((x) >> 16) & 0xff)
#define AMD_L1_EAX_ITLB_ASSOC(x) (((x) >> 8) & 0xff)
#define AMD_L1_EAX_ITLB_ENTRIES(x) ( (x) & 0xff)
/* L1 TLB 4K pages */
#define AMD_L1_EBX_DTLB_ASSOC(x) (((x) >> 24) & 0xff)
#define AMD_L1_EBX_DTLB_ENTRIES(x) (((x) >> 16) & 0xff)
#define AMD_L1_EBX_ITLB_ASSOC(x) (((x) >> 8) & 0xff)
#define AMD_L1_EBX_ITLB_ENTRIES(x) ( (x) & 0xff)
/* L1 Data Cache */
#define AMD_L1_ECX_DC_SIZE(x) ((((x) >> 24) & 0xff) * 1024)
#define AMD_L1_ECX_DC_ASSOC(x) (((x) >> 16) & 0xff)
#define AMD_L1_ECX_DC_LPT(x) (((x) >> 8) & 0xff)
#define AMD_L1_ECX_DC_LS(x) ( (x) & 0xff)
/* L1 Instruction Cache */
#define AMD_L1_EDX_IC_SIZE(x) ((((x) >> 24) & 0xff) * 1024)
#define AMD_L1_EDX_IC_ASSOC(x) (((x) >> 16) & 0xff)
#define AMD_L1_EDX_IC_LPT(x) (((x) >> 8) & 0xff)
#define AMD_L1_EDX_IC_LS(x) ( (x) & 0xff)
/* Note for L2 TLB -- if the upper 16 bits are 0, it is a unified TLB */
/* L2 TLB 2/4MB pages */
#define AMD_L2_EAX_DTLB_ASSOC(x) (((x) >> 28) & 0xf)
#define AMD_L2_EAX_DTLB_ENTRIES(x) (((x) >> 16) & 0xfff)
#define AMD_L2_EAX_IUTLB_ASSOC(x) (((x) >> 12) & 0xf)
#define AMD_L2_EAX_IUTLB_ENTRIES(x) ( (x) & 0xfff)
/* L2 TLB 4K pages */
#define AMD_L2_EBX_DTLB_ASSOC(x) (((x) >> 28) & 0xf)
#define AMD_L2_EBX_DTLB_ENTRIES(x) (((x) >> 16) & 0xfff)
#define AMD_L2_EBX_IUTLB_ASSOC(x) (((x) >> 12) & 0xf)
#define AMD_L2_EBX_IUTLB_ENTRIES(x) ( (x) & 0xfff)
/* L2 Cache */
#define AMD_L2_ECX_C_SIZE(x) ((((x) >> 16) & 0xffff) * 1024)
#define AMD_L2_ECX_C_ASSOC(x) (((x) >> 12) & 0xf)
#define AMD_L2_ECX_C_LPT(x) (((x) >> 8) & 0xf)
#define AMD_L2_ECX_C_LS(x) ( (x) & 0xff)
static const struct i386_cache_info amd_cpuid_l2cache_assoc_info[] = {
{ 0, 0x01, 1 },
{ 0, 0x02, 2 },
{ 0, 0x04, 4 },
{ 0, 0x06, 8 },
{ 0, 0x08, 16 },
{ 0, 0x0f, 0xff },
{ 0, 0x00, 0 },
};
void
amd_cpu_cacheinfo(struct cpu_info *ci)
{
const struct i386_cache_info *cp;
struct i386_cache_info *cai;
int family, model;
u_int descs[4];
u_int lfunc;
family = (ci->ci_signature >> 8) & 15;
if (family < CPU_MINFAMILY)
panic("amd_cpu_cacheinfo: strange family value");
model = CPUID2MODEL(ci->ci_signature);
/*
* K5 model 0 has none of this info.
*/
if (family == 5 && model == 0)
return;
/*
* Determine the largest extended function value.
*/
CPUID(0x80000000, descs[0], descs[1], descs[2], descs[3]);
lfunc = descs[0];
/*
* Determine L1 cache/TLB info.
*/
if (lfunc < 0x80000005) {
/* No L1 cache info available. */
return;
}
CPUID(0x80000005, descs[0], descs[1], descs[2], descs[3]);
/*
* K6-III and higher have large page TLBs.
*/
if ((family == 5 && model >= 9) || family >= 6) {
cai = &ci->ci_cinfo[CAI_ITLB2];
cai->cai_totalsize = AMD_L1_EAX_ITLB_ENTRIES(descs[0]);
cai->cai_associativity = AMD_L1_EAX_ITLB_ASSOC(descs[0]);
cai->cai_linesize = (4 * 1024 * 1024);
cai = &ci->ci_cinfo[CAI_DTLB2];
cai->cai_totalsize = AMD_L1_EAX_DTLB_ENTRIES(descs[0]);
cai->cai_associativity = AMD_L1_EAX_DTLB_ASSOC(descs[0]);
cai->cai_linesize = (4 * 1024 * 1024);
}
cai = &ci->ci_cinfo[CAI_ITLB];
cai->cai_totalsize = AMD_L1_EBX_ITLB_ENTRIES(descs[1]);
cai->cai_associativity = AMD_L1_EBX_ITLB_ASSOC(descs[1]);
cai->cai_linesize = (4 * 1024);
cai = &ci->ci_cinfo[CAI_DTLB];
cai->cai_totalsize = AMD_L1_EBX_DTLB_ENTRIES(descs[1]);
cai->cai_associativity = AMD_L1_EBX_DTLB_ASSOC(descs[1]);
cai->cai_linesize = (4 * 1024);
cai = &ci->ci_cinfo[CAI_DCACHE];
cai->cai_totalsize = AMD_L1_ECX_DC_SIZE(descs[2]);
cai->cai_associativity = AMD_L1_ECX_DC_ASSOC(descs[2]);
cai->cai_linesize = AMD_L1_EDX_IC_LS(descs[2]);
cai = &ci->ci_cinfo[CAI_ICACHE];
cai->cai_totalsize = AMD_L1_EDX_IC_SIZE(descs[3]);
cai->cai_associativity = AMD_L1_EDX_IC_ASSOC(descs[3]);
cai->cai_linesize = AMD_L1_EDX_IC_LS(descs[3]);
/*
* Determine L2 cache/TLB info.
*/
if (lfunc < 0x80000006) {
/* No L2 cache info available. */
return;
}
CPUID(0x80000006, descs[0], descs[1], descs[2], descs[3]);
cai = &ci->ci_cinfo[CAI_L2CACHE];
cai->cai_totalsize = AMD_L2_ECX_C_SIZE(descs[2]);
cai->cai_associativity = AMD_L2_ECX_C_ASSOC(descs[2]);
cai->cai_linesize = AMD_L2_ECX_C_LS(descs[2]);
cp = cache_info_lookup(amd_cpuid_l2cache_assoc_info,
cai->cai_associativity);
if (cp != NULL)
cai->cai_associativity = cp->cai_associativity;
else
cai->cai_associativity = 0; /* XXX Unknown/reserved */
}
static const char n_support[] __attribute__((__unused__)) =
"NOTICE: this kernel does not support %s CPU class\n";
static const char n_lower[] __attribute__((__unused__)) =
@ -1329,7 +1046,6 @@ identifycpu(struct cpu_info *ci)
const struct cpu_cpuid_family *cpufam;
char *cpuname = ci->ci_dev->dv_xname;
char buf[1024];
char *sep;
char *feature_str[3];
if (ci->ci_cpuid_level == -1) {
@ -1483,30 +1199,7 @@ identifycpu(struct cpu_info *ci)
}
}
if (ci->ci_cinfo[CAI_ICACHE].cai_totalsize != 0 ||
ci->ci_cinfo[CAI_DCACHE].cai_totalsize != 0) {
sep = print_cache_config(ci, CAI_ICACHE, "I-cache", NULL);
sep = print_cache_config(ci, CAI_DCACHE, "D-cache", sep);
if (sep != NULL)
printf("\n");
}
if (ci->ci_cinfo[CAI_L2CACHE].cai_totalsize != 0) {
sep = print_cache_config(ci, CAI_L2CACHE, "L2 cache", NULL);
if (sep != NULL)
printf("\n");
}
if (ci->ci_cinfo[CAI_ITLB].cai_totalsize != 0) {
sep = print_tlb_config(ci, CAI_ITLB, "ITLB", NULL);
sep = print_tlb_config(ci, CAI_ITLB2, NULL, sep);
if (sep != NULL)
printf("\n");
}
if (ci->ci_cinfo[CAI_DTLB].cai_totalsize != 0) {
sep = print_tlb_config(ci, CAI_DTLB, "DTLB", NULL);
sep = print_tlb_config(ci, CAI_DTLB2, NULL, sep);
if (sep != NULL)
printf("\n");
}
x86_print_cacheinfo(ci);
if (ci->ci_cpuid_level >= 3 && (ci->ci_feature_flags & CPUID_PN)) {
printf("%s: serial number %04X-%04X-%04X-%04X-%04X-%04X\n",

View File

@ -1,4 +1,4 @@
/* $NetBSD: cpu.h,v 1.99 2003/03/18 22:29:58 fvdl Exp $ */
/* $NetBSD: cpu.h,v 1.100 2003/04/25 21:54:29 fvdl Exp $ */
/*-
* Copyright (c) 1990 The Regents of the University of California.
@ -52,30 +52,12 @@
#include <machine/segments.h>
#include <machine/tss.h>
#include <machine/intrdefs.h>
#include <x86/cacheinfo.h>
#include <sys/device.h>
#include <sys/lock.h> /* will also get LOCKDEBUG */
#include <sys/sched.h>
struct i386_cache_info {
uint8_t cai_index;
uint8_t cai_desc;
uint8_t cai_associativity;
u_int cai_totalsize; /* #entries for TLB, bytes for cache */
u_int cai_linesize; /* or page size for TLB */
const char *cai_string;
};
#define CAI_ITLB 0 /* Instruction TLB (4K pages) */
#define CAI_ITLB2 1 /* Instruction TLB (2/4M pages) */
#define CAI_DTLB 2 /* Data TLB (4K pages) */
#define CAI_DTLB2 3 /* Data TLB (2/4M pages) */
#define CAI_ICACHE 4 /* Instruction cache */
#define CAI_DCACHE 5 /* Data cache */
#define CAI_L2CACHE 6 /* Level 2 cache */
#define CAI_COUNT 7
struct intrsource;
/*
@ -143,7 +125,7 @@ struct cpu_info {
struct trapframe *ci_ddb_regs;
u_int ci_cflush_lsize; /* CFLUSH insn line size */
struct i386_cache_info ci_cinfo[CAI_COUNT];
struct x86_cache_info ci_cinfo[CAI_COUNT];
/*
* Variables used by cc_microtime().

View File

@ -1,4 +1,4 @@
# $NetBSD: files.x86,v 1.5 2003/03/12 00:09:51 thorpej Exp $
# $NetBSD: files.x86,v 1.6 2003/04/25 21:54:30 fvdl Exp $
# options for MP configuration through the MP spec
defflag opt_mpbios.h MPBIOS MPVERBOSE MPDEBUG
@ -11,6 +11,7 @@ define mainbus { [apid = -1] }
file arch/x86/x86/apic.c ioapic | lapic
file arch/x86/x86/bus_dma.c
file arch/x86/x86/bus_space.c
file arch/x86/x86/cacheinfo.c
file arch/x86/x86/consinit.c
file arch/x86/x86/i8259.c
file arch/x86/x86/intr.c

View File

@ -0,0 +1,110 @@
/* $NetBSD: cacheinfo.h,v 1.1 2003/04/25 21:54:30 fvdl Exp $ */
#ifndef _X86_CACHEINFO_H
#define _X86_CACHEINFO_H
struct x86_cache_info {
uint8_t cai_index;
uint8_t cai_desc;
uint8_t cai_associativity;
u_int cai_totalsize; /* #entries for TLB, bytes for cache */
u_int cai_linesize; /* or page size for TLB */
const char *cai_string;
};
#define CAI_ITLB 0 /* Instruction TLB (4K pages) */
#define CAI_ITLB2 1 /* Instruction TLB (2/4M pages) */
#define CAI_DTLB 2 /* Data TLB (4K pages) */
#define CAI_DTLB2 3 /* Data TLB (2/4M pages) */
#define CAI_ICACHE 4 /* Instruction cache */
#define CAI_DCACHE 5 /* Data cache */
#define CAI_L2CACHE 6 /* Level 2 cache */
#define CAI_COUNT 7
struct cpu_info;
const struct x86_cache_info *cache_info_lookup(const struct x86_cache_info *,
u_int8_t);
void amd_cpu_cacheinfo(struct cpu_info *);
void x86_print_cacheinfo(struct cpu_info *);
/*
* AMD Cache Info:
*
* Athlon, Duron:
*
* Function 8000.0005 L1 TLB/Cache Information
* EAX -- L1 TLB 2/4MB pages
* EBX -- L1 TLB 4K pages
* ECX -- L1 D-cache
* EDX -- L1 I-cache
*
* Function 8000.0006 L2 TLB/Cache Information
* EAX -- L2 TLB 2/4MB pages
* EBX -- L2 TLB 4K pages
* ECX -- L2 Unified cache
* EDX -- reserved
*
* K5, K6:
*
* Function 8000.0005 L1 TLB/Cache Information
* EAX -- reserved
* EBX -- TLB 4K pages
* ECX -- L1 D-cache
* EDX -- L1 I-cache
*
* K6-III:
*
* Function 8000.0006 L2 Cache Information
* EAX -- reserved
* EBX -- reserved
* ECX -- L2 Unified cache
* EDX -- reserved
*/
/* L1 TLB 2/4MB pages */
#define AMD_L1_EAX_DTLB_ASSOC(x) (((x) >> 24) & 0xff)
#define AMD_L1_EAX_DTLB_ENTRIES(x) (((x) >> 16) & 0xff)
#define AMD_L1_EAX_ITLB_ASSOC(x) (((x) >> 8) & 0xff)
#define AMD_L1_EAX_ITLB_ENTRIES(x) ( (x) & 0xff)
/* L1 TLB 4K pages */
#define AMD_L1_EBX_DTLB_ASSOC(x) (((x) >> 24) & 0xff)
#define AMD_L1_EBX_DTLB_ENTRIES(x) (((x) >> 16) & 0xff)
#define AMD_L1_EBX_ITLB_ASSOC(x) (((x) >> 8) & 0xff)
#define AMD_L1_EBX_ITLB_ENTRIES(x) ( (x) & 0xff)
/* L1 Data Cache */
#define AMD_L1_ECX_DC_SIZE(x) ((((x) >> 24) & 0xff) * 1024)
#define AMD_L1_ECX_DC_ASSOC(x) (((x) >> 16) & 0xff)
#define AMD_L1_ECX_DC_LPT(x) (((x) >> 8) & 0xff)
#define AMD_L1_ECX_DC_LS(x) ( (x) & 0xff)
/* L1 Instruction Cache */
#define AMD_L1_EDX_IC_SIZE(x) ((((x) >> 24) & 0xff) * 1024)
#define AMD_L1_EDX_IC_ASSOC(x) (((x) >> 16) & 0xff)
#define AMD_L1_EDX_IC_LPT(x) (((x) >> 8) & 0xff)
#define AMD_L1_EDX_IC_LS(x) ( (x) & 0xff)
/* Note for L2 TLB -- if the upper 16 bits are 0, it is a unified TLB */
/* L2 TLB 2/4MB pages */
#define AMD_L2_EAX_DTLB_ASSOC(x) (((x) >> 28) & 0xf)
#define AMD_L2_EAX_DTLB_ENTRIES(x) (((x) >> 16) & 0xfff)
#define AMD_L2_EAX_IUTLB_ASSOC(x) (((x) >> 12) & 0xf)
#define AMD_L2_EAX_IUTLB_ENTRIES(x) ( (x) & 0xfff)
/* L2 TLB 4K pages */
#define AMD_L2_EBX_DTLB_ASSOC(x) (((x) >> 28) & 0xf)
#define AMD_L2_EBX_DTLB_ENTRIES(x) (((x) >> 16) & 0xfff)
#define AMD_L2_EBX_IUTLB_ASSOC(x) (((x) >> 12) & 0xf)
#define AMD_L2_EBX_IUTLB_ENTRIES(x) ( (x) & 0xfff)
/* L2 Cache */
#define AMD_L2_ECX_C_SIZE(x) ((((x) >> 16) & 0xffff) * 1024)
#define AMD_L2_ECX_C_ASSOC(x) (((x) >> 12) & 0xf)
#define AMD_L2_ECX_C_LPT(x) (((x) >> 8) & 0xf)
#define AMD_L2_ECX_C_LS(x) ( (x) & 0xff)
#endif /* _X86_CACHEINFO_H */

View File

@ -1,4 +1,4 @@
/* $NetBSD: specialreg.h,v 1.1 2003/02/26 21:26:11 fvdl Exp $ */
/* $NetBSD: specialreg.h,v 1.2 2003/04/25 21:54:30 fvdl Exp $ */
/*-
* Copyright (c) 1991 The Regents of the University of California.
@ -143,14 +143,19 @@
#define CPUID_3DNOW 0x80000000 /* 3DNow! Instructions */
#define CPUID_EXT_FLAGS2 "\20\16PGE\17MCA\20CMOV\21PAT\22PSE36\23PN" \
"\24MPC\25B20\26B21\27MMXX\30MMX"
#define CPUID_EXT_FLAGS3 "\20\31FXSR\32SSE\33B26\34B27\35B28\36B29" \
"\24MPC\25NOX\26B21\27MMXX\30MMX"
#define CPUID_EXT_FLAGS3 "\20\31FXSR\32SSE\33SSE2\34B27\35B28\36LONG" \
"\0373DNOW2\0403DNOW"
#define CPUID2FAMILY(cpuid) (((cpuid) >> 8) & 15)
#define CPUID2MODEL(cpuid) (((cpuid) >> 4) & 15)
#define CPUID2STEPPING(cpuid) ((cpuid) & 15)
#define CPUID(code, eax, ebx, ecx, edx) \
__asm("cpuid" \
: "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) \
: "a" (code));
/*
* Model-specific registers for the i386 family

View File

@ -0,0 +1,242 @@
#include <sys/types.h>
#include <sys/systm.h>
#include <sys/null.h>
#include <machine/cpu.h>
#include <machine/specialreg.h>
static char *print_cache_config(struct cpu_info *, int, char *, char *);
static char *print_tlb_config(struct cpu_info *, int, char *, char *);
static char *
print_cache_config(struct cpu_info *ci, int cache_tag, char *name, char *sep)
{
char cbuf[7];
struct x86_cache_info *cai = &ci->ci_cinfo[cache_tag];
if (cai->cai_totalsize == 0)
return sep;
if (sep == NULL)
printf("%s: ", ci->ci_dev->dv_xname);
else
printf("%s", sep);
if (name != NULL)
printf("%s ", name);
if (cai->cai_string != NULL) {
printf("%s ", cai->cai_string);
} else {
format_bytes(cbuf, sizeof(cbuf), cai->cai_totalsize);
printf("%s %db/line ", cbuf, cai->cai_linesize);
}
switch (cai->cai_associativity) {
case 0:
printf("disabled");
break;
case 1:
printf("direct-mapped");
break;
case 0xff:
printf("fully associative");
break;
default:
printf("%d-way", cai->cai_associativity);
break;
}
return ", ";
}
static char *
print_tlb_config(struct cpu_info *ci, int cache_tag, char *name, char *sep)
{
char cbuf[7];
struct x86_cache_info *cai = &ci->ci_cinfo[cache_tag];
if (cai->cai_totalsize == 0)
return sep;
if (sep == NULL)
printf("%s: ", ci->ci_dev->dv_xname);
else
printf("%s", sep);
if (name != NULL)
printf("%s ", name);
if (cai->cai_string != NULL) {
printf("%s", cai->cai_string);
} else {
format_bytes(cbuf, sizeof(cbuf), cai->cai_linesize);
printf("%d %s entries ", cai->cai_totalsize, cbuf);
switch (cai->cai_associativity) {
case 0:
printf("disabled");
break;
case 1:
printf("direct-mapped");
break;
case 0xff:
printf("fully associative");
break;
default:
printf("%d-way", cai->cai_associativity);
break;
}
}
return ", ";
}
const struct x86_cache_info *
cache_info_lookup(const struct x86_cache_info *cai, u_int8_t desc)
{
int i;
for (i = 0; cai[i].cai_desc != 0; i++) {
if (cai[i].cai_desc == desc)
return (&cai[i]);
}
return (NULL);
}
static const struct x86_cache_info amd_cpuid_l2cache_assoc_info[] = {
{ 0, 0x01, 1 },
{ 0, 0x02, 2 },
{ 0, 0x04, 4 },
{ 0, 0x06, 8 },
{ 0, 0x08, 16 },
{ 0, 0x0f, 0xff },
{ 0, 0x00, 0 },
};
void
amd_cpu_cacheinfo(struct cpu_info *ci)
{
const struct x86_cache_info *cp;
struct x86_cache_info *cai;
int family, model;
u_int descs[4];
u_int lfunc;
family = (ci->ci_signature >> 8) & 15;
model = CPUID2MODEL(ci->ci_signature);
/*
* K5 model 0 has none of this info.
*/
if (family == 5 && model == 0)
return;
/*
* Get extended values for K8 and up.
*/
if (family == 0xf) {
family += (ci->ci_signature >> 20) & 0xff;
model += (ci->ci_signature >> 16) & 0xf;
}
/*
* Determine the largest extended function value.
*/
CPUID(0x80000000, descs[0], descs[1], descs[2], descs[3]);
lfunc = descs[0];
/*
* Determine L1 cache/TLB info.
*/
if (lfunc < 0x80000005) {
/* No L1 cache info available. */
return;
}
CPUID(0x80000005, descs[0], descs[1], descs[2], descs[3]);
/*
* K6-III and higher have large page TLBs.
*/
if ((family == 5 && model >= 9) || family >= 6) {
cai = &ci->ci_cinfo[CAI_ITLB2];
cai->cai_totalsize = AMD_L1_EAX_ITLB_ENTRIES(descs[0]);
cai->cai_associativity = AMD_L1_EAX_ITLB_ASSOC(descs[0]);
cai->cai_linesize = (4 * 1024 * 1024);
cai = &ci->ci_cinfo[CAI_DTLB2];
cai->cai_totalsize = AMD_L1_EAX_DTLB_ENTRIES(descs[0]);
cai->cai_associativity = AMD_L1_EAX_DTLB_ASSOC(descs[0]);
cai->cai_linesize = (4 * 1024 * 1024);
}
cai = &ci->ci_cinfo[CAI_ITLB];
cai->cai_totalsize = AMD_L1_EBX_ITLB_ENTRIES(descs[1]);
cai->cai_associativity = AMD_L1_EBX_ITLB_ASSOC(descs[1]);
cai->cai_linesize = (4 * 1024);
cai = &ci->ci_cinfo[CAI_DTLB];
cai->cai_totalsize = AMD_L1_EBX_DTLB_ENTRIES(descs[1]);
cai->cai_associativity = AMD_L1_EBX_DTLB_ASSOC(descs[1]);
cai->cai_linesize = (4 * 1024);
cai = &ci->ci_cinfo[CAI_DCACHE];
cai->cai_totalsize = AMD_L1_ECX_DC_SIZE(descs[2]);
cai->cai_associativity = AMD_L1_ECX_DC_ASSOC(descs[2]);
cai->cai_linesize = AMD_L1_EDX_IC_LS(descs[2]);
cai = &ci->ci_cinfo[CAI_ICACHE];
cai->cai_totalsize = AMD_L1_EDX_IC_SIZE(descs[3]);
cai->cai_associativity = AMD_L1_EDX_IC_ASSOC(descs[3]);
cai->cai_linesize = AMD_L1_EDX_IC_LS(descs[3]);
/*
* Determine L2 cache/TLB info.
*/
if (lfunc < 0x80000006) {
/* No L2 cache info available. */
return;
}
CPUID(0x80000006, descs[0], descs[1], descs[2], descs[3]);
cai = &ci->ci_cinfo[CAI_L2CACHE];
cai->cai_totalsize = AMD_L2_ECX_C_SIZE(descs[2]);
cai->cai_associativity = AMD_L2_ECX_C_ASSOC(descs[2]);
cai->cai_linesize = AMD_L2_ECX_C_LS(descs[2]);
cp = cache_info_lookup(amd_cpuid_l2cache_assoc_info,
cai->cai_associativity);
if (cp != NULL)
cai->cai_associativity = cp->cai_associativity;
else
cai->cai_associativity = 0; /* XXX Unknown/reserved */
}
void
x86_print_cacheinfo(struct cpu_info *ci)
{
char *sep;
if (ci->ci_cinfo[CAI_ICACHE].cai_totalsize != 0 ||
ci->ci_cinfo[CAI_DCACHE].cai_totalsize != 0) {
sep = print_cache_config(ci, CAI_ICACHE, "I-cache", NULL);
sep = print_cache_config(ci, CAI_DCACHE, "D-cache", sep);
if (sep != NULL)
printf("\n");
}
if (ci->ci_cinfo[CAI_L2CACHE].cai_totalsize != 0) {
sep = print_cache_config(ci, CAI_L2CACHE, "L2 cache", NULL);
if (sep != NULL)
printf("\n");
}
if (ci->ci_cinfo[CAI_ITLB].cai_totalsize != 0) {
sep = print_tlb_config(ci, CAI_ITLB, "ITLB", NULL);
sep = print_tlb_config(ci, CAI_ITLB2, NULL, sep);
if (sep != NULL)
printf("\n");
}
if (ci->ci_cinfo[CAI_DTLB].cai_totalsize != 0) {
sep = print_tlb_config(ci, CAI_DTLB, "DTLB", NULL);
sep = print_tlb_config(ci, CAI_DTLB2, NULL, sep);
if (sep != NULL)
printf("\n");
}
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: cpu.h,v 1.8 2003/03/18 22:31:00 fvdl Exp $ */
/* $NetBSD: cpu.h,v 1.9 2003/04/25 21:54:30 fvdl Exp $ */
/*-
* Copyright (c) 1990 The Regents of the University of California.
@ -53,6 +53,7 @@
#include <machine/segments.h>
#include <machine/tss.h>
#include <machine/intrdefs.h>
#include <x86/cacheinfo.h>
#include <sys/device.h>
#include <sys/lock.h>
@ -105,6 +106,8 @@ struct cpu_info {
int ci_astpending;
struct trapframe *ci_ddb_regs;
struct x86_cache_info ci_cinfo[CAI_COUNT];
struct timeval ci_cc_time;
int64_t ci_cc_cc;
int64_t ci_cc_ms_delta;

View File

@ -1,4 +1,4 @@
/* $NetBSD: cpu.c,v 1.2 2003/04/01 15:08:29 thorpej Exp $ */
/* $NetBSD: cpu.c,v 1.3 2003/04/25 21:54:31 fvdl Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
@ -192,13 +192,36 @@ cpu_match(parent, match, aux)
static void
cpu_vm_init(struct cpu_info *ci)
{
int ncolors = 2, i;
for (i = CAI_ICACHE; i <= CAI_L2CACHE; i++) {
struct x86_cache_info *cai;
int tcolors;
cai = &ci->ci_cinfo[i];
tcolors = atop(cai->cai_totalsize);
switch(cai->cai_associativity) {
case 0xff:
tcolors = 1; /* fully associative */
break;
case 0:
case 1:
break;
default:
tcolors /= cai->cai_associativity;
}
ncolors = max(ncolors, tcolors);
}
/*
* XXX extract cache info.
* Knowing the size of the largest cache on this CPU, re-color
* our pages.
*/
if (uvmexp.ncolors > 2)
if (ncolors <= uvmexp.ncolors)
return;
printf("%s: %d page colors\n", ci->ci_dev->dv_xname, 2);
uvm_page_recolor(2);
printf("%s: %d page colors\n", ci->ci_dev->dv_xname, ncolors);
uvm_page_recolor(ncolors);
}

View File

@ -46,17 +46,54 @@ void
identifycpu(struct cpu_info *ci)
{
u_int64_t last_tsc;
u_int32_t dummy, val;
char buf[512];
u_int32_t brand[12];
char chipname[48];
CPUID(1, ci->ci_signature, val, dummy, ci->ci_feature_flags);
CPUID(0x80000001, dummy, dummy, dummy, val);
ci->ci_feature_flags |= val;
CPUID(0x80000002, brand[0], brand[1], brand[2], brand[3]);
CPUID(0x80000003, brand[4], brand[5], brand[6], brand[7]);
CPUID(0x80000004, brand[8], brand[9], brand[10], brand[11]);
strcpy(chipname, (char *)brand);
if (chipname[0] == 0)
strcpy(chipname, "Opteron or Athlon 64");
last_tsc = rdtsc();
delay(100000);
ci->ci_tsc_freq = (rdtsc() - last_tsc) * 10;
printf("AMD x86-64");
amd_cpu_cacheinfo(ci);
printf("%s: %s", ci->ci_dev->dv_xname, chipname);
if (ci->ci_tsc_freq != 0)
printf(", %lu.%02lu MHz", (ci->ci_tsc_freq + 4999) / 1000000,
((ci->ci_tsc_freq + 4999) / 10000) % 100);
printf("\n");
if ((ci->ci_feature_flags & CPUID_MASK1) != 0) {
bitmask_snprintf(ci->ci_feature_flags,
CPUID_FLAGS1, buf, sizeof(buf));
printf("%s: features: %s\n", ci->ci_dev->dv_xname, buf);
}
if ((ci->ci_feature_flags & CPUID_MASK2) != 0) {
bitmask_snprintf(ci->ci_feature_flags,
CPUID_EXT_FLAGS2, buf, sizeof(buf));
printf("%s: features: %s\n", ci->ci_dev->dv_xname, buf);
}
if ((ci->ci_feature_flags & CPUID_MASK3) != 0) {
bitmask_snprintf(ci->ci_feature_flags,
CPUID_EXT_FLAGS3, buf, sizeof(buf));
printf("%s: features: %s\n", ci->ci_dev->dv_xname, buf);
}
x86_print_cacheinfo(ci);
microtime_func = cc_microtime;
}