Add a CPU features framework on PowerPC and simplify CPU setup a little

more. This provides three new sysctls to user space:
hw.cpu_features - A bitmask of available CPU features
hw.floatingpoint - Whether or not there is hardware FP support
hw.altivec - Whether or not Altivec is available

PR:		powerpc/139154
MFC after:	10 days
This commit is contained in:
Nathan Whitehorn 2009-11-28 17:33:19 +00:00
parent d9c18e5627
commit 227f66048e
6 changed files with 131 additions and 99 deletions

View File

@ -130,7 +130,6 @@ extern vm_offset_t ksym_start, ksym_end;
int cold = 1;
int cacheline_size = 32;
int ppc64 = 0;
int hw_direct_map = 1;
struct pcpu __pcpu[MAXCPU];
@ -256,6 +255,7 @@ powerpc_init(u_int startkernel, u_int endkernel, u_int basekernel, void *mdp)
char *env;
uint32_t msr, scratch;
uint8_t *cache_check;
int ppc64;
end = 0;
kmdp = NULL;
@ -405,12 +405,15 @@ powerpc_init(u_int startkernel, u_int endkernel, u_int basekernel, void *mdp)
mfsprg2 %1;"
: "=r"(scratch), "=r"(ppc64));
if (ppc64)
cpu_features |= PPC_FEATURE_64;
/*
* Now copy restorebridge into all the handlers, if necessary,
* and set up the trap tables.
*/
if (ppc64) {
if (cpu_features & PPC_FEATURE_64) {
/* Patch the two instances of rfi -> rfid */
bcopy(&rfid_patch,&rfi_patch1,4);
#ifdef KDB
@ -489,7 +492,7 @@ powerpc_init(u_int startkernel, u_int endkernel, u_int basekernel, void *mdp)
* in case the platform module had a better idea of what we
* should do.
*/
if (ppc64)
if (cpu_features & PPC_FEATURE_64)
pmap_mmu_install(MMU_TYPE_G5, BUS_PROBE_GENERIC);
else
pmap_mmu_install(MMU_TYPE_OEA, BUS_PROBE_GENERIC);

View File

@ -54,6 +54,7 @@ __FBSDID("$FreeBSD$");
#include <vm/vm_page.h>
#include <machine/bus.h>
#include <machine/cpu.h>
#include <machine/md_var.h>
#include <machine/platform.h>
#include <machine/ofw_machdep.h>
@ -336,7 +337,7 @@ openfirmware(void *args)
/*
* Clear battable[] translations
*/
if (!ppc64) {
if (!(cpu_features & PPC_FEATURE_64)) {
__asm __volatile("mtdbatu 2, %0\n"
"mtdbatu 3, %0" : : "r" (0));
}

View File

@ -179,7 +179,6 @@ SYSCTL_INT(_machdep, CPU_CACHELINE, cacheline_size,
CTLFLAG_RD, &cacheline_size, 0, "");
int hw_direct_map = 0;
int ppc64 = 0;
static void cpu_e500_startup(void *);
SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_e500_startup, NULL);

View File

@ -39,6 +39,27 @@
#include <machine/pcb.h>
#include <machine/psl.h>
/*
* CPU Feature Attributes
*
* These are defined in the PowerPC ELF ABI for the AT_HWCAP vector,
* and are exported to userland via the machdep.cpu_features
* sysctl.
*/
extern int cpu_features;
#define PPC_FEATURE_32 0x80000000 /* Always true */
#define PPC_FEATURE_64 0x40000000 /* Defined on a 64-bit CPU */
#define PPC_FEATURE_HAS_ALTIVEC 0x10000000
#define PPC_FEATURE_HAS_FPU 0x08000000
#define PPC_FEATURE_HAS_MMU 0x04000000
#define PPC_FEATURE_UNIFIED_CACHE 0x01000000
#define PPC_FEATURE_BITMASK \
"\20" \
"\040PPC32\037PPC64\035ALTIVEC\034FPU\033MMU\031UNIFIEDCACHE"
#define TRAPF_USERMODE(frame) (((frame)->srr1 & PSL_PR) != 0)
#define TRAPF_PC(frame) ((frame)->srr0)

View File

@ -46,7 +46,6 @@ extern u_long ns_per_tick;
extern int powerpc_pow_enabled;
extern int cacheline_size;
extern int ppc64;
extern int hw_direct_map;
void __syncicache(void *, int);

View File

@ -67,6 +67,7 @@
#include <sys/sysctl.h>
#include <machine/bus.h>
#include <machine/cpu.h>
#include <machine/hid.h>
#include <machine/md_var.h>
#include <machine/smp.h>
@ -74,59 +75,102 @@
int powerpc_pow_enabled;
static void cpu_6xx_setup(int cpuid, uint16_t vers);
static void cpu_e500_setup(int cpuid, uint16_t vers);
static void cpu_970_setup(int cpuid, uint16_t vers);
struct cputab {
const char *name;
uint16_t version;
uint16_t revfmt;
int features; /* Do not include PPC_FEATURE_32 or
* PPC_FEATURE_HAS_MMU */
void (*cpu_setup)(int cpuid, uint16_t vers);
};
#define REVFMT_MAJMIN 1 /* %u.%u */
#define REVFMT_HEX 2 /* 0x%04x */
#define REVFMT_DEC 3 /* %u */
static const struct cputab models[] = {
{ "Motorola PowerPC 601", MPC601, REVFMT_DEC },
{ "Motorola PowerPC 602", MPC602, REVFMT_DEC },
{ "Motorola PowerPC 603", MPC603, REVFMT_MAJMIN },
{ "Motorola PowerPC 603e", MPC603e, REVFMT_MAJMIN },
{ "Motorola PowerPC 603ev", MPC603ev, REVFMT_MAJMIN },
{ "Motorola PowerPC 604", MPC604, REVFMT_MAJMIN },
{ "Motorola PowerPC 604ev", MPC604ev, REVFMT_MAJMIN },
{ "Motorola PowerPC 620", MPC620, REVFMT_HEX },
{ "Motorola PowerPC 750", MPC750, REVFMT_MAJMIN },
{ "IBM PowerPC 750FX", IBM750FX, REVFMT_MAJMIN },
{ "IBM PowerPC 970", IBM970, REVFMT_MAJMIN },
{ "IBM PowerPC 970FX", IBM970FX, REVFMT_MAJMIN },
{ "IBM PowerPC 970GX", IBM970GX, REVFMT_MAJMIN },
{ "IBM PowerPC 970MP", IBM970MP, REVFMT_MAJMIN },
{ "Motorola PowerPC 7400", MPC7400, REVFMT_MAJMIN },
{ "Motorola PowerPC 7410", MPC7410, REVFMT_MAJMIN },
{ "Motorola PowerPC 7450", MPC7450, REVFMT_MAJMIN },
{ "Motorola PowerPC 7455", MPC7455, REVFMT_MAJMIN },
{ "Motorola PowerPC 7457", MPC7457, REVFMT_MAJMIN },
{ "Motorola PowerPC 7447A", MPC7447A, REVFMT_MAJMIN },
{ "Motorola PowerPC 7448", MPC7448, REVFMT_MAJMIN },
{ "Motorola PowerPC 8240", MPC8240, REVFMT_MAJMIN },
{ "Freescale e500v1 core", FSL_E500v1, REVFMT_MAJMIN },
{ "Freescale e500v2 core", FSL_E500v2, REVFMT_MAJMIN },
{ "Unknown PowerPC CPU", 0, REVFMT_HEX }
{ "Motorola PowerPC 601", MPC601, REVFMT_DEC,
PPC_FEATURE_HAS_FPU | PPC_FEATURE_UNIFIED_CACHE, cpu_6xx_setup },
{ "Motorola PowerPC 602", MPC602, REVFMT_DEC,
PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
{ "Motorola PowerPC 603", MPC603, REVFMT_MAJMIN,
PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
{ "Motorola PowerPC 603e", MPC603e, REVFMT_MAJMIN,
PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
{ "Motorola PowerPC 603ev", MPC603ev, REVFMT_MAJMIN,
PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
{ "Motorola PowerPC 604", MPC604, REVFMT_MAJMIN,
PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
{ "Motorola PowerPC 604ev", MPC604ev, REVFMT_MAJMIN,
PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
{ "Motorola PowerPC 620", MPC620, REVFMT_HEX,
PPC_FEATURE_64 | PPC_FEATURE_HAS_FPU, NULL },
{ "Motorola PowerPC 750", MPC750, REVFMT_MAJMIN,
PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
{ "IBM PowerPC 750FX", IBM750FX, REVFMT_MAJMIN,
PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
{ "IBM PowerPC 970", IBM970, REVFMT_MAJMIN,
PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU,
cpu_970_setup },
{ "IBM PowerPC 970FX", IBM970FX, REVFMT_MAJMIN,
PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU,
cpu_970_setup },
{ "IBM PowerPC 970GX", IBM970GX, REVFMT_MAJMIN,
PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU,
cpu_970_setup },
{ "IBM PowerPC 970MP", IBM970MP, REVFMT_MAJMIN,
PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU,
cpu_970_setup },
{ "Motorola PowerPC 7400", MPC7400, REVFMT_MAJMIN,
PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
{ "Motorola PowerPC 7410", MPC7410, REVFMT_MAJMIN,
PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
{ "Motorola PowerPC 7450", MPC7450, REVFMT_MAJMIN,
PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
{ "Motorola PowerPC 7455", MPC7455, REVFMT_MAJMIN,
PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
{ "Motorola PowerPC 7457", MPC7457, REVFMT_MAJMIN,
PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
{ "Motorola PowerPC 7447A", MPC7447A, REVFMT_MAJMIN,
PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
{ "Motorola PowerPC 7448", MPC7448, REVFMT_MAJMIN,
PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
{ "Motorola PowerPC 8240", MPC8240, REVFMT_MAJMIN,
PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
{ "Motorola PowerPC 8245", MPC8245, REVFMT_MAJMIN,
PPC_FEATURE_HAS_FPU, cpu_6xx_setup },
{ "Freescale e500v1 core", FSL_E500v1, REVFMT_MAJMIN,
0, cpu_e500_setup },
{ "Freescale e500v2 core", FSL_E500v2, REVFMT_MAJMIN,
0, cpu_e500_setup },
{ "Unknown PowerPC CPU", 0, REVFMT_HEX, 0, NULL },
};
static void cpu_6xx_print_cacheinfo(u_int, uint16_t);
static int cpu_feature_bit(SYSCTL_HANDLER_ARGS);
static char model[64];
SYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD, model, 0, "");
static void cpu_print_speed(void);
int cpu_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU;
SYSCTL_OPAQUE(_hw, OID_AUTO, cpu_features, CTLTYPE_INT | CTLFLAG_RD,
&cpu_features, sizeof(cpu_features), "IX", "PowerPC CPU features");
static void cpu_6xx_setup(int cpuid, uint16_t vers);
static void cpu_6xx_print_cacheinfo(u_int, uint16_t);
static void cpu_e500_setup(int cpuid, uint16_t vers);
#ifndef E500
static void cpu_970_setup(int cpuid, uint16_t vers);
#endif
/* Provide some user-friendly aliases for bits in cpu_features */
SYSCTL_PROC(_hw, OID_AUTO, floatingpoint, CTLTYPE_INT | CTLFLAG_RD,
0, PPC_FEATURE_HAS_FPU, cpu_feature_bit, "I",
"Floating point instructions executed in hardware");
SYSCTL_PROC(_hw, OID_AUTO, altivec, CTLTYPE_INT | CTLFLAG_RD,
0, PPC_FEATURE_HAS_ALTIVEC, cpu_feature_bit, "I", "CPU supports Altivec");
void
cpu_setup(u_int cpuid)
{
u_int pvr, maj, min;
uint16_t vers, rev, revfmt;
uint64_t cps;
const struct cputab *cp;
const char *name;
@ -175,57 +219,19 @@ cpu_setup(u_int cpuid)
break;
}
if (cpu_est_clockrate(0, &cps) == 0)
printf(", %lld.%02lld MHz", cps / 1000000, (cps / 10000) % 100);
printf("\n");
cpu_features |= cp->features;
printf("cpu%d: Features %b\n", cpuid, cpu_features,
PPC_FEATURE_BITMASK);
/*
* Configure CPU
*/
switch (vers) {
case MPC603:
case MPC603e:
case MPC603ev:
case MPC604ev:
case MPC750:
case IBM750FX:
case MPC7400:
case MPC7410:
case MPC7447A:
case MPC7448:
case MPC7450:
case MPC7455:
case MPC7457:
case MPC8240:
case MPC8245:
cpu_6xx_setup(cpuid, vers);
break;
#ifndef E500
case IBM970:
case IBM970FX:
case IBM970GX:
case IBM970MP:
cpu_970_setup(cpuid, vers);
break;
#endif
case FSL_E500v1:
case FSL_E500v2:
cpu_e500_setup(cpuid, vers);
break;
default:
/* HID setup is unknown */
break;
}
printf("\n");
}
void
cpu_print_speed(void)
{
uint64_t cps;
if (cpu_est_clockrate(0, &cps) == 0)
printf(", %lld.%02lld MHz", cps / 1000000, (cps / 10000) % 100);
if (cp->cpu_setup != NULL)
cp->cpu_setup(cpuid, vers);
}
/* Get current clock frequency for the given cpu id. */
@ -351,9 +357,6 @@ cpu_6xx_setup(int cpuid, uint16_t vers)
mtspr(SPR_HID0, hid0);
cpu_print_speed();
printf("\n");
if (bootverbose)
cpu_6xx_print_cacheinfo(cpuid, vers);
@ -370,7 +373,7 @@ cpu_6xx_setup(int cpuid, uint16_t vers)
break;
}
printf("cpu%d: HID0 %b", cpuid, (int)hid0, bitmask);
printf("cpu%d: HID0 %b\n", cpuid, (int)hid0, bitmask);
}
@ -429,16 +432,14 @@ cpu_e500_setup(int cpuid, uint16_t vers)
{
register_t hid0;
printf("\n");
hid0 = mfspr(SPR_HID0);
printf("cpu%d: HID0 %b", cpuid, (int)hid0, HID0_E500_BITMASK);
printf("cpu%d: HID0 %b\n", cpuid, (int)hid0, HID0_E500_BITMASK);
}
#ifndef E500
static void
cpu_970_setup(int cpuid, uint16_t vers)
{
#ifdef AIM
uint32_t hid0_hi, hid0_lo;
__asm __volatile ("mfspr %0,%2; clrldi %1,%0,32; srdi %0,%0,32;"
@ -458,11 +459,19 @@ cpu_970_setup(int cpuid, uint16_t vers)
sync; isync"
:: "r" (hid0_hi), "r"(hid0_lo), "K" (SPR_HID0));
cpu_print_speed();
printf("\n");
__asm __volatile ("mfspr %0,%1; srdi %0,%0,32;"
: "=r" (hid0_hi) : "K" (SPR_HID0));
printf("cpu%d: HID0 %b", cpuid, (int)(hid0_hi), HID0_970_BITMASK);
}
printf("cpu%d: HID0 %b\n", cpuid, (int)(hid0_hi), HID0_970_BITMASK);
#endif
}
static int
cpu_feature_bit(SYSCTL_HANDLER_ARGS)
{
int result;
result = (cpu_features & arg2) ? 1 : 0;
return (sysctl_handle_int(oidp, &result, 0, req));
}