Share some common cache info cpuid code between i386 and x86_64.
This commit is contained in:
parent
766d04f56a
commit
4b293b5851
|
@ -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];
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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().
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue